xref: /petsc/src/snes/tutorials/ex19.c (revision 1bb3edfd3d106a9ce6e99783e45c9200c8e18d90)
1 
2 static char help[] = "Nonlinear driven cavity with multigrid in 2d.\n \
3   \n\
4 The 2D driven cavity problem is solved in a velocity-vorticity formulation.\n\
5 The flow can be driven with the lid or with bouyancy or both:\n\
6   -lidvelocity &ltlid&gt, where &ltlid&gt = dimensionless velocity of lid\n\
7   -grashof &ltgr&gt, where &ltgr&gt = dimensionless temperature gradent\n\
8   -prandtl &ltpr&gt, where &ltpr&gt = dimensionless thermal/momentum diffusity ratio\n\
9  -contours : draw contour plots of solution\n\n";
10 /* in HTML, '&lt' = '<' and '&gt' = '>' */
11 
12 /*
13       See src/ksp/ksp/tutorials/ex45.c
14 */
15 
16 /*F-----------------------------------------------------------------------
17 
18     We thank David E. Keyes for contributing the driven cavity discretization within this example code.
19 
20     This problem is modeled by the partial differential equation system
21 
22 \begin{eqnarray}
23         - \triangle U - \nabla_y \Omega & = & 0  \\
24         - \triangle V + \nabla_x\Omega & = & 0  \\
25         - \triangle \Omega + \nabla \cdot ([U*\Omega,V*\Omega]) - GR* \nabla_x T & = & 0  \\
26         - \triangle T + PR* \nabla \cdot ([U*T,V*T]) & = & 0
27 \end{eqnarray}
28 
29     in the unit square, which is uniformly discretized in each of x and y in this simple encoding.
30 
31     No-slip, rigid-wall Dirichlet conditions are used for $ [U,V]$.
32     Dirichlet conditions are used for Omega, based on the definition of
33     vorticity: $ \Omega = - \nabla_y U + \nabla_x V$, where along each
34     constant coordinate boundary, the tangential derivative is zero.
35     Dirichlet conditions are used for T on the left and right walls,
36     and insulation homogeneous Neumann conditions are used for T on
37     the top and bottom walls.
38 
39     A finite difference approximation with the usual 5-point stencil
40     is used to discretize the boundary value problem to obtain a
41     nonlinear system of equations.  Upwinding is used for the divergence
42     (convective) terms and central for the gradient (source) terms.
43 
44     The Jacobian can be either
45       * formed via finite differencing using coloring (the default), or
46       * applied matrix-free via the option -snes_mf
47         (for larger grid problems this variant may not converge
48         without a preconditioner due to ill-conditioning).
49 
50   ------------------------------------------------------------------------F*/
51 
52 /*
53    Include "petscdmda.h" so that we can use distributed arrays (DMDAs).
54    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
55    file automatically includes:
56      petscsys.h       - base PETSc routines   petscvec.h - vectors
57      petscmat.h - matrices
58      petscis.h     - index sets            petscksp.h - Krylov subspace methods
59      petscviewer.h - viewers               petscpc.h  - preconditioners
60      petscksp.h   - linear solvers
61 */
62 #if defined(PETSC_APPLE_FRAMEWORK)
63 #import <PETSc/petscsnes.h>
64 #import <PETSc/petscdmda.h>
65 #else
66 #include <petscsnes.h>
67 #include <petscdm.h>
68 #include <petscdmda.h>
69 #endif
70 
71 /*
72    User-defined routines and data structures
73 */
74 typedef struct {
75   PetscScalar u,v,omega,temp;
76 } Field;
77 
78 PetscErrorCode FormFunctionLocal(DMDALocalInfo*,Field**,Field**,void*);
79 
80 typedef struct {
81   PetscReal   lidvelocity,prandtl,grashof;  /* physical parameters */
82   PetscBool   draw_contours;                /* flag - 1 indicates drawing contours */
83 } AppCtx;
84 
85 extern PetscErrorCode FormInitialGuess(AppCtx*,DM,Vec);
86 extern PetscErrorCode NonlinearGS(SNES,Vec,Vec,void*);
87 
88 int main(int argc,char **argv)
89 {
90   AppCtx         user;                /* user-defined work context */
91   PetscInt       mx,my,its;
92   MPI_Comm       comm;
93   SNES           snes;
94   DM             da;
95   Vec            x;
96 
97   PetscCall(PetscInitialize(&argc,&argv,(char*)0,help));
98 
99   PetscFunctionBeginUser;
100   comm = PETSC_COMM_WORLD;
101   PetscCall(SNESCreate(comm,&snes));
102 
103   /*
104       Create distributed array object to manage parallel grid and vectors
105       for principal unknowns (x) and governing residuals (f)
106   */
107   PetscCall(DMDACreate2d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,DM_BOUNDARY_NONE,DMDA_STENCIL_STAR,4,4,PETSC_DECIDE,PETSC_DECIDE,4,1,0,0,&da));
108   PetscCall(DMSetFromOptions(da));
109   PetscCall(DMSetUp(da));
110   PetscCall(SNESSetDM(snes,(DM)da));
111   PetscCall(SNESSetNGS(snes, NonlinearGS, (void*)&user));
112 
113   PetscCall(DMDAGetInfo(da,0,&mx,&my,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE));
114   /*
115      Problem parameters (velocity of lid, prandtl, and grashof numbers)
116   */
117   user.lidvelocity = 1.0/(mx*my);
118   user.prandtl     = 1.0;
119   user.grashof     = 1.0;
120 
121   PetscCall(PetscOptionsGetReal(NULL,NULL,"-lidvelocity",&user.lidvelocity,NULL));
122   PetscCall(PetscOptionsGetReal(NULL,NULL,"-prandtl",&user.prandtl,NULL));
123   PetscCall(PetscOptionsGetReal(NULL,NULL,"-grashof",&user.grashof,NULL));
124   PetscCall(PetscOptionsHasName(NULL,NULL,"-contours",&user.draw_contours));
125 
126   PetscCall(DMDASetFieldName(da,0,"x_velocity"));
127   PetscCall(DMDASetFieldName(da,1,"y_velocity"));
128   PetscCall(DMDASetFieldName(da,2,"Omega"));
129   PetscCall(DMDASetFieldName(da,3,"temperature"));
130 
131   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
132      Create user context, set problem data, create vector data structures.
133      Also, compute the initial guess.
134      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
135 
136   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
137      Create nonlinear solver context
138 
139      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
140   PetscCall(DMSetApplicationContext(da,&user));
141   PetscCall(DMDASNESSetFunctionLocal(da,INSERT_VALUES,(PetscErrorCode (*)(DMDALocalInfo*,void*,void*,void*))FormFunctionLocal,&user));
142   PetscCall(SNESSetFromOptions(snes));
143   PetscCall(PetscPrintf(comm,"lid velocity = %g, prandtl # = %g, grashof # = %g\n",(double)user.lidvelocity,(double)user.prandtl,(double)user.grashof));
144 
145   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
146      Solve the nonlinear system
147      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
148   PetscCall(DMCreateGlobalVector(da,&x));
149   PetscCall(FormInitialGuess(&user,da,x));
150 
151   PetscCall(SNESSolve(snes,NULL,x));
152 
153   PetscCall(SNESGetIterationNumber(snes,&its));
154   PetscCall(PetscPrintf(comm,"Number of SNES iterations = %D\n", its));
155 
156   /*
157      Visualize solution
158   */
159   if (user.draw_contours) {
160     PetscCall(VecView(x,PETSC_VIEWER_DRAW_WORLD));
161   }
162 
163   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
164      Free work space.  All PETSc objects should be destroyed when they
165      are no longer needed.
166      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
167   PetscCall(VecDestroy(&x));
168   PetscCall(DMDestroy(&da));
169   PetscCall(SNESDestroy(&snes));
170   PetscCall(PetscFinalize());
171   return 0;
172 }
173 
174 /* ------------------------------------------------------------------- */
175 
176 /*
177    FormInitialGuess - Forms initial approximation.
178 
179    Input Parameters:
180    user - user-defined application context
181    X - vector
182 
183    Output Parameter:
184    X - vector
185 */
186 PetscErrorCode FormInitialGuess(AppCtx *user,DM da,Vec X)
187 {
188   PetscInt       i,j,mx,xs,ys,xm,ym;
189   PetscReal      grashof,dx;
190   Field          **x;
191 
192   PetscFunctionBeginUser;
193   grashof = user->grashof;
194 
195   PetscCall(DMDAGetInfo(da,0,&mx,0,0,0,0,0,0,0,0,0,0,0));
196   dx   = 1.0/(mx-1);
197 
198   /*
199      Get local grid boundaries (for 2-dimensional DMDA):
200        xs, ys   - starting grid indices (no ghost points)
201        xm, ym   - widths of local grid (no ghost points)
202   */
203   PetscCall(DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL));
204 
205   /*
206      Get a pointer to vector data.
207        - For default PETSc vectors, VecGetArray() returns a pointer to
208          the data array.  Otherwise, the routine is implementation dependent.
209        - You MUST call VecRestoreArray() when you no longer need access to
210          the array.
211   */
212   PetscCall(DMDAVecGetArrayWrite(da,X,&x));
213 
214   /*
215      Compute initial guess over the locally owned part of the grid
216      Initial condition is motionless fluid and equilibrium temperature
217   */
218   for (j=ys; j<ys+ym; j++) {
219     for (i=xs; i<xs+xm; i++) {
220       x[j][i].u     = 0.0;
221       x[j][i].v     = 0.0;
222       x[j][i].omega = 0.0;
223       x[j][i].temp  = (grashof>0)*i*dx;
224     }
225   }
226 
227   /*
228      Restore vector
229   */
230   PetscCall(DMDAVecRestoreArrayWrite(da,X,&x));
231   PetscFunctionReturn(0);
232 }
233 
234 PetscErrorCode FormFunctionLocal(DMDALocalInfo *info,Field **x,Field **f,void *ptr)
235 {
236   AppCtx         *user = (AppCtx*)ptr;
237   PetscInt       xints,xinte,yints,yinte,i,j;
238   PetscReal      hx,hy,dhx,dhy,hxdhy,hydhx;
239   PetscReal      grashof,prandtl,lid;
240   PetscScalar    u,uxx,uyy,vx,vy,avx,avy,vxp,vxm,vyp,vym;
241 
242   PetscFunctionBeginUser;
243   grashof = user->grashof;
244   prandtl = user->prandtl;
245   lid     = user->lidvelocity;
246 
247   /*
248      Define mesh intervals ratios for uniform grid.
249 
250      Note: FD formulae below are normalized by multiplying through by
251      local volume element (i.e. hx*hy) to obtain coefficients O(1) in two dimensions.
252 
253   */
254   dhx   = (PetscReal)(info->mx-1);  dhy = (PetscReal)(info->my-1);
255   hx    = 1.0/dhx;                   hy = 1.0/dhy;
256   hxdhy = hx*dhy;                 hydhx = hy*dhx;
257 
258   xints = info->xs; xinte = info->xs+info->xm; yints = info->ys; yinte = info->ys+info->ym;
259 
260   /* Test whether we are on the bottom edge of the global array */
261   if (yints == 0) {
262     j     = 0;
263     yints = yints + 1;
264     /* bottom edge */
265     for (i=info->xs; i<info->xs+info->xm; i++) {
266       f[j][i].u     = x[j][i].u;
267       f[j][i].v     = x[j][i].v;
268       f[j][i].omega = x[j][i].omega + (x[j+1][i].u - x[j][i].u)*dhy;
269       f[j][i].temp  = x[j][i].temp-x[j+1][i].temp;
270     }
271   }
272 
273   /* Test whether we are on the top edge of the global array */
274   if (yinte == info->my) {
275     j     = info->my - 1;
276     yinte = yinte - 1;
277     /* top edge */
278     for (i=info->xs; i<info->xs+info->xm; i++) {
279       f[j][i].u     = x[j][i].u - lid;
280       f[j][i].v     = x[j][i].v;
281       f[j][i].omega = x[j][i].omega + (x[j][i].u - x[j-1][i].u)*dhy;
282       f[j][i].temp  = x[j][i].temp-x[j-1][i].temp;
283     }
284   }
285 
286   /* Test whether we are on the left edge of the global array */
287   if (xints == 0) {
288     i     = 0;
289     xints = xints + 1;
290     /* left edge */
291     for (j=info->ys; j<info->ys+info->ym; j++) {
292       f[j][i].u     = x[j][i].u;
293       f[j][i].v     = x[j][i].v;
294       f[j][i].omega = x[j][i].omega - (x[j][i+1].v - x[j][i].v)*dhx;
295       f[j][i].temp  = x[j][i].temp;
296     }
297   }
298 
299   /* Test whether we are on the right edge of the global array */
300   if (xinte == info->mx) {
301     i     = info->mx - 1;
302     xinte = xinte - 1;
303     /* right edge */
304     for (j=info->ys; j<info->ys+info->ym; j++) {
305       f[j][i].u     = x[j][i].u;
306       f[j][i].v     = x[j][i].v;
307       f[j][i].omega = x[j][i].omega - (x[j][i].v - x[j][i-1].v)*dhx;
308       f[j][i].temp  = x[j][i].temp - (PetscReal)(grashof>0);
309     }
310   }
311 
312   /* Compute over the interior points */
313   for (j=yints; j<yinte; j++) {
314     for (i=xints; i<xinte; i++) {
315 
316       /*
317        convective coefficients for upwinding
318       */
319       vx  = x[j][i].u; avx = PetscAbsScalar(vx);
320       vxp = .5*(vx+avx); vxm = .5*(vx-avx);
321       vy  = x[j][i].v; avy = PetscAbsScalar(vy);
322       vyp = .5*(vy+avy); vym = .5*(vy-avy);
323 
324       /* U velocity */
325       u         = x[j][i].u;
326       uxx       = (2.0*u - x[j][i-1].u - x[j][i+1].u)*hydhx;
327       uyy       = (2.0*u - x[j-1][i].u - x[j+1][i].u)*hxdhy;
328       f[j][i].u = uxx + uyy - .5*(x[j+1][i].omega-x[j-1][i].omega)*hx;
329 
330       /* V velocity */
331       u         = x[j][i].v;
332       uxx       = (2.0*u - x[j][i-1].v - x[j][i+1].v)*hydhx;
333       uyy       = (2.0*u - x[j-1][i].v - x[j+1][i].v)*hxdhy;
334       f[j][i].v = uxx + uyy + .5*(x[j][i+1].omega-x[j][i-1].omega)*hy;
335 
336       /* Omega */
337       u             = x[j][i].omega;
338       uxx           = (2.0*u - x[j][i-1].omega - x[j][i+1].omega)*hydhx;
339       uyy           = (2.0*u - x[j-1][i].omega - x[j+1][i].omega)*hxdhy;
340       f[j][i].omega = uxx + uyy + (vxp*(u - x[j][i-1].omega) + vxm*(x[j][i+1].omega - u))*hy +
341                       (vyp*(u - x[j-1][i].omega) + vym*(x[j+1][i].omega - u))*hx -
342                       .5*grashof*(x[j][i+1].temp - x[j][i-1].temp)*hy;
343 
344       /* Temperature */
345       u            = x[j][i].temp;
346       uxx          = (2.0*u - x[j][i-1].temp - x[j][i+1].temp)*hydhx;
347       uyy          = (2.0*u - x[j-1][i].temp - x[j+1][i].temp)*hxdhy;
348       f[j][i].temp =  uxx + uyy  + prandtl*((vxp*(u - x[j][i-1].temp) + vxm*(x[j][i+1].temp - u))*hy +
349                                             (vyp*(u - x[j-1][i].temp) + vym*(x[j+1][i].temp - u))*hx);
350     }
351   }
352 
353   /*
354      Flop count (multiply-adds are counted as 2 operations)
355   */
356   PetscCall(PetscLogFlops(84.0*info->ym*info->xm));
357   PetscFunctionReturn(0);
358 }
359 
360 /*
361     Performs sweeps of point block nonlinear Gauss-Seidel on all the local grid points
362 */
363 PetscErrorCode NonlinearGS(SNES snes, Vec X, Vec B, void *ctx)
364 {
365   DMDALocalInfo  info;
366   Field          **x,**b;
367   Vec            localX, localB;
368   DM             da;
369   PetscInt       xints,xinte,yints,yinte,i,j,k,l;
370   PetscInt       max_its,tot_its;
371   PetscInt       sweeps;
372   PetscReal      rtol,atol,stol;
373   PetscReal      hx,hy,dhx,dhy,hxdhy,hydhx;
374   PetscReal      grashof,prandtl,lid;
375   PetscScalar    u,uxx,uyy,vx,vy,avx,avy,vxp,vxm,vyp,vym;
376   PetscScalar    fu, fv, fomega, ftemp;
377   PetscScalar    dfudu;
378   PetscScalar    dfvdv;
379   PetscScalar    dfodu, dfodv, dfodo;
380   PetscScalar    dftdu, dftdv, dftdt;
381   PetscScalar    yu=0, yv=0, yo=0, yt=0;
382   PetscScalar    bjiu, bjiv, bjiomega, bjitemp;
383   PetscBool      ptconverged;
384   PetscReal      pfnorm,pfnorm0,pynorm,pxnorm;
385   AppCtx         *user = (AppCtx*)ctx;
386 
387   PetscFunctionBeginUser;
388   grashof = user->grashof;
389   prandtl = user->prandtl;
390   lid     = user->lidvelocity;
391   tot_its = 0;
392   PetscCall(SNESNGSGetTolerances(snes,&rtol,&atol,&stol,&max_its));
393   PetscCall(SNESNGSGetSweeps(snes,&sweeps));
394   PetscCall(SNESGetDM(snes,(DM*)&da));
395   PetscCall(DMGetLocalVector(da,&localX));
396   if (B) {
397     PetscCall(DMGetLocalVector(da,&localB));
398   }
399   /*
400      Scatter ghost points to local vector, using the 2-step process
401         DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
402   */
403   PetscCall(DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX));
404   PetscCall(DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX));
405   if (B) {
406     PetscCall(DMGlobalToLocalBegin(da,B,INSERT_VALUES,localB));
407     PetscCall(DMGlobalToLocalEnd(da,B,INSERT_VALUES,localB));
408   }
409   PetscCall(DMDAGetLocalInfo(da,&info));
410   PetscCall(DMDAVecGetArrayWrite(da,localX,&x));
411   if (B) {
412     PetscCall(DMDAVecGetArrayRead(da,localB,&b));
413   }
414   /* looks like a combination of the formfunction / formjacobian routines */
415   dhx   = (PetscReal)(info.mx-1);dhy   = (PetscReal)(info.my-1);
416   hx    = 1.0/dhx;               hy    = 1.0/dhy;
417   hxdhy = hx*dhy;                hydhx = hy*dhx;
418 
419   xints = info.xs; xinte = info.xs+info.xm; yints = info.ys; yinte = info.ys+info.ym;
420 
421   /* Set the boundary conditions on the momentum equations */
422   /* Test whether we are on the bottom edge of the global array */
423   if (yints == 0) {
424     j     = 0;
425     /* bottom edge */
426     for (i=info.xs; i<info.xs+info.xm; i++) {
427 
428       if (B) {
429         bjiu = b[j][i].u;
430         bjiv = b[j][i].v;
431       } else {
432         bjiu = 0.0;
433         bjiv = 0.0;
434       }
435       x[j][i].u = 0.0 + bjiu;
436       x[j][i].v = 0.0 + bjiv;
437     }
438   }
439 
440   /* Test whether we are on the top edge of the global array */
441   if (yinte == info.my) {
442     j     = info.my - 1;
443     /* top edge */
444     for (i=info.xs; i<info.xs+info.xm; i++) {
445       if (B) {
446         bjiu = b[j][i].u;
447         bjiv = b[j][i].v;
448       } else {
449         bjiu = 0.0;
450         bjiv = 0.0;
451       }
452       x[j][i].u = lid + bjiu;
453       x[j][i].v = bjiv;
454     }
455   }
456 
457   /* Test whether we are on the left edge of the global array */
458   if (xints == 0) {
459     i     = 0;
460     /* left edge */
461     for (j=info.ys; j<info.ys+info.ym; j++) {
462       if (B) {
463         bjiu = b[j][i].u;
464         bjiv = b[j][i].v;
465       } else {
466         bjiu = 0.0;
467         bjiv = 0.0;
468       }
469       x[j][i].u = 0.0 + bjiu;
470       x[j][i].v = 0.0 + bjiv;
471     }
472   }
473 
474   /* Test whether we are on the right edge of the global array */
475   if (xinte == info.mx) {
476     i     = info.mx - 1;
477     /* right edge */
478     for (j=info.ys; j<info.ys+info.ym; j++) {
479       if (B) {
480         bjiu = b[j][i].u;
481         bjiv = b[j][i].v;
482       } else {
483         bjiu = 0.0;
484         bjiv = 0.0;
485       }
486       x[j][i].u = 0.0 + bjiu;
487       x[j][i].v = 0.0 + bjiv;
488     }
489   }
490 
491   for (k=0; k < sweeps; k++) {
492     for (j=info.ys; j<info.ys + info.ym; j++) {
493       for (i=info.xs; i<info.xs + info.xm; i++) {
494         ptconverged = PETSC_FALSE;
495         pfnorm0     = 0.0;
496         fu          = 0.0;
497         fv          = 0.0;
498         fomega      = 0.0;
499         ftemp       = 0.0;
500         /*  Run Newton's method on a single grid point */
501         for (l = 0; l < max_its && !ptconverged; l++) {
502           if (B) {
503             bjiu     = b[j][i].u;
504             bjiv     = b[j][i].v;
505             bjiomega = b[j][i].omega;
506             bjitemp  = b[j][i].temp;
507           } else {
508             bjiu     = 0.0;
509             bjiv     = 0.0;
510             bjiomega = 0.0;
511             bjitemp  = 0.0;
512           }
513 
514           if (i != 0 && i != info.mx - 1 && j != 0 && j != info.my-1) {
515             /* U velocity */
516             u     = x[j][i].u;
517             uxx   = (2.0*u - x[j][i-1].u - x[j][i+1].u)*hydhx;
518             uyy   = (2.0*u - x[j-1][i].u - x[j+1][i].u)*hxdhy;
519             fu    = uxx + uyy - .5*(x[j+1][i].omega-x[j-1][i].omega)*hx - bjiu;
520             dfudu = 2.0*(hydhx + hxdhy);
521             /* V velocity */
522             u     = x[j][i].v;
523             uxx   = (2.0*u - x[j][i-1].v - x[j][i+1].v)*hydhx;
524             uyy   = (2.0*u - x[j-1][i].v - x[j+1][i].v)*hxdhy;
525             fv    = uxx + uyy + .5*(x[j][i+1].omega-x[j][i-1].omega)*hy - bjiv;
526             dfvdv = 2.0*(hydhx + hxdhy);
527             /*
528              convective coefficients for upwinding
529              */
530             vx  = x[j][i].u; avx = PetscAbsScalar(vx);
531             vxp = .5*(vx+avx); vxm = .5*(vx-avx);
532             vy  = x[j][i].v; avy = PetscAbsScalar(vy);
533             vyp = .5*(vy+avy); vym = .5*(vy-avy);
534             /* Omega */
535             u      = x[j][i].omega;
536             uxx    = (2.0*u - x[j][i-1].omega - x[j][i+1].omega)*hydhx;
537             uyy    = (2.0*u - x[j-1][i].omega - x[j+1][i].omega)*hxdhy;
538             fomega = uxx + uyy +  (vxp*(u - x[j][i-1].omega) + vxm*(x[j][i+1].omega - u))*hy +
539                      (vyp*(u - x[j-1][i].omega) + vym*(x[j+1][i].omega - u))*hx -
540                      .5*grashof*(x[j][i+1].temp - x[j][i-1].temp)*hy - bjiomega;
541             /* convective coefficient derivatives */
542             dfodo = 2.0*(hydhx + hxdhy) + ((vxp - vxm)*hy + (vyp - vym)*hx);
543             if (PetscRealPart(vx) > 0.0) dfodu = (u - x[j][i-1].omega)*hy;
544             else dfodu = (x[j][i+1].omega - u)*hy;
545 
546             if (PetscRealPart(vy) > 0.0) dfodv = (u - x[j-1][i].omega)*hx;
547             else dfodv = (x[j+1][i].omega - u)*hx;
548 
549             /* Temperature */
550             u     = x[j][i].temp;
551             uxx   = (2.0*u - x[j][i-1].temp - x[j][i+1].temp)*hydhx;
552             uyy   = (2.0*u - x[j-1][i].temp - x[j+1][i].temp)*hxdhy;
553             ftemp =  uxx + uyy  + prandtl*((vxp*(u - x[j][i-1].temp) + vxm*(x[j][i+1].temp - u))*hy + (vyp*(u - x[j-1][i].temp) + vym*(x[j+1][i].temp - u))*hx) - bjitemp;
554             dftdt = 2.0*(hydhx + hxdhy) + prandtl*((vxp - vxm)*hy + (vyp - vym)*hx);
555             if (PetscRealPart(vx) > 0.0) dftdu = prandtl*(u - x[j][i-1].temp)*hy;
556             else dftdu = prandtl*(x[j][i+1].temp - u)*hy;
557 
558             if (PetscRealPart(vy) > 0.0) dftdv = prandtl*(u - x[j-1][i].temp)*hx;
559             else dftdv = prandtl*(x[j+1][i].temp - u)*hx;
560 
561             /* invert the system:
562              [ dfu / du     0        0        0    ][yu] = [fu]
563              [     0    dfv / dv     0        0    ][yv]   [fv]
564              [ dfo / du dfo / dv dfo / do     0    ][yo]   [fo]
565              [ dft / du dft / dv     0    dft / dt ][yt]   [ft]
566              by simple back-substitution
567            */
568             yu = fu / dfudu;
569             yv = fv / dfvdv;
570             yo = (fomega - (dfodu*yu + dfodv*yv)) / dfodo;
571             yt = (ftemp - (dftdu*yu + dftdv*yv)) / dftdt;
572 
573             x[j][i].u     = x[j][i].u - yu;
574             x[j][i].v     = x[j][i].v - yv;
575             x[j][i].temp  = x[j][i].temp - yt;
576             x[j][i].omega = x[j][i].omega - yo;
577           }
578           if (i == 0) {
579             fomega        = x[j][i].omega - (x[j][i+1].v - x[j][i].v)*dhx - bjiomega;
580             ftemp         = x[j][i].temp - bjitemp;
581             yo            = fomega;
582             yt            = ftemp;
583             x[j][i].omega = x[j][i].omega - fomega;
584             x[j][i].temp  = x[j][i].temp - ftemp;
585           }
586           if (i == info.mx - 1) {
587             fomega        = x[j][i].omega - (x[j][i].v - x[j][i-1].v)*dhx - bjiomega;
588             ftemp         = x[j][i].temp - (PetscReal)(grashof>0) - bjitemp;
589             yo            = fomega;
590             yt            = ftemp;
591             x[j][i].omega = x[j][i].omega - fomega;
592             x[j][i].temp  = x[j][i].temp - ftemp;
593           }
594           if (j == 0) {
595             fomega        = x[j][i].omega + (x[j+1][i].u - x[j][i].u)*dhy - bjiomega;
596             ftemp         = x[j][i].temp-x[j+1][i].temp - bjitemp;
597             yo            = fomega;
598             yt            = ftemp;
599             x[j][i].omega = x[j][i].omega - fomega;
600             x[j][i].temp  = x[j][i].temp - ftemp;
601           }
602           if (j == info.my - 1) {
603             fomega        = x[j][i].omega + (x[j][i].u - x[j-1][i].u)*dhy - bjiomega;
604             ftemp         = x[j][i].temp-x[j-1][i].temp - bjitemp;
605             yo            = fomega;
606             yt            = ftemp;
607             x[j][i].omega = x[j][i].omega - fomega;
608             x[j][i].temp  = x[j][i].temp - ftemp;
609           }
610           tot_its++;
611           pfnorm = PetscRealPart(fu*fu + fv*fv + fomega*fomega + ftemp*ftemp);
612           pfnorm = PetscSqrtReal(pfnorm);
613           pynorm = PetscRealPart(yu*yu + yv*yv + yo*yo + yt*yt);
614           pynorm = PetscSqrtReal(pynorm);
615           pxnorm = PetscRealPart(x[j][i].u*x[j][i].u + x[j][i].v*x[j][i].v + x[j][i].omega*x[j][i].omega + x[j][i].temp*x[j][i].temp);
616           pxnorm = PetscSqrtReal(pxnorm);
617           if (l == 0) pfnorm0 = pfnorm;
618           if (rtol*pfnorm0 >pfnorm || atol > pfnorm || pxnorm*stol > pynorm) ptconverged = PETSC_TRUE;
619         }
620       }
621     }
622   }
623   PetscCall(DMDAVecRestoreArrayWrite(da,localX,&x));
624   if (B) {
625     PetscCall(DMDAVecRestoreArrayRead(da,localB,&b));
626   }
627   PetscCall(DMLocalToGlobalBegin(da,localX,INSERT_VALUES,X));
628   PetscCall(DMLocalToGlobalEnd(da,localX,INSERT_VALUES,X));
629   PetscCall(PetscLogFlops(tot_its*(84.0 + 41.0 + 26.0)));
630   PetscCall(DMRestoreLocalVector(da,&localX));
631   if (B) {
632     PetscCall(DMRestoreLocalVector(da,&localB));
633   }
634   PetscFunctionReturn(0);
635 }
636 
637 /*TEST
638 
639    test:
640       nsize: 2
641       args: -da_refine 3 -snes_monitor_short -pc_type mg -ksp_type fgmres -pc_mg_type full
642       requires: !single
643 
644    test:
645       suffix: 10
646       nsize: 3
647       args: -snes_monitor_short -ksp_monitor_short -pc_type fieldsplit -pc_fieldsplit_type symmetric_multiplicative -snes_view -da_refine 1 -ksp_type fgmres
648       requires: !single
649 
650    test:
651       suffix: 11
652       nsize: 4
653       requires: pastix
654       args: -snes_monitor_short -pc_type redundant -dm_mat_type mpiaij -redundant_pc_factor_mat_solver_type pastix -pc_redundant_number 2 -da_refine 4 -ksp_type fgmres
655 
656    test:
657       suffix: 12
658       nsize: 12
659       requires: pastix
660       args: -snes_monitor_short -pc_type redundant -dm_mat_type mpiaij -redundant_pc_factor_mat_solver_type pastix -pc_redundant_number 5 -da_refine 4 -ksp_type fgmres
661 
662    test:
663       suffix: 13
664       nsize: 3
665       args: -snes_monitor_short -ksp_monitor_short -pc_type fieldsplit -pc_fieldsplit_type multiplicative -snes_view -da_refine 1 -ksp_type fgmres -snes_mf_operator
666       requires: !single
667 
668    test:
669       suffix: 14
670       nsize: 4
671       args: -snes_monitor_short -pc_type mg -dm_mat_type baij -mg_coarse_pc_type bjacobi -da_refine 3 -ksp_type fgmres
672       requires: !single
673 
674    test:
675       suffix: 14_ds
676       nsize: 4
677       args: -snes_converged_reason -pc_type mg -dm_mat_type baij -mg_coarse_pc_type bjacobi -da_refine 3 -ksp_type fgmres -mat_fd_type ds
678       output_file: output/ex19_2.out
679       requires: !single
680 
681    test:
682       suffix: 17
683       args: -snes_monitor_short -ksp_pc_side right
684       requires: !single
685 
686    test:
687       suffix: 18
688       args: -snes_monitor_ksp draw::draw_lg -ksp_pc_side right
689       requires: x !single
690 
691    test:
692       suffix: 19
693       nsize: 2
694       args: -da_refine 3 -snes_monitor_short -pc_type mg -ksp_type fgmres -pc_mg_type full -snes_type newtontrdc
695       requires: !single
696 
697    test:
698       suffix: 20
699       nsize: 2
700       args: -da_refine 3 -snes_monitor_short -pc_type mg -ksp_type fgmres -pc_mg_type full -snes_type newtontrdc -snes_trdc_use_cauchy false
701       requires: !single
702 
703    test:
704       suffix: 2
705       nsize: 4
706       args: -da_refine 3 -snes_converged_reason -pc_type mg -mat_fd_type ds
707       requires: !single
708 
709    test:
710       suffix: 2_bcols1
711       nsize: 4
712       args: -da_refine 3 -snes_converged_reason -pc_type mg -mat_fd_type ds -mat_fd_coloring_bcols
713       output_file: output/ex19_2.out
714       requires: !single
715 
716    test:
717       suffix: 3
718       nsize: 4
719       requires: mumps
720       args: -da_refine 3 -snes_monitor_short -pc_type redundant -dm_mat_type mpiaij -redundant_ksp_type preonly -redundant_pc_factor_mat_solver_type mumps -pc_redundant_number 2
721 
722    test:
723       suffix: 4
724       nsize: 12
725       requires: mumps
726       args: -da_refine 3 -snes_monitor_short -pc_type redundant -dm_mat_type mpiaij -redundant_ksp_type preonly -redundant_pc_factor_mat_solver_type mumps -pc_redundant_number 5
727       output_file: output/ex19_3.out
728 
729    test:
730       suffix: 6
731       args: -snes_monitor_short -ksp_monitor_short -pc_type fieldsplit -snes_view -ksp_type fgmres -da_refine 1
732       requires: !single
733 
734    test:
735       suffix: 7
736       nsize: 3
737       args: -snes_monitor_short -ksp_monitor_short -pc_type fieldsplit -snes_view -da_refine 1 -ksp_type fgmres
738 
739       requires: !single
740    test:
741       suffix: 8
742       args: -snes_monitor_short -ksp_monitor_short -pc_type fieldsplit -pc_fieldsplit_block_size 2 -pc_fieldsplit_0_fields 0,1 -pc_fieldsplit_1_fields 0,1 -pc_fieldsplit_type multiplicative -snes_view -fieldsplit_pc_type lu -da_refine 1 -ksp_type fgmres
743       requires: !single
744 
745    test:
746       suffix: 9
747       nsize: 3
748       args: -snes_monitor_short -ksp_monitor_short -pc_type fieldsplit -pc_fieldsplit_type multiplicative -snes_view -da_refine 1 -ksp_type fgmres
749       requires: !single
750 
751    test:
752       suffix: aspin
753       nsize: 4
754       args: -da_refine 3 -da_overlap 2 -snes_monitor_short -snes_type aspin -grashof 4e4 -lidvelocity 100 -ksp_monitor_short
755       requires: !single
756 
757    test:
758       suffix: bcgsl
759       nsize: 2
760       args: -ksp_type bcgsl -ksp_monitor_short -da_refine 2 -ksp_bcgsl_ell 3 -snes_view
761       requires: !single
762 
763    test:
764       suffix: bcols1
765       nsize: 2
766       args: -da_refine 3 -snes_monitor_short -pc_type mg -ksp_type fgmres -pc_mg_type full -mat_fd_coloring_bcols 1
767       output_file: output/ex19_1.out
768       requires: !single
769 
770    test:
771       suffix: bjacobi
772       nsize: 4
773       args: -da_refine 4 -ksp_type fgmres -pc_type bjacobi -pc_bjacobi_blocks 2 -sub_ksp_type gmres -sub_ksp_max_it 2 -sub_pc_type bjacobi -sub_sub_ksp_type preonly -sub_sub_pc_type ilu -snes_monitor_short
774       requires: !single
775 
776    test:
777       suffix: cgne
778       args: -da_refine 2 -pc_type lu -ksp_type cgne -ksp_monitor_short -ksp_converged_reason -ksp_view -ksp_norm_type unpreconditioned
779       filter: grep -v HERMITIAN
780       requires: !single
781 
782    test:
783       suffix: cgs
784       args: -da_refine 1 -ksp_monitor_short -ksp_type cgs
785       requires: !single
786 
787    test:
788       suffix: composite_fieldsplit
789       args: -ksp_type fgmres -pc_type composite -pc_composite_type MULTIPLICATIVE -pc_composite_pcs fieldsplit,none -sub_0_pc_fieldsplit_block_size 4 -sub_0_pc_fieldsplit_type additive -sub_0_pc_fieldsplit_0_fields 0,1,2 -sub_0_pc_fieldsplit_1_fields 3 -snes_monitor_short -ksp_monitor_short
790       requires: !single
791 
792    test:
793       suffix: composite_fieldsplit_bjacobi
794       args: -ksp_type fgmres -pc_type composite -pc_composite_type MULTIPLICATIVE -pc_composite_pcs fieldsplit,bjacobi -sub_0_pc_fieldsplit_block_size 4 -sub_0_pc_fieldsplit_type additive -sub_0_pc_fieldsplit_0_fields 0,1,2 -sub_0_pc_fieldsplit_1_fields 3 -sub_1_pc_bjacobi_blocks 16 -sub_1_sub_pc_type lu -snes_monitor_short -ksp_monitor_short
795       requires: !single
796 
797    test:
798       suffix: composite_fieldsplit_bjacobi_2
799       nsize: 4
800       args: -ksp_type fgmres -pc_type composite -pc_composite_type MULTIPLICATIVE -pc_composite_pcs fieldsplit,bjacobi -sub_0_pc_fieldsplit_block_size 4 -sub_0_pc_fieldsplit_type additive -sub_0_pc_fieldsplit_0_fields 0,1,2 -sub_0_pc_fieldsplit_1_fields 3 -sub_1_pc_bjacobi_blocks 16 -sub_1_sub_pc_type lu -snes_monitor_short -ksp_monitor_short
801       requires: !single
802 
803    test:
804       suffix: composite_gs_newton
805       nsize: 2
806       args: -da_refine 3 -grashof 4e4 -lidvelocity 100 -snes_monitor_short -snes_type composite -snes_composite_type additiveoptimal -snes_composite_sneses ngs,newtonls -sub_0_snes_max_it 20 -sub_1_pc_type mg
807       requires: !single
808 
809    test:
810       suffix: cuda
811       requires: cuda !single
812       args: -dm_vec_type cuda -dm_mat_type aijcusparse -pc_type none -ksp_type fgmres -snes_monitor_short -snes_rtol 1.e-5
813 
814    test:
815       suffix: draw
816       args: -pc_type fieldsplit -snes_view draw -fieldsplit_x_velocity_pc_type mg -fieldsplit_x_velocity_pc_mg_galerkin pmat -fieldsplit_x_velocity_pc_mg_levels 2 -da_refine 1 -fieldsplit_x_velocity_mg_coarse_pc_type svd
817       requires: x !single
818 
819    test:
820       suffix: drawports
821       args: -snes_monitor_solution draw::draw_ports -da_refine 1
822       output_file: output/ex19_draw.out
823       requires: x !single
824 
825    test:
826       suffix: fas
827       args: -da_refine 4 -snes_monitor_short -snes_type fas -fas_levels_snes_type ngs -fas_levels_snes_ngs_sweeps 3 -fas_levels_snes_ngs_atol 0.0 -fas_levels_snes_ngs_stol 0.0 -grashof 4e4 -snes_fas_smoothup 6 -snes_fas_smoothdown 6 -lidvelocity 100
828       requires: !single
829 
830    test:
831       suffix: fas_full
832       args: -da_refine 4 -snes_monitor_short -snes_type fas -snes_fas_type full -snes_fas_full_downsweep -fas_levels_snes_type ngs -fas_levels_snes_ngs_sweeps 3 -fas_levels_snes_ngs_atol 0.0 -fas_levels_snes_ngs_stol 0.0 -grashof 4e4 -snes_fas_smoothup 6 -snes_fas_smoothdown 6 -lidvelocity 100
833       requires: !single
834 
835    test:
836       suffix: fdcoloring_ds
837       args: -da_refine 3 -snes_converged_reason -pc_type mg -mat_fd_type ds
838       output_file: output/ex19_2.out
839       requires: !single
840 
841    test:
842       suffix: fdcoloring_ds_baij
843       args: -da_refine 3 -snes_converged_reason -pc_type mg -mat_fd_type ds -dm_mat_type baij
844       output_file: output/ex19_2.out
845       requires: !single
846 
847    test:
848       suffix: fdcoloring_ds_bcols1
849       args: -da_refine 3 -snes_converged_reason -pc_type mg -mat_fd_type ds -mat_fd_coloring_bcols 1
850       output_file: output/ex19_2.out
851       requires: !single
852 
853    test:
854       suffix: fdcoloring_wp
855       args: -da_refine 3 -snes_monitor_short -pc_type mg
856       requires: !single
857 
858    test:
859       suffix: fdcoloring_wp_baij
860       args: -da_refine 3 -snes_monitor_short -pc_type mg -dm_mat_type baij
861       output_file: output/ex19_fdcoloring_wp.out
862       requires: !single
863 
864    test:
865       suffix: fdcoloring_wp_bcols1
866       args: -da_refine 3 -snes_monitor_short -pc_type mg -mat_fd_coloring_bcols 1
867       output_file: output/ex19_fdcoloring_wp.out
868       requires: !single
869 
870    test:
871       suffix: fieldsplit_2
872       args: -ksp_type fgmres -pc_type fieldsplit -pc_fieldsplit_block_size 4 -pc_fieldsplit_type additive -pc_fieldsplit_0_fields 0,1,2 -pc_fieldsplit_1_fields 3 -snes_monitor_short -ksp_monitor_short
873       requires: !single
874 
875    test:
876       suffix: fieldsplit_3
877       args: -ksp_type fgmres -pc_type fieldsplit -pc_fieldsplit_block_size 4 -pc_fieldsplit_type additive -pc_fieldsplit_0_fields 0,1,2 -pc_fieldsplit_1_fields 3 -fieldsplit_0_pc_type lu -fieldsplit_1_pc_type lu -snes_monitor_short -ksp_monitor_short
878       requires: !single
879 
880    test:
881       suffix: fieldsplit_4
882       args: -ksp_type fgmres -pc_type fieldsplit -pc_fieldsplit_block_size 4 -pc_fieldsplit_type SCHUR -pc_fieldsplit_0_fields 0,1,2 -pc_fieldsplit_1_fields 3 -fieldsplit_0_pc_type lu -fieldsplit_1_pc_type lu -snes_monitor_short -ksp_monitor_short
883       requires: !single
884 
885    # HYPRE PtAP broken with complex numbers
886    test:
887       suffix: fieldsplit_hypre
888       nsize: 2
889       requires: hypre mumps !complex !defined(PETSC_HAVE_HYPRE_DEVICE)
890       args: -pc_type fieldsplit -pc_fieldsplit_block_size 4 -pc_fieldsplit_type SCHUR -pc_fieldsplit_0_fields 0,1,2 -pc_fieldsplit_1_fields 3 -fieldsplit_0_pc_type lu -fieldsplit_0_pc_factor_mat_solver_type mumps -fieldsplit_1_pc_type hypre -fieldsplit_1_pc_hypre_type boomeramg -snes_monitor_short -ksp_monitor_short
891 
892    test:
893       suffix: fieldsplit_mumps
894       nsize: 2
895       requires: mumps
896       args: -pc_type fieldsplit -pc_fieldsplit_block_size 4 -pc_fieldsplit_type SCHUR -pc_fieldsplit_0_fields 0,1,2 -pc_fieldsplit_1_fields 3 -fieldsplit_0_pc_type lu -fieldsplit_1_pc_type lu -snes_monitor_short -ksp_monitor_short -fieldsplit_0_pc_factor_mat_solver_type mumps -fieldsplit_1_pc_factor_mat_solver_type mumps
897       output_file: output/ex19_fieldsplit_5.out
898 
899    test:
900       suffix: greedy_coloring
901       nsize: 2
902       args: -da_refine 3 -snes_monitor_short -snes_fd_color -snes_fd_color_use_mat -mat_coloring_type greedy -mat_coloring_weight_type lf -mat_coloring_view> ex19_greedy_coloring.tmp 2>&1
903       requires: !single
904 
905    # HYPRE PtAP broken with complex numbers
906    test:
907       suffix: hypre
908       nsize: 2
909       requires: hypre !complex !defined(PETSC_HAVE_HYPRE_DEVICE)
910       args: -da_refine 3 -snes_monitor_short -pc_type hypre -ksp_norm_type unpreconditioned
911 
912    # ibcgs is broken when using device vectors
913    test:
914       suffix: ibcgs
915       nsize: 2
916       args: -ksp_type ibcgs -ksp_monitor_short -da_refine 2 -snes_view
917       requires: !complex !single
918 
919    test:
920       suffix: kaczmarz
921       nsize: 2
922       args: -pc_type kaczmarz -ksp_monitor_short -snes_monitor_short -snes_view
923       requires: !single
924 
925    test:
926       suffix: klu
927       requires: suitesparse
928       args: -da_grid_x 20 -da_grid_y 20 -pc_type lu -pc_factor_mat_solver_type klu
929       output_file: output/ex19_superlu.out
930 
931    test:
932       suffix: klu_2
933       requires: suitesparse
934       args: -da_grid_x 20 -da_grid_y 20 -pc_type lu -pc_factor_mat_solver_type klu -pc_factor_mat_ordering_type nd
935       output_file: output/ex19_superlu.out
936 
937    test:
938       suffix: klu_3
939       requires: suitesparse
940       args: -da_grid_x 20 -da_grid_y 20 -pc_type lu -pc_factor_mat_solver_type klu -mat_klu_use_btf 0
941       output_file: output/ex19_superlu.out
942 
943    test:
944       suffix: ml
945       nsize: 2
946       requires: ml
947       args: -da_refine 3 -snes_monitor_short -pc_type ml
948 
949    test:
950       suffix: ngmres_fas
951       args: -da_refine 4 -snes_monitor_short -snes_type ngmres -npc_fas_levels_snes_type ngs -npc_fas_levels_snes_ngs_sweeps 3 -npc_fas_levels_snes_ngs_atol 0.0 -npc_fas_levels_snes_ngs_stol 0.0 -npc_snes_type fas -npc_fas_levels_snes_type ngs -npc_snes_max_it 1 -npc_snes_fas_smoothup 6 -npc_snes_fas_smoothdown 6 -lidvelocity 100 -grashof 4e4
952       requires: !single
953 
954    test:
955       suffix: ngmres_fas_gssecant
956       args: -da_refine 3 -snes_monitor_short -snes_type ngmres -npc_snes_type fas -npc_fas_levels_snes_type ngs -npc_fas_levels_snes_max_it 6 -npc_fas_levels_snes_ngs_secant -npc_fas_levels_snes_ngs_max_it 1 -npc_fas_coarse_snes_max_it 1 -lidvelocity 100 -grashof 4e4
957       requires: !single
958 
959    test:
960       suffix: ngmres_fas_ms
961       nsize: 2
962       args: -snes_grid_sequence 2 -lidvelocity 200 -grashof 1e4 -snes_monitor_short -snes_view -snes_converged_reason -snes_type ngmres -npc_snes_type fas -npc_fas_coarse_snes_type newtonls -npc_fas_coarse_ksp_type preonly -npc_snes_max_it 1
963       requires: !single
964 
965    test:
966       suffix: ngmres_nasm
967       nsize: 4
968       args: -da_refine 4 -da_overlap 2 -snes_monitor_short -snes_type ngmres -snes_max_it 10 -npc_snes_type nasm -npc_snes_nasm_type basic -grashof 4e4 -lidvelocity 100
969       requires: !single
970 
971    test:
972       suffix: ngs
973       args: -snes_type ngs -snes_view -snes_monitor -snes_rtol 1e-4
974       requires: !single
975 
976    test:
977       suffix: ngs_fd
978       args: -snes_type ngs -snes_ngs_secant -snes_view -snes_monitor -snes_rtol 1e-4
979       requires: !single
980 
981    test:
982       suffix: parms
983       nsize: 2
984       requires: parms
985       args: -pc_type parms -ksp_monitor_short -snes_view
986 
987    test:
988       suffix: superlu
989       requires: superlu
990       args: -da_grid_x 20 -da_grid_y 20 -pc_type lu -pc_factor_mat_solver_type superlu
991 
992    test:
993       suffix: superlu_sell
994       requires: superlu
995       args: -da_grid_x 20 -da_grid_y 20 -pc_type lu -pc_factor_mat_solver_type superlu -dm_mat_type sell -pc_factor_mat_ordering_type natural
996       output_file: output/ex19_superlu.out
997 
998    test:
999       suffix: superlu_dist
1000       requires: superlu_dist
1001       args: -da_grid_x 20 -da_grid_y 20 -pc_type lu -pc_factor_mat_solver_type superlu_dist
1002       output_file: output/ex19_superlu.out
1003 
1004    test:
1005       suffix: superlu_dist_2
1006       nsize: 2
1007       requires: superlu_dist
1008       args: -da_grid_x 20 -da_grid_y 20 -pc_type lu -pc_factor_mat_solver_type superlu_dist
1009       output_file: output/ex19_superlu.out
1010 
1011    test:
1012       suffix: superlu_dist_3d
1013       nsize: 4
1014       requires: superlu_dist !defined(PETSCTEST_VALGRIND)
1015       filter: grep -v iam | grep -v openMP
1016       args: -da_grid_x 20 -da_grid_y 20 -pc_type lu -pc_factor_mat_solver_type superlu_dist -mat_superlu_dist_3d -mat_superlu_dist_d 2 -snes_view -snes_monitor -ksp_monitor
1017 
1018    test:
1019       suffix: superlu_equil
1020       requires: superlu
1021       args: -da_grid_x 20 -da_grid_y 20 -{snes,ksp}_monitor_short -pc_type lu -pc_factor_mat_solver_type superlu -mat_superlu_equil
1022 
1023    test:
1024       suffix: superlu_equil_sell
1025       requires: superlu
1026       args: -da_grid_x 20 -da_grid_y 20 -{snes,ksp}_monitor_short -pc_type lu -pc_factor_mat_solver_type superlu -mat_superlu_equil -dm_mat_type sell -pc_factor_mat_ordering_type natural
1027       output_file: output/ex19_superlu_equil.out
1028 
1029    test:
1030       suffix: tcqmr
1031       args: -da_refine 1 -ksp_monitor_short -ksp_type tcqmr
1032       requires: !single
1033 
1034    test:
1035       suffix: tfqmr
1036       args: -da_refine 1 -ksp_monitor_short -ksp_type tfqmr
1037       requires: !single
1038 
1039    test:
1040       suffix: umfpack
1041       requires: suitesparse
1042       args: -da_refine 2 -pc_type lu -pc_factor_mat_solver_type umfpack -snes_view -snes_monitor_short -ksp_monitor_short -pc_factor_mat_ordering_type external
1043 
1044    test:
1045       suffix: tut_1
1046       nsize: 4
1047       requires: !single
1048       args: -da_refine 5 -snes_monitor -ksp_monitor -snes_view
1049 
1050    test:
1051       suffix: tut_2
1052       nsize: 4
1053       requires: !single
1054       args: -da_refine 5 -snes_monitor -ksp_monitor -snes_view -pc_type mg
1055 
1056    # HYPRE PtAP broken with complex numbers
1057    test:
1058       suffix: tut_3
1059       nsize: 4
1060       requires: hypre !single !complex !defined(PETSC_HAVE_HYPRE_DEVICE)
1061       args: -da_refine 5 -snes_monitor -ksp_monitor -snes_view -pc_type hypre
1062 
1063    test:
1064       suffix: tut_8
1065       nsize: 4
1066       requires: ml !single
1067       args: -da_refine 5 -snes_monitor -ksp_monitor -snes_view -pc_type ml
1068 
1069    test:
1070       suffix: tut_4
1071       nsize: 1
1072       requires: !single
1073       args: -da_refine 5 -log_view
1074       filter: head -n 2
1075       filter_output: head -n 2
1076 
1077    test:
1078       suffix: tut_5
1079       nsize: 1
1080       requires: !single
1081       args: -da_refine 5 -log_view -pc_type mg
1082       filter: head -n 2
1083       filter_output: head -n 2
1084 
1085    test:
1086       suffix: tut_6
1087       nsize: 4
1088       requires: !single
1089       args: -da_refine 5 -log_view
1090       filter: head -n 2
1091       filter_output: head -n 2
1092 
1093    test:
1094       suffix: tut_7
1095       nsize: 4
1096       requires: !single
1097       args: -da_refine 5 -log_view -pc_type mg
1098       filter: head -n 2
1099       filter_output: head -n 2
1100 
1101    test:
1102       suffix: cuda_1
1103       nsize: 1
1104       requires: cuda
1105       args: -snes_monitor -dm_mat_type seqaijcusparse -dm_vec_type seqcuda -pc_type gamg -pc_gamg_esteig_ksp_max_it 10 -ksp_monitor -mg_levels_ksp_max_it 3
1106 
1107    test:
1108       suffix: cuda_2
1109       nsize: 3
1110       requires: cuda !single
1111       args: -snes_monitor -dm_mat_type mpiaijcusparse -dm_vec_type mpicuda -pc_type gamg -pc_gamg_esteig_ksp_max_it 10 -ksp_monitor  -mg_levels_ksp_max_it 3
1112 
1113    test:
1114       suffix: cuda_dm_bind_below
1115       nsize: 2
1116       requires: cuda
1117       args: -dm_mat_type aijcusparse -dm_vec_type cuda -da_refine 3 -pc_type mg -mg_levels_ksp_type chebyshev -mg_levels_pc_type jacobi -log_view -pc_mg_log -dm_bind_below 10000
1118       filter: awk "/Level/ {print \$24}"
1119 
1120    test:
1121       suffix: viennacl_dm_bind_below
1122       nsize: 2
1123       requires: viennacl
1124       args: -dm_mat_type aijviennacl -dm_vec_type viennacl -da_refine 3 -pc_type mg -mg_levels_ksp_type chebyshev -mg_levels_pc_type jacobi -log_view -pc_mg_log -dm_bind_below 10000
1125       filter: awk "/Level/ {print \$24}"
1126 
1127    test:
1128       suffix: seqbaijmkl
1129       nsize: 1
1130       requires: defined(PETSC_HAVE_MKL_SPARSE_OPTIMIZE)
1131       args: -dm_mat_type baij -snes_monitor -ksp_monitor -snes_view
1132 
1133    test:
1134       suffix: mpibaijmkl
1135       nsize: 2
1136       requires:  defined(PETSC_HAVE_MKL_SPARSE_OPTIMIZE)
1137       args: -dm_mat_type baij -snes_monitor -ksp_monitor -snes_view
1138 
1139    test:
1140      suffix: cpardiso
1141      nsize: 4
1142      requires: mkl_cpardiso
1143      args: -pc_type lu -pc_factor_mat_solver_type mkl_cpardiso -ksp_monitor
1144 
1145    test:
1146      suffix: logviewmemory
1147      requires: defined(PETSC_USE_LOG) !defined(PETSCTEST_VALGRIND)
1148      args: -log_view -log_view_memory -da_refine 4
1149      filter: grep MatFDColorSetUp | wc -w | xargs  -I % sh -c "expr % \> 21"
1150 
1151    test:
1152      suffix: fs
1153      args: -pc_type fieldsplit -da_refine 3  -all_ksp_monitor -fieldsplit_y_velocity_pc_type lu  -fieldsplit_temperature_pc_type lu -fieldsplit_x_velocity_pc_type lu  -snes_view
1154 
1155    test:
1156      suffix: asm_matconvert
1157      args: -mat_type aij -pc_type asm -pc_asm_sub_mat_type dense -snes_view
1158 
1159    test:
1160       suffix: euclid
1161       nsize: 2
1162       requires: hypre !single !complex !defined(PETSC_HAVE_HYPRE_MIXEDINT) !defined(PETSC_HAVE_HYPRE_DEVICE)
1163       args: -da_refine 2 -ksp_monitor -snes_monitor -snes_view -pc_type hypre -pc_hypre_type euclid
1164 
1165    test:
1166       suffix: euclid_bj
1167       nsize: 2
1168       requires: hypre !single !complex !defined(PETSC_HAVE_HYPRE_MIXEDINT) !defined(PETSC_HAVE_HYPRE_DEVICE)
1169       args: -da_refine 2 -ksp_monitor -snes_monitor -snes_view -pc_type hypre -pc_hypre_type euclid -pc_hypre_euclid_bj
1170 
1171    test:
1172       suffix: euclid_droptolerance
1173       nsize: 1
1174       requires: hypre !single !complex !defined(PETSC_HAVE_HYPRE_MIXEDINT) !defined(PETSC_HAVE_HYPRE_DEVICE)
1175       args: -da_refine 2 -ksp_monitor -snes_monitor -snes_view -pc_type hypre -pc_hypre_type euclid -pc_hypre_euclid_droptolerance .1
1176 
1177 TEST*/
1178