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) :: tensor4_assign_tensor4
80 procedure, pass(t) :: tensor4_assign_scalar
81
82 generic :: assignment(=) => tensor4_assign_tensor4, &
84
86 procedure, pass(t), private :: alloc => tensor4_allocate
87 end type tensor4_t
88
89 type, public :: tensor4_ptr_t
90 type(tensor4_t), pointer :: ptr => null()
91 contains
93 procedure, pass(this) :: init => tensor4_ptr_init
95 procedure, pass(this) :: free => tensor4_ptr_free
96 end type tensor4_ptr_t
97
98contains
99
107 subroutine tensor4_init(t, n1, n2, n3, n4, name)
108 class(tensor4_t), intent(inout) :: t
109 integer, intent(in) :: n1
110 integer, intent(in) :: n2
111 integer, intent(in) :: n3
112 integer, intent(in) :: n4
113 character(len=*), intent(in), optional :: name
114
115 ! t%alloc zeroes the device side (and synchronizes) before any
116 ! host-side touch: under zero-copy the device then faults the
117 ! pages first (device first touch), which gives contiguous
118 ! physical mappings and thus better GPU TLB utilisation; rewriting
119 ! the zeros on the host afterwards is benign.
120 call t%alloc(n1, n2, n3, n4)
121
122 if (present(name)) then
123 t%name = name
124 end if
125
126 end subroutine tensor4_init
127
134 subroutine tensor4_allocate(t, n1, n2, n3, n4)
135 class(tensor4_t), intent(inout) :: t
136 integer, intent(in) :: n1
137 integer, intent(in) :: n2
138 integer, intent(in) :: n3
139 integer, intent(in) :: n4
140
141 call t%free()
142
143 allocate(t%x(n1, n2, n3, n4))
144 t%n1 = n1
145 t%n2 = n2
146 t%n3 = n3
147 t%n4 = n4
148 t%n = n1*n2*n3*n4
149
150 if (neko_bcknd_device .eq. 1) then
151 call device_map(t%x, t%x_d, t%n)
152 call device_cfill(t%x_d, 0.0_rp, t%n)
153 call device_sync()
154 end if
155 call cfill(t%x, 0.0_rp, t%n)
156
157 end subroutine tensor4_allocate
158
161 subroutine tensor4_free(t)
162 class(tensor4_t), intent(inout) :: t
163
164 if (allocated(t%x)) then
165 if (neko_bcknd_device .eq. 1) then
166 call device_unmap(t%x, t%x_d)
167 end if
168 deallocate(t%x)
169 end if
170
171 t%n1 = 0
172 t%n2 = 0
173 t%n3 = 0
174 t%n4 = 0
175 t%n = 0
176 t%name = ""
177
178 end subroutine tensor4_free
179
182 pure function tensor4_size(t) result(s)
183 class(tensor4_t), intent(in) :: t
184 integer :: s
185 s = t%n
186 end function tensor4_size
187
192 subroutine tensor4_copy_from(t, memdir, sync)
193 class(tensor4_t), intent(inout) :: t
194 integer, intent(in) :: memdir
195 logical, intent(in) :: sync
196
197 if (neko_bcknd_device .eq. 1) then
198 call device_memcpy(t%x, t%x_d, t%n, memdir, sync)
199 end if
200
201 end subroutine tensor4_copy_from
202
205 pure function tensor4_n1(t) result(n1)
206 class(tensor4_t), intent(in) :: t
207 integer :: n1
208 n1 = t%n1
209 end function tensor4_n1
210
213 pure function tensor4_n2(t) result(n2)
214 class(tensor4_t), intent(in) :: t
215 integer :: n2
216 n2 = t%n2
217 end function tensor4_n2
218
221 pure function tensor4_n3(t) result(n3)
222 class(tensor4_t), intent(in) :: t
223 integer :: n3
224 n3 = t%n3
225 end function tensor4_n3
226
229 pure function tensor4_n4(t) result(n4)
230 class(tensor4_t), intent(in) :: t
231 integer :: n4
232 n4 = t%n4
233 end function tensor4_n4
234
238 subroutine tensor4_assign_tensor4(t, w)
239 class(tensor4_t), intent(inout) :: t
240 type(tensor4_t), intent(in) :: w
241
242 if (allocated(t%x)) then
243 call t%free()
244 end if
245
246 if (.not. allocated(t%x)) then
247
248 t%n1 = w%n1
249 t%n2 = w%n2
250 t%n3 = w%n3
251 t%n4 = w%n4
252 t%n = w%n
253 allocate(t%x(t%n1, t%n2, t%n3, t%n4))
254
255 if (neko_bcknd_device .eq. 1) then
256 call device_map(t%x, t%x_d, t%n)
257 end if
258
259 end if
260
261 if (neko_bcknd_device .eq. 1) then
262 call device_copy(t%x_d, w%x_d, t%n)
263 else
264 t%x = w%x
265 end if
266
267 t%name = w%name
268
269 end subroutine tensor4_assign_tensor4
270
274 subroutine tensor4_assign_scalar(t, s)
275 class(tensor4_t), intent(inout) :: t
276 real(kind=rp), intent(in) :: s
277
278 if (.not. allocated(t%x)) then
279 call neko_error('tensor4 not allocated')
280 end if
281
282 if (neko_bcknd_device .eq. 1) then
283 call device_cfill(t%x_d, s, t%n)
284 else
285 t%x = s
286 end if
287
288 end subroutine tensor4_assign_scalar
289
290 ! ========================================================================== !
291 ! tensor4 pointer type subroutines
292
296 subroutine tensor4_ptr_init(this, ptr)
297 class(tensor4_ptr_t), intent(inout) :: this
298 type(tensor4_t), target, intent(in) :: ptr
299
300 call this%free()
301 this%ptr => ptr
302 end subroutine tensor4_ptr_init
303
306 subroutine tensor4_ptr_free(this)
307 class(tensor4_ptr_t), intent(inout) :: this
308
309 if (associated(this%ptr)) then
310 nullify(this%ptr)
311 end if
312
313 end subroutine tensor4_ptr_free
314
315end 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:600
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:307
subroutine tensor4_copy_from(t, memdir, sync)
Easy way to copy between host and device.
Definition tensor4.f90:193
pure integer function tensor4_size(t)
Returns the number of entries in the tensor.
Definition tensor4.f90:183
subroutine tensor4_init(t, n1, n2, n3, n4, name)
Initialise a tensor of size n1*n2*n3*n4.
Definition tensor4.f90:108
subroutine tensor4_allocate(t, n1, n2, n3, n4)
Allocate a tensor of size n1*n2*n3*n4.
Definition tensor4.f90:135
subroutine tensor4_free(t)
Deallocate a tensor.
Definition tensor4.f90:162
pure integer function tensor4_n3(t)
Returns the size of the third dimension.
Definition tensor4.f90:222
subroutine tensor4_ptr_init(this, ptr)
Constructor. Just assigns the pointer.
Definition tensor4.f90:297
pure integer function tensor4_n4(t)
Returns the size of the fourth dimension.
Definition tensor4.f90:230
pure integer function tensor4_n2(t)
Returns the size of the second dimension.
Definition tensor4.f90:214
pure integer function tensor4_n1(t)
Returns the size of the first dimension.
Definition tensor4.f90:206
subroutine tensor4_assign_tensor4(t, w)
Assignment .
Definition tensor4.f90:239
subroutine tensor4_assign_scalar(t, s)
Assignment .
Definition tensor4.f90:275
Utilities.
Definition utils.f90:35
integer, parameter, public neko_varname_len
Definition utils.f90:43