xref: /petsc/src/ts/tutorials/ex30.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
1811d88abSStefano Zampini static char help[] = "Biological network from https://link.springer.com/article/10.1007/s42967-023-00297-3\n\n\n";
2811d88abSStefano Zampini 
3811d88abSStefano Zampini #include <petscts.h>
4811d88abSStefano Zampini #include <petscsf.h>
5811d88abSStefano Zampini #include <petscdmplex.h>
6811d88abSStefano Zampini #include <petscdmplextransform.h>
7811d88abSStefano Zampini #include <petscdmforest.h>
8811d88abSStefano Zampini #include <petscviewerhdf5.h>
9811d88abSStefano Zampini #include <petscds.h>
10811d88abSStefano Zampini 
11811d88abSStefano Zampini /*
1266edf50cSStefano Zampini     Here we solve the system of PDEs on \Omega \in R^d:
13811d88abSStefano Zampini 
1466edf50cSStefano Zampini     * dC/dt - D^2 \Delta C - \nabla p \cross \nabla p + \alpha sqrt(||C||^2_F + eps)^(\gamma-2) C = 0
15811d88abSStefano Zampini     * - \nabla \cdot ((r + C) \nabla p) = S
16811d88abSStefano Zampini 
17811d88abSStefano Zampini     where:
1866edf50cSStefano Zampini       C = symmetric dxd conductivity tensor
19811d88abSStefano Zampini       p = potential
20811d88abSStefano Zampini       S = source
21811d88abSStefano Zampini 
22811d88abSStefano Zampini     with natural boundary conditions on \partial\Omega:
23811d88abSStefano Zampini       \nabla C \cdot n  = 0
24811d88abSStefano Zampini       \nabla ((r + C)\nabla p) \cdot n  = 0
25811d88abSStefano Zampini 
26811d88abSStefano Zampini     Parameters:
27811d88abSStefano Zampini       D = diffusion constant
28811d88abSStefano Zampini       \alpha = metabolic coefficient
29811d88abSStefano Zampini       \gamma = metabolic exponent
30811d88abSStefano Zampini       r, eps are regularization parameters
31811d88abSStefano Zampini 
32811d88abSStefano Zampini     We use Lagrange elements for C_ij and P.
3366edf50cSStefano Zampini     Equations are rescaled to obtain a symmetric Jacobian.
34811d88abSStefano Zampini */
35811d88abSStefano Zampini 
36811d88abSStefano Zampini typedef enum _fieldidx {
37811d88abSStefano Zampini   C_FIELD_ID = 0,
38811d88abSStefano Zampini   P_FIELD_ID,
39811d88abSStefano Zampini   NUM_FIELDS
40811d88abSStefano Zampini } FieldIdx;
41811d88abSStefano Zampini 
42811d88abSStefano Zampini typedef enum _constantidx {
43811d88abSStefano Zampini   R_ID = 0,
44811d88abSStefano Zampini   EPS_ID,
45811d88abSStefano Zampini   ALPHA_ID,
46811d88abSStefano Zampini   GAMMA_ID,
47811d88abSStefano Zampini   D_ID,
48204aa523SStefano Zampini   FIXC_ID,
4966edf50cSStefano Zampini   SPLIT_ID,
50811d88abSStefano Zampini   NUM_CONSTANTS
51811d88abSStefano Zampini } ConstantIdx;
52811d88abSStefano Zampini 
53811d88abSStefano Zampini PetscLogStage SetupStage, SolveStage;
54811d88abSStefano Zampini 
5566edf50cSStefano Zampini #define NORM2C(c00, c01, c11)                   (PetscSqr(c00) + 2 * PetscSqr(c01) + PetscSqr(c11))
5666edf50cSStefano Zampini #define NORM2C_3d(c00, c01, c02, c11, c12, c22) (PetscSqr(c00) + 2 * PetscSqr(c01) + 2 * PetscSqr(c02) + PetscSqr(c11) + 2 * PetscSqr(c12) + PetscSqr(c22))
5766edf50cSStefano Zampini 
5866edf50cSStefano Zampini /* Eigenvalues real 3x3 symmetric matrix https://onlinelibrary.wiley.com/doi/full/10.1002/nme.7153 */
5966edf50cSStefano Zampini #if !PetscDefined(USE_COMPLEX)
Eigenvalues_Sym3x3(PetscReal a11,PetscReal a12,PetscReal a13,PetscReal a22,PetscReal a23,PetscReal a33,PetscReal x[3])6066edf50cSStefano Zampini static inline void Eigenvalues_Sym3x3(PetscReal a11, PetscReal a12, PetscReal a13, PetscReal a22, PetscReal a23, PetscReal a33, PetscReal x[3])
6166edf50cSStefano Zampini {
6266edf50cSStefano Zampini   const PetscBool td = (PetscBool)(a13 == 0 && a23 == 0);
6366edf50cSStefano Zampini   if (td) { /* two-dimensional case */
6466edf50cSStefano Zampini     PetscReal a12_2 = PetscSqr(a12);
6566edf50cSStefano Zampini     PetscReal delta = PetscSqr(a11 - a22) + 4 * a12_2;
6666edf50cSStefano Zampini     PetscReal b     = -(a11 + a22);
6766edf50cSStefano Zampini     PetscReal c     = a11 * a22 - a12_2;
6866edf50cSStefano Zampini     PetscReal temp  = -0.5 * (b + PetscCopysignReal(1.0, b) * PetscSqrtReal(delta));
6966edf50cSStefano Zampini 
7066edf50cSStefano Zampini     x[0] = temp;
7166edf50cSStefano Zampini     x[1] = c / temp;
7266edf50cSStefano Zampini     x[2] = a33;
7366edf50cSStefano Zampini   } else {
7466edf50cSStefano Zampini     const PetscReal I1  = a11 + a22 + a33;
7566edf50cSStefano Zampini     const PetscReal J2  = (PetscSqr(a11 - a22) + PetscSqr(a22 - a33) + PetscSqr(a33 - a11)) / 6 + PetscSqr(a12) + PetscSqr(a23) + PetscSqr(a13);
7666edf50cSStefano Zampini     const PetscReal s   = PetscSqrtReal(J2 / 3);
7766edf50cSStefano Zampini     const PetscReal tol = PETSC_MACHINE_EPSILON;
7866edf50cSStefano Zampini 
7966edf50cSStefano Zampini     if (s < tol) {
8066edf50cSStefano Zampini       x[0] = x[1] = x[2] = 0.0;
8166edf50cSStefano Zampini     } else {
8266edf50cSStefano Zampini       const PetscReal S[] = {a11 - I1 / 3, a12, a13, a22 - I1 / 3, a23, a33 - I1 / 3};
8366edf50cSStefano Zampini 
8466edf50cSStefano Zampini       /* T = S^2 */
8566edf50cSStefano Zampini       PetscReal T[6];
8666edf50cSStefano Zampini       T[0] = S[0] * S[0] + S[1] * S[1] + S[2] * S[2];
8766edf50cSStefano Zampini       T[1] = S[0] * S[1] + S[1] * S[3] + S[2] * S[4];
8866edf50cSStefano Zampini       T[2] = S[0] * S[2] + S[1] * S[4] + S[2] * S[5];
8966edf50cSStefano Zampini       T[3] = S[1] * S[1] + S[3] * S[3] + S[4] * S[4];
9066edf50cSStefano Zampini       T[4] = S[1] * S[2] + S[3] * S[4] + S[4] * S[5];
9166edf50cSStefano Zampini       T[5] = S[2] * S[2] + S[4] * S[4] + S[5] * S[5];
9266edf50cSStefano Zampini 
9366edf50cSStefano Zampini       T[0] = T[0] - 2.0 * J2 / 3.0;
9466edf50cSStefano Zampini       T[3] = T[3] - 2.0 * J2 / 3.0;
9566edf50cSStefano Zampini       T[5] = T[5] - 2.0 * J2 / 3.0;
9666edf50cSStefano Zampini 
9766edf50cSStefano Zampini       const PetscReal aa = NORM2C_3d(T[0] - s * S[0], T[1] - s * S[1], T[2] - s * S[2], T[3] - s * S[3], T[4] - s * S[4], T[5] - s * S[5]);
9866edf50cSStefano Zampini       const PetscReal bb = NORM2C_3d(T[0] + s * S[0], T[1] + s * S[1], T[2] + s * S[2], T[3] + s * S[3], T[4] + s * S[4], T[5] + s * S[5]);
9966edf50cSStefano Zampini       const PetscReal d  = PetscSqrtReal(aa / bb);
10066edf50cSStefano Zampini       const PetscBool sj = (PetscBool)(1.0 - d > 0.0);
10166edf50cSStefano Zampini 
10266edf50cSStefano Zampini       if (PetscAbsReal(1 - d) < tol) {
10366edf50cSStefano Zampini         x[0] = -PetscSqrtReal(J2);
10466edf50cSStefano Zampini         x[1] = 0.0;
10566edf50cSStefano Zampini         x[2] = PetscSqrtReal(J2);
10666edf50cSStefano Zampini       } else {
10766edf50cSStefano Zampini         const PetscReal sjn = sj ? 1.0 : -1.0;
10866edf50cSStefano Zampini         //const PetscReal atanarg = sj ? d : 1.0 / d;
10966edf50cSStefano Zampini         //const PetscReal alpha   = 2.0 * PetscAtanReal(atanarg) / 3.0;
11066edf50cSStefano Zampini         const PetscReal atanval = d > tol ? 2.0 * PetscAtanReal(sj ? d : 1.0 / d) : (sj ? 0.0 : PETSC_PI);
11166edf50cSStefano Zampini         const PetscReal alpha   = atanval / 3.0;
11266edf50cSStefano Zampini         const PetscReal cd      = s * PetscCosReal(alpha) * sjn;
11366edf50cSStefano Zampini         const PetscReal sd      = PetscSqrtReal(J2) * PetscSinReal(alpha);
11466edf50cSStefano Zampini 
11566edf50cSStefano Zampini         x[0] = 2 * cd;
11666edf50cSStefano Zampini         x[1] = -cd + sd;
11766edf50cSStefano Zampini         x[2] = -cd - sd;
11866edf50cSStefano Zampini       }
11966edf50cSStefano Zampini     }
12066edf50cSStefano Zampini     x[0] += I1 / 3.0;
12166edf50cSStefano Zampini     x[1] += I1 / 3.0;
12266edf50cSStefano Zampini     x[2] += I1 / 3.0;
12366edf50cSStefano Zampini   }
12466edf50cSStefano Zampini }
12566edf50cSStefano Zampini #endif
12666edf50cSStefano Zampini 
12766edf50cSStefano Zampini /* compute shift to make C positive definite */
FIX_C_3d(PetscScalar C00,PetscScalar C01,PetscScalar C02,PetscScalar C11,PetscScalar C12,PetscScalar C22)12866edf50cSStefano Zampini static inline PetscReal FIX_C_3d(PetscScalar C00, PetscScalar C01, PetscScalar C02, PetscScalar C11, PetscScalar C12, PetscScalar C22)
12966edf50cSStefano Zampini {
13066edf50cSStefano Zampini #if !PetscDefined(USE_COMPLEX)
13166edf50cSStefano Zampini   PetscReal eigs[3], s = 0.0;
13266edf50cSStefano Zampini   PetscBool twod = (PetscBool)(C02 == 0 && C12 == 0 && C22 == 0);
13366edf50cSStefano Zampini   Eigenvalues_Sym3x3(C00, C01, C02, C11, C12, C22, eigs);
13466edf50cSStefano Zampini   if (twod) eigs[2] = 1.0;
13566edf50cSStefano Zampini   if (eigs[0] <= 0 || eigs[1] <= 0 || eigs[2] <= 0) s = -PetscMin(eigs[0], PetscMin(eigs[1], eigs[2])) + PETSC_SMALL;
13666edf50cSStefano Zampini   return s;
13766edf50cSStefano Zampini #else
13866edf50cSStefano Zampini   return 0.0;
13966edf50cSStefano Zampini #endif
14066edf50cSStefano Zampini }
14166edf50cSStefano Zampini 
FIX_C(PetscScalar C00,PetscScalar C01,PetscScalar C11)14266edf50cSStefano Zampini static inline PetscReal FIX_C(PetscScalar C00, PetscScalar C01, PetscScalar C11)
14366edf50cSStefano Zampini {
14466edf50cSStefano Zampini   return FIX_C_3d(C00, C01, 0, C11, 0, 0);
14566edf50cSStefano Zampini }
146811d88abSStefano Zampini 
147811d88abSStefano Zampini /* residual for C when tested against basis functions */
C_0(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])148811d88abSStefano Zampini static void C_0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
149811d88abSStefano Zampini {
150811d88abSStefano Zampini   const PetscReal    alpha    = PetscRealPart(constants[ALPHA_ID]);
151811d88abSStefano Zampini   const PetscReal    gamma    = PetscRealPart(constants[GAMMA_ID]);
152811d88abSStefano Zampini   const PetscReal    eps      = PetscRealPart(constants[EPS_ID]);
15366edf50cSStefano Zampini   const PetscBool    split    = (PetscBool)(PetscRealPart(constants[SPLIT_ID]) != 0.0);
15466edf50cSStefano Zampini   const PetscScalar *gradp    = split ? a_x + aOff_x[P_FIELD_ID] : u_x + uOff_x[P_FIELD_ID];
15566edf50cSStefano Zampini   const PetscScalar  outerp[] = {gradp[0] * gradp[0], gradp[0] * gradp[1], gradp[1] * gradp[1]};
15666edf50cSStefano Zampini   const PetscScalar  C00      = split ? a[aOff[C_FIELD_ID]] : u[uOff[C_FIELD_ID]];
15766edf50cSStefano Zampini   const PetscScalar  C01      = split ? a[aOff[C_FIELD_ID] + 1] : u[uOff[C_FIELD_ID] + 1];
15866edf50cSStefano Zampini   const PetscScalar  C11      = split ? a[aOff[C_FIELD_ID] + 2] : u[uOff[C_FIELD_ID] + 2];
159811d88abSStefano Zampini   const PetscScalar  norm     = NORM2C(C00, C01, C11) + eps;
160811d88abSStefano Zampini   const PetscScalar  nexp     = (gamma - 2.0) / 2.0;
161811d88abSStefano Zampini   const PetscScalar  fnorm    = PetscPowScalar(norm, nexp);
16266edf50cSStefano Zampini   const PetscScalar  eqss[]   = {0.5, 1., 0.5}; /* equations rescaling for a symmetric Jacobian */
163811d88abSStefano Zampini 
16466edf50cSStefano Zampini   for (PetscInt k = 0; k < 3; k++) f0[k] = eqss[k] * (u_t[uOff[C_FIELD_ID] + k] - outerp[k] + alpha * fnorm * u[uOff[C_FIELD_ID] + k]);
16566edf50cSStefano Zampini }
16666edf50cSStefano Zampini 
16766edf50cSStefano Zampini /* 3D version */
C_0_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])16866edf50cSStefano Zampini static void C_0_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
16966edf50cSStefano Zampini {
17066edf50cSStefano Zampini   const PetscReal    alpha    = PetscRealPart(constants[ALPHA_ID]);
17166edf50cSStefano Zampini   const PetscReal    gamma    = PetscRealPart(constants[GAMMA_ID]);
17266edf50cSStefano Zampini   const PetscReal    eps      = PetscRealPart(constants[EPS_ID]);
17366edf50cSStefano Zampini   const PetscBool    split    = (PetscBool)(PetscRealPart(constants[SPLIT_ID]) != 0.0);
17466edf50cSStefano Zampini   const PetscScalar *gradp    = split ? a_x + aOff_x[P_FIELD_ID] : u_x + uOff_x[P_FIELD_ID];
17566edf50cSStefano Zampini   const PetscScalar  outerp[] = {gradp[0] * gradp[0], gradp[0] * gradp[1], gradp[0] * gradp[2], gradp[1] * gradp[1], gradp[1] * gradp[2], gradp[2] * gradp[2]};
17666edf50cSStefano Zampini   const PetscScalar  C00      = split ? a[aOff[C_FIELD_ID]] : u[uOff[C_FIELD_ID]];
17766edf50cSStefano Zampini   const PetscScalar  C01      = split ? a[aOff[C_FIELD_ID] + 1] : u[uOff[C_FIELD_ID] + 1];
17866edf50cSStefano Zampini   const PetscScalar  C02      = split ? a[aOff[C_FIELD_ID] + 2] : u[uOff[C_FIELD_ID] + 2];
17966edf50cSStefano Zampini   const PetscScalar  C11      = split ? a[aOff[C_FIELD_ID] + 3] : u[uOff[C_FIELD_ID] + 3];
18066edf50cSStefano Zampini   const PetscScalar  C12      = split ? a[aOff[C_FIELD_ID] + 4] : u[uOff[C_FIELD_ID] + 4];
18166edf50cSStefano Zampini   const PetscScalar  C22      = split ? a[aOff[C_FIELD_ID] + 5] : u[uOff[C_FIELD_ID] + 5];
18266edf50cSStefano Zampini   const PetscScalar  norm     = NORM2C_3d(C00, C01, C02, C11, C12, C22) + eps;
18366edf50cSStefano Zampini   const PetscScalar  nexp     = (gamma - 2.0) / 2.0;
18466edf50cSStefano Zampini   const PetscScalar  fnorm    = PetscPowScalar(norm, nexp);
18566edf50cSStefano Zampini   const PetscScalar  eqss[]   = {0.5, 1., 1., 0.5, 1., 0.5};
18666edf50cSStefano Zampini 
18766edf50cSStefano Zampini   for (PetscInt k = 0; k < 6; k++) f0[k] = eqss[k] * (u_t[uOff[C_FIELD_ID] + k] - outerp[k] + alpha * fnorm * u[uOff[C_FIELD_ID] + k]);
188811d88abSStefano Zampini }
189811d88abSStefano Zampini 
190811d88abSStefano Zampini /* Jacobian for C against C basis functions */
JC_0_c0c0(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])191811d88abSStefano Zampini static void JC_0_c0c0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
192811d88abSStefano Zampini {
193811d88abSStefano Zampini   const PetscReal   alpha  = PetscRealPart(constants[ALPHA_ID]);
194811d88abSStefano Zampini   const PetscReal   gamma  = PetscRealPart(constants[GAMMA_ID]);
195811d88abSStefano Zampini   const PetscReal   eps    = PetscRealPart(constants[EPS_ID]);
19666edf50cSStefano Zampini   const PetscBool   split  = (PetscBool)(PetscRealPart(constants[SPLIT_ID]) != 0.0);
19766edf50cSStefano Zampini   const PetscScalar C00    = split ? a[aOff[C_FIELD_ID]] : u[uOff[C_FIELD_ID]];
19866edf50cSStefano Zampini   const PetscScalar C01    = split ? a[aOff[C_FIELD_ID] + 1] : u[uOff[C_FIELD_ID] + 1];
19966edf50cSStefano Zampini   const PetscScalar C11    = split ? a[aOff[C_FIELD_ID] + 2] : u[uOff[C_FIELD_ID] + 2];
200811d88abSStefano Zampini   const PetscScalar norm   = NORM2C(C00, C01, C11) + eps;
201811d88abSStefano Zampini   const PetscScalar nexp   = (gamma - 2.0) / 2.0;
202811d88abSStefano Zampini   const PetscScalar fnorm  = PetscPowScalar(norm, nexp);
203811d88abSStefano Zampini   const PetscScalar dfnorm = nexp * PetscPowScalar(norm, nexp - 1.0);
204811d88abSStefano Zampini   const PetscScalar dC[]   = {2 * C00, 4 * C01, 2 * C11};
20566edf50cSStefano Zampini   const PetscScalar eqss[] = {0.5, 1., 0.5};
206811d88abSStefano Zampini 
207811d88abSStefano Zampini   for (PetscInt k = 0; k < 3; k++) {
20866edf50cSStefano Zampini     if (!split) {
20966edf50cSStefano Zampini       for (PetscInt j = 0; j < 3; j++) J[k * 3 + j] = eqss[k] * (alpha * dfnorm * dC[j] * u[uOff[C_FIELD_ID] + k]);
21066edf50cSStefano Zampini     }
21166edf50cSStefano Zampini     J[k * 3 + k] += eqss[k] * (alpha * fnorm + u_tShift);
21266edf50cSStefano Zampini   }
21366edf50cSStefano Zampini }
21466edf50cSStefano Zampini 
JC_0_c0c0_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])21566edf50cSStefano Zampini static void JC_0_c0c0_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
21666edf50cSStefano Zampini {
21766edf50cSStefano Zampini   const PetscReal   alpha  = PetscRealPart(constants[ALPHA_ID]);
21866edf50cSStefano Zampini   const PetscReal   gamma  = PetscRealPart(constants[GAMMA_ID]);
21966edf50cSStefano Zampini   const PetscReal   eps    = PetscRealPart(constants[EPS_ID]);
22066edf50cSStefano Zampini   const PetscBool   split  = (PetscBool)(PetscRealPart(constants[SPLIT_ID]) != 0.0);
22166edf50cSStefano Zampini   const PetscScalar C00    = split ? a[aOff[C_FIELD_ID]] : u[uOff[C_FIELD_ID]];
22266edf50cSStefano Zampini   const PetscScalar C01    = split ? a[aOff[C_FIELD_ID] + 1] : u[uOff[C_FIELD_ID] + 1];
22366edf50cSStefano Zampini   const PetscScalar C02    = split ? a[aOff[C_FIELD_ID] + 2] : u[uOff[C_FIELD_ID] + 2];
22466edf50cSStefano Zampini   const PetscScalar C11    = split ? a[aOff[C_FIELD_ID] + 3] : u[uOff[C_FIELD_ID] + 3];
22566edf50cSStefano Zampini   const PetscScalar C12    = split ? a[aOff[C_FIELD_ID] + 4] : u[uOff[C_FIELD_ID] + 4];
22666edf50cSStefano Zampini   const PetscScalar C22    = split ? a[aOff[C_FIELD_ID] + 5] : u[uOff[C_FIELD_ID] + 5];
22766edf50cSStefano Zampini   const PetscScalar norm   = NORM2C_3d(C00, C01, C02, C11, C12, C22) + eps;
22866edf50cSStefano Zampini   const PetscScalar nexp   = (gamma - 2.0) / 2.0;
22966edf50cSStefano Zampini   const PetscScalar fnorm  = PetscPowScalar(norm, nexp);
23066edf50cSStefano Zampini   const PetscScalar dfnorm = nexp * PetscPowScalar(norm, nexp - 1.0);
23166edf50cSStefano Zampini   const PetscScalar dC[]   = {2 * C00, 4 * C01, 4 * C02, 2 * C11, 4 * C12, 2 * C22};
23266edf50cSStefano Zampini   const PetscScalar eqss[] = {0.5, 1., 1., 0.5, 1., 0.5};
23366edf50cSStefano Zampini 
23466edf50cSStefano Zampini   for (PetscInt k = 0; k < 6; k++) {
23566edf50cSStefano Zampini     if (!split) {
23666edf50cSStefano Zampini       for (PetscInt j = 0; j < 6; j++) J[k * 6 + j] = eqss[k] * (alpha * dfnorm * dC[j] * u[uOff[C_FIELD_ID] + k]);
23766edf50cSStefano Zampini     }
23866edf50cSStefano Zampini     J[k * 6 + k] += eqss[k] * (alpha * fnorm + u_tShift);
239811d88abSStefano Zampini   }
240811d88abSStefano Zampini }
241811d88abSStefano Zampini 
242811d88abSStefano Zampini /* Jacobian for C against C basis functions and gradients of P basis functions */
JC_0_c0p1(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])243811d88abSStefano Zampini static void JC_0_c0p1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
244811d88abSStefano Zampini {
24566edf50cSStefano Zampini   const PetscScalar *gradp  = u_x + uOff_x[P_FIELD_ID];
24666edf50cSStefano Zampini   const PetscScalar  eqss[] = {0.5, 1., 0.5};
247811d88abSStefano Zampini 
24866edf50cSStefano Zampini   J[0] = -2 * gradp[0] * eqss[0];
249811d88abSStefano Zampini   J[1] = 0.0;
25066edf50cSStefano Zampini 
25166edf50cSStefano Zampini   J[2] = -gradp[1] * eqss[1];
25266edf50cSStefano Zampini   J[3] = -gradp[0] * eqss[1];
25366edf50cSStefano Zampini 
254811d88abSStefano Zampini   J[4] = 0.0;
25566edf50cSStefano Zampini   J[5] = -2 * gradp[1] * eqss[2];
25666edf50cSStefano Zampini }
25766edf50cSStefano Zampini 
JC_0_c0p1_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])25866edf50cSStefano Zampini static void JC_0_c0p1_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
25966edf50cSStefano Zampini {
26066edf50cSStefano Zampini   const PetscScalar *gradp  = u_x + uOff_x[P_FIELD_ID];
26166edf50cSStefano Zampini   const PetscScalar  eqss[] = {0.5, 1., 1., 0.5, 1., 0.5};
26266edf50cSStefano Zampini 
26366edf50cSStefano Zampini   J[0] = -2 * gradp[0] * eqss[0];
26466edf50cSStefano Zampini   J[1] = 0.0;
26566edf50cSStefano Zampini   J[2] = 0.0;
26666edf50cSStefano Zampini 
26766edf50cSStefano Zampini   J[3] = -gradp[1] * eqss[1];
26866edf50cSStefano Zampini   J[4] = -gradp[0] * eqss[1];
26966edf50cSStefano Zampini   J[5] = 0.0;
27066edf50cSStefano Zampini 
27166edf50cSStefano Zampini   J[6] = -gradp[2] * eqss[2];
27266edf50cSStefano Zampini   J[7] = 0.0;
27366edf50cSStefano Zampini   J[8] = -gradp[0] * eqss[2];
27466edf50cSStefano Zampini 
27566edf50cSStefano Zampini   J[9]  = 0.0;
27666edf50cSStefano Zampini   J[10] = -2 * gradp[1] * eqss[3];
27766edf50cSStefano Zampini   J[11] = 0.0;
27866edf50cSStefano Zampini 
27966edf50cSStefano Zampini   J[12] = 0.0;
28066edf50cSStefano Zampini   J[13] = -gradp[2] * eqss[4];
28166edf50cSStefano Zampini   J[14] = -gradp[1] * eqss[4];
28266edf50cSStefano Zampini 
28366edf50cSStefano Zampini   J[15] = 0.0;
28466edf50cSStefano Zampini   J[16] = 0.0;
28566edf50cSStefano Zampini   J[17] = -2 * gradp[2] * eqss[5];
286811d88abSStefano Zampini }
287811d88abSStefano Zampini 
288811d88abSStefano Zampini /* residual for C when tested against gradients of basis functions */
C_1(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])289811d88abSStefano Zampini static void C_1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
290811d88abSStefano Zampini {
291811d88abSStefano Zampini   const PetscReal D = PetscRealPart(constants[D_ID]);
292811d88abSStefano Zampini   for (PetscInt k = 0; k < 3; k++)
293811d88abSStefano Zampini     for (PetscInt d = 0; d < 2; d++) f1[k * 2 + d] = PetscSqr(D) * u_x[uOff_x[C_FIELD_ID] + k * 2 + d];
294811d88abSStefano Zampini }
295811d88abSStefano Zampini 
C_1_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])29666edf50cSStefano Zampini static void C_1_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
29766edf50cSStefano Zampini {
29866edf50cSStefano Zampini   const PetscReal D = PetscRealPart(constants[D_ID]);
29966edf50cSStefano Zampini   for (PetscInt k = 0; k < 6; k++)
30066edf50cSStefano Zampini     for (PetscInt d = 0; d < 3; d++) f1[k * 3 + d] = PetscSqr(D) * u_x[uOff_x[C_FIELD_ID] + k * 3 + d];
30166edf50cSStefano Zampini }
30266edf50cSStefano Zampini 
303811d88abSStefano Zampini /* Jacobian for C against gradients of C basis functions */
JC_1_c1c1(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])304811d88abSStefano Zampini static void JC_1_c1c1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
305811d88abSStefano Zampini {
306811d88abSStefano Zampini   const PetscReal D = PetscRealPart(constants[D_ID]);
307811d88abSStefano Zampini   for (PetscInt k = 0; k < 3; k++)
308811d88abSStefano Zampini     for (PetscInt d = 0; d < 2; d++) J[k * (3 + 1) * 2 * 2 + d * 2 + d] = PetscSqr(D);
309811d88abSStefano Zampini }
310811d88abSStefano Zampini 
JC_1_c1c1_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])31166edf50cSStefano Zampini static void JC_1_c1c1_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
312811d88abSStefano Zampini {
31366edf50cSStefano Zampini   const PetscReal D = PetscRealPart(constants[D_ID]);
31466edf50cSStefano Zampini   for (PetscInt k = 0; k < 6; k++)
31566edf50cSStefano Zampini     for (PetscInt d = 0; d < 3; d++) J[k * (6 + 1) * 3 * 3 + d * 3 + d] = PetscSqr(D);
316811d88abSStefano Zampini }
317811d88abSStefano Zampini 
31866edf50cSStefano Zampini /* residual for P when tested against basis functions.
31966edf50cSStefano Zampini    The source term always comes from the auxiliary data because it must be zero mean (algebraically) */
P_0(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])32066edf50cSStefano Zampini static void P_0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
321204aa523SStefano Zampini {
32266edf50cSStefano Zampini   PetscScalar S = a[aOff[NUM_FIELDS]];
323204aa523SStefano Zampini 
32466edf50cSStefano Zampini   f0[0] = S;
32566edf50cSStefano Zampini }
32666edf50cSStefano Zampini 
32766edf50cSStefano Zampini /* residual for P when tested against basis functions for the initial condition problem
32866edf50cSStefano Zampini    here we don't impose symmetry, and we thus flip the sign of the source function */
P_0_aux(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])32966edf50cSStefano Zampini static void P_0_aux(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
33066edf50cSStefano Zampini {
33166edf50cSStefano Zampini   PetscScalar S = a[aOff[NUM_FIELDS]];
33266edf50cSStefano Zampini 
33366edf50cSStefano Zampini   f0[0] = -S;
334204aa523SStefano Zampini }
335204aa523SStefano Zampini 
336811d88abSStefano Zampini /* residual for P when tested against gradients of basis functions */
P_1(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])337811d88abSStefano Zampini static void P_1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
338811d88abSStefano Zampini {
339811d88abSStefano Zampini   const PetscReal    r     = PetscRealPart(constants[R_ID]);
340204aa523SStefano Zampini   const PetscScalar  C00   = u[uOff[C_FIELD_ID]] + r;
341811d88abSStefano Zampini   const PetscScalar  C01   = u[uOff[C_FIELD_ID] + 1];
342811d88abSStefano Zampini   const PetscScalar  C10   = C01;
343204aa523SStefano Zampini   const PetscScalar  C11   = u[uOff[C_FIELD_ID] + 2] + r;
34466edf50cSStefano Zampini   const PetscScalar *gradp = u_x + uOff_x[P_FIELD_ID];
345204aa523SStefano Zampini   const PetscBool    fix_c = (PetscBool)(PetscRealPart(constants[FIXC_ID]) > 1.0);
346204aa523SStefano Zampini   const PetscScalar  s     = fix_c ? FIX_C(C00, C01, C11) : 0.0;
347811d88abSStefano Zampini 
34866edf50cSStefano Zampini   f1[0] = -((C00 + s) * gradp[0] + C01 * gradp[1]);
34966edf50cSStefano Zampini   f1[1] = -(C10 * gradp[0] + (C11 + s) * gradp[1]);
350811d88abSStefano Zampini }
351811d88abSStefano Zampini 
P_1_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])35266edf50cSStefano Zampini static void P_1_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
35366edf50cSStefano Zampini {
35466edf50cSStefano Zampini   const PetscReal    r     = PetscRealPart(constants[R_ID]);
35566edf50cSStefano Zampini   const PetscScalar  C00   = u[uOff[C_FIELD_ID]] + r;
35666edf50cSStefano Zampini   const PetscScalar  C01   = u[uOff[C_FIELD_ID] + 1];
35766edf50cSStefano Zampini   const PetscScalar  C02   = u[uOff[C_FIELD_ID] + 2];
35866edf50cSStefano Zampini   const PetscScalar  C10   = C01;
35966edf50cSStefano Zampini   const PetscScalar  C11   = u[uOff[C_FIELD_ID] + 3] + r;
36066edf50cSStefano Zampini   const PetscScalar  C12   = u[uOff[C_FIELD_ID] + 4];
36166edf50cSStefano Zampini   const PetscScalar  C20   = C02;
36266edf50cSStefano Zampini   const PetscScalar  C21   = C12;
36366edf50cSStefano Zampini   const PetscScalar  C22   = u[uOff[C_FIELD_ID] + 5] + r;
36466edf50cSStefano Zampini   const PetscScalar *gradp = u_x + uOff_x[P_FIELD_ID];
36566edf50cSStefano Zampini   const PetscBool    fix_c = (PetscBool)(PetscRealPart(constants[FIXC_ID]) > 1.0);
36666edf50cSStefano Zampini   const PetscScalar  s     = fix_c ? FIX_C_3d(C00, C01, C02, C11, C12, C22) : 0.0;
36766edf50cSStefano Zampini 
36866edf50cSStefano Zampini   f1[0] = -((C00 + s) * gradp[0] + C01 * gradp[1] + C02 * gradp[2]);
36966edf50cSStefano Zampini   f1[1] = -(C10 * gradp[0] + (C11 + s) * gradp[1] + C12 * gradp[2]);
37066edf50cSStefano Zampini   f1[2] = -(C20 * gradp[0] + C21 * gradp[1] + (C22 + s) * gradp[2]);
37166edf50cSStefano Zampini }
37266edf50cSStefano Zampini 
37366edf50cSStefano Zampini /* Same as above except that the conductivity values come from the auxiliary vec */
P_1_aux(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])374811d88abSStefano Zampini static void P_1_aux(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
375811d88abSStefano Zampini {
376811d88abSStefano Zampini   const PetscReal    r     = PetscRealPart(constants[R_ID]);
377204aa523SStefano Zampini   const PetscScalar  C00   = a[aOff[C_FIELD_ID]] + r;
378811d88abSStefano Zampini   const PetscScalar  C01   = a[aOff[C_FIELD_ID] + 1];
379811d88abSStefano Zampini   const PetscScalar  C10   = C01;
380204aa523SStefano Zampini   const PetscScalar  C11   = a[aOff[C_FIELD_ID] + 2] + r;
38166edf50cSStefano Zampini   const PetscScalar *gradp = u_x + uOff_x[Nf > 1 ? P_FIELD_ID : 0];
382204aa523SStefano Zampini   const PetscBool    fix_c = (PetscBool)(PetscRealPart(constants[FIXC_ID]) > 1.0);
383204aa523SStefano Zampini   const PetscScalar  s     = fix_c ? FIX_C(C00, C01, C11) : 0.0;
384811d88abSStefano Zampini 
385204aa523SStefano Zampini   f1[0] = (C00 + s) * gradp[0] + C01 * gradp[1];
386204aa523SStefano Zampini   f1[1] = C10 * gradp[0] + (C11 + s) * gradp[1];
387811d88abSStefano Zampini }
388811d88abSStefano Zampini 
P_1_aux_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f1[])38966edf50cSStefano Zampini static void P_1_aux_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
39066edf50cSStefano Zampini {
39166edf50cSStefano Zampini   const PetscReal    r     = PetscRealPart(constants[R_ID]);
39266edf50cSStefano Zampini   const PetscScalar  C00   = a[aOff[C_FIELD_ID]] + r;
39366edf50cSStefano Zampini   const PetscScalar  C01   = a[aOff[C_FIELD_ID] + 1];
39466edf50cSStefano Zampini   const PetscScalar  C02   = a[aOff[C_FIELD_ID] + 2];
39566edf50cSStefano Zampini   const PetscScalar  C10   = C01;
39666edf50cSStefano Zampini   const PetscScalar  C11   = a[aOff[C_FIELD_ID] + 3] + r;
39766edf50cSStefano Zampini   const PetscScalar  C12   = a[aOff[C_FIELD_ID] + 4];
39866edf50cSStefano Zampini   const PetscScalar  C20   = C02;
39966edf50cSStefano Zampini   const PetscScalar  C21   = C12;
40066edf50cSStefano Zampini   const PetscScalar  C22   = a[aOff[C_FIELD_ID] + 5] + r;
40166edf50cSStefano Zampini   const PetscScalar *gradp = u_x + uOff_x[Nf > 1 ? P_FIELD_ID : 0];
40266edf50cSStefano Zampini   const PetscBool    fix_c = (PetscBool)(PetscRealPart(constants[FIXC_ID]) > 1.0);
40366edf50cSStefano Zampini   const PetscScalar  s     = fix_c ? FIX_C_3d(C00, C01, C02, C11, C12, C22) : 0.0;
40466edf50cSStefano Zampini 
40566edf50cSStefano Zampini   f1[0] = (C00 + s) * gradp[0] + C01 * gradp[1] + C02 * gradp[2];
40666edf50cSStefano Zampini   f1[1] = C10 * gradp[0] + (C11 + s) * gradp[1] + C12 * gradp[2];
40766edf50cSStefano Zampini   f1[2] = C20 * gradp[0] + C21 * gradp[1] + (C22 + s) * gradp[2];
40866edf50cSStefano Zampini }
40966edf50cSStefano Zampini 
410811d88abSStefano Zampini /* Jacobian for P against gradients of P basis functions */
JP_1_p1p1(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])411811d88abSStefano Zampini static void JP_1_p1p1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
412811d88abSStefano Zampini {
413811d88abSStefano Zampini   const PetscReal   r     = PetscRealPart(constants[R_ID]);
414204aa523SStefano Zampini   const PetscScalar C00   = u[uOff[C_FIELD_ID]] + r;
415811d88abSStefano Zampini   const PetscScalar C01   = u[uOff[C_FIELD_ID] + 1];
416811d88abSStefano Zampini   const PetscScalar C10   = C01;
417204aa523SStefano Zampini   const PetscScalar C11   = u[uOff[C_FIELD_ID] + 2] + r;
418204aa523SStefano Zampini   const PetscBool   fix_c = (PetscBool)(PetscRealPart(constants[FIXC_ID]) > 0.0);
419204aa523SStefano Zampini   const PetscScalar s     = fix_c ? FIX_C(C00, C01, C11) : 0.0;
420811d88abSStefano Zampini 
42166edf50cSStefano Zampini   J[0] = -(C00 + s);
42266edf50cSStefano Zampini   J[1] = -C01;
42366edf50cSStefano Zampini   J[2] = -C10;
42466edf50cSStefano Zampini   J[3] = -(C11 + s);
425811d88abSStefano Zampini }
426811d88abSStefano Zampini 
JP_1_p1p1_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])42766edf50cSStefano Zampini static void JP_1_p1p1_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
42866edf50cSStefano Zampini {
42966edf50cSStefano Zampini   const PetscReal   r     = PetscRealPart(constants[R_ID]);
43066edf50cSStefano Zampini   const PetscScalar C00   = u[uOff[C_FIELD_ID]] + r;
43166edf50cSStefano Zampini   const PetscScalar C01   = u[uOff[C_FIELD_ID] + 1];
43266edf50cSStefano Zampini   const PetscScalar C02   = u[uOff[C_FIELD_ID] + 2];
43366edf50cSStefano Zampini   const PetscScalar C10   = C01;
43466edf50cSStefano Zampini   const PetscScalar C11   = u[uOff[C_FIELD_ID] + 3] + r;
43566edf50cSStefano Zampini   const PetscScalar C12   = u[uOff[C_FIELD_ID] + 4];
43666edf50cSStefano Zampini   const PetscScalar C20   = C02;
43766edf50cSStefano Zampini   const PetscScalar C21   = C12;
43866edf50cSStefano Zampini   const PetscScalar C22   = u[uOff[C_FIELD_ID] + 5] + r;
43966edf50cSStefano Zampini   const PetscBool   fix_c = (PetscBool)(PetscRealPart(constants[FIXC_ID]) > 0.0);
44066edf50cSStefano Zampini   const PetscScalar s     = fix_c ? FIX_C_3d(C00, C01, C02, C11, C12, C22) : 0.0;
44166edf50cSStefano Zampini 
44266edf50cSStefano Zampini   J[0] = -(C00 + s);
44366edf50cSStefano Zampini   J[1] = -C01;
44466edf50cSStefano Zampini   J[2] = -C02;
44566edf50cSStefano Zampini   J[3] = -C10;
44666edf50cSStefano Zampini   J[4] = -(C11 + s);
44766edf50cSStefano Zampini   J[5] = -C12;
44866edf50cSStefano Zampini   J[6] = -C20;
44966edf50cSStefano Zampini   J[7] = -C21;
45066edf50cSStefano Zampini   J[8] = -(C22 + s);
45166edf50cSStefano Zampini }
45266edf50cSStefano Zampini 
JP_1_p1p1_aux(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])453811d88abSStefano Zampini static void JP_1_p1p1_aux(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
454811d88abSStefano Zampini {
455811d88abSStefano Zampini   const PetscReal   r     = PetscRealPart(constants[R_ID]);
456204aa523SStefano Zampini   const PetscScalar C00   = a[aOff[C_FIELD_ID]] + r;
457811d88abSStefano Zampini   const PetscScalar C01   = a[aOff[C_FIELD_ID] + 1];
458811d88abSStefano Zampini   const PetscScalar C10   = C01;
459204aa523SStefano Zampini   const PetscScalar C11   = a[aOff[C_FIELD_ID] + 2] + r;
460204aa523SStefano Zampini   const PetscBool   fix_c = (PetscBool)(PetscRealPart(constants[FIXC_ID]) > 0.0);
461204aa523SStefano Zampini   const PetscScalar s     = fix_c ? FIX_C(C00, C01, C11) : 0.0;
462811d88abSStefano Zampini 
463204aa523SStefano Zampini   J[0] = C00 + s;
464811d88abSStefano Zampini   J[1] = C01;
465811d88abSStefano Zampini   J[2] = C10;
466204aa523SStefano Zampini   J[3] = C11 + s;
467811d88abSStefano Zampini }
468811d88abSStefano Zampini 
JP_1_p1p1_aux_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])46966edf50cSStefano Zampini static void JP_1_p1p1_aux_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
47066edf50cSStefano Zampini {
47166edf50cSStefano Zampini   const PetscReal   r     = PetscRealPart(constants[R_ID]);
47266edf50cSStefano Zampini   const PetscScalar C00   = a[aOff[C_FIELD_ID]] + r;
47366edf50cSStefano Zampini   const PetscScalar C01   = a[aOff[C_FIELD_ID] + 1];
47466edf50cSStefano Zampini   const PetscScalar C02   = a[aOff[C_FIELD_ID] + 2];
47566edf50cSStefano Zampini   const PetscScalar C10   = C01;
47666edf50cSStefano Zampini   const PetscScalar C11   = a[aOff[C_FIELD_ID] + 3] + r;
47766edf50cSStefano Zampini   const PetscScalar C12   = a[aOff[C_FIELD_ID] + 4];
47866edf50cSStefano Zampini   const PetscScalar C20   = C02;
47966edf50cSStefano Zampini   const PetscScalar C21   = C12;
48066edf50cSStefano Zampini   const PetscScalar C22   = a[aOff[C_FIELD_ID] + 5] + r;
48166edf50cSStefano Zampini   const PetscBool   fix_c = (PetscBool)(PetscRealPart(constants[FIXC_ID]) > 0.0);
48266edf50cSStefano Zampini   const PetscScalar s     = fix_c ? FIX_C_3d(C00, C01, C02, C11, C12, C22) : 0.0;
48366edf50cSStefano Zampini 
48466edf50cSStefano Zampini   J[0] = C00 + s;
48566edf50cSStefano Zampini   J[1] = C01;
48666edf50cSStefano Zampini   J[2] = C02;
48766edf50cSStefano Zampini   J[3] = C10;
48866edf50cSStefano Zampini   J[4] = C11 + s;
48966edf50cSStefano Zampini   J[5] = C12;
49066edf50cSStefano Zampini   J[6] = C20;
49166edf50cSStefano Zampini   J[7] = C21;
49266edf50cSStefano Zampini   J[8] = C22 + s;
49366edf50cSStefano Zampini }
49466edf50cSStefano Zampini 
495811d88abSStefano Zampini /* Jacobian for P against gradients of P basis functions and C basis functions */
JP_1_p1c0(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])496811d88abSStefano Zampini static void JP_1_p1c0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
497811d88abSStefano Zampini {
49866edf50cSStefano Zampini   const PetscScalar *gradp = u_x + uOff_x[P_FIELD_ID];
499811d88abSStefano Zampini 
50066edf50cSStefano Zampini   J[0] = -gradp[0];
501811d88abSStefano Zampini   J[1] = 0;
50266edf50cSStefano Zampini 
50366edf50cSStefano Zampini   J[2] = -gradp[1];
50466edf50cSStefano Zampini   J[3] = -gradp[0];
50566edf50cSStefano Zampini 
506811d88abSStefano Zampini   J[4] = 0;
50766edf50cSStefano Zampini   J[5] = -gradp[1];
508811d88abSStefano Zampini }
509811d88abSStefano Zampini 
JP_1_p1c0_3d(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,PetscReal u_tShift,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar J[])51066edf50cSStefano Zampini static void JP_1_p1c0_3d(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
511811d88abSStefano Zampini {
51266edf50cSStefano Zampini   const PetscScalar *gradp = u_x + uOff_x[P_FIELD_ID];
51366edf50cSStefano Zampini 
51466edf50cSStefano Zampini   J[0] = -gradp[0];
51566edf50cSStefano Zampini   J[1] = 0;
51666edf50cSStefano Zampini   J[2] = 0;
51766edf50cSStefano Zampini 
51866edf50cSStefano Zampini   J[3] = -gradp[1];
51966edf50cSStefano Zampini   J[4] = -gradp[0];
52066edf50cSStefano Zampini   J[5] = 0;
52166edf50cSStefano Zampini 
52266edf50cSStefano Zampini   J[6] = -gradp[2];
52366edf50cSStefano Zampini   J[7] = 0;
52466edf50cSStefano Zampini   J[8] = -gradp[0];
52566edf50cSStefano Zampini 
52666edf50cSStefano Zampini   J[9]  = 0;
52766edf50cSStefano Zampini   J[10] = -gradp[1];
52866edf50cSStefano Zampini   J[11] = 0;
52966edf50cSStefano Zampini 
53066edf50cSStefano Zampini   J[12] = 0;
53166edf50cSStefano Zampini   J[13] = -gradp[2];
53266edf50cSStefano Zampini   J[14] = -gradp[1];
53366edf50cSStefano Zampini 
53466edf50cSStefano Zampini   J[15] = 0;
53566edf50cSStefano Zampini   J[16] = 0;
53666edf50cSStefano Zampini   J[17] = -gradp[2];
53766edf50cSStefano Zampini }
53866edf50cSStefano Zampini 
53966edf50cSStefano Zampini /* a collection of gaussian, Dirac-like, source term S(x) = scale * cos(2*pi*(frequency*t + phase)) * exp(-w*||x - x0||^2) */
54066edf50cSStefano Zampini typedef struct {
54166edf50cSStefano Zampini   PetscInt   n;
54266edf50cSStefano Zampini   PetscReal *x0;
54366edf50cSStefano Zampini   PetscReal *w;
54466edf50cSStefano Zampini   PetscReal *k;
54566edf50cSStefano Zampini   PetscReal *p;
54666edf50cSStefano Zampini   PetscReal *r;
54766edf50cSStefano Zampini } MultiSourceCtx;
54866edf50cSStefano Zampini 
54966edf50cSStefano Zampini typedef struct {
55066edf50cSStefano Zampini   PetscReal x0[3];
55166edf50cSStefano Zampini   PetscReal w;
55266edf50cSStefano Zampini   PetscReal k;
55366edf50cSStefano Zampini   PetscReal p;
55466edf50cSStefano Zampini   PetscReal r;
55566edf50cSStefano Zampini } SingleSourceCtx;
55666edf50cSStefano Zampini 
gaussian(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar * u,PetscCtx ctx)557*2a8381b2SBarry Smith static PetscErrorCode gaussian(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, PetscCtx ctx)
55866edf50cSStefano Zampini {
55966edf50cSStefano Zampini   SingleSourceCtx *s  = (SingleSourceCtx *)ctx;
56066edf50cSStefano Zampini   const PetscReal *x0 = s->x0;
56166edf50cSStefano Zampini   const PetscReal  w  = s->w;
56266edf50cSStefano Zampini   const PetscReal  k  = s->k; /* frequency */
56366edf50cSStefano Zampini   const PetscReal  p  = s->p; /* phase */
56466edf50cSStefano Zampini   const PetscReal  r  = s->r; /* scale */
565811d88abSStefano Zampini   PetscReal        n  = 0;
566811d88abSStefano Zampini 
567811d88abSStefano Zampini   for (PetscInt d = 0; d < dim; ++d) n += (x[d] - x0[d]) * (x[d] - x0[d]);
56866edf50cSStefano Zampini   u[0] = r * PetscCosReal(2 * PETSC_PI * (k * time + p)) * PetscExpReal(-w * n);
569811d88abSStefano Zampini   return PETSC_SUCCESS;
570811d88abSStefano Zampini }
571811d88abSStefano Zampini 
source(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar * u,PetscCtx ctx)572*2a8381b2SBarry Smith static PetscErrorCode source(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, PetscCtx ctx)
573811d88abSStefano Zampini {
57466edf50cSStefano Zampini   MultiSourceCtx *s = (MultiSourceCtx *)ctx;
575811d88abSStefano Zampini 
57666edf50cSStefano Zampini   u[0] = 0.0;
57766edf50cSStefano Zampini   for (PetscInt i = 0; i < s->n; i++) {
57866edf50cSStefano Zampini     SingleSourceCtx sctx;
57966edf50cSStefano Zampini     PetscScalar     ut[1];
58066edf50cSStefano Zampini 
58166edf50cSStefano Zampini     sctx.x0[0] = s->x0[dim * i];
58266edf50cSStefano Zampini     sctx.x0[1] = s->x0[dim * i + 1];
58366edf50cSStefano Zampini     sctx.x0[2] = dim > 2 ? s->x0[dim * i + 2] : 0.0;
58466edf50cSStefano Zampini     sctx.w     = s->w[i];
58566edf50cSStefano Zampini     sctx.k     = s->k[i];
58666edf50cSStefano Zampini     sctx.p     = s->p[i];
58766edf50cSStefano Zampini     sctx.r     = s->r[i];
58866edf50cSStefano Zampini 
58966edf50cSStefano Zampini     PetscCall(gaussian(dim, time, x, Nf, ut, &sctx));
59066edf50cSStefano Zampini 
591811d88abSStefano Zampini     u[0] += ut[0];
59266edf50cSStefano Zampini   }
593811d88abSStefano Zampini   return PETSC_SUCCESS;
594811d88abSStefano Zampini }
595811d88abSStefano Zampini 
596811d88abSStefano Zampini /* functionals to be integrated: average -> \int_\Omega u dx */
average(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar obj[])597811d88abSStefano Zampini static void average(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[])
598811d88abSStefano Zampini {
59966edf50cSStefano Zampini   const PetscInt fid = (PetscInt)PetscRealPart(constants[numConstants]);
60066edf50cSStefano Zampini   obj[0]             = u[uOff[fid]];
601811d88abSStefano Zampini }
602811d88abSStefano Zampini 
60366edf50cSStefano Zampini /* functionals to be integrated: volume -> \int_\Omega dx */
volume(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar obj[])60466edf50cSStefano Zampini static void volume(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[])
605811d88abSStefano Zampini {
60666edf50cSStefano Zampini   obj[0] = 1;
607811d88abSStefano Zampini }
608811d88abSStefano Zampini 
609811d88abSStefano Zampini /* functionals to be integrated: energy -> D^2/2 * ||\nabla C||^2 + c^2\nabla p * (r + C) * \nabla p + \alpha/ \gamma * ||C||^\gamma */
energy(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar obj[])610811d88abSStefano Zampini static void energy(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[])
611811d88abSStefano Zampini {
612811d88abSStefano Zampini   const PetscReal D     = PetscRealPart(constants[D_ID]);
613811d88abSStefano Zampini   const PetscReal r     = PetscRealPart(constants[R_ID]);
614811d88abSStefano Zampini   const PetscReal alpha = PetscRealPart(constants[ALPHA_ID]);
615811d88abSStefano Zampini   const PetscReal gamma = PetscRealPart(constants[GAMMA_ID]);
61666edf50cSStefano Zampini   const PetscReal eps   = PetscRealPart(constants[EPS_ID]);
61766edf50cSStefano Zampini 
61866edf50cSStefano Zampini   if (dim == 2) {
619811d88abSStefano Zampini     const PetscScalar  C00       = u[uOff[C_FIELD_ID]];
620811d88abSStefano Zampini     const PetscScalar  C01       = u[uOff[C_FIELD_ID] + 1];
621811d88abSStefano Zampini     const PetscScalar  C10       = C01;
622811d88abSStefano Zampini     const PetscScalar  C11       = u[uOff[C_FIELD_ID] + 2];
62366edf50cSStefano Zampini     const PetscScalar *gradp     = u_x + uOff_x[P_FIELD_ID];
62466edf50cSStefano Zampini     const PetscScalar *gradC00   = u_x + uOff_x[C_FIELD_ID];
62566edf50cSStefano Zampini     const PetscScalar *gradC01   = u_x + uOff_x[C_FIELD_ID] + 2;
62666edf50cSStefano Zampini     const PetscScalar *gradC11   = u_x + uOff_x[C_FIELD_ID] + 4;
62766edf50cSStefano Zampini     const PetscScalar  normC     = NORM2C(C00, C01, C11) + eps;
628811d88abSStefano Zampini     const PetscScalar  normgradC = NORM2C(gradC00[0], gradC01[0], gradC11[0]) + NORM2C(gradC00[1], gradC01[1], gradC11[1]);
629811d88abSStefano Zampini     const PetscScalar  nexp      = gamma / 2.0;
630811d88abSStefano Zampini 
631811d88abSStefano Zampini     const PetscScalar t0 = PetscSqr(D) / 2.0 * normgradC;
63266edf50cSStefano Zampini     const PetscScalar t1 = gradp[0] * ((C00 + r) * gradp[0] + C01 * gradp[1]) + gradp[1] * (C10 * gradp[0] + (C11 + r) * gradp[1]);
63366edf50cSStefano Zampini     const PetscScalar t2 = alpha / gamma * PetscPowScalar(normC, nexp);
63466edf50cSStefano Zampini 
63566edf50cSStefano Zampini     obj[0] = t0 + t1 + t2;
63666edf50cSStefano Zampini   } else {
63766edf50cSStefano Zampini     const PetscScalar  C00     = u[uOff[C_FIELD_ID]];
63866edf50cSStefano Zampini     const PetscScalar  C01     = u[uOff[C_FIELD_ID] + 1];
63966edf50cSStefano Zampini     const PetscScalar  C02     = u[uOff[C_FIELD_ID] + 2];
64066edf50cSStefano Zampini     const PetscScalar  C10     = C01;
64166edf50cSStefano Zampini     const PetscScalar  C11     = u[uOff[C_FIELD_ID] + 3];
64266edf50cSStefano Zampini     const PetscScalar  C12     = u[uOff[C_FIELD_ID] + 4];
64366edf50cSStefano Zampini     const PetscScalar  C20     = C02;
64466edf50cSStefano Zampini     const PetscScalar  C21     = C12;
64566edf50cSStefano Zampini     const PetscScalar  C22     = u[uOff[C_FIELD_ID] + 5];
64666edf50cSStefano Zampini     const PetscScalar *gradp   = u_x + uOff_x[P_FIELD_ID];
64766edf50cSStefano Zampini     const PetscScalar *gradC00 = u_x + uOff_x[C_FIELD_ID];
64866edf50cSStefano Zampini     const PetscScalar *gradC01 = u_x + uOff_x[C_FIELD_ID] + 3;
64966edf50cSStefano Zampini     const PetscScalar *gradC02 = u_x + uOff_x[C_FIELD_ID] + 6;
65066edf50cSStefano Zampini     const PetscScalar *gradC11 = u_x + uOff_x[C_FIELD_ID] + 9;
65166edf50cSStefano Zampini     const PetscScalar *gradC12 = u_x + uOff_x[C_FIELD_ID] + 12;
65266edf50cSStefano Zampini     const PetscScalar *gradC22 = u_x + uOff_x[C_FIELD_ID] + 15;
65366edf50cSStefano Zampini     const PetscScalar  normC   = NORM2C_3d(C00, C01, C02, C11, C12, C22) + eps;
65466edf50cSStefano Zampini     const PetscScalar normgradC = NORM2C_3d(gradC00[0], gradC01[0], gradC02[0], gradC11[0], gradC12[0], gradC22[0]) + NORM2C_3d(gradC00[1], gradC01[1], gradC02[1], gradC11[1], gradC12[1], gradC22[1]) + NORM2C_3d(gradC00[2], gradC01[2], gradC02[2], gradC11[2], gradC12[2], gradC22[2]);
65566edf50cSStefano Zampini     const PetscScalar nexp = gamma / 2.0;
65666edf50cSStefano Zampini 
65766edf50cSStefano Zampini     const PetscScalar t0 = PetscSqr(D) / 2.0 * normgradC;
65866edf50cSStefano Zampini     const PetscScalar t1 = gradp[0] * ((C00 + r) * gradp[0] + C01 * gradp[1] + C02 * gradp[2]) + gradp[1] * (C10 * gradp[0] + (C11 + r) * gradp[1] + C12 * gradp[2]) + gradp[2] * (C20 * gradp[0] + C21 * gradp[1] + (C22 + r) * gradp[2]);
659811d88abSStefano Zampini     const PetscScalar t2 = alpha / gamma * PetscPowScalar(normC, nexp);
660811d88abSStefano Zampini 
661811d88abSStefano Zampini     obj[0] = t0 + t1 + t2;
662811d88abSStefano Zampini   }
66366edf50cSStefano Zampini }
664811d88abSStefano Zampini 
66566edf50cSStefano Zampini /* functionals to be integrated: ellipticity_fail_private -> see below */
ellipticity_fail_private(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar obj[],PetscBool add_reg)66666edf50cSStefano Zampini static void ellipticity_fail_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[], PetscBool add_reg)
66766edf50cSStefano Zampini {
66866edf50cSStefano Zampini #if !PetscDefined(USE_COMPLEX)
66966edf50cSStefano Zampini   PetscReal       eigs[3];
67066edf50cSStefano Zampini   PetscScalar     C00, C01, C02 = 0.0, C11, C12 = 0.0, C22 = 0.0;
67166edf50cSStefano Zampini   const PetscReal r = add_reg ? PetscRealPart(constants[R_ID]) : 0.0;
67266edf50cSStefano Zampini 
67366edf50cSStefano Zampini   if (dim == 2) {
67466edf50cSStefano Zampini     C00 = u[uOff[C_FIELD_ID]] + r;
67566edf50cSStefano Zampini     C01 = u[uOff[C_FIELD_ID] + 1];
67666edf50cSStefano Zampini     C11 = u[uOff[C_FIELD_ID] + 2] + r;
67766edf50cSStefano Zampini   } else {
67866edf50cSStefano Zampini     C00 = u[uOff[C_FIELD_ID]] + r;
67966edf50cSStefano Zampini     C01 = u[uOff[C_FIELD_ID] + 1];
68066edf50cSStefano Zampini     C02 = u[uOff[C_FIELD_ID] + 2];
68166edf50cSStefano Zampini     C11 = u[uOff[C_FIELD_ID] + 3] + r;
68266edf50cSStefano Zampini     C12 = u[uOff[C_FIELD_ID] + 4];
68366edf50cSStefano Zampini     C22 = u[uOff[C_FIELD_ID] + 5] + r;
68466edf50cSStefano Zampini   }
68566edf50cSStefano Zampini   Eigenvalues_Sym3x3(C00, C01, C02, C11, C12, C22, eigs);
68666edf50cSStefano Zampini   if (eigs[0] < 0 || eigs[1] < 0 || eigs[2] < 0) obj[0] = -PetscMin(eigs[0], PetscMin(eigs[1], eigs[2]));
68766edf50cSStefano Zampini   else obj[0] = 0.0;
68866edf50cSStefano Zampini #else
68966edf50cSStefano Zampini   obj[0] = 0.0;
69066edf50cSStefano Zampini #endif
69166edf50cSStefano Zampini }
69266edf50cSStefano Zampini 
69366edf50cSStefano Zampini /* functionals to be integrated: ellipticity_fail -> 0 means C is elliptic at quadrature point, otherwise it returns 1 */
ellipticity_fail(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar obj[])694811d88abSStefano Zampini static void ellipticity_fail(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[])
695811d88abSStefano Zampini {
69666edf50cSStefano Zampini   ellipticity_fail_private(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, t, x, numConstants, constants, obj, PETSC_FALSE);
69766edf50cSStefano Zampini   if (PetscAbsScalar(obj[0]) > 0.0) obj[0] = 1.0;
69866edf50cSStefano Zampini }
699811d88abSStefano Zampini 
70066edf50cSStefano Zampini /* functionals to be integrated: jacobian_fail -> 0 means C + r is elliptic at quadrature point, otherwise it returns the absolute value of the most negative eigenvalue */
jacobian_fail(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar obj[])70166edf50cSStefano Zampini static void jacobian_fail(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[])
70266edf50cSStefano Zampini {
70366edf50cSStefano Zampini   ellipticity_fail_private(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, t, x, numConstants, constants, obj, PETSC_TRUE);
704811d88abSStefano Zampini }
705811d88abSStefano Zampini 
706811d88abSStefano Zampini /* initial conditions for C: eq. 16 */
initial_conditions_C_0(PetscInt dim,PetscReal time,const PetscReal xx[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)707*2a8381b2SBarry Smith static PetscErrorCode initial_conditions_C_0(PetscInt dim, PetscReal time, const PetscReal xx[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
708811d88abSStefano Zampini {
70966edf50cSStefano Zampini   if (dim == 2) {
710811d88abSStefano Zampini     u[0] = 1;
711811d88abSStefano Zampini     u[1] = 0;
712811d88abSStefano Zampini     u[2] = 1;
71366edf50cSStefano Zampini   } else {
71466edf50cSStefano Zampini     u[0] = 1;
71566edf50cSStefano Zampini     u[1] = 0;
71666edf50cSStefano Zampini     u[2] = 0;
71766edf50cSStefano Zampini     u[3] = 1;
71866edf50cSStefano Zampini     u[4] = 0;
71966edf50cSStefano Zampini     u[5] = 1;
72066edf50cSStefano Zampini   }
721811d88abSStefano Zampini   return PETSC_SUCCESS;
722811d88abSStefano Zampini }
723811d88abSStefano Zampini 
724811d88abSStefano Zampini /* initial conditions for C: eq. 17 */
initial_conditions_C_1(PetscInt dim,PetscReal time,const PetscReal xx[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)725*2a8381b2SBarry Smith static PetscErrorCode initial_conditions_C_1(PetscInt dim, PetscReal time, const PetscReal xx[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
726811d88abSStefano Zampini {
727811d88abSStefano Zampini   const PetscReal x = xx[0];
728811d88abSStefano Zampini   const PetscReal y = xx[1];
729811d88abSStefano Zampini 
73066edf50cSStefano Zampini   if (dim == 3) return PETSC_ERR_SUP;
731811d88abSStefano Zampini   u[0] = (2 - PetscAbsReal(x + y)) * PetscExpReal(-10 * PetscAbsReal(x - y));
732811d88abSStefano Zampini   u[1] = 0;
733811d88abSStefano Zampini   u[2] = (2 - PetscAbsReal(x + y)) * PetscExpReal(-10 * PetscAbsReal(x - y));
734811d88abSStefano Zampini   return PETSC_SUCCESS;
735811d88abSStefano Zampini }
736811d88abSStefano Zampini 
737811d88abSStefano Zampini /* initial conditions for C: eq. 18 */
initial_conditions_C_2(PetscInt dim,PetscReal time,const PetscReal xx[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)738*2a8381b2SBarry Smith static PetscErrorCode initial_conditions_C_2(PetscInt dim, PetscReal time, const PetscReal xx[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
739811d88abSStefano Zampini {
740811d88abSStefano Zampini   u[0] = 0;
741811d88abSStefano Zampini   u[1] = 0;
742811d88abSStefano Zampini   u[2] = 0;
74366edf50cSStefano Zampini   if (dim == 3) {
74466edf50cSStefano Zampini     u[3] = 0;
74566edf50cSStefano Zampini     u[4] = 0;
74666edf50cSStefano Zampini     u[5] = 0;
74766edf50cSStefano Zampini   }
748811d88abSStefano Zampini   return PETSC_SUCCESS;
749811d88abSStefano Zampini }
750811d88abSStefano Zampini 
75166edf50cSStefano Zampini /* random initial conditions for the diagonal of C */
initial_conditions_C_random(PetscInt dim,PetscReal time,const PetscReal xx[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)752*2a8381b2SBarry Smith static PetscErrorCode initial_conditions_C_random(PetscInt dim, PetscReal time, const PetscReal xx[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
753811d88abSStefano Zampini {
75466edf50cSStefano Zampini   PetscScalar vals[3];
75566edf50cSStefano Zampini   PetscRandom r = (PetscRandom)ctx;
756811d88abSStefano Zampini 
75766edf50cSStefano Zampini   PetscCall(PetscRandomGetValues(r, dim, vals));
75866edf50cSStefano Zampini   if (dim == 2) {
75966edf50cSStefano Zampini     u[0] = vals[0];
76066edf50cSStefano Zampini     u[1] = 0;
76166edf50cSStefano Zampini     u[2] = vals[1];
76266edf50cSStefano Zampini   } else {
76366edf50cSStefano Zampini     u[0] = vals[0];
76466edf50cSStefano Zampini     u[1] = 0;
76566edf50cSStefano Zampini     u[2] = 0;
76666edf50cSStefano Zampini     u[3] = vals[1];
76766edf50cSStefano Zampini     u[4] = 0;
76866edf50cSStefano Zampini     u[5] = vals[2];
769811d88abSStefano Zampini   }
77066edf50cSStefano Zampini   return PETSC_SUCCESS;
771811d88abSStefano Zampini }
772811d88abSStefano Zampini 
773811d88abSStefano Zampini /* functionals to be sampled: zero */
zero(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[])774811d88abSStefano Zampini static void zero(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
775811d88abSStefano Zampini {
776811d88abSStefano Zampini   f[0] = 0.0;
777811d88abSStefano Zampini }
778811d88abSStefano Zampini 
77966edf50cSStefano Zampini /* functionals to be sampled: - (C + r) * \grad p */
flux(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[])78066edf50cSStefano Zampini static void flux(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
78166edf50cSStefano Zampini {
78266edf50cSStefano Zampini   const PetscReal    r     = PetscRealPart(constants[R_ID]);
78366edf50cSStefano Zampini   const PetscScalar *gradp = u_x + uOff_x[P_FIELD_ID];
78466edf50cSStefano Zampini 
78566edf50cSStefano Zampini   if (dim == 2) {
78666edf50cSStefano Zampini     const PetscScalar C00 = u[uOff[C_FIELD_ID]] + r;
78766edf50cSStefano Zampini     const PetscScalar C01 = u[uOff[C_FIELD_ID] + 1];
78866edf50cSStefano Zampini     const PetscScalar C10 = C01;
78966edf50cSStefano Zampini     const PetscScalar C11 = u[uOff[C_FIELD_ID] + 2] + r;
79066edf50cSStefano Zampini 
79166edf50cSStefano Zampini     f[0] = -C00 * gradp[0] - C01 * gradp[1];
79266edf50cSStefano Zampini     f[1] = -C10 * gradp[0] - C11 * gradp[1];
79366edf50cSStefano Zampini   } else {
79466edf50cSStefano Zampini     const PetscScalar C00 = u[uOff[C_FIELD_ID]] + r;
79566edf50cSStefano Zampini     const PetscScalar C01 = u[uOff[C_FIELD_ID] + 1];
79666edf50cSStefano Zampini     const PetscScalar C02 = u[uOff[C_FIELD_ID] + 2];
79766edf50cSStefano Zampini     const PetscScalar C10 = C01;
79866edf50cSStefano Zampini     const PetscScalar C11 = u[uOff[C_FIELD_ID] + 3] + r;
79966edf50cSStefano Zampini     const PetscScalar C12 = u[uOff[C_FIELD_ID] + 4];
80066edf50cSStefano Zampini     const PetscScalar C20 = C02;
80166edf50cSStefano Zampini     const PetscScalar C21 = C12;
80266edf50cSStefano Zampini     const PetscScalar C22 = u[uOff[C_FIELD_ID] + 5] + r;
80366edf50cSStefano Zampini 
80466edf50cSStefano Zampini     f[0] = -C00 * gradp[0] - C01 * gradp[1] - C02 * gradp[2];
80566edf50cSStefano Zampini     f[1] = -C10 * gradp[0] - C11 * gradp[1] - C12 * gradp[2];
80666edf50cSStefano Zampini     f[2] = -C20 * gradp[0] - C21 * gradp[1] - C22 * gradp[2];
80766edf50cSStefano Zampini   }
80866edf50cSStefano Zampini }
80966edf50cSStefano Zampini 
81066edf50cSStefano Zampini /* functionals to be sampled: ||C|| */
normc(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[])81166edf50cSStefano Zampini static void normc(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
81266edf50cSStefano Zampini {
81366edf50cSStefano Zampini   if (dim == 2) {
81466edf50cSStefano Zampini     const PetscScalar C00 = u[uOff[C_FIELD_ID]];
81566edf50cSStefano Zampini     const PetscScalar C01 = u[uOff[C_FIELD_ID] + 1];
81666edf50cSStefano Zampini     const PetscScalar C11 = u[uOff[C_FIELD_ID] + 2];
81766edf50cSStefano Zampini 
81866edf50cSStefano Zampini     f[0] = PetscSqrtReal(PetscRealPart(NORM2C(C00, C01, C11)));
81966edf50cSStefano Zampini   } else {
82066edf50cSStefano Zampini     const PetscScalar C00 = u[uOff[C_FIELD_ID]];
82166edf50cSStefano Zampini     const PetscScalar C01 = u[uOff[C_FIELD_ID] + 1];
82266edf50cSStefano Zampini     const PetscScalar C02 = u[uOff[C_FIELD_ID] + 2];
82366edf50cSStefano Zampini     const PetscScalar C11 = u[uOff[C_FIELD_ID] + 3];
82466edf50cSStefano Zampini     const PetscScalar C12 = u[uOff[C_FIELD_ID] + 4];
82566edf50cSStefano Zampini     const PetscScalar C22 = u[uOff[C_FIELD_ID] + 5];
82666edf50cSStefano Zampini 
82766edf50cSStefano Zampini     f[0] = PetscSqrtReal(PetscRealPart(NORM2C_3d(C00, C01, C02, C11, C12, C22)));
82866edf50cSStefano Zampini   }
82966edf50cSStefano Zampini }
83066edf50cSStefano Zampini 
83166edf50cSStefano Zampini /* functionals to be sampled: eigenvalues of C */
eigsc(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[])83266edf50cSStefano Zampini static void eigsc(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
83366edf50cSStefano Zampini {
83466edf50cSStefano Zampini #if !PetscDefined(USE_COMPLEX)
83566edf50cSStefano Zampini   PetscReal   eigs[3];
83666edf50cSStefano Zampini   PetscScalar C00, C01, C02 = 0.0, C11, C12 = 0.0, C22 = 0.0;
83766edf50cSStefano Zampini   if (dim == 2) {
83866edf50cSStefano Zampini     C00 = u[uOff[C_FIELD_ID]];
83966edf50cSStefano Zampini     C01 = u[uOff[C_FIELD_ID] + 1];
84066edf50cSStefano Zampini     C11 = u[uOff[C_FIELD_ID] + 2];
84166edf50cSStefano Zampini   } else {
84266edf50cSStefano Zampini     C00 = u[uOff[C_FIELD_ID]];
84366edf50cSStefano Zampini     C01 = u[uOff[C_FIELD_ID] + 1];
84466edf50cSStefano Zampini     C02 = u[uOff[C_FIELD_ID] + 2];
84566edf50cSStefano Zampini     C11 = u[uOff[C_FIELD_ID] + 3];
84666edf50cSStefano Zampini     C12 = u[uOff[C_FIELD_ID] + 4];
84766edf50cSStefano Zampini     C22 = u[uOff[C_FIELD_ID] + 5];
84866edf50cSStefano Zampini   }
84966edf50cSStefano Zampini   Eigenvalues_Sym3x3(C00, C01, C02, C11, C12, C22, eigs);
85066edf50cSStefano Zampini   PetscCallVoid(PetscSortReal(dim, eigs));
85166edf50cSStefano Zampini   for (PetscInt d = 0; d < dim; d++) f[d] = eigs[d];
85266edf50cSStefano Zampini #else
85366edf50cSStefano Zampini   for (PetscInt d = 0; d < dim; d++) f[d] = 0;
85466edf50cSStefano Zampini #endif
85566edf50cSStefano Zampini }
85666edf50cSStefano Zampini 
857811d88abSStefano Zampini /* functions to be sampled: zero function */
zerof(PetscInt dim,PetscReal time,const PetscReal xx[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)858*2a8381b2SBarry Smith static PetscErrorCode zerof(PetscInt dim, PetscReal time, const PetscReal xx[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
859811d88abSStefano Zampini {
860811d88abSStefano Zampini   for (PetscInt d = 0; d < Nc; ++d) u[d] = 0.0;
861811d88abSStefano Zampini   return PETSC_SUCCESS;
862811d88abSStefano Zampini }
863811d88abSStefano Zampini 
864811d88abSStefano Zampini /* functions to be sampled: constant function */
constantf(PetscInt dim,PetscReal time,const PetscReal xx[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)865*2a8381b2SBarry Smith static PetscErrorCode constantf(PetscInt dim, PetscReal time, const PetscReal xx[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
866811d88abSStefano Zampini {
86766edf50cSStefano Zampini   for (PetscInt d = 0; d < Nc; ++d) u[d] = 1.0;
868811d88abSStefano Zampini   return PETSC_SUCCESS;
869811d88abSStefano Zampini }
870811d88abSStefano Zampini 
871811d88abSStefano Zampini /* application context: customizable parameters */
872811d88abSStefano Zampini typedef struct {
87366edf50cSStefano Zampini   PetscInt              dim;
87466edf50cSStefano Zampini   PetscBool             simplex;
875811d88abSStefano Zampini   PetscReal             r;
876811d88abSStefano Zampini   PetscReal             eps;
877811d88abSStefano Zampini   PetscReal             alpha;
878811d88abSStefano Zampini   PetscReal             gamma;
879811d88abSStefano Zampini   PetscReal             D;
88066edf50cSStefano Zampini   PetscReal             domain_volume;
881811d88abSStefano Zampini   PetscInt              ic_num;
88266edf50cSStefano Zampini   PetscBool             split;
883204aa523SStefano Zampini   PetscBool             lump;
884811d88abSStefano Zampini   PetscBool             amr;
885811d88abSStefano Zampini   PetscBool             load;
886811d88abSStefano Zampini   char                  load_filename[PETSC_MAX_PATH_LEN];
887811d88abSStefano Zampini   PetscBool             save;
888811d88abSStefano Zampini   char                  save_filename[PETSC_MAX_PATH_LEN];
889811d88abSStefano Zampini   PetscInt              save_every;
890811d88abSStefano Zampini   PetscBool             test_restart;
891204aa523SStefano Zampini   PetscInt              fix_c;
89266edf50cSStefano Zampini   MultiSourceCtx       *source_ctx;
89366edf50cSStefano Zampini   DM                    view_dm;
89466edf50cSStefano Zampini   TSMonitorVTKCtx       view_vtk_ctx;
89566edf50cSStefano Zampini   PetscViewerAndFormat *view_hdf5_ctx;
89666edf50cSStefano Zampini   PetscInt              diagnostic_num;
89766edf50cSStefano Zampini   PetscReal             view_times[64];
89866edf50cSStefano Zampini   PetscInt              view_times_n, view_times_k;
89966edf50cSStefano Zampini   PetscReal             function_domain_error_tol;
90066edf50cSStefano Zampini   VecScatter            subsct[NUM_FIELDS];
90166edf50cSStefano Zampini   Vec                   subvec[NUM_FIELDS];
90266edf50cSStefano Zampini   PetscBool             monitor_norms;
90366edf50cSStefano Zampini   PetscBool             exclude_potential_lte;
90466edf50cSStefano Zampini 
90566edf50cSStefano Zampini   /* hack: need some more plumbing in the library */
90666edf50cSStefano Zampini   SNES snes;
907811d88abSStefano Zampini } AppCtx;
908811d88abSStefano Zampini 
909811d88abSStefano Zampini /* process command line options */
91066edf50cSStefano Zampini #include <petsc/private/tsimpl.h> /* To access TSMonitorVTKCtx */
ProcessOptions(AppCtx * options)911811d88abSStefano Zampini static PetscErrorCode ProcessOptions(AppCtx *options)
912811d88abSStefano Zampini {
91366edf50cSStefano Zampini   char      vtkmonfilename[PETSC_MAX_PATH_LEN];
91466edf50cSStefano Zampini   char      hdf5monfilename[PETSC_MAX_PATH_LEN];
91566edf50cSStefano Zampini   PetscInt  tmp;
91666edf50cSStefano Zampini   PetscBool flg;
917811d88abSStefano Zampini 
918811d88abSStefano Zampini   PetscFunctionBeginUser;
91966edf50cSStefano Zampini   options->dim                       = 2;
920811d88abSStefano Zampini   options->r                         = 1.e-1;
921811d88abSStefano Zampini   options->eps                       = 1.e-3;
922811d88abSStefano Zampini   options->alpha                     = 0.75;
923811d88abSStefano Zampini   options->gamma                     = 0.75;
924811d88abSStefano Zampini   options->D                         = 1.e-2;
925811d88abSStefano Zampini   options->ic_num                    = 0;
92666edf50cSStefano Zampini   options->split                     = PETSC_FALSE;
927204aa523SStefano Zampini   options->lump                      = PETSC_FALSE;
928811d88abSStefano Zampini   options->amr                       = PETSC_FALSE;
929811d88abSStefano Zampini   options->load                      = PETSC_FALSE;
930811d88abSStefano Zampini   options->save                      = PETSC_FALSE;
931811d88abSStefano Zampini   options->save_every                = -1;
932811d88abSStefano Zampini   options->test_restart              = PETSC_FALSE;
93366edf50cSStefano Zampini   options->fix_c                     = 1; /* 1 means only Jac, 2 means function and Jac, < 0 means raise SNESFunctionDomainError when C+r is not posdef */
93466edf50cSStefano Zampini   options->view_vtk_ctx              = NULL;
93566edf50cSStefano Zampini   options->view_hdf5_ctx             = NULL;
93666edf50cSStefano Zampini   options->view_dm                   = NULL;
93766edf50cSStefano Zampini   options->diagnostic_num            = 1;
93866edf50cSStefano Zampini   options->function_domain_error_tol = -1;
93966edf50cSStefano Zampini   options->monitor_norms             = PETSC_FALSE;
94066edf50cSStefano Zampini   options->exclude_potential_lte     = PETSC_FALSE;
94166edf50cSStefano Zampini   for (PetscInt i = 0; i < NUM_FIELDS; i++) {
94266edf50cSStefano Zampini     options->subsct[i] = NULL;
94366edf50cSStefano Zampini     options->subvec[i] = NULL;
94466edf50cSStefano Zampini   }
94566edf50cSStefano Zampini   for (PetscInt i = 0; i < 64; i++) options->view_times[i] = PETSC_MAX_REAL;
946811d88abSStefano Zampini 
947811d88abSStefano Zampini   PetscOptionsBegin(PETSC_COMM_WORLD, "", __FILE__, "DMPLEX");
94866edf50cSStefano Zampini   PetscCall(PetscOptionsInt("-dim", "space dimension", __FILE__, options->dim, &options->dim, NULL));
949811d88abSStefano Zampini   PetscCall(PetscOptionsReal("-alpha", "alpha", __FILE__, options->alpha, &options->alpha, NULL));
950811d88abSStefano Zampini   PetscCall(PetscOptionsReal("-gamma", "gamma", __FILE__, options->gamma, &options->gamma, NULL));
951811d88abSStefano Zampini   PetscCall(PetscOptionsReal("-d", "D", __FILE__, options->D, &options->D, NULL));
952811d88abSStefano Zampini   PetscCall(PetscOptionsReal("-eps", "eps", __FILE__, options->eps, &options->eps, NULL));
953811d88abSStefano Zampini   PetscCall(PetscOptionsReal("-r", "r", __FILE__, options->r, &options->r, NULL));
954811d88abSStefano Zampini   PetscCall(PetscOptionsInt("-ic_num", "ic_num", __FILE__, options->ic_num, &options->ic_num, NULL));
95566edf50cSStefano Zampini   PetscCall(PetscOptionsBool("-split", "Operator splitting", __FILE__, options->split, &options->split, NULL));
956204aa523SStefano Zampini   PetscCall(PetscOptionsBool("-lump", "use mass lumping", __FILE__, options->lump, &options->lump, NULL));
95766edf50cSStefano Zampini   PetscCall(PetscOptionsInt("-fix_c", "Fix conductivity: shift to always be positive semi-definite or raise domain error", __FILE__, options->fix_c, &options->fix_c, NULL));
958811d88abSStefano Zampini   PetscCall(PetscOptionsBool("-amr", "use adaptive mesh refinement", __FILE__, options->amr, &options->amr, NULL));
95966edf50cSStefano Zampini   PetscCall(PetscOptionsReal("-domain_error_tol", "domain error tolerance", __FILE__, options->function_domain_error_tol, &options->function_domain_error_tol, NULL));
960811d88abSStefano Zampini   PetscCall(PetscOptionsBool("-test_restart", "test restarting files", __FILE__, options->test_restart, &options->test_restart, NULL));
961811d88abSStefano Zampini   if (!options->test_restart) {
962811d88abSStefano Zampini     PetscCall(PetscOptionsString("-load", "filename with data to be loaded for restarting", __FILE__, options->load_filename, options->load_filename, PETSC_MAX_PATH_LEN, &options->load));
963811d88abSStefano Zampini     PetscCall(PetscOptionsString("-save", "filename with data to be saved for restarting", __FILE__, options->save_filename, options->save_filename, PETSC_MAX_PATH_LEN, &options->save));
964811d88abSStefano Zampini     if (options->save) PetscCall(PetscOptionsInt("-save_every", "save every n timestep (-1 saves only the last)", __FILE__, options->save_every, &options->save_every, NULL));
965811d88abSStefano Zampini   }
96666edf50cSStefano Zampini   PetscCall(PetscOptionsBool("-exclude_potential_lte", "exclude potential from LTE", __FILE__, options->exclude_potential_lte, &options->exclude_potential_lte, NULL));
96766edf50cSStefano Zampini   options->view_times_k = 0;
96866edf50cSStefano Zampini   options->view_times_n = 0;
96966edf50cSStefano Zampini   PetscCall(PetscOptionsRealArray("-monitor_times", "Save at specific times", NULL, options->view_times, (tmp = 64, &tmp), &flg));
97066edf50cSStefano Zampini   if (flg) options->view_times_n = tmp;
97166edf50cSStefano Zampini 
97266edf50cSStefano Zampini   PetscCall(PetscOptionsString("-monitor_vtk", "Dump VTK file for diagnostic", "TSMonitorSolutionVTK", NULL, vtkmonfilename, sizeof(vtkmonfilename), &flg));
97366edf50cSStefano Zampini   if (flg) {
97466edf50cSStefano Zampini     PetscCall(TSMonitorSolutionVTKCtxCreate(vtkmonfilename, &options->view_vtk_ctx));
97566edf50cSStefano Zampini     PetscCall(PetscOptionsInt("-monitor_vtk_interval", "Save every interval time steps", NULL, options->view_vtk_ctx->interval, &options->view_vtk_ctx->interval, NULL));
97666edf50cSStefano Zampini   }
97766edf50cSStefano Zampini   PetscCall(PetscOptionsString("-monitor_hdf5", "Dump HDF5 file for diagnostic", "TSMonitorSolution", NULL, hdf5monfilename, sizeof(hdf5monfilename), &flg));
97866edf50cSStefano Zampini   PetscCall(PetscOptionsInt("-monitor_diagnostic_num", "Number of diagnostics to be computed", __FILE__, options->diagnostic_num, &options->diagnostic_num, NULL));
97966edf50cSStefano Zampini 
98066edf50cSStefano Zampini   if (flg) {
98166edf50cSStefano Zampini #if defined(PETSC_HAVE_HDF5)
98266edf50cSStefano Zampini     PetscViewer viewer;
98366edf50cSStefano Zampini 
98466edf50cSStefano Zampini     PetscCall(PetscViewerHDF5Open(PETSC_COMM_WORLD, hdf5monfilename, FILE_MODE_WRITE, &viewer));
98566edf50cSStefano Zampini     PetscCall(PetscViewerAndFormatCreate(viewer, PETSC_VIEWER_HDF5_VIZ, &options->view_hdf5_ctx));
98666edf50cSStefano Zampini     options->view_hdf5_ctx->view_interval = 1;
98766edf50cSStefano Zampini     PetscCall(PetscOptionsInt("-monitor_hdf5_interval", "Save every interval time steps", NULL, options->view_hdf5_ctx->view_interval, &options->view_hdf5_ctx->view_interval, NULL));
98866edf50cSStefano Zampini     PetscCall(PetscViewerDestroy(&viewer));
98966edf50cSStefano Zampini #else
99066edf50cSStefano Zampini     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Needs HDF5 support. Please reconfigure using --download-hdf5");
99166edf50cSStefano Zampini #endif
99266edf50cSStefano Zampini   }
99366edf50cSStefano Zampini   PetscCall(PetscOptionsBool("-monitor_norms", "Monitor separate SNES norms", __FILE__, options->monitor_norms, &options->monitor_norms, NULL));
99466edf50cSStefano Zampini 
99566edf50cSStefano Zampini   /* source options */
99666edf50cSStefano Zampini   PetscCall(PetscNew(&options->source_ctx));
99766edf50cSStefano Zampini   options->source_ctx->n = 1;
99866edf50cSStefano Zampini 
99966edf50cSStefano Zampini   PetscCall(PetscOptionsInt("-source_num", "number of sources", __FILE__, options->source_ctx->n, &options->source_ctx->n, NULL));
100066edf50cSStefano Zampini   tmp = options->source_ctx->n;
100166edf50cSStefano Zampini   PetscCall(PetscMalloc5(options->dim * tmp, &options->source_ctx->x0, tmp, &options->source_ctx->w, tmp, &options->source_ctx->k, tmp, &options->source_ctx->p, tmp, &options->source_ctx->r));
100266edf50cSStefano Zampini   for (PetscInt i = 0; i < options->source_ctx->n; i++) {
1003ac530a7eSPierre Jolivet     for (PetscInt d = 0; d < options->dim; d++) options->source_ctx->x0[options->dim * i + d] = 0.25;
100466edf50cSStefano Zampini     options->source_ctx->w[i] = 500;
100566edf50cSStefano Zampini     options->source_ctx->k[i] = 0;
100666edf50cSStefano Zampini     options->source_ctx->p[i] = 0;
100766edf50cSStefano Zampini     options->source_ctx->r[i] = 1;
100866edf50cSStefano Zampini   }
100966edf50cSStefano Zampini   tmp = options->dim * options->source_ctx->n;
101066edf50cSStefano Zampini   PetscCall(PetscOptionsRealArray("-source_x0", "source location", __FILE__, options->source_ctx->x0, &tmp, NULL));
101166edf50cSStefano Zampini   tmp = options->source_ctx->n;
101266edf50cSStefano Zampini   PetscCall(PetscOptionsRealArray("-source_w", "source factor", __FILE__, options->source_ctx->w, &tmp, NULL));
101366edf50cSStefano Zampini   tmp = options->source_ctx->n;
101466edf50cSStefano Zampini   PetscCall(PetscOptionsRealArray("-source_k", "source frequency", __FILE__, options->source_ctx->k, &tmp, NULL));
101566edf50cSStefano Zampini   tmp = options->source_ctx->n;
101666edf50cSStefano Zampini   PetscCall(PetscOptionsRealArray("-source_p", "source phase", __FILE__, options->source_ctx->p, &tmp, NULL));
101766edf50cSStefano Zampini   tmp = options->source_ctx->n;
101866edf50cSStefano Zampini   PetscCall(PetscOptionsRealArray("-source_r", "source scaling", __FILE__, options->source_ctx->r, &tmp, NULL));
1019811d88abSStefano Zampini   PetscOptionsEnd();
1020811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1021811d88abSStefano Zampini }
1022811d88abSStefano Zampini 
SaveToFile(DM dm,Vec u,const char * filename)1023811d88abSStefano Zampini static PetscErrorCode SaveToFile(DM dm, Vec u, const char *filename)
1024811d88abSStefano Zampini {
1025811d88abSStefano Zampini #if defined(PETSC_HAVE_HDF5)
1026811d88abSStefano Zampini   PetscViewerFormat format = PETSC_VIEWER_HDF5_PETSC;
1027811d88abSStefano Zampini   PetscViewer       viewer;
1028811d88abSStefano Zampini   DM                cdm       = dm;
1029811d88abSStefano Zampini   PetscInt          numlevels = 0;
1030811d88abSStefano Zampini 
1031811d88abSStefano Zampini   PetscFunctionBeginUser;
1032811d88abSStefano Zampini   while (cdm) {
1033811d88abSStefano Zampini     numlevels++;
1034811d88abSStefano Zampini     PetscCall(DMGetCoarseDM(cdm, &cdm));
1035811d88abSStefano Zampini   }
1036811d88abSStefano Zampini   /* Cannot be set programmatically */
1037811d88abSStefano Zampini   PetscCall(PetscOptionsInsertString(NULL, "-dm_plex_view_hdf5_storage_version 3.0.0"));
1038811d88abSStefano Zampini   PetscCall(PetscViewerHDF5Open(PetscObjectComm((PetscObject)dm), filename, FILE_MODE_WRITE, &viewer));
1039811d88abSStefano Zampini   PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "numlevels", PETSC_INT, &numlevels));
1040811d88abSStefano Zampini   PetscCall(PetscViewerPushFormat(viewer, format));
1041811d88abSStefano Zampini   for (PetscInt level = numlevels - 1; level >= 0; level--) {
1042811d88abSStefano Zampini     PetscInt    cc, rr;
1043811d88abSStefano Zampini     PetscBool   isRegular, isUniform;
1044811d88abSStefano Zampini     const char *dmname;
1045811d88abSStefano Zampini     char        groupname[PETSC_MAX_PATH_LEN];
1046811d88abSStefano Zampini 
1047811d88abSStefano Zampini     PetscCall(PetscSNPrintf(groupname, sizeof(groupname), "level_%" PetscInt_FMT, level));
1048811d88abSStefano Zampini     PetscCall(PetscViewerHDF5PushGroup(viewer, groupname));
1049811d88abSStefano Zampini     PetscCall(PetscObjectGetName((PetscObject)dm, &dmname));
1050811d88abSStefano Zampini     PetscCall(DMGetCoarsenLevel(dm, &cc));
1051811d88abSStefano Zampini     PetscCall(DMGetRefineLevel(dm, &rr));
1052811d88abSStefano Zampini     PetscCall(DMPlexGetRegularRefinement(dm, &isRegular));
1053811d88abSStefano Zampini     PetscCall(DMPlexGetRefinementUniform(dm, &isUniform));
1054811d88abSStefano Zampini     PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "meshname", PETSC_STRING, dmname));
1055811d88abSStefano Zampini     PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "refinelevel", PETSC_INT, &rr));
1056811d88abSStefano Zampini     PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "coarsenlevel", PETSC_INT, &cc));
1057811d88abSStefano Zampini     PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "refRegular", PETSC_BOOL, &isRegular));
1058811d88abSStefano Zampini     PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "refUniform", PETSC_BOOL, &isUniform));
1059811d88abSStefano Zampini     PetscCall(DMPlexTopologyView(dm, viewer));
1060811d88abSStefano Zampini     PetscCall(DMPlexLabelsView(dm, viewer));
1061811d88abSStefano Zampini     PetscCall(DMPlexCoordinatesView(dm, viewer));
1062811d88abSStefano Zampini     PetscCall(DMPlexSectionView(dm, viewer, NULL));
1063811d88abSStefano Zampini     if (level == numlevels - 1) {
1064811d88abSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)u, "solution_"));
1065811d88abSStefano Zampini       PetscCall(DMPlexGlobalVectorView(dm, viewer, NULL, u));
1066811d88abSStefano Zampini     }
1067811d88abSStefano Zampini     if (level) {
1068811d88abSStefano Zampini       PetscInt        cStart, cEnd, ccStart, ccEnd, cpStart;
1069811d88abSStefano Zampini       DMPolytopeType  ct;
1070811d88abSStefano Zampini       DMPlexTransform tr;
1071811d88abSStefano Zampini       DM              sdm;
1072811d88abSStefano Zampini       PetscScalar    *array;
1073811d88abSStefano Zampini       PetscSection    section;
1074811d88abSStefano Zampini       Vec             map;
1075811d88abSStefano Zampini       IS              gis;
1076811d88abSStefano Zampini       const PetscInt *gidx;
1077811d88abSStefano Zampini 
1078811d88abSStefano Zampini       PetscCall(DMGetCoarseDM(dm, &cdm));
1079811d88abSStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1080811d88abSStefano Zampini       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
1081811d88abSStefano Zampini       PetscCall(PetscSectionSetChart(section, cStart, cEnd));
1082811d88abSStefano Zampini       for (PetscInt c = cStart; c < cEnd; c++) PetscCall(PetscSectionSetDof(section, c, 1));
1083811d88abSStefano Zampini       PetscCall(PetscSectionSetUp(section));
1084811d88abSStefano Zampini 
1085811d88abSStefano Zampini       PetscCall(DMClone(dm, &sdm));
1086811d88abSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)sdm, "pdm"));
1087811d88abSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)section, "pdm_section"));
1088811d88abSStefano Zampini       PetscCall(DMSetLocalSection(sdm, section));
1089811d88abSStefano Zampini       PetscCall(PetscSectionDestroy(&section));
1090811d88abSStefano Zampini 
1091811d88abSStefano Zampini       PetscCall(DMGetLocalVector(sdm, &map));
1092811d88abSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)map, "pdm_map"));
1093811d88abSStefano Zampini       PetscCall(VecGetArray(map, &array));
1094811d88abSStefano Zampini       PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr));
1095811d88abSStefano Zampini       PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR));
1096811d88abSStefano Zampini       PetscCall(DMPlexTransformSetDM(tr, cdm));
1097811d88abSStefano Zampini       PetscCall(DMPlexTransformSetFromOptions(tr));
1098811d88abSStefano Zampini       PetscCall(DMPlexTransformSetUp(tr));
1099811d88abSStefano Zampini       PetscCall(DMPlexGetHeightStratum(cdm, 0, &ccStart, &ccEnd));
1100811d88abSStefano Zampini       PetscCall(DMPlexGetChart(cdm, &cpStart, NULL));
1101811d88abSStefano Zampini       PetscCall(DMPlexCreatePointNumbering(cdm, &gis));
1102811d88abSStefano Zampini       PetscCall(ISGetIndices(gis, &gidx));
1103811d88abSStefano Zampini       for (PetscInt c = ccStart; c < ccEnd; c++) {
1104811d88abSStefano Zampini         PetscInt       *rsize, *rcone, *rornt, Nt;
1105811d88abSStefano Zampini         DMPolytopeType *rct;
1106811d88abSStefano Zampini         PetscInt        gnum = gidx[c - cpStart] >= 0 ? gidx[c - cpStart] : -(gidx[c - cpStart] + 1);
1107811d88abSStefano Zampini 
1108811d88abSStefano Zampini         PetscCall(DMPlexGetCellType(cdm, c, &ct));
1109811d88abSStefano Zampini         PetscCall(DMPlexTransformCellTransform(tr, ct, c, NULL, &Nt, &rct, &rsize, &rcone, &rornt));
1110811d88abSStefano Zampini         for (PetscInt r = 0; r < rsize[Nt - 1]; ++r) {
1111811d88abSStefano Zampini           PetscInt pNew;
1112811d88abSStefano Zampini 
1113811d88abSStefano Zampini           PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[Nt - 1], c, r, &pNew));
1114811d88abSStefano Zampini           array[pNew - cStart] = gnum;
1115811d88abSStefano Zampini         }
1116811d88abSStefano Zampini       }
1117811d88abSStefano Zampini       PetscCall(ISRestoreIndices(gis, &gidx));
1118811d88abSStefano Zampini       PetscCall(ISDestroy(&gis));
1119811d88abSStefano Zampini       PetscCall(VecRestoreArray(map, &array));
1120811d88abSStefano Zampini       PetscCall(DMPlexTransformDestroy(&tr));
1121811d88abSStefano Zampini       PetscCall(DMPlexSectionView(dm, viewer, sdm));
1122811d88abSStefano Zampini       PetscCall(DMPlexLocalVectorView(dm, viewer, sdm, map));
1123811d88abSStefano Zampini       PetscCall(DMRestoreLocalVector(sdm, &map));
1124811d88abSStefano Zampini       PetscCall(DMDestroy(&sdm));
1125811d88abSStefano Zampini     }
1126811d88abSStefano Zampini     PetscCall(PetscViewerHDF5PopGroup(viewer));
1127811d88abSStefano Zampini     PetscCall(DMGetCoarseDM(dm, &dm));
1128811d88abSStefano Zampini   }
1129811d88abSStefano Zampini   PetscCall(PetscViewerPopFormat(viewer));
1130811d88abSStefano Zampini   PetscCall(PetscViewerDestroy(&viewer));
1131811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1132811d88abSStefano Zampini #else
1133811d88abSStefano Zampini   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Needs HDF5 support. Please reconfigure using --download-hdf5");
1134811d88abSStefano Zampini #endif
1135811d88abSStefano Zampini }
1136811d88abSStefano Zampini 
LoadFromFile(MPI_Comm comm,const char * filename,DM * odm)1137811d88abSStefano Zampini static PetscErrorCode LoadFromFile(MPI_Comm comm, const char *filename, DM *odm)
1138811d88abSStefano Zampini {
1139811d88abSStefano Zampini #if defined(PETSC_HAVE_HDF5)
1140811d88abSStefano Zampini   PetscViewerFormat format = PETSC_VIEWER_HDF5_PETSC;
1141811d88abSStefano Zampini   PetscViewer       viewer;
1142811d88abSStefano Zampini   DM                dm, cdm = NULL;
1143811d88abSStefano Zampini   PetscSF           sfXC      = NULL;
1144811d88abSStefano Zampini   PetscInt          numlevels = -1;
1145811d88abSStefano Zampini 
1146811d88abSStefano Zampini   PetscFunctionBeginUser;
1147811d88abSStefano Zampini   PetscCall(PetscViewerHDF5Open(comm, filename, FILE_MODE_READ, &viewer));
1148811d88abSStefano Zampini   PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "numlevels", PETSC_INT, NULL, &numlevels));
1149811d88abSStefano Zampini   PetscCall(PetscViewerPushFormat(viewer, format));
1150811d88abSStefano Zampini   for (PetscInt level = 0; level < numlevels; level++) {
1151811d88abSStefano Zampini     char             groupname[PETSC_MAX_PATH_LEN], *dmname;
1152811d88abSStefano Zampini     PetscSF          sfXB, sfBC, sfG;
1153811d88abSStefano Zampini     PetscPartitioner part;
1154811d88abSStefano Zampini     PetscInt         rr, cc;
1155811d88abSStefano Zampini     PetscBool        isRegular, isUniform;
1156811d88abSStefano Zampini 
1157811d88abSStefano Zampini     PetscCall(DMCreate(comm, &dm));
1158811d88abSStefano Zampini     PetscCall(DMSetType(dm, DMPLEX));
1159811d88abSStefano Zampini     PetscCall(PetscSNPrintf(groupname, sizeof(groupname), "level_%" PetscInt_FMT, level));
1160811d88abSStefano Zampini     PetscCall(PetscViewerHDF5PushGroup(viewer, groupname));
1161811d88abSStefano Zampini     PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "meshname", PETSC_STRING, NULL, &dmname));
1162811d88abSStefano Zampini     PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "refinelevel", PETSC_INT, NULL, &rr));
1163811d88abSStefano Zampini     PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "coarsenlevel", PETSC_INT, NULL, &cc));
1164811d88abSStefano Zampini     PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "refRegular", PETSC_BOOL, NULL, &isRegular));
1165811d88abSStefano Zampini     PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "refUniform", PETSC_BOOL, NULL, &isUniform));
1166811d88abSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)dm, dmname));
1167811d88abSStefano Zampini     PetscCall(DMPlexTopologyLoad(dm, viewer, &sfXB));
1168811d88abSStefano Zampini     PetscCall(DMPlexLabelsLoad(dm, viewer, sfXB));
1169811d88abSStefano Zampini     PetscCall(DMPlexCoordinatesLoad(dm, viewer, sfXB));
1170811d88abSStefano Zampini     PetscCall(DMPlexGetPartitioner(dm, &part));
1171811d88abSStefano Zampini     if (!level) { /* partition the coarse level only */
1172811d88abSStefano Zampini       PetscCall(PetscPartitionerSetFromOptions(part));
1173811d88abSStefano Zampini     } else { /* propagate partitioning information from coarser to finer level */
1174811d88abSStefano Zampini       DM           sdm;
1175811d88abSStefano Zampini       Vec          map;
1176811d88abSStefano Zampini       PetscSF      sf;
1177811d88abSStefano Zampini       PetscLayout  clayout;
1178811d88abSStefano Zampini       PetscScalar *array;
1179811d88abSStefano Zampini       PetscInt    *cranks_leaf, *cranks_root, *npoints, *points, *ranks, *starts, *gidxs;
1180811d88abSStefano Zampini       PetscInt     nparts, cStart, cEnd, nr, ccStart, ccEnd, cpStart, cpEnd;
1181811d88abSStefano Zampini       PetscMPIInt  size, rank;
1182811d88abSStefano Zampini 
1183811d88abSStefano Zampini       PetscCall(DMClone(dm, &sdm));
1184811d88abSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)sdm, "pdm"));
1185811d88abSStefano Zampini       PetscCall(DMPlexSectionLoad(dm, viewer, sdm, sfXB, NULL, &sf));
1186811d88abSStefano Zampini       PetscCall(DMGetLocalVector(sdm, &map));
1187811d88abSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)map, "pdm_map"));
1188811d88abSStefano Zampini       PetscCall(DMPlexLocalVectorLoad(dm, viewer, sdm, sf, map));
1189811d88abSStefano Zampini 
1190811d88abSStefano Zampini       PetscCallMPI(MPI_Comm_size(comm, &size));
1191811d88abSStefano Zampini       PetscCallMPI(MPI_Comm_rank(comm, &rank));
1192811d88abSStefano Zampini       nparts = size;
1193811d88abSStefano Zampini       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1194811d88abSStefano Zampini       PetscCall(DMPlexGetHeightStratum(cdm, 0, &ccStart, &ccEnd));
1195811d88abSStefano Zampini       PetscCall(DMPlexGetChart(cdm, &cpStart, &cpEnd));
1196811d88abSStefano Zampini       PetscCall(PetscCalloc1(nparts, &npoints));
1197811d88abSStefano Zampini       PetscCall(PetscMalloc4(cEnd - cStart, &points, cEnd - cStart, &ranks, nparts + 1, &starts, cEnd - cStart, &gidxs));
1198811d88abSStefano Zampini       PetscCall(PetscSFGetGraph(sfXC, &nr, NULL, NULL, NULL));
1199811d88abSStefano Zampini       PetscCall(PetscMalloc2(cpEnd - cpStart, &cranks_leaf, nr, &cranks_root));
1200811d88abSStefano Zampini       for (PetscInt c = 0; c < cpEnd - cpStart; c++) cranks_leaf[c] = rank;
1201811d88abSStefano Zampini       PetscCall(PetscSFReduceBegin(sfXC, MPIU_INT, cranks_leaf, cranks_root, MPI_REPLACE));
1202811d88abSStefano Zampini       PetscCall(PetscSFReduceEnd(sfXC, MPIU_INT, cranks_leaf, cranks_root, MPI_REPLACE));
1203811d88abSStefano Zampini 
1204811d88abSStefano Zampini       PetscCall(VecGetArray(map, &array));
1205811d88abSStefano Zampini       for (PetscInt c = 0; c < cEnd - cStart; c++) gidxs[c] = (PetscInt)PetscRealPart(array[c]);
1206811d88abSStefano Zampini       PetscCall(VecRestoreArray(map, &array));
1207811d88abSStefano Zampini 
1208811d88abSStefano Zampini       PetscCall(PetscLayoutCreate(comm, &clayout));
1209811d88abSStefano Zampini       PetscCall(PetscLayoutSetLocalSize(clayout, nr));
1210811d88abSStefano Zampini       PetscCall(PetscSFSetGraphLayout(sf, clayout, cEnd - cStart, NULL, PETSC_OWN_POINTER, gidxs));
1211811d88abSStefano Zampini       PetscCall(PetscLayoutDestroy(&clayout));
1212811d88abSStefano Zampini 
1213811d88abSStefano Zampini       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, cranks_root, ranks, MPI_REPLACE));
1214811d88abSStefano Zampini       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, cranks_root, ranks, MPI_REPLACE));
1215811d88abSStefano Zampini       PetscCall(PetscSFDestroy(&sf));
1216811d88abSStefano Zampini       PetscCall(PetscFree2(cranks_leaf, cranks_root));
1217811d88abSStefano Zampini       for (PetscInt c = 0; c < cEnd - cStart; c++) npoints[ranks[c]]++;
1218811d88abSStefano Zampini 
1219811d88abSStefano Zampini       starts[0] = 0;
1220811d88abSStefano Zampini       for (PetscInt c = 0; c < nparts; c++) starts[c + 1] = starts[c] + npoints[c];
1221811d88abSStefano Zampini       for (PetscInt c = 0; c < cEnd - cStart; c++) points[starts[ranks[c]]++] = c;
1222811d88abSStefano Zampini       PetscCall(PetscPartitionerSetType(part, PETSCPARTITIONERSHELL));
1223811d88abSStefano Zampini       PetscCall(PetscPartitionerShellSetPartition(part, nparts, npoints, points));
1224811d88abSStefano Zampini       PetscCall(PetscFree(npoints));
1225811d88abSStefano Zampini       PetscCall(PetscFree4(points, ranks, starts, gidxs));
1226811d88abSStefano Zampini       PetscCall(DMRestoreLocalVector(sdm, &map));
1227811d88abSStefano Zampini       PetscCall(DMDestroy(&sdm));
1228811d88abSStefano Zampini     }
1229811d88abSStefano Zampini     PetscCall(PetscSFDestroy(&sfXC));
1230811d88abSStefano Zampini     PetscCall(DMPlexDistribute(dm, 0, &sfBC, odm));
1231811d88abSStefano Zampini     if (*odm) {
1232811d88abSStefano Zampini       PetscCall(DMDestroy(&dm));
1233811d88abSStefano Zampini       dm   = *odm;
1234811d88abSStefano Zampini       *odm = NULL;
1235811d88abSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)dm, dmname));
1236811d88abSStefano Zampini     }
1237811d88abSStefano Zampini     if (sfBC) PetscCall(PetscSFCompose(sfXB, sfBC, &sfXC));
1238811d88abSStefano Zampini     else {
1239811d88abSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)sfXB));
1240811d88abSStefano Zampini       sfXC = sfXB;
1241811d88abSStefano Zampini     }
1242811d88abSStefano Zampini     PetscCall(PetscSFDestroy(&sfXB));
1243811d88abSStefano Zampini     PetscCall(PetscSFDestroy(&sfBC));
1244811d88abSStefano Zampini     PetscCall(DMSetCoarsenLevel(dm, cc));
1245811d88abSStefano Zampini     PetscCall(DMSetRefineLevel(dm, rr));
1246811d88abSStefano Zampini     PetscCall(DMPlexSetRegularRefinement(dm, isRegular));
1247811d88abSStefano Zampini     PetscCall(DMPlexSetRefinementUniform(dm, isUniform));
1248811d88abSStefano Zampini     PetscCall(DMPlexSectionLoad(dm, viewer, NULL, sfXC, &sfG, NULL));
1249811d88abSStefano Zampini     if (level == numlevels - 1) {
1250811d88abSStefano Zampini       Vec u;
1251811d88abSStefano Zampini 
1252811d88abSStefano Zampini       PetscCall(DMGetNamedGlobalVector(dm, "solution_", &u));
1253811d88abSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)u, "solution_"));
1254811d88abSStefano Zampini       PetscCall(DMPlexGlobalVectorLoad(dm, viewer, NULL, sfG, u));
1255811d88abSStefano Zampini       PetscCall(DMRestoreNamedGlobalVector(dm, "solution_", &u));
1256811d88abSStefano Zampini     }
1257811d88abSStefano Zampini     PetscCall(PetscFree(dmname));
1258811d88abSStefano Zampini     PetscCall(PetscSFDestroy(&sfG));
1259811d88abSStefano Zampini     PetscCall(DMSetCoarseDM(dm, cdm));
1260811d88abSStefano Zampini     PetscCall(DMDestroy(&cdm));
1261811d88abSStefano Zampini     PetscCall(PetscViewerHDF5PopGroup(viewer));
1262811d88abSStefano Zampini     cdm = dm;
1263811d88abSStefano Zampini   }
1264811d88abSStefano Zampini   *odm = dm;
1265811d88abSStefano Zampini   PetscCall(PetscViewerPopFormat(viewer));
1266811d88abSStefano Zampini   PetscCall(PetscViewerDestroy(&viewer));
1267811d88abSStefano Zampini   PetscCall(PetscSFDestroy(&sfXC));
1268811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1269811d88abSStefano Zampini #else
1270811d88abSStefano Zampini   SETERRQ(comm, PETSC_ERR_SUP, "Needs HDF5 support. Please reconfigure using --download-hdf5");
1271811d88abSStefano Zampini #endif
1272811d88abSStefano Zampini }
1273811d88abSStefano Zampini 
127466edf50cSStefano Zampini /*
127566edf50cSStefano Zampini    Setup AuxDM:
127666edf50cSStefano Zampini      - project source function and make it zero-mean
127766edf50cSStefano Zampini      - sample frozen fields for operator splitting
127866edf50cSStefano Zampini */
ProjectAuxDM(DM dm,PetscReal time,Vec u,AppCtx * ctx)127966edf50cSStefano Zampini static PetscErrorCode ProjectAuxDM(DM dm, PetscReal time, Vec u, AppCtx *ctx)
1280811d88abSStefano Zampini {
1281811d88abSStefano Zampini   DM          dmAux;
128266edf50cSStefano Zampini   Vec         la, a;
128366edf50cSStefano Zampini   void       *ctxs[NUM_FIELDS + 1];
128466edf50cSStefano Zampini   PetscScalar vals[NUM_FIELDS + 1];
128566edf50cSStefano Zampini   VecScatter  sctAux;
1286811d88abSStefano Zampini   PetscDS     ds;
128766edf50cSStefano Zampini   PetscErrorCode (*funcs[NUM_FIELDS + 1])(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *);
1288811d88abSStefano Zampini 
1289811d88abSStefano Zampini   PetscFunctionBeginUser;
129066edf50cSStefano Zampini   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &la));
129166edf50cSStefano Zampini   if (!la) {
129266edf50cSStefano Zampini     PetscFE  field;
129366edf50cSStefano Zampini     PetscInt fields[NUM_FIELDS];
129466edf50cSStefano Zampini     IS       is;
129566edf50cSStefano Zampini     Vec      tu, ta;
129666edf50cSStefano Zampini     PetscInt dim;
129766edf50cSStefano Zampini 
129866edf50cSStefano Zampini     PetscCall(DMClone(dm, &dmAux));
129966edf50cSStefano Zampini     PetscCall(DMSetNumFields(dmAux, NUM_FIELDS + 1));
130066edf50cSStefano Zampini     for (PetscInt i = 0; i < NUM_FIELDS; i++) {
130166edf50cSStefano Zampini       PetscCall(DMGetField(dm, i, NULL, (PetscObject *)&field));
130266edf50cSStefano Zampini       PetscCall(DMSetField(dmAux, i, NULL, (PetscObject)field));
130366edf50cSStefano Zampini       fields[i] = i;
1304811d88abSStefano Zampini     }
130566edf50cSStefano Zampini     /* PetscFEDuplicate? */
130666edf50cSStefano Zampini     PetscCall(DMGetDimension(dm, &dim));
130766edf50cSStefano Zampini     PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dm), dim, 1, ctx->simplex, "p_", -1, &field));
130866edf50cSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)field, "source"));
130966edf50cSStefano Zampini     PetscCall(DMSetField(dmAux, NUM_FIELDS, NULL, (PetscObject)field));
131066edf50cSStefano Zampini     PetscCall(PetscFEDestroy(&field));
131166edf50cSStefano Zampini     PetscCall(DMCreateDS(dmAux));
131266edf50cSStefano Zampini     PetscCall(DMCreateSubDM(dmAux, NUM_FIELDS, fields, &is, NULL));
131366edf50cSStefano Zampini     PetscCall(DMGetGlobalVector(dm, &tu));
131466edf50cSStefano Zampini     PetscCall(DMGetGlobalVector(dmAux, &ta));
131566edf50cSStefano Zampini     PetscCall(VecScatterCreate(tu, NULL, ta, is, &sctAux));
131666edf50cSStefano Zampini     PetscCall(DMRestoreGlobalVector(dm, &tu));
131766edf50cSStefano Zampini     PetscCall(DMRestoreGlobalVector(dmAux, &ta));
131866edf50cSStefano Zampini     PetscCall(PetscObjectCompose((PetscObject)dmAux, "scatterAux", (PetscObject)sctAux));
131966edf50cSStefano Zampini     PetscCall(VecScatterDestroy(&sctAux));
132066edf50cSStefano Zampini     PetscCall(ISDestroy(&is));
132166edf50cSStefano Zampini     PetscCall(DMCreateLocalVector(dmAux, &la));
132266edf50cSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)la, "auxiliary_"));
132366edf50cSStefano Zampini     PetscCall(DMSetAuxiliaryVec(dm, NULL, 0, 0, la));
132466edf50cSStefano Zampini     PetscCall(DMDestroy(&dmAux));
132566edf50cSStefano Zampini     PetscCall(VecDestroy(&la));
132666edf50cSStefano Zampini   }
132766edf50cSStefano Zampini   if (time == PETSC_MIN_REAL) PetscFunctionReturn(PETSC_SUCCESS);
132866edf50cSStefano Zampini 
132966edf50cSStefano Zampini   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &la));
133066edf50cSStefano Zampini   PetscCall(VecGetDM(la, &dmAux));
133166edf50cSStefano Zampini   PetscCall(DMGetDS(dmAux, &ds));
133266edf50cSStefano Zampini   PetscCall(DMGetGlobalVector(dmAux, &a));
1333811d88abSStefano Zampini   funcs[C_FIELD_ID] = zerof;
1334811d88abSStefano Zampini   ctxs[C_FIELD_ID]  = NULL;
133566edf50cSStefano Zampini   funcs[P_FIELD_ID] = zerof;
133666edf50cSStefano Zampini   ctxs[P_FIELD_ID]  = NULL;
133766edf50cSStefano Zampini   funcs[NUM_FIELDS] = source;
133866edf50cSStefano Zampini   ctxs[NUM_FIELDS]  = ctx->source_ctx;
133966edf50cSStefano Zampini   PetscCall(DMProjectFunction(dmAux, time, funcs, ctxs, INSERT_ALL_VALUES, a));
1340811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, P_FIELD_ID, zero));
134166edf50cSStefano Zampini   PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, zero));
134266edf50cSStefano Zampini   PetscCall(PetscDSSetObjective(ds, NUM_FIELDS, average));
134366edf50cSStefano Zampini   PetscCall(DMPlexComputeIntegralFEM(dmAux, a, vals, NULL));
134466edf50cSStefano Zampini   PetscCall(VecShift(a, -vals[NUM_FIELDS] / ctx->domain_volume));
134566edf50cSStefano Zampini   if (u) {
134666edf50cSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)dmAux, "scatterAux", (PetscObject *)&sctAux));
134766edf50cSStefano Zampini     PetscCheck(sctAux, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing scatterAux");
134866edf50cSStefano Zampini     PetscCall(VecScatterBegin(sctAux, u, a, INSERT_VALUES, SCATTER_FORWARD));
134966edf50cSStefano Zampini     PetscCall(VecScatterEnd(sctAux, u, a, INSERT_VALUES, SCATTER_FORWARD));
135066edf50cSStefano Zampini   }
135166edf50cSStefano Zampini   PetscCall(DMGlobalToLocal(dmAux, a, INSERT_VALUES, la));
135266edf50cSStefano Zampini   PetscCall(VecViewFromOptions(la, NULL, "-aux_view"));
135366edf50cSStefano Zampini   PetscCall(DMRestoreGlobalVector(dmAux, &a));
1354811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1355811d88abSStefano Zampini }
1356811d88abSStefano Zampini 
1357811d88abSStefano Zampini /* callback for the creation of the potential null space */
CreatePotentialNullSpace(DM dm,PetscInt ofield,PetscInt nfield,MatNullSpace * nullSpace)1358811d88abSStefano Zampini static PetscErrorCode CreatePotentialNullSpace(DM dm, PetscInt ofield, PetscInt nfield, MatNullSpace *nullSpace)
1359811d88abSStefano Zampini {
1360811d88abSStefano Zampini   Vec vec;
1361811d88abSStefano Zampini   PetscErrorCode (*funcs[NUM_FIELDS])(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *) = {zerof};
1362811d88abSStefano Zampini 
1363811d88abSStefano Zampini   PetscFunctionBeginUser;
1364811d88abSStefano Zampini   funcs[nfield] = constantf;
1365811d88abSStefano Zampini   PetscCall(DMCreateGlobalVector(dm, &vec));
1366811d88abSStefano Zampini   PetscCall(DMProjectFunction(dm, 0.0, funcs, NULL, INSERT_ALL_VALUES, vec));
1367811d88abSStefano Zampini   PetscCall(VecNormalize(vec, NULL));
1368811d88abSStefano Zampini   PetscCall(MatNullSpaceCreate(PetscObjectComm((PetscObject)dm), PETSC_FALSE, 1, &vec, nullSpace));
1369811d88abSStefano Zampini   /* break ref cycles */
1370811d88abSStefano Zampini   PetscCall(VecSetDM(vec, NULL));
1371811d88abSStefano Zampini   PetscCall(VecDestroy(&vec));
1372811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1373811d88abSStefano Zampini }
1374811d88abSStefano Zampini 
DMGetLumpedMass(DM dm,PetscBool local,Vec * lumped_mass)1375204aa523SStefano Zampini static PetscErrorCode DMGetLumpedMass(DM dm, PetscBool local, Vec *lumped_mass)
1376204aa523SStefano Zampini {
1377204aa523SStefano Zampini   PetscBool has;
1378204aa523SStefano Zampini 
1379204aa523SStefano Zampini   PetscFunctionBeginUser;
1380204aa523SStefano Zampini   if (local) {
1381204aa523SStefano Zampini     PetscCall(DMHasNamedLocalVector(dm, "lumped_mass", &has));
1382204aa523SStefano Zampini     PetscCall(DMGetNamedLocalVector(dm, "lumped_mass", lumped_mass));
1383204aa523SStefano Zampini   } else {
1384204aa523SStefano Zampini     PetscCall(DMHasNamedGlobalVector(dm, "lumped_mass", &has));
1385204aa523SStefano Zampini     PetscCall(DMGetNamedGlobalVector(dm, "lumped_mass", lumped_mass));
1386204aa523SStefano Zampini   }
1387204aa523SStefano Zampini   if (!has) {
1388204aa523SStefano Zampini     Vec w;
1389204aa523SStefano Zampini     IS  is;
1390204aa523SStefano Zampini 
1391204aa523SStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)dm, "IS potential", (PetscObject *)&is));
139266edf50cSStefano Zampini     PetscCheck(is, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing potential IS");
1393204aa523SStefano Zampini     if (local) {
1394204aa523SStefano Zampini       Vec w2, wg;
1395204aa523SStefano Zampini 
1396204aa523SStefano Zampini       PetscCall(DMCreateMassMatrixLumped(dm, &w, NULL));
1397204aa523SStefano Zampini       PetscCall(DMGetGlobalVector(dm, &wg));
1398204aa523SStefano Zampini       PetscCall(DMGetLocalVector(dm, &w2));
1399204aa523SStefano Zampini       PetscCall(VecSet(w2, 0.0));
1400204aa523SStefano Zampini       PetscCall(VecSet(wg, 1.0));
1401204aa523SStefano Zampini       PetscCall(VecISSet(wg, is, 0.0));
1402204aa523SStefano Zampini       PetscCall(DMGlobalToLocal(dm, wg, INSERT_VALUES, w2));
1403204aa523SStefano Zampini       PetscCall(VecPointwiseMult(w, w, w2));
1404204aa523SStefano Zampini       PetscCall(DMRestoreGlobalVector(dm, &wg));
1405204aa523SStefano Zampini       PetscCall(DMRestoreLocalVector(dm, &w2));
1406204aa523SStefano Zampini     } else {
1407204aa523SStefano Zampini       PetscCall(DMCreateMassMatrixLumped(dm, NULL, &w));
1408204aa523SStefano Zampini       PetscCall(VecISSet(w, is, 0.0));
1409204aa523SStefano Zampini     }
1410204aa523SStefano Zampini     PetscCall(VecCopy(w, *lumped_mass));
1411204aa523SStefano Zampini     PetscCall(VecDestroy(&w));
1412204aa523SStefano Zampini   }
1413204aa523SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1414204aa523SStefano Zampini }
1415204aa523SStefano Zampini 
DMRestoreLumpedMass(DM dm,PetscBool local,Vec * lumped_mass)1416204aa523SStefano Zampini static PetscErrorCode DMRestoreLumpedMass(DM dm, PetscBool local, Vec *lumped_mass)
1417204aa523SStefano Zampini {
1418204aa523SStefano Zampini   PetscFunctionBeginUser;
1419204aa523SStefano Zampini   if (local) PetscCall(DMRestoreNamedLocalVector(dm, "lumped_mass", lumped_mass));
1420204aa523SStefano Zampini   else PetscCall(DMRestoreNamedGlobalVector(dm, "lumped_mass", lumped_mass));
1421204aa523SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1422204aa523SStefano Zampini }
1423204aa523SStefano Zampini 
142466edf50cSStefano Zampini /* callbacks for residual and Jacobian */
DMPlexTSComputeIFunctionFEM_Private(DM dm,PetscReal time,Vec locX,Vec locX_t,Vec locF,void * user)142566edf50cSStefano Zampini static PetscErrorCode DMPlexTSComputeIFunctionFEM_Private(DM dm, PetscReal time, Vec locX, Vec locX_t, Vec locF, void *user)
1426204aa523SStefano Zampini {
1427204aa523SStefano Zampini   Vec     work, local_lumped_mass;
142866edf50cSStefano Zampini   AppCtx *ctx = (AppCtx *)user;
1429204aa523SStefano Zampini 
1430204aa523SStefano Zampini   PetscFunctionBeginUser;
143166edf50cSStefano Zampini   if (ctx->fix_c < 0) {
143266edf50cSStefano Zampini     PetscReal vals[NUM_FIELDS];
143366edf50cSStefano Zampini     PetscDS   ds;
143466edf50cSStefano Zampini 
143566edf50cSStefano Zampini     PetscCall(DMGetDS(dm, &ds));
143666edf50cSStefano Zampini     PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, jacobian_fail));
143766edf50cSStefano Zampini     PetscCall(DMPlexSNESComputeObjectiveFEM(dm, locX, vals, NULL));
143866edf50cSStefano Zampini     PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, energy));
143966edf50cSStefano Zampini     if (vals[C_FIELD_ID]) PetscCall(SNESSetFunctionDomainError(ctx->snes));
144066edf50cSStefano Zampini   }
144166edf50cSStefano Zampini   if (ctx->lump) {
1442204aa523SStefano Zampini     PetscCall(DMGetLumpedMass(dm, PETSC_TRUE, &local_lumped_mass));
1443204aa523SStefano Zampini     PetscCall(DMGetLocalVector(dm, &work));
1444204aa523SStefano Zampini     PetscCall(VecSet(work, 0.0));
1445204aa523SStefano Zampini     PetscCall(DMPlexTSComputeIFunctionFEM(dm, time, locX, work, locF, user));
1446204aa523SStefano Zampini     PetscCall(VecPointwiseMult(work, locX_t, local_lumped_mass));
1447204aa523SStefano Zampini     PetscCall(VecAXPY(locF, 1.0, work));
1448204aa523SStefano Zampini     PetscCall(DMRestoreLocalVector(dm, &work));
1449204aa523SStefano Zampini     PetscCall(DMRestoreLumpedMass(dm, PETSC_TRUE, &local_lumped_mass));
145066edf50cSStefano Zampini   } else {
145166edf50cSStefano Zampini     PetscCall(DMPlexTSComputeIFunctionFEM(dm, time, locX, locX_t, locF, user));
145266edf50cSStefano Zampini   }
1453204aa523SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1454204aa523SStefano Zampini }
1455204aa523SStefano Zampini 
DMPlexTSComputeIJacobianFEM_Private(DM dm,PetscReal time,Vec locX,Vec locX_t,PetscReal X_tShift,Mat Jac,Mat JacP,void * user)145666edf50cSStefano Zampini static PetscErrorCode DMPlexTSComputeIJacobianFEM_Private(DM dm, PetscReal time, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
1457204aa523SStefano Zampini {
1458204aa523SStefano Zampini   Vec     lumped_mass, work;
145966edf50cSStefano Zampini   AppCtx *ctx = (AppCtx *)user;
1460204aa523SStefano Zampini 
1461204aa523SStefano Zampini   PetscFunctionBeginUser;
146266edf50cSStefano Zampini   if (ctx->lump) {
1463204aa523SStefano Zampini     PetscCall(DMGetLumpedMass(dm, PETSC_FALSE, &lumped_mass));
1464204aa523SStefano Zampini     PetscCall(DMPlexTSComputeIJacobianFEM(dm, time, locX, locX_t, 0.0, Jac, JacP, user));
1465204aa523SStefano Zampini     PetscCall(DMGetGlobalVector(dm, &work));
1466204aa523SStefano Zampini     PetscCall(VecAXPBY(work, X_tShift, 0.0, lumped_mass));
1467204aa523SStefano Zampini     PetscCall(MatDiagonalSet(JacP, work, ADD_VALUES));
1468204aa523SStefano Zampini     PetscCall(DMRestoreGlobalVector(dm, &work));
1469204aa523SStefano Zampini     PetscCall(DMRestoreLumpedMass(dm, PETSC_FALSE, &lumped_mass));
147066edf50cSStefano Zampini   } else {
147166edf50cSStefano Zampini     PetscCall(DMPlexTSComputeIJacobianFEM(dm, time, locX, locX_t, X_tShift, Jac, JacP, user));
147266edf50cSStefano Zampini   }
1473204aa523SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1474204aa523SStefano Zampini }
1475204aa523SStefano Zampini 
1476811d88abSStefano Zampini /* customize residuals and Jacobians */
SetupProblem(DM dm,AppCtx * ctx)1477811d88abSStefano Zampini static PetscErrorCode SetupProblem(DM dm, AppCtx *ctx)
1478811d88abSStefano Zampini {
1479811d88abSStefano Zampini   PetscDS     ds;
1480811d88abSStefano Zampini   PetscInt    cdim, dim;
1481811d88abSStefano Zampini   PetscScalar constants[NUM_CONSTANTS];
148266edf50cSStefano Zampini   PetscScalar vals[NUM_FIELDS];
148366edf50cSStefano Zampini   PetscInt    fields[NUM_FIELDS] = {C_FIELD_ID, P_FIELD_ID};
148466edf50cSStefano Zampini   Vec         dummy;
148566edf50cSStefano Zampini   IS          is;
1486811d88abSStefano Zampini 
1487811d88abSStefano Zampini   PetscFunctionBeginUser;
1488811d88abSStefano Zampini   constants[R_ID]     = ctx->r;
1489811d88abSStefano Zampini   constants[EPS_ID]   = ctx->eps;
1490811d88abSStefano Zampini   constants[ALPHA_ID] = ctx->alpha;
1491811d88abSStefano Zampini   constants[GAMMA_ID] = ctx->gamma;
1492811d88abSStefano Zampini   constants[D_ID]     = ctx->D;
1493204aa523SStefano Zampini   constants[FIXC_ID]  = ctx->fix_c;
149466edf50cSStefano Zampini   constants[SPLIT_ID] = ctx->split;
1495811d88abSStefano Zampini 
1496811d88abSStefano Zampini   PetscCall(DMGetDimension(dm, &dim));
1497811d88abSStefano Zampini   PetscCall(DMGetCoordinateDim(dm, &cdim));
149866edf50cSStefano Zampini   PetscCheck(dim == 2 || dim == 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Topological dimension must be 2 or 3");
149966edf50cSStefano Zampini   PetscCheck(dim == ctx->dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Topological dimension mismatch: expected %" PetscInt_FMT ", found %" PetscInt_FMT, dim, ctx->dim);
150066edf50cSStefano Zampini   PetscCheck(cdim == ctx->dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Geometrical dimension mismatch: expected %" PetscInt_FMT ", found %" PetscInt_FMT, cdim, ctx->dim);
1501811d88abSStefano Zampini   PetscCall(DMGetDS(dm, &ds));
1502811d88abSStefano Zampini   PetscCall(PetscDSSetConstants(ds, NUM_CONSTANTS, constants));
1503811d88abSStefano Zampini   PetscCall(PetscDSSetImplicit(ds, C_FIELD_ID, PETSC_TRUE));
1504811d88abSStefano Zampini   PetscCall(PetscDSSetImplicit(ds, P_FIELD_ID, PETSC_TRUE));
1505811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, energy));
1506811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, P_FIELD_ID, zero));
150766edf50cSStefano Zampini   if (ctx->dim == 2) {
1508811d88abSStefano Zampini     PetscCall(PetscDSSetResidual(ds, C_FIELD_ID, C_0, C_1));
1509811d88abSStefano Zampini     PetscCall(PetscDSSetResidual(ds, P_FIELD_ID, P_0, P_1));
151066edf50cSStefano Zampini     PetscCall(PetscDSSetJacobian(ds, C_FIELD_ID, C_FIELD_ID, JC_0_c0c0, NULL, NULL, ctx->D > 0 ? JC_1_c1c1 : NULL));
151166edf50cSStefano Zampini     if (!ctx->split) { /* we solve a block diagonal system to mimic operator splitting, jacobians will not be correct */
1512811d88abSStefano Zampini       PetscCall(PetscDSSetJacobian(ds, C_FIELD_ID, P_FIELD_ID, NULL, JC_0_c0p1, NULL, NULL));
1513811d88abSStefano Zampini       PetscCall(PetscDSSetJacobian(ds, P_FIELD_ID, C_FIELD_ID, NULL, NULL, JP_1_p1c0, NULL));
151466edf50cSStefano Zampini     }
1515811d88abSStefano Zampini     PetscCall(PetscDSSetJacobian(ds, P_FIELD_ID, P_FIELD_ID, NULL, NULL, NULL, JP_1_p1p1));
151666edf50cSStefano Zampini   } else {
151766edf50cSStefano Zampini     PetscCall(PetscDSSetResidual(ds, C_FIELD_ID, C_0_3d, C_1_3d));
151866edf50cSStefano Zampini     PetscCall(PetscDSSetResidual(ds, P_FIELD_ID, P_0, P_1_3d));
151966edf50cSStefano Zampini     PetscCall(PetscDSSetJacobian(ds, C_FIELD_ID, C_FIELD_ID, JC_0_c0c0_3d, NULL, NULL, ctx->D > 0 ? JC_1_c1c1_3d : NULL));
152066edf50cSStefano Zampini     if (!ctx->split) {
152166edf50cSStefano Zampini       PetscCall(PetscDSSetJacobian(ds, C_FIELD_ID, P_FIELD_ID, NULL, JC_0_c0p1_3d, NULL, NULL));
152266edf50cSStefano Zampini       PetscCall(PetscDSSetJacobian(ds, P_FIELD_ID, C_FIELD_ID, NULL, NULL, JP_1_p1c0_3d, NULL));
152366edf50cSStefano Zampini     }
152466edf50cSStefano Zampini     PetscCall(PetscDSSetJacobian(ds, P_FIELD_ID, P_FIELD_ID, NULL, NULL, NULL, JP_1_p1p1_3d));
152566edf50cSStefano Zampini   }
1526811d88abSStefano Zampini   /* Attach potential nullspace */
1527811d88abSStefano Zampini   PetscCall(DMSetNullSpaceConstructor(dm, P_FIELD_ID, CreatePotentialNullSpace));
1528811d88abSStefano Zampini 
152966edf50cSStefano Zampini   /* Compute domain volume */
153066edf50cSStefano Zampini   PetscCall(DMGetGlobalVector(dm, &dummy));
153166edf50cSStefano Zampini   PetscCall(PetscDSSetObjective(ds, P_FIELD_ID, volume));
153266edf50cSStefano Zampini   PetscCall(DMPlexComputeIntegralFEM(dm, dummy, vals, NULL));
153366edf50cSStefano Zampini   PetscCall(PetscDSSetObjective(ds, P_FIELD_ID, zero));
153466edf50cSStefano Zampini   PetscCall(DMRestoreGlobalVector(dm, &dummy));
153566edf50cSStefano Zampini   ctx->domain_volume = PetscRealPart(vals[P_FIELD_ID]);
153666edf50cSStefano Zampini 
153766edf50cSStefano Zampini   /* Index sets for potential and conductivities */
153866edf50cSStefano Zampini   PetscCall(DMCreateSubDM(dm, 1, fields, &is, NULL));
153966edf50cSStefano Zampini   PetscCall(PetscObjectCompose((PetscObject)dm, "IS conductivity", (PetscObject)is));
154066edf50cSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)is, "C"));
154166edf50cSStefano Zampini   PetscCall(ISViewFromOptions(is, NULL, "-is_conductivity_view"));
154266edf50cSStefano Zampini   PetscCall(ISDestroy(&is));
154366edf50cSStefano Zampini   PetscCall(DMCreateSubDM(dm, 1, fields + 1, &is, NULL));
154466edf50cSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)is, "P"));
154566edf50cSStefano Zampini   PetscCall(PetscObjectCompose((PetscObject)dm, "IS potential", (PetscObject)is));
154666edf50cSStefano Zampini   PetscCall(ISViewFromOptions(is, NULL, "-is_potential_view"));
154766edf50cSStefano Zampini   PetscCall(ISDestroy(&is));
154866edf50cSStefano Zampini 
154966edf50cSStefano Zampini   /* Create auxiliary DM */
155066edf50cSStefano Zampini   PetscCall(ProjectAuxDM(dm, PETSC_MIN_REAL, NULL, ctx));
1551811d88abSStefano Zampini 
1552811d88abSStefano Zampini   /* Add callbacks */
155366edf50cSStefano Zampini   PetscCall(DMTSSetIFunctionLocal(dm, DMPlexTSComputeIFunctionFEM_Private, ctx));
155466edf50cSStefano Zampini   PetscCall(DMTSSetIJacobianLocal(dm, DMPlexTSComputeIJacobianFEM_Private, ctx));
155566edf50cSStefano Zampini   /* DMPlexTSComputeBoundary is not needed because we use natural boundary conditions */
155666edf50cSStefano Zampini   PetscCall(DMTSSetBoundaryLocal(dm, NULL, NULL));
155766edf50cSStefano Zampini 
155866edf50cSStefano Zampini   /* handle nullspace in residual (move it to TSComputeIFunction_DMLocal?) */
155966edf50cSStefano Zampini   {
156066edf50cSStefano Zampini     MatNullSpace nullsp;
156166edf50cSStefano Zampini 
156266edf50cSStefano Zampini     PetscCall(CreatePotentialNullSpace(dm, P_FIELD_ID, P_FIELD_ID, &nullsp));
156366edf50cSStefano Zampini     PetscCall(PetscObjectCompose((PetscObject)dm, "__dmtsnullspace", (PetscObject)nullsp));
156466edf50cSStefano Zampini     PetscCall(MatNullSpaceDestroy(&nullsp));
1565204aa523SStefano Zampini   }
1566811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1567811d88abSStefano Zampini }
1568811d88abSStefano Zampini 
1569811d88abSStefano Zampini /* setup discrete spaces and residuals */
SetupDiscretization(DM dm,AppCtx * ctx)1570811d88abSStefano Zampini static PetscErrorCode SetupDiscretization(DM dm, AppCtx *ctx)
1571811d88abSStefano Zampini {
157266edf50cSStefano Zampini   DM       cdm = dm;
1573811d88abSStefano Zampini   PetscFE  feC, feP;
1574811d88abSStefano Zampini   PetscInt dim;
1575811d88abSStefano Zampini   MPI_Comm comm = PetscObjectComm((PetscObject)dm);
1576811d88abSStefano Zampini 
1577811d88abSStefano Zampini   PetscFunctionBeginUser;
1578811d88abSStefano Zampini   PetscCall(DMGetDimension(dm, &dim));
1579811d88abSStefano Zampini 
1580204aa523SStefano Zampini   /* We model Cij with Cij = Cji -> dim*(dim+1)/2 components */
158166edf50cSStefano Zampini   PetscCall(PetscFECreateDefault(comm, dim, (dim * (dim + 1)) / 2, ctx->simplex, "c_", -1, &feC));
1582811d88abSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)feC, "conductivity"));
158366edf50cSStefano Zampini   PetscCall(PetscFECreateDefault(comm, dim, 1, ctx->simplex, "p_", -1, &feP));
1584811d88abSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)feP, "potential"));
1585204aa523SStefano Zampini   PetscCall(PetscFECopyQuadrature(feP, feC));
158666edf50cSStefano Zampini   PetscCall(PetscFEViewFromOptions(feP, NULL, "-view_fe"));
158766edf50cSStefano Zampini   PetscCall(PetscFEViewFromOptions(feC, NULL, "-view_fe"));
1588811d88abSStefano Zampini 
1589811d88abSStefano Zampini   PetscCall(DMSetNumFields(dm, 2));
1590811d88abSStefano Zampini   PetscCall(DMSetField(dm, C_FIELD_ID, NULL, (PetscObject)feC));
1591811d88abSStefano Zampini   PetscCall(DMSetField(dm, P_FIELD_ID, NULL, (PetscObject)feP));
1592811d88abSStefano Zampini   PetscCall(PetscFEDestroy(&feC));
1593811d88abSStefano Zampini   PetscCall(PetscFEDestroy(&feP));
1594811d88abSStefano Zampini   PetscCall(DMCreateDS(dm));
1595811d88abSStefano Zampini   while (cdm) {
1596811d88abSStefano Zampini     PetscCall(DMCopyDisc(dm, cdm));
1597811d88abSStefano Zampini     PetscCall(SetupProblem(cdm, ctx));
1598811d88abSStefano Zampini     PetscCall(DMGetCoarseDM(cdm, &cdm));
1599811d88abSStefano Zampini   }
1600811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1601811d88abSStefano Zampini }
1602811d88abSStefano Zampini 
1603811d88abSStefano Zampini /* Create mesh by command line options */
CreateMesh(MPI_Comm comm,DM * dm,AppCtx * ctx)1604811d88abSStefano Zampini static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm, AppCtx *ctx)
1605811d88abSStefano Zampini {
160666edf50cSStefano Zampini   DM plex;
160766edf50cSStefano Zampini 
1608811d88abSStefano Zampini   PetscFunctionBeginUser;
1609811d88abSStefano Zampini   if (ctx->load) {
1610811d88abSStefano Zampini     PetscInt  refine = 0;
1611811d88abSStefano Zampini     PetscBool isHierarchy;
1612811d88abSStefano Zampini     DM       *dms;
1613811d88abSStefano Zampini     char      typeName[256];
1614811d88abSStefano Zampini     PetscBool flg;
1615811d88abSStefano Zampini 
1616811d88abSStefano Zampini     PetscCall(LoadFromFile(comm, ctx->load_filename, dm));
1617811d88abSStefano Zampini     PetscOptionsBegin(comm, "", "Additional mesh options", "DMPLEX");
1618811d88abSStefano Zampini     PetscCall(PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, MATAIJ, typeName, sizeof(typeName), &flg));
1619811d88abSStefano Zampini     if (flg) PetscCall(DMSetMatType(*dm, typeName));
1620811d88abSStefano Zampini     PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0));
1621811d88abSStefano Zampini     PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0));
1622811d88abSStefano Zampini     PetscOptionsEnd();
1623811d88abSStefano Zampini     if (refine) {
1624811d88abSStefano Zampini       PetscCall(SetupDiscretization(*dm, ctx));
1625811d88abSStefano Zampini       PetscCall(DMPlexSetRefinementUniform(*dm, PETSC_TRUE));
1626811d88abSStefano Zampini     }
1627811d88abSStefano Zampini     PetscCall(PetscCalloc1(refine, &dms));
1628811d88abSStefano Zampini     if (isHierarchy) PetscCall(DMRefineHierarchy(*dm, refine, dms));
1629811d88abSStefano Zampini     for (PetscInt r = 0; r < refine; r++) {
1630811d88abSStefano Zampini       Mat M;
1631811d88abSStefano Zampini       DM  dmr = dms[r];
1632811d88abSStefano Zampini       Vec u, ur;
1633811d88abSStefano Zampini 
1634811d88abSStefano Zampini       if (!isHierarchy) {
163555bffe1bSPierre Jolivet         PetscCall(DMRefine(*dm, PetscObjectComm((PetscObject)*dm), &dmr));
1636811d88abSStefano Zampini         PetscCall(DMSetCoarseDM(dmr, *dm));
1637811d88abSStefano Zampini       }
1638811d88abSStefano Zampini       PetscCall(DMCreateInterpolation(*dm, dmr, &M, NULL));
1639811d88abSStefano Zampini       PetscCall(DMGetNamedGlobalVector(*dm, "solution_", &u));
1640811d88abSStefano Zampini       PetscCall(DMGetNamedGlobalVector(dmr, "solution_", &ur));
1641811d88abSStefano Zampini       PetscCall(MatInterpolate(M, u, ur));
1642811d88abSStefano Zampini       PetscCall(DMRestoreNamedGlobalVector(*dm, "solution_", &u));
1643811d88abSStefano Zampini       PetscCall(DMRestoreNamedGlobalVector(dmr, "solution_", &ur));
1644811d88abSStefano Zampini       PetscCall(MatDestroy(&M));
1645811d88abSStefano Zampini       if (!isHierarchy) PetscCall(DMSetCoarseDM(dmr, NULL));
1646811d88abSStefano Zampini       PetscCall(DMDestroy(dm));
1647811d88abSStefano Zampini       *dm = dmr;
1648811d88abSStefano Zampini     }
1649811d88abSStefano Zampini     if (refine && !isHierarchy) PetscCall(DMSetRefineLevel(*dm, 0));
1650811d88abSStefano Zampini     PetscCall(PetscFree(dms));
1651811d88abSStefano Zampini   } else {
1652811d88abSStefano Zampini     PetscCall(DMCreate(comm, dm));
1653811d88abSStefano Zampini     PetscCall(DMSetType(*dm, DMPLEX));
1654811d88abSStefano Zampini     PetscCall(DMSetFromOptions(*dm));
1655811d88abSStefano Zampini     PetscCall(DMLocalizeCoordinates(*dm));
1656811d88abSStefano Zampini     {
1657811d88abSStefano Zampini       char      convType[256];
1658811d88abSStefano Zampini       PetscBool flg;
1659811d88abSStefano Zampini       PetscOptionsBegin(comm, "", "Additional mesh options", "DMPLEX");
1660811d88abSStefano Zampini       PetscCall(PetscOptionsFList("-dm_plex_convert_type", "Convert DMPlex to another format", __FILE__, DMList, DMPLEX, convType, 256, &flg));
1661811d88abSStefano Zampini       PetscOptionsEnd();
1662811d88abSStefano Zampini       if (flg) {
1663811d88abSStefano Zampini         DM dmConv;
1664811d88abSStefano Zampini         PetscCall(DMConvert(*dm, convType, &dmConv));
1665811d88abSStefano Zampini         if (dmConv) {
1666811d88abSStefano Zampini           PetscCall(DMDestroy(dm));
1667811d88abSStefano Zampini           *dm = dmConv;
1668811d88abSStefano Zampini           PetscCall(DMSetFromOptions(*dm));
1669811d88abSStefano Zampini           PetscCall(DMSetUp(*dm));
1670811d88abSStefano Zampini         }
1671811d88abSStefano Zampini       }
1672811d88abSStefano Zampini     }
1673811d88abSStefano Zampini   }
167466edf50cSStefano Zampini   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, "ref_"));
167566edf50cSStefano Zampini   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
167666edf50cSStefano Zampini   PetscCall(DMSetFromOptions(*dm));
167766edf50cSStefano Zampini   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, NULL));
167866edf50cSStefano Zampini 
167966edf50cSStefano Zampini   PetscCall(DMConvert(*dm, DMPLEX, &plex));
168066edf50cSStefano Zampini   PetscCall(DMPlexIsSimplex(plex, &ctx->simplex));
16815440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &ctx->simplex, 1, MPI_C_BOOL, MPI_LOR, comm));
168266edf50cSStefano Zampini   PetscCall(DMDestroy(&plex));
168366edf50cSStefano Zampini 
1684811d88abSStefano Zampini   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
1685811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1686811d88abSStefano Zampini }
1687811d88abSStefano Zampini 
1688811d88abSStefano Zampini /* Make potential field zero mean */
ZeroMeanPotential(DM dm,Vec u,PetscScalar domain_volume)168966edf50cSStefano Zampini static PetscErrorCode ZeroMeanPotential(DM dm, Vec u, PetscScalar domain_volume)
1690811d88abSStefano Zampini {
1691811d88abSStefano Zampini   PetscScalar vals[NUM_FIELDS];
1692811d88abSStefano Zampini   PetscDS     ds;
1693811d88abSStefano Zampini   IS          is;
1694811d88abSStefano Zampini 
1695811d88abSStefano Zampini   PetscFunctionBeginUser;
1696811d88abSStefano Zampini   PetscCall(PetscObjectQuery((PetscObject)dm, "IS potential", (PetscObject *)&is));
1697811d88abSStefano Zampini   PetscCheck(is, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing potential IS");
1698811d88abSStefano Zampini   PetscCall(DMGetDS(dm, &ds));
1699811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, P_FIELD_ID, average));
1700811d88abSStefano Zampini   PetscCall(DMPlexComputeIntegralFEM(dm, u, vals, NULL));
1701811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, P_FIELD_ID, zero));
170266edf50cSStefano Zampini   PetscCall(VecISShift(u, is, -vals[P_FIELD_ID] / domain_volume));
1703811d88abSStefano Zampini   PetscCall(DMPlexComputeIntegralFEM(dm, u, vals, NULL));
1704811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1705811d88abSStefano Zampini }
1706811d88abSStefano Zampini 
1707811d88abSStefano Zampini /* Compute initial conditions and exclude potential from local truncation error
1708811d88abSStefano Zampini    Since we are solving a DAE, once the initial conditions for the differential
1709811d88abSStefano Zampini    variables are set, we need to compute the corresponding value for the
1710811d88abSStefano Zampini    algebraic variables. We do so by creating a subDM for the potential only
1711811d88abSStefano Zampini    and solve a static problem with SNES */
SetInitialConditionsAndTolerances(TS ts,PetscInt nv,Vec vecs[],PetscBool valid)1712811d88abSStefano Zampini static PetscErrorCode SetInitialConditionsAndTolerances(TS ts, PetscInt nv, Vec vecs[], PetscBool valid)
1713811d88abSStefano Zampini {
1714811d88abSStefano Zampini   DM         dm;
171566edf50cSStefano Zampini   Vec        u, p, subaux, vatol, vrtol;
1716811d88abSStefano Zampini   PetscReal  t, atol, rtol;
1717811d88abSStefano Zampini   PetscInt   fields[NUM_FIELDS] = {C_FIELD_ID, P_FIELD_ID};
1718811d88abSStefano Zampini   IS         isp;
1719811d88abSStefano Zampini   DM         dmp;
1720811d88abSStefano Zampini   VecScatter sctp = NULL;
1721811d88abSStefano Zampini   PetscDS    ds;
1722811d88abSStefano Zampini   SNES       snes;
1723811d88abSStefano Zampini   KSP        ksp;
1724811d88abSStefano Zampini   PC         pc;
1725811d88abSStefano Zampini   AppCtx    *ctx;
1726811d88abSStefano Zampini 
1727811d88abSStefano Zampini   PetscFunctionBeginUser;
1728811d88abSStefano Zampini   PetscCall(TSGetDM(ts, &dm));
1729811d88abSStefano Zampini   PetscCall(TSGetApplicationContext(ts, &ctx));
173066edf50cSStefano Zampini   PetscCall(PetscObjectQuery((PetscObject)dm, "IS potential", (PetscObject *)&isp));
173166edf50cSStefano Zampini   PetscCheck(isp, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing potential IS");
1732204aa523SStefano Zampini   if (valid) {
173366edf50cSStefano Zampini     if (ctx->exclude_potential_lte) {
1734811d88abSStefano Zampini       PetscCall(DMCreateGlobalVector(dm, &vatol));
1735811d88abSStefano Zampini       PetscCall(DMCreateGlobalVector(dm, &vrtol));
1736811d88abSStefano Zampini       PetscCall(TSGetTolerances(ts, &atol, NULL, &rtol, NULL));
1737811d88abSStefano Zampini       PetscCall(VecSet(vatol, atol));
1738811d88abSStefano Zampini       PetscCall(VecISSet(vatol, isp, -1));
1739811d88abSStefano Zampini       PetscCall(VecSet(vrtol, rtol));
1740811d88abSStefano Zampini       PetscCall(VecISSet(vrtol, isp, -1));
1741811d88abSStefano Zampini       PetscCall(TSSetTolerances(ts, atol, vatol, rtol, vrtol));
1742811d88abSStefano Zampini       PetscCall(VecDestroy(&vatol));
1743811d88abSStefano Zampini       PetscCall(VecDestroy(&vrtol));
174466edf50cSStefano Zampini     }
174566edf50cSStefano Zampini     for (PetscInt i = 0; i < nv; i++) PetscCall(ZeroMeanPotential(dm, vecs[i], ctx->domain_volume));
1746811d88abSStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
1747811d88abSStefano Zampini   }
174866edf50cSStefano Zampini   PetscCall(DMCreateSubDM(dm, 1, fields + 1, NULL, &dmp));
1749811d88abSStefano Zampini   PetscCall(DMSetMatType(dmp, MATAIJ));
1750811d88abSStefano Zampini   PetscCall(DMGetDS(dmp, &ds));
175166edf50cSStefano Zampini   if (ctx->dim == 2) {
175266edf50cSStefano Zampini     PetscCall(PetscDSSetResidual(ds, 0, P_0_aux, P_1_aux));
1753811d88abSStefano Zampini     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, JP_1_p1p1_aux));
175466edf50cSStefano Zampini   } else {
175566edf50cSStefano Zampini     PetscCall(PetscDSSetResidual(ds, 0, P_0_aux, P_1_aux_3d));
175666edf50cSStefano Zampini     PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, JP_1_p1p1_aux_3d));
175766edf50cSStefano Zampini   }
1758811d88abSStefano Zampini   PetscCall(DMPlexSetSNESLocalFEM(dmp, PETSC_FALSE, NULL));
1759811d88abSStefano Zampini 
1760811d88abSStefano Zampini   PetscCall(DMCreateGlobalVector(dmp, &p));
1761811d88abSStefano Zampini 
1762811d88abSStefano Zampini   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dmp), &snes));
1763811d88abSStefano Zampini   PetscCall(SNESSetDM(snes, dmp));
1764811d88abSStefano Zampini   PetscCall(SNESSetOptionsPrefix(snes, "initial_"));
1765811d88abSStefano Zampini   PetscCall(SNESSetErrorIfNotConverged(snes, PETSC_TRUE));
1766811d88abSStefano Zampini   PetscCall(SNESGetKSP(snes, &ksp));
1767204aa523SStefano Zampini   PetscCall(KSPSetType(ksp, KSPFGMRES));
1768811d88abSStefano Zampini   PetscCall(KSPGetPC(ksp, &pc));
1769811d88abSStefano Zampini   PetscCall(PCSetType(pc, PCGAMG));
1770811d88abSStefano Zampini   PetscCall(SNESSetFromOptions(snes));
1771811d88abSStefano Zampini   PetscCall(SNESSetUp(snes));
1772811d88abSStefano Zampini 
1773811d88abSStefano Zampini   /* Loop over input vectors and compute corresponding potential */
1774811d88abSStefano Zampini   for (PetscInt i = 0; i < nv; i++) {
1775811d88abSStefano Zampini     u = vecs[i];
1776811d88abSStefano Zampini     if (!valid) { /* Assumes entries in u are not valid */
177766edf50cSStefano Zampini       PetscErrorCode (*funcs[NUM_FIELDS])(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *);
177866edf50cSStefano Zampini       void       *ctxs[NUM_FIELDS] = {NULL};
177966edf50cSStefano Zampini       PetscRandom r                = NULL;
178066edf50cSStefano Zampini 
1781811d88abSStefano Zampini       PetscCall(TSGetTime(ts, &t));
1782811d88abSStefano Zampini       switch (ctx->ic_num) {
1783811d88abSStefano Zampini       case 0:
1784811d88abSStefano Zampini         funcs[C_FIELD_ID] = initial_conditions_C_0;
1785811d88abSStefano Zampini         break;
1786811d88abSStefano Zampini       case 1:
1787811d88abSStefano Zampini         funcs[C_FIELD_ID] = initial_conditions_C_1;
1788811d88abSStefano Zampini         break;
1789811d88abSStefano Zampini       case 2:
1790811d88abSStefano Zampini         funcs[C_FIELD_ID] = initial_conditions_C_2;
1791811d88abSStefano Zampini         break;
179266edf50cSStefano Zampini       case 3:
179366edf50cSStefano Zampini         funcs[C_FIELD_ID] = initial_conditions_C_random;
179466edf50cSStefano Zampini         PetscCall(PetscRandomCreate(PetscObjectComm((PetscObject)ts), &r));
179566edf50cSStefano Zampini         PetscCall(PetscRandomSetOptionsPrefix(r, "ic_"));
179666edf50cSStefano Zampini         PetscCall(PetscRandomSetFromOptions(r));
179766edf50cSStefano Zampini         ctxs[C_FIELD_ID] = r;
179866edf50cSStefano Zampini         break;
1799811d88abSStefano Zampini       default:
1800d8b4a066SPierre Jolivet         SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Unknown IC");
1801811d88abSStefano Zampini       }
1802811d88abSStefano Zampini       funcs[P_FIELD_ID] = zerof;
180366edf50cSStefano Zampini       PetscCall(DMProjectFunction(dm, t, funcs, ctxs, INSERT_ALL_VALUES, u));
180466edf50cSStefano Zampini       PetscCall(ProjectAuxDM(dm, t, u, ctx));
180566edf50cSStefano Zampini       PetscCall(PetscRandomDestroy(&r));
1806811d88abSStefano Zampini     }
1807811d88abSStefano Zampini 
180866edf50cSStefano Zampini     /* pass conductivity information via auxiliary data */
180966edf50cSStefano Zampini     PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &subaux));
1810811d88abSStefano Zampini     PetscCall(DMSetAuxiliaryVec(dmp, NULL, 0, 0, subaux));
1811811d88abSStefano Zampini 
1812811d88abSStefano Zampini     /* solve the subproblem */
1813811d88abSStefano Zampini     if (!sctp) PetscCall(VecScatterCreate(u, isp, p, NULL, &sctp));
1814811d88abSStefano Zampini     PetscCall(VecScatterBegin(sctp, u, p, INSERT_VALUES, SCATTER_FORWARD));
1815811d88abSStefano Zampini     PetscCall(VecScatterEnd(sctp, u, p, INSERT_VALUES, SCATTER_FORWARD));
1816811d88abSStefano Zampini     PetscCall(SNESSolve(snes, NULL, p));
1817811d88abSStefano Zampini 
1818811d88abSStefano Zampini     /* scatter from potential only to full space */
1819811d88abSStefano Zampini     PetscCall(VecScatterBegin(sctp, p, u, INSERT_VALUES, SCATTER_REVERSE));
1820811d88abSStefano Zampini     PetscCall(VecScatterEnd(sctp, p, u, INSERT_VALUES, SCATTER_REVERSE));
182166edf50cSStefano Zampini     PetscCall(ZeroMeanPotential(dm, u, ctx->domain_volume));
1822811d88abSStefano Zampini   }
1823811d88abSStefano Zampini   PetscCall(VecDestroy(&p));
1824811d88abSStefano Zampini   PetscCall(DMDestroy(&dmp));
1825811d88abSStefano Zampini   PetscCall(SNESDestroy(&snes));
1826811d88abSStefano Zampini   PetscCall(VecScatterDestroy(&sctp));
1827811d88abSStefano Zampini 
1828811d88abSStefano Zampini   /* exclude potential from computation of the LTE */
182966edf50cSStefano Zampini   if (ctx->exclude_potential_lte) {
1830811d88abSStefano Zampini     PetscCall(DMCreateGlobalVector(dm, &vatol));
1831811d88abSStefano Zampini     PetscCall(DMCreateGlobalVector(dm, &vrtol));
1832811d88abSStefano Zampini     PetscCall(TSGetTolerances(ts, &atol, NULL, &rtol, NULL));
1833811d88abSStefano Zampini     PetscCall(VecSet(vatol, atol));
1834811d88abSStefano Zampini     PetscCall(VecISSet(vatol, isp, -1));
1835811d88abSStefano Zampini     PetscCall(VecSet(vrtol, rtol));
1836811d88abSStefano Zampini     PetscCall(VecISSet(vrtol, isp, -1));
1837811d88abSStefano Zampini     PetscCall(TSSetTolerances(ts, atol, vatol, rtol, vrtol));
1838811d88abSStefano Zampini     PetscCall(VecDestroy(&vatol));
1839811d88abSStefano Zampini     PetscCall(VecDestroy(&vrtol));
184066edf50cSStefano Zampini   }
1841811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1842811d88abSStefano Zampini }
1843811d88abSStefano Zampini 
1844811d88abSStefano Zampini /* mesh adaption context */
1845811d88abSStefano Zampini typedef struct {
1846811d88abSStefano Zampini   VecTagger refineTag;
1847811d88abSStefano Zampini   DMLabel   adaptLabel;
1848811d88abSStefano Zampini   PetscInt  cnt;
1849811d88abSStefano Zampini } AdaptCtx;
1850811d88abSStefano Zampini 
ResizeSetUp(TS ts,PetscInt nstep,PetscReal time,Vec u,PetscBool * resize,void * vctx)1851811d88abSStefano Zampini static PetscErrorCode ResizeSetUp(TS ts, PetscInt nstep, PetscReal time, Vec u, PetscBool *resize, void *vctx)
1852811d88abSStefano Zampini {
1853811d88abSStefano Zampini   AdaptCtx *ctx = (AdaptCtx *)vctx;
1854811d88abSStefano Zampini   Vec       ellVecCells, ellVecCellsF;
1855811d88abSStefano Zampini   DM        dm, plex;
1856811d88abSStefano Zampini   PetscDS   ds;
1857811d88abSStefano Zampini   PetscReal norm;
1858811d88abSStefano Zampini   PetscInt  cStart, cEnd;
1859811d88abSStefano Zampini 
1860811d88abSStefano Zampini   PetscFunctionBeginUser;
1861811d88abSStefano Zampini   PetscCall(TSGetDM(ts, &dm));
1862811d88abSStefano Zampini   PetscCall(DMConvert(dm, DMPLEX, &plex));
1863811d88abSStefano Zampini   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
1864811d88abSStefano Zampini   PetscCall(DMDestroy(&plex));
1865811d88abSStefano Zampini   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)ts), NUM_FIELDS * (cEnd - cStart), PETSC_DECIDE, &ellVecCellsF));
1866811d88abSStefano Zampini   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)ts), cEnd - cStart, PETSC_DECIDE, &ellVecCells));
1867811d88abSStefano Zampini   PetscCall(VecSetBlockSize(ellVecCellsF, NUM_FIELDS));
1868811d88abSStefano Zampini   PetscCall(DMGetDS(dm, &ds));
1869811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, ellipticity_fail));
1870811d88abSStefano Zampini   PetscCall(DMPlexComputeCellwiseIntegralFEM(dm, u, ellVecCellsF, NULL));
1871811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, energy));
1872811d88abSStefano Zampini   PetscCall(VecStrideGather(ellVecCellsF, C_FIELD_ID, ellVecCells, INSERT_VALUES));
1873811d88abSStefano Zampini   PetscCall(VecDestroy(&ellVecCellsF));
1874811d88abSStefano Zampini   PetscCall(VecNorm(ellVecCells, NORM_1, &norm));
1875811d88abSStefano Zampini   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "STEP %d norm %g\n", (int)nstep, (double)norm));
1876811d88abSStefano Zampini   if (norm && !ctx->cnt) {
1877811d88abSStefano Zampini     IS refineIS;
1878811d88abSStefano Zampini 
1879811d88abSStefano Zampini     *resize = PETSC_TRUE;
1880811d88abSStefano Zampini     if (!ctx->refineTag) {
1881811d88abSStefano Zampini       VecTaggerBox refineBox;
1882811d88abSStefano Zampini       refineBox.min = PETSC_MACHINE_EPSILON;
1883811d88abSStefano Zampini       refineBox.max = PETSC_MAX_REAL;
1884811d88abSStefano Zampini 
1885811d88abSStefano Zampini       PetscCall(VecTaggerCreate(PETSC_COMM_SELF, &ctx->refineTag));
1886811d88abSStefano Zampini       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)ctx->refineTag, "refine_"));
1887811d88abSStefano Zampini       PetscCall(VecTaggerSetType(ctx->refineTag, VECTAGGERABSOLUTE));
1888811d88abSStefano Zampini       PetscCall(VecTaggerAbsoluteSetBox(ctx->refineTag, &refineBox));
1889811d88abSStefano Zampini       PetscCall(VecTaggerSetFromOptions(ctx->refineTag));
1890811d88abSStefano Zampini       PetscCall(VecTaggerSetUp(ctx->refineTag));
1891811d88abSStefano Zampini       PetscCall(PetscObjectViewFromOptions((PetscObject)ctx->refineTag, NULL, "-tag_view"));
1892811d88abSStefano Zampini     }
1893811d88abSStefano Zampini     PetscCall(DMLabelDestroy(&ctx->adaptLabel));
1894811d88abSStefano Zampini     PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)ts), "adapt", &ctx->adaptLabel));
1895811d88abSStefano Zampini     PetscCall(VecTaggerComputeIS(ctx->refineTag, ellVecCells, &refineIS, NULL));
1896811d88abSStefano Zampini     PetscCall(DMLabelSetStratumIS(ctx->adaptLabel, DM_ADAPT_REFINE, refineIS));
1897811d88abSStefano Zampini     PetscCall(ISDestroy(&refineIS));
1898811d88abSStefano Zampini #if 0
1899811d88abSStefano Zampini     void (*funcs[NUM_FIELDS])(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
1900811d88abSStefano Zampini     Vec ellVec;
1901811d88abSStefano Zampini 
1902811d88abSStefano Zampini     funcs[P_FIELD_ID] = ellipticity_fail;
1903811d88abSStefano Zampini     funcs[C_FIELD_ID] = NULL;
1904811d88abSStefano Zampini 
1905811d88abSStefano Zampini     PetscCall(DMGetGlobalVector(dm, &ellVec));
1906811d88abSStefano Zampini     PetscCall(DMProjectField(dm, 0, u, funcs, INSERT_VALUES, ellVec));
1907811d88abSStefano Zampini     PetscCall(VecViewFromOptions(ellVec,NULL,"-view_amr_ell"));
1908811d88abSStefano Zampini     PetscCall(DMRestoreGlobalVector(dm, &ellVec));
1909811d88abSStefano Zampini #endif
1910811d88abSStefano Zampini     ctx->cnt++;
1911811d88abSStefano Zampini   } else {
1912811d88abSStefano Zampini     ctx->cnt = 0;
1913811d88abSStefano Zampini   }
1914811d88abSStefano Zampini   PetscCall(VecDestroy(&ellVecCells));
1915811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1916811d88abSStefano Zampini }
1917811d88abSStefano Zampini 
ResizeTransfer(TS ts,PetscInt nv,Vec vecsin[],Vec vecsout[],void * vctx)1918811d88abSStefano Zampini static PetscErrorCode ResizeTransfer(TS ts, PetscInt nv, Vec vecsin[], Vec vecsout[], void *vctx)
1919811d88abSStefano Zampini {
1920811d88abSStefano Zampini   AdaptCtx *actx = (AdaptCtx *)vctx;
1921811d88abSStefano Zampini   AppCtx   *ctx;
1922811d88abSStefano Zampini   DM        dm, adm;
1923811d88abSStefano Zampini   PetscReal time;
192466edf50cSStefano Zampini   PetscInt  fields[NUM_FIELDS] = {C_FIELD_ID, P_FIELD_ID};
192566edf50cSStefano Zampini   IS        is;
1926811d88abSStefano Zampini 
1927811d88abSStefano Zampini   PetscFunctionBeginUser;
1928811d88abSStefano Zampini   PetscCall(TSGetDM(ts, &dm));
1929811d88abSStefano Zampini   PetscCheck(actx->adaptLabel, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "Missing adaptLabel");
1930811d88abSStefano Zampini   PetscCall(DMAdaptLabel(dm, actx->adaptLabel, &adm));
1931811d88abSStefano Zampini   PetscCheck(adm, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "Missing adapted DM");
1932811d88abSStefano Zampini   PetscCall(TSGetTime(ts, &time));
1933811d88abSStefano Zampini   PetscCall(DMLabelDestroy(&actx->adaptLabel));
1934811d88abSStefano Zampini   for (PetscInt i = 0; i < nv; i++) {
1935811d88abSStefano Zampini     PetscCall(DMCreateGlobalVector(adm, &vecsout[i]));
1936811d88abSStefano Zampini     PetscCall(DMForestTransferVec(dm, vecsin[i], adm, vecsout[i], PETSC_TRUE, time));
1937811d88abSStefano Zampini   }
1938811d88abSStefano Zampini   PetscCall(DMForestSetAdaptivityForest(adm, NULL));
1939811d88abSStefano Zampini   PetscCall(DMSetCoarseDM(adm, NULL));
1940811d88abSStefano Zampini   PetscCall(DMSetLocalSection(adm, NULL));
1941811d88abSStefano Zampini   PetscCall(TSSetDM(ts, adm));
1942811d88abSStefano Zampini   PetscCall(TSGetTime(ts, &time));
1943811d88abSStefano Zampini   PetscCall(TSGetApplicationContext(ts, &ctx));
1944204aa523SStefano Zampini   PetscCall(DMSetNullSpaceConstructor(adm, P_FIELD_ID, CreatePotentialNullSpace));
194566edf50cSStefano Zampini   PetscCall(DMCreateSubDM(adm, 1, fields, &is, NULL));
194666edf50cSStefano Zampini   PetscCall(PetscObjectCompose((PetscObject)adm, "IS conductivity", (PetscObject)is));
194766edf50cSStefano Zampini   PetscCall(ISDestroy(&is));
194866edf50cSStefano Zampini   PetscCall(DMCreateSubDM(adm, 1, fields + 1, &is, NULL));
194966edf50cSStefano Zampini   PetscCall(PetscObjectCompose((PetscObject)adm, "IS potential", (PetscObject)is));
195066edf50cSStefano Zampini   PetscCall(ISDestroy(&is));
195166edf50cSStefano Zampini   PetscCall(ProjectAuxDM(adm, time, NULL, ctx));
195266edf50cSStefano Zampini   {
195366edf50cSStefano Zampini     MatNullSpace nullsp;
195466edf50cSStefano Zampini 
195566edf50cSStefano Zampini     PetscCall(CreatePotentialNullSpace(adm, P_FIELD_ID, P_FIELD_ID, &nullsp));
195666edf50cSStefano Zampini     PetscCall(PetscObjectCompose((PetscObject)adm, "__dmtsnullspace", (PetscObject)nullsp));
195766edf50cSStefano Zampini     PetscCall(MatNullSpaceDestroy(&nullsp));
195866edf50cSStefano Zampini   }
1959811d88abSStefano Zampini   PetscCall(SetInitialConditionsAndTolerances(ts, nv, vecsout, PETSC_TRUE));
196066edf50cSStefano Zampini   PetscCall(DMDestroy(&ctx->view_dm));
196166edf50cSStefano Zampini   for (PetscInt i = 0; i < NUM_FIELDS; i++) {
196266edf50cSStefano Zampini     PetscCall(VecScatterDestroy(&ctx->subsct[i]));
196366edf50cSStefano Zampini     PetscCall(VecDestroy(&ctx->subvec[i]));
196466edf50cSStefano Zampini   }
1965811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1966811d88abSStefano Zampini }
1967811d88abSStefano Zampini 
ComputeDiagnostic(Vec u,AppCtx * ctx,Vec * out)196866edf50cSStefano Zampini static PetscErrorCode ComputeDiagnostic(Vec u, AppCtx *ctx, Vec *out)
1969811d88abSStefano Zampini {
197066edf50cSStefano Zampini   DM       dm;
197166edf50cSStefano Zampini   PetscInt dim;
197266edf50cSStefano Zampini   PetscFE  feFluxC, feNormC, feEigsC;
197366edf50cSStefano Zampini 
197466edf50cSStefano Zampini   void (*funcs[])(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]) = {normc, eigsc, flux};
197566edf50cSStefano Zampini 
1976811d88abSStefano Zampini   PetscFunctionBeginUser;
197766edf50cSStefano Zampini   if (!ctx->view_dm) {
197866edf50cSStefano Zampini     PetscFE  feP;
197966edf50cSStefano Zampini     PetscInt nf = PetscMax(PetscMin(ctx->diagnostic_num, 3), 1);
198066edf50cSStefano Zampini 
198166edf50cSStefano Zampini     PetscCall(VecGetDM(u, &dm));
198266edf50cSStefano Zampini     PetscCall(DMGetDimension(dm, &dim));
198366edf50cSStefano Zampini     PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dm), dim, 1, ctx->simplex, "normc_", -1, &feNormC));
198466edf50cSStefano Zampini     PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dm), dim, dim, ctx->simplex, "eigsc_", -1, &feEigsC));
198566edf50cSStefano Zampini     PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dm), dim, dim, ctx->simplex, "flux_", -1, &feFluxC));
198666edf50cSStefano Zampini     PetscCall(DMGetField(dm, P_FIELD_ID, NULL, (PetscObject *)&feP));
198766edf50cSStefano Zampini     PetscCall(PetscFECopyQuadrature(feP, feNormC));
198866edf50cSStefano Zampini     PetscCall(PetscFECopyQuadrature(feP, feEigsC));
198966edf50cSStefano Zampini     PetscCall(PetscFECopyQuadrature(feP, feFluxC));
199066edf50cSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)feNormC, "normC"));
199166edf50cSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)feEigsC, "eigsC"));
199266edf50cSStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)feFluxC, "flux"));
199366edf50cSStefano Zampini 
199466edf50cSStefano Zampini     PetscCall(DMClone(dm, &ctx->view_dm));
199566edf50cSStefano Zampini     PetscCall(DMSetNumFields(ctx->view_dm, nf));
199666edf50cSStefano Zampini     PetscCall(DMSetField(ctx->view_dm, 0, NULL, (PetscObject)feNormC));
199766edf50cSStefano Zampini     if (nf > 1) PetscCall(DMSetField(ctx->view_dm, 1, NULL, (PetscObject)feEigsC));
199866edf50cSStefano Zampini     if (nf > 2) PetscCall(DMSetField(ctx->view_dm, 2, NULL, (PetscObject)feFluxC));
199966edf50cSStefano Zampini     PetscCall(DMCreateDS(ctx->view_dm));
200066edf50cSStefano Zampini     PetscCall(PetscFEDestroy(&feFluxC));
200166edf50cSStefano Zampini     PetscCall(PetscFEDestroy(&feNormC));
200266edf50cSStefano Zampini     PetscCall(PetscFEDestroy(&feEigsC));
200366edf50cSStefano Zampini   }
200466edf50cSStefano Zampini   PetscCall(DMCreateGlobalVector(ctx->view_dm, out));
200566edf50cSStefano Zampini   PetscCall(DMProjectField(ctx->view_dm, 0.0, u, funcs, INSERT_VALUES, *out));
200666edf50cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
200766edf50cSStefano Zampini }
200866edf50cSStefano Zampini 
MakeScatterAndVec(Vec X,IS is,Vec * Y,VecScatter * sct)200966edf50cSStefano Zampini static PetscErrorCode MakeScatterAndVec(Vec X, IS is, Vec *Y, VecScatter *sct)
201066edf50cSStefano Zampini {
201166edf50cSStefano Zampini   PetscInt n;
201266edf50cSStefano Zampini 
201366edf50cSStefano Zampini   PetscFunctionBeginUser;
201466edf50cSStefano Zampini   PetscCall(ISGetLocalSize(is, &n));
201566edf50cSStefano Zampini   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)X), n, PETSC_DECIDE, Y));
201666edf50cSStefano Zampini   PetscCall(VecScatterCreate(X, is, *Y, NULL, sct));
201766edf50cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
201866edf50cSStefano Zampini }
201966edf50cSStefano Zampini 
FunctionDomainError(TS ts,PetscReal time,Vec X,PetscBool * accept)202066edf50cSStefano Zampini static PetscErrorCode FunctionDomainError(TS ts, PetscReal time, Vec X, PetscBool *accept)
202166edf50cSStefano Zampini {
202266edf50cSStefano Zampini   AppCtx     *ctx;
202366edf50cSStefano Zampini   PetscScalar vals[NUM_FIELDS];
202466edf50cSStefano Zampini   DM          dm;
202566edf50cSStefano Zampini   PetscDS     ds;
202666edf50cSStefano Zampini 
202766edf50cSStefano Zampini   PetscFunctionBeginUser;
202866edf50cSStefano Zampini   *accept = PETSC_TRUE;
202966edf50cSStefano Zampini   PetscCall(TSGetApplicationContext(ts, &ctx));
203066edf50cSStefano Zampini   if (ctx->function_domain_error_tol < 0) PetscFunctionReturn(PETSC_SUCCESS);
203166edf50cSStefano Zampini   PetscCall(TSGetDM(ts, &dm));
203266edf50cSStefano Zampini   PetscCall(DMGetDS(dm, &ds));
203366edf50cSStefano Zampini   PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, ellipticity_fail));
203466edf50cSStefano Zampini   PetscCall(DMPlexComputeIntegralFEM(dm, X, vals, NULL));
203566edf50cSStefano Zampini   PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, energy));
203666edf50cSStefano Zampini   if (PetscAbsScalar(vals[C_FIELD_ID]) > ctx->function_domain_error_tol) *accept = PETSC_FALSE;
203766edf50cSStefano Zampini   if (!*accept) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "Domain error value %g > %g\n", (double)PetscAbsScalar(vals[C_FIELD_ID]), (double)ctx->function_domain_error_tol));
2038811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2039811d88abSStefano Zampini }
2040811d88abSStefano Zampini 
2041811d88abSStefano Zampini /* Monitor relevant functionals */
Monitor(TS ts,PetscInt stepnum,PetscReal time,Vec u,void * vctx)2042811d88abSStefano Zampini static PetscErrorCode Monitor(TS ts, PetscInt stepnum, PetscReal time, Vec u, void *vctx)
2043811d88abSStefano Zampini {
2044811d88abSStefano Zampini   PetscScalar vals[2 * NUM_FIELDS];
2045811d88abSStefano Zampini   DM          dm;
2046811d88abSStefano Zampini   PetscDS     ds;
2047811d88abSStefano Zampini   AppCtx     *ctx;
204866edf50cSStefano Zampini   PetscBool   need_hdf5, need_vtk;
2049811d88abSStefano Zampini 
2050811d88abSStefano Zampini   PetscFunctionBeginUser;
2051811d88abSStefano Zampini   PetscCall(TSGetDM(ts, &dm));
2052811d88abSStefano Zampini   PetscCall(TSGetApplicationContext(ts, &ctx));
2053811d88abSStefano Zampini   PetscCall(DMGetDS(dm, &ds));
2054811d88abSStefano Zampini 
2055811d88abSStefano Zampini   /* monitor energy and potential average */
2056811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, P_FIELD_ID, average));
2057811d88abSStefano Zampini   PetscCall(DMPlexComputeIntegralFEM(dm, u, vals, NULL));
2058811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, P_FIELD_ID, zero));
2059811d88abSStefano Zampini 
2060811d88abSStefano Zampini   /* monitor ellipticity_fail */
2061811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, ellipticity_fail));
2062811d88abSStefano Zampini   PetscCall(DMPlexComputeIntegralFEM(dm, u, vals + NUM_FIELDS, NULL));
2063811d88abSStefano Zampini   PetscCall(PetscDSSetObjective(ds, C_FIELD_ID, energy));
206466edf50cSStefano Zampini   vals[C_FIELD_ID] /= ctx->domain_volume;
2065811d88abSStefano Zampini 
2066811d88abSStefano Zampini   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "%4" PetscInt_FMT " TS: time %g, energy %g, intp %g, ell %g\n", stepnum, (double)time, (double)PetscRealPart(vals[C_FIELD_ID]), (double)PetscRealPart(vals[P_FIELD_ID]), (double)PetscRealPart(vals[NUM_FIELDS + C_FIELD_ID])));
206766edf50cSStefano Zampini 
206866edf50cSStefano Zampini   /* monitor diagnostic */
206966edf50cSStefano Zampini   need_hdf5 = (PetscBool)(ctx->view_hdf5_ctx && ((ctx->view_hdf5_ctx->view_interval > 0 && !(stepnum % ctx->view_hdf5_ctx->view_interval)) || (ctx->view_hdf5_ctx->view_interval && ts->reason)));
207066edf50cSStefano Zampini   need_vtk  = (PetscBool)(ctx->view_vtk_ctx && ((ctx->view_vtk_ctx->interval > 0 && !(stepnum % ctx->view_vtk_ctx->interval)) || (ctx->view_vtk_ctx->interval && ts->reason)));
207166edf50cSStefano Zampini   if (ctx->view_times_k < ctx->view_times_n && time >= ctx->view_times[ctx->view_times_k] && time < ctx->view_times[ctx->view_times_k + 1]) {
207266edf50cSStefano Zampini     if (ctx->view_hdf5_ctx) need_hdf5 = PETSC_TRUE;
207366edf50cSStefano Zampini     if (ctx->view_vtk_ctx) need_vtk = PETSC_TRUE;
207466edf50cSStefano Zampini     ctx->view_times_k++;
207566edf50cSStefano Zampini   }
207666edf50cSStefano Zampini   if (need_vtk || need_hdf5) {
207766edf50cSStefano Zampini     Vec       diagnostic;
207866edf50cSStefano Zampini     PetscBool dump_dm = (PetscBool)(!!ctx->view_dm);
207966edf50cSStefano Zampini 
208066edf50cSStefano Zampini     PetscCall(ComputeDiagnostic(u, ctx, &diagnostic));
208166edf50cSStefano Zampini     if (need_vtk) {
208266edf50cSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)diagnostic, ""));
208366edf50cSStefano Zampini       PetscCall(TSMonitorSolutionVTK(ts, stepnum, time, diagnostic, ctx->view_vtk_ctx));
208466edf50cSStefano Zampini     }
208566edf50cSStefano Zampini     if (need_hdf5) {
208666edf50cSStefano Zampini       DM       vdm;
208766edf50cSStefano Zampini       PetscInt seqnum;
208866edf50cSStefano Zampini 
208966edf50cSStefano Zampini       PetscCall(VecGetDM(diagnostic, &vdm));
209066edf50cSStefano Zampini       if (!dump_dm) {
209166edf50cSStefano Zampini         PetscCall(PetscViewerPushFormat(ctx->view_hdf5_ctx->viewer, ctx->view_hdf5_ctx->format));
209266edf50cSStefano Zampini         PetscCall(DMView(vdm, ctx->view_hdf5_ctx->viewer));
209366edf50cSStefano Zampini         PetscCall(PetscViewerPopFormat(ctx->view_hdf5_ctx->viewer));
209466edf50cSStefano Zampini       }
209566edf50cSStefano Zampini       PetscCall(DMGetOutputSequenceNumber(vdm, &seqnum, NULL));
209666edf50cSStefano Zampini       PetscCall(DMSetOutputSequenceNumber(vdm, seqnum + 1, time));
209766edf50cSStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)diagnostic, "diagnostic"));
209866edf50cSStefano Zampini       PetscCall(PetscViewerPushFormat(ctx->view_hdf5_ctx->viewer, ctx->view_hdf5_ctx->format));
209966edf50cSStefano Zampini       PetscCall(VecView(diagnostic, ctx->view_hdf5_ctx->viewer));
210066edf50cSStefano Zampini       if (ctx->diagnostic_num > 3 || ctx->diagnostic_num < 0) {
210166edf50cSStefano Zampini         PetscCall(DMSetOutputSequenceNumber(dm, seqnum + 1, time));
210266edf50cSStefano Zampini         PetscCall(VecView(u, ctx->view_hdf5_ctx->viewer));
210366edf50cSStefano Zampini       }
210466edf50cSStefano Zampini       PetscCall(PetscViewerPopFormat(ctx->view_hdf5_ctx->viewer));
210566edf50cSStefano Zampini     }
210666edf50cSStefano Zampini     PetscCall(VecDestroy(&diagnostic));
210766edf50cSStefano Zampini   }
2108811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2109811d88abSStefano Zampini }
2110811d88abSStefano Zampini 
2111811d88abSStefano Zampini /* Save restart information */
MonitorSave(TS ts,PetscInt steps,PetscReal time,Vec u,void * vctx)2112811d88abSStefano Zampini static PetscErrorCode MonitorSave(TS ts, PetscInt steps, PetscReal time, Vec u, void *vctx)
2113811d88abSStefano Zampini {
2114811d88abSStefano Zampini   DM                dm;
2115811d88abSStefano Zampini   AppCtx           *ctx        = (AppCtx *)vctx;
2116811d88abSStefano Zampini   PetscInt          save_every = ctx->save_every;
2117811d88abSStefano Zampini   TSConvergedReason reason;
2118811d88abSStefano Zampini 
2119811d88abSStefano Zampini   PetscFunctionBeginUser;
2120811d88abSStefano Zampini   if (!ctx->save) PetscFunctionReturn(PETSC_SUCCESS);
2121811d88abSStefano Zampini   PetscCall(TSGetDM(ts, &dm));
2122811d88abSStefano Zampini   PetscCall(TSGetConvergedReason(ts, &reason));
2123811d88abSStefano Zampini   if ((save_every > 0 && steps % save_every == 0) || (save_every == -1 && reason) || save_every < -1) PetscCall(SaveToFile(dm, u, ctx->save_filename));
2124811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2125811d88abSStefano Zampini }
2126811d88abSStefano Zampini 
212766edf50cSStefano Zampini /* Resample source if time dependent */
PreStage(TS ts,PetscReal stagetime)212866edf50cSStefano Zampini static PetscErrorCode PreStage(TS ts, PetscReal stagetime)
212966edf50cSStefano Zampini {
213066edf50cSStefano Zampini   AppCtx   *ctx;
213166edf50cSStefano Zampini   PetscBool resample, ismatis;
213266edf50cSStefano Zampini   Mat       A, P;
213366edf50cSStefano Zampini 
213466edf50cSStefano Zampini   PetscFunctionBeginUser;
213566edf50cSStefano Zampini   PetscCall(TSGetApplicationContext(ts, &ctx));
213666edf50cSStefano Zampini   /* in case we need to call SNESSetFunctionDomainError */
213766edf50cSStefano Zampini   PetscCall(TSGetSNES(ts, &ctx->snes));
213866edf50cSStefano Zampini 
213966edf50cSStefano Zampini   resample = ctx->split ? PETSC_TRUE : PETSC_FALSE;
214066edf50cSStefano Zampini   for (PetscInt i = 0; i < ctx->source_ctx->n; i++) {
214166edf50cSStefano Zampini     if (ctx->source_ctx->k[i] != 0.0) {
214266edf50cSStefano Zampini       resample = PETSC_TRUE;
214366edf50cSStefano Zampini       break;
214466edf50cSStefano Zampini     }
214566edf50cSStefano Zampini   }
214666edf50cSStefano Zampini   if (resample) {
214766edf50cSStefano Zampini     DM  dm;
214866edf50cSStefano Zampini     Vec u = NULL;
214966edf50cSStefano Zampini 
215066edf50cSStefano Zampini     PetscCall(TSGetDM(ts, &dm));
215166edf50cSStefano Zampini     /* In case of a multistage method, we always use the frozen values at the previous time-step */
215266edf50cSStefano Zampini     if (ctx->split) PetscCall(TSGetSolution(ts, &u));
215366edf50cSStefano Zampini     PetscCall(ProjectAuxDM(dm, stagetime, u, ctx));
215466edf50cSStefano Zampini   }
215566edf50cSStefano Zampini 
215666edf50cSStefano Zampini   /* element matrices are sparse, ignore zero entries */
215766edf50cSStefano Zampini   PetscCall(TSGetIJacobian(ts, &A, &P, NULL, NULL));
215866edf50cSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
215966edf50cSStefano Zampini   if (!ismatis) PetscCall(MatSetOption(A, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
216066edf50cSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)P, MATIS, &ismatis));
216166edf50cSStefano Zampini   if (!ismatis) PetscCall(MatSetOption(P, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
216266edf50cSStefano Zampini 
216366edf50cSStefano Zampini   /* Set symmetric flag */
216466edf50cSStefano Zampini   PetscCall(MatSetOption(A, MAT_SYMMETRIC, PETSC_TRUE));
216566edf50cSStefano Zampini   PetscCall(MatSetOption(P, MAT_SYMMETRIC, PETSC_TRUE));
216666edf50cSStefano Zampini   PetscCall(MatSetOption(A, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
216766edf50cSStefano Zampini   PetscCall(MatSetOption(P, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
216866edf50cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
216966edf50cSStefano Zampini }
217066edf50cSStefano Zampini 
2171811d88abSStefano Zampini /* Make potential zero mean after SNES solve */
PostStage(TS ts,PetscReal stagetime,PetscInt stageindex,Vec * Y)2172811d88abSStefano Zampini static PetscErrorCode PostStage(TS ts, PetscReal stagetime, PetscInt stageindex, Vec *Y)
2173811d88abSStefano Zampini {
2174811d88abSStefano Zampini   DM       dm;
2175811d88abSStefano Zampini   Vec      u = Y[stageindex];
2176204aa523SStefano Zampini   SNES     snes;
2177204aa523SStefano Zampini   PetscInt nits, lits, stepnum;
2178204aa523SStefano Zampini   AppCtx  *ctx;
2179811d88abSStefano Zampini 
2180811d88abSStefano Zampini   PetscFunctionBeginUser;
2181811d88abSStefano Zampini   PetscCall(TSGetDM(ts, &dm));
2182204aa523SStefano Zampini   PetscCall(TSGetApplicationContext(ts, &ctx));
218366edf50cSStefano Zampini 
218466edf50cSStefano Zampini   PetscCall(ZeroMeanPotential(dm, u, ctx->domain_volume));
218566edf50cSStefano Zampini 
2186204aa523SStefano Zampini   if (ctx->test_restart) PetscFunctionReturn(PETSC_SUCCESS);
2187204aa523SStefano Zampini 
2188204aa523SStefano Zampini   /* monitor linear and nonlinear iterations */
2189204aa523SStefano Zampini   PetscCall(TSGetStepNumber(ts, &stepnum));
2190204aa523SStefano Zampini   PetscCall(TSGetSNES(ts, &snes));
2191204aa523SStefano Zampini   PetscCall(SNESGetIterationNumber(snes, &nits));
2192204aa523SStefano Zampini   PetscCall(SNESGetLinearSolveIterations(snes, &lits));
2193204aa523SStefano Zampini 
2194204aa523SStefano Zampini   /* if function evals in TSDIRK are zero in the first stage, it is FSAL */
2195204aa523SStefano Zampini   if (stageindex == 0) {
2196204aa523SStefano Zampini     PetscBool dirk;
2197204aa523SStefano Zampini     PetscInt  nf;
2198204aa523SStefano Zampini 
2199204aa523SStefano Zampini     PetscCall(PetscObjectTypeCompare((PetscObject)ts, TSDIRK, &dirk));
2200204aa523SStefano Zampini     PetscCall(SNESGetNumberFunctionEvals(snes, &nf));
2201204aa523SStefano Zampini     if (dirk && nf == 0) nits = 0;
2202204aa523SStefano Zampini   }
2203204aa523SStefano Zampini   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "         step %" PetscInt_FMT " stage %" PetscInt_FMT " nonlinear its %" PetscInt_FMT ", linear its %" PetscInt_FMT "\n", stepnum, stageindex, nits, lits));
2204811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2205811d88abSStefano Zampini }
2206811d88abSStefano Zampini 
MonitorNorms(SNES snes,PetscInt its,PetscReal f,void * vctx)220766edf50cSStefano Zampini PetscErrorCode MonitorNorms(SNES snes, PetscInt its, PetscReal f, void *vctx)
2208811d88abSStefano Zampini {
220966edf50cSStefano Zampini   AppCtx   *ctx = (AppCtx *)vctx;
221066edf50cSStefano Zampini   Vec       F;
221166edf50cSStefano Zampini   DM        dm;
221266edf50cSStefano Zampini   PetscReal subnorm[NUM_FIELDS];
2213811d88abSStefano Zampini 
2214811d88abSStefano Zampini   PetscFunctionBeginUser;
221566edf50cSStefano Zampini   PetscCall(SNESGetDM(snes, &dm));
221666edf50cSStefano Zampini   PetscCall(SNESGetFunction(snes, &F, NULL, NULL));
221766edf50cSStefano Zampini   if (!ctx->subsct[C_FIELD_ID]) {
221866edf50cSStefano Zampini     IS is;
2219811d88abSStefano Zampini 
222066edf50cSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)dm, "IS conductivity", (PetscObject *)&is));
222166edf50cSStefano Zampini     PetscCheck(is, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing conductivity IS");
222266edf50cSStefano Zampini     PetscCall(MakeScatterAndVec(F, is, &ctx->subvec[C_FIELD_ID], &ctx->subsct[C_FIELD_ID]));
222366edf50cSStefano Zampini   }
222466edf50cSStefano Zampini   if (!ctx->subsct[P_FIELD_ID]) {
222566edf50cSStefano Zampini     IS is;
222666edf50cSStefano Zampini 
222766edf50cSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)dm, "IS potential", (PetscObject *)&is));
222866edf50cSStefano Zampini     PetscCheck(is, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing potential IS");
222966edf50cSStefano Zampini     PetscCall(MakeScatterAndVec(F, is, &ctx->subvec[P_FIELD_ID], &ctx->subsct[P_FIELD_ID]));
223066edf50cSStefano Zampini   }
223166edf50cSStefano Zampini   PetscCall(VecScatterBegin(ctx->subsct[C_FIELD_ID], F, ctx->subvec[C_FIELD_ID], INSERT_VALUES, SCATTER_FORWARD));
223266edf50cSStefano Zampini   PetscCall(VecScatterEnd(ctx->subsct[C_FIELD_ID], F, ctx->subvec[C_FIELD_ID], INSERT_VALUES, SCATTER_FORWARD));
223366edf50cSStefano Zampini   PetscCall(VecScatterBegin(ctx->subsct[P_FIELD_ID], F, ctx->subvec[P_FIELD_ID], INSERT_VALUES, SCATTER_FORWARD));
223466edf50cSStefano Zampini   PetscCall(VecScatterEnd(ctx->subsct[P_FIELD_ID], F, ctx->subvec[P_FIELD_ID], INSERT_VALUES, SCATTER_FORWARD));
223566edf50cSStefano Zampini   PetscCall(VecNorm(ctx->subvec[C_FIELD_ID], NORM_2, &subnorm[C_FIELD_ID]));
223666edf50cSStefano Zampini   PetscCall(VecNorm(ctx->subvec[P_FIELD_ID], NORM_2, &subnorm[P_FIELD_ID]));
223766edf50cSStefano Zampini   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "    %3" PetscInt_FMT " SNES Function norms %14.12e, %14.12e\n", its, (double)subnorm[C_FIELD_ID], (double)subnorm[P_FIELD_ID]));
2238811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2239811d88abSStefano Zampini }
2240811d88abSStefano Zampini 
Run(MPI_Comm comm,AppCtx * ctx)2241811d88abSStefano Zampini static PetscErrorCode Run(MPI_Comm comm, AppCtx *ctx)
2242811d88abSStefano Zampini {
2243811d88abSStefano Zampini   DM        dm;
2244811d88abSStefano Zampini   TS        ts;
2245811d88abSStefano Zampini   Vec       u;
2246811d88abSStefano Zampini   AdaptCtx *actx;
2247811d88abSStefano Zampini   PetscBool flg;
2248811d88abSStefano Zampini 
2249811d88abSStefano Zampini   PetscFunctionBeginUser;
2250811d88abSStefano Zampini   if (ctx->test_restart) {
2251811d88abSStefano Zampini     PetscViewer subviewer;
2252811d88abSStefano Zampini     PetscMPIInt rank;
2253811d88abSStefano Zampini 
2254811d88abSStefano Zampini     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2255811d88abSStefano Zampini     PetscCall(PetscViewerGetSubViewer(PETSC_VIEWER_STDOUT_WORLD, comm, &subviewer));
2256811d88abSStefano Zampini     if (ctx->load) PetscCall(PetscViewerASCIIPrintf(subviewer, "rank %d loading from %s\n", rank, ctx->load_filename));
2257811d88abSStefano Zampini     if (ctx->save) PetscCall(PetscViewerASCIIPrintf(subviewer, "rank %d saving to %s\n", rank, ctx->save_filename));
2258811d88abSStefano Zampini     PetscCall(PetscViewerRestoreSubViewer(PETSC_VIEWER_STDOUT_WORLD, comm, &subviewer));
2259811d88abSStefano Zampini     PetscCall(PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD));
2260811d88abSStefano Zampini   } else {
2261811d88abSStefano Zampini     PetscCall(PetscPrintf(comm, "----------------------------\n"));
2262811d88abSStefano Zampini     PetscCall(PetscPrintf(comm, "Simulation parameters:\n"));
226366edf50cSStefano Zampini     PetscCall(PetscPrintf(comm, "  dim  : %" PetscInt_FMT "\n", ctx->dim));
2264811d88abSStefano Zampini     PetscCall(PetscPrintf(comm, "  r    : %g\n", (double)ctx->r));
2265811d88abSStefano Zampini     PetscCall(PetscPrintf(comm, "  eps  : %g\n", (double)ctx->eps));
2266811d88abSStefano Zampini     PetscCall(PetscPrintf(comm, "  alpha: %g\n", (double)ctx->alpha));
2267811d88abSStefano Zampini     PetscCall(PetscPrintf(comm, "  gamma: %g\n", (double)ctx->gamma));
2268811d88abSStefano Zampini     PetscCall(PetscPrintf(comm, "  D    : %g\n", (double)ctx->D));
2269811d88abSStefano Zampini     if (ctx->load) PetscCall(PetscPrintf(comm, "  load : %s\n", ctx->load_filename));
2270811d88abSStefano Zampini     else PetscCall(PetscPrintf(comm, "  IC   : %" PetscInt_FMT "\n", ctx->ic_num));
227166edf50cSStefano Zampini     PetscCall(PetscPrintf(comm, "  snum : %" PetscInt_FMT "\n", ctx->source_ctx->n));
227266edf50cSStefano Zampini     for (PetscInt i = 0; i < ctx->source_ctx->n; i++) {
227366edf50cSStefano Zampini       const PetscReal *x0 = ctx->source_ctx->x0 + ctx->dim * i;
227466edf50cSStefano Zampini       const PetscReal  w  = ctx->source_ctx->w[i];
227566edf50cSStefano Zampini       const PetscReal  k  = ctx->source_ctx->k[i];
227666edf50cSStefano Zampini       const PetscReal  p  = ctx->source_ctx->p[i];
227766edf50cSStefano Zampini       const PetscReal  r  = ctx->source_ctx->r[i];
227866edf50cSStefano Zampini 
227966edf50cSStefano Zampini       if (ctx->dim == 2) {
228066edf50cSStefano Zampini         PetscCall(PetscPrintf(comm, "  x0   : (%g,%g)\n", (double)x0[0], (double)x0[1]));
228166edf50cSStefano Zampini       } else {
228266edf50cSStefano Zampini         PetscCall(PetscPrintf(comm, "  x0   : (%g,%g,%g)\n", (double)x0[0], (double)x0[1], (double)x0[2]));
228366edf50cSStefano Zampini       }
228466edf50cSStefano Zampini       PetscCall(PetscPrintf(comm, "  scals: (%g,%g,%g,%g)\n", (double)w, (double)k, (double)p, (double)r));
228566edf50cSStefano Zampini     }
2286811d88abSStefano Zampini     PetscCall(PetscPrintf(comm, "----------------------------\n"));
2287811d88abSStefano Zampini   }
2288811d88abSStefano Zampini 
2289811d88abSStefano Zampini   if (!ctx->test_restart) PetscCall(PetscLogStagePush(SetupStage));
2290811d88abSStefano Zampini   PetscCall(CreateMesh(comm, &dm, ctx));
2291811d88abSStefano Zampini   PetscCall(SetupDiscretization(dm, ctx));
2292811d88abSStefano Zampini 
2293811d88abSStefano Zampini   PetscCall(TSCreate(comm, &ts));
2294811d88abSStefano Zampini   PetscCall(TSSetApplicationContext(ts, ctx));
2295811d88abSStefano Zampini 
2296811d88abSStefano Zampini   PetscCall(TSSetDM(ts, dm));
2297811d88abSStefano Zampini   if (ctx->test_restart) {
2298811d88abSStefano Zampini     PetscViewer subviewer;
2299811d88abSStefano Zampini     PetscMPIInt rank;
2300811d88abSStefano Zampini     PetscInt    level;
2301811d88abSStefano Zampini 
2302811d88abSStefano Zampini     PetscCall(DMGetRefineLevel(dm, &level));
2303811d88abSStefano Zampini     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2304811d88abSStefano Zampini     PetscCall(PetscViewerGetSubViewer(PETSC_VIEWER_STDOUT_WORLD, comm, &subviewer));
2305811d88abSStefano Zampini     PetscCall(PetscViewerASCIIPrintf(subviewer, "rank %d DM refinement level %" PetscInt_FMT "\n", rank, level));
2306811d88abSStefano Zampini     PetscCall(PetscViewerRestoreSubViewer(PETSC_VIEWER_STDOUT_WORLD, comm, &subviewer));
2307811d88abSStefano Zampini     PetscCall(PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD));
2308811d88abSStefano Zampini   }
2309811d88abSStefano Zampini 
2310811d88abSStefano Zampini   if (ctx->test_restart) PetscCall(TSSetMaxSteps(ts, 1));
2311811d88abSStefano Zampini   PetscCall(TSSetMaxTime(ts, 10.0));
2312811d88abSStefano Zampini   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
2313811d88abSStefano Zampini   if (!ctx->test_restart) PetscCall(TSMonitorSet(ts, Monitor, NULL, NULL));
2314811d88abSStefano Zampini   PetscCall(TSMonitorSet(ts, MonitorSave, ctx, NULL));
2315811d88abSStefano Zampini   PetscCall(PetscNew(&actx));
2316811d88abSStefano Zampini   if (ctx->amr) PetscCall(TSSetResize(ts, PETSC_TRUE, ResizeSetUp, ResizeTransfer, actx));
231766edf50cSStefano Zampini   PetscCall(TSSetPreStage(ts, PreStage));
2318811d88abSStefano Zampini   PetscCall(TSSetPostStage(ts, PostStage));
2319811d88abSStefano Zampini   PetscCall(TSSetMaxSNESFailures(ts, -1));
232066edf50cSStefano Zampini   PetscCall(TSSetFunctionDomainError(ts, FunctionDomainError));
2321811d88abSStefano Zampini   PetscCall(TSSetFromOptions(ts));
232266edf50cSStefano Zampini   if (ctx->monitor_norms) {
232366edf50cSStefano Zampini     SNES snes;
232466edf50cSStefano Zampini 
232566edf50cSStefano Zampini     PetscCall(TSGetSNES(ts, &snes));
232666edf50cSStefano Zampini     PetscCall(SNESMonitorSet(snes, MonitorNorms, ctx, NULL));
232766edf50cSStefano Zampini   }
2328811d88abSStefano Zampini 
2329811d88abSStefano Zampini   PetscCall(DMCreateGlobalVector(dm, &u));
2330811d88abSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)u, "solution_"));
2331811d88abSStefano Zampini   PetscCall(DMHasNamedGlobalVector(dm, "solution_", &flg));
233266edf50cSStefano Zampini   if (flg) { /* load from restart file */
2333811d88abSStefano Zampini     Vec ru;
2334811d88abSStefano Zampini 
2335811d88abSStefano Zampini     PetscCall(DMGetNamedGlobalVector(dm, "solution_", &ru));
2336811d88abSStefano Zampini     PetscCall(VecCopy(ru, u));
2337811d88abSStefano Zampini     PetscCall(DMRestoreNamedGlobalVector(dm, "solution_", &ru));
2338811d88abSStefano Zampini   }
233966edf50cSStefano Zampini   PetscCall(SetInitialConditionsAndTolerances(ts, 1, &u, flg));
2340811d88abSStefano Zampini   PetscCall(TSSetSolution(ts, u));
2341811d88abSStefano Zampini   PetscCall(VecDestroy(&u));
2342811d88abSStefano Zampini   PetscCall(DMDestroy(&dm));
2343811d88abSStefano Zampini   if (!ctx->test_restart) PetscCall(PetscLogStagePop());
2344811d88abSStefano Zampini 
2345811d88abSStefano Zampini   if (!ctx->test_restart) PetscCall(PetscLogStagePush(SolveStage));
2346811d88abSStefano Zampini   PetscCall(TSSolve(ts, NULL));
2347811d88abSStefano Zampini   if (!ctx->test_restart) PetscCall(PetscLogStagePop());
234866edf50cSStefano Zampini   if (ctx->view_vtk_ctx) PetscCall(TSMonitorSolutionVTKDestroy(&ctx->view_vtk_ctx));
234966edf50cSStefano Zampini   if (ctx->view_hdf5_ctx) PetscCall(PetscViewerAndFormatDestroy(&ctx->view_hdf5_ctx));
235066edf50cSStefano Zampini   PetscCall(DMDestroy(&ctx->view_dm));
235166edf50cSStefano Zampini   for (PetscInt i = 0; i < NUM_FIELDS; i++) {
235266edf50cSStefano Zampini     PetscCall(VecScatterDestroy(&ctx->subsct[i]));
235366edf50cSStefano Zampini     PetscCall(VecDestroy(&ctx->subvec[i]));
235466edf50cSStefano Zampini   }
2355811d88abSStefano Zampini 
2356811d88abSStefano Zampini   PetscCall(TSDestroy(&ts));
2357811d88abSStefano Zampini   PetscCall(VecTaggerDestroy(&actx->refineTag));
2358811d88abSStefano Zampini   PetscCall(PetscFree(actx));
2359811d88abSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2360811d88abSStefano Zampini }
2361811d88abSStefano Zampini 
main(int argc,char ** argv)2362811d88abSStefano Zampini int main(int argc, char **argv)
2363811d88abSStefano Zampini {
2364811d88abSStefano Zampini   AppCtx ctx;
2365811d88abSStefano Zampini 
2366811d88abSStefano Zampini   PetscFunctionBeginUser;
2367811d88abSStefano Zampini   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
2368811d88abSStefano Zampini   PetscCall(ProcessOptions(&ctx));
2369811d88abSStefano Zampini   PetscCall(PetscLogStageRegister("Setup", &SetupStage));
2370811d88abSStefano Zampini   PetscCall(PetscLogStageRegister("Solve", &SolveStage));
2371811d88abSStefano Zampini   if (ctx.test_restart) { /* Test sequences of save and loads */
2372811d88abSStefano Zampini     PetscMPIInt rank;
2373811d88abSStefano Zampini 
2374811d88abSStefano Zampini     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2375811d88abSStefano Zampini 
2376811d88abSStefano Zampini     /* test saving */
2377811d88abSStefano Zampini     ctx.load = PETSC_FALSE;
2378811d88abSStefano Zampini     ctx.save = PETSC_TRUE;
2379811d88abSStefano Zampini     /* sequential save */
2380811d88abSStefano Zampini     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test sequential save\n"));
2381811d88abSStefano Zampini     PetscCall(PetscSNPrintf(ctx.save_filename, sizeof(ctx.save_filename), "test_ex30_seq_%d.h5", rank));
2382811d88abSStefano Zampini     PetscCall(Run(PETSC_COMM_SELF, &ctx));
2383811d88abSStefano Zampini     /* parallel save */
2384811d88abSStefano Zampini     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test parallel save\n"));
2385811d88abSStefano Zampini     PetscCall(PetscSNPrintf(ctx.save_filename, sizeof(ctx.save_filename), "test_ex30_par.h5"));
2386811d88abSStefano Zampini     PetscCall(Run(PETSC_COMM_WORLD, &ctx));
2387811d88abSStefano Zampini 
2388811d88abSStefano Zampini     /* test loading */
2389811d88abSStefano Zampini     ctx.load = PETSC_TRUE;
2390811d88abSStefano Zampini     ctx.save = PETSC_FALSE;
2391811d88abSStefano Zampini     /* sequential and parallel runs from sequential save */
2392811d88abSStefano Zampini     PetscCall(PetscSNPrintf(ctx.load_filename, sizeof(ctx.load_filename), "test_ex30_seq_0.h5"));
2393811d88abSStefano Zampini     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test sequential load from sequential save\n"));
2394811d88abSStefano Zampini     PetscCall(Run(PETSC_COMM_SELF, &ctx));
2395811d88abSStefano Zampini     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test parallel load from sequential save\n"));
2396811d88abSStefano Zampini     PetscCall(Run(PETSC_COMM_WORLD, &ctx));
2397811d88abSStefano Zampini     /* sequential and parallel runs from parallel save */
2398811d88abSStefano Zampini     PetscCall(PetscSNPrintf(ctx.load_filename, sizeof(ctx.load_filename), "test_ex30_par.h5"));
2399811d88abSStefano Zampini     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test sequential load from parallel save\n"));
2400811d88abSStefano Zampini     PetscCall(Run(PETSC_COMM_SELF, &ctx));
2401811d88abSStefano Zampini     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test parallel load from parallel save\n"));
2402811d88abSStefano Zampini     PetscCall(Run(PETSC_COMM_WORLD, &ctx));
2403811d88abSStefano Zampini   } else { /* Run the simulation */
2404811d88abSStefano Zampini     PetscCall(Run(PETSC_COMM_WORLD, &ctx));
2405811d88abSStefano Zampini   }
240666edf50cSStefano Zampini   PetscCall(PetscFree5(ctx.source_ctx->x0, ctx.source_ctx->w, ctx.source_ctx->k, ctx.source_ctx->p, ctx.source_ctx->r));
240766edf50cSStefano Zampini   PetscCall(PetscFree(ctx.source_ctx));
2408811d88abSStefano Zampini   PetscCall(PetscFinalize());
2409811d88abSStefano Zampini   return 0;
2410811d88abSStefano Zampini }
2411811d88abSStefano Zampini 
2412811d88abSStefano Zampini /*TEST
2413811d88abSStefano Zampini 
2414811d88abSStefano Zampini   testset:
241566edf50cSStefano Zampini     args: -dm_plex_box_faces 3,3 -ksp_type preonly -pc_type svd -c_petscspace_degree 1 -p_petscspace_degree 1 -ts_max_steps 1 -initial_snes_test_jacobian -snes_test_jacobian -initial_snes_type ksponly -snes_type ksponly -petscpartitioner_type simple -dm_plex_simplex 0 -ts_adapt_type none -ic_num 3
2416811d88abSStefano Zampini 
2417811d88abSStefano Zampini     test:
2418811d88abSStefano Zampini       suffix: 0
2419811d88abSStefano Zampini       nsize: {{1 2}}
242066edf50cSStefano Zampini       args: -dm_refine 1 -lump {{0 1}} -exclude_potential_lte
242166edf50cSStefano Zampini 
242266edf50cSStefano Zampini     test:
242366edf50cSStefano Zampini       suffix: 0_split
242466edf50cSStefano Zampini       nsize: {{1 2}}
242566edf50cSStefano Zampini       args: -dm_refine 1 -split
242666edf50cSStefano Zampini 
242766edf50cSStefano Zampini     test:
242866edf50cSStefano Zampini       suffix: 0_3d
242966edf50cSStefano Zampini       nsize: {{1 2}}
243066edf50cSStefano Zampini       args: -dm_plex_box_faces 3,3,3 -dim 3 -dm_plex_dim 3 -lump {{0 1}}
2431811d88abSStefano Zampini 
2432811d88abSStefano Zampini     test:
2433811d88abSStefano Zampini       suffix: 0_dirk
2434811d88abSStefano Zampini       nsize: {{1 2}}
2435811d88abSStefano Zampini       args: -dm_refine 1 -ts_type dirk
2436811d88abSStefano Zampini 
2437811d88abSStefano Zampini     test:
2438811d88abSStefano Zampini       suffix: 0_dirk_mg
2439811d88abSStefano Zampini       nsize: {{1 2}}
2440204aa523SStefano Zampini       args: -dm_refine_hierarchy 1 -ts_type dirk -pc_type mg -mg_levels_pc_type bjacobi -mg_levels_sub_pc_factor_levels 2 -mg_levels_sub_pc_factor_mat_ordering_type rcm -mg_levels_sub_pc_factor_reuse_ordering -mg_coarse_pc_type svd -lump {{0 1}}
2441204aa523SStefano Zampini 
2442204aa523SStefano Zampini     test:
2443204aa523SStefano Zampini       suffix: 0_dirk_fieldsplit
2444204aa523SStefano Zampini       nsize: {{1 2}}
2445204aa523SStefano Zampini       args: -dm_refine 1 -ts_type dirk -pc_type fieldsplit -pc_fieldsplit_type multiplicative -lump {{0 1}}
2446811d88abSStefano Zampini 
2447811d88abSStefano Zampini     test:
2448811d88abSStefano Zampini       requires: p4est
2449811d88abSStefano Zampini       suffix: 0_p4est
2450811d88abSStefano Zampini       nsize: {{1 2}}
2451204aa523SStefano Zampini       args: -dm_refine 1 -dm_plex_convert_type p4est -lump 0
2452811d88abSStefano Zampini 
2453811d88abSStefano Zampini     test:
2454811d88abSStefano Zampini       suffix: 0_periodic
2455811d88abSStefano Zampini       nsize: {{1 2}}
2456204aa523SStefano Zampini       args: -dm_plex_box_bd periodic,periodic -dm_refine_pre 1 -lump {{0 1}}
2457811d88abSStefano Zampini 
2458811d88abSStefano Zampini     test:
2459811d88abSStefano Zampini       requires: p4est
2460811d88abSStefano Zampini       suffix: 0_p4est_periodic
2461811d88abSStefano Zampini       nsize: {{1 2}}
2462204aa523SStefano Zampini       args: -dm_plex_box_bd periodic,periodic -dm_refine_pre 1 -dm_plex_convert_type p4est -lump 0
2463811d88abSStefano Zampini 
2464811d88abSStefano Zampini     test:
2465811d88abSStefano Zampini       requires: p4est
2466811d88abSStefano Zampini       suffix: 0_p4est_mg
2467811d88abSStefano Zampini       nsize: {{1 2}}
2468204aa523SStefano Zampini       args: -dm_forest_minimum_refinement 0 -dm_forest_initial_refinement 2 -dm_plex_convert_type p4est -pc_type mg -mg_coarse_pc_type svd -mg_levels_pc_type svd -lump 0
2469811d88abSStefano Zampini 
2470811d88abSStefano Zampini   testset:
2471811d88abSStefano Zampini     requires: hdf5
2472811d88abSStefano Zampini     args: -test_restart -dm_plex_box_faces 3,3 -ksp_type preonly -pc_type mg -mg_levels_pc_type svd -c_petscspace_degree 1 -p_petscspace_degree 1 -petscpartitioner_type simple -test_restart
2473811d88abSStefano Zampini 
2474811d88abSStefano Zampini     test:
2475910b42cbSStefano Zampini       requires: !single
2476811d88abSStefano Zampini       suffix: restart
2477811d88abSStefano Zampini       nsize: {{1 2}separate output}
2478811d88abSStefano Zampini       args: -dm_refine_hierarchy {{0 1}separate output} -dm_plex_simplex 0
2479811d88abSStefano Zampini 
2480811d88abSStefano Zampini     test:
2481811d88abSStefano Zampini       requires: triangle
2482811d88abSStefano Zampini       suffix: restart_simplex
2483811d88abSStefano Zampini       nsize: {{1 2}separate output}
2484811d88abSStefano Zampini       args: -dm_refine_hierarchy {{0 1}separate output} -dm_plex_simplex 1
2485811d88abSStefano Zampini 
2486811d88abSStefano Zampini     test:
2487910b42cbSStefano Zampini       requires: !single
2488811d88abSStefano Zampini       suffix: restart_refonly
2489811d88abSStefano Zampini       nsize: {{1 2}separate output}
2490811d88abSStefano Zampini       args: -dm_refine 1 -dm_plex_simplex 0
2491811d88abSStefano Zampini 
2492811d88abSStefano Zampini     test:
2493811d88abSStefano Zampini       requires: triangle
2494811d88abSStefano Zampini       suffix: restart_simplex_refonly
2495811d88abSStefano Zampini       nsize: {{1 2}separate output}
2496811d88abSStefano Zampini       args: -dm_refine 1 -dm_plex_simplex 1
2497811d88abSStefano Zampini 
249866edf50cSStefano Zampini   test:
249966edf50cSStefano Zampini     suffix: annulus
250066edf50cSStefano Zampini     requires: exodusii
250166edf50cSStefano Zampini     args: -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo -ksp_type preonly -pc_type none -c_petscspace_degree 1 -p_petscspace_degree 1 -ts_max_steps 2 -initial_snes_type ksponly -snes_type ksponly -petscpartitioner_type simple -dm_plex_simplex 0 -ts_adapt_type none -source_num 2 -source_k 1,2
250266edf50cSStefano Zampini 
250366edf50cSStefano Zampini   test:
250466edf50cSStefano Zampini     suffix: hdf5_diagnostic
250566edf50cSStefano Zampini     requires: hdf5 exodusii
250666edf50cSStefano Zampini     args: -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo -ksp_type preonly -pc_type none -c_petscspace_degree 1 -p_petscspace_degree 1 -ts_max_steps 2 -initial_snes_type ksponly -snes_type ksponly -petscpartitioner_type simple -dm_plex_simplex 0 -ts_adapt_type none -source_num 2 -source_k 1,2 -monitor_hdf5 diagnostic.h5 -ic_num 3
250766edf50cSStefano Zampini 
250866edf50cSStefano Zampini   test:
250966edf50cSStefano Zampini     suffix: vtk_diagnostic
251066edf50cSStefano Zampini     requires: exodusii
251166edf50cSStefano Zampini     args: -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo -ksp_type preonly -pc_type none -c_petscspace_degree 1 -p_petscspace_degree 1 -ts_max_steps 2 -initial_snes_type ksponly -snes_type ksponly -petscpartitioner_type simple -dm_plex_simplex 0 -ts_adapt_type none -source_num 2 -source_k 1,2 -monitor_vtk 'diagnostic-%03d.vtu' -ic_num 3
251266edf50cSStefano Zampini 
251366edf50cSStefano Zampini   test:
251466edf50cSStefano Zampini     suffix: full_cdisc
251566edf50cSStefano Zampini     args: -dm_plex_box_faces 3,3 -c_petscspace_degree 0 -p_petscspace_degree 1 -ts_max_steps 1 -petscpartitioner_type simple -dm_plex_simplex 0 -ts_adapt_type none -ic_num 0 -dm_refine 1 -ts_type beuler -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_precondition selfp -fieldsplit_conductivity_pc_type pbjacobi -fieldsplit_potential_mat_schur_complement_ainv_type blockdiag -fieldsplit_potential_ksp_type preonly -fieldsplit_potential_pc_type svd
251666edf50cSStefano Zampini 
251766edf50cSStefano Zampini   test:
251866edf50cSStefano Zampini     suffix: full_cdisc_split
251966edf50cSStefano Zampini     args: -dm_plex_box_faces 3,3 -c_petscspace_degree 0 -p_petscspace_degree 1 -ts_max_steps 1 -petscpartitioner_type simple -dm_plex_simplex 0 -ts_adapt_type none -ic_num 0 -dm_refine 1 -ts_type beuler -pc_type fieldsplit -pc_fieldsplit_type additive -fieldsplit_conductivity_pc_type pbjacobi -fieldsplit_potential_pc_type gamg -split -monitor_norms
252066edf50cSStefano Zampini 
252166edf50cSStefano Zampini   test:
252266edf50cSStefano Zampini     suffix: full_cdisc_minres
252366edf50cSStefano Zampini     args: -dm_plex_box_faces 3,3 -c_petscspace_degree 0 -p_petscspace_degree 1 -ts_max_steps 1 -petscpartitioner_type simple -dm_plex_simplex 0 -ts_adapt_type none -ic_num 0 -dm_refine 1 -ts_type beuler -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_fact_type diag -pc_fieldsplit_schur_precondition selfp -fieldsplit_conductivity_pc_type pbjacobi -fieldsplit_potential_mat_schur_complement_ainv_type blockdiag -fieldsplit_potential_ksp_type preonly -fieldsplit_potential_pc_type svd -ksp_type minres
252466edf50cSStefano Zampini 
2525811d88abSStefano Zampini TEST*/
2526