xref: /petsc/src/dm/impls/plex/tests/ex19.c (revision cd7e8a5e83fb5f23fbe440fa5d826b1569053b5a) !
1 static char help[] = "Tests mesh adaptation with DMPlex and pragmatic.\n";
2 
3 #include <petsc/private/dmpleximpl.h>
4 
5 #include <petscsnes.h>
6 
7 typedef struct {
8   PetscInt  Nr;         /* The number of refinement passes */
9   PetscInt  metOpt;     /* Different choices of metric */
10   PetscReal hmax, hmin; /* Max and min sizes prescribed by the metric */
11   PetscBool doL2;       /* Test L2 projection */
12 } AppCtx;
13 
14 /*
15 Classic hyperbolic sensor function for testing multi-scale anisotropic mesh adaptation:
16 
17   f:[-1, 1]x[-1, 1] \to R,
18     f(x, y) = sin(50xy)/100 if |xy| > 2\pi/50 else sin(50xy)
19 
20 (mapped to have domain [0,1] x [0,1] in this case).
21 */
22 static PetscErrorCode sensor(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx)
23 {
24   const PetscReal xref = 2.*x[0] - 1.;
25   const PetscReal yref = 2.*x[1] - 1.;
26   const PetscReal xy   = xref*yref;
27 
28   PetscFunctionBeginUser;
29   u[0] = PetscSinReal(50.*xy);
30   if (PetscAbsReal(xy) > 2.*PETSC_PI/50.) u[0] *= 0.01;
31   PetscFunctionReturn(0);
32 }
33 
34 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
35 {
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   options->Nr     = 1;
40   options->metOpt = 1;
41   options->hmin   = 0.05;
42   options->hmax   = 0.5;
43   options->doL2   = PETSC_FALSE;
44 
45   ierr = PetscOptionsBegin(comm, "", "Meshing Adaptation Options", "DMPLEX");CHKERRQ(ierr);
46   ierr = PetscOptionsBoundedInt("-Nr", "Numberof refinement passes", "ex19.c", options->Nr, &options->Nr, NULL, 1);CHKERRQ(ierr);
47   ierr = PetscOptionsBoundedInt("-met", "Different choices of metric", "ex19.c", options->metOpt, &options->metOpt, NULL,0);CHKERRQ(ierr);
48   ierr = PetscOptionsReal("-hmax", "Max size prescribed by the metric", "ex19.c", options->hmax, &options->hmax, NULL);CHKERRQ(ierr);
49   ierr = PetscOptionsReal("-hmin", "Min size prescribed by the metric", "ex19.c", options->hmin, &options->hmin, NULL);CHKERRQ(ierr);
50   ierr = PetscOptionsBool("-do_L2", "Test L2 projection", "ex19.c", options->doL2, &options->doL2, NULL);CHKERRQ(ierr);
51   ierr = PetscOptionsEnd();CHKERRQ(ierr);
52 
53   PetscFunctionReturn(0);
54 }
55 
56 static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm)
57 {
58   PetscErrorCode ierr;
59 
60   PetscFunctionBegin;
61   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
62   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
63   ierr = DMSetFromOptions(*dm);CHKERRQ(ierr);
64   ierr = PetscObjectSetName((PetscObject) *dm, "DMinit");CHKERRQ(ierr);
65   ierr = DMViewFromOptions(*dm, NULL, "-init_dm_view");CHKERRQ(ierr);
66   PetscFunctionReturn(0);
67 }
68 
69 static PetscErrorCode ComputeMetricSensor(DM dm, AppCtx *user, Vec *metric)
70 {
71   PetscSimplePointFunc funcs[1] = {sensor};
72   DM             dmSensor, dmGrad, dmHess;
73   PetscFE        fe;
74   Vec            f, g, H;
75   PetscBool      simplex;
76   PetscInt       dim;
77   PetscErrorCode ierr;
78 
79   PetscFunctionBegin;
80   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
81   ierr = DMPlexIsSimplex(dm, &simplex);CHKERRQ(ierr);
82 
83   ierr = DMClone(dm, &dmSensor);CHKERRQ(ierr);
84   ierr = PetscFECreateLagrange(PETSC_COMM_SELF, dim, 1, simplex, 1, -1, &fe);CHKERRQ(ierr);
85   ierr = DMSetField(dmSensor, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
86   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
87   ierr = DMCreateDS(dmSensor);CHKERRQ(ierr);
88   ierr = DMCreateLocalVector(dmSensor, &f);CHKERRQ(ierr);
89   ierr = DMProjectFunctionLocal(dmSensor, 0., funcs, NULL, INSERT_VALUES, f);CHKERRQ(ierr);
90   ierr = VecViewFromOptions(f, NULL, "-sensor_view");CHKERRQ(ierr);
91 
92   // Recover the gradient of the sensor function
93   ierr = DMClone(dm, &dmGrad);CHKERRQ(ierr);
94   ierr = PetscFECreateLagrange(PETSC_COMM_SELF, dim, dim, simplex, 1, -1, &fe);CHKERRQ(ierr);
95   ierr = DMSetField(dmGrad, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
96   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
97   ierr = DMCreateDS(dmGrad);CHKERRQ(ierr);
98   ierr = DMCreateLocalVector(dmGrad, &g);CHKERRQ(ierr);
99   ierr = DMPlexComputeGradientClementInterpolant(dmSensor, f, g);CHKERRQ(ierr);
100   ierr = VecDestroy(&f);CHKERRQ(ierr);
101   ierr = VecViewFromOptions(g, NULL, "-gradient_view");CHKERRQ(ierr);
102 
103   // Recover the Hessian of the sensor function
104   ierr = DMClone(dm, &dmHess);CHKERRQ(ierr);
105   ierr = DMPlexMetricCreate(dmHess, 0, &H);CHKERRQ(ierr);
106   ierr = DMPlexComputeGradientClementInterpolant(dmGrad, g, H);CHKERRQ(ierr);
107   ierr = VecDestroy(&g);CHKERRQ(ierr);
108   ierr = VecViewFromOptions(H, NULL, "-hessian_view");CHKERRQ(ierr);
109 
110   // Obtain a metric by Lp normalization
111   ierr = DMPlexMetricNormalize(dmHess, H, PETSC_TRUE, PETSC_TRUE, metric);CHKERRQ(ierr);
112   ierr = VecDestroy(&H);CHKERRQ(ierr);
113   ierr = DMDestroy(&dmHess);CHKERRQ(ierr);
114   ierr = DMDestroy(&dmGrad);CHKERRQ(ierr);
115   ierr = DMDestroy(&dmSensor);CHKERRQ(ierr);
116   PetscFunctionReturn(0);
117 }
118 
119 static PetscErrorCode ComputeMetric(DM dm, AppCtx *user, Vec *metric)
120 {
121   PetscReal          lambda = 1/(user->hmax*user->hmax);
122   PetscErrorCode     ierr;
123 
124   PetscFunctionBeginUser;
125   if (user->metOpt == 0) {
126     /* Specify a uniform, isotropic metric */
127     ierr = DMPlexMetricCreateUniform(dm, 0, lambda, metric);CHKERRQ(ierr);
128   } else if (user->metOpt == 3) {
129     ierr = ComputeMetricSensor(dm, user, metric);CHKERRQ(ierr);
130   } else {
131     DM                 cdm;
132     Vec                coordinates;
133     const PetscScalar *coords;
134     PetscScalar       *met;
135     PetscReal          h;
136     PetscInt           vStart, vEnd, v;
137 
138     ierr = DMPlexMetricCreateUniform(dm, 0, lambda, metric);CHKERRQ(ierr);
139     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
140     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
141     ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
142     ierr = VecGetArray(*metric, &met);CHKERRQ(ierr);
143     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
144     for (v = vStart; v < vEnd; ++v) {
145       PetscScalar       *vcoords;
146       PetscScalar       *pmet;
147 
148       ierr = DMPlexPointLocalRead(cdm, v, coords, &vcoords);CHKERRQ(ierr);
149       switch (user->metOpt) {
150       case 1:
151         h = user->hmax - (user->hmax-user->hmin)*PetscRealPart(vcoords[0]);
152         break;
153       case 2:
154         h = user->hmax*PetscAbsReal(((PetscReal) 1.0)-PetscExpReal(-PetscAbsScalar(vcoords[0]-(PetscReal)0.5))) + user->hmin;
155         break;
156       default:
157         SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "metOpt = 0, 1 or 2, cannot be %d", user->metOpt);
158       }
159       lambda = 1/(h*h);
160       ierr = DMPlexPointLocalRef(dm, v, met, &pmet);CHKERRQ(ierr);
161       pmet[0] = lambda;
162     }
163     ierr = VecRestoreArray(*metric, &met);CHKERRQ(ierr);
164     ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
165   }
166   PetscFunctionReturn(0);
167 }
168 
169 static PetscErrorCode linear(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
170 {
171   u[0] = x[0] + x[1];
172   return 0;
173 }
174 
175 static PetscErrorCode TestL2Projection(DM dm, DM dma, AppCtx *user)
176 {
177   PetscErrorCode (*funcs[1])(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *) = {linear};
178   DM               dmProj, dmaProj;
179   PetscFE          fe;
180   KSP              ksp;
181   Mat              Interp, mass, mass2;
182   Vec              u, ua, scaling, rhs, uproj;
183   PetscReal        error;
184   PetscBool        simplex;
185   PetscInt         dim;
186   PetscErrorCode   ierr;
187 
188   PetscFunctionBeginUser;
189   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
190   ierr = DMPlexIsSimplex(dm, &simplex);CHKERRQ(ierr);
191 
192   ierr = DMClone(dm, &dmProj);CHKERRQ(ierr);
193   ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, -1, &fe);CHKERRQ(ierr);
194   ierr = DMSetField(dmProj, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
195   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
196   ierr = DMCreateDS(dmProj);CHKERRQ(ierr);
197 
198   ierr = DMClone(dma, &dmaProj);CHKERRQ(ierr);
199   ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, NULL, -1, &fe);CHKERRQ(ierr);
200   ierr = DMSetField(dmaProj, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
201   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
202   ierr = DMCreateDS(dmaProj);CHKERRQ(ierr);
203 
204   ierr = DMGetGlobalVector(dmProj, &u);CHKERRQ(ierr);
205   ierr = DMGetGlobalVector(dmaProj, &ua);CHKERRQ(ierr);
206   ierr = DMGetGlobalVector(dmaProj, &rhs);CHKERRQ(ierr);
207   ierr = DMGetGlobalVector(dmaProj, &uproj);CHKERRQ(ierr);
208 
209   // Interpolate onto original mesh using dual basis
210   ierr = DMProjectFunction(dmProj, 0.0, funcs, NULL, INSERT_VALUES, u);CHKERRQ(ierr);
211   ierr = PetscObjectSetName((PetscObject) u, "Original");CHKERRQ(ierr);
212   ierr = VecViewFromOptions(u, NULL, "-orig_vec_view");CHKERRQ(ierr);
213   ierr = DMComputeL2Diff(dmProj, 0.0, funcs, NULL, u, &error);CHKERRQ(ierr);
214   ierr = PetscPrintf(PETSC_COMM_WORLD, "Original L2 Error: %g\n", (double) error);CHKERRQ(ierr);
215   // Interpolate onto NEW mesh using dual basis
216   ierr = DMProjectFunction(dmaProj, 0.0, funcs, NULL, INSERT_VALUES, ua);CHKERRQ(ierr);
217   ierr = PetscObjectSetName((PetscObject) ua, "Adapted");CHKERRQ(ierr);
218   ierr = VecViewFromOptions(ua, NULL, "-adapt_vec_view");CHKERRQ(ierr);
219   ierr = DMComputeL2Diff(dmaProj, 0.0, funcs, NULL, ua, &error);CHKERRQ(ierr);
220   ierr = PetscPrintf(PETSC_COMM_WORLD, "Adapted L2 Error: %g\n", (double) error);CHKERRQ(ierr);
221   // Interpolate between meshes using interpolation matrix
222   ierr = DMCreateInterpolation(dmProj, dmaProj, &Interp, &scaling);CHKERRQ(ierr);
223   ierr = MatInterpolate(Interp, u, ua);CHKERRQ(ierr);
224   ierr = MatDestroy(&Interp);CHKERRQ(ierr);
225   ierr = VecDestroy(&scaling);CHKERRQ(ierr);
226   ierr = PetscObjectSetName((PetscObject) ua, "Interpolation");CHKERRQ(ierr);
227   ierr = VecViewFromOptions(ua, NULL, "-interp_vec_view");CHKERRQ(ierr);
228   ierr = DMComputeL2Diff(dmaProj, 0.0, funcs, NULL, ua, &error);CHKERRQ(ierr);
229   ierr = PetscPrintf(PETSC_COMM_WORLD, "Interpolated L2 Error: %g\n", (double) error);CHKERRQ(ierr);
230   // L2 projection
231   ierr = DMCreateMassMatrix(dmaProj, dmaProj, &mass);CHKERRQ(ierr);
232   ierr = MatViewFromOptions(mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
233   ierr = KSPCreate(PETSC_COMM_WORLD, &ksp);CHKERRQ(ierr);
234   ierr = KSPSetOperators(ksp, mass, mass);CHKERRQ(ierr);
235   ierr = KSPSetFromOptions(ksp);CHKERRQ(ierr);
236   //   Compute rhs as M f, could also direclty project the analytic function but we might not have it
237   ierr = DMCreateMassMatrix(dmProj, dmaProj, &mass2);CHKERRQ(ierr);
238   ierr = MatMult(mass2, u, rhs);CHKERRQ(ierr);
239   ierr = MatDestroy(&mass2);CHKERRQ(ierr);
240   ierr = KSPSolve(ksp, rhs, uproj);CHKERRQ(ierr);
241   ierr = PetscObjectSetName((PetscObject) uproj, "L_2 Projection");CHKERRQ(ierr);
242   ierr = VecViewFromOptions(uproj, NULL, "-proj_vec_view");CHKERRQ(ierr);
243   ierr = DMComputeL2Diff(dmaProj, 0.0, funcs, NULL, uproj, &error);CHKERRQ(ierr);
244   ierr = PetscPrintf(PETSC_COMM_WORLD, "Projected L2 Error: %g\n", (double) error);CHKERRQ(ierr);
245   ierr = KSPDestroy(&ksp);CHKERRQ(ierr);
246   ierr = MatDestroy(&mass);CHKERRQ(ierr);
247   ierr = DMRestoreGlobalVector(dmProj, &u);CHKERRQ(ierr);
248   ierr = DMRestoreGlobalVector(dmaProj, &ua);CHKERRQ(ierr);
249   ierr = DMRestoreGlobalVector(dmaProj, &rhs);CHKERRQ(ierr);
250   ierr = DMRestoreGlobalVector(dmaProj, &uproj);CHKERRQ(ierr);
251   ierr = DMDestroy(&dmProj);CHKERRQ(ierr);
252   ierr = DMDestroy(&dmaProj);CHKERRQ(ierr);
253   PetscFunctionReturn(0);
254 }
255 
256 int main (int argc, char * argv[]) {
257   DM             dm;
258   AppCtx         user;                 /* user-defined work context */
259   MPI_Comm       comm;
260   DM             dma, odm;
261   Vec            metric;
262   PetscInt       r;
263   PetscErrorCode ierr;
264 
265   ierr = PetscInitialize(&argc, &argv, NULL, help);if (ierr) return ierr;
266   comm = PETSC_COMM_WORLD;
267   ierr = ProcessOptions(comm, &user);CHKERRQ(ierr);
268   ierr = CreateMesh(comm, &dm);CHKERRQ(ierr);
269 
270   odm  = dm;
271   ierr = DMPlexDistributeOverlap(odm, 1, NULL, &dm);CHKERRQ(ierr);
272   if (!dm) {dm = odm;}
273   else     {ierr = DMDestroy(&odm);CHKERRQ(ierr);}
274 
275   for (r = 0; r < user.Nr; ++r) {
276     DMLabel label;
277 
278     ierr = ComputeMetric(dm, &user, &metric);CHKERRQ(ierr);
279     ierr = DMGetLabel(dm, "marker", &label);CHKERRQ(ierr);
280     ierr = DMAdaptMetric(dm, metric, label, &dma);CHKERRQ(ierr);
281     ierr = VecDestroy(&metric);CHKERRQ(ierr);
282     ierr = PetscObjectSetName((PetscObject) dma, "DMadapt");CHKERRQ(ierr);
283     ierr = PetscObjectSetOptionsPrefix((PetscObject) dma, "adapt_");CHKERRQ(ierr);
284     ierr = DMViewFromOptions(dma, NULL, "-dm_view");CHKERRQ(ierr);
285     if (user.doL2) {ierr = TestL2Projection(dm, dma, &user);CHKERRQ(ierr);}
286     ierr = DMDestroy(&dm);CHKERRQ(ierr);
287     dm   = dma;
288   }
289   ierr = PetscObjectSetOptionsPrefix((PetscObject) dm, "final_");CHKERRQ(ierr);
290   ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);
291   ierr = DMDestroy(&dm);CHKERRQ(ierr);
292   ierr = PetscFinalize();
293   return ierr;
294 }
295 
296 /*TEST
297 
298   build:
299     requires: pragmatic
300 
301   testset:
302     args: -dm_plex_box_faces 4,4,4 -met 2 -init_dm_view -adapt_dm_view
303 
304     test:
305       suffix: 0
306       args: -dm_plex_separate_marker 0
307     test:
308       suffix: 1
309       args: -dm_plex_separate_marker 1
310     test:
311       suffix: 2
312       args: -dm_plex_dim 3
313     test:
314       suffix: 3
315       args: -dm_plex_dim 3
316 
317   # Pragmatic hangs for simple partitioner
318   testset:
319     requires: parmetis
320     args: -dm_plex_box_faces 2,2 -dm_distribute -petscpartitioner_type parmetis -met 2 -init_dm_view -adapt_dm_view
321 
322     test:
323       suffix: 4
324       nsize: 2
325     test:
326       suffix: 5
327       nsize: 4
328 
329   test:
330     suffix: 6
331     nsize: 2
332     args: -dm_plex_dim 3 -dm_plex_box_faces 9,9,9 -dm_distribute -petscpartitioner_type parmetis \
333           -met 0 -hmin 0.01 -hmax 0.03 -init_dm_view -adapt_dm_view
334   test:
335     suffix: 7
336     nsize: 2
337     args: -dm_plex_box_faces 19,19 -dm_distribute -petscpartitioner_type parmetis \
338           -met 2 -hmax 0.5 -hmin 0.001 -init_dm_view -adapt_dm_view
339   test:
340     suffix: proj_0
341     args: -dm_plex_box_faces 2,2 -dm_plex_hash_location -init_dm_view -adapt_dm_view -do_L2 \
342           -petscspace_degree 1 -petscfe_default_quadrature_order 1 -pc_type lu
343   test:
344     suffix: proj_1
345     args: -dm_plex_box_faces 4,4 -dm_plex_hash_location -init_dm_view -adapt_dm_view -do_L2 \
346           -petscspace_degree 1 -petscfe_default_quadrature_order 1 -pc_type lu
347 
348   test:
349     suffix: sensor
350     args: -dm_plex_box_faces 9,9 -met 3 -init_dm_view -adapt_dm_view \
351           -dm_plex_metric_h_min 1.e-10 -dm_plex_metric_h_max 1.0e-01 -dm_plex_metric_a_max 1.0e+05 -dm_plex_metric_p 1.0 \
352             -dm_plex_metric_target_complexity 10000.0
353 
354 TEST*/
355