xref: /petsc/src/dm/interface/dmceed.c (revision 607e733f3db3ee7f6f605a13295c517df8dbb9c9)
1 #include <petsc/private/dmimpl.h> /*I      "petscdm.h"          I*/
2 #include <petscdmceed.h>
3 
4 #ifdef PETSC_HAVE_LIBCEED
5   #include <petsc/private/dmpleximpl.h>
6   #include <petscdmplexceed.h>
7   #include <petscfeceed.h>
8 
9 /*@C
10   DMGetCeed - Get the LibCEED context associated with this `DM`
11 
12   Not Collective
13 
14   Input Parameter:
15 . DM   - The `DM`
16 
17   Output Parameter:
18 . ceed - The LibCEED context
19 
20   Level: intermediate
21 
22 .seealso: `DM`, `DMCreate()`
23 @*/
24 PetscErrorCode DMGetCeed(DM dm, Ceed *ceed)
25 {
26   PetscFunctionBegin;
27   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28   PetscAssertPointer(ceed, 2);
29   if (!dm->ceed) {
30     char        ceedresource[PETSC_MAX_PATH_LEN]; /* libCEED resource specifier */
31     const char *prefix;
32 
33     PetscCall(PetscStrncpy(ceedresource, "/cpu/self", sizeof(ceedresource)));
34     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
35     PetscCall(PetscOptionsGetString(NULL, prefix, "-dm_ceed", ceedresource, sizeof(ceedresource), NULL));
36     PetscCallCEED(CeedInit(ceedresource, &dm->ceed));
37   }
38   *ceed = dm->ceed;
39   PetscFunctionReturn(PETSC_SUCCESS);
40 }
41 
42 static CeedMemType PetscMemType2Ceed(PetscMemType mem_type)
43 {
44   return PetscMemTypeDevice(mem_type) ? CEED_MEM_DEVICE : CEED_MEM_HOST;
45 }
46 
47 PetscErrorCode VecGetCeedVector(Vec X, Ceed ceed, CeedVector *cx)
48 {
49   PetscMemType memtype;
50   PetscScalar *x;
51   PetscInt     n;
52 
53   PetscFunctionBegin;
54   PetscCall(VecGetLocalSize(X, &n));
55   PetscCall(VecGetArrayAndMemType(X, &x, &memtype));
56   PetscCallCEED(CeedVectorCreate(ceed, n, cx));
57   PetscCallCEED(CeedVectorSetArray(*cx, PetscMemType2Ceed(memtype), CEED_USE_POINTER, x));
58   PetscFunctionReturn(PETSC_SUCCESS);
59 }
60 
61 PetscErrorCode VecRestoreCeedVector(Vec X, CeedVector *cx)
62 {
63   PetscFunctionBegin;
64   PetscCall(VecRestoreArrayAndMemType(X, NULL));
65   PetscCallCEED(CeedVectorDestroy(cx));
66   PetscFunctionReturn(PETSC_SUCCESS);
67 }
68 
69 PetscErrorCode VecGetCeedVectorRead(Vec X, Ceed ceed, CeedVector *cx)
70 {
71   PetscMemType       memtype;
72   const PetscScalar *x;
73   PetscInt           n;
74 
75   PetscFunctionBegin;
76   PetscCall(VecGetLocalSize(X, &n));
77   PetscCall(VecGetArrayReadAndMemType(X, &x, &memtype));
78   PetscCallCEED(CeedVectorCreate(ceed, n, cx));
79   PetscCallCEED(CeedVectorSetArray(*cx, PetscMemType2Ceed(memtype), CEED_USE_POINTER, (PetscScalar *)x));
80   PetscFunctionReturn(PETSC_SUCCESS);
81 }
82 
83 PetscErrorCode VecRestoreCeedVectorRead(Vec X, CeedVector *cx)
84 {
85   PetscFunctionBegin;
86   PetscCall(VecRestoreArrayReadAndMemType(X, NULL));
87   PetscCallCEED(CeedVectorDestroy(cx));
88   PetscFunctionReturn(PETSC_SUCCESS);
89 }
90 
91 CEED_QFUNCTION(Geometry2D)(PetscCtx ctx, const CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out)
92 {
93   const CeedScalar *x = in[0], *Jac = in[1], *w = in[2];
94   CeedScalar       *qdata = out[0];
95 
96   CeedPragmaSIMD for (CeedInt i = 0; i < Q; ++i)
97   {
98     const CeedScalar J[2][2] = {
99       {Jac[i + Q * 0], Jac[i + Q * 2]},
100       {Jac[i + Q * 1], Jac[i + Q * 3]}
101     };
102     const CeedScalar det = J[0][0] * J[1][1] - J[0][1] * J[1][0];
103 
104     qdata[i + Q * 0] = det * w[i];
105     qdata[i + Q * 1] = x[i + Q * 0];
106     qdata[i + Q * 2] = x[i + Q * 1];
107     qdata[i + Q * 3] = J[1][1] / det;
108     qdata[i + Q * 4] = -J[1][0] / det;
109     qdata[i + Q * 5] = -J[0][1] / det;
110     qdata[i + Q * 6] = J[0][0] / det;
111   }
112   return CEED_ERROR_SUCCESS;
113 }
114 
115 CEED_QFUNCTION(Geometry3D)(PetscCtx ctx, const CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out)
116 {
117   const CeedScalar *Jac = in[1], *w = in[2];
118   CeedScalar       *qdata = out[0];
119 
120   CeedPragmaSIMD for (CeedInt i = 0; i < Q; ++i)
121   {
122     const CeedScalar J[3][3] = {
123       {Jac[i + Q * 0], Jac[i + Q * 3], Jac[i + Q * 6]},
124       {Jac[i + Q * 1], Jac[i + Q * 4], Jac[i + Q * 7]},
125       {Jac[i + Q * 2], Jac[i + Q * 5], Jac[i + Q * 8]}
126     };
127     const CeedScalar det = J[0][0] * (J[1][1] * J[2][2] - J[1][2] * J[2][1]) + J[0][1] * (J[1][2] * J[2][0] - J[1][0] * J[2][2]) + J[0][2] * (J[1][0] * J[2][1] - J[1][1] * J[2][0]);
128 
129     qdata[i + Q * 0] = det * w[i]; /* det J * weight */
130   }
131   return CEED_ERROR_SUCCESS;
132 }
133 
134 static PetscErrorCode DMCeedCreateGeometry(DM dm, IS cellIS, PetscInt *Nqdata, CeedElemRestriction *erq, CeedVector *qd, DMCeed *soldata)
135 {
136   Ceed              ceed;
137   DMCeed            sd;
138   PetscDS           ds;
139   PetscFE           fe;
140   CeedQFunctionUser geom     = NULL;
141   const char       *geomName = NULL;
142   const PetscInt   *cells;
143   PetscInt          dim, cdim, cStart, cEnd, Ncell;
144   CeedInt           Nq;
145 
146   PetscFunctionBegin;
147   PetscCall(PetscCalloc1(1, &sd));
148   PetscCall(DMGetDimension(dm, &dim));
149   PetscCall(DMGetCoordinateDim(dm, &cdim));
150   PetscCall(DMGetCeed(dm, &ceed));
151   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
152   Ncell = cEnd - cStart;
153 
154   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL));
155   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
156   PetscCall(PetscFEGetCeedBasis(fe, &sd->basis));
157   PetscCall(CeedBasisGetNumQuadraturePoints(sd->basis, &Nq));
158   PetscCall(DMPlexGetCeedRestriction(dm, NULL, 0, 0, 0, &sd->er));
159 
160   *Nqdata = 1 + cdim + cdim * dim; // |J| * w_q, x, J^{-1}
161   PetscCallCEED(CeedElemRestrictionCreateStrided(ceed, Ncell, Nq, *Nqdata, Ncell * Nq * (*Nqdata), CEED_STRIDES_BACKEND, erq));
162 
163   switch (dim) {
164   case 2:
165     geom     = Geometry2D;
166     geomName = Geometry2D_loc;
167     break;
168   case 3:
169     geom     = Geometry3D;
170     geomName = Geometry3D_loc;
171     break;
172   }
173   PetscCallCEED(CeedQFunctionCreateInterior(ceed, 1, geom, geomName, &sd->qf));
174   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "x", cdim, CEED_EVAL_INTERP));
175   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "dx", cdim * dim, CEED_EVAL_GRAD));
176   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "weight", 1, CEED_EVAL_WEIGHT));
177   PetscCallCEED(CeedQFunctionAddOutput(sd->qf, "qdata", *Nqdata, CEED_EVAL_NONE));
178 
179   PetscCallCEED(CeedOperatorCreate(ceed, sd->qf, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &sd->op));
180   PetscCallCEED(CeedOperatorSetField(sd->op, "x", sd->er, sd->basis, CEED_VECTOR_ACTIVE));
181   PetscCallCEED(CeedOperatorSetField(sd->op, "dx", sd->er, sd->basis, CEED_VECTOR_ACTIVE));
182   PetscCallCEED(CeedOperatorSetField(sd->op, "weight", CEED_ELEMRESTRICTION_NONE, sd->basis, CEED_VECTOR_NONE));
183   PetscCallCEED(CeedOperatorSetField(sd->op, "qdata", *erq, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE));
184 
185   PetscCallCEED(CeedElemRestrictionCreateVector(*erq, qd, NULL));
186   *soldata = sd;
187   PetscFunctionReturn(PETSC_SUCCESS);
188 }
189 
190 PetscErrorCode DMRefineHook_Ceed(DM coarse, DM fine, PetscCtx ctx)
191 {
192   PetscFunctionBegin;
193   if (coarse->dmceed) PetscCall(DMCeedCreate(fine, coarse->dmceed->geom ? PETSC_TRUE : PETSC_FALSE, coarse->dmceed->func, coarse->dmceed->funcSource));
194   PetscFunctionReturn(PETSC_SUCCESS);
195 }
196 
197 PetscErrorCode DMCeedCreate_Internal(DM dm, IS cellIS, PetscBool createGeometry, CeedQFunctionUser func, const char *func_source, DMCeed *soldata)
198 {
199   PetscDS  ds;
200   PetscFE  fe;
201   DMCeed   sd;
202   Ceed     ceed;
203   PetscInt dim, Nc, Nqdata = 0;
204   CeedInt  Nq;
205 
206   PetscFunctionBegin;
207   PetscCall(PetscCalloc1(1, &sd));
208   PetscCall(DMGetDimension(dm, &dim));
209   PetscCall(DMGetCeed(dm, &ceed));
210   PetscCall(DMGetDS(dm, &ds));
211   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fe));
212   PetscCall(PetscFEGetCeedBasis(fe, &sd->basis));
213   PetscCall(PetscFEGetNumComponents(fe, &Nc));
214   PetscCall(CeedBasisGetNumQuadraturePoints(sd->basis, &Nq));
215   PetscCall(DMPlexGetCeedRestriction(dm, NULL, 0, 0, 0, &sd->er));
216 
217   if (createGeometry) {
218     DM cdm;
219 
220     PetscCall(DMGetCoordinateDM(dm, &cdm));
221     PetscCall(DMCeedCreateGeometry(cdm, cellIS, &Nqdata, &sd->erq, &sd->qd, &sd->geom));
222   }
223 
224   if (sd->geom) {
225     PetscInt cdim;
226     CeedInt  Nqx;
227 
228     PetscCallCEED(CeedBasisGetNumQuadraturePoints(sd->geom->basis, &Nqx));
229     PetscCheck(Nqx == Nq, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Number of qpoints for solution %" CeedInt_FMT " != %" CeedInt_FMT " Number of qpoints for coordinates", Nq, Nqx);
230     /* TODO Remove this limitation */
231     PetscCall(DMGetCoordinateDim(dm, &cdim));
232     PetscCheck(dim == cdim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Topological dimension %" PetscInt_FMT " != %" PetscInt_FMT " embedding dimension", dim, cdim);
233   }
234 
235   PetscCallCEED(CeedQFunctionCreateInterior(ceed, 1, func, func_source, &sd->qf));
236   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "u", Nc, CEED_EVAL_INTERP));
237   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "du", Nc * dim, CEED_EVAL_GRAD));
238   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "qdata", Nqdata, CEED_EVAL_NONE));
239   PetscCallCEED(CeedQFunctionAddOutput(sd->qf, "v", Nc, CEED_EVAL_INTERP));
240   PetscCallCEED(CeedQFunctionAddOutput(sd->qf, "dv", Nc * dim, CEED_EVAL_GRAD));
241 
242   PetscCallCEED(CeedOperatorCreate(ceed, sd->qf, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &sd->op));
243   PetscCallCEED(CeedOperatorSetField(sd->op, "u", sd->er, sd->basis, CEED_VECTOR_ACTIVE));
244   PetscCallCEED(CeedOperatorSetField(sd->op, "du", sd->er, sd->basis, CEED_VECTOR_ACTIVE));
245   PetscCallCEED(CeedOperatorSetField(sd->op, "qdata", sd->erq, CEED_BASIS_NONE, sd->qd));
246   PetscCallCEED(CeedOperatorSetField(sd->op, "v", sd->er, sd->basis, CEED_VECTOR_ACTIVE));
247   PetscCallCEED(CeedOperatorSetField(sd->op, "dv", sd->er, sd->basis, CEED_VECTOR_ACTIVE));
248 
249   // Handle refinement
250   sd->func = func;
251   PetscCall(PetscStrallocpy(func_source, &sd->funcSource));
252   PetscCall(DMRefineHookAdd(dm, DMRefineHook_Ceed, NULL, NULL));
253 
254   *soldata = sd;
255   PetscFunctionReturn(PETSC_SUCCESS);
256 }
257 
258 PetscErrorCode DMCeedCreate(DM dm, PetscBool createGeometry, CeedQFunctionUser func, const char *func_source)
259 {
260   DM plex;
261   IS cellIS;
262 
263   PetscFunctionBegin;
264   PetscCall(DMConvert(dm, DMPLEX, &plex));
265   PetscCall(DMPlexGetAllCells_Internal(plex, &cellIS));
266   #ifdef PETSC_HAVE_LIBCEED
267   PetscCall(DMCeedCreate_Internal(dm, cellIS, createGeometry, func, func_source, &dm->dmceed));
268   #endif
269   PetscCall(ISDestroy(&cellIS));
270   PetscCall(DMDestroy(&plex));
271   PetscFunctionReturn(PETSC_SUCCESS);
272 }
273 
274 static PetscErrorCode DMCeedCreateGeometryFVM(DM dm, IS faceIS, PetscInt *Nqdata, CeedElemRestriction *erq, CeedVector *qd, DMCeed *soldata)
275 {
276   Ceed            ceed;
277   DMCeed          sd;
278   const PetscInt *faces;
279   CeedInt         strides[3];
280   PetscInt        dim, cdim, fStart, fEnd, Nface, Nq = 1;
281 
282   PetscFunctionBegin;
283   PetscCall(PetscCalloc1(1, &sd));
284   PetscCall(DMGetDimension(dm, &dim));
285   PetscCall(DMGetCoordinateDim(dm, &cdim));
286   PetscCall(DMGetCeed(dm, &ceed));
287   PetscCall(ISGetPointRange(faceIS, &fStart, &fEnd, &faces));
288   Nface = fEnd - fStart;
289 
290   *Nqdata    = cdim + 2; // face normal and support cell volumes
291   strides[0] = 1;
292   strides[1] = Nq;
293   strides[2] = Nq * (*Nqdata);
294   PetscCallCEED(CeedElemRestrictionCreateStrided(ceed, Nface, Nq, *Nqdata, Nface * Nq * (*Nqdata), strides, erq));
295   PetscCallCEED(CeedElemRestrictionCreateVector(*erq, qd, NULL));
296   *soldata = sd;
297   PetscFunctionReturn(PETSC_SUCCESS);
298 }
299 
300 static PetscErrorCode DMCeedCreateInfoFVM(DM dm, IS faceIS, PetscInt *Nqinfo, CeedElemRestriction *eri, CeedVector *qi, DMCeed *solinfo)
301 {
302   Ceed            ceed;
303   DMCeed          si;
304   const PetscInt *faces;
305   CeedInt         strides[3];
306   PetscInt        dim, fStart, fEnd, Nface, Nq = 1;
307 
308   PetscFunctionBegin;
309   PetscCall(PetscCalloc1(1, &si));
310   PetscCall(DMGetDimension(dm, &dim));
311   PetscCall(DMGetCeed(dm, &ceed));
312   PetscCall(ISGetPointRange(faceIS, &fStart, &fEnd, &faces));
313   Nface = fEnd - fStart;
314 
315   *Nqinfo    = 3; // face number and support cell numbers
316   strides[0] = 1;
317   strides[1] = Nq;
318   strides[2] = Nq * (*Nqinfo);
319   PetscCallCEED(CeedElemRestrictionCreateStrided(ceed, Nface, Nq, *Nqinfo, Nface * Nq * (*Nqinfo), strides, eri));
320   PetscCallCEED(CeedElemRestrictionCreateVector(*eri, qi, NULL));
321   *solinfo = si;
322   PetscFunctionReturn(PETSC_SUCCESS);
323 }
324 
325 PetscErrorCode DMCeedCreateFVM_Internal(DM dm, IS faceIS, PetscBool createGeometry, PetscBool createInfo, CeedQFunctionUser func, const char *func_source, DMCeed *soldata, CeedQFunctionContext qfCtx)
326 {
327   PetscDS  ds;
328   PetscFV  fv;
329   DMCeed   sd;
330   Ceed     ceed;
331   PetscInt dim, Nc, Nqdata = 0, Nqinfo = 0;
332 
333   PetscFunctionBegin;
334   PetscCall(PetscCalloc1(1, &sd));
335   PetscCall(DMGetDimension(dm, &dim));
336   PetscCall(DMGetCeed(dm, &ceed));
337   PetscCall(DMGetDS(dm, &ds));
338   PetscCall(PetscDSGetDiscretization(ds, 0, (PetscObject *)&fv));
339   PetscCall(PetscFVGetNumComponents(fv, &Nc));
340   PetscCall(DMPlexCreateCeedRestrictionFVM(dm, &sd->erL, &sd->erR));
341 
342   if (createGeometry) {
343     DM cdm;
344 
345     PetscCall(DMGetCoordinateDM(dm, &cdm));
346     PetscCall(DMCeedCreateGeometryFVM(cdm, faceIS, &Nqdata, &sd->erq, &sd->qd, &sd->geom));
347   }
348 
349   if (createInfo) {
350     DM cdm;
351 
352     PetscCall(DMGetCoordinateDM(dm, &cdm));
353     PetscCall(DMCeedCreateInfoFVM(cdm, faceIS, &Nqinfo, &sd->eri, &sd->qi, &sd->info));
354     PetscCall(DMCeedComputeInfo(dm, sd));
355   }
356 
357   PetscCallCEED(CeedQFunctionCreateInterior(ceed, 1, func, func_source, &sd->qf));
358   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "uL", Nc, CEED_EVAL_NONE));
359   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "uR", Nc, CEED_EVAL_NONE));
360   PetscCallCEED(CeedQFunctionAddInput(sd->qf, "geom", Nqdata, CEED_EVAL_NONE));
361   if (createInfo) PetscCallCEED(CeedQFunctionAddInput(sd->qf, "info", Nqinfo, CEED_EVAL_NONE));
362   PetscCallCEED(CeedQFunctionAddOutput(sd->qf, "cL", Nc, CEED_EVAL_NONE));
363   PetscCallCEED(CeedQFunctionAddOutput(sd->qf, "cR", Nc, CEED_EVAL_NONE));
364 
365   PetscCallCEED(CeedQFunctionSetContext(sd->qf, qfCtx));
366 
367   PetscCallCEED(CeedOperatorCreate(ceed, sd->qf, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &sd->op));
368   PetscCallCEED(CeedOperatorSetField(sd->op, "uL", sd->erL, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE));
369   PetscCallCEED(CeedOperatorSetField(sd->op, "uR", sd->erR, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE));
370   PetscCallCEED(CeedOperatorSetField(sd->op, "geom", sd->erq, CEED_BASIS_NONE, sd->qd));
371   if (createInfo) PetscCallCEED(CeedOperatorSetField(sd->op, "info", sd->eri, CEED_BASIS_NONE, sd->qi));
372   PetscCallCEED(CeedOperatorSetField(sd->op, "cL", sd->erL, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE));
373   PetscCallCEED(CeedOperatorSetField(sd->op, "cR", sd->erR, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE));
374 
375   // Handle refinement
376   sd->func = func;
377   PetscCall(PetscStrallocpy(func_source, &sd->funcSource));
378   PetscCall(DMRefineHookAdd(dm, DMRefineHook_Ceed, NULL, NULL));
379 
380   *soldata = sd;
381   PetscFunctionReturn(PETSC_SUCCESS);
382 }
383 
384 PetscErrorCode DMCeedCreateFVM(DM dm, PetscBool createGeometry, CeedQFunctionUser func, const char *func_source, CeedQFunctionContext qfCtx)
385 {
386   DM plex;
387   IS faceIS;
388 
389   PetscFunctionBegin;
390   PetscCall(DMConvert(dm, DMPLEX, &plex));
391   PetscCall(DMPlexGetAllFaces_Internal(plex, &faceIS));
392   #ifdef PETSC_HAVE_LIBCEED
393   PetscCall(DMCeedCreateFVM_Internal(dm, faceIS, createGeometry, PETSC_TRUE, func, func_source, &dm->dmceed, qfCtx));
394   #endif
395   PetscCall(ISDestroy(&faceIS));
396   PetscCall(DMDestroy(&plex));
397   PetscFunctionReturn(PETSC_SUCCESS);
398 }
399 
400 #endif
401 
402 PetscErrorCode DMCeedDestroy(DMCeed *pceed)
403 {
404   DMCeed p = *pceed;
405 
406   PetscFunctionBegin;
407   if (!p) PetscFunctionReturn(PETSC_SUCCESS);
408 #ifdef PETSC_HAVE_LIBCEED
409   PetscCall(PetscFree(p->funcSource));
410   if (p->qd) PetscCallCEED(CeedVectorDestroy(&p->qd));
411   if (p->qi) PetscCallCEED(CeedVectorDestroy(&p->qi));
412   if (p->op) PetscCallCEED(CeedOperatorDestroy(&p->op));
413   if (p->qf) PetscCallCEED(CeedQFunctionDestroy(&p->qf));
414   if (p->erL) PetscCallCEED(CeedElemRestrictionDestroy(&p->erL));
415   if (p->erR) PetscCallCEED(CeedElemRestrictionDestroy(&p->erR));
416   if (p->erq) PetscCallCEED(CeedElemRestrictionDestroy(&p->erq));
417   if (p->eri) PetscCallCEED(CeedElemRestrictionDestroy(&p->eri));
418   PetscCall(DMCeedDestroy(&p->geom));
419   PetscCall(DMCeedDestroy(&p->info));
420 #endif
421   PetscCall(PetscFree(p));
422   *pceed = NULL;
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 PetscErrorCode DMCeedComputeGeometry(DM dm, DMCeed sd)
427 {
428 #ifdef PETSC_HAVE_LIBCEED
429   Ceed       ceed;
430   Vec        coords;
431   CeedVector ccoords;
432 #endif
433 
434   PetscFunctionBegin;
435 #ifdef PETSC_HAVE_LIBCEED
436   PetscCall(DMGetCeed(dm, &ceed));
437   PetscCall(DMGetCoordinatesLocal(dm, &coords));
438   PetscCall(VecGetCeedVectorRead(coords, ceed, &ccoords));
439   if (sd->geom->op) PetscCallCEED(CeedOperatorApply(sd->geom->op, ccoords, sd->qd, CEED_REQUEST_IMMEDIATE));
440   else PetscCall(DMPlexCeedComputeGeometryFVM(dm, sd->qd));
441   //PetscCallCEED(CeedVectorView(sd->qd, "%g", stdout));
442   PetscCall(VecRestoreCeedVectorRead(coords, &ccoords));
443 #endif
444   PetscFunctionReturn(PETSC_SUCCESS);
445 }
446 
447 PetscErrorCode DMCeedComputeInfo(DM dm, DMCeed sd)
448 {
449 #ifdef PETSC_HAVE_LIBCEED
450   CeedScalar *a;
451 #endif
452 
453   PetscFunctionBegin;
454 #ifdef PETSC_HAVE_LIBCEED
455   PetscCallCEED(CeedVectorGetArrayWrite(sd->qi, CEED_MEM_HOST, &a));
456 
457   IS              iterIS;
458   DMLabel         label = NULL;
459   const PetscInt *indices;
460   PetscInt        value = 0, height = 1, NfInt = 0, Nf = 0;
461 
462   PetscCall(DMGetPoints_Internal(dm, label, value, height, &iterIS));
463   if (iterIS) {
464     PetscCall(ISGetIndices(iterIS, &indices));
465     PetscCall(ISGetLocalSize(iterIS, &Nf));
466     for (PetscInt p = 0, Ns; p < Nf; ++p) {
467       PetscCall(DMPlexGetSupportSize(dm, indices[p], &Ns));
468       if (Ns == 2) ++NfInt;
469     }
470   } else {
471     indices = NULL;
472   }
473 
474   PetscInt infoOffset = 0;
475 
476   for (PetscInt p = 0; p < Nf; ++p) {
477     const PetscInt  face = indices[p];
478     const PetscInt *supp;
479     PetscInt        Ns;
480 
481     PetscCall(DMPlexGetSupport(dm, face, &supp));
482     PetscCall(DMPlexGetSupportSize(dm, face, &Ns));
483     // Ignore boundary faces
484     //   TODO check for face on parallel boundary
485     if (Ns == 2) {
486       a[infoOffset++] = face;
487       a[infoOffset++] = supp[0];
488       a[infoOffset++] = supp[1];
489     }
490   }
491   PetscCheck(infoOffset == NfInt * 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Shape mismatch, info offsets array of shape (%" PetscInt_FMT ") initialized for %" PetscInt_FMT " nodes", infoOffset, NfInt * 3);
492   if (iterIS) PetscCall(ISRestoreIndices(iterIS, &indices));
493   PetscCall(ISDestroy(&iterIS));
494 
495   PetscCallCEED(CeedVectorRestoreArray(sd->qi, &a));
496 #endif
497   PetscFunctionReturn(PETSC_SUCCESS);
498 }
499