xref: /petsc/src/dm/dt/tests/ex13.c (revision d8f25ad8743d25410dd8d312c13b124729e61267)
1*d8f25ad8SToby Isaac const char help[] = "Tests PetscDTPTrimmedEvalJet()";
2*d8f25ad8SToby Isaac 
3*d8f25ad8SToby Isaac #include <petscdt.h>
4*d8f25ad8SToby Isaac #include <petscblaslapack.h>
5*d8f25ad8SToby Isaac #include <petscmat.h>
6*d8f25ad8SToby Isaac 
7*d8f25ad8SToby Isaac static PetscErrorCode constructTabulationAndMass(PetscInt dim, PetscInt deg, PetscInt form, PetscInt jetDegree, PetscInt npoints,
8*d8f25ad8SToby Isaac                                                  const PetscReal *points, const PetscReal *weights,
9*d8f25ad8SToby Isaac                                                  PetscInt *_Nb, PetscInt *_Nf, PetscInt *_Nk,
10*d8f25ad8SToby Isaac                                                  PetscReal **B, PetscScalar **M)
11*d8f25ad8SToby Isaac {
12*d8f25ad8SToby Isaac   PetscInt       Nf; // Number of form components
13*d8f25ad8SToby Isaac   PetscInt       Nbpt; // number of trimmed polynomials
14*d8f25ad8SToby Isaac   PetscInt       Nk; // jet size
15*d8f25ad8SToby Isaac   PetscReal     *p_trimmed;
16*d8f25ad8SToby Isaac   PetscErrorCode ierr;
17*d8f25ad8SToby Isaac 
18*d8f25ad8SToby Isaac   PetscFunctionBegin;
19*d8f25ad8SToby Isaac   ierr = PetscDTBinomialInt(dim, PetscAbsInt(form), &Nf);CHKERRQ(ierr);
20*d8f25ad8SToby Isaac   ierr = PetscDTPTrimmedSize(dim, deg, form, &Nbpt);CHKERRQ(ierr);
21*d8f25ad8SToby Isaac   ierr = PetscDTBinomialInt(dim + jetDegree, dim, &Nk);CHKERRQ(ierr);
22*d8f25ad8SToby Isaac   ierr = PetscMalloc1(Nbpt * Nf * Nk * npoints, &p_trimmed);CHKERRQ(ierr);
23*d8f25ad8SToby Isaac   ierr = PetscDTPTrimmedEvalJet(dim, npoints, points, deg, form, jetDegree, p_trimmed);CHKERRQ(ierr);
24*d8f25ad8SToby Isaac 
25*d8f25ad8SToby Isaac   // compute the direct mass matrix
26*d8f25ad8SToby Isaac   PetscScalar *M_trimmed;
27*d8f25ad8SToby Isaac   ierr = PetscCalloc1(Nbpt * Nbpt, &M_trimmed);CHKERRQ(ierr);
28*d8f25ad8SToby Isaac   for (PetscInt i = 0; i < Nbpt; i++) {
29*d8f25ad8SToby Isaac     for (PetscInt j = 0; j < Nbpt; j++) {
30*d8f25ad8SToby Isaac       PetscReal v = 0.;
31*d8f25ad8SToby Isaac 
32*d8f25ad8SToby Isaac       for (PetscInt f = 0; f < Nf; f++) {
33*d8f25ad8SToby Isaac         const PetscReal *p_i = &p_trimmed[(i * Nf + f) * Nk * npoints];
34*d8f25ad8SToby Isaac         const PetscReal *p_j = &p_trimmed[(j * Nf + f) * Nk * npoints];
35*d8f25ad8SToby Isaac 
36*d8f25ad8SToby Isaac         for (PetscInt pt = 0; pt < npoints; pt++) {
37*d8f25ad8SToby Isaac           v += p_i[pt] * p_j[pt] * weights[pt];
38*d8f25ad8SToby Isaac         }
39*d8f25ad8SToby Isaac       }
40*d8f25ad8SToby Isaac       M_trimmed[i * Nbpt + j] += v;
41*d8f25ad8SToby Isaac     }
42*d8f25ad8SToby Isaac   }
43*d8f25ad8SToby Isaac   *_Nb = Nbpt;
44*d8f25ad8SToby Isaac   *_Nf = Nf;
45*d8f25ad8SToby Isaac   *_Nk = Nk;
46*d8f25ad8SToby Isaac   *B = p_trimmed;
47*d8f25ad8SToby Isaac   *M = M_trimmed;
48*d8f25ad8SToby Isaac   PetscFunctionReturn(0);
49*d8f25ad8SToby Isaac }
50*d8f25ad8SToby Isaac 
51*d8f25ad8SToby Isaac static PetscErrorCode test(PetscInt dim, PetscInt deg, PetscInt form, PetscInt jetDegree, PetscBool cond)
52*d8f25ad8SToby Isaac {
53*d8f25ad8SToby Isaac   PetscQuadrature  q;
54*d8f25ad8SToby Isaac   PetscInt         npoints;
55*d8f25ad8SToby Isaac   const PetscReal *points;
56*d8f25ad8SToby Isaac   const PetscReal *weights;
57*d8f25ad8SToby Isaac   PetscInt         Nf; // Number of form components
58*d8f25ad8SToby Isaac   PetscInt         Nk; // jet size
59*d8f25ad8SToby Isaac   PetscInt         Nbpt; // number of trimmed polynomials
60*d8f25ad8SToby Isaac   PetscReal       *p_trimmed;
61*d8f25ad8SToby Isaac   PetscScalar     *M_trimmed;
62*d8f25ad8SToby Isaac   PetscReal       *p_scalar;
63*d8f25ad8SToby Isaac   PetscInt         Nbp; // number of scalar polynomials
64*d8f25ad8SToby Isaac   PetscScalar     *Mcopy;
65*d8f25ad8SToby Isaac   PetscScalar     *M_moments;
66*d8f25ad8SToby Isaac   PetscReal        frob_err = 0.;
67*d8f25ad8SToby Isaac   Mat              mat_trimmed;
68*d8f25ad8SToby Isaac   Mat              mat_moments_T;
69*d8f25ad8SToby Isaac   Mat              AinvB;
70*d8f25ad8SToby Isaac   PetscInt         Nbm1;
71*d8f25ad8SToby Isaac   Mat              Mm1;
72*d8f25ad8SToby Isaac   PetscReal       *p_trimmed_copy;
73*d8f25ad8SToby Isaac   PetscReal       *M_moment_real;
74*d8f25ad8SToby Isaac   PetscErrorCode   ierr;
75*d8f25ad8SToby Isaac 
76*d8f25ad8SToby Isaac   PetscFunctionBegin;
77*d8f25ad8SToby Isaac   // Construct an appropriate quadrature
78*d8f25ad8SToby Isaac   ierr = PetscDTStroudConicalQuadrature(dim, 1, deg + 2, -1., 1., &q);CHKERRQ(ierr);
79*d8f25ad8SToby Isaac   ierr = PetscQuadratureGetData(q, NULL, NULL, &npoints, &points, &weights);CHKERRQ(ierr);
80*d8f25ad8SToby Isaac 
81*d8f25ad8SToby Isaac   ierr = constructTabulationAndMass(dim, deg, form, jetDegree, npoints, points, weights, &Nbpt, &Nf, &Nk, &p_trimmed, &M_trimmed);CHKERRQ(ierr);
82*d8f25ad8SToby Isaac 
83*d8f25ad8SToby Isaac   ierr = PetscDTBinomialInt(dim + deg, dim, &Nbp);CHKERRQ(ierr);
84*d8f25ad8SToby Isaac   ierr = PetscMalloc1(Nbp * Nk * npoints, &p_scalar);CHKERRQ(ierr);
85*d8f25ad8SToby Isaac   ierr = PetscDTPKDEvalJet(dim, npoints, points, deg, jetDegree, p_scalar);CHKERRQ(ierr);
86*d8f25ad8SToby Isaac 
87*d8f25ad8SToby Isaac   ierr = PetscMalloc1(Nbpt * Nbpt, &Mcopy);CHKERRQ(ierr);
88*d8f25ad8SToby Isaac   // Print the condition numbers (useful for testing out different bases internally in PetscDTPTrimmedEvalJet())
89*d8f25ad8SToby Isaac #if !defined(PETSC_USE_COMPLEX)
90*d8f25ad8SToby Isaac   if (cond) {
91*d8f25ad8SToby Isaac     PetscReal *S;
92*d8f25ad8SToby Isaac     PetscScalar *work;
93*d8f25ad8SToby Isaac     PetscBLASInt n = Nbpt;
94*d8f25ad8SToby Isaac     PetscBLASInt lwork = 5 * Nbpt;
95*d8f25ad8SToby Isaac     PetscBLASInt lierr;
96*d8f25ad8SToby Isaac 
97*d8f25ad8SToby Isaac     ierr = PetscMalloc1(Nbpt, &S);CHKERRQ(ierr);
98*d8f25ad8SToby Isaac     ierr = PetscMalloc1(5*Nbpt, &work);CHKERRQ(ierr);
99*d8f25ad8SToby Isaac     ierr = PetscArraycpy(Mcopy, M_trimmed, Nbpt * Nbpt);CHKERRQ(ierr);
100*d8f25ad8SToby Isaac 
101*d8f25ad8SToby Isaac     PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&n,&n,Mcopy,&n,S,NULL,&n,NULL,&n,work,&lwork,&lierr));
102*d8f25ad8SToby Isaac     PetscReal cond = S[0] / S[Nbpt - 1];
103*d8f25ad8SToby Isaac     ierr = PetscPrintf(PETSC_COMM_WORLD, "dimension %D, degree %D, form %D: condition number %g\n", dim, deg, form, (double) cond);
104*d8f25ad8SToby Isaac     ierr = PetscFree(work);CHKERRQ(ierr);
105*d8f25ad8SToby Isaac     ierr = PetscFree(S);CHKERRQ(ierr);
106*d8f25ad8SToby Isaac   }
107*d8f25ad8SToby Isaac #endif
108*d8f25ad8SToby Isaac 
109*d8f25ad8SToby Isaac   // compute the moments with the orthonormal polynomials
110*d8f25ad8SToby Isaac   ierr = PetscCalloc1(Nbpt * Nbp * Nf, &M_moments);CHKERRQ(ierr);
111*d8f25ad8SToby Isaac   for (PetscInt i = 0; i < Nbp; i++) {
112*d8f25ad8SToby Isaac     for (PetscInt j = 0; j < Nbpt; j++) {
113*d8f25ad8SToby Isaac       for (PetscInt f = 0; f < Nf; f++) {
114*d8f25ad8SToby Isaac         PetscReal        v = 0.;
115*d8f25ad8SToby Isaac         const PetscReal *p_i = &p_scalar[i * Nk * npoints];
116*d8f25ad8SToby Isaac         const PetscReal *p_j = &p_trimmed[(j * Nf + f) * Nk * npoints];
117*d8f25ad8SToby Isaac 
118*d8f25ad8SToby Isaac         for (PetscInt pt = 0; pt < npoints; pt++) {
119*d8f25ad8SToby Isaac           v += p_i[pt] * p_j[pt] * weights[pt];
120*d8f25ad8SToby Isaac         }
121*d8f25ad8SToby Isaac         M_moments[(i * Nf + f) * Nbpt + j] += v;
122*d8f25ad8SToby Isaac       }
123*d8f25ad8SToby Isaac     }
124*d8f25ad8SToby Isaac   }
125*d8f25ad8SToby Isaac 
126*d8f25ad8SToby Isaac   // subtract M_moments^T * M_moments from M_trimmed: because the trimmed polynomials should be contained in
127*d8f25ad8SToby Isaac   // the full polynomials, the result should be zero
128*d8f25ad8SToby Isaac   ierr = PetscArraycpy(Mcopy, M_trimmed, Nbpt * Nbpt);CHKERRQ(ierr);
129*d8f25ad8SToby Isaac   {
130*d8f25ad8SToby Isaac     PetscBLASInt m = Nbpt;
131*d8f25ad8SToby Isaac     PetscBLASInt n = Nbpt;
132*d8f25ad8SToby Isaac     PetscBLASInt k = Nbp * Nf;
133*d8f25ad8SToby Isaac     PetscScalar mone = -1.;
134*d8f25ad8SToby Isaac     PetscScalar one = 1.;
135*d8f25ad8SToby Isaac 
136*d8f25ad8SToby Isaac     PetscStackCallBLAS("BLASgemm",BLASgemm_("N","T",&m,&n,&k,&mone,M_moments,&m,M_moments,&m,&one,Mcopy,&m));
137*d8f25ad8SToby Isaac   }
138*d8f25ad8SToby Isaac 
139*d8f25ad8SToby Isaac   frob_err = 0.;
140*d8f25ad8SToby Isaac   for (PetscInt i = 0; i < Nbpt * Nbpt; i++) frob_err += PetscRealPart(Mcopy[i]) * PetscRealPart(Mcopy[i]);
141*d8f25ad8SToby Isaac   frob_err = PetscSqrtReal(frob_err);
142*d8f25ad8SToby Isaac 
143*d8f25ad8SToby Isaac   if (frob_err > PETSC_SMALL) {
144*d8f25ad8SToby Isaac     SETERRQ4(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "dimension %D, degree %D, form %D: trimmed projection error %g\n", dim, deg, form, (double) frob_err);
145*d8f25ad8SToby Isaac   }
146*d8f25ad8SToby Isaac 
147*d8f25ad8SToby Isaac   // P trimmed is also supposed to contain the polynomials of one degree less: construction M_moment[0:sub,:] * M_trimmed^{-1} * M_moments[0:sub,:]^T should be the identity matrix
148*d8f25ad8SToby Isaac   ierr = MatCreateSeqDense(PETSC_COMM_SELF, Nbpt, Nbpt, M_trimmed, &mat_trimmed);CHKERRQ(ierr);
149*d8f25ad8SToby Isaac   ierr = PetscDTBinomialInt(dim + deg - 1, dim, &Nbm1);CHKERRQ(ierr);
150*d8f25ad8SToby Isaac   ierr = MatCreateSeqDense(PETSC_COMM_SELF, Nbpt, Nbm1 * Nf, M_moments, &mat_moments_T);CHKERRQ(ierr);
151*d8f25ad8SToby Isaac   ierr = MatDuplicate(mat_moments_T, MAT_DO_NOT_COPY_VALUES, &AinvB);CHKERRQ(ierr);
152*d8f25ad8SToby Isaac   ierr = MatLUFactor(mat_trimmed, NULL, NULL, NULL);CHKERRQ(ierr);
153*d8f25ad8SToby Isaac   ierr = MatMatSolve(mat_trimmed, mat_moments_T, AinvB);CHKERRQ(ierr);
154*d8f25ad8SToby Isaac   ierr = MatTransposeMatMult(mat_moments_T, AinvB, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &Mm1);CHKERRQ(ierr);
155*d8f25ad8SToby Isaac   ierr = MatShift(Mm1, -1.);CHKERRQ(ierr);
156*d8f25ad8SToby Isaac   ierr = MatNorm(Mm1, NORM_FROBENIUS, &frob_err);CHKERRQ(ierr);
157*d8f25ad8SToby Isaac   if (frob_err > PETSC_SMALL) {
158*d8f25ad8SToby Isaac     SETERRQ4(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "dimension %D, degree %D, form %D: trimmed reverse projection error %g\n", dim, deg, form, (double) frob_err);
159*d8f25ad8SToby Isaac   }
160*d8f25ad8SToby Isaac   ierr = MatDestroy(&Mm1);CHKERRQ(ierr);
161*d8f25ad8SToby Isaac   ierr = MatDestroy(&AinvB);CHKERRQ(ierr);
162*d8f25ad8SToby Isaac   ierr = MatDestroy(&mat_moments_T);CHKERRQ(ierr);
163*d8f25ad8SToby Isaac 
164*d8f25ad8SToby Isaac   // The Koszul differential applied to P trimmed (Lambda k+1) should be contained in P trimmed (Lambda k)
165*d8f25ad8SToby Isaac   if (PetscAbsInt(form) < dim) {
166*d8f25ad8SToby Isaac     PetscInt     Nf1, Nbpt1, Nk1;
167*d8f25ad8SToby Isaac     PetscReal   *p_trimmed1;
168*d8f25ad8SToby Isaac     PetscScalar *M_trimmed1;
169*d8f25ad8SToby Isaac     PetscInt   (*pattern)[3];
170*d8f25ad8SToby Isaac     PetscReal   *p_koszul;
171*d8f25ad8SToby Isaac     PetscScalar *M_koszul;
172*d8f25ad8SToby Isaac     PetscScalar *M_k_moment;
173*d8f25ad8SToby Isaac     Mat          mat_koszul;
174*d8f25ad8SToby Isaac     Mat          mat_k_moment_T;
175*d8f25ad8SToby Isaac     Mat          AinvB;
176*d8f25ad8SToby Isaac     Mat          prod;
177*d8f25ad8SToby Isaac 
178*d8f25ad8SToby Isaac     ierr = constructTabulationAndMass(dim, deg, form < 0 ? form - 1 : form + 1, 0, npoints, points, weights, &Nbpt1, &Nf1, &Nk1,
179*d8f25ad8SToby Isaac                                       &p_trimmed1, &M_trimmed1);CHKERRQ(ierr);
180*d8f25ad8SToby Isaac 
181*d8f25ad8SToby Isaac     ierr = PetscMalloc1(Nf1 * (PetscAbsInt(form) + 1), &pattern);CHKERRQ(ierr);
182*d8f25ad8SToby Isaac     ierr = PetscDTAltVInteriorPattern(dim, PetscAbsInt(form) + 1, pattern);CHKERRQ(ierr);
183*d8f25ad8SToby Isaac 
184*d8f25ad8SToby Isaac     // apply the Koszul operator
185*d8f25ad8SToby Isaac     ierr = PetscCalloc1(Nbpt1 * Nf * npoints, &p_koszul);CHKERRQ(ierr);
186*d8f25ad8SToby Isaac     for (PetscInt b = 0; b < Nbpt1; b++) {
187*d8f25ad8SToby Isaac       for (PetscInt a = 0; a < Nf1 * (PetscAbsInt(form) + 1); a++) {
188*d8f25ad8SToby Isaac         PetscInt         i,j,k;
189*d8f25ad8SToby Isaac         PetscReal        sign;
190*d8f25ad8SToby Isaac         PetscReal       *p_i;
191*d8f25ad8SToby Isaac         const PetscReal *p_j;
192*d8f25ad8SToby Isaac 
193*d8f25ad8SToby Isaac         i = pattern[a][0];
194*d8f25ad8SToby Isaac         if (form < 0) {
195*d8f25ad8SToby Isaac           i = Nf-1-i;
196*d8f25ad8SToby Isaac         }
197*d8f25ad8SToby Isaac         j = pattern[a][1];
198*d8f25ad8SToby Isaac         if (form < 0) {
199*d8f25ad8SToby Isaac           j = Nf1-1-j;
200*d8f25ad8SToby Isaac         }
201*d8f25ad8SToby Isaac         k = pattern[a][2] < 0 ? -(pattern[a][2] + 1) : pattern[a][2];
202*d8f25ad8SToby Isaac         sign = pattern[a][2] < 0 ? -1 : 1;
203*d8f25ad8SToby Isaac         if (form < 0 && (i & 1) ^ (j & 1)) {
204*d8f25ad8SToby Isaac           sign = -sign;
205*d8f25ad8SToby Isaac         }
206*d8f25ad8SToby Isaac 
207*d8f25ad8SToby Isaac         p_i = &p_koszul[(b * Nf + i) * npoints];
208*d8f25ad8SToby Isaac         p_j = &p_trimmed1[(b * Nf1 + j) * npoints];
209*d8f25ad8SToby Isaac         for (PetscInt pt = 0; pt < npoints; pt++) {
210*d8f25ad8SToby Isaac           p_i[pt] += p_j[pt] * points[pt * dim + k] * sign;
211*d8f25ad8SToby Isaac         }
212*d8f25ad8SToby Isaac       }
213*d8f25ad8SToby Isaac     }
214*d8f25ad8SToby Isaac 
215*d8f25ad8SToby Isaac     // mass matrix of the result
216*d8f25ad8SToby Isaac     ierr = PetscMalloc1(Nbpt1 * Nbpt1, &M_koszul);CHKERRQ(ierr);
217*d8f25ad8SToby Isaac     for (PetscInt i = 0; i < Nbpt1; i++) {
218*d8f25ad8SToby Isaac       for (PetscInt j = 0; j < Nbpt1; j++) {
219*d8f25ad8SToby Isaac         PetscReal val = 0.;
220*d8f25ad8SToby Isaac 
221*d8f25ad8SToby Isaac         for (PetscInt v = 0; v < Nf; v++) {
222*d8f25ad8SToby Isaac           const PetscReal *p_i = &p_koszul[(i * Nf + v) * npoints];
223*d8f25ad8SToby Isaac           const PetscReal *p_j = &p_koszul[(j * Nf + v) * npoints];
224*d8f25ad8SToby Isaac 
225*d8f25ad8SToby Isaac           for (PetscInt pt = 0; pt < npoints; pt++) {
226*d8f25ad8SToby Isaac             val += p_i[pt] * p_j[pt] * weights[pt];
227*d8f25ad8SToby Isaac           }
228*d8f25ad8SToby Isaac         }
229*d8f25ad8SToby Isaac         M_koszul[i * Nbpt1 + j] = val;
230*d8f25ad8SToby Isaac       }
231*d8f25ad8SToby Isaac     }
232*d8f25ad8SToby Isaac 
233*d8f25ad8SToby Isaac     // moment matrix between the result and P trimmed
234*d8f25ad8SToby Isaac     ierr = PetscMalloc1(Nbpt * Nbpt1, &M_k_moment);CHKERRQ(ierr);
235*d8f25ad8SToby Isaac     for (PetscInt i = 0; i < Nbpt1; i++) {
236*d8f25ad8SToby Isaac       for (PetscInt j = 0; j < Nbpt; j++) {
237*d8f25ad8SToby Isaac         PetscReal val = 0.;
238*d8f25ad8SToby Isaac 
239*d8f25ad8SToby Isaac         for (PetscInt v = 0; v < Nf; v++) {
240*d8f25ad8SToby Isaac           const PetscReal *p_i = &p_koszul[(i * Nf + v) * npoints];
241*d8f25ad8SToby Isaac           const PetscReal *p_j = &p_trimmed[(j * Nf + v) * Nk * npoints];
242*d8f25ad8SToby Isaac 
243*d8f25ad8SToby Isaac           for (PetscInt pt = 0; pt < npoints; pt++) {
244*d8f25ad8SToby Isaac             val += p_i[pt] * p_j[pt] * weights[pt];
245*d8f25ad8SToby Isaac           }
246*d8f25ad8SToby Isaac         }
247*d8f25ad8SToby Isaac         M_k_moment[i * Nbpt + j] = val;
248*d8f25ad8SToby Isaac       }
249*d8f25ad8SToby Isaac     }
250*d8f25ad8SToby Isaac 
251*d8f25ad8SToby Isaac     // M_k_moment M_trimmed^{-1} M_k_moment^T == M_koszul
252*d8f25ad8SToby Isaac     ierr = MatCreateSeqDense(PETSC_COMM_SELF, Nbpt1, Nbpt1, M_koszul, &mat_koszul);CHKERRQ(ierr);
253*d8f25ad8SToby Isaac     ierr = MatCreateSeqDense(PETSC_COMM_SELF, Nbpt, Nbpt1, M_k_moment, &mat_k_moment_T);CHKERRQ(ierr);
254*d8f25ad8SToby Isaac     ierr = MatDuplicate(mat_k_moment_T, MAT_DO_NOT_COPY_VALUES, &AinvB);CHKERRQ(ierr);
255*d8f25ad8SToby Isaac     ierr = MatMatSolve(mat_trimmed, mat_k_moment_T, AinvB);CHKERRQ(ierr);
256*d8f25ad8SToby Isaac     ierr = MatTransposeMatMult(mat_k_moment_T, AinvB, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &prod);CHKERRQ(ierr);
257*d8f25ad8SToby Isaac     ierr = MatAXPY(prod, -1., mat_koszul, SAME_NONZERO_PATTERN);CHKERRQ(ierr);
258*d8f25ad8SToby Isaac     ierr = MatNorm(prod, NORM_FROBENIUS, &frob_err);CHKERRQ(ierr);
259*d8f25ad8SToby Isaac     if (frob_err > PETSC_SMALL) {
260*d8f25ad8SToby Isaac       SETERRQ5(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "dimension %D, degree %D, forms (%D, %D): koszul projection error %g\n", dim, deg, form, form < 0 ? (form-1):(form+1), (double) frob_err);
261*d8f25ad8SToby Isaac     }
262*d8f25ad8SToby Isaac 
263*d8f25ad8SToby Isaac     ierr = MatDestroy(&prod);CHKERRQ(ierr);
264*d8f25ad8SToby Isaac     ierr = MatDestroy(&AinvB);CHKERRQ(ierr);
265*d8f25ad8SToby Isaac     ierr = MatDestroy(&mat_k_moment_T);CHKERRQ(ierr);
266*d8f25ad8SToby Isaac     ierr = MatDestroy(&mat_koszul);CHKERRQ(ierr);
267*d8f25ad8SToby Isaac     ierr = PetscFree(M_k_moment);CHKERRQ(ierr);
268*d8f25ad8SToby Isaac     ierr = PetscFree(M_koszul);CHKERRQ(ierr);
269*d8f25ad8SToby Isaac     ierr = PetscFree(p_koszul);CHKERRQ(ierr);
270*d8f25ad8SToby Isaac     ierr = PetscFree(pattern);CHKERRQ(ierr);
271*d8f25ad8SToby Isaac     ierr = PetscFree(p_trimmed1);CHKERRQ(ierr);
272*d8f25ad8SToby Isaac     ierr = PetscFree(M_trimmed1);CHKERRQ(ierr);
273*d8f25ad8SToby Isaac   }
274*d8f25ad8SToby Isaac 
275*d8f25ad8SToby Isaac   // M_moments has shape [Nbp][Nf][Nbpt]
276*d8f25ad8SToby Isaac   // p_scalar has shape [Nbp][Nk][npoints]
277*d8f25ad8SToby Isaac   // contracting on [Nbp] should be the same shape as
278*d8f25ad8SToby Isaac   // p_trimmed, which is [Nbpt][Nf][Nk][npoints]
279*d8f25ad8SToby Isaac   ierr = PetscCalloc1(Nbpt * Nf * Nk * npoints, &p_trimmed_copy);CHKERRQ(ierr);
280*d8f25ad8SToby Isaac   ierr = PetscMalloc1(Nbp * Nf * Nbpt, &M_moment_real);CHKERRQ(ierr);
281*d8f25ad8SToby Isaac   for (PetscInt i = 0; i < Nbp * Nf * Nbpt; i++) {
282*d8f25ad8SToby Isaac     M_moment_real[i] = PetscRealPart(M_moments[i]);
283*d8f25ad8SToby Isaac   }
284*d8f25ad8SToby Isaac   for (PetscInt f = 0; f < Nf; f++) {
285*d8f25ad8SToby Isaac     PetscBLASInt m = Nk * npoints;
286*d8f25ad8SToby Isaac     PetscBLASInt n = Nbpt;
287*d8f25ad8SToby Isaac     PetscBLASInt k = Nbp;
288*d8f25ad8SToby Isaac     PetscBLASInt lda = Nk * npoints;
289*d8f25ad8SToby Isaac     PetscBLASInt ldb = Nf * Nbpt;
290*d8f25ad8SToby Isaac     PetscBLASInt ldc = Nf * Nk * npoints;
291*d8f25ad8SToby Isaac     PetscReal    alpha = 1.0;
292*d8f25ad8SToby Isaac     PetscReal    beta = 1.0;
293*d8f25ad8SToby Isaac 
294*d8f25ad8SToby Isaac     PetscStackCallBLAS("BLASREALgemm",BLASREALgemm_("N","T",&m,&n,&k,&alpha,p_scalar,&lda,&M_moment_real[f * Nbpt],&ldb,&beta,&p_trimmed_copy[f * Nk * npoints],&ldc));
295*d8f25ad8SToby Isaac   }
296*d8f25ad8SToby Isaac   frob_err = 0.;
297*d8f25ad8SToby Isaac   for (PetscInt i = 0; i < Nbpt * Nf * Nk * npoints; i++) {
298*d8f25ad8SToby Isaac     frob_err += (p_trimmed_copy[i] - p_trimmed[i]) * (p_trimmed_copy[i] - p_trimmed[i]);
299*d8f25ad8SToby Isaac   }
300*d8f25ad8SToby Isaac   frob_err = PetscSqrtReal(frob_err);
301*d8f25ad8SToby Isaac 
302*d8f25ad8SToby Isaac   if (frob_err > PETSC_SMALL) {
303*d8f25ad8SToby Isaac     SETERRQ4(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "dimension %D, degree %D, form %D: jet error %g\n", dim, deg, form, (double) frob_err);
304*d8f25ad8SToby Isaac   }
305*d8f25ad8SToby Isaac 
306*d8f25ad8SToby Isaac   ierr = PetscFree(M_moment_real);CHKERRQ(ierr);
307*d8f25ad8SToby Isaac   ierr = PetscFree(p_trimmed_copy);CHKERRQ(ierr);
308*d8f25ad8SToby Isaac   ierr = MatDestroy(&mat_trimmed);CHKERRQ(ierr);
309*d8f25ad8SToby Isaac   ierr = PetscFree(Mcopy);CHKERRQ(ierr);
310*d8f25ad8SToby Isaac   ierr = PetscFree(M_moments);CHKERRQ(ierr);
311*d8f25ad8SToby Isaac   ierr = PetscFree(M_trimmed);CHKERRQ(ierr);
312*d8f25ad8SToby Isaac   ierr = PetscFree(p_trimmed);CHKERRQ(ierr);
313*d8f25ad8SToby Isaac   ierr = PetscFree(p_scalar);CHKERRQ(ierr);
314*d8f25ad8SToby Isaac   ierr = PetscQuadratureDestroy(&q);CHKERRQ(ierr);
315*d8f25ad8SToby Isaac   PetscFunctionReturn(0);
316*d8f25ad8SToby Isaac }
317*d8f25ad8SToby Isaac 
318*d8f25ad8SToby Isaac int main(int argc, char **argv)
319*d8f25ad8SToby Isaac {
320*d8f25ad8SToby Isaac   PetscInt  max_dim = 3;
321*d8f25ad8SToby Isaac   PetscInt  max_deg = 4;
322*d8f25ad8SToby Isaac   PetscInt  k = 3;
323*d8f25ad8SToby Isaac   PetscBool cond = PETSC_FALSE;
324*d8f25ad8SToby Isaac 
325*d8f25ad8SToby Isaac   PetscErrorCode ierr = PetscInitialize(&argc, &argv, NULL, help); if (ierr) return ierr;
326*d8f25ad8SToby Isaac   ierr = PetscOptionsBegin(PETSC_COMM_WORLD,"","Options for PetscDTPTrimmedEvalJet() tests","none");CHKERRQ(ierr);
327*d8f25ad8SToby Isaac   ierr = PetscOptionsInt("-max_dim", "Maximum dimension of the simplex",__FILE__,max_dim,&max_dim,NULL);CHKERRQ(ierr);
328*d8f25ad8SToby Isaac   ierr = PetscOptionsInt("-max_degree", "Maximum degree of the trimmed polynomial space",__FILE__,max_deg,&max_deg,NULL);CHKERRQ(ierr);
329*d8f25ad8SToby Isaac   ierr = PetscOptionsInt("-max_jet", "The number of derivatives to test",__FILE__,k,&k,NULL);CHKERRQ(ierr);
330*d8f25ad8SToby Isaac   ierr = PetscOptionsBool("-cond", "Compute the condition numbers of the mass matrices of the bases",__FILE__,cond,&cond,NULL);CHKERRQ(ierr);
331*d8f25ad8SToby Isaac   ierr = PetscOptionsEnd();CHKERRQ(ierr);
332*d8f25ad8SToby Isaac   for (PetscInt dim = 2; dim <= max_dim; dim++) {
333*d8f25ad8SToby Isaac     for (PetscInt deg = 1; deg <= max_deg; deg++) {
334*d8f25ad8SToby Isaac       for (PetscInt form = -dim+1; form <= dim; form++) {
335*d8f25ad8SToby Isaac         ierr = test(dim, deg, form, PetscMax(1, k), cond);CHKERRQ(ierr);
336*d8f25ad8SToby Isaac       }
337*d8f25ad8SToby Isaac     }
338*d8f25ad8SToby Isaac   }
339*d8f25ad8SToby Isaac   ierr = PetscFinalize();
340*d8f25ad8SToby Isaac   return ierr;
341*d8f25ad8SToby Isaac }
342*d8f25ad8SToby Isaac 
343*d8f25ad8SToby Isaac /*TEST
344*d8f25ad8SToby Isaac 
345*d8f25ad8SToby Isaac   test:
346*d8f25ad8SToby Isaac     requires: !single
347*d8f25ad8SToby Isaac     args:
348*d8f25ad8SToby Isaac 
349*d8f25ad8SToby Isaac TEST*/
350