xref: /petsc/src/snes/tutorials/ex26.c (revision f97672e55eacc8688507b9471cd7ec2664d7f203)
1 static char help[] = "'Good Cop' Helmholtz Problem in 2d and 3d with finite elements.\n\
2 We solve the 'Good Cop' Helmholtz problem in a rectangular\n\
3 domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\
4 This example supports automatic convergence estimation\n\
5 and coarse space adaptivity.\n\n\n";
6 
7 /*
8    The model problem:
9       Solve "Good Cop" Helmholtz equation on the unit square: (0,1) x (0,1)
10           - \Delta u + u = f,
11            where \Delta = Laplace operator
12       Dirichlet b.c.'s on all sides
13 
14 */
15 
16 #include <petscdmplex.h>
17 #include <petscsnes.h>
18 #include <petscds.h>
19 #include <petscconvest.h>
20 
21 typedef struct {
22   PetscBool trig; /* Use trig function as exact solution */
23 } AppCtx;
24 
25 /*For Primal Problem*/
26 static void g0_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
27                    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
28                    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
29                    PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
30 {
31   PetscInt d;
32   for (d = 0; d < dim; ++d) g0[0] = 1.0;
33 }
34 
35 static void g3_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
36                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
37                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
38                   PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
39 {
40   PetscInt d;
41   for (d = 0; d < dim; ++d) g3[d*dim+d] = 1.0;
42 }
43 
44 static PetscErrorCode trig_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
45 {
46   PetscInt d;
47   *u = 0.0;
48   for (d = 0; d < dim; ++d) *u += PetscSinReal(2.0*PETSC_PI*x[d]);
49   return 0;
50 }
51 
52 static PetscErrorCode quad_u(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
53 {
54   PetscInt d;
55   *u = 1.0;
56   for (d = 0; d < dim; ++d) *u += (d+1)*PetscSqr(x[d]);
57   return 0;
58 }
59 
60 static void f0_trig_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
61                       const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
62                       const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
63                       PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
64 {
65   PetscInt d;
66   f0[0] += u[0];
67   for (d = 0; d < dim; ++d) f0[0] -= 4.0*PetscSqr(PETSC_PI)*PetscSinReal(2.0*PETSC_PI*x[d]) + PetscSinReal(2.0*PETSC_PI*x[d]);
68 }
69 
70 static void f0_quad_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
71                       const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
72                       const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
73                       PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
74 {
75     PetscInt d;
76     switch (dim) {
77         case 1:
78             f0[0] = 1.0;
79             break;
80         case 2:
81             f0[0] = 5.0;
82             break;
83         case 3:
84             f0[0] = 11.0;
85             break;
86         default:
87             f0[0] = 5.0;
88             break;
89     }
90     f0[0] += u[0];
91     for (d = 0; d < dim; ++d) f0[0] -= (d+1)*PetscSqr(x[d]);
92 }
93 
94 static void f1_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
95                  const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
96                  const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
97                  PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
98 {
99   PetscInt d;
100   for (d = 0; d < dim; ++d) f1[d] = u_x[d];
101 }
102 
103 static PetscErrorCode ProcessOptions(DM dm, AppCtx *options)
104 {
105   MPI_Comm       comm;
106   PetscInt       dim;
107 
108   PetscFunctionBeginUser;
109   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
110   PetscCall(DMGetDimension(dm, &dim));
111   options->trig = PETSC_FALSE;
112 
113   PetscOptionsBegin(comm, "", "Helmholtz Problem Options", "DMPLEX");
114   PetscCall(PetscOptionsBool("-exact_trig", "Use trigonometric exact solution (better for more complex finite elements)", "ex26.c", options->trig, &options->trig, NULL));
115   PetscOptionsEnd();
116 
117   PetscFunctionReturn(0);
118 }
119 
120 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
121 {
122   PetscFunctionBeginUser;
123   PetscCall(DMCreate(comm, dm));
124   PetscCall(DMSetType(*dm, DMPLEX));
125   PetscCall(DMSetFromOptions(*dm));
126 
127   PetscCall(PetscObjectSetName((PetscObject) *dm, "Mesh"));
128   PetscCall(DMSetApplicationContext(*dm, user));
129   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
130 
131   PetscFunctionReturn(0);
132 }
133 
134 static PetscErrorCode SetupPrimalProblem(DM dm, AppCtx *user)
135 {
136   PetscDS        ds;
137   DMLabel        label;
138   const PetscInt id = 1;
139 
140   PetscFunctionBeginUser;
141   PetscCall(DMGetDS(dm, &ds));
142   PetscCall(DMGetLabel(dm, "marker", &label));
143   if (user->trig) {
144     PetscCall(PetscDSSetResidual(ds, 0, f0_trig_u, f1_u));
145     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_uu, NULL, NULL, g3_uu));
146     PetscCall(PetscDSSetExactSolution(ds, 0, trig_u, user));
147     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void)) trig_u, NULL, user, NULL));
148     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Trig Exact Solution\n"));
149   } else {
150     PetscCall(PetscDSSetResidual(ds, 0, f0_quad_u, f1_u));
151     PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_uu, NULL, NULL, g3_uu));
152     PetscCall(PetscDSSetExactSolution(ds, 0, quad_u, user));
153     PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (void (*)(void)) quad_u, NULL, user, NULL));
154   }
155   PetscFunctionReturn(0);
156 }
157 
158 static PetscErrorCode SetupDiscretization(DM dm, const char name[], PetscErrorCode (*setup)(DM, AppCtx *), AppCtx *user)
159 {
160   DM             cdm = dm;
161   PetscFE        fe;
162   DMPolytopeType ct;
163   PetscBool      simplex;
164   PetscInt       dim, cStart;
165   char           prefix[PETSC_MAX_PATH_LEN];
166 
167   PetscFunctionBeginUser;
168   PetscCall(DMGetDimension(dm, &dim));
169 
170   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
171   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
172   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
173   /* Create finite element */
174   PetscCall(PetscSNPrintf(prefix, PETSC_MAX_PATH_LEN, "%s_", name));
175   PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, name ? prefix : NULL, -1, &fe));
176   PetscCall(PetscObjectSetName((PetscObject) fe, name));
177   /* Set discretization and boundary conditions for each mesh */
178   PetscCall(DMSetField(dm, 0, NULL, (PetscObject) fe));
179   PetscCall(DMCreateDS(dm));
180   PetscCall((*setup)(dm, user));
181   while (cdm) {
182     PetscCall(DMCopyDisc(dm,cdm));
183     PetscCall(DMGetCoarseDM(cdm, &cdm));
184   }
185   PetscCall(PetscFEDestroy(&fe));
186   PetscFunctionReturn(0);
187 }
188 
189 int main(int argc, char **argv)
190 {
191     DM             dm;   /* Problem specification */
192     PetscDS        ds;
193     SNES           snes; /* Nonlinear solver */
194     Vec            u;    /* Solutions */
195     AppCtx         user; /* User-defined work context */
196 
197     PetscCall(PetscInitialize(&argc, &argv, NULL, help));
198     /* Primal system */
199     PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
200     PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
201     PetscCall(ProcessOptions(dm, &user));
202     PetscCall(SNESSetDM(snes, dm));
203     PetscCall(SetupDiscretization(dm, "potential", SetupPrimalProblem, &user));
204     PetscCall(DMCreateGlobalVector(dm, &u));
205     PetscCall(VecSet(u, 0.0));
206     PetscCall(PetscObjectSetName((PetscObject) u, "potential"));
207     PetscCall(DMPlexSetSNESLocalFEM(dm, &user, &user, &user));
208     PetscCall(SNESSetFromOptions(snes));
209     PetscCall(DMSNESCheckFromOptions(snes, u));
210 
211     /*Looking for field error*/
212     PetscInt Nfields;
213     PetscCall(DMGetDS(dm, &ds));
214     PetscCall(PetscDSGetNumFields(ds, &Nfields));
215     PetscCall(SNESSolve(snes, NULL, u));
216     PetscCall(SNESGetSolution(snes, &u));
217     PetscCall(VecViewFromOptions(u, NULL, "-potential_view"));
218 
219     /* Cleanup */
220     PetscCall(VecDestroy(&u));
221     PetscCall(SNESDestroy(&snes));
222     PetscCall(DMDestroy(&dm));
223     PetscCall(PetscFinalize());
224     return 0;
225 }
226 
227 /*TEST
228 test:
229   # L_2 convergence rate: 1.9
230   suffix: 2d_p1_conv
231   requires: triangle
232   args: -potential_petscspace_degree 1 -snes_convergence_estimate -dm_refine 2 -convest_num_refine 3 -pc_type lu
233 test:
234   # L_2 convergence rate: 1.9
235   suffix: 2d_q1_conv
236   args: -dm_plex_simplex 0 -potential_petscspace_degree 1 -snes_convergence_estimate -dm_refine 2 -convest_num_refine 3 -pc_type lu
237 test:
238   # Using -convest_num_refine 3 we get L_2 convergence rate: -1.5
239   suffix: 3d_p1_conv
240   requires: ctetgen
241   args: -dm_plex_dim 3 -dm_refine 2 -potential_petscspace_degree 1 -snes_convergence_estimate -convest_num_refine 1 -pc_type lu
242 test:
243   # Using -dm_refine 2 -convest_num_refine 3 we get L_2 convergence rate: -1.2
244   suffix: 3d_q1_conv
245   args: -dm_plex_dim 3 -dm_plex_simplex 0 -dm_refine 2 -potential_petscspace_degree 1 -snes_convergence_estimate -convest_num_refine 1 -pc_type lu
246 test:
247   # L_2 convergence rate: 1.9
248   suffix: 2d_p1_trig_conv
249   requires: triangle
250   args: -potential_petscspace_degree 1 -snes_convergence_estimate -dm_refine 2 -convest_num_refine 3 -pc_type lu -exact_trig
251 test:
252   # L_2 convergence rate: 1.9
253   suffix: 2d_q1_trig_conv
254   args: -dm_plex_simplex 0 -potential_petscspace_degree 1 -snes_convergence_estimate -dm_refine 2 -convest_num_refine 3 -pc_type lu -exact_trig
255 test:
256   # Using -convest_num_refine 3 we get L_2 convergence rate: -1.5
257   suffix: 3d_p1_trig_conv
258   requires: ctetgen
259   args: -dm_plex_dim 3 -dm_refine 2 -potential_petscspace_degree 1 -snes_convergence_estimate -convest_num_refine 1 -pc_type lu -exact_trig
260 test:
261   # Using -dm_refine 2 -convest_num_refine 3 we get L_2 convergence rate: -1.2
262   suffix: 3d_q1_trig_conv
263   args: -dm_plex_dim 3 -dm_plex_simplex 0 -dm_refine 2 -potential_petscspace_degree 1 -snes_convergence_estimate -convest_num_refine 1 -pc_type lu -exact_trig
264 test:
265   suffix: 2d_p1_gmg_vcycle
266   requires: triangle
267   args: -potential_petscspace_degree 1 -dm_plex_box_faces 2,2 -dm_refine_hierarchy 3 \
268     -ksp_type cg -ksp_rtol 1e-10 -pc_type mg \
269     -mg_levels_ksp_max_it 1 \
270     -mg_levels_pc_type jacobi -snes_monitor -ksp_monitor
271 test:
272   suffix: 2d_p1_gmg_fcycle
273   requires: triangle
274   args: -potential_petscspace_degree 1 -dm_plex_box_faces 2,2 -dm_refine_hierarchy 3 \
275     -ksp_type cg -ksp_rtol 1e-10 -pc_type mg -pc_mg_type full \
276     -mg_levels_ksp_max_it 2 \
277     -mg_levels_pc_type jacobi -snes_monitor -ksp_monitor
278 test:
279   suffix: 2d_p1_gmg_vcycle_trig
280   requires: triangle
281   args: -exact_trig -potential_petscspace_degree 1 -dm_plex_box_faces 2,2 -dm_refine_hierarchy 3 \
282     -ksp_type cg -ksp_rtol 1e-10 -pc_type mg \
283     -mg_levels_ksp_max_it 1 \
284     -mg_levels_pc_type jacobi -snes_monitor -ksp_monitor
285 TEST*/
286