Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
projection.f90
Go to the documentation of this file.
1! Copyright (c) 2008-2020, UCHICAGO ARGONNE, LLC.
2!
3! The UChicago Argonne, LLC as Operator of Argonne National
4! Laboratory holds copyright in the Software. The copyright holder
5! reserves all rights except those expressly granted to licensees,
6! and U.S. Government license rights.
7!
8! Redistribution and use in source and binary forms, with or without
9! modification, are permitted provided that the following conditions
10! are met:
11!
12! 1. Redistributions of source code must retain the above copyright
13! notice, this list of conditions and the disclaimer below.
14!
15! 2. Redistributions in binary form must reproduce the above copyright
16! notice, this list of conditions and the disclaimer (as noted below)
17! in the documentation and/or other materials provided with the
18! distribution.
19!
20! 3. Neither the name of ANL nor the names of its contributors
21! may be used to endorse or promote products derived from this software
22! without specific prior written permission.
23!
24! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28! UCHICAGO ARGONNE, LLC, THE U.S. DEPARTMENT OF
29! ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
31! TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32! DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34! (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36!
37! Additional BSD Notice
38! ---------------------
39! 1. This notice is required to be provided under our contract with
40! the U.S. Department of Energy (DOE). This work was produced at
41! Argonne National Laboratory under Contract
42! No. DE-AC02-06CH11357 with the DOE.
43!
44! 2. Neither the United States Government nor UCHICAGO ARGONNE,
45! LLC nor any of their employees, makes any warranty,
46! express or implied, or assumes any liability or responsibility for the
47! accuracy, completeness, or usefulness of any information, apparatus,
48! product, or process disclosed, or represents that its use would not
49! infringe privately-owned rights.
50!
51! 3. Also, reference herein to any specific commercial products, process,
52! or services by trade name, trademark, manufacturer or otherwise does
53! not necessarily constitute or imply its endorsement, recommendation,
54! or favoring by the United States Government or UCHICAGO ARGONNE LLC.
55! The views and opinions of authors expressed
56! herein do not necessarily state or reflect those of the United States
57! Government or UCHICAGO ARGONNE, LLC, and shall
58! not be used for advertising or product endorsement purposes.
59!
64 use num_types, only : rp, c_rp
65 use math, only : rzero, glsc3, add2, add2s2, copy, cmult
66 use coefs, only : coef_t
67 use ax_product, only : ax_t
69 use gather_scatter, only : gs_t, gs_op_add
79 use logger, only : log_size, neko_log
80 use utils, only : neko_warning
83 use mpi_f08, only : mpi_allreduce, mpi_in_place, mpi_sum, mpi_wtime
84 use, intrinsic :: iso_c_binding, only : c_ptr, c_size_t, &
85 c_sizeof, c_null_ptr, c_loc, c_associated
86 implicit none
87 private
88 public :: proj_ortho
89
90 type, public :: projection_t
91 real(kind=rp), allocatable :: xx(:,:)
92 real(kind=rp), allocatable :: bb(:,:)
93 real(kind=rp), allocatable :: xbar(:)
94 type(c_ptr), allocatable :: xx_d(:)
95 type(c_ptr), allocatable :: bb_d(:)
96 type(c_ptr) :: xbar_d = c_null_ptr
97 type(c_ptr) :: alpha_d = c_null_ptr
98 type(c_ptr) :: xx_d_d = c_null_ptr
99 type(c_ptr) :: bb_d_d = c_null_ptr
100 integer :: m, l
101 real(kind=rp) :: tol = 1e-7_rp
102 !logging variables
103 real(kind=rp) :: proj_res
104 integer :: proj_m = 0
105 integer :: activ_step ! steps to activate projection
106 logical :: prj_reorthogonalize_basis = .false.
107 contains
108 procedure, pass(this) :: clear => bcknd_clear
109 procedure, pass(this) :: project_on => bcknd_project_on
110 procedure, pass(this) :: project_back => bcknd_project_back
111 procedure, pass(this) :: log_info => print_proj_info
112 procedure, pass(this) :: init => projection_init
113 procedure, pass(this) :: free => projection_free
114 procedure, pass(this) :: pre_solving => projection_pre_solving
115 procedure, pass(this) :: post_solving => projection_post_solving
116 procedure, pass(this) :: reortho_basis => bcknd_reorthogonalize_basis
117 end type projection_t
118
119contains
120
121 subroutine projection_init(this, n, L, activ_step, reorthogonalize_basis)
122 class(projection_t), target, intent(inout) :: this
123 integer, intent(in) :: n
124 integer, intent(in) :: L
125 integer, optional, intent(in) :: activ_step
126 logical, optional, intent(in) :: reorthogonalize_basis
127 integer :: i
128 integer(c_size_t) :: ptr_size
129 type(c_ptr) :: ptr
130 real(c_rp) :: dummy
131
132 call this%free()
133
134 this%L = l
135
136 if (present(activ_step)) then
137 this%activ_step = activ_step
138 else
139 this%activ_step = 5
140 end if
141
142 if (present(reorthogonalize_basis)) then
143 this%prj_reorthogonalize_basis = reorthogonalize_basis
144 end if
145
146 this%m = 0
147
148 ! Return if the space is 0, to avoid allocating zero sized
149 ! arrays, which are not supported for all backends
150 if (this%L .le. 0) then
151 return
152 end if
153
154 allocate(this%xx(n, this%L))
155 allocate(this%bb(n, this%L))
156 allocate(this%xbar(n))
157 call rzero(this%xbar, n)
158 do i = 1, this%L
159 call rzero(this%xx(1, i), n)
160 call rzero(this%bb(1, i), n)
161 end do
162 if (neko_bcknd_device .eq. 1) then
163
164 allocate(this%xx_d(this%L))
165 allocate(this%bb_d(this%L))
166
167 call device_map(this%xbar, this%xbar_d, n)
168 call device_alloc(this%alpha_d, int(c_sizeof(dummy)*this%L, c_size_t))
169
170 call device_rzero(this%xbar_d, n)
171 call device_rzero(this%alpha_d, this%L)
172
173 do i = 1, this%L
174 this%xx_d(i) = c_null_ptr
175 call device_map(this%xx(:, i), this%xx_d(i), n)
176 call device_rzero(this%xx_d(i), n)
177 this%bb_d(i) = c_null_ptr
178 call device_map(this%bb(:, i), this%bb_d(i), n)
179 call device_rzero(this%bb_d(i), n)
180 end do
181
182 ptr_size = c_sizeof(c_null_ptr) * this%L
183 call device_alloc(this%xx_d_d, ptr_size)
184 ptr = c_loc(this%xx_d)
185 call device_memcpy(ptr, this%xx_d_d, ptr_size, &
186 host_to_device, sync = .false.)
187 call device_alloc(this%bb_d_d, ptr_size)
188 ptr = c_loc(this%bb_d)
189 call device_memcpy(ptr, this%bb_d_d, ptr_size, &
190 host_to_device, sync = .false.)
191 end if
192
193
194 end subroutine projection_init
195
196 subroutine projection_free(this)
197 class(projection_t), intent(inout) :: this
198 integer :: i
199 if (c_associated(this%xx_d_d)) then
200 call device_free(this%xx_d_d)
201 end if
202 if (c_associated(this%bb_d_d)) then
203 call device_free(this%bb_d_d)
204 end if
205 if (c_associated(this%alpha_d)) then
206 call device_free(this%alpha_d)
207 end if
208 if (allocated(this%xx)) then
209 if (neko_bcknd_device .eq. 1) then
210 do i = 1, this%L
211 call device_unmap(this%xx(:, i), this%xx_d(i))
212 end do
213 deallocate(this%xx_d)
214 end if
215 deallocate(this%xx)
216 end if
217 if (allocated(this%xbar)) then
218 if (neko_bcknd_device .eq. 1) then
219 call device_unmap(this%xbar, this%xbar_d)
220 end if
221 deallocate(this%xbar)
222 end if
223 if (allocated(this%bb)) then
224 if (neko_bcknd_device .eq. 1) then
225 do i = 1, this%L
226 call device_unmap(this%bb(:, i), this%bb_d(i))
227 end do
228 deallocate(this%bb_d)
229 end if
230 deallocate(this%bb)
231 end if
232
233 end subroutine projection_free
234
235 subroutine projection_pre_solving(this, b, tstep, coef, n, dt_controller, &
236 string, Ax, gs_h, bclst)
237 class(projection_t), intent(inout) :: this
238 integer, intent(inout) :: n
239 real(kind=rp), intent(inout), dimension(n) :: b
240 integer, intent(in) :: tstep
241 class(coef_t), intent(inout) :: coef
242 type(time_step_controller_t), intent(in) :: dt_controller
243 class(scalar_bc_projector_t), optional, intent(inout) :: bclst
244 type(gs_t), optional, intent(inout) :: gs_h
245 class(ax_t), optional, intent(in) :: Ax
246 character(len=*), optional :: string
247
248 if (tstep .gt. this%activ_step .and. this%L .gt. 0) then
249 if (dt_controller%is_variable_dt) then
250 ! the time step at which dt is changed
251 if (dt_controller%dt_last_change .eq. 0) then
252 call this%clear(n)
253 else if (dt_controller%dt_last_change .gt. this%activ_step - 1) then
254 ! Re-orthogonalize basis if requested
255 if (this%prj_reorthogonalize_basis .and. present(gs_h) &
256 .and. present(ax) .and. present(bclst)) then
257 call this%reortho_basis(ax, coef, gs_h, bclst, n)
258 end if
259 ! activate projection some steps after dt is changed
260 ! note that dt_last_change start from 0
261 call this%project_on(b, coef, n)
262 if (present(string)) then
263 call this%log_info(string, tstep)
264 end if
265 end if
266 else
267 ! Re-orthogonalize basis if requested
268 if (this%prj_reorthogonalize_basis .and. present(gs_h) &
269 .and. present(ax) .and. present(bclst)) then
270 call this%reortho_basis(ax, coef, gs_h, bclst, n)
271 end if
272 call this%project_on(b, coef, n)
273 if (present(string)) then
274 call this%log_info(string, tstep)
275 end if
276 end if
277 end if
278
279 end subroutine projection_pre_solving
280
281 subroutine projection_post_solving(this, x, Ax, coef, bclst, gs_h, n, tstep, &
282 dt_controller)
283 class(projection_t), intent(inout) :: this
284 integer, intent(inout) :: n
285 class(ax_t), intent(inout) :: Ax
286 class(coef_t), intent(inout) :: coef
287 class(scalar_bc_projector_t), intent(inout) :: bclst
288 type(gs_t), intent(inout) :: gs_h
289 real(kind=rp), intent(inout), dimension(n) :: x
290 integer, intent(in) :: tstep
291 type(time_step_controller_t), intent(in) :: dt_controller
292
293 if (tstep .gt. this%activ_step .and. this%L .gt. 0) then
294 if (.not.(dt_controller%is_variable_dt) .or. &
295 (dt_controller%dt_last_change .gt. this%activ_step - 1)) then
296 call this%project_back(x, ax, coef, bclst, gs_h, n)
297 end if
298 end if
299
300 end subroutine projection_post_solving
301
302 subroutine bcknd_project_on(this, b, coef, n)
303 class(projection_t), intent(inout) :: this
304 integer, intent(inout) :: n
305 class(coef_t), intent(inout) :: coef
306 real(kind=rp), intent(inout), dimension(n) :: b
307 call profiler_start_region('Project on', 16)
308 if (neko_bcknd_device .eq. 1) then
309 call device_project_on(this, b, coef, n)
310 else
311 call cpu_project_on(this, b, coef, n)
312 end if
313 call profiler_end_region('Project on', 16)
314 end subroutine bcknd_project_on
315
316 subroutine bcknd_project_back(this, x, Ax, coef, bclst, gs_h, n)
317 class(projection_t), intent(inout) :: this
318 integer, intent(inout) :: n
319 class(ax_t), intent(inout) :: Ax
320 class(coef_t), intent(inout) :: coef
321 class(scalar_bc_projector_t), intent(inout) :: bclst
322 type(gs_t), intent(inout) :: gs_h
323 real(kind=rp), intent(inout), dimension(n) :: x
324 type(c_ptr) :: x_d
325
326 call profiler_start_region('Project back', 17)
327
328 if (neko_bcknd_device .eq. 1) then
329 x_d = device_get_ptr(x)
330 ! Restore desired solution
331 if (this%m .gt. 0) call device_add2(x_d, this%xbar_d, n)
332 if (this%m .eq. this%L) then
333 this%m = 1
334 else
335 this%m = min(this%m+1, this%L)
336 end if
337
338 call device_copy(this%xx_d(this%m), x_d, n) ! Update (X,B)
339
340 else
341 if (this%m .gt. 0) call add2(x, this%xbar, n) ! Restore desired solution
342 if (this%m .eq. this%L) then
343 this%m = 1
344 else
345 this%m = min(this%m+1, this%L)
346 end if
347
348 call copy(this%xx(1, this%m), x, n) ! Update (X,B)
349 end if
350
351 call ax%compute(this%bb(1, this%m), x, coef, coef%msh, coef%Xh)
352 call gs_h%gs_op_vector(this%bb(1, this%m), n, gs_op_add)
353 call bclst%apply(this%bb(1, this%m), n)
354
355 call proj_ortho(this, coef, n)
356 call profiler_end_region('Project back', 17)
357 end subroutine bcknd_project_back
358
359 subroutine bcknd_reorthogonalize_basis(this, Ax, coef, gs_h, blst, n)
360 class(projection_t), intent(inout) :: this
361 class(ax_t), intent(in) :: Ax
362 class(coef_t), intent(in) :: coef
363 type(gs_t), intent(inout) :: gs_h
364 type(scalar_bc_projector_t), intent(inout) :: blst
365 integer, intent(in) :: n
366
367 call profiler_start_region('Project reortho basis')
368 if (neko_bcknd_device .eq. 1) then
369 call device_reorthogonalize_basis(this, ax, coef, gs_h, blst, n)
370 else
371 call cpu_reorthogonalize_basis(this, ax, coef, gs_h, blst, n)
372 end if
373 call profiler_end_region('Project reortho basis')
374 end subroutine bcknd_reorthogonalize_basis
375
376 subroutine cpu_reorthogonalize_basis(this, Ax, coef, gs_h, blst, n)
377 class(projection_t), intent(inout) :: this
378 class(ax_t), intent(in) :: Ax
379 class(coef_t), intent(in) :: coef
380 type(gs_t), intent(inout) :: gs_h
381 type(scalar_bc_projector_t), intent(inout) :: blst
382 integer, intent(in) :: n
383 character(len=1000) :: msg
384
385 integer :: i, j
386 real(kind=rp) :: alpha, s, norm_fac
387 real(kind=rp) :: start_time, end_time, time
388
389 if (this%m .le. 0) return
390
391 associate(xx => this%xx, bb => this%bb)
392 start_time = mpi_wtime()
393
394 ! Recompute B = A_new * X using the new mesh metrics
395 do i = 1, this%m
396 call ax%compute(bb(1,i), xx(1,i), coef, coef%msh, coef%Xh)
397 call gs_h%gs_op_vector(bb(1,i), n, gs_op_add)
398 call blst%apply(bb(1,i), n)
399 end do
400
401 ! Modified Gram-Schmidt
402 do i = 1, this%m
403
404 ! Orthogonalize against previous vectors
405 do j = 1, i - 1
406 alpha = glsc3(xx(1,i), bb(1,j), coef%mult, n)
407 call add2s2(xx(1,i), xx(1,j), -alpha, n)
408 call add2s2(bb(1,i), bb(1,j), -alpha, n)
409 end do
410
411 s = glsc3(xx(1,i), bb(1,i), coef%mult, n)
412 norm_fac = 1.0_rp / sqrt(s)
413 call cmult(xx(1,i), norm_fac, n)
414 call cmult(bb(1,i), norm_fac, n)
415
416 end do
417 end_time = mpi_wtime()
418 time = end_time - start_time
419 write(msg, '(A, E15.7)') &
420 "Projection basis reorthogonalization (s): ", time
421 call neko_log%message(trim(msg))
422 end associate
423 end subroutine cpu_reorthogonalize_basis
424
425 subroutine device_reorthogonalize_basis(this, Ax, coef, gs_h, blst, n)
426 class(projection_t), intent(inout) :: this
427 class(ax_t), intent(in) :: Ax
428 class(coef_t), intent(in) :: coef
429 type(gs_t), intent(inout) :: gs_h
430 type(scalar_bc_projector_t), intent(inout) :: blst
431 integer, intent(in) :: n
432 character(len=1000) :: msg
433
434 integer :: i, j
435 real(kind=rp) :: alpha, s, norm_fac
436 real(kind=rp) :: start_time, end_time, time
437
438 if (this%m .le. 0) return
439
440 associate(xx_d => this%xx_d, bb_d => this%bb_d)
441 start_time = mpi_wtime()
442
443 ! Recompute B = A_new * X using the new mesh metrics
444 do i = 1, this%m
445 call ax%compute(this%bb(1,i), this%xx(1,i), coef, coef%msh, coef%Xh)
446 call gs_h%gs_op_vector(this%bb(1,i), n, gs_op_add)
447 call blst%apply(this%bb(1,i), n)
448 end do
449
450 ! Modified Gram-Schmidt
451 do i = 1, this%m
452
453 ! Orthogonalize against previous vectors
454 do j = 1, i - 1
455 alpha = device_glsc3(xx_d(i), bb_d(j), coef%mult_d, n)
456 call device_add2s2(xx_d(i), xx_d(j), -alpha, n)
457 call device_add2s2(bb_d(i), bb_d(j), -alpha, n)
458 end do
459
460 s = device_glsc3(xx_d(i), bb_d(i), coef%mult_d, n)
461 norm_fac = 1.0_rp / sqrt(s)
462 call device_cmult(xx_d(i), norm_fac, n)
463 call device_cmult(bb_d(i), norm_fac, n)
464
465 end do
466 end_time = mpi_wtime()
467 time = end_time - start_time
468 write(msg, '(A, E15.7)') &
469 "Projection basis reorthogonalization (s): ", time
470 call neko_log%message(trim(msg))
471 end associate
472 end subroutine device_reorthogonalize_basis
473
474
475 subroutine cpu_project_on(this, b, coef, n)
476 class(projection_t), intent(inout) :: this
477 integer, intent(inout) :: n
478 class(coef_t), intent(inout) :: coef
479 real(kind=rp), intent(inout), dimension(n) :: b
480 integer :: i, j, k, l, ierr
481 real(kind=rp) :: work(this%L), alpha(this%L), s
482
483 associate(xbar => this%xbar, xx => this%xx, &
484 bb => this%bb)
485
486 if (this%m .le. 0) return
487
488 !First round of CGS
489 call rzero(alpha, this%m)
490 this%proj_res = sqrt(glsc3(b, b, coef%mult, n) / coef%volume)
491 this%proj_m = this%m
492 !$omp parallel do private(j, k, l, s) reduction(+:alpha)
493 do i = 1, n, neko_blk_size
494 j = min(neko_blk_size, n-i+1)
495 do k = 1, this%m
496 s = 0.0_rp
497 do l = 0, (j-1)
498 s = s + xx(i+l, k) * coef%mult(i+l,1,1,1) * b(i+l)
499 end do
500 alpha(k) = alpha(k) + s
501 end do
502 end do
503 !$omp end parallel do
504
505 !First one outside loop to avoid zeroing xbar and bbar
506 call mpi_allreduce(mpi_in_place, alpha, this%m, &
507 mpi_real_precision, mpi_sum, neko_comm, ierr)
508
509 call rzero(work, this%m)
510
511 !$omp parallel do private(j, k, l, s) reduction(+:work)
512 do i = 1, n, neko_blk_size
513 j = min(neko_blk_size, n-i+1)
514 do l = 0, (j-1)
515 xbar(i+l) = alpha(1) * xx(i+l,1)
516 b(i+l) = b(i+l) - alpha(1) * bb(i+l,1)
517 end do
518 do k = 2, this%m
519 do l = 0, (j-1)
520 xbar(i+l) = xbar(i+l) + alpha(k) * xx(i+l,k)
521 b(i+l) = b(i+l)- alpha(k) * bb(i+l,k)
522 end do
523 end do
524 !Second round of CGS
525 do k = 1, this%m
526 s = 0.0_rp
527 do l = 0, (j-1)
528 s = s + xx(i+l,k) * coef%mult(i+l,1,1,1) * b(i+l)
529 end do
530 work(k) = work(k) + s
531 end do
532 end do
533 !$omp end parallel do
534
535 call mpi_allreduce(work, alpha, this%m, &
536 mpi_real_precision, mpi_sum, neko_comm, ierr)
537
538 !$omp parallel do private(j, k, l)
539 do i = 1, n, neko_blk_size
540 j = min(neko_blk_size, n-i+1)
541 do k = 1, this%m
542 do l = 0, (j-1)
543 xbar(i+l) = xbar(i+l) + alpha(k) * xx(i+l,k)
544 b(i+l) = b(i+l) - alpha(k) * bb(i+l,k)
545 end do
546 end do
547 end do
548 !$omp end parallel do
549 end associate
550 end subroutine cpu_project_on
551
552 subroutine device_project_on(this, b, coef, n)
553 class(projection_t), intent(inout) :: this
554 integer, intent(inout) :: n
555 class(coef_t), intent(inout) :: coef
556 real(kind=rp), intent(inout), dimension(n) :: b
557 real(kind=rp) :: alpha(this%L)
558 type(c_ptr) :: b_d
559 integer :: i
560 b_d = device_get_ptr(b)
561
562 associate(xbar_d => this%xbar_d, xx_d => this%xx_d, xx_d_d => this%xx_d_d, &
563 bb_d => this%bb_d, bb_d_d => this%bb_d_d, alpha_d => this%alpha_d)
564
565 if (this%m .le. 0) return
566
567
568
569 this%proj_res = sqrt(device_glsc3(b_d, b_d, coef%mult_d, n)/coef%volume)
570 this%proj_m = this%m
571 if (neko_device_mpi .and. (neko_bcknd_opencl .ne. 1)) then
572 call device_proj_on(alpha_d, b_d, xx_d_d, bb_d_d, &
573 coef%mult_d, xbar_d, this%m, n)
574 else
575 if (neko_bcknd_opencl .eq. 1) then
576 do i = 1, this%m
577 alpha(i) = device_glsc3(b_d, xx_d(i), coef%mult_d, n)
578 end do
579 else
580 call device_glsc3_many(alpha, b_d, xx_d_d, coef%mult_d, this%m, n)
581 call device_memcpy(alpha, alpha_d, this%m, &
582 host_to_device, sync = .false.)
583 end if
584 call device_rzero(xbar_d, n)
585 if (neko_bcknd_opencl .eq. 1) then
586 do i = 1, this%m
587 call device_add2s2(xbar_d, xx_d(i), alpha(i), n)
588 end do
589 call cmult(alpha, -1.0_rp, this%m)
590 else
591 call device_add2s2_many(xbar_d, xx_d_d, alpha_d, this%m, n)
592 call device_cmult(alpha_d, -1.0_rp, this%m)
593 end if
594
595 if (neko_bcknd_opencl .eq. 1) then
596 do i = 1, this%m
597 call device_add2s2(b_d, bb_d(i), alpha(i), n)
598 alpha(i) = device_glsc3(b_d, xx_d(i), coef%mult_d, n)
599 end do
600 else
601 call device_add2s2_many(b_d, bb_d_d, alpha_d, this%m, n)
602 call device_glsc3_many(alpha, b_d, xx_d_d, coef%mult_d, this%m, n)
603 call device_memcpy(alpha, alpha_d, this%m, &
604 host_to_device, sync = .false.)
605 end if
606
607 if (neko_bcknd_opencl .eq. 1) then
608 do i = 1, this%m
609 call device_add2s2(xbar_d, xx_d(i), alpha(i), n)
610 call cmult(alpha, -1.0_rp, this%m)
611 call device_add2s2(b_d, bb_d(i), alpha(i), n)
612 end do
613 else
614 call device_add2s2_many(xbar_d, xx_d_d, alpha_d, this%m, n)
615 call device_cmult(alpha_d, -1.0_rp, this%m)
616 call device_add2s2_many(b_d, bb_d_d, alpha_d, this%m, n)
617 end if
618 end if
619
620 end associate
621 end subroutine device_project_on
622
623 !Choose between CPU or device for proj_ortho
624 subroutine proj_ortho(this, coef, n)
625 class(projection_t), intent(inout) :: this
626 type(coef_t), intent(in) :: coef
627 integer, intent(in) :: n
628
629 if (neko_bcknd_device .eq. 1) then
630 call device_proj_ortho(this, this%xx_d, this%bb_d, coef%mult_d, n)
631 else
632 call cpu_proj_ortho (this, this%xx, this%bb, coef%mult, n)
633 end if
634 end subroutine proj_ortho
635
636 !This is a lot more primitive than on the CPU
637 subroutine device_proj_ortho(this, xx_d, bb_d, w_d, n)
638 type(projection_t), intent(inout) :: this
639 integer, intent(in) :: n
640 type(c_ptr), dimension(this%L) :: xx_d, bb_d
641 type(c_ptr), intent(in) :: w_d
642 real(kind=rp) :: nrm, scl
643 real(kind=rp) :: alpha(this%L)
644 integer :: i
645
646 associate(m => this%m, xx_d_d => this%xx_d_d, &
647 bb_d_d => this%bb_d_d, alpha_d => this%alpha_d)
648
649 if (m .le. 0) return
650
651 if (neko_device_mpi .and. (neko_bcknd_opencl .ne. 1)) then
652 call device_project_ortho(alpha_d, bb_d(m), xx_d_d, bb_d_d, &
653 w_d, xx_d(m), this%m, n, nrm)
654 else
655 if (neko_bcknd_opencl .eq. 1)then
656 do i = 1, m
657 alpha(i) = device_glsc3(bb_d(m), xx_d(i), w_d,n)
658 end do
659 else
660 call device_glsc3_many(alpha, bb_d(m), xx_d_d, w_d, m, n)
661 end if
662 nrm = sqrt(alpha(m))
663 call cmult(alpha, -1.0_rp,m)
664 if (neko_bcknd_opencl .eq. 1)then
665 do i = 1, m - 1
666 call device_add2s2(xx_d(m), xx_d(i), alpha(i), n)
667 call device_add2s2(bb_d(m), bb_d(i), alpha(i), n)
668
669 alpha(i) = device_glsc3(bb_d(m), xx_d(i), w_d, n)
670 end do
671 else
672 call device_memcpy(alpha, alpha_d, this%m, &
673 host_to_device, sync = .false.)
674 call device_add2s2_many(xx_d(m), xx_d_d, alpha_d, m-1, n)
675 call device_add2s2_many(bb_d(m), bb_d_d, alpha_d, m-1, n)
676
677 call device_glsc3_many(alpha, bb_d(m), xx_d_d, w_d, m, n)
678 end if
679 call cmult(alpha, -1.0_rp,m)
680 if (neko_bcknd_opencl .eq. 1)then
681 do i = 1, m - 1
682 call device_add2s2(xx_d(m), xx_d(i), alpha(i), n)
683 call device_add2s2(bb_d(m), bb_d(i), alpha(i), n)
684 alpha(i) = device_glsc3(bb_d(m), xx_d(i), w_d, n)
685 end do
686 else
687 call device_memcpy(alpha, alpha_d, m, &
688 host_to_device, sync = .false.)
689 call device_add2s2_many(xx_d(m), xx_d_d, alpha_d, m-1, n)
690 call device_add2s2_many(bb_d(m), bb_d_d, alpha_d, m-1, n)
691 call device_glsc3_many(alpha, bb_d(m), xx_d_d, w_d, m, n)
692 end if
693 end if
694
695 alpha(m) = device_glsc3(xx_d(m), w_d, bb_d(m), n)
696 alpha(m) = sqrt(alpha(m))
697
698 if (alpha(m) .gt. this%tol*nrm) then !New vector is linearly independent
699 scl = 1.0_rp / alpha(m)
700 call device_cmult(xx_d(m), scl, n)
701 call device_cmult(bb_d(m), scl, n)
702
703
704 else !New vector is not linearly independent, forget about it
705 if (pe_rank .eq. 0) then
706 call neko_warning('New vector not linearly independent!')
707 end if
708 m = m - 1 !Remove column
709 end if
710
711 end associate
712
713 end subroutine device_proj_ortho
714
715
716 subroutine cpu_proj_ortho(this, xx, bb, w, n)
717 type(projection_t), intent(inout) :: this
718 integer, intent(in) :: n
719 real(kind=rp), dimension(n, this%L), intent(inout) :: xx, bb
720 real(kind=rp), dimension(n), intent(in) :: w
721 real(kind=rp) :: nrm, scl1, scl2, c, s, alpha_m
722 real(kind=rp) :: alpha(this%L), beta(this%L)
723 integer :: i, j, k, l, h, ierr
724
725 associate(m => this%m)
726
727 if (m .le. 0) return !No vectors to ortho-normalize
728
729 ! AX = B
730 ! Calculate dx, db: dx = x-XX^Tb, db=b-BX^Tb
731 call rzero(alpha, m)
732 !$omp parallel do private(j, k, l, s, c) reduction(+:alpha)
733 do i = 1, n, neko_blk_size
734 j = min(neko_blk_size, n-i+1)
735 do k = 1, m !First round CGS
736 s = 0.0_rp
737 c = 0.0_rp
738 do l = 0, (j-1)
739 s = s + xx(i+l,k) * w(i+l) * bb(i+l,m)
740 c = c + bb(i+l,k) * w(i+l) * xx(i+l,m)
741 end do
742 alpha(k) = alpha(k) + 0.5_rp * (s + c)
743 end do
744 end do
745 !$omp end parallel do
746
747 call mpi_allreduce(mpi_in_place, alpha, this%m, &
748 mpi_real_precision, mpi_sum, neko_comm, ierr)
749
750 nrm = sqrt(alpha(m)) !Calculate A-norm of new vector
751
752
753 !$omp parallel do private(j, k, l)
754 do i = 1, n, neko_blk_size
755 j = min(neko_blk_size, n-i+1)
756 do k = 1, m-1
757 do l = 0, (j-1)
758 xx(i+l,m) = xx(i+l,m) - alpha(k) * xx(i+l,k)
759 bb(i+l,m) = bb(i+l,m) - alpha(k) * bb(i+l,k)
760 end do
761 end do
762 end do
763 !$omp end parallel do
764 call rzero(beta,m)
765
766 !$omp parallel do private(j, k, l, s, c) reduction(+:beta)
767 do i = 1, n, neko_blk_size
768 j = min(neko_blk_size, n-i+1)
769 do k = 1, m-1
770 s = 0.0_rp
771 c = 0.0_rp
772 do l = 0, (j-1)
773 s = s + xx(i+l,k) * w(i+l) * bb(i+l,m)
774 c = c + bb(i+l,k) * w(i+l) * xx(i+l,m)
775 end do
776 beta(k) = beta(k) + 0.5_rp * (s + c)
777 end do
778 end do
779 !$omp end parallel do
780
781 call mpi_allreduce(mpi_in_place, beta, this%m-1, &
782 mpi_real_precision, mpi_sum, neko_comm, ierr)
783
784 alpha_m = 0.0_rp
785
786 !$omp parallel do private(j, k, l, s) reduction(+:alpha_m)
787 do i = 1, n, neko_blk_size
788 j = min(neko_blk_size,n-i+1)
789 do k = 1, m-1
790 do l = 0, (j-1)
791 xx(i+l,m) = xx(i+l,m) - beta(k) * xx(i+l,k)
792 bb(i+l,m) = bb(i+l,m) - beta(k) * bb(i+l,k)
793 end do
794 end do
795 s = 0.0_rp
796 do l = 0, (j-1)
797 s = s + xx(i+l,m) * w(i+l) * bb(i+l,m)
798 end do
799 alpha_m = alpha_m + s
800 end do
801 !$omp end parallel do
802 alpha(m) = alpha_m
803 do k = 1, m-1
804 alpha(k) = alpha(k) + beta(k)
805 end do
806
807 !alpha(m) = glsc3(xx(1,m), w, bb(1,m), n)
808 call mpi_allreduce(mpi_in_place, alpha(m), 1, &
809 mpi_real_precision, mpi_sum, neko_comm, ierr)
810 alpha(m) = sqrt(alpha(m))
811 !dx and db now stored in last column of xx and bb
812
813 if (alpha(m) .gt. this%tol*nrm) then !New vector is linearly independent
814 !Normalize dx and db
815 scl1 = 1.0_rp / alpha(m)
816 !$omp parallel do
817 do i = 0, (n - 1)
818 xx(1+i,m) = scl1 * xx(1+i,m)
819 bb(1+i,m) = scl1 * bb(1+i,m)
820 end do
821 !$omp end parallel do
822
823 else !New vector is not linearly independent, forget about it
824 k = m !location of rank deficient column
825 if (pe_rank .eq. 0) then
826 call neko_warning('New vector not linearly independent!')
827 end if
828 m = m - 1 !Remove column
829 end if
830
831 end associate
832
833 end subroutine cpu_proj_ortho
834
835 subroutine print_proj_info(this, string, tstep)
836 class(projection_t), intent(in) :: this
837 character(len=*), intent(in) :: string
838 integer, intent(in) :: tstep
839 character(len=LOG_SIZE) :: log_buf
840 character(len=12) :: tstep_str
841
842 if (this%proj_m .gt. 0) then
843 write(tstep_str, '(I12)') tstep
844 write(log_buf, '(A12,A14,1X,A8,A10,1X,I3,A16,1X,E10.4)') &
845 adjustl(tstep_str), ' | Projection:', string, &
846 ', Vectors:', this%proj_m, &
847 ', Original res.:', this%proj_res
848 call neko_log%message(log_buf)
849 call neko_log%newline()
850 end if
851
852 end subroutine print_proj_info
853
854 subroutine bcknd_clear(this, n)
855 class(projection_t), intent(inout) :: this
856 integer, intent(in) :: n
857 integer :: i, j
858
859 this%m = 0
860 this%proj_m = 0
861
862 do i = 1, this%L
863 if (neko_bcknd_device .eq. 1) then
864 call device_rzero(this%xx_d(i), n)
865 call device_rzero(this%bb_d(i), n)
866 else
867 do j = 1, n
868 this%xx(j,i) = 0.0_rp
869 this%bb(j,i) = 0.0_rp
870 end do
871 end if
872 end do
873
874 end subroutine bcknd_clear
875
876end module projection
Return the device pointer for an associated Fortran array.
Definition device.F90:113
Map a Fortran array to a device (allocate and associate)
Definition device.F90:83
Copy data between host and device (or device and device)
Definition device.F90:72
Unmap a Fortran array from a device (deassociate and free)
Definition device.F90:89
Defines a Matrix-vector product.
Definition ax.f90:34
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
Definition comm.F90:54
integer, public pe_rank
MPI rank.
Definition comm.F90:59
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
subroutine, public device_add2s2_many(y_d, x_d_d, a_d, j, n, strm)
subroutine, public device_add2s2(a_d, b_d, c1, n, strm)
Vector addition with scalar multiplication (multiplication on first argument)
subroutine, public device_add2(a_d, b_d, n, strm)
Vector addition .
subroutine, public device_rzero(a_d, n, strm)
Zero a real vector.
subroutine, public device_cmult(a_d, c, n, strm)
Multiplication by constant c .
subroutine, public device_glsc3_many(h, w_d, v_d_d, mult_d, j, n, strm)
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
real(kind=rp) function, public device_glsc3(a_d, b_d, c_d, n, strm)
Weighted inner product .
Interface for device projection.
subroutine, public device_proj_on(alpha_d, b_d, x_d_d, b_d_d, mult_d, xbar_d, j, n)
subroutine, public device_project_ortho(alpha_d, b_d, x_d_d, b_d_d, w_d, xm_d, j, n, nrm)
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:243
subroutine, public device_alloc(x_d, s)
Allocate memory on the device.
Definition device.F90:212
Gather-scatter.
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:80
integer, parameter, public log_size
Definition log.f90:46
Definition math.f90:60
subroutine, public cmult(a, c, n)
Multiplication by constant c .
Definition math.f90:507
real(kind=rp) function, public glsc3(a, b, c, n)
Weighted inner product .
Definition math.f90:1290
subroutine, public add2(a, b, n)
Vector addition .
Definition math.f90:903
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:294
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:238
subroutine, public add2s2(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on second argument)
Definition math.f90:1001
Build configurations.
integer, parameter neko_blk_size
integer, parameter neko_bcknd_device
integer, parameter neko_bcknd_opencl
logical, parameter neko_device_mpi
integer, parameter, public c_rp
Definition num_types.f90:15
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Profiling interface.
Definition profiler.F90:34
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
Definition profiler.F90:79
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Definition profiler.F90:116
Project x onto X, the space of old solutions and back again.
subroutine device_project_on(this, b, coef, n)
subroutine projection_free(this)
subroutine bcknd_clear(this, n)
subroutine projection_init(this, n, l, activ_step, reorthogonalize_basis)
subroutine device_proj_ortho(this, xx_d, bb_d, w_d, n)
subroutine bcknd_project_back(this, x, ax, coef, bclst, gs_h, n)
subroutine cpu_proj_ortho(this, xx, bb, w, n)
subroutine projection_pre_solving(this, b, tstep, coef, n, dt_controller, string, ax, gs_h, bclst)
subroutine bcknd_reorthogonalize_basis(this, ax, coef, gs_h, blst, n)
subroutine device_reorthogonalize_basis(this, ax, coef, gs_h, blst, n)
subroutine, public proj_ortho(this, coef, n)
subroutine bcknd_project_on(this, b, coef, n)
subroutine cpu_reorthogonalize_basis(this, ax, coef, gs_h, blst, n)
subroutine cpu_project_on(this, b, coef, n)
subroutine projection_post_solving(this, x, ax, coef, bclst, gs_h, n, tstep, dt_controller)
subroutine print_proj_info(this, string, tstep)
Implements scalar_projector_t.
Implements type time_step_controller.
Utilities.
Definition utils.f90:35
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:398
Base type for a matrix-vector product providing .
Definition ax.f90:43
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:93
Gather-scatter kernel.
Projector for scalar boundary conditions.