xref: /petsc/src/dm/dt/dualspace/impls/lagrange/tests/ex1.c (revision ef46b1a67e276116c83b5d4ce8efc2932ea4fc0a)
1 
2 #include <petscfe.h>
3 #include <petscdmplex.h>
4 #include <petsc/private/hashmap.h>
5 #include <petsc/private/dmpleximpl.h>
6 #include <petsc/private/petscfeimpl.h>
7 
8 const char help[] = "Test PETSCDUALSPACELAGRANGE\n";
9 
10 typedef struct _PetscHashLagKey
11 {
12   PetscInt  dim;
13   PetscInt  order;
14   PetscInt  formDegree;
15   PetscBool trimmed;
16   PetscInt  tensor;
17   PetscBool continuous;
18 } PetscHashLagKey;
19 
20 #define PetscHashLagKeyHash(key) \
21   PetscHashCombine(PetscHashCombine(PetscHashCombine(PetscHashInt((key).dim), \
22                                                      PetscHashInt((key).order)), \
23                                     PetscHashInt((key).formDegree)), \
24                    PetscHashCombine(PetscHashCombine(PetscHashInt((key).trimmed), \
25                                                      PetscHashInt((key).tensor)), \
26                                     PetscHashInt((key).continuous)))
27 
28 #define PetscHashLagKeyEqual(k1,k2) \
29   (((k1).dim == (k2).dim) ? \
30    ((k1).order == (k2).order) ? \
31    ((k1).formDegree == (k2).formDegree) ? \
32    ((k1).trimmed == (k2).trimmed) ? \
33    ((k1).tensor == (k2).tensor) ? \
34    ((k1).continuous == (k2).continuous) : 0 : 0 : 0 : 0 : 0)
35 
36 PETSC_HASH_MAP(HashLag, PetscHashLagKey, PetscInt, PetscHashLagKeyHash, PetscHashLagKeyEqual, 0)
37 
38 static PetscErrorCode ExpectedNumDofs_Total(PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscInt nCopies, PetscInt *nDofs);
39 static PetscErrorCode ExpectedNumDofs_Interior(PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscInt nCopies, PetscInt *nDofs);
40 
41 static PetscErrorCode ExpectedNumDofs_Total(PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscInt nCopies, PetscInt *nDofs)
42 {
43   PetscFunctionBegin;
44   formDegree = PetscAbsInt(formDegree);
45   /* see femtable.org for the source of most of these values */
46   *nDofs = -1;
47   if (tensor == 0) { /* simplex spaces */
48     if (trimmed) {
49       PetscInt rnchooserk;
50       PetscInt rkm1choosek;
51 
52       PetscCall(PetscDTBinomialInt(order + dim, order + formDegree, &rnchooserk));
53       PetscCall(PetscDTBinomialInt(order + formDegree - 1, formDegree, &rkm1choosek));
54       *nDofs = rnchooserk * rkm1choosek * nCopies;
55     } else {
56       PetscInt rnchooserk;
57       PetscInt rkchoosek;
58 
59       PetscCall(PetscDTBinomialInt(order + dim, order + formDegree, &rnchooserk));
60       PetscCall(PetscDTBinomialInt(order + formDegree, formDegree, &rkchoosek));
61       *nDofs = rnchooserk * rkchoosek * nCopies;
62     }
63   } else if (tensor == 1) { /* hypercubes */
64     if (trimmed) {
65       PetscInt nchoosek;
66       PetscInt rpowk, rp1pownmk;
67 
68       PetscCall(PetscDTBinomialInt(dim, formDegree, &nchoosek));
69       rpowk = PetscPowInt(order, formDegree);
70       rp1pownmk = PetscPowInt(order + 1, dim - formDegree);
71       *nDofs = nchoosek * rpowk * rp1pownmk * nCopies;
72     } else {
73       PetscInt nchoosek;
74       PetscInt rp1pown;
75 
76       PetscCall(PetscDTBinomialInt(dim, formDegree, &nchoosek));
77       rp1pown = PetscPowInt(order + 1, dim);
78       *nDofs = nchoosek * rp1pown * nCopies;
79     }
80   } else { /* prism */
81     PetscInt tracek = 0;
82     PetscInt tracekm1 = 0;
83     PetscInt fiber0 = 0;
84     PetscInt fiber1 = 0;
85 
86     if (formDegree < dim) {
87       PetscCall(ExpectedNumDofs_Total(dim - 1, order, formDegree, trimmed, 0, 1, &tracek));
88       PetscCall(ExpectedNumDofs_Total(1, order, 0, trimmed, 0, 1, &fiber0));
89     }
90     if (formDegree > 0) {
91       PetscCall(ExpectedNumDofs_Total(dim - 1, order, formDegree - 1, trimmed, 0, 1, &tracekm1));
92       PetscCall(ExpectedNumDofs_Total(1, order, 1, trimmed, 0, 1, &fiber1));
93     }
94     *nDofs = (tracek * fiber0 + tracekm1 * fiber1) * nCopies;
95   }
96   PetscFunctionReturn(0);
97 }
98 
99 static PetscErrorCode ExpectedNumDofs_Interior(PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed,
100                                                PetscInt tensor, PetscInt nCopies, PetscInt *nDofs)
101 {
102   PetscFunctionBegin;
103   formDegree = PetscAbsInt(formDegree);
104   /* see femtable.org for the source of most of these values */
105   *nDofs = -1;
106   if (tensor == 0) { /* simplex spaces */
107     if (trimmed) {
108       if (order + formDegree > dim) {
109         PetscInt eorder = order + formDegree - dim - 1;
110         PetscInt eformDegree = dim - formDegree;
111         PetscInt rnchooserk;
112         PetscInt rkchoosek;
113 
114         PetscCall(PetscDTBinomialInt(eorder + dim, eorder + eformDegree, &rnchooserk));
115         PetscCall(PetscDTBinomialInt(eorder + eformDegree, eformDegree, &rkchoosek));
116         *nDofs = rnchooserk * rkchoosek * nCopies;
117       } else {
118         *nDofs = 0;
119       }
120 
121     } else {
122       if (order + formDegree > dim) {
123         PetscInt eorder = order + formDegree - dim;
124         PetscInt eformDegree = dim - formDegree;
125         PetscInt rnchooserk;
126         PetscInt rkm1choosek;
127 
128         PetscCall(PetscDTBinomialInt(eorder + dim, eorder + eformDegree, &rnchooserk));
129         PetscCall(PetscDTBinomialInt(eorder + eformDegree - 1, eformDegree, &rkm1choosek));
130         *nDofs = rnchooserk * rkm1choosek * nCopies;
131       } else {
132         *nDofs = 0;
133       }
134     }
135   } else if (tensor == 1) { /* hypercubes */
136     if (dim < 2) {
137       PetscCall(ExpectedNumDofs_Interior(dim, order, formDegree, trimmed, 0, nCopies, nDofs));
138     } else {
139       PetscInt tracek = 0;
140       PetscInt tracekm1 = 0;
141       PetscInt fiber0 = 0;
142       PetscInt fiber1 = 0;
143 
144       if (formDegree < dim) {
145         PetscCall(ExpectedNumDofs_Interior(dim - 1, order, formDegree, trimmed, dim > 2 ? 1 : 0, 1, &tracek));
146         PetscCall(ExpectedNumDofs_Interior(1, order, 0, trimmed, 0, 1, &fiber0));
147       }
148       if (formDegree > 0) {
149         PetscCall(ExpectedNumDofs_Interior(dim - 1, order, formDegree - 1, trimmed, dim > 2 ? 1 : 0, 1, &tracekm1));
150         PetscCall(ExpectedNumDofs_Interior(1, order, 1, trimmed, 0, 1, &fiber1));
151       }
152       *nDofs = (tracek * fiber0 + tracekm1 * fiber1) * nCopies;
153     }
154   } else { /* prism */
155     PetscInt tracek = 0;
156     PetscInt tracekm1 = 0;
157     PetscInt fiber0 = 0;
158     PetscInt fiber1 = 0;
159 
160     if (formDegree < dim) {
161       PetscCall(ExpectedNumDofs_Interior(dim - 1, order, formDegree, trimmed, 0, 1, &tracek));
162       PetscCall(ExpectedNumDofs_Interior(1, order, 0, trimmed, 0, 1, &fiber0));
163     }
164     if (formDegree > 0) {
165       PetscCall(ExpectedNumDofs_Interior(dim - 1, order, formDegree - 1, trimmed, 0, 1, &tracekm1));
166       PetscCall(ExpectedNumDofs_Interior(1, order, 1, trimmed, 0, 1, &fiber1));
167     }
168     *nDofs = (tracek * fiber0 + tracekm1 * fiber1) * nCopies;
169   }
170   PetscFunctionReturn(0);
171 }
172 
173 PetscErrorCode testLagrange(PetscHashLag lagTable, DM K, PetscInt dim, PetscInt order, PetscInt formDegree, PetscBool trimmed, PetscInt tensor, PetscBool continuous, PetscInt nCopies)
174 {
175   PetscDualSpace  sp;
176   MPI_Comm        comm = PETSC_COMM_SELF;
177   PetscInt        Nk;
178   PetscHashLagKey key;
179   PetscHashIter   iter;
180   PetscBool       missing;
181   PetscInt        spdim, spintdim, exspdim, exspintdim;
182 
183   PetscFunctionBegin;
184   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &Nk));
185   PetscCall(PetscDualSpaceCreate(comm, &sp));
186   PetscCall(PetscDualSpaceSetType(sp, PETSCDUALSPACELAGRANGE));
187   PetscCall(PetscDualSpaceSetDM(sp, K));
188   PetscCall(PetscDualSpaceSetOrder(sp, order));
189   PetscCall(PetscDualSpaceSetFormDegree(sp, formDegree));
190   PetscCall(PetscDualSpaceSetNumComponents(sp, nCopies * Nk));
191   PetscCall(PetscDualSpaceLagrangeSetContinuity(sp, continuous));
192   PetscCall(PetscDualSpaceLagrangeSetTensor(sp, (PetscBool) tensor));
193   PetscCall(PetscDualSpaceLagrangeSetTrimmed(sp, trimmed));
194   PetscCall(PetscInfo(NULL, "Input: dim %D, order %D, trimmed %D, tensor %D, continuous %D, formDegree %D, nCopies %D\n", dim, order, (PetscInt) trimmed, tensor, (PetscInt) continuous, formDegree, nCopies));
195   PetscCall(ExpectedNumDofs_Total(dim, order, formDegree, trimmed, tensor, nCopies, &exspdim));
196   if (continuous && dim > 0 && order > 0) {
197     PetscCall(ExpectedNumDofs_Interior(dim, order, formDegree, trimmed, tensor, nCopies, &exspintdim));
198   } else {
199     exspintdim = exspdim;
200   }
201   PetscCall(PetscDualSpaceSetUp(sp));
202   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
203   PetscCall(PetscDualSpaceGetInteriorDimension(sp, &spintdim));
204   PetscCheck(spdim == exspdim,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected dual space dimension %D, got %D", exspdim, spdim);
205   PetscCheck(spintdim == exspintdim,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected dual space interior dimension %D, got %D", exspintdim, spintdim);
206   key.dim = dim;
207   key.formDegree = formDegree;
208   PetscCall(PetscDualSpaceGetOrder(sp, &key.order));
209   PetscCall(PetscDualSpaceLagrangeGetContinuity(sp, &key.continuous));
210   if (tensor == 2) {
211     key.tensor = 2;
212   } else {
213     PetscBool bTensor;
214 
215     PetscCall(PetscDualSpaceLagrangeGetTensor(sp, &bTensor));
216     key.tensor = bTensor;
217   }
218   PetscCall(PetscDualSpaceLagrangeGetTrimmed(sp, &key.trimmed));
219   PetscCall(PetscInfo(NULL, "After setup:  order %D, trimmed %D, tensor %D, continuous %D\n", key.order, (PetscInt) key.trimmed, key.tensor, (PetscInt) key.continuous));
220   PetscCall(PetscHashLagPut(lagTable, key, &iter, &missing));
221   if (missing) {
222     DMPolytopeType type;
223 
224     PetscCall(DMPlexGetCellType(K, 0, &type));
225     PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "New space: %s, order %D, trimmed %D, tensor %D, continuous %D, form degree %D\n", DMPolytopeTypes[type], order, (PetscInt) trimmed, tensor, (PetscInt) continuous, formDegree));
226     PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_SELF));
227     {
228       PetscQuadrature intNodes, allNodes;
229       Mat intMat, allMat;
230       MatInfo info;
231       PetscInt i, j, nodeIdxDim, nodeVecDim, nNodes;
232       const PetscInt *nodeIdx;
233       const PetscReal *nodeVec;
234 
235       PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data;
236 
237       PetscCall(PetscLagNodeIndicesGetData_Internal(lag->allNodeIndices, &nodeIdxDim, &nodeVecDim, &nNodes, &nodeIdx, &nodeVec));
238       PetscCheck(nodeVecDim == Nk,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect nodeVecDim");
239       PetscCheck(nNodes == spdim,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect nNodes");
240 
241       PetscCall(PetscDualSpaceGetAllData(sp, &allNodes, &allMat));
242 
243       PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "All nodes:\n"));
244       PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_SELF));
245       PetscCall(PetscQuadratureView(allNodes, PETSC_VIEWER_STDOUT_SELF));
246       PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_SELF));
247       PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "All node indices:\n"));
248       for (i = 0; i < spdim; i++) {
249         PetscCall(PetscPrintf(PETSC_COMM_SELF, "("));
250         for (j = 0; j < nodeIdxDim; j++) {
251           PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D,", nodeIdx[i * nodeIdxDim + j]));
252         }
253         PetscCall(PetscPrintf(PETSC_COMM_SELF, "): ["));
254         for (j = 0; j < nodeVecDim; j++) {
255           PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g,", (double) nodeVec[i * nodeVecDim + j]));
256         }
257         PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
258       }
259 
260       PetscCall(MatGetInfo(allMat, MAT_LOCAL, &info));
261       PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "All matrix: %D nonzeros\n", (PetscInt) info.nz_used));
262 
263       PetscCall(PetscDualSpaceGetInteriorData(sp, &intNodes, &intMat));
264       if (intMat && intMat != allMat) {
265         PetscInt        intNodeIdxDim, intNodeVecDim, intNnodes;
266         const PetscInt  *intNodeIdx;
267         const PetscReal *intNodeVec;
268         PetscBool       same;
269 
270         PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "Interior nodes:\n"));
271         PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_SELF));
272         PetscCall(PetscQuadratureView(intNodes, PETSC_VIEWER_STDOUT_SELF));
273         PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_SELF));
274 
275         PetscCall(MatGetInfo(intMat, MAT_LOCAL, &info));
276         PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "Interior matrix: %D nonzeros\n", (PetscInt) info.nz_used));
277         PetscCall(PetscLagNodeIndicesGetData_Internal(lag->intNodeIndices, &intNodeIdxDim, &intNodeVecDim, &intNnodes, &intNodeIdx, &intNodeVec));
278         PetscCheckFalse(intNodeIdxDim != nodeIdxDim || intNodeVecDim != nodeVecDim,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior node indices not the same shale as all node indices");
279         PetscCheck(intNnodes == spintdim,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect interior nNodes");
280         PetscCall(PetscArraycmp(intNodeIdx, nodeIdx, nodeIdxDim * intNnodes, &same));
281         PetscCheck(same,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior node indices not the same as start of all node indices");
282         PetscCall(PetscArraycmp(intNodeVec, nodeVec, nodeVecDim * intNnodes, &same));
283         PetscCheck(same,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior node vectors not the same as start of all node vectors");
284       } else if (intMat) {
285         PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "Interior data is the same as all data\n"));
286         PetscCheck(intNodes == allNodes,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior nodes should be the same as all nodes");
287         PetscCheck(lag->intNodeIndices == lag->allNodeIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Interior node indices should be the same as all node indices");
288       }
289     }
290     if (dim <= 2 && spintdim) {
291       PetscInt numFaces, o;
292 
293       {
294         DMPolytopeType ct;
295         /* The number of arrangements is no longer based on the number of faces */
296         PetscCall(DMPlexGetCellType(K, 0, &ct));
297         numFaces = DMPolytopeTypeGetNumArrangments(ct) / 2;
298       }
299       for (o = -numFaces; o < numFaces; ++o) {
300         Mat symMat;
301 
302         PetscCall(PetscDualSpaceCreateInteriorSymmetryMatrix_Lagrange(sp, o, &symMat));
303         PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "Interior node symmetry matrix for orientation %D:\n", o));
304         PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_SELF));
305         PetscCall(MatView(symMat, PETSC_VIEWER_STDOUT_SELF));
306         PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_SELF));
307         PetscCall(MatDestroy(&symMat));
308       }
309     }
310     PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_SELF));
311   }
312   PetscCall(PetscDualSpaceDestroy(&sp));
313   PetscFunctionReturn(0);
314 }
315 
316 int main (int argc, char **argv)
317 {
318   PetscInt        dim;
319   PetscHashLag    lagTable;
320   PetscInt        tensorCell;
321   PetscInt        order, ordermin, ordermax;
322   PetscBool       continuous;
323   PetscBool       trimmed;
324   DM              dm;
325 
326   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
327   dim = 3;
328   tensorCell = 0;
329   continuous = PETSC_FALSE;
330   trimmed = PETSC_FALSE;
331   PetscOptionsBegin(PETSC_COMM_WORLD,"","Options for PETSCDUALSPACELAGRANGE test","none");
332   PetscCall(PetscOptionsRangeInt("-dim", "The spatial dimension","ex1.c",dim,&dim,NULL,0,3));
333   PetscCall(PetscOptionsRangeInt("-tensor", "(0) simplex (1) hypercube (2) wedge","ex1.c",tensorCell,&tensorCell,NULL,0,2));
334   PetscCall(PetscOptionsBool("-continuous", "Whether the dual space has continuity","ex1.c",continuous,&continuous,NULL));
335   PetscCall(PetscOptionsBool("-trimmed", "Whether the dual space matches a trimmed polynomial space","ex1.c",trimmed,&trimmed,NULL));
336   PetscOptionsEnd();
337   PetscCall(PetscHashLagCreate(&lagTable));
338 
339   if (tensorCell < 2) {
340     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, (PetscBool) !tensorCell), &dm));
341   } else {
342     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DM_POLYTOPE_TRI_PRISM, &dm));
343   }
344   ordermin = trimmed ? 1 : 0;
345   ordermax = tensorCell == 2 ? 4 : tensorCell == 1 ? 3 : dim + 2;
346   for (order = ordermin; order <= ordermax; order++) {
347     PetscInt formDegree;
348 
349     for (formDegree = PetscMin(0,-dim+1); formDegree <= dim; formDegree++) {
350       PetscInt nCopies;
351 
352       for (nCopies = 1; nCopies <= 3; nCopies++) {
353         PetscCall(testLagrange(lagTable, dm, dim, order, formDegree, trimmed, (PetscBool) tensorCell, continuous, nCopies));
354       }
355     }
356   }
357   PetscCall(DMDestroy(&dm));
358   PetscCall(PetscHashLagDestroy(&lagTable));
359   PetscCall(PetscFinalize());
360   return 0;
361 }
362 
363 /*TEST
364 
365  test:
366    suffix: 0
367    args: -dim 0
368 
369  test:
370    suffix: 1_discontinuous_full
371    args: -dim 1 -continuous 0 -trimmed 0
372 
373  test:
374    suffix: 1_continuous_full
375    args: -dim 1 -continuous 1 -trimmed 0
376 
377  test:
378    suffix: 2_simplex_discontinuous_full
379    args: -dim 2 -tensor 0 -continuous 0 -trimmed 0
380 
381  test:
382    suffix: 2_simplex_continuous_full
383    args: -dim 2 -tensor 0 -continuous 1 -trimmed 0
384 
385  test:
386    suffix: 2_tensor_discontinuous_full
387    args: -dim 2 -tensor 1 -continuous 0 -trimmed 0
388 
389  test:
390    suffix: 2_tensor_continuous_full
391    args: -dim 2 -tensor 1 -continuous 1 -trimmed 0
392 
393  test:
394    suffix: 3_simplex_discontinuous_full
395    args: -dim 3 -tensor 0 -continuous 0 -trimmed 0
396 
397  test:
398    suffix: 3_simplex_continuous_full
399    args: -dim 3 -tensor 0 -continuous 1 -trimmed 0
400 
401  test:
402    suffix: 3_tensor_discontinuous_full
403    args: -dim 3 -tensor 1 -continuous 0 -trimmed 0
404 
405  test:
406    suffix: 3_tensor_continuous_full
407    args: -dim 3 -tensor 1 -continuous 1 -trimmed 0
408 
409  test:
410    suffix: 3_wedge_discontinuous_full
411    args: -dim 3 -tensor 2 -continuous 0 -trimmed 0
412 
413  test:
414    suffix: 3_wedge_continuous_full
415    args: -dim 3 -tensor 2 -continuous 1 -trimmed 0
416 
417  test:
418    suffix: 1_discontinuous_trimmed
419    args: -dim 1 -continuous 0 -trimmed 1
420 
421  test:
422    suffix: 1_continuous_trimmed
423    args: -dim 1 -continuous 1 -trimmed 1
424 
425  test:
426    suffix: 2_simplex_discontinuous_trimmed
427    args: -dim 2 -tensor 0 -continuous 0 -trimmed 1
428 
429  test:
430    suffix: 2_simplex_continuous_trimmed
431    args: -dim 2 -tensor 0 -continuous 1 -trimmed 1
432 
433  test:
434    suffix: 2_tensor_discontinuous_trimmed
435    args: -dim 2 -tensor 1 -continuous 0 -trimmed 1
436 
437  test:
438    suffix: 2_tensor_continuous_trimmed
439    args: -dim 2 -tensor 1 -continuous 1 -trimmed 1
440 
441  test:
442    suffix: 3_simplex_discontinuous_trimmed
443    args: -dim 3 -tensor 0 -continuous 0 -trimmed 1
444 
445  test:
446    suffix: 3_simplex_continuous_trimmed
447    args: -dim 3 -tensor 0 -continuous 1 -trimmed 1
448 
449  test:
450    suffix: 3_tensor_discontinuous_trimmed
451    args: -dim 3 -tensor 1 -continuous 0 -trimmed 1
452 
453  test:
454    suffix: 3_tensor_continuous_trimmed
455    args: -dim 3 -tensor 1 -continuous 1 -trimmed 1
456 
457  test:
458    suffix: 3_wedge_discontinuous_trimmed
459    args: -dim 3 -tensor 2 -continuous 0 -trimmed 1
460 
461  test:
462    suffix: 3_wedge_continuous_trimmed
463    args: -dim 3 -tensor 2 -continuous 1 -trimmed 1
464 
465 TEST*/
466