xref: /petsc/src/tao/pde_constrained/tutorials/elliptic.c (revision 327415f76d85372a4417cf1aaa14db707d4d6c04)
1c4762a1bSJed Brown #include <petsc/private/taoimpl.h>
2c4762a1bSJed Brown 
3c4762a1bSJed Brown typedef struct {
4c4762a1bSJed Brown   PetscInt n; /* Number of total variables */
5c4762a1bSJed Brown   PetscInt m; /* Number of constraints */
6c4762a1bSJed Brown   PetscInt nstate;
7c4762a1bSJed Brown   PetscInt ndesign;
8c4762a1bSJed Brown   PetscInt mx; /* grid points in each direction */
9c4762a1bSJed Brown   PetscInt ns; /* Number of data samples (1<=ns<=8)
10c4762a1bSJed Brown                   Currently only ns=1 is supported */
11c4762a1bSJed Brown   PetscInt ndata; /* Number of data points per sample */
12c4762a1bSJed Brown   IS       s_is;
13c4762a1bSJed Brown   IS       d_is;
14c4762a1bSJed Brown 
15c4762a1bSJed Brown   VecScatter state_scatter;
16c4762a1bSJed Brown   VecScatter design_scatter;
17c4762a1bSJed Brown   VecScatter *yi_scatter, *di_scatter;
18c4762a1bSJed Brown   Vec        suby,subq,subd;
19c4762a1bSJed Brown   Mat        Js,Jd,JsPrec,JsInv,JsBlock;
20c4762a1bSJed Brown 
21c4762a1bSJed Brown   PetscReal alpha; /* Regularization parameter */
22c4762a1bSJed Brown   PetscReal beta; /* Weight attributed to ||u||^2 in regularization functional */
23c4762a1bSJed Brown   PetscReal noise; /* Amount of noise to add to data */
24c4762a1bSJed Brown   PetscReal *ones;
25c4762a1bSJed Brown   Mat       Q;
26c4762a1bSJed Brown   Mat       MQ;
27c4762a1bSJed Brown   Mat       L;
28c4762a1bSJed Brown 
29c4762a1bSJed Brown   Mat Grad;
30c4762a1bSJed Brown   Mat Av,Avwork;
31c4762a1bSJed Brown   Mat Div, Divwork;
32c4762a1bSJed Brown   Mat DSG;
33c4762a1bSJed Brown   Mat Diag,Ones;
34c4762a1bSJed Brown 
35c4762a1bSJed Brown   Vec q;
36c4762a1bSJed Brown   Vec ur; /* reference */
37c4762a1bSJed Brown 
38c4762a1bSJed Brown   Vec d;
39c4762a1bSJed Brown   Vec dwork;
40c4762a1bSJed Brown 
41c4762a1bSJed Brown   Vec x; /* super vec of y,u */
42c4762a1bSJed Brown 
43c4762a1bSJed Brown   Vec y; /* state variables */
44c4762a1bSJed Brown   Vec ywork;
45c4762a1bSJed Brown 
46c4762a1bSJed Brown   Vec ytrue;
47c4762a1bSJed Brown 
48c4762a1bSJed Brown   Vec u; /* design variables */
49c4762a1bSJed Brown   Vec uwork;
50c4762a1bSJed Brown 
51c4762a1bSJed Brown   Vec utrue;
52c4762a1bSJed Brown 
53c4762a1bSJed Brown   Vec js_diag;
54c4762a1bSJed Brown 
55c4762a1bSJed Brown   Vec c; /* constraint vector */
56c4762a1bSJed Brown   Vec cwork;
57c4762a1bSJed Brown 
58c4762a1bSJed Brown   Vec lwork;
59c4762a1bSJed Brown   Vec S;
60c4762a1bSJed Brown   Vec Swork,Twork,Sdiag,Ywork;
61c4762a1bSJed Brown   Vec Av_u;
62c4762a1bSJed Brown 
63c4762a1bSJed Brown   KSP solver;
64c4762a1bSJed Brown   PC  prec;
65c4762a1bSJed Brown 
66c4762a1bSJed Brown   PetscReal tola,tolb,tolc,told;
67c4762a1bSJed Brown   PetscInt  ksp_its;
68c4762a1bSJed Brown   PetscInt  ksp_its_initial;
69c4762a1bSJed Brown   PetscLogStage stages[10];
70c4762a1bSJed Brown   PetscBool use_ptap;
71c4762a1bSJed Brown   PetscBool use_lrc;
72c4762a1bSJed Brown } AppCtx;
73c4762a1bSJed Brown 
74c4762a1bSJed Brown PetscErrorCode FormFunction(Tao, Vec, PetscReal*, void*);
75c4762a1bSJed Brown PetscErrorCode FormGradient(Tao, Vec, Vec, void*);
76c4762a1bSJed Brown PetscErrorCode FormFunctionGradient(Tao, Vec, PetscReal*, Vec, void*);
77c4762a1bSJed Brown PetscErrorCode FormJacobianState(Tao, Vec, Mat, Mat, Mat, void*);
78c4762a1bSJed Brown PetscErrorCode FormJacobianDesign(Tao, Vec, Mat,void*);
79c4762a1bSJed Brown PetscErrorCode FormConstraints(Tao, Vec, Vec, void*);
80c4762a1bSJed Brown PetscErrorCode FormHessian(Tao, Vec, Mat, Mat, void*);
81c4762a1bSJed Brown PetscErrorCode Gather(Vec, Vec, VecScatter, Vec, VecScatter);
82c4762a1bSJed Brown PetscErrorCode Scatter(Vec, Vec, VecScatter, Vec, VecScatter);
83c4762a1bSJed Brown PetscErrorCode EllipticInitialize(AppCtx*);
84c4762a1bSJed Brown PetscErrorCode EllipticDestroy(AppCtx*);
85c4762a1bSJed Brown PetscErrorCode EllipticMonitor(Tao, void*);
86c4762a1bSJed Brown 
87c4762a1bSJed Brown PetscErrorCode StateBlockMatMult(Mat,Vec,Vec);
88c4762a1bSJed Brown PetscErrorCode StateMatMult(Mat,Vec,Vec);
89c4762a1bSJed Brown 
90c4762a1bSJed Brown PetscErrorCode StateInvMatMult(Mat,Vec,Vec);
91c4762a1bSJed Brown PetscErrorCode DesignMatMult(Mat,Vec,Vec);
92c4762a1bSJed Brown PetscErrorCode DesignMatMultTranspose(Mat,Vec,Vec);
93c4762a1bSJed Brown 
94c4762a1bSJed Brown PetscErrorCode QMatMult(Mat,Vec,Vec);
95c4762a1bSJed Brown PetscErrorCode QMatMultTranspose(Mat,Vec,Vec);
96c4762a1bSJed Brown 
97c4762a1bSJed Brown static  char help[]="";
98c4762a1bSJed Brown 
99c4762a1bSJed Brown int main(int argc, char **argv)
100c4762a1bSJed Brown {
101c4762a1bSJed Brown   Vec                x0;
102c4762a1bSJed Brown   Tao                tao;
103c4762a1bSJed Brown   AppCtx             user;
104c4762a1bSJed Brown   PetscInt           ntests = 1;
105c4762a1bSJed Brown   PetscInt           i;
106c4762a1bSJed Brown 
107*327415f7SBarry Smith   PetscFunctionBeginUser;
1089566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, (char*)0,help));
109c4762a1bSJed Brown   user.mx = 8;
110d0609cedSBarry Smith   PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"elliptic example",NULL);
1119566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-mx","Number of grid points in each direction","",user.mx,&user.mx,NULL));
112c4762a1bSJed Brown   user.ns = 6;
1139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-ns","Number of data samples (1<=ns<=8)","",user.ns,&user.ns,NULL));
114c4762a1bSJed Brown   user.ndata = 64;
1159566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-ndata","Numbers of data points per sample","",user.ndata,&user.ndata,NULL));
116c4762a1bSJed Brown   user.alpha = 0.1;
1179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-alpha","Regularization parameter","",user.alpha,&user.alpha,NULL));
118c4762a1bSJed Brown   user.beta = 0.00001;
1199566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-beta","Weight attributed to ||u||^2 in regularization functional","",user.beta,&user.beta,NULL));
120c4762a1bSJed Brown   user.noise = 0.01;
1219566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-noise","Amount of noise to add to data","",user.noise,&user.noise,NULL));
122c4762a1bSJed Brown 
123c4762a1bSJed Brown   user.use_ptap = PETSC_FALSE;
1249566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-use_ptap","Use ptap matrix for DSG","",user.use_ptap,&user.use_ptap,NULL));
125c4762a1bSJed Brown   user.use_lrc = PETSC_FALSE;
1269566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-use_lrc","Use lrc matrix for Js","",user.use_lrc,&user.use_lrc,NULL));
1279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-ntests","Number of times to repeat TaoSolve","",ntests,&ntests,NULL));
128d0609cedSBarry Smith   PetscOptionsEnd();
12976280437SVaclav Hapla 
130c4762a1bSJed Brown   user.m = user.ns*user.mx*user.mx*user.mx; /* number of constraints */
131c4762a1bSJed Brown   user.nstate =  user.m;
132c4762a1bSJed Brown   user.ndesign = user.mx*user.mx*user.mx;
133c4762a1bSJed Brown   user.n = user.nstate + user.ndesign; /* number of variables */
134c4762a1bSJed Brown 
135c4762a1bSJed Brown   /* Create TAO solver and set desired solution method */
1369566063dSJacob Faibussowitsch   PetscCall(TaoCreate(PETSC_COMM_WORLD,&tao));
1379566063dSJacob Faibussowitsch   PetscCall(TaoSetType(tao,TAOLCL));
138c4762a1bSJed Brown 
139c4762a1bSJed Brown   /* Set up initial vectors and matrices */
1409566063dSJacob Faibussowitsch   PetscCall(EllipticInitialize(&user));
141c4762a1bSJed Brown 
1429566063dSJacob Faibussowitsch   PetscCall(Gather(user.x,user.y,user.state_scatter,user.u,user.design_scatter));
1439566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user.x,&x0));
1449566063dSJacob Faibussowitsch   PetscCall(VecCopy(user.x,x0));
145c4762a1bSJed Brown 
146c4762a1bSJed Brown   /* Set solution vector with an initial guess */
1479566063dSJacob Faibussowitsch   PetscCall(TaoSetSolution(tao,user.x));
1489566063dSJacob Faibussowitsch   PetscCall(TaoSetObjective(tao, FormFunction, &user));
1499566063dSJacob Faibussowitsch   PetscCall(TaoSetGradient(tao, NULL, FormGradient, &user));
1509566063dSJacob Faibussowitsch   PetscCall(TaoSetConstraintsRoutine(tao, user.c, FormConstraints, &user));
151c4762a1bSJed Brown 
1529566063dSJacob Faibussowitsch   PetscCall(TaoSetJacobianStateRoutine(tao, user.Js, NULL, user.JsInv, FormJacobianState, &user));
1539566063dSJacob Faibussowitsch   PetscCall(TaoSetJacobianDesignRoutine(tao, user.Jd, FormJacobianDesign, &user));
154c4762a1bSJed Brown 
1559566063dSJacob Faibussowitsch   PetscCall(TaoSetStateDesignIS(tao,user.s_is,user.d_is));
1569566063dSJacob Faibussowitsch   PetscCall(TaoSetFromOptions(tao));
157c4762a1bSJed Brown 
158c4762a1bSJed Brown   /* SOLVE THE APPLICATION */
1599566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Trials",&user.stages[1]));
1609566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(user.stages[1]));
161c4762a1bSJed Brown   for (i=0; i<ntests; i++) {
1629566063dSJacob Faibussowitsch     PetscCall(TaoSolve(tao));
16363a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"KSP Iterations = %" PetscInt_FMT "\n",user.ksp_its));
1649566063dSJacob Faibussowitsch     PetscCall(VecCopy(x0,user.x));
165c4762a1bSJed Brown   }
1669566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
1679566063dSJacob Faibussowitsch   PetscCall(PetscBarrier((PetscObject)user.x));
1689566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"KSP iterations within initialization: "));
16963a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"%" PetscInt_FMT "\n",user.ksp_its_initial));
170c4762a1bSJed Brown 
1719566063dSJacob Faibussowitsch   PetscCall(TaoDestroy(&tao));
1729566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x0));
1739566063dSJacob Faibussowitsch   PetscCall(EllipticDestroy(&user));
1749566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
175b122ec5aSJacob Faibussowitsch   return 0;
176c4762a1bSJed Brown }
177c4762a1bSJed Brown /* ------------------------------------------------------------------- */
178c4762a1bSJed Brown /*
179c4762a1bSJed Brown    dwork = Qy - d
180c4762a1bSJed Brown    lwork = L*(u-ur)
181c4762a1bSJed Brown    f = 1/2 * (dwork.dwork + alpha*lwork.lwork)
182c4762a1bSJed Brown */
183c4762a1bSJed Brown PetscErrorCode FormFunction(Tao tao,Vec X,PetscReal *f,void *ptr)
184c4762a1bSJed Brown {
185c4762a1bSJed Brown   PetscReal      d1=0,d2=0;
186c4762a1bSJed Brown   AppCtx         *user = (AppCtx*)ptr;
187c4762a1bSJed Brown 
188c4762a1bSJed Brown   PetscFunctionBegin;
1899566063dSJacob Faibussowitsch   PetscCall(Scatter(X,user->y,user->state_scatter,user->u,user->design_scatter));
1909566063dSJacob Faibussowitsch   PetscCall(MatMult(user->MQ,user->y,user->dwork));
1919566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->dwork,-1.0,user->d));
1929566063dSJacob Faibussowitsch   PetscCall(VecDot(user->dwork,user->dwork,&d1));
1939566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(user->uwork,-1.0,user->ur,user->u));
1949566063dSJacob Faibussowitsch   PetscCall(MatMult(user->L,user->uwork,user->lwork));
1959566063dSJacob Faibussowitsch   PetscCall(VecDot(user->lwork,user->lwork,&d2));
196c4762a1bSJed Brown   *f = 0.5 * (d1 + user->alpha*d2);
197c4762a1bSJed Brown   PetscFunctionReturn(0);
198c4762a1bSJed Brown }
199c4762a1bSJed Brown 
200c4762a1bSJed Brown /* ------------------------------------------------------------------- */
201c4762a1bSJed Brown /*
202c4762a1bSJed Brown     state: g_s = Q' *(Qy - d)
203c4762a1bSJed Brown     design: g_d = alpha*L'*L*(u-ur)
204c4762a1bSJed Brown */
205c4762a1bSJed Brown PetscErrorCode FormGradient(Tao tao,Vec X,Vec G,void *ptr)
206c4762a1bSJed Brown {
207c4762a1bSJed Brown   AppCtx         *user = (AppCtx*)ptr;
208c4762a1bSJed Brown 
209c4762a1bSJed Brown   PetscFunctionBegin;
2109566063dSJacob Faibussowitsch   PetscCall(Scatter(X,user->y,user->state_scatter,user->u,user->design_scatter));
2119566063dSJacob Faibussowitsch   PetscCall(MatMult(user->MQ,user->y,user->dwork));
2129566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->dwork,-1.0,user->d));
2139566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(user->MQ,user->dwork,user->ywork));
2149566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(user->uwork,-1.0,user->ur,user->u));
2159566063dSJacob Faibussowitsch   PetscCall(MatMult(user->L,user->uwork,user->lwork));
2169566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(user->L,user->lwork,user->uwork));
2179566063dSJacob Faibussowitsch   PetscCall(VecScale(user->uwork, user->alpha));
2189566063dSJacob Faibussowitsch   PetscCall(Gather(G,user->ywork,user->state_scatter,user->uwork,user->design_scatter));
219c4762a1bSJed Brown   PetscFunctionReturn(0);
220c4762a1bSJed Brown }
221c4762a1bSJed Brown 
222c4762a1bSJed Brown PetscErrorCode FormFunctionGradient(Tao tao, Vec X, PetscReal *f, Vec G, void *ptr)
223c4762a1bSJed Brown {
224c4762a1bSJed Brown   PetscReal      d1,d2;
225c4762a1bSJed Brown   AppCtx         *user = (AppCtx*)ptr;
226c4762a1bSJed Brown 
227c4762a1bSJed Brown   PetscFunctionBegin;
2289566063dSJacob Faibussowitsch   PetscCall(Scatter(X,user->y,user->state_scatter,user->u,user->design_scatter));
2299566063dSJacob Faibussowitsch   PetscCall(MatMult(user->MQ,user->y,user->dwork));
2309566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->dwork,-1.0,user->d));
2319566063dSJacob Faibussowitsch   PetscCall(VecDot(user->dwork,user->dwork,&d1));
2329566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(user->MQ,user->dwork,user->ywork));
233c4762a1bSJed Brown 
2349566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(user->uwork,-1.0,user->ur,user->u));
2359566063dSJacob Faibussowitsch   PetscCall(MatMult(user->L,user->uwork,user->lwork));
2369566063dSJacob Faibussowitsch   PetscCall(VecDot(user->lwork,user->lwork,&d2));
2379566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(user->L,user->lwork,user->uwork));
2389566063dSJacob Faibussowitsch   PetscCall(VecScale(user->uwork, user->alpha));
239c4762a1bSJed Brown   *f = 0.5 * (d1 + user->alpha*d2);
2409566063dSJacob Faibussowitsch   PetscCall(Gather(G,user->ywork,user->state_scatter,user->uwork,user->design_scatter));
241c4762a1bSJed Brown   PetscFunctionReturn(0);
242c4762a1bSJed Brown }
243c4762a1bSJed Brown 
244c4762a1bSJed Brown /* ------------------------------------------------------------------- */
245c4762a1bSJed Brown /* A
246c4762a1bSJed Brown MatShell object
247c4762a1bSJed Brown */
248c4762a1bSJed Brown PetscErrorCode FormJacobianState(Tao tao, Vec X, Mat J, Mat JPre, Mat JInv, void *ptr)
249c4762a1bSJed Brown {
250c4762a1bSJed Brown   AppCtx         *user = (AppCtx*)ptr;
251c4762a1bSJed Brown 
252c4762a1bSJed Brown   PetscFunctionBegin;
2539566063dSJacob Faibussowitsch   PetscCall(Scatter(X,user->y,user->state_scatter,user->u,user->design_scatter));
254c4762a1bSJed Brown   /* DSG = Div * (1/Av_u) * Grad */
2559566063dSJacob Faibussowitsch   PetscCall(VecSet(user->uwork,0));
2569566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->uwork,-1.0,user->u));
2579566063dSJacob Faibussowitsch   PetscCall(VecExp(user->uwork));
2589566063dSJacob Faibussowitsch   PetscCall(MatMult(user->Av,user->uwork,user->Av_u));
2599566063dSJacob Faibussowitsch   PetscCall(VecCopy(user->Av_u,user->Swork));
2609566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(user->Swork));
261c4762a1bSJed Brown   if (user->use_ptap) {
2629566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(user->Diag,user->Swork,INSERT_VALUES));
2639566063dSJacob Faibussowitsch     PetscCall(MatPtAP(user->Diag,user->Grad,MAT_REUSE_MATRIX,1.0,&user->DSG));
264c4762a1bSJed Brown   } else {
2659566063dSJacob Faibussowitsch     PetscCall(MatCopy(user->Div,user->Divwork,SAME_NONZERO_PATTERN));
2669566063dSJacob Faibussowitsch     PetscCall(MatDiagonalScale(user->Divwork,NULL,user->Swork));
2679566063dSJacob Faibussowitsch     PetscCall(MatProductNumeric(user->DSG));
268c4762a1bSJed Brown   }
269c4762a1bSJed Brown   PetscFunctionReturn(0);
270c4762a1bSJed Brown }
271c4762a1bSJed Brown /* ------------------------------------------------------------------- */
272c4762a1bSJed Brown /* B */
273c4762a1bSJed Brown PetscErrorCode FormJacobianDesign(Tao tao, Vec X, Mat J, void *ptr)
274c4762a1bSJed Brown {
275c4762a1bSJed Brown   AppCtx         *user = (AppCtx*)ptr;
276c4762a1bSJed Brown 
277c4762a1bSJed Brown   PetscFunctionBegin;
2789566063dSJacob Faibussowitsch   PetscCall(Scatter(X,user->y,user->state_scatter,user->u,user->design_scatter));
279c4762a1bSJed Brown   PetscFunctionReturn(0);
280c4762a1bSJed Brown }
281c4762a1bSJed Brown 
282c4762a1bSJed Brown PetscErrorCode StateBlockMatMult(Mat J_shell, Vec X, Vec Y)
283c4762a1bSJed Brown {
284c4762a1bSJed Brown   PetscReal      sum;
285c4762a1bSJed Brown   AppCtx         *user;
286c4762a1bSJed Brown 
287c4762a1bSJed Brown   PetscFunctionBegin;
2889566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J_shell,&user));
2899566063dSJacob Faibussowitsch   PetscCall(MatMult(user->DSG,X,Y));
2909566063dSJacob Faibussowitsch   PetscCall(VecSum(X,&sum));
291c4762a1bSJed Brown   sum /= user->ndesign;
2929566063dSJacob Faibussowitsch   PetscCall(VecShift(Y,sum));
293c4762a1bSJed Brown   PetscFunctionReturn(0);
294c4762a1bSJed Brown }
295c4762a1bSJed Brown 
296c4762a1bSJed Brown PetscErrorCode StateMatMult(Mat J_shell, Vec X, Vec Y)
297c4762a1bSJed Brown {
298c4762a1bSJed Brown   PetscInt       i;
299c4762a1bSJed Brown   AppCtx         *user;
300c4762a1bSJed Brown 
301c4762a1bSJed Brown   PetscFunctionBegin;
3029566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J_shell,&user));
303c4762a1bSJed Brown   if (user->ns == 1) {
3049566063dSJacob Faibussowitsch     PetscCall(MatMult(user->JsBlock,X,Y));
305c4762a1bSJed Brown   } else {
306c4762a1bSJed Brown     for (i=0;i<user->ns;i++) {
3079566063dSJacob Faibussowitsch       PetscCall(Scatter(X,user->subq,user->yi_scatter[i],0,0));
3089566063dSJacob Faibussowitsch       PetscCall(Scatter(Y,user->suby,user->yi_scatter[i],0,0));
3099566063dSJacob Faibussowitsch       PetscCall(MatMult(user->JsBlock,user->subq,user->suby));
3109566063dSJacob Faibussowitsch       PetscCall(Gather(Y,user->suby,user->yi_scatter[i],0,0));
311c4762a1bSJed Brown     }
312c4762a1bSJed Brown   }
313c4762a1bSJed Brown   PetscFunctionReturn(0);
314c4762a1bSJed Brown }
315c4762a1bSJed Brown 
316c4762a1bSJed Brown PetscErrorCode StateInvMatMult(Mat J_shell, Vec X, Vec Y)
317c4762a1bSJed Brown {
318c4762a1bSJed Brown   PetscInt       its,i;
319c4762a1bSJed Brown   AppCtx         *user;
320c4762a1bSJed Brown 
321c4762a1bSJed Brown   PetscFunctionBegin;
3229566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J_shell,&user));
3239566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(user->solver,user->JsBlock,user->DSG));
324c4762a1bSJed Brown   if (Y == user->ytrue) {
325c4762a1bSJed Brown     /* First solve is done using true solution to set up problem */
3269566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(user->solver,1e-8,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT));
327c4762a1bSJed Brown   } else {
3289566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(user->solver,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT));
329c4762a1bSJed Brown   }
330c4762a1bSJed Brown   if (user->ns == 1) {
3319566063dSJacob Faibussowitsch     PetscCall(KSPSolve(user->solver,X,Y));
3329566063dSJacob Faibussowitsch     PetscCall(KSPGetIterationNumber(user->solver,&its));
333c4762a1bSJed Brown     user->ksp_its+=its;
334c4762a1bSJed Brown   } else {
335c4762a1bSJed Brown     for (i=0;i<user->ns;i++) {
3369566063dSJacob Faibussowitsch       PetscCall(Scatter(X,user->subq,user->yi_scatter[i],0,0));
3379566063dSJacob Faibussowitsch       PetscCall(Scatter(Y,user->suby,user->yi_scatter[i],0,0));
3389566063dSJacob Faibussowitsch       PetscCall(KSPSolve(user->solver,user->subq,user->suby));
3399566063dSJacob Faibussowitsch       PetscCall(KSPGetIterationNumber(user->solver,&its));
340c4762a1bSJed Brown       user->ksp_its+=its;
3419566063dSJacob Faibussowitsch       PetscCall(Gather(Y,user->suby,user->yi_scatter[i],0,0));
342c4762a1bSJed Brown     }
343c4762a1bSJed Brown   }
344c4762a1bSJed Brown   PetscFunctionReturn(0);
345c4762a1bSJed Brown }
346c4762a1bSJed Brown PetscErrorCode QMatMult(Mat J_shell, Vec X, Vec Y)
347c4762a1bSJed Brown {
348c4762a1bSJed Brown   AppCtx         *user;
349c4762a1bSJed Brown   PetscInt       i;
350c4762a1bSJed Brown 
351c4762a1bSJed Brown   PetscFunctionBegin;
3529566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J_shell,&user));
353c4762a1bSJed Brown   if (user->ns == 1) {
3549566063dSJacob Faibussowitsch     PetscCall(MatMult(user->Q,X,Y));
355c4762a1bSJed Brown   } else {
356c4762a1bSJed Brown     for (i=0;i<user->ns;i++) {
3579566063dSJacob Faibussowitsch       PetscCall(Scatter(X,user->subq,user->yi_scatter[i],0,0));
3589566063dSJacob Faibussowitsch       PetscCall(Scatter(Y,user->subd,user->di_scatter[i],0,0));
3599566063dSJacob Faibussowitsch       PetscCall(MatMult(user->Q,user->subq,user->subd));
3609566063dSJacob Faibussowitsch       PetscCall(Gather(Y,user->subd,user->di_scatter[i],0,0));
361c4762a1bSJed Brown     }
362c4762a1bSJed Brown   }
363c4762a1bSJed Brown   PetscFunctionReturn(0);
364c4762a1bSJed Brown }
365c4762a1bSJed Brown 
366c4762a1bSJed Brown PetscErrorCode QMatMultTranspose(Mat J_shell, Vec X, Vec Y)
367c4762a1bSJed Brown {
368c4762a1bSJed Brown   AppCtx         *user;
369c4762a1bSJed Brown   PetscInt       i;
370c4762a1bSJed Brown 
371c4762a1bSJed Brown   PetscFunctionBegin;
3729566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J_shell,&user));
373c4762a1bSJed Brown   if (user->ns == 1) {
3749566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(user->Q,X,Y));
375c4762a1bSJed Brown   } else {
376c4762a1bSJed Brown     for (i=0;i<user->ns;i++) {
3779566063dSJacob Faibussowitsch       PetscCall(Scatter(X,user->subd,user->di_scatter[i],0,0));
3789566063dSJacob Faibussowitsch       PetscCall(Scatter(Y,user->suby,user->yi_scatter[i],0,0));
3799566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(user->Q,user->subd,user->suby));
3809566063dSJacob Faibussowitsch       PetscCall(Gather(Y,user->suby,user->yi_scatter[i],0,0));
381c4762a1bSJed Brown     }
382c4762a1bSJed Brown   }
383c4762a1bSJed Brown   PetscFunctionReturn(0);
384c4762a1bSJed Brown }
385c4762a1bSJed Brown 
386c4762a1bSJed Brown PetscErrorCode DesignMatMult(Mat J_shell, Vec X, Vec Y)
387c4762a1bSJed Brown {
388c4762a1bSJed Brown   PetscInt       i;
389c4762a1bSJed Brown   AppCtx         *user;
390c4762a1bSJed Brown 
391c4762a1bSJed Brown   PetscFunctionBegin;
3929566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J_shell,&user));
393c4762a1bSJed Brown 
394c4762a1bSJed Brown   /* sdiag(1./v) */
3959566063dSJacob Faibussowitsch   PetscCall(VecSet(user->uwork,0));
3969566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->uwork,-1.0,user->u));
3979566063dSJacob Faibussowitsch   PetscCall(VecExp(user->uwork));
398c4762a1bSJed Brown 
399c4762a1bSJed Brown   /* sdiag(1./((Av*(1./v)).^2)) */
4009566063dSJacob Faibussowitsch   PetscCall(MatMult(user->Av,user->uwork,user->Swork));
4019566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(user->Swork,user->Swork,user->Swork));
4029566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(user->Swork));
403c4762a1bSJed Brown 
404c4762a1bSJed Brown   /* (Av * (sdiag(1./v) * b)) */
4059566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(user->uwork,user->uwork,X));
4069566063dSJacob Faibussowitsch   PetscCall(MatMult(user->Av,user->uwork,user->Twork));
407c4762a1bSJed Brown 
408c4762a1bSJed Brown   /* (sdiag(1./((Av*(1./v)).^2)) * (Av * (sdiag(1./v) * b))) */
4099566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(user->Swork,user->Twork,user->Swork));
410c4762a1bSJed Brown 
411c4762a1bSJed Brown   if (user->ns == 1) {
412c4762a1bSJed Brown     /* (sdiag(Grad*y(:,i)) */
4139566063dSJacob Faibussowitsch     PetscCall(MatMult(user->Grad,user->y,user->Twork));
414c4762a1bSJed Brown 
415c4762a1bSJed Brown     /* Div * (sdiag(Grad*y(:,i)) * (sdiag(1./((Av*(1./v)).^2)) * (Av * (sdiag(1./v) * b)))) */
4169566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(user->Swork,user->Twork,user->Swork));
4179566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(user->Grad,user->Swork,Y));
418c4762a1bSJed Brown   } else {
419c4762a1bSJed Brown     for (i=0;i<user->ns;i++) {
4209566063dSJacob Faibussowitsch       PetscCall(Scatter(user->y,user->suby,user->yi_scatter[i],0,0));
4219566063dSJacob Faibussowitsch       PetscCall(Scatter(Y,user->subq,user->yi_scatter[i],0,0));
422c4762a1bSJed Brown 
4239566063dSJacob Faibussowitsch       PetscCall(MatMult(user->Grad,user->suby,user->Twork));
4249566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(user->Twork,user->Twork,user->Swork));
4259566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(user->Grad,user->Twork,user->subq));
4269566063dSJacob Faibussowitsch       PetscCall(Gather(user->y,user->suby,user->yi_scatter[i],0,0));
4279566063dSJacob Faibussowitsch       PetscCall(Gather(Y,user->subq,user->yi_scatter[i],0,0));
428c4762a1bSJed Brown     }
429c4762a1bSJed Brown   }
430c4762a1bSJed Brown   PetscFunctionReturn(0);
431c4762a1bSJed Brown }
432c4762a1bSJed Brown 
433c4762a1bSJed Brown PetscErrorCode DesignMatMultTranspose(Mat J_shell, Vec X, Vec Y)
434c4762a1bSJed Brown {
435c4762a1bSJed Brown   PetscInt       i;
436c4762a1bSJed Brown   AppCtx         *user;
437c4762a1bSJed Brown 
438c4762a1bSJed Brown   PetscFunctionBegin;
4399566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J_shell,&user));
4409566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(Y));
441c4762a1bSJed Brown 
442c4762a1bSJed Brown   /* Sdiag = 1./((Av*(1./v)).^2) */
4439566063dSJacob Faibussowitsch   PetscCall(VecSet(user->uwork,0));
4449566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->uwork,-1.0,user->u));
4459566063dSJacob Faibussowitsch   PetscCall(VecExp(user->uwork));
4469566063dSJacob Faibussowitsch   PetscCall(MatMult(user->Av,user->uwork,user->Swork));
4479566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(user->Sdiag,user->Swork,user->Swork));
4489566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(user->Sdiag));
449c4762a1bSJed Brown 
450c4762a1bSJed Brown   for (i=0;i<user->ns;i++) {
4519566063dSJacob Faibussowitsch     PetscCall(Scatter(X,user->subq,user->yi_scatter[i],0,0));
4529566063dSJacob Faibussowitsch     PetscCall(Scatter(user->y,user->suby,user->yi_scatter[i],0,0));
453c4762a1bSJed Brown 
454c4762a1bSJed Brown     /* Swork = (Div' * b(:,i)) */
4559566063dSJacob Faibussowitsch     PetscCall(MatMult(user->Grad,user->subq,user->Swork));
456c4762a1bSJed Brown 
457c4762a1bSJed Brown     /* Twork = Grad*y(:,i) */
4589566063dSJacob Faibussowitsch     PetscCall(MatMult(user->Grad,user->suby,user->Twork));
459c4762a1bSJed Brown 
460c4762a1bSJed Brown     /* Twork = sdiag(Twork) * Swork */
4619566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(user->Twork,user->Swork,user->Twork));
462c4762a1bSJed Brown 
463c4762a1bSJed Brown     /* Swork = pointwisemult(Sdiag,Twork) */
4649566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(user->Swork,user->Twork,user->Sdiag));
465c4762a1bSJed Brown 
466c4762a1bSJed Brown     /* Ywork = Av' * Swork */
4679566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(user->Av,user->Swork,user->Ywork));
468c4762a1bSJed Brown 
469c4762a1bSJed Brown     /* Ywork = pointwisemult(uwork,Ywork) */
4709566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(user->Ywork,user->uwork,user->Ywork));
4719566063dSJacob Faibussowitsch     PetscCall(VecAXPY(Y,1.0,user->Ywork));
4729566063dSJacob Faibussowitsch     PetscCall(Gather(user->y,user->suby,user->yi_scatter[i],0,0));
473c4762a1bSJed Brown   }
474c4762a1bSJed Brown   PetscFunctionReturn(0);
475c4762a1bSJed Brown }
476c4762a1bSJed Brown 
477c4762a1bSJed Brown PetscErrorCode FormConstraints(Tao tao, Vec X, Vec C, void *ptr)
478c4762a1bSJed Brown {
479c4762a1bSJed Brown    /* C=Ay - q      A = Div * Sigma * Grad + hx*hx*hx*ones(n,n) */
480c4762a1bSJed Brown    PetscReal      sum;
481c4762a1bSJed Brown    PetscInt       i;
482c4762a1bSJed Brown    AppCtx         *user = (AppCtx*)ptr;
483c4762a1bSJed Brown 
484c4762a1bSJed Brown    PetscFunctionBegin;
4859566063dSJacob Faibussowitsch    PetscCall(Scatter(X,user->y,user->state_scatter,user->u,user->design_scatter));
486c4762a1bSJed Brown    if (user->ns == 1) {
4879566063dSJacob Faibussowitsch      PetscCall(MatMult(user->Grad,user->y,user->Swork));
4889566063dSJacob Faibussowitsch      PetscCall(VecPointwiseDivide(user->Swork,user->Swork,user->Av_u));
4899566063dSJacob Faibussowitsch      PetscCall(MatMultTranspose(user->Grad,user->Swork,C));
4909566063dSJacob Faibussowitsch      PetscCall(VecSum(user->y,&sum));
491c4762a1bSJed Brown      sum /= user->ndesign;
4929566063dSJacob Faibussowitsch      PetscCall(VecShift(C,sum));
493c4762a1bSJed Brown    } else {
494c4762a1bSJed Brown      for (i=0;i<user->ns;i++) {
4959566063dSJacob Faibussowitsch       PetscCall(Scatter(user->y,user->suby,user->yi_scatter[i],0,0));
4969566063dSJacob Faibussowitsch       PetscCall(Scatter(C,user->subq,user->yi_scatter[i],0,0));
4979566063dSJacob Faibussowitsch       PetscCall(MatMult(user->Grad,user->suby,user->Swork));
4989566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(user->Swork,user->Swork,user->Av_u));
4999566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(user->Grad,user->Swork,user->subq));
500c4762a1bSJed Brown 
5019566063dSJacob Faibussowitsch       PetscCall(VecSum(user->suby,&sum));
502c4762a1bSJed Brown       sum /= user->ndesign;
5039566063dSJacob Faibussowitsch       PetscCall(VecShift(user->subq,sum));
504c4762a1bSJed Brown 
5059566063dSJacob Faibussowitsch       PetscCall(Gather(user->y,user->suby,user->yi_scatter[i],0,0));
5069566063dSJacob Faibussowitsch       PetscCall(Gather(C,user->subq,user->yi_scatter[i],0,0));
507c4762a1bSJed Brown      }
508c4762a1bSJed Brown    }
5099566063dSJacob Faibussowitsch    PetscCall(VecAXPY(C,-1.0,user->q));
510c4762a1bSJed Brown    PetscFunctionReturn(0);
511c4762a1bSJed Brown }
512c4762a1bSJed Brown 
513c4762a1bSJed Brown PetscErrorCode Scatter(Vec x, Vec sub1, VecScatter scat1, Vec sub2, VecScatter scat2)
514c4762a1bSJed Brown {
515c4762a1bSJed Brown   PetscFunctionBegin;
5169566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(scat1,x,sub1,INSERT_VALUES,SCATTER_FORWARD));
5179566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(scat1,x,sub1,INSERT_VALUES,SCATTER_FORWARD));
518c4762a1bSJed Brown   if (sub2) {
5199566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat2,x,sub2,INSERT_VALUES,SCATTER_FORWARD));
5209566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat2,x,sub2,INSERT_VALUES,SCATTER_FORWARD));
521c4762a1bSJed Brown   }
522c4762a1bSJed Brown   PetscFunctionReturn(0);
523c4762a1bSJed Brown }
524c4762a1bSJed Brown 
525c4762a1bSJed Brown PetscErrorCode Gather(Vec x, Vec sub1, VecScatter scat1, Vec sub2, VecScatter scat2)
526c4762a1bSJed Brown {
527c4762a1bSJed Brown   PetscFunctionBegin;
5289566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(scat1,sub1,x,INSERT_VALUES,SCATTER_REVERSE));
5299566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(scat1,sub1,x,INSERT_VALUES,SCATTER_REVERSE));
530c4762a1bSJed Brown   if (sub2) {
5319566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(scat2,sub2,x,INSERT_VALUES,SCATTER_REVERSE));
5329566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(scat2,sub2,x,INSERT_VALUES,SCATTER_REVERSE));
533c4762a1bSJed Brown   }
534c4762a1bSJed Brown   PetscFunctionReturn(0);
535c4762a1bSJed Brown }
536c4762a1bSJed Brown 
537c4762a1bSJed Brown PetscErrorCode EllipticInitialize(AppCtx *user)
538c4762a1bSJed Brown {
539c4762a1bSJed Brown   PetscInt       m,n,i,j,k,l,linear_index,is,js,ks,ls,istart,iend,iblock;
540c4762a1bSJed Brown   Vec            XX,YY,ZZ,XXwork,YYwork,ZZwork,UTwork;
541c4762a1bSJed Brown   PetscReal      *x,*y,*z;
542c4762a1bSJed Brown   PetscReal      h,meanut;
543c4762a1bSJed Brown   PetscScalar    hinv,neg_hinv,half = 0.5,sqrt_beta;
544c4762a1bSJed Brown   PetscInt       im,indx1,indx2,indy1,indy2,indz1,indz2,nx,ny,nz;
545c4762a1bSJed Brown   IS             is_alldesign,is_allstate;
546c4762a1bSJed Brown   IS             is_from_d;
547c4762a1bSJed Brown   IS             is_from_y;
548c4762a1bSJed Brown   PetscInt       lo,hi,hi2,lo2,ysubnlocal,dsubnlocal;
549c4762a1bSJed Brown   const PetscInt *ranges, *subranges;
550c4762a1bSJed Brown   PetscMPIInt    size;
551c4762a1bSJed Brown   PetscReal      xri,yri,zri,xim,yim,zim,dx1,dx2,dy1,dy2,dz1,dz2,Dx,Dy,Dz;
552c4762a1bSJed Brown   PetscScalar    v,vx,vy,vz;
553c4762a1bSJed Brown   PetscInt       offset,subindex,subvec,nrank,kk;
554c4762a1bSJed Brown 
555c4762a1bSJed Brown   PetscScalar xr[64] = {0.4970,     0.8498,     0.7814,     0.6268,     0.7782,     0.6402,     0.3617,     0.3160,
556c4762a1bSJed Brown                         0.3610,     0.5298,     0.6987,     0.3331,     0.7962,     0.5596,     0.3866,     0.6774,
557c4762a1bSJed Brown                         0.5407,     0.4518,     0.6702,     0.6061,     0.7580,     0.8997,     0.5198,     0.8326,
558c4762a1bSJed Brown                         0.2138,     0.9198,     0.3000,     0.2833,     0.8288,     0.7076,     0.1820,     0.0728,
559c4762a1bSJed Brown                         0.8447,     0.2367,     0.3239,     0.6413,     0.3114,     0.4731,     0.1192,     0.9273,
560c4762a1bSJed Brown                         0.5724,     0.4331,     0.5136,     0.3547,     0.4413,     0.2602,     0.5698,     0.7278,
561c4762a1bSJed Brown                         0.5261,     0.6230,     0.2454,     0.3948,     0.7479,     0.6582,     0.4660,     0.5594,
562c4762a1bSJed Brown                         0.7574,     0.1143,     0.5900,     0.1065,     0.4260,     0.3294,     0.8276,     0.0756};
563c4762a1bSJed Brown 
564c4762a1bSJed Brown   PetscScalar yr[64] = {0.7345,     0.9120,     0.9288,     0.7528,     0.4463,     0.4985,     0.2497,     0.6256,
565c4762a1bSJed Brown                         0.3425,     0.9026,     0.6983,     0.4230,     0.7140,     0.2970,     0.4474,     0.8792,
566c4762a1bSJed Brown                         0.6604,     0.2485,     0.7968,     0.6127,     0.1796,     0.2437,     0.5938,     0.6137,
567c4762a1bSJed Brown                         0.3867,     0.5658,     0.4575,     0.1009,     0.0863,     0.3361,     0.0738,     0.3985,
568c4762a1bSJed Brown                         0.6602,     0.1437,     0.0934,     0.5983,     0.5950,     0.0763,     0.0768,     0.2288,
569c4762a1bSJed Brown                         0.5761,     0.1129,     0.3841,     0.6150,     0.6904,     0.6686,     0.1361,     0.4601,
570c4762a1bSJed Brown                         0.4491,     0.3716,     0.1969,     0.6537,     0.6743,     0.6991,     0.4811,     0.5480,
571c4762a1bSJed Brown                         0.1684,     0.4569,     0.6889,     0.8437,     0.3015,     0.2854,     0.8199,     0.2658};
572c4762a1bSJed Brown 
573c4762a1bSJed Brown   PetscScalar zr[64] = {0.7668,     0.8573,     0.2654,     0.2719,     0.1060,     0.1311,     0.6232,     0.2295,
574c4762a1bSJed Brown                         0.8009,     0.2147,     0.2119,     0.9325,     0.4473,     0.3600,     0.3374,     0.3819,
575c4762a1bSJed Brown                         0.4066,     0.5801,     0.1673,     0.0959,     0.4638,     0.8236,     0.8800,     0.2939,
576c4762a1bSJed Brown                         0.2028,     0.8262,     0.2706,     0.6276,     0.9085,     0.6443,     0.8241,     0.0712,
577c4762a1bSJed Brown                         0.1824,     0.7789,     0.4389,     0.8415,     0.7055,     0.6639,     0.3653,     0.2078,
578c4762a1bSJed Brown                         0.1987,     0.2297,     0.4321,     0.8115,     0.4915,     0.7764,     0.4657,     0.4627,
579c4762a1bSJed Brown                         0.4569,     0.4232,     0.8514,     0.0674,     0.3227,     0.1055,     0.6690,     0.6313,
580c4762a1bSJed Brown                         0.9226,     0.5461,     0.4126,     0.2364,     0.6096,     0.7042,     0.3914,     0.0711};
581c4762a1bSJed Brown 
582c4762a1bSJed Brown   PetscFunctionBegin;
5839566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
5849566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Elliptic Setup",&user->stages[0]));
5859566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(user->stages[0]));
586c4762a1bSJed Brown 
587c4762a1bSJed Brown   /* Create u,y,c,x */
5889566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->u));
5899566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->y));
5909566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->c));
5919566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->u,PETSC_DECIDE,user->ndesign));
5929566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->u));
5939566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(user->u,&ysubnlocal));
5949566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->y,ysubnlocal*user->ns,user->nstate));
5959566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->c,ysubnlocal*user->ns,user->m));
5969566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->y));
5979566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->c));
598c4762a1bSJed Brown 
599c4762a1bSJed Brown   /*
600c4762a1bSJed Brown      *******************************
601c4762a1bSJed Brown      Create scatters for x <-> y,u
602c4762a1bSJed Brown      *******************************
603c4762a1bSJed Brown 
604c4762a1bSJed Brown      If the state vector y and design vector u are partitioned as
605c4762a1bSJed Brown      [y_1; y_2; ...; y_np] and [u_1; u_2; ...; u_np] (with np = # of processors),
606c4762a1bSJed Brown      then the solution vector x is organized as
607c4762a1bSJed Brown      [y_1; u_1; y_2; u_2; ...; y_np; u_np].
608c4762a1bSJed Brown      The index sets user->s_is and user->d_is correspond to the indices of the
609c4762a1bSJed Brown      state and design variables owned by the current processor.
610c4762a1bSJed Brown   */
6119566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->x));
612c4762a1bSJed Brown 
6139566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(user->y,&lo,&hi));
6149566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(user->u,&lo2,&hi2));
615c4762a1bSJed Brown 
6169566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF,hi-lo,lo,1,&is_allstate));
6179566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF,hi-lo,lo+lo2,1,&user->s_is));
6189566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF,hi2-lo2,lo2,1,&is_alldesign));
6199566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF,hi2-lo2,hi+lo2,1,&user->d_is));
620c4762a1bSJed Brown 
6219566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->x,hi-lo+hi2-lo2,user->n));
6229566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->x));
623c4762a1bSJed Brown 
6249566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(user->x,user->s_is,user->y,is_allstate,&user->state_scatter));
6259566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(user->x,user->d_is,user->u,is_alldesign,&user->design_scatter));
6269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_alldesign));
6279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_allstate));
628c4762a1bSJed Brown   /*
629c4762a1bSJed Brown      *******************************
630c4762a1bSJed Brown      Create scatter from y to y_1,y_2,...,y_ns
631c4762a1bSJed Brown      *******************************
632c4762a1bSJed Brown   */
6339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(user->ns,&user->yi_scatter));
6349566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->u,&user->suby));
6359566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->u,&user->subq));
636c4762a1bSJed Brown 
6379566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(user->y,&lo2,&hi2));
638c4762a1bSJed Brown   istart = 0;
639c4762a1bSJed Brown   for (i=0; i<user->ns; i++) {
6409566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(user->suby,&lo,&hi));
6419566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF,hi-lo,lo2+istart,1,&is_from_y));
6429566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(user->y,is_from_y,user->suby,NULL,&user->yi_scatter[i]));
643c4762a1bSJed Brown     istart = istart + hi-lo;
6449566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_from_y));
645c4762a1bSJed Brown   }
646c4762a1bSJed Brown   /*
647c4762a1bSJed Brown      *******************************
648c4762a1bSJed Brown      Create scatter from d to d_1,d_2,...,d_ns
649c4762a1bSJed Brown      *******************************
650c4762a1bSJed Brown   */
6519566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->subd));
6529566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->subd,PETSC_DECIDE,user->ndata));
6539566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->subd));
6549566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->d));
6559566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(user->subd,&dsubnlocal));
6569566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->d,dsubnlocal*user->ns,user->ndata*user->ns));
6579566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->d));
6589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(user->ns,&user->di_scatter));
659c4762a1bSJed Brown 
6609566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(user->d,&lo2,&hi2));
661c4762a1bSJed Brown   istart = 0;
662c4762a1bSJed Brown   for (i=0; i<user->ns; i++) {
6639566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(user->subd,&lo,&hi));
6649566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF,hi-lo,lo2+istart,1,&is_from_d));
6659566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(user->d,is_from_d,user->subd,NULL,&user->di_scatter[i]));
666c4762a1bSJed Brown     istart = istart + hi-lo;
6679566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_from_d));
668c4762a1bSJed Brown   }
669c4762a1bSJed Brown 
6709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(user->mx,&x));
6719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(user->mx,&y));
6729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(user->mx,&z));
673c4762a1bSJed Brown 
674c4762a1bSJed Brown   user->ksp_its = 0;
675c4762a1bSJed Brown   user->ksp_its_initial = 0;
676c4762a1bSJed Brown 
677c4762a1bSJed Brown   n = user->mx * user->mx * user->mx;
678c4762a1bSJed Brown   m = 3 * user->mx * user->mx * (user->mx-1);
679c4762a1bSJed Brown   sqrt_beta = PetscSqrtScalar(user->beta);
680c4762a1bSJed Brown 
6819566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&XX));
6829566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->q));
6839566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(XX,ysubnlocal,n));
6849566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->q,ysubnlocal*user->ns,user->m));
6859566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(XX));
6869566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->q));
687c4762a1bSJed Brown 
6889566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(XX,&YY));
6899566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(XX,&ZZ));
6909566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(XX,&XXwork));
6919566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(XX,&YYwork));
6929566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(XX,&ZZwork));
6939566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(XX,&UTwork));
6949566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(XX,&user->utrue));
695c4762a1bSJed Brown 
696c4762a1bSJed Brown   /* map for striding q */
6979566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRanges(user->q,&ranges));
6989566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRanges(user->u,&subranges));
699c4762a1bSJed Brown 
7009566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(user->q,&lo2,&hi2));
7019566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(user->u,&lo,&hi));
702c4762a1bSJed Brown   /* Generate 3D grid, and collect ns (1<=ns<=8) right-hand-side vectors into user->q */
703c4762a1bSJed Brown   h = 1.0/user->mx;
704c4762a1bSJed Brown   hinv = user->mx;
705c4762a1bSJed Brown   neg_hinv = -hinv;
706c4762a1bSJed Brown 
7079566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(XX,&istart,&iend));
708c4762a1bSJed Brown   for (linear_index=istart; linear_index<iend; linear_index++) {
709c4762a1bSJed Brown     i = linear_index % user->mx;
710c4762a1bSJed Brown     j = ((linear_index-i)/user->mx) % user->mx;
711c4762a1bSJed Brown     k = ((linear_index-i)/user->mx-j) / user->mx;
712c4762a1bSJed Brown     vx = h*(i+0.5);
713c4762a1bSJed Brown     vy = h*(j+0.5);
714c4762a1bSJed Brown     vz = h*(k+0.5);
7159566063dSJacob Faibussowitsch     PetscCall(VecSetValues(XX,1,&linear_index,&vx,INSERT_VALUES));
7169566063dSJacob Faibussowitsch     PetscCall(VecSetValues(YY,1,&linear_index,&vy,INSERT_VALUES));
7179566063dSJacob Faibussowitsch     PetscCall(VecSetValues(ZZ,1,&linear_index,&vz,INSERT_VALUES));
718c4762a1bSJed Brown     for (is=0; is<2; is++) {
719c4762a1bSJed Brown       for (js=0; js<2; js++) {
720c4762a1bSJed Brown         for (ks=0; ks<2; ks++) {
721c4762a1bSJed Brown           ls = is*4 + js*2 + ks;
722c4762a1bSJed Brown           if (ls<user->ns) {
723c4762a1bSJed Brown             l =ls*n + linear_index;
724c4762a1bSJed Brown             /* remap */
725c4762a1bSJed Brown             subindex = l%n;
726c4762a1bSJed Brown             subvec = l/n;
727c4762a1bSJed Brown             nrank=0;
728c4762a1bSJed Brown             while (subindex >= subranges[nrank+1]) nrank++;
729c4762a1bSJed Brown             offset = subindex - subranges[nrank];
730c4762a1bSJed Brown             istart=0;
731c4762a1bSJed Brown             for (kk=0;kk<nrank;kk++) istart+=user->ns*(subranges[kk+1]-subranges[kk]);
732c4762a1bSJed Brown             istart += (subranges[nrank+1]-subranges[nrank])*subvec;
733c4762a1bSJed Brown             l = istart+offset;
734c4762a1bSJed Brown             v = 100*PetscSinScalar(2*PETSC_PI*(vx+0.25*is))*PetscSinScalar(2*PETSC_PI*(vy+0.25*js))*PetscSinScalar(2*PETSC_PI*(vz+0.25*ks));
7359566063dSJacob Faibussowitsch             PetscCall(VecSetValues(user->q,1,&l,&v,INSERT_VALUES));
736c4762a1bSJed Brown           }
737c4762a1bSJed Brown         }
738c4762a1bSJed Brown       }
739c4762a1bSJed Brown     }
740c4762a1bSJed Brown   }
741c4762a1bSJed Brown 
7429566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(XX));
7439566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(XX));
7449566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(YY));
7459566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(YY));
7469566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(ZZ));
7479566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(ZZ));
7489566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(user->q));
7499566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(user->q));
750c4762a1bSJed Brown 
751c4762a1bSJed Brown   /* Compute true parameter function
752c4762a1bSJed Brown      ut = exp(-((x-0.25)^2+(y-0.25)^2+(z-0.25)^2)/0.05) - exp((x-0.75)^2-(y-0.75)^2-(z-0.75))^2/0.05) */
7539566063dSJacob Faibussowitsch   PetscCall(VecCopy(XX,XXwork));
7549566063dSJacob Faibussowitsch   PetscCall(VecCopy(YY,YYwork));
7559566063dSJacob Faibussowitsch   PetscCall(VecCopy(ZZ,ZZwork));
756c4762a1bSJed Brown 
7579566063dSJacob Faibussowitsch   PetscCall(VecShift(XXwork,-0.25));
7589566063dSJacob Faibussowitsch   PetscCall(VecShift(YYwork,-0.25));
7599566063dSJacob Faibussowitsch   PetscCall(VecShift(ZZwork,-0.25));
760c4762a1bSJed Brown 
7619566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(XXwork,XXwork,XXwork));
7629566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(YYwork,YYwork,YYwork));
7639566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(ZZwork,ZZwork,ZZwork));
764c4762a1bSJed Brown 
7659566063dSJacob Faibussowitsch   PetscCall(VecCopy(XXwork,UTwork));
7669566063dSJacob Faibussowitsch   PetscCall(VecAXPY(UTwork,1.0,YYwork));
7679566063dSJacob Faibussowitsch   PetscCall(VecAXPY(UTwork,1.0,ZZwork));
7689566063dSJacob Faibussowitsch   PetscCall(VecScale(UTwork,-20.0));
7699566063dSJacob Faibussowitsch   PetscCall(VecExp(UTwork));
7709566063dSJacob Faibussowitsch   PetscCall(VecCopy(UTwork,user->utrue));
771c4762a1bSJed Brown 
7729566063dSJacob Faibussowitsch   PetscCall(VecCopy(XX,XXwork));
7739566063dSJacob Faibussowitsch   PetscCall(VecCopy(YY,YYwork));
7749566063dSJacob Faibussowitsch   PetscCall(VecCopy(ZZ,ZZwork));
775c4762a1bSJed Brown 
7769566063dSJacob Faibussowitsch   PetscCall(VecShift(XXwork,-0.75));
7779566063dSJacob Faibussowitsch   PetscCall(VecShift(YYwork,-0.75));
7789566063dSJacob Faibussowitsch   PetscCall(VecShift(ZZwork,-0.75));
779c4762a1bSJed Brown 
7809566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(XXwork,XXwork,XXwork));
7819566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(YYwork,YYwork,YYwork));
7829566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(ZZwork,ZZwork,ZZwork));
783c4762a1bSJed Brown 
7849566063dSJacob Faibussowitsch   PetscCall(VecCopy(XXwork,UTwork));
7859566063dSJacob Faibussowitsch   PetscCall(VecAXPY(UTwork,1.0,YYwork));
7869566063dSJacob Faibussowitsch   PetscCall(VecAXPY(UTwork,1.0,ZZwork));
7879566063dSJacob Faibussowitsch   PetscCall(VecScale(UTwork,-20.0));
7889566063dSJacob Faibussowitsch   PetscCall(VecExp(UTwork));
789c4762a1bSJed Brown 
7909566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->utrue,-1.0,UTwork));
791c4762a1bSJed Brown 
7929566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&XX));
7939566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&YY));
7949566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ZZ));
7959566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&XXwork));
7969566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&YYwork));
7979566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&ZZwork));
7989566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&UTwork));
799c4762a1bSJed Brown 
800c4762a1bSJed Brown   /* Initial guess and reference model */
8019566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->utrue,&user->ur));
8029566063dSJacob Faibussowitsch   PetscCall(VecSum(user->utrue,&meanut));
803c4762a1bSJed Brown   meanut = meanut / n;
8049566063dSJacob Faibussowitsch   PetscCall(VecSet(user->ur,meanut));
8059566063dSJacob Faibussowitsch   PetscCall(VecCopy(user->ur,user->u));
806c4762a1bSJed Brown 
807c4762a1bSJed Brown   /* Generate Grad matrix */
8089566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD,&user->Grad));
8099566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(user->Grad,PETSC_DECIDE,ysubnlocal,m,n));
8109566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(user->Grad));
8119566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(user->Grad,2,NULL,2,NULL));
8129566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(user->Grad,2,NULL));
8139566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(user->Grad,&istart,&iend));
814c4762a1bSJed Brown 
815c4762a1bSJed Brown   for (i=istart; i<iend; i++) {
816c4762a1bSJed Brown     if (i<m/3) {
817c4762a1bSJed Brown       iblock = i / (user->mx-1);
818c4762a1bSJed Brown       j = iblock*user->mx + (i % (user->mx-1));
8199566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Grad,1,&i,1,&j,&neg_hinv,INSERT_VALUES));
820c4762a1bSJed Brown       j = j+1;
8219566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Grad,1,&i,1,&j,&hinv,INSERT_VALUES));
822c4762a1bSJed Brown     }
823c4762a1bSJed Brown     if (i>=m/3 && i<2*m/3) {
824c4762a1bSJed Brown       iblock = (i-m/3) / (user->mx*(user->mx-1));
825c4762a1bSJed Brown       j = iblock*user->mx*user->mx + ((i-m/3) % (user->mx*(user->mx-1)));
8269566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Grad,1,&i,1,&j,&neg_hinv,INSERT_VALUES));
827c4762a1bSJed Brown       j = j + user->mx;
8289566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Grad,1,&i,1,&j,&hinv,INSERT_VALUES));
829c4762a1bSJed Brown     }
830c4762a1bSJed Brown     if (i>=2*m/3) {
831c4762a1bSJed Brown       j = i-2*m/3;
8329566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Grad,1,&i,1,&j,&neg_hinv,INSERT_VALUES));
833c4762a1bSJed Brown       j = j + user->mx*user->mx;
8349566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Grad,1,&i,1,&j,&hinv,INSERT_VALUES));
835c4762a1bSJed Brown     }
836c4762a1bSJed Brown   }
837c4762a1bSJed Brown 
8389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(user->Grad,MAT_FINAL_ASSEMBLY));
8399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(user->Grad,MAT_FINAL_ASSEMBLY));
840c4762a1bSJed Brown 
841c4762a1bSJed Brown   /* Generate arithmetic averaging matrix Av */
8429566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD,&user->Av));
8439566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(user->Av,PETSC_DECIDE,ysubnlocal,m,n));
8449566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(user->Av));
8459566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(user->Av,2,NULL,2,NULL));
8469566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(user->Av,2,NULL));
8479566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(user->Av,&istart,&iend));
848c4762a1bSJed Brown 
849c4762a1bSJed Brown   for (i=istart; i<iend; i++) {
850c4762a1bSJed Brown     if (i<m/3) {
851c4762a1bSJed Brown       iblock = i / (user->mx-1);
852c4762a1bSJed Brown       j = iblock*user->mx + (i % (user->mx-1));
8539566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Av,1,&i,1,&j,&half,INSERT_VALUES));
854c4762a1bSJed Brown       j = j+1;
8559566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Av,1,&i,1,&j,&half,INSERT_VALUES));
856c4762a1bSJed Brown     }
857c4762a1bSJed Brown     if (i>=m/3 && i<2*m/3) {
858c4762a1bSJed Brown       iblock = (i-m/3) / (user->mx*(user->mx-1));
859c4762a1bSJed Brown       j = iblock*user->mx*user->mx + ((i-m/3) % (user->mx*(user->mx-1)));
8609566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Av,1,&i,1,&j,&half,INSERT_VALUES));
861c4762a1bSJed Brown       j = j + user->mx;
8629566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Av,1,&i,1,&j,&half,INSERT_VALUES));
863c4762a1bSJed Brown     }
864c4762a1bSJed Brown     if (i>=2*m/3) {
865c4762a1bSJed Brown       j = i-2*m/3;
8669566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Av,1,&i,1,&j,&half,INSERT_VALUES));
867c4762a1bSJed Brown       j = j + user->mx*user->mx;
8689566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->Av,1,&i,1,&j,&half,INSERT_VALUES));
869c4762a1bSJed Brown     }
870c4762a1bSJed Brown   }
871c4762a1bSJed Brown 
8729566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(user->Av,MAT_FINAL_ASSEMBLY));
8739566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(user->Av,MAT_FINAL_ASSEMBLY));
874c4762a1bSJed Brown 
8759566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD,&user->L));
8769566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(user->L,PETSC_DECIDE,ysubnlocal,m+n,n));
8779566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(user->L));
8789566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(user->L,2,NULL,2,NULL));
8799566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(user->L,2,NULL));
8809566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(user->L,&istart,&iend));
881c4762a1bSJed Brown 
882c4762a1bSJed Brown   for (i=istart; i<iend; i++) {
883c4762a1bSJed Brown     if (i<m/3) {
884c4762a1bSJed Brown       iblock = i / (user->mx-1);
885c4762a1bSJed Brown       j = iblock*user->mx + (i % (user->mx-1));
8869566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->L,1,&i,1,&j,&neg_hinv,INSERT_VALUES));
887c4762a1bSJed Brown       j = j+1;
8889566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->L,1,&i,1,&j,&hinv,INSERT_VALUES));
889c4762a1bSJed Brown     }
890c4762a1bSJed Brown     if (i>=m/3 && i<2*m/3) {
891c4762a1bSJed Brown       iblock = (i-m/3) / (user->mx*(user->mx-1));
892c4762a1bSJed Brown       j = iblock*user->mx*user->mx + ((i-m/3) % (user->mx*(user->mx-1)));
8939566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->L,1,&i,1,&j,&neg_hinv,INSERT_VALUES));
894c4762a1bSJed Brown       j = j + user->mx;
8959566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->L,1,&i,1,&j,&hinv,INSERT_VALUES));
896c4762a1bSJed Brown     }
897c4762a1bSJed Brown     if (i>=2*m/3 && i<m) {
898c4762a1bSJed Brown       j = i-2*m/3;
8999566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->L,1,&i,1,&j,&neg_hinv,INSERT_VALUES));
900c4762a1bSJed Brown       j = j + user->mx*user->mx;
9019566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->L,1,&i,1,&j,&hinv,INSERT_VALUES));
902c4762a1bSJed Brown     }
903c4762a1bSJed Brown     if (i>=m) {
904c4762a1bSJed Brown       j = i - m;
9059566063dSJacob Faibussowitsch       PetscCall(MatSetValues(user->L,1,&i,1,&j,&sqrt_beta,INSERT_VALUES));
906c4762a1bSJed Brown     }
907c4762a1bSJed Brown   }
9089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(user->L,MAT_FINAL_ASSEMBLY));
9099566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(user->L,MAT_FINAL_ASSEMBLY));
9109566063dSJacob Faibussowitsch   PetscCall(MatScale(user->L,PetscPowScalar(h,1.5)));
911c4762a1bSJed Brown 
912c4762a1bSJed Brown   /* Generate Div matrix */
913c4762a1bSJed Brown   if (!user->use_ptap) {
914c4762a1bSJed Brown     /* Generate Div matrix */
9159566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_WORLD,&user->Div));
9169566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(user->Div,ysubnlocal,PETSC_DECIDE,n,m));
9179566063dSJacob Faibussowitsch     PetscCall(MatSetFromOptions(user->Div));
9189566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(user->Div,4,NULL,4,NULL));
9199566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(user->Div,6,NULL));
9209566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(user->Grad,&istart,&iend));
921c4762a1bSJed Brown 
922c4762a1bSJed Brown     for (i=istart; i<iend; i++) {
923c4762a1bSJed Brown       if (i<m/3) {
924c4762a1bSJed Brown         iblock = i / (user->mx-1);
925c4762a1bSJed Brown         j = iblock*user->mx + (i % (user->mx-1));
9269566063dSJacob Faibussowitsch         PetscCall(MatSetValues(user->Div,1,&j,1,&i,&neg_hinv,INSERT_VALUES));
927c4762a1bSJed Brown         j = j+1;
9289566063dSJacob Faibussowitsch         PetscCall(MatSetValues(user->Div,1,&j,1,&i,&hinv,INSERT_VALUES));
929c4762a1bSJed Brown       }
930c4762a1bSJed Brown       if (i>=m/3 && i<2*m/3) {
931c4762a1bSJed Brown         iblock = (i-m/3) / (user->mx*(user->mx-1));
932c4762a1bSJed Brown         j = iblock*user->mx*user->mx + ((i-m/3) % (user->mx*(user->mx-1)));
9339566063dSJacob Faibussowitsch         PetscCall(MatSetValues(user->Div,1,&j,1,&i,&neg_hinv,INSERT_VALUES));
934c4762a1bSJed Brown         j = j + user->mx;
9359566063dSJacob Faibussowitsch         PetscCall(MatSetValues(user->Div,1,&j,1,&i,&hinv,INSERT_VALUES));
936c4762a1bSJed Brown       }
937c4762a1bSJed Brown       if (i>=2*m/3) {
938c4762a1bSJed Brown         j = i-2*m/3;
9399566063dSJacob Faibussowitsch         PetscCall(MatSetValues(user->Div,1,&j,1,&i,&neg_hinv,INSERT_VALUES));
940c4762a1bSJed Brown         j = j + user->mx*user->mx;
9419566063dSJacob Faibussowitsch         PetscCall(MatSetValues(user->Div,1,&j,1,&i,&hinv,INSERT_VALUES));
942c4762a1bSJed Brown       }
943c4762a1bSJed Brown     }
944c4762a1bSJed Brown 
9459566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(user->Div,MAT_FINAL_ASSEMBLY));
9469566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(user->Div,MAT_FINAL_ASSEMBLY));
9479566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(user->Div,MAT_SHARE_NONZERO_PATTERN,&user->Divwork));
948c4762a1bSJed Brown   } else {
9499566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_WORLD,&user->Diag));
9509566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(user->Diag,PETSC_DECIDE,PETSC_DECIDE,m,m));
9519566063dSJacob Faibussowitsch     PetscCall(MatSetFromOptions(user->Diag));
9529566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(user->Diag,1,NULL,0,NULL));
9539566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(user->Diag,1,NULL));
954c4762a1bSJed Brown   }
955c4762a1bSJed Brown 
956c4762a1bSJed Brown   /* Build work vectors and matrices */
9579566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->S));
9589566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->S, PETSC_DECIDE, m));
9599566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->S));
960c4762a1bSJed Brown 
9619566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_WORLD,&user->lwork));
9629566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(user->lwork,PETSC_DECIDE,m+user->mx*user->mx*user->mx));
9639566063dSJacob Faibussowitsch   PetscCall(VecSetFromOptions(user->lwork));
964c4762a1bSJed Brown 
9659566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(user->Av,MAT_SHARE_NONZERO_PATTERN,&user->Avwork));
966c4762a1bSJed Brown 
9679566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->S,&user->Swork));
9689566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->S,&user->Sdiag));
9699566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->S,&user->Av_u));
9709566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->S,&user->Twork));
9719566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->y,&user->ywork));
9729566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->u,&user->Ywork));
9739566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->u,&user->uwork));
9749566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->u,&user->js_diag));
9759566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->c,&user->cwork));
9769566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->d,&user->dwork));
977c4762a1bSJed Brown 
978c4762a1bSJed Brown   /* Create a matrix-free shell user->Jd for computing B*x */
9799566063dSJacob Faibussowitsch   PetscCall(MatCreateShell(PETSC_COMM_WORLD,ysubnlocal*user->ns,ysubnlocal,user->nstate,user->ndesign,user,&user->Jd));
9809566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(user->Jd,MATOP_MULT,(void(*)(void))DesignMatMult));
9819566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(user->Jd,MATOP_MULT_TRANSPOSE,(void(*)(void))DesignMatMultTranspose));
982c4762a1bSJed Brown 
983c4762a1bSJed Brown   /* Compute true state function ytrue given utrue */
9849566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(user->y,&user->ytrue));
985c4762a1bSJed Brown 
986c4762a1bSJed Brown   /* First compute Av_u = Av*exp(-u) */
9879566063dSJacob Faibussowitsch   PetscCall(VecSet(user->uwork, 0));
9889566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->uwork,-1.0,user->utrue)); /* Note: user->utrue */
9899566063dSJacob Faibussowitsch   PetscCall(VecExp(user->uwork));
9909566063dSJacob Faibussowitsch   PetscCall(MatMult(user->Av,user->uwork,user->Av_u));
991c4762a1bSJed Brown 
992c4762a1bSJed Brown   /* Next form DSG = Div*S*Grad */
9939566063dSJacob Faibussowitsch   PetscCall(VecCopy(user->Av_u,user->Swork));
9949566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(user->Swork));
995c4762a1bSJed Brown   if (user->use_ptap) {
9969566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(user->Diag,user->Swork,INSERT_VALUES));
9979566063dSJacob Faibussowitsch     PetscCall(MatPtAP(user->Diag,user->Grad,MAT_INITIAL_MATRIX,1.0,&user->DSG));
998c4762a1bSJed Brown   } else {
9999566063dSJacob Faibussowitsch     PetscCall(MatCopy(user->Div,user->Divwork,SAME_NONZERO_PATTERN));
10009566063dSJacob Faibussowitsch     PetscCall(MatDiagonalScale(user->Divwork,NULL,user->Swork));
1001c20d7725SJed Brown 
10029566063dSJacob Faibussowitsch     PetscCall(MatMatMult(user->Divwork,user->Grad,MAT_INITIAL_MATRIX,1.0,&user->DSG));
1003c4762a1bSJed Brown   }
1004c4762a1bSJed Brown 
10059566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->DSG,MAT_SYMMETRIC,PETSC_TRUE));
10069566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->DSG,MAT_SYMMETRY_ETERNAL,PETSC_TRUE));
1007c4762a1bSJed Brown 
1008c4762a1bSJed Brown   if (user->use_lrc == PETSC_TRUE) {
1009c4762a1bSJed Brown     v=PetscSqrtReal(1.0 /user->ndesign);
10109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(user->ndesign,&user->ones));
1011c4762a1bSJed Brown 
1012c4762a1bSJed Brown     for (i=0;i<user->ndesign;i++) {
1013c4762a1bSJed Brown       user->ones[i]=v;
1014c4762a1bSJed Brown     }
10159566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PETSC_COMM_WORLD,ysubnlocal,PETSC_DECIDE,user->ndesign,1,user->ones,&user->Ones));
10169566063dSJacob Faibussowitsch     PetscCall(MatCreateLRC(user->DSG,user->Ones,NULL,user->Ones,&user->JsBlock));
10179566063dSJacob Faibussowitsch     PetscCall(MatSetUp(user->JsBlock));
1018c4762a1bSJed Brown   } else {
1019c4762a1bSJed Brown     /* Create matrix-free shell user->Js for computing (A + h^3*e*e^T)*x */
10209566063dSJacob Faibussowitsch     PetscCall(MatCreateShell(PETSC_COMM_WORLD,ysubnlocal,ysubnlocal,user->ndesign,user->ndesign,user,&user->JsBlock));
10219566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(user->JsBlock,MATOP_MULT,(void(*)(void))StateBlockMatMult));
10229566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(user->JsBlock,MATOP_MULT_TRANSPOSE,(void(*)(void))StateBlockMatMult));
1023c4762a1bSJed Brown   }
10249566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->JsBlock,MAT_SYMMETRIC,PETSC_TRUE));
10259566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->JsBlock,MAT_SYMMETRY_ETERNAL,PETSC_TRUE));
10269566063dSJacob Faibussowitsch   PetscCall(MatCreateShell(PETSC_COMM_WORLD,ysubnlocal*user->ns,ysubnlocal*user->ns,user->nstate,user->nstate,user,&user->Js));
10279566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(user->Js,MATOP_MULT,(void(*)(void))StateMatMult));
10289566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(user->Js,MATOP_MULT_TRANSPOSE,(void(*)(void))StateMatMult));
10299566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->Js,MAT_SYMMETRIC,PETSC_TRUE));
10309566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->Js,MAT_SYMMETRY_ETERNAL,PETSC_TRUE));
1031c4762a1bSJed Brown 
10329566063dSJacob Faibussowitsch   PetscCall(MatCreateShell(PETSC_COMM_WORLD,ysubnlocal*user->ns,ysubnlocal*user->ns,user->nstate,user->nstate,user,&user->JsInv));
10339566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(user->JsInv,MATOP_MULT,(void(*)(void))StateInvMatMult));
10349566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(user->JsInv,MATOP_MULT_TRANSPOSE,(void(*)(void))StateInvMatMult));
10359566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->JsInv,MAT_SYMMETRIC,PETSC_TRUE));
10369566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->JsInv,MAT_SYMMETRY_ETERNAL,PETSC_TRUE));
1037c4762a1bSJed Brown 
10389566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->DSG,MAT_SYMMETRIC,PETSC_TRUE));
10399566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user->DSG,MAT_SYMMETRY_ETERNAL,PETSC_TRUE));
1040c4762a1bSJed Brown   /* Now solve for ytrue */
10419566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PETSC_COMM_WORLD,&user->solver));
10429566063dSJacob Faibussowitsch   PetscCall(KSPSetFromOptions(user->solver));
1043c4762a1bSJed Brown 
10449566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(user->solver,user->JsBlock,user->DSG));
1045c4762a1bSJed Brown 
10469566063dSJacob Faibussowitsch   PetscCall(MatMult(user->JsInv,user->q,user->ytrue));
1047c4762a1bSJed Brown   /* First compute Av_u = Av*exp(-u) */
10489566063dSJacob Faibussowitsch   PetscCall(VecSet(user->uwork,0));
10499566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->uwork,-1.0,user->u)); /* Note: user->u */
10509566063dSJacob Faibussowitsch   PetscCall(VecExp(user->uwork));
10519566063dSJacob Faibussowitsch   PetscCall(MatMult(user->Av,user->uwork,user->Av_u));
1052c4762a1bSJed Brown 
1053c4762a1bSJed Brown   /* Next update DSG = Div*S*Grad  with user->u */
10549566063dSJacob Faibussowitsch   PetscCall(VecCopy(user->Av_u,user->Swork));
10559566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(user->Swork));
1056c4762a1bSJed Brown   if (user->use_ptap) {
10579566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(user->Diag,user->Swork,INSERT_VALUES));
10589566063dSJacob Faibussowitsch     PetscCall(MatPtAP(user->Diag,user->Grad,MAT_REUSE_MATRIX,1.0,&user->DSG));
1059c4762a1bSJed Brown   } else {
10609566063dSJacob Faibussowitsch     PetscCall(MatCopy(user->Div,user->Divwork,SAME_NONZERO_PATTERN));
10619566063dSJacob Faibussowitsch     PetscCall(MatDiagonalScale(user->Divwork,NULL,user->Av_u));
10629566063dSJacob Faibussowitsch     PetscCall(MatProductNumeric(user->DSG));
1063c4762a1bSJed Brown   }
1064c4762a1bSJed Brown 
1065c4762a1bSJed Brown   /* Now solve for y */
1066c4762a1bSJed Brown 
10679566063dSJacob Faibussowitsch   PetscCall(MatMult(user->JsInv,user->q,user->y));
1068c4762a1bSJed Brown 
1069c4762a1bSJed Brown   user->ksp_its_initial = user->ksp_its;
1070c4762a1bSJed Brown   user->ksp_its = 0;
1071c4762a1bSJed Brown   /* Construct projection matrix Q (blocks) */
10729566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD,&user->Q));
10739566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(user->Q,dsubnlocal,ysubnlocal,user->ndata,user->ndesign));
10749566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(user->Q));
10759566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(user->Q,8,NULL,8,NULL));
10769566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(user->Q,8,NULL));
1077c4762a1bSJed Brown 
1078c4762a1bSJed Brown   for (i=0; i<user->mx; i++) {
1079c4762a1bSJed Brown     x[i] = h*(i+0.5);
1080c4762a1bSJed Brown     y[i] = h*(i+0.5);
1081c4762a1bSJed Brown     z[i] = h*(i+0.5);
1082c4762a1bSJed Brown   }
10839566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(user->Q,&istart,&iend));
1084c4762a1bSJed Brown 
1085c4762a1bSJed Brown   nx = user->mx; ny = user->mx; nz = user->mx;
1086c4762a1bSJed Brown   for (i=istart; i<iend; i++) {
1087c4762a1bSJed Brown 
1088c4762a1bSJed Brown     xri = xr[i];
1089c4762a1bSJed Brown     im = 0;
1090c4762a1bSJed Brown     xim = x[im];
1091c4762a1bSJed Brown     while (xri>xim && im<nx) {
1092c4762a1bSJed Brown       im = im+1;
1093c4762a1bSJed Brown       xim = x[im];
1094c4762a1bSJed Brown     }
1095c4762a1bSJed Brown     indx1 = im-1;
1096c4762a1bSJed Brown     indx2 = im;
1097c4762a1bSJed Brown     dx1 = xri - x[indx1];
1098c4762a1bSJed Brown     dx2 = x[indx2] - xri;
1099c4762a1bSJed Brown 
1100c4762a1bSJed Brown     yri = yr[i];
1101c4762a1bSJed Brown     im = 0;
1102c4762a1bSJed Brown     yim = y[im];
1103c4762a1bSJed Brown     while (yri>yim && im<ny) {
1104c4762a1bSJed Brown       im = im+1;
1105c4762a1bSJed Brown       yim = y[im];
1106c4762a1bSJed Brown     }
1107c4762a1bSJed Brown     indy1 = im-1;
1108c4762a1bSJed Brown     indy2 = im;
1109c4762a1bSJed Brown     dy1 = yri - y[indy1];
1110c4762a1bSJed Brown     dy2 = y[indy2] - yri;
1111c4762a1bSJed Brown 
1112c4762a1bSJed Brown     zri = zr[i];
1113c4762a1bSJed Brown     im = 0;
1114c4762a1bSJed Brown     zim = z[im];
1115c4762a1bSJed Brown     while (zri>zim && im<nz) {
1116c4762a1bSJed Brown       im = im+1;
1117c4762a1bSJed Brown       zim = z[im];
1118c4762a1bSJed Brown     }
1119c4762a1bSJed Brown     indz1 = im-1;
1120c4762a1bSJed Brown     indz2 = im;
1121c4762a1bSJed Brown     dz1 = zri - z[indz1];
1122c4762a1bSJed Brown     dz2 = z[indz2] - zri;
1123c4762a1bSJed Brown 
1124c4762a1bSJed Brown     Dx = x[indx2] - x[indx1];
1125c4762a1bSJed Brown     Dy = y[indy2] - y[indy1];
1126c4762a1bSJed Brown     Dz = z[indz2] - z[indz1];
1127c4762a1bSJed Brown 
1128c4762a1bSJed Brown     j = indx1 + indy1*nx + indz1*nx*ny;
1129c4762a1bSJed Brown     v = (1-dx1/Dx)*(1-dy1/Dy)*(1-dz1/Dz);
11309566063dSJacob Faibussowitsch     PetscCall(MatSetValues(user->Q,1,&i,1,&j,&v,INSERT_VALUES));
1131c4762a1bSJed Brown 
1132c4762a1bSJed Brown     j = indx1 + indy1*nx + indz2*nx*ny;
1133c4762a1bSJed Brown     v = (1-dx1/Dx)*(1-dy1/Dy)*(1-dz2/Dz);
11349566063dSJacob Faibussowitsch     PetscCall(MatSetValues(user->Q,1,&i,1,&j,&v,INSERT_VALUES));
1135c4762a1bSJed Brown 
1136c4762a1bSJed Brown     j = indx1 + indy2*nx + indz1*nx*ny;
1137c4762a1bSJed Brown     v = (1-dx1/Dx)*(1-dy2/Dy)*(1-dz1/Dz);
11389566063dSJacob Faibussowitsch     PetscCall(MatSetValues(user->Q,1,&i,1,&j,&v,INSERT_VALUES));
1139c4762a1bSJed Brown 
1140c4762a1bSJed Brown     j = indx1 + indy2*nx + indz2*nx*ny;
1141c4762a1bSJed Brown     v = (1-dx1/Dx)*(1-dy2/Dy)*(1-dz2/Dz);
11429566063dSJacob Faibussowitsch     PetscCall(MatSetValues(user->Q,1,&i,1,&j,&v,INSERT_VALUES));
1143c4762a1bSJed Brown 
1144c4762a1bSJed Brown     j = indx2 + indy1*nx + indz1*nx*ny;
1145c4762a1bSJed Brown     v = (1-dx2/Dx)*(1-dy1/Dy)*(1-dz1/Dz);
11469566063dSJacob Faibussowitsch     PetscCall(MatSetValues(user->Q,1,&i,1,&j,&v,INSERT_VALUES));
1147c4762a1bSJed Brown 
1148c4762a1bSJed Brown     j = indx2 + indy1*nx + indz2*nx*ny;
1149c4762a1bSJed Brown     v = (1-dx2/Dx)*(1-dy1/Dy)*(1-dz2/Dz);
11509566063dSJacob Faibussowitsch     PetscCall(MatSetValues(user->Q,1,&i,1,&j,&v,INSERT_VALUES));
1151c4762a1bSJed Brown 
1152c4762a1bSJed Brown     j = indx2 + indy2*nx + indz1*nx*ny;
1153c4762a1bSJed Brown     v = (1-dx2/Dx)*(1-dy2/Dy)*(1-dz1/Dz);
11549566063dSJacob Faibussowitsch     PetscCall(MatSetValues(user->Q,1,&i,1,&j,&v,INSERT_VALUES));
1155c4762a1bSJed Brown 
1156c4762a1bSJed Brown     j = indx2 + indy2*nx + indz2*nx*ny;
1157c4762a1bSJed Brown     v = (1-dx2/Dx)*(1-dy2/Dy)*(1-dz2/Dz);
11589566063dSJacob Faibussowitsch     PetscCall(MatSetValues(user->Q,1,&i,1,&j,&v,INSERT_VALUES));
1159c4762a1bSJed Brown   }
1160c4762a1bSJed Brown 
11619566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(user->Q,MAT_FINAL_ASSEMBLY));
11629566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(user->Q,MAT_FINAL_ASSEMBLY));
1163c4762a1bSJed Brown   /* Create MQ (composed of blocks of Q */
11649566063dSJacob Faibussowitsch   PetscCall(MatCreateShell(PETSC_COMM_WORLD,dsubnlocal*user->ns,PETSC_DECIDE,user->ndata*user->ns,user->nstate,user,&user->MQ));
11659566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(user->MQ,MATOP_MULT,(void(*)(void))QMatMult));
11669566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(user->MQ,MATOP_MULT_TRANSPOSE,(void(*)(void))QMatMultTranspose));
1167c4762a1bSJed Brown 
1168c4762a1bSJed Brown   /* Add noise to the measurement data */
11699566063dSJacob Faibussowitsch   PetscCall(VecSet(user->ywork,1.0));
11709566063dSJacob Faibussowitsch   PetscCall(VecAYPX(user->ywork,user->noise,user->ytrue));
11719566063dSJacob Faibussowitsch   PetscCall(MatMult(user->MQ,user->ywork,user->d));
1172c4762a1bSJed Brown 
1173c4762a1bSJed Brown   /* Now that initial conditions have been set, let the user pass tolerance options to the KSP solver */
11749566063dSJacob Faibussowitsch   PetscCall(PetscFree(x));
11759566063dSJacob Faibussowitsch   PetscCall(PetscFree(y));
11769566063dSJacob Faibussowitsch   PetscCall(PetscFree(z));
11779566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
1178c4762a1bSJed Brown   PetscFunctionReturn(0);
1179c4762a1bSJed Brown }
1180c4762a1bSJed Brown 
1181c4762a1bSJed Brown PetscErrorCode EllipticDestroy(AppCtx *user)
1182c4762a1bSJed Brown {
1183c4762a1bSJed Brown   PetscInt       i;
1184c4762a1bSJed Brown 
1185c4762a1bSJed Brown   PetscFunctionBegin;
11869566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->DSG));
11879566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&user->solver));
11889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->Q));
11899566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->MQ));
1190c4762a1bSJed Brown   if (!user->use_ptap) {
11919566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&user->Div));
11929566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&user->Divwork));
1193c4762a1bSJed Brown   } else {
11949566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&user->Diag));
1195c4762a1bSJed Brown   }
1196c4762a1bSJed Brown   if (user->use_lrc) {
11979566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&user->Ones));
1198c4762a1bSJed Brown   }
1199c4762a1bSJed Brown 
12009566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->Grad));
12019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->Av));
12029566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->Avwork));
12039566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->L));
12049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->Js));
12059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->Jd));
12069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->JsBlock));
12079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user->JsInv));
1208c4762a1bSJed Brown 
12099566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->x));
12109566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->u));
12119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->uwork));
12129566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->utrue));
12139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->y));
12149566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->ywork));
12159566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->ytrue));
12169566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->c));
12179566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->cwork));
12189566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->ur));
12199566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->q));
12209566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->d));
12219566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->dwork));
12229566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->lwork));
12239566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->S));
12249566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->Swork));
12259566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->Sdiag));
12269566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->Ywork));
12279566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->Twork));
12289566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->Av_u));
12299566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->js_diag));
12309566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&user->s_is));
12319566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&user->d_is));
12329566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->suby));
12339566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->subd));
12349566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user->subq));
12359566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&user->state_scatter));
12369566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&user->design_scatter));
1237c4762a1bSJed Brown   for (i=0;i<user->ns;i++) {
12389566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&user->yi_scatter[i]));
12399566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&user->di_scatter[i]));
1240c4762a1bSJed Brown   }
12419566063dSJacob Faibussowitsch   PetscCall(PetscFree(user->yi_scatter));
12429566063dSJacob Faibussowitsch   PetscCall(PetscFree(user->di_scatter));
1243c4762a1bSJed Brown   if (user->use_lrc) {
12449566063dSJacob Faibussowitsch     PetscCall(PetscFree(user->ones));
12459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&user->Ones));
1246c4762a1bSJed Brown   }
1247c4762a1bSJed Brown   PetscFunctionReturn(0);
1248c4762a1bSJed Brown }
1249c4762a1bSJed Brown 
1250c4762a1bSJed Brown PetscErrorCode EllipticMonitor(Tao tao, void *ptr)
1251c4762a1bSJed Brown {
1252c4762a1bSJed Brown   Vec            X;
1253c4762a1bSJed Brown   PetscReal      unorm,ynorm;
1254c4762a1bSJed Brown   AppCtx         *user = (AppCtx*)ptr;
1255c4762a1bSJed Brown 
1256c4762a1bSJed Brown   PetscFunctionBegin;
12579566063dSJacob Faibussowitsch   PetscCall(TaoGetSolution(tao,&X));
12589566063dSJacob Faibussowitsch   PetscCall(Scatter(X,user->ywork,user->state_scatter,user->uwork,user->design_scatter));
12599566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->ywork,-1.0,user->ytrue));
12609566063dSJacob Faibussowitsch   PetscCall(VecAXPY(user->uwork,-1.0,user->utrue));
12619566063dSJacob Faibussowitsch   PetscCall(VecNorm(user->uwork,NORM_2,&unorm));
12629566063dSJacob Faibussowitsch   PetscCall(VecNorm(user->ywork,NORM_2,&ynorm));
12639566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(MPI_COMM_WORLD, "||u-ut||=%g ||y-yt||=%g\n",(double)unorm,(double)ynorm));
1264c4762a1bSJed Brown   PetscFunctionReturn(0);
1265c4762a1bSJed Brown }
1266c4762a1bSJed Brown 
1267c4762a1bSJed Brown /*TEST
1268c4762a1bSJed Brown 
1269c4762a1bSJed Brown    build:
1270c4762a1bSJed Brown       requires: !complex
1271c4762a1bSJed Brown 
1272c4762a1bSJed Brown    test:
1273c4762a1bSJed Brown       args: -tao_cmonitor -ns 1 -tao_type lcl -tao_gatol 1.e-3 -tao_max_it 11
1274c4762a1bSJed Brown       requires: !single
1275c4762a1bSJed Brown 
1276c4762a1bSJed Brown    test:
1277c4762a1bSJed Brown       suffix: 2
1278c4762a1bSJed Brown       args: -tao_cmonitor -tao_type lcl -tao_max_it 11 -use_ptap -use_lrc -ns 1 -tao_gatol 1.e-3
1279c4762a1bSJed Brown       requires: !single
1280c4762a1bSJed Brown 
1281c4762a1bSJed Brown TEST*/
1282