xref: /petsc/src/snes/utils/dm/dminterpolatesnes.c (revision c6f61ee217dbd23bd0792f1ef4cfacda5212558b)
1*c6f61ee2SBarry Smith #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/
2*c6f61ee2SBarry Smith #include <petsc/private/snesimpl.h>   /*I "petscsnes.h"   I*/
3*c6f61ee2SBarry Smith #include <petscds.h>
4*c6f61ee2SBarry Smith #include <petsc/private/petscimpl.h>
5*c6f61ee2SBarry Smith #include <petsc/private/petscfeimpl.h>
6*c6f61ee2SBarry Smith 
7*c6f61ee2SBarry Smith /*@C
8*c6f61ee2SBarry Smith   DMInterpolationCreate - Creates a `DMInterpolationInfo` context
9*c6f61ee2SBarry Smith 
10*c6f61ee2SBarry Smith   Collective
11*c6f61ee2SBarry Smith 
12*c6f61ee2SBarry Smith   Input Parameter:
13*c6f61ee2SBarry Smith . comm - the communicator
14*c6f61ee2SBarry Smith 
15*c6f61ee2SBarry Smith   Output Parameter:
16*c6f61ee2SBarry Smith . ctx - the context
17*c6f61ee2SBarry Smith 
18*c6f61ee2SBarry Smith   Level: beginner
19*c6f61ee2SBarry Smith 
20*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationDestroy()`
21*c6f61ee2SBarry Smith @*/
22*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx)
23*c6f61ee2SBarry Smith {
24*c6f61ee2SBarry Smith   PetscFunctionBegin;
25*c6f61ee2SBarry Smith   PetscAssertPointer(ctx, 2);
26*c6f61ee2SBarry Smith   PetscCall(PetscNew(ctx));
27*c6f61ee2SBarry Smith 
28*c6f61ee2SBarry Smith   (*ctx)->comm   = comm;
29*c6f61ee2SBarry Smith   (*ctx)->dim    = -1;
30*c6f61ee2SBarry Smith   (*ctx)->nInput = 0;
31*c6f61ee2SBarry Smith   (*ctx)->points = NULL;
32*c6f61ee2SBarry Smith   (*ctx)->cells  = NULL;
33*c6f61ee2SBarry Smith   (*ctx)->n      = -1;
34*c6f61ee2SBarry Smith   (*ctx)->coords = NULL;
35*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
36*c6f61ee2SBarry Smith }
37*c6f61ee2SBarry Smith 
38*c6f61ee2SBarry Smith /*@C
39*c6f61ee2SBarry Smith   DMInterpolationSetDim - Sets the spatial dimension for the interpolation context
40*c6f61ee2SBarry Smith 
41*c6f61ee2SBarry Smith   Not Collective
42*c6f61ee2SBarry Smith 
43*c6f61ee2SBarry Smith   Input Parameters:
44*c6f61ee2SBarry Smith + ctx - the context
45*c6f61ee2SBarry Smith - dim - the spatial dimension
46*c6f61ee2SBarry Smith 
47*c6f61ee2SBarry Smith   Level: intermediate
48*c6f61ee2SBarry Smith 
49*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationGetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
50*c6f61ee2SBarry Smith @*/
51*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim)
52*c6f61ee2SBarry Smith {
53*c6f61ee2SBarry Smith   PetscFunctionBegin;
54*c6f61ee2SBarry Smith   PetscCheck(!(dim < 1) && !(dim > 3), ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %" PetscInt_FMT, dim);
55*c6f61ee2SBarry Smith   ctx->dim = dim;
56*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
57*c6f61ee2SBarry Smith }
58*c6f61ee2SBarry Smith 
59*c6f61ee2SBarry Smith /*@C
60*c6f61ee2SBarry Smith   DMInterpolationGetDim - Gets the spatial dimension for the interpolation context
61*c6f61ee2SBarry Smith 
62*c6f61ee2SBarry Smith   Not Collective
63*c6f61ee2SBarry Smith 
64*c6f61ee2SBarry Smith   Input Parameter:
65*c6f61ee2SBarry Smith . ctx - the context
66*c6f61ee2SBarry Smith 
67*c6f61ee2SBarry Smith   Output Parameter:
68*c6f61ee2SBarry Smith . dim - the spatial dimension
69*c6f61ee2SBarry Smith 
70*c6f61ee2SBarry Smith   Level: intermediate
71*c6f61ee2SBarry Smith 
72*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
73*c6f61ee2SBarry Smith @*/
74*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim)
75*c6f61ee2SBarry Smith {
76*c6f61ee2SBarry Smith   PetscFunctionBegin;
77*c6f61ee2SBarry Smith   PetscAssertPointer(dim, 2);
78*c6f61ee2SBarry Smith   *dim = ctx->dim;
79*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
80*c6f61ee2SBarry Smith }
81*c6f61ee2SBarry Smith 
82*c6f61ee2SBarry Smith /*@C
83*c6f61ee2SBarry Smith   DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context
84*c6f61ee2SBarry Smith 
85*c6f61ee2SBarry Smith   Not Collective
86*c6f61ee2SBarry Smith 
87*c6f61ee2SBarry Smith   Input Parameters:
88*c6f61ee2SBarry Smith + ctx - the context
89*c6f61ee2SBarry Smith - dof - the number of fields
90*c6f61ee2SBarry Smith 
91*c6f61ee2SBarry Smith   Level: intermediate
92*c6f61ee2SBarry Smith 
93*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationGetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
94*c6f61ee2SBarry Smith @*/
95*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof)
96*c6f61ee2SBarry Smith {
97*c6f61ee2SBarry Smith   PetscFunctionBegin;
98*c6f61ee2SBarry Smith   PetscCheck(dof >= 1, ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %" PetscInt_FMT, dof);
99*c6f61ee2SBarry Smith   ctx->dof = dof;
100*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
101*c6f61ee2SBarry Smith }
102*c6f61ee2SBarry Smith 
103*c6f61ee2SBarry Smith /*@C
104*c6f61ee2SBarry Smith   DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context
105*c6f61ee2SBarry Smith 
106*c6f61ee2SBarry Smith   Not Collective
107*c6f61ee2SBarry Smith 
108*c6f61ee2SBarry Smith   Input Parameter:
109*c6f61ee2SBarry Smith . ctx - the context
110*c6f61ee2SBarry Smith 
111*c6f61ee2SBarry Smith   Output Parameter:
112*c6f61ee2SBarry Smith . dof - the number of fields
113*c6f61ee2SBarry Smith 
114*c6f61ee2SBarry Smith   Level: intermediate
115*c6f61ee2SBarry Smith 
116*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationSetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`
117*c6f61ee2SBarry Smith @*/
118*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof)
119*c6f61ee2SBarry Smith {
120*c6f61ee2SBarry Smith   PetscFunctionBegin;
121*c6f61ee2SBarry Smith   PetscAssertPointer(dof, 2);
122*c6f61ee2SBarry Smith   *dof = ctx->dof;
123*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
124*c6f61ee2SBarry Smith }
125*c6f61ee2SBarry Smith 
126*c6f61ee2SBarry Smith /*@C
127*c6f61ee2SBarry Smith   DMInterpolationAddPoints - Add points at which we will interpolate the fields
128*c6f61ee2SBarry Smith 
129*c6f61ee2SBarry Smith   Not Collective
130*c6f61ee2SBarry Smith 
131*c6f61ee2SBarry Smith   Input Parameters:
132*c6f61ee2SBarry Smith + ctx    - the context
133*c6f61ee2SBarry Smith . n      - the number of points
134*c6f61ee2SBarry Smith - points - the coordinates for each point, an array of size n * dim
135*c6f61ee2SBarry Smith 
136*c6f61ee2SBarry Smith   Level: intermediate
137*c6f61ee2SBarry Smith 
138*c6f61ee2SBarry Smith   Note:
139*c6f61ee2SBarry Smith   The coordinate information is copied.
140*c6f61ee2SBarry Smith 
141*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationCreate()`
142*c6f61ee2SBarry Smith @*/
143*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[])
144*c6f61ee2SBarry Smith {
145*c6f61ee2SBarry Smith   PetscFunctionBegin;
146*c6f61ee2SBarry Smith   PetscCheck(ctx->dim >= 0, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
147*c6f61ee2SBarry Smith   PetscCheck(!ctx->points, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet");
148*c6f61ee2SBarry Smith   ctx->nInput = n;
149*c6f61ee2SBarry Smith 
150*c6f61ee2SBarry Smith   PetscCall(PetscMalloc1(n * ctx->dim, &ctx->points));
151*c6f61ee2SBarry Smith   PetscCall(PetscArraycpy(ctx->points, points, n * ctx->dim));
152*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
153*c6f61ee2SBarry Smith }
154*c6f61ee2SBarry Smith 
155*c6f61ee2SBarry Smith /*@C
156*c6f61ee2SBarry Smith   DMInterpolationSetUp - Compute spatial indices for point location during interpolation
157*c6f61ee2SBarry Smith 
158*c6f61ee2SBarry Smith   Collective
159*c6f61ee2SBarry Smith 
160*c6f61ee2SBarry Smith   Input Parameters:
161*c6f61ee2SBarry Smith + ctx                 - the context
162*c6f61ee2SBarry Smith . dm                  - the `DM` for the function space used for interpolation
163*c6f61ee2SBarry Smith . redundantPoints     - If `PETSC_TRUE`, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes.
164*c6f61ee2SBarry Smith - ignoreOutsideDomain - If `PETSC_TRUE`, ignore points outside the domain, otherwise return an error
165*c6f61ee2SBarry Smith 
166*c6f61ee2SBarry Smith   Level: intermediate
167*c6f61ee2SBarry Smith 
168*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
169*c6f61ee2SBarry Smith @*/
170*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain)
171*c6f61ee2SBarry Smith {
172*c6f61ee2SBarry Smith   MPI_Comm           comm = ctx->comm;
173*c6f61ee2SBarry Smith   PetscScalar       *a;
174*c6f61ee2SBarry Smith   PetscInt           p, q, i;
175*c6f61ee2SBarry Smith   PetscMPIInt        rank, size;
176*c6f61ee2SBarry Smith   Vec                pointVec;
177*c6f61ee2SBarry Smith   PetscSF            cellSF;
178*c6f61ee2SBarry Smith   PetscLayout        layout;
179*c6f61ee2SBarry Smith   PetscReal         *globalPoints;
180*c6f61ee2SBarry Smith   PetscScalar       *globalPointsScalar;
181*c6f61ee2SBarry Smith   const PetscInt    *ranges;
182*c6f61ee2SBarry Smith   PetscMPIInt       *counts, *displs;
183*c6f61ee2SBarry Smith   const PetscSFNode *foundCells;
184*c6f61ee2SBarry Smith   const PetscInt    *foundPoints;
185*c6f61ee2SBarry Smith   PetscMPIInt       *foundProcs, *globalProcs;
186*c6f61ee2SBarry Smith   PetscInt           n, N, numFound;
187*c6f61ee2SBarry Smith 
188*c6f61ee2SBarry Smith   PetscFunctionBegin;
189*c6f61ee2SBarry Smith   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
190*c6f61ee2SBarry Smith   PetscCallMPI(MPI_Comm_size(comm, &size));
191*c6f61ee2SBarry Smith   PetscCallMPI(MPI_Comm_rank(comm, &rank));
192*c6f61ee2SBarry Smith   PetscCheck(ctx->dim >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set");
193*c6f61ee2SBarry Smith   /* Locate points */
194*c6f61ee2SBarry Smith   n = ctx->nInput;
195*c6f61ee2SBarry Smith   if (!redundantPoints) {
196*c6f61ee2SBarry Smith     PetscCall(PetscLayoutCreate(comm, &layout));
197*c6f61ee2SBarry Smith     PetscCall(PetscLayoutSetBlockSize(layout, 1));
198*c6f61ee2SBarry Smith     PetscCall(PetscLayoutSetLocalSize(layout, n));
199*c6f61ee2SBarry Smith     PetscCall(PetscLayoutSetUp(layout));
200*c6f61ee2SBarry Smith     PetscCall(PetscLayoutGetSize(layout, &N));
201*c6f61ee2SBarry Smith     /* Communicate all points to all processes */
202*c6f61ee2SBarry Smith     PetscCall(PetscMalloc3(N * ctx->dim, &globalPoints, size, &counts, size, &displs));
203*c6f61ee2SBarry Smith     PetscCall(PetscLayoutGetRanges(layout, &ranges));
204*c6f61ee2SBarry Smith     for (p = 0; p < size; ++p) {
205*c6f61ee2SBarry Smith       counts[p] = (ranges[p + 1] - ranges[p]) * ctx->dim;
206*c6f61ee2SBarry Smith       displs[p] = ranges[p] * ctx->dim;
207*c6f61ee2SBarry Smith     }
208*c6f61ee2SBarry Smith     PetscCallMPI(MPI_Allgatherv(ctx->points, n * ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm));
209*c6f61ee2SBarry Smith   } else {
210*c6f61ee2SBarry Smith     N            = n;
211*c6f61ee2SBarry Smith     globalPoints = ctx->points;
212*c6f61ee2SBarry Smith     counts = displs = NULL;
213*c6f61ee2SBarry Smith     layout          = NULL;
214*c6f61ee2SBarry Smith   }
215*c6f61ee2SBarry Smith #if 0
216*c6f61ee2SBarry Smith   PetscCall(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs));
217*c6f61ee2SBarry Smith   /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */
218*c6f61ee2SBarry Smith #else
219*c6f61ee2SBarry Smith   #if defined(PETSC_USE_COMPLEX)
220*c6f61ee2SBarry Smith   PetscCall(PetscMalloc1(N * ctx->dim, &globalPointsScalar));
221*c6f61ee2SBarry Smith   for (i = 0; i < N * ctx->dim; i++) globalPointsScalar[i] = globalPoints[i];
222*c6f61ee2SBarry Smith   #else
223*c6f61ee2SBarry Smith   globalPointsScalar = globalPoints;
224*c6f61ee2SBarry Smith   #endif
225*c6f61ee2SBarry Smith   PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N * ctx->dim, globalPointsScalar, &pointVec));
226*c6f61ee2SBarry Smith   PetscCall(PetscMalloc2(N, &foundProcs, N, &globalProcs));
227*c6f61ee2SBarry Smith   for (p = 0; p < N; ++p) foundProcs[p] = size;
228*c6f61ee2SBarry Smith   cellSF = NULL;
229*c6f61ee2SBarry Smith   PetscCall(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF));
230*c6f61ee2SBarry Smith   PetscCall(PetscSFGetGraph(cellSF, NULL, &numFound, &foundPoints, &foundCells));
231*c6f61ee2SBarry Smith #endif
232*c6f61ee2SBarry Smith   for (p = 0; p < numFound; ++p) {
233*c6f61ee2SBarry Smith     if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank;
234*c6f61ee2SBarry Smith   }
235*c6f61ee2SBarry Smith   /* Let the lowest rank process own each point */
236*c6f61ee2SBarry Smith   PetscCall(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm));
237*c6f61ee2SBarry Smith   ctx->n = 0;
238*c6f61ee2SBarry Smith   for (p = 0; p < N; ++p) {
239*c6f61ee2SBarry Smith     if (globalProcs[p] == size) {
240*c6f61ee2SBarry Smith       PetscCheck(ignoreOutsideDomain, comm, PETSC_ERR_PLIB, "Point %" PetscInt_FMT ": %g %g %g not located in mesh", p, (double)globalPoints[p * ctx->dim + 0], (double)(ctx->dim > 1 ? globalPoints[p * ctx->dim + 1] : 0.0),
241*c6f61ee2SBarry Smith                  (double)(ctx->dim > 2 ? globalPoints[p * ctx->dim + 2] : 0.0));
242*c6f61ee2SBarry Smith       if (rank == 0) ++ctx->n;
243*c6f61ee2SBarry Smith     } else if (globalProcs[p] == rank) ++ctx->n;
244*c6f61ee2SBarry Smith   }
245*c6f61ee2SBarry Smith   /* Create coordinates vector and array of owned cells */
246*c6f61ee2SBarry Smith   PetscCall(PetscMalloc1(ctx->n, &ctx->cells));
247*c6f61ee2SBarry Smith   PetscCall(VecCreate(comm, &ctx->coords));
248*c6f61ee2SBarry Smith   PetscCall(VecSetSizes(ctx->coords, ctx->n * ctx->dim, PETSC_DECIDE));
249*c6f61ee2SBarry Smith   PetscCall(VecSetBlockSize(ctx->coords, ctx->dim));
250*c6f61ee2SBarry Smith   PetscCall(VecSetType(ctx->coords, VECSTANDARD));
251*c6f61ee2SBarry Smith   PetscCall(VecGetArray(ctx->coords, &a));
252*c6f61ee2SBarry Smith   for (p = 0, q = 0, i = 0; p < N; ++p) {
253*c6f61ee2SBarry Smith     if (globalProcs[p] == rank) {
254*c6f61ee2SBarry Smith       PetscInt d;
255*c6f61ee2SBarry Smith 
256*c6f61ee2SBarry Smith       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p * ctx->dim + d];
257*c6f61ee2SBarry Smith       ctx->cells[q] = foundCells[q].index;
258*c6f61ee2SBarry Smith       ++q;
259*c6f61ee2SBarry Smith     }
260*c6f61ee2SBarry Smith     if (globalProcs[p] == size && rank == 0) {
261*c6f61ee2SBarry Smith       PetscInt d;
262*c6f61ee2SBarry Smith 
263*c6f61ee2SBarry Smith       for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.;
264*c6f61ee2SBarry Smith       ctx->cells[q] = -1;
265*c6f61ee2SBarry Smith       ++q;
266*c6f61ee2SBarry Smith     }
267*c6f61ee2SBarry Smith   }
268*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(ctx->coords, &a));
269*c6f61ee2SBarry Smith #if 0
270*c6f61ee2SBarry Smith   PetscCall(PetscFree3(foundCells,foundProcs,globalProcs));
271*c6f61ee2SBarry Smith #else
272*c6f61ee2SBarry Smith   PetscCall(PetscFree2(foundProcs, globalProcs));
273*c6f61ee2SBarry Smith   PetscCall(PetscSFDestroy(&cellSF));
274*c6f61ee2SBarry Smith   PetscCall(VecDestroy(&pointVec));
275*c6f61ee2SBarry Smith #endif
276*c6f61ee2SBarry Smith   if ((void *)globalPointsScalar != (void *)globalPoints) PetscCall(PetscFree(globalPointsScalar));
277*c6f61ee2SBarry Smith   if (!redundantPoints) PetscCall(PetscFree3(globalPoints, counts, displs));
278*c6f61ee2SBarry Smith   PetscCall(PetscLayoutDestroy(&layout));
279*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
280*c6f61ee2SBarry Smith }
281*c6f61ee2SBarry Smith 
282*c6f61ee2SBarry Smith /*@C
283*c6f61ee2SBarry Smith   DMInterpolationGetCoordinates - Gets a `Vec` with the coordinates of each interpolation point
284*c6f61ee2SBarry Smith 
285*c6f61ee2SBarry Smith   Collective
286*c6f61ee2SBarry Smith 
287*c6f61ee2SBarry Smith   Input Parameter:
288*c6f61ee2SBarry Smith . ctx - the context
289*c6f61ee2SBarry Smith 
290*c6f61ee2SBarry Smith   Output Parameter:
291*c6f61ee2SBarry Smith . coordinates - the coordinates of interpolation points
292*c6f61ee2SBarry Smith 
293*c6f61ee2SBarry Smith   Level: intermediate
294*c6f61ee2SBarry Smith 
295*c6f61ee2SBarry Smith   Note:
296*c6f61ee2SBarry Smith   The local vector entries correspond to interpolation points lying on this process, according to the associated `DM`.
297*c6f61ee2SBarry Smith   This is a borrowed vector that the user should not destroy.
298*c6f61ee2SBarry Smith 
299*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
300*c6f61ee2SBarry Smith @*/
301*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates)
302*c6f61ee2SBarry Smith {
303*c6f61ee2SBarry Smith   PetscFunctionBegin;
304*c6f61ee2SBarry Smith   PetscAssertPointer(coordinates, 2);
305*c6f61ee2SBarry Smith   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
306*c6f61ee2SBarry Smith   *coordinates = ctx->coords;
307*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
308*c6f61ee2SBarry Smith }
309*c6f61ee2SBarry Smith 
310*c6f61ee2SBarry Smith /*@C
311*c6f61ee2SBarry Smith   DMInterpolationGetVector - Gets a `Vec` which can hold all the interpolated field values
312*c6f61ee2SBarry Smith 
313*c6f61ee2SBarry Smith   Collective
314*c6f61ee2SBarry Smith 
315*c6f61ee2SBarry Smith   Input Parameter:
316*c6f61ee2SBarry Smith . ctx - the context
317*c6f61ee2SBarry Smith 
318*c6f61ee2SBarry Smith   Output Parameter:
319*c6f61ee2SBarry Smith . v - a vector capable of holding the interpolated field values
320*c6f61ee2SBarry Smith 
321*c6f61ee2SBarry Smith   Level: intermediate
322*c6f61ee2SBarry Smith 
323*c6f61ee2SBarry Smith   Note:
324*c6f61ee2SBarry Smith   This vector should be returned using `DMInterpolationRestoreVector()`.
325*c6f61ee2SBarry Smith 
326*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationRestoreVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
327*c6f61ee2SBarry Smith @*/
328*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v)
329*c6f61ee2SBarry Smith {
330*c6f61ee2SBarry Smith   PetscFunctionBegin;
331*c6f61ee2SBarry Smith   PetscAssertPointer(v, 2);
332*c6f61ee2SBarry Smith   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
333*c6f61ee2SBarry Smith   PetscCall(VecCreate(ctx->comm, v));
334*c6f61ee2SBarry Smith   PetscCall(VecSetSizes(*v, ctx->n * ctx->dof, PETSC_DECIDE));
335*c6f61ee2SBarry Smith   PetscCall(VecSetBlockSize(*v, ctx->dof));
336*c6f61ee2SBarry Smith   PetscCall(VecSetType(*v, VECSTANDARD));
337*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
338*c6f61ee2SBarry Smith }
339*c6f61ee2SBarry Smith 
340*c6f61ee2SBarry Smith /*@C
341*c6f61ee2SBarry Smith   DMInterpolationRestoreVector - Returns a `Vec` which can hold all the interpolated field values
342*c6f61ee2SBarry Smith 
343*c6f61ee2SBarry Smith   Collective
344*c6f61ee2SBarry Smith 
345*c6f61ee2SBarry Smith   Input Parameters:
346*c6f61ee2SBarry Smith + ctx - the context
347*c6f61ee2SBarry Smith - v   - a vector capable of holding the interpolated field values
348*c6f61ee2SBarry Smith 
349*c6f61ee2SBarry Smith   Level: intermediate
350*c6f61ee2SBarry Smith 
351*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
352*c6f61ee2SBarry Smith @*/
353*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v)
354*c6f61ee2SBarry Smith {
355*c6f61ee2SBarry Smith   PetscFunctionBegin;
356*c6f61ee2SBarry Smith   PetscAssertPointer(v, 2);
357*c6f61ee2SBarry Smith   PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup.");
358*c6f61ee2SBarry Smith   PetscCall(VecDestroy(v));
359*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
360*c6f61ee2SBarry Smith }
361*c6f61ee2SBarry Smith 
362*c6f61ee2SBarry Smith static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, PetscInt p, Vec xLocal, Vec v)
363*c6f61ee2SBarry Smith {
364*c6f61ee2SBarry Smith   const PetscInt     c   = ctx->cells[p];
365*c6f61ee2SBarry Smith   const PetscInt     dof = ctx->dof;
366*c6f61ee2SBarry Smith   PetscScalar       *x   = NULL;
367*c6f61ee2SBarry Smith   const PetscScalar *coords;
368*c6f61ee2SBarry Smith   PetscScalar       *a;
369*c6f61ee2SBarry Smith   PetscReal          v0, J, invJ, detJ, xir[1];
370*c6f61ee2SBarry Smith   PetscInt           xSize, comp;
371*c6f61ee2SBarry Smith 
372*c6f61ee2SBarry Smith   PetscFunctionBegin;
373*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(ctx->coords, &coords));
374*c6f61ee2SBarry Smith   PetscCall(VecGetArray(v, &a));
375*c6f61ee2SBarry Smith   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ));
376*c6f61ee2SBarry Smith   PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
377*c6f61ee2SBarry Smith   xir[0] = invJ * PetscRealPart(coords[p] - v0);
378*c6f61ee2SBarry Smith   PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
379*c6f61ee2SBarry Smith   if (2 * dof == xSize) {
380*c6f61ee2SBarry Smith     for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp] * (1 - xir[0]) + x[1 * dof + comp] * xir[0];
381*c6f61ee2SBarry Smith   } else if (dof == xSize) {
382*c6f61ee2SBarry Smith     for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp];
383*c6f61ee2SBarry Smith   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input closure size %" PetscInt_FMT " must be either %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 2 * dof, dof);
384*c6f61ee2SBarry Smith   PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
385*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(v, &a));
386*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
387*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
388*c6f61ee2SBarry Smith }
389*c6f61ee2SBarry Smith 
390*c6f61ee2SBarry Smith static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, PetscInt p, Vec xLocal, Vec v)
391*c6f61ee2SBarry Smith {
392*c6f61ee2SBarry Smith   const PetscInt     c = ctx->cells[p];
393*c6f61ee2SBarry Smith   PetscScalar       *x = NULL;
394*c6f61ee2SBarry Smith   const PetscScalar *coords;
395*c6f61ee2SBarry Smith   PetscScalar       *a;
396*c6f61ee2SBarry Smith   PetscReal         *v0, *J, *invJ, detJ;
397*c6f61ee2SBarry Smith   PetscReal          xi[4];
398*c6f61ee2SBarry Smith 
399*c6f61ee2SBarry Smith   PetscFunctionBegin;
400*c6f61ee2SBarry Smith   PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ));
401*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(ctx->coords, &coords));
402*c6f61ee2SBarry Smith   PetscCall(VecGetArray(v, &a));
403*c6f61ee2SBarry Smith   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
404*c6f61ee2SBarry Smith   PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
405*c6f61ee2SBarry Smith   PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
406*c6f61ee2SBarry Smith   for (PetscInt comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
407*c6f61ee2SBarry Smith   for (PetscInt d = 0; d < ctx->dim; ++d) {
408*c6f61ee2SBarry Smith     xi[d] = 0.0;
409*c6f61ee2SBarry Smith     for (PetscInt f = 0; f < ctx->dim; ++f) xi[d] += invJ[d * ctx->dim + f] * 0.5 * PetscRealPart(coords[p * ctx->dim + f] - v0[f]);
410*c6f61ee2SBarry Smith     for (PetscInt comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] += PetscRealPart(x[(d + 1) * ctx->dof + comp] - x[0 * ctx->dof + comp]) * xi[d];
411*c6f61ee2SBarry Smith   }
412*c6f61ee2SBarry Smith   PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
413*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(v, &a));
414*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
415*c6f61ee2SBarry Smith   PetscCall(PetscFree3(v0, J, invJ));
416*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
417*c6f61ee2SBarry Smith }
418*c6f61ee2SBarry Smith 
419*c6f61ee2SBarry Smith static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, PetscInt p, Vec xLocal, Vec v)
420*c6f61ee2SBarry Smith {
421*c6f61ee2SBarry Smith   const PetscInt     c        = ctx->cells[p];
422*c6f61ee2SBarry Smith   const PetscInt     order[3] = {2, 1, 3};
423*c6f61ee2SBarry Smith   PetscScalar       *x        = NULL;
424*c6f61ee2SBarry Smith   PetscReal         *v0, *J, *invJ, detJ;
425*c6f61ee2SBarry Smith   const PetscScalar *coords;
426*c6f61ee2SBarry Smith   PetscScalar       *a;
427*c6f61ee2SBarry Smith   PetscReal          xi[4];
428*c6f61ee2SBarry Smith 
429*c6f61ee2SBarry Smith   PetscFunctionBegin;
430*c6f61ee2SBarry Smith   PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ));
431*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(ctx->coords, &coords));
432*c6f61ee2SBarry Smith   PetscCall(VecGetArray(v, &a));
433*c6f61ee2SBarry Smith   PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ));
434*c6f61ee2SBarry Smith   PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c);
435*c6f61ee2SBarry Smith   PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x));
436*c6f61ee2SBarry Smith   for (PetscInt comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
437*c6f61ee2SBarry Smith   for (PetscInt d = 0; d < ctx->dim; ++d) {
438*c6f61ee2SBarry Smith     xi[d] = 0.0;
439*c6f61ee2SBarry Smith     for (PetscInt f = 0; f < ctx->dim; ++f) xi[d] += invJ[d * ctx->dim + f] * 0.5 * PetscRealPart(coords[p * ctx->dim + f] - v0[f]);
440*c6f61ee2SBarry Smith     for (PetscInt comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] += PetscRealPart(x[order[d] * ctx->dof + comp] - x[0 * ctx->dof + comp]) * xi[d];
441*c6f61ee2SBarry Smith   }
442*c6f61ee2SBarry Smith   PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x));
443*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(v, &a));
444*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
445*c6f61ee2SBarry Smith   PetscCall(PetscFree3(v0, J, invJ));
446*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
447*c6f61ee2SBarry Smith }
448*c6f61ee2SBarry Smith 
449*c6f61ee2SBarry Smith static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
450*c6f61ee2SBarry Smith {
451*c6f61ee2SBarry Smith   const PetscScalar *vertices = (const PetscScalar *)ctx;
452*c6f61ee2SBarry Smith   const PetscScalar  x0       = vertices[0];
453*c6f61ee2SBarry Smith   const PetscScalar  y0       = vertices[1];
454*c6f61ee2SBarry Smith   const PetscScalar  x1       = vertices[2];
455*c6f61ee2SBarry Smith   const PetscScalar  y1       = vertices[3];
456*c6f61ee2SBarry Smith   const PetscScalar  x2       = vertices[4];
457*c6f61ee2SBarry Smith   const PetscScalar  y2       = vertices[5];
458*c6f61ee2SBarry Smith   const PetscScalar  x3       = vertices[6];
459*c6f61ee2SBarry Smith   const PetscScalar  y3       = vertices[7];
460*c6f61ee2SBarry Smith   const PetscScalar  f_1      = x1 - x0;
461*c6f61ee2SBarry Smith   const PetscScalar  g_1      = y1 - y0;
462*c6f61ee2SBarry Smith   const PetscScalar  f_3      = x3 - x0;
463*c6f61ee2SBarry Smith   const PetscScalar  g_3      = y3 - y0;
464*c6f61ee2SBarry Smith   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
465*c6f61ee2SBarry Smith   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
466*c6f61ee2SBarry Smith   const PetscScalar *ref;
467*c6f61ee2SBarry Smith   PetscScalar       *real;
468*c6f61ee2SBarry Smith 
469*c6f61ee2SBarry Smith   PetscFunctionBegin;
470*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(Xref, &ref));
471*c6f61ee2SBarry Smith   PetscCall(VecGetArray(Xreal, &real));
472*c6f61ee2SBarry Smith   {
473*c6f61ee2SBarry Smith     const PetscScalar p0 = ref[0];
474*c6f61ee2SBarry Smith     const PetscScalar p1 = ref[1];
475*c6f61ee2SBarry Smith 
476*c6f61ee2SBarry Smith     real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1;
477*c6f61ee2SBarry Smith     real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1;
478*c6f61ee2SBarry Smith   }
479*c6f61ee2SBarry Smith   PetscCall(PetscLogFlops(28));
480*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(Xref, &ref));
481*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(Xreal, &real));
482*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
483*c6f61ee2SBarry Smith }
484*c6f61ee2SBarry Smith 
485*c6f61ee2SBarry Smith #include <petsc/private/dmimpl.h>
486*c6f61ee2SBarry Smith static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
487*c6f61ee2SBarry Smith {
488*c6f61ee2SBarry Smith   const PetscScalar *vertices = (const PetscScalar *)ctx;
489*c6f61ee2SBarry Smith   const PetscScalar  x0       = vertices[0];
490*c6f61ee2SBarry Smith   const PetscScalar  y0       = vertices[1];
491*c6f61ee2SBarry Smith   const PetscScalar  x1       = vertices[2];
492*c6f61ee2SBarry Smith   const PetscScalar  y1       = vertices[3];
493*c6f61ee2SBarry Smith   const PetscScalar  x2       = vertices[4];
494*c6f61ee2SBarry Smith   const PetscScalar  y2       = vertices[5];
495*c6f61ee2SBarry Smith   const PetscScalar  x3       = vertices[6];
496*c6f61ee2SBarry Smith   const PetscScalar  y3       = vertices[7];
497*c6f61ee2SBarry Smith   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
498*c6f61ee2SBarry Smith   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
499*c6f61ee2SBarry Smith   const PetscScalar *ref;
500*c6f61ee2SBarry Smith 
501*c6f61ee2SBarry Smith   PetscFunctionBegin;
502*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(Xref, &ref));
503*c6f61ee2SBarry Smith   {
504*c6f61ee2SBarry Smith     const PetscScalar x       = ref[0];
505*c6f61ee2SBarry Smith     const PetscScalar y       = ref[1];
506*c6f61ee2SBarry Smith     const PetscInt    rows[2] = {0, 1};
507*c6f61ee2SBarry Smith     PetscScalar       values[4];
508*c6f61ee2SBarry Smith 
509*c6f61ee2SBarry Smith     values[0] = (x1 - x0 + f_01 * y) * 0.5;
510*c6f61ee2SBarry Smith     values[1] = (x3 - x0 + f_01 * x) * 0.5;
511*c6f61ee2SBarry Smith     values[2] = (y1 - y0 + g_01 * y) * 0.5;
512*c6f61ee2SBarry Smith     values[3] = (y3 - y0 + g_01 * x) * 0.5;
513*c6f61ee2SBarry Smith     PetscCall(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES));
514*c6f61ee2SBarry Smith   }
515*c6f61ee2SBarry Smith   PetscCall(PetscLogFlops(30));
516*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(Xref, &ref));
517*c6f61ee2SBarry Smith   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
518*c6f61ee2SBarry Smith   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
519*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
520*c6f61ee2SBarry Smith }
521*c6f61ee2SBarry Smith 
522*c6f61ee2SBarry Smith static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, PetscInt p, Vec xLocal, Vec v)
523*c6f61ee2SBarry Smith {
524*c6f61ee2SBarry Smith   const PetscInt     c   = ctx->cells[p];
525*c6f61ee2SBarry Smith   PetscFE            fem = NULL;
526*c6f61ee2SBarry Smith   DM                 dmCoord;
527*c6f61ee2SBarry Smith   SNES               snes;
528*c6f61ee2SBarry Smith   KSP                ksp;
529*c6f61ee2SBarry Smith   PC                 pc;
530*c6f61ee2SBarry Smith   Vec                coordsLocal, r, ref, real;
531*c6f61ee2SBarry Smith   Mat                J;
532*c6f61ee2SBarry Smith   PetscTabulation    T = NULL;
533*c6f61ee2SBarry Smith   const PetscScalar *coords;
534*c6f61ee2SBarry Smith   PetscScalar       *a;
535*c6f61ee2SBarry Smith   PetscReal          xir[2] = {0., 0.};
536*c6f61ee2SBarry Smith   PetscInt           Nf;
537*c6f61ee2SBarry Smith   const PetscInt     dof = ctx->dof;
538*c6f61ee2SBarry Smith   PetscScalar       *x = NULL, *vertices = NULL;
539*c6f61ee2SBarry Smith   PetscScalar       *xi;
540*c6f61ee2SBarry Smith   PetscInt           coordSize, xSize;
541*c6f61ee2SBarry Smith 
542*c6f61ee2SBarry Smith   PetscFunctionBegin;
543*c6f61ee2SBarry Smith   PetscCall(DMGetNumFields(dm, &Nf));
544*c6f61ee2SBarry Smith   if (Nf) {
545*c6f61ee2SBarry Smith     PetscObject  obj;
546*c6f61ee2SBarry Smith     PetscClassId id;
547*c6f61ee2SBarry Smith 
548*c6f61ee2SBarry Smith     PetscCall(DMGetField(dm, 0, NULL, &obj));
549*c6f61ee2SBarry Smith     PetscCall(PetscObjectGetClassId(obj, &id));
550*c6f61ee2SBarry Smith     if (id == PETSCFE_CLASSID) {
551*c6f61ee2SBarry Smith       fem = (PetscFE)obj;
552*c6f61ee2SBarry Smith       PetscCall(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T));
553*c6f61ee2SBarry Smith     }
554*c6f61ee2SBarry Smith   }
555*c6f61ee2SBarry Smith   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
556*c6f61ee2SBarry Smith   PetscCall(DMGetCoordinateDM(dm, &dmCoord));
557*c6f61ee2SBarry Smith   PetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
558*c6f61ee2SBarry Smith   PetscCall(SNESSetOptionsPrefix(snes, "quad_interp_"));
559*c6f61ee2SBarry Smith   PetscCall(VecCreate(PETSC_COMM_SELF, &r));
560*c6f61ee2SBarry Smith   PetscCall(VecSetSizes(r, 2, 2));
561*c6f61ee2SBarry Smith   PetscCall(VecSetType(r, dm->vectype));
562*c6f61ee2SBarry Smith   PetscCall(VecDuplicate(r, &ref));
563*c6f61ee2SBarry Smith   PetscCall(VecDuplicate(r, &real));
564*c6f61ee2SBarry Smith   PetscCall(MatCreate(PETSC_COMM_SELF, &J));
565*c6f61ee2SBarry Smith   PetscCall(MatSetSizes(J, 2, 2, 2, 2));
566*c6f61ee2SBarry Smith   PetscCall(MatSetType(J, MATSEQDENSE));
567*c6f61ee2SBarry Smith   PetscCall(MatSetUp(J));
568*c6f61ee2SBarry Smith   PetscCall(SNESSetFunction(snes, r, QuadMap_Private, NULL));
569*c6f61ee2SBarry Smith   PetscCall(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL));
570*c6f61ee2SBarry Smith   PetscCall(SNESGetKSP(snes, &ksp));
571*c6f61ee2SBarry Smith   PetscCall(KSPGetPC(ksp, &pc));
572*c6f61ee2SBarry Smith   PetscCall(PCSetType(pc, PCLU));
573*c6f61ee2SBarry Smith   PetscCall(SNESSetFromOptions(snes));
574*c6f61ee2SBarry Smith 
575*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(ctx->coords, &coords));
576*c6f61ee2SBarry Smith   PetscCall(VecGetArray(v, &a));
577*c6f61ee2SBarry Smith   PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
578*c6f61ee2SBarry Smith   PetscCheck(4 * 2 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %" PetscInt_FMT " should be %d", coordSize, 4 * 2);
579*c6f61ee2SBarry Smith   PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
580*c6f61ee2SBarry Smith   PetscCall(SNESSetFunction(snes, NULL, NULL, vertices));
581*c6f61ee2SBarry Smith   PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
582*c6f61ee2SBarry Smith   PetscCall(VecGetArray(real, &xi));
583*c6f61ee2SBarry Smith   xi[0] = coords[p * ctx->dim + 0];
584*c6f61ee2SBarry Smith   xi[1] = coords[p * ctx->dim + 1];
585*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(real, &xi));
586*c6f61ee2SBarry Smith   PetscCall(SNESSolve(snes, real, ref));
587*c6f61ee2SBarry Smith   PetscCall(VecGetArray(ref, &xi));
588*c6f61ee2SBarry Smith   xir[0] = PetscRealPart(xi[0]);
589*c6f61ee2SBarry Smith   xir[1] = PetscRealPart(xi[1]);
590*c6f61ee2SBarry Smith   if (4 * dof == xSize) {
591*c6f61ee2SBarry Smith     for (PetscInt comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp] * (1 - xir[0]) * (1 - xir[1]) + x[1 * dof + comp] * xir[0] * (1 - xir[1]) + x[2 * dof + comp] * xir[0] * xir[1] + x[3 * dof + comp] * (1 - xir[0]) * xir[1];
592*c6f61ee2SBarry Smith   } else if (dof == xSize) {
593*c6f61ee2SBarry Smith     for (PetscInt comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp];
594*c6f61ee2SBarry Smith   } else {
595*c6f61ee2SBarry Smith     PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE");
596*c6f61ee2SBarry Smith     xir[0] = 2.0 * xir[0] - 1.0;
597*c6f61ee2SBarry Smith     xir[1] = 2.0 * xir[1] - 1.0;
598*c6f61ee2SBarry Smith     PetscCall(PetscFEComputeTabulation(fem, 1, xir, 0, T));
599*c6f61ee2SBarry Smith     for (PetscInt comp = 0; comp < dof; ++comp) {
600*c6f61ee2SBarry Smith       a[p * dof + comp] = 0.0;
601*c6f61ee2SBarry Smith       for (PetscInt d = 0; d < xSize / dof; ++d) a[p * dof + comp] += x[d * dof + comp] * T->T[0][d * dof + comp];
602*c6f61ee2SBarry Smith     }
603*c6f61ee2SBarry Smith   }
604*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(ref, &xi));
605*c6f61ee2SBarry Smith   PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
606*c6f61ee2SBarry Smith   PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
607*c6f61ee2SBarry Smith   PetscCall(PetscTabulationDestroy(&T));
608*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(v, &a));
609*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
610*c6f61ee2SBarry Smith 
611*c6f61ee2SBarry Smith   PetscCall(SNESDestroy(&snes));
612*c6f61ee2SBarry Smith   PetscCall(VecDestroy(&r));
613*c6f61ee2SBarry Smith   PetscCall(VecDestroy(&ref));
614*c6f61ee2SBarry Smith   PetscCall(VecDestroy(&real));
615*c6f61ee2SBarry Smith   PetscCall(MatDestroy(&J));
616*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
617*c6f61ee2SBarry Smith }
618*c6f61ee2SBarry Smith 
619*c6f61ee2SBarry Smith static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx)
620*c6f61ee2SBarry Smith {
621*c6f61ee2SBarry Smith   const PetscScalar *vertices = (const PetscScalar *)ctx;
622*c6f61ee2SBarry Smith   const PetscScalar  x0       = vertices[0];
623*c6f61ee2SBarry Smith   const PetscScalar  y0       = vertices[1];
624*c6f61ee2SBarry Smith   const PetscScalar  z0       = vertices[2];
625*c6f61ee2SBarry Smith   const PetscScalar  x1       = vertices[9];
626*c6f61ee2SBarry Smith   const PetscScalar  y1       = vertices[10];
627*c6f61ee2SBarry Smith   const PetscScalar  z1       = vertices[11];
628*c6f61ee2SBarry Smith   const PetscScalar  x2       = vertices[6];
629*c6f61ee2SBarry Smith   const PetscScalar  y2       = vertices[7];
630*c6f61ee2SBarry Smith   const PetscScalar  z2       = vertices[8];
631*c6f61ee2SBarry Smith   const PetscScalar  x3       = vertices[3];
632*c6f61ee2SBarry Smith   const PetscScalar  y3       = vertices[4];
633*c6f61ee2SBarry Smith   const PetscScalar  z3       = vertices[5];
634*c6f61ee2SBarry Smith   const PetscScalar  x4       = vertices[12];
635*c6f61ee2SBarry Smith   const PetscScalar  y4       = vertices[13];
636*c6f61ee2SBarry Smith   const PetscScalar  z4       = vertices[14];
637*c6f61ee2SBarry Smith   const PetscScalar  x5       = vertices[15];
638*c6f61ee2SBarry Smith   const PetscScalar  y5       = vertices[16];
639*c6f61ee2SBarry Smith   const PetscScalar  z5       = vertices[17];
640*c6f61ee2SBarry Smith   const PetscScalar  x6       = vertices[18];
641*c6f61ee2SBarry Smith   const PetscScalar  y6       = vertices[19];
642*c6f61ee2SBarry Smith   const PetscScalar  z6       = vertices[20];
643*c6f61ee2SBarry Smith   const PetscScalar  x7       = vertices[21];
644*c6f61ee2SBarry Smith   const PetscScalar  y7       = vertices[22];
645*c6f61ee2SBarry Smith   const PetscScalar  z7       = vertices[23];
646*c6f61ee2SBarry Smith   const PetscScalar  f_1      = x1 - x0;
647*c6f61ee2SBarry Smith   const PetscScalar  g_1      = y1 - y0;
648*c6f61ee2SBarry Smith   const PetscScalar  h_1      = z1 - z0;
649*c6f61ee2SBarry Smith   const PetscScalar  f_3      = x3 - x0;
650*c6f61ee2SBarry Smith   const PetscScalar  g_3      = y3 - y0;
651*c6f61ee2SBarry Smith   const PetscScalar  h_3      = z3 - z0;
652*c6f61ee2SBarry Smith   const PetscScalar  f_4      = x4 - x0;
653*c6f61ee2SBarry Smith   const PetscScalar  g_4      = y4 - y0;
654*c6f61ee2SBarry Smith   const PetscScalar  h_4      = z4 - z0;
655*c6f61ee2SBarry Smith   const PetscScalar  f_01     = x2 - x1 - x3 + x0;
656*c6f61ee2SBarry Smith   const PetscScalar  g_01     = y2 - y1 - y3 + y0;
657*c6f61ee2SBarry Smith   const PetscScalar  h_01     = z2 - z1 - z3 + z0;
658*c6f61ee2SBarry Smith   const PetscScalar  f_12     = x7 - x3 - x4 + x0;
659*c6f61ee2SBarry Smith   const PetscScalar  g_12     = y7 - y3 - y4 + y0;
660*c6f61ee2SBarry Smith   const PetscScalar  h_12     = z7 - z3 - z4 + z0;
661*c6f61ee2SBarry Smith   const PetscScalar  f_02     = x5 - x1 - x4 + x0;
662*c6f61ee2SBarry Smith   const PetscScalar  g_02     = y5 - y1 - y4 + y0;
663*c6f61ee2SBarry Smith   const PetscScalar  h_02     = z5 - z1 - z4 + z0;
664*c6f61ee2SBarry Smith   const PetscScalar  f_012    = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
665*c6f61ee2SBarry Smith   const PetscScalar  g_012    = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
666*c6f61ee2SBarry Smith   const PetscScalar  h_012    = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
667*c6f61ee2SBarry Smith   const PetscScalar *ref;
668*c6f61ee2SBarry Smith   PetscScalar       *real;
669*c6f61ee2SBarry Smith 
670*c6f61ee2SBarry Smith   PetscFunctionBegin;
671*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(Xref, &ref));
672*c6f61ee2SBarry Smith   PetscCall(VecGetArray(Xreal, &real));
673*c6f61ee2SBarry Smith   {
674*c6f61ee2SBarry Smith     const PetscScalar p0 = ref[0];
675*c6f61ee2SBarry Smith     const PetscScalar p1 = ref[1];
676*c6f61ee2SBarry Smith     const PetscScalar p2 = ref[2];
677*c6f61ee2SBarry Smith 
678*c6f61ee2SBarry Smith     real[0] = x0 + f_1 * p0 + f_3 * p1 + f_4 * p2 + f_01 * p0 * p1 + f_12 * p1 * p2 + f_02 * p0 * p2 + f_012 * p0 * p1 * p2;
679*c6f61ee2SBarry Smith     real[1] = y0 + g_1 * p0 + g_3 * p1 + g_4 * p2 + g_01 * p0 * p1 + g_01 * p0 * p1 + g_12 * p1 * p2 + g_02 * p0 * p2 + g_012 * p0 * p1 * p2;
680*c6f61ee2SBarry Smith     real[2] = z0 + h_1 * p0 + h_3 * p1 + h_4 * p2 + h_01 * p0 * p1 + h_01 * p0 * p1 + h_12 * p1 * p2 + h_02 * p0 * p2 + h_012 * p0 * p1 * p2;
681*c6f61ee2SBarry Smith   }
682*c6f61ee2SBarry Smith   PetscCall(PetscLogFlops(114));
683*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(Xref, &ref));
684*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(Xreal, &real));
685*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
686*c6f61ee2SBarry Smith }
687*c6f61ee2SBarry Smith 
688*c6f61ee2SBarry Smith static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx)
689*c6f61ee2SBarry Smith {
690*c6f61ee2SBarry Smith   const PetscScalar *vertices = (const PetscScalar *)ctx;
691*c6f61ee2SBarry Smith   const PetscScalar  x0       = vertices[0];
692*c6f61ee2SBarry Smith   const PetscScalar  y0       = vertices[1];
693*c6f61ee2SBarry Smith   const PetscScalar  z0       = vertices[2];
694*c6f61ee2SBarry Smith   const PetscScalar  x1       = vertices[9];
695*c6f61ee2SBarry Smith   const PetscScalar  y1       = vertices[10];
696*c6f61ee2SBarry Smith   const PetscScalar  z1       = vertices[11];
697*c6f61ee2SBarry Smith   const PetscScalar  x2       = vertices[6];
698*c6f61ee2SBarry Smith   const PetscScalar  y2       = vertices[7];
699*c6f61ee2SBarry Smith   const PetscScalar  z2       = vertices[8];
700*c6f61ee2SBarry Smith   const PetscScalar  x3       = vertices[3];
701*c6f61ee2SBarry Smith   const PetscScalar  y3       = vertices[4];
702*c6f61ee2SBarry Smith   const PetscScalar  z3       = vertices[5];
703*c6f61ee2SBarry Smith   const PetscScalar  x4       = vertices[12];
704*c6f61ee2SBarry Smith   const PetscScalar  y4       = vertices[13];
705*c6f61ee2SBarry Smith   const PetscScalar  z4       = vertices[14];
706*c6f61ee2SBarry Smith   const PetscScalar  x5       = vertices[15];
707*c6f61ee2SBarry Smith   const PetscScalar  y5       = vertices[16];
708*c6f61ee2SBarry Smith   const PetscScalar  z5       = vertices[17];
709*c6f61ee2SBarry Smith   const PetscScalar  x6       = vertices[18];
710*c6f61ee2SBarry Smith   const PetscScalar  y6       = vertices[19];
711*c6f61ee2SBarry Smith   const PetscScalar  z6       = vertices[20];
712*c6f61ee2SBarry Smith   const PetscScalar  x7       = vertices[21];
713*c6f61ee2SBarry Smith   const PetscScalar  y7       = vertices[22];
714*c6f61ee2SBarry Smith   const PetscScalar  z7       = vertices[23];
715*c6f61ee2SBarry Smith   const PetscScalar  f_xy     = x2 - x1 - x3 + x0;
716*c6f61ee2SBarry Smith   const PetscScalar  g_xy     = y2 - y1 - y3 + y0;
717*c6f61ee2SBarry Smith   const PetscScalar  h_xy     = z2 - z1 - z3 + z0;
718*c6f61ee2SBarry Smith   const PetscScalar  f_yz     = x7 - x3 - x4 + x0;
719*c6f61ee2SBarry Smith   const PetscScalar  g_yz     = y7 - y3 - y4 + y0;
720*c6f61ee2SBarry Smith   const PetscScalar  h_yz     = z7 - z3 - z4 + z0;
721*c6f61ee2SBarry Smith   const PetscScalar  f_xz     = x5 - x1 - x4 + x0;
722*c6f61ee2SBarry Smith   const PetscScalar  g_xz     = y5 - y1 - y4 + y0;
723*c6f61ee2SBarry Smith   const PetscScalar  h_xz     = z5 - z1 - z4 + z0;
724*c6f61ee2SBarry Smith   const PetscScalar  f_xyz    = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7;
725*c6f61ee2SBarry Smith   const PetscScalar  g_xyz    = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7;
726*c6f61ee2SBarry Smith   const PetscScalar  h_xyz    = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7;
727*c6f61ee2SBarry Smith   const PetscScalar *ref;
728*c6f61ee2SBarry Smith 
729*c6f61ee2SBarry Smith   PetscFunctionBegin;
730*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(Xref, &ref));
731*c6f61ee2SBarry Smith   {
732*c6f61ee2SBarry Smith     const PetscScalar x       = ref[0];
733*c6f61ee2SBarry Smith     const PetscScalar y       = ref[1];
734*c6f61ee2SBarry Smith     const PetscScalar z       = ref[2];
735*c6f61ee2SBarry Smith     const PetscInt    rows[3] = {0, 1, 2};
736*c6f61ee2SBarry Smith     PetscScalar       values[9];
737*c6f61ee2SBarry Smith 
738*c6f61ee2SBarry Smith     values[0] = (x1 - x0 + f_xy * y + f_xz * z + f_xyz * y * z) / 2.0;
739*c6f61ee2SBarry Smith     values[1] = (x3 - x0 + f_xy * x + f_yz * z + f_xyz * x * z) / 2.0;
740*c6f61ee2SBarry Smith     values[2] = (x4 - x0 + f_yz * y + f_xz * x + f_xyz * x * y) / 2.0;
741*c6f61ee2SBarry Smith     values[3] = (y1 - y0 + g_xy * y + g_xz * z + g_xyz * y * z) / 2.0;
742*c6f61ee2SBarry Smith     values[4] = (y3 - y0 + g_xy * x + g_yz * z + g_xyz * x * z) / 2.0;
743*c6f61ee2SBarry Smith     values[5] = (y4 - y0 + g_yz * y + g_xz * x + g_xyz * x * y) / 2.0;
744*c6f61ee2SBarry Smith     values[6] = (z1 - z0 + h_xy * y + h_xz * z + h_xyz * y * z) / 2.0;
745*c6f61ee2SBarry Smith     values[7] = (z3 - z0 + h_xy * x + h_yz * z + h_xyz * x * z) / 2.0;
746*c6f61ee2SBarry Smith     values[8] = (z4 - z0 + h_yz * y + h_xz * x + h_xyz * x * y) / 2.0;
747*c6f61ee2SBarry Smith 
748*c6f61ee2SBarry Smith     PetscCall(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES));
749*c6f61ee2SBarry Smith   }
750*c6f61ee2SBarry Smith   PetscCall(PetscLogFlops(152));
751*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(Xref, &ref));
752*c6f61ee2SBarry Smith   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
753*c6f61ee2SBarry Smith   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
754*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
755*c6f61ee2SBarry Smith }
756*c6f61ee2SBarry Smith 
757*c6f61ee2SBarry Smith static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, PetscInt p, Vec xLocal, Vec v)
758*c6f61ee2SBarry Smith {
759*c6f61ee2SBarry Smith   const PetscInt     c = ctx->cells[p];
760*c6f61ee2SBarry Smith   DM                 dmCoord;
761*c6f61ee2SBarry Smith   SNES               snes;
762*c6f61ee2SBarry Smith   KSP                ksp;
763*c6f61ee2SBarry Smith   PC                 pc;
764*c6f61ee2SBarry Smith   Vec                coordsLocal, r, ref, real;
765*c6f61ee2SBarry Smith   Mat                J;
766*c6f61ee2SBarry Smith   const PetscScalar *coords;
767*c6f61ee2SBarry Smith   PetscScalar       *a;
768*c6f61ee2SBarry Smith   PetscScalar       *x = NULL, *vertices = NULL;
769*c6f61ee2SBarry Smith   PetscScalar       *xi;
770*c6f61ee2SBarry Smith   PetscReal          xir[3];
771*c6f61ee2SBarry Smith   PetscInt           coordSize, xSize;
772*c6f61ee2SBarry Smith 
773*c6f61ee2SBarry Smith   PetscFunctionBegin;
774*c6f61ee2SBarry Smith   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
775*c6f61ee2SBarry Smith   PetscCall(DMGetCoordinateDM(dm, &dmCoord));
776*c6f61ee2SBarry Smith   PetscCall(SNESCreate(PETSC_COMM_SELF, &snes));
777*c6f61ee2SBarry Smith   PetscCall(SNESSetOptionsPrefix(snes, "hex_interp_"));
778*c6f61ee2SBarry Smith   PetscCall(VecCreate(PETSC_COMM_SELF, &r));
779*c6f61ee2SBarry Smith   PetscCall(VecSetSizes(r, 3, 3));
780*c6f61ee2SBarry Smith   PetscCall(VecSetType(r, dm->vectype));
781*c6f61ee2SBarry Smith   PetscCall(VecDuplicate(r, &ref));
782*c6f61ee2SBarry Smith   PetscCall(VecDuplicate(r, &real));
783*c6f61ee2SBarry Smith   PetscCall(MatCreate(PETSC_COMM_SELF, &J));
784*c6f61ee2SBarry Smith   PetscCall(MatSetSizes(J, 3, 3, 3, 3));
785*c6f61ee2SBarry Smith   PetscCall(MatSetType(J, MATSEQDENSE));
786*c6f61ee2SBarry Smith   PetscCall(MatSetUp(J));
787*c6f61ee2SBarry Smith   PetscCall(SNESSetFunction(snes, r, HexMap_Private, NULL));
788*c6f61ee2SBarry Smith   PetscCall(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL));
789*c6f61ee2SBarry Smith   PetscCall(SNESGetKSP(snes, &ksp));
790*c6f61ee2SBarry Smith   PetscCall(KSPGetPC(ksp, &pc));
791*c6f61ee2SBarry Smith   PetscCall(PCSetType(pc, PCLU));
792*c6f61ee2SBarry Smith   PetscCall(SNESSetFromOptions(snes));
793*c6f61ee2SBarry Smith 
794*c6f61ee2SBarry Smith   PetscCall(VecGetArrayRead(ctx->coords, &coords));
795*c6f61ee2SBarry Smith   PetscCall(VecGetArray(v, &a));
796*c6f61ee2SBarry Smith   PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
797*c6f61ee2SBarry Smith   PetscCheck(8 * 3 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8 * 3);
798*c6f61ee2SBarry Smith   PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x));
799*c6f61ee2SBarry Smith   PetscCheck((8 * ctx->dof == xSize) || (ctx->dof == xSize), ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input closure size %" PetscInt_FMT " should be %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 8 * ctx->dof, ctx->dof);
800*c6f61ee2SBarry Smith   PetscCall(SNESSetFunction(snes, NULL, NULL, vertices));
801*c6f61ee2SBarry Smith   PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices));
802*c6f61ee2SBarry Smith   PetscCall(VecGetArray(real, &xi));
803*c6f61ee2SBarry Smith   xi[0] = coords[p * ctx->dim + 0];
804*c6f61ee2SBarry Smith   xi[1] = coords[p * ctx->dim + 1];
805*c6f61ee2SBarry Smith   xi[2] = coords[p * ctx->dim + 2];
806*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(real, &xi));
807*c6f61ee2SBarry Smith   PetscCall(SNESSolve(snes, real, ref));
808*c6f61ee2SBarry Smith   PetscCall(VecGetArray(ref, &xi));
809*c6f61ee2SBarry Smith   xir[0] = PetscRealPart(xi[0]);
810*c6f61ee2SBarry Smith   xir[1] = PetscRealPart(xi[1]);
811*c6f61ee2SBarry Smith   xir[2] = PetscRealPart(xi[2]);
812*c6f61ee2SBarry Smith   if (8 * ctx->dof == xSize) {
813*c6f61ee2SBarry Smith     for (PetscInt comp = 0; comp < ctx->dof; ++comp) {
814*c6f61ee2SBarry Smith       a[p * ctx->dof + comp] = x[0 * ctx->dof + comp] * (1 - xir[0]) * (1 - xir[1]) * (1 - xir[2]) + x[3 * ctx->dof + comp] * xir[0] * (1 - xir[1]) * (1 - xir[2]) + x[2 * ctx->dof + comp] * xir[0] * xir[1] * (1 - xir[2]) + x[1 * ctx->dof + comp] * (1 - xir[0]) * xir[1] * (1 - xir[2]) +
815*c6f61ee2SBarry Smith                                x[4 * ctx->dof + comp] * (1 - xir[0]) * (1 - xir[1]) * xir[2] + x[5 * ctx->dof + comp] * xir[0] * (1 - xir[1]) * xir[2] + x[6 * ctx->dof + comp] * xir[0] * xir[1] * xir[2] + x[7 * ctx->dof + comp] * (1 - xir[0]) * xir[1] * xir[2];
816*c6f61ee2SBarry Smith     }
817*c6f61ee2SBarry Smith   } else {
818*c6f61ee2SBarry Smith     for (PetscInt comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp];
819*c6f61ee2SBarry Smith   }
820*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(ref, &xi));
821*c6f61ee2SBarry Smith   PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices));
822*c6f61ee2SBarry Smith   PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x));
823*c6f61ee2SBarry Smith   PetscCall(VecRestoreArray(v, &a));
824*c6f61ee2SBarry Smith   PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
825*c6f61ee2SBarry Smith 
826*c6f61ee2SBarry Smith   PetscCall(SNESDestroy(&snes));
827*c6f61ee2SBarry Smith   PetscCall(VecDestroy(&r));
828*c6f61ee2SBarry Smith   PetscCall(VecDestroy(&ref));
829*c6f61ee2SBarry Smith   PetscCall(VecDestroy(&real));
830*c6f61ee2SBarry Smith   PetscCall(MatDestroy(&J));
831*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
832*c6f61ee2SBarry Smith }
833*c6f61ee2SBarry Smith 
834*c6f61ee2SBarry Smith /*@C
835*c6f61ee2SBarry Smith   DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points.
836*c6f61ee2SBarry Smith 
837*c6f61ee2SBarry Smith   Input Parameters:
838*c6f61ee2SBarry Smith + ctx - The `DMInterpolationInfo` context
839*c6f61ee2SBarry Smith . dm  - The `DM`
840*c6f61ee2SBarry Smith - x   - The local vector containing the field to be interpolated
841*c6f61ee2SBarry Smith 
842*c6f61ee2SBarry Smith   Output Parameter:
843*c6f61ee2SBarry Smith . v - The vector containing the interpolated values
844*c6f61ee2SBarry Smith 
845*c6f61ee2SBarry Smith   Level: beginner
846*c6f61ee2SBarry Smith 
847*c6f61ee2SBarry Smith   Note:
848*c6f61ee2SBarry Smith   A suitable `v` can be obtained using `DMInterpolationGetVector()`.
849*c6f61ee2SBarry Smith 
850*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
851*c6f61ee2SBarry Smith @*/
852*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v)
853*c6f61ee2SBarry Smith {
854*c6f61ee2SBarry Smith   PetscDS   ds;
855*c6f61ee2SBarry Smith   PetscInt  n, p, Nf, field;
856*c6f61ee2SBarry Smith   PetscBool useDS = PETSC_FALSE;
857*c6f61ee2SBarry Smith 
858*c6f61ee2SBarry Smith   PetscFunctionBegin;
859*c6f61ee2SBarry Smith   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
860*c6f61ee2SBarry Smith   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
861*c6f61ee2SBarry Smith   PetscValidHeaderSpecific(v, VEC_CLASSID, 4);
862*c6f61ee2SBarry Smith   PetscCall(VecGetLocalSize(v, &n));
863*c6f61ee2SBarry Smith   PetscCheck(n == ctx->n * ctx->dof, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input vector size %" PetscInt_FMT " should be %" PetscInt_FMT, n, ctx->n * ctx->dof);
864*c6f61ee2SBarry Smith   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
865*c6f61ee2SBarry Smith   PetscCall(DMGetDS(dm, &ds));
866*c6f61ee2SBarry Smith   if (ds) {
867*c6f61ee2SBarry Smith     useDS = PETSC_TRUE;
868*c6f61ee2SBarry Smith     PetscCall(PetscDSGetNumFields(ds, &Nf));
869*c6f61ee2SBarry Smith     for (field = 0; field < Nf; ++field) {
870*c6f61ee2SBarry Smith       PetscObject  obj;
871*c6f61ee2SBarry Smith       PetscClassId id;
872*c6f61ee2SBarry Smith 
873*c6f61ee2SBarry Smith       PetscCall(PetscDSGetDiscretization(ds, field, &obj));
874*c6f61ee2SBarry Smith       PetscCall(PetscObjectGetClassId(obj, &id));
875*c6f61ee2SBarry Smith       if (id != PETSCFE_CLASSID && id != PETSCFV_CLASSID) {
876*c6f61ee2SBarry Smith         useDS = PETSC_FALSE;
877*c6f61ee2SBarry Smith         break;
878*c6f61ee2SBarry Smith       }
879*c6f61ee2SBarry Smith     }
880*c6f61ee2SBarry Smith   }
881*c6f61ee2SBarry Smith   if (useDS) {
882*c6f61ee2SBarry Smith     const PetscScalar *coords;
883*c6f61ee2SBarry Smith     PetscScalar       *interpolant;
884*c6f61ee2SBarry Smith     PetscInt           cdim, d;
885*c6f61ee2SBarry Smith 
886*c6f61ee2SBarry Smith     PetscCall(DMGetCoordinateDim(dm, &cdim));
887*c6f61ee2SBarry Smith     PetscCall(VecGetArrayRead(ctx->coords, &coords));
888*c6f61ee2SBarry Smith     PetscCall(VecGetArrayWrite(v, &interpolant));
889*c6f61ee2SBarry Smith     for (p = 0; p < ctx->n; ++p) {
890*c6f61ee2SBarry Smith       PetscReal    pcoords[3], xi[3];
891*c6f61ee2SBarry Smith       PetscScalar *xa   = NULL;
892*c6f61ee2SBarry Smith       PetscInt     coff = 0, foff = 0, clSize;
893*c6f61ee2SBarry Smith 
894*c6f61ee2SBarry Smith       if (ctx->cells[p] < 0) continue;
895*c6f61ee2SBarry Smith       for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p * cdim + d]);
896*c6f61ee2SBarry Smith       PetscCall(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi));
897*c6f61ee2SBarry Smith       PetscCall(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
898*c6f61ee2SBarry Smith       for (field = 0; field < Nf; ++field) {
899*c6f61ee2SBarry Smith         PetscTabulation T;
900*c6f61ee2SBarry Smith         PetscObject     obj;
901*c6f61ee2SBarry Smith         PetscClassId    id;
902*c6f61ee2SBarry Smith 
903*c6f61ee2SBarry Smith         PetscCall(PetscDSGetDiscretization(ds, field, &obj));
904*c6f61ee2SBarry Smith         PetscCall(PetscObjectGetClassId(obj, &id));
905*c6f61ee2SBarry Smith         if (id == PETSCFE_CLASSID) {
906*c6f61ee2SBarry Smith           PetscFE fe = (PetscFE)obj;
907*c6f61ee2SBarry Smith 
908*c6f61ee2SBarry Smith           PetscCall(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T));
909*c6f61ee2SBarry Smith           {
910*c6f61ee2SBarry Smith             const PetscReal *basis = T->T[0];
911*c6f61ee2SBarry Smith             const PetscInt   Nb    = T->Nb;
912*c6f61ee2SBarry Smith             const PetscInt   Nc    = T->Nc;
913*c6f61ee2SBarry Smith 
914*c6f61ee2SBarry Smith             for (PetscInt fc = 0; fc < Nc; ++fc) {
915*c6f61ee2SBarry Smith               interpolant[p * ctx->dof + coff + fc] = 0.0;
916*c6f61ee2SBarry Smith               for (PetscInt f = 0; f < Nb; ++f) interpolant[p * ctx->dof + coff + fc] += xa[foff + f] * basis[(0 * Nb + f) * Nc + fc];
917*c6f61ee2SBarry Smith             }
918*c6f61ee2SBarry Smith             coff += Nc;
919*c6f61ee2SBarry Smith             foff += Nb;
920*c6f61ee2SBarry Smith           }
921*c6f61ee2SBarry Smith           PetscCall(PetscTabulationDestroy(&T));
922*c6f61ee2SBarry Smith         } else if (id == PETSCFV_CLASSID) {
923*c6f61ee2SBarry Smith           PetscFV  fv = (PetscFV)obj;
924*c6f61ee2SBarry Smith           PetscInt Nc;
925*c6f61ee2SBarry Smith 
926*c6f61ee2SBarry Smith           // TODO Could use reconstruction if available
927*c6f61ee2SBarry Smith           PetscCall(PetscFVGetNumComponents(fv, &Nc));
928*c6f61ee2SBarry Smith           for (PetscInt fc = 0; fc < Nc; ++fc) interpolant[p * ctx->dof + coff + fc] = xa[foff + fc];
929*c6f61ee2SBarry Smith           coff += Nc;
930*c6f61ee2SBarry Smith           foff += Nc;
931*c6f61ee2SBarry Smith         }
932*c6f61ee2SBarry Smith       }
933*c6f61ee2SBarry Smith       PetscCall(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa));
934*c6f61ee2SBarry Smith       PetscCheck(coff == ctx->dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %" PetscInt_FMT " != %" PetscInt_FMT " dof specified for interpolation", coff, ctx->dof);
935*c6f61ee2SBarry Smith       PetscCheck(foff == clSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE/FV space size %" PetscInt_FMT " != %" PetscInt_FMT " closure size", foff, clSize);
936*c6f61ee2SBarry Smith     }
937*c6f61ee2SBarry Smith     PetscCall(VecRestoreArrayRead(ctx->coords, &coords));
938*c6f61ee2SBarry Smith     PetscCall(VecRestoreArrayWrite(v, &interpolant));
939*c6f61ee2SBarry Smith   } else {
940*c6f61ee2SBarry Smith     for (PetscInt p = 0; p < ctx->n; ++p) {
941*c6f61ee2SBarry Smith       const PetscInt cell = ctx->cells[p];
942*c6f61ee2SBarry Smith       DMPolytopeType ct;
943*c6f61ee2SBarry Smith 
944*c6f61ee2SBarry Smith       PetscCall(DMPlexGetCellType(dm, cell, &ct));
945*c6f61ee2SBarry Smith       switch (ct) {
946*c6f61ee2SBarry Smith       case DM_POLYTOPE_SEGMENT:
947*c6f61ee2SBarry Smith         PetscCall(DMInterpolate_Segment_Private(ctx, dm, p, x, v));
948*c6f61ee2SBarry Smith         break;
949*c6f61ee2SBarry Smith       case DM_POLYTOPE_TRIANGLE:
950*c6f61ee2SBarry Smith         PetscCall(DMInterpolate_Triangle_Private(ctx, dm, p, x, v));
951*c6f61ee2SBarry Smith         break;
952*c6f61ee2SBarry Smith       case DM_POLYTOPE_QUADRILATERAL:
953*c6f61ee2SBarry Smith         PetscCall(DMInterpolate_Quad_Private(ctx, dm, p, x, v));
954*c6f61ee2SBarry Smith         break;
955*c6f61ee2SBarry Smith       case DM_POLYTOPE_TETRAHEDRON:
956*c6f61ee2SBarry Smith         PetscCall(DMInterpolate_Tetrahedron_Private(ctx, dm, p, x, v));
957*c6f61ee2SBarry Smith         break;
958*c6f61ee2SBarry Smith       case DM_POLYTOPE_HEXAHEDRON:
959*c6f61ee2SBarry Smith         PetscCall(DMInterpolate_Hex_Private(ctx, dm, cell, x, v));
960*c6f61ee2SBarry Smith         break;
961*c6f61ee2SBarry Smith       default:
962*c6f61ee2SBarry Smith         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]);
963*c6f61ee2SBarry Smith       }
964*c6f61ee2SBarry Smith     }
965*c6f61ee2SBarry Smith   }
966*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
967*c6f61ee2SBarry Smith }
968*c6f61ee2SBarry Smith 
969*c6f61ee2SBarry Smith /*@C
970*c6f61ee2SBarry Smith   DMInterpolationDestroy - Destroys a `DMInterpolationInfo` context
971*c6f61ee2SBarry Smith 
972*c6f61ee2SBarry Smith   Collective
973*c6f61ee2SBarry Smith 
974*c6f61ee2SBarry Smith   Input Parameter:
975*c6f61ee2SBarry Smith . ctx - the context
976*c6f61ee2SBarry Smith 
977*c6f61ee2SBarry Smith   Level: beginner
978*c6f61ee2SBarry Smith 
979*c6f61ee2SBarry Smith .seealso: [](ch_snes), `DM`, `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()`
980*c6f61ee2SBarry Smith @*/
981*c6f61ee2SBarry Smith PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx)
982*c6f61ee2SBarry Smith {
983*c6f61ee2SBarry Smith   PetscFunctionBegin;
984*c6f61ee2SBarry Smith   PetscAssertPointer(ctx, 1);
985*c6f61ee2SBarry Smith   PetscCall(VecDestroy(&(*ctx)->coords));
986*c6f61ee2SBarry Smith   PetscCall(PetscFree((*ctx)->points));
987*c6f61ee2SBarry Smith   PetscCall(PetscFree((*ctx)->cells));
988*c6f61ee2SBarry Smith   PetscCall(PetscFree(*ctx));
989*c6f61ee2SBarry Smith   *ctx = NULL;
990*c6f61ee2SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
991*c6f61ee2SBarry Smith }
992