xref: /petsc/src/snes/tutorials/ex11.c (revision 3f02e49b19195914bf17f317a25cb39636853415)
1 static char help[] = "Poisson problem with finite elements.\n\
2 We solve the Poisson problem using a parallel unstructured mesh to discretize it.\n\
3 This example is a simplified version of ex12.c that only solves the linear problem.\n\
4 It uses discretized auxiliary fields for coefficient and right-hand side, \n\
5 supports multilevel solvers and non-conforming mesh refinement.\n\n\n";
6 
7 /*
8 Here we describe the PETSc approach to solve nonlinear problems arising from Finite Element (FE) discretizations.
9 
10 The general model requires to solve the residual equations
11 
12     residual(u) := \int_\Omega \phi \cdot f_0(u, \nabla u, a, \nabla a) + \nabla \phi : f_1(u, \nabla u, a, \nabla a) = 0
13 
14 where \phi is a test function, u is the sought FE solution, and a generically describes auxiliary data (for example material properties).
15 
16 The functions f_0 (scalar) and f_1 (vector) describe the problem, while : is the usual contraction operator for tensors, i.e. A : B = \sum_{ij} A_{ij} B_{ij}.
17 
18 The discrete residual is (with abuse of notation)
19 
20     F(u) := \sum_e E_e^T [ B^T_e W_{0,e} f_0(u_q, \nabla u_q, a_q, \nabla a_q) + D_e W_{1,e} f_1(u_q, \nabla u_q, a_q, \nabla a_q) ]
21 
22 where E are element restriction matrices (can support non-conforming meshes), W are quadrature weights, B (resp. D) are basis function (resp. derivative of basis function) matrices, and u_q,a_q are vectors sampled at quadrature points.
23 
24 Having the residual in the above form, it is straightforward to derive its Jacobian (again with abuse of notation)
25 
26     J(u) := \sum_e E_e^T [B^T_e D^T_e] W  J_e [ B_e^T, D_e^T ]^T E_e,
27 
28 where J_e is the 2x2 matrix
29 
30    | \partial_u f_0, \partial_{\grad u} f_0 |
31    | \partial_u f_1, \partial_{\grad u} f_1 |
32 
33 Here we use a single-field approach, but the extension to the multi-field case is straightforward.
34 
35 To keep the presentation simple, here we are interested in solving the Poisson problem in divergence form
36 
37    - \nabla \cdot (K * \nabla u) = g
38 
39 with either u = 0 or K * \partial_n u = 0 on \partial \Omega.
40 The above problem possesses the weak form
41 
42    \int_\Omega \nabla \phi K \nabla u + \phi g = 0,
43 
44 thus we have:
45 
46    f_0 = g, f_1 = K * \nabla u, and the only non-zero term of the Jacobian is J_{11} = K
47 
48 See https://petsc.org/release/manual/fe the and the paper "Achieving High Performance with Unified Residual Evaluation" (available at https://arxiv.org/abs/1309.1204) for additional information.
49 */
50 
51 /* Include the necessary definitions */
52 #include <petscdmplex.h>
53 #include <petscsnes.h>
54 #include <petscds.h>
55 
56 /* The f_0 function: we read the right-hand side from the first field of the auxiliary data */
57 static void f_0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
58 {
59   const PetscScalar g = a[0];
60 
61   f0[0] = g;
62 }
63 
64 /* The f_1 function: we read the conductivity tensor from the second field of the auxiliary data */
65 static void f_1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
66 {
67   const PetscScalar *K = &a[1];
68 
69   for (PetscInt d1 = 0; d1 < dim; ++d1) {
70     PetscScalar v = 0;
71     for (PetscInt d2 = 0; d2 < dim; ++d2) v += K[d1 * dim + d2] * u_x[d2];
72     f1[d1] = v;
73   }
74 }
75 
76 /* The only non-zero term for the Jacobian is J_11 */
77 static void J_11(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J11[])
78 {
79   const PetscScalar *K = &a[1];
80 
81   for (PetscInt d1 = 0; d1 < dim; ++d1) {
82     for (PetscInt d2 = 0; d2 < dim; ++d2) J11[d1 * dim + d2] = K[d1 * dim + d2];
83   }
84 }
85 
86 /* The boundary conditions: Dirichlet (essential) or Neumann (natural) */
87 typedef enum {
88   BC_DIRICHLET,
89   BC_NEUMANN,
90 } bcType;
91 
92 static const char *const bcTypes[] = {"DIRICHLET", "NEUMANN", "bcType", "BC_", 0};
93 
94 /* The forcing term: constant or analytical */
95 typedef enum {
96   RHS_CONSTANT,
97   RHS_ANALYTICAL,
98 } rhsType;
99 
100 static const char *const rhsTypes[] = {"CONSTANT", "ANALYTICAL", "rhsType", "RHS_", 0};
101 
102 /* the constant case */
103 static PetscErrorCode rhs_constant(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *g, void *ctx)
104 {
105   *g = 1.0;
106   return PETSC_SUCCESS;
107 }
108 
109 /* the analytical case */
110 static PetscErrorCode rhs_analytical(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *g, void *ctx)
111 {
112   PetscScalar v = 1.0;
113   for (PetscInt d = 0; d < dim; d++) v *= PetscSinReal(2.0 * PETSC_PI * x[d]);
114   *g = v;
115   return PETSC_SUCCESS;
116 }
117 
118 /* For the Neumann BC case we need a functional to be integrated: average -> \int_\Omega u dx */
119 static void average(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[])
120 {
121   obj[0] = u[0];
122 }
123 
124 /* The conductivity coefficient term: constant, checkerboard or analytical */
125 typedef enum {
126   COEFF_CONSTANT,
127   COEFF_CHECKERBOARD,
128   COEFF_ANALYTICAL,
129 } coeffType;
130 
131 static const char *const coeffTypes[] = {"CONSTANT", "CHECKERBOARD", "ANALYTICAL", "coeffType", "COEFF_", 0};
132 
133 /* the constant coefficient case */
134 static PetscErrorCode coefficient_constant(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *K, void *ctx)
135 {
136   for (PetscInt d = 0; d < dim; d++) K[d * dim + d] = 1.0;
137   return PETSC_SUCCESS;
138 }
139 
140 /* the checkerboard coefficient case: 10^2 in odd ranks, 10^-2 in even ranks */
141 static PetscErrorCode coefficient_checkerboard(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *K, void *ctx)
142 {
143   PetscScalar exponent = PetscGlobalRank % 2 ? 2.0 : -2.0;
144   for (PetscInt d = 0; d < dim; d++) K[d * dim + d] = PetscPowScalar(10.0, exponent);
145   return PETSC_SUCCESS;
146 }
147 
148 /* the analytical case (channels in diagonal with 4 order of magnitude in jumps) */
149 static PetscErrorCode coefficient_analytical(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *K, void *ctx)
150 {
151   for (PetscInt d = 0; d < dim; d++) {
152     const PetscReal v = PetscPowReal(10.0, 4.0 * PetscSinReal(4.0 * PETSC_PI * x[d]) * PetscCosReal(4.0 * PETSC_PI * x[d]));
153     K[d * dim + d]    = v;
154   }
155   return PETSC_SUCCESS;
156 }
157 
158 /* The application context that defines our problem */
159 typedef struct {
160   bcType    bc;         /* type of boundary conditions */
161   rhsType   rhs;        /* type of right-hand side */
162   coeffType coeff;      /* type of conductivity coefficient */
163   PetscInt  order;      /* the polynomial order for the solution */
164   PetscInt  rhsOrder;   /* the polynomial order for the right-hand side */
165   PetscInt  coeffOrder; /* the polynomial order for the coefficient */
166   PetscBool p4est;      /* if we want to use non-conforming AMR */
167 } AppCtx;
168 
169 /* Process command line options */
170 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
171 {
172   PetscFunctionBeginUser;
173   options->bc         = BC_DIRICHLET;
174   options->rhs        = RHS_CONSTANT;
175   options->coeff      = COEFF_CONSTANT;
176   options->order      = 1;
177   options->rhsOrder   = 1;
178   options->coeffOrder = 1;
179   options->p4est      = PETSC_FALSE;
180 
181   PetscOptionsBegin(comm, "", "Poisson problem options", "DMPLEX");
182   PetscCall(PetscOptionsEnum("-bc_type", "Type of boundary condition", __FILE__, bcTypes, (PetscEnum)options->bc, (PetscEnum *)&options->bc, NULL));
183   PetscCall(PetscOptionsEnum("-rhs_type", "Type of forcing term", __FILE__, rhsTypes, (PetscEnum)options->rhs, (PetscEnum *)&options->rhs, NULL));
184   PetscCall(PetscOptionsEnum("-coefficient_type", "Type of conductivity coefficient", __FILE__, coeffTypes, (PetscEnum)options->coeff, (PetscEnum *)&options->coeff, NULL));
185   PetscCall(PetscOptionsInt("-order", "The polynomial order for the approximation of the solution", __FILE__, options->order, &options->order, NULL));
186   PetscCall(PetscOptionsInt("-rhs_order", "The polynomial order for the approximation of the right-hand side", __FILE__, options->rhsOrder, &options->rhsOrder, NULL));
187   PetscCall(PetscOptionsInt("-coefficient_order", "The polynomial order for the approximation of the coefficient", __FILE__, options->coeffOrder, &options->coeffOrder, NULL));
188   PetscCall(PetscOptionsBool("-p4est", "Use p4est to represent the mesh", __FILE__, options->p4est, &options->p4est, NULL));
189   PetscOptionsEnd();
190 
191   /* View processed options */
192   PetscCall(PetscPrintf(comm, "Simulation parameters\n"));
193   PetscCall(PetscPrintf(comm, "  polynomial order: %" PetscInt_FMT "\n", options->order));
194   PetscCall(PetscPrintf(comm, "  boundary conditions: %s\n", bcTypes[options->bc]));
195   PetscCall(PetscPrintf(comm, "  right-hand side: %s, order %" PetscInt_FMT "\n", rhsTypes[options->rhs], options->rhsOrder));
196   PetscCall(PetscPrintf(comm, "  coefficient: %s, order %" PetscInt_FMT "\n", coeffTypes[options->coeff], options->coeffOrder));
197   PetscCall(PetscPrintf(comm, "  non-conforming AMR: %d\n", options->p4est));
198   PetscFunctionReturn(PETSC_SUCCESS);
199 }
200 
201 /* Create mesh from command line options */
202 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
203 {
204   PetscFunctionBeginUser;
205   /* Create various types of meshes only with command line options */
206   PetscCall(DMCreate(comm, dm));
207   PetscCall(DMSetType(*dm, DMPLEX));
208   PetscCall(DMSetOptionsPrefix(*dm, "initial_"));
209   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
210   PetscCall(DMSetFromOptions(*dm));
211   PetscCall(DMLocalizeCoordinates(*dm));
212   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
213   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_TRUE));
214   PetscCall(DMSetOptionsPrefix(*dm, "mesh_"));
215   PetscCall(DMSetFromOptions(*dm));
216 
217   /* If requested convert to a format suitable for non-conforming adaptive mesh refinement */
218   if (user->p4est) {
219     PetscInt dim;
220     DM       dmConv;
221 
222     PetscCall(DMGetDimension(*dm, &dim));
223     PetscCheck(dim == 2 || dim == 3, comm, PETSC_ERR_SUP, "p4est support not for dimension %" PetscInt_FMT, dim);
224     PetscCall(DMConvert(*dm, dim == 3 ? DMP8EST : DMP4EST, &dmConv));
225     if (dmConv) {
226       PetscCall(DMDestroy(dm));
227       PetscCall(DMSetOptionsPrefix(dmConv, "mesh_"));
228       PetscCall(DMSetFromOptions(dmConv));
229       *dm = dmConv;
230     }
231   }
232   PetscCall(DMSetUp(*dm));
233 
234   /* View the mesh.
235      With a single call we can dump ASCII information, VTK data for visualization, store the mesh in HDF5 format, etc. */
236   PetscCall(PetscObjectSetName((PetscObject)*dm, "Mesh"));
237   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
238   PetscFunctionReturn(PETSC_SUCCESS);
239 }
240 
241 /* Setup the discrete problem */
242 static PetscErrorCode SetupProblem(DM dm, DM fdm, AppCtx *user)
243 {
244   DM             plex, dmAux, cdm = NULL, coordDM;
245   Vec            auxData, auxDataGlobal;
246   PetscDS        ds;
247   DMPolytopeType ct;
248   PetscInt       dim, cdim, cStart;
249   PetscFE        fe, fe_rhs, fe_K;
250   PetscErrorCode (*auxFuncs[])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx) = {NULL, NULL};
251   void *auxCtxs[]                                                                                                          = {NULL, NULL};
252 
253   PetscFunctionBeginUser;
254   /* Create the Finite Element for the solution and pass it to the problem DM */
255   PetscCall(DMGetDimension(dm, &dim));
256   PetscCall(DMConvert(dm, DMPLEX, &plex));
257   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL));
258   PetscCall(DMPlexGetCellType(plex, cStart, &ct));
259   PetscCall(DMDestroy(&plex));
260   PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, 1, ct, user->order, PETSC_DETERMINE, &fe));
261   PetscCall(PetscObjectSetName((PetscObject)fe, "potential"));
262   PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fe));
263   PetscCall(DMCreateDS(dm));
264 
265   /* Set residual and Jacobian callbacks */
266   PetscCall(DMGetDS(dm, &ds));
267   PetscCall(PetscDSSetResidual(ds, 0, f_0, f_1));
268   PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, J_11));
269   /* Tell DMPLEX we are going to use FEM callbacks */
270   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, &user));
271 
272   /* Create the Finite Element for the auxiliary data */
273   PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, 1, ct, user->rhsOrder, PETSC_DETERMINE, &fe_rhs));
274   PetscCall(PetscObjectSetName((PetscObject)fe_rhs, "g"));
275   PetscCall(PetscFECopyQuadrature(fe, fe_rhs));
276   PetscCall(DMGetCoordinateDM(dm, &coordDM));
277   PetscCall(DMGetDimension(coordDM, &cdim));
278   PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, cdim * cdim, ct, user->coeffOrder, PETSC_DETERMINE, &fe_K));
279   PetscCall(PetscObjectSetName((PetscObject)fe_K, "K"));
280   PetscCall(PetscFECopyQuadrature(fe, fe_K));
281   PetscCall(DMClone(dm, &dmAux));
282   PetscCall(DMSetField(dmAux, 0, NULL, (PetscObject)fe_rhs));
283   PetscCall(DMSetField(dmAux, 1, NULL, (PetscObject)fe_K));
284   PetscCall(DMCreateDS(dmAux));
285 
286   /* Project the requested rhs and K to the auxiliary DM and pass it to the problem DM */
287   PetscCall(DMCreateLocalVector(dmAux, &auxData));
288   PetscCall(DMCreateGlobalVector(dmAux, &auxDataGlobal));
289   PetscCall(PetscObjectSetName((PetscObject)auxData, ""));
290   if (!fdm) {
291     switch (user->rhs) {
292     case RHS_CONSTANT:
293       auxFuncs[0] = rhs_constant;
294       auxCtxs[0]  = NULL;
295       break;
296     case RHS_ANALYTICAL:
297       auxFuncs[0] = rhs_analytical;
298       auxCtxs[0]  = NULL;
299       break;
300     default:
301       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported rhs type %s", rhsTypes[user->rhs]);
302     }
303     switch (user->coeff) {
304     case COEFF_CONSTANT:
305       auxFuncs[1] = coefficient_constant;
306       auxCtxs[1]  = NULL;
307       break;
308     case COEFF_CHECKERBOARD:
309       auxFuncs[1] = coefficient_checkerboard;
310       auxCtxs[1]  = NULL;
311       break;
312     case COEFF_ANALYTICAL:
313       auxFuncs[1] = coefficient_analytical;
314       auxCtxs[1]  = NULL;
315       break;
316     default:
317       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported coefficient type %s", coeffTypes[user->coeff]);
318     }
319     PetscCall(DMGetDS(dmAux, &ds));
320     PetscCall(DMProjectFunction(dmAux, 0.0, auxFuncs, auxCtxs, INSERT_ALL_VALUES, auxDataGlobal));
321     if (user->bc == BC_NEUMANN) {
322       PetscScalar vals[2];
323       PetscInt    rhs_id = 0;
324       IS          is;
325 
326       PetscCall(PetscDSSetObjective(ds, rhs_id, average));
327       PetscCall(DMPlexComputeIntegralFEM(dmAux, auxDataGlobal, vals, NULL));
328       PetscCall(DMCreateSubDM(dmAux, 1, &rhs_id, &is, NULL));
329       PetscCall(VecISShift(auxDataGlobal, is, -vals[rhs_id]));
330       PetscCall(DMPlexComputeIntegralFEM(dmAux, auxDataGlobal, vals, NULL));
331       PetscCall(ISDestroy(&is));
332     }
333   } else {
334     Mat J;
335     Vec auxDataGlobalf, auxDataf, Jscale;
336     DM  dmAuxf;
337 
338     PetscCall(DMGetAuxiliaryVec(fdm, NULL, 0, 0, &auxDataf));
339     PetscCall(VecGetDM(auxDataf, &dmAuxf));
340     PetscCall(DMSetCoarseDM(dmAuxf, dmAux));
341     PetscCall(DMCreateGlobalVector(dmAuxf, &auxDataGlobalf));
342     PetscCall(DMLocalToGlobal(dmAuxf, auxDataf, INSERT_VALUES, auxDataGlobalf));
343     PetscCall(DMCreateInterpolation(dmAux, dmAuxf, &J, &Jscale));
344     PetscCall(MatInterpolate(J, auxDataGlobalf, auxDataGlobal));
345     PetscCall(VecPointwiseMult(auxDataGlobal, auxDataGlobal, Jscale));
346     PetscCall(VecDestroy(&Jscale));
347     PetscCall(VecDestroy(&auxDataGlobalf));
348     PetscCall(MatDestroy(&J));
349     PetscCall(DMSetCoarseDM(dmAuxf, NULL));
350   }
351   /* auxiliary data must be a local vector */
352   PetscCall(DMGlobalToLocal(dmAux, auxDataGlobal, INSERT_VALUES, auxData));
353   { /* view auxiliary data */
354     PetscInt level;
355     char     optionName[PETSC_MAX_PATH_LEN];
356 
357     PetscCall(DMGetRefineLevel(dm, &level));
358     PetscCall(PetscSNPrintf(optionName, sizeof(optionName), "-aux_%" PetscInt_FMT "_vec_view", level));
359     PetscCall(VecViewFromOptions(auxData, NULL, optionName));
360   }
361   PetscCall(DMSetAuxiliaryVec(dm, NULL, 0, 0, auxData));
362   PetscCall(VecDestroy(&auxData));
363   PetscCall(VecDestroy(&auxDataGlobal));
364   PetscCall(DMDestroy(&dmAux));
365 
366   /* Setup boundary conditions
367      Since we use homogeneous natural boundary conditions for the Neumann problem we
368      only handle the Dirichlet case here */
369   if (user->bc == BC_DIRICHLET) {
370     DMLabel  label;
371     PetscInt id = 1;
372 
373     /* Label faces on the mesh boundary */
374     PetscCall(DMCreateLabel(dm, "boundary"));
375     PetscCall(DMGetLabel(dm, "boundary", &label));
376     PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label));
377     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "dirichlet", label, 1, &id, 0, 0, NULL, NULL, NULL, NULL, NULL));
378   }
379 
380   /* Iterate on coarser mesh if present */
381   PetscCall(DMGetCoarseDM(dm, &cdm));
382   if (cdm) PetscCall(SetupProblem(cdm, dm, user));
383 
384   PetscCall(PetscFEDestroy(&fe));
385   PetscCall(PetscFEDestroy(&fe_rhs));
386   PetscCall(PetscFEDestroy(&fe_K));
387   PetscFunctionReturn(PETSC_SUCCESS);
388 }
389 
390 /* We are now ready to run the simulation */
391 int main(int argc, char **argv)
392 {
393   DM     dm;   /* problem specification */
394   SNES   snes; /* nonlinear solver */
395   KSP    ksp;  /* linear solver */
396   Vec    u;    /* solution vector */
397   AppCtx user; /* user-defined work context */
398 
399   PetscFunctionBeginUser;
400   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
401   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
402   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
403   PetscCall(SetupProblem(dm, NULL, &user));
404 
405   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
406   PetscCall(SNESSetDM(snes, dm));
407   PetscCall(SNESSetType(snes, SNESKSPONLY));
408   PetscCall(SNESGetKSP(snes, &ksp));
409   PetscCall(KSPSetType(ksp, KSPCG));
410   PetscCall(KSPSetNormType(ksp, KSP_NORM_NATURAL));
411   PetscCall(SNESSetFromOptions(snes));
412 
413   PetscCall(DMCreateGlobalVector(dm, &u));
414   PetscCall(PetscObjectSetName((PetscObject)u, ""));
415   PetscCall(VecSetRandom(u, NULL));
416   PetscCall(SNESSolve(snes, NULL, u));
417   PetscCall(VecDestroy(&u));
418   PetscCall(SNESDestroy(&snes));
419   PetscCall(DMDestroy(&dm));
420   PetscCall(PetscFinalize());
421   return 0;
422 }
423 
424 /*TEST
425 
426   test:
427     suffix: 0
428     requires: triangle !single
429     args: -bc_type {{dirichlet neumann}separate output} -rhs_type {{constant analytical}separate output} -coefficient_type {{constant checkerboard analytical}separate output} -initial_dm_plex_simplex 1 -pc_type svd -snes_type newtonls -snes_error_if_not_converged
430 
431   test:
432     requires: !single
433     suffix: 0_quad
434     args: -bc_type {{dirichlet neumann}separate output} -rhs_type {{constant analytical}separate output} -coefficient_type {{constant checkerboard analytical}separate output} -initial_dm_plex_simplex 0 -pc_type svd -snes_type newtonls -snes_error_if_not_converged
435 
436   test:
437     suffix: 0_p4est
438     requires: p4est !single
439     args: -bc_type {{dirichlet neumann}separate output} -rhs_type {{constant analytical}separate output} -coefficient_type {{constant checkerboard analytical}separate output} -initial_dm_plex_simplex 0 -pc_type svd -snes_type newtonls -snes_error_if_not_converged
440 
441   testset:
442     nsize: 2
443     requires: hpddm slepc !single defined(PETSC_HAVE_DYNAMIC_LIBRARIES) defined(PETSC_USE_SHARED_LIBRARIES)
444     args: -pc_type hpddm -pc_hpddm_coarse_correction balanced -pc_hpddm_coarse_mat_type aij -pc_hpddm_levels_eps_nev 1 -pc_hpddm_levels_sub_pc_type lu -ksp_monitor -initial_dm_plex_simplex 0 -petscpartitioner_type simple
445     output_file: output/ex11_hpddm.out
446     test:
447       suffix: hpddm
448       args:
449     test:
450       suffix: hpddm_harmonic_overlap
451       args: -pc_hpddm_harmonic_overlap 1 -pc_hpddm_has_neumann false -pc_hpddm_levels_1_pc_asm_type basic
452     test:
453       suffix: hpddm_p4est
454       requires: p4est
455       args: -p4est
456       filter: sed -e "s/non-conforming AMR: 1/non-conforming AMR: 0/g"
457 
458   test:
459     nsize: 4
460     suffix: gdsw_corner
461     requires: triangle
462     args: -pc_type mg -pc_mg_galerkin -pc_mg_adapt_interp_coarse_space gdsw -pc_mg_levels 2 -mg_levels_pc_type asm -initial_dm_plex_shape ball -initial_dm_refine 2 -mesh_dm_mat_type {{aij is}} -mg_levels_sub_pc_type lu -mg_levels_pc_asm_type basic -petscpartitioner_type simple
463 
464   test:
465     suffix: asm_seq
466     args: -pc_type asm -pc_asm_dm_subdomains -sub_pc_type cholesky -snes_type newtonls -snes_error_if_not_converged -initial_dm_plex_simplex 0
467 
468 TEST*/
469