Neko 1.99.5
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
map_1d.f90
Go to the documentation of this file.
1! Copyright (c) 2023-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!
33!
36module map_1d
38 use num_types, only : rp
39 use space, only : space_t
40 use dofmap, only : dofmap_t
41 use gather_scatter, only : gs_op_add
42 use mesh, only : mesh_t
46 use coefs, only : coef_t
47 use field_list, only : field_list_t
48 use matrix, only : matrix_t
49 use vector, only : vector_ptr_t
50 use utils, only : neko_error, neko_warning
51 use math, only : glmax, glmin, glimax, relcmp, cmult, add2s1, col2
52 use mpi_f08, only : mpi_allreduce, mpi_sum, mpi_barrier, mpi_in_place
53 use, intrinsic :: iso_c_binding
54 implicit none
55 private
56
88 type, public :: map_1d_t
92 integer, allocatable :: dir_el(:)
95 integer, allocatable :: el_lvl(:)
99 integer, allocatable :: pt_lvl(:, :, :, :)
101 integer :: n_el_lvls
105 integer :: n_gll_lvls
107 type(dofmap_t), pointer :: dof => null()
109 type(coef_t), pointer :: coef => null()
111 type(mesh_t), pointer :: msh => null()
114 integer :: dir
116 real(kind=rp) :: tol = 1e-7
119 real(kind=rp), allocatable :: volume_per_gll_lvl(:)
120 contains
122 procedure, pass(this) :: init_int => map_1d_init
123 procedure, pass(this) :: init_char => map_1d_init_char
124 generic :: init => init_int, init_char
126 procedure, pass(this) :: free => map_1d_free
128 procedure, pass(this) :: average_planes_fld_lst => &
130 procedure, pass(this) :: average_planes_vec_ptr => &
132 generic :: average_planes => average_planes_fld_lst, average_planes_vec_ptr
133 end type map_1d_t
134
135
136contains
137
138 subroutine map_1d_init(this, coef, dir, tol)
139 class(map_1d_t) :: this
140 type(coef_t), intent(inout), target :: coef
141 integer, intent(in) :: dir
142 real(kind=rp), intent(in) :: tol
143 integer :: nelv, lx, n, i, e, lvl, ierr
144 real(kind=rp), contiguous, pointer :: line(:, :, :, :)
145 real(kind=rp), allocatable :: min_vals(:, :, :, :)
146 real(kind=rp), allocatable :: min_temp(:, :, :, :)
147 type(c_ptr) :: min_vals_d = c_null_ptr
148 real(kind=rp) :: el_dim(3, 3), glb_min, glb_max, el_min
149
150 call this%free()
151
152 if (neko_bcknd_device .eq. 1) then
153 if (pe_rank .eq. 0) then
154 call neko_warning('map_1d does not copy indices to device, ' // &
155 ' but ok if used on cpu and for io')
156 end if
157 end if
158
159 this%dir = dir
160 this%tol = tol
161 this%dof => coef%dof
162 this%coef => coef
163 this%msh => coef%msh
164 nelv = this%msh%nelv
165 lx = this%dof%Xh%lx
166 n = this%dof%size()
167
168 if (dir .eq. 1) then
169 line => this%dof%x
170 else if (dir .eq. 2) then
171 line => this%dof%y
172 else if (dir .eq. 3) then
173 line => this%dof%z
174 else
175 call neko_error('Invalid dir for geopmetric comm')
176 end if
177 allocate(this%dir_el(nelv))
178 allocate(this%el_lvl(nelv))
179 allocate(this%pt_lvl(lx, lx, lx, nelv))
180 allocate(min_vals(lx, lx, lx, nelv))
181 allocate(min_temp(lx, lx, lx, nelv))
182 call mpi_barrier(neko_comm)
183 if (neko_bcknd_device .eq. 1) then
184
185 call device_map(min_vals, min_vals_d, n)
186 end if
187 call mpi_barrier(neko_comm)
188
189 do i = 1, nelv
190 ! Store which direction r,s,t corresponds to specified direction, x,y,z
191 ! we assume elements are stacked on each other...
192 ! Check which one of the normalized vectors are closest to dir
193 ! If we want to incorporate other directions, we should look here
194
195 ! This follows the point ordering defined in hex.f90
196 el_dim(1, :) = abs(this%msh%elements(i)%e%pts(1)%p%x - &
197 this%msh%elements(i)%e%pts(2)%p%x)
198 el_dim(1, :) = el_dim(1, :)/norm2(el_dim(1, :))
199 el_dim(2, :) = abs(this%msh%elements(i)%e%pts(1)%p%x - &
200 this%msh%elements(i)%e%pts(3)%p%x)
201 el_dim(2, :) = el_dim(2, :)/norm2(el_dim(2, :))
202 el_dim(3, :) = abs(this%msh%elements(i)%e%pts(1)%p%x - &
203 this%msh%elements(i)%e%pts(5)%p%x)
204 el_dim(3, :) = el_dim(3, :)/norm2(el_dim(3, :))
205 ! Checks which directions in rst the xyz corresponds to
206 ! 1 corresponds to r, 2 to s, 3 to t and are stored in dir_el
207 this%dir_el(i) = maxloc(el_dim(:, this%dir), dim = 1)
208 end do
209
210 glb_min = glmin(line, n)
211 glb_max = glmax(line, n)
212
213 i = 1
214 this%el_lvl = -1
215 ! Check what the minimum value in each element and put in min_vals
216 do e = 1, nelv
217 el_min = minval(line(:, :, :, e))
218 min_vals(:, :, :, e) = el_min
219 ! Check if this element is on the bottom,
220 ! in this case assign el_lvl = i = 1
221 if (relcmp(el_min, glb_min, this%tol)) then
222 if (this%el_lvl(e) .eq. -1) this%el_lvl(e) = i
223 end if
224 end do
225
226 ! While loop where at each iteration the global maximum value
227 ! propagates down one level.
228 ! When the minimum value has propagated to the highest level this stops.
229 ! Only works when the bottom plate of the domain is flat.
230 do while (.not. relcmp(glmax(min_vals, n), glb_min, this%tol))
231
232 ! This is the assigned level
233 i = i + 1
234
235 do e = 1, nelv
236 !Sets the value at the bottom of each element to glb_max
237 if (this%dir_el(e) .eq. 1) then
238 if (line(1, 1, 1, e) .gt. line(lx, 1, 1, e)) then
239 min_vals(lx, :, :, e) = glb_max
240 else
241 min_vals(1, :, :, e) = glb_max
242 end if
243 end if
244 if (this%dir_el(e) .eq. 2) then
245 if (line(1, 1, 1, e) .gt. line(1, lx, 1, e)) then
246 min_vals(:, lx, :, e) = glb_max
247 else
248 min_vals(:, 1, :, e) = glb_max
249 end if
250 end if
251 if (this%dir_el(e) .eq. 3) then
252 if (line(1, 1, 1, e) .gt. line(1, 1, lx, e)) then
253 min_vals(:, :, lx, e) = glb_max
254 else
255 min_vals(:, :, 1, e) = glb_max
256 end if
257 end if
258 end do
259
260 !Make sketchy min as GS_OP_MIN is not supported with device mpi
261 min_temp = min_vals
262
263 if (neko_bcknd_device .eq. 1) then
264 call device_memcpy(min_vals, min_vals_d, n, host_to_device, &
265 sync = .false.)
266 end if
267
268 !Propagates the minimum value along the element boundary.
269 call coef%gs_h%op(min_vals, n, gs_op_add)
270
271 if (neko_bcknd_device .eq. 1) then
272 call device_memcpy(min_vals, min_vals_d, n, device_to_host, &
273 sync = .true.)
274 end if
275
276 !Obtain average along boundary
277 call col2(min_vals, coef%mult, n)
278 call cmult(min_temp, -1.0_rp, n)
279 call add2s1(min_vals, min_temp, 2.0_rp, n)
280
281 !Checks the new minimum value on each element
282 !Assign this value to all points in this element in min_val
283 !If the element has not already been assigned a level,
284 !and it has obtained the minval, set el_lvl = i
285 do e = 1, nelv
286 el_min = minval(min_vals(:, :, :, e))
287 min_vals(:, :, :, e) = el_min
288 if (relcmp(el_min, glb_min, this%tol)) then
289 if (this%el_lvl(e) .eq. -1) this%el_lvl(e) = i
290 end if
291 end do
292 end do
293 this%n_el_lvls = glimax(this%el_lvl, nelv)
294 this%n_gll_lvls = this%n_el_lvls*lx
295
296 !Numbers the points in each element based on the element level
297 !and its orientation
298 do e = 1, nelv
299 do i = 1, lx
300 lvl = lx * (this%el_lvl(e) - 1) + i
301 if (this%dir_el(e) .eq. 1) then
302 if (line(1, 1, 1, e) .gt. line(lx, 1, 1, e)) then
303 this%pt_lvl(lx-i+1, :, :, e) = lvl
304 else
305 this%pt_lvl(i, :, :, e) = lvl
306 end if
307 end if
308 if (this%dir_el(e) .eq. 2) then
309 if (line(1, 1, 1, e) .gt. line(1, lx, 1, e)) then
310 this%pt_lvl(:, lx-i+1, :, e) = lvl
311 else
312 this%pt_lvl(:, i, :, e) = lvl
313 end if
314 end if
315 if (this%dir_el(e) .eq. 3) then
316 if (line(1, 1, 1, e) .gt. line(1, 1, lx, e)) then
317 this%pt_lvl(:, :, lx-i+1, e) = lvl
318 else
319 this%pt_lvl(:, :, i, e) = lvl
320 end if
321 end if
322 end do
323 end do
324
325 if (allocated(min_vals)) then
326 if (c_associated(min_vals_d)) call device_unmap(min_vals, min_vals_d)
327 deallocate(min_vals)
328 end if
329
330 if (allocated(min_temp)) deallocate(min_temp)
331 allocate(this%volume_per_gll_lvl(this%n_gll_lvls))
332
333 this%volume_per_gll_lvl = 0.0_rp
334
335 do i = 1, n
336 this%volume_per_gll_lvl(this%pt_lvl(i, 1, 1, 1)) = &
337 this%volume_per_gll_lvl(this%pt_lvl(i, 1, 1, 1)) + &
338 coef%B(i, 1, 1, 1)
339 end do
340
341 call mpi_allreduce(mpi_in_place, this%volume_per_gll_lvl, this%n_gll_lvls, &
342 mpi_real_precision, mpi_sum, neko_comm, ierr)
343
344 end subroutine map_1d_init
345
346 subroutine map_1d_init_char(this, coef, dir, tol)
347 class(map_1d_t) :: this
348 type(coef_t), intent(inout), target :: coef
349 character(len=*), intent(in) :: dir
350 real(kind=rp), intent(in) :: tol
351 integer :: idir
352
353 if (trim(dir) .eq. 'yz' .or. trim(dir) .eq. 'zy') then
354 idir = 1
355 else if (trim(dir) .eq. 'xz' .or. trim(dir) .eq. 'zx') then
356 idir = 2
357 else if (trim(dir) .eq. 'xy' .or. trim(dir) .eq. 'yx') then
358 idir = 3
359 else
360 call neko_error('homogenous direction not supported')
361 end if
362
363 call this%init(coef, idir, tol)
364
365 end subroutine map_1d_init_char
366
368 subroutine map_1d_free(this)
369 class(map_1d_t) :: this
370
371 if (allocated(this%dir_el)) deallocate(this%dir_el)
372 if (allocated(this%el_lvl)) deallocate(this%el_lvl)
373 if (allocated(this%pt_lvl)) deallocate(this%pt_lvl)
374 if (associated(this%dof)) nullify(this%dof)
375 if (associated(this%msh)) nullify(this%msh)
376 if (associated(this%coef)) nullify(this%coef)
377 if (allocated(this%volume_per_gll_lvl)) deallocate(this%volume_per_gll_lvl)
378 this%dir = 0
379 this%n_el_lvls = 0
380 this%n_gll_lvls = 0
381
382 end subroutine map_1d_free
383
384
390 subroutine map_1d_average_field_list(this, avg_planes, field_list)
391 class(map_1d_t), intent(inout) :: this
392 type(field_list_t), intent(inout) :: field_list
393 type(matrix_t), intent(inout) :: avg_planes
394 integer :: n, ierr, j, i
395 real(kind=rp) :: coord
396 call avg_planes%free()
397 call avg_planes%init(this%n_gll_lvls, field_list%size() + 1)
398 avg_planes = 0.0_rp
399 !ugly way of getting coordinates, computes average
400 n = this%dof%size()
401 do i = 1, n
402 if (this%dir .eq. 1) coord = this%dof%x(i,1,1,1)
403 if (this%dir .eq. 2) coord = this%dof%y(i,1,1,1)
404 if (this%dir .eq. 3) coord = this%dof%z(i,1,1,1)
405 avg_planes%x(this%pt_lvl(i,1,1,1), 1) = &
406 avg_planes%x(this%pt_lvl(i,1,1,1), 1) + &
407 coord * this%coef%B(i,1,1,1) / &
408 this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1))
409 end do
410 do j = 2, field_list%size() + 1
411 do i = 1, n
412 avg_planes%x(this%pt_lvl(i,1,1,1), j) = &
413 avg_planes%x(this%pt_lvl(i,1,1,1), j) + &
414 field_list%items(j-1)%ptr%x(i,1,1,1) * this%coef%B(i,1,1,1) &
415 /this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1))
416 end do
417 end do
418 if (pe_size .gt. 1) then
419 call mpi_allreduce(mpi_in_place, avg_planes%x, &
420 (field_list%size() + 1) * this%n_gll_lvls, mpi_real_precision, &
421 mpi_sum, neko_comm, ierr)
422 end if
423
424 end subroutine map_1d_average_field_list
425
431 subroutine map_1d_average_vector_ptr(this, avg_planes, vector_ptr)
432 class(map_1d_t), intent(inout) :: this
433 !Observe is an array...
434 type(vector_ptr_t), intent(inout) :: vector_ptr(:)
435 type(matrix_t), intent(inout) :: avg_planes
436 integer :: n, ierr, j, i
437 real(kind=rp) :: coord
438
439 call avg_planes%free()
440 call avg_planes%init(this%n_gll_lvls, size(vector_ptr) + 1)
441 !ugly way of getting coordinates, computes average
442 avg_planes = 0.0_rp
443
444 n = this%dof%size()
445 do i = 1, n
446 if (this%dir .eq. 1) coord = this%dof%x(i,1,1,1)
447 if (this%dir .eq. 2) coord = this%dof%y(i,1,1,1)
448 if (this%dir .eq. 3) coord = this%dof%z(i,1,1,1)
449 avg_planes%x(this%pt_lvl(i,1,1,1), 1) = &
450 avg_planes%x(this%pt_lvl(i,1,1,1), 1) + &
451 coord * this%coef%B(i,1,1,1) / &
452 this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1))
453 end do
454 do j = 2, size(vector_ptr) + 1
455 do i = 1, n
456 avg_planes%x(this%pt_lvl(i,1,1,1), j) = &
457 avg_planes%x(this%pt_lvl(i,1,1,1), j) + &
458 vector_ptr(j-1)%ptr%x(i)*this%coef%B(i,1,1,1) &
459 /this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1))
460 end do
461 end do
462 call mpi_allreduce(mpi_in_place, avg_planes%x, &
463 (size(vector_ptr) + 1) * this%n_gll_lvls, mpi_real_precision, &
464 mpi_sum, neko_comm, ierr)
465
466
467 end subroutine map_1d_average_vector_ptr
468
469end module map_1d
Map a Fortran array to a device (allocate and associate)
Definition device.F90:78
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:84
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
Definition comm.F90:53
integer, public pe_size
MPI size of communicator.
Definition comm.F90:61
integer, public pe_rank
MPI rank.
Definition comm.F90:58
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
Gather-scatter.
Creates a 1d GLL point map along a specified direction based on the connectivity in the mesh.
Definition map_1d.f90:36
subroutine map_1d_init(this, coef, dir, tol)
Definition map_1d.f90:139
subroutine map_1d_free(this)
Destructor.
Definition map_1d.f90:369
subroutine map_1d_average_field_list(this, avg_planes, field_list)
Computes average if field list in two directions and outputs matrix with averaged values avg_planes c...
Definition map_1d.f90:391
subroutine map_1d_init_char(this, coef, dir, tol)
Definition map_1d.f90:347
subroutine map_1d_average_vector_ptr(this, avg_planes, vector_ptr)
Computes average of vector_pt in two directions and outputs matrix with averaged values avg_planes co...
Definition map_1d.f90:432
Definition math.f90:60
subroutine, public cmult(a, c, n)
Multiplication by constant c .
Definition math.f90:504
subroutine, public add2s1(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on first argument)
Definition math.f90:981
subroutine, public col2(a, b, n)
Vector multiplication .
Definition math.f90:1046
real(kind=rp) function, public glmax(a, n)
Max of a vector of length n.
Definition math.f90:650
integer function, public glimax(a, n)
Max of an integer vector of length n.
Definition math.f90:669
real(kind=rp) function, public glmin(a, n)
Min of a vector of length n.
Definition math.f90:688
Defines a matrix.
Definition matrix.f90:34
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
Defines a function space.
Definition space.f90:34
Utilities.
Definition utils.f90:35
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:398
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
The function space for the SEM solution fields.
Definition space.f90:63