xref: /petsc/src/dm/impls/plex/tests/ex39.c (revision 5f80ce2ab25dff0f4601e710601cbbcecf323266)
130602db0SMatthew G. Knepley const char help[] = "A test of H-div conforming discretizations on different cell types.\n";
2c4762a1bSJed Brown 
3c4762a1bSJed Brown #include <petscdmplex.h>
4c4762a1bSJed Brown #include <petscds.h>
5c4762a1bSJed Brown #include <petscsnes.h>
6c4762a1bSJed Brown #include <petscconvest.h>
7c4762a1bSJed Brown #include <petscfe.h>
8c4762a1bSJed Brown #include <petsc/private/petscfeimpl.h>
9c4762a1bSJed Brown 
10c4762a1bSJed Brown /*
110e3d61c9SBarry Smith   We are using the system
120e3d61c9SBarry Smith 
130e3d61c9SBarry Smith   \vec{u} = \vec{\hat{u}}
140e3d61c9SBarry Smith   p = \div{\vec{u}} in low degree approximation space
150e3d61c9SBarry Smith   d = \div{\vec{u}} - p == 0 in higher degree approximation space
160e3d61c9SBarry Smith 
170e3d61c9SBarry Smith   That is, we are using the field d to compute the error between \div{\vec{u}}
180e3d61c9SBarry Smith   computed in a space 1 degree higher than p and the value of p which is
190e3d61c9SBarry Smith   \div{u} computed in the low degree space. If H-div
200e3d61c9SBarry Smith   elements are implemented correctly then this should be identically zero since
210e3d61c9SBarry Smith   the divergence of a function in H(div) should be exactly representable in L_2
220e3d61c9SBarry Smith   by definition.
23c4762a1bSJed Brown */
24c4762a1bSJed Brown static PetscErrorCode zero_func(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar *u,void *ctx)
25c4762a1bSJed Brown {
26c4762a1bSJed Brown   PetscInt c;
27c4762a1bSJed Brown   for (c = 0; c < Nc; ++c) u[c] = 0;
28c4762a1bSJed Brown   return 0;
29c4762a1bSJed Brown }
30c4762a1bSJed Brown /* Linear Exact Functions
31c4762a1bSJed Brown    \vec{u} = \vec{x};
32c4762a1bSJed Brown    p = dim;
33c4762a1bSJed Brown    */
34c4762a1bSJed Brown static PetscErrorCode linear_u(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar *u,void *ctx)
35c4762a1bSJed Brown {
36c4762a1bSJed Brown   PetscInt c;
37c4762a1bSJed Brown   for (c = 0; c < Nc; ++c) u[c] = x[c];
38c4762a1bSJed Brown   return 0;
39c4762a1bSJed Brown }
40c4762a1bSJed Brown static PetscErrorCode linear_p(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar *u,void *ctx)
41c4762a1bSJed Brown {
42c4762a1bSJed Brown   u[0] = dim;
43c4762a1bSJed Brown   return 0;
44c4762a1bSJed Brown }
45c4762a1bSJed Brown 
46c4762a1bSJed Brown /* Sinusoidal Exact Functions
47c4762a1bSJed Brown  * u_i = \sin{2*\pi*x_i}
48c4762a1bSJed Brown  * p = \Sum_{i=1}^{dim} 2*\pi*cos{2*\pi*x_i}
49c4762a1bSJed Brown  * */
50c4762a1bSJed Brown 
51c4762a1bSJed Brown static PetscErrorCode sinusoid_u(PetscInt dim,PetscReal time,const PetscReal
52c4762a1bSJed Brown                                  x[],PetscInt Nc,PetscScalar *u,void *ctx)
53c4762a1bSJed Brown {
54c4762a1bSJed Brown   PetscInt c;
55c4762a1bSJed Brown   for (c = 0; c< Nc; ++c) u[c] = PetscSinReal(2*PETSC_PI*x[c]);
56c4762a1bSJed Brown   return 0;
57c4762a1bSJed Brown }
58c4762a1bSJed Brown static PetscErrorCode sinusoid_p(PetscInt dim,PetscReal time,const PetscReal
59c4762a1bSJed Brown                                  x[],PetscInt Nc,PetscScalar *u,void *ctx)
60c4762a1bSJed Brown {
61c4762a1bSJed Brown   PetscInt d;
62c4762a1bSJed Brown   u[0]=0;
63c4762a1bSJed Brown   for (d=0; d<dim; ++d) u[0] += 2*PETSC_PI*PetscCosReal(2*PETSC_PI*x[d]);
64c4762a1bSJed Brown   return 0;
65c4762a1bSJed Brown }
66c4762a1bSJed Brown 
67c4762a1bSJed Brown /* Pointwise residual for u = u*. Need one of these for each possible u* */
68c4762a1bSJed Brown static void f0_v_linear(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])
69c4762a1bSJed Brown {
70c4762a1bSJed Brown   PetscInt    i;
71c4762a1bSJed Brown   PetscScalar *u_rhs;
72c4762a1bSJed Brown 
73c4762a1bSJed Brown   PetscCalloc1(dim,&u_rhs);
74c4762a1bSJed Brown   (void) linear_u(dim,t,x,dim,u_rhs,NULL);
75c4762a1bSJed Brown   for (i = 0; i < dim; ++i) f0[i] = u[uOff[0]+i]-u_rhs[i];
76c4762a1bSJed Brown   PetscFree(u_rhs);
77c4762a1bSJed Brown }
78c4762a1bSJed Brown 
79c4762a1bSJed Brown static void f0_v_sinusoid(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])
80c4762a1bSJed Brown {
81c4762a1bSJed Brown   PetscInt    i;
82c4762a1bSJed Brown   PetscScalar *u_rhs;
83c4762a1bSJed Brown 
84c4762a1bSJed Brown   PetscCalloc1(dim,&u_rhs);
85c4762a1bSJed Brown   (void) sinusoid_u(dim,t,x,dim,u_rhs,NULL);
86c4762a1bSJed Brown   for (i = 0; i < dim; ++i) f0[i] = u[uOff[0]+i]-u_rhs[i];
87c4762a1bSJed Brown   PetscFree(u_rhs);
88c4762a1bSJed Brown }
89c4762a1bSJed Brown 
90c4762a1bSJed Brown /* Residual function for enforcing p = \div{u}. */
91c4762a1bSJed Brown static void f0_q(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])
92c4762a1bSJed Brown {
93c4762a1bSJed Brown   PetscInt    i;
94c4762a1bSJed Brown   PetscScalar divu;
95c4762a1bSJed Brown 
96c4762a1bSJed Brown   divu = 0.;
97c4762a1bSJed Brown   for (i = 0; i< dim; ++i) divu += u_x[uOff_x[0]+i*dim+i];
98c4762a1bSJed Brown   f0[0] = u[uOff[1]] - divu;
99c4762a1bSJed Brown }
100c4762a1bSJed Brown 
101c4762a1bSJed Brown /* Residual function for p_err = \div{u} - p. */
102c4762a1bSJed Brown static void f0_w(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])
103c4762a1bSJed Brown {
104c4762a1bSJed Brown   PetscInt    i;
105c4762a1bSJed Brown   PetscScalar divu;
106c4762a1bSJed Brown 
107c4762a1bSJed Brown   divu = 0.;
108c4762a1bSJed Brown   for (i = 0; i < dim; ++i) divu += u_x[uOff_x[0] + i*dim +i];
109c4762a1bSJed Brown   f0[0] = u[uOff[2]] - u[uOff[1]] + divu;
110c4762a1bSJed Brown }
111c4762a1bSJed Brown 
112c4762a1bSJed Brown /* Boundary residual for the embedding system. Need one for each form of
113c4762a1bSJed Brown  * solution. These enforce u = \hat{u} at the boundary. */
114c4762a1bSJed Brown static void f0_bd_u_sinusoid(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])
115c4762a1bSJed Brown {
116c4762a1bSJed Brown   PetscInt    d;
117c4762a1bSJed Brown   PetscScalar *u_rhs;
118c4762a1bSJed Brown   PetscCalloc1(dim,&u_rhs);
119c4762a1bSJed Brown   (void) sinusoid_u(dim,t,x,dim,u_rhs,NULL);
120c4762a1bSJed Brown 
121c4762a1bSJed Brown   for (d=0; d<dim; ++d) f0[d] = u_rhs[d];
122c4762a1bSJed Brown   PetscFree(u_rhs);
123c4762a1bSJed Brown 
124c4762a1bSJed Brown }
125c4762a1bSJed Brown 
126c4762a1bSJed Brown static void f0_bd_u_linear(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])
127c4762a1bSJed Brown {
128c4762a1bSJed Brown   PetscInt    d;
129c4762a1bSJed Brown   PetscScalar *u_rhs;
130c4762a1bSJed Brown   PetscCalloc1(dim,&u_rhs);
131c4762a1bSJed Brown   (void) linear_u(dim,t,x,dim,u_rhs,NULL);
132c4762a1bSJed Brown 
133c4762a1bSJed Brown   for (d=0; d<dim; ++d) f0[d] = u_rhs[d];
134c4762a1bSJed Brown   PetscFree(u_rhs);
135c4762a1bSJed Brown }
136c4762a1bSJed Brown /* Jacobian functions. For the following, v is the test function associated with
137c4762a1bSJed Brown  * u, q the test function associated with p, and w the test function associated
138c4762a1bSJed Brown  * with d. */
139c4762a1bSJed Brown /* <v, u> */
140c4762a1bSJed Brown static void g0_vu(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])
141c4762a1bSJed Brown {
142c4762a1bSJed Brown   PetscInt c;
143c4762a1bSJed Brown   for (c = 0; c < dim; ++c) g0[c * dim + c] = 1.0;
144c4762a1bSJed Brown }
145c4762a1bSJed Brown 
146c4762a1bSJed Brown /* <q, p> */
147c4762a1bSJed Brown static void g0_qp(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])
148c4762a1bSJed Brown {
149c4762a1bSJed Brown   PetscInt d;
150c4762a1bSJed Brown   for (d=0; d< dim; ++d) g0[d * dim + d] = 1.0;
151c4762a1bSJed Brown }
152c4762a1bSJed Brown 
153c4762a1bSJed Brown /* -<q, \div{u}> For the embedded system. This is different from the method of
154c4762a1bSJed Brown  * manufactured solution because instead of computing <q,\div{u}> - <q,f> we
155c4762a1bSJed Brown  * need <q,p> - <q,\div{u}.*/
156c4762a1bSJed Brown static void g1_qu(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g1[])
157c4762a1bSJed Brown {
158c4762a1bSJed Brown   PetscInt d;
159c4762a1bSJed Brown   for (d = 0; d < dim; ++d) g1[d * dim + d] = -1.0;
160c4762a1bSJed Brown }
161c4762a1bSJed Brown 
162c4762a1bSJed Brown /* <w, p> This is only used by the embedded system. Where we need to compute
163c4762a1bSJed Brown  * <w,d> - <w,p> + <w, \div{u}>*/
164c4762a1bSJed Brown static void g0_wp(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])
165c4762a1bSJed Brown {
166c4762a1bSJed Brown   PetscInt d;
167c4762a1bSJed Brown   for (d=0; d< dim; ++d) g0[d * dim + d] = -1.0;
168c4762a1bSJed Brown }
169c4762a1bSJed Brown 
170c4762a1bSJed Brown /* <w, d> */
171c4762a1bSJed Brown static void g0_wd(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g0[])
172c4762a1bSJed Brown {
173c4762a1bSJed Brown   PetscInt c;
174c4762a1bSJed Brown   for (c = 0; c < dim; ++c) g0[c*dim+c] = 1.0;
175c4762a1bSJed Brown }
176c4762a1bSJed Brown 
177c4762a1bSJed Brown /* <w, \div{u}> for the embedded system. */
178c4762a1bSJed Brown static void g1_wu(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar g1[])
179c4762a1bSJed Brown {
180c4762a1bSJed Brown   PetscInt d;
181c4762a1bSJed Brown   for (d = 0; d < dim; ++d) g1[d * dim + d] = 1.0;
182c4762a1bSJed Brown }
183c4762a1bSJed Brown 
184c4762a1bSJed Brown /* Enum and string array for selecting mesh perturbation options */
185c4762a1bSJed Brown typedef enum { NONE = 0,PERTURB = 1,SKEW = 2,SKEW_PERTURB = 3 } Transform;
186c4762a1bSJed Brown const char* const TransformTypes[] = {"none","perturb","skew","skew_perturb","Perturbation","",NULL};
187c4762a1bSJed Brown 
188c4762a1bSJed Brown /* Enum and string array for selecting the form of the exact solution*/
189c4762a1bSJed Brown typedef enum
190c4762a1bSJed Brown { LINEAR = 0,SINUSOIDAL = 1 } Solution;
191c4762a1bSJed Brown const char* const SolutionTypes[] = {"linear","sinusoidal","Solution","",NULL};
192c4762a1bSJed Brown 
193c4762a1bSJed Brown typedef struct
194c4762a1bSJed Brown {
195c4762a1bSJed Brown   Transform mesh_transform;
196c4762a1bSJed Brown   Solution  sol_form;
197c4762a1bSJed Brown } UserCtx;
198c4762a1bSJed Brown 
199c4762a1bSJed Brown /* Process command line options and initialize the UserCtx struct */
200c4762a1bSJed Brown static PetscErrorCode ProcessOptions(MPI_Comm comm,UserCtx * user)
201c4762a1bSJed Brown {
202c4762a1bSJed Brown   PetscErrorCode ierr;
203c4762a1bSJed Brown 
204c4762a1bSJed Brown   PetscFunctionBegin;
205c4762a1bSJed Brown   /* Default to  2D, unperturbed triangle mesh and Linear solution.*/
206c4762a1bSJed Brown   user->mesh_transform = NONE;
207c4762a1bSJed Brown   user->sol_form       = LINEAR;
208c4762a1bSJed Brown 
209c4762a1bSJed Brown   ierr = PetscOptionsBegin(comm,"","H-div Test Options","DMPLEX");CHKERRQ(ierr);
210*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsEnum("-mesh_transform","Method used to perturb the mesh vertices. Options are skew, perturb, skew_perturb,or none","ex39.c",TransformTypes,(PetscEnum) user->mesh_transform,(PetscEnum*) &user->mesh_transform,NULL));
211*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsEnum("-sol_form","Form of the exact solution. Options are Linear or Sinusoidal","ex39.c",SolutionTypes,(PetscEnum) user->sol_form,(PetscEnum*) &user->sol_form,NULL));
212c4762a1bSJed Brown   ierr = PetscOptionsEnd();CHKERRQ(ierr);
213c4762a1bSJed Brown   PetscFunctionReturn(0);
214c4762a1bSJed Brown }
215c4762a1bSJed Brown 
216c4762a1bSJed Brown /* Perturb the position of each mesh vertex by a small amount.*/
217c4762a1bSJed Brown static PetscErrorCode PerturbMesh(DM *mesh,PetscScalar *coordVals,PetscInt npoints,PetscInt dim)
218c4762a1bSJed Brown {
219c4762a1bSJed Brown   PetscInt       i,j,k;
220d092c84bSBrandon Whitchurch   PetscReal      minCoords[3],maxCoords[3],maxPert[3],randVal,amp;
221c4762a1bSJed Brown   PetscRandom    ran;
222c4762a1bSJed Brown 
223c4762a1bSJed Brown   PetscFunctionBegin;
224*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDim(*mesh,&dim));
225*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalBoundingBox(*mesh,minCoords,maxCoords));
226*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscRandomCreate(PETSC_COMM_WORLD,&ran));
227c4762a1bSJed Brown 
228c4762a1bSJed Brown   /* Compute something approximately equal to half an edge length. This is the
229a5b23f4aSJose E. Roman    * most we can perturb points and guarantee that there won't be any topology
230c4762a1bSJed Brown    * issues. */
231d092c84bSBrandon Whitchurch   for (k = 0; k < dim; ++k) maxPert[k] = 0.025 * (maxCoords[k] - minCoords[k]) / (PetscPowReal(npoints,1. / dim) - 1);
232c4762a1bSJed Brown   /* For each mesh vertex */
233c4762a1bSJed Brown   for (i = 0; i < npoints; ++i) {
234c4762a1bSJed Brown     /* For each coordinate of the vertex */
235c4762a1bSJed Brown     for (j = 0; j < dim; ++j) {
236c4762a1bSJed Brown       /* Generate a random amplitude in [-0.5*maxPert, 0.5*maxPert] */
237*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscRandomGetValueReal(ran,&randVal));
238c4762a1bSJed Brown       amp  = maxPert[j] * (randVal - 0.5);
239c4762a1bSJed Brown       /* Add the perturbation to the vertex*/
240d092c84bSBrandon Whitchurch       coordVals[dim * i + j] += amp;
241c4762a1bSJed Brown     }
242c4762a1bSJed Brown   }
243c4762a1bSJed Brown 
244c4762a1bSJed Brown   PetscRandomDestroy(&ran);
245c4762a1bSJed Brown   PetscFunctionReturn(0);
246c4762a1bSJed Brown }
247c4762a1bSJed Brown 
248c4762a1bSJed Brown /* Apply a global skew transformation to the mesh. */
249c4762a1bSJed Brown static PetscErrorCode SkewMesh(DM * mesh,PetscScalar * coordVals,PetscInt npoints,PetscInt dim)
250c4762a1bSJed Brown {
251c4762a1bSJed Brown   PetscInt       i,j,k,l;
252c4762a1bSJed Brown   PetscScalar    * transMat;
253c4762a1bSJed Brown   PetscScalar    tmpcoord[3];
254c4762a1bSJed Brown   PetscRandom    ran;
255c4762a1bSJed Brown   PetscReal      randVal;
256c4762a1bSJed Brown 
257c4762a1bSJed Brown   PetscFunctionBegin;
258*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(dim * dim,&transMat));
259*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscRandomCreate(PETSC_COMM_WORLD,&ran));
260c4762a1bSJed Brown 
261c4762a1bSJed Brown   /* Make a matrix representing a skew transformation */
262c4762a1bSJed Brown   for (i = 0; i < dim; ++i) {
263c4762a1bSJed Brown     for (j = 0; j < dim; ++j) {
264*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscRandomGetValueReal(ran,&randVal));
265d092c84bSBrandon Whitchurch       if (i == j) transMat[i * dim + j] = 1.;
266c4762a1bSJed Brown       else if (j < i) transMat[i * dim + j] = 2 * (j + i)*randVal;
267c4762a1bSJed Brown       else transMat[i * dim + j] = 0;
268c4762a1bSJed Brown     }
269c4762a1bSJed Brown   }
270c4762a1bSJed Brown 
271c4762a1bSJed Brown   /* Multiply each coordinate vector by our tranformation.*/
272c4762a1bSJed Brown   for (i = 0; i < npoints; ++i) {
273c4762a1bSJed Brown     for (j = 0; j < dim; ++j) {
274c4762a1bSJed Brown       tmpcoord[j] = 0;
275c4762a1bSJed Brown       for (k = 0; k < dim; ++k) tmpcoord[j] += coordVals[dim * i + k] * transMat[dim * k + j];
276c4762a1bSJed Brown     }
277c4762a1bSJed Brown     for (l = 0; l < dim; ++l) coordVals[dim * i + l] = tmpcoord[l];
278c4762a1bSJed Brown   }
279*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(transMat));
280*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscRandomDestroy(&ran));
281c4762a1bSJed Brown   PetscFunctionReturn(0);
282c4762a1bSJed Brown }
283c4762a1bSJed Brown 
284c4762a1bSJed Brown /* Accesses the mesh coordinate array and performs the transformation operations
285c4762a1bSJed Brown  * specified by the user options */
286c4762a1bSJed Brown static PetscErrorCode TransformMesh(UserCtx * user,DM * mesh)
287c4762a1bSJed Brown {
288c4762a1bSJed Brown   PetscInt       dim,npoints;
289c4762a1bSJed Brown   PetscScalar    * coordVals;
290c4762a1bSJed Brown   Vec            coords;
291c4762a1bSJed Brown 
292c4762a1bSJed Brown   PetscFunctionBegin;
293*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinates(*mesh,&coords));
294*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(coords,&coordVals));
295*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetLocalSize(coords,&npoints));
296*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDim(*mesh,&dim));
297c4762a1bSJed Brown   npoints = npoints / dim;
298c4762a1bSJed Brown 
299c4762a1bSJed Brown   switch (user->mesh_transform) {
300c4762a1bSJed Brown   case PERTURB:
301*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PerturbMesh(mesh,coordVals,npoints,dim));
302c4762a1bSJed Brown     break;
303c4762a1bSJed Brown   case SKEW:
304*5f80ce2aSJacob Faibussowitsch     CHKERRQ(SkewMesh(mesh,coordVals,npoints,dim));
305c4762a1bSJed Brown     break;
306c4762a1bSJed Brown   case SKEW_PERTURB:
307*5f80ce2aSJacob Faibussowitsch     CHKERRQ(SkewMesh(mesh,coordVals,npoints,dim));
308*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PerturbMesh(mesh,coordVals,npoints,dim));
309c4762a1bSJed Brown     break;
310c4762a1bSJed Brown   default:
311c4762a1bSJed Brown     PetscFunctionReturn(-1);
312c4762a1bSJed Brown   }
313*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(coords,&coordVals));
314*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetCoordinates(*mesh,coords));
315c4762a1bSJed Brown   PetscFunctionReturn(0);
316c4762a1bSJed Brown }
317c4762a1bSJed Brown 
318c4762a1bSJed Brown static PetscErrorCode CreateMesh(MPI_Comm comm,UserCtx * user,DM * mesh)
319c4762a1bSJed Brown {
320c4762a1bSJed Brown   PetscFunctionBegin;
321*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreate(comm, mesh));
322*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetType(*mesh, DMPLEX));
323*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetFromOptions(*mesh));
324c4762a1bSJed Brown 
325c4762a1bSJed Brown   /* Perform any mesh transformations if specified by user */
326c4762a1bSJed Brown   if (user->mesh_transform != NONE) {
327*5f80ce2aSJacob Faibussowitsch     CHKERRQ(TransformMesh(user,mesh));
328c4762a1bSJed Brown   }
329c4762a1bSJed Brown 
330c4762a1bSJed Brown   /* Get any other mesh options from the command line */
331*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetApplicationContext(*mesh,user));
332*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMViewFromOptions(*mesh,NULL,"-dm_view"));
333c4762a1bSJed Brown   PetscFunctionReturn(0);
334c4762a1bSJed Brown }
335c4762a1bSJed Brown 
336c4762a1bSJed Brown /* Setup the system of equations that we wish to solve */
337c4762a1bSJed Brown static PetscErrorCode SetupProblem(DM dm,UserCtx * user)
338c4762a1bSJed Brown {
339c4762a1bSJed Brown   PetscDS        prob;
34045480ffeSMatthew G. Knepley   DMLabel        label;
341c4762a1bSJed Brown   const PetscInt id=1;
342c4762a1bSJed Brown 
343c4762a1bSJed Brown   PetscFunctionBegin;
344*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(dm,&prob));
345c4762a1bSJed Brown   /* All of these are independent of the user's choice of solution */
346*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetResidual(prob,1,f0_q,NULL));
347*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetResidual(prob,2,f0_w,NULL));
348*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetJacobian(prob,0,0,g0_vu,NULL,NULL,NULL));
349*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetJacobian(prob,1,0,NULL,g1_qu,NULL,NULL));
350*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetJacobian(prob,1,1,g0_qp,NULL,NULL,NULL));
351*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetJacobian(prob,2,0,NULL,g1_wu,NULL,NULL));
352*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetJacobian(prob,2,1,g0_wp,NULL,NULL,NULL));
353*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetJacobian(prob,2,2,g0_wd,NULL,NULL,NULL));
354c4762a1bSJed Brown 
355c4762a1bSJed Brown   /* Field 2 is the error between \div{u} and pressure in a higher dimensional
356c4762a1bSJed Brown    * space. If all is right this should be machine zero. */
357*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSSetExactSolution(prob,2,zero_func,NULL));
358c4762a1bSJed Brown 
359c4762a1bSJed Brown   switch (user->sol_form) {
360c4762a1bSJed Brown   case LINEAR:
361*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSSetResidual(prob,0,f0_v_linear,NULL));
362*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSSetBdResidual(prob,0,f0_bd_u_linear,NULL));
363*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSSetExactSolution(prob,0,linear_u,NULL));
364*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSSetExactSolution(prob,1,linear_p,NULL));
365c4762a1bSJed Brown     break;
366c4762a1bSJed Brown   case SINUSOIDAL:
367*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSSetResidual(prob,0,f0_v_sinusoid,NULL));
368*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSSetBdResidual(prob,0,f0_bd_u_sinusoid,NULL));
369*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSSetExactSolution(prob,0,sinusoid_u,NULL));
370*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDSSetExactSolution(prob,1,sinusoid_p,NULL));
371c4762a1bSJed Brown     break;
372c4762a1bSJed Brown   default:
373c4762a1bSJed Brown     PetscFunctionReturn(-1);
374c4762a1bSJed Brown   }
375c4762a1bSJed Brown 
376*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLabel(dm, "marker", &label));
377*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDSAddBoundary(prob,DM_BC_NATURAL,"Boundary Integral",label,1,&id,0,0,NULL,(void (*)(void))NULL,NULL,user,NULL));
378c4762a1bSJed Brown   PetscFunctionReturn(0);
379c4762a1bSJed Brown }
380c4762a1bSJed Brown 
381c4762a1bSJed Brown /* Create the finite element spaces we will use for this system */
382c4762a1bSJed Brown static PetscErrorCode SetupDiscretization(DM mesh,PetscErrorCode (*setup)(DM,UserCtx*),UserCtx *user)
383c4762a1bSJed Brown {
384c4762a1bSJed Brown   DM             cdm = mesh;
385c4762a1bSJed Brown   PetscFE        fevel,fepres,fedivErr;
38630602db0SMatthew G. Knepley   PetscInt       dim;
38730602db0SMatthew G. Knepley   PetscBool      simplex;
388c4762a1bSJed Brown   PetscErrorCode ierr;
389c4762a1bSJed Brown 
390c4762a1bSJed Brown   PetscFunctionBegin;
391*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(mesh, &dim));
392*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexIsSimplex(mesh, &simplex));
393c4762a1bSJed Brown   /* Create FE objects and give them names so that options can be set from
394c4762a1bSJed Brown    * command line */
395*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFECreateDefault(PetscObjectComm((PetscObject) mesh),dim,dim,simplex,"velocity_",-1,&fevel));
396*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectSetName((PetscObject) fevel,"velocity"));
397c4762a1bSJed Brown 
398*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFECreateDefault(PetscObjectComm((PetscObject) mesh),dim,1,simplex,"pressure_",-1,&fepres));
399*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectSetName((PetscObject) fepres,"pressure"));
400c4762a1bSJed Brown 
401c4762a1bSJed Brown   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject)
40230602db0SMatthew G. Knepley                                               mesh),dim,1,simplex,"divErr_",-1,&fedivErr);CHKERRQ(ierr);
403*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectSetName((PetscObject) fedivErr,"divErr"));
404c4762a1bSJed Brown 
405*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFECopyQuadrature(fevel,fepres));
406*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFECopyQuadrature(fevel,fedivErr));
407c4762a1bSJed Brown 
408c4762a1bSJed Brown   /* Associate the FE objects with the mesh and setup the system */
409*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetField(mesh,0,NULL,(PetscObject) fevel));
410*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetField(mesh,1,NULL,(PetscObject) fepres));
411*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetField(mesh,2,NULL,(PetscObject) fedivErr));
412*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateDS(mesh));
413*5f80ce2aSJacob Faibussowitsch   CHKERRQ((*setup)(mesh,user));
414c4762a1bSJed Brown 
415c4762a1bSJed Brown   while (cdm) {
416*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCopyDisc(mesh,cdm));
417*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoarseDM(cdm,&cdm));
418c4762a1bSJed Brown   }
419c4762a1bSJed Brown 
420c4762a1bSJed Brown   /* The Mesh now owns the fields, so we can destroy the FEs created in this
421c4762a1bSJed Brown    * function */
422*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFEDestroy(&fevel));
423*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFEDestroy(&fepres));
424*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFEDestroy(&fedivErr));
425*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&cdm));
426c4762a1bSJed Brown   PetscFunctionReturn(0);
427c4762a1bSJed Brown }
428c4762a1bSJed Brown 
429c4762a1bSJed Brown int main(int argc,char **argv)
430c4762a1bSJed Brown {
431c4762a1bSJed Brown   PetscInt        i;
432c4762a1bSJed Brown   UserCtx         user;
433c4762a1bSJed Brown   DM              mesh;
434c4762a1bSJed Brown   SNES            snes;
435c4762a1bSJed Brown   Vec             computed,divErr;
436c4762a1bSJed Brown   PetscReal       divErrNorm;
437c4762a1bSJed Brown   PetscErrorCode  ierr;
438c4762a1bSJed Brown   IS              * fieldIS;
439c4762a1bSJed Brown   PetscBool       exampleSuccess = PETSC_FALSE;
440d092c84bSBrandon Whitchurch   const PetscReal errTol         = 10. * PETSC_SMALL;
441c4762a1bSJed Brown 
442c4762a1bSJed Brown   char stdFormat[] = "L2 Norm of the Divergence Error is: %g\n H(div) elements working correctly: %s\n";
443c4762a1bSJed Brown 
444c4762a1bSJed Brown   /* Initialize PETSc */
445c4762a1bSJed Brown   ierr = PetscInitialize(&argc,&argv,NULL,help);if (ierr) return ierr;
446*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ProcessOptions(PETSC_COMM_WORLD,&user));
447c4762a1bSJed Brown 
448c4762a1bSJed Brown   /* Set up the system, we need to create a solver and a mesh and then assign
449c4762a1bSJed Brown    * the correct spaces into the mesh*/
450*5f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESCreate(PETSC_COMM_WORLD,&snes));
451*5f80ce2aSJacob Faibussowitsch   CHKERRQ(CreateMesh(PETSC_COMM_WORLD,&user,&mesh));
452*5f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetDM(snes,mesh));
453*5f80ce2aSJacob Faibussowitsch   CHKERRQ(SetupDiscretization(mesh,SetupProblem,&user));
454*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetSNESLocalFEM(mesh,&user,&user,&user));
455*5f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetFromOptions(snes));
456c4762a1bSJed Brown 
457c4762a1bSJed Brown   /* Grab field IS so that we can view the solution by field */
458*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateFieldIS(mesh,NULL,NULL,&fieldIS));
459c4762a1bSJed Brown 
460c4762a1bSJed Brown   /* Create a vector to store the SNES solution, solve the system and grab the
461c4762a1bSJed Brown    * solution from SNES */
462*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateGlobalVector(mesh,&computed));
463*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectSetName((PetscObject) computed,"computedSolution"));
464*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSet(computed,0.0));
465*5f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSolve(snes,NULL,computed));
466*5f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESGetSolution(snes,&computed));
467*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecViewFromOptions(computed,NULL,"-computedSolution_view"));
468c4762a1bSJed Brown 
469c4762a1bSJed Brown   /* Now we pull out the portion of the vector corresponding to the 3rd field
470c4762a1bSJed Brown    * which is the error between \div{u} computed in a higher dimensional space
471c4762a1bSJed Brown    * and p = \div{u} computed in a low dimension space. We report the L2 norm of
472c4762a1bSJed Brown    * this vector which should be zero if the H(div) spaces are implemented
473c4762a1bSJed Brown    * correctly. */
474*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetSubVector(computed,fieldIS[2],&divErr));
475*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecNorm(divErr,NORM_2,&divErrNorm));
476*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreSubVector(computed,fieldIS[2],&divErr));
477c4762a1bSJed Brown   exampleSuccess = (PetscBool)(divErrNorm <= errTol);
478c4762a1bSJed Brown 
479*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscPrintf(PETSC_COMM_WORLD,stdFormat,divErrNorm,exampleSuccess ? "true" : "false"));
480c4762a1bSJed Brown 
481c4762a1bSJed Brown   /* Tear down */
482*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&divErr));
483*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&computed));
484c4762a1bSJed Brown   for (i = 0; i < 3; ++i) {
485*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&fieldIS[i]));
486c4762a1bSJed Brown   }
487*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(fieldIS));
488*5f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESDestroy(&snes));
489*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&mesh));
490c4762a1bSJed Brown   ierr = PetscFinalize();
491c4762a1bSJed Brown   return ierr;
492c4762a1bSJed Brown }
493c4762a1bSJed Brown 
494c4762a1bSJed Brown /*TEST
495c4762a1bSJed Brown   testset:
496c4762a1bSJed Brown     suffix: 2d_bdm
497c4762a1bSJed Brown     requires: triangle
49830602db0SMatthew G. Knepley     args: -velocity_petscfe_default_quadrature_order 1 \
499c4762a1bSJed Brown       -velocity_petscspace_degree 1 \
500c4762a1bSJed Brown       -velocity_petscdualspace_type bdm \
501c4762a1bSJed Brown       -divErr_petscspace_degree 1 \
502c4762a1bSJed Brown       -divErr_petscdualspace_lagrange_continuity false \
503c4762a1bSJed Brown       -snes_error_if_not_converged \
504c4762a1bSJed Brown       -ksp_rtol 1e-10 \
505c4762a1bSJed Brown       -ksp_error_if_not_converged \
506c4762a1bSJed Brown       -pc_type fieldsplit\
507c4762a1bSJed Brown       -pc_fieldsplit_detect_saddle_point\
508c4762a1bSJed Brown       -pc_fieldsplit_type schur\
509c4762a1bSJed Brown       -pc_fieldsplit_schur_precondition full
510c4762a1bSJed Brown     test:
511c4762a1bSJed Brown       suffix: linear
512c4762a1bSJed Brown       args: -sol_form linear -mesh_transform none
513c4762a1bSJed Brown     test:
514c4762a1bSJed Brown       suffix: sinusoidal
515c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform none
516c4762a1bSJed Brown     test:
517c4762a1bSJed Brown       suffix: sinusoidal_skew
518c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform skew
519c4762a1bSJed Brown     test:
520c4762a1bSJed Brown       suffix: sinusoidal_perturb
521c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform perturb
522c4762a1bSJed Brown     test:
523c4762a1bSJed Brown       suffix: sinusoidal_skew_perturb
524c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform skew_perturb
525c4762a1bSJed Brown 
526c4762a1bSJed Brown   testset:
527c4762a1bSJed Brown     TODO: broken
528c4762a1bSJed Brown     suffix: 2d_bdmq
52930602db0SMatthew G. Knepley     args: -dm_plex_simplex false \
530c4762a1bSJed Brown       -velocity_petscspace_degree 1 \
531c4762a1bSJed Brown       -velocity_petscdualspace_type bdm \
532d092c84bSBrandon Whitchurch       -velocity_petscdualspace_lagrange_tensor 1 \
533c4762a1bSJed Brown       -divErr_petscspace_degree 1 \
534c4762a1bSJed Brown       -divErr_petscdualspace_lagrange_continuity false \
535c4762a1bSJed Brown       -snes_error_if_not_converged \
536c4762a1bSJed Brown       -ksp_rtol 1e-10 \
537c4762a1bSJed Brown       -ksp_error_if_not_converged \
538c4762a1bSJed Brown       -pc_type fieldsplit\
539c4762a1bSJed Brown       -pc_fieldsplit_detect_saddle_point\
540c4762a1bSJed Brown       -pc_fieldsplit_type schur\
541c4762a1bSJed Brown       -pc_fieldsplit_schur_precondition full
542c4762a1bSJed Brown     test:
543c4762a1bSJed Brown       suffix: linear
544c4762a1bSJed Brown       args: -sol_form linear -mesh_transform none
545c4762a1bSJed Brown     test:
546c4762a1bSJed Brown       suffix: sinusoidal
547c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform none
548c4762a1bSJed Brown     test:
549c4762a1bSJed Brown       suffix: sinusoidal_skew
550c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform skew
551c4762a1bSJed Brown     test:
552c4762a1bSJed Brown       suffix: sinusoidal_perturb
553c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform perturb
554c4762a1bSJed Brown     test:
555c4762a1bSJed Brown       suffix: sinusoidal_skew_perturb
556c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform skew_perturb
557c4762a1bSJed Brown 
558c4762a1bSJed Brown   testset:
559c4762a1bSJed Brown     suffix: 3d_bdm
560c4762a1bSJed Brown     requires: ctetgen
56130602db0SMatthew G. Knepley     args: -dm_plex_dim 3 \
562c4762a1bSJed Brown       -velocity_petscspace_degree 1 \
563c4762a1bSJed Brown       -velocity_petscdualspace_type bdm \
564c4762a1bSJed Brown       -divErr_petscspace_degree 1 \
565c4762a1bSJed Brown       -divErr_petscdualspace_lagrange_continuity false \
566c4762a1bSJed Brown       -snes_error_if_not_converged \
567c4762a1bSJed Brown       -ksp_rtol 1e-10 \
568c4762a1bSJed Brown       -ksp_error_if_not_converged \
569c4762a1bSJed Brown       -pc_type fieldsplit \
570c4762a1bSJed Brown       -pc_fieldsplit_detect_saddle_point \
571c4762a1bSJed Brown       -pc_fieldsplit_type schur \
572c4762a1bSJed Brown       -pc_fieldsplit_schur_precondition full
573c4762a1bSJed Brown     test:
574c4762a1bSJed Brown       suffix: linear
575c4762a1bSJed Brown       args: -sol_form linear -mesh_transform none
576c4762a1bSJed Brown     test:
577c4762a1bSJed Brown       suffix: sinusoidal
578c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform none
579c4762a1bSJed Brown     test:
580c4762a1bSJed Brown       suffix: sinusoidal_skew
581c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform skew
582c4762a1bSJed Brown     test:
583c4762a1bSJed Brown       suffix: sinusoidal_perturb
584c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform perturb
585c4762a1bSJed Brown     test:
586c4762a1bSJed Brown       suffix: sinusoidal_skew_perturb
587c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform skew_perturb
588c4762a1bSJed Brown 
589c4762a1bSJed Brown   testset:
590c4762a1bSJed Brown     TODO: broken
591c4762a1bSJed Brown     suffix: 3d_bdmq
592c4762a1bSJed Brown     requires: ctetgen
59330602db0SMatthew G. Knepley     args: -dm_plex_dim 3 \
59430602db0SMatthew G. Knepley       -dm_plex_simplex false \
595c4762a1bSJed Brown       -velocity_petscspace_degree 1 \
596c4762a1bSJed Brown       -velocity_petscdualspace_type bdm \
597d092c84bSBrandon Whitchurch       -velocity_petscdualspace_lagrange_tensor 1 \
598c4762a1bSJed Brown       -divErr_petscspace_degree 1 \
599c4762a1bSJed Brown       -divErr_petscdualspace_lagrange_continuity false \
600c4762a1bSJed Brown       -snes_error_if_not_converged \
601c4762a1bSJed Brown       -ksp_rtol 1e-10 \
602c4762a1bSJed Brown       -ksp_error_if_not_converged \
603c4762a1bSJed Brown       -pc_type fieldsplit \
604c4762a1bSJed Brown       -pc_fieldsplit_detect_saddle_point \
605c4762a1bSJed Brown       -pc_fieldsplit_type schur \
606c4762a1bSJed Brown       -pc_fieldsplit_schur_precondition full
607c4762a1bSJed Brown     test:
608c4762a1bSJed Brown       suffix: linear
609c4762a1bSJed Brown       args: -sol_form linear -mesh_transform none
610c4762a1bSJed Brown     test:
611c4762a1bSJed Brown       suffix: sinusoidal
612c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform none
613c4762a1bSJed Brown     test:
614c4762a1bSJed Brown       suffix: sinusoidal_skew
615c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform skew
616c4762a1bSJed Brown     test:
617c4762a1bSJed Brown       suffix: sinusoidal_perturb
618c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform perturb
619c4762a1bSJed Brown     test:
620c4762a1bSJed Brown       suffix: sinusoidal_skew_perturb
621c4762a1bSJed Brown       args: -sol_form sinusoidal -mesh_transform skew_perturb
622d092c84bSBrandon Whitchurch 
623d092c84bSBrandon Whitchurch   test:
624d092c84bSBrandon Whitchurch     suffix: quad_rt_0
62530602db0SMatthew G. Knepley     args: -dm_plex_simplex false -mesh_transform skew \
626d092c84bSBrandon Whitchurch           -divErr_petscspace_degree 1 \
627d092c84bSBrandon Whitchurch           -divErr_petscdualspace_lagrange_continuity false \
628d092c84bSBrandon Whitchurch           -snes_error_if_not_converged \
629d092c84bSBrandon Whitchurch           -ksp_rtol 1e-10 \
630d092c84bSBrandon Whitchurch           -ksp_error_if_not_converged \
631d092c84bSBrandon Whitchurch           -pc_type fieldsplit\
632d092c84bSBrandon Whitchurch           -pc_fieldsplit_detect_saddle_point\
633d092c84bSBrandon Whitchurch           -pc_fieldsplit_type schur\
634d092c84bSBrandon Whitchurch           -pc_fieldsplit_schur_precondition full \
635d092c84bSBrandon Whitchurch           -velocity_petscfe_default_quadrature_order 1 \
636d092c84bSBrandon Whitchurch           -velocity_petscspace_type sum \
637d092c84bSBrandon Whitchurch           -velocity_petscspace_variables 2 \
638d092c84bSBrandon Whitchurch           -velocity_petscspace_components 2 \
639d092c84bSBrandon Whitchurch           -velocity_petscspace_sum_spaces 2 \
640d092c84bSBrandon Whitchurch           -velocity_petscspace_sum_concatenate true \
641417c287bSToby Isaac           -velocity_sumcomp_0_petscspace_variables 2 \
642417c287bSToby Isaac           -velocity_sumcomp_0_petscspace_type tensor \
643417c287bSToby Isaac           -velocity_sumcomp_0_petscspace_tensor_spaces 2 \
644417c287bSToby Isaac           -velocity_sumcomp_0_petscspace_tensor_uniform false \
645417c287bSToby Isaac           -velocity_sumcomp_0_tensorcomp_0_petscspace_degree 1 \
646417c287bSToby Isaac           -velocity_sumcomp_0_tensorcomp_1_petscspace_degree 0 \
647417c287bSToby Isaac           -velocity_sumcomp_1_petscspace_variables 2 \
648417c287bSToby Isaac           -velocity_sumcomp_1_petscspace_type tensor \
649417c287bSToby Isaac           -velocity_sumcomp_1_petscspace_tensor_spaces 2 \
650417c287bSToby Isaac           -velocity_sumcomp_1_petscspace_tensor_uniform false \
651417c287bSToby Isaac           -velocity_sumcomp_1_tensorcomp_0_petscspace_degree 0 \
652417c287bSToby Isaac           -velocity_sumcomp_1_tensorcomp_1_petscspace_degree 1 \
653d092c84bSBrandon Whitchurch           -velocity_petscdualspace_form_degree -1 \
654d092c84bSBrandon Whitchurch           -velocity_petscdualspace_order 1 \
655d092c84bSBrandon Whitchurch           -velocity_petscdualspace_lagrange_trimmed true
656c4762a1bSJed Brown TEST*/
657