11a989b97SToby Isaac #include <petsc/private/petscimpl.h> 228222859SToby Isaac #include <petsc/private/dtimpl.h> /*I "petscdt.h" I*/ 31a989b97SToby Isaac 4*29a920c6SToby Isaac /*MC 5*29a920c6SToby Isaac PetscDTAltV - An interface for common operations on k-forms, also known as alternating algebraic forms or alternating k-linear maps. 6*29a920c6SToby Isaac The name of the interface comes from the notation "Alt V" for the algebra of all k-forms acting vectors in the space V, also known as the exterior algebra of V*. 7*29a920c6SToby Isaac 8*29a920c6SToby Isaac A recommended reference for this material is Section 2 "Exterior algebra and exterior calculus" in "Finite element 9*29a920c6SToby Isaac exterior calculus, homological techniques, and applications", by Arnold, Falk, & Winther (2006, doi:10.1017/S0962492906210018). 10*29a920c6SToby Isaac 11*29a920c6SToby Isaac A k-form w (k is called the "form degree" of w) is an alternating k-linear map acting on tuples (v_1, ..., v_k) of 12*29a920c6SToby Isaac vectors from a vector space V and producing a real number: 13*29a920c6SToby Isaac - alternating: swapping any two vectors in a tuple reverses the sign of the result, e.g. w(v_1, v_2, ..., v_k) = -w(v_2, v_1, ..., v_k) 14*29a920c6SToby Isaac - k-linear: w acts linear in each vector separately, e.g. w(a*v + b*y, v_2, ..., v_k) = a*w(v,v_2,...,v_k) + b*w(y,v_2,...,v_k) 15*29a920c6SToby Isaac This action is implemented as PetscDTAltVApply. 16*29a920c6SToby Isaac 17*29a920c6SToby Isaac The k-forms on a vector space form a vector space themselves, Alt^k V. The dimension of Alt^k V, if V is N dimensional, is N choose k. (This 18*29a920c6SToby Isaac shows that for an N dimensional space, only 0 <= k <= N are valid form degrees.) 19*29a920c6SToby Isaac The standard basis for Alt^k V, used in PetscDTAltV, has one basis k-form for each ordered subset of k coordinates of the N dimensional space: 20*29a920c6SToby Isaac For example, if the coordinate directions of a four dimensional space are (t, x, y, z), then there are 4 choose 2 = 6 ordered subsets of two coordinates. 21*29a920c6SToby Isaac They are, in lexicographic order, (t, x), (t, y), (t, z), (x, y), (x, z) and (y, z). PetscDTAltV also orders the basis of Alt^k V lexicographically 22*29a920c6SToby Isaac by the associated subsets. 23*29a920c6SToby Isaac 24*29a920c6SToby Isaac The unit basis k-form associated with coordinates (c_1, ..., c_k) acts on a set of k vectors (v_1, ..., v_k) by creating a square matrix V where 25*29a920c6SToby Isaac V[i,j] = v_i[c_j] and taking the determinant of V. 26*29a920c6SToby Isaac 27*29a920c6SToby Isaac If j + k <= N, then a j-form f and a k-form g can be multiplied to create a (j+k)-form using the wedge or exterior product, (f wedge g). 28*29a920c6SToby Isaac This is an anticommutative product, (f wedge g) = -(g wedge f). It is sufficient to describe the wedge product of two basis forms. 29*29a920c6SToby Isaac Let f be the basis j-form associated with coordinates (f_1,...,f_j) and g be the basis k-form associated with coordinates (g_1,...,g_k): 30*29a920c6SToby Isaac - If there is any coordinate in both sets, then (f wedge g) = 0. 31*29a920c6SToby Isaac - Otherwise, (f wedge g) is a multiple of the basis (j+k)-form h associated with (f_1,...,f_j,g_1,...,g_k). 32*29a920c6SToby Isaac - In fact it is equal to either h or -h depending on how (f_1,...,f_j,g_1,...,g_k) compares to the same list of coordinates given in ascending order: if it is an even permutation of that list, then (f wedge g) = h, otherwise (f wedge g) = -h. 33*29a920c6SToby Isaac The wedge product is implemented for either two inputs (f and g) in PetscDTAltVWedge, or for one (just f, giving a 34*29a920c6SToby Isaac matrix to multiply against multiple choices of g) in PetscDTAltVWedgeMatrix. 35*29a920c6SToby Isaac 36*29a920c6SToby Isaac If k > 0, a k-form w and a vector v can combine to make a (k-1)-formm through the interior product, (w int v), 37*29a920c6SToby Isaac defined by (w int v)(v_1,...,v_{k-1}) = w(v,v_1,...,v_{k-1}). 38*29a920c6SToby Isaac 39*29a920c6SToby Isaac The interior product is implemented for either two inputs (w and v) in PetscDTAltVInterior, for one (just v, giving a 40*29a920c6SToby Isaac matrix to multiply against multiple choices of w) in PetscDTAltVInteriorMatrix, 41*29a920c6SToby Isaac or for no inputs (giving the sparsity pattern of PetscDTAltVInteriorMatrix) in PetscDTAltVInteriorPattern. 42*29a920c6SToby Isaac 43*29a920c6SToby Isaac When there is a linear map L: V -> W from an N dimensional vector space to an M dimensional vector space, 44*29a920c6SToby Isaac it induces the linear pullback map L^* : Alt^k W -> Alt^k V, defined by L^* w(v_1,...,v_k) = w(L v_1, ..., L v_k). 45*29a920c6SToby Isaac The pullback is implemented as PetscDTAltVPullback (acting on a known w) and PetscDTAltVPullbackMatrix (creating a matrix that computes the actin of L^*). 46*29a920c6SToby Isaac 47*29a920c6SToby Isaac Alt^k V and Alt^(N-k) V have the same dimension, and the Hodge star operator maps between them. We note that Alt^N V is a one dimensional space, and its 48*29a920c6SToby Isaac basis vector is sometime called vol. The Hodge star operator has the property that (f wedge (star g)) = (f,g) vol, where (f,g) is the simple inner product 49*29a920c6SToby Isaac of the basis coefficients of f and g. 50*29a920c6SToby Isaac Powers of the Hodge star operator can be applied with PetscDTAltVStar 51*29a920c6SToby Isaac 52*29a920c6SToby Isaac level: intermediate 53*29a920c6SToby Isaac 54*29a920c6SToby Isaac .seealso: PetscDTAltVApply(), PetscDTAltVWedge(), PetscDTAltVInterior(), PetscDTAltVPullback(), PetscDTAltVStar() 55*29a920c6SToby Isaac M*/ 56*29a920c6SToby Isaac 57fad4db65SToby Isaac /*@ 5828222859SToby Isaac PetscDTAltVApply - Apply an a k-form (an alternating k-linear map) to a set of k N-dimensional vectors 59fad4db65SToby Isaac 60fad4db65SToby Isaac Input Arguments: 6128222859SToby Isaac + N - the dimension of the vector space, N >= 0 6228222859SToby Isaac . k - the degree k of the k-form w, 0 <= k <= N 6328222859SToby Isaac . w - a k-form, size [N choose k] (each degree of freedom of a k-form is associated with a subset of k coordinates of the N-dimensional vectors: the degrees of freedom are ordered lexicographically by their associated subsets) 6428222859SToby Isaac - v - a set of k vectors of size N, size [k x N], each vector stored contiguously 65fad4db65SToby Isaac 66fad4db65SToby Isaac Output Arguments: 6728222859SToby Isaac . wv - w(v_1,...,v_k) = \sum_i w_i * det(V_i): the degree of freedom w_i is associated with coordinates [s_{i,1},...,s_{i,k}], and the square matrix V_i has entry (j,k) given by the s_{i,k}'th coordinate of v_j 68fad4db65SToby Isaac 69fad4db65SToby Isaac Level: intermediate 70fad4db65SToby Isaac 71*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVPullback(), PetscDTAltVPullbackMatrix() 72fad4db65SToby Isaac @*/ 731a989b97SToby Isaac PetscErrorCode PetscDTAltVApply(PetscInt N, PetscInt k, const PetscReal *w, const PetscReal *v, PetscReal *wv) 741a989b97SToby Isaac { 751a989b97SToby Isaac PetscErrorCode ierr; 761a989b97SToby Isaac 771a989b97SToby Isaac PetscFunctionBegin; 781a989b97SToby Isaac if (N < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid dimension"); 791a989b97SToby Isaac if (k < 0 || k > N) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid form degree"); 801a989b97SToby Isaac if (N <= 3) { 811a989b97SToby Isaac if (!k) { 821a989b97SToby Isaac *wv = w[0]; 831a989b97SToby Isaac } else { 841a989b97SToby Isaac if (N == 1) {*wv = w[0] * v[0];} 851a989b97SToby Isaac else if (N == 2) { 861a989b97SToby Isaac if (k == 1) {*wv = w[0] * v[0] + w[1] * v[1];} 871a989b97SToby Isaac else {*wv = w[0] * (v[0] * v[3] - v[1] * v[2]);} 881a989b97SToby Isaac } else { 891a989b97SToby Isaac if (k == 1) {*wv = w[0] * v[0] + w[1] * v[1] + w[2] * v[2];} 901a989b97SToby Isaac else if (k == 2) { 911a989b97SToby Isaac *wv = w[0] * (v[0] * v[4] - v[1] * v[3]) + 921a989b97SToby Isaac w[1] * (v[0] * v[5] - v[2] * v[3]) + 931a989b97SToby Isaac w[2] * (v[1] * v[5] - v[2] * v[4]); 941a989b97SToby Isaac } else { 951a989b97SToby Isaac *wv = w[0] * (v[0] * (v[4] * v[8] - v[5] * v[7]) + 961a989b97SToby Isaac v[1] * (v[5] * v[6] - v[3] * v[8]) + 971a989b97SToby Isaac v[2] * (v[3] * v[7] - v[4] * v[6])); 981a989b97SToby Isaac } 991a989b97SToby Isaac } 1001a989b97SToby Isaac } 1011a989b97SToby Isaac } else { 1021a989b97SToby Isaac PetscInt Nk, Nf; 103fad4db65SToby Isaac PetscInt *subset, *perm; 1041a989b97SToby Isaac PetscInt i, j, l; 1051a989b97SToby Isaac PetscReal sum = 0.; 1061a989b97SToby Isaac 107fad4db65SToby Isaac ierr = PetscDTFactorialInt(k, &Nf);CHKERRQ(ierr); 108fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k, &Nk);CHKERRQ(ierr); 109fad4db65SToby Isaac ierr = PetscMalloc2(k, &subset, k, &perm);CHKERRQ(ierr); 1101a989b97SToby Isaac for (i = 0; i < Nk; i++) { 1111a989b97SToby Isaac PetscReal subsum = 0.; 1121a989b97SToby Isaac 1131a989b97SToby Isaac ierr = PetscDTEnumSubset(N, k, i, subset);CHKERRQ(ierr); 1141a989b97SToby Isaac for (j = 0; j < Nf; j++) { 1151a989b97SToby Isaac PetscBool permOdd; 1161a989b97SToby Isaac PetscReal prod; 1171a989b97SToby Isaac 118fad4db65SToby Isaac ierr = PetscDTEnumPerm(k, j, perm, &permOdd);CHKERRQ(ierr); 1191a989b97SToby Isaac prod = permOdd ? -1. : 1.; 1201a989b97SToby Isaac for (l = 0; l < k; l++) { 1211a989b97SToby Isaac prod *= v[perm[l] * N + subset[l]]; 1221a989b97SToby Isaac } 1231a989b97SToby Isaac subsum += prod; 1241a989b97SToby Isaac } 1251a989b97SToby Isaac sum += w[i] * subsum; 1261a989b97SToby Isaac } 127fad4db65SToby Isaac ierr = PetscFree2(subset, perm);CHKERRQ(ierr); 1281a989b97SToby Isaac *wv = sum; 1291a989b97SToby Isaac } 1301a989b97SToby Isaac PetscFunctionReturn(0); 1311a989b97SToby Isaac } 1321a989b97SToby Isaac 133fad4db65SToby Isaac /*@ 13428222859SToby Isaac PetscDTAltVWedge - Compute the wedge product of a j-form and a k-form, giving a (j+k) form 135fad4db65SToby Isaac 136fad4db65SToby Isaac Input Arguments: 13728222859SToby Isaac + N - the dimension of the vector space, N >= 0 13828222859SToby Isaac . j - the degree j of the j-form a, 0 <= j <= N 13928222859SToby Isaac . k - the degree k of the k-form b, 0 <= k <= N and 0 <= j+k <= N 14028222859SToby Isaac . a - a j-form, size [N choose j] 14128222859SToby Isaac - b - a k-form, size [N choose k] 142fad4db65SToby Isaac 143fad4db65SToby Isaac Output Arguments: 14428222859SToby Isaac . awedgeb - the (j+k)-form a wedge b, size [N choose (j+k)]: (a wedge b)(v_1,...,v_{j+k}) = \sum_{s} sign(s) a(v_{s_1},...,v_{s_j}) b(v_{s_{j+1}},...,v_{s_{j+k}}), 14528222859SToby Isaac where the sum is over permutations s such that s_1 < s_2 < ... < s_j and s_{j+1} < s_{j+2} < ... < s_{j+k}. 146fad4db65SToby Isaac 147fad4db65SToby Isaac Level: intermediate 148fad4db65SToby Isaac 149*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVWedgeMatrix(), PetscDTAltVPullback(), PetscDTAltVPullbackMatrix() 150fad4db65SToby Isaac @*/ 1511a989b97SToby Isaac PetscErrorCode PetscDTAltVWedge(PetscInt N, PetscInt j, PetscInt k, const PetscReal *a, const PetscReal *b, PetscReal *awedgeb) 1521a989b97SToby Isaac { 1531a989b97SToby Isaac PetscInt i; 1541a989b97SToby Isaac PetscErrorCode ierr; 1551a989b97SToby Isaac 1561a989b97SToby Isaac PetscFunctionBegin; 1571a989b97SToby Isaac if (N < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid dimension"); 1581a989b97SToby Isaac if (j < 0 || k < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "negative form degree"); 1591a989b97SToby Isaac if (j + k > N) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Wedge greater than dimension"); 1601a989b97SToby Isaac if (N <= 3) { 1611a989b97SToby Isaac PetscInt Njk; 1621a989b97SToby Isaac 163fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, j+k, &Njk);CHKERRQ(ierr); 1641a989b97SToby Isaac if (!j) {for (i = 0; i < Njk; i++) {awedgeb[i] = a[0] * b[i];}} 1651a989b97SToby Isaac else if (!k) {for (i = 0; i < Njk; i++) {awedgeb[i] = a[i] * b[0];}} 1661a989b97SToby Isaac else { 1671a989b97SToby Isaac if (N == 2) {awedgeb[0] = a[0] * b[1] - a[1] * b[0];} 1681a989b97SToby Isaac else { 1691a989b97SToby Isaac if (j+k == 2) { 1701a989b97SToby Isaac awedgeb[0] = a[0] * b[1] - a[1] * b[0]; 1711a989b97SToby Isaac awedgeb[1] = a[0] * b[2] - a[2] * b[0]; 1721a989b97SToby Isaac awedgeb[2] = a[1] * b[2] - a[2] * b[1]; 1731a989b97SToby Isaac } else { 1741a989b97SToby Isaac awedgeb[0] = a[0] * b[2] - a[1] * b[1] + a[2] * b[0]; 1751a989b97SToby Isaac } 1761a989b97SToby Isaac } 1771a989b97SToby Isaac } 1781a989b97SToby Isaac } else { 1791a989b97SToby Isaac PetscInt Njk; 1801a989b97SToby Isaac PetscInt JKj; 1811a989b97SToby Isaac PetscInt *subset, *subsetjk, *subsetj, *subsetk; 1821a989b97SToby Isaac PetscInt i; 1831a989b97SToby Isaac 184fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, j+k, &Njk);CHKERRQ(ierr); 185fad4db65SToby Isaac ierr = PetscDTBinomialInt(j+k, j, &JKj);CHKERRQ(ierr); 1861a989b97SToby Isaac ierr = PetscMalloc4(j+k, &subset, j+k, &subsetjk, j, &subsetj, k, &subsetk);CHKERRQ(ierr); 1871a989b97SToby Isaac for (i = 0; i < Njk; i++) { 1881a989b97SToby Isaac PetscReal sum = 0.; 1891a989b97SToby Isaac PetscInt l; 1901a989b97SToby Isaac 1911a989b97SToby Isaac ierr = PetscDTEnumSubset(N, j+k, i, subset);CHKERRQ(ierr); 1921a989b97SToby Isaac for (l = 0; l < JKj; l++) { 1931a989b97SToby Isaac PetscBool jkOdd; 1941a989b97SToby Isaac PetscInt m, jInd, kInd; 1951a989b97SToby Isaac 1961a989b97SToby Isaac ierr = PetscDTEnumSplit(j+k, j, l, subsetjk, &jkOdd);CHKERRQ(ierr); 1971a989b97SToby Isaac for (m = 0; m < j; m++) { 1981a989b97SToby Isaac subsetj[m] = subset[subsetjk[m]]; 1991a989b97SToby Isaac } 2001a989b97SToby Isaac for (m = 0; m < k; m++) { 2011a989b97SToby Isaac subsetk[m] = subset[subsetjk[j+m]]; 2021a989b97SToby Isaac } 2031a989b97SToby Isaac ierr = PetscDTSubsetIndex(N, j, subsetj, &jInd);CHKERRQ(ierr); 2041a989b97SToby Isaac ierr = PetscDTSubsetIndex(N, k, subsetk, &kInd);CHKERRQ(ierr); 2051a989b97SToby Isaac sum += jkOdd ? -(a[jInd] * b[kInd]) : (a[jInd] * b[kInd]); 2061a989b97SToby Isaac } 2071a989b97SToby Isaac awedgeb[i] = sum; 2081a989b97SToby Isaac } 2091a989b97SToby Isaac ierr = PetscFree4(subset, subsetjk, subsetj, subsetk);CHKERRQ(ierr); 2101a989b97SToby Isaac } 2111a989b97SToby Isaac PetscFunctionReturn(0); 2121a989b97SToby Isaac } 2131a989b97SToby Isaac 214fad4db65SToby Isaac /*@ 21528222859SToby Isaac PetscDTAltVWedgeMatrix - Compute the matrix defined by the wedge product with a given j-form that maps k-forms to (j+k)-forms 216fad4db65SToby Isaac 217fad4db65SToby Isaac Input Arguments: 21828222859SToby Isaac + N - the dimension of the vector space, N >= 0 21928222859SToby Isaac . j - the degree j of the j-form a, 0 <= j <= N 22028222859SToby Isaac . k - the degree k of the k-forms that (a wedge) will be applied to, 0 <= k <= N and 0 <= j+k <= N 22128222859SToby Isaac - a - a j-form, size [N choose j] 222fad4db65SToby Isaac 223fad4db65SToby Isaac Output Arguments: 22428222859SToby Isaac . awedge - (a wedge), an [(N choose j+k) x (N choose k)] matrix in row-major order, such that (a wedge) * b = a wedge b 225fad4db65SToby Isaac 226fad4db65SToby Isaac Level: intermediate 227fad4db65SToby Isaac 228*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVPullback(), PetscDTAltVPullbackMatrix() 229fad4db65SToby Isaac @*/ 2301a989b97SToby Isaac PetscErrorCode PetscDTAltVWedgeMatrix(PetscInt N, PetscInt j, PetscInt k, const PetscReal *a, PetscReal *awedgeMat) 2311a989b97SToby Isaac { 2321a989b97SToby Isaac PetscInt i; 2331a989b97SToby Isaac PetscErrorCode ierr; 2341a989b97SToby Isaac 2351a989b97SToby Isaac PetscFunctionBegin; 2361a989b97SToby Isaac if (N < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid dimension"); 2371a989b97SToby Isaac if (j < 0 || k < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "negative form degree"); 2381a989b97SToby Isaac if (j + k > N) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Wedge greater than dimension"); 2391a989b97SToby Isaac if (N <= 3) { 2401a989b97SToby Isaac PetscInt Njk; 2411a989b97SToby Isaac 242fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, j+k, &Njk);CHKERRQ(ierr); 2431a989b97SToby Isaac if (!j) { 2441a989b97SToby Isaac for (i = 0; i < Njk * Njk; i++) {awedgeMat[i] = 0.;} 2451a989b97SToby Isaac for (i = 0; i < Njk; i++) {awedgeMat[i * (Njk + 1)] = a[0];} 2461a989b97SToby Isaac } else if (!k) { 2471a989b97SToby Isaac for (i = 0; i < Njk; i++) {awedgeMat[i] = a[i];} 2481a989b97SToby Isaac } else { 2491a989b97SToby Isaac if (N == 2) { 2501a989b97SToby Isaac awedgeMat[0] = -a[1]; awedgeMat[1] = a[0]; 2511a989b97SToby Isaac } else { 2521a989b97SToby Isaac if (j+k == 2) { 2531a989b97SToby Isaac awedgeMat[0] = -a[1]; awedgeMat[1] = a[0]; awedgeMat[2] = 0.; 2541a989b97SToby Isaac awedgeMat[3] = -a[2]; awedgeMat[4] = 0.; awedgeMat[5] = a[0]; 2551a989b97SToby Isaac awedgeMat[6] = 0.; awedgeMat[7] = -a[2]; awedgeMat[8] = a[1]; 2561a989b97SToby Isaac } else { 2571a989b97SToby Isaac awedgeMat[0] = a[2]; awedgeMat[1] = -a[1]; awedgeMat[2] = a[0]; 2581a989b97SToby Isaac } 2591a989b97SToby Isaac } 2601a989b97SToby Isaac } 2611a989b97SToby Isaac } else { 2621a989b97SToby Isaac PetscInt Njk; 2631a989b97SToby Isaac PetscInt Nk; 2641a989b97SToby Isaac PetscInt JKj, i; 2651a989b97SToby Isaac PetscInt *subset, *subsetjk, *subsetj, *subsetk; 2661a989b97SToby Isaac 267fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k, &Nk);CHKERRQ(ierr); 268fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, j+k, &Njk);CHKERRQ(ierr); 269fad4db65SToby Isaac ierr = PetscDTBinomialInt(j+k, j, &JKj);CHKERRQ(ierr); 2701a989b97SToby Isaac ierr = PetscMalloc4(j+k, &subset, j+k, &subsetjk, j, &subsetj, k, &subsetk);CHKERRQ(ierr); 2711a989b97SToby Isaac for (i = 0; i < Njk * Nk; i++) awedgeMat[i] = 0.; 2721a989b97SToby Isaac for (i = 0; i < Njk; i++) { 2731a989b97SToby Isaac PetscInt l; 2741a989b97SToby Isaac 2751a989b97SToby Isaac ierr = PetscDTEnumSubset(N, j+k, i, subset);CHKERRQ(ierr); 2761a989b97SToby Isaac for (l = 0; l < JKj; l++) { 2771a989b97SToby Isaac PetscBool jkOdd; 2781a989b97SToby Isaac PetscInt m, jInd, kInd; 2791a989b97SToby Isaac 2801a989b97SToby Isaac ierr = PetscDTEnumSplit(j+k, j, l, subsetjk, &jkOdd);CHKERRQ(ierr); 2811a989b97SToby Isaac for (m = 0; m < j; m++) { 2821a989b97SToby Isaac subsetj[m] = subset[subsetjk[m]]; 2831a989b97SToby Isaac } 2841a989b97SToby Isaac for (m = 0; m < k; m++) { 2851a989b97SToby Isaac subsetk[m] = subset[subsetjk[j+m]]; 2861a989b97SToby Isaac } 2871a989b97SToby Isaac ierr = PetscDTSubsetIndex(N, j, subsetj, &jInd);CHKERRQ(ierr); 2881a989b97SToby Isaac ierr = PetscDTSubsetIndex(N, k, subsetk, &kInd);CHKERRQ(ierr); 2891a989b97SToby Isaac awedgeMat[i * Nk + kInd] += jkOdd ? - a[jInd] : a[jInd]; 2901a989b97SToby Isaac } 2911a989b97SToby Isaac } 2921a989b97SToby Isaac ierr = PetscFree4(subset, subsetjk, subsetj, subsetk);CHKERRQ(ierr); 2931a989b97SToby Isaac } 2941a989b97SToby Isaac PetscFunctionReturn(0); 2951a989b97SToby Isaac } 2961a989b97SToby Isaac 297fad4db65SToby Isaac /*@ 29828222859SToby Isaac PetscDTAltVPullback - Compute the pullback of a k-form under a linear transformation of the coordinate space 299fad4db65SToby Isaac 300fad4db65SToby Isaac Input Arguments: 30128222859SToby Isaac + N - the dimension of the origin vector space of the linear transformation, M >= 0 30228222859SToby Isaac . M - the dimension of the image vector space of the linear transformation, N >= 0 30328222859SToby Isaac . L - a linear transformation, an [M x N] matrix in row-major format 30428222859SToby Isaac . k - the *signed* degree k of the |k|-form w, -(min(M,N)) <= k <= min(M,N). A negative form degree indicates that the pullback should be conjugated by the Hodge star operator (see note). 30528222859SToby Isaac - w - a |k|-form in the image space, size [M choose |k|] 306fad4db65SToby Isaac 307fad4db65SToby Isaac Output Arguments: 30828222859SToby Isaac . Lstarw - the pullback of w to a |k|-form in the origin space, size [N choose |k|]: (Lstarw)(v_1,...v_k) = w(L*v_1,...,L*v_k). 309fad4db65SToby Isaac 310fad4db65SToby Isaac Level: intermediate 311fad4db65SToby Isaac 312fad4db65SToby Isaac Note: negative form degrees accomodate, e.g., H-div conforming vector fields. An H-div conforming vector field stores its degrees of freedom as (dx, dy, dz), like a 1-form, 31328222859SToby Isaac but its normal trace is integrated on faces, like a 2-form. The correct pullback then is to apply the Hodge star transformation from (M-2)-form to 2-form, pullback as a 2-form, 314fad4db65SToby Isaac then the inverse Hodge star transformation. 315fad4db65SToby Isaac 316*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVPullbackMatrix(), PetscDTAltVStar() 317fad4db65SToby Isaac @*/ 3181a989b97SToby Isaac PetscErrorCode PetscDTAltVPullback(PetscInt N, PetscInt M, const PetscReal *L, PetscInt k, const PetscReal *w, PetscReal *Lstarw) 3191a989b97SToby Isaac { 3201a989b97SToby Isaac PetscInt i, j, Nk, Mk; 3211a989b97SToby Isaac PetscErrorCode ierr; 3221a989b97SToby Isaac 3231a989b97SToby Isaac PetscFunctionBegin; 3241a989b97SToby Isaac if (N < 0 || M < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid dimensions"); 3251a989b97SToby Isaac if (PetscAbsInt(k) > N || PetscAbsInt(k) > M) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid form degree"); 3261a989b97SToby Isaac if (N <= 3 && M <= 3) { 3271a989b97SToby Isaac 328fad4db65SToby Isaac ierr = PetscDTBinomialInt(M, PetscAbsInt(k), &Mk);CHKERRQ(ierr); 329fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 3301a989b97SToby Isaac if (!k) { 3311a989b97SToby Isaac Lstarw[0] = w[0]; 3321a989b97SToby Isaac } else if (k == 1) { 3331a989b97SToby Isaac for (i = 0; i < Nk; i++) { 3341a989b97SToby Isaac PetscReal sum = 0.; 3351a989b97SToby Isaac 3361a989b97SToby Isaac for (j = 0; j < Mk; j++) {sum += L[j * Nk + i] * w[j];} 3371a989b97SToby Isaac Lstarw[i] = sum; 3381a989b97SToby Isaac } 3391a989b97SToby Isaac } else if (k == -1) { 3401a989b97SToby Isaac PetscReal mult[3] = {1., -1., 1.}; 3411a989b97SToby Isaac 3421a989b97SToby Isaac for (i = 0; i < Nk; i++) { 3431a989b97SToby Isaac PetscReal sum = 0.; 3441a989b97SToby Isaac 3451a989b97SToby Isaac for (j = 0; j < Mk; j++) { 3461a989b97SToby Isaac sum += L[(Mk - 1 - j) * Nk + (Nk - 1 - i)] * w[j] * mult[j]; 3471a989b97SToby Isaac } 3481a989b97SToby Isaac Lstarw[i] = mult[i] * sum; 3491a989b97SToby Isaac } 3501a989b97SToby Isaac } else if (k == 2) { 3511a989b97SToby Isaac PetscInt pairs[3][2] = {{0,1},{0,2},{1,2}}; 3521a989b97SToby Isaac 3531a989b97SToby Isaac for (i = 0; i < Nk; i++) { 3541a989b97SToby Isaac PetscReal sum = 0.; 3551a989b97SToby Isaac for (j = 0; j < Mk; j++) { 3561a989b97SToby Isaac sum += (L[pairs[j][0] * N + pairs[i][0]] * L[pairs[j][1] * N + pairs[i][1]] - 3571a989b97SToby Isaac L[pairs[j][1] * N + pairs[i][0]] * L[pairs[j][0] * N + pairs[i][1]]) * w[j]; 3581a989b97SToby Isaac } 3591a989b97SToby Isaac Lstarw[i] = sum; 3601a989b97SToby Isaac } 3611a989b97SToby Isaac } else if (k == -2) { 3621a989b97SToby Isaac PetscInt pairs[3][2] = {{1,2},{2,0},{0,1}}; 3631a989b97SToby Isaac PetscInt offi = (N == 2) ? 2 : 0; 3641a989b97SToby Isaac PetscInt offj = (M == 2) ? 2 : 0; 3651a989b97SToby Isaac 3661a989b97SToby Isaac for (i = 0; i < Nk; i++) { 3671a989b97SToby Isaac PetscReal sum = 0.; 3681a989b97SToby Isaac 3691a989b97SToby Isaac for (j = 0; j < Mk; j++) { 3701a989b97SToby Isaac sum += (L[pairs[offj + j][0] * N + pairs[offi + i][0]] * 3711a989b97SToby Isaac L[pairs[offj + j][1] * N + pairs[offi + i][1]] - 3721a989b97SToby Isaac L[pairs[offj + j][1] * N + pairs[offi + i][0]] * 3731a989b97SToby Isaac L[pairs[offj + j][0] * N + pairs[offi + i][1]]) * w[j]; 3741a989b97SToby Isaac 3751a989b97SToby Isaac } 3761a989b97SToby Isaac Lstarw[i] = sum; 3771a989b97SToby Isaac } 3781a989b97SToby Isaac } else { 3791a989b97SToby Isaac PetscReal detL = L[0] * (L[4] * L[8] - L[5] * L[7]) + 3801a989b97SToby Isaac L[1] * (L[5] * L[6] - L[3] * L[8]) + 3811a989b97SToby Isaac L[2] * (L[3] * L[7] - L[4] * L[6]); 3821a989b97SToby Isaac 3831a989b97SToby Isaac for (i = 0; i < Nk; i++) {Lstarw[i] = detL * w[i];} 3841a989b97SToby Isaac } 3851a989b97SToby Isaac } else { 3861a989b97SToby Isaac PetscInt Nf, l, p; 3871a989b97SToby Isaac PetscReal *Lw, *Lwv; 3881a989b97SToby Isaac PetscInt *subsetw, *subsetv; 389fad4db65SToby Isaac PetscInt *perm; 3901a989b97SToby Isaac PetscReal *walloc = NULL; 3911a989b97SToby Isaac const PetscReal *ww = NULL; 3921a989b97SToby Isaac PetscBool negative = PETSC_FALSE; 3931a989b97SToby Isaac 394fad4db65SToby Isaac ierr = PetscDTBinomialInt(M, PetscAbsInt(k), &Mk);CHKERRQ(ierr); 395fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 396fad4db65SToby Isaac ierr = PetscDTFactorialInt(PetscAbsInt(k), &Nf);CHKERRQ(ierr); 3971a989b97SToby Isaac if (k < 0) { 3981a989b97SToby Isaac negative = PETSC_TRUE; 3991a989b97SToby Isaac k = -k; 4001a989b97SToby Isaac ierr = PetscMalloc1(Mk, &walloc);CHKERRQ(ierr); 4011a989b97SToby Isaac ierr = PetscDTAltVStar(M, M - k, 1, w, walloc);CHKERRQ(ierr); 4021a989b97SToby Isaac ww = walloc; 4031a989b97SToby Isaac } else { 4041a989b97SToby Isaac ww = w; 4051a989b97SToby Isaac } 406fad4db65SToby Isaac ierr = PetscMalloc5(k, &subsetw, k, &subsetv, k, &perm, N * k, &Lw, k * k, &Lwv);CHKERRQ(ierr); 4071a989b97SToby Isaac for (i = 0; i < Nk; i++) Lstarw[i] = 0.; 4081a989b97SToby Isaac for (i = 0; i < Mk; i++) { 4091a989b97SToby Isaac ierr = PetscDTEnumSubset(M, k, i, subsetw);CHKERRQ(ierr); 4101a989b97SToby Isaac for (j = 0; j < Nk; j++) { 4111a989b97SToby Isaac ierr = PetscDTEnumSubset(N, k, j, subsetv);CHKERRQ(ierr); 4121a989b97SToby Isaac for (p = 0; p < Nf; p++) { 4131a989b97SToby Isaac PetscReal prod; 4141a989b97SToby Isaac PetscBool isOdd; 4151a989b97SToby Isaac 416fad4db65SToby Isaac ierr = PetscDTEnumPerm(k, p, perm, &isOdd);CHKERRQ(ierr); 4171a989b97SToby Isaac prod = isOdd ? -ww[i] : ww[i]; 4181a989b97SToby Isaac for (l = 0; l < k; l++) { 4191a989b97SToby Isaac prod *= L[subsetw[perm[l]] * N + subsetv[l]]; 4201a989b97SToby Isaac } 4211a989b97SToby Isaac Lstarw[j] += prod; 4221a989b97SToby Isaac } 4231a989b97SToby Isaac } 4241a989b97SToby Isaac } 4251a989b97SToby Isaac if (negative) { 4261a989b97SToby Isaac PetscReal *sLsw; 4271a989b97SToby Isaac 4281a989b97SToby Isaac ierr = PetscMalloc1(Nk, &sLsw);CHKERRQ(ierr); 4291a989b97SToby Isaac ierr = PetscDTAltVStar(N, N - k, -1, Lstarw, sLsw);CHKERRQ(ierr); 4301a989b97SToby Isaac for (i = 0; i < Nk; i++) Lstarw[i] = sLsw[i]; 4311a989b97SToby Isaac ierr = PetscFree(sLsw);CHKERRQ(ierr); 4321a989b97SToby Isaac } 433fad4db65SToby Isaac ierr = PetscFree5(subsetw, subsetv, perm, Lw, Lwv);CHKERRQ(ierr); 4341a989b97SToby Isaac ierr = PetscFree(walloc);CHKERRQ(ierr); 4351a989b97SToby Isaac } 4361a989b97SToby Isaac PetscFunctionReturn(0); 4371a989b97SToby Isaac } 4381a989b97SToby Isaac 439fad4db65SToby Isaac /*@ 440fad4db65SToby Isaac PetscDTAltVPullbackMatrix - Compute the pullback matrix for k-forms under a linear transformation 441fad4db65SToby Isaac 442fad4db65SToby Isaac Input Arguments: 44328222859SToby Isaac + N - the dimension of the origin vector space of the linear transformation, N >= 0 44428222859SToby Isaac . M - the dimension of the image vector space of the linear transformation, M >= 0 44528222859SToby Isaac . L - a linear transformation, an [M x N] matrix in row-major format 44628222859SToby Isaac - k - the *signed* degree k of the |k|-forms on which Lstar acts, -(min(M,N)) <= k <= min(M,N). A negative form degree indicates that the pullback should be conjugated by the Hodge star operator (see note in PetscDTAltvPullback()) 447fad4db65SToby Isaac 448fad4db65SToby Isaac Output Arguments: 44928222859SToby Isaac . Lstar - the pullback matrix, an [(N choose |k|) x (M choose |k|)] matrix in row-major format such that Lstar * w = L^* w 450fad4db65SToby Isaac 451fad4db65SToby Isaac Level: intermediate 452fad4db65SToby Isaac 453*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVPullback(), PetscDTAltVStar() 454fad4db65SToby Isaac @*/ 4551a989b97SToby Isaac PetscErrorCode PetscDTAltVPullbackMatrix(PetscInt N, PetscInt M, const PetscReal *L, PetscInt k, PetscReal *Lstar) 4561a989b97SToby Isaac { 4571a989b97SToby Isaac PetscInt Nk, Mk, Nf, i, j, l, p; 4581a989b97SToby Isaac PetscReal *Lw, *Lwv; 4591a989b97SToby Isaac PetscInt *subsetw, *subsetv; 460fad4db65SToby Isaac PetscInt *perm; 4611a989b97SToby Isaac PetscBool negative = PETSC_FALSE; 4621a989b97SToby Isaac PetscErrorCode ierr; 4631a989b97SToby Isaac 4641a989b97SToby Isaac PetscFunctionBegin; 4651a989b97SToby Isaac if (N < 0 || M < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid dimensions"); 4661a989b97SToby Isaac if (PetscAbsInt(k) > N || PetscAbsInt(k) > M) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid form degree"); 4671a989b97SToby Isaac if (N <= 3 && M <= 3) { 4681a989b97SToby Isaac PetscReal mult[3] = {1., -1., 1.}; 4691a989b97SToby Isaac 470fad4db65SToby Isaac ierr = PetscDTBinomialInt(M, PetscAbsInt(k), &Mk);CHKERRQ(ierr); 471fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 4721a989b97SToby Isaac if (!k) { 4731a989b97SToby Isaac Lstar[0] = 1.; 4741a989b97SToby Isaac } else if (k == 1) { 4751a989b97SToby Isaac for (i = 0; i < Nk; i++) {for (j = 0; j < Mk; j++) {Lstar[i * Mk + j] = L[j * Nk + i];}} 4761a989b97SToby Isaac } else if (k == -1) { 4771a989b97SToby Isaac for (i = 0; i < Nk; i++) { 4781a989b97SToby Isaac for (j = 0; j < Mk; j++) { 4791a989b97SToby Isaac Lstar[i * Mk + j] = L[(Mk - 1 - j) * Nk + (Nk - 1 - i)] * mult[i] * mult[j]; 4801a989b97SToby Isaac } 4811a989b97SToby Isaac } 4821a989b97SToby Isaac } else if (k == 2) { 4831a989b97SToby Isaac PetscInt pairs[3][2] = {{0,1},{0,2},{1,2}}; 4841a989b97SToby Isaac 4851a989b97SToby Isaac for (i = 0; i < Nk; i++) { 4861a989b97SToby Isaac for (j = 0; j < Mk; j++) { 4871a989b97SToby Isaac Lstar[i * Mk + j] = L[pairs[j][0] * N + pairs[i][0]] * 4881a989b97SToby Isaac L[pairs[j][1] * N + pairs[i][1]] - 4891a989b97SToby Isaac L[pairs[j][1] * N + pairs[i][0]] * 4901a989b97SToby Isaac L[pairs[j][0] * N + pairs[i][1]]; 4911a989b97SToby Isaac } 4921a989b97SToby Isaac } 4931a989b97SToby Isaac } else if (k == -2) { 4941a989b97SToby Isaac PetscInt pairs[3][2] = {{1,2},{2,0},{0,1}}; 4951a989b97SToby Isaac PetscInt offi = (N == 2) ? 2 : 0; 4961a989b97SToby Isaac PetscInt offj = (M == 2) ? 2 : 0; 4971a989b97SToby Isaac 4981a989b97SToby Isaac for (i = 0; i < Nk; i++) { 4991a989b97SToby Isaac for (j = 0; j < Mk; j++) { 5001a989b97SToby Isaac Lstar[i * Mk + j] = L[pairs[offj + j][0] * N + pairs[offi + i][0]] * 5011a989b97SToby Isaac L[pairs[offj + j][1] * N + pairs[offi + i][1]] - 5021a989b97SToby Isaac L[pairs[offj + j][1] * N + pairs[offi + i][0]] * 5031a989b97SToby Isaac L[pairs[offj + j][0] * N + pairs[offi + i][1]]; 5041a989b97SToby Isaac } 5051a989b97SToby Isaac } 5061a989b97SToby Isaac } else { 5071a989b97SToby Isaac PetscReal detL = L[0] * (L[4] * L[8] - L[5] * L[7]) + 5081a989b97SToby Isaac L[1] * (L[5] * L[6] - L[3] * L[8]) + 5091a989b97SToby Isaac L[2] * (L[3] * L[7] - L[4] * L[6]); 5101a989b97SToby Isaac 5111a989b97SToby Isaac for (i = 0; i < Nk; i++) {Lstar[i] = detL;} 5121a989b97SToby Isaac } 5131a989b97SToby Isaac } else { 5141a989b97SToby Isaac if (k < 0) { 5151a989b97SToby Isaac negative = PETSC_TRUE; 5161a989b97SToby Isaac k = -k; 5171a989b97SToby Isaac } 518fad4db65SToby Isaac ierr = PetscDTBinomialInt(M, PetscAbsInt(k), &Mk);CHKERRQ(ierr); 519fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, PetscAbsInt(k), &Nk);CHKERRQ(ierr); 520fad4db65SToby Isaac ierr = PetscDTFactorialInt(PetscAbsInt(k), &Nf);CHKERRQ(ierr); 521fad4db65SToby Isaac ierr = PetscMalloc5(M, &subsetw, N, &subsetv, k, &perm, N * k, &Lw, k * k, &Lwv);CHKERRQ(ierr); 5221a989b97SToby Isaac for (i = 0; i < Nk * Mk; i++) Lstar[i] = 0.; 5231a989b97SToby Isaac for (i = 0; i < Mk; i++) { 5241a989b97SToby Isaac PetscBool iOdd; 5251a989b97SToby Isaac PetscInt iidx, jidx; 5261a989b97SToby Isaac 5271a989b97SToby Isaac ierr = PetscDTEnumSplit(M, k, i, subsetw, &iOdd);CHKERRQ(ierr); 5281a989b97SToby Isaac iidx = negative ? Mk - 1 - i : i; 52928222859SToby Isaac iOdd = negative ? (PetscBool) (iOdd ^ ((k * (M-k)) & 1)) : PETSC_FALSE; 5301a989b97SToby Isaac for (j = 0; j < Nk; j++) { 5311a989b97SToby Isaac PetscBool jOdd; 5321a989b97SToby Isaac 5331a989b97SToby Isaac ierr = PetscDTEnumSplit(N, k, j, subsetv, &jOdd);CHKERRQ(ierr); 5341a989b97SToby Isaac jidx = negative ? Nk - 1 - j : j; 53528222859SToby Isaac jOdd = negative ? (PetscBool) (iOdd ^ jOdd ^ ((k * (N-k)) & 1)) : PETSC_FALSE; 5361a989b97SToby Isaac for (p = 0; p < Nf; p++) { 5371a989b97SToby Isaac PetscReal prod; 5381a989b97SToby Isaac PetscBool isOdd; 5391a989b97SToby Isaac 540fad4db65SToby Isaac ierr = PetscDTEnumPerm(k, p, perm, &isOdd);CHKERRQ(ierr); 54128222859SToby Isaac isOdd = (PetscBool) (isOdd ^ jOdd); 5421a989b97SToby Isaac prod = isOdd ? -1. : 1.; 5431a989b97SToby Isaac for (l = 0; l < k; l++) { 5441a989b97SToby Isaac prod *= L[subsetw[perm[l]] * N + subsetv[l]]; 5451a989b97SToby Isaac } 5461a989b97SToby Isaac Lstar[jidx * Mk + iidx] += prod; 5471a989b97SToby Isaac } 5481a989b97SToby Isaac } 5491a989b97SToby Isaac } 550fad4db65SToby Isaac ierr = PetscFree5(subsetw, subsetv, perm, Lw, Lwv);CHKERRQ(ierr); 5511a989b97SToby Isaac } 5521a989b97SToby Isaac PetscFunctionReturn(0); 5531a989b97SToby Isaac } 5541a989b97SToby Isaac 555fad4db65SToby Isaac /*@ 55628222859SToby Isaac PetscDTAltVInterior - Compute the interior product of a k-form with a vector 557fad4db65SToby Isaac 558fad4db65SToby Isaac Input Arguments: 55928222859SToby Isaac + N - the dimension of the vector space, N >= 0 56028222859SToby Isaac . k - the degree k of the k-form w, 0 <= k <= N 56128222859SToby Isaac . w - a k-form, size [N choose k] 56228222859SToby Isaac - v - an N dimensional vector 563fad4db65SToby Isaac 564fad4db65SToby Isaac Output Arguments: 56528222859SToby Isaac . wIntv - the (k-1)-form (w int v), size [N choose (k-1)]: (w int v) is defined by its action on (k-1) vectors {v_1, ..., v_{k-1}} as (w inv v)(v_1, ..., v_{k-1}) = w(v, v_1, ..., v_{k-1}). 566fad4db65SToby Isaac 567fad4db65SToby Isaac Level: intermediate 568fad4db65SToby Isaac 569*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVInteriorMatrix(), PetscDTAltVInteriorPattern(), PetscDTAltVPullback(), PetscDTAltVPullbackMatrix() 570fad4db65SToby Isaac @*/ 5711a989b97SToby Isaac PetscErrorCode PetscDTAltVInterior(PetscInt N, PetscInt k, const PetscReal *w, const PetscReal *v, PetscReal *wIntv) 5721a989b97SToby Isaac { 5731a989b97SToby Isaac PetscInt i, Nk, Nkm; 5741a989b97SToby Isaac PetscErrorCode ierr; 5751a989b97SToby Isaac 5761a989b97SToby Isaac PetscFunctionBegin; 5771a989b97SToby Isaac if (k <= 0 || k > N) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid form degree"); 578fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k, &Nk);CHKERRQ(ierr); 579fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k-1, &Nkm);CHKERRQ(ierr); 5801a989b97SToby Isaac if (N <= 3) { 5811a989b97SToby Isaac if (k == 1) { 5821a989b97SToby Isaac PetscReal sum = 0.; 5831a989b97SToby Isaac 5841a989b97SToby Isaac for (i = 0; i < N; i++) { 5851a989b97SToby Isaac sum += w[i] * v[i]; 5861a989b97SToby Isaac } 5871a989b97SToby Isaac wIntv[0] = sum; 5881a989b97SToby Isaac } else if (k == N) { 5891a989b97SToby Isaac PetscReal mult[3] = {1., -1., 1.}; 5901a989b97SToby Isaac 5911a989b97SToby Isaac for (i = 0; i < N; i++) { 5921a989b97SToby Isaac wIntv[N - 1 - i] = w[0] * v[i] * mult[i]; 5931a989b97SToby Isaac } 5941a989b97SToby Isaac } else { 5951a989b97SToby Isaac wIntv[0] = - w[0]*v[1] - w[1]*v[2]; 5961a989b97SToby Isaac wIntv[1] = w[0]*v[0] - w[2]*v[2]; 5971a989b97SToby Isaac wIntv[2] = w[1]*v[0] + w[2]*v[1]; 5981a989b97SToby Isaac } 5991a989b97SToby Isaac } else { 6001a989b97SToby Isaac PetscInt *subset, *work; 6011a989b97SToby Isaac 6021a989b97SToby Isaac ierr = PetscMalloc2(k, &subset, k, &work);CHKERRQ(ierr); 6031a989b97SToby Isaac for (i = 0; i < Nkm; i++) wIntv[i] = 0.; 6041a989b97SToby Isaac for (i = 0; i < Nk; i++) { 6051a989b97SToby Isaac PetscInt j, l, m; 6061a989b97SToby Isaac 6071a989b97SToby Isaac ierr = PetscDTEnumSubset(N, k, i, subset);CHKERRQ(ierr); 6081a989b97SToby Isaac for (j = 0; j < k; j++) { 6091a989b97SToby Isaac PetscInt idx; 61028222859SToby Isaac PetscBool flip = (PetscBool) (j & 1); 6111a989b97SToby Isaac 6121a989b97SToby Isaac for (l = 0, m = 0; l < k; l++) { 6131a989b97SToby Isaac if (l != j) work[m++] = subset[l]; 6141a989b97SToby Isaac } 6151a989b97SToby Isaac ierr = PetscDTSubsetIndex(N, k - 1, work, &idx);CHKERRQ(ierr); 6161a989b97SToby Isaac wIntv[idx] += flip ? -(w[i] * v[subset[j]]) : (w[i] * v[subset[j]]); 6171a989b97SToby Isaac } 6181a989b97SToby Isaac } 6191a989b97SToby Isaac ierr = PetscFree2(subset, work);CHKERRQ(ierr); 6201a989b97SToby Isaac } 6211a989b97SToby Isaac PetscFunctionReturn(0); 6221a989b97SToby Isaac } 6231a989b97SToby Isaac 624fad4db65SToby Isaac /*@ 62528222859SToby Isaac PetscDTAltVInteriorMatrix - Compute the matrix of the linear transformation induced on a k-form by the interior product with a vector 626fad4db65SToby Isaac 627fad4db65SToby Isaac Input Arguments: 62828222859SToby Isaac + N - the dimension of the vector space, N >= 0 62928222859SToby Isaac . k - the degree k of the k-forms on which intvMat acts, 0 <= k <= N 63028222859SToby Isaac - v - an N dimensional vector 631fad4db65SToby Isaac 632fad4db65SToby Isaac Output Arguments: 633fad4db65SToby Isaac . intvMat - an [(N choose (k-1)) x (N choose k)] matrix, row-major: (intvMat) * w = (w int v) 634fad4db65SToby Isaac 635fad4db65SToby Isaac Level: intermediate 636fad4db65SToby Isaac 637*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVInterior(), PetscDTAltVInteriorPattern(), PetscDTAltVPullback(), PetscDTAltVPullbackMatrix() 638fad4db65SToby Isaac @*/ 6391a989b97SToby Isaac PetscErrorCode PetscDTAltVInteriorMatrix(PetscInt N, PetscInt k, const PetscReal *v, PetscReal *intvMat) 6401a989b97SToby Isaac { 6411a989b97SToby Isaac PetscInt i, Nk, Nkm; 6421a989b97SToby Isaac PetscErrorCode ierr; 6431a989b97SToby Isaac 6441a989b97SToby Isaac PetscFunctionBegin; 6451a989b97SToby Isaac if (k <= 0 || k > N) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid form degree"); 646fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k, &Nk);CHKERRQ(ierr); 647fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k-1, &Nkm);CHKERRQ(ierr); 6481a989b97SToby Isaac if (N <= 3) { 6491a989b97SToby Isaac if (k == 1) { 6501a989b97SToby Isaac for (i = 0; i < N; i++) intvMat[i] = v[i]; 6511a989b97SToby Isaac } else if (k == N) { 6521a989b97SToby Isaac PetscReal mult[3] = {1., -1., 1.}; 6531a989b97SToby Isaac 6541a989b97SToby Isaac for (i = 0; i < N; i++) intvMat[N - 1 - i] = v[i] * mult[i]; 6551a989b97SToby Isaac } else { 6561a989b97SToby Isaac intvMat[0] = -v[1]; intvMat[1] = -v[2]; intvMat[2] = 0.; 6571a989b97SToby Isaac intvMat[3] = v[0]; intvMat[4] = 0.; intvMat[5] = -v[2]; 6581a989b97SToby Isaac intvMat[6] = 0.; intvMat[7] = v[0]; intvMat[8] = v[1]; 6591a989b97SToby Isaac } 6601a989b97SToby Isaac } else { 6611a989b97SToby Isaac PetscInt *subset, *work; 6621a989b97SToby Isaac 6631a989b97SToby Isaac ierr = PetscMalloc2(k, &subset, k, &work);CHKERRQ(ierr); 6641a989b97SToby Isaac for (i = 0; i < Nk * Nkm; i++) intvMat[i] = 0.; 6651a989b97SToby Isaac for (i = 0; i < Nk; i++) { 6661a989b97SToby Isaac PetscInt j, l, m; 6671a989b97SToby Isaac 6681a989b97SToby Isaac ierr = PetscDTEnumSubset(N, k, i, subset);CHKERRQ(ierr); 6691a989b97SToby Isaac for (j = 0; j < k; j++) { 6701a989b97SToby Isaac PetscInt idx; 67128222859SToby Isaac PetscBool flip = (PetscBool) (j & 1); 6721a989b97SToby Isaac 6731a989b97SToby Isaac for (l = 0, m = 0; l < k; l++) { 6741a989b97SToby Isaac if (l != j) work[m++] = subset[l]; 6751a989b97SToby Isaac } 6761a989b97SToby Isaac ierr = PetscDTSubsetIndex(N, k - 1, work, &idx);CHKERRQ(ierr); 6771a989b97SToby Isaac intvMat[idx * Nk + i] += flip ? -v[subset[j]] : v[subset[j]]; 6781a989b97SToby Isaac } 6791a989b97SToby Isaac } 6801a989b97SToby Isaac ierr = PetscFree2(subset, work);CHKERRQ(ierr); 6811a989b97SToby Isaac } 6821a989b97SToby Isaac PetscFunctionReturn(0); 6831a989b97SToby Isaac } 6841a989b97SToby Isaac 685fad4db65SToby Isaac /*@ 686fad4db65SToby Isaac PetscDTAltVInteriorPattern - compute the sparsity and sign pattern of the interior product matrix computed in PetscDTAltVInteriorMatrix() 687fad4db65SToby Isaac 688fad4db65SToby Isaac Input Arguments: 68928222859SToby Isaac + N - the dimension of the vector space, N >= 0 69028222859SToby Isaac - k - the degree of the k-forms on which intvMat from PetscDTAltVInteriorMatrix() acts, 0 <= k <= N. 691fad4db65SToby Isaac 692fad4db65SToby Isaac Output Arguments: 69328222859SToby Isaac . indices - The interior product matrix intvMat has size [(N choose (k-1)) x (N choose k)] and has (N choose k) * k 69428222859SToby Isaac non-zeros. indices[i][0] and indices[i][1] are the row and column of a non-zero, and its value is equal to the vector 69528222859SToby Isaac coordinate v[j] if indices[i][2] = j, or -v[j] if indices[i][2] = -(j+1) 696fad4db65SToby Isaac 697fad4db65SToby Isaac Level: intermediate 698fad4db65SToby Isaac 69928222859SToby Isaac Note: this function is useful when the interior product needs to be computed at multiple locations, as when computing the Koszul differential 700fad4db65SToby Isaac 701*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVInterior(), PetscDTAltVInteriorMatrix(), PetscDTAltVPullback(), PetscDTAltVPullbackMatrix() 702fad4db65SToby Isaac @*/ 703dda711d0SToby Isaac PetscErrorCode PetscDTAltVInteriorPattern(PetscInt N, PetscInt k, PetscInt (*indices)[3]) 704dda711d0SToby Isaac { 705dda711d0SToby Isaac PetscInt i, Nk, Nkm; 706dda711d0SToby Isaac PetscErrorCode ierr; 707dda711d0SToby Isaac 708dda711d0SToby Isaac PetscFunctionBegin; 709dda711d0SToby Isaac if (k <= 0 || k > N) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid form degree"); 710fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k, &Nk);CHKERRQ(ierr); 711fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k-1, &Nkm);CHKERRQ(ierr); 712dda711d0SToby Isaac if (N <= 3) { 713dda711d0SToby Isaac if (k == 1) { 714dda711d0SToby Isaac for (i = 0; i < N; i++) { 715dda711d0SToby Isaac indices[i][0] = 0; 716dda711d0SToby Isaac indices[i][1] = i; 717dda711d0SToby Isaac indices[i][2] = i; 718dda711d0SToby Isaac } 719dda711d0SToby Isaac } else if (k == N) { 720dda711d0SToby Isaac PetscInt val[3] = {0, -2, 2}; 721dda711d0SToby Isaac 722dda711d0SToby Isaac for (i = 0; i < N; i++) { 723dda711d0SToby Isaac indices[i][0] = N - 1 - i; 724dda711d0SToby Isaac indices[i][1] = 0; 725dda711d0SToby Isaac indices[i][2] = val[i]; 726dda711d0SToby Isaac } 727dda711d0SToby Isaac } else { 728dda711d0SToby Isaac indices[0][0] = 0; indices[0][1] = 0; indices[0][2] = -(1 + 1); 729dda711d0SToby Isaac indices[1][0] = 0; indices[1][1] = 1; indices[1][2] = -(2 + 1); 730dda711d0SToby Isaac indices[2][0] = 1; indices[2][1] = 0; indices[2][2] = 0; 731dda711d0SToby Isaac indices[3][0] = 1; indices[3][1] = 2; indices[3][2] = -(2 + 1); 732dda711d0SToby Isaac indices[4][0] = 2; indices[4][1] = 1; indices[4][2] = 0; 733dda711d0SToby Isaac indices[5][0] = 2; indices[5][1] = 2; indices[5][2] = 1; 734dda711d0SToby Isaac } 735dda711d0SToby Isaac } else { 736dda711d0SToby Isaac PetscInt *subset, *work; 737dda711d0SToby Isaac 738dda711d0SToby Isaac ierr = PetscMalloc2(k, &subset, k, &work);CHKERRQ(ierr); 739dda711d0SToby Isaac for (i = 0; i < Nk; i++) { 740dda711d0SToby Isaac PetscInt j, l, m; 741dda711d0SToby Isaac 742dda711d0SToby Isaac ierr = PetscDTEnumSubset(N, k, i, subset);CHKERRQ(ierr); 743dda711d0SToby Isaac for (j = 0; j < k; j++) { 744dda711d0SToby Isaac PetscInt idx; 74528222859SToby Isaac PetscBool flip = (PetscBool) (j & 1); 746dda711d0SToby Isaac 747dda711d0SToby Isaac for (l = 0, m = 0; l < k; l++) { 748dda711d0SToby Isaac if (l != j) work[m++] = subset[l]; 749dda711d0SToby Isaac } 750dda711d0SToby Isaac ierr = PetscDTSubsetIndex(N, k - 1, work, &idx);CHKERRQ(ierr); 751dda711d0SToby Isaac indices[i * k + j][0] = idx; 752dda711d0SToby Isaac indices[i * k + j][1] = i; 753dda711d0SToby Isaac indices[i * k + j][2] = flip ? -(subset[j] + 1) : subset[j]; 754dda711d0SToby Isaac } 755dda711d0SToby Isaac } 756dda711d0SToby Isaac ierr = PetscFree2(subset, work);CHKERRQ(ierr); 757dda711d0SToby Isaac } 758dda711d0SToby Isaac PetscFunctionReturn(0); 759dda711d0SToby Isaac } 760dda711d0SToby Isaac 761fad4db65SToby Isaac /*@ 76228222859SToby Isaac PetscDTAltVStar - Apply a power of the Hodge star operator, which maps k-forms to (N-k) forms, to a k-form 763fad4db65SToby Isaac 764fad4db65SToby Isaac Input Arguments: 76528222859SToby Isaac + N - the dimension of the vector space, N >= 0 76628222859SToby Isaac . k - the degree k of the k-form w, 0 <= k <= N 76728222859SToby Isaac . pow - the number of times to apply the Hodge star operator: pow < 0 indicates that the inverse of the Hodge star operator should be applied |pow| times. 76828222859SToby Isaac - w - a k-form, size [N choose k] 769fad4db65SToby Isaac 770fad4db65SToby Isaac Output Arguments: 77128222859SToby Isaac . starw = (star)^pow w. Each degree of freedom of a k-form is associated with a subset S of k coordinates of the N dimensional vector space: the Hodge start operator (star) maps that degree of freedom to the degree of freedom associated with S', the complement of S, with a sign change if the permutation of coordinates {S[0], ... S[k-1], S'[0], ... S'[N-k- 1]} is an odd permutation. This implies (star)^2 w = (-1)^{k(N-k)} w, and (star)^4 w = w. 772fad4db65SToby Isaac 773fad4db65SToby Isaac Level: intermediate 774fad4db65SToby Isaac 775*29a920c6SToby Isaac .seealso: PetscDTAltV, PetscDTAltVPullback(), PetscDTAltVPullbackMatrix() 776fad4db65SToby Isaac @*/ 7771a989b97SToby Isaac PetscErrorCode PetscDTAltVStar(PetscInt N, PetscInt k, PetscInt pow, const PetscReal *w, PetscReal *starw) 7781a989b97SToby Isaac { 7791a989b97SToby Isaac PetscInt Nk, i; 7801a989b97SToby Isaac PetscErrorCode ierr; 7811a989b97SToby Isaac 7821a989b97SToby Isaac PetscFunctionBegin; 7831a989b97SToby Isaac if (k < 0 || k > N) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid form degree"); 784fad4db65SToby Isaac ierr = PetscDTBinomialInt(N, k, &Nk);CHKERRQ(ierr); 7851a989b97SToby Isaac pow = pow % 4; 7861a989b97SToby Isaac pow = (pow + 4) % 4; /* make non-negative */ 7871a989b97SToby Isaac /* pow is now 0, 1, 2, 3 */ 7881a989b97SToby Isaac if (N <= 3) { 7891a989b97SToby Isaac if (pow & 1) { 7901a989b97SToby Isaac PetscReal mult[3] = {1., -1., 1.}; 7911a989b97SToby Isaac 7921a989b97SToby Isaac for (i = 0; i < Nk; i++) starw[Nk - 1 - i] = w[i] * mult[i]; 7931a989b97SToby Isaac } else { 7941a989b97SToby Isaac for (i = 0; i < Nk; i++) starw[i] = w[i]; 7951a989b97SToby Isaac } 7961a989b97SToby Isaac if (pow > 1 && ((k * (N - k)) & 1)) { 7971a989b97SToby Isaac for (i = 0; i < Nk; i++) starw[i] = -starw[i]; 7981a989b97SToby Isaac } 7991a989b97SToby Isaac } else { 8001a989b97SToby Isaac PetscInt *subset; 8011a989b97SToby Isaac 8021a989b97SToby Isaac ierr = PetscMalloc1(N, &subset);CHKERRQ(ierr); 8031a989b97SToby Isaac if (pow % 2) { 8041a989b97SToby Isaac PetscInt l = (pow == 1) ? k : N - k; 8051a989b97SToby Isaac for (i = 0; i < Nk; i++) { 8061a989b97SToby Isaac PetscBool sOdd; 8071a989b97SToby Isaac PetscInt j, idx; 8081a989b97SToby Isaac 8091a989b97SToby Isaac ierr = PetscDTEnumSplit(N, l, i, subset, &sOdd);CHKERRQ(ierr); 8101a989b97SToby Isaac ierr = PetscDTSubsetIndex(N, l, subset, &idx);CHKERRQ(ierr); 8111a989b97SToby Isaac ierr = PetscDTSubsetIndex(N, N-l, &subset[l], &j);CHKERRQ(ierr); 8121a989b97SToby Isaac starw[j] = sOdd ? -w[idx] : w[idx]; 8131a989b97SToby Isaac } 8141a989b97SToby Isaac } else { 8151a989b97SToby Isaac for (i = 0; i < Nk; i++) starw[i] = w[i]; 8161a989b97SToby Isaac } 8171a989b97SToby Isaac /* star^2 = -1^(k * (N - k)) */ 8181a989b97SToby Isaac if (pow > 1 && (k * (N - k)) % 2) { 8191a989b97SToby Isaac for (i = 0; i < Nk; i++) starw[i] = -starw[i]; 8201a989b97SToby Isaac } 8211a989b97SToby Isaac ierr = PetscFree(subset);CHKERRQ(ierr); 8221a989b97SToby Isaac } 8231a989b97SToby Isaac PetscFunctionReturn(0); 8241a989b97SToby Isaac } 825