xref: /petsc/src/ksp/pc/impls/parms/parms.c (revision fbf9dbe564678ed6eff1806adbc4c4f01b9743f4)
1 #define PETSCKSP_DLL
2 
3 /*
4    Provides an interface to pARMS.
5    Requires pARMS 3.2 or later.
6 */
7 
8 #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/
9 
10 #if defined(PETSC_USE_COMPLEX)
11   #define DBL_CMPLX
12 #else
13   #define DBL
14 #endif
15 #define USE_MPI
16 #define REAL double
17 #define HAS_BLAS
18 #define FORTRAN_UNDERSCORE
19 #include "parms_sys.h"
20 #undef FLOAT
21 #define FLOAT PetscScalar
22 #include <parms.h>
23 
24 /*
25    Private context (data structure) for the  preconditioner.
26 */
27 typedef struct {
28   parms_Map         map;
29   parms_Mat         A;
30   parms_PC          pc;
31   PCPARMSGlobalType global;
32   PCPARMSLocalType  local;
33   PetscInt          levels, blocksize, maxdim, maxits, lfil[7];
34   PetscBool         nonsymperm, meth[8];
35   PetscReal         solvetol, indtol, droptol[7];
36   PetscScalar      *lvec0, *lvec1;
37 } PC_PARMS;
38 
39 static PetscErrorCode PCSetUp_PARMS(PC pc)
40 {
41   Mat                pmat;
42   PC_PARMS          *parms = (PC_PARMS *)pc->data;
43   const PetscInt    *mapptr0;
44   PetscInt           n, lsize, low, high, i, pos, ncols, length;
45   int               *maptmp, *mapptr, *ia, *ja, *ja1, *im;
46   PetscScalar       *aa, *aa1;
47   const PetscInt    *cols;
48   PetscInt           meth[8];
49   const PetscScalar *values;
50   MatInfo            matinfo;
51   PetscMPIInt        rank, npro;
52 
53   PetscFunctionBegin;
54   /* Get preconditioner matrix from PETSc and setup pARMS structs */
55   PetscCall(PCGetOperators(pc, NULL, &pmat));
56   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pmat), &npro));
57   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pmat), &rank));
58 
59   PetscCall(MatGetSize(pmat, &n, NULL));
60   PetscCall(PetscMalloc1(npro + 1, &mapptr));
61   PetscCall(PetscMalloc1(n, &maptmp));
62   PetscCall(MatGetOwnershipRanges(pmat, &mapptr0));
63   low   = mapptr0[rank];
64   high  = mapptr0[rank + 1];
65   lsize = high - low;
66 
67   for (i = 0; i < npro + 1; i++) mapptr[i] = mapptr0[i] + 1;
68   for (i = 0; i < n; i++) maptmp[i] = i + 1;
69 
70   /* if created, destroy the previous map */
71   if (parms->map) {
72     parms_MapFree(&parms->map);
73     parms->map = NULL;
74   }
75 
76   /* create pARMS map object */
77   parms_MapCreateFromPtr(&parms->map, (int)n, maptmp, mapptr, PetscObjectComm((PetscObject)pmat), 1, NONINTERLACED);
78 
79   /* if created, destroy the previous pARMS matrix */
80   if (parms->A) {
81     parms_MatFree(&parms->A);
82     parms->A = NULL;
83   }
84 
85   /* create pARMS mat object */
86   parms_MatCreate(&parms->A, parms->map);
87 
88   /* setup and copy csr data structure for pARMS */
89   PetscCall(PetscMalloc1(lsize + 1, &ia));
90   ia[0] = 1;
91   PetscCall(MatGetInfo(pmat, MAT_LOCAL, &matinfo));
92   length = matinfo.nz_used;
93   PetscCall(PetscMalloc1(length, &ja));
94   PetscCall(PetscMalloc1(length, &aa));
95 
96   for (i = low; i < high; i++) {
97     pos = ia[i - low] - 1;
98     PetscCall(MatGetRow(pmat, i, &ncols, &cols, &values));
99     ia[i - low + 1] = ia[i - low] + ncols;
100 
101     if (ia[i - low + 1] >= length) {
102       length += ncols;
103       PetscCall(PetscMalloc1(length, &ja1));
104       PetscCall(PetscArraycpy(ja1, ja, ia[i - low] - 1));
105       PetscCall(PetscFree(ja));
106       ja = ja1;
107       PetscCall(PetscMalloc1(length, &aa1));
108       PetscCall(PetscArraycpy(aa1, aa, ia[i - low] - 1));
109       PetscCall(PetscFree(aa));
110       aa = aa1;
111     }
112     PetscCall(PetscArraycpy(&ja[pos], cols, ncols));
113     PetscCall(PetscArraycpy(&aa[pos], values, ncols));
114     PetscCall(MatRestoreRow(pmat, i, &ncols, &cols, &values));
115   }
116 
117   /* csr info is for local matrix so initialize im[] locally */
118   PetscCall(PetscMalloc1(lsize, &im));
119   PetscCall(PetscArraycpy(im, &maptmp[mapptr[rank] - 1], lsize));
120 
121   /* 1-based indexing */
122   for (i = 0; i < ia[lsize] - 1; i++) ja[i] = ja[i] + 1;
123 
124   /* Now copy csr matrix to parms_mat object */
125   parms_MatSetValues(parms->A, (int)lsize, im, ia, ja, aa, INSERT);
126 
127   /* free memory */
128   PetscCall(PetscFree(maptmp));
129   PetscCall(PetscFree(mapptr));
130   PetscCall(PetscFree(aa));
131   PetscCall(PetscFree(ja));
132   PetscCall(PetscFree(ia));
133   PetscCall(PetscFree(im));
134 
135   /* setup parms matrix */
136   parms_MatSetup(parms->A);
137 
138   /* if created, destroy the previous pARMS pc */
139   if (parms->pc) {
140     parms_PCFree(&parms->pc);
141     parms->pc = NULL;
142   }
143 
144   /* Now create pARMS preconditioner object based on A */
145   parms_PCCreate(&parms->pc, parms->A);
146 
147   /* Transfer options from PC to pARMS */
148   switch (parms->global) {
149   case 0:
150     parms_PCSetType(parms->pc, PCRAS);
151     break;
152   case 1:
153     parms_PCSetType(parms->pc, PCSCHUR);
154     break;
155   case 2:
156     parms_PCSetType(parms->pc, PCBJ);
157     break;
158   }
159   switch (parms->local) {
160   case 0:
161     parms_PCSetILUType(parms->pc, PCILU0);
162     break;
163   case 1:
164     parms_PCSetILUType(parms->pc, PCILUK);
165     break;
166   case 2:
167     parms_PCSetILUType(parms->pc, PCILUT);
168     break;
169   case 3:
170     parms_PCSetILUType(parms->pc, PCARMS);
171     break;
172   }
173   parms_PCSetInnerEps(parms->pc, parms->solvetol);
174   parms_PCSetNlevels(parms->pc, parms->levels);
175   parms_PCSetPermType(parms->pc, parms->nonsymperm ? 1 : 0);
176   parms_PCSetBsize(parms->pc, parms->blocksize);
177   parms_PCSetTolInd(parms->pc, parms->indtol);
178   parms_PCSetInnerKSize(parms->pc, parms->maxdim);
179   parms_PCSetInnerMaxits(parms->pc, parms->maxits);
180   for (i = 0; i < 8; i++) meth[i] = parms->meth[i] ? 1 : 0;
181   parms_PCSetPermScalOptions(parms->pc, &meth[0], 1);
182   parms_PCSetPermScalOptions(parms->pc, &meth[4], 0);
183   parms_PCSetFill(parms->pc, parms->lfil);
184   parms_PCSetTol(parms->pc, parms->droptol);
185 
186   parms_PCSetup(parms->pc);
187 
188   /* Allocate two auxiliary vector of length lsize */
189   if (parms->lvec0) PetscCall(PetscFree(parms->lvec0));
190   PetscCall(PetscMalloc1(lsize, &parms->lvec0));
191   if (parms->lvec1) PetscCall(PetscFree(parms->lvec1));
192   PetscCall(PetscMalloc1(lsize, &parms->lvec1));
193   PetscFunctionReturn(PETSC_SUCCESS);
194 }
195 
196 static PetscErrorCode PCView_PARMS(PC pc, PetscViewer viewer)
197 {
198   PetscBool iascii;
199   PC_PARMS *parms = (PC_PARMS *)pc->data;
200   char     *str;
201   double    fill_fact;
202 
203   PetscFunctionBegin;
204   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
205   if (iascii) {
206     parms_PCGetName(parms->pc, &str);
207     PetscCall(PetscViewerASCIIPrintf(viewer, "  global preconditioner: %s\n", str));
208     parms_PCILUGetName(parms->pc, &str);
209     PetscCall(PetscViewerASCIIPrintf(viewer, "  local preconditioner: %s\n", str));
210     parms_PCGetRatio(parms->pc, &fill_fact);
211     PetscCall(PetscViewerASCIIPrintf(viewer, "  non-zero elements/original non-zero entries: %-4.2f\n", fill_fact));
212     PetscCall(PetscViewerASCIIPrintf(viewer, "  Tolerance for local solve: %g\n", parms->solvetol));
213     PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of levels: %d\n", parms->levels));
214     if (parms->nonsymperm) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using nonsymmetric permutation\n"));
215     PetscCall(PetscViewerASCIIPrintf(viewer, "  Block size: %d\n", parms->blocksize));
216     PetscCall(PetscViewerASCIIPrintf(viewer, "  Tolerance for independent sets: %g\n", parms->indtol));
217     PetscCall(PetscViewerASCIIPrintf(viewer, "  Inner Krylov dimension: %d\n", parms->maxdim));
218     PetscCall(PetscViewerASCIIPrintf(viewer, "  Maximum number of inner iterations: %d\n", parms->maxits));
219     if (parms->meth[0]) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using nonsymmetric permutation for interlevel blocks\n"));
220     if (parms->meth[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using column permutation for interlevel blocks\n"));
221     if (parms->meth[2]) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using row scaling for interlevel blocks\n"));
222     if (parms->meth[3]) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using column scaling for interlevel blocks\n"));
223     if (parms->meth[4]) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using nonsymmetric permutation for last level blocks\n"));
224     if (parms->meth[5]) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using column permutation for last level blocks\n"));
225     if (parms->meth[6]) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using row scaling for last level blocks\n"));
226     if (parms->meth[7]) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using column scaling for last level blocks\n"));
227     PetscCall(PetscViewerASCIIPrintf(viewer, "  amount of fill-in for ilut, iluk and arms: %d\n", parms->lfil[0]));
228     PetscCall(PetscViewerASCIIPrintf(viewer, "  amount of fill-in for schur: %d\n", parms->lfil[4]));
229     PetscCall(PetscViewerASCIIPrintf(viewer, "  amount of fill-in for ILUT L and U: %d\n", parms->lfil[5]));
230     PetscCall(PetscViewerASCIIPrintf(viewer, "  drop tolerance for L, U, L^{-1}F and EU^{-1}: %g\n", parms->droptol[0]));
231     PetscCall(PetscViewerASCIIPrintf(viewer, "  drop tolerance for schur complement at each level: %g\n", parms->droptol[4]));
232     PetscCall(PetscViewerASCIIPrintf(viewer, "  drop tolerance for ILUT in last level schur complement: %g\n", parms->droptol[5]));
233   }
234   PetscFunctionReturn(PETSC_SUCCESS);
235 }
236 
237 static PetscErrorCode PCDestroy_PARMS(PC pc)
238 {
239   PC_PARMS *parms = (PC_PARMS *)pc->data;
240 
241   PetscFunctionBegin;
242   if (parms->map) parms_MapFree(&parms->map);
243   if (parms->A) parms_MatFree(&parms->A);
244   if (parms->pc) parms_PCFree(&parms->pc);
245   if (parms->lvec0) PetscCall(PetscFree(parms->lvec0));
246   if (parms->lvec1) PetscCall(PetscFree(parms->lvec1));
247   PetscCall(PetscFree(pc->data));
248 
249   PetscCall(PetscObjectChangeTypeName((PetscObject)pc, 0));
250   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetGlobal_C", NULL));
251   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetLocal_C", NULL));
252   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetSolveTolerances_C", NULL));
253   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetSolveRestart_C", NULL));
254   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetNonsymPerm_C", NULL));
255   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetFill_C", NULL));
256   PetscFunctionReturn(PETSC_SUCCESS);
257 }
258 
259 static PetscErrorCode PCSetFromOptions_PARMS(PC pc, PetscOptionItems *PetscOptionsObject)
260 {
261   PC_PARMS         *parms = (PC_PARMS *)pc->data;
262   PetscBool         flag;
263   PCPARMSGlobalType global;
264   PCPARMSLocalType  local;
265 
266   PetscFunctionBegin;
267   PetscOptionsHeadBegin(PetscOptionsObject, "PARMS Options");
268   PetscCall(PetscOptionsEnum("-pc_parms_global", "Global preconditioner", "PCPARMSSetGlobal", PCPARMSGlobalTypes, (PetscEnum)parms->global, (PetscEnum *)&global, &flag));
269   if (flag) PetscCall(PCPARMSSetGlobal(pc, global));
270   PetscCall(PetscOptionsEnum("-pc_parms_local", "Local preconditioner", "PCPARMSSetLocal", PCPARMSLocalTypes, (PetscEnum)parms->local, (PetscEnum *)&local, &flag));
271   if (flag) PetscCall(PCPARMSSetLocal(pc, local));
272   PetscCall(PetscOptionsReal("-pc_parms_solve_tol", "Tolerance for local solve", "PCPARMSSetSolveTolerances", parms->solvetol, &parms->solvetol, NULL));
273   PetscCall(PetscOptionsInt("-pc_parms_levels", "Number of levels", "None", parms->levels, &parms->levels, NULL));
274   PetscCall(PetscOptionsBool("-pc_parms_nonsymmetric_perm", "Use nonsymmetric permutation", "PCPARMSSetNonsymPerm", parms->nonsymperm, &parms->nonsymperm, NULL));
275   PetscCall(PetscOptionsInt("-pc_parms_blocksize", "Block size", "None", parms->blocksize, &parms->blocksize, NULL));
276   PetscCall(PetscOptionsReal("-pc_parms_ind_tol", "Tolerance for independent sets", "None", parms->indtol, &parms->indtol, NULL));
277   PetscCall(PetscOptionsInt("-pc_parms_max_dim", "Inner Krylov dimension", "PCPARMSSetSolveRestart", parms->maxdim, &parms->maxdim, NULL));
278   PetscCall(PetscOptionsInt("-pc_parms_max_it", "Maximum number of inner iterations", "PCPARMSSetSolveTolerances", parms->maxits, &parms->maxits, NULL));
279   PetscCall(PetscOptionsBool("-pc_parms_inter_nonsymmetric_perm", "nonsymmetric permutation for interlevel blocks", "None", parms->meth[0], &parms->meth[0], NULL));
280   PetscCall(PetscOptionsBool("-pc_parms_inter_column_perm", "column permutation for interlevel blocks", "None", parms->meth[1], &parms->meth[1], NULL));
281   PetscCall(PetscOptionsBool("-pc_parms_inter_row_scaling", "row scaling for interlevel blocks", "None", parms->meth[2], &parms->meth[2], NULL));
282   PetscCall(PetscOptionsBool("-pc_parms_inter_column_scaling", "column scaling for interlevel blocks", "None", parms->meth[3], &parms->meth[3], NULL));
283   PetscCall(PetscOptionsBool("-pc_parms_last_nonsymmetric_perm", "nonsymmetric permutation for last level blocks", "None", parms->meth[4], &parms->meth[4], NULL));
284   PetscCall(PetscOptionsBool("-pc_parms_last_column_perm", "column permutation for last level blocks", "None", parms->meth[5], &parms->meth[5], NULL));
285   PetscCall(PetscOptionsBool("-pc_parms_last_row_scaling", "row scaling for last level blocks", "None", parms->meth[6], &parms->meth[6], NULL));
286   PetscCall(PetscOptionsBool("-pc_parms_last_column_scaling", "column scaling for last level blocks", "None", parms->meth[7], &parms->meth[7], NULL));
287   PetscCall(PetscOptionsInt("-pc_parms_lfil_ilu_arms", "amount of fill-in for ilut, iluk and arms", "PCPARMSSetFill", parms->lfil[0], &parms->lfil[0], &flag));
288   if (flag) parms->lfil[1] = parms->lfil[2] = parms->lfil[3] = parms->lfil[0];
289   PetscCall(PetscOptionsInt("-pc_parms_lfil_schur", "amount of fill-in for schur", "PCPARMSSetFill", parms->lfil[4], &parms->lfil[4], NULL));
290   PetscCall(PetscOptionsInt("-pc_parms_lfil_ilut_L_U", "amount of fill-in for ILUT L and U", "PCPARMSSetFill", parms->lfil[5], &parms->lfil[5], &flag));
291   if (flag) parms->lfil[6] = parms->lfil[5];
292   PetscCall(PetscOptionsReal("-pc_parms_droptol_factors", "drop tolerance for L, U, L^{-1}F and EU^{-1}", "None", parms->droptol[0], &parms->droptol[0], NULL));
293   PetscCall(PetscOptionsReal("-pc_parms_droptol_schur_compl", "drop tolerance for schur complement at each level", "None", parms->droptol[4], &parms->droptol[4], &flag));
294   if (flag) parms->droptol[1] = parms->droptol[2] = parms->droptol[3] = parms->droptol[0];
295   PetscCall(PetscOptionsReal("-pc_parms_droptol_last_schur", "drop tolerance for ILUT in last level schur complement", "None", parms->droptol[5], &parms->droptol[5], &flag));
296   if (flag) parms->droptol[6] = parms->droptol[5];
297   PetscOptionsHeadEnd();
298   PetscFunctionReturn(PETSC_SUCCESS);
299 }
300 
301 static PetscErrorCode PCApply_PARMS(PC pc, Vec b, Vec x)
302 {
303   PC_PARMS          *parms = (PC_PARMS *)pc->data;
304   const PetscScalar *b1;
305   PetscScalar       *x1;
306 
307   PetscFunctionBegin;
308   PetscCall(VecGetArrayRead(b, &b1));
309   PetscCall(VecGetArray(x, &x1));
310   parms_VecPermAux((PetscScalar *)b1, parms->lvec0, parms->map);
311   parms_PCApply(parms->pc, parms->lvec0, parms->lvec1);
312   parms_VecInvPermAux(parms->lvec1, x1, parms->map);
313   PetscCall(VecRestoreArrayRead(b, &b1));
314   PetscCall(VecRestoreArray(x, &x1));
315   PetscFunctionReturn(PETSC_SUCCESS);
316 }
317 
318 static PetscErrorCode PCPARMSSetGlobal_PARMS(PC pc, PCPARMSGlobalType type)
319 {
320   PC_PARMS *parms = (PC_PARMS *)pc->data;
321 
322   PetscFunctionBegin;
323   if (type != parms->global) {
324     parms->global   = type;
325     pc->setupcalled = 0;
326   }
327   PetscFunctionReturn(PETSC_SUCCESS);
328 }
329 
330 /*@
331    PCPARMSSetGlobal - Sets the global preconditioner to be used in `PCPARMS`.
332 
333    Collective
334 
335    Input Parameters:
336 +  pc - the preconditioner context
337 -  type - the global preconditioner type, one of
338 .vb
339      PC_PARMS_GLOBAL_RAS   - Restricted additive Schwarz
340      PC_PARMS_GLOBAL_SCHUR - Schur complement
341      PC_PARMS_GLOBAL_BJ    - Block Jacobi
342 .ve
343 
344    Options Database Key:
345 .   -pc_parms_global [ras,schur,bj] - Sets global preconditioner
346 
347    Level: intermediate
348 
349    Note:
350    See the pARMS function `parms_PCSetType()` for more information.
351 
352 .seealso: `PCPARMS`, `PCPARMSSetLocal()`
353 @*/
354 PetscErrorCode PCPARMSSetGlobal(PC pc, PCPARMSGlobalType type)
355 {
356   PetscFunctionBegin;
357   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
358   PetscValidLogicalCollectiveEnum(pc, type, 2);
359   PetscTryMethod(pc, "PCPARMSSetGlobal_C", (PC, PCPARMSGlobalType), (pc, type));
360   PetscFunctionReturn(PETSC_SUCCESS);
361 }
362 
363 static PetscErrorCode PCPARMSSetLocal_PARMS(PC pc, PCPARMSLocalType type)
364 {
365   PC_PARMS *parms = (PC_PARMS *)pc->data;
366 
367   PetscFunctionBegin;
368   if (type != parms->local) {
369     parms->local    = type;
370     pc->setupcalled = 0;
371   }
372   PetscFunctionReturn(PETSC_SUCCESS);
373 }
374 
375 /*@
376    PCPARMSSetLocal - Sets the local preconditioner to be used in `PCPARMS`.
377 
378    Collective
379 
380    Input Parameters:
381 +  pc - the preconditioner context
382 -  type - the local preconditioner type, one of
383 .vb
384      PC_PARMS_LOCAL_ILU0   - ILU0 preconditioner
385      PC_PARMS_LOCAL_ILUK   - ILU(k) preconditioner
386      PC_PARMS_LOCAL_ILUT   - ILUT preconditioner
387      PC_PARMS_LOCAL_ARMS   - ARMS preconditioner
388 .ve
389 
390    Options Database Keys:
391    -pc_parms_local [ilu0,iluk,ilut,arms] - Sets local preconditioner
392 
393    Level: intermediate
394 
395    Notes:
396    For the ARMS preconditioner, one can use either the symmetric ARMS or the non-symmetric
397    variant (ARMS-ddPQ) by setting the permutation type with PCPARMSSetNonsymPerm().
398 
399    See the pARMS function `parms_PCILUSetType()` for more information.
400 
401 .seealso: `PCPARMS`, `PCPARMSSetGlobal()`, `PCPARMSSetNonsymPerm()`
402 
403 @*/
404 PetscErrorCode PCPARMSSetLocal(PC pc, PCPARMSLocalType type)
405 {
406   PetscFunctionBegin;
407   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
408   PetscValidLogicalCollectiveEnum(pc, type, 2);
409   PetscTryMethod(pc, "PCPARMSSetLocal_C", (PC, PCPARMSLocalType), (pc, type));
410   PetscFunctionReturn(PETSC_SUCCESS);
411 }
412 
413 static PetscErrorCode PCPARMSSetSolveTolerances_PARMS(PC pc, PetscReal tol, PetscInt maxits)
414 {
415   PC_PARMS *parms = (PC_PARMS *)pc->data;
416 
417   PetscFunctionBegin;
418   if (tol != parms->solvetol) {
419     parms->solvetol = tol;
420     pc->setupcalled = 0;
421   }
422   if (maxits != parms->maxits) {
423     parms->maxits   = maxits;
424     pc->setupcalled = 0;
425   }
426   PetscFunctionReturn(PETSC_SUCCESS);
427 }
428 
429 /*@
430    PCPARMSSetSolveTolerances - Sets the convergence tolerance and the maximum iterations for the
431    inner GMRES solver, when the Schur global preconditioner is used.
432 
433    Collective
434 
435    Input Parameters:
436 +  pc - the preconditioner context
437 .  tol - the convergence tolerance
438 -  maxits - the maximum number of iterations to use
439 
440    Options Database Keys:
441 +  -pc_parms_solve_tol - set the tolerance for local solve
442 -  -pc_parms_max_it - set the maximum number of inner iterations
443 
444    Level: intermediate
445 
446    Note:
447    See the pARMS functions `parms_PCSetInnerEps()` and `parms_PCSetInnerMaxits()` for more information.
448 
449 .seealso: `PCPARMS`, `PCPARMSSetSolveRestart()`
450 @*/
451 PetscErrorCode PCPARMSSetSolveTolerances(PC pc, PetscReal tol, PetscInt maxits)
452 {
453   PetscFunctionBegin;
454   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
455   PetscTryMethod(pc, "PCPARMSSetSolveTolerances_C", (PC, PetscReal, PetscInt), (pc, tol, maxits));
456   PetscFunctionReturn(PETSC_SUCCESS);
457 }
458 
459 static PetscErrorCode PCPARMSSetSolveRestart_PARMS(PC pc, PetscInt restart)
460 {
461   PC_PARMS *parms = (PC_PARMS *)pc->data;
462 
463   PetscFunctionBegin;
464   if (restart != parms->maxdim) {
465     parms->maxdim   = restart;
466     pc->setupcalled = 0;
467   }
468   PetscFunctionReturn(PETSC_SUCCESS);
469 }
470 
471 /*@
472    PCPARMSSetSolveRestart - Sets the number of iterations at which the
473    inner GMRES solver restarts.
474 
475    Collective
476 
477    Input Parameters:
478 +  pc - the preconditioner context
479 -  restart - maximum dimension of the Krylov subspace
480 
481    Options Database Key:
482 .  -pc_parms_max_dim - sets the inner Krylov dimension
483 
484    Level: intermediate
485 
486    Note:
487    See the pARMS function parms_PCSetInnerKSize for more information.
488 
489 .seealso: `PCPARMS`, `PCPARMSSetSolveTolerances()`
490 @*/
491 PetscErrorCode PCPARMSSetSolveRestart(PC pc, PetscInt restart)
492 {
493   PetscFunctionBegin;
494   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
495   PetscTryMethod(pc, "PCPARMSSetSolveRestart_C", (PC, PetscInt), (pc, restart));
496   PetscFunctionReturn(PETSC_SUCCESS);
497 }
498 
499 static PetscErrorCode PCPARMSSetNonsymPerm_PARMS(PC pc, PetscBool nonsym)
500 {
501   PC_PARMS *parms = (PC_PARMS *)pc->data;
502 
503   PetscFunctionBegin;
504   if ((nonsym && !parms->nonsymperm) || (!nonsym && parms->nonsymperm)) {
505     parms->nonsymperm = nonsym;
506     pc->setupcalled   = 0;
507   }
508   PetscFunctionReturn(PETSC_SUCCESS);
509 }
510 
511 /*@
512    PCPARMSSetNonsymPerm - Sets the type of permutation for the ARMS preconditioner: the standard
513    symmetric ARMS or the non-symmetric ARMS (ARMS-ddPQ).
514 
515    Collective
516 
517    Input Parameters:
518 +  pc - the preconditioner context
519 -  nonsym - `PETSC_TRUE` indicates the non-symmetric ARMS is used;
520             `PETSC_FALSE` indicates the symmetric ARMS is used
521 
522    Options Database Key:
523 .  -pc_parms_nonsymmetric_perm - sets the use of nonsymmetric permutation
524 
525    Level: intermediate
526 
527    Note:
528    See the pARMS function `parms_PCSetPermType()` for more information.
529 
530 .seealso: `PCPARMS`
531 @*/
532 PetscErrorCode PCPARMSSetNonsymPerm(PC pc, PetscBool nonsym)
533 {
534   PetscFunctionBegin;
535   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
536   PetscTryMethod(pc, "PCPARMSSetNonsymPerm_C", (PC, PetscBool), (pc, nonsym));
537   PetscFunctionReturn(PETSC_SUCCESS);
538 }
539 
540 static PetscErrorCode PCPARMSSetFill_PARMS(PC pc, PetscInt lfil0, PetscInt lfil1, PetscInt lfil2)
541 {
542   PC_PARMS *parms = (PC_PARMS *)pc->data;
543 
544   PetscFunctionBegin;
545   if (lfil0 != parms->lfil[0] || lfil0 != parms->lfil[1] || lfil0 != parms->lfil[2] || lfil0 != parms->lfil[3]) {
546     parms->lfil[1] = parms->lfil[2] = parms->lfil[3] = parms->lfil[0] = lfil0;
547     pc->setupcalled                                                   = 0;
548   }
549   if (lfil1 != parms->lfil[4]) {
550     parms->lfil[4]  = lfil1;
551     pc->setupcalled = 0;
552   }
553   if (lfil2 != parms->lfil[5] || lfil2 != parms->lfil[6]) {
554     parms->lfil[5] = parms->lfil[6] = lfil2;
555     pc->setupcalled                 = 0;
556   }
557   PetscFunctionReturn(PETSC_SUCCESS);
558 }
559 
560 /*@
561    PCPARMSSetFill - Sets the fill-in parameters for ILUT, ILUK and ARMS preconditioners.
562    Consider the original matrix A = [B F; E C] and the approximate version
563    M = [LB 0; E/UB I]*[UB LB\F; 0 S].
564 
565    Collective
566 
567    Input Parameters:
568 +  pc - the preconditioner context
569 .  fil0 - the level of fill-in kept in LB, UB, E/UB and LB\F
570 .  fil1 - the level of fill-in kept in S
571 -  fil2 - the level of fill-in kept in the L and U parts of the LU factorization of S
572 
573    Options Database Keys:
574 +  -pc_parms_lfil_ilu_arms - set the amount of fill-in for ilut, iluk and arms
575 .  -pc_parms_lfil_schur - set the amount of fill-in for schur
576 -  -pc_parms_lfil_ilut_L_U - set the amount of fill-in for ILUT L and U
577 
578    Level: intermediate
579 
580    Note:
581    See the pARMS function `parms_PCSetFill()` for more information.
582 
583 .seealso: `PCPARMS`
584 @*/
585 PetscErrorCode PCPARMSSetFill(PC pc, PetscInt lfil0, PetscInt lfil1, PetscInt lfil2)
586 {
587   PetscFunctionBegin;
588   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
589   PetscTryMethod(pc, "PCPARMSSetFill_C", (PC, PetscInt, PetscInt, PetscInt), (pc, lfil0, lfil1, lfil2));
590   PetscFunctionReturn(PETSC_SUCCESS);
591 }
592 
593 /*MC
594    PCPARMS - Allows the use of the parallel Algebraic Recursive Multilevel Solvers
595       available in the package pARMS
596 
597    Options Database Keys:
598 +  -pc_parms_global - one of ras, schur, bj
599 .  -pc_parms_local - one of ilu0, iluk, ilut, arms
600 .  -pc_parms_solve_tol - set the tolerance for local solve
601 .  -pc_parms_levels - set the number of levels
602 .  -pc_parms_nonsymmetric_perm - set the use of nonsymmetric permutation
603 .  -pc_parms_blocksize - set the block size
604 .  -pc_parms_ind_tol - set the tolerance for independent sets
605 .  -pc_parms_max_dim - set the inner krylov dimension
606 .  -pc_parms_max_it - set the maximum number of inner iterations
607 .  -pc_parms_inter_nonsymmetric_perm - set the use of nonsymmetric permutation for interlevel blocks
608 .  -pc_parms_inter_column_perm - set the use of column permutation for interlevel blocks
609 .  -pc_parms_inter_row_scaling - set the use of row scaling for interlevel blocks
610 .  -pc_parms_inter_column_scaling - set the use of column scaling for interlevel blocks
611 .  -pc_parms_last_nonsymmetric_perm - set the use of nonsymmetric permutation for last level blocks
612 .  -pc_parms_last_column_perm - set the use of column permutation for last level blocks
613 .  -pc_parms_last_row_scaling - set the use of row scaling for last level blocks
614 .  -pc_parms_last_column_scaling - set the use of column scaling for last level blocks
615 .  -pc_parms_lfil_ilu_arms - set the amount of fill-in for ilut, iluk and arms
616 .  -pc_parms_lfil_schur - set the amount of fill-in for schur
617 .  -pc_parms_lfil_ilut_L_U - set the amount of fill-in for ILUT L and U
618 .  -pc_parms_droptol_factors - set the drop tolerance for L, U, L^{-1}F and EU^{-1}
619 .  -pc_parms_droptol_schur_compl - set the drop tolerance for schur complement at each level
620 -  -pc_parms_droptol_last_schur - set the drop tolerance for ILUT in last level schur complement
621 
622    Note:
623    Unless configured appropriately, this preconditioner performs an inexact solve
624    as part of the preconditioner application. Therefore, it must be used in combination
625    with flexible variants of iterative solvers, such as `KSPFGMRES` or `KSPGCR`.
626 
627    Level: intermediate
628 
629 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMG`, `PCGAMG`, `PCHYPRE`, `PCPARMSSetGlobal()`,
630           `PCPARMSSetLocal()`, `PCPARMSSetSolveTolerances()`, `PCPARMSSetSolveRestart()`, `PCPARMSSetNonsymPerm()`,
631           `PCPARMSSetFill()`
632 M*/
633 
634 PETSC_EXTERN PetscErrorCode PCCreate_PARMS(PC pc)
635 {
636   PC_PARMS *parms;
637 
638   PetscFunctionBegin;
639   PetscCall(PetscNew(&parms));
640 
641   parms->map        = 0;
642   parms->A          = 0;
643   parms->pc         = 0;
644   parms->global     = PC_PARMS_GLOBAL_RAS;
645   parms->local      = PC_PARMS_LOCAL_ARMS;
646   parms->levels     = 10;
647   parms->nonsymperm = PETSC_TRUE;
648   parms->blocksize  = 250;
649   parms->maxdim     = 0;
650   parms->maxits     = 0;
651   parms->meth[0]    = PETSC_FALSE;
652   parms->meth[1]    = PETSC_FALSE;
653   parms->meth[2]    = PETSC_FALSE;
654   parms->meth[3]    = PETSC_FALSE;
655   parms->meth[4]    = PETSC_FALSE;
656   parms->meth[5]    = PETSC_FALSE;
657   parms->meth[6]    = PETSC_FALSE;
658   parms->meth[7]    = PETSC_FALSE;
659   parms->solvetol   = 0.01;
660   parms->indtol     = 0.4;
661   parms->lfil[0] = parms->lfil[1] = parms->lfil[2] = parms->lfil[3] = 20;
662   parms->lfil[4] = parms->lfil[5] = parms->lfil[6] = 20;
663   parms->droptol[0] = parms->droptol[1] = parms->droptol[2] = parms->droptol[3] = 0.00001;
664   parms->droptol[4]                                                             = 0.001;
665   parms->droptol[5] = parms->droptol[6] = 0.001;
666 
667   pc->data                = parms;
668   pc->ops->destroy        = PCDestroy_PARMS;
669   pc->ops->setfromoptions = PCSetFromOptions_PARMS;
670   pc->ops->setup          = PCSetUp_PARMS;
671   pc->ops->apply          = PCApply_PARMS;
672   pc->ops->view           = PCView_PARMS;
673 
674   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetGlobal_C", PCPARMSSetGlobal_PARMS));
675   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetLocal_C", PCPARMSSetLocal_PARMS));
676   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetSolveTolerances_C", PCPARMSSetSolveTolerances_PARMS));
677   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetSolveRestart_C", PCPARMSSetSolveRestart_PARMS));
678   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetNonsymPerm_C", PCPARMSSetNonsymPerm_PARMS));
679   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPARMSSetFill_C", PCPARMSSetFill_PARMS));
680   PetscFunctionReturn(PETSC_SUCCESS);
681 }
682