Actual source code: cholesky.c

petsc-3.14.6 2021-03-30
Report Typos and Errors

  2: /*
  3:    Defines a direct factorization preconditioner for any Mat implementation
  4:    Note: this need not be consided a preconditioner since it supplies
  5:          a direct solver.
  6: */
  7: #include <../src/ksp/pc/impls/factor/factor.h>

  9: typedef struct {
 10:   PC_Factor hdr;
 11:   IS        row,col;                 /* index sets used for reordering */
 12: } PC_Cholesky;

 14: static PetscErrorCode PCSetFromOptions_Cholesky(PetscOptionItems *PetscOptionsObject,PC pc)
 15: {

 19:   PetscOptionsHead(PetscOptionsObject,"Cholesky options");
 20:   PCSetFromOptions_Factor(PetscOptionsObject,pc);
 21:   PetscOptionsTail();
 22:   return(0);
 23: }

 25: static PetscErrorCode PCSetUp_Cholesky(PC pc)
 26: {
 27:   PetscErrorCode         ierr;
 28:   PetscBool              flg;
 29:   PC_Cholesky            *dir = (PC_Cholesky*)pc->data;
 30:   MatSolverType          stype;
 31:   MatFactorError         err;

 34:   pc->failedreason = PC_NOERROR;
 35:   if (dir->hdr.reusefill && pc->setupcalled) ((PC_Factor*)dir)->info.fill = dir->hdr.actualfill;

 37:   MatSetErrorIfFailure(pc->pmat,pc->erroriffailure);
 38:   if (dir->hdr.inplace) {
 39:     if (dir->row && dir->col && (dir->row != dir->col)) {
 40:       ISDestroy(&dir->row);
 41:     }
 42:     ISDestroy(&dir->col);
 43:     /* should only get reordering if the factor matrix uses it but cannot determine because MatGetFactor() not called */
 44:     MatGetOrdering(pc->pmat,((PC_Factor*)dir)->ordering,&dir->row,&dir->col);
 45:     if (dir->col && (dir->row != dir->col)) {  /* only use row ordering for SBAIJ */
 46:       ISDestroy(&dir->col);
 47:     }
 48:     if (dir->row) {PetscLogObjectParent((PetscObject)pc,(PetscObject)dir->row);}
 49:     MatCholeskyFactor(pc->pmat,dir->row,&((PC_Factor*)dir)->info);
 50:     MatFactorGetError(pc->pmat,&err);
 51:     if (err) { /* Factor() fails */
 52:       pc->failedreason = (PCFailedReason)err;
 53:       return(0);
 54:     }

 56:     ((PC_Factor*)dir)->fact = pc->pmat;
 57:   } else {
 58:     MatInfo info;

 60:     if (!pc->setupcalled) {
 61:       PetscBool useordering;
 62:       if (!((PC_Factor*)dir)->fact) {
 63:         MatGetFactor(pc->pmat,((PC_Factor*)dir)->solvertype,MAT_FACTOR_CHOLESKY,&((PC_Factor*)dir)->fact);
 64:         PetscLogObjectParent((PetscObject)pc,(PetscObject)((PC_Factor*)dir)->fact);
 65:       }
 66:       MatFactorGetUseOrdering(((PC_Factor*)dir)->fact,&useordering);
 67:       if (useordering) {
 68:         MatGetOrdering(pc->pmat,((PC_Factor*)dir)->ordering,&dir->row,&dir->col);
 69:         /* check if dir->row == dir->col */
 70:         ISEqual(dir->row,dir->col,&flg);
 71:         if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"row and column permutations must equal");
 72:         ISDestroy(&dir->col); /* only pass one ordering into CholeskyFactor */

 74:         flg  = PETSC_FALSE;
 75:         PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_factor_nonzeros_along_diagonal",&flg,NULL);
 76:         if (flg) {
 77:           PetscReal tol = 1.e-10;
 78:           PetscOptionsGetReal(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_factor_nonzeros_along_diagonal",&tol,NULL);
 79:           MatReorderForNonzeroDiagonal(pc->pmat,tol,dir->row,dir->row);
 80:         }
 81:         PetscLogObjectParent((PetscObject)pc,(PetscObject)dir->row);
 82:       }
 83:       MatCholeskyFactorSymbolic(((PC_Factor*)dir)->fact,pc->pmat,dir->row,&((PC_Factor*)dir)->info);
 84:       MatGetInfo(((PC_Factor*)dir)->fact,MAT_LOCAL,&info);
 85:       dir->hdr.actualfill = info.fill_ratio_needed;
 86:     } else if (pc->flag != SAME_NONZERO_PATTERN) {
 87:       if (!dir->hdr.reuseordering) {
 88:         PetscBool useordering;
 89:         MatDestroy(&((PC_Factor*)dir)->fact);
 90:         MatGetFactor(pc->pmat,((PC_Factor*)dir)->solvertype,MAT_FACTOR_CHOLESKY,&((PC_Factor*)dir)->fact);
 91:         PetscLogObjectParent((PetscObject)pc,(PetscObject)((PC_Factor*)dir)->fact);
 92:         MatFactorGetUseOrdering(((PC_Factor*)dir)->fact,&useordering);
 93:         if (useordering) {
 94:           ISDestroy(&dir->row);
 95:           MatGetOrdering(pc->pmat,((PC_Factor*)dir)->ordering,&dir->row,&dir->col);
 96:           ISDestroy(&dir->col); /* only use dir->row ordering in CholeskyFactor */

 98:           flg  = PETSC_FALSE;
 99:           PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_factor_nonzeros_along_diagonal",&flg,NULL);
100:           if (flg) {
101:             PetscReal tol = 1.e-10;
102:             PetscOptionsGetReal(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_factor_nonzeros_along_diagonal",&tol,NULL);
103:             MatReorderForNonzeroDiagonal(pc->pmat,tol,dir->row,dir->row);
104:           }
105:           PetscLogObjectParent((PetscObject)pc,(PetscObject)dir->row);
106:         }
107:       }
108:       MatCholeskyFactorSymbolic(((PC_Factor*)dir)->fact,pc->pmat,dir->row,&((PC_Factor*)dir)->info);
109:       MatGetInfo(((PC_Factor*)dir)->fact,MAT_LOCAL,&info);
110:       dir->hdr.actualfill = info.fill_ratio_needed;
111:       PetscLogObjectParent((PetscObject)pc,(PetscObject)((PC_Factor*)dir)->fact);
112:     } else {
113:       MatFactorGetError(((PC_Factor*)dir)->fact,&err);
114:       if (err == MAT_FACTOR_NUMERIC_ZEROPIVOT) {
115:         MatFactorClearError(((PC_Factor*)dir)->fact);
116:         pc->failedreason = PC_NOERROR;
117:       }
118:     }
119:     MatFactorGetError(((PC_Factor*)dir)->fact,&err);
120:     if (err) { /* FactorSymbolic() fails */
121:       pc->failedreason = (PCFailedReason)err;
122:       return(0);
123:     }

125:     MatCholeskyFactorNumeric(((PC_Factor*)dir)->fact,pc->pmat,&((PC_Factor*)dir)->info);
126:     MatFactorGetError(((PC_Factor*)dir)->fact,&err);
127:     if (err) { /* FactorNumeric() fails */
128:       pc->failedreason = (PCFailedReason)err;
129:     }
130:   }

132:   PCFactorGetMatSolverType(pc,&stype);
133:   if (!stype) {
134:     MatSolverType solverpackage;
135:     MatFactorGetSolverType(((PC_Factor*)dir)->fact,&solverpackage);
136:     PCFactorSetMatSolverType(pc,solverpackage);
137:   }
138:   return(0);
139: }

141: static PetscErrorCode PCReset_Cholesky(PC pc)
142: {
143:   PC_Cholesky    *dir = (PC_Cholesky*)pc->data;

147:   if (!dir->hdr.inplace && ((PC_Factor*)dir)->fact) {MatDestroy(&((PC_Factor*)dir)->fact);}
148:   ISDestroy(&dir->row);
149:   ISDestroy(&dir->col);
150:   return(0);
151: }

153: static PetscErrorCode PCDestroy_Cholesky(PC pc)
154: {
155:   PC_Cholesky    *dir = (PC_Cholesky*)pc->data;

159:   PCReset_Cholesky(pc);
160:   PetscFree(((PC_Factor*)dir)->ordering);
161:   PetscFree(((PC_Factor*)dir)->solvertype);
162:   PetscFree(pc->data);
163:   return(0);
164: }

166: static PetscErrorCode PCApply_Cholesky(PC pc,Vec x,Vec y)
167: {
168:   PC_Cholesky    *dir = (PC_Cholesky*)pc->data;

172:   if (dir->hdr.inplace) {
173:     MatSolve(pc->pmat,x,y);
174:   } else {
175:     MatSolve(((PC_Factor*)dir)->fact,x,y);
176:   }
177:   return(0);
178: }

180: static PetscErrorCode PCMatApply_Cholesky(PC pc,Mat X,Mat Y)
181: {
182:   PC_Cholesky    *dir = (PC_Cholesky*)pc->data;

186:   if (dir->hdr.inplace) {
187:     MatMatSolve(pc->pmat,X,Y);
188:   } else {
189:     MatMatSolve(((PC_Factor*)dir)->fact,X,Y);
190:   }
191:   return(0);
192: }

194: static PetscErrorCode PCApplySymmetricLeft_Cholesky(PC pc,Vec x,Vec y)
195: {
196:   PC_Cholesky    *dir = (PC_Cholesky*)pc->data;

200:   if (dir->hdr.inplace) {
201:     MatForwardSolve(pc->pmat,x,y);
202:   } else {
203:     MatForwardSolve(((PC_Factor*)dir)->fact,x,y);
204:   }
205:   return(0);
206: }

208: static PetscErrorCode PCApplySymmetricRight_Cholesky(PC pc,Vec x,Vec y)
209: {
210:   PC_Cholesky    *dir = (PC_Cholesky*)pc->data;

214:   if (dir->hdr.inplace) {
215:     MatBackwardSolve(pc->pmat,x,y);
216:   } else {
217:     MatBackwardSolve(((PC_Factor*)dir)->fact,x,y);
218:   }
219:   return(0);
220: }

222: static PetscErrorCode PCApplyTranspose_Cholesky(PC pc,Vec x,Vec y)
223: {
224:   PC_Cholesky    *dir = (PC_Cholesky*)pc->data;

228:   if (dir->hdr.inplace) {
229:     MatSolveTranspose(pc->pmat,x,y);
230:   } else {
231:     MatSolveTranspose(((PC_Factor*)dir)->fact,x,y);
232:   }
233:   return(0);
234: }

236: /* -----------------------------------------------------------------------------------*/

238: /* -----------------------------------------------------------------------------------*/

240: /*@
241:    PCFactorSetReuseOrdering - When similar matrices are factored, this
242:    causes the ordering computed in the first factor to be used for all
243:    following factors.

245:    Logically Collective on PC

247:    Input Parameters:
248: +  pc - the preconditioner context
249: -  flag - PETSC_TRUE to reuse else PETSC_FALSE

251:    Options Database Key:
252: .  -pc_factor_reuse_ordering - Activate PCFactorSetReuseOrdering()

254:    Level: intermediate

256: .seealso: PCFactorSetReuseFill()
257: @*/
258: PetscErrorCode  PCFactorSetReuseOrdering(PC pc,PetscBool flag)
259: {

265:   PetscTryMethod(pc,"PCFactorSetReuseOrdering_C",(PC,PetscBool),(pc,flag));
266:   return(0);
267: }

269: /*MC
270:    PCCHOLESKY - Uses a direct solver, based on Cholesky factorization, as a preconditioner

272:    Options Database Keys:
273: +  -pc_factor_reuse_ordering - Activate PCFactorSetReuseOrdering()
274: .  -pc_factor_mat_solver_type - Actives PCFactorSetMatSolverType() to choose the direct solver, like superlu
275: .  -pc_factor_reuse_fill - Activates PCFactorSetReuseFill()
276: .  -pc_factor_fill <fill> - Sets fill amount
277: .  -pc_factor_in_place - Activates in-place factorization
278: -  -pc_factor_mat_ordering_type <nd,rcm,...> - Sets ordering routine

280:    Notes:
281:     Not all options work for all matrix formats

283:    Level: beginner

285:    Notes:
286:     Usually this will compute an "exact" solution in one iteration and does
287:           not need a Krylov method (i.e. you can use -ksp_type preonly, or
288:           KSPSetType(ksp,KSPPREONLY) for the Krylov method

290: .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
291:            PCILU, PCLU, PCICC, PCFactorSetReuseOrdering(), PCFactorSetReuseFill(), PCFactorGetMatrix(),
292:            PCFactorSetFill(), PCFactorSetShiftNonzero(), PCFactorSetShiftType(), PCFactorSetShiftAmount()
293:            PCFactorSetUseInPlace(), PCFactorGetUseInPlace(), PCFactorSetMatOrderingType()

295: M*/

297: PETSC_EXTERN PetscErrorCode PCCreate_Cholesky(PC pc)
298: {
300:   PC_Cholesky    *dir;

303:   PetscNewLog(pc,&dir);
304:   pc->data = (void*)dir;
305:   PCFactorInitialize(pc);

307:   ((PC_Factor*)dir)->factortype         = MAT_FACTOR_CHOLESKY;
308:   ((PC_Factor*)dir)->info.fill          = 5.0;

310:   dir->col = NULL;
311:   dir->row = NULL;

313:   /* MATORDERINGNATURAL_OR_ND allows selecting type based on matrix type sbaij or aij */
314:   PetscStrallocpy(MATORDERINGNATURAL_OR_ND,(char**)&((PC_Factor*)dir)->ordering);

316:   pc->ops->destroy             = PCDestroy_Cholesky;
317:   pc->ops->reset               = PCReset_Cholesky;
318:   pc->ops->apply               = PCApply_Cholesky;
319:   pc->ops->matapply            = PCMatApply_Cholesky;
320:   pc->ops->applysymmetricleft  = PCApplySymmetricLeft_Cholesky;
321:   pc->ops->applysymmetricright = PCApplySymmetricRight_Cholesky;
322:   pc->ops->applytranspose      = PCApplyTranspose_Cholesky;
323:   pc->ops->setup               = PCSetUp_Cholesky;
324:   pc->ops->setfromoptions      = PCSetFromOptions_Cholesky;
325:   pc->ops->view                = PCView_Factor;
326:   pc->ops->applyrichardson     = NULL;
327:   return(0);
328: }