Actual source code: picard.c
1: #define PETSCSNES_DLL
3: #include ../src/snes/impls/picard/picard.h
5: /*
6: SNESDestroy_Picard - Destroys the private SNES_Picard context that was created with SNESCreate_Picard().
8: Input Parameter:
9: . snes - the SNES context
11: Application Interface Routine: SNESDestroy()
12: */
15: PetscErrorCode SNESDestroy_Picard(SNES snes)
16: {
20: if (snes->vec_sol_update) {
21: VecDestroy(snes->vec_sol_update);
22: snes->vec_sol_update = PETSC_NULL;
23: }
24: if (snes->nwork) {
25: VecDestroyVecs(snes->work, snes->nwork);
26: snes->nwork = 0;
27: snes->work = PETSC_NULL;
28: }
29: PetscFree(snes->data);
30: return(0);
31: }
33: /*
34: SNESSetUp_Picard - Sets up the internal data structures for the later use
35: of the SNESPICARD nonlinear solver.
37: Input Parameters:
38: + snes - the SNES context
39: - x - the solution vector
41: Application Interface Routine: SNESSetUp()
42: */
45: PetscErrorCode SNESSetUp_Picard(SNES snes)
46: {
50: if (!snes->vec_sol_update) {
51: VecDuplicate(snes->vec_sol, &snes->vec_sol_update);
52: PetscLogObjectParent(snes, snes->vec_sol_update);
53: }
54: if (!snes->work) {
55: snes->nwork = 1;
56: VecDuplicateVecs(snes->vec_sol, snes->nwork, &snes->work);
57: PetscLogObjectParents(snes,snes->nwork, snes->work);
58: }
59: return(0);
60: }
62: PetscErrorCode PicardLineSearchQuadratic(SNES snes, void *lsctx, Vec X, Vec F, Vec dummyG, Vec Y, Vec dummyW, PetscReal fnorm, PetscReal dummyXnorm, PetscReal *dummyYnorm, PetscReal *gnorm, PetscTruth *flag);
63: /*
64: SNESSetFromOptions_Picard - Sets various parameters for the SNESLS method.
66: Input Parameter:
67: . snes - the SNES context
69: Application Interface Routine: SNESSetFromOptions()
70: */
73: static PetscErrorCode SNESSetFromOptions_Picard(SNES snes)
74: {
75: SNES_Picard *ls = (SNES_Picard *)snes->data;
76: const char *types[] = {"basic", "quadratic", "cubic"};
77: PetscInt indx = 0;
78: PetscTruth flg;
82: PetscOptionsHead("SNES Picard options");
83: PetscOptionsEList("-snes_picard","Picard Type","SNESLineSearchSet",types,3,"basic",&indx,&flg);
84: ls->type = indx;
85: if (flg) {
86: switch (indx) {
87: case 0:
88: SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);
89: break;
90: case 1:
91: SNESLineSearchSet(snes,PicardLineSearchQuadratic,PETSC_NULL);
92: break;
93: case 2:
94: SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);
95: break;
96: }
97: }
98: ls->alpha = 1.0;
99: PetscOptionsReal("-snes_picard_alpha","Momentum parameter","SNES",ls->alpha,&ls->alpha,&flg);
100: PetscOptionsTail();
101: return(0);
102: }
104: /*
105: SNESView_Picard - Prints info from the SNESPICARD data structure.
107: Input Parameters:
108: + SNES - the SNES context
109: - viewer - visualization context
111: Application Interface Routine: SNESView()
112: */
115: static PetscErrorCode SNESView_Picard(SNES snes, PetscViewer viewer)
116: {
117: SNES_Picard *ls = (SNES_Picard *)snes->data;
118: const char *cstr;
119: PetscTruth iascii;
123: PetscTypeCompare((PetscObject) viewer, PETSC_VIEWER_ASCII, &iascii);
124: if (iascii) {
125: switch(ls->type) {
126: case 0:
127: cstr = "basic";
128: break;
129: default:
130: cstr = "unknown";
131: }
132: PetscViewerASCIIPrintf(viewer," picard variant: %s\n", cstr);
133: } else {
134: SETERRQ1(PETSC_ERR_SUP, "Viewer type %s not supported for SNES Picard", ((PetscObject)viewer)->type_name);
135: }
136: return(0);
137: }
141: PetscErrorCode PicardLineSearchQuadratic(SNES snes, void *lsctx, Vec X, Vec F, Vec dummyG, Vec Y, Vec W, PetscReal fnorm, PetscReal dummyXnorm, PetscReal *dummyYnorm, PetscReal *gnorm, PetscTruth *flag)
142: {
143: PetscInt i;
144: PetscReal alphas[3] = {0.0, 0.5, 1.0};
145: PetscReal norms[3];
146: PetscReal alpha,a,b;
150: norms[0] = fnorm;
151: /* Calculate trial solutions */
152: for(i = 1; i < 3; ++i) {
153: /* Calculate X^{n+1} = (1 - \alpha) X^n + \alpha Y */
154: VecCopy(X, W);
155: VecAXPBY(W, alphas[i], 1 - alphas[i], Y);
156: SNESComputeFunction(snes, W, F);
157: VecNorm(F, NORM_2, &norms[i]);
158: }
159: for(i = 0; i < 3; ++i) {
160: norms[i] = PetscSqr(norms[i]);
161: }
162: /* Fit a quadratic:
163: If we have x_{0,1,2} = 0, x_1, x_2 which generate norms y_{0,1,2}
164: a = (x_1 y_2 - x_2 y_1 + (x_2 - x_1) y_0)/(x^2_2 x_1 - x_2 x^2_1)
165: b = (x^2_1 y_2 - x^2_2 y_1 + (x^2_2 - x^2_1) y_0)/(x_2 x^2_1 - x^2_2 x_1)
166: c = y_0
167: x_min = -b/2a
169: If we let x_{0,1,2} = 0, 0.5, 1.0
170: a = 2 y_2 - 4 y_1 + 2 y_0
171: b = -y_2 + 4 y_1 - 3 y_0
172: c = y_0
173: */
174: a = (alphas[1]*norms[2] - alphas[2]*norms[1] + (alphas[2] - alphas[1])*norms[0])/
175: (PetscSqr(alphas[2])*alphas[1] - alphas[2]*PetscSqr(alphas[1]));
176: b = (PetscSqr(alphas[1])*norms[2] - PetscSqr(alphas[2])*norms[1] + (PetscSqr(alphas[2]) - PetscSqr(alphas[1]))*norms[0])/
177: (alphas[2]*PetscSqr(alphas[1]) - PetscSqr(alphas[2])*alphas[1]);
178: /* Check for positive a (concave up) */
179: if (a >= 0.0) {
180: alpha = -b/(2.0*a);
181: alpha = PetscMin(alpha, alphas[2]);
182: alpha = PetscMax(alpha, alphas[0]);
183: } else {
184: alpha = 1.0;
185: }
186: PetscPrintf(snes->hdr.comm, "norms[0] = %g, norms[1] = %g, norms[2] = %g\n", sqrt(norms[0]), sqrt(norms[1]), sqrt(norms[2]));
187: PetscPrintf(snes->hdr.comm, "Choose alpha = %g\n", alpha);
188: VecAXPBY(X, alpha, 1 - alpha, Y);
189: SNESComputeFunction(snes, X, F);
190: VecNorm(F, NORM_2, gnorm);
191: *flag = PETSC_TRUE;
192: return(0);
193: }
195: /*
196: SNESSolve_Picard - Solves a nonlinear system with the Picard method.
198: Input Parameters:
199: . snes - the SNES context
201: Output Parameter:
202: . outits - number of iterations until termination
204: Application Interface Routine: SNESSolve()
205: */
208: PetscErrorCode SNESSolve_Picard(SNES snes)
209: {
210: SNES_Picard *neP = (SNES_Picard *) snes->data;
211: Vec X, Y, F, W;
212: PetscReal alpha = neP->alpha;
213: PetscReal fnorm;
214: PetscInt maxits, i;
218: snes->reason = SNES_CONVERGED_ITERATING;
220: maxits = snes->max_its; /* maximum number of iterations */
221: X = snes->vec_sol; /* X^n */
222: Y = snes->vec_sol_update; /* \tilde X */
223: F = snes->vec_func; /* residual vector */
224: W = snes->work[0]; /* work vector */
226: PetscObjectTakeAccess(snes);
227: snes->iter = 0;
228: snes->norm = 0;
229: PetscObjectGrantAccess(snes);
230: SNESComputeFunction(snes,X,F);
231: if (snes->domainerror) {
232: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
233: return(0);
234: }
235: VecNorm(F, NORM_2, &fnorm); /* fnorm <- ||F|| */
236: if PetscIsInfOrNanReal(fnorm) SETERRQ(PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
237: PetscObjectTakeAccess(snes);
238: snes->norm = fnorm;
239: PetscObjectGrantAccess(snes);
240: SNESLogConvHistory(snes,fnorm,0);
241: SNESMonitor(snes,0,fnorm);
243: /* set parameter for default relative tolerance convergence test */
244: snes->ttol = fnorm*snes->rtol;
245: /* test convergence */
246: (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
247: if (snes->reason) return(0);
249: for(i = 0; i < maxits; i++) {
250: PetscTruth lsSuccess = PETSC_TRUE;
252: /* Call general purpose update function */
253: if (snes->ops->update) {
254: (*snes->ops->update)(snes, snes->iter);
255: }
256: if (neP->type == 0) {
257: PetscPrintf(snes->hdr.comm, "Fixed alpha = %g\n", alpha);
258: /* Update guess Y = X^n - F(X^n) */
259: VecWAXPY(Y, -1.0, F, X);
260: /* X^{n+1} = (1 - \alpha) X^n + \alpha Y */
261: VecAXPBY(X, alpha, 1 - alpha, Y);
262: /* Compute F(X^{new}) */
263: SNESComputeFunction(snes, X, F);
264: VecNorm(F, NORM_2, &fnorm);
265: if PetscIsInfOrNanReal(fnorm) SETERRQ(PETSC_ERR_FP,"Infinite or not-a-number generated norm");
266: } else {
267: PetscReal dummyNorm;
268: /* Compute a (scaled) negative update in the line search routine:
269: Y <- X - lambda*Y
270: and evaluate G = function(Y) (depends on the line search). */
271: #if 1
272: /* Calculate the solution increment, Y = X^n - F(X^n) */
273: VecWAXPY(Y, -1.0, F, X);
274: (*neP->LineSearch)(snes, neP->lsP, X, F, F/*G*/, Y, W, fnorm, 0.0, &dummyNorm, &fnorm, &lsSuccess);
275: #else
276: /* Put this in function after it works */
277: PetscReal alphas[3] = {0.0, 0.5, 1.0};
278: PetscReal norms[3];
280: norms[0] = fnorm;
281: /* Calculate the solution increment, Y = X^n - F(X^n) */
282: VecWAXPY(Y, -1.0, F, X);
283: {
284: PetscReal norm0, norm1;
286: VecNorm(n_3(X), NORM_INFINITY, &norm0);
287: VecNorm(n_3(Y), NORM_INFINITY, &norm1);
288: if (norm1 > 0.9) {
289: alpha[2] = (norm1 - 0.9)/(norm1 - norm0);
290: }
291: }
292: alpha[1] = 0.5*alpha[2];
293: /* Calculate trial solutions */
294: for(PetscInt i = 1; i < 3; ++i) {
295: /* Calculate X^{n+1} = (1 - \alpha) X^n + \alpha Y */
296: VecCopy(X, W);
297: VecAXPBY(W, alphas[i], 1 - alphas[i], Y);
298: SNESComputeFunction(snes, W, F);
299: VecNorm(F, NORM_2, &norms[i]);
300: }
301: for(PetscInt i = 0; i < 3; ++i) {
302: norms[i] = PetscSqr(norms[i]);
303: }
304: /* Fit a quadratic:
305: If we have x_{0,1,2} = 0, x_1, x_2 which generate norms y_{0,1,2}
306: a = (x_1 y_2 - x_2 y_1 + (x_2 - x_1) y_0)/(x^2_2 x_1 - x_2 x^2_1)
307: b = (x^2_1 y_2 - x^2_2 y_1 + (x^2_2 - x^2_1) y_0)/(x_2 x^2_1 - x^2_2 x_1)
308: c = y_0
309: x_min = -b/2a
311: If we let x_{0,1,2} = 0, 0.5, 1.0
312: a = 2 y_2 - 4 y_1 + 2 y_0
313: b = -y_2 + 4 y_1 - 3 y_0
314: c = y_0
315: */
316: const PetscReal a = (alphas[1]*norms[2] - alphas[2]*norms[1] + (alphas[2] - alphas[1])*norms[0])/
317: (PetscSqr(alphas[2])*alphas[1] - alphas[2]*PetscSqr(alphas[1]));
318: const PetscReal b = (PetscSqr(alphas[1])*norms[2] - PetscSqr(alphas[2])*norms[1] + (PetscSqr(alphas[2]) - PetscSqr(alphas[1]))*norms[0])/
319: (alphas[2]*PetscSqr(alphas[1]) - PetscSqr(alphas[2])*alphas[1]);
320: /* Check for positive a (concave up) */
321: if (a >= 0.0) {
322: alpha = -b/(2.0*a);
323: alpha = PetscMin(alpha, alphas[2]);
324: alpha = PetscMax(alpha, alphas[0]);
325: } else {
326: alpha = 1.0;
327: }
328: PetscPrintf(snes->hdr.comm, "norms[0] = %g, norms[1] = %g, norms[2] = %g\n", norms[0], norms[1], norms[2]);
329: PetscPrintf(snes->hdr.comm, "Choose alpha = %g\n", alpha);
330: VecAXPBY(X, alpha, 1 - alpha, Y);
331: SNESComputeFunction(snes, X, F);
332: VecNorm(F, NORM_2, &fnorm);
333: #endif
334: }
335: if (!lsSuccess) {
336: if (++snes->numFailures >= snes->maxFailures) {
337: snes->reason = SNES_DIVERGED_LS_FAILURE;
338: break;
339: }
340: }
341: if (snes->nfuncs >= snes->max_funcs) {
342: snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
343: break;
344: }
345: if (snes->domainerror) {
346: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
347: return(0);
348: }
349: /* Monitor convergence */
350: PetscObjectTakeAccess(snes);
351: snes->iter = i+1;
352: snes->norm = fnorm;
353: PetscObjectGrantAccess(snes);
354: SNESLogConvHistory(snes,snes->norm,0);
355: SNESMonitor(snes,snes->iter,snes->norm);
356: /* Test for convergence */
357: (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
358: if (snes->reason) break;
359: }
360: if (i == maxits) {
361: PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);
362: if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
363: }
364: return(0);
365: }
371: PetscErrorCode SNESLineSearchSetPreCheck_Picard(SNES snes, FCN1 func, void *checkctx)
372: {
374: ((SNES_Picard *)(snes->data))->precheckstep = func;
375: ((SNES_Picard *)(snes->data))->precheck = checkctx;
376: return(0);
377: }
384: PetscErrorCode SNESLineSearchSet_Picard(SNES snes, FCN2 func, void *lsctx)
385: {
387: ((SNES_Picard *)(snes->data))->LineSearch = func;
388: ((SNES_Picard *)(snes->data))->lsP = lsctx;
389: return(0);
390: }
397: PetscErrorCode SNESLineSearchSetPostCheck_Picard(SNES snes, FCN3 func, void *checkctx)
398: {
400: ((SNES_Picard *)(snes->data))->postcheckstep = func;
401: ((SNES_Picard *)(snes->data))->postcheck = checkctx;
402: return(0);
403: }
406: /*MC
407: SNESPICARD - Picard nonlinear solver that uses successive substitutions
409: Level: beginner
411: .seealso: SNESCreate(), SNES, SNESSetType(), SNESLS, SNESTR
412: M*/
416: PetscErrorCode SNESCreate_Picard(SNES snes)
417: {
418: SNES_Picard *neP;
422: snes->ops->destroy = SNESDestroy_Picard;
423: snes->ops->setup = SNESSetUp_Picard;
424: snes->ops->setfromoptions = SNESSetFromOptions_Picard;
425: snes->ops->view = SNESView_Picard;
426: snes->ops->solve = SNESSolve_Picard;
428: PetscNewLog(snes, SNES_Picard, &neP);
429: snes->data = (void*) neP;
430: neP->type = 0;
431: neP->alpha = 1.e-4;
432: neP->maxstep = 1.e8;
433: neP->steptol = 1.e-12;
434: neP->LineSearch = SNESLineSearchNo;
435: neP->lsP = PETSC_NULL;
436: neP->postcheckstep = PETSC_NULL;
437: neP->postcheck = PETSC_NULL;
438: neP->precheckstep = PETSC_NULL;
439: neP->precheck = PETSC_NULL;
441: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C",
442: "SNESLineSearchSet_Picard",
443: SNESLineSearchSet_Picard);
444: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C",
445: "SNESLineSearchSetPostCheck_Picard",
446: SNESLineSearchSetPostCheck_Picard);
447: PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C",
448: "SNESLineSearchSetPreCheck_Picard",
449: SNESLineSearchSetPreCheck_Picard);
450: return(0);
451: }