Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
tensor3.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 tensor3
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 :: tensor3_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 :: n = 0
53 contains
55 procedure, pass(t) :: init => tensor3_init
57 procedure, pass(t) :: free => tensor3_free
59 procedure, pass(t) :: size => tensor3_size
61 procedure, pass(t) :: copy_from => tensor3_copy_from
63 procedure, pass(t) :: get_n1 => tensor3_n1
65 procedure, pass(t) :: get_n2 => tensor3_n2
67 procedure, pass(t) :: get_n3 => tensor3_n3
69 procedure, pass(t) :: get_dims => tensor3_get_dims
71 procedure, pass(t) :: tensor3_assign_tensor3
73 procedure, pass(t) :: tensor3_assign_scalar
74
75 generic :: assignment(=) => tensor3_assign_tensor3, &
77
79 procedure, pass(t), private :: alloc => tensor3_allocate
80 end type tensor3_t
81
82 type, public :: tensor3_ptr_t
83 type(tensor3_t), pointer :: ptr => null()
84 contains
86 procedure, pass(this) :: init => tensor3_ptr_init
88 procedure, pass(this) :: free => tensor3_ptr_free
89 end type tensor3_ptr_t
90
91contains
92
99 subroutine tensor3_init(t, n1, n2, n3, name)
100 class(tensor3_t), intent(inout) :: t
101 integer, intent(in) :: n1
102 integer, intent(in) :: n2
103 integer, intent(in) :: n3
104 character(len=*), intent(in), optional :: name
105
106 ! t%alloc zeroes the device side (and synchronizes) before any
107 ! host-side touch: under zero-copy the device then faults the
108 ! pages first (device first touch), which gives contiguous
109 ! physical mappings and thus better GPU TLB utilisation; rewriting
110 ! the zeros on the host afterwards is benign.
111 call t%alloc(n1, n2, n3)
112
113 if (present(name)) then
114 t%name = name
115 end if
116
117 end subroutine tensor3_init
118
124 subroutine tensor3_allocate(t, n1, n2, n3)
125 class(tensor3_t), intent(inout) :: t
126 integer, intent(in) :: n1
127 integer, intent(in) :: n2
128 integer, intent(in) :: n3
129
130 call t%free()
131
132 allocate(t%x(n1, n2, n3))
133 t%n1 = n1
134 t%n2 = n2
135 t%n3 = n3
136 t%n = n1*n2*n3
137
138 if (neko_bcknd_device .eq. 1) then
139 call device_map(t%x, t%x_d, t%n)
140 call device_cfill(t%x_d, 0.0_rp, t%n)
141 call device_sync()
142 end if
143 call cfill(t%x, 0.0_rp, t%n)
144
145 end subroutine tensor3_allocate
146
149 subroutine tensor3_free(t)
150 class(tensor3_t), intent(inout) :: t
151
152 if (allocated(t%x)) then
153 if (neko_bcknd_device .eq. 1) then
154 call device_unmap(t%x, t%x_d)
155 end if
156 deallocate(t%x)
157 end if
158
159 t%n1 = 0
160 t%n2 = 0
161 t%n3 = 0
162 t%n = 0
163 t%name = ""
164
165 end subroutine tensor3_free
166
169 pure function tensor3_size(t) result(s)
170 class(tensor3_t), intent(in) :: t
171 integer :: s
172 s = t%n
173 end function tensor3_size
174
179 subroutine tensor3_copy_from(t, memdir, sync)
180 class(tensor3_t), intent(inout) :: t
181 integer, intent(in) :: memdir
182 logical, intent(in) :: sync
183
184 if (neko_bcknd_device .eq. 1) then
185 call device_memcpy(t%x, t%x_d, t%n, memdir, sync)
186 end if
187
188 end subroutine tensor3_copy_from
189
192 pure function tensor3_n1(t) result(n1)
193 class(tensor3_t), intent(in) :: t
194 integer :: n1
195 n1 = t%n1
196 end function tensor3_n1
197
200 pure function tensor3_n2(t) result(n2)
201 class(tensor3_t), intent(in) :: t
202 integer :: n2
203 n2 = t%n2
204 end function tensor3_n2
205
208 pure function tensor3_n3(t) result(n3)
209 class(tensor3_t), intent(in) :: t
210 integer :: n3
211 n3 = t%n3
212 end function tensor3_n3
213
216 pure function tensor3_get_dims(t) result(dims)
217 class(tensor3_t), intent(in) :: t
218 integer :: dims(3)
219 dims = [t%n1, t%n2, t%n3]
220 end function tensor3_get_dims
221
225 subroutine tensor3_assign_tensor3(t, w)
226 class(tensor3_t), intent(inout) :: t
227 type(tensor3_t), intent(in) :: w
228
229 if (allocated(t%x)) then
230 call t%free()
231 end if
232
233 if (.not. allocated(t%x)) then
234
235 t%n1 = w%n1
236 t%n2 = w%n2
237 t%n3 = w%n3
238 t%n = w%n
239 allocate(t%x(t%n1, t%n2, t%n3))
240
241 if (neko_bcknd_device .eq. 1) then
242 call device_map(t%x, t%x_d, t%n)
243 end if
244
245 end if
246
247 if (neko_bcknd_device .eq. 1) then
248 call device_copy(t%x_d, w%x_d, t%n)
249 else
250 t%x = w%x
251 end if
252
253 t%name = w%name
254
255 end subroutine tensor3_assign_tensor3
256
260 subroutine tensor3_assign_scalar(t, s)
261 class(tensor3_t), intent(inout) :: t
262 real(kind=rp), intent(in) :: s
263
264 if (.not. allocated(t%x)) then
265 call neko_error('tensor3 not allocated')
266 end if
267
268 if (neko_bcknd_device .eq. 1) then
269 call device_cfill(t%x_d, s, t%n)
270 else
271 t%x = s
272 end if
273
274 end subroutine tensor3_assign_scalar
275
276 ! ========================================================================== !
277 ! tensor3 pointer type subroutines
278
282 subroutine tensor3_ptr_init(this, ptr)
283 class(tensor3_ptr_t), intent(inout) :: this
284 type(tensor3_t), target, intent(in) :: ptr
285
286 call this%free()
287 this%ptr => ptr
288 end subroutine tensor3_ptr_init
289
292 subroutine tensor3_ptr_free(this)
293 class(tensor3_ptr_t), intent(inout) :: this
294
295 if (associated(this%ptr)) then
296 nullify(this%ptr)
297 end if
298
299 end subroutine tensor3_ptr_free
300
301end module tensor3
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-3 tensor.
Definition tensor3.f90:34
subroutine tensor3_ptr_free(this)
Destructor. Just nullifies the pointer.
Definition tensor3.f90:293
subroutine tensor3_init(t, n1, n2, n3, name)
Initialise a tensor of size n1*n2*n3.
Definition tensor3.f90:100
pure integer function tensor3_n3(t)
Returns the size of the third dimension.
Definition tensor3.f90:209
pure integer function, dimension(3) tensor3_get_dims(t)
Returns the dimensions of the tensor.
Definition tensor3.f90:217
pure integer function tensor3_n2(t)
Returns the size of the second dimension.
Definition tensor3.f90:201
subroutine tensor3_assign_scalar(t, s)
Assignment .
Definition tensor3.f90:261
subroutine tensor3_ptr_init(this, ptr)
Constructor. Just assigns the pointer.
Definition tensor3.f90:283
pure integer function tensor3_size(t)
Returns the number of entries in the tensor.
Definition tensor3.f90:170
subroutine tensor3_copy_from(t, memdir, sync)
Easy way to copy between host and device.
Definition tensor3.f90:180
pure integer function tensor3_n1(t)
Returns the size of the first dimension.
Definition tensor3.f90:193
subroutine tensor3_assign_tensor3(t, w)
Assignment .
Definition tensor3.f90:226
subroutine tensor3_allocate(t, n1, n2, n3)
Allocate a tensor of size n1*n2*n3.
Definition tensor3.f90:125
subroutine tensor3_free(t)
Deallocate a tensor.
Definition tensor3.f90:150
Utilities.
Definition utils.f90:35
integer, parameter, public neko_varname_len
Definition utils.f90:43