Actual source code: snescomposite.c
petsc-dev 2014-02-02
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;
25: /* context for ADDITIVEOPTIMAL */
26: Vec *Xes,*Fes; /* solution and residual vectors for the subsolvers */
27: PetscReal *fnorms; /* norms of the solutions */
28: PetscScalar *h; /* the matrix formed as q_ij = (rdot_i, rdot_j) */
29: PetscScalar *g; /* the dotproducts of the previous function with the candidate functions */
30: PetscBLASInt n; /* matrix dimension -- nsnes */
31: PetscBLASInt nrhs; /* the number of right hand sides */
32: PetscBLASInt lda; /* the padded matrix dimension */
33: PetscBLASInt ldb; /* the padded vector dimension */
34: PetscReal *s; /* the singular values */
35: PetscScalar *beta; /* the RHS and combination */
36: PetscReal rcond; /* the exit condition */
37: PetscBLASInt rank; /* the effective rank */
38: PetscScalar *work; /* the work vector */
39: PetscReal *rwork; /* the real work vector used for complex */
40: PetscBLASInt lwork; /* the size of the work vector */
41: PetscBLASInt info; /* the output condition */
43: PetscReal rtol; /* restart tolerance for accepting the combination */
44: PetscReal stol; /* restart tolerance for the combination */
45: } SNES_Composite;
49: static PetscErrorCode SNESCompositeApply_Multiplicative(SNES snes,Vec X,Vec B,Vec F,PetscReal *fnorm)
50: {
51: PetscErrorCode ierr;
52: SNES_Composite *jac = (SNES_Composite*)snes->data;
53: SNES_CompositeLink next = jac->head;
54: Vec FSub;
55: SNESConvergedReason reason;
58: if (!next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"No composite SNESes supplied via SNESCompositeAddSNES() or -snes_composite_sneses");
59: if (snes->normschedule == SNES_NORM_ALWAYS) {
60: SNESSetInitialFunction(next->snes,F);
61: }
62: SNESSolve(next->snes,B,X);
63: SNESGetConvergedReason(next->snes,&reason);
64: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
65: snes->reason = SNES_DIVERGED_INNER;
66: return(0);
67: }
69: while (next->next) {
70: /* only copy the function over in the case where the functions correspond */
71: if (next->snes->pcside == PC_RIGHT && next->snes->normschedule != SNES_NORM_NONE) {
72: SNESGetFunction(next->snes,&FSub,NULL,NULL);
73: next = next->next;
74: SNESSetInitialFunction(next->snes,FSub);
75: } else {
76: next = next->next;
77: }
78: SNESSolve(next->snes,B,X);
79: SNESGetConvergedReason(next->snes,&reason);
80: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
81: snes->reason = SNES_DIVERGED_INNER;
82: return(0);
83: }
84: }
85: if (next->snes->pcside == PC_RIGHT) {
86: SNESGetFunction(next->snes,&FSub,NULL,NULL);
87: VecCopy(FSub,F);
88: if (fnorm) {
89: SNESGetFunctionNorm(next->snes,fnorm);
90: if (PetscIsInfOrNanReal(*fnorm)) {
91: snes->reason = SNES_DIVERGED_FNORM_NAN;
92: return(0);
93: }
94: }
95: } else if (snes->normschedule == SNES_NORM_ALWAYS) {
96: SNESComputeFunction(snes,X,F);
97: if (snes->domainerror) {
98: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
99: return(0);
100: }
101: if (fnorm) {
102: VecNorm(F,NORM_2,fnorm);
103: if (PetscIsInfOrNanReal(*fnorm)) {
104: snes->reason = SNES_DIVERGED_FNORM_NAN;
105: return(0);
106: }
107: }
108: }
109: return(0);
110: }
114: static PetscErrorCode SNESCompositeApply_Additive(SNES snes,Vec X,Vec B,Vec F,PetscReal *fnorm)
115: {
116: PetscErrorCode ierr;
117: SNES_Composite *jac = (SNES_Composite*)snes->data;
118: SNES_CompositeLink next = jac->head;
119: Vec Y,Xorig;
120: SNESConvergedReason reason;
123: Y = snes->vec_sol_update;
124: if (!jac->Xorig) {VecDuplicate(X,&jac->Xorig);}
125: Xorig = jac->Xorig;
126: VecCopy(X,Xorig);
127: if (!next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"No composite SNESes supplied via SNESCompositeAddSNES() or -snes_composite_sneses");
128: if (snes->normschedule == SNES_NORM_ALWAYS) {
129: SNESSetInitialFunction(next->snes,F);
130: while (next->next) {
131: next = next->next;
132: SNESSetInitialFunction(next->snes,F);
133: }
134: }
135: next = jac->head;
136: VecCopy(Xorig,Y);
137: SNESSolve(next->snes,B,Y);
138: SNESGetConvergedReason(next->snes,&reason);
139: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
140: snes->reason = SNES_DIVERGED_INNER;
141: return(0);
142: }
143: VecAXPY(Y,-1.0,Xorig);
144: VecAXPY(X,next->dmp,Y);
145: while (next->next) {
146: next = next->next;
147: VecCopy(Xorig,Y);
148: SNESSolve(next->snes,B,Y);
149: SNESGetConvergedReason(next->snes,&reason);
150: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
151: snes->reason = SNES_DIVERGED_INNER;
152: return(0);
153: }
154: VecAXPY(Y,-1.0,Xorig);
155: VecAXPY(X,next->dmp,Y);
156: }
157: if (snes->normschedule == SNES_NORM_ALWAYS) {
158: SNESComputeFunction(snes,X,F);
159: if (fnorm) {VecNorm(F,NORM_2,fnorm);}
160: }
161: return(0);
162: }
166: /* approximately solve the overdetermined system:
168: 2*F(x_i)\cdot F(\x_j)\alpha_i = 0
169: \alpha_i = 1
171: Which minimizes the L2 norm of the linearization of:
172: ||F(\sum_i \alpha_i*x_i)||^2
174: With the constraint that \sum_i\alpha_i = 1
175: Where x_i is the solution from the ith subsolver.
176: */
177: static PetscErrorCode SNESCompositeApply_AdditiveOptimal(SNES snes,Vec X,Vec B,Vec F,PetscReal *fnorm)
178: {
179: PetscErrorCode ierr;
180: SNES_Composite *jac = (SNES_Composite*)snes->data;
181: SNES_CompositeLink next = jac->head;
182: Vec *Xes = jac->Xes,*Fes = jac->Fes;
183: PetscInt i,j;
184: PetscScalar tot,total,ftf;
185: PetscReal min_fnorm;
186: PetscInt min_i;
187: SNESConvergedReason reason;
190: if (!next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"No composite SNESes supplied via SNESCompositeAddSNES() or -snes_composite_sneses");
192: if (snes->normschedule == SNES_NORM_ALWAYS) {
193: next = jac->head;
194: SNESSetInitialFunction(next->snes,F);
195: while (next->next) {
196: next = next->next;
197: SNESSetInitialFunction(next->snes,F);
198: }
199: }
201: next = jac->head;
202: i = 0;
203: VecCopy(X,Xes[i]);
204: SNESSolve(next->snes,B,Xes[i]);
205: SNESGetConvergedReason(next->snes,&reason);
206: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
207: snes->reason = SNES_DIVERGED_INNER;
208: return(0);
209: }
210: while (next->next) {
211: i++;
212: next = next->next;
213: VecCopy(X,Xes[i]);
214: SNESSolve(next->snes,B,Xes[i]);
215: SNESGetConvergedReason(next->snes,&reason);
216: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
217: snes->reason = SNES_DIVERGED_INNER;
218: return(0);
219: }
220: }
222: /* all the solutions are collected; combine optimally */
223: for (i=0;i<jac->n;i++) {
224: for (j=0;j<i+1;j++) {
225: VecDotBegin(Fes[i],Fes[j],&jac->h[i + j*jac->n]);
226: }
227: VecDotBegin(Fes[i],F,&jac->g[i]);
228: }
230: for (i=0;i<jac->n;i++) {
231: for (j=0;j<i+1;j++) {
232: VecDotEnd(Fes[i],Fes[j],&jac->h[i + j*jac->n]);
233: if (i == j) jac->fnorms[i] = PetscSqrtReal(PetscRealPart(jac->h[i + j*jac->n]));
234: }
235: VecDotEnd(Fes[i],F,&jac->g[i]);
236: }
238: ftf = (*fnorm)*(*fnorm);
240: for (i=0; i<jac->n; i++) {
241: for (j=i+1;j<jac->n;j++) {
242: jac->h[i + j*jac->n] = jac->h[j + i*jac->n];
243: }
244: }
246: for (i=0; i<jac->n; i++) {
247: for (j=0; j<jac->n; j++) {
248: jac->h[i + j*jac->n] = jac->h[i + j*jac->n] - jac->g[j] - jac->g[i] + ftf;
249: }
250: jac->beta[i] = ftf - jac->g[i];
251: }
253: #if defined(PETSC_MISSING_LAPACK_GELSS)
254: SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"SNESCOMPOSITE with ADDITIVEOPTIMAL requires the LAPACK GELSS routine.");
255: #else
256: jac->info = 0;
257: jac->rcond = -1.;
258: PetscFPTrapPush(PETSC_FP_TRAP_OFF);
259: #if defined(PETSC_USE_COMPLEX)
260: 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));
261: #else
262: 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));
263: #endif
264: PetscFPTrapPop();
265: if (jac->info < 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"Bad argument to GELSS");
266: if (jac->info > 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD failed to converge");
267: #endif
268: tot = 0.;
269: total = 0.;
270: for (i=0; i<jac->n; i++) {
271: if (PetscIsInfOrNanScalar(jac->beta[i])) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD generated inconsistent output");
272: PetscInfo2(snes,"%d: %f\n",i,PetscRealPart(jac->beta[i]));
273: tot += jac->beta[i];
274: total += PetscAbsScalar(jac->beta[i]);
275: }
276: VecScale(X,(1. - tot));
277: VecMAXPY(X,jac->n,jac->beta,Xes);
278: SNESComputeFunction(snes,X,F);
279: VecNorm(F,NORM_2,fnorm);
281: /* take the minimum-normed candidate if it beats the combination by a factor of rtol or the combination has stagnated */
282: min_fnorm = jac->fnorms[0];
283: min_i = 0;
284: for (i=0; i<jac->n; i++) {
285: if (jac->fnorms[i] < min_fnorm) {
286: min_fnorm = jac->fnorms[i];
287: min_i = i;
288: }
289: }
291: /* stagnation or divergence restart to the solution of the solver that failed the least */
292: if (PetscRealPart(total) < jac->stol || min_fnorm*jac->rtol < *fnorm) {
293: VecCopy(jac->Xes[min_i],X);
294: VecCopy(jac->Fes[min_i],F);
295: *fnorm = min_fnorm;
296: }
297: return(0);
298: }
302: static PetscErrorCode SNESSetUp_Composite(SNES snes)
303: {
304: PetscErrorCode ierr;
305: DM dm;
306: SNES_Composite *jac = (SNES_Composite*)snes->data;
307: SNES_CompositeLink next = jac->head;
308: PetscInt n=0,i;
309: Vec F;
312: SNESGetDM(snes,&dm);
313: while (next) {
314: n++;
315: SNESSetDM(next->snes,dm);
316: SNESSetFromOptions(next->snes);
317: next = next->next;
318: }
319: jac->nsnes = n;
320: SNESGetFunction(snes,&F,NULL,NULL);
321: if (jac->type == SNES_COMPOSITE_ADDITIVEOPTIMAL) {
322: VecDuplicateVecs(F,jac->nsnes,&jac->Xes);
323: PetscMalloc(sizeof(Vec)*n,&jac->Fes);
324: PetscMalloc(sizeof(PetscReal)*n,&jac->fnorms);
325: next = jac->head;
326: i = 0;
327: while (next) {
328: SNESGetFunction(next->snes,&F,NULL,NULL);
329: jac->Fes[i] = F;
330: PetscObjectReference((PetscObject)F);
331: next = next->next;
332: i++;
333: }
334: /* allocate the subspace direct solve area */
335: jac->nrhs = 1;
336: jac->lda = jac->nsnes;
337: jac->ldb = jac->nsnes;
338: jac->n = jac->nsnes;
340: PetscMalloc1(jac->n*jac->n,&jac->h);
341: PetscMalloc1(jac->n,&jac->beta);
342: PetscMalloc1(jac->n,&jac->s);
343: PetscMalloc1(jac->n,&jac->g);
344: jac->lwork = 12*jac->n;
345: #if PETSC_USE_COMPLEX
346: PetscMalloc(sizeof(PetscReal)*jac->lwork,&jac->rwork);
347: #endif
348: PetscMalloc(sizeof(PetscScalar)*jac->lwork,&jac->work);
349: }
351: return(0);
352: }
356: static PetscErrorCode SNESReset_Composite(SNES snes)
357: {
358: SNES_Composite *jac = (SNES_Composite*)snes->data;
359: PetscErrorCode ierr;
360: SNES_CompositeLink next = jac->head;
363: while (next) {
364: SNESReset(next->snes);
365: next = next->next;
366: }
367: VecDestroy(&jac->Xorig);
368: if (jac->Xes) {VecDestroyVecs(jac->nsnes,&jac->Xes);}
369: if (jac->Fes) {VecDestroyVecs(jac->nsnes,&jac->Fes);}
370: PetscFree(jac->fnorms);
371: PetscFree(jac->h);
372: PetscFree(jac->s);
373: PetscFree(jac->g);
374: PetscFree(jac->beta);
375: PetscFree(jac->work);
376: PetscFree(jac->rwork);
378: return(0);
379: }
383: static PetscErrorCode SNESDestroy_Composite(SNES snes)
384: {
385: SNES_Composite *jac = (SNES_Composite*)snes->data;
386: PetscErrorCode ierr;
387: SNES_CompositeLink next = jac->head,next_tmp;
390: SNESReset_Composite(snes);
391: while (next) {
392: SNESDestroy(&next->snes);
393: next_tmp = next;
394: next = next->next;
395: PetscFree(next_tmp);
396: }
397: PetscFree(snes->data);
398: return(0);
399: }
403: static PetscErrorCode SNESSetFromOptions_Composite(SNES snes)
404: {
405: SNES_Composite *jac = (SNES_Composite*)snes->data;
406: PetscErrorCode ierr;
407: PetscInt nmax = 8,i;
408: SNES_CompositeLink next;
409: char *sneses[8];
410: PetscReal dmps[8];
411: PetscBool flg;
414: PetscOptionsHead("Composite preconditioner options");
415: PetscOptionsEnum("-snes_composite_type","Type of composition","SNESCompositeSetType",SNESCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);
416: if (flg) {
417: SNESCompositeSetType(snes,jac->type);
418: }
419: PetscOptionsStringArray("-snes_composite_sneses","List of composite solvers","SNESCompositeAddSNES",sneses,&nmax,&flg);
420: if (flg) {
421: for (i=0; i<nmax; i++) {
422: SNESCompositeAddSNES(snes,sneses[i]);
423: PetscFree(sneses[i]); /* deallocate string sneses[i], which is allocated in PetscOptionsStringArray() */
424: }
425: }
426: PetscOptionsRealArray("-snes_composite_damping","Damping of the additive composite solvers","SNESCompositeSetDamping",dmps,&nmax,&flg);
427: if (flg) {
428: for (i=0; i<nmax; i++) {
429: SNESCompositeSetDamping(snes,i,dmps[i]);
430: }
431: }
432: PetscOptionsReal("-snes_composite_stol","Step tolerance for restart on the additive composite solvers","",jac->stol,&jac->stol,NULL);
433: PetscOptionsReal("-snes_composite_rtol","Residual tolerance for the additive composite solvers","",jac->rtol,&jac->rtol,NULL);
434: PetscOptionsTail();
436: next = jac->head;
437: while (next) {
438: SNESSetFromOptions(next->snes);
439: next = next->next;
440: }
441: return(0);
442: }
446: static PetscErrorCode SNESView_Composite(SNES snes,PetscViewer viewer)
447: {
448: SNES_Composite *jac = (SNES_Composite*)snes->data;
449: PetscErrorCode ierr;
450: SNES_CompositeLink next = jac->head;
451: PetscBool iascii;
454: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
455: if (iascii) {
456: PetscViewerASCIIPrintf(viewer,"Composite SNES type - %s\n",SNESCompositeTypes[jac->type]);
457: PetscViewerASCIIPrintf(viewer,"SNESes on composite preconditioner follow\n");
458: PetscViewerASCIIPrintf(viewer,"---------------------------------\n");
459: }
460: if (iascii) {
461: PetscViewerASCIIPushTab(viewer);
462: }
463: while (next) {
464: SNESView(next->snes,viewer);
465: next = next->next;
466: }
467: if (iascii) {
468: PetscViewerASCIIPopTab(viewer);
469: PetscViewerASCIIPrintf(viewer,"---------------------------------\n");
470: }
471: return(0);
472: }
474: /* ------------------------------------------------------------------------------*/
478: static PetscErrorCode SNESCompositeSetType_Composite(SNES snes,SNESCompositeType type)
479: {
480: SNES_Composite *jac = (SNES_Composite*)snes->data;
483: jac->type = type;
484: return(0);
485: }
489: static PetscErrorCode SNESCompositeAddSNES_Composite(SNES snes,SNESType type)
490: {
491: SNES_Composite *jac;
492: SNES_CompositeLink next,ilink;
493: PetscErrorCode ierr;
494: PetscInt cnt = 0;
495: const char *prefix;
496: char newprefix[8];
497: DM dm;
500: PetscNewLog(snes,&ilink);
501: ilink->next = 0;
502: SNESCreate(PetscObjectComm((PetscObject)snes),&ilink->snes);
503: PetscLogObjectParent((PetscObject)snes,(PetscObject)ilink->snes);
504: SNESGetDM(snes,&dm);
505: SNESSetDM(ilink->snes,dm);
506: SNESSetTolerances(ilink->snes,ilink->snes->abstol,ilink->snes->rtol,ilink->snes->stol,1,ilink->snes->max_funcs);
507: jac = (SNES_Composite*)snes->data;
508: next = jac->head;
509: if (!next) {
510: jac->head = ilink;
511: ilink->previous = NULL;
512: } else {
513: cnt++;
514: while (next->next) {
515: next = next->next;
516: cnt++;
517: }
518: next->next = ilink;
519: ilink->previous = next;
520: }
521: SNESGetOptionsPrefix(snes,&prefix);
522: SNESSetOptionsPrefix(ilink->snes,prefix);
523: sprintf(newprefix,"sub_%d_",(int)cnt);
524: SNESAppendOptionsPrefix(ilink->snes,newprefix);
525: PetscObjectIncrementTabLevel((PetscObject)ilink->snes,(PetscObject)snes,1);
526: SNESSetType(ilink->snes,type);
527: SNESSetNormSchedule(ilink->snes, SNES_NORM_FINAL_ONLY);
528: ilink->dmp = 1.0;
529: jac->nsnes++;
530: return(0);
531: }
535: static PetscErrorCode SNESCompositeGetSNES_Composite(SNES snes,PetscInt n,SNES *subsnes)
536: {
537: SNES_Composite *jac;
538: SNES_CompositeLink next;
539: PetscInt i;
542: jac = (SNES_Composite*)snes->data;
543: next = jac->head;
544: for (i=0; i<n; i++) {
545: if (!next->next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Not enough SNESes in composite preconditioner");
546: next = next->next;
547: }
548: *subsnes = next->snes;
549: return(0);
550: }
552: /* -------------------------------------------------------------------------------- */
555: /*@C
556: SNESCompositeSetType - Sets the type of composite preconditioner.
558: Logically Collective on SNES
560: Input Parameter:
561: + snes - the preconditioner context
562: - type - SNES_COMPOSITE_ADDITIVE (default), SNES_COMPOSITE_MULTIPLICATIVE
564: Options Database Key:
565: . -snes_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
567: Level: Developer
569: .keywords: SNES, set, type, composite preconditioner, additive, multiplicative
570: @*/
571: PetscErrorCode SNESCompositeSetType(SNES snes,SNESCompositeType type)
572: {
578: PetscTryMethod(snes,"SNESCompositeSetType_C",(SNES,SNESCompositeType),(snes,type));
579: return(0);
580: }
584: /*@C
585: SNESCompositeAddSNES - Adds another SNES to the composite SNES.
587: Collective on SNES
589: Input Parameters:
590: + snes - the preconditioner context
591: - type - the type of the new preconditioner
593: Level: Developer
595: .keywords: SNES, composite preconditioner, add
596: @*/
597: PetscErrorCode SNESCompositeAddSNES(SNES snes,SNESType type)
598: {
603: PetscTryMethod(snes,"SNESCompositeAddSNES_C",(SNES,SNESType),(snes,type));
604: return(0);
605: }
608: /*@
609: SNESCompositeGetSNES - Gets one of the SNES objects in the composite SNES.
611: Not Collective
613: Input Parameter:
614: + snes - the preconditioner context
615: - n - the number of the snes requested
617: Output Parameters:
618: . subsnes - the SNES requested
620: Level: Developer
622: .keywords: SNES, get, composite preconditioner, sub preconditioner
624: .seealso: SNESCompositeAddSNES()
625: @*/
626: PetscErrorCode SNESCompositeGetSNES(SNES snes,PetscInt n,SNES *subsnes)
627: {
633: PetscUseMethod(snes,"SNESCompositeGetSNES_C",(SNES,PetscInt,SNES*),(snes,n,subsnes));
634: return(0);
635: }
639: static PetscErrorCode SNESCompositeSetDamping_Composite(SNES snes,PetscInt n,PetscReal dmp)
640: {
641: SNES_Composite *jac;
642: SNES_CompositeLink next;
643: PetscInt i;
646: jac = (SNES_Composite*)snes->data;
647: next = jac->head;
648: for (i=0; i<n; i++) {
649: if (!next->next) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Not enough SNESes in composite preconditioner");
650: next = next->next;
651: }
652: next->dmp = dmp;
653: return(0);
654: }
658: /*@
659: SNESCompositeSetDamping - Sets the damping of a subsolver when using additive composite SNES.
661: Not Collective
663: Input Parameter:
664: + snes - the preconditioner context
665: . n - the number of the snes requested
666: - dmp - the damping
668: Level: Developer
670: .keywords: SNES, get, composite preconditioner, sub preconditioner
672: .seealso: SNESCompositeAddSNES()
673: @*/
674: PetscErrorCode SNESCompositeSetDamping(SNES snes,PetscInt n,PetscReal dmp)
675: {
680: PetscUseMethod(snes,"SNESCompositeSetDamping_C",(SNES,PetscInt,PetscReal),(snes,n,dmp));
681: return(0);
682: }
686: PetscErrorCode SNESSolve_Composite(SNES snes)
687: {
688: Vec F;
689: Vec X;
690: Vec B;
691: PetscInt i;
692: PetscReal fnorm = 0.0;
694: SNESNormSchedule normtype;
695: SNES_Composite *comp = (SNES_Composite*)snes->data;
698: X = snes->vec_sol;
699: F = snes->vec_func;
700: B = snes->vec_rhs;
702: PetscObjectSAWsTakeAccess((PetscObject)snes);
703: snes->iter = 0;
704: snes->norm = 0.;
705: PetscObjectSAWsGrantAccess((PetscObject)snes);
706: snes->reason = SNES_CONVERGED_ITERATING;
707: SNESGetNormSchedule(snes, &normtype);
708: if (normtype == SNES_NORM_ALWAYS || normtype == SNES_NORM_INITIAL_ONLY || normtype == SNES_NORM_INITIAL_FINAL_ONLY) {
709: if (!snes->vec_func_init_set) {
710: SNESComputeFunction(snes,X,F);
711: if (snes->domainerror) {
712: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
713: return(0);
714: }
715: } else snes->vec_func_init_set = PETSC_FALSE;
717: VecNorm(F, NORM_2, &fnorm); /* fnorm <- ||F|| */
718: if (PetscIsInfOrNanReal(fnorm)) {
719: snes->reason = SNES_DIVERGED_FNORM_NAN;
720: return(0);
721: }
722: PetscObjectSAWsTakeAccess((PetscObject)snes);
723: snes->iter = 0;
724: snes->norm = fnorm;
725: PetscObjectSAWsGrantAccess((PetscObject)snes);
726: SNESLogConvergenceHistory(snes,snes->norm,0);
727: SNESMonitor(snes,0,snes->norm);
729: /* test convergence */
730: (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
731: if (snes->reason) return(0);
732: } else {
733: PetscObjectSAWsGrantAccess((PetscObject)snes);
734: SNESLogConvergenceHistory(snes,snes->norm,0);
735: SNESMonitor(snes,0,snes->norm);
736: }
738: /* Call general purpose update function */
739: if (snes->ops->update) {
740: (*snes->ops->update)(snes, snes->iter);
741: }
743: for (i = 0; i < snes->max_its; i++) {
744: if (comp->type == SNES_COMPOSITE_ADDITIVE) {
745: SNESCompositeApply_Additive(snes,X,B,F,&fnorm);
746: } else if (comp->type == SNES_COMPOSITE_MULTIPLICATIVE) {
747: SNESCompositeApply_Multiplicative(snes,X,B,F,&fnorm);
748: } else if (comp->type == SNES_COMPOSITE_ADDITIVEOPTIMAL) {
749: SNESCompositeApply_AdditiveOptimal(snes,X,B,F,&fnorm);
750: } else {
751: SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Unsupported SNESComposite type");
752: }
753: if (snes->reason < 0) break;
755: if ((i == snes->max_its - 1) && (normtype == SNES_NORM_INITIAL_FINAL_ONLY || normtype == SNES_NORM_FINAL_ONLY)) {
756: SNESComputeFunction(snes,X,F);
757: if (snes->domainerror) {
758: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
759: break;
760: }
761: VecNorm(F, NORM_2, &fnorm);
762: if (PetscIsInfOrNanReal(fnorm)) {
763: snes->reason = SNES_DIVERGED_FNORM_NAN;
764: break;
765: }
766: }
767: /* Monitor convergence */
768: PetscObjectSAWsTakeAccess((PetscObject)snes);
769: snes->iter = i+1;
770: snes->norm = fnorm;
771: PetscObjectSAWsGrantAccess((PetscObject)snes);
772: SNESLogConvergenceHistory(snes,snes->norm,0);
773: SNESMonitor(snes,snes->iter,snes->norm);
774: /* Test for convergence */
775: if (normtype == SNES_NORM_ALWAYS) {(*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);}
776: if (snes->reason) break;
777: /* Call general purpose update function */
778: if (snes->ops->update) {(*snes->ops->update)(snes, snes->iter);}
779: }
780: if (normtype == SNES_NORM_ALWAYS) {
781: if (i == snes->max_its) {
782: PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",snes->max_its);
783: if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
784: }
785: } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS;
786: return(0);
787: }
789: /* -------------------------------------------------------------------------------------------*/
791: /*MC
792: SNESCOMPOSITE - Build a preconditioner by composing together several nonlinear solvers
794: Options Database Keys:
795: + -snes_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
796: - -snes_composite_sneses - <snes0,snes1,...> list of SNESes to compose
798: Level: intermediate
800: Concepts: composing solvers
802: .seealso: SNESCreate(), SNESSetType(), SNESType (for list of available types), SNES,
803: SNESSHELL, SNESCompositeSetType(), SNESCompositeSpecialSetAlpha(), SNESCompositeAddSNES(),
804: SNESCompositeGetSNES()
806: M*/
810: PETSC_EXTERN PetscErrorCode SNESCreate_Composite(SNES snes)
811: {
813: SNES_Composite *jac;
816: PetscNewLog(snes,&jac);
818: snes->ops->solve = SNESSolve_Composite;
819: snes->ops->setup = SNESSetUp_Composite;
820: snes->ops->reset = SNESReset_Composite;
821: snes->ops->destroy = SNESDestroy_Composite;
822: snes->ops->setfromoptions = SNESSetFromOptions_Composite;
823: snes->ops->view = SNESView_Composite;
825: snes->data = (void*)jac;
826: jac->type = SNES_COMPOSITE_ADDITIVEOPTIMAL;
827: jac->Fes = NULL;
828: jac->Xes = NULL;
829: jac->fnorms = NULL;
830: jac->nsnes = 0;
831: jac->head = 0;
832: jac->stol = 0.1;
833: jac->rtol = 1.1;
835: jac->h = NULL;
836: jac->s = NULL;
837: jac->beta = NULL;
838: jac->work = NULL;
839: jac->rwork = NULL;
841: PetscObjectComposeFunction((PetscObject)snes,"SNESCompositeSetType_C",SNESCompositeSetType_Composite);
842: PetscObjectComposeFunction((PetscObject)snes,"SNESCompositeAddSNES_C",SNESCompositeAddSNES_Composite);
843: PetscObjectComposeFunction((PetscObject)snes,"SNESCompositeGetSNES_C",SNESCompositeGetSNES_Composite);
844: PetscObjectComposeFunction((PetscObject)snes,"SNESCompositeSetDamping_C",SNESCompositeSetDamping_Composite);
845: return(0);
846: }