xref: /petsc/src/dm/dt/dualspace/impls/lagrange/dspacelagrange.c (revision d083f849a86f1f43e18d534ee43954e2786cb29a)
120cf1dd8SToby Isaac #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
220cf1dd8SToby Isaac #include <petscdmplex.h>
320cf1dd8SToby Isaac 
46f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceDestroy_Lagrange(PetscDualSpace sp)
520cf1dd8SToby Isaac {
620cf1dd8SToby Isaac   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
76f905325SMatthew G. Knepley   PetscInt            i;
86f905325SMatthew G. Knepley   PetscErrorCode      ierr;
920cf1dd8SToby Isaac 
1020cf1dd8SToby Isaac   PetscFunctionBegin;
116f905325SMatthew G. Knepley   if (lag->symmetries) {
126f905325SMatthew G. Knepley     PetscInt **selfSyms = lag->symmetries[0];
136f905325SMatthew G. Knepley 
146f905325SMatthew G. Knepley     if (selfSyms) {
156f905325SMatthew G. Knepley       PetscInt i, **allocated = &selfSyms[-lag->selfSymOff];
166f905325SMatthew G. Knepley 
176f905325SMatthew G. Knepley       for (i = 0; i < lag->numSelfSym; i++) {
186f905325SMatthew G. Knepley         ierr = PetscFree(allocated[i]);CHKERRQ(ierr);
196f905325SMatthew G. Knepley       }
206f905325SMatthew G. Knepley       ierr = PetscFree(allocated);CHKERRQ(ierr);
216f905325SMatthew G. Knepley     }
226f905325SMatthew G. Knepley     ierr = PetscFree(lag->symmetries);CHKERRQ(ierr);
236f905325SMatthew G. Knepley   }
246f905325SMatthew G. Knepley   for (i = 0; i < lag->height; i++) {
256f905325SMatthew G. Knepley     ierr = PetscDualSpaceDestroy(&lag->subspaces[i]);CHKERRQ(ierr);
266f905325SMatthew G. Knepley   }
276f905325SMatthew G. Knepley   ierr = PetscFree(lag->subspaces);CHKERRQ(ierr);
286f905325SMatthew G. Knepley   ierr = PetscFree(lag->numDof);CHKERRQ(ierr);
296f905325SMatthew G. Knepley   ierr = PetscFree(lag);CHKERRQ(ierr);
306f905325SMatthew G. Knepley   ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetContinuity_C", NULL);CHKERRQ(ierr);
316f905325SMatthew G. Knepley   ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetContinuity_C", NULL);CHKERRQ(ierr);
326f905325SMatthew G. Knepley   ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetTensor_C", NULL);CHKERRQ(ierr);
336f905325SMatthew G. Knepley   ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetTensor_C", NULL);CHKERRQ(ierr);
3420cf1dd8SToby Isaac   PetscFunctionReturn(0);
3520cf1dd8SToby Isaac }
3620cf1dd8SToby Isaac 
376f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeView_Ascii(PetscDualSpace sp, PetscViewer viewer)
3820cf1dd8SToby Isaac {
3920cf1dd8SToby Isaac   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
406f905325SMatthew G. Knepley   PetscErrorCode      ierr;
4120cf1dd8SToby Isaac 
4220cf1dd8SToby Isaac   PetscFunctionBegin;
436f905325SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "%s %sLagrange dual space\n", lag->continuous ? "Continuous" : "Discontinuous", lag->tensorSpace ? "tensor " : "");CHKERRQ(ierr);
4420cf1dd8SToby Isaac   PetscFunctionReturn(0);
4520cf1dd8SToby Isaac }
4620cf1dd8SToby Isaac 
476f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceView_Lagrange(PetscDualSpace sp, PetscViewer viewer)
4820cf1dd8SToby Isaac {
496f905325SMatthew G. Knepley   PetscBool      iascii;
506f905325SMatthew G. Knepley   PetscErrorCode ierr;
516f905325SMatthew G. Knepley 
5220cf1dd8SToby Isaac   PetscFunctionBegin;
536f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
546f905325SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
556f905325SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
566f905325SMatthew G. Knepley   if (iascii) {ierr = PetscDualSpaceLagrangeView_Ascii(sp, viewer);CHKERRQ(ierr);}
5720cf1dd8SToby Isaac   PetscFunctionReturn(0);
5820cf1dd8SToby Isaac }
5920cf1dd8SToby Isaac 
606f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceSetFromOptions_Lagrange(PetscOptionItems *PetscOptionsObject,PetscDualSpace sp)
6120cf1dd8SToby Isaac {
626f905325SMatthew G. Knepley   PetscBool      continuous, tensor, flg;
636f905325SMatthew G. Knepley   PetscErrorCode ierr;
646f905325SMatthew G. Knepley 
656f905325SMatthew G. Knepley   PetscFunctionBegin;
666f905325SMatthew G. Knepley   ierr = PetscDualSpaceLagrangeGetContinuity(sp, &continuous);CHKERRQ(ierr);
676f905325SMatthew G. Knepley   ierr = PetscDualSpaceLagrangeGetTensor(sp, &tensor);CHKERRQ(ierr);
686f905325SMatthew G. Knepley   ierr = PetscOptionsHead(PetscOptionsObject,"PetscDualSpace Lagrange Options");CHKERRQ(ierr);
696f905325SMatthew G. Knepley   ierr = PetscOptionsBool("-petscdualspace_lagrange_continuity", "Flag for continuous element", "PetscDualSpaceLagrangeSetContinuity", continuous, &continuous, &flg);CHKERRQ(ierr);
706f905325SMatthew G. Knepley   if (flg) {ierr = PetscDualSpaceLagrangeSetContinuity(sp, continuous);CHKERRQ(ierr);}
716f905325SMatthew G. Knepley   ierr = PetscOptionsBool("-petscdualspace_lagrange_tensor", "Flag for tensor dual space", "PetscDualSpaceLagrangeSetContinuity", tensor, &tensor, &flg);CHKERRQ(ierr);
726f905325SMatthew G. Knepley   if (flg) {ierr = PetscDualSpaceLagrangeSetTensor(sp, tensor);CHKERRQ(ierr);}
736f905325SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
746f905325SMatthew G. Knepley   PetscFunctionReturn(0);
756f905325SMatthew G. Knepley }
766f905325SMatthew G. Knepley 
776f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceDuplicate_Lagrange(PetscDualSpace sp, PetscDualSpace *spNew)
786f905325SMatthew G. Knepley {
796f905325SMatthew G. Knepley   PetscInt       order, Nc;
806f905325SMatthew G. Knepley   PetscBool      cont, tensor;
816f905325SMatthew G. Knepley   const char    *name;
826f905325SMatthew G. Knepley   PetscErrorCode ierr;
836f905325SMatthew G. Knepley 
846f905325SMatthew G. Knepley   PetscFunctionBegin;
856f905325SMatthew G. Knepley   ierr = PetscDualSpaceCreate(PetscObjectComm((PetscObject) sp), spNew);CHKERRQ(ierr);
866f905325SMatthew G. Knepley   ierr = PetscObjectGetName((PetscObject) sp,     &name);CHKERRQ(ierr);
876f905325SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) *spNew,  name);CHKERRQ(ierr);
886f905325SMatthew G. Knepley   ierr = PetscDualSpaceSetType(*spNew, PETSCDUALSPACELAGRANGE);CHKERRQ(ierr);
896f905325SMatthew G. Knepley   ierr = PetscDualSpaceGetOrder(sp, &order);CHKERRQ(ierr);
906f905325SMatthew G. Knepley   ierr = PetscDualSpaceSetOrder(*spNew, order);CHKERRQ(ierr);
916f905325SMatthew G. Knepley   ierr = PetscDualSpaceGetNumComponents(sp, &Nc);CHKERRQ(ierr);
926f905325SMatthew G. Knepley   ierr = PetscDualSpaceSetNumComponents(*spNew, Nc);CHKERRQ(ierr);
936f905325SMatthew G. Knepley   ierr = PetscDualSpaceLagrangeGetContinuity(sp, &cont);CHKERRQ(ierr);
946f905325SMatthew G. Knepley   ierr = PetscDualSpaceLagrangeSetContinuity(*spNew, cont);CHKERRQ(ierr);
956f905325SMatthew G. Knepley   ierr = PetscDualSpaceLagrangeGetTensor(sp, &tensor);CHKERRQ(ierr);
966f905325SMatthew G. Knepley   ierr = PetscDualSpaceLagrangeSetTensor(*spNew, tensor);CHKERRQ(ierr);
976f905325SMatthew G. Knepley   PetscFunctionReturn(0);
986f905325SMatthew G. Knepley }
996f905325SMatthew G. Knepley 
1006f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceGetDimension_SingleCell_Lagrange(PetscDualSpace sp, PetscInt order, PetscInt *dim)
1016f905325SMatthew G. Knepley {
1026f905325SMatthew G. Knepley   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
1036f905325SMatthew G. Knepley   PetscReal           D   = 1.0;
1046f905325SMatthew G. Knepley   PetscInt            n, d;
1056f905325SMatthew G. Knepley   PetscErrorCode      ierr;
1066f905325SMatthew G. Knepley 
1076f905325SMatthew G. Knepley   PetscFunctionBegin;
1086f905325SMatthew G. Knepley   *dim = -1;
1096f905325SMatthew G. Knepley   ierr = DMGetDimension(sp->dm, &n);CHKERRQ(ierr);
1106f905325SMatthew G. Knepley   if (!lag->tensorSpace) {
1116f905325SMatthew G. Knepley     for (d = 1; d <= n; ++d) {
1126f905325SMatthew G. Knepley       D *= ((PetscReal) (order+d))/d;
1136f905325SMatthew G. Knepley     }
1146f905325SMatthew G. Knepley     *dim = (PetscInt) (D + 0.5);
1156f905325SMatthew G. Knepley   } else {
1166f905325SMatthew G. Knepley     *dim = 1;
1176f905325SMatthew G. Knepley     for (d = 0; d < n; ++d) *dim *= (order+1);
1186f905325SMatthew G. Knepley   }
1196f905325SMatthew G. Knepley   *dim *= sp->Nc;
1206f905325SMatthew G. Knepley   PetscFunctionReturn(0);
1216f905325SMatthew G. Knepley }
1226f905325SMatthew G. Knepley 
1236f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceCreateHeightSubspace_Lagrange(PetscDualSpace sp, PetscInt height, PetscDualSpace *bdsp)
1246f905325SMatthew G. Knepley {
1256f905325SMatthew G. Knepley   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
1266f905325SMatthew G. Knepley   PetscBool          continuous, tensor;
1276f905325SMatthew G. Knepley   PetscInt           order;
1286f905325SMatthew G. Knepley   PetscErrorCode     ierr;
1296f905325SMatthew G. Knepley 
1306f905325SMatthew G. Knepley   PetscFunctionBegin;
1316f905325SMatthew G. Knepley   ierr = PetscDualSpaceLagrangeGetContinuity(sp,&continuous);CHKERRQ(ierr);
1326f905325SMatthew G. Knepley   ierr = PetscDualSpaceGetOrder(sp,&order);CHKERRQ(ierr);
1336f905325SMatthew G. Knepley   if (height == 0) {
1346f905325SMatthew G. Knepley     ierr = PetscObjectReference((PetscObject)sp);CHKERRQ(ierr);
1356f905325SMatthew G. Knepley     *bdsp = sp;
1366f905325SMatthew G. Knepley   } else if (continuous == PETSC_FALSE || !order) {
1376f905325SMatthew G. Knepley     *bdsp = NULL;
1386f905325SMatthew G. Knepley   } else {
1396f905325SMatthew G. Knepley     DM dm, K;
1406f905325SMatthew G. Knepley     PetscInt dim;
1416f905325SMatthew G. Knepley 
1426f905325SMatthew G. Knepley     ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr);
1436f905325SMatthew G. Knepley     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1446f905325SMatthew G. Knepley     if (height > dim || height < 0) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Asked for dual space at height %d for dimension %d reference element\n",height,dim);
1456f905325SMatthew G. Knepley     ierr = PetscDualSpaceDuplicate(sp,bdsp);CHKERRQ(ierr);
1466f905325SMatthew G. Knepley     ierr = PetscDualSpaceCreateReferenceCell(*bdsp, dim-height, lag->simplexCell, &K);CHKERRQ(ierr);
1476f905325SMatthew G. Knepley     ierr = PetscDualSpaceSetDM(*bdsp, K);CHKERRQ(ierr);
1486f905325SMatthew G. Knepley     ierr = DMDestroy(&K);CHKERRQ(ierr);
1496f905325SMatthew G. Knepley     ierr = PetscDualSpaceLagrangeGetTensor(sp,&tensor);CHKERRQ(ierr);
1506f905325SMatthew G. Knepley     ierr = PetscDualSpaceLagrangeSetTensor(*bdsp,tensor);CHKERRQ(ierr);
1516f905325SMatthew G. Knepley     ierr = PetscDualSpaceSetUp(*bdsp);CHKERRQ(ierr);
1526f905325SMatthew G. Knepley   }
1536f905325SMatthew G. Knepley   PetscFunctionReturn(0);
1546f905325SMatthew G. Knepley }
1556f905325SMatthew G. Knepley 
1566f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceSetUp_Lagrange(PetscDualSpace sp)
1576f905325SMatthew G. Knepley {
1586f905325SMatthew G. Knepley   PetscDualSpace_Lag *lag   = (PetscDualSpace_Lag *) sp->data;
1596f905325SMatthew G. Knepley   DM                  dm    = sp->dm;
1606f905325SMatthew G. Knepley   PetscInt            order = sp->order;
1616f905325SMatthew G. Knepley   PetscInt            Nc    = sp->Nc;
1626f905325SMatthew G. Knepley   MPI_Comm            comm;
1636f905325SMatthew G. Knepley   PetscBool           continuous;
1646f905325SMatthew G. Knepley   PetscSection        csection;
1656f905325SMatthew G. Knepley   Vec                 coordinates;
1666f905325SMatthew G. Knepley   PetscReal          *qpoints, *qweights;
1676f905325SMatthew G. Knepley   PetscInt            depth, dim, pdimMax, pStart, pEnd, p, *pStratStart, *pStratEnd, coneSize, d, f = 0, c;
1686f905325SMatthew G. Knepley   PetscBool           simplex, tensorSpace;
1696f905325SMatthew G. Knepley   PetscErrorCode      ierr;
1706f905325SMatthew G. Knepley 
1716f905325SMatthew G. Knepley   PetscFunctionBegin;
1726f905325SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) sp, &comm);CHKERRQ(ierr);
1736f905325SMatthew G. Knepley   if (!order) lag->continuous = PETSC_FALSE;
1746f905325SMatthew G. Knepley   continuous = lag->continuous;
1756f905325SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1766f905325SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1776f905325SMatthew G. Knepley   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1786f905325SMatthew G. Knepley   ierr = PetscCalloc1(dim+1, &lag->numDof);CHKERRQ(ierr);
1796f905325SMatthew G. Knepley   ierr = PetscMalloc2(depth+1,&pStratStart,depth+1,&pStratEnd);CHKERRQ(ierr);
1806f905325SMatthew G. Knepley   for (d = 0; d <= depth; ++d) {ierr = DMPlexGetDepthStratum(dm, d, &pStratStart[d], &pStratEnd[d]);CHKERRQ(ierr);}
1816f905325SMatthew G. Knepley   ierr = DMPlexGetConeSize(dm, pStratStart[depth], &coneSize);CHKERRQ(ierr);
1826f905325SMatthew G. Knepley   ierr = DMGetCoordinateSection(dm, &csection);CHKERRQ(ierr);
1836f905325SMatthew G. Knepley   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
1846f905325SMatthew G. Knepley   if (depth == 1) {
1856f905325SMatthew G. Knepley     if      (coneSize == dim+1)    simplex = PETSC_TRUE;
1866f905325SMatthew G. Knepley     else if (coneSize == 1 << dim) simplex = PETSC_FALSE;
1876f905325SMatthew G. Knepley     else SETERRQ(comm, PETSC_ERR_SUP, "Only support simplices and tensor product cells");
1886f905325SMatthew G. Knepley   } else if (depth == dim) {
1896f905325SMatthew G. Knepley     if      (coneSize == dim+1)   simplex = PETSC_TRUE;
1906f905325SMatthew G. Knepley     else if (coneSize == 2 * dim) simplex = PETSC_FALSE;
1916f905325SMatthew G. Knepley     else SETERRQ(comm, PETSC_ERR_SUP, "Only support simplices and tensor product cells");
1926f905325SMatthew G. Knepley   } else SETERRQ(comm, PETSC_ERR_SUP, "Only support cell-vertex meshes or fully interpolated meshes");
1936f905325SMatthew G. Knepley   lag->simplexCell = simplex;
1946f905325SMatthew G. Knepley   if (dim > 1 && continuous && lag->simplexCell == lag->tensorSpace) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP, "Mismatching simplex/tensor cells and spaces only allowed for discontinuous elements");
1956f905325SMatthew G. Knepley   tensorSpace    = lag->tensorSpace;
1966f905325SMatthew G. Knepley   lag->height    = 0;
1976f905325SMatthew G. Knepley   lag->subspaces = NULL;
1986f905325SMatthew G. Knepley   if (continuous && order > 0 && dim > 0) {
19920cf1dd8SToby Isaac     PetscInt i;
20020cf1dd8SToby Isaac 
2016f905325SMatthew G. Knepley     lag->height = dim;
2026f905325SMatthew G. Knepley     ierr = PetscMalloc1(dim,&lag->subspaces);CHKERRQ(ierr);
2036f905325SMatthew G. Knepley     ierr = PetscDualSpaceCreateHeightSubspace_Lagrange(sp,1,&lag->subspaces[0]);CHKERRQ(ierr);
2046f905325SMatthew G. Knepley     ierr = PetscDualSpaceSetUp(lag->subspaces[0]);CHKERRQ(ierr);
2056f905325SMatthew G. Knepley     for (i = 1; i < dim; i++) {
2066f905325SMatthew G. Knepley       ierr = PetscDualSpaceGetHeightSubspace(lag->subspaces[i-1],1,&lag->subspaces[i]);CHKERRQ(ierr);
2076f905325SMatthew G. Knepley       ierr = PetscObjectReference((PetscObject)(lag->subspaces[i]));CHKERRQ(ierr);
2086f905325SMatthew G. Knepley     }
2096f905325SMatthew G. Knepley   }
2106f905325SMatthew G. Knepley   ierr = PetscDualSpaceGetDimension_SingleCell_Lagrange(sp, sp->order, &pdimMax);CHKERRQ(ierr);
2116f905325SMatthew G. Knepley   pdimMax *= (pStratEnd[depth] - pStratStart[depth]);
2126f905325SMatthew G. Knepley   ierr = PetscMalloc1(pdimMax, &sp->functional);CHKERRQ(ierr);
2136f905325SMatthew G. Knepley   if (!dim) {
2146f905325SMatthew G. Knepley     for (c = 0; c < Nc; ++c) {
2156f905325SMatthew G. Knepley       ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &sp->functional[f]);CHKERRQ(ierr);
2166f905325SMatthew G. Knepley       ierr = PetscCalloc1(Nc, &qweights);CHKERRQ(ierr);
2176f905325SMatthew G. Knepley       ierr = PetscQuadratureSetOrder(sp->functional[f], 0);CHKERRQ(ierr);
2186f905325SMatthew G. Knepley       ierr = PetscQuadratureSetData(sp->functional[f], 0, Nc, 1, NULL, qweights);CHKERRQ(ierr);
2196f905325SMatthew G. Knepley       qweights[c] = 1.0;
2206f905325SMatthew G. Knepley       ++f;
2216f905325SMatthew G. Knepley       lag->numDof[0]++;
2226f905325SMatthew G. Knepley     }
22320cf1dd8SToby Isaac   } else {
2246f905325SMatthew G. Knepley     PetscSection section;
2256f905325SMatthew G. Knepley     PetscReal    *v0, *hv0, *J, *invJ, detJ, hdetJ;
2266f905325SMatthew G. Knepley     PetscInt     *tup;
2276f905325SMatthew G. Knepley 
2286f905325SMatthew G. Knepley     ierr = PetscSectionCreate(PETSC_COMM_SELF,&section);CHKERRQ(ierr);
2296f905325SMatthew G. Knepley     ierr = PetscSectionSetChart(section,pStart,pEnd);CHKERRQ(ierr);
2306f905325SMatthew G. Knepley     ierr = PetscCalloc5(dim+1,&tup,dim,&v0,dim,&hv0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr);
2316f905325SMatthew G. Knepley     for (p = pStart; p < pEnd; p++) {
2326f905325SMatthew G. Knepley       PetscInt       pointDim, d, nFunc = 0;
2336f905325SMatthew G. Knepley       PetscDualSpace hsp;
2346f905325SMatthew G. Knepley 
2356f905325SMatthew G. Knepley       ierr = DMPlexComputeCellGeometryFEM(dm, p, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr);
2366f905325SMatthew G. Knepley       for (d = 0; d < depth; d++) {if (p >= pStratStart[d] && p < pStratEnd[d]) break;}
2376f905325SMatthew G. Knepley       pointDim = (depth == 1 && d == 1) ? dim : d;
2386f905325SMatthew G. Knepley       hsp = ((pointDim < dim) && lag->subspaces) ? lag->subspaces[dim - pointDim - 1] : NULL;
2396f905325SMatthew G. Knepley       if (hsp) {
2406f905325SMatthew G. Knepley         PetscDualSpace_Lag *hlag = (PetscDualSpace_Lag *) hsp->data;
2416f905325SMatthew G. Knepley         DM                 hdm;
2426f905325SMatthew G. Knepley 
2436f905325SMatthew G. Knepley         ierr = PetscDualSpaceGetDM(hsp,&hdm);CHKERRQ(ierr);
2446f905325SMatthew G. Knepley         ierr = DMPlexComputeCellGeometryFEM(hdm, 0, NULL, hv0, NULL, NULL, &hdetJ);CHKERRQ(ierr);
2456f905325SMatthew G. Knepley         nFunc = lag->numDof[pointDim] = hlag->numDof[pointDim];
2466f905325SMatthew G. Knepley       }
2476f905325SMatthew G. Knepley       if (pointDim == dim) {
2486f905325SMatthew G. Knepley         /* Cells, create for self */
2496f905325SMatthew G. Knepley         PetscInt     orderEff = continuous ? (!tensorSpace ? order-1-dim : order-2) : order;
2506f905325SMatthew G. Knepley         PetscReal    denom    = continuous ? order : (!tensorSpace ? order+1+dim : order+2);
2516f905325SMatthew G. Knepley         PetscReal    numer    = (!simplex || !tensorSpace) ? 2. : (2./dim);
2526f905325SMatthew G. Knepley         PetscReal    dx = numer/denom;
2536f905325SMatthew G. Knepley         PetscInt     cdim, d, d2;
2546f905325SMatthew G. Knepley 
2556f905325SMatthew G. Knepley         if (orderEff < 0) continue;
2566f905325SMatthew G. Knepley         ierr = PetscDualSpaceGetDimension_SingleCell_Lagrange(sp, orderEff, &cdim);CHKERRQ(ierr);
2576f905325SMatthew G. Knepley         ierr = PetscMemzero(tup,(dim+1)*sizeof(PetscInt));CHKERRQ(ierr);
2586f905325SMatthew G. Knepley         if (!tensorSpace) {
2596f905325SMatthew G. Knepley           while (!tup[dim]) {
2606f905325SMatthew G. Knepley             for (c = 0; c < Nc; ++c) {
2616f905325SMatthew G. Knepley               ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &sp->functional[f]);CHKERRQ(ierr);
2626f905325SMatthew G. Knepley               ierr = PetscMalloc1(dim, &qpoints);CHKERRQ(ierr);
2636f905325SMatthew G. Knepley               ierr = PetscCalloc1(Nc,  &qweights);CHKERRQ(ierr);
2646f905325SMatthew G. Knepley               ierr = PetscQuadratureSetOrder(sp->functional[f], 0);CHKERRQ(ierr);
2656f905325SMatthew G. Knepley               ierr = PetscQuadratureSetData(sp->functional[f], dim, Nc, 1, qpoints, qweights);CHKERRQ(ierr);
2666f905325SMatthew G. Knepley               for (d = 0; d < dim; ++d) {
2676f905325SMatthew G. Knepley                 qpoints[d] = v0[d];
2686f905325SMatthew G. Knepley                 for (d2 = 0; d2 < dim; ++d2) qpoints[d] += J[d*dim+d2]*((tup[d2]+1)*dx);
2696f905325SMatthew G. Knepley               }
2706f905325SMatthew G. Knepley               qweights[c] = 1.0;
2716f905325SMatthew G. Knepley               ++f;
2726f905325SMatthew G. Knepley             }
2736f905325SMatthew G. Knepley             ierr = PetscDualSpaceLatticePointLexicographic_Internal(dim, orderEff, tup);CHKERRQ(ierr);
2746f905325SMatthew G. Knepley           }
2756f905325SMatthew G. Knepley         } else {
2766f905325SMatthew G. Knepley           while (!tup[dim]) {
2776f905325SMatthew G. Knepley             for (c = 0; c < Nc; ++c) {
2786f905325SMatthew G. Knepley               ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &sp->functional[f]);CHKERRQ(ierr);
2796f905325SMatthew G. Knepley               ierr = PetscMalloc1(dim, &qpoints);CHKERRQ(ierr);
2806f905325SMatthew G. Knepley               ierr = PetscCalloc1(Nc,  &qweights);CHKERRQ(ierr);
2816f905325SMatthew G. Knepley               ierr = PetscQuadratureSetOrder(sp->functional[f], 0);CHKERRQ(ierr);
2826f905325SMatthew G. Knepley               ierr = PetscQuadratureSetData(sp->functional[f], dim, Nc, 1, qpoints, qweights);CHKERRQ(ierr);
2836f905325SMatthew G. Knepley               for (d = 0; d < dim; ++d) {
2846f905325SMatthew G. Knepley                 qpoints[d] = v0[d];
2856f905325SMatthew G. Knepley                 for (d2 = 0; d2 < dim; ++d2) qpoints[d] += J[d*dim+d2]*((tup[d2]+1)*dx);
2866f905325SMatthew G. Knepley               }
2876f905325SMatthew G. Knepley               qweights[c] = 1.0;
2886f905325SMatthew G. Knepley               ++f;
2896f905325SMatthew G. Knepley             }
2906f905325SMatthew G. Knepley             ierr = PetscDualSpaceTensorPointLexicographic_Internal(dim, orderEff, tup);CHKERRQ(ierr);
29120cf1dd8SToby Isaac           }
29220cf1dd8SToby Isaac         }
2936f905325SMatthew G. Knepley         lag->numDof[dim] = cdim;
2946f905325SMatthew G. Knepley       } else { /* transform functionals from subspaces */
2956f905325SMatthew G. Knepley         PetscInt q;
2966f905325SMatthew G. Knepley 
2976f905325SMatthew G. Knepley         for (q = 0; q < nFunc; q++, f++) {
2986f905325SMatthew G. Knepley           PetscQuadrature fn;
2996f905325SMatthew G. Knepley           PetscInt        fdim, Nc, c, nPoints, i;
3006f905325SMatthew G. Knepley           const PetscReal *points;
3016f905325SMatthew G. Knepley           const PetscReal *weights;
3026f905325SMatthew G. Knepley           PetscReal       *qpoints;
3036f905325SMatthew G. Knepley           PetscReal       *qweights;
3046f905325SMatthew G. Knepley 
3056f905325SMatthew G. Knepley           ierr = PetscDualSpaceGetFunctional(hsp, q, &fn);CHKERRQ(ierr);
3066f905325SMatthew G. Knepley           ierr = PetscQuadratureGetData(fn,&fdim,&Nc,&nPoints,&points,&weights);CHKERRQ(ierr);
3076f905325SMatthew G. Knepley           if (fdim != pointDim) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected height dual space dim %D, got %D",pointDim,fdim);
3086f905325SMatthew G. Knepley           ierr = PetscMalloc1(nPoints * dim, &qpoints);CHKERRQ(ierr);
3096f905325SMatthew G. Knepley           ierr = PetscCalloc1(nPoints * Nc,  &qweights);CHKERRQ(ierr);
3106f905325SMatthew G. Knepley           for (i = 0; i < nPoints; i++) {
3116f905325SMatthew G. Knepley             PetscInt  j, k;
3126f905325SMatthew G. Knepley             PetscReal *qp = &qpoints[i * dim];
3136f905325SMatthew G. Knepley 
3146f905325SMatthew G. Knepley             for (c = 0; c < Nc; ++c) qweights[i*Nc+c] = weights[i*Nc+c];
3156f905325SMatthew G. Knepley             for (j = 0; j < dim; ++j) qp[j] = v0[j];
3166f905325SMatthew G. Knepley             for (j = 0; j < dim; ++j) {
3176f905325SMatthew G. Knepley               for (k = 0; k < pointDim; k++) qp[j] += J[dim * j + k] * (points[pointDim * i + k] - hv0[k]);
3186f905325SMatthew G. Knepley             }
3196f905325SMatthew G. Knepley           }
3206f905325SMatthew G. Knepley           ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &sp->functional[f]);CHKERRQ(ierr);
3216f905325SMatthew G. Knepley           ierr = PetscQuadratureSetOrder(sp->functional[f],0);CHKERRQ(ierr);
3226f905325SMatthew G. Knepley           ierr = PetscQuadratureSetData(sp->functional[f],dim,Nc,nPoints,qpoints,qweights);CHKERRQ(ierr);
3236f905325SMatthew G. Knepley         }
3246f905325SMatthew G. Knepley       }
3256f905325SMatthew G. Knepley       ierr = PetscSectionSetDof(section,p,lag->numDof[pointDim]);CHKERRQ(ierr);
3266f905325SMatthew G. Knepley     }
3276f905325SMatthew G. Knepley     ierr = PetscFree5(tup,v0,hv0,J,invJ);CHKERRQ(ierr);
3286f905325SMatthew G. Knepley     ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
3296f905325SMatthew G. Knepley     { /* reorder to closure order */
3306f905325SMatthew G. Knepley       PetscInt *key, count;
3316f905325SMatthew G. Knepley       PetscQuadrature *reorder = NULL;
3326f905325SMatthew G. Knepley 
3336f905325SMatthew G. Knepley       ierr = PetscCalloc1(f,&key);CHKERRQ(ierr);
3346f905325SMatthew G. Knepley       ierr = PetscMalloc1(f*sp->Nc,&reorder);CHKERRQ(ierr);
3356f905325SMatthew G. Knepley 
3366f905325SMatthew G. Knepley       for (p = pStratStart[depth], count = 0; p < pStratEnd[depth]; p++) {
3376f905325SMatthew G. Knepley         PetscInt *closure = NULL, closureSize, c;
3386f905325SMatthew G. Knepley 
3396f905325SMatthew G. Knepley         ierr = DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
3406f905325SMatthew G. Knepley         for (c = 0; c < closureSize; c++) {
3416f905325SMatthew G. Knepley           PetscInt point = closure[2 * c], dof, off, i;
3426f905325SMatthew G. Knepley 
3436f905325SMatthew G. Knepley           ierr = PetscSectionGetDof(section,point,&dof);CHKERRQ(ierr);
3446f905325SMatthew G. Knepley           ierr = PetscSectionGetOffset(section,point,&off);CHKERRQ(ierr);
3456f905325SMatthew G. Knepley           for (i = 0; i < dof; i++) {
3466f905325SMatthew G. Knepley             PetscInt fi = i + off;
3476f905325SMatthew G. Knepley             if (!key[fi]) {
3486f905325SMatthew G. Knepley               key[fi] = 1;
3496f905325SMatthew G. Knepley               reorder[count++] = sp->functional[fi];
3506f905325SMatthew G. Knepley             }
3516f905325SMatthew G. Knepley           }
3526f905325SMatthew G. Knepley         }
3536f905325SMatthew G. Knepley         ierr = DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
3546f905325SMatthew G. Knepley       }
3556f905325SMatthew G. Knepley       ierr = PetscFree(sp->functional);CHKERRQ(ierr);
3566f905325SMatthew G. Knepley       sp->functional = reorder;
3576f905325SMatthew G. Knepley       ierr = PetscFree(key);CHKERRQ(ierr);
3586f905325SMatthew G. Knepley     }
3596f905325SMatthew G. Knepley     ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3606f905325SMatthew G. Knepley   }
3616f905325SMatthew G. Knepley   if (pStratEnd[depth] == 1 && f != pdimMax) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of dual basis vectors %D not equal to dimension %D", f, pdimMax);
3626f905325SMatthew G. Knepley   if (f > pdimMax) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of dual basis vectors %D is greater than max size %D", f, pdimMax);
3636f905325SMatthew G. Knepley   ierr = PetscFree2(pStratStart, pStratEnd);CHKERRQ(ierr);
36420cf1dd8SToby Isaac   PetscFunctionReturn(0);
36520cf1dd8SToby Isaac }
36620cf1dd8SToby Isaac 
3676f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceGetDimension_Lagrange(PetscDualSpace sp, PetscInt *dim)
3686f905325SMatthew G. Knepley {
3696f905325SMatthew G. Knepley   DM              K;
3706f905325SMatthew G. Knepley   const PetscInt *numDof;
3716f905325SMatthew G. Knepley   PetscInt        spatialDim, Nc, size = 0, d;
3726f905325SMatthew G. Knepley   PetscErrorCode  ierr;
3736f905325SMatthew G. Knepley 
3746f905325SMatthew G. Knepley   PetscFunctionBegin;
3756f905325SMatthew G. Knepley   ierr = PetscDualSpaceGetDM(sp, &K);CHKERRQ(ierr);
3766f905325SMatthew G. Knepley   ierr = PetscDualSpaceGetNumDof(sp, &numDof);CHKERRQ(ierr);
3776f905325SMatthew G. Knepley   ierr = DMGetDimension(K, &spatialDim);CHKERRQ(ierr);
3786f905325SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(K, 0, NULL, &Nc);CHKERRQ(ierr);
3796f905325SMatthew G. Knepley   if (Nc == 1) {ierr = PetscDualSpaceGetDimension_SingleCell_Lagrange(sp, sp->order, dim);CHKERRQ(ierr); PetscFunctionReturn(0);}
3806f905325SMatthew G. Knepley   for (d = 0; d <= spatialDim; ++d) {
3816f905325SMatthew G. Knepley     PetscInt pStart, pEnd;
3826f905325SMatthew G. Knepley 
3836f905325SMatthew G. Knepley     ierr = DMPlexGetDepthStratum(K, d, &pStart, &pEnd);CHKERRQ(ierr);
3846f905325SMatthew G. Knepley     size += (pEnd-pStart)*numDof[d];
3856f905325SMatthew G. Knepley   }
3866f905325SMatthew G. Knepley   *dim = size;
3876f905325SMatthew G. Knepley   PetscFunctionReturn(0);
3886f905325SMatthew G. Knepley }
3896f905325SMatthew G. Knepley 
3906f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceGetNumDof_Lagrange(PetscDualSpace sp, const PetscInt **numDof)
3916f905325SMatthew G. Knepley {
3926f905325SMatthew G. Knepley   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
3936f905325SMatthew G. Knepley 
3946f905325SMatthew G. Knepley   PetscFunctionBegin;
3956f905325SMatthew G. Knepley   *numDof = lag->numDof;
3966f905325SMatthew G. Knepley   PetscFunctionReturn(0);
3976f905325SMatthew G. Knepley }
3986f905325SMatthew G. Knepley 
3996f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceGetHeightSubspace_Lagrange(PetscDualSpace sp, PetscInt height, PetscDualSpace *bdsp)
4006f905325SMatthew G. Knepley {
4016f905325SMatthew G. Knepley   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
4026f905325SMatthew G. Knepley   PetscErrorCode     ierr;
4036f905325SMatthew G. Knepley 
4046f905325SMatthew G. Knepley   PetscFunctionBegin;
4056f905325SMatthew G. Knepley   if (height == 0) {
4066f905325SMatthew G. Knepley     *bdsp = sp;
4076f905325SMatthew G. Knepley   } else {
4086f905325SMatthew G. Knepley     DM       dm;
4096f905325SMatthew G. Knepley     PetscInt dim;
4106f905325SMatthew G. Knepley 
4116f905325SMatthew G. Knepley     ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr);
4126f905325SMatthew G. Knepley     ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
4136f905325SMatthew G. Knepley     if (height > dim || height < 0) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Asked for dual space at height %D for dimension %D reference element\n",height,dim);
4146f905325SMatthew G. Knepley     if (height <= lag->height) {*bdsp = lag->subspaces[height-1];}
4156f905325SMatthew G. Knepley     else                       {*bdsp = NULL;}
4166f905325SMatthew G. Knepley   }
4176f905325SMatthew G. Knepley   PetscFunctionReturn(0);
4186f905325SMatthew G. Knepley }
41920cf1dd8SToby Isaac 
42020cf1dd8SToby Isaac #define BaryIndex(perEdge,a,b,c) (((b)*(2*perEdge+1-(b)))/2)+(c)
42120cf1dd8SToby Isaac 
42220cf1dd8SToby Isaac #define CartIndex(perEdge,a,b) (perEdge*(a)+b)
42320cf1dd8SToby Isaac 
42420cf1dd8SToby Isaac static PetscErrorCode PetscDualSpaceGetSymmetries_Lagrange(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips)
42520cf1dd8SToby Isaac {
42620cf1dd8SToby Isaac 
42720cf1dd8SToby Isaac   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
42820cf1dd8SToby Isaac   PetscInt           dim, order, p, Nc;
42920cf1dd8SToby Isaac   PetscErrorCode     ierr;
43020cf1dd8SToby Isaac 
43120cf1dd8SToby Isaac   PetscFunctionBegin;
43220cf1dd8SToby Isaac   ierr = PetscDualSpaceGetOrder(sp,&order);CHKERRQ(ierr);
43320cf1dd8SToby Isaac   ierr = PetscDualSpaceGetNumComponents(sp,&Nc);CHKERRQ(ierr);
43420cf1dd8SToby Isaac   ierr = DMGetDimension(sp->dm,&dim);CHKERRQ(ierr);
43520cf1dd8SToby Isaac   if (!dim || !lag->continuous || order < 3) PetscFunctionReturn(0);
43620cf1dd8SToby Isaac   if (dim > 3) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Lagrange symmetries not implemented for dim = %D > 3",dim);
43720cf1dd8SToby Isaac   if (!lag->symmetries) { /* store symmetries */
43820cf1dd8SToby Isaac     PetscDualSpace hsp;
43920cf1dd8SToby Isaac     DM             K;
44020cf1dd8SToby Isaac     PetscInt       numPoints = 1, d;
44120cf1dd8SToby Isaac     PetscInt       numFaces;
44220cf1dd8SToby Isaac     PetscInt       ***symmetries;
44320cf1dd8SToby Isaac     const PetscInt ***hsymmetries;
44420cf1dd8SToby Isaac 
44520cf1dd8SToby Isaac     if (lag->simplexCell) {
44620cf1dd8SToby Isaac       numFaces = 1 + dim;
44720cf1dd8SToby Isaac       for (d = 0; d < dim; d++) numPoints = numPoints * 2 + 1;
4486f905325SMatthew G. Knepley     } else {
44920cf1dd8SToby Isaac       numPoints = PetscPowInt(3,dim);
45020cf1dd8SToby Isaac       numFaces  = 2 * dim;
45120cf1dd8SToby Isaac     }
45220cf1dd8SToby Isaac     ierr = PetscCalloc1(numPoints,&symmetries);CHKERRQ(ierr);
45320cf1dd8SToby Isaac     if (0 < dim && dim < 3) { /* compute self symmetries */
45420cf1dd8SToby Isaac       PetscInt **cellSymmetries;
45520cf1dd8SToby Isaac 
45620cf1dd8SToby Isaac       lag->numSelfSym = 2 * numFaces;
45720cf1dd8SToby Isaac       lag->selfSymOff = numFaces;
45820cf1dd8SToby Isaac       ierr = PetscCalloc1(2*numFaces,&cellSymmetries);CHKERRQ(ierr);
45920cf1dd8SToby Isaac       /* we want to be able to index symmetries directly with the orientations, which range from [-numFaces,numFaces) */
46020cf1dd8SToby Isaac       symmetries[0] = &cellSymmetries[numFaces];
46120cf1dd8SToby Isaac       if (dim == 1) {
46220cf1dd8SToby Isaac         PetscInt dofPerEdge = order - 1;
46320cf1dd8SToby Isaac 
46420cf1dd8SToby Isaac         if (dofPerEdge > 1) {
46520cf1dd8SToby Isaac           PetscInt i, j, *reverse;
46620cf1dd8SToby Isaac 
46720cf1dd8SToby Isaac           ierr = PetscMalloc1(dofPerEdge*Nc,&reverse);CHKERRQ(ierr);
46820cf1dd8SToby Isaac           for (i = 0; i < dofPerEdge; i++) {
46920cf1dd8SToby Isaac             for (j = 0; j < Nc; j++) {
47020cf1dd8SToby Isaac               reverse[i*Nc + j] = Nc * (dofPerEdge - 1 - i) + j;
47120cf1dd8SToby Isaac             }
47220cf1dd8SToby Isaac           }
47320cf1dd8SToby Isaac           symmetries[0][-2] = reverse;
47420cf1dd8SToby Isaac 
47520cf1dd8SToby Isaac           /* yes, this is redundant, but it makes it easier to cleanup if I don't have to worry about what not to free */
47620cf1dd8SToby Isaac           ierr = PetscMalloc1(dofPerEdge*Nc,&reverse);CHKERRQ(ierr);
47720cf1dd8SToby Isaac           for (i = 0; i < dofPerEdge; i++) {
47820cf1dd8SToby Isaac             for (j = 0; j < Nc; j++) {
47920cf1dd8SToby Isaac               reverse[i*Nc + j] = Nc * (dofPerEdge - 1 - i) + j;
48020cf1dd8SToby Isaac             }
48120cf1dd8SToby Isaac           }
48220cf1dd8SToby Isaac           symmetries[0][1] = reverse;
48320cf1dd8SToby Isaac         }
48420cf1dd8SToby Isaac       } else {
48520cf1dd8SToby Isaac         PetscInt dofPerEdge = lag->simplexCell ? (order - 2) : (order - 1), s;
48620cf1dd8SToby Isaac         PetscInt dofPerFace;
48720cf1dd8SToby Isaac 
48820cf1dd8SToby Isaac         if (dofPerEdge > 1) {
48920cf1dd8SToby Isaac           for (s = -numFaces; s < numFaces; s++) {
49020cf1dd8SToby Isaac             PetscInt *sym, i, j, k, l;
49120cf1dd8SToby Isaac 
49220cf1dd8SToby Isaac             if (!s) continue;
49320cf1dd8SToby Isaac             if (lag->simplexCell) {
49420cf1dd8SToby Isaac               dofPerFace = (dofPerEdge * (dofPerEdge + 1))/2;
49520cf1dd8SToby Isaac               ierr = PetscMalloc1(Nc*dofPerFace,&sym);CHKERRQ(ierr);
49620cf1dd8SToby Isaac               for (j = 0, l = 0; j < dofPerEdge; j++) {
49720cf1dd8SToby Isaac                 for (k = 0; k < dofPerEdge - j; k++, l++) {
49820cf1dd8SToby Isaac                   i = dofPerEdge - 1 - j - k;
49920cf1dd8SToby Isaac                   switch (s) {
50020cf1dd8SToby Isaac                   case -3:
50120cf1dd8SToby Isaac                     sym[Nc*l] = BaryIndex(dofPerEdge,i,k,j);
50220cf1dd8SToby Isaac                     break;
50320cf1dd8SToby Isaac                   case -2:
50420cf1dd8SToby Isaac                     sym[Nc*l] = BaryIndex(dofPerEdge,j,i,k);
50520cf1dd8SToby Isaac                     break;
50620cf1dd8SToby Isaac                   case -1:
50720cf1dd8SToby Isaac                     sym[Nc*l] = BaryIndex(dofPerEdge,k,j,i);
50820cf1dd8SToby Isaac                     break;
50920cf1dd8SToby Isaac                   case 1:
51020cf1dd8SToby Isaac                     sym[Nc*l] = BaryIndex(dofPerEdge,k,i,j);
51120cf1dd8SToby Isaac                     break;
51220cf1dd8SToby Isaac                   case 2:
51320cf1dd8SToby Isaac                     sym[Nc*l] = BaryIndex(dofPerEdge,j,k,i);
51420cf1dd8SToby Isaac                     break;
51520cf1dd8SToby Isaac                   }
51620cf1dd8SToby Isaac                 }
51720cf1dd8SToby Isaac               }
51820cf1dd8SToby Isaac             } else {
51920cf1dd8SToby Isaac               dofPerFace = dofPerEdge * dofPerEdge;
52020cf1dd8SToby Isaac               ierr = PetscMalloc1(Nc*dofPerFace,&sym);CHKERRQ(ierr);
52120cf1dd8SToby Isaac               for (j = 0, l = 0; j < dofPerEdge; j++) {
52220cf1dd8SToby Isaac                 for (k = 0; k < dofPerEdge; k++, l++) {
52320cf1dd8SToby Isaac                   switch (s) {
52420cf1dd8SToby Isaac                   case -4:
52520cf1dd8SToby Isaac                     sym[Nc*l] = CartIndex(dofPerEdge,k,j);
52620cf1dd8SToby Isaac                     break;
52720cf1dd8SToby Isaac                   case -3:
52820cf1dd8SToby Isaac                     sym[Nc*l] = CartIndex(dofPerEdge,(dofPerEdge - 1 - j),k);
52920cf1dd8SToby Isaac                     break;
53020cf1dd8SToby Isaac                   case -2:
53120cf1dd8SToby Isaac                     sym[Nc*l] = CartIndex(dofPerEdge,(dofPerEdge - 1 - k),(dofPerEdge - 1 - j));
53220cf1dd8SToby Isaac                     break;
53320cf1dd8SToby Isaac                   case -1:
53420cf1dd8SToby Isaac                     sym[Nc*l] = CartIndex(dofPerEdge,j,(dofPerEdge - 1 - k));
53520cf1dd8SToby Isaac                     break;
53620cf1dd8SToby Isaac                   case 1:
53720cf1dd8SToby Isaac                     sym[Nc*l] = CartIndex(dofPerEdge,(dofPerEdge - 1 - k),j);
53820cf1dd8SToby Isaac                     break;
53920cf1dd8SToby Isaac                   case 2:
54020cf1dd8SToby Isaac                     sym[Nc*l] = CartIndex(dofPerEdge,(dofPerEdge - 1 - j),(dofPerEdge - 1 - k));
54120cf1dd8SToby Isaac                     break;
54220cf1dd8SToby Isaac                   case 3:
54320cf1dd8SToby Isaac                     sym[Nc*l] = CartIndex(dofPerEdge,k,(dofPerEdge - 1 - j));
54420cf1dd8SToby Isaac                     break;
54520cf1dd8SToby Isaac                   }
54620cf1dd8SToby Isaac                 }
54720cf1dd8SToby Isaac               }
54820cf1dd8SToby Isaac             }
54920cf1dd8SToby Isaac             for (i = 0; i < dofPerFace; i++) {
55020cf1dd8SToby Isaac               sym[Nc*i] *= Nc;
55120cf1dd8SToby Isaac               for (j = 1; j < Nc; j++) {
55220cf1dd8SToby Isaac                 sym[Nc*i+j] = sym[Nc*i] + j;
55320cf1dd8SToby Isaac               }
55420cf1dd8SToby Isaac             }
55520cf1dd8SToby Isaac             symmetries[0][s] = sym;
55620cf1dd8SToby Isaac           }
55720cf1dd8SToby Isaac         }
55820cf1dd8SToby Isaac       }
55920cf1dd8SToby Isaac     }
56020cf1dd8SToby Isaac     ierr = PetscDualSpaceGetHeightSubspace(sp,1,&hsp);CHKERRQ(ierr);
56120cf1dd8SToby Isaac     ierr = PetscDualSpaceGetSymmetries(hsp,&hsymmetries,NULL);CHKERRQ(ierr);
56220cf1dd8SToby Isaac     if (hsymmetries) {
56320cf1dd8SToby Isaac       PetscBool      *seen;
56420cf1dd8SToby Isaac       const PetscInt *cone;
56520cf1dd8SToby Isaac       PetscInt       KclosureSize, *Kclosure = NULL;
56620cf1dd8SToby Isaac 
56720cf1dd8SToby Isaac       ierr = PetscDualSpaceGetDM(sp,&K);CHKERRQ(ierr);
56820cf1dd8SToby Isaac       ierr = PetscCalloc1(numPoints,&seen);CHKERRQ(ierr);
56920cf1dd8SToby Isaac       ierr = DMPlexGetCone(K,0,&cone);CHKERRQ(ierr);
57020cf1dd8SToby Isaac       ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&KclosureSize,&Kclosure);CHKERRQ(ierr);
57120cf1dd8SToby Isaac       for (p = 0; p < numFaces; p++) {
57220cf1dd8SToby Isaac         PetscInt closureSize, *closure = NULL, q;
57320cf1dd8SToby Isaac 
57420cf1dd8SToby Isaac         ierr = DMPlexGetTransitiveClosure(K,cone[p],PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
57520cf1dd8SToby Isaac         for (q = 0; q < closureSize; q++) {
57620cf1dd8SToby Isaac           PetscInt point = closure[2*q], r;
57720cf1dd8SToby Isaac 
57820cf1dd8SToby Isaac           if(!seen[point]) {
57920cf1dd8SToby Isaac             for (r = 0; r < KclosureSize; r++) {
58020cf1dd8SToby Isaac               if (Kclosure[2 * r] == point) break;
58120cf1dd8SToby Isaac             }
58220cf1dd8SToby Isaac             seen[point] = PETSC_TRUE;
58320cf1dd8SToby Isaac             symmetries[r] = (PetscInt **) hsymmetries[q];
58420cf1dd8SToby Isaac           }
58520cf1dd8SToby Isaac         }
58620cf1dd8SToby Isaac         ierr = DMPlexRestoreTransitiveClosure(K,cone[p],PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
58720cf1dd8SToby Isaac       }
58820cf1dd8SToby Isaac       ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&KclosureSize,&Kclosure);CHKERRQ(ierr);
58920cf1dd8SToby Isaac       ierr = PetscFree(seen);CHKERRQ(ierr);
59020cf1dd8SToby Isaac     }
59120cf1dd8SToby Isaac     lag->symmetries = symmetries;
59220cf1dd8SToby Isaac   }
59320cf1dd8SToby Isaac   if (perms) *perms = (const PetscInt ***) lag->symmetries;
59420cf1dd8SToby Isaac   PetscFunctionReturn(0);
59520cf1dd8SToby Isaac }
59620cf1dd8SToby Isaac 
59720cf1dd8SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeGetContinuity_Lagrange(PetscDualSpace sp, PetscBool *continuous)
59820cf1dd8SToby Isaac {
59920cf1dd8SToby Isaac   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
60020cf1dd8SToby Isaac 
60120cf1dd8SToby Isaac   PetscFunctionBegin;
60220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
60320cf1dd8SToby Isaac   PetscValidPointer(continuous, 2);
60420cf1dd8SToby Isaac   *continuous = lag->continuous;
60520cf1dd8SToby Isaac   PetscFunctionReturn(0);
60620cf1dd8SToby Isaac }
60720cf1dd8SToby Isaac 
60820cf1dd8SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeSetContinuity_Lagrange(PetscDualSpace sp, PetscBool continuous)
60920cf1dd8SToby Isaac {
61020cf1dd8SToby Isaac   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
61120cf1dd8SToby Isaac 
61220cf1dd8SToby Isaac   PetscFunctionBegin;
61320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
61420cf1dd8SToby Isaac   lag->continuous = continuous;
61520cf1dd8SToby Isaac   PetscFunctionReturn(0);
61620cf1dd8SToby Isaac }
61720cf1dd8SToby Isaac 
61820cf1dd8SToby Isaac /*@
61920cf1dd8SToby Isaac   PetscDualSpaceLagrangeGetContinuity - Retrieves the flag for element continuity
62020cf1dd8SToby Isaac 
62120cf1dd8SToby Isaac   Not Collective
62220cf1dd8SToby Isaac 
62320cf1dd8SToby Isaac   Input Parameter:
62420cf1dd8SToby Isaac . sp         - the PetscDualSpace
62520cf1dd8SToby Isaac 
62620cf1dd8SToby Isaac   Output Parameter:
62720cf1dd8SToby Isaac . continuous - flag for element continuity
62820cf1dd8SToby Isaac 
62920cf1dd8SToby Isaac   Level: intermediate
63020cf1dd8SToby Isaac 
63120cf1dd8SToby Isaac .seealso: PetscDualSpaceLagrangeSetContinuity()
63220cf1dd8SToby Isaac @*/
63320cf1dd8SToby Isaac PetscErrorCode PetscDualSpaceLagrangeGetContinuity(PetscDualSpace sp, PetscBool *continuous)
63420cf1dd8SToby Isaac {
63520cf1dd8SToby Isaac   PetscErrorCode ierr;
63620cf1dd8SToby Isaac 
63720cf1dd8SToby Isaac   PetscFunctionBegin;
63820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
63920cf1dd8SToby Isaac   PetscValidPointer(continuous, 2);
64020cf1dd8SToby Isaac   ierr = PetscTryMethod(sp, "PetscDualSpaceLagrangeGetContinuity_C", (PetscDualSpace,PetscBool*),(sp,continuous));CHKERRQ(ierr);
64120cf1dd8SToby Isaac   PetscFunctionReturn(0);
64220cf1dd8SToby Isaac }
64320cf1dd8SToby Isaac 
64420cf1dd8SToby Isaac /*@
64520cf1dd8SToby Isaac   PetscDualSpaceLagrangeSetContinuity - Indicate whether the element is continuous
64620cf1dd8SToby Isaac 
647*d083f849SBarry Smith   Logically Collective on sp
64820cf1dd8SToby Isaac 
64920cf1dd8SToby Isaac   Input Parameters:
65020cf1dd8SToby Isaac + sp         - the PetscDualSpace
65120cf1dd8SToby Isaac - continuous - flag for element continuity
65220cf1dd8SToby Isaac 
65320cf1dd8SToby Isaac   Options Database:
65420cf1dd8SToby Isaac . -petscdualspace_lagrange_continuity <bool>
65520cf1dd8SToby Isaac 
65620cf1dd8SToby Isaac   Level: intermediate
65720cf1dd8SToby Isaac 
65820cf1dd8SToby Isaac .seealso: PetscDualSpaceLagrangeGetContinuity()
65920cf1dd8SToby Isaac @*/
66020cf1dd8SToby Isaac PetscErrorCode PetscDualSpaceLagrangeSetContinuity(PetscDualSpace sp, PetscBool continuous)
66120cf1dd8SToby Isaac {
66220cf1dd8SToby Isaac   PetscErrorCode ierr;
66320cf1dd8SToby Isaac 
66420cf1dd8SToby Isaac   PetscFunctionBegin;
66520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
66620cf1dd8SToby Isaac   PetscValidLogicalCollectiveBool(sp, continuous, 2);
66720cf1dd8SToby Isaac   ierr = PetscTryMethod(sp, "PetscDualSpaceLagrangeSetContinuity_C", (PetscDualSpace,PetscBool),(sp,continuous));CHKERRQ(ierr);
66820cf1dd8SToby Isaac   PetscFunctionReturn(0);
66920cf1dd8SToby Isaac }
67020cf1dd8SToby Isaac 
6716f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeGetTensor_Lagrange(PetscDualSpace sp, PetscBool *tensor)
67220cf1dd8SToby Isaac {
67320cf1dd8SToby Isaac   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data;
6746f905325SMatthew G. Knepley 
6756f905325SMatthew G. Knepley   PetscFunctionBegin;
6766f905325SMatthew G. Knepley   *tensor = lag->tensorSpace;
6776f905325SMatthew G. Knepley   PetscFunctionReturn(0);
6786f905325SMatthew G. Knepley }
6796f905325SMatthew G. Knepley 
6806f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeSetTensor_Lagrange(PetscDualSpace sp, PetscBool tensor)
6816f905325SMatthew G. Knepley {
6826f905325SMatthew G. Knepley   PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data;
6836f905325SMatthew G. Knepley 
6846f905325SMatthew G. Knepley   PetscFunctionBegin;
6856f905325SMatthew G. Knepley   lag->tensorSpace = tensor;
6866f905325SMatthew G. Knepley   PetscFunctionReturn(0);
6876f905325SMatthew G. Knepley }
6886f905325SMatthew G. Knepley 
6896f905325SMatthew G. Knepley /*@
6906f905325SMatthew G. Knepley   PetscDualSpaceLagrangeGetTensor - Get the tensor nature of the dual space
6916f905325SMatthew G. Knepley 
6926f905325SMatthew G. Knepley   Not collective
6936f905325SMatthew G. Knepley 
6946f905325SMatthew G. Knepley   Input Parameter:
6956f905325SMatthew G. Knepley . sp - The PetscDualSpace
6966f905325SMatthew G. Knepley 
6976f905325SMatthew G. Knepley   Output Parameter:
6986f905325SMatthew G. Knepley . tensor - Whether the dual space has tensor layout (vs. simplicial)
6996f905325SMatthew G. Knepley 
7006f905325SMatthew G. Knepley   Level: intermediate
7016f905325SMatthew G. Knepley 
7026f905325SMatthew G. Knepley .seealso: PetscDualSpaceLagrangeSetTensor(), PetscDualSpaceCreate()
7036f905325SMatthew G. Knepley @*/
7046f905325SMatthew G. Knepley PetscErrorCode PetscDualSpaceLagrangeGetTensor(PetscDualSpace sp, PetscBool *tensor)
7056f905325SMatthew G. Knepley {
70620cf1dd8SToby Isaac   PetscErrorCode ierr;
70720cf1dd8SToby Isaac 
70820cf1dd8SToby Isaac   PetscFunctionBegin;
70920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
7106f905325SMatthew G. Knepley   PetscValidPointer(tensor, 2);
7116f905325SMatthew G. Knepley   ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeGetTensor_C",(PetscDualSpace,PetscBool *),(sp,tensor));CHKERRQ(ierr);
71220cf1dd8SToby Isaac   PetscFunctionReturn(0);
71320cf1dd8SToby Isaac }
71420cf1dd8SToby Isaac 
7156f905325SMatthew G. Knepley /*@
7166f905325SMatthew G. Knepley   PetscDualSpaceLagrangeSetTensor - Set the tensor nature of the dual space
7176f905325SMatthew G. Knepley 
7186f905325SMatthew G. Knepley   Not collective
7196f905325SMatthew G. Knepley 
7206f905325SMatthew G. Knepley   Input Parameters:
7216f905325SMatthew G. Knepley + sp - The PetscDualSpace
7226f905325SMatthew G. Knepley - tensor - Whether the dual space has tensor layout (vs. simplicial)
7236f905325SMatthew G. Knepley 
7246f905325SMatthew G. Knepley   Level: intermediate
7256f905325SMatthew G. Knepley 
7266f905325SMatthew G. Knepley .seealso: PetscDualSpaceLagrangeGetTensor(), PetscDualSpaceCreate()
7276f905325SMatthew G. Knepley @*/
7286f905325SMatthew G. Knepley PetscErrorCode PetscDualSpaceLagrangeSetTensor(PetscDualSpace sp, PetscBool tensor)
7296f905325SMatthew G. Knepley {
7306f905325SMatthew G. Knepley   PetscErrorCode ierr;
7316f905325SMatthew G. Knepley 
7326f905325SMatthew G. Knepley   PetscFunctionBegin;
7336f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
7346f905325SMatthew G. Knepley   ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeSetTensor_C",(PetscDualSpace,PetscBool),(sp,tensor));CHKERRQ(ierr);
7356f905325SMatthew G. Knepley   PetscFunctionReturn(0);
7366f905325SMatthew G. Knepley }
7376f905325SMatthew G. Knepley 
7386f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceInitialize_Lagrange(PetscDualSpace sp)
73920cf1dd8SToby Isaac {
74020cf1dd8SToby Isaac   PetscFunctionBegin;
74120cf1dd8SToby Isaac   sp->ops->destroy           = PetscDualSpaceDestroy_Lagrange;
7426f905325SMatthew G. Knepley   sp->ops->view              = PetscDualSpaceView_Lagrange;
7436f905325SMatthew G. Knepley   sp->ops->setfromoptions    = PetscDualSpaceSetFromOptions_Lagrange;
74420cf1dd8SToby Isaac   sp->ops->duplicate         = PetscDualSpaceDuplicate_Lagrange;
7456f905325SMatthew G. Knepley   sp->ops->setup             = PetscDualSpaceSetUp_Lagrange;
74620cf1dd8SToby Isaac   sp->ops->getdimension      = PetscDualSpaceGetDimension_Lagrange;
74720cf1dd8SToby Isaac   sp->ops->getnumdof         = PetscDualSpaceGetNumDof_Lagrange;
74820cf1dd8SToby Isaac   sp->ops->getheightsubspace = PetscDualSpaceGetHeightSubspace_Lagrange;
74920cf1dd8SToby Isaac   sp->ops->getsymmetries     = PetscDualSpaceGetSymmetries_Lagrange;
75020cf1dd8SToby Isaac   sp->ops->apply             = PetscDualSpaceApplyDefault;
75120cf1dd8SToby Isaac   sp->ops->applyall          = PetscDualSpaceApplyAllDefault;
75220cf1dd8SToby Isaac   sp->ops->createallpoints   = PetscDualSpaceCreateAllPointsDefault;
75320cf1dd8SToby Isaac   PetscFunctionReturn(0);
75420cf1dd8SToby Isaac }
75520cf1dd8SToby Isaac 
75620cf1dd8SToby Isaac /*MC
75720cf1dd8SToby Isaac   PETSCDUALSPACELAGRANGE = "lagrange" - A PetscDualSpace object that encapsulates a dual space of pointwise evaluation functionals
75820cf1dd8SToby Isaac 
75920cf1dd8SToby Isaac   Level: intermediate
76020cf1dd8SToby Isaac 
76120cf1dd8SToby Isaac .seealso: PetscDualSpaceType, PetscDualSpaceCreate(), PetscDualSpaceSetType()
76220cf1dd8SToby Isaac M*/
76320cf1dd8SToby Isaac 
76420cf1dd8SToby Isaac PETSC_EXTERN PetscErrorCode PetscDualSpaceCreate_Lagrange(PetscDualSpace sp)
76520cf1dd8SToby Isaac {
76620cf1dd8SToby Isaac   PetscDualSpace_Lag *lag;
76720cf1dd8SToby Isaac   PetscErrorCode      ierr;
76820cf1dd8SToby Isaac 
76920cf1dd8SToby Isaac   PetscFunctionBegin;
77020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
77120cf1dd8SToby Isaac   ierr     = PetscNewLog(sp,&lag);CHKERRQ(ierr);
77220cf1dd8SToby Isaac   sp->data = lag;
77320cf1dd8SToby Isaac 
77420cf1dd8SToby Isaac   lag->numDof      = NULL;
77520cf1dd8SToby Isaac   lag->simplexCell = PETSC_TRUE;
77620cf1dd8SToby Isaac   lag->tensorSpace = PETSC_FALSE;
77720cf1dd8SToby Isaac   lag->continuous  = PETSC_TRUE;
77820cf1dd8SToby Isaac 
77920cf1dd8SToby Isaac   ierr = PetscDualSpaceInitialize_Lagrange(sp);CHKERRQ(ierr);
78020cf1dd8SToby Isaac   ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetContinuity_C", PetscDualSpaceLagrangeGetContinuity_Lagrange);CHKERRQ(ierr);
78120cf1dd8SToby Isaac   ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetContinuity_C", PetscDualSpaceLagrangeSetContinuity_Lagrange);CHKERRQ(ierr);
78220cf1dd8SToby Isaac   ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetTensor_C", PetscDualSpaceLagrangeGetTensor_Lagrange);CHKERRQ(ierr);
78320cf1dd8SToby Isaac   ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetTensor_C", PetscDualSpaceLagrangeSetTensor_Lagrange);CHKERRQ(ierr);
78420cf1dd8SToby Isaac   PetscFunctionReturn(0);
78520cf1dd8SToby Isaac }
78620cf1dd8SToby Isaac 
787