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
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
101 real(kind=
rp) :: tol = 1e-7_rp
103 real(kind=
rp) :: proj_res
104 integer :: proj_m = 0
105 integer :: activ_step
106 logical :: prj_reorthogonalize_basis = .false.
123 integer,
intent(in) :: n
124 integer,
intent(in) :: L
125 integer,
optional,
intent(in) :: activ_step
126 logical,
optional,
intent(in) :: reorthogonalize_basis
128 integer(c_size_t) :: ptr_size
136 if (
present(activ_step))
then
137 this%activ_step = activ_step
142 if (
present(reorthogonalize_basis))
then
143 this%prj_reorthogonalize_basis = reorthogonalize_basis
150 if (this%L .le. 0)
then
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)
159 call rzero(this%xx(1, i), n)
160 call rzero(this%bb(1, i), n)
164 allocate(this%xx_d(this%L))
165 allocate(this%bb_d(this%L))
168 call device_alloc(this%alpha_d, int(c_sizeof(dummy)*this%L, c_size_t))
174 this%xx_d(i) = c_null_ptr
175 call device_map(this%xx(:, i), 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)
182 ptr_size = c_sizeof(c_null_ptr) * this%L
184 ptr = c_loc(this%xx_d)
188 ptr = c_loc(this%bb_d)
199 if (c_associated(this%xx_d_d))
then
202 if (c_associated(this%bb_d_d))
then
205 if (c_associated(this%alpha_d))
then
208 if (
allocated(this%xx))
then
213 deallocate(this%xx_d)
217 if (
allocated(this%xbar))
then
221 deallocate(this%xbar)
223 if (
allocated(this%bb))
then
228 deallocate(this%bb_d)
236 string, Ax, gs_h, bclst)
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
244 type(
gs_t),
optional,
intent(inout) :: gs_h
245 class(
ax_t),
optional,
intent(in) :: Ax
246 character(len=*),
optional :: string
248 if (tstep .gt. this%activ_step .and. this%L .gt. 0)
then
249 if (dt_controller%is_variable_dt)
then
251 if (dt_controller%dt_last_change .eq. 0)
then
253 else if (dt_controller%dt_last_change .gt. this%activ_step - 1)
then
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)
261 call this%project_on(b, coef, n)
262 if (
present(string))
then
263 call this%log_info(string, tstep)
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)
272 call this%project_on(b, coef, n)
273 if (
present(string))
then
274 call this%log_info(string, tstep)
284 integer,
intent(inout) :: n
285 class(
ax_t),
intent(inout) :: Ax
286 class(
coef_t),
intent(inout) :: coef
288 type(
gs_t),
intent(inout) :: gs_h
289 real(kind=
rp),
intent(inout),
dimension(n) :: x
290 integer,
intent(in) :: tstep
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)
304 integer,
intent(inout) :: n
305 class(
coef_t),
intent(inout) :: coef
306 real(kind=
rp),
intent(inout),
dimension(n) :: b
318 integer,
intent(inout) :: n
319 class(
ax_t),
intent(inout) :: Ax
320 class(
coef_t),
intent(inout) :: coef
322 type(
gs_t),
intent(inout) :: gs_h
323 real(kind=
rp),
intent(inout),
dimension(n) :: x
331 if (this%m .gt. 0)
call device_add2(x_d, this%xbar_d, n)
332 if (this%m .eq. this%L)
then
335 this%m = min(this%m+1, this%L)
341 if (this%m .gt. 0)
call add2(x, this%xbar, n)
342 if (this%m .eq. this%L)
then
345 this%m = min(this%m+1, this%L)
348 call copy(this%xx(1, this%m), x, n)
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)
361 class(
ax_t),
intent(in) :: Ax
362 class(
coef_t),
intent(in) :: coef
363 type(
gs_t),
intent(inout) :: gs_h
365 integer,
intent(in) :: n
378 class(
ax_t),
intent(in) :: Ax
379 class(
coef_t),
intent(in) :: coef
380 type(
gs_t),
intent(inout) :: gs_h
382 integer,
intent(in) :: n
383 character(len=1000) :: msg
386 real(kind=
rp) :: alpha, s, norm_fac
387 real(kind=
rp) :: start_time, end_time, time
389 if (this%m .le. 0)
return
391 associate(xx => this%xx, bb => this%bb)
392 start_time = mpi_wtime()
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)
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)
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)
417 end_time = mpi_wtime()
418 time = end_time - start_time
419 write(msg,
'(A, E15.7)') &
420 "Projection basis reorthogonalization (s): ", time
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
435 real(kind=rp) :: alpha, s, norm_fac
436 real(kind=rp) :: start_time, end_time, time
438 if (this%m .le. 0)
return
440 associate(xx_d => this%xx_d, bb_d => this%bb_d)
441 start_time = mpi_wtime()
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)
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)
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)
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))
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
483 associate(xbar => this%xbar, xx => this%xx, &
486 if (this%m .le. 0)
return
489 call rzero(alpha, this%m)
490 this%proj_res = sqrt(glsc3(b, b, coef%mult, n) / coef%volume)
493 do i = 1, n, neko_blk_size
494 j = min(neko_blk_size, n-i+1)
498 s = s + xx(i+l, k) * coef%mult(i+l,1,1,1) * b(i+l)
500 alpha(k) = alpha(k) + s
506 call mpi_allreduce(mpi_in_place, alpha, this%m, &
507 mpi_real_precision, mpi_sum, neko_comm, ierr)
509 call rzero(work, this%m)
512 do i = 1, n, neko_blk_size
513 j = min(neko_blk_size, n-i+1)
515 xbar(i+l) = alpha(1) * xx(i+l,1)
516 b(i+l) = b(i+l) - alpha(1) * bb(i+l,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)
528 s = s + xx(i+l,k) * coef%mult(i+l,1,1,1) * b(i+l)
530 work(k) = work(k) + s
535 call mpi_allreduce(work, alpha, this%m, &
536 mpi_real_precision, mpi_sum, neko_comm, ierr)
539 do i = 1, n, neko_blk_size
540 j = min(neko_blk_size, n-i+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)
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)
560 b_d = device_get_ptr(b)
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)
565 if (this%m .le. 0)
return
569 this%proj_res = sqrt(device_glsc3(b_d, b_d, coef%mult_d, n)/coef%volume)
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)
575 if (neko_bcknd_opencl .eq. 1)
then
577 alpha(i) = device_glsc3(b_d, xx_d(i), coef%mult_d, n)
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.)
584 call device_rzero(xbar_d, n)
585 if (neko_bcknd_opencl .eq. 1)
then
587 call device_add2s2(xbar_d, xx_d(i), alpha(i), n)
589 call cmult(alpha, -1.0_rp, this%m)
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)
595 if (neko_bcknd_opencl .eq. 1)
then
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)
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.)
607 if (neko_bcknd_opencl .eq. 1)
then
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)
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)
626 type(coef_t),
intent(in) :: coef
627 integer,
intent(in) :: n
629 if (neko_bcknd_device .eq. 1)
then
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)
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)
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)
655 if (neko_bcknd_opencl .eq. 1)
then
657 alpha(i) = device_glsc3(bb_d(m), xx_d(i), w_d,n)
660 call device_glsc3_many(alpha, bb_d(m), xx_d_d, w_d, m, n)
663 call cmult(alpha, -1.0_rp,m)
664 if (neko_bcknd_opencl .eq. 1)
then
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)
669 alpha(i) = device_glsc3(bb_d(m), xx_d(i), w_d, n)
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)
677 call device_glsc3_many(alpha, bb_d(m), xx_d_d, w_d, m, n)
679 call cmult(alpha, -1.0_rp,m)
680 if (neko_bcknd_opencl .eq. 1)
then
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)
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)
695 alpha(m) = device_glsc3(xx_d(m), w_d, bb_d(m), n)
696 alpha(m) = sqrt(alpha(m))
698 if (alpha(m) .gt. this%tol*nrm)
then
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)
705 if (pe_rank .eq. 0)
then
706 call neko_warning(
'New vector not linearly independent!')
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
725 associate(m => this%m)
733 do i = 1, n, neko_blk_size
734 j = min(neko_blk_size, n-i+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)
742 alpha(k) = alpha(k) + 0.5_rp * (s + c)
747 call mpi_allreduce(mpi_in_place, alpha, this%m, &
748 mpi_real_precision, mpi_sum, neko_comm, ierr)
754 do i = 1, n, neko_blk_size
755 j = min(neko_blk_size, n-i+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)
767 do i = 1, n, neko_blk_size
768 j = min(neko_blk_size, n-i+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)
776 beta(k) = beta(k) + 0.5_rp * (s + c)
781 call mpi_allreduce(mpi_in_place, beta, this%m-1, &
782 mpi_real_precision, mpi_sum, neko_comm, ierr)
787 do i = 1, n, neko_blk_size
788 j = min(neko_blk_size,n-i+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)
797 s = s + xx(i+l,m) * w(i+l) * bb(i+l,m)
799 alpha_m = alpha_m + s
804 alpha(k) = alpha(k) + beta(k)
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))
813 if (alpha(m) .gt. this%tol*nrm)
then
815 scl1 = 1.0_rp / alpha(m)
818 xx(1+i,m) = scl1 * xx(1+i,m)
819 bb(1+i,m) = scl1 * bb(1+i,m)
825 if (pe_rank .eq. 0)
then
826 call neko_warning(
'New vector not linearly independent!')
837 character(len=*),
intent(in) :: string
838 integer,
intent(in) :: tstep
839 character(len=LOG_SIZE) :: log_buf
840 character(len=12) :: tstep_str
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()
856 integer,
intent(in) :: n
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)
868 this%xx(j,i) = 0.0_rp
869 this%bb(j,i) = 0.0_rp
Return the device pointer for an associated Fortran array.
Map a Fortran array to a device (allocate and associate)
Copy data between host and device (or device and device)
Unmap a Fortran array from a device (deassociate and free)
Defines a Matrix-vector product.
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
integer, public pe_rank
MPI rank.
type(mpi_comm), public neko_comm
MPI communicator.
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.
integer, parameter, public host_to_device
subroutine, public device_free(x_d)
Deallocate memory on the device.
subroutine, public device_alloc(x_d, s)
Allocate memory on the device.
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
subroutine, public cmult(a, c, n)
Multiplication by constant c .
real(kind=rp) function, public glsc3(a, b, c, n)
Weighted inner product .
subroutine, public add2(a, b, n)
Vector addition .
subroutine, public copy(a, b, n)
Copy a vector .
subroutine, public rzero(a, n)
Zero a real vector.
subroutine, public add2s2(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on second argument)
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
integer, parameter, public rp
Global precision used in computations.
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
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.
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Base type for a matrix-vector product providing .
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Projector for scalar boundary conditions.
Provides a tool to set time step dt.