Neko 1.99.5
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 nullify(this%msh)
214 nullify(this%dof)
215 nullify(this%coef)
216 end subroutine map_2d_free
217
218
223 subroutine map_2d_average_field_list(this, fld_data2D, fld_data3D)
224 class(map_2d_t), intent(inout) :: this
225 type(fld_file_data_t), intent(inout) :: fld_data2D
226 type(field_list_t), intent(inout) :: fld_data3D
227 real(kind=rp), pointer, contiguous, dimension(:,:,:,:) :: x_ptr, y_ptr
228
229 type(vector_ptr_t), allocatable :: fields2d(:)
230 integer :: n_2d, n
231 integer :: i, j, lx, lxy
232
233 call fld_data2d%init(this%nelv_2d, this%offset_el_2d)
234 fld_data2d%gdim = 2
235 fld_data2d%lx = this%dof%Xh%lx
236 fld_data2d%ly = this%dof%Xh%ly
237 fld_data2d%lz = 1
238 lx = this%dof%Xh%lx
239 fld_data2d%glb_nelv = this%glb_nelv_2d
240 lxy = fld_data2d%lx*fld_data2d%ly
241 n_2d = lxy*this%nelv_2d
242 n = this%dof%size()
243 call fld_data2d%x%init(n_2d)
244 call fld_data2d%y%init(n_2d)
245 allocate(fld_data2d%idx(this%nelv_2d))
246
247 if (this%dir .eq. 1) then
248 x_ptr => this%dof%z
249 y_ptr => this%dof%y
250 end if
251 if (this%dir .eq. 2) then
252 x_ptr => this%dof%x
253 y_ptr => this%dof%z
254 end if
255 if (this%dir .eq. 3) then
256 x_ptr => this%dof%x
257 y_ptr => this%dof%y
258 end if
259 do j = 1, this%nelv_2d
260 fld_data2d%idx(j) = this%el_idx_2d(j)
261 end do
262 do j = 1, n_2d
263 fld_data2d%x%x(j) = x_ptr(this%idx_2d(j),1,1,1)
264 fld_data2d%y%x(j) = y_ptr(this%idx_2d(j),1,1,1)
265 end do
266 allocate(fields2d(fld_data3d%size()))
267
268 call fld_data2d%init_n_fields(fld_data3d%size(), n_2d)
269 this%u = 0.0_rp
270 this%old_u = 0.0_rp
271 this%avg_u = 0.0_rp
272 do i = 1, fld_data3d%size()
273 call copy(this%old_u%x, fld_data3d%items(i)%ptr%x, n)
274 call perform_local_summation(this%u, this%old_u, &
275 this%el_heights, this%domain_height, &
276 this%map_1d%dir_el, this%coef, this%msh%nelv, lx)
277 call copy(this%old_u%x, this%u%x, n)
278 call copy(this%avg_u%x, this%u%x, n)
279 call perform_global_summation(this%u, this%avg_u, &
280 this%old_u, this%map_1d%n_el_lvls, &
281 this%map_1d%dir_el,this%coef%gs_h, this%coef%mult, &
282 this%msh%nelv, lx)
283 call copy(fld_data3d%items(i)%ptr%x, this%u%x, n)
284 end do
285 call fld_data2d%get_list(fields2d, fld_data2d%size())
286 do i = 1, fld_data3d%size()
287 do j = 1, n_2d
288 fields2d(i)%ptr%x(j) = fld_data3d%items(i)%ptr%x(this%idx_2d(j),1,1,1)
289 end do
290 end do
291
292 end subroutine map_2d_average_field_list
293
294
299 subroutine map_2d_average(this, fld_data2D, fld_data3D)
300 class(map_2d_t), intent(inout) :: this
301 type(fld_file_data_t), intent(inout) :: fld_data2D
302 type(fld_file_data_t), intent(inout) :: fld_data3D
303 real(kind=rp), pointer, dimension(:,:,:,:) :: x_ptr, y_ptr
304
305 type(vector_ptr_t), allocatable :: fields3d(:), fields2d(:)
306 integer :: n_2d, n
307 integer :: i, j, lx, lxy
308
309 call fld_data2d%init(this%nelv_2d, this%offset_el_2d)
310 fld_data2d%gdim = 2
311 fld_data2d%lx = this%dof%Xh%lx
312 fld_data2d%ly = this%dof%Xh%ly
313 fld_data2d%lz = 1
314 lx = this%dof%Xh%lx
315 fld_data2d%glb_nelv = this%glb_nelv_2d
316 lxy = fld_data2d%lx*fld_data2d%ly
317 n_2d = lxy*this%nelv_2d
318 n = this%dof%size()
319 call fld_data2d%x%init(n_2d)
320 call fld_data2d%y%init(n_2d)
321 allocate(fld_data2d%idx(n_2d))
322
323 if (this%dir .eq. 1) then
324 x_ptr => this%dof%z
325 y_ptr => this%dof%y
326 end if
327 if (this%dir .eq. 2) then
328 x_ptr => this%dof%x
329 y_ptr => this%dof%z
330 end if
331 if (this%dir .eq. 3) then
332 x_ptr => this%dof%x
333 y_ptr => this%dof%y
334 end if
335 do j = 1, n_2d
336 fld_data2d%idx(j) = this%idx_2d(j)
337 fld_data2d%x%x(j) = x_ptr(this%idx_2d(j),1,1,1)
338 fld_data2d%y%x(j) = y_ptr(this%idx_2d(j),1,1,1)
339 end do
340 allocate(fields3d(fld_data3d%size()))
341 allocate(fields2d(fld_data3d%size()))
342
343 call fld_data2d%init_n_fields(fld_data3d%size(), n_2d)
344 call fld_data3d%get_list(fields3d,fld_data3d%size())
345
346 this%u = 0.0_rp
347 this%old_u = 0.0_rp
348 this%avg_u = 0.0_rp
349 do i = 1, fld_data3d%size()
350 call copy(this%old_u%x, fields3d(i)%ptr%x, n)
351 call perform_local_summation(this%u,this%old_u,&
352 this%el_heights, this%domain_height, &
353 this%map_1d%dir_el, this%coef, this%msh%nelv, lx)
354 call copy(this%old_u%x, this%u%x,n)
355 call copy(this%avg_u%x, this%u%x,n)
356 call perform_global_summation(this%u, this%avg_u, &
357 this%old_u, this%map_1d%n_el_lvls, &
358 this%map_1d%dir_el, this%coef%gs_h,&
359 this%coef%mult, this%msh%nelv, lx)
360 call copy(fields3d(i)%ptr%x, this%u%x, n)
361 end do
362 call fld_data2d%get_list(fields2d, fld_data2d%size())
363 do i = 1, fld_data3d%size()
364 do j = 1, n_2d
365 fields2d(i)%ptr%x(j) = fields3d(i)%ptr%x(this%idx_2d(j))
366 end do
367 end do
368 end subroutine map_2d_average
369
370 subroutine perform_global_summation(u, avg_u, old_u, n_levels, &
371 hom_dir_el, gs_h, mult, nelv, lx)
372 type(field_t), intent(inout) :: u, avg_u, old_u
373 type(gs_t), intent(inout) :: gs_h
374 integer, intent(in) :: n_levels, nelv, lx
375 integer, intent(in) :: hom_dir_el(nelv)
376 real(kind=rp), intent(in) :: mult(nelv*lx**3)
377 real(kind=rp) :: temp_el(lx,lx,lx)
378 integer :: n, i, j, e
379
380 n = u%dof%size()
381
382 do i = 1, n_levels-1
383 !compute average
384 if (neko_bcknd_device .eq. 1) &
385 call device_memcpy(u%x, u%x_d, n, &
386 host_to_device, sync=.true.)
387 call gs_h%op(u,gs_op_add)
388 if (neko_bcknd_device .eq. 1) &
389 call device_memcpy(u%x, u%x_d, n, device_to_host, sync=.true.)
390 call col2(u%x,mult,n)
391 !Assumes sugarcube I think
392 do e = 1, nelv
393 temp_el = 2.0*u%x(:,:,:,e)-old_u%x(:,:,:,e)
394 if (hom_dir_el(e) .eq. 1) then
395 u%x(1,:,:,e) = temp_el(lx,:,:)
396 avg_u%x(1,:,:,e) = avg_u%x(1,:,:,e)+temp_el(1,:,:)
397 u%x(lx,:,:,e) = temp_el(1,:,:)
398 else if (hom_dir_el(e) .eq. 2) then
399 u%x(:,1,:,e) = temp_el(:,lx,:)
400 avg_u%x(:,1,:,e) = avg_u%x(:,1,:,e)+temp_el(:,1,:)
401 u%x(:,lx,:,e) = temp_el(:,1,:)
402 else if (hom_dir_el(e) .eq. 3) then
403 u%x(:,:,1,e) = temp_el(:,:,lx)
404 avg_u%x(:,:,1,e) = avg_u%x(:,:,1,e)+temp_el(:,:,1)
405 u%x(:,:,lx,e) = temp_el(:,:,1)
406 end if
407 old_u%x(:,:,:,e) = u%x(:,:,:,e)
408 end do
409 end do
410 do e = 1, nelv
411 do i = 1,lx
412 do j = 1, lx
413 if (hom_dir_el(e) .eq. 1) then
414 u%x(:,i,j,e) = avg_u%x(1,i,j,e)
415 else if (hom_dir_el(e) .eq. 2) then
416 u%x(i,:,j,e) = avg_u%x(i,1,j,e)
417 else if (hom_dir_el(e) .eq. 3) then
418 u%x(i,j,:,e) = avg_u%x(i,j,1,e)
419 end if
420 end do
421 end do
422 end do
423 end subroutine perform_global_summation
424
425 subroutine perform_local_summation(u_out, u, el_heights, domain_height,&
426 hom_dir_el, coef, nelv, lx)
427 type(field_t), intent(inout) :: u, u_out, el_heights
428 type(coef_t), intent(inout) :: coef
429 integer, intent(in) :: nelv, lx
430 integer, intent(in) :: hom_dir_el(nelv)
431 real(kind=rp), intent(in) :: domain_height
432 real(kind=rp) :: wt
433 integer :: n, i, j, e, k
434
435 n = nelv*lx**3
436
437 call col2(u%x,el_heights%x,n)
438 call cmult(u%x, 1.0_rp/(2.0*domain_height),n)
439 call rzero(u_out%x,n)
440
441
442 do e = 1, nelv
443 do i = 1,lx
444 do j = 1, lx
445 do k = 1, lx
446 wt = coef%Xh%wx(k)
447 if (hom_dir_el(e) .eq. 1) then
448 u_out%x(1,i,j,e) = u_out%x(1,i,j,e)+wt*u%x(k,i,j,e)
449 else if (hom_dir_el(e) .eq. 2) then
450 u_out%x(i,1,j,e) = u_out%x(i,1,j,e)+wt*u%x(i,k,j,e)
451 else if (hom_dir_el(e) .eq. 3) then
452 u_out%x(i,j,1,e) = u_out%x(i,j,1,e)+wt*u%x(i,j,k,e)
453 end if
454 end do
455 end do
456 end do
457 end do
458
459 do e = 1, nelv
460 do i = 1,lx
461 do j = 1, lx
462 if (hom_dir_el(e) .eq. 1) then
463 u_out%x(:,i,j,e) = u_out%x(1,i,j,e)
464 else if (hom_dir_el(e) .eq. 2) then
465 u_out%x(i,:,j,e) = u_out%x(i,1,j,e)
466 else if (hom_dir_el(e) .eq. 3) then
467 u_out%x(i,j,:,e) = u_out%x(i,j,1,e)
468 end if
469 end do
470 end do
471 end do
472 end subroutine perform_local_summation
473
474end 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:45
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:427
subroutine perform_global_summation(u, avg_u, old_u, n_levels, hom_dir_el, gs_h, mult, nelv, lx)
Definition map_2d.f90:372
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:224
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:300
Definition math.f90:60
subroutine, public cmult(a, c, n)
Multiplication by constant c .
Definition math.f90:504
subroutine, public col2(a, b, n)
Vector multiplication .
Definition math.f90:1046
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:291
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:235
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:12
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:289
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:62
field_list_t, To be able to group fields together
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:88