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