xref: /petsc/src/tao/constrained/impls/ipm/ipm.c (revision 3c9e27cfca911a7d7e3219758be42726e83c4ab2)
1 #include "taolinesearch.h"
2 #include "ipm.h" /*I "ipm.h" I*/
3 //#define DEBUG_IPM
4 //#define DEBUG_K
5 //#define DEBUG_SCATTER
6 //#define DEBUG_KKT
7 /*
8    x,d in R^n
9    f in R
10    nb = mi + nlb+nub
11    s in R^nb is slack vector CI(x) / x-XL / -x+XU
12    bin in R^mi (tao->constraints_inequality)
13    beq in R^me (tao->constraints_equality)
14    lamdai in R^nb (ipmP->lamdai)
15    lamdae in R^me (ipmP->lamdae)
16    Jeq in R^(me x n) (tao->jacobian_equality)
17    Jin in R^(mi x n) (tao->jacobian_inequality)
18    Ai in  R^(nb x n) (ipmP->Ai)
19    H in R^(n x n) (tao->hessian)
20    min f=(1/2)*x'*H*x + d'*x
21    s.t.  CE(x) == 0
22          CI(x) >= 0
23 	 x >= tao->XL
24 	 -x >= -tao->XU
25 */
26 
27 static PetscErrorCode IPMComputeKKT(TaoSolver tao);
28 static PetscErrorCode IPMPushInitialPoint(TaoSolver tao);
29 static PetscErrorCode IPMEvaluate(TaoSolver tao);
30 static PetscErrorCode IPMUpdateK(TaoSolver tao);
31 static PetscErrorCode IPMUpdateAi(TaoSolver tao);
32 static PetscErrorCode IPMGatherRHS(TaoSolver tao,Vec,Vec,Vec,Vec,Vec);
33 static PetscErrorCode IPMScatterStep(TaoSolver tao,Vec,Vec,Vec,Vec,Vec);
34 static PetscErrorCode IPMInitializeBounds(TaoSolver tao);
35 
36 #undef __FUNCT__
37 #define __FUNCT__ "TaoSolve_IPM"
38 static PetscErrorCode TaoSolve_IPM(TaoSolver tao)
39 {
40   PetscErrorCode ierr;
41   TAO_IPM* ipmP = (TAO_IPM*)tao->data;
42 
43 
44   TaoSolverTerminationReason reason = TAO_CONTINUE_ITERATING;
45   PetscInt iter = 0,its,i;
46   PetscScalar stepsize=1.0;
47   PetscScalar step_s,step_l,alpha,tau,sigma,phi_target;
48   PetscFunctionBegin;
49 
50   /* Push initial point away from bounds */
51 #if defined(DEBUG_IPM)
52   ierr = VecNorm(tao->solution,NORM_2,&tau); CHKERRQ(ierr);
53   VecView(tao->solution,0);
54 #endif
55   ierr = IPMInitializeBounds(tao); CHKERRQ(ierr);
56   ierr = IPMPushInitialPoint(tao); CHKERRQ(ierr);
57 #if defined(DEBUG_IPM)
58   ierr = VecNorm(tao->solution,NORM_2,&tau); CHKERRQ(ierr);
59   VecView(tao->solution,0);
60   //  PetscPrintf(PETSC_COMM_WORLD,"||x0|| = %g\n",tau);
61 #endif
62   ierr = VecCopy(tao->solution,ipmP->rhs_x); CHKERRQ(ierr);
63   ierr = IPMEvaluate(tao); CHKERRQ(ierr);
64   ierr = IPMComputeKKT(tao); CHKERRQ(ierr);
65   ierr = TaoMonitor(tao,iter++,ipmP->kkt_f,ipmP->phi,0.0,1.0,&reason);
66 
67 
68   while (reason == TAO_CONTINUE_ITERATING) {
69     ierr = IPMUpdateK(tao); CHKERRQ(ierr);
70     /*
71        rhs.x    = -rd
72        rhs.lame = -rpe
73        rhs.lami = -rpi
74        rhs.com  = -com
75     */
76 
77     ierr = VecCopy(ipmP->rd,ipmP->rhs_x); CHKERRQ(ierr);
78     if (ipmP->me > 0) {
79       ierr = VecCopy(ipmP->rpe,ipmP->rhs_lamdae); CHKERRQ(ierr);
80     }
81     if (ipmP->nb > 0) {
82 	ierr = VecCopy(ipmP->rpi,ipmP->rhs_lamdai); CHKERRQ(ierr);
83 	ierr = VecCopy(ipmP->complementarity,ipmP->rhs_s); CHKERRQ(ierr);
84     }
85     ierr = IPMGatherRHS(tao,ipmP->bigrhs,ipmP->rhs_x,ipmP->rhs_lamdae,
86 			ipmP->rhs_lamdai,ipmP->rhs_s); CHKERRQ(ierr);
87     ierr = VecScale(ipmP->bigrhs,-1.0); CHKERRQ(ierr);
88 
89     /* solve K * step = rhs */
90     ierr = KSPSetOperators(tao->ksp,ipmP->K,ipmP->K,DIFFERENT_NONZERO_PATTERN); CHKERRQ(ierr);
91     ierr = KSPSolve(tao->ksp,ipmP->bigrhs,ipmP->bigstep);CHKERRQ(ierr);
92 
93     ierr = IPMScatterStep(tao,ipmP->bigstep,tao->stepdirection,ipmP->ds,
94 			  ipmP->dlamdae,ipmP->dlamdai); CHKERRQ(ierr);
95     ierr = KSPGetIterationNumber(tao->ksp,&its); CHKERRQ(ierr);
96     tao->ksp_its += its;
97 #if defined DEBUG_KKT
98     PetscPrintf(PETSC_COMM_WORLD,"first solve.\n");
99     PetscPrintf(PETSC_COMM_WORLD,"rhs_lamdai\n");
100     //VecView(ipmP->rhs_lamdai,0);
101     //ierr = VecView(ipmP->bigrhs,0);
102     //ierr = VecView(ipmP->bigstep,0);
103     PetscScalar norm1,norm2;
104     ierr = VecNorm(ipmP->bigrhs,NORM_2,&norm1);
105     ierr = VecNorm(ipmP->bigstep,NORM_2,&norm2);
106     PetscPrintf(PETSC_COMM_WORLD,"||rhs|| = %g\t ||step|| = %g\n",norm1,norm2);
107 #endif
108      /* Find distance along step direction to closest bound */
109     if (ipmP->nb > 0) {
110       ierr = VecStepBoundInfo(ipmP->s,ipmP->Zero_nb,ipmP->Inf_nb,ipmP->ds,&step_s,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
111       ierr = VecStepBoundInfo(ipmP->lamdai,ipmP->Zero_nb,ipmP->Inf_nb,ipmP->dlamdai,&step_l,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
112       alpha = PetscMin(step_s,step_l);
113       alpha = PetscMin(alpha,1.0);
114       ipmP->alpha1 = alpha;
115     } else {
116       ipmP->alpha1 = alpha = 1.0;
117     }
118 
119 
120     /* x_aff = x + alpha*d */
121     ierr = VecCopy(tao->solution,ipmP->save_x); CHKERRQ(ierr);
122     if (ipmP->me > 0) {
123       ierr = VecCopy(ipmP->lamdae,ipmP->save_lamdae); CHKERRQ(ierr);
124     }
125     if (ipmP->nb > 0) {
126       ierr = VecCopy(ipmP->lamdai,ipmP->save_lamdai); CHKERRQ(ierr);
127       ierr = VecCopy(ipmP->s,ipmP->save_s); CHKERRQ(ierr);
128     }
129 
130     ierr = VecAXPY(tao->solution,alpha,tao->stepdirection); CHKERRQ(ierr);
131     if (ipmP->me > 0) {
132       ierr = VecAXPY(ipmP->lamdae,alpha,ipmP->dlamdae); CHKERRQ(ierr);
133     }
134     if (ipmP->nb > 0) {
135       ierr = VecAXPY(ipmP->lamdai,alpha,ipmP->dlamdai); CHKERRQ(ierr);
136       ierr = VecAXPY(ipmP->s,alpha,ipmP->ds); CHKERRQ(ierr);
137     }
138 
139 
140     /* Recompute kkt to find centering parameter sigma = (new_mu/old_mu)^3 */
141     if (ipmP->mu == 0.0) {
142       sigma = 0.0;
143     } else {
144       sigma = 1.0/ipmP->mu;
145     }
146     ierr = IPMComputeKKT(tao); CHKERRQ(ierr);
147     sigma *= ipmP->mu;
148     sigma*=sigma*sigma;
149 
150     /* revert kkt info */
151     ierr = VecCopy(ipmP->save_x,tao->solution); CHKERRQ(ierr);
152     if (ipmP->me > 0) {
153       ierr = VecCopy(ipmP->save_lamdae,ipmP->lamdae); CHKERRQ(ierr);
154     }
155     if (ipmP->nb > 0) {
156       ierr = VecCopy(ipmP->save_lamdai,ipmP->lamdai); CHKERRQ(ierr);
157       ierr = VecCopy(ipmP->save_s,ipmP->s); CHKERRQ(ierr);
158     }
159     ierr = IPMComputeKKT(tao); CHKERRQ(ierr);
160 
161     /* update rhs with new complementarity vector */
162     if (ipmP->nb > 0) {
163       ierr = VecCopy(ipmP->complementarity,ipmP->rhs_s); CHKERRQ(ierr);
164       ierr = VecScale(ipmP->rhs_s,-1.0); CHKERRQ(ierr);
165       ierr = VecShift(ipmP->rhs_s,sigma*ipmP->mu); CHKERRQ(ierr);
166     }
167     ierr = IPMGatherRHS(tao,ipmP->bigrhs,PETSC_NULL,PETSC_NULL,
168 		      PETSC_NULL,ipmP->rhs_s); CHKERRQ(ierr);
169 
170     /* solve K * step = rhs */
171     ierr = KSPSetOperators(tao->ksp,ipmP->K,ipmP->K,DIFFERENT_NONZERO_PATTERN); CHKERRQ(ierr);
172     ierr = KSPSolve(tao->ksp,ipmP->bigrhs,ipmP->bigstep);CHKERRQ(ierr);
173 
174     ierr = IPMScatterStep(tao,ipmP->bigstep,tao->stepdirection,ipmP->ds,
175 			  ipmP->dlamdae,ipmP->dlamdai); CHKERRQ(ierr);
176     ierr = KSPGetIterationNumber(tao->ksp,&its); CHKERRQ(ierr);
177 #if defined DEBUG_KKT2
178     PetscPrintf(PETSC_COMM_WORLD,"rhs_lamdai\n");
179     VecView(ipmP->rhs_lamdai,0);
180     ierr = VecView(ipmP->bigrhs,0);
181     ierr = VecView(ipmP->bigstep,0);
182 #endif
183     tao->ksp_its += its;
184 
185 
186     if (ipmP->nb > 0) {
187       /* Get max step size and apply frac-to-boundary */
188       tau = PetscMax(ipmP->taumin,1.0-ipmP->mu);
189       tau = PetscMin(tau,1.0);
190       if (tau != 1.0) {
191 	ierr = VecScale(ipmP->s,tau); CHKERRQ(ierr);
192 	ierr = VecScale(ipmP->lamdai,tau); CHKERRQ(ierr);
193       }
194       ierr = VecStepBoundInfo(ipmP->s,ipmP->Zero_nb,ipmP->Inf_nb,ipmP->ds,&step_s,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
195       ierr = VecStepBoundInfo(ipmP->lamdai,ipmP->Zero_nb,ipmP->Inf_nb,ipmP->dlamdai,&step_l,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
196       if (tau != 1.0) {
197 	ierr = VecCopy(ipmP->save_s,ipmP->s); CHKERRQ(ierr);
198 	ierr = VecCopy(ipmP->save_lamdai,ipmP->lamdai); CHKERRQ(ierr);
199       }
200       alpha = PetscMin(step_s,step_l);
201       alpha = PetscMin(alpha,1.0);
202     } else {
203       alpha = 1.0;
204     }
205     ipmP->alpha2 = alpha;
206     /* TODO make phi_target meaningful */
207     phi_target = ipmP->dec * ipmP->phi;
208     for (i=0; i<11;i++) {
209 #if defined DEBUG_KKT2
210     PetscPrintf(PETSC_COMM_WORLD,"alpha2=%g\n",alpha);
211       PetscPrintf(PETSC_COMM_WORLD,"old point:\n");
212       VecView(tao->solution,0);
213       VecView(ipmP->lamdae,0);
214       VecView(ipmP->s,0);
215       VecView(ipmP->lamdai,0);
216 #endif
217       ierr = VecAXPY(tao->solution,alpha,tao->stepdirection); CHKERRQ(ierr);
218       if (ipmP->nb > 0) {
219 	ierr = VecAXPY(ipmP->s,alpha,ipmP->ds); CHKERRQ(ierr);
220 	ierr = VecAXPY(ipmP->lamdai,alpha,ipmP->dlamdai); CHKERRQ(ierr);
221       }
222       if (ipmP->me > 0) {
223 	ierr = VecAXPY(ipmP->lamdae,alpha,ipmP->dlamdae); CHKERRQ(ierr);
224       }
225 #if defined DEBUG_KKT
226       PetscPrintf(PETSC_COMM_WORLD,"step direction:\n");
227       VecView(tao->stepdirection,0);
228       //VecView(ipmP->dlamdae,0);
229       //VecView(ipmP->ds,0);
230       //VecView(ipmP->dlamdai,0);
231 
232       //PetscPrintf(PETSC_COMM_WORLD,"New iterate:\n");
233       //VecView(tao->solution,0);
234       //VecView(ipmP->lamdae,0);
235       //VecView(ipmP->s,0);
236       //VecView(ipmP->lamdai,0);
237 #endif
238       /* update dual variables */
239       if (ipmP->me > 0) {
240 	ierr = VecCopy(ipmP->lamdae,tao->DE); CHKERRQ(ierr);
241       }
242       /* TODO: fix
243       if (ipmP->nb > 0) {
244 	ierr = VecScatterBegin
245 	PetscInt lstart,lend;
246 
247 	ierr = VecGetOwnershipRange(ipmP->lamdai,&lstart,&lend);
248 	ierr = VecGetArray(ipmP->lamdai,&li); CHKERRQ(ierr);
249 	ierr = VecGetArray(tao->DI,&di); CHKERRQ(ierr);
250 	for (j=lstart;j<lend;j++) {
251 	  if (j < ipmP->nilb) {
252 	    di[j] = li[j];
253 	  }
254 	}
255 	ierr = VecRestoreArray(ipmP->lamdai,&li); CHKERRQ(ierr);
256 	ierr = VecRestoreArray(tao->DI,&di); CHKERRQ(ierr);
257       }
258       */
259 
260 
261       ierr = IPMEvaluate(tao); CHKERRQ(ierr);
262       ierr = IPMComputeKKT(tao); CHKERRQ(ierr);
263       if (ipmP->phi <= phi_target) break;
264       alpha /= 2.0;
265     }
266 
267     ierr = TaoMonitor(tao,iter,ipmP->kkt_f,ipmP->phi,0.0,stepsize,&reason);
268     iter++;
269     CHKERRQ(ierr);
270 
271   }
272 
273   PetscFunctionReturn(0);
274 }
275 
276 #undef __FUNCT__
277 #define __FUNCT__ "TaoSetup_IPM"
278 static PetscErrorCode TaoSetup_IPM(TaoSolver tao)
279 {
280   TAO_IPM *ipmP = (TAO_IPM*)tao->data;
281   PetscErrorCode ierr;
282 
283   PetscFunctionBegin;
284   ipmP->nb = ipmP->mi = ipmP->me = 0;
285   ipmP->K=0;
286   ierr = VecGetSize(tao->solution,&ipmP->n); CHKERRQ(ierr);
287   if (!tao->gradient) {
288     ierr = VecDuplicate(tao->solution, &tao->gradient); CHKERRQ(ierr);
289     ierr = VecDuplicate(tao->solution, &tao->stepdirection); CHKERRQ(ierr);
290     ierr = VecDuplicate(tao->solution, &ipmP->rd); CHKERRQ(ierr);
291     ierr = VecDuplicate(tao->solution, &ipmP->rhs_x); CHKERRQ(ierr);
292     ierr = VecDuplicate(tao->solution, &ipmP->work); CHKERRQ(ierr);
293     ierr = VecDuplicate(tao->solution, &ipmP->save_x); CHKERRQ(ierr);
294   }
295 
296   if (tao->constraints_equality) {
297     ierr = VecGetSize(tao->constraints_equality,&ipmP->me); CHKERRQ(ierr);
298     ierr = VecDuplicate(tao->constraints_equality,&ipmP->lamdae); CHKERRQ(ierr);
299     ierr = VecDuplicate(tao->constraints_equality,&ipmP->dlamdae); CHKERRQ(ierr);
300     ierr = VecDuplicate(tao->constraints_equality,&ipmP->rhs_lamdae); CHKERRQ(ierr);
301     ierr = VecDuplicate(tao->constraints_equality,&ipmP->save_lamdae); CHKERRQ(ierr);
302     ierr = VecDuplicate(tao->constraints_equality,&ipmP->rpe); CHKERRQ(ierr);
303     ierr = VecDuplicate(tao->constraints_equality,&tao->DE); CHKERRQ(ierr);
304   }
305   if (tao->constraints_inequality) {
306     ierr = VecDuplicate(tao->constraints_inequality,&tao->DI); CHKERRQ(ierr);
307   }
308 
309   PetscFunctionReturn(0);
310 }
311 
312 #undef __FUNCT__
313 #define __FUNCT__ "IPMInitializeBounds"
314 static PetscErrorCode IPMInitializeBounds(TaoSolver tao)
315 {
316   TAO_IPM *ipmP = (TAO_IPM*)tao->data;
317   Vec xtmp;
318   //PetscInt cstart,cend; /* ci (userci + lb + ub) */
319   PetscInt xstart,xend;
320   PetscInt ucstart,ucend; /* user ci */
321   PetscInt ucestart,uceend; /* user ce */
322   PetscInt sstart,send;
323   PetscInt bigsize;
324   PetscInt i,counter,nloc;
325   PetscInt *cind,*xind,*ucind,*uceind,*stepind;
326   VecType vtype;
327   const PetscInt *xli,*xui;
328   PetscInt xl_offset,xu_offset;
329   IS bigxl,bigxu,isuc,isc,isx,sis,is1;
330   PetscErrorCode ierr;
331 
332   MPI_Comm comm;
333   PetscFunctionBegin;
334   cind=xind=ucind=uceind=stepind=0;
335   ipmP->mi=0;
336   ipmP->nxlb=0;
337   ipmP->nxub=0;
338   ipmP->nb=0;
339   ipmP->nslack=0;
340 
341   ierr = VecDuplicate(tao->solution,&xtmp); CHKERRQ(ierr);
342   if (!tao->XL && !tao->XU && tao->ops->computebounds) {
343     ierr = TaoComputeVariableBounds(tao); CHKERRQ(ierr);
344   }
345   if (tao->XL) {
346     ierr = VecSet(xtmp,TAO_NINFINITY); CHKERRQ(ierr);
347     ierr = VecWhichGreaterThan(tao->XL,xtmp,&ipmP->isxl); CHKERRQ(ierr);
348     ierr = ISGetSize(ipmP->isxl,&ipmP->nxlb); CHKERRQ(ierr);
349   } else {
350     ipmP->nxlb=0;
351   }
352   if (tao->XU) {
353     ierr = VecSet(xtmp,TAO_INFINITY); CHKERRQ(ierr);
354     ierr = VecWhichLessThan(tao->XU,xtmp,&ipmP->isxu); CHKERRQ(ierr);
355     ierr = ISGetSize(ipmP->isxu,&ipmP->nxub); CHKERRQ(ierr);
356   } else {
357     ipmP->nxub=0;
358   }
359   ierr = VecDestroy(&xtmp); CHKERRQ(ierr);
360   if (tao->constraints_inequality) {
361     ierr = VecGetSize(tao->constraints_inequality,&ipmP->mi); CHKERRQ(ierr);
362   } else {
363     ipmP->mi = 0;
364   }
365 #if defined DEBUG_K
366   PetscPrintf(PETSC_COMM_WORLD,"isxl:\n");
367   if (ipmP->nxlb) {
368     ISView(ipmP->isxl,0);
369   }
370   PetscPrintf(PETSC_COMM_WORLD,"isxu:\n");
371   if (ipmP->nxub) {
372     ISView(ipmP->isxu,0);
373   }
374 
375 #endif
376   ipmP->nb = ipmP->nxlb + ipmP->nxub + ipmP->mi;
377 
378   comm = ((PetscObject)(tao->solution))->comm;
379 
380   bigsize = ipmP->n+2*ipmP->nb+ipmP->me;
381   ierr = PetscMalloc(bigsize*sizeof(PetscInt),&stepind); CHKERRQ(ierr);
382   ierr = PetscMalloc(ipmP->n*sizeof(PetscInt),&xind); CHKERRQ(ierr);
383   ierr = PetscMalloc(ipmP->me*sizeof(PetscInt),&uceind); CHKERRQ(ierr);
384   ierr = VecGetOwnershipRange(tao->solution,&xstart,&xend);CHKERRQ(ierr);
385 
386   if (ipmP->nb > 0) {
387     ierr = VecCreate(comm,&ipmP->s); CHKERRQ(ierr);
388     ierr = VecSetSizes(ipmP->s,PETSC_DECIDE,ipmP->nb); CHKERRQ(ierr);
389     ierr = VecSetFromOptions(ipmP->s); CHKERRQ(ierr);
390     ierr = VecDuplicate(ipmP->s,&ipmP->ds); CHKERRQ(ierr);
391     ierr = VecDuplicate(ipmP->s,&ipmP->rhs_s); CHKERRQ(ierr);
392     ierr = VecDuplicate(ipmP->s,&ipmP->complementarity); CHKERRQ(ierr);
393     ierr = VecDuplicate(ipmP->s,&ipmP->ci); CHKERRQ(ierr);
394 
395     ierr = VecDuplicate(ipmP->s,&ipmP->lamdai); CHKERRQ(ierr);
396     ierr = VecDuplicate(ipmP->s,&ipmP->dlamdai); CHKERRQ(ierr);
397     ierr = VecDuplicate(ipmP->s,&ipmP->rhs_lamdai); CHKERRQ(ierr);
398     ierr = VecDuplicate(ipmP->s,&ipmP->save_lamdai); CHKERRQ(ierr);
399 
400 
401     ierr = VecDuplicate(ipmP->s,&ipmP->save_s); CHKERRQ(ierr);
402     ierr = VecDuplicate(ipmP->s,&ipmP->rpi); CHKERRQ(ierr);
403     ierr = VecDuplicate(ipmP->s,&ipmP->Zero_nb); CHKERRQ(ierr);
404     ierr = VecSet(ipmP->Zero_nb,0.0); CHKERRQ(ierr);
405     ierr = VecDuplicate(ipmP->s,&ipmP->One_nb); CHKERRQ(ierr);
406     ierr = VecSet(ipmP->One_nb,1.0); CHKERRQ(ierr);
407     ierr = VecDuplicate(ipmP->s,&ipmP->Inf_nb); CHKERRQ(ierr);
408     ierr = VecSet(ipmP->Inf_nb,TAO_INFINITY); CHKERRQ(ierr);
409 
410     ierr = PetscMalloc(ipmP->nb*sizeof(PetscInt),&cind); CHKERRQ(ierr);
411     ierr = PetscMalloc(ipmP->mi*sizeof(PetscInt),&ucind); CHKERRQ(ierr);
412     ierr = VecGetOwnershipRange(ipmP->s,&sstart,&send);CHKERRQ(ierr);
413 
414 
415 
416     if (ipmP->mi > 0) {
417       ierr = VecGetOwnershipRange(tao->constraints_inequality,&ucstart,&ucend); CHKERRQ(ierr);
418       counter=0;
419       for (i=ucstart;i<ucend;i++) {
420 	cind[counter++] = i;
421       }
422       ierr = ISCreateGeneral(comm,counter,cind,PETSC_COPY_VALUES,&isuc); CHKERRQ(ierr);
423       ierr = ISCreateGeneral(comm,counter,cind,PETSC_COPY_VALUES,&isc); CHKERRQ(ierr);
424       ierr = VecScatterCreate(tao->constraints_inequality,isuc,ipmP->ci,isc,&ipmP->ci_scat); CHKERRQ(ierr);
425 
426       ierr = ISDestroy(&isuc);
427       ierr = ISDestroy(&isc);
428     }
429     /* need to know how may xbound indices are on each process */
430     /* TODO better way */
431     if (ipmP->nxlb) {
432       ierr = ISAllGather(ipmP->isxl,&bigxl);CHKERRQ(ierr);
433       ierr = ISGetIndices(bigxl,&xli);CHKERRQ(ierr);
434       /* find offsets for this processor */
435       xl_offset = ipmP->mi;
436       for (i=0;i<ipmP->nxlb;i++) {
437 	if (xli[i] < xstart) {
438 	  xl_offset++;
439 	} else break;
440       }
441       ierr = ISRestoreIndices(bigxl,&xli);CHKERRQ(ierr);
442 
443       ierr = ISGetIndices(ipmP->isxl,&xli);CHKERRQ(ierr);
444       ierr = ISGetLocalSize(ipmP->isxl,&nloc);CHKERRQ(ierr);
445       for (i=0;i<nloc;i++) {
446 	xind[i] = xli[i];
447 	cind[i] = xl_offset+i;
448       }
449 
450       ierr = ISCreateGeneral(comm,nloc,xind,PETSC_COPY_VALUES,&isx); CHKERRQ(ierr);
451       ierr = ISCreateGeneral(comm,nloc,cind,PETSC_COPY_VALUES,&isc);CHKERRQ(ierr);
452       ierr = VecScatterCreate(tao->XL,isx,ipmP->ci,isc,&ipmP->xl_scat); CHKERRQ(ierr);
453       ierr = ISDestroy(&isx);CHKERRQ(ierr);
454       ierr = ISDestroy(&isc);CHKERRQ(ierr);
455       ierr = ISDestroy(&bigxl);CHKERRQ(ierr);
456     }
457 
458 
459     if (ipmP->nxub) {
460       ierr = ISAllGather(ipmP->isxu,&bigxu);CHKERRQ(ierr);
461       ierr = ISGetIndices(bigxu,&xui);CHKERRQ(ierr);
462       /* find offsets for this processor */
463       xu_offset = ipmP->mi + ipmP->nxlb;
464       for (i=0;i<ipmP->nxub;i++) {
465 	if (xui[i] < xstart) {
466 	  xu_offset++;
467 	} else break;
468       }
469       ierr = ISRestoreIndices(bigxu,&xui);CHKERRQ(ierr);
470 
471       ierr = ISGetIndices(ipmP->isxu,&xui);CHKERRQ(ierr);
472       ierr = ISGetLocalSize(ipmP->isxu,&nloc);CHKERRQ(ierr);
473       for (i=0;i<nloc;i++) {
474 	xind[i] = xui[i];
475 	cind[i] = xu_offset+i;
476       }
477 
478       ierr = ISCreateGeneral(comm,nloc,xind,PETSC_COPY_VALUES,&isx); CHKERRQ(ierr);
479       ierr = ISCreateGeneral(comm,nloc,cind,PETSC_COPY_VALUES,&isc);CHKERRQ(ierr);
480       ierr = VecScatterCreate(tao->XU,isx,ipmP->ci,isc,&ipmP->xu_scat); CHKERRQ(ierr);
481       ierr = ISDestroy(&isx);CHKERRQ(ierr);
482       ierr = ISDestroy(&isc);CHKERRQ(ierr);
483       ierr = ISDestroy(&bigxu);CHKERRQ(ierr);
484     }
485   }
486 
487 
488   ierr = VecCreate(comm,&ipmP->bigrhs); CHKERRQ(ierr);
489   ierr = VecGetType(tao->solution,&vtype); CHKERRQ(ierr);
490   ierr = VecSetType(ipmP->bigrhs,vtype); CHKERRQ(ierr);
491   ierr = VecSetSizes(ipmP->bigrhs,PETSC_DECIDE,bigsize); CHKERRQ(ierr);
492   ierr = VecSetFromOptions(ipmP->bigrhs); CHKERRQ(ierr);
493   ierr = VecDuplicate(ipmP->bigrhs,&ipmP->bigstep); CHKERRQ(ierr);
494 
495   /* create scatters for step->x and x->rhs */
496   for (i=xstart;i<xend;i++) {
497     stepind[i-xstart] = i;
498     xind[i-xstart] = i;
499   }
500   ierr = ISCreateGeneral(comm,xend-xstart,stepind,PETSC_COPY_VALUES,&sis); CHKERRQ(ierr);
501   ierr = ISCreateGeneral(comm,xend-xstart,xind,PETSC_COPY_VALUES,&is1); CHKERRQ(ierr);
502   ierr = VecScatterCreate(ipmP->bigstep,sis,tao->solution,is1,&ipmP->step1); CHKERRQ(ierr);
503   ierr = VecScatterCreate(tao->solution,is1,ipmP->bigrhs,sis,&ipmP->rhs1); CHKERRQ(ierr);
504   ierr = ISDestroy(&sis); CHKERRQ(ierr);
505   ierr = ISDestroy(&is1); CHKERRQ(ierr);
506 
507   if (ipmP->nb > 0) {
508     for (i=sstart;i<send;i++) {
509       stepind[i-sstart] = i+ipmP->n;
510       cind[i-sstart] = i;
511     }
512     ierr = ISCreateGeneral(comm,send-sstart,stepind,PETSC_COPY_VALUES,&sis); CHKERRQ(ierr);
513     ierr = ISCreateGeneral(comm,send-sstart,cind,PETSC_COPY_VALUES,&is1); CHKERRQ(ierr);
514     ierr = VecScatterCreate(ipmP->bigstep,sis,ipmP->s,is1,&ipmP->step2); CHKERRQ(ierr);
515     ierr = ISDestroy(&sis); CHKERRQ(ierr);
516 
517     for (i=sstart;i<send;i++) {
518       stepind[i-sstart] = i+ipmP->n+ipmP->me;
519       cind[i-sstart] = i;
520     }
521     ierr = ISCreateGeneral(comm,send-sstart,stepind,PETSC_COPY_VALUES,&sis); CHKERRQ(ierr);
522     ierr = VecScatterCreate(ipmP->s,is1,ipmP->bigrhs,sis,&ipmP->rhs3); CHKERRQ(ierr);
523     ierr = ISDestroy(&sis); CHKERRQ(ierr);
524     ierr = ISDestroy(&is1); CHKERRQ(ierr);
525 
526 
527   }
528 
529   if (ipmP->me > 0) {
530     ierr = VecGetOwnershipRange(tao->constraints_equality,&ucestart,&uceend); CHKERRQ(ierr);
531     for (i=ucestart;i<uceend;i++) {
532       stepind[i-ucestart] = i + ipmP->n+ipmP->nb;
533       uceind[i-ucestart] = i;
534     }
535 
536     ierr = ISCreateGeneral(comm,uceend-ucestart,stepind,PETSC_COPY_VALUES,&sis); CHKERRQ(ierr);
537     ierr = ISCreateGeneral(comm,uceend-ucestart,uceind,PETSC_COPY_VALUES,&is1); CHKERRQ(ierr);
538     ierr = VecScatterCreate(ipmP->bigstep,sis,tao->constraints_equality,is1,&ipmP->step3); CHKERRQ(ierr);
539     ierr = ISDestroy(&sis); CHKERRQ(ierr);
540 
541 
542     for (i=ucestart;i<uceend;i++) {
543       stepind[i-ucestart] = i + ipmP->n;
544     }
545 
546     ierr = ISCreateGeneral(comm,uceend-ucestart,stepind,PETSC_COPY_VALUES,&sis); CHKERRQ(ierr);
547     ierr = VecScatterCreate(tao->constraints_equality,is1,ipmP->bigrhs,sis,&ipmP->rhs2); CHKERRQ(ierr);
548     ierr = ISDestroy(&sis); CHKERRQ(ierr);
549     ierr = ISDestroy(&is1); CHKERRQ(ierr);
550   }
551 
552   if (ipmP->nb > 0) {
553     for (i=sstart;i<send;i++) {
554       stepind[i-sstart] = i + ipmP->n + ipmP->nb + ipmP->me;
555       cind[i-sstart] = i;
556     }
557     ierr = ISCreateGeneral(comm,send-sstart,cind,PETSC_COPY_VALUES,&is1);
558     ierr = ISCreateGeneral(comm,send-sstart,stepind,PETSC_COPY_VALUES,&sis); CHKERRQ(ierr);
559     ierr = VecScatterCreate(ipmP->bigstep,sis,ipmP->s,is1,&ipmP->step4); CHKERRQ(ierr);
560     ierr = VecScatterCreate(ipmP->s,is1,ipmP->bigrhs,sis,&ipmP->rhs4); CHKERRQ(ierr);
561     ierr = ISDestroy(&sis); CHKERRQ(ierr);
562     ierr = ISDestroy(&is1); CHKERRQ(ierr);
563   }
564 
565   ierr = PetscFree(stepind); CHKERRQ(ierr);
566   ierr = PetscFree(cind); CHKERRQ(ierr);
567   ierr = PetscFree(ucind); CHKERRQ(ierr);
568   ierr = PetscFree(uceind); CHKERRQ(ierr);
569   ierr = PetscFree(xind); CHKERRQ(ierr);
570 
571   PetscFunctionReturn(0);
572 }
573 
574 #undef __FUNCT__
575 #define __FUNCT__ "TaoDestroy_IPM"
576 static PetscErrorCode TaoDestroy_IPM(TaoSolver tao)
577 {
578   TAO_IPM *ipmP = (TAO_IPM*)tao->data;
579   PetscErrorCode ierr;
580   PetscFunctionBegin;
581   ierr = VecDestroy(&ipmP->rd); CHKERRQ(ierr);
582   ierr = VecDestroy(&ipmP->rpe); CHKERRQ(ierr);
583   ierr = VecDestroy(&ipmP->rpi); CHKERRQ(ierr);
584   ierr = VecDestroy(&ipmP->work); CHKERRQ(ierr);
585   ierr = VecDestroy(&ipmP->lamdae); CHKERRQ(ierr);
586   ierr = VecDestroy(&ipmP->lamdai); CHKERRQ(ierr);
587   ierr = VecDestroy(&ipmP->s); CHKERRQ(ierr);
588   ierr = VecDestroy(&ipmP->ds); CHKERRQ(ierr);
589   ierr = VecDestroy(&ipmP->ci); CHKERRQ(ierr);
590 
591   ierr = VecDestroy(&ipmP->rhs_x); CHKERRQ(ierr);
592   ierr = VecDestroy(&ipmP->rhs_lamdae); CHKERRQ(ierr);
593   ierr = VecDestroy(&ipmP->rhs_lamdai); CHKERRQ(ierr);
594   ierr = VecDestroy(&ipmP->rhs_s); CHKERRQ(ierr);
595 
596   ierr = VecDestroy(&ipmP->save_x); CHKERRQ(ierr);
597   ierr = VecDestroy(&ipmP->save_lamdae); CHKERRQ(ierr);
598   ierr = VecDestroy(&ipmP->save_lamdai); CHKERRQ(ierr);
599   ierr = VecDestroy(&ipmP->save_s); CHKERRQ(ierr);
600 
601   ierr = VecScatterDestroy(&ipmP->step1); CHKERRQ(ierr);
602   ierr = VecScatterDestroy(&ipmP->step2); CHKERRQ(ierr);
603   ierr = VecScatterDestroy(&ipmP->step3); CHKERRQ(ierr);
604   ierr = VecScatterDestroy(&ipmP->step4); CHKERRQ(ierr);
605 
606   ierr = VecScatterDestroy(&ipmP->rhs1); CHKERRQ(ierr);
607   ierr = VecScatterDestroy(&ipmP->rhs2); CHKERRQ(ierr);
608   ierr = VecScatterDestroy(&ipmP->rhs3); CHKERRQ(ierr);
609   ierr = VecScatterDestroy(&ipmP->rhs4); CHKERRQ(ierr);
610 
611   ierr = VecScatterDestroy(&ipmP->ci_scat); CHKERRQ(ierr);
612   ierr = VecScatterDestroy(&ipmP->xl_scat); CHKERRQ(ierr);
613   ierr = VecScatterDestroy(&ipmP->xu_scat); CHKERRQ(ierr);
614 
615   ierr = VecDestroy(&ipmP->dlamdai); CHKERRQ(ierr);
616   ierr = VecDestroy(&ipmP->dlamdae); CHKERRQ(ierr);
617   ierr = VecDestroy(&ipmP->Zero_nb); CHKERRQ(ierr);
618   ierr = VecDestroy(&ipmP->One_nb); CHKERRQ(ierr);
619   ierr = VecDestroy(&ipmP->Inf_nb); CHKERRQ(ierr);
620   ierr = VecDestroy(&ipmP->complementarity); CHKERRQ(ierr);
621 
622 
623   ierr = VecDestroy(&ipmP->bigrhs); CHKERRQ(ierr);
624   ierr = VecDestroy(&ipmP->bigstep); CHKERRQ(ierr);
625   ierr = MatDestroy(&ipmP->Ai); CHKERRQ(ierr);
626   ierr = MatDestroy(&ipmP->K); CHKERRQ(ierr);
627   ierr = ISDestroy(&ipmP->isxu); CHKERRQ(ierr);
628   ierr = ISDestroy(&ipmP->isxl); CHKERRQ(ierr);
629   ierr = PetscFree(tao->data); CHKERRQ(ierr);
630   tao->data = PETSC_NULL;
631   PetscFunctionReturn(0);
632 }
633 
634 #undef __FUNCT__
635 #define __FUNCT__ "TaoSetFromOptions_IPM"
636 static PetscErrorCode TaoSetFromOptions_IPM(TaoSolver tao)
637 {
638   TAO_IPM *ipmP = (TAO_IPM*)tao->data;
639   PetscErrorCode ierr;
640   PetscBool flg;
641   PetscFunctionBegin;
642   ierr = PetscOptionsHead("IPM method for constrained optimization"); CHKERRQ(ierr);
643   ierr = PetscOptionsBool("-ipm_monitorkkt","monitor kkt status",PETSC_NULL,ipmP->monitorkkt,&ipmP->monitorkkt,&flg); CHKERRQ(ierr);
644   ierr = PetscOptionsReal("-ipm_pushs","parameter to push initial slack variables away from bounds",PETSC_NULL,ipmP->pushs,&ipmP->pushs,&flg);
645   ierr = PetscOptionsReal("-ipm_pushnu","parameter to push initial (inequality) dual variables away from bounds",PETSC_NULL,ipmP->pushnu,&ipmP->pushnu,&flg);
646   ierr = PetscOptionsTail(); CHKERRQ(ierr);
647   ierr =KSPSetFromOptions(tao->ksp); CHKERRQ(ierr);
648   PetscFunctionReturn(0);
649 }
650 
651 #undef __FUNCT__
652 #define __FUNCT__ "TaoView_IPM"
653 static PetscErrorCode TaoView_IPM(TaoSolver tao, PetscViewer viewer)
654 {
655   return 0;
656 }
657 
658 /* IPMObjectiveAndGradient()
659    f = d'x + 0.5 * x' * H * x
660    rd = H*x + d + Ae'*lame - Ai'*lami
661    rpe = Ae*x - be
662    rpi = Ai*x - yi - bi
663    mu = yi' * lami/mi;
664    com = yi.*lami
665 
666    phi = ||rd|| + ||rpe|| + ||rpi|| + ||com||
667 */
668 /*
669 #undef __FUNCT__
670 #define __FUNCT__ "IPMObjective"
671 static PetscErrorCode IPMObjective(TaoLineSearch ls, Vec X, PetscReal *f, void *tptr)
672 {
673   TaoSolver tao = (TaoSolver)tptr;
674   TAO_IPM *ipmP = (TAO_IPM*)tao->data;
675   PetscErrorCode ierr;
676   PetscFunctionBegin;
677   ierr = IPMComputeKKT(tao); CHKERRQ(ierr);
678   *f = ipmP->phi;
679   PetscFunctionReturn(0);
680 }
681 */
682 
683 /*
684    f = d'x + 0.5 * x' * H * x
685    rd = H*x + d + Ae'*lame - Ai'*lami
686        Ai =   jac_ineq
687 	       I (w/lb)
688 	      -I (w/ub)
689 
690    rpe = ce
691    rpi = ci - s;
692    com = s.*lami
693    mu = yi' * lami/mi;
694 
695    phi = ||rd|| + ||rpe|| + ||rpi|| + ||com||
696 */
697 #undef __FUNCT__
698 #define __FUNCT__ "IPMComputeKKT"
699 static PetscErrorCode IPMComputeKKT(TaoSolver tao)
700 {
701   TAO_IPM *ipmP = (TAO_IPM *)tao->data;
702   PetscScalar norm;
703   PetscErrorCode ierr;
704   ierr = VecCopy(tao->gradient,ipmP->rd); CHKERRQ(ierr);
705 
706   if (ipmP->me > 0) {
707     /* rd = gradient + Ae'*lamdae */
708     ierr = MatMultTranspose(tao->jacobian_equality,ipmP->lamdae,ipmP->work); CHKERRQ(ierr);
709     ierr = VecAXPY(ipmP->rd, 1.0, ipmP->work); CHKERRQ(ierr);
710 
711 #if defined DEBUG_KKT
712     PetscPrintf(PETSC_COMM_WORLD,"\nAe.lamdae\n");
713     ierr = VecView(ipmP->work,0);
714 #endif
715     /* rpe = ce(x) */
716     ierr = VecCopy(tao->constraints_equality,ipmP->rpe); CHKERRQ(ierr);
717 
718   }
719   if (ipmP->nb > 0) {
720     /* rd = rd - Ai'*lamdai */
721     ierr = MatMultTranspose(ipmP->Ai,ipmP->lamdai,ipmP->work); CHKERRQ(ierr);
722     ierr = VecAXPY(ipmP->rd, -1.0, ipmP->work); CHKERRQ(ierr);
723 #if defined DEBUG_KKT
724     PetscPrintf(PETSC_COMM_WORLD,"\nAi\n");
725     ierr = MatView(ipmP->Ai,0);
726     PetscPrintf(PETSC_COMM_WORLD,"\nAi.lamdai\n");
727     ierr = VecView(ipmP->work,0);
728 #endif
729     /* rpi = cin - s */
730     ierr = VecCopy(ipmP->ci,ipmP->rpi); CHKERRQ(ierr);
731     ierr = VecAXPY(ipmP->rpi, -1.0, ipmP->s); CHKERRQ(ierr);
732 
733     /* com = s .* lami */
734     ierr = VecPointwiseMult(ipmP->complementarity, ipmP->s,ipmP->lamdai); CHKERRQ(ierr);
735 
736   }
737   /* phi = ||rd; rpe; rpi; com|| */
738   ierr = VecDot(ipmP->rd,ipmP->rd,&norm); CHKERRQ(ierr);
739   ipmP->phi = norm;
740   if (ipmP->me > 0 ) {
741     ierr = VecDot(ipmP->rpe,ipmP->rpe,&norm); CHKERRQ(ierr);
742     ipmP->phi += norm;
743   }
744   if (ipmP->nb > 0) {
745     ierr = VecDot(ipmP->rpi,ipmP->rpi,&norm); CHKERRQ(ierr);
746     ipmP->phi += norm;
747     ierr = VecDot(ipmP->complementarity,ipmP->complementarity,&norm); CHKERRQ(ierr);
748     ipmP->phi += norm;
749     /* mu = s'*lami/nb */
750     ierr = VecDot(ipmP->s,ipmP->lamdai,&ipmP->mu); CHKERRQ(ierr);
751     ipmP->mu /= ipmP->nb;
752   } else {
753     ipmP->mu = 1.0;
754   }
755 
756   ipmP->phi = PetscSqrtScalar(ipmP->phi);
757 #if defined DEBUG_KKT
758   if (ipmP->monitorkkt) {
759     ierr = PetscPrintf(PETSC_COMM_WORLD,"obj=%G,\tphi = %G,\tmu=%G\talpha1=%G\talpha2=%G\n",ipmP->kkt_f,ipmP->phi,ipmP->mu,ipmP->alpha1,ipmP->alpha2);
760   }
761   CHKMEMQ;
762   PetscPrintf(PETSC_COMM_WORLD,"\ngradient\n");
763   ierr = VecView(tao->gradient,0);
764   PetscPrintf(PETSC_COMM_WORLD,"\nrd\n");
765   ierr = VecView(ipmP->rd,0);
766   PetscPrintf(PETSC_COMM_WORLD,"\nrpe\n");
767   ierr = VecView(ipmP->rpe,0);
768   PetscPrintf(PETSC_COMM_WORLD,"\nrpi\n");
769   ierr = VecView(ipmP->rpi,0);
770   PetscPrintf(PETSC_COMM_WORLD,"\ncomplementarity\n");
771   ierr = VecView(ipmP->complementarity,0);
772 #endif
773   PetscFunctionReturn(0);
774 }
775 
776 #undef __FUNCT__
777 #define __FUNCT__ "IPMEvaluate"
778 /* evaluate user info at current point */
779 PetscErrorCode IPMEvaluate(TaoSolver tao)
780 {
781   TAO_IPM *ipmP = (TAO_IPM *)tao->data;
782   PetscErrorCode ierr;
783   PetscFunctionBegin;
784   ierr = TaoComputeObjectiveAndGradient(tao,tao->solution,&ipmP->kkt_f,tao->gradient); CHKERRQ(ierr);
785   ierr = TaoComputeHessian(tao,tao->solution,&tao->hessian,&tao->hessian_pre,&ipmP->Hflag); CHKERRQ(ierr);
786 
787   if (ipmP->me > 0) {
788     ierr = TaoComputeEqualityConstraints(tao,tao->solution,tao->constraints_equality);
789     ierr = TaoComputeJacobianEquality(tao,tao->solution,&tao->jacobian_equality,&tao->jacobian_equality_pre,&ipmP->Aiflag); CHKERRQ(ierr);
790   }
791   if (ipmP->mi > 0) {
792     ierr = TaoComputeInequalityConstraints(tao,tao->solution,tao->constraints_inequality);
793     ierr = TaoComputeJacobianInequality(tao,tao->solution,&tao->jacobian_inequality,&tao->jacobian_inequality_pre,&ipmP->Aeflag); CHKERRQ(ierr);
794 
795   }
796   if (ipmP->nb > 0) {
797     /* Ai' =   jac_ineq | I (w/lb) | -I (w/ub)  */
798     ierr = IPMUpdateAi(tao); CHKERRQ(ierr);
799   }
800   PetscFunctionReturn(0);
801 }
802 
803 #undef __FUNCT__
804 #define __FUNCT__ "IPMPushInitialPoint"
805 /* Push initial point away from bounds */
806 PetscErrorCode IPMPushInitialPoint(TaoSolver tao)
807 {
808   TAO_IPM *ipmP = (TAO_IPM *)tao->data;
809   PetscErrorCode ierr;
810   PetscFunctionBegin;
811 
812   ierr = TaoComputeVariableBounds(tao); CHKERRQ(ierr);
813   if (tao->XL && tao->XU) {
814     ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution); CHKERRQ(ierr);
815   }
816   if (ipmP->nb > 0) {
817     ierr = VecSet(ipmP->s,ipmP->pushs); CHKERRQ(ierr);
818     ierr = VecSet(ipmP->lamdai,ipmP->pushnu); CHKERRQ(ierr);
819     if (ipmP->mi > 0) {
820       ierr = VecSet(tao->DI,ipmP->pushnu); CHKERRQ(ierr);
821     }
822   }
823   if (ipmP->me > 0) {
824     ierr = VecSet(tao->DE,1.0); CHKERRQ(ierr);
825     ierr = VecSet(ipmP->lamdae,1.0); CHKERRQ(ierr);
826   }
827 
828 
829   PetscFunctionReturn(0);
830 }
831 
832 #undef __FUNCT__
833 #define __FUNCT__ "IPMUpdateAi"
834 PetscErrorCode IPMUpdateAi(TaoSolver tao)
835 {
836   /* Ai =     Ji
837 	      I (w/lb)
838 	     -I (w/ub) */
839 
840   /* Ci =    user->ci
841              Xi - lb (w/lb)
842 	     -Xi + ub (w/ub)  */
843 
844   TAO_IPM *ipmP = (TAO_IPM *)tao->data;
845   MPI_Comm comm;
846   PetscInt i;
847   PetscScalar newval;
848   PetscInt newrow,newcol,ncols;
849   const PetscScalar *vals;
850   const PetscInt *cols;
851   PetscInt astart,aend,jstart,jend;
852   PetscInt *nonzeros;
853   PetscInt r2,r3,r4;
854   PetscMPIInt mpisize;
855   PetscErrorCode ierr;
856 
857   PetscFunctionBegin;
858   CHKMEMQ;
859   r2 = ipmP->mi;
860   r3 = r2 + ipmP->nxlb;
861   r4 = r3 + ipmP->nxub;
862 
863   if (!ipmP->nb) {
864     PetscFunctionReturn(0);
865   }
866   CHKMEMQ;
867 
868   /* Create Ai matrix if it doesn't exist yet */
869   if (!ipmP->Ai) {
870     comm = ((PetscObject)(tao->solution))->comm;
871     ierr = PetscMalloc(ipmP->nb*sizeof(PetscInt),&nonzeros); CHKERRQ(ierr);
872     ierr = MPI_Comm_size(comm,&mpisize);
873     if (mpisize == 1) {
874       for (i=0;i<ipmP->mi;i++) {
875 	ierr = MatGetRow(tao->jacobian_inequality,i,&ncols,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
876 	nonzeros[i] = ncols;
877 	ierr = MatRestoreRow(tao->jacobian_inequality,i,&ncols,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
878       }
879       for (i=r2;i<r4;i++) {
880 	nonzeros[i] = 1;
881       }
882     }
883     ierr = MatCreate(comm,&ipmP->Ai); CHKERRQ(ierr);
884     ierr = MatSetType(ipmP->Ai,MATAIJ); CHKERRQ(ierr);
885     ierr = MatSetSizes(ipmP->Ai,PETSC_DECIDE,PETSC_DECIDE,ipmP->nb,ipmP->n);CHKERRQ(ierr);
886     ierr = MatSetFromOptions(ipmP->Ai); CHKERRQ(ierr);
887     ierr = MatMPIAIJSetPreallocation(ipmP->Ai,ipmP->nb,PETSC_NULL,ipmP->nb,PETSC_NULL);
888     ierr = MatSeqAIJSetPreallocation(ipmP->Ai,PETSC_DEFAULT,nonzeros);CHKERRQ(ierr);
889     if (mpisize ==1) {
890       ierr = PetscFree(nonzeros);CHKERRQ(ierr);
891     }
892   }
893 
894 
895   /* Copy values from user jacobian to Ai */
896   ierr = MatGetOwnershipRange(ipmP->Ai,&astart,&aend); CHKERRQ(ierr);
897 
898   /* Ai w/lb */
899   if (ipmP->mi) {
900     ierr = MatZeroEntries(ipmP->Ai); CHKERRQ(ierr);
901     ierr = MatGetOwnershipRange(tao->jacobian_inequality,&jstart,&jend); CHKERRQ(ierr);
902     for (i=jstart;i<jend;i++) {
903       ierr = MatGetRow(tao->jacobian_inequality,i,&ncols,&cols,&vals); CHKERRQ(ierr);
904       newrow = i;
905       ierr = MatSetValues(ipmP->Ai,1,&newrow,ncols,cols,vals,INSERT_VALUES); CHKERRQ(ierr);
906       ierr = MatRestoreRow(tao->jacobian_inequality,i,&ncols,&cols,&vals); CHKERRQ(ierr);
907     }
908   }
909 
910 
911   /* I w/ xlb */
912   if (ipmP->nxlb) {
913     for (i=0;i<ipmP->nxlb;i++) {
914       if (i>=astart && i<aend) {
915 	newrow = i+r2;
916 	newcol = i;
917 	newval = 1.0;
918 	ierr = MatSetValues(ipmP->Ai,1,&newrow,1,&newcol,&newval,INSERT_VALUES); CHKERRQ(ierr);
919       }
920     }
921   }
922   if (ipmP->nxub) {
923     /* I w/ xub */
924     for (i=0;i<ipmP->nxub;i++) {
925       if (i>=astart && i<aend) {
926       newrow = i+r3;
927       newcol = i;
928       newval = -1.0;
929       ierr = MatSetValues(ipmP->Ai,1,&newrow,1,&newcol,&newval,INSERT_VALUES); CHKERRQ(ierr);
930       }
931     }
932   }
933 
934 
935   ierr = MatAssemblyBegin(ipmP->Ai,MAT_FINAL_ASSEMBLY);
936   ierr = MatAssemblyEnd(ipmP->Ai,MAT_FINAL_ASSEMBLY);
937   CHKMEMQ;
938 
939   ierr = VecSet(ipmP->ci,0.0); CHKERRQ(ierr);
940 
941   /* user ci */
942   if (ipmP->mi > 0) {
943     ierr = VecScatterBegin(ipmP->ci_scat,tao->constraints_inequality,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD); CHKERRQ(ierr);
944     ierr = VecScatterEnd(ipmP->ci_scat,tao->constraints_inequality,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD); CHKERRQ(ierr);
945   }
946   if (!ipmP->work){
947     VecDuplicate(tao->solution,&ipmP->work);
948   }
949   ierr = VecCopy(tao->solution,ipmP->work);CHKERRQ(ierr);
950   if (tao->XL) {
951     ierr = VecAXPY(ipmP->work,-1.0,tao->XL);CHKERRQ(ierr);
952 
953     /* lower bounds on variables */
954     if (ipmP->nxlb > 0) {
955       ierr = VecScatterBegin(ipmP->xl_scat,ipmP->work,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD); CHKERRQ(ierr);
956       ierr = VecScatterEnd(ipmP->xl_scat,ipmP->work,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD); CHKERRQ(ierr);
957     }
958   }
959   if (tao->XU) {
960     /* upper bounds on variables */
961     ierr = VecCopy(tao->solution,ipmP->work);CHKERRQ(ierr);
962     ierr = VecScale(ipmP->work,-1.0);CHKERRQ(ierr);
963     ierr = VecAXPY(ipmP->work,1.0,tao->XU);CHKERRQ(ierr);
964     if (ipmP->nxub > 0) {
965       ierr = VecScatterBegin(ipmP->xu_scat,ipmP->work,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD); CHKERRQ(ierr);
966       ierr = VecScatterEnd(ipmP->xu_scat,ipmP->work,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD); CHKERRQ(ierr);
967     }
968   }
969 
970   PetscFunctionReturn(0);
971 }
972 
973 #undef __FUNCT__
974 #define __FUNCT__ "IPMUpdateK"
975 /* create K = [ Hlag , 0 , Ae', -Ai'];
976               [Ae , 0,   0  , 0];
977               [Ai ,-I,   0 ,  0];
978               [ 0 , S ,  0,   Y ];  */
979 PetscErrorCode IPMUpdateK(TaoSolver tao)
980 {
981   TAO_IPM *ipmP = (TAO_IPM *)tao->data;
982   MPI_Comm comm;
983   PetscMPIInt mpisize;
984   PetscErrorCode ierr;
985   PetscInt i,j,row;
986   PetscInt ncols,newcol,newcols[2],newrow;
987   const PetscInt *cols;
988   const PetscReal *vals;
989   PetscReal *l,*y;
990   PetscReal *newvals;
991   PetscReal newval;
992   PetscInt subsize;
993   const PetscInt *indices;
994   PetscInt *nonzeros,*d_nonzeros,*o_nonzeros;
995   PetscInt bigsize;
996   PetscInt r1,r2,r3;
997   PetscInt c1,c2,c3;
998   PetscInt klocalsize;
999   PetscInt hstart,hend,kstart,kend;
1000   PetscInt aistart,aiend,aestart,aeend;
1001   PetscInt sstart,send;
1002   PetscFunctionBegin;
1003 
1004   comm = ((PetscObject)(tao->solution))->comm;
1005   ierr = MPI_Comm_size(comm,&mpisize);
1006   ierr = IPMUpdateAi(tao); CHKERRQ(ierr);
1007 #if defined DEBUG_K
1008   PetscPrintf(PETSC_COMM_WORLD,"H\n");  MatView(tao->hessian,0);
1009   if (ipmP->nb) {
1010     PetscPrintf(PETSC_COMM_WORLD,"Ai\n"); MatView(ipmP->Ai,0);
1011   }
1012   if (ipmP->me) {
1013     PetscPrintf(PETSC_COMM_WORLD,"Ae\n"); MatView(tao->jacobian_equality,0);
1014   }
1015 
1016 #endif
1017   /* allocate workspace */
1018   subsize = PetscMax(ipmP->n,ipmP->nb);
1019   subsize = PetscMax(ipmP->me,subsize);
1020   subsize = PetscMax(2,subsize);
1021   ierr = PetscMalloc(sizeof(PetscInt)*subsize,&indices); CHKERRQ(ierr);
1022   ierr = PetscMalloc(sizeof(PetscReal)*subsize,&newvals); CHKERRQ(ierr);
1023 
1024   r1 = c1 = ipmP->n;
1025   r2 = r1 + ipmP->me;  c2 = c1 + ipmP->nb;
1026   r3 = c3 = r2 + ipmP->nb;
1027 
1028 
1029 
1030   bigsize = ipmP->n+2*ipmP->nb+ipmP->me;
1031   ierr = VecGetOwnershipRange(ipmP->bigrhs,&kstart,&kend); CHKERRQ(ierr);
1032   ierr = MatGetOwnershipRange(tao->hessian,&hstart,&hend); CHKERRQ(ierr);
1033   klocalsize = kend-kstart;
1034   if (!ipmP->K) {
1035     if (mpisize == 1) {
1036       ierr = PetscMalloc((kend-kstart)*sizeof(PetscInt),&nonzeros);CHKERRQ(ierr);
1037       for (i=0;i<bigsize;i++) {
1038 	if (i<r1) {
1039 	  ierr = MatGetRow(tao->hessian,i,&ncols,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
1040 	  nonzeros[i] = ncols;
1041 	  ierr = MatRestoreRow(tao->hessian,i,&ncols,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
1042 	  nonzeros[i] += ipmP->me+ipmP->nb;
1043 	} else if (i<r2) {
1044 	  nonzeros[i-kstart] = ipmP->n;
1045 	} else if (i<r3) {
1046 	  nonzeros[i-kstart] = ipmP->n+1;
1047 	} else if (i<bigsize) {
1048 	  nonzeros[i-kstart] = 2;
1049 	}
1050       }
1051       ierr = MatCreate(comm,&ipmP->K); CHKERRQ(ierr);
1052       ierr = MatSetType(ipmP->K,MATSEQAIJ); CHKERRQ(ierr);
1053       ierr = MatSetSizes(ipmP->K,klocalsize,klocalsize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
1054       ierr = MatSeqAIJSetPreallocation(ipmP->K,0,nonzeros); CHKERRQ(ierr);
1055       ierr = MatSetFromOptions(ipmP->K); CHKERRQ(ierr);
1056       ierr = PetscFree(nonzeros); CHKERRQ(ierr);
1057     } else {
1058       ierr = PetscMalloc((kend-kstart)*sizeof(PetscInt),&d_nonzeros); CHKERRQ(ierr);
1059       ierr = PetscMalloc((kend-kstart)*sizeof(PetscInt),&o_nonzeros); CHKERRQ(ierr);
1060       for (i=kstart;i<kend;i++) {
1061 	if (i<r1) {
1062 	  /* TODO fix preallocation for mpi mats */
1063 	  d_nonzeros[i-kstart] = PetscMin(ipmP->n+ipmP->me+ipmP->nb,kend-kstart);
1064 	  o_nonzeros[i-kstart] = PetscMin(ipmP->n+ipmP->me+ipmP->nb,bigsize-(kend-kstart));
1065 	} else if (i<r2) {
1066 	  d_nonzeros[i-kstart] = PetscMin(ipmP->n,kend-kstart);
1067 	  o_nonzeros[i-kstart] = PetscMin(ipmP->n,bigsize-(kend-kstart));
1068 	} else if (i<r3) {
1069 	  d_nonzeros[i-kstart] = PetscMin(ipmP->n+2,kend-kstart);
1070 	  o_nonzeros[i-kstart] = PetscMin(ipmP->n+2,bigsize-(kend-kstart));
1071 	} else {
1072 	  d_nonzeros[i-kstart] = PetscMin(2,kend-kstart);
1073 	  o_nonzeros[i-kstart] = PetscMin(2,bigsize-(kend-kstart));
1074 	}
1075       }
1076       ierr = MatCreate(comm,&ipmP->K); CHKERRQ(ierr);
1077       ierr = MatSetType(ipmP->K,MATMPIAIJ); CHKERRQ(ierr);
1078       ierr = MatSetSizes(ipmP->K,klocalsize,klocalsize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
1079       ierr = MatMPIAIJSetPreallocation(ipmP->K,0,d_nonzeros,0,o_nonzeros); CHKERRQ(ierr);
1080       ierr = PetscFree(d_nonzeros); CHKERRQ(ierr);
1081       ierr = PetscFree(o_nonzeros); CHKERRQ(ierr);
1082       ierr = MatSetFromOptions(ipmP->K); CHKERRQ(ierr);
1083 
1084     }
1085   }
1086 
1087 
1088   ierr = MatZeroEntries(ipmP->K); CHKERRQ(ierr);
1089   /* Copy H */
1090   for (i=hstart;i<hend;i++) {
1091     ierr = MatGetRow(tao->hessian,i,&ncols,&cols,&vals); CHKERRQ(ierr);
1092     if (ncols > 0) {
1093       ierr = MatSetValues(ipmP->K,1,&i,ncols,cols,vals,INSERT_VALUES); CHKERRQ(ierr);
1094     }
1095     ierr = MatRestoreRow(tao->hessian,i,&ncols,&cols,&vals); CHKERRQ(ierr);
1096   }
1097 
1098   /* Copy Ae and Ae' */
1099   if (ipmP->me > 0) {
1100     ierr = MatGetOwnershipRange(tao->jacobian_equality,&aestart,&aeend); CHKERRQ(ierr);
1101     for (i=aestart;i<aeend;i++) {
1102       ierr = MatGetRow(tao->jacobian_equality,i,&ncols,&cols,&vals); CHKERRQ(ierr);
1103       if (ncols > 0) {
1104 	/*Ae*/
1105 	row = i+r1;
1106 	ierr = MatSetValues(ipmP->K,1,&row,ncols,cols,vals,INSERT_VALUES); CHKERRQ(ierr);
1107 	/*Ae'*/
1108 	for (j=0;j<ncols;j++) {
1109 	  newcol = i + c2;
1110 	  newrow = cols[j];
1111 	  newval = vals[j];
1112 	  ierr = MatSetValues(ipmP->K,1,&newrow,1,&newcol,&newval,INSERT_VALUES); CHKERRQ(ierr);
1113 	}
1114       }
1115       ierr = MatRestoreRow(tao->jacobian_equality,i,&ncols,&cols,&vals); CHKERRQ(ierr);
1116     }
1117   }
1118 
1119   if (ipmP->nb > 0) {
1120     ierr = MatGetOwnershipRange(ipmP->Ai,&aistart,&aiend); CHKERRQ(ierr);
1121     /* Copy Ai,and Ai' */
1122     for (i=aistart;i<aiend;i++) {
1123       row = i+r2;
1124       ierr = MatGetRow(ipmP->Ai,i,&ncols,&cols,&vals); CHKERRQ(ierr);
1125       if (ncols > 0) {
1126 	/*Ai*/
1127 	ierr = MatSetValues(ipmP->K,1,&row,ncols,cols,vals,INSERT_VALUES); CHKERRQ(ierr);
1128 	/*-Ai'*/
1129 	for (j=0;j<ncols;j++) {
1130 	  newcol = i + c3;
1131 	  newrow = cols[j];
1132 	  newval = -vals[j];
1133 	  ierr = MatSetValues(ipmP->K,1,&newrow,1,&newcol,&newval,INSERT_VALUES); CHKERRQ(ierr);
1134 	}
1135       }
1136       ierr = MatRestoreRow(ipmP->Ai,i,&ncols,&cols,&vals); CHKERRQ(ierr);
1137     }
1138 
1139 
1140 
1141     /* -I */
1142     for (i=kstart;i<kend;i++) {
1143       if (i>=r2 && i<r3) {
1144 	newrow = i;
1145 	newcol = i-r2+c1;
1146 	newval = -1.0;
1147 	MatSetValues(ipmP->K,1,&newrow,1,&newcol,&newval,INSERT_VALUES); CHKERRQ(ierr);
1148       }
1149     }
1150 
1151     /* Copy L,Y */
1152     ierr = VecGetOwnershipRange(ipmP->s,&sstart,&send);CHKERRQ(ierr);
1153     ierr = VecGetArray(ipmP->lamdai,&l); CHKERRQ(ierr);
1154     ierr = VecGetArray(ipmP->s,&y); CHKERRQ(ierr);
1155 
1156     for (i=sstart;i<send;i++) {
1157       newcols[0] = c1+i;
1158       newcols[1] = c3+i;
1159       newvals[0] = l[i-sstart];
1160       newvals[1] = y[i-sstart];
1161       newrow = r3+i;
1162       ierr = MatSetValues(ipmP->K,1,&newrow,2,newcols,newvals,INSERT_VALUES); CHKERRQ(ierr);
1163     }
1164 
1165     ierr = VecRestoreArray(ipmP->lamdai,&l); CHKERRQ(ierr);
1166     ierr = VecRestoreArray(ipmP->s,&y); CHKERRQ(ierr);
1167   }
1168 
1169   ierr = PetscFree(indices); CHKERRQ(ierr);
1170   ierr = PetscFree(newvals); CHKERRQ(ierr);
1171   ierr = MatAssemblyBegin(ipmP->K,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
1172   ierr = MatAssemblyEnd(ipmP->K,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
1173 #if defined DEBUG_K
1174   PetscPrintf(PETSC_COMM_WORLD,"K\n");  MatView(ipmP->K,0);
1175 #endif
1176   PetscFunctionReturn(0);
1177 }
1178 
1179 #undef __FUNCT__
1180 #define __FUNCT__ "IPMGatherRHS"
1181 PetscErrorCode IPMGatherRHS(TaoSolver tao,Vec RHS,Vec X1,Vec X2,Vec X3,Vec X4)
1182 {
1183   TAO_IPM *ipmP = (TAO_IPM *)tao->data;
1184   PetscErrorCode ierr;
1185   PetscFunctionBegin;
1186 
1187   /* rhs = [x1      (n)
1188             x2     (me)
1189 	    x3     (nb)
1190 	    x4     (nb)] */
1191   if (X1) {
1192     ierr = VecScatterBegin(ipmP->rhs1,X1,RHS,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1193     ierr = VecScatterEnd(ipmP->rhs1,X1,RHS,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1194   }
1195   if (ipmP->me > 0 && X2) {
1196     ierr = VecScatterBegin(ipmP->rhs2,X2,RHS,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1197     ierr = VecScatterEnd(ipmP->rhs2,X2,RHS,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1198   }
1199   if (ipmP->nb > 0) {
1200     if (X3) {
1201       ierr = VecScatterBegin(ipmP->rhs3,X3,RHS,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1202       ierr = VecScatterEnd(ipmP->rhs3,X3,RHS,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1203     }
1204     if (X4) {
1205       ierr = VecScatterBegin(ipmP->rhs4,X4,RHS,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1206       ierr = VecScatterEnd(ipmP->rhs4,X4,RHS,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1207     }
1208   }
1209 #if defined(DEBUG_SCATTER)
1210   PetscPrintf(PETSC_COMM_WORLD,"X1-X4\n");
1211   if (X1) {VecView(X1,0);}
1212   if (X2) {VecView(X2,0);}
1213   if (X3) {VecView(X3,0);}
1214   if (X4) {VecView(X4,0);}
1215   PetscPrintf(PETSC_COMM_WORLD,"RHS\n");
1216   VecView(RHS,0);
1217 #endif
1218   PetscFunctionReturn(0);
1219 }
1220 
1221 
1222 
1223 #undef __FUNCT__
1224 #define __FUNCT__ "IPMScatterStep"
1225 PetscErrorCode IPMScatterStep(TaoSolver tao, Vec STEP, Vec X1, Vec X2, Vec X3, Vec X4)
1226 {
1227   TAO_IPM *ipmP = (TAO_IPM *)tao->data;
1228   PetscErrorCode ierr;
1229   PetscFunctionBegin;
1230   CHKMEMQ;
1231   /*        [x1    (n)
1232 	     x2    (nb) may be 0
1233  	     x3    (me) may be 0
1234 	     x4    (nb) may be 0 */
1235   if (X1) {
1236     ierr = VecScatterBegin(ipmP->step1,STEP,X1,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1237     ierr = VecScatterEnd(ipmP->step1,STEP,X1,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1238   }
1239   if (X2 && ipmP->nb > 0) {
1240     ierr = VecScatterBegin(ipmP->step2,STEP,X2,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1241     ierr = VecScatterEnd(ipmP->step2,STEP,X2,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1242   }
1243   if (X3 && ipmP->me > 0) {
1244     ierr = VecScatterBegin(ipmP->step3,STEP,X3,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1245     ierr = VecScatterEnd(ipmP->step3,STEP,X3,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1246   }
1247   if (X4 && ipmP->nb > 0) {
1248     ierr = VecScatterBegin(ipmP->step4,STEP,X4,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1249     ierr = VecScatterEnd(ipmP->step4,STEP,X4,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1250   }
1251   CHKMEMQ;
1252 #if defined(DEBUG_SCATTER)
1253   PetscPrintf(PETSC_COMM_WORLD,"Step\n");
1254   VecView(STEP,0);
1255   PetscPrintf(PETSC_COMM_WORLD,"X1-X4\n");
1256   if (X1) {VecView(X1,0);}
1257   if (X2) {VecView(X2,0);}
1258   if (X3) {VecView(X3,0);}
1259   if (X4) {VecView(X4,0);}
1260 #endif
1261   PetscFunctionReturn(0);
1262 }
1263 
1264 
1265 EXTERN_C_BEGIN
1266 
1267 #undef __FUNCT__
1268 #define __FUNCT__ "TaoCreate_IPM"
1269 PetscErrorCode TaoCreate_IPM(TaoSolver tao)
1270 {
1271   TAO_IPM *ipmP;
1272   //  const char *ipmls_type = TAOLINESEARCH_IPM;
1273   PetscErrorCode ierr;
1274 
1275   PetscFunctionBegin;
1276   tao->ops->setup = TaoSetup_IPM;
1277   tao->ops->solve = TaoSolve_IPM;
1278   tao->ops->view = TaoView_IPM;
1279   tao->ops->setfromoptions = TaoSetFromOptions_IPM;
1280   tao->ops->destroy = TaoDestroy_IPM;
1281   //tao->ops->computedual = TaoComputeDual_IPM;
1282 
1283   ierr = PetscNewLog(tao,&ipmP); CHKERRQ(ierr);
1284   tao->data = (void*)ipmP;
1285   tao->max_it = 200;
1286   tao->max_funcs = 500;
1287   tao->fatol = 1e-4;
1288   tao->frtol = 1e-4;
1289   ipmP->dec = 10000; /* line search critera */
1290   ipmP->taumin = 0.995;
1291   ipmP->monitorkkt = PETSC_FALSE;
1292   ipmP->pushs = 100;
1293   ipmP->pushnu = 100;
1294   ierr = KSPCreate(((PetscObject)tao)->comm, &tao->ksp); CHKERRQ(ierr);
1295   PetscFunctionReturn(0);
1296 
1297 
1298 }
1299 EXTERN_C_END
1300 
1301