Actual source code: ex22.c
petsc-3.13.6 2020-09-29
2: static const char help[] = "Solves PDE optimization problem using full-space method, interlaces state and adjoint variables.\n\n";
5: #include <petscdm.h>
6: #include <petscdmda.h>
7: #include <petscdmredundant.h>
8: #include <petscdmcomposite.h>
9: #include <petscpf.h>
10: #include <petscsnes.h>
11: #include <petsc/private/dmimpl.h>
13: /*
15: w - design variables (what we change to get an optimal solution)
16: u - state variables (i.e. the PDE solution)
17: lambda - the Lagrange multipliers
19: U = (w [u_0 lambda_0 u_1 lambda_1 .....])
21: fu, fw, flambda contain the gradient of L(w,u,lambda)
23: FU = (fw [fu_0 flambda_0 .....])
25: In this example the PDE is
26: Uxx = 2,
27: u(0) = w(0), thus this is the free parameter
28: u(1) = 0
29: the function we wish to minimize is
30: \integral u^{2}
32: The exact solution for u is given by u(x) = x*x - 1.25*x + .25
34: Use the usual centered finite differences.
36: Note we treat the problem as non-linear though it happens to be linear
38: See ex21.c for the same code, but that does NOT interlaces the u and the lambda
40: The vectors u_lambda and fu_lambda contain the u and the lambda interlaced
41: */
43: typedef struct {
44: PetscViewer u_lambda_viewer;
45: PetscViewer fu_lambda_viewer;
46: } UserCtx;
48: extern PetscErrorCode ComputeFunction(SNES,Vec,Vec,void*);
49: extern PetscErrorCode ComputeJacobian_MF(SNES,Vec,Mat,Mat,void*);
50: extern PetscErrorCode Monitor(SNES,PetscInt,PetscReal,void*);
52: /*
53: Uses full multigrid preconditioner with GMRES (with no preconditioner inside the GMRES) as the
54: smoother on all levels. This is because (1) in the matrix free case no matrix entries are
55: available for doing Jacobi or SOR preconditioning and (2) the explicit matrix case the diagonal
56: entry for the control variable is zero which means default SOR will not work.
58: */
59: char common_options[] = "-ksp_type fgmres\
60: -snes_grid_sequence 2 \
61: -pc_type mg\
62: -mg_levels_pc_type none \
63: -mg_coarse_pc_type none \
64: -pc_mg_type full \
65: -mg_coarse_ksp_type gmres \
66: -mg_levels_ksp_type gmres \
67: -mg_coarse_ksp_max_it 6 \
68: -mg_levels_ksp_max_it 3";
70: char matrix_free_options[] = "-mat_mffd_compute_normu no \
71: -mat_mffd_type wp";
73: extern PetscErrorCode DMCreateMatrix_MF(DM,Mat*);
75: int main(int argc,char **argv)
76: {
78: UserCtx user;
79: DM red,da;
80: SNES snes;
81: DM packer;
82: PetscBool use_monitor = PETSC_FALSE;
84: PetscInitialize(&argc,&argv,NULL,help);if (ierr) return ierr;
85: PetscOptionsSetFromOptions(NULL);
87: /* Hardwire several options; can be changed at command line */
88: PetscOptionsInsertString(NULL,common_options);
89: PetscOptionsInsertString(NULL,matrix_free_options);
90: PetscOptionsInsert(NULL,&argc,&argv,NULL);
91: PetscOptionsGetBool(NULL,NULL,"-use_monitor",&use_monitor,PETSC_IGNORE);
93: /* Create a global vector that includes a single redundant array and two da arrays */
94: DMCompositeCreate(PETSC_COMM_WORLD,&packer);
95: DMRedundantCreate(PETSC_COMM_WORLD,0,1,&red);
96: DMSetOptionsPrefix(red,"red_");
97: DMCompositeAddDM(packer,red);
98: DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,5,2,1,NULL,&da);
99: DMSetOptionsPrefix(red,"da_");
100: DMSetFromOptions(da);
101: DMSetUp(da);
102: DMDASetFieldName(da,0,"u");
103: DMDASetFieldName(da,1,"lambda");
104: DMCompositeAddDM(packer,(DM)da);
105: DMSetApplicationContext(packer,&user);
107: packer->ops->creatematrix = DMCreateMatrix_MF;
109: /* create nonlinear multi-level solver */
110: SNESCreate(PETSC_COMM_WORLD,&snes);
111: SNESSetDM(snes,packer);
112: SNESSetFunction(snes,NULL,ComputeFunction,NULL);
113: SNESSetJacobian(snes,NULL, NULL,ComputeJacobian_MF,NULL);
115: SNESSetFromOptions(snes);
117: if (use_monitor) {
118: /* create graphics windows */
119: PetscViewerDrawOpen(PETSC_COMM_WORLD,0,"u_lambda - state variables and Lagrange multipliers",-1,-1,-1,-1,&user.u_lambda_viewer);
120: PetscViewerDrawOpen(PETSC_COMM_WORLD,0,"fu_lambda - derivate w.r.t. state variables and Lagrange multipliers",-1,-1,-1,-1,&user.fu_lambda_viewer);
121: SNESMonitorSet(snes,Monitor,0,0);
122: }
124: SNESSolve(snes,NULL,NULL);
125: SNESDestroy(&snes);
127: DMDestroy(&red);
128: DMDestroy(&da);
129: DMDestroy(&packer);
130: if (use_monitor) {
131: PetscViewerDestroy(&user.u_lambda_viewer);
132: PetscViewerDestroy(&user.fu_lambda_viewer);
133: }
134: PetscFinalize();
135: return ierr;
136: }
138: typedef struct {
139: PetscScalar u;
140: PetscScalar lambda;
141: } ULambda;
143: /*
144: Evaluates FU = Gradiant(L(w,u,lambda))
146: This local function acts on the ghosted version of U (accessed via DMCompositeGetLocalVectors() and
147: DMCompositeScatter()) BUT the global, nonghosted version of FU (via DMCompositeGetAccess()).
149: */
150: PetscErrorCode ComputeFunction(SNES snes,Vec U,Vec FU,void *ctx)
151: {
153: PetscInt xs,xm,i,N;
154: ULambda *u_lambda,*fu_lambda;
155: PetscScalar d,h,*w,*fw;
156: Vec vw,vfw,vu_lambda,vfu_lambda;
157: DM packer,red,da;
160: VecGetDM(U, &packer);
161: DMCompositeGetEntries(packer,&red,&da);
162: DMCompositeGetLocalVectors(packer,&vw,&vu_lambda);
163: DMCompositeScatter(packer,U,vw,vu_lambda);
164: DMCompositeGetAccess(packer,FU,&vfw,&vfu_lambda);
166: DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);
167: DMDAGetInfo(da,0,&N,0,0,0,0,0,0,0,0,0,0,0);
168: VecGetArray(vw,&w);
169: VecGetArray(vfw,&fw);
170: DMDAVecGetArray(da,vu_lambda,&u_lambda);
171: DMDAVecGetArray(da,vfu_lambda,&fu_lambda);
172: d = N-1.0;
173: h = 1.0/d;
175: /* derivative of L() w.r.t. w */
176: if (xs == 0) { /* only first processor computes this */
177: fw[0] = -2.0*d*u_lambda[0].lambda;
178: }
180: /* derivative of L() w.r.t. u */
181: for (i=xs; i<xs+xm; i++) {
182: if (i == 0) fu_lambda[0].lambda = h*u_lambda[0].u + 2.*d*u_lambda[0].lambda - d*u_lambda[1].lambda;
183: else if (i == 1) fu_lambda[1].lambda = 2.*h*u_lambda[1].u + 2.*d*u_lambda[1].lambda - d*u_lambda[2].lambda;
184: else if (i == N-1) fu_lambda[N-1].lambda = h*u_lambda[N-1].u + 2.*d*u_lambda[N-1].lambda - d*u_lambda[N-2].lambda;
185: else if (i == N-2) fu_lambda[N-2].lambda = 2.*h*u_lambda[N-2].u + 2.*d*u_lambda[N-2].lambda - d*u_lambda[N-3].lambda;
186: else fu_lambda[i].lambda = 2.*h*u_lambda[i].u - d*(u_lambda[i+1].lambda - 2.0*u_lambda[i].lambda + u_lambda[i-1].lambda);
187: }
189: /* derivative of L() w.r.t. lambda */
190: for (i=xs; i<xs+xm; i++) {
191: if (i == 0) fu_lambda[0].u = 2.0*d*(u_lambda[0].u - w[0]);
192: else if (i == N-1) fu_lambda[N-1].u = 2.0*d*u_lambda[N-1].u;
193: else fu_lambda[i].u = -(d*(u_lambda[i+1].u - 2.0*u_lambda[i].u + u_lambda[i-1].u) - 2.0*h);
194: }
196: VecRestoreArray(vw,&w);
197: VecRestoreArray(vfw,&fw);
198: DMDAVecRestoreArray(da,vu_lambda,&u_lambda);
199: DMDAVecRestoreArray(da,vfu_lambda,&fu_lambda);
200: DMCompositeRestoreLocalVectors(packer,&vw,&vu_lambda);
201: DMCompositeRestoreAccess(packer,FU,&vfw,&vfu_lambda);
202: PetscLogFlops(13.0*N);
203: return(0);
204: }
206: /*
207: Computes the exact solution
208: */
209: PetscErrorCode u_solution(void *dummy,PetscInt n,const PetscScalar *x,PetscScalar *u)
210: {
211: PetscInt i;
214: for (i=0; i<n; i++) u[2*i] = x[i]*x[i] - 1.25*x[i] + .25;
215: return(0);
216: }
218: PetscErrorCode ExactSolution(DM packer,Vec U)
219: {
220: PF pf;
221: Vec x,u_global;
222: PetscScalar *w;
223: DM da;
225: PetscInt m;
228: DMCompositeGetEntries(packer,&m,&da);
230: PFCreate(PETSC_COMM_WORLD,1,2,&pf);
231: /* The cast through PETSC_UINTPTR_T is so that compilers will warn about casting to void * from void(*)(void) */
232: PFSetType(pf,PFQUICK,(void*)(PETSC_UINTPTR_T)u_solution);
233: DMGetCoordinates(da,&x);
234: if (!x) {
235: DMDASetUniformCoordinates(da,0.0,1.0,0.0,1.0,0.0,1.0);
236: DMGetCoordinates(da,&x);
237: }
238: DMCompositeGetAccess(packer,U,&w,&u_global,0);
239: if (w) w[0] = .25;
240: PFApplyVec(pf,x,u_global);
241: PFDestroy(&pf);
242: DMCompositeRestoreAccess(packer,U,&w,&u_global,0);
243: return(0);
244: }
246: PetscErrorCode Monitor(SNES snes,PetscInt its,PetscReal rnorm,void *dummy)
247: {
248: UserCtx *user;
250: PetscInt m,N;
251: PetscScalar *w,*dw;
252: Vec u_lambda,U,F,Uexact;
253: DM packer;
254: PetscReal norm;
255: DM da;
258: SNESGetDM(snes,&packer);
259: DMGetApplicationContext(packer,&user);
260: SNESGetSolution(snes,&U);
261: DMCompositeGetAccess(packer,U,&w,&u_lambda);
262: VecView(u_lambda,user->u_lambda_viewer);
263: DMCompositeRestoreAccess(packer,U,&w,&u_lambda);
265: SNESGetFunction(snes,&F,0,0);
266: DMCompositeGetAccess(packer,F,&w,&u_lambda);
267: /* VecView(u_lambda,user->fu_lambda_viewer); */
268: DMCompositeRestoreAccess(packer,U,&w,&u_lambda);
270: DMCompositeGetEntries(packer,&m,&da);
271: DMDAGetInfo(da,0,&N,0,0,0,0,0,0,0,0,0,0,0);
272: VecDuplicate(U,&Uexact);
273: ExactSolution(packer,Uexact);
274: VecAXPY(Uexact,-1.0,U);
275: DMCompositeGetAccess(packer,Uexact,&dw,&u_lambda);
276: VecStrideNorm(u_lambda,0,NORM_2,&norm);
277: norm = norm/PetscSqrtReal((PetscReal)N-1.);
278: if (dw) PetscPrintf(PETSC_COMM_WORLD,"Norm of error %g Error at x = 0 %g\n",(double)norm,(double)PetscRealPart(dw[0]));
279: VecView(u_lambda,user->fu_lambda_viewer);
280: DMCompositeRestoreAccess(packer,Uexact,&dw,&u_lambda);
281: VecDestroy(&Uexact);
282: return(0);
283: }
285: PetscErrorCode DMCreateMatrix_MF(DM packer,Mat *A)
286: {
288: Vec t;
289: PetscInt m;
292: DMGetGlobalVector(packer,&t);
293: VecGetLocalSize(t,&m);
294: DMRestoreGlobalVector(packer,&t);
295: MatCreateMFFD(PETSC_COMM_WORLD,m,m,PETSC_DETERMINE,PETSC_DETERMINE,A);
296: MatSetUp(*A);
297: MatSetDM(*A,packer);
298: return(0);
299: }
301: PetscErrorCode ComputeJacobian_MF(SNES snes,Vec x,Mat A,Mat B,void *ctx)
302: {
306: MatMFFDSetFunction(A,(PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunction,snes);
307: MatMFFDSetBase(A,x,NULL);
308: return(0);
309: }
312: /*TEST
314: test:
315: nsize: 2
316: args: -da_grid_x 10 -snes_converged_reason -ksp_converged_reason -snes_view
317: requires: !single
319: TEST*/