Actual source code: ex11.c
petsc-dev 2014-02-02
1: static char help[] = "Second Order TVD Finite Volume Example.\n" ;
We use a second order TVD finite volume method to evolve a system of PDEs. Our simple upwinded residual evaluation loops
over all mesh faces and uses a Riemann solver to produce the flux given the face geometry and cell values,
\begin{equation}
f_i = \mathrm{riemann}(\mathrm{phys}, p_\mathrm{centroid}, \hat n, x^L, x^R)
\end{equation}
and then update the cell values given the cell volume.
\begin{eqnarray}
f^L_i &-=& \frac{f_i}{vol^L} \\
f^R_i &+=& \frac{f_i}{vol^R}
\end{eqnarray}
As an example, we can consider the shallow water wave equation,
\begin{eqnarray}
h_t + \nabla\cdot \left( uh \right) &=& 0 \\
(uh)_t + \nabla\cdot \left( u\otimes uh + \frac{g h^2}{2} I \right) &=& 0
\end{eqnarray}
where $h$ is wave height, $u$ is wave velocity, and $g$ is the acceleration due to gravity.
A representative Riemann solver for the shallow water equations is given in the PhysicsRiemann_SW() function,
\begin{eqnarray}
f^{L,R}_h &=& uh^{L,R} \cdot \hat n \\
f^{L,R}_{uh} &=& \frac{f^{L,R}_h}{h^{L,R}} uh^{L,R} + g (h^{L,R})^2 \hat n \\
c^{L,R} &=& \sqrt{g h^{L,R}} \\
s &=& \max\left( \left|\frac{uh^L \cdot \hat n}{h^L}\right| + c^L, \left|\frac{uh^R \cdot \hat n}{h^R}\right| + c^R \right) \\
f_i &=& \frac{A_\mathrm{face}}{2} \left( f^L_i + f^R_i + s \left( x^L_i - x^R_i \right) \right)
\end{eqnarray}
where $c$ is the local gravity wave speed and $f_i$ is a Rusanov flux.
The more sophisticated residual evaluation in RHSFunctionLocal_LS() uses a least-squares fit to a quadratic polynomial
over a neighborhood of the given element.
The mesh is read in from an ExodusII file, usually generated by Cubit.
37: #include <petscts.h>
38: #include <petscdmplex.h>
39: #include <petscsf.h>
40: #include <petscblaslapack.h>
41: #if defined(PETSC_HAVE_EXODUSII)
42: #include <exodusII.h>
43: #else
44: #error This example requires ExodusII support. Reconfigure using --download-exodusii
45: #endif
47: #define DIM 2 /* Geometric dimension */
48: #define ALEN(a) (sizeof(a)/sizeof((a)[0]))
50: static PetscFunctionList PhysicsList;
51: static PetscFunctionList LimitList;
53: /* Represents continuum physical equations. */
54: typedef struct _n_Physics *Physics;
56: /* Physical model includes boundary conditions, initial conditions, and functionals of interest. It is
57: * discretization-independent, but its members depend on the scenario being solved. */
58: typedef struct _n_Model *Model;
60: /* 'User' implements a discretization of a continuous model. */
61: typedef struct _n_User *User;
63: typedef PetscErrorCode (*RiemannFunction)(Physics,const PetscReal *,const PetscReal *,const PetscScalar *,const PetscScalar *,PetscScalar *) ;
64: typedef PetscErrorCode (*SolutionFunction)(Model,PetscReal ,const PetscReal *,PetscScalar *,void*) ;
65: typedef PetscErrorCode (*BoundaryFunction)(Model,PetscReal ,const PetscReal *,const PetscReal *,const PetscScalar *,PetscScalar *,void*) ;
66: typedef PetscErrorCode (*FunctionalFunction)(Model,PetscReal ,const PetscReal *,const PetscScalar *,PetscReal *,void*) ;
67: typedef PetscErrorCode (*SetupFields)(Physics,PetscSection ) ;
68: static PetscErrorCode ModelBoundaryRegister(Model,const char*,BoundaryFunction,void*,PetscInt ,const PetscInt *) ;
69: static PetscErrorCode ModelSolutionSetDefault(Model,SolutionFunction,void*) ;
70: static PetscErrorCode ModelFunctionalRegister(Model,const char*,PetscInt *,FunctionalFunction,void*) ;
71: static PetscErrorCode OutputVTK(DM,const char*,PetscViewer *) ;
73: struct FieldDescription {
74: const char *name;
75: PetscInt dof;
76: };
78: typedef struct _n_BoundaryLink *BoundaryLink;
79: struct _n_BoundaryLink {
80: char *name;
81: BoundaryFunction func;
82: void *ctx;
83: PetscInt numids;
84: PetscInt *ids;
85: BoundaryLink next;
86: };
88: typedef struct _n_FunctionalLink *FunctionalLink;
89: struct _n_FunctionalLink {
90: char *name;
91: FunctionalFunction func;
92: void *ctx;
93: PetscInt offset;
94: FunctionalLink next;
95: };
97: struct _n_Physics {
98: RiemannFunction riemann;
99: PetscInt dof; /* number of degrees of freedom per cell */
100: PetscReal maxspeed; /* kludge to pick initial time step, need to add monitoring and step control */
101: void *data;
102: PetscInt nfields;
103: const struct FieldDescription *field_desc;
104: };
106: struct _n_Model {
107: MPI_Comm comm; /* Does not do collective communicaton, but some error conditions can be collective */
108: Physics physics;
109: BoundaryLink boundary;
110: FunctionalLink functionalRegistry;
111: PetscInt maxComputed;
112: PetscInt numMonitored;
113: FunctionalLink *functionalMonitored;
114: PetscInt numCall;
115: FunctionalLink *functionalCall;
116: SolutionFunction solution;
117: void *solutionctx;
118: PetscReal maxspeed; /* estimate of global maximum speed (for CFL calculation) */
119: };
121: struct _n_User {
122: PetscErrorCode (*RHSFunctionLocal)(DM,DM,DM,PetscReal ,Vec ,Vec ,User);
123: PetscReal (*Limit)(PetscReal );
124: PetscBool reconstruct;
125: PetscInt numGhostCells, numSplitFaces;
126: PetscInt cEndInterior; /* First boundary ghost cell */
127: Vec cellgeom, facegeom;
128: DM dmGrad;
129: PetscReal minradius;
130: PetscInt vtkInterval; /* For monitor */
131: Model model;
132: struct {
133: PetscScalar *flux;
134: PetscScalar *state0;
135: PetscScalar *state1;
136: } work;
137: };
139: typedef struct {
140: PetscScalar normal[DIM]; /* Area-scaled normals */
141: PetscScalar centroid[DIM]; /* Location of centroid (quadrature point) */
142: PetscScalar grad[2][DIM]; /* Face contribution to gradient in left and right cell */
143: } FaceGeom;
145: typedef struct {
146: PetscScalar centroid[DIM];
147: PetscScalar volume;
148: } CellGeom;
151: PETSC_STATIC_INLINE PetscScalar DotDIM(const PetscScalar *x,const PetscScalar *y)
152: {
153: PetscInt i;
154: PetscScalar prod=0.0;
156: for (i=0; i<DIM; i++) prod += x[i]*y[i];
157: return prod;
158: }
159: PETSC_STATIC_INLINE PetscReal NormDIM(const PetscScalar *x) { return PetscSqrtReal(PetscAbsScalar(DotDIM(x,x))); }
160: PETSC_STATIC_INLINE void axDIM(const PetscScalar a,PetscScalar *x)
161: {
162: PetscInt i;
163: for (i=0; i<DIM; i++) x[i] *= a;
164: }
165: PETSC_STATIC_INLINE void waxDIM(const PetscScalar a,const PetscScalar *x, PetscScalar *w)
166: {
167: PetscInt i;
168: for (i=0; i<DIM; i++) w[i] = x[i]*a;
169: }
170: PETSC_STATIC_INLINE void NormalSplitDIM(const PetscReal *n,const PetscScalar *x,PetscScalar *xn,PetscScalar *xt)
171: { /* Split x into normal and tangential components */
172: PetscInt i;
173: PetscScalar c;
174: c = DotDIM(x,n)/DotDIM(n,n);
175: for (i=0; i<DIM; i++) {
176: xn[i] = c*n[i];
177: xt[i] = x[i]-xn[i];
178: }
179: }
181: PETSC_STATIC_INLINE PetscScalar Dot2(const PetscScalar *x,const PetscScalar *y) { return x[0]*y[0] + x[1]*y[1];}
182: PETSC_STATIC_INLINE PetscReal Norm2(const PetscScalar *x) { return PetscSqrtReal(PetscAbsScalar(Dot2(x,x)));}
183: PETSC_STATIC_INLINE void Normalize2(PetscScalar *x) { PetscReal a = 1./Norm2(x); x[0] *= a; x[1] *= a; }
184: PETSC_STATIC_INLINE void Waxpy2(PetscScalar a,const PetscScalar *x,const PetscScalar *y,PetscScalar *w) { w[0] = a*x[0] + y[0]; w[1] = a*x[1] + y[1]; }
185: PETSC_STATIC_INLINE void Scale2(PetscScalar a,const PetscScalar *x,PetscScalar *y) { y[0] = a*x[0]; y[1] = a*x[1]; }
187: PETSC_STATIC_INLINE void WaxpyD(PetscInt dim, PetscScalar a, const PetscScalar *x, const PetscScalar *y, PetscScalar *w) {PetscInt d; for (d = 0; d < dim; ++d) w[d] = a*x[d] + y[d];}
188: PETSC_STATIC_INLINE PetscScalar DotD(PetscInt dim, const PetscScalar *x, const PetscScalar *y) {PetscScalar sum = 0.0; PetscInt d; for (d = 0; d < dim; ++d) sum += x[d]*y[d]; return sum;}
189: PETSC_STATIC_INLINE PetscReal NormD(PetscInt dim, const PetscScalar *x) {return PetscSqrtReal(PetscAbsScalar(DotD(dim,x,x)));}
191: PETSC_STATIC_INLINE void NormalSplit(const PetscReal *n,const PetscScalar *x,PetscScalar *xn,PetscScalar *xt)
192: { /* Split x into normal and tangential components */
193: Scale2(Dot2(x,n)/Dot2(n,n),n,xn);
194: Waxpy2(-1,xn,x,xt);
195: }
197: /* Limiters given in symmetric form following Berger, Aftosmis, and Murman 2005
198: *
199: * The classical flux-limited formulation is psi(r) where
200: *
201: * r = (u[0] - u[-1]) / (u[1] - u[0])
202: *
203: * The second order TVD region is bounded by
204: *
205: * psi_minmod(r) = min(r,1) and psi_superbee(r) = min(2, 2r, max(1,r))
206: *
207: * where all limiters are implicitly clipped to be non-negative. A more convenient slope-limited form is psi(r) =
208: * phi(r)(r+1)/2 in which the reconstructed interface values are
209: *
210: * u(v) = u[0] + phi(r) (grad u)[0] v
211: *
212: * where v is the vector from centroid to quadrature point. In these variables, the usual limiters become
213: *
214: * 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))
215: *
216: * For a nicer symmetric formulation, rewrite in terms of
217: *
218: * f = (u[0] - u[-1]) / (u[1] - u[-1])
219: *
220: * where r(f) = f/(1-f). Not that r(1-f) = (1-f)/f = 1/r(f) so the symmetry condition
221: *
222: * phi(r) = phi(1/r)
223: *
224: * becomes
225: *
226: * w(f) = w(1-f).
227: *
228: * The limiters below implement this final form w(f). The reference methods are
229: *
230: * w_minmod(f) = 2 min(f,(1-f)) w_superbee(r) = 4 min((1-f), f)
231: * */
232: static PetscReal Limit_Zero(PetscReal f) { return 0; }
233: static PetscReal Limit_None(PetscReal f) { return 1; }
234: static PetscReal Limit_Minmod(PetscReal f) { return PetscMax(0,PetscMin(f,(1-f))*2); }
235: static PetscReal Limit_VanLeer(PetscReal f) { return PetscMax(0,4*f*(1-f)); }
236: static PetscReal Limit_VanAlbada(PetscReal f) { return PetscMax(0,2*f*(1-f) / (PetscSqr(f) + PetscSqr(1-f))); }
237: static PetscReal Limit_Sin(PetscReal f)
238: {
239: PetscReal fclip = PetscMax(0,PetscMin(f,1));
240: return PetscSinReal(PETSC_PI*fclip);
241: }
242: static PetscReal Limit_Superbee(PetscReal f) { return 2*Limit_Minmod(f); }
243: static PetscReal Limit_MC(PetscReal f) { return PetscMin(1,Limit_Superbee(f)); } /* aka Barth-Jespersen */
245: /******************* Advect ********************/
246: typedef enum {ADVECT_SOL_TILTED,ADVECT_SOL_BUMP} AdvectSolType;
247: static const char *const AdvectSolTypes[] = {"TILTED" ,"BUMP" ,"AdvectSolType" ,"ADVECT_SOL_" ,0};
248: typedef enum {ADVECT_SOL_BUMP_CONE,ADVECT_SOL_BUMP_COS} AdvectSolBumpType;
249: static const char *const AdvectSolBumpTypes[] = {"CONE" ,"COS" ,"AdvectSolBumpType" ,"ADVECT_SOL_BUMP_" ,0};
251: typedef struct {
252: PetscReal wind[DIM];
253: } Physics_Advect_Tilted;
254: typedef struct {
255: PetscReal center[DIM];
256: PetscReal radius;
257: AdvectSolBumpType type;
258: } Physics_Advect_Bump;
260: typedef struct {
261: PetscReal inflowState;
262: AdvectSolType soltype;
263: union {
264: Physics_Advect_Tilted tilted;
265: Physics_Advect_Bump bump;
266: } sol;
267: struct {
268: PetscInt Error;
269: } functional;
270: } Physics_Advect;
272: static const struct FieldDescription PhysicsFields_Advect[] = {{"U" ,1},{NULL,0}};
276: static PetscErrorCode PhysicsBoundary_Advect_Inflow(Model mod, PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *xI, PetscScalar *xG, void *ctx)
277: {
278: Physics phys = (Physics)ctx;
279: Physics_Advect *advect = (Physics_Advect*)phys->data;
282: xG[0] = advect->inflowState;
283: return (0);
284: }
288: static PetscErrorCode PhysicsBoundary_Advect_Outflow(Model mod, PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *xI, PetscScalar *xG, void *ctx)
289: {
291: xG[0] = xI[0];
292: return (0);
293: }
297: static PetscErrorCode PhysicsRiemann_Advect(Physics phys, const PetscReal *qp, const PetscReal *n, const PetscScalar *xL, const PetscScalar *xR, PetscScalar *flux)
298: {
299: Physics_Advect *advect = (Physics_Advect*)phys->data;
300: PetscReal wind[DIM],wn;
303: switch (advect->soltype) {
304: case ADVECT_SOL_TILTED: {
305: Physics_Advect_Tilted *tilted = &advect->sol.tilted;
306: wind[0] = tilted->wind[0];
307: wind[1] = tilted->wind[1];
308: } break ;
309: case ADVECT_SOL_BUMP:
310: wind[0] = -qp[1];
311: wind[1] = qp[0];
312: break ;
313: default: SETERRQ1 (PETSC_COMM_SELF ,PETSC_ERR_SUP,"No support for solution type %s" ,AdvectSolBumpTypes[advect->soltype]);
314: }
315: wn = Dot2(wind, n);
316: flux[0] = (wn > 0 ? xL[0] : xR[0]) * wn;
317: return (0);
318: }
322: static PetscErrorCode PhysicsSolution_Advect(Model mod,PetscReal time,const PetscReal *x,PetscScalar *u,void *ctx)
323: {
324: Physics phys = (Physics)ctx;
325: Physics_Advect *advect = (Physics_Advect*)phys->data;
328: switch (advect->soltype) {
329: case ADVECT_SOL_TILTED: {
330: PetscReal x0[DIM];
331: Physics_Advect_Tilted *tilted = &advect->sol.tilted;
332: Waxpy2(-time,tilted->wind,x,x0);
333: if (x0[1] > 0) u[0] = 1.*x[0] + 3.*x[1];
334: else u[0] = advect->inflowState;
335: } break ;
336: case ADVECT_SOL_BUMP: {
337: Physics_Advect_Bump *bump = &advect->sol.bump;
338: PetscReal x0[DIM],v[DIM],r,cost,sint;
339: cost = PetscCosReal(time);
340: sint = PetscSinReal(time);
341: x0[0] = cost*x[0] + sint*x[1];
342: x0[1] = -sint*x[0] + cost*x[1];
343: Waxpy2(-1,bump->center,x0,v);
344: r = Norm2(v);
345: switch (bump->type) {
346: case ADVECT_SOL_BUMP_CONE:
347: u[0] = PetscMax(1 - r/bump->radius,0);
348: break ;
349: case ADVECT_SOL_BUMP_COS:
350: u[0] = 0.5 + 0.5*PetscCosReal(PetscMin(r/bump->radius,1)*PETSC_PI);
351: break ;
352: }
353: } break ;
354: default: SETERRQ (PETSC_COMM_SELF ,PETSC_ERR_SUP,"Unknown solution type" );
355: }
356: return (0);
357: }
361: static PetscErrorCode PhysicsFunctional_Advect(Model mod,PetscReal time,const PetscScalar *x,const PetscScalar *y,PetscReal *f,void *ctx)
362: {
363: Physics phys = (Physics)ctx;
364: Physics_Advect *advect = (Physics_Advect*)phys->data;
365: PetscScalar yexact[1];
369: PhysicsSolution_Advect(mod,time,x,yexact,phys);
370: f[advect->functional.Error] = PetscAbsScalar(y[0]-yexact[0]);
371: return (0);
372: }
376: static PetscErrorCode PhysicsCreate_Advect(Model mod,Physics phys)
377: {
378: Physics_Advect *advect;
382: phys->field_desc = PhysicsFields_Advect;
383: phys->riemann = PhysicsRiemann_Advect;
384: PetscNew (&phys->data);
385: advect = (Physics_Advect*)phys->data;
386: PetscOptionsHead ("Advect options" );
387: {
388: PetscInt two = 2,dof = 1;
389: advect->soltype = ADVECT_SOL_TILTED;
390: PetscOptionsEnum ("-advect_sol_type" ,"solution type" ,"" ,AdvectSolTypes,(PetscEnum )advect->soltype,(PetscEnum *)&advect->soltype,NULL);
391: switch (advect->soltype) {
392: case ADVECT_SOL_TILTED: {
393: Physics_Advect_Tilted *tilted = &advect->sol.tilted;
394: two = 2;
395: tilted->wind[0] = 0.0;
396: tilted->wind[1] = 1.0;
397: PetscOptionsRealArray ("-advect_tilted_wind" ,"background wind vx,vy" ,"" ,tilted->wind,&two,NULL);
398: advect->inflowState = -2.0;
399: PetscOptionsRealArray ("-advect_tilted_inflow" ,"Inflow state" ,"" ,&advect->inflowState,&dof,NULL);
400: phys->maxspeed = Norm2(tilted->wind);
401: } break ;
402: case ADVECT_SOL_BUMP: {
403: Physics_Advect_Bump *bump = &advect->sol.bump;
404: two = 2;
405: bump->center[0] = 2.;
406: bump->center[1] = 0.;
407: PetscOptionsRealArray ("-advect_bump_center" ,"location of center of bump x,y" ,"" ,bump->center,&two,NULL);
408: bump->radius = 0.9;
409: PetscOptionsReal ("-advect_bump_radius" ,"radius of bump" ,"" ,bump->radius,&bump->radius,NULL);
410: bump->type = ADVECT_SOL_BUMP_CONE;
411: PetscOptionsEnum ("-advect_bump_type" ,"type of bump" ,"" ,AdvectSolBumpTypes,(PetscEnum )bump->type,(PetscEnum *)&bump->type,NULL);
412: phys->maxspeed = 3.; /* radius of mesh, kludge */
413: } break ;
414: }
415: }
416: PetscOptionsTail ();
418: {
419: const PetscInt inflowids[] = {100,200,300},outflowids[] = {101};
420: /* Register "canned" boundary conditions and defaults for where to apply. */
421: ModelBoundaryRegister(mod,"inflow" ,PhysicsBoundary_Advect_Inflow,phys,ALEN(inflowids),inflowids);
422: ModelBoundaryRegister(mod,"outflow" ,PhysicsBoundary_Advect_Outflow,phys,ALEN(outflowids),outflowids);
423: /* Initial/transient solution with default boundary conditions */
424: ModelSolutionSetDefault(mod,PhysicsSolution_Advect,phys);
425: /* Register "canned" functionals */
426: ModelFunctionalRegister(mod,"Error" ,&advect->functional.Error,PhysicsFunctional_Advect,phys);
427: }
428: return (0);
429: }
431: /******************* Shallow Water ********************/
432: typedef struct {
433: PetscReal gravity;
434: PetscReal boundaryHeight;
435: struct {
436: PetscInt Height;
437: PetscInt Speed;
438: PetscInt Energy;
439: } functional;
440: } Physics_SW;
441: typedef struct {
442: PetscScalar vals[0];
443: PetscScalar h;
444: PetscScalar uh[DIM];
445: } SWNode;
447: static const struct FieldDescription PhysicsFields_SW[] = {{"Height" ,1},{"Momentum" ,DIM},{NULL,0}};
451: /*
452: * h_t + div(uh) = 0
453: * (uh)_t + div (u\otimes uh + g h^2 / 2 I) = 0
454: *
455: * */
456: static PetscErrorCode SWFlux(Physics phys,const PetscReal *n,const SWNode *x,SWNode *f)
457: {
458: Physics_SW *sw = (Physics_SW*)phys->data;
459: PetscScalar uhn,u[DIM];
460: PetscInt i;
463: Scale2(1./x->h,x->uh,u);
464: uhn = Dot2(x->uh,n);
465: f->h = uhn;
466: for (i=0; i<DIM; i++) f->uh[i] = u[i] * uhn + sw->gravity * PetscSqr(x->h) * n[i];
467: return (0);
468: }
472: static PetscErrorCode PhysicsBoundary_SW_Wall(Model mod, PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *xI, PetscScalar *xG, void *ctx)
473: {
475: xG[0] = xI[0];
476: xG[1] = -xI[1];
477: xG[2] = -xI[2];
478: return (0);
479: }
483: static PetscErrorCode PhysicsRiemann_SW(Physics phys, const PetscReal *qp, const PetscReal *n, const PetscScalar *xL, const PetscScalar *xR, PetscScalar *flux)
484: {
485: Physics_SW *sw = (Physics_SW*)phys->data;
486: PetscReal cL,cR,speed,nn[DIM];
487: const SWNode *uL = (const SWNode*)xL,*uR = (const SWNode*)xR;
488: SWNode fL,fR;
489: PetscInt i;
492: if (uL->h < 0 || uR->h < 0) SETERRQ (PETSC_COMM_SELF ,PETSC_ERR_ARG_OUTOFRANGE,"Reconstructed thickness is negative" );
493: nn[0] = n[0];
494: nn[1] = n[1];
495: Normalize2(nn);
496: SWFlux(phys,nn,uL,&fL);
497: SWFlux(phys,nn,uR,&fR);
498: cL = PetscSqrtReal(sw->gravity*PetscRealPart(uL->h));
499: cR = PetscSqrtReal(sw->gravity*PetscRealPart(uR->h)); /* gravity wave speed */
500: speed = PetscMax(PetscAbsScalar(Dot2(uL->uh,nn)/uL->h) + cL,PetscAbsScalar(Dot2(uR->uh,nn)/uR->h) + cR);
501: for (i=0; i<1+DIM; i++) flux[i] = (0.5*(fL.vals[i] + fR.vals[i]) + 0.5*speed*(xL[i] - xR[i])) * Norm2(n);
502: return (0);
503: }
507: static PetscErrorCode PhysicsSolution_SW(Model mod,PetscReal time,const PetscReal *x,PetscScalar *u,void *ctx)
508: {
509: PetscReal dx[2],r,sigma;
512: if (time != 0.0) SETERRQ1 (mod->comm,PETSC_ERR_SUP,"No solution known for time %g" ,(double)time);
513: dx[0] = x[0] - 1.5;
514: dx[1] = x[1] - 1.0;
515: r = Norm2(dx);
516: sigma = 0.5;
517: u[0] = 1 + 2*PetscExpScalar(-PetscSqr(r)/(2*PetscSqr(sigma)));
518: u[1] = 0.0;
519: u[2] = 0.0;
520: return (0);
521: }
525: static PetscErrorCode PhysicsFunctional_SW(Model mod,PetscReal time,const PetscReal *coord,const PetscScalar *xx,PetscReal *f,void *ctx)
526: {
527: Physics phys = (Physics)ctx;
528: Physics_SW *sw = (Physics_SW*)phys->data;
529: const SWNode *x = (const SWNode*)xx;
530: PetscScalar u[2];
531: PetscReal h;
534: h = PetscRealPart(x->h);
535: Scale2(1./x->h,x->uh,u);
536: f[sw->functional.Height] = h;
537: f[sw->functional.Speed] = Norm2(u) + PetscSqrtReal(sw->gravity*h);
538: f[sw->functional.Energy] = 0.5*(Dot2(x->uh,u) + sw->gravity*PetscSqr(h));
539: return (0);
540: }
544: static PetscErrorCode PhysicsCreate_SW(Model mod,Physics phys)
545: {
546: Physics_SW *sw;
550: phys->field_desc = PhysicsFields_SW;
551: phys->riemann = PhysicsRiemann_SW;
552: PetscNew (&phys->data);
553: sw = (Physics_SW*)phys->data;
554: PetscOptionsHead ("SW options" );
555: {
556: sw->gravity = 1.0;
557: PetscOptionsReal ("-sw_gravity" ,"Gravitational constant" ,"" ,sw->gravity,&sw->gravity,NULL);
558: }
559: PetscOptionsTail ();
560: phys->maxspeed = PetscSqrtReal(2.0*sw->gravity); /* Mach 1 for depth of 2 */
562: {
563: const PetscInt wallids[] = {100,101,200,300};
564: ModelBoundaryRegister(mod,"wall" ,PhysicsBoundary_SW_Wall,phys,ALEN(wallids),wallids);
565: ModelSolutionSetDefault(mod,PhysicsSolution_SW,phys);
566: ModelFunctionalRegister(mod,"Height" ,&sw->functional.Height,PhysicsFunctional_SW,phys);
567: ModelFunctionalRegister(mod,"Speed" ,&sw->functional.Speed,PhysicsFunctional_SW,phys);
568: ModelFunctionalRegister(mod,"Energy" ,&sw->functional.Energy,PhysicsFunctional_SW,phys);
569: }
570: return (0);
571: }
573: /******************* Euler ********************/
574: typedef struct {
575: PetscScalar vals[0];
576: PetscScalar r;
577: PetscScalar ru[DIM];
578: PetscScalar e;
579: } EulerNode;
580: typedef PetscErrorCode (*EquationOfState)(const PetscReal *, const EulerNode*, PetscScalar *) ;
581: typedef struct {
582: PetscInt npars;
583: PetscReal pars[DIM];
584: EquationOfState pressure;
585: EquationOfState sound;
586: struct {
587: PetscInt Density;
588: PetscInt Momentum;
589: PetscInt Energy;
590: PetscInt Pressure;
591: PetscInt Speed;
592: } monitor;
593: } Physics_Euler;
595: static const struct FieldDescription PhysicsFields_Euler[] = {{"Density" ,1},{"Momentum" ,DIM},{"Energy" ,1},{NULL,0}};
599: static PetscErrorCode Pressure_PG(const PetscReal *pars,const EulerNode *x,PetscScalar *p)
600: {
601: PetscScalar ru2;
604: ru2 = DotDIM(x->ru,x->ru);
605: ru2 /= x->r;
606: /* kinematic dof = params[0] */
607: (*p)=2.0*(x->e-0.5*ru2)/pars[0];
608: return (0);
609: }
613: static PetscErrorCode SpeedOfSound_PG(const PetscReal *pars,const EulerNode *x,PetscScalar *c)
614: {
615: PetscScalar p;
618: /* TODO remove direct usage of Pressure_PG */
619: Pressure_PG(pars,x,&p);
620: /* TODO check the sign of p */
621: /* pars[1] = heat capacity ratio */
622: (*c)=PetscSqrtScalar(pars[1]*p/x->r);
623: return (0);
624: }
628: /*
629: * x = (rho,rho*(u_1),...,rho*e)^T
630: * x_t+div(f_1(x))+...+div(f_DIM(x)) = 0
631: *
632: * f_i(x) = u_i*x+(0,0,...,p,...,p*u_i)^T
633: *
634: * */
635: static PetscErrorCode EulerFlux(Physics phys,const PetscReal *n,const EulerNode *x,EulerNode *f)
636: {
637: Physics_Euler *eu = (Physics_Euler*)phys->data;
638: PetscScalar u,nu,p;
639: PetscInt i;
642: u = DotDIM(x->ru,x->ru);
643: u /= (x->r * x->r);
644: nu = DotDIM(x->ru,n);
645: /* TODO check the sign of p */
646: eu->pressure(eu->pars,x,&p);
647: f->r = nu * x->r;
648: for (i=0; i<DIM; i++) f->ru[i] = nu * x->ru[i] + n[i]*p;
649: f->e = nu*(x->e+p);
650: return (0);
651: }
653: /* PetscReal * => EulerNode* conversion */
656: static PetscErrorCode PhysicsBoundary_Euler_Wall(Model mod, PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *xI, PetscScalar *xG, void *ctx)
657: {
658: PetscInt i;
659: PetscScalar xn[DIM],xt[DIM];
662: xG[0] = xI[0];
663: NormalSplitDIM(n,xI+1,xn,xt);
664: for (i=0; i<DIM; i++) xG[i+1] = -xn[i]+xt[i];
665: xG[DIM+1] = xI[DIM+1];
666: return (0);
667: }
669: /* PetscReal * => EulerNode* conversion */
672: static PetscErrorCode PhysicsRiemann_Euler_Rusanov(Physics phys, const PetscReal *qp, const PetscReal *n, const PetscScalar *xL, const PetscScalar *xR, PetscScalar *flux)
673: {
674: Physics_Euler *eu = (Physics_Euler*)phys->data;
675: PetscScalar cL,cR,speed;
676: const EulerNode *uL = (const EulerNode*)xL,*uR = (const EulerNode*)xR;
677: EulerNode fL,fR;
678: PetscInt i;
681: if (uL->r < 0 || uR->r < 0) SETERRQ (PETSC_COMM_SELF ,PETSC_ERR_ARG_OUTOFRANGE,"Reconstructed density is negative" );
682: EulerFlux(phys,n,uL,&fL);
683: EulerFlux(phys,n,uR,&fR);
684: eu->sound(eu->pars,uL,&cL);
685: eu->sound(eu->pars,uR,&cR);
686: speed = PetscMax(cL,cR)+PetscMax(PetscAbsScalar(DotDIM(uL->ru,n)/NormDIM(n)),PetscAbsScalar(DotDIM(uR->ru,n)/NormDIM(n)));
687: for (i=0; i<2+DIM; i++) flux[i] = 0.5*(fL.vals[i]+fR.vals[i])+0.5*speed*(xL[i]-xR[i]);
688: return (0);
689: }
693: static PetscErrorCode PhysicsSolution_Euler(Model mod,PetscReal time,const PetscReal *x,PetscScalar *u,void *ctx)
694: {
695: PetscInt i;
698: if (time != 0.0) SETERRQ1 (mod->comm,PETSC_ERR_SUP,"No solution known for time %g" ,(double)time);
699: u[0] = 1.0;
700: u[DIM+1] = 1.0+PetscAbsReal(x[0]);
701: for (i=1; i<DIM+1; i++) u[i] = 0.0;
702: return (0);
703: }
707: static PetscErrorCode PhysicsFunctional_Euler(Model mod,PetscReal time,const PetscReal *coord,const PetscScalar *xx,PetscReal *f,void *ctx)
708: {
709: Physics phys = (Physics)ctx;
710: Physics_Euler *eu = (Physics_Euler*)phys->data;
711: const EulerNode *x = (const EulerNode*)xx;
712: PetscScalar p;
715: f[eu->monitor.Density] = x->r;
716: f[eu->monitor.Momentum] = NormDIM(x->ru);
717: f[eu->monitor.Energy] = x->e;
718: f[eu->monitor.Speed] = NormDIM(x->ru)/x->r;
719: eu->pressure(eu->pars, x, &p);
720: f[eu->monitor.Pressure] = p;
721: return (0);
722: }
726: static PetscErrorCode PhysicsCreate_Euler(Model mod,Physics phys)
727: {
728: Physics_Euler *eu;
729: PetscErrorCode ierr;
732: phys->field_desc = PhysicsFields_Euler;
733: phys->riemann = PhysicsRiemann_Euler_Rusanov;
734: PetscNew (&phys->data);
735: eu = (Physics_Euler*)phys->data;
736: PetscOptionsHead ("Euler options" );
737: {
738: eu->pars[0] = 3.0;
739: eu->pars[1] = 1.67;
740: PetscOptionsReal ("-eu_f" ,"Degrees of freedom" ,"" ,eu->pars[0],&eu->pars[0],NULL);
741: PetscOptionsReal ("-eu_gamma" ,"Heat capacity ratio" ,"" ,eu->pars[1],&eu->pars[1],NULL);
742: }
743: PetscOptionsTail ();
744: eu->pressure = Pressure_PG;
745: eu->sound = SpeedOfSound_PG;
746: phys->maxspeed = 1.0;
747: {
748: const PetscInt wallids[] = {100,101,200,300};
749: ModelBoundaryRegister(mod,"wall" ,PhysicsBoundary_Euler_Wall,phys,ALEN(wallids),wallids);
750: ModelSolutionSetDefault(mod,PhysicsSolution_Euler,phys);
751: ModelFunctionalRegister(mod,"Speed" ,&eu->monitor.Speed,PhysicsFunctional_Euler,phys);
752: ModelFunctionalRegister(mod,"Energy" ,&eu->monitor.Energy,PhysicsFunctional_Euler,phys);
753: ModelFunctionalRegister(mod,"Density" ,&eu->monitor.Density,PhysicsFunctional_Euler,phys);
754: ModelFunctionalRegister(mod,"Momentum" ,&eu->monitor.Momentum,PhysicsFunctional_Euler,phys);
755: ModelFunctionalRegister(mod,"Pressure" ,&eu->monitor.Pressure,PhysicsFunctional_Euler,phys);
756: }
757: return (0);
758: }
762: PetscErrorCode ConstructCellBoundary(DM dm, User user)
763: {
764: const char *name = "Cell Sets" ;
765: const char *bdname = "split faces" ;
766: IS regionIS, innerIS;
767: const PetscInt *regions, *cells;
768: PetscInt numRegions, innerRegion, numCells, c;
770: PetscInt cStart, cEnd, fStart, fEnd;
772: PetscBool hasLabel;
776: DMPlexGetHeightStratum (dm, 0, &cStart, &cEnd);
777: DMPlexGetHeightStratum (dm, 1, &fStart, &fEnd);
779: DMPlexHasLabel (dm, name, &hasLabel);
780: if (!hasLabel) return (0);
781: DMPlexGetLabelSize (dm, name, &numRegions);
782: if (numRegions != 2) return (0);
783: /* Get the inner id */
784: DMPlexGetLabelIdIS (dm, name, ®ionIS);
785: ISGetIndices (regionIS, ®ions);
786: innerRegion = regions[0];
787: ISRestoreIndices (regionIS, ®ions);
788: ISDestroy (®ionIS);
789: /* Find the faces between cells in different regions, could call DMPlexCreateNeighborCSR() */
790: DMPlexGetStratumIS (dm, name, innerRegion, &innerIS);
791: ISGetLocalSize (innerIS, &numCells);
792: ISGetIndices (innerIS, &cells);
793: DMPlexCreateLabel (dm, bdname);
794: for (c = 0; c < numCells; ++c) {
795: const PetscInt cell = cells[c];
796: const PetscInt *faces;
797: PetscInt numFaces, f;
799: if ((cell < cStart) || (cell >= cEnd)) SETERRQ1 (PETSC_COMM_SELF , PETSC_ERR_LIB, "Got invalid point %d which is not a cell" , cell);
800: DMPlexGetConeSize (dm, cell, &numFaces);
801: DMPlexGetCone (dm, cell, &faces);
802: for (f = 0; f < numFaces; ++f) {
803: const PetscInt face = faces[f];
804: const PetscInt *neighbors;
805: PetscInt nC, regionA, regionB;
807: if ((face < fStart) || (face >= fEnd)) SETERRQ1 (PETSC_COMM_SELF , PETSC_ERR_LIB, "Got invalid point %d which is not a face" , face);
808: DMPlexGetSupportSize (dm, face, &nC);
809: if (nC != 2) continue ;
810: DMPlexGetSupport (dm, face, &neighbors);
811: if ((neighbors[0] >= user->cEndInterior) || (neighbors[1] >= user->cEndInterior)) continue ;
812: if ((neighbors[0] < cStart) || (neighbors[0] >= cEnd)) SETERRQ1 (PETSC_COMM_SELF , PETSC_ERR_LIB, "Got invalid point %d which is not a cell" , neighbors[0]);
813: if ((neighbors[1] < cStart) || (neighbors[1] >= cEnd)) SETERRQ1 (PETSC_COMM_SELF , PETSC_ERR_LIB, "Got invalid point %d which is not a cell" , neighbors[1]);
814: DMPlexGetLabelValue (dm, name, neighbors[0], ®ionA);
815: DMPlexGetLabelValue (dm, name, neighbors[1], ®ionB);
816: if (regionA < 0) SETERRQ2 (PetscObjectComm ((PetscObject )dm), PETSC_ERR_ARG_WRONG, "Invalid label %s: Cell %d has no value" , name, neighbors[0]);
817: if (regionB < 0) SETERRQ2 (PetscObjectComm ((PetscObject )dm), PETSC_ERR_ARG_WRONG, "Invalid label %s: Cell %d has no value" , name, neighbors[1]);
818: if (regionA != regionB) {
819: DMPlexSetLabelValue (dm, bdname, faces[f], 1);
820: }
821: }
822: }
823: ISRestoreIndices (innerIS, &cells);
824: ISDestroy (&innerIS);
825: {
826: DMLabel label;
828: PetscViewerASCIISynchronizedAllow (PETSC_VIEWER_STDOUT_WORLD , PETSC_TRUE );
829: DMPlexGetLabel (dm, bdname, &label);
830: DMLabelView(label, PETSC_VIEWER_STDOUT_WORLD );
831: }
832: return (0);
833: }
837: /* Right now, I have just added duplicate faces, which see both cells. We can
838: - Add duplicate vertices and decouple the face cones
839: - Disconnect faces from cells across the rotation gap
840: */
841: PetscErrorCode SplitFaces(DM *dmSplit, const char labelName[], User user)
842: {
843: DM dm = *dmSplit, sdm;
844: PetscSF sfPoint, gsfPoint;
845: PetscSection coordSection, newCoordSection;
846: Vec coordinates;
847: IS idIS;
848: const PetscInt *ids;
849: PetscInt *newpoints;
850: PetscInt dim, depth, maxConeSize, maxSupportSize, numLabels;
851: PetscInt numFS, fs, pStart, pEnd, p, vStart, vEnd, v, fStart, fEnd, newf, d, l;
852: PetscBool hasLabel;
856: DMPlexHasLabel (dm, labelName, &hasLabel);
857: if (!hasLabel) return (0);
858: DMCreate (PetscObjectComm ((PetscObject )dm), &sdm);
859: DMSetType (sdm, DMPLEX );
860: DMPlexGetDimension (dm, &dim);
861: DMPlexSetDimension (sdm, dim);
863: DMPlexGetLabelIdIS (dm, labelName, &idIS);
864: ISGetLocalSize (idIS, &numFS);
865: ISGetIndices (idIS, &ids);
867: user->numSplitFaces = 0;
868: for (fs = 0; fs < numFS; ++fs) {
869: PetscInt numBdFaces;
871: DMPlexGetStratumSize (dm, labelName, ids[fs], &numBdFaces);
872: user->numSplitFaces += numBdFaces;
873: }
874: DMPlexGetChart (dm, &pStart, &pEnd);
875: pEnd += user->numSplitFaces;
876: DMPlexSetChart (sdm, pStart, pEnd);
877: /* Set cone and support sizes */
878: DMPlexGetDepth (dm, &depth);
879: for (d = 0; d <= depth; ++d) {
880: DMPlexGetDepthStratum (dm, d, &pStart, &pEnd);
881: for (p = pStart; p < pEnd; ++p) {
882: PetscInt newp = p;
883: PetscInt size;
885: DMPlexGetConeSize (dm, p, &size);
886: DMPlexSetConeSize (sdm, newp, size);
887: DMPlexGetSupportSize (dm, p, &size);
888: DMPlexSetSupportSize (sdm, newp, size);
889: }
890: }
891: DMPlexGetHeightStratum (dm, 1, &fStart, &fEnd);
892: for (fs = 0, newf = fEnd; fs < numFS; ++fs) {
893: IS faceIS;
894: const PetscInt *faces;
895: PetscInt numFaces, f;
897: DMPlexGetStratumIS (dm, labelName, ids[fs], &faceIS);
898: ISGetLocalSize (faceIS, &numFaces);
899: ISGetIndices (faceIS, &faces);
900: for (f = 0; f < numFaces; ++f, ++newf) {
901: PetscInt size;
903: /* Right now I think that both faces should see both cells */
904: DMPlexGetConeSize (dm, faces[f], &size);
905: DMPlexSetConeSize (sdm, newf, size);
906: DMPlexGetSupportSize (dm, faces[f], &size);
907: DMPlexSetSupportSize (sdm, newf, size);
908: }
909: ISRestoreIndices (faceIS, &faces);
910: ISDestroy (&faceIS);
911: }
912: DMSetUp (sdm);
913: /* Set cones and supports */
914: DMPlexGetMaxSizes (dm, &maxConeSize, &maxSupportSize);
915: PetscMalloc (PetscMax(maxConeSize, maxSupportSize) * sizeof (PetscInt ), &newpoints);
916: DMPlexGetChart (dm, &pStart, &pEnd);
917: for (p = pStart; p < pEnd; ++p) {
918: const PetscInt *points, *orientations;
919: PetscInt size, i, newp = p;
921: DMPlexGetConeSize (dm, p, &size);
922: DMPlexGetCone (dm, p, &points);
923: DMPlexGetConeOrientation (dm, p, &orientations);
924: for (i = 0; i < size; ++i) newpoints[i] = points[i];
925: DMPlexSetCone (sdm, newp, newpoints);
926: DMPlexSetConeOrientation (sdm, newp, orientations);
927: DMPlexGetSupportSize (dm, p, &size);
928: DMPlexGetSupport (dm, p, &points);
929: for (i = 0; i < size; ++i) newpoints[i] = points[i];
930: DMPlexSetSupport (sdm, newp, newpoints);
931: }
932: PetscFree (newpoints);
933: for (fs = 0, newf = fEnd; fs < numFS; ++fs) {
934: IS faceIS;
935: const PetscInt *faces;
936: PetscInt numFaces, f;
938: DMPlexGetStratumIS (dm, labelName, ids[fs], &faceIS);
939: ISGetLocalSize (faceIS, &numFaces);
940: ISGetIndices (faceIS, &faces);
941: for (f = 0; f < numFaces; ++f, ++newf) {
942: const PetscInt *points;
944: DMPlexGetCone (dm, faces[f], &points);
945: DMPlexSetCone (sdm, newf, points);
946: DMPlexGetSupport (dm, faces[f], &points);
947: DMPlexSetSupport (sdm, newf, points);
948: }
949: ISRestoreIndices (faceIS, &faces);
950: ISDestroy (&faceIS);
951: }
952: ISRestoreIndices (idIS, &ids);
953: ISDestroy (&idIS);
954: DMPlexStratify (sdm);
955: /* Convert coordinates */
956: DMPlexGetDepthStratum (dm, 0, &vStart, &vEnd);
957: DMGetCoordinateSection (dm, &coordSection);
958: PetscSectionCreate (PetscObjectComm ((PetscObject )dm), &newCoordSection);
959: PetscSectionSetNumFields (newCoordSection, 1);
960: PetscSectionSetFieldComponents (newCoordSection, 0, dim);
961: PetscSectionSetChart (newCoordSection, vStart, vEnd);
962: for (v = vStart; v < vEnd; ++v) {
963: PetscSectionSetDof (newCoordSection, v, dim);
964: PetscSectionSetFieldDof (newCoordSection, v, 0, dim);
965: }
966: PetscSectionSetUp (newCoordSection);
967: DMSetCoordinateSection (sdm, newCoordSection);
968: PetscSectionDestroy (&newCoordSection); /* relinquish our reference */
969: DMGetCoordinatesLocal (dm, &coordinates);
970: DMSetCoordinatesLocal (sdm, coordinates);
971: /* Convert labels */
972: DMPlexGetNumLabels (dm, &numLabels);
973: for (l = 0; l < numLabels; ++l) {
974: const char *lname;
975: PetscBool isDepth;
977: DMPlexGetLabelName (dm, l, &lname);
978: PetscStrcmp (lname, "depth" , &isDepth);
979: if (isDepth) continue ;
980: DMPlexCreateLabel (sdm, lname);
981: DMPlexGetLabelIdIS (dm, lname, &idIS);
982: ISGetLocalSize (idIS, &numFS);
983: ISGetIndices (idIS, &ids);
984: for (fs = 0; fs < numFS; ++fs) {
985: IS pointIS;
986: const PetscInt *points;
987: PetscInt numPoints;
989: DMPlexGetStratumIS (dm, lname, ids[fs], &pointIS);
990: ISGetLocalSize (pointIS, &numPoints);
991: ISGetIndices (pointIS, &points);
992: for (p = 0; p < numPoints; ++p) {
993: PetscInt newpoint = points[p];
995: DMPlexSetLabelValue (sdm, lname, newpoint, ids[fs]);
996: }
997: ISRestoreIndices (pointIS, &points);
998: ISDestroy (&pointIS);
999: }
1000: ISRestoreIndices (idIS, &ids);
1001: ISDestroy (&idIS);
1002: }
1003: /* Convert pointSF */
1004: const PetscSFNode *remotePoints;
1005: PetscSFNode *gremotePoints;
1006: const PetscInt *localPoints;
1007: PetscInt *glocalPoints,*newLocation,*newRemoteLocation;
1008: PetscInt numRoots, numLeaves;
1009: PetscMPIInt numProcs;
1011: MPI_Comm_size (PetscObjectComm ((PetscObject )dm), &numProcs);
1012: DMGetPointSF (dm, &sfPoint);
1013: DMGetPointSF (sdm, &gsfPoint);
1014: DMPlexGetChart (dm,&pStart,&pEnd);
1015: PetscSFGetGraph (sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
1016: if (numRoots >= 0) {
1017: PetscMalloc2 (numRoots,&newLocation,pEnd-pStart,&newRemoteLocation);
1018: for (l=0; l<numRoots; l++) newLocation[l] = l; /* + (l >= cEnd ? user->numGhostCells : 0); */
1019: PetscSFBcastBegin (sfPoint, MPIU_INT, newLocation, newRemoteLocation);
1020: PetscSFBcastEnd (sfPoint, MPIU_INT, newLocation, newRemoteLocation);
1021: PetscMalloc1 (numLeaves, &glocalPoints);
1022: PetscMalloc1 (numLeaves, &gremotePoints);
1023: for (l = 0; l < numLeaves; ++l) {
1024: glocalPoints[l] = localPoints[l]; /* localPoints[l] >= cEnd ? localPoints[l] + user->numGhostCells : localPoints[l]; */
1025: gremotePoints[l].rank = remotePoints[l].rank;
1026: gremotePoints[l].index = newRemoteLocation[localPoints[l]];
1027: }
1028: PetscFree2 (newLocation,newRemoteLocation);
1029: PetscSFSetGraph (gsfPoint, numRoots+user->numGhostCells, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);
1030: }
1031: DMDestroy (dmSplit);
1032: *dmSplit = sdm;
1033: return (0);
1034: }
1038: static PetscErrorCode IsExteriorOrGhostFace(DM dm,PetscInt face,PetscBool *isghost)
1039: {
1041: PetscInt ghost,boundary;
1044: *isghost = PETSC_FALSE ;
1045: DMPlexGetLabelValue (dm, "ghost" , face, &ghost);
1046: DMPlexGetLabelValue (dm, "Face Sets" , face, &boundary);
1047: if (ghost >= 0 || boundary >= 0) *isghost = PETSC_TRUE ;
1048: return (0);
1049: }
1053: /* Overwrites A. Can only handle full-rank problems with m>=n */
1054: static PetscErrorCode PseudoInverse(PetscInt m,PetscInt mstride,PetscInt n,PetscScalar *A,PetscScalar *Ainv,PetscScalar *tau,PetscInt worksize,PetscScalar *work)
1055: {
1056: PetscBool debug = PETSC_FALSE ;
1058: PetscBLASInt M,N,K,lda,ldb,ldwork,info;
1059: PetscScalar *R,*Q,*Aback,Alpha;
1062: if (debug) {
1063: PetscMalloc1 (m*n,&Aback);
1064: PetscMemcpy (Aback,A,m*n*sizeof (PetscScalar ));
1065: }
1067: PetscBLASIntCast(m,&M);
1068: PetscBLASIntCast(n,&N);
1069: PetscBLASIntCast(mstride,&lda);
1070: PetscBLASIntCast(worksize,&ldwork);
1071: PetscFPTrapPush (PETSC_FP_TRAP_OFF);
1072: LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info);
1073: PetscFPTrapPop ();
1074: if (info) SETERRQ (PETSC_COMM_SELF ,PETSC_ERR_LIB,"xGEQRF error" );
1075: R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */
1077: /* Extract an explicit representation of Q */
1078: Q = Ainv;
1079: PetscMemcpy (Q,A,mstride*n*sizeof (PetscScalar ));
1080: K = N; /* full rank */
1081: LAPACKungqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info);
1082: if (info) SETERRQ (PETSC_COMM_SELF ,PETSC_ERR_LIB,"xORGQR/xUNGQR error" );
1084: /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */
1085: Alpha = 1.0;
1086: ldb = lda;
1087: BLAStrsm_("Right" ,"Upper" ,"ConjugateTranspose" ,"NotUnitTriangular" ,&M,&N,&Alpha,R,&lda,Q,&ldb);
1088: /* Ainv is Q, overwritten with inverse */
1090: if (debug) { /* Check that pseudo-inverse worked */
1091: PetscScalar Beta = 0.0;
1092: PetscInt ldc;
1093: K = N;
1094: ldc = N;
1095: BLASgemm_("ConjugateTranspose" ,"Normal" ,&N,&K,&M,&Alpha,Ainv,&lda,Aback,&ldb,&Beta,work,&ldc);
1096: PetscScalarView (n*n,work,PETSC_VIEWER_STDOUT_SELF );
1097: PetscFree (Aback);
1098: }
1099: return (0);
1100: }
1104: static PetscErrorCode PseudoInverseGetWorkRequired(PetscInt maxFaces,PetscInt *work)
1105: {
1106: PetscInt m,n,nrhs,minwork;
1109: m = maxFaces;
1110: n = DIM;
1111: nrhs = maxFaces;
1112: minwork = 3*PetscMin(m,n) + PetscMax(2*PetscMin(m,n), PetscMax(PetscMax(m,n), nrhs)); /* required by LAPACK */
1113: *work = 5*minwork; /* We can afford to be extra generous */
1114: return (0);
1115: }
1119: /* Overwrites A. Can handle degenerate problems and m<n. */
1120: static PetscErrorCode PseudoInverseSVD(PetscInt m,PetscInt mstride,PetscInt n,PetscScalar *A,PetscScalar *Ainv,PetscScalar *tau,PetscInt worksize,PetscScalar *work)
1121: {
1122: PetscBool debug = PETSC_FALSE ;
1124: PetscInt i,j,maxmn;
1125: PetscBLASInt M,N,nrhs,lda,ldb,irank,ldwork,info;
1126: PetscScalar rcond,*tmpwork,*Brhs,*Aback;
1129: if (debug) {
1130: PetscMalloc1 (m*n,&Aback);
1131: PetscMemcpy (Aback,A,m*n*sizeof (PetscScalar ));
1132: }
1134: /* initialize to identity */
1135: tmpwork = Ainv;
1136: Brhs = work;
1137: maxmn = PetscMax(m,n);
1138: for (j=0; j<maxmn; j++) {
1139: for (i=0; i<maxmn; i++) Brhs[i + j*maxmn] = 1.0*(i == j);
1140: }
1142: PetscBLASIntCast(m,&M);
1143: PetscBLASIntCast(n,&N);
1144: nrhs = M;
1145: PetscBLASIntCast(mstride,&lda);
1146: PetscBLASIntCast(maxmn,&ldb);
1147: PetscBLASIntCast(worksize,&ldwork);
1148: rcond = -1;
1149: PetscFPTrapPush (PETSC_FP_TRAP_OFF);
1150: LAPACKgelss_(&M,&N,&nrhs,A,&lda,Brhs,&ldb,tau,&rcond,&irank,tmpwork,&ldwork,&info);
1151: PetscFPTrapPop ();
1152: if (info) SETERRQ (PETSC_COMM_SELF ,PETSC_ERR_LIB,"xGELSS error" );
1153: /* The following check should be turned into a diagnostic as soon as someone wants to do this intentionally */
1154: 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" );
1156: /* Brhs shaped (M,nrhs) column-major coldim=mstride was overwritten by Ainv shaped (N,nrhs) column-major coldim=maxmn.
1157: * Here we transpose to (N,nrhs) row-major rowdim=mstride. */
1158: for (i=0; i<n; i++) {
1159: for (j=0; j<nrhs; j++) Ainv[i*mstride+j] = Brhs[i + j*maxmn];
1160: }
1161: return (0);
1162: }
1166: /* Build least squares gradient reconstruction operators */
1167: static PetscErrorCode BuildLeastSquares(DM dm,PetscInt cEndInterior,DM dmFace,PetscScalar *fgeom,DM dmCell,PetscScalar *cgeom)
1168: {
1170: PetscInt c,cStart,cEnd,maxNumFaces,worksize;
1171: PetscScalar *B,*Binv,*work,*tau,**gref;
1174: DMPlexGetHeightStratum (dm,0,&cStart,&cEnd);
1175: DMPlexGetMaxSizes (dm,&maxNumFaces,NULL);
1176: PseudoInverseGetWorkRequired(maxNumFaces,&worksize);
1177: PetscMalloc5 (maxNumFaces*DIM,&B,worksize,&Binv,worksize,&work,maxNumFaces,&tau,maxNumFaces,&gref);
1178: for (c=cStart; c<cEndInterior; c++) {
1179: const PetscInt *faces;
1180: PetscInt numFaces,usedFaces,f,i,j;
1181: const CellGeom *cg;
1182: PetscBool ghost;
1183: DMPlexGetConeSize (dm,c,&numFaces);
1184: if (numFaces < DIM) SETERRQ2 (PETSC_COMM_SELF ,PETSC_ERR_ARG_INCOMP,"Cell %D has only %D faces, not enough for gradient reconstruction" ,c,numFaces);
1185: DMPlexGetCone (dm,c,&faces);
1186: DMPlexPointLocalRead (dmCell,c,cgeom,&cg);
1187: for (f=0,usedFaces=0; f<numFaces; f++) {
1188: const PetscInt *fcells;
1189: PetscInt ncell,side;
1190: FaceGeom *fg;
1191: const CellGeom *cg1;
1192: IsExteriorOrGhostFace(dm,faces[f],&ghost);
1193: if (ghost) continue ;
1194: DMPlexGetSupport (dm,faces[f],&fcells);
1195: side = (c != fcells[0]); /* c is on left=0 or right=1 of face */
1196: ncell = fcells[!side]; /* the neighbor */
1197: DMPlexPointLocalRef (dmFace,faces[f],fgeom,&fg);
1198: DMPlexPointLocalRead (dmCell,ncell,cgeom,&cg1);
1199: for (j=0; j<DIM; j++) B[j*numFaces+usedFaces] = cg1->centroid[j] - cg->centroid[j];
1200: gref[usedFaces++] = fg->grad[side]; /* Gradient reconstruction term will go here */
1201: }
1202: if (!usedFaces) SETERRQ (PETSC_COMM_SELF ,PETSC_ERR_USER,"Mesh contains isolated cell (no neighbors). Is it intentional?" );
1203: /* Overwrites B with garbage, returns Binv in row-major format */
1204: if (0) {
1205: PseudoInverse(usedFaces,numFaces,DIM,B,Binv,tau,worksize,work);
1206: } else {
1207: PseudoInverseSVD(usedFaces,numFaces,DIM,B,Binv,tau,worksize,work);
1208: }
1209: for (f=0,i=0; f<numFaces; f++) {
1210: IsExteriorOrGhostFace(dm,faces[f],&ghost);
1211: if (ghost) continue ;
1212: for (j=0; j<DIM; j++) gref[i][j] = Binv[j*numFaces+i];
1213: i++;
1214: }
1216: #if 1
1217: if (0) {
1218: PetscReal grad[2] = {0,0};
1219: for (f=0; f<numFaces; f++) {
1220: const PetscInt *fcells;
1221: const CellGeom *cg1;
1222: const FaceGeom *fg;
1223: DMPlexGetSupport (dm,faces[f],&fcells);
1224: DMPlexPointLocalRead (dmFace,faces[f],fgeom,&fg);
1225: for (i=0; i<2; i++) {
1226: if (fcells[i] == c) continue ;
1227: DMPlexPointLocalRead (dmCell,fcells[i],cgeom,&cg1);
1228: PetscScalar du = cg1->centroid[0] + 3*cg1->centroid[1] - (cg->centroid[0] + 3*cg->centroid[1]);
1229: grad[0] += fg->grad[!i][0] * du;
1230: grad[1] += fg->grad[!i][1] * du;
1231: }
1232: }
1233: printf("cell[%d] grad (%g,%g)\n" ,c,grad[0],grad[1]);
1234: }
1235: #endif
1236: }
1237: PetscFree5 (B,Binv,work,tau,gref);
1238: return (0);
1239: }
1243: /* Set up face data and cell data */
1244: PetscErrorCode ConstructGeometry(DM dm, Vec *facegeom, Vec *cellgeom, User user)
1245: {
1246: DM dmFace, dmCell;
1247: DMLabel ghostLabel;
1248: PetscSection sectionFace, sectionCell;
1249: PetscSection coordSection;
1250: Vec coordinates;
1251: PetscReal minradius;
1252: PetscScalar *fgeom, *cgeom;
1253: PetscInt dim, cStart, cEnd, c, fStart, fEnd, f;
1257: DMPlexGetDimension (dm, &dim);
1258: if (dim != DIM) SETERRQ2 (PetscObjectComm ((PetscObject )dm),PETSC_ERR_SUP,"No support for dim %D != DIM %D" ,dim,DIM);
1259: DMGetCoordinateSection (dm, &coordSection);
1260: DMGetCoordinatesLocal (dm, &coordinates);
1262: /* Make cell centroids and volumes */
1263: DMClone (dm, &dmCell);
1264: DMSetCoordinateSection (dmCell, coordSection);
1265: DMSetCoordinatesLocal (dmCell, coordinates);
1266: PetscSectionCreate (PetscObjectComm ((PetscObject )dm), §ionCell);
1267: DMPlexGetHeightStratum (dm, 0, &cStart, &cEnd);
1268: PetscSectionSetChart (sectionCell, cStart, cEnd);
1269: for (c = cStart; c < cEnd; ++c) {
1270: PetscSectionSetDof (sectionCell, c, sizeof (CellGeom)/sizeof (PetscScalar ));
1271: }
1272: PetscSectionSetUp (sectionCell);
1273: DMSetDefaultSection (dmCell, sectionCell);
1274: PetscSectionDestroy (§ionCell); /* relinquish our reference */
1276: DMCreateLocalVector (dmCell, cellgeom);
1277: VecGetArray (*cellgeom, &cgeom);
1278: for (c = cStart; c < user->cEndInterior; ++c) {
1279: CellGeom *cg;
1281: DMPlexPointLocalRef (dmCell, c, cgeom, &cg);
1282: PetscMemzero (cg,sizeof (*cg));
1283: DMPlexComputeCellGeometryFVM (dmCell, c, &cg->volume, cg->centroid, NULL);
1284: }
1285: /* Compute face normals and minimum cell radius */
1286: DMClone (dm, &dmFace);
1287: PetscSectionCreate (PetscObjectComm ((PetscObject )dm), §ionFace);
1288: DMPlexGetHeightStratum (dm, 1, &fStart, &fEnd);
1289: PetscSectionSetChart (sectionFace, fStart, fEnd);
1290: for (f = fStart; f < fEnd; ++f) {
1291: PetscSectionSetDof (sectionFace, f, sizeof (FaceGeom)/sizeof (PetscScalar ));
1292: }
1293: PetscSectionSetUp (sectionFace);
1294: DMSetDefaultSection (dmFace, sectionFace);
1295: PetscSectionDestroy (§ionFace);
1296: DMCreateLocalVector (dmFace, facegeom);
1297: VecGetArray (*facegeom, &fgeom);
1298: DMPlexGetLabel (dm, "ghost" , &ghostLabel);
1299: minradius = PETSC_MAX_REAL;
1300: for (f = fStart; f < fEnd; ++f) {
1301: FaceGeom *fg;
1302: PetscInt ghost;
1304: DMLabelGetValue (ghostLabel, f, &ghost);
1305: if (ghost >= 0) continue ;
1306: DMPlexPointLocalRef (dmFace, f, fgeom, &fg);
1307: DMPlexComputeCellGeometryFVM (dm, f, NULL, fg->centroid, fg->normal);
1308: /* Flip face orientation if necessary to match ordering in support, and Update minimum radius */
1309: {
1310: CellGeom *cL, *cR;
1311: const PetscInt *cells;
1312: PetscReal *lcentroid, *rcentroid;
1313: PetscScalar v[3];
1314: PetscInt d;
1316: DMPlexGetSupport (dm, f, &cells);
1317: DMPlexPointLocalRead (dmCell, cells[0], cgeom, &cL);
1318: DMPlexPointLocalRead (dmCell, cells[1], cgeom, &cR);
1319: lcentroid = cells[0] >= user->cEndInterior ? fg->centroid : cL->centroid;
1320: rcentroid = cells[1] >= user->cEndInterior ? fg->centroid : cR->centroid;
1321: WaxpyD(dim, -1, lcentroid, rcentroid, v);
1322: if (DotD(dim, fg->normal, v) < 0) {
1323: for (d = 0; d < dim; ++d) fg->normal[d] = -fg->normal[d];
1324: }
1325: if (DotD(dim, fg->normal, v) <= 0) {
1326: #if DIM == 2
1327: SETERRQ5(PETSC_COMM_SELF ,PETSC_ERR_PLIB,"Direction for face %d could not be fixed, normal (%g,%g) v (%g,%g)" , f, fg->normal[0], fg->normal[1], v[0], v[1]);
1328: #elif DIM == 3
1329: SETERRQ7(PETSC_COMM_SELF ,PETSC_ERR_PLIB,"Direction for face %d could not be fixed, normal (%g,%g,%g) v (%g,%g,%g)" , f, fg->normal[0], fg->normal[1], fg->normal[2], v[0], v[1], v[2]);
1330: #else
1331: # error DIM not supported
1332: #endif
1333: }
1334: if (cells[0] < user->cEndInterior) {
1335: WaxpyD(dim, -1, fg->centroid, cL->centroid, v);
1336: minradius = PetscMin(minradius, NormD(dim, v));
1337: }
1338: if (cells[1] < user->cEndInterior) {
1339: WaxpyD(dim, -1, fg->centroid, cR->centroid, v);
1340: minradius = PetscMin(minradius, NormD(dim, v));
1341: }
1342: }
1343: }
1344: /* Compute centroids of ghost cells */
1345: for (c = user->cEndInterior; c < cEnd; ++c) {
1346: FaceGeom *fg;
1347: const PetscInt *cone, *support;
1348: PetscInt coneSize, supportSize, s;
1350: DMPlexGetConeSize (dmCell, c, &coneSize);
1351: if (coneSize != 1) SETERRQ2 (PETSC_COMM_SELF , PETSC_ERR_ARG_WRONG, "Ghost cell %d has cone size %d != 1" , c, coneSize);
1352: DMPlexGetCone (dmCell, c, &cone);
1353: DMPlexGetSupportSize (dmCell, cone[0], &supportSize);
1354: if (supportSize != 2) SETERRQ2 (PETSC_COMM_SELF , PETSC_ERR_ARG_WRONG, "Face %d has support size %d != 1" , cone[0], supportSize);
1355: DMPlexGetSupport (dmCell, cone[0], &support);
1356: DMPlexPointLocalRef (dmFace, cone[0], fgeom, &fg);
1357: for (s = 0; s < 2; ++s) {
1358: /* Reflect ghost centroid across plane of face */
1359: if (support[s] == c) {
1360: const CellGeom *ci;
1361: CellGeom *cg;
1362: PetscScalar c2f[3], a;
1364: DMPlexPointLocalRead (dmCell, support[(s+1)%2], cgeom, &ci);
1365: WaxpyD(dim, -1, ci->centroid, fg->centroid, c2f); /* cell to face centroid */
1366: a = DotD(dim, c2f, fg->normal)/DotD(dim, fg->normal, fg->normal);
1367: DMPlexPointLocalRef (dmCell, support[s], cgeom, &cg);
1368: WaxpyD(dim, 2*a, fg->normal, ci->centroid, cg->centroid);
1369: cg->volume = ci->volume;
1370: }
1371: }
1372: }
1373: if (user->reconstruct) {
1374: PetscSection sectionGrad;
1375: BuildLeastSquares(dm,user->cEndInterior,dmFace,fgeom,dmCell,cgeom);
1376: DMClone (dm,&user->dmGrad);
1377: PetscSectionCreate (PetscObjectComm ((PetscObject )dm),§ionGrad);
1378: PetscSectionSetChart (sectionGrad,cStart,cEnd);
1379: for (c=cStart; c<cEnd; c++) {
1380: PetscSectionSetDof (sectionGrad,c,user->model->physics->dof*DIM);
1381: }
1382: PetscSectionSetUp (sectionGrad);
1383: DMSetDefaultSection (user->dmGrad,sectionGrad);
1384: PetscSectionDestroy (§ionGrad);
1385: }
1386: VecRestoreArray (*facegeom, &fgeom);
1387: VecRestoreArray (*cellgeom, &cgeom);
1388: MPI_Allreduce (&minradius, &user->minradius, 1, MPIU_SCALAR , MPI_MIN, PetscObjectComm ((PetscObject )dm));
1389: DMDestroy (&dmCell);
1390: DMDestroy (&dmFace);
1391: return (0);
1392: }
1396: PetscErrorCode CreatePartitionVec(DM dm, DM *dmCell, Vec *partition)
1397: {
1398: PetscSF sfPoint;
1399: PetscSection coordSection;
1400: Vec coordinates;
1401: PetscSection sectionCell;
1402: PetscScalar *part;
1403: PetscInt cStart, cEnd, c;
1404: PetscMPIInt rank;
1408: DMGetCoordinateSection (dm, &coordSection);
1409: DMGetCoordinatesLocal (dm, &coordinates);
1410: DMClone (dm, dmCell);
1411: DMGetPointSF (dm, &sfPoint);
1412: DMSetPointSF (*dmCell, sfPoint);
1413: DMSetCoordinateSection (*dmCell, coordSection);
1414: DMSetCoordinatesLocal (*dmCell, coordinates);
1415: MPI_Comm_rank (PetscObjectComm ((PetscObject )dm), &rank);
1416: PetscSectionCreate (PetscObjectComm ((PetscObject )dm), §ionCell);
1417: DMPlexGetHeightStratum (*dmCell, 0, &cStart, &cEnd);
1418: PetscSectionSetChart (sectionCell, cStart, cEnd);
1419: for (c = cStart; c < cEnd; ++c) {
1420: PetscSectionSetDof (sectionCell, c, 1);
1421: }
1422: PetscSectionSetUp (sectionCell);
1423: DMSetDefaultSection (*dmCell, sectionCell);
1424: PetscSectionDestroy (§ionCell);
1425: DMCreateLocalVector (*dmCell, partition);
1426: PetscObjectSetName ((PetscObject )*partition, "partition" );
1427: VecGetArray (*partition, &part);
1428: for (c = cStart; c < cEnd; ++c) {
1429: PetscScalar *p;
1431: DMPlexPointLocalRef (*dmCell, c, part, &p);
1432: p[0] = rank;
1433: }
1434: VecRestoreArray (*partition, &part);
1435: return (0);
1436: }
1440: PetscErrorCode CreateMassMatrix(DM dm, Vec *massMatrix, User user)
1441: {
1442: DM dmMass, dmFace, dmCell, dmCoord;
1443: PetscSection coordSection;
1444: Vec coordinates;
1445: PetscSection sectionMass;
1446: PetscScalar *m;
1447: const PetscScalar *facegeom, *cellgeom, *coords;
1448: PetscInt vStart, vEnd, v;
1449: PetscErrorCode ierr;
1452: DMGetCoordinateSection (dm, &coordSection);
1453: DMGetCoordinatesLocal (dm, &coordinates);
1454: DMClone (dm, &dmMass);
1455: DMSetCoordinateSection (dmMass, coordSection);
1456: DMSetCoordinatesLocal (dmMass, coordinates);
1457: PetscSectionCreate (PetscObjectComm ((PetscObject )dm), §ionMass);
1458: DMPlexGetDepthStratum (dm, 0, &vStart, &vEnd);
1459: PetscSectionSetChart (sectionMass, vStart, vEnd);
1460: for (v = vStart; v < vEnd; ++v) {
1461: PetscInt numFaces;
1463: DMPlexGetSupportSize (dmMass, v, &numFaces);
1464: PetscSectionSetDof (sectionMass, v, numFaces*numFaces);
1465: }
1466: PetscSectionSetUp (sectionMass);
1467: DMSetDefaultSection (dmMass, sectionMass);
1468: PetscSectionDestroy (§ionMass);
1469: DMGetLocalVector (dmMass, massMatrix);
1470: VecGetArray (*massMatrix, &m);
1471: VecGetDM (user->facegeom, &dmFace);
1472: VecGetArrayRead (user->facegeom, &facegeom);
1473: VecGetDM (user->cellgeom, &dmCell);
1474: VecGetArrayRead (user->cellgeom, &cellgeom);
1475: DMGetCoordinateDM (dm, &dmCoord);
1476: VecGetArrayRead (coordinates, &coords);
1477: for (v = vStart; v < vEnd; ++v) {
1478: const PetscInt *faces;
1479: const FaceGeom *fgA, *fgB, *cg;
1480: const PetscScalar *vertex;
1481: PetscInt numFaces, sides[2], f, g;
1483: DMPlexPointLocalRead (dmCoord, v, coords, &vertex);
1484: DMPlexGetSupportSize (dmMass, v, &numFaces);
1485: DMPlexGetSupport (dmMass, v, &faces);
1486: for (f = 0; f < numFaces; ++f) {
1487: sides[0] = faces[f];
1488: DMPlexPointLocalRead (dmFace, faces[f], facegeom, &fgA);
1489: for (g = 0; g < numFaces; ++g) {
1490: const PetscInt *cells = NULL;;
1491: PetscReal area = 0.0;
1492: PetscInt numCells;
1494: sides[1] = faces[g];
1495: DMPlexPointLocalRead (dmFace, faces[g], facegeom, &fgB);
1496: DMPlexGetJoin (dmMass, 2, sides, &numCells, &cells);
1497: if (numCells != 1) SETERRQ (PETSC_COMM_SELF , PETSC_ERR_LIB, "Invalid join for faces" );
1498: DMPlexPointLocalRead (dmCell, cells[0], cellgeom, &cg);
1499: area += PetscAbsScalar((vertex[0] - cg->centroid[0])*(fgA->centroid[1] - cg->centroid[1]) - (vertex[1] - cg->centroid[1])*(fgA->centroid[0] - cg->centroid[0]));
1500: area += PetscAbsScalar((vertex[0] - cg->centroid[0])*(fgB->centroid[1] - cg->centroid[1]) - (vertex[1] - cg->centroid[1])*(fgB->centroid[0] - cg->centroid[0]));
1501: m[f*numFaces+g] = Dot2(fgA->normal, fgB->normal)*area*0.5;
1502: DMPlexRestoreJoin (dmMass, 2, sides, &numCells, &cells);
1503: }
1504: }
1505: }
1506: VecRestoreArrayRead (user->facegeom, &facegeom);
1507: VecRestoreArrayRead (user->facegeom, &facegeom);
1508: VecRestoreArrayRead (coordinates, &coords);
1509: VecRestoreArray (*massMatrix, &m);
1510: DMDestroy (&dmMass);
1511: return (0);
1512: }
1516: PetscErrorCode SetUpLocalSpace(DM dm, User user)
1517: {
1518: PetscSection stateSection;
1519: Physics phys;
1520: PetscInt dof = user->model->physics->dof, *cind, d, stateSize, cStart, cEnd, c, i;
1524: DMPlexGetHeightStratum (dm, 0, &cStart, &cEnd);
1525: PetscSectionCreate (PetscObjectComm ((PetscObject )dm), &stateSection);
1526: phys = user->model->physics;
1527: PetscSectionSetNumFields (stateSection,phys->nfields);
1528: for (i=0; i<phys->nfields; i++) {
1529: PetscSectionSetFieldName (stateSection,i,phys->field_desc[i].name);
1530: PetscSectionSetFieldComponents (stateSection,i,phys->field_desc[i].dof);
1531: }
1532: PetscSectionSetChart (stateSection, cStart, cEnd);
1533: for (c = cStart; c < cEnd; ++c) {
1534: for (i=0; i<phys->nfields; i++) {
1535: PetscSectionSetFieldDof (stateSection,c,i,phys->field_desc[i].dof);
1536: }
1537: PetscSectionSetDof (stateSection, c, dof);
1538: }
1539: for (c = user->cEndInterior; c < cEnd; ++c) {
1540: PetscSectionSetConstraintDof (stateSection, c, dof);
1541: }
1542: PetscSectionSetUp (stateSection);
1543: PetscMalloc1 (dof, &cind);
1544: for (d = 0; d < dof; ++d) cind[d] = d;
1545: #if 0
1546: for (c = cStart; c < cEnd; ++c) {
1547: PetscInt val;
1549: DMPlexGetLabelValue (dm, "vtk" , c, &val);
1550: if (val < 0) {PetscSectionSetConstraintIndices(stateSection, c, cind);}
1551: }
1552: #endif
1553: for (c = user->cEndInterior; c < cEnd; ++c) {
1554: PetscSectionSetConstraintIndices(stateSection, c, cind);
1555: }
1556: PetscFree (cind);
1557: PetscSectionGetStorageSize (stateSection, &stateSize);
1558: DMSetDefaultSection (dm,stateSection);
1559: PetscSectionDestroy (&stateSection);
1560: return (0);
1561: }
1565: PetscErrorCode SetUpBoundaries(DM dm, User user)
1566: {
1567: Model mod = user->model;
1569: BoundaryLink b;
1572: PetscOptionsBegin (PetscObjectComm ((PetscObject )dm),NULL,"Boundary condition options" ,"" );
1573: for (b = mod->boundary; b; b=b->next) {
1574: char optname[512];
1575: PetscInt ids[512],len = 512;
1576: PetscBool flg;
1577: PetscSNPrintf (optname,sizeof optname,"-bc_%s" ,b->name);
1578: PetscMemzero (ids,sizeof (ids));
1579: PetscOptionsIntArray (optname,"List of boundary IDs" ,"" ,ids,&len,&flg);
1580: if (flg) {
1581: /* TODO: check all IDs to make sure they exist in the mesh */
1582: PetscFree (b->ids);
1583: b->numids = len;
1584: PetscMalloc1 (len,&b->ids);
1585: PetscMemcpy (b->ids,ids,len*sizeof (PetscInt ));
1586: }
1587: }
1588: PetscOptionsEnd ();
1589: return (0);
1590: }
1594: /* The ids are just defaults, can be overridden at command line. I expect to set defaults based on names in the future. */
1595: static PetscErrorCode ModelBoundaryRegister(Model mod,const char *name,BoundaryFunction bcFunc,void *ctx,PetscInt numids,const PetscInt *ids)
1596: {
1598: BoundaryLink link;
1601: PetscNew (&link);
1602: PetscStrallocpy (name,&link->name);
1603: link->numids = numids;
1604: PetscMalloc1 (numids,&link->ids);
1605: PetscMemcpy (link->ids,ids,numids*sizeof (PetscInt ));
1606: link->func = bcFunc;
1607: link->ctx = ctx;
1608: link->next = mod->boundary;
1609: mod->boundary = link;
1610: return (0);
1611: }
1615: static PetscErrorCode BoundaryLinkDestroy(BoundaryLink *link)
1616: {
1618: BoundaryLink l,next;
1621: if (!link) return (0);
1622: l = *link;
1623: *link = NULL;
1624: for (; l; l=next) {
1625: next = l->next;
1626: PetscFree (l->ids);
1627: PetscFree (l->name);
1628: PetscFree (l);
1629: }
1630: return (0);
1631: }
1635: static PetscErrorCode ModelBoundaryFind(Model mod,PetscInt id,BoundaryFunction *bcFunc,void **ctx)
1636: {
1637: BoundaryLink link;
1638: PetscInt i;
1641: *bcFunc = NULL;
1642: for (link=mod->boundary; link; link=link->next) {
1643: for (i=0; i<link->numids; i++) {
1644: if (link->ids[i] == id) {
1645: *bcFunc = link->func;
1646: *ctx = link->ctx;
1647: return (0);
1648: }
1649: }
1650: }
1651: SETERRQ1 (mod->comm,PETSC_ERR_USER,"Boundary ID %D not associated with any registered boundary condition" ,id);
1652: return (0);
1653: }
1656: /* Behavior will be different for multi-physics or when using non-default boundary conditions */
1657: static PetscErrorCode ModelSolutionSetDefault(Model mod,SolutionFunction func,void *ctx)
1658: {
1660: mod->solution = func;
1661: mod->solutionctx = ctx;
1662: return (0);
1663: }
1667: static PetscErrorCode ModelFunctionalRegister(Model mod,const char *name,PetscInt *offset,FunctionalFunction func,void *ctx)
1668: {
1670: FunctionalLink link,*ptr;
1671: PetscInt lastoffset = -1;
1674: for (ptr=&mod->functionalRegistry; *ptr; ptr = &(*ptr)->next) lastoffset = (*ptr)->offset;
1675: PetscNew (&link);
1676: PetscStrallocpy (name,&link->name);
1677: link->offset = lastoffset + 1;
1678: link->func = func;
1679: link->ctx = ctx;
1680: link->next = NULL;
1681: *ptr = link;
1682: *offset = link->offset;
1683: return (0);
1684: }
1688: static PetscErrorCode ModelFunctionalSetFromOptions(Model mod)
1689: {
1691: PetscInt i,j;
1692: FunctionalLink link;
1693: char *names[256];
1696: mod->numMonitored = ALEN(names);
1697: PetscOptionsStringArray ("-monitor" ,"list of functionals to monitor" ,"" ,names,&mod->numMonitored,NULL);
1698: /* Create list of functionals that will be computed somehow */
1699: PetscMalloc1 (mod->numMonitored,&mod->functionalMonitored);
1700: /* Create index of calls that we will have to make to compute these functionals (over-allocation in general). */
1701: PetscMalloc1 (mod->numMonitored,&mod->functionalCall);
1702: mod->numCall = 0;
1703: for (i=0; i<mod->numMonitored; i++) {
1704: for (link=mod->functionalRegistry; link; link=link->next) {
1705: PetscBool match;
1706: PetscStrcasecmp (names[i],link->name,&match);
1707: if (match) break ;
1708: }
1709: if (!link) SETERRQ1 (mod->comm,PETSC_ERR_USER,"No known functional '%s'" ,names[i]);
1710: mod->functionalMonitored[i] = link;
1711: for (j=0; j<i; j++) {
1712: if (mod->functionalCall[j]->func == link->func && mod->functionalCall[j]->ctx == link->ctx) goto next_name;
1713: }
1714: mod->functionalCall[mod->numCall++] = link; /* Just points to the first link using the result. There may be more results. */
1715: next_name:
1716: PetscFree (names[i]);
1717: }
1719: /* Find out the maximum index of any functional computed by a function we will be calling (even if we are not using it) */
1720: mod->maxComputed = -1;
1721: for (link=mod->functionalRegistry; link; link=link->next) {
1722: for (i=0; i<mod->numCall; i++) {
1723: FunctionalLink call = mod->functionalCall[i];
1724: if (link->func == call->func && link->ctx == call->ctx) {
1725: mod->maxComputed = PetscMax(mod->maxComputed,link->offset);
1726: }
1727: }
1728: }
1729: return (0);
1730: }
1734: static PetscErrorCode FunctionalLinkDestroy(FunctionalLink *link)
1735: {
1737: FunctionalLink l,next;
1740: if (!link) return (0);
1741: l = *link;
1742: *link = NULL;
1743: for (; l; l=next) {
1744: next = l->next;
1745: PetscFree (l->name);
1746: PetscFree (l);
1747: }
1748: return (0);
1749: }
1753: PetscErrorCode SetInitialCondition(DM dm, Vec X, User user)
1754: {
1755: DM dmCell;
1756: Model mod = user->model;
1757: const PetscScalar *cellgeom;
1758: PetscScalar *x;
1759: PetscInt cStart, cEnd, cEndInterior = user->cEndInterior, c;
1760: PetscErrorCode ierr;
1763: VecGetDM (user->cellgeom, &dmCell);
1764: DMPlexGetHeightStratum (dm, 0, &cStart, &cEnd);
1765: VecGetArrayRead (user->cellgeom, &cellgeom);
1766: VecGetArray (X, &x);
1767: for (c = cStart; c < cEndInterior; ++c) {
1768: const CellGeom *cg;
1769: PetscScalar *xc;
1771: DMPlexPointLocalRead (dmCell,c,cellgeom,&cg);
1772: DMPlexPointGlobalRef (dm,c,x,&xc);
1773: if (xc) {(*mod->solution)(mod,0.0,cg->centroid,xc,mod->solutionctx);}
1774: }
1775: VecRestoreArrayRead (user->cellgeom, &cellgeom);
1776: VecRestoreArray (X, &x);
1777: return (0);
1778: }
1782: static PetscErrorCode ApplyBC(DM dm, PetscReal time, Vec locX, User user)
1783: {
1784: Model mod = user->model;
1785: const char *name = "Face Sets" ;
1786: DM dmFace;
1787: IS idIS;
1788: const PetscInt *ids;
1789: PetscScalar *x;
1790: const PetscScalar *facegeom;
1791: PetscInt numFS, fs;
1792: PetscErrorCode ierr;
1795: VecGetDM (user->facegeom,&dmFace);
1796: DMPlexGetLabelIdIS (dm, name, &idIS);
1797: if (!idIS) return (0);
1798: ISGetLocalSize (idIS, &numFS);
1799: ISGetIndices (idIS, &ids);
1800: VecGetArrayRead (user->facegeom, &facegeom);
1801: VecGetArray (locX, &x);
1802: for (fs = 0; fs < numFS; ++fs) {
1803: BoundaryFunction bcFunc;
1804: void *bcCtx;
1805: IS faceIS;
1806: const PetscInt *faces;
1807: PetscInt numFaces, f;
1809: ModelBoundaryFind(mod,ids[fs],&bcFunc,&bcCtx);
1810: DMPlexGetStratumIS (dm, name, ids[fs], &faceIS);
1811: ISGetLocalSize (faceIS, &numFaces);
1812: ISGetIndices (faceIS, &faces);
1813: for (f = 0; f < numFaces; ++f) {
1814: const PetscInt face = faces[f], *cells;
1815: const PetscScalar *xI;
1816: PetscScalar *xG;
1817: const FaceGeom *fg;
1819: DMPlexPointLocalRead (dmFace, face, facegeom, &fg);
1820: DMPlexGetSupport (dm, face, &cells);
1821: DMPlexPointLocalRead (dm, cells[0], x, &xI);
1822: DMPlexPointLocalRef (dm, cells[1], x, &xG);
1823: (*bcFunc)(mod, time, fg->centroid, fg->normal, xI, xG, bcCtx);
1824: }
1825: ISRestoreIndices (faceIS, &faces);
1826: ISDestroy (&faceIS);
1827: }
1828: VecRestoreArray (locX, &x);
1829: VecRestoreArrayRead (user->facegeom,&facegeom);
1830: ISRestoreIndices (idIS, &ids);
1831: ISDestroy (&idIS);
1832: return (0);
1833: }
1837: static PetscErrorCode RHSFunctionLocal_Upwind(DM dm,DM dmFace,DM dmCell,PetscReal time,Vec locX,Vec F,User user)
1838: {
1839: Physics phys = user->model->physics;
1840: DMLabel ghostLabel;
1841: PetscErrorCode ierr;
1842: const PetscScalar *facegeom, *cellgeom, *x;
1843: PetscScalar *f;
1844: PetscInt fStart, fEnd, face;
1847: VecGetArrayRead (user->facegeom,&facegeom);
1848: VecGetArrayRead (user->cellgeom,&cellgeom);
1849: VecGetArrayRead (locX,&x);
1850: VecGetArray (F,&f);
1851: DMPlexGetLabel (dm, "ghost" , &ghostLabel);
1852: DMPlexGetHeightStratum (dm, 1, &fStart, &fEnd);
1853: for (face = fStart; face < fEnd; ++face) {
1854: const PetscInt *cells;
1855: PetscInt i,ghost;
1856: PetscScalar *flux = user->work.flux,*fL,*fR;
1857: const FaceGeom *fg;
1858: const CellGeom *cgL,*cgR;
1859: const PetscScalar *xL,*xR;
1861: DMLabelGetValue (ghostLabel, face, &ghost);
1862: if (ghost >= 0) continue ;
1863: DMPlexGetSupport (dm, face, &cells);
1864: DMPlexPointLocalRead (dmFace,face,facegeom,&fg);
1865: DMPlexPointLocalRead (dmCell,cells[0],cellgeom,&cgL);
1866: DMPlexPointLocalRead (dmCell,cells[1],cellgeom,&cgR);
1867: DMPlexPointLocalRead (dm,cells[0],x,&xL);
1868: DMPlexPointLocalRead (dm,cells[1],x,&xR);
1869: DMPlexPointGlobalRef (dm,cells[0],f,&fL);
1870: DMPlexPointGlobalRef (dm,cells[1],f,&fR);
1871: (*phys->riemann)(phys, fg->centroid, fg->normal, xL, xR, flux);
1872: for (i=0; i<phys->dof; i++) {
1873: if (fL) fL[i] -= flux[i] / cgL->volume;
1874: if (fR) fR[i] += flux[i] / cgR->volume;
1875: }
1876: }
1877: VecRestoreArrayRead (user->facegeom,&facegeom);
1878: VecRestoreArrayRead (user->cellgeom,&cellgeom);
1879: VecRestoreArrayRead (locX,&x);
1880: VecRestoreArray (F,&f);
1881: return (0);
1882: }
1886: static PetscErrorCode RHSFunctionLocal_LS(DM dm,DM dmFace,DM dmCell,PetscReal time,Vec locX,Vec F,User user)
1887: {
1888: DM dmGrad = user->dmGrad;
1889: Model mod = user->model;
1890: Physics phys = mod->physics;
1891: const PetscInt dof = phys->dof;
1892: PetscErrorCode ierr;
1893: const PetscScalar *facegeom, *cellgeom, *x;
1894: PetscScalar *f;
1895: PetscInt fStart, fEnd, face, cStart, cell;
1896: Vec locGrad,Grad;
1899: DMGetGlobalVector (dmGrad,&Grad);
1900: VecZeroEntries (Grad);
1901: VecGetArrayRead (user->facegeom,&facegeom);
1902: VecGetArrayRead (user->cellgeom,&cellgeom);
1903: VecGetArrayRead (locX,&x);
1904: DMPlexGetHeightStratum (dm, 1, &fStart, &fEnd);
1905: DMPlexGetHeightStratum (dm, 0, &cStart, NULL);
1906: {
1907: PetscScalar *grad;
1908: VecGetArray (Grad,&grad);
1909: /* Reconstruct gradients */
1910: for (face=fStart; face<fEnd; ++face) {
1911: const PetscInt *cells;
1912: const PetscScalar *cx[2];
1913: const FaceGeom *fg;
1914: PetscScalar *cgrad[2];
1915: PetscInt i,j;
1916: PetscBool ghost;
1918: IsExteriorOrGhostFace(dm,face,&ghost);
1919: if (ghost) continue ;
1920: DMPlexGetSupport (dm,face,&cells);
1921: DMPlexPointLocalRead (dmFace,face,facegeom,&fg);
1922: for (i=0; i<2; i++) {
1923: DMPlexPointLocalRead (dm,cells[i],x,&cx[i]);
1924: DMPlexPointGlobalRef (dmGrad,cells[i],grad,&cgrad[i]);
1925: }
1926: for (i=0; i<dof; i++) {
1927: PetscScalar delta = cx[1][i] - cx[0][i];
1928: for (j=0; j<DIM; j++) {
1929: if (cgrad[0]) cgrad[0][i*DIM+j] += fg->grad[0][j] * delta;
1930: if (cgrad[1]) cgrad[1][i*DIM+j] -= fg->grad[1][j] * delta;
1931: }
1932: }
1933: }
1934: /* Limit interior gradients. Using cell-based loop because it generalizes better to vector limiters. */
1935: for (cell=cStart; cell<user->cEndInterior; cell++) {
1936: const PetscInt *faces;
1937: PetscInt numFaces,f;
1938: PetscReal *cellPhi = user->work.state0; /* Scalar limiter applied to each component separately */
1939: const PetscScalar *cx;
1940: const CellGeom *cg;
1941: PetscScalar *cgrad;
1942: PetscInt i;
1943: DMPlexGetConeSize (dm,cell,&numFaces);
1944: DMPlexGetCone (dm,cell,&faces);
1945: DMPlexPointLocalRead (dm,cell,x,&cx);
1946: DMPlexPointLocalRead (dmCell,cell,cellgeom,&cg);
1947: DMPlexPointGlobalRef (dmGrad,cell,grad,&cgrad);
1948: if (!cgrad) continue ; /* ghost cell, we don't compute */
1949: /* Limiter will be minimum value over all neighbors */
1950: for (i=0; i<dof; i++) cellPhi[i] = PETSC_MAX_REAL;
1951: for (f=0; f<numFaces; f++) {
1952: const PetscScalar *ncx;
1953: const CellGeom *ncg;
1954: const PetscInt *fcells;
1955: PetscInt face = faces[f],ncell;
1956: PetscScalar v[DIM];
1957: PetscBool ghost;
1958: IsExteriorOrGhostFace(dm,face,&ghost);
1959: if (ghost) continue ;
1960: DMPlexGetSupport (dm,face,&fcells);
1961: ncell = cell == fcells[0] ? fcells[1] : fcells[0];
1962: DMPlexPointLocalRead (dm,ncell,x,&ncx);
1963: DMPlexPointLocalRead (dmCell,ncell,cellgeom,&ncg);
1964: Waxpy2(-1,cg->centroid,ncg->centroid,v);
1965: for (i=0; i<dof; i++) {
1966: /* We use the symmetric slope limited form of Berger, Aftosmis, and Murman 2005 */
1967: PetscScalar phi,flim = 0.5 * (ncx[i] - cx[i]) / Dot2(&cgrad[i*DIM],v);
1968: phi = (*user->Limit)(flim);
1969: cellPhi[i] = PetscMin(cellPhi[i],phi);
1970: }
1971: }
1972: /* Apply limiter to gradient */
1973: for (i=0; i<dof; i++) Scale2(cellPhi[i],&cgrad[i*DIM],&cgrad[i*DIM]);
1974: }
1975: VecRestoreArray (Grad,&grad);
1976: }
1977: DMGetLocalVector (dmGrad,&locGrad);
1978: DMGlobalToLocalBegin (dmGrad,Grad,INSERT_VALUES ,locGrad);
1979: DMGlobalToLocalEnd (dmGrad,Grad,INSERT_VALUES ,locGrad);
1980: DMRestoreGlobalVector (dmGrad,&Grad);
1982: {
1983: DMLabel ghostLabel, faceLabel;
1984: const PetscScalar *grad;
1985: DMPlexGetLabel (dm, "ghost" , &ghostLabel);
1986: DMPlexGetLabel (dm, "Face Sets" , &faceLabel);
1987: VecGetArrayRead (locGrad,&grad);
1988: VecGetArray (F,&f);
1989: for (face=fStart; face<fEnd; ++face) {
1990: const PetscInt *cells;
1991: PetscInt ghost,i,j,bset;
1992: PetscScalar *flux = user->work.flux,*fx[2] = {user->work.state0,user->work.state1},*cf[2];
1993: const FaceGeom *fg;
1994: const CellGeom *cg[2];
1995: const PetscScalar *cx[2],*cgrad[2];
1997: DMLabelGetValue (ghostLabel, face, &ghost);
1998: if (ghost >= 0) continue ;
1999: DMPlexGetSupport (dm, face, &cells);
2000: DMPlexPointLocalRead (dmFace,face,facegeom,&fg);
2001: for (i=0; i<2; i++) {
2002: PetscScalar dx[DIM];
2003: DMPlexPointLocalRead (dmCell,cells[i],cellgeom,&cg[i]);
2004: DMPlexPointLocalRead (dm,cells[i],x,&cx[i]);
2005: DMPlexPointLocalRead (dmGrad,cells[i],grad,&cgrad[i]);
2006: DMPlexPointGlobalRef (dm,cells[i],f,&cf[i]);
2007: Waxpy2(-1,cg[i]->centroid,fg->centroid,dx);
2008: for (j=0; j<dof; j++) fx[i][j] = cx[i][j] + Dot2(cgrad[i],dx);
2009: }
2010: DMLabelGetValue (faceLabel, face, &bset);
2011: if (bset != -1) {
2012: BoundaryFunction bcFunc;
2013: void *bcCtx;
2014: ModelBoundaryFind(mod,bset,&bcFunc,&bcCtx);
2015: (*bcFunc)(mod,time,fg->centroid,fg->normal,fx[0],fx[1],bcCtx);
2016: }
2017: (*phys->riemann)(phys, fg->centroid, fg->normal, fx[0], fx[1], flux);
2018: for (i=0; i<phys->dof; i++) {
2019: if (cf[0]) cf[0][i] -= flux[i] / cg[0]->volume;
2020: if (cf[1]) cf[1][i] += flux[i] / cg[1]->volume;
2021: }
2022: }
2023: VecRestoreArrayRead (locGrad,&grad);
2024: VecRestoreArray (F,&f);
2025: }
2026: VecRestoreArrayRead (user->facegeom,&facegeom);
2027: VecRestoreArrayRead (user->cellgeom,&cellgeom);
2028: VecRestoreArrayRead (locX,&x);
2029: DMRestoreLocalVector (dmGrad,&locGrad);
2030: return (0);
2031: }
2035: static PetscErrorCode RHSFunction(TS ts,PetscReal time,Vec X,Vec F,void *ctx)
2036: {
2037: User user = (User)ctx;
2038: DM dm, dmFace, dmCell;
2039: PetscSection section;
2040: Vec locX;
2044: TSGetDM (ts,&dm);
2045: VecGetDM (user->facegeom,&dmFace);
2046: VecGetDM (user->cellgeom,&dmCell);
2047: DMGetLocalVector (dm,&locX);
2048: DMGlobalToLocalBegin (dm, X, INSERT_VALUES , locX);
2049: DMGlobalToLocalEnd (dm, X, INSERT_VALUES , locX);
2050: DMGetDefaultSection (dm, §ion);
2052: ApplyBC(dm, time, locX, user);
2054: VecZeroEntries (F);
2055: (*user->RHSFunctionLocal)(dm,dmFace,dmCell,time,locX,F,user);
2056: DMRestoreLocalVector (dm,&locX);
2057: return (0);
2058: }
2062: static PetscErrorCode OutputVTK(DM dm, const char *filename, PetscViewer *viewer)
2063: {
2067: PetscViewerCreate (PetscObjectComm ((PetscObject )dm), viewer);
2068: PetscViewerSetType (*viewer, PETSCVIEWERVTK);
2069: PetscViewerFileSetName (*viewer, filename);
2070: return (0);
2071: }
2075: static PetscErrorCode MonitorVTK(TS ts,PetscInt stepnum,PetscReal time,Vec X,void *ctx)
2076: {
2077: User user = (User)ctx;
2078: DM dm;
2079: PetscViewer viewer;
2080: char filename[PETSC_MAX_PATH_LEN],*ftable = NULL;
2081: PetscReal xnorm;
2085: PetscObjectSetName ((PetscObject ) X, "solution" );
2086: VecGetDM (X,&dm);
2087: VecNorm (X,NORM_INFINITY ,&xnorm);
2088: if (stepnum >= 0) { /* No summary for final time */
2089: Model mod = user->model;
2090: PetscInt c,cStart,cEnd,fcount,i;
2091: size_t ftableused,ftablealloc;
2092: const PetscScalar *cellgeom,*x;
2093: DM dmCell;
2094: PetscReal *fmin,*fmax,*fintegral,*ftmp;
2095: fcount = mod->maxComputed+1;
2096: PetscMalloc4 (fcount,&fmin,fcount,&fmax,fcount,&fintegral,fcount,&ftmp);
2097: for (i=0; i<fcount; i++) {
2098: fmin[i] = PETSC_MAX_REAL;
2099: fmax[i] = PETSC_MIN_REAL;
2100: fintegral[i] = 0;
2101: }
2102: DMPlexGetHeightStratum (dm,0,&cStart,&cEnd);
2103: VecGetDM (user->cellgeom,&dmCell);
2104: VecGetArrayRead (user->cellgeom,&cellgeom);
2105: VecGetArrayRead (X,&x);
2106: for (c=cStart; c<user->cEndInterior; c++) {
2107: const CellGeom *cg;
2108: const PetscScalar *cx;
2109: DMPlexPointLocalRead (dmCell,c,cellgeom,&cg);
2110: DMPlexPointGlobalRead (dm,c,x,&cx);
2111: if (!cx) continue ; /* not a global cell */
2112: for (i=0; i<mod->numCall; i++) {
2113: FunctionalLink flink = mod->functionalCall[i];
2114: (*flink->func)(mod,time,cg->centroid,cx,ftmp,flink->ctx);
2115: }
2116: for (i=0; i<fcount; i++) {
2117: fmin[i] = PetscMin(fmin[i],ftmp[i]);
2118: fmax[i] = PetscMax(fmax[i],ftmp[i]);
2119: fintegral[i] += cg->volume * ftmp[i];
2120: }
2121: }
2122: VecRestoreArrayRead (user->cellgeom,&cellgeom);
2123: VecRestoreArrayRead (X,&x);
2124: MPI_Allreduce (MPI_IN_PLACE,fmin,fcount,MPIU_REAL,MPI_MIN,PetscObjectComm ((PetscObject )ts));
2125: MPI_Allreduce (MPI_IN_PLACE,fmax,fcount,MPIU_REAL,MPI_MAX,PetscObjectComm ((PetscObject )ts));
2126: MPI_Allreduce (MPI_IN_PLACE,fintegral,fcount,MPIU_REAL,MPI_SUM,PetscObjectComm ((PetscObject )ts));
2128: ftablealloc = fcount * 100;
2129: ftableused = 0;
2130: PetscMalloc (ftablealloc,&ftable);
2131: for (i=0; i<mod->numMonitored; i++) {
2132: size_t countused;
2133: char buffer[256],*p;
2134: FunctionalLink flink = mod->functionalMonitored[i];
2135: PetscInt id = flink->offset;
2136: if (i % 3) {
2137: PetscMemcpy (buffer," " ,2);
2138: p = buffer + 2;
2139: } else if (i) {
2140: char newline[] = "\n" ;
2141: PetscMemcpy (buffer,newline,sizeof newline-1);
2142: p = buffer + sizeof newline - 1;
2143: } else {
2144: p = buffer;
2145: }
2146: PetscSNPrintfCount (p,sizeof buffer-(p-buffer),"%12s [%10.7G,%10.7G] int %10.7G" ,&countused,flink->name,fmin[id],fmax[id],fintegral[id]);
2147: countused += p - buffer;
2148: if (countused > ftablealloc-ftableused-1) { /* reallocate */
2149: char *ftablenew;
2150: ftablealloc = 2*ftablealloc + countused;
2151: PetscMalloc (ftablealloc,&ftablenew);
2152: PetscMemcpy (ftablenew,ftable,ftableused);
2153: PetscFree (ftable);
2154: ftable = ftablenew;
2155: }
2156: PetscMemcpy (ftable+ftableused,buffer,countused);
2157: ftableused += countused;
2158: ftable[ftableused] = 0;
2159: }
2160: PetscFree4 (fmin,fmax,fintegral,ftmp);
2162: PetscPrintf (PetscObjectComm ((PetscObject )ts),"% 3D time %8.4G |x| %8.4G %s\n" ,stepnum,time,xnorm,ftable ? ftable : "" );
2163: PetscFree (ftable);
2164: }
2165: if (user->vtkInterval < 1) return (0);
2166: if ((stepnum == -1) ^ (stepnum % user->vtkInterval == 0)) {
2167: if (stepnum == -1) { /* Final time is not multiple of normal time interval, write it anyway */
2168: TSGetTimeStepNumber (ts,&stepnum);
2169: }
2170: PetscSNPrintf (filename,sizeof filename,"ex11-%03D.vtu" ,stepnum);
2171: OutputVTK(dm,filename,&viewer);
2172: VecView (X,viewer);
2173: PetscViewerDestroy (&viewer);
2174: }
2175: return (0);
2176: }
2180: int main(int argc, char **argv)
2181: {
2182: MPI_Comm comm;
2183: User user;
2184: Model mod;
2185: Physics phys;
2186: DM dm, dmDist;
2187: PetscReal ftime,cfl,dt;
2188: PetscInt dim, overlap, nsteps;
2189: int CPU_word_size = 0, IO_word_size = 0, exoid;
2190: float version;
2191: TS ts;
2192: TSConvergedReason reason;
2193: Vec X;
2194: PetscViewer viewer;
2195: PetscMPIInt rank;
2196: char filename[PETSC_MAX_PATH_LEN] = "sevenside.exo" ;
2197: PetscBool vtkCellGeom, splitFaces;
2198: PetscErrorCode ierr;
2200: PetscInitialize (&argc, &argv, (char*) 0, help);
2201: comm = PETSC_COMM_WORLD ;
2202: MPI_Comm_rank (comm, &rank);
2204: PetscNew (&user);
2205: PetscNew (&user->model);
2206: PetscNew (&user->model->physics);
2207: mod = user->model;
2208: phys = mod->physics;
2209: mod->comm = comm;
2211: /* Register physical models to be available on the command line */
2212: PetscFunctionListAdd (&PhysicsList,"advect" ,PhysicsCreate_Advect);
2213: PetscFunctionListAdd (&PhysicsList,"sw" ,PhysicsCreate_SW);
2214: PetscFunctionListAdd (&PhysicsList,"euler" ,PhysicsCreate_Euler);
2216: PetscFunctionListAdd (&LimitList,"zero" ,Limit_Zero);
2217: PetscFunctionListAdd (&LimitList,"none" ,Limit_None);
2218: PetscFunctionListAdd (&LimitList,"minmod" ,Limit_Minmod);
2219: PetscFunctionListAdd (&LimitList,"vanleer" ,Limit_VanLeer);
2220: PetscFunctionListAdd (&LimitList,"vanalbada" ,Limit_VanAlbada);
2221: PetscFunctionListAdd (&LimitList,"sin" ,Limit_Sin);
2222: PetscFunctionListAdd (&LimitList,"superbee" ,Limit_Superbee);
2223: PetscFunctionListAdd (&LimitList,"mc" ,Limit_MC);
2225: PetscOptionsBegin (comm,NULL,"Unstructured Finite Volume Options" ,"" );
2226: {
2227: char physname[256] = "advect" ,limitname[256] = "minmod" ;
2228: PetscErrorCode (*physcreate)(Model,Physics);
2229: cfl = 0.9 * 4; /* default SSPRKS2 with s=5 stages is stable for CFL number s-1 */
2230: PetscOptionsReal ("-ufv_cfl" ,"CFL number per step" ,"" ,cfl,&cfl,NULL);
2231: PetscOptionsString ("-f" ,"Exodus.II filename to read" ,"" ,filename,filename,sizeof (filename),NULL);
2232: user->vtkInterval = 1;
2233: PetscOptionsInt ("-ufv_vtk_interval" ,"VTK output interval (0 to disable)" ,"" ,user->vtkInterval,&user->vtkInterval,NULL);
2234: overlap = 1;
2235: PetscOptionsInt ("-ufv_mesh_overlap" ,"Number of cells to overlap partitions" ,"" ,overlap,&overlap,NULL);
2236: vtkCellGeom = PETSC_FALSE ;
2238: PetscOptionsBool ("-ufv_vtk_cellgeom" ,"Write cell geometry (for debugging)" ,"" ,vtkCellGeom,&vtkCellGeom,NULL);
2239: PetscOptionsFList ("-physics" ,"Physics module to solve" ,"" ,PhysicsList,physname,physname,sizeof physname,NULL);
2240: PetscFunctionListFind (PhysicsList,physname,&physcreate);
2241: PetscMemzero (phys,sizeof (struct _n_Physics ));
2242: (*physcreate)(mod,phys);
2243: mod->maxspeed = phys->maxspeed;
2244: /* Count number of fields and dofs */
2245: for (phys->nfields=0,phys->dof=0; phys->field_desc[phys->nfields].name; phys->nfields++) phys->dof += phys->field_desc[phys->nfields].dof;
2247: if (mod->maxspeed <= 0) SETERRQ1 (comm,PETSC_ERR_ARG_WRONGSTATE,"Physics '%s' did not set maxspeed" ,physname);
2248: if (phys->dof <= 0) SETERRQ1 (comm,PETSC_ERR_ARG_WRONGSTATE,"Physics '%s' did not set dof" ,physname);
2249: PetscMalloc3 (phys->dof,&user->work.flux,phys->dof,&user->work.state0,phys->dof,&user->work.state1);
2250: user->reconstruct = PETSC_FALSE ;
2251: PetscOptionsBool ("-ufv_reconstruct" ,"Reconstruct gradients for a second order method (grows stencil)" ,"" ,user->reconstruct,&user->reconstruct,NULL);
2252: user->RHSFunctionLocal = user->reconstruct ? RHSFunctionLocal_LS : RHSFunctionLocal_Upwind;
2253: splitFaces = PETSC_FALSE ;
2254: PetscOptionsBool ("-ufv_split_faces" ,"Split faces between cell sets" ,"" ,splitFaces,&splitFaces,NULL);
2255: if (user->reconstruct) {
2256: PetscOptionsFList ("-ufv_limit" ,"Limiter to apply to reconstructed solution" ,"" ,LimitList,limitname,limitname,sizeof limitname,NULL);
2257: PetscFunctionListFind (LimitList,limitname,&user->Limit);
2258: }
2259: ModelFunctionalSetFromOptions(mod);
2260: }
2261: PetscOptionsEnd ();
2263: if (!rank) {
2264: exoid = ex_open(filename, EX_READ, &CPU_word_size, &IO_word_size, &version);
2265: if (exoid <= 0) SETERRQ1 (PETSC_COMM_SELF ,PETSC_ERR_LIB,"ex_open(\"%s\",...) did not return a valid file ID" ,filename);
2266: } else exoid = -1; /* Not used */
2267: DMPlexCreateExodus (comm, exoid, PETSC_TRUE , &dm);
2268: if (!rank) {ex_close(exoid);}
2269: /* Distribute mesh */
2270: DMPlexDistribute (dm, "chaco" , overlap, NULL, &dmDist);
2271: if (dmDist) {
2272: DMDestroy (&dm);
2273: dm = dmDist;
2274: }
2275: DMSetFromOptions (dm);
2276: {
2277: DM gdm;
2279: DMPlexGetHeightStratum (dm, 0, NULL, &user->cEndInterior);
2280: DMPlexConstructGhostCells (dm, NULL, &user->numGhostCells, &gdm);
2281: DMDestroy (&dm);
2282: dm = gdm;
2283: }
2284: if (splitFaces) {ConstructCellBoundary(dm, user);}
2285: SplitFaces(&dm, "split faces" , user);
2286: ConstructGeometry(dm, &user->facegeom, &user->cellgeom, user);
2287: if (0) {VecView (user->cellgeom, PETSC_VIEWER_STDOUT_WORLD );}
2288: DMPlexGetDimension (dm, &dim);
2289: DMPlexSetPreallocationCenterDimension (dm, 0);
2291: /* Set up DM with section describing local vector and configure local vector. */
2292: SetUpLocalSpace(dm, user);
2293: SetUpBoundaries(dm, user);
2295: DMCreateGlobalVector (dm, &X);
2296: PetscObjectSetName ((PetscObject ) X, "solution" );
2297: SetInitialCondition(dm, X, user);
2298: if (vtkCellGeom) {
2299: DM dmCell;
2300: Vec partition;
2302: OutputVTK(dm, "ex11-cellgeom.vtk" , &viewer);
2303: VecView (user->cellgeom, viewer);
2304: PetscViewerDestroy (&viewer);
2305: CreatePartitionVec(dm, &dmCell, &partition);
2306: OutputVTK(dmCell, "ex11-partition.vtk" , &viewer);
2307: VecView (partition, viewer);
2308: PetscViewerDestroy (&viewer);
2309: VecDestroy (&partition);
2310: DMDestroy (&dmCell);
2311: }
2313: TSCreate (comm, &ts);
2314: TSSetType (ts, TSSSP );
2315: TSSetDM (ts, dm);
2316: TSMonitorSet (ts,MonitorVTK,user,NULL);
2317: TSSetRHSFunction (ts,NULL,RHSFunction,user);
2318: TSSetDuration (ts,1000,2.0);
2319: dt = cfl * user->minradius / user->model->maxspeed;
2320: TSSetInitialTimeStep (ts,0.0,dt);
2321: TSSetFromOptions (ts);
2322: TSSolve (ts,X);
2323: TSGetSolveTime (ts,&ftime);
2324: TSGetTimeStepNumber (ts,&nsteps);
2325: TSGetConvergedReason (ts,&reason);
2326: PetscPrintf (PETSC_COMM_WORLD ,"%s at time %g after %D steps\n" ,TSConvergedReasons[reason],(double)ftime,nsteps);
2327: TSDestroy (&ts);
2329: VecDestroy (&user->cellgeom);
2330: VecDestroy (&user->facegeom);
2331: DMDestroy (&user->dmGrad);
2332: PetscFunctionListDestroy (&PhysicsList);
2333: PetscFunctionListDestroy (&LimitList);
2334: BoundaryLinkDestroy(&user->model->boundary);
2335: FunctionalLinkDestroy(&user->model->functionalRegistry);
2336: PetscFree (user->model->functionalMonitored);
2337: PetscFree (user->model->functionalCall);
2338: PetscFree (user->model->physics->data);
2339: PetscFree (user->model->physics);
2340: PetscFree (user->model);
2341: PetscFree3 (user->work.flux,user->work.state0,user->work.state1);
2342: PetscFree (user);
2343: VecDestroy (&X);
2344: DMDestroy (&dm);
2345: PetscFinalize ();
2346: return (0);
2347: }