xref: /petsc/src/snes/impls/vi/vi.c (revision ed70e96a4de3cd8a7bd6336d7f25f499d1f74ed4)
12b4ed282SShri Abhyankar 
2c6db04a5SJed Brown #include <../src/snes/impls/vi/viimpl.h> /*I "petscsnes.h" I*/
3c6db04a5SJed Brown #include <../include/private/kspimpl.h>
4c6db04a5SJed Brown #include <../include/private/matimpl.h>
5d0af7cd3SBarry Smith #include <../include/private/dmimpl.h>
6d0af7cd3SBarry Smith 
7d0af7cd3SBarry Smith #undef __FUNCT__
82176524cSBarry Smith #define __FUNCT__ "SNESVISetComputeVariableBounds"
92176524cSBarry Smith /*@C
102176524cSBarry Smith    SNESVISetComputeVariableBounds - Sets a function  that is called to compute the variable bounds
112176524cSBarry Smith 
122176524cSBarry Smith    Input parameter
132176524cSBarry Smith +  snes - the SNES context
142176524cSBarry Smith -  compute - computes the bounds
152176524cSBarry Smith 
162176524cSBarry Smith 
17aab9d709SJed Brown @*/
1877cdaf69SJed Brown PetscErrorCode SNESVISetComputeVariableBounds(SNES snes, PetscErrorCode (*compute)(SNES,Vec,Vec))
192176524cSBarry Smith {
202176524cSBarry Smith   PetscErrorCode   ierr;
212176524cSBarry Smith   SNES_VI          *vi;
222176524cSBarry Smith 
232176524cSBarry Smith   PetscFunctionBegin;
242176524cSBarry Smith   ierr = SNESSetType(snes,SNESVI);CHKERRQ(ierr);
252176524cSBarry Smith   vi = (SNES_VI*)snes->data;
262176524cSBarry Smith   vi->computevariablebounds = compute;
272176524cSBarry Smith   PetscFunctionReturn(0);
282176524cSBarry Smith }
292176524cSBarry Smith 
302176524cSBarry Smith 
312176524cSBarry Smith #undef __FUNCT__
32*ed70e96aSJungho Lee #define __FUNCT__ "SNESVIComputeInactiveSetIS"
33d0af7cd3SBarry Smith /*
34*ed70e96aSJungho Lee    SNESVIComputeInactiveSetIS - Gets the global indices for the bogus inactive set variables
35d0af7cd3SBarry Smith 
36d0af7cd3SBarry Smith    Input parameter
37d0af7cd3SBarry Smith .  snes - the SNES context
38d0af7cd3SBarry Smith .  X    - the snes solution vector
39d0af7cd3SBarry Smith 
40d0af7cd3SBarry Smith    Output parameter
41d0af7cd3SBarry Smith .  ISact - active set index set
42d0af7cd3SBarry Smith 
43d0af7cd3SBarry Smith  */
44*ed70e96aSJungho Lee PetscErrorCode SNESVIComputeInactiveSetIS(Vec upper,Vec lower,Vec X,Vec F,IS* inact)
45d0af7cd3SBarry Smith {
46d0af7cd3SBarry Smith   PetscErrorCode   ierr;
47d0af7cd3SBarry Smith   const PetscScalar *x,*xl,*xu,*f;
48d0af7cd3SBarry Smith   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
49d0af7cd3SBarry Smith 
50d0af7cd3SBarry Smith   PetscFunctionBegin;
51d0af7cd3SBarry Smith   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
52d0af7cd3SBarry Smith   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
53d0af7cd3SBarry Smith   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
54d0af7cd3SBarry Smith   ierr = VecGetArrayRead(lower,&xl);CHKERRQ(ierr);
55d0af7cd3SBarry Smith   ierr = VecGetArrayRead(upper,&xu);CHKERRQ(ierr);
56d0af7cd3SBarry Smith   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
57d0af7cd3SBarry Smith   /* Compute inactive set size */
58d0af7cd3SBarry Smith   for (i=0; i < nlocal;i++) {
59d0af7cd3SBarry Smith     if (((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) nloc_isact++;
60d0af7cd3SBarry Smith   }
61d0af7cd3SBarry Smith 
62d0af7cd3SBarry Smith   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
63d0af7cd3SBarry Smith 
64d0af7cd3SBarry Smith   /* Set inactive set indices */
65d0af7cd3SBarry Smith   for(i=0; i < nlocal; i++) {
66d0af7cd3SBarry Smith     if (((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) idx_act[i1++] = ilow+i;
67d0af7cd3SBarry Smith   }
68d0af7cd3SBarry Smith 
69d0af7cd3SBarry Smith    /* Create inactive set IS */
70d0af7cd3SBarry Smith   ierr = ISCreateGeneral(((PetscObject)upper)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,inact);CHKERRQ(ierr);
71d0af7cd3SBarry Smith 
72d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
73d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(lower,&xl);CHKERRQ(ierr);
74d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(upper,&xu);CHKERRQ(ierr);
75d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
76d0af7cd3SBarry Smith   PetscFunctionReturn(0);
77d0af7cd3SBarry Smith }
78d0af7cd3SBarry Smith 
793c0c59f3SBarry Smith /*
803c0c59f3SBarry Smith     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
813c0c59f3SBarry Smith   defined by the reduced space method.
823c0c59f3SBarry Smith 
833c0c59f3SBarry Smith     Simple calls the regular DM interpolation and restricts it to operation on the variables not associated with active constraints.
843c0c59f3SBarry Smith 
85*ed70e96aSJungho Lee <*/
863c0c59f3SBarry Smith typedef struct {
873c0c59f3SBarry Smith   PetscInt       n;                                        /* size of vectors in the reduced DM space */
883c0c59f3SBarry Smith   IS             inactive;
893c0c59f3SBarry Smith   Vec            upper,lower,values,F;                    /* upper and lower bounds of all variables on this level, the values and the function values */
903c0c59f3SBarry Smith   PetscErrorCode (*getinterpolation)(DM,DM,Mat*,Vec*);    /* DM's original routines */
913c0c59f3SBarry Smith   PetscErrorCode (*coarsen)(DM, MPI_Comm, DM*);
923c0c59f3SBarry Smith   PetscErrorCode (*createglobalvector)(DM,Vec*);
934c661befSBarry Smith   DM             dm;                                      /* when destroying this object we need to reset the above function into the base DM */
943c0c59f3SBarry Smith } DM_SNESVI;
953c0c59f3SBarry Smith 
96d0af7cd3SBarry Smith #undef __FUNCT__
974dcab191SBarry Smith #define __FUNCT__ "DMCreateGlobalVector_SNESVI"
984dcab191SBarry Smith /*
994dcab191SBarry Smith      DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space
1004dcab191SBarry Smith 
1014dcab191SBarry Smith */
1024dcab191SBarry Smith PetscErrorCode  DMCreateGlobalVector_SNESVI(DM dm,Vec *vec)
1034dcab191SBarry Smith {
1044dcab191SBarry Smith   PetscErrorCode          ierr;
1054dcab191SBarry Smith   PetscContainer          isnes;
1063c0c59f3SBarry Smith   DM_SNESVI               *dmsnesvi;
1074dcab191SBarry Smith 
1084dcab191SBarry Smith   PetscFunctionBegin;
1094dcab191SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
1104dcab191SBarry Smith   if (!isnes) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
1114dcab191SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
1124dcab191SBarry Smith   ierr = VecCreateMPI(((PetscObject)dm)->comm,dmsnesvi->n,PETSC_DETERMINE,vec);CHKERRQ(ierr);
1134dcab191SBarry Smith   PetscFunctionReturn(0);
1144dcab191SBarry Smith }
1154dcab191SBarry Smith 
1164dcab191SBarry Smith #undef __FUNCT__
117d0af7cd3SBarry Smith #define __FUNCT__ "DMGetInterpolation_SNESVI"
118d0af7cd3SBarry Smith /*
119d0af7cd3SBarry Smith      DMGetInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.
120d0af7cd3SBarry Smith 
121d0af7cd3SBarry Smith */
122d0af7cd3SBarry Smith PetscErrorCode  DMGetInterpolation_SNESVI(DM dm1,DM dm2,Mat *mat,Vec *vec)
123d0af7cd3SBarry Smith {
124d0af7cd3SBarry Smith   PetscErrorCode          ierr;
125d0af7cd3SBarry Smith   PetscContainer          isnes;
1263c0c59f3SBarry Smith   DM_SNESVI               *dmsnesvi1,*dmsnesvi2;
127d0af7cd3SBarry Smith   Mat                     interp;
128d0af7cd3SBarry Smith 
129d0af7cd3SBarry Smith   PetscFunctionBegin;
130d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
1314c661befSBarry Smith   if (!isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
132d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
133d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm2,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
1344c661befSBarry Smith   if (!isnes) SETERRQ(((PetscObject)dm2)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
135d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi2);CHKERRQ(ierr);
136d0af7cd3SBarry Smith 
137d0af7cd3SBarry Smith   ierr = (*dmsnesvi1->getinterpolation)(dm1,dm2,&interp,PETSC_NULL);CHKERRQ(ierr);
1384dcab191SBarry Smith   ierr = MatGetSubMatrix(interp,dmsnesvi2->inactive,dmsnesvi1->inactive,MAT_INITIAL_MATRIX,mat);CHKERRQ(ierr);
139d0af7cd3SBarry Smith   ierr = MatDestroy(&interp);CHKERRQ(ierr);
14000ac8be1SBarry Smith   *vec = 0;
141d0af7cd3SBarry Smith   PetscFunctionReturn(0);
142d0af7cd3SBarry Smith }
143d0af7cd3SBarry Smith 
144d0af7cd3SBarry Smith extern PetscErrorCode  DMSetVI(DM,Vec,Vec,Vec,Vec,IS);
145d0af7cd3SBarry Smith 
146d0af7cd3SBarry Smith #undef __FUNCT__
147d0af7cd3SBarry Smith #define __FUNCT__ "DMCoarsen_SNESVI"
148d0af7cd3SBarry Smith /*
149d0af7cd3SBarry Smith      DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set
150d0af7cd3SBarry Smith 
151d0af7cd3SBarry Smith */
152d0af7cd3SBarry Smith PetscErrorCode  DMCoarsen_SNESVI(DM dm1,MPI_Comm comm,DM *dm2)
153d0af7cd3SBarry Smith {
154d0af7cd3SBarry Smith   PetscErrorCode          ierr;
155d0af7cd3SBarry Smith   PetscContainer          isnes;
1563c0c59f3SBarry Smith   DM_SNESVI               *dmsnesvi1;
157d0af7cd3SBarry Smith   Vec                     upper,lower,values,F;
158d0af7cd3SBarry Smith   IS                      inactive;
159d0af7cd3SBarry Smith   VecScatter              inject;
160d0af7cd3SBarry Smith 
161d0af7cd3SBarry Smith   PetscFunctionBegin;
162d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
1634c661befSBarry Smith   if (!isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed VI data structure is missing");
164d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
165d0af7cd3SBarry Smith 
166298cc208SBarry Smith   /* get the original coarsen */
167d0af7cd3SBarry Smith   ierr = (*dmsnesvi1->coarsen)(dm1,comm,dm2);CHKERRQ(ierr);
168298cc208SBarry Smith 
1693c0c59f3SBarry Smith   /* not sure why this extra reference is needed, but without the dm2 disappears too early */
1703c0c59f3SBarry Smith   ierr = PetscObjectReference((PetscObject)*dm2);CHKERRQ(ierr);
1713c0c59f3SBarry Smith 
172298cc208SBarry Smith   /* need to set back global vectors in order to use the original injection */
173298cc208SBarry Smith   ierr = DMClearGlobalVectors(dm1);CHKERRQ(ierr);
174298cc208SBarry Smith   dm1->ops->createglobalvector = dmsnesvi1->createglobalvector;
175d0af7cd3SBarry Smith   ierr = DMGetInjection(*dm2,dm1,&inject);CHKERRQ(ierr);
176d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&upper);CHKERRQ(ierr);
177d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->upper,upper,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
178d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->upper,upper,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
179d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&lower);CHKERRQ(ierr);
180d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->lower,lower,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
181d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->lower,lower,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
182d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&values);CHKERRQ(ierr);
183d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->values,values,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
184d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->values,values,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
185d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&F);CHKERRQ(ierr);
186d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->F,F,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
187d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->F,F,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
188d0af7cd3SBarry Smith   ierr = VecScatterDestroy(&inject);CHKERRQ(ierr);
189298cc208SBarry Smith   ierr = DMClearGlobalVectors(dm1);CHKERRQ(ierr);
190298cc208SBarry Smith   dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
191*ed70e96aSJungho Lee   ierr = SNESVIComputeInactiveSetIS(upper,lower,values,F,&inactive);CHKERRQ(ierr);
192d0af7cd3SBarry Smith   ierr = DMSetVI(*dm2,upper,lower,values,F,inactive);CHKERRQ(ierr);
1933c0c59f3SBarry Smith   ierr = VecDestroy(&upper);CHKERRQ(ierr);
1943c0c59f3SBarry Smith   ierr = VecDestroy(&lower);CHKERRQ(ierr);
1953c0c59f3SBarry Smith   ierr = VecDestroy(&values);CHKERRQ(ierr);
1963c0c59f3SBarry Smith   ierr = VecDestroy(&F);CHKERRQ(ierr);
1973c0c59f3SBarry Smith   ierr = ISDestroy(&inactive);CHKERRQ(ierr);
198d0af7cd3SBarry Smith   PetscFunctionReturn(0);
199d0af7cd3SBarry Smith }
200d0af7cd3SBarry Smith 
201d0af7cd3SBarry Smith #undef __FUNCT__
2023c0c59f3SBarry Smith #define __FUNCT__ "DMDestroy_SNESVI"
2033c0c59f3SBarry Smith PetscErrorCode DMDestroy_SNESVI(DM_SNESVI *dmsnesvi)
204d0af7cd3SBarry Smith {
205d0af7cd3SBarry Smith   PetscErrorCode ierr;
206d0af7cd3SBarry Smith 
207d0af7cd3SBarry Smith   PetscFunctionBegin;
2084c661befSBarry Smith   /* reset the base methods in the DM object that were changed when the DM_SNESVI was reset */
2094c661befSBarry Smith   dmsnesvi->dm->ops->getinterpolation   = dmsnesvi->getinterpolation;
2104c661befSBarry Smith   dmsnesvi->dm->ops->coarsen            = dmsnesvi->coarsen;
2114c661befSBarry Smith   dmsnesvi->dm->ops->createglobalvector = dmsnesvi->createglobalvector;
21200ac8be1SBarry Smith   /* need to clear out this vectors because some of them may not have a reference to the DM
21300ac8be1SBarry Smith     but they are counted as having references to the DM in DMDestroy() */
21400ac8be1SBarry Smith   ierr = DMClearGlobalVectors(dmsnesvi->dm);CHKERRQ(ierr);
2154c661befSBarry Smith 
216d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->upper);CHKERRQ(ierr);
217d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->lower);CHKERRQ(ierr);
218d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->values);CHKERRQ(ierr);
219d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->F);CHKERRQ(ierr);
220d0af7cd3SBarry Smith   ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
221d0af7cd3SBarry Smith   ierr = PetscFree(dmsnesvi);CHKERRQ(ierr);
222d0af7cd3SBarry Smith   PetscFunctionReturn(0);
223d0af7cd3SBarry Smith }
224d0af7cd3SBarry Smith 
225d0af7cd3SBarry Smith #undef __FUNCT__
226d0af7cd3SBarry Smith #define __FUNCT__ "DMSetVI"
227d0af7cd3SBarry Smith /*
228d0af7cd3SBarry Smith      DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to
229d0af7cd3SBarry Smith                be restricted to only those variables NOT associated with active constraints.
230d0af7cd3SBarry Smith 
231d0af7cd3SBarry Smith */
232d0af7cd3SBarry Smith PetscErrorCode  DMSetVI(DM dm,Vec upper,Vec lower,Vec values,Vec F,IS inactive)
233d0af7cd3SBarry Smith {
234d0af7cd3SBarry Smith   PetscErrorCode          ierr;
235d0af7cd3SBarry Smith   PetscContainer          isnes;
2363c0c59f3SBarry Smith   DM_SNESVI               *dmsnesvi;
237d0af7cd3SBarry Smith 
238d0af7cd3SBarry Smith   PetscFunctionBegin;
2394dcab191SBarry Smith   if (!dm) PetscFunctionReturn(0);
2401c0a9e84SBarry Smith 
241d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)upper);CHKERRQ(ierr);
242d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)lower);CHKERRQ(ierr);
243d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)values);CHKERRQ(ierr);
244d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)F);CHKERRQ(ierr);
245d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)inactive);CHKERRQ(ierr);
246d0af7cd3SBarry Smith 
247d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
248d0af7cd3SBarry Smith   if (!isnes) {
249d0af7cd3SBarry Smith     ierr = PetscContainerCreate(((PetscObject)dm)->comm,&isnes);CHKERRQ(ierr);
2503c0c59f3SBarry Smith     ierr = PetscContainerSetUserDestroy(isnes,(PetscErrorCode (*)(void*))DMDestroy_SNESVI);CHKERRQ(ierr);
2513c0c59f3SBarry Smith     ierr = PetscNew(DM_SNESVI,&dmsnesvi);CHKERRQ(ierr);
252d0af7cd3SBarry Smith     ierr = PetscContainerSetPointer(isnes,(void*)dmsnesvi);CHKERRQ(ierr);
253d0af7cd3SBarry Smith     ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)isnes);CHKERRQ(ierr);
2543c0c59f3SBarry Smith     ierr = PetscContainerDestroy(&isnes);CHKERRQ(ierr);
255d0af7cd3SBarry Smith     dmsnesvi->getinterpolation   = dm->ops->getinterpolation;
256d0af7cd3SBarry Smith     dm->ops->getinterpolation    = DMGetInterpolation_SNESVI;
257d0af7cd3SBarry Smith     dmsnesvi->coarsen            = dm->ops->coarsen;
258d0af7cd3SBarry Smith     dm->ops->coarsen             = DMCoarsen_SNESVI;
259298cc208SBarry Smith     dmsnesvi->createglobalvector = dm->ops->createglobalvector;
2604dcab191SBarry Smith     dm->ops->createglobalvector  = DMCreateGlobalVector_SNESVI;
2616ba4bc90SBarry Smith     /* since these vectors may reference the DM, need to remove circle referencing */
2626ba4bc90SBarry Smith     ierr = PetscObjectRemoveReference((PetscObject)upper,"DM");CHKERRQ(ierr);
2636ba4bc90SBarry Smith     ierr = PetscObjectRemoveReference((PetscObject)lower,"DM");CHKERRQ(ierr);
2646ba4bc90SBarry Smith     ierr = PetscObjectRemoveReference((PetscObject)values,"DM");CHKERRQ(ierr);
2656ba4bc90SBarry Smith     ierr = PetscObjectRemoveReference((PetscObject)F,"DM");CHKERRQ(ierr);
266d0af7cd3SBarry Smith   } else {
267d0af7cd3SBarry Smith     ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
268d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->upper);CHKERRQ(ierr);
269d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->lower);CHKERRQ(ierr);
270d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->values);CHKERRQ(ierr);
271d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->F);CHKERRQ(ierr);
272d0af7cd3SBarry Smith     ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
273d0af7cd3SBarry Smith   }
2744dcab191SBarry Smith   ierr = DMClearGlobalVectors(dm);CHKERRQ(ierr);
2754dcab191SBarry Smith   ierr = ISGetLocalSize(inactive,&dmsnesvi->n);CHKERRQ(ierr);
276d0af7cd3SBarry Smith   dmsnesvi->upper    = upper;
277d0af7cd3SBarry Smith   dmsnesvi->lower    = lower;
278d0af7cd3SBarry Smith   dmsnesvi->values   = values;
279d0af7cd3SBarry Smith   dmsnesvi->F        = F;
280d0af7cd3SBarry Smith   dmsnesvi->inactive = inactive;
2811a223a97SBarry Smith   dmsnesvi->dm       = dm;
282d0af7cd3SBarry Smith   PetscFunctionReturn(0);
283d0af7cd3SBarry Smith }
284d0af7cd3SBarry Smith 
2854c661befSBarry Smith #undef __FUNCT__
2864c661befSBarry Smith #define __FUNCT__ "DMDestroyVI"
2874c661befSBarry Smith /*
2884c661befSBarry Smith      DMDestroyVI - Frees the DM_SNESVI object contained in the DM
2894c661befSBarry Smith          - also resets the function pointers in the DM for getinterpolation() etc to use the original DM
2904c661befSBarry Smith */
2914c661befSBarry Smith PetscErrorCode  DMDestroyVI(DM dm)
2924c661befSBarry Smith {
2934c661befSBarry Smith   PetscErrorCode          ierr;
2944c661befSBarry Smith 
2954c661befSBarry Smith   PetscFunctionBegin;
2964c661befSBarry Smith   if (!dm) PetscFunctionReturn(0);
2974c661befSBarry Smith   ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)PETSC_NULL);CHKERRQ(ierr);
2984c661befSBarry Smith   PetscFunctionReturn(0);
2994c661befSBarry Smith }
3004c661befSBarry Smith 
3013c0c59f3SBarry Smith /* --------------------------------------------------------------------------------------------------------*/
3022b4ed282SShri Abhyankar 
3039308c137SBarry Smith #undef __FUNCT__
3049308c137SBarry Smith #define __FUNCT__ "SNESMonitorVI"
3057087cfbeSBarry Smith PetscErrorCode  SNESMonitorVI(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
3069308c137SBarry Smith {
3079308c137SBarry Smith   PetscErrorCode    ierr;
3089308c137SBarry Smith   SNES_VI            *vi = (SNES_VI*)snes->data;
309649052a6SBarry Smith   PetscViewer        viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)snes)->comm);
3109308c137SBarry Smith   const PetscScalar  *x,*xl,*xu,*f;
31109573ac7SBarry Smith   PetscInt           i,n,act = 0;
3129308c137SBarry Smith   PetscReal          rnorm,fnorm;
3139308c137SBarry Smith 
3149308c137SBarry Smith   PetscFunctionBegin;
3159308c137SBarry Smith   ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
3169308c137SBarry Smith   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
3179308c137SBarry Smith   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
3189308c137SBarry Smith   ierr = VecGetArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
3193f731af5SBarry Smith   ierr = VecGetArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
3209308c137SBarry Smith 
3219308c137SBarry Smith   rnorm = 0.0;
3229308c137SBarry Smith   for (i=0; i<n; i++) {
32310f5ae6bSBarry Smith     if (((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) rnorm += PetscRealPart(PetscConj(f[i])*f[i]);
32409573ac7SBarry Smith     else act++;
3259308c137SBarry Smith   }
3263f731af5SBarry Smith   ierr = VecRestoreArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
3279308c137SBarry Smith   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
3289308c137SBarry Smith   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
3299308c137SBarry Smith   ierr = VecRestoreArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
330d9822059SBarry Smith   ierr = MPI_Allreduce(&rnorm,&fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
3319308c137SBarry Smith   fnorm = sqrt(fnorm);
332649052a6SBarry Smith   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
333649052a6SBarry Smith   ierr = PetscViewerASCIIPrintf(viewer,"%3D SNES VI Function norm %14.12e Active constraints %D\n",its,fnorm,act);CHKERRQ(ierr);
334649052a6SBarry Smith   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
3359308c137SBarry Smith   PetscFunctionReturn(0);
3369308c137SBarry Smith }
3379308c137SBarry Smith 
3382b4ed282SShri Abhyankar /*
3392b4ed282SShri Abhyankar      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
3402b4ed282SShri Abhyankar     || F(u) ||_2 but not a zero, F(u) = 0. In the case when one cannot compute J^T F we use the fact that
3412b4ed282SShri Abhyankar     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
3422b4ed282SShri Abhyankar     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
3432b4ed282SShri Abhyankar */
3442b4ed282SShri Abhyankar #undef __FUNCT__
3452b4ed282SShri Abhyankar #define __FUNCT__ "SNESVICheckLocalMin_Private"
346ace3abfcSBarry Smith PetscErrorCode SNESVICheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool *ismin)
3472b4ed282SShri Abhyankar {
3482b4ed282SShri Abhyankar   PetscReal      a1;
3492b4ed282SShri Abhyankar   PetscErrorCode ierr;
350ace3abfcSBarry Smith   PetscBool     hastranspose;
3512b4ed282SShri Abhyankar 
3522b4ed282SShri Abhyankar   PetscFunctionBegin;
3532b4ed282SShri Abhyankar   *ismin = PETSC_FALSE;
3542b4ed282SShri Abhyankar   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
3552b4ed282SShri Abhyankar   if (hastranspose) {
3562b4ed282SShri Abhyankar     /* Compute || J^T F|| */
3572b4ed282SShri Abhyankar     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
3582b4ed282SShri Abhyankar     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
3592b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);CHKERRQ(ierr);
3602b4ed282SShri Abhyankar     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
3612b4ed282SShri Abhyankar   } else {
3622b4ed282SShri Abhyankar     Vec         work;
3632b4ed282SShri Abhyankar     PetscScalar result;
3642b4ed282SShri Abhyankar     PetscReal   wnorm;
3652b4ed282SShri Abhyankar 
3662b4ed282SShri Abhyankar     ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr);
3672b4ed282SShri Abhyankar     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
3682b4ed282SShri Abhyankar     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
3692b4ed282SShri Abhyankar     ierr = MatMult(A,W,work);CHKERRQ(ierr);
3702b4ed282SShri Abhyankar     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
3716bf464f9SBarry Smith     ierr = VecDestroy(&work);CHKERRQ(ierr);
3722b4ed282SShri Abhyankar     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
3732b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);CHKERRQ(ierr);
3742b4ed282SShri Abhyankar     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
3752b4ed282SShri Abhyankar   }
3762b4ed282SShri Abhyankar   PetscFunctionReturn(0);
3772b4ed282SShri Abhyankar }
3782b4ed282SShri Abhyankar 
3792b4ed282SShri Abhyankar /*
3802b4ed282SShri Abhyankar      Checks if J^T(F - J*X) = 0
3812b4ed282SShri Abhyankar */
3822b4ed282SShri Abhyankar #undef __FUNCT__
3832b4ed282SShri Abhyankar #define __FUNCT__ "SNESVICheckResidual_Private"
3842b4ed282SShri Abhyankar PetscErrorCode SNESVICheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
3852b4ed282SShri Abhyankar {
3862b4ed282SShri Abhyankar   PetscReal      a1,a2;
3872b4ed282SShri Abhyankar   PetscErrorCode ierr;
388ace3abfcSBarry Smith   PetscBool     hastranspose;
3892b4ed282SShri Abhyankar 
3902b4ed282SShri Abhyankar   PetscFunctionBegin;
3912b4ed282SShri Abhyankar   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
3922b4ed282SShri Abhyankar   if (hastranspose) {
3932b4ed282SShri Abhyankar     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
3942b4ed282SShri Abhyankar     ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr);
3952b4ed282SShri Abhyankar 
3962b4ed282SShri Abhyankar     /* Compute || J^T W|| */
3972b4ed282SShri Abhyankar     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
3982b4ed282SShri Abhyankar     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
3992b4ed282SShri Abhyankar     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
4002b4ed282SShri Abhyankar     if (a1 != 0.0) {
4012b4ed282SShri Abhyankar       ierr = PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);CHKERRQ(ierr);
4022b4ed282SShri Abhyankar     }
4032b4ed282SShri Abhyankar   }
4042b4ed282SShri Abhyankar   PetscFunctionReturn(0);
4052b4ed282SShri Abhyankar }
4062b4ed282SShri Abhyankar 
4072b4ed282SShri Abhyankar /*
4082b4ed282SShri Abhyankar   SNESDefaultConverged_VI - Checks the convergence of the semismooth newton algorithm.
4092b4ed282SShri Abhyankar 
4102b4ed282SShri Abhyankar   Notes:
4112b4ed282SShri Abhyankar   The convergence criterion currently implemented is
4122b4ed282SShri Abhyankar   merit < abstol
4132b4ed282SShri Abhyankar   merit < rtol*merit_initial
4142b4ed282SShri Abhyankar */
4152b4ed282SShri Abhyankar #undef __FUNCT__
4162b4ed282SShri Abhyankar #define __FUNCT__ "SNESDefaultConverged_VI"
4177fe79bc4SShri Abhyankar PetscErrorCode SNESDefaultConverged_VI(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gradnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
4182b4ed282SShri Abhyankar {
4192b4ed282SShri Abhyankar   PetscErrorCode ierr;
4202b4ed282SShri Abhyankar 
4212b4ed282SShri Abhyankar   PetscFunctionBegin;
4222b4ed282SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
4232b4ed282SShri Abhyankar   PetscValidPointer(reason,6);
4242b4ed282SShri Abhyankar 
4252b4ed282SShri Abhyankar   *reason = SNES_CONVERGED_ITERATING;
4262b4ed282SShri Abhyankar 
4272b4ed282SShri Abhyankar   if (!it) {
4282b4ed282SShri Abhyankar     /* set parameter for default relative tolerance convergence test */
4297fe79bc4SShri Abhyankar     snes->ttol = fnorm*snes->rtol;
4302b4ed282SShri Abhyankar   }
4317fe79bc4SShri Abhyankar   if (fnorm != fnorm) {
4322b4ed282SShri Abhyankar     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
4332b4ed282SShri Abhyankar     *reason = SNES_DIVERGED_FNORM_NAN;
4347fe79bc4SShri Abhyankar   } else if (fnorm < snes->abstol) {
4357fe79bc4SShri Abhyankar     ierr = PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);CHKERRQ(ierr);
4362b4ed282SShri Abhyankar     *reason = SNES_CONVERGED_FNORM_ABS;
4372b4ed282SShri Abhyankar   } else if (snes->nfuncs >= snes->max_funcs) {
4382b4ed282SShri Abhyankar     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
4392b4ed282SShri Abhyankar     *reason = SNES_DIVERGED_FUNCTION_COUNT;
4402b4ed282SShri Abhyankar   }
4412b4ed282SShri Abhyankar 
4422b4ed282SShri Abhyankar   if (it && !*reason) {
4437fe79bc4SShri Abhyankar     if (fnorm < snes->ttol) {
4447fe79bc4SShri Abhyankar       ierr = PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);CHKERRQ(ierr);
4452b4ed282SShri Abhyankar       *reason = SNES_CONVERGED_FNORM_RELATIVE;
4462b4ed282SShri Abhyankar     }
4472b4ed282SShri Abhyankar   }
4482b4ed282SShri Abhyankar   PetscFunctionReturn(0);
4492b4ed282SShri Abhyankar }
4502b4ed282SShri Abhyankar 
4512b4ed282SShri Abhyankar /*
4522b4ed282SShri Abhyankar   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.
4532b4ed282SShri Abhyankar 
4542b4ed282SShri Abhyankar   Input Parameter:
4552b4ed282SShri Abhyankar . phi - the semismooth function
4562b4ed282SShri Abhyankar 
4572b4ed282SShri Abhyankar   Output Parameter:
4582b4ed282SShri Abhyankar . merit - the merit function
4592b4ed282SShri Abhyankar . phinorm - ||phi||
4602b4ed282SShri Abhyankar 
4612b4ed282SShri Abhyankar   Notes:
4622b4ed282SShri Abhyankar   The merit function for the mixed complementarity problem is defined as
4632b4ed282SShri Abhyankar      merit = 0.5*phi^T*phi
4642b4ed282SShri Abhyankar */
4652b4ed282SShri Abhyankar #undef __FUNCT__
4662b4ed282SShri Abhyankar #define __FUNCT__ "SNESVIComputeMeritFunction"
4672b4ed282SShri Abhyankar static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm)
4682b4ed282SShri Abhyankar {
4692b4ed282SShri Abhyankar   PetscErrorCode ierr;
4702b4ed282SShri Abhyankar 
4712b4ed282SShri Abhyankar   PetscFunctionBegin;
4725f48b12bSBarry Smith   ierr = VecNormBegin(phi,NORM_2,phinorm);CHKERRQ(ierr);
4735f48b12bSBarry Smith   ierr = VecNormEnd(phi,NORM_2,phinorm);CHKERRQ(ierr);
4742b4ed282SShri Abhyankar 
4752b4ed282SShri Abhyankar   *merit = 0.5*(*phinorm)*(*phinorm);
4762b4ed282SShri Abhyankar   PetscFunctionReturn(0);
4772b4ed282SShri Abhyankar }
4782b4ed282SShri Abhyankar 
4797f6f51e9SSatish Balay PETSC_STATIC_INLINE PetscScalar Phi(PetscScalar a,PetscScalar b)
4804c21c6cdSBarry Smith {
4814c21c6cdSBarry Smith   return a + b - sqrt(a*a + b*b);
4824c21c6cdSBarry Smith }
4834c21c6cdSBarry Smith 
4847f6f51e9SSatish Balay PETSC_STATIC_INLINE PetscScalar DPhi(PetscScalar a,PetscScalar b)
4854c21c6cdSBarry Smith {
4865559b345SBarry Smith   if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return  1.0 - a/ sqrt(a*a + b*b);
4875559b345SBarry Smith   else return .5;
4884c21c6cdSBarry Smith }
4894c21c6cdSBarry Smith 
4902b4ed282SShri Abhyankar /*
4911f79c099SShri Abhyankar    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form.
4922b4ed282SShri Abhyankar 
4932b4ed282SShri Abhyankar    Input Parameters:
4942b4ed282SShri Abhyankar .  snes - the SNES context
4952b4ed282SShri Abhyankar .  x - current iterate
4962b4ed282SShri Abhyankar .  functx - user defined function context
4972b4ed282SShri Abhyankar 
4982b4ed282SShri Abhyankar    Output Parameters:
4992b4ed282SShri Abhyankar .  phi - Semismooth function
5002b4ed282SShri Abhyankar 
5012b4ed282SShri Abhyankar */
5022b4ed282SShri Abhyankar #undef __FUNCT__
5031f79c099SShri Abhyankar #define __FUNCT__ "SNESVIComputeFunction"
5041f79c099SShri Abhyankar static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void* functx)
5052b4ed282SShri Abhyankar {
5062b4ed282SShri Abhyankar   PetscErrorCode  ierr;
5072b4ed282SShri Abhyankar   SNES_VI         *vi = (SNES_VI*)snes->data;
5082b4ed282SShri Abhyankar   Vec             Xl = vi->xl,Xu = vi->xu,F = snes->vec_func;
5094c21c6cdSBarry Smith   PetscScalar     *phi_arr,*x_arr,*f_arr,*l,*u;
5102b4ed282SShri Abhyankar   PetscInt        i,nlocal;
5112b4ed282SShri Abhyankar 
5122b4ed282SShri Abhyankar   PetscFunctionBegin;
5132b4ed282SShri Abhyankar   ierr = (*vi->computeuserfunction)(snes,X,F,functx);CHKERRQ(ierr);
5142b4ed282SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
5152b4ed282SShri Abhyankar   ierr = VecGetArray(X,&x_arr);CHKERRQ(ierr);
5162b4ed282SShri Abhyankar   ierr = VecGetArray(F,&f_arr);CHKERRQ(ierr);
5172b4ed282SShri Abhyankar   ierr = VecGetArray(Xl,&l);CHKERRQ(ierr);
5182b4ed282SShri Abhyankar   ierr = VecGetArray(Xu,&u);CHKERRQ(ierr);
5192b4ed282SShri Abhyankar   ierr = VecGetArray(phi,&phi_arr);CHKERRQ(ierr);
5202b4ed282SShri Abhyankar 
5212b4ed282SShri Abhyankar   for (i=0;i < nlocal;i++) {
52210f5ae6bSBarry Smith     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) { /* no constraints on variable */
5234c21c6cdSBarry Smith       phi_arr[i] = f_arr[i];
52410f5ae6bSBarry Smith     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                      /* upper bound on variable only */
5254c21c6cdSBarry Smith       phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]);
52610f5ae6bSBarry Smith     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                       /* lower bound on variable only */
5274c21c6cdSBarry Smith       phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]);
5285559b345SBarry Smith     } else if (l[i] == u[i]) {
5292b4ed282SShri Abhyankar       phi_arr[i] = l[i] - x_arr[i];
5305559b345SBarry Smith     } else {                                                /* both bounds on variable */
5314c21c6cdSBarry Smith       phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i]));
5322b4ed282SShri Abhyankar     }
5332b4ed282SShri Abhyankar   }
5342b4ed282SShri Abhyankar 
5352b4ed282SShri Abhyankar   ierr = VecRestoreArray(X,&x_arr);CHKERRQ(ierr);
5362b4ed282SShri Abhyankar   ierr = VecRestoreArray(F,&f_arr);CHKERRQ(ierr);
5372b4ed282SShri Abhyankar   ierr = VecRestoreArray(Xl,&l);CHKERRQ(ierr);
5382b4ed282SShri Abhyankar   ierr = VecRestoreArray(Xu,&u);CHKERRQ(ierr);
5392b4ed282SShri Abhyankar   ierr = VecRestoreArray(phi,&phi_arr);CHKERRQ(ierr);
5402b4ed282SShri Abhyankar   PetscFunctionReturn(0);
5412b4ed282SShri Abhyankar }
5422b4ed282SShri Abhyankar 
5432b4ed282SShri Abhyankar /*
544a79edbefSShri Abhyankar    SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the
545a79edbefSShri Abhyankar                                           the semismooth jacobian.
5462b4ed282SShri Abhyankar */
5472b4ed282SShri Abhyankar #undef __FUNCT__
548a79edbefSShri Abhyankar #define __FUNCT__ "SNESVIComputeBsubdifferentialVectors"
549a79edbefSShri Abhyankar PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db)
5502b4ed282SShri Abhyankar {
5512b4ed282SShri Abhyankar   PetscErrorCode ierr;
5522b4ed282SShri Abhyankar   SNES_VI      *vi = (SNES_VI*)snes->data;
5534c21c6cdSBarry Smith   PetscScalar    *l,*u,*x,*f,*da,*db,da1,da2,db1,db2;
5542b4ed282SShri Abhyankar   PetscInt       i,nlocal;
5552b4ed282SShri Abhyankar 
5562b4ed282SShri Abhyankar   PetscFunctionBegin;
5572b4ed282SShri Abhyankar 
5582b4ed282SShri Abhyankar   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
5592b4ed282SShri Abhyankar   ierr = VecGetArray(F,&f);CHKERRQ(ierr);
5602b4ed282SShri Abhyankar   ierr = VecGetArray(vi->xl,&l);CHKERRQ(ierr);
5612b4ed282SShri Abhyankar   ierr = VecGetArray(vi->xu,&u);CHKERRQ(ierr);
562a79edbefSShri Abhyankar   ierr = VecGetArray(Da,&da);CHKERRQ(ierr);
563a79edbefSShri Abhyankar   ierr = VecGetArray(Db,&db);CHKERRQ(ierr);
5642b4ed282SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
5654c21c6cdSBarry Smith 
5662b4ed282SShri Abhyankar   for (i=0;i< nlocal;i++) {
56710f5ae6bSBarry Smith     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) {/* no constraints on variable */
5684c21c6cdSBarry Smith       da[i] = 0;
5692b4ed282SShri Abhyankar       db[i] = 1;
57010f5ae6bSBarry Smith     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                     /* upper bound on variable only */
5714c21c6cdSBarry Smith       da[i] = DPhi(u[i] - x[i], -f[i]);
5724c21c6cdSBarry Smith       db[i] = DPhi(-f[i],u[i] - x[i]);
57310f5ae6bSBarry Smith     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                      /* lower bound on variable only */
5745559b345SBarry Smith       da[i] = DPhi(x[i] - l[i], f[i]);
5755559b345SBarry Smith       db[i] = DPhi(f[i],x[i] - l[i]);
5765559b345SBarry Smith     } else if (l[i] == u[i]) {                              /* fixed variable */
5774c21c6cdSBarry Smith       da[i] = 1;
5782b4ed282SShri Abhyankar       db[i] = 0;
5795559b345SBarry Smith     } else {                                                /* upper and lower bounds on variable */
5804c21c6cdSBarry Smith       da1 = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i]));
5814c21c6cdSBarry Smith       db1 = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]);
5824c21c6cdSBarry Smith       da2 = DPhi(u[i] - x[i], -f[i]);
5834c21c6cdSBarry Smith       db2 = DPhi(-f[i],u[i] - x[i]);
5844c21c6cdSBarry Smith       da[i] = da1 + db1*da2;
5854c21c6cdSBarry Smith       db[i] = db1*db2;
5862b4ed282SShri Abhyankar     }
5872b4ed282SShri Abhyankar   }
5885559b345SBarry Smith 
5892b4ed282SShri Abhyankar   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
5902b4ed282SShri Abhyankar   ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
5912b4ed282SShri Abhyankar   ierr = VecRestoreArray(vi->xl,&l);CHKERRQ(ierr);
5922b4ed282SShri Abhyankar   ierr = VecRestoreArray(vi->xu,&u);CHKERRQ(ierr);
593a79edbefSShri Abhyankar   ierr = VecRestoreArray(Da,&da);CHKERRQ(ierr);
594a79edbefSShri Abhyankar   ierr = VecRestoreArray(Db,&db);CHKERRQ(ierr);
595a79edbefSShri Abhyankar   PetscFunctionReturn(0);
596a79edbefSShri Abhyankar }
597a79edbefSShri Abhyankar 
598a79edbefSShri Abhyankar /*
599a79edbefSShri Abhyankar    SNESVIComputeJacobian - Computes the jacobian of the semismooth function.The Jacobian for the semismooth function is an element of the B-subdifferential of the Fischer-Burmeister function for complementarity problems.
600a79edbefSShri Abhyankar 
601a79edbefSShri Abhyankar    Input Parameters:
602a79edbefSShri Abhyankar .  Da       - Diagonal shift vector for the semismooth jacobian.
603a79edbefSShri Abhyankar .  Db       - Row scaling vector for the semismooth jacobian.
604a79edbefSShri Abhyankar 
605a79edbefSShri Abhyankar    Output Parameters:
606a79edbefSShri Abhyankar .  jac      - semismooth jacobian
607a79edbefSShri Abhyankar .  jac_pre  - optional preconditioning matrix
608a79edbefSShri Abhyankar 
609a79edbefSShri Abhyankar    Notes:
610a79edbefSShri Abhyankar    The semismooth jacobian matrix is given by
611a79edbefSShri Abhyankar    jac = Da + Db*jacfun
612a79edbefSShri Abhyankar    where Db is the row scaling matrix stored as a vector,
613a79edbefSShri Abhyankar          Da is the diagonal perturbation matrix stored as a vector
614a79edbefSShri Abhyankar    and   jacfun is the jacobian of the original nonlinear function.
615a79edbefSShri Abhyankar */
616a79edbefSShri Abhyankar #undef __FUNCT__
617a79edbefSShri Abhyankar #define __FUNCT__ "SNESVIComputeJacobian"
618a79edbefSShri Abhyankar PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db)
619a79edbefSShri Abhyankar {
620a79edbefSShri Abhyankar   PetscErrorCode ierr;
621a79edbefSShri Abhyankar 
6222b4ed282SShri Abhyankar   /* Do row scaling  and add diagonal perturbation */
623a79edbefSShri Abhyankar   ierr = MatDiagonalScale(jac,Db,PETSC_NULL);CHKERRQ(ierr);
624a79edbefSShri Abhyankar   ierr = MatDiagonalSet(jac,Da,ADD_VALUES);CHKERRQ(ierr);
625a79edbefSShri Abhyankar   if (jac != jac_pre) { /* If jac and jac_pre are different */
626a79edbefSShri Abhyankar     ierr = MatDiagonalScale(jac_pre,Db,PETSC_NULL);
627a79edbefSShri Abhyankar     ierr = MatDiagonalSet(jac_pre,Da,ADD_VALUES);CHKERRQ(ierr);
6282b4ed282SShri Abhyankar   }
6292b4ed282SShri Abhyankar   PetscFunctionReturn(0);
6302b4ed282SShri Abhyankar }
6312b4ed282SShri Abhyankar 
6322b4ed282SShri Abhyankar /*
633ee657d29SShri Abhyankar    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.
634ee657d29SShri Abhyankar 
635ee657d29SShri Abhyankar    Input Parameters:
636ee657d29SShri Abhyankar    phi - semismooth function.
637ee657d29SShri Abhyankar    H   - semismooth jacobian
638ee657d29SShri Abhyankar 
639ee657d29SShri Abhyankar    Output Parameters:
640ee657d29SShri Abhyankar    dpsi - merit function gradient
641ee657d29SShri Abhyankar 
642ee657d29SShri Abhyankar    Notes:
643ee657d29SShri Abhyankar   The merit function gradient is computed as follows
644ee657d29SShri Abhyankar         dpsi = H^T*phi
645ee657d29SShri Abhyankar */
646ee657d29SShri Abhyankar #undef __FUNCT__
647ee657d29SShri Abhyankar #define __FUNCT__ "SNESVIComputeMeritFunctionGradient"
648ee657d29SShri Abhyankar PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
649ee657d29SShri Abhyankar {
650ee657d29SShri Abhyankar   PetscErrorCode ierr;
651ee657d29SShri Abhyankar 
652ee657d29SShri Abhyankar   PetscFunctionBegin;
6535f48b12bSBarry Smith   ierr = MatMultTranspose(H,phi,dpsi);CHKERRQ(ierr);
654ee657d29SShri Abhyankar   PetscFunctionReturn(0);
655ee657d29SShri Abhyankar }
656ee657d29SShri Abhyankar 
657c1a5e521SShri Abhyankar /* -------------------------------------------------------------------------- */
658c1a5e521SShri Abhyankar /*
659c1a5e521SShri Abhyankar    SNESVIProjectOntoBounds - Projects X onto the feasible region so that Xl[i] <= X[i] <= Xu[i] for i = 1...n.
660c1a5e521SShri Abhyankar 
661c1a5e521SShri Abhyankar    Input Parameters:
662c1a5e521SShri Abhyankar .  SNES - nonlinear solver context
663c1a5e521SShri Abhyankar 
664c1a5e521SShri Abhyankar    Output Parameters:
665c1a5e521SShri Abhyankar .  X - Bound projected X
666c1a5e521SShri Abhyankar 
667c1a5e521SShri Abhyankar */
668c1a5e521SShri Abhyankar 
669c1a5e521SShri Abhyankar #undef __FUNCT__
670c1a5e521SShri Abhyankar #define __FUNCT__ "SNESVIProjectOntoBounds"
671c1a5e521SShri Abhyankar PetscErrorCode SNESVIProjectOntoBounds(SNES snes,Vec X)
672c1a5e521SShri Abhyankar {
673c1a5e521SShri Abhyankar   PetscErrorCode    ierr;
674c1a5e521SShri Abhyankar   SNES_VI           *vi = (SNES_VI*)snes->data;
675c1a5e521SShri Abhyankar   const PetscScalar *xl,*xu;
676c1a5e521SShri Abhyankar   PetscScalar       *x;
677c1a5e521SShri Abhyankar   PetscInt          i,n;
678c1a5e521SShri Abhyankar 
679c1a5e521SShri Abhyankar   PetscFunctionBegin;
680c1a5e521SShri Abhyankar   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
681c1a5e521SShri Abhyankar   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
682c1a5e521SShri Abhyankar   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
683c1a5e521SShri Abhyankar   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
684c1a5e521SShri Abhyankar 
685c1a5e521SShri Abhyankar   for(i = 0;i<n;i++) {
68610f5ae6bSBarry Smith     if (PetscRealPart(x[i]) < PetscRealPart(xl[i])) x[i] = xl[i];
68710f5ae6bSBarry Smith     else if (PetscRealPart(x[i]) > PetscRealPart(xu[i])) x[i] = xu[i];
688c1a5e521SShri Abhyankar   }
689c1a5e521SShri Abhyankar   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
690c1a5e521SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
691c1a5e521SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
692c1a5e521SShri Abhyankar   PetscFunctionReturn(0);
693c1a5e521SShri Abhyankar }
694c1a5e521SShri Abhyankar 
6952b4ed282SShri Abhyankar /*  --------------------------------------------------------------------
6962b4ed282SShri Abhyankar 
6972b4ed282SShri Abhyankar      This file implements a semismooth truncated Newton method with a line search,
6982b4ed282SShri Abhyankar      for solving a system of nonlinear equations in complementarity form, using the KSP, Vec,
6992b4ed282SShri Abhyankar      and Mat interfaces for linear solvers, vectors, and matrices,
7002b4ed282SShri Abhyankar      respectively.
7012b4ed282SShri Abhyankar 
7022b4ed282SShri Abhyankar      The following basic routines are required for each nonlinear solver:
7032b4ed282SShri Abhyankar           SNESCreate_XXX()          - Creates a nonlinear solver context
7042b4ed282SShri Abhyankar           SNESSetFromOptions_XXX()  - Sets runtime options
7052b4ed282SShri Abhyankar           SNESSolve_XXX()           - Solves the nonlinear system
7062b4ed282SShri Abhyankar           SNESDestroy_XXX()         - Destroys the nonlinear solver context
7072b4ed282SShri Abhyankar      The suffix "_XXX" denotes a particular implementation, in this case
7082b4ed282SShri Abhyankar      we use _VI (e.g., SNESCreate_VI, SNESSolve_VI) for solving
7092b4ed282SShri Abhyankar      systems of nonlinear equations with a line search (LS) method.
7102b4ed282SShri Abhyankar      These routines are actually called via the common user interface
7112b4ed282SShri Abhyankar      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
7122b4ed282SShri Abhyankar      SNESDestroy(), so the application code interface remains identical
7132b4ed282SShri Abhyankar      for all nonlinear solvers.
7142b4ed282SShri Abhyankar 
7152b4ed282SShri Abhyankar      Another key routine is:
7162b4ed282SShri Abhyankar           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
7172b4ed282SShri Abhyankar      by setting data structures and options.   The interface routine SNESSetUp()
7182b4ed282SShri Abhyankar      is not usually called directly by the user, but instead is called by
7192b4ed282SShri Abhyankar      SNESSolve() if necessary.
7202b4ed282SShri Abhyankar 
7212b4ed282SShri Abhyankar      Additional basic routines are:
7222b4ed282SShri Abhyankar           SNESView_XXX()            - Prints details of runtime options that
7232b4ed282SShri Abhyankar                                       have actually been used.
7242b4ed282SShri Abhyankar      These are called by application codes via the interface routines
7252b4ed282SShri Abhyankar      SNESView().
7262b4ed282SShri Abhyankar 
7272b4ed282SShri Abhyankar      The various types of solvers (preconditioners, Krylov subspace methods,
7282b4ed282SShri Abhyankar      nonlinear solvers, timesteppers) are all organized similarly, so the
7292b4ed282SShri Abhyankar      above description applies to these categories also.
7302b4ed282SShri Abhyankar 
7312b4ed282SShri Abhyankar     -------------------------------------------------------------------- */
7322b4ed282SShri Abhyankar /*
73369c03620SShri Abhyankar    SNESSolveVI_SS - Solves the complementarity problem with a semismooth Newton
7342b4ed282SShri Abhyankar    method using a line search.
7352b4ed282SShri Abhyankar 
7362b4ed282SShri Abhyankar    Input Parameters:
7372b4ed282SShri Abhyankar .  snes - the SNES context
7382b4ed282SShri Abhyankar 
7392b4ed282SShri Abhyankar    Output Parameter:
7402b4ed282SShri Abhyankar .  outits - number of iterations until termination
7412b4ed282SShri Abhyankar 
7422b4ed282SShri Abhyankar    Application Interface Routine: SNESSolve()
7432b4ed282SShri Abhyankar 
7442b4ed282SShri Abhyankar    Notes:
7452b4ed282SShri Abhyankar    This implements essentially a semismooth Newton method with a
74651defd01SShri Abhyankar    line search. The default line search does not do any line seach
74751defd01SShri Abhyankar    but rather takes a full newton step.
7482b4ed282SShri Abhyankar */
7492b4ed282SShri Abhyankar #undef __FUNCT__
75069c03620SShri Abhyankar #define __FUNCT__ "SNESSolveVI_SS"
75169c03620SShri Abhyankar PetscErrorCode SNESSolveVI_SS(SNES snes)
7522b4ed282SShri Abhyankar {
7532b4ed282SShri Abhyankar   SNES_VI            *vi = (SNES_VI*)snes->data;
7542b4ed282SShri Abhyankar   PetscErrorCode     ierr;
7552b4ed282SShri Abhyankar   PetscInt           maxits,i,lits;
7563b336b49SShri Abhyankar   PetscBool          lssucceed;
7572b4ed282SShri Abhyankar   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
7582b4ed282SShri Abhyankar   PetscReal          gnorm,xnorm=0,ynorm;
7592b4ed282SShri Abhyankar   Vec                Y,X,F,G,W;
7602b4ed282SShri Abhyankar   KSPConvergedReason kspreason;
7612b4ed282SShri Abhyankar 
7622b4ed282SShri Abhyankar   PetscFunctionBegin;
7639ce7406fSBarry Smith   vi->computeuserfunction    = snes->ops->computefunction;
7649ce7406fSBarry Smith   snes->ops->computefunction = SNESVIComputeFunction;
7659ce7406fSBarry Smith 
7662b4ed282SShri Abhyankar   snes->numFailures            = 0;
7672b4ed282SShri Abhyankar   snes->numLinearSolveFailures = 0;
7682b4ed282SShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
7692b4ed282SShri Abhyankar 
7702b4ed282SShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
7712b4ed282SShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
7722b4ed282SShri Abhyankar   F		= snes->vec_func;	/* residual vector */
7732b4ed282SShri Abhyankar   Y		= snes->work[0];	/* work vectors */
7742b4ed282SShri Abhyankar   G		= snes->work[1];
7752b4ed282SShri Abhyankar   W		= snes->work[2];
7762b4ed282SShri Abhyankar 
7772b4ed282SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
7782b4ed282SShri Abhyankar   snes->iter = 0;
7792b4ed282SShri Abhyankar   snes->norm = 0.0;
7802b4ed282SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
7812b4ed282SShri Abhyankar 
7827fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
7832b4ed282SShri Abhyankar   ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr);
7842b4ed282SShri Abhyankar   if (snes->domainerror) {
7852b4ed282SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
7869ce7406fSBarry Smith     snes->ops->computefunction = vi->computeuserfunction;
7872b4ed282SShri Abhyankar     PetscFunctionReturn(0);
7882b4ed282SShri Abhyankar   }
7892b4ed282SShri Abhyankar    /* Compute Merit function */
7902b4ed282SShri Abhyankar   ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr);
7912b4ed282SShri Abhyankar 
7922b4ed282SShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
7932b4ed282SShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
79462cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(vi->merit)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
7952b4ed282SShri Abhyankar 
7962b4ed282SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
7972b4ed282SShri Abhyankar   snes->norm = vi->phinorm;
7982b4ed282SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
7992b4ed282SShri Abhyankar   SNESLogConvHistory(snes,vi->phinorm,0);
8007a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,vi->phinorm);CHKERRQ(ierr);
8012b4ed282SShri Abhyankar 
8022b4ed282SShri Abhyankar   /* set parameter for default relative tolerance convergence test */
8032b4ed282SShri Abhyankar   snes->ttol = vi->phinorm*snes->rtol;
8042b4ed282SShri Abhyankar   /* test convergence */
8052b4ed282SShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
8069ce7406fSBarry Smith   if (snes->reason) {
8079ce7406fSBarry Smith     snes->ops->computefunction = vi->computeuserfunction;
8089ce7406fSBarry Smith     PetscFunctionReturn(0);
8099ce7406fSBarry Smith   }
8102b4ed282SShri Abhyankar 
8112b4ed282SShri Abhyankar   for (i=0; i<maxits; i++) {
8122b4ed282SShri Abhyankar 
8132b4ed282SShri Abhyankar     /* Call general purpose update function */
8142b4ed282SShri Abhyankar     if (snes->ops->update) {
8152b4ed282SShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
8162b4ed282SShri Abhyankar     }
8172b4ed282SShri Abhyankar 
8182b4ed282SShri Abhyankar     /* Solve J Y = Phi, where J is the semismooth jacobian */
819a79edbefSShri Abhyankar     /* Get the nonlinear function jacobian */
8202b4ed282SShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
821a79edbefSShri Abhyankar     /* Get the diagonal shift and row scaling vectors */
822a79edbefSShri Abhyankar     ierr = SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);CHKERRQ(ierr);
823a79edbefSShri Abhyankar     /* Compute the semismooth jacobian */
824a79edbefSShri Abhyankar     ierr = SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);CHKERRQ(ierr);
825ee657d29SShri Abhyankar     /* Compute the merit function gradient */
826ee657d29SShri Abhyankar     ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr);
8272b4ed282SShri Abhyankar     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
8282b4ed282SShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);CHKERRQ(ierr);
8292b4ed282SShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
8303b336b49SShri Abhyankar 
8313b336b49SShri Abhyankar     if (kspreason < 0) {
8322b4ed282SShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
8332b4ed282SShri Abhyankar         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
8342b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
8352b4ed282SShri Abhyankar         break;
8362b4ed282SShri Abhyankar       }
8372b4ed282SShri Abhyankar     }
8382b4ed282SShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
8392b4ed282SShri Abhyankar     snes->linear_its += lits;
8402b4ed282SShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
8412b4ed282SShri Abhyankar     /*
8422b4ed282SShri Abhyankar     if (vi->precheckstep) {
843ace3abfcSBarry Smith       PetscBool changed_y = PETSC_FALSE;
8442b4ed282SShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
8452b4ed282SShri Abhyankar     }
8462b4ed282SShri Abhyankar 
8472b4ed282SShri Abhyankar     if (PetscLogPrintInfo){
8482b4ed282SShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
8492b4ed282SShri Abhyankar     }
8502b4ed282SShri Abhyankar     */
8512b4ed282SShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
8522b4ed282SShri Abhyankar          Y <- X - lambda*Y
8532b4ed282SShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
8542b4ed282SShri Abhyankar     */
8552b4ed282SShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
8562b4ed282SShri Abhyankar     ynorm = 1; gnorm = vi->phinorm;
8572b4ed282SShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,vi->phi,G,Y,W,vi->phinorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
8582b4ed282SShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",vi->phinorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
8592b4ed282SShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
8602b4ed282SShri Abhyankar     if (snes->domainerror) {
8612b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
8629ce7406fSBarry Smith       snes->ops->computefunction = vi->computeuserfunction;
8632b4ed282SShri Abhyankar       PetscFunctionReturn(0);
8642b4ed282SShri Abhyankar     }
8652b4ed282SShri Abhyankar     if (!lssucceed) {
8662b4ed282SShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
867ace3abfcSBarry Smith 	PetscBool ismin;
8682b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
8692b4ed282SShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
8702b4ed282SShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
8712b4ed282SShri Abhyankar         break;
8722b4ed282SShri Abhyankar       }
8732b4ed282SShri Abhyankar     }
8742b4ed282SShri Abhyankar     /* Update function and solution vectors */
8752b4ed282SShri Abhyankar     vi->phinorm = gnorm;
8762b4ed282SShri Abhyankar     vi->merit = 0.5*vi->phinorm*vi->phinorm;
8772b4ed282SShri Abhyankar     ierr = VecCopy(G,vi->phi);CHKERRQ(ierr);
8782b4ed282SShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
8792b4ed282SShri Abhyankar     /* Monitor convergence */
8802b4ed282SShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
8812b4ed282SShri Abhyankar     snes->iter = i+1;
8822b4ed282SShri Abhyankar     snes->norm = vi->phinorm;
8832b4ed282SShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
8842b4ed282SShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
8857a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
8862b4ed282SShri Abhyankar     /* Test for convergence, xnorm = || X || */
8872b4ed282SShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
8882b4ed282SShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
8892b4ed282SShri Abhyankar     if (snes->reason) break;
8902b4ed282SShri Abhyankar   }
8912b4ed282SShri Abhyankar   if (i == maxits) {
8922b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
8932b4ed282SShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
8942b4ed282SShri Abhyankar   }
8959ce7406fSBarry Smith   snes->ops->computefunction = vi->computeuserfunction;
8962b4ed282SShri Abhyankar   PetscFunctionReturn(0);
8972b4ed282SShri Abhyankar }
89869c03620SShri Abhyankar 
89969c03620SShri Abhyankar #undef __FUNCT__
900693ddf92SShri Abhyankar #define __FUNCT__ "SNESVIGetActiveSetIS"
901693ddf92SShri Abhyankar /*
902693ddf92SShri Abhyankar    SNESVIGetActiveSetIndices - Gets the global indices for the active set variables
903693ddf92SShri Abhyankar 
904693ddf92SShri Abhyankar    Input parameter
905693ddf92SShri Abhyankar .  snes - the SNES context
906693ddf92SShri Abhyankar .  X    - the snes solution vector
907693ddf92SShri Abhyankar .  F    - the nonlinear function vector
908693ddf92SShri Abhyankar 
909693ddf92SShri Abhyankar    Output parameter
910693ddf92SShri Abhyankar .  ISact - active set index set
911693ddf92SShri Abhyankar  */
912693ddf92SShri Abhyankar PetscErrorCode SNESVIGetActiveSetIS(SNES snes,Vec X,Vec F,IS* ISact)
913d950fb63SShri Abhyankar {
914d950fb63SShri Abhyankar   PetscErrorCode   ierr;
915693ddf92SShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
916693ddf92SShri Abhyankar   Vec               Xl=vi->xl,Xu=vi->xu;
917693ddf92SShri Abhyankar   const PetscScalar *x,*f,*xl,*xu;
918693ddf92SShri Abhyankar   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
919d950fb63SShri Abhyankar 
920d950fb63SShri Abhyankar   PetscFunctionBegin;
921d950fb63SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
922d950fb63SShri Abhyankar   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
923fe835674SShri Abhyankar   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
924fe835674SShri Abhyankar   ierr = VecGetArrayRead(Xl,&xl);CHKERRQ(ierr);
925fe835674SShri Abhyankar   ierr = VecGetArrayRead(Xu,&xu);CHKERRQ(ierr);
926fe835674SShri Abhyankar   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
927693ddf92SShri Abhyankar   /* Compute active set size */
928d950fb63SShri Abhyankar   for (i=0; i < nlocal;i++) {
92910f5ae6bSBarry Smith     if (!((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) nloc_isact++;
930d950fb63SShri Abhyankar   }
931693ddf92SShri Abhyankar 
932d950fb63SShri Abhyankar   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
933d950fb63SShri Abhyankar 
934693ddf92SShri Abhyankar   /* Set active set indices */
935d950fb63SShri Abhyankar   for(i=0; i < nlocal; i++) {
93610f5ae6bSBarry Smith     if (!((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) idx_act[i1++] = ilow+i;
937d950fb63SShri Abhyankar   }
938d950fb63SShri Abhyankar 
939693ddf92SShri Abhyankar    /* Create active set IS */
94062298a1eSBarry Smith   ierr = ISCreateGeneral(((PetscObject)snes)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,ISact);CHKERRQ(ierr);
941d950fb63SShri Abhyankar 
942fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
943fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(Xl,&xl);CHKERRQ(ierr);
944fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(Xu,&xu);CHKERRQ(ierr);
945fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
946d950fb63SShri Abhyankar   PetscFunctionReturn(0);
947d950fb63SShri Abhyankar }
948d950fb63SShri Abhyankar 
949693ddf92SShri Abhyankar #undef __FUNCT__
950693ddf92SShri Abhyankar #define __FUNCT__ "SNESVICreateIndexSets_RS"
951693ddf92SShri Abhyankar PetscErrorCode SNESVICreateIndexSets_RS(SNES snes,Vec X,Vec F,IS* ISact,IS* ISinact)
952693ddf92SShri Abhyankar {
953693ddf92SShri Abhyankar   PetscErrorCode     ierr;
954693ddf92SShri Abhyankar 
955693ddf92SShri Abhyankar   PetscFunctionBegin;
956693ddf92SShri Abhyankar   ierr = SNESVIGetActiveSetIS(snes,X,F,ISact);CHKERRQ(ierr);
957693ddf92SShri Abhyankar   ierr = ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);CHKERRQ(ierr);
958693ddf92SShri Abhyankar   PetscFunctionReturn(0);
959693ddf92SShri Abhyankar }
960693ddf92SShri Abhyankar 
961dbd914b8SShri Abhyankar /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
962dbd914b8SShri Abhyankar #undef __FUNCT__
963fe835674SShri Abhyankar #define __FUNCT__ "SNESVICreateSubVectors"
964fe835674SShri Abhyankar PetscErrorCode SNESVICreateSubVectors(SNES snes,PetscInt n,Vec* newv)
965dbd914b8SShri Abhyankar {
966dbd914b8SShri Abhyankar   PetscErrorCode ierr;
967dbd914b8SShri Abhyankar   Vec            v;
968dbd914b8SShri Abhyankar 
969dbd914b8SShri Abhyankar   PetscFunctionBegin;
970dbd914b8SShri Abhyankar   ierr = VecCreate(((PetscObject)snes)->comm,&v);CHKERRQ(ierr);
971dbd914b8SShri Abhyankar   ierr = VecSetSizes(v,n,PETSC_DECIDE);CHKERRQ(ierr);
972dbd914b8SShri Abhyankar   ierr = VecSetFromOptions(v);CHKERRQ(ierr);
973dbd914b8SShri Abhyankar   *newv = v;
974dbd914b8SShri Abhyankar 
975dbd914b8SShri Abhyankar   PetscFunctionReturn(0);
976dbd914b8SShri Abhyankar }
977dbd914b8SShri Abhyankar 
978732bb160SShri Abhyankar /* Resets the snes PC and KSP when the active set sizes change */
979732bb160SShri Abhyankar #undef __FUNCT__
980732bb160SShri Abhyankar #define __FUNCT__ "SNESVIResetPCandKSP"
981732bb160SShri Abhyankar PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)
982732bb160SShri Abhyankar {
983732bb160SShri Abhyankar   PetscErrorCode         ierr;
984d0af7cd3SBarry Smith   KSP                    snesksp;
985dbd914b8SShri Abhyankar 
986732bb160SShri Abhyankar   PetscFunctionBegin;
987732bb160SShri Abhyankar   ierr = SNESGetKSP(snes,&snesksp);CHKERRQ(ierr);
988d0af7cd3SBarry Smith   ierr = KSPReset(snesksp);CHKERRQ(ierr);
989c2efdce3SBarry Smith 
990c2efdce3SBarry Smith   /*
991d0af7cd3SBarry Smith   KSP                    kspnew;
992d0af7cd3SBarry Smith   PC                     pcnew;
993d0af7cd3SBarry Smith   const MatSolverPackage stype;
994d0af7cd3SBarry Smith 
995c2efdce3SBarry Smith 
996732bb160SShri Abhyankar   ierr = KSPCreate(((PetscObject)snes)->comm,&kspnew);CHKERRQ(ierr);
997732bb160SShri Abhyankar   kspnew->pc_side = snesksp->pc_side;
998732bb160SShri Abhyankar   kspnew->rtol    = snesksp->rtol;
999732bb160SShri Abhyankar   kspnew->abstol    = snesksp->abstol;
1000732bb160SShri Abhyankar   kspnew->max_it  = snesksp->max_it;
1001732bb160SShri Abhyankar   ierr = KSPSetType(kspnew,((PetscObject)snesksp)->type_name);CHKERRQ(ierr);
1002732bb160SShri Abhyankar   ierr = KSPGetPC(kspnew,&pcnew);CHKERRQ(ierr);
1003732bb160SShri Abhyankar   ierr = PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);CHKERRQ(ierr);
1004732bb160SShri Abhyankar   ierr = PCSetOperators(kspnew->pc,Amat,Pmat,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
1005732bb160SShri Abhyankar   ierr = PCFactorGetMatSolverPackage(snesksp->pc,&stype);CHKERRQ(ierr);
1006732bb160SShri Abhyankar   ierr = PCFactorSetMatSolverPackage(kspnew->pc,stype);CHKERRQ(ierr);
10076bf464f9SBarry Smith   ierr = KSPDestroy(&snesksp);CHKERRQ(ierr);
1008732bb160SShri Abhyankar   snes->ksp = kspnew;
1009732bb160SShri Abhyankar   ierr = PetscLogObjectParent(snes,kspnew);CHKERRQ(ierr);
1010d0af7cd3SBarry Smith    ierr = KSPSetFromOptions(kspnew);CHKERRQ(ierr);*/
1011732bb160SShri Abhyankar   PetscFunctionReturn(0);
1012732bb160SShri Abhyankar }
101369c03620SShri Abhyankar 
101469c03620SShri Abhyankar 
1015fe835674SShri Abhyankar #undef __FUNCT__
1016fe835674SShri Abhyankar #define __FUNCT__ "SNESVIComputeInactiveSetFnorm"
101710f5ae6bSBarry Smith PetscErrorCode SNESVIComputeInactiveSetFnorm(SNES snes,Vec F,Vec X,PetscReal *fnorm)
1018fe835674SShri Abhyankar {
1019fe835674SShri Abhyankar   PetscErrorCode    ierr;
1020fe835674SShri Abhyankar   SNES_VI           *vi = (SNES_VI*)snes->data;
1021fe835674SShri Abhyankar   const PetscScalar *x,*xl,*xu,*f;
1022fe835674SShri Abhyankar   PetscInt          i,n;
1023fe835674SShri Abhyankar   PetscReal         rnorm;
1024fe835674SShri Abhyankar 
1025fe835674SShri Abhyankar   PetscFunctionBegin;
1026fe835674SShri Abhyankar   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
1027fe835674SShri Abhyankar   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
1028fe835674SShri Abhyankar   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
1029fe835674SShri Abhyankar   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
1030fe835674SShri Abhyankar   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
1031fe835674SShri Abhyankar   rnorm = 0.0;
1032fe835674SShri Abhyankar   for (i=0; i<n; i++) {
103310f5ae6bSBarry Smith     if (((PetscRealPart(x[i]) > PetscRealPart(xl[i]) + 1.e-8 || (PetscRealPart(f[i]) < 0.0)) && ((PetscRealPart(x[i]) < PetscRealPart(xu[i]) - 1.e-8) || PetscRealPart(f[i]) > 0.0))) rnorm += PetscRealPart(PetscConj(f[i])*f[i]);
1034fe835674SShri Abhyankar   }
1035fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
1036fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
1037fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
1038fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
1039d9822059SBarry Smith   ierr = MPI_Allreduce(&rnorm,fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
1040fe835674SShri Abhyankar   *fnorm = sqrt(*fnorm);
1041fe835674SShri Abhyankar   PetscFunctionReturn(0);
1042fe835674SShri Abhyankar }
1043fe835674SShri Abhyankar 
1044fe835674SShri Abhyankar /* Variational Inequality solver using reduce space method. No semismooth algorithm is
1045c2efdce3SBarry Smith    implemented in this algorithm. It basically identifies the active constraints and does
1046c2efdce3SBarry Smith    a linear solve on the other variables (those not associated with the active constraints). */
1047d950fb63SShri Abhyankar #undef __FUNCT__
1048d950fb63SShri Abhyankar #define __FUNCT__ "SNESSolveVI_RS"
1049d950fb63SShri Abhyankar PetscErrorCode SNESSolveVI_RS(SNES snes)
1050d950fb63SShri Abhyankar {
1051d950fb63SShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
1052d950fb63SShri Abhyankar   PetscErrorCode    ierr;
1053abcba341SShri Abhyankar   PetscInt          maxits,i,lits;
1054d950fb63SShri Abhyankar   PetscBool         lssucceed;
1055d950fb63SShri Abhyankar   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
1056fe835674SShri Abhyankar   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
1057d950fb63SShri Abhyankar   Vec                Y,X,F,G,W;
1058d950fb63SShri Abhyankar   KSPConvergedReason kspreason;
1059d950fb63SShri Abhyankar 
1060d950fb63SShri Abhyankar   PetscFunctionBegin;
1061d950fb63SShri Abhyankar   snes->numFailures            = 0;
1062d950fb63SShri Abhyankar   snes->numLinearSolveFailures = 0;
1063d950fb63SShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
1064d950fb63SShri Abhyankar 
1065d950fb63SShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
1066d950fb63SShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
1067d950fb63SShri Abhyankar   F		= snes->vec_func;	/* residual vector */
1068d950fb63SShri Abhyankar   Y		= snes->work[0];	/* work vectors */
1069d950fb63SShri Abhyankar   G		= snes->work[1];
1070d950fb63SShri Abhyankar   W		= snes->work[2];
1071d950fb63SShri Abhyankar 
1072d950fb63SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1073d950fb63SShri Abhyankar   snes->iter = 0;
1074d950fb63SShri Abhyankar   snes->norm = 0.0;
1075d950fb63SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1076d950fb63SShri Abhyankar 
10777fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
1078fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
1079d950fb63SShri Abhyankar   if (snes->domainerror) {
1080d950fb63SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1081d950fb63SShri Abhyankar     PetscFunctionReturn(0);
1082d950fb63SShri Abhyankar   }
1083fe835674SShri Abhyankar   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
1084d950fb63SShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
1085d950fb63SShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
108662cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1087d950fb63SShri Abhyankar 
1088d950fb63SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1089fe835674SShri Abhyankar   snes->norm = fnorm;
1090d950fb63SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1091fe835674SShri Abhyankar   SNESLogConvHistory(snes,fnorm,0);
10927a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
1093d950fb63SShri Abhyankar 
1094d950fb63SShri Abhyankar   /* set parameter for default relative tolerance convergence test */
1095fe835674SShri Abhyankar   snes->ttol = fnorm*snes->rtol;
1096d950fb63SShri Abhyankar   /* test convergence */
1097fe835674SShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1098d950fb63SShri Abhyankar   if (snes->reason) PetscFunctionReturn(0);
1099d950fb63SShri Abhyankar 
1100d950fb63SShri Abhyankar   for (i=0; i<maxits; i++) {
1101d950fb63SShri Abhyankar 
1102d950fb63SShri Abhyankar     IS         IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1103a6b72b01SJungho Lee     IS         IS_redact; /* redundant active set */
1104d950fb63SShri Abhyankar     VecScatter scat_act,scat_inact;
1105abcba341SShri Abhyankar     PetscInt   nis_act,nis_inact;
1106fe835674SShri Abhyankar     Vec        Y_act,Y_inact,F_inact;
1107d950fb63SShri Abhyankar     Mat        jac_inact_inact,prejac_inact_inact;
110862298a1eSBarry Smith     IS         keptrows;
1109abcba341SShri Abhyankar     PetscBool  isequal;
1110d950fb63SShri Abhyankar 
1111d950fb63SShri Abhyankar     /* Call general purpose update function */
1112d950fb63SShri Abhyankar     if (snes->ops->update) {
1113d950fb63SShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
1114d950fb63SShri Abhyankar     }
1115d950fb63SShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
111662298a1eSBarry Smith 
1117d950fb63SShri Abhyankar     /* Create active and inactive index sets */
1118a6b72b01SJungho Lee 
1119a6b72b01SJungho Lee     /*original
1120693ddf92SShri Abhyankar     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
1121a6b72b01SJungho Lee      */
1122a6b72b01SJungho Lee     ierr = SNESVIGetActiveSetIS(snes,X,F,&IS_act);CHKERRQ(ierr);
1123a6b72b01SJungho Lee 
1124a6b72b01SJungho Lee     if (vi->checkredundancy) {
1125a6b72b01SJungho Lee       (*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);CHKERRQ(ierr);
1126*ed70e96aSJungho Lee       if (IS_redact){
1127*ed70e96aSJungho Lee         ierr = ISSort(IS_redact);CHKERRQ(ierr);
1128a6b72b01SJungho Lee         ierr = ISComplement(IS_redact,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr);
1129a6b72b01SJungho Lee         ierr = ISDestroy(&IS_redact);CHKERRQ(ierr);
1130*ed70e96aSJungho Lee       }
1131*ed70e96aSJungho Lee       else {
1132*ed70e96aSJungho Lee         ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr);
1133*ed70e96aSJungho Lee       }
1134a6b72b01SJungho Lee     } else {
1135a6b72b01SJungho Lee       ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr);
1136a6b72b01SJungho Lee     }
1137d950fb63SShri Abhyankar 
11384dcab191SBarry Smith 
1139abcba341SShri Abhyankar     /* Create inactive set submatrix */
114062298a1eSBarry Smith     ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
1141a6b72b01SJungho Lee 
1142b3a44c85SBarry Smith     ierr = MatFindNonzeroRows(jac_inact_inact,&keptrows);CHKERRQ(ierr);
114362298a1eSBarry Smith     if (keptrows) {
114462298a1eSBarry Smith       PetscInt       cnt,*nrows,k;
114562298a1eSBarry Smith       const PetscInt *krows,*inact;
114627d4218bSShri Abhyankar       PetscInt       rstart=jac_inact_inact->rmap->rstart;
114762298a1eSBarry Smith 
11486bf464f9SBarry Smith       ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
11496bf464f9SBarry Smith       ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
115062298a1eSBarry Smith 
115162298a1eSBarry Smith       ierr = ISGetLocalSize(keptrows,&cnt);CHKERRQ(ierr);
115262298a1eSBarry Smith       ierr = ISGetIndices(keptrows,&krows);CHKERRQ(ierr);
115362298a1eSBarry Smith       ierr = ISGetIndices(IS_inact,&inact);CHKERRQ(ierr);
115462298a1eSBarry Smith       ierr = PetscMalloc(cnt*sizeof(PetscInt),&nrows);CHKERRQ(ierr);
115562298a1eSBarry Smith       for (k=0; k<cnt; k++) {
115627d4218bSShri Abhyankar         nrows[k] = inact[krows[k]-rstart];
115762298a1eSBarry Smith       }
115862298a1eSBarry Smith       ierr = ISRestoreIndices(keptrows,&krows);CHKERRQ(ierr);
115962298a1eSBarry Smith       ierr = ISRestoreIndices(IS_inact,&inact);CHKERRQ(ierr);
11606bf464f9SBarry Smith       ierr = ISDestroy(&keptrows);CHKERRQ(ierr);
11616bf464f9SBarry Smith       ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
116262298a1eSBarry Smith 
116327d4218bSShri Abhyankar       ierr = ISCreateGeneral(PETSC_COMM_WORLD,cnt,nrows,PETSC_OWN_POINTER,&IS_inact);CHKERRQ(ierr);
116427d4218bSShri Abhyankar       ierr = ISComplement(IS_inact,F->map->rstart,F->map->rend,&IS_act);CHKERRQ(ierr);
116562298a1eSBarry Smith       ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
116662298a1eSBarry Smith     }
11679e516c8fSBarry Smith     ierr = DMSetVI(snes->dm,vi->xu,vi->xl,X,F,IS_inact);CHKERRQ(ierr);
116862298a1eSBarry Smith 
1169d950fb63SShri Abhyankar     /* Get sizes of active and inactive sets */
1170d950fb63SShri Abhyankar     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
1171d950fb63SShri Abhyankar     ierr = ISGetLocalSize(IS_inact,&nis_inact);CHKERRQ(ierr);
1172d950fb63SShri Abhyankar 
1173d950fb63SShri Abhyankar     /* Create active and inactive set vectors */
1174fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_inact,&F_inact);CHKERRQ(ierr);
1175fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_act,&Y_act);CHKERRQ(ierr);
1176fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_inact,&Y_inact);CHKERRQ(ierr);
1177d950fb63SShri Abhyankar 
1178d950fb63SShri Abhyankar     /* Create scatter contexts */
1179d950fb63SShri Abhyankar     ierr = VecScatterCreate(Y,IS_act,Y_act,PETSC_NULL,&scat_act);CHKERRQ(ierr);
1180d950fb63SShri Abhyankar     ierr = VecScatterCreate(Y,IS_inact,Y_inact,PETSC_NULL,&scat_inact);CHKERRQ(ierr);
1181d950fb63SShri Abhyankar 
1182d950fb63SShri Abhyankar     /* Do a vec scatter to active and inactive set vectors */
1183fe835674SShri Abhyankar     ierr = VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1184fe835674SShri Abhyankar     ierr = VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1185d950fb63SShri Abhyankar 
1186d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1187d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1188d950fb63SShri Abhyankar 
1189d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1190d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1191d950fb63SShri Abhyankar 
1192d950fb63SShri Abhyankar     /* Active set direction = 0 */
1193d950fb63SShri Abhyankar     ierr = VecSet(Y_act,0);CHKERRQ(ierr);
1194d950fb63SShri Abhyankar     if (snes->jacobian != snes->jacobian_pre) {
1195d950fb63SShri Abhyankar       ierr = MatGetSubMatrix(snes->jacobian_pre,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);CHKERRQ(ierr);
1196d950fb63SShri Abhyankar     } else prejac_inact_inact = jac_inact_inact;
1197d950fb63SShri Abhyankar 
1198abcba341SShri Abhyankar     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
1199abcba341SShri Abhyankar     if (!isequal) {
1200732bb160SShri Abhyankar       ierr = SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr);
1201c58c0d17SBarry Smith       flg  = DIFFERENT_NONZERO_PATTERN;
1202d950fb63SShri Abhyankar     }
1203d950fb63SShri Abhyankar 
120413e0d083SBarry Smith     /*      ierr = ISView(IS_inact,0);CHKERRQ(ierr); */
120513e0d083SBarry Smith     /*      ierr = ISView(IS_act,0);CHKERRQ(ierr);*/
120613e0d083SBarry Smith     /*      ierr = MatView(snes->jacobian_pre,0); */
120713e0d083SBarry Smith 
1208d950fb63SShri Abhyankar     ierr = KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact,flg);CHKERRQ(ierr);
120913e0d083SBarry Smith     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
121013e0d083SBarry Smith     {
121113e0d083SBarry Smith       PC        pc;
121213e0d083SBarry Smith       PetscBool flg;
121313e0d083SBarry Smith       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
121413e0d083SBarry Smith       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
121513e0d083SBarry Smith       if (flg) {
121613e0d083SBarry Smith         KSP      *subksps;
121713e0d083SBarry Smith         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
121813e0d083SBarry Smith         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
121913e0d083SBarry Smith         ierr = PetscFree(subksps);CHKERRQ(ierr);
122013e0d083SBarry Smith         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
122113e0d083SBarry Smith         if (flg) {
122213e0d083SBarry Smith           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
122313e0d083SBarry Smith           const PetscInt *ii;
122413e0d083SBarry Smith 
122513e0d083SBarry Smith           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
122613e0d083SBarry Smith           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
122713e0d083SBarry Smith           for (j=0; j<n; j++) {
122813e0d083SBarry Smith             if (ii[j] < N) cnts[0]++;
122913e0d083SBarry Smith             else if (ii[j] < 2*N) cnts[1]++;
123013e0d083SBarry Smith             else if (ii[j] < 3*N) cnts[2]++;
123113e0d083SBarry Smith           }
123213e0d083SBarry Smith           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
123313e0d083SBarry Smith 
123413e0d083SBarry Smith           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
123513e0d083SBarry Smith         }
123613e0d083SBarry Smith       }
123713e0d083SBarry Smith     }
123813e0d083SBarry Smith 
1239fe835674SShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,F_inact,Y_inact);CHKERRQ(ierr);
1240d950fb63SShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
1241d950fb63SShri Abhyankar     if (kspreason < 0) {
1242d950fb63SShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
1243d950fb63SShri Abhyankar         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
1244d950fb63SShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
1245d950fb63SShri Abhyankar         break;
1246d950fb63SShri Abhyankar       }
1247d950fb63SShri Abhyankar      }
1248d950fb63SShri Abhyankar 
1249d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1250d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1251d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1252d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1253d950fb63SShri Abhyankar 
12546bf464f9SBarry Smith     ierr = VecDestroy(&F_inact);CHKERRQ(ierr);
12556bf464f9SBarry Smith     ierr = VecDestroy(&Y_act);CHKERRQ(ierr);
12566bf464f9SBarry Smith     ierr = VecDestroy(&Y_inact);CHKERRQ(ierr);
12576bf464f9SBarry Smith     ierr = VecScatterDestroy(&scat_act);CHKERRQ(ierr);
12586bf464f9SBarry Smith     ierr = VecScatterDestroy(&scat_inact);CHKERRQ(ierr);
12596bf464f9SBarry Smith     ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
1260abcba341SShri Abhyankar     if (!isequal) {
12616bf464f9SBarry Smith       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
1262abcba341SShri Abhyankar       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
1263abcba341SShri Abhyankar     }
12646bf464f9SBarry Smith     ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
12656bf464f9SBarry Smith     ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
1266d950fb63SShri Abhyankar     if (snes->jacobian != snes->jacobian_pre) {
12676bf464f9SBarry Smith       ierr = MatDestroy(&prejac_inact_inact);CHKERRQ(ierr);
1268d950fb63SShri Abhyankar     }
1269d950fb63SShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
1270d950fb63SShri Abhyankar     snes->linear_its += lits;
1271d950fb63SShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
1272d950fb63SShri Abhyankar     /*
1273d950fb63SShri Abhyankar     if (vi->precheckstep) {
1274d950fb63SShri Abhyankar       PetscBool changed_y = PETSC_FALSE;
1275d950fb63SShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
1276d950fb63SShri Abhyankar     }
1277d950fb63SShri Abhyankar 
1278d950fb63SShri Abhyankar     if (PetscLogPrintInfo){
1279d950fb63SShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
1280d950fb63SShri Abhyankar     }
1281d950fb63SShri Abhyankar     */
1282d950fb63SShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
1283d950fb63SShri Abhyankar          Y <- X - lambda*Y
1284d950fb63SShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
1285d950fb63SShri Abhyankar     */
1286d950fb63SShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
1287fe835674SShri Abhyankar     ynorm = 1; gnorm = fnorm;
1288fe835674SShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
1289fe835674SShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
12902b4ed282SShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
12912b4ed282SShri Abhyankar     if (snes->domainerror) {
12922b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
12934c661befSBarry Smith       ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr);
12942b4ed282SShri Abhyankar       PetscFunctionReturn(0);
12952b4ed282SShri Abhyankar     }
12962b4ed282SShri Abhyankar     if (!lssucceed) {
12972b4ed282SShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
12982b4ed282SShri Abhyankar 	PetscBool ismin;
12992b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
13002b4ed282SShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
13012b4ed282SShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
13022b4ed282SShri Abhyankar         break;
13032b4ed282SShri Abhyankar       }
13042b4ed282SShri Abhyankar     }
13052b4ed282SShri Abhyankar     /* Update function and solution vectors */
1306fe835674SShri Abhyankar     fnorm = gnorm;
1307fe835674SShri Abhyankar     ierr = VecCopy(G,F);CHKERRQ(ierr);
13082b4ed282SShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
13092b4ed282SShri Abhyankar     /* Monitor convergence */
13102b4ed282SShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
13112b4ed282SShri Abhyankar     snes->iter = i+1;
1312fe835674SShri Abhyankar     snes->norm = fnorm;
13132b4ed282SShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
13142b4ed282SShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
13157a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
13162b4ed282SShri Abhyankar     /* Test for convergence, xnorm = || X || */
13172b4ed282SShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
1318fe835674SShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
13192b4ed282SShri Abhyankar     if (snes->reason) break;
13202b4ed282SShri Abhyankar   }
13214c661befSBarry Smith   ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr);
13222b4ed282SShri Abhyankar   if (i == maxits) {
13232b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
13242b4ed282SShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
13252b4ed282SShri Abhyankar   }
13262b4ed282SShri Abhyankar   PetscFunctionReturn(0);
13272b4ed282SShri Abhyankar }
13282b4ed282SShri Abhyankar 
13292f63a38cSShri Abhyankar #undef __FUNCT__
1330720c9a41SShri Abhyankar #define __FUNCT__ "SNESVISetRedundancyCheck"
1331cb5fe31bSShri Abhyankar PetscErrorCode SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (*func)(SNES,IS,IS*,void*),void *ctx)
13322f63a38cSShri Abhyankar {
13332f63a38cSShri Abhyankar   SNES_VI         *vi = (SNES_VI*)snes->data;
13342f63a38cSShri Abhyankar 
13352f63a38cSShri Abhyankar   PetscFunctionBegin;
13362f63a38cSShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
13372f63a38cSShri Abhyankar   vi->checkredundancy = func;
1338cb5fe31bSShri Abhyankar   vi->ctxP            = ctx;
13392f63a38cSShri Abhyankar   PetscFunctionReturn(0);
13402f63a38cSShri Abhyankar }
13412f63a38cSShri Abhyankar 
1342ff596062SShri Abhyankar #if defined(PETSC_HAVE_MATLAB_ENGINE)
1343ff596062SShri Abhyankar #include <engine.h>
1344ff596062SShri Abhyankar #include <mex.h>
1345cb5fe31bSShri Abhyankar typedef struct {char *funcname; mxArray *ctx;} SNESMatlabContext;
1346ff596062SShri Abhyankar 
1347ff596062SShri Abhyankar #undef __FUNCT__
1348ff596062SShri Abhyankar #define __FUNCT__ "SNESVIRedundancyCheck_Matlab"
1349ff596062SShri Abhyankar PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS* is_redact,void* ctx)
1350ff596062SShri Abhyankar {
1351ff596062SShri Abhyankar   PetscErrorCode      ierr;
1352cb5fe31bSShri Abhyankar   SNESMatlabContext   *sctx = (SNESMatlabContext*)ctx;
1353cb5fe31bSShri Abhyankar   int                 nlhs = 1, nrhs = 5;
1354cb5fe31bSShri Abhyankar   mxArray             *plhs[1], *prhs[5];
1355cb5fe31bSShri Abhyankar   long long int       l1 = 0, l2 = 0, ls = 0;
1356fcb1c9afSShri Abhyankar   PetscInt            *indices=PETSC_NULL;
1357ff596062SShri Abhyankar 
1358ff596062SShri Abhyankar   PetscFunctionBegin;
1359ff596062SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1360ff596062SShri Abhyankar   PetscValidHeaderSpecific(is_act,IS_CLASSID,2);
1361ff596062SShri Abhyankar   PetscValidPointer(is_redact,3);
1362ff596062SShri Abhyankar   PetscCheckSameComm(snes,1,is_act,2);
1363ff596062SShri Abhyankar 
136409db5ad8SShri Abhyankar   /* Create IS for reduced active set of size 0, its size and indices will
136509db5ad8SShri Abhyankar    bet set by the Matlab function */
1366fcb1c9afSShri Abhyankar   ierr = ISCreateGeneral(((PetscObject)snes)->comm,0,indices,PETSC_OWN_POINTER,is_redact);CHKERRQ(ierr);
1367cb5fe31bSShri Abhyankar   /* call Matlab function in ctx */
1368ff596062SShri Abhyankar   ierr = PetscMemcpy(&ls,&snes,sizeof(snes));CHKERRQ(ierr);
1369ff596062SShri Abhyankar   ierr = PetscMemcpy(&l1,&is_act,sizeof(is_act));CHKERRQ(ierr);
1370cb5fe31bSShri Abhyankar   ierr = PetscMemcpy(&l2,is_redact,sizeof(is_act));CHKERRQ(ierr);
1371ff596062SShri Abhyankar   prhs[0] = mxCreateDoubleScalar((double)ls);
1372ff596062SShri Abhyankar   prhs[1] = mxCreateDoubleScalar((double)l1);
1373cb5fe31bSShri Abhyankar   prhs[2] = mxCreateDoubleScalar((double)l2);
1374cb5fe31bSShri Abhyankar   prhs[3] = mxCreateString(sctx->funcname);
1375cb5fe31bSShri Abhyankar   prhs[4] = sctx->ctx;
1376ff596062SShri Abhyankar   ierr    = mexCallMATLAB(nlhs,plhs,nrhs,prhs,"PetscSNESVIRedundancyCheckInternal");CHKERRQ(ierr);
1377ff596062SShri Abhyankar   ierr    = mxGetScalar(plhs[0]);CHKERRQ(ierr);
1378ff596062SShri Abhyankar   mxDestroyArray(prhs[0]);
1379ff596062SShri Abhyankar   mxDestroyArray(prhs[1]);
1380ff596062SShri Abhyankar   mxDestroyArray(prhs[2]);
1381ff596062SShri Abhyankar   mxDestroyArray(prhs[3]);
1382ff596062SShri Abhyankar   mxDestroyArray(plhs[0]);
1383ff596062SShri Abhyankar   PetscFunctionReturn(0);
1384ff596062SShri Abhyankar }
1385ff596062SShri Abhyankar 
1386ff596062SShri Abhyankar #undef __FUNCT__
1387ff596062SShri Abhyankar #define __FUNCT__ "SNESVISetRedundancyCheckMatlab"
1388ff596062SShri Abhyankar PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes,const char* func,mxArray* ctx)
1389ff596062SShri Abhyankar {
1390ff596062SShri Abhyankar   PetscErrorCode      ierr;
1391cb5fe31bSShri Abhyankar   SNESMatlabContext   *sctx;
1392ff596062SShri Abhyankar 
1393ff596062SShri Abhyankar   PetscFunctionBegin;
1394ff596062SShri Abhyankar   /* currently sctx is memory bleed */
1395cb5fe31bSShri Abhyankar   ierr = PetscMalloc(sizeof(SNESMatlabContext),&sctx);CHKERRQ(ierr);
1396ff596062SShri Abhyankar   ierr = PetscStrallocpy(func,&sctx->funcname);CHKERRQ(ierr);
1397ff596062SShri Abhyankar   sctx->ctx = mxDuplicateArray(ctx);
1398cb5fe31bSShri Abhyankar   ierr = SNESVISetRedundancyCheck(snes,SNESVIRedundancyCheck_Matlab,sctx);CHKERRQ(ierr);
1399ff596062SShri Abhyankar   PetscFunctionReturn(0);
1400ff596062SShri Abhyankar }
1401ff596062SShri Abhyankar 
1402ff596062SShri Abhyankar #endif
1403ff596062SShri Abhyankar 
1404ff596062SShri Abhyankar 
14052f63a38cSShri Abhyankar /* Variational Inequality solver using augmented space method. It does the opposite of the
14062f63a38cSShri Abhyankar    reduced space method i.e. it identifies the active set variables and instead of discarding
1407720c9a41SShri Abhyankar    them it augments the original system by introducing additional equality
140856a221efSShri Abhyankar    constraint equations for active set variables. The user can optionally provide an IS for
140956a221efSShri Abhyankar    a subset of 'redundant' active set variables which will treated as free variables.
14102f63a38cSShri Abhyankar    Specific implementation for Allen-Cahn problem
14112f63a38cSShri Abhyankar */
14122f63a38cSShri Abhyankar #undef __FUNCT__
1413b350b9c9SBarry Smith #define __FUNCT__ "SNESSolveVI_RSAUG"
1414b350b9c9SBarry Smith PetscErrorCode SNESSolveVI_RSAUG(SNES snes)
14152f63a38cSShri Abhyankar {
14162f63a38cSShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
14172f63a38cSShri Abhyankar   PetscErrorCode    ierr;
14182f63a38cSShri Abhyankar   PetscInt          maxits,i,lits;
14192f63a38cSShri Abhyankar   PetscBool         lssucceed;
14202f63a38cSShri Abhyankar   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
14212f63a38cSShri Abhyankar   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
14222f63a38cSShri Abhyankar   Vec                Y,X,F,G,W;
14232f63a38cSShri Abhyankar   KSPConvergedReason kspreason;
14242f63a38cSShri Abhyankar 
14252f63a38cSShri Abhyankar   PetscFunctionBegin;
14262f63a38cSShri Abhyankar   snes->numFailures            = 0;
14272f63a38cSShri Abhyankar   snes->numLinearSolveFailures = 0;
14282f63a38cSShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
14292f63a38cSShri Abhyankar 
14302f63a38cSShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
14312f63a38cSShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
14322f63a38cSShri Abhyankar   F		= snes->vec_func;	/* residual vector */
14332f63a38cSShri Abhyankar   Y		= snes->work[0];	/* work vectors */
14342f63a38cSShri Abhyankar   G		= snes->work[1];
14352f63a38cSShri Abhyankar   W		= snes->work[2];
14362f63a38cSShri Abhyankar 
14372f63a38cSShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
14382f63a38cSShri Abhyankar   snes->iter = 0;
14392f63a38cSShri Abhyankar   snes->norm = 0.0;
14402f63a38cSShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
14412f63a38cSShri Abhyankar 
14422f63a38cSShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
14432f63a38cSShri Abhyankar   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
14442f63a38cSShri Abhyankar   if (snes->domainerror) {
14452f63a38cSShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
14462f63a38cSShri Abhyankar     PetscFunctionReturn(0);
14472f63a38cSShri Abhyankar   }
14482f63a38cSShri Abhyankar   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
14492f63a38cSShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
14502f63a38cSShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
145162cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
14522f63a38cSShri Abhyankar 
14532f63a38cSShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
14542f63a38cSShri Abhyankar   snes->norm = fnorm;
14552f63a38cSShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
14562f63a38cSShri Abhyankar   SNESLogConvHistory(snes,fnorm,0);
14577a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
14582f63a38cSShri Abhyankar 
14592f63a38cSShri Abhyankar   /* set parameter for default relative tolerance convergence test */
14602f63a38cSShri Abhyankar   snes->ttol = fnorm*snes->rtol;
14612f63a38cSShri Abhyankar   /* test convergence */
14622f63a38cSShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
14632f63a38cSShri Abhyankar   if (snes->reason) PetscFunctionReturn(0);
14642f63a38cSShri Abhyankar 
14652f63a38cSShri Abhyankar   for (i=0; i<maxits; i++) {
14662f63a38cSShri Abhyankar     IS             IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1467cb5fe31bSShri Abhyankar     IS             IS_redact; /* redundant active set */
146856a221efSShri Abhyankar     Mat            J_aug,Jpre_aug;
146956a221efSShri Abhyankar     Vec            F_aug,Y_aug;
147056a221efSShri Abhyankar     PetscInt       nis_redact,nis_act;
147156a221efSShri Abhyankar     const PetscInt *idx_redact,*idx_act;
147256a221efSShri Abhyankar     PetscInt       k;
147363ee972cSSatish Balay     PetscInt       *idx_actkept=PETSC_NULL,nkept=0; /* list of kept active set */
147456a221efSShri Abhyankar     PetscScalar    *f,*f2;
14752f63a38cSShri Abhyankar     PetscBool      isequal;
147656a221efSShri Abhyankar     PetscInt       i1=0,j1=0;
14772f63a38cSShri Abhyankar 
14782f63a38cSShri Abhyankar     /* Call general purpose update function */
14792f63a38cSShri Abhyankar     if (snes->ops->update) {
14802f63a38cSShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
14812f63a38cSShri Abhyankar     }
14822f63a38cSShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
14832f63a38cSShri Abhyankar 
14842f63a38cSShri Abhyankar     /* Create active and inactive index sets */
14852f63a38cSShri Abhyankar     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
14862f63a38cSShri Abhyankar 
148756a221efSShri Abhyankar     /* Get local active set size */
14882f63a38cSShri Abhyankar     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
148956a221efSShri Abhyankar     if (nis_act) {
1490e63076c7SBarry Smith       ierr = ISGetIndices(IS_act,&idx_act);CHKERRQ(ierr);
1491e63076c7SBarry Smith       IS_redact  = PETSC_NULL;
149256a221efSShri Abhyankar       if(vi->checkredundancy) {
1493cb5fe31bSShri Abhyankar 	(*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);
149456a221efSShri Abhyankar       }
14952f63a38cSShri Abhyankar 
149656a221efSShri Abhyankar       if(!IS_redact) {
149756a221efSShri Abhyankar 	/* User called checkredundancy function but didn't create IS_redact because
149856a221efSShri Abhyankar            there were no redundant active set variables */
149956a221efSShri Abhyankar 	/* Copy over all active set indices to the list */
150056a221efSShri Abhyankar 	ierr = PetscMalloc(nis_act*sizeof(PetscInt),&idx_actkept);CHKERRQ(ierr);
150156a221efSShri Abhyankar 	for(k=0;k < nis_act;k++) idx_actkept[k] = idx_act[k];
150256a221efSShri Abhyankar 	nkept = nis_act;
150356a221efSShri Abhyankar       } else {
150456a221efSShri Abhyankar 	ierr = ISGetLocalSize(IS_redact,&nis_redact);CHKERRQ(ierr);
150556a221efSShri Abhyankar 	ierr = PetscMalloc((nis_act-nis_redact)*sizeof(PetscInt),&idx_actkept);CHKERRQ(ierr);
15062f63a38cSShri Abhyankar 
150756a221efSShri Abhyankar 	/* Create reduced active set list */
150856a221efSShri Abhyankar 	ierr = ISGetIndices(IS_act,&idx_act);CHKERRQ(ierr);
150956a221efSShri Abhyankar 	ierr = ISGetIndices(IS_redact,&idx_redact);CHKERRQ(ierr);
1510cb5fe31bSShri Abhyankar 	j1 = 0;nkept = 0;
151156a221efSShri Abhyankar 	for(k=0;k<nis_act;k++) {
151256a221efSShri Abhyankar 	  if(j1 < nis_redact && idx_act[k] == idx_redact[j1]) j1++;
151356a221efSShri Abhyankar 	  else idx_actkept[nkept++] = idx_act[k];
151456a221efSShri Abhyankar 	}
151556a221efSShri Abhyankar 	ierr = ISRestoreIndices(IS_act,&idx_act);CHKERRQ(ierr);
151656a221efSShri Abhyankar 	ierr = ISRestoreIndices(IS_redact,&idx_redact);CHKERRQ(ierr);
1517cb5fe31bSShri Abhyankar 
1518cb5fe31bSShri Abhyankar         ierr = ISDestroy(&IS_redact);CHKERRQ(ierr);
151956a221efSShri Abhyankar       }
15202f63a38cSShri Abhyankar 
152156a221efSShri Abhyankar       /* Create augmented F and Y */
152256a221efSShri Abhyankar       ierr = VecCreate(((PetscObject)snes)->comm,&F_aug);CHKERRQ(ierr);
152356a221efSShri Abhyankar       ierr = VecSetSizes(F_aug,F->map->n+nkept,PETSC_DECIDE);CHKERRQ(ierr);
152456a221efSShri Abhyankar       ierr = VecSetFromOptions(F_aug);CHKERRQ(ierr);
152556a221efSShri Abhyankar       ierr = VecDuplicate(F_aug,&Y_aug);CHKERRQ(ierr);
15262f63a38cSShri Abhyankar 
152756a221efSShri Abhyankar       /* Copy over F to F_aug in the first n locations */
152856a221efSShri Abhyankar       ierr = VecGetArray(F,&f);CHKERRQ(ierr);
152956a221efSShri Abhyankar       ierr = VecGetArray(F_aug,&f2);CHKERRQ(ierr);
153056a221efSShri Abhyankar       ierr = PetscMemcpy(f2,f,F->map->n*sizeof(PetscScalar));CHKERRQ(ierr);
153156a221efSShri Abhyankar       ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
153256a221efSShri Abhyankar       ierr = VecRestoreArray(F_aug,&f2);CHKERRQ(ierr);
15332f63a38cSShri Abhyankar 
153456a221efSShri Abhyankar       /* Create the augmented jacobian matrix */
153556a221efSShri Abhyankar       ierr = MatCreate(((PetscObject)snes)->comm,&J_aug);CHKERRQ(ierr);
153656a221efSShri Abhyankar       ierr = MatSetSizes(J_aug,X->map->n+nkept,X->map->n+nkept,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
153756a221efSShri Abhyankar       ierr = MatSetFromOptions(J_aug);CHKERRQ(ierr);
15382f63a38cSShri Abhyankar 
153956a221efSShri Abhyankar 
15409521db3cSSatish Balay       { /* local vars */
1541493a4f3dSShri Abhyankar       /* Preallocate augmented matrix and set values in it...Doing only sequential case first*/
154256a221efSShri Abhyankar       PetscInt          ncols;
154356a221efSShri Abhyankar       const PetscInt    *cols;
154456a221efSShri Abhyankar       const PetscScalar *vals;
15452969f145SShri Abhyankar       PetscScalar        value[2];
15462969f145SShri Abhyankar       PetscInt           row,col[2];
1547493a4f3dSShri Abhyankar       PetscInt           *d_nnz;
15482969f145SShri Abhyankar       value[0] = 1.0; value[1] = 0.0;
1549493a4f3dSShri Abhyankar       ierr = PetscMalloc((X->map->n+nkept)*sizeof(PetscInt),&d_nnz);CHKERRQ(ierr);
1550493a4f3dSShri Abhyankar       ierr = PetscMemzero(d_nnz,(X->map->n+nkept)*sizeof(PetscInt));CHKERRQ(ierr);
1551493a4f3dSShri Abhyankar       for(row=0;row<snes->jacobian->rmap->n;row++) {
1552493a4f3dSShri Abhyankar         ierr = MatGetRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
1553493a4f3dSShri Abhyankar         d_nnz[row] += ncols;
1554493a4f3dSShri Abhyankar         ierr = MatRestoreRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
1555493a4f3dSShri Abhyankar       }
1556493a4f3dSShri Abhyankar 
1557493a4f3dSShri Abhyankar       for(k=0;k<nkept;k++) {
1558493a4f3dSShri Abhyankar         d_nnz[idx_actkept[k]] += 1;
15592969f145SShri Abhyankar         d_nnz[snes->jacobian->rmap->n+k] += 2;
1560493a4f3dSShri Abhyankar       }
1561493a4f3dSShri Abhyankar       ierr = MatSeqAIJSetPreallocation(J_aug,PETSC_NULL,d_nnz);CHKERRQ(ierr);
1562493a4f3dSShri Abhyankar 
1563493a4f3dSShri Abhyankar       ierr = PetscFree(d_nnz);CHKERRQ(ierr);
156456a221efSShri Abhyankar 
156556a221efSShri Abhyankar       /* Set the original jacobian matrix in J_aug */
156656a221efSShri Abhyankar       for(row=0;row<snes->jacobian->rmap->n;row++) {
156756a221efSShri Abhyankar 	ierr = MatGetRow(snes->jacobian,row,&ncols,&cols,&vals);CHKERRQ(ierr);
156856a221efSShri Abhyankar 	ierr = MatSetValues(J_aug,1,&row,ncols,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
156956a221efSShri Abhyankar 	ierr = MatRestoreRow(snes->jacobian,row,&ncols,&cols,&vals);CHKERRQ(ierr);
157056a221efSShri Abhyankar       }
157156a221efSShri Abhyankar       /* Add the augmented part */
157256a221efSShri Abhyankar       for(k=0;k<nkept;k++) {
15732969f145SShri Abhyankar 	row = snes->jacobian->rmap->n+k;
15742969f145SShri Abhyankar 	col[0] = idx_actkept[k]; col[1] = snes->jacobian->rmap->n+k;
15752969f145SShri Abhyankar 	ierr = MatSetValues(J_aug,1,&row,1,col,value,INSERT_VALUES);CHKERRQ(ierr);
15762969f145SShri Abhyankar 	ierr = MatSetValues(J_aug,1,&col[0],1,&row,&value[0],INSERT_VALUES);CHKERRQ(ierr);
157756a221efSShri Abhyankar       }
157856a221efSShri Abhyankar       ierr = MatAssemblyBegin(J_aug,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
157956a221efSShri Abhyankar       ierr = MatAssemblyEnd(J_aug,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
158056a221efSShri Abhyankar       /* Only considering prejac = jac for now */
158156a221efSShri Abhyankar       Jpre_aug = J_aug;
15829521db3cSSatish Balay       } /* local vars*/
1583e63076c7SBarry Smith       ierr = ISRestoreIndices(IS_act,&idx_act);CHKERRQ(ierr);
1584e63076c7SBarry Smith       ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
158556a221efSShri Abhyankar     } else {
158656a221efSShri Abhyankar       F_aug = F; J_aug = snes->jacobian; Y_aug = Y; Jpre_aug = snes->jacobian_pre;
158756a221efSShri Abhyankar     }
15882f63a38cSShri Abhyankar 
15892f63a38cSShri Abhyankar     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
15902f63a38cSShri Abhyankar     if (!isequal) {
159156a221efSShri Abhyankar       ierr = SNESVIResetPCandKSP(snes,J_aug,Jpre_aug);CHKERRQ(ierr);
15922f63a38cSShri Abhyankar     }
159356a221efSShri Abhyankar     ierr = KSPSetOperators(snes->ksp,J_aug,Jpre_aug,flg);CHKERRQ(ierr);
15942f63a38cSShri Abhyankar     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
159556a221efSShri Abhyankar     /*  {
15962f63a38cSShri Abhyankar       PC        pc;
15972f63a38cSShri Abhyankar       PetscBool flg;
15982f63a38cSShri Abhyankar       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
15992f63a38cSShri Abhyankar       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
16002f63a38cSShri Abhyankar       if (flg) {
16012f63a38cSShri Abhyankar         KSP      *subksps;
16022f63a38cSShri Abhyankar         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
16032f63a38cSShri Abhyankar         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
16042f63a38cSShri Abhyankar         ierr = PetscFree(subksps);CHKERRQ(ierr);
16052f63a38cSShri Abhyankar         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
16062f63a38cSShri Abhyankar         if (flg) {
16072f63a38cSShri Abhyankar           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
16082f63a38cSShri Abhyankar           const PetscInt *ii;
16092f63a38cSShri Abhyankar 
16102f63a38cSShri Abhyankar           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
16112f63a38cSShri Abhyankar           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
16122f63a38cSShri Abhyankar           for (j=0; j<n; j++) {
16132f63a38cSShri Abhyankar             if (ii[j] < N) cnts[0]++;
16142f63a38cSShri Abhyankar             else if (ii[j] < 2*N) cnts[1]++;
16152f63a38cSShri Abhyankar             else if (ii[j] < 3*N) cnts[2]++;
16162f63a38cSShri Abhyankar           }
16172f63a38cSShri Abhyankar           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
16182f63a38cSShri Abhyankar 
16192f63a38cSShri Abhyankar           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
16202f63a38cSShri Abhyankar         }
16212f63a38cSShri Abhyankar       }
16222f63a38cSShri Abhyankar     }
162356a221efSShri Abhyankar     */
162456a221efSShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,F_aug,Y_aug);CHKERRQ(ierr);
16252f63a38cSShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
16262f63a38cSShri Abhyankar     if (kspreason < 0) {
16272f63a38cSShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
16282f63a38cSShri Abhyankar         ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr);
16292f63a38cSShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
16302f63a38cSShri Abhyankar         break;
16312f63a38cSShri Abhyankar       }
16322f63a38cSShri Abhyankar     }
16332f63a38cSShri Abhyankar 
163456a221efSShri Abhyankar     if(nis_act) {
163556a221efSShri Abhyankar       PetscScalar *y1,*y2;
163656a221efSShri Abhyankar       ierr = VecGetArray(Y,&y1);CHKERRQ(ierr);
163756a221efSShri Abhyankar       ierr = VecGetArray(Y_aug,&y2);CHKERRQ(ierr);
163856a221efSShri Abhyankar       /* Copy over inactive Y_aug to Y */
163956a221efSShri Abhyankar       j1 = 0;
164056a221efSShri Abhyankar       for(i1=Y->map->rstart;i1 < Y->map->rend;i1++) {
164156a221efSShri Abhyankar 	if(j1 < nkept && idx_actkept[j1] == i1) j1++;
164256a221efSShri Abhyankar 	else y1[i1-Y->map->rstart] = y2[i1-Y->map->rstart];
164356a221efSShri Abhyankar       }
164456a221efSShri Abhyankar       ierr = VecRestoreArray(Y,&y1);CHKERRQ(ierr);
164556a221efSShri Abhyankar       ierr = VecRestoreArray(Y_aug,&y2);CHKERRQ(ierr);
16462f63a38cSShri Abhyankar 
16476bf464f9SBarry Smith       ierr = VecDestroy(&F_aug);CHKERRQ(ierr);
16486bf464f9SBarry Smith       ierr = VecDestroy(&Y_aug);CHKERRQ(ierr);
16496bf464f9SBarry Smith       ierr = MatDestroy(&J_aug);CHKERRQ(ierr);
165056a221efSShri Abhyankar       ierr = PetscFree(idx_actkept);CHKERRQ(ierr);
165156a221efSShri Abhyankar     }
165256a221efSShri Abhyankar 
16532f63a38cSShri Abhyankar     if (!isequal) {
16546bf464f9SBarry Smith       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
16552f63a38cSShri Abhyankar       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
16562f63a38cSShri Abhyankar     }
16576bf464f9SBarry Smith     ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
165856a221efSShri Abhyankar 
16592f63a38cSShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
16602f63a38cSShri Abhyankar     snes->linear_its += lits;
16612f63a38cSShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
16622f63a38cSShri Abhyankar     /*
16632f63a38cSShri Abhyankar     if (vi->precheckstep) {
16642f63a38cSShri Abhyankar       PetscBool changed_y = PETSC_FALSE;
16652f63a38cSShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
16662f63a38cSShri Abhyankar     }
16672f63a38cSShri Abhyankar 
16682f63a38cSShri Abhyankar     if (PetscLogPrintInfo){
16692f63a38cSShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
16702f63a38cSShri Abhyankar     }
16712f63a38cSShri Abhyankar     */
16722f63a38cSShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
16732f63a38cSShri Abhyankar          Y <- X - lambda*Y
16742f63a38cSShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
16752f63a38cSShri Abhyankar     */
16762f63a38cSShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
16772f63a38cSShri Abhyankar     ynorm = 1; gnorm = fnorm;
16782f63a38cSShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
16792f63a38cSShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
16802f63a38cSShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
16812f63a38cSShri Abhyankar     if (snes->domainerror) {
16822f63a38cSShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
16832f63a38cSShri Abhyankar       PetscFunctionReturn(0);
16842f63a38cSShri Abhyankar     }
16852f63a38cSShri Abhyankar     if (!lssucceed) {
16862f63a38cSShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
16872f63a38cSShri Abhyankar 	PetscBool ismin;
16882f63a38cSShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
16892f63a38cSShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
16902f63a38cSShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
16912f63a38cSShri Abhyankar         break;
16922f63a38cSShri Abhyankar       }
16932f63a38cSShri Abhyankar     }
16942f63a38cSShri Abhyankar     /* Update function and solution vectors */
16952f63a38cSShri Abhyankar     fnorm = gnorm;
16962f63a38cSShri Abhyankar     ierr = VecCopy(G,F);CHKERRQ(ierr);
16972f63a38cSShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
16982f63a38cSShri Abhyankar     /* Monitor convergence */
16992f63a38cSShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
17002f63a38cSShri Abhyankar     snes->iter = i+1;
17012f63a38cSShri Abhyankar     snes->norm = fnorm;
17022f63a38cSShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
17032f63a38cSShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
17047a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
17052f63a38cSShri Abhyankar     /* Test for convergence, xnorm = || X || */
17062f63a38cSShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
17072f63a38cSShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
17082f63a38cSShri Abhyankar     if (snes->reason) break;
17092f63a38cSShri Abhyankar   }
17102f63a38cSShri Abhyankar   if (i == maxits) {
17112f63a38cSShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
17122f63a38cSShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
17132f63a38cSShri Abhyankar   }
17142f63a38cSShri Abhyankar   PetscFunctionReturn(0);
17152f63a38cSShri Abhyankar }
17162f63a38cSShri Abhyankar 
17172b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
17182b4ed282SShri Abhyankar /*
17192b4ed282SShri Abhyankar    SNESSetUp_VI - Sets up the internal data structures for the later use
17202b4ed282SShri Abhyankar    of the SNESVI nonlinear solver.
17212b4ed282SShri Abhyankar 
17222b4ed282SShri Abhyankar    Input Parameter:
17232b4ed282SShri Abhyankar .  snes - the SNES context
17242b4ed282SShri Abhyankar .  x - the solution vector
17252b4ed282SShri Abhyankar 
17262b4ed282SShri Abhyankar    Application Interface Routine: SNESSetUp()
17272b4ed282SShri Abhyankar 
17282b4ed282SShri Abhyankar    Notes:
17292b4ed282SShri Abhyankar    For basic use of the SNES solvers, the user need not explicitly call
17302b4ed282SShri Abhyankar    SNESSetUp(), since these actions will automatically occur during
17312b4ed282SShri Abhyankar    the call to SNESSolve().
17322b4ed282SShri Abhyankar  */
17332b4ed282SShri Abhyankar #undef __FUNCT__
17342b4ed282SShri Abhyankar #define __FUNCT__ "SNESSetUp_VI"
17352b4ed282SShri Abhyankar PetscErrorCode SNESSetUp_VI(SNES snes)
17362b4ed282SShri Abhyankar {
17372b4ed282SShri Abhyankar   PetscErrorCode ierr;
17382b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*) snes->data;
17392b4ed282SShri Abhyankar   PetscInt       i_start[3],i_end[3];
17402b4ed282SShri Abhyankar 
17412b4ed282SShri Abhyankar   PetscFunctionBegin;
174258c9b817SLisandro Dalcin 
174358c9b817SLisandro Dalcin   ierr = SNESDefaultGetWork(snes,3);CHKERRQ(ierr);
17442b4ed282SShri Abhyankar 
17452176524cSBarry Smith   if (vi->computevariablebounds) {
174677cdaf69SJed Brown     if (!vi->xl) {ierr = VecDuplicate(snes->vec_sol,&vi->xl);CHKERRQ(ierr);}
174777cdaf69SJed Brown     if (!vi->xu) {ierr = VecDuplicate(snes->vec_sol,&vi->xu);CHKERRQ(ierr);}
174877cdaf69SJed Brown     ierr = (*vi->computevariablebounds)(snes,vi->xl,vi->xu);CHKERRQ(ierr);
17492176524cSBarry Smith   } else if (!vi->xl && !vi->xu) {
17502176524cSBarry Smith     /* If the lower and upper bound on variables are not set, set it to -Inf and Inf */
17512b4ed282SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->xl);CHKERRQ(ierr);
175201f0b76bSBarry Smith     ierr = VecSet(vi->xl,SNES_VI_NINF);CHKERRQ(ierr);
17532b4ed282SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->xu);CHKERRQ(ierr);
175401f0b76bSBarry Smith     ierr = VecSet(vi->xu,SNES_VI_INF);CHKERRQ(ierr);
17552b4ed282SShri Abhyankar   } else {
17562b4ed282SShri Abhyankar     /* Check if lower bound, upper bound and solution vector distribution across the processors is identical */
17572b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(snes->vec_sol,i_start,i_end);CHKERRQ(ierr);
17582b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(vi->xl,i_start+1,i_end+1);CHKERRQ(ierr);
17592b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(vi->xu,i_start+2,i_end+2);CHKERRQ(ierr);
17602b4ed282SShri Abhyankar     if ((i_start[0] != i_start[1]) || (i_start[0] != i_start[2]) || (i_end[0] != i_end[1]) || (i_end[0] != i_end[2]))
17612b4ed282SShri Abhyankar       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Distribution of lower bound, upper bound and the solution vector should be identical across all the processors.");
17622b4ed282SShri Abhyankar   }
17632f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
1764abcba341SShri Abhyankar     /* Set up previous active index set for the first snes solve
1765abcba341SShri Abhyankar        vi->IS_inact_prev = 0,1,2,....N */
1766abcba341SShri Abhyankar     PetscInt *indices;
1767abcba341SShri Abhyankar     PetscInt  i,n,rstart,rend;
1768abcba341SShri Abhyankar 
1769abcba341SShri Abhyankar     ierr = VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);CHKERRQ(ierr);
1770abcba341SShri Abhyankar     ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
1771abcba341SShri Abhyankar     ierr = PetscMalloc(n*sizeof(PetscInt),&indices);CHKERRQ(ierr);
1772abcba341SShri Abhyankar     for(i=0;i < n; i++) indices[i] = rstart + i;
1773abcba341SShri Abhyankar     ierr = ISCreateGeneral(((PetscObject)snes)->comm,n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);
1774abcba341SShri Abhyankar   }
17752b4ed282SShri Abhyankar 
17762f63a38cSShri Abhyankar   if (snes->ops->solve == SNESSolveVI_SS) {
1777fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->dpsi);CHKERRQ(ierr);
1778fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->phi);CHKERRQ(ierr);
1779fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->Da);CHKERRQ(ierr);
1780fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->Db);CHKERRQ(ierr);
1781fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->z);CHKERRQ(ierr);
1782fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->t);CHKERRQ(ierr);
1783fe835674SShri Abhyankar   }
17842b4ed282SShri Abhyankar   PetscFunctionReturn(0);
17852b4ed282SShri Abhyankar }
17862b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
17872176524cSBarry Smith #undef __FUNCT__
17882176524cSBarry Smith #define __FUNCT__ "SNESReset_VI"
17892176524cSBarry Smith PetscErrorCode SNESReset_VI(SNES snes)
17902176524cSBarry Smith {
17912176524cSBarry Smith   SNES_VI        *vi = (SNES_VI*) snes->data;
17922176524cSBarry Smith   PetscErrorCode ierr;
17932176524cSBarry Smith 
17942176524cSBarry Smith   PetscFunctionBegin;
17952176524cSBarry Smith   ierr = VecDestroy(&vi->xl);CHKERRQ(ierr);
17962176524cSBarry Smith   ierr = VecDestroy(&vi->xu);CHKERRQ(ierr);
1797d655a5daSBarry Smith   if (snes->ops->solve != SNESSolveVI_SS) {
1798d655a5daSBarry Smith     ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
1799d655a5daSBarry Smith   }
18002176524cSBarry Smith   PetscFunctionReturn(0);
18012176524cSBarry Smith }
18022176524cSBarry Smith 
18032b4ed282SShri Abhyankar /*
18042b4ed282SShri Abhyankar    SNESDestroy_VI - Destroys the private SNES_VI context that was created
18052b4ed282SShri Abhyankar    with SNESCreate_VI().
18062b4ed282SShri Abhyankar 
18072b4ed282SShri Abhyankar    Input Parameter:
18082b4ed282SShri Abhyankar .  snes - the SNES context
18092b4ed282SShri Abhyankar 
18102b4ed282SShri Abhyankar    Application Interface Routine: SNESDestroy()
18112b4ed282SShri Abhyankar  */
18122b4ed282SShri Abhyankar #undef __FUNCT__
18132b4ed282SShri Abhyankar #define __FUNCT__ "SNESDestroy_VI"
18142b4ed282SShri Abhyankar PetscErrorCode SNESDestroy_VI(SNES snes)
18152b4ed282SShri Abhyankar {
18162b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*) snes->data;
18172b4ed282SShri Abhyankar   PetscErrorCode ierr;
18182b4ed282SShri Abhyankar 
18192b4ed282SShri Abhyankar   PetscFunctionBegin;
18202b4ed282SShri Abhyankar 
18212f63a38cSShri Abhyankar   if (snes->ops->solve == SNESSolveVI_SS) {
18222b4ed282SShri Abhyankar     /* clear vectors */
18236bf464f9SBarry Smith     ierr = VecDestroy(&vi->dpsi);CHKERRQ(ierr);
18246bf464f9SBarry Smith     ierr = VecDestroy(&vi->phi);CHKERRQ(ierr);
18256bf464f9SBarry Smith     ierr = VecDestroy(&vi->Da);CHKERRQ(ierr);
18266bf464f9SBarry Smith     ierr = VecDestroy(&vi->Db);CHKERRQ(ierr);
18276bf464f9SBarry Smith     ierr = VecDestroy(&vi->z);CHKERRQ(ierr);
18286bf464f9SBarry Smith     ierr = VecDestroy(&vi->t);CHKERRQ(ierr);
18297fe79bc4SShri Abhyankar   }
18307fe79bc4SShri Abhyankar 
1831649052a6SBarry Smith   ierr = PetscViewerDestroy(&vi->lsmonitor);CHKERRQ(ierr);
18322b4ed282SShri Abhyankar   ierr = PetscFree(snes->data);CHKERRQ(ierr);
18332b4ed282SShri Abhyankar 
18342b4ed282SShri Abhyankar   /* clear composed functions */
18352b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr);
1836c92abb8aSShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);CHKERRQ(ierr);
18372b4ed282SShri Abhyankar   PetscFunctionReturn(0);
18382b4ed282SShri Abhyankar }
18397fe79bc4SShri Abhyankar 
18402b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
18412b4ed282SShri Abhyankar #undef __FUNCT__
18422b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchNo_VI"
18432b4ed282SShri Abhyankar 
18442b4ed282SShri Abhyankar /*
18457fe79bc4SShri Abhyankar   This routine does not actually do a line search but it takes a full newton
18467fe79bc4SShri Abhyankar   step while ensuring that the new iterates remain within the constraints.
18472b4ed282SShri Abhyankar 
18482b4ed282SShri Abhyankar */
1849ace3abfcSBarry Smith PetscErrorCode SNESLineSearchNo_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
18502b4ed282SShri Abhyankar {
18512b4ed282SShri Abhyankar   PetscErrorCode ierr;
18522b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1853ace3abfcSBarry Smith   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
18542b4ed282SShri Abhyankar 
18552b4ed282SShri Abhyankar   PetscFunctionBegin;
18562b4ed282SShri Abhyankar   *flag = PETSC_TRUE;
18572b4ed282SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
18582b4ed282SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);         /* ynorm = || y || */
18592b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1860c1a5e521SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1861c1a5e521SShri Abhyankar   if (vi->postcheckstep) {
1862c1a5e521SShri Abhyankar    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1863c1a5e521SShri Abhyankar   }
1864c1a5e521SShri Abhyankar   if (changed_y) {
1865c1a5e521SShri Abhyankar     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
18667fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1867c1a5e521SShri Abhyankar   }
1868c1a5e521SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1869c1a5e521SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1870c1a5e521SShri Abhyankar   if (!snes->domainerror) {
18712f63a38cSShri Abhyankar     if (snes->ops->solve != SNESSolveVI_SS) {
18727fe79bc4SShri Abhyankar        ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
18737fe79bc4SShri Abhyankar     } else {
1874c1a5e521SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
18757fe79bc4SShri Abhyankar     }
187662cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1877c1a5e521SShri Abhyankar   }
1878c1a5e521SShri Abhyankar   if (vi->lsmonitor) {
1879649052a6SBarry Smith     ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1880649052a6SBarry Smith     ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1881649052a6SBarry Smith     ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1882c1a5e521SShri Abhyankar   }
1883c1a5e521SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1884c1a5e521SShri Abhyankar   PetscFunctionReturn(0);
1885c1a5e521SShri Abhyankar }
1886c1a5e521SShri Abhyankar 
1887c1a5e521SShri Abhyankar /* -------------------------------------------------------------------------- */
1888c1a5e521SShri Abhyankar #undef __FUNCT__
18892b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchNoNorms_VI"
18902b4ed282SShri Abhyankar 
18912b4ed282SShri Abhyankar /*
18922b4ed282SShri Abhyankar   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
18932b4ed282SShri Abhyankar */
1894ace3abfcSBarry Smith PetscErrorCode SNESLineSearchNoNorms_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
18952b4ed282SShri Abhyankar {
18962b4ed282SShri Abhyankar   PetscErrorCode ierr;
18972b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1898ace3abfcSBarry Smith   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
18992b4ed282SShri Abhyankar 
19002b4ed282SShri Abhyankar   PetscFunctionBegin;
19012b4ed282SShri Abhyankar   *flag = PETSC_TRUE;
19022b4ed282SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
19032b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y      */
19047fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
19052b4ed282SShri Abhyankar   if (vi->postcheckstep) {
19062b4ed282SShri Abhyankar    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
19072b4ed282SShri Abhyankar   }
19082b4ed282SShri Abhyankar   if (changed_y) {
19092b4ed282SShri Abhyankar     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
19107fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
19112b4ed282SShri Abhyankar   }
19122b4ed282SShri Abhyankar 
19132b4ed282SShri Abhyankar   /* don't evaluate function the last time through */
19142b4ed282SShri Abhyankar   if (snes->iter < snes->max_its-1) {
19152b4ed282SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
19162b4ed282SShri Abhyankar   }
19172b4ed282SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
19182b4ed282SShri Abhyankar   PetscFunctionReturn(0);
19192b4ed282SShri Abhyankar }
19207fe79bc4SShri Abhyankar 
19212b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
19222b4ed282SShri Abhyankar #undef __FUNCT__
19232b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchCubic_VI"
19242b4ed282SShri Abhyankar /*
19257fe79bc4SShri Abhyankar   This routine implements a cubic line search while doing a projection on the variable bounds
19262b4ed282SShri Abhyankar */
1927ace3abfcSBarry Smith PetscErrorCode SNESLineSearchCubic_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
19282b4ed282SShri Abhyankar {
1929fe835674SShri Abhyankar   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
1930fe835674SShri Abhyankar   PetscReal      minlambda,lambda,lambdatemp;
1931fe835674SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
1932fe835674SShri Abhyankar   PetscScalar    cinitslope;
1933fe835674SShri Abhyankar #endif
1934fe835674SShri Abhyankar   PetscErrorCode ierr;
1935fe835674SShri Abhyankar   PetscInt       count;
1936fe835674SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1937fe835674SShri Abhyankar   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1938fe835674SShri Abhyankar   MPI_Comm       comm;
1939fe835674SShri Abhyankar 
1940fe835674SShri Abhyankar   PetscFunctionBegin;
1941fe835674SShri Abhyankar   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
1942fe835674SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1943fe835674SShri Abhyankar   *flag   = PETSC_TRUE;
1944fe835674SShri Abhyankar 
1945fe835674SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1946fe835674SShri Abhyankar   if (*ynorm == 0.0) {
1947fe835674SShri Abhyankar     if (vi->lsmonitor) {
1948649052a6SBarry Smith       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1949649052a6SBarry Smith       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
1950649052a6SBarry Smith       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1951fe835674SShri Abhyankar     }
1952fe835674SShri Abhyankar     *gnorm = fnorm;
1953fe835674SShri Abhyankar     ierr   = VecCopy(x,w);CHKERRQ(ierr);
1954fe835674SShri Abhyankar     ierr   = VecCopy(f,g);CHKERRQ(ierr);
1955fe835674SShri Abhyankar     *flag  = PETSC_FALSE;
1956fe835674SShri Abhyankar     goto theend1;
1957fe835674SShri Abhyankar   }
1958fe835674SShri Abhyankar   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
1959fe835674SShri Abhyankar     if (vi->lsmonitor) {
1960649052a6SBarry Smith       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1961649052a6SBarry Smith       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Scaling step by %G old ynorm %G\n",vi->maxstep/(*ynorm),*ynorm);CHKERRQ(ierr);
1962649052a6SBarry Smith       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
1963fe835674SShri Abhyankar     }
1964fe835674SShri Abhyankar     ierr = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
1965fe835674SShri Abhyankar     *ynorm = vi->maxstep;
1966fe835674SShri Abhyankar   }
1967fe835674SShri Abhyankar   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
1968fe835674SShri Abhyankar   minlambda = vi->minlambda/rellength;
1969fe835674SShri Abhyankar   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
1970fe835674SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
1971fe835674SShri Abhyankar   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
1972fe835674SShri Abhyankar   initslope = PetscRealPart(cinitslope);
1973fe835674SShri Abhyankar #else
1974fe835674SShri Abhyankar   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
1975fe835674SShri Abhyankar #endif
1976fe835674SShri Abhyankar   if (initslope > 0.0)  initslope = -initslope;
1977fe835674SShri Abhyankar   if (initslope == 0.0) initslope = -1.0;
1978fe835674SShri Abhyankar 
1979fe835674SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1980fe835674SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1981fe835674SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
1982fe835674SShri Abhyankar     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
1983fe835674SShri Abhyankar     *flag = PETSC_FALSE;
1984fe835674SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1985fe835674SShri Abhyankar     goto theend1;
1986fe835674SShri Abhyankar   }
1987fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
19882f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
1989fe835674SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
19907fe79bc4SShri Abhyankar   } else {
19917fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
19927fe79bc4SShri Abhyankar   }
1993fe835674SShri Abhyankar   if (snes->domainerror) {
1994fe835674SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1995fe835674SShri Abhyankar     PetscFunctionReturn(0);
1996fe835674SShri Abhyankar   }
199762cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1998*ed70e96aSJungho Lee   ierr = PetscInfo4(snes,"Initial fnorm %G gnorm %G alpha %G initslope %G\n",fnorm,*gnorm,vi->alpha,initslope);CHKERRQ(ierr);
1999*ed70e96aSJungho Lee   if ((*gnorm)*(*gnorm) <= (1-vi->alpha)*fnorm*fnorm ) { /* Sufficient reduction */
2000fe835674SShri Abhyankar     if (vi->lsmonitor) {
2001649052a6SBarry Smith       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2002649052a6SBarry Smith       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
2003649052a6SBarry Smith       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2004fe835674SShri Abhyankar     }
2005fe835674SShri Abhyankar     goto theend1;
2006fe835674SShri Abhyankar   }
2007fe835674SShri Abhyankar 
2008fe835674SShri Abhyankar   /* Fit points with quadratic */
2009fe835674SShri Abhyankar   lambda     = 1.0;
2010fe835674SShri Abhyankar   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2011fe835674SShri Abhyankar   lambdaprev = lambda;
2012fe835674SShri Abhyankar   gnormprev  = *gnorm;
2013fe835674SShri Abhyankar   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
2014fe835674SShri Abhyankar   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
2015fe835674SShri Abhyankar   else                         lambda = lambdatemp;
2016fe835674SShri Abhyankar 
2017fe835674SShri Abhyankar   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
2018fe835674SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2019fe835674SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
2020fe835674SShri Abhyankar     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
2021fe835674SShri Abhyankar     *flag = PETSC_FALSE;
2022fe835674SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2023fe835674SShri Abhyankar     goto theend1;
2024fe835674SShri Abhyankar   }
2025fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
20262f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
2027fe835674SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
20287fe79bc4SShri Abhyankar   } else {
20297fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
20307fe79bc4SShri Abhyankar   }
2031fe835674SShri Abhyankar   if (snes->domainerror) {
2032fe835674SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2033fe835674SShri Abhyankar     PetscFunctionReturn(0);
2034fe835674SShri Abhyankar   }
203562cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2036fe835674SShri Abhyankar   if (vi->lsmonitor) {
2037649052a6SBarry Smith     ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2038649052a6SBarry Smith     ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: gnorm after quadratic fit %G\n",*gnorm);CHKERRQ(ierr);
2039649052a6SBarry Smith     ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2040fe835674SShri Abhyankar   }
2041*ed70e96aSJungho Lee   if ((*gnorm)*(*gnorm) < (1-vi->alpha)*fnorm*fnorm ) { /* sufficient reduction */
2042fe835674SShri Abhyankar     if (vi->lsmonitor) {
2043649052a6SBarry Smith       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2044649052a6SBarry Smith       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr);
2045649052a6SBarry Smith       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2046fe835674SShri Abhyankar     }
2047fe835674SShri Abhyankar     goto theend1;
2048fe835674SShri Abhyankar   }
2049fe835674SShri Abhyankar 
2050fe835674SShri Abhyankar   /* Fit points with cubic */
2051fe835674SShri Abhyankar   count = 1;
2052fe835674SShri Abhyankar   while (PETSC_TRUE) {
2053fe835674SShri Abhyankar     if (lambda <= minlambda) {
2054fe835674SShri Abhyankar       if (vi->lsmonitor) {
2055649052a6SBarry Smith         ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2056649052a6SBarry Smith  	ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
2057649052a6SBarry Smith 	ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,minlambda,lambda,initslope);CHKERRQ(ierr);
2058649052a6SBarry Smith         ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2059fe835674SShri Abhyankar       }
2060fe835674SShri Abhyankar       *flag = PETSC_FALSE;
2061fe835674SShri Abhyankar       break;
2062fe835674SShri Abhyankar     }
2063fe835674SShri Abhyankar     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
2064fe835674SShri Abhyankar     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
2065fe835674SShri Abhyankar     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2066fe835674SShri Abhyankar     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2067fe835674SShri Abhyankar     d  = b*b - 3*a*initslope;
2068fe835674SShri Abhyankar     if (d < 0.0) d = 0.0;
2069fe835674SShri Abhyankar     if (a == 0.0) {
2070fe835674SShri Abhyankar       lambdatemp = -initslope/(2.0*b);
2071fe835674SShri Abhyankar     } else {
2072fe835674SShri Abhyankar       lambdatemp = (-b + sqrt(d))/(3.0*a);
2073fe835674SShri Abhyankar     }
2074fe835674SShri Abhyankar     lambdaprev = lambda;
2075fe835674SShri Abhyankar     gnormprev  = *gnorm;
2076fe835674SShri Abhyankar     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
2077fe835674SShri Abhyankar     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
2078fe835674SShri Abhyankar     else                         lambda     = lambdatemp;
2079fe835674SShri Abhyankar     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
2080fe835674SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2081fe835674SShri Abhyankar     if (snes->nfuncs >= snes->max_funcs) {
2082fe835674SShri Abhyankar       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
2083fe835674SShri Abhyankar       ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr);
2084fe835674SShri Abhyankar       *flag = PETSC_FALSE;
2085fe835674SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
2086fe835674SShri Abhyankar       break;
2087fe835674SShri Abhyankar     }
2088fe835674SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
20892f63a38cSShri Abhyankar     if (snes->ops->solve != SNESSolveVI_SS) {
2090fe835674SShri Abhyankar       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
20917fe79bc4SShri Abhyankar     } else {
20927fe79bc4SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
20937fe79bc4SShri Abhyankar     }
2094fe835674SShri Abhyankar     if (snes->domainerror) {
2095fe835674SShri Abhyankar       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2096fe835674SShri Abhyankar       PetscFunctionReturn(0);
2097fe835674SShri Abhyankar     }
209862cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2099*ed70e96aSJungho Lee     if ((*gnorm)*(*gnorm) < (1-vi->alpha)*fnorm*fnorm) { /* is reduction enough? */
2100fe835674SShri Abhyankar       if (vi->lsmonitor) {
2101fe835674SShri Abhyankar 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
2102fe835674SShri Abhyankar       }
2103fe835674SShri Abhyankar       break;
2104fe835674SShri Abhyankar     } else {
2105fe835674SShri Abhyankar       if (vi->lsmonitor) {
2106fe835674SShri Abhyankar         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
2107fe835674SShri Abhyankar       }
2108fe835674SShri Abhyankar     }
2109fe835674SShri Abhyankar     count++;
2110fe835674SShri Abhyankar   }
2111fe835674SShri Abhyankar   theend1:
2112fe835674SShri Abhyankar   /* Optional user-defined check for line search step validity */
2113fe835674SShri Abhyankar   if (vi->postcheckstep && *flag) {
2114fe835674SShri Abhyankar     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
2115fe835674SShri Abhyankar     if (changed_y) {
2116fe835674SShri Abhyankar       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
2117fe835674SShri Abhyankar       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
2118fe835674SShri Abhyankar     }
2119fe835674SShri Abhyankar     if (changed_y || changed_w) { /* recompute the function if the step has changed */
2120fe835674SShri Abhyankar       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
21212f63a38cSShri Abhyankar       if (snes->ops->solve != SNESSolveVI_SS) {
2122fe835674SShri Abhyankar         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
21237fe79bc4SShri Abhyankar       } else {
21247fe79bc4SShri Abhyankar         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
21257fe79bc4SShri Abhyankar       }
2126fe835674SShri Abhyankar       if (snes->domainerror) {
2127fe835674SShri Abhyankar         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2128fe835674SShri Abhyankar         PetscFunctionReturn(0);
2129fe835674SShri Abhyankar       }
213062cbcd01SMatthew G Knepley       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2131fe835674SShri Abhyankar       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
2132fe835674SShri Abhyankar       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
2133fe835674SShri Abhyankar     }
2134fe835674SShri Abhyankar   }
2135fe835674SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2136fe835674SShri Abhyankar   PetscFunctionReturn(0);
2137fe835674SShri Abhyankar }
2138fe835674SShri Abhyankar 
21392b4ed282SShri Abhyankar #undef __FUNCT__
21402b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchQuadratic_VI"
21412b4ed282SShri Abhyankar /*
21427fe79bc4SShri Abhyankar   This routine does a quadratic line search while keeping the iterates within the variable bounds
21432b4ed282SShri Abhyankar */
2144ace3abfcSBarry Smith PetscErrorCode SNESLineSearchQuadratic_VI(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal xnorm,PetscReal *ynorm,PetscReal *gnorm,PetscBool *flag)
21452b4ed282SShri Abhyankar {
21462b4ed282SShri Abhyankar   /*
21472b4ed282SShri Abhyankar      Note that for line search purposes we work with with the related
21482b4ed282SShri Abhyankar      minimization problem:
21492b4ed282SShri Abhyankar         min  z(x):  R^n -> R,
21502b4ed282SShri Abhyankar      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
21512b4ed282SShri Abhyankar    */
21522b4ed282SShri Abhyankar   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
21532b4ed282SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
21542b4ed282SShri Abhyankar   PetscScalar    cinitslope;
21552b4ed282SShri Abhyankar #endif
21562b4ed282SShri Abhyankar   PetscErrorCode ierr;
21572b4ed282SShri Abhyankar   PetscInt       count;
21582b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
2159ace3abfcSBarry Smith   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
21602b4ed282SShri Abhyankar 
21612b4ed282SShri Abhyankar   PetscFunctionBegin;
21622b4ed282SShri Abhyankar   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
21632b4ed282SShri Abhyankar   *flag   = PETSC_TRUE;
21642b4ed282SShri Abhyankar 
21652b4ed282SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
21662b4ed282SShri Abhyankar   if (*ynorm == 0.0) {
2167c92abb8aSShri Abhyankar     if (vi->lsmonitor) {
2168649052a6SBarry Smith       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2169649052a6SBarry Smith       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
2170649052a6SBarry Smith       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
21712b4ed282SShri Abhyankar     }
21722b4ed282SShri Abhyankar     *gnorm = fnorm;
21732b4ed282SShri Abhyankar     ierr   = VecCopy(x,w);CHKERRQ(ierr);
21742b4ed282SShri Abhyankar     ierr   = VecCopy(f,g);CHKERRQ(ierr);
21752b4ed282SShri Abhyankar     *flag  = PETSC_FALSE;
21762b4ed282SShri Abhyankar     goto theend2;
21772b4ed282SShri Abhyankar   }
21782b4ed282SShri Abhyankar   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
21792b4ed282SShri Abhyankar     ierr   = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
21802b4ed282SShri Abhyankar     *ynorm = vi->maxstep;
21812b4ed282SShri Abhyankar   }
21822b4ed282SShri Abhyankar   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
21832b4ed282SShri Abhyankar   minlambda = vi->minlambda/rellength;
21847fe79bc4SShri Abhyankar   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
21852b4ed282SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
21867fe79bc4SShri Abhyankar   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
21872b4ed282SShri Abhyankar   initslope = PetscRealPart(cinitslope);
21882b4ed282SShri Abhyankar #else
21897fe79bc4SShri Abhyankar   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
21902b4ed282SShri Abhyankar #endif
21912b4ed282SShri Abhyankar   if (initslope > 0.0)  initslope = -initslope;
21922b4ed282SShri Abhyankar   if (initslope == 0.0) initslope = -1.0;
21932b4ed282SShri Abhyankar   ierr = PetscInfo1(snes,"Initslope %G \n",initslope);CHKERRQ(ierr);
21942b4ed282SShri Abhyankar 
21952b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
21967fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
21972b4ed282SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
21982b4ed282SShri Abhyankar     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
21992b4ed282SShri Abhyankar     *flag = PETSC_FALSE;
22002b4ed282SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
22012b4ed282SShri Abhyankar     goto theend2;
22022b4ed282SShri Abhyankar   }
22032b4ed282SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
22042f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
22057fe79bc4SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
22067fe79bc4SShri Abhyankar   } else {
22077fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
22087fe79bc4SShri Abhyankar   }
22092b4ed282SShri Abhyankar   if (snes->domainerror) {
22102b4ed282SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
22112b4ed282SShri Abhyankar     PetscFunctionReturn(0);
22122b4ed282SShri Abhyankar   }
221362cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
22142b4ed282SShri Abhyankar   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
2215c92abb8aSShri Abhyankar     if (vi->lsmonitor) {
2216649052a6SBarry Smith       ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2217649052a6SBarry Smith       ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
2218649052a6SBarry Smith       ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
22192b4ed282SShri Abhyankar     }
22202b4ed282SShri Abhyankar     goto theend2;
22212b4ed282SShri Abhyankar   }
22222b4ed282SShri Abhyankar 
22232b4ed282SShri Abhyankar   /* Fit points with quadratic */
22242b4ed282SShri Abhyankar   lambda = 1.0;
22252b4ed282SShri Abhyankar   count = 1;
22262b4ed282SShri Abhyankar   while (PETSC_TRUE) {
22272b4ed282SShri Abhyankar     if (lambda <= minlambda) { /* bad luck; use full step */
2228c92abb8aSShri Abhyankar       if (vi->lsmonitor) {
2229649052a6SBarry Smith         ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2230649052a6SBarry Smith         ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
2231649052a6SBarry Smith         ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"Line search: fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr);
2232649052a6SBarry Smith         ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
22332b4ed282SShri Abhyankar       }
22342b4ed282SShri Abhyankar       ierr = VecCopy(x,w);CHKERRQ(ierr);
22352b4ed282SShri Abhyankar       *flag = PETSC_FALSE;
22362b4ed282SShri Abhyankar       break;
22372b4ed282SShri Abhyankar     }
22382b4ed282SShri Abhyankar     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
22392b4ed282SShri Abhyankar     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
22402b4ed282SShri Abhyankar     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
22412b4ed282SShri Abhyankar     else                         lambda     = lambdatemp;
22422b4ed282SShri Abhyankar 
22432b4ed282SShri Abhyankar     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
22447fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
22452b4ed282SShri Abhyankar     if (snes->nfuncs >= snes->max_funcs) {
22462b4ed282SShri Abhyankar       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
22472b4ed282SShri Abhyankar       ierr  = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr);
22482b4ed282SShri Abhyankar       *flag = PETSC_FALSE;
22492b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
22502b4ed282SShri Abhyankar       break;
22512b4ed282SShri Abhyankar     }
22522b4ed282SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
22532b4ed282SShri Abhyankar     if (snes->domainerror) {
22542b4ed282SShri Abhyankar       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
22552b4ed282SShri Abhyankar       PetscFunctionReturn(0);
22562b4ed282SShri Abhyankar     }
22572f63a38cSShri Abhyankar     if (snes->ops->solve != SNESSolveVI_SS) {
22587fe79bc4SShri Abhyankar       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
22597fe79bc4SShri Abhyankar     } else {
22602b4ed282SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
22617fe79bc4SShri Abhyankar     }
226262cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
22632b4ed282SShri Abhyankar     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
2264c92abb8aSShri Abhyankar       if (vi->lsmonitor) {
2265649052a6SBarry Smith         ierr = PetscViewerASCIIAddTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
2266649052a6SBarry Smith         ierr = PetscViewerASCIIPrintf(vi->lsmonitor,"    Line Search: Quadratically determined step, lambda=%G\n",lambda);CHKERRQ(ierr);
2267649052a6SBarry Smith         ierr = PetscViewerASCIISubtractTab(vi->lsmonitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
22682b4ed282SShri Abhyankar       }
22692b4ed282SShri Abhyankar       break;
22702b4ed282SShri Abhyankar     }
22712b4ed282SShri Abhyankar     count++;
22722b4ed282SShri Abhyankar   }
22732b4ed282SShri Abhyankar   theend2:
22742b4ed282SShri Abhyankar   /* Optional user-defined check for line search step validity */
22752b4ed282SShri Abhyankar   if (vi->postcheckstep) {
22762b4ed282SShri Abhyankar     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
22772b4ed282SShri Abhyankar     if (changed_y) {
22782b4ed282SShri Abhyankar       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
22797fe79bc4SShri Abhyankar       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
22802b4ed282SShri Abhyankar     }
22812b4ed282SShri Abhyankar     if (changed_y || changed_w) { /* recompute the function if the step has changed */
22822b4ed282SShri Abhyankar       ierr = SNESComputeFunction(snes,w,g);
22832b4ed282SShri Abhyankar       if (snes->domainerror) {
22842b4ed282SShri Abhyankar         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
22852b4ed282SShri Abhyankar         PetscFunctionReturn(0);
22862b4ed282SShri Abhyankar       }
22872f63a38cSShri Abhyankar       if (snes->ops->solve != SNESSolveVI_SS) {
22887fe79bc4SShri Abhyankar         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
22897fe79bc4SShri Abhyankar       } else {
22907fe79bc4SShri Abhyankar         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
22917fe79bc4SShri Abhyankar       }
22927fe79bc4SShri Abhyankar 
22932b4ed282SShri Abhyankar       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
22942b4ed282SShri Abhyankar       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
229562cbcd01SMatthew G Knepley       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
22962b4ed282SShri Abhyankar     }
22972b4ed282SShri Abhyankar   }
22982b4ed282SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
22992b4ed282SShri Abhyankar   PetscFunctionReturn(0);
23002b4ed282SShri Abhyankar }
23012b4ed282SShri Abhyankar 
2302ace3abfcSBarry Smith typedef PetscErrorCode (*FCN2)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal*,PetscReal*,PetscBool*); /* force argument to next function to not be extern C*/
23032b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
23042b4ed282SShri Abhyankar EXTERN_C_BEGIN
23052b4ed282SShri Abhyankar #undef __FUNCT__
23062b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchSet_VI"
23077087cfbeSBarry Smith PetscErrorCode  SNESLineSearchSet_VI(SNES snes,FCN2 func,void *lsctx)
23082b4ed282SShri Abhyankar {
23092b4ed282SShri Abhyankar   PetscFunctionBegin;
23102b4ed282SShri Abhyankar   ((SNES_VI *)(snes->data))->LineSearch = func;
23112b4ed282SShri Abhyankar   ((SNES_VI *)(snes->data))->lsP        = lsctx;
23122b4ed282SShri Abhyankar   PetscFunctionReturn(0);
23132b4ed282SShri Abhyankar }
23142b4ed282SShri Abhyankar EXTERN_C_END
23152b4ed282SShri Abhyankar 
23162b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
23172b4ed282SShri Abhyankar EXTERN_C_BEGIN
23182b4ed282SShri Abhyankar #undef __FUNCT__
23192b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchSetMonitor_VI"
23207087cfbeSBarry Smith PetscErrorCode  SNESLineSearchSetMonitor_VI(SNES snes,PetscBool flg)
23212b4ed282SShri Abhyankar {
23222b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
23232b4ed282SShri Abhyankar   PetscErrorCode ierr;
23242b4ed282SShri Abhyankar 
23252b4ed282SShri Abhyankar   PetscFunctionBegin;
2326c92abb8aSShri Abhyankar   if (flg && !vi->lsmonitor) {
2327649052a6SBarry Smith     ierr = PetscViewerASCIIOpen(((PetscObject)snes)->comm,"stdout",&vi->lsmonitor);CHKERRQ(ierr);
2328c92abb8aSShri Abhyankar   } else if (!flg && vi->lsmonitor) {
2329649052a6SBarry Smith     ierr = PetscViewerDestroy(&vi->lsmonitor);CHKERRQ(ierr);
23302b4ed282SShri Abhyankar   }
23312b4ed282SShri Abhyankar   PetscFunctionReturn(0);
23322b4ed282SShri Abhyankar }
23332b4ed282SShri Abhyankar EXTERN_C_END
23342b4ed282SShri Abhyankar 
23352b4ed282SShri Abhyankar /*
23362b4ed282SShri Abhyankar    SNESView_VI - Prints info from the SNESVI data structure.
23372b4ed282SShri Abhyankar 
23382b4ed282SShri Abhyankar    Input Parameters:
23392b4ed282SShri Abhyankar .  SNES - the SNES context
23402b4ed282SShri Abhyankar .  viewer - visualization context
23412b4ed282SShri Abhyankar 
23422b4ed282SShri Abhyankar    Application Interface Routine: SNESView()
23432b4ed282SShri Abhyankar */
23442b4ed282SShri Abhyankar #undef __FUNCT__
23452b4ed282SShri Abhyankar #define __FUNCT__ "SNESView_VI"
23462b4ed282SShri Abhyankar static PetscErrorCode SNESView_VI(SNES snes,PetscViewer viewer)
23472b4ed282SShri Abhyankar {
23482b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI *)snes->data;
234978c4b9d3SShri Abhyankar   const char     *cstr,*tstr;
23502b4ed282SShri Abhyankar   PetscErrorCode ierr;
2351ace3abfcSBarry Smith   PetscBool     iascii;
23522b4ed282SShri Abhyankar 
23532b4ed282SShri Abhyankar   PetscFunctionBegin;
23542b4ed282SShri Abhyankar   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
23552b4ed282SShri Abhyankar   if (iascii) {
23562b4ed282SShri Abhyankar     if (vi->LineSearch == SNESLineSearchNo_VI)             cstr = "SNESLineSearchNo";
23572b4ed282SShri Abhyankar     else if (vi->LineSearch == SNESLineSearchQuadratic_VI) cstr = "SNESLineSearchQuadratic";
23582b4ed282SShri Abhyankar     else if (vi->LineSearch == SNESLineSearchCubic_VI)     cstr = "SNESLineSearchCubic";
23592b4ed282SShri Abhyankar     else                                                   cstr = "unknown";
236078c4b9d3SShri Abhyankar     if (snes->ops->solve == SNESSolveVI_SS)         tstr = "Semismooth";
23610a7c7af0SShri Abhyankar     else if (snes->ops->solve == SNESSolveVI_RS)    tstr = "Reduced Space";
2362b350b9c9SBarry Smith     else if (snes->ops->solve == SNESSolveVI_RSAUG) tstr = "Reduced space with augmented variables";
236378c4b9d3SShri Abhyankar     else                                         tstr = "unknown";
236478c4b9d3SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  VI algorithm: %s\n",tstr);CHKERRQ(ierr);
23652b4ed282SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
23662b4ed282SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, minlambda=%G\n",vi->alpha,vi->maxstep,vi->minlambda);CHKERRQ(ierr);
23672b4ed282SShri Abhyankar   } else {
23682b4ed282SShri Abhyankar     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ VI",((PetscObject)viewer)->type_name);
23692b4ed282SShri Abhyankar   }
23702b4ed282SShri Abhyankar   PetscFunctionReturn(0);
23712b4ed282SShri Abhyankar }
23722b4ed282SShri Abhyankar 
23735559b345SBarry Smith #undef __FUNCT__
23745559b345SBarry Smith #define __FUNCT__ "SNESVISetVariableBounds"
23755559b345SBarry Smith /*@
23762b4ed282SShri Abhyankar    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.
23772b4ed282SShri Abhyankar 
23782b4ed282SShri Abhyankar    Input Parameters:
23792b4ed282SShri Abhyankar .  snes - the SNES context.
23802b4ed282SShri Abhyankar .  xl   - lower bound.
23812b4ed282SShri Abhyankar .  xu   - upper bound.
23822b4ed282SShri Abhyankar 
23832b4ed282SShri Abhyankar    Notes:
23842b4ed282SShri Abhyankar    If this routine is not called then the lower and upper bounds are set to
238501f0b76bSBarry Smith    SNES_VI_INF and SNES_VI_NINF respectively during SNESSetUp().
238684c105d7SBarry Smith 
23875559b345SBarry Smith @*/
238869c03620SShri Abhyankar PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
23892b4ed282SShri Abhyankar {
2390d923200aSJungho Lee   SNES_VI        *vi;
2391d923200aSJungho Lee   PetscErrorCode ierr;
23922b4ed282SShri Abhyankar 
23932b4ed282SShri Abhyankar   PetscFunctionBegin;
23942b4ed282SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
23952b4ed282SShri Abhyankar   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
23962b4ed282SShri Abhyankar   PetscValidHeaderSpecific(xu,VEC_CLASSID,3);
23972b4ed282SShri Abhyankar   if (!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() first");
23982b4ed282SShri Abhyankar   if (xl->map->N != snes->vec_func->map->N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Incompatible vector lengths lower bound = %D solution vector = %D",xl->map->N,snes->vec_func->map->N);
23992b4ed282SShri Abhyankar   if (xu->map->N != snes->vec_func->map->N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Incompatible vector lengths: upper bound = %D solution vector = %D",xu->map->N,snes->vec_func->map->N);
2400d923200aSJungho Lee   ierr = SNESSetType(snes,SNESVI);CHKERRQ(ierr);
2401d923200aSJungho Lee   vi = (SNES_VI*)snes->data;
24022176524cSBarry Smith   ierr = PetscObjectReference((PetscObject)xl);CHKERRQ(ierr);
24032176524cSBarry Smith   ierr = PetscObjectReference((PetscObject)xu);CHKERRQ(ierr);
24042176524cSBarry Smith   ierr = VecDestroy(&vi->xl);CHKERRQ(ierr);
24052176524cSBarry Smith   ierr = VecDestroy(&vi->xu);CHKERRQ(ierr);
24062b4ed282SShri Abhyankar   vi->xl = xl;
24072b4ed282SShri Abhyankar   vi->xu = xu;
24082b4ed282SShri Abhyankar   PetscFunctionReturn(0);
24092b4ed282SShri Abhyankar }
2410693ddf92SShri Abhyankar 
24112b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
24122b4ed282SShri Abhyankar /*
24132b4ed282SShri Abhyankar    SNESSetFromOptions_VI - Sets various parameters for the SNESVI method.
24142b4ed282SShri Abhyankar 
24152b4ed282SShri Abhyankar    Input Parameter:
24162b4ed282SShri Abhyankar .  snes - the SNES context
24172b4ed282SShri Abhyankar 
24182b4ed282SShri Abhyankar    Application Interface Routine: SNESSetFromOptions()
24192b4ed282SShri Abhyankar */
24202b4ed282SShri Abhyankar #undef __FUNCT__
24212b4ed282SShri Abhyankar #define __FUNCT__ "SNESSetFromOptions_VI"
24222b4ed282SShri Abhyankar static PetscErrorCode SNESSetFromOptions_VI(SNES snes)
24232b4ed282SShri Abhyankar {
24242b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI *)snes->data;
24257fe79bc4SShri Abhyankar   const char     *lses[] = {"basic","basicnonorms","quadratic","cubic"};
2426b350b9c9SBarry Smith   const char     *vies[] = {"ss","rs","rsaug"};
24272b4ed282SShri Abhyankar   PetscErrorCode ierr;
24282b4ed282SShri Abhyankar   PetscInt       indx;
242969c03620SShri Abhyankar   PetscBool      flg,set,flg2;
24302b4ed282SShri Abhyankar 
24312b4ed282SShri Abhyankar   PetscFunctionBegin;
24322b4ed282SShri Abhyankar   ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr);
24339308c137SBarry Smith   ierr = PetscOptionsBool("-snes_vi_monitor","Monitor all non-active variables","None",PETSC_FALSE,&flg,0);CHKERRQ(ierr);
24349308c137SBarry Smith   if (flg) {
24359308c137SBarry Smith     ierr = SNESMonitorSet(snes,SNESMonitorVI,0,0);CHKERRQ(ierr);
24369308c137SBarry Smith   }
2437be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",vi->alpha,&vi->alpha,0);CHKERRQ(ierr);
2438be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",vi->maxstep,&vi->maxstep,0);CHKERRQ(ierr);
2439be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_minlambda","Minimum lambda allowed","None",vi->minlambda,&vi->minlambda,0);CHKERRQ(ierr);
24402b4ed282SShri Abhyankar   ierr = PetscOptionsReal("-snes_vi_const_tol","constraint tolerance","None",vi->const_tol,&vi->const_tol,0);CHKERRQ(ierr);
2441be6adb11SBarry Smith   ierr = PetscOptionsBool("-snes_ls_monitor","Print progress of line searches","SNESLineSearchSetMonitor",vi->lsmonitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
24422b4ed282SShri Abhyankar   if (set) {ierr = SNESLineSearchSetMonitor(snes,flg);CHKERRQ(ierr);}
24432f63a38cSShri Abhyankar   ierr = PetscOptionsEList("-snes_vi_type","Semismooth algorithm used","",vies,3,"ss",&indx,&flg2);CHKERRQ(ierr);
244469c03620SShri Abhyankar   if (flg2) {
244569c03620SShri Abhyankar     switch (indx) {
244669c03620SShri Abhyankar     case 0:
244769c03620SShri Abhyankar       snes->ops->solve = SNESSolveVI_SS;
244869c03620SShri Abhyankar       break;
244969c03620SShri Abhyankar     case 1:
2450d950fb63SShri Abhyankar       snes->ops->solve = SNESSolveVI_RS;
2451d950fb63SShri Abhyankar       break;
24522f63a38cSShri Abhyankar     case 2:
2453b350b9c9SBarry Smith       snes->ops->solve = SNESSolveVI_RSAUG;
245469c03620SShri Abhyankar     }
245569c03620SShri Abhyankar   }
2456be6adb11SBarry Smith   ierr = PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"basic",&indx,&flg);CHKERRQ(ierr);
24572b4ed282SShri Abhyankar   if (flg) {
24582b4ed282SShri Abhyankar     switch (indx) {
24592b4ed282SShri Abhyankar     case 0:
24602b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);CHKERRQ(ierr);
24612b4ed282SShri Abhyankar       break;
24622b4ed282SShri Abhyankar     case 1:
24632b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);CHKERRQ(ierr);
24642b4ed282SShri Abhyankar       break;
24652b4ed282SShri Abhyankar     case 2:
24662b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);CHKERRQ(ierr);
24672b4ed282SShri Abhyankar       break;
24682b4ed282SShri Abhyankar     case 3:
24692b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);CHKERRQ(ierr);
24702b4ed282SShri Abhyankar       break;
24712b4ed282SShri Abhyankar     }
2472fe835674SShri Abhyankar   }
24732b4ed282SShri Abhyankar   ierr = PetscOptionsTail();CHKERRQ(ierr);
24742b4ed282SShri Abhyankar   PetscFunctionReturn(0);
24752b4ed282SShri Abhyankar }
24762b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
24772b4ed282SShri Abhyankar /*MC
24788b4c83edSBarry Smith       SNESVI - Various solvers for variational inequalities based on Newton's method
24792b4ed282SShri Abhyankar 
24802b4ed282SShri Abhyankar    Options Database:
24818b4c83edSBarry Smith +   -snes_vi_type <ss,rs,rsaug> a semi-smooth solver, a reduced space active set method and a reduced space active set method that does not eliminate the active constraints from the Jacobian instead augments the Jacobian with
24828b4c83edSBarry Smith                                 additional variables that enforce the constraints
24838b4c83edSBarry Smith -   -snes_vi_monitor - prints the number of active constraints at each iteration.
24842b4ed282SShri Abhyankar 
24852b4ed282SShri Abhyankar 
24862b4ed282SShri Abhyankar    Level: beginner
24872b4ed282SShri Abhyankar 
24882b4ed282SShri Abhyankar .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
24892b4ed282SShri Abhyankar            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
24902b4ed282SShri Abhyankar            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
24912b4ed282SShri Abhyankar 
24922b4ed282SShri Abhyankar M*/
24932b4ed282SShri Abhyankar EXTERN_C_BEGIN
24942b4ed282SShri Abhyankar #undef __FUNCT__
24952b4ed282SShri Abhyankar #define __FUNCT__ "SNESCreate_VI"
24967087cfbeSBarry Smith PetscErrorCode  SNESCreate_VI(SNES snes)
24972b4ed282SShri Abhyankar {
24982b4ed282SShri Abhyankar   PetscErrorCode ierr;
24992b4ed282SShri Abhyankar   SNES_VI        *vi;
25002b4ed282SShri Abhyankar 
25012b4ed282SShri Abhyankar   PetscFunctionBegin;
25022176524cSBarry Smith   snes->ops->reset           = SNESReset_VI;
25032b4ed282SShri Abhyankar   snes->ops->setup           = SNESSetUp_VI;
2504edafb9efSBarry Smith   snes->ops->solve           = SNESSolveVI_RS;
25052b4ed282SShri Abhyankar   snes->ops->destroy         = SNESDestroy_VI;
25062b4ed282SShri Abhyankar   snes->ops->setfromoptions  = SNESSetFromOptions_VI;
25072b4ed282SShri Abhyankar   snes->ops->view            = SNESView_VI;
25082b4ed282SShri Abhyankar   snes->ops->converged       = SNESDefaultConverged_VI;
25092b4ed282SShri Abhyankar 
25102b4ed282SShri Abhyankar   ierr                  = PetscNewLog(snes,SNES_VI,&vi);CHKERRQ(ierr);
25112b4ed282SShri Abhyankar   snes->data            = (void*)vi;
25122b4ed282SShri Abhyankar   vi->alpha             = 1.e-4;
25132b4ed282SShri Abhyankar   vi->maxstep           = 1.e8;
25142b4ed282SShri Abhyankar   vi->minlambda         = 1.e-12;
25157fe79bc4SShri Abhyankar   vi->LineSearch        = SNESLineSearchNo_VI;
25162b4ed282SShri Abhyankar   vi->lsP               = PETSC_NULL;
25172b4ed282SShri Abhyankar   vi->postcheckstep     = PETSC_NULL;
25182b4ed282SShri Abhyankar   vi->postcheck         = PETSC_NULL;
25192b4ed282SShri Abhyankar   vi->precheckstep      = PETSC_NULL;
25202b4ed282SShri Abhyankar   vi->precheck          = PETSC_NULL;
25212b4ed282SShri Abhyankar   vi->const_tol         =  2.2204460492503131e-16;
25222f63a38cSShri Abhyankar   vi->checkredundancy   = PETSC_NULL;
25232b4ed282SShri Abhyankar 
25242b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_VI",SNESLineSearchSetMonitor_VI);CHKERRQ(ierr);
25252b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_VI",SNESLineSearchSet_VI);CHKERRQ(ierr);
25262b4ed282SShri Abhyankar 
25272b4ed282SShri Abhyankar   PetscFunctionReturn(0);
25282b4ed282SShri Abhyankar }
25292b4ed282SShri Abhyankar EXTERN_C_END
2530*ed70e96aSJungho Lee 
2531*ed70e96aSJungho Lee #undef __FUNCT__
2532*ed70e96aSJungho Lee #define __FUNCT__ "SNESVIGetInactiveSet"
2533*ed70e96aSJungho Lee /*
2534*ed70e96aSJungho Lee    SNESVIGetInactiveSet - Gets the global indices for the inactive set variables (these correspond to the degrees of freedom the linear
2535*ed70e96aSJungho Lee      system is solved on)
2536*ed70e96aSJungho Lee 
2537*ed70e96aSJungho Lee    Input parameter
2538*ed70e96aSJungho Lee .  snes - the SNES context
2539*ed70e96aSJungho Lee 
2540*ed70e96aSJungho Lee    Output parameter
2541*ed70e96aSJungho Lee .  ISact - active set index set
2542*ed70e96aSJungho Lee 
2543*ed70e96aSJungho Lee  */
2544*ed70e96aSJungho Lee PetscErrorCode SNESVIGetInactiveSet(SNES snes,IS* inact)
2545*ed70e96aSJungho Lee {
2546*ed70e96aSJungho Lee   SNES_VI          *vi = (SNES_VI*)snes->data;
2547*ed70e96aSJungho Lee   PetscFunctionBegin;
2548*ed70e96aSJungho Lee   *inact = vi->IS_inact_prev;
2549*ed70e96aSJungho Lee   PetscFunctionReturn(0);
2550*ed70e96aSJungho Lee }
2551