FrontISTR  6.0.0
Large-scale structural analysis program with finit element method
hecmw_precond_SAAMG.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! Copyright (c) 2026 FrontISTR Commons
3 ! This software is released under the MIT License, see License.txt
4 !-------------------------------------------------------------------------------
13  use hecmw_util
17  use hecmw_precond_saamg_comm, only: hecmwst_saamg_comm, hecmw_saamg_comm_free, &
20  use hecmw_precond_saamg_core, only: hecmwst_saamg_hier, hecmw_saamg_setup, &
24  use hecmw_precond_saamg_matrix, only: hecmwst_saamg_bcsr, hecmw_saamg_bcsr_free
25  use hecmw_precond_saamg_param, only: hecmwst_saamg_params
30  use hecmw_mat_id
31  implicit none
32 
33  private
37 
38  type(hecmwST_saamg_hier), save :: g_dh
39  type(hecmwST_saamg_comm), save :: g_cmt
40  logical, save :: INITIALIZED = .false.
41  integer(kind=kint), save :: g_n = 0
42  integer(kind=kint), save :: g_id = 0
43  ! Size part of the structure signature of the matrix the hierarchy was built
44  ! from. The recycling flags (Iarray(98)/(97)) are a caller-side CONTRACT:
45  ! structure changes must be reported via Iarray(98). The one known caller whose
46  ! structure can change under a values-only flag -- the contact-elimination path,
47  ! whose reduced system depends on a value-driven slave-dof choice -- now detects
48  ! this itself and raises Iarray(98) at the source (notify_structure_change in
49  ! solve_LINEQ_contact_elim; full pattern hash there). This O(1) size check is
50  ! kept as a last-resort safety net against OTHER contract violations: a stale
51  ! hierarchy applied to a matrix of different size corrupts memory (observed on
52  ! mobile_case np=8 before the fixes). On mismatch we fall through to a full
53  ! rebuild (notice under LOGLEVEL>=1).
54  integer(kind=kint), save :: g_sig(4) = 0
55 
56 contains
57 
58  subroutine hecmw_precond_saamg_setup(hecMAT, hecMESH, sym)
59  implicit none
60  type(hecmwst_matrix), intent(inout) :: hecmat
61  type(hecmwst_local_mesh), intent(inout) :: hecmesh
62  integer(kind=kint), intent(in) :: sym
63  type(hecmwst_saamg_bcsr) :: a
64  type(hecmwst_saamg_params) :: prm
65  real(kind=kreal), allocatable :: b(:,:)
66  integer(kind=kint) :: ndof, nint, iopt(10), m, astat, myrank, sig_bad
67  real(kind=kreal) :: ropt(10)
68  logical :: will_use_mumps
69 
70  ! SA-AMG's setup needs LAPACK (dense coarsest factorization, per-aggregate QR,
71  ! Lanczos tridiagonal eigenvalue). LAPACK is optional in FrontISTR, so fail
72  ! early with a clear message rather than at an obscure link/runtime point.
73  if (.not. hecmw_saamg_lapack_available()) then
74  if (hecmw_comm_get_rank() == 0) write(*,'(a)') &
75  '#### SA-AMG (PRECOND=22) requires a LAPACK-enabled build. Rebuild with '// &
76  '--with-lapack (setup.sh) or -DWITH_LAPACK=ON (cmake), or select another preconditioner.'
78  end if
79 
80  ! Recycle-flag branches below are guarded by the structure signature (g_sig):
81  ! the flags are a caller-side contract that some callers break (see g_sig
82  ! comment). The verdict MUST be identical on every rank -- reuse / refresh /
83  ! rebuild all execute different collective patterns, so a per-rank decision
84  ! deadlocks (one rank's contact state can change while another's does not).
85  ! Hence the local check is allreduced before branching.
86  if (initialized .and. hecmat%Iarray(98) == 0) then
87  sig_bad = 0
88  if (.not. sig_sizes_match(hecmat)) sig_bad = 1
89  call hecmw_saamg_comm_allreduce_sum_int(g_cmt, sig_bad)
90  if (sig_bad > 0) then
91  if (hecmw_mat_get_loglevel(hecmat) >= 1 .and. hecmw_comm_get_rank() == 0) write(*,'(a)') &
92  '#### SA-AMG: matrix structure changed under a values-only recycle flag -- full rebuild'
93  else if (hecmat%Iarray(97) == 0) then
94  ! nothing changed -> reuse the hierarchy as-is (also covers precond recycling)
95  call saamg_register_mat(hecmat, hecmesh) ! keep the matvec hook pointing at the current matrix
96  return
97  else
98  ! structure unchanged, values changed -> numeric-only refresh (Newton reuse):
99  ! reuse aggregation / coarse comm table / tentative P-hat, recompute the rest.
100  call saamg_register_mat(hecmat, hecmesh) ! refresh the fine-level matvec hook to the new values
101  call hecmw_saamg_from_hecmat(hecmat, a, include_halo=.true.)
102  call hecmw_saamg_refresh(g_dh, a)
103  call hecmw_saamg_bcsr_free(a)
104  hecmat%Iarray(97) = 0
105  return
106  end if
107  end if
108 
109  ! structure changed -> full rebuild
110  if (initialized) call hecmw_precond_saamg_clear(hecmat%NDOF)
111  call saamg_register_mat(hecmat, hecmesh) ! register for the fine-level matvec hook (HEC-MW matvec)
112 
113  ndof = hecmat%NDOF
114  ! near-kernel size m by problem type: 1=heat(const), 2=plane(2D RBM, 3 modes),
115  ! 3=solid / 6=shell (3D RBM, 6 modes).
116  select case (ndof)
117  case (1); m = 1
118  case (2); m = 3
119  case (3, 6); m = 6
120  case default
121  write(*,'(a)') '#### SA-AMG (PRECOND=22): only NDOF=1 (heat) / 2 (plane) / 3 (solid) / 6 (shell) supported'
123  end select
124  nint = hecmat%N
125 
126  ! map control-file options; 0 = keep default. Integer line (Iarray 41:50) and
127  ! real line (Rarray 41:50). Integer slots 1-7 mirror the ML (PRECOND=5) layout
128  ! so ML users can reuse the same option line (see fstr_ctrl_common precond==22
129  ! and hecmw_ML_wrapper.c, which reads opt[0..6] = slots 1-7); slots 8-10 are
130  ! outside what ML reads and hold SA-AMG-specific knobs. The real line is not
131  ! read by ML at all, so it carries the remaining knobs (including a few integer
132  ! ones, rounded on read).
133  ! 1 = coarsest solver (ML CoarseSolver: 0=auto, 1=Smoother, 2=dense, 3=MUMPS;
134  ! SA-AMG extension: 4=DIRECTmf (redundant sparse))
135  ! 2 = smoother type (ML SmootherType: 0/1=Chebyshev; 2/3 N/A -> Chebyshev)
136  ! 3 = cycle (ML MGType: 0=default(=W)/1=V, 2=W; 3=FullV N/A -> W)
137  ! 4 = max levels (ML MaxLevels)
138  ! 5 = RESERVED (ML CoarsenScheme; SA-AMG is always uncoupled -> warn
139  ! and ignore. Deliberately kept unused: an ML deck
140  ! carries 1..5 here, which used to be silently taken as
141  ! max_size and wrecked the hierarchy)
142  ! 6 = Chebyshev degree (ML NumSweeps)
143  ! 7 = coarse size (ML MaxCoarseSize)
144  ! 8 = max aggregate size (SA-AMG-specific: the aggressive-coarsening lever)
145  ! 9 = galerkin_lowmem (Ac=P^T A P: 0 = default (2-stage everywhere, faster),
146  ! > 0 = low-memory (fuse the finest level only, same
147  ! peak as fully fused but faster; deep levels 2-stage))
148  ! 10 = RESERVED (free slot for future SA-AMG-specific knobs)
149  ! Real line: 1 = theta (strength threshold), 2 = cheb_alpha, 3 = safety,
150  ! 4 = taper_k (coarsening taper, 3-1: 0 = default 100, > 0 = use as K,
151  ! < 0 = disable the taper / legacy behavior)
152  ! 5 = agg_order (aggregation seed-scan ordering: 0 = default (BFS),
153  ! < 0 = natural node order / legacy, 1..4 = explicit mode
154  ! (1=bfs, 2=gid-hash, 3=mindeg, 4=maxdeg))
155  ! 6 = min aggregate size (0 = default 3)
156  ! 7 = verify (0 = off, > 0 = on) / 8 = dump_vtk (0 = off, > 0 = on)
157  call hecmw_mat_get_solver_opt(hecmat, iopt)
158  myrank = hecmw_comm_get_rank()
159  ! slot 1: coarsest solver. The external encoding (ML CoarseSolver-compatible;
160  ! 4 is an SA-AMG extension beyond ML) and the internal prm%coarsest_solver share
161  ! the SAME numbering, so no translation is needed: 0=auto, 1=smoother, 2=dense,
162  ! 3=MUMPS, 4=DIRECTmf (redundant sparse).
163  select case (iopt(1))
164  case (0, 1, 2, 3, 4) ; prm%coarsest_solver = iopt(1)
165  case default ; if (myrank == 0) write(*,'(a,i0,a)') &
166  '#### SA-AMG: invalid coarse solver ', iopt(1), ' (ignored) -- using auto'
167  end select
168  ! slot 2: smoother type -- SA-AMG only implements Chebyshev
169  select case (iopt(2))
170  case (0, 1) ; ! Chebyshev (only supported smoother)
171  case default ; if (myrank == 0) write(*,'(a,i0,a)') &
172  '#### SA-AMG: smoother type ', iopt(2), ' not supported -- using Chebyshev'
173  end select
174  ! slot 3: multigrid cycle order gamma (ML MGType-compatible: 1=V, 2=W).
175  ! 0 = keep default = W (prm%ncycle=2): never slower than V and markedly fewer
176  ! iterations on deep hierarchies; nlevel=2 degenerates to V (is_coarsest guard).
177  select case (iopt(3))
178  case (0) ; ! default -> keep prm%ncycle (=2, W-cycle)
179  case (1) ; prm%ncycle = 1 ! V-cycle (explicit)
180  case (2) ; prm%ncycle = 2 ! W-cycle
181  case (3) ; prm%ncycle = 2 ; if (myrank == 0) write(*,'(a)') &
182  '#### SA-AMG: Full-V cycle not supported -- using W-cycle'
183  case default ; if (myrank == 0) write(*,'(a,i0,a)') &
184  '#### SA-AMG: invalid cycle ', iopt(3), ' (ignored) -- using default (W)'
185  end select
186  if (iopt(4) > 0) prm%max_level = iopt(4) ! ML MaxLevels
187  ! slot 5: reserved. ML puts CoarsenScheme here (1..5 = UncoupledMIS/METIS/
188  ! ParMETIS/Zoltan/DD); SA-AMG always uses uncoupled aggregation, so the value is
189  ! ignored -- but say so, otherwise a reused ML option line looks like it selects
190  ! a coarsening scheme.
191  if (iopt(5) /= 0 .and. myrank == 0) then
192  write(*,'(a,i0,a)') '#### SA-AMG: int slot5 (ML CoarsenScheme) = ', iopt(5), &
193  ' is ignored -- SA-AMG always uses uncoupled aggregation'
194  write(*,'(a)') '#### (max aggregate size is int slot8)'
195  end if
196  if (iopt(6) > 0) prm%cheb_deg = iopt(6) ! ML NumSweeps (Chebyshev degree)
197  if (iopt(7) > 0) prm%coarse_size = iopt(7) ! ML MaxCoarseSize
198  if (iopt(8) > 0) prm%max_size = iopt(8) ! SA-AMG-specific (aggressive coarsening lever)
199  if (iopt(9) > 0) prm%galerkin_lowmem = .true. ! SA-AMG-specific (fuse the finest level only)
200  ! verbose has no iopt slot: enable it via !SOLVER LOGLEVEL>=1 (independent of
201  ! TIMELOG; LOGLEVEL unset = -1 leaves verbose off).
202  prm%loglevel = hecmw_mat_get_loglevel(hecmat) ! independent LOGLEVEL (-1 if unset); >=2 -> [mem] probes
203  prm%verbose = (prm%loglevel >= 1)
204  prm%timelog = hecmw_mat_get_timelog(hecmat) ! !SOLVER TIMELOG (2=VERBOSE -> per-section [time] probes)
205  call hecmw_mat_get_solver_ropt(hecmat, ropt)
206  if (ropt(1) > 0.0d0) prm%theta = ropt(1)
207  if (ropt(2) > 0.0d0) prm%cheb_alpha = ropt(2)
208  if (ropt(3) > 0.0d0) prm%safety = ropt(3)
209  ! real slot 4: coarsening-taper K (an integer carried on the real line: the int
210  ! line is reserved for the ML-compatible and high-traffic knobs, and the taper is
211  ! rarely touched). 0 = default (prm%taper_k = 100), > 0 = use as K,
212  ! < 0 = disable the taper (legacy pre-taper coarsening).
213  ! (int(x+0.5), not the intrinsic nint(): a local variable `nint` shadows it.)
214  if (ropt(4) > 0.0d0) prm%taper_k = int(ropt(4) + 0.5d0, kind=kint)
215  if (ropt(4) < 0.0d0) prm%taper_k = 0
216  ! real slot 5: aggregation seed-scan ordering. 0 = default (BFS), < 0 = natural
217  ! (legacy), 1..4 = explicit mode.
218  if (ropt(5) > 0.0d0 .and. ropt(5) < 4.5d0) prm%agg_order = int(ropt(5) + 0.5d0, kind=kint)
219  if (ropt(5) < 0.0d0) prm%agg_order = 0
220  ! real slot 6: min aggregate size (integer carried on the real line; rarely
221  ! touched -- it only sets the forced-merge threshold for leftover aggregates).
222  if (ropt(6) > 0.0d0) prm%min_size = int(ropt(6) + 0.5d0, kind=kint)
223  ! real slots 7/8: diagnostics (0 = off, > 0 = on), alongside LOGLEVEL/TIMELOG.
224  prm%verify = (ropt(7) > 0.0d0)
225  prm%dump_vtk = (ropt(8) > 0.0d0) ! write finest aggregation to saamg_agg.<rank>.vtk
226  ! symmetric (CG, sym=1) vs non-symmetric (BiCGSTAB/GMRES, sym=0): the latter uses a
227  ! general (SYM=0 / LU) coarsest so the actual non-symmetric coarse is factored exactly.
228  prm%symmetric = (sym == 1)
229 
230  ! coarse_size auto-default by coarsest solver (only when the user left it unset):
231  ! dense LDL^T is O(N^3) so keep the coarsest small (100 dof); a sparse direct
232  ! coarsest (distributed MUMPS, or redundant DIRECTmf) is cheap at tens of
233  ! thousands of dof -> use a much larger default so the hierarchy stays shallow
234  ! (matches the ML+MUMPS convention of 50000).
235  if (iopt(7) == 0) then
236  will_use_mumps = (prm%coarsest_solver == 3) .or. &
237  (prm%coarsest_solver == 0 .and. hecmw_saamg_cmumps_available())
238  if (will_use_mumps .or. prm%coarsest_solver == 4) prm%coarse_size = 50000
239  end if
240 
241  ! finest-level communication table (empty on 1 rank -> sequential behavior)
242  call hecmw_saamg_comm_from_mesh(hecmesh, ndof, g_cmt)
243  ! F4a: verify the distributed (halo-aware) matvec is consistent across ranks
244  if (prm%verify) call hecmw_saamg_verify_matvec(hecmat, hecmesh, g_cmt, ndof)
245  ! F4b: verify uncoupled aggregation + coarse comm-table construction
246  if (prm%verify) call hecmw_saamg_verify_coarsen(hecmat, g_cmt, m, prm)
247  ! F4b-2: verify halo-extended tentative P-hat (P-hat * B_coarse = B_fine, all rows)
248  if (prm%verify) call hecmw_saamg_verify_prolong(hecmat, hecmesh, g_cmt, ndof, m, prm)
249  ! F4c-1: verify the distributed smoothed prolongator (global ||P B_c - B_f|| rank-independent)
250  if (prm%verify) call hecmw_saamg_verify_smoothp(hecmat, hecmesh, g_cmt, ndof, m, prm)
251 
252  ! fully-distributed multilevel hierarchy: finest operator keeps halo columns
253  call hecmw_saamg_from_hecmat(hecmat, a, include_halo=.true.)
254  allocate(b(nint*ndof, m), stat=astat)
255  call hecmw_saamg_check_alloc(astat, 'near-kernel B (rigid-body modes)')
256  ! shared rigid-body near-kernel (with ML)
257  call hecmw_precond_rbm_from_mesh(hecmesh, ndof, b)
258  ! move A into the hierarchy (no redundant copy) unless verify still needs it
259  call hecmw_saamg_setup(a, g_cmt, b, m, prm, g_dh, saamg_fine_matvec, &
260  move_in=(.not. prm%verify))
261  ! verify: a numeric refresh reproduces (a) the full build for the SAME A and
262  ! (b) a fresh full build for a value-perturbed A' (same pattern) -- S4 routing
263  if (prm%verify) call hecmw_saamg_verify_refresh(g_dh, a, g_cmt, b, m, prm, nint*ndof)
264  if (prm%dump_vtk) call dump_agg_vtk(g_dh, hecmesh, ndof, nint)
265  call hecmw_saamg_bcsr_free(a)
266  deallocate(b)
267 
268  g_n = nint*ndof
269  g_sig = (/ hecmat%N, hecmat%NP, hecmat%NPL, hecmat%NPU /)
270  initialized = .true.
271  hecmat%Iarray(98) = 0
272  hecmat%Iarray(97) = 0
273  end subroutine hecmw_precond_saamg_setup
274 
276  logical function sig_sizes_match(hecMAT) result(ok)
277  implicit none
278  type(hecmwst_matrix), intent(in) :: hecmat
279  ok = (g_sig(1) == hecmat%N .and. g_sig(2) == hecmat%NP .and. &
280  g_sig(3) == hecmat%NPL .and. g_sig(4) == hecmat%NPU)
281  end function sig_sizes_match
282 
283 
288  subroutine dump_agg_vtk(dh, hecMESH, ndof, nint)
289  implicit none
290  type(hecmwst_saamg_hier), intent(in) :: dh
291  type(hecmwst_local_mesh), intent(in) :: hecmesh
292  integer(kind=kint), intent(in) :: ndof, nint
293  character(len=128) :: fname
294  integer(kind=kint) :: rank, idummy
295  idummy = ndof
296  if (.not. allocated(dh%aggr_fine)) return
297  rank = hecmw_comm_get_rank()
298  write(fname,'(a,i0,a)') 'saamg_agg.', rank, '.vtk'
299  ! hecMESH%node is 3*n_node interleaved; internal nodes are 1..nint
300  call hecmw_saamg_write_vtk(trim(fname), hecmesh%node, nint, dh%aggr_fine)
301  if (rank == 0) write(*,'(a)') &
302  '#### SA-AMG: wrote finest aggregation to saamg_agg.<rank>.vtk (ParaView)'
303  end subroutine dump_agg_vtk
304 
305  subroutine hecmw_precond_saamg_apply(ZP, NDOF)
306  implicit none
307  real(kind=kreal), intent(inout) :: zp(:)
308  integer(kind=kint), intent(in) :: ndof
309  real(kind=kreal), allocatable :: r(:), z(:)
310  allocate(r(g_n), z(g_n))
311  r(1:g_n) = zp(1:g_n)
312  z(1:g_n) = 0.0d0
313  call hecmw_saamg_apply(g_dh, r, z) ! z = M^{-1} r (one distributed V-cycle)
314  zp(1:g_n) = z(1:g_n)
315  deallocate(r, z)
316  end subroutine hecmw_precond_saamg_apply
317 
318  subroutine hecmw_precond_saamg_clear(NDOF)
319  implicit none
320  integer(kind=kint), intent(in) :: ndof
321  if (initialized) then
322  call hecmw_saamg_free(g_dh)
323  call hecmw_saamg_comm_free(g_cmt)
324  initialized = .false.
325  g_n = 0
326  g_sig = 0
327  end if
328  if (g_id > 0) then; call hecmw_mat_id_clear(g_id); g_id = 0; end if
329  end subroutine hecmw_precond_saamg_clear
330 
334  subroutine saamg_register_mat(hecMAT, hecMESH)
335  implicit none
336  type(hecmwst_matrix), intent(in), target :: hecmat
337  type(hecmwst_local_mesh), intent(in), target :: hecmesh
338  if (g_id > 0) call hecmw_mat_id_clear(g_id)
339  call hecmw_mat_id_set(hecmat, hecmesh, g_id)
340  end subroutine saamg_register_mat
341 
346  subroutine saamg_fine_matvec(x, y)
347  implicit none
348  real(kind=kreal), intent(inout) :: x(:)
349  real(kind=kreal), intent(out) :: y(:)
350  type(hecmwst_matrix), pointer :: mat
351  type(hecmwst_local_mesh), pointer :: mesh
352  call hecmw_mat_id_get(g_id, mat, mesh)
353  call hecmw_matvec(mesh, mat, x, y)
354  end subroutine saamg_fine_matvec
355 
356 end module hecmw_precond_saamg
subroutine, public hecmw_mat_id_set(hecMAT, hecMESH, id)
subroutine, public hecmw_mat_id_get(id, hecMAT, hecMESH)
subroutine, public hecmw_mat_id_clear(id)
subroutine, public hecmw_mat_get_solver_opt(hecMAT, solver_opt)
integer(kind=kint) function, public hecmw_mat_get_timelog(hecMAT)
integer(kind=kint) function, public hecmw_mat_get_loglevel(hecMAT)
subroutine, public hecmw_mat_get_solver_ropt(hecMAT, solver_ropt)
Rigid-body / near-kernel modes from mesh coordinates.
subroutine, public hecmw_precond_rbm_from_mesh(hecMESH, ndof, rbm)
Smoothed Aggregation AMG preconditioner : FrontISTR adapter.
subroutine, public hecmw_saamg_from_hecmat(hecMAT, A, include_halo)
Convert hecmwST_matrix (FrontISTR block storage) -> internal block-CSR. Rows are always internal only...
subroutine, public hecmw_saamg_comm_from_mesh(hecMESH, ndof, cmt)
Build the finest-level communication table from the FrontISTR mesh. Copies the node-based halo descri...
Smoothed Aggregation AMG preconditioner : node graph + aggregation.
subroutine, public hecmw_saamg_write_vtk(fname, coord, nnode, aggr)
Write a legacy-VTK point cloud colored by aggregate id (ParaView diagnostic). coord is (x,...
Smoothed Aggregation AMG preconditioner : distributed MUMPS coarsest solver.
logical function, public hecmw_saamg_cmumps_available()
.true. only when compiled with MUMPS; the caller uses the dense coarsest else.
Smoothed Aggregation AMG preconditioner : lightweight comm table.
logical function, public hecmw_saamg_lapack_available()
Whether this build links LAPACK (SA-AMG's setup needs it: dense coarsest factorization,...
subroutine, public hecmw_saamg_check_alloc(ier, what)
Report a failed allocation (stat /= 0) with a clear message and a collective abort,...
subroutine, public hecmw_saamg_comm_allreduce_sum_r(cmt, s)
Global sum-reduction of a scalar over the communicator (no-op when serial).
subroutine, public hecmw_saamg_comm_allreduce_sum_int(cmt, n)
Global sum-reduction of an integer over the communicator (no-op when serial).
subroutine, public hecmw_saamg_comm_free(cmt)
Smoothed Aggregation AMG preconditioner : distributed coarsening.
subroutine, public hecmw_saamg_free(dh)
subroutine, public hecmw_saamg_setup(A, cmt, bfine_int, m, prm, dh, fine_matvec, move_in)
Build a fully-distributed multilevel SA-AMG hierarchy. bfine_int is the near-kernel on internal nodes...
subroutine, public hecmw_saamg_refresh(dh, A_new)
Numeric-only refresh (Newton): reuse each level's aggregation / comm table / tentative P-hat AND the ...
subroutine, public hecmw_saamg_apply(dh, r, z)
Apply one distributed multilevel V-cycle: z = M^{-1} r (internal, length nint*nb).
Smoothed Aggregation AMG preconditioner : internal block-CSR matrix.
subroutine, public hecmw_saamg_bcsr_free(A)
Release the storage held by a hecmwST_saamg_bcsr.
Smoothed Aggregation AMG preconditioner : tunable parameters.
Smoothed Aggregation AMG preconditioner : distributed self-checks.
subroutine, public hecmw_saamg_verify_coarsen(hecMAT, cmt, m, prm)
F4b self-check: build the uncoupled aggregation and the coarse comm table on the distributed finest o...
subroutine, public hecmw_saamg_verify_prolong(hecMAT, hecMESH, cmt, ndof, m, prm)
F4b-2 self-check: build the halo-extended tentative prolongator P-hat_ext on the distributed operator...
subroutine, public hecmw_saamg_verify_refresh(dh, A, cmt, B, m, prm, n)
Verify the distributed numeric refresh: refreshing with the SAME operator A must reproduce the freshl...
subroutine, public hecmw_saamg_verify_matvec(hecMAT, hecMESH, cmt, ndof)
F4a self-check: the distributed (halo-aware) matvec applied to a globally consistent vector x (define...
subroutine, public hecmw_saamg_verify_smoothp(hecMAT, hecMESH, cmt, ndof, m, prm)
F4c-1 self-check: build the distributed SMOOTHED prolongator P and confirm the global near-kernel res...
Smoothed Aggregation AMG preconditioner : FrontISTR backend (id 22)
subroutine, public hecmw_precond_saamg_setup(hecMAT, hecMESH, sym)
subroutine, public hecmw_precond_saamg_apply(ZP, NDOF)
subroutine, public hecmw_precond_saamg_clear(NDOF)
subroutine, public hecmw_matvec(hecMESH, hecMAT, X, Y, COMMtime)
I/O and Utility.
Definition: hecmw_util_f.F90:7
subroutine hecmw_abort(comm, code)
integer(kind=4), parameter kint
integer(kind=kint) function hecmw_comm_get_comm()
integer(kind=4), parameter kreal
integer(kind=kint) function hecmw_comm_get_rank()