1 2 static const char help[] = "Solves PDE optimization problem using full-space method, treats state and adjoint variables separately.\n\n"; 3 4 #include <petscdm.h> 5 #include <petscdmda.h> 6 #include <petscdmredundant.h> 7 #include <petscdmcomposite.h> 8 #include <petscpf.h> 9 #include <petscsnes.h> 10 11 /* 12 13 w - design variables (what we change to get an optimal solution) 14 u - state variables (i.e. the PDE solution) 15 lambda - the Lagrange multipliers 16 17 U = (w u lambda) 18 19 fu, fw, flambda contain the gradient of L(w,u,lambda) 20 21 FU = (fw fu flambda) 22 23 In this example the PDE is 24 Uxx = 2, 25 u(0) = w(0), thus this is the free parameter 26 u(1) = 0 27 the function we wish to minimize is 28 \integral u^{2} 29 30 The exact solution for u is given by u(x) = x*x - 1.25*x + .25 31 32 Use the usual centered finite differences. 33 34 Note we treat the problem as non-linear though it happens to be linear 35 36 See ex22.c for the same code, but that interlaces the u and the lambda 37 38 */ 39 40 typedef struct { 41 DM red1, da1, da2; 42 DM packer; 43 PetscViewer u_viewer, lambda_viewer; 44 PetscViewer fu_viewer, flambda_viewer; 45 } UserCtx; 46 47 extern PetscErrorCode FormFunction(SNES, Vec, Vec, void *); 48 extern PetscErrorCode Monitor(SNES, PetscInt, PetscReal, void *); 49 50 int main(int argc, char **argv) { 51 PetscInt its; 52 Vec U, FU; 53 SNES snes; 54 UserCtx user; 55 56 PetscFunctionBeginUser; 57 PetscCall(PetscInitialize(&argc, &argv, (char *)0, help)); 58 59 /* Create a global vector that includes a single redundant array and two da arrays */ 60 PetscCall(DMCompositeCreate(PETSC_COMM_WORLD, &user.packer)); 61 PetscCall(DMRedundantCreate(PETSC_COMM_WORLD, 0, 1, &user.red1)); 62 PetscCall(DMCompositeAddDM(user.packer, user.red1)); 63 PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, 5, 1, 1, NULL, &user.da1)); 64 PetscCall(DMSetFromOptions(user.da1)); 65 PetscCall(DMSetUp(user.da1)); 66 PetscCall(DMCompositeAddDM(user.packer, user.da1)); 67 PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, 5, 1, 1, NULL, &user.da2)); 68 PetscCall(DMSetFromOptions(user.da2)); 69 PetscCall(DMSetUp(user.da2)); 70 PetscCall(DMDASetFieldName(user.da1, 0, "u")); 71 PetscCall(DMDASetFieldName(user.da2, 0, "lambda")); 72 PetscCall(DMCompositeAddDM(user.packer, user.da2)); 73 PetscCall(DMCreateGlobalVector(user.packer, &U)); 74 PetscCall(VecDuplicate(U, &FU)); 75 76 /* create graphics windows */ 77 PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, 0, "u - state variables", -1, -1, -1, -1, &user.u_viewer)); 78 PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, 0, "lambda - Lagrange multipliers", -1, -1, -1, -1, &user.lambda_viewer)); 79 PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, 0, "fu - derivate w.r.t. state variables", -1, -1, -1, -1, &user.fu_viewer)); 80 PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, 0, "flambda - derivate w.r.t. Lagrange multipliers", -1, -1, -1, -1, &user.flambda_viewer)); 81 82 /* create nonlinear solver */ 83 PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes)); 84 PetscCall(SNESSetFunction(snes, FU, FormFunction, &user)); 85 PetscCall(SNESSetFromOptions(snes)); 86 PetscCall(SNESMonitorSet(snes, Monitor, &user, 0)); 87 PetscCall(SNESSolve(snes, NULL, U)); 88 PetscCall(SNESGetIterationNumber(snes, &its)); 89 PetscCall(SNESDestroy(&snes)); 90 91 PetscCall(DMDestroy(&user.red1)); 92 PetscCall(DMDestroy(&user.da1)); 93 PetscCall(DMDestroy(&user.da2)); 94 PetscCall(DMDestroy(&user.packer)); 95 PetscCall(VecDestroy(&U)); 96 PetscCall(VecDestroy(&FU)); 97 PetscCall(PetscViewerDestroy(&user.u_viewer)); 98 PetscCall(PetscViewerDestroy(&user.lambda_viewer)); 99 PetscCall(PetscViewerDestroy(&user.fu_viewer)); 100 PetscCall(PetscViewerDestroy(&user.flambda_viewer)); 101 PetscCall(PetscFinalize()); 102 return 0; 103 } 104 105 /* 106 Evaluates FU = Gradiant(L(w,u,lambda)) 107 108 */ 109 PetscErrorCode FormFunction(SNES snes, Vec U, Vec FU, void *dummy) { 110 UserCtx *user = (UserCtx *)dummy; 111 PetscInt xs, xm, i, N; 112 PetscScalar *u, *lambda, *w, *fu, *fw, *flambda, d, h; 113 Vec vw, vu, vlambda, vfw, vfu, vflambda; 114 115 PetscFunctionBeginUser; 116 PetscCall(DMCompositeGetLocalVectors(user->packer, &vw, &vu, &vlambda)); 117 PetscCall(DMCompositeGetLocalVectors(user->packer, &vfw, &vfu, &vflambda)); 118 PetscCall(DMCompositeScatter(user->packer, U, vw, vu, vlambda)); 119 120 PetscCall(DMDAGetCorners(user->da1, &xs, NULL, NULL, &xm, NULL, NULL)); 121 PetscCall(DMDAGetInfo(user->da1, 0, &N, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); 122 PetscCall(VecGetArray(vw, &w)); 123 PetscCall(VecGetArray(vfw, &fw)); 124 PetscCall(DMDAVecGetArray(user->da1, vu, &u)); 125 PetscCall(DMDAVecGetArray(user->da1, vfu, &fu)); 126 PetscCall(DMDAVecGetArray(user->da1, vlambda, &lambda)); 127 PetscCall(DMDAVecGetArray(user->da1, vflambda, &flambda)); 128 d = (N - 1.0); 129 h = 1.0 / d; 130 131 /* derivative of L() w.r.t. w */ 132 if (xs == 0) { /* only first processor computes this */ 133 fw[0] = -2. * d * lambda[0]; 134 } 135 136 /* derivative of L() w.r.t. u */ 137 for (i = xs; i < xs + xm; i++) { 138 if (i == 0) flambda[0] = h * u[0] + 2. * d * lambda[0] - d * lambda[1]; 139 else if (i == 1) flambda[1] = 2. * h * u[1] + 2. * d * lambda[1] - d * lambda[2]; 140 else if (i == N - 1) flambda[N - 1] = h * u[N - 1] + 2. * d * lambda[N - 1] - d * lambda[N - 2]; 141 else if (i == N - 2) flambda[N - 2] = 2. * h * u[N - 2] + 2. * d * lambda[N - 2] - d * lambda[N - 3]; 142 else flambda[i] = 2. * h * u[i] - d * (lambda[i + 1] - 2.0 * lambda[i] + lambda[i - 1]); 143 } 144 145 /* derivative of L() w.r.t. lambda */ 146 for (i = xs; i < xs + xm; i++) { 147 if (i == 0) fu[0] = 2.0 * d * (u[0] - w[0]); 148 else if (i == N - 1) fu[N - 1] = 2.0 * d * u[N - 1]; 149 else fu[i] = -(d * (u[i + 1] - 2.0 * u[i] + u[i - 1]) - 2.0 * h); 150 } 151 152 PetscCall(VecRestoreArray(vw, &w)); 153 PetscCall(VecRestoreArray(vfw, &fw)); 154 PetscCall(DMDAVecRestoreArray(user->da1, vu, &u)); 155 PetscCall(DMDAVecRestoreArray(user->da1, vfu, &fu)); 156 PetscCall(DMDAVecRestoreArray(user->da1, vlambda, &lambda)); 157 PetscCall(DMDAVecRestoreArray(user->da1, vflambda, &flambda)); 158 159 PetscCall(DMCompositeGather(user->packer, INSERT_VALUES, FU, vfw, vfu, vflambda)); 160 PetscCall(DMCompositeRestoreLocalVectors(user->packer, &vw, &vu, &vlambda)); 161 PetscCall(DMCompositeRestoreLocalVectors(user->packer, &vfw, &vfu, &vflambda)); 162 PetscFunctionReturn(0); 163 } 164 165 PetscErrorCode Monitor(SNES snes, PetscInt its, PetscReal rnorm, void *dummy) { 166 UserCtx *user = (UserCtx *)dummy; 167 Vec w, u, lambda, U, F; 168 169 PetscFunctionBeginUser; 170 PetscCall(SNESGetSolution(snes, &U)); 171 PetscCall(DMCompositeGetAccess(user->packer, U, &w, &u, &lambda)); 172 PetscCall(VecView(u, user->u_viewer)); 173 PetscCall(VecView(lambda, user->lambda_viewer)); 174 PetscCall(DMCompositeRestoreAccess(user->packer, U, &w, &u, &lambda)); 175 176 PetscCall(SNESGetFunction(snes, &F, 0, 0)); 177 PetscCall(DMCompositeGetAccess(user->packer, F, &w, &u, &lambda)); 178 PetscCall(VecView(u, user->fu_viewer)); 179 PetscCall(VecView(lambda, user->flambda_viewer)); 180 PetscCall(DMCompositeRestoreAccess(user->packer, F, &w, &u, &lambda)); 181 PetscFunctionReturn(0); 182 } 183 184 /*TEST 185 186 test: 187 nsize: 4 188 args: -snes_linesearch_monitor -snes_mf -pc_type none -snes_monitor_short -nox -ksp_monitor_short -snes_converged_reason 189 requires: !single 190 191 TEST*/ 192