Actual source code: ex22.c
petsc-3.13.6 2020-09-29
Report Typos and Errors

      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*/