Neko 1.99.3
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 call m%alloc(nrows, ncols)
96 m%x = 0.0_rp
97 if (neko_bcknd_device .eq. 1) then
98 call device_cfill(m%x_d, 0.0_rp, m%n)
99 end if
100
101 if (present(name)) then
102 m%name = name
103 end if
104
105
106 end subroutine matrix_init
107
111 subroutine matrix_allocate(m, nrows, ncols)
112 class(matrix_t), intent(inout) :: m
113 integer, intent(in) :: nrows
114 integer, intent(in) :: ncols
115
116 call m%free()
117
118 allocate(m%x(nrows, ncols))
119 m%nrows = nrows
120 m%ncols = ncols
121 m%n = nrows*ncols
122
123 if (neko_bcknd_device .eq. 1) then
124 call device_map(m%x, m%x_d, m%n)
125 call device_cfill(m%x_d, 0.0_rp, m%n)
126 call device_sync()
127 end if
128
129 end subroutine matrix_allocate
130
132 subroutine matrix_free(m)
133 class(matrix_t), intent(inout) :: m
134
135 if (allocated(m%x)) then
136 deallocate(m%x)
137 end if
138
139 if (c_associated(m%x_d)) then
140 call device_deassociate(m%x)
141 call device_free(m%x_d)
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
Deassociate a Fortran array from a device pointer.
Definition device.F90:101
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
Synchronize a device or stream.
Definition device.F90:113
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
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:225
Defines a matrix.
Definition matrix.f90:34
subroutine matrix_free(m)
Deallocate a matrix.
Definition matrix.f90:133
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:112
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:42