Actual source code: virs.c
petsc-3.15.0 2021-03-30
2: #include <../src/snes/impls/vi/rs/virsimpl.h>
3: #include <petsc/private/dmimpl.h>
4: #include <petsc/private/vecimpl.h>
6: /*
7: SNESVIGetInactiveSet - Gets the global indices for the inactive set variables (these correspond to the degrees of freedom the linear
8: system is solved on)
10: Input parameter:
11: . snes - the SNES context
13: Output parameter:
14: . inact - inactive set index set
16: */
17: PetscErrorCode SNESVIGetInactiveSet(SNES snes,IS *inact)
18: {
19: SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data;
22: *inact = vi->IS_inact;
23: return(0);
24: }
26: /*
27: Provides a wrapper to a DM to allow it to be used to generated the interpolation/restriction from the DM for the smaller matrices and vectors
28: defined by the reduced space method.
30: Simple calls the regular DM interpolation and restricts it to operation on the variables not associated with active constraints.
32: <*/
33: typedef struct {
34: PetscInt n; /* size of vectors in the reduced DM space */
35: IS inactive;
37: PetscErrorCode (*createinterpolation)(DM,DM,Mat*,Vec*); /* DM's original routines */
38: PetscErrorCode (*coarsen)(DM, MPI_Comm, DM*);
39: PetscErrorCode (*createglobalvector)(DM,Vec*);
40: PetscErrorCode (*createinjection)(DM,DM,Mat*);
41: PetscErrorCode (*hascreateinjection)(DM,PetscBool*);
43: DM dm; /* when destroying this object we need to reset the above function into the base DM */
44: } DM_SNESVI;
46: /*
47: DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space
49: */
50: PetscErrorCode DMCreateGlobalVector_SNESVI(DM dm,Vec *vec)
51: {
53: PetscContainer isnes;
54: DM_SNESVI *dmsnesvi;
57: PetscObjectQuery((PetscObject)dm,"VI",(PetscObject*)&isnes);
58: if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Composed SNES is missing");
59: PetscContainerGetPointer(isnes,(void**)&dmsnesvi);
60: VecCreateMPI(PetscObjectComm((PetscObject)dm),dmsnesvi->n,PETSC_DETERMINE,vec);
61: VecSetDM(*vec, dm);
62: return(0);
63: }
65: /*
66: DMCreateInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.
68: */
69: PetscErrorCode DMCreateInterpolation_SNESVI(DM dm1,DM dm2,Mat *mat,Vec *vec)
70: {
72: PetscContainer isnes;
73: DM_SNESVI *dmsnesvi1,*dmsnesvi2;
74: Mat interp;
77: PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject*)&isnes);
78: if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_PLIB,"Composed VI data structure is missing");
79: PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);
80: PetscObjectQuery((PetscObject)dm2,"VI",(PetscObject*)&isnes);
81: if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm2),PETSC_ERR_PLIB,"Composed VI data structure is missing");
82: PetscContainerGetPointer(isnes,(void**)&dmsnesvi2);
84: (*dmsnesvi1->createinterpolation)(dm1,dm2,&interp,NULL);
85: MatCreateSubMatrix(interp,dmsnesvi2->inactive,dmsnesvi1->inactive,MAT_INITIAL_MATRIX,mat);
86: MatDestroy(&interp);
87: *vec = NULL;
88: return(0);
89: }
91: static PetscErrorCode DMSetVI(DM,IS);
92: static PetscErrorCode DMDestroyVI(DM);
94: /*
95: DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set
97: */
98: PetscErrorCode DMCoarsen_SNESVI(DM dm1,MPI_Comm comm,DM *dm2)
99: {
101: PetscContainer isnes;
102: DM_SNESVI *dmsnesvi1;
103: Vec finemarked,coarsemarked;
104: IS inactive;
105: Mat inject;
106: const PetscInt *index;
107: PetscInt n,k,cnt = 0,rstart,*coarseindex;
108: PetscScalar *marked;
111: PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject*)&isnes);
112: if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_PLIB,"Composed VI data structure is missing");
113: PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);
115: /* get the original coarsen */
116: (*dmsnesvi1->coarsen)(dm1,comm,dm2);
118: /* not sure why this extra reference is needed, but without the dm2 disappears too early */
119: /* Updating the KSPCreateVecs() to avoid using DMGetGlobalVector() when matrix is available removes the need for this reference? */
120: /* PetscObjectReference((PetscObject)*dm2);*/
122: /* need to set back global vectors in order to use the original injection */
123: DMClearGlobalVectors(dm1);
125: dm1->ops->createglobalvector = dmsnesvi1->createglobalvector;
127: DMCreateGlobalVector(dm1,&finemarked);
128: DMCreateGlobalVector(*dm2,&coarsemarked);
130: /*
131: fill finemarked with locations of inactive points
132: */
133: ISGetIndices(dmsnesvi1->inactive,&index);
134: ISGetLocalSize(dmsnesvi1->inactive,&n);
135: VecSet(finemarked,0.0);
136: for (k=0; k<n; k++) {
137: VecSetValue(finemarked,index[k],1.0,INSERT_VALUES);
138: }
139: VecAssemblyBegin(finemarked);
140: VecAssemblyEnd(finemarked);
142: DMCreateInjection(*dm2,dm1,&inject);
143: MatRestrict(inject,finemarked,coarsemarked);
144: MatDestroy(&inject);
146: /*
147: create index set list of coarse inactive points from coarsemarked
148: */
149: VecGetLocalSize(coarsemarked,&n);
150: VecGetOwnershipRange(coarsemarked,&rstart,NULL);
151: VecGetArray(coarsemarked,&marked);
152: for (k=0; k<n; k++) {
153: if (marked[k] != 0.0) cnt++;
154: }
155: PetscMalloc1(cnt,&coarseindex);
156: cnt = 0;
157: for (k=0; k<n; k++) {
158: if (marked[k] != 0.0) coarseindex[cnt++] = k + rstart;
159: }
160: VecRestoreArray(coarsemarked,&marked);
161: ISCreateGeneral(PetscObjectComm((PetscObject)coarsemarked),cnt,coarseindex,PETSC_OWN_POINTER,&inactive);
163: DMClearGlobalVectors(dm1);
165: dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
167: DMSetVI(*dm2,inactive);
169: VecDestroy(&finemarked);
170: VecDestroy(&coarsemarked);
171: ISDestroy(&inactive);
172: return(0);
173: }
175: PetscErrorCode DMDestroy_SNESVI(DM_SNESVI *dmsnesvi)
176: {
180: /* reset the base methods in the DM object that were changed when the DM_SNESVI was reset */
181: dmsnesvi->dm->ops->createinterpolation = dmsnesvi->createinterpolation;
182: dmsnesvi->dm->ops->coarsen = dmsnesvi->coarsen;
183: dmsnesvi->dm->ops->createglobalvector = dmsnesvi->createglobalvector;
184: dmsnesvi->dm->ops->createinjection = dmsnesvi->createinjection;
185: dmsnesvi->dm->ops->hascreateinjection = dmsnesvi->hascreateinjection;
186: /* need to clear out this vectors because some of them may not have a reference to the DM
187: but they are counted as having references to the DM in DMDestroy() */
188: DMClearGlobalVectors(dmsnesvi->dm);
190: ISDestroy(&dmsnesvi->inactive);
191: PetscFree(dmsnesvi);
192: return(0);
193: }
195: /*
196: DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to
197: be restricted to only those variables NOT associated with active constraints.
199: */
200: static PetscErrorCode DMSetVI(DM dm,IS inactive)
201: {
203: PetscContainer isnes;
204: DM_SNESVI *dmsnesvi;
207: if (!dm) return(0);
209: PetscObjectReference((PetscObject)inactive);
211: PetscObjectQuery((PetscObject)dm,"VI",(PetscObject*)&isnes);
212: if (!isnes) {
213: PetscContainerCreate(PetscObjectComm((PetscObject)dm),&isnes);
214: PetscContainerSetUserDestroy(isnes,(PetscErrorCode (*)(void*))DMDestroy_SNESVI);
215: PetscNew(&dmsnesvi);
216: PetscContainerSetPointer(isnes,(void*)dmsnesvi);
217: PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)isnes);
218: PetscContainerDestroy(&isnes);
220: dmsnesvi->createinterpolation = dm->ops->createinterpolation;
221: dm->ops->createinterpolation = DMCreateInterpolation_SNESVI;
222: dmsnesvi->coarsen = dm->ops->coarsen;
223: dm->ops->coarsen = DMCoarsen_SNESVI;
224: dmsnesvi->createglobalvector = dm->ops->createglobalvector;
225: dm->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
226: dmsnesvi->createinjection = dm->ops->createinjection;
227: dm->ops->createinjection = NULL;
228: dmsnesvi->hascreateinjection = dm->ops->hascreateinjection;
229: dm->ops->hascreateinjection = NULL;
230: } else {
231: PetscContainerGetPointer(isnes,(void**)&dmsnesvi);
232: ISDestroy(&dmsnesvi->inactive);
233: }
234: DMClearGlobalVectors(dm);
235: ISGetLocalSize(inactive,&dmsnesvi->n);
237: dmsnesvi->inactive = inactive;
238: dmsnesvi->dm = dm;
239: return(0);
240: }
242: /*
243: DMDestroyVI - Frees the DM_SNESVI object contained in the DM
244: - also resets the function pointers in the DM for createinterpolation() etc to use the original DM
245: */
246: static PetscErrorCode DMDestroyVI(DM dm)
247: {
251: if (!dm) return(0);
252: PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)NULL);
253: return(0);
254: }
256: /* --------------------------------------------------------------------------------------------------------*/
259: PetscErrorCode SNESCreateIndexSets_VINEWTONRSLS(SNES snes,Vec X,Vec F,IS *ISact,IS *ISinact)
260: {
264: SNESVIGetActiveSetIS(snes,X,F,ISact);
265: ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);
266: return(0);
267: }
269: /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
270: PetscErrorCode SNESCreateSubVectors_VINEWTONRSLS(SNES snes,PetscInt n,Vec *newv)
271: {
273: Vec v;
276: VecCreate(PetscObjectComm((PetscObject)snes),&v);
277: VecSetSizes(v,n,PETSC_DECIDE);
278: VecSetType(v,VECSTANDARD);
279: *newv = v;
280: return(0);
281: }
283: /* Resets the snes PC and KSP when the active set sizes change */
284: PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)
285: {
287: KSP snesksp;
290: SNESGetKSP(snes,&snesksp);
291: KSPReset(snesksp);
292: KSPResetFromOptions(snesksp);
294: /*
295: KSP kspnew;
296: PC pcnew;
297: MatSolverType stype;
300: KSPCreate(PetscObjectComm((PetscObject)snes),&kspnew);
301: kspnew->pc_side = snesksp->pc_side;
302: kspnew->rtol = snesksp->rtol;
303: kspnew->abstol = snesksp->abstol;
304: kspnew->max_it = snesksp->max_it;
305: KSPSetType(kspnew,((PetscObject)snesksp)->type_name);
306: KSPGetPC(kspnew,&pcnew);
307: PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);
308: PCSetOperators(kspnew->pc,Amat,Pmat);
309: PCFactorGetMatSolverType(snesksp->pc,&stype);
310: PCFactorSetMatSolverType(kspnew->pc,stype);
311: KSPDestroy(&snesksp);
312: snes->ksp = kspnew;
313: PetscLogObjectParent((PetscObject)snes,(PetscObject)kspnew);
314: KSPSetFromOptions(kspnew);*/
315: return(0);
316: }
318: /* Variational Inequality solver using reduce space method. No semismooth algorithm is
319: implemented in this algorithm. It basically identifies the active constraints and does
320: a linear solve on the other variables (those not associated with the active constraints). */
321: PetscErrorCode SNESSolve_VINEWTONRSLS(SNES snes)
322: {
323: SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data;
324: PetscErrorCode ierr;
325: PetscInt maxits,i,lits;
326: SNESLineSearchReason lssucceed;
327: PetscReal fnorm,gnorm,xnorm=0,ynorm;
328: Vec Y,X,F;
329: KSPConvergedReason kspreason;
330: KSP ksp;
331: PC pc;
334: /* Multigrid must use Galerkin for coarse grids with active set/reduced space methods; cannot rediscretize on coarser grids*/
335: SNESGetKSP(snes,&ksp);
336: KSPGetPC(ksp,&pc);
337: PCMGSetGalerkin(pc,PC_MG_GALERKIN_BOTH);
339: snes->numFailures = 0;
340: snes->numLinearSolveFailures = 0;
341: snes->reason = SNES_CONVERGED_ITERATING;
343: maxits = snes->max_its; /* maximum number of iterations */
344: X = snes->vec_sol; /* solution vector */
345: F = snes->vec_func; /* residual vector */
346: Y = snes->work[0]; /* work vectors */
348: SNESLineSearchSetVIFunctions(snes->linesearch, SNESVIProjectOntoBounds, SNESVIComputeInactiveSetFnorm);
349: SNESLineSearchSetVecs(snes->linesearch, X, NULL, NULL, NULL, NULL);
350: SNESLineSearchSetUp(snes->linesearch);
352: PetscObjectSAWsTakeAccess((PetscObject)snes);
353: snes->iter = 0;
354: snes->norm = 0.0;
355: PetscObjectSAWsGrantAccess((PetscObject)snes);
357: SNESVIProjectOntoBounds(snes,X);
358: SNESComputeFunction(snes,X,F);
359: SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);
360: VecNorm(X,NORM_2,&xnorm); /* xnorm <- ||x|| */
361: SNESCheckFunctionNorm(snes,fnorm);
362: PetscObjectSAWsTakeAccess((PetscObject)snes);
363: snes->norm = fnorm;
364: PetscObjectSAWsGrantAccess((PetscObject)snes);
365: SNESLogConvergenceHistory(snes,fnorm,0);
366: SNESMonitor(snes,0,fnorm);
368: /* test convergence */
369: (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
370: if (snes->reason) return(0);
373: for (i=0; i<maxits; i++) {
375: IS IS_act; /* _act -> active set _inact -> inactive set */
376: IS IS_redact; /* redundant active set */
377: VecScatter scat_act,scat_inact;
378: PetscInt nis_act,nis_inact;
379: Vec Y_act,Y_inact,F_inact;
380: Mat jac_inact_inact,prejac_inact_inact;
381: PetscBool isequal;
383: /* Call general purpose update function */
384: if (snes->ops->update) {
385: (*snes->ops->update)(snes, snes->iter);
386: }
387: SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);
388: SNESCheckJacobianDomainerror(snes);
390: /* Create active and inactive index sets */
392: /*original
393: SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&vi->IS_inact);
394: */
395: SNESVIGetActiveSetIS(snes,X,F,&IS_act);
397: if (vi->checkredundancy) {
398: (*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);
399: if (IS_redact) {
400: ISSort(IS_redact);
401: ISComplement(IS_redact,X->map->rstart,X->map->rend,&vi->IS_inact);
402: ISDestroy(&IS_redact);
403: } else {
404: ISComplement(IS_act,X->map->rstart,X->map->rend,&vi->IS_inact);
405: }
406: } else {
407: ISComplement(IS_act,X->map->rstart,X->map->rend,&vi->IS_inact);
408: }
411: /* Create inactive set submatrix */
412: MatCreateSubMatrix(snes->jacobian,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);
414: if (0) { /* Dead code (temporary developer hack) */
415: IS keptrows;
416: MatFindNonzeroRows(jac_inact_inact,&keptrows);
417: if (keptrows) {
418: PetscInt cnt,*nrows,k;
419: const PetscInt *krows,*inact;
420: PetscInt rstart;
422: MatGetOwnershipRange(jac_inact_inact,&rstart,NULL);
423: MatDestroy(&jac_inact_inact);
424: ISDestroy(&IS_act);
426: ISGetLocalSize(keptrows,&cnt);
427: ISGetIndices(keptrows,&krows);
428: ISGetIndices(vi->IS_inact,&inact);
429: PetscMalloc1(cnt,&nrows);
430: for (k=0; k<cnt; k++) nrows[k] = inact[krows[k]-rstart];
431: ISRestoreIndices(keptrows,&krows);
432: ISRestoreIndices(vi->IS_inact,&inact);
433: ISDestroy(&keptrows);
434: ISDestroy(&vi->IS_inact);
436: ISCreateGeneral(PetscObjectComm((PetscObject)snes),cnt,nrows,PETSC_OWN_POINTER,&vi->IS_inact);
437: ISComplement(vi->IS_inact,F->map->rstart,F->map->rend,&IS_act);
438: MatCreateSubMatrix(snes->jacobian,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);
439: }
440: }
441: DMSetVI(snes->dm,vi->IS_inact);
442: /* remove later */
444: /*
445: VecView(vi->xu,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xu))->comm));
446: VecView(vi->xl,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xl))->comm));
447: VecView(X,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)X)));
448: VecView(F,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)F)));
449: ISView(vi->IS_inact,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)vi->IS_inact)));
450: */
452: /* Get sizes of active and inactive sets */
453: ISGetLocalSize(IS_act,&nis_act);
454: ISGetLocalSize(vi->IS_inact,&nis_inact);
456: /* Create active and inactive set vectors */
457: SNESCreateSubVectors_VINEWTONRSLS(snes,nis_inact,&F_inact);
458: SNESCreateSubVectors_VINEWTONRSLS(snes,nis_act,&Y_act);
459: SNESCreateSubVectors_VINEWTONRSLS(snes,nis_inact,&Y_inact);
461: /* Create scatter contexts */
462: VecScatterCreate(Y,IS_act,Y_act,NULL,&scat_act);
463: VecScatterCreate(Y,vi->IS_inact,Y_inact,NULL,&scat_inact);
465: /* Do a vec scatter to active and inactive set vectors */
466: VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);
467: VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);
469: VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);
470: VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);
472: VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);
473: VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);
475: /* Active set direction = 0 */
476: VecSet(Y_act,0);
477: if (snes->jacobian != snes->jacobian_pre) {
478: MatCreateSubMatrix(snes->jacobian_pre,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);
479: } else prejac_inact_inact = jac_inact_inact;
481: ISEqual(vi->IS_inact_prev,vi->IS_inact,&isequal);
482: if (!isequal) {
483: SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);
484: PCFieldSplitRestrictIS(pc,vi->IS_inact);
485: }
487: /* ISView(vi->IS_inact,0); */
488: /* ISView(IS_act,0);*/
489: /* MatView(snes->jacobian_pre,0); */
493: KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact);
494: KSPSetUp(snes->ksp);
495: {
496: PC pc;
497: PetscBool flg;
498: KSPGetPC(snes->ksp,&pc);
499: PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);
500: if (flg) {
501: KSP *subksps;
502: PCFieldSplitGetSubKSP(pc,NULL,&subksps);
503: KSPGetPC(subksps[0],&pc);
504: PetscFree(subksps);
505: PetscObjectTypeCompare((PetscObject)pc,PCBJACOBI,&flg);
506: if (flg) {
507: PetscInt n,N = 101*101,j,cnts[3] = {0,0,0};
508: const PetscInt *ii;
510: ISGetSize(vi->IS_inact,&n);
511: ISGetIndices(vi->IS_inact,&ii);
512: for (j=0; j<n; j++) {
513: if (ii[j] < N) cnts[0]++;
514: else if (ii[j] < 2*N) cnts[1]++;
515: else if (ii[j] < 3*N) cnts[2]++;
516: }
517: ISRestoreIndices(vi->IS_inact,&ii);
519: PCBJacobiSetTotalBlocks(pc,3,cnts);
520: }
521: }
522: }
524: KSPSolve(snes->ksp,F_inact,Y_inact);
525: VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);
526: VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);
527: VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);
528: VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);
530: VecDestroy(&F_inact);
531: VecDestroy(&Y_act);
532: VecDestroy(&Y_inact);
533: VecScatterDestroy(&scat_act);
534: VecScatterDestroy(&scat_inact);
535: ISDestroy(&IS_act);
536: if (!isequal) {
537: ISDestroy(&vi->IS_inact_prev);
538: ISDuplicate(vi->IS_inact,&vi->IS_inact_prev);
539: }
540: ISDestroy(&vi->IS_inact);
541: MatDestroy(&jac_inact_inact);
542: if (snes->jacobian != snes->jacobian_pre) {
543: MatDestroy(&prejac_inact_inact);
544: }
546: KSPGetConvergedReason(snes->ksp,&kspreason);
547: if (kspreason < 0) {
548: if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
549: PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);
550: snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
551: break;
552: }
553: }
555: KSPGetIterationNumber(snes->ksp,&lits);
556: snes->linear_its += lits;
557: PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);
558: /*
559: if (snes->ops->precheck) {
560: PetscBool changed_y = PETSC_FALSE;
561: (*snes->ops->precheck)(snes,X,Y,snes->precheck,&changed_y);
562: }
564: if (PetscLogPrintInfo) {
565: SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);
566: }
567: */
568: /* Compute a (scaled) negative update in the line search routine:
569: Y <- X - lambda*Y
570: and evaluate G = function(Y) (depends on the line search).
571: */
572: VecCopy(Y,snes->vec_sol_update);
573: ynorm = 1; gnorm = fnorm;
574: SNESLineSearchApply(snes->linesearch, X, F, &gnorm, Y);
575: SNESLineSearchGetReason(snes->linesearch, &lssucceed);
576: SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm);
577: PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)fnorm,(double)gnorm,(double)ynorm,(int)lssucceed);
578: if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
579: if (snes->domainerror) {
580: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
581: DMDestroyVI(snes->dm);
582: return(0);
583: }
584: if (lssucceed) {
585: if (++snes->numFailures >= snes->maxFailures) {
586: PetscBool ismin;
587: snes->reason = SNES_DIVERGED_LINE_SEARCH;
588: SNESVICheckLocalMin_Private(snes,snes->jacobian,F,X,gnorm,&ismin);
589: if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
590: break;
591: }
592: }
593: DMDestroyVI(snes->dm);
594: /* Update function and solution vectors */
595: fnorm = gnorm;
596: /* Monitor convergence */
597: PetscObjectSAWsTakeAccess((PetscObject)snes);
598: snes->iter = i+1;
599: snes->norm = fnorm;
600: snes->xnorm = xnorm;
601: snes->ynorm = ynorm;
602: PetscObjectSAWsGrantAccess((PetscObject)snes);
603: SNESLogConvergenceHistory(snes,snes->norm,lits);
604: SNESMonitor(snes,snes->iter,snes->norm);
605: /* Test for convergence, xnorm = || X || */
606: if (snes->ops->converged != SNESConvergedSkip) { VecNorm(X,NORM_2,&xnorm); }
607: (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
608: if (snes->reason) break;
609: }
610: /* make sure that the VI information attached to the DM is removed if the for loop above was broken early due to some exceptional conditional */
611: DMDestroyVI(snes->dm);
612: if (i == maxits) {
613: PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
614: if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
615: }
616: return(0);
617: }
619: PetscErrorCode SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (*func)(SNES,IS,IS*,void*),void *ctx)
620: {
621: SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data;
625: vi->checkredundancy = func;
626: vi->ctxP = ctx;
627: return(0);
628: }
630: #if defined(PETSC_HAVE_MATLAB_ENGINE)
631: #include <engine.h>
632: #include <mex.h>
633: typedef struct {char *funcname; mxArray *ctx;} SNESMatlabContext;
635: PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS *is_redact,void *ctx)
636: {
637: PetscErrorCode ierr;
638: SNESMatlabContext *sctx = (SNESMatlabContext*)ctx;
639: int nlhs = 1, nrhs = 5;
640: mxArray *plhs[1], *prhs[5];
641: long long int l1 = 0, l2 = 0, ls = 0;
642: PetscInt *indices=NULL;
650: /* Create IS for reduced active set of size 0, its size and indices will
651: bet set by the Matlab function */
652: ISCreateGeneral(PetscObjectComm((PetscObject)snes),0,indices,PETSC_OWN_POINTER,is_redact);
653: /* call Matlab function in ctx */
654: PetscArraycpy(&ls,&snes,1);
655: PetscArraycpy(&l1,&is_act,1);
656: PetscArraycpy(&l2,is_redact,1);
657: prhs[0] = mxCreateDoubleScalar((double)ls);
658: prhs[1] = mxCreateDoubleScalar((double)l1);
659: prhs[2] = mxCreateDoubleScalar((double)l2);
660: prhs[3] = mxCreateString(sctx->funcname);
661: prhs[4] = sctx->ctx;
662: mexCallMATLAB(nlhs,plhs,nrhs,prhs,"PetscSNESVIRedundancyCheckInternal");
663: mxGetScalar(plhs[0]);
664: mxDestroyArray(prhs[0]);
665: mxDestroyArray(prhs[1]);
666: mxDestroyArray(prhs[2]);
667: mxDestroyArray(prhs[3]);
668: mxDestroyArray(plhs[0]);
669: return(0);
670: }
672: PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes,const char *func,mxArray *ctx)
673: {
674: PetscErrorCode ierr;
675: SNESMatlabContext *sctx;
678: /* currently sctx is memory bleed */
679: PetscNew(&sctx);
680: PetscStrallocpy(func,&sctx->funcname);
681: sctx->ctx = mxDuplicateArray(ctx);
682: SNESVISetRedundancyCheck(snes,SNESVIRedundancyCheck_Matlab,sctx);
683: return(0);
684: }
686: #endif
688: /* -------------------------------------------------------------------------- */
689: /*
690: SNESSetUp_VINEWTONRSLS - Sets up the internal data structures for the later use
691: of the SNESVI nonlinear solver.
693: Input Parameter:
694: . snes - the SNES context
696: Application Interface Routine: SNESSetUp()
698: Notes:
699: For basic use of the SNES solvers, the user need not explicitly call
700: SNESSetUp(), since these actions will automatically occur during
701: the call to SNESSolve().
702: */
703: PetscErrorCode SNESSetUp_VINEWTONRSLS(SNES snes)
704: {
705: PetscErrorCode ierr;
706: SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*) snes->data;
707: PetscInt *indices;
708: PetscInt i,n,rstart,rend;
709: SNESLineSearch linesearch;
712: SNESSetUp_VI(snes);
714: /* Set up previous active index set for the first snes solve
715: vi->IS_inact_prev = 0,1,2,....N */
717: VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);
718: VecGetLocalSize(snes->vec_sol,&n);
719: PetscMalloc1(n,&indices);
720: for (i=0; i < n; i++) indices[i] = rstart + i;
721: ISCreateGeneral(PetscObjectComm((PetscObject)snes),n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);
723: /* set the line search functions */
724: if (!snes->linesearch) {
725: SNESGetLineSearch(snes, &linesearch);
726: SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);
727: }
728: return(0);
729: }
730: /* -------------------------------------------------------------------------- */
731: PetscErrorCode SNESReset_VINEWTONRSLS(SNES snes)
732: {
733: SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*) snes->data;
734: PetscErrorCode ierr;
737: SNESReset_VI(snes);
738: ISDestroy(&vi->IS_inact_prev);
739: return(0);
740: }
742: /* -------------------------------------------------------------------------- */
743: /*MC
744: SNESVINEWTONRSLS - Reduced space active set solvers for variational inequalities based on Newton's method
746: Options Database:
747: + -snes_type <vinewtonssls,vinewtonrsls> - a semi-smooth solver, a reduced space active set method
748: - -snes_vi_monitor - prints the number of active constraints at each iteration.
750: Level: beginner
752: References:
753: . 1. - T. S. Munson, and S. Benson. Flexible Complementarity Solvers for Large Scale
754: Applications, Optimization Methods and Software, 21 (2006).
756: .seealso: SNESVISetVariableBounds(), SNESVISetComputeVariableBounds(), SNESCreate(), SNES, SNESSetType(), SNESVINEWTONSSLS, SNESNEWTONTR, SNESLineSearchSetType(),SNESLineSearchSetPostCheck(), SNESLineSearchSetPreCheck()
758: M*/
759: PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONRSLS(SNES snes)
760: {
761: PetscErrorCode ierr;
762: SNES_VINEWTONRSLS *vi;
763: SNESLineSearch linesearch;
766: snes->ops->reset = SNESReset_VINEWTONRSLS;
767: snes->ops->setup = SNESSetUp_VINEWTONRSLS;
768: snes->ops->solve = SNESSolve_VINEWTONRSLS;
769: snes->ops->destroy = SNESDestroy_VI;
770: snes->ops->setfromoptions = SNESSetFromOptions_VI;
771: snes->ops->view = NULL;
772: snes->ops->converged = SNESConvergedDefault_VI;
774: snes->usesksp = PETSC_TRUE;
775: snes->usesnpc = PETSC_FALSE;
777: SNESGetLineSearch(snes, &linesearch);
778: if (!((PetscObject)linesearch)->type_name) {
779: SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);
780: }
781: SNESLineSearchBTSetAlpha(linesearch, 0.0);
783: snes->alwayscomputesfinalresidual = PETSC_TRUE;
785: PetscNewLog(snes,&vi);
786: snes->data = (void*)vi;
787: vi->checkredundancy = NULL;
789: PetscObjectComposeFunction((PetscObject)snes,"SNESVISetVariableBounds_C",SNESVISetVariableBounds_VI);
790: PetscObjectComposeFunction((PetscObject)snes,"SNESVISetComputeVariableBounds_C",SNESVISetComputeVariableBounds_VI);
791: return(0);
792: }