xref: /petsc/src/dm/field/interface/dmfield.c (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888)
1 #include <petsc/private/dmfieldimpl.h> /*I "petscdmfield.h" I*/
2 #include <petsc/private/petscfeimpl.h> /*I "petscdmfield.h" I*/
3 #include <petscdmplex.h>
4 
5 const char *const DMFieldContinuities[] = {"VERTEX", "EDGE", "FACET", "CELL", NULL};
6 
7 PETSC_INTERN PetscErrorCode DMFieldCreate(DM dm, PetscInt numComponents, DMFieldContinuity continuity, DMField *field)
8 {
9   DMField b;
10 
11   PetscFunctionBegin;
12   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13   PetscAssertPointer(field, 4);
14   PetscCall(DMFieldInitializePackage());
15 
16   PetscCall(PetscHeaderCreate(b, DMFIELD_CLASSID, "DMField", "Field over DM", "DM", PetscObjectComm((PetscObject)dm), DMFieldDestroy, DMFieldView));
17   PetscCall(PetscObjectReference((PetscObject)dm));
18   b->dm            = dm;
19   b->continuity    = continuity;
20   b->numComponents = numComponents;
21   *field           = b;
22   PetscFunctionReturn(PETSC_SUCCESS);
23 }
24 
25 /*@
26   DMFieldDestroy - destroy a `DMField`
27 
28   Collective
29 
30   Input Parameter:
31 . field - address of `DMField`
32 
33   Level: advanced
34 
35 .seealso: `DMField`, `DMFieldCreate()`
36 @*/
37 PetscErrorCode DMFieldDestroy(DMField *field)
38 {
39   PetscFunctionBegin;
40   if (!*field) PetscFunctionReturn(PETSC_SUCCESS);
41   PetscValidHeaderSpecific(*field, DMFIELD_CLASSID, 1);
42   if (--((PetscObject)*field)->refct > 0) {
43     *field = NULL;
44     PetscFunctionReturn(PETSC_SUCCESS);
45   }
46   PetscTryTypeMethod(*field, destroy);
47   PetscCall(DMDestroy(&((*field)->dm)));
48   PetscCall(PetscHeaderDestroy(field));
49   PetscFunctionReturn(PETSC_SUCCESS);
50 }
51 
52 /*@C
53   DMFieldView - view a `DMField`
54 
55   Collective
56 
57   Input Parameters:
58 + field  - `DMField`
59 - viewer - viewer to display field, for example `PETSC_VIEWER_STDOUT_WORLD`
60 
61   Level: advanced
62 
63 .seealso: `DMField`, `DMFieldCreate()`
64 @*/
65 PetscErrorCode DMFieldView(DMField field, PetscViewer viewer)
66 {
67   PetscBool iascii;
68 
69   PetscFunctionBegin;
70   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
71   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)field), &viewer));
72   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
73   PetscCheckSameComm(field, 1, viewer, 2);
74   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
75   if (iascii) {
76     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)field, viewer));
77     PetscCall(PetscViewerASCIIPushTab(viewer));
78     PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " components\n", field->numComponents));
79     PetscCall(PetscViewerASCIIPrintf(viewer, "%s continuity\n", DMFieldContinuities[field->continuity]));
80     PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_DEFAULT));
81     PetscCall(DMView(field->dm, viewer));
82     PetscCall(PetscViewerPopFormat(viewer));
83   }
84   PetscTryTypeMethod(field, view, viewer);
85   if (iascii) PetscCall(PetscViewerASCIIPopTab(viewer));
86   PetscFunctionReturn(PETSC_SUCCESS);
87 }
88 
89 /*@C
90   DMFieldSetType - set the `DMField` implementation
91 
92   Collective
93 
94   Input Parameters:
95 + field - the `DMField` context
96 - type  - a known method
97 
98   Level: advanced
99 
100   Notes:
101   See "include/petscvec.h" for available methods (for instance)
102 +    `DMFIELDDA`    - a field defined only by its values at the corners of a `DMDA`
103 .    `DMFIELDDS`    - a field defined by a discretization over a mesh set with `DMSetField()`
104 -    `DMFIELDSHELL` - a field defined by arbitrary callbacks
105 
106 .seealso: `DMField`, `DMFieldGetType()`, `DMFieldType`,
107 @*/
108 PetscErrorCode DMFieldSetType(DMField field, DMFieldType type)
109 {
110   PetscBool match;
111   PetscErrorCode (*r)(DMField);
112 
113   PetscFunctionBegin;
114   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
115   PetscAssertPointer(type, 2);
116 
117   PetscCall(PetscObjectTypeCompare((PetscObject)field, type, &match));
118   if (match) PetscFunctionReturn(PETSC_SUCCESS);
119 
120   PetscCall(PetscFunctionListFind(DMFieldList, type, &r));
121   PetscCheck(r, PetscObjectComm((PetscObject)field), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested DMField type %s", type);
122   /* Destroy the previous private DMField context */
123   PetscTryTypeMethod(field, destroy);
124 
125   PetscCall(PetscMemzero(field->ops, sizeof(*field->ops)));
126   PetscCall(PetscObjectChangeTypeName((PetscObject)field, type));
127   field->ops->create = r;
128   PetscCall((*r)(field));
129   PetscFunctionReturn(PETSC_SUCCESS);
130 }
131 
132 /*@C
133   DMFieldGetType - Gets the `DMFieldType` name (as a string) from the `DMField`.
134 
135   Not Collective
136 
137   Input Parameter:
138 . field - The `DMField` context
139 
140   Output Parameter:
141 . type - The `DMFieldType` name
142 
143   Level: advanced
144 
145 .seealso: `DMField`, `DMFieldSetType()`, `DMFieldType`
146 @*/
147 PetscErrorCode DMFieldGetType(DMField field, DMFieldType *type)
148 {
149   PetscFunctionBegin;
150   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
151   PetscAssertPointer(type, 2);
152   PetscCall(DMFieldRegisterAll());
153   *type = ((PetscObject)field)->type_name;
154   PetscFunctionReturn(PETSC_SUCCESS);
155 }
156 
157 /*@
158   DMFieldGetNumComponents - Returns the number of components in the field
159 
160   Not Collective
161 
162   Input Parameter:
163 . field - The `DMField` object
164 
165   Output Parameter:
166 . nc - The number of field components
167 
168   Level: intermediate
169 
170 .seealso: `DMField`, `DMFieldEvaluate()`
171 @*/
172 PetscErrorCode DMFieldGetNumComponents(DMField field, PetscInt *nc)
173 {
174   PetscFunctionBegin;
175   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
176   PetscAssertPointer(nc, 2);
177   *nc = field->numComponents;
178   PetscFunctionReturn(PETSC_SUCCESS);
179 }
180 
181 /*@
182   DMFieldGetDM - Returns the `DM` for the manifold over which the field is defined.
183 
184   Not Collective
185 
186   Input Parameter:
187 . field - The `DMField` object
188 
189   Output Parameter:
190 . dm - The `DM` object
191 
192   Level: intermediate
193 
194 .seealso: `DMField`, `DM`, `DMFieldEvaluate()`
195 @*/
196 PetscErrorCode DMFieldGetDM(DMField field, DM *dm)
197 {
198   PetscFunctionBegin;
199   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
200   PetscAssertPointer(dm, 2);
201   *dm = field->dm;
202   PetscFunctionReturn(PETSC_SUCCESS);
203 }
204 
205 /*@
206   DMFieldEvaluate - Evaluate the field and its derivatives on a set of points
207 
208   Collective
209 
210   Input Parameters:
211 + field    - The `DMField` object
212 . points   - The points at which to evaluate the field.  Should have size d x n,
213            where d is the coordinate dimension of the manifold and n is the number
214            of points
215 - datatype - The PetscDataType of the output arrays: either `PETSC_REAL` or `PETSC_SCALAR`.
216              If the field is complex and datatype is `PETSC_REAL`, the real part of the
217              field is returned.
218 
219   Output Parameters:
220 + B - pointer to data of size c * n * sizeof(datatype), where c is the number of components in the field.
221       If B is not NULL, the values of the field are written in this array, varying first by component,
222       then by point.
223 . D - pointer to data of size d * c * n * sizeof(datatype).
224       If D is not NULL, the values of the field's spatial derivatives are written in this array,
225       varying first by the partial derivative component, then by field component, then by point.
226 - H - pointer to data of size d * d * c * n * sizeof(datatype).
227       If H is not NULL, the values of the field's second spatial derivatives are written in this array,
228       varying first by the second partial derivative component, then by field component, then by point.
229 
230   Level: intermediate
231 
232 .seealso: `DMField`, `DMFieldGetDM()`, `DMFieldGetNumComponents()`, `DMFieldEvaluateFE()`, `DMFieldEvaluateFV()`, `PetscDataType`
233 @*/
234 PetscErrorCode DMFieldEvaluate(DMField field, Vec points, PetscDataType datatype, void *B, void *D, void *H)
235 {
236   PetscFunctionBegin;
237   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
238   PetscValidHeaderSpecific(points, VEC_CLASSID, 2);
239   if (B) PetscAssertPointer(B, 4);
240   if (D) PetscAssertPointer(D, 5);
241   if (H) PetscAssertPointer(H, 6);
242   PetscUseTypeMethod(field, evaluate, points, datatype, B, D, H);
243   PetscFunctionReturn(PETSC_SUCCESS);
244 }
245 
246 /*@
247   DMFieldEvaluateFE - Evaluate the field and its derivatives on a set of points mapped from
248   quadrature points on a reference point.  The derivatives are taken with respect to the
249   reference coordinates.
250 
251   Not Collective
252 
253   Input Parameters:
254 + field    - The `DMField` object
255 . cellIS   - Index set for cells on which to evaluate the field
256 . points   - The quadature containing the points in the reference cell at which to evaluate the field.
257 - datatype - The PetscDataType of the output arrays: either `PETSC_REAL` or `PETSC_SCALAR`.
258              If the field is complex and datatype is `PETSC_REAL`, the real part of the
259              field is returned.
260 
261   Output Parameters:
262 + B - pointer to data of size c * n * sizeof(datatype), where c is the number of components in the field.
263       If B is not `NULL`, the values of the field are written in this array, varying first by component,
264       then by point.
265 . D - pointer to data of size d * c * n * sizeof(datatype).
266       If D is not `NULL`, the values of the field's spatial derivatives are written in this array,
267       varying first by the partial derivative component, then by field component, then by point.
268 - H - pointer to data of size d * d * c * n * sizeof(datatype).
269       If H is not `NULL`, the values of the field's second spatial derivatives are written in this array,
270       varying first by the second partial derivative component, then by field component, then by point.
271 
272   Level: intermediate
273 
274 .seealso: `DMField`, `DM`, `DMFieldGetNumComponents()`, `DMFieldEvaluate()`, `DMFieldEvaluateFV()`
275 @*/
276 PetscErrorCode DMFieldEvaluateFE(DMField field, IS cellIS, PetscQuadrature points, PetscDataType datatype, void *B, void *D, void *H)
277 {
278   PetscFunctionBegin;
279   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
280   PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2);
281   PetscValidHeader(points, 3);
282   if (B) PetscAssertPointer(B, 5);
283   if (D) PetscAssertPointer(D, 6);
284   if (H) PetscAssertPointer(H, 7);
285   PetscUseTypeMethod(field, evaluateFE, cellIS, points, datatype, B, D, H);
286   PetscFunctionReturn(PETSC_SUCCESS);
287 }
288 
289 /*@
290   DMFieldEvaluateFV - Evaluate the mean of a field and its finite volume derivatives on a set of points.
291 
292   Not Collective
293 
294   Input Parameters:
295 + field    - The `DMField` object
296 . cellIS   - Index set for cells on which to evaluate the field
297 - datatype - The PetscDataType of the output arrays: either `PETSC_REAL` or `PETSC_SCALAR`.
298              If the field is complex and datatype is `PETSC_REAL`, the real part of the
299              field is returned.
300 
301   Output Parameters:
302 + B - pointer to data of size c * n * sizeof(datatype), where c is the number of components in the field.
303       If B is not `NULL`, the values of the field are written in this array, varying first by component,
304       then by point.
305 . D - pointer to data of size d * c * n * sizeof(datatype).
306       If D is not `NULL`, the values of the field's spatial derivatives are written in this array,
307       varying first by the partial derivative component, then by field component, then by point.
308 - H - pointer to data of size d * d * c * n * sizeof(datatype).
309       If H is not `NULL`, the values of the field's second spatial derivatives are written in this array,
310       varying first by the second partial derivative component, then by field component, then by point.
311 
312   Level: intermediate
313 
314 .seealso: `DMField`, `IS`, `DMFieldGetNumComponents()`, `DMFieldEvaluate()`, `DMFieldEvaluateFE()`, `PetscDataType`
315 @*/
316 PetscErrorCode DMFieldEvaluateFV(DMField field, IS cellIS, PetscDataType datatype, void *B, void *D, void *H)
317 {
318   PetscFunctionBegin;
319   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
320   PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2);
321   if (B) PetscAssertPointer(B, 4);
322   if (D) PetscAssertPointer(D, 5);
323   if (H) PetscAssertPointer(H, 6);
324   PetscUseTypeMethod(field, evaluateFV, cellIS, datatype, B, D, H);
325   PetscFunctionReturn(PETSC_SUCCESS);
326 }
327 
328 /*@
329   DMFieldGetDegree - Get the polynomial degree of a field when pulled back onto the
330   reference element
331 
332   Not Collective
333 
334   Input Parameters:
335 + field  - the `DMField` object
336 - cellIS - the index set of points over which we want know the invariance
337 
338   Output Parameters:
339 + minDegree - the degree of the largest polynomial space contained in the field on each element
340 - maxDegree - the largest degree of the smallest polynomial space containing the field on any element
341 
342   Level: intermediate
343 
344 .seealso: `DMField`, `IS`, `DMFieldEvaluateFE()`
345 @*/
346 PetscErrorCode DMFieldGetDegree(DMField field, IS cellIS, PetscInt *minDegree, PetscInt *maxDegree)
347 {
348   PetscFunctionBegin;
349   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
350   PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2);
351   if (minDegree) PetscAssertPointer(minDegree, 3);
352   if (maxDegree) PetscAssertPointer(maxDegree, 4);
353 
354   if (minDegree) *minDegree = -1;
355   if (maxDegree) *maxDegree = PETSC_MAX_INT;
356 
357   PetscTryTypeMethod(field, getDegree, cellIS, minDegree, maxDegree);
358   PetscFunctionReturn(PETSC_SUCCESS);
359 }
360 
361 /*@
362   DMFieldCreateDefaultQuadrature - Creates a quadrature sufficient to integrate the field on the selected
363   points via pullback onto the reference element
364 
365   Not Collective
366 
367   Input Parameters:
368 + field   - the `DMField` object
369 - pointIS - the index set of points over which we wish to integrate the field
370 
371   Output Parameter:
372 . quad - a `PetscQuadrature` object
373 
374   Level: developer
375 
376 .seealso: `DMField`, `PetscQuadrature`, `IS`, `DMFieldEvaluteFE()`, `DMFieldGetDegree()`
377 @*/
378 PetscErrorCode DMFieldCreateDefaultQuadrature(DMField field, IS pointIS, PetscQuadrature *quad)
379 {
380   PetscFunctionBegin;
381   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
382   PetscValidHeaderSpecific(pointIS, IS_CLASSID, 2);
383   PetscAssertPointer(quad, 3);
384 
385   *quad = NULL;
386   PetscTryTypeMethod(field, createDefaultQuadrature, pointIS, quad);
387   PetscFunctionReturn(PETSC_SUCCESS);
388 }
389 
390 /*@C
391   DMFieldCreateFEGeom - Compute and create the geometric factors of a coordinate field
392 
393   Not Collective
394 
395   Input Parameters:
396 + field    - the `DMField` object
397 . pointIS  - the index set of points over which we wish to integrate the field
398 . quad     - the quadrature points at which to evaluate the geometric factors
399 - faceData - whether additional data for facets (the normal vectors and adjacent cells) should
400   be calculated
401 
402   Output Parameter:
403 . geom - the geometric factors
404 
405   Level: developer
406 
407 .seealso: `DMField`, `PetscQuadrature`, `IS`, `PetscFEGeom`, `DMFieldEvaluateFE()`, `DMFieldCreateDefaulteQuadrature()`, `DMFieldGetDegree()`
408 @*/
409 PetscErrorCode DMFieldCreateFEGeom(DMField field, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
410 {
411   PetscInt     dim, dE;
412   PetscInt     nPoints;
413   PetscInt     maxDegree;
414   PetscFEGeom *g;
415 
416   PetscFunctionBegin;
417   PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 1);
418   PetscValidHeaderSpecific(pointIS, IS_CLASSID, 2);
419   PetscValidHeader(quad, 3);
420   PetscCall(ISGetLocalSize(pointIS, &nPoints));
421   dE = field->numComponents;
422   PetscCall(PetscFEGeomCreate(quad, nPoints, dE, faceData, &g));
423   PetscCall(DMFieldEvaluateFE(field, pointIS, quad, PETSC_REAL, g->v, g->J, NULL));
424   dim = g->dim;
425   if (dE > dim) {
426     /* space out J and make square Jacobians */
427     PetscInt i, j, k, N = g->numPoints * g->numCells;
428 
429     for (i = N - 1; i >= 0; i--) {
430       PetscReal J[9] = {0};
431 
432       for (j = 0; j < dE; j++) {
433         for (k = 0; k < dim; k++) J[j * dE + k] = g->J[i * dE * dim + j * dim + k];
434       }
435       switch (dim) {
436       case 0:
437         for (j = 0; j < dE; j++) {
438           for (k = 0; k < dE; k++) J[j * dE + k] = (j == k) ? 1. : 0.;
439         }
440         break;
441       case 1:
442         if (dE == 2) {
443           PetscReal norm = PetscSqrtReal(J[0] * J[0] + J[2] * J[2]);
444 
445           J[1] = -J[2] / norm;
446           J[3] = J[0] / norm;
447         } else {
448           PetscReal inorm = 1. / PetscSqrtReal(J[0] * J[0] + J[3] * J[3] + J[6] * J[6]);
449           PetscReal x     = J[0] * inorm;
450           PetscReal y     = J[3] * inorm;
451           PetscReal z     = J[6] * inorm;
452 
453           if (x > 0.) {
454             PetscReal inv1pX = 1. / (1. + x);
455 
456             J[1] = -y;
457             J[2] = -z;
458             J[4] = 1. - y * y * inv1pX;
459             J[5] = -y * z * inv1pX;
460             J[7] = -y * z * inv1pX;
461             J[8] = 1. - z * z * inv1pX;
462           } else {
463             PetscReal inv1mX = 1. / (1. - x);
464 
465             J[1] = z;
466             J[2] = y;
467             J[4] = -y * z * inv1mX;
468             J[5] = 1. - y * y * inv1mX;
469             J[7] = 1. - z * z * inv1mX;
470             J[8] = -y * z * inv1mX;
471           }
472         }
473         break;
474       case 2: {
475         PetscReal inorm;
476 
477         J[2] = J[3] * J[7] - J[6] * J[4];
478         J[5] = J[6] * J[1] - J[0] * J[7];
479         J[8] = J[0] * J[4] - J[3] * J[1];
480 
481         inorm = 1. / PetscSqrtReal(J[2] * J[2] + J[5] * J[5] + J[8] * J[8]);
482 
483         J[2] *= inorm;
484         J[5] *= inorm;
485         J[8] *= inorm;
486       } break;
487       }
488       for (j = 0; j < dE * dE; j++) g->J[i * dE * dE + j] = J[j];
489     }
490   }
491   PetscCall(PetscFEGeomComplete(g));
492   PetscCall(DMFieldGetDegree(field, pointIS, NULL, &maxDegree));
493   g->isAffine = (maxDegree <= 1) ? PETSC_TRUE : PETSC_FALSE;
494   if (faceData) PetscUseTypeMethod(field, computeFaceData, pointIS, quad, g);
495   *geom = g;
496   PetscFunctionReturn(PETSC_SUCCESS);
497 }
498