Neko 1.99.6
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
matrix.f90
Go to the documentation of this file.
1! Copyright (c) 2024, 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 matrix
36 use num_types, only : rp, xp
41 use, intrinsic :: iso_c_binding
42 implicit none
43 private
44
45 type, public :: matrix_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 :: nrows = 0
50 integer, private :: ncols = 0
51 integer, private :: n = 0
52 contains
54 procedure, pass(m) :: init => matrix_init
56 procedure, pass(m) :: free => matrix_free
58 procedure, pass(m) :: size => matrix_size
60 procedure, pass(m) :: copy_from => matrix_copy_from
62 procedure, pass(m) :: get_nrows => matrix_nrows
64 procedure, pass(m) :: get_ncols => matrix_ncols
66 procedure, pass(m) :: matrix_assign_matrix
68 procedure, pass(m) :: matrix_assign_scalar
70 procedure, pass(m) :: inverse => matrix_bcknd_inverse
71 procedure, pass(m) :: inverse_on_host => cpu_matrix_inverse
72
73 generic :: assignment(=) => matrix_assign_matrix, &
75
77 procedure, pass(m), private :: alloc => matrix_allocate
78 end type matrix_t
79
80 type, public :: matrix_ptr_t
81 type(matrix_t), pointer :: ptr
82 end type matrix_ptr_t
83
84contains
85
89 subroutine matrix_init(m, nrows, ncols, name)
90 class(matrix_t), intent(inout) :: m
91 integer, intent(in) :: nrows
92 integer, intent(in) :: ncols
93 character(len=*), intent(in), optional :: name
94
95 ! m%alloc zeroes the device side (and synchronizes) before any
96 ! host-side touch: under zero-copy the device then faults the
97 ! pages (device first touch), which gives contiguous physical
98 ! mappings and thus better GPU TLB utilisation; rewriting the
99 ! zeros on the host afterwards is benign
100 call m%alloc(nrows, ncols)
101 m%x = 0.0_rp
102
103 if (present(name)) then
104 m%name = name
105 end if
106
107
108 end subroutine matrix_init
109
113 subroutine matrix_allocate(m, nrows, ncols)
114 class(matrix_t), intent(inout) :: m
115 integer, intent(in) :: nrows
116 integer, intent(in) :: ncols
117
118 call m%free()
119
120 allocate(m%x(nrows, ncols))
121 m%nrows = nrows
122 m%ncols = ncols
123 m%n = nrows*ncols
124
125 if (neko_bcknd_device .eq. 1) then
126 call device_map(m%x, m%x_d, m%n)
127 call device_cfill(m%x_d, 0.0_rp, m%n)
128 call device_sync()
129 end if
130
131 end subroutine matrix_allocate
132
134 subroutine matrix_free(m)
135 class(matrix_t), intent(inout) :: m
136
137 if (allocated(m%x)) then
138 if (neko_bcknd_device .eq. 1) then
139 call device_unmap(m%x, m%x_d)
140 end if
141 deallocate(m%x)
142 end if
143
144 m%nrows = 0
145 m%ncols = 0
146 m%n = 0
147 m%name = ""
148
149 end subroutine matrix_free
150
152 pure function matrix_size(m) result(s)
153 class(matrix_t), intent(in) :: m
154 integer :: s
155 s = m%n
156 end function matrix_size
157
158
163 subroutine matrix_copy_from(m, memdir, sync)
164 class(matrix_t), intent(inout) :: m
165 integer, intent(in) :: memdir
166 logical, intent(in) :: sync
167
168 if (neko_bcknd_device .eq. 1) then
169 call device_memcpy(m%x, m%x_d, m%n, memdir, sync)
170 end if
171
172 end subroutine matrix_copy_from
173
175 pure function matrix_nrows(m) result(nr)
176 class(matrix_t), intent(in) :: m
177 integer :: nr
178 nr = m%nrows
179 end function matrix_nrows
180
182 pure function matrix_ncols(m) result(nc)
183 class(matrix_t), intent(in) :: m
184 integer :: nc
185 nc = m%ncols
186 end function matrix_ncols
187
189 subroutine matrix_assign_matrix(m, w)
190 class(matrix_t), intent(inout) :: m
191 type(matrix_t), intent(in) :: w
192
193 if (allocated(m%x)) then
194 call m%free()
195 end if
196
197 if (.not. allocated(m%x)) then
198
199 m%nrows = w%nrows
200 m%ncols = w%ncols
201 m%n = w%n
202 allocate(m%x(m%nrows, m%ncols))
203
204 if (neko_bcknd_device .eq. 1) then
205 call device_map(m%x, m%x_d, m%n)
206 end if
207
208 end if
209
210 if (neko_bcknd_device .eq. 1) then
211 call device_copy(m%x_d, w%x_d, m%n)
212 else
213 m%x = w%x
214 end if
215
216 m%name = w%name
217
218 end subroutine matrix_assign_matrix
219
221 subroutine matrix_assign_scalar(m, s)
222 class(matrix_t), intent(inout) :: m
223 real(kind=rp), intent(in) :: s
224
225 if (.not. allocated(m%x)) then
226 call neko_error('matrix not allocated')
227 end if
228
229 if (neko_bcknd_device .eq. 1) then
230 call device_cfill(m%x_d, s, m%n)
231 else
232 m%x = s
233 end if
234
235 end subroutine matrix_assign_scalar
236
237 subroutine matrix_bcknd_inverse(m, bcknd)
238 class(matrix_t), intent(inout) :: m
239 integer, optional :: bcknd
240
241 if (neko_bcknd_device .eq. 1 .and. &
242 bcknd .eq. neko_bcknd_device) then
243 call neko_error("matrix_bcknd_inverse not &
244 &implemented on accelarators.")
245 else
246 call cpu_matrix_inverse(m)
247 end if
248
249 end subroutine matrix_bcknd_inverse
250
251 subroutine cpu_matrix_inverse(m)
252 ! Gauss-Jordan matrix inversion with full pivoting
253 ! Num. Rec. p. 30, 2nd Ed., Fortran
254 ! m%x is an sqaure matrix
255 ! rmult is m work array of length nrows = ncols
256 class(matrix_t), intent(inout) :: m
257 integer :: indr(m%nrows), indc(m%ncols), ipiv(m%ncols)
258 real(kind=xp) :: rmult(m%nrows), amx, tmp, piv, eps
259 integer :: i, j, k, ir, jc
260
261 if (.not. (m%ncols .eq. m%nrows)) then
262 call neko_error("Fatal error: trying to invert m matrix that is not &
263 &square")
264 end if
265
266 eps = 1e-9_rp
267 ipiv = 0
268
269 do k = 1, m%nrows
270 amx = 0.0_rp
271 do i = 1, m%nrows ! Pivot search
272 if (ipiv(i) .ne. 1) then
273 do j = 1, m%nrows
274 if (ipiv(j) .eq. 0) then
275 if (abs(m%x(i, j)) .ge. amx) then
276 amx = abs(m%x(i, j))
277 ir = i
278 jc = j
279 end if
280 else if (ipiv(j) .gt. 1) then
281 return
282 end if
283 end do
284 end if
285 end do
286 ipiv(jc) = ipiv(jc) + 1
287
288 ! Swap rows
289 if (ir .ne. jc) then
290 do j = 1, m%ncols
291 tmp = m%x(ir, j)
292 m%x(ir, j) = m%x(jc, j)
293 m%x(jc, j) = tmp
294 end do
295 end if
296 indr(k) = ir
297 indc(k) = jc
298
299 if (abs(m%x(jc, jc)) .lt. eps) then
300 call neko_error("matrix_inverse error: small Gauss Jordan Piv")
301 end if
302 piv = 1.0_xp/m%x(jc, jc)
303 m%x(jc, jc) = 1.0_xp
304 do j = 1, m%ncols
305 m%x(jc, j) = m%x(jc, j)*piv
306 end do
307
308 do j = 1, m%ncols
309 tmp = m%x(jc, j)
310 m%x(jc, j) = m%x(1 , j)
311 m%x(1 , j) = tmp
312 end do
313 do i = 2, m%nrows
314 rmult(i) = m%x(i, jc)
315 m%x(i, jc) = 0.0_rp
316 end do
317
318 do j = 1, m%ncols
319 do i = 2, m%nrows
320 m%x(i, j) = m%x(i, j) - rmult(i)*m%x(1, j)
321 end do
322 end do
323
324 do j = 1, m%ncols
325 tmp = m%x(jc, j)
326 m%x(jc, j) = m%x(1 , j)
327 m%x(1 , j) = tmp
328 end do
329 end do
330
331 ! Unscramble matrix
332 do j = m%nrows, 1, -1
333 if (indr(j) .ne. indc(j)) then
334 do i = 1, m%nrows
335 tmp = m%x(i, indr(j))
336 m%x(i, indr(j)) = m%x(i, indc(j))
337 m%x(i, indc(j)) = tmp
338 end do
339 end if
340 end do
341
342 return
343 end subroutine cpu_matrix_inverse
344
345end module matrix
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
Defines a matrix.
Definition matrix.f90:34
subroutine matrix_free(m)
Deallocate a matrix.
Definition matrix.f90:135
subroutine matrix_bcknd_inverse(m, bcknd)
Definition matrix.f90:238
pure integer function matrix_ncols(m)
Returns the number of columns in the matrix.
Definition matrix.f90:183
subroutine matrix_assign_matrix(m, w)
Assignment .
Definition matrix.f90:190
subroutine cpu_matrix_inverse(m)
Definition matrix.f90:252
pure integer function matrix_nrows(m)
Returns the number of rows in the matrix.
Definition matrix.f90:176
subroutine matrix_init(m, nrows, ncols, name)
Initialise a matrix of size nrows*ncols.
Definition matrix.f90:90
pure integer function matrix_size(m)
Returns the number of entries in the matrix.
Definition matrix.f90:153
subroutine matrix_copy_from(m, memdir, sync)
Easy way to copy between host and device.
Definition matrix.f90:164
subroutine matrix_assign_scalar(m, s)
Assignment .
Definition matrix.f90:222
subroutine matrix_allocate(m, nrows, ncols)
Allocate a matrix of size nrows*ncols.
Definition matrix.f90:114
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public xp
Definition num_types.f90:14
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Utilities.
Definition utils.f90:35
integer, parameter, public neko_varname_len
Definition utils.f90:43