Neko 1.99.6
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
field.f90
Go to the documentation of this file.
1! Copyright (c) 2018-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!
34module field
37 use num_types, only : rp, c_rp
39 use math, only : add2, copy, cadd, cfill
40 use mesh, only : mesh_t
41 use space, only : space_t, operator(.ne.)
42 use dofmap, only : dofmap_t
43 use utils, only : neko_varname_len
44 use, intrinsic :: iso_c_binding
45 implicit none
46 private
47
48 type, public :: field_t
49 real(kind=rp), allocatable :: x(:,:,:,:)
50
51 type(space_t), pointer :: xh
52 type(mesh_t), pointer :: msh
53 type(dofmap_t), pointer :: dof
54
55 logical :: internal_dofmap = .false.
56 character(len=NEKO_VARNAME_LEN) :: name = ""
57 type(c_ptr) :: x_d = c_null_ptr
58 contains
59 procedure, private, pass(this) :: init_common => field_init_common
60 procedure, private, pass(this) :: init_external_dof => &
62 procedure, private, pass(this) :: init_internal_dof => &
64 procedure, private, pass(this) :: assign_field => field_assign_field
65 procedure, private, pass(this) :: assign_scalar => field_assign_scalar
66 procedure, private, pass(this) :: add_field => field_add_field
67 procedure, private, pass(this) :: add_scalar => field_add_scalar
68 procedure, pass(this) :: copy_from => field_copy_from
69 procedure, pass(this) :: free => field_free
71 procedure, pass(this) :: size => field_size
73 generic :: init => init_external_dof, init_internal_dof
75 generic :: assignment(=) => assign_field, assign_scalar
79 generic :: add => add_field, add_scalar
80 end type field_t
81
83 type, public :: field_ptr_t
84 type(field_t), pointer :: ptr => null()
85 contains
87 procedure, pass(this) :: init => field_ptr_init
89 procedure, pass(this) :: free => field_ptr_free
90 end type field_ptr_t
91
93 type, public :: field_wrapper_t
94 type(field_t), pointer :: field => null()
95 contains
97 generic :: init => init_field, init_internal_dof, init_external_dof
99 procedure, pass(this) :: init_field => field_wrapper_init_field
101 procedure, pass(this) :: init_internal_dof => &
104 procedure, pass(this) :: init_external_dof => &
107 procedure, pass(this) :: free => field_wrapper_free
108 end type field_wrapper_t
109
110contains
111
113 subroutine field_init_internal_dof(this, msh, space, fld_name)
114 class(field_t), intent(inout) :: this
115 type(mesh_t), target, intent(in) :: msh
116 type(space_t), target, intent(in) :: space
117 character(len=*), optional :: fld_name
118
119 call this%free()
120
121 this%Xh => space
122 this%msh => msh
123
124 allocate(this%dof)
125 call this%dof%init(this%msh, this%Xh)
126 this%internal_dofmap = .true.
127
128 if (present(fld_name)) then
129 call this%init_common(fld_name)
130 else
131 call this%init_common()
132 end if
133
134 end subroutine field_init_internal_dof
135
137 subroutine field_init_external_dof(this, dof, fld_name)
138 class(field_t), intent(inout) :: this
139 type(dofmap_t), target, intent(in) :: dof
140 character(len=*), optional :: fld_name
141
142 call this%free()
143
144 this%dof => dof
145 this%Xh => dof%Xh
146 this%msh => dof%msh
147
148 if (present(fld_name)) then
149 call this%init_common(fld_name)
150 else
151 call this%init_common()
152 end if
153
154 end subroutine field_init_external_dof
155
157 subroutine field_init_common(this, fld_name)
158 class(field_t), intent(inout) :: this
159 character(len=*), optional :: fld_name
160 integer :: ierr
161 integer :: n
162 logical :: fresh
163
164 associate(lx => this%Xh%lx, ly => this%Xh%ly, &
165 lz => this%Xh%lz, nelv => this%msh%nelv)
166
167 fresh = .not. allocated(this%x)
168 if (fresh) then
169 allocate(this%x(lx, ly, lz, nelv), stat = ierr)
170 end if
171
172 if (present(fld_name)) then
173 this%name = fld_name
174 else
175 this%name = "Field"
176 end if
177
178 if (neko_bcknd_device .eq. 1) then
179 n = lx * ly * lz * nelv
180 call device_map(this%x, this%x_d, n)
181 block
182 real(c_rp) :: rp_dummy
183 integer(c_size_t) :: s
184 s = c_sizeof(rp_dummy) * n
185 call device_memset(this%x_d, 0, s, sync = .true.)
186 end block
187 end if
188
189 ! Zero on the host after the device-side memset: under zero-copy
190 ! the device then faults the pages first (device first touch),
191 ! which gives contiguous physical mappings and thus better GPU
192 ! TLB utilisation; rewriting the zeros on the host is benign
193 if (fresh) then
194 this%x = 0.0_rp
195 end if
196 end associate
197
198 end subroutine field_init_common
199
201 subroutine field_free(this)
202 class(field_t), intent(inout) :: this
203
204 this%name = ""
205 if (allocated(this%x)) then
206 if (neko_bcknd_device .eq. 1) then
207 call device_unmap(this%x, this%x_d)
208 end if
209 deallocate(this%x)
210 end if
211
212 if (this%internal_dofmap) then
213 call this%dof%free()
214 deallocate(this%dof)
215 this%internal_dofmap = .false.
216 end if
217
218 nullify(this%msh)
219 nullify(this%Xh)
220 nullify(this%dof)
221
222 end subroutine field_free
223
228 subroutine field_copy_from(this, memdir, sync)
229 class(field_t), intent(inout) :: this
230 integer, intent(in) :: memdir
231 logical, intent(in) :: sync
232
233 if (neko_bcknd_device .eq. 1) then
234 call device_memcpy(this%x, this%x_d, this%size(), memdir, sync)
235 end if
236
237 end subroutine field_copy_from
238
239
243 subroutine field_assign_field(this, g)
244 class(field_t), intent(inout) :: this
245 type(field_t), intent(in) :: g
246
247 if (allocated(this%x)) then
248 if (.not. associated(this%Xh, g%Xh)) then
249 call this%free()
250 end if
251 end if
252
253 this%Xh => g%Xh
254 this%msh => g%msh
255 if (len_trim(this%name) == 0) then
256 this%name = g%name
257 end if
258
259 if (.not. g%internal_dofmap) then
260 if (this%internal_dofmap) then
261 call this%dof%free()
262 deallocate(this%dof)
263 this%internal_dofmap = .false.
264 end if
265 this%dof => g%dof
266 else
267 if (this%internal_dofmap) then
268 call this%dof%free()
269 else
270 allocate(this%dof)
271 this%internal_dofmap = .true.
272 end if
273 call this%dof%init(this%msh, this%Xh)
274 end if
275
276 if (.not. allocated(this%x)) then
277
278 allocate(this%x(this%Xh%lx, this%Xh%ly, this%Xh%lz, this%msh%nelv))
279
280 if (neko_bcknd_device .eq. 1) then
281 call device_map(this%x, this%x_d, this%size())
282 end if
283
284 end if
285
286 if (neko_bcknd_device .eq. 1) then
287 call device_copy(this%x_d, g%x_d, this%size())
288 else
289 call copy(this%x, g%x, this%dof%size())
290 end if
291
292 end subroutine field_assign_field
293
295 subroutine field_assign_scalar(this, a)
296 class(field_t), intent(inout) :: this
297 real(kind=rp), intent(in) :: a
298
299 if (neko_bcknd_device .eq. 1) then
300 call device_cfill(this%x_d, a, this%size())
301 else
302 call cfill(this%x, a, this%size())
303 end if
304
305 end subroutine field_assign_scalar
306
310 subroutine field_add_field(this, g)
311 class(field_t), intent(inout) :: this
312 type(field_t), intent(in) :: g
313
314 if (neko_bcknd_device .eq. 1) then
315 call device_add2(this%x_d, g%x_d, this%size())
316 else
317 call add2(this%x, g%x, this%size())
318 end if
319
320 end subroutine field_add_field
321
322
325 subroutine field_add_scalar(this, a)
326 class(field_t), intent(inout) :: this
327 real(kind=rp), intent(in) :: a
328
329 if (neko_bcknd_device .eq. 1) then
330 call device_cadd(this%x_d, a, this%size())
331 else
332 call cadd(this%x, a, this%size())
333 end if
334
335 end subroutine field_add_scalar
336
338 pure function field_size(this) result(size)
339 class(field_t), intent(in) :: this
340 integer :: size
341
342 size = this%dof%size()
343 end function field_size
344
345 ! ========================================================================== !
346 ! Field pointer type subroutines
347
348 subroutine field_ptr_init(this, ptr)
349 class(field_ptr_t), intent(inout) :: this
350 type(field_t), target, intent(in) :: ptr
351
352 call this%free()
353
354 this%ptr => ptr
355
356 end subroutine field_ptr_init
357
358 subroutine field_ptr_free(this)
359 class(field_ptr_t), intent(inout) :: this
360
361 if (associated(this%ptr)) then
362 nullify(this%ptr)
363 end if
364
365 end subroutine field_ptr_free
366
367 ! ========================================================================== !
368 ! Field wrapper type subroutines
369
370 subroutine field_wrapper_init_field(this, f)
371 class(field_wrapper_t), intent(inout) :: this
372 type(field_t), intent(in) :: f
373
374 call this%free()
375 allocate(this%field)
376 this%field = f
377
378 end subroutine field_wrapper_init_field
379
380 subroutine field_wrapper_init_internal_dof(this, msh, space, fld_name)
381 class(field_wrapper_t), intent(inout) :: this
382 type(mesh_t), target, intent(in) :: msh
383 type(space_t), target, intent(in) :: space
384 character(len=*), optional :: fld_name
385
386 call this%free()
387 allocate(this%field)
388 call this%field%init(msh, space, fld_name)
389
391
392 subroutine field_wrapper_init_external_dof(this, dof, fld_name)
393 class(field_wrapper_t), intent(inout) :: this
394 type(dofmap_t), target, intent(in) :: dof
395 character(len=*), optional :: fld_name
396
397 call this%free()
398 allocate(this%field)
399 call this%field%init(dof, fld_name)
400
402
403 subroutine field_wrapper_free(this)
404 class(field_wrapper_t), intent(inout) :: this
405
406 if (associated(this%field)) then
407 call this%field%free()
408 deallocate(this%field)
409 end if
410
411 end subroutine field_wrapper_free
412
413end module field
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
subroutine, public device_add2(a_d, b_d, n, strm)
Vector addition .
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
subroutine, public device_cfill(a_d, c, n, strm)
Set all elements to a constant c .
Device abstraction, common interface for various accelerators.
Definition device.F90:34
subroutine, public device_memset(x_d, v, s, sync, strm)
Set memory on the device to a value.
Definition device.F90:268
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Defines a field.
Definition field.f90:34
subroutine field_add_field(this, g)
Add .
Definition field.f90:311
pure integer function field_size(this)
Return the size of the field based on the underlying dofmap.
Definition field.f90:339
subroutine field_assign_field(this, g)
Assignment .
Definition field.f90:244
subroutine field_wrapper_free(this)
Definition field.f90:404
subroutine field_add_scalar(this, a)
Add .
Definition field.f90:326
subroutine field_copy_from(this, memdir, sync)
Easy way to copy between host and device.
Definition field.f90:229
subroutine field_assign_scalar(this, a)
Assignment .
Definition field.f90:296
subroutine field_ptr_init(this, ptr)
Definition field.f90:349
subroutine field_ptr_free(this)
Definition field.f90:359
subroutine field_wrapper_init_internal_dof(this, msh, space, fld_name)
Definition field.f90:381
subroutine field_init_common(this, fld_name)
Initialize a field this.
Definition field.f90:158
subroutine field_wrapper_init_external_dof(this, dof, fld_name)
Definition field.f90:393
subroutine field_wrapper_init_field(this, f)
Definition field.f90:371
subroutine field_init_external_dof(this, dof, fld_name)
Initialize a field this on the mesh msh using an internal dofmap.
Definition field.f90:138
subroutine field_init_internal_dof(this, msh, space, fld_name)
Initialize a field this on the mesh msh using an internal dofmap.
Definition field.f90:114
subroutine field_free(this)
Deallocate a field f.
Definition field.f90:202
Definition math.f90:60
subroutine, public cadd(a, s, n)
Add a scalar to vector .
Definition math.f90:566
subroutine, public add2(a, b, n)
Vector addition .
Definition math.f90:900
subroutine, public cfill(a, c, n)
Set all elements to a constant c .
Definition math.f90:597
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:291
Defines a mesh.
Definition mesh.f90:34
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public c_rp
Definition num_types.f90:13
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
integer, parameter, public neko_varname_len
Definition utils.f90:43
field_ptr_t, To easily obtain a pointer to a field
Definition field.f90:83
field_wrapper_t, used to wrap an allocated field for use in a field list
Definition field.f90:93
The function space for the SEM solution fields.
Definition space.f90:64