xref: /petsc/src/dm/dt/dualspace/impls/lagrange/tests/ex1.c (revision 3ba1676111f5c958fe6c2729b46ca4d523958bb3)
18a820b8eSToby Isaac 
28a820b8eSToby Isaac #include <petscfe.h>
38a820b8eSToby Isaac #include <petscdmplex.h>
48a820b8eSToby Isaac #include <petsc/private/hashmap.h>
58a820b8eSToby Isaac #include <petsc/private/dmpleximpl.h>
68a820b8eSToby Isaac #include <petsc/private/petscfeimpl.h>
78a820b8eSToby Isaac 
88a820b8eSToby Isaac const char help[] = "Test PETSCDUALSPACELAGRANGE\n";
98a820b8eSToby Isaac 
109371c9d4SSatish Balay typedef struct _PetscHashLagKey {
118a820b8eSToby Isaac   PetscInt  dim;
128a820b8eSToby Isaac   PetscInt  order;
138a820b8eSToby Isaac   PetscInt  formDegree;
148a820b8eSToby Isaac   PetscBool trimmed;
156ff15688SToby Isaac   PetscInt  tensor;
168a820b8eSToby Isaac   PetscBool continuous;
178a820b8eSToby Isaac } PetscHashLagKey;
188a820b8eSToby Isaac 
198a820b8eSToby Isaac #define PetscHashLagKeyHash(key) \
209371c9d4SSatish Balay   PetscHashCombine(PetscHashCombine(PetscHashCombine(PetscHashInt((key).dim), PetscHashInt((key).order)), PetscHashInt((key).formDegree)), PetscHashCombine(PetscHashCombine(PetscHashInt((key).trimmed), PetscHashInt((key).tensor)), PetscHashInt((key).continuous)))
218a820b8eSToby Isaac 
228a820b8eSToby Isaac #define PetscHashLagKeyEqual(k1, k2) \
239371c9d4SSatish Balay   (((k1).dim == (k2).dim) ? ((k1).order == (k2).order) ? ((k1).formDegree == (k2).formDegree) ? ((k1).trimmed == (k2).trimmed) ? ((k1).tensor == (k2).tensor) ? ((k1).continuous == (k2).continuous) : 0 : 0 : 0 : 0 : 0)
248a820b8eSToby Isaac 
258a820b8eSToby Isaac PETSC_HASH_MAP(HashLag, PetscHashLagKey, PetscInt, PetscHashLagKeyHash, PetscHashLagKeyEqual, 0)
268a820b8eSToby Isaac 
278a820b8eSToby Isaac static PetscErrorCode ExpectedNumDofs_Total(PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscInt nCopies, PetscInt *nDofs);
288a820b8eSToby Isaac static PetscErrorCode ExpectedNumDofs_Interior(PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscInt nCopies, PetscInt *nDofs);
298a820b8eSToby Isaac 
30d71ae5a4SJacob Faibussowitsch static PetscErrorCode ExpectedNumDofs_Total(PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscInt nCopies, PetscInt *nDofs)
31d71ae5a4SJacob Faibussowitsch {
328a820b8eSToby Isaac   PetscFunctionBegin;
338a820b8eSToby Isaac   formDegree = PetscAbsInt(formDegree);
348a820b8eSToby Isaac   /* see femtable.org for the source of most of these values */
358a820b8eSToby Isaac   *nDofs = -1;
368a820b8eSToby Isaac   if (tensor == 0) { /* simplex spaces */
378a820b8eSToby Isaac     if (trimmed) {
388a820b8eSToby Isaac       PetscInt rnchooserk;
398a820b8eSToby Isaac       PetscInt rkm1choosek;
408a820b8eSToby Isaac 
419566063dSJacob Faibussowitsch       PetscCall(PetscDTBinomialInt(order + dim, order + formDegree, &rnchooserk));
429566063dSJacob Faibussowitsch       PetscCall(PetscDTBinomialInt(order + formDegree - 1, formDegree, &rkm1choosek));
438a820b8eSToby Isaac       *nDofs = rnchooserk * rkm1choosek * nCopies;
448a820b8eSToby Isaac     } else {
458a820b8eSToby Isaac       PetscInt rnchooserk;
468a820b8eSToby Isaac       PetscInt rkchoosek;
478a820b8eSToby Isaac 
489566063dSJacob Faibussowitsch       PetscCall(PetscDTBinomialInt(order + dim, order + formDegree, &rnchooserk));
499566063dSJacob Faibussowitsch       PetscCall(PetscDTBinomialInt(order + formDegree, formDegree, &rkchoosek));
508a820b8eSToby Isaac       *nDofs = rnchooserk * rkchoosek * nCopies;
518a820b8eSToby Isaac     }
528a820b8eSToby Isaac   } else if (tensor == 1) { /* hypercubes */
538a820b8eSToby Isaac     if (trimmed) {
548a820b8eSToby Isaac       PetscInt nchoosek;
558a820b8eSToby Isaac       PetscInt rpowk, rp1pownmk;
568a820b8eSToby Isaac 
579566063dSJacob Faibussowitsch       PetscCall(PetscDTBinomialInt(dim, formDegree, &nchoosek));
582f613bf5SBarry Smith       rpowk     = PetscPowInt(order, formDegree);
592f613bf5SBarry Smith       rp1pownmk = PetscPowInt(order + 1, dim - formDegree);
608a820b8eSToby Isaac       *nDofs    = nchoosek * rpowk * rp1pownmk * nCopies;
618a820b8eSToby Isaac     } else {
628a820b8eSToby Isaac       PetscInt nchoosek;
638a820b8eSToby Isaac       PetscInt rp1pown;
648a820b8eSToby Isaac 
659566063dSJacob Faibussowitsch       PetscCall(PetscDTBinomialInt(dim, formDegree, &nchoosek));
662f613bf5SBarry Smith       rp1pown = PetscPowInt(order + 1, dim);
678a820b8eSToby Isaac       *nDofs  = nchoosek * rp1pown * nCopies;
688a820b8eSToby Isaac     }
698a820b8eSToby Isaac   } else { /* prism */
708a820b8eSToby Isaac     PetscInt tracek   = 0;
718a820b8eSToby Isaac     PetscInt tracekm1 = 0;
728a820b8eSToby Isaac     PetscInt fiber0   = 0;
738a820b8eSToby Isaac     PetscInt fiber1   = 0;
748a820b8eSToby Isaac 
758a820b8eSToby Isaac     if (formDegree < dim) {
769566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Total(dim - 1, order, formDegree, trimmed, 0, 1, &tracek));
779566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Total(1, order, 0, trimmed, 0, 1, &fiber0));
788a820b8eSToby Isaac     }
798a820b8eSToby Isaac     if (formDegree > 0) {
809566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Total(dim - 1, order, formDegree - 1, trimmed, 0, 1, &tracekm1));
819566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Total(1, order, 1, trimmed, 0, 1, &fiber1));
828a820b8eSToby Isaac     }
838a820b8eSToby Isaac     *nDofs = (tracek * fiber0 + tracekm1 * fiber1) * nCopies;
848a820b8eSToby Isaac   }
85*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
868a820b8eSToby Isaac }
878a820b8eSToby Isaac 
88d71ae5a4SJacob Faibussowitsch static PetscErrorCode ExpectedNumDofs_Interior(PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscInt nCopies, PetscInt *nDofs)
89d71ae5a4SJacob Faibussowitsch {
908a820b8eSToby Isaac   PetscFunctionBegin;
918a820b8eSToby Isaac   formDegree = PetscAbsInt(formDegree);
928a820b8eSToby Isaac   /* see femtable.org for the source of most of these values */
938a820b8eSToby Isaac   *nDofs = -1;
948a820b8eSToby Isaac   if (tensor == 0) { /* simplex spaces */
958a820b8eSToby Isaac     if (trimmed) {
968a820b8eSToby Isaac       if (order + formDegree > dim) {
978a820b8eSToby Isaac         PetscInt eorder      = order + formDegree - dim - 1;
988a820b8eSToby Isaac         PetscInt eformDegree = dim - formDegree;
998a820b8eSToby Isaac         PetscInt rnchooserk;
1008a820b8eSToby Isaac         PetscInt rkchoosek;
1018a820b8eSToby Isaac 
1029566063dSJacob Faibussowitsch         PetscCall(PetscDTBinomialInt(eorder + dim, eorder + eformDegree, &rnchooserk));
1039566063dSJacob Faibussowitsch         PetscCall(PetscDTBinomialInt(eorder + eformDegree, eformDegree, &rkchoosek));
1048a820b8eSToby Isaac         *nDofs = rnchooserk * rkchoosek * nCopies;
1058a820b8eSToby Isaac       } else {
1068a820b8eSToby Isaac         *nDofs = 0;
1078a820b8eSToby Isaac       }
1088a820b8eSToby Isaac 
1098a820b8eSToby Isaac     } else {
1108a820b8eSToby Isaac       if (order + formDegree > dim) {
1118a820b8eSToby Isaac         PetscInt eorder      = order + formDegree - dim;
1128a820b8eSToby Isaac         PetscInt eformDegree = dim - formDegree;
1138a820b8eSToby Isaac         PetscInt rnchooserk;
1148a820b8eSToby Isaac         PetscInt rkm1choosek;
1158a820b8eSToby Isaac 
1169566063dSJacob Faibussowitsch         PetscCall(PetscDTBinomialInt(eorder + dim, eorder + eformDegree, &rnchooserk));
1179566063dSJacob Faibussowitsch         PetscCall(PetscDTBinomialInt(eorder + eformDegree - 1, eformDegree, &rkm1choosek));
1188a820b8eSToby Isaac         *nDofs = rnchooserk * rkm1choosek * nCopies;
1198a820b8eSToby Isaac       } else {
1208a820b8eSToby Isaac         *nDofs = 0;
1218a820b8eSToby Isaac       }
1228a820b8eSToby Isaac     }
1238a820b8eSToby Isaac   } else if (tensor == 1) { /* hypercubes */
1248a820b8eSToby Isaac     if (dim < 2) {
1259566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Interior(dim, order, formDegree, trimmed, 0, nCopies, nDofs));
1268a820b8eSToby Isaac     } else {
1278a820b8eSToby Isaac       PetscInt tracek   = 0;
1288a820b8eSToby Isaac       PetscInt tracekm1 = 0;
1298a820b8eSToby Isaac       PetscInt fiber0   = 0;
1308a820b8eSToby Isaac       PetscInt fiber1   = 0;
1318a820b8eSToby Isaac 
1328a820b8eSToby Isaac       if (formDegree < dim) {
1339566063dSJacob Faibussowitsch         PetscCall(ExpectedNumDofs_Interior(dim - 1, order, formDegree, trimmed, dim > 2 ? 1 : 0, 1, &tracek));
1349566063dSJacob Faibussowitsch         PetscCall(ExpectedNumDofs_Interior(1, order, 0, trimmed, 0, 1, &fiber0));
1358a820b8eSToby Isaac       }
1368a820b8eSToby Isaac       if (formDegree > 0) {
1379566063dSJacob Faibussowitsch         PetscCall(ExpectedNumDofs_Interior(dim - 1, order, formDegree - 1, trimmed, dim > 2 ? 1 : 0, 1, &tracekm1));
1389566063dSJacob Faibussowitsch         PetscCall(ExpectedNumDofs_Interior(1, order, 1, trimmed, 0, 1, &fiber1));
1398a820b8eSToby Isaac       }
1408a820b8eSToby Isaac       *nDofs = (tracek * fiber0 + tracekm1 * fiber1) * nCopies;
1418a820b8eSToby Isaac     }
1428a820b8eSToby Isaac   } else { /* prism */
1438a820b8eSToby Isaac     PetscInt tracek   = 0;
1448a820b8eSToby Isaac     PetscInt tracekm1 = 0;
1458a820b8eSToby Isaac     PetscInt fiber0   = 0;
1468a820b8eSToby Isaac     PetscInt fiber1   = 0;
1478a820b8eSToby Isaac 
1488a820b8eSToby Isaac     if (formDegree < dim) {
1499566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Interior(dim - 1, order, formDegree, trimmed, 0, 1, &tracek));
1509566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Interior(1, order, 0, trimmed, 0, 1, &fiber0));
1518a820b8eSToby Isaac     }
1528a820b8eSToby Isaac     if (formDegree > 0) {
1539566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Interior(dim - 1, order, formDegree - 1, trimmed, 0, 1, &tracekm1));
1549566063dSJacob Faibussowitsch       PetscCall(ExpectedNumDofs_Interior(1, order, 1, trimmed, 0, 1, &fiber1));
1558a820b8eSToby Isaac     }
1568a820b8eSToby Isaac     *nDofs = (tracek * fiber0 + tracekm1 * fiber1) * nCopies;
1578a820b8eSToby Isaac   }
158*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1598a820b8eSToby Isaac }
1608a820b8eSToby Isaac 
161d71ae5a4SJacob Faibussowitsch PetscErrorCode testLagrange(PetscHashLag lagTable, DM K, PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscBool continuous, PetscInt nCopies)
162d71ae5a4SJacob Faibussowitsch {
1638a820b8eSToby Isaac   PetscDualSpace  sp;
1648a820b8eSToby Isaac   MPI_Comm        comm = PETSC_COMM_SELF;
1658a820b8eSToby Isaac   PetscInt        Nk;
1668a820b8eSToby Isaac   PetscHashLagKey key;
1678a820b8eSToby Isaac   PetscHashIter   iter;
1688a820b8eSToby Isaac   PetscBool       missing;
1698a820b8eSToby Isaac   PetscInt        spdim, spintdim, exspdim, exspintdim;
1708a820b8eSToby Isaac 
1718a820b8eSToby Isaac   PetscFunctionBegin;
1729566063dSJacob Faibussowitsch   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &Nk));
1739566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(comm, &sp));
1749566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(sp, PETSCDUALSPACELAGRANGE));
1759566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(sp, K));
1769566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetOrder(sp, order));
1779566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetFormDegree(sp, formDegree));
1789566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetNumComponents(sp, nCopies * Nk));
1799566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetContinuity(sp, continuous));
1809566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetTensor(sp, (PetscBool)tensor));
1819566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetTrimmed(sp, trimmed));
18263a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "Input: dim %" PetscInt_FMT ", order %" PetscInt_FMT ", trimmed %" PetscInt_FMT ", tensor %" PetscInt_FMT ", continuous %" PetscInt_FMT ", formDegree %" PetscInt_FMT ", nCopies %" PetscInt_FMT "\n", dim, order, (PetscInt)trimmed, tensor, (PetscInt)continuous, formDegree, nCopies));
1839566063dSJacob Faibussowitsch   PetscCall(ExpectedNumDofs_Total(dim, order, formDegree, trimmed, tensor, nCopies, &exspdim));
1848a820b8eSToby Isaac   if (continuous && dim > 0 && order > 0) {
1859566063dSJacob Faibussowitsch     PetscCall(ExpectedNumDofs_Interior(dim, order, formDegree, trimmed, tensor, nCopies, &exspintdim));
1868a820b8eSToby Isaac   } else {
1878a820b8eSToby Isaac     exspintdim = exspdim;
1888a820b8eSToby Isaac   }
1899566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetUp(sp));
1909566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
1919566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorDimension(sp, &spintdim));
19263a3b9bcSJacob Faibussowitsch   PetscCheck(spdim == exspdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected dual space dimension %" PetscInt_FMT ", got %" PetscInt_FMT, exspdim, spdim);
19363a3b9bcSJacob Faibussowitsch   PetscCheck(spintdim == exspintdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected dual space interior dimension %" PetscInt_FMT ", got %" PetscInt_FMT, exspintdim, spintdim);
1948a820b8eSToby Isaac   key.dim        = dim;
1958a820b8eSToby Isaac   key.formDegree = formDegree;
1969566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetOrder(sp, &key.order));
1979566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeGetContinuity(sp, &key.continuous));
1988a820b8eSToby Isaac   if (tensor == 2) {
1998a820b8eSToby Isaac     key.tensor = 2;
2008a820b8eSToby Isaac   } else {
2016ff15688SToby Isaac     PetscBool bTensor;
2026ff15688SToby Isaac 
2039566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceLagrangeGetTensor(sp, &bTensor));
2046ff15688SToby Isaac     key.tensor = bTensor;
2058a820b8eSToby Isaac   }
2069566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeGetTrimmed(sp, &key.trimmed));
20763a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "After setup:  order %" PetscInt_FMT ", trimmed %" PetscInt_FMT ", tensor %" PetscInt_FMT ", continuous %" PetscInt_FMT "\n", key.order, (PetscInt)key.trimmed, key.tensor, (PetscInt)key.continuous));
2089566063dSJacob Faibussowitsch   PetscCall(PetscHashLagPut(lagTable, key, &iter, &missing));
2098a820b8eSToby Isaac   if (missing) {
2108a820b8eSToby Isaac     DMPolytopeType type;
2118a820b8eSToby Isaac 
2129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellType(K, 0, &type));
21363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "New space: %s, order %" PetscInt_FMT ", trimmed %" PetscInt_FMT ", tensor %" PetscInt_FMT ", continuous %" PetscInt_FMT ", form degree %" PetscInt_FMT "\n", DMPolytopeTypes[type], order, (PetscInt)trimmed, tensor, (PetscInt)continuous, formDegree));
2149566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_SELF));
2158a820b8eSToby Isaac     {
2168a820b8eSToby Isaac       PetscQuadrature  intNodes, allNodes;
2178a820b8eSToby Isaac       Mat              intMat, allMat;
2188a820b8eSToby Isaac       MatInfo          info;
2198a820b8eSToby Isaac       PetscInt         i, j, nodeIdxDim, nodeVecDim, nNodes;
2208a820b8eSToby Isaac       const PetscInt  *nodeIdx;
2218a820b8eSToby Isaac       const PetscReal *nodeVec;
2228a820b8eSToby Isaac 
2238a820b8eSToby Isaac       PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data;
2248a820b8eSToby Isaac 
2259566063dSJacob Faibussowitsch       PetscCall(PetscLagNodeIndicesGetData_Internal(lag->allNodeIndices, &nodeIdxDim, &nodeVecDim, &nNodes, &nodeIdx, &nodeVec));
22608401ef6SPierre Jolivet       PetscCheck(nodeVecDim == Nk, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect nodeVecDim");
22708401ef6SPierre Jolivet       PetscCheck(nNodes == spdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect nNodes");
2288a820b8eSToby Isaac 
2299566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetAllData(sp, &allNodes, &allMat));
2308a820b8eSToby Isaac 
2319566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "All nodes:\n"));
2329566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_SELF));
2339566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureView(allNodes, PETSC_VIEWER_STDOUT_SELF));
2349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_SELF));
2359566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "All node indices:\n"));
2368a820b8eSToby Isaac       for (i = 0; i < spdim; i++) {
2379566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "("));
23848a46eb9SPierre Jolivet         for (j = 0; j < nodeIdxDim; j++) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT ",", nodeIdx[i * nodeIdxDim + j]));
2399566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "): ["));
24048a46eb9SPierre Jolivet         for (j = 0; j < nodeVecDim; j++) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g,", (double)nodeVec[i * nodeVecDim + j]));
2419566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
2428a820b8eSToby Isaac       }
2438a820b8eSToby Isaac 
2449566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(allMat, MAT_LOCAL, &info));
24563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "All matrix: %" PetscInt_FMT " nonzeros\n", (PetscInt)info.nz_used));
2468a820b8eSToby Isaac 
2479566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetInteriorData(sp, &intNodes, &intMat));
2488a820b8eSToby Isaac       if (intMat && intMat != allMat) {
2498a820b8eSToby Isaac         PetscInt         intNodeIdxDim, intNodeVecDim, intNnodes;
2508a820b8eSToby Isaac         const PetscInt  *intNodeIdx;
2518a820b8eSToby Isaac         const PetscReal *intNodeVec;
2528a820b8eSToby Isaac         PetscBool        same;
2538a820b8eSToby Isaac 
2549566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "Interior nodes:\n"));
2559566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_SELF));
2569566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureView(intNodes, PETSC_VIEWER_STDOUT_SELF));
2579566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_SELF));
2588a820b8eSToby Isaac 
2599566063dSJacob Faibussowitsch         PetscCall(MatGetInfo(intMat, MAT_LOCAL, &info));
26063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "Interior matrix: %" PetscInt_FMT " nonzeros\n", (PetscInt)info.nz_used));
2619566063dSJacob Faibussowitsch         PetscCall(PetscLagNodeIndicesGetData_Internal(lag->intNodeIndices, &intNodeIdxDim, &intNodeVecDim, &intNnodes, &intNodeIdx, &intNodeVec));
2621dca8a05SBarry Smith         PetscCheck(intNodeIdxDim == nodeIdxDim && intNodeVecDim == nodeVecDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior node indices not the same shale as all node indices");
26308401ef6SPierre Jolivet         PetscCheck(intNnodes == spintdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect interior nNodes");
2649566063dSJacob Faibussowitsch         PetscCall(PetscArraycmp(intNodeIdx, nodeIdx, nodeIdxDim * intNnodes, &same));
26528b400f6SJacob Faibussowitsch         PetscCheck(same, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior node indices not the same as start of all node indices");
2669566063dSJacob Faibussowitsch         PetscCall(PetscArraycmp(intNodeVec, nodeVec, nodeVecDim * intNnodes, &same));
26728b400f6SJacob Faibussowitsch         PetscCheck(same, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior node vectors not the same as start of all node vectors");
2688a820b8eSToby Isaac       } else if (intMat) {
2699566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "Interior data is the same as all data\n"));
27008401ef6SPierre Jolivet         PetscCheck(intNodes == allNodes, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior nodes should be the same as all nodes");
27108401ef6SPierre Jolivet         PetscCheck(lag->intNodeIndices == lag->allNodeIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior node indices should be the same as all node indices");
2728a820b8eSToby Isaac       }
2738a820b8eSToby Isaac     }
2748a820b8eSToby Isaac     if (dim <= 2 && spintdim) {
275b5a892a1SMatthew G. Knepley       PetscInt numFaces, o;
2768a820b8eSToby Isaac 
277b5a892a1SMatthew G. Knepley       {
278b5a892a1SMatthew G. Knepley         DMPolytopeType ct;
279b5a892a1SMatthew G. Knepley         /* The number of arrangements is no longer based on the number of faces */
2809566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(K, 0, &ct));
281b5a892a1SMatthew G. Knepley         numFaces = DMPolytopeTypeGetNumArrangments(ct) / 2;
282b5a892a1SMatthew G. Knepley       }
283b5a892a1SMatthew G. Knepley       for (o = -numFaces; o < numFaces; ++o) {
2848a820b8eSToby Isaac         Mat symMat;
2858a820b8eSToby Isaac 
2869566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceCreateInteriorSymmetryMatrix_Lagrange(sp, o, &symMat));
28763a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "Interior node symmetry matrix for orientation %" PetscInt_FMT ":\n", o));
2889566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_SELF));
2899566063dSJacob Faibussowitsch         PetscCall(MatView(symMat, PETSC_VIEWER_STDOUT_SELF));
2909566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_SELF));
2919566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&symMat));
2928a820b8eSToby Isaac       }
2938a820b8eSToby Isaac     }
2949566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_SELF));
2958a820b8eSToby Isaac   }
2969566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceDestroy(&sp));
297*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2988a820b8eSToby Isaac }
2998a820b8eSToby Isaac 
300d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
301d71ae5a4SJacob Faibussowitsch {
3028a820b8eSToby Isaac   PetscInt     dim;
3038a820b8eSToby Isaac   PetscHashLag lagTable;
3048a820b8eSToby Isaac   PetscInt     tensorCell;
3058a820b8eSToby Isaac   PetscInt     order, ordermin, ordermax;
3068a820b8eSToby Isaac   PetscBool    continuous;
3078a820b8eSToby Isaac   PetscBool    trimmed;
3088a820b8eSToby Isaac   DM           dm;
3098a820b8eSToby Isaac 
310327415f7SBarry Smith   PetscFunctionBeginUser;
3119566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
3128a820b8eSToby Isaac   dim        = 3;
3138a820b8eSToby Isaac   tensorCell = 0;
3148a820b8eSToby Isaac   continuous = PETSC_FALSE;
3158a820b8eSToby Isaac   trimmed    = PETSC_FALSE;
316d0609cedSBarry Smith   PetscOptionsBegin(PETSC_COMM_WORLD, "", "Options for PETSCDUALSPACELAGRANGE test", "none");
3179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsRangeInt("-dim", "The spatial dimension", "ex1.c", dim, &dim, NULL, 0, 3));
3189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsRangeInt("-tensor", "(0) simplex (1) hypercube (2) wedge", "ex1.c", tensorCell, &tensorCell, NULL, 0, 2));
3199566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-continuous", "Whether the dual space has continuity", "ex1.c", continuous, &continuous, NULL));
3209566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-trimmed", "Whether the dual space matches a trimmed polynomial space", "ex1.c", trimmed, &trimmed, NULL));
321d0609cedSBarry Smith   PetscOptionsEnd();
3229566063dSJacob Faibussowitsch   PetscCall(PetscHashLagCreate(&lagTable));
3238a820b8eSToby Isaac 
3248a820b8eSToby Isaac   if (tensorCell < 2) {
3259566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, (PetscBool)!tensorCell), &dm));
3268a820b8eSToby Isaac   } else {
3279566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DM_POLYTOPE_TRI_PRISM, &dm));
3288a820b8eSToby Isaac   }
3298a820b8eSToby Isaac   ordermin = trimmed ? 1 : 0;
3308a820b8eSToby Isaac   ordermax = tensorCell == 2 ? 4 : tensorCell == 1 ? 3 : dim + 2;
3318a820b8eSToby Isaac   for (order = ordermin; order <= ordermax; order++) {
3328a820b8eSToby Isaac     PetscInt formDegree;
3338a820b8eSToby Isaac 
3348a820b8eSToby Isaac     for (formDegree = PetscMin(0, -dim + 1); formDegree <= dim; formDegree++) {
3358a820b8eSToby Isaac       PetscInt nCopies;
3368a820b8eSToby Isaac 
33748a46eb9SPierre Jolivet       for (nCopies = 1; nCopies <= 3; nCopies++) PetscCall(testLagrange(lagTable, dm, dim, order, formDegree, trimmed, (PetscBool)tensorCell, continuous, nCopies));
3388a820b8eSToby Isaac     }
3398a820b8eSToby Isaac   }
3409566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
3419566063dSJacob Faibussowitsch   PetscCall(PetscHashLagDestroy(&lagTable));
3429566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
343b122ec5aSJacob Faibussowitsch   return 0;
3448a820b8eSToby Isaac }
3458a820b8eSToby Isaac 
3468a820b8eSToby Isaac /*TEST
3478a820b8eSToby Isaac 
3488a820b8eSToby Isaac  test:
3498a820b8eSToby Isaac    suffix: 0
3508a820b8eSToby Isaac    args: -dim 0
3518a820b8eSToby Isaac 
3528a820b8eSToby Isaac  test:
3538a820b8eSToby Isaac    suffix: 1_discontinuous_full
3548a820b8eSToby Isaac    args: -dim 1 -continuous 0 -trimmed 0
3558a820b8eSToby Isaac 
3568a820b8eSToby Isaac  test:
3578a820b8eSToby Isaac    suffix: 1_continuous_full
3588a820b8eSToby Isaac    args: -dim 1 -continuous 1 -trimmed 0
3598a820b8eSToby Isaac 
3608a820b8eSToby Isaac  test:
3618a820b8eSToby Isaac    suffix: 2_simplex_discontinuous_full
3628a820b8eSToby Isaac    args: -dim 2 -tensor 0 -continuous 0 -trimmed 0
3638a820b8eSToby Isaac 
3648a820b8eSToby Isaac  test:
3658a820b8eSToby Isaac    suffix: 2_simplex_continuous_full
3668a820b8eSToby Isaac    args: -dim 2 -tensor 0 -continuous 1 -trimmed 0
3678a820b8eSToby Isaac 
3688a820b8eSToby Isaac  test:
3698a820b8eSToby Isaac    suffix: 2_tensor_discontinuous_full
3708a820b8eSToby Isaac    args: -dim 2 -tensor 1 -continuous 0 -trimmed 0
3718a820b8eSToby Isaac 
3728a820b8eSToby Isaac  test:
3738a820b8eSToby Isaac    suffix: 2_tensor_continuous_full
3748a820b8eSToby Isaac    args: -dim 2 -tensor 1 -continuous 1 -trimmed 0
3758a820b8eSToby Isaac 
3768a820b8eSToby Isaac  test:
3778a820b8eSToby Isaac    suffix: 3_simplex_discontinuous_full
3788a820b8eSToby Isaac    args: -dim 3 -tensor 0 -continuous 0 -trimmed 0
3798a820b8eSToby Isaac 
3808a820b8eSToby Isaac  test:
3818a820b8eSToby Isaac    suffix: 3_simplex_continuous_full
3828a820b8eSToby Isaac    args: -dim 3 -tensor 0 -continuous 1 -trimmed 0
3838a820b8eSToby Isaac 
3848a820b8eSToby Isaac  test:
3858a820b8eSToby Isaac    suffix: 3_tensor_discontinuous_full
3868a820b8eSToby Isaac    args: -dim 3 -tensor 1 -continuous 0 -trimmed 0
3878a820b8eSToby Isaac 
3888a820b8eSToby Isaac  test:
3898a820b8eSToby Isaac    suffix: 3_tensor_continuous_full
3908a820b8eSToby Isaac    args: -dim 3 -tensor 1 -continuous 1 -trimmed 0
3918a820b8eSToby Isaac 
3928a820b8eSToby Isaac  test:
3938a820b8eSToby Isaac    suffix: 3_wedge_discontinuous_full
3948a820b8eSToby Isaac    args: -dim 3 -tensor 2 -continuous 0 -trimmed 0
3958a820b8eSToby Isaac 
3968a820b8eSToby Isaac  test:
3978a820b8eSToby Isaac    suffix: 3_wedge_continuous_full
3988a820b8eSToby Isaac    args: -dim 3 -tensor 2 -continuous 1 -trimmed 0
3998a820b8eSToby Isaac 
4008a820b8eSToby Isaac  test:
4018a820b8eSToby Isaac    suffix: 1_discontinuous_trimmed
4028a820b8eSToby Isaac    args: -dim 1 -continuous 0 -trimmed 1
4038a820b8eSToby Isaac 
4048a820b8eSToby Isaac  test:
4058a820b8eSToby Isaac    suffix: 1_continuous_trimmed
4068a820b8eSToby Isaac    args: -dim 1 -continuous 1 -trimmed 1
4078a820b8eSToby Isaac 
4088a820b8eSToby Isaac  test:
4098a820b8eSToby Isaac    suffix: 2_simplex_discontinuous_trimmed
4108a820b8eSToby Isaac    args: -dim 2 -tensor 0 -continuous 0 -trimmed 1
4118a820b8eSToby Isaac 
4128a820b8eSToby Isaac  test:
4138a820b8eSToby Isaac    suffix: 2_simplex_continuous_trimmed
4148a820b8eSToby Isaac    args: -dim 2 -tensor 0 -continuous 1 -trimmed 1
4158a820b8eSToby Isaac 
4168a820b8eSToby Isaac  test:
4178a820b8eSToby Isaac    suffix: 2_tensor_discontinuous_trimmed
4188a820b8eSToby Isaac    args: -dim 2 -tensor 1 -continuous 0 -trimmed 1
4198a820b8eSToby Isaac 
4208a820b8eSToby Isaac  test:
4218a820b8eSToby Isaac    suffix: 2_tensor_continuous_trimmed
4228a820b8eSToby Isaac    args: -dim 2 -tensor 1 -continuous 1 -trimmed 1
4238a820b8eSToby Isaac 
4248a820b8eSToby Isaac  test:
4258a820b8eSToby Isaac    suffix: 3_simplex_discontinuous_trimmed
4268a820b8eSToby Isaac    args: -dim 3 -tensor 0 -continuous 0 -trimmed 1
4278a820b8eSToby Isaac 
4288a820b8eSToby Isaac  test:
4298a820b8eSToby Isaac    suffix: 3_simplex_continuous_trimmed
4308a820b8eSToby Isaac    args: -dim 3 -tensor 0 -continuous 1 -trimmed 1
4318a820b8eSToby Isaac 
4328a820b8eSToby Isaac  test:
4338a820b8eSToby Isaac    suffix: 3_tensor_discontinuous_trimmed
4348a820b8eSToby Isaac    args: -dim 3 -tensor 1 -continuous 0 -trimmed 1
4358a820b8eSToby Isaac 
4368a820b8eSToby Isaac  test:
4378a820b8eSToby Isaac    suffix: 3_tensor_continuous_trimmed
4388a820b8eSToby Isaac    args: -dim 3 -tensor 1 -continuous 1 -trimmed 1
4398a820b8eSToby Isaac 
4408a820b8eSToby Isaac  test:
4418a820b8eSToby Isaac    suffix: 3_wedge_discontinuous_trimmed
4428a820b8eSToby Isaac    args: -dim 3 -tensor 2 -continuous 0 -trimmed 1
4438a820b8eSToby Isaac 
4448a820b8eSToby Isaac  test:
4458a820b8eSToby Isaac    suffix: 3_wedge_continuous_trimmed
4468a820b8eSToby Isaac    args: -dim 3 -tensor 2 -continuous 1 -trimmed 1
4478a820b8eSToby Isaac 
4488a820b8eSToby Isaac TEST*/
449