Actual source code: lmvmimpl.c
petsc-3.12.2 2019-11-22
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: }