xref: /petsc/src/tao/unconstrained/tutorials/spectraladjointassimilation.c (revision a5b23f4acc7afc99d3844ebd5fb65a81c16e8b8c)
1c4762a1bSJed Brown 
2c4762a1bSJed Brown static char help[] ="Solves a simple data assimilation problem with one dimensional advection diffusion equation using TSAdjoint\n\n";
3c4762a1bSJed Brown 
4c4762a1bSJed Brown /*
5c4762a1bSJed Brown 
6c4762a1bSJed Brown     Not yet tested in parallel
7c4762a1bSJed Brown 
8c4762a1bSJed Brown */
9c4762a1bSJed Brown /*
10c4762a1bSJed Brown    Concepts: TS^time-dependent linear problems
11c4762a1bSJed Brown    Concepts: TS^heat equation
12c4762a1bSJed Brown    Concepts: TS^diffusion equation
13c4762a1bSJed Brown    Concepts: adjoints
14c4762a1bSJed Brown    Processors: n
15c4762a1bSJed Brown */
16c4762a1bSJed Brown 
17c4762a1bSJed Brown /* ------------------------------------------------------------------------
18c4762a1bSJed Brown 
19c4762a1bSJed Brown    This program uses the one-dimensional advection-diffusion equation),
20c4762a1bSJed Brown        u_t = mu*u_xx - a u_x,
21c4762a1bSJed Brown    on the domain 0 <= x <= 1, with periodic boundary conditions
22c4762a1bSJed Brown 
23c4762a1bSJed Brown    to demonstrate solving a data assimilation problem of finding the initial conditions
24c4762a1bSJed Brown    to produce a given solution at a fixed time.
25c4762a1bSJed Brown 
26c4762a1bSJed Brown    The operators are discretized with the spectral element method
27c4762a1bSJed Brown 
28c4762a1bSJed Brown   ------------------------------------------------------------------------- */
29c4762a1bSJed Brown 
30c4762a1bSJed Brown /*
31c4762a1bSJed Brown    Include "petscts.h" so that we can use TS solvers.  Note that this file
32c4762a1bSJed Brown    automatically includes:
33c4762a1bSJed Brown      petscsys.h       - base PETSc routines   petscvec.h  - vectors
34c4762a1bSJed Brown      petscmat.h  - matrices
35c4762a1bSJed Brown      petscis.h     - index sets            petscksp.h  - Krylov subspace methods
36c4762a1bSJed Brown      petscviewer.h - viewers               petscpc.h   - preconditioners
37c4762a1bSJed Brown      petscksp.h   - linear solvers        petscsnes.h - nonlinear solvers
38c4762a1bSJed Brown */
39c4762a1bSJed Brown 
40c4762a1bSJed Brown #include <petsctao.h>
41c4762a1bSJed Brown #include <petscts.h>
42c4762a1bSJed Brown #include <petscdt.h>
43c4762a1bSJed Brown #include <petscdraw.h>
44c4762a1bSJed Brown #include <petscdmda.h>
45c4762a1bSJed Brown 
46c4762a1bSJed Brown /*
47c4762a1bSJed Brown    User-defined application context - contains data needed by the
48c4762a1bSJed Brown    application-provided call-back routines.
49c4762a1bSJed Brown */
50c4762a1bSJed Brown 
51c4762a1bSJed Brown typedef struct {
52c4762a1bSJed Brown   PetscInt  n;                /* number of nodes */
53c4762a1bSJed Brown   PetscReal *nodes;           /* GLL nodes */
54c4762a1bSJed Brown   PetscReal *weights;         /* GLL weights */
55c4762a1bSJed Brown } PetscGLL;
56c4762a1bSJed Brown 
57c4762a1bSJed Brown typedef struct {
58c4762a1bSJed Brown   PetscInt    N;             /* grid points per elements*/
59c4762a1bSJed Brown   PetscInt    E;              /* number of elements */
60c4762a1bSJed Brown   PetscReal   tol_L2,tol_max; /* error norms */
61c4762a1bSJed Brown   PetscInt    steps;          /* number of timesteps */
62c4762a1bSJed Brown   PetscReal   Tend;           /* endtime */
63c4762a1bSJed Brown   PetscReal   mu;             /* viscosity */
64c4762a1bSJed Brown   PetscReal   a;              /* advection speed */
65c4762a1bSJed Brown   PetscReal   L;              /* total length of domain */
66c4762a1bSJed Brown   PetscReal   Le;
67c4762a1bSJed Brown   PetscReal   Tadj;
68c4762a1bSJed Brown } PetscParam;
69c4762a1bSJed Brown 
70c4762a1bSJed Brown typedef struct {
71c4762a1bSJed Brown   Vec         reference;               /* desired end state */
72c4762a1bSJed Brown   Vec         grid;              /* total grid */
73c4762a1bSJed Brown   Vec         grad;
74c4762a1bSJed Brown   Vec         ic;
75c4762a1bSJed Brown   Vec         curr_sol;
76c4762a1bSJed Brown   Vec         joe;
77c4762a1bSJed Brown   Vec         true_solution;     /* actual initial conditions for the final solution */
78c4762a1bSJed Brown } PetscData;
79c4762a1bSJed Brown 
80c4762a1bSJed Brown typedef struct {
81c4762a1bSJed Brown   Vec         grid;              /* total grid */
82c4762a1bSJed Brown   Vec         mass;              /* mass matrix for total integration */
83c4762a1bSJed Brown   Mat         stiff;             /* stifness matrix */
84c4762a1bSJed Brown   Mat         advec;
85c4762a1bSJed Brown   Mat         keptstiff;
86c4762a1bSJed Brown   PetscGLL    gll;
87c4762a1bSJed Brown } PetscSEMOperators;
88c4762a1bSJed Brown 
89c4762a1bSJed Brown typedef struct {
90c4762a1bSJed Brown   DM                da;                /* distributed array data structure */
91c4762a1bSJed Brown   PetscSEMOperators SEMop;
92c4762a1bSJed Brown   PetscParam        param;
93c4762a1bSJed Brown   PetscData         dat;
94c4762a1bSJed Brown   TS                ts;
95c4762a1bSJed Brown   PetscReal         initial_dt;
96c4762a1bSJed Brown   PetscReal         *solutioncoefficients;
97c4762a1bSJed Brown   PetscInt          ncoeff;
98c4762a1bSJed Brown } AppCtx;
99c4762a1bSJed Brown 
100c4762a1bSJed Brown /*
101c4762a1bSJed Brown    User-defined routines
102c4762a1bSJed Brown */
103c4762a1bSJed Brown extern PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*);
104c4762a1bSJed Brown extern PetscErrorCode RHSLaplacian(TS,PetscReal,Vec,Mat,Mat,void*);
105c4762a1bSJed Brown extern PetscErrorCode RHSAdvection(TS,PetscReal,Vec,Mat,Mat,void*);
106c4762a1bSJed Brown extern PetscErrorCode InitialConditions(Vec,AppCtx*);
107c4762a1bSJed Brown extern PetscErrorCode ComputeReference(TS,PetscReal,Vec,AppCtx*);
108c4762a1bSJed Brown extern PetscErrorCode MonitorError(Tao,void*);
109c4762a1bSJed Brown extern PetscErrorCode MonitorDestroy(void**);
110c4762a1bSJed Brown extern PetscErrorCode ComputeSolutionCoefficients(AppCtx*);
111c4762a1bSJed Brown extern PetscErrorCode RHSFunction(TS,PetscReal,Vec,Vec,void*);
112c4762a1bSJed Brown extern PetscErrorCode RHSJacobian(TS,PetscReal,Vec,Mat,Mat,void*);
113c4762a1bSJed Brown 
114c4762a1bSJed Brown int main(int argc,char **argv)
115c4762a1bSJed Brown {
116c4762a1bSJed Brown   AppCtx         appctx;                 /* user-defined application context */
117c4762a1bSJed Brown   Tao            tao;
118c4762a1bSJed Brown   Vec            u;                      /* approximate solution vector */
119c4762a1bSJed Brown   PetscErrorCode ierr;
120c4762a1bSJed Brown   PetscInt       i, xs, xm, ind, j, lenglob;
121c4762a1bSJed Brown   PetscReal      x, *wrk_ptr1, *wrk_ptr2;
122c4762a1bSJed Brown   MatNullSpace   nsp;
123c4762a1bSJed Brown 
124c4762a1bSJed Brown    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
125c4762a1bSJed Brown      Initialize program and set problem parameters
126c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
127c4762a1bSJed Brown   PetscFunctionBegin;
128c4762a1bSJed Brown 
129c4762a1bSJed Brown   ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
130c4762a1bSJed Brown 
131c4762a1bSJed Brown   /*initialize parameters */
132c4762a1bSJed Brown   appctx.param.N    = 10;  /* order of the spectral element */
133c4762a1bSJed Brown   appctx.param.E    = 8;  /* number of elements */
134c4762a1bSJed Brown   appctx.param.L    = 1.0;  /* length of the domain */
135c4762a1bSJed Brown   appctx.param.mu   = 0.00001; /* diffusion coefficient */
136c4762a1bSJed Brown   appctx.param.a    = 0.0;     /* advection speed */
137c4762a1bSJed Brown   appctx.initial_dt = 1e-4;
138c4762a1bSJed Brown   appctx.param.steps = PETSC_MAX_INT;
139c4762a1bSJed Brown   appctx.param.Tend  = 0.01;
140c4762a1bSJed Brown   appctx.ncoeff      = 2;
141c4762a1bSJed Brown 
142c4762a1bSJed Brown   ierr = PetscOptionsGetInt(NULL,NULL,"-N",&appctx.param.N,NULL);CHKERRQ(ierr);
143c4762a1bSJed Brown   ierr = PetscOptionsGetInt(NULL,NULL,"-E",&appctx.param.E,NULL);CHKERRQ(ierr);
144c4762a1bSJed Brown   ierr = PetscOptionsGetInt(NULL,NULL,"-ncoeff",&appctx.ncoeff,NULL);CHKERRQ(ierr);
145c4762a1bSJed Brown   ierr = PetscOptionsGetReal(NULL,NULL,"-Tend",&appctx.param.Tend,NULL);CHKERRQ(ierr);
146c4762a1bSJed Brown   ierr = PetscOptionsGetReal(NULL,NULL,"-mu",&appctx.param.mu,NULL);CHKERRQ(ierr);
147c4762a1bSJed Brown   ierr = PetscOptionsGetReal(NULL,NULL,"-a",&appctx.param.a,NULL);CHKERRQ(ierr);
148c4762a1bSJed Brown   appctx.param.Le = appctx.param.L/appctx.param.E;
149c4762a1bSJed Brown 
150c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
151c4762a1bSJed Brown      Create GLL data structures
152c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
153c4762a1bSJed Brown   ierr = PetscMalloc2(appctx.param.N,&appctx.SEMop.gll.nodes,appctx.param.N,&appctx.SEMop.gll.weights);CHKERRQ(ierr);
154c4762a1bSJed Brown   ierr = PetscDTGaussLobattoLegendreQuadrature(appctx.param.N,PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA,appctx.SEMop.gll.nodes,appctx.SEMop.gll.weights);CHKERRQ(ierr);
155c4762a1bSJed Brown   appctx.SEMop.gll.n = appctx.param.N;
156c4762a1bSJed Brown   lenglob  = appctx.param.E*(appctx.param.N-1);
157c4762a1bSJed Brown 
158c4762a1bSJed Brown   /*
159c4762a1bSJed Brown      Create distributed array (DMDA) to manage parallel grid and vectors
160c4762a1bSJed Brown      and to set up the ghost point communication pattern.  There are E*(Nl-1)+1
161c4762a1bSJed Brown      total grid values spread equally among all the processors, except first and last
162c4762a1bSJed Brown   */
163c4762a1bSJed Brown 
164c4762a1bSJed Brown   ierr = DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_PERIODIC,lenglob,1,1,NULL,&appctx.da);CHKERRQ(ierr);
165c4762a1bSJed Brown   ierr = DMSetFromOptions(appctx.da);CHKERRQ(ierr);
166c4762a1bSJed Brown   ierr = DMSetUp(appctx.da);CHKERRQ(ierr);
167c4762a1bSJed Brown 
168c4762a1bSJed Brown   /*
169c4762a1bSJed Brown      Extract global and local vectors from DMDA; we use these to store the
170c4762a1bSJed Brown      approximate solution.  Then duplicate these for remaining vectors that
171c4762a1bSJed Brown      have the same types.
172c4762a1bSJed Brown   */
173c4762a1bSJed Brown 
174c4762a1bSJed Brown   ierr = DMCreateGlobalVector(appctx.da,&u);CHKERRQ(ierr);
175c4762a1bSJed Brown   ierr = VecDuplicate(u,&appctx.dat.ic);CHKERRQ(ierr);
176c4762a1bSJed Brown   ierr = VecDuplicate(u,&appctx.dat.true_solution);CHKERRQ(ierr);
177c4762a1bSJed Brown   ierr = VecDuplicate(u,&appctx.dat.reference);CHKERRQ(ierr);
178c4762a1bSJed Brown   ierr = VecDuplicate(u,&appctx.SEMop.grid);CHKERRQ(ierr);
179c4762a1bSJed Brown   ierr = VecDuplicate(u,&appctx.SEMop.mass);CHKERRQ(ierr);
180c4762a1bSJed Brown   ierr = VecDuplicate(u,&appctx.dat.curr_sol);CHKERRQ(ierr);
181c4762a1bSJed Brown   ierr = VecDuplicate(u,&appctx.dat.joe);CHKERRQ(ierr);
182c4762a1bSJed Brown 
183c4762a1bSJed Brown   ierr = DMDAGetCorners(appctx.da,&xs,NULL,NULL,&xm,NULL,NULL);CHKERRQ(ierr);
184c4762a1bSJed Brown   ierr = DMDAVecGetArray(appctx.da,appctx.SEMop.grid,&wrk_ptr1);CHKERRQ(ierr);
185c4762a1bSJed Brown   ierr = DMDAVecGetArray(appctx.da,appctx.SEMop.mass,&wrk_ptr2);CHKERRQ(ierr);
186c4762a1bSJed Brown 
187c4762a1bSJed Brown   /* Compute function over the locally owned part of the grid */
188c4762a1bSJed Brown 
189c4762a1bSJed Brown     xs=xs/(appctx.param.N-1);
190c4762a1bSJed Brown     xm=xm/(appctx.param.N-1);
191c4762a1bSJed Brown 
192c4762a1bSJed Brown   /*
193c4762a1bSJed Brown      Build total grid and mass over entire mesh (multi-elemental)
194c4762a1bSJed Brown   */
195c4762a1bSJed Brown 
196c4762a1bSJed Brown   for (i=xs; i<xs+xm; i++) {
197c4762a1bSJed Brown     for (j=0; j<appctx.param.N-1; j++) {
198c4762a1bSJed Brown       x = (appctx.param.Le/2.0)*(appctx.SEMop.gll.nodes[j]+1.0)+appctx.param.Le*i;
199c4762a1bSJed Brown       ind=i*(appctx.param.N-1)+j;
200c4762a1bSJed Brown       wrk_ptr1[ind]=x;
201c4762a1bSJed Brown       wrk_ptr2[ind]=.5*appctx.param.Le*appctx.SEMop.gll.weights[j];
202c4762a1bSJed Brown       if (j==0) wrk_ptr2[ind]+=.5*appctx.param.Le*appctx.SEMop.gll.weights[j];
203c4762a1bSJed Brown     }
204c4762a1bSJed Brown   }
205c4762a1bSJed Brown   ierr = DMDAVecRestoreArray(appctx.da,appctx.SEMop.grid,&wrk_ptr1);CHKERRQ(ierr);
206c4762a1bSJed Brown   ierr = DMDAVecRestoreArray(appctx.da,appctx.SEMop.mass,&wrk_ptr2);CHKERRQ(ierr);
207c4762a1bSJed Brown 
208c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
209c4762a1bSJed Brown    Create matrix data structure; set matrix evaluation routine.
210c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
211c4762a1bSJed Brown   ierr = DMSetMatrixPreallocateOnly(appctx.da, PETSC_TRUE);CHKERRQ(ierr);
212c4762a1bSJed Brown   ierr = DMCreateMatrix(appctx.da,&appctx.SEMop.stiff);CHKERRQ(ierr);
213c4762a1bSJed Brown   ierr = DMCreateMatrix(appctx.da,&appctx.SEMop.advec);CHKERRQ(ierr);
214c4762a1bSJed Brown 
215c4762a1bSJed Brown   /*
216c4762a1bSJed Brown    For linear problems with a time-dependent f(u,t) in the equation
217c4762a1bSJed Brown    u_t = f(u,t), the user provides the discretized right-hand-side
218c4762a1bSJed Brown    as a time-dependent matrix.
219c4762a1bSJed Brown    */
220c4762a1bSJed Brown   ierr = RHSLaplacian(appctx.ts,0.0,u,appctx.SEMop.stiff,appctx.SEMop.stiff,&appctx);CHKERRQ(ierr);
221c4762a1bSJed Brown   ierr = RHSAdvection(appctx.ts,0.0,u,appctx.SEMop.advec,appctx.SEMop.advec,&appctx);CHKERRQ(ierr);
222c4762a1bSJed Brown   ierr = MatAXPY(appctx.SEMop.stiff,-1.0,appctx.SEMop.advec,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
223c4762a1bSJed Brown   ierr = MatDuplicate(appctx.SEMop.stiff,MAT_COPY_VALUES,&appctx.SEMop.keptstiff);CHKERRQ(ierr);
224c4762a1bSJed Brown 
225c4762a1bSJed Brown   /* attach the null space to the matrix, this probably is not needed but does no harm */
226c4762a1bSJed Brown   ierr = MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,NULL,&nsp);CHKERRQ(ierr);
227c4762a1bSJed Brown   ierr = MatSetNullSpace(appctx.SEMop.stiff,nsp);CHKERRQ(ierr);
228c4762a1bSJed Brown   ierr = MatNullSpaceTest(nsp,appctx.SEMop.stiff,NULL);CHKERRQ(ierr);
229c4762a1bSJed Brown   ierr = MatNullSpaceDestroy(&nsp);CHKERRQ(ierr);
230c4762a1bSJed Brown 
231c4762a1bSJed Brown   /* Create the TS solver that solves the ODE and its adjoint; set its options */
232c4762a1bSJed Brown   ierr = TSCreate(PETSC_COMM_WORLD,&appctx.ts);CHKERRQ(ierr);
233c4762a1bSJed Brown   ierr = TSSetSolutionFunction(appctx.ts,(PetscErrorCode (*)(TS,PetscReal,Vec, void *))ComputeReference,&appctx);CHKERRQ(ierr);
234c4762a1bSJed Brown   ierr = TSSetProblemType(appctx.ts,TS_LINEAR);CHKERRQ(ierr);
235c4762a1bSJed Brown   ierr = TSSetType(appctx.ts,TSRK);CHKERRQ(ierr);
236c4762a1bSJed Brown   ierr = TSSetDM(appctx.ts,appctx.da);CHKERRQ(ierr);
237c4762a1bSJed Brown   ierr = TSSetTime(appctx.ts,0.0);CHKERRQ(ierr);
238c4762a1bSJed Brown   ierr = TSSetTimeStep(appctx.ts,appctx.initial_dt);CHKERRQ(ierr);
239c4762a1bSJed Brown   ierr = TSSetMaxSteps(appctx.ts,appctx.param.steps);CHKERRQ(ierr);
240c4762a1bSJed Brown   ierr = TSSetMaxTime(appctx.ts,appctx.param.Tend);CHKERRQ(ierr);
241c4762a1bSJed Brown   ierr = TSSetExactFinalTime(appctx.ts,TS_EXACTFINALTIME_MATCHSTEP);CHKERRQ(ierr);
242c4762a1bSJed Brown   ierr = TSSetTolerances(appctx.ts,1e-7,NULL,1e-7,NULL);CHKERRQ(ierr);
243c4762a1bSJed Brown   ierr = TSSetFromOptions(appctx.ts);CHKERRQ(ierr);
244c4762a1bSJed Brown   /* Need to save initial timestep user may have set with -ts_dt so it can be reset for each new TSSolve() */
245c4762a1bSJed Brown   ierr = TSGetTimeStep(appctx.ts,&appctx.initial_dt);CHKERRQ(ierr);
246c4762a1bSJed Brown   ierr = TSSetRHSFunction(appctx.ts,NULL,TSComputeRHSFunctionLinear,&appctx);CHKERRQ(ierr);
247c4762a1bSJed Brown   ierr = TSSetRHSJacobian(appctx.ts,appctx.SEMop.stiff,appctx.SEMop.stiff,TSComputeRHSJacobianConstant,&appctx);CHKERRQ(ierr);
248c4762a1bSJed Brown   /*  ierr = TSSetRHSFunction(appctx.ts,NULL,RHSFunction,&appctx);CHKERRQ(ierr);
249c4762a1bSJed Brown       ierr = TSSetRHSJacobian(appctx.ts,appctx.SEMop.stiff,appctx.SEMop.stiff,RHSJacobian,&appctx);CHKERRQ(ierr); */
250c4762a1bSJed Brown 
251c4762a1bSJed Brown   /* Set random initial conditions as initial guess, compute analytic reference solution and analytic (true) initial conditions */
252c4762a1bSJed Brown   ierr = ComputeSolutionCoefficients(&appctx);CHKERRQ(ierr);
253c4762a1bSJed Brown   ierr = InitialConditions(appctx.dat.ic,&appctx);CHKERRQ(ierr);
254c4762a1bSJed Brown   ierr = ComputeReference(appctx.ts,appctx.param.Tend,appctx.dat.reference,&appctx);CHKERRQ(ierr);
255c4762a1bSJed Brown   ierr = ComputeReference(appctx.ts,0.0,appctx.dat.true_solution,&appctx);CHKERRQ(ierr);
256c4762a1bSJed Brown 
257f32d6360SSatish Balay   /* Set up to save trajectory before TSSetFromOptions() so that TSTrajectory options can be captured */
258f32d6360SSatish Balay   ierr = TSSetSaveTrajectory(appctx.ts);CHKERRQ(ierr);
259f32d6360SSatish Balay   ierr = TSSetFromOptions(appctx.ts);CHKERRQ(ierr);
260f32d6360SSatish Balay 
261c4762a1bSJed Brown   /* Create TAO solver and set desired solution method  */
262c4762a1bSJed Brown   ierr = TaoCreate(PETSC_COMM_WORLD,&tao);CHKERRQ(ierr);
263c4762a1bSJed Brown   ierr = TaoSetMonitor(tao,MonitorError,&appctx,MonitorDestroy);CHKERRQ(ierr);
264c4762a1bSJed Brown   ierr = TaoSetType(tao,TAOBQNLS);CHKERRQ(ierr);
265c4762a1bSJed Brown   ierr = TaoSetInitialVector(tao,appctx.dat.ic);CHKERRQ(ierr);
266c4762a1bSJed Brown   /* Set routine for function and gradient evaluation  */
267c4762a1bSJed Brown   ierr = TaoSetObjectiveAndGradientRoutine(tao,FormFunctionGradient,(void *)&appctx);CHKERRQ(ierr);
268c4762a1bSJed Brown   /* Check for any TAO command line options  */
269c4762a1bSJed Brown   ierr = TaoSetTolerances(tao,1e-8,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
270c4762a1bSJed Brown   ierr = TaoSetFromOptions(tao);CHKERRQ(ierr);
271c4762a1bSJed Brown   ierr = TaoSolve(tao);CHKERRQ(ierr);
272c4762a1bSJed Brown 
273c4762a1bSJed Brown   ierr = TaoDestroy(&tao);CHKERRQ(ierr);
274c4762a1bSJed Brown   ierr = PetscFree(appctx.solutioncoefficients);CHKERRQ(ierr);
275c4762a1bSJed Brown   ierr = MatDestroy(&appctx.SEMop.advec);CHKERRQ(ierr);
276c4762a1bSJed Brown   ierr = MatDestroy(&appctx.SEMop.stiff);CHKERRQ(ierr);
277c4762a1bSJed Brown   ierr = MatDestroy(&appctx.SEMop.keptstiff);CHKERRQ(ierr);
278c4762a1bSJed Brown   ierr = VecDestroy(&u);CHKERRQ(ierr);
279c4762a1bSJed Brown   ierr = VecDestroy(&appctx.dat.ic);CHKERRQ(ierr);
280c4762a1bSJed Brown   ierr = VecDestroy(&appctx.dat.joe);CHKERRQ(ierr);
281c4762a1bSJed Brown   ierr = VecDestroy(&appctx.dat.true_solution);CHKERRQ(ierr);
282c4762a1bSJed Brown   ierr = VecDestroy(&appctx.dat.reference);CHKERRQ(ierr);
283c4762a1bSJed Brown   ierr = VecDestroy(&appctx.SEMop.grid);CHKERRQ(ierr);
284c4762a1bSJed Brown   ierr = VecDestroy(&appctx.SEMop.mass);CHKERRQ(ierr);
285c4762a1bSJed Brown   ierr = VecDestroy(&appctx.dat.curr_sol);CHKERRQ(ierr);
286c4762a1bSJed Brown   ierr = PetscFree2(appctx.SEMop.gll.nodes,appctx.SEMop.gll.weights);CHKERRQ(ierr);
287c4762a1bSJed Brown   ierr = DMDestroy(&appctx.da);CHKERRQ(ierr);
288c4762a1bSJed Brown   ierr = TSDestroy(&appctx.ts);CHKERRQ(ierr);
289c4762a1bSJed Brown 
290c4762a1bSJed Brown   /*
291c4762a1bSJed Brown      Always call PetscFinalize() before exiting a program.  This routine
292c4762a1bSJed Brown        - finalizes the PETSc libraries as well as MPI
293c4762a1bSJed Brown        - provides summary and diagnostic information if certain runtime
294c4762a1bSJed Brown          options are chosen (e.g., -log_summary).
295c4762a1bSJed Brown   */
296c4762a1bSJed Brown     ierr = PetscFinalize();
297c4762a1bSJed Brown     return ierr;
298c4762a1bSJed Brown }
299c4762a1bSJed Brown 
300c4762a1bSJed Brown /*
301c4762a1bSJed Brown     Computes the coefficients for the analytic solution to the PDE
302c4762a1bSJed Brown */
303c4762a1bSJed Brown PetscErrorCode ComputeSolutionCoefficients(AppCtx *appctx)
304c4762a1bSJed Brown {
305c4762a1bSJed Brown   PetscErrorCode    ierr;
306c4762a1bSJed Brown   PetscRandom       rand;
307c4762a1bSJed Brown   PetscInt          i;
308c4762a1bSJed Brown 
309c4762a1bSJed Brown   PetscFunctionBegin;
310c4762a1bSJed Brown   ierr = PetscMalloc1(appctx->ncoeff,&appctx->solutioncoefficients);CHKERRQ(ierr);
311c4762a1bSJed Brown   ierr = PetscRandomCreate(PETSC_COMM_WORLD,&rand);CHKERRQ(ierr);
312c4762a1bSJed Brown   ierr = PetscRandomSetInterval(rand,.9,1.0);CHKERRQ(ierr);
313c4762a1bSJed Brown   for (i=0; i<appctx->ncoeff; i++) {
314c4762a1bSJed Brown     ierr = PetscRandomGetValue(rand,&appctx->solutioncoefficients[i]);CHKERRQ(ierr);
315c4762a1bSJed Brown   }
316c4762a1bSJed Brown   ierr = PetscRandomDestroy(&rand);CHKERRQ(ierr);
317c4762a1bSJed Brown   PetscFunctionReturn(0);
318c4762a1bSJed Brown }
319c4762a1bSJed Brown 
320c4762a1bSJed Brown /* --------------------------------------------------------------------- */
321c4762a1bSJed Brown /*
322c4762a1bSJed Brown    InitialConditions - Computes the (random) initial conditions for the Tao optimization solve (these are also initial conditions for the first TSSolve()
323c4762a1bSJed Brown 
324c4762a1bSJed Brown    Input Parameter:
325c4762a1bSJed Brown    u - uninitialized solution vector (global)
326c4762a1bSJed Brown    appctx - user-defined application context
327c4762a1bSJed Brown 
328c4762a1bSJed Brown    Output Parameter:
329c4762a1bSJed Brown    u - vector with solution at initial time (global)
330c4762a1bSJed Brown */
331c4762a1bSJed Brown PetscErrorCode InitialConditions(Vec u,AppCtx *appctx)
332c4762a1bSJed Brown {
333c4762a1bSJed Brown   PetscScalar       *s;
334c4762a1bSJed Brown   const PetscScalar *xg;
335c4762a1bSJed Brown   PetscErrorCode    ierr;
336c4762a1bSJed Brown   PetscInt          i,j,lenglob;
337c4762a1bSJed Brown   PetscReal         sum,val;
338c4762a1bSJed Brown   PetscRandom       rand;
339c4762a1bSJed Brown 
340c4762a1bSJed Brown   PetscFunctionBegin;
341c4762a1bSJed Brown   ierr = PetscRandomCreate(PETSC_COMM_WORLD,&rand);CHKERRQ(ierr);
342c4762a1bSJed Brown   ierr = PetscRandomSetInterval(rand,.9,1.0);CHKERRQ(ierr);
343c4762a1bSJed Brown   ierr = DMDAVecGetArray(appctx->da,u,&s);CHKERRQ(ierr);
344c4762a1bSJed Brown   ierr = DMDAVecGetArrayRead(appctx->da,appctx->SEMop.grid,(void*)&xg);CHKERRQ(ierr);
345c4762a1bSJed Brown   lenglob  = appctx->param.E*(appctx->param.N-1);
346c4762a1bSJed Brown   for (i=0; i<lenglob; i++) {
347c4762a1bSJed Brown     s[i]= 0;
348c4762a1bSJed Brown     for (j=0; j<appctx->ncoeff; j++) {
349c4762a1bSJed Brown       ierr =  PetscRandomGetValue(rand,&val);CHKERRQ(ierr);
350c4762a1bSJed Brown       s[i] += val*PetscSinScalar(2*(j+1)*PETSC_PI*xg[i]);
351c4762a1bSJed Brown     }
352c4762a1bSJed Brown   }
353c4762a1bSJed Brown   ierr = PetscRandomDestroy(&rand);CHKERRQ(ierr);
354c4762a1bSJed Brown   ierr = DMDAVecRestoreArray(appctx->da,u,&s);CHKERRQ(ierr);
355c4762a1bSJed Brown   ierr = DMDAVecRestoreArrayRead(appctx->da,appctx->SEMop.grid,(void*)&xg);CHKERRQ(ierr);
356c4762a1bSJed Brown   /* make sure initial conditions do not contain the constant functions, since with periodic boundary conditions the constant functions introduce a null space */
357c4762a1bSJed Brown   ierr = VecSum(u,&sum);CHKERRQ(ierr);
358c4762a1bSJed Brown   ierr = VecShift(u,-sum/lenglob);CHKERRQ(ierr);
359c4762a1bSJed Brown   PetscFunctionReturn(0);
360c4762a1bSJed Brown }
361c4762a1bSJed Brown 
362c4762a1bSJed Brown /*
363c4762a1bSJed Brown    TrueSolution() computes the true solution for the Tao optimization solve which means they are the initial conditions for the objective function.
364c4762a1bSJed Brown 
365*a5b23f4aSJose E. Roman              InitialConditions() computes the initial conditions for the beginning of the Tao iterations
366c4762a1bSJed Brown 
367c4762a1bSJed Brown    Input Parameter:
368c4762a1bSJed Brown    u - uninitialized solution vector (global)
369c4762a1bSJed Brown    appctx - user-defined application context
370c4762a1bSJed Brown 
371c4762a1bSJed Brown    Output Parameter:
372c4762a1bSJed Brown    u - vector with solution at initial time (global)
373c4762a1bSJed Brown */
374c4762a1bSJed Brown PetscErrorCode TrueSolution(Vec u,AppCtx *appctx)
375c4762a1bSJed Brown {
376c4762a1bSJed Brown   PetscScalar       *s;
377c4762a1bSJed Brown   const PetscScalar *xg;
378c4762a1bSJed Brown   PetscErrorCode    ierr;
379c4762a1bSJed Brown   PetscInt          i,j,lenglob;
380c4762a1bSJed Brown   PetscReal         sum;
381c4762a1bSJed Brown 
382c4762a1bSJed Brown   PetscFunctionBegin;
383c4762a1bSJed Brown   ierr = DMDAVecGetArray(appctx->da,u,&s);CHKERRQ(ierr);
384c4762a1bSJed Brown   ierr = DMDAVecGetArrayRead(appctx->da,appctx->SEMop.grid,(void*)&xg);CHKERRQ(ierr);
385c4762a1bSJed Brown   lenglob  = appctx->param.E*(appctx->param.N-1);
386c4762a1bSJed Brown   for (i=0; i<lenglob; i++) {
387c4762a1bSJed Brown     s[i]= 0;
388c4762a1bSJed Brown     for (j=0; j<appctx->ncoeff; j++) {
389c4762a1bSJed Brown       s[i] += appctx->solutioncoefficients[j]*PetscSinScalar(2*(j+1)*PETSC_PI*xg[i]);
390c4762a1bSJed Brown     }
391c4762a1bSJed Brown   }
392c4762a1bSJed Brown   ierr = DMDAVecRestoreArray(appctx->da,u,&s);CHKERRQ(ierr);
393c4762a1bSJed Brown   ierr = DMDAVecRestoreArrayRead(appctx->da,appctx->SEMop.grid,(void*)&xg);CHKERRQ(ierr);
394c4762a1bSJed Brown   /* make sure initial conditions do not contain the constant functions, since with periodic boundary conditions the constant functions introduce a null space */
395c4762a1bSJed Brown   ierr = VecSum(u,&sum);CHKERRQ(ierr);
396c4762a1bSJed Brown   ierr = VecShift(u,-sum/lenglob);CHKERRQ(ierr);
397c4762a1bSJed Brown   PetscFunctionReturn(0);
398c4762a1bSJed Brown }
399c4762a1bSJed Brown /* --------------------------------------------------------------------- */
400c4762a1bSJed Brown /*
401c4762a1bSJed Brown    Sets the desired profile for the final end time
402c4762a1bSJed Brown 
403c4762a1bSJed Brown    Input Parameters:
404c4762a1bSJed Brown    t - final time
405c4762a1bSJed Brown    obj - vector storing the desired profile
406c4762a1bSJed Brown    appctx - user-defined application context
407c4762a1bSJed Brown 
408c4762a1bSJed Brown */
409c4762a1bSJed Brown PetscErrorCode ComputeReference(TS ts,PetscReal t,Vec obj,AppCtx *appctx)
410c4762a1bSJed Brown {
411c4762a1bSJed Brown   PetscScalar       *s,tc;
412c4762a1bSJed Brown   const PetscScalar *xg;
413c4762a1bSJed Brown   PetscErrorCode    ierr;
414c4762a1bSJed Brown   PetscInt          i, j,lenglob;
415c4762a1bSJed Brown 
416c4762a1bSJed Brown   PetscFunctionBegin;
417c4762a1bSJed Brown   ierr = DMDAVecGetArray(appctx->da,obj,&s);CHKERRQ(ierr);
418c4762a1bSJed Brown   ierr = DMDAVecGetArrayRead(appctx->da,appctx->SEMop.grid,(void*)&xg);CHKERRQ(ierr);
419c4762a1bSJed Brown   lenglob  = appctx->param.E*(appctx->param.N-1);
420c4762a1bSJed Brown   for (i=0; i<lenglob; i++) {
421c4762a1bSJed Brown     s[i]= 0;
422c4762a1bSJed Brown     for (j=0; j<appctx->ncoeff; j++) {
423c4762a1bSJed Brown       tc    = -appctx->param.mu*(j+1)*(j+1)*4.0*PETSC_PI*PETSC_PI*t;
424c4762a1bSJed Brown       s[i] += appctx->solutioncoefficients[j]*PetscSinScalar(2*(j+1)*PETSC_PI*(xg[i] + appctx->param.a*t))*PetscExpReal(tc);
425c4762a1bSJed Brown     }
426c4762a1bSJed Brown   }
427c4762a1bSJed Brown   ierr = DMDAVecRestoreArray(appctx->da,obj,&s);CHKERRQ(ierr);
428c4762a1bSJed Brown   ierr = DMDAVecRestoreArrayRead(appctx->da,appctx->SEMop.grid,(void*)&xg);CHKERRQ(ierr);
429c4762a1bSJed Brown   PetscFunctionReturn(0);
430c4762a1bSJed Brown }
431c4762a1bSJed Brown 
432c4762a1bSJed Brown PetscErrorCode RHSFunction(TS ts,PetscReal t,Vec globalin,Vec globalout,void *ctx)
433c4762a1bSJed Brown {
434c4762a1bSJed Brown   PetscErrorCode ierr;
435c4762a1bSJed Brown   AppCtx          *appctx = (AppCtx*)ctx;
436c4762a1bSJed Brown 
437c4762a1bSJed Brown   PetscFunctionBegin;
438c4762a1bSJed Brown   ierr = MatMult(appctx->SEMop.keptstiff,globalin,globalout);CHKERRQ(ierr);
439c4762a1bSJed Brown   PetscFunctionReturn(0);
440c4762a1bSJed Brown }
441c4762a1bSJed Brown 
442c4762a1bSJed Brown PetscErrorCode RHSJacobian(TS ts,PetscReal t,Vec globalin,Mat A, Mat B,void *ctx)
443c4762a1bSJed Brown {
444c4762a1bSJed Brown   PetscErrorCode ierr;
445c4762a1bSJed Brown   AppCtx         *appctx = (AppCtx*)ctx;
446c4762a1bSJed Brown 
447c4762a1bSJed Brown   PetscFunctionBegin;
448c4762a1bSJed Brown   ierr = MatCopy(appctx->SEMop.keptstiff,A,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
449c4762a1bSJed Brown   PetscFunctionReturn(0);
450c4762a1bSJed Brown }
451c4762a1bSJed Brown 
452c4762a1bSJed Brown /* --------------------------------------------------------------------- */
453c4762a1bSJed Brown 
454c4762a1bSJed Brown /*
455c4762a1bSJed Brown    RHSLaplacian -   matrix for diffusion
456c4762a1bSJed Brown 
457c4762a1bSJed Brown    Input Parameters:
458c4762a1bSJed Brown    ts - the TS context
459c4762a1bSJed Brown    t - current time  (ignored)
460c4762a1bSJed Brown    X - current solution (ignored)
461c4762a1bSJed Brown    dummy - optional user-defined context, as set by TSetRHSJacobian()
462c4762a1bSJed Brown 
463c4762a1bSJed Brown    Output Parameters:
464c4762a1bSJed Brown    AA - Jacobian matrix
465c4762a1bSJed Brown    BB - optionally different matrix from which the preconditioner is built
466c4762a1bSJed Brown    str - flag indicating matrix structure
467c4762a1bSJed Brown 
468c4762a1bSJed Brown    Scales by the inverse of the mass matrix (perhaps that should be pulled out)
469c4762a1bSJed Brown 
470c4762a1bSJed Brown */
471c4762a1bSJed Brown PetscErrorCode RHSLaplacian(TS ts,PetscReal t,Vec X,Mat A,Mat BB,void *ctx)
472c4762a1bSJed Brown {
473c4762a1bSJed Brown   PetscReal      **temp;
474c4762a1bSJed Brown   PetscReal      vv;
475c4762a1bSJed Brown   AppCtx         *appctx = (AppCtx*)ctx;     /* user-defined application context */
476c4762a1bSJed Brown   PetscErrorCode ierr;
477c4762a1bSJed Brown   PetscInt       i,xs,xn,l,j;
478c4762a1bSJed Brown   PetscInt       *rowsDM;
479c4762a1bSJed Brown 
480c4762a1bSJed Brown   PetscFunctionBegin;
481c4762a1bSJed Brown   /*
482c4762a1bSJed Brown    Creates the element stiffness matrix for the given gll
483c4762a1bSJed Brown    */
484c4762a1bSJed Brown   ierr = PetscGaussLobattoLegendreElementLaplacianCreate(appctx->SEMop.gll.n,appctx->SEMop.gll.nodes,appctx->SEMop.gll.weights,&temp);CHKERRQ(ierr);
485c4762a1bSJed Brown 
486c4762a1bSJed Brown   /* scale by the size of the element */
487c4762a1bSJed Brown   for (i=0; i<appctx->param.N; i++) {
488c4762a1bSJed Brown     vv=-appctx->param.mu*2.0/appctx->param.Le;
489c4762a1bSJed Brown     for (j=0; j<appctx->param.N; j++) temp[i][j]=temp[i][j]*vv;
490c4762a1bSJed Brown   }
491c4762a1bSJed Brown 
492c4762a1bSJed Brown   ierr = MatSetOption(A,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr);
493c4762a1bSJed Brown   ierr = DMDAGetCorners(appctx->da,&xs,NULL,NULL,&xn,NULL,NULL);CHKERRQ(ierr);
494c4762a1bSJed Brown 
495c4762a1bSJed Brown   if (appctx->param.N-1 < 1) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_OUTOFRANGE,"Polynomial order must be at least 2");
496c4762a1bSJed Brown   xs   = xs/(appctx->param.N-1);
497c4762a1bSJed Brown   xn   = xn/(appctx->param.N-1);
498c4762a1bSJed Brown 
499c4762a1bSJed Brown   ierr = PetscMalloc1(appctx->param.N,&rowsDM);CHKERRQ(ierr);
500c4762a1bSJed Brown   /*
501c4762a1bSJed Brown    loop over local elements
502c4762a1bSJed Brown    */
503c4762a1bSJed Brown   for (j=xs; j<xs+xn; j++) {
504c4762a1bSJed Brown     for (l=0; l<appctx->param.N; l++) {
505c4762a1bSJed Brown       rowsDM[l] = 1+(j-xs)*(appctx->param.N-1)+l;
506c4762a1bSJed Brown     }
507c4762a1bSJed Brown     ierr = MatSetValuesLocal(A,appctx->param.N,rowsDM,appctx->param.N,rowsDM,&temp[0][0],ADD_VALUES);CHKERRQ(ierr);
508c4762a1bSJed Brown   }
509c4762a1bSJed Brown   ierr = PetscFree(rowsDM);CHKERRQ(ierr);
510c4762a1bSJed Brown   ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
511c4762a1bSJed Brown   ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
512c4762a1bSJed Brown   ierr = VecReciprocal(appctx->SEMop.mass);CHKERRQ(ierr);
513c4762a1bSJed Brown   ierr = MatDiagonalScale(A,appctx->SEMop.mass,0);CHKERRQ(ierr);
514c4762a1bSJed Brown   ierr = VecReciprocal(appctx->SEMop.mass);CHKERRQ(ierr);
515c4762a1bSJed Brown 
516c4762a1bSJed Brown   ierr = PetscGaussLobattoLegendreElementLaplacianDestroy(appctx->SEMop.gll.n,appctx->SEMop.gll.nodes,appctx->SEMop.gll.weights,&temp);CHKERRQ(ierr);
517c4762a1bSJed Brown   PetscFunctionReturn(0);
518c4762a1bSJed Brown }
519c4762a1bSJed Brown 
520c4762a1bSJed Brown /*
521c4762a1bSJed Brown     Almost identical to Laplacian
522c4762a1bSJed Brown 
523c4762a1bSJed Brown     Note that the element matrix is NOT scaled by the size of element like the Laplacian term.
524c4762a1bSJed Brown  */
525c4762a1bSJed Brown PetscErrorCode RHSAdvection(TS ts,PetscReal t,Vec X,Mat A,Mat BB,void *ctx)
526c4762a1bSJed Brown {
527c4762a1bSJed Brown   PetscReal      **temp;
528c4762a1bSJed Brown   PetscReal      vv;
529c4762a1bSJed Brown   AppCtx         *appctx = (AppCtx*)ctx;     /* user-defined application context */
530c4762a1bSJed Brown   PetscErrorCode ierr;
531c4762a1bSJed Brown   PetscInt       i,xs,xn,l,j;
532c4762a1bSJed Brown   PetscInt       *rowsDM;
533c4762a1bSJed Brown 
534c4762a1bSJed Brown   PetscFunctionBegin;
535c4762a1bSJed Brown   /*
536c4762a1bSJed Brown    Creates the element stiffness matrix for the given gll
537c4762a1bSJed Brown    */
538c4762a1bSJed Brown   ierr = PetscGaussLobattoLegendreElementAdvectionCreate(appctx->SEMop.gll.n,appctx->SEMop.gll.nodes,appctx->SEMop.gll.weights,&temp);CHKERRQ(ierr);
539c4762a1bSJed Brown 
540c4762a1bSJed Brown   /* scale by the size of the element */
541c4762a1bSJed Brown   for (i=0; i<appctx->param.N; i++) {
542c4762a1bSJed Brown     vv = -appctx->param.a;
543c4762a1bSJed Brown     for (j=0; j<appctx->param.N; j++) temp[i][j]=temp[i][j]*vv;
544c4762a1bSJed Brown   }
545c4762a1bSJed Brown 
546c4762a1bSJed Brown   ierr = MatSetOption(A,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr);
547c4762a1bSJed Brown   ierr = DMDAGetCorners(appctx->da,&xs,NULL,NULL,&xn,NULL,NULL);CHKERRQ(ierr);
548c4762a1bSJed Brown 
549c4762a1bSJed Brown   if (appctx->param.N-1 < 1) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_ARG_OUTOFRANGE,"Polynomial order must be at least 2");
550c4762a1bSJed Brown   xs   = xs/(appctx->param.N-1);
551c4762a1bSJed Brown   xn   = xn/(appctx->param.N-1);
552c4762a1bSJed Brown 
553c4762a1bSJed Brown   ierr = PetscMalloc1(appctx->param.N,&rowsDM);CHKERRQ(ierr);
554c4762a1bSJed Brown   /*
555c4762a1bSJed Brown    loop over local elements
556c4762a1bSJed Brown    */
557c4762a1bSJed Brown   for (j=xs; j<xs+xn; j++) {
558c4762a1bSJed Brown     for (l=0; l<appctx->param.N; l++) {
559c4762a1bSJed Brown       rowsDM[l] = 1+(j-xs)*(appctx->param.N-1)+l;
560c4762a1bSJed Brown     }
561c4762a1bSJed Brown     ierr = MatSetValuesLocal(A,appctx->param.N,rowsDM,appctx->param.N,rowsDM,&temp[0][0],ADD_VALUES);CHKERRQ(ierr);
562c4762a1bSJed Brown   }
563c4762a1bSJed Brown   ierr = PetscFree(rowsDM);CHKERRQ(ierr);
564c4762a1bSJed Brown   ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
565c4762a1bSJed Brown   ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
566c4762a1bSJed Brown   ierr = VecReciprocal(appctx->SEMop.mass);CHKERRQ(ierr);
567c4762a1bSJed Brown   ierr = MatDiagonalScale(A,appctx->SEMop.mass,0);CHKERRQ(ierr);
568c4762a1bSJed Brown   ierr = VecReciprocal(appctx->SEMop.mass);CHKERRQ(ierr);
569c4762a1bSJed Brown 
570c4762a1bSJed Brown   ierr = PetscGaussLobattoLegendreElementAdvectionDestroy(appctx->SEMop.gll.n,appctx->SEMop.gll.nodes,appctx->SEMop.gll.weights,&temp);CHKERRQ(ierr);
571c4762a1bSJed Brown   PetscFunctionReturn(0);
572c4762a1bSJed Brown }
573c4762a1bSJed Brown 
574c4762a1bSJed Brown /* ------------------------------------------------------------------ */
575c4762a1bSJed Brown /*
576c4762a1bSJed Brown    FormFunctionGradient - Evaluates the function and corresponding gradient.
577c4762a1bSJed Brown 
578c4762a1bSJed Brown    Input Parameters:
579c4762a1bSJed Brown    tao - the Tao context
580c4762a1bSJed Brown    ic   - the input vector
581c4762a1bSJed Brown    ctx - optional user-defined context, as set when calling TaoSetObjectiveAndGradientRoutine()
582c4762a1bSJed Brown 
583c4762a1bSJed Brown    Output Parameters:
584c4762a1bSJed Brown    f   - the newly evaluated function
585c4762a1bSJed Brown    G   - the newly evaluated gradient
586c4762a1bSJed Brown 
587c4762a1bSJed Brown    Notes:
588c4762a1bSJed Brown 
589c4762a1bSJed Brown           The forward equation is
590c4762a1bSJed Brown               M u_t = F(U)
591c4762a1bSJed Brown           which is converted to
592c4762a1bSJed Brown                 u_t = M^{-1} F(u)
593c4762a1bSJed Brown           in the user code since TS has no direct way of providing a mass matrix. The Jacobian of this is
594c4762a1bSJed Brown                  M^{-1} J
595c4762a1bSJed Brown           where J is the Jacobian of F. Now the adjoint equation is
596c4762a1bSJed Brown                 M v_t = J^T v
597c4762a1bSJed Brown           but TSAdjoint does not solve this since it can only solve the transposed system for the
598c4762a1bSJed Brown           Jacobian the user provided. Hence TSAdjoint solves
599c4762a1bSJed Brown                  w_t = J^T M^{-1} w  (where w = M v)
600*a5b23f4aSJose E. Roman           since there is no way to indicate the mass matrix as a separate entity to TS. Thus one
601c4762a1bSJed Brown           must be careful in initializing the "adjoint equation" and using the result. This is
602c4762a1bSJed Brown           why
603c4762a1bSJed Brown               G = -2 M(u(T) - u_d)
604c4762a1bSJed Brown           below (instead of -2(u(T) - u_d)
605c4762a1bSJed Brown 
606c4762a1bSJed Brown */
607c4762a1bSJed Brown PetscErrorCode FormFunctionGradient(Tao tao,Vec ic,PetscReal *f,Vec G,void *ctx)
608c4762a1bSJed Brown {
609c4762a1bSJed Brown   AppCtx           *appctx = (AppCtx*)ctx;     /* user-defined application context */
610c4762a1bSJed Brown   PetscErrorCode    ierr;
611c4762a1bSJed Brown   Vec               temp;
612c4762a1bSJed Brown 
613c4762a1bSJed Brown   PetscFunctionBegin;
614c4762a1bSJed Brown   ierr = TSSetTime(appctx->ts,0.0);CHKERRQ(ierr);
615c4762a1bSJed Brown   ierr = TSSetStepNumber(appctx->ts,0);CHKERRQ(ierr);
616c4762a1bSJed Brown   ierr = TSSetTimeStep(appctx->ts,appctx->initial_dt);CHKERRQ(ierr);
617c4762a1bSJed Brown   ierr = VecCopy(ic,appctx->dat.curr_sol);CHKERRQ(ierr);
618c4762a1bSJed Brown 
619c4762a1bSJed Brown   ierr = TSSolve(appctx->ts,appctx->dat.curr_sol);CHKERRQ(ierr);
620c4762a1bSJed Brown   ierr = VecCopy(appctx->dat.curr_sol,appctx->dat.joe);CHKERRQ(ierr);
621c4762a1bSJed Brown 
622c4762a1bSJed Brown   /*     Compute the difference between the current ODE solution and target ODE solution */
623c4762a1bSJed Brown   ierr = VecWAXPY(G,-1.0,appctx->dat.curr_sol,appctx->dat.reference);CHKERRQ(ierr);
624c4762a1bSJed Brown 
625c4762a1bSJed Brown   /*     Compute the objective/cost function   */
626c4762a1bSJed Brown   ierr = VecDuplicate(G,&temp);CHKERRQ(ierr);
627c4762a1bSJed Brown   ierr = VecPointwiseMult(temp,G,G);CHKERRQ(ierr);
628c4762a1bSJed Brown   ierr = VecDot(temp,appctx->SEMop.mass,f);CHKERRQ(ierr);
629c4762a1bSJed Brown   ierr = VecDestroy(&temp);CHKERRQ(ierr);
630c4762a1bSJed Brown 
631c4762a1bSJed Brown   /*     Compute initial conditions for the adjoint integration. See Notes above  */
632c4762a1bSJed Brown   ierr = VecScale(G, -2.0);CHKERRQ(ierr);
633c4762a1bSJed Brown   ierr = VecPointwiseMult(G,G,appctx->SEMop.mass);CHKERRQ(ierr);
634c4762a1bSJed Brown   ierr = TSSetCostGradients(appctx->ts,1,&G,NULL);CHKERRQ(ierr);
635c4762a1bSJed Brown 
636c4762a1bSJed Brown   ierr = TSAdjointSolve(appctx->ts);CHKERRQ(ierr);
637c4762a1bSJed Brown   /* ierr = VecPointwiseDivide(G,G,appctx->SEMop.mass);CHKERRQ(ierr);*/
638c4762a1bSJed Brown   PetscFunctionReturn(0);
639c4762a1bSJed Brown }
640c4762a1bSJed Brown 
641c4762a1bSJed Brown PetscErrorCode MonitorError(Tao tao,void *ctx)
642c4762a1bSJed Brown {
643c4762a1bSJed Brown   AppCtx         *appctx = (AppCtx*)ctx;
644c4762a1bSJed Brown   Vec            temp,grad;
645c4762a1bSJed Brown   PetscReal      nrm;
646c4762a1bSJed Brown   PetscErrorCode ierr;
647c4762a1bSJed Brown   PetscInt       its;
648c4762a1bSJed Brown   PetscReal      fct,gnorm;
649c4762a1bSJed Brown 
650c4762a1bSJed Brown   PetscFunctionBegin;
651c4762a1bSJed Brown   ierr  = VecDuplicate(appctx->dat.ic,&temp);CHKERRQ(ierr);
652c4762a1bSJed Brown   ierr  = VecWAXPY(temp,-1.0,appctx->dat.ic,appctx->dat.true_solution);CHKERRQ(ierr);
653c4762a1bSJed Brown   ierr  = VecPointwiseMult(temp,temp,temp);CHKERRQ(ierr);
654c4762a1bSJed Brown   ierr  = VecDot(temp,appctx->SEMop.mass,&nrm);CHKERRQ(ierr);
655c4762a1bSJed Brown   nrm   = PetscSqrtReal(nrm);
656c4762a1bSJed Brown   ierr  = TaoGetGradientVector(tao,&grad);CHKERRQ(ierr);
657c4762a1bSJed Brown   ierr  = VecPointwiseMult(temp,temp,temp);CHKERRQ(ierr);
658c4762a1bSJed Brown   ierr  = VecDot(temp,appctx->SEMop.mass,&gnorm);CHKERRQ(ierr);
659c4762a1bSJed Brown   gnorm = PetscSqrtReal(gnorm);
660c4762a1bSJed Brown   ierr  = VecDestroy(&temp);CHKERRQ(ierr);
661c4762a1bSJed Brown   ierr  = TaoGetIterationNumber(tao,&its);CHKERRQ(ierr);
662c4762a1bSJed Brown   ierr  = TaoGetObjective(tao,&fct);CHKERRQ(ierr);
663c4762a1bSJed Brown   if (!its) {
664c4762a1bSJed Brown     ierr = PetscPrintf(PETSC_COMM_WORLD,"%% Iteration Error Objective Gradient-norm\n");CHKERRQ(ierr);
665c4762a1bSJed Brown     ierr = PetscPrintf(PETSC_COMM_WORLD,"history = [\n");CHKERRQ(ierr);
666c4762a1bSJed Brown   }
667c4762a1bSJed Brown   ierr = PetscPrintf(PETSC_COMM_WORLD,"%3D %g %g %g\n",its,(double)nrm,(double)fct,(double)gnorm);CHKERRQ(ierr);
668c4762a1bSJed Brown   PetscFunctionReturn(0);
669c4762a1bSJed Brown }
670c4762a1bSJed Brown 
671c4762a1bSJed Brown PetscErrorCode MonitorDestroy(void **ctx)
672c4762a1bSJed Brown {
673c4762a1bSJed Brown   PetscErrorCode ierr;
674c4762a1bSJed Brown 
675c4762a1bSJed Brown   PetscFunctionBegin;
676c4762a1bSJed Brown   ierr = PetscPrintf(PETSC_COMM_WORLD,"];\n");CHKERRQ(ierr);
677c4762a1bSJed Brown   PetscFunctionReturn(0);
678c4762a1bSJed Brown }
679c4762a1bSJed Brown 
680c4762a1bSJed Brown /*TEST
681c4762a1bSJed Brown 
682c4762a1bSJed Brown    build:
683c4762a1bSJed Brown      requires: !complex
684c4762a1bSJed Brown 
685c4762a1bSJed Brown    test:
686c4762a1bSJed Brown      requires: !single
687c4762a1bSJed Brown      args:  -ts_adapt_dt_max 3.e-3 -E 10 -N 8 -ncoeff 5 -tao_bqnls_mat_lmvm_scale_type none
688c4762a1bSJed Brown 
689c4762a1bSJed Brown    test:
690c4762a1bSJed Brown      suffix: cn
691c4762a1bSJed Brown      requires: !single
692c4762a1bSJed Brown      args:  -ts_type cn -ts_dt .003 -pc_type lu -E 10 -N 8 -ncoeff 5 -tao_bqnls_mat_lmvm_scale_type none
693c4762a1bSJed Brown 
694c4762a1bSJed Brown    test:
695c4762a1bSJed Brown      suffix: 2
696c4762a1bSJed Brown      requires: !single
697c4762a1bSJed Brown      args:  -ts_adapt_dt_max 3.e-3 -E 10 -N 8 -ncoeff 5  -a .1 -tao_bqnls_mat_lmvm_scale_type none
698c4762a1bSJed Brown 
699c4762a1bSJed Brown TEST*/
700