Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
tensor4.f90
Go to the documentation of this file.
1! Copyright (c) 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 tensor4
36 use num_types, only : rp
38 use math, only : cfill
41 use, intrinsic :: iso_c_binding
42 implicit none
43 private
44
45 type, public :: tensor4_t
46 real(kind=rp), allocatable :: x(:,:,:,:)
47 character(len=NEKO_VARNAME_LEN) :: name = ""
48 type(c_ptr) :: x_d = c_null_ptr
49 integer, private :: n1 = 0
50 integer, private :: n2 = 0
51 integer, private :: n3 = 0
52 integer, private :: n4 = 0
53 integer, private :: n = 0
54 contains
56 procedure, pass(t), private :: init_dims => tensor4_init
62 generic :: init => init_dims
64 procedure, pass(t) :: free => tensor4_free
66 procedure, pass(t) :: size => tensor4_size
68 procedure, pass(t) :: copy_from => tensor4_copy_from
70 procedure, pass(t) :: get_n1 => tensor4_n1
72 procedure, pass(t) :: get_n2 => tensor4_n2
74 procedure, pass(t) :: get_n3 => tensor4_n3
76 procedure, pass(t) :: get_n4 => tensor4_n4
78 procedure, pass(t) :: get_dims => tensor4_get_dims
80 procedure, pass(t) :: tensor4_assign_tensor4
82 procedure, pass(t) :: tensor4_assign_scalar
83
84 generic :: assignment(=) => tensor4_assign_tensor4, &
86
88 procedure, pass(t), private :: alloc => tensor4_allocate
89 end type tensor4_t
90
91 type, public :: tensor4_ptr_t
92 type(tensor4_t), pointer :: ptr => null()
93 contains
95 procedure, pass(this) :: init => tensor4_ptr_init
97 procedure, pass(this) :: free => tensor4_ptr_free
98 end type tensor4_ptr_t
99
100contains
101
109 subroutine tensor4_init(t, n1, n2, n3, n4, name)
110 class(tensor4_t), intent(inout) :: t
111 integer, intent(in) :: n1
112 integer, intent(in) :: n2
113 integer, intent(in) :: n3
114 integer, intent(in) :: n4
115 character(len=*), intent(in), optional :: name
116
117 ! t%alloc zeroes the device side (and synchronizes) before any
118 ! host-side touch: under zero-copy the device then faults the
119 ! pages first (device first touch), which gives contiguous
120 ! physical mappings and thus better GPU TLB utilisation; rewriting
121 ! the zeros on the host afterwards is benign.
122 call t%alloc(n1, n2, n3, n4)
123
124 if (present(name)) then
125 t%name = name
126 end if
127
128 end subroutine tensor4_init
129
136 subroutine tensor4_allocate(t, n1, n2, n3, n4)
137 class(tensor4_t), intent(inout) :: t
138 integer, intent(in) :: n1
139 integer, intent(in) :: n2
140 integer, intent(in) :: n3
141 integer, intent(in) :: n4
142
143 call t%free()
144
145 allocate(t%x(n1, n2, n3, n4))
146 t%n1 = n1
147 t%n2 = n2
148 t%n3 = n3
149 t%n4 = n4
150 t%n = n1*n2*n3*n4
151
152 if (neko_bcknd_device .eq. 1) then
153 call device_map(t%x, t%x_d, t%n)
154 call device_cfill(t%x_d, 0.0_rp, t%n)
155 call device_sync()
156 end if
157 call cfill(t%x, 0.0_rp, t%n)
158
159 end subroutine tensor4_allocate
160
163 subroutine tensor4_free(t)
164 class(tensor4_t), intent(inout) :: t
165
166 if (allocated(t%x)) then
167 if (neko_bcknd_device .eq. 1) then
168 call device_unmap(t%x, t%x_d)
169 end if
170 deallocate(t%x)
171 end if
172
173 t%n1 = 0
174 t%n2 = 0
175 t%n3 = 0
176 t%n4 = 0
177 t%n = 0
178 t%name = ""
179
180 end subroutine tensor4_free
181
184 pure function tensor4_size(t) result(s)
185 class(tensor4_t), intent(in) :: t
186 integer :: s
187 s = t%n
188 end function tensor4_size
189
194 subroutine tensor4_copy_from(t, memdir, sync)
195 class(tensor4_t), intent(inout) :: t
196 integer, intent(in) :: memdir
197 logical, intent(in) :: sync
198
199 if (neko_bcknd_device .eq. 1) then
200 call device_memcpy(t%x, t%x_d, t%n, memdir, sync)
201 end if
202
203 end subroutine tensor4_copy_from
204
207 pure function tensor4_n1(t) result(n1)
208 class(tensor4_t), intent(in) :: t
209 integer :: n1
210 n1 = t%n1
211 end function tensor4_n1
212
215 pure function tensor4_n2(t) result(n2)
216 class(tensor4_t), intent(in) :: t
217 integer :: n2
218 n2 = t%n2
219 end function tensor4_n2
220
223 pure function tensor4_n3(t) result(n3)
224 class(tensor4_t), intent(in) :: t
225 integer :: n3
226 n3 = t%n3
227 end function tensor4_n3
228
231 pure function tensor4_n4(t) result(n4)
232 class(tensor4_t), intent(in) :: t
233 integer :: n4
234 n4 = t%n4
235 end function tensor4_n4
236
239 pure function tensor4_get_dims(t) result(dims)
240 class(tensor4_t), intent(in) :: t
241 integer :: dims(4)
242 dims = [t%n1, t%n2, t%n3, t%n4]
243 end function tensor4_get_dims
244
248 subroutine tensor4_assign_tensor4(t, w)
249 class(tensor4_t), intent(inout) :: t
250 type(tensor4_t), intent(in) :: w
251
252 if (allocated(t%x)) then
253 call t%free()
254 end if
255
256 if (.not. allocated(t%x)) then
257
258 t%n1 = w%n1
259 t%n2 = w%n2
260 t%n3 = w%n3
261 t%n4 = w%n4
262 t%n = w%n
263 allocate(t%x(t%n1, t%n2, t%n3, t%n4))
264
265 if (neko_bcknd_device .eq. 1) then
266 call device_map(t%x, t%x_d, t%n)
267 end if
268
269 end if
270
271 if (neko_bcknd_device .eq. 1) then
272 call device_copy(t%x_d, w%x_d, t%n)
273 else
274 t%x = w%x
275 end if
276
277 t%name = w%name
278
279 end subroutine tensor4_assign_tensor4
280
284 subroutine tensor4_assign_scalar(t, s)
285 class(tensor4_t), intent(inout) :: t
286 real(kind=rp), intent(in) :: s
287
288 if (.not. allocated(t%x)) then
289 call neko_error('tensor4 not allocated')
290 end if
291
292 if (neko_bcknd_device .eq. 1) then
293 call device_cfill(t%x_d, s, t%n)
294 else
295 t%x = s
296 end if
297
298 end subroutine tensor4_assign_scalar
299
300 ! ========================================================================== !
301 ! tensor4 pointer type subroutines
302
306 subroutine tensor4_ptr_init(this, ptr)
307 class(tensor4_ptr_t), intent(inout) :: this
308 type(tensor4_t), target, intent(in) :: ptr
309
310 call this%free()
311 this%ptr => ptr
312 end subroutine tensor4_ptr_init
313
316 subroutine tensor4_ptr_free(this)
317 class(tensor4_ptr_t), intent(inout) :: this
318
319 if (associated(this%ptr)) then
320 nullify(this%ptr)
321 end if
322
323 end subroutine tensor4_ptr_free
324
325end module tensor4
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
Synchronize a device or stream.
Definition device.F90:119
Unmap a Fortran array from a device (deassociate and free)
Definition device.F90:89
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
Definition math.f90:60
subroutine, public cfill(a, c, n)
Set all elements to a constant c .
Definition math.f90:601
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Defines a rank-4 tensor.
Definition tensor4.f90:34
subroutine tensor4_ptr_free(this)
Destructor. Just nullifies the pointer.
Definition tensor4.f90:317
subroutine tensor4_copy_from(t, memdir, sync)
Easy way to copy between host and device.
Definition tensor4.f90:195
pure integer function, dimension(4) tensor4_get_dims(t)
Returns the dimensions of the tensor.
Definition tensor4.f90:240
pure integer function tensor4_size(t)
Returns the number of entries in the tensor.
Definition tensor4.f90:185
subroutine tensor4_init(t, n1, n2, n3, n4, name)
Initialise a tensor of size n1*n2*n3*n4.
Definition tensor4.f90:110
subroutine tensor4_allocate(t, n1, n2, n3, n4)
Allocate a tensor of size n1*n2*n3*n4.
Definition tensor4.f90:137
subroutine tensor4_free(t)
Deallocate a tensor.
Definition tensor4.f90:164
pure integer function tensor4_n3(t)
Returns the size of the third dimension.
Definition tensor4.f90:224
subroutine tensor4_ptr_init(this, ptr)
Constructor. Just assigns the pointer.
Definition tensor4.f90:307
pure integer function tensor4_n4(t)
Returns the size of the fourth dimension.
Definition tensor4.f90:232
pure integer function tensor4_n2(t)
Returns the size of the second dimension.
Definition tensor4.f90:216
pure integer function tensor4_n1(t)
Returns the size of the first dimension.
Definition tensor4.f90:208
subroutine tensor4_assign_tensor4(t, w)
Assignment .
Definition tensor4.f90:249
subroutine tensor4_assign_scalar(t, s)
Assignment .
Definition tensor4.f90:285
Utilities.
Definition utils.f90:35
integer, parameter, public neko_varname_len
Definition utils.f90:43