Neko 1.99.3
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
mask.f90
Go to the documentation of this file.
1! Copyright (c) 2020-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 mask
35 use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr, c_associated, &
36 c_size_t
40 use device_math, only : device_cadd
41 use utils, only : neko_error
42
43 implicit none
44 private
45
51 type, public :: mask_t
52 private
53 integer :: n_elements = 0 ! Number of elements in the mask
54 integer, allocatable :: mask(:) ! The mask array
55 type(c_ptr) :: mask_d = c_null_ptr ! Pointer to the device mask array
56 logical :: is_set_ = .false. ! Flag to indicate if the mask is set
57
58 contains
59 ! Public interface for the mask type
60 generic, public :: init => init_from_array, init_from_array_device, &
62 procedure, public, pass(this) :: free => mask_free
63
64 procedure, public, pass(this) :: invert_from => invert_mask
65 procedure, public, pass(this) :: size => mask_size
66 procedure, public, pass(this) :: is_set => mask_is_set
67 procedure, public, pass(this) :: get_d => mask_get_d
68
69 generic, public :: set => mask_set, mask_set_d
70 generic, public :: get => mask_get, mask_get_i
71
72 ! Private procedures
73 procedure, pass(this) :: allocate => mask_allocate
74 procedure, pass(this) :: init_from_array
75 procedure, pass(this) :: init_from_array_device
76 procedure, pass(this) :: init_from_mask
77 procedure, pass(this) :: invert_mask
78
79 ! Setters
80 procedure, pass(this) :: mask_set
81 procedure, pass(this) :: mask_set_d
82
83 ! Getters
84 procedure, pass(this) :: mask_get
85 procedure, pass(this) :: mask_get_i
86
87 end type mask_t
88
89contains
90
92 subroutine mask_allocate(this, n_elements)
93 class(mask_t), intent(inout) :: this
94 integer, intent(in) :: n_elements
95
96 this%is_set_ = .false.
97 if (n_elements .eq. this%n_elements) return
98 call this%free()
99
100 allocate(this%mask(n_elements))
101
102 if (neko_bcknd_device .eq. 1) then
103 call device_map(this%mask, this%mask_d, n_elements)
104 end if
105
106 this%n_elements = n_elements
107 end subroutine mask_allocate
108
110 subroutine mask_free(this)
111 class(mask_t), intent(inout) :: this
112
113 if (allocated(this%mask)) then
114 deallocate(this%mask)
115 end if
116
117 if (c_associated(this%mask_d)) then
118 call device_free(this%mask_d)
119 end if
120
121 this%n_elements = 0
122 this%mask_d = c_null_ptr
123 this%is_set_ = .false.
124 end subroutine mask_free
125
127 subroutine init_from_array(this, mask_array, n_elements)
128 class(mask_t), intent(inout) :: this
129 integer, intent(in) :: n_elements
130 integer, intent(in) :: mask_array(n_elements)
131
132 call this%allocate(n_elements)
133
134 this%mask = mask_array
135 if (neko_bcknd_device .eq. 1) then
136 call device_memcpy(this%mask, this%mask_d, this%n_elements, &
137 host_to_device, sync = .true.)
138 call device_cadd(this%mask_d, -1, this%n_elements)
139 end if
140
141 this%is_set_ = .true.
142 end subroutine init_from_array
143
145 subroutine init_from_array_device(this, mask_array_d, n_elements)
146 class(mask_t), intent(inout) :: this
147 integer, intent(in) :: n_elements
148 type(c_ptr), intent(inout):: mask_array_d
149 integer(kind=c_size_t) :: size_c
150
151 size_c = n_elements * int(4, c_size_t)
152
153 call this%allocate(n_elements)
154 call device_memcpy(this%mask_d, mask_array_d, size_c, &
155 device_to_device, sync = .false.)
156 call device_memcpy(this%mask, mask_array_d, n_elements, &
157 device_to_host, sync = .true.)
158 this%mask = this%mask - 1 ! Adjust for 0-based indexing
159
160 this%is_set_ = .true.
161 end subroutine init_from_array_device
162
164 subroutine init_from_mask(this, other)
165 class(mask_t), intent(inout) :: this
166 class(mask_t), intent(inout) :: other
167 integer(kind=c_size_t) :: size_c
168
169 call this%allocate(other%n_elements)
170
171 size_c = other%n_elements * int(4, c_size_t)
172
173 this%mask = other%mask
174 if (neko_bcknd_device .eq. 1) then
175 call device_memcpy(this%mask_d, other%mask_d, size_c, &
176 device_to_device, sync = .true.)
177 end if
178
179 this%n_elements = other%n_elements
180 this%is_set_ = other%is_set_
181 end subroutine init_from_mask
182
184 subroutine invert_mask(this, other, total_elements)
185 class(mask_t), intent(inout) :: this
186 class(mask_t), intent(in) :: other
187 integer, intent(in) :: total_elements
188
189 logical, allocatable :: found(:)
190 integer, allocatable :: new_mask(:)
191 integer :: i, j, k, v, new_size
192
193 allocate(found(total_elements))
194 found = .false.
195
196 ! mark present
197 do i = 1, other%size()
198 v = other%mask(i)
199 if (v >= 1 .and. v <= total_elements) found(v) = .true.
200 end do
201
202 ! count complement
203 new_size = 0
204 do j = 1, total_elements
205 if (.not. found(j)) new_size = new_size + 1
206 end do
207
208 allocate(new_mask(new_size))
209
210 ! fill complement
211 k = 1
212 do j = 1, total_elements
213 if (.not. found(j)) then
214 new_mask(k) = j
215 k = k + 1
216 end if
217 end do
218
219 call this%init_from_array(new_mask, new_size)
220 end subroutine invert_mask
221
223 pure function mask_size(this) result(n_elements)
224 class(mask_t), intent(in) :: this
225 integer :: n_elements
226
227 n_elements = this%n_elements
228 end function mask_size
229
231 pure function mask_is_set(this) result(is_set)
232 class(mask_t), intent(in) :: this
233 logical :: is_set
234
235 is_set = this%is_set_
236 end function mask_is_set
237
239 function mask_get(this) result(mask_array)
240 class(mask_t), intent(in), target :: this
241 integer, pointer :: mask_array(:)
242
243 if (.not. this%is_set()) call neko_error("Mask is not set.")
244
245 mask_array => this%mask
246 end function mask_get
247
249 function mask_get_i(this, index) result(mask_value)
250 class(mask_t), intent(in), target :: this
251 integer, intent(in) :: index
252 integer :: mask_value
253
254 if (.not. this%is_set()) call neko_error("Mask is not set.")
255 if (index < 1 .or. index > this%n_elements) then
256 call neko_error("Index out of bounds in mask_get_i")
257 end if
258
259 mask_value = this%mask(index)
260 end function mask_get_i
261
263 function mask_get_d(this) result(mask_array_d)
264 class(mask_t), intent(in) :: this
265 type(c_ptr) :: mask_array_d
266
267 if (.not. this%is_set()) call neko_error("Mask is not set.")
268
269 mask_array_d = this%mask_d
270 end function mask_get_d
271
273 subroutine mask_set(this, mask_array, n_elements)
274 class(mask_t), intent(inout) :: this
275 integer, intent(in) :: n_elements
276 integer, intent(in) :: mask_array(n_elements)
277
278 call this%allocate(n_elements)
279
280 this%mask = mask_array
281 if (neko_bcknd_device .eq. 1) then
282 call device_memcpy(this%mask, this%mask_d, n_elements, &
283 host_to_device, sync = .true.)
284 call device_cadd(this%mask_d, -1, n_elements)
285 end if
286
287 this%is_set_ = .true.
288 end subroutine mask_set
289
291 subroutine mask_set_d(this, mask_array_d, n_elements)
292 class(mask_t), intent(inout) :: this
293 integer, intent(in) :: n_elements
294 type(c_ptr), intent(inout) :: mask_array_d
295 integer(kind=c_size_t) :: size_c
296
297 call this%allocate(n_elements)
298 size_c = n_elements * int(4, c_size_t)
299
300 call device_memcpy(this%mask_d, mask_array_d, size_c, &
301 device_to_device, sync = .false.)
302 call device_memcpy(this%mask, mask_array_d, n_elements, &
303 device_to_host, sync = .true.)
304 this%mask = this%mask - 1 ! Adjust for 0-based indexing
305
306 this%is_set_ = .true.
307 end subroutine mask_set_d
308
309
310end module mask
Map a Fortran array to a device (allocate and associate)
Definition device.F90:77
Copy data between host and device (or device and device)
Definition device.F90:71
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public device_to_device
Definition device.F90:47
integer, parameter, public host_to_device
Definition device.F90:47
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:219
integer, parameter, public device_to_host
Definition device.F90:47
Object for handling masks in Neko.
Definition mask.f90:34
subroutine invert_mask(this, other, total_elements)
Invert the contents of another mask object.
Definition mask.f90:185
pure logical function mask_is_set(this)
Check if the mask is set.
Definition mask.f90:232
integer function, dimension(:), pointer mask_get(this)
Get the mask array.
Definition mask.f90:240
subroutine init_from_array(this, mask_array, n_elements)
Initialize the mask from a 1-indexed host array.
Definition mask.f90:128
subroutine init_from_mask(this, other)
Initialize the mask from another mask object.
Definition mask.f90:165
pure integer function mask_size(this)
Get the size of the mask.
Definition mask.f90:224
subroutine mask_allocate(this, n_elements)
Allocate the mask object.
Definition mask.f90:93
integer function mask_get_i(this, index)
Get the mask array.
Definition mask.f90:250
subroutine mask_set_d(this, mask_array_d, n_elements)
Set the mask from a 0-indexed device array.
Definition mask.f90:292
subroutine mask_free(this)
Free the mask object.
Definition mask.f90:111
subroutine mask_set(this, mask_array, n_elements)
Set the mask from a 1-indexed host array.
Definition mask.f90:274
type(c_ptr) function mask_get_d(this)
Get the device pointer to the mask array.
Definition mask.f90:264
subroutine init_from_array_device(this, mask_array_d, n_elements)
Initialize the mask from a 0-indexed device array.
Definition mask.f90:146
Build configurations.
integer, parameter neko_bcknd_device
Utilities.
Definition utils.f90:35
Type for consistently handling masks in Neko. This type encapsulates the mask array and its associate...
Definition mask.f90:51