xref: /petsc/src/ts/tutorials/ex48.c (revision 29e10dd4463b4488500a1612bd63f12e7bb25f67)
1*29e10dd4SMark Adams static char help[] = "Magnetohydrodynamics (MHD) with Poisson brackets and "
2*29e10dd4SMark Adams                      "stream functions, solver testbed for M3D-C1. Used in https://arxiv.org/abs/2302.10242";
3c4762a1bSJed Brown 
4c4762a1bSJed Brown /*F
5*29e10dd4SMark Adams The strong form of a two field model for vorticity $\Omega$ and magnetic flux
6*29e10dd4SMark Adams $\psi$, using auxiliary variables potential $\phi$ and (negative) current
7*29e10dd4SMark Adams density $j_z$ \cite{Jardin04,Strauss98}.See http://arxiv.org/abs/  for more details
8c4762a1bSJed Brown F*/
9c4762a1bSJed Brown 
10*29e10dd4SMark Adams #include <assert.h>
11c4762a1bSJed Brown #include <petscdmplex.h>
12c4762a1bSJed Brown #include <petscds.h>
13*29e10dd4SMark Adams #include <petscts.h>
14*29e10dd4SMark Adams 
15*29e10dd4SMark Adams typedef enum _testidx {
16*29e10dd4SMark Adams   TEST_TILT,
17*29e10dd4SMark Adams   NUM_TEST_TYPES
18*29e10dd4SMark Adams } TestType;
19*29e10dd4SMark Adams const char *testTypes[NUM_TEST_TYPES + 1] = {"tilt", "unknown"};
20*29e10dd4SMark Adams typedef enum _modelidx {
21*29e10dd4SMark Adams   TWO_FILD,
22*29e10dd4SMark Adams   ONE_FILD,
23*29e10dd4SMark Adams   NUM_MODELS
24*29e10dd4SMark Adams } ModelType;
25*29e10dd4SMark Adams const char *modelTypes[NUM_MODELS + 1] = {"two-field", "one-field", "unknown"};
26*29e10dd4SMark Adams typedef enum _fieldidx {
27*29e10dd4SMark Adams   JZ,
28*29e10dd4SMark Adams   PSI,
29*29e10dd4SMark Adams   PHI,
30*29e10dd4SMark Adams   OMEGA,
31*29e10dd4SMark Adams   NUM_COMP
32*29e10dd4SMark Adams } FieldIdx; // add more
33*29e10dd4SMark Adams typedef enum _const_idx {
34*29e10dd4SMark Adams   MU_CONST,
35*29e10dd4SMark Adams   ETA_CONST,
36*29e10dd4SMark Adams   TEST_CONST,
37*29e10dd4SMark Adams   NUM_CONSTS
38*29e10dd4SMark Adams } ConstIdx;
39c4762a1bSJed Brown 
40c4762a1bSJed Brown typedef struct {
41c4762a1bSJed Brown   PetscInt  debug; /* The debugging level */
42*29e10dd4SMark Adams   PetscReal plotDt;
43*29e10dd4SMark Adams   PetscReal plotStartTime;
44*29e10dd4SMark Adams   PetscInt  plotIdx;
45*29e10dd4SMark Adams   PetscInt  plotStep;
46*29e10dd4SMark Adams   PetscBool plotting;
47*29e10dd4SMark Adams   PetscInt  dim;                          /* The topological mesh dimension */
48*29e10dd4SMark Adams   char      filename[PETSC_MAX_PATH_LEN]; /* The optional ExodusII file */
49c4762a1bSJed Brown   PetscErrorCode (**initialFuncs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx);
50*29e10dd4SMark Adams   PetscReal mu, eta;
51*29e10dd4SMark Adams   PetscReal perturb;
52*29e10dd4SMark Adams   TestType  testType;
53*29e10dd4SMark Adams   ModelType modelType;
54*29e10dd4SMark Adams   PetscInt  Nf;
55c4762a1bSJed Brown } AppCtx;
56c4762a1bSJed Brown 
57*29e10dd4SMark Adams static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
58*29e10dd4SMark Adams {
59*29e10dd4SMark Adams   PetscInt ii;
60c4762a1bSJed Brown 
61*29e10dd4SMark Adams   PetscFunctionBeginUser;
62*29e10dd4SMark Adams   options->debug         = 1;
63*29e10dd4SMark Adams   options->filename[0]   = '\0';
64*29e10dd4SMark Adams   options->testType      = TEST_TILT;
65*29e10dd4SMark Adams   options->modelType     = TWO_FILD;
66*29e10dd4SMark Adams   options->mu            = 0.005;
67*29e10dd4SMark Adams   options->eta           = 0.001;
68*29e10dd4SMark Adams   options->perturb       = 0;
69*29e10dd4SMark Adams   options->plotDt        = 0.1;
70*29e10dd4SMark Adams   options->plotStartTime = 0.0;
71*29e10dd4SMark Adams   options->plotIdx       = 0;
72*29e10dd4SMark Adams   options->plotStep      = PETSC_MAX_INT;
73*29e10dd4SMark Adams   options->plotting      = PETSC_FALSE;
74*29e10dd4SMark Adams 
75*29e10dd4SMark Adams   PetscOptionsBegin(comm, "", "MHD Problem Options", "DMPLEX");
76*29e10dd4SMark Adams   PetscCall(PetscOptionsInt("-debug", "The debugging level", "mhd.c", options->debug, &options->debug, NULL));
77*29e10dd4SMark Adams   ii                = (PetscInt)options->testType;
78*29e10dd4SMark Adams   options->testType = TEST_TILT;
79*29e10dd4SMark Adams   ii                = options->testType;
80*29e10dd4SMark Adams   PetscCall(PetscOptionsEList("-test_type", "The test type: 'tilt' Tilt instability", "mhd.c", testTypes, NUM_TEST_TYPES, testTypes[options->testType], &ii, NULL));
81*29e10dd4SMark Adams   options->testType  = (TestType)ii;
82*29e10dd4SMark Adams   ii                 = (PetscInt)options->modelType;
83*29e10dd4SMark Adams   options->modelType = TWO_FILD;
84*29e10dd4SMark Adams   ii                 = options->modelType;
85*29e10dd4SMark Adams   PetscCall(PetscOptionsEList("-model_type", "The model type: 'two', 'one' field", "mhd.c", modelTypes, NUM_MODELS, modelTypes[options->modelType], &ii, NULL));
86*29e10dd4SMark Adams   options->modelType = (ModelType)ii;
87*29e10dd4SMark Adams   options->Nf        = options->modelType == TWO_FILD ? 4 : 2;
88*29e10dd4SMark Adams 
89*29e10dd4SMark Adams   PetscCall(PetscOptionsReal("-mu", "Magnetic resistivity", "mhd.c", options->mu, &options->mu, NULL));
90*29e10dd4SMark Adams   PetscCall(PetscOptionsReal("-eta", "Viscosity", "mhd.c", options->eta, &options->eta, NULL));
91*29e10dd4SMark Adams   PetscCall(PetscOptionsReal("-plot_dt", "Plot frequency in time", "mhd.c", options->plotDt, &options->plotDt, NULL));
92*29e10dd4SMark Adams   PetscCall(PetscOptionsReal("-plot_start_time", "Time to delay start of plotting", "mhd.c", options->plotStartTime, &options->plotStartTime, NULL));
93*29e10dd4SMark Adams   PetscCall(PetscOptionsReal("-perturbation", "Random perturbation of initial psi scale", "mhd.c", options->perturb, &options->perturb, NULL));
94*29e10dd4SMark Adams   PetscCall(PetscPrintf(comm, "Test Type = %s\n", testTypes[options->testType]));
95*29e10dd4SMark Adams   PetscCall(PetscPrintf(comm, "Model Type = %s\n", modelTypes[options->modelType]));
96*29e10dd4SMark Adams   PetscCall(PetscPrintf(comm, "eta = %g\n", (double)options->eta));
97*29e10dd4SMark Adams   PetscCall(PetscPrintf(comm, "mu = %g\n", (double)options->mu));
98*29e10dd4SMark Adams   PetscOptionsEnd();
99*29e10dd4SMark Adams 
100*29e10dd4SMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
101*29e10dd4SMark Adams }
102*29e10dd4SMark Adams 
103*29e10dd4SMark Adams // | 0 1 | matrix to apply bracket
104*29e10dd4SMark Adams // |-1 0 |
105*29e10dd4SMark Adams static PetscReal s_K[2][2] = {
106*29e10dd4SMark Adams   {0,  1},
107*29e10dd4SMark Adams   {-1, 0}
108*29e10dd4SMark Adams };
109*29e10dd4SMark Adams 
110*29e10dd4SMark Adams /*
111*29e10dd4SMark Adams  dt - "g0" are mass terms
112*29e10dd4SMark Adams */
113*29e10dd4SMark Adams static void g0_dt(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 g0[])
114*29e10dd4SMark Adams {
115*29e10dd4SMark Adams   g0[0] = u_tShift;
116*29e10dd4SMark Adams }
117*29e10dd4SMark Adams 
118*29e10dd4SMark Adams /*
119*29e10dd4SMark Adams  Identity, Mass
120*29e10dd4SMark Adams */
121*29e10dd4SMark Adams static void g0_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, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
122*29e10dd4SMark Adams {
123*29e10dd4SMark Adams   g0[0] = 1;
124*29e10dd4SMark Adams }
125*29e10dd4SMark Adams /* 'right' Poisson bracket -<.,phi>, linearized variable is left (column), data
126*29e10dd4SMark Adams  * variable right */
127*29e10dd4SMark Adams static void g1_phi_right(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 g1[])
128*29e10dd4SMark Adams {
129*29e10dd4SMark Adams   PetscInt           i, j;
130*29e10dd4SMark Adams   const PetscScalar *pphiDer = &u_x[uOff_x[PHI]]; // get derivative of the 'right' ("dg") and apply to
131*29e10dd4SMark Adams                                                   // live var "df"
132*29e10dd4SMark Adams   for (i = 0; i < dim; ++i)
133*29e10dd4SMark Adams     for (j = 0; j < dim; ++j)
134*29e10dd4SMark Adams       //  indexing with inner, j, index generates the left live variable [dy,-]
135*29e10dd4SMark Adams       //  by convension, put j index on right, with i destination: [ d/dy,
136*29e10dd4SMark Adams       //  -d/dx]'
137*29e10dd4SMark Adams       g1[i] += s_K[i][j] * pphiDer[j];
138*29e10dd4SMark Adams }
139*29e10dd4SMark Adams /* 'left' bracket -{jz,.}, "n" for negative, linearized variable right (column),
140*29e10dd4SMark Adams  * data variable left */
141*29e10dd4SMark Adams static void g1_njz_left(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 g1[])
142*29e10dd4SMark Adams {
143*29e10dd4SMark Adams   PetscInt           i, j;
144*29e10dd4SMark Adams   const PetscScalar *jzDer = &u_x[uOff_x[JZ]]; // get derivative of the 'left' ("df") and apply to live
145*29e10dd4SMark Adams                                                // var "dg"
146*29e10dd4SMark Adams   for (i = 0; i < dim; ++i)
147*29e10dd4SMark Adams     for (j = 0; j < dim; ++j)
148*29e10dd4SMark Adams       // live right: Der[i] * K: Der[j] --> j: [d/dy, -d/dx]'
149*29e10dd4SMark Adams       g1[j] += -jzDer[i] * s_K[i][j];
150*29e10dd4SMark Adams }
151*29e10dd4SMark Adams /* 'left' Poisson bracket -< . , psi> */
152*29e10dd4SMark Adams static void g1_npsi_right(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 g1[])
153*29e10dd4SMark Adams {
154*29e10dd4SMark Adams   PetscInt           i, j;
155*29e10dd4SMark Adams   const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
156*29e10dd4SMark Adams   for (i = 0; i < dim; ++i)
157*29e10dd4SMark Adams     for (j = 0; j < dim; ++j) g1[i] += -s_K[i][j] * psiDer[j];
158*29e10dd4SMark Adams }
159*29e10dd4SMark Adams 
160*29e10dd4SMark Adams /* < Omega , . > */
161*29e10dd4SMark Adams static void g1_omega_left(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 g1[])
162*29e10dd4SMark Adams {
163*29e10dd4SMark Adams   PetscInt           i, j;
164*29e10dd4SMark Adams   const PetscScalar *pOmegaDer = &u_x[uOff_x[OMEGA]];
165*29e10dd4SMark Adams   for (i = 0; i < dim; ++i)
166*29e10dd4SMark Adams     for (j = 0; j < dim; ++j) g1[j] += pOmegaDer[i] * s_K[i][j];
167*29e10dd4SMark Adams }
168*29e10dd4SMark Adams 
169*29e10dd4SMark Adams /* < psi , . > */
170*29e10dd4SMark Adams static void g1_psi_left(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 g1[])
171*29e10dd4SMark Adams {
172*29e10dd4SMark Adams   PetscInt           i, j;
173*29e10dd4SMark Adams   const PetscScalar *pPsiDer = &u_x[uOff_x[PSI]];
174*29e10dd4SMark Adams   for (i = 0; i < dim; ++i)
175*29e10dd4SMark Adams     for (j = 0; j < dim; ++j) g1[j] += pPsiDer[i] * s_K[i][j];
176*29e10dd4SMark Adams }
177*29e10dd4SMark Adams 
178*29e10dd4SMark Adams // -Lapacians (resistivity), negative sign goes away from IBP
179*29e10dd4SMark Adams static void g3_nmu(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 g3[])
180*29e10dd4SMark Adams {
181*29e10dd4SMark Adams   PetscReal mu = PetscRealPart(constants[MU_CONST]);
182*29e10dd4SMark Adams   for (PetscInt d = 0; d < dim; ++d) g3[d * dim + d] = mu;
183*29e10dd4SMark Adams }
184*29e10dd4SMark Adams 
185*29e10dd4SMark Adams // Auxilary variable = -del^2 x, negative sign goes away from IBP
186*29e10dd4SMark Adams static void g3_n1(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 g3[])
187*29e10dd4SMark Adams {
188*29e10dd4SMark Adams   PetscInt d;
189*29e10dd4SMark Adams   for (d = 0; d < dim; ++d) g3[d * dim + d] = 1;
190*29e10dd4SMark Adams }
191*29e10dd4SMark Adams 
192*29e10dd4SMark Adams /* residual point methods */
193d71ae5a4SJacob Faibussowitsch static PetscScalar poissonBracket(PetscInt dim, const PetscScalar df[], const PetscScalar dg[])
194d71ae5a4SJacob Faibussowitsch {
195c4762a1bSJed Brown   PetscScalar ret = df[0] * dg[1] - df[1] * dg[0];
196*29e10dd4SMark Adams   if (dim == 3) {
197*29e10dd4SMark Adams     ret += df[1] * dg[2] - df[2] * dg[1];
198*29e10dd4SMark Adams     ret += df[2] * dg[0] - df[0] * dg[2];
199*29e10dd4SMark Adams   }
200c4762a1bSJed Brown   return ret;
201c4762a1bSJed Brown }
202*29e10dd4SMark Adams //
203d71ae5a4SJacob Faibussowitsch static void f0_Omega(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[])
204d71ae5a4SJacob Faibussowitsch {
205*29e10dd4SMark Adams   const PetscScalar *omegaDer = &u_x[uOff_x[OMEGA]];
206*29e10dd4SMark Adams   const PetscScalar *psiDer   = &u_x[uOff_x[PSI]];
207*29e10dd4SMark Adams   const PetscScalar *phiDer   = &u_x[uOff_x[PHI]];
208c4762a1bSJed Brown   const PetscScalar *jzDer    = &u_x[uOff_x[JZ]];
209c4762a1bSJed Brown 
210*29e10dd4SMark Adams   f0[0] += poissonBracket(dim, omegaDer, phiDer) - poissonBracket(dim, jzDer, psiDer);
211*29e10dd4SMark Adams 
212c4762a1bSJed Brown   if (u_t) f0[0] += u_t[OMEGA];
213c4762a1bSJed Brown }
214c4762a1bSJed Brown 
215d71ae5a4SJacob Faibussowitsch static void f1_Omega(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[])
216d71ae5a4SJacob Faibussowitsch {
217*29e10dd4SMark Adams   const PetscScalar *omegaDer = &u_x[uOff_x[OMEGA]];
218*29e10dd4SMark Adams   PetscReal          mu       = PetscRealPart(constants[MU_CONST]);
219c4762a1bSJed Brown 
220*29e10dd4SMark Adams   for (PetscInt d = 0; d < dim; ++d) f1[d] += mu * omegaDer[d];
221c4762a1bSJed Brown }
222c4762a1bSJed Brown 
223*29e10dd4SMark Adams // d/dt + {psi,phi} - eta j_z
224*29e10dd4SMark Adams static void f0_psi_4f(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[])
225d71ae5a4SJacob Faibussowitsch {
226*29e10dd4SMark Adams   const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
227*29e10dd4SMark Adams   const PetscScalar *phiDer = &u_x[uOff_x[PHI]];
228*29e10dd4SMark Adams   PetscReal          eta    = PetscRealPart(constants[ETA_CONST]);
229*29e10dd4SMark Adams 
230*29e10dd4SMark Adams   f0[0] = -eta * u[uOff[JZ]];
231*29e10dd4SMark Adams   f0[0] += poissonBracket(dim, psiDer, phiDer);
232*29e10dd4SMark Adams 
233c4762a1bSJed Brown   if (u_t) f0[0] += u_t[PSI];
234*29e10dd4SMark Adams   // printf("psiDer = %20.15e %20.15e psi = %20.15e
235c4762a1bSJed Brown }
236c4762a1bSJed Brown 
237*29e10dd4SMark Adams // d/dt - eta j_z
238*29e10dd4SMark Adams static void f0_psi_2f(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[])
239d71ae5a4SJacob Faibussowitsch {
240*29e10dd4SMark Adams   PetscReal eta = PetscRealPart(constants[ETA_CONST]);
241c4762a1bSJed Brown 
242*29e10dd4SMark Adams   f0[0] = -eta * u[uOff[JZ]];
243*29e10dd4SMark Adams 
244*29e10dd4SMark Adams   if (u_t) f0[0] += u_t[PSI];
245*29e10dd4SMark Adams   // printf("psiDer = %20.15e %20.15e psi = %20.15e
246c4762a1bSJed Brown }
247c4762a1bSJed Brown 
248d71ae5a4SJacob Faibussowitsch static void f0_phi(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[])
249d71ae5a4SJacob Faibussowitsch {
250*29e10dd4SMark Adams   f0[0] += u[uOff[OMEGA]];
251c4762a1bSJed Brown }
252c4762a1bSJed Brown 
253d71ae5a4SJacob Faibussowitsch static void f1_phi(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[])
254d71ae5a4SJacob Faibussowitsch {
255*29e10dd4SMark Adams   const PetscScalar *phiDer = &u_x[uOff_x[PHI]];
256c4762a1bSJed Brown 
257*29e10dd4SMark Adams   for (PetscInt d = 0; d < dim; ++d) f1[d] = phiDer[d];
258*29e10dd4SMark Adams }
259*29e10dd4SMark Adams 
260*29e10dd4SMark Adams /* - eta M */
261*29e10dd4SMark Adams static void g0_neta(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 g0[])
262*29e10dd4SMark Adams {
263*29e10dd4SMark Adams   PetscReal eta = PetscRealPart(constants[ETA_CONST]);
264*29e10dd4SMark Adams 
265*29e10dd4SMark Adams   g0[0] = -eta;
266c4762a1bSJed Brown }
267c4762a1bSJed Brown 
268d71ae5a4SJacob Faibussowitsch static void f0_jz(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[])
269d71ae5a4SJacob Faibussowitsch {
270c4762a1bSJed Brown   f0[0] = u[uOff[JZ]];
271c4762a1bSJed Brown }
272c4762a1bSJed Brown 
273*29e10dd4SMark Adams /* -del^2 psi = (grad v, grad psi) */
274d71ae5a4SJacob Faibussowitsch static void f1_jz(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[])
275d71ae5a4SJacob Faibussowitsch {
276*29e10dd4SMark Adams   const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
277c4762a1bSJed Brown 
278*29e10dd4SMark Adams   for (PetscInt d = 0; d < dim; ++d) f1[d] = psiDer[d];
279c4762a1bSJed Brown }
280c4762a1bSJed Brown 
281*29e10dd4SMark Adams static void f0_mhd_B_energy2(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)
282d71ae5a4SJacob Faibussowitsch {
283*29e10dd4SMark Adams   const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
284*29e10dd4SMark Adams   PetscScalar        b2     = 0;
285*29e10dd4SMark Adams   for (int i = 0; i < dim; ++i) b2 += psiDer[i] * psiDer[i];
286*29e10dd4SMark Adams   f0[0] = b2;
287c4762a1bSJed Brown }
288c4762a1bSJed Brown 
289*29e10dd4SMark Adams static void f0_mhd_v_energy2(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)
290*29e10dd4SMark Adams {
291*29e10dd4SMark Adams   const PetscScalar *phiDer = &u_x[uOff_x[PHI]];
292*29e10dd4SMark Adams   PetscScalar        v2     = 0;
293*29e10dd4SMark Adams   for (int i = 0; i < dim; ++i) v2 += phiDer[i] * phiDer[i];
294*29e10dd4SMark Adams   f0[0] = v2;
295*29e10dd4SMark Adams }
296*29e10dd4SMark Adams 
297*29e10dd4SMark Adams static PetscErrorCode Monitor(TS ts, PetscInt stepi, PetscReal time, Vec X, void *actx)
298*29e10dd4SMark Adams {
299*29e10dd4SMark Adams   AppCtx             *ctx = (AppCtx *)actx; /* user-defined application context */
300*29e10dd4SMark Adams   SNES                snes;
301*29e10dd4SMark Adams   SNESConvergedReason reason;
302*29e10dd4SMark Adams   TSConvergedReason   tsreason;
303*29e10dd4SMark Adams 
304*29e10dd4SMark Adams   PetscFunctionBegin;
305*29e10dd4SMark Adams   // PetscCall(TSGetApplicationContext(ts, &ctx));
306*29e10dd4SMark Adams   if (ctx->debug < 1) PetscFunctionReturn(PETSC_SUCCESS);
307*29e10dd4SMark Adams   PetscCall(TSGetSNES(ts, &snes));
308*29e10dd4SMark Adams   PetscCall(SNESGetConvergedReason(snes, &reason));
309*29e10dd4SMark Adams   if (reason < 0) {
310*29e10dd4SMark Adams     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "\t\t ***************** Monitor: SNES diverged with reason %d.\n", (int)reason));
3113ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
312c4762a1bSJed Brown   }
313*29e10dd4SMark Adams   if (stepi > ctx->plotStep && ctx->plotting) {
314*29e10dd4SMark Adams     ctx->plotting = PETSC_FALSE; /* was doing diagnostics, now done */
315*29e10dd4SMark Adams     ctx->plotIdx++;
316c4762a1bSJed Brown   }
317*29e10dd4SMark Adams   PetscCall(TSGetTime(ts, &time));
318*29e10dd4SMark Adams   PetscCall(TSGetConvergedReason(ts, &tsreason));
319*29e10dd4SMark Adams   if (((time - ctx->plotStartTime) / ctx->plotDt >= (PetscReal)ctx->plotIdx && time >= ctx->plotStartTime) || (tsreason == TS_CONVERGED_TIME || tsreason == TS_CONVERGED_ITS) || ctx->plotIdx == 0) {
320*29e10dd4SMark Adams     DM          dm, plex;
321c4762a1bSJed Brown     Vec         X;
322*29e10dd4SMark Adams     PetscReal   val;
323*29e10dd4SMark Adams     PetscScalar tt[12]; // FE integral seems to need a large array
324*29e10dd4SMark Adams     PetscDS     prob;
325*29e10dd4SMark Adams     if (!ctx->plotting) { /* first step of possible backtracks */
326*29e10dd4SMark Adams       ctx->plotting = PETSC_TRUE;
327*29e10dd4SMark Adams     } else {
328*29e10dd4SMark Adams       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\t\t ?????? ------\n"));
329*29e10dd4SMark Adams       ctx->plotting = PETSC_TRUE;
330*29e10dd4SMark Adams     }
331*29e10dd4SMark Adams     ctx->plotStep = stepi;
3329566063dSJacob Faibussowitsch     PetscCall(TSGetSolution(ts, &X));
3339566063dSJacob Faibussowitsch     PetscCall(VecGetDM(X, &dm));
334*29e10dd4SMark Adams     PetscCall(DMGetOutputSequenceNumber(dm, NULL, &val));
335*29e10dd4SMark Adams     PetscCall(DMSetOutputSequenceNumber(dm, ctx->plotIdx, val));
336*29e10dd4SMark Adams     PetscCall(VecViewFromOptions(X, NULL, "-vec_view_mhd"));
337*29e10dd4SMark Adams     if (ctx->debug > 2) {
338*29e10dd4SMark Adams       Vec R;
339*29e10dd4SMark Adams       PetscCall(SNESGetFunction(snes, &R, NULL, NULL));
340*29e10dd4SMark Adams       PetscCall(VecViewFromOptions(R, NULL, "-vec_view_res"));
341*29e10dd4SMark Adams     }
342*29e10dd4SMark Adams     // compute energy
343*29e10dd4SMark Adams     PetscCall(DMGetDS(dm, &prob));
3449566063dSJacob Faibussowitsch     PetscCall(DMConvert(dm, DMPLEX, &plex));
345*29e10dd4SMark Adams     PetscCall(PetscDSSetObjective(prob, 0, &f0_mhd_v_energy2));
346*29e10dd4SMark Adams     PetscCall(DMPlexComputeIntegralFEM(plex, X, &tt[0], ctx));
347*29e10dd4SMark Adams     val = PetscRealPart(tt[0]);
348*29e10dd4SMark Adams     PetscCall(PetscDSSetObjective(prob, 0, &f0_mhd_B_energy2));
349*29e10dd4SMark Adams     PetscCall(DMPlexComputeIntegralFEM(plex, X, &tt[0], ctx));
350*29e10dd4SMark Adams     val = PetscSqrtReal(val) * 0.5 + PetscSqrtReal(PetscRealPart(tt[0])) * 0.5;
351*29e10dd4SMark Adams     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "MHD %4d) time = %9.5g, Eergy= %20.13e (plot ID %d)\n", (int)ctx->plotIdx, (double)time, (double)val, (int)ctx->plotIdx));
352*29e10dd4SMark Adams     /* clean up */
3539566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&plex));
354c4762a1bSJed Brown   }
3553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
356c4762a1bSJed Brown }
357c4762a1bSJed Brown 
358*29e10dd4SMark Adams static PetscErrorCode CreateBCLabel(DM dm, const char name[])
359*29e10dd4SMark Adams {
360*29e10dd4SMark Adams   DMLabel label;
361*29e10dd4SMark Adams   PetscFunctionBeginUser;
362*29e10dd4SMark Adams   PetscCall(DMCreateLabel(dm, name));
363*29e10dd4SMark Adams   PetscCall(DMGetLabel(dm, name, &label));
364*29e10dd4SMark Adams   PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, label));
365*29e10dd4SMark Adams   PetscCall(DMPlexLabelComplete(dm, label));
366*29e10dd4SMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
367*29e10dd4SMark Adams }
368*29e10dd4SMark Adams // Create mesh, dim is set here
369d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *ctx, DM *dm)
370d71ae5a4SJacob Faibussowitsch {
371*29e10dd4SMark Adams   const char *filename = ctx->filename;
372*29e10dd4SMark Adams   size_t      len;
373*29e10dd4SMark Adams   char        buff[256];
374*29e10dd4SMark Adams   PetscMPIInt size;
375*29e10dd4SMark Adams   PetscInt    nface = 1;
376c4762a1bSJed Brown   PetscFunctionBeginUser;
377*29e10dd4SMark Adams   PetscCall(PetscStrlen(filename, &len));
378*29e10dd4SMark Adams   if (len) {
379*29e10dd4SMark Adams     PetscCall(DMPlexCreateFromFile(comm, filename, "", PETSC_TRUE, dm));
380*29e10dd4SMark Adams   } else {
3819566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm, dm));
3829566063dSJacob Faibussowitsch     PetscCall(DMSetType(*dm, DMPLEX));
383*29e10dd4SMark Adams   }
384*29e10dd4SMark Adams   PetscCallMPI(MPI_Comm_size(comm, &size));
385*29e10dd4SMark Adams   while (nface * nface < size) nface *= 2; // 2D
386*29e10dd4SMark Adams   if (nface < 2) nface = 2;
387*29e10dd4SMark Adams   PetscCall(PetscSNPrintf(buff, sizeof(buff), "-dm_plex_box_faces %d,%d -petscpartitioner_type simple", (int)nface, (int)nface));
388*29e10dd4SMark Adams   PetscCall(PetscOptionsInsertString(NULL, buff));
389*29e10dd4SMark Adams   PetscCall(PetscOptionsInsertString(NULL, "-dm_plex_box_lower -2,-2 -dm_plex_box_upper 2,2"));
3909566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(*dm));
391*29e10dd4SMark Adams   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
392*29e10dd4SMark Adams   PetscCall(DMGetDimension(*dm, &ctx->dim));
393*29e10dd4SMark Adams   {
394*29e10dd4SMark Adams     char      convType[256];
395*29e10dd4SMark Adams     PetscBool flg;
396*29e10dd4SMark Adams     PetscOptionsBegin(comm, "", "Mesh conversion options", "DMPLEX");
397*29e10dd4SMark Adams     PetscCall(PetscOptionsFList("-dm_plex_convert_type", "Convert DMPlex to another format", "mhd", DMList, DMPLEX, convType, 256, &flg));
398*29e10dd4SMark Adams     PetscOptionsEnd();
399*29e10dd4SMark Adams     if (flg) {
400*29e10dd4SMark Adams       DM dmConv;
401*29e10dd4SMark Adams       PetscCall(DMConvert(*dm, convType, &dmConv));
402*29e10dd4SMark Adams       if (dmConv) {
403*29e10dd4SMark Adams         PetscCall(DMDestroy(dm));
404*29e10dd4SMark Adams         *dm = dmConv;
405*29e10dd4SMark Adams       }
406*29e10dd4SMark Adams     }
407*29e10dd4SMark Adams   }
408*29e10dd4SMark Adams   PetscCall(DMLocalizeCoordinates(*dm)); /* needed for periodic */
409*29e10dd4SMark Adams   {
410*29e10dd4SMark Adams     PetscBool hasLabel;
411*29e10dd4SMark Adams     PetscCall(DMHasLabel(*dm, "marker", &hasLabel));
412*29e10dd4SMark Adams     if (!hasLabel) PetscCall(CreateBCLabel(*dm, "marker"));
413*29e10dd4SMark Adams   }
414*29e10dd4SMark Adams   PetscCall(PetscObjectSetName((PetscObject)*dm, "Mesh"));
415*29e10dd4SMark Adams   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view_mhd"));
416*29e10dd4SMark Adams   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view_res"));
41730602db0SMatthew G. Knepley 
4183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
419c4762a1bSJed Brown }
420c4762a1bSJed Brown 
421d71ae5a4SJacob Faibussowitsch static PetscErrorCode initialSolution_Omega(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
422d71ae5a4SJacob Faibussowitsch {
423c4762a1bSJed Brown   u[0] = 0.0;
4243ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
425c4762a1bSJed Brown }
426c4762a1bSJed Brown 
427*29e10dd4SMark Adams static PetscErrorCode initialSolution_Psi(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *a_ctx)
428d71ae5a4SJacob Faibussowitsch {
429c4762a1bSJed Brown   AppCtx   *ctx = (AppCtx *)a_ctx;
430*29e10dd4SMark Adams   PetscReal r   = 0, theta, cos_theta;
431*29e10dd4SMark Adams   // k = sp.jn_zeros(1, 1)[0]
432*29e10dd4SMark Adams   const PetscReal k = 3.8317059702075125;
433*29e10dd4SMark Adams   for (PetscInt i = 0; i < dim; i++) r += x[i] * x[i];
434*29e10dd4SMark Adams   r = PetscSqrtReal(r);
435*29e10dd4SMark Adams   // r = sqrt(dot(x,x))
436*29e10dd4SMark Adams   theta     = PetscAtan2Real(x[1], x[0]);
437*29e10dd4SMark Adams   cos_theta = PetscCosReal(theta);
438*29e10dd4SMark Adams   // f = conditional(gt(r, 1.0), outer_f, inner_f)
439*29e10dd4SMark Adams   if (r < 1.0) {
440*29e10dd4SMark Adams     // inner_f =
441*29e10dd4SMark Adams     // (2/(Constant(k)*bessel_J(0,Constant(k))))*bessel_J(1,Constant(k)*r)*cos_theta
442*29e10dd4SMark Adams     u[0] = 2.0 / (k * j0(k)) * j1(k * r) * cos_theta;
443*29e10dd4SMark Adams   } else {
444*29e10dd4SMark Adams     // outer_f =  (1/r - r)*cos_theta
445*29e10dd4SMark Adams     u[0] = (r - 1.0 / r) * cos_theta;
446*29e10dd4SMark Adams   }
447*29e10dd4SMark Adams   u[0] += ctx->perturb * ((double)rand() / (double)RAND_MAX - 0.5);
4483ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
449c4762a1bSJed Brown }
450c4762a1bSJed Brown 
451*29e10dd4SMark Adams static PetscErrorCode initialSolution_Phi(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
452d71ae5a4SJacob Faibussowitsch {
453c4762a1bSJed Brown   u[0] = 0.0;
4543ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
455c4762a1bSJed Brown }
456c4762a1bSJed Brown 
457*29e10dd4SMark Adams static PetscErrorCode initialSolution_Jz(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
458d71ae5a4SJacob Faibussowitsch {
459c4762a1bSJed Brown   u[0] = 0.0;
4603ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
461c4762a1bSJed Brown }
462c4762a1bSJed Brown 
463*29e10dd4SMark Adams static PetscErrorCode SetupProblem(PetscDS prob, DM dm, AppCtx *ctx)
464d71ae5a4SJacob Faibussowitsch {
465c4762a1bSJed Brown   PetscInt f;
466c4762a1bSJed Brown 
4677510d9b0SBarry Smith   PetscFunctionBeginUser;
468*29e10dd4SMark Adams   // for both 2 & 4 field (j_z is same)
469*29e10dd4SMark Adams   PetscCall(PetscDSSetJacobian(prob, JZ, JZ, g0_1, NULL, NULL, NULL));
470*29e10dd4SMark Adams   PetscCall(PetscDSSetJacobian(prob, JZ, PSI, NULL, NULL, NULL, g3_n1));
471*29e10dd4SMark Adams   PetscCall(PetscDSSetResidual(prob, JZ, f0_jz, f1_jz));
472*29e10dd4SMark Adams 
473*29e10dd4SMark Adams   PetscCall(PetscDSSetJacobian(prob, PSI, JZ, g0_neta, NULL, NULL, NULL));
474*29e10dd4SMark Adams   if (ctx->modelType == ONE_FILD) {
475*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, PSI, PSI, g0_dt, NULL, NULL,
476*29e10dd4SMark Adams                                  NULL)); // remove phi term
477*29e10dd4SMark Adams 
478*29e10dd4SMark Adams     PetscCall(PetscDSSetResidual(prob, PSI, f0_psi_2f, NULL));
479*29e10dd4SMark Adams   } else {
480*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, PSI, PSI, g0_dt, g1_phi_right, NULL, NULL));
481*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, PSI, PHI, NULL, g1_psi_left, NULL, NULL));
482*29e10dd4SMark Adams     PetscCall(PetscDSSetResidual(prob, PSI, f0_psi_4f, NULL));
483*29e10dd4SMark Adams 
484*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, PHI, PHI, NULL, NULL, NULL, g3_n1));
485*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, PHI, OMEGA, g0_1, NULL, NULL, NULL));
486*29e10dd4SMark Adams     PetscCall(PetscDSSetResidual(prob, PHI, f0_phi, f1_phi));
487*29e10dd4SMark Adams 
488*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, OMEGA, OMEGA, g0_dt, g1_phi_right, NULL, g3_nmu));
489*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, OMEGA, PSI, NULL, g1_njz_left, NULL, NULL));
490*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, OMEGA, PHI, NULL, g1_omega_left, NULL, NULL));
491*29e10dd4SMark Adams     PetscCall(PetscDSSetJacobian(prob, OMEGA, JZ, NULL, g1_npsi_right, NULL, NULL));
492*29e10dd4SMark Adams     PetscCall(PetscDSSetResidual(prob, OMEGA, f0_Omega, f1_Omega));
493*29e10dd4SMark Adams   }
494*29e10dd4SMark Adams   /* Setup constants - is this persistant? */
495*29e10dd4SMark Adams   {
496*29e10dd4SMark Adams     PetscScalar scales[NUM_CONSTS]; // +1 adding in testType for use in the f
497*29e10dd4SMark Adams                                     // and g functions
498*29e10dd4SMark Adams     /* These could be set from the command line */
499*29e10dd4SMark Adams     scales[MU_CONST]  = ctx->mu;
500*29e10dd4SMark Adams     scales[ETA_CONST] = ctx->eta;
501*29e10dd4SMark Adams     // scales[TEST_CONST] = (PetscReal)ctx->testType; -- how to make work with complex
502*29e10dd4SMark Adams     PetscCall(PetscDSSetConstants(prob, NUM_CONSTS, scales));
503*29e10dd4SMark Adams   }
504*29e10dd4SMark Adams   for (f = 0; f < ctx->Nf; ++f) {
505*29e10dd4SMark Adams     ctx->initialFuncs[f] = NULL;
506*29e10dd4SMark Adams     PetscCall(PetscDSSetImplicit(prob, f, PETSC_TRUE));
507*29e10dd4SMark Adams   }
508*29e10dd4SMark Adams   if (ctx->testType == TEST_TILT) {
509*29e10dd4SMark Adams     const PetscInt id = 1;
510*29e10dd4SMark Adams     DMLabel        label;
511*29e10dd4SMark Adams     PetscCall(DMGetLabel(dm, "marker", &label));
512*29e10dd4SMark Adams 
513*29e10dd4SMark Adams     ctx->initialFuncs[JZ]  = initialSolution_Jz;
514*29e10dd4SMark Adams     ctx->initialFuncs[PSI] = initialSolution_Psi;
515*29e10dd4SMark Adams 
516*29e10dd4SMark Adams     PetscCall(PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "Jz for tilt test", label, 1, &id, JZ, 0, NULL, (void (*)(void))initialSolution_Jz, NULL, ctx, NULL));
517*29e10dd4SMark Adams     PetscCall(PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "Psi for tilt test", label, 1, &id, PSI, 0, NULL, (void (*)(void))initialSolution_Psi, NULL, ctx, NULL));
518*29e10dd4SMark Adams     if (ctx->modelType == TWO_FILD) {
519*29e10dd4SMark Adams       ctx->initialFuncs[OMEGA] = initialSolution_Omega;
520*29e10dd4SMark Adams       ctx->initialFuncs[PHI]   = initialSolution_Phi;
521*29e10dd4SMark Adams       PetscCall(PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "Omega for tilt test", label, 1, &id, OMEGA, 0, NULL, (void (*)(void))initialSolution_Omega, NULL, ctx, NULL));
522*29e10dd4SMark Adams       PetscCall(PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "Phi for tilt test", label, 1, &id, PHI, 0, NULL, (void (*)(void))initialSolution_Phi, NULL, ctx, NULL));
523*29e10dd4SMark Adams     }
524*29e10dd4SMark Adams   } else {
525*29e10dd4SMark Adams     PetscCheck(0, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Unsupported test type: %s (%d)", testTypes[PetscMin(ctx->testType, NUM_TEST_TYPES)], (int)ctx->testType);
526*29e10dd4SMark Adams   }
527*29e10dd4SMark Adams   PetscCall(PetscDSSetContext(prob, 0, ctx));
528*29e10dd4SMark Adams   PetscCall(PetscDSSetFromOptions(prob));
5293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
530c4762a1bSJed Brown }
531c4762a1bSJed Brown 
532d71ae5a4SJacob Faibussowitsch static PetscErrorCode SetupDiscretization(DM dm, AppCtx *ctx)
533d71ae5a4SJacob Faibussowitsch {
534*29e10dd4SMark Adams   DM             cdm;
535*29e10dd4SMark Adams   const PetscInt dim = ctx->dim;
536*29e10dd4SMark Adams   PetscFE        fe[NUM_COMP];
537*29e10dd4SMark Adams   PetscDS        prob;
538*29e10dd4SMark Adams   PetscInt       Nf           = ctx->Nf, f;
539*29e10dd4SMark Adams   PetscBool      cell_simplex = PETSC_TRUE;
540*29e10dd4SMark Adams   MPI_Comm       comm         = PetscObjectComm((PetscObject)dm);
541c4762a1bSJed Brown 
542c4762a1bSJed Brown   PetscFunctionBeginUser;
543c4762a1bSJed Brown   /* Create finite element */
544*29e10dd4SMark Adams   PetscCall(PetscFECreateDefault(comm, dim, 1, cell_simplex, NULL, -1, &fe[JZ]));
545*29e10dd4SMark Adams   PetscCall(PetscObjectSetName((PetscObject)fe[JZ], "j_z"));
546*29e10dd4SMark Adams   PetscCall(DMSetField(dm, JZ, NULL, (PetscObject)fe[JZ]));
547*29e10dd4SMark Adams   PetscCall(PetscFECreateDefault(comm, dim, 1, cell_simplex, NULL, -1, &fe[PSI]));
548*29e10dd4SMark Adams   PetscCall(PetscObjectSetName((PetscObject)fe[PSI], "psi"));
549*29e10dd4SMark Adams   PetscCall(DMSetField(dm, PSI, NULL, (PetscObject)fe[PSI]));
550*29e10dd4SMark Adams   if (ctx->modelType == TWO_FILD) {
551*29e10dd4SMark Adams     PetscCall(PetscFECreateDefault(comm, dim, 1, cell_simplex, NULL, -1, &fe[OMEGA]));
552*29e10dd4SMark Adams     PetscCall(PetscObjectSetName((PetscObject)fe[OMEGA], "Omega"));
553*29e10dd4SMark Adams     PetscCall(DMSetField(dm, OMEGA, NULL, (PetscObject)fe[OMEGA]));
554c4762a1bSJed Brown 
555*29e10dd4SMark Adams     PetscCall(PetscFECreateDefault(comm, dim, 1, cell_simplex, NULL, -1, &fe[PHI]));
556*29e10dd4SMark Adams     PetscCall(PetscObjectSetName((PetscObject)fe[PHI], "phi"));
557*29e10dd4SMark Adams     PetscCall(DMSetField(dm, PHI, NULL, (PetscObject)fe[PHI]));
558*29e10dd4SMark Adams   }
559c4762a1bSJed Brown   /* Set discretization and boundary conditions for each mesh */
5609566063dSJacob Faibussowitsch   PetscCall(DMCreateDS(dm));
561*29e10dd4SMark Adams   PetscCall(DMGetDS(dm, &prob));
562*29e10dd4SMark Adams   for (f = 0; f < Nf; ++f) PetscCall(PetscDSSetDiscretization(prob, f, (PetscObject)fe[f]));
563*29e10dd4SMark Adams   PetscCall(SetupProblem(prob, dm, ctx));
564*29e10dd4SMark Adams   cdm = dm;
565c4762a1bSJed Brown   while (cdm) {
5669566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(dm, cdm));
567*29e10dd4SMark Adams     if (dm != cdm) PetscCall(PetscObjectSetName((PetscObject)cdm, "Coarse"));
5689566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(cdm, &cdm));
569c4762a1bSJed Brown   }
5709566063dSJacob Faibussowitsch   for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&fe[f]));
5713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
572c4762a1bSJed Brown }
573c4762a1bSJed Brown 
574d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
575d71ae5a4SJacob Faibussowitsch {
576c4762a1bSJed Brown   DM          dm;
577c4762a1bSJed Brown   TS          ts;
578c4762a1bSJed Brown   Vec         u, r;
579c4762a1bSJed Brown   AppCtx      ctx;
580c4762a1bSJed Brown   PetscReal   t        = 0.0;
581*29e10dd4SMark Adams   AppCtx     *ctxarr[] = {&ctx, &ctx, &ctx, &ctx}; // each variable could have a different context
582*29e10dd4SMark Adams   PetscMPIInt rank;
583c4762a1bSJed Brown 
5849566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
585*29e10dd4SMark Adams   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
586*29e10dd4SMark Adams   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &ctx)); // dim is not set
587c4762a1bSJed Brown   /* create mesh and problem */
5889566063dSJacob Faibussowitsch   PetscCall(CreateMesh(PETSC_COMM_WORLD, &ctx, &dm));
589*29e10dd4SMark Adams   PetscCall(DMView(dm, PETSC_VIEWER_STDOUT_WORLD));
5909566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dm, &ctx));
591*29e10dd4SMark Adams   PetscCall(PetscMalloc1(ctx.Nf, &ctx.initialFuncs));
5929566063dSJacob Faibussowitsch   PetscCall(SetupDiscretization(dm, &ctx));
5939566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(dm, &u));
5949566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)u, "u"));
5959566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(u, &r));
5969566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)r, "r"));
597c4762a1bSJed Brown   /* create TS */
5989566063dSJacob Faibussowitsch   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
5999566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, dm));
6009566063dSJacob Faibussowitsch   PetscCall(TSSetApplicationContext(ts, &ctx));
6019566063dSJacob Faibussowitsch   PetscCall(DMTSSetBoundaryLocal(dm, DMPlexTSComputeBoundary, &ctx));
6029566063dSJacob Faibussowitsch   PetscCall(DMTSSetIFunctionLocal(dm, DMPlexTSComputeIFunctionFEM, &ctx));
6039566063dSJacob Faibussowitsch   PetscCall(DMTSSetIJacobianLocal(dm, DMPlexTSComputeIJacobianFEM, &ctx));
6049566063dSJacob Faibussowitsch   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
605*29e10dd4SMark Adams   PetscCall(TSSetMaxTime(ts, 15.0));
6069566063dSJacob Faibussowitsch   PetscCall(TSSetFromOptions(ts));
607*29e10dd4SMark Adams   PetscCall(TSMonitorSet(ts, Monitor, &ctx, NULL));
608*29e10dd4SMark Adams   /* make solution */
6099566063dSJacob Faibussowitsch   PetscCall(DMProjectFunction(dm, t, ctx.initialFuncs, (void **)ctxarr, INSERT_ALL_VALUES, u));
610*29e10dd4SMark Adams   ctx.perturb = 0.0;
6119566063dSJacob Faibussowitsch   PetscCall(TSSetSolution(ts, u));
612*29e10dd4SMark Adams   // solve
6139566063dSJacob Faibussowitsch   PetscCall(TSSolve(ts, u));
614*29e10dd4SMark Adams   // cleanup
6159566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&u));
6169566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
6179566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
6189566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
6199566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx.initialFuncs));
6209566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
621b122ec5aSJacob Faibussowitsch   return 0;
622c4762a1bSJed Brown }
623c4762a1bSJed Brown 
624c4762a1bSJed Brown /*TEST
625c4762a1bSJed Brown 
626c4762a1bSJed Brown   test:
627c4762a1bSJed Brown     suffix: 0
628*29e10dd4SMark Adams     requires: triangle !complex
629*29e10dd4SMark Adams     nsize: 4
630*29e10dd4SMark Adams     args: -dm_plex_box_lower -2,-2 -dm_plex_box_upper 2,2 -dm_plex_simplex 1 -dm_refine_hierarchy 2 \
631*29e10dd4SMark Adams       -eta 0.0001 -ksp_converged_reason -ksp_max_it 50 -ksp_rtol 1e-3 -ksp_type fgmres -mg_coarse_ksp_rtol 1e-1 \
632*29e10dd4SMark Adams       -mg_coarse_ksp_type fgmres -mg_coarse_mg_levels_ksp_type gmres -mg_coarse_pc_type gamg -mg_levels_ksp_max_it 4 \
633*29e10dd4SMark Adams       -mg_levels_ksp_type gmres -mg_levels_pc_type jacobi -mu 0.005 -pc_mg_type full -pc_type mg \
634*29e10dd4SMark Adams       -petscpartitioner_type simple -petscspace_degree 2 -snes_converged_reason -snes_max_it 10 -snes_monitor \
635*29e10dd4SMark Adams       -snes_rtol 1.e-9 -snes_stol 1.e-9 -ts_adapt_dt_max 0.01 -ts_adapt_monitor -ts_arkimex_type 1bee \
636*29e10dd4SMark Adams       -ts_dt 0.001 -ts_max_reject 10 -ts_max_snes_failures -1 -ts_max_steps 1 -ts_max_time -ts_monitor -ts_type arkimex
637*29e10dd4SMark Adams     filter: grep -v DM_
638c4762a1bSJed Brown 
639c4762a1bSJed Brown TEST*/
640