xref: /petsc/src/dm/dt/interface/dtaltv.c (revision 29a920c6539ef04363564f700a0b63899f84bfea)
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