Actual source code: snescomposite.c

petsc-dev 2014-02-02
Report Typos and Errors
  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: }