Actual source code: lmvmimpl.c

petsc-3.12.4 2020-02-04
Report Typos and Errors
  1:  #include <../src/ksp/ksp/utils/lmvm/lmvm.h>

  3: /*------------------------------------------------------------*/

  5: PetscErrorCode MatReset_LMVM(Mat B, PetscBool destructive)
  6: {
  7:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
  8:   PetscErrorCode    ierr;

 11:   lmvm->k = -1;
 12:   lmvm->prev_set = PETSC_FALSE;
 13:   lmvm->shift = 0.0;
 14:   if (destructive && lmvm->allocated) {
 15:     MatLMVMClearJ0(B);
 16:     B->rmap->n = B->rmap->N = B->cmap->n = B->cmap->N = 0;
 17:     VecDestroyVecs(lmvm->m, &lmvm->S);
 18:     VecDestroyVecs(lmvm->m, &lmvm->Y);
 19:     VecDestroy(&lmvm->Xprev);
 20:     VecDestroy(&lmvm->Fprev);
 21:     lmvm->nupdates = 0;
 22:     lmvm->nrejects = 0;
 23:     lmvm->allocated = PETSC_FALSE;
 24:     B->preallocated = PETSC_FALSE;
 25:     B->assembled = PETSC_FALSE;
 26:   }
 27:   ++lmvm->nresets;
 28:   return(0);
 29: }

 31: /*------------------------------------------------------------*/

 33: PetscErrorCode MatAllocate_LMVM(Mat B, Vec X, Vec F)
 34: {
 35:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
 36:   PetscErrorCode    ierr;
 37:   PetscBool         same, allocate = PETSC_FALSE;
 38:   PetscInt          m, n, M, N;
 39:   VecType           type;

 42:   if (lmvm->allocated) {
 43:     VecCheckMatCompatible(B, X, 2, F, 3);
 44:     VecGetType(X, &type);
 45:     PetscObjectTypeCompare((PetscObject)lmvm->Xprev, type, &same);
 46:     if (!same) {
 47:       /* Given X vector has a different type than allocated X-type data structures.
 48:          We need to destroy all of this and duplicate again out of the given vector. */
 49:       allocate = PETSC_TRUE;
 50:       MatLMVMReset(B, PETSC_TRUE);
 51:     }
 52:   } else {
 53:     allocate = PETSC_TRUE;
 54:   }
 55:   if (allocate) {
 56:     VecGetLocalSize(X, &n);
 57:     VecGetSize(X, &N);
 58:     VecGetLocalSize(F, &m);
 59:     VecGetSize(F, &M);
 60:     MatSetSizes(B, m, n, M, N);
 61:     PetscLayoutSetUp(B->rmap);
 62:     PetscLayoutSetUp(B->cmap);
 63:     VecDuplicate(X, &lmvm->Xprev);
 64:     VecDuplicate(F, &lmvm->Fprev);
 65:     if (lmvm->m > 0) {
 66:       VecDuplicateVecs(lmvm->Xprev, lmvm->m, &lmvm->S);
 67:       VecDuplicateVecs(lmvm->Fprev, lmvm->m, &lmvm->Y);
 68:     }
 69:     lmvm->allocated = PETSC_TRUE;
 70:     B->preallocated = PETSC_TRUE;
 71:     B->assembled = PETSC_TRUE;
 72:   }
 73:   return(0);
 74: }

 76: /*------------------------------------------------------------*/

 78: PetscErrorCode MatUpdateKernel_LMVM(Mat B, Vec S, Vec Y)
 79: {
 80:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
 81:   PetscErrorCode    ierr;
 82:   PetscInt          i;
 83:   Vec               Stmp, Ytmp;

 86:   if (lmvm->k == lmvm->m-1) {
 87:     /* We hit the memory limit, so shift all the vectors back one spot 
 88:        and shift the oldest to the front to receive the latest update. */
 89:     Stmp = lmvm->S[0];
 90:     Ytmp = lmvm->Y[0];
 91:     for (i = 0; i < lmvm->k; ++i) {
 92:       lmvm->S[i] = lmvm->S[i+1];
 93:       lmvm->Y[i] = lmvm->Y[i+1];
 94:     }
 95:     lmvm->S[lmvm->k] = Stmp;
 96:     lmvm->Y[lmvm->k] = Ytmp;
 97:   } else {
 98:     ++lmvm->k;
 99:   }
100:   /* Put the precomputed update into the last vector */
101:   VecCopy(S, lmvm->S[lmvm->k]);
102:   VecCopy(Y, lmvm->Y[lmvm->k]);
103:   ++lmvm->nupdates;
104:   return(0);
105: }

107: /*------------------------------------------------------------*/

109: PetscErrorCode MatUpdate_LMVM(Mat B, Vec X, Vec F)
110: {
111:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
112:   PetscErrorCode    ierr;

115:   if (!lmvm->m) return(0);
116:   if (lmvm->prev_set) {
117:     /* Compute the new (S = X - Xprev) and (Y = F - Fprev) vectors */
118:     VecAXPBY(lmvm->Xprev, 1.0, -1.0, X);
119:     VecAXPBY(lmvm->Fprev, 1.0, -1.0, F);
120:     /* Update S and Y */
121:     MatUpdateKernel_LMVM(B, lmvm->Xprev, lmvm->Fprev);
122:   }

124:   /* Save the solution and function to be used in the next update */
125:   VecCopy(X, lmvm->Xprev);
126:   VecCopy(F, lmvm->Fprev);
127:   lmvm->prev_set = PETSC_TRUE;
128:   return(0);
129: }

131: /*------------------------------------------------------------*/

133: static PetscErrorCode MatMultAdd_LMVM(Mat B, Vec X, Vec Y, Vec Z)
134: {
135:   PetscErrorCode    ierr;

138:   MatMult(B, X, Z);
139:   VecAXPY(Z, 1.0, Y);
140:   return(0);
141: }

143: /*------------------------------------------------------------*/

145: static PetscErrorCode MatMult_LMVM(Mat B, Vec X, Vec Y)
146: {
147:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
148:   PetscErrorCode    ierr;

151:   VecCheckSameSize(X, 2, Y, 3);
152:   VecCheckMatCompatible(B, X, 2, Y, 3);
153:   if (!lmvm->allocated) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ORDER, "LMVM matrix must be allocated first");
154:   (*lmvm->ops->mult)(B, X, Y);
155:   if (lmvm->shift != 0.0) {
156:     VecAXPY(Y, lmvm->shift, X);
157:   }
158:   return(0);
159: }

161: /*------------------------------------------------------------*/

163: static PetscErrorCode MatCopy_LMVM(Mat B, Mat M, MatStructure str)
164: {
165:   Mat_LMVM          *bctx = (Mat_LMVM*)B->data;
166:   Mat_LMVM          *mctx;
167:   PetscErrorCode    ierr;
168:   PetscInt          i;
169:   PetscBool         allocatedM;

172:   if (str == DIFFERENT_NONZERO_PATTERN) {
173:     MatLMVMReset(M, PETSC_TRUE);
174:     MatLMVMAllocate(M, bctx->Xprev, bctx->Fprev);
175:   } else {
176:     MatLMVMIsAllocated(M, &allocatedM);
177:     if (!allocatedM) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Target matrix must be allocated first");
178:     MatCheckSameSize(B, 1, M, 2);
179:   }
180: 
181:   mctx = (Mat_LMVM*)M->data;
182:   if (bctx->user_pc) {
183:     MatLMVMSetJ0PC(M, bctx->J0pc);
184:   } else if (bctx->user_ksp) {
185:     MatLMVMSetJ0KSP(M, bctx->J0ksp);
186:   } else if (bctx->J0) {
187:     MatLMVMSetJ0(M, bctx->J0);
188:   } else if (bctx->user_scale) {
189:     if (bctx->J0diag) {
190:       MatLMVMSetJ0Diag(M, bctx->J0diag);
191:     } else {
192:       MatLMVMSetJ0Scale(M, bctx->J0scalar);
193:     }
194:   }
195:   mctx->nupdates = bctx->nupdates;
196:   mctx->nrejects = bctx->nrejects;
197:   mctx->k = bctx->k;
198:   for (i=0; i<=bctx->k; ++i) {
199:     VecCopy(bctx->S[i], mctx->S[i]);
200:     VecCopy(bctx->Y[i], mctx->Y[i]);
201:     VecCopy(bctx->Xprev, mctx->Xprev);
202:     VecCopy(bctx->Fprev, mctx->Fprev);
203:   }
204:   if (bctx->ops->copy) {
205:     (*bctx->ops->copy)(B, M, str);
206:   }
207:   return(0);
208: }

210: /*------------------------------------------------------------*/

212: static PetscErrorCode MatDuplicate_LMVM(Mat B, MatDuplicateOption op, Mat *mat)
213: {
214:   Mat_LMVM          *bctx = (Mat_LMVM*)B->data;
215:   Mat_LMVM          *mctx;
216:   PetscErrorCode    ierr;
217:   MatType           lmvmType;
218:   Mat               A;

221:   MatGetType(B, &lmvmType);
222:   MatCreate(PetscObjectComm((PetscObject)B), mat);
223:   MatSetType(*mat, lmvmType);

225:   A = *mat;
226:   mctx = (Mat_LMVM*)A->data;
227:   mctx->m = bctx->m;
228:   mctx->ksp_max_it = bctx->ksp_max_it;
229:   mctx->ksp_rtol = bctx->ksp_rtol;
230:   mctx->ksp_atol = bctx->ksp_atol;
231:   mctx->shift = bctx->shift;
232:   KSPSetTolerances(mctx->J0ksp, mctx->ksp_rtol, mctx->ksp_atol, PETSC_DEFAULT, mctx->ksp_max_it);

234:   MatLMVMAllocate(*mat, bctx->Xprev, bctx->Fprev);
235:   if (op == MAT_COPY_VALUES) {
236:     MatCopy(B, *mat, SAME_NONZERO_PATTERN);
237:   }
238:   return(0);
239: }

241: /*------------------------------------------------------------*/

243: static PetscErrorCode MatShift_LMVM(Mat B, PetscScalar a)
244: {
245:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;

248:   if (!lmvm->allocated) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ORDER, "LMVM matrix must be allocated first");
249:   lmvm->shift += PetscRealPart(a);
250:   return(0);
251: }

253: /*------------------------------------------------------------*/

255: static PetscErrorCode MatGetVecs_LMVM(Mat B, Vec *L, Vec *R)
256: {
257:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
258:   PetscErrorCode    ierr;
259: 
261:   if (!lmvm->allocated) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ORDER, "LMVM matrix must be allocated first");
262:   VecDuplicate(lmvm->Xprev, L);
263:   VecDuplicate(lmvm->Fprev, R);
264:   return(0);
265: }

267: /*------------------------------------------------------------*/

269: PetscErrorCode MatView_LMVM(Mat B, PetscViewer pv)
270: {
271:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
272:   PetscErrorCode    ierr;
273:   PetscBool         isascii;
274:   MatType           type;

277:   PetscObjectTypeCompare((PetscObject)pv,PETSCVIEWERASCII,&isascii);
278:   if (isascii) {
279:     MatGetType(B, &type);
280:     PetscViewerASCIIPrintf(pv,"Max. storage: %D\n",lmvm->m);
281:     PetscViewerASCIIPrintf(pv,"Used storage: %D\n",lmvm->k+1);
282:     PetscViewerASCIIPrintf(pv,"Number of updates: %D\n",lmvm->nupdates);
283:     PetscViewerASCIIPrintf(pv,"Number of rejects: %D\n",lmvm->nrejects);
284:     PetscViewerASCIIPrintf(pv,"Number of resets: %D\n",lmvm->nresets);
285:     if (lmvm->J0) {
286:       PetscViewerASCIIPrintf(pv,"J0 Matrix:\n");
287:       PetscViewerPushFormat(pv, PETSC_VIEWER_ASCII_INFO);
288:       MatView(lmvm->J0, pv);
289:       PetscViewerPopFormat(pv);
290:     }
291:   }
292:   return(0);
293: }

295: /*------------------------------------------------------------*/

297: PetscErrorCode MatSetFromOptions_LMVM(PetscOptionItems *PetscOptionsObject, Mat B)
298: {
299:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
300:   PetscErrorCode    ierr;

303:   PetscOptionsHead(PetscOptionsObject,"Limited-memory Variable Metric matrix for approximating Jacobians");
304:   PetscOptionsInt("-mat_lmvm_num_vecs","number of correction vectors kept in memory for the approximation","",lmvm->m,&lmvm->m,NULL);
305:   PetscOptionsInt("-mat_lmvm_ksp_its","(developer) fixed number of KSP iterations to take when inverting J0","",lmvm->ksp_max_it,&lmvm->ksp_max_it,NULL);
306:   PetscOptionsReal("-mat_lmvm_eps","(developer) machine zero definition","",lmvm->eps,&lmvm->eps,NULL);
307:   PetscOptionsTail();
308:   KSPSetFromOptions(lmvm->J0ksp);
309:   return(0);
310: }

312: /*------------------------------------------------------------*/

314: PetscErrorCode MatSetUp_LMVM(Mat B)
315: {
316:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
317:   PetscErrorCode    ierr;
318:   PetscInt          m, n, M, N;
319:   PetscMPIInt       size;
320:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);
321: 
323:   MatGetSize(B, &M, &N);
324:   if (M == 0 && N == 0) SETERRQ(comm, PETSC_ERR_ORDER, "MatSetSizes() must be called before MatSetUp()");
325:   if (!lmvm->allocated) {
326:     MPI_Comm_size(comm, &size);
327:     if (size == 1) {
328:       VecCreateSeq(comm, N, &lmvm->Xprev);
329:       VecCreateSeq(comm, M, &lmvm->Fprev);
330:     } else {
331:       MatGetLocalSize(B, &m, &n);
332:       VecCreateMPI(comm, n, N, &lmvm->Xprev);
333:       VecCreateMPI(comm, m, M, &lmvm->Fprev);
334:     }
335:     if (lmvm->m > 0) {
336:       VecDuplicateVecs(lmvm->Xprev, lmvm->m, &lmvm->S);
337:       VecDuplicateVecs(lmvm->Fprev, lmvm->m, &lmvm->Y);
338:     }
339:     lmvm->allocated = PETSC_TRUE;
340:     B->preallocated = PETSC_TRUE;
341:     B->assembled = PETSC_TRUE;
342:   }
343:   return(0);
344: }

346: /*------------------------------------------------------------*/

348: PetscErrorCode MatDestroy_LMVM(Mat B)
349: {
350:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
351:   PetscErrorCode    ierr;

354:   if (lmvm->allocated) {
355:     VecDestroyVecs(lmvm->m, &lmvm->S);
356:     VecDestroyVecs(lmvm->m, &lmvm->Y);
357:     VecDestroy(&lmvm->Xprev);
358:     VecDestroy(&lmvm->Fprev);
359:   }
360:   KSPDestroy(&lmvm->J0ksp);
361:   MatLMVMClearJ0(B);
362:   PetscFree(B->data);
363:   return(0);
364: }

366: /*------------------------------------------------------------*/

368: PetscErrorCode MatCreate_LMVM(Mat B)
369: {
370:   Mat_LMVM          *lmvm;
371:   PetscErrorCode    ierr;

374:   PetscNewLog(B, &lmvm);
375:   B->data = (void*)lmvm;
376: 
377:   lmvm->m = 5;
378:   lmvm->k = -1;
379:   lmvm->nupdates = 0;
380:   lmvm->nrejects = 0;
381:   lmvm->nresets = 0;
382: 
383:   lmvm->ksp_max_it = 20;
384:   lmvm->ksp_rtol = 0.0;
385:   lmvm->ksp_atol = 0.0;
386: 
387:   lmvm->shift = 0.0;
388: 
389:   lmvm->eps = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0);
390:   lmvm->allocated = PETSC_FALSE;
391:   lmvm->prev_set = PETSC_FALSE;
392:   lmvm->user_scale = PETSC_FALSE;
393:   lmvm->user_pc = PETSC_FALSE;
394:   lmvm->user_ksp = PETSC_FALSE;
395:   lmvm->square = PETSC_FALSE;
396: 
397:   B->ops->destroy = MatDestroy_LMVM;
398:   B->ops->setfromoptions = MatSetFromOptions_LMVM;
399:   B->ops->view = MatView_LMVM;
400:   B->ops->setup = MatSetUp_LMVM;
401:   B->ops->getvecs = MatGetVecs_LMVM;
402:   B->ops->shift = MatShift_LMVM;
403:   B->ops->duplicate = MatDuplicate_LMVM;
404:   B->ops->mult = MatMult_LMVM;
405:   B->ops->multadd = MatMultAdd_LMVM;
406:   B->ops->copy = MatCopy_LMVM;
407: 
408:   lmvm->ops->update = MatUpdate_LMVM;
409:   lmvm->ops->allocate = MatAllocate_LMVM;
410:   lmvm->ops->reset = MatReset_LMVM;
411: 
412:   KSPCreate(PetscObjectComm((PetscObject)B), &lmvm->J0ksp);
413:   PetscObjectIncrementTabLevel((PetscObject)lmvm->J0ksp, (PetscObject)B, 1);
414:   KSPSetOptionsPrefix(lmvm->J0ksp, "mat_lmvm_");
415:   KSPSetType(lmvm->J0ksp, KSPGMRES);
416:   KSPSetTolerances(lmvm->J0ksp, lmvm->ksp_rtol, lmvm->ksp_atol, PETSC_DEFAULT, lmvm->ksp_max_it);
417:   return(0);
418: }