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,§ion);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(§ion);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