Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
coef.f90
Go to the documentation of this file.
1! Copyright (c) 2020-2026, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
34module coefs
35 use gather_scatter, only : gs_t
36 use gs_ops, only : gs_op_add
38 use num_types, only : rp, sp, dp
39 use dofmap, only : dofmap_t
40 use space, only : space_t
41 use math, only : rone, invcol1, addcol3, subcol3, copy, &
44 use logger, only : neko_log, log_size
45 use mesh, only : mesh_t
51 use mxm_wrapper, only : mxm
56 use comm, only : neko_comm
58 use mpi_f08, only : mpi_allreduce, mpi_integer, mpi_sum
59 use, intrinsic :: iso_c_binding
60 implicit none
61 private
62
79 real(kind=rp), public, parameter :: neko_metric_cond_sp = 1.0e4_rp
80
113 real(kind=rp), public, parameter :: neko_metric_perturb_max = 1.0e-5_rp
114
118 integer, public, parameter :: coef_full = 0
131 integer, public, parameter :: coef_operator = 1
132
135 type, public :: coef_t
137 real(kind=rp), allocatable :: g11(:,:,:,:)
139 real(kind=rp), allocatable :: g22(:,:,:,:)
141 real(kind=rp), allocatable :: g33(:,:,:,:)
143 real(kind=rp), allocatable :: g12(:,:,:,:)
145 real(kind=rp), allocatable :: g13(:,:,:,:)
147 real(kind=rp), allocatable :: g23(:,:,:,:)
148
152 real(kind=rp) :: metric_cond = 0.0_rp
159 real(kind=rp) :: metric_scaled_cond = 0.0_rp
162 integer :: metric_degenerate = 0
168 real(kind=rp) :: metric_perturb = 0.0_rp
179 logical :: metric_sp_safe = .false.
181 real(kind=rp), allocatable :: g11_compressed(:,:,:,:)
183 real(kind=rp), allocatable :: g22_compressed(:,:,:,:)
185 real(kind=rp), allocatable :: g33_compressed(:,:,:,:)
187 real(kind=rp), allocatable :: g12_compressed(:,:,:,:)
189 real(kind=rp), allocatable :: g13_compressed(:,:,:,:)
191 real(kind=rp), allocatable :: g23_compressed(:,:,:,:)
193 integer, allocatable :: compression_inds(:)
194
195 real(kind=rp), allocatable :: mult(:,:,:,:)
200 real(kind=rp), allocatable :: dxdr(:,:,:,:), dydr(:,:,:,:), dzdr(:,:,:,:)
201 real(kind=rp), allocatable :: dxds(:,:,:,:), dyds(:,:,:,:), dzds(:,:,:,:)
202 real(kind=rp), allocatable :: dxdt(:,:,:,:), dydt(:,:,:,:), dzdt(:,:,:,:)
206 real(kind=rp), allocatable :: drdx(:,:,:,:), drdy(:,:,:,:), drdz(:,:,:,:)
207 real(kind=rp), allocatable :: dsdx(:,:,:,:), dsdy(:,:,:,:), dsdz(:,:,:,:)
208 real(kind=rp), allocatable :: dtdx(:,:,:,:), dtdy(:,:,:,:), dtdz(:,:,:,:)
209
210 real(kind=rp), allocatable :: h1(:,:,:,:)
211 real(kind=rp), allocatable :: h2(:,:,:,:)
212 logical :: ifh2
213
214 real(kind=rp), allocatable :: jac(:,:,:,:)
215 real(kind=rp), allocatable :: jacinv(:,:,:,:)
216 real(kind=rp), allocatable :: b(:,:,:,:)
217 real(kind=rp), allocatable :: binv(:,:,:,:)
218 real(kind=rp), pointer :: blag(:,:,:,:) => null()
219 real(kind=rp), pointer :: blaglag(:,:,:,:) => null()
220 real(kind=rp), allocatable :: area(:,:,:,:)
221 real(kind=rp), allocatable :: nx(:,:,:,:)
222 real(kind=rp), allocatable :: ny(:,:,:,:)
223 real(kind=rp), allocatable :: nz(:,:,:,:)
224 logical :: cyclic = .false.
225 integer, allocatable :: cyc_msk(:)
226 real(kind=rp), allocatable :: r11(:)
227 real(kind=rp), allocatable :: r12(:)
228
229 !! True if geometric metrics have been initialized
230 logical, private :: coef_metrics_initialized = .false.
231
234 integer :: scope = coef_full
235
237
238 real(kind=rp) :: volume = 0.0_rp
239
240 type(space_t), pointer :: xh => null()
241 type(mesh_t), pointer :: msh => null()
242 type(dofmap_t), pointer :: dof => null()
243 type(gs_t), pointer :: gs_h=> null()
244
245 !
246 ! Device pointers (if present)
247 !
248
249 type(c_ptr) :: g11_d = c_null_ptr
250 type(c_ptr) :: g22_d = c_null_ptr
251 type(c_ptr) :: g33_d = c_null_ptr
252 type(c_ptr) :: g12_d = c_null_ptr
253 type(c_ptr) :: g13_d = c_null_ptr
254 type(c_ptr) :: g23_d = c_null_ptr
255 type(c_ptr) :: dxdr_d = c_null_ptr
256 type(c_ptr) :: dydr_d = c_null_ptr
257 type(c_ptr) :: dzdr_d = c_null_ptr
258 type(c_ptr) :: dxds_d = c_null_ptr
259 type(c_ptr) :: dyds_d = c_null_ptr
260 type(c_ptr) :: dzds_d = c_null_ptr
261 type(c_ptr) :: dxdt_d = c_null_ptr
262 type(c_ptr) :: dydt_d = c_null_ptr
263 type(c_ptr) :: dzdt_d = c_null_ptr
264 type(c_ptr) :: drdx_d = c_null_ptr
265 type(c_ptr) :: drdy_d = c_null_ptr
266 type(c_ptr) :: drdz_d = c_null_ptr
267 type(c_ptr) :: dsdx_d = c_null_ptr
268 type(c_ptr) :: dsdy_d = c_null_ptr
269 type(c_ptr) :: dsdz_d = c_null_ptr
270 type(c_ptr) :: dtdx_d = c_null_ptr
271 type(c_ptr) :: dtdy_d = c_null_ptr
272 type(c_ptr) :: dtdz_d = c_null_ptr
273 type(c_ptr) :: mult_d = c_null_ptr
274 type(c_ptr) :: h1_d = c_null_ptr
275 type(c_ptr) :: h2_d = c_null_ptr
276 type(c_ptr) :: jac_d = c_null_ptr
277 type(c_ptr) :: jacinv_d = c_null_ptr
278 type(c_ptr) :: b_d = c_null_ptr
279 type(c_ptr) :: blag_d = c_null_ptr
280 type(c_ptr) :: blaglag_d = c_null_ptr
281 type(c_ptr) :: binv_d = c_null_ptr
282 type(c_ptr) :: area_d = c_null_ptr
283 type(c_ptr) :: nx_d = c_null_ptr
284 type(c_ptr) :: ny_d = c_null_ptr
285 type(c_ptr) :: nz_d = c_null_ptr
286 type(c_ptr) :: cyc_msk_d = c_null_ptr
287 type(c_ptr) :: r11_d = c_null_ptr
288 type(c_ptr) :: r12_d = c_null_ptr
289
291 integer :: metrics_version = 0
292
293 contains
294 procedure, private, pass(this) :: init_empty => coef_init_empty
295 procedure, private, pass(this) :: init_all => coef_init_all
296 procedure, pass(this) :: free => coef_free
297 procedure, pass(this) :: get_normal => coef_get_normal
298 procedure, pass(this) :: get_area => coef_get_area
299 procedure, pass(this) :: require_facets => coef_require_facets
300 procedure, pass(this) :: generate_cyclic_bc => coef_generate_cyclic_bc
301 procedure, pass(this) :: recompute_metrics => coef_recompute_metrics
302 procedure, pass(this) :: metric_condition => coef_metric_condition
303 procedure, pass(this) :: enable_b_history => coef_enable_lagged_mass
304 procedure, pass(this) :: update_b_history => coef_update_lagged_mass
305 generic :: init => init_empty, init_all
306 end type coef_t
307
308contains
309
311 subroutine coef_init_empty(this, Xh, msh)
312 class(coef_t), intent(inout) :: this
313 type(space_t), intent(inout), target :: Xh
314 type(mesh_t), intent(inout), target :: msh
315 integer :: n
316 call this%free()
317 this%msh => msh
318 this%Xh => xh
319
320 allocate(this%drdx(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
321 allocate(this%dsdx(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
322 allocate(this%dtdx(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
323
324 allocate(this%drdy(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
325 allocate(this%dsdy(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
326 allocate(this%dtdy(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
327
328 allocate(this%drdz(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
329 allocate(this%dsdz(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
330 allocate(this%dtdz(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
331
332
333 !
334 ! Setup device memory (if present)
335 !
336
337 n = this%Xh%lx * this%Xh%ly * this%Xh%lz * this%msh%nelv
338 if (neko_bcknd_device .eq. 1) then
339
340 call device_map(this%drdx, this%drdx_d, n)
341 call device_map(this%drdy, this%drdy_d, n)
342 call device_map(this%drdz, this%drdz_d, n)
343
344 call device_map(this%dsdx, this%dsdx_d, n)
345 call device_map(this%dsdy, this%dsdy_d, n)
346 call device_map(this%dsdz, this%dsdz_d, n)
347
348 call device_map(this%dtdx, this%dtdx_d, n)
349 call device_map(this%dtdy, this%dtdy_d, n)
350 call device_map(this%dtdz, this%dtdz_d, n)
351
352 end if
353
354 end subroutine coef_init_empty
355
360 subroutine coef_init_all(this, gs_h, scope)
361 class(coef_t), intent(inout), target :: this
362 type(gs_t), intent(inout), target :: gs_h
363 integer, intent(in), optional :: scope
364 integer :: n, m, ncyc
365
366 call this%free()
367
368 ! After free(), so that it survives into the initialized state
369 if (present(scope)) then
370 if (scope .ne. coef_full .and. scope .ne. coef_operator) then
371 call neko_error('Unknown coefficient scope')
372 end if
373 this%scope = scope
374 end if
375
376 call neko_log%section('Coefficients')
377
378 this%msh => gs_h%dofmap%msh
379 this%Xh => gs_h%dofmap%Xh
380 this%dof => gs_h%dofmap
381 this%gs_h => gs_h
382
383 !
384 ! Allocate arrays for geometric data
385 !
387 allocate(this%G11(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
388 allocate(this%G22(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
389 allocate(this%G33(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
390 allocate(this%G12(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
391 allocate(this%G13(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
392 allocate(this%G23(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
393
394 allocate(this%dxdr(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
395 allocate(this%dxds(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
396 allocate(this%dxdt(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
397
398 allocate(this%dydr(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
399 allocate(this%dyds(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
400 allocate(this%dydt(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
401
402 allocate(this%dzdr(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
403 allocate(this%dzds(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
404 allocate(this%dzdt(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
405
406 allocate(this%drdx(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
407 allocate(this%dsdx(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
408 allocate(this%dtdx(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
409
410 allocate(this%drdy(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
411 allocate(this%dsdy(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
412 allocate(this%dtdy(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
413
414 allocate(this%drdz(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
415 allocate(this%dsdz(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
416 allocate(this%dtdz(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
417
418 allocate(this%jac(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
419 allocate(this%jacinv(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
420
421 if (this%scope .eq. coef_full) then
422 allocate(this%area(this%Xh%lx, this%Xh%ly, 6, this%msh%nelv))
423 allocate(this%nx(this%Xh%lx, this%Xh%ly, 6, this%msh%nelv))
424 allocate(this%ny(this%Xh%lx, this%Xh%ly, 6, this%msh%nelv))
425 allocate(this%nz(this%Xh%lx, this%Xh%ly, 6, this%msh%nelv))
426 end if
427
428 allocate(this%B(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
429 allocate(this%Binv(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
430
431 ! We do this so in a static simulation we don't allocate extra memory
432 this%Blag => this%B
433 this%Blaglag => this%B
434
435 allocate(this%h1(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
436 allocate(this%h2(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
437
438 allocate(this%mult(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
439
440
441 !
442 ! Setup device memory (if present)
443 !
444
445 n = this%Xh%lx * this%Xh%ly * this%Xh%lz * this%msh%nelv
446 if (neko_bcknd_device .eq. 1) then
447 call device_map(this%G11, this%G11_d, n)
448 call device_map(this%G22, this%G22_d, n)
449 call device_map(this%G33, this%G33_d, n)
450 call device_map(this%G12, this%G12_d, n)
451 call device_map(this%G13, this%G13_d, n)
452 call device_map(this%G23, this%G23_d, n)
453
454 call device_map(this%dxdr, this%dxdr_d, n)
455 call device_map(this%dydr, this%dydr_d, n)
456 call device_map(this%dzdr, this%dzdr_d, n)
457
458 call device_map(this%dxds, this%dxds_d, n)
459 call device_map(this%dyds, this%dyds_d, n)
460 call device_map(this%dzds, this%dzds_d, n)
461
462 call device_map(this%dxdt, this%dxdt_d, n)
463 call device_map(this%dydt, this%dydt_d, n)
464 call device_map(this%dzdt, this%dzdt_d, n)
465
466 call device_map(this%drdx, this%drdx_d, n)
467 call device_map(this%drdy, this%drdy_d, n)
468 call device_map(this%drdz, this%drdz_d, n)
469
470 call device_map(this%dsdx, this%dsdx_d, n)
471 call device_map(this%dsdy, this%dsdy_d, n)
472 call device_map(this%dsdz, this%dsdz_d, n)
473
474 call device_map(this%dtdx, this%dtdx_d, n)
475 call device_map(this%dtdy, this%dtdy_d, n)
476 call device_map(this%dtdz, this%dtdz_d, n)
477
478 call device_map(this%mult, this%mult_d, n)
479 call device_map(this%h1, this%h1_d, n)
480 call device_map(this%h2, this%h2_d, n)
481
482 call device_map(this%jac, this%jac_d, n)
483 call device_map(this%jacinv, this%jacinv_d, n)
484 call device_map(this%B, this%B_d, n)
485 call device_map(this%Binv, this%Binv_d, n)
486
487 this%Blag_d = this%B_d
488 this%Blaglag_d = this%B_d
489
490 if (this%scope .eq. coef_full) then
491 m = this%Xh%lx * this%Xh%ly * 6 * this%msh%nelv
492
493 call device_map(this%area, this%area_d, m)
494 call device_map(this%nx, this%nx_d, m)
495 call device_map(this%ny, this%ny_d, m)
496 call device_map(this%nz, this%nz_d, m)
497 end if
498
499 end if
500
501 call coef_generate_dxyzdrst(this)
502
503 call coef_generate_geo(this)
504
505 ! call coef_generate_geo_compressed(this)
506
507 ! Both are dead weight under COEF_OPERATOR: nothing reads the facet
508 ! metrics, and the conditioning diagnostic is two per-point eigenvalue
509 ! solves plus three reductions spent on something no one consumes yet.
510 if (this%scope .eq. coef_full) then
511 call coef_metric_condition(this)
512
514 end if
515
516 call coef_generate_mass(this)
517
518 this%coef_metrics_initialized = .true.
519
520
521 ! This is a placeholder, just for now
522 ! We can probably find a prettier solution
523 if (neko_bcknd_device .eq. 1) then
524 call device_rone(this%h1_d, n)
525 call device_rone(this%h2_d, n)
526 call device_memcpy(this%h1, this%h1_d, n, &
527 device_to_host, sync = .false.)
528 call device_memcpy(this%h2, this%h2_d, n, &
529 device_to_host, sync = .false.)
530 else
531 call rone(this%h1,n)
532 call rone(this%h2,n)
533 end if
534
535 this%ifh2 = .false.
536
537 !
538 ! Set up multiplicity
539 !
540 if (neko_bcknd_device .eq. 1) then
541 call device_rone(this%mult_d, n)
542 else
543 call rone(this%mult, n)
544 end if
545
546 call gs_h%op(this%mult, n, gs_op_add)
547
548 if (neko_bcknd_device .eq. 1) then
549 call device_invcol1(this%mult_d, n)
550 call device_memcpy(this%mult, this%mult_d, n, &
551 device_to_host, sync = .true.)
552 else
553 call invcol1(this%mult, n)
554 end if
555
556 ncyc = this%msh%periodic%size * this%Xh%lx * this%Xh%lx
557 allocate(this%cyc_msk(0:ncyc))
558 this%cyc_msk(0) = ncyc + 1
559 if (ncyc .gt. 0) then
560 allocate(this%R11(ncyc))
561 allocate(this%R12(ncyc))
562
564 call rone(this%R11, ncyc)
565 call rzero(this%R12, ncyc)
566
567 if (neko_bcknd_device .eq. 1) then
568 call device_map(this%cyc_msk, this%cyc_msk_d, ncyc+1)
569 call device_map(this%R11, this%R11_d, ncyc)
570 call device_map(this%R12, this%R12_d, ncyc)
571
572 call device_memcpy(this%cyc_msk, this%cyc_msk_d, ncyc+1, &
573 host_to_device, sync = .false.)
574 call device_memcpy(this%R11, this%R11_d, ncyc, &
575 host_to_device, sync = .false.)
576 call device_memcpy(this%R12, this%R12_d, ncyc, &
577 host_to_device, sync = .false.)
578 end if
579
580 end if
581
582 call coef_release_scratch(this)
583
584 call neko_log%end_section()
585
586 end subroutine coef_init_all
587
589 subroutine coef_free(this)
590 class(coef_t), intent(inout), target :: this
591
592 if (allocated(this%G11)) then
593 if (neko_bcknd_device .eq. 1) call device_unmap(this%G11, this%G11_d)
594 deallocate(this%G11)
595 end if
596
597 if (allocated(this%G22)) then
598 if (neko_bcknd_device .eq. 1) call device_unmap(this%G22, this%G22_d)
599 deallocate(this%G22)
600 end if
601
602 if (allocated(this%G33)) then
603 if (neko_bcknd_device .eq. 1) call device_unmap(this%G33, this%G33_d)
604 deallocate(this%G33)
605 end if
606
607 if (allocated(this%G12)) then
608 if (neko_bcknd_device .eq. 1) call device_unmap(this%G12, this%G12_d)
609 deallocate(this%G12)
610 end if
611
612 if (allocated(this%G13)) then
613 if (neko_bcknd_device .eq. 1) call device_unmap(this%G13, this%G13_d)
614 deallocate(this%G13)
615 end if
616
617 if (allocated(this%G23)) then
618 if (neko_bcknd_device .eq. 1) call device_unmap(this%G23, this%G23_d)
619 deallocate(this%G23)
620 end if
621
622 if (allocated(this%G11_compressed)) then
623 deallocate(this%G11_compressed)
624 end if
625
626 if (allocated(this%compression_inds)) then
627 deallocate(this%compression_inds)
628 end if
629
630 if (allocated(this%G22_compressed)) then
631 deallocate(this%G22_compressed)
632 end if
633
634 if (allocated(this%G33_compressed)) then
635 deallocate(this%G33_compressed)
636 end if
637
638 if (allocated(this%G12_compressed)) then
639 deallocate(this%G12_compressed)
640 end if
641
642 if (allocated(this%G13_compressed)) then
643 deallocate(this%G13_compressed)
644 end if
645
646 if (allocated(this%G23_compressed)) then
647 deallocate(this%G23_compressed)
648 end if
649
650 if (allocated(this%mult)) then
651 if (neko_bcknd_device .eq. 1) call device_unmap(this%mult, this%mult_d)
652 deallocate(this%mult)
653 end if
654
655 if (associated(this%Blag) .and. &
656 .not. associated(this%Blag, this%B)) then
657 if (c_associated(this%Blag_d) .and. &
658 .not. c_associated(this%Blag_d, this%B_d)) then
659 call device_unmap(this%Blag, this%Blag_d)
660 end if
661 deallocate(this%Blag)
662 end if
663 nullify(this%Blag)
664
665 if (associated(this%Blaglag) .and. &
666 .not. associated(this%Blaglag, this%B)) then
667 if (c_associated(this%Blaglag_d) .and. &
668 .not. c_associated(this%Blaglag_d, this%B_d)) then
669 call device_unmap(this%Blaglag, this%Blaglag_d)
670 end if
671 deallocate(this%Blaglag)
672 end if
673 nullify(this%Blaglag)
674
675 if (c_associated(this%Blag_d) .and. &
676 .not. c_associated(this%Blag_d, this%B_d)) then
677 this%Blag_d = c_null_ptr
678 end if
679 this%Blag_d = c_null_ptr
680
681 if (c_associated(this%Blaglag_d) .and. &
682 .not. c_associated(this%Blaglag_d, this%B_d)) then
683 this%Blaglag_d = c_null_ptr
684 end if
685 this%Blaglag_d = c_null_ptr
686
687 if (allocated(this%B)) then
688 if (neko_bcknd_device .eq. 1) call device_unmap(this%B, this%B_d)
689 deallocate(this%B)
690 end if
691
692 if (allocated(this%Binv)) then
693 if (neko_bcknd_device .eq. 1) call device_unmap(this%Binv, this%Binv_d)
694 deallocate(this%Binv)
695 end if
696
697 if (allocated(this%dxdr)) then
698 if (neko_bcknd_device .eq. 1) call device_unmap(this%dxdr, this%dxdr_d)
699 deallocate(this%dxdr)
700 end if
701
702 if (allocated(this%dxds)) then
703 if (neko_bcknd_device .eq. 1) call device_unmap(this%dxds, this%dxds_d)
704 deallocate(this%dxds)
705 end if
706
707 if (allocated(this%dxdt)) then
708 if (neko_bcknd_device .eq. 1) call device_unmap(this%dxdt, this%dxdt_d)
709 deallocate(this%dxdt)
710 end if
711
712 if (allocated(this%dydr)) then
713 if (neko_bcknd_device .eq. 1) call device_unmap(this%dydr, this%dydr_d)
714 deallocate(this%dydr)
715 end if
716
717 if (allocated(this%dyds)) then
718 if (neko_bcknd_device .eq. 1) call device_unmap(this%dyds, this%dyds_d)
719 deallocate(this%dyds)
720 end if
721
722 if (allocated(this%dydt)) then
723 if (neko_bcknd_device .eq. 1) call device_unmap(this%dydt, this%dydt_d)
724 deallocate(this%dydt)
725 end if
726
727 if (allocated(this%dzdr)) then
728 if (neko_bcknd_device .eq. 1) call device_unmap(this%dzdr, this%dzdr_d)
729 deallocate(this%dzdr)
730 end if
731
732 if (allocated(this%dzds)) then
733 if (neko_bcknd_device .eq. 1) call device_unmap(this%dzds, this%dzds_d)
734 deallocate(this%dzds)
735 end if
736
737 if (allocated(this%dzdt)) then
738 if (neko_bcknd_device .eq. 1) call device_unmap(this%dzdt, this%dzdt_d)
739 deallocate(this%dzdt)
740 end if
741
742 if (allocated(this%drdx)) then
743 if (neko_bcknd_device .eq. 1) call device_unmap(this%drdx, this%drdx_d)
744 deallocate(this%drdx)
745 end if
746
747 if (allocated(this%dsdx)) then
748 if (neko_bcknd_device .eq. 1) call device_unmap(this%dsdx, this%dsdx_d)
749 deallocate(this%dsdx)
750 end if
751
752 if (allocated(this%dtdx)) then
753 if (neko_bcknd_device .eq. 1) call device_unmap(this%dtdx, this%dtdx_d)
754 deallocate(this%dtdx)
755 end if
756
757 if (allocated(this%drdy)) then
758 if (neko_bcknd_device .eq. 1) call device_unmap(this%drdy, this%drdy_d)
759 deallocate(this%drdy)
760 end if
761
762 if (allocated(this%dsdy)) then
763 if (neko_bcknd_device .eq. 1) call device_unmap(this%dsdy, this%dsdy_d)
764 deallocate(this%dsdy)
765 end if
766
767 if (allocated(this%dtdy)) then
768 if (neko_bcknd_device .eq. 1) call device_unmap(this%dtdy, this%dtdy_d)
769 deallocate(this%dtdy)
770 end if
771
772 if (allocated(this%drdz)) then
773 if (neko_bcknd_device .eq. 1) call device_unmap(this%drdz, this%drdz_d)
774 deallocate(this%drdz)
775 end if
776
777 if (allocated(this%dsdz)) then
778 if (neko_bcknd_device .eq. 1) call device_unmap(this%dsdz, this%dsdz_d)
779 deallocate(this%dsdz)
780 end if
781
782 if (allocated(this%dtdz)) then
783 if (neko_bcknd_device .eq. 1) call device_unmap(this%dtdz, this%dtdz_d)
784 deallocate(this%dtdz)
785 end if
786
787 if (allocated(this%jac)) then
788 if (neko_bcknd_device .eq. 1) call device_unmap(this%jac, this%jac_d)
789 deallocate(this%jac)
790 end if
791
792 if (allocated(this%jacinv)) then
793 if (neko_bcknd_device .eq. 1) then
794 call device_unmap(this%jacinv, this%jacinv_d)
795 end if
796 deallocate(this%jacinv)
797 end if
798
799 if (allocated(this%h1)) then
800 if (neko_bcknd_device .eq. 1) call device_unmap(this%h1, this%h1_d)
801 deallocate(this%h1)
802 end if
803
804 if (allocated(this%h2)) then
805 if (neko_bcknd_device .eq. 1) call device_unmap(this%h2, this%h2_d)
806 deallocate(this%h2)
807 end if
808
809 if (allocated(this%area)) then
810 if (neko_bcknd_device .eq. 1) call device_unmap(this%area, this%area_d)
811 deallocate(this%area)
812 end if
813
814 if (allocated(this%nx)) then
815 if (neko_bcknd_device .eq. 1) call device_unmap(this%nx, this%nx_d)
816 deallocate(this%nx)
817 end if
818
819 if (allocated(this%ny)) then
820 if (neko_bcknd_device .eq. 1) call device_unmap(this%ny, this%ny_d)
821 deallocate(this%ny)
822 end if
823
824 if (allocated(this%nz)) then
825 if (neko_bcknd_device .eq. 1) call device_unmap(this%nz, this%nz_d)
826 deallocate(this%nz)
827 end if
828
829 if (allocated(this%cyc_msk)) then
830 if (neko_bcknd_device .eq. 1) then
831 call device_unmap(this%cyc_msk, this%cyc_msk_d)
832 end if
833 deallocate(this%cyc_msk)
834 end if
835
836 if (allocated(this%R11)) then
837 if (neko_bcknd_device .eq. 1) call device_unmap(this%R11, this%R11_d)
838 deallocate(this%R11)
839 end if
840
841 if (allocated(this%R12)) then
842 if (neko_bcknd_device .eq. 1) call device_unmap(this%R12, this%R12_d)
843 deallocate(this%R12)
844 end if
845
846
847 nullify(this%msh)
848 nullify(this%Xh)
849 nullify(this%dof)
850 nullify(this%gs_h)
851
852 this%coef_metrics_initialized = .false.
853 this%scope = coef_full
854
855 end subroutine coef_free
856
867 subroutine coef_release_scratch(this)
868 class(coef_t), intent(inout), target :: this
869
870 if (this%scope .eq. coef_full) return
871
872 if (allocated(this%dxdr)) then
873 if (neko_bcknd_device .eq. 1) call device_unmap(this%dxdr, this%dxdr_d)
874 deallocate(this%dxdr)
875 end if
876
877 if (allocated(this%dxds)) then
878 if (neko_bcknd_device .eq. 1) call device_unmap(this%dxds, this%dxds_d)
879 deallocate(this%dxds)
880 end if
881
882 if (allocated(this%dxdt)) then
883 if (neko_bcknd_device .eq. 1) call device_unmap(this%dxdt, this%dxdt_d)
884 deallocate(this%dxdt)
885 end if
886
887 if (allocated(this%dydr)) then
888 if (neko_bcknd_device .eq. 1) call device_unmap(this%dydr, this%dydr_d)
889 deallocate(this%dydr)
890 end if
891
892 if (allocated(this%dyds)) then
893 if (neko_bcknd_device .eq. 1) call device_unmap(this%dyds, this%dyds_d)
894 deallocate(this%dyds)
895 end if
896
897 if (allocated(this%dydt)) then
898 if (neko_bcknd_device .eq. 1) call device_unmap(this%dydt, this%dydt_d)
899 deallocate(this%dydt)
900 end if
901
902 if (allocated(this%dzdr)) then
903 if (neko_bcknd_device .eq. 1) call device_unmap(this%dzdr, this%dzdr_d)
904 deallocate(this%dzdr)
905 end if
906
907 if (allocated(this%dzds)) then
908 if (neko_bcknd_device .eq. 1) call device_unmap(this%dzds, this%dzds_d)
909 deallocate(this%dzds)
910 end if
911
912 if (allocated(this%dzdt)) then
913 if (neko_bcknd_device .eq. 1) call device_unmap(this%dzdt, this%dzdt_d)
914 deallocate(this%dzdt)
915 end if
916
917 if (allocated(this%drdx)) then
918 if (neko_bcknd_device .eq. 1) call device_unmap(this%drdx, this%drdx_d)
919 deallocate(this%drdx)
920 end if
921
922 if (allocated(this%drdy)) then
923 if (neko_bcknd_device .eq. 1) call device_unmap(this%drdy, this%drdy_d)
924 deallocate(this%drdy)
925 end if
926
927 if (allocated(this%drdz)) then
928 if (neko_bcknd_device .eq. 1) call device_unmap(this%drdz, this%drdz_d)
929 deallocate(this%drdz)
930 end if
931
932 if (allocated(this%dsdx)) then
933 if (neko_bcknd_device .eq. 1) call device_unmap(this%dsdx, this%dsdx_d)
934 deallocate(this%dsdx)
935 end if
936
937 if (allocated(this%dsdy)) then
938 if (neko_bcknd_device .eq. 1) call device_unmap(this%dsdy, this%dsdy_d)
939 deallocate(this%dsdy)
940 end if
941
942 if (allocated(this%dsdz)) then
943 if (neko_bcknd_device .eq. 1) call device_unmap(this%dsdz, this%dsdz_d)
944 deallocate(this%dsdz)
945 end if
946
947 if (allocated(this%dtdx)) then
948 if (neko_bcknd_device .eq. 1) call device_unmap(this%dtdx, this%dtdx_d)
949 deallocate(this%dtdx)
950 end if
951
952 if (allocated(this%dtdy)) then
953 if (neko_bcknd_device .eq. 1) call device_unmap(this%dtdy, this%dtdy_d)
954 deallocate(this%dtdy)
955 end if
956
957 if (allocated(this%dtdz)) then
958 if (neko_bcknd_device .eq. 1) call device_unmap(this%dtdz, this%dtdz_d)
959 deallocate(this%dtdz)
960 end if
961
962 if (allocated(this%jac)) then
963 if (neko_bcknd_device .eq. 1) call device_unmap(this%jac, this%jac_d)
964 deallocate(this%jac)
965 end if
966
967 if (allocated(this%jacinv)) then
968 if (neko_bcknd_device .eq. 1) then
969 call device_unmap(this%jacinv, this%jacinv_d)
970 end if
971 deallocate(this%jacinv)
972 end if
973
974 if (allocated(this%Binv)) then
975 if (neko_bcknd_device .eq. 1) call device_unmap(this%Binv, this%Binv_d)
976 deallocate(this%Binv)
977 end if
978
979 if (allocated(this%area)) then
980 if (neko_bcknd_device .eq. 1) call device_unmap(this%area, this%area_d)
981 deallocate(this%area)
982 end if
983
984 if (allocated(this%nx)) then
985 if (neko_bcknd_device .eq. 1) call device_unmap(this%nx, this%nx_d)
986 deallocate(this%nx)
987 end if
988
989 if (allocated(this%ny)) then
990 if (neko_bcknd_device .eq. 1) call device_unmap(this%ny, this%ny_d)
991 deallocate(this%ny)
992 end if
993
994 if (allocated(this%nz)) then
995 if (neko_bcknd_device .eq. 1) call device_unmap(this%nz, this%nz_d)
996 deallocate(this%nz)
997 end if
998
999 end subroutine coef_release_scratch
1000
1002 type(coef_t), intent(inout) :: c
1003 integer :: e, i, lxy, lyz, ntot
1004
1005 lxy = c%Xh%lx*c%Xh%ly
1006 lyz = c%Xh%ly*c%Xh%lz
1007 ntot = c%dof%size()
1008
1009 associate(drdx => c%drdx, drdy => c%drdy, drdz => c%drdz, &
1010 dsdx => c%dsdx, dsdy => c%dsdy, dsdz => c%dsdz, &
1011 dtdx => c%dtdx, dtdy => c%dtdy, dtdz => c%dtdz, &
1012 dxdr => c%dxdr, dydr => c%dydr, dzdr => c%dzdr, &
1013 dxds => c%dxds, dyds => c%dyds, dzds => c%dzds, &
1014 dxdt => c%dxdt, dydt => c%dydt, dzdt => c%dzdt, &
1015 dx => c%Xh%dx, dy => c%Xh%dy, dz => c%Xh%dz, &
1016 x => c%dof%x%x, y => c%dof%y%x, z => c%dof%z%x, &
1017 lx => c%Xh%lx, ly => c%Xh%ly, lz => c%Xh%lz, &
1018 dyt => c%Xh%dyt, dzt => c%Xh%dzt, &
1019 jacinv => c%jacinv, jac => c%jac)
1020
1021 if (neko_bcknd_device .eq. 1) then
1022
1023 call device_coef_generate_dxydrst(c%drdx_d, c%drdy_d, c%drdz_d, &
1024 c%dsdx_d, c%dsdy_d, c%dsdz_d, c%dtdx_d, c%dtdy_d, c%dtdz_d, &
1025 c%dxdr_d, c%dydr_d, c%dzdr_d, c%dxds_d, c%dyds_d, c%dzds_d, &
1026 c%dxdt_d, c%dydt_d, c%dzdt_d, c%Xh%dx_d, c%Xh%dy_d, c%Xh%dz_d, &
1027 c%dof%x%x_d, c%dof%y%x_d, c%dof%z%x_d, c%jacinv_d, c%jac_d, &
1028 c%Xh%lx, c%msh%nelv)
1029
1030 ! copy to host only at initialization.
1031 if (.not. c%coef_metrics_initialized) then
1032 call device_memcpy(dxdr, c%dxdr_d, ntot, device_to_host, &
1033 sync = .false.)
1034 call device_memcpy(dydr, c%dydr_d, ntot, device_to_host, &
1035 sync = .false.)
1036 call device_memcpy(dzdr, c%dzdr_d, ntot, device_to_host, &
1037 sync = .false.)
1038 call device_memcpy(dxds, c%dxds_d, ntot, device_to_host, &
1039 sync = .false.)
1040 call device_memcpy(dyds, c%dyds_d, ntot, device_to_host, &
1041 sync = .false.)
1042 call device_memcpy(dzds, c%dzds_d, ntot, device_to_host, &
1043 sync = .false.)
1044 call device_memcpy(dxdt, c%dxdt_d, ntot, device_to_host, &
1045 sync = .false.)
1046 call device_memcpy(dydt, c%dydt_d, ntot, device_to_host, &
1047 sync = .false.)
1048 call device_memcpy(dzdt, c%dzdt_d, ntot, device_to_host, &
1049 sync = .false.)
1050 call device_memcpy(drdx, c%drdx_d, ntot, device_to_host, &
1051 sync = .false.)
1052 call device_memcpy(drdy, c%drdy_d, ntot, device_to_host, &
1053 sync = .false.)
1054 call device_memcpy(drdz, c%drdz_d, ntot, device_to_host, &
1055 sync = .false.)
1056 call device_memcpy(dsdx, c%dsdx_d, ntot, device_to_host, &
1057 sync = .false.)
1058 call device_memcpy(dsdy, c%dsdy_d, ntot, device_to_host, &
1059 sync = .false.)
1060 call device_memcpy(dsdz, c%dsdz_d, ntot, device_to_host, &
1061 sync = .false.)
1062 call device_memcpy(dtdx, c%dtdx_d, ntot, device_to_host, &
1063 sync = .false.)
1064 call device_memcpy(dtdy, c%dtdy_d, ntot, device_to_host, &
1065 sync = .false.)
1066 call device_memcpy(dtdz, c%dtdz_d, ntot, device_to_host, &
1067 sync = .false.)
1068 call device_memcpy(jac, c%jac_d, ntot, device_to_host, &
1069 sync = .false.)
1070 call device_memcpy(jacinv, c%jacinv_d, ntot, device_to_host, &
1071 sync = .true.)
1072 end if
1073
1074 else
1075 !$omp parallel do private(i)
1076 do e = 1, c%msh%nelv
1077 call mxm(dx, lx, x(1,1,1,e), lx, dxdr(1,1,1,e), lyz)
1078 call mxm(dx, lx, y(1,1,1,e), lx, dydr(1,1,1,e), lyz)
1079 call mxm(dx, lx, z(1,1,1,e), lx, dzdr(1,1,1,e), lyz)
1080
1081 do i = 1, lz
1082 call mxm(x(1,1,i,e), lx, dyt, ly, dxds(1,1,i,e), ly)
1083 call mxm(y(1,1,i,e), lx, dyt, ly, dyds(1,1,i,e), ly)
1084 call mxm(z(1,1,i,e), lx, dyt, ly, dzds(1,1,i,e), ly)
1085 end do
1086
1087 ! We actually take 2d into account, wow, need to do that for the rest.
1088 if (c%msh%gdim .eq. 3) then
1089 call mxm(x(1,1,1,e), lxy, dzt, lz, dxdt(1,1,1,e), lz)
1090 call mxm(y(1,1,1,e), lxy, dzt, lz, dydt(1,1,1,e), lz)
1091 call mxm(z(1,1,1,e), lxy, dzt, lz, dzdt(1,1,1,e), lz)
1092 else
1093 call rzero(dxdt(1,1,1,e), lxy)
1094 call rzero(dydt(1,1,1,e), lxy)
1095 call rone(dzdt(1,1,1,e), lxy)
1096 end if
1097 end do
1098 !$omp end parallel do
1099
1100 if (c%msh%gdim .eq. 2) then
1101 call rzero (jac, ntot)
1102 call addcol3 (jac, dxdr, dyds, ntot)
1103 call subcol3 (jac, dxds, dydr, ntot)
1104 call copy (drdx, dyds, ntot)
1105 call copy (drdy, dxds, ntot)
1106 call chsign (drdy, ntot)
1107 call copy (dsdx, dydr, ntot)
1108 call chsign (dsdx, ntot)
1109 call copy (dsdy, dxdr, ntot)
1110 call rzero (drdz, ntot)
1111 call rzero (dsdz, ntot)
1112 call rone (dtdz, ntot)
1113 else
1114 !$omp parallel private(i)
1115 !$omp do simd
1116 do i = 1, ntot
1117 c%jac(i, 1, 1, 1) = 0.0_rp
1118 end do
1119 !$omp end do simd
1120 !$omp do simd
1121 do i = 1, ntot
1122 c%jac(i, 1, 1, 1) = c%jac(i, 1, 1, 1) + ( c%dxdr(i, 1, 1, 1) &
1123 * c%dyds(i, 1, 1, 1) * c%dzdt(i, 1, 1, 1) )
1124
1125 c%jac(i, 1, 1, 1) = c%jac(i, 1, 1, 1) + ( c%dxdt(i, 1, 1, 1) &
1126 * c%dydr(i, 1, 1, 1) * c%dzds(i, 1, 1, 1) )
1127
1128 c%jac(i, 1, 1, 1) = c%jac(i, 1, 1, 1) + ( c%dxds(i, 1, 1, 1) &
1129 * c%dydt(i, 1, 1, 1) * c%dzdr(i, 1, 1, 1) )
1130 end do
1131 !$omp end do simd
1132 !$omp do simd
1133 do i = 1, ntot
1134 c%jac(i, 1, 1, 1) = c%jac(i, 1, 1, 1) - ( c%dxdr(i, 1, 1, 1) &
1135 * c%dydt(i, 1, 1, 1) * c%dzds(i, 1, 1, 1) )
1136
1137 c%jac(i, 1, 1, 1) = c%jac(i, 1, 1, 1) - ( c%dxds(i, 1, 1, 1) &
1138 * c%dydr(i, 1, 1, 1) * c%dzdt(i, 1, 1, 1) )
1139
1140 c%jac(i, 1, 1, 1) = c%jac(i, 1, 1, 1) - ( c%dxdt(i, 1, 1, 1) &
1141 * c%dyds(i, 1, 1, 1) * c%dzdr(i, 1, 1, 1) )
1142 end do
1143 !$omp end do simd
1144 !$omp do simd
1145 do i = 1, ntot
1146 c%drdx(i, 1, 1, 1) = c%dyds(i, 1, 1, 1) * c%dzdt(i, 1, 1, 1) &
1147 - c%dydt(i, 1, 1, 1) * c%dzds(i, 1, 1, 1)
1148
1149 c%drdy(i, 1, 1, 1) = c%dxdt(i, 1, 1, 1) * c%dzds(i, 1, 1, 1) &
1150 - c%dxds(i, 1, 1, 1) * c%dzdt(i, 1, 1, 1)
1151
1152 c%drdz(i, 1, 1, 1) = c%dxds(i, 1, 1, 1) * c%dydt(i, 1, 1, 1) &
1153 - c%dxdt(i, 1, 1, 1) * c%dyds(i, 1, 1, 1)
1154 end do
1155 !$omp end do simd
1156 !$omp do simd
1157 do i = 1, ntot
1158 c%dsdx(i, 1, 1, 1) = c%dydt(i, 1, 1, 1) * c%dzdr(i, 1, 1, 1) &
1159 - c%dydr(i, 1, 1, 1) * c%dzdt(i, 1, 1, 1)
1160
1161 c%dsdy(i, 1, 1, 1) = c%dxdr(i, 1, 1, 1) * c%dzdt(i, 1, 1, 1) &
1162 - c%dxdt(i, 1, 1, 1) * c%dzdr(i, 1, 1, 1)
1163
1164 c%dsdz(i, 1, 1, 1) = c%dxdt(i, 1, 1, 1) * c%dydr(i, 1, 1, 1) &
1165 - c%dxdr(i, 1, 1, 1) * c%dydt(i, 1, 1, 1)
1166 end do
1167 !$omp end do simd
1168 !$omp do simd
1169 do i = 1, ntot
1170 c%dtdx(i, 1, 1, 1) = c%dydr(i, 1, 1, 1) * c%dzds(i, 1, 1, 1) &
1171 - c%dyds(i, 1, 1, 1) * c%dzdr(i, 1, 1, 1)
1172
1173 c%dtdy(i, 1, 1, 1) = c%dxds(i, 1, 1, 1) * c%dzdr(i, 1, 1, 1) &
1174 - c%dxdr(i, 1, 1, 1) * c%dzds(i, 1, 1, 1)
1175
1176 c%dtdz(i, 1, 1, 1) = c%dxdr(i, 1, 1, 1) * c%dyds(i, 1, 1, 1) &
1177 - c%dxds(i, 1, 1, 1) * c%dydr(i, 1, 1, 1)
1178 end do
1179 !$omp end do simd
1180 !$omp end parallel
1181 end if
1182 call invers2(jacinv, jac, ntot)
1183 end if
1184 end associate
1185
1186 end subroutine coef_generate_dxyzdrst
1187
1190 subroutine coef_generate_geo(c)
1191 type(coef_t), intent(inout) :: c
1192 integer :: e, i, lxyz, ntot
1193
1194 lxyz = c%Xh%lx * c%Xh%ly * c%Xh%lz
1195 ntot = c%dof%size()
1196
1197 if (neko_bcknd_device .eq. 1) then
1198
1199 call device_coef_generate_geo(c%G11_d, c%G12_d, c%G13_d, &
1200 c%G22_d, c%G23_d, c%G33_d, &
1201 c%drdx_d, c%drdy_d, c%drdz_d, &
1202 c%dsdx_d, c%dsdy_d, c%dsdz_d, &
1203 c%dtdx_d, c%dtdy_d, c%dtdz_d, &
1204 c%jacinv_d, c%Xh%w3_d, c%msh%nelv, &
1205 c%Xh%lx, c%msh%gdim)
1206
1207 ! copy to host only at initialization.
1208 if (.not. c%coef_metrics_initialized) then
1209 call device_memcpy(c%G11, c%G11_d, ntot, device_to_host, &
1210 sync = .false.)
1211 call device_memcpy(c%G22, c%G22_d, ntot, device_to_host, &
1212 sync = .false.)
1213 call device_memcpy(c%G33, c%G33_d, ntot, device_to_host, &
1214 sync = .false.)
1215 call device_memcpy(c%G12, c%G12_d, ntot, device_to_host, &
1216 sync = .false.)
1217 call device_memcpy(c%G13, c%G13_d, ntot, device_to_host, &
1218 sync = .false.)
1219 call device_memcpy(c%G23, c%G23_d, ntot, device_to_host, &
1220 sync = .true.)
1221 end if
1222
1223 else
1224 if (c%msh%gdim .eq. 2) then
1225
1226 do i = 1, ntot
1227 c%G11(i, 1, 1, 1) = c%drdx(i, 1, 1, 1) * c%drdx(i, 1, 1, 1) &
1228 + c%drdy(i, 1, 1, 1) * c%drdy(i, 1, 1, 1)
1229
1230 c%G22(i, 1, 1, 1) = c%dsdx(i, 1, 1, 1) * c%dsdx(i, 1, 1, 1) &
1231 + c%dsdy(i, 1, 1, 1) * c%dsdy(i, 1, 1, 1)
1232
1233 c%G12(i, 1, 1, 1) = c%drdx(i, 1, 1, 1) * c%dsdx(i, 1, 1, 1) &
1234 + c%drdy(i, 1, 1, 1) * c%dsdy(i, 1, 1, 1)
1235 end do
1236
1237 do i = 1, ntot
1238 c%G11(i, 1, 1, 1) = c%G11(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1239 c%G22(i, 1, 1, 1) = c%G22(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1240 c%G12(i, 1, 1, 1) = c%G12(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1241 c%G33(i, 1, 1, 1) = 0.0_rp
1242 c%G13(i, 1, 1, 1) = 0.0_rp
1243 c%G23(i, 1, 1, 1) = 0.0_rp
1244 end do
1245
1246 do concurrent(e = 1:c%msh%nelv)
1247 do concurrent(i = 1:lxyz)
1248 c%G11(i,1,1,e) = c%G11(i,1,1,e) * c%Xh%w3(i,1,1)
1249 c%G22(i,1,1,e) = c%G22(i,1,1,e) * c%Xh%w3(i,1,1)
1250 c%G12(i,1,1,e) = c%G12(i,1,1,e) * c%Xh%w3(i,1,1)
1251 end do
1252 end do
1253
1254 else
1255 !$omp parallel private(i)
1256 !$omp do
1257 do i = 1, ntot
1258 c%G11(i, 1, 1, 1) = c%drdx(i, 1, 1, 1) * c%drdx(i, 1, 1, 1) &
1259 + c%drdy(i, 1, 1, 1) * c%drdy(i, 1, 1, 1) &
1260 + c%drdz(i, 1, 1, 1) * c%drdz(i, 1, 1, 1)
1261
1262 c%G22(i, 1, 1, 1) = c%dsdx(i, 1, 1, 1) * c%dsdx(i, 1, 1, 1) &
1263 + c%dsdy(i, 1, 1, 1) * c%dsdy(i, 1, 1, 1) &
1264 + c%dsdz(i, 1, 1, 1) * c%dsdz(i, 1, 1, 1)
1265
1266 c%G33(i, 1, 1, 1) = c%dtdx(i, 1, 1, 1) * c%dtdx(i, 1, 1, 1) &
1267 + c%dtdy(i, 1, 1, 1) * c%dtdy(i, 1, 1, 1) &
1268 + c%dtdz(i, 1, 1, 1) * c%dtdz(i, 1, 1, 1)
1269 end do
1270 !$omp end do
1271 !$omp do
1272 do i = 1, ntot
1273 c%G11(i, 1, 1, 1) = c%G11(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1274 c%G22(i, 1, 1, 1) = c%G22(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1275 c%G33(i, 1, 1, 1) = c%G33(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1276 end do
1277 !$omp end do
1278 !$omp do
1279 do i = 1, ntot
1280 c%G12(i, 1, 1, 1) = c%drdx(i, 1, 1, 1) * c%dsdx(i, 1, 1, 1) &
1281 + c%drdy(i, 1, 1, 1) * c%dsdy(i, 1, 1, 1) &
1282 + c%drdz(i, 1, 1, 1) * c%dsdz(i, 1, 1, 1)
1283
1284 c%G13(i, 1, 1, 1) = c%drdx(i, 1, 1, 1) * c%dtdx(i, 1, 1, 1) &
1285 + c%drdy(i, 1, 1, 1) * c%dtdy(i, 1, 1, 1) &
1286 + c%drdz(i, 1, 1, 1) * c%dtdz(i, 1, 1, 1)
1287
1288 c%G23(i, 1, 1, 1) = c%dsdx(i, 1, 1, 1) * c%dtdx(i, 1, 1, 1) &
1289 + c%dsdy(i, 1, 1, 1) * c%dtdy(i, 1, 1, 1) &
1290 + c%dsdz(i, 1, 1, 1) * c%dtdz(i, 1, 1, 1)
1291 end do
1292 !$omp end do
1293 !$omp do
1294 do i = 1, ntot
1295 c%G12(i, 1, 1, 1) = c%G12(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1296 c%G13(i, 1, 1, 1) = c%G13(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1297 c%G23(i, 1, 1, 1) = c%G23(i, 1, 1, 1) * c%jacinv(i, 1, 1, 1)
1298 end do
1299 !$omp end do
1300 !$omp do
1301 do e = 1, c%msh%nelv
1302 do concurrent(i = 1:lxyz)
1303 c%G11(i,1,1,e) = c%G11(i,1,1,e) * c%Xh%w3(i,1,1)
1304 c%G22(i,1,1,e) = c%G22(i,1,1,e) * c%Xh%w3(i,1,1)
1305 c%G12(i,1,1,e) = c%G12(i,1,1,e) * c%Xh%w3(i,1,1)
1306
1307 c%G33(i,1,1,e) = c%G33(i,1,1,e) * c%Xh%w3(i,1,1)
1308 c%G13(i,1,1,e) = c%G13(i,1,1,e) * c%Xh%w3(i,1,1)
1309 c%G23(i,1,1,e) = c%G23(i,1,1,e) * c%Xh%w3(i,1,1)
1310 end do
1311 end do
1312 !$omp end do
1313 !$omp end parallel
1314 end if
1315 end if
1316
1317 end subroutine coef_generate_geo
1318
1377 subroutine coef_metric_condition(this)
1378 class(coef_t), intent(inout) :: this
1379 real(kind=dp) :: e1, e2, e3, scal
1380 real(kind=dp) :: c1, c2, c3, c12, c13, c23
1381 real(kind=rp) :: kmax, kcmax, tmp(1)
1382 integer :: i, j, k, e, n, ndeg, ndeg_glb, ierr
1383 character(len=LOG_SIZE) :: log_buf
1384
1385 n = this%dof%size()
1386
1387 ! Post-initialization the host copy is stale on device builds
1388 if (neko_bcknd_device .eq. 1 .and. this%coef_metrics_initialized) then
1389 call device_memcpy(this%G11, this%G11_d, n, device_to_host, &
1390 sync = .false.)
1391 call device_memcpy(this%G22, this%G22_d, n, device_to_host, &
1392 sync = .false.)
1393 call device_memcpy(this%G33, this%G33_d, n, device_to_host, &
1394 sync = .false.)
1395 call device_memcpy(this%G12, this%G12_d, n, device_to_host, &
1396 sync = .false.)
1397 call device_memcpy(this%G13, this%G13_d, n, device_to_host, &
1398 sync = .false.)
1399 call device_memcpy(this%G23, this%G23_d, n, device_to_host, &
1400 sync = .true.)
1401 end if
1402
1403 kmax = 0.0_rp
1404 kcmax = 0.0_rp
1405 ndeg = 0
1406
1407 do e = 1, this%msh%nelv
1408 do k = 1, this%Xh%lz
1409 do j = 1, this%Xh%ly
1410 do i = 1, this%Xh%lx
1411
1412 ! Scale out the magnitude before the eigenvalue solve; the
1413 ! condition number is invariant under it and w3*J spans a
1414 ! wide range within an element
1415 scal = max(abs(real(this%G11(i,j,k,e), dp)), &
1416 abs(real(this%G22(i,j,k,e), dp)))
1417 scal = max(scal, abs(real(this%G33(i,j,k,e), dp)))
1418 scal = max(scal, abs(real(this%G12(i,j,k,e), dp)))
1419 scal = max(scal, abs(real(this%G13(i,j,k,e), dp)))
1420 scal = max(scal, abs(real(this%G23(i,j,k,e), dp)))
1421
1422 if (scal .le. 0.0_dp) then
1423 ndeg = ndeg + 1
1424 cycle
1425 end if
1426
1427 if (this%msh%gdim .eq. 2) then
1428 call eig_sym2(real(this%G11(i,j,k,e), dp) / scal, &
1429 real(this%G22(i,j,k,e), dp) / scal, &
1430 real(this%G12(i,j,k,e), dp) / scal, e1, e3)
1431 else
1432 call eig_sym3(real(this%G11(i,j,k,e), dp) / scal, &
1433 real(this%G22(i,j,k,e), dp) / scal, &
1434 real(this%G33(i,j,k,e), dp) / scal, &
1435 real(this%G12(i,j,k,e), dp) / scal, &
1436 real(this%G13(i,j,k,e), dp) / scal, &
1437 real(this%G23(i,j,k,e), dp) / scal, e1, e2, e3)
1438 end if
1439
1440 if (e3 .le. 0.0_dp) then
1441 ndeg = ndeg + 1
1442 else
1443 kmax = max(kmax, real(e1 / e3, rp))
1444
1445 ! Jacobi scale the metric: C_ij = G_ij/sqrt(G_ii G_jj).
1446 ! kappa(C) is what bounds the effect of rounding G to a
1447 ! lower precision, and unlike kappa(G) it is independent
1448 ! of the element aspect ratio. The point is positive
1449 ! definite here, so the diagonal is strictly positive and
1450 ! the square roots are safe. An orthogonal element gives
1451 ! the identity, which eig_sym3 returns exactly through
1452 ! its isotropic branch.
1453 c12 = real(this%G12(i,j,k,e), dp) &
1454 / sqrt(real(this%G11(i,j,k,e), dp) &
1455 * real(this%G22(i,j,k,e), dp))
1456
1457 if (this%msh%gdim .eq. 2) then
1458 call eig_sym2(1.0_dp, 1.0_dp, c12, c1, c3)
1459 else
1460 c13 = real(this%G13(i,j,k,e), dp) &
1461 / sqrt(real(this%G11(i,j,k,e), dp) &
1462 * real(this%G33(i,j,k,e), dp))
1463 c23 = real(this%G23(i,j,k,e), dp) &
1464 / sqrt(real(this%G22(i,j,k,e), dp) &
1465 * real(this%G33(i,j,k,e), dp))
1466 call eig_sym3(1.0_dp, 1.0_dp, 1.0_dp, &
1467 c12, c13, c23, c1, c2, c3)
1468 end if
1469
1470 if (c3 .gt. 0.0_dp) then
1471 kcmax = max(kcmax, real(c1 / c3, rp))
1472 else
1473 ! C is a positive diagonal congruence of a metric
1474 ! already found definite, so this is unreachable
1475 ! analytically. Fail safe rather than underreport.
1476 kcmax = huge(0.0_rp)
1477 end if
1478 end if
1479
1480 end do
1481 end do
1482 end do
1483 end do
1484
1485 tmp(1) = kmax
1486 this%metric_cond = glmax(tmp, 1)
1487
1488 tmp(1) = kcmax
1489 this%metric_scaled_cond = glmax(tmp, 1)
1490
1491 call mpi_allreduce(ndeg, ndeg_glb, 1, mpi_integer, mpi_sum, &
1492 neko_comm, ierr)
1493 this%metric_degenerate = ndeg_glb
1494
1495 ! The two condition numbers enter through different unit roundoffs, so
1496 ! the estimate is additive: storage rounding of G contributes
1497 ! eps_sp*kappa(C) and accumulation in rp contributes eps_rp*kappa(G).
1498 ! On a double build the second term all but vanishes and skew decides; on
1499 ! an rp = sp build it dominates and aspect ratio decides. No test on the
1500 ! build is needed, which is the point of writing it this way.
1501 this%metric_perturb = real(neko_eps_sp, rp) * this%metric_scaled_cond &
1502 + neko_eps * this%metric_cond
1503
1504 this%metric_sp_safe = (this%metric_degenerate .eq. 0) .and. &
1505 (this%metric_perturb .le. neko_metric_perturb_max)
1506
1507 write(log_buf, '(A,ES12.5)') 'Metric condition : ', this%metric_cond
1508 call neko_log%message(log_buf)
1509 write(log_buf, '(A,ES12.5)') 'Metric skew cond : ', &
1510 this%metric_scaled_cond
1511 call neko_log%message(log_buf)
1512 write(log_buf, '(A,ES12.5)') 'Metric perturb : ', this%metric_perturb
1513 call neko_log%message(log_buf)
1514 write(log_buf, '(A,L1)') 'Metric fp32 safe : ', this%metric_sp_safe
1515 call neko_log%message(log_buf)
1516
1517 ! Three independent questions, reported independently: can the solve
1518 ! break down, how far wrong is the operator, and is the mesh valid at
1519 ! all. They are not grades of one thing, so none suppresses another -- a
1520 ! wall resolved boundary layer in a single precision build trips the
1521 ! first two at once, and both are worth saying, because the definiteness
1522 ! limit is a possibility while the perturbation is a certainty.
1523
1524 ! Past the arithmetic limit the local operator can lose positive
1525 ! definiteness and a Krylov solve can break down rather than degrade,
1526 ! which is only reachable when rp is sp. Reported rather than fatal: the
1527 ! threshold keeps three orders of margin below 1/eps_sp, so crossing it
1528 ! makes breakdown possible, not certain, and the run may well be fine.
1529 if (rp .eq. sp .and. this%metric_cond .gt. neko_metric_cond_sp) then
1530 write(log_buf, '(A,ES12.5)') &
1531 'Metric too ill conditioned for single precision, limit ', &
1533 call neko_log%warning(log_buf)
1534 call neko_log%message('Geometric factors may lose positive ' // &
1535 'definiteness, consider a double precision build')
1536 end if
1537
1538 ! How much the single precision factors actually perturb the operator,
1539 ! regardless of whether the definiteness limit above was also crossed.
1540 ! On a single precision build that error is being incurred now, so it
1541 ! warrants a warning; on a double precision build it describes a storage
1542 ! path that may not be in use, so it is recorded without one. Which of
1543 ! the two terms dominates is the actionable part: skew is a meshing
1544 ! problem, aspect ratio is a precision problem, and they have different
1545 ! remedies.
1546 if (this%metric_perturb .gt. neko_metric_perturb_max) then
1547 if (rp .eq. sp) then
1548 write(log_buf, '(A,ES12.5,A,ES12.5)') &
1549 'Single precision metric error ', this%metric_perturb, &
1550 ', tolerance ', neko_metric_perturb_max
1551 call neko_log%warning(log_buf)
1552 else
1553 call neko_log%message('Single precision storage of the ' // &
1554 'geometric factors would exceed the error tolerance')
1555 end if
1556
1557 if (real(neko_eps_sp, rp) * this%metric_scaled_cond .ge. &
1558 neko_eps * this%metric_cond) then
1559 call neko_log%message('Dominated by element skew')
1560 else
1561 call neko_log%message('Dominated by element aspect ratio')
1562 end if
1563 end if
1564
1565 ! A metric that is not positive definite is a degenerate or inverted
1566 ! element, which is a mesh problem in any precision. Reported rather than
1567 ! fatal, since this is a diagnostic and the rest of the setup may still
1568 ! want to run
1569 if (this%metric_degenerate .gt. 0) then
1570 write(log_buf, '(A,I0)') &
1571 'Non positive definite metric at points: ', this%metric_degenerate
1572 call neko_log%error(log_buf)
1573 end if
1574
1575 end subroutine coef_metric_condition
1576
1580 type(coef_t), intent(inout) :: c
1581 integer :: e, m, i, lxyz, m_max
1582 integer, allocatable :: c_inds_rev(:) ! reverse compression indices map
1583 real(kind=rp) :: ctol = 1.0e-7_rp
1584 real(kind=rp) :: diff = 0.0_rp
1585
1586 ! First step, allocate full-size lookup structure for entire mesh
1587 allocate(c%compression_inds(c%msh%nelv))
1588 allocate(c_inds_rev(c%msh%nelv))
1589
1590 ! Second step, loop over all elements, compute compression mapping
1591 ! First entry must be itself to get started
1592 m_max = 1
1593 c%compression_inds(1) = 1
1594 c_inds_rev = 0
1595 c_inds_rev(1) = 1
1596
1597 ! Loop over elements, but skip first
1598 lxyz = c%Xh%lx * c%Xh%ly * c%Xh%lz
1599 do e = 2, c%msh%nelv
1600 ! Loop over possible compression candidates
1601 do m = 1, m_max
1602 diff = 0.0_rp
1603 ! Loop over quadrature points
1604 do i = 1, lxyz
1605 ! diff += abs( \| G(i,:,:,e) - G(i,:,:,reverse(m)) \|_l1 )
1606 diff = diff + abs(c%G11(i,1,1,e) - c%G11(i,1,1,c_inds_rev(m))) &
1607 + 2.0*abs(c%G12(i,1,1,e) - c%G12(i,1,1,c_inds_rev(m))) &
1608 + 2.0*abs(c%G13(i,1,1,e) - c%G13(i,1,1,c_inds_rev(m))) &
1609 + abs(c%G22(i,1,1,e) - c%G22(i,1,1,c_inds_rev(m))) &
1610 + 2.0*abs(c%G23(i,1,1,e) - c%G23(i,1,1,c_inds_rev(m))) &
1611 + abs(c%G33(i,1,1,e) - c%G33(i,1,1,c_inds_rev(m)))
1612 end do
1613
1614 ! match is found; mapping(e) is redundant
1615 if ( diff .le. ctol ) then
1616 c%compression_inds(e) = m
1617 exit
1618 end if
1619 end do
1620
1621 ! never found a match
1622 if ( diff .gt. ctol ) then
1623 m_max = m_max + 1
1624 c%compression_inds(e) = m_max
1625 c_inds_rev(m_max) = e
1626 end if
1627 end do
1628
1629 write(*,*)
1630 write(*,*) '------Mapping Compression-----'
1631 write(*,*) 'Compressed from ', c%msh%nelv, ' to ', m_max
1632
1633 ! Third step, allocate and fill Gij_compressed objects
1634 allocate(c%G11_compressed(c%Xh%lx, c%Xh%ly, c%Xh%lz, m_max))
1635 allocate(c%G22_compressed(c%Xh%lx, c%Xh%ly, c%Xh%lz, m_max))
1636 allocate(c%G33_compressed(c%Xh%lx, c%Xh%ly, c%Xh%lz, m_max))
1637 allocate(c%G12_compressed(c%Xh%lx, c%Xh%ly, c%Xh%lz, m_max))
1638 allocate(c%G13_compressed(c%Xh%lx, c%Xh%ly, c%Xh%lz, m_max))
1639 allocate(c%G23_compressed(c%Xh%lx, c%Xh%ly, c%Xh%lz, m_max))
1640 do m = 1, m_max
1641 do i = 1, lxyz
1642 c%G11_compressed(i,1,1,m) = c%G11(i,1,1,c_inds_rev(m))
1643 c%G22_compressed(i,1,1,m) = c%G22(i,1,1,c_inds_rev(m))
1644 c%G33_compressed(i,1,1,m) = c%G33(i,1,1,c_inds_rev(m))
1645 c%G12_compressed(i,1,1,m) = c%G12(i,1,1,c_inds_rev(m))
1646 c%G13_compressed(i,1,1,m) = c%G13(i,1,1,c_inds_rev(m))
1647 c%G23_compressed(i,1,1,m) = c%G23(i,1,1,c_inds_rev(m))
1648 end do
1649 end do
1650
1651 deallocate(c_inds_rev)
1652
1653 end subroutine coef_generate_geo_compressed
1654
1658 type(coef_t), intent(inout) :: c
1659 integer :: e, i, lxyz, ntot
1660
1661 lxyz = c%Xh%lx * c%Xh%ly * c%Xh%lz
1662 ntot = c%dof%size()
1663
1664 if (neko_bcknd_device .eq. 1) then
1665 call device_coef_generate_mass(c%B_d, c%Binv_d, c%jac_d, c%Xh%w3_d, &
1666 lxyz, c%msh%nelv)
1667 ! copy to host only at initialization.
1668 if (.not. c%coef_metrics_initialized) then
1669 ! Under COEF_OPERATOR the Binv transfer below is skipped, so this
1670 ! becomes the last one of the routine and has to synchronise.
1671 call device_memcpy(c%B, c%B_d, ntot, device_to_host, &
1672 sync = (c%scope .eq. coef_operator))
1673 end if
1674 else
1675 !$omp parallel do private(e, i)
1676 do e = 1, c%msh%nelv
1677 ! Here we need to handle things differently for axis symmetric elements
1678 do i = 1, lxyz
1679 c%B(i,1,1,e) = c%jac(i,1,1,e) * c%Xh%w3(i,1,1)
1680 c%Binv(i,1,1,e) = c%B(i,1,1,e)
1681 end do
1682 end do
1683 !$omp end parallel do
1684 end if
1685
1686 ! Neither Binv nor the volume is read when only applying an operator,
1687 ! and assembling Binv costs a gather-scatter round on top of that.
1688 if (c%scope .ne. coef_full) return
1689
1690 call c%gs_h%op(c%Binv, ntot, gs_op_add)
1691
1692 if (neko_bcknd_device .eq. 1) then
1693 call device_invcol1(c%Binv_d, ntot)
1694 ! copy to host only at initialization.
1695 if (.not. c%coef_metrics_initialized) then
1696 call device_memcpy(c%Binv, c%Binv_d, ntot, &
1697 device_to_host, sync = .true.)
1698 end if
1699 else
1700 call invcol1(c%Binv, ntot)
1701 end if
1702
1704 if (neko_bcknd_device .eq. 1) then
1705 c%volume = device_glsum(c%B_d, ntot)
1706 else
1707 c%volume = glsum(c%B, ntot)
1708 end if
1709
1710 end subroutine coef_generate_mass
1711
1721 subroutine coef_require_facets(this, who)
1722 class(coef_t), intent(in) :: this
1723 character(len=*), intent(in) :: who
1724
1725 if (this%scope .ne. coef_full) then
1726 call neko_error(who // ' needs the facet areas and normals, which ' // &
1727 'a COEF_OPERATOR coef does not build')
1728 end if
1729
1730 end subroutine coef_require_facets
1731
1736 pure function coef_get_normal(this, i, j, k, e, facet) result(normal)
1737 class(coef_t), intent(in) :: this
1738 integer, intent(in) :: i, j, k, e, facet
1739 real(kind=rp) :: normal(3)
1740
1741 select case (facet)
1742 case (1, 2)
1743 normal(1) = this%nx(j, k, facet, e)
1744 normal(2) = this%ny(j, k, facet, e)
1745 normal(3) = this%nz(j, k, facet, e)
1746 case (3, 4)
1747 normal(1) = this%nx(i, k, facet, e)
1748 normal(2) = this%ny(i, k, facet, e)
1749 normal(3) = this%nz(i, k, facet, e)
1750 case (5, 6)
1751 normal(1) = this%nx(i, j, facet, e)
1752 normal(2) = this%ny(i, j, facet, e)
1753 normal(3) = this%nz(i, j, facet, e)
1754 end select
1755 end function coef_get_normal
1756
1760 pure function coef_get_area(this, i, j, k, e, facet) result(area)
1761 class(coef_t), intent(in) :: this
1762 integer, intent(in) :: i, j, k, e, facet
1763 real(kind=rp) :: area
1764
1765 select case (facet)
1766 case (1, 2)
1767 area = this%area(j, k, facet, e)
1768 case (3, 4)
1769 area = this%area(i, k, facet, e)
1770 case (5, 6)
1771 area = this%area(i, j, facet, e)
1772 end select
1773 end function coef_get_area
1774
1775
1778 type(coef_t), intent(inout) :: coef
1779 real(kind=rp), allocatable :: a(:,:,:,:)
1780 real(kind=rp), allocatable :: b(:,:,:,:)
1781 real(kind=rp), allocatable :: c(:,:,:,:)
1782 real(kind=rp), allocatable :: dot(:,:,:,:)
1783 integer :: n, m, e, i, j, k, lx
1784 real(kind=rp) :: weight, len
1785 n = coef%dof%size()
1786 lx = coef%Xh%lx
1787
1788 if (neko_bcknd_device .eq. 1) then
1789
1790 call device_coef_generate_area_and_normal( &
1791 coef%area_d, coef%nx_d, coef%ny_d, coef%nz_d, &
1792 coef%dxdr_d, coef%dydr_d, coef%dzdr_d, &
1793 coef%dxds_d, coef%dyds_d, coef%dzds_d, &
1794 coef%dxdt_d, coef%dydt_d, coef%dzdt_d, &
1795 coef%Xh%wx_d, coef%Xh%wy_d, coef%Xh%wz_d, &
1796 lx, coef%msh%nelv, neko_eps)
1797
1798 ! Here, we always copy back to host.
1799 m = size(coef%area)
1800 call device_memcpy(coef%area, coef%area_d, m, &
1801 device_to_host, sync = .false.)
1802 call device_memcpy(coef%nx, coef%nx_d, m, &
1803 device_to_host, sync = .false.)
1804 call device_memcpy(coef%ny, coef%ny_d, m, &
1805 device_to_host, sync = .false.)
1806 call device_memcpy(coef%nz, coef%nz_d, &
1807 m, device_to_host, sync = .true.)
1808
1809 else
1810
1811 allocate(a(coef%Xh%lx, coef%Xh%lx, coef%Xh%lx, coef%msh%nelv))
1812 allocate(b(coef%Xh%lx, coef%Xh%lx, coef%Xh%lx, coef%msh%nelv))
1813 allocate(c(coef%Xh%lx, coef%Xh%lx, coef%Xh%lx, coef%msh%nelv))
1814 allocate(dot(coef%Xh%lx, coef%Xh%lx, coef%Xh%lx, coef%msh%nelv))
1815
1816 !$omp parallel private (e, i, j, k, weight, len)
1817
1818 ! ds x dt
1819 !$omp do simd
1820 do i = 1, n
1821 a(i, 1, 1, 1) = coef%dyds(i, 1, 1, 1) * coef%dzdt(i, 1, 1, 1) &
1822 - coef%dzds(i, 1, 1, 1) * coef%dydt(i, 1, 1, 1)
1823
1824 b(i, 1, 1, 1) = coef%dzds(i, 1, 1, 1) * coef%dxdt(i, 1, 1, 1) &
1825 - coef%dxds(i, 1, 1, 1) * coef%dzdt(i, 1, 1, 1)
1826
1827 c(i, 1, 1, 1) = coef%dxds(i, 1, 1, 1) * coef%dydt(i, 1, 1, 1) &
1828 - coef%dyds(i, 1, 1, 1) * coef%dxdt(i, 1, 1, 1)
1829 end do
1830 !$omp end do simd
1831 !$omp do simd
1832 do i = 1, n
1833 dot(i, 1, 1, 1) = a(i, 1, 1, 1) * a(i, 1, 1, 1) &
1834 + b(i, 1, 1, 1) * b(i, 1, 1, 1) &
1835 + c(i, 1, 1, 1) * c(i, 1, 1, 1)
1836 end do
1837 !$omp end do simd
1838 !$omp do
1839 do e = 1, coef%msh%nelv
1840 do concurrent(k = 1:coef%Xh%lx)
1841 do concurrent(j = 1:coef%Xh%lx)
1842 weight = coef%Xh%wy(j) * coef%Xh%wz(k)
1843 coef%area(j, k, 2, e) = sqrt(dot(lx, j, k, e)) * weight
1844 coef%area(j, k, 1, e) = sqrt(dot(1, j, k, e)) * weight
1845 coef%nx(j,k, 1, e) = -a(1, j, k, e)
1846 coef%nx(j,k, 2, e) = a(lx, j, k, e)
1847 coef%ny(j,k, 1, e) = -b(1, j, k, e)
1848 coef%ny(j,k, 2, e) = b(lx, j, k, e)
1849 coef%nz(j,k, 1, e) = -c(1, j, k, e)
1850 coef%nz(j,k, 2, e) = c(lx, j, k, e)
1851 end do
1852 end do
1853 end do
1854 !$omp end do
1855
1856 ! dr x dt
1857 !$omp do simd
1858 do i = 1, n
1859 a(i, 1, 1, 1) = coef%dydr(i, 1, 1, 1) * coef%dzdt(i, 1, 1, 1) &
1860 - coef%dzdr(i, 1, 1, 1) * coef%dydt(i, 1, 1, 1)
1861
1862 b(i, 1, 1, 1) = coef%dzdr(i, 1, 1, 1) * coef%dxdt(i, 1, 1, 1) &
1863 - coef%dxdr(i, 1, 1, 1) * coef%dzdt(i, 1, 1, 1)
1864
1865 c(i, 1, 1, 1) = coef%dxdr(i, 1, 1, 1) * coef%dydt(i, 1, 1, 1) &
1866 - coef%dydr(i, 1, 1, 1) * coef%dxdt(i, 1, 1, 1)
1867 end do
1868 !$omp end do simd
1869 !$omp do simd
1870 do i = 1, n
1871 dot(i, 1, 1, 1) = a(i, 1, 1, 1) * a(i, 1, 1, 1) &
1872 + b(i, 1, 1, 1) * b(i, 1, 1, 1) &
1873 + c(i, 1, 1, 1) * c(i, 1, 1, 1)
1874 end do
1875 !$omp end do simd
1876 !$omp do
1877 do e = 1, coef%msh%nelv
1878 do concurrent(k = 1:coef%Xh%lx)
1879 do concurrent(j = 1:coef%Xh%lx)
1880 weight = coef%Xh%wx(j) * coef%Xh%wz(k)
1881 coef%area(j, k, 3, e) = sqrt(dot(j, 1, k, e)) * weight
1882 coef%area(j, k, 4, e) = sqrt(dot(j, lx, k, e)) * weight
1883 coef%nx(j,k, 3, e) = a(j, 1, k, e)
1884 coef%nx(j,k, 4, e) = -a(j, lx, k, e)
1885 coef%ny(j,k, 3, e) = b(j, 1, k, e)
1886 coef%ny(j,k, 4, e) = -b(j, lx, k, e)
1887 coef%nz(j,k, 3, e) = c(j, 1, k, e)
1888 coef%nz(j,k, 4, e) = -c(j, lx, k, e)
1889 end do
1890 end do
1891 end do
1892 !$omp end do
1893 ! dr x ds
1894 !$omp do simd
1895 do i = 1, n
1896 a(i, 1, 1, 1) = coef%dydr(i, 1, 1, 1) * coef%dzds(i, 1, 1, 1) &
1897 - coef%dzdr(i, 1, 1, 1) * coef%dyds(i, 1, 1, 1)
1898
1899 b(i, 1, 1, 1) = coef%dzdr(i, 1, 1, 1) * coef%dxds(i, 1, 1, 1) &
1900 - coef%dxdr(i, 1, 1, 1) * coef%dzds(i, 1, 1, 1)
1901
1902 c(i, 1, 1, 1) = coef%dxdr(i, 1, 1, 1) * coef%dyds(i, 1, 1, 1) &
1903 - coef%dydr(i, 1, 1, 1) * coef%dxds(i, 1, 1, 1)
1904 end do
1905 !$omp end do simd
1906 !$omp do simd
1907 do i = 1, n
1908 dot(i, 1, 1, 1) = a(i, 1, 1, 1) * a(i, 1, 1, 1) &
1909 + b(i, 1, 1, 1) * b(i, 1, 1, 1) &
1910 + c(i, 1, 1, 1) * c(i, 1, 1, 1)
1911 end do
1912 !$omp end do simd
1913 !$omp do
1914 do e = 1, coef%msh%nelv
1915 do concurrent(k = 1:coef%Xh%lx)
1916 do concurrent(j = 1:coef%Xh%lx)
1917 weight = coef%Xh%wx(j) * coef%Xh%wy(k)
1918 coef%area(j, k, 5, e) = sqrt(dot(j, k, 1, e)) * weight
1919 coef%area(j, k, 6, e) = sqrt(dot(j, k, lx, e)) * weight
1920 coef%nx(j,k, 5, e) = -a(j, k, 1, e)
1921 coef%nx(j,k, 6, e) = a(j, k, lx, e)
1922 coef%ny(j,k, 5, e) = -b(j, k, 1, e)
1923 coef%ny(j,k, 6, e) = b(j, k, lx, e)
1924 coef%nz(j,k, 5, e) = -c(j, k, 1, e)
1925 coef%nz(j,k, 6, e) = c(j, k, lx, e)
1926 end do
1927 end do
1928 end do
1929 !$omp end do
1930 ! Normalize
1931 !$omp do
1932 do j = 1, size(coef%nz)
1933 len = sqrt(coef%nx(j,1,1,1)**2 + &
1934 coef%ny(j,1,1,1)**2 + coef%nz(j,1,1,1)**2)
1935 if (len .gt. neko_eps) then
1936 coef%nx(j,1,1,1) = coef%nx(j,1,1,1) / len
1937 coef%ny(j,1,1,1) = coef%ny(j,1,1,1) / len
1938 coef%nz(j,1,1,1) = coef%nz(j,1,1,1) / len
1939 end if
1940 end do
1941 !$omp end do
1942 !$omp end parallel
1943
1944 deallocate(dot)
1945 deallocate(c)
1946 deallocate(b)
1947 deallocate(a)
1948
1949 end if
1950
1951 end subroutine coef_generate_area_and_normal
1952
1954 class(coef_t), intent(inout) :: this
1955 real(kind=rp) :: un(3), len, d
1956 integer :: lx, ly, lz, np, np_glb, ierr
1957 integer :: i, j, k, pf, pe, n, nc, ncyc
1958
1959 if (.not. this%cyclic) return
1960
1961 ! Builds the rotation matrices from get_normal()
1962 if (this%scope .ne. coef_full) then
1963 call neko_error('Cyclic boundaries need the facet normals, ' // &
1964 'which COEF_OPERATOR does not build')
1965 end if
1966
1967 np = this%msh%periodic%size
1968 call mpi_allreduce(np, np_glb, 1, &
1969 mpi_integer, mpi_sum, neko_comm, ierr)
1970
1971 if (np_glb .eq. 0) then
1972 call neko_error("There are no periodic boundaries. " // &
1973 "Switch cyclic off in the case file.")
1974 end if
1975
1976 if (np .eq. 0) return
1977
1978 lx = this%Xh%lx
1979 ly = this%Xh%ly
1980 lz = this%Xh%lz
1981 ncyc = this%cyc_msk(0) - 1
1982 nc = 1
1983 do n = 1, np
1984 pf = this%msh%periodic%facet_el(n)%x(1)
1985 pe = this%msh%periodic%facet_el(n)%x(2)
1986 do k = 1, lz
1987 do j = 1, ly
1988 do i = 1, lx
1989 if (index_is_on_facet(i, j, k, lx, ly, lz, pf)) then
1990 un = this%get_normal(i, j, k, pe, pf)
1991 len = sqrt(un(1) * un(1) + un(2) * un(2))
1992 if (len .gt. neko_eps) then
1993 d = this%dof%y%x(i, j, k, pe) * un(1) &
1994 - this%dof%x%x(i, j, k, pe) * un(2)
1995
1996 this%cyc_msk(nc) = linear_index(i, j, k, pe, lx, ly, lz)
1997 this%R11(nc) = un(1) / len * sign(1.0_rp, d)
1998 this%R12(nc) = un(2) / len * sign(1.0_rp, d)
1999 nc = nc + 1
2000 else
2001 call neko_error("x and y components of surface " // &
2002 "normals are zero. Cyclic rotations must be " // &
2003 "around z-axis.")
2004 end if
2005 end if
2006 end do
2007 end do
2008 end do
2009 end do
2010
2011 if (nc - 1 /= ncyc) then
2012 call neko_error("The number of cyclic GLL points were " // &
2013 "not estimated correctly.")
2014 end if
2015
2016 if (neko_bcknd_device .eq. 1) then
2017 call device_memcpy(this%cyc_msk, this%cyc_msk_d, ncyc+1, &
2018 host_to_device, sync = .false.)
2019 call device_memcpy(this%R11, this%R11_d, ncyc, &
2020 host_to_device, sync = .false.)
2021 call device_memcpy(this%R12, this%R12_d, ncyc, &
2022 host_to_device, sync = .false.)
2023 end if
2024
2025 end subroutine coef_generate_cyclic_bc
2026
2027
2029 subroutine coef_recompute_metrics(this)
2030 class(coef_t), intent(inout) :: this
2031
2032 if (this%scope .ne. coef_full) then
2033 call neko_error('Rebuilding the geometry needs the derivative ' // &
2034 'arrays, which COEF_OPERATOR releases')
2035 end if
2036
2037 call coef_generate_dxyzdrst(this)
2038 call coef_generate_geo(this)
2040 call coef_generate_mass(this)
2041 if (this%cyclic) then
2042 call coef_generate_cyclic_bc(this)
2043 end if
2044 this%metrics_version = this%metrics_version + 1
2045 end subroutine coef_recompute_metrics
2046
2047
2051 class(coef_t), intent(inout), target :: this
2052 integer :: n
2053
2054 ! Return if already allocated distinctly
2055 if (.not. associated(this%Blag, this%B)) return
2056
2057 n = this%Xh%lx * this%Xh%ly * this%Xh%lz * this%msh%nelv
2058
2059
2060 nullify(this%Blag)
2061 nullify(this%Blaglag)
2062
2063 allocate(this%Blag(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
2064 allocate(this%Blaglag(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
2065
2066 this%Blag = this%B
2067 this%Blaglag = this%B
2068
2069 if (neko_bcknd_device .eq. 1) then
2070
2071 this%Blag_d = c_null_ptr
2072 this%Blaglag_d = c_null_ptr
2073
2074 call device_map(this%Blag, this%Blag_d, n)
2075 call device_map(this%Blaglag, this%Blaglag_d, n)
2076
2077 call device_memcpy(this%Blag, this%Blag_d, n, &
2078 host_to_device, sync = .false.)
2079 call device_memcpy(this%Blaglag, this%Blaglag_d, n, &
2080 host_to_device, sync = .true.)
2081 end if
2082
2083 end subroutine coef_enable_lagged_mass
2084
2085
2088 class(coef_t), intent(inout), target :: this
2089 integer :: n
2090
2091 ! If this%Blag does not have separate memory, we don't need to update it.
2092 if (associated(this%Blag, this%B)) return
2093 n = this%Xh%lx * this%Xh%ly * this%Xh%lz * this%msh%nelv
2094 if (neko_bcknd_device .eq. 1) then
2095 call device_copy(this%Blaglag_d, this%Blag_d, n)
2096 call device_copy(this%Blag_d, this%B_d, n)
2097 else
2098 this%Blaglag = this%Blag
2099 this%Blag = this%B
2100 end if
2101
2102 end subroutine coef_update_lagged_mass
2103
2104end module coefs
double real
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
Coefficients.
Definition coef.f90:34
integer, parameter, public coef_full
Retain every coefficient. The default, and the only scope that supports recompute_metrics(),...
Definition coef.f90:118
subroutine coef_generate_geo(c)
Generate geometric data for the given mesh.
Definition coef.f90:1191
subroutine coef_free(this)
Deallocate coefficients.
Definition coef.f90:590
subroutine coef_release_scratch(this)
Release the coefficients that COEF_OPERATOR does not retain.
Definition coef.f90:868
integer, parameter, public coef_operator
Retain only what applying a discrete operator needs: , h1, h2, B and mult.
Definition coef.f90:131
subroutine coef_recompute_metrics(this)
Recompute and update geometric factors (ALE)
Definition coef.f90:2030
pure real(kind=rp) function coef_get_area(this, i, j, k, e, facet)
Facet area at a point.
Definition coef.f90:1761
pure real(kind=rp) function, dimension(3) coef_get_normal(this, i, j, k, e, facet)
Facet normal at a point.
Definition coef.f90:1737
subroutine coef_init_all(this, gs_h, scope)
Initialize coefficients.
Definition coef.f90:361
subroutine coef_update_lagged_mass(this)
Update history: Blaglag = Blag, Blag = B.
Definition coef.f90:2088
subroutine coef_generate_dxyzdrst(c)
Definition coef.f90:1002
subroutine coef_generate_area_and_normal(coef)
Generate facet area and surface normals.
Definition coef.f90:1778
subroutine coef_init_empty(this, xh, msh)
Initialize empty coefs for a space and a mesh.
Definition coef.f90:312
real(kind=rp), parameter, public neko_metric_perturb_max
Largest predicted relative perturbation of the element Helmholtz operator, in its own energy norm,...
Definition coef.f90:113
subroutine coef_metric_condition(this)
Compute the metric tensor condition numbers over the mesh.
Definition coef.f90:1378
subroutine coef_enable_lagged_mass(this)
Enable separate memory for lagged B matrices if needed. For eg. when mesh moves.
Definition coef.f90:2051
subroutine coef_require_facets(this, who)
Abort unless this coef holds the facet areas and normals.
Definition coef.f90:1722
real(kind=rp), parameter, public neko_metric_cond_sp
Largest metric condition number for which single precision arithmetic on the geometric factors is co...
Definition coef.f90:79
subroutine coef_generate_geo_compressed(c)
Compute processor-local compressed versions of mappings Gij.
Definition coef.f90:1580
subroutine coef_generate_cyclic_bc(this)
Definition coef.f90:1954
subroutine coef_generate_mass(c)
Generate mass matrix B for the given mesh and space.
Definition coef.f90:1658
Definition comm.F90:1
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
subroutine, public device_coef_generate_area_and_normal(area_d, nx_d, ny_d, nz_d, dxdr_d, dydr_d, dzdr_d, dxds_d, dyds_d, dzds_d, dxdt_d, dydt_d, dzdt_d, wx_d, wy_d, wz_d, lx, nel, eps)
subroutine, public device_coef_generate_dxydrst(drdx_d, drdy_d, drdz_d, dsdx_d, dsdy_d, dsdz_d, dtdx_d, dtdy_d, dtdz_d, dxdr_d, dydr_d, dzdr_d, dxds_d, dyds_d, dzds_d, dxdt_d, dydt_d, dzdt_d, dx_d, dy_d, dz_d, x_d, y_d, z_d, jacinv_d, jac_d, lx, nel)
subroutine, public device_coef_generate_mass(b, binv, jac, w3, lxyz, nel)
subroutine, public device_coef_generate_geo(g11_d, g12_d, g13_d, g22_d, g23_d, g33_d, drdx_d, drdy_d, drdz_d, dsdx_d, dsdy_d, dsdz_d, dtdx_d, dtdy_d, dtdz_d, jacinv_d, w3_d, nel, lx, gdim)
real(kind=rp) function, public device_glsum(a_d, n, strm)
Sum a vector of length n.
subroutine, public device_invcol1(a_d, n, strm)
Invert a vector .
subroutine, public device_rone(a_d, n, strm)
Set all elements to one.
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
integer, parameter, public device_to_host
Definition device.F90:48
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Gather-scatter.
Defines Gather-scatter operations.
Definition gs_ops.f90:34
integer, parameter, public gs_op_add
Definition gs_ops.f90:36
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:91
integer, parameter, public log_size
Definition log.f90:46
Definition math.f90:60
pure subroutine, public eig_sym3(a11, a22, a33, a12, a13, a23, e1, e2, e3)
Eigenvalues of a symmetric 3x3 matrix, descending.
Definition math.f90:2003
subroutine, public invers2(a, b, n)
Compute inverted vector .
Definition math.f90:839
pure subroutine, public eig_sym2(a11, a22, a12, e1, e2)
Eigenvalues of a symmetric 2x2 matrix, descending.
Definition math.f90:1952
subroutine, public subcol3(a, b, c, n)
Returns .
Definition math.f90:1116
subroutine, public rone(a, n)
Set all elements to one.
Definition math.f90:281
real(kind=rp) function, public glsum(a, n)
Sum a vector of length n.
Definition math.f90:633
subroutine, public addcol3(a, b, c, n)
Returns .
Definition math.f90:1203
subroutine, public invcol1(a, n)
Invert a vector .
Definition math.f90:810
subroutine, public chsign(a, n)
Change sign of vector .
Definition math.f90:750
real(kind=rp) function, public glmax(a, n)
Max of a vector of length n.
Definition math.f90:654
real(kind=sp), parameter, public neko_eps_sp
Definition math.f90:72
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:295
real(kind=rp), parameter, public neko_eps
Machine epsilon .
Definition math.f90:70
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:239
Defines a mesh.
Definition mesh.f90:34
Wrapper for all matrix-matrix product implementations.
subroutine, public mxm(a, n1, b, n2, c, n3)
Compute matrix-matrix product for contiguously packed matrices A,B, and C.
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter neko_bcknd_opencl
integer, parameter, public dp
Definition num_types.f90:10
integer, parameter, public sp
Definition num_types.f90:8
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Defines a function space.
Definition space.f90:34
Utilities.
Definition utils.f90:35
pure logical function, public index_is_on_facet(i, j, k, lx, ly, lz, facet)
Definition utils.f90:351
pure integer function, public linear_index(i, j, k, l, lx, ly, lz)
Compute the address of a (i,j,k,l) array with sizes (1:lx, 1:ly, 1:lz, :)
Definition utils.f90:326
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:135
Gather-scatter kernel.
The function space for the SEM solution fields.
Definition space.f90:64
#define max(a, b)
Definition tensor.cu:40