xref: /petsc/src/dm/dt/fv/interface/fv.c (revision 4da3aa2f3126a6cd4b4bbde88727b583cddd4ee7)
1 #include <petsc/private/petscfvimpl.h> /*I "petscfv.h" I*/
2 #include <petsc/private/dmpleximpl.h> /* For CellRefiner */
3 #include <petscds.h>
4 
5 PetscClassId PETSCLIMITER_CLASSID = 0;
6 
7 PetscFunctionList PetscLimiterList              = NULL;
8 PetscBool         PetscLimiterRegisterAllCalled = PETSC_FALSE;
9 
10 PetscBool Limitercite = PETSC_FALSE;
11 const char LimiterCitation[] = "@article{BergerAftosmisMurman2005,\n"
12                                "  title   = {Analysis of slope limiters on irregular grids},\n"
13                                "  journal = {AIAA paper},\n"
14                                "  author  = {Marsha Berger and Michael J. Aftosmis and Scott M. Murman},\n"
15                                "  volume  = {490},\n"
16                                "  year    = {2005}\n}\n";
17 
18 /*@C
19   PetscLimiterRegister - Adds a new PetscLimiter implementation
20 
21   Not Collective
22 
23   Input Parameters:
24 + name        - The name of a new user-defined creation routine
25 - create_func - The creation routine itself
26 
27   Notes:
28   PetscLimiterRegister() may be called multiple times to add several user-defined PetscLimiters
29 
30   Sample usage:
31 .vb
32     PetscLimiterRegister("my_lim", MyPetscLimiterCreate);
33 .ve
34 
35   Then, your PetscLimiter type can be chosen with the procedural interface via
36 .vb
37     PetscLimiterCreate(MPI_Comm, PetscLimiter *);
38     PetscLimiterSetType(PetscLimiter, "my_lim");
39 .ve
40    or at runtime via the option
41 .vb
42     -petsclimiter_type my_lim
43 .ve
44 
45   Level: advanced
46 
47 .seealso: PetscLimiterRegisterAll(), PetscLimiterRegisterDestroy()
48 
49 @*/
50 PetscErrorCode PetscLimiterRegister(const char sname[], PetscErrorCode (*function)(PetscLimiter))
51 {
52   PetscErrorCode ierr;
53 
54   PetscFunctionBegin;
55   ierr = PetscFunctionListAdd(&PetscLimiterList, sname, function);CHKERRQ(ierr);
56   PetscFunctionReturn(0);
57 }
58 
59 /*@C
60   PetscLimiterSetType - Builds a particular PetscLimiter
61 
62   Collective on lim
63 
64   Input Parameters:
65 + lim  - The PetscLimiter object
66 - name - The kind of limiter
67 
68   Options Database Key:
69 . -petsclimiter_type <type> - Sets the PetscLimiter type; use -help for a list of available types
70 
71   Level: intermediate
72 
73 .seealso: PetscLimiterGetType(), PetscLimiterCreate()
74 @*/
75 PetscErrorCode PetscLimiterSetType(PetscLimiter lim, PetscLimiterType name)
76 {
77   PetscErrorCode (*r)(PetscLimiter);
78   PetscBool      match;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
83   ierr = PetscObjectTypeCompare((PetscObject) lim, name, &match);CHKERRQ(ierr);
84   if (match) PetscFunctionReturn(0);
85 
86   ierr = PetscLimiterRegisterAll();CHKERRQ(ierr);
87   ierr = PetscFunctionListFind(PetscLimiterList, name, &r);CHKERRQ(ierr);
88   if (!r) SETERRQ1(PetscObjectComm((PetscObject) lim), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscLimiter type: %s", name);
89 
90   if (lim->ops->destroy) {
91     ierr              = (*lim->ops->destroy)(lim);CHKERRQ(ierr);
92     lim->ops->destroy = NULL;
93   }
94   ierr = (*r)(lim);CHKERRQ(ierr);
95   ierr = PetscObjectChangeTypeName((PetscObject) lim, name);CHKERRQ(ierr);
96   PetscFunctionReturn(0);
97 }
98 
99 /*@C
100   PetscLimiterGetType - Gets the PetscLimiter type name (as a string) from the object.
101 
102   Not Collective
103 
104   Input Parameter:
105 . lim  - The PetscLimiter
106 
107   Output Parameter:
108 . name - The PetscLimiter type name
109 
110   Level: intermediate
111 
112 .seealso: PetscLimiterSetType(), PetscLimiterCreate()
113 @*/
114 PetscErrorCode PetscLimiterGetType(PetscLimiter lim, PetscLimiterType *name)
115 {
116   PetscErrorCode ierr;
117 
118   PetscFunctionBegin;
119   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
120   PetscValidPointer(name, 2);
121   ierr = PetscLimiterRegisterAll();CHKERRQ(ierr);
122   *name = ((PetscObject) lim)->type_name;
123   PetscFunctionReturn(0);
124 }
125 
126 /*@C
127    PetscLimiterViewFromOptions - View from Options
128 
129    Collective on PetscLimiter
130 
131    Input Parameters:
132 +  A - the PetscLimiter object to view
133 .  obj - Optional object
134 -  name - command line option
135 
136    Level: intermediate
137 .seealso:  PetscLimiter, PetscLimiterView, PetscObjectViewFromOptions(), PetscLimiterCreate()
138 @*/
139 PetscErrorCode  PetscLimiterViewFromOptions(PetscLimiter A,PetscObject obj,const char name[])
140 {
141   PetscErrorCode ierr;
142 
143   PetscFunctionBegin;
144   PetscValidHeaderSpecific(A,PETSCLIMITER_CLASSID,1);
145   ierr = PetscObjectViewFromOptions((PetscObject)A,obj,name);CHKERRQ(ierr);
146   PetscFunctionReturn(0);
147 }
148 
149 /*@C
150   PetscLimiterView - Views a PetscLimiter
151 
152   Collective on lim
153 
154   Input Parameter:
155 + lim - the PetscLimiter object to view
156 - v   - the viewer
157 
158   Level: beginner
159 
160 .seealso: PetscLimiterDestroy()
161 @*/
162 PetscErrorCode PetscLimiterView(PetscLimiter lim, PetscViewer v)
163 {
164   PetscErrorCode ierr;
165 
166   PetscFunctionBegin;
167   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
168   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) lim), &v);CHKERRQ(ierr);}
169   if (lim->ops->view) {ierr = (*lim->ops->view)(lim, v);CHKERRQ(ierr);}
170   PetscFunctionReturn(0);
171 }
172 
173 /*@
174   PetscLimiterSetFromOptions - sets parameters in a PetscLimiter from the options database
175 
176   Collective on lim
177 
178   Input Parameter:
179 . lim - the PetscLimiter object to set options for
180 
181   Level: intermediate
182 
183 .seealso: PetscLimiterView()
184 @*/
185 PetscErrorCode PetscLimiterSetFromOptions(PetscLimiter lim)
186 {
187   const char    *defaultType;
188   char           name[256];
189   PetscBool      flg;
190   PetscErrorCode ierr;
191 
192   PetscFunctionBegin;
193   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
194   if (!((PetscObject) lim)->type_name) defaultType = PETSCLIMITERSIN;
195   else                                 defaultType = ((PetscObject) lim)->type_name;
196   ierr = PetscLimiterRegisterAll();CHKERRQ(ierr);
197 
198   ierr = PetscObjectOptionsBegin((PetscObject) lim);CHKERRQ(ierr);
199   ierr = PetscOptionsFList("-petsclimiter_type", "Finite volume slope limiter", "PetscLimiterSetType", PetscLimiterList, defaultType, name, 256, &flg);CHKERRQ(ierr);
200   if (flg) {
201     ierr = PetscLimiterSetType(lim, name);CHKERRQ(ierr);
202   } else if (!((PetscObject) lim)->type_name) {
203     ierr = PetscLimiterSetType(lim, defaultType);CHKERRQ(ierr);
204   }
205   if (lim->ops->setfromoptions) {ierr = (*lim->ops->setfromoptions)(lim);CHKERRQ(ierr);}
206   /* process any options handlers added with PetscObjectAddOptionsHandler() */
207   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) lim);CHKERRQ(ierr);
208   ierr = PetscOptionsEnd();CHKERRQ(ierr);
209   ierr = PetscLimiterViewFromOptions(lim, NULL, "-petsclimiter_view");CHKERRQ(ierr);
210   PetscFunctionReturn(0);
211 }
212 
213 /*@C
214   PetscLimiterSetUp - Construct data structures for the PetscLimiter
215 
216   Collective on lim
217 
218   Input Parameter:
219 . lim - the PetscLimiter object to setup
220 
221   Level: intermediate
222 
223 .seealso: PetscLimiterView(), PetscLimiterDestroy()
224 @*/
225 PetscErrorCode PetscLimiterSetUp(PetscLimiter lim)
226 {
227   PetscErrorCode ierr;
228 
229   PetscFunctionBegin;
230   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
231   if (lim->ops->setup) {ierr = (*lim->ops->setup)(lim);CHKERRQ(ierr);}
232   PetscFunctionReturn(0);
233 }
234 
235 /*@
236   PetscLimiterDestroy - Destroys a PetscLimiter object
237 
238   Collective on lim
239 
240   Input Parameter:
241 . lim - the PetscLimiter object to destroy
242 
243   Level: beginner
244 
245 .seealso: PetscLimiterView()
246 @*/
247 PetscErrorCode PetscLimiterDestroy(PetscLimiter *lim)
248 {
249   PetscErrorCode ierr;
250 
251   PetscFunctionBegin;
252   if (!*lim) PetscFunctionReturn(0);
253   PetscValidHeaderSpecific((*lim), PETSCLIMITER_CLASSID, 1);
254 
255   if (--((PetscObject)(*lim))->refct > 0) {*lim = 0; PetscFunctionReturn(0);}
256   ((PetscObject) (*lim))->refct = 0;
257 
258   if ((*lim)->ops->destroy) {ierr = (*(*lim)->ops->destroy)(*lim);CHKERRQ(ierr);}
259   ierr = PetscHeaderDestroy(lim);CHKERRQ(ierr);
260   PetscFunctionReturn(0);
261 }
262 
263 /*@
264   PetscLimiterCreate - Creates an empty PetscLimiter object. The type can then be set with PetscLimiterSetType().
265 
266   Collective
267 
268   Input Parameter:
269 . comm - The communicator for the PetscLimiter object
270 
271   Output Parameter:
272 . lim - The PetscLimiter object
273 
274   Level: beginner
275 
276 .seealso: PetscLimiterSetType(), PETSCLIMITERSIN
277 @*/
278 PetscErrorCode PetscLimiterCreate(MPI_Comm comm, PetscLimiter *lim)
279 {
280   PetscLimiter   l;
281   PetscErrorCode ierr;
282 
283   PetscFunctionBegin;
284   PetscValidPointer(lim, 2);
285   ierr = PetscCitationsRegister(LimiterCitation,&Limitercite);CHKERRQ(ierr);
286   *lim = NULL;
287   ierr = PetscFVInitializePackage();CHKERRQ(ierr);
288 
289   ierr = PetscHeaderCreate(l, PETSCLIMITER_CLASSID, "PetscLimiter", "Finite Volume Slope Limiter", "PetscLimiter", comm, PetscLimiterDestroy, PetscLimiterView);CHKERRQ(ierr);
290 
291   *lim = l;
292   PetscFunctionReturn(0);
293 }
294 
295 /*@
296   PetscLimiterLimit - Limit the flux
297 
298   Input Parameters:
299 + lim  - The PetscLimiter
300 - flim - The input field
301 
302   Output Parameter:
303 . phi  - The limited field
304 
305 Note: Limiters given in symmetric form following Berger, Aftosmis, and Murman 2005
306 $ The classical flux-limited formulation is psi(r) where
307 $
308 $ r = (u[0] - u[-1]) / (u[1] - u[0])
309 $
310 $ The second order TVD region is bounded by
311 $
312 $ psi_minmod(r) = min(r,1)      and        psi_superbee(r) = min(2, 2r, max(1,r))
313 $
314 $ where all limiters are implicitly clipped to be non-negative. A more convenient slope-limited form is psi(r) =
315 $ phi(r)(r+1)/2 in which the reconstructed interface values are
316 $
317 $ u(v) = u[0] + phi(r) (grad u)[0] v
318 $
319 $ where v is the vector from centroid to quadrature point. In these variables, the usual limiters become
320 $
321 $ phi_minmod(r) = 2 min(1/(1+r),r/(1+r))   phi_superbee(r) = 2 min(2/(1+r), 2r/(1+r), max(1,r)/(1+r))
322 $
323 $ For a nicer symmetric formulation, rewrite in terms of
324 $
325 $ f = (u[0] - u[-1]) / (u[1] - u[-1])
326 $
327 $ where r(f) = f/(1-f). Not that r(1-f) = (1-f)/f = 1/r(f) so the symmetry condition
328 $
329 $ phi(r) = phi(1/r)
330 $
331 $ becomes
332 $
333 $ w(f) = w(1-f).
334 $
335 $ The limiters below implement this final form w(f). The reference methods are
336 $
337 $ w_minmod(f) = 2 min(f,(1-f))             w_superbee(r) = 4 min((1-f), f)
338 
339   Level: beginner
340 
341 .seealso: PetscLimiterSetType(), PetscLimiterCreate()
342 @*/
343 PetscErrorCode PetscLimiterLimit(PetscLimiter lim, PetscReal flim, PetscReal *phi)
344 {
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
349   PetscValidPointer(phi, 3);
350   ierr = (*lim->ops->limit)(lim, flim, phi);CHKERRQ(ierr);
351   PetscFunctionReturn(0);
352 }
353 
354 static PetscErrorCode PetscLimiterDestroy_Sin(PetscLimiter lim)
355 {
356   PetscLimiter_Sin *l = (PetscLimiter_Sin *) lim->data;
357   PetscErrorCode    ierr;
358 
359   PetscFunctionBegin;
360   ierr = PetscFree(l);CHKERRQ(ierr);
361   PetscFunctionReturn(0);
362 }
363 
364 static PetscErrorCode PetscLimiterView_Sin_Ascii(PetscLimiter lim, PetscViewer viewer)
365 {
366   PetscViewerFormat format;
367   PetscErrorCode    ierr;
368 
369   PetscFunctionBegin;
370   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
371   ierr = PetscViewerASCIIPrintf(viewer, "Sin Slope Limiter:\n");CHKERRQ(ierr);
372   PetscFunctionReturn(0);
373 }
374 
375 static PetscErrorCode PetscLimiterView_Sin(PetscLimiter lim, PetscViewer viewer)
376 {
377   PetscBool      iascii;
378   PetscErrorCode ierr;
379 
380   PetscFunctionBegin;
381   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
382   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
383   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
384   if (iascii) {ierr = PetscLimiterView_Sin_Ascii(lim, viewer);CHKERRQ(ierr);}
385   PetscFunctionReturn(0);
386 }
387 
388 static PetscErrorCode PetscLimiterLimit_Sin(PetscLimiter lim, PetscReal f, PetscReal *phi)
389 {
390   PetscFunctionBegin;
391   *phi = PetscSinReal(PETSC_PI*PetscMax(0, PetscMin(f, 1)));
392   PetscFunctionReturn(0);
393 }
394 
395 static PetscErrorCode PetscLimiterInitialize_Sin(PetscLimiter lim)
396 {
397   PetscFunctionBegin;
398   lim->ops->view    = PetscLimiterView_Sin;
399   lim->ops->destroy = PetscLimiterDestroy_Sin;
400   lim->ops->limit   = PetscLimiterLimit_Sin;
401   PetscFunctionReturn(0);
402 }
403 
404 /*MC
405   PETSCLIMITERSIN = "sin" - A PetscLimiter object
406 
407   Level: intermediate
408 
409 .seealso: PetscLimiterType, PetscLimiterCreate(), PetscLimiterSetType()
410 M*/
411 
412 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_Sin(PetscLimiter lim)
413 {
414   PetscLimiter_Sin *l;
415   PetscErrorCode    ierr;
416 
417   PetscFunctionBegin;
418   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
419   ierr      = PetscNewLog(lim, &l);CHKERRQ(ierr);
420   lim->data = l;
421 
422   ierr = PetscLimiterInitialize_Sin(lim);CHKERRQ(ierr);
423   PetscFunctionReturn(0);
424 }
425 
426 static PetscErrorCode PetscLimiterDestroy_Zero(PetscLimiter lim)
427 {
428   PetscLimiter_Zero *l = (PetscLimiter_Zero *) lim->data;
429   PetscErrorCode    ierr;
430 
431   PetscFunctionBegin;
432   ierr = PetscFree(l);CHKERRQ(ierr);
433   PetscFunctionReturn(0);
434 }
435 
436 static PetscErrorCode PetscLimiterView_Zero_Ascii(PetscLimiter lim, PetscViewer viewer)
437 {
438   PetscViewerFormat format;
439   PetscErrorCode    ierr;
440 
441   PetscFunctionBegin;
442   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
443   ierr = PetscViewerASCIIPrintf(viewer, "Zero Slope Limiter:\n");CHKERRQ(ierr);
444   PetscFunctionReturn(0);
445 }
446 
447 static PetscErrorCode PetscLimiterView_Zero(PetscLimiter lim, PetscViewer viewer)
448 {
449   PetscBool      iascii;
450   PetscErrorCode ierr;
451 
452   PetscFunctionBegin;
453   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
454   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
455   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
456   if (iascii) {ierr = PetscLimiterView_Zero_Ascii(lim, viewer);CHKERRQ(ierr);}
457   PetscFunctionReturn(0);
458 }
459 
460 static PetscErrorCode PetscLimiterLimit_Zero(PetscLimiter lim, PetscReal f, PetscReal *phi)
461 {
462   PetscFunctionBegin;
463   *phi = 0.0;
464   PetscFunctionReturn(0);
465 }
466 
467 static PetscErrorCode PetscLimiterInitialize_Zero(PetscLimiter lim)
468 {
469   PetscFunctionBegin;
470   lim->ops->view    = PetscLimiterView_Zero;
471   lim->ops->destroy = PetscLimiterDestroy_Zero;
472   lim->ops->limit   = PetscLimiterLimit_Zero;
473   PetscFunctionReturn(0);
474 }
475 
476 /*MC
477   PETSCLIMITERZERO = "zero" - A PetscLimiter object
478 
479   Level: intermediate
480 
481 .seealso: PetscLimiterType, PetscLimiterCreate(), PetscLimiterSetType()
482 M*/
483 
484 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_Zero(PetscLimiter lim)
485 {
486   PetscLimiter_Zero *l;
487   PetscErrorCode     ierr;
488 
489   PetscFunctionBegin;
490   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
491   ierr      = PetscNewLog(lim, &l);CHKERRQ(ierr);
492   lim->data = l;
493 
494   ierr = PetscLimiterInitialize_Zero(lim);CHKERRQ(ierr);
495   PetscFunctionReturn(0);
496 }
497 
498 static PetscErrorCode PetscLimiterDestroy_None(PetscLimiter lim)
499 {
500   PetscLimiter_None *l = (PetscLimiter_None *) lim->data;
501   PetscErrorCode    ierr;
502 
503   PetscFunctionBegin;
504   ierr = PetscFree(l);CHKERRQ(ierr);
505   PetscFunctionReturn(0);
506 }
507 
508 static PetscErrorCode PetscLimiterView_None_Ascii(PetscLimiter lim, PetscViewer viewer)
509 {
510   PetscViewerFormat format;
511   PetscErrorCode    ierr;
512 
513   PetscFunctionBegin;
514   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
515   ierr = PetscViewerASCIIPrintf(viewer, "None Slope Limiter:\n");CHKERRQ(ierr);
516   PetscFunctionReturn(0);
517 }
518 
519 static PetscErrorCode PetscLimiterView_None(PetscLimiter lim, PetscViewer viewer)
520 {
521   PetscBool      iascii;
522   PetscErrorCode ierr;
523 
524   PetscFunctionBegin;
525   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
526   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
527   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
528   if (iascii) {ierr = PetscLimiterView_None_Ascii(lim, viewer);CHKERRQ(ierr);}
529   PetscFunctionReturn(0);
530 }
531 
532 static PetscErrorCode PetscLimiterLimit_None(PetscLimiter lim, PetscReal f, PetscReal *phi)
533 {
534   PetscFunctionBegin;
535   *phi = 1.0;
536   PetscFunctionReturn(0);
537 }
538 
539 static PetscErrorCode PetscLimiterInitialize_None(PetscLimiter lim)
540 {
541   PetscFunctionBegin;
542   lim->ops->view    = PetscLimiterView_None;
543   lim->ops->destroy = PetscLimiterDestroy_None;
544   lim->ops->limit   = PetscLimiterLimit_None;
545   PetscFunctionReturn(0);
546 }
547 
548 /*MC
549   PETSCLIMITERNONE = "none" - A PetscLimiter object
550 
551   Level: intermediate
552 
553 .seealso: PetscLimiterType, PetscLimiterCreate(), PetscLimiterSetType()
554 M*/
555 
556 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_None(PetscLimiter lim)
557 {
558   PetscLimiter_None *l;
559   PetscErrorCode    ierr;
560 
561   PetscFunctionBegin;
562   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
563   ierr      = PetscNewLog(lim, &l);CHKERRQ(ierr);
564   lim->data = l;
565 
566   ierr = PetscLimiterInitialize_None(lim);CHKERRQ(ierr);
567   PetscFunctionReturn(0);
568 }
569 
570 static PetscErrorCode PetscLimiterDestroy_Minmod(PetscLimiter lim)
571 {
572   PetscLimiter_Minmod *l = (PetscLimiter_Minmod *) lim->data;
573   PetscErrorCode    ierr;
574 
575   PetscFunctionBegin;
576   ierr = PetscFree(l);CHKERRQ(ierr);
577   PetscFunctionReturn(0);
578 }
579 
580 static PetscErrorCode PetscLimiterView_Minmod_Ascii(PetscLimiter lim, PetscViewer viewer)
581 {
582   PetscViewerFormat format;
583   PetscErrorCode    ierr;
584 
585   PetscFunctionBegin;
586   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
587   ierr = PetscViewerASCIIPrintf(viewer, "Minmod Slope Limiter:\n");CHKERRQ(ierr);
588   PetscFunctionReturn(0);
589 }
590 
591 static PetscErrorCode PetscLimiterView_Minmod(PetscLimiter lim, PetscViewer viewer)
592 {
593   PetscBool      iascii;
594   PetscErrorCode ierr;
595 
596   PetscFunctionBegin;
597   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
598   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
599   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
600   if (iascii) {ierr = PetscLimiterView_Minmod_Ascii(lim, viewer);CHKERRQ(ierr);}
601   PetscFunctionReturn(0);
602 }
603 
604 static PetscErrorCode PetscLimiterLimit_Minmod(PetscLimiter lim, PetscReal f, PetscReal *phi)
605 {
606   PetscFunctionBegin;
607   *phi = 2*PetscMax(0, PetscMin(f, 1-f));
608   PetscFunctionReturn(0);
609 }
610 
611 static PetscErrorCode PetscLimiterInitialize_Minmod(PetscLimiter lim)
612 {
613   PetscFunctionBegin;
614   lim->ops->view    = PetscLimiterView_Minmod;
615   lim->ops->destroy = PetscLimiterDestroy_Minmod;
616   lim->ops->limit   = PetscLimiterLimit_Minmod;
617   PetscFunctionReturn(0);
618 }
619 
620 /*MC
621   PETSCLIMITERMINMOD = "minmod" - A PetscLimiter object
622 
623   Level: intermediate
624 
625 .seealso: PetscLimiterType, PetscLimiterCreate(), PetscLimiterSetType()
626 M*/
627 
628 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_Minmod(PetscLimiter lim)
629 {
630   PetscLimiter_Minmod *l;
631   PetscErrorCode    ierr;
632 
633   PetscFunctionBegin;
634   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
635   ierr      = PetscNewLog(lim, &l);CHKERRQ(ierr);
636   lim->data = l;
637 
638   ierr = PetscLimiterInitialize_Minmod(lim);CHKERRQ(ierr);
639   PetscFunctionReturn(0);
640 }
641 
642 static PetscErrorCode PetscLimiterDestroy_VanLeer(PetscLimiter lim)
643 {
644   PetscLimiter_VanLeer *l = (PetscLimiter_VanLeer *) lim->data;
645   PetscErrorCode    ierr;
646 
647   PetscFunctionBegin;
648   ierr = PetscFree(l);CHKERRQ(ierr);
649   PetscFunctionReturn(0);
650 }
651 
652 static PetscErrorCode PetscLimiterView_VanLeer_Ascii(PetscLimiter lim, PetscViewer viewer)
653 {
654   PetscViewerFormat format;
655   PetscErrorCode    ierr;
656 
657   PetscFunctionBegin;
658   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
659   ierr = PetscViewerASCIIPrintf(viewer, "Van Leer Slope Limiter:\n");CHKERRQ(ierr);
660   PetscFunctionReturn(0);
661 }
662 
663 static PetscErrorCode PetscLimiterView_VanLeer(PetscLimiter lim, PetscViewer viewer)
664 {
665   PetscBool      iascii;
666   PetscErrorCode ierr;
667 
668   PetscFunctionBegin;
669   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
670   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
671   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
672   if (iascii) {ierr = PetscLimiterView_VanLeer_Ascii(lim, viewer);CHKERRQ(ierr);}
673   PetscFunctionReturn(0);
674 }
675 
676 static PetscErrorCode PetscLimiterLimit_VanLeer(PetscLimiter lim, PetscReal f, PetscReal *phi)
677 {
678   PetscFunctionBegin;
679   *phi = PetscMax(0, 4*f*(1-f));
680   PetscFunctionReturn(0);
681 }
682 
683 static PetscErrorCode PetscLimiterInitialize_VanLeer(PetscLimiter lim)
684 {
685   PetscFunctionBegin;
686   lim->ops->view    = PetscLimiterView_VanLeer;
687   lim->ops->destroy = PetscLimiterDestroy_VanLeer;
688   lim->ops->limit   = PetscLimiterLimit_VanLeer;
689   PetscFunctionReturn(0);
690 }
691 
692 /*MC
693   PETSCLIMITERVANLEER = "vanleer" - A PetscLimiter object
694 
695   Level: intermediate
696 
697 .seealso: PetscLimiterType, PetscLimiterCreate(), PetscLimiterSetType()
698 M*/
699 
700 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_VanLeer(PetscLimiter lim)
701 {
702   PetscLimiter_VanLeer *l;
703   PetscErrorCode    ierr;
704 
705   PetscFunctionBegin;
706   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
707   ierr      = PetscNewLog(lim, &l);CHKERRQ(ierr);
708   lim->data = l;
709 
710   ierr = PetscLimiterInitialize_VanLeer(lim);CHKERRQ(ierr);
711   PetscFunctionReturn(0);
712 }
713 
714 static PetscErrorCode PetscLimiterDestroy_VanAlbada(PetscLimiter lim)
715 {
716   PetscLimiter_VanAlbada *l = (PetscLimiter_VanAlbada *) lim->data;
717   PetscErrorCode    ierr;
718 
719   PetscFunctionBegin;
720   ierr = PetscFree(l);CHKERRQ(ierr);
721   PetscFunctionReturn(0);
722 }
723 
724 static PetscErrorCode PetscLimiterView_VanAlbada_Ascii(PetscLimiter lim, PetscViewer viewer)
725 {
726   PetscViewerFormat format;
727   PetscErrorCode    ierr;
728 
729   PetscFunctionBegin;
730   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
731   ierr = PetscViewerASCIIPrintf(viewer, "Van Albada Slope Limiter:\n");CHKERRQ(ierr);
732   PetscFunctionReturn(0);
733 }
734 
735 static PetscErrorCode PetscLimiterView_VanAlbada(PetscLimiter lim, PetscViewer viewer)
736 {
737   PetscBool      iascii;
738   PetscErrorCode ierr;
739 
740   PetscFunctionBegin;
741   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
742   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
743   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
744   if (iascii) {ierr = PetscLimiterView_VanAlbada_Ascii(lim, viewer);CHKERRQ(ierr);}
745   PetscFunctionReturn(0);
746 }
747 
748 static PetscErrorCode PetscLimiterLimit_VanAlbada(PetscLimiter lim, PetscReal f, PetscReal *phi)
749 {
750   PetscFunctionBegin;
751   *phi = PetscMax(0, 2*f*(1-f) / (PetscSqr(f) + PetscSqr(1-f)));
752   PetscFunctionReturn(0);
753 }
754 
755 static PetscErrorCode PetscLimiterInitialize_VanAlbada(PetscLimiter lim)
756 {
757   PetscFunctionBegin;
758   lim->ops->view    = PetscLimiterView_VanAlbada;
759   lim->ops->destroy = PetscLimiterDestroy_VanAlbada;
760   lim->ops->limit   = PetscLimiterLimit_VanAlbada;
761   PetscFunctionReturn(0);
762 }
763 
764 /*MC
765   PETSCLIMITERVANALBADA = "vanalbada" - A PetscLimiter object
766 
767   Level: intermediate
768 
769 .seealso: PetscLimiterType, PetscLimiterCreate(), PetscLimiterSetType()
770 M*/
771 
772 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_VanAlbada(PetscLimiter lim)
773 {
774   PetscLimiter_VanAlbada *l;
775   PetscErrorCode    ierr;
776 
777   PetscFunctionBegin;
778   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
779   ierr      = PetscNewLog(lim, &l);CHKERRQ(ierr);
780   lim->data = l;
781 
782   ierr = PetscLimiterInitialize_VanAlbada(lim);CHKERRQ(ierr);
783   PetscFunctionReturn(0);
784 }
785 
786 static PetscErrorCode PetscLimiterDestroy_Superbee(PetscLimiter lim)
787 {
788   PetscLimiter_Superbee *l = (PetscLimiter_Superbee *) lim->data;
789   PetscErrorCode    ierr;
790 
791   PetscFunctionBegin;
792   ierr = PetscFree(l);CHKERRQ(ierr);
793   PetscFunctionReturn(0);
794 }
795 
796 static PetscErrorCode PetscLimiterView_Superbee_Ascii(PetscLimiter lim, PetscViewer viewer)
797 {
798   PetscViewerFormat format;
799   PetscErrorCode    ierr;
800 
801   PetscFunctionBegin;
802   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
803   ierr = PetscViewerASCIIPrintf(viewer, "Superbee Slope Limiter:\n");CHKERRQ(ierr);
804   PetscFunctionReturn(0);
805 }
806 
807 static PetscErrorCode PetscLimiterView_Superbee(PetscLimiter lim, PetscViewer viewer)
808 {
809   PetscBool      iascii;
810   PetscErrorCode ierr;
811 
812   PetscFunctionBegin;
813   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
814   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
815   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
816   if (iascii) {ierr = PetscLimiterView_Superbee_Ascii(lim, viewer);CHKERRQ(ierr);}
817   PetscFunctionReturn(0);
818 }
819 
820 static PetscErrorCode PetscLimiterLimit_Superbee(PetscLimiter lim, PetscReal f, PetscReal *phi)
821 {
822   PetscFunctionBegin;
823   *phi = 4*PetscMax(0, PetscMin(f, 1-f));
824   PetscFunctionReturn(0);
825 }
826 
827 static PetscErrorCode PetscLimiterInitialize_Superbee(PetscLimiter lim)
828 {
829   PetscFunctionBegin;
830   lim->ops->view    = PetscLimiterView_Superbee;
831   lim->ops->destroy = PetscLimiterDestroy_Superbee;
832   lim->ops->limit   = PetscLimiterLimit_Superbee;
833   PetscFunctionReturn(0);
834 }
835 
836 /*MC
837   PETSCLIMITERSUPERBEE = "superbee" - A PetscLimiter object
838 
839   Level: intermediate
840 
841 .seealso: PetscLimiterType, PetscLimiterCreate(), PetscLimiterSetType()
842 M*/
843 
844 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_Superbee(PetscLimiter lim)
845 {
846   PetscLimiter_Superbee *l;
847   PetscErrorCode    ierr;
848 
849   PetscFunctionBegin;
850   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
851   ierr      = PetscNewLog(lim, &l);CHKERRQ(ierr);
852   lim->data = l;
853 
854   ierr = PetscLimiterInitialize_Superbee(lim);CHKERRQ(ierr);
855   PetscFunctionReturn(0);
856 }
857 
858 static PetscErrorCode PetscLimiterDestroy_MC(PetscLimiter lim)
859 {
860   PetscLimiter_MC *l = (PetscLimiter_MC *) lim->data;
861   PetscErrorCode    ierr;
862 
863   PetscFunctionBegin;
864   ierr = PetscFree(l);CHKERRQ(ierr);
865   PetscFunctionReturn(0);
866 }
867 
868 static PetscErrorCode PetscLimiterView_MC_Ascii(PetscLimiter lim, PetscViewer viewer)
869 {
870   PetscViewerFormat format;
871   PetscErrorCode    ierr;
872 
873   PetscFunctionBegin;
874   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
875   ierr = PetscViewerASCIIPrintf(viewer, "MC Slope Limiter:\n");CHKERRQ(ierr);
876   PetscFunctionReturn(0);
877 }
878 
879 static PetscErrorCode PetscLimiterView_MC(PetscLimiter lim, PetscViewer viewer)
880 {
881   PetscBool      iascii;
882   PetscErrorCode ierr;
883 
884   PetscFunctionBegin;
885   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
886   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
887   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
888   if (iascii) {ierr = PetscLimiterView_MC_Ascii(lim, viewer);CHKERRQ(ierr);}
889   PetscFunctionReturn(0);
890 }
891 
892 /* aka Barth-Jespersen */
893 static PetscErrorCode PetscLimiterLimit_MC(PetscLimiter lim, PetscReal f, PetscReal *phi)
894 {
895   PetscFunctionBegin;
896   *phi = PetscMin(1, 4*PetscMax(0, PetscMin(f, 1-f)));
897   PetscFunctionReturn(0);
898 }
899 
900 static PetscErrorCode PetscLimiterInitialize_MC(PetscLimiter lim)
901 {
902   PetscFunctionBegin;
903   lim->ops->view    = PetscLimiterView_MC;
904   lim->ops->destroy = PetscLimiterDestroy_MC;
905   lim->ops->limit   = PetscLimiterLimit_MC;
906   PetscFunctionReturn(0);
907 }
908 
909 /*MC
910   PETSCLIMITERMC = "mc" - A PetscLimiter object
911 
912   Level: intermediate
913 
914 .seealso: PetscLimiterType, PetscLimiterCreate(), PetscLimiterSetType()
915 M*/
916 
917 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_MC(PetscLimiter lim)
918 {
919   PetscLimiter_MC *l;
920   PetscErrorCode    ierr;
921 
922   PetscFunctionBegin;
923   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1);
924   ierr      = PetscNewLog(lim, &l);CHKERRQ(ierr);
925   lim->data = l;
926 
927   ierr = PetscLimiterInitialize_MC(lim);CHKERRQ(ierr);
928   PetscFunctionReturn(0);
929 }
930 
931 PetscClassId PETSCFV_CLASSID = 0;
932 
933 PetscFunctionList PetscFVList              = NULL;
934 PetscBool         PetscFVRegisterAllCalled = PETSC_FALSE;
935 
936 /*@C
937   PetscFVRegister - Adds a new PetscFV implementation
938 
939   Not Collective
940 
941   Input Parameters:
942 + name        - The name of a new user-defined creation routine
943 - create_func - The creation routine itself
944 
945   Notes:
946   PetscFVRegister() may be called multiple times to add several user-defined PetscFVs
947 
948   Sample usage:
949 .vb
950     PetscFVRegister("my_fv", MyPetscFVCreate);
951 .ve
952 
953   Then, your PetscFV type can be chosen with the procedural interface via
954 .vb
955     PetscFVCreate(MPI_Comm, PetscFV *);
956     PetscFVSetType(PetscFV, "my_fv");
957 .ve
958    or at runtime via the option
959 .vb
960     -petscfv_type my_fv
961 .ve
962 
963   Level: advanced
964 
965 .seealso: PetscFVRegisterAll(), PetscFVRegisterDestroy()
966 
967 @*/
968 PetscErrorCode PetscFVRegister(const char sname[], PetscErrorCode (*function)(PetscFV))
969 {
970   PetscErrorCode ierr;
971 
972   PetscFunctionBegin;
973   ierr = PetscFunctionListAdd(&PetscFVList, sname, function);CHKERRQ(ierr);
974   PetscFunctionReturn(0);
975 }
976 
977 /*@C
978   PetscFVSetType - Builds a particular PetscFV
979 
980   Collective on fvm
981 
982   Input Parameters:
983 + fvm  - The PetscFV object
984 - name - The kind of FVM space
985 
986   Options Database Key:
987 . -petscfv_type <type> - Sets the PetscFV type; use -help for a list of available types
988 
989   Level: intermediate
990 
991 .seealso: PetscFVGetType(), PetscFVCreate()
992 @*/
993 PetscErrorCode PetscFVSetType(PetscFV fvm, PetscFVType name)
994 {
995   PetscErrorCode (*r)(PetscFV);
996   PetscBool      match;
997   PetscErrorCode ierr;
998 
999   PetscFunctionBegin;
1000   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1001   ierr = PetscObjectTypeCompare((PetscObject) fvm, name, &match);CHKERRQ(ierr);
1002   if (match) PetscFunctionReturn(0);
1003 
1004   ierr = PetscFVRegisterAll();CHKERRQ(ierr);
1005   ierr = PetscFunctionListFind(PetscFVList, name, &r);CHKERRQ(ierr);
1006   if (!r) SETERRQ1(PetscObjectComm((PetscObject) fvm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscFV type: %s", name);
1007 
1008   if (fvm->ops->destroy) {
1009     ierr              = (*fvm->ops->destroy)(fvm);CHKERRQ(ierr);
1010     fvm->ops->destroy = NULL;
1011   }
1012   ierr = (*r)(fvm);CHKERRQ(ierr);
1013   ierr = PetscObjectChangeTypeName((PetscObject) fvm, name);CHKERRQ(ierr);
1014   PetscFunctionReturn(0);
1015 }
1016 
1017 /*@C
1018   PetscFVGetType - Gets the PetscFV type name (as a string) from the object.
1019 
1020   Not Collective
1021 
1022   Input Parameter:
1023 . fvm  - The PetscFV
1024 
1025   Output Parameter:
1026 . name - The PetscFV type name
1027 
1028   Level: intermediate
1029 
1030 .seealso: PetscFVSetType(), PetscFVCreate()
1031 @*/
1032 PetscErrorCode PetscFVGetType(PetscFV fvm, PetscFVType *name)
1033 {
1034   PetscErrorCode ierr;
1035 
1036   PetscFunctionBegin;
1037   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1038   PetscValidPointer(name, 2);
1039   ierr = PetscFVRegisterAll();CHKERRQ(ierr);
1040   *name = ((PetscObject) fvm)->type_name;
1041   PetscFunctionReturn(0);
1042 }
1043 
1044 /*@C
1045    PetscFVViewFromOptions - View from Options
1046 
1047    Collective on PetscFV
1048 
1049    Input Parameters:
1050 +  A - the PetscFV object
1051 .  obj - Optional object
1052 -  name - command line option
1053 
1054    Level: intermediate
1055 .seealso:  PetscFV, PetscFVView, PetscObjectViewFromOptions(), PetscFVCreate()
1056 @*/
1057 PetscErrorCode  PetscFVViewFromOptions(PetscFV A,PetscObject obj,const char name[])
1058 {
1059   PetscErrorCode ierr;
1060 
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(A,PETSCFV_CLASSID,1);
1063   ierr = PetscObjectViewFromOptions((PetscObject)A,obj,name);CHKERRQ(ierr);
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 /*@C
1068   PetscFVView - Views a PetscFV
1069 
1070   Collective on fvm
1071 
1072   Input Parameter:
1073 + fvm - the PetscFV object to view
1074 - v   - the viewer
1075 
1076   Level: beginner
1077 
1078 .seealso: PetscFVDestroy()
1079 @*/
1080 PetscErrorCode PetscFVView(PetscFV fvm, PetscViewer v)
1081 {
1082   PetscErrorCode ierr;
1083 
1084   PetscFunctionBegin;
1085   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1086   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) fvm), &v);CHKERRQ(ierr);}
1087   if (fvm->ops->view) {ierr = (*fvm->ops->view)(fvm, v);CHKERRQ(ierr);}
1088   PetscFunctionReturn(0);
1089 }
1090 
1091 /*@
1092   PetscFVSetFromOptions - sets parameters in a PetscFV from the options database
1093 
1094   Collective on fvm
1095 
1096   Input Parameter:
1097 . fvm - the PetscFV object to set options for
1098 
1099   Options Database Key:
1100 . -petscfv_compute_gradients <bool> - Determines whether cell gradients are calculated
1101 
1102   Level: intermediate
1103 
1104 .seealso: PetscFVView()
1105 @*/
1106 PetscErrorCode PetscFVSetFromOptions(PetscFV fvm)
1107 {
1108   const char    *defaultType;
1109   char           name[256];
1110   PetscBool      flg;
1111   PetscErrorCode ierr;
1112 
1113   PetscFunctionBegin;
1114   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1115   if (!((PetscObject) fvm)->type_name) defaultType = PETSCFVUPWIND;
1116   else                                 defaultType = ((PetscObject) fvm)->type_name;
1117   ierr = PetscFVRegisterAll();CHKERRQ(ierr);
1118 
1119   ierr = PetscObjectOptionsBegin((PetscObject) fvm);CHKERRQ(ierr);
1120   ierr = PetscOptionsFList("-petscfv_type", "Finite volume discretization", "PetscFVSetType", PetscFVList, defaultType, name, 256, &flg);CHKERRQ(ierr);
1121   if (flg) {
1122     ierr = PetscFVSetType(fvm, name);CHKERRQ(ierr);
1123   } else if (!((PetscObject) fvm)->type_name) {
1124     ierr = PetscFVSetType(fvm, defaultType);CHKERRQ(ierr);
1125 
1126   }
1127   ierr = PetscOptionsBool("-petscfv_compute_gradients", "Compute cell gradients", "PetscFVSetComputeGradients", fvm->computeGradients, &fvm->computeGradients, NULL);CHKERRQ(ierr);
1128   if (fvm->ops->setfromoptions) {ierr = (*fvm->ops->setfromoptions)(fvm);CHKERRQ(ierr);}
1129   /* process any options handlers added with PetscObjectAddOptionsHandler() */
1130   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) fvm);CHKERRQ(ierr);
1131   ierr = PetscLimiterSetFromOptions(fvm->limiter);CHKERRQ(ierr);
1132   ierr = PetscOptionsEnd();CHKERRQ(ierr);
1133   ierr = PetscFVViewFromOptions(fvm, NULL, "-petscfv_view");CHKERRQ(ierr);
1134   PetscFunctionReturn(0);
1135 }
1136 
1137 /*@
1138   PetscFVSetUp - Construct data structures for the PetscFV
1139 
1140   Collective on fvm
1141 
1142   Input Parameter:
1143 . fvm - the PetscFV object to setup
1144 
1145   Level: intermediate
1146 
1147 .seealso: PetscFVView(), PetscFVDestroy()
1148 @*/
1149 PetscErrorCode PetscFVSetUp(PetscFV fvm)
1150 {
1151   PetscErrorCode ierr;
1152 
1153   PetscFunctionBegin;
1154   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1155   ierr = PetscLimiterSetUp(fvm->limiter);CHKERRQ(ierr);
1156   if (fvm->ops->setup) {ierr = (*fvm->ops->setup)(fvm);CHKERRQ(ierr);}
1157   PetscFunctionReturn(0);
1158 }
1159 
1160 /*@
1161   PetscFVDestroy - Destroys a PetscFV object
1162 
1163   Collective on fvm
1164 
1165   Input Parameter:
1166 . fvm - the PetscFV object to destroy
1167 
1168   Level: beginner
1169 
1170 .seealso: PetscFVView()
1171 @*/
1172 PetscErrorCode PetscFVDestroy(PetscFV *fvm)
1173 {
1174   PetscInt       i;
1175   PetscErrorCode ierr;
1176 
1177   PetscFunctionBegin;
1178   if (!*fvm) PetscFunctionReturn(0);
1179   PetscValidHeaderSpecific((*fvm), PETSCFV_CLASSID, 1);
1180 
1181   if (--((PetscObject)(*fvm))->refct > 0) {*fvm = 0; PetscFunctionReturn(0);}
1182   ((PetscObject) (*fvm))->refct = 0;
1183 
1184   for (i = 0; i < (*fvm)->numComponents; i++) {
1185     ierr = PetscFree((*fvm)->componentNames[i]);CHKERRQ(ierr);
1186   }
1187   ierr = PetscFree((*fvm)->componentNames);CHKERRQ(ierr);
1188   ierr = PetscLimiterDestroy(&(*fvm)->limiter);CHKERRQ(ierr);
1189   ierr = PetscDualSpaceDestroy(&(*fvm)->dualSpace);CHKERRQ(ierr);
1190   ierr = PetscFree((*fvm)->fluxWork);CHKERRQ(ierr);
1191   ierr = PetscQuadratureDestroy(&(*fvm)->quadrature);CHKERRQ(ierr);
1192   ierr = PetscFVRestoreTabulation((*fvm), 0, NULL, &(*fvm)->B, &(*fvm)->D, NULL /*&(*fvm)->H*/);CHKERRQ(ierr);
1193 
1194   if ((*fvm)->ops->destroy) {ierr = (*(*fvm)->ops->destroy)(*fvm);CHKERRQ(ierr);}
1195   ierr = PetscHeaderDestroy(fvm);CHKERRQ(ierr);
1196   PetscFunctionReturn(0);
1197 }
1198 
1199 /*@
1200   PetscFVCreate - Creates an empty PetscFV object. The type can then be set with PetscFVSetType().
1201 
1202   Collective
1203 
1204   Input Parameter:
1205 . comm - The communicator for the PetscFV object
1206 
1207   Output Parameter:
1208 . fvm - The PetscFV object
1209 
1210   Level: beginner
1211 
1212 .seealso: PetscFVSetType(), PETSCFVUPWIND
1213 @*/
1214 PetscErrorCode PetscFVCreate(MPI_Comm comm, PetscFV *fvm)
1215 {
1216   PetscFV        f;
1217   PetscErrorCode ierr;
1218 
1219   PetscFunctionBegin;
1220   PetscValidPointer(fvm, 2);
1221   *fvm = NULL;
1222   ierr = PetscFVInitializePackage();CHKERRQ(ierr);
1223 
1224   ierr = PetscHeaderCreate(f, PETSCFV_CLASSID, "PetscFV", "Finite Volume", "PetscFV", comm, PetscFVDestroy, PetscFVView);CHKERRQ(ierr);
1225   ierr = PetscMemzero(f->ops, sizeof(struct _PetscFVOps));CHKERRQ(ierr);
1226 
1227   ierr = PetscLimiterCreate(comm, &f->limiter);CHKERRQ(ierr);
1228   f->numComponents    = 1;
1229   f->dim              = 0;
1230   f->computeGradients = PETSC_FALSE;
1231   f->fluxWork         = NULL;
1232   ierr = PetscCalloc1(f->numComponents,&f->componentNames);CHKERRQ(ierr);
1233 
1234   *fvm = f;
1235   PetscFunctionReturn(0);
1236 }
1237 
1238 /*@
1239   PetscFVSetLimiter - Set the limiter object
1240 
1241   Logically collective on fvm
1242 
1243   Input Parameters:
1244 + fvm - the PetscFV object
1245 - lim - The PetscLimiter
1246 
1247   Level: intermediate
1248 
1249 .seealso: PetscFVGetLimiter()
1250 @*/
1251 PetscErrorCode PetscFVSetLimiter(PetscFV fvm, PetscLimiter lim)
1252 {
1253   PetscErrorCode ierr;
1254 
1255   PetscFunctionBegin;
1256   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1257   PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 2);
1258   ierr = PetscLimiterDestroy(&fvm->limiter);CHKERRQ(ierr);
1259   ierr = PetscObjectReference((PetscObject) lim);CHKERRQ(ierr);
1260   fvm->limiter = lim;
1261   PetscFunctionReturn(0);
1262 }
1263 
1264 /*@
1265   PetscFVGetLimiter - Get the limiter object
1266 
1267   Not collective
1268 
1269   Input Parameter:
1270 . fvm - the PetscFV object
1271 
1272   Output Parameter:
1273 . lim - The PetscLimiter
1274 
1275   Level: intermediate
1276 
1277 .seealso: PetscFVSetLimiter()
1278 @*/
1279 PetscErrorCode PetscFVGetLimiter(PetscFV fvm, PetscLimiter *lim)
1280 {
1281   PetscFunctionBegin;
1282   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1283   PetscValidPointer(lim, 2);
1284   *lim = fvm->limiter;
1285   PetscFunctionReturn(0);
1286 }
1287 
1288 /*@
1289   PetscFVSetNumComponents - Set the number of field components
1290 
1291   Logically collective on fvm
1292 
1293   Input Parameters:
1294 + fvm - the PetscFV object
1295 - comp - The number of components
1296 
1297   Level: intermediate
1298 
1299 .seealso: PetscFVGetNumComponents()
1300 @*/
1301 PetscErrorCode PetscFVSetNumComponents(PetscFV fvm, PetscInt comp)
1302 {
1303   PetscErrorCode ierr;
1304 
1305   PetscFunctionBegin;
1306   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1307   if (fvm->numComponents != comp) {
1308     PetscInt i;
1309 
1310     for (i = 0; i < fvm->numComponents; i++) {
1311       ierr = PetscFree(fvm->componentNames[i]);CHKERRQ(ierr);
1312     }
1313     ierr = PetscFree(fvm->componentNames);CHKERRQ(ierr);
1314     ierr = PetscCalloc1(comp,&fvm->componentNames);CHKERRQ(ierr);
1315   }
1316   fvm->numComponents = comp;
1317   ierr = PetscFree(fvm->fluxWork);CHKERRQ(ierr);
1318   ierr = PetscMalloc1(comp, &fvm->fluxWork);CHKERRQ(ierr);
1319   PetscFunctionReturn(0);
1320 }
1321 
1322 /*@
1323   PetscFVGetNumComponents - Get the number of field components
1324 
1325   Not collective
1326 
1327   Input Parameter:
1328 . fvm - the PetscFV object
1329 
1330   Output Parameter:
1331 , comp - The number of components
1332 
1333   Level: intermediate
1334 
1335 .seealso: PetscFVSetNumComponents()
1336 @*/
1337 PetscErrorCode PetscFVGetNumComponents(PetscFV fvm, PetscInt *comp)
1338 {
1339   PetscFunctionBegin;
1340   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1341   PetscValidPointer(comp, 2);
1342   *comp = fvm->numComponents;
1343   PetscFunctionReturn(0);
1344 }
1345 
1346 /*@C
1347   PetscFVSetComponentName - Set the name of a component (used in output and viewing)
1348 
1349   Logically collective on fvm
1350   Input Parameters:
1351 + fvm - the PetscFV object
1352 . comp - the component number
1353 - name - the component name
1354 
1355   Level: intermediate
1356 
1357 .seealso: PetscFVGetComponentName()
1358 @*/
1359 PetscErrorCode PetscFVSetComponentName(PetscFV fvm, PetscInt comp, const char *name)
1360 {
1361   PetscErrorCode ierr;
1362 
1363   PetscFunctionBegin;
1364   ierr = PetscFree(fvm->componentNames[comp]);CHKERRQ(ierr);
1365   ierr = PetscStrallocpy(name,&fvm->componentNames[comp]);CHKERRQ(ierr);
1366   PetscFunctionReturn(0);
1367 }
1368 
1369 /*@C
1370   PetscFVGetComponentName - Get the name of a component (used in output and viewing)
1371 
1372   Logically collective on fvm
1373   Input Parameters:
1374 + fvm - the PetscFV object
1375 - comp - the component number
1376 
1377   Output Parameter:
1378 . name - the component name
1379 
1380   Level: intermediate
1381 
1382 .seealso: PetscFVSetComponentName()
1383 @*/
1384 PetscErrorCode PetscFVGetComponentName(PetscFV fvm, PetscInt comp, const char **name)
1385 {
1386   PetscFunctionBegin;
1387   *name = fvm->componentNames[comp];
1388   PetscFunctionReturn(0);
1389 }
1390 
1391 /*@
1392   PetscFVSetSpatialDimension - Set the spatial dimension
1393 
1394   Logically collective on fvm
1395 
1396   Input Parameters:
1397 + fvm - the PetscFV object
1398 - dim - The spatial dimension
1399 
1400   Level: intermediate
1401 
1402 .seealso: PetscFVGetSpatialDimension()
1403 @*/
1404 PetscErrorCode PetscFVSetSpatialDimension(PetscFV fvm, PetscInt dim)
1405 {
1406   PetscFunctionBegin;
1407   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1408   fvm->dim = dim;
1409   PetscFunctionReturn(0);
1410 }
1411 
1412 /*@
1413   PetscFVGetSpatialDimension - Get the spatial dimension
1414 
1415   Logically collective on fvm
1416 
1417   Input Parameter:
1418 . fvm - the PetscFV object
1419 
1420   Output Parameter:
1421 . dim - The spatial dimension
1422 
1423   Level: intermediate
1424 
1425 .seealso: PetscFVSetSpatialDimension()
1426 @*/
1427 PetscErrorCode PetscFVGetSpatialDimension(PetscFV fvm, PetscInt *dim)
1428 {
1429   PetscFunctionBegin;
1430   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1431   PetscValidPointer(dim, 2);
1432   *dim = fvm->dim;
1433   PetscFunctionReturn(0);
1434 }
1435 
1436 /*@
1437   PetscFVSetComputeGradients - Toggle computation of cell gradients
1438 
1439   Logically collective on fvm
1440 
1441   Input Parameters:
1442 + fvm - the PetscFV object
1443 - computeGradients - Flag to compute cell gradients
1444 
1445   Level: intermediate
1446 
1447 .seealso: PetscFVGetComputeGradients()
1448 @*/
1449 PetscErrorCode PetscFVSetComputeGradients(PetscFV fvm, PetscBool computeGradients)
1450 {
1451   PetscFunctionBegin;
1452   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1453   fvm->computeGradients = computeGradients;
1454   PetscFunctionReturn(0);
1455 }
1456 
1457 /*@
1458   PetscFVGetComputeGradients - Return flag for computation of cell gradients
1459 
1460   Not collective
1461 
1462   Input Parameter:
1463 . fvm - the PetscFV object
1464 
1465   Output Parameter:
1466 . computeGradients - Flag to compute cell gradients
1467 
1468   Level: intermediate
1469 
1470 .seealso: PetscFVSetComputeGradients()
1471 @*/
1472 PetscErrorCode PetscFVGetComputeGradients(PetscFV fvm, PetscBool *computeGradients)
1473 {
1474   PetscFunctionBegin;
1475   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1476   PetscValidPointer(computeGradients, 2);
1477   *computeGradients = fvm->computeGradients;
1478   PetscFunctionReturn(0);
1479 }
1480 
1481 /*@
1482   PetscFVSetQuadrature - Set the quadrature object
1483 
1484   Logically collective on fvm
1485 
1486   Input Parameters:
1487 + fvm - the PetscFV object
1488 - q - The PetscQuadrature
1489 
1490   Level: intermediate
1491 
1492 .seealso: PetscFVGetQuadrature()
1493 @*/
1494 PetscErrorCode PetscFVSetQuadrature(PetscFV fvm, PetscQuadrature q)
1495 {
1496   PetscErrorCode ierr;
1497 
1498   PetscFunctionBegin;
1499   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1500   ierr = PetscQuadratureDestroy(&fvm->quadrature);CHKERRQ(ierr);
1501   ierr = PetscObjectReference((PetscObject) q);CHKERRQ(ierr);
1502   fvm->quadrature = q;
1503   PetscFunctionReturn(0);
1504 }
1505 
1506 /*@
1507   PetscFVGetQuadrature - Get the quadrature object
1508 
1509   Not collective
1510 
1511   Input Parameter:
1512 . fvm - the PetscFV object
1513 
1514   Output Parameter:
1515 . lim - The PetscQuadrature
1516 
1517   Level: intermediate
1518 
1519 .seealso: PetscFVSetQuadrature()
1520 @*/
1521 PetscErrorCode PetscFVGetQuadrature(PetscFV fvm, PetscQuadrature *q)
1522 {
1523   PetscFunctionBegin;
1524   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1525   PetscValidPointer(q, 2);
1526   if (!fvm->quadrature) {
1527     /* Create default 1-point quadrature */
1528     PetscReal     *points, *weights;
1529     PetscErrorCode ierr;
1530 
1531     ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &fvm->quadrature);CHKERRQ(ierr);
1532     ierr = PetscCalloc1(fvm->dim, &points);CHKERRQ(ierr);
1533     ierr = PetscMalloc1(1, &weights);CHKERRQ(ierr);
1534     weights[0] = 1.0;
1535     ierr = PetscQuadratureSetData(fvm->quadrature, fvm->dim, 1, 1, points, weights);CHKERRQ(ierr);
1536   }
1537   *q = fvm->quadrature;
1538   PetscFunctionReturn(0);
1539 }
1540 
1541 /*@
1542   PetscFVGetDualSpace - Returns the PetscDualSpace used to define the inner product
1543 
1544   Not collective
1545 
1546   Input Parameter:
1547 . fvm - The PetscFV object
1548 
1549   Output Parameter:
1550 . sp - The PetscDualSpace object
1551 
1552   Note: A simple dual space is provided automatically, and the user typically will not need to override it.
1553 
1554   Level: intermediate
1555 
1556 .seealso: PetscFVCreate()
1557 @*/
1558 PetscErrorCode PetscFVGetDualSpace(PetscFV fvm, PetscDualSpace *sp)
1559 {
1560   PetscFunctionBegin;
1561   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1562   PetscValidPointer(sp, 2);
1563   if (!fvm->dualSpace) {
1564     DM              K;
1565     PetscInt        dim, Nc, c;
1566     PetscErrorCode  ierr;
1567 
1568     ierr = PetscFVGetSpatialDimension(fvm, &dim);CHKERRQ(ierr);
1569     ierr = PetscFVGetNumComponents(fvm, &Nc);CHKERRQ(ierr);
1570     ierr = PetscDualSpaceCreate(PetscObjectComm((PetscObject) fvm), &fvm->dualSpace);CHKERRQ(ierr);
1571     ierr = PetscDualSpaceSetType(fvm->dualSpace, PETSCDUALSPACESIMPLE);CHKERRQ(ierr);
1572     ierr = PetscDualSpaceCreateReferenceCell(fvm->dualSpace, dim, PETSC_FALSE, &K);CHKERRQ(ierr); /* TODO: The reference cell type should be held by the discretization object */
1573     ierr = PetscDualSpaceSetNumComponents(fvm->dualSpace, Nc);CHKERRQ(ierr);
1574     ierr = PetscDualSpaceSetDM(fvm->dualSpace, K);CHKERRQ(ierr);
1575     ierr = DMDestroy(&K);CHKERRQ(ierr);
1576     ierr = PetscDualSpaceSimpleSetDimension(fvm->dualSpace, Nc);CHKERRQ(ierr);
1577     /* Should we be using PetscFVGetQuadrature() here? */
1578     for (c = 0; c < Nc; ++c) {
1579       PetscQuadrature qc;
1580       PetscReal      *points, *weights;
1581       PetscErrorCode  ierr;
1582 
1583       ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &qc);CHKERRQ(ierr);
1584       ierr = PetscCalloc1(dim, &points);CHKERRQ(ierr);
1585       ierr = PetscCalloc1(Nc, &weights);CHKERRQ(ierr);
1586       weights[c] = 1.0;
1587       ierr = PetscQuadratureSetData(qc, dim, Nc, 1, points, weights);CHKERRQ(ierr);
1588       ierr = PetscDualSpaceSimpleSetFunctional(fvm->dualSpace, c, qc);CHKERRQ(ierr);
1589       ierr = PetscQuadratureDestroy(&qc);CHKERRQ(ierr);
1590     }
1591   }
1592   *sp = fvm->dualSpace;
1593   PetscFunctionReturn(0);
1594 }
1595 
1596 /*@
1597   PetscFVSetDualSpace - Sets the PetscDualSpace used to define the inner product
1598 
1599   Not collective
1600 
1601   Input Parameters:
1602 + fvm - The PetscFV object
1603 - sp  - The PetscDualSpace object
1604 
1605   Level: intermediate
1606 
1607   Note: A simple dual space is provided automatically, and the user typically will not need to override it.
1608 
1609 .seealso: PetscFVCreate()
1610 @*/
1611 PetscErrorCode PetscFVSetDualSpace(PetscFV fvm, PetscDualSpace sp)
1612 {
1613   PetscErrorCode ierr;
1614 
1615   PetscFunctionBegin;
1616   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1617   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 2);
1618   ierr = PetscDualSpaceDestroy(&fvm->dualSpace);CHKERRQ(ierr);
1619   fvm->dualSpace = sp;
1620   ierr = PetscObjectReference((PetscObject) fvm->dualSpace);CHKERRQ(ierr);
1621   PetscFunctionReturn(0);
1622 }
1623 
1624 /*@C
1625   PetscFVGetDefaultTabulation - Returns the tabulation of the basis functions at the quadrature points
1626 
1627   Not collective
1628 
1629   Input Parameter:
1630 . fvm - The PetscFV object
1631 
1632   Output Parameters:
1633 + B - The basis function values at quadrature points
1634 . D - The basis function derivatives at quadrature points
1635 - H - The basis function second derivatives at quadrature points
1636 
1637   Note:
1638 $ B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c
1639 $ D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d
1640 $ H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e
1641 
1642   Level: intermediate
1643 
1644 .seealso: PetscFEGetDefaultTabulation(), PetscFEGetTabulation(), PetscFERestoreTabulation(), PetscFVGetQuadrature(), PetscQuadratureGetData()
1645 @*/
1646 PetscErrorCode PetscFVGetDefaultTabulation(PetscFV fvm, PetscReal **B, PetscReal **D, PetscReal **H)
1647 {
1648   PetscInt         npoints;
1649   const PetscReal *points;
1650   PetscErrorCode   ierr;
1651 
1652   PetscFunctionBegin;
1653   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1654   if (B) PetscValidPointer(B, 2);
1655   if (D) PetscValidPointer(D, 3);
1656   if (H) PetscValidPointer(H, 4);
1657   ierr = PetscQuadratureGetData(fvm->quadrature, NULL, NULL, &npoints, &points, NULL);CHKERRQ(ierr);
1658   if (!fvm->B) {ierr = PetscFVGetTabulation(fvm, npoints, points, &fvm->B, &fvm->D, NULL/*&fvm->H*/);CHKERRQ(ierr);}
1659   if (B) *B = fvm->B;
1660   if (D) *D = fvm->D;
1661   if (H) *H = fvm->H;
1662   PetscFunctionReturn(0);
1663 }
1664 
1665 /*@C
1666   PetscFVGetTabulation - Tabulates the basis functions, and perhaps derivatives, at the points provided.
1667 
1668   Not collective
1669 
1670   Input Parameters:
1671 + fvm     - The PetscFV object
1672 . npoints - The number of tabulation points
1673 - points  - The tabulation point coordinates
1674 
1675   Output Parameters:
1676 + B - The basis function values at tabulation points
1677 . D - The basis function derivatives at tabulation points
1678 - H - The basis function second derivatives at tabulation points
1679 
1680   Note:
1681 $ B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c
1682 $ D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d
1683 $ H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e
1684 
1685   Level: intermediate
1686 
1687 .seealso: PetscFEGetTabulation(), PetscFERestoreTabulation(), PetscFEGetDefaultTabulation()
1688 @*/
1689 PetscErrorCode PetscFVGetTabulation(PetscFV fvm, PetscInt npoints, const PetscReal points[], PetscReal **B, PetscReal **D, PetscReal **H)
1690 {
1691   PetscInt         pdim = 1; /* Dimension of approximation space P */
1692   PetscInt         dim;      /* Spatial dimension */
1693   PetscInt         comp;     /* Field components */
1694   PetscInt         p, d, c, e;
1695   PetscErrorCode   ierr;
1696 
1697   PetscFunctionBegin;
1698   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1699   PetscValidPointer(points, 3);
1700   if (B) PetscValidPointer(B, 4);
1701   if (D) PetscValidPointer(D, 5);
1702   if (H) PetscValidPointer(H, 6);
1703   ierr = PetscFVGetSpatialDimension(fvm, &dim);CHKERRQ(ierr);
1704   ierr = PetscFVGetNumComponents(fvm, &comp);CHKERRQ(ierr);
1705   if (B) {ierr = PetscMalloc1(npoints*pdim*comp, B);CHKERRQ(ierr);}
1706   if (D) {ierr = PetscMalloc1(npoints*pdim*comp*dim, D);CHKERRQ(ierr);}
1707   if (H) {ierr = PetscMalloc1(npoints*pdim*comp*dim*dim, H);CHKERRQ(ierr);}
1708   if (B) {for (p = 0; p < npoints; ++p) for (d = 0; d < pdim; ++d) for (c = 0; c < comp; ++c) (*B)[(p*pdim + d)*comp + c] = 1.0;}
1709   if (D) {for (p = 0; p < npoints; ++p) for (d = 0; d < pdim; ++d) for (c = 0; c < comp; ++c) for (e = 0; e < dim; ++e) (*D)[((p*pdim + d)*comp + c)*dim + e] = 0.0;}
1710   if (H) {for (p = 0; p < npoints; ++p) for (d = 0; d < pdim; ++d) for (c = 0; c < comp; ++c) for (e = 0; e < dim*dim; ++e) (*H)[((p*pdim + d)*comp + c)*dim*dim + e] = 0.0;}
1711   PetscFunctionReturn(0);
1712 }
1713 
1714 /*@C
1715   PetscFVRestoreTabulation - Frees memory from the associated tabulation.
1716 
1717   Not collective
1718 
1719   Input Parameters:
1720 + fvm     - The PetscFV object
1721 . npoints - The number of tabulation points
1722 . points  - The tabulation point coordinates
1723 . B - The basis function values at tabulation points
1724 . D - The basis function derivatives at tabulation points
1725 - H - The basis function second derivatives at tabulation points
1726 
1727   Note:
1728 $ B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c
1729 $ D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d
1730 $ H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e
1731 
1732   Level: intermediate
1733 
1734 .seealso: PetscFVGetTabulation(), PetscFVGetDefaultTabulation()
1735 @*/
1736 PetscErrorCode PetscFVRestoreTabulation(PetscFV fvm, PetscInt npoints, const PetscReal points[], PetscReal **B, PetscReal **D, PetscReal **H)
1737 {
1738   PetscErrorCode ierr;
1739 
1740   PetscFunctionBegin;
1741   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1742   if (B && *B) {ierr = PetscFree(*B);CHKERRQ(ierr);}
1743   if (D && *D) {ierr = PetscFree(*D);CHKERRQ(ierr);}
1744   if (H && *H) {ierr = PetscFree(*H);CHKERRQ(ierr);}
1745   PetscFunctionReturn(0);
1746 }
1747 
1748 /*@C
1749   PetscFVComputeGradient - Compute the gradient reconstruction matrix for a given cell
1750 
1751   Input Parameters:
1752 + fvm      - The PetscFV object
1753 . numFaces - The number of cell faces which are not constrained
1754 - dx       - The vector from the cell centroid to the neighboring cell centroid for each face
1755 
1756   Level: advanced
1757 
1758 .seealso: PetscFVCreate()
1759 @*/
1760 PetscErrorCode PetscFVComputeGradient(PetscFV fvm, PetscInt numFaces, PetscScalar dx[], PetscScalar grad[])
1761 {
1762   PetscErrorCode ierr;
1763 
1764   PetscFunctionBegin;
1765   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1766   if (fvm->ops->computegradient) {ierr = (*fvm->ops->computegradient)(fvm, numFaces, dx, grad);CHKERRQ(ierr);}
1767   PetscFunctionReturn(0);
1768 }
1769 
1770 /*@C
1771   PetscFVIntegrateRHSFunction - Produce the cell residual vector for a chunk of elements by quadrature integration
1772 
1773   Not collective
1774 
1775   Input Parameters:
1776 + fvm          - The PetscFV object for the field being integrated
1777 . prob         - The PetscDS specifing the discretizations and continuum functions
1778 . field        - The field being integrated
1779 . Nf           - The number of faces in the chunk
1780 . fgeom        - The face geometry for each face in the chunk
1781 . neighborVol  - The volume for each pair of cells in the chunk
1782 . uL           - The state from the cell on the left
1783 - uR           - The state from the cell on the right
1784 
1785   Output Parameter
1786 + fluxL        - the left fluxes for each face
1787 - fluxR        - the right fluxes for each face
1788 
1789   Level: developer
1790 
1791 .seealso: PetscFVCreate()
1792 @*/
1793 PetscErrorCode PetscFVIntegrateRHSFunction(PetscFV fvm, PetscDS prob, PetscInt field, PetscInt Nf, PetscFVFaceGeom *fgeom, PetscReal *neighborVol,
1794                                            PetscScalar uL[], PetscScalar uR[], PetscScalar fluxL[], PetscScalar fluxR[])
1795 {
1796   PetscErrorCode ierr;
1797 
1798   PetscFunctionBegin;
1799   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1800   if (fvm->ops->integraterhsfunction) {ierr = (*fvm->ops->integraterhsfunction)(fvm, prob, field, Nf, fgeom, neighborVol, uL, uR, fluxL, fluxR);CHKERRQ(ierr);}
1801   PetscFunctionReturn(0);
1802 }
1803 
1804 /*@
1805   PetscFVRefine - Create a "refined" PetscFV object that refines the reference cell into smaller copies. This is typically used
1806   to precondition a higher order method with a lower order method on a refined mesh having the same number of dofs (but more
1807   sparsity). It is also used to create an interpolation between regularly refined meshes.
1808 
1809   Input Parameter:
1810 . fv - The initial PetscFV
1811 
1812   Output Parameter:
1813 . fvRef - The refined PetscFV
1814 
1815   Level: advanced
1816 
1817 .seealso: PetscFVType, PetscFVCreate(), PetscFVSetType()
1818 @*/
1819 PetscErrorCode PetscFVRefine(PetscFV fv, PetscFV *fvRef)
1820 {
1821   PetscDualSpace   Q, Qref;
1822   DM               K, Kref;
1823   PetscQuadrature  q, qref;
1824   CellRefiner      cellRefiner;
1825   PetscReal       *v0;
1826   PetscReal       *jac, *invjac;
1827   PetscInt         numComp, numSubelements, s;
1828   PetscErrorCode   ierr;
1829 
1830   PetscFunctionBegin;
1831   ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr);
1832   ierr = PetscFVGetQuadrature(fv, &q);CHKERRQ(ierr);
1833   ierr = PetscDualSpaceGetDM(Q, &K);CHKERRQ(ierr);
1834   /* Create dual space */
1835   ierr = PetscDualSpaceDuplicate(Q, &Qref);CHKERRQ(ierr);
1836   ierr = DMRefine(K, PetscObjectComm((PetscObject) fv), &Kref);CHKERRQ(ierr);
1837   ierr = PetscDualSpaceSetDM(Qref, Kref);CHKERRQ(ierr);
1838   ierr = DMDestroy(&Kref);CHKERRQ(ierr);
1839   ierr = PetscDualSpaceSetUp(Qref);CHKERRQ(ierr);
1840   /* Create volume */
1841   ierr = PetscFVCreate(PetscObjectComm((PetscObject) fv), fvRef);CHKERRQ(ierr);
1842   ierr = PetscFVSetDualSpace(*fvRef, Qref);CHKERRQ(ierr);
1843   ierr = PetscFVGetNumComponents(fv,    &numComp);CHKERRQ(ierr);
1844   ierr = PetscFVSetNumComponents(*fvRef, numComp);CHKERRQ(ierr);
1845   ierr = PetscFVSetUp(*fvRef);CHKERRQ(ierr);
1846   /* Create quadrature */
1847   ierr = DMPlexGetCellRefiner_Internal(K, &cellRefiner);CHKERRQ(ierr);
1848   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubelements, &v0, &jac, &invjac);CHKERRQ(ierr);
1849   ierr = PetscQuadratureExpandComposite(q, numSubelements, v0, jac, &qref);CHKERRQ(ierr);
1850   ierr = PetscDualSpaceSimpleSetDimension(Qref, numSubelements);CHKERRQ(ierr);
1851   for (s = 0; s < numSubelements; ++s) {
1852     PetscQuadrature  qs;
1853     const PetscReal *points, *weights;
1854     PetscReal       *p, *w;
1855     PetscInt         dim, Nc, npoints, np;
1856 
1857     ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &qs);CHKERRQ(ierr);
1858     ierr = PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights);CHKERRQ(ierr);
1859     np   = npoints/numSubelements;
1860     ierr = PetscMalloc1(np*dim,&p);CHKERRQ(ierr);
1861     ierr = PetscMalloc1(np*Nc,&w);CHKERRQ(ierr);
1862     ierr = PetscArraycpy(p, &points[s*np*dim], np*dim);CHKERRQ(ierr);
1863     ierr = PetscArraycpy(w, &weights[s*np*Nc], np*Nc);CHKERRQ(ierr);
1864     ierr = PetscQuadratureSetData(qs, dim, Nc, np, p, w);CHKERRQ(ierr);
1865     ierr = PetscDualSpaceSimpleSetFunctional(Qref, s, qs);CHKERRQ(ierr);
1866     ierr = PetscQuadratureDestroy(&qs);CHKERRQ(ierr);
1867   }
1868   ierr = CellRefinerRestoreAffineTransforms_Internal(cellRefiner, &numSubelements, &v0, &jac, &invjac);CHKERRQ(ierr);
1869   ierr = PetscFVSetQuadrature(*fvRef, qref);CHKERRQ(ierr);
1870   ierr = PetscQuadratureDestroy(&qref);CHKERRQ(ierr);
1871   ierr = PetscDualSpaceDestroy(&Qref);CHKERRQ(ierr);
1872   PetscFunctionReturn(0);
1873 }
1874 
1875 static PetscErrorCode PetscFVDestroy_Upwind(PetscFV fvm)
1876 {
1877   PetscFV_Upwind *b = (PetscFV_Upwind *) fvm->data;
1878   PetscErrorCode ierr;
1879 
1880   PetscFunctionBegin;
1881   ierr = PetscFree(b);CHKERRQ(ierr);
1882   PetscFunctionReturn(0);
1883 }
1884 
1885 static PetscErrorCode PetscFVView_Upwind_Ascii(PetscFV fv, PetscViewer viewer)
1886 {
1887   PetscInt          Nc, c;
1888   PetscViewerFormat format;
1889   PetscErrorCode    ierr;
1890 
1891   PetscFunctionBegin;
1892   ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
1893   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1894   ierr = PetscViewerASCIIPrintf(viewer, "Upwind Finite Volume:\n");CHKERRQ(ierr);
1895   ierr = PetscViewerASCIIPrintf(viewer, "  num components: %d\n", Nc);CHKERRQ(ierr);
1896   for (c = 0; c < Nc; c++) {
1897     if (fv->componentNames[c]) {
1898       ierr = PetscViewerASCIIPrintf(viewer, "    component %d: %s\n", c, fv->componentNames[c]);CHKERRQ(ierr);
1899     }
1900   }
1901   PetscFunctionReturn(0);
1902 }
1903 
1904 static PetscErrorCode PetscFVView_Upwind(PetscFV fv, PetscViewer viewer)
1905 {
1906   PetscBool      iascii;
1907   PetscErrorCode ierr;
1908 
1909   PetscFunctionBegin;
1910   PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 1);
1911   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1912   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1913   if (iascii) {ierr = PetscFVView_Upwind_Ascii(fv, viewer);CHKERRQ(ierr);}
1914   PetscFunctionReturn(0);
1915 }
1916 
1917 static PetscErrorCode PetscFVSetUp_Upwind(PetscFV fvm)
1918 {
1919   PetscFunctionBegin;
1920   PetscFunctionReturn(0);
1921 }
1922 
1923 /*
1924   neighborVol[f*2+0] contains the left  geom
1925   neighborVol[f*2+1] contains the right geom
1926 */
1927 static PetscErrorCode PetscFVIntegrateRHSFunction_Upwind(PetscFV fvm, PetscDS prob, PetscInt field, PetscInt Nf, PetscFVFaceGeom *fgeom, PetscReal *neighborVol,
1928                                                          PetscScalar uL[], PetscScalar uR[], PetscScalar fluxL[], PetscScalar fluxR[])
1929 {
1930   void             (*riemann)(PetscInt, PetscInt, const PetscReal[], const PetscReal[], const PetscScalar[], const PetscScalar[], PetscInt, const PetscScalar[], PetscScalar[], void *);
1931   void              *rctx;
1932   PetscScalar       *flux = fvm->fluxWork;
1933   const PetscScalar *constants;
1934   PetscInt           dim, numConstants, pdim, totDim, Nc, off, f, d;
1935   PetscErrorCode     ierr;
1936 
1937   PetscFunctionBegin;
1938   ierr = PetscDSGetTotalComponents(prob, &Nc);CHKERRQ(ierr);
1939   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
1940   ierr = PetscDSGetFieldOffset(prob, field, &off);CHKERRQ(ierr);
1941   ierr = PetscDSGetRiemannSolver(prob, field, &riemann);CHKERRQ(ierr);
1942   ierr = PetscDSGetContext(prob, field, &rctx);CHKERRQ(ierr);
1943   ierr = PetscDSGetConstants(prob, &numConstants, &constants);CHKERRQ(ierr);
1944   ierr = PetscFVGetSpatialDimension(fvm, &dim);CHKERRQ(ierr);
1945   ierr = PetscFVGetNumComponents(fvm, &pdim);CHKERRQ(ierr);
1946   for (f = 0; f < Nf; ++f) {
1947     (*riemann)(dim, pdim, fgeom[f].centroid, fgeom[f].normal, &uL[f*Nc], &uR[f*Nc], numConstants, constants, flux, rctx);
1948     for (d = 0; d < pdim; ++d) {
1949       fluxL[f*totDim+off+d] = flux[d] / neighborVol[f*2+0];
1950       fluxR[f*totDim+off+d] = flux[d] / neighborVol[f*2+1];
1951     }
1952   }
1953   PetscFunctionReturn(0);
1954 }
1955 
1956 static PetscErrorCode PetscFVInitialize_Upwind(PetscFV fvm)
1957 {
1958   PetscFunctionBegin;
1959   fvm->ops->setfromoptions          = NULL;
1960   fvm->ops->setup                   = PetscFVSetUp_Upwind;
1961   fvm->ops->view                    = PetscFVView_Upwind;
1962   fvm->ops->destroy                 = PetscFVDestroy_Upwind;
1963   fvm->ops->integraterhsfunction    = PetscFVIntegrateRHSFunction_Upwind;
1964   PetscFunctionReturn(0);
1965 }
1966 
1967 /*MC
1968   PETSCFVUPWIND = "upwind" - A PetscFV object
1969 
1970   Level: intermediate
1971 
1972 .seealso: PetscFVType, PetscFVCreate(), PetscFVSetType()
1973 M*/
1974 
1975 PETSC_EXTERN PetscErrorCode PetscFVCreate_Upwind(PetscFV fvm)
1976 {
1977   PetscFV_Upwind *b;
1978   PetscErrorCode  ierr;
1979 
1980   PetscFunctionBegin;
1981   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
1982   ierr      = PetscNewLog(fvm,&b);CHKERRQ(ierr);
1983   fvm->data = b;
1984 
1985   ierr = PetscFVInitialize_Upwind(fvm);CHKERRQ(ierr);
1986   PetscFunctionReturn(0);
1987 }
1988 
1989 #include <petscblaslapack.h>
1990 
1991 static PetscErrorCode PetscFVDestroy_LeastSquares(PetscFV fvm)
1992 {
1993   PetscFV_LeastSquares *ls = (PetscFV_LeastSquares *) fvm->data;
1994   PetscErrorCode        ierr;
1995 
1996   PetscFunctionBegin;
1997   ierr = PetscObjectComposeFunction((PetscObject) fvm, "PetscFVLeastSquaresSetMaxFaces_C", NULL);CHKERRQ(ierr);
1998   ierr = PetscFree4(ls->B, ls->Binv, ls->tau, ls->work);CHKERRQ(ierr);
1999   ierr = PetscFree(ls);CHKERRQ(ierr);
2000   PetscFunctionReturn(0);
2001 }
2002 
2003 static PetscErrorCode PetscFVView_LeastSquares_Ascii(PetscFV fv, PetscViewer viewer)
2004 {
2005   PetscInt          Nc, c;
2006   PetscViewerFormat format;
2007   PetscErrorCode    ierr;
2008 
2009   PetscFunctionBegin;
2010   ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
2011   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2012   ierr = PetscViewerASCIIPrintf(viewer, "Finite Volume with Least Squares Reconstruction:\n");CHKERRQ(ierr);
2013   ierr = PetscViewerASCIIPrintf(viewer, "  num components: %d\n", Nc);CHKERRQ(ierr);
2014   for (c = 0; c < Nc; c++) {
2015     if (fv->componentNames[c]) {
2016       ierr = PetscViewerASCIIPrintf(viewer, "    component %d: %s\n", c, fv->componentNames[c]);CHKERRQ(ierr);
2017     }
2018   }
2019   PetscFunctionReturn(0);
2020 }
2021 
2022 static PetscErrorCode PetscFVView_LeastSquares(PetscFV fv, PetscViewer viewer)
2023 {
2024   PetscBool      iascii;
2025   PetscErrorCode ierr;
2026 
2027   PetscFunctionBegin;
2028   PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 1);
2029   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2030   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
2031   if (iascii) {ierr = PetscFVView_LeastSquares_Ascii(fv, viewer);CHKERRQ(ierr);}
2032   PetscFunctionReturn(0);
2033 }
2034 
2035 static PetscErrorCode PetscFVSetUp_LeastSquares(PetscFV fvm)
2036 {
2037   PetscFunctionBegin;
2038   PetscFunctionReturn(0);
2039 }
2040 
2041 /* Overwrites A. Can only handle full-rank problems with m>=n */
2042 static PetscErrorCode PetscFVLeastSquaresPseudoInverse_Static(PetscInt m,PetscInt mstride,PetscInt n,PetscScalar *A,PetscScalar *Ainv,PetscScalar *tau,PetscInt worksize,PetscScalar *work)
2043 {
2044   PetscBool      debug = PETSC_FALSE;
2045   PetscErrorCode ierr;
2046   PetscBLASInt   M,N,K,lda,ldb,ldwork,info;
2047   PetscScalar    *R,*Q,*Aback,Alpha;
2048 
2049   PetscFunctionBegin;
2050   if (debug) {
2051     ierr = PetscMalloc1(m*n,&Aback);CHKERRQ(ierr);
2052     ierr = PetscArraycpy(Aback,A,m*n);CHKERRQ(ierr);
2053   }
2054 
2055   ierr = PetscBLASIntCast(m,&M);CHKERRQ(ierr);
2056   ierr = PetscBLASIntCast(n,&N);CHKERRQ(ierr);
2057   ierr = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr);
2058   ierr = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr);
2059   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
2060   LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info);
2061   ierr = PetscFPTrapPop();CHKERRQ(ierr);
2062   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xGEQRF error");
2063   R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */
2064 
2065   /* Extract an explicit representation of Q */
2066   Q    = Ainv;
2067   ierr = PetscArraycpy(Q,A,mstride*n);CHKERRQ(ierr);
2068   K    = N;                     /* full rank */
2069   PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info));
2070   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xORGQR/xUNGQR error");
2071 
2072   /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */
2073   Alpha = 1.0;
2074   ldb   = lda;
2075   BLAStrsm_("Right","Upper","ConjugateTranspose","NotUnitTriangular",&M,&N,&Alpha,R,&lda,Q,&ldb);
2076   /* Ainv is Q, overwritten with inverse */
2077 
2078   if (debug) {                      /* Check that pseudo-inverse worked */
2079     PetscScalar  Beta = 0.0;
2080     PetscBLASInt ldc;
2081     K   = N;
2082     ldc = N;
2083     BLASgemm_("ConjugateTranspose","Normal",&N,&K,&M,&Alpha,Ainv,&lda,Aback,&ldb,&Beta,work,&ldc);
2084     ierr = PetscScalarView(n*n,work,PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
2085     ierr = PetscFree(Aback);CHKERRQ(ierr);
2086   }
2087   PetscFunctionReturn(0);
2088 }
2089 
2090 /* Overwrites A. Can handle degenerate problems and m<n. */
2091 static PetscErrorCode PetscFVLeastSquaresPseudoInverseSVD_Static(PetscInt m,PetscInt mstride,PetscInt n,PetscScalar *A,PetscScalar *Ainv,PetscScalar *tau,PetscInt worksize,PetscScalar *work)
2092 {
2093   PetscBool      debug = PETSC_FALSE;
2094   PetscScalar   *Brhs, *Aback;
2095   PetscScalar   *tmpwork;
2096   PetscReal      rcond;
2097 #if defined (PETSC_USE_COMPLEX)
2098   PetscInt       rworkSize;
2099   PetscReal     *rwork;
2100 #endif
2101   PetscInt       i, j, maxmn;
2102   PetscBLASInt   M, N, lda, ldb, ldwork;
2103   PetscBLASInt   nrhs, irank, info;
2104   PetscErrorCode ierr;
2105 
2106   PetscFunctionBegin;
2107   if (debug) {
2108     ierr = PetscMalloc1(m*n,&Aback);CHKERRQ(ierr);
2109     ierr = PetscArraycpy(Aback,A,m*n);CHKERRQ(ierr);
2110   }
2111 
2112   /* initialize to identity */
2113   tmpwork = Ainv;
2114   Brhs = work;
2115   maxmn = PetscMax(m,n);
2116   for (j=0; j<maxmn; j++) {
2117     for (i=0; i<maxmn; i++) Brhs[i + j*maxmn] = 1.0*(i == j);
2118   }
2119 
2120   ierr  = PetscBLASIntCast(m,&M);CHKERRQ(ierr);
2121   ierr  = PetscBLASIntCast(n,&N);CHKERRQ(ierr);
2122   ierr  = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr);
2123   ierr  = PetscBLASIntCast(maxmn,&ldb);CHKERRQ(ierr);
2124   ierr  = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr);
2125   rcond = -1;
2126   ierr  = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
2127   nrhs  = M;
2128 #if defined(PETSC_USE_COMPLEX)
2129   rworkSize = 5 * PetscMin(M,N);
2130   ierr  = PetscMalloc1(rworkSize,&rwork);CHKERRQ(ierr);
2131   LAPACKgelss_(&M,&N,&nrhs,A,&lda,Brhs,&ldb, (PetscReal *) tau,&rcond,&irank,tmpwork,&ldwork,rwork,&info);
2132   ierr = PetscFPTrapPop();CHKERRQ(ierr);
2133   ierr = PetscFree(rwork);CHKERRQ(ierr);
2134 #else
2135   nrhs  = M;
2136   LAPACKgelss_(&M,&N,&nrhs,A,&lda,Brhs,&ldb, (PetscReal *) tau,&rcond,&irank,tmpwork,&ldwork,&info);
2137   ierr = PetscFPTrapPop();CHKERRQ(ierr);
2138 #endif
2139   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xGELSS error");
2140   /* The following check should be turned into a diagnostic as soon as someone wants to do this intentionally */
2141   if (irank < PetscMin(M,N)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Rank deficient least squares fit, indicates an isolated cell with two colinear points");
2142 
2143   /* Brhs shaped (M,nrhs) column-major coldim=mstride was overwritten by Ainv shaped (N,nrhs) column-major coldim=maxmn.
2144    * Here we transpose to (N,nrhs) row-major rowdim=mstride. */
2145   for (i=0; i<n; i++) {
2146     for (j=0; j<nrhs; j++) Ainv[i*mstride+j] = Brhs[i + j*maxmn];
2147   }
2148   PetscFunctionReturn(0);
2149 }
2150 
2151 #if 0
2152 static PetscErrorCode PetscFVLeastSquaresDebugCell_Static(PetscFV fvm, PetscInt cell, DM dm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom)
2153 {
2154   PetscReal       grad[2] = {0, 0};
2155   const PetscInt *faces;
2156   PetscInt        numFaces, f;
2157   PetscErrorCode  ierr;
2158 
2159   PetscFunctionBegin;
2160   ierr = DMPlexGetConeSize(dm, cell, &numFaces);CHKERRQ(ierr);
2161   ierr = DMPlexGetCone(dm, cell, &faces);CHKERRQ(ierr);
2162   for (f = 0; f < numFaces; ++f) {
2163     const PetscInt *fcells;
2164     const CellGeom *cg1;
2165     const FaceGeom *fg;
2166 
2167     ierr = DMPlexGetSupport(dm, faces[f], &fcells);CHKERRQ(ierr);
2168     ierr = DMPlexPointLocalRead(dmFace, faces[f], fgeom, &fg);CHKERRQ(ierr);
2169     for (i = 0; i < 2; ++i) {
2170       PetscScalar du;
2171 
2172       if (fcells[i] == c) continue;
2173       ierr = DMPlexPointLocalRead(dmCell, fcells[i], cgeom, &cg1);CHKERRQ(ierr);
2174       du   = cg1->centroid[0] + 3*cg1->centroid[1] - (cg->centroid[0] + 3*cg->centroid[1]);
2175       grad[0] += fg->grad[!i][0] * du;
2176       grad[1] += fg->grad[!i][1] * du;
2177     }
2178   }
2179   PetscPrintf(PETSC_COMM_SELF, "cell[%d] grad (%g, %g)\n", cell, grad[0], grad[1]);CHKERRQ(ierr);
2180   PetscFunctionReturn(0);
2181 }
2182 #endif
2183 
2184 /*
2185   PetscFVComputeGradient - Compute the gradient reconstruction matrix for a given cell
2186 
2187   Input Parameters:
2188 + fvm      - The PetscFV object
2189 . numFaces - The number of cell faces which are not constrained
2190 . dx       - The vector from the cell centroid to the neighboring cell centroid for each face
2191 
2192   Level: developer
2193 
2194 .seealso: PetscFVCreate()
2195 */
2196 static PetscErrorCode PetscFVComputeGradient_LeastSquares(PetscFV fvm, PetscInt numFaces, const PetscScalar dx[], PetscScalar grad[])
2197 {
2198   PetscFV_LeastSquares *ls       = (PetscFV_LeastSquares *) fvm->data;
2199   const PetscBool       useSVD   = PETSC_TRUE;
2200   const PetscInt        maxFaces = ls->maxFaces;
2201   PetscInt              dim, f, d;
2202   PetscErrorCode        ierr;
2203 
2204   PetscFunctionBegin;
2205   if (numFaces > maxFaces) {
2206     if (maxFaces < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Reconstruction has not been initialized, call PetscFVLeastSquaresSetMaxFaces()");
2207     SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input faces %D > %D maxfaces", numFaces, maxFaces);
2208   }
2209   ierr = PetscFVGetSpatialDimension(fvm, &dim);CHKERRQ(ierr);
2210   for (f = 0; f < numFaces; ++f) {
2211     for (d = 0; d < dim; ++d) ls->B[d*maxFaces+f] = dx[f*dim+d];
2212   }
2213   /* Overwrites B with garbage, returns Binv in row-major format */
2214   if (useSVD) {ierr = PetscFVLeastSquaresPseudoInverseSVD_Static(numFaces, maxFaces, dim, ls->B, ls->Binv, ls->tau, ls->workSize, ls->work);CHKERRQ(ierr);}
2215   else        {ierr = PetscFVLeastSquaresPseudoInverse_Static(numFaces, maxFaces, dim, ls->B, ls->Binv, ls->tau, ls->workSize, ls->work);CHKERRQ(ierr);}
2216   for (f = 0; f < numFaces; ++f) {
2217     for (d = 0; d < dim; ++d) grad[f*dim+d] = ls->Binv[d*maxFaces+f];
2218   }
2219   PetscFunctionReturn(0);
2220 }
2221 
2222 /*
2223   neighborVol[f*2+0] contains the left  geom
2224   neighborVol[f*2+1] contains the right geom
2225 */
2226 static PetscErrorCode PetscFVIntegrateRHSFunction_LeastSquares(PetscFV fvm, PetscDS prob, PetscInt field, PetscInt Nf, PetscFVFaceGeom *fgeom, PetscReal *neighborVol,
2227                                                                PetscScalar uL[], PetscScalar uR[], PetscScalar fluxL[], PetscScalar fluxR[])
2228 {
2229   void             (*riemann)(PetscInt, PetscInt, const PetscReal[], const PetscReal[], const PetscScalar[], const PetscScalar[], PetscInt, const PetscScalar[], PetscScalar[], void *);
2230   void              *rctx;
2231   PetscScalar       *flux = fvm->fluxWork;
2232   const PetscScalar *constants;
2233   PetscInt           dim, numConstants, pdim, Nc, totDim, off, f, d;
2234   PetscErrorCode     ierr;
2235 
2236   PetscFunctionBegin;
2237   ierr = PetscDSGetTotalComponents(prob, &Nc);CHKERRQ(ierr);
2238   ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr);
2239   ierr = PetscDSGetFieldOffset(prob, field, &off);CHKERRQ(ierr);
2240   ierr = PetscDSGetRiemannSolver(prob, field, &riemann);CHKERRQ(ierr);
2241   ierr = PetscDSGetContext(prob, field, &rctx);CHKERRQ(ierr);
2242   ierr = PetscDSGetConstants(prob, &numConstants, &constants);CHKERRQ(ierr);
2243   ierr = PetscFVGetSpatialDimension(fvm, &dim);CHKERRQ(ierr);
2244   ierr = PetscFVGetNumComponents(fvm, &pdim);CHKERRQ(ierr);
2245   for (f = 0; f < Nf; ++f) {
2246     (*riemann)(dim, pdim, fgeom[f].centroid, fgeom[f].normal, &uL[f*Nc], &uR[f*Nc], numConstants, constants, flux, rctx);
2247     for (d = 0; d < pdim; ++d) {
2248       fluxL[f*totDim+off+d] = flux[d] / neighborVol[f*2+0];
2249       fluxR[f*totDim+off+d] = flux[d] / neighborVol[f*2+1];
2250     }
2251   }
2252   PetscFunctionReturn(0);
2253 }
2254 
2255 static PetscErrorCode PetscFVLeastSquaresSetMaxFaces_LS(PetscFV fvm, PetscInt maxFaces)
2256 {
2257   PetscFV_LeastSquares *ls = (PetscFV_LeastSquares *) fvm->data;
2258   PetscInt              dim, m, n, nrhs, minwork;
2259   PetscErrorCode        ierr;
2260 
2261   PetscFunctionBegin;
2262   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
2263   ierr = PetscFVGetSpatialDimension(fvm, &dim);CHKERRQ(ierr);
2264   ierr = PetscFree4(ls->B, ls->Binv, ls->tau, ls->work);CHKERRQ(ierr);
2265   ls->maxFaces = maxFaces;
2266   m       = ls->maxFaces;
2267   n       = dim;
2268   nrhs    = ls->maxFaces;
2269   minwork = 3*PetscMin(m,n) + PetscMax(2*PetscMin(m,n), PetscMax(PetscMax(m,n), nrhs)); /* required by LAPACK */
2270   ls->workSize = 5*minwork; /* We can afford to be extra generous */
2271   ierr = PetscMalloc4(ls->maxFaces*dim,&ls->B,ls->workSize,&ls->Binv,ls->maxFaces,&ls->tau,ls->workSize,&ls->work);CHKERRQ(ierr);
2272   PetscFunctionReturn(0);
2273 }
2274 
2275 PetscErrorCode PetscFVInitialize_LeastSquares(PetscFV fvm)
2276 {
2277   PetscFunctionBegin;
2278   fvm->ops->setfromoptions          = NULL;
2279   fvm->ops->setup                   = PetscFVSetUp_LeastSquares;
2280   fvm->ops->view                    = PetscFVView_LeastSquares;
2281   fvm->ops->destroy                 = PetscFVDestroy_LeastSquares;
2282   fvm->ops->computegradient         = PetscFVComputeGradient_LeastSquares;
2283   fvm->ops->integraterhsfunction    = PetscFVIntegrateRHSFunction_LeastSquares;
2284   PetscFunctionReturn(0);
2285 }
2286 
2287 /*MC
2288   PETSCFVLEASTSQUARES = "leastsquares" - A PetscFV object
2289 
2290   Level: intermediate
2291 
2292 .seealso: PetscFVType, PetscFVCreate(), PetscFVSetType()
2293 M*/
2294 
2295 PETSC_EXTERN PetscErrorCode PetscFVCreate_LeastSquares(PetscFV fvm)
2296 {
2297   PetscFV_LeastSquares *ls;
2298   PetscErrorCode        ierr;
2299 
2300   PetscFunctionBegin;
2301   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
2302   ierr      = PetscNewLog(fvm, &ls);CHKERRQ(ierr);
2303   fvm->data = ls;
2304 
2305   ls->maxFaces = -1;
2306   ls->workSize = -1;
2307   ls->B        = NULL;
2308   ls->Binv     = NULL;
2309   ls->tau      = NULL;
2310   ls->work     = NULL;
2311 
2312   ierr = PetscFVSetComputeGradients(fvm, PETSC_TRUE);CHKERRQ(ierr);
2313   ierr = PetscFVInitialize_LeastSquares(fvm);CHKERRQ(ierr);
2314   ierr = PetscObjectComposeFunction((PetscObject) fvm, "PetscFVLeastSquaresSetMaxFaces_C", PetscFVLeastSquaresSetMaxFaces_LS);CHKERRQ(ierr);
2315   PetscFunctionReturn(0);
2316 }
2317 
2318 /*@
2319   PetscFVLeastSquaresSetMaxFaces - Set the maximum number of cell faces for gradient reconstruction
2320 
2321   Not collective
2322 
2323   Input parameters:
2324 + fvm      - The PetscFV object
2325 - maxFaces - The maximum number of cell faces
2326 
2327   Level: intermediate
2328 
2329 .seealso: PetscFVCreate(), PETSCFVLEASTSQUARES
2330 @*/
2331 PetscErrorCode PetscFVLeastSquaresSetMaxFaces(PetscFV fvm, PetscInt maxFaces)
2332 {
2333   PetscErrorCode ierr;
2334 
2335   PetscFunctionBegin;
2336   PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1);
2337   ierr = PetscTryMethod(fvm, "PetscFVLeastSquaresSetMaxFaces_C", (PetscFV,PetscInt), (fvm,maxFaces));CHKERRQ(ierr);
2338   PetscFunctionReturn(0);
2339 }
2340