xref: /petsc/src/snes/impls/vi/vi.c (revision d0af7cd330563f97edd88b8a891ae212dc5b714a)
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>
5*d0af7cd3SBarry Smith #include <../include/private/dmimpl.h>
6*d0af7cd3SBarry Smith 
7*d0af7cd3SBarry Smith typedef struct {
8*d0af7cd3SBarry Smith   IS             inactive;
9*d0af7cd3SBarry Smith   Vec            upper,lower,values,F;                    /* upper and lower bounds of all variables on this level, the values and the function values */
10*d0af7cd3SBarry Smith   PetscErrorCode (*getinterpolation)(DM,DM,Mat*,Vec*);    /* DM's original routines */
11*d0af7cd3SBarry Smith   PetscErrorCode (*coarsen)(DM, MPI_Comm, DM*);
12*d0af7cd3SBarry Smith } DMSNESVI;
13*d0af7cd3SBarry Smith 
14*d0af7cd3SBarry Smith #undef __FUNCT__
15*d0af7cd3SBarry Smith #define __FUNCT__ "SNESVIGetInActiveSetIS"
16*d0af7cd3SBarry Smith /*
17*d0af7cd3SBarry Smith    SNESVIGetInActiveSetIS - Gets the global indices for the bogus inactive set variables
18*d0af7cd3SBarry Smith 
19*d0af7cd3SBarry Smith    Input parameter
20*d0af7cd3SBarry Smith .  snes - the SNES context
21*d0af7cd3SBarry Smith .  X    - the snes solution vector
22*d0af7cd3SBarry Smith 
23*d0af7cd3SBarry Smith    Output parameter
24*d0af7cd3SBarry Smith .  ISact - active set index set
25*d0af7cd3SBarry Smith 
26*d0af7cd3SBarry Smith  */
27*d0af7cd3SBarry Smith PetscErrorCode SNESVIGetInActiveSetIS(Vec upper,Vec lower,Vec X,Vec F,IS* inact)
28*d0af7cd3SBarry Smith {
29*d0af7cd3SBarry Smith   PetscErrorCode   ierr;
30*d0af7cd3SBarry Smith   const PetscScalar *x,*xl,*xu,*f;
31*d0af7cd3SBarry Smith   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
32*d0af7cd3SBarry Smith 
33*d0af7cd3SBarry Smith   PetscFunctionBegin;
34*d0af7cd3SBarry Smith   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
35*d0af7cd3SBarry Smith   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
36*d0af7cd3SBarry Smith   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
37*d0af7cd3SBarry Smith   ierr = VecGetArrayRead(lower,&xl);CHKERRQ(ierr);
38*d0af7cd3SBarry Smith   ierr = VecGetArrayRead(upper,&xu);CHKERRQ(ierr);
39*d0af7cd3SBarry Smith   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
40*d0af7cd3SBarry Smith   /* Compute inactive set size */
41*d0af7cd3SBarry Smith   for (i=0; i < nlocal;i++) {
42*d0af7cd3SBarry 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++;
43*d0af7cd3SBarry Smith   }
44*d0af7cd3SBarry Smith 
45*d0af7cd3SBarry Smith   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
46*d0af7cd3SBarry Smith 
47*d0af7cd3SBarry Smith   /* Set inactive set indices */
48*d0af7cd3SBarry Smith   for(i=0; i < nlocal; i++) {
49*d0af7cd3SBarry 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;
50*d0af7cd3SBarry Smith   }
51*d0af7cd3SBarry Smith 
52*d0af7cd3SBarry Smith    /* Create inactive set IS */
53*d0af7cd3SBarry Smith   ierr = ISCreateGeneral(((PetscObject)upper)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,inact);CHKERRQ(ierr);
54*d0af7cd3SBarry Smith 
55*d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
56*d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(lower,&xl);CHKERRQ(ierr);
57*d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(upper,&xu);CHKERRQ(ierr);
58*d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
59*d0af7cd3SBarry Smith   PetscFunctionReturn(0);
60*d0af7cd3SBarry Smith }
61*d0af7cd3SBarry Smith 
62*d0af7cd3SBarry Smith #undef __FUNCT__
63*d0af7cd3SBarry Smith #define __FUNCT__ "DMGetInterpolation_SNESVI"
64*d0af7cd3SBarry Smith /*
65*d0af7cd3SBarry Smith      DMGetInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.
66*d0af7cd3SBarry Smith 
67*d0af7cd3SBarry Smith */
68*d0af7cd3SBarry Smith PetscErrorCode  DMGetInterpolation_SNESVI(DM dm1,DM dm2,Mat *mat,Vec *vec)
69*d0af7cd3SBarry Smith {
70*d0af7cd3SBarry Smith   PetscErrorCode          ierr;
71*d0af7cd3SBarry Smith   PetscContainer          isnes;
72*d0af7cd3SBarry Smith   DMSNESVI                *dmsnesvi1,*dmsnesvi2;
73*d0af7cd3SBarry Smith   Mat                     interp;
74*d0af7cd3SBarry Smith 
75*d0af7cd3SBarry Smith   PetscFunctionBegin;
76*d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
77*d0af7cd3SBarry Smith   if (isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
78*d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
79*d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm2,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
80*d0af7cd3SBarry Smith   if (isnes) SETERRQ(((PetscObject)dm2)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
81*d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi2);CHKERRQ(ierr);
82*d0af7cd3SBarry Smith 
83*d0af7cd3SBarry Smith   ierr = (*dmsnesvi1->getinterpolation)(dm1,dm2,&interp,PETSC_NULL);CHKERRQ(ierr);
84*d0af7cd3SBarry Smith   ierr = MatGetSubMatrix(interp,dmsnesvi1->inactive,dmsnesvi2->inactive,MAT_INITIAL_MATRIX,mat);CHKERRQ(ierr);
85*d0af7cd3SBarry Smith   ierr = MatDestroy(&interp);CHKERRQ(ierr);
86*d0af7cd3SBarry Smith   PetscFunctionReturn(0);
87*d0af7cd3SBarry Smith }
88*d0af7cd3SBarry Smith 
89*d0af7cd3SBarry Smith extern PetscErrorCode  DMSetVI(DM,Vec,Vec,Vec,Vec,IS);
90*d0af7cd3SBarry Smith 
91*d0af7cd3SBarry Smith #undef __FUNCT__
92*d0af7cd3SBarry Smith #define __FUNCT__ "DMCoarsen_SNESVI"
93*d0af7cd3SBarry Smith /*
94*d0af7cd3SBarry Smith      DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set
95*d0af7cd3SBarry Smith 
96*d0af7cd3SBarry Smith */
97*d0af7cd3SBarry Smith PetscErrorCode  DMCoarsen_SNESVI(DM dm1,MPI_Comm comm,DM *dm2)
98*d0af7cd3SBarry Smith {
99*d0af7cd3SBarry Smith   PetscErrorCode          ierr;
100*d0af7cd3SBarry Smith   PetscContainer          isnes;
101*d0af7cd3SBarry Smith   DMSNESVI                *dmsnesvi1;
102*d0af7cd3SBarry Smith   Vec                     upper,lower,values,F;
103*d0af7cd3SBarry Smith   IS                      inactive;
104*d0af7cd3SBarry Smith   VecScatter              inject;
105*d0af7cd3SBarry Smith 
106*d0af7cd3SBarry Smith   PetscFunctionBegin;
107*d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
108*d0af7cd3SBarry Smith   if (isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
109*d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
110*d0af7cd3SBarry Smith 
111*d0af7cd3SBarry Smith   ierr = (*dmsnesvi1->coarsen)(dm1,comm,dm2);CHKERRQ(ierr);
112*d0af7cd3SBarry Smith   ierr = DMGetInjection(*dm2,dm1,&inject);CHKERRQ(ierr);
113*d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&upper);CHKERRQ(ierr);
114*d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->upper,upper,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
115*d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->upper,upper,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
116*d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&lower);CHKERRQ(ierr);
117*d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->lower,lower,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
118*d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->lower,lower,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
119*d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&values);CHKERRQ(ierr);
120*d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->values,values,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
121*d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->values,values,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
122*d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&F);CHKERRQ(ierr);
123*d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->F,F,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
124*d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->F,F,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
125*d0af7cd3SBarry Smith   ierr = VecScatterDestroy(&inject);CHKERRQ(ierr);
126*d0af7cd3SBarry Smith   ierr = SNESVIGetInActiveSetIS(upper,lower,values,F,&inactive);CHKERRQ(ierr);
127*d0af7cd3SBarry Smith   ierr = DMSetVI(*dm2,upper,lower,values,F,inactive);CHKERRQ(ierr);
128*d0af7cd3SBarry Smith   PetscFunctionReturn(0);
129*d0af7cd3SBarry Smith }
130*d0af7cd3SBarry Smith 
131*d0af7cd3SBarry Smith #undef __FUNCT__
132*d0af7cd3SBarry Smith #define __FUNCT__ "DMSNESVIDestroy"
133*d0af7cd3SBarry Smith PetscErrorCode DMSNESVIDestroy(DMSNESVI *dmsnesvi)
134*d0af7cd3SBarry Smith {
135*d0af7cd3SBarry Smith   PetscErrorCode ierr;
136*d0af7cd3SBarry Smith 
137*d0af7cd3SBarry Smith   PetscFunctionBegin;
138*d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->upper);CHKERRQ(ierr);
139*d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->lower);CHKERRQ(ierr);
140*d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->values);CHKERRQ(ierr);
141*d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->F);CHKERRQ(ierr);
142*d0af7cd3SBarry Smith   ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
143*d0af7cd3SBarry Smith   ierr = PetscFree(dmsnesvi);CHKERRQ(ierr);
144*d0af7cd3SBarry Smith   PetscFunctionReturn(0);
145*d0af7cd3SBarry Smith }
146*d0af7cd3SBarry Smith 
147*d0af7cd3SBarry Smith #undef __FUNCT__
148*d0af7cd3SBarry Smith #define __FUNCT__ "DMSetVI"
149*d0af7cd3SBarry Smith /*
150*d0af7cd3SBarry Smith      DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to
151*d0af7cd3SBarry Smith                be restricted to only those variables NOT associated with active constraints.
152*d0af7cd3SBarry Smith 
153*d0af7cd3SBarry Smith */
154*d0af7cd3SBarry Smith PetscErrorCode  DMSetVI(DM dm,Vec upper,Vec lower,Vec values,Vec F,IS inactive)
155*d0af7cd3SBarry Smith {
156*d0af7cd3SBarry Smith   PetscErrorCode          ierr;
157*d0af7cd3SBarry Smith   PetscContainer          isnes;
158*d0af7cd3SBarry Smith   DMSNESVI                *dmsnesvi;
159*d0af7cd3SBarry Smith 
160*d0af7cd3SBarry Smith   PetscFunctionBegin;
161*d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)upper);CHKERRQ(ierr);
162*d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)lower);CHKERRQ(ierr);
163*d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)values);CHKERRQ(ierr);
164*d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)F);CHKERRQ(ierr);
165*d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)inactive);CHKERRQ(ierr);
166*d0af7cd3SBarry Smith 
167*d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
168*d0af7cd3SBarry Smith   if (!isnes) {
169*d0af7cd3SBarry Smith     /* cannot just compose snes into dm because that will cause circular reference */
170*d0af7cd3SBarry Smith     ierr = PetscContainerCreate(((PetscObject)dm)->comm,&isnes);CHKERRQ(ierr);
171*d0af7cd3SBarry Smith     ierr = PetscContainerSetUserDestroy(isnes,(PetscErrorCode (*)(void*))DMSNESVIDestroy);CHKERRQ(ierr);
172*d0af7cd3SBarry Smith     ierr = PetscNew(DMSNESVI,&dmsnesvi);CHKERRQ(ierr);
173*d0af7cd3SBarry Smith     ierr = PetscContainerSetPointer(isnes,(void*)dmsnesvi);CHKERRQ(ierr);
174*d0af7cd3SBarry Smith     ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)isnes);CHKERRQ(ierr);
175*d0af7cd3SBarry Smith     dmsnesvi->getinterpolation = dm->ops->getinterpolation;
176*d0af7cd3SBarry Smith     dm->ops->getinterpolation  = DMGetInterpolation_SNESVI;
177*d0af7cd3SBarry Smith     dmsnesvi->coarsen          = dm->ops->coarsen;
178*d0af7cd3SBarry Smith     dm->ops->coarsen           = DMCoarsen_SNESVI;
179*d0af7cd3SBarry Smith   } else {
180*d0af7cd3SBarry Smith     ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
181*d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->upper);CHKERRQ(ierr);
182*d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->lower);CHKERRQ(ierr);
183*d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->values);CHKERRQ(ierr);
184*d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->F);CHKERRQ(ierr);
185*d0af7cd3SBarry Smith     ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
186*d0af7cd3SBarry Smith   }
187*d0af7cd3SBarry Smith   dmsnesvi->upper    = upper;
188*d0af7cd3SBarry Smith   dmsnesvi->lower    = lower;
189*d0af7cd3SBarry Smith   dmsnesvi->values   = values;
190*d0af7cd3SBarry Smith   dmsnesvi->F        = F;
191*d0af7cd3SBarry Smith   dmsnesvi->inactive = inactive;
192*d0af7cd3SBarry Smith   PetscFunctionReturn(0);
193*d0af7cd3SBarry Smith }
194*d0af7cd3SBarry Smith 
195*d0af7cd3SBarry Smith 
1962b4ed282SShri Abhyankar 
1979308c137SBarry Smith #undef __FUNCT__
1989308c137SBarry Smith #define __FUNCT__ "SNESMonitorVI"
1997087cfbeSBarry Smith PetscErrorCode  SNESMonitorVI(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
2009308c137SBarry Smith {
2019308c137SBarry Smith   PetscErrorCode          ierr;
2029308c137SBarry Smith   SNES_VI                 *vi = (SNES_VI*)snes->data;
2039308c137SBarry Smith   PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor) dummy;
2049308c137SBarry Smith   const PetscScalar       *x,*xl,*xu,*f;
20509573ac7SBarry Smith   PetscInt                i,n,act = 0;
2069308c137SBarry Smith   PetscReal               rnorm,fnorm;
2079308c137SBarry Smith 
2089308c137SBarry Smith   PetscFunctionBegin;
2099308c137SBarry Smith   if (!dummy) {
2109308c137SBarry Smith     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)snes)->comm,"stdout",0,&viewer);CHKERRQ(ierr);
2119308c137SBarry Smith   }
2129308c137SBarry Smith   ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
2139308c137SBarry Smith   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
2149308c137SBarry Smith   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
2159308c137SBarry Smith   ierr = VecGetArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
2163f731af5SBarry Smith   ierr = VecGetArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
2179308c137SBarry Smith 
2189308c137SBarry Smith   rnorm = 0.0;
2199308c137SBarry Smith   for (i=0; i<n; i++) {
22010f5ae6bSBarry 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]);
22109573ac7SBarry Smith     else act++;
2229308c137SBarry Smith   }
2233f731af5SBarry Smith   ierr = VecRestoreArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
2249308c137SBarry Smith   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
2259308c137SBarry Smith   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
2269308c137SBarry Smith   ierr = VecRestoreArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
227d9822059SBarry Smith   ierr = MPI_Allreduce(&rnorm,&fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
2289308c137SBarry Smith   fnorm = sqrt(fnorm);
22909573ac7SBarry Smith   ierr = PetscViewerASCIIMonitorPrintf(viewer,"%3D SNES VI Function norm %14.12e Active constraints %D\n",its,fnorm,act);CHKERRQ(ierr);
2309308c137SBarry Smith   if (!dummy) {
2316bf464f9SBarry Smith     ierr = PetscViewerASCIIMonitorDestroy(&viewer);CHKERRQ(ierr);
2329308c137SBarry Smith   }
2339308c137SBarry Smith   PetscFunctionReturn(0);
2349308c137SBarry Smith }
2359308c137SBarry Smith 
2362b4ed282SShri Abhyankar /*
2372b4ed282SShri Abhyankar      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
2382b4ed282SShri 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
2392b4ed282SShri Abhyankar     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
2402b4ed282SShri Abhyankar     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
2412b4ed282SShri Abhyankar */
2422b4ed282SShri Abhyankar #undef __FUNCT__
2432b4ed282SShri Abhyankar #define __FUNCT__ "SNESVICheckLocalMin_Private"
244ace3abfcSBarry Smith PetscErrorCode SNESVICheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool *ismin)
2452b4ed282SShri Abhyankar {
2462b4ed282SShri Abhyankar   PetscReal      a1;
2472b4ed282SShri Abhyankar   PetscErrorCode ierr;
248ace3abfcSBarry Smith   PetscBool     hastranspose;
2492b4ed282SShri Abhyankar 
2502b4ed282SShri Abhyankar   PetscFunctionBegin;
2512b4ed282SShri Abhyankar   *ismin = PETSC_FALSE;
2522b4ed282SShri Abhyankar   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
2532b4ed282SShri Abhyankar   if (hastranspose) {
2542b4ed282SShri Abhyankar     /* Compute || J^T F|| */
2552b4ed282SShri Abhyankar     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
2562b4ed282SShri Abhyankar     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
2572b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);CHKERRQ(ierr);
2582b4ed282SShri Abhyankar     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
2592b4ed282SShri Abhyankar   } else {
2602b4ed282SShri Abhyankar     Vec         work;
2612b4ed282SShri Abhyankar     PetscScalar result;
2622b4ed282SShri Abhyankar     PetscReal   wnorm;
2632b4ed282SShri Abhyankar 
2642b4ed282SShri Abhyankar     ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr);
2652b4ed282SShri Abhyankar     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
2662b4ed282SShri Abhyankar     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
2672b4ed282SShri Abhyankar     ierr = MatMult(A,W,work);CHKERRQ(ierr);
2682b4ed282SShri Abhyankar     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
2696bf464f9SBarry Smith     ierr = VecDestroy(&work);CHKERRQ(ierr);
2702b4ed282SShri Abhyankar     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
2712b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);CHKERRQ(ierr);
2722b4ed282SShri Abhyankar     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
2732b4ed282SShri Abhyankar   }
2742b4ed282SShri Abhyankar   PetscFunctionReturn(0);
2752b4ed282SShri Abhyankar }
2762b4ed282SShri Abhyankar 
2772b4ed282SShri Abhyankar /*
2782b4ed282SShri Abhyankar      Checks if J^T(F - J*X) = 0
2792b4ed282SShri Abhyankar */
2802b4ed282SShri Abhyankar #undef __FUNCT__
2812b4ed282SShri Abhyankar #define __FUNCT__ "SNESVICheckResidual_Private"
2822b4ed282SShri Abhyankar PetscErrorCode SNESVICheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
2832b4ed282SShri Abhyankar {
2842b4ed282SShri Abhyankar   PetscReal      a1,a2;
2852b4ed282SShri Abhyankar   PetscErrorCode ierr;
286ace3abfcSBarry Smith   PetscBool     hastranspose;
2872b4ed282SShri Abhyankar 
2882b4ed282SShri Abhyankar   PetscFunctionBegin;
2892b4ed282SShri Abhyankar   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
2902b4ed282SShri Abhyankar   if (hastranspose) {
2912b4ed282SShri Abhyankar     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
2922b4ed282SShri Abhyankar     ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr);
2932b4ed282SShri Abhyankar 
2942b4ed282SShri Abhyankar     /* Compute || J^T W|| */
2952b4ed282SShri Abhyankar     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
2962b4ed282SShri Abhyankar     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
2972b4ed282SShri Abhyankar     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
2982b4ed282SShri Abhyankar     if (a1 != 0.0) {
2992b4ed282SShri Abhyankar       ierr = PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);CHKERRQ(ierr);
3002b4ed282SShri Abhyankar     }
3012b4ed282SShri Abhyankar   }
3022b4ed282SShri Abhyankar   PetscFunctionReturn(0);
3032b4ed282SShri Abhyankar }
3042b4ed282SShri Abhyankar 
3052b4ed282SShri Abhyankar /*
3062b4ed282SShri Abhyankar   SNESDefaultConverged_VI - Checks the convergence of the semismooth newton algorithm.
3072b4ed282SShri Abhyankar 
3082b4ed282SShri Abhyankar   Notes:
3092b4ed282SShri Abhyankar   The convergence criterion currently implemented is
3102b4ed282SShri Abhyankar   merit < abstol
3112b4ed282SShri Abhyankar   merit < rtol*merit_initial
3122b4ed282SShri Abhyankar */
3132b4ed282SShri Abhyankar #undef __FUNCT__
3142b4ed282SShri Abhyankar #define __FUNCT__ "SNESDefaultConverged_VI"
3157fe79bc4SShri Abhyankar PetscErrorCode SNESDefaultConverged_VI(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gradnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
3162b4ed282SShri Abhyankar {
3172b4ed282SShri Abhyankar   PetscErrorCode ierr;
3182b4ed282SShri Abhyankar 
3192b4ed282SShri Abhyankar   PetscFunctionBegin;
3202b4ed282SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
3212b4ed282SShri Abhyankar   PetscValidPointer(reason,6);
3222b4ed282SShri Abhyankar 
3232b4ed282SShri Abhyankar   *reason = SNES_CONVERGED_ITERATING;
3242b4ed282SShri Abhyankar 
3252b4ed282SShri Abhyankar   if (!it) {
3262b4ed282SShri Abhyankar     /* set parameter for default relative tolerance convergence test */
3277fe79bc4SShri Abhyankar     snes->ttol = fnorm*snes->rtol;
3282b4ed282SShri Abhyankar   }
3297fe79bc4SShri Abhyankar   if (fnorm != fnorm) {
3302b4ed282SShri Abhyankar     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
3312b4ed282SShri Abhyankar     *reason = SNES_DIVERGED_FNORM_NAN;
3327fe79bc4SShri Abhyankar   } else if (fnorm < snes->abstol) {
3337fe79bc4SShri Abhyankar     ierr = PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);CHKERRQ(ierr);
3342b4ed282SShri Abhyankar     *reason = SNES_CONVERGED_FNORM_ABS;
3352b4ed282SShri Abhyankar   } else if (snes->nfuncs >= snes->max_funcs) {
3362b4ed282SShri Abhyankar     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
3372b4ed282SShri Abhyankar     *reason = SNES_DIVERGED_FUNCTION_COUNT;
3382b4ed282SShri Abhyankar   }
3392b4ed282SShri Abhyankar 
3402b4ed282SShri Abhyankar   if (it && !*reason) {
3417fe79bc4SShri Abhyankar     if (fnorm < snes->ttol) {
3427fe79bc4SShri Abhyankar       ierr = PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);CHKERRQ(ierr);
3432b4ed282SShri Abhyankar       *reason = SNES_CONVERGED_FNORM_RELATIVE;
3442b4ed282SShri Abhyankar     }
3452b4ed282SShri Abhyankar   }
3462b4ed282SShri Abhyankar   PetscFunctionReturn(0);
3472b4ed282SShri Abhyankar }
3482b4ed282SShri Abhyankar 
3492b4ed282SShri Abhyankar /*
3502b4ed282SShri Abhyankar   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.
3512b4ed282SShri Abhyankar 
3522b4ed282SShri Abhyankar   Input Parameter:
3532b4ed282SShri Abhyankar . phi - the semismooth function
3542b4ed282SShri Abhyankar 
3552b4ed282SShri Abhyankar   Output Parameter:
3562b4ed282SShri Abhyankar . merit - the merit function
3572b4ed282SShri Abhyankar . phinorm - ||phi||
3582b4ed282SShri Abhyankar 
3592b4ed282SShri Abhyankar   Notes:
3602b4ed282SShri Abhyankar   The merit function for the mixed complementarity problem is defined as
3612b4ed282SShri Abhyankar      merit = 0.5*phi^T*phi
3622b4ed282SShri Abhyankar */
3632b4ed282SShri Abhyankar #undef __FUNCT__
3642b4ed282SShri Abhyankar #define __FUNCT__ "SNESVIComputeMeritFunction"
3652b4ed282SShri Abhyankar static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm)
3662b4ed282SShri Abhyankar {
3672b4ed282SShri Abhyankar   PetscErrorCode ierr;
3682b4ed282SShri Abhyankar 
3692b4ed282SShri Abhyankar   PetscFunctionBegin;
3705f48b12bSBarry Smith   ierr = VecNormBegin(phi,NORM_2,phinorm);CHKERRQ(ierr);
3715f48b12bSBarry Smith   ierr = VecNormEnd(phi,NORM_2,phinorm);CHKERRQ(ierr);
3722b4ed282SShri Abhyankar 
3732b4ed282SShri Abhyankar   *merit = 0.5*(*phinorm)*(*phinorm);
3742b4ed282SShri Abhyankar   PetscFunctionReturn(0);
3752b4ed282SShri Abhyankar }
3762b4ed282SShri Abhyankar 
3777f6f51e9SSatish Balay PETSC_STATIC_INLINE PetscScalar Phi(PetscScalar a,PetscScalar b)
3784c21c6cdSBarry Smith {
3794c21c6cdSBarry Smith   return a + b - sqrt(a*a + b*b);
3804c21c6cdSBarry Smith }
3814c21c6cdSBarry Smith 
3827f6f51e9SSatish Balay PETSC_STATIC_INLINE PetscScalar DPhi(PetscScalar a,PetscScalar b)
3834c21c6cdSBarry Smith {
3845559b345SBarry Smith   if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return  1.0 - a/ sqrt(a*a + b*b);
3855559b345SBarry Smith   else return .5;
3864c21c6cdSBarry Smith }
3874c21c6cdSBarry Smith 
3882b4ed282SShri Abhyankar /*
3891f79c099SShri Abhyankar    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form.
3902b4ed282SShri Abhyankar 
3912b4ed282SShri Abhyankar    Input Parameters:
3922b4ed282SShri Abhyankar .  snes - the SNES context
3932b4ed282SShri Abhyankar .  x - current iterate
3942b4ed282SShri Abhyankar .  functx - user defined function context
3952b4ed282SShri Abhyankar 
3962b4ed282SShri Abhyankar    Output Parameters:
3972b4ed282SShri Abhyankar .  phi - Semismooth function
3982b4ed282SShri Abhyankar 
3992b4ed282SShri Abhyankar */
4002b4ed282SShri Abhyankar #undef __FUNCT__
4011f79c099SShri Abhyankar #define __FUNCT__ "SNESVIComputeFunction"
4021f79c099SShri Abhyankar static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void* functx)
4032b4ed282SShri Abhyankar {
4042b4ed282SShri Abhyankar   PetscErrorCode  ierr;
4052b4ed282SShri Abhyankar   SNES_VI         *vi = (SNES_VI*)snes->data;
4062b4ed282SShri Abhyankar   Vec             Xl = vi->xl,Xu = vi->xu,F = snes->vec_func;
4074c21c6cdSBarry Smith   PetscScalar     *phi_arr,*x_arr,*f_arr,*l,*u;
4082b4ed282SShri Abhyankar   PetscInt        i,nlocal;
4092b4ed282SShri Abhyankar 
4102b4ed282SShri Abhyankar   PetscFunctionBegin;
4112b4ed282SShri Abhyankar   ierr = (*vi->computeuserfunction)(snes,X,F,functx);CHKERRQ(ierr);
4122b4ed282SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
4132b4ed282SShri Abhyankar   ierr = VecGetArray(X,&x_arr);CHKERRQ(ierr);
4142b4ed282SShri Abhyankar   ierr = VecGetArray(F,&f_arr);CHKERRQ(ierr);
4152b4ed282SShri Abhyankar   ierr = VecGetArray(Xl,&l);CHKERRQ(ierr);
4162b4ed282SShri Abhyankar   ierr = VecGetArray(Xu,&u);CHKERRQ(ierr);
4172b4ed282SShri Abhyankar   ierr = VecGetArray(phi,&phi_arr);CHKERRQ(ierr);
4182b4ed282SShri Abhyankar 
4192b4ed282SShri Abhyankar   for (i=0;i < nlocal;i++) {
42010f5ae6bSBarry Smith     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) { /* no constraints on variable */
4214c21c6cdSBarry Smith       phi_arr[i] = f_arr[i];
42210f5ae6bSBarry Smith     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                      /* upper bound on variable only */
4234c21c6cdSBarry Smith       phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]);
42410f5ae6bSBarry Smith     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                       /* lower bound on variable only */
4254c21c6cdSBarry Smith       phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]);
4265559b345SBarry Smith     } else if (l[i] == u[i]) {
4272b4ed282SShri Abhyankar       phi_arr[i] = l[i] - x_arr[i];
4285559b345SBarry Smith     } else {                                                /* both bounds on variable */
4294c21c6cdSBarry Smith       phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i]));
4302b4ed282SShri Abhyankar     }
4312b4ed282SShri Abhyankar   }
4322b4ed282SShri Abhyankar 
4332b4ed282SShri Abhyankar   ierr = VecRestoreArray(X,&x_arr);CHKERRQ(ierr);
4342b4ed282SShri Abhyankar   ierr = VecRestoreArray(F,&f_arr);CHKERRQ(ierr);
4352b4ed282SShri Abhyankar   ierr = VecRestoreArray(Xl,&l);CHKERRQ(ierr);
4362b4ed282SShri Abhyankar   ierr = VecRestoreArray(Xu,&u);CHKERRQ(ierr);
4372b4ed282SShri Abhyankar   ierr = VecRestoreArray(phi,&phi_arr);CHKERRQ(ierr);
4382b4ed282SShri Abhyankar   PetscFunctionReturn(0);
4392b4ed282SShri Abhyankar }
4402b4ed282SShri Abhyankar 
4412b4ed282SShri Abhyankar /*
442a79edbefSShri Abhyankar    SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the
443a79edbefSShri Abhyankar                                           the semismooth jacobian.
4442b4ed282SShri Abhyankar */
4452b4ed282SShri Abhyankar #undef __FUNCT__
446a79edbefSShri Abhyankar #define __FUNCT__ "SNESVIComputeBsubdifferentialVectors"
447a79edbefSShri Abhyankar PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db)
4482b4ed282SShri Abhyankar {
4492b4ed282SShri Abhyankar   PetscErrorCode ierr;
4502b4ed282SShri Abhyankar   SNES_VI      *vi = (SNES_VI*)snes->data;
4514c21c6cdSBarry Smith   PetscScalar    *l,*u,*x,*f,*da,*db,da1,da2,db1,db2;
4522b4ed282SShri Abhyankar   PetscInt       i,nlocal;
4532b4ed282SShri Abhyankar 
4542b4ed282SShri Abhyankar   PetscFunctionBegin;
4552b4ed282SShri Abhyankar 
4562b4ed282SShri Abhyankar   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
4572b4ed282SShri Abhyankar   ierr = VecGetArray(F,&f);CHKERRQ(ierr);
4582b4ed282SShri Abhyankar   ierr = VecGetArray(vi->xl,&l);CHKERRQ(ierr);
4592b4ed282SShri Abhyankar   ierr = VecGetArray(vi->xu,&u);CHKERRQ(ierr);
460a79edbefSShri Abhyankar   ierr = VecGetArray(Da,&da);CHKERRQ(ierr);
461a79edbefSShri Abhyankar   ierr = VecGetArray(Db,&db);CHKERRQ(ierr);
4622b4ed282SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
4634c21c6cdSBarry Smith 
4642b4ed282SShri Abhyankar   for (i=0;i< nlocal;i++) {
46510f5ae6bSBarry Smith     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) {/* no constraints on variable */
4664c21c6cdSBarry Smith       da[i] = 0;
4672b4ed282SShri Abhyankar       db[i] = 1;
46810f5ae6bSBarry Smith     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                     /* upper bound on variable only */
4694c21c6cdSBarry Smith       da[i] = DPhi(u[i] - x[i], -f[i]);
4704c21c6cdSBarry Smith       db[i] = DPhi(-f[i],u[i] - x[i]);
47110f5ae6bSBarry Smith     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                      /* lower bound on variable only */
4725559b345SBarry Smith       da[i] = DPhi(x[i] - l[i], f[i]);
4735559b345SBarry Smith       db[i] = DPhi(f[i],x[i] - l[i]);
4745559b345SBarry Smith     } else if (l[i] == u[i]) {                              /* fixed variable */
4754c21c6cdSBarry Smith       da[i] = 1;
4762b4ed282SShri Abhyankar       db[i] = 0;
4775559b345SBarry Smith     } else {                                                /* upper and lower bounds on variable */
4784c21c6cdSBarry Smith       da1 = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i]));
4794c21c6cdSBarry Smith       db1 = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]);
4804c21c6cdSBarry Smith       da2 = DPhi(u[i] - x[i], -f[i]);
4814c21c6cdSBarry Smith       db2 = DPhi(-f[i],u[i] - x[i]);
4824c21c6cdSBarry Smith       da[i] = da1 + db1*da2;
4834c21c6cdSBarry Smith       db[i] = db1*db2;
4842b4ed282SShri Abhyankar     }
4852b4ed282SShri Abhyankar   }
4865559b345SBarry Smith 
4872b4ed282SShri Abhyankar   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
4882b4ed282SShri Abhyankar   ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
4892b4ed282SShri Abhyankar   ierr = VecRestoreArray(vi->xl,&l);CHKERRQ(ierr);
4902b4ed282SShri Abhyankar   ierr = VecRestoreArray(vi->xu,&u);CHKERRQ(ierr);
491a79edbefSShri Abhyankar   ierr = VecRestoreArray(Da,&da);CHKERRQ(ierr);
492a79edbefSShri Abhyankar   ierr = VecRestoreArray(Db,&db);CHKERRQ(ierr);
493a79edbefSShri Abhyankar   PetscFunctionReturn(0);
494a79edbefSShri Abhyankar }
495a79edbefSShri Abhyankar 
496a79edbefSShri Abhyankar /*
497a79edbefSShri 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.
498a79edbefSShri Abhyankar 
499a79edbefSShri Abhyankar    Input Parameters:
500a79edbefSShri Abhyankar .  Da       - Diagonal shift vector for the semismooth jacobian.
501a79edbefSShri Abhyankar .  Db       - Row scaling vector for the semismooth jacobian.
502a79edbefSShri Abhyankar 
503a79edbefSShri Abhyankar    Output Parameters:
504a79edbefSShri Abhyankar .  jac      - semismooth jacobian
505a79edbefSShri Abhyankar .  jac_pre  - optional preconditioning matrix
506a79edbefSShri Abhyankar 
507a79edbefSShri Abhyankar    Notes:
508a79edbefSShri Abhyankar    The semismooth jacobian matrix is given by
509a79edbefSShri Abhyankar    jac = Da + Db*jacfun
510a79edbefSShri Abhyankar    where Db is the row scaling matrix stored as a vector,
511a79edbefSShri Abhyankar          Da is the diagonal perturbation matrix stored as a vector
512a79edbefSShri Abhyankar    and   jacfun is the jacobian of the original nonlinear function.
513a79edbefSShri Abhyankar */
514a79edbefSShri Abhyankar #undef __FUNCT__
515a79edbefSShri Abhyankar #define __FUNCT__ "SNESVIComputeJacobian"
516a79edbefSShri Abhyankar PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db)
517a79edbefSShri Abhyankar {
518a79edbefSShri Abhyankar   PetscErrorCode ierr;
519a79edbefSShri Abhyankar 
5202b4ed282SShri Abhyankar   /* Do row scaling  and add diagonal perturbation */
521a79edbefSShri Abhyankar   ierr = MatDiagonalScale(jac,Db,PETSC_NULL);CHKERRQ(ierr);
522a79edbefSShri Abhyankar   ierr = MatDiagonalSet(jac,Da,ADD_VALUES);CHKERRQ(ierr);
523a79edbefSShri Abhyankar   if (jac != jac_pre) { /* If jac and jac_pre are different */
524a79edbefSShri Abhyankar     ierr = MatDiagonalScale(jac_pre,Db,PETSC_NULL);
525a79edbefSShri Abhyankar     ierr = MatDiagonalSet(jac_pre,Da,ADD_VALUES);CHKERRQ(ierr);
5262b4ed282SShri Abhyankar   }
5272b4ed282SShri Abhyankar   PetscFunctionReturn(0);
5282b4ed282SShri Abhyankar }
5292b4ed282SShri Abhyankar 
5302b4ed282SShri Abhyankar /*
531ee657d29SShri Abhyankar    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.
532ee657d29SShri Abhyankar 
533ee657d29SShri Abhyankar    Input Parameters:
534ee657d29SShri Abhyankar    phi - semismooth function.
535ee657d29SShri Abhyankar    H   - semismooth jacobian
536ee657d29SShri Abhyankar 
537ee657d29SShri Abhyankar    Output Parameters:
538ee657d29SShri Abhyankar    dpsi - merit function gradient
539ee657d29SShri Abhyankar 
540ee657d29SShri Abhyankar    Notes:
541ee657d29SShri Abhyankar   The merit function gradient is computed as follows
542ee657d29SShri Abhyankar         dpsi = H^T*phi
543ee657d29SShri Abhyankar */
544ee657d29SShri Abhyankar #undef __FUNCT__
545ee657d29SShri Abhyankar #define __FUNCT__ "SNESVIComputeMeritFunctionGradient"
546ee657d29SShri Abhyankar PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
547ee657d29SShri Abhyankar {
548ee657d29SShri Abhyankar   PetscErrorCode ierr;
549ee657d29SShri Abhyankar 
550ee657d29SShri Abhyankar   PetscFunctionBegin;
5515f48b12bSBarry Smith   ierr = MatMultTranspose(H,phi,dpsi);CHKERRQ(ierr);
552ee657d29SShri Abhyankar   PetscFunctionReturn(0);
553ee657d29SShri Abhyankar }
554ee657d29SShri Abhyankar 
555c1a5e521SShri Abhyankar /* -------------------------------------------------------------------------- */
556c1a5e521SShri Abhyankar /*
557c1a5e521SShri Abhyankar    SNESVIProjectOntoBounds - Projects X onto the feasible region so that Xl[i] <= X[i] <= Xu[i] for i = 1...n.
558c1a5e521SShri Abhyankar 
559c1a5e521SShri Abhyankar    Input Parameters:
560c1a5e521SShri Abhyankar .  SNES - nonlinear solver context
561c1a5e521SShri Abhyankar 
562c1a5e521SShri Abhyankar    Output Parameters:
563c1a5e521SShri Abhyankar .  X - Bound projected X
564c1a5e521SShri Abhyankar 
565c1a5e521SShri Abhyankar */
566c1a5e521SShri Abhyankar 
567c1a5e521SShri Abhyankar #undef __FUNCT__
568c1a5e521SShri Abhyankar #define __FUNCT__ "SNESVIProjectOntoBounds"
569c1a5e521SShri Abhyankar PetscErrorCode SNESVIProjectOntoBounds(SNES snes,Vec X)
570c1a5e521SShri Abhyankar {
571c1a5e521SShri Abhyankar   PetscErrorCode    ierr;
572c1a5e521SShri Abhyankar   SNES_VI           *vi = (SNES_VI*)snes->data;
573c1a5e521SShri Abhyankar   const PetscScalar *xl,*xu;
574c1a5e521SShri Abhyankar   PetscScalar       *x;
575c1a5e521SShri Abhyankar   PetscInt          i,n;
576c1a5e521SShri Abhyankar 
577c1a5e521SShri Abhyankar   PetscFunctionBegin;
578c1a5e521SShri Abhyankar   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
579c1a5e521SShri Abhyankar   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
580c1a5e521SShri Abhyankar   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
581c1a5e521SShri Abhyankar   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
582c1a5e521SShri Abhyankar 
583c1a5e521SShri Abhyankar   for(i = 0;i<n;i++) {
58410f5ae6bSBarry Smith     if (PetscRealPart(x[i]) < PetscRealPart(xl[i])) x[i] = xl[i];
58510f5ae6bSBarry Smith     else if (PetscRealPart(x[i]) > PetscRealPart(xu[i])) x[i] = xu[i];
586c1a5e521SShri Abhyankar   }
587c1a5e521SShri Abhyankar   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
588c1a5e521SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
589c1a5e521SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
590c1a5e521SShri Abhyankar   PetscFunctionReturn(0);
591c1a5e521SShri Abhyankar }
592c1a5e521SShri Abhyankar 
5932b4ed282SShri Abhyankar /*  --------------------------------------------------------------------
5942b4ed282SShri Abhyankar 
5952b4ed282SShri Abhyankar      This file implements a semismooth truncated Newton method with a line search,
5962b4ed282SShri Abhyankar      for solving a system of nonlinear equations in complementarity form, using the KSP, Vec,
5972b4ed282SShri Abhyankar      and Mat interfaces for linear solvers, vectors, and matrices,
5982b4ed282SShri Abhyankar      respectively.
5992b4ed282SShri Abhyankar 
6002b4ed282SShri Abhyankar      The following basic routines are required for each nonlinear solver:
6012b4ed282SShri Abhyankar           SNESCreate_XXX()          - Creates a nonlinear solver context
6022b4ed282SShri Abhyankar           SNESSetFromOptions_XXX()  - Sets runtime options
6032b4ed282SShri Abhyankar           SNESSolve_XXX()           - Solves the nonlinear system
6042b4ed282SShri Abhyankar           SNESDestroy_XXX()         - Destroys the nonlinear solver context
6052b4ed282SShri Abhyankar      The suffix "_XXX" denotes a particular implementation, in this case
6062b4ed282SShri Abhyankar      we use _VI (e.g., SNESCreate_VI, SNESSolve_VI) for solving
6072b4ed282SShri Abhyankar      systems of nonlinear equations with a line search (LS) method.
6082b4ed282SShri Abhyankar      These routines are actually called via the common user interface
6092b4ed282SShri Abhyankar      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
6102b4ed282SShri Abhyankar      SNESDestroy(), so the application code interface remains identical
6112b4ed282SShri Abhyankar      for all nonlinear solvers.
6122b4ed282SShri Abhyankar 
6132b4ed282SShri Abhyankar      Another key routine is:
6142b4ed282SShri Abhyankar           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
6152b4ed282SShri Abhyankar      by setting data structures and options.   The interface routine SNESSetUp()
6162b4ed282SShri Abhyankar      is not usually called directly by the user, but instead is called by
6172b4ed282SShri Abhyankar      SNESSolve() if necessary.
6182b4ed282SShri Abhyankar 
6192b4ed282SShri Abhyankar      Additional basic routines are:
6202b4ed282SShri Abhyankar           SNESView_XXX()            - Prints details of runtime options that
6212b4ed282SShri Abhyankar                                       have actually been used.
6222b4ed282SShri Abhyankar      These are called by application codes via the interface routines
6232b4ed282SShri Abhyankar      SNESView().
6242b4ed282SShri Abhyankar 
6252b4ed282SShri Abhyankar      The various types of solvers (preconditioners, Krylov subspace methods,
6262b4ed282SShri Abhyankar      nonlinear solvers, timesteppers) are all organized similarly, so the
6272b4ed282SShri Abhyankar      above description applies to these categories also.
6282b4ed282SShri Abhyankar 
6292b4ed282SShri Abhyankar     -------------------------------------------------------------------- */
6302b4ed282SShri Abhyankar /*
63169c03620SShri Abhyankar    SNESSolveVI_SS - Solves the complementarity problem with a semismooth Newton
6322b4ed282SShri Abhyankar    method using a line search.
6332b4ed282SShri Abhyankar 
6342b4ed282SShri Abhyankar    Input Parameters:
6352b4ed282SShri Abhyankar .  snes - the SNES context
6362b4ed282SShri Abhyankar 
6372b4ed282SShri Abhyankar    Output Parameter:
6382b4ed282SShri Abhyankar .  outits - number of iterations until termination
6392b4ed282SShri Abhyankar 
6402b4ed282SShri Abhyankar    Application Interface Routine: SNESSolve()
6412b4ed282SShri Abhyankar 
6422b4ed282SShri Abhyankar    Notes:
6432b4ed282SShri Abhyankar    This implements essentially a semismooth Newton method with a
64451defd01SShri Abhyankar    line search. The default line search does not do any line seach
64551defd01SShri Abhyankar    but rather takes a full newton step.
6462b4ed282SShri Abhyankar */
6472b4ed282SShri Abhyankar #undef __FUNCT__
64869c03620SShri Abhyankar #define __FUNCT__ "SNESSolveVI_SS"
64969c03620SShri Abhyankar PetscErrorCode SNESSolveVI_SS(SNES snes)
6502b4ed282SShri Abhyankar {
6512b4ed282SShri Abhyankar   SNES_VI            *vi = (SNES_VI*)snes->data;
6522b4ed282SShri Abhyankar   PetscErrorCode     ierr;
6532b4ed282SShri Abhyankar   PetscInt           maxits,i,lits;
6543b336b49SShri Abhyankar   PetscBool          lssucceed;
6552b4ed282SShri Abhyankar   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
6562b4ed282SShri Abhyankar   PetscReal          gnorm,xnorm=0,ynorm;
6572b4ed282SShri Abhyankar   Vec                Y,X,F,G,W;
6582b4ed282SShri Abhyankar   KSPConvergedReason kspreason;
6592b4ed282SShri Abhyankar 
6602b4ed282SShri Abhyankar   PetscFunctionBegin;
6619ce7406fSBarry Smith   vi->computeuserfunction    = snes->ops->computefunction;
6629ce7406fSBarry Smith   snes->ops->computefunction = SNESVIComputeFunction;
6639ce7406fSBarry Smith 
6642b4ed282SShri Abhyankar   snes->numFailures            = 0;
6652b4ed282SShri Abhyankar   snes->numLinearSolveFailures = 0;
6662b4ed282SShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
6672b4ed282SShri Abhyankar 
6682b4ed282SShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
6692b4ed282SShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
6702b4ed282SShri Abhyankar   F		= snes->vec_func;	/* residual vector */
6712b4ed282SShri Abhyankar   Y		= snes->work[0];	/* work vectors */
6722b4ed282SShri Abhyankar   G		= snes->work[1];
6732b4ed282SShri Abhyankar   W		= snes->work[2];
6742b4ed282SShri Abhyankar 
6752b4ed282SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
6762b4ed282SShri Abhyankar   snes->iter = 0;
6772b4ed282SShri Abhyankar   snes->norm = 0.0;
6782b4ed282SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
6792b4ed282SShri Abhyankar 
6807fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
6812b4ed282SShri Abhyankar   ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr);
6822b4ed282SShri Abhyankar   if (snes->domainerror) {
6832b4ed282SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
6849ce7406fSBarry Smith     snes->ops->computefunction = vi->computeuserfunction;
6852b4ed282SShri Abhyankar     PetscFunctionReturn(0);
6862b4ed282SShri Abhyankar   }
6872b4ed282SShri Abhyankar    /* Compute Merit function */
6882b4ed282SShri Abhyankar   ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr);
6892b4ed282SShri Abhyankar 
6902b4ed282SShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
6912b4ed282SShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
69262cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(vi->merit)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
6932b4ed282SShri Abhyankar 
6942b4ed282SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
6952b4ed282SShri Abhyankar   snes->norm = vi->phinorm;
6962b4ed282SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
6972b4ed282SShri Abhyankar   SNESLogConvHistory(snes,vi->phinorm,0);
6987a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,vi->phinorm);CHKERRQ(ierr);
6992b4ed282SShri Abhyankar 
7002b4ed282SShri Abhyankar   /* set parameter for default relative tolerance convergence test */
7012b4ed282SShri Abhyankar   snes->ttol = vi->phinorm*snes->rtol;
7022b4ed282SShri Abhyankar   /* test convergence */
7032b4ed282SShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
7049ce7406fSBarry Smith   if (snes->reason) {
7059ce7406fSBarry Smith     snes->ops->computefunction = vi->computeuserfunction;
7069ce7406fSBarry Smith     PetscFunctionReturn(0);
7079ce7406fSBarry Smith   }
7082b4ed282SShri Abhyankar 
7092b4ed282SShri Abhyankar   for (i=0; i<maxits; i++) {
7102b4ed282SShri Abhyankar 
7112b4ed282SShri Abhyankar     /* Call general purpose update function */
7122b4ed282SShri Abhyankar     if (snes->ops->update) {
7132b4ed282SShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
7142b4ed282SShri Abhyankar     }
7152b4ed282SShri Abhyankar 
7162b4ed282SShri Abhyankar     /* Solve J Y = Phi, where J is the semismooth jacobian */
717a79edbefSShri Abhyankar     /* Get the nonlinear function jacobian */
7182b4ed282SShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
719a79edbefSShri Abhyankar     /* Get the diagonal shift and row scaling vectors */
720a79edbefSShri Abhyankar     ierr = SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);CHKERRQ(ierr);
721a79edbefSShri Abhyankar     /* Compute the semismooth jacobian */
722a79edbefSShri Abhyankar     ierr = SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);CHKERRQ(ierr);
723ee657d29SShri Abhyankar     /* Compute the merit function gradient */
724ee657d29SShri Abhyankar     ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr);
7252b4ed282SShri Abhyankar     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
7262b4ed282SShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);CHKERRQ(ierr);
7272b4ed282SShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
7283b336b49SShri Abhyankar 
7293b336b49SShri Abhyankar     if (kspreason < 0) {
7302b4ed282SShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
7312b4ed282SShri 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);
7322b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
7332b4ed282SShri Abhyankar         break;
7342b4ed282SShri Abhyankar       }
7352b4ed282SShri Abhyankar     }
7362b4ed282SShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
7372b4ed282SShri Abhyankar     snes->linear_its += lits;
7382b4ed282SShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
7392b4ed282SShri Abhyankar     /*
7402b4ed282SShri Abhyankar     if (vi->precheckstep) {
741ace3abfcSBarry Smith       PetscBool changed_y = PETSC_FALSE;
7422b4ed282SShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
7432b4ed282SShri Abhyankar     }
7442b4ed282SShri Abhyankar 
7452b4ed282SShri Abhyankar     if (PetscLogPrintInfo){
7462b4ed282SShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
7472b4ed282SShri Abhyankar     }
7482b4ed282SShri Abhyankar     */
7492b4ed282SShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
7502b4ed282SShri Abhyankar          Y <- X - lambda*Y
7512b4ed282SShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
7522b4ed282SShri Abhyankar     */
7532b4ed282SShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
7542b4ed282SShri Abhyankar     ynorm = 1; gnorm = vi->phinorm;
7552b4ed282SShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,vi->phi,G,Y,W,vi->phinorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
7562b4ed282SShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",vi->phinorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
7572b4ed282SShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
7582b4ed282SShri Abhyankar     if (snes->domainerror) {
7592b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
7609ce7406fSBarry Smith       snes->ops->computefunction = vi->computeuserfunction;
7612b4ed282SShri Abhyankar       PetscFunctionReturn(0);
7622b4ed282SShri Abhyankar     }
7632b4ed282SShri Abhyankar     if (!lssucceed) {
7642b4ed282SShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
765ace3abfcSBarry Smith 	PetscBool ismin;
7662b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
7672b4ed282SShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
7682b4ed282SShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
7692b4ed282SShri Abhyankar         break;
7702b4ed282SShri Abhyankar       }
7712b4ed282SShri Abhyankar     }
7722b4ed282SShri Abhyankar     /* Update function and solution vectors */
7732b4ed282SShri Abhyankar     vi->phinorm = gnorm;
7742b4ed282SShri Abhyankar     vi->merit = 0.5*vi->phinorm*vi->phinorm;
7752b4ed282SShri Abhyankar     ierr = VecCopy(G,vi->phi);CHKERRQ(ierr);
7762b4ed282SShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
7772b4ed282SShri Abhyankar     /* Monitor convergence */
7782b4ed282SShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
7792b4ed282SShri Abhyankar     snes->iter = i+1;
7802b4ed282SShri Abhyankar     snes->norm = vi->phinorm;
7812b4ed282SShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
7822b4ed282SShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
7837a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
7842b4ed282SShri Abhyankar     /* Test for convergence, xnorm = || X || */
7852b4ed282SShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
7862b4ed282SShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
7872b4ed282SShri Abhyankar     if (snes->reason) break;
7882b4ed282SShri Abhyankar   }
7892b4ed282SShri Abhyankar   if (i == maxits) {
7902b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
7912b4ed282SShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
7922b4ed282SShri Abhyankar   }
7939ce7406fSBarry Smith   snes->ops->computefunction = vi->computeuserfunction;
7942b4ed282SShri Abhyankar   PetscFunctionReturn(0);
7952b4ed282SShri Abhyankar }
79669c03620SShri Abhyankar 
79769c03620SShri Abhyankar #undef __FUNCT__
798693ddf92SShri Abhyankar #define __FUNCT__ "SNESVIGetActiveSetIS"
799693ddf92SShri Abhyankar /*
800693ddf92SShri Abhyankar    SNESVIGetActiveSetIndices - Gets the global indices for the active set variables
801693ddf92SShri Abhyankar 
802693ddf92SShri Abhyankar    Input parameter
803693ddf92SShri Abhyankar .  snes - the SNES context
804693ddf92SShri Abhyankar .  X    - the snes solution vector
805693ddf92SShri Abhyankar .  F    - the nonlinear function vector
806693ddf92SShri Abhyankar 
807693ddf92SShri Abhyankar    Output parameter
808693ddf92SShri Abhyankar .  ISact - active set index set
809693ddf92SShri Abhyankar  */
810693ddf92SShri Abhyankar PetscErrorCode SNESVIGetActiveSetIS(SNES snes,Vec X,Vec F,IS* ISact)
811d950fb63SShri Abhyankar {
812d950fb63SShri Abhyankar   PetscErrorCode   ierr;
813693ddf92SShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
814693ddf92SShri Abhyankar   Vec               Xl=vi->xl,Xu=vi->xu;
815693ddf92SShri Abhyankar   const PetscScalar *x,*f,*xl,*xu;
816693ddf92SShri Abhyankar   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
817d950fb63SShri Abhyankar 
818d950fb63SShri Abhyankar   PetscFunctionBegin;
819d950fb63SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
820d950fb63SShri Abhyankar   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
821fe835674SShri Abhyankar   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
822fe835674SShri Abhyankar   ierr = VecGetArrayRead(Xl,&xl);CHKERRQ(ierr);
823fe835674SShri Abhyankar   ierr = VecGetArrayRead(Xu,&xu);CHKERRQ(ierr);
824fe835674SShri Abhyankar   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
825693ddf92SShri Abhyankar   /* Compute active set size */
826d950fb63SShri Abhyankar   for (i=0; i < nlocal;i++) {
82710f5ae6bSBarry 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++;
828d950fb63SShri Abhyankar   }
829693ddf92SShri Abhyankar 
830d950fb63SShri Abhyankar   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
831d950fb63SShri Abhyankar 
832693ddf92SShri Abhyankar   /* Set active set indices */
833d950fb63SShri Abhyankar   for(i=0; i < nlocal; i++) {
83410f5ae6bSBarry 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;
835d950fb63SShri Abhyankar   }
836d950fb63SShri Abhyankar 
837693ddf92SShri Abhyankar    /* Create active set IS */
83862298a1eSBarry Smith   ierr = ISCreateGeneral(((PetscObject)snes)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,ISact);CHKERRQ(ierr);
839d950fb63SShri Abhyankar 
840fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
841fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(Xl,&xl);CHKERRQ(ierr);
842fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(Xu,&xu);CHKERRQ(ierr);
843fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
844d950fb63SShri Abhyankar   PetscFunctionReturn(0);
845d950fb63SShri Abhyankar }
846d950fb63SShri Abhyankar 
847693ddf92SShri Abhyankar #undef __FUNCT__
848693ddf92SShri Abhyankar #define __FUNCT__ "SNESVICreateIndexSets_RS"
849693ddf92SShri Abhyankar PetscErrorCode SNESVICreateIndexSets_RS(SNES snes,Vec X,Vec F,IS* ISact,IS* ISinact)
850693ddf92SShri Abhyankar {
851693ddf92SShri Abhyankar   PetscErrorCode     ierr;
852693ddf92SShri Abhyankar 
853693ddf92SShri Abhyankar   PetscFunctionBegin;
854693ddf92SShri Abhyankar   ierr = SNESVIGetActiveSetIS(snes,X,F,ISact);CHKERRQ(ierr);
855693ddf92SShri Abhyankar   ierr = ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);CHKERRQ(ierr);
856693ddf92SShri Abhyankar   PetscFunctionReturn(0);
857693ddf92SShri Abhyankar }
858693ddf92SShri Abhyankar 
859dbd914b8SShri Abhyankar /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
860dbd914b8SShri Abhyankar #undef __FUNCT__
861fe835674SShri Abhyankar #define __FUNCT__ "SNESVICreateSubVectors"
862fe835674SShri Abhyankar PetscErrorCode SNESVICreateSubVectors(SNES snes,PetscInt n,Vec* newv)
863dbd914b8SShri Abhyankar {
864dbd914b8SShri Abhyankar   PetscErrorCode ierr;
865dbd914b8SShri Abhyankar   Vec            v;
866dbd914b8SShri Abhyankar 
867dbd914b8SShri Abhyankar   PetscFunctionBegin;
868dbd914b8SShri Abhyankar   ierr = VecCreate(((PetscObject)snes)->comm,&v);CHKERRQ(ierr);
869dbd914b8SShri Abhyankar   ierr = VecSetSizes(v,n,PETSC_DECIDE);CHKERRQ(ierr);
870dbd914b8SShri Abhyankar   ierr = VecSetFromOptions(v);CHKERRQ(ierr);
871dbd914b8SShri Abhyankar   *newv = v;
872dbd914b8SShri Abhyankar 
873dbd914b8SShri Abhyankar   PetscFunctionReturn(0);
874dbd914b8SShri Abhyankar }
875dbd914b8SShri Abhyankar 
876732bb160SShri Abhyankar /* Resets the snes PC and KSP when the active set sizes change */
877732bb160SShri Abhyankar #undef __FUNCT__
878732bb160SShri Abhyankar #define __FUNCT__ "SNESVIResetPCandKSP"
879732bb160SShri Abhyankar PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)
880732bb160SShri Abhyankar {
881732bb160SShri Abhyankar   PetscErrorCode         ierr;
882*d0af7cd3SBarry Smith   KSP                    snesksp;
883dbd914b8SShri Abhyankar 
884732bb160SShri Abhyankar   PetscFunctionBegin;
885732bb160SShri Abhyankar   ierr = SNESGetKSP(snes,&snesksp);CHKERRQ(ierr);
886*d0af7cd3SBarry Smith   ierr = KSPReset(snesksp);CHKERRQ(ierr);
887c2efdce3SBarry Smith 
888c2efdce3SBarry Smith   /*
889*d0af7cd3SBarry Smith   KSP                    kspnew;
890*d0af7cd3SBarry Smith   PC                     pcnew;
891*d0af7cd3SBarry Smith   const MatSolverPackage stype;
892*d0af7cd3SBarry Smith 
893c2efdce3SBarry Smith 
894732bb160SShri Abhyankar   ierr = KSPCreate(((PetscObject)snes)->comm,&kspnew);CHKERRQ(ierr);
895732bb160SShri Abhyankar   kspnew->pc_side = snesksp->pc_side;
896732bb160SShri Abhyankar   kspnew->rtol    = snesksp->rtol;
897732bb160SShri Abhyankar   kspnew->abstol    = snesksp->abstol;
898732bb160SShri Abhyankar   kspnew->max_it  = snesksp->max_it;
899732bb160SShri Abhyankar   ierr = KSPSetType(kspnew,((PetscObject)snesksp)->type_name);CHKERRQ(ierr);
900732bb160SShri Abhyankar   ierr = KSPGetPC(kspnew,&pcnew);CHKERRQ(ierr);
901732bb160SShri Abhyankar   ierr = PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);CHKERRQ(ierr);
902732bb160SShri Abhyankar   ierr = PCSetOperators(kspnew->pc,Amat,Pmat,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
903732bb160SShri Abhyankar   ierr = PCFactorGetMatSolverPackage(snesksp->pc,&stype);CHKERRQ(ierr);
904732bb160SShri Abhyankar   ierr = PCFactorSetMatSolverPackage(kspnew->pc,stype);CHKERRQ(ierr);
9056bf464f9SBarry Smith   ierr = KSPDestroy(&snesksp);CHKERRQ(ierr);
906732bb160SShri Abhyankar   snes->ksp = kspnew;
907732bb160SShri Abhyankar   ierr = PetscLogObjectParent(snes,kspnew);CHKERRQ(ierr);
908*d0af7cd3SBarry Smith    ierr = KSPSetFromOptions(kspnew);CHKERRQ(ierr);*/
909732bb160SShri Abhyankar   PetscFunctionReturn(0);
910732bb160SShri Abhyankar }
91169c03620SShri Abhyankar 
91269c03620SShri Abhyankar 
913fe835674SShri Abhyankar #undef __FUNCT__
914fe835674SShri Abhyankar #define __FUNCT__ "SNESVIComputeInactiveSetFnorm"
91510f5ae6bSBarry Smith PetscErrorCode SNESVIComputeInactiveSetFnorm(SNES snes,Vec F,Vec X,PetscReal *fnorm)
916fe835674SShri Abhyankar {
917fe835674SShri Abhyankar   PetscErrorCode    ierr;
918fe835674SShri Abhyankar   SNES_VI           *vi = (SNES_VI*)snes->data;
919fe835674SShri Abhyankar   const PetscScalar *x,*xl,*xu,*f;
920fe835674SShri Abhyankar   PetscInt          i,n;
921fe835674SShri Abhyankar   PetscReal         rnorm;
922fe835674SShri Abhyankar 
923fe835674SShri Abhyankar   PetscFunctionBegin;
924fe835674SShri Abhyankar   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
925fe835674SShri Abhyankar   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
926fe835674SShri Abhyankar   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
927fe835674SShri Abhyankar   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
928fe835674SShri Abhyankar   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
929fe835674SShri Abhyankar   rnorm = 0.0;
930fe835674SShri Abhyankar   for (i=0; i<n; i++) {
93110f5ae6bSBarry 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]);
932fe835674SShri Abhyankar   }
933fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
934fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
935fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
936fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
937d9822059SBarry Smith   ierr = MPI_Allreduce(&rnorm,fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
938fe835674SShri Abhyankar   *fnorm = sqrt(*fnorm);
939fe835674SShri Abhyankar   PetscFunctionReturn(0);
940fe835674SShri Abhyankar }
941fe835674SShri Abhyankar 
942fe835674SShri Abhyankar /* Variational Inequality solver using reduce space method. No semismooth algorithm is
943c2efdce3SBarry Smith    implemented in this algorithm. It basically identifies the active constraints and does
944c2efdce3SBarry Smith    a linear solve on the other variables (those not associated with the active constraints). */
945d950fb63SShri Abhyankar #undef __FUNCT__
946d950fb63SShri Abhyankar #define __FUNCT__ "SNESSolveVI_RS"
947d950fb63SShri Abhyankar PetscErrorCode SNESSolveVI_RS(SNES snes)
948d950fb63SShri Abhyankar {
949d950fb63SShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
950d950fb63SShri Abhyankar   PetscErrorCode    ierr;
951abcba341SShri Abhyankar   PetscInt          maxits,i,lits;
952d950fb63SShri Abhyankar   PetscBool         lssucceed;
953d950fb63SShri Abhyankar   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
954fe835674SShri Abhyankar   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
955d950fb63SShri Abhyankar   Vec                Y,X,F,G,W;
956d950fb63SShri Abhyankar   KSPConvergedReason kspreason;
957d950fb63SShri Abhyankar 
958d950fb63SShri Abhyankar   PetscFunctionBegin;
959d950fb63SShri Abhyankar   snes->numFailures            = 0;
960d950fb63SShri Abhyankar   snes->numLinearSolveFailures = 0;
961d950fb63SShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
962d950fb63SShri Abhyankar 
963d950fb63SShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
964d950fb63SShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
965d950fb63SShri Abhyankar   F		= snes->vec_func;	/* residual vector */
966d950fb63SShri Abhyankar   Y		= snes->work[0];	/* work vectors */
967d950fb63SShri Abhyankar   G		= snes->work[1];
968d950fb63SShri Abhyankar   W		= snes->work[2];
969d950fb63SShri Abhyankar 
970d950fb63SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
971d950fb63SShri Abhyankar   snes->iter = 0;
972d950fb63SShri Abhyankar   snes->norm = 0.0;
973d950fb63SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
974d950fb63SShri Abhyankar 
9757fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
976fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
977d950fb63SShri Abhyankar   if (snes->domainerror) {
978d950fb63SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
979d950fb63SShri Abhyankar     PetscFunctionReturn(0);
980d950fb63SShri Abhyankar   }
981fe835674SShri Abhyankar   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
982d950fb63SShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
983d950fb63SShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
98462cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
985d950fb63SShri Abhyankar 
986d950fb63SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
987fe835674SShri Abhyankar   snes->norm = fnorm;
988d950fb63SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
989fe835674SShri Abhyankar   SNESLogConvHistory(snes,fnorm,0);
9907a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
991d950fb63SShri Abhyankar 
992d950fb63SShri Abhyankar   /* set parameter for default relative tolerance convergence test */
993fe835674SShri Abhyankar   snes->ttol = fnorm*snes->rtol;
994d950fb63SShri Abhyankar   /* test convergence */
995fe835674SShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
996d950fb63SShri Abhyankar   if (snes->reason) PetscFunctionReturn(0);
997d950fb63SShri Abhyankar 
998d950fb63SShri Abhyankar   for (i=0; i<maxits; i++) {
999d950fb63SShri Abhyankar 
1000d950fb63SShri Abhyankar     IS         IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1001d950fb63SShri Abhyankar     VecScatter scat_act,scat_inact;
1002abcba341SShri Abhyankar     PetscInt   nis_act,nis_inact;
1003fe835674SShri Abhyankar     Vec        Y_act,Y_inact,F_inact;
1004d950fb63SShri Abhyankar     Mat        jac_inact_inact,prejac_inact_inact;
100562298a1eSBarry Smith     IS         keptrows;
1006abcba341SShri Abhyankar     PetscBool  isequal;
1007d950fb63SShri Abhyankar 
1008d950fb63SShri Abhyankar     /* Call general purpose update function */
1009d950fb63SShri Abhyankar     if (snes->ops->update) {
1010d950fb63SShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
1011d950fb63SShri Abhyankar     }
1012d950fb63SShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
101362298a1eSBarry Smith 
1014d950fb63SShri Abhyankar     /* Create active and inactive index sets */
1015693ddf92SShri Abhyankar     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
1016d950fb63SShri Abhyankar 
1017abcba341SShri Abhyankar     /* Create inactive set submatrix */
101862298a1eSBarry Smith     ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
1019b3a44c85SBarry Smith     ierr = MatFindNonzeroRows(jac_inact_inact,&keptrows);CHKERRQ(ierr);
102062298a1eSBarry Smith     if (keptrows) {
102162298a1eSBarry Smith       PetscInt       cnt,*nrows,k;
102262298a1eSBarry Smith       const PetscInt *krows,*inact;
102327d4218bSShri Abhyankar       PetscInt       rstart=jac_inact_inact->rmap->rstart;
102462298a1eSBarry Smith 
10256bf464f9SBarry Smith       ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
10266bf464f9SBarry Smith       ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
102762298a1eSBarry Smith 
102862298a1eSBarry Smith       ierr = ISGetLocalSize(keptrows,&cnt);CHKERRQ(ierr);
102962298a1eSBarry Smith       ierr = ISGetIndices(keptrows,&krows);CHKERRQ(ierr);
103062298a1eSBarry Smith       ierr = ISGetIndices(IS_inact,&inact);CHKERRQ(ierr);
103162298a1eSBarry Smith       ierr = PetscMalloc(cnt*sizeof(PetscInt),&nrows);CHKERRQ(ierr);
103262298a1eSBarry Smith       for (k=0; k<cnt; k++) {
103327d4218bSShri Abhyankar         nrows[k] = inact[krows[k]-rstart];
103462298a1eSBarry Smith       }
103562298a1eSBarry Smith       ierr = ISRestoreIndices(keptrows,&krows);CHKERRQ(ierr);
103662298a1eSBarry Smith       ierr = ISRestoreIndices(IS_inact,&inact);CHKERRQ(ierr);
10376bf464f9SBarry Smith       ierr = ISDestroy(&keptrows);CHKERRQ(ierr);
10386bf464f9SBarry Smith       ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
103962298a1eSBarry Smith 
104027d4218bSShri Abhyankar       ierr = ISCreateGeneral(PETSC_COMM_WORLD,cnt,nrows,PETSC_OWN_POINTER,&IS_inact);CHKERRQ(ierr);
104127d4218bSShri Abhyankar       ierr = ISComplement(IS_inact,F->map->rstart,F->map->rend,&IS_act);CHKERRQ(ierr);
104262298a1eSBarry Smith       ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
104362298a1eSBarry Smith     }
104462298a1eSBarry Smith 
1045d950fb63SShri Abhyankar     /* Get sizes of active and inactive sets */
1046d950fb63SShri Abhyankar     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
1047d950fb63SShri Abhyankar     ierr = ISGetLocalSize(IS_inact,&nis_inact);CHKERRQ(ierr);
1048d950fb63SShri Abhyankar 
1049d950fb63SShri Abhyankar     /* Create active and inactive set vectors */
1050fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_inact,&F_inact);CHKERRQ(ierr);
1051fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_act,&Y_act);CHKERRQ(ierr);
1052fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_inact,&Y_inact);CHKERRQ(ierr);
1053d950fb63SShri Abhyankar 
1054d950fb63SShri Abhyankar     /* Create scatter contexts */
1055d950fb63SShri Abhyankar     ierr = VecScatterCreate(Y,IS_act,Y_act,PETSC_NULL,&scat_act);CHKERRQ(ierr);
1056d950fb63SShri Abhyankar     ierr = VecScatterCreate(Y,IS_inact,Y_inact,PETSC_NULL,&scat_inact);CHKERRQ(ierr);
1057d950fb63SShri Abhyankar 
1058d950fb63SShri Abhyankar     /* Do a vec scatter to active and inactive set vectors */
1059fe835674SShri Abhyankar     ierr = VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1060fe835674SShri Abhyankar     ierr = VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1061d950fb63SShri Abhyankar 
1062d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1063d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1064d950fb63SShri Abhyankar 
1065d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1066d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1067d950fb63SShri Abhyankar 
1068d950fb63SShri Abhyankar     /* Active set direction = 0 */
1069d950fb63SShri Abhyankar     ierr = VecSet(Y_act,0);CHKERRQ(ierr);
1070d950fb63SShri Abhyankar     if (snes->jacobian != snes->jacobian_pre) {
1071d950fb63SShri Abhyankar       ierr = MatGetSubMatrix(snes->jacobian_pre,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);CHKERRQ(ierr);
1072d950fb63SShri Abhyankar     } else prejac_inact_inact = jac_inact_inact;
1073d950fb63SShri Abhyankar 
1074abcba341SShri Abhyankar     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
1075abcba341SShri Abhyankar     if (!isequal) {
1076732bb160SShri Abhyankar       ierr = SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr);
1077d950fb63SShri Abhyankar     }
1078d950fb63SShri Abhyankar 
107913e0d083SBarry Smith     /*      ierr = ISView(IS_inact,0);CHKERRQ(ierr); */
108013e0d083SBarry Smith     /*      ierr = ISView(IS_act,0);CHKERRQ(ierr);*/
108113e0d083SBarry Smith     /*      ierr = MatView(snes->jacobian_pre,0); */
108213e0d083SBarry Smith 
1083d950fb63SShri Abhyankar     ierr = KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact,flg);CHKERRQ(ierr);
108413e0d083SBarry Smith     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
108513e0d083SBarry Smith     {
108613e0d083SBarry Smith       PC        pc;
108713e0d083SBarry Smith       PetscBool flg;
108813e0d083SBarry Smith       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
108913e0d083SBarry Smith       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
109013e0d083SBarry Smith       if (flg) {
109113e0d083SBarry Smith         KSP      *subksps;
109213e0d083SBarry Smith         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
109313e0d083SBarry Smith         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
109413e0d083SBarry Smith         ierr = PetscFree(subksps);CHKERRQ(ierr);
109513e0d083SBarry Smith         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
109613e0d083SBarry Smith         if (flg) {
109713e0d083SBarry Smith           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
109813e0d083SBarry Smith           const PetscInt *ii;
109913e0d083SBarry Smith 
110013e0d083SBarry Smith           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
110113e0d083SBarry Smith           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
110213e0d083SBarry Smith           for (j=0; j<n; j++) {
110313e0d083SBarry Smith             if (ii[j] < N) cnts[0]++;
110413e0d083SBarry Smith             else if (ii[j] < 2*N) cnts[1]++;
110513e0d083SBarry Smith             else if (ii[j] < 3*N) cnts[2]++;
110613e0d083SBarry Smith           }
110713e0d083SBarry Smith           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
110813e0d083SBarry Smith 
110913e0d083SBarry Smith           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
111013e0d083SBarry Smith         }
111113e0d083SBarry Smith       }
111213e0d083SBarry Smith     }
111313e0d083SBarry Smith 
1114fe835674SShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,F_inact,Y_inact);CHKERRQ(ierr);
1115d950fb63SShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
1116d950fb63SShri Abhyankar     if (kspreason < 0) {
1117d950fb63SShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
1118d950fb63SShri 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);
1119d950fb63SShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
1120d950fb63SShri Abhyankar         break;
1121d950fb63SShri Abhyankar       }
1122d950fb63SShri Abhyankar      }
1123d950fb63SShri Abhyankar 
1124d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1125d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1126d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1127d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1128d950fb63SShri Abhyankar 
11296bf464f9SBarry Smith     ierr = VecDestroy(&F_inact);CHKERRQ(ierr);
11306bf464f9SBarry Smith     ierr = VecDestroy(&Y_act);CHKERRQ(ierr);
11316bf464f9SBarry Smith     ierr = VecDestroy(&Y_inact);CHKERRQ(ierr);
11326bf464f9SBarry Smith     ierr = VecScatterDestroy(&scat_act);CHKERRQ(ierr);
11336bf464f9SBarry Smith     ierr = VecScatterDestroy(&scat_inact);CHKERRQ(ierr);
11346bf464f9SBarry Smith     ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
1135abcba341SShri Abhyankar     if (!isequal) {
11366bf464f9SBarry Smith       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
1137abcba341SShri Abhyankar       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
1138abcba341SShri Abhyankar     }
11396bf464f9SBarry Smith     ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
11406bf464f9SBarry Smith     ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
1141d950fb63SShri Abhyankar     if (snes->jacobian != snes->jacobian_pre) {
11426bf464f9SBarry Smith       ierr = MatDestroy(&prejac_inact_inact);CHKERRQ(ierr);
1143d950fb63SShri Abhyankar     }
1144d950fb63SShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
1145d950fb63SShri Abhyankar     snes->linear_its += lits;
1146d950fb63SShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
1147d950fb63SShri Abhyankar     /*
1148d950fb63SShri Abhyankar     if (vi->precheckstep) {
1149d950fb63SShri Abhyankar       PetscBool changed_y = PETSC_FALSE;
1150d950fb63SShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
1151d950fb63SShri Abhyankar     }
1152d950fb63SShri Abhyankar 
1153d950fb63SShri Abhyankar     if (PetscLogPrintInfo){
1154d950fb63SShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
1155d950fb63SShri Abhyankar     }
1156d950fb63SShri Abhyankar     */
1157d950fb63SShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
1158d950fb63SShri Abhyankar          Y <- X - lambda*Y
1159d950fb63SShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
1160d950fb63SShri Abhyankar     */
1161d950fb63SShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
1162fe835674SShri Abhyankar     ynorm = 1; gnorm = fnorm;
1163fe835674SShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
1164fe835674SShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
11652b4ed282SShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
11662b4ed282SShri Abhyankar     if (snes->domainerror) {
11672b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
11682b4ed282SShri Abhyankar       PetscFunctionReturn(0);
11692b4ed282SShri Abhyankar     }
11702b4ed282SShri Abhyankar     if (!lssucceed) {
11712b4ed282SShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
11722b4ed282SShri Abhyankar 	PetscBool ismin;
11732b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
11742b4ed282SShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
11752b4ed282SShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
11762b4ed282SShri Abhyankar         break;
11772b4ed282SShri Abhyankar       }
11782b4ed282SShri Abhyankar     }
11792b4ed282SShri Abhyankar     /* Update function and solution vectors */
1180fe835674SShri Abhyankar     fnorm = gnorm;
1181fe835674SShri Abhyankar     ierr = VecCopy(G,F);CHKERRQ(ierr);
11822b4ed282SShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
11832b4ed282SShri Abhyankar     /* Monitor convergence */
11842b4ed282SShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
11852b4ed282SShri Abhyankar     snes->iter = i+1;
1186fe835674SShri Abhyankar     snes->norm = fnorm;
11872b4ed282SShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
11882b4ed282SShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
11897a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
11902b4ed282SShri Abhyankar     /* Test for convergence, xnorm = || X || */
11912b4ed282SShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
1192fe835674SShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
11932b4ed282SShri Abhyankar     if (snes->reason) break;
11942b4ed282SShri Abhyankar   }
11952b4ed282SShri Abhyankar   if (i == maxits) {
11962b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
11972b4ed282SShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
11982b4ed282SShri Abhyankar   }
11992b4ed282SShri Abhyankar   PetscFunctionReturn(0);
12002b4ed282SShri Abhyankar }
12012b4ed282SShri Abhyankar 
12022f63a38cSShri Abhyankar #undef __FUNCT__
1203720c9a41SShri Abhyankar #define __FUNCT__ "SNESVISetRedundancyCheck"
1204cb5fe31bSShri Abhyankar PetscErrorCode SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (*func)(SNES,IS,IS*,void*),void *ctx)
12052f63a38cSShri Abhyankar {
12062f63a38cSShri Abhyankar   SNES_VI         *vi = (SNES_VI*)snes->data;
12072f63a38cSShri Abhyankar 
12082f63a38cSShri Abhyankar   PetscFunctionBegin;
12092f63a38cSShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
12102f63a38cSShri Abhyankar   vi->checkredundancy = func;
1211cb5fe31bSShri Abhyankar   vi->ctxP            = ctx;
12122f63a38cSShri Abhyankar   PetscFunctionReturn(0);
12132f63a38cSShri Abhyankar }
12142f63a38cSShri Abhyankar 
1215ff596062SShri Abhyankar #if defined(PETSC_HAVE_MATLAB_ENGINE)
1216ff596062SShri Abhyankar #include <engine.h>
1217ff596062SShri Abhyankar #include <mex.h>
1218cb5fe31bSShri Abhyankar typedef struct {char *funcname; mxArray *ctx;} SNESMatlabContext;
1219ff596062SShri Abhyankar 
1220ff596062SShri Abhyankar #undef __FUNCT__
1221ff596062SShri Abhyankar #define __FUNCT__ "SNESVIRedundancyCheck_Matlab"
1222ff596062SShri Abhyankar PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS* is_redact,void* ctx)
1223ff596062SShri Abhyankar {
1224ff596062SShri Abhyankar   PetscErrorCode      ierr;
1225cb5fe31bSShri Abhyankar   SNESMatlabContext   *sctx = (SNESMatlabContext*)ctx;
1226cb5fe31bSShri Abhyankar   int                 nlhs = 1, nrhs = 5;
1227cb5fe31bSShri Abhyankar   mxArray             *plhs[1], *prhs[5];
1228cb5fe31bSShri Abhyankar   long long int       l1 = 0, l2 = 0, ls = 0;
1229fcb1c9afSShri Abhyankar   PetscInt            *indices=PETSC_NULL;
1230ff596062SShri Abhyankar 
1231ff596062SShri Abhyankar   PetscFunctionBegin;
1232ff596062SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1233ff596062SShri Abhyankar   PetscValidHeaderSpecific(is_act,IS_CLASSID,2);
1234ff596062SShri Abhyankar   PetscValidPointer(is_redact,3);
1235ff596062SShri Abhyankar   PetscCheckSameComm(snes,1,is_act,2);
1236ff596062SShri Abhyankar 
123709db5ad8SShri Abhyankar   /* Create IS for reduced active set of size 0, its size and indices will
123809db5ad8SShri Abhyankar    bet set by the Matlab function */
1239fcb1c9afSShri Abhyankar   ierr = ISCreateGeneral(((PetscObject)snes)->comm,0,indices,PETSC_OWN_POINTER,is_redact);CHKERRQ(ierr);
1240cb5fe31bSShri Abhyankar   /* call Matlab function in ctx */
1241ff596062SShri Abhyankar   ierr = PetscMemcpy(&ls,&snes,sizeof(snes));CHKERRQ(ierr);
1242ff596062SShri Abhyankar   ierr = PetscMemcpy(&l1,&is_act,sizeof(is_act));CHKERRQ(ierr);
1243cb5fe31bSShri Abhyankar   ierr = PetscMemcpy(&l2,is_redact,sizeof(is_act));CHKERRQ(ierr);
1244ff596062SShri Abhyankar   prhs[0] = mxCreateDoubleScalar((double)ls);
1245ff596062SShri Abhyankar   prhs[1] = mxCreateDoubleScalar((double)l1);
1246cb5fe31bSShri Abhyankar   prhs[2] = mxCreateDoubleScalar((double)l2);
1247cb5fe31bSShri Abhyankar   prhs[3] = mxCreateString(sctx->funcname);
1248cb5fe31bSShri Abhyankar   prhs[4] = sctx->ctx;
1249ff596062SShri Abhyankar   ierr    = mexCallMATLAB(nlhs,plhs,nrhs,prhs,"PetscSNESVIRedundancyCheckInternal");CHKERRQ(ierr);
1250ff596062SShri Abhyankar   ierr    = mxGetScalar(plhs[0]);CHKERRQ(ierr);
1251ff596062SShri Abhyankar   mxDestroyArray(prhs[0]);
1252ff596062SShri Abhyankar   mxDestroyArray(prhs[1]);
1253ff596062SShri Abhyankar   mxDestroyArray(prhs[2]);
1254ff596062SShri Abhyankar   mxDestroyArray(prhs[3]);
1255ff596062SShri Abhyankar   mxDestroyArray(plhs[0]);
1256ff596062SShri Abhyankar   PetscFunctionReturn(0);
1257ff596062SShri Abhyankar }
1258ff596062SShri Abhyankar 
1259ff596062SShri Abhyankar #undef __FUNCT__
1260ff596062SShri Abhyankar #define __FUNCT__ "SNESVISetRedundancyCheckMatlab"
1261ff596062SShri Abhyankar PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes,const char* func,mxArray* ctx)
1262ff596062SShri Abhyankar {
1263ff596062SShri Abhyankar   PetscErrorCode      ierr;
1264cb5fe31bSShri Abhyankar   SNESMatlabContext   *sctx;
1265ff596062SShri Abhyankar 
1266ff596062SShri Abhyankar   PetscFunctionBegin;
1267ff596062SShri Abhyankar   /* currently sctx is memory bleed */
1268cb5fe31bSShri Abhyankar   ierr = PetscMalloc(sizeof(SNESMatlabContext),&sctx);CHKERRQ(ierr);
1269ff596062SShri Abhyankar   ierr = PetscStrallocpy(func,&sctx->funcname);CHKERRQ(ierr);
1270ff596062SShri Abhyankar   sctx->ctx = mxDuplicateArray(ctx);
1271cb5fe31bSShri Abhyankar   ierr = SNESVISetRedundancyCheck(snes,SNESVIRedundancyCheck_Matlab,sctx);CHKERRQ(ierr);
1272ff596062SShri Abhyankar   PetscFunctionReturn(0);
1273ff596062SShri Abhyankar }
1274ff596062SShri Abhyankar 
1275ff596062SShri Abhyankar #endif
1276ff596062SShri Abhyankar 
1277ff596062SShri Abhyankar 
12782f63a38cSShri Abhyankar /* Variational Inequality solver using augmented space method. It does the opposite of the
12792f63a38cSShri Abhyankar    reduced space method i.e. it identifies the active set variables and instead of discarding
1280720c9a41SShri Abhyankar    them it augments the original system by introducing additional equality
128156a221efSShri Abhyankar    constraint equations for active set variables. The user can optionally provide an IS for
128256a221efSShri Abhyankar    a subset of 'redundant' active set variables which will treated as free variables.
12832f63a38cSShri Abhyankar    Specific implementation for Allen-Cahn problem
12842f63a38cSShri Abhyankar */
12852f63a38cSShri Abhyankar #undef __FUNCT__
1286b350b9c9SBarry Smith #define __FUNCT__ "SNESSolveVI_RSAUG"
1287b350b9c9SBarry Smith PetscErrorCode SNESSolveVI_RSAUG(SNES snes)
12882f63a38cSShri Abhyankar {
12892f63a38cSShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
12902f63a38cSShri Abhyankar   PetscErrorCode    ierr;
12912f63a38cSShri Abhyankar   PetscInt          maxits,i,lits;
12922f63a38cSShri Abhyankar   PetscBool         lssucceed;
12932f63a38cSShri Abhyankar   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
12942f63a38cSShri Abhyankar   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
12952f63a38cSShri Abhyankar   Vec                Y,X,F,G,W;
12962f63a38cSShri Abhyankar   KSPConvergedReason kspreason;
12972f63a38cSShri Abhyankar 
12982f63a38cSShri Abhyankar   PetscFunctionBegin;
12992f63a38cSShri Abhyankar   snes->numFailures            = 0;
13002f63a38cSShri Abhyankar   snes->numLinearSolveFailures = 0;
13012f63a38cSShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
13022f63a38cSShri Abhyankar 
13032f63a38cSShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
13042f63a38cSShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
13052f63a38cSShri Abhyankar   F		= snes->vec_func;	/* residual vector */
13062f63a38cSShri Abhyankar   Y		= snes->work[0];	/* work vectors */
13072f63a38cSShri Abhyankar   G		= snes->work[1];
13082f63a38cSShri Abhyankar   W		= snes->work[2];
13092f63a38cSShri Abhyankar 
13102f63a38cSShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
13112f63a38cSShri Abhyankar   snes->iter = 0;
13122f63a38cSShri Abhyankar   snes->norm = 0.0;
13132f63a38cSShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
13142f63a38cSShri Abhyankar 
13152f63a38cSShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
13162f63a38cSShri Abhyankar   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
13172f63a38cSShri Abhyankar   if (snes->domainerror) {
13182f63a38cSShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
13192f63a38cSShri Abhyankar     PetscFunctionReturn(0);
13202f63a38cSShri Abhyankar   }
13212f63a38cSShri Abhyankar   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
13222f63a38cSShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
13232f63a38cSShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
132462cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
13252f63a38cSShri Abhyankar 
13262f63a38cSShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
13272f63a38cSShri Abhyankar   snes->norm = fnorm;
13282f63a38cSShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
13292f63a38cSShri Abhyankar   SNESLogConvHistory(snes,fnorm,0);
13307a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
13312f63a38cSShri Abhyankar 
13322f63a38cSShri Abhyankar   /* set parameter for default relative tolerance convergence test */
13332f63a38cSShri Abhyankar   snes->ttol = fnorm*snes->rtol;
13342f63a38cSShri Abhyankar   /* test convergence */
13352f63a38cSShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
13362f63a38cSShri Abhyankar   if (snes->reason) PetscFunctionReturn(0);
13372f63a38cSShri Abhyankar 
13382f63a38cSShri Abhyankar   for (i=0; i<maxits; i++) {
13392f63a38cSShri Abhyankar     IS             IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1340cb5fe31bSShri Abhyankar     IS             IS_redact; /* redundant active set */
134156a221efSShri Abhyankar     Mat            J_aug,Jpre_aug;
134256a221efSShri Abhyankar     Vec            F_aug,Y_aug;
134356a221efSShri Abhyankar     PetscInt       nis_redact,nis_act;
134456a221efSShri Abhyankar     const PetscInt *idx_redact,*idx_act;
134556a221efSShri Abhyankar     PetscInt       k;
134663ee972cSSatish Balay     PetscInt       *idx_actkept=PETSC_NULL,nkept=0; /* list of kept active set */
134756a221efSShri Abhyankar     PetscScalar    *f,*f2;
13482f63a38cSShri Abhyankar     PetscBool      isequal;
134956a221efSShri Abhyankar     PetscInt       i1=0,j1=0;
13502f63a38cSShri Abhyankar 
13512f63a38cSShri Abhyankar     /* Call general purpose update function */
13522f63a38cSShri Abhyankar     if (snes->ops->update) {
13532f63a38cSShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
13542f63a38cSShri Abhyankar     }
13552f63a38cSShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
13562f63a38cSShri Abhyankar 
13572f63a38cSShri Abhyankar     /* Create active and inactive index sets */
13582f63a38cSShri Abhyankar     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
13592f63a38cSShri Abhyankar 
136056a221efSShri Abhyankar     /* Get local active set size */
13612f63a38cSShri Abhyankar     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
136256a221efSShri Abhyankar     if (nis_act) {
1363e63076c7SBarry Smith       ierr = ISGetIndices(IS_act,&idx_act);CHKERRQ(ierr);
1364e63076c7SBarry Smith       IS_redact  = PETSC_NULL;
136556a221efSShri Abhyankar       if(vi->checkredundancy) {
1366cb5fe31bSShri Abhyankar 	(*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);
136756a221efSShri Abhyankar       }
13682f63a38cSShri Abhyankar 
136956a221efSShri Abhyankar       if(!IS_redact) {
137056a221efSShri Abhyankar 	/* User called checkredundancy function but didn't create IS_redact because
137156a221efSShri Abhyankar            there were no redundant active set variables */
137256a221efSShri Abhyankar 	/* Copy over all active set indices to the list */
137356a221efSShri Abhyankar 	ierr = PetscMalloc(nis_act*sizeof(PetscInt),&idx_actkept);CHKERRQ(ierr);
137456a221efSShri Abhyankar 	for(k=0;k < nis_act;k++) idx_actkept[k] = idx_act[k];
137556a221efSShri Abhyankar 	nkept = nis_act;
137656a221efSShri Abhyankar       } else {
137756a221efSShri Abhyankar 	ierr = ISGetLocalSize(IS_redact,&nis_redact);CHKERRQ(ierr);
137856a221efSShri Abhyankar 	ierr = PetscMalloc((nis_act-nis_redact)*sizeof(PetscInt),&idx_actkept);CHKERRQ(ierr);
13792f63a38cSShri Abhyankar 
138056a221efSShri Abhyankar 	/* Create reduced active set list */
138156a221efSShri Abhyankar 	ierr = ISGetIndices(IS_act,&idx_act);CHKERRQ(ierr);
138256a221efSShri Abhyankar 	ierr = ISGetIndices(IS_redact,&idx_redact);CHKERRQ(ierr);
1383cb5fe31bSShri Abhyankar 	j1 = 0;nkept = 0;
138456a221efSShri Abhyankar 	for(k=0;k<nis_act;k++) {
138556a221efSShri Abhyankar 	  if(j1 < nis_redact && idx_act[k] == idx_redact[j1]) j1++;
138656a221efSShri Abhyankar 	  else idx_actkept[nkept++] = idx_act[k];
138756a221efSShri Abhyankar 	}
138856a221efSShri Abhyankar 	ierr = ISRestoreIndices(IS_act,&idx_act);CHKERRQ(ierr);
138956a221efSShri Abhyankar 	ierr = ISRestoreIndices(IS_redact,&idx_redact);CHKERRQ(ierr);
1390cb5fe31bSShri Abhyankar 
1391cb5fe31bSShri Abhyankar         ierr = ISDestroy(&IS_redact);CHKERRQ(ierr);
139256a221efSShri Abhyankar       }
13932f63a38cSShri Abhyankar 
139456a221efSShri Abhyankar       /* Create augmented F and Y */
139556a221efSShri Abhyankar       ierr = VecCreate(((PetscObject)snes)->comm,&F_aug);CHKERRQ(ierr);
139656a221efSShri Abhyankar       ierr = VecSetSizes(F_aug,F->map->n+nkept,PETSC_DECIDE);CHKERRQ(ierr);
139756a221efSShri Abhyankar       ierr = VecSetFromOptions(F_aug);CHKERRQ(ierr);
139856a221efSShri Abhyankar       ierr = VecDuplicate(F_aug,&Y_aug);CHKERRQ(ierr);
13992f63a38cSShri Abhyankar 
140056a221efSShri Abhyankar       /* Copy over F to F_aug in the first n locations */
140156a221efSShri Abhyankar       ierr = VecGetArray(F,&f);CHKERRQ(ierr);
140256a221efSShri Abhyankar       ierr = VecGetArray(F_aug,&f2);CHKERRQ(ierr);
140356a221efSShri Abhyankar       ierr = PetscMemcpy(f2,f,F->map->n*sizeof(PetscScalar));CHKERRQ(ierr);
140456a221efSShri Abhyankar       ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
140556a221efSShri Abhyankar       ierr = VecRestoreArray(F_aug,&f2);CHKERRQ(ierr);
14062f63a38cSShri Abhyankar 
140756a221efSShri Abhyankar       /* Create the augmented jacobian matrix */
140856a221efSShri Abhyankar       ierr = MatCreate(((PetscObject)snes)->comm,&J_aug);CHKERRQ(ierr);
140956a221efSShri Abhyankar       ierr = MatSetSizes(J_aug,X->map->n+nkept,X->map->n+nkept,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
141056a221efSShri Abhyankar       ierr = MatSetFromOptions(J_aug);CHKERRQ(ierr);
14112f63a38cSShri Abhyankar 
141256a221efSShri Abhyankar 
14139521db3cSSatish Balay       { /* local vars */
1414493a4f3dSShri Abhyankar       /* Preallocate augmented matrix and set values in it...Doing only sequential case first*/
141556a221efSShri Abhyankar       PetscInt          ncols;
141656a221efSShri Abhyankar       const PetscInt    *cols;
141756a221efSShri Abhyankar       const PetscScalar *vals;
14182969f145SShri Abhyankar       PetscScalar        value[2];
14192969f145SShri Abhyankar       PetscInt           row,col[2];
1420493a4f3dSShri Abhyankar       PetscInt           *d_nnz;
14212969f145SShri Abhyankar       value[0] = 1.0; value[1] = 0.0;
1422493a4f3dSShri Abhyankar       ierr = PetscMalloc((X->map->n+nkept)*sizeof(PetscInt),&d_nnz);CHKERRQ(ierr);
1423493a4f3dSShri Abhyankar       ierr = PetscMemzero(d_nnz,(X->map->n+nkept)*sizeof(PetscInt));CHKERRQ(ierr);
1424493a4f3dSShri Abhyankar       for(row=0;row<snes->jacobian->rmap->n;row++) {
1425493a4f3dSShri Abhyankar         ierr = MatGetRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
1426493a4f3dSShri Abhyankar         d_nnz[row] += ncols;
1427493a4f3dSShri Abhyankar         ierr = MatRestoreRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
1428493a4f3dSShri Abhyankar       }
1429493a4f3dSShri Abhyankar 
1430493a4f3dSShri Abhyankar       for(k=0;k<nkept;k++) {
1431493a4f3dSShri Abhyankar         d_nnz[idx_actkept[k]] += 1;
14322969f145SShri Abhyankar         d_nnz[snes->jacobian->rmap->n+k] += 2;
1433493a4f3dSShri Abhyankar       }
1434493a4f3dSShri Abhyankar       ierr = MatSeqAIJSetPreallocation(J_aug,PETSC_NULL,d_nnz);CHKERRQ(ierr);
1435493a4f3dSShri Abhyankar 
1436493a4f3dSShri Abhyankar       ierr = PetscFree(d_nnz);CHKERRQ(ierr);
143756a221efSShri Abhyankar 
143856a221efSShri Abhyankar       /* Set the original jacobian matrix in J_aug */
143956a221efSShri Abhyankar       for(row=0;row<snes->jacobian->rmap->n;row++) {
144056a221efSShri Abhyankar 	ierr = MatGetRow(snes->jacobian,row,&ncols,&cols,&vals);CHKERRQ(ierr);
144156a221efSShri Abhyankar 	ierr = MatSetValues(J_aug,1,&row,ncols,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
144256a221efSShri Abhyankar 	ierr = MatRestoreRow(snes->jacobian,row,&ncols,&cols,&vals);CHKERRQ(ierr);
144356a221efSShri Abhyankar       }
144456a221efSShri Abhyankar       /* Add the augmented part */
144556a221efSShri Abhyankar       for(k=0;k<nkept;k++) {
14462969f145SShri Abhyankar 	row = snes->jacobian->rmap->n+k;
14472969f145SShri Abhyankar 	col[0] = idx_actkept[k]; col[1] = snes->jacobian->rmap->n+k;
14482969f145SShri Abhyankar 	ierr = MatSetValues(J_aug,1,&row,1,col,value,INSERT_VALUES);CHKERRQ(ierr);
14492969f145SShri Abhyankar 	ierr = MatSetValues(J_aug,1,&col[0],1,&row,&value[0],INSERT_VALUES);CHKERRQ(ierr);
145056a221efSShri Abhyankar       }
145156a221efSShri Abhyankar       ierr = MatAssemblyBegin(J_aug,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
145256a221efSShri Abhyankar       ierr = MatAssemblyEnd(J_aug,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
145356a221efSShri Abhyankar       /* Only considering prejac = jac for now */
145456a221efSShri Abhyankar       Jpre_aug = J_aug;
14559521db3cSSatish Balay       } /* local vars*/
1456e63076c7SBarry Smith       ierr = ISRestoreIndices(IS_act,&idx_act);CHKERRQ(ierr);
1457e63076c7SBarry Smith       ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
145856a221efSShri Abhyankar     } else {
145956a221efSShri Abhyankar       F_aug = F; J_aug = snes->jacobian; Y_aug = Y; Jpre_aug = snes->jacobian_pre;
146056a221efSShri Abhyankar     }
14612f63a38cSShri Abhyankar 
14622f63a38cSShri Abhyankar     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
14632f63a38cSShri Abhyankar     if (!isequal) {
146456a221efSShri Abhyankar       ierr = SNESVIResetPCandKSP(snes,J_aug,Jpre_aug);CHKERRQ(ierr);
14652f63a38cSShri Abhyankar     }
146656a221efSShri Abhyankar     ierr = KSPSetOperators(snes->ksp,J_aug,Jpre_aug,flg);CHKERRQ(ierr);
14672f63a38cSShri Abhyankar     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
146856a221efSShri Abhyankar     /*  {
14692f63a38cSShri Abhyankar       PC        pc;
14702f63a38cSShri Abhyankar       PetscBool flg;
14712f63a38cSShri Abhyankar       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
14722f63a38cSShri Abhyankar       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
14732f63a38cSShri Abhyankar       if (flg) {
14742f63a38cSShri Abhyankar         KSP      *subksps;
14752f63a38cSShri Abhyankar         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
14762f63a38cSShri Abhyankar         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
14772f63a38cSShri Abhyankar         ierr = PetscFree(subksps);CHKERRQ(ierr);
14782f63a38cSShri Abhyankar         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
14792f63a38cSShri Abhyankar         if (flg) {
14802f63a38cSShri Abhyankar           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
14812f63a38cSShri Abhyankar           const PetscInt *ii;
14822f63a38cSShri Abhyankar 
14832f63a38cSShri Abhyankar           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
14842f63a38cSShri Abhyankar           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
14852f63a38cSShri Abhyankar           for (j=0; j<n; j++) {
14862f63a38cSShri Abhyankar             if (ii[j] < N) cnts[0]++;
14872f63a38cSShri Abhyankar             else if (ii[j] < 2*N) cnts[1]++;
14882f63a38cSShri Abhyankar             else if (ii[j] < 3*N) cnts[2]++;
14892f63a38cSShri Abhyankar           }
14902f63a38cSShri Abhyankar           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
14912f63a38cSShri Abhyankar 
14922f63a38cSShri Abhyankar           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
14932f63a38cSShri Abhyankar         }
14942f63a38cSShri Abhyankar       }
14952f63a38cSShri Abhyankar     }
149656a221efSShri Abhyankar     */
149756a221efSShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,F_aug,Y_aug);CHKERRQ(ierr);
14982f63a38cSShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
14992f63a38cSShri Abhyankar     if (kspreason < 0) {
15002f63a38cSShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
15012f63a38cSShri 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);
15022f63a38cSShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
15032f63a38cSShri Abhyankar         break;
15042f63a38cSShri Abhyankar       }
15052f63a38cSShri Abhyankar     }
15062f63a38cSShri Abhyankar 
150756a221efSShri Abhyankar     if(nis_act) {
150856a221efSShri Abhyankar       PetscScalar *y1,*y2;
150956a221efSShri Abhyankar       ierr = VecGetArray(Y,&y1);CHKERRQ(ierr);
151056a221efSShri Abhyankar       ierr = VecGetArray(Y_aug,&y2);CHKERRQ(ierr);
151156a221efSShri Abhyankar       /* Copy over inactive Y_aug to Y */
151256a221efSShri Abhyankar       j1 = 0;
151356a221efSShri Abhyankar       for(i1=Y->map->rstart;i1 < Y->map->rend;i1++) {
151456a221efSShri Abhyankar 	if(j1 < nkept && idx_actkept[j1] == i1) j1++;
151556a221efSShri Abhyankar 	else y1[i1-Y->map->rstart] = y2[i1-Y->map->rstart];
151656a221efSShri Abhyankar       }
151756a221efSShri Abhyankar       ierr = VecRestoreArray(Y,&y1);CHKERRQ(ierr);
151856a221efSShri Abhyankar       ierr = VecRestoreArray(Y_aug,&y2);CHKERRQ(ierr);
15192f63a38cSShri Abhyankar 
15206bf464f9SBarry Smith       ierr = VecDestroy(&F_aug);CHKERRQ(ierr);
15216bf464f9SBarry Smith       ierr = VecDestroy(&Y_aug);CHKERRQ(ierr);
15226bf464f9SBarry Smith       ierr = MatDestroy(&J_aug);CHKERRQ(ierr);
152356a221efSShri Abhyankar       ierr = PetscFree(idx_actkept);CHKERRQ(ierr);
152456a221efSShri Abhyankar     }
152556a221efSShri Abhyankar 
15262f63a38cSShri Abhyankar     if (!isequal) {
15276bf464f9SBarry Smith       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
15282f63a38cSShri Abhyankar       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
15292f63a38cSShri Abhyankar     }
15306bf464f9SBarry Smith     ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
153156a221efSShri Abhyankar 
15322f63a38cSShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
15332f63a38cSShri Abhyankar     snes->linear_its += lits;
15342f63a38cSShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
15352f63a38cSShri Abhyankar     /*
15362f63a38cSShri Abhyankar     if (vi->precheckstep) {
15372f63a38cSShri Abhyankar       PetscBool changed_y = PETSC_FALSE;
15382f63a38cSShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
15392f63a38cSShri Abhyankar     }
15402f63a38cSShri Abhyankar 
15412f63a38cSShri Abhyankar     if (PetscLogPrintInfo){
15422f63a38cSShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
15432f63a38cSShri Abhyankar     }
15442f63a38cSShri Abhyankar     */
15452f63a38cSShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
15462f63a38cSShri Abhyankar          Y <- X - lambda*Y
15472f63a38cSShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
15482f63a38cSShri Abhyankar     */
15492f63a38cSShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
15502f63a38cSShri Abhyankar     ynorm = 1; gnorm = fnorm;
15512f63a38cSShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
15522f63a38cSShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
15532f63a38cSShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
15542f63a38cSShri Abhyankar     if (snes->domainerror) {
15552f63a38cSShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
15562f63a38cSShri Abhyankar       PetscFunctionReturn(0);
15572f63a38cSShri Abhyankar     }
15582f63a38cSShri Abhyankar     if (!lssucceed) {
15592f63a38cSShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
15602f63a38cSShri Abhyankar 	PetscBool ismin;
15612f63a38cSShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
15622f63a38cSShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
15632f63a38cSShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
15642f63a38cSShri Abhyankar         break;
15652f63a38cSShri Abhyankar       }
15662f63a38cSShri Abhyankar     }
15672f63a38cSShri Abhyankar     /* Update function and solution vectors */
15682f63a38cSShri Abhyankar     fnorm = gnorm;
15692f63a38cSShri Abhyankar     ierr = VecCopy(G,F);CHKERRQ(ierr);
15702f63a38cSShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
15712f63a38cSShri Abhyankar     /* Monitor convergence */
15722f63a38cSShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
15732f63a38cSShri Abhyankar     snes->iter = i+1;
15742f63a38cSShri Abhyankar     snes->norm = fnorm;
15752f63a38cSShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
15762f63a38cSShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
15777a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
15782f63a38cSShri Abhyankar     /* Test for convergence, xnorm = || X || */
15792f63a38cSShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
15802f63a38cSShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
15812f63a38cSShri Abhyankar     if (snes->reason) break;
15822f63a38cSShri Abhyankar   }
15832f63a38cSShri Abhyankar   if (i == maxits) {
15842f63a38cSShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
15852f63a38cSShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
15862f63a38cSShri Abhyankar   }
15872f63a38cSShri Abhyankar   PetscFunctionReturn(0);
15882f63a38cSShri Abhyankar }
15892f63a38cSShri Abhyankar 
15902b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
15912b4ed282SShri Abhyankar /*
15922b4ed282SShri Abhyankar    SNESSetUp_VI - Sets up the internal data structures for the later use
15932b4ed282SShri Abhyankar    of the SNESVI nonlinear solver.
15942b4ed282SShri Abhyankar 
15952b4ed282SShri Abhyankar    Input Parameter:
15962b4ed282SShri Abhyankar .  snes - the SNES context
15972b4ed282SShri Abhyankar .  x - the solution vector
15982b4ed282SShri Abhyankar 
15992b4ed282SShri Abhyankar    Application Interface Routine: SNESSetUp()
16002b4ed282SShri Abhyankar 
16012b4ed282SShri Abhyankar    Notes:
16022b4ed282SShri Abhyankar    For basic use of the SNES solvers, the user need not explicitly call
16032b4ed282SShri Abhyankar    SNESSetUp(), since these actions will automatically occur during
16042b4ed282SShri Abhyankar    the call to SNESSolve().
16052b4ed282SShri Abhyankar  */
16062b4ed282SShri Abhyankar #undef __FUNCT__
16072b4ed282SShri Abhyankar #define __FUNCT__ "SNESSetUp_VI"
16082b4ed282SShri Abhyankar PetscErrorCode SNESSetUp_VI(SNES snes)
16092b4ed282SShri Abhyankar {
16102b4ed282SShri Abhyankar   PetscErrorCode ierr;
16112b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*) snes->data;
16122b4ed282SShri Abhyankar   PetscInt       i_start[3],i_end[3];
16132b4ed282SShri Abhyankar 
16142b4ed282SShri Abhyankar   PetscFunctionBegin;
161558c9b817SLisandro Dalcin 
161658c9b817SLisandro Dalcin   ierr = SNESDefaultGetWork(snes,3);CHKERRQ(ierr);
16172b4ed282SShri Abhyankar 
16182b4ed282SShri Abhyankar   /* If the lower and upper bound on variables are not set, set it to
16192b4ed282SShri Abhyankar      -Inf and Inf */
16202b4ed282SShri Abhyankar   if (!vi->xl && !vi->xu) {
16212b4ed282SShri Abhyankar     vi->usersetxbounds = PETSC_FALSE;
16222b4ed282SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->xl); CHKERRQ(ierr);
162301f0b76bSBarry Smith     ierr = VecSet(vi->xl,SNES_VI_NINF);CHKERRQ(ierr);
16242b4ed282SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->xu); CHKERRQ(ierr);
162501f0b76bSBarry Smith     ierr = VecSet(vi->xu,SNES_VI_INF);CHKERRQ(ierr);
16262b4ed282SShri Abhyankar   } else {
16272b4ed282SShri Abhyankar     /* Check if lower bound, upper bound and solution vector distribution across the processors is identical */
16282b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(snes->vec_sol,i_start,i_end);CHKERRQ(ierr);
16292b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(vi->xl,i_start+1,i_end+1);CHKERRQ(ierr);
16302b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(vi->xu,i_start+2,i_end+2);CHKERRQ(ierr);
16312b4ed282SShri 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]))
16322b4ed282SShri 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.");
16332b4ed282SShri Abhyankar   }
16342f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
1635abcba341SShri Abhyankar     /* Set up previous active index set for the first snes solve
1636abcba341SShri Abhyankar        vi->IS_inact_prev = 0,1,2,....N */
1637abcba341SShri Abhyankar     PetscInt *indices;
1638abcba341SShri Abhyankar     PetscInt  i,n,rstart,rend;
1639abcba341SShri Abhyankar 
1640abcba341SShri Abhyankar     ierr = VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);CHKERRQ(ierr);
1641abcba341SShri Abhyankar     ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
1642abcba341SShri Abhyankar     ierr = PetscMalloc(n*sizeof(PetscInt),&indices);CHKERRQ(ierr);
1643abcba341SShri Abhyankar     for(i=0;i < n; i++) indices[i] = rstart + i;
1644abcba341SShri Abhyankar     ierr = ISCreateGeneral(((PetscObject)snes)->comm,n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);
1645abcba341SShri Abhyankar   }
16462b4ed282SShri Abhyankar 
16472f63a38cSShri Abhyankar   if (snes->ops->solve == SNESSolveVI_SS) {
1648fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->dpsi);CHKERRQ(ierr);
1649fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->phi); CHKERRQ(ierr);
1650fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->Da); CHKERRQ(ierr);
1651fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->Db); CHKERRQ(ierr);
1652fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->z);CHKERRQ(ierr);
1653fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->t); CHKERRQ(ierr);
1654fe835674SShri Abhyankar   }
16552b4ed282SShri Abhyankar   PetscFunctionReturn(0);
16562b4ed282SShri Abhyankar }
16572b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
16582b4ed282SShri Abhyankar /*
16592b4ed282SShri Abhyankar    SNESDestroy_VI - Destroys the private SNES_VI context that was created
16602b4ed282SShri Abhyankar    with SNESCreate_VI().
16612b4ed282SShri Abhyankar 
16622b4ed282SShri Abhyankar    Input Parameter:
16632b4ed282SShri Abhyankar .  snes - the SNES context
16642b4ed282SShri Abhyankar 
16652b4ed282SShri Abhyankar    Application Interface Routine: SNESDestroy()
16662b4ed282SShri Abhyankar  */
16672b4ed282SShri Abhyankar #undef __FUNCT__
16682b4ed282SShri Abhyankar #define __FUNCT__ "SNESDestroy_VI"
16692b4ed282SShri Abhyankar PetscErrorCode SNESDestroy_VI(SNES snes)
16702b4ed282SShri Abhyankar {
16712b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*) snes->data;
16722b4ed282SShri Abhyankar   PetscErrorCode ierr;
16732b4ed282SShri Abhyankar 
16742b4ed282SShri Abhyankar   PetscFunctionBegin;
16752f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
16766bf464f9SBarry Smith     ierr = ISDestroy(&vi->IS_inact_prev);
1677abcba341SShri Abhyankar   }
16782b4ed282SShri Abhyankar 
16792f63a38cSShri Abhyankar   if (snes->ops->solve == SNESSolveVI_SS) {
16802b4ed282SShri Abhyankar     /* clear vectors */
16816bf464f9SBarry Smith     ierr = VecDestroy(&vi->dpsi);CHKERRQ(ierr);
16826bf464f9SBarry Smith     ierr = VecDestroy(&vi->phi); CHKERRQ(ierr);
16836bf464f9SBarry Smith     ierr = VecDestroy(&vi->Da); CHKERRQ(ierr);
16846bf464f9SBarry Smith     ierr = VecDestroy(&vi->Db); CHKERRQ(ierr);
16856bf464f9SBarry Smith     ierr = VecDestroy(&vi->z); CHKERRQ(ierr);
16866bf464f9SBarry Smith     ierr = VecDestroy(&vi->t); CHKERRQ(ierr);
16877fe79bc4SShri Abhyankar   }
16887fe79bc4SShri Abhyankar 
16892b4ed282SShri Abhyankar   if (!vi->usersetxbounds) {
16906bf464f9SBarry Smith     ierr = VecDestroy(&vi->xl); CHKERRQ(ierr);
16916bf464f9SBarry Smith     ierr = VecDestroy(&vi->xu); CHKERRQ(ierr);
16922b4ed282SShri Abhyankar   }
16937fe79bc4SShri Abhyankar 
16946bf464f9SBarry Smith   ierr = PetscViewerASCIIMonitorDestroy(&vi->lsmonitor);CHKERRQ(ierr);
16952b4ed282SShri Abhyankar   ierr = PetscFree(snes->data);CHKERRQ(ierr);
16962b4ed282SShri Abhyankar 
16972b4ed282SShri Abhyankar   /* clear composed functions */
16982b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr);
1699c92abb8aSShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);CHKERRQ(ierr);
17002b4ed282SShri Abhyankar   PetscFunctionReturn(0);
17012b4ed282SShri Abhyankar }
17027fe79bc4SShri Abhyankar 
17032b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
17042b4ed282SShri Abhyankar #undef __FUNCT__
17052b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchNo_VI"
17062b4ed282SShri Abhyankar 
17072b4ed282SShri Abhyankar /*
17087fe79bc4SShri Abhyankar   This routine does not actually do a line search but it takes a full newton
17097fe79bc4SShri Abhyankar   step while ensuring that the new iterates remain within the constraints.
17102b4ed282SShri Abhyankar 
17112b4ed282SShri Abhyankar */
1712ace3abfcSBarry 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)
17132b4ed282SShri Abhyankar {
17142b4ed282SShri Abhyankar   PetscErrorCode ierr;
17152b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1716ace3abfcSBarry Smith   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
17172b4ed282SShri Abhyankar 
17182b4ed282SShri Abhyankar   PetscFunctionBegin;
17192b4ed282SShri Abhyankar   *flag = PETSC_TRUE;
17202b4ed282SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
17212b4ed282SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);         /* ynorm = || y || */
17222b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1723c1a5e521SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1724c1a5e521SShri Abhyankar   if (vi->postcheckstep) {
1725c1a5e521SShri Abhyankar    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1726c1a5e521SShri Abhyankar   }
1727c1a5e521SShri Abhyankar   if (changed_y) {
1728c1a5e521SShri Abhyankar     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
17297fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1730c1a5e521SShri Abhyankar   }
1731c1a5e521SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1732c1a5e521SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1733c1a5e521SShri Abhyankar   if (!snes->domainerror) {
17342f63a38cSShri Abhyankar     if (snes->ops->solve != SNESSolveVI_SS) {
17357fe79bc4SShri Abhyankar        ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
17367fe79bc4SShri Abhyankar     } else {
1737c1a5e521SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
17387fe79bc4SShri Abhyankar     }
173962cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1740c1a5e521SShri Abhyankar   }
1741c1a5e521SShri Abhyankar   if (vi->lsmonitor) {
1742c1a5e521SShri Abhyankar     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1743c1a5e521SShri Abhyankar   }
1744c1a5e521SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1745c1a5e521SShri Abhyankar   PetscFunctionReturn(0);
1746c1a5e521SShri Abhyankar }
1747c1a5e521SShri Abhyankar 
1748c1a5e521SShri Abhyankar /* -------------------------------------------------------------------------- */
1749c1a5e521SShri Abhyankar #undef __FUNCT__
17502b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchNoNorms_VI"
17512b4ed282SShri Abhyankar 
17522b4ed282SShri Abhyankar /*
17532b4ed282SShri Abhyankar   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
17542b4ed282SShri Abhyankar */
1755ace3abfcSBarry 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)
17562b4ed282SShri Abhyankar {
17572b4ed282SShri Abhyankar   PetscErrorCode ierr;
17582b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1759ace3abfcSBarry Smith   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
17602b4ed282SShri Abhyankar 
17612b4ed282SShri Abhyankar   PetscFunctionBegin;
17622b4ed282SShri Abhyankar   *flag = PETSC_TRUE;
17632b4ed282SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
17642b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y      */
17657fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
17662b4ed282SShri Abhyankar   if (vi->postcheckstep) {
17672b4ed282SShri Abhyankar    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
17682b4ed282SShri Abhyankar   }
17692b4ed282SShri Abhyankar   if (changed_y) {
17702b4ed282SShri Abhyankar     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
17717fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
17722b4ed282SShri Abhyankar   }
17732b4ed282SShri Abhyankar 
17742b4ed282SShri Abhyankar   /* don't evaluate function the last time through */
17752b4ed282SShri Abhyankar   if (snes->iter < snes->max_its-1) {
17762b4ed282SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
17772b4ed282SShri Abhyankar   }
17782b4ed282SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
17792b4ed282SShri Abhyankar   PetscFunctionReturn(0);
17802b4ed282SShri Abhyankar }
17817fe79bc4SShri Abhyankar 
17822b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
17832b4ed282SShri Abhyankar #undef __FUNCT__
17842b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchCubic_VI"
17852b4ed282SShri Abhyankar /*
17867fe79bc4SShri Abhyankar   This routine implements a cubic line search while doing a projection on the variable bounds
17872b4ed282SShri Abhyankar */
1788ace3abfcSBarry 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)
17892b4ed282SShri Abhyankar {
1790fe835674SShri Abhyankar   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
1791fe835674SShri Abhyankar   PetscReal      minlambda,lambda,lambdatemp;
1792fe835674SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
1793fe835674SShri Abhyankar   PetscScalar    cinitslope;
1794fe835674SShri Abhyankar #endif
1795fe835674SShri Abhyankar   PetscErrorCode ierr;
1796fe835674SShri Abhyankar   PetscInt       count;
1797fe835674SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1798fe835674SShri Abhyankar   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1799fe835674SShri Abhyankar   MPI_Comm       comm;
1800fe835674SShri Abhyankar 
1801fe835674SShri Abhyankar   PetscFunctionBegin;
1802fe835674SShri Abhyankar   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
1803fe835674SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1804fe835674SShri Abhyankar   *flag   = PETSC_TRUE;
1805fe835674SShri Abhyankar 
1806fe835674SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1807fe835674SShri Abhyankar   if (*ynorm == 0.0) {
1808fe835674SShri Abhyankar     if (vi->lsmonitor) {
1809fe835674SShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
1810fe835674SShri Abhyankar     }
1811fe835674SShri Abhyankar     *gnorm = fnorm;
1812fe835674SShri Abhyankar     ierr   = VecCopy(x,w);CHKERRQ(ierr);
1813fe835674SShri Abhyankar     ierr   = VecCopy(f,g);CHKERRQ(ierr);
1814fe835674SShri Abhyankar     *flag  = PETSC_FALSE;
1815fe835674SShri Abhyankar     goto theend1;
1816fe835674SShri Abhyankar   }
1817fe835674SShri Abhyankar   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
1818fe835674SShri Abhyankar     if (vi->lsmonitor) {
1819fe835674SShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Scaling step by %G old ynorm %G\n",vi->maxstep/(*ynorm),*ynorm);CHKERRQ(ierr);
1820fe835674SShri Abhyankar     }
1821fe835674SShri Abhyankar     ierr = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
1822fe835674SShri Abhyankar     *ynorm = vi->maxstep;
1823fe835674SShri Abhyankar   }
1824fe835674SShri Abhyankar   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
1825fe835674SShri Abhyankar   minlambda = vi->minlambda/rellength;
1826fe835674SShri Abhyankar   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
1827fe835674SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
1828fe835674SShri Abhyankar   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
1829fe835674SShri Abhyankar   initslope = PetscRealPart(cinitslope);
1830fe835674SShri Abhyankar #else
1831fe835674SShri Abhyankar   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
1832fe835674SShri Abhyankar #endif
1833fe835674SShri Abhyankar   if (initslope > 0.0)  initslope = -initslope;
1834fe835674SShri Abhyankar   if (initslope == 0.0) initslope = -1.0;
1835fe835674SShri Abhyankar 
1836fe835674SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1837fe835674SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1838fe835674SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
1839fe835674SShri Abhyankar     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
1840fe835674SShri Abhyankar     *flag = PETSC_FALSE;
1841fe835674SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1842fe835674SShri Abhyankar     goto theend1;
1843fe835674SShri Abhyankar   }
1844fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
18452f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
1846fe835674SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
18477fe79bc4SShri Abhyankar   } else {
18487fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
18497fe79bc4SShri Abhyankar   }
1850fe835674SShri Abhyankar   if (snes->domainerror) {
1851fe835674SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1852fe835674SShri Abhyankar     PetscFunctionReturn(0);
1853fe835674SShri Abhyankar   }
185462cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1855fe835674SShri Abhyankar   ierr = PetscInfo2(snes,"Initial fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1856fe835674SShri Abhyankar   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
1857fe835674SShri Abhyankar     if (vi->lsmonitor) {
1858fe835674SShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1859fe835674SShri Abhyankar     }
1860fe835674SShri Abhyankar     goto theend1;
1861fe835674SShri Abhyankar   }
1862fe835674SShri Abhyankar 
1863fe835674SShri Abhyankar   /* Fit points with quadratic */
1864fe835674SShri Abhyankar   lambda     = 1.0;
1865fe835674SShri Abhyankar   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
1866fe835674SShri Abhyankar   lambdaprev = lambda;
1867fe835674SShri Abhyankar   gnormprev  = *gnorm;
1868fe835674SShri Abhyankar   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1869fe835674SShri Abhyankar   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
1870fe835674SShri Abhyankar   else                         lambda = lambdatemp;
1871fe835674SShri Abhyankar 
1872fe835674SShri Abhyankar   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1873fe835674SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1874fe835674SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
1875fe835674SShri Abhyankar     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
1876fe835674SShri Abhyankar     *flag = PETSC_FALSE;
1877fe835674SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1878fe835674SShri Abhyankar     goto theend1;
1879fe835674SShri Abhyankar   }
1880fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
18812f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
1882fe835674SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
18837fe79bc4SShri Abhyankar   } else {
18847fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
18857fe79bc4SShri Abhyankar   }
1886fe835674SShri Abhyankar   if (snes->domainerror) {
1887fe835674SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1888fe835674SShri Abhyankar     PetscFunctionReturn(0);
1889fe835674SShri Abhyankar   }
189062cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1891fe835674SShri Abhyankar   if (vi->lsmonitor) {
1892fe835674SShri Abhyankar     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: gnorm after quadratic fit %G\n",*gnorm);CHKERRQ(ierr);
1893fe835674SShri Abhyankar   }
1894fe835674SShri Abhyankar   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
1895fe835674SShri Abhyankar     if (vi->lsmonitor) {
1896fe835674SShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr);
1897fe835674SShri Abhyankar     }
1898fe835674SShri Abhyankar     goto theend1;
1899fe835674SShri Abhyankar   }
1900fe835674SShri Abhyankar 
1901fe835674SShri Abhyankar   /* Fit points with cubic */
1902fe835674SShri Abhyankar   count = 1;
1903fe835674SShri Abhyankar   while (PETSC_TRUE) {
1904fe835674SShri Abhyankar     if (lambda <= minlambda) {
1905fe835674SShri Abhyankar       if (vi->lsmonitor) {
1906fe835674SShri Abhyankar 	ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
1907fe835674SShri Abhyankar 	ierr = PetscViewerASCIIMonitorPrintf(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);
1908fe835674SShri Abhyankar       }
1909fe835674SShri Abhyankar       *flag = PETSC_FALSE;
1910fe835674SShri Abhyankar       break;
1911fe835674SShri Abhyankar     }
1912fe835674SShri Abhyankar     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
1913fe835674SShri Abhyankar     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
1914fe835674SShri Abhyankar     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1915fe835674SShri Abhyankar     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1916fe835674SShri Abhyankar     d  = b*b - 3*a*initslope;
1917fe835674SShri Abhyankar     if (d < 0.0) d = 0.0;
1918fe835674SShri Abhyankar     if (a == 0.0) {
1919fe835674SShri Abhyankar       lambdatemp = -initslope/(2.0*b);
1920fe835674SShri Abhyankar     } else {
1921fe835674SShri Abhyankar       lambdatemp = (-b + sqrt(d))/(3.0*a);
1922fe835674SShri Abhyankar     }
1923fe835674SShri Abhyankar     lambdaprev = lambda;
1924fe835674SShri Abhyankar     gnormprev  = *gnorm;
1925fe835674SShri Abhyankar     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1926fe835674SShri Abhyankar     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
1927fe835674SShri Abhyankar     else                         lambda     = lambdatemp;
1928fe835674SShri Abhyankar     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1929fe835674SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1930fe835674SShri Abhyankar     if (snes->nfuncs >= snes->max_funcs) {
1931fe835674SShri Abhyankar       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
1932fe835674SShri 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);
1933fe835674SShri Abhyankar       *flag = PETSC_FALSE;
1934fe835674SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1935fe835674SShri Abhyankar       break;
1936fe835674SShri Abhyankar     }
1937fe835674SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
19382f63a38cSShri Abhyankar     if (snes->ops->solve != SNESSolveVI_SS) {
1939fe835674SShri Abhyankar       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
19407fe79bc4SShri Abhyankar     } else {
19417fe79bc4SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
19427fe79bc4SShri Abhyankar     }
1943fe835674SShri Abhyankar     if (snes->domainerror) {
1944fe835674SShri Abhyankar       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1945fe835674SShri Abhyankar       PetscFunctionReturn(0);
1946fe835674SShri Abhyankar     }
194762cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1948fe835674SShri Abhyankar     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* is reduction enough? */
1949fe835674SShri Abhyankar       if (vi->lsmonitor) {
1950fe835674SShri Abhyankar 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1951fe835674SShri Abhyankar       }
1952fe835674SShri Abhyankar       break;
1953fe835674SShri Abhyankar     } else {
1954fe835674SShri Abhyankar       if (vi->lsmonitor) {
1955fe835674SShri Abhyankar         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1956fe835674SShri Abhyankar       }
1957fe835674SShri Abhyankar     }
1958fe835674SShri Abhyankar     count++;
1959fe835674SShri Abhyankar   }
1960fe835674SShri Abhyankar   theend1:
1961fe835674SShri Abhyankar   /* Optional user-defined check for line search step validity */
1962fe835674SShri Abhyankar   if (vi->postcheckstep && *flag) {
1963fe835674SShri Abhyankar     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1964fe835674SShri Abhyankar     if (changed_y) {
1965fe835674SShri Abhyankar       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1966fe835674SShri Abhyankar       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1967fe835674SShri Abhyankar     }
1968fe835674SShri Abhyankar     if (changed_y || changed_w) { /* recompute the function if the step has changed */
1969fe835674SShri Abhyankar       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
19702f63a38cSShri Abhyankar       if (snes->ops->solve != SNESSolveVI_SS) {
1971fe835674SShri Abhyankar         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
19727fe79bc4SShri Abhyankar       } else {
19737fe79bc4SShri Abhyankar         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
19747fe79bc4SShri Abhyankar       }
1975fe835674SShri Abhyankar       if (snes->domainerror) {
1976fe835674SShri Abhyankar         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1977fe835674SShri Abhyankar         PetscFunctionReturn(0);
1978fe835674SShri Abhyankar       }
197962cbcd01SMatthew G Knepley       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1980fe835674SShri Abhyankar       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
1981fe835674SShri Abhyankar       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
1982fe835674SShri Abhyankar     }
1983fe835674SShri Abhyankar   }
1984fe835674SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1985fe835674SShri Abhyankar   PetscFunctionReturn(0);
1986fe835674SShri Abhyankar }
1987fe835674SShri Abhyankar 
19882b4ed282SShri Abhyankar #undef __FUNCT__
19892b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchQuadratic_VI"
19902b4ed282SShri Abhyankar /*
19917fe79bc4SShri Abhyankar   This routine does a quadratic line search while keeping the iterates within the variable bounds
19922b4ed282SShri Abhyankar */
1993ace3abfcSBarry 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)
19942b4ed282SShri Abhyankar {
19952b4ed282SShri Abhyankar   /*
19962b4ed282SShri Abhyankar      Note that for line search purposes we work with with the related
19972b4ed282SShri Abhyankar      minimization problem:
19982b4ed282SShri Abhyankar         min  z(x):  R^n -> R,
19992b4ed282SShri Abhyankar      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
20002b4ed282SShri Abhyankar    */
20012b4ed282SShri Abhyankar   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
20022b4ed282SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
20032b4ed282SShri Abhyankar   PetscScalar    cinitslope;
20042b4ed282SShri Abhyankar #endif
20052b4ed282SShri Abhyankar   PetscErrorCode ierr;
20062b4ed282SShri Abhyankar   PetscInt       count;
20072b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
2008ace3abfcSBarry Smith   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
20092b4ed282SShri Abhyankar 
20102b4ed282SShri Abhyankar   PetscFunctionBegin;
20112b4ed282SShri Abhyankar   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
20122b4ed282SShri Abhyankar   *flag   = PETSC_TRUE;
20132b4ed282SShri Abhyankar 
20142b4ed282SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
20152b4ed282SShri Abhyankar   if (*ynorm == 0.0) {
2016c92abb8aSShri Abhyankar     if (vi->lsmonitor) {
2017c92abb8aSShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
20182b4ed282SShri Abhyankar     }
20192b4ed282SShri Abhyankar     *gnorm = fnorm;
20202b4ed282SShri Abhyankar     ierr   = VecCopy(x,w);CHKERRQ(ierr);
20212b4ed282SShri Abhyankar     ierr   = VecCopy(f,g);CHKERRQ(ierr);
20222b4ed282SShri Abhyankar     *flag  = PETSC_FALSE;
20232b4ed282SShri Abhyankar     goto theend2;
20242b4ed282SShri Abhyankar   }
20252b4ed282SShri Abhyankar   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
20262b4ed282SShri Abhyankar     ierr   = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
20272b4ed282SShri Abhyankar     *ynorm = vi->maxstep;
20282b4ed282SShri Abhyankar   }
20292b4ed282SShri Abhyankar   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
20302b4ed282SShri Abhyankar   minlambda = vi->minlambda/rellength;
20317fe79bc4SShri Abhyankar   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
20322b4ed282SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
20337fe79bc4SShri Abhyankar   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
20342b4ed282SShri Abhyankar   initslope = PetscRealPart(cinitslope);
20352b4ed282SShri Abhyankar #else
20367fe79bc4SShri Abhyankar   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
20372b4ed282SShri Abhyankar #endif
20382b4ed282SShri Abhyankar   if (initslope > 0.0)  initslope = -initslope;
20392b4ed282SShri Abhyankar   if (initslope == 0.0) initslope = -1.0;
20402b4ed282SShri Abhyankar   ierr = PetscInfo1(snes,"Initslope %G \n",initslope);CHKERRQ(ierr);
20412b4ed282SShri Abhyankar 
20422b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
20437fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
20442b4ed282SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
20452b4ed282SShri Abhyankar     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
20462b4ed282SShri Abhyankar     *flag = PETSC_FALSE;
20472b4ed282SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
20482b4ed282SShri Abhyankar     goto theend2;
20492b4ed282SShri Abhyankar   }
20502b4ed282SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
20512f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
20527fe79bc4SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
20537fe79bc4SShri Abhyankar   } else {
20547fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
20557fe79bc4SShri Abhyankar   }
20562b4ed282SShri Abhyankar   if (snes->domainerror) {
20572b4ed282SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
20582b4ed282SShri Abhyankar     PetscFunctionReturn(0);
20592b4ed282SShri Abhyankar   }
206062cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
20612b4ed282SShri Abhyankar   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
2062c92abb8aSShri Abhyankar     if (vi->lsmonitor) {
2063c92abb8aSShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
20642b4ed282SShri Abhyankar     }
20652b4ed282SShri Abhyankar     goto theend2;
20662b4ed282SShri Abhyankar   }
20672b4ed282SShri Abhyankar 
20682b4ed282SShri Abhyankar   /* Fit points with quadratic */
20692b4ed282SShri Abhyankar   lambda = 1.0;
20702b4ed282SShri Abhyankar   count = 1;
20712b4ed282SShri Abhyankar   while (PETSC_TRUE) {
20722b4ed282SShri Abhyankar     if (lambda <= minlambda) { /* bad luck; use full step */
2073c92abb8aSShri Abhyankar       if (vi->lsmonitor) {
2074c92abb8aSShri Abhyankar         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
2075c92abb8aSShri Abhyankar         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr);
20762b4ed282SShri Abhyankar       }
20772b4ed282SShri Abhyankar       ierr = VecCopy(x,w);CHKERRQ(ierr);
20782b4ed282SShri Abhyankar       *flag = PETSC_FALSE;
20792b4ed282SShri Abhyankar       break;
20802b4ed282SShri Abhyankar     }
20812b4ed282SShri Abhyankar     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
20822b4ed282SShri Abhyankar     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
20832b4ed282SShri Abhyankar     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
20842b4ed282SShri Abhyankar     else                         lambda     = lambdatemp;
20852b4ed282SShri Abhyankar 
20862b4ed282SShri Abhyankar     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
20877fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
20882b4ed282SShri Abhyankar     if (snes->nfuncs >= snes->max_funcs) {
20892b4ed282SShri Abhyankar       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
20902b4ed282SShri 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);
20912b4ed282SShri Abhyankar       *flag = PETSC_FALSE;
20922b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
20932b4ed282SShri Abhyankar       break;
20942b4ed282SShri Abhyankar     }
20952b4ed282SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
20962b4ed282SShri Abhyankar     if (snes->domainerror) {
20972b4ed282SShri Abhyankar       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
20982b4ed282SShri Abhyankar       PetscFunctionReturn(0);
20992b4ed282SShri Abhyankar     }
21002f63a38cSShri Abhyankar     if (snes->ops->solve != SNESSolveVI_SS) {
21017fe79bc4SShri Abhyankar       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
21027fe79bc4SShri Abhyankar     } else {
21032b4ed282SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
21047fe79bc4SShri Abhyankar     }
210562cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
21062b4ed282SShri Abhyankar     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
2107c92abb8aSShri Abhyankar       if (vi->lsmonitor) {
2108c92abb8aSShri Abhyankar         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line Search: Quadratically determined step, lambda=%G\n",lambda);CHKERRQ(ierr);
21092b4ed282SShri Abhyankar       }
21102b4ed282SShri Abhyankar       break;
21112b4ed282SShri Abhyankar     }
21122b4ed282SShri Abhyankar     count++;
21132b4ed282SShri Abhyankar   }
21142b4ed282SShri Abhyankar   theend2:
21152b4ed282SShri Abhyankar   /* Optional user-defined check for line search step validity */
21162b4ed282SShri Abhyankar   if (vi->postcheckstep) {
21172b4ed282SShri Abhyankar     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
21182b4ed282SShri Abhyankar     if (changed_y) {
21192b4ed282SShri Abhyankar       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
21207fe79bc4SShri Abhyankar       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
21212b4ed282SShri Abhyankar     }
21222b4ed282SShri Abhyankar     if (changed_y || changed_w) { /* recompute the function if the step has changed */
21232b4ed282SShri Abhyankar       ierr = SNESComputeFunction(snes,w,g);
21242b4ed282SShri Abhyankar       if (snes->domainerror) {
21252b4ed282SShri Abhyankar         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
21262b4ed282SShri Abhyankar         PetscFunctionReturn(0);
21272b4ed282SShri Abhyankar       }
21282f63a38cSShri Abhyankar       if (snes->ops->solve != SNESSolveVI_SS) {
21297fe79bc4SShri Abhyankar         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
21307fe79bc4SShri Abhyankar       } else {
21317fe79bc4SShri Abhyankar         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
21327fe79bc4SShri Abhyankar       }
21337fe79bc4SShri Abhyankar 
21342b4ed282SShri Abhyankar       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
21352b4ed282SShri Abhyankar       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
213662cbcd01SMatthew G Knepley       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
21372b4ed282SShri Abhyankar     }
21382b4ed282SShri Abhyankar   }
21392b4ed282SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
21402b4ed282SShri Abhyankar   PetscFunctionReturn(0);
21412b4ed282SShri Abhyankar }
21422b4ed282SShri Abhyankar 
2143ace3abfcSBarry 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*/
21442b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
21452b4ed282SShri Abhyankar EXTERN_C_BEGIN
21462b4ed282SShri Abhyankar #undef __FUNCT__
21472b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchSet_VI"
21487087cfbeSBarry Smith PetscErrorCode  SNESLineSearchSet_VI(SNES snes,FCN2 func,void *lsctx)
21492b4ed282SShri Abhyankar {
21502b4ed282SShri Abhyankar   PetscFunctionBegin;
21512b4ed282SShri Abhyankar   ((SNES_VI *)(snes->data))->LineSearch = func;
21522b4ed282SShri Abhyankar   ((SNES_VI *)(snes->data))->lsP        = lsctx;
21532b4ed282SShri Abhyankar   PetscFunctionReturn(0);
21542b4ed282SShri Abhyankar }
21552b4ed282SShri Abhyankar EXTERN_C_END
21562b4ed282SShri Abhyankar 
21572b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
21582b4ed282SShri Abhyankar EXTERN_C_BEGIN
21592b4ed282SShri Abhyankar #undef __FUNCT__
21602b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchSetMonitor_VI"
21617087cfbeSBarry Smith PetscErrorCode  SNESLineSearchSetMonitor_VI(SNES snes,PetscBool flg)
21622b4ed282SShri Abhyankar {
21632b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
21642b4ed282SShri Abhyankar   PetscErrorCode ierr;
21652b4ed282SShri Abhyankar 
21662b4ed282SShri Abhyankar   PetscFunctionBegin;
2167c92abb8aSShri Abhyankar   if (flg && !vi->lsmonitor) {
2168c92abb8aSShri Abhyankar     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)snes)->comm,"stdout",((PetscObject)snes)->tablevel,&vi->lsmonitor);CHKERRQ(ierr);
2169c92abb8aSShri Abhyankar   } else if (!flg && vi->lsmonitor) {
21706bf464f9SBarry Smith     ierr = PetscViewerASCIIMonitorDestroy(&vi->lsmonitor);CHKERRQ(ierr);
21712b4ed282SShri Abhyankar   }
21722b4ed282SShri Abhyankar   PetscFunctionReturn(0);
21732b4ed282SShri Abhyankar }
21742b4ed282SShri Abhyankar EXTERN_C_END
21752b4ed282SShri Abhyankar 
21762b4ed282SShri Abhyankar /*
21772b4ed282SShri Abhyankar    SNESView_VI - Prints info from the SNESVI data structure.
21782b4ed282SShri Abhyankar 
21792b4ed282SShri Abhyankar    Input Parameters:
21802b4ed282SShri Abhyankar .  SNES - the SNES context
21812b4ed282SShri Abhyankar .  viewer - visualization context
21822b4ed282SShri Abhyankar 
21832b4ed282SShri Abhyankar    Application Interface Routine: SNESView()
21842b4ed282SShri Abhyankar */
21852b4ed282SShri Abhyankar #undef __FUNCT__
21862b4ed282SShri Abhyankar #define __FUNCT__ "SNESView_VI"
21872b4ed282SShri Abhyankar static PetscErrorCode SNESView_VI(SNES snes,PetscViewer viewer)
21882b4ed282SShri Abhyankar {
21892b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI *)snes->data;
219078c4b9d3SShri Abhyankar   const char     *cstr,*tstr;
21912b4ed282SShri Abhyankar   PetscErrorCode ierr;
2192ace3abfcSBarry Smith   PetscBool     iascii;
21932b4ed282SShri Abhyankar 
21942b4ed282SShri Abhyankar   PetscFunctionBegin;
21952b4ed282SShri Abhyankar   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
21962b4ed282SShri Abhyankar   if (iascii) {
21972b4ed282SShri Abhyankar     if (vi->LineSearch == SNESLineSearchNo_VI)             cstr = "SNESLineSearchNo";
21982b4ed282SShri Abhyankar     else if (vi->LineSearch == SNESLineSearchQuadratic_VI) cstr = "SNESLineSearchQuadratic";
21992b4ed282SShri Abhyankar     else if (vi->LineSearch == SNESLineSearchCubic_VI)     cstr = "SNESLineSearchCubic";
22002b4ed282SShri Abhyankar     else                                                   cstr = "unknown";
220178c4b9d3SShri Abhyankar     if (snes->ops->solve == SNESSolveVI_SS)         tstr = "Semismooth";
22020a7c7af0SShri Abhyankar     else if (snes->ops->solve == SNESSolveVI_RS)    tstr = "Reduced Space";
2203b350b9c9SBarry Smith     else if (snes->ops->solve == SNESSolveVI_RSAUG) tstr = "Reduced space with augmented variables";
220478c4b9d3SShri Abhyankar     else                                         tstr = "unknown";
220578c4b9d3SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  VI algorithm: %s\n",tstr);CHKERRQ(ierr);
22062b4ed282SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
22072b4ed282SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, minlambda=%G\n",vi->alpha,vi->maxstep,vi->minlambda);CHKERRQ(ierr);
22082b4ed282SShri Abhyankar   } else {
22092b4ed282SShri Abhyankar     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ VI",((PetscObject)viewer)->type_name);
22102b4ed282SShri Abhyankar   }
22112b4ed282SShri Abhyankar   PetscFunctionReturn(0);
22122b4ed282SShri Abhyankar }
22132b4ed282SShri Abhyankar 
22145559b345SBarry Smith #undef __FUNCT__
22155559b345SBarry Smith #define __FUNCT__ "SNESVISetVariableBounds"
22165559b345SBarry Smith /*@
22172b4ed282SShri Abhyankar    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.
22182b4ed282SShri Abhyankar 
22192b4ed282SShri Abhyankar    Input Parameters:
22202b4ed282SShri Abhyankar .  snes - the SNES context.
22212b4ed282SShri Abhyankar .  xl   - lower bound.
22222b4ed282SShri Abhyankar .  xu   - upper bound.
22232b4ed282SShri Abhyankar 
22242b4ed282SShri Abhyankar    Notes:
22252b4ed282SShri Abhyankar    If this routine is not called then the lower and upper bounds are set to
222601f0b76bSBarry Smith    SNES_VI_INF and SNES_VI_NINF respectively during SNESSetUp().
222784c105d7SBarry Smith 
22285559b345SBarry Smith @*/
222969c03620SShri Abhyankar PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
22302b4ed282SShri Abhyankar {
2231d923200aSJungho Lee   SNES_VI        *vi;
2232d923200aSJungho Lee   PetscErrorCode ierr;
22332b4ed282SShri Abhyankar 
22342b4ed282SShri Abhyankar   PetscFunctionBegin;
22352b4ed282SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
22362b4ed282SShri Abhyankar   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
22372b4ed282SShri Abhyankar   PetscValidHeaderSpecific(xu,VEC_CLASSID,3);
22382b4ed282SShri Abhyankar   if (!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() first");
22392b4ed282SShri 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);
22402b4ed282SShri 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);
2241d923200aSJungho Lee   ierr = SNESSetType(snes,SNESVI);CHKERRQ(ierr);
2242d923200aSJungho Lee   vi = (SNES_VI*)snes->data;
22432b4ed282SShri Abhyankar   vi->usersetxbounds = PETSC_TRUE;
22442b4ed282SShri Abhyankar   vi->xl = xl;
22452b4ed282SShri Abhyankar   vi->xu = xu;
22462b4ed282SShri Abhyankar   PetscFunctionReturn(0);
22472b4ed282SShri Abhyankar }
2248693ddf92SShri Abhyankar 
22492b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
22502b4ed282SShri Abhyankar /*
22512b4ed282SShri Abhyankar    SNESSetFromOptions_VI - Sets various parameters for the SNESVI method.
22522b4ed282SShri Abhyankar 
22532b4ed282SShri Abhyankar    Input Parameter:
22542b4ed282SShri Abhyankar .  snes - the SNES context
22552b4ed282SShri Abhyankar 
22562b4ed282SShri Abhyankar    Application Interface Routine: SNESSetFromOptions()
22572b4ed282SShri Abhyankar */
22582b4ed282SShri Abhyankar #undef __FUNCT__
22592b4ed282SShri Abhyankar #define __FUNCT__ "SNESSetFromOptions_VI"
22602b4ed282SShri Abhyankar static PetscErrorCode SNESSetFromOptions_VI(SNES snes)
22612b4ed282SShri Abhyankar {
22622b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI *)snes->data;
22637fe79bc4SShri Abhyankar   const char     *lses[] = {"basic","basicnonorms","quadratic","cubic"};
2264b350b9c9SBarry Smith   const char     *vies[] = {"ss","rs","rsaug"};
22652b4ed282SShri Abhyankar   PetscErrorCode ierr;
22662b4ed282SShri Abhyankar   PetscInt       indx;
226769c03620SShri Abhyankar   PetscBool      flg,set,flg2;
22682b4ed282SShri Abhyankar 
22692b4ed282SShri Abhyankar   PetscFunctionBegin;
22702b4ed282SShri Abhyankar   ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr);
22719308c137SBarry Smith   ierr = PetscOptionsBool("-snes_vi_monitor","Monitor all non-active variables","None",PETSC_FALSE,&flg,0);CHKERRQ(ierr);
22729308c137SBarry Smith   if (flg) {
22739308c137SBarry Smith     ierr = SNESMonitorSet(snes,SNESMonitorVI,0,0);CHKERRQ(ierr);
22749308c137SBarry Smith   }
2275be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",vi->alpha,&vi->alpha,0);CHKERRQ(ierr);
2276be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",vi->maxstep,&vi->maxstep,0);CHKERRQ(ierr);
2277be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_minlambda","Minimum lambda allowed","None",vi->minlambda,&vi->minlambda,0);CHKERRQ(ierr);
22782b4ed282SShri Abhyankar   ierr = PetscOptionsReal("-snes_vi_const_tol","constraint tolerance","None",vi->const_tol,&vi->const_tol,0);CHKERRQ(ierr);
2279be6adb11SBarry Smith   ierr = PetscOptionsBool("-snes_ls_monitor","Print progress of line searches","SNESLineSearchSetMonitor",vi->lsmonitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
22802b4ed282SShri Abhyankar   if (set) {ierr = SNESLineSearchSetMonitor(snes,flg);CHKERRQ(ierr);}
22812f63a38cSShri Abhyankar   ierr = PetscOptionsEList("-snes_vi_type","Semismooth algorithm used","",vies,3,"ss",&indx,&flg2);CHKERRQ(ierr);
228269c03620SShri Abhyankar   if (flg2) {
228369c03620SShri Abhyankar     switch (indx) {
228469c03620SShri Abhyankar     case 0:
228569c03620SShri Abhyankar       snes->ops->solve = SNESSolveVI_SS;
228669c03620SShri Abhyankar       break;
228769c03620SShri Abhyankar     case 1:
2288d950fb63SShri Abhyankar       snes->ops->solve = SNESSolveVI_RS;
2289d950fb63SShri Abhyankar       break;
22902f63a38cSShri Abhyankar     case 2:
2291b350b9c9SBarry Smith       snes->ops->solve = SNESSolveVI_RSAUG;
229269c03620SShri Abhyankar     }
229369c03620SShri Abhyankar   }
2294be6adb11SBarry Smith   ierr = PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"basic",&indx,&flg);CHKERRQ(ierr);
22952b4ed282SShri Abhyankar   if (flg) {
22962b4ed282SShri Abhyankar     switch (indx) {
22972b4ed282SShri Abhyankar     case 0:
22982b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);CHKERRQ(ierr);
22992b4ed282SShri Abhyankar       break;
23002b4ed282SShri Abhyankar     case 1:
23012b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);CHKERRQ(ierr);
23022b4ed282SShri Abhyankar       break;
23032b4ed282SShri Abhyankar     case 2:
23042b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);CHKERRQ(ierr);
23052b4ed282SShri Abhyankar       break;
23062b4ed282SShri Abhyankar     case 3:
23072b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);CHKERRQ(ierr);
23082b4ed282SShri Abhyankar       break;
23092b4ed282SShri Abhyankar     }
2310fe835674SShri Abhyankar   }
23112b4ed282SShri Abhyankar   ierr = PetscOptionsTail();CHKERRQ(ierr);
23122b4ed282SShri Abhyankar   PetscFunctionReturn(0);
23132b4ed282SShri Abhyankar }
23142b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
23152b4ed282SShri Abhyankar /*MC
23168b4c83edSBarry Smith       SNESVI - Various solvers for variational inequalities based on Newton's method
23172b4ed282SShri Abhyankar 
23182b4ed282SShri Abhyankar    Options Database:
23198b4c83edSBarry 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
23208b4c83edSBarry Smith                                 additional variables that enforce the constraints
23218b4c83edSBarry Smith -   -snes_vi_monitor - prints the number of active constraints at each iteration.
23222b4ed282SShri Abhyankar 
23232b4ed282SShri Abhyankar 
23242b4ed282SShri Abhyankar    Level: beginner
23252b4ed282SShri Abhyankar 
23262b4ed282SShri Abhyankar .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
23272b4ed282SShri Abhyankar            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
23282b4ed282SShri Abhyankar            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
23292b4ed282SShri Abhyankar 
23302b4ed282SShri Abhyankar M*/
23312b4ed282SShri Abhyankar EXTERN_C_BEGIN
23322b4ed282SShri Abhyankar #undef __FUNCT__
23332b4ed282SShri Abhyankar #define __FUNCT__ "SNESCreate_VI"
23347087cfbeSBarry Smith PetscErrorCode  SNESCreate_VI(SNES snes)
23352b4ed282SShri Abhyankar {
23362b4ed282SShri Abhyankar   PetscErrorCode ierr;
23372b4ed282SShri Abhyankar   SNES_VI      *vi;
23382b4ed282SShri Abhyankar 
23392b4ed282SShri Abhyankar   PetscFunctionBegin;
23402b4ed282SShri Abhyankar   snes->ops->setup           = SNESSetUp_VI;
2341edafb9efSBarry Smith   snes->ops->solve           = SNESSolveVI_RS;
23422b4ed282SShri Abhyankar   snes->ops->destroy         = SNESDestroy_VI;
23432b4ed282SShri Abhyankar   snes->ops->setfromoptions  = SNESSetFromOptions_VI;
23442b4ed282SShri Abhyankar   snes->ops->view            = SNESView_VI;
234537596af1SLisandro Dalcin   snes->ops->reset           = 0; /* XXX Implement!!! */
23462b4ed282SShri Abhyankar   snes->ops->converged       = SNESDefaultConverged_VI;
23472b4ed282SShri Abhyankar 
23482b4ed282SShri Abhyankar   ierr                  = PetscNewLog(snes,SNES_VI,&vi);CHKERRQ(ierr);
23492b4ed282SShri Abhyankar   snes->data            = (void*)vi;
23502b4ed282SShri Abhyankar   vi->alpha             = 1.e-4;
23512b4ed282SShri Abhyankar   vi->maxstep           = 1.e8;
23522b4ed282SShri Abhyankar   vi->minlambda         = 1.e-12;
23537fe79bc4SShri Abhyankar   vi->LineSearch        = SNESLineSearchNo_VI;
23542b4ed282SShri Abhyankar   vi->lsP               = PETSC_NULL;
23552b4ed282SShri Abhyankar   vi->postcheckstep     = PETSC_NULL;
23562b4ed282SShri Abhyankar   vi->postcheck         = PETSC_NULL;
23572b4ed282SShri Abhyankar   vi->precheckstep      = PETSC_NULL;
23582b4ed282SShri Abhyankar   vi->precheck          = PETSC_NULL;
23592b4ed282SShri Abhyankar   vi->const_tol         =  2.2204460492503131e-16;
23602f63a38cSShri Abhyankar   vi->checkredundancy   = PETSC_NULL;
23612b4ed282SShri Abhyankar 
23622b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_VI",SNESLineSearchSetMonitor_VI);CHKERRQ(ierr);
23632b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_VI",SNESLineSearchSet_VI);CHKERRQ(ierr);
23642b4ed282SShri Abhyankar 
23652b4ed282SShri Abhyankar   PetscFunctionReturn(0);
23662b4ed282SShri Abhyankar }
23672b4ed282SShri Abhyankar EXTERN_C_END
2368