Actual source code: snescomposite.c
petsc-3.6.0 2015-06-09
2: /*
3: Defines a SNES that can consist of a collection of SNESes
4: */
5: #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/
6: #include <petscblaslapack.h>
8: const char *const SNESCompositeTypes[] = {"ADDITIVE","MULTIPLICATIVE","ADDITIVEOPTIMAL","SNESCompositeType","SNES_COMPOSITE",0};
10: typedef struct _SNES_CompositeLink *SNES_CompositeLink;
11: struct _SNES_CompositeLink {
12: SNES snes;
13: PetscReal dmp;
14: Vec X;
15: SNES_CompositeLink next;
16: SNES_CompositeLink previous;
17: };
19: typedef struct {
20: SNES_CompositeLink head;
21: PetscInt nsnes;
22: SNESCompositeType type;
23: Vec Xorig;
24: PetscInt innerFailures; /* the number of inner failures we've seen */
26: /* context for ADDITIVEOPTIMAL */
27: Vec *Xes,*Fes; /* solution and residual vectors for the subsolvers */
28: PetscReal *fnorms; /* norms of the solutions */
29: PetscScalar *h; /* the matrix formed as q_ij = (rdot_i, rdot_j) */
30: PetscScalar *g; /* the dotproducts of the previous function with the candidate functions */
31: PetscBLASInt n; /* matrix dimension -- nsnes */
32: PetscBLASInt nrhs; /* the number of right hand sides */
33: PetscBLASInt lda; /* the padded matrix dimension */
34: PetscBLASInt ldb; /* the padded vector dimension */
35: PetscReal *s; /* the singular values */
36: PetscScalar *beta; /* the RHS and combination */
37: PetscReal rcond; /* the exit condition */
38: PetscBLASInt rank; /* the effective rank */
39: PetscScalar *work; /* the work vector */
40: PetscReal *rwork; /* the real work vector used for complex */
41: PetscBLASInt lwork; /* the size of the work vector */
42: PetscBLASInt info; /* the output condition */
44: PetscReal rtol; /* restart tolerance for accepting the combination */
45: PetscReal stol; /* restart tolerance for the combination */
46: } SNES_Composite;
50: static PetscErrorCode SNESCompositeApply_Multiplicative(SNES snes,Vec X,Vec B,Vec F,PetscReal *fnorm)
51: {
52: PetscErrorCode ierr;
53: SNES_Composite *jac = (SNES_Composite*)snes->data;
54: SNES_CompositeLink next = jac->head;
55: Vec FSub;
56: SNESConvergedReason reason;
59: if (!next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"No composite SNESes supplied via SNESCompositeAddSNES() or -snes_composite_sneses");
60: if (snes->normschedule == SNES_NORM_ALWAYS) {
61: SNESSetInitialFunction(next->snes,F);
62: }
63: SNESSolve(next->snes,B,X);
64: SNESGetConvergedReason(next->snes,&reason);
65: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
66: jac->innerFailures++;
67: if (jac->innerFailures >= snes->maxFailures) {
68: snes->reason = SNES_DIVERGED_INNER;
69: return(0);
70: }
71: }
73: while (next->next) {
74: /* only copy the function over in the case where the functions correspond */
75: if (next->snes->pcside == PC_RIGHT && next->snes->normschedule != SNES_NORM_NONE) {
76: SNESGetFunction(next->snes,&FSub,NULL,NULL);
77: next = next->next;
78: SNESSetInitialFunction(next->snes,FSub);
79: } else {
80: next = next->next;
81: }
82: SNESSolve(next->snes,B,X);
83: SNESGetConvergedReason(next->snes,&reason);
84: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
85: jac->innerFailures++;
86: if (jac->innerFailures >= snes->maxFailures) {
87: snes->reason = SNES_DIVERGED_INNER;
88: return(0);
89: }
90: }
91: }
92: if (next->snes->pcside == PC_RIGHT) {
93: SNESGetFunction(next->snes,&FSub,NULL,NULL);
94: VecCopy(FSub,F);
95: if (fnorm) {
96: if (snes->xl && snes->xu) {
97: SNESVIComputeInactiveSetFnorm(snes, F, X, fnorm);
98: } else {
99: VecNorm(F, NORM_2, fnorm);
100: }
101: SNESCheckFunctionNorm(snes,*fnorm);
102: }
103: } else if (snes->normschedule == SNES_NORM_ALWAYS) {
104: SNESComputeFunction(snes,X,F);
105: if (fnorm) {
106: if (snes->xl && snes->xu) {
107: SNESVIComputeInactiveSetFnorm(snes, F, X, fnorm);
108: } else {
109: VecNorm(F, NORM_2, fnorm);
110: }
111: SNESCheckFunctionNorm(snes,*fnorm);
112: }
113: }
114: return(0);
115: }
119: static PetscErrorCode SNESCompositeApply_Additive(SNES snes,Vec X,Vec B,Vec F,PetscReal *fnorm)
120: {
121: PetscErrorCode ierr;
122: SNES_Composite *jac = (SNES_Composite*)snes->data;
123: SNES_CompositeLink next = jac->head;
124: Vec Y,Xorig;
125: SNESConvergedReason reason;
128: Y = snes->vec_sol_update;
129: if (!jac->Xorig) {VecDuplicate(X,&jac->Xorig);}
130: Xorig = jac->Xorig;
131: VecCopy(X,Xorig);
132: if (!next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"No composite SNESes supplied via SNESCompositeAddSNES() or -snes_composite_sneses");
133: if (snes->normschedule == SNES_NORM_ALWAYS) {
134: SNESSetInitialFunction(next->snes,F);
135: while (next->next) {
136: next = next->next;
137: SNESSetInitialFunction(next->snes,F);
138: }
139: }
140: next = jac->head;
141: VecCopy(Xorig,Y);
142: SNESSolve(next->snes,B,Y);
143: SNESGetConvergedReason(next->snes,&reason);
144: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
145: jac->innerFailures++;
146: if (jac->innerFailures >= snes->maxFailures) {
147: snes->reason = SNES_DIVERGED_INNER;
148: return(0);
149: }
150: }
151: VecAXPY(Y,-1.0,Xorig);
152: VecAXPY(X,next->dmp,Y);
153: while (next->next) {
154: next = next->next;
155: VecCopy(Xorig,Y);
156: SNESSolve(next->snes,B,Y);
157: SNESGetConvergedReason(next->snes,&reason);
158: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
159: jac->innerFailures++;
160: if (jac->innerFailures >= snes->maxFailures) {
161: snes->reason = SNES_DIVERGED_INNER;
162: return(0);
163: }
164: }
165: VecAXPY(Y,-1.0,Xorig);
166: VecAXPY(X,next->dmp,Y);
167: }
168: if (snes->normschedule == SNES_NORM_ALWAYS) {
169: SNESComputeFunction(snes,X,F);
170: if (fnorm) {
171: if (snes->xl && snes->xu) {
172: SNESVIComputeInactiveSetFnorm(snes, F, X, fnorm);
173: } else {
174: VecNorm(F, NORM_2, fnorm);
175: }
176: SNESCheckFunctionNorm(snes,*fnorm);
177: }
178: }
179: return(0);
180: }
184: /* approximately solve the overdetermined system:
186: 2*F(x_i)\cdot F(\x_j)\alpha_i = 0
187: \alpha_i = 1
189: Which minimizes the L2 norm of the linearization of:
190: ||F(\sum_i \alpha_i*x_i)||^2
192: With the constraint that \sum_i\alpha_i = 1
193: Where x_i is the solution from the ith subsolver.
194: */
195: static PetscErrorCode SNESCompositeApply_AdditiveOptimal(SNES snes,Vec X,Vec B,Vec F,PetscReal *fnorm)
196: {
197: PetscErrorCode ierr;
198: SNES_Composite *jac = (SNES_Composite*)snes->data;
199: SNES_CompositeLink next = jac->head;
200: Vec *Xes = jac->Xes,*Fes = jac->Fes;
201: PetscInt i,j;
202: PetscScalar tot,total,ftf;
203: PetscReal min_fnorm;
204: PetscInt min_i;
205: SNESConvergedReason reason;
208: if (!next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"No composite SNESes supplied via SNESCompositeAddSNES() or -snes_composite_sneses");
210: if (snes->normschedule == SNES_NORM_ALWAYS) {
211: next = jac->head;
212: SNESSetInitialFunction(next->snes,F);
213: while (next->next) {
214: next = next->next;
215: SNESSetInitialFunction(next->snes,F);
216: }
217: }
219: next = jac->head;
220: i = 0;
221: VecCopy(X,Xes[i]);
222: SNESSolve(next->snes,B,Xes[i]);
223: SNESGetConvergedReason(next->snes,&reason);
224: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
225: jac->innerFailures++;
226: if (jac->innerFailures >= snes->maxFailures) {
227: snes->reason = SNES_DIVERGED_INNER;
228: return(0);
229: }
230: }
231: while (next->next) {
232: i++;
233: next = next->next;
234: VecCopy(X,Xes[i]);
235: SNESSolve(next->snes,B,Xes[i]);
236: SNESGetConvergedReason(next->snes,&reason);
237: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
238: jac->innerFailures++;
239: if (jac->innerFailures >= snes->maxFailures) {
240: snes->reason = SNES_DIVERGED_INNER;
241: return(0);
242: }
243: }
244: }
246: /* all the solutions are collected; combine optimally */
247: for (i=0;i<jac->n;i++) {
248: for (j=0;j<i+1;j++) {
249: VecDotBegin(Fes[i],Fes[j],&jac->h[i + j*jac->n]);
250: }
251: VecDotBegin(Fes[i],F,&jac->g[i]);
252: }
254: for (i=0;i<jac->n;i++) {
255: for (j=0;j<i+1;j++) {
256: VecDotEnd(Fes[i],Fes[j],&jac->h[i + j*jac->n]);
257: if (i == j) jac->fnorms[i] = PetscSqrtReal(PetscRealPart(jac->h[i + j*jac->n]));
258: }
259: VecDotEnd(Fes[i],F,&jac->g[i]);
260: }
262: ftf = (*fnorm)*(*fnorm);
264: for (i=0; i<jac->n; i++) {
265: for (j=i+1;j<jac->n;j++) {
266: jac->h[i + j*jac->n] = jac->h[j + i*jac->n];
267: }
268: }
270: for (i=0; i<jac->n; i++) {
271: for (j=0; j<jac->n; j++) {
272: jac->h[i + j*jac->n] = jac->h[i + j*jac->n] - jac->g[j] - jac->g[i] + ftf;
273: }
274: jac->beta[i] = ftf - jac->g[i];
275: }
277: #if defined(PETSC_MISSING_LAPACK_GELSS)
278: SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"SNESCOMPOSITE with ADDITIVEOPTIMAL requires the LAPACK GELSS routine.");
279: #else
280: jac->info = 0;
281: jac->rcond = -1.;
282: PetscFPTrapPush(PETSC_FP_TRAP_OFF);
283: #if defined(PETSC_USE_COMPLEX)
284: PetscStackCall("LAPACKgelss",LAPACKgelss_(&jac->n,&jac->n,&jac->nrhs,jac->h,&jac->lda,jac->beta,&jac->lda,jac->s,&jac->rcond,&jac->rank,jac->work,&jac->lwork,jac->rwork,&jac->info));
285: #else
286: PetscStackCall("LAPACKgelss",LAPACKgelss_(&jac->n,&jac->n,&jac->nrhs,jac->h,&jac->lda,jac->beta,&jac->lda,jac->s,&jac->rcond,&jac->rank,jac->work,&jac->lwork,&jac->info));
287: #endif
288: PetscFPTrapPop();
289: if (jac->info < 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"Bad argument to GELSS");
290: if (jac->info > 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD failed to converge");
291: #endif
292: tot = 0.;
293: total = 0.;
294: for (i=0; i<jac->n; i++) {
295: if (snes->errorifnotconverged && PetscIsInfOrNanScalar(jac->beta[i])) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD generated inconsistent output");
296: PetscInfo2(snes,"%D: %g\n",i,(double)PetscRealPart(jac->beta[i]));
297: tot += jac->beta[i];
298: total += PetscAbsScalar(jac->beta[i]);
299: }
300: VecScale(X,(1. - tot));
301: VecMAXPY(X,jac->n,jac->beta,Xes);
302: SNESComputeFunction(snes,X,F);
304: if (snes->xl && snes->xu) {
305: SNESVIComputeInactiveSetFnorm(snes, F, X, fnorm);
306: } else {
307: VecNorm(F, NORM_2, fnorm);
308: }
310: /* take the minimum-normed candidate if it beats the combination by a factor of rtol or the combination has stagnated */
311: min_fnorm = jac->fnorms[0];
312: min_i = 0;
313: for (i=0; i<jac->n; i++) {
314: if (jac->fnorms[i] < min_fnorm) {
315: min_fnorm = jac->fnorms[i];
316: min_i = i;
317: }
318: }
320: /* stagnation or divergence restart to the solution of the solver that failed the least */
321: if (PetscRealPart(total) < jac->stol || min_fnorm*jac->rtol < *fnorm) {
322: VecCopy(jac->Xes[min_i],X);
323: VecCopy(jac->Fes[min_i],F);
324: *fnorm = min_fnorm;
325: }
326: return(0);
327: }
331: static PetscErrorCode SNESSetUp_Composite(SNES snes)
332: {
333: PetscErrorCode ierr;
334: DM dm;
335: SNES_Composite *jac = (SNES_Composite*)snes->data;
336: SNES_CompositeLink next = jac->head;
337: PetscInt n=0,i;
338: Vec F;
341: SNESGetDM(snes,&dm);
343: if (snes->ops->computevariablebounds) {
344: /* SNESVI only ever calls computevariablebounds once, so calling it once here is justified */
345: if (!snes->xl) {VecDuplicate(snes->vec_sol,&snes->xl);}
346: if (!snes->xu) {VecDuplicate(snes->vec_sol,&snes->xu);}
347: (*snes->ops->computevariablebounds)(snes,snes->xl,snes->xu);
348: }
350: while (next) {
351: n++;
352: SNESSetDM(next->snes,dm);
353: SNESSetFromOptions(next->snes);
354: SNESSetApplicationContext(next->snes, snes->user);
355: if (snes->xl && snes->xu) {
356: if (snes->ops->computevariablebounds) {
357: SNESVISetComputeVariableBounds(next->snes, snes->ops->computevariablebounds);
358: } else {
359: SNESVISetVariableBounds(next->snes,snes->xl,snes->xu);
360: }
361: }
363: next = next->next;
364: }
365: jac->nsnes = n;
366: SNESGetFunction(snes,&F,NULL,NULL);
367: if (jac->type == SNES_COMPOSITE_ADDITIVEOPTIMAL) {
368: VecDuplicateVecs(F,jac->nsnes,&jac->Xes);
369: PetscMalloc1(n,&jac->Fes);
370: PetscMalloc1(n,&jac->fnorms);
371: next = jac->head;
372: i = 0;
373: while (next) {
374: SNESGetFunction(next->snes,&F,NULL,NULL);
375: jac->Fes[i] = F;
376: PetscObjectReference((PetscObject)F);
377: next = next->next;
378: i++;
379: }
380: /* allocate the subspace direct solve area */
381: jac->nrhs = 1;
382: jac->lda = jac->nsnes;
383: jac->ldb = jac->nsnes;
384: jac->n = jac->nsnes;
386: PetscMalloc1(jac->n*jac->n,&jac->h);
387: PetscMalloc1(jac->n,&jac->beta);
388: PetscMalloc1(jac->n,&jac->s);
389: PetscMalloc1(jac->n,&jac->g);
390: jac->lwork = 12*jac->n;
391: #if PETSC_USE_COMPLEX
392: PetscMalloc1(jac->lwork,&jac->rwork);
393: #endif
394: PetscMalloc1(jac->lwork,&jac->work);
395: }
397: return(0);
398: }
402: static PetscErrorCode SNESReset_Composite(SNES snes)
403: {
404: SNES_Composite *jac = (SNES_Composite*)snes->data;
405: PetscErrorCode ierr;
406: SNES_CompositeLink next = jac->head;
409: while (next) {
410: SNESReset(next->snes);
411: next = next->next;
412: }
413: VecDestroy(&jac->Xorig);
414: if (jac->Xes) {VecDestroyVecs(jac->nsnes,&jac->Xes);}
415: if (jac->Fes) {VecDestroyVecs(jac->nsnes,&jac->Fes);}
416: PetscFree(jac->fnorms);
417: PetscFree(jac->h);
418: PetscFree(jac->s);
419: PetscFree(jac->g);
420: PetscFree(jac->beta);
421: PetscFree(jac->work);
422: PetscFree(jac->rwork);
423: return(0);
424: }
428: static PetscErrorCode SNESDestroy_Composite(SNES snes)
429: {
430: SNES_Composite *jac = (SNES_Composite*)snes->data;
431: PetscErrorCode ierr;
432: SNES_CompositeLink next = jac->head,next_tmp;
435: SNESReset_Composite(snes);
436: while (next) {
437: SNESDestroy(&next->snes);
438: next_tmp = next;
439: next = next->next;
440: PetscFree(next_tmp);
441: }
442: PetscFree(snes->data);
443: return(0);
444: }
448: static PetscErrorCode SNESSetFromOptions_Composite(PetscOptions *PetscOptionsObject,SNES snes)
449: {
450: SNES_Composite *jac = (SNES_Composite*)snes->data;
451: PetscErrorCode ierr;
452: PetscInt nmax = 8,i;
453: SNES_CompositeLink next;
454: char *sneses[8];
455: PetscReal dmps[8];
456: PetscBool flg;
459: PetscOptionsHead(PetscOptionsObject,"Composite preconditioner options");
460: PetscOptionsEnum("-snes_composite_type","Type of composition","SNESCompositeSetType",SNESCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);
461: if (flg) {
462: SNESCompositeSetType(snes,jac->type);
463: }
464: PetscOptionsStringArray("-snes_composite_sneses","List of composite solvers","SNESCompositeAddSNES",sneses,&nmax,&flg);
465: if (flg) {
466: for (i=0; i<nmax; i++) {
467: SNESCompositeAddSNES(snes,sneses[i]);
468: PetscFree(sneses[i]); /* deallocate string sneses[i], which is allocated in PetscOptionsStringArray() */
469: }
470: }
471: PetscOptionsRealArray("-snes_composite_damping","Damping of the additive composite solvers","SNESCompositeSetDamping",dmps,&nmax,&flg);
472: if (flg) {
473: for (i=0; i<nmax; i++) {
474: SNESCompositeSetDamping(snes,i,dmps[i]);
475: }
476: }
477: PetscOptionsReal("-snes_composite_stol","Step tolerance for restart on the additive composite solvers","",jac->stol,&jac->stol,NULL);
478: PetscOptionsReal("-snes_composite_rtol","Residual tolerance for the additive composite solvers","",jac->rtol,&jac->rtol,NULL);
479: PetscOptionsTail();
481: next = jac->head;
482: while (next) {
483: SNESSetFromOptions(next->snes);
484: next = next->next;
485: }
486: return(0);
487: }
491: static PetscErrorCode SNESView_Composite(SNES snes,PetscViewer viewer)
492: {
493: SNES_Composite *jac = (SNES_Composite*)snes->data;
494: PetscErrorCode ierr;
495: SNES_CompositeLink next = jac->head;
496: PetscBool iascii;
499: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
500: if (iascii) {
501: PetscViewerASCIIPrintf(viewer,"Composite SNES type - %s\n",SNESCompositeTypes[jac->type]);
502: PetscViewerASCIIPrintf(viewer,"SNESes on composite preconditioner follow\n");
503: PetscViewerASCIIPrintf(viewer,"---------------------------------\n");
504: }
505: if (iascii) {
506: PetscViewerASCIIPushTab(viewer);
507: }
508: while (next) {
509: SNESView(next->snes,viewer);
510: next = next->next;
511: }
512: if (iascii) {
513: PetscViewerASCIIPopTab(viewer);
514: PetscViewerASCIIPrintf(viewer,"---------------------------------\n");
515: }
516: return(0);
517: }
519: /* ------------------------------------------------------------------------------*/
523: static PetscErrorCode SNESCompositeSetType_Composite(SNES snes,SNESCompositeType type)
524: {
525: SNES_Composite *jac = (SNES_Composite*)snes->data;
528: jac->type = type;
529: return(0);
530: }
534: static PetscErrorCode SNESCompositeAddSNES_Composite(SNES snes,SNESType type)
535: {
536: SNES_Composite *jac;
537: SNES_CompositeLink next,ilink;
538: PetscErrorCode ierr;
539: PetscInt cnt = 0;
540: const char *prefix;
541: char newprefix[8];
542: DM dm;
545: PetscNewLog(snes,&ilink);
546: ilink->next = 0;
547: SNESCreate(PetscObjectComm((PetscObject)snes),&ilink->snes);
548: PetscLogObjectParent((PetscObject)snes,(PetscObject)ilink->snes);
549: SNESGetDM(snes,&dm);
550: SNESSetDM(ilink->snes,dm);
551: SNESSetTolerances(ilink->snes,ilink->snes->abstol,ilink->snes->rtol,ilink->snes->stol,1,ilink->snes->max_funcs);
552: jac = (SNES_Composite*)snes->data;
553: next = jac->head;
554: if (!next) {
555: jac->head = ilink;
556: ilink->previous = NULL;
557: } else {
558: cnt++;
559: while (next->next) {
560: next = next->next;
561: cnt++;
562: }
563: next->next = ilink;
564: ilink->previous = next;
565: }
566: SNESGetOptionsPrefix(snes,&prefix);
567: SNESSetOptionsPrefix(ilink->snes,prefix);
568: sprintf(newprefix,"sub_%d_",(int)cnt);
569: SNESAppendOptionsPrefix(ilink->snes,newprefix);
570: PetscObjectIncrementTabLevel((PetscObject)ilink->snes,(PetscObject)snes,1);
571: SNESSetType(ilink->snes,type);
572: SNESSetNormSchedule(ilink->snes, SNES_NORM_FINAL_ONLY);
574: ilink->dmp = 1.0;
575: jac->nsnes++;
576: return(0);
577: }
581: static PetscErrorCode SNESCompositeGetSNES_Composite(SNES snes,PetscInt n,SNES *subsnes)
582: {
583: SNES_Composite *jac;
584: SNES_CompositeLink next;
585: PetscInt i;
588: jac = (SNES_Composite*)snes->data;
589: next = jac->head;
590: for (i=0; i<n; i++) {
591: if (!next->next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Not enough SNESes in composite preconditioner");
592: next = next->next;
593: }
594: *subsnes = next->snes;
595: return(0);
596: }
598: /* -------------------------------------------------------------------------------- */
601: /*@C
602: SNESCompositeSetType - Sets the type of composite preconditioner.
604: Logically Collective on SNES
606: Input Parameter:
607: + snes - the preconditioner context
608: - type - SNES_COMPOSITE_ADDITIVE (default), SNES_COMPOSITE_MULTIPLICATIVE
610: Options Database Key:
611: . -snes_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
613: Level: Developer
615: .keywords: SNES, set, type, composite preconditioner, additive, multiplicative
616: @*/
617: PetscErrorCode SNESCompositeSetType(SNES snes,SNESCompositeType type)
618: {
624: PetscTryMethod(snes,"SNESCompositeSetType_C",(SNES,SNESCompositeType),(snes,type));
625: return(0);
626: }
630: /*@C
631: SNESCompositeAddSNES - Adds another SNES to the composite SNES.
633: Collective on SNES
635: Input Parameters:
636: + snes - the preconditioner context
637: - type - the type of the new preconditioner
639: Level: Developer
641: .keywords: SNES, composite preconditioner, add
642: @*/
643: PetscErrorCode SNESCompositeAddSNES(SNES snes,SNESType type)
644: {
649: PetscTryMethod(snes,"SNESCompositeAddSNES_C",(SNES,SNESType),(snes,type));
650: return(0);
651: }
654: /*@
655: SNESCompositeGetSNES - Gets one of the SNES objects in the composite SNES.
657: Not Collective
659: Input Parameter:
660: + snes - the preconditioner context
661: - n - the number of the snes requested
663: Output Parameters:
664: . subsnes - the SNES requested
666: Level: Developer
668: .keywords: SNES, get, composite preconditioner, sub preconditioner
670: .seealso: SNESCompositeAddSNES()
671: @*/
672: PetscErrorCode SNESCompositeGetSNES(SNES snes,PetscInt n,SNES *subsnes)
673: {
679: PetscUseMethod(snes,"SNESCompositeGetSNES_C",(SNES,PetscInt,SNES*),(snes,n,subsnes));
680: return(0);
681: }
685: /*@
686: SNESCompositeGetNumber - Get the number of subsolvers in the composite SNES.
688: Logically Collective on SNES
690: Input Parameter:
691: snes - the preconditioner context
693: Output Parameter:
694: n - the number of subsolvers
696: Level: Developer
698: .keywords: SNES, composite preconditioner
699: @*/
700: PetscErrorCode SNESCompositeGetNumber(SNES snes,PetscInt *n)
701: {
702: SNES_Composite *jac;
703: SNES_CompositeLink next;
706: jac = (SNES_Composite*)snes->data;
707: next = jac->head;
709: *n = 0;
710: while (next) {
711: *n = *n + 1;
712: next = next->next;
713: }
714: return(0);
715: }
719: static PetscErrorCode SNESCompositeSetDamping_Composite(SNES snes,PetscInt n,PetscReal dmp)
720: {
721: SNES_Composite *jac;
722: SNES_CompositeLink next;
723: PetscInt i;
726: jac = (SNES_Composite*)snes->data;
727: next = jac->head;
728: for (i=0; i<n; i++) {
729: if (!next->next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Not enough SNESes in composite preconditioner");
730: next = next->next;
731: }
732: next->dmp = dmp;
733: return(0);
734: }
738: /*@
739: SNESCompositeSetDamping - Sets the damping of a subsolver when using additive composite SNES.
741: Not Collective
743: Input Parameter:
744: + snes - the preconditioner context
745: . n - the number of the snes requested
746: - dmp - the damping
748: Level: Developer
750: .keywords: SNES, get, composite preconditioner, sub preconditioner
752: .seealso: SNESCompositeAddSNES()
753: @*/
754: PetscErrorCode SNESCompositeSetDamping(SNES snes,PetscInt n,PetscReal dmp)
755: {
760: PetscUseMethod(snes,"SNESCompositeSetDamping_C",(SNES,PetscInt,PetscReal),(snes,n,dmp));
761: return(0);
762: }
766: PetscErrorCode SNESSolve_Composite(SNES snes)
767: {
768: Vec F;
769: Vec X;
770: Vec B;
771: PetscInt i;
772: PetscReal fnorm = 0.0, xnorm = 0.0, snorm = 0.0;
774: SNESNormSchedule normtype;
775: SNES_Composite *comp = (SNES_Composite*)snes->data;
778: X = snes->vec_sol;
779: F = snes->vec_func;
780: B = snes->vec_rhs;
782: PetscObjectSAWsTakeAccess((PetscObject)snes);
783: snes->iter = 0;
784: snes->norm = 0.;
785: comp->innerFailures = 0;
786: PetscObjectSAWsGrantAccess((PetscObject)snes);
787: SNESSetWorkVecs(snes, 1);
788: snes->reason = SNES_CONVERGED_ITERATING;
789: SNESGetNormSchedule(snes, &normtype);
790: if (normtype == SNES_NORM_ALWAYS || normtype == SNES_NORM_INITIAL_ONLY || normtype == SNES_NORM_INITIAL_FINAL_ONLY) {
791: if (!snes->vec_func_init_set) {
792: SNESComputeFunction(snes,X,F);
793: } else snes->vec_func_init_set = PETSC_FALSE;
795: if (snes->xl && snes->xu) {
796: SNESVIComputeInactiveSetFnorm(snes, F, X, &fnorm);
797: } else {
798: VecNorm(F, NORM_2, &fnorm); /* fnorm <- ||F|| */
799: }
800: SNESCheckFunctionNorm(snes,fnorm);
801: PetscObjectSAWsTakeAccess((PetscObject)snes);
802: snes->iter = 0;
803: snes->norm = fnorm;
804: PetscObjectSAWsGrantAccess((PetscObject)snes);
805: SNESLogConvergenceHistory(snes,snes->norm,0);
806: SNESMonitor(snes,0,snes->norm);
808: /* test convergence */
809: (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
810: if (snes->reason) return(0);
811: } else {
812: PetscObjectSAWsGrantAccess((PetscObject)snes);
813: SNESLogConvergenceHistory(snes,snes->norm,0);
814: SNESMonitor(snes,0,snes->norm);
815: }
817: /* Call general purpose update function */
818: if (snes->ops->update) {
819: (*snes->ops->update)(snes, snes->iter);
820: }
822: for (i = 0; i < snes->max_its; i++) {
823: /* Copy the state before modification by application of the composite solver;
824: we will subtract the new state after application */
825: VecCopy(X, snes->work[0]);
827: if (comp->type == SNES_COMPOSITE_ADDITIVE) {
828: SNESCompositeApply_Additive(snes,X,B,F,&fnorm);
829: } else if (comp->type == SNES_COMPOSITE_MULTIPLICATIVE) {
830: SNESCompositeApply_Multiplicative(snes,X,B,F,&fnorm);
831: } else if (comp->type == SNES_COMPOSITE_ADDITIVEOPTIMAL) {
832: SNESCompositeApply_AdditiveOptimal(snes,X,B,F,&fnorm);
833: } else {
834: SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Unsupported SNESComposite type");
835: }
836: if (snes->reason < 0) break;
838: /* Compute the solution update for convergence testing */
839: VecAXPY(snes->work[0], -1.0, X);
840: VecScale(snes->work[0], -1.0);
842: if ((i == snes->max_its - 1) && (normtype == SNES_NORM_INITIAL_FINAL_ONLY || normtype == SNES_NORM_FINAL_ONLY)) {
843: SNESComputeFunction(snes,X,F);
845: if (snes->xl && snes->xu) {
846: VecNormBegin(X, NORM_2, &xnorm);
847: VecNormBegin(snes->work[0], NORM_2, &snorm);
848: SNESVIComputeInactiveSetFnorm(snes, F, X, &fnorm);
849: VecNormEnd(X, NORM_2, &xnorm);
850: VecNormEnd(snes->work[0], NORM_2, &snorm);
851: } else {
852: VecNormBegin(F, NORM_2, &fnorm);
853: VecNormBegin(X, NORM_2, &xnorm);
854: VecNormBegin(snes->work[0], NORM_2, &snorm);
856: VecNormEnd(F, NORM_2, &fnorm);
857: VecNormEnd(X, NORM_2, &xnorm);
858: VecNormEnd(snes->work[0], NORM_2, &snorm);
859: }
860: SNESCheckFunctionNorm(snes,fnorm);
861: } else if (normtype == SNES_NORM_ALWAYS) {
862: VecNormBegin(X, NORM_2, &xnorm);
863: VecNormBegin(snes->work[0], NORM_2, &snorm);
864: VecNormEnd(X, NORM_2, &xnorm);
865: VecNormEnd(snes->work[0], NORM_2, &snorm);
866: }
867: /* Monitor convergence */
868: PetscObjectSAWsTakeAccess((PetscObject)snes);
869: snes->iter = i+1;
870: snes->norm = fnorm;
871: PetscObjectSAWsGrantAccess((PetscObject)snes);
872: SNESLogConvergenceHistory(snes,snes->norm,0);
873: SNESMonitor(snes,snes->iter,snes->norm);
874: /* Test for convergence */
875: if (normtype == SNES_NORM_ALWAYS) {(*snes->ops->converged)(snes,snes->iter,xnorm,snorm,fnorm,&snes->reason,snes->cnvP);}
876: if (snes->reason) break;
877: /* Call general purpose update function */
878: if (snes->ops->update) {(*snes->ops->update)(snes, snes->iter);}
879: }
880: if (normtype == SNES_NORM_ALWAYS) {
881: if (i == snes->max_its) {
882: PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",snes->max_its);
883: if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
884: }
885: } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS;
886: return(0);
887: }
889: /* -------------------------------------------------------------------------------------------*/
891: /*MC
892: SNESCOMPOSITE - Build a preconditioner by composing together several nonlinear solvers
894: Options Database Keys:
895: + -snes_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
896: - -snes_composite_sneses - <snes0,snes1,...> list of SNESes to compose
898: Level: intermediate
900: Concepts: composing solvers
902: .seealso: SNESCreate(), SNESSetType(), SNESType (for list of available types), SNES,
903: SNESSHELL, SNESCompositeSetType(), SNESCompositeSpecialSetAlpha(), SNESCompositeAddSNES(),
904: SNESCompositeGetSNES()
906: M*/
910: PETSC_EXTERN PetscErrorCode SNESCreate_Composite(SNES snes)
911: {
913: SNES_Composite *jac;
916: PetscNewLog(snes,&jac);
918: snes->ops->solve = SNESSolve_Composite;
919: snes->ops->setup = SNESSetUp_Composite;
920: snes->ops->reset = SNESReset_Composite;
921: snes->ops->destroy = SNESDestroy_Composite;
922: snes->ops->setfromoptions = SNESSetFromOptions_Composite;
923: snes->ops->view = SNESView_Composite;
925: snes->data = (void*)jac;
926: jac->type = SNES_COMPOSITE_ADDITIVEOPTIMAL;
927: jac->Fes = NULL;
928: jac->Xes = NULL;
929: jac->fnorms = NULL;
930: jac->nsnes = 0;
931: jac->head = 0;
932: jac->stol = 0.1;
933: jac->rtol = 1.1;
935: jac->h = NULL;
936: jac->s = NULL;
937: jac->beta = NULL;
938: jac->work = NULL;
939: jac->rwork = NULL;
941: PetscObjectComposeFunction((PetscObject)snes,"SNESCompositeSetType_C",SNESCompositeSetType_Composite);
942: PetscObjectComposeFunction((PetscObject)snes,"SNESCompositeAddSNES_C",SNESCompositeAddSNES_Composite);
943: PetscObjectComposeFunction((PetscObject)snes,"SNESCompositeGetSNES_C",SNESCompositeGetSNES_Composite);
944: PetscObjectComposeFunction((PetscObject)snes,"SNESCompositeSetDamping_C",SNESCompositeSetDamping_Composite);
945: return(0);
946: }