Actual source code: parms.c

  1: #define PETSCKSP_DLL

  3: /*
  4:    Provides an interface to pARMS.
  5:    Requires pARMS 3.2 or later.
  6: */

  8: #include <petsc/private/pcimpl.h>

 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>

 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;

 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;

 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));

 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;

 67:   for (i = 0; i < npro + 1; i++) mapptr[i] = mapptr0[i] + 1;
 68:   for (i = 0; i < n; i++) maptmp[i] = i + 1;

 70:   /* if created, destroy the previous map */
 71:   if (parms->map) {
 72:     parms_MapFree(&parms->map);
 73:     parms->map = NULL;
 74:   }

 76:   /* create pARMS map object */
 77:   parms_MapCreateFromPtr(&parms->map, (int)n, maptmp, mapptr, PetscObjectComm((PetscObject)pmat), 1, NONINTERLACED);

 79:   /* if created, destroy the previous pARMS matrix */
 80:   if (parms->A) {
 81:     parms_MatFree(&parms->A);
 82:     parms->A = NULL;
 83:   }

 85:   /* create pARMS mat object */
 86:   parms_MatCreate(&parms->A, parms->map);

 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));

 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;

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:   }

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));

121:   /* 1-based indexing */
122:   for (i = 0; i < ia[lsize] - 1; i++) ja[i] = ja[i] + 1;

124:   /* Now copy csr matrix to parms_mat object */
125:   parms_MatSetValues(parms->A, (int)lsize, im, ia, ja, aa, INSERT);

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));

135:   /* setup parms matrix */
136:   parms_MatSetup(parms->A);

138:   /* if created, destroy the previous pARMS pc */
139:   if (parms->pc) {
140:     parms_PCFree(&parms->pc);
141:     parms->pc = NULL;
142:   }

144:   /* Now create pARMS preconditioner object based on A */
145:   parms_PCCreate(&parms->pc, parms->A);

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);

186:   parms_PCSetup(parms->pc);

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: }

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;

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: }

237: static PetscErrorCode PCDestroy_PARMS(PC pc)
238: {
239:   PC_PARMS *parms = (PC_PARMS *)pc->data;

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));

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: }

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;

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: }

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;

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: }

318: static PetscErrorCode PCPARMSSetGlobal_PARMS(PC pc, PCPARMSGlobalType type)
319: {
320:   PC_PARMS *parms = (PC_PARMS *)pc->data;

322:   PetscFunctionBegin;
323:   if (type != parms->global) {
324:     parms->global   = type;
325:     pc->setupcalled = 0;
326:   }
327:   PetscFunctionReturn(PETSC_SUCCESS);
328: }

330: /*@
331:   PCPARMSSetGlobal - Sets the global preconditioner to be used in `PCPARMS`.

333:   Collective

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

344:   Options Database Key:
345: . -pc_parms_global [ras,schur,bj] - Sets global preconditioner

347:   Level: intermediate

349:   Note:
350:   See the pARMS function `parms_PCSetType()` for more information.

352: .seealso: [](ch_ksp), `PCPARMS`, `PCPARMSSetLocal()`
353: @*/
354: PetscErrorCode PCPARMSSetGlobal(PC pc, PCPARMSGlobalType type)
355: {
356:   PetscFunctionBegin;
359:   PetscTryMethod(pc, "PCPARMSSetGlobal_C", (PC, PCPARMSGlobalType), (pc, type));
360:   PetscFunctionReturn(PETSC_SUCCESS);
361: }

363: static PetscErrorCode PCPARMSSetLocal_PARMS(PC pc, PCPARMSLocalType type)
364: {
365:   PC_PARMS *parms = (PC_PARMS *)pc->data;

367:   PetscFunctionBegin;
368:   if (type != parms->local) {
369:     parms->local    = type;
370:     pc->setupcalled = 0;
371:   }
372:   PetscFunctionReturn(PETSC_SUCCESS);
373: }

375: /*@
376:   PCPARMSSetLocal - Sets the local preconditioner to be used in `PCPARMS`.

378:   Collective

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

390:   Options Database Keys:
391: . pc_parms_local [ilu0,iluk,ilut,arms] - Sets local preconditioner

393:   Level: intermediate

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().

399:   See the pARMS function `parms_PCILUSetType()` for more information.

401: .seealso: [](ch_ksp), `PCPARMS`, `PCPARMSSetGlobal()`, `PCPARMSSetNonsymPerm()`

403: @*/
404: PetscErrorCode PCPARMSSetLocal(PC pc, PCPARMSLocalType type)
405: {
406:   PetscFunctionBegin;
409:   PetscTryMethod(pc, "PCPARMSSetLocal_C", (PC, PCPARMSLocalType), (pc, type));
410:   PetscFunctionReturn(PETSC_SUCCESS);
411: }

413: static PetscErrorCode PCPARMSSetSolveTolerances_PARMS(PC pc, PetscReal tol, PetscInt maxits)
414: {
415:   PC_PARMS *parms = (PC_PARMS *)pc->data;

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: }

429: /*@
430:   PCPARMSSetSolveTolerances - Sets the convergence tolerance and the maximum iterations for the
431:   inner GMRES solver, when the Schur global preconditioner is used.

433:   Collective

435:   Input Parameters:
436: + pc     - the preconditioner context
437: . tol    - the convergence tolerance
438: - maxits - the maximum number of iterations to use

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

444:   Level: intermediate

446:   Note:
447:   See the pARMS functions `parms_PCSetInnerEps()` and `parms_PCSetInnerMaxits()` for more information.

449: .seealso: [](ch_ksp), `PCPARMS`, `PCPARMSSetSolveRestart()`
450: @*/
451: PetscErrorCode PCPARMSSetSolveTolerances(PC pc, PetscReal tol, PetscInt maxits)
452: {
453:   PetscFunctionBegin;
455:   PetscTryMethod(pc, "PCPARMSSetSolveTolerances_C", (PC, PetscReal, PetscInt), (pc, tol, maxits));
456:   PetscFunctionReturn(PETSC_SUCCESS);
457: }

459: static PetscErrorCode PCPARMSSetSolveRestart_PARMS(PC pc, PetscInt restart)
460: {
461:   PC_PARMS *parms = (PC_PARMS *)pc->data;

463:   PetscFunctionBegin;
464:   if (restart != parms->maxdim) {
465:     parms->maxdim   = restart;
466:     pc->setupcalled = 0;
467:   }
468:   PetscFunctionReturn(PETSC_SUCCESS);
469: }

471: /*@
472:   PCPARMSSetSolveRestart - Sets the number of iterations at which the
473:   inner GMRES solver restarts.

475:   Collective

477:   Input Parameters:
478: + pc      - the preconditioner context
479: - restart - maximum dimension of the Krylov subspace

481:   Options Database Key:
482: . -pc_parms_max_dim - sets the inner Krylov dimension

484:   Level: intermediate

486:   Note:
487:   See the pARMS function parms_PCSetInnerKSize for more information.

489: .seealso: [](ch_ksp), `PCPARMS`, `PCPARMSSetSolveTolerances()`
490: @*/
491: PetscErrorCode PCPARMSSetSolveRestart(PC pc, PetscInt restart)
492: {
493:   PetscFunctionBegin;
495:   PetscTryMethod(pc, "PCPARMSSetSolveRestart_C", (PC, PetscInt), (pc, restart));
496:   PetscFunctionReturn(PETSC_SUCCESS);
497: }

499: static PetscErrorCode PCPARMSSetNonsymPerm_PARMS(PC pc, PetscBool nonsym)
500: {
501:   PC_PARMS *parms = (PC_PARMS *)pc->data;

503:   PetscFunctionBegin;
504:   if ((nonsym && !parms->nonsymperm) || (!nonsym && parms->nonsymperm)) {
505:     parms->nonsymperm = nonsym;
506:     pc->setupcalled   = 0;
507:   }
508:   PetscFunctionReturn(PETSC_SUCCESS);
509: }

511: /*@
512:   PCPARMSSetNonsymPerm - Sets the type of permutation for the ARMS preconditioner: the standard
513:   symmetric ARMS or the non-symmetric ARMS (ARMS-ddPQ).

515:   Collective

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

522:   Options Database Key:
523: . -pc_parms_nonsymmetric_perm - sets the use of nonsymmetric permutation

525:   Level: intermediate

527:   Note:
528:   See the pARMS function `parms_PCSetPermType()` for more information.

530: .seealso: [](ch_ksp), `PCPARMS`
531: @*/
532: PetscErrorCode PCPARMSSetNonsymPerm(PC pc, PetscBool nonsym)
533: {
534:   PetscFunctionBegin;
536:   PetscTryMethod(pc, "PCPARMSSetNonsymPerm_C", (PC, PetscBool), (pc, nonsym));
537:   PetscFunctionReturn(PETSC_SUCCESS);
538: }

540: static PetscErrorCode PCPARMSSetFill_PARMS(PC pc, PetscInt lfil0, PetscInt lfil1, PetscInt lfil2)
541: {
542:   PC_PARMS *parms = (PC_PARMS *)pc->data;

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: }

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].

565:   Collective

567:   Input Parameters:
568: + pc    - the preconditioner context
569: . lfil0 - the level of fill-in kept in LB, UB, E/UB and LB\F
570: . lfil1 - the level of fill-in kept in S
571: - lfil2 - the level of fill-in kept in the L and U parts of the LU factorization of S

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

578:   Level: intermediate

580:   Note:
581:   See the pARMS function `parms_PCSetFill()` for more information.

583: .seealso: [](ch_ksp), `PCPARMS`
584: @*/
585: PetscErrorCode PCPARMSSetFill(PC pc, PetscInt lfil0, PetscInt lfil1, PetscInt lfil2)
586: {
587:   PetscFunctionBegin;
589:   PetscTryMethod(pc, "PCPARMSSetFill_C", (PC, PetscInt, PetscInt, PetscInt), (pc, lfil0, lfil1, lfil2));
590:   PetscFunctionReturn(PETSC_SUCCESS);
591: }

593: /*MC
594:    PCPARMS - Allows the use of the parallel Algebraic Recursive Multilevel Solvers
595:       available in the package pARMS

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

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`.

627:    Level: intermediate

629: .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCMG`, `PCGAMG`, `PCHYPRE`, `PCPARMSSetGlobal()`,
630:           `PCPARMSSetLocal()`, `PCPARMSSetSolveTolerances()`, `PCPARMSSetSolveRestart()`, `PCPARMSSetNonsymPerm()`,
631:           `PCPARMSSetFill()`
632: M*/

634: PETSC_EXTERN PetscErrorCode PCCreate_PARMS(PC pc)
635: {
636:   PC_PARMS *parms;

638:   PetscFunctionBegin;
639:   PetscCall(PetscNew(&parms));

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;

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;

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: }