Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
map_2d.f90
Go to the documentation of this file.
1! Copyright (c) 2024-2025, 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!
33!
35
36module map_2d
38 use num_types, only: rp
39 use dofmap, only: dofmap_t
40 use map_1d, only : map_1d_t
41 use gather_scatter, only : gs_t, gs_op_add
42 use mesh, only: mesh_t
43 use field_list, only : field_list_t
44 use coefs, only: coef_t
45 use vector, only: vector_ptr_t
46 use utils, only: neko_error, linear_index
47 use math, only: cmult, col2, copy, rzero
48 use field, only : field_t
49 use, intrinsic :: iso_c_binding
51 use comm, only : neko_comm
53 use mpi_f08, only : mpi_allreduce, mpi_integer, mpi_sum, mpi_exscan
55 implicit none
56 private
57
58 type, public :: map_2d_t
59 integer :: nelv_2d = 0
60 integer :: glb_nelv_2d = 0
61 integer :: offset_el_2d = 0
62 integer :: lxy = 0
63 integer :: n_2d = 0
64 integer, allocatable :: idx_2d(:)
65 integer, allocatable :: el_idx_2d(:)
67 type(mesh_t), pointer :: msh
68 type(dofmap_t), pointer :: dof => null()
69 type(coef_t), pointer :: coef => null()
70 type(field_t) :: u
71 type(field_t) :: old_u
72 type(field_t) :: avg_u
73 type(field_t) :: el_heights
74 integer :: dir
75 real(kind=rp) :: domain_height
76 contains
77 procedure, pass(this) :: init_int => map_2d_init
78 procedure, pass(this) :: init_char => map_2d_init_char
79 procedure, pass(this) :: free => map_2d_free
80 generic :: init => init_int, init_char
81 procedure, pass(this) :: average_file => map_2d_average
82 procedure, pass(this) :: average_list => map_2d_average_field_list
83 generic :: average => average_list, average_file
84 end type map_2d_t
85
86contains
87
88 subroutine map_2d_init(this, coef, dir, tol)
89 class(map_2d_t), intent(inout) :: this
90 type(coef_t), intent(inout), target :: coef
91 integer, intent(in) :: dir
92 real(kind=rp), intent(in) :: tol
93 real(kind=rp) :: el_dim(3,3), el_h
94 integer :: i, e, j, ierr, k, lx, lxy, n
95 call this%map_1d%init(coef,dir,tol)
96 this%msh => coef%msh
97 this%coef => coef
98 this%dof => coef%dof
99
100 call this%u%init(this%dof)
101 call this%old_u%init(this%dof)
102 call this%avg_u%init(this%dof)
103 call this%el_heights%init(this%dof)
104 this%dir = dir
105
106 n = this%dof%size()
107 lx = this%dof%Xh%lx
108 lxy = this%dof%Xh%lxy
109 this%nelv_2d = 0
110 do i = 1, this%msh%nelv
111 if (this%map_1d%el_lvl(i) .eq. 1) then
112 this%nelv_2d = this%nelv_2d + 1
113 end if
114 end do
115 this%glb_nelv_2d = 0
116 call mpi_allreduce(this%nelv_2d, this%glb_nelv_2d, 1, &
117 mpi_integer, mpi_sum, neko_comm, ierr)
118
119 this%offset_el_2d = 0
120 call mpi_exscan(this%nelv_2d, this%offset_el_2d, 1, &
121 mpi_integer, mpi_sum, neko_comm, ierr)
122 allocate(this%el_idx_2d(this%nelv_2d))
123 do i = 1, this%nelv_2d
124 this%el_idx_2d(i) = this%offset_el_2d + i
125 end do
126 this%n_2d = this%nelv_2d*lxy
127 allocate(this%idx_2d(this%n_2d))
128
129 j = 0
130 do e = 1, this%msh%nelv
131 if (this%map_1d%el_lvl(e) .eq. 1) then
132 if (this%map_1d%dir_el(e) .eq. 1) then
133 do i = 1, lxy
134 this%idx_2d(j*lxy+i) = linear_index(1,i,1,e,lx,lx,lx)
135 end do
136 end if
137 if (this%map_1d%dir_el(e) .eq. 2) then
138 do i = 1, lx
139 do k = 1, lx
140 this%idx_2d(j * lxy + k + lx * (i - 1)) = &
141 linear_index(k, 1, i, e, lx, lx, lx)
142 end do
143 end do
144 end if
145 if (this%map_1d%dir_el(e) .eq. 3) then
146 do i = 1, lxy
147 this%idx_2d(j*lxy+i) = linear_index(i,1,1,e,lx,lx,lx)
148 end do
149 end if
150 j = j +1
151 end if
152 end do
153 do i = 1, this%msh%nelv
154 !find height in hom-dir
155 !direction in local coords (r,s,t) that is hom is stored in map_1d%dir_el
156 !set element to height
157 !we assume elements are stacked on eachother...
158 el_dim(1,:) = abs(this%msh%elements(i)%e%pts(1)%p%x-&
159 this%msh%elements(i)%e%pts(2)%p%x)
160 el_dim(2,:) = abs(this%msh%elements(i)%e%pts(1)%p%x-&
161 this%msh%elements(i)%e%pts(3)%p%x)
162 el_dim(3,:) = abs(this%msh%elements(i)%e%pts(1)%p%x-&
163 this%msh%elements(i)%e%pts(5)%p%x)
164 ! 1 corresponds to x, 2 to y, 3 to z
165 el_h = el_dim(this%map_1d%dir_el(i),dir)
166 this%el_heights%x(:,:,:,i) = el_h
167 end do
168 !Need to compute mapping for 3d to 2d
169 !Does order matter? Think its ok as long as values written in same order
170
171 call copy(this%u%x,this%el_heights%x,n)
172 call copy(this%old_u%x,this%el_heights%x,n)
173 call copy(this%avg_u%x,this%el_heights%x,n)
174 call perform_global_summation(this%u, this%avg_u, this%old_u, &
175 this%map_1d%n_el_lvls, &
176 this%map_1d%dir_el,this%coef%gs_h, this%coef%mult, this%msh%nelv, lx)
177 this%domain_height = this%u%x(1,1,1,1)
178
179 end subroutine map_2d_init
180
181 subroutine map_2d_init_char(this, coef, dir, tol)
182 class(map_2d_t) :: this
183 type(coef_t), intent(inout), target :: coef
184 character(len=*), intent(in) :: dir
185 real(kind=rp), intent(in) :: tol
186 integer :: idir
187
188 if (trim(dir) .eq. 'x') then
189 idir = 1
190 else if (trim(dir) .eq. 'y') then
191 idir = 2
192 else if (trim(dir) .eq. 'z') then
193 idir = 3
194 else
195 call neko_error('Direction not supported, map_2d')
196 end if
197
198 call this%init(coef,idir,tol)
199
200 end subroutine map_2d_init_char
201
202 subroutine map_2d_free(this)
203 class(map_2d_t), intent(inout) :: this
204
205 if (allocated(this%idx_2d)) then
206 deallocate(this%idx_2d)
207 end if
208
209 if (allocated(this%el_idx_2d)) then
210 deallocate(this%el_idx_2d)
211 end if
212
213 call this%u%free()
214 call this%old_u%free()
215 call this%avg_u%free()
216 call this%el_heights%free()
217 call this%map_1d%free()
218
219 nullify(this%msh)
220 nullify(this%dof)
221 nullify(this%coef)
222 end subroutine map_2d_free
223
224
229 subroutine map_2d_average_field_list(this, fld_data2D, fld_data3D)
230 class(map_2d_t), intent(inout) :: this
231 type(fld_file_data_t), intent(inout) :: fld_data2D
232 type(field_list_t), intent(inout) :: fld_data3D
233 real(kind=rp), pointer, contiguous, dimension(:,:,:,:) :: x_ptr, y_ptr
234
235 type(vector_ptr_t), allocatable :: fields2d(:)
236 integer :: n_2d, n
237 integer :: i, j, lx, lxy
238
239 call fld_data2d%init(this%nelv_2d, this%offset_el_2d)
240 fld_data2d%gdim = 2
241 fld_data2d%lx = this%dof%Xh%lx
242 fld_data2d%ly = this%dof%Xh%ly
243 fld_data2d%lz = 1
244 lx = this%dof%Xh%lx
245 fld_data2d%glb_nelv = this%glb_nelv_2d
246 lxy = fld_data2d%lx*fld_data2d%ly
247 n_2d = lxy*this%nelv_2d
248 n = this%dof%size()
249 call fld_data2d%x%init(n_2d)
250 call fld_data2d%y%init(n_2d)
251 allocate(fld_data2d%idx(this%nelv_2d))
252
253 if (this%dir .eq. 1) then
254 x_ptr => this%dof%z%x
255 y_ptr => this%dof%y%x
256 end if
257 if (this%dir .eq. 2) then
258 x_ptr => this%dof%x%x
259 y_ptr => this%dof%z%x
260 end if
261 if (this%dir .eq. 3) then
262 x_ptr => this%dof%x%x
263 y_ptr => this%dof%y%x
264 end if
265 do j = 1, this%nelv_2d
266 fld_data2d%idx(j) = this%el_idx_2d(j)
267 end do
268 do j = 1, n_2d
269 fld_data2d%x%x(j) = x_ptr(this%idx_2d(j),1,1,1)
270 fld_data2d%y%x(j) = y_ptr(this%idx_2d(j),1,1,1)
271 end do
272 allocate(fields2d(fld_data3d%size()))
273
274 call fld_data2d%init_n_fields(fld_data3d%size(), n_2d)
275 this%u = 0.0_rp
276 this%old_u = 0.0_rp
277 this%avg_u = 0.0_rp
278 do i = 1, fld_data3d%size()
279 call copy(this%old_u%x, fld_data3d%items(i)%ptr%x, n)
280 call perform_local_summation(this%u, this%old_u, &
281 this%el_heights, this%domain_height, &
282 this%map_1d%dir_el, this%coef, this%msh%nelv, lx)
283 call copy(this%old_u%x, this%u%x, n)
284 call copy(this%avg_u%x, this%u%x, n)
285 call perform_global_summation(this%u, this%avg_u, &
286 this%old_u, this%map_1d%n_el_lvls, &
287 this%map_1d%dir_el,this%coef%gs_h, this%coef%mult, &
288 this%msh%nelv, lx)
289 call copy(fld_data3d%items(i)%ptr%x, this%u%x, n)
290 end do
291 call fld_data2d%get_list(fields2d, fld_data2d%size())
292 do i = 1, fld_data3d%size()
293 do j = 1, n_2d
294 fields2d(i)%ptr%x(j) = fld_data3d%items(i)%ptr%x(this%idx_2d(j),1,1,1)
295 end do
296 end do
297
298 end subroutine map_2d_average_field_list
299
300
305 subroutine map_2d_average(this, fld_data2D, fld_data3D)
306 class(map_2d_t), intent(inout) :: this
307 type(fld_file_data_t), intent(inout) :: fld_data2D
308 type(fld_file_data_t), intent(inout) :: fld_data3D
309 real(kind=rp), pointer, dimension(:,:,:,:) :: x_ptr, y_ptr
310
311 type(vector_ptr_t), allocatable :: fields3d(:), fields2d(:)
312 integer :: n_2d, n
313 integer :: i, j, lx, lxy
314
315 call fld_data2d%init(this%nelv_2d, this%offset_el_2d)
316 fld_data2d%gdim = 2
317 fld_data2d%lx = this%dof%Xh%lx
318 fld_data2d%ly = this%dof%Xh%ly
319 fld_data2d%lz = 1
320 lx = this%dof%Xh%lx
321 fld_data2d%glb_nelv = this%glb_nelv_2d
322 lxy = fld_data2d%lx*fld_data2d%ly
323 n_2d = lxy*this%nelv_2d
324 n = this%dof%size()
325 call fld_data2d%x%init(n_2d)
326 call fld_data2d%y%init(n_2d)
327 allocate(fld_data2d%idx(n_2d))
328
329 if (this%dir .eq. 1) then
330 x_ptr => this%dof%z%x
331 y_ptr => this%dof%y%x
332 end if
333 if (this%dir .eq. 2) then
334 x_ptr => this%dof%x%x
335 y_ptr => this%dof%z%x
336 end if
337 if (this%dir .eq. 3) then
338 x_ptr => this%dof%x%x
339 y_ptr => this%dof%y%x
340 end if
341 do j = 1, n_2d
342 fld_data2d%idx(j) = this%idx_2d(j)
343 fld_data2d%x%x(j) = x_ptr(this%idx_2d(j),1,1,1)
344 fld_data2d%y%x(j) = y_ptr(this%idx_2d(j),1,1,1)
345 end do
346 allocate(fields3d(fld_data3d%size()))
347 allocate(fields2d(fld_data3d%size()))
348
349 call fld_data2d%init_n_fields(fld_data3d%size(), n_2d)
350 call fld_data3d%get_list(fields3d,fld_data3d%size())
351
352 this%u = 0.0_rp
353 this%old_u = 0.0_rp
354 this%avg_u = 0.0_rp
355 do i = 1, fld_data3d%size()
356 call copy(this%old_u%x, fields3d(i)%ptr%x, n)
357 call perform_local_summation(this%u,this%old_u,&
358 this%el_heights, this%domain_height, &
359 this%map_1d%dir_el, this%coef, this%msh%nelv, lx)
360 call copy(this%old_u%x, this%u%x,n)
361 call copy(this%avg_u%x, this%u%x,n)
362 call perform_global_summation(this%u, this%avg_u, &
363 this%old_u, this%map_1d%n_el_lvls, &
364 this%map_1d%dir_el, this%coef%gs_h,&
365 this%coef%mult, this%msh%nelv, lx)
366 call copy(fields3d(i)%ptr%x, this%u%x, n)
367 end do
368 call fld_data2d%get_list(fields2d, fld_data2d%size())
369 do i = 1, fld_data3d%size()
370 do j = 1, n_2d
371 fields2d(i)%ptr%x(j) = fields3d(i)%ptr%x(this%idx_2d(j))
372 end do
373 end do
374 end subroutine map_2d_average
375
376 subroutine perform_global_summation(u, avg_u, old_u, n_levels, &
377 hom_dir_el, gs_h, mult, nelv, lx)
378 type(field_t), intent(inout) :: u, avg_u, old_u
379 type(gs_t), intent(inout) :: gs_h
380 integer, intent(in) :: n_levels, nelv, lx
381 integer, intent(in) :: hom_dir_el(nelv)
382 real(kind=rp), intent(in) :: mult(nelv*lx**3)
383 real(kind=rp) :: temp_el(lx,lx,lx)
384 integer :: n, i, j, e
385
386 n = u%dof%size()
387
388 do i = 1, n_levels-1
389 !compute average
390 if (neko_bcknd_device .eq. 1) &
391 call device_memcpy(u%x, u%x_d, n, &
392 host_to_device, sync=.true.)
393 call gs_h%op(u,gs_op_add)
394 if (neko_bcknd_device .eq. 1) &
395 call device_memcpy(u%x, u%x_d, n, device_to_host, sync=.true.)
396 call col2(u%x,mult,n)
397 !Assumes sugarcube I think
398 do e = 1, nelv
399 temp_el = 2.0*u%x(:,:,:,e)-old_u%x(:,:,:,e)
400 if (hom_dir_el(e) .eq. 1) then
401 u%x(1,:,:,e) = temp_el(lx,:,:)
402 avg_u%x(1,:,:,e) = avg_u%x(1,:,:,e)+temp_el(1,:,:)
403 u%x(lx,:,:,e) = temp_el(1,:,:)
404 else if (hom_dir_el(e) .eq. 2) then
405 u%x(:,1,:,e) = temp_el(:,lx,:)
406 avg_u%x(:,1,:,e) = avg_u%x(:,1,:,e)+temp_el(:,1,:)
407 u%x(:,lx,:,e) = temp_el(:,1,:)
408 else if (hom_dir_el(e) .eq. 3) then
409 u%x(:,:,1,e) = temp_el(:,:,lx)
410 avg_u%x(:,:,1,e) = avg_u%x(:,:,1,e)+temp_el(:,:,1)
411 u%x(:,:,lx,e) = temp_el(:,:,1)
412 end if
413 old_u%x(:,:,:,e) = u%x(:,:,:,e)
414 end do
415 end do
416 do e = 1, nelv
417 do i = 1,lx
418 do j = 1, lx
419 if (hom_dir_el(e) .eq. 1) then
420 u%x(:,i,j,e) = avg_u%x(1,i,j,e)
421 else if (hom_dir_el(e) .eq. 2) then
422 u%x(i,:,j,e) = avg_u%x(i,1,j,e)
423 else if (hom_dir_el(e) .eq. 3) then
424 u%x(i,j,:,e) = avg_u%x(i,j,1,e)
425 end if
426 end do
427 end do
428 end do
429 end subroutine perform_global_summation
430
431 subroutine perform_local_summation(u_out, u, el_heights, domain_height,&
432 hom_dir_el, coef, nelv, lx)
433 type(field_t), intent(inout) :: u, u_out, el_heights
434 type(coef_t), intent(inout) :: coef
435 integer, intent(in) :: nelv, lx
436 integer, intent(in) :: hom_dir_el(nelv)
437 real(kind=rp), intent(in) :: domain_height
438 real(kind=rp) :: wt
439 integer :: n, i, j, e, k
440
441 n = nelv*lx**3
442
443 call col2(u%x,el_heights%x,n)
444 call cmult(u%x, 1.0_rp/(2.0*domain_height),n)
445 call rzero(u_out%x,n)
446
447
448 do e = 1, nelv
449 do i = 1,lx
450 do j = 1, lx
451 do k = 1, lx
452 wt = coef%Xh%wx(k)
453 if (hom_dir_el(e) .eq. 1) then
454 u_out%x(1,i,j,e) = u_out%x(1,i,j,e)+wt*u%x(k,i,j,e)
455 else if (hom_dir_el(e) .eq. 2) then
456 u_out%x(i,1,j,e) = u_out%x(i,1,j,e)+wt*u%x(i,k,j,e)
457 else if (hom_dir_el(e) .eq. 3) then
458 u_out%x(i,j,1,e) = u_out%x(i,j,1,e)+wt*u%x(i,j,k,e)
459 end if
460 end do
461 end do
462 end do
463 end do
464
465 do e = 1, nelv
466 do i = 1,lx
467 do j = 1, lx
468 if (hom_dir_el(e) .eq. 1) then
469 u_out%x(:,i,j,e) = u_out%x(1,i,j,e)
470 else if (hom_dir_el(e) .eq. 2) then
471 u_out%x(i,:,j,e) = u_out%x(i,1,j,e)
472 else if (hom_dir_el(e) .eq. 3) then
473 u_out%x(i,j,:,e) = u_out%x(i,j,1,e)
474 end if
475 end do
476 end do
477 end do
478 end subroutine perform_local_summation
479
480end module map_2d
Copy data between host and device (or device and device)
Definition device.F90:72
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
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
Defines a field.
Definition field.f90:34
Simple module to handle fld file series. Provides an interface to the different fields sotred in a fl...
Gather-scatter.
Creates a 1d GLL point map along a specified direction based on the connectivity in the mesh.
Definition map_1d.f90:36
Maps a 3D dofmap to a 2D spectral element grid.
Definition map_2d.f90:36
subroutine map_2d_free(this)
Definition map_2d.f90:203
subroutine perform_local_summation(u_out, u, el_heights, domain_height, hom_dir_el, coef, nelv, lx)
Definition map_2d.f90:433
subroutine perform_global_summation(u, avg_u, old_u, n_levels, hom_dir_el, gs_h, mult, nelv, lx)
Definition map_2d.f90:378
subroutine map_2d_init(this, coef, dir, tol)
Definition map_2d.f90:89
subroutine map_2d_init_char(this, coef, dir, tol)
Definition map_2d.f90:182
subroutine map_2d_average_field_list(this, fld_data2d, fld_data3d)
Computes average if field list in one direction and outputs 2D field with averaged values.
Definition map_2d.f90:230
subroutine map_2d_average(this, fld_data2d, fld_data3d)
Computes average if field list in one direction and outputs 2D field with averaged values.
Definition map_2d.f90:306
Definition math.f90:60
subroutine, public cmult(a, c, n)
Multiplication by constant c .
Definition math.f90:508
subroutine, public col2(a, b, n)
Vector multiplication .
Definition math.f90:1085
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:295
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:239
Defines a mesh.
Definition mesh.f90:34
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Utilities.
Definition utils.f90:35
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:328
Defines a vector.
Definition vector.f90:34
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:136
field_list_t, To be able to group fields together
Gather-scatter kernel.
Map every GLL point in the mesh to a level in one physical direction. Can be used to average across t...
Definition map_1d.f90:96