120cf1dd8SToby Isaac #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/ 220cf1dd8SToby Isaac #include <petscdmplex.h> 33f27d899SToby Isaac #include <petscblaslapack.h> 43f27d899SToby Isaac 53f27d899SToby Isaac PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM, PetscInt, PetscInt, PetscBool, PetscInt *, PetscInt *[]); 63f27d899SToby Isaac 73f27d899SToby Isaac struct _n_Petsc1DNodeFamily 83f27d899SToby Isaac { 93f27d899SToby Isaac PetscInt refct; 103f27d899SToby Isaac PetscDTNodeType nodeFamily; 113f27d899SToby Isaac PetscReal gaussJacobiExp; 123f27d899SToby Isaac PetscInt nComputed; 133f27d899SToby Isaac PetscReal **nodesets; 143f27d899SToby Isaac PetscBool endpoints; 153f27d899SToby Isaac }; 163f27d899SToby Isaac 1777f1a120SToby Isaac /* users set node families for PETSCDUALSPACELAGRANGE with just the inputs to this function, but internally we create 1877f1a120SToby Isaac * an object that can cache the computations across multiple dual spaces */ 193f27d899SToby Isaac static PetscErrorCode Petsc1DNodeFamilyCreate(PetscDTNodeType family, PetscReal gaussJacobiExp, PetscBool endpoints, Petsc1DNodeFamily *nf) 203f27d899SToby Isaac { 213f27d899SToby Isaac Petsc1DNodeFamily f; 223f27d899SToby Isaac PetscErrorCode ierr; 233f27d899SToby Isaac 243f27d899SToby Isaac PetscFunctionBegin; 253f27d899SToby Isaac ierr = PetscNew(&f);CHKERRQ(ierr); 263f27d899SToby Isaac switch (family) { 273f27d899SToby Isaac case PETSCDTNODES_GAUSSJACOBI: 283f27d899SToby Isaac case PETSCDTNODES_EQUISPACED: 293f27d899SToby Isaac f->nodeFamily = family; 303f27d899SToby Isaac break; 313f27d899SToby Isaac default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown 1D node family"); 323f27d899SToby Isaac } 333f27d899SToby Isaac f->endpoints = endpoints; 343f27d899SToby Isaac f->gaussJacobiExp = 0.; 353f27d899SToby Isaac if (family == PETSCDTNODES_GAUSSJACOBI) { 363f27d899SToby Isaac if (gaussJacobiExp <= -1.) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Gauss-Jacobi exponent must be > -1.\n"); 373f27d899SToby Isaac f->gaussJacobiExp = gaussJacobiExp; 383f27d899SToby Isaac } 393f27d899SToby Isaac f->refct = 1; 403f27d899SToby Isaac *nf = f; 413f27d899SToby Isaac PetscFunctionReturn(0); 423f27d899SToby Isaac } 433f27d899SToby Isaac 443f27d899SToby Isaac static PetscErrorCode Petsc1DNodeFamilyReference(Petsc1DNodeFamily nf) 453f27d899SToby Isaac { 463f27d899SToby Isaac PetscFunctionBegin; 473f27d899SToby Isaac if (nf) nf->refct++; 483f27d899SToby Isaac PetscFunctionReturn(0); 493f27d899SToby Isaac } 503f27d899SToby Isaac 51bdb10af2SPierre Jolivet static PetscErrorCode Petsc1DNodeFamilyDestroy(Petsc1DNodeFamily *nf) 52bdb10af2SPierre Jolivet { 533f27d899SToby Isaac PetscInt i, nc; 543f27d899SToby Isaac PetscErrorCode ierr; 553f27d899SToby Isaac 563f27d899SToby Isaac PetscFunctionBegin; 573f27d899SToby Isaac if (!(*nf)) PetscFunctionReturn(0); 583f27d899SToby Isaac if (--(*nf)->refct > 0) { 593f27d899SToby Isaac *nf = NULL; 603f27d899SToby Isaac PetscFunctionReturn(0); 613f27d899SToby Isaac } 623f27d899SToby Isaac nc = (*nf)->nComputed; 633f27d899SToby Isaac for (i = 0; i < nc; i++) { 643f27d899SToby Isaac ierr = PetscFree((*nf)->nodesets[i]);CHKERRQ(ierr); 653f27d899SToby Isaac } 663f27d899SToby Isaac ierr = PetscFree((*nf)->nodesets);CHKERRQ(ierr); 673f27d899SToby Isaac ierr = PetscFree(*nf);CHKERRQ(ierr); 683f27d899SToby Isaac *nf = NULL; 693f27d899SToby Isaac PetscFunctionReturn(0); 703f27d899SToby Isaac } 713f27d899SToby Isaac 723f27d899SToby Isaac static PetscErrorCode Petsc1DNodeFamilyGetNodeSets(Petsc1DNodeFamily f, PetscInt degree, PetscReal ***nodesets) 733f27d899SToby Isaac { 743f27d899SToby Isaac PetscInt nc; 753f27d899SToby Isaac PetscErrorCode ierr; 763f27d899SToby Isaac 773f27d899SToby Isaac PetscFunctionBegin; 783f27d899SToby Isaac nc = f->nComputed; 793f27d899SToby Isaac if (degree >= nc) { 803f27d899SToby Isaac PetscInt i, j; 813f27d899SToby Isaac PetscReal **new_nodesets; 823f27d899SToby Isaac PetscReal *w; 833f27d899SToby Isaac 843f27d899SToby Isaac ierr = PetscMalloc1(degree + 1, &new_nodesets);CHKERRQ(ierr); 853f27d899SToby Isaac ierr = PetscArraycpy(new_nodesets, f->nodesets, nc);CHKERRQ(ierr); 863f27d899SToby Isaac ierr = PetscFree(f->nodesets);CHKERRQ(ierr); 873f27d899SToby Isaac f->nodesets = new_nodesets; 883f27d899SToby Isaac ierr = PetscMalloc1(degree + 1, &w);CHKERRQ(ierr); 893f27d899SToby Isaac for (i = nc; i < degree + 1; i++) { 903f27d899SToby Isaac ierr = PetscMalloc1(i + 1, &(f->nodesets[i]));CHKERRQ(ierr); 913f27d899SToby Isaac if (!i) { 923f27d899SToby Isaac f->nodesets[i][0] = 0.5; 933f27d899SToby Isaac } else { 943f27d899SToby Isaac switch (f->nodeFamily) { 953f27d899SToby Isaac case PETSCDTNODES_EQUISPACED: 963f27d899SToby Isaac if (f->endpoints) { 973f27d899SToby Isaac for (j = 0; j <= i; j++) f->nodesets[i][j] = (PetscReal) j / (PetscReal) i; 983f27d899SToby Isaac } else { 9977f1a120SToby Isaac /* these nodes are at the centroids of the small simplices created by the equispaced nodes that include 10077f1a120SToby Isaac * the endpoints */ 1013f27d899SToby Isaac for (j = 0; j <= i; j++) f->nodesets[i][j] = ((PetscReal) j + 0.5) / ((PetscReal) i + 1.); 1023f27d899SToby Isaac } 1033f27d899SToby Isaac break; 1043f27d899SToby Isaac case PETSCDTNODES_GAUSSJACOBI: 1053f27d899SToby Isaac if (f->endpoints) { 1063f27d899SToby Isaac ierr = PetscDTGaussLobattoJacobiQuadrature(i + 1, 0., 1., f->gaussJacobiExp, f->gaussJacobiExp, f->nodesets[i], w);CHKERRQ(ierr); 1073f27d899SToby Isaac } else { 1083f27d899SToby Isaac ierr = PetscDTGaussJacobiQuadrature(i + 1, 0., 1., f->gaussJacobiExp, f->gaussJacobiExp, f->nodesets[i], w);CHKERRQ(ierr); 1093f27d899SToby Isaac } 1103f27d899SToby Isaac break; 1113f27d899SToby Isaac default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown 1D node family"); 1123f27d899SToby Isaac } 1133f27d899SToby Isaac } 1143f27d899SToby Isaac } 1153f27d899SToby Isaac ierr = PetscFree(w);CHKERRQ(ierr); 1163f27d899SToby Isaac f->nComputed = degree + 1; 1173f27d899SToby Isaac } 1183f27d899SToby Isaac *nodesets = f->nodesets; 1193f27d899SToby Isaac PetscFunctionReturn(0); 1203f27d899SToby Isaac } 1213f27d899SToby Isaac 12277f1a120SToby Isaac /* http://arxiv.org/abs/2002.09421 for details */ 1233f27d899SToby Isaac static PetscErrorCode PetscNodeRecursive_Internal(PetscInt dim, PetscInt degree, PetscReal **nodesets, PetscInt tup[], PetscReal node[]) 1243f27d899SToby Isaac { 1253f27d899SToby Isaac PetscReal w; 1263f27d899SToby Isaac PetscInt i, j; 1273f27d899SToby Isaac PetscErrorCode ierr; 1283f27d899SToby Isaac 1293f27d899SToby Isaac PetscFunctionBeginHot; 1303f27d899SToby Isaac w = 0.; 1313f27d899SToby Isaac if (dim == 1) { 1323f27d899SToby Isaac node[0] = nodesets[degree][tup[0]]; 1333f27d899SToby Isaac node[1] = nodesets[degree][tup[1]]; 1343f27d899SToby Isaac } else { 1353f27d899SToby Isaac for (i = 0; i < dim + 1; i++) node[i] = 0.; 1363f27d899SToby Isaac for (i = 0; i < dim + 1; i++) { 1373f27d899SToby Isaac PetscReal wi = nodesets[degree][degree-tup[i]]; 1383f27d899SToby Isaac 1393f27d899SToby Isaac for (j = 0; j < dim+1; j++) tup[dim+1+j] = tup[j+(j>=i)]; 1403f27d899SToby Isaac ierr = PetscNodeRecursive_Internal(dim-1,degree-tup[i],nodesets,&tup[dim+1],&node[dim+1]);CHKERRQ(ierr); 1413f27d899SToby Isaac for (j = 0; j < dim+1; j++) node[j+(j>=i)] += wi * node[dim+1+j]; 1423f27d899SToby Isaac w += wi; 1433f27d899SToby Isaac } 1443f27d899SToby Isaac for (i = 0; i < dim+1; i++) node[i] /= w; 1453f27d899SToby Isaac } 1463f27d899SToby Isaac PetscFunctionReturn(0); 1473f27d899SToby Isaac } 1483f27d899SToby Isaac 1493f27d899SToby Isaac /* compute simplex nodes for the biunit simplex from the 1D node family */ 1503f27d899SToby Isaac static PetscErrorCode Petsc1DNodeFamilyComputeSimplexNodes(Petsc1DNodeFamily f, PetscInt dim, PetscInt degree, PetscReal points[]) 1513f27d899SToby Isaac { 1523f27d899SToby Isaac PetscInt *tup; 1533f27d899SToby Isaac PetscInt k; 1543f27d899SToby Isaac PetscInt npoints; 1553f27d899SToby Isaac PetscReal **nodesets = NULL; 1563f27d899SToby Isaac PetscInt worksize; 1573f27d899SToby Isaac PetscReal *nodework; 1583f27d899SToby Isaac PetscInt *tupwork; 1593f27d899SToby Isaac PetscErrorCode ierr; 1603f27d899SToby Isaac 1613f27d899SToby Isaac PetscFunctionBegin; 1623f27d899SToby Isaac if (dim < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have non-negative dimension\n"); 1633f27d899SToby Isaac if (degree < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have non-negative degree\n"); 1643f27d899SToby Isaac if (!dim) PetscFunctionReturn(0); 1653f27d899SToby Isaac ierr = PetscCalloc1(dim+2, &tup);CHKERRQ(ierr); 1663f27d899SToby Isaac k = 0; 1673f27d899SToby Isaac ierr = PetscDTBinomialInt(degree + dim, dim, &npoints);CHKERRQ(ierr); 1683f27d899SToby Isaac ierr = Petsc1DNodeFamilyGetNodeSets(f, degree, &nodesets);CHKERRQ(ierr); 1693f27d899SToby Isaac worksize = ((dim + 2) * (dim + 3)) / 2; 1703f27d899SToby Isaac ierr = PetscMalloc2(worksize, &nodework, worksize, &tupwork);CHKERRQ(ierr); 17177f1a120SToby Isaac /* loop over the tuples of length dim with sum at most degree */ 1723f27d899SToby Isaac for (k = 0; k < npoints; k++) { 1733f27d899SToby Isaac PetscInt i; 1743f27d899SToby Isaac 17577f1a120SToby Isaac /* turn thm into tuples of length dim + 1 with sum equal to degree (barycentric indice) */ 1763f27d899SToby Isaac tup[0] = degree; 1773f27d899SToby Isaac for (i = 0; i < dim; i++) { 1783f27d899SToby Isaac tup[0] -= tup[i+1]; 1793f27d899SToby Isaac } 1803f27d899SToby Isaac switch(f->nodeFamily) { 1813f27d899SToby Isaac case PETSCDTNODES_EQUISPACED: 18277f1a120SToby Isaac /* compute equispaces nodes on the unit reference triangle */ 1833f27d899SToby Isaac if (f->endpoints) { 1843f27d899SToby Isaac for (i = 0; i < dim; i++) { 1853f27d899SToby Isaac points[dim*k + i] = (PetscReal) tup[i+1] / (PetscReal) degree; 1863f27d899SToby Isaac } 1873f27d899SToby Isaac } else { 1883f27d899SToby Isaac for (i = 0; i < dim; i++) { 18977f1a120SToby Isaac /* these nodes are at the centroids of the small simplices created by the equispaced nodes that include 19077f1a120SToby Isaac * the endpoints */ 1913f27d899SToby Isaac points[dim*k + i] = ((PetscReal) tup[i+1] + 1./(dim+1.)) / (PetscReal) (degree + 1.); 1923f27d899SToby Isaac } 1933f27d899SToby Isaac } 1943f27d899SToby Isaac break; 1953f27d899SToby Isaac default: 19677f1a120SToby Isaac /* compute equispaces nodes on the barycentric reference triangle (the trace on the first dim dimensions are the 19777f1a120SToby Isaac * unit reference triangle nodes */ 1983f27d899SToby Isaac for (i = 0; i < dim + 1; i++) tupwork[i] = tup[i]; 1993f27d899SToby Isaac ierr = PetscNodeRecursive_Internal(dim, degree, nodesets, tupwork, nodework);CHKERRQ(ierr); 2003f27d899SToby Isaac for (i = 0; i < dim; i++) points[dim*k + i] = nodework[i + 1]; 2013f27d899SToby Isaac break; 2023f27d899SToby Isaac } 2033f27d899SToby Isaac ierr = PetscDualSpaceLatticePointLexicographic_Internal(dim, degree, &tup[1]);CHKERRQ(ierr); 2043f27d899SToby Isaac } 2053f27d899SToby Isaac /* map from unit simplex to biunit simplex */ 2063f27d899SToby Isaac for (k = 0; k < npoints * dim; k++) points[k] = points[k] * 2. - 1.; 2073f27d899SToby Isaac ierr = PetscFree2(nodework, tupwork);CHKERRQ(ierr); 208*1e1ea65dSPierre Jolivet ierr = PetscFree(tup);CHKERRQ(ierr); 2093f27d899SToby Isaac PetscFunctionReturn(0); 2103f27d899SToby Isaac } 2113f27d899SToby Isaac 21277f1a120SToby Isaac /* If we need to get the dofs from a mesh point, or add values into dofs at a mesh point, and there is more than one dof 21377f1a120SToby Isaac * on that mesh point, we have to be careful about getting/adding everything in the right place. 21477f1a120SToby Isaac * 21577f1a120SToby Isaac * With nodal dofs like PETSCDUALSPACELAGRANGE makes, the general approach to calculate the value of dofs associate 21677f1a120SToby Isaac * with a node A is 21777f1a120SToby Isaac * - transform the node locations x(A) by the map that takes the mesh point to its reorientation, x' = phi(x(A)) 21877f1a120SToby Isaac * - figure out which node was originally at the location of the transformed point, A' = idx(x') 21977f1a120SToby Isaac * - if the dofs are not scalars, figure out how to represent the transformed dofs in terms of the basis 22077f1a120SToby Isaac * of dofs at A' (using pushforward/pullback rules) 22177f1a120SToby Isaac * 22277f1a120SToby Isaac * The one sticky point with this approach is the "A' = idx(x')" step: trying to go from real valued coordinates 22377f1a120SToby Isaac * back to indices. I don't want to rely on floating point tolerances. Additionally, PETSCDUALSPACELAGRANGE may 22477f1a120SToby Isaac * eventually support quasi-Lagrangian dofs, which could involve quadrature at multiple points, so the location "x(A)" 22577f1a120SToby Isaac * would be ambiguous. 22677f1a120SToby Isaac * 22777f1a120SToby Isaac * So each dof gets an integer value coordinate (nodeIdx in the structure below). The choice of integer coordinates 22877f1a120SToby Isaac * is somewhat arbitrary, as long as all of the relevant symmetries of the mesh point correspond to *permutations* of 22977f1a120SToby Isaac * the integer coordinates, which do not depend on numerical precision. 23077f1a120SToby Isaac * 23177f1a120SToby Isaac * So 23277f1a120SToby Isaac * 23377f1a120SToby Isaac * - DMPlexGetTransitiveClosure_Internal() tells me how an orientation turns into a permutation of the vertices of a 23477f1a120SToby Isaac * mesh point 23577f1a120SToby Isaac * - The permutation of the vertices, and the nodeIdx values assigned to them, tells what permutation in index space 23677f1a120SToby Isaac * is associated with the orientation 23777f1a120SToby Isaac * - I uses that permutation to get xi' = phi(xi(A)), the integer coordinate of the transformed dof 23877f1a120SToby Isaac * - I can without numerical issues compute A' = idx(xi') 23977f1a120SToby Isaac * 24077f1a120SToby Isaac * Here are some examples of how the process works 24177f1a120SToby Isaac * 24277f1a120SToby Isaac * - With a triangle: 24377f1a120SToby Isaac * 24477f1a120SToby Isaac * The triangle has the following integer coordinates for vertices, taken from the barycentric triangle 24577f1a120SToby Isaac * 24677f1a120SToby Isaac * closure order 2 24777f1a120SToby Isaac * nodeIdx (0,0,1) 24877f1a120SToby Isaac * \ 24977f1a120SToby Isaac * + 25077f1a120SToby Isaac * |\ 25177f1a120SToby Isaac * | \ 25277f1a120SToby Isaac * | \ 25377f1a120SToby Isaac * | \ closure order 1 25477f1a120SToby Isaac * | \ / nodeIdx (0,1,0) 25577f1a120SToby Isaac * +-----+ 25677f1a120SToby Isaac * \ 25777f1a120SToby Isaac * closure order 0 25877f1a120SToby Isaac * nodeIdx (1,0,0) 25977f1a120SToby Isaac * 26077f1a120SToby Isaac * If I do DMPlexGetTransitiveClosure_Internal() with orientation 1, the vertices would appear 26177f1a120SToby Isaac * in the order (1, 2, 0) 26277f1a120SToby Isaac * 26377f1a120SToby Isaac * If I list the nodeIdx of each vertex in closure order for orientation 0 (0, 1, 2) and orientation 1 (1, 2, 0), I 26477f1a120SToby Isaac * see 26577f1a120SToby Isaac * 26677f1a120SToby Isaac * orientation 0 | orientation 1 26777f1a120SToby Isaac * 26877f1a120SToby Isaac * [0] (1,0,0) [1] (0,1,0) 26977f1a120SToby Isaac * [1] (0,1,0) [2] (0,0,1) 27077f1a120SToby Isaac * [2] (0,0,1) [0] (1,0,0) 27177f1a120SToby Isaac * A B 27277f1a120SToby Isaac * 27377f1a120SToby Isaac * In other words, B is the result of a row permutation of A. But, there is also 27477f1a120SToby Isaac * a column permutation that accomplishes the same result, (2,0,1). 27577f1a120SToby Isaac * 27677f1a120SToby Isaac * So if a dof has nodeIdx coordinate (a,b,c), after the transformation its nodeIdx coordinate 27777f1a120SToby Isaac * is (c,a,b), and the transformed degree of freedom will be a linear combination of dofs 27877f1a120SToby Isaac * that originally had coordinate (c,a,b). 27977f1a120SToby Isaac * 28077f1a120SToby Isaac * - With a quadrilateral: 28177f1a120SToby Isaac * 28277f1a120SToby Isaac * The quadrilateral has the following integer coordinates for vertices, taken from concatenating barycentric 28377f1a120SToby Isaac * coordinates for two segments: 28477f1a120SToby Isaac * 28577f1a120SToby Isaac * closure order 3 closure order 2 28677f1a120SToby Isaac * nodeIdx (1,0,0,1) nodeIdx (0,1,0,1) 28777f1a120SToby Isaac * \ / 28877f1a120SToby Isaac * +----+ 28977f1a120SToby Isaac * | | 29077f1a120SToby Isaac * | | 29177f1a120SToby Isaac * +----+ 29277f1a120SToby Isaac * / \ 29377f1a120SToby Isaac * closure order 0 closure order 1 29477f1a120SToby Isaac * nodeIdx (1,0,1,0) nodeIdx (0,1,1,0) 29577f1a120SToby Isaac * 29677f1a120SToby Isaac * If I do DMPlexGetTransitiveClosure_Internal() with orientation 1, the vertices would appear 29777f1a120SToby Isaac * in the order (1, 2, 3, 0) 29877f1a120SToby Isaac * 29977f1a120SToby Isaac * If I list the nodeIdx of each vertex in closure order for orientation 0 (0, 1, 2, 3) and 30077f1a120SToby Isaac * orientation 1 (1, 2, 3, 0), I see 30177f1a120SToby Isaac * 30277f1a120SToby Isaac * orientation 0 | orientation 1 30377f1a120SToby Isaac * 30477f1a120SToby Isaac * [0] (1,0,1,0) [1] (0,1,1,0) 30577f1a120SToby Isaac * [1] (0,1,1,0) [2] (0,1,0,1) 30677f1a120SToby Isaac * [2] (0,1,0,1) [3] (1,0,0,1) 30777f1a120SToby Isaac * [3] (1,0,0,1) [0] (1,0,1,0) 30877f1a120SToby Isaac * A B 30977f1a120SToby Isaac * 31077f1a120SToby Isaac * The column permutation that accomplishes the same result is (3,2,0,1). 31177f1a120SToby Isaac * 31277f1a120SToby Isaac * So if a dof has nodeIdx coordinate (a,b,c,d), after the transformation its nodeIdx coordinate 31377f1a120SToby Isaac * is (d,c,a,b), and the transformed degree of freedom will be a linear combination of dofs 31477f1a120SToby Isaac * that originally had coordinate (d,c,a,b). 31577f1a120SToby Isaac * 31677f1a120SToby Isaac * Previously PETSCDUALSPACELAGRANGE had hardcoded symmetries for the triangle and quadrilateral, 31777f1a120SToby Isaac * but this approach will work for any polytope, such as the wedge (triangular prism). 31877f1a120SToby Isaac */ 3193f27d899SToby Isaac struct _n_PetscLagNodeIndices 3203f27d899SToby Isaac { 3213f27d899SToby Isaac PetscInt refct; 3223f27d899SToby Isaac PetscInt nodeIdxDim; 3233f27d899SToby Isaac PetscInt nodeVecDim; 3243f27d899SToby Isaac PetscInt nNodes; 3253f27d899SToby Isaac PetscInt *nodeIdx; /* for each node an index of size nodeIdxDim */ 3263f27d899SToby Isaac PetscReal *nodeVec; /* for each node a vector of size nodeVecDim */ 3273f27d899SToby Isaac PetscInt *perm; /* if these are vertices, perm takes DMPlex point index to closure order; 3283f27d899SToby Isaac if these are nodes, perm lists nodes in index revlex order */ 3293f27d899SToby Isaac }; 3303f27d899SToby Isaac 33177f1a120SToby Isaac /* this is just here so I can access the values in tests/ex1.c outside the library */ 3323f27d899SToby Isaac PetscErrorCode PetscLagNodeIndicesGetData_Internal(PetscLagNodeIndices ni, PetscInt *nodeIdxDim, PetscInt *nodeVecDim, PetscInt *nNodes, const PetscInt *nodeIdx[], const PetscReal *nodeVec[]) 3333f27d899SToby Isaac { 3343f27d899SToby Isaac PetscFunctionBegin; 3353f27d899SToby Isaac *nodeIdxDim = ni->nodeIdxDim; 3363f27d899SToby Isaac *nodeVecDim = ni->nodeVecDim; 3373f27d899SToby Isaac *nNodes = ni->nNodes; 3383f27d899SToby Isaac *nodeIdx = ni->nodeIdx; 3393f27d899SToby Isaac *nodeVec = ni->nodeVec; 3403f27d899SToby Isaac PetscFunctionReturn(0); 3413f27d899SToby Isaac } 3423f27d899SToby Isaac 3433f27d899SToby Isaac static PetscErrorCode PetscLagNodeIndicesReference(PetscLagNodeIndices ni) 3443f27d899SToby Isaac { 3453f27d899SToby Isaac PetscFunctionBegin; 3463f27d899SToby Isaac if (ni) ni->refct++; 3473f27d899SToby Isaac PetscFunctionReturn(0); 3483f27d899SToby Isaac } 3493f27d899SToby Isaac 3501f440fbeSToby Isaac static PetscErrorCode PetscLagNodeIndicesDuplicate(PetscLagNodeIndices ni, PetscLagNodeIndices *niNew) 3511f440fbeSToby Isaac { 3521f440fbeSToby Isaac PetscErrorCode ierr; 3531f440fbeSToby Isaac 3541f440fbeSToby Isaac PetscFunctionBegin; 3551f440fbeSToby Isaac ierr = PetscNew(niNew);CHKERRQ(ierr); 3561f440fbeSToby Isaac (*niNew)->refct = 1; 3571f440fbeSToby Isaac (*niNew)->nodeIdxDim = ni->nodeIdxDim; 3581f440fbeSToby Isaac (*niNew)->nodeVecDim = ni->nodeVecDim; 3591f440fbeSToby Isaac (*niNew)->nNodes = ni->nNodes; 3601f440fbeSToby Isaac ierr = PetscMalloc1(ni->nNodes * ni->nodeIdxDim, &((*niNew)->nodeIdx));CHKERRQ(ierr); 3611f440fbeSToby Isaac ierr = PetscArraycpy((*niNew)->nodeIdx, ni->nodeIdx, ni->nNodes * ni->nodeIdxDim);CHKERRQ(ierr); 3621f440fbeSToby Isaac ierr = PetscMalloc1(ni->nNodes * ni->nodeVecDim, &((*niNew)->nodeVec));CHKERRQ(ierr); 3631f440fbeSToby Isaac ierr = PetscArraycpy((*niNew)->nodeVec, ni->nodeVec, ni->nNodes * ni->nodeVecDim);CHKERRQ(ierr); 3641f440fbeSToby Isaac (*niNew)->perm = NULL; 3651f440fbeSToby Isaac PetscFunctionReturn(0); 3661f440fbeSToby Isaac } 3671f440fbeSToby Isaac 368bdb10af2SPierre Jolivet static PetscErrorCode PetscLagNodeIndicesDestroy(PetscLagNodeIndices *ni) 369bdb10af2SPierre Jolivet { 3703f27d899SToby Isaac PetscErrorCode ierr; 3713f27d899SToby Isaac 3723f27d899SToby Isaac PetscFunctionBegin; 3733f27d899SToby Isaac if (!(*ni)) PetscFunctionReturn(0); 3743f27d899SToby Isaac if (--(*ni)->refct > 0) { 3753f27d899SToby Isaac *ni = NULL; 3763f27d899SToby Isaac PetscFunctionReturn(0); 3773f27d899SToby Isaac } 3783f27d899SToby Isaac ierr = PetscFree((*ni)->nodeIdx);CHKERRQ(ierr); 3793f27d899SToby Isaac ierr = PetscFree((*ni)->nodeVec);CHKERRQ(ierr); 3803f27d899SToby Isaac ierr = PetscFree((*ni)->perm);CHKERRQ(ierr); 3813f27d899SToby Isaac ierr = PetscFree(*ni);CHKERRQ(ierr); 3823f27d899SToby Isaac *ni = NULL; 3833f27d899SToby Isaac PetscFunctionReturn(0); 3843f27d899SToby Isaac } 3853f27d899SToby Isaac 38677f1a120SToby Isaac /* The vertices are given nodeIdx coordinates (e.g. the corners of the barycentric triangle). Those coordinates are 38777f1a120SToby Isaac * in some other order, and to understand the effect of different symmetries, we need them to be in closure order. 38877f1a120SToby Isaac * 38977f1a120SToby Isaac * If sortIdx is PETSC_FALSE, the coordinates are already in revlex order, otherwise we must sort them 39077f1a120SToby Isaac * to that order before we do the real work of this function, which is 39177f1a120SToby Isaac * 39277f1a120SToby Isaac * - mark the vertices in closure order 39377f1a120SToby Isaac * - sort them in revlex order 39477f1a120SToby Isaac * - use the resulting permutation to list the vertex coordinates in closure order 39577f1a120SToby Isaac */ 3963f27d899SToby Isaac static PetscErrorCode PetscLagNodeIndicesComputeVertexOrder(DM dm, PetscLagNodeIndices ni, PetscBool sortIdx) 3973f27d899SToby Isaac { 3983f27d899SToby Isaac PetscInt v, w, vStart, vEnd, c, d; 3993f27d899SToby Isaac PetscInt nVerts; 4003f27d899SToby Isaac PetscInt closureSize = 0; 4013f27d899SToby Isaac PetscInt *closure = NULL; 4023f27d899SToby Isaac PetscInt *closureOrder; 4033f27d899SToby Isaac PetscInt *invClosureOrder; 4043f27d899SToby Isaac PetscInt *revlexOrder; 4053f27d899SToby Isaac PetscInt *newNodeIdx; 4063f27d899SToby Isaac PetscInt dim; 4073f27d899SToby Isaac Vec coordVec; 4083f27d899SToby Isaac const PetscScalar *coords; 4093f27d899SToby Isaac PetscErrorCode ierr; 4103f27d899SToby Isaac 4113f27d899SToby Isaac PetscFunctionBegin; 4123f27d899SToby Isaac ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 4133f27d899SToby Isaac ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 4143f27d899SToby Isaac nVerts = vEnd - vStart; 4153f27d899SToby Isaac ierr = PetscMalloc1(nVerts, &closureOrder);CHKERRQ(ierr); 4163f27d899SToby Isaac ierr = PetscMalloc1(nVerts, &invClosureOrder);CHKERRQ(ierr); 4173f27d899SToby Isaac ierr = PetscMalloc1(nVerts, &revlexOrder);CHKERRQ(ierr); 41877f1a120SToby Isaac if (sortIdx) { /* bubble sort nodeIdx into revlex order */ 4193f27d899SToby Isaac PetscInt nodeIdxDim = ni->nodeIdxDim; 4203f27d899SToby Isaac PetscInt *idxOrder; 4213f27d899SToby Isaac 4223f27d899SToby Isaac ierr = PetscMalloc1(nVerts * nodeIdxDim, &newNodeIdx);CHKERRQ(ierr); 4233f27d899SToby Isaac ierr = PetscMalloc1(nVerts, &idxOrder);CHKERRQ(ierr); 4243f27d899SToby Isaac for (v = 0; v < nVerts; v++) idxOrder[v] = v; 4253f27d899SToby Isaac for (v = 0; v < nVerts; v++) { 4263f27d899SToby Isaac for (w = v + 1; w < nVerts; w++) { 4273f27d899SToby Isaac const PetscInt *iv = &(ni->nodeIdx[idxOrder[v] * nodeIdxDim]); 4283f27d899SToby Isaac const PetscInt *iw = &(ni->nodeIdx[idxOrder[w] * nodeIdxDim]); 4293f27d899SToby Isaac PetscInt diff = 0; 4303f27d899SToby Isaac 4313f27d899SToby Isaac for (d = nodeIdxDim - 1; d >= 0; d--) if ((diff = (iv[d] - iw[d]))) break; 4323f27d899SToby Isaac if (diff > 0) { 4333f27d899SToby Isaac PetscInt swap = idxOrder[v]; 4343f27d899SToby Isaac 4353f27d899SToby Isaac idxOrder[v] = idxOrder[w]; 4363f27d899SToby Isaac idxOrder[w] = swap; 4373f27d899SToby Isaac } 4383f27d899SToby Isaac } 4393f27d899SToby Isaac } 4403f27d899SToby Isaac for (v = 0; v < nVerts; v++) { 4413f27d899SToby Isaac for (d = 0; d < nodeIdxDim; d++) { 4423f27d899SToby Isaac newNodeIdx[v * ni->nodeIdxDim + d] = ni->nodeIdx[idxOrder[v] * nodeIdxDim + d]; 4433f27d899SToby Isaac } 4443f27d899SToby Isaac } 4453f27d899SToby Isaac ierr = PetscFree(ni->nodeIdx);CHKERRQ(ierr); 4463f27d899SToby Isaac ni->nodeIdx = newNodeIdx; 4473f27d899SToby Isaac newNodeIdx = NULL; 4483f27d899SToby Isaac ierr = PetscFree(idxOrder);CHKERRQ(ierr); 4493f27d899SToby Isaac } 4503f27d899SToby Isaac ierr = DMPlexGetTransitiveClosure(dm, 0, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 4513f27d899SToby Isaac c = closureSize - nVerts; 4523f27d899SToby Isaac for (v = 0; v < nVerts; v++) closureOrder[v] = closure[2 * (c + v)] - vStart; 4533f27d899SToby Isaac for (v = 0; v < nVerts; v++) invClosureOrder[closureOrder[v]] = v; 4543f27d899SToby Isaac ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 4553f27d899SToby Isaac ierr = DMGetCoordinatesLocal(dm, &coordVec);CHKERRQ(ierr); 4563f27d899SToby Isaac ierr = VecGetArrayRead(coordVec, &coords);CHKERRQ(ierr); 4573f27d899SToby Isaac /* bubble sort closure vertices by coordinates in revlex order */ 4583f27d899SToby Isaac for (v = 0; v < nVerts; v++) revlexOrder[v] = v; 4593f27d899SToby Isaac for (v = 0; v < nVerts; v++) { 4603f27d899SToby Isaac for (w = v + 1; w < nVerts; w++) { 4613f27d899SToby Isaac const PetscScalar *cv = &coords[closureOrder[revlexOrder[v]] * dim]; 4623f27d899SToby Isaac const PetscScalar *cw = &coords[closureOrder[revlexOrder[w]] * dim]; 4633f27d899SToby Isaac PetscReal diff = 0; 4643f27d899SToby Isaac 4653f27d899SToby Isaac for (d = dim - 1; d >= 0; d--) if ((diff = PetscRealPart(cv[d] - cw[d])) != 0.) break; 4663f27d899SToby Isaac if (diff > 0.) { 4673f27d899SToby Isaac PetscInt swap = revlexOrder[v]; 4683f27d899SToby Isaac 4693f27d899SToby Isaac revlexOrder[v] = revlexOrder[w]; 4703f27d899SToby Isaac revlexOrder[w] = swap; 4713f27d899SToby Isaac } 4723f27d899SToby Isaac } 4733f27d899SToby Isaac } 4743f27d899SToby Isaac ierr = VecRestoreArrayRead(coordVec, &coords);CHKERRQ(ierr); 4753f27d899SToby Isaac ierr = PetscMalloc1(ni->nodeIdxDim * nVerts, &newNodeIdx);CHKERRQ(ierr); 4763f27d899SToby Isaac /* reorder nodeIdx to be in closure order */ 4773f27d899SToby Isaac for (v = 0; v < nVerts; v++) { 4783f27d899SToby Isaac for (d = 0; d < ni->nodeIdxDim; d++) { 4793f27d899SToby Isaac newNodeIdx[revlexOrder[v] * ni->nodeIdxDim + d] = ni->nodeIdx[v * ni->nodeIdxDim + d]; 4803f27d899SToby Isaac } 4813f27d899SToby Isaac } 4823f27d899SToby Isaac ierr = PetscFree(ni->nodeIdx);CHKERRQ(ierr); 4833f27d899SToby Isaac ni->nodeIdx = newNodeIdx; 4843f27d899SToby Isaac ni->perm = invClosureOrder; 4853f27d899SToby Isaac ierr = PetscFree(revlexOrder);CHKERRQ(ierr); 4863f27d899SToby Isaac ierr = PetscFree(closureOrder);CHKERRQ(ierr); 4873f27d899SToby Isaac PetscFunctionReturn(0); 4883f27d899SToby Isaac } 4893f27d899SToby Isaac 49077f1a120SToby Isaac /* the coordinates of the simplex vertices are the corners of the barycentric simplex. 49177f1a120SToby Isaac * When we stack them on top of each other in revlex order, they look like the identity matrix */ 4923f27d899SToby Isaac static PetscErrorCode PetscLagNodeIndicesCreateSimplexVertices(DM dm, PetscLagNodeIndices *nodeIndices) 4933f27d899SToby Isaac { 4943f27d899SToby Isaac PetscLagNodeIndices ni; 4953f27d899SToby Isaac PetscInt dim, d; 4963f27d899SToby Isaac 4973f27d899SToby Isaac PetscErrorCode ierr; 4983f27d899SToby Isaac 4993f27d899SToby Isaac PetscFunctionBegin; 5003f27d899SToby Isaac ierr = PetscNew(&ni);CHKERRQ(ierr); 5013f27d899SToby Isaac ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5023f27d899SToby Isaac ni->nodeIdxDim = dim + 1; 5033f27d899SToby Isaac ni->nodeVecDim = 0; 5043f27d899SToby Isaac ni->nNodes = dim + 1; 5053f27d899SToby Isaac ni->refct = 1; 5063f27d899SToby Isaac ierr = PetscCalloc1((dim + 1)*(dim + 1), &(ni->nodeIdx));CHKERRQ(ierr); 5073f27d899SToby Isaac for (d = 0; d < dim + 1; d++) ni->nodeIdx[d*(dim + 2)] = 1; 5083f27d899SToby Isaac ierr = PetscLagNodeIndicesComputeVertexOrder(dm, ni, PETSC_FALSE);CHKERRQ(ierr); 5093f27d899SToby Isaac *nodeIndices = ni; 5103f27d899SToby Isaac PetscFunctionReturn(0); 5113f27d899SToby Isaac } 5123f27d899SToby Isaac 51377f1a120SToby Isaac /* A polytope that is a tensor product of a facet and a segment. 51477f1a120SToby Isaac * We take whatever coordinate system was being used for the facet 5151f440fbeSToby Isaac * and we concatenate the barycentric coordinates for the vertices 51677f1a120SToby Isaac * at the end of the segment, (1,0) and (0,1), to get a coordinate 51777f1a120SToby Isaac * system for the tensor product element */ 5183f27d899SToby Isaac static PetscErrorCode PetscLagNodeIndicesCreateTensorVertices(DM dm, PetscLagNodeIndices facetni, PetscLagNodeIndices *nodeIndices) 5193f27d899SToby Isaac { 5203f27d899SToby Isaac PetscLagNodeIndices ni; 5213f27d899SToby Isaac PetscInt nodeIdxDim, subNodeIdxDim = facetni->nodeIdxDim; 5223f27d899SToby Isaac PetscInt nVerts, nSubVerts = facetni->nNodes; 5233f27d899SToby Isaac PetscInt dim, d, e, f, g; 5243f27d899SToby Isaac 5253f27d899SToby Isaac PetscErrorCode ierr; 5263f27d899SToby Isaac 5273f27d899SToby Isaac PetscFunctionBegin; 5283f27d899SToby Isaac ierr = PetscNew(&ni);CHKERRQ(ierr); 5293f27d899SToby Isaac ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5303f27d899SToby Isaac ni->nodeIdxDim = nodeIdxDim = subNodeIdxDim + 2; 5313f27d899SToby Isaac ni->nodeVecDim = 0; 5323f27d899SToby Isaac ni->nNodes = nVerts = 2 * nSubVerts; 5333f27d899SToby Isaac ni->refct = 1; 5343f27d899SToby Isaac ierr = PetscCalloc1(nodeIdxDim * nVerts, &(ni->nodeIdx));CHKERRQ(ierr); 5353f27d899SToby Isaac for (f = 0, d = 0; d < 2; d++) { 5363f27d899SToby Isaac for (e = 0; e < nSubVerts; e++, f++) { 5373f27d899SToby Isaac for (g = 0; g < subNodeIdxDim; g++) { 5383f27d899SToby Isaac ni->nodeIdx[f * nodeIdxDim + g] = facetni->nodeIdx[e * subNodeIdxDim + g]; 5393f27d899SToby Isaac } 5403f27d899SToby Isaac ni->nodeIdx[f * nodeIdxDim + subNodeIdxDim] = (1 - d); 5413f27d899SToby Isaac ni->nodeIdx[f * nodeIdxDim + subNodeIdxDim + 1] = d; 5423f27d899SToby Isaac } 5433f27d899SToby Isaac } 5443f27d899SToby Isaac ierr = PetscLagNodeIndicesComputeVertexOrder(dm, ni, PETSC_TRUE);CHKERRQ(ierr); 5453f27d899SToby Isaac *nodeIndices = ni; 5463f27d899SToby Isaac PetscFunctionReturn(0); 5473f27d899SToby Isaac } 5483f27d899SToby Isaac 54977f1a120SToby Isaac /* This helps us compute symmetries, and it also helps us compute coordinates for dofs that are being pushed 55077f1a120SToby Isaac * forward from a boundary mesh point. 55177f1a120SToby Isaac * 55277f1a120SToby Isaac * Input: 55377f1a120SToby Isaac * 55477f1a120SToby Isaac * dm - the target reference cell where we want new coordinates and dof directions to be valid 55577f1a120SToby Isaac * vert - the vertex coordinate system for the target reference cell 55677f1a120SToby Isaac * p - the point in the target reference cell that the dofs are coming from 55777f1a120SToby Isaac * vertp - the vertex coordinate system for p's reference cell 55877f1a120SToby Isaac * ornt - the resulting coordinates and dof vectors will be for p under this orientation 55977f1a120SToby Isaac * nodep - the node coordinates and dof vectors in p's reference cell 56077f1a120SToby Isaac * formDegree - the form degree that the dofs transform as 56177f1a120SToby Isaac * 56277f1a120SToby Isaac * Output: 56377f1a120SToby Isaac * 56477f1a120SToby Isaac * pfNodeIdx - the node coordinates for p's dofs, in the dm reference cell, from the ornt perspective 56577f1a120SToby Isaac * pfNodeVec - the node dof vectors for p's dofs, in the dm reference cell, from the ornt perspective 56677f1a120SToby Isaac */ 5673f27d899SToby Isaac static PetscErrorCode PetscLagNodeIndicesPushForward(DM dm, PetscLagNodeIndices vert, PetscInt p, PetscLagNodeIndices vertp, PetscLagNodeIndices nodep, PetscInt ornt, PetscInt formDegree, PetscInt pfNodeIdx[], PetscReal pfNodeVec[]) 5683f27d899SToby Isaac { 5693f27d899SToby Isaac PetscInt *closureVerts; 5703f27d899SToby Isaac PetscInt closureSize = 0; 5713f27d899SToby Isaac PetscInt *closure = NULL; 5723f27d899SToby Isaac PetscInt dim, pdim, c, i, j, k, n, v, vStart, vEnd; 5733f27d899SToby Isaac PetscInt nSubVert = vertp->nNodes; 5743f27d899SToby Isaac PetscInt nodeIdxDim = vert->nodeIdxDim; 5753f27d899SToby Isaac PetscInt subNodeIdxDim = vertp->nodeIdxDim; 5763f27d899SToby Isaac PetscInt nNodes = nodep->nNodes; 5773f27d899SToby Isaac const PetscInt *vertIdx = vert->nodeIdx; 5783f27d899SToby Isaac const PetscInt *subVertIdx = vertp->nodeIdx; 5793f27d899SToby Isaac const PetscInt *nodeIdx = nodep->nodeIdx; 5803f27d899SToby Isaac const PetscReal *nodeVec = nodep->nodeVec; 5813f27d899SToby Isaac PetscReal *J, *Jstar; 5823f27d899SToby Isaac PetscReal detJ; 5833f27d899SToby Isaac PetscInt depth, pdepth, Nk, pNk; 5843f27d899SToby Isaac Vec coordVec; 5853f27d899SToby Isaac PetscScalar *newCoords = NULL; 5863f27d899SToby Isaac const PetscScalar *oldCoords = NULL; 5873f27d899SToby Isaac PetscErrorCode ierr; 5883f27d899SToby Isaac 5893f27d899SToby Isaac PetscFunctionBegin; 5903f27d899SToby Isaac ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5913f27d899SToby Isaac ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5923f27d899SToby Isaac ierr = DMGetCoordinatesLocal(dm, &coordVec);CHKERRQ(ierr); 5933f27d899SToby Isaac ierr = DMPlexGetPointDepth(dm, p, &pdepth);CHKERRQ(ierr); 5943f27d899SToby Isaac pdim = pdepth != depth ? pdepth != 0 ? pdepth : 0 : dim; 5953f27d899SToby Isaac ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 5963f27d899SToby Isaac ierr = DMGetWorkArray(dm, nSubVert, MPIU_INT, &closureVerts);CHKERRQ(ierr); 5973f27d899SToby Isaac ierr = DMPlexGetTransitiveClosure_Internal(dm, p, ornt, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5983f27d899SToby Isaac c = closureSize - nSubVert; 5993f27d899SToby Isaac /* we want which cell closure indices the closure of this point corresponds to */ 6003f27d899SToby Isaac for (v = 0; v < nSubVert; v++) closureVerts[v] = vert->perm[closure[2 * (c + v)] - vStart]; 6013f27d899SToby Isaac ierr = DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 6023f27d899SToby Isaac /* push forward indices */ 6033f27d899SToby Isaac for (i = 0; i < nodeIdxDim; i++) { /* for every component of the target index space */ 6043f27d899SToby Isaac /* check if this is a component that all vertices around this point have in common */ 6053f27d899SToby Isaac for (j = 1; j < nSubVert; j++) { 6063f27d899SToby Isaac if (vertIdx[closureVerts[j] * nodeIdxDim + i] != vertIdx[closureVerts[0] * nodeIdxDim + i]) break; 6073f27d899SToby Isaac } 6083f27d899SToby Isaac if (j == nSubVert) { /* all vertices have this component in common, directly copy to output */ 6093f27d899SToby Isaac PetscInt val = vertIdx[closureVerts[0] * nodeIdxDim + i]; 6103f27d899SToby Isaac for (n = 0; n < nNodes; n++) pfNodeIdx[n * nodeIdxDim + i] = val; 6113f27d899SToby Isaac } else { 6123f27d899SToby Isaac PetscInt subi = -1; 6133f27d899SToby Isaac /* there must be a component in vertp that looks the same */ 6143f27d899SToby Isaac for (k = 0; k < subNodeIdxDim; k++) { 6153f27d899SToby Isaac for (j = 0; j < nSubVert; j++) { 6163f27d899SToby Isaac if (vertIdx[closureVerts[j] * nodeIdxDim + i] != subVertIdx[j * subNodeIdxDim + k]) break; 6173f27d899SToby Isaac } 6183f27d899SToby Isaac if (j == nSubVert) { 6193f27d899SToby Isaac subi = k; 6203f27d899SToby Isaac break; 6213f27d899SToby Isaac } 6223f27d899SToby Isaac } 6233f27d899SToby Isaac if (subi < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not find matching coordinate\n"); 62477f1a120SToby Isaac /* that component in the vertp system becomes component i in the vert system for each dof */ 6253f27d899SToby Isaac for (n = 0; n < nNodes; n++) pfNodeIdx[n * nodeIdxDim + i] = nodeIdx[n * subNodeIdxDim + subi]; 6263f27d899SToby Isaac } 6273f27d899SToby Isaac } 6283f27d899SToby Isaac /* push forward vectors */ 6293f27d899SToby Isaac ierr = DMGetWorkArray(dm, dim * dim, MPIU_REAL, &J);CHKERRQ(ierr); 63077f1a120SToby Isaac if (ornt != 0) { /* temporarily change the coordinate vector so 63177f1a120SToby Isaac DMPlexComputeCellGeometryAffineFEM gives us the Jacobian we want */ 6323f27d899SToby Isaac PetscInt closureSize2 = 0; 6333f27d899SToby Isaac PetscInt *closure2 = NULL; 6343f27d899SToby Isaac 6353f27d899SToby Isaac ierr = DMPlexGetTransitiveClosure_Internal(dm, p, 0, PETSC_TRUE, &closureSize2, &closure2);CHKERRQ(ierr); 6363f27d899SToby Isaac ierr = PetscMalloc1(dim * nSubVert, &newCoords);CHKERRQ(ierr); 6373f27d899SToby Isaac ierr = VecGetArrayRead(coordVec, &oldCoords);CHKERRQ(ierr); 6383f27d899SToby Isaac for (v = 0; v < nSubVert; v++) { 6393f27d899SToby Isaac PetscInt d; 6403f27d899SToby Isaac for (d = 0; d < dim; d++) { 6413f27d899SToby Isaac newCoords[(closure2[2 * (c + v)] - vStart) * dim + d] = oldCoords[closureVerts[v] * dim + d]; 6423f27d899SToby Isaac } 6433f27d899SToby Isaac } 6443f27d899SToby Isaac ierr = VecRestoreArrayRead(coordVec, &oldCoords);CHKERRQ(ierr); 6453f27d899SToby Isaac ierr = DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize2, &closure2);CHKERRQ(ierr); 6463f27d899SToby Isaac ierr = VecPlaceArray(coordVec, newCoords);CHKERRQ(ierr); 6473f27d899SToby Isaac } 6483f27d899SToby Isaac ierr = DMPlexComputeCellGeometryAffineFEM(dm, p, NULL, J, NULL, &detJ);CHKERRQ(ierr); 6493f27d899SToby Isaac if (ornt != 0) { 6503f27d899SToby Isaac ierr = VecResetArray(coordVec);CHKERRQ(ierr); 6513f27d899SToby Isaac ierr = PetscFree(newCoords);CHKERRQ(ierr); 6523f27d899SToby Isaac } 6533f27d899SToby Isaac ierr = DMRestoreWorkArray(dm, nSubVert, MPIU_INT, &closureVerts);CHKERRQ(ierr); 6543f27d899SToby Isaac /* compactify */ 6553f27d899SToby Isaac for (i = 0; i < dim; i++) for (j = 0; j < pdim; j++) J[i * pdim + j] = J[i * dim + j]; 65677f1a120SToby Isaac /* We have the Jacobian mapping the point's reference cell to this reference cell: 65777f1a120SToby Isaac * pulling back a function to the point and applying the dof is what we want, 65877f1a120SToby Isaac * so we get the pullback matrix and multiply the dof by that matrix on the right */ 6593f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &Nk);CHKERRQ(ierr); 6603f27d899SToby Isaac ierr = PetscDTBinomialInt(pdim, PetscAbsInt(formDegree), &pNk);CHKERRQ(ierr); 6613f27d899SToby Isaac ierr = DMGetWorkArray(dm, pNk * Nk, MPIU_REAL, &Jstar);CHKERRQ(ierr); 6623f27d899SToby Isaac ierr = PetscDTAltVPullbackMatrix(pdim, dim, J, formDegree, Jstar);CHKERRQ(ierr); 6633f27d899SToby Isaac for (n = 0; n < nNodes; n++) { 6643f27d899SToby Isaac for (i = 0; i < Nk; i++) { 6653f27d899SToby Isaac PetscReal val = 0.; 6665efe5503SToby Isaac for (j = 0; j < pNk; j++) val += nodeVec[n * pNk + j] * Jstar[j * Nk + i]; 6673f27d899SToby Isaac pfNodeVec[n * Nk + i] = val; 6683f27d899SToby Isaac } 6693f27d899SToby Isaac } 6703f27d899SToby Isaac ierr = DMRestoreWorkArray(dm, pNk * Nk, MPIU_REAL, &Jstar);CHKERRQ(ierr); 6713f27d899SToby Isaac ierr = DMRestoreWorkArray(dm, dim * dim, MPIU_REAL, &J);CHKERRQ(ierr); 6723f27d899SToby Isaac PetscFunctionReturn(0); 6733f27d899SToby Isaac } 6743f27d899SToby Isaac 67577f1a120SToby Isaac /* given to sets of nodes, take the tensor product, where the product of the dof indices is concatenation and the 67677f1a120SToby Isaac * product of the dof vectors is the wedge product */ 6773f27d899SToby Isaac static PetscErrorCode PetscLagNodeIndicesTensor(PetscLagNodeIndices tracei, PetscInt dimT, PetscInt kT, PetscLagNodeIndices fiberi, PetscInt dimF, PetscInt kF, PetscLagNodeIndices *nodeIndices) 6783f27d899SToby Isaac { 6793f27d899SToby Isaac PetscInt dim = dimT + dimF; 6803f27d899SToby Isaac PetscInt nodeIdxDim, nNodes; 6813f27d899SToby Isaac PetscInt formDegree = kT + kF; 6823f27d899SToby Isaac PetscInt Nk, NkT, NkF; 6833f27d899SToby Isaac PetscInt MkT, MkF; 6843f27d899SToby Isaac PetscLagNodeIndices ni; 6853f27d899SToby Isaac PetscInt i, j, l; 6863f27d899SToby Isaac PetscReal *projF, *projT; 6873f27d899SToby Isaac PetscReal *projFstar, *projTstar; 6883f27d899SToby Isaac PetscReal *workF, *workF2, *workT, *workT2, *work, *work2; 6893f27d899SToby Isaac PetscReal *wedgeMat; 6903f27d899SToby Isaac PetscReal sign; 6913f27d899SToby Isaac PetscErrorCode ierr; 6923f27d899SToby Isaac 6933f27d899SToby Isaac PetscFunctionBegin; 6943f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &Nk);CHKERRQ(ierr); 6953f27d899SToby Isaac ierr = PetscDTBinomialInt(dimT, PetscAbsInt(kT), &NkT);CHKERRQ(ierr); 6963f27d899SToby Isaac ierr = PetscDTBinomialInt(dimF, PetscAbsInt(kF), &NkF);CHKERRQ(ierr); 6973f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(kT), &MkT);CHKERRQ(ierr); 6983f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(kF), &MkF);CHKERRQ(ierr); 6993f27d899SToby Isaac ierr = PetscNew(&ni);CHKERRQ(ierr); 7003f27d899SToby Isaac ni->nodeIdxDim = nodeIdxDim = tracei->nodeIdxDim + fiberi->nodeIdxDim; 7013f27d899SToby Isaac ni->nodeVecDim = Nk; 7023f27d899SToby Isaac ni->nNodes = nNodes = tracei->nNodes * fiberi->nNodes; 7033f27d899SToby Isaac ni->refct = 1; 7043f27d899SToby Isaac ierr = PetscMalloc1(nNodes * nodeIdxDim, &(ni->nodeIdx));CHKERRQ(ierr); 7053f27d899SToby Isaac /* first concatenate the indices */ 7063f27d899SToby Isaac for (l = 0, j = 0; j < fiberi->nNodes; j++) { 7073f27d899SToby Isaac for (i = 0; i < tracei->nNodes; i++, l++) { 7083f27d899SToby Isaac PetscInt m, n = 0; 7093f27d899SToby Isaac 7103f27d899SToby Isaac for (m = 0; m < tracei->nodeIdxDim; m++) ni->nodeIdx[l * nodeIdxDim + n++] = tracei->nodeIdx[i * tracei->nodeIdxDim + m]; 7113f27d899SToby Isaac for (m = 0; m < fiberi->nodeIdxDim; m++) ni->nodeIdx[l * nodeIdxDim + n++] = fiberi->nodeIdx[j * fiberi->nodeIdxDim + m]; 7123f27d899SToby Isaac } 7133f27d899SToby Isaac } 7143f27d899SToby Isaac 7153f27d899SToby Isaac /* now wedge together the push-forward vectors */ 7163f27d899SToby Isaac ierr = PetscMalloc1(nNodes * Nk, &(ni->nodeVec));CHKERRQ(ierr); 7173f27d899SToby Isaac ierr = PetscCalloc2(dimT*dim, &projT, dimF*dim, &projF);CHKERRQ(ierr); 7183f27d899SToby Isaac for (i = 0; i < dimT; i++) projT[i * (dim + 1)] = 1.; 7193f27d899SToby Isaac for (i = 0; i < dimF; i++) projF[i * (dim + dimT + 1) + dimT] = 1.; 7203f27d899SToby Isaac ierr = PetscMalloc2(MkT*NkT, &projTstar, MkF*NkF, &projFstar);CHKERRQ(ierr); 7213f27d899SToby Isaac ierr = PetscDTAltVPullbackMatrix(dim, dimT, projT, kT, projTstar);CHKERRQ(ierr); 7223f27d899SToby Isaac ierr = PetscDTAltVPullbackMatrix(dim, dimF, projF, kF, projFstar);CHKERRQ(ierr); 7233f27d899SToby Isaac ierr = PetscMalloc6(MkT, &workT, MkT, &workT2, MkF, &workF, MkF, &workF2, Nk, &work, Nk, &work2);CHKERRQ(ierr); 7243f27d899SToby Isaac ierr = PetscMalloc1(Nk * MkT, &wedgeMat);CHKERRQ(ierr); 7253f27d899SToby Isaac sign = (PetscAbsInt(kT * kF) & 1) ? -1. : 1.; 7263f27d899SToby Isaac for (l = 0, j = 0; j < fiberi->nNodes; j++) { 7273f27d899SToby Isaac PetscInt d, e; 7283f27d899SToby Isaac 7293f27d899SToby Isaac /* push forward fiber k-form */ 7303f27d899SToby Isaac for (d = 0; d < MkF; d++) { 7313f27d899SToby Isaac PetscReal val = 0.; 7323f27d899SToby Isaac for (e = 0; e < NkF; e++) val += projFstar[d * NkF + e] * fiberi->nodeVec[j * NkF + e]; 7333f27d899SToby Isaac workF[d] = val; 7343f27d899SToby Isaac } 7353f27d899SToby Isaac /* Hodge star to proper form if necessary */ 7363f27d899SToby Isaac if (kF < 0) { 7373f27d899SToby Isaac for (d = 0; d < MkF; d++) workF2[d] = workF[d]; 7383f27d899SToby Isaac ierr = PetscDTAltVStar(dim, PetscAbsInt(kF), 1, workF2, workF);CHKERRQ(ierr); 7393f27d899SToby Isaac } 7403f27d899SToby Isaac /* Compute the matrix that wedges this form with one of the trace k-form */ 7413f27d899SToby Isaac ierr = PetscDTAltVWedgeMatrix(dim, PetscAbsInt(kF), PetscAbsInt(kT), workF, wedgeMat);CHKERRQ(ierr); 7423f27d899SToby Isaac for (i = 0; i < tracei->nNodes; i++, l++) { 7433f27d899SToby Isaac /* push forward trace k-form */ 7443f27d899SToby Isaac for (d = 0; d < MkT; d++) { 7453f27d899SToby Isaac PetscReal val = 0.; 7463f27d899SToby Isaac for (e = 0; e < NkT; e++) val += projTstar[d * NkT + e] * tracei->nodeVec[i * NkT + e]; 7473f27d899SToby Isaac workT[d] = val; 7483f27d899SToby Isaac } 7493f27d899SToby Isaac /* Hodge star to proper form if necessary */ 7503f27d899SToby Isaac if (kT < 0) { 7513f27d899SToby Isaac for (d = 0; d < MkT; d++) workT2[d] = workT[d]; 7523f27d899SToby Isaac ierr = PetscDTAltVStar(dim, PetscAbsInt(kT), 1, workT2, workT);CHKERRQ(ierr); 7533f27d899SToby Isaac } 7543f27d899SToby Isaac /* compute the wedge product of the push-forward trace form and firer forms */ 7553f27d899SToby Isaac for (d = 0; d < Nk; d++) { 7563f27d899SToby Isaac PetscReal val = 0.; 7573f27d899SToby Isaac for (e = 0; e < MkT; e++) val += wedgeMat[d * MkT + e] * workT[e]; 7583f27d899SToby Isaac work[d] = val; 7593f27d899SToby Isaac } 7603f27d899SToby Isaac /* inverse Hodge star from proper form if necessary */ 7613f27d899SToby Isaac if (formDegree < 0) { 7623f27d899SToby Isaac for (d = 0; d < Nk; d++) work2[d] = work[d]; 7633f27d899SToby Isaac ierr = PetscDTAltVStar(dim, PetscAbsInt(formDegree), -1, work2, work);CHKERRQ(ierr); 7643f27d899SToby Isaac } 7653f27d899SToby Isaac /* insert into the array (adjusting for sign) */ 7663f27d899SToby Isaac for (d = 0; d < Nk; d++) ni->nodeVec[l * Nk + d] = sign * work[d]; 7673f27d899SToby Isaac } 7683f27d899SToby Isaac } 7693f27d899SToby Isaac ierr = PetscFree(wedgeMat);CHKERRQ(ierr); 7703f27d899SToby Isaac ierr = PetscFree6(workT, workT2, workF, workF2, work, work2);CHKERRQ(ierr); 7713f27d899SToby Isaac ierr = PetscFree2(projTstar, projFstar);CHKERRQ(ierr); 7723f27d899SToby Isaac ierr = PetscFree2(projT, projF);CHKERRQ(ierr); 7733f27d899SToby Isaac *nodeIndices = ni; 7743f27d899SToby Isaac PetscFunctionReturn(0); 7753f27d899SToby Isaac } 7763f27d899SToby Isaac 77777f1a120SToby Isaac /* simple union of two sets of nodes */ 7783f27d899SToby Isaac static PetscErrorCode PetscLagNodeIndicesMerge(PetscLagNodeIndices niA, PetscLagNodeIndices niB, PetscLagNodeIndices *nodeIndices) 7793f27d899SToby Isaac { 7803f27d899SToby Isaac PetscLagNodeIndices ni; 7813f27d899SToby Isaac PetscInt nodeIdxDim, nodeVecDim, nNodes; 7823f27d899SToby Isaac PetscErrorCode ierr; 7833f27d899SToby Isaac 7843f27d899SToby Isaac PetscFunctionBegin; 7853f27d899SToby Isaac ierr = PetscNew(&ni);CHKERRQ(ierr); 7863f27d899SToby Isaac ni->nodeIdxDim = nodeIdxDim = niA->nodeIdxDim; 7873f27d899SToby Isaac if (niB->nodeIdxDim != nodeIdxDim) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cannot merge PetscLagNodeIndices with different nodeIdxDim"); 7883f27d899SToby Isaac ni->nodeVecDim = nodeVecDim = niA->nodeVecDim; 7893f27d899SToby Isaac if (niB->nodeVecDim != nodeVecDim) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cannot merge PetscLagNodeIndices with different nodeVecDim"); 7903f27d899SToby Isaac ni->nNodes = nNodes = niA->nNodes + niB->nNodes; 7913f27d899SToby Isaac ni->refct = 1; 7923f27d899SToby Isaac ierr = PetscMalloc1(nNodes * nodeIdxDim, &(ni->nodeIdx));CHKERRQ(ierr); 7933f27d899SToby Isaac ierr = PetscMalloc1(nNodes * nodeVecDim, &(ni->nodeVec));CHKERRQ(ierr); 7943f27d899SToby Isaac ierr = PetscArraycpy(ni->nodeIdx, niA->nodeIdx, niA->nNodes * nodeIdxDim);CHKERRQ(ierr); 7953f27d899SToby Isaac ierr = PetscArraycpy(ni->nodeVec, niA->nodeVec, niA->nNodes * nodeVecDim);CHKERRQ(ierr); 7963f27d899SToby Isaac ierr = PetscArraycpy(&(ni->nodeIdx[niA->nNodes * nodeIdxDim]), niB->nodeIdx, niB->nNodes * nodeIdxDim);CHKERRQ(ierr); 7973f27d899SToby Isaac ierr = PetscArraycpy(&(ni->nodeVec[niA->nNodes * nodeVecDim]), niB->nodeVec, niB->nNodes * nodeVecDim);CHKERRQ(ierr); 7983f27d899SToby Isaac *nodeIndices = ni; 7993f27d899SToby Isaac PetscFunctionReturn(0); 8003f27d899SToby Isaac } 8013f27d899SToby Isaac 8023f27d899SToby Isaac #define PETSCTUPINTCOMPREVLEX(N) \ 8033f27d899SToby Isaac static int PetscTupIntCompRevlex_##N(const void *a, const void *b) \ 8043f27d899SToby Isaac { \ 8053f27d899SToby Isaac const PetscInt *A = (const PetscInt *) a; \ 8063f27d899SToby Isaac const PetscInt *B = (const PetscInt *) b; \ 8073f27d899SToby Isaac int i; \ 8083f27d899SToby Isaac PetscInt diff = 0; \ 8093f27d899SToby Isaac for (i = 0; i < N; i++) { \ 8103f27d899SToby Isaac diff = A[N - i] - B[N - i]; \ 8113f27d899SToby Isaac if (diff) break; \ 8123f27d899SToby Isaac } \ 8133f27d899SToby Isaac return (diff <= 0) ? (diff < 0) ? -1 : 0 : 1; \ 8143f27d899SToby Isaac } 8153f27d899SToby Isaac 8163f27d899SToby Isaac PETSCTUPINTCOMPREVLEX(3) 8173f27d899SToby Isaac PETSCTUPINTCOMPREVLEX(4) 8183f27d899SToby Isaac PETSCTUPINTCOMPREVLEX(5) 8193f27d899SToby Isaac PETSCTUPINTCOMPREVLEX(6) 8203f27d899SToby Isaac PETSCTUPINTCOMPREVLEX(7) 8213f27d899SToby Isaac 8223f27d899SToby Isaac static int PetscTupIntCompRevlex_N(const void *a, const void *b) 8233f27d899SToby Isaac { 8243f27d899SToby Isaac const PetscInt *A = (const PetscInt *) a; 8253f27d899SToby Isaac const PetscInt *B = (const PetscInt *) b; 8263f27d899SToby Isaac int i; 8273f27d899SToby Isaac int N = A[0]; 8283f27d899SToby Isaac PetscInt diff = 0; 8293f27d899SToby Isaac for (i = 0; i < N; i++) { 8303f27d899SToby Isaac diff = A[N - i] - B[N - i]; 8313f27d899SToby Isaac if (diff) break; 8323f27d899SToby Isaac } 8333f27d899SToby Isaac return (diff <= 0) ? (diff < 0) ? -1 : 0 : 1; 8343f27d899SToby Isaac } 8353f27d899SToby Isaac 83677f1a120SToby Isaac /* The nodes are not necessarily in revlex order wrt nodeIdx: get the permutation 83777f1a120SToby Isaac * that puts them in that order */ 8383f27d899SToby Isaac static PetscErrorCode PetscLagNodeIndicesGetPermutation(PetscLagNodeIndices ni, PetscInt *perm[]) 8393f27d899SToby Isaac { 8403f27d899SToby Isaac PetscErrorCode ierr; 8413f27d899SToby Isaac 8423f27d899SToby Isaac PetscFunctionBegin; 8433f27d899SToby Isaac if (!(ni->perm)) { 8443f27d899SToby Isaac PetscInt *sorter; 8453f27d899SToby Isaac PetscInt m = ni->nNodes; 8463f27d899SToby Isaac PetscInt nodeIdxDim = ni->nodeIdxDim; 8473f27d899SToby Isaac PetscInt i, j, k, l; 8483f27d899SToby Isaac PetscInt *prm; 8493f27d899SToby Isaac int (*comp) (const void *, const void *); 8503f27d899SToby Isaac 8513f27d899SToby Isaac ierr = PetscMalloc1((nodeIdxDim + 2) * m, &sorter);CHKERRQ(ierr); 8523f27d899SToby Isaac for (k = 0, l = 0, i = 0; i < m; i++) { 8533f27d899SToby Isaac sorter[k++] = nodeIdxDim + 1; 8543f27d899SToby Isaac sorter[k++] = i; 8553f27d899SToby Isaac for (j = 0; j < nodeIdxDim; j++) sorter[k++] = ni->nodeIdx[l++]; 8563f27d899SToby Isaac } 8573f27d899SToby Isaac switch (nodeIdxDim) { 8583f27d899SToby Isaac case 2: 8593f27d899SToby Isaac comp = PetscTupIntCompRevlex_3; 8603f27d899SToby Isaac break; 8613f27d899SToby Isaac case 3: 8623f27d899SToby Isaac comp = PetscTupIntCompRevlex_4; 8633f27d899SToby Isaac break; 8643f27d899SToby Isaac case 4: 8653f27d899SToby Isaac comp = PetscTupIntCompRevlex_5; 8663f27d899SToby Isaac break; 8673f27d899SToby Isaac case 5: 8683f27d899SToby Isaac comp = PetscTupIntCompRevlex_6; 8693f27d899SToby Isaac break; 8703f27d899SToby Isaac case 6: 8713f27d899SToby Isaac comp = PetscTupIntCompRevlex_7; 8723f27d899SToby Isaac break; 8733f27d899SToby Isaac default: 8743f27d899SToby Isaac comp = PetscTupIntCompRevlex_N; 8753f27d899SToby Isaac break; 8763f27d899SToby Isaac } 8773f27d899SToby Isaac qsort(sorter, m, (nodeIdxDim + 2) * sizeof(PetscInt), comp); 8783f27d899SToby Isaac ierr = PetscMalloc1(m, &prm);CHKERRQ(ierr); 8793f27d899SToby Isaac for (i = 0; i < m; i++) prm[i] = sorter[(nodeIdxDim + 2) * i + 1]; 8803f27d899SToby Isaac ni->perm = prm; 881*1e1ea65dSPierre Jolivet ierr = PetscFree(sorter);CHKERRQ(ierr); 8823f27d899SToby Isaac } 8833f27d899SToby Isaac *perm = ni->perm; 8843f27d899SToby Isaac PetscFunctionReturn(0); 8853f27d899SToby Isaac } 88620cf1dd8SToby Isaac 8876f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceDestroy_Lagrange(PetscDualSpace sp) 88820cf1dd8SToby Isaac { 88920cf1dd8SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 8906f905325SMatthew G. Knepley PetscErrorCode ierr; 89120cf1dd8SToby Isaac 89220cf1dd8SToby Isaac PetscFunctionBegin; 8933f27d899SToby Isaac if (lag->symperms) { 8943f27d899SToby Isaac PetscInt **selfSyms = lag->symperms[0]; 8956f905325SMatthew G. Knepley 8966f905325SMatthew G. Knepley if (selfSyms) { 8976f905325SMatthew G. Knepley PetscInt i, **allocated = &selfSyms[-lag->selfSymOff]; 8986f905325SMatthew G. Knepley 8996f905325SMatthew G. Knepley for (i = 0; i < lag->numSelfSym; i++) { 9006f905325SMatthew G. Knepley ierr = PetscFree(allocated[i]);CHKERRQ(ierr); 9016f905325SMatthew G. Knepley } 9026f905325SMatthew G. Knepley ierr = PetscFree(allocated);CHKERRQ(ierr); 9036f905325SMatthew G. Knepley } 9043f27d899SToby Isaac ierr = PetscFree(lag->symperms);CHKERRQ(ierr); 9056f905325SMatthew G. Knepley } 9063f27d899SToby Isaac if (lag->symflips) { 9073f27d899SToby Isaac PetscScalar **selfSyms = lag->symflips[0]; 9083f27d899SToby Isaac 9093f27d899SToby Isaac if (selfSyms) { 9103f27d899SToby Isaac PetscInt i; 9113f27d899SToby Isaac PetscScalar **allocated = &selfSyms[-lag->selfSymOff]; 9123f27d899SToby Isaac 9133f27d899SToby Isaac for (i = 0; i < lag->numSelfSym; i++) { 9143f27d899SToby Isaac ierr = PetscFree(allocated[i]);CHKERRQ(ierr); 9156f905325SMatthew G. Knepley } 9163f27d899SToby Isaac ierr = PetscFree(allocated);CHKERRQ(ierr); 9173f27d899SToby Isaac } 9183f27d899SToby Isaac ierr = PetscFree(lag->symflips);CHKERRQ(ierr); 9193f27d899SToby Isaac } 9203f27d899SToby Isaac ierr = Petsc1DNodeFamilyDestroy(&(lag->nodeFamily));CHKERRQ(ierr); 9213f27d899SToby Isaac ierr = PetscLagNodeIndicesDestroy(&(lag->vertIndices));CHKERRQ(ierr); 9223f27d899SToby Isaac ierr = PetscLagNodeIndicesDestroy(&(lag->intNodeIndices));CHKERRQ(ierr); 9233f27d899SToby Isaac ierr = PetscLagNodeIndicesDestroy(&(lag->allNodeIndices));CHKERRQ(ierr); 9246f905325SMatthew G. Knepley ierr = PetscFree(lag);CHKERRQ(ierr); 9256f905325SMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetContinuity_C", NULL);CHKERRQ(ierr); 9266f905325SMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetContinuity_C", NULL);CHKERRQ(ierr); 9276f905325SMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetTensor_C", NULL);CHKERRQ(ierr); 9286f905325SMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetTensor_C", NULL);CHKERRQ(ierr); 9293f27d899SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetTrimmed_C", NULL);CHKERRQ(ierr); 9303f27d899SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetTrimmed_C", NULL);CHKERRQ(ierr); 9313f27d899SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetNodeType_C", NULL);CHKERRQ(ierr); 9323f27d899SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetNodeType_C", NULL);CHKERRQ(ierr); 93366a6c23cSMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetUseMoments_C", NULL);CHKERRQ(ierr); 93466a6c23cSMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetUseMoments_C", NULL);CHKERRQ(ierr); 93566a6c23cSMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetMomentOrder_C", NULL);CHKERRQ(ierr); 93666a6c23cSMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetMomentOrder_C", NULL);CHKERRQ(ierr); 93720cf1dd8SToby Isaac PetscFunctionReturn(0); 93820cf1dd8SToby Isaac } 93920cf1dd8SToby Isaac 9406f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeView_Ascii(PetscDualSpace sp, PetscViewer viewer) 94120cf1dd8SToby Isaac { 94220cf1dd8SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 9436f905325SMatthew G. Knepley PetscErrorCode ierr; 94420cf1dd8SToby Isaac 94520cf1dd8SToby Isaac PetscFunctionBegin; 9463f27d899SToby Isaac ierr = PetscViewerASCIIPrintf(viewer, "%s %s%sLagrange dual space\n", lag->continuous ? "Continuous" : "Discontinuous", lag->tensorSpace ? "tensor " : "", lag->trimmed ? "trimmed " : "");CHKERRQ(ierr); 94720cf1dd8SToby Isaac PetscFunctionReturn(0); 94820cf1dd8SToby Isaac } 94920cf1dd8SToby Isaac 9506f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceView_Lagrange(PetscDualSpace sp, PetscViewer viewer) 95120cf1dd8SToby Isaac { 9526f905325SMatthew G. Knepley PetscBool iascii; 9536f905325SMatthew G. Knepley PetscErrorCode ierr; 9546f905325SMatthew G. Knepley 95520cf1dd8SToby Isaac PetscFunctionBegin; 9566f905325SMatthew G. Knepley PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 9576f905325SMatthew G. Knepley PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 9586f905325SMatthew G. Knepley ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 9596f905325SMatthew G. Knepley if (iascii) {ierr = PetscDualSpaceLagrangeView_Ascii(sp, viewer);CHKERRQ(ierr);} 96020cf1dd8SToby Isaac PetscFunctionReturn(0); 96120cf1dd8SToby Isaac } 96220cf1dd8SToby Isaac 9636f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceSetFromOptions_Lagrange(PetscOptionItems *PetscOptionsObject,PetscDualSpace sp) 96420cf1dd8SToby Isaac { 9653f27d899SToby Isaac PetscBool continuous, tensor, trimmed, flg, flg2, flg3; 9663f27d899SToby Isaac PetscDTNodeType nodeType; 9673f27d899SToby Isaac PetscReal nodeExponent; 96866a6c23cSMatthew G. Knepley PetscInt momentOrder; 96966a6c23cSMatthew G. Knepley PetscBool nodeEndpoints, useMoments; 9706f905325SMatthew G. Knepley PetscErrorCode ierr; 9716f905325SMatthew G. Knepley 9726f905325SMatthew G. Knepley PetscFunctionBegin; 9736f905325SMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetContinuity(sp, &continuous);CHKERRQ(ierr); 9746f905325SMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetTensor(sp, &tensor);CHKERRQ(ierr); 9753f27d899SToby Isaac ierr = PetscDualSpaceLagrangeGetTrimmed(sp, &trimmed);CHKERRQ(ierr); 9763f27d899SToby Isaac ierr = PetscDualSpaceLagrangeGetNodeType(sp, &nodeType, &nodeEndpoints, &nodeExponent);CHKERRQ(ierr); 9773f27d899SToby Isaac if (nodeType == PETSCDTNODES_DEFAULT) nodeType = PETSCDTNODES_GAUSSJACOBI; 97866a6c23cSMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetUseMoments(sp, &useMoments);CHKERRQ(ierr); 97966a6c23cSMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetMomentOrder(sp, &momentOrder);CHKERRQ(ierr); 9806f905325SMatthew G. Knepley ierr = PetscOptionsHead(PetscOptionsObject,"PetscDualSpace Lagrange Options");CHKERRQ(ierr); 9816f905325SMatthew G. Knepley ierr = PetscOptionsBool("-petscdualspace_lagrange_continuity", "Flag for continuous element", "PetscDualSpaceLagrangeSetContinuity", continuous, &continuous, &flg);CHKERRQ(ierr); 9826f905325SMatthew G. Knepley if (flg) {ierr = PetscDualSpaceLagrangeSetContinuity(sp, continuous);CHKERRQ(ierr);} 9833f27d899SToby Isaac ierr = PetscOptionsBool("-petscdualspace_lagrange_tensor", "Flag for tensor dual space", "PetscDualSpaceLagrangeSetTensor", tensor, &tensor, &flg);CHKERRQ(ierr); 9846f905325SMatthew G. Knepley if (flg) {ierr = PetscDualSpaceLagrangeSetTensor(sp, tensor);CHKERRQ(ierr);} 9853f27d899SToby Isaac ierr = PetscOptionsBool("-petscdualspace_lagrange_trimmed", "Flag for trimmed dual space", "PetscDualSpaceLagrangeSetTrimmed", trimmed, &trimmed, &flg);CHKERRQ(ierr); 9863f27d899SToby Isaac if (flg) {ierr = PetscDualSpaceLagrangeSetTrimmed(sp, trimmed);CHKERRQ(ierr);} 9873f27d899SToby Isaac ierr = PetscOptionsEnum("-petscdualspace_lagrange_node_type", "Lagrange node location type", "PetscDualSpaceLagrangeSetNodeType", PetscDTNodeTypes, (PetscEnum)nodeType, (PetscEnum *)&nodeType, &flg);CHKERRQ(ierr); 9883f27d899SToby Isaac ierr = PetscOptionsBool("-petscdualspace_lagrange_node_endpoints", "Flag for nodes that include endpoints", "PetscDualSpaceLagrangeSetNodeType", nodeEndpoints, &nodeEndpoints, &flg2);CHKERRQ(ierr); 9893f27d899SToby Isaac flg3 = PETSC_FALSE; 9903f27d899SToby Isaac if (nodeType == PETSCDTNODES_GAUSSJACOBI) { 9913f27d899SToby Isaac ierr = PetscOptionsReal("-petscdualspace_lagrange_node_exponent", "Gauss-Jacobi weight function exponent", "PetscDualSpaceLagrangeSetNodeType", nodeExponent, &nodeExponent, &flg3);CHKERRQ(ierr); 9923f27d899SToby Isaac } 9933f27d899SToby Isaac if (flg || flg2 || flg3) {ierr = PetscDualSpaceLagrangeSetNodeType(sp, nodeType, nodeEndpoints, nodeExponent);CHKERRQ(ierr);} 99466a6c23cSMatthew G. Knepley ierr = PetscOptionsBool("-petscdualspace_lagrange_use_moments", "Use moments (where appropriate) for functionals", "PetscDualSpaceLagrangeSetUseMoments", useMoments, &useMoments, &flg);CHKERRQ(ierr); 99566a6c23cSMatthew G. Knepley if (flg) {ierr = PetscDualSpaceLagrangeSetUseMoments(sp, useMoments);CHKERRQ(ierr);} 99666a6c23cSMatthew G. Knepley ierr = PetscOptionsInt("-petscdualspace_lagrange_moment_order", "Quadrature order for moment functionals", "PetscDualSpaceLagrangeSetMomentOrder", momentOrder, &momentOrder, &flg);CHKERRQ(ierr); 99766a6c23cSMatthew G. Knepley if (flg) {ierr = PetscDualSpaceLagrangeSetMomentOrder(sp, momentOrder);CHKERRQ(ierr);} 9986f905325SMatthew G. Knepley ierr = PetscOptionsTail();CHKERRQ(ierr); 9996f905325SMatthew G. Knepley PetscFunctionReturn(0); 10006f905325SMatthew G. Knepley } 10016f905325SMatthew G. Knepley 1002b4457527SToby Isaac static PetscErrorCode PetscDualSpaceDuplicate_Lagrange(PetscDualSpace sp, PetscDualSpace spNew) 10036f905325SMatthew G. Knepley { 10043f27d899SToby Isaac PetscBool cont, tensor, trimmed, boundary; 10053f27d899SToby Isaac PetscDTNodeType nodeType; 10063f27d899SToby Isaac PetscReal exponent; 10073f27d899SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 10086f905325SMatthew G. Knepley PetscErrorCode ierr; 10096f905325SMatthew G. Knepley 10106f905325SMatthew G. Knepley PetscFunctionBegin; 10116f905325SMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetContinuity(sp, &cont);CHKERRQ(ierr); 1012b4457527SToby Isaac ierr = PetscDualSpaceLagrangeSetContinuity(spNew, cont);CHKERRQ(ierr); 10136f905325SMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetTensor(sp, &tensor);CHKERRQ(ierr); 1014b4457527SToby Isaac ierr = PetscDualSpaceLagrangeSetTensor(spNew, tensor);CHKERRQ(ierr); 10153f27d899SToby Isaac ierr = PetscDualSpaceLagrangeGetTrimmed(sp, &trimmed);CHKERRQ(ierr); 10163f27d899SToby Isaac ierr = PetscDualSpaceLagrangeSetTrimmed(spNew, trimmed);CHKERRQ(ierr); 10173f27d899SToby Isaac ierr = PetscDualSpaceLagrangeGetNodeType(sp, &nodeType, &boundary, &exponent);CHKERRQ(ierr); 10183f27d899SToby Isaac ierr = PetscDualSpaceLagrangeSetNodeType(spNew, nodeType, boundary, exponent);CHKERRQ(ierr); 10193f27d899SToby Isaac if (lag->nodeFamily) { 10203f27d899SToby Isaac PetscDualSpace_Lag *lagnew = (PetscDualSpace_Lag *) spNew->data; 10213f27d899SToby Isaac 10223f27d899SToby Isaac ierr = Petsc1DNodeFamilyReference(lag->nodeFamily);CHKERRQ(ierr); 10233f27d899SToby Isaac lagnew->nodeFamily = lag->nodeFamily; 10243f27d899SToby Isaac } 10256f905325SMatthew G. Knepley PetscFunctionReturn(0); 10266f905325SMatthew G. Knepley } 10276f905325SMatthew G. Knepley 102877f1a120SToby Isaac /* for making tensor product spaces: take a dual space and product a segment space that has all the same 102977f1a120SToby Isaac * specifications (trimmed, continuous, order, node set), except for the form degree */ 10303f27d899SToby Isaac static PetscErrorCode PetscDualSpaceCreateEdgeSubspace_Lagrange(PetscDualSpace sp, PetscInt order, PetscInt k, PetscInt Nc, PetscBool interiorOnly, PetscDualSpace *bdsp) 10316f905325SMatthew G. Knepley { 10323f27d899SToby Isaac DM K; 10333f27d899SToby Isaac PetscDualSpace_Lag *newlag; 10346f905325SMatthew G. Knepley PetscErrorCode ierr; 10356f905325SMatthew G. Knepley 10366f905325SMatthew G. Knepley PetscFunctionBegin; 10376f905325SMatthew G. Knepley ierr = PetscDualSpaceDuplicate(sp,bdsp);CHKERRQ(ierr); 10383f27d899SToby Isaac ierr = PetscDualSpaceSetFormDegree(*bdsp, k);CHKERRQ(ierr); 10393f27d899SToby Isaac ierr = PetscDualSpaceCreateReferenceCell(*bdsp, 1, PETSC_TRUE, &K);CHKERRQ(ierr); 10406f905325SMatthew G. Knepley ierr = PetscDualSpaceSetDM(*bdsp, K);CHKERRQ(ierr); 10416f905325SMatthew G. Knepley ierr = DMDestroy(&K);CHKERRQ(ierr); 10423f27d899SToby Isaac ierr = PetscDualSpaceSetOrder(*bdsp, order);CHKERRQ(ierr); 10433f27d899SToby Isaac ierr = PetscDualSpaceSetNumComponents(*bdsp, Nc);CHKERRQ(ierr); 10443f27d899SToby Isaac newlag = (PetscDualSpace_Lag *) (*bdsp)->data; 10453f27d899SToby Isaac newlag->interiorOnly = interiorOnly; 10466f905325SMatthew G. Knepley ierr = PetscDualSpaceSetUp(*bdsp);CHKERRQ(ierr); 10473f27d899SToby Isaac PetscFunctionReturn(0); 10486f905325SMatthew G. Knepley } 10493f27d899SToby Isaac 10503f27d899SToby Isaac /* just the points, weights aren't handled */ 10513f27d899SToby Isaac static PetscErrorCode PetscQuadratureCreateTensor(PetscQuadrature trace, PetscQuadrature fiber, PetscQuadrature *product) 10523f27d899SToby Isaac { 10533f27d899SToby Isaac PetscInt dimTrace, dimFiber; 10543f27d899SToby Isaac PetscInt numPointsTrace, numPointsFiber; 10553f27d899SToby Isaac PetscInt dim, numPoints; 10563f27d899SToby Isaac const PetscReal *pointsTrace; 10573f27d899SToby Isaac const PetscReal *pointsFiber; 10583f27d899SToby Isaac PetscReal *points; 10593f27d899SToby Isaac PetscInt i, j, k, p; 10603f27d899SToby Isaac PetscErrorCode ierr; 10613f27d899SToby Isaac 10623f27d899SToby Isaac PetscFunctionBegin; 10633f27d899SToby Isaac ierr = PetscQuadratureGetData(trace, &dimTrace, NULL, &numPointsTrace, &pointsTrace, NULL);CHKERRQ(ierr); 10643f27d899SToby Isaac ierr = PetscQuadratureGetData(fiber, &dimFiber, NULL, &numPointsFiber, &pointsFiber, NULL);CHKERRQ(ierr); 10653f27d899SToby Isaac dim = dimTrace + dimFiber; 10663f27d899SToby Isaac numPoints = numPointsFiber * numPointsTrace; 10673f27d899SToby Isaac ierr = PetscMalloc1(numPoints * dim, &points);CHKERRQ(ierr); 10683f27d899SToby Isaac for (p = 0, j = 0; j < numPointsFiber; j++) { 10693f27d899SToby Isaac for (i = 0; i < numPointsTrace; i++, p++) { 10703f27d899SToby Isaac for (k = 0; k < dimTrace; k++) points[p * dim + k] = pointsTrace[i * dimTrace + k]; 10713f27d899SToby Isaac for (k = 0; k < dimFiber; k++) points[p * dim + dimTrace + k] = pointsFiber[j * dimFiber + k]; 10723f27d899SToby Isaac } 10733f27d899SToby Isaac } 10743f27d899SToby Isaac ierr = PetscQuadratureCreate(PETSC_COMM_SELF, product);CHKERRQ(ierr); 10753f27d899SToby Isaac ierr = PetscQuadratureSetData(*product, dim, 0, numPoints, points, NULL);CHKERRQ(ierr); 10763f27d899SToby Isaac PetscFunctionReturn(0); 10773f27d899SToby Isaac } 10783f27d899SToby Isaac 107977f1a120SToby Isaac /* Kronecker tensor product where matrix is considered a matrix of k-forms, so that 108077f1a120SToby Isaac * the entries in the product matrix are wedge products of the entries in the original matrices */ 10813f27d899SToby Isaac static PetscErrorCode MatTensorAltV(Mat trace, Mat fiber, PetscInt dimTrace, PetscInt kTrace, PetscInt dimFiber, PetscInt kFiber, Mat *product) 10823f27d899SToby Isaac { 10833f27d899SToby Isaac PetscInt mTrace, nTrace, mFiber, nFiber, m, n, k, i, j, l; 10843f27d899SToby Isaac PetscInt dim, NkTrace, NkFiber, Nk; 10853f27d899SToby Isaac PetscInt dT, dF; 10863f27d899SToby Isaac PetscInt *nnzTrace, *nnzFiber, *nnz; 10873f27d899SToby Isaac PetscInt iT, iF, jT, jF, il, jl; 10883f27d899SToby Isaac PetscReal *workT, *workT2, *workF, *workF2, *work, *workstar; 10893f27d899SToby Isaac PetscReal *projT, *projF; 10903f27d899SToby Isaac PetscReal *projTstar, *projFstar; 10913f27d899SToby Isaac PetscReal *wedgeMat; 10923f27d899SToby Isaac PetscReal sign; 10933f27d899SToby Isaac PetscScalar *workS; 10943f27d899SToby Isaac Mat prod; 10953f27d899SToby Isaac /* this produces dof groups that look like the identity */ 10963f27d899SToby Isaac PetscErrorCode ierr; 10973f27d899SToby Isaac 10983f27d899SToby Isaac PetscFunctionBegin; 10993f27d899SToby Isaac ierr = MatGetSize(trace, &mTrace, &nTrace);CHKERRQ(ierr); 11003f27d899SToby Isaac ierr = PetscDTBinomialInt(dimTrace, PetscAbsInt(kTrace), &NkTrace);CHKERRQ(ierr); 11013f27d899SToby Isaac if (nTrace % NkTrace) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point value space of trace matrix is not a multiple of k-form size"); 11023f27d899SToby Isaac ierr = MatGetSize(fiber, &mFiber, &nFiber);CHKERRQ(ierr); 11033f27d899SToby Isaac ierr = PetscDTBinomialInt(dimFiber, PetscAbsInt(kFiber), &NkFiber);CHKERRQ(ierr); 11043f27d899SToby Isaac if (nFiber % NkFiber) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point value space of fiber matrix is not a multiple of k-form size"); 11053f27d899SToby Isaac ierr = PetscMalloc2(mTrace, &nnzTrace, mFiber, &nnzFiber);CHKERRQ(ierr); 11063f27d899SToby Isaac for (i = 0; i < mTrace; i++) { 11073f27d899SToby Isaac ierr = MatGetRow(trace, i, &(nnzTrace[i]), NULL, NULL);CHKERRQ(ierr); 11083f27d899SToby Isaac if (nnzTrace[i] % NkTrace) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "nonzeros in trace matrix are not in k-form size blocks"); 11093f27d899SToby Isaac } 11103f27d899SToby Isaac for (i = 0; i < mFiber; i++) { 11113f27d899SToby Isaac ierr = MatGetRow(fiber, i, &(nnzFiber[i]), NULL, NULL);CHKERRQ(ierr); 11123f27d899SToby Isaac if (nnzFiber[i] % NkFiber) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "nonzeros in fiber matrix are not in k-form size blocks"); 11133f27d899SToby Isaac } 11143f27d899SToby Isaac dim = dimTrace + dimFiber; 11153f27d899SToby Isaac k = kFiber + kTrace; 11163f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 11173f27d899SToby Isaac m = mTrace * mFiber; 11183f27d899SToby Isaac ierr = PetscMalloc1(m, &nnz);CHKERRQ(ierr); 11193f27d899SToby Isaac for (l = 0, j = 0; j < mFiber; j++) for (i = 0; i < mTrace; i++, l++) nnz[l] = (nnzTrace[i] / NkTrace) * (nnzFiber[j] / NkFiber) * Nk; 11203f27d899SToby Isaac n = (nTrace / NkTrace) * (nFiber / NkFiber) * Nk; 11213f27d899SToby Isaac ierr = MatCreateSeqAIJ(PETSC_COMM_SELF, m, n, 0, nnz, &prod);CHKERRQ(ierr); 11223f27d899SToby Isaac ierr = PetscFree(nnz);CHKERRQ(ierr); 11233f27d899SToby Isaac ierr = PetscFree2(nnzTrace,nnzFiber);CHKERRQ(ierr); 11243f27d899SToby Isaac /* reasoning about which points each dof needs depends on having zeros computed at points preserved */ 11253f27d899SToby Isaac ierr = MatSetOption(prod, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);CHKERRQ(ierr); 11263f27d899SToby Isaac /* compute pullbacks */ 11273f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(kTrace), &dT);CHKERRQ(ierr); 11283f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(kFiber), &dF);CHKERRQ(ierr); 11293f27d899SToby Isaac ierr = PetscMalloc4(dimTrace * dim, &projT, dimFiber * dim, &projF, dT * NkTrace, &projTstar, dF * NkFiber, &projFstar);CHKERRQ(ierr); 11303f27d899SToby Isaac ierr = PetscArrayzero(projT, dimTrace * dim);CHKERRQ(ierr); 11313f27d899SToby Isaac for (i = 0; i < dimTrace; i++) projT[i * (dim + 1)] = 1.; 11323f27d899SToby Isaac ierr = PetscArrayzero(projF, dimFiber * dim);CHKERRQ(ierr); 11333f27d899SToby Isaac for (i = 0; i < dimFiber; i++) projF[i * (dim + 1) + dimTrace] = 1.; 11343f27d899SToby Isaac ierr = PetscDTAltVPullbackMatrix(dim, dimTrace, projT, kTrace, projTstar);CHKERRQ(ierr); 11353f27d899SToby Isaac ierr = PetscDTAltVPullbackMatrix(dim, dimFiber, projF, kFiber, projFstar);CHKERRQ(ierr); 11363f27d899SToby Isaac ierr = PetscMalloc5(dT, &workT, dF, &workF, Nk, &work, Nk, &workstar, Nk, &workS);CHKERRQ(ierr); 11373f27d899SToby Isaac ierr = PetscMalloc2(dT, &workT2, dF, &workF2);CHKERRQ(ierr); 11383f27d899SToby Isaac ierr = PetscMalloc1(Nk * dT, &wedgeMat);CHKERRQ(ierr); 11393f27d899SToby Isaac sign = (PetscAbsInt(kTrace * kFiber) & 1) ? -1. : 1.; 11403f27d899SToby Isaac for (i = 0, iF = 0; iF < mFiber; iF++) { 11413f27d899SToby Isaac PetscInt ncolsF, nformsF; 11423f27d899SToby Isaac const PetscInt *colsF; 11433f27d899SToby Isaac const PetscScalar *valsF; 11443f27d899SToby Isaac 11453f27d899SToby Isaac ierr = MatGetRow(fiber, iF, &ncolsF, &colsF, &valsF);CHKERRQ(ierr); 11463f27d899SToby Isaac nformsF = ncolsF / NkFiber; 11473f27d899SToby Isaac for (iT = 0; iT < mTrace; iT++, i++) { 11483f27d899SToby Isaac PetscInt ncolsT, nformsT; 11493f27d899SToby Isaac const PetscInt *colsT; 11503f27d899SToby Isaac const PetscScalar *valsT; 11513f27d899SToby Isaac 11523f27d899SToby Isaac ierr = MatGetRow(trace, iT, &ncolsT, &colsT, &valsT);CHKERRQ(ierr); 11533f27d899SToby Isaac nformsT = ncolsT / NkTrace; 11543f27d899SToby Isaac for (j = 0, jF = 0; jF < nformsF; jF++) { 11553f27d899SToby Isaac PetscInt colF = colsF[jF * NkFiber] / NkFiber; 11563f27d899SToby Isaac 11573f27d899SToby Isaac for (il = 0; il < dF; il++) { 11583f27d899SToby Isaac PetscReal val = 0.; 11593f27d899SToby Isaac for (jl = 0; jl < NkFiber; jl++) val += projFstar[il * NkFiber + jl] * PetscRealPart(valsF[jF * NkFiber + jl]); 11603f27d899SToby Isaac workF[il] = val; 11613f27d899SToby Isaac } 11623f27d899SToby Isaac if (kFiber < 0) { 11633f27d899SToby Isaac for (il = 0; il < dF; il++) workF2[il] = workF[il]; 11643f27d899SToby Isaac ierr = PetscDTAltVStar(dim, PetscAbsInt(kFiber), 1, workF2, workF);CHKERRQ(ierr); 11653f27d899SToby Isaac } 11663f27d899SToby Isaac ierr = PetscDTAltVWedgeMatrix(dim, PetscAbsInt(kFiber), PetscAbsInt(kTrace), workF, wedgeMat);CHKERRQ(ierr); 11673f27d899SToby Isaac for (jT = 0; jT < nformsT; jT++, j++) { 11683f27d899SToby Isaac PetscInt colT = colsT[jT * NkTrace] / NkTrace; 11693f27d899SToby Isaac PetscInt col = colF * (nTrace / NkTrace) + colT; 11703f27d899SToby Isaac const PetscScalar *vals; 11713f27d899SToby Isaac 11723f27d899SToby Isaac for (il = 0; il < dT; il++) { 11733f27d899SToby Isaac PetscReal val = 0.; 11743f27d899SToby Isaac for (jl = 0; jl < NkTrace; jl++) val += projTstar[il * NkTrace + jl] * PetscRealPart(valsT[jT * NkTrace + jl]); 11753f27d899SToby Isaac workT[il] = val; 11763f27d899SToby Isaac } 11773f27d899SToby Isaac if (kTrace < 0) { 11783f27d899SToby Isaac for (il = 0; il < dT; il++) workT2[il] = workT[il]; 11793f27d899SToby Isaac ierr = PetscDTAltVStar(dim, PetscAbsInt(kTrace), 1, workT2, workT);CHKERRQ(ierr); 11803f27d899SToby Isaac } 11813f27d899SToby Isaac 11823f27d899SToby Isaac for (il = 0; il < Nk; il++) { 11833f27d899SToby Isaac PetscReal val = 0.; 11843f27d899SToby Isaac for (jl = 0; jl < dT; jl++) val += sign * wedgeMat[il * dT + jl] * workT[jl]; 11853f27d899SToby Isaac work[il] = val; 11863f27d899SToby Isaac } 11873f27d899SToby Isaac if (k < 0) { 11883f27d899SToby Isaac ierr = PetscDTAltVStar(dim, PetscAbsInt(k), -1, work, workstar);CHKERRQ(ierr); 11893f27d899SToby Isaac #if defined(PETSC_USE_COMPLEX) 11903f27d899SToby Isaac for (l = 0; l < Nk; l++) workS[l] = workstar[l]; 11913f27d899SToby Isaac vals = &workS[0]; 11923f27d899SToby Isaac #else 11933f27d899SToby Isaac vals = &workstar[0]; 11943f27d899SToby Isaac #endif 11953f27d899SToby Isaac } else { 11963f27d899SToby Isaac #if defined(PETSC_USE_COMPLEX) 11973f27d899SToby Isaac for (l = 0; l < Nk; l++) workS[l] = work[l]; 11983f27d899SToby Isaac vals = &workS[0]; 11993f27d899SToby Isaac #else 12003f27d899SToby Isaac vals = &work[0]; 12013f27d899SToby Isaac #endif 12023f27d899SToby Isaac } 12033f27d899SToby Isaac for (l = 0; l < Nk; l++) { 12043f27d899SToby Isaac ierr = MatSetValue(prod, i, col * Nk + l, vals[l], INSERT_VALUES);CHKERRQ(ierr); 12053f27d899SToby Isaac } /* Nk */ 12063f27d899SToby Isaac } /* jT */ 12073f27d899SToby Isaac } /* jF */ 12083f27d899SToby Isaac ierr = MatRestoreRow(trace, iT, &ncolsT, &colsT, &valsT);CHKERRQ(ierr); 12093f27d899SToby Isaac } /* iT */ 12103f27d899SToby Isaac ierr = MatRestoreRow(fiber, iF, &ncolsF, &colsF, &valsF);CHKERRQ(ierr); 12113f27d899SToby Isaac } /* iF */ 12123f27d899SToby Isaac ierr = PetscFree(wedgeMat);CHKERRQ(ierr); 12133f27d899SToby Isaac ierr = PetscFree4(projT, projF, projTstar, projFstar);CHKERRQ(ierr); 12143f27d899SToby Isaac ierr = PetscFree2(workT2, workF2);CHKERRQ(ierr); 12153f27d899SToby Isaac ierr = PetscFree5(workT, workF, work, workstar, workS);CHKERRQ(ierr); 12163f27d899SToby Isaac ierr = MatAssemblyBegin(prod, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 12173f27d899SToby Isaac ierr = MatAssemblyEnd(prod, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 12183f27d899SToby Isaac *product = prod; 12193f27d899SToby Isaac PetscFunctionReturn(0); 12203f27d899SToby Isaac } 12213f27d899SToby Isaac 122277f1a120SToby Isaac /* Union of quadrature points, with an attempt to identify commont points in the two sets */ 12233f27d899SToby Isaac static PetscErrorCode PetscQuadraturePointsMerge(PetscQuadrature quadA, PetscQuadrature quadB, PetscQuadrature *quadJoint, PetscInt *aToJoint[], PetscInt *bToJoint[]) 12243f27d899SToby Isaac { 12253f27d899SToby Isaac PetscInt dimA, dimB; 12263f27d899SToby Isaac PetscInt nA, nB, nJoint, i, j, d; 12273f27d899SToby Isaac const PetscReal *pointsA; 12283f27d899SToby Isaac const PetscReal *pointsB; 12293f27d899SToby Isaac PetscReal *pointsJoint; 12303f27d899SToby Isaac PetscInt *aToJ, *bToJ; 12313f27d899SToby Isaac PetscQuadrature qJ; 12323f27d899SToby Isaac PetscErrorCode ierr; 12333f27d899SToby Isaac 12343f27d899SToby Isaac PetscFunctionBegin; 12353f27d899SToby Isaac ierr = PetscQuadratureGetData(quadA, &dimA, NULL, &nA, &pointsA, NULL);CHKERRQ(ierr); 12363f27d899SToby Isaac ierr = PetscQuadratureGetData(quadB, &dimB, NULL, &nB, &pointsB, NULL);CHKERRQ(ierr); 12373f27d899SToby Isaac if (dimA != dimB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Quadrature points must be in the same dimension"); 12383f27d899SToby Isaac nJoint = nA; 12393f27d899SToby Isaac ierr = PetscMalloc1(nA, &aToJ);CHKERRQ(ierr); 12403f27d899SToby Isaac for (i = 0; i < nA; i++) aToJ[i] = i; 12413f27d899SToby Isaac ierr = PetscMalloc1(nB, &bToJ);CHKERRQ(ierr); 12423f27d899SToby Isaac for (i = 0; i < nB; i++) { 12433f27d899SToby Isaac for (j = 0; j < nA; j++) { 12443f27d899SToby Isaac bToJ[i] = -1; 12456ff15688SToby Isaac for (d = 0; d < dimA; d++) if (PetscAbsReal(pointsB[i * dimA + d] - pointsA[j * dimA + d]) > PETSC_SMALL) break; 12463f27d899SToby Isaac if (d == dimA) { 12473f27d899SToby Isaac bToJ[i] = j; 12483f27d899SToby Isaac break; 12493f27d899SToby Isaac } 12503f27d899SToby Isaac } 12513f27d899SToby Isaac if (bToJ[i] == -1) { 12523f27d899SToby Isaac bToJ[i] = nJoint++; 12533f27d899SToby Isaac } 12543f27d899SToby Isaac } 12553f27d899SToby Isaac *aToJoint = aToJ; 12563f27d899SToby Isaac *bToJoint = bToJ; 12573f27d899SToby Isaac ierr = PetscMalloc1(nJoint * dimA, &pointsJoint);CHKERRQ(ierr); 12583f27d899SToby Isaac ierr = PetscArraycpy(pointsJoint, pointsA, nA * dimA);CHKERRQ(ierr); 12593f27d899SToby Isaac for (i = 0; i < nB; i++) { 12603f27d899SToby Isaac if (bToJ[i] >= nA) { 12613f27d899SToby Isaac for (d = 0; d < dimA; d++) pointsJoint[bToJ[i] * dimA + d] = pointsB[i * dimA + d]; 12623f27d899SToby Isaac } 12633f27d899SToby Isaac } 12643f27d899SToby Isaac ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &qJ);CHKERRQ(ierr); 12653f27d899SToby Isaac ierr = PetscQuadratureSetData(qJ, dimA, 0, nJoint, pointsJoint, NULL);CHKERRQ(ierr); 12663f27d899SToby Isaac *quadJoint = qJ; 12673f27d899SToby Isaac PetscFunctionReturn(0); 12683f27d899SToby Isaac } 12693f27d899SToby Isaac 127077f1a120SToby Isaac /* Matrices matA and matB are both quadrature -> dof matrices: produce a matrix that is joint quadrature -> union of 127177f1a120SToby Isaac * dofs, where the joint quadrature was produced by PetscQuadraturePointsMerge */ 12723f27d899SToby Isaac static PetscErrorCode MatricesMerge(Mat matA, Mat matB, PetscInt dim, PetscInt k, PetscInt numMerged, const PetscInt aToMerged[], const PetscInt bToMerged[], Mat *matMerged) 12733f27d899SToby Isaac { 12743f27d899SToby Isaac PetscInt m, n, mA, nA, mB, nB, Nk, i, j, l; 12753f27d899SToby Isaac Mat M; 12763f27d899SToby Isaac PetscInt *nnz; 12773f27d899SToby Isaac PetscInt maxnnz; 12783f27d899SToby Isaac PetscInt *work; 12793f27d899SToby Isaac PetscErrorCode ierr; 12803f27d899SToby Isaac 12813f27d899SToby Isaac PetscFunctionBegin; 12823f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 12833f27d899SToby Isaac ierr = MatGetSize(matA, &mA, &nA);CHKERRQ(ierr); 12843f27d899SToby Isaac if (nA % Nk) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "matA column space not a multiple of k-form size"); 12853f27d899SToby Isaac ierr = MatGetSize(matB, &mB, &nB);CHKERRQ(ierr); 12863f27d899SToby Isaac if (nB % Nk) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "matB column space not a multiple of k-form size"); 12873f27d899SToby Isaac m = mA + mB; 12883f27d899SToby Isaac n = numMerged * Nk; 12893f27d899SToby Isaac ierr = PetscMalloc1(m, &nnz);CHKERRQ(ierr); 12903f27d899SToby Isaac maxnnz = 0; 12913f27d899SToby Isaac for (i = 0; i < mA; i++) { 12923f27d899SToby Isaac ierr = MatGetRow(matA, i, &(nnz[i]), NULL, NULL);CHKERRQ(ierr); 12933f27d899SToby Isaac if (nnz[i] % Nk) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "nonzeros in matA are not in k-form size blocks"); 12943f27d899SToby Isaac maxnnz = PetscMax(maxnnz, nnz[i]); 12953f27d899SToby Isaac } 12963f27d899SToby Isaac for (i = 0; i < mB; i++) { 12973f27d899SToby Isaac ierr = MatGetRow(matB, i, &(nnz[i+mA]), NULL, NULL);CHKERRQ(ierr); 12983f27d899SToby Isaac if (nnz[i+mA] % Nk) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "nonzeros in matB are not in k-form size blocks"); 12993f27d899SToby Isaac maxnnz = PetscMax(maxnnz, nnz[i+mA]); 13003f27d899SToby Isaac } 13013f27d899SToby Isaac ierr = MatCreateSeqAIJ(PETSC_COMM_SELF, m, n, 0, nnz, &M);CHKERRQ(ierr); 13023f27d899SToby Isaac ierr = PetscFree(nnz);CHKERRQ(ierr); 13033f27d899SToby Isaac /* reasoning about which points each dof needs depends on having zeros computed at points preserved */ 13043f27d899SToby Isaac ierr = MatSetOption(M, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);CHKERRQ(ierr); 13053f27d899SToby Isaac ierr = PetscMalloc1(maxnnz, &work);CHKERRQ(ierr); 13063f27d899SToby Isaac for (i = 0; i < mA; i++) { 13073f27d899SToby Isaac const PetscInt *cols; 13083f27d899SToby Isaac const PetscScalar *vals; 13093f27d899SToby Isaac PetscInt nCols; 13103f27d899SToby Isaac ierr = MatGetRow(matA, i, &nCols, &cols, &vals);CHKERRQ(ierr); 13113f27d899SToby Isaac for (j = 0; j < nCols / Nk; j++) { 13123f27d899SToby Isaac PetscInt newCol = aToMerged[cols[j * Nk] / Nk]; 13133f27d899SToby Isaac for (l = 0; l < Nk; l++) work[j * Nk + l] = newCol * Nk + l; 13143f27d899SToby Isaac } 13153f27d899SToby Isaac ierr = MatSetValuesBlocked(M, 1, &i, nCols, work, vals, INSERT_VALUES);CHKERRQ(ierr); 13163f27d899SToby Isaac ierr = MatRestoreRow(matA, i, &nCols, &cols, &vals);CHKERRQ(ierr); 13173f27d899SToby Isaac } 13183f27d899SToby Isaac for (i = 0; i < mB; i++) { 13193f27d899SToby Isaac const PetscInt *cols; 13203f27d899SToby Isaac const PetscScalar *vals; 13213f27d899SToby Isaac 13223f27d899SToby Isaac PetscInt row = i + mA; 13233f27d899SToby Isaac PetscInt nCols; 13243f27d899SToby Isaac ierr = MatGetRow(matB, i, &nCols, &cols, &vals);CHKERRQ(ierr); 13253f27d899SToby Isaac for (j = 0; j < nCols / Nk; j++) { 13263f27d899SToby Isaac PetscInt newCol = bToMerged[cols[j * Nk] / Nk]; 13273f27d899SToby Isaac for (l = 0; l < Nk; l++) work[j * Nk + l] = newCol * Nk + l; 13283f27d899SToby Isaac } 13293f27d899SToby Isaac ierr = MatSetValuesBlocked(M, 1, &row, nCols, work, vals, INSERT_VALUES);CHKERRQ(ierr); 13303f27d899SToby Isaac ierr = MatRestoreRow(matB, i, &nCols, &cols, &vals);CHKERRQ(ierr); 13313f27d899SToby Isaac } 13323f27d899SToby Isaac ierr = PetscFree(work);CHKERRQ(ierr); 13333f27d899SToby Isaac ierr = MatAssemblyBegin(M, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 13343f27d899SToby Isaac ierr = MatAssemblyEnd(M, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 13353f27d899SToby Isaac *matMerged = M; 13363f27d899SToby Isaac PetscFunctionReturn(0); 13373f27d899SToby Isaac } 13383f27d899SToby Isaac 133977f1a120SToby Isaac /* Take a dual space and product a segment space that has all the same specifications (trimmed, continuous, order, 134077f1a120SToby Isaac * node set), except for the form degree. For computing boundary dofs and for making tensor product spaces */ 13413f27d899SToby Isaac static PetscErrorCode PetscDualSpaceCreateFacetSubspace_Lagrange(PetscDualSpace sp, DM K, PetscInt f, PetscInt k, PetscInt Ncopies, PetscBool interiorOnly, PetscDualSpace *bdsp) 13423f27d899SToby Isaac { 13433f27d899SToby Isaac PetscInt Nknew, Ncnew; 13443f27d899SToby Isaac PetscInt dim, pointDim = -1; 13453f27d899SToby Isaac PetscInt depth; 13463f27d899SToby Isaac DM dm; 13473f27d899SToby Isaac PetscDualSpace_Lag *newlag; 13483f27d899SToby Isaac PetscErrorCode ierr; 13493f27d899SToby Isaac 13503f27d899SToby Isaac PetscFunctionBegin; 13513f27d899SToby Isaac ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr); 13523f27d899SToby Isaac ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr); 13533f27d899SToby Isaac ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr); 13543f27d899SToby Isaac ierr = PetscDualSpaceDuplicate(sp,bdsp);CHKERRQ(ierr); 13553f27d899SToby Isaac ierr = PetscDualSpaceSetFormDegree(*bdsp,k);CHKERRQ(ierr); 13563f27d899SToby Isaac if (!K) { 13573f27d899SToby Isaac PetscBool isSimplex; 13583f27d899SToby Isaac 13593f27d899SToby Isaac if (depth == dim) { 13603f27d899SToby Isaac PetscInt coneSize; 13613f27d899SToby Isaac 13626ff15688SToby Isaac pointDim = dim - 1; 13633f27d899SToby Isaac ierr = DMPlexGetConeSize(dm,f,&coneSize);CHKERRQ(ierr); 13643f27d899SToby Isaac isSimplex = (PetscBool) (coneSize == dim); 13653f27d899SToby Isaac ierr = PetscDualSpaceCreateReferenceCell(*bdsp, dim-1, isSimplex, &K);CHKERRQ(ierr); 13663f27d899SToby Isaac } else if (depth == 1) { 13673f27d899SToby Isaac pointDim = 0; 13683f27d899SToby Isaac ierr = PetscDualSpaceCreateReferenceCell(*bdsp, 0, PETSC_TRUE, &K);CHKERRQ(ierr); 13693f27d899SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported interpolation state of reference element"); 13703f27d899SToby Isaac } else { 13713f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)K);CHKERRQ(ierr); 13723f27d899SToby Isaac ierr = DMGetDimension(K, &pointDim);CHKERRQ(ierr); 13733f27d899SToby Isaac } 13743f27d899SToby Isaac ierr = PetscDualSpaceSetDM(*bdsp, K);CHKERRQ(ierr); 13753f27d899SToby Isaac ierr = DMDestroy(&K);CHKERRQ(ierr); 13763f27d899SToby Isaac ierr = PetscDTBinomialInt(pointDim, PetscAbsInt(k), &Nknew);CHKERRQ(ierr); 13773f27d899SToby Isaac Ncnew = Nknew * Ncopies; 13783f27d899SToby Isaac ierr = PetscDualSpaceSetNumComponents(*bdsp, Ncnew);CHKERRQ(ierr); 13793f27d899SToby Isaac newlag = (PetscDualSpace_Lag *) (*bdsp)->data; 13803f27d899SToby Isaac newlag->interiorOnly = interiorOnly; 13813f27d899SToby Isaac ierr = PetscDualSpaceSetUp(*bdsp);CHKERRQ(ierr); 13823f27d899SToby Isaac PetscFunctionReturn(0); 13833f27d899SToby Isaac } 13843f27d899SToby Isaac 138577f1a120SToby Isaac /* Construct simplex nodes from a nodefamily, add Nk dof vectors of length Nk at each node. 138677f1a120SToby Isaac * Return the (quadrature, matrix) form of the dofs and the nodeIndices form as well. 138777f1a120SToby Isaac * 138877f1a120SToby Isaac * Sometimes we want a set of nodes to be contained in the interior of the element, 138977f1a120SToby Isaac * even when the node scheme puts nodes on the boundaries. numNodeSkip tells 139077f1a120SToby Isaac * the routine how many "layers" of nodes need to be skipped. 139177f1a120SToby Isaac * */ 13923f27d899SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeCreateSimplexNodeMat(Petsc1DNodeFamily nodeFamily, PetscInt dim, PetscInt sum, PetscInt Nk, PetscInt numNodeSkip, PetscQuadrature *iNodes, Mat *iMat, PetscLagNodeIndices *nodeIndices) 13933f27d899SToby Isaac { 13943f27d899SToby Isaac PetscReal *extraNodeCoords, *nodeCoords; 13953f27d899SToby Isaac PetscInt nNodes, nExtraNodes; 13963f27d899SToby Isaac PetscInt i, j, k, extraSum = sum + numNodeSkip * (1 + dim); 13973f27d899SToby Isaac PetscQuadrature intNodes; 13983f27d899SToby Isaac Mat intMat; 13993f27d899SToby Isaac PetscLagNodeIndices ni; 14003f27d899SToby Isaac PetscErrorCode ierr; 14013f27d899SToby Isaac 14023f27d899SToby Isaac PetscFunctionBegin; 14033f27d899SToby Isaac ierr = PetscDTBinomialInt(dim + sum, dim, &nNodes);CHKERRQ(ierr); 14043f27d899SToby Isaac ierr = PetscDTBinomialInt(dim + extraSum, dim, &nExtraNodes);CHKERRQ(ierr); 14053f27d899SToby Isaac 14063f27d899SToby Isaac ierr = PetscMalloc1(dim * nExtraNodes, &extraNodeCoords);CHKERRQ(ierr); 14073f27d899SToby Isaac ierr = PetscNew(&ni);CHKERRQ(ierr); 14083f27d899SToby Isaac ni->nodeIdxDim = dim + 1; 14093f27d899SToby Isaac ni->nodeVecDim = Nk; 14103f27d899SToby Isaac ni->nNodes = nNodes * Nk; 14113f27d899SToby Isaac ni->refct = 1; 14123f27d899SToby Isaac ierr = PetscMalloc1(nNodes * Nk * (dim + 1), &(ni->nodeIdx));CHKERRQ(ierr); 14133f27d899SToby Isaac ierr = PetscMalloc1(nNodes * Nk * Nk, &(ni->nodeVec));CHKERRQ(ierr); 14143f27d899SToby Isaac for (i = 0; i < nNodes; i++) for (j = 0; j < Nk; j++) for (k = 0; k < Nk; k++) ni->nodeVec[(i * Nk + j) * Nk + k] = (j == k) ? 1. : 0.; 14153f27d899SToby Isaac ierr = Petsc1DNodeFamilyComputeSimplexNodes(nodeFamily, dim, extraSum, extraNodeCoords);CHKERRQ(ierr); 14163f27d899SToby Isaac if (numNodeSkip) { 14173f27d899SToby Isaac PetscInt k; 14183f27d899SToby Isaac PetscInt *tup; 14193f27d899SToby Isaac 14203f27d899SToby Isaac ierr = PetscMalloc1(dim * nNodes, &nodeCoords);CHKERRQ(ierr); 14213f27d899SToby Isaac ierr = PetscMalloc1(dim + 1, &tup);CHKERRQ(ierr); 14223f27d899SToby Isaac for (k = 0; k < nNodes; k++) { 14233f27d899SToby Isaac PetscInt j, c; 14243f27d899SToby Isaac PetscInt index; 14253f27d899SToby Isaac 14263f27d899SToby Isaac ierr = PetscDTIndexToBary(dim + 1, sum, k, tup);CHKERRQ(ierr); 14273f27d899SToby Isaac for (j = 0; j < dim + 1; j++) tup[j] += numNodeSkip; 14283f27d899SToby Isaac for (c = 0; c < Nk; c++) { 14293f27d899SToby Isaac for (j = 0; j < dim + 1; j++) { 14303f27d899SToby Isaac ni->nodeIdx[(k * Nk + c) * (dim + 1) + j] = tup[j] + 1; 14313f27d899SToby Isaac } 14323f27d899SToby Isaac } 14333f27d899SToby Isaac ierr = PetscDTBaryToIndex(dim + 1, extraSum, tup, &index);CHKERRQ(ierr); 14343f27d899SToby Isaac for (j = 0; j < dim; j++) nodeCoords[k * dim + j] = extraNodeCoords[index * dim + j]; 14353f27d899SToby Isaac } 14363f27d899SToby Isaac ierr = PetscFree(tup);CHKERRQ(ierr); 14373f27d899SToby Isaac ierr = PetscFree(extraNodeCoords);CHKERRQ(ierr); 14383f27d899SToby Isaac } else { 14393f27d899SToby Isaac PetscInt k; 14403f27d899SToby Isaac PetscInt *tup; 14413f27d899SToby Isaac 14423f27d899SToby Isaac nodeCoords = extraNodeCoords; 14433f27d899SToby Isaac ierr = PetscMalloc1(dim + 1, &tup);CHKERRQ(ierr); 14443f27d899SToby Isaac for (k = 0; k < nNodes; k++) { 14453f27d899SToby Isaac PetscInt j, c; 14463f27d899SToby Isaac 14473f27d899SToby Isaac ierr = PetscDTIndexToBary(dim + 1, sum, k, tup);CHKERRQ(ierr); 14483f27d899SToby Isaac for (c = 0; c < Nk; c++) { 14493f27d899SToby Isaac for (j = 0; j < dim + 1; j++) { 14503f27d899SToby Isaac /* barycentric indices can have zeros, but we don't want to push forward zeros because it makes it harder to 145177f1a120SToby Isaac * determine which nodes correspond to which under symmetries, so we increase by 1. This is fine 145277f1a120SToby Isaac * because the nodeIdx coordinates don't have any meaning other than helping to identify symmetries */ 14533f27d899SToby Isaac ni->nodeIdx[(k * Nk + c) * (dim + 1) + j] = tup[j] + 1; 14543f27d899SToby Isaac } 14553f27d899SToby Isaac } 14563f27d899SToby Isaac } 14573f27d899SToby Isaac ierr = PetscFree(tup);CHKERRQ(ierr); 14583f27d899SToby Isaac } 14593f27d899SToby Isaac ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &intNodes);CHKERRQ(ierr); 14603f27d899SToby Isaac ierr = PetscQuadratureSetData(intNodes, dim, 0, nNodes, nodeCoords, NULL);CHKERRQ(ierr); 14613f27d899SToby Isaac ierr = MatCreateSeqAIJ(PETSC_COMM_SELF, nNodes * Nk, nNodes * Nk, Nk, NULL, &intMat);CHKERRQ(ierr); 14623f27d899SToby Isaac ierr = MatSetOption(intMat,MAT_IGNORE_ZERO_ENTRIES,PETSC_FALSE);CHKERRQ(ierr); 14633f27d899SToby Isaac for (j = 0; j < nNodes * Nk; j++) { 14643f27d899SToby Isaac PetscInt rem = j % Nk; 14653f27d899SToby Isaac PetscInt a, aprev = j - rem; 14663f27d899SToby Isaac PetscInt anext = aprev + Nk; 14673f27d899SToby Isaac 14683f27d899SToby Isaac for (a = aprev; a < anext; a++) { 14693f27d899SToby Isaac ierr = MatSetValue(intMat, j, a, (a == j) ? 1. : 0., INSERT_VALUES);CHKERRQ(ierr); 14703f27d899SToby Isaac } 14713f27d899SToby Isaac } 14723f27d899SToby Isaac ierr = MatAssemblyBegin(intMat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 14733f27d899SToby Isaac ierr = MatAssemblyEnd(intMat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 14743f27d899SToby Isaac *iNodes = intNodes; 14753f27d899SToby Isaac *iMat = intMat; 14763f27d899SToby Isaac *nodeIndices = ni; 14773f27d899SToby Isaac PetscFunctionReturn(0); 14783f27d899SToby Isaac } 14793f27d899SToby Isaac 148077f1a120SToby Isaac /* once the nodeIndices have been created for the interior of the reference cell, and for all of the boundary cells, 148177f1a120SToby Isaac * push forward the boudary dofs and concatenate them into the full node indices for the dual space */ 14823f27d899SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeCreateAllNodeIdx(PetscDualSpace sp) 14833f27d899SToby Isaac { 14843f27d899SToby Isaac DM dm; 14853f27d899SToby Isaac PetscInt dim, nDofs; 14863f27d899SToby Isaac PetscSection section; 14873f27d899SToby Isaac PetscInt pStart, pEnd, p; 14883f27d899SToby Isaac PetscInt formDegree, Nk; 14893f27d899SToby Isaac PetscInt nodeIdxDim, spintdim; 14903f27d899SToby Isaac PetscDualSpace_Lag *lag; 14913f27d899SToby Isaac PetscLagNodeIndices ni, verti; 14923f27d899SToby Isaac PetscErrorCode ierr; 14933f27d899SToby Isaac 14943f27d899SToby Isaac PetscFunctionBegin; 14953f27d899SToby Isaac lag = (PetscDualSpace_Lag *) sp->data; 14963f27d899SToby Isaac verti = lag->vertIndices; 14973f27d899SToby Isaac ierr = PetscDualSpaceGetDM(sp, &dm);CHKERRQ(ierr); 14983f27d899SToby Isaac ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 14993f27d899SToby Isaac ierr = PetscDualSpaceGetFormDegree(sp, &formDegree);CHKERRQ(ierr); 15003f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &Nk);CHKERRQ(ierr); 15013f27d899SToby Isaac ierr = PetscDualSpaceGetSection(sp, §ion);CHKERRQ(ierr); 15023f27d899SToby Isaac ierr = PetscSectionGetStorageSize(section, &nDofs);CHKERRQ(ierr); 15033f27d899SToby Isaac ierr = PetscNew(&ni);CHKERRQ(ierr); 15043f27d899SToby Isaac ni->nodeIdxDim = nodeIdxDim = verti->nodeIdxDim; 15053f27d899SToby Isaac ni->nodeVecDim = Nk; 15063f27d899SToby Isaac ni->nNodes = nDofs; 15073f27d899SToby Isaac ni->refct = 1; 15083f27d899SToby Isaac ierr = PetscMalloc1(nodeIdxDim * nDofs, &(ni->nodeIdx));CHKERRQ(ierr); 15093f27d899SToby Isaac ierr = PetscMalloc1(Nk * nDofs, &(ni->nodeVec));CHKERRQ(ierr); 15103f27d899SToby Isaac ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 15113f27d899SToby Isaac ierr = PetscSectionGetDof(section, 0, &spintdim);CHKERRQ(ierr); 15123f27d899SToby Isaac if (spintdim) { 15133f27d899SToby Isaac ierr = PetscArraycpy(ni->nodeIdx, lag->intNodeIndices->nodeIdx, spintdim * nodeIdxDim);CHKERRQ(ierr); 15143f27d899SToby Isaac ierr = PetscArraycpy(ni->nodeVec, lag->intNodeIndices->nodeVec, spintdim * Nk);CHKERRQ(ierr); 15153f27d899SToby Isaac } 15163f27d899SToby Isaac for (p = pStart + 1; p < pEnd; p++) { 15173f27d899SToby Isaac PetscDualSpace psp = sp->pointSpaces[p]; 15183f27d899SToby Isaac PetscDualSpace_Lag *plag; 15193f27d899SToby Isaac PetscInt dof, off; 15203f27d899SToby Isaac 15213f27d899SToby Isaac ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 15223f27d899SToby Isaac if (!dof) continue; 15233f27d899SToby Isaac plag = (PetscDualSpace_Lag *) psp->data; 15243f27d899SToby Isaac ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 15253f27d899SToby Isaac ierr = PetscLagNodeIndicesPushForward(dm, verti, p, plag->vertIndices, plag->intNodeIndices, 0, formDegree, &(ni->nodeIdx[off * nodeIdxDim]), &(ni->nodeVec[off * Nk]));CHKERRQ(ierr); 15263f27d899SToby Isaac } 15273f27d899SToby Isaac lag->allNodeIndices = ni; 15283f27d899SToby Isaac PetscFunctionReturn(0); 15293f27d899SToby Isaac } 15303f27d899SToby Isaac 153177f1a120SToby Isaac /* once the (quadrature, Matrix) forms of the dofs have been created for the interior of the 153277f1a120SToby Isaac * reference cell and for the boundary cells, jk 153377f1a120SToby Isaac * push forward the boundary data and concatenate them into the full (quadrature, matrix) data 153477f1a120SToby Isaac * for the dual space */ 15353f27d899SToby Isaac static PetscErrorCode PetscDualSpaceCreateAllDataFromInteriorData(PetscDualSpace sp) 15363f27d899SToby Isaac { 15373f27d899SToby Isaac DM dm; 15383f27d899SToby Isaac PetscSection section; 15393f27d899SToby Isaac PetscInt pStart, pEnd, p, k, Nk, dim, Nc; 15403f27d899SToby Isaac PetscInt nNodes; 15413f27d899SToby Isaac PetscInt countNodes; 15423f27d899SToby Isaac Mat allMat; 15433f27d899SToby Isaac PetscQuadrature allNodes; 15443f27d899SToby Isaac PetscInt nDofs; 15453f27d899SToby Isaac PetscInt maxNzforms, j; 15463f27d899SToby Isaac PetscScalar *work; 15473f27d899SToby Isaac PetscReal *L, *J, *Jinv, *v0, *pv0; 15483f27d899SToby Isaac PetscInt *iwork; 15493f27d899SToby Isaac PetscReal *nodes; 15503f27d899SToby Isaac PetscErrorCode ierr; 15513f27d899SToby Isaac 15523f27d899SToby Isaac PetscFunctionBegin; 15533f27d899SToby Isaac ierr = PetscDualSpaceGetDM(sp, &dm);CHKERRQ(ierr); 15543f27d899SToby Isaac ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 15553f27d899SToby Isaac ierr = PetscDualSpaceGetSection(sp, §ion);CHKERRQ(ierr); 15563f27d899SToby Isaac ierr = PetscSectionGetStorageSize(section, &nDofs);CHKERRQ(ierr); 15573f27d899SToby Isaac ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 15583f27d899SToby Isaac ierr = PetscDualSpaceGetFormDegree(sp, &k);CHKERRQ(ierr); 15593f27d899SToby Isaac ierr = PetscDualSpaceGetNumComponents(sp, &Nc);CHKERRQ(ierr); 15603f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 15613f27d899SToby Isaac for (p = pStart, nNodes = 0, maxNzforms = 0; p < pEnd; p++) { 15623f27d899SToby Isaac PetscDualSpace psp; 15633f27d899SToby Isaac DM pdm; 15643f27d899SToby Isaac PetscInt pdim, pNk; 15653f27d899SToby Isaac PetscQuadrature intNodes; 15663f27d899SToby Isaac Mat intMat; 15673f27d899SToby Isaac 15683f27d899SToby Isaac ierr = PetscDualSpaceGetPointSubspace(sp, p, &psp);CHKERRQ(ierr); 15693f27d899SToby Isaac if (!psp) continue; 15703f27d899SToby Isaac ierr = PetscDualSpaceGetDM(psp, &pdm);CHKERRQ(ierr); 15713f27d899SToby Isaac ierr = DMGetDimension(pdm, &pdim);CHKERRQ(ierr); 15723f27d899SToby Isaac if (pdim < PetscAbsInt(k)) continue; 15733f27d899SToby Isaac ierr = PetscDTBinomialInt(pdim, PetscAbsInt(k), &pNk);CHKERRQ(ierr); 15743f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorData(psp, &intNodes, &intMat);CHKERRQ(ierr); 15753f27d899SToby Isaac if (intNodes) { 15763f27d899SToby Isaac PetscInt nNodesp; 15773f27d899SToby Isaac 15783f27d899SToby Isaac ierr = PetscQuadratureGetData(intNodes, NULL, NULL, &nNodesp, NULL, NULL);CHKERRQ(ierr); 15793f27d899SToby Isaac nNodes += nNodesp; 15803f27d899SToby Isaac } 15813f27d899SToby Isaac if (intMat) { 15823f27d899SToby Isaac PetscInt maxNzsp; 15833f27d899SToby Isaac PetscInt maxNzformsp; 15843f27d899SToby Isaac 15853f27d899SToby Isaac ierr = MatSeqAIJGetMaxRowNonzeros(intMat, &maxNzsp);CHKERRQ(ierr); 15863f27d899SToby Isaac if (maxNzsp % pNk) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "interior matrix is not laid out as blocks of k-forms"); 15873f27d899SToby Isaac maxNzformsp = maxNzsp / pNk; 15883f27d899SToby Isaac maxNzforms = PetscMax(maxNzforms, maxNzformsp); 15893f27d899SToby Isaac } 15903f27d899SToby Isaac } 15913f27d899SToby Isaac ierr = MatCreateSeqAIJ(PETSC_COMM_SELF, nDofs, nNodes * Nc, maxNzforms * Nk, NULL, &allMat);CHKERRQ(ierr); 15923f27d899SToby Isaac ierr = MatSetOption(allMat,MAT_IGNORE_ZERO_ENTRIES,PETSC_FALSE);CHKERRQ(ierr); 15933f27d899SToby Isaac ierr = PetscMalloc7(dim, &v0, dim, &pv0, dim * dim, &J, dim * dim, &Jinv, Nk * Nk, &L, maxNzforms * Nk, &work, maxNzforms * Nk, &iwork);CHKERRQ(ierr); 15943f27d899SToby Isaac for (j = 0; j < dim; j++) pv0[j] = -1.; 15953f27d899SToby Isaac ierr = PetscMalloc1(dim * nNodes, &nodes);CHKERRQ(ierr); 15963f27d899SToby Isaac for (p = pStart, countNodes = 0; p < pEnd; p++) { 15973f27d899SToby Isaac PetscDualSpace psp; 15983f27d899SToby Isaac PetscQuadrature intNodes; 15993f27d899SToby Isaac DM pdm; 16003f27d899SToby Isaac PetscInt pdim, pNk; 16013f27d899SToby Isaac PetscInt countNodesIn = countNodes; 16023f27d899SToby Isaac PetscReal detJ; 16033f27d899SToby Isaac Mat intMat; 16043f27d899SToby Isaac 16053f27d899SToby Isaac ierr = PetscDualSpaceGetPointSubspace(sp, p, &psp);CHKERRQ(ierr); 16063f27d899SToby Isaac if (!psp) continue; 16073f27d899SToby Isaac ierr = PetscDualSpaceGetDM(psp, &pdm);CHKERRQ(ierr); 16083f27d899SToby Isaac ierr = DMGetDimension(pdm, &pdim);CHKERRQ(ierr); 16093f27d899SToby Isaac if (pdim < PetscAbsInt(k)) continue; 16103f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorData(psp, &intNodes, &intMat);CHKERRQ(ierr); 16113f27d899SToby Isaac if (intNodes == NULL && intMat == NULL) continue; 16123f27d899SToby Isaac ierr = PetscDTBinomialInt(pdim, PetscAbsInt(k), &pNk);CHKERRQ(ierr); 16133f27d899SToby Isaac if (p) { 16143f27d899SToby Isaac ierr = DMPlexComputeCellGeometryAffineFEM(dm, p, v0, J, Jinv, &detJ);CHKERRQ(ierr); 16153f27d899SToby Isaac } else { /* identity */ 16163f27d899SToby Isaac PetscInt i,j; 16173f27d899SToby Isaac 16183f27d899SToby Isaac for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) J[i * dim + j] = Jinv[i * dim + j] = 0.; 16193f27d899SToby Isaac for (i = 0; i < dim; i++) J[i * dim + i] = Jinv[i * dim + i] = 1.; 16203f27d899SToby Isaac for (i = 0; i < dim; i++) v0[i] = -1.; 16213f27d899SToby Isaac } 16223f27d899SToby Isaac if (pdim != dim) { /* compactify Jacobian */ 16233f27d899SToby Isaac PetscInt i, j; 16243f27d899SToby Isaac 16253f27d899SToby Isaac for (i = 0; i < dim; i++) for (j = 0; j < pdim; j++) J[i * pdim + j] = J[i * dim + j]; 16263f27d899SToby Isaac } 16273f27d899SToby Isaac ierr = PetscDTAltVPullbackMatrix(pdim, dim, J, k, L);CHKERRQ(ierr); 162877f1a120SToby Isaac if (intNodes) { /* push forward quadrature locations by the affine transformation */ 16293f27d899SToby Isaac PetscInt nNodesp; 16303f27d899SToby Isaac const PetscReal *nodesp; 16313f27d899SToby Isaac PetscInt j; 16323f27d899SToby Isaac 16333f27d899SToby Isaac ierr = PetscQuadratureGetData(intNodes, NULL, NULL, &nNodesp, &nodesp, NULL);CHKERRQ(ierr); 16343f27d899SToby Isaac for (j = 0; j < nNodesp; j++, countNodes++) { 16353f27d899SToby Isaac PetscInt d, e; 16363f27d899SToby Isaac 16373f27d899SToby Isaac for (d = 0; d < dim; d++) { 16383f27d899SToby Isaac nodes[countNodes * dim + d] = v0[d]; 16393f27d899SToby Isaac for (e = 0; e < pdim; e++) { 16403f27d899SToby Isaac nodes[countNodes * dim + d] += J[d * pdim + e] * (nodesp[j * pdim + e] - pv0[e]); 16413f27d899SToby Isaac } 16423f27d899SToby Isaac } 16433f27d899SToby Isaac } 16443f27d899SToby Isaac } 16453f27d899SToby Isaac if (intMat) { 16463f27d899SToby Isaac PetscInt nrows; 16473f27d899SToby Isaac PetscInt off; 16483f27d899SToby Isaac 16493f27d899SToby Isaac ierr = PetscSectionGetDof(section, p, &nrows);CHKERRQ(ierr); 16503f27d899SToby Isaac ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 16513f27d899SToby Isaac for (j = 0; j < nrows; j++) { 16523f27d899SToby Isaac PetscInt ncols; 16533f27d899SToby Isaac const PetscInt *cols; 16543f27d899SToby Isaac const PetscScalar *vals; 16553f27d899SToby Isaac PetscInt l, d, e; 16563f27d899SToby Isaac PetscInt row = j + off; 16573f27d899SToby Isaac 16583f27d899SToby Isaac ierr = MatGetRow(intMat, j, &ncols, &cols, &vals);CHKERRQ(ierr); 16593f27d899SToby Isaac if (ncols % pNk) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "interior matrix is not laid out as blocks of k-forms"); 16603f27d899SToby Isaac for (l = 0; l < ncols / pNk; l++) { 16613f27d899SToby Isaac PetscInt blockcol; 16623f27d899SToby Isaac 16633f27d899SToby Isaac for (d = 0; d < pNk; d++) { 16643f27d899SToby Isaac if ((cols[l * pNk + d] % pNk) != d) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "interior matrix is not laid out as blocks of k-forms"); 16653f27d899SToby Isaac } 16663f27d899SToby Isaac blockcol = cols[l * pNk] / pNk; 16673f27d899SToby Isaac for (d = 0; d < Nk; d++) { 16683f27d899SToby Isaac iwork[l * Nk + d] = (blockcol + countNodesIn) * Nk + d; 16693f27d899SToby Isaac } 16703f27d899SToby Isaac for (d = 0; d < Nk; d++) work[l * Nk + d] = 0.; 16713f27d899SToby Isaac for (d = 0; d < Nk; d++) { 16723f27d899SToby Isaac for (e = 0; e < pNk; e++) { 16733f27d899SToby Isaac /* "push forward" dof by pulling back a k-form to be evaluated on the point: multiply on the right by L */ 16745efe5503SToby Isaac work[l * Nk + d] += vals[l * pNk + e] * L[e * Nk + d]; 16753f27d899SToby Isaac } 16763f27d899SToby Isaac } 16773f27d899SToby Isaac } 16783f27d899SToby Isaac ierr = MatSetValues(allMat, 1, &row, (ncols / pNk) * Nk, iwork, work, INSERT_VALUES);CHKERRQ(ierr); 16793f27d899SToby Isaac ierr = MatRestoreRow(intMat, j, &ncols, &cols, &vals);CHKERRQ(ierr); 16803f27d899SToby Isaac } 16813f27d899SToby Isaac } 16823f27d899SToby Isaac } 16833f27d899SToby Isaac ierr = MatAssemblyBegin(allMat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 16843f27d899SToby Isaac ierr = MatAssemblyEnd(allMat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 16853f27d899SToby Isaac ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &allNodes);CHKERRQ(ierr); 16863f27d899SToby Isaac ierr = PetscQuadratureSetData(allNodes, dim, 0, nNodes, nodes, NULL);CHKERRQ(ierr); 16873f27d899SToby Isaac ierr = PetscFree7(v0, pv0, J, Jinv, L, work, iwork);CHKERRQ(ierr); 16883f27d899SToby Isaac ierr = MatDestroy(&(sp->allMat));CHKERRQ(ierr); 16893f27d899SToby Isaac sp->allMat = allMat; 16903f27d899SToby Isaac ierr = PetscQuadratureDestroy(&(sp->allNodes));CHKERRQ(ierr); 16913f27d899SToby Isaac sp->allNodes = allNodes; 16923f27d899SToby Isaac PetscFunctionReturn(0); 16933f27d899SToby Isaac } 16943f27d899SToby Isaac 169577f1a120SToby Isaac /* rather than trying to get all data from the functionals, we create 169677f1a120SToby Isaac * the functionals from rows of the quadrature -> dof matrix. 169777f1a120SToby Isaac * 169877f1a120SToby Isaac * Ideally most of the uses of PetscDualSpace in PetscFE will switch 169977f1a120SToby Isaac * to using intMat and allMat, so that the individual functionals 170077f1a120SToby Isaac * don't need to be constructed at all */ 17013f27d899SToby Isaac static PetscErrorCode PetscDualSpaceComputeFunctionalsFromAllData(PetscDualSpace sp) 17023f27d899SToby Isaac { 17033f27d899SToby Isaac PetscQuadrature allNodes; 17043f27d899SToby Isaac Mat allMat; 17053f27d899SToby Isaac PetscInt nDofs; 17063f27d899SToby Isaac PetscInt dim, k, Nk, Nc, f; 17073f27d899SToby Isaac DM dm; 17083f27d899SToby Isaac PetscInt nNodes, spdim; 17093f27d899SToby Isaac const PetscReal *nodes = NULL; 17103f27d899SToby Isaac PetscSection section; 171166a6c23cSMatthew G. Knepley PetscBool useMoments; 17123f27d899SToby Isaac PetscErrorCode ierr; 17133f27d899SToby Isaac 17143f27d899SToby Isaac PetscFunctionBegin; 17153f27d899SToby Isaac ierr = PetscDualSpaceGetDM(sp, &dm);CHKERRQ(ierr); 17163f27d899SToby Isaac ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 17173f27d899SToby Isaac ierr = PetscDualSpaceGetNumComponents(sp, &Nc);CHKERRQ(ierr); 17183f27d899SToby Isaac ierr = PetscDualSpaceGetFormDegree(sp, &k);CHKERRQ(ierr); 17193f27d899SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 17203f27d899SToby Isaac ierr = PetscDualSpaceGetAllData(sp, &allNodes, &allMat);CHKERRQ(ierr); 17213f27d899SToby Isaac nNodes = 0; 17223f27d899SToby Isaac if (allNodes) { 17233f27d899SToby Isaac ierr = PetscQuadratureGetData(allNodes, NULL, NULL, &nNodes, &nodes, NULL);CHKERRQ(ierr); 17243f27d899SToby Isaac } 17253f27d899SToby Isaac ierr = MatGetSize(allMat, &nDofs, NULL);CHKERRQ(ierr); 17263f27d899SToby Isaac ierr = PetscDualSpaceGetSection(sp, §ion);CHKERRQ(ierr); 17273f27d899SToby Isaac ierr = PetscSectionGetStorageSize(section, &spdim);CHKERRQ(ierr); 17283f27d899SToby Isaac if (spdim != nDofs) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "incompatible all matrix size"); 17293f27d899SToby Isaac ierr = PetscMalloc1(nDofs, &(sp->functional));CHKERRQ(ierr); 173066a6c23cSMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetUseMoments(sp, &useMoments);CHKERRQ(ierr); 173166a6c23cSMatthew G. Knepley if (useMoments) { 173266a6c23cSMatthew G. Knepley Mat allMat; 173366a6c23cSMatthew G. Knepley PetscInt momentOrder, i; 173466a6c23cSMatthew G. Knepley PetscBool tensor; 173566a6c23cSMatthew G. Knepley const PetscReal *weights; 173666a6c23cSMatthew G. Knepley PetscScalar *array; 173766a6c23cSMatthew G. Knepley 173866a6c23cSMatthew G. Knepley if (nDofs != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "We do not yet support moments beyond P0, nDofs == %D", nDofs); 173966a6c23cSMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetMomentOrder(sp, &momentOrder);CHKERRQ(ierr); 174066a6c23cSMatthew G. Knepley ierr = PetscDualSpaceLagrangeGetTensor(sp, &tensor);CHKERRQ(ierr); 174166a6c23cSMatthew G. Knepley if (!tensor) {ierr = PetscDTStroudConicalQuadrature(dim, Nc, PetscMax(momentOrder + 1,1), -1.0, 1.0, &(sp->functional[0]));CHKERRQ(ierr);} 174266a6c23cSMatthew G. Knepley else {ierr = PetscDTGaussTensorQuadrature(dim, Nc, PetscMax(momentOrder + 1,1), -1.0, 1.0, &(sp->functional[0]));CHKERRQ(ierr);} 174366a6c23cSMatthew G. Knepley /* Need to replace allNodes and allMat */ 174466a6c23cSMatthew G. Knepley ierr = PetscObjectReference((PetscObject) sp->functional[0]);CHKERRQ(ierr); 174566a6c23cSMatthew G. Knepley ierr = PetscQuadratureDestroy(&(sp->allNodes));CHKERRQ(ierr); 174666a6c23cSMatthew G. Knepley sp->allNodes = sp->functional[0]; 174766a6c23cSMatthew G. Knepley ierr = PetscQuadratureGetData(sp->allNodes, NULL, NULL, &nNodes, NULL, &weights);CHKERRQ(ierr); 174866a6c23cSMatthew G. Knepley ierr = MatCreateSeqDense(PETSC_COMM_SELF, nDofs, nNodes * Nc, NULL, &allMat);CHKERRQ(ierr); 174966a6c23cSMatthew G. Knepley ierr = MatDenseGetArrayWrite(allMat, &array);CHKERRQ(ierr); 175066a6c23cSMatthew G. Knepley for (i = 0; i < nNodes * Nc; ++i) array[i] = weights[i]; 175166a6c23cSMatthew G. Knepley ierr = MatDenseRestoreArrayWrite(allMat, &array);CHKERRQ(ierr); 175266a6c23cSMatthew G. Knepley ierr = MatAssemblyBegin(allMat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 175366a6c23cSMatthew G. Knepley ierr = MatAssemblyEnd(allMat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 175466a6c23cSMatthew G. Knepley ierr = MatDestroy(&(sp->allMat));CHKERRQ(ierr); 175566a6c23cSMatthew G. Knepley sp->allMat = allMat; 175666a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 175766a6c23cSMatthew G. Knepley } 17583f27d899SToby Isaac for (f = 0; f < nDofs; f++) { 17593f27d899SToby Isaac PetscInt ncols, c; 17603f27d899SToby Isaac const PetscInt *cols; 17613f27d899SToby Isaac const PetscScalar *vals; 17623f27d899SToby Isaac PetscReal *nodesf; 17633f27d899SToby Isaac PetscReal *weightsf; 17643f27d899SToby Isaac PetscInt nNodesf; 17653f27d899SToby Isaac PetscInt countNodes; 17663f27d899SToby Isaac 17673f27d899SToby Isaac ierr = MatGetRow(allMat, f, &ncols, &cols, &vals);CHKERRQ(ierr); 17683f27d899SToby Isaac if (ncols % Nk) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "all matrix is not laid out as blocks of k-forms"); 17693f27d899SToby Isaac for (c = 1, nNodesf = 1; c < ncols; c++) { 17703f27d899SToby Isaac if ((cols[c] / Nc) != (cols[c-1] / Nc)) nNodesf++; 17713f27d899SToby Isaac } 17723f27d899SToby Isaac ierr = PetscMalloc1(dim * nNodesf, &nodesf);CHKERRQ(ierr); 17733f27d899SToby Isaac ierr = PetscMalloc1(Nc * nNodesf, &weightsf);CHKERRQ(ierr); 17743f27d899SToby Isaac for (c = 0, countNodes = 0; c < ncols; c++) { 17753f27d899SToby Isaac if (!c || ((cols[c] / Nc) != (cols[c-1] / Nc))) { 17763f27d899SToby Isaac PetscInt d; 17773f27d899SToby Isaac 17783f27d899SToby Isaac for (d = 0; d < Nc; d++) { 17793f27d899SToby Isaac weightsf[countNodes * Nc + d] = 0.; 17803f27d899SToby Isaac } 17813f27d899SToby Isaac for (d = 0; d < dim; d++) { 17823f27d899SToby Isaac nodesf[countNodes * dim + d] = nodes[(cols[c] / Nc) * dim + d]; 17833f27d899SToby Isaac } 17843f27d899SToby Isaac countNodes++; 17853f27d899SToby Isaac } 17863f27d899SToby Isaac weightsf[(countNodes - 1) * Nc + (cols[c] % Nc)] = PetscRealPart(vals[c]); 17873f27d899SToby Isaac } 17883f27d899SToby Isaac ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &(sp->functional[f]));CHKERRQ(ierr); 17893f27d899SToby Isaac ierr = PetscQuadratureSetData(sp->functional[f], dim, Nc, nNodesf, nodesf, weightsf);CHKERRQ(ierr); 17903f27d899SToby Isaac ierr = MatRestoreRow(allMat, f, &ncols, &cols, &vals);CHKERRQ(ierr); 17913f27d899SToby Isaac } 17923f27d899SToby Isaac PetscFunctionReturn(0); 17933f27d899SToby Isaac } 17943f27d899SToby Isaac 17953f27d899SToby Isaac /* take a matrix meant for k-forms and expand it to one for Ncopies */ 17963f27d899SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeMatrixCreateCopies(Mat A, PetscInt Nk, PetscInt Ncopies, Mat *Abs) 17973f27d899SToby Isaac { 17983f27d899SToby Isaac PetscInt m, n, i, j, k; 17993f27d899SToby Isaac PetscInt maxnnz, *nnz, *iwork; 18003f27d899SToby Isaac Mat Ac; 18013f27d899SToby Isaac PetscErrorCode ierr; 18023f27d899SToby Isaac 18033f27d899SToby Isaac PetscFunctionBegin; 18043f27d899SToby Isaac ierr = MatGetSize(A, &m, &n);CHKERRQ(ierr); 18053f27d899SToby Isaac if (n % Nk) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of columns in A %D is not a multiple of Nk %D", n, Nk); 18063f27d899SToby Isaac ierr = PetscMalloc1(m * Ncopies, &nnz);CHKERRQ(ierr); 18073f27d899SToby Isaac for (i = 0, maxnnz = 0; i < m; i++) { 18083f27d899SToby Isaac PetscInt innz; 18093f27d899SToby Isaac ierr = MatGetRow(A, i, &innz, NULL, NULL);CHKERRQ(ierr); 18103f27d899SToby Isaac if (innz % Nk) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "A row %D nnzs is not a multiple of Nk %D", innz, Nk); 18113f27d899SToby Isaac for (j = 0; j < Ncopies; j++) nnz[i * Ncopies + j] = innz; 18123f27d899SToby Isaac maxnnz = PetscMax(maxnnz, innz); 18133f27d899SToby Isaac } 18143f27d899SToby Isaac ierr = MatCreateSeqAIJ(PETSC_COMM_SELF, m * Ncopies, n * Ncopies, 0, nnz, &Ac);CHKERRQ(ierr); 18153f27d899SToby Isaac ierr = MatSetOption(Ac, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);CHKERRQ(ierr); 18163f27d899SToby Isaac ierr = PetscFree(nnz);CHKERRQ(ierr); 18173f27d899SToby Isaac ierr = PetscMalloc1(maxnnz, &iwork);CHKERRQ(ierr); 18183f27d899SToby Isaac for (i = 0; i < m; i++) { 18193f27d899SToby Isaac PetscInt innz; 18203f27d899SToby Isaac const PetscInt *cols; 18213f27d899SToby Isaac const PetscScalar *vals; 18223f27d899SToby Isaac 18233f27d899SToby Isaac ierr = MatGetRow(A, i, &innz, &cols, &vals);CHKERRQ(ierr); 18243f27d899SToby Isaac for (j = 0; j < innz; j++) iwork[j] = (cols[j] / Nk) * (Nk * Ncopies) + (cols[j] % Nk); 18253f27d899SToby Isaac for (j = 0; j < Ncopies; j++) { 18263f27d899SToby Isaac PetscInt row = i * Ncopies + j; 18273f27d899SToby Isaac 18283f27d899SToby Isaac ierr = MatSetValues(Ac, 1, &row, innz, iwork, vals, INSERT_VALUES);CHKERRQ(ierr); 18293f27d899SToby Isaac for (k = 0; k < innz; k++) iwork[k] += Nk; 18303f27d899SToby Isaac } 18313f27d899SToby Isaac ierr = MatRestoreRow(A, i, &innz, &cols, &vals);CHKERRQ(ierr); 18323f27d899SToby Isaac } 18333f27d899SToby Isaac ierr = PetscFree(iwork);CHKERRQ(ierr); 18343f27d899SToby Isaac ierr = MatAssemblyBegin(Ac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 18353f27d899SToby Isaac ierr = MatAssemblyEnd(Ac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 18363f27d899SToby Isaac *Abs = Ac; 18373f27d899SToby Isaac PetscFunctionReturn(0); 18383f27d899SToby Isaac } 18393f27d899SToby Isaac 184077f1a120SToby Isaac /* check if a cell is a tensor product of the segment with a facet, 184177f1a120SToby Isaac * specifically checking if f and f2 can be the "endpoints" (like the triangles 184277f1a120SToby Isaac * at either end of a wedge) */ 18433f27d899SToby Isaac static PetscErrorCode DMPlexPointIsTensor_Internal_Given(DM dm, PetscInt p, PetscInt f, PetscInt f2, PetscBool *isTensor) 18443f27d899SToby Isaac { 18453f27d899SToby Isaac PetscInt coneSize, c; 18463f27d899SToby Isaac const PetscInt *cone; 18473f27d899SToby Isaac const PetscInt *fCone; 18483f27d899SToby Isaac const PetscInt *f2Cone; 18493f27d899SToby Isaac PetscInt fs[2]; 18503f27d899SToby Isaac PetscInt meetSize, nmeet; 18513f27d899SToby Isaac const PetscInt *meet; 18523f27d899SToby Isaac PetscErrorCode ierr; 18533f27d899SToby Isaac 18543f27d899SToby Isaac PetscFunctionBegin; 18553f27d899SToby Isaac fs[0] = f; 18563f27d899SToby Isaac fs[1] = f2; 18573f27d899SToby Isaac ierr = DMPlexGetMeet(dm, 2, fs, &meetSize, &meet);CHKERRQ(ierr); 18583f27d899SToby Isaac nmeet = meetSize; 18593f27d899SToby Isaac ierr = DMPlexRestoreMeet(dm, 2, fs, &meetSize, &meet);CHKERRQ(ierr); 186077f1a120SToby Isaac /* two points that have a non-empty meet cannot be at opposite ends of a cell */ 18613f27d899SToby Isaac if (nmeet) { 18623f27d899SToby Isaac *isTensor = PETSC_FALSE; 18633f27d899SToby Isaac PetscFunctionReturn(0); 18643f27d899SToby Isaac } 18653f27d899SToby Isaac ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 18663f27d899SToby Isaac ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 18673f27d899SToby Isaac ierr = DMPlexGetCone(dm, f, &fCone);CHKERRQ(ierr); 18683f27d899SToby Isaac ierr = DMPlexGetCone(dm, f2, &f2Cone);CHKERRQ(ierr); 18693f27d899SToby Isaac for (c = 0; c < coneSize; c++) { 18703f27d899SToby Isaac PetscInt e, ef; 18713f27d899SToby Isaac PetscInt d = -1, d2 = -1; 18723f27d899SToby Isaac PetscInt dcount, d2count; 18733f27d899SToby Isaac PetscInt t = cone[c]; 18743f27d899SToby Isaac PetscInt tConeSize; 18753f27d899SToby Isaac PetscBool tIsTensor; 18763f27d899SToby Isaac const PetscInt *tCone; 18773f27d899SToby Isaac 18783f27d899SToby Isaac if (t == f || t == f2) continue; 187977f1a120SToby Isaac /* for every other facet in the cone, check that is has 188077f1a120SToby Isaac * one ridge in common with each end */ 18813f27d899SToby Isaac ierr = DMPlexGetConeSize(dm, t, &tConeSize);CHKERRQ(ierr); 18823f27d899SToby Isaac ierr = DMPlexGetCone(dm, t, &tCone);CHKERRQ(ierr); 18833f27d899SToby Isaac 18843f27d899SToby Isaac dcount = 0; 18853f27d899SToby Isaac d2count = 0; 18863f27d899SToby Isaac for (e = 0; e < tConeSize; e++) { 18873f27d899SToby Isaac PetscInt q = tCone[e]; 18883f27d899SToby Isaac for (ef = 0; ef < coneSize - 2; ef++) { 18893f27d899SToby Isaac if (fCone[ef] == q) { 18903f27d899SToby Isaac if (dcount) { 18913f27d899SToby Isaac *isTensor = PETSC_FALSE; 18923f27d899SToby Isaac PetscFunctionReturn(0); 18933f27d899SToby Isaac } 18943f27d899SToby Isaac d = q; 18953f27d899SToby Isaac dcount++; 18963f27d899SToby Isaac } else if (f2Cone[ef] == q) { 18973f27d899SToby Isaac if (d2count) { 18983f27d899SToby Isaac *isTensor = PETSC_FALSE; 18993f27d899SToby Isaac PetscFunctionReturn(0); 19003f27d899SToby Isaac } 19013f27d899SToby Isaac d2 = q; 19023f27d899SToby Isaac d2count++; 19033f27d899SToby Isaac } 19043f27d899SToby Isaac } 19053f27d899SToby Isaac } 190677f1a120SToby Isaac /* if the whole cell is a tensor with the segment, then this 190777f1a120SToby Isaac * facet should be a tensor with the segment */ 19083f27d899SToby Isaac ierr = DMPlexPointIsTensor_Internal_Given(dm, t, d, d2, &tIsTensor);CHKERRQ(ierr); 19093f27d899SToby Isaac if (!tIsTensor) { 19103f27d899SToby Isaac *isTensor = PETSC_FALSE; 19113f27d899SToby Isaac PetscFunctionReturn(0); 19123f27d899SToby Isaac } 19133f27d899SToby Isaac } 19143f27d899SToby Isaac *isTensor = PETSC_TRUE; 19153f27d899SToby Isaac PetscFunctionReturn(0); 19163f27d899SToby Isaac } 19173f27d899SToby Isaac 191877f1a120SToby Isaac /* determine if a cell is a tensor with a segment by looping over pairs of facets to find a pair 191977f1a120SToby Isaac * that could be the opposite ends */ 19203f27d899SToby Isaac static PetscErrorCode DMPlexPointIsTensor_Internal(DM dm, PetscInt p, PetscBool *isTensor, PetscInt *endA, PetscInt *endB) 19213f27d899SToby Isaac { 19223f27d899SToby Isaac PetscInt coneSize, c, c2; 19233f27d899SToby Isaac const PetscInt *cone; 19243f27d899SToby Isaac PetscErrorCode ierr; 19253f27d899SToby Isaac 19263f27d899SToby Isaac PetscFunctionBegin; 19273f27d899SToby Isaac ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 19283f27d899SToby Isaac if (!coneSize) { 19293f27d899SToby Isaac if (isTensor) *isTensor = PETSC_FALSE; 19303f27d899SToby Isaac if (endA) *endA = -1; 19313f27d899SToby Isaac if (endB) *endB = -1; 19323f27d899SToby Isaac } 19333f27d899SToby Isaac ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 19343f27d899SToby Isaac for (c = 0; c < coneSize; c++) { 19353f27d899SToby Isaac PetscInt f = cone[c]; 19363f27d899SToby Isaac PetscInt fConeSize; 19373f27d899SToby Isaac 19383f27d899SToby Isaac ierr = DMPlexGetConeSize(dm, f, &fConeSize);CHKERRQ(ierr); 19393f27d899SToby Isaac if (fConeSize != coneSize - 2) continue; 19403f27d899SToby Isaac 19413f27d899SToby Isaac for (c2 = c + 1; c2 < coneSize; c2++) { 19423f27d899SToby Isaac PetscInt f2 = cone[c2]; 19433f27d899SToby Isaac PetscBool isTensorff2; 19443f27d899SToby Isaac PetscInt f2ConeSize; 19453f27d899SToby Isaac 19463f27d899SToby Isaac ierr = DMPlexGetConeSize(dm, f2, &f2ConeSize);CHKERRQ(ierr); 19473f27d899SToby Isaac if (f2ConeSize != coneSize - 2) continue; 19483f27d899SToby Isaac 19493f27d899SToby Isaac ierr = DMPlexPointIsTensor_Internal_Given(dm, p, f, f2, &isTensorff2);CHKERRQ(ierr); 19503f27d899SToby Isaac if (isTensorff2) { 19513f27d899SToby Isaac if (isTensor) *isTensor = PETSC_TRUE; 19523f27d899SToby Isaac if (endA) *endA = f; 19533f27d899SToby Isaac if (endB) *endB = f2; 19543f27d899SToby Isaac PetscFunctionReturn(0); 19553f27d899SToby Isaac } 19563f27d899SToby Isaac } 19573f27d899SToby Isaac } 19583f27d899SToby Isaac if (isTensor) *isTensor = PETSC_FALSE; 19593f27d899SToby Isaac if (endA) *endA = -1; 19603f27d899SToby Isaac if (endB) *endB = -1; 19613f27d899SToby Isaac PetscFunctionReturn(0); 19623f27d899SToby Isaac } 19633f27d899SToby Isaac 196477f1a120SToby Isaac /* determine if a cell is a tensor with a segment by looping over pairs of facets to find a pair 196577f1a120SToby Isaac * that could be the opposite ends */ 19663f27d899SToby Isaac static PetscErrorCode DMPlexPointIsTensor(DM dm, PetscInt p, PetscBool *isTensor, PetscInt *endA, PetscInt *endB) 19673f27d899SToby Isaac { 19683f27d899SToby Isaac DMPlexInterpolatedFlag interpolated; 19693f27d899SToby Isaac PetscErrorCode ierr; 19703f27d899SToby Isaac 19713f27d899SToby Isaac PetscFunctionBegin; 19723f27d899SToby Isaac ierr = DMPlexIsInterpolated(dm, &interpolated);CHKERRQ(ierr); 19733f27d899SToby Isaac if (interpolated != DMPLEX_INTERPOLATED_FULL) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Only for interpolated DMPlex's"); 19743f27d899SToby Isaac ierr = DMPlexPointIsTensor_Internal(dm, p, isTensor, endA, endB);CHKERRQ(ierr); 19753f27d899SToby Isaac PetscFunctionReturn(0); 19763f27d899SToby Isaac } 19773f27d899SToby Isaac 19788f28b7bfSToby Isaac /* Let k = formDegree and k' = -sign(k) * dim + k. Transform a symmetric frame for k-forms on the biunit simplex into 19798f28b7bfSToby Isaac * a symmetric frame for k'-forms on the biunit simplex. 19801f440fbeSToby Isaac * 19818f28b7bfSToby Isaac * A frame is "symmetric" if the pullback of every symmetry of the biunit simplex is a permutation of the frame. 19821f440fbeSToby Isaac * 19838f28b7bfSToby Isaac * forms in the symmetric frame are used as dofs in the untrimmed simplex spaces. This way, symmetries of the 19848f28b7bfSToby Isaac * reference cell result in permutations of dofs grouped by node. 19851f440fbeSToby Isaac * 19868f28b7bfSToby Isaac * Use T to transform dof matrices for k'-forms into dof matrices for k-forms as a block diagonal transformation on 19878f28b7bfSToby Isaac * the right. 19881f440fbeSToby Isaac */ 19891f440fbeSToby Isaac static PetscErrorCode BiunitSimplexSymmetricFormTransformation(PetscInt dim, PetscInt formDegree, PetscReal T[]) 19901f440fbeSToby Isaac { 19911f440fbeSToby Isaac PetscInt k = formDegree; 19921f440fbeSToby Isaac PetscInt kd = k < 0 ? dim + k : k - dim; 19931f440fbeSToby Isaac PetscInt Nk; 19941f440fbeSToby Isaac PetscReal *biToEq, *eqToBi, *biToEqStar, *eqToBiStar; 19951f440fbeSToby Isaac PetscInt fact; 19961f440fbeSToby Isaac PetscErrorCode ierr; 19971f440fbeSToby Isaac 19981f440fbeSToby Isaac PetscFunctionBegin; 19991f440fbeSToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 20001f440fbeSToby Isaac ierr = PetscCalloc4(dim * dim, &biToEq, dim * dim, &eqToBi, Nk * Nk, &biToEqStar, Nk * Nk, &eqToBiStar);CHKERRQ(ierr); 20011f440fbeSToby Isaac /* fill in biToEq: Jacobian of the transformation from the biunit simplex to the equilateral simplex */ 20021f440fbeSToby Isaac fact = 0; 20031f440fbeSToby Isaac for (PetscInt i = 0; i < dim; i++) { 20041f440fbeSToby Isaac biToEq[i * dim + i] = PetscSqrtReal(((PetscReal)i + 2.) / (2.*((PetscReal)i+1.))); 20051f440fbeSToby Isaac fact += 4*(i+1); 20061f440fbeSToby Isaac for (PetscInt j = i+1; j < dim; j++) { 20071f440fbeSToby Isaac biToEq[i * dim + j] = PetscSqrtReal(1./(PetscReal)fact); 20081f440fbeSToby Isaac } 20091f440fbeSToby Isaac } 20108f28b7bfSToby Isaac /* fill in eqToBi: Jacobian of the transformation from the equilateral simplex to the biunit simplex */ 20111f440fbeSToby Isaac fact = 0; 20121f440fbeSToby Isaac for (PetscInt j = 0; j < dim; j++) { 20131f440fbeSToby Isaac eqToBi[j * dim + j] = PetscSqrtReal(2.*((PetscReal)j+1.)/((PetscReal)j+2)); 20141f440fbeSToby Isaac fact += j+1; 20151f440fbeSToby Isaac for (PetscInt i = 0; i < j; i++) { 20161f440fbeSToby Isaac eqToBi[i * dim + j] = -PetscSqrtReal(1./(PetscReal)fact); 20171f440fbeSToby Isaac } 20181f440fbeSToby Isaac } 20191f440fbeSToby Isaac ierr = PetscDTAltVPullbackMatrix(dim, dim, biToEq, kd, biToEqStar);CHKERRQ(ierr); 20201f440fbeSToby Isaac ierr = PetscDTAltVPullbackMatrix(dim, dim, eqToBi, k, eqToBiStar);CHKERRQ(ierr); 20218f28b7bfSToby Isaac /* product of pullbacks simulates the following steps 20228f28b7bfSToby Isaac * 20238f28b7bfSToby Isaac * 1. start with frame W = [w_1, w_2, ..., w_m] of k forms that is symmetric on the biunit simplex: 20248f28b7bfSToby Isaac if J is the Jacobian of a symmetry of the biunit simplex, then J_k* W = [J_k*w_1, ..., J_k*w_m] 20258f28b7bfSToby Isaac is a permutation of W. 20268f28b7bfSToby Isaac Even though a k' form --- a (dim - k) form represented by its Hodge star --- has the same geometric 20278f28b7bfSToby Isaac content as a k form, W is not a symmetric frame of k' forms on the biunit simplex. That's because, 20288f28b7bfSToby Isaac for general Jacobian J, J_k* != J_k'*. 20298f28b7bfSToby Isaac * 2. pullback W to the equilateral triangle using the k pullback, W_eq = eqToBi_k* W. All symmetries of the 20308f28b7bfSToby Isaac equilateral simplex have orthonormal Jacobians. For an orthonormal Jacobian O, J_k* = J_k'*, so W_eq is 20318f28b7bfSToby Isaac also a symmetric frame for k' forms on the equilateral simplex. 20328f28b7bfSToby Isaac 3. pullback W_eq back to the biunit simplex using the k' pulback, V = biToEq_k'* W_eq = biToEq_k'* eqToBi_k* W. 20338f28b7bfSToby Isaac V is a symmetric frame for k' forms on the biunit simplex. 20348f28b7bfSToby Isaac */ 20351f440fbeSToby Isaac for (PetscInt i = 0; i < Nk; i++) { 20361f440fbeSToby Isaac for (PetscInt j = 0; j < Nk; j++) { 20371f440fbeSToby Isaac PetscReal val = 0.; 20381f440fbeSToby Isaac for (PetscInt k = 0; k < Nk; k++) val += biToEqStar[i * Nk + k] * eqToBiStar[k * Nk + j]; 20391f440fbeSToby Isaac T[i * Nk + j] = val; 20401f440fbeSToby Isaac } 20411f440fbeSToby Isaac } 20421f440fbeSToby Isaac ierr = PetscFree4(biToEq, eqToBi, biToEqStar, eqToBiStar);CHKERRQ(ierr); 20431f440fbeSToby Isaac PetscFunctionReturn(0); 20441f440fbeSToby Isaac } 20451f440fbeSToby Isaac 204677f1a120SToby Isaac /* permute a quadrature -> dof matrix so that its rows are in revlex order by nodeIdx */ 20473f27d899SToby Isaac static PetscErrorCode MatPermuteByNodeIdx(Mat A, PetscLagNodeIndices ni, Mat *Aperm) 20483f27d899SToby Isaac { 20493f27d899SToby Isaac PetscInt m, n, i, j; 20503f27d899SToby Isaac PetscInt nodeIdxDim = ni->nodeIdxDim; 20513f27d899SToby Isaac PetscInt nodeVecDim = ni->nodeVecDim; 20523f27d899SToby Isaac PetscInt *perm; 20533f27d899SToby Isaac IS permIS; 20543f27d899SToby Isaac IS id; 20553f27d899SToby Isaac PetscInt *nIdxPerm; 20563f27d899SToby Isaac PetscReal *nVecPerm; 20573f27d899SToby Isaac PetscErrorCode ierr; 20583f27d899SToby Isaac 20593f27d899SToby Isaac PetscFunctionBegin; 20603f27d899SToby Isaac ierr = PetscLagNodeIndicesGetPermutation(ni, &perm);CHKERRQ(ierr); 20613f27d899SToby Isaac ierr = MatGetSize(A, &m, &n);CHKERRQ(ierr); 20623f27d899SToby Isaac ierr = PetscMalloc1(nodeIdxDim * m, &nIdxPerm);CHKERRQ(ierr); 20633f27d899SToby Isaac ierr = PetscMalloc1(nodeVecDim * m, &nVecPerm);CHKERRQ(ierr); 20643f27d899SToby Isaac for (i = 0; i < m; i++) for (j = 0; j < nodeIdxDim; j++) nIdxPerm[i * nodeIdxDim + j] = ni->nodeIdx[perm[i] * nodeIdxDim + j]; 20653f27d899SToby Isaac for (i = 0; i < m; i++) for (j = 0; j < nodeVecDim; j++) nVecPerm[i * nodeVecDim + j] = ni->nodeVec[perm[i] * nodeVecDim + j]; 20663f27d899SToby Isaac ierr = ISCreateGeneral(PETSC_COMM_SELF, m, perm, PETSC_USE_POINTER, &permIS);CHKERRQ(ierr); 20673f27d899SToby Isaac ierr = ISSetPermutation(permIS);CHKERRQ(ierr); 20683f27d899SToby Isaac ierr = ISCreateStride(PETSC_COMM_SELF, n, 0, 1, &id);CHKERRQ(ierr); 20693f27d899SToby Isaac ierr = ISSetPermutation(id);CHKERRQ(ierr); 20703f27d899SToby Isaac ierr = MatPermute(A, permIS, id, Aperm);CHKERRQ(ierr); 20713f27d899SToby Isaac ierr = ISDestroy(&permIS);CHKERRQ(ierr); 20723f27d899SToby Isaac ierr = ISDestroy(&id);CHKERRQ(ierr); 20733f27d899SToby Isaac for (i = 0; i < m; i++) perm[i] = i; 20743f27d899SToby Isaac ierr = PetscFree(ni->nodeIdx);CHKERRQ(ierr); 20753f27d899SToby Isaac ierr = PetscFree(ni->nodeVec);CHKERRQ(ierr); 20763f27d899SToby Isaac ni->nodeIdx = nIdxPerm; 20773f27d899SToby Isaac ni->nodeVec = nVecPerm; 20786f905325SMatthew G. Knepley PetscFunctionReturn(0); 20796f905325SMatthew G. Knepley } 20806f905325SMatthew G. Knepley 20816f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceSetUp_Lagrange(PetscDualSpace sp) 20826f905325SMatthew G. Knepley { 20836f905325SMatthew G. Knepley PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 20846f905325SMatthew G. Knepley DM dm = sp->dm; 20853f27d899SToby Isaac DM dmint = NULL; 20863f27d899SToby Isaac PetscInt order; 20876f905325SMatthew G. Knepley PetscInt Nc = sp->Nc; 20886f905325SMatthew G. Knepley MPI_Comm comm; 20896f905325SMatthew G. Knepley PetscBool continuous; 20903f27d899SToby Isaac PetscSection section; 20913f27d899SToby Isaac PetscInt depth, dim, pStart, pEnd, cStart, cEnd, p, *pStratStart, *pStratEnd, d; 20923f27d899SToby Isaac PetscInt formDegree, Nk, Ncopies; 20933f27d899SToby Isaac PetscInt tensorf = -1, tensorf2 = -1; 20943f27d899SToby Isaac PetscBool tensorCell, tensorSpace; 20953f27d899SToby Isaac PetscBool uniform, trimmed; 20963f27d899SToby Isaac Petsc1DNodeFamily nodeFamily; 20973f27d899SToby Isaac PetscInt numNodeSkip; 20983f27d899SToby Isaac DMPlexInterpolatedFlag interpolated; 20993f27d899SToby Isaac PetscBool isbdm; 21006f905325SMatthew G. Knepley PetscErrorCode ierr; 21016f905325SMatthew G. Knepley 21026f905325SMatthew G. Knepley PetscFunctionBegin; 21033f27d899SToby Isaac /* step 1: sanitize input */ 21046f905325SMatthew G. Knepley ierr = PetscObjectGetComm((PetscObject) sp, &comm);CHKERRQ(ierr); 21056f905325SMatthew G. Knepley ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2106efac50ffSToby Isaac ierr = PetscObjectTypeCompare((PetscObject)sp, PETSCDUALSPACEBDM, &isbdm);CHKERRQ(ierr); 21073f27d899SToby Isaac if (isbdm) { 21083f27d899SToby Isaac sp->k = -(dim-1); /* form degree of H-div */ 21093f27d899SToby Isaac ierr = PetscObjectChangeTypeName((PetscObject)sp, PETSCDUALSPACELAGRANGE);CHKERRQ(ierr); 21103f27d899SToby Isaac } 21113f27d899SToby Isaac ierr = PetscDualSpaceGetFormDegree(sp, &formDegree);CHKERRQ(ierr); 21123f27d899SToby Isaac if (PetscAbsInt(formDegree) > dim) SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Form degree must be bounded by dimension"); 21133f27d899SToby Isaac ierr = PetscDTBinomialInt(dim,PetscAbsInt(formDegree),&Nk);CHKERRQ(ierr); 21143f27d899SToby Isaac if (sp->Nc <= 0 && lag->numCopies > 0) sp->Nc = Nk * lag->numCopies; 21153f27d899SToby Isaac Nc = sp->Nc; 21163f27d899SToby Isaac if (Nc % Nk) SETERRQ(comm, PETSC_ERR_ARG_INCOMP, "Number of components is not a multiple of form degree size"); 21173f27d899SToby Isaac if (lag->numCopies <= 0) lag->numCopies = Nc / Nk; 21183f27d899SToby Isaac Ncopies = lag->numCopies; 21193f27d899SToby Isaac if (Nc / Nk != Ncopies) SETERRQ(comm, PETSC_ERR_ARG_INCOMP, "Number of copies * (dim choose k) != Nc"); 21203f27d899SToby Isaac if (!dim) sp->order = 0; 21213f27d899SToby Isaac order = sp->order; 21223f27d899SToby Isaac uniform = sp->uniform; 21233f27d899SToby Isaac if (!uniform) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Variable order not supported yet"); 21243f27d899SToby Isaac if (lag->trimmed && !formDegree) lag->trimmed = PETSC_FALSE; /* trimmed spaces are the same as full spaces for 0-forms */ 21253f27d899SToby Isaac if (lag->nodeType == PETSCDTNODES_DEFAULT) { 21263f27d899SToby Isaac lag->nodeType = PETSCDTNODES_GAUSSJACOBI; 21273f27d899SToby Isaac lag->nodeExponent = 0.; 21283f27d899SToby Isaac /* trimmed spaces don't include corner vertices, so don't use end nodes by default */ 21293f27d899SToby Isaac lag->endNodes = lag->trimmed ? PETSC_FALSE : PETSC_TRUE; 21303f27d899SToby Isaac } 21313f27d899SToby Isaac /* If a trimmed space and the user did choose nodes with endpoints, skip them by default */ 21323f27d899SToby Isaac if (lag->numNodeSkip < 0) lag->numNodeSkip = (lag->trimmed && lag->endNodes) ? 1 : 0; 21333f27d899SToby Isaac numNodeSkip = lag->numNodeSkip; 21343f27d899SToby Isaac if (lag->trimmed && !order) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot have zeroth order trimmed elements"); 21353f27d899SToby Isaac if (lag->trimmed && PetscAbsInt(formDegree) == dim) { /* convert trimmed n-forms to untrimmed of one polynomial order less */ 21363f27d899SToby Isaac sp->order--; 21373f27d899SToby Isaac order--; 21383f27d899SToby Isaac lag->trimmed = PETSC_FALSE; 21393f27d899SToby Isaac } 21403f27d899SToby Isaac trimmed = lag->trimmed; 21413f27d899SToby Isaac if (!order || PetscAbsInt(formDegree) == dim) lag->continuous = PETSC_FALSE; 21423f27d899SToby Isaac continuous = lag->continuous; 21436f905325SMatthew G. Knepley ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 21446f905325SMatthew G. Knepley ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 21453f27d899SToby Isaac ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 21463f27d899SToby Isaac if (pStart != 0 || cStart != 0) SETERRQ(PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Expect DM with chart starting at zero and cells first"); 21473f27d899SToby Isaac if (cEnd != 1) SETERRQ(PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Use PETSCDUALSPACEREFINED for multi-cell reference meshes"); 21483f27d899SToby Isaac ierr = DMPlexIsInterpolated(dm, &interpolated);CHKERRQ(ierr); 21493f27d899SToby Isaac if (interpolated != DMPLEX_INTERPOLATED_FULL) { 21503f27d899SToby Isaac ierr = DMPlexInterpolate(dm, &dmint);CHKERRQ(ierr); 21513f27d899SToby Isaac } else { 21523f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)dm);CHKERRQ(ierr); 21533f27d899SToby Isaac dmint = dm; 21543f27d899SToby Isaac } 21553f27d899SToby Isaac tensorCell = PETSC_FALSE; 21563f27d899SToby Isaac if (dim > 1) { 21573f27d899SToby Isaac ierr = DMPlexPointIsTensor(dmint, 0, &tensorCell, &tensorf, &tensorf2);CHKERRQ(ierr); 21583f27d899SToby Isaac } 21593f27d899SToby Isaac lag->tensorCell = tensorCell; 21603f27d899SToby Isaac if (dim < 2 || !lag->tensorCell) lag->tensorSpace = PETSC_FALSE; 21616f905325SMatthew G. Knepley tensorSpace = lag->tensorSpace; 21623f27d899SToby Isaac if (!lag->nodeFamily) { 21633f27d899SToby Isaac ierr = Petsc1DNodeFamilyCreate(lag->nodeType, lag->nodeExponent, lag->endNodes, &lag->nodeFamily);CHKERRQ(ierr); 21643f27d899SToby Isaac } 21653f27d899SToby Isaac nodeFamily = lag->nodeFamily; 21663f27d899SToby Isaac if (interpolated != DMPLEX_INTERPOLATED_FULL && continuous && (PetscAbsInt(formDegree) > 0 || order > 1)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Reference element won't support all boundary nodes"); 216720cf1dd8SToby Isaac 21683f27d899SToby Isaac /* step 2: construct the boundary spaces */ 21693f27d899SToby Isaac ierr = PetscMalloc2(depth+1,&pStratStart,depth+1,&pStratEnd);CHKERRQ(ierr); 21703f27d899SToby Isaac ierr = PetscCalloc1(pEnd,&(sp->pointSpaces));CHKERRQ(ierr); 21713f27d899SToby Isaac for (d = 0; d <= depth; ++d) {ierr = DMPlexGetDepthStratum(dm, d, &pStratStart[d], &pStratEnd[d]);CHKERRQ(ierr);} 21723f27d899SToby Isaac ierr = PetscDualSpaceSectionCreate_Internal(sp, §ion);CHKERRQ(ierr); 21733f27d899SToby Isaac sp->pointSection = section; 21743f27d899SToby Isaac if (continuous && !(lag->interiorOnly)) { 21753f27d899SToby Isaac PetscInt h; 21766f905325SMatthew G. Knepley 21773f27d899SToby Isaac for (p = pStratStart[depth - 1]; p < pStratEnd[depth - 1]; p++) { /* calculate the facet dual spaces */ 21783f27d899SToby Isaac PetscReal v0[3]; 21793f27d899SToby Isaac DMPolytopeType ptype; 21803f27d899SToby Isaac PetscReal J[9], detJ; 21816f905325SMatthew G. Knepley PetscInt q; 21826f905325SMatthew G. Knepley 21833f27d899SToby Isaac ierr = DMPlexComputeCellGeometryAffineFEM(dm, p, v0, J, NULL, &detJ);CHKERRQ(ierr); 21843f27d899SToby Isaac ierr = DMPlexGetCellType(dm, p, &ptype);CHKERRQ(ierr); 21856f905325SMatthew G. Knepley 218677f1a120SToby Isaac /* compare to previous facets: if computed, reference that dualspace */ 21873f27d899SToby Isaac for (q = pStratStart[depth - 1]; q < p; q++) { 21883f27d899SToby Isaac DMPolytopeType qtype; 21896f905325SMatthew G. Knepley 21903f27d899SToby Isaac ierr = DMPlexGetCellType(dm, q, &qtype);CHKERRQ(ierr); 21913f27d899SToby Isaac if (qtype == ptype) break; 21926f905325SMatthew G. Knepley } 21933f27d899SToby Isaac if (q < p) { /* this facet has the same dual space as that one */ 21943f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)sp->pointSpaces[q]);CHKERRQ(ierr); 21953f27d899SToby Isaac sp->pointSpaces[p] = sp->pointSpaces[q]; 21963f27d899SToby Isaac continue; 21976f905325SMatthew G. Knepley } 21983f27d899SToby Isaac /* if not, recursively compute this dual space */ 21993f27d899SToby Isaac ierr = PetscDualSpaceCreateFacetSubspace_Lagrange(sp,NULL,p,formDegree,Ncopies,PETSC_FALSE,&sp->pointSpaces[p]);CHKERRQ(ierr); 22006f905325SMatthew G. Knepley } 22013f27d899SToby Isaac for (h = 2; h <= depth; h++) { /* get the higher subspaces from the facet subspaces */ 22023f27d899SToby Isaac PetscInt hd = depth - h; 22033f27d899SToby Isaac PetscInt hdim = dim - h; 22046f905325SMatthew G. Knepley 22053f27d899SToby Isaac if (hdim < PetscAbsInt(formDegree)) break; 22063f27d899SToby Isaac for (p = pStratStart[hd]; p < pStratEnd[hd]; p++) { 22073f27d899SToby Isaac PetscInt suppSize, s; 22083f27d899SToby Isaac const PetscInt *supp; 22096f905325SMatthew G. Knepley 22103f27d899SToby Isaac ierr = DMPlexGetSupportSize(dm, p, &suppSize);CHKERRQ(ierr); 22113f27d899SToby Isaac ierr = DMPlexGetSupport(dm, p, &supp);CHKERRQ(ierr); 22123f27d899SToby Isaac for (s = 0; s < suppSize; s++) { 22133f27d899SToby Isaac DM qdm; 22143f27d899SToby Isaac PetscDualSpace qsp, psp; 22153f27d899SToby Isaac PetscInt c, coneSize, q; 22163f27d899SToby Isaac const PetscInt *cone; 22173f27d899SToby Isaac const PetscInt *refCone; 22186f905325SMatthew G. Knepley 22193f27d899SToby Isaac q = supp[0]; 22203f27d899SToby Isaac qsp = sp->pointSpaces[q]; 22213f27d899SToby Isaac ierr = DMPlexGetConeSize(dm, q, &coneSize);CHKERRQ(ierr); 22223f27d899SToby Isaac ierr = DMPlexGetCone(dm, q, &cone);CHKERRQ(ierr); 22233f27d899SToby Isaac for (c = 0; c < coneSize; c++) if (cone[c] == p) break; 22242479783cSJose E. Roman if (c == coneSize) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "cone/support mismatch"); 22253f27d899SToby Isaac ierr = PetscDualSpaceGetDM(qsp, &qdm);CHKERRQ(ierr); 22263f27d899SToby Isaac ierr = DMPlexGetCone(qdm, 0, &refCone);CHKERRQ(ierr); 22273f27d899SToby Isaac /* get the equivalent dual space from the support dual space */ 22283f27d899SToby Isaac ierr = PetscDualSpaceGetPointSubspace(qsp, refCone[c], &psp);CHKERRQ(ierr); 22293f27d899SToby Isaac if (!s) { 22303f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)psp);CHKERRQ(ierr); 22313f27d899SToby Isaac sp->pointSpaces[p] = psp; 22323f27d899SToby Isaac } 22333f27d899SToby Isaac } 22343f27d899SToby Isaac } 22353f27d899SToby Isaac } 22363f27d899SToby Isaac for (p = 1; p < pEnd; p++) { 22373f27d899SToby Isaac PetscInt pspdim; 22383f27d899SToby Isaac if (!sp->pointSpaces[p]) continue; 22393f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorDimension(sp->pointSpaces[p], &pspdim);CHKERRQ(ierr); 22403f27d899SToby Isaac ierr = PetscSectionSetDof(section, p, pspdim);CHKERRQ(ierr); 22413f27d899SToby Isaac } 22423f27d899SToby Isaac } 22436f905325SMatthew G. Knepley 22443f27d899SToby Isaac if (Ncopies > 1) { 22453f27d899SToby Isaac Mat intMatScalar, allMatScalar; 22463f27d899SToby Isaac PetscDualSpace scalarsp; 22473f27d899SToby Isaac PetscDualSpace_Lag *scalarlag; 22483f27d899SToby Isaac 22493f27d899SToby Isaac ierr = PetscDualSpaceDuplicate(sp, &scalarsp);CHKERRQ(ierr); 225077f1a120SToby Isaac /* Setting the number of components to Nk is a space with 1 copy of each k-form */ 22513f27d899SToby Isaac ierr = PetscDualSpaceSetNumComponents(scalarsp, Nk);CHKERRQ(ierr); 22523f27d899SToby Isaac ierr = PetscDualSpaceSetUp(scalarsp);CHKERRQ(ierr); 22533f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorData(scalarsp, &(sp->intNodes), &intMatScalar);CHKERRQ(ierr); 22543f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)(sp->intNodes));CHKERRQ(ierr); 22553f27d899SToby Isaac if (intMatScalar) {ierr = PetscDualSpaceLagrangeMatrixCreateCopies(intMatScalar, Nk, Ncopies, &(sp->intMat));CHKERRQ(ierr);} 22563f27d899SToby Isaac ierr = PetscDualSpaceGetAllData(scalarsp, &(sp->allNodes), &allMatScalar);CHKERRQ(ierr); 22573f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)(sp->allNodes));CHKERRQ(ierr); 22583f27d899SToby Isaac ierr = PetscDualSpaceLagrangeMatrixCreateCopies(allMatScalar, Nk, Ncopies, &(sp->allMat));CHKERRQ(ierr); 22593f27d899SToby Isaac sp->spdim = scalarsp->spdim * Ncopies; 22603f27d899SToby Isaac sp->spintdim = scalarsp->spintdim * Ncopies; 22613f27d899SToby Isaac scalarlag = (PetscDualSpace_Lag *) scalarsp->data; 22623f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(scalarlag->vertIndices);CHKERRQ(ierr); 22633f27d899SToby Isaac lag->vertIndices = scalarlag->vertIndices; 22643f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(scalarlag->intNodeIndices);CHKERRQ(ierr); 22653f27d899SToby Isaac lag->intNodeIndices = scalarlag->intNodeIndices; 22663f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(scalarlag->allNodeIndices);CHKERRQ(ierr); 22673f27d899SToby Isaac lag->allNodeIndices = scalarlag->allNodeIndices; 22683f27d899SToby Isaac ierr = PetscDualSpaceDestroy(&scalarsp);CHKERRQ(ierr); 22693f27d899SToby Isaac ierr = PetscSectionSetDof(section, 0, sp->spintdim);CHKERRQ(ierr); 22703f27d899SToby Isaac ierr = PetscDualSpaceSectionSetUp_Internal(sp, section);CHKERRQ(ierr); 22713f27d899SToby Isaac ierr = PetscDualSpaceComputeFunctionalsFromAllData(sp);CHKERRQ(ierr); 22726f905325SMatthew G. Knepley ierr = PetscFree2(pStratStart, pStratEnd);CHKERRQ(ierr); 22733f27d899SToby Isaac ierr = DMDestroy(&dmint);CHKERRQ(ierr); 227420cf1dd8SToby Isaac PetscFunctionReturn(0); 227520cf1dd8SToby Isaac } 227620cf1dd8SToby Isaac 22773f27d899SToby Isaac if (trimmed && !continuous) { 22783f27d899SToby Isaac /* the dofs of a trimmed space don't have a nice tensor/lattice structure: 22793f27d899SToby Isaac * just construct the continuous dual space and copy all of the data over, 22803f27d899SToby Isaac * allocating it all to the cell instead of splitting it up between the boundaries */ 22813f27d899SToby Isaac PetscDualSpace spcont; 22823f27d899SToby Isaac PetscInt spdim, f; 22833f27d899SToby Isaac PetscQuadrature allNodes; 22843f27d899SToby Isaac PetscDualSpace_Lag *lagc; 22853f27d899SToby Isaac Mat allMat; 22863f27d899SToby Isaac 22873f27d899SToby Isaac ierr = PetscDualSpaceDuplicate(sp, &spcont);CHKERRQ(ierr); 22883f27d899SToby Isaac ierr = PetscDualSpaceLagrangeSetContinuity(spcont, PETSC_TRUE);CHKERRQ(ierr); 22893f27d899SToby Isaac ierr = PetscDualSpaceSetUp(spcont);CHKERRQ(ierr); 22903f27d899SToby Isaac ierr = PetscDualSpaceGetDimension(spcont, &spdim);CHKERRQ(ierr); 22913f27d899SToby Isaac sp->spdim = sp->spintdim = spdim; 22923f27d899SToby Isaac ierr = PetscSectionSetDof(section, 0, spdim);CHKERRQ(ierr); 22933f27d899SToby Isaac ierr = PetscDualSpaceSectionSetUp_Internal(sp, section);CHKERRQ(ierr); 22943f27d899SToby Isaac ierr = PetscMalloc1(spdim, &(sp->functional));CHKERRQ(ierr); 22953f27d899SToby Isaac for (f = 0; f < spdim; f++) { 22963f27d899SToby Isaac PetscQuadrature fn; 22973f27d899SToby Isaac 22983f27d899SToby Isaac ierr = PetscDualSpaceGetFunctional(spcont, f, &fn);CHKERRQ(ierr); 22993f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)fn);CHKERRQ(ierr); 23003f27d899SToby Isaac sp->functional[f] = fn; 23013f27d899SToby Isaac } 23023f27d899SToby Isaac ierr = PetscDualSpaceGetAllData(spcont, &allNodes, &allMat);CHKERRQ(ierr); 23033f27d899SToby Isaac ierr = PetscObjectReference((PetscObject) allNodes);CHKERRQ(ierr); 23043f27d899SToby Isaac ierr = PetscObjectReference((PetscObject) allNodes);CHKERRQ(ierr); 23053f27d899SToby Isaac sp->allNodes = sp->intNodes = allNodes; 23063f27d899SToby Isaac ierr = PetscObjectReference((PetscObject) allMat);CHKERRQ(ierr); 23073f27d899SToby Isaac ierr = PetscObjectReference((PetscObject) allMat);CHKERRQ(ierr); 23083f27d899SToby Isaac sp->allMat = sp->intMat = allMat; 23093f27d899SToby Isaac lagc = (PetscDualSpace_Lag *) spcont->data; 23103f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(lagc->vertIndices);CHKERRQ(ierr); 23113f27d899SToby Isaac lag->vertIndices = lagc->vertIndices; 23123f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(lagc->allNodeIndices);CHKERRQ(ierr); 23133f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(lagc->allNodeIndices);CHKERRQ(ierr); 23143f27d899SToby Isaac lag->intNodeIndices = lagc->allNodeIndices; 23153f27d899SToby Isaac lag->allNodeIndices = lagc->allNodeIndices; 23163f27d899SToby Isaac ierr = PetscDualSpaceDestroy(&spcont);CHKERRQ(ierr); 23173f27d899SToby Isaac ierr = PetscFree2(pStratStart, pStratEnd);CHKERRQ(ierr); 23183f27d899SToby Isaac ierr = DMDestroy(&dmint);CHKERRQ(ierr); 23193f27d899SToby Isaac PetscFunctionReturn(0); 23203f27d899SToby Isaac } 23213f27d899SToby Isaac 23223f27d899SToby Isaac /* step 3: construct intNodes, and intMat, and combine it with boundray data to make allNodes and allMat */ 23233f27d899SToby Isaac if (!tensorSpace) { 23246ff15688SToby Isaac if (!tensorCell) {ierr = PetscLagNodeIndicesCreateSimplexVertices(dm, &(lag->vertIndices));CHKERRQ(ierr);} 23253f27d899SToby Isaac 23263f27d899SToby Isaac if (trimmed) { 232777f1a120SToby Isaac /* there is one dof in the interior of the a trimmed element for each full polynomial of with degree at most 232877f1a120SToby Isaac * order + k - dim - 1 */ 23293f27d899SToby Isaac if (order + PetscAbsInt(formDegree) > dim) { 23303f27d899SToby Isaac PetscInt sum = order + PetscAbsInt(formDegree) - dim - 1; 23313f27d899SToby Isaac PetscInt nDofs; 23323f27d899SToby Isaac 23333f27d899SToby Isaac ierr = PetscDualSpaceLagrangeCreateSimplexNodeMat(nodeFamily, dim, sum, Nk, numNodeSkip, &sp->intNodes, &sp->intMat, &(lag->intNodeIndices));CHKERRQ(ierr); 23343f27d899SToby Isaac ierr = MatGetSize(sp->intMat, &nDofs, NULL);CHKERRQ(ierr); 23353f27d899SToby Isaac ierr = PetscSectionSetDof(section, 0, nDofs);CHKERRQ(ierr); 23363f27d899SToby Isaac } 23373f27d899SToby Isaac ierr = PetscDualSpaceSectionSetUp_Internal(sp, section);CHKERRQ(ierr); 23383f27d899SToby Isaac ierr = PetscDualSpaceCreateAllDataFromInteriorData(sp);CHKERRQ(ierr); 23393f27d899SToby Isaac ierr = PetscDualSpaceLagrangeCreateAllNodeIdx(sp);CHKERRQ(ierr); 23403f27d899SToby Isaac } else { 23413f27d899SToby Isaac if (!continuous) { 234277f1a120SToby Isaac /* if discontinuous just construct one node for each set of dofs (a set of dofs is a basis for the k-form 234377f1a120SToby Isaac * space) */ 23443f27d899SToby Isaac PetscInt sum = order; 23453f27d899SToby Isaac PetscInt nDofs; 23463f27d899SToby Isaac 23473f27d899SToby Isaac ierr = PetscDualSpaceLagrangeCreateSimplexNodeMat(nodeFamily, dim, sum, Nk, numNodeSkip, &sp->intNodes, &sp->intMat, &(lag->intNodeIndices));CHKERRQ(ierr); 23483f27d899SToby Isaac ierr = MatGetSize(sp->intMat, &nDofs, NULL);CHKERRQ(ierr); 23493f27d899SToby Isaac ierr = PetscSectionSetDof(section, 0, nDofs);CHKERRQ(ierr); 23503f27d899SToby Isaac ierr = PetscDualSpaceSectionSetUp_Internal(sp, section);CHKERRQ(ierr); 23513f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)(sp->intNodes));CHKERRQ(ierr); 23523f27d899SToby Isaac sp->allNodes = sp->intNodes; 23533f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)(sp->intMat));CHKERRQ(ierr); 23543f27d899SToby Isaac sp->allMat = sp->intMat; 23553f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(lag->intNodeIndices);CHKERRQ(ierr); 23563f27d899SToby Isaac lag->allNodeIndices = lag->intNodeIndices; 23573f27d899SToby Isaac } else { 235877f1a120SToby Isaac /* there is one dof in the interior of the a full element for each trimmed polynomial of with degree at most 235977f1a120SToby Isaac * order + k - dim, but with complementary form degree */ 23603f27d899SToby Isaac if (order + PetscAbsInt(formDegree) > dim) { 23613f27d899SToby Isaac PetscDualSpace trimmedsp; 23623f27d899SToby Isaac PetscDualSpace_Lag *trimmedlag; 23633f27d899SToby Isaac PetscQuadrature intNodes; 23643f27d899SToby Isaac PetscInt trFormDegree = formDegree >= 0 ? formDegree - dim : dim - PetscAbsInt(formDegree); 23653f27d899SToby Isaac PetscInt nDofs; 23663f27d899SToby Isaac Mat intMat; 23673f27d899SToby Isaac 23683f27d899SToby Isaac ierr = PetscDualSpaceDuplicate(sp, &trimmedsp);CHKERRQ(ierr); 23693f27d899SToby Isaac ierr = PetscDualSpaceLagrangeSetTrimmed(trimmedsp, PETSC_TRUE);CHKERRQ(ierr); 23703f27d899SToby Isaac ierr = PetscDualSpaceSetOrder(trimmedsp, order + PetscAbsInt(formDegree) - dim);CHKERRQ(ierr); 23713f27d899SToby Isaac ierr = PetscDualSpaceSetFormDegree(trimmedsp, trFormDegree);CHKERRQ(ierr); 23723f27d899SToby Isaac trimmedlag = (PetscDualSpace_Lag *) trimmedsp->data; 23733f27d899SToby Isaac trimmedlag->numNodeSkip = numNodeSkip + 1; 23743f27d899SToby Isaac ierr = PetscDualSpaceSetUp(trimmedsp);CHKERRQ(ierr); 23753f27d899SToby Isaac ierr = PetscDualSpaceGetAllData(trimmedsp, &intNodes, &intMat);CHKERRQ(ierr); 23763f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)intNodes);CHKERRQ(ierr); 23773f27d899SToby Isaac sp->intNodes = intNodes; 23783f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(trimmedlag->allNodeIndices);CHKERRQ(ierr); 23793f27d899SToby Isaac lag->intNodeIndices = trimmedlag->allNodeIndices; 23801f440fbeSToby Isaac ierr = PetscObjectReference((PetscObject)intMat);CHKERRQ(ierr); 23811f440fbeSToby Isaac if (PetscAbsInt(formDegree) > 0 && PetscAbsInt(formDegree) < dim) { 23821f440fbeSToby Isaac PetscReal *T; 23831f440fbeSToby Isaac PetscScalar *work; 23841f440fbeSToby Isaac PetscInt nCols, nRows; 23851f440fbeSToby Isaac Mat intMatT; 23861f440fbeSToby Isaac 23871f440fbeSToby Isaac ierr = MatDuplicate(intMat, MAT_COPY_VALUES, &intMatT);CHKERRQ(ierr); 23881f440fbeSToby Isaac ierr = MatGetSize(intMat, &nRows, &nCols);CHKERRQ(ierr); 23891f440fbeSToby Isaac ierr = PetscMalloc2(Nk * Nk, &T, nCols, &work);CHKERRQ(ierr); 23901f440fbeSToby Isaac ierr = BiunitSimplexSymmetricFormTransformation(dim, formDegree, T);CHKERRQ(ierr); 23911f440fbeSToby Isaac for (PetscInt row = 0; row < nRows; row++) { 23921f440fbeSToby Isaac PetscInt nrCols; 23931f440fbeSToby Isaac const PetscInt *rCols; 23941f440fbeSToby Isaac const PetscScalar *rVals; 23951f440fbeSToby Isaac 23961f440fbeSToby Isaac ierr = MatGetRow(intMat, row, &nrCols, &rCols, &rVals);CHKERRQ(ierr); 23971f440fbeSToby Isaac if (nrCols % Nk) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "nonzeros in intMat matrix are not in k-form size blocks"); 23981f440fbeSToby Isaac for (PetscInt b = 0; b < nrCols; b += Nk) { 23991f440fbeSToby Isaac const PetscScalar *v = &rVals[b]; 24001f440fbeSToby Isaac PetscScalar *w = &work[b]; 24011f440fbeSToby Isaac for (PetscInt j = 0; j < Nk; j++) { 24021f440fbeSToby Isaac w[j] = 0.; 24031f440fbeSToby Isaac for (PetscInt i = 0; i < Nk; i++) { 24041f440fbeSToby Isaac w[j] += v[i] * T[i * Nk + j]; 24051f440fbeSToby Isaac } 24061f440fbeSToby Isaac } 24071f440fbeSToby Isaac } 24081f440fbeSToby Isaac ierr = MatSetValuesBlocked(intMatT, 1, &row, nrCols, rCols, work, INSERT_VALUES);CHKERRQ(ierr); 24091f440fbeSToby Isaac ierr = MatRestoreRow(intMat, row, &nrCols, &rCols, &rVals);CHKERRQ(ierr); 24101f440fbeSToby Isaac } 24111f440fbeSToby Isaac ierr = MatAssemblyBegin(intMatT, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 24121f440fbeSToby Isaac ierr = MatAssemblyEnd(intMatT, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 24131f440fbeSToby Isaac ierr = MatDestroy(&intMat);CHKERRQ(ierr); 24141f440fbeSToby Isaac intMat = intMatT; 24151f440fbeSToby Isaac ierr = PetscLagNodeIndicesDestroy(&(lag->intNodeIndices));CHKERRQ(ierr); 24161f440fbeSToby Isaac ierr = PetscLagNodeIndicesDuplicate(trimmedlag->allNodeIndices, &(lag->intNodeIndices));CHKERRQ(ierr); 24171f440fbeSToby Isaac { 24181f440fbeSToby Isaac PetscInt nNodes = lag->intNodeIndices->nNodes; 24191f440fbeSToby Isaac PetscReal *newNodeVec = lag->intNodeIndices->nodeVec; 24201f440fbeSToby Isaac const PetscReal *oldNodeVec = trimmedlag->allNodeIndices->nodeVec; 24211f440fbeSToby Isaac 24221f440fbeSToby Isaac for (PetscInt n = 0; n < nNodes; n++) { 24231f440fbeSToby Isaac PetscReal *w = &newNodeVec[n * Nk]; 24241f440fbeSToby Isaac const PetscReal *v = &oldNodeVec[n * Nk]; 24251f440fbeSToby Isaac 24261f440fbeSToby Isaac for (PetscInt j = 0; j < Nk; j++) { 24271f440fbeSToby Isaac w[j] = 0.; 24281f440fbeSToby Isaac for (PetscInt i = 0; i < Nk; i++) { 24291f440fbeSToby Isaac w[j] += v[i] * T[i * Nk + j]; 24301f440fbeSToby Isaac } 24311f440fbeSToby Isaac } 24321f440fbeSToby Isaac } 24331f440fbeSToby Isaac } 24341f440fbeSToby Isaac ierr = PetscFree2(T, work);CHKERRQ(ierr); 24351f440fbeSToby Isaac } 24361f440fbeSToby Isaac sp->intMat = intMat; 24371f440fbeSToby Isaac ierr = MatGetSize(sp->intMat, &nDofs, NULL);CHKERRQ(ierr); 24383f27d899SToby Isaac ierr = PetscDualSpaceDestroy(&trimmedsp);CHKERRQ(ierr); 24393f27d899SToby Isaac ierr = PetscSectionSetDof(section, 0, nDofs);CHKERRQ(ierr); 24403f27d899SToby Isaac } 24413f27d899SToby Isaac ierr = PetscDualSpaceSectionSetUp_Internal(sp, section);CHKERRQ(ierr); 24423f27d899SToby Isaac ierr = PetscDualSpaceCreateAllDataFromInteriorData(sp);CHKERRQ(ierr); 24433f27d899SToby Isaac ierr = PetscDualSpaceLagrangeCreateAllNodeIdx(sp);CHKERRQ(ierr); 24443f27d899SToby Isaac } 24453f27d899SToby Isaac } 24463f27d899SToby Isaac } else { 24473f27d899SToby Isaac PetscQuadrature intNodesTrace = NULL; 24483f27d899SToby Isaac PetscQuadrature intNodesFiber = NULL; 24493f27d899SToby Isaac PetscQuadrature intNodes = NULL; 24503f27d899SToby Isaac PetscLagNodeIndices intNodeIndices = NULL; 24513f27d899SToby Isaac Mat intMat = NULL; 24523f27d899SToby Isaac 245377f1a120SToby Isaac if (PetscAbsInt(formDegree) < dim) { /* get the trace k-forms on the first facet, and the 0-forms on the edge, 245477f1a120SToby Isaac and wedge them together to create some of the k-form dofs */ 24553f27d899SToby Isaac PetscDualSpace trace, fiber; 24563f27d899SToby Isaac PetscDualSpace_Lag *tracel, *fiberl; 24573f27d899SToby Isaac Mat intMatTrace, intMatFiber; 24583f27d899SToby Isaac 24593f27d899SToby Isaac if (sp->pointSpaces[tensorf]) { 24603f27d899SToby Isaac ierr = PetscObjectReference((PetscObject)(sp->pointSpaces[tensorf]));CHKERRQ(ierr); 24613f27d899SToby Isaac trace = sp->pointSpaces[tensorf]; 24623f27d899SToby Isaac } else { 24633f27d899SToby Isaac ierr = PetscDualSpaceCreateFacetSubspace_Lagrange(sp,NULL,tensorf,formDegree,Ncopies,PETSC_TRUE,&trace);CHKERRQ(ierr); 24643f27d899SToby Isaac } 24653f27d899SToby Isaac ierr = PetscDualSpaceCreateEdgeSubspace_Lagrange(sp,order,0,1,PETSC_TRUE,&fiber);CHKERRQ(ierr); 24663f27d899SToby Isaac tracel = (PetscDualSpace_Lag *) trace->data; 24673f27d899SToby Isaac fiberl = (PetscDualSpace_Lag *) fiber->data; 24683f27d899SToby Isaac ierr = PetscLagNodeIndicesCreateTensorVertices(dm, tracel->vertIndices, &(lag->vertIndices));CHKERRQ(ierr); 24693f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorData(trace, &intNodesTrace, &intMatTrace);CHKERRQ(ierr); 24703f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorData(fiber, &intNodesFiber, &intMatFiber);CHKERRQ(ierr); 24713f27d899SToby Isaac if (intNodesTrace && intNodesFiber) { 24723f27d899SToby Isaac ierr = PetscQuadratureCreateTensor(intNodesTrace, intNodesFiber, &intNodes);CHKERRQ(ierr); 24733f27d899SToby Isaac ierr = MatTensorAltV(intMatTrace, intMatFiber, dim-1, formDegree, 1, 0, &intMat);CHKERRQ(ierr); 24743f27d899SToby Isaac ierr = PetscLagNodeIndicesTensor(tracel->intNodeIndices, dim - 1, formDegree, fiberl->intNodeIndices, 1, 0, &intNodeIndices);CHKERRQ(ierr); 24753f27d899SToby Isaac } 24763f27d899SToby Isaac ierr = PetscObjectReference((PetscObject) intNodesTrace);CHKERRQ(ierr); 24773f27d899SToby Isaac ierr = PetscObjectReference((PetscObject) intNodesFiber);CHKERRQ(ierr); 24783f27d899SToby Isaac ierr = PetscDualSpaceDestroy(&fiber);CHKERRQ(ierr); 24793f27d899SToby Isaac ierr = PetscDualSpaceDestroy(&trace);CHKERRQ(ierr); 24803f27d899SToby Isaac } 248177f1a120SToby Isaac if (PetscAbsInt(formDegree) > 0) { /* get the trace (k-1)-forms on the first facet, and the 1-forms on the edge, 248277f1a120SToby Isaac and wedge them together to create the remaining k-form dofs */ 24833f27d899SToby Isaac PetscDualSpace trace, fiber; 24843f27d899SToby Isaac PetscDualSpace_Lag *tracel, *fiberl; 24853f27d899SToby Isaac PetscQuadrature intNodesTrace2, intNodesFiber2, intNodes2; 24863f27d899SToby Isaac PetscLagNodeIndices intNodeIndices2; 24873f27d899SToby Isaac Mat intMatTrace, intMatFiber, intMat2; 24883f27d899SToby Isaac PetscInt traceDegree = formDegree > 0 ? formDegree - 1 : formDegree + 1; 24893f27d899SToby Isaac PetscInt fiberDegree = formDegree > 0 ? 1 : -1; 24903f27d899SToby Isaac 24913f27d899SToby Isaac ierr = PetscDualSpaceCreateFacetSubspace_Lagrange(sp,NULL,tensorf,traceDegree,Ncopies,PETSC_TRUE,&trace);CHKERRQ(ierr); 24923f27d899SToby Isaac ierr = PetscDualSpaceCreateEdgeSubspace_Lagrange(sp,order,fiberDegree,1,PETSC_TRUE,&fiber);CHKERRQ(ierr); 24933f27d899SToby Isaac tracel = (PetscDualSpace_Lag *) trace->data; 24943f27d899SToby Isaac fiberl = (PetscDualSpace_Lag *) fiber->data; 24953f27d899SToby Isaac if (!lag->vertIndices) { 24963f27d899SToby Isaac ierr = PetscLagNodeIndicesCreateTensorVertices(dm, tracel->vertIndices, &(lag->vertIndices));CHKERRQ(ierr); 24973f27d899SToby Isaac } 24983f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorData(trace, &intNodesTrace2, &intMatTrace);CHKERRQ(ierr); 24993f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorData(fiber, &intNodesFiber2, &intMatFiber);CHKERRQ(ierr); 25003f27d899SToby Isaac if (intNodesTrace2 && intNodesFiber2) { 25013f27d899SToby Isaac ierr = PetscQuadratureCreateTensor(intNodesTrace2, intNodesFiber2, &intNodes2);CHKERRQ(ierr); 25023f27d899SToby Isaac ierr = MatTensorAltV(intMatTrace, intMatFiber, dim-1, traceDegree, 1, fiberDegree, &intMat2);CHKERRQ(ierr); 25033f27d899SToby Isaac ierr = PetscLagNodeIndicesTensor(tracel->intNodeIndices, dim - 1, traceDegree, fiberl->intNodeIndices, 1, fiberDegree, &intNodeIndices2);CHKERRQ(ierr); 25043f27d899SToby Isaac if (!intMat) { 25053f27d899SToby Isaac intMat = intMat2; 25063f27d899SToby Isaac intNodes = intNodes2; 25073f27d899SToby Isaac intNodeIndices = intNodeIndices2; 25083f27d899SToby Isaac } else { 250977f1a120SToby Isaac /* merge the matrices, quadrature points, and nodes */ 25103f27d899SToby Isaac PetscInt nM; 25113f27d899SToby Isaac PetscInt nDof, nDof2; 25126ff15688SToby Isaac PetscInt *toMerged = NULL, *toMerged2 = NULL; 25136ff15688SToby Isaac PetscQuadrature merged = NULL; 25143f27d899SToby Isaac PetscLagNodeIndices intNodeIndicesMerged = NULL; 25153f27d899SToby Isaac Mat matMerged = NULL; 25163f27d899SToby Isaac 2517ea78f98cSLisandro Dalcin ierr = MatGetSize(intMat, &nDof, NULL);CHKERRQ(ierr); 2518ea78f98cSLisandro Dalcin ierr = MatGetSize(intMat2, &nDof2, NULL);CHKERRQ(ierr); 25193f27d899SToby Isaac ierr = PetscQuadraturePointsMerge(intNodes, intNodes2, &merged, &toMerged, &toMerged2);CHKERRQ(ierr); 25203f27d899SToby Isaac ierr = PetscQuadratureGetData(merged, NULL, NULL, &nM, NULL, NULL);CHKERRQ(ierr); 25213f27d899SToby Isaac ierr = MatricesMerge(intMat, intMat2, dim, formDegree, nM, toMerged, toMerged2, &matMerged);CHKERRQ(ierr); 25223f27d899SToby Isaac ierr = PetscLagNodeIndicesMerge(intNodeIndices, intNodeIndices2, &intNodeIndicesMerged);CHKERRQ(ierr); 25236ff15688SToby Isaac ierr = PetscFree(toMerged);CHKERRQ(ierr); 25246ff15688SToby Isaac ierr = PetscFree(toMerged2);CHKERRQ(ierr); 25253f27d899SToby Isaac ierr = MatDestroy(&intMat);CHKERRQ(ierr); 25263f27d899SToby Isaac ierr = MatDestroy(&intMat2);CHKERRQ(ierr); 25273f27d899SToby Isaac ierr = PetscQuadratureDestroy(&intNodes);CHKERRQ(ierr); 25283f27d899SToby Isaac ierr = PetscQuadratureDestroy(&intNodes2);CHKERRQ(ierr); 25293f27d899SToby Isaac ierr = PetscLagNodeIndicesDestroy(&intNodeIndices);CHKERRQ(ierr); 25303f27d899SToby Isaac ierr = PetscLagNodeIndicesDestroy(&intNodeIndices2);CHKERRQ(ierr); 25313f27d899SToby Isaac intNodes = merged; 25323f27d899SToby Isaac intMat = matMerged; 25333f27d899SToby Isaac intNodeIndices = intNodeIndicesMerged; 25343f27d899SToby Isaac if (!trimmed) { 253577f1a120SToby Isaac /* I think users expect that, when a node has a full basis for the k-forms, 253677f1a120SToby Isaac * they should be consecutive dofs. That isn't the case for trimmed spaces, 253777f1a120SToby Isaac * but is for some of the nodes in untrimmed spaces, so in that case we 253877f1a120SToby Isaac * sort them to group them by node */ 25393f27d899SToby Isaac Mat intMatPerm; 25403f27d899SToby Isaac 25413f27d899SToby Isaac ierr = MatPermuteByNodeIdx(intMat, intNodeIndices, &intMatPerm);CHKERRQ(ierr); 25423f27d899SToby Isaac ierr = MatDestroy(&intMat);CHKERRQ(ierr); 25433f27d899SToby Isaac intMat = intMatPerm; 25443f27d899SToby Isaac } 25453f27d899SToby Isaac } 25463f27d899SToby Isaac } 25473f27d899SToby Isaac ierr = PetscDualSpaceDestroy(&fiber);CHKERRQ(ierr); 25483f27d899SToby Isaac ierr = PetscDualSpaceDestroy(&trace);CHKERRQ(ierr); 25493f27d899SToby Isaac } 25503f27d899SToby Isaac ierr = PetscQuadratureDestroy(&intNodesTrace);CHKERRQ(ierr); 25513f27d899SToby Isaac ierr = PetscQuadratureDestroy(&intNodesFiber);CHKERRQ(ierr); 25523f27d899SToby Isaac sp->intNodes = intNodes; 25533f27d899SToby Isaac sp->intMat = intMat; 25543f27d899SToby Isaac lag->intNodeIndices = intNodeIndices; 25556f905325SMatthew G. Knepley { 25563f27d899SToby Isaac PetscInt nDofs = 0; 25573f27d899SToby Isaac 25583f27d899SToby Isaac if (intMat) { 25593f27d899SToby Isaac ierr = MatGetSize(intMat, &nDofs, NULL);CHKERRQ(ierr); 25603f27d899SToby Isaac } 25613f27d899SToby Isaac ierr = PetscSectionSetDof(section, 0, nDofs);CHKERRQ(ierr); 25623f27d899SToby Isaac } 25633f27d899SToby Isaac ierr = PetscDualSpaceSectionSetUp_Internal(sp, section);CHKERRQ(ierr); 25643f27d899SToby Isaac if (continuous) { 25653f27d899SToby Isaac ierr = PetscDualSpaceCreateAllDataFromInteriorData(sp);CHKERRQ(ierr); 25663f27d899SToby Isaac ierr = PetscDualSpaceLagrangeCreateAllNodeIdx(sp);CHKERRQ(ierr); 25673f27d899SToby Isaac } else { 25683f27d899SToby Isaac ierr = PetscObjectReference((PetscObject) intNodes);CHKERRQ(ierr); 25693f27d899SToby Isaac sp->allNodes = intNodes; 25703f27d899SToby Isaac ierr = PetscObjectReference((PetscObject) intMat);CHKERRQ(ierr); 25713f27d899SToby Isaac sp->allMat = intMat; 25723f27d899SToby Isaac ierr = PetscLagNodeIndicesReference(intNodeIndices);CHKERRQ(ierr); 25733f27d899SToby Isaac lag->allNodeIndices = intNodeIndices; 25743f27d899SToby Isaac } 25753f27d899SToby Isaac } 25763f27d899SToby Isaac ierr = PetscSectionGetStorageSize(section, &sp->spdim);CHKERRQ(ierr); 25773f27d899SToby Isaac ierr = PetscSectionGetConstrainedStorageSize(section, &sp->spintdim);CHKERRQ(ierr); 25783f27d899SToby Isaac ierr = PetscDualSpaceComputeFunctionalsFromAllData(sp);CHKERRQ(ierr); 25793f27d899SToby Isaac ierr = PetscFree2(pStratStart, pStratEnd);CHKERRQ(ierr); 25803f27d899SToby Isaac ierr = DMDestroy(&dmint);CHKERRQ(ierr); 25813f27d899SToby Isaac PetscFunctionReturn(0); 25823f27d899SToby Isaac } 25833f27d899SToby Isaac 258477f1a120SToby Isaac /* Create a matrix that represents the transformation that DMPlexVecGetClosure() would need 258577f1a120SToby Isaac * to get the representation of the dofs for a mesh point if the mesh point had this orientation 258677f1a120SToby Isaac * relative to the cell */ 25873f27d899SToby Isaac PetscErrorCode PetscDualSpaceCreateInteriorSymmetryMatrix_Lagrange(PetscDualSpace sp, PetscInt ornt, Mat *symMat) 25883f27d899SToby Isaac { 25893f27d899SToby Isaac PetscDualSpace_Lag *lag; 25903f27d899SToby Isaac DM dm; 25913f27d899SToby Isaac PetscLagNodeIndices vertIndices, intNodeIndices; 25923f27d899SToby Isaac PetscLagNodeIndices ni; 25933f27d899SToby Isaac PetscInt nodeIdxDim, nodeVecDim, nNodes; 25943f27d899SToby Isaac PetscInt formDegree; 25953f27d899SToby Isaac PetscInt *perm, *permOrnt; 25963f27d899SToby Isaac PetscInt *nnz; 25973f27d899SToby Isaac PetscInt n; 25983f27d899SToby Isaac PetscInt maxGroupSize; 25993f27d899SToby Isaac PetscScalar *V, *W, *work; 26003f27d899SToby Isaac Mat A; 26016f905325SMatthew G. Knepley PetscErrorCode ierr; 26026f905325SMatthew G. Knepley 26036f905325SMatthew G. Knepley PetscFunctionBegin; 26043f27d899SToby Isaac if (!sp->spintdim) { 26053f27d899SToby Isaac *symMat = NULL; 26063f27d899SToby Isaac PetscFunctionReturn(0); 26076f905325SMatthew G. Knepley } 26083f27d899SToby Isaac lag = (PetscDualSpace_Lag *) sp->data; 26093f27d899SToby Isaac vertIndices = lag->vertIndices; 26103f27d899SToby Isaac intNodeIndices = lag->intNodeIndices; 26113f27d899SToby Isaac ierr = PetscDualSpaceGetDM(sp, &dm);CHKERRQ(ierr); 26123f27d899SToby Isaac ierr = PetscDualSpaceGetFormDegree(sp, &formDegree);CHKERRQ(ierr); 26133f27d899SToby Isaac ierr = PetscNew(&ni);CHKERRQ(ierr); 26143f27d899SToby Isaac ni->refct = 1; 26153f27d899SToby Isaac ni->nodeIdxDim = nodeIdxDim = intNodeIndices->nodeIdxDim; 26163f27d899SToby Isaac ni->nodeVecDim = nodeVecDim = intNodeIndices->nodeVecDim; 26173f27d899SToby Isaac ni->nNodes = nNodes = intNodeIndices->nNodes; 26183f27d899SToby Isaac ierr = PetscMalloc1(nNodes * nodeIdxDim, &(ni->nodeIdx));CHKERRQ(ierr); 26193f27d899SToby Isaac ierr = PetscMalloc1(nNodes * nodeVecDim, &(ni->nodeVec));CHKERRQ(ierr); 262077f1a120SToby Isaac /* push forward the dofs by the symmetry of the reference element induced by ornt */ 26213f27d899SToby Isaac ierr = PetscLagNodeIndicesPushForward(dm, vertIndices, 0, vertIndices, intNodeIndices, ornt, formDegree, ni->nodeIdx, ni->nodeVec);CHKERRQ(ierr); 262277f1a120SToby Isaac /* get the revlex order for both the original and transformed dofs */ 26233f27d899SToby Isaac ierr = PetscLagNodeIndicesGetPermutation(intNodeIndices, &perm);CHKERRQ(ierr); 26243f27d899SToby Isaac ierr = PetscLagNodeIndicesGetPermutation(ni, &permOrnt);CHKERRQ(ierr); 26253f27d899SToby Isaac ierr = PetscMalloc1(nNodes, &nnz);CHKERRQ(ierr); 26263f27d899SToby Isaac for (n = 0, maxGroupSize = 0; n < nNodes;) { /* incremented in the loop */ 26273f27d899SToby Isaac PetscInt *nind = &(ni->nodeIdx[permOrnt[n] * nodeIdxDim]); 26283f27d899SToby Isaac PetscInt m, nEnd; 26293f27d899SToby Isaac PetscInt groupSize; 263077f1a120SToby Isaac /* for each group of dofs that have the same nodeIdx coordinate */ 26313f27d899SToby Isaac for (nEnd = n + 1; nEnd < nNodes; nEnd++) { 26323f27d899SToby Isaac PetscInt *mind = &(ni->nodeIdx[permOrnt[nEnd] * nodeIdxDim]); 26333f27d899SToby Isaac PetscInt d; 26343f27d899SToby Isaac 26353f27d899SToby Isaac /* compare the oriented permutation indices */ 26363f27d899SToby Isaac for (d = 0; d < nodeIdxDim; d++) if (mind[d] != nind[d]) break; 26373f27d899SToby Isaac if (d < nodeIdxDim) break; 26383f27d899SToby Isaac } 263977f1a120SToby Isaac /* permOrnt[[n, nEnd)] is a group of dofs that, under the symmetry are at the same location */ 264076bd3646SJed Brown 264177f1a120SToby Isaac /* the symmetry had better map the group of dofs with the same permuted nodeIdx 264277f1a120SToby Isaac * to a group of dofs with the same size, otherwise we messed up */ 264376bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 26443f27d899SToby Isaac PetscInt m; 26453f27d899SToby Isaac PetscInt *nind = &(intNodeIndices->nodeIdx[perm[n] * nodeIdxDim]); 26463f27d899SToby Isaac 26473f27d899SToby Isaac for (m = n + 1; m < nEnd; m++) { 26483f27d899SToby Isaac PetscInt *mind = &(intNodeIndices->nodeIdx[perm[m] * nodeIdxDim]); 26493f27d899SToby Isaac PetscInt d; 26503f27d899SToby Isaac 26513f27d899SToby Isaac /* compare the oriented permutation indices */ 26523f27d899SToby Isaac for (d = 0; d < nodeIdxDim; d++) if (mind[d] != nind[d]) break; 26533f27d899SToby Isaac if (d < nodeIdxDim) break; 26543f27d899SToby Isaac } 26553f27d899SToby Isaac if (m < nEnd) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Dofs with same index after symmetry not same block size"); 26563f27d899SToby Isaac } 26573f27d899SToby Isaac groupSize = nEnd - n; 265877f1a120SToby Isaac /* each pushforward dof vector will be expressed in a basis of the unpermuted dofs */ 26593f27d899SToby Isaac for (m = n; m < nEnd; m++) nnz[permOrnt[m]] = groupSize; 26603f27d899SToby Isaac 26613f27d899SToby Isaac maxGroupSize = PetscMax(maxGroupSize, nEnd - n); 26623f27d899SToby Isaac n = nEnd; 26633f27d899SToby Isaac } 26643f27d899SToby Isaac if (maxGroupSize > nodeVecDim) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Dofs are not in blocks that can be solved"); 26653f27d899SToby Isaac ierr = MatCreateSeqAIJ(PETSC_COMM_SELF, nNodes, nNodes, 0, nnz, &A);CHKERRQ(ierr); 26663f27d899SToby Isaac ierr = PetscFree(nnz);CHKERRQ(ierr); 26673f27d899SToby Isaac ierr = PetscMalloc3(maxGroupSize * nodeVecDim, &V, maxGroupSize * nodeVecDim, &W, nodeVecDim * 2, &work);CHKERRQ(ierr); 26683f27d899SToby Isaac for (n = 0; n < nNodes;) { /* incremented in the loop */ 26693f27d899SToby Isaac PetscInt *nind = &(ni->nodeIdx[permOrnt[n] * nodeIdxDim]); 26703f27d899SToby Isaac PetscInt nEnd; 26713f27d899SToby Isaac PetscInt m; 26723f27d899SToby Isaac PetscInt groupSize; 26733f27d899SToby Isaac for (nEnd = n + 1; nEnd < nNodes; nEnd++) { 26743f27d899SToby Isaac PetscInt *mind = &(ni->nodeIdx[permOrnt[nEnd] * nodeIdxDim]); 26753f27d899SToby Isaac PetscInt d; 26763f27d899SToby Isaac 26773f27d899SToby Isaac /* compare the oriented permutation indices */ 26783f27d899SToby Isaac for (d = 0; d < nodeIdxDim; d++) if (mind[d] != nind[d]) break; 26793f27d899SToby Isaac if (d < nodeIdxDim) break; 26803f27d899SToby Isaac } 26813f27d899SToby Isaac groupSize = nEnd - n; 268277f1a120SToby Isaac /* get all of the vectors from the original and all of the pushforward vectors */ 26833f27d899SToby Isaac for (m = n; m < nEnd; m++) { 26843f27d899SToby Isaac PetscInt d; 26853f27d899SToby Isaac 26863f27d899SToby Isaac for (d = 0; d < nodeVecDim; d++) { 26873f27d899SToby Isaac V[(m - n) * nodeVecDim + d] = intNodeIndices->nodeVec[perm[m] * nodeVecDim + d]; 26883f27d899SToby Isaac W[(m - n) * nodeVecDim + d] = ni->nodeVec[permOrnt[m] * nodeVecDim + d]; 26893f27d899SToby Isaac } 26903f27d899SToby Isaac } 269177f1a120SToby Isaac /* now we have to solve for W in terms of V: the systems isn't always square, but the span 269277f1a120SToby Isaac * of V and W should always be the same, so the solution of the normal equations works */ 26933f27d899SToby Isaac { 26943f27d899SToby Isaac char transpose = 'N'; 26953f27d899SToby Isaac PetscBLASInt bm = nodeVecDim; 26963f27d899SToby Isaac PetscBLASInt bn = groupSize; 26973f27d899SToby Isaac PetscBLASInt bnrhs = groupSize; 26983f27d899SToby Isaac PetscBLASInt blda = bm; 26993f27d899SToby Isaac PetscBLASInt bldb = bm; 27003f27d899SToby Isaac PetscBLASInt blwork = 2 * nodeVecDim; 27013f27d899SToby Isaac PetscBLASInt info; 27023f27d899SToby Isaac 27033f27d899SToby Isaac PetscStackCallBLAS("LAPACKgels",LAPACKgels_(&transpose,&bm,&bn,&bnrhs,V,&blda,W,&bldb,work,&blwork, &info)); 27043f27d899SToby Isaac if (info != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Bad argument to GELS"); 27053f27d899SToby Isaac /* repack */ 27063f27d899SToby Isaac { 27073f27d899SToby Isaac PetscInt i, j; 27083f27d899SToby Isaac 27093f27d899SToby Isaac for (i = 0; i < groupSize; i++) { 27103f27d899SToby Isaac for (j = 0; j < groupSize; j++) { 271177f1a120SToby Isaac /* notice the different leading dimension */ 27123f27d899SToby Isaac V[i * groupSize + j] = W[i * nodeVecDim + j]; 27133f27d899SToby Isaac } 27143f27d899SToby Isaac } 27153f27d899SToby Isaac } 2716c5c386beSToby Isaac if (PetscDefined(USE_DEBUG)) { 2717c5c386beSToby Isaac PetscReal res; 2718c5c386beSToby Isaac 2719c5c386beSToby Isaac /* check that the normal error is 0 */ 2720c5c386beSToby Isaac for (m = n; m < nEnd; m++) { 2721c5c386beSToby Isaac PetscInt d; 2722c5c386beSToby Isaac 2723c5c386beSToby Isaac for (d = 0; d < nodeVecDim; d++) { 2724c5c386beSToby Isaac W[(m - n) * nodeVecDim + d] = ni->nodeVec[permOrnt[m] * nodeVecDim + d]; 2725c5c386beSToby Isaac } 2726c5c386beSToby Isaac } 2727c5c386beSToby Isaac res = 0.; 2728c5c386beSToby Isaac for (PetscInt i = 0; i < groupSize; i++) { 2729c5c386beSToby Isaac for (PetscInt j = 0; j < nodeVecDim; j++) { 2730c5c386beSToby Isaac for (PetscInt k = 0; k < groupSize; k++) { 2731c5c386beSToby Isaac W[i * nodeVecDim + j] -= V[i * groupSize + k] * intNodeIndices->nodeVec[perm[n+k] * nodeVecDim + j]; 2732c5c386beSToby Isaac } 2733c5c386beSToby Isaac res += PetscAbsScalar(W[i * nodeVecDim + j]); 2734c5c386beSToby Isaac } 2735c5c386beSToby Isaac } 2736c5c386beSToby Isaac if (res > PETSC_SMALL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Dof block did not solve"); 2737c5c386beSToby Isaac } 27383f27d899SToby Isaac } 27393f27d899SToby Isaac ierr = MatSetValues(A, groupSize, &permOrnt[n], groupSize, &perm[n], V, INSERT_VALUES);CHKERRQ(ierr); 27403f27d899SToby Isaac n = nEnd; 27413f27d899SToby Isaac } 27423f27d899SToby Isaac ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 27433f27d899SToby Isaac ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 27443f27d899SToby Isaac *symMat = A; 27453f27d899SToby Isaac ierr = PetscFree3(V,W,work);CHKERRQ(ierr); 27463f27d899SToby Isaac ierr = PetscLagNodeIndicesDestroy(&ni);CHKERRQ(ierr); 27476f905325SMatthew G. Knepley PetscFunctionReturn(0); 27486f905325SMatthew G. Knepley } 274920cf1dd8SToby Isaac 275020cf1dd8SToby Isaac #define BaryIndex(perEdge,a,b,c) (((b)*(2*perEdge+1-(b)))/2)+(c) 275120cf1dd8SToby Isaac 275220cf1dd8SToby Isaac #define CartIndex(perEdge,a,b) (perEdge*(a)+b) 275320cf1dd8SToby Isaac 275477f1a120SToby Isaac /* the existing interface for symmetries is insufficient for all cases: 275577f1a120SToby Isaac * - it should be sufficient for form degrees that are scalar (0 and n) 275677f1a120SToby Isaac * - it should be sufficient for hypercube dofs 275777f1a120SToby Isaac * - it isn't sufficient for simplex cells with non-scalar form degrees if 275877f1a120SToby Isaac * there are any dofs in the interior 275977f1a120SToby Isaac * 276077f1a120SToby Isaac * We compute the general transformation matrices, and if they fit, we return them, 276177f1a120SToby Isaac * otherwise we error (but we should probably change the interface to allow for 276277f1a120SToby Isaac * these symmetries) 276377f1a120SToby Isaac */ 276420cf1dd8SToby Isaac static PetscErrorCode PetscDualSpaceGetSymmetries_Lagrange(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips) 276520cf1dd8SToby Isaac { 276620cf1dd8SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 27673f27d899SToby Isaac PetscInt dim, order, Nc; 276820cf1dd8SToby Isaac PetscErrorCode ierr; 276920cf1dd8SToby Isaac 277020cf1dd8SToby Isaac PetscFunctionBegin; 277120cf1dd8SToby Isaac ierr = PetscDualSpaceGetOrder(sp,&order);CHKERRQ(ierr); 277220cf1dd8SToby Isaac ierr = PetscDualSpaceGetNumComponents(sp,&Nc);CHKERRQ(ierr); 277320cf1dd8SToby Isaac ierr = DMGetDimension(sp->dm,&dim);CHKERRQ(ierr); 27743f27d899SToby Isaac if (!lag->symComputed) { /* store symmetries */ 27753f27d899SToby Isaac PetscInt pStart, pEnd, p; 27763f27d899SToby Isaac PetscInt numPoints; 277720cf1dd8SToby Isaac PetscInt numFaces; 27783f27d899SToby Isaac PetscInt spintdim; 27793f27d899SToby Isaac PetscInt ***symperms; 27803f27d899SToby Isaac PetscScalar ***symflips; 278120cf1dd8SToby Isaac 27823f27d899SToby Isaac ierr = DMPlexGetChart(sp->dm, &pStart, &pEnd);CHKERRQ(ierr); 27833f27d899SToby Isaac numPoints = pEnd - pStart; 27843f27d899SToby Isaac ierr = DMPlexGetConeSize(sp->dm, 0, &numFaces);CHKERRQ(ierr); 27853f27d899SToby Isaac ierr = PetscCalloc1(numPoints,&symperms);CHKERRQ(ierr); 27863f27d899SToby Isaac ierr = PetscCalloc1(numPoints,&symflips);CHKERRQ(ierr); 27873f27d899SToby Isaac spintdim = sp->spintdim; 27883f27d899SToby Isaac /* The nodal symmetry behavior is not present when tensorSpace != tensorCell: someone might want this for the "S" 27893f27d899SToby Isaac * family of FEEC spaces. Most used in particular are discontinuous polynomial L2 spaces in tensor cells, where 27903f27d899SToby Isaac * the symmetries are not necessary for FE assembly. So for now we assume this is the case and don't return 27913f27d899SToby Isaac * symmetries if tensorSpace != tensorCell */ 27923f27d899SToby Isaac if (spintdim && 0 < dim && dim < 3 && (lag->tensorSpace == lag->tensorCell)) { /* compute self symmetries */ 27933f27d899SToby Isaac PetscInt **cellSymperms; 27943f27d899SToby Isaac PetscScalar **cellSymflips; 27953f27d899SToby Isaac PetscInt ornt; 27963f27d899SToby Isaac PetscInt nCopies = Nc / lag->intNodeIndices->nodeVecDim; 27973f27d899SToby Isaac PetscInt nNodes = lag->intNodeIndices->nNodes; 279820cf1dd8SToby Isaac 279920cf1dd8SToby Isaac lag->numSelfSym = 2 * numFaces; 280020cf1dd8SToby Isaac lag->selfSymOff = numFaces; 28013f27d899SToby Isaac ierr = PetscCalloc1(2*numFaces,&cellSymperms);CHKERRQ(ierr); 28023f27d899SToby Isaac ierr = PetscCalloc1(2*numFaces,&cellSymflips);CHKERRQ(ierr); 280320cf1dd8SToby Isaac /* we want to be able to index symmetries directly with the orientations, which range from [-numFaces,numFaces) */ 28043f27d899SToby Isaac symperms[0] = &cellSymperms[numFaces]; 28053f27d899SToby Isaac symflips[0] = &cellSymflips[numFaces]; 28063f27d899SToby Isaac if (lag->intNodeIndices->nodeVecDim * nCopies != Nc) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Node indices incompatible with dofs"); 28073f27d899SToby Isaac if (nNodes * nCopies != spintdim) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Node indices incompatible with dofs"); 28083f27d899SToby Isaac for (ornt = -numFaces; ornt < numFaces; ornt++) { /* for every symmetry, compute the symmetry matrix, and extract rows to see if it fits in the perm + flip framework */ 28093f27d899SToby Isaac Mat symMat; 28103f27d899SToby Isaac PetscInt *perm; 28113f27d899SToby Isaac PetscScalar *flips; 28123f27d899SToby Isaac PetscInt i; 281320cf1dd8SToby Isaac 28143f27d899SToby Isaac if (!ornt) continue; 28153f27d899SToby Isaac ierr = PetscMalloc1(spintdim, &perm);CHKERRQ(ierr); 28163f27d899SToby Isaac ierr = PetscCalloc1(spintdim, &flips);CHKERRQ(ierr); 28173f27d899SToby Isaac for (i = 0; i < spintdim; i++) perm[i] = -1; 28183f27d899SToby Isaac ierr = PetscDualSpaceCreateInteriorSymmetryMatrix_Lagrange(sp, ornt, &symMat);CHKERRQ(ierr); 28193f27d899SToby Isaac for (i = 0; i < nNodes; i++) { 28203f27d899SToby Isaac PetscInt ncols; 28213f27d899SToby Isaac PetscInt j, k; 28223f27d899SToby Isaac const PetscInt *cols; 28233f27d899SToby Isaac const PetscScalar *vals; 28243f27d899SToby Isaac PetscBool nz_seen = PETSC_FALSE; 282520cf1dd8SToby Isaac 28263f27d899SToby Isaac ierr = MatGetRow(symMat, i, &ncols, &cols, &vals);CHKERRQ(ierr); 28273f27d899SToby Isaac for (j = 0; j < ncols; j++) { 28283f27d899SToby Isaac if (PetscAbsScalar(vals[j]) > PETSC_SMALL) { 28293f27d899SToby Isaac if (nz_seen) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "This dual space has symmetries that can't be described as a permutation + sign flips"); 28303f27d899SToby Isaac nz_seen = PETSC_TRUE; 2831cd1695a5SJed Brown if (PetscAbsReal(PetscAbsScalar(vals[j]) - PetscRealConstant(1.)) > PETSC_SMALL) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "This dual space has symmetries that can't be described as a permutation + sign flips"); 28323f27d899SToby Isaac if (PetscAbsReal(PetscImaginaryPart(vals[j])) > PETSC_SMALL) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "This dual space has symmetries that can't be described as a permutation + sign flips"); 28333f27d899SToby Isaac if (perm[cols[j] * nCopies] >= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "This dual space has symmetries that can't be described as a permutation + sign flips"); 28343f27d899SToby Isaac for (k = 0; k < nCopies; k++) { 28353f27d899SToby Isaac perm[cols[j] * nCopies + k] = i * nCopies + k; 283620cf1dd8SToby Isaac } 28373f27d899SToby Isaac if (PetscRealPart(vals[j]) < 0.) { 28383f27d899SToby Isaac for (k = 0; k < nCopies; k++) { 28393f27d899SToby Isaac flips[i * nCopies + k] = -1.; 284020cf1dd8SToby Isaac } 284120cf1dd8SToby Isaac } else { 28423f27d899SToby Isaac for (k = 0; k < nCopies; k++) { 28433f27d899SToby Isaac flips[i * nCopies + k] = 1.; 28443f27d899SToby Isaac } 28453f27d899SToby Isaac } 28463f27d899SToby Isaac } 28473f27d899SToby Isaac } 28483f27d899SToby Isaac ierr = MatRestoreRow(symMat, i, &ncols, &cols, &vals);CHKERRQ(ierr); 28493f27d899SToby Isaac } 28503f27d899SToby Isaac ierr = MatDestroy(&symMat);CHKERRQ(ierr); 28513f27d899SToby Isaac /* if there were no sign flips, keep NULL */ 28523f27d899SToby Isaac for (i = 0; i < spintdim; i++) if (flips[i] != 1.) break; 28533f27d899SToby Isaac if (i == spintdim) { 28543f27d899SToby Isaac ierr = PetscFree(flips);CHKERRQ(ierr); 28553f27d899SToby Isaac flips = NULL; 28563f27d899SToby Isaac } 28573f27d899SToby Isaac /* if the permutation is identity, keep NULL */ 28583f27d899SToby Isaac for (i = 0; i < spintdim; i++) if (perm[i] != i) break; 28593f27d899SToby Isaac if (i == spintdim) { 28603f27d899SToby Isaac ierr = PetscFree(perm);CHKERRQ(ierr); 28613f27d899SToby Isaac perm = NULL; 28623f27d899SToby Isaac } 28633f27d899SToby Isaac symperms[0][ornt] = perm; 28643f27d899SToby Isaac symflips[0][ornt] = flips; 28653f27d899SToby Isaac } 28663f27d899SToby Isaac /* if no orientations produced non-identity permutations, keep NULL */ 28673f27d899SToby Isaac for (ornt = -numFaces; ornt < numFaces; ornt++) if (symperms[0][ornt]) break; 28683f27d899SToby Isaac if (ornt == numFaces) { 28693f27d899SToby Isaac ierr = PetscFree(cellSymperms);CHKERRQ(ierr); 28703f27d899SToby Isaac symperms[0] = NULL; 28713f27d899SToby Isaac } 28723f27d899SToby Isaac /* if no orientations produced sign flips, keep NULL */ 28733f27d899SToby Isaac for (ornt = -numFaces; ornt < numFaces; ornt++) if (symflips[0][ornt]) break; 28743f27d899SToby Isaac if (ornt == numFaces) { 28753f27d899SToby Isaac ierr = PetscFree(cellSymflips);CHKERRQ(ierr); 28763f27d899SToby Isaac symflips[0] = NULL; 28773f27d899SToby Isaac } 28783f27d899SToby Isaac } 287977f1a120SToby Isaac { /* get the symmetries of closure points */ 28803f27d899SToby Isaac PetscInt closureSize = 0; 28813f27d899SToby Isaac PetscInt *closure = NULL; 28823f27d899SToby Isaac PetscInt r; 288320cf1dd8SToby Isaac 28843f27d899SToby Isaac ierr = DMPlexGetTransitiveClosure(sp->dm,0,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 28853f27d899SToby Isaac for (r = 0; r < closureSize; r++) { 28863f27d899SToby Isaac PetscDualSpace psp; 28873f27d899SToby Isaac PetscInt point = closure[2 * r]; 28883f27d899SToby Isaac PetscInt pspintdim; 28893f27d899SToby Isaac const PetscInt ***psymperms = NULL; 28903f27d899SToby Isaac const PetscScalar ***psymflips = NULL; 289120cf1dd8SToby Isaac 28923f27d899SToby Isaac if (!point) continue; 28933f27d899SToby Isaac ierr = PetscDualSpaceGetPointSubspace(sp, point, &psp);CHKERRQ(ierr); 28943f27d899SToby Isaac if (!psp) continue; 28953f27d899SToby Isaac ierr = PetscDualSpaceGetInteriorDimension(psp, &pspintdim);CHKERRQ(ierr); 28963f27d899SToby Isaac if (!pspintdim) continue; 28973f27d899SToby Isaac ierr = PetscDualSpaceGetSymmetries(psp,&psymperms,&psymflips);CHKERRQ(ierr); 28983f27d899SToby Isaac symperms[r] = (PetscInt **) (psymperms ? psymperms[0] : NULL); 28993f27d899SToby Isaac symflips[r] = (PetscScalar **) (psymflips ? psymflips[0] : NULL); 290020cf1dd8SToby Isaac } 29013f27d899SToby Isaac ierr = DMPlexRestoreTransitiveClosure(sp->dm,0,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 290220cf1dd8SToby Isaac } 29033f27d899SToby Isaac for (p = 0; p < pEnd; p++) if (symperms[p]) break; 29043f27d899SToby Isaac if (p == pEnd) { 29053f27d899SToby Isaac ierr = PetscFree(symperms);CHKERRQ(ierr); 29063f27d899SToby Isaac symperms = NULL; 290720cf1dd8SToby Isaac } 29083f27d899SToby Isaac for (p = 0; p < pEnd; p++) if (symflips[p]) break; 29093f27d899SToby Isaac if (p == pEnd) { 29103f27d899SToby Isaac ierr = PetscFree(symflips);CHKERRQ(ierr); 29113f27d899SToby Isaac symflips = NULL; 291220cf1dd8SToby Isaac } 29133f27d899SToby Isaac lag->symperms = symperms; 29143f27d899SToby Isaac lag->symflips = symflips; 29153f27d899SToby Isaac lag->symComputed = PETSC_TRUE; 291620cf1dd8SToby Isaac } 29173f27d899SToby Isaac if (perms) *perms = (const PetscInt ***) lag->symperms; 29183f27d899SToby Isaac if (flips) *flips = (const PetscScalar ***) lag->symflips; 291920cf1dd8SToby Isaac PetscFunctionReturn(0); 292020cf1dd8SToby Isaac } 292120cf1dd8SToby Isaac 292220cf1dd8SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeGetContinuity_Lagrange(PetscDualSpace sp, PetscBool *continuous) 292320cf1dd8SToby Isaac { 292420cf1dd8SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 292520cf1dd8SToby Isaac 292620cf1dd8SToby Isaac PetscFunctionBegin; 292720cf1dd8SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 292820cf1dd8SToby Isaac PetscValidPointer(continuous, 2); 292920cf1dd8SToby Isaac *continuous = lag->continuous; 293020cf1dd8SToby Isaac PetscFunctionReturn(0); 293120cf1dd8SToby Isaac } 293220cf1dd8SToby Isaac 293320cf1dd8SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeSetContinuity_Lagrange(PetscDualSpace sp, PetscBool continuous) 293420cf1dd8SToby Isaac { 293520cf1dd8SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 293620cf1dd8SToby Isaac 293720cf1dd8SToby Isaac PetscFunctionBegin; 293820cf1dd8SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 293920cf1dd8SToby Isaac lag->continuous = continuous; 294020cf1dd8SToby Isaac PetscFunctionReturn(0); 294120cf1dd8SToby Isaac } 294220cf1dd8SToby Isaac 294320cf1dd8SToby Isaac /*@ 294420cf1dd8SToby Isaac PetscDualSpaceLagrangeGetContinuity - Retrieves the flag for element continuity 294520cf1dd8SToby Isaac 294620cf1dd8SToby Isaac Not Collective 294720cf1dd8SToby Isaac 294820cf1dd8SToby Isaac Input Parameter: 294920cf1dd8SToby Isaac . sp - the PetscDualSpace 295020cf1dd8SToby Isaac 295120cf1dd8SToby Isaac Output Parameter: 295220cf1dd8SToby Isaac . continuous - flag for element continuity 295320cf1dd8SToby Isaac 295420cf1dd8SToby Isaac Level: intermediate 295520cf1dd8SToby Isaac 295620cf1dd8SToby Isaac .seealso: PetscDualSpaceLagrangeSetContinuity() 295720cf1dd8SToby Isaac @*/ 295820cf1dd8SToby Isaac PetscErrorCode PetscDualSpaceLagrangeGetContinuity(PetscDualSpace sp, PetscBool *continuous) 295920cf1dd8SToby Isaac { 296020cf1dd8SToby Isaac PetscErrorCode ierr; 296120cf1dd8SToby Isaac 296220cf1dd8SToby Isaac PetscFunctionBegin; 296320cf1dd8SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 296420cf1dd8SToby Isaac PetscValidPointer(continuous, 2); 296520cf1dd8SToby Isaac ierr = PetscTryMethod(sp, "PetscDualSpaceLagrangeGetContinuity_C", (PetscDualSpace,PetscBool*),(sp,continuous));CHKERRQ(ierr); 296620cf1dd8SToby Isaac PetscFunctionReturn(0); 296720cf1dd8SToby Isaac } 296820cf1dd8SToby Isaac 296920cf1dd8SToby Isaac /*@ 297020cf1dd8SToby Isaac PetscDualSpaceLagrangeSetContinuity - Indicate whether the element is continuous 297120cf1dd8SToby Isaac 2972d083f849SBarry Smith Logically Collective on sp 297320cf1dd8SToby Isaac 297420cf1dd8SToby Isaac Input Parameters: 297520cf1dd8SToby Isaac + sp - the PetscDualSpace 297620cf1dd8SToby Isaac - continuous - flag for element continuity 297720cf1dd8SToby Isaac 297820cf1dd8SToby Isaac Options Database: 297920cf1dd8SToby Isaac . -petscdualspace_lagrange_continuity <bool> 298020cf1dd8SToby Isaac 298120cf1dd8SToby Isaac Level: intermediate 298220cf1dd8SToby Isaac 298320cf1dd8SToby Isaac .seealso: PetscDualSpaceLagrangeGetContinuity() 298420cf1dd8SToby Isaac @*/ 298520cf1dd8SToby Isaac PetscErrorCode PetscDualSpaceLagrangeSetContinuity(PetscDualSpace sp, PetscBool continuous) 298620cf1dd8SToby Isaac { 298720cf1dd8SToby Isaac PetscErrorCode ierr; 298820cf1dd8SToby Isaac 298920cf1dd8SToby Isaac PetscFunctionBegin; 299020cf1dd8SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 299120cf1dd8SToby Isaac PetscValidLogicalCollectiveBool(sp, continuous, 2); 299220cf1dd8SToby Isaac ierr = PetscTryMethod(sp, "PetscDualSpaceLagrangeSetContinuity_C", (PetscDualSpace,PetscBool),(sp,continuous));CHKERRQ(ierr); 299320cf1dd8SToby Isaac PetscFunctionReturn(0); 299420cf1dd8SToby Isaac } 299520cf1dd8SToby Isaac 29966f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeGetTensor_Lagrange(PetscDualSpace sp, PetscBool *tensor) 299720cf1dd8SToby Isaac { 299820cf1dd8SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 29996f905325SMatthew G. Knepley 30006f905325SMatthew G. Knepley PetscFunctionBegin; 30016f905325SMatthew G. Knepley *tensor = lag->tensorSpace; 30026f905325SMatthew G. Knepley PetscFunctionReturn(0); 30036f905325SMatthew G. Knepley } 30046f905325SMatthew G. Knepley 30056f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeSetTensor_Lagrange(PetscDualSpace sp, PetscBool tensor) 30066f905325SMatthew G. Knepley { 30076f905325SMatthew G. Knepley PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 30086f905325SMatthew G. Knepley 30096f905325SMatthew G. Knepley PetscFunctionBegin; 30106f905325SMatthew G. Knepley lag->tensorSpace = tensor; 30116f905325SMatthew G. Knepley PetscFunctionReturn(0); 30126f905325SMatthew G. Knepley } 30136f905325SMatthew G. Knepley 30143f27d899SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeGetTrimmed_Lagrange(PetscDualSpace sp, PetscBool *trimmed) 30153f27d899SToby Isaac { 30163f27d899SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 30173f27d899SToby Isaac 30183f27d899SToby Isaac PetscFunctionBegin; 30193f27d899SToby Isaac *trimmed = lag->trimmed; 30203f27d899SToby Isaac PetscFunctionReturn(0); 30213f27d899SToby Isaac } 30223f27d899SToby Isaac 30233f27d899SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeSetTrimmed_Lagrange(PetscDualSpace sp, PetscBool trimmed) 30243f27d899SToby Isaac { 30253f27d899SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 30263f27d899SToby Isaac 30273f27d899SToby Isaac PetscFunctionBegin; 30283f27d899SToby Isaac lag->trimmed = trimmed; 30293f27d899SToby Isaac PetscFunctionReturn(0); 30303f27d899SToby Isaac } 30313f27d899SToby Isaac 30323f27d899SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeGetNodeType_Lagrange(PetscDualSpace sp, PetscDTNodeType *nodeType, PetscBool *boundary, PetscReal *exponent) 30333f27d899SToby Isaac { 30343f27d899SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 30353f27d899SToby Isaac 30363f27d899SToby Isaac PetscFunctionBegin; 30373f27d899SToby Isaac if (nodeType) *nodeType = lag->nodeType; 30383f27d899SToby Isaac if (boundary) *boundary = lag->endNodes; 30393f27d899SToby Isaac if (exponent) *exponent = lag->nodeExponent; 30403f27d899SToby Isaac PetscFunctionReturn(0); 30413f27d899SToby Isaac } 30423f27d899SToby Isaac 30433f27d899SToby Isaac static PetscErrorCode PetscDualSpaceLagrangeSetNodeType_Lagrange(PetscDualSpace sp, PetscDTNodeType nodeType, PetscBool boundary, PetscReal exponent) 30443f27d899SToby Isaac { 30453f27d899SToby Isaac PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 30463f27d899SToby Isaac 30473f27d899SToby Isaac PetscFunctionBegin; 30483f27d899SToby Isaac if (nodeType == PETSCDTNODES_GAUSSJACOBI && exponent <= -1.) SETERRQ(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_OUTOFRANGE, "Exponent must be > -1"); 30493f27d899SToby Isaac lag->nodeType = nodeType; 30503f27d899SToby Isaac lag->endNodes = boundary; 30513f27d899SToby Isaac lag->nodeExponent = exponent; 30523f27d899SToby Isaac PetscFunctionReturn(0); 30533f27d899SToby Isaac } 30543f27d899SToby Isaac 305566a6c23cSMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeGetUseMoments_Lagrange(PetscDualSpace sp, PetscBool *useMoments) 305666a6c23cSMatthew G. Knepley { 305766a6c23cSMatthew G. Knepley PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 305866a6c23cSMatthew G. Knepley 305966a6c23cSMatthew G. Knepley PetscFunctionBegin; 306066a6c23cSMatthew G. Knepley *useMoments = lag->useMoments; 306166a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 306266a6c23cSMatthew G. Knepley } 306366a6c23cSMatthew G. Knepley 306466a6c23cSMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeSetUseMoments_Lagrange(PetscDualSpace sp, PetscBool useMoments) 306566a6c23cSMatthew G. Knepley { 306666a6c23cSMatthew G. Knepley PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 306766a6c23cSMatthew G. Knepley 306866a6c23cSMatthew G. Knepley PetscFunctionBegin; 306966a6c23cSMatthew G. Knepley lag->useMoments = useMoments; 307066a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 307166a6c23cSMatthew G. Knepley } 307266a6c23cSMatthew G. Knepley 307366a6c23cSMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeGetMomentOrder_Lagrange(PetscDualSpace sp, PetscInt *momentOrder) 307466a6c23cSMatthew G. Knepley { 307566a6c23cSMatthew G. Knepley PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 307666a6c23cSMatthew G. Knepley 307766a6c23cSMatthew G. Knepley PetscFunctionBegin; 307866a6c23cSMatthew G. Knepley *momentOrder = lag->momentOrder; 307966a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 308066a6c23cSMatthew G. Knepley } 308166a6c23cSMatthew G. Knepley 308266a6c23cSMatthew G. Knepley static PetscErrorCode PetscDualSpaceLagrangeSetMomentOrder_Lagrange(PetscDualSpace sp, PetscInt momentOrder) 308366a6c23cSMatthew G. Knepley { 308466a6c23cSMatthew G. Knepley PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 308566a6c23cSMatthew G. Knepley 308666a6c23cSMatthew G. Knepley PetscFunctionBegin; 308766a6c23cSMatthew G. Knepley lag->momentOrder = momentOrder; 308866a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 308966a6c23cSMatthew G. Knepley } 309066a6c23cSMatthew G. Knepley 30916f905325SMatthew G. Knepley /*@ 30926f905325SMatthew G. Knepley PetscDualSpaceLagrangeGetTensor - Get the tensor nature of the dual space 30936f905325SMatthew G. Knepley 30946f905325SMatthew G. Knepley Not collective 30956f905325SMatthew G. Knepley 30966f905325SMatthew G. Knepley Input Parameter: 30976f905325SMatthew G. Knepley . sp - The PetscDualSpace 30986f905325SMatthew G. Knepley 30996f905325SMatthew G. Knepley Output Parameter: 31006f905325SMatthew G. Knepley . tensor - Whether the dual space has tensor layout (vs. simplicial) 31016f905325SMatthew G. Knepley 31026f905325SMatthew G. Knepley Level: intermediate 31036f905325SMatthew G. Knepley 31046f905325SMatthew G. Knepley .seealso: PetscDualSpaceLagrangeSetTensor(), PetscDualSpaceCreate() 31056f905325SMatthew G. Knepley @*/ 31066f905325SMatthew G. Knepley PetscErrorCode PetscDualSpaceLagrangeGetTensor(PetscDualSpace sp, PetscBool *tensor) 31076f905325SMatthew G. Knepley { 310820cf1dd8SToby Isaac PetscErrorCode ierr; 310920cf1dd8SToby Isaac 311020cf1dd8SToby Isaac PetscFunctionBegin; 311120cf1dd8SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 31126f905325SMatthew G. Knepley PetscValidPointer(tensor, 2); 31136f905325SMatthew G. Knepley ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeGetTensor_C",(PetscDualSpace,PetscBool *),(sp,tensor));CHKERRQ(ierr); 311420cf1dd8SToby Isaac PetscFunctionReturn(0); 311520cf1dd8SToby Isaac } 311620cf1dd8SToby Isaac 31176f905325SMatthew G. Knepley /*@ 31186f905325SMatthew G. Knepley PetscDualSpaceLagrangeSetTensor - Set the tensor nature of the dual space 31196f905325SMatthew G. Knepley 31206f905325SMatthew G. Knepley Not collective 31216f905325SMatthew G. Knepley 31226f905325SMatthew G. Knepley Input Parameters: 31236f905325SMatthew G. Knepley + sp - The PetscDualSpace 31246f905325SMatthew G. Knepley - tensor - Whether the dual space has tensor layout (vs. simplicial) 31256f905325SMatthew G. Knepley 31266f905325SMatthew G. Knepley Level: intermediate 31276f905325SMatthew G. Knepley 31286f905325SMatthew G. Knepley .seealso: PetscDualSpaceLagrangeGetTensor(), PetscDualSpaceCreate() 31296f905325SMatthew G. Knepley @*/ 31306f905325SMatthew G. Knepley PetscErrorCode PetscDualSpaceLagrangeSetTensor(PetscDualSpace sp, PetscBool tensor) 31316f905325SMatthew G. Knepley { 31326f905325SMatthew G. Knepley PetscErrorCode ierr; 31336f905325SMatthew G. Knepley 31346f905325SMatthew G. Knepley PetscFunctionBegin; 31356f905325SMatthew G. Knepley PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 31366f905325SMatthew G. Knepley ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeSetTensor_C",(PetscDualSpace,PetscBool),(sp,tensor));CHKERRQ(ierr); 31376f905325SMatthew G. Knepley PetscFunctionReturn(0); 31386f905325SMatthew G. Knepley } 31396f905325SMatthew G. Knepley 31403f27d899SToby Isaac /*@ 31413f27d899SToby Isaac PetscDualSpaceLagrangeGetTrimmed - Get the trimmed nature of the dual space 31423f27d899SToby Isaac 31433f27d899SToby Isaac Not collective 31443f27d899SToby Isaac 31453f27d899SToby Isaac Input Parameter: 31463f27d899SToby Isaac . sp - The PetscDualSpace 31473f27d899SToby Isaac 31483f27d899SToby Isaac Output Parameter: 31493f27d899SToby Isaac . trimmed - Whether the dual space represents to dual basis of a trimmed polynomial space (e.g. Raviart-Thomas and higher order / other form degree variants) 31503f27d899SToby Isaac 31513f27d899SToby Isaac Level: intermediate 31523f27d899SToby Isaac 31533f27d899SToby Isaac .seealso: PetscDualSpaceLagrangeSetTrimmed(), PetscDualSpaceCreate() 31543f27d899SToby Isaac @*/ 31553f27d899SToby Isaac PetscErrorCode PetscDualSpaceLagrangeGetTrimmed(PetscDualSpace sp, PetscBool *trimmed) 31563f27d899SToby Isaac { 31573f27d899SToby Isaac PetscErrorCode ierr; 31583f27d899SToby Isaac 31593f27d899SToby Isaac PetscFunctionBegin; 31603f27d899SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 31613f27d899SToby Isaac PetscValidPointer(trimmed, 2); 31623f27d899SToby Isaac ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeGetTrimmed_C",(PetscDualSpace,PetscBool *),(sp,trimmed));CHKERRQ(ierr); 31633f27d899SToby Isaac PetscFunctionReturn(0); 31643f27d899SToby Isaac } 31653f27d899SToby Isaac 31663f27d899SToby Isaac /*@ 31673f27d899SToby Isaac PetscDualSpaceLagrangeSetTrimmed - Set the trimmed nature of the dual space 31683f27d899SToby Isaac 31693f27d899SToby Isaac Not collective 31703f27d899SToby Isaac 31713f27d899SToby Isaac Input Parameters: 31723f27d899SToby Isaac + sp - The PetscDualSpace 31733f27d899SToby Isaac - trimmed - Whether the dual space represents to dual basis of a trimmed polynomial space (e.g. Raviart-Thomas and higher order / other form degree variants) 31743f27d899SToby Isaac 31753f27d899SToby Isaac Level: intermediate 31763f27d899SToby Isaac 31773f27d899SToby Isaac .seealso: PetscDualSpaceLagrangeGetTrimmed(), PetscDualSpaceCreate() 31783f27d899SToby Isaac @*/ 31793f27d899SToby Isaac PetscErrorCode PetscDualSpaceLagrangeSetTrimmed(PetscDualSpace sp, PetscBool trimmed) 31803f27d899SToby Isaac { 31813f27d899SToby Isaac PetscErrorCode ierr; 31823f27d899SToby Isaac 31833f27d899SToby Isaac PetscFunctionBegin; 31843f27d899SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 31853f27d899SToby Isaac ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeSetTrimmed_C",(PetscDualSpace,PetscBool),(sp,trimmed));CHKERRQ(ierr); 31863f27d899SToby Isaac PetscFunctionReturn(0); 31873f27d899SToby Isaac } 31883f27d899SToby Isaac 31893f27d899SToby Isaac /*@ 31903f27d899SToby Isaac PetscDualSpaceLagrangeGetNodeType - Get a description of how nodes are laid out for Lagrange polynomials in this 31913f27d899SToby Isaac dual space 31923f27d899SToby Isaac 31933f27d899SToby Isaac Not collective 31943f27d899SToby Isaac 31953f27d899SToby Isaac Input Parameter: 31963f27d899SToby Isaac . sp - The PetscDualSpace 31973f27d899SToby Isaac 31983f27d899SToby Isaac Output Parameters: 31993f27d899SToby Isaac + nodeType - The type of nodes 32003f27d899SToby Isaac . boundary - Whether the node type is one that includes endpoints (if nodeType is PETSCDTNODES_GAUSSJACOBI, nodes that 32013f27d899SToby Isaac include the boundary are Gauss-Lobatto-Jacobi nodes) 32023f27d899SToby Isaac - exponent - If nodeType is PETSCDTNODES_GAUSJACOBI, indicates the exponent used for both ends of the 1D Jacobi weight function 32033f27d899SToby Isaac '0' is Gauss-Legendre, '-0.5' is Gauss-Chebyshev of the first type, '0.5' is Gauss-Chebyshev of the second type 32043f27d899SToby Isaac 32053f27d899SToby Isaac Level: advanced 32063f27d899SToby Isaac 32073f27d899SToby Isaac .seealso: PetscDTNodeType, PetscDualSpaceLagrangeSetNodeType() 32083f27d899SToby Isaac @*/ 32093f27d899SToby Isaac PetscErrorCode PetscDualSpaceLagrangeGetNodeType(PetscDualSpace sp, PetscDTNodeType *nodeType, PetscBool *boundary, PetscReal *exponent) 32103f27d899SToby Isaac { 32113f27d899SToby Isaac PetscErrorCode ierr; 32123f27d899SToby Isaac 32133f27d899SToby Isaac PetscFunctionBegin; 32143f27d899SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 32153f27d899SToby Isaac if (nodeType) PetscValidPointer(nodeType, 2); 32163f27d899SToby Isaac if (boundary) PetscValidPointer(boundary, 3); 32173f27d899SToby Isaac if (exponent) PetscValidPointer(exponent, 4); 32183f27d899SToby Isaac ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeGetNodeType_C",(PetscDualSpace,PetscDTNodeType *,PetscBool *,PetscReal *),(sp,nodeType,boundary,exponent));CHKERRQ(ierr); 32193f27d899SToby Isaac PetscFunctionReturn(0); 32203f27d899SToby Isaac } 32213f27d899SToby Isaac 32223f27d899SToby Isaac /*@ 32233f27d899SToby Isaac PetscDualSpaceLagrangeSetNodeType - Set a description of how nodes are laid out for Lagrange polynomials in this 32243f27d899SToby Isaac dual space 32253f27d899SToby Isaac 32263f27d899SToby Isaac Logically collective 32273f27d899SToby Isaac 32283f27d899SToby Isaac Input Parameters: 32293f27d899SToby Isaac + sp - The PetscDualSpace 32303f27d899SToby Isaac . nodeType - The type of nodes 32313f27d899SToby Isaac . boundary - Whether the node type is one that includes endpoints (if nodeType is PETSCDTNODES_GAUSSJACOBI, nodes that 32323f27d899SToby Isaac include the boundary are Gauss-Lobatto-Jacobi nodes) 32333f27d899SToby Isaac - exponent - If nodeType is PETSCDTNODES_GAUSJACOBI, indicates the exponent used for both ends of the 1D Jacobi weight function 32343f27d899SToby Isaac '0' is Gauss-Legendre, '-0.5' is Gauss-Chebyshev of the first type, '0.5' is Gauss-Chebyshev of the second type 32353f27d899SToby Isaac 32363f27d899SToby Isaac Level: advanced 32373f27d899SToby Isaac 32383f27d899SToby Isaac .seealso: PetscDTNodeType, PetscDualSpaceLagrangeGetNodeType() 32393f27d899SToby Isaac @*/ 32403f27d899SToby Isaac PetscErrorCode PetscDualSpaceLagrangeSetNodeType(PetscDualSpace sp, PetscDTNodeType nodeType, PetscBool boundary, PetscReal exponent) 32413f27d899SToby Isaac { 32423f27d899SToby Isaac PetscErrorCode ierr; 32433f27d899SToby Isaac 32443f27d899SToby Isaac PetscFunctionBegin; 32453f27d899SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 32463f27d899SToby Isaac ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeSetNodeType_C",(PetscDualSpace,PetscDTNodeType,PetscBool,PetscReal),(sp,nodeType,boundary,exponent));CHKERRQ(ierr); 32473f27d899SToby Isaac PetscFunctionReturn(0); 32483f27d899SToby Isaac } 32493f27d899SToby Isaac 325066a6c23cSMatthew G. Knepley /*@ 325166a6c23cSMatthew G. Knepley PetscDualSpaceLagrangeGetUseMoments - Get the flag for using moment functionals 325266a6c23cSMatthew G. Knepley 325366a6c23cSMatthew G. Knepley Not collective 325466a6c23cSMatthew G. Knepley 325566a6c23cSMatthew G. Knepley Input Parameter: 325666a6c23cSMatthew G. Knepley . sp - The PetscDualSpace 325766a6c23cSMatthew G. Knepley 325866a6c23cSMatthew G. Knepley Output Parameter: 325966a6c23cSMatthew G. Knepley . useMoments - Moment flag 326066a6c23cSMatthew G. Knepley 326166a6c23cSMatthew G. Knepley Level: advanced 326266a6c23cSMatthew G. Knepley 326366a6c23cSMatthew G. Knepley .seealso: PetscDualSpaceLagrangeSetUseMoments() 326466a6c23cSMatthew G. Knepley @*/ 326566a6c23cSMatthew G. Knepley PetscErrorCode PetscDualSpaceLagrangeGetUseMoments(PetscDualSpace sp, PetscBool *useMoments) 326666a6c23cSMatthew G. Knepley { 326766a6c23cSMatthew G. Knepley PetscErrorCode ierr; 326866a6c23cSMatthew G. Knepley 326966a6c23cSMatthew G. Knepley PetscFunctionBegin; 327066a6c23cSMatthew G. Knepley PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 327166a6c23cSMatthew G. Knepley PetscValidBoolPointer(useMoments, 2); 327266a6c23cSMatthew G. Knepley ierr = PetscUseMethod(sp,"PetscDualSpaceLagrangeGetUseMoments_C",(PetscDualSpace,PetscBool *),(sp,useMoments));CHKERRQ(ierr); 327366a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 327466a6c23cSMatthew G. Knepley } 327566a6c23cSMatthew G. Knepley 327666a6c23cSMatthew G. Knepley /*@ 327766a6c23cSMatthew G. Knepley PetscDualSpaceLagrangeSetUseMoments - Set the flag for moment functionals 327866a6c23cSMatthew G. Knepley 327966a6c23cSMatthew G. Knepley Logically collective 328066a6c23cSMatthew G. Knepley 328166a6c23cSMatthew G. Knepley Input Parameters: 328266a6c23cSMatthew G. Knepley + sp - The PetscDualSpace 328366a6c23cSMatthew G. Knepley - useMoments - The flag for moment functionals 328466a6c23cSMatthew G. Knepley 328566a6c23cSMatthew G. Knepley Level: advanced 328666a6c23cSMatthew G. Knepley 328766a6c23cSMatthew G. Knepley .seealso: PetscDualSpaceLagrangeGetUseMoments() 328866a6c23cSMatthew G. Knepley @*/ 328966a6c23cSMatthew G. Knepley PetscErrorCode PetscDualSpaceLagrangeSetUseMoments(PetscDualSpace sp, PetscBool useMoments) 329066a6c23cSMatthew G. Knepley { 329166a6c23cSMatthew G. Knepley PetscErrorCode ierr; 329266a6c23cSMatthew G. Knepley 329366a6c23cSMatthew G. Knepley PetscFunctionBegin; 329466a6c23cSMatthew G. Knepley PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 329566a6c23cSMatthew G. Knepley ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeSetUseMoments_C",(PetscDualSpace,PetscBool),(sp,useMoments));CHKERRQ(ierr); 329666a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 329766a6c23cSMatthew G. Knepley } 329866a6c23cSMatthew G. Knepley 329966a6c23cSMatthew G. Knepley /*@ 330066a6c23cSMatthew G. Knepley PetscDualSpaceLagrangeGetMomentOrder - Get the order for moment integration 330166a6c23cSMatthew G. Knepley 330266a6c23cSMatthew G. Knepley Not collective 330366a6c23cSMatthew G. Knepley 330466a6c23cSMatthew G. Knepley Input Parameter: 330566a6c23cSMatthew G. Knepley . sp - The PetscDualSpace 330666a6c23cSMatthew G. Knepley 330766a6c23cSMatthew G. Knepley Output Parameter: 330866a6c23cSMatthew G. Knepley . order - Moment integration order 330966a6c23cSMatthew G. Knepley 331066a6c23cSMatthew G. Knepley Level: advanced 331166a6c23cSMatthew G. Knepley 331266a6c23cSMatthew G. Knepley .seealso: PetscDualSpaceLagrangeSetMomentOrder() 331366a6c23cSMatthew G. Knepley @*/ 331466a6c23cSMatthew G. Knepley PetscErrorCode PetscDualSpaceLagrangeGetMomentOrder(PetscDualSpace sp, PetscInt *order) 331566a6c23cSMatthew G. Knepley { 331666a6c23cSMatthew G. Knepley PetscErrorCode ierr; 331766a6c23cSMatthew G. Knepley 331866a6c23cSMatthew G. Knepley PetscFunctionBegin; 331966a6c23cSMatthew G. Knepley PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 332066a6c23cSMatthew G. Knepley PetscValidIntPointer(order, 2); 332166a6c23cSMatthew G. Knepley ierr = PetscUseMethod(sp,"PetscDualSpaceLagrangeGetMomentOrder_C",(PetscDualSpace,PetscInt *),(sp,order));CHKERRQ(ierr); 332266a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 332366a6c23cSMatthew G. Knepley } 332466a6c23cSMatthew G. Knepley 332566a6c23cSMatthew G. Knepley /*@ 332666a6c23cSMatthew G. Knepley PetscDualSpaceLagrangeSetMomentOrder - Set the order for moment integration 332766a6c23cSMatthew G. Knepley 332866a6c23cSMatthew G. Knepley Logically collective 332966a6c23cSMatthew G. Knepley 333066a6c23cSMatthew G. Knepley Input Parameters: 333166a6c23cSMatthew G. Knepley + sp - The PetscDualSpace 333266a6c23cSMatthew G. Knepley - order - The order for moment integration 333366a6c23cSMatthew G. Knepley 333466a6c23cSMatthew G. Knepley Level: advanced 333566a6c23cSMatthew G. Knepley 333666a6c23cSMatthew G. Knepley .seealso: PetscDualSpaceLagrangeGetMomentOrder() 333766a6c23cSMatthew G. Knepley @*/ 333866a6c23cSMatthew G. Knepley PetscErrorCode PetscDualSpaceLagrangeSetMomentOrder(PetscDualSpace sp, PetscInt order) 333966a6c23cSMatthew G. Knepley { 334066a6c23cSMatthew G. Knepley PetscErrorCode ierr; 334166a6c23cSMatthew G. Knepley 334266a6c23cSMatthew G. Knepley PetscFunctionBegin; 334366a6c23cSMatthew G. Knepley PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 334466a6c23cSMatthew G. Knepley ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeSetMomentOrder_C",(PetscDualSpace,PetscInt),(sp,order));CHKERRQ(ierr); 334566a6c23cSMatthew G. Knepley PetscFunctionReturn(0); 334666a6c23cSMatthew G. Knepley } 33473f27d899SToby Isaac 33486f905325SMatthew G. Knepley static PetscErrorCode PetscDualSpaceInitialize_Lagrange(PetscDualSpace sp) 334920cf1dd8SToby Isaac { 335020cf1dd8SToby Isaac PetscFunctionBegin; 335120cf1dd8SToby Isaac sp->ops->destroy = PetscDualSpaceDestroy_Lagrange; 33526f905325SMatthew G. Knepley sp->ops->view = PetscDualSpaceView_Lagrange; 33536f905325SMatthew G. Knepley sp->ops->setfromoptions = PetscDualSpaceSetFromOptions_Lagrange; 335420cf1dd8SToby Isaac sp->ops->duplicate = PetscDualSpaceDuplicate_Lagrange; 33556f905325SMatthew G. Knepley sp->ops->setup = PetscDualSpaceSetUp_Lagrange; 33563f27d899SToby Isaac sp->ops->createheightsubspace = NULL; 33573f27d899SToby Isaac sp->ops->createpointsubspace = NULL; 335820cf1dd8SToby Isaac sp->ops->getsymmetries = PetscDualSpaceGetSymmetries_Lagrange; 335920cf1dd8SToby Isaac sp->ops->apply = PetscDualSpaceApplyDefault; 336020cf1dd8SToby Isaac sp->ops->applyall = PetscDualSpaceApplyAllDefault; 3361b4457527SToby Isaac sp->ops->applyint = PetscDualSpaceApplyInteriorDefault; 33623f27d899SToby Isaac sp->ops->createalldata = PetscDualSpaceCreateAllDataDefault; 3363b4457527SToby Isaac sp->ops->createintdata = PetscDualSpaceCreateInteriorDataDefault; 336420cf1dd8SToby Isaac PetscFunctionReturn(0); 336520cf1dd8SToby Isaac } 336620cf1dd8SToby Isaac 336720cf1dd8SToby Isaac /*MC 336820cf1dd8SToby Isaac PETSCDUALSPACELAGRANGE = "lagrange" - A PetscDualSpace object that encapsulates a dual space of pointwise evaluation functionals 336920cf1dd8SToby Isaac 337020cf1dd8SToby Isaac Level: intermediate 337120cf1dd8SToby Isaac 337220cf1dd8SToby Isaac .seealso: PetscDualSpaceType, PetscDualSpaceCreate(), PetscDualSpaceSetType() 337320cf1dd8SToby Isaac M*/ 337420cf1dd8SToby Isaac PETSC_EXTERN PetscErrorCode PetscDualSpaceCreate_Lagrange(PetscDualSpace sp) 337520cf1dd8SToby Isaac { 337620cf1dd8SToby Isaac PetscDualSpace_Lag *lag; 337720cf1dd8SToby Isaac PetscErrorCode ierr; 337820cf1dd8SToby Isaac 337920cf1dd8SToby Isaac PetscFunctionBegin; 338020cf1dd8SToby Isaac PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 338120cf1dd8SToby Isaac ierr = PetscNewLog(sp,&lag);CHKERRQ(ierr); 338220cf1dd8SToby Isaac sp->data = lag; 338320cf1dd8SToby Isaac 33843f27d899SToby Isaac lag->tensorCell = PETSC_FALSE; 338520cf1dd8SToby Isaac lag->tensorSpace = PETSC_FALSE; 338620cf1dd8SToby Isaac lag->continuous = PETSC_TRUE; 33873f27d899SToby Isaac lag->numCopies = PETSC_DEFAULT; 33883f27d899SToby Isaac lag->numNodeSkip = PETSC_DEFAULT; 33893f27d899SToby Isaac lag->nodeType = PETSCDTNODES_DEFAULT; 339066a6c23cSMatthew G. Knepley lag->useMoments = PETSC_FALSE; 339166a6c23cSMatthew G. Knepley lag->momentOrder = 0; 339220cf1dd8SToby Isaac 339320cf1dd8SToby Isaac ierr = PetscDualSpaceInitialize_Lagrange(sp);CHKERRQ(ierr); 339420cf1dd8SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetContinuity_C", PetscDualSpaceLagrangeGetContinuity_Lagrange);CHKERRQ(ierr); 339520cf1dd8SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetContinuity_C", PetscDualSpaceLagrangeSetContinuity_Lagrange);CHKERRQ(ierr); 339620cf1dd8SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetTensor_C", PetscDualSpaceLagrangeGetTensor_Lagrange);CHKERRQ(ierr); 339720cf1dd8SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetTensor_C", PetscDualSpaceLagrangeSetTensor_Lagrange);CHKERRQ(ierr); 33983f27d899SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetTrimmed_C", PetscDualSpaceLagrangeGetTrimmed_Lagrange);CHKERRQ(ierr); 33993f27d899SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetTrimmed_C", PetscDualSpaceLagrangeSetTrimmed_Lagrange);CHKERRQ(ierr); 34003f27d899SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetNodeType_C", PetscDualSpaceLagrangeGetNodeType_Lagrange);CHKERRQ(ierr); 34013f27d899SToby Isaac ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetNodeType_C", PetscDualSpaceLagrangeSetNodeType_Lagrange);CHKERRQ(ierr); 340266a6c23cSMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetUseMoments_C", PetscDualSpaceLagrangeGetUseMoments_Lagrange);CHKERRQ(ierr); 340366a6c23cSMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetUseMoments_C", PetscDualSpaceLagrangeSetUseMoments_Lagrange);CHKERRQ(ierr); 340466a6c23cSMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetMomentOrder_C", PetscDualSpaceLagrangeGetMomentOrder_Lagrange);CHKERRQ(ierr); 340566a6c23cSMatthew G. Knepley ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetMomentOrder_C", PetscDualSpaceLagrangeSetMomentOrder_Lagrange);CHKERRQ(ierr); 340620cf1dd8SToby Isaac PetscFunctionReturn(0); 340720cf1dd8SToby Isaac } 3408