MODFLOW 6  version 6.7.0.dev0
USGS Modular Hydrologic Model
PetscMatrix.F90
Go to the documentation of this file.
1 module petscmatrixmodule
2 #include <petsc/finclude/petscksp.h>
3  use petscksp
4  use kindmodule, only: i4b, dp, lgp
5  use constantsmodule, only: dzero
6  use sparsemodule, only: sparsematrix
11  implicit none
12  private
13 
14  type, public, extends(matrixbasetype) :: petscmatrixtype
15  mat :: mat !< the PETSc matrix object, NOTE: update() should be called before using this,
16  !! in case the matrix CSR array has changed!!!
17  integer(I4B) :: nrow !< number of rows in this portion of the global matrix
18  integer(I4B) :: ncol !< number of columns in the matrix
19  integer(I4B) :: nnz !< number of nonzeros in the matrix
20  integer(I4B) :: nnz_local !< number of nonzeros in the local matrix (the diagonal block tied to this process)
21  integer(I4B) :: offset !< global offset for the first row in the matrix
22  integer(I4B), dimension(:), pointer, contiguous, private :: ia_local !< IA(CSR) for local block, contains 1-based index values
23  integer(I4B), dimension(:), pointer, contiguous, private :: ja_local !< JA(CSR) for local block, contains 1-based index values
24  real(DP), dimension(:), pointer, contiguous, private :: amat_local !< A(CSR) for local block
25  integer(I4B), dimension(:), pointer, contiguous :: ia_petsc !< IA(CSR) for petsc, contains 0-based index values
26  integer(I4B), dimension(:), pointer, contiguous :: ja_petsc !< JA(CSR) for petsc, contains 0-based index values
27  real(DP), dimension(:), pointer, contiguous :: amat_petsc !< A(CSR) for petsc
28  logical(LGP) :: is_parallel
29  contains
30  ! override
31  procedure :: init => pm_init
32  procedure :: destroy => pm_destroy
33  procedure :: create_vec_mm => pm_create_vec_mm
34  procedure :: create_vec => pm_create_vec
35  procedure :: get_value_pos => pm_get_value_pos
36  procedure :: get_diag_value => pm_get_diag_value
37  procedure :: set_diag_value => pm_set_diag_value
38  procedure :: set_value_pos => pm_set_value_pos
39  procedure :: add_value_pos => pm_add_value_pos
40  procedure :: add_diag_value => pm_add_diag_value
41  procedure :: zero_entries => pm_zero_entries
42  procedure :: zero_row_offdiag => pm_zero_row_offdiag
43  procedure :: get_first_col_pos => pm_get_first_col_pos
44  procedure :: get_last_col_pos => pm_get_last_col_pos
45  procedure :: get_column => pm_get_column
46  procedure :: get_position => pm_get_position
47  procedure :: get_position_diag => pm_get_position_diag
48  procedure :: get_aij => pm_get_aij
49  procedure :: get_row_offset => pm_get_row_offset
50 
51  procedure :: multiply => pm_multiply
52 
53  ! public
54  procedure :: update => pm_update
55  procedure :: get_aij_local => pm_get_aij_local
56 
57  ! private
58  procedure, private :: pm_get_position
59 
60  end type petscmatrixtype
61 
62 contains
63 
64  subroutine pm_init(this, sparse, mem_path)
66  class(PetscMatrixType) :: this
67  type(sparsematrix) :: sparse
68  character(len=*) :: mem_path
69  ! local
70  petscerrorcode :: ierr
71  integer(I4B) :: i, ierror
72  mat :: local_mat
73  integer(I4B), dimension(:), pointer :: ia_tmp, ja_tmp
74  integer(I4B) :: nrows_local
75  logical(LGP) :: done
76 
77  this%memory_path = mem_path
78  this%nrow = sparse%nrow
79  this%ncol = sparse%ncol
80  this%nnz = sparse%nnz
81  this%nnz_local = sparse%nnz - sparse%nnz_od
82  this%offset = sparse%offset
83 
84  ! allocate the diagonal block of the matrix
85  call mem_allocate(this%ia_local, this%nrow + 1, 'IA_LOCAL', this%memory_path)
86  call mem_allocate(this%ja_local, this%nnz_local, 'JA_LOCAL', this%memory_path)
87  call mem_allocate(this%amat_local, this%nnz_local, 'AMAT_LOCAL', &
88  this%memory_path)
89  call mem_allocate(this%ia_petsc, this%nrow + 1, 'IA_PETSC', this%memory_path)
90  call mem_allocate(this%ja_petsc, this%nnz, 'JA_PETSC', this%memory_path)
91  call mem_allocate(this%amat_petsc, this%nnz, 'AMAT_PETSC', this%memory_path)
92 
93  call sparse%sort(with_csr=.true.) !< PETSc has full row sorting, MF6 had diagonal first and then sorted
94  call sparse%filliaja(this%ia_petsc, this%ja_petsc, ierror)
95 
96  ! go to C indexing for PETSc internals
97  do i = 1, this%nrow + 1
98  this%ia_petsc(i) = this%ia_petsc(i) - 1
99  end do
100  do i = 1, this%nnz
101  this%ja_petsc(i) = this%ja_petsc(i) - 1
102  this%amat_petsc(i) = dzero
103  end do
104 
105  ! create PETSc matrix object
106  if (simulation_mode == 'PARALLEL') then
107  this%is_parallel = .true.
108  call matcreatempiaijwitharrays(petsc_comm_world, &
109  sparse%nrow, sparse%nrow, &
110  sparse%ncol, sparse%ncol, &
111  this%ia_petsc, this%ja_petsc, &
112  this%amat_petsc, this%mat, &
113  ierr)
114  else
115  this%is_parallel = .false.
116  call matcreateseqaijwitharrays(petsc_comm_world, &
117  sparse%nrow, sparse%ncol, &
118  this%ia_petsc, this%ja_petsc, &
119  this%amat_petsc, this%mat, &
120  ierr)
121  end if
122  chkerrq(ierr)
123 
124  ! set up local block sparsity structure
125  nrows_local = 0
126  call matgetdiagonalblock(this%mat, local_mat, ierr)
127  chkerrq(ierr)
128 
129  call matgetrowijf90(local_mat, 1, petsc_false, petsc_false, &
130  nrows_local, ia_tmp, ja_tmp, &
131  done, ierr)
132  chkerrq(ierr)
133 
134  do i = 1, size(ia_tmp)
135  this%ia_local(i) = ia_tmp(i)
136  end do
137  do i = 1, size(ja_tmp) - 1
138  this%ja_local(i) = ja_tmp(i)
139  end do
140 
141  call matrestorerowijf90(local_mat, 1, petsc_false, petsc_false, &
142  nrows_local, ia_tmp, ja_tmp, done, ierr)
143  chkerrq(ierr)
144 
145  end subroutine pm_init
146 
147  !> @brief Copies the values from the CSR array into
148  !< the PETSc matrix object
149  subroutine pm_update(this)
150  class(PetscMatrixType) :: this
151  ! local
152  petscerrorcode :: ierr
153 
154  if (this%is_parallel) then
155  call matupdatempiaijwitharrays(this%mat, this%nrow, this%nrow, &
156  this%ncol, this%ncol, &
157  this%ia_petsc, this%ja_petsc, &
158  this%amat_petsc, ierr)
159  chkerrq(ierr)
160  end if
161 
162  end subroutine pm_update
163 
164  subroutine pm_destroy(this)
165  class(PetscMatrixType) :: this
166  ! local
167  petscerrorcode :: ierr
168 
169  call matdestroy(this%mat, ierr)
170  chkerrq(ierr)
171 
172  call mem_deallocate(this%ia_local)
173  call mem_deallocate(this%ja_local)
174  call mem_deallocate(this%amat_local)
175  call mem_deallocate(this%ia_petsc)
176  call mem_deallocate(this%ja_petsc)
177  call mem_deallocate(this%amat_petsc)
178 
179  end subroutine pm_destroy
180 
181  function pm_create_vec_mm(this, n, name, mem_path) result(vec)
182  class(PetscMatrixType) :: this
183  integer(I4B) :: n !< the nr. of elements in the vector
184  character(len=*) :: name !< the variable name (for access through memory manager)
185  character(len=*) :: mem_path !< memory path for storing the underlying memory items
186  class(VectorBaseType), pointer :: vec !< the vector object to return
187  ! local
188  class(PetscVectorType), pointer :: petsc_vec
189 
190  allocate (petsc_vec)
191  call petsc_vec%create_mm(n, name, mem_path)
192  vec => petsc_vec
193 
194  end function pm_create_vec_mm
195 
196  function pm_create_vec(this, n) result(vec)
197  class(PetscMatrixType) :: this
198  integer(I4B) :: n !< the nr. of elements in the vector
199  class(VectorBaseType), pointer :: vec !< the vector object to return
200  ! local
201  class(PetscVectorType), pointer :: petsc_vec
202 
203  allocate (petsc_vec)
204  call petsc_vec%create(n)
205  vec => petsc_vec
206 
207  end function pm_create_vec
208 
209  function pm_get_value_pos(this, ipos) result(value)
210  class(PetscMatrixType) :: this
211  integer(I4B) :: ipos
212  real(DP) :: value
213 
214  value = this%amat_petsc(ipos)
215 
216  end function pm_get_value_pos
217 
218  function pm_get_diag_value(this, irow) result(diag_value)
219  class(PetscMatrixType) :: this
220  integer(I4B) :: irow
221  real(DP) :: diag_value
222  ! local
223  integer(I4B) :: idiag
224 
225  idiag = this%get_position_diag(irow)
226  diag_value = this%amat_petsc(idiag)
227 
228  end function pm_get_diag_value
229 
230  subroutine pm_set_diag_value(this, irow, diag_value)
231  class(PetscMatrixType) :: this
232  integer(I4B) :: irow
233  real(DP) :: diag_value
234  ! local
235  integer(I4B) :: idiag
236 
237  idiag = this%get_position_diag(irow)
238  this%amat_petsc(idiag) = diag_value
239 
240  end subroutine pm_set_diag_value
241 
242  subroutine pm_set_value_pos(this, ipos, value)
243  class(PetscMatrixType) :: this
244  integer(I4B) :: ipos
245  real(DP) :: value
246 
247  this%amat_petsc(ipos) = value
248 
249  end subroutine pm_set_value_pos
250 
251  subroutine pm_add_value_pos(this, ipos, value)
252  class(PetscMatrixType) :: this
253  integer(I4B) :: ipos
254  real(DP) :: value
255 
256  this%amat_petsc(ipos) = this%amat_petsc(ipos) + value
257 
258  end subroutine pm_add_value_pos
259 
260  subroutine pm_add_diag_value(this, irow, value)
261  class(PetscMatrixType) :: this
262  integer(I4B) :: irow
263  real(DP) :: value
264  ! local
265  integer(I4B) :: idiag
266 
267  idiag = this%get_position_diag(irow)
268  this%amat_petsc(idiag) = this%amat_petsc(idiag) + value
269 
270  end subroutine pm_add_diag_value
271 
272  function pm_get_first_col_pos(this, irow) result(first_col_pos)
273  class(PetscMatrixType) :: this
274  integer(I4B) :: irow
275  integer(I4B) :: first_col_pos
276  ! local
277  integer(I4B) :: irow_local
278 
279  ! convert to local row index
280  irow_local = irow - this%offset
281 
282  ! includes conversion to Fortran's 1-based
283  first_col_pos = this%ia_petsc(irow_local) + 1
284 
285  end function pm_get_first_col_pos
286 
287  function pm_get_last_col_pos(this, irow) result(last_col_pos)
288  class(PetscMatrixType) :: this
289  integer(I4B) :: irow
290  integer(I4B) :: last_col_pos
291  ! local
292  integer(I4B) :: irow_local
293 
294  ! convert to local row index
295  irow_local = irow - this%offset
296 
297  ! includes conversion to Fortran's 1-based
298  last_col_pos = this%ia_petsc(irow_local + 1)
299 
300  end function pm_get_last_col_pos
301 
302  function pm_get_column(this, ipos) result(icol)
303  class(PetscMatrixType) :: this
304  integer(I4B) :: ipos
305  integer(I4B) :: icol
306 
307  ! includes conversion to Fortran's 1-based
308  icol = this%ja_petsc(ipos) + 1
309 
310  end function pm_get_column
311 
312  !> @brief Return position index for (irow,icol) element
313  !! in the matrix. This index can be used in other
314  !! routines for direct access.
315  !< Returns -1 when not found.
316  function pm_get_position(this, irow, icol) result(ipos)
317  class(PetscMatrixType) :: this
318  integer(I4B) :: irow
319  integer(I4B) :: icol
320  integer(I4B) :: ipos
321  ! local
322  integer(I4B) :: ipos_f
323  integer(I4B) :: irow_local
324 
325  ipos = -1
326 
327  ! convert to local row index
328  irow_local = irow - this%offset
329 
330  ! includes conversion to Fortran's 1-based
331  do ipos_f = this%ia_petsc(irow_local) + 1, this%ia_petsc(irow_local + 1)
332  if (this%ja_petsc(ipos_f) + 1 == icol) then
333  ipos = ipos_f
334  return
335  end if
336  end do
337 
338  end function pm_get_position
339 
340  function pm_get_position_diag(this, irow) result(ipos_diag)
341  class(PetscMatrixType) :: this
342  integer(I4B) :: irow
343  integer(I4B) :: ipos_diag
344 
345  ipos_diag = this%pm_get_position(irow, irow)
346 
347  end function pm_get_position_diag
348 
349  !> @brief Set all entries in the matrix to zero
350  !<
351  subroutine pm_zero_entries(this)
352  class(PetscMatrixType) :: this
353  ! local
354  integer(I4B) :: i
355 
356  do i = 1, this%nnz
357  this%amat_petsc(i) = dzero
358  end do
359 
360  end subroutine pm_zero_entries
361 
362  !> @brief Set all off-diagonal entries in the matrix to zero
363  !<
364  subroutine pm_zero_row_offdiag(this, irow)
365  class(PetscMatrixType) :: this
366  integer(I4B) :: irow
367  ! local
368  integer(I4B) :: ipos, idiag
369 
370  idiag = this%get_position_diag(irow)
371  do ipos = this%get_first_col_pos(irow), this%get_last_col_pos(irow)
372  if (ipos == idiag) cycle
373  this%amat_petsc(ipos) = dzero
374  end do
375 
376  end subroutine pm_zero_row_offdiag
377 
378  subroutine pm_get_aij(this, ia, ja, amat)
379  use simmodule, only: ustop
380  class(PetscMatrixType) :: this
381  integer(I4B), dimension(:), pointer, contiguous :: ia
382  integer(I4B), dimension(:), pointer, contiguous :: ja
383  real(DP), dimension(:), pointer, contiguous :: amat
384 
385  call ustop("pm_get_aij not implemented")
386 
387  end subroutine pm_get_aij
388 
389  !> @brief Get the ia/ja and amat values for the local
390  !< diagonal block of this matrix. It's a copy.
391  subroutine pm_get_aij_local(this, ia, ja, amat)
392  class(PetscMatrixType) :: this
393  integer(I4B), dimension(:), pointer, contiguous :: ia
394  integer(I4B), dimension(:), pointer, contiguous :: ja
395  real(DP), dimension(:), pointer, contiguous :: amat
396  ! local
397  petscerrorcode :: ierr
398  integer(I4B) :: irow, icol, ipos
399  integer(I4B), dimension(1) :: irow_idxs, icol_idxs
400  real(DP), dimension(1) :: values
401  mat :: local_mat
402 
403  call matgetdiagonalblock(this%mat, local_mat, ierr)
404  chkerrq(ierr)
405 
406  do irow = 1, this%nrow
407  do ipos = this%ia_local(irow), this%ia_local(irow + 1) - 1
408  icol = this%ja_local(ipos)
409  irow_idxs(1) = irow - 1
410  icol_idxs(1) = icol - 1
411  call matgetvalues(local_mat, 1, irow_idxs, 1, icol_idxs, values, ierr)
412  chkerrq(ierr)
413  this%amat_local(ipos) = values(1)
414  end do
415  end do
416 
417  ia => this%ia_local
418  ja => this%ja_local
419  amat => this%amat_local
420 
421  end subroutine pm_get_aij_local
422 
423  function pm_get_row_offset(this) result(offset)
424  class(PetscMatrixType) :: this
425  integer(I4B) :: offset
426 
427  offset = this%offset
428 
429  end function pm_get_row_offset
430 
431  !> @brief Calculates global matrix vector product: y = A * x
432  !<
433  subroutine pm_multiply(this, vec_x, vec_y)
434  class(PetscMatrixType) :: this
435  class(VectorBaseType), pointer :: vec_x
436  class(VectorBaseType), pointer :: vec_y
437  ! local
438  petscerrorcode :: ierr
439  class(PetscVectorType), pointer :: x, y
440 
441  x => null()
442  select type (vec_x)
443  class is (petscvectortype)
444  x => vec_x
445  end select
446  y => null()
447  select type (vec_y)
448  class is (petscvectortype)
449  y => vec_y
450  end select
451 
452  ! copy data into petsc object
453  call this%update()
454  ! and multiply
455  call matmult(this%mat, x%vec_impl, y%vec_impl, ierr)
456  chkerrq(ierr)
457 
458  end subroutine pm_multiply
459 
460 end module petscmatrixmodule
This module contains simulation constants.
Definition: Constants.f90:9
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
This module defines variable data types.
Definition: kind.f90:8
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public ustop(stopmess, ioutlocal)
Stop the simulation.
Definition: Sim.f90:312
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=linelength) simulation_mode