xref: /petsc/src/snes/impls/vi/vi.c (revision 4dcab191b6ecfe0f91628c07d441680327aa1ed7)
12b4ed282SShri Abhyankar 
2c6db04a5SJed Brown #include <../src/snes/impls/vi/viimpl.h> /*I "petscsnes.h" I*/
3c6db04a5SJed Brown #include <../include/private/kspimpl.h>
4c6db04a5SJed Brown #include <../include/private/matimpl.h>
5d0af7cd3SBarry Smith #include <../include/private/dmimpl.h>
6d0af7cd3SBarry Smith 
7d0af7cd3SBarry Smith typedef struct {
8*4dcab191SBarry Smith   PetscInt       n;                                        /* size of vectors in the reduced DM space */
9d0af7cd3SBarry Smith   IS             inactive;
10d0af7cd3SBarry Smith   Vec            upper,lower,values,F;                    /* upper and lower bounds of all variables on this level, the values and the function values */
11d0af7cd3SBarry Smith   PetscErrorCode (*getinterpolation)(DM,DM,Mat*,Vec*);    /* DM's original routines */
12d0af7cd3SBarry Smith   PetscErrorCode (*coarsen)(DM, MPI_Comm, DM*);
13d0af7cd3SBarry Smith } DMSNESVI;
14d0af7cd3SBarry Smith 
15d0af7cd3SBarry Smith #undef __FUNCT__
16d0af7cd3SBarry Smith #define __FUNCT__ "SNESVIGetInActiveSetIS"
17d0af7cd3SBarry Smith /*
18d0af7cd3SBarry Smith    SNESVIGetInActiveSetIS - Gets the global indices for the bogus inactive set variables
19d0af7cd3SBarry Smith 
20d0af7cd3SBarry Smith    Input parameter
21d0af7cd3SBarry Smith .  snes - the SNES context
22d0af7cd3SBarry Smith .  X    - the snes solution vector
23d0af7cd3SBarry Smith 
24d0af7cd3SBarry Smith    Output parameter
25d0af7cd3SBarry Smith .  ISact - active set index set
26d0af7cd3SBarry Smith 
27d0af7cd3SBarry Smith  */
28d0af7cd3SBarry Smith PetscErrorCode SNESVIGetInActiveSetIS(Vec upper,Vec lower,Vec X,Vec F,IS* inact)
29d0af7cd3SBarry Smith {
30d0af7cd3SBarry Smith   PetscErrorCode   ierr;
31d0af7cd3SBarry Smith   const PetscScalar *x,*xl,*xu,*f;
32d0af7cd3SBarry Smith   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
33d0af7cd3SBarry Smith 
34d0af7cd3SBarry Smith   PetscFunctionBegin;
35d0af7cd3SBarry Smith   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
36d0af7cd3SBarry Smith   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
37d0af7cd3SBarry Smith   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
38d0af7cd3SBarry Smith   ierr = VecGetArrayRead(lower,&xl);CHKERRQ(ierr);
39d0af7cd3SBarry Smith   ierr = VecGetArrayRead(upper,&xu);CHKERRQ(ierr);
40d0af7cd3SBarry Smith   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
41d0af7cd3SBarry Smith   /* Compute inactive set size */
42d0af7cd3SBarry Smith   for (i=0; i < nlocal;i++) {
43d0af7cd3SBarry 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++;
44d0af7cd3SBarry Smith   }
45d0af7cd3SBarry Smith 
46d0af7cd3SBarry Smith   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
47d0af7cd3SBarry Smith 
48d0af7cd3SBarry Smith   /* Set inactive set indices */
49d0af7cd3SBarry Smith   for(i=0; i < nlocal; i++) {
50d0af7cd3SBarry 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;
51d0af7cd3SBarry Smith   }
52d0af7cd3SBarry Smith 
53d0af7cd3SBarry Smith    /* Create inactive set IS */
54d0af7cd3SBarry Smith   ierr = ISCreateGeneral(((PetscObject)upper)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,inact);CHKERRQ(ierr);
55d0af7cd3SBarry Smith 
56d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
57d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(lower,&xl);CHKERRQ(ierr);
58d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(upper,&xu);CHKERRQ(ierr);
59d0af7cd3SBarry Smith   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
60d0af7cd3SBarry Smith   PetscFunctionReturn(0);
61d0af7cd3SBarry Smith }
62d0af7cd3SBarry Smith 
63d0af7cd3SBarry Smith #undef __FUNCT__
64*4dcab191SBarry Smith #define __FUNCT__ "DMCreateGlobalVector_SNESVI"
65*4dcab191SBarry Smith /*
66*4dcab191SBarry Smith      DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space
67*4dcab191SBarry Smith 
68*4dcab191SBarry Smith */
69*4dcab191SBarry Smith PetscErrorCode  DMCreateGlobalVector_SNESVI(DM dm,Vec *vec)
70*4dcab191SBarry Smith {
71*4dcab191SBarry Smith   PetscErrorCode          ierr;
72*4dcab191SBarry Smith   PetscContainer          isnes;
73*4dcab191SBarry Smith   DMSNESVI                *dmsnesvi;
74*4dcab191SBarry Smith 
75*4dcab191SBarry Smith   PetscFunctionBegin;
76*4dcab191SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
77*4dcab191SBarry Smith   if (!isnes) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
78*4dcab191SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
79*4dcab191SBarry Smith   ierr = VecCreateMPI(((PetscObject)dm)->comm,dmsnesvi->n,PETSC_DETERMINE,vec);CHKERRQ(ierr);
80*4dcab191SBarry Smith   PetscFunctionReturn(0);
81*4dcab191SBarry Smith }
82*4dcab191SBarry Smith 
83*4dcab191SBarry Smith #undef __FUNCT__
84d0af7cd3SBarry Smith #define __FUNCT__ "DMGetInterpolation_SNESVI"
85d0af7cd3SBarry Smith /*
86d0af7cd3SBarry Smith      DMGetInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints.
87d0af7cd3SBarry Smith 
88d0af7cd3SBarry Smith */
89d0af7cd3SBarry Smith PetscErrorCode  DMGetInterpolation_SNESVI(DM dm1,DM dm2,Mat *mat,Vec *vec)
90d0af7cd3SBarry Smith {
91d0af7cd3SBarry Smith   PetscErrorCode          ierr;
92d0af7cd3SBarry Smith   PetscContainer          isnes;
93d0af7cd3SBarry Smith   DMSNESVI                *dmsnesvi1,*dmsnesvi2;
94d0af7cd3SBarry Smith   Mat                     interp;
95d0af7cd3SBarry Smith 
96d0af7cd3SBarry Smith   PetscFunctionBegin;
97d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
98*4dcab191SBarry Smith   if (!isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
99d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
100d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm2,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
101*4dcab191SBarry Smith   if (!isnes) SETERRQ(((PetscObject)dm2)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
102d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi2);CHKERRQ(ierr);
103d0af7cd3SBarry Smith 
104d0af7cd3SBarry Smith   ierr = (*dmsnesvi1->getinterpolation)(dm1,dm2,&interp,PETSC_NULL);CHKERRQ(ierr);
105*4dcab191SBarry Smith   ierr = MatGetSubMatrix(interp,dmsnesvi2->inactive,dmsnesvi1->inactive,MAT_INITIAL_MATRIX,mat);CHKERRQ(ierr);
106d0af7cd3SBarry Smith   ierr = MatDestroy(&interp);CHKERRQ(ierr);
107d0af7cd3SBarry Smith   PetscFunctionReturn(0);
108d0af7cd3SBarry Smith }
109d0af7cd3SBarry Smith 
110d0af7cd3SBarry Smith extern PetscErrorCode  DMSetVI(DM,Vec,Vec,Vec,Vec,IS);
111d0af7cd3SBarry Smith 
112d0af7cd3SBarry Smith #undef __FUNCT__
113d0af7cd3SBarry Smith #define __FUNCT__ "DMCoarsen_SNESVI"
114d0af7cd3SBarry Smith /*
115d0af7cd3SBarry Smith      DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set
116d0af7cd3SBarry Smith 
117d0af7cd3SBarry Smith */
118d0af7cd3SBarry Smith PetscErrorCode  DMCoarsen_SNESVI(DM dm1,MPI_Comm comm,DM *dm2)
119d0af7cd3SBarry Smith {
120d0af7cd3SBarry Smith   PetscErrorCode          ierr;
121d0af7cd3SBarry Smith   PetscContainer          isnes;
122d0af7cd3SBarry Smith   DMSNESVI                *dmsnesvi1;
123d0af7cd3SBarry Smith   Vec                     upper,lower,values,F;
124d0af7cd3SBarry Smith   IS                      inactive;
125d0af7cd3SBarry Smith   VecScatter              inject;
126d0af7cd3SBarry Smith 
127d0af7cd3SBarry Smith   PetscFunctionBegin;
128d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
129*4dcab191SBarry Smith   if (!isnes) SETERRQ(((PetscObject)dm1)->comm,PETSC_ERR_PLIB,"Composed SNES is missing");
130d0af7cd3SBarry Smith   ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr);
131d0af7cd3SBarry Smith 
132d0af7cd3SBarry Smith   ierr = (*dmsnesvi1->coarsen)(dm1,comm,dm2);CHKERRQ(ierr);
133d0af7cd3SBarry Smith   ierr = DMGetInjection(*dm2,dm1,&inject);CHKERRQ(ierr);
134d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&upper);CHKERRQ(ierr);
135d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->upper,upper,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
136d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->upper,upper,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
137d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&lower);CHKERRQ(ierr);
138d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->lower,lower,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
139d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->lower,lower,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
140d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&values);CHKERRQ(ierr);
141d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->values,values,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
142d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->values,values,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
143d0af7cd3SBarry Smith   ierr = DMCreateGlobalVector(*dm2,&F);CHKERRQ(ierr);
144d0af7cd3SBarry Smith   ierr = VecScatterBegin(inject,dmsnesvi1->F,F,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
145d0af7cd3SBarry Smith   ierr = VecScatterEnd(inject,dmsnesvi1->F,F,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
146d0af7cd3SBarry Smith   ierr = VecScatterDestroy(&inject);CHKERRQ(ierr);
147d0af7cd3SBarry Smith   ierr = SNESVIGetInActiveSetIS(upper,lower,values,F,&inactive);CHKERRQ(ierr);
148d0af7cd3SBarry Smith   ierr = DMSetVI(*dm2,upper,lower,values,F,inactive);CHKERRQ(ierr);
149d0af7cd3SBarry Smith   PetscFunctionReturn(0);
150d0af7cd3SBarry Smith }
151d0af7cd3SBarry Smith 
152d0af7cd3SBarry Smith #undef __FUNCT__
153d0af7cd3SBarry Smith #define __FUNCT__ "DMSNESVIDestroy"
154d0af7cd3SBarry Smith PetscErrorCode DMSNESVIDestroy(DMSNESVI *dmsnesvi)
155d0af7cd3SBarry Smith {
156d0af7cd3SBarry Smith   PetscErrorCode ierr;
157d0af7cd3SBarry Smith 
158d0af7cd3SBarry Smith   PetscFunctionBegin;
159d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->upper);CHKERRQ(ierr);
160d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->lower);CHKERRQ(ierr);
161d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->values);CHKERRQ(ierr);
162d0af7cd3SBarry Smith   ierr = VecDestroy(&dmsnesvi->F);CHKERRQ(ierr);
163d0af7cd3SBarry Smith   ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
164d0af7cd3SBarry Smith   ierr = PetscFree(dmsnesvi);CHKERRQ(ierr);
165d0af7cd3SBarry Smith   PetscFunctionReturn(0);
166d0af7cd3SBarry Smith }
167d0af7cd3SBarry Smith 
168d0af7cd3SBarry Smith #undef __FUNCT__
169d0af7cd3SBarry Smith #define __FUNCT__ "DMSetVI"
170d0af7cd3SBarry Smith /*
171d0af7cd3SBarry Smith      DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to
172d0af7cd3SBarry Smith                be restricted to only those variables NOT associated with active constraints.
173d0af7cd3SBarry Smith 
174d0af7cd3SBarry Smith */
175d0af7cd3SBarry Smith PetscErrorCode  DMSetVI(DM dm,Vec upper,Vec lower,Vec values,Vec F,IS inactive)
176d0af7cd3SBarry Smith {
177d0af7cd3SBarry Smith   PetscErrorCode          ierr;
178d0af7cd3SBarry Smith   PetscContainer          isnes;
179d0af7cd3SBarry Smith   DMSNESVI                *dmsnesvi;
180d0af7cd3SBarry Smith 
181d0af7cd3SBarry Smith   PetscFunctionBegin;
182*4dcab191SBarry Smith   if (!dm) PetscFunctionReturn(0);
183d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)upper);CHKERRQ(ierr);
184d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)lower);CHKERRQ(ierr);
185d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)values);CHKERRQ(ierr);
186d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)F);CHKERRQ(ierr);
187d0af7cd3SBarry Smith   ierr = PetscObjectReference((PetscObject)inactive);CHKERRQ(ierr);
188d0af7cd3SBarry Smith 
189d0af7cd3SBarry Smith   ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject *)&isnes);CHKERRQ(ierr);
190d0af7cd3SBarry Smith   if (!isnes) {
191d0af7cd3SBarry Smith     /* cannot just compose snes into dm because that will cause circular reference */
192d0af7cd3SBarry Smith     ierr = PetscContainerCreate(((PetscObject)dm)->comm,&isnes);CHKERRQ(ierr);
193d0af7cd3SBarry Smith     ierr = PetscContainerSetUserDestroy(isnes,(PetscErrorCode (*)(void*))DMSNESVIDestroy);CHKERRQ(ierr);
194d0af7cd3SBarry Smith     ierr = PetscNew(DMSNESVI,&dmsnesvi);CHKERRQ(ierr);
195d0af7cd3SBarry Smith     ierr = PetscContainerSetPointer(isnes,(void*)dmsnesvi);CHKERRQ(ierr);
196d0af7cd3SBarry Smith     ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)isnes);CHKERRQ(ierr);
197d0af7cd3SBarry Smith     dmsnesvi->getinterpolation  = dm->ops->getinterpolation;
198d0af7cd3SBarry Smith     dm->ops->getinterpolation   = DMGetInterpolation_SNESVI;
199d0af7cd3SBarry Smith     dmsnesvi->coarsen           = dm->ops->coarsen;
200d0af7cd3SBarry Smith     dm->ops->coarsen            = DMCoarsen_SNESVI;
201*4dcab191SBarry Smith     dm->ops->createglobalvector = DMCreateGlobalVector_SNESVI;
202d0af7cd3SBarry Smith   } else {
203d0af7cd3SBarry Smith     ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr);
204d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->upper);CHKERRQ(ierr);
205d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->lower);CHKERRQ(ierr);
206d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->values);CHKERRQ(ierr);
207d0af7cd3SBarry Smith     ierr = VecDestroy(&dmsnesvi->F);CHKERRQ(ierr);
208d0af7cd3SBarry Smith     ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr);
209d0af7cd3SBarry Smith   }
210*4dcab191SBarry Smith   ierr = DMClearGlobalVectors(dm);CHKERRQ(ierr);
211*4dcab191SBarry Smith   ierr = ISGetLocalSize(inactive,&dmsnesvi->n);CHKERRQ(ierr);
212d0af7cd3SBarry Smith   dmsnesvi->upper    = upper;
213d0af7cd3SBarry Smith   dmsnesvi->lower    = lower;
214d0af7cd3SBarry Smith   dmsnesvi->values   = values;
215d0af7cd3SBarry Smith   dmsnesvi->F        = F;
216d0af7cd3SBarry Smith   dmsnesvi->inactive = inactive;
217d0af7cd3SBarry Smith   PetscFunctionReturn(0);
218d0af7cd3SBarry Smith }
219d0af7cd3SBarry Smith 
220d0af7cd3SBarry Smith 
2212b4ed282SShri Abhyankar 
2229308c137SBarry Smith #undef __FUNCT__
2239308c137SBarry Smith #define __FUNCT__ "SNESMonitorVI"
2247087cfbeSBarry Smith PetscErrorCode  SNESMonitorVI(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
2259308c137SBarry Smith {
2269308c137SBarry Smith   PetscErrorCode          ierr;
2279308c137SBarry Smith   SNES_VI                 *vi = (SNES_VI*)snes->data;
2289308c137SBarry Smith   PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor) dummy;
2299308c137SBarry Smith   const PetscScalar       *x,*xl,*xu,*f;
23009573ac7SBarry Smith   PetscInt                i,n,act = 0;
2319308c137SBarry Smith   PetscReal               rnorm,fnorm;
2329308c137SBarry Smith 
2339308c137SBarry Smith   PetscFunctionBegin;
2349308c137SBarry Smith   if (!dummy) {
2359308c137SBarry Smith     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)snes)->comm,"stdout",0,&viewer);CHKERRQ(ierr);
2369308c137SBarry Smith   }
2379308c137SBarry Smith   ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
2389308c137SBarry Smith   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
2399308c137SBarry Smith   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
2409308c137SBarry Smith   ierr = VecGetArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
2413f731af5SBarry Smith   ierr = VecGetArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
2429308c137SBarry Smith 
2439308c137SBarry Smith   rnorm = 0.0;
2449308c137SBarry Smith   for (i=0; i<n; i++) {
24510f5ae6bSBarry 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]);
24609573ac7SBarry Smith     else act++;
2479308c137SBarry Smith   }
2483f731af5SBarry Smith   ierr = VecRestoreArrayRead(snes->vec_func,&f);CHKERRQ(ierr);
2499308c137SBarry Smith   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
2509308c137SBarry Smith   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
2519308c137SBarry Smith   ierr = VecRestoreArrayRead(snes->vec_sol,&x);CHKERRQ(ierr);
252d9822059SBarry Smith   ierr = MPI_Allreduce(&rnorm,&fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
2539308c137SBarry Smith   fnorm = sqrt(fnorm);
25409573ac7SBarry Smith   ierr = PetscViewerASCIIMonitorPrintf(viewer,"%3D SNES VI Function norm %14.12e Active constraints %D\n",its,fnorm,act);CHKERRQ(ierr);
2559308c137SBarry Smith   if (!dummy) {
2566bf464f9SBarry Smith     ierr = PetscViewerASCIIMonitorDestroy(&viewer);CHKERRQ(ierr);
2579308c137SBarry Smith   }
2589308c137SBarry Smith   PetscFunctionReturn(0);
2599308c137SBarry Smith }
2609308c137SBarry Smith 
2612b4ed282SShri Abhyankar /*
2622b4ed282SShri Abhyankar      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
2632b4ed282SShri 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
2642b4ed282SShri Abhyankar     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More
2652b4ed282SShri Abhyankar     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
2662b4ed282SShri Abhyankar */
2672b4ed282SShri Abhyankar #undef __FUNCT__
2682b4ed282SShri Abhyankar #define __FUNCT__ "SNESVICheckLocalMin_Private"
269ace3abfcSBarry Smith PetscErrorCode SNESVICheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool *ismin)
2702b4ed282SShri Abhyankar {
2712b4ed282SShri Abhyankar   PetscReal      a1;
2722b4ed282SShri Abhyankar   PetscErrorCode ierr;
273ace3abfcSBarry Smith   PetscBool     hastranspose;
2742b4ed282SShri Abhyankar 
2752b4ed282SShri Abhyankar   PetscFunctionBegin;
2762b4ed282SShri Abhyankar   *ismin = PETSC_FALSE;
2772b4ed282SShri Abhyankar   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
2782b4ed282SShri Abhyankar   if (hastranspose) {
2792b4ed282SShri Abhyankar     /* Compute || J^T F|| */
2802b4ed282SShri Abhyankar     ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr);
2812b4ed282SShri Abhyankar     ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr);
2822b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);CHKERRQ(ierr);
2832b4ed282SShri Abhyankar     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
2842b4ed282SShri Abhyankar   } else {
2852b4ed282SShri Abhyankar     Vec         work;
2862b4ed282SShri Abhyankar     PetscScalar result;
2872b4ed282SShri Abhyankar     PetscReal   wnorm;
2882b4ed282SShri Abhyankar 
2892b4ed282SShri Abhyankar     ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr);
2902b4ed282SShri Abhyankar     ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr);
2912b4ed282SShri Abhyankar     ierr = VecDuplicate(W,&work);CHKERRQ(ierr);
2922b4ed282SShri Abhyankar     ierr = MatMult(A,W,work);CHKERRQ(ierr);
2932b4ed282SShri Abhyankar     ierr = VecDot(F,work,&result);CHKERRQ(ierr);
2946bf464f9SBarry Smith     ierr = VecDestroy(&work);CHKERRQ(ierr);
2952b4ed282SShri Abhyankar     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
2962b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);CHKERRQ(ierr);
2972b4ed282SShri Abhyankar     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
2982b4ed282SShri Abhyankar   }
2992b4ed282SShri Abhyankar   PetscFunctionReturn(0);
3002b4ed282SShri Abhyankar }
3012b4ed282SShri Abhyankar 
3022b4ed282SShri Abhyankar /*
3032b4ed282SShri Abhyankar      Checks if J^T(F - J*X) = 0
3042b4ed282SShri Abhyankar */
3052b4ed282SShri Abhyankar #undef __FUNCT__
3062b4ed282SShri Abhyankar #define __FUNCT__ "SNESVICheckResidual_Private"
3072b4ed282SShri Abhyankar PetscErrorCode SNESVICheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
3082b4ed282SShri Abhyankar {
3092b4ed282SShri Abhyankar   PetscReal      a1,a2;
3102b4ed282SShri Abhyankar   PetscErrorCode ierr;
311ace3abfcSBarry Smith   PetscBool     hastranspose;
3122b4ed282SShri Abhyankar 
3132b4ed282SShri Abhyankar   PetscFunctionBegin;
3142b4ed282SShri Abhyankar   ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr);
3152b4ed282SShri Abhyankar   if (hastranspose) {
3162b4ed282SShri Abhyankar     ierr = MatMult(A,X,W1);CHKERRQ(ierr);
3172b4ed282SShri Abhyankar     ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr);
3182b4ed282SShri Abhyankar 
3192b4ed282SShri Abhyankar     /* Compute || J^T W|| */
3202b4ed282SShri Abhyankar     ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr);
3212b4ed282SShri Abhyankar     ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr);
3222b4ed282SShri Abhyankar     ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr);
3232b4ed282SShri Abhyankar     if (a1 != 0.0) {
3242b4ed282SShri Abhyankar       ierr = PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);CHKERRQ(ierr);
3252b4ed282SShri Abhyankar     }
3262b4ed282SShri Abhyankar   }
3272b4ed282SShri Abhyankar   PetscFunctionReturn(0);
3282b4ed282SShri Abhyankar }
3292b4ed282SShri Abhyankar 
3302b4ed282SShri Abhyankar /*
3312b4ed282SShri Abhyankar   SNESDefaultConverged_VI - Checks the convergence of the semismooth newton algorithm.
3322b4ed282SShri Abhyankar 
3332b4ed282SShri Abhyankar   Notes:
3342b4ed282SShri Abhyankar   The convergence criterion currently implemented is
3352b4ed282SShri Abhyankar   merit < abstol
3362b4ed282SShri Abhyankar   merit < rtol*merit_initial
3372b4ed282SShri Abhyankar */
3382b4ed282SShri Abhyankar #undef __FUNCT__
3392b4ed282SShri Abhyankar #define __FUNCT__ "SNESDefaultConverged_VI"
3407fe79bc4SShri Abhyankar PetscErrorCode SNESDefaultConverged_VI(SNES snes,PetscInt it,PetscReal xnorm,PetscReal gradnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
3412b4ed282SShri Abhyankar {
3422b4ed282SShri Abhyankar   PetscErrorCode ierr;
3432b4ed282SShri Abhyankar 
3442b4ed282SShri Abhyankar   PetscFunctionBegin;
3452b4ed282SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
3462b4ed282SShri Abhyankar   PetscValidPointer(reason,6);
3472b4ed282SShri Abhyankar 
3482b4ed282SShri Abhyankar   *reason = SNES_CONVERGED_ITERATING;
3492b4ed282SShri Abhyankar 
3502b4ed282SShri Abhyankar   if (!it) {
3512b4ed282SShri Abhyankar     /* set parameter for default relative tolerance convergence test */
3527fe79bc4SShri Abhyankar     snes->ttol = fnorm*snes->rtol;
3532b4ed282SShri Abhyankar   }
3547fe79bc4SShri Abhyankar   if (fnorm != fnorm) {
3552b4ed282SShri Abhyankar     ierr = PetscInfo(snes,"Failed to converged, function norm is NaN\n");CHKERRQ(ierr);
3562b4ed282SShri Abhyankar     *reason = SNES_DIVERGED_FNORM_NAN;
3577fe79bc4SShri Abhyankar   } else if (fnorm < snes->abstol) {
3587fe79bc4SShri Abhyankar     ierr = PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);CHKERRQ(ierr);
3592b4ed282SShri Abhyankar     *reason = SNES_CONVERGED_FNORM_ABS;
3602b4ed282SShri Abhyankar   } else if (snes->nfuncs >= snes->max_funcs) {
3612b4ed282SShri Abhyankar     ierr = PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);CHKERRQ(ierr);
3622b4ed282SShri Abhyankar     *reason = SNES_DIVERGED_FUNCTION_COUNT;
3632b4ed282SShri Abhyankar   }
3642b4ed282SShri Abhyankar 
3652b4ed282SShri Abhyankar   if (it && !*reason) {
3667fe79bc4SShri Abhyankar     if (fnorm < snes->ttol) {
3677fe79bc4SShri Abhyankar       ierr = PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);CHKERRQ(ierr);
3682b4ed282SShri Abhyankar       *reason = SNES_CONVERGED_FNORM_RELATIVE;
3692b4ed282SShri Abhyankar     }
3702b4ed282SShri Abhyankar   }
3712b4ed282SShri Abhyankar   PetscFunctionReturn(0);
3722b4ed282SShri Abhyankar }
3732b4ed282SShri Abhyankar 
3742b4ed282SShri Abhyankar /*
3752b4ed282SShri Abhyankar   SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem.
3762b4ed282SShri Abhyankar 
3772b4ed282SShri Abhyankar   Input Parameter:
3782b4ed282SShri Abhyankar . phi - the semismooth function
3792b4ed282SShri Abhyankar 
3802b4ed282SShri Abhyankar   Output Parameter:
3812b4ed282SShri Abhyankar . merit - the merit function
3822b4ed282SShri Abhyankar . phinorm - ||phi||
3832b4ed282SShri Abhyankar 
3842b4ed282SShri Abhyankar   Notes:
3852b4ed282SShri Abhyankar   The merit function for the mixed complementarity problem is defined as
3862b4ed282SShri Abhyankar      merit = 0.5*phi^T*phi
3872b4ed282SShri Abhyankar */
3882b4ed282SShri Abhyankar #undef __FUNCT__
3892b4ed282SShri Abhyankar #define __FUNCT__ "SNESVIComputeMeritFunction"
3902b4ed282SShri Abhyankar static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm)
3912b4ed282SShri Abhyankar {
3922b4ed282SShri Abhyankar   PetscErrorCode ierr;
3932b4ed282SShri Abhyankar 
3942b4ed282SShri Abhyankar   PetscFunctionBegin;
3955f48b12bSBarry Smith   ierr = VecNormBegin(phi,NORM_2,phinorm);CHKERRQ(ierr);
3965f48b12bSBarry Smith   ierr = VecNormEnd(phi,NORM_2,phinorm);CHKERRQ(ierr);
3972b4ed282SShri Abhyankar 
3982b4ed282SShri Abhyankar   *merit = 0.5*(*phinorm)*(*phinorm);
3992b4ed282SShri Abhyankar   PetscFunctionReturn(0);
4002b4ed282SShri Abhyankar }
4012b4ed282SShri Abhyankar 
4027f6f51e9SSatish Balay PETSC_STATIC_INLINE PetscScalar Phi(PetscScalar a,PetscScalar b)
4034c21c6cdSBarry Smith {
4044c21c6cdSBarry Smith   return a + b - sqrt(a*a + b*b);
4054c21c6cdSBarry Smith }
4064c21c6cdSBarry Smith 
4077f6f51e9SSatish Balay PETSC_STATIC_INLINE PetscScalar DPhi(PetscScalar a,PetscScalar b)
4084c21c6cdSBarry Smith {
4095559b345SBarry Smith   if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return  1.0 - a/ sqrt(a*a + b*b);
4105559b345SBarry Smith   else return .5;
4114c21c6cdSBarry Smith }
4124c21c6cdSBarry Smith 
4132b4ed282SShri Abhyankar /*
4141f79c099SShri Abhyankar    SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form.
4152b4ed282SShri Abhyankar 
4162b4ed282SShri Abhyankar    Input Parameters:
4172b4ed282SShri Abhyankar .  snes - the SNES context
4182b4ed282SShri Abhyankar .  x - current iterate
4192b4ed282SShri Abhyankar .  functx - user defined function context
4202b4ed282SShri Abhyankar 
4212b4ed282SShri Abhyankar    Output Parameters:
4222b4ed282SShri Abhyankar .  phi - Semismooth function
4232b4ed282SShri Abhyankar 
4242b4ed282SShri Abhyankar */
4252b4ed282SShri Abhyankar #undef __FUNCT__
4261f79c099SShri Abhyankar #define __FUNCT__ "SNESVIComputeFunction"
4271f79c099SShri Abhyankar static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void* functx)
4282b4ed282SShri Abhyankar {
4292b4ed282SShri Abhyankar   PetscErrorCode  ierr;
4302b4ed282SShri Abhyankar   SNES_VI         *vi = (SNES_VI*)snes->data;
4312b4ed282SShri Abhyankar   Vec             Xl = vi->xl,Xu = vi->xu,F = snes->vec_func;
4324c21c6cdSBarry Smith   PetscScalar     *phi_arr,*x_arr,*f_arr,*l,*u;
4332b4ed282SShri Abhyankar   PetscInt        i,nlocal;
4342b4ed282SShri Abhyankar 
4352b4ed282SShri Abhyankar   PetscFunctionBegin;
4362b4ed282SShri Abhyankar   ierr = (*vi->computeuserfunction)(snes,X,F,functx);CHKERRQ(ierr);
4372b4ed282SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
4382b4ed282SShri Abhyankar   ierr = VecGetArray(X,&x_arr);CHKERRQ(ierr);
4392b4ed282SShri Abhyankar   ierr = VecGetArray(F,&f_arr);CHKERRQ(ierr);
4402b4ed282SShri Abhyankar   ierr = VecGetArray(Xl,&l);CHKERRQ(ierr);
4412b4ed282SShri Abhyankar   ierr = VecGetArray(Xu,&u);CHKERRQ(ierr);
4422b4ed282SShri Abhyankar   ierr = VecGetArray(phi,&phi_arr);CHKERRQ(ierr);
4432b4ed282SShri Abhyankar 
4442b4ed282SShri Abhyankar   for (i=0;i < nlocal;i++) {
44510f5ae6bSBarry Smith     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) { /* no constraints on variable */
4464c21c6cdSBarry Smith       phi_arr[i] = f_arr[i];
44710f5ae6bSBarry Smith     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                      /* upper bound on variable only */
4484c21c6cdSBarry Smith       phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]);
44910f5ae6bSBarry Smith     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                       /* lower bound on variable only */
4504c21c6cdSBarry Smith       phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]);
4515559b345SBarry Smith     } else if (l[i] == u[i]) {
4522b4ed282SShri Abhyankar       phi_arr[i] = l[i] - x_arr[i];
4535559b345SBarry Smith     } else {                                                /* both bounds on variable */
4544c21c6cdSBarry Smith       phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i]));
4552b4ed282SShri Abhyankar     }
4562b4ed282SShri Abhyankar   }
4572b4ed282SShri Abhyankar 
4582b4ed282SShri Abhyankar   ierr = VecRestoreArray(X,&x_arr);CHKERRQ(ierr);
4592b4ed282SShri Abhyankar   ierr = VecRestoreArray(F,&f_arr);CHKERRQ(ierr);
4602b4ed282SShri Abhyankar   ierr = VecRestoreArray(Xl,&l);CHKERRQ(ierr);
4612b4ed282SShri Abhyankar   ierr = VecRestoreArray(Xu,&u);CHKERRQ(ierr);
4622b4ed282SShri Abhyankar   ierr = VecRestoreArray(phi,&phi_arr);CHKERRQ(ierr);
4632b4ed282SShri Abhyankar   PetscFunctionReturn(0);
4642b4ed282SShri Abhyankar }
4652b4ed282SShri Abhyankar 
4662b4ed282SShri Abhyankar /*
467a79edbefSShri Abhyankar    SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the
468a79edbefSShri Abhyankar                                           the semismooth jacobian.
4692b4ed282SShri Abhyankar */
4702b4ed282SShri Abhyankar #undef __FUNCT__
471a79edbefSShri Abhyankar #define __FUNCT__ "SNESVIComputeBsubdifferentialVectors"
472a79edbefSShri Abhyankar PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db)
4732b4ed282SShri Abhyankar {
4742b4ed282SShri Abhyankar   PetscErrorCode ierr;
4752b4ed282SShri Abhyankar   SNES_VI      *vi = (SNES_VI*)snes->data;
4764c21c6cdSBarry Smith   PetscScalar    *l,*u,*x,*f,*da,*db,da1,da2,db1,db2;
4772b4ed282SShri Abhyankar   PetscInt       i,nlocal;
4782b4ed282SShri Abhyankar 
4792b4ed282SShri Abhyankar   PetscFunctionBegin;
4802b4ed282SShri Abhyankar 
4812b4ed282SShri Abhyankar   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
4822b4ed282SShri Abhyankar   ierr = VecGetArray(F,&f);CHKERRQ(ierr);
4832b4ed282SShri Abhyankar   ierr = VecGetArray(vi->xl,&l);CHKERRQ(ierr);
4842b4ed282SShri Abhyankar   ierr = VecGetArray(vi->xu,&u);CHKERRQ(ierr);
485a79edbefSShri Abhyankar   ierr = VecGetArray(Da,&da);CHKERRQ(ierr);
486a79edbefSShri Abhyankar   ierr = VecGetArray(Db,&db);CHKERRQ(ierr);
4872b4ed282SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
4884c21c6cdSBarry Smith 
4892b4ed282SShri Abhyankar   for (i=0;i< nlocal;i++) {
49010f5ae6bSBarry Smith     if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) {/* no constraints on variable */
4914c21c6cdSBarry Smith       da[i] = 0;
4922b4ed282SShri Abhyankar       db[i] = 1;
49310f5ae6bSBarry Smith     } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) {                     /* upper bound on variable only */
4944c21c6cdSBarry Smith       da[i] = DPhi(u[i] - x[i], -f[i]);
4954c21c6cdSBarry Smith       db[i] = DPhi(-f[i],u[i] - x[i]);
49610f5ae6bSBarry Smith     } else if (PetscRealPart(u[i]) >= SNES_VI_INF) {                      /* lower bound on variable only */
4975559b345SBarry Smith       da[i] = DPhi(x[i] - l[i], f[i]);
4985559b345SBarry Smith       db[i] = DPhi(f[i],x[i] - l[i]);
4995559b345SBarry Smith     } else if (l[i] == u[i]) {                              /* fixed variable */
5004c21c6cdSBarry Smith       da[i] = 1;
5012b4ed282SShri Abhyankar       db[i] = 0;
5025559b345SBarry Smith     } else {                                                /* upper and lower bounds on variable */
5034c21c6cdSBarry Smith       da1 = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i]));
5044c21c6cdSBarry Smith       db1 = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]);
5054c21c6cdSBarry Smith       da2 = DPhi(u[i] - x[i], -f[i]);
5064c21c6cdSBarry Smith       db2 = DPhi(-f[i],u[i] - x[i]);
5074c21c6cdSBarry Smith       da[i] = da1 + db1*da2;
5084c21c6cdSBarry Smith       db[i] = db1*db2;
5092b4ed282SShri Abhyankar     }
5102b4ed282SShri Abhyankar   }
5115559b345SBarry Smith 
5122b4ed282SShri Abhyankar   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
5132b4ed282SShri Abhyankar   ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
5142b4ed282SShri Abhyankar   ierr = VecRestoreArray(vi->xl,&l);CHKERRQ(ierr);
5152b4ed282SShri Abhyankar   ierr = VecRestoreArray(vi->xu,&u);CHKERRQ(ierr);
516a79edbefSShri Abhyankar   ierr = VecRestoreArray(Da,&da);CHKERRQ(ierr);
517a79edbefSShri Abhyankar   ierr = VecRestoreArray(Db,&db);CHKERRQ(ierr);
518a79edbefSShri Abhyankar   PetscFunctionReturn(0);
519a79edbefSShri Abhyankar }
520a79edbefSShri Abhyankar 
521a79edbefSShri Abhyankar /*
522a79edbefSShri 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.
523a79edbefSShri Abhyankar 
524a79edbefSShri Abhyankar    Input Parameters:
525a79edbefSShri Abhyankar .  Da       - Diagonal shift vector for the semismooth jacobian.
526a79edbefSShri Abhyankar .  Db       - Row scaling vector for the semismooth jacobian.
527a79edbefSShri Abhyankar 
528a79edbefSShri Abhyankar    Output Parameters:
529a79edbefSShri Abhyankar .  jac      - semismooth jacobian
530a79edbefSShri Abhyankar .  jac_pre  - optional preconditioning matrix
531a79edbefSShri Abhyankar 
532a79edbefSShri Abhyankar    Notes:
533a79edbefSShri Abhyankar    The semismooth jacobian matrix is given by
534a79edbefSShri Abhyankar    jac = Da + Db*jacfun
535a79edbefSShri Abhyankar    where Db is the row scaling matrix stored as a vector,
536a79edbefSShri Abhyankar          Da is the diagonal perturbation matrix stored as a vector
537a79edbefSShri Abhyankar    and   jacfun is the jacobian of the original nonlinear function.
538a79edbefSShri Abhyankar */
539a79edbefSShri Abhyankar #undef __FUNCT__
540a79edbefSShri Abhyankar #define __FUNCT__ "SNESVIComputeJacobian"
541a79edbefSShri Abhyankar PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db)
542a79edbefSShri Abhyankar {
543a79edbefSShri Abhyankar   PetscErrorCode ierr;
544a79edbefSShri Abhyankar 
5452b4ed282SShri Abhyankar   /* Do row scaling  and add diagonal perturbation */
546a79edbefSShri Abhyankar   ierr = MatDiagonalScale(jac,Db,PETSC_NULL);CHKERRQ(ierr);
547a79edbefSShri Abhyankar   ierr = MatDiagonalSet(jac,Da,ADD_VALUES);CHKERRQ(ierr);
548a79edbefSShri Abhyankar   if (jac != jac_pre) { /* If jac and jac_pre are different */
549a79edbefSShri Abhyankar     ierr = MatDiagonalScale(jac_pre,Db,PETSC_NULL);
550a79edbefSShri Abhyankar     ierr = MatDiagonalSet(jac_pre,Da,ADD_VALUES);CHKERRQ(ierr);
5512b4ed282SShri Abhyankar   }
5522b4ed282SShri Abhyankar   PetscFunctionReturn(0);
5532b4ed282SShri Abhyankar }
5542b4ed282SShri Abhyankar 
5552b4ed282SShri Abhyankar /*
556ee657d29SShri Abhyankar    SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi.
557ee657d29SShri Abhyankar 
558ee657d29SShri Abhyankar    Input Parameters:
559ee657d29SShri Abhyankar    phi - semismooth function.
560ee657d29SShri Abhyankar    H   - semismooth jacobian
561ee657d29SShri Abhyankar 
562ee657d29SShri Abhyankar    Output Parameters:
563ee657d29SShri Abhyankar    dpsi - merit function gradient
564ee657d29SShri Abhyankar 
565ee657d29SShri Abhyankar    Notes:
566ee657d29SShri Abhyankar   The merit function gradient is computed as follows
567ee657d29SShri Abhyankar         dpsi = H^T*phi
568ee657d29SShri Abhyankar */
569ee657d29SShri Abhyankar #undef __FUNCT__
570ee657d29SShri Abhyankar #define __FUNCT__ "SNESVIComputeMeritFunctionGradient"
571ee657d29SShri Abhyankar PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi)
572ee657d29SShri Abhyankar {
573ee657d29SShri Abhyankar   PetscErrorCode ierr;
574ee657d29SShri Abhyankar 
575ee657d29SShri Abhyankar   PetscFunctionBegin;
5765f48b12bSBarry Smith   ierr = MatMultTranspose(H,phi,dpsi);CHKERRQ(ierr);
577ee657d29SShri Abhyankar   PetscFunctionReturn(0);
578ee657d29SShri Abhyankar }
579ee657d29SShri Abhyankar 
580c1a5e521SShri Abhyankar /* -------------------------------------------------------------------------- */
581c1a5e521SShri Abhyankar /*
582c1a5e521SShri Abhyankar    SNESVIProjectOntoBounds - Projects X onto the feasible region so that Xl[i] <= X[i] <= Xu[i] for i = 1...n.
583c1a5e521SShri Abhyankar 
584c1a5e521SShri Abhyankar    Input Parameters:
585c1a5e521SShri Abhyankar .  SNES - nonlinear solver context
586c1a5e521SShri Abhyankar 
587c1a5e521SShri Abhyankar    Output Parameters:
588c1a5e521SShri Abhyankar .  X - Bound projected X
589c1a5e521SShri Abhyankar 
590c1a5e521SShri Abhyankar */
591c1a5e521SShri Abhyankar 
592c1a5e521SShri Abhyankar #undef __FUNCT__
593c1a5e521SShri Abhyankar #define __FUNCT__ "SNESVIProjectOntoBounds"
594c1a5e521SShri Abhyankar PetscErrorCode SNESVIProjectOntoBounds(SNES snes,Vec X)
595c1a5e521SShri Abhyankar {
596c1a5e521SShri Abhyankar   PetscErrorCode    ierr;
597c1a5e521SShri Abhyankar   SNES_VI           *vi = (SNES_VI*)snes->data;
598c1a5e521SShri Abhyankar   const PetscScalar *xl,*xu;
599c1a5e521SShri Abhyankar   PetscScalar       *x;
600c1a5e521SShri Abhyankar   PetscInt          i,n;
601c1a5e521SShri Abhyankar 
602c1a5e521SShri Abhyankar   PetscFunctionBegin;
603c1a5e521SShri Abhyankar   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
604c1a5e521SShri Abhyankar   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
605c1a5e521SShri Abhyankar   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
606c1a5e521SShri Abhyankar   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
607c1a5e521SShri Abhyankar 
608c1a5e521SShri Abhyankar   for(i = 0;i<n;i++) {
60910f5ae6bSBarry Smith     if (PetscRealPart(x[i]) < PetscRealPart(xl[i])) x[i] = xl[i];
61010f5ae6bSBarry Smith     else if (PetscRealPart(x[i]) > PetscRealPart(xu[i])) x[i] = xu[i];
611c1a5e521SShri Abhyankar   }
612c1a5e521SShri Abhyankar   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
613c1a5e521SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
614c1a5e521SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
615c1a5e521SShri Abhyankar   PetscFunctionReturn(0);
616c1a5e521SShri Abhyankar }
617c1a5e521SShri Abhyankar 
6182b4ed282SShri Abhyankar /*  --------------------------------------------------------------------
6192b4ed282SShri Abhyankar 
6202b4ed282SShri Abhyankar      This file implements a semismooth truncated Newton method with a line search,
6212b4ed282SShri Abhyankar      for solving a system of nonlinear equations in complementarity form, using the KSP, Vec,
6222b4ed282SShri Abhyankar      and Mat interfaces for linear solvers, vectors, and matrices,
6232b4ed282SShri Abhyankar      respectively.
6242b4ed282SShri Abhyankar 
6252b4ed282SShri Abhyankar      The following basic routines are required for each nonlinear solver:
6262b4ed282SShri Abhyankar           SNESCreate_XXX()          - Creates a nonlinear solver context
6272b4ed282SShri Abhyankar           SNESSetFromOptions_XXX()  - Sets runtime options
6282b4ed282SShri Abhyankar           SNESSolve_XXX()           - Solves the nonlinear system
6292b4ed282SShri Abhyankar           SNESDestroy_XXX()         - Destroys the nonlinear solver context
6302b4ed282SShri Abhyankar      The suffix "_XXX" denotes a particular implementation, in this case
6312b4ed282SShri Abhyankar      we use _VI (e.g., SNESCreate_VI, SNESSolve_VI) for solving
6322b4ed282SShri Abhyankar      systems of nonlinear equations with a line search (LS) method.
6332b4ed282SShri Abhyankar      These routines are actually called via the common user interface
6342b4ed282SShri Abhyankar      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
6352b4ed282SShri Abhyankar      SNESDestroy(), so the application code interface remains identical
6362b4ed282SShri Abhyankar      for all nonlinear solvers.
6372b4ed282SShri Abhyankar 
6382b4ed282SShri Abhyankar      Another key routine is:
6392b4ed282SShri Abhyankar           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
6402b4ed282SShri Abhyankar      by setting data structures and options.   The interface routine SNESSetUp()
6412b4ed282SShri Abhyankar      is not usually called directly by the user, but instead is called by
6422b4ed282SShri Abhyankar      SNESSolve() if necessary.
6432b4ed282SShri Abhyankar 
6442b4ed282SShri Abhyankar      Additional basic routines are:
6452b4ed282SShri Abhyankar           SNESView_XXX()            - Prints details of runtime options that
6462b4ed282SShri Abhyankar                                       have actually been used.
6472b4ed282SShri Abhyankar      These are called by application codes via the interface routines
6482b4ed282SShri Abhyankar      SNESView().
6492b4ed282SShri Abhyankar 
6502b4ed282SShri Abhyankar      The various types of solvers (preconditioners, Krylov subspace methods,
6512b4ed282SShri Abhyankar      nonlinear solvers, timesteppers) are all organized similarly, so the
6522b4ed282SShri Abhyankar      above description applies to these categories also.
6532b4ed282SShri Abhyankar 
6542b4ed282SShri Abhyankar     -------------------------------------------------------------------- */
6552b4ed282SShri Abhyankar /*
65669c03620SShri Abhyankar    SNESSolveVI_SS - Solves the complementarity problem with a semismooth Newton
6572b4ed282SShri Abhyankar    method using a line search.
6582b4ed282SShri Abhyankar 
6592b4ed282SShri Abhyankar    Input Parameters:
6602b4ed282SShri Abhyankar .  snes - the SNES context
6612b4ed282SShri Abhyankar 
6622b4ed282SShri Abhyankar    Output Parameter:
6632b4ed282SShri Abhyankar .  outits - number of iterations until termination
6642b4ed282SShri Abhyankar 
6652b4ed282SShri Abhyankar    Application Interface Routine: SNESSolve()
6662b4ed282SShri Abhyankar 
6672b4ed282SShri Abhyankar    Notes:
6682b4ed282SShri Abhyankar    This implements essentially a semismooth Newton method with a
66951defd01SShri Abhyankar    line search. The default line search does not do any line seach
67051defd01SShri Abhyankar    but rather takes a full newton step.
6712b4ed282SShri Abhyankar */
6722b4ed282SShri Abhyankar #undef __FUNCT__
67369c03620SShri Abhyankar #define __FUNCT__ "SNESSolveVI_SS"
67469c03620SShri Abhyankar PetscErrorCode SNESSolveVI_SS(SNES snes)
6752b4ed282SShri Abhyankar {
6762b4ed282SShri Abhyankar   SNES_VI            *vi = (SNES_VI*)snes->data;
6772b4ed282SShri Abhyankar   PetscErrorCode     ierr;
6782b4ed282SShri Abhyankar   PetscInt           maxits,i,lits;
6793b336b49SShri Abhyankar   PetscBool          lssucceed;
6802b4ed282SShri Abhyankar   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
6812b4ed282SShri Abhyankar   PetscReal          gnorm,xnorm=0,ynorm;
6822b4ed282SShri Abhyankar   Vec                Y,X,F,G,W;
6832b4ed282SShri Abhyankar   KSPConvergedReason kspreason;
6842b4ed282SShri Abhyankar 
6852b4ed282SShri Abhyankar   PetscFunctionBegin;
6869ce7406fSBarry Smith   vi->computeuserfunction    = snes->ops->computefunction;
6879ce7406fSBarry Smith   snes->ops->computefunction = SNESVIComputeFunction;
6889ce7406fSBarry Smith 
6892b4ed282SShri Abhyankar   snes->numFailures            = 0;
6902b4ed282SShri Abhyankar   snes->numLinearSolveFailures = 0;
6912b4ed282SShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
6922b4ed282SShri Abhyankar 
6932b4ed282SShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
6942b4ed282SShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
6952b4ed282SShri Abhyankar   F		= snes->vec_func;	/* residual vector */
6962b4ed282SShri Abhyankar   Y		= snes->work[0];	/* work vectors */
6972b4ed282SShri Abhyankar   G		= snes->work[1];
6982b4ed282SShri Abhyankar   W		= snes->work[2];
6992b4ed282SShri Abhyankar 
7002b4ed282SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
7012b4ed282SShri Abhyankar   snes->iter = 0;
7022b4ed282SShri Abhyankar   snes->norm = 0.0;
7032b4ed282SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
7042b4ed282SShri Abhyankar 
7057fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
7062b4ed282SShri Abhyankar   ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr);
7072b4ed282SShri Abhyankar   if (snes->domainerror) {
7082b4ed282SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
7099ce7406fSBarry Smith     snes->ops->computefunction = vi->computeuserfunction;
7102b4ed282SShri Abhyankar     PetscFunctionReturn(0);
7112b4ed282SShri Abhyankar   }
7122b4ed282SShri Abhyankar    /* Compute Merit function */
7132b4ed282SShri Abhyankar   ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr);
7142b4ed282SShri Abhyankar 
7152b4ed282SShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
7162b4ed282SShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
71762cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(vi->merit)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
7182b4ed282SShri Abhyankar 
7192b4ed282SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
7202b4ed282SShri Abhyankar   snes->norm = vi->phinorm;
7212b4ed282SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
7222b4ed282SShri Abhyankar   SNESLogConvHistory(snes,vi->phinorm,0);
7237a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,vi->phinorm);CHKERRQ(ierr);
7242b4ed282SShri Abhyankar 
7252b4ed282SShri Abhyankar   /* set parameter for default relative tolerance convergence test */
7262b4ed282SShri Abhyankar   snes->ttol = vi->phinorm*snes->rtol;
7272b4ed282SShri Abhyankar   /* test convergence */
7282b4ed282SShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
7299ce7406fSBarry Smith   if (snes->reason) {
7309ce7406fSBarry Smith     snes->ops->computefunction = vi->computeuserfunction;
7319ce7406fSBarry Smith     PetscFunctionReturn(0);
7329ce7406fSBarry Smith   }
7332b4ed282SShri Abhyankar 
7342b4ed282SShri Abhyankar   for (i=0; i<maxits; i++) {
7352b4ed282SShri Abhyankar 
7362b4ed282SShri Abhyankar     /* Call general purpose update function */
7372b4ed282SShri Abhyankar     if (snes->ops->update) {
7382b4ed282SShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
7392b4ed282SShri Abhyankar     }
7402b4ed282SShri Abhyankar 
7412b4ed282SShri Abhyankar     /* Solve J Y = Phi, where J is the semismooth jacobian */
742a79edbefSShri Abhyankar     /* Get the nonlinear function jacobian */
7432b4ed282SShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
744a79edbefSShri Abhyankar     /* Get the diagonal shift and row scaling vectors */
745a79edbefSShri Abhyankar     ierr = SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);CHKERRQ(ierr);
746a79edbefSShri Abhyankar     /* Compute the semismooth jacobian */
747a79edbefSShri Abhyankar     ierr = SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);CHKERRQ(ierr);
748ee657d29SShri Abhyankar     /* Compute the merit function gradient */
749ee657d29SShri Abhyankar     ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr);
7502b4ed282SShri Abhyankar     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr);
7512b4ed282SShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);CHKERRQ(ierr);
7522b4ed282SShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
7533b336b49SShri Abhyankar 
7543b336b49SShri Abhyankar     if (kspreason < 0) {
7552b4ed282SShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
7562b4ed282SShri 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);
7572b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
7582b4ed282SShri Abhyankar         break;
7592b4ed282SShri Abhyankar       }
7602b4ed282SShri Abhyankar     }
7612b4ed282SShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
7622b4ed282SShri Abhyankar     snes->linear_its += lits;
7632b4ed282SShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
7642b4ed282SShri Abhyankar     /*
7652b4ed282SShri Abhyankar     if (vi->precheckstep) {
766ace3abfcSBarry Smith       PetscBool changed_y = PETSC_FALSE;
7672b4ed282SShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
7682b4ed282SShri Abhyankar     }
7692b4ed282SShri Abhyankar 
7702b4ed282SShri Abhyankar     if (PetscLogPrintInfo){
7712b4ed282SShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
7722b4ed282SShri Abhyankar     }
7732b4ed282SShri Abhyankar     */
7742b4ed282SShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
7752b4ed282SShri Abhyankar          Y <- X - lambda*Y
7762b4ed282SShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
7772b4ed282SShri Abhyankar     */
7782b4ed282SShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
7792b4ed282SShri Abhyankar     ynorm = 1; gnorm = vi->phinorm;
7802b4ed282SShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,vi->phi,G,Y,W,vi->phinorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
7812b4ed282SShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",vi->phinorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
7822b4ed282SShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
7832b4ed282SShri Abhyankar     if (snes->domainerror) {
7842b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
7859ce7406fSBarry Smith       snes->ops->computefunction = vi->computeuserfunction;
7862b4ed282SShri Abhyankar       PetscFunctionReturn(0);
7872b4ed282SShri Abhyankar     }
7882b4ed282SShri Abhyankar     if (!lssucceed) {
7892b4ed282SShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
790ace3abfcSBarry Smith 	PetscBool ismin;
7912b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
7922b4ed282SShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
7932b4ed282SShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
7942b4ed282SShri Abhyankar         break;
7952b4ed282SShri Abhyankar       }
7962b4ed282SShri Abhyankar     }
7972b4ed282SShri Abhyankar     /* Update function and solution vectors */
7982b4ed282SShri Abhyankar     vi->phinorm = gnorm;
7992b4ed282SShri Abhyankar     vi->merit = 0.5*vi->phinorm*vi->phinorm;
8002b4ed282SShri Abhyankar     ierr = VecCopy(G,vi->phi);CHKERRQ(ierr);
8012b4ed282SShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
8022b4ed282SShri Abhyankar     /* Monitor convergence */
8032b4ed282SShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
8042b4ed282SShri Abhyankar     snes->iter = i+1;
8052b4ed282SShri Abhyankar     snes->norm = vi->phinorm;
8062b4ed282SShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
8072b4ed282SShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
8087a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
8092b4ed282SShri Abhyankar     /* Test for convergence, xnorm = || X || */
8102b4ed282SShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
8112b4ed282SShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
8122b4ed282SShri Abhyankar     if (snes->reason) break;
8132b4ed282SShri Abhyankar   }
8142b4ed282SShri Abhyankar   if (i == maxits) {
8152b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
8162b4ed282SShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
8172b4ed282SShri Abhyankar   }
8189ce7406fSBarry Smith   snes->ops->computefunction = vi->computeuserfunction;
8192b4ed282SShri Abhyankar   PetscFunctionReturn(0);
8202b4ed282SShri Abhyankar }
82169c03620SShri Abhyankar 
82269c03620SShri Abhyankar #undef __FUNCT__
823693ddf92SShri Abhyankar #define __FUNCT__ "SNESVIGetActiveSetIS"
824693ddf92SShri Abhyankar /*
825693ddf92SShri Abhyankar    SNESVIGetActiveSetIndices - Gets the global indices for the active set variables
826693ddf92SShri Abhyankar 
827693ddf92SShri Abhyankar    Input parameter
828693ddf92SShri Abhyankar .  snes - the SNES context
829693ddf92SShri Abhyankar .  X    - the snes solution vector
830693ddf92SShri Abhyankar .  F    - the nonlinear function vector
831693ddf92SShri Abhyankar 
832693ddf92SShri Abhyankar    Output parameter
833693ddf92SShri Abhyankar .  ISact - active set index set
834693ddf92SShri Abhyankar  */
835693ddf92SShri Abhyankar PetscErrorCode SNESVIGetActiveSetIS(SNES snes,Vec X,Vec F,IS* ISact)
836d950fb63SShri Abhyankar {
837d950fb63SShri Abhyankar   PetscErrorCode   ierr;
838693ddf92SShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
839693ddf92SShri Abhyankar   Vec               Xl=vi->xl,Xu=vi->xu;
840693ddf92SShri Abhyankar   const PetscScalar *x,*f,*xl,*xu;
841693ddf92SShri Abhyankar   PetscInt          *idx_act,i,nlocal,nloc_isact=0,ilow,ihigh,i1=0;
842d950fb63SShri Abhyankar 
843d950fb63SShri Abhyankar   PetscFunctionBegin;
844d950fb63SShri Abhyankar   ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr);
845d950fb63SShri Abhyankar   ierr = VecGetOwnershipRange(X,&ilow,&ihigh);CHKERRQ(ierr);
846fe835674SShri Abhyankar   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
847fe835674SShri Abhyankar   ierr = VecGetArrayRead(Xl,&xl);CHKERRQ(ierr);
848fe835674SShri Abhyankar   ierr = VecGetArrayRead(Xu,&xu);CHKERRQ(ierr);
849fe835674SShri Abhyankar   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
850693ddf92SShri Abhyankar   /* Compute active set size */
851d950fb63SShri Abhyankar   for (i=0; i < nlocal;i++) {
85210f5ae6bSBarry 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++;
853d950fb63SShri Abhyankar   }
854693ddf92SShri Abhyankar 
855d950fb63SShri Abhyankar   ierr = PetscMalloc(nloc_isact*sizeof(PetscInt),&idx_act);CHKERRQ(ierr);
856d950fb63SShri Abhyankar 
857693ddf92SShri Abhyankar   /* Set active set indices */
858d950fb63SShri Abhyankar   for(i=0; i < nlocal; i++) {
85910f5ae6bSBarry 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;
860d950fb63SShri Abhyankar   }
861d950fb63SShri Abhyankar 
862693ddf92SShri Abhyankar    /* Create active set IS */
86362298a1eSBarry Smith   ierr = ISCreateGeneral(((PetscObject)snes)->comm,nloc_isact,idx_act,PETSC_OWN_POINTER,ISact);CHKERRQ(ierr);
864d950fb63SShri Abhyankar 
865fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
866fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(Xl,&xl);CHKERRQ(ierr);
867fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(Xu,&xu);CHKERRQ(ierr);
868fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
869d950fb63SShri Abhyankar   PetscFunctionReturn(0);
870d950fb63SShri Abhyankar }
871d950fb63SShri Abhyankar 
872693ddf92SShri Abhyankar #undef __FUNCT__
873693ddf92SShri Abhyankar #define __FUNCT__ "SNESVICreateIndexSets_RS"
874693ddf92SShri Abhyankar PetscErrorCode SNESVICreateIndexSets_RS(SNES snes,Vec X,Vec F,IS* ISact,IS* ISinact)
875693ddf92SShri Abhyankar {
876693ddf92SShri Abhyankar   PetscErrorCode     ierr;
877693ddf92SShri Abhyankar 
878693ddf92SShri Abhyankar   PetscFunctionBegin;
879693ddf92SShri Abhyankar   ierr = SNESVIGetActiveSetIS(snes,X,F,ISact);CHKERRQ(ierr);
880693ddf92SShri Abhyankar   ierr = ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);CHKERRQ(ierr);
881693ddf92SShri Abhyankar   PetscFunctionReturn(0);
882693ddf92SShri Abhyankar }
883693ddf92SShri Abhyankar 
884dbd914b8SShri Abhyankar /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */
885dbd914b8SShri Abhyankar #undef __FUNCT__
886fe835674SShri Abhyankar #define __FUNCT__ "SNESVICreateSubVectors"
887fe835674SShri Abhyankar PetscErrorCode SNESVICreateSubVectors(SNES snes,PetscInt n,Vec* newv)
888dbd914b8SShri Abhyankar {
889dbd914b8SShri Abhyankar   PetscErrorCode ierr;
890dbd914b8SShri Abhyankar   Vec            v;
891dbd914b8SShri Abhyankar 
892dbd914b8SShri Abhyankar   PetscFunctionBegin;
893dbd914b8SShri Abhyankar   ierr = VecCreate(((PetscObject)snes)->comm,&v);CHKERRQ(ierr);
894dbd914b8SShri Abhyankar   ierr = VecSetSizes(v,n,PETSC_DECIDE);CHKERRQ(ierr);
895dbd914b8SShri Abhyankar   ierr = VecSetFromOptions(v);CHKERRQ(ierr);
896dbd914b8SShri Abhyankar   *newv = v;
897dbd914b8SShri Abhyankar 
898dbd914b8SShri Abhyankar   PetscFunctionReturn(0);
899dbd914b8SShri Abhyankar }
900dbd914b8SShri Abhyankar 
901732bb160SShri Abhyankar /* Resets the snes PC and KSP when the active set sizes change */
902732bb160SShri Abhyankar #undef __FUNCT__
903732bb160SShri Abhyankar #define __FUNCT__ "SNESVIResetPCandKSP"
904732bb160SShri Abhyankar PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat)
905732bb160SShri Abhyankar {
906732bb160SShri Abhyankar   PetscErrorCode         ierr;
907d0af7cd3SBarry Smith   KSP                    snesksp;
908dbd914b8SShri Abhyankar 
909732bb160SShri Abhyankar   PetscFunctionBegin;
910732bb160SShri Abhyankar   ierr = SNESGetKSP(snes,&snesksp);CHKERRQ(ierr);
911d0af7cd3SBarry Smith   ierr = KSPReset(snesksp);CHKERRQ(ierr);
912c2efdce3SBarry Smith 
913c2efdce3SBarry Smith   /*
914d0af7cd3SBarry Smith   KSP                    kspnew;
915d0af7cd3SBarry Smith   PC                     pcnew;
916d0af7cd3SBarry Smith   const MatSolverPackage stype;
917d0af7cd3SBarry Smith 
918c2efdce3SBarry Smith 
919732bb160SShri Abhyankar   ierr = KSPCreate(((PetscObject)snes)->comm,&kspnew);CHKERRQ(ierr);
920732bb160SShri Abhyankar   kspnew->pc_side = snesksp->pc_side;
921732bb160SShri Abhyankar   kspnew->rtol    = snesksp->rtol;
922732bb160SShri Abhyankar   kspnew->abstol    = snesksp->abstol;
923732bb160SShri Abhyankar   kspnew->max_it  = snesksp->max_it;
924732bb160SShri Abhyankar   ierr = KSPSetType(kspnew,((PetscObject)snesksp)->type_name);CHKERRQ(ierr);
925732bb160SShri Abhyankar   ierr = KSPGetPC(kspnew,&pcnew);CHKERRQ(ierr);
926732bb160SShri Abhyankar   ierr = PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);CHKERRQ(ierr);
927732bb160SShri Abhyankar   ierr = PCSetOperators(kspnew->pc,Amat,Pmat,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
928732bb160SShri Abhyankar   ierr = PCFactorGetMatSolverPackage(snesksp->pc,&stype);CHKERRQ(ierr);
929732bb160SShri Abhyankar   ierr = PCFactorSetMatSolverPackage(kspnew->pc,stype);CHKERRQ(ierr);
9306bf464f9SBarry Smith   ierr = KSPDestroy(&snesksp);CHKERRQ(ierr);
931732bb160SShri Abhyankar   snes->ksp = kspnew;
932732bb160SShri Abhyankar   ierr = PetscLogObjectParent(snes,kspnew);CHKERRQ(ierr);
933d0af7cd3SBarry Smith    ierr = KSPSetFromOptions(kspnew);CHKERRQ(ierr);*/
934732bb160SShri Abhyankar   PetscFunctionReturn(0);
935732bb160SShri Abhyankar }
93669c03620SShri Abhyankar 
93769c03620SShri Abhyankar 
938fe835674SShri Abhyankar #undef __FUNCT__
939fe835674SShri Abhyankar #define __FUNCT__ "SNESVIComputeInactiveSetFnorm"
94010f5ae6bSBarry Smith PetscErrorCode SNESVIComputeInactiveSetFnorm(SNES snes,Vec F,Vec X,PetscReal *fnorm)
941fe835674SShri Abhyankar {
942fe835674SShri Abhyankar   PetscErrorCode    ierr;
943fe835674SShri Abhyankar   SNES_VI           *vi = (SNES_VI*)snes->data;
944fe835674SShri Abhyankar   const PetscScalar *x,*xl,*xu,*f;
945fe835674SShri Abhyankar   PetscInt          i,n;
946fe835674SShri Abhyankar   PetscReal         rnorm;
947fe835674SShri Abhyankar 
948fe835674SShri Abhyankar   PetscFunctionBegin;
949fe835674SShri Abhyankar   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
950fe835674SShri Abhyankar   ierr = VecGetArrayRead(vi->xl,&xl);CHKERRQ(ierr);
951fe835674SShri Abhyankar   ierr = VecGetArrayRead(vi->xu,&xu);CHKERRQ(ierr);
952fe835674SShri Abhyankar   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
953fe835674SShri Abhyankar   ierr = VecGetArrayRead(F,&f);CHKERRQ(ierr);
954fe835674SShri Abhyankar   rnorm = 0.0;
955fe835674SShri Abhyankar   for (i=0; i<n; i++) {
95610f5ae6bSBarry 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]);
957fe835674SShri Abhyankar   }
958fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(F,&f);CHKERRQ(ierr);
959fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xl,&xl);CHKERRQ(ierr);
960fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(vi->xu,&xu);CHKERRQ(ierr);
961fe835674SShri Abhyankar   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
962d9822059SBarry Smith   ierr = MPI_Allreduce(&rnorm,fnorm,1,MPIU_REAL,MPIU_SUM,((PetscObject)snes)->comm);CHKERRQ(ierr);
963fe835674SShri Abhyankar   *fnorm = sqrt(*fnorm);
964fe835674SShri Abhyankar   PetscFunctionReturn(0);
965fe835674SShri Abhyankar }
966fe835674SShri Abhyankar 
967fe835674SShri Abhyankar /* Variational Inequality solver using reduce space method. No semismooth algorithm is
968c2efdce3SBarry Smith    implemented in this algorithm. It basically identifies the active constraints and does
969c2efdce3SBarry Smith    a linear solve on the other variables (those not associated with the active constraints). */
970d950fb63SShri Abhyankar #undef __FUNCT__
971d950fb63SShri Abhyankar #define __FUNCT__ "SNESSolveVI_RS"
972d950fb63SShri Abhyankar PetscErrorCode SNESSolveVI_RS(SNES snes)
973d950fb63SShri Abhyankar {
974d950fb63SShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
975d950fb63SShri Abhyankar   PetscErrorCode    ierr;
976abcba341SShri Abhyankar   PetscInt          maxits,i,lits;
977d950fb63SShri Abhyankar   PetscBool         lssucceed;
978d950fb63SShri Abhyankar   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
979fe835674SShri Abhyankar   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
980d950fb63SShri Abhyankar   Vec                Y,X,F,G,W;
981d950fb63SShri Abhyankar   KSPConvergedReason kspreason;
982d950fb63SShri Abhyankar 
983d950fb63SShri Abhyankar   PetscFunctionBegin;
984d950fb63SShri Abhyankar   snes->numFailures            = 0;
985d950fb63SShri Abhyankar   snes->numLinearSolveFailures = 0;
986d950fb63SShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
987d950fb63SShri Abhyankar 
988d950fb63SShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
989d950fb63SShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
990d950fb63SShri Abhyankar   F		= snes->vec_func;	/* residual vector */
991d950fb63SShri Abhyankar   Y		= snes->work[0];	/* work vectors */
992d950fb63SShri Abhyankar   G		= snes->work[1];
993d950fb63SShri Abhyankar   W		= snes->work[2];
994d950fb63SShri Abhyankar 
995d950fb63SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
996d950fb63SShri Abhyankar   snes->iter = 0;
997d950fb63SShri Abhyankar   snes->norm = 0.0;
998d950fb63SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
999d950fb63SShri Abhyankar 
10007fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
1001fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
1002d950fb63SShri Abhyankar   if (snes->domainerror) {
1003d950fb63SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
1004d950fb63SShri Abhyankar     PetscFunctionReturn(0);
1005d950fb63SShri Abhyankar   }
1006fe835674SShri Abhyankar   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
1007d950fb63SShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
1008d950fb63SShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
100962cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1010d950fb63SShri Abhyankar 
1011d950fb63SShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
1012fe835674SShri Abhyankar   snes->norm = fnorm;
1013d950fb63SShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
1014fe835674SShri Abhyankar   SNESLogConvHistory(snes,fnorm,0);
10157a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
1016d950fb63SShri Abhyankar 
1017d950fb63SShri Abhyankar   /* set parameter for default relative tolerance convergence test */
1018fe835674SShri Abhyankar   snes->ttol = fnorm*snes->rtol;
1019d950fb63SShri Abhyankar   /* test convergence */
1020fe835674SShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
1021d950fb63SShri Abhyankar   if (snes->reason) PetscFunctionReturn(0);
1022d950fb63SShri Abhyankar 
1023d950fb63SShri Abhyankar   for (i=0; i<maxits; i++) {
1024d950fb63SShri Abhyankar 
1025d950fb63SShri Abhyankar     IS         IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1026d950fb63SShri Abhyankar     VecScatter scat_act,scat_inact;
1027abcba341SShri Abhyankar     PetscInt   nis_act,nis_inact;
1028fe835674SShri Abhyankar     Vec        Y_act,Y_inact,F_inact;
1029d950fb63SShri Abhyankar     Mat        jac_inact_inact,prejac_inact_inact;
103062298a1eSBarry Smith     IS         keptrows;
1031abcba341SShri Abhyankar     PetscBool  isequal;
1032d950fb63SShri Abhyankar 
1033d950fb63SShri Abhyankar     /* Call general purpose update function */
1034d950fb63SShri Abhyankar     if (snes->ops->update) {
1035d950fb63SShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
1036d950fb63SShri Abhyankar     }
1037d950fb63SShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
103862298a1eSBarry Smith 
1039d950fb63SShri Abhyankar     /* Create active and inactive index sets */
1040693ddf92SShri Abhyankar     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
1041d950fb63SShri Abhyankar 
1042*4dcab191SBarry Smith     ierr = DMSetVI(snes->dm,vi->xu,vi->xl,X,F,IS_inact);CHKERRQ(ierr);
1043*4dcab191SBarry Smith 
1044*4dcab191SBarry Smith 
1045abcba341SShri Abhyankar     /* Create inactive set submatrix */
104662298a1eSBarry Smith     ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
1047b3a44c85SBarry Smith     ierr = MatFindNonzeroRows(jac_inact_inact,&keptrows);CHKERRQ(ierr);
104862298a1eSBarry Smith     if (keptrows) {
104962298a1eSBarry Smith       PetscInt       cnt,*nrows,k;
105062298a1eSBarry Smith       const PetscInt *krows,*inact;
105127d4218bSShri Abhyankar       PetscInt       rstart=jac_inact_inact->rmap->rstart;
105262298a1eSBarry Smith 
10536bf464f9SBarry Smith       ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
10546bf464f9SBarry Smith       ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
105562298a1eSBarry Smith 
105662298a1eSBarry Smith       ierr = ISGetLocalSize(keptrows,&cnt);CHKERRQ(ierr);
105762298a1eSBarry Smith       ierr = ISGetIndices(keptrows,&krows);CHKERRQ(ierr);
105862298a1eSBarry Smith       ierr = ISGetIndices(IS_inact,&inact);CHKERRQ(ierr);
105962298a1eSBarry Smith       ierr = PetscMalloc(cnt*sizeof(PetscInt),&nrows);CHKERRQ(ierr);
106062298a1eSBarry Smith       for (k=0; k<cnt; k++) {
106127d4218bSShri Abhyankar         nrows[k] = inact[krows[k]-rstart];
106262298a1eSBarry Smith       }
106362298a1eSBarry Smith       ierr = ISRestoreIndices(keptrows,&krows);CHKERRQ(ierr);
106462298a1eSBarry Smith       ierr = ISRestoreIndices(IS_inact,&inact);CHKERRQ(ierr);
10656bf464f9SBarry Smith       ierr = ISDestroy(&keptrows);CHKERRQ(ierr);
10666bf464f9SBarry Smith       ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
106762298a1eSBarry Smith 
106827d4218bSShri Abhyankar       ierr = ISCreateGeneral(PETSC_COMM_WORLD,cnt,nrows,PETSC_OWN_POINTER,&IS_inact);CHKERRQ(ierr);
106927d4218bSShri Abhyankar       ierr = ISComplement(IS_inact,F->map->rstart,F->map->rend,&IS_act);CHKERRQ(ierr);
107062298a1eSBarry Smith       ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr);
107162298a1eSBarry Smith     }
107262298a1eSBarry Smith 
1073d950fb63SShri Abhyankar     /* Get sizes of active and inactive sets */
1074d950fb63SShri Abhyankar     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
1075d950fb63SShri Abhyankar     ierr = ISGetLocalSize(IS_inact,&nis_inact);CHKERRQ(ierr);
1076d950fb63SShri Abhyankar 
1077d950fb63SShri Abhyankar     /* Create active and inactive set vectors */
1078fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_inact,&F_inact);CHKERRQ(ierr);
1079fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_act,&Y_act);CHKERRQ(ierr);
1080fe835674SShri Abhyankar     ierr = SNESVICreateSubVectors(snes,nis_inact,&Y_inact);CHKERRQ(ierr);
1081d950fb63SShri Abhyankar 
1082d950fb63SShri Abhyankar     /* Create scatter contexts */
1083d950fb63SShri Abhyankar     ierr = VecScatterCreate(Y,IS_act,Y_act,PETSC_NULL,&scat_act);CHKERRQ(ierr);
1084d950fb63SShri Abhyankar     ierr = VecScatterCreate(Y,IS_inact,Y_inact,PETSC_NULL,&scat_inact);CHKERRQ(ierr);
1085d950fb63SShri Abhyankar 
1086d950fb63SShri Abhyankar     /* Do a vec scatter to active and inactive set vectors */
1087fe835674SShri Abhyankar     ierr = VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1088fe835674SShri Abhyankar     ierr = VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1089d950fb63SShri Abhyankar 
1090d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1091d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1092d950fb63SShri Abhyankar 
1093d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1094d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1095d950fb63SShri Abhyankar 
1096d950fb63SShri Abhyankar     /* Active set direction = 0 */
1097d950fb63SShri Abhyankar     ierr = VecSet(Y_act,0);CHKERRQ(ierr);
1098d950fb63SShri Abhyankar     if (snes->jacobian != snes->jacobian_pre) {
1099d950fb63SShri Abhyankar       ierr = MatGetSubMatrix(snes->jacobian_pre,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);CHKERRQ(ierr);
1100d950fb63SShri Abhyankar     } else prejac_inact_inact = jac_inact_inact;
1101d950fb63SShri Abhyankar 
1102abcba341SShri Abhyankar     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
1103abcba341SShri Abhyankar     if (!isequal) {
1104732bb160SShri Abhyankar       ierr = SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr);
1105d950fb63SShri Abhyankar     }
1106d950fb63SShri Abhyankar 
110713e0d083SBarry Smith     /*      ierr = ISView(IS_inact,0);CHKERRQ(ierr); */
110813e0d083SBarry Smith     /*      ierr = ISView(IS_act,0);CHKERRQ(ierr);*/
110913e0d083SBarry Smith     /*      ierr = MatView(snes->jacobian_pre,0); */
111013e0d083SBarry Smith 
1111d950fb63SShri Abhyankar     ierr = KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact,flg);CHKERRQ(ierr);
111213e0d083SBarry Smith     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
111313e0d083SBarry Smith     {
111413e0d083SBarry Smith       PC        pc;
111513e0d083SBarry Smith       PetscBool flg;
111613e0d083SBarry Smith       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
111713e0d083SBarry Smith       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
111813e0d083SBarry Smith       if (flg) {
111913e0d083SBarry Smith         KSP      *subksps;
112013e0d083SBarry Smith         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
112113e0d083SBarry Smith         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
112213e0d083SBarry Smith         ierr = PetscFree(subksps);CHKERRQ(ierr);
112313e0d083SBarry Smith         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
112413e0d083SBarry Smith         if (flg) {
112513e0d083SBarry Smith           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
112613e0d083SBarry Smith           const PetscInt *ii;
112713e0d083SBarry Smith 
112813e0d083SBarry Smith           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
112913e0d083SBarry Smith           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
113013e0d083SBarry Smith           for (j=0; j<n; j++) {
113113e0d083SBarry Smith             if (ii[j] < N) cnts[0]++;
113213e0d083SBarry Smith             else if (ii[j] < 2*N) cnts[1]++;
113313e0d083SBarry Smith             else if (ii[j] < 3*N) cnts[2]++;
113413e0d083SBarry Smith           }
113513e0d083SBarry Smith           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
113613e0d083SBarry Smith 
113713e0d083SBarry Smith           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
113813e0d083SBarry Smith         }
113913e0d083SBarry Smith       }
114013e0d083SBarry Smith     }
114113e0d083SBarry Smith 
1142fe835674SShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,F_inact,Y_inact);CHKERRQ(ierr);
1143d950fb63SShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
1144d950fb63SShri Abhyankar     if (kspreason < 0) {
1145d950fb63SShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
1146d950fb63SShri 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);
1147d950fb63SShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
1148d950fb63SShri Abhyankar         break;
1149d950fb63SShri Abhyankar       }
1150d950fb63SShri Abhyankar      }
1151d950fb63SShri Abhyankar 
1152d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1153d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1154d950fb63SShri Abhyankar     ierr = VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1155d950fb63SShri Abhyankar     ierr = VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1156d950fb63SShri Abhyankar 
11576bf464f9SBarry Smith     ierr = VecDestroy(&F_inact);CHKERRQ(ierr);
11586bf464f9SBarry Smith     ierr = VecDestroy(&Y_act);CHKERRQ(ierr);
11596bf464f9SBarry Smith     ierr = VecDestroy(&Y_inact);CHKERRQ(ierr);
11606bf464f9SBarry Smith     ierr = VecScatterDestroy(&scat_act);CHKERRQ(ierr);
11616bf464f9SBarry Smith     ierr = VecScatterDestroy(&scat_inact);CHKERRQ(ierr);
11626bf464f9SBarry Smith     ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
1163abcba341SShri Abhyankar     if (!isequal) {
11646bf464f9SBarry Smith       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
1165abcba341SShri Abhyankar       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
1166abcba341SShri Abhyankar     }
11676bf464f9SBarry Smith     ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
11686bf464f9SBarry Smith     ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr);
1169d950fb63SShri Abhyankar     if (snes->jacobian != snes->jacobian_pre) {
11706bf464f9SBarry Smith       ierr = MatDestroy(&prejac_inact_inact);CHKERRQ(ierr);
1171d950fb63SShri Abhyankar     }
1172d950fb63SShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
1173d950fb63SShri Abhyankar     snes->linear_its += lits;
1174d950fb63SShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
1175d950fb63SShri Abhyankar     /*
1176d950fb63SShri Abhyankar     if (vi->precheckstep) {
1177d950fb63SShri Abhyankar       PetscBool changed_y = PETSC_FALSE;
1178d950fb63SShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
1179d950fb63SShri Abhyankar     }
1180d950fb63SShri Abhyankar 
1181d950fb63SShri Abhyankar     if (PetscLogPrintInfo){
1182d950fb63SShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
1183d950fb63SShri Abhyankar     }
1184d950fb63SShri Abhyankar     */
1185d950fb63SShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
1186d950fb63SShri Abhyankar          Y <- X - lambda*Y
1187d950fb63SShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
1188d950fb63SShri Abhyankar     */
1189d950fb63SShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
1190fe835674SShri Abhyankar     ynorm = 1; gnorm = fnorm;
1191fe835674SShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
1192fe835674SShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
11932b4ed282SShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
11942b4ed282SShri Abhyankar     if (snes->domainerror) {
11952b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
11962b4ed282SShri Abhyankar       PetscFunctionReturn(0);
11972b4ed282SShri Abhyankar     }
11982b4ed282SShri Abhyankar     if (!lssucceed) {
11992b4ed282SShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
12002b4ed282SShri Abhyankar 	PetscBool ismin;
12012b4ed282SShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
12022b4ed282SShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
12032b4ed282SShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
12042b4ed282SShri Abhyankar         break;
12052b4ed282SShri Abhyankar       }
12062b4ed282SShri Abhyankar     }
12072b4ed282SShri Abhyankar     /* Update function and solution vectors */
1208fe835674SShri Abhyankar     fnorm = gnorm;
1209fe835674SShri Abhyankar     ierr = VecCopy(G,F);CHKERRQ(ierr);
12102b4ed282SShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
12112b4ed282SShri Abhyankar     /* Monitor convergence */
12122b4ed282SShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
12132b4ed282SShri Abhyankar     snes->iter = i+1;
1214fe835674SShri Abhyankar     snes->norm = fnorm;
12152b4ed282SShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
12162b4ed282SShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
12177a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
12182b4ed282SShri Abhyankar     /* Test for convergence, xnorm = || X || */
12192b4ed282SShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
1220fe835674SShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
12212b4ed282SShri Abhyankar     if (snes->reason) break;
12222b4ed282SShri Abhyankar   }
12232b4ed282SShri Abhyankar   if (i == maxits) {
12242b4ed282SShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
12252b4ed282SShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
12262b4ed282SShri Abhyankar   }
12272b4ed282SShri Abhyankar   PetscFunctionReturn(0);
12282b4ed282SShri Abhyankar }
12292b4ed282SShri Abhyankar 
12302f63a38cSShri Abhyankar #undef __FUNCT__
1231720c9a41SShri Abhyankar #define __FUNCT__ "SNESVISetRedundancyCheck"
1232cb5fe31bSShri Abhyankar PetscErrorCode SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (*func)(SNES,IS,IS*,void*),void *ctx)
12332f63a38cSShri Abhyankar {
12342f63a38cSShri Abhyankar   SNES_VI         *vi = (SNES_VI*)snes->data;
12352f63a38cSShri Abhyankar 
12362f63a38cSShri Abhyankar   PetscFunctionBegin;
12372f63a38cSShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
12382f63a38cSShri Abhyankar   vi->checkredundancy = func;
1239cb5fe31bSShri Abhyankar   vi->ctxP            = ctx;
12402f63a38cSShri Abhyankar   PetscFunctionReturn(0);
12412f63a38cSShri Abhyankar }
12422f63a38cSShri Abhyankar 
1243ff596062SShri Abhyankar #if defined(PETSC_HAVE_MATLAB_ENGINE)
1244ff596062SShri Abhyankar #include <engine.h>
1245ff596062SShri Abhyankar #include <mex.h>
1246cb5fe31bSShri Abhyankar typedef struct {char *funcname; mxArray *ctx;} SNESMatlabContext;
1247ff596062SShri Abhyankar 
1248ff596062SShri Abhyankar #undef __FUNCT__
1249ff596062SShri Abhyankar #define __FUNCT__ "SNESVIRedundancyCheck_Matlab"
1250ff596062SShri Abhyankar PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS* is_redact,void* ctx)
1251ff596062SShri Abhyankar {
1252ff596062SShri Abhyankar   PetscErrorCode      ierr;
1253cb5fe31bSShri Abhyankar   SNESMatlabContext   *sctx = (SNESMatlabContext*)ctx;
1254cb5fe31bSShri Abhyankar   int                 nlhs = 1, nrhs = 5;
1255cb5fe31bSShri Abhyankar   mxArray             *plhs[1], *prhs[5];
1256cb5fe31bSShri Abhyankar   long long int       l1 = 0, l2 = 0, ls = 0;
1257fcb1c9afSShri Abhyankar   PetscInt            *indices=PETSC_NULL;
1258ff596062SShri Abhyankar 
1259ff596062SShri Abhyankar   PetscFunctionBegin;
1260ff596062SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1261ff596062SShri Abhyankar   PetscValidHeaderSpecific(is_act,IS_CLASSID,2);
1262ff596062SShri Abhyankar   PetscValidPointer(is_redact,3);
1263ff596062SShri Abhyankar   PetscCheckSameComm(snes,1,is_act,2);
1264ff596062SShri Abhyankar 
126509db5ad8SShri Abhyankar   /* Create IS for reduced active set of size 0, its size and indices will
126609db5ad8SShri Abhyankar    bet set by the Matlab function */
1267fcb1c9afSShri Abhyankar   ierr = ISCreateGeneral(((PetscObject)snes)->comm,0,indices,PETSC_OWN_POINTER,is_redact);CHKERRQ(ierr);
1268cb5fe31bSShri Abhyankar   /* call Matlab function in ctx */
1269ff596062SShri Abhyankar   ierr = PetscMemcpy(&ls,&snes,sizeof(snes));CHKERRQ(ierr);
1270ff596062SShri Abhyankar   ierr = PetscMemcpy(&l1,&is_act,sizeof(is_act));CHKERRQ(ierr);
1271cb5fe31bSShri Abhyankar   ierr = PetscMemcpy(&l2,is_redact,sizeof(is_act));CHKERRQ(ierr);
1272ff596062SShri Abhyankar   prhs[0] = mxCreateDoubleScalar((double)ls);
1273ff596062SShri Abhyankar   prhs[1] = mxCreateDoubleScalar((double)l1);
1274cb5fe31bSShri Abhyankar   prhs[2] = mxCreateDoubleScalar((double)l2);
1275cb5fe31bSShri Abhyankar   prhs[3] = mxCreateString(sctx->funcname);
1276cb5fe31bSShri Abhyankar   prhs[4] = sctx->ctx;
1277ff596062SShri Abhyankar   ierr    = mexCallMATLAB(nlhs,plhs,nrhs,prhs,"PetscSNESVIRedundancyCheckInternal");CHKERRQ(ierr);
1278ff596062SShri Abhyankar   ierr    = mxGetScalar(plhs[0]);CHKERRQ(ierr);
1279ff596062SShri Abhyankar   mxDestroyArray(prhs[0]);
1280ff596062SShri Abhyankar   mxDestroyArray(prhs[1]);
1281ff596062SShri Abhyankar   mxDestroyArray(prhs[2]);
1282ff596062SShri Abhyankar   mxDestroyArray(prhs[3]);
1283ff596062SShri Abhyankar   mxDestroyArray(plhs[0]);
1284ff596062SShri Abhyankar   PetscFunctionReturn(0);
1285ff596062SShri Abhyankar }
1286ff596062SShri Abhyankar 
1287ff596062SShri Abhyankar #undef __FUNCT__
1288ff596062SShri Abhyankar #define __FUNCT__ "SNESVISetRedundancyCheckMatlab"
1289ff596062SShri Abhyankar PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes,const char* func,mxArray* ctx)
1290ff596062SShri Abhyankar {
1291ff596062SShri Abhyankar   PetscErrorCode      ierr;
1292cb5fe31bSShri Abhyankar   SNESMatlabContext   *sctx;
1293ff596062SShri Abhyankar 
1294ff596062SShri Abhyankar   PetscFunctionBegin;
1295ff596062SShri Abhyankar   /* currently sctx is memory bleed */
1296cb5fe31bSShri Abhyankar   ierr = PetscMalloc(sizeof(SNESMatlabContext),&sctx);CHKERRQ(ierr);
1297ff596062SShri Abhyankar   ierr = PetscStrallocpy(func,&sctx->funcname);CHKERRQ(ierr);
1298ff596062SShri Abhyankar   sctx->ctx = mxDuplicateArray(ctx);
1299cb5fe31bSShri Abhyankar   ierr = SNESVISetRedundancyCheck(snes,SNESVIRedundancyCheck_Matlab,sctx);CHKERRQ(ierr);
1300ff596062SShri Abhyankar   PetscFunctionReturn(0);
1301ff596062SShri Abhyankar }
1302ff596062SShri Abhyankar 
1303ff596062SShri Abhyankar #endif
1304ff596062SShri Abhyankar 
1305ff596062SShri Abhyankar 
13062f63a38cSShri Abhyankar /* Variational Inequality solver using augmented space method. It does the opposite of the
13072f63a38cSShri Abhyankar    reduced space method i.e. it identifies the active set variables and instead of discarding
1308720c9a41SShri Abhyankar    them it augments the original system by introducing additional equality
130956a221efSShri Abhyankar    constraint equations for active set variables. The user can optionally provide an IS for
131056a221efSShri Abhyankar    a subset of 'redundant' active set variables which will treated as free variables.
13112f63a38cSShri Abhyankar    Specific implementation for Allen-Cahn problem
13122f63a38cSShri Abhyankar */
13132f63a38cSShri Abhyankar #undef __FUNCT__
1314b350b9c9SBarry Smith #define __FUNCT__ "SNESSolveVI_RSAUG"
1315b350b9c9SBarry Smith PetscErrorCode SNESSolveVI_RSAUG(SNES snes)
13162f63a38cSShri Abhyankar {
13172f63a38cSShri Abhyankar   SNES_VI          *vi = (SNES_VI*)snes->data;
13182f63a38cSShri Abhyankar   PetscErrorCode    ierr;
13192f63a38cSShri Abhyankar   PetscInt          maxits,i,lits;
13202f63a38cSShri Abhyankar   PetscBool         lssucceed;
13212f63a38cSShri Abhyankar   MatStructure      flg = DIFFERENT_NONZERO_PATTERN;
13222f63a38cSShri Abhyankar   PetscReal         fnorm,gnorm,xnorm=0,ynorm;
13232f63a38cSShri Abhyankar   Vec                Y,X,F,G,W;
13242f63a38cSShri Abhyankar   KSPConvergedReason kspreason;
13252f63a38cSShri Abhyankar 
13262f63a38cSShri Abhyankar   PetscFunctionBegin;
13272f63a38cSShri Abhyankar   snes->numFailures            = 0;
13282f63a38cSShri Abhyankar   snes->numLinearSolveFailures = 0;
13292f63a38cSShri Abhyankar   snes->reason                 = SNES_CONVERGED_ITERATING;
13302f63a38cSShri Abhyankar 
13312f63a38cSShri Abhyankar   maxits	= snes->max_its;	/* maximum number of iterations */
13322f63a38cSShri Abhyankar   X		= snes->vec_sol;	/* solution vector */
13332f63a38cSShri Abhyankar   F		= snes->vec_func;	/* residual vector */
13342f63a38cSShri Abhyankar   Y		= snes->work[0];	/* work vectors */
13352f63a38cSShri Abhyankar   G		= snes->work[1];
13362f63a38cSShri Abhyankar   W		= snes->work[2];
13372f63a38cSShri Abhyankar 
13382f63a38cSShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
13392f63a38cSShri Abhyankar   snes->iter = 0;
13402f63a38cSShri Abhyankar   snes->norm = 0.0;
13412f63a38cSShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
13422f63a38cSShri Abhyankar 
13432f63a38cSShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr);
13442f63a38cSShri Abhyankar   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
13452f63a38cSShri Abhyankar   if (snes->domainerror) {
13462f63a38cSShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
13472f63a38cSShri Abhyankar     PetscFunctionReturn(0);
13482f63a38cSShri Abhyankar   }
13492f63a38cSShri Abhyankar   ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr);
13502f63a38cSShri Abhyankar   ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr);	/* xnorm <- ||x||  */
13512f63a38cSShri Abhyankar   ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr);
135262cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
13532f63a38cSShri Abhyankar 
13542f63a38cSShri Abhyankar   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
13552f63a38cSShri Abhyankar   snes->norm = fnorm;
13562f63a38cSShri Abhyankar   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
13572f63a38cSShri Abhyankar   SNESLogConvHistory(snes,fnorm,0);
13587a03ce2fSLisandro Dalcin   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
13592f63a38cSShri Abhyankar 
13602f63a38cSShri Abhyankar   /* set parameter for default relative tolerance convergence test */
13612f63a38cSShri Abhyankar   snes->ttol = fnorm*snes->rtol;
13622f63a38cSShri Abhyankar   /* test convergence */
13632f63a38cSShri Abhyankar   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
13642f63a38cSShri Abhyankar   if (snes->reason) PetscFunctionReturn(0);
13652f63a38cSShri Abhyankar 
13662f63a38cSShri Abhyankar   for (i=0; i<maxits; i++) {
13672f63a38cSShri Abhyankar     IS             IS_act,IS_inact; /* _act -> active set _inact -> inactive set */
1368cb5fe31bSShri Abhyankar     IS             IS_redact; /* redundant active set */
136956a221efSShri Abhyankar     Mat            J_aug,Jpre_aug;
137056a221efSShri Abhyankar     Vec            F_aug,Y_aug;
137156a221efSShri Abhyankar     PetscInt       nis_redact,nis_act;
137256a221efSShri Abhyankar     const PetscInt *idx_redact,*idx_act;
137356a221efSShri Abhyankar     PetscInt       k;
137463ee972cSSatish Balay     PetscInt       *idx_actkept=PETSC_NULL,nkept=0; /* list of kept active set */
137556a221efSShri Abhyankar     PetscScalar    *f,*f2;
13762f63a38cSShri Abhyankar     PetscBool      isequal;
137756a221efSShri Abhyankar     PetscInt       i1=0,j1=0;
13782f63a38cSShri Abhyankar 
13792f63a38cSShri Abhyankar     /* Call general purpose update function */
13802f63a38cSShri Abhyankar     if (snes->ops->update) {
13812f63a38cSShri Abhyankar       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
13822f63a38cSShri Abhyankar     }
13832f63a38cSShri Abhyankar     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
13842f63a38cSShri Abhyankar 
13852f63a38cSShri Abhyankar     /* Create active and inactive index sets */
13862f63a38cSShri Abhyankar     ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr);
13872f63a38cSShri Abhyankar 
138856a221efSShri Abhyankar     /* Get local active set size */
13892f63a38cSShri Abhyankar     ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr);
139056a221efSShri Abhyankar     if (nis_act) {
1391e63076c7SBarry Smith       ierr = ISGetIndices(IS_act,&idx_act);CHKERRQ(ierr);
1392e63076c7SBarry Smith       IS_redact  = PETSC_NULL;
139356a221efSShri Abhyankar       if(vi->checkredundancy) {
1394cb5fe31bSShri Abhyankar 	(*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);
139556a221efSShri Abhyankar       }
13962f63a38cSShri Abhyankar 
139756a221efSShri Abhyankar       if(!IS_redact) {
139856a221efSShri Abhyankar 	/* User called checkredundancy function but didn't create IS_redact because
139956a221efSShri Abhyankar            there were no redundant active set variables */
140056a221efSShri Abhyankar 	/* Copy over all active set indices to the list */
140156a221efSShri Abhyankar 	ierr = PetscMalloc(nis_act*sizeof(PetscInt),&idx_actkept);CHKERRQ(ierr);
140256a221efSShri Abhyankar 	for(k=0;k < nis_act;k++) idx_actkept[k] = idx_act[k];
140356a221efSShri Abhyankar 	nkept = nis_act;
140456a221efSShri Abhyankar       } else {
140556a221efSShri Abhyankar 	ierr = ISGetLocalSize(IS_redact,&nis_redact);CHKERRQ(ierr);
140656a221efSShri Abhyankar 	ierr = PetscMalloc((nis_act-nis_redact)*sizeof(PetscInt),&idx_actkept);CHKERRQ(ierr);
14072f63a38cSShri Abhyankar 
140856a221efSShri Abhyankar 	/* Create reduced active set list */
140956a221efSShri Abhyankar 	ierr = ISGetIndices(IS_act,&idx_act);CHKERRQ(ierr);
141056a221efSShri Abhyankar 	ierr = ISGetIndices(IS_redact,&idx_redact);CHKERRQ(ierr);
1411cb5fe31bSShri Abhyankar 	j1 = 0;nkept = 0;
141256a221efSShri Abhyankar 	for(k=0;k<nis_act;k++) {
141356a221efSShri Abhyankar 	  if(j1 < nis_redact && idx_act[k] == idx_redact[j1]) j1++;
141456a221efSShri Abhyankar 	  else idx_actkept[nkept++] = idx_act[k];
141556a221efSShri Abhyankar 	}
141656a221efSShri Abhyankar 	ierr = ISRestoreIndices(IS_act,&idx_act);CHKERRQ(ierr);
141756a221efSShri Abhyankar 	ierr = ISRestoreIndices(IS_redact,&idx_redact);CHKERRQ(ierr);
1418cb5fe31bSShri Abhyankar 
1419cb5fe31bSShri Abhyankar         ierr = ISDestroy(&IS_redact);CHKERRQ(ierr);
142056a221efSShri Abhyankar       }
14212f63a38cSShri Abhyankar 
142256a221efSShri Abhyankar       /* Create augmented F and Y */
142356a221efSShri Abhyankar       ierr = VecCreate(((PetscObject)snes)->comm,&F_aug);CHKERRQ(ierr);
142456a221efSShri Abhyankar       ierr = VecSetSizes(F_aug,F->map->n+nkept,PETSC_DECIDE);CHKERRQ(ierr);
142556a221efSShri Abhyankar       ierr = VecSetFromOptions(F_aug);CHKERRQ(ierr);
142656a221efSShri Abhyankar       ierr = VecDuplicate(F_aug,&Y_aug);CHKERRQ(ierr);
14272f63a38cSShri Abhyankar 
142856a221efSShri Abhyankar       /* Copy over F to F_aug in the first n locations */
142956a221efSShri Abhyankar       ierr = VecGetArray(F,&f);CHKERRQ(ierr);
143056a221efSShri Abhyankar       ierr = VecGetArray(F_aug,&f2);CHKERRQ(ierr);
143156a221efSShri Abhyankar       ierr = PetscMemcpy(f2,f,F->map->n*sizeof(PetscScalar));CHKERRQ(ierr);
143256a221efSShri Abhyankar       ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
143356a221efSShri Abhyankar       ierr = VecRestoreArray(F_aug,&f2);CHKERRQ(ierr);
14342f63a38cSShri Abhyankar 
143556a221efSShri Abhyankar       /* Create the augmented jacobian matrix */
143656a221efSShri Abhyankar       ierr = MatCreate(((PetscObject)snes)->comm,&J_aug);CHKERRQ(ierr);
143756a221efSShri Abhyankar       ierr = MatSetSizes(J_aug,X->map->n+nkept,X->map->n+nkept,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
143856a221efSShri Abhyankar       ierr = MatSetFromOptions(J_aug);CHKERRQ(ierr);
14392f63a38cSShri Abhyankar 
144056a221efSShri Abhyankar 
14419521db3cSSatish Balay       { /* local vars */
1442493a4f3dSShri Abhyankar       /* Preallocate augmented matrix and set values in it...Doing only sequential case first*/
144356a221efSShri Abhyankar       PetscInt          ncols;
144456a221efSShri Abhyankar       const PetscInt    *cols;
144556a221efSShri Abhyankar       const PetscScalar *vals;
14462969f145SShri Abhyankar       PetscScalar        value[2];
14472969f145SShri Abhyankar       PetscInt           row,col[2];
1448493a4f3dSShri Abhyankar       PetscInt           *d_nnz;
14492969f145SShri Abhyankar       value[0] = 1.0; value[1] = 0.0;
1450493a4f3dSShri Abhyankar       ierr = PetscMalloc((X->map->n+nkept)*sizeof(PetscInt),&d_nnz);CHKERRQ(ierr);
1451493a4f3dSShri Abhyankar       ierr = PetscMemzero(d_nnz,(X->map->n+nkept)*sizeof(PetscInt));CHKERRQ(ierr);
1452493a4f3dSShri Abhyankar       for(row=0;row<snes->jacobian->rmap->n;row++) {
1453493a4f3dSShri Abhyankar         ierr = MatGetRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
1454493a4f3dSShri Abhyankar         d_nnz[row] += ncols;
1455493a4f3dSShri Abhyankar         ierr = MatRestoreRow(snes->jacobian,row,&ncols,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
1456493a4f3dSShri Abhyankar       }
1457493a4f3dSShri Abhyankar 
1458493a4f3dSShri Abhyankar       for(k=0;k<nkept;k++) {
1459493a4f3dSShri Abhyankar         d_nnz[idx_actkept[k]] += 1;
14602969f145SShri Abhyankar         d_nnz[snes->jacobian->rmap->n+k] += 2;
1461493a4f3dSShri Abhyankar       }
1462493a4f3dSShri Abhyankar       ierr = MatSeqAIJSetPreallocation(J_aug,PETSC_NULL,d_nnz);CHKERRQ(ierr);
1463493a4f3dSShri Abhyankar 
1464493a4f3dSShri Abhyankar       ierr = PetscFree(d_nnz);CHKERRQ(ierr);
146556a221efSShri Abhyankar 
146656a221efSShri Abhyankar       /* Set the original jacobian matrix in J_aug */
146756a221efSShri Abhyankar       for(row=0;row<snes->jacobian->rmap->n;row++) {
146856a221efSShri Abhyankar 	ierr = MatGetRow(snes->jacobian,row,&ncols,&cols,&vals);CHKERRQ(ierr);
146956a221efSShri Abhyankar 	ierr = MatSetValues(J_aug,1,&row,ncols,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
147056a221efSShri Abhyankar 	ierr = MatRestoreRow(snes->jacobian,row,&ncols,&cols,&vals);CHKERRQ(ierr);
147156a221efSShri Abhyankar       }
147256a221efSShri Abhyankar       /* Add the augmented part */
147356a221efSShri Abhyankar       for(k=0;k<nkept;k++) {
14742969f145SShri Abhyankar 	row = snes->jacobian->rmap->n+k;
14752969f145SShri Abhyankar 	col[0] = idx_actkept[k]; col[1] = snes->jacobian->rmap->n+k;
14762969f145SShri Abhyankar 	ierr = MatSetValues(J_aug,1,&row,1,col,value,INSERT_VALUES);CHKERRQ(ierr);
14772969f145SShri Abhyankar 	ierr = MatSetValues(J_aug,1,&col[0],1,&row,&value[0],INSERT_VALUES);CHKERRQ(ierr);
147856a221efSShri Abhyankar       }
147956a221efSShri Abhyankar       ierr = MatAssemblyBegin(J_aug,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
148056a221efSShri Abhyankar       ierr = MatAssemblyEnd(J_aug,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
148156a221efSShri Abhyankar       /* Only considering prejac = jac for now */
148256a221efSShri Abhyankar       Jpre_aug = J_aug;
14839521db3cSSatish Balay       } /* local vars*/
1484e63076c7SBarry Smith       ierr = ISRestoreIndices(IS_act,&idx_act);CHKERRQ(ierr);
1485e63076c7SBarry Smith       ierr = ISDestroy(&IS_act);CHKERRQ(ierr);
148656a221efSShri Abhyankar     } else {
148756a221efSShri Abhyankar       F_aug = F; J_aug = snes->jacobian; Y_aug = Y; Jpre_aug = snes->jacobian_pre;
148856a221efSShri Abhyankar     }
14892f63a38cSShri Abhyankar 
14902f63a38cSShri Abhyankar     ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr);
14912f63a38cSShri Abhyankar     if (!isequal) {
149256a221efSShri Abhyankar       ierr = SNESVIResetPCandKSP(snes,J_aug,Jpre_aug);CHKERRQ(ierr);
14932f63a38cSShri Abhyankar     }
149456a221efSShri Abhyankar     ierr = KSPSetOperators(snes->ksp,J_aug,Jpre_aug,flg);CHKERRQ(ierr);
14952f63a38cSShri Abhyankar     ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr);
149656a221efSShri Abhyankar     /*  {
14972f63a38cSShri Abhyankar       PC        pc;
14982f63a38cSShri Abhyankar       PetscBool flg;
14992f63a38cSShri Abhyankar       ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr);
15002f63a38cSShri Abhyankar       ierr = PetscTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr);
15012f63a38cSShri Abhyankar       if (flg) {
15022f63a38cSShri Abhyankar         KSP      *subksps;
15032f63a38cSShri Abhyankar         ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr);
15042f63a38cSShri Abhyankar         ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr);
15052f63a38cSShri Abhyankar         ierr = PetscFree(subksps);CHKERRQ(ierr);
15062f63a38cSShri Abhyankar         ierr = PetscTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr);
15072f63a38cSShri Abhyankar         if (flg) {
15082f63a38cSShri Abhyankar           PetscInt       n,N = 101*101,j,cnts[3] = {0,0,0};
15092f63a38cSShri Abhyankar           const PetscInt *ii;
15102f63a38cSShri Abhyankar 
15112f63a38cSShri Abhyankar           ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr);
15122f63a38cSShri Abhyankar           ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr);
15132f63a38cSShri Abhyankar           for (j=0; j<n; j++) {
15142f63a38cSShri Abhyankar             if (ii[j] < N) cnts[0]++;
15152f63a38cSShri Abhyankar             else if (ii[j] < 2*N) cnts[1]++;
15162f63a38cSShri Abhyankar             else if (ii[j] < 3*N) cnts[2]++;
15172f63a38cSShri Abhyankar           }
15182f63a38cSShri Abhyankar           ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr);
15192f63a38cSShri Abhyankar 
15202f63a38cSShri Abhyankar           ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr);
15212f63a38cSShri Abhyankar         }
15222f63a38cSShri Abhyankar       }
15232f63a38cSShri Abhyankar     }
152456a221efSShri Abhyankar     */
152556a221efSShri Abhyankar     ierr = SNES_KSPSolve(snes,snes->ksp,F_aug,Y_aug);CHKERRQ(ierr);
15262f63a38cSShri Abhyankar     ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr);
15272f63a38cSShri Abhyankar     if (kspreason < 0) {
15282f63a38cSShri Abhyankar       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
15292f63a38cSShri 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);
15302f63a38cSShri Abhyankar         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
15312f63a38cSShri Abhyankar         break;
15322f63a38cSShri Abhyankar       }
15332f63a38cSShri Abhyankar     }
15342f63a38cSShri Abhyankar 
153556a221efSShri Abhyankar     if(nis_act) {
153656a221efSShri Abhyankar       PetscScalar *y1,*y2;
153756a221efSShri Abhyankar       ierr = VecGetArray(Y,&y1);CHKERRQ(ierr);
153856a221efSShri Abhyankar       ierr = VecGetArray(Y_aug,&y2);CHKERRQ(ierr);
153956a221efSShri Abhyankar       /* Copy over inactive Y_aug to Y */
154056a221efSShri Abhyankar       j1 = 0;
154156a221efSShri Abhyankar       for(i1=Y->map->rstart;i1 < Y->map->rend;i1++) {
154256a221efSShri Abhyankar 	if(j1 < nkept && idx_actkept[j1] == i1) j1++;
154356a221efSShri Abhyankar 	else y1[i1-Y->map->rstart] = y2[i1-Y->map->rstart];
154456a221efSShri Abhyankar       }
154556a221efSShri Abhyankar       ierr = VecRestoreArray(Y,&y1);CHKERRQ(ierr);
154656a221efSShri Abhyankar       ierr = VecRestoreArray(Y_aug,&y2);CHKERRQ(ierr);
15472f63a38cSShri Abhyankar 
15486bf464f9SBarry Smith       ierr = VecDestroy(&F_aug);CHKERRQ(ierr);
15496bf464f9SBarry Smith       ierr = VecDestroy(&Y_aug);CHKERRQ(ierr);
15506bf464f9SBarry Smith       ierr = MatDestroy(&J_aug);CHKERRQ(ierr);
155156a221efSShri Abhyankar       ierr = PetscFree(idx_actkept);CHKERRQ(ierr);
155256a221efSShri Abhyankar     }
155356a221efSShri Abhyankar 
15542f63a38cSShri Abhyankar     if (!isequal) {
15556bf464f9SBarry Smith       ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr);
15562f63a38cSShri Abhyankar       ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr);
15572f63a38cSShri Abhyankar     }
15586bf464f9SBarry Smith     ierr = ISDestroy(&IS_inact);CHKERRQ(ierr);
155956a221efSShri Abhyankar 
15602f63a38cSShri Abhyankar     ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
15612f63a38cSShri Abhyankar     snes->linear_its += lits;
15622f63a38cSShri Abhyankar     ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr);
15632f63a38cSShri Abhyankar     /*
15642f63a38cSShri Abhyankar     if (vi->precheckstep) {
15652f63a38cSShri Abhyankar       PetscBool changed_y = PETSC_FALSE;
15662f63a38cSShri Abhyankar       ierr = (*vi->precheckstep)(snes,X,Y,vi->precheck,&changed_y);CHKERRQ(ierr);
15672f63a38cSShri Abhyankar     }
15682f63a38cSShri Abhyankar 
15692f63a38cSShri Abhyankar     if (PetscLogPrintInfo){
15702f63a38cSShri Abhyankar       ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr);
15712f63a38cSShri Abhyankar     }
15722f63a38cSShri Abhyankar     */
15732f63a38cSShri Abhyankar     /* Compute a (scaled) negative update in the line search routine:
15742f63a38cSShri Abhyankar          Y <- X - lambda*Y
15752f63a38cSShri Abhyankar        and evaluate G = function(Y) (depends on the line search).
15762f63a38cSShri Abhyankar     */
15772f63a38cSShri Abhyankar     ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr);
15782f63a38cSShri Abhyankar     ynorm = 1; gnorm = fnorm;
15792f63a38cSShri Abhyankar     ierr = (*vi->LineSearch)(snes,vi->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr);
15802f63a38cSShri Abhyankar     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr);
15812f63a38cSShri Abhyankar     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
15822f63a38cSShri Abhyankar     if (snes->domainerror) {
15832f63a38cSShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
15842f63a38cSShri Abhyankar       PetscFunctionReturn(0);
15852f63a38cSShri Abhyankar     }
15862f63a38cSShri Abhyankar     if (!lssucceed) {
15872f63a38cSShri Abhyankar       if (++snes->numFailures >= snes->maxFailures) {
15882f63a38cSShri Abhyankar 	PetscBool ismin;
15892f63a38cSShri Abhyankar         snes->reason = SNES_DIVERGED_LINE_SEARCH;
15902f63a38cSShri Abhyankar         ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr);
15912f63a38cSShri Abhyankar         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
15922f63a38cSShri Abhyankar         break;
15932f63a38cSShri Abhyankar       }
15942f63a38cSShri Abhyankar     }
15952f63a38cSShri Abhyankar     /* Update function and solution vectors */
15962f63a38cSShri Abhyankar     fnorm = gnorm;
15972f63a38cSShri Abhyankar     ierr = VecCopy(G,F);CHKERRQ(ierr);
15982f63a38cSShri Abhyankar     ierr = VecCopy(W,X);CHKERRQ(ierr);
15992f63a38cSShri Abhyankar     /* Monitor convergence */
16002f63a38cSShri Abhyankar     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
16012f63a38cSShri Abhyankar     snes->iter = i+1;
16022f63a38cSShri Abhyankar     snes->norm = fnorm;
16032f63a38cSShri Abhyankar     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
16042f63a38cSShri Abhyankar     SNESLogConvHistory(snes,snes->norm,lits);
16057a03ce2fSLisandro Dalcin     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
16062f63a38cSShri Abhyankar     /* Test for convergence, xnorm = || X || */
16072f63a38cSShri Abhyankar     if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); }
16082f63a38cSShri Abhyankar     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
16092f63a38cSShri Abhyankar     if (snes->reason) break;
16102f63a38cSShri Abhyankar   }
16112f63a38cSShri Abhyankar   if (i == maxits) {
16122f63a38cSShri Abhyankar     ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr);
16132f63a38cSShri Abhyankar     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
16142f63a38cSShri Abhyankar   }
16152f63a38cSShri Abhyankar   PetscFunctionReturn(0);
16162f63a38cSShri Abhyankar }
16172f63a38cSShri Abhyankar 
16182b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
16192b4ed282SShri Abhyankar /*
16202b4ed282SShri Abhyankar    SNESSetUp_VI - Sets up the internal data structures for the later use
16212b4ed282SShri Abhyankar    of the SNESVI nonlinear solver.
16222b4ed282SShri Abhyankar 
16232b4ed282SShri Abhyankar    Input Parameter:
16242b4ed282SShri Abhyankar .  snes - the SNES context
16252b4ed282SShri Abhyankar .  x - the solution vector
16262b4ed282SShri Abhyankar 
16272b4ed282SShri Abhyankar    Application Interface Routine: SNESSetUp()
16282b4ed282SShri Abhyankar 
16292b4ed282SShri Abhyankar    Notes:
16302b4ed282SShri Abhyankar    For basic use of the SNES solvers, the user need not explicitly call
16312b4ed282SShri Abhyankar    SNESSetUp(), since these actions will automatically occur during
16322b4ed282SShri Abhyankar    the call to SNESSolve().
16332b4ed282SShri Abhyankar  */
16342b4ed282SShri Abhyankar #undef __FUNCT__
16352b4ed282SShri Abhyankar #define __FUNCT__ "SNESSetUp_VI"
16362b4ed282SShri Abhyankar PetscErrorCode SNESSetUp_VI(SNES snes)
16372b4ed282SShri Abhyankar {
16382b4ed282SShri Abhyankar   PetscErrorCode ierr;
16392b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*) snes->data;
16402b4ed282SShri Abhyankar   PetscInt       i_start[3],i_end[3];
16412b4ed282SShri Abhyankar 
16422b4ed282SShri Abhyankar   PetscFunctionBegin;
164358c9b817SLisandro Dalcin 
164458c9b817SLisandro Dalcin   ierr = SNESDefaultGetWork(snes,3);CHKERRQ(ierr);
16452b4ed282SShri Abhyankar 
16462b4ed282SShri Abhyankar   /* If the lower and upper bound on variables are not set, set it to
16472b4ed282SShri Abhyankar      -Inf and Inf */
16482b4ed282SShri Abhyankar   if (!vi->xl && !vi->xu) {
16492b4ed282SShri Abhyankar     vi->usersetxbounds = PETSC_FALSE;
16502b4ed282SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->xl); CHKERRQ(ierr);
165101f0b76bSBarry Smith     ierr = VecSet(vi->xl,SNES_VI_NINF);CHKERRQ(ierr);
16522b4ed282SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->xu); CHKERRQ(ierr);
165301f0b76bSBarry Smith     ierr = VecSet(vi->xu,SNES_VI_INF);CHKERRQ(ierr);
16542b4ed282SShri Abhyankar   } else {
16552b4ed282SShri Abhyankar     /* Check if lower bound, upper bound and solution vector distribution across the processors is identical */
16562b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(snes->vec_sol,i_start,i_end);CHKERRQ(ierr);
16572b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(vi->xl,i_start+1,i_end+1);CHKERRQ(ierr);
16582b4ed282SShri Abhyankar     ierr = VecGetOwnershipRange(vi->xu,i_start+2,i_end+2);CHKERRQ(ierr);
16592b4ed282SShri 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]))
16602b4ed282SShri 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.");
16612b4ed282SShri Abhyankar   }
16622f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
1663abcba341SShri Abhyankar     /* Set up previous active index set for the first snes solve
1664abcba341SShri Abhyankar        vi->IS_inact_prev = 0,1,2,....N */
1665abcba341SShri Abhyankar     PetscInt *indices;
1666abcba341SShri Abhyankar     PetscInt  i,n,rstart,rend;
1667abcba341SShri Abhyankar 
1668abcba341SShri Abhyankar     ierr = VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);CHKERRQ(ierr);
1669abcba341SShri Abhyankar     ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr);
1670abcba341SShri Abhyankar     ierr = PetscMalloc(n*sizeof(PetscInt),&indices);CHKERRQ(ierr);
1671abcba341SShri Abhyankar     for(i=0;i < n; i++) indices[i] = rstart + i;
1672abcba341SShri Abhyankar     ierr = ISCreateGeneral(((PetscObject)snes)->comm,n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);
1673abcba341SShri Abhyankar   }
16742b4ed282SShri Abhyankar 
16752f63a38cSShri Abhyankar   if (snes->ops->solve == SNESSolveVI_SS) {
1676fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->dpsi);CHKERRQ(ierr);
1677fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->phi); CHKERRQ(ierr);
1678fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->Da); CHKERRQ(ierr);
1679fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->Db); CHKERRQ(ierr);
1680fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->z);CHKERRQ(ierr);
1681fe835674SShri Abhyankar     ierr = VecDuplicate(snes->vec_sol, &vi->t); CHKERRQ(ierr);
1682fe835674SShri Abhyankar   }
16832b4ed282SShri Abhyankar   PetscFunctionReturn(0);
16842b4ed282SShri Abhyankar }
16852b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
16862b4ed282SShri Abhyankar /*
16872b4ed282SShri Abhyankar    SNESDestroy_VI - Destroys the private SNES_VI context that was created
16882b4ed282SShri Abhyankar    with SNESCreate_VI().
16892b4ed282SShri Abhyankar 
16902b4ed282SShri Abhyankar    Input Parameter:
16912b4ed282SShri Abhyankar .  snes - the SNES context
16922b4ed282SShri Abhyankar 
16932b4ed282SShri Abhyankar    Application Interface Routine: SNESDestroy()
16942b4ed282SShri Abhyankar  */
16952b4ed282SShri Abhyankar #undef __FUNCT__
16962b4ed282SShri Abhyankar #define __FUNCT__ "SNESDestroy_VI"
16972b4ed282SShri Abhyankar PetscErrorCode SNESDestroy_VI(SNES snes)
16982b4ed282SShri Abhyankar {
16992b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*) snes->data;
17002b4ed282SShri Abhyankar   PetscErrorCode ierr;
17012b4ed282SShri Abhyankar 
17022b4ed282SShri Abhyankar   PetscFunctionBegin;
17032f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
17046bf464f9SBarry Smith     ierr = ISDestroy(&vi->IS_inact_prev);
1705abcba341SShri Abhyankar   }
17062b4ed282SShri Abhyankar 
17072f63a38cSShri Abhyankar   if (snes->ops->solve == SNESSolveVI_SS) {
17082b4ed282SShri Abhyankar     /* clear vectors */
17096bf464f9SBarry Smith     ierr = VecDestroy(&vi->dpsi);CHKERRQ(ierr);
17106bf464f9SBarry Smith     ierr = VecDestroy(&vi->phi); CHKERRQ(ierr);
17116bf464f9SBarry Smith     ierr = VecDestroy(&vi->Da); CHKERRQ(ierr);
17126bf464f9SBarry Smith     ierr = VecDestroy(&vi->Db); CHKERRQ(ierr);
17136bf464f9SBarry Smith     ierr = VecDestroy(&vi->z); CHKERRQ(ierr);
17146bf464f9SBarry Smith     ierr = VecDestroy(&vi->t); CHKERRQ(ierr);
17157fe79bc4SShri Abhyankar   }
17167fe79bc4SShri Abhyankar 
17172b4ed282SShri Abhyankar   if (!vi->usersetxbounds) {
17186bf464f9SBarry Smith     ierr = VecDestroy(&vi->xl); CHKERRQ(ierr);
17196bf464f9SBarry Smith     ierr = VecDestroy(&vi->xu); CHKERRQ(ierr);
17202b4ed282SShri Abhyankar   }
17217fe79bc4SShri Abhyankar 
17226bf464f9SBarry Smith   ierr = PetscViewerASCIIMonitorDestroy(&vi->lsmonitor);CHKERRQ(ierr);
17232b4ed282SShri Abhyankar   ierr = PetscFree(snes->data);CHKERRQ(ierr);
17242b4ed282SShri Abhyankar 
17252b4ed282SShri Abhyankar   /* clear composed functions */
17262b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr);
1727c92abb8aSShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","",PETSC_NULL);CHKERRQ(ierr);
17282b4ed282SShri Abhyankar   PetscFunctionReturn(0);
17292b4ed282SShri Abhyankar }
17307fe79bc4SShri Abhyankar 
17312b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
17322b4ed282SShri Abhyankar #undef __FUNCT__
17332b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchNo_VI"
17342b4ed282SShri Abhyankar 
17352b4ed282SShri Abhyankar /*
17367fe79bc4SShri Abhyankar   This routine does not actually do a line search but it takes a full newton
17377fe79bc4SShri Abhyankar   step while ensuring that the new iterates remain within the constraints.
17382b4ed282SShri Abhyankar 
17392b4ed282SShri Abhyankar */
1740ace3abfcSBarry 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)
17412b4ed282SShri Abhyankar {
17422b4ed282SShri Abhyankar   PetscErrorCode ierr;
17432b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1744ace3abfcSBarry Smith   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
17452b4ed282SShri Abhyankar 
17462b4ed282SShri Abhyankar   PetscFunctionBegin;
17472b4ed282SShri Abhyankar   *flag = PETSC_TRUE;
17482b4ed282SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
17492b4ed282SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);         /* ynorm = || y || */
17502b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
1751c1a5e521SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1752c1a5e521SShri Abhyankar   if (vi->postcheckstep) {
1753c1a5e521SShri Abhyankar    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1754c1a5e521SShri Abhyankar   }
1755c1a5e521SShri Abhyankar   if (changed_y) {
1756c1a5e521SShri Abhyankar     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
17577fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1758c1a5e521SShri Abhyankar   }
1759c1a5e521SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1760c1a5e521SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
1761c1a5e521SShri Abhyankar   if (!snes->domainerror) {
17622f63a38cSShri Abhyankar     if (snes->ops->solve != SNESSolveVI_SS) {
17637fe79bc4SShri Abhyankar        ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
17647fe79bc4SShri Abhyankar     } else {
1765c1a5e521SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);  /* gnorm = || g || */
17667fe79bc4SShri Abhyankar     }
176762cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1768c1a5e521SShri Abhyankar   }
1769c1a5e521SShri Abhyankar   if (vi->lsmonitor) {
1770c1a5e521SShri Abhyankar     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1771c1a5e521SShri Abhyankar   }
1772c1a5e521SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1773c1a5e521SShri Abhyankar   PetscFunctionReturn(0);
1774c1a5e521SShri Abhyankar }
1775c1a5e521SShri Abhyankar 
1776c1a5e521SShri Abhyankar /* -------------------------------------------------------------------------- */
1777c1a5e521SShri Abhyankar #undef __FUNCT__
17782b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchNoNorms_VI"
17792b4ed282SShri Abhyankar 
17802b4ed282SShri Abhyankar /*
17812b4ed282SShri Abhyankar   This routine is a copy of SNESLineSearchNoNorms in snes/impls/ls/ls.c
17822b4ed282SShri Abhyankar */
1783ace3abfcSBarry 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)
17842b4ed282SShri Abhyankar {
17852b4ed282SShri Abhyankar   PetscErrorCode ierr;
17862b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1787ace3abfcSBarry Smith   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
17882b4ed282SShri Abhyankar 
17892b4ed282SShri Abhyankar   PetscFunctionBegin;
17902b4ed282SShri Abhyankar   *flag = PETSC_TRUE;
17912b4ed282SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
17922b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y      */
17937fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
17942b4ed282SShri Abhyankar   if (vi->postcheckstep) {
17952b4ed282SShri Abhyankar    ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
17962b4ed282SShri Abhyankar   }
17972b4ed282SShri Abhyankar   if (changed_y) {
17982b4ed282SShri Abhyankar     ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);            /* w <- x - y   */
17997fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
18002b4ed282SShri Abhyankar   }
18012b4ed282SShri Abhyankar 
18022b4ed282SShri Abhyankar   /* don't evaluate function the last time through */
18032b4ed282SShri Abhyankar   if (snes->iter < snes->max_its-1) {
18042b4ed282SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
18052b4ed282SShri Abhyankar   }
18062b4ed282SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
18072b4ed282SShri Abhyankar   PetscFunctionReturn(0);
18082b4ed282SShri Abhyankar }
18097fe79bc4SShri Abhyankar 
18102b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
18112b4ed282SShri Abhyankar #undef __FUNCT__
18122b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchCubic_VI"
18132b4ed282SShri Abhyankar /*
18147fe79bc4SShri Abhyankar   This routine implements a cubic line search while doing a projection on the variable bounds
18152b4ed282SShri Abhyankar */
1816ace3abfcSBarry 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)
18172b4ed282SShri Abhyankar {
1818fe835674SShri Abhyankar   PetscReal      initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength;
1819fe835674SShri Abhyankar   PetscReal      minlambda,lambda,lambdatemp;
1820fe835674SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
1821fe835674SShri Abhyankar   PetscScalar    cinitslope;
1822fe835674SShri Abhyankar #endif
1823fe835674SShri Abhyankar   PetscErrorCode ierr;
1824fe835674SShri Abhyankar   PetscInt       count;
1825fe835674SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
1826fe835674SShri Abhyankar   PetscBool      changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
1827fe835674SShri Abhyankar   MPI_Comm       comm;
1828fe835674SShri Abhyankar 
1829fe835674SShri Abhyankar   PetscFunctionBegin;
1830fe835674SShri Abhyankar   ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr);
1831fe835674SShri Abhyankar   ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1832fe835674SShri Abhyankar   *flag   = PETSC_TRUE;
1833fe835674SShri Abhyankar 
1834fe835674SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
1835fe835674SShri Abhyankar   if (*ynorm == 0.0) {
1836fe835674SShri Abhyankar     if (vi->lsmonitor) {
1837fe835674SShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
1838fe835674SShri Abhyankar     }
1839fe835674SShri Abhyankar     *gnorm = fnorm;
1840fe835674SShri Abhyankar     ierr   = VecCopy(x,w);CHKERRQ(ierr);
1841fe835674SShri Abhyankar     ierr   = VecCopy(f,g);CHKERRQ(ierr);
1842fe835674SShri Abhyankar     *flag  = PETSC_FALSE;
1843fe835674SShri Abhyankar     goto theend1;
1844fe835674SShri Abhyankar   }
1845fe835674SShri Abhyankar   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
1846fe835674SShri Abhyankar     if (vi->lsmonitor) {
1847fe835674SShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Scaling step by %G old ynorm %G\n",vi->maxstep/(*ynorm),*ynorm);CHKERRQ(ierr);
1848fe835674SShri Abhyankar     }
1849fe835674SShri Abhyankar     ierr = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
1850fe835674SShri Abhyankar     *ynorm = vi->maxstep;
1851fe835674SShri Abhyankar   }
1852fe835674SShri Abhyankar   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
1853fe835674SShri Abhyankar   minlambda = vi->minlambda/rellength;
1854fe835674SShri Abhyankar   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
1855fe835674SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
1856fe835674SShri Abhyankar   ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
1857fe835674SShri Abhyankar   initslope = PetscRealPart(cinitslope);
1858fe835674SShri Abhyankar #else
1859fe835674SShri Abhyankar   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
1860fe835674SShri Abhyankar #endif
1861fe835674SShri Abhyankar   if (initslope > 0.0)  initslope = -initslope;
1862fe835674SShri Abhyankar   if (initslope == 0.0) initslope = -1.0;
1863fe835674SShri Abhyankar 
1864fe835674SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1865fe835674SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1866fe835674SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
1867fe835674SShri Abhyankar     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
1868fe835674SShri Abhyankar     *flag = PETSC_FALSE;
1869fe835674SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1870fe835674SShri Abhyankar     goto theend1;
1871fe835674SShri Abhyankar   }
1872fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
18732f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
1874fe835674SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
18757fe79bc4SShri Abhyankar   } else {
18767fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
18777fe79bc4SShri Abhyankar   }
1878fe835674SShri Abhyankar   if (snes->domainerror) {
1879fe835674SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1880fe835674SShri Abhyankar     PetscFunctionReturn(0);
1881fe835674SShri Abhyankar   }
188262cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1883fe835674SShri Abhyankar   ierr = PetscInfo2(snes,"Initial fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1884fe835674SShri Abhyankar   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
1885fe835674SShri Abhyankar     if (vi->lsmonitor) {
1886fe835674SShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
1887fe835674SShri Abhyankar     }
1888fe835674SShri Abhyankar     goto theend1;
1889fe835674SShri Abhyankar   }
1890fe835674SShri Abhyankar 
1891fe835674SShri Abhyankar   /* Fit points with quadratic */
1892fe835674SShri Abhyankar   lambda     = 1.0;
1893fe835674SShri Abhyankar   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
1894fe835674SShri Abhyankar   lambdaprev = lambda;
1895fe835674SShri Abhyankar   gnormprev  = *gnorm;
1896fe835674SShri Abhyankar   if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1897fe835674SShri Abhyankar   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
1898fe835674SShri Abhyankar   else                         lambda = lambdatemp;
1899fe835674SShri Abhyankar 
1900fe835674SShri Abhyankar   ierr  = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1901fe835674SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1902fe835674SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
1903fe835674SShri Abhyankar     ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
1904fe835674SShri Abhyankar     *flag = PETSC_FALSE;
1905fe835674SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1906fe835674SShri Abhyankar     goto theend1;
1907fe835674SShri Abhyankar   }
1908fe835674SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
19092f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
1910fe835674SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
19117fe79bc4SShri Abhyankar   } else {
19127fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
19137fe79bc4SShri Abhyankar   }
1914fe835674SShri Abhyankar   if (snes->domainerror) {
1915fe835674SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1916fe835674SShri Abhyankar     PetscFunctionReturn(0);
1917fe835674SShri Abhyankar   }
191862cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1919fe835674SShri Abhyankar   if (vi->lsmonitor) {
1920fe835674SShri Abhyankar     ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: gnorm after quadratic fit %G\n",*gnorm);CHKERRQ(ierr);
1921fe835674SShri Abhyankar   }
1922fe835674SShri Abhyankar   if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
1923fe835674SShri Abhyankar     if (vi->lsmonitor) {
1924fe835674SShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr);
1925fe835674SShri Abhyankar     }
1926fe835674SShri Abhyankar     goto theend1;
1927fe835674SShri Abhyankar   }
1928fe835674SShri Abhyankar 
1929fe835674SShri Abhyankar   /* Fit points with cubic */
1930fe835674SShri Abhyankar   count = 1;
1931fe835674SShri Abhyankar   while (PETSC_TRUE) {
1932fe835674SShri Abhyankar     if (lambda <= minlambda) {
1933fe835674SShri Abhyankar       if (vi->lsmonitor) {
1934fe835674SShri Abhyankar 	ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
1935fe835674SShri 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);
1936fe835674SShri Abhyankar       }
1937fe835674SShri Abhyankar       *flag = PETSC_FALSE;
1938fe835674SShri Abhyankar       break;
1939fe835674SShri Abhyankar     }
1940fe835674SShri Abhyankar     t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope;
1941fe835674SShri Abhyankar     t2 = .5*(gnormprev*gnormprev  - fnorm*fnorm) - lambdaprev*initslope;
1942fe835674SShri Abhyankar     a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1943fe835674SShri Abhyankar     b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
1944fe835674SShri Abhyankar     d  = b*b - 3*a*initslope;
1945fe835674SShri Abhyankar     if (d < 0.0) d = 0.0;
1946fe835674SShri Abhyankar     if (a == 0.0) {
1947fe835674SShri Abhyankar       lambdatemp = -initslope/(2.0*b);
1948fe835674SShri Abhyankar     } else {
1949fe835674SShri Abhyankar       lambdatemp = (-b + sqrt(d))/(3.0*a);
1950fe835674SShri Abhyankar     }
1951fe835674SShri Abhyankar     lambdaprev = lambda;
1952fe835674SShri Abhyankar     gnormprev  = *gnorm;
1953fe835674SShri Abhyankar     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
1954fe835674SShri Abhyankar     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
1955fe835674SShri Abhyankar     else                         lambda     = lambdatemp;
1956fe835674SShri Abhyankar     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
1957fe835674SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1958fe835674SShri Abhyankar     if (snes->nfuncs >= snes->max_funcs) {
1959fe835674SShri Abhyankar       ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
1960fe835674SShri 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);
1961fe835674SShri Abhyankar       *flag = PETSC_FALSE;
1962fe835674SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
1963fe835674SShri Abhyankar       break;
1964fe835674SShri Abhyankar     }
1965fe835674SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
19662f63a38cSShri Abhyankar     if (snes->ops->solve != SNESSolveVI_SS) {
1967fe835674SShri Abhyankar       ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
19687fe79bc4SShri Abhyankar     } else {
19697fe79bc4SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
19707fe79bc4SShri Abhyankar     }
1971fe835674SShri Abhyankar     if (snes->domainerror) {
1972fe835674SShri Abhyankar       ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
1973fe835674SShri Abhyankar       PetscFunctionReturn(0);
1974fe835674SShri Abhyankar     }
197562cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
1976fe835674SShri Abhyankar     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* is reduction enough? */
1977fe835674SShri Abhyankar       if (vi->lsmonitor) {
1978fe835674SShri Abhyankar 	ierr = PetscPrintf(comm,"    Line search: Cubically determined step, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1979fe835674SShri Abhyankar       }
1980fe835674SShri Abhyankar       break;
1981fe835674SShri Abhyankar     } else {
1982fe835674SShri Abhyankar       if (vi->lsmonitor) {
1983fe835674SShri Abhyankar         ierr = PetscPrintf(comm,"    Line search: Cubic step no good, shrinking lambda, current gnorm %G lambda=%18.16e\n",*gnorm,lambda);CHKERRQ(ierr);
1984fe835674SShri Abhyankar       }
1985fe835674SShri Abhyankar     }
1986fe835674SShri Abhyankar     count++;
1987fe835674SShri Abhyankar   }
1988fe835674SShri Abhyankar   theend1:
1989fe835674SShri Abhyankar   /* Optional user-defined check for line search step validity */
1990fe835674SShri Abhyankar   if (vi->postcheckstep && *flag) {
1991fe835674SShri Abhyankar     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
1992fe835674SShri Abhyankar     if (changed_y) {
1993fe835674SShri Abhyankar       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
1994fe835674SShri Abhyankar       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
1995fe835674SShri Abhyankar     }
1996fe835674SShri Abhyankar     if (changed_y || changed_w) { /* recompute the function if the step has changed */
1997fe835674SShri Abhyankar       ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
19982f63a38cSShri Abhyankar       if (snes->ops->solve != SNESSolveVI_SS) {
1999fe835674SShri Abhyankar         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
20007fe79bc4SShri Abhyankar       } else {
20017fe79bc4SShri Abhyankar         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
20027fe79bc4SShri Abhyankar       }
2003fe835674SShri Abhyankar       if (snes->domainerror) {
2004fe835674SShri Abhyankar         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2005fe835674SShri Abhyankar         PetscFunctionReturn(0);
2006fe835674SShri Abhyankar       }
200762cbcd01SMatthew G Knepley       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
2008fe835674SShri Abhyankar       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
2009fe835674SShri Abhyankar       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
2010fe835674SShri Abhyankar     }
2011fe835674SShri Abhyankar   }
2012fe835674SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
2013fe835674SShri Abhyankar   PetscFunctionReturn(0);
2014fe835674SShri Abhyankar }
2015fe835674SShri Abhyankar 
20162b4ed282SShri Abhyankar #undef __FUNCT__
20172b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchQuadratic_VI"
20182b4ed282SShri Abhyankar /*
20197fe79bc4SShri Abhyankar   This routine does a quadratic line search while keeping the iterates within the variable bounds
20202b4ed282SShri Abhyankar */
2021ace3abfcSBarry 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)
20222b4ed282SShri Abhyankar {
20232b4ed282SShri Abhyankar   /*
20242b4ed282SShri Abhyankar      Note that for line search purposes we work with with the related
20252b4ed282SShri Abhyankar      minimization problem:
20262b4ed282SShri Abhyankar         min  z(x):  R^n -> R,
20272b4ed282SShri Abhyankar      where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2.
20282b4ed282SShri Abhyankar    */
20292b4ed282SShri Abhyankar   PetscReal      initslope,minlambda,lambda,lambdatemp,rellength;
20302b4ed282SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
20312b4ed282SShri Abhyankar   PetscScalar    cinitslope;
20322b4ed282SShri Abhyankar #endif
20332b4ed282SShri Abhyankar   PetscErrorCode ierr;
20342b4ed282SShri Abhyankar   PetscInt       count;
20352b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
2036ace3abfcSBarry Smith   PetscBool     changed_w = PETSC_FALSE,changed_y = PETSC_FALSE;
20372b4ed282SShri Abhyankar 
20382b4ed282SShri Abhyankar   PetscFunctionBegin;
20392b4ed282SShri Abhyankar   ierr    = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
20402b4ed282SShri Abhyankar   *flag   = PETSC_TRUE;
20412b4ed282SShri Abhyankar 
20422b4ed282SShri Abhyankar   ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr);
20432b4ed282SShri Abhyankar   if (*ynorm == 0.0) {
2044c92abb8aSShri Abhyankar     if (vi->lsmonitor) {
2045c92abb8aSShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Direction and size is 0\n");CHKERRQ(ierr);
20462b4ed282SShri Abhyankar     }
20472b4ed282SShri Abhyankar     *gnorm = fnorm;
20482b4ed282SShri Abhyankar     ierr   = VecCopy(x,w);CHKERRQ(ierr);
20492b4ed282SShri Abhyankar     ierr   = VecCopy(f,g);CHKERRQ(ierr);
20502b4ed282SShri Abhyankar     *flag  = PETSC_FALSE;
20512b4ed282SShri Abhyankar     goto theend2;
20522b4ed282SShri Abhyankar   }
20532b4ed282SShri Abhyankar   if (*ynorm > vi->maxstep) {	/* Step too big, so scale back */
20542b4ed282SShri Abhyankar     ierr   = VecScale(y,vi->maxstep/(*ynorm));CHKERRQ(ierr);
20552b4ed282SShri Abhyankar     *ynorm = vi->maxstep;
20562b4ed282SShri Abhyankar   }
20572b4ed282SShri Abhyankar   ierr      = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr);
20582b4ed282SShri Abhyankar   minlambda = vi->minlambda/rellength;
20597fe79bc4SShri Abhyankar   ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr);
20602b4ed282SShri Abhyankar #if defined(PETSC_USE_COMPLEX)
20617fe79bc4SShri Abhyankar   ierr      = VecDot(f,w,&cinitslope);CHKERRQ(ierr);
20622b4ed282SShri Abhyankar   initslope = PetscRealPart(cinitslope);
20632b4ed282SShri Abhyankar #else
20647fe79bc4SShri Abhyankar   ierr = VecDot(f,w,&initslope);CHKERRQ(ierr);
20652b4ed282SShri Abhyankar #endif
20662b4ed282SShri Abhyankar   if (initslope > 0.0)  initslope = -initslope;
20672b4ed282SShri Abhyankar   if (initslope == 0.0) initslope = -1.0;
20682b4ed282SShri Abhyankar   ierr = PetscInfo1(snes,"Initslope %G \n",initslope);CHKERRQ(ierr);
20692b4ed282SShri Abhyankar 
20702b4ed282SShri Abhyankar   ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
20717fe79bc4SShri Abhyankar   ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
20722b4ed282SShri Abhyankar   if (snes->nfuncs >= snes->max_funcs) {
20732b4ed282SShri Abhyankar     ierr  = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
20742b4ed282SShri Abhyankar     *flag = PETSC_FALSE;
20752b4ed282SShri Abhyankar     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
20762b4ed282SShri Abhyankar     goto theend2;
20772b4ed282SShri Abhyankar   }
20782b4ed282SShri Abhyankar   ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
20792f63a38cSShri Abhyankar   if (snes->ops->solve != SNESSolveVI_SS) {
20807fe79bc4SShri Abhyankar     ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
20817fe79bc4SShri Abhyankar   } else {
20827fe79bc4SShri Abhyankar     ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
20837fe79bc4SShri Abhyankar   }
20842b4ed282SShri Abhyankar   if (snes->domainerror) {
20852b4ed282SShri Abhyankar     ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
20862b4ed282SShri Abhyankar     PetscFunctionReturn(0);
20872b4ed282SShri Abhyankar   }
208862cbcd01SMatthew G Knepley   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
20892b4ed282SShri Abhyankar   if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + vi->alpha*initslope) { /* Sufficient reduction */
2090c92abb8aSShri Abhyankar     if (vi->lsmonitor) {
2091c92abb8aSShri Abhyankar       ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line search: Using full step: fnorm %G gnorm %G\n",fnorm,*gnorm);CHKERRQ(ierr);
20922b4ed282SShri Abhyankar     }
20932b4ed282SShri Abhyankar     goto theend2;
20942b4ed282SShri Abhyankar   }
20952b4ed282SShri Abhyankar 
20962b4ed282SShri Abhyankar   /* Fit points with quadratic */
20972b4ed282SShri Abhyankar   lambda = 1.0;
20982b4ed282SShri Abhyankar   count = 1;
20992b4ed282SShri Abhyankar   while (PETSC_TRUE) {
21002b4ed282SShri Abhyankar     if (lambda <= minlambda) { /* bad luck; use full step */
2101c92abb8aSShri Abhyankar       if (vi->lsmonitor) {
2102c92abb8aSShri Abhyankar         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"Line search: Unable to find good step length! %D \n",count);CHKERRQ(ierr);
2103c92abb8aSShri 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);
21042b4ed282SShri Abhyankar       }
21052b4ed282SShri Abhyankar       ierr = VecCopy(x,w);CHKERRQ(ierr);
21062b4ed282SShri Abhyankar       *flag = PETSC_FALSE;
21072b4ed282SShri Abhyankar       break;
21082b4ed282SShri Abhyankar     }
21092b4ed282SShri Abhyankar     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
21102b4ed282SShri Abhyankar     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
21112b4ed282SShri Abhyankar     if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
21122b4ed282SShri Abhyankar     else                         lambda     = lambdatemp;
21132b4ed282SShri Abhyankar 
21142b4ed282SShri Abhyankar     ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr);
21157fe79bc4SShri Abhyankar     ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
21162b4ed282SShri Abhyankar     if (snes->nfuncs >= snes->max_funcs) {
21172b4ed282SShri Abhyankar       ierr  = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
21182b4ed282SShri 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);
21192b4ed282SShri Abhyankar       *flag = PETSC_FALSE;
21202b4ed282SShri Abhyankar       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
21212b4ed282SShri Abhyankar       break;
21222b4ed282SShri Abhyankar     }
21232b4ed282SShri Abhyankar     ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr);
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 {
21312b4ed282SShri Abhyankar       ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
21327fe79bc4SShri Abhyankar     }
213362cbcd01SMatthew G Knepley     if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
21342b4ed282SShri Abhyankar     if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*vi->alpha*initslope) { /* sufficient reduction */
2135c92abb8aSShri Abhyankar       if (vi->lsmonitor) {
2136c92abb8aSShri Abhyankar         ierr = PetscViewerASCIIMonitorPrintf(vi->lsmonitor,"    Line Search: Quadratically determined step, lambda=%G\n",lambda);CHKERRQ(ierr);
21372b4ed282SShri Abhyankar       }
21382b4ed282SShri Abhyankar       break;
21392b4ed282SShri Abhyankar     }
21402b4ed282SShri Abhyankar     count++;
21412b4ed282SShri Abhyankar   }
21422b4ed282SShri Abhyankar   theend2:
21432b4ed282SShri Abhyankar   /* Optional user-defined check for line search step validity */
21442b4ed282SShri Abhyankar   if (vi->postcheckstep) {
21452b4ed282SShri Abhyankar     ierr = (*vi->postcheckstep)(snes,x,y,w,vi->postcheck,&changed_y,&changed_w);CHKERRQ(ierr);
21462b4ed282SShri Abhyankar     if (changed_y) {
21472b4ed282SShri Abhyankar       ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr);
21487fe79bc4SShri Abhyankar       ierr = SNESVIProjectOntoBounds(snes,w);CHKERRQ(ierr);
21492b4ed282SShri Abhyankar     }
21502b4ed282SShri Abhyankar     if (changed_y || changed_w) { /* recompute the function if the step has changed */
21512b4ed282SShri Abhyankar       ierr = SNESComputeFunction(snes,w,g);
21522b4ed282SShri Abhyankar       if (snes->domainerror) {
21532b4ed282SShri Abhyankar         ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
21542b4ed282SShri Abhyankar         PetscFunctionReturn(0);
21552b4ed282SShri Abhyankar       }
21562f63a38cSShri Abhyankar       if (snes->ops->solve != SNESSolveVI_SS) {
21577fe79bc4SShri Abhyankar         ierr = SNESVIComputeInactiveSetFnorm(snes,g,w,gnorm);CHKERRQ(ierr);
21587fe79bc4SShri Abhyankar       } else {
21597fe79bc4SShri Abhyankar         ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr);
21607fe79bc4SShri Abhyankar       }
21617fe79bc4SShri Abhyankar 
21622b4ed282SShri Abhyankar       ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr);
21632b4ed282SShri Abhyankar       ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr);
216462cbcd01SMatthew G Knepley       if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
21652b4ed282SShri Abhyankar     }
21662b4ed282SShri Abhyankar   }
21672b4ed282SShri Abhyankar   ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr);
21682b4ed282SShri Abhyankar   PetscFunctionReturn(0);
21692b4ed282SShri Abhyankar }
21702b4ed282SShri Abhyankar 
2171ace3abfcSBarry 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*/
21722b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
21732b4ed282SShri Abhyankar EXTERN_C_BEGIN
21742b4ed282SShri Abhyankar #undef __FUNCT__
21752b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchSet_VI"
21767087cfbeSBarry Smith PetscErrorCode  SNESLineSearchSet_VI(SNES snes,FCN2 func,void *lsctx)
21772b4ed282SShri Abhyankar {
21782b4ed282SShri Abhyankar   PetscFunctionBegin;
21792b4ed282SShri Abhyankar   ((SNES_VI *)(snes->data))->LineSearch = func;
21802b4ed282SShri Abhyankar   ((SNES_VI *)(snes->data))->lsP        = lsctx;
21812b4ed282SShri Abhyankar   PetscFunctionReturn(0);
21822b4ed282SShri Abhyankar }
21832b4ed282SShri Abhyankar EXTERN_C_END
21842b4ed282SShri Abhyankar 
21852b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
21862b4ed282SShri Abhyankar EXTERN_C_BEGIN
21872b4ed282SShri Abhyankar #undef __FUNCT__
21882b4ed282SShri Abhyankar #define __FUNCT__ "SNESLineSearchSetMonitor_VI"
21897087cfbeSBarry Smith PetscErrorCode  SNESLineSearchSetMonitor_VI(SNES snes,PetscBool flg)
21902b4ed282SShri Abhyankar {
21912b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI*)snes->data;
21922b4ed282SShri Abhyankar   PetscErrorCode ierr;
21932b4ed282SShri Abhyankar 
21942b4ed282SShri Abhyankar   PetscFunctionBegin;
2195c92abb8aSShri Abhyankar   if (flg && !vi->lsmonitor) {
2196c92abb8aSShri Abhyankar     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)snes)->comm,"stdout",((PetscObject)snes)->tablevel,&vi->lsmonitor);CHKERRQ(ierr);
2197c92abb8aSShri Abhyankar   } else if (!flg && vi->lsmonitor) {
21986bf464f9SBarry Smith     ierr = PetscViewerASCIIMonitorDestroy(&vi->lsmonitor);CHKERRQ(ierr);
21992b4ed282SShri Abhyankar   }
22002b4ed282SShri Abhyankar   PetscFunctionReturn(0);
22012b4ed282SShri Abhyankar }
22022b4ed282SShri Abhyankar EXTERN_C_END
22032b4ed282SShri Abhyankar 
22042b4ed282SShri Abhyankar /*
22052b4ed282SShri Abhyankar    SNESView_VI - Prints info from the SNESVI data structure.
22062b4ed282SShri Abhyankar 
22072b4ed282SShri Abhyankar    Input Parameters:
22082b4ed282SShri Abhyankar .  SNES - the SNES context
22092b4ed282SShri Abhyankar .  viewer - visualization context
22102b4ed282SShri Abhyankar 
22112b4ed282SShri Abhyankar    Application Interface Routine: SNESView()
22122b4ed282SShri Abhyankar */
22132b4ed282SShri Abhyankar #undef __FUNCT__
22142b4ed282SShri Abhyankar #define __FUNCT__ "SNESView_VI"
22152b4ed282SShri Abhyankar static PetscErrorCode SNESView_VI(SNES snes,PetscViewer viewer)
22162b4ed282SShri Abhyankar {
22172b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI *)snes->data;
221878c4b9d3SShri Abhyankar   const char     *cstr,*tstr;
22192b4ed282SShri Abhyankar   PetscErrorCode ierr;
2220ace3abfcSBarry Smith   PetscBool     iascii;
22212b4ed282SShri Abhyankar 
22222b4ed282SShri Abhyankar   PetscFunctionBegin;
22232b4ed282SShri Abhyankar   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
22242b4ed282SShri Abhyankar   if (iascii) {
22252b4ed282SShri Abhyankar     if (vi->LineSearch == SNESLineSearchNo_VI)             cstr = "SNESLineSearchNo";
22262b4ed282SShri Abhyankar     else if (vi->LineSearch == SNESLineSearchQuadratic_VI) cstr = "SNESLineSearchQuadratic";
22272b4ed282SShri Abhyankar     else if (vi->LineSearch == SNESLineSearchCubic_VI)     cstr = "SNESLineSearchCubic";
22282b4ed282SShri Abhyankar     else                                                   cstr = "unknown";
222978c4b9d3SShri Abhyankar     if (snes->ops->solve == SNESSolveVI_SS)         tstr = "Semismooth";
22300a7c7af0SShri Abhyankar     else if (snes->ops->solve == SNESSolveVI_RS)    tstr = "Reduced Space";
2231b350b9c9SBarry Smith     else if (snes->ops->solve == SNESSolveVI_RSAUG) tstr = "Reduced space with augmented variables";
223278c4b9d3SShri Abhyankar     else                                         tstr = "unknown";
223378c4b9d3SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  VI algorithm: %s\n",tstr);CHKERRQ(ierr);
22342b4ed282SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  line search variant: %s\n",cstr);CHKERRQ(ierr);
22352b4ed282SShri Abhyankar     ierr = PetscViewerASCIIPrintf(viewer,"  alpha=%G, maxstep=%G, minlambda=%G\n",vi->alpha,vi->maxstep,vi->minlambda);CHKERRQ(ierr);
22362b4ed282SShri Abhyankar   } else {
22372b4ed282SShri Abhyankar     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ VI",((PetscObject)viewer)->type_name);
22382b4ed282SShri Abhyankar   }
22392b4ed282SShri Abhyankar   PetscFunctionReturn(0);
22402b4ed282SShri Abhyankar }
22412b4ed282SShri Abhyankar 
22425559b345SBarry Smith #undef __FUNCT__
22435559b345SBarry Smith #define __FUNCT__ "SNESVISetVariableBounds"
22445559b345SBarry Smith /*@
22452b4ed282SShri Abhyankar    SNESVISetVariableBounds - Sets the lower and upper bounds for the solution vector. xl <= x <= xu.
22462b4ed282SShri Abhyankar 
22472b4ed282SShri Abhyankar    Input Parameters:
22482b4ed282SShri Abhyankar .  snes - the SNES context.
22492b4ed282SShri Abhyankar .  xl   - lower bound.
22502b4ed282SShri Abhyankar .  xu   - upper bound.
22512b4ed282SShri Abhyankar 
22522b4ed282SShri Abhyankar    Notes:
22532b4ed282SShri Abhyankar    If this routine is not called then the lower and upper bounds are set to
225401f0b76bSBarry Smith    SNES_VI_INF and SNES_VI_NINF respectively during SNESSetUp().
225584c105d7SBarry Smith 
22565559b345SBarry Smith @*/
225769c03620SShri Abhyankar PetscErrorCode SNESVISetVariableBounds(SNES snes, Vec xl, Vec xu)
22582b4ed282SShri Abhyankar {
2259d923200aSJungho Lee   SNES_VI        *vi;
2260d923200aSJungho Lee   PetscErrorCode ierr;
22612b4ed282SShri Abhyankar 
22622b4ed282SShri Abhyankar   PetscFunctionBegin;
22632b4ed282SShri Abhyankar   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
22642b4ed282SShri Abhyankar   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
22652b4ed282SShri Abhyankar   PetscValidHeaderSpecific(xu,VEC_CLASSID,3);
22662b4ed282SShri Abhyankar   if (!snes->vec_func) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() first");
22672b4ed282SShri 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);
22682b4ed282SShri 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);
2269d923200aSJungho Lee   ierr = SNESSetType(snes,SNESVI);CHKERRQ(ierr);
2270d923200aSJungho Lee   vi = (SNES_VI*)snes->data;
22712b4ed282SShri Abhyankar   vi->usersetxbounds = PETSC_TRUE;
22722b4ed282SShri Abhyankar   vi->xl = xl;
22732b4ed282SShri Abhyankar   vi->xu = xu;
22742b4ed282SShri Abhyankar   PetscFunctionReturn(0);
22752b4ed282SShri Abhyankar }
2276693ddf92SShri Abhyankar 
22772b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
22782b4ed282SShri Abhyankar /*
22792b4ed282SShri Abhyankar    SNESSetFromOptions_VI - Sets various parameters for the SNESVI method.
22802b4ed282SShri Abhyankar 
22812b4ed282SShri Abhyankar    Input Parameter:
22822b4ed282SShri Abhyankar .  snes - the SNES context
22832b4ed282SShri Abhyankar 
22842b4ed282SShri Abhyankar    Application Interface Routine: SNESSetFromOptions()
22852b4ed282SShri Abhyankar */
22862b4ed282SShri Abhyankar #undef __FUNCT__
22872b4ed282SShri Abhyankar #define __FUNCT__ "SNESSetFromOptions_VI"
22882b4ed282SShri Abhyankar static PetscErrorCode SNESSetFromOptions_VI(SNES snes)
22892b4ed282SShri Abhyankar {
22902b4ed282SShri Abhyankar   SNES_VI        *vi = (SNES_VI *)snes->data;
22917fe79bc4SShri Abhyankar   const char     *lses[] = {"basic","basicnonorms","quadratic","cubic"};
2292b350b9c9SBarry Smith   const char     *vies[] = {"ss","rs","rsaug"};
22932b4ed282SShri Abhyankar   PetscErrorCode ierr;
22942b4ed282SShri Abhyankar   PetscInt       indx;
229569c03620SShri Abhyankar   PetscBool      flg,set,flg2;
22962b4ed282SShri Abhyankar 
22972b4ed282SShri Abhyankar   PetscFunctionBegin;
22982b4ed282SShri Abhyankar   ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr);
22999308c137SBarry Smith   ierr = PetscOptionsBool("-snes_vi_monitor","Monitor all non-active variables","None",PETSC_FALSE,&flg,0);CHKERRQ(ierr);
23009308c137SBarry Smith   if (flg) {
23019308c137SBarry Smith     ierr = SNESMonitorSet(snes,SNESMonitorVI,0,0);CHKERRQ(ierr);
23029308c137SBarry Smith   }
2303be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",vi->alpha,&vi->alpha,0);CHKERRQ(ierr);
2304be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",vi->maxstep,&vi->maxstep,0);CHKERRQ(ierr);
2305be6adb11SBarry Smith   ierr = PetscOptionsReal("-snes_ls_minlambda","Minimum lambda allowed","None",vi->minlambda,&vi->minlambda,0);CHKERRQ(ierr);
23062b4ed282SShri Abhyankar   ierr = PetscOptionsReal("-snes_vi_const_tol","constraint tolerance","None",vi->const_tol,&vi->const_tol,0);CHKERRQ(ierr);
2307be6adb11SBarry Smith   ierr = PetscOptionsBool("-snes_ls_monitor","Print progress of line searches","SNESLineSearchSetMonitor",vi->lsmonitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
23082b4ed282SShri Abhyankar   if (set) {ierr = SNESLineSearchSetMonitor(snes,flg);CHKERRQ(ierr);}
23092f63a38cSShri Abhyankar   ierr = PetscOptionsEList("-snes_vi_type","Semismooth algorithm used","",vies,3,"ss",&indx,&flg2);CHKERRQ(ierr);
231069c03620SShri Abhyankar   if (flg2) {
231169c03620SShri Abhyankar     switch (indx) {
231269c03620SShri Abhyankar     case 0:
231369c03620SShri Abhyankar       snes->ops->solve = SNESSolveVI_SS;
231469c03620SShri Abhyankar       break;
231569c03620SShri Abhyankar     case 1:
2316d950fb63SShri Abhyankar       snes->ops->solve = SNESSolveVI_RS;
2317d950fb63SShri Abhyankar       break;
23182f63a38cSShri Abhyankar     case 2:
2319b350b9c9SBarry Smith       snes->ops->solve = SNESSolveVI_RSAUG;
232069c03620SShri Abhyankar     }
232169c03620SShri Abhyankar   }
2322be6adb11SBarry Smith   ierr = PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"basic",&indx,&flg);CHKERRQ(ierr);
23232b4ed282SShri Abhyankar   if (flg) {
23242b4ed282SShri Abhyankar     switch (indx) {
23252b4ed282SShri Abhyankar     case 0:
23262b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchNo_VI,PETSC_NULL);CHKERRQ(ierr);
23272b4ed282SShri Abhyankar       break;
23282b4ed282SShri Abhyankar     case 1:
23292b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms_VI,PETSC_NULL);CHKERRQ(ierr);
23302b4ed282SShri Abhyankar       break;
23312b4ed282SShri Abhyankar     case 2:
23322b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic_VI,PETSC_NULL);CHKERRQ(ierr);
23332b4ed282SShri Abhyankar       break;
23342b4ed282SShri Abhyankar     case 3:
23352b4ed282SShri Abhyankar       ierr = SNESLineSearchSet(snes,SNESLineSearchCubic_VI,PETSC_NULL);CHKERRQ(ierr);
23362b4ed282SShri Abhyankar       break;
23372b4ed282SShri Abhyankar     }
2338fe835674SShri Abhyankar   }
23392b4ed282SShri Abhyankar   ierr = PetscOptionsTail();CHKERRQ(ierr);
23402b4ed282SShri Abhyankar   PetscFunctionReturn(0);
23412b4ed282SShri Abhyankar }
23422b4ed282SShri Abhyankar /* -------------------------------------------------------------------------- */
23432b4ed282SShri Abhyankar /*MC
23448b4c83edSBarry Smith       SNESVI - Various solvers for variational inequalities based on Newton's method
23452b4ed282SShri Abhyankar 
23462b4ed282SShri Abhyankar    Options Database:
23478b4c83edSBarry 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
23488b4c83edSBarry Smith                                 additional variables that enforce the constraints
23498b4c83edSBarry Smith -   -snes_vi_monitor - prints the number of active constraints at each iteration.
23502b4ed282SShri Abhyankar 
23512b4ed282SShri Abhyankar 
23522b4ed282SShri Abhyankar    Level: beginner
23532b4ed282SShri Abhyankar 
23542b4ed282SShri Abhyankar .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(),
23552b4ed282SShri Abhyankar            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(),
23562b4ed282SShri Abhyankar            SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()
23572b4ed282SShri Abhyankar 
23582b4ed282SShri Abhyankar M*/
23592b4ed282SShri Abhyankar EXTERN_C_BEGIN
23602b4ed282SShri Abhyankar #undef __FUNCT__
23612b4ed282SShri Abhyankar #define __FUNCT__ "SNESCreate_VI"
23627087cfbeSBarry Smith PetscErrorCode  SNESCreate_VI(SNES snes)
23632b4ed282SShri Abhyankar {
23642b4ed282SShri Abhyankar   PetscErrorCode ierr;
23652b4ed282SShri Abhyankar   SNES_VI      *vi;
23662b4ed282SShri Abhyankar 
23672b4ed282SShri Abhyankar   PetscFunctionBegin;
23682b4ed282SShri Abhyankar   snes->ops->setup           = SNESSetUp_VI;
2369edafb9efSBarry Smith   snes->ops->solve           = SNESSolveVI_RS;
23702b4ed282SShri Abhyankar   snes->ops->destroy         = SNESDestroy_VI;
23712b4ed282SShri Abhyankar   snes->ops->setfromoptions  = SNESSetFromOptions_VI;
23722b4ed282SShri Abhyankar   snes->ops->view            = SNESView_VI;
237337596af1SLisandro Dalcin   snes->ops->reset           = 0; /* XXX Implement!!! */
23742b4ed282SShri Abhyankar   snes->ops->converged       = SNESDefaultConverged_VI;
23752b4ed282SShri Abhyankar 
23762b4ed282SShri Abhyankar   ierr                  = PetscNewLog(snes,SNES_VI,&vi);CHKERRQ(ierr);
23772b4ed282SShri Abhyankar   snes->data            = (void*)vi;
23782b4ed282SShri Abhyankar   vi->alpha             = 1.e-4;
23792b4ed282SShri Abhyankar   vi->maxstep           = 1.e8;
23802b4ed282SShri Abhyankar   vi->minlambda         = 1.e-12;
23817fe79bc4SShri Abhyankar   vi->LineSearch        = SNESLineSearchNo_VI;
23822b4ed282SShri Abhyankar   vi->lsP               = PETSC_NULL;
23832b4ed282SShri Abhyankar   vi->postcheckstep     = PETSC_NULL;
23842b4ed282SShri Abhyankar   vi->postcheck         = PETSC_NULL;
23852b4ed282SShri Abhyankar   vi->precheckstep      = PETSC_NULL;
23862b4ed282SShri Abhyankar   vi->precheck          = PETSC_NULL;
23872b4ed282SShri Abhyankar   vi->const_tol         =  2.2204460492503131e-16;
23882f63a38cSShri Abhyankar   vi->checkredundancy   = PETSC_NULL;
23892b4ed282SShri Abhyankar 
23902b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetMonitor_C","SNESLineSearchSetMonitor_VI",SNESLineSearchSetMonitor_VI);CHKERRQ(ierr);
23912b4ed282SShri Abhyankar   ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","SNESLineSearchSet_VI",SNESLineSearchSet_VI);CHKERRQ(ierr);
23922b4ed282SShri Abhyankar 
23932b4ed282SShri Abhyankar   PetscFunctionReturn(0);
23942b4ed282SShri Abhyankar }
23952b4ed282SShri Abhyankar EXTERN_C_END
2396