129e10dd4SMark Adams static char help[] = "Magnetohydrodynamics (MHD) with Poisson brackets and "
229e10dd4SMark Adams "stream functions, solver testbed for M3D-C1. Used in https://arxiv.org/abs/2302.10242";
3c4762a1bSJed Brown
4c4762a1bSJed Brown /*F
529e10dd4SMark Adams The strong form of a two field model for vorticity $\Omega$ and magnetic flux
629e10dd4SMark Adams $\psi$, using auxiliary variables potential $\phi$ and (negative) current
729e10dd4SMark Adams density $j_z$ \cite{Jardin04,Strauss98}.See http://arxiv.org/abs/ for more details
8c4762a1bSJed Brown F*/
9c4762a1bSJed Brown
1029e10dd4SMark Adams #include <assert.h>
11c4762a1bSJed Brown #include <petscdmplex.h>
12c4762a1bSJed Brown #include <petscds.h>
1329e10dd4SMark Adams #include <petscts.h>
1429e10dd4SMark Adams
1529e10dd4SMark Adams typedef enum _testidx {
1629e10dd4SMark Adams TEST_TILT,
1729e10dd4SMark Adams NUM_TEST_TYPES
1829e10dd4SMark Adams } TestType;
1929e10dd4SMark Adams const char *testTypes[NUM_TEST_TYPES + 1] = {"tilt", "unknown"};
2029e10dd4SMark Adams typedef enum _modelidx {
2129e10dd4SMark Adams TWO_FILD,
2229e10dd4SMark Adams ONE_FILD,
2329e10dd4SMark Adams NUM_MODELS
2429e10dd4SMark Adams } ModelType;
2529e10dd4SMark Adams const char *modelTypes[NUM_MODELS + 1] = {"two-field", "one-field", "unknown"};
2629e10dd4SMark Adams typedef enum _fieldidx {
2729e10dd4SMark Adams JZ,
2829e10dd4SMark Adams PSI,
2929e10dd4SMark Adams PHI,
3029e10dd4SMark Adams OMEGA,
3129e10dd4SMark Adams NUM_COMP
3229e10dd4SMark Adams } FieldIdx; // add more
3329e10dd4SMark Adams typedef enum _const_idx {
3429e10dd4SMark Adams MU_CONST,
3529e10dd4SMark Adams ETA_CONST,
3629e10dd4SMark Adams TEST_CONST,
3729e10dd4SMark Adams NUM_CONSTS
3829e10dd4SMark Adams } ConstIdx;
39c4762a1bSJed Brown
40c4762a1bSJed Brown typedef struct {
41c4762a1bSJed Brown PetscInt debug; /* The debugging level */
4229e10dd4SMark Adams PetscReal plotDt;
4329e10dd4SMark Adams PetscReal plotStartTime;
4429e10dd4SMark Adams PetscInt plotIdx;
4529e10dd4SMark Adams PetscInt plotStep;
4629e10dd4SMark Adams PetscBool plotting;
4729e10dd4SMark Adams PetscInt dim; /* The topological mesh dimension */
4829e10dd4SMark Adams char filename[PETSC_MAX_PATH_LEN]; /* The optional ExodusII file */
49*2a8381b2SBarry Smith PetscErrorCode (**initialFuncs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, PetscCtx ctx);
5029e10dd4SMark Adams PetscReal mu, eta;
5129e10dd4SMark Adams PetscReal perturb;
5229e10dd4SMark Adams TestType testType;
5329e10dd4SMark Adams ModelType modelType;
5429e10dd4SMark Adams PetscInt Nf;
55c4762a1bSJed Brown } AppCtx;
56c4762a1bSJed Brown
ProcessOptions(MPI_Comm comm,AppCtx * options)5729e10dd4SMark Adams static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options)
5829e10dd4SMark Adams {
5929e10dd4SMark Adams PetscInt ii;
60c4762a1bSJed Brown
6129e10dd4SMark Adams PetscFunctionBeginUser;
6229e10dd4SMark Adams options->debug = 1;
6329e10dd4SMark Adams options->filename[0] = '\0';
6429e10dd4SMark Adams options->testType = TEST_TILT;
6529e10dd4SMark Adams options->modelType = TWO_FILD;
6629e10dd4SMark Adams options->mu = 0.005;
6729e10dd4SMark Adams options->eta = 0.001;
6829e10dd4SMark Adams options->perturb = 0;
6929e10dd4SMark Adams options->plotDt = 0.1;
7029e10dd4SMark Adams options->plotStartTime = 0.0;
7129e10dd4SMark Adams options->plotIdx = 0;
721690c2aeSBarry Smith options->plotStep = PETSC_INT_MAX;
7329e10dd4SMark Adams options->plotting = PETSC_FALSE;
7429e10dd4SMark Adams
7529e10dd4SMark Adams PetscOptionsBegin(comm, "", "MHD Problem Options", "DMPLEX");
7629e10dd4SMark Adams PetscCall(PetscOptionsInt("-debug", "The debugging level", "mhd.c", options->debug, &options->debug, NULL));
7729e10dd4SMark Adams ii = (PetscInt)options->testType;
7829e10dd4SMark Adams options->testType = TEST_TILT;
7929e10dd4SMark Adams ii = options->testType;
8029e10dd4SMark Adams PetscCall(PetscOptionsEList("-test_type", "The test type: 'tilt' Tilt instability", "mhd.c", testTypes, NUM_TEST_TYPES, testTypes[options->testType], &ii, NULL));
8129e10dd4SMark Adams options->testType = (TestType)ii;
8229e10dd4SMark Adams ii = (PetscInt)options->modelType;
8329e10dd4SMark Adams options->modelType = TWO_FILD;
8429e10dd4SMark Adams ii = options->modelType;
8529e10dd4SMark Adams PetscCall(PetscOptionsEList("-model_type", "The model type: 'two', 'one' field", "mhd.c", modelTypes, NUM_MODELS, modelTypes[options->modelType], &ii, NULL));
8629e10dd4SMark Adams options->modelType = (ModelType)ii;
8729e10dd4SMark Adams options->Nf = options->modelType == TWO_FILD ? 4 : 2;
8829e10dd4SMark Adams
8929e10dd4SMark Adams PetscCall(PetscOptionsReal("-mu", "Magnetic resistivity", "mhd.c", options->mu, &options->mu, NULL));
9029e10dd4SMark Adams PetscCall(PetscOptionsReal("-eta", "Viscosity", "mhd.c", options->eta, &options->eta, NULL));
9129e10dd4SMark Adams PetscCall(PetscOptionsReal("-plot_dt", "Plot frequency in time", "mhd.c", options->plotDt, &options->plotDt, NULL));
9229e10dd4SMark Adams PetscCall(PetscOptionsReal("-plot_start_time", "Time to delay start of plotting", "mhd.c", options->plotStartTime, &options->plotStartTime, NULL));
9329e10dd4SMark Adams PetscCall(PetscOptionsReal("-perturbation", "Random perturbation of initial psi scale", "mhd.c", options->perturb, &options->perturb, NULL));
9429e10dd4SMark Adams PetscCall(PetscPrintf(comm, "Test Type = %s\n", testTypes[options->testType]));
9529e10dd4SMark Adams PetscCall(PetscPrintf(comm, "Model Type = %s\n", modelTypes[options->modelType]));
9629e10dd4SMark Adams PetscCall(PetscPrintf(comm, "eta = %g\n", (double)options->eta));
9729e10dd4SMark Adams PetscCall(PetscPrintf(comm, "mu = %g\n", (double)options->mu));
9829e10dd4SMark Adams PetscOptionsEnd();
9929e10dd4SMark Adams PetscFunctionReturn(PETSC_SUCCESS);
10029e10dd4SMark Adams }
10129e10dd4SMark Adams
10229e10dd4SMark Adams // | 0 1 | matrix to apply bracket
10329e10dd4SMark Adams // |-1 0 |
10429e10dd4SMark Adams static PetscReal s_K[2][2] = {
10529e10dd4SMark Adams {0, 1},
10629e10dd4SMark Adams {-1, 0}
10729e10dd4SMark Adams };
10829e10dd4SMark Adams
10929e10dd4SMark Adams /*
11029e10dd4SMark Adams dt - "g0" are mass terms
11129e10dd4SMark Adams */
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[])11229e10dd4SMark 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[])
11329e10dd4SMark Adams {
11429e10dd4SMark Adams g0[0] = u_tShift;
11529e10dd4SMark Adams }
11629e10dd4SMark Adams
11729e10dd4SMark Adams /*
11829e10dd4SMark Adams Identity, Mass
11929e10dd4SMark Adams */
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[])12029e10dd4SMark 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[])
12129e10dd4SMark Adams {
12229e10dd4SMark Adams g0[0] = 1;
12329e10dd4SMark Adams }
12429e10dd4SMark Adams /* 'right' Poisson bracket -<.,phi>, linearized variable is left (column), data
12529e10dd4SMark Adams * variable right */
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[])12629e10dd4SMark 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[])
12729e10dd4SMark Adams {
12829e10dd4SMark Adams PetscInt i, j;
12929e10dd4SMark Adams const PetscScalar *pphiDer = &u_x[uOff_x[PHI]]; // get derivative of the 'right' ("dg") and apply to
13029e10dd4SMark Adams // live var "df"
13129e10dd4SMark Adams for (i = 0; i < dim; ++i)
13229e10dd4SMark Adams for (j = 0; j < dim; ++j)
13329e10dd4SMark Adams // indexing with inner, j, index generates the left live variable [dy,-]
134aaa8cc7dSPierre Jolivet // by convention, put j index on right, with i destination: [ d/dy,
13529e10dd4SMark Adams // -d/dx]'
13629e10dd4SMark Adams g1[i] += s_K[i][j] * pphiDer[j];
13729e10dd4SMark Adams }
13829e10dd4SMark Adams /* 'left' bracket -{jz,.}, "n" for negative, linearized variable right (column),
13929e10dd4SMark Adams * data variable left */
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[])14029e10dd4SMark 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[])
14129e10dd4SMark Adams {
14229e10dd4SMark Adams PetscInt i, j;
14329e10dd4SMark Adams const PetscScalar *jzDer = &u_x[uOff_x[JZ]]; // get derivative of the 'left' ("df") and apply to live
14429e10dd4SMark Adams // var "dg"
14529e10dd4SMark Adams for (i = 0; i < dim; ++i)
14629e10dd4SMark Adams for (j = 0; j < dim; ++j)
14729e10dd4SMark Adams // live right: Der[i] * K: Der[j] --> j: [d/dy, -d/dx]'
14829e10dd4SMark Adams g1[j] += -jzDer[i] * s_K[i][j];
14929e10dd4SMark Adams }
15029e10dd4SMark Adams /* 'left' Poisson bracket -< . , psi> */
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[])15129e10dd4SMark 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[])
15229e10dd4SMark Adams {
15329e10dd4SMark Adams PetscInt i, j;
15429e10dd4SMark Adams const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
15529e10dd4SMark Adams for (i = 0; i < dim; ++i)
15629e10dd4SMark Adams for (j = 0; j < dim; ++j) g1[i] += -s_K[i][j] * psiDer[j];
15729e10dd4SMark Adams }
15829e10dd4SMark Adams
15929e10dd4SMark Adams /* < Omega , . > */
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[])16029e10dd4SMark 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[])
16129e10dd4SMark Adams {
16229e10dd4SMark Adams PetscInt i, j;
16329e10dd4SMark Adams const PetscScalar *pOmegaDer = &u_x[uOff_x[OMEGA]];
16429e10dd4SMark Adams for (i = 0; i < dim; ++i)
16529e10dd4SMark Adams for (j = 0; j < dim; ++j) g1[j] += pOmegaDer[i] * s_K[i][j];
16629e10dd4SMark Adams }
16729e10dd4SMark Adams
16829e10dd4SMark Adams /* < psi , . > */
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[])16929e10dd4SMark 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[])
17029e10dd4SMark Adams {
17129e10dd4SMark Adams PetscInt i, j;
17229e10dd4SMark Adams const PetscScalar *pPsiDer = &u_x[uOff_x[PSI]];
17329e10dd4SMark Adams for (i = 0; i < dim; ++i)
17429e10dd4SMark Adams for (j = 0; j < dim; ++j) g1[j] += pPsiDer[i] * s_K[i][j];
17529e10dd4SMark Adams }
17629e10dd4SMark Adams
17729e10dd4SMark Adams // -Lapacians (resistivity), negative sign goes away from IBP
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[])17829e10dd4SMark 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[])
17929e10dd4SMark Adams {
18029e10dd4SMark Adams PetscReal mu = PetscRealPart(constants[MU_CONST]);
18129e10dd4SMark Adams for (PetscInt d = 0; d < dim; ++d) g3[d * dim + d] = mu;
18229e10dd4SMark Adams }
18329e10dd4SMark Adams
184aaa8cc7dSPierre Jolivet // Auxiliary variable = -del^2 x, negative sign goes away from IBP
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[])18529e10dd4SMark 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[])
18629e10dd4SMark Adams {
18729e10dd4SMark Adams PetscInt d;
18829e10dd4SMark Adams for (d = 0; d < dim; ++d) g3[d * dim + d] = 1;
18929e10dd4SMark Adams }
19029e10dd4SMark Adams
19129e10dd4SMark Adams /* residual point methods */
poissonBracket(PetscInt dim,const PetscScalar df[],const PetscScalar dg[])192d71ae5a4SJacob Faibussowitsch static PetscScalar poissonBracket(PetscInt dim, const PetscScalar df[], const PetscScalar dg[])
193d71ae5a4SJacob Faibussowitsch {
194c4762a1bSJed Brown PetscScalar ret = df[0] * dg[1] - df[1] * dg[0];
19529e10dd4SMark Adams if (dim == 3) {
19629e10dd4SMark Adams ret += df[1] * dg[2] - df[2] * dg[1];
19729e10dd4SMark Adams ret += df[2] * dg[0] - df[0] * dg[2];
19829e10dd4SMark Adams }
199c4762a1bSJed Brown return ret;
200c4762a1bSJed Brown }
20129e10dd4SMark Adams //
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[])202d71ae5a4SJacob 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[])
203d71ae5a4SJacob Faibussowitsch {
20429e10dd4SMark Adams const PetscScalar *omegaDer = &u_x[uOff_x[OMEGA]];
20529e10dd4SMark Adams const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
20629e10dd4SMark Adams const PetscScalar *phiDer = &u_x[uOff_x[PHI]];
207c4762a1bSJed Brown const PetscScalar *jzDer = &u_x[uOff_x[JZ]];
208c4762a1bSJed Brown
20929e10dd4SMark Adams f0[0] += poissonBracket(dim, omegaDer, phiDer) - poissonBracket(dim, jzDer, psiDer);
21029e10dd4SMark Adams
211c4762a1bSJed Brown if (u_t) f0[0] += u_t[OMEGA];
212c4762a1bSJed Brown }
213c4762a1bSJed Brown
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[])214d71ae5a4SJacob 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[])
215d71ae5a4SJacob Faibussowitsch {
21629e10dd4SMark Adams const PetscScalar *omegaDer = &u_x[uOff_x[OMEGA]];
21729e10dd4SMark Adams PetscReal mu = PetscRealPart(constants[MU_CONST]);
218c4762a1bSJed Brown
21929e10dd4SMark Adams for (PetscInt d = 0; d < dim; ++d) f1[d] += mu * omegaDer[d];
220c4762a1bSJed Brown }
221c4762a1bSJed Brown
22229e10dd4SMark Adams // d/dt + {psi,phi} - eta j_z
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[])22329e10dd4SMark 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[])
224d71ae5a4SJacob Faibussowitsch {
22529e10dd4SMark Adams const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
22629e10dd4SMark Adams const PetscScalar *phiDer = &u_x[uOff_x[PHI]];
22729e10dd4SMark Adams PetscReal eta = PetscRealPart(constants[ETA_CONST]);
22829e10dd4SMark Adams
22929e10dd4SMark Adams f0[0] = -eta * u[uOff[JZ]];
23029e10dd4SMark Adams f0[0] += poissonBracket(dim, psiDer, phiDer);
23129e10dd4SMark Adams
232c4762a1bSJed Brown if (u_t) f0[0] += u_t[PSI];
23329e10dd4SMark Adams // printf("psiDer = %20.15e %20.15e psi = %20.15e
234c4762a1bSJed Brown }
235c4762a1bSJed Brown
23629e10dd4SMark Adams // d/dt - eta j_z
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[])23729e10dd4SMark 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[])
238d71ae5a4SJacob Faibussowitsch {
23929e10dd4SMark Adams PetscReal eta = PetscRealPart(constants[ETA_CONST]);
240c4762a1bSJed Brown
24129e10dd4SMark Adams f0[0] = -eta * u[uOff[JZ]];
24229e10dd4SMark Adams
24329e10dd4SMark Adams if (u_t) f0[0] += u_t[PSI];
24429e10dd4SMark Adams // printf("psiDer = %20.15e %20.15e psi = %20.15e
245c4762a1bSJed Brown }
246c4762a1bSJed Brown
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[])247d71ae5a4SJacob 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[])
248d71ae5a4SJacob Faibussowitsch {
24929e10dd4SMark Adams f0[0] += u[uOff[OMEGA]];
250c4762a1bSJed Brown }
251c4762a1bSJed Brown
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[])252d71ae5a4SJacob 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[])
253d71ae5a4SJacob Faibussowitsch {
25429e10dd4SMark Adams const PetscScalar *phiDer = &u_x[uOff_x[PHI]];
255c4762a1bSJed Brown
25629e10dd4SMark Adams for (PetscInt d = 0; d < dim; ++d) f1[d] = phiDer[d];
25729e10dd4SMark Adams }
25829e10dd4SMark Adams
25929e10dd4SMark Adams /* - eta M */
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[])26029e10dd4SMark 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[])
26129e10dd4SMark Adams {
26229e10dd4SMark Adams PetscReal eta = PetscRealPart(constants[ETA_CONST]);
26329e10dd4SMark Adams
26429e10dd4SMark Adams g0[0] = -eta;
265c4762a1bSJed Brown }
266c4762a1bSJed Brown
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[])267d71ae5a4SJacob 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[])
268d71ae5a4SJacob Faibussowitsch {
269c4762a1bSJed Brown f0[0] = u[uOff[JZ]];
270c4762a1bSJed Brown }
271c4762a1bSJed Brown
27229e10dd4SMark Adams /* -del^2 psi = (grad v, grad psi) */
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[])273d71ae5a4SJacob 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[])
274d71ae5a4SJacob Faibussowitsch {
27529e10dd4SMark Adams const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
276c4762a1bSJed Brown
27729e10dd4SMark Adams for (PetscInt d = 0; d < dim; ++d) f1[d] = psiDer[d];
278c4762a1bSJed Brown }
279c4762a1bSJed Brown
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)28029e10dd4SMark 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)
281d71ae5a4SJacob Faibussowitsch {
28229e10dd4SMark Adams const PetscScalar *psiDer = &u_x[uOff_x[PSI]];
28329e10dd4SMark Adams PetscScalar b2 = 0;
28429e10dd4SMark Adams for (int i = 0; i < dim; ++i) b2 += psiDer[i] * psiDer[i];
28529e10dd4SMark Adams f0[0] = b2;
286c4762a1bSJed Brown }
287c4762a1bSJed Brown
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)28829e10dd4SMark 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)
28929e10dd4SMark Adams {
29029e10dd4SMark Adams const PetscScalar *phiDer = &u_x[uOff_x[PHI]];
29129e10dd4SMark Adams PetscScalar v2 = 0;
29229e10dd4SMark Adams for (int i = 0; i < dim; ++i) v2 += phiDer[i] * phiDer[i];
29329e10dd4SMark Adams f0[0] = v2;
29429e10dd4SMark Adams }
29529e10dd4SMark Adams
Monitor(TS ts,PetscInt stepi,PetscReal time,Vec X,void * actx)29629e10dd4SMark Adams static PetscErrorCode Monitor(TS ts, PetscInt stepi, PetscReal time, Vec X, void *actx)
29729e10dd4SMark Adams {
29829e10dd4SMark Adams AppCtx *ctx = (AppCtx *)actx; /* user-defined application context */
29929e10dd4SMark Adams SNES snes;
30029e10dd4SMark Adams SNESConvergedReason reason;
30129e10dd4SMark Adams TSConvergedReason tsreason;
30229e10dd4SMark Adams
30329e10dd4SMark Adams PetscFunctionBegin;
30429e10dd4SMark Adams // PetscCall(TSGetApplicationContext(ts, &ctx));
30529e10dd4SMark Adams if (ctx->debug < 1) PetscFunctionReturn(PETSC_SUCCESS);
30629e10dd4SMark Adams PetscCall(TSGetSNES(ts, &snes));
30729e10dd4SMark Adams PetscCall(SNESGetConvergedReason(snes, &reason));
30829e10dd4SMark Adams if (reason < 0) {
30929e10dd4SMark Adams PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "\t\t ***************** Monitor: SNES diverged with reason %d.\n", (int)reason));
3103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
311c4762a1bSJed Brown }
31229e10dd4SMark Adams if (stepi > ctx->plotStep && ctx->plotting) {
31329e10dd4SMark Adams ctx->plotting = PETSC_FALSE; /* was doing diagnostics, now done */
31429e10dd4SMark Adams ctx->plotIdx++;
315c4762a1bSJed Brown }
31629e10dd4SMark Adams PetscCall(TSGetTime(ts, &time));
31729e10dd4SMark Adams PetscCall(TSGetConvergedReason(ts, &tsreason));
31829e10dd4SMark Adams if (((time - ctx->plotStartTime) / ctx->plotDt >= (PetscReal)ctx->plotIdx && time >= ctx->plotStartTime) || (tsreason == TS_CONVERGED_TIME || tsreason == TS_CONVERGED_ITS) || ctx->plotIdx == 0) {
31929e10dd4SMark Adams DM dm, plex;
320c4762a1bSJed Brown Vec X;
32129e10dd4SMark Adams PetscReal val;
32229e10dd4SMark Adams PetscScalar tt[12]; // FE integral seems to need a large array
32329e10dd4SMark Adams PetscDS prob;
32429e10dd4SMark Adams if (!ctx->plotting) { /* first step of possible backtracks */
32529e10dd4SMark Adams ctx->plotting = PETSC_TRUE;
32629e10dd4SMark Adams } else {
32729e10dd4SMark Adams PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\t\t ?????? ------\n"));
32829e10dd4SMark Adams ctx->plotting = PETSC_TRUE;
32929e10dd4SMark Adams }
33029e10dd4SMark Adams ctx->plotStep = stepi;
3319566063dSJacob Faibussowitsch PetscCall(TSGetSolution(ts, &X));
3329566063dSJacob Faibussowitsch PetscCall(VecGetDM(X, &dm));
33329e10dd4SMark Adams PetscCall(DMGetOutputSequenceNumber(dm, NULL, &val));
33429e10dd4SMark Adams PetscCall(DMSetOutputSequenceNumber(dm, ctx->plotIdx, val));
33529e10dd4SMark Adams PetscCall(VecViewFromOptions(X, NULL, "-vec_view_mhd"));
33629e10dd4SMark Adams if (ctx->debug > 2) {
33729e10dd4SMark Adams Vec R;
33829e10dd4SMark Adams PetscCall(SNESGetFunction(snes, &R, NULL, NULL));
33929e10dd4SMark Adams PetscCall(VecViewFromOptions(R, NULL, "-vec_view_res"));
34029e10dd4SMark Adams }
34129e10dd4SMark Adams // compute energy
34229e10dd4SMark Adams PetscCall(DMGetDS(dm, &prob));
3439566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, &plex));
34429e10dd4SMark Adams PetscCall(PetscDSSetObjective(prob, 0, &f0_mhd_v_energy2));
34529e10dd4SMark Adams PetscCall(DMPlexComputeIntegralFEM(plex, X, &tt[0], ctx));
34629e10dd4SMark Adams val = PetscRealPart(tt[0]);
34729e10dd4SMark Adams PetscCall(PetscDSSetObjective(prob, 0, &f0_mhd_B_energy2));
34829e10dd4SMark Adams PetscCall(DMPlexComputeIntegralFEM(plex, X, &tt[0], ctx));
34929e10dd4SMark Adams val = PetscSqrtReal(val) * 0.5 + PetscSqrtReal(PetscRealPart(tt[0])) * 0.5;
35029e10dd4SMark 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));
35129e10dd4SMark Adams /* clean up */
3529566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex));
353c4762a1bSJed Brown }
3543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
355c4762a1bSJed Brown }
356c4762a1bSJed Brown
CreateBCLabel(DM dm,const char name[])35729e10dd4SMark Adams static PetscErrorCode CreateBCLabel(DM dm, const char name[])
35829e10dd4SMark Adams {
35929e10dd4SMark Adams DMLabel label;
3604d86920dSPierre Jolivet
36129e10dd4SMark Adams PetscFunctionBeginUser;
36229e10dd4SMark Adams PetscCall(DMCreateLabel(dm, name));
36329e10dd4SMark Adams PetscCall(DMGetLabel(dm, name, &label));
36429e10dd4SMark Adams PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, label));
36529e10dd4SMark Adams PetscCall(DMPlexLabelComplete(dm, label));
36629e10dd4SMark Adams PetscFunctionReturn(PETSC_SUCCESS);
36729e10dd4SMark Adams }
36829e10dd4SMark Adams // Create mesh, dim is set here
CreateMesh(MPI_Comm comm,AppCtx * ctx,DM * dm)369d71ae5a4SJacob Faibussowitsch static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *ctx, DM *dm)
370d71ae5a4SJacob Faibussowitsch {
37129e10dd4SMark Adams const char *filename = ctx->filename;
37229e10dd4SMark Adams size_t len;
37329e10dd4SMark Adams char buff[256];
37429e10dd4SMark Adams PetscMPIInt size;
37529e10dd4SMark Adams PetscInt nface = 1;
3764d86920dSPierre Jolivet
377c4762a1bSJed Brown PetscFunctionBeginUser;
37829e10dd4SMark Adams PetscCall(PetscStrlen(filename, &len));
37929e10dd4SMark Adams if (len) {
38029e10dd4SMark Adams PetscCall(DMPlexCreateFromFile(comm, filename, "", PETSC_TRUE, dm));
38129e10dd4SMark Adams } else {
3829566063dSJacob Faibussowitsch PetscCall(DMCreate(comm, dm));
3839566063dSJacob Faibussowitsch PetscCall(DMSetType(*dm, DMPLEX));
38429e10dd4SMark Adams }
38529e10dd4SMark Adams PetscCallMPI(MPI_Comm_size(comm, &size));
38629e10dd4SMark Adams while (nface * nface < size) nface *= 2; // 2D
38729e10dd4SMark Adams if (nface < 2) nface = 2;
38829e10dd4SMark Adams PetscCall(PetscSNPrintf(buff, sizeof(buff), "-dm_plex_box_faces %d,%d -petscpartitioner_type simple", (int)nface, (int)nface));
38929e10dd4SMark Adams PetscCall(PetscOptionsInsertString(NULL, buff));
39029e10dd4SMark Adams PetscCall(PetscOptionsInsertString(NULL, "-dm_plex_box_lower -2,-2 -dm_plex_box_upper 2,2"));
3919566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(*dm));
39229e10dd4SMark Adams PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
39329e10dd4SMark Adams PetscCall(DMGetDimension(*dm, &ctx->dim));
39429e10dd4SMark Adams {
39529e10dd4SMark Adams char convType[256];
39629e10dd4SMark Adams PetscBool flg;
39729e10dd4SMark Adams PetscOptionsBegin(comm, "", "Mesh conversion options", "DMPLEX");
39829e10dd4SMark Adams PetscCall(PetscOptionsFList("-dm_plex_convert_type", "Convert DMPlex to another format", "mhd", DMList, DMPLEX, convType, 256, &flg));
39929e10dd4SMark Adams PetscOptionsEnd();
40029e10dd4SMark Adams if (flg) {
40129e10dd4SMark Adams DM dmConv;
40229e10dd4SMark Adams PetscCall(DMConvert(*dm, convType, &dmConv));
40329e10dd4SMark Adams if (dmConv) {
40429e10dd4SMark Adams PetscCall(DMDestroy(dm));
40529e10dd4SMark Adams *dm = dmConv;
40629e10dd4SMark Adams }
40729e10dd4SMark Adams }
40829e10dd4SMark Adams }
40929e10dd4SMark Adams PetscCall(DMLocalizeCoordinates(*dm)); /* needed for periodic */
41029e10dd4SMark Adams {
41129e10dd4SMark Adams PetscBool hasLabel;
41229e10dd4SMark Adams PetscCall(DMHasLabel(*dm, "marker", &hasLabel));
41329e10dd4SMark Adams if (!hasLabel) PetscCall(CreateBCLabel(*dm, "marker"));
41429e10dd4SMark Adams }
41529e10dd4SMark Adams PetscCall(PetscObjectSetName((PetscObject)*dm, "Mesh"));
41629e10dd4SMark Adams PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view_mhd"));
41729e10dd4SMark Adams PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view_res"));
4183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
419c4762a1bSJed Brown }
420c4762a1bSJed Brown
initialSolution_Omega(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar * u,PetscCtx ctx)421*2a8381b2SBarry Smith static PetscErrorCode initialSolution_Omega(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, PetscCtx ctx)
422d71ae5a4SJacob Faibussowitsch {
423c4762a1bSJed Brown u[0] = 0.0;
4243ba16761SJacob Faibussowitsch return PETSC_SUCCESS;
425c4762a1bSJed Brown }
426c4762a1bSJed Brown
initialSolution_Psi(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar * u,void * a_ctx)42729e10dd4SMark 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;
43029e10dd4SMark Adams PetscReal r = 0, theta, cos_theta;
43129e10dd4SMark Adams // k = sp.jn_zeros(1, 1)[0]
43229e10dd4SMark Adams const PetscReal k = 3.8317059702075125;
43329e10dd4SMark Adams for (PetscInt i = 0; i < dim; i++) r += x[i] * x[i];
43429e10dd4SMark Adams r = PetscSqrtReal(r);
43529e10dd4SMark Adams // r = sqrt(dot(x,x))
43629e10dd4SMark Adams theta = PetscAtan2Real(x[1], x[0]);
43729e10dd4SMark Adams cos_theta = PetscCosReal(theta);
43829e10dd4SMark Adams // f = conditional(gt(r, 1.0), outer_f, inner_f)
43929e10dd4SMark Adams if (r < 1.0) {
44029e10dd4SMark Adams // inner_f =
44129e10dd4SMark Adams // (2/(Constant(k)*bessel_J(0,Constant(k))))*bessel_J(1,Constant(k)*r)*cos_theta
44229e10dd4SMark Adams u[0] = 2.0 / (k * j0(k)) * j1(k * r) * cos_theta;
44329e10dd4SMark Adams } else {
44429e10dd4SMark Adams // outer_f = (1/r - r)*cos_theta
44529e10dd4SMark Adams u[0] = (r - 1.0 / r) * cos_theta;
44629e10dd4SMark Adams }
44729e10dd4SMark Adams u[0] += ctx->perturb * ((double)rand() / (double)RAND_MAX - 0.5);
4483ba16761SJacob Faibussowitsch return PETSC_SUCCESS;
449c4762a1bSJed Brown }
450c4762a1bSJed Brown
initialSolution_Phi(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar * u,PetscCtx ctx)451*2a8381b2SBarry Smith static PetscErrorCode initialSolution_Phi(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, PetscCtx ctx)
452d71ae5a4SJacob Faibussowitsch {
453c4762a1bSJed Brown u[0] = 0.0;
4543ba16761SJacob Faibussowitsch return PETSC_SUCCESS;
455c4762a1bSJed Brown }
456c4762a1bSJed Brown
initialSolution_Jz(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nf,PetscScalar * u,PetscCtx ctx)457*2a8381b2SBarry Smith static PetscErrorCode initialSolution_Jz(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, PetscCtx ctx)
458d71ae5a4SJacob Faibussowitsch {
459c4762a1bSJed Brown u[0] = 0.0;
4603ba16761SJacob Faibussowitsch return PETSC_SUCCESS;
461c4762a1bSJed Brown }
462c4762a1bSJed Brown
SetupProblem(PetscDS prob,DM dm,AppCtx * ctx)46329e10dd4SMark Adams static PetscErrorCode SetupProblem(PetscDS prob, DM dm, AppCtx *ctx)
464d71ae5a4SJacob Faibussowitsch {
465c4762a1bSJed Brown PetscInt f;
466c4762a1bSJed Brown
4677510d9b0SBarry Smith PetscFunctionBeginUser;
46829e10dd4SMark Adams // for both 2 & 4 field (j_z is same)
46929e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, JZ, JZ, g0_1, NULL, NULL, NULL));
47029e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, JZ, PSI, NULL, NULL, NULL, g3_n1));
47129e10dd4SMark Adams PetscCall(PetscDSSetResidual(prob, JZ, f0_jz, f1_jz));
47229e10dd4SMark Adams
47329e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, PSI, JZ, g0_neta, NULL, NULL, NULL));
47429e10dd4SMark Adams if (ctx->modelType == ONE_FILD) {
47529e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, PSI, PSI, g0_dt, NULL, NULL,
47629e10dd4SMark Adams NULL)); // remove phi term
47729e10dd4SMark Adams
47829e10dd4SMark Adams PetscCall(PetscDSSetResidual(prob, PSI, f0_psi_2f, NULL));
47929e10dd4SMark Adams } else {
48029e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, PSI, PSI, g0_dt, g1_phi_right, NULL, NULL));
48129e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, PSI, PHI, NULL, g1_psi_left, NULL, NULL));
48229e10dd4SMark Adams PetscCall(PetscDSSetResidual(prob, PSI, f0_psi_4f, NULL));
48329e10dd4SMark Adams
48429e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, PHI, PHI, NULL, NULL, NULL, g3_n1));
48529e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, PHI, OMEGA, g0_1, NULL, NULL, NULL));
48629e10dd4SMark Adams PetscCall(PetscDSSetResidual(prob, PHI, f0_phi, f1_phi));
48729e10dd4SMark Adams
48829e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, OMEGA, OMEGA, g0_dt, g1_phi_right, NULL, g3_nmu));
48929e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, OMEGA, PSI, NULL, g1_njz_left, NULL, NULL));
49029e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, OMEGA, PHI, NULL, g1_omega_left, NULL, NULL));
49129e10dd4SMark Adams PetscCall(PetscDSSetJacobian(prob, OMEGA, JZ, NULL, g1_npsi_right, NULL, NULL));
49229e10dd4SMark Adams PetscCall(PetscDSSetResidual(prob, OMEGA, f0_Omega, f1_Omega));
49329e10dd4SMark Adams }
494aaa8cc7dSPierre Jolivet /* Setup constants - is this persistent? */
49529e10dd4SMark Adams {
49629e10dd4SMark Adams PetscScalar scales[NUM_CONSTS]; // +1 adding in testType for use in the f
49729e10dd4SMark Adams // and g functions
49829e10dd4SMark Adams /* These could be set from the command line */
49929e10dd4SMark Adams scales[MU_CONST] = ctx->mu;
50029e10dd4SMark Adams scales[ETA_CONST] = ctx->eta;
50129e10dd4SMark Adams // scales[TEST_CONST] = (PetscReal)ctx->testType; -- how to make work with complex
50229e10dd4SMark Adams PetscCall(PetscDSSetConstants(prob, NUM_CONSTS, scales));
50329e10dd4SMark Adams }
50429e10dd4SMark Adams for (f = 0; f < ctx->Nf; ++f) {
50529e10dd4SMark Adams ctx->initialFuncs[f] = NULL;
50629e10dd4SMark Adams PetscCall(PetscDSSetImplicit(prob, f, PETSC_TRUE));
50729e10dd4SMark Adams }
50829e10dd4SMark Adams if (ctx->testType == TEST_TILT) {
50929e10dd4SMark Adams const PetscInt id = 1;
51029e10dd4SMark Adams DMLabel label;
51129e10dd4SMark Adams PetscCall(DMGetLabel(dm, "marker", &label));
51229e10dd4SMark Adams
51329e10dd4SMark Adams ctx->initialFuncs[JZ] = initialSolution_Jz;
51429e10dd4SMark Adams ctx->initialFuncs[PSI] = initialSolution_Psi;
51529e10dd4SMark Adams
51657d50842SBarry Smith PetscCall(PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "Jz for tilt test", label, 1, &id, JZ, 0, NULL, (PetscVoidFn *)initialSolution_Jz, NULL, ctx, NULL));
51757d50842SBarry Smith PetscCall(PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "Psi for tilt test", label, 1, &id, PSI, 0, NULL, (PetscVoidFn *)initialSolution_Psi, NULL, ctx, NULL));
51829e10dd4SMark Adams if (ctx->modelType == TWO_FILD) {
51929e10dd4SMark Adams ctx->initialFuncs[OMEGA] = initialSolution_Omega;
52029e10dd4SMark Adams ctx->initialFuncs[PHI] = initialSolution_Phi;
52157d50842SBarry Smith PetscCall(PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "Omega for tilt test", label, 1, &id, OMEGA, 0, NULL, (PetscVoidFn *)initialSolution_Omega, NULL, ctx, NULL));
52257d50842SBarry Smith PetscCall(PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "Phi for tilt test", label, 1, &id, PHI, 0, NULL, (PetscVoidFn *)initialSolution_Phi, NULL, ctx, NULL));
52329e10dd4SMark Adams }
52429e10dd4SMark Adams } else {
52529e10dd4SMark 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);
52629e10dd4SMark Adams }
52729e10dd4SMark Adams PetscCall(PetscDSSetContext(prob, 0, ctx));
52829e10dd4SMark Adams PetscCall(PetscDSSetFromOptions(prob));
5293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
530c4762a1bSJed Brown }
531c4762a1bSJed Brown
SetupDiscretization(DM dm,AppCtx * ctx)532d71ae5a4SJacob Faibussowitsch static PetscErrorCode SetupDiscretization(DM dm, AppCtx *ctx)
533d71ae5a4SJacob Faibussowitsch {
53429e10dd4SMark Adams DM cdm;
53529e10dd4SMark Adams const PetscInt dim = ctx->dim;
53629e10dd4SMark Adams PetscFE fe[NUM_COMP];
53729e10dd4SMark Adams PetscDS prob;
53829e10dd4SMark Adams PetscInt Nf = ctx->Nf, f;
53929e10dd4SMark Adams PetscBool cell_simplex = PETSC_TRUE;
54029e10dd4SMark Adams MPI_Comm comm = PetscObjectComm((PetscObject)dm);
541c4762a1bSJed Brown
542c4762a1bSJed Brown PetscFunctionBeginUser;
543c4762a1bSJed Brown /* Create finite element */
54429e10dd4SMark Adams PetscCall(PetscFECreateDefault(comm, dim, 1, cell_simplex, NULL, -1, &fe[JZ]));
54529e10dd4SMark Adams PetscCall(PetscObjectSetName((PetscObject)fe[JZ], "j_z"));
54629e10dd4SMark Adams PetscCall(DMSetField(dm, JZ, NULL, (PetscObject)fe[JZ]));
54729e10dd4SMark Adams PetscCall(PetscFECreateDefault(comm, dim, 1, cell_simplex, NULL, -1, &fe[PSI]));
54829e10dd4SMark Adams PetscCall(PetscObjectSetName((PetscObject)fe[PSI], "psi"));
54929e10dd4SMark Adams PetscCall(DMSetField(dm, PSI, NULL, (PetscObject)fe[PSI]));
55029e10dd4SMark Adams if (ctx->modelType == TWO_FILD) {
55129e10dd4SMark Adams PetscCall(PetscFECreateDefault(comm, dim, 1, cell_simplex, NULL, -1, &fe[OMEGA]));
55229e10dd4SMark Adams PetscCall(PetscObjectSetName((PetscObject)fe[OMEGA], "Omega"));
55329e10dd4SMark Adams PetscCall(DMSetField(dm, OMEGA, NULL, (PetscObject)fe[OMEGA]));
554c4762a1bSJed Brown
55529e10dd4SMark Adams PetscCall(PetscFECreateDefault(comm, dim, 1, cell_simplex, NULL, -1, &fe[PHI]));
55629e10dd4SMark Adams PetscCall(PetscObjectSetName((PetscObject)fe[PHI], "phi"));
55729e10dd4SMark Adams PetscCall(DMSetField(dm, PHI, NULL, (PetscObject)fe[PHI]));
55829e10dd4SMark Adams }
559c4762a1bSJed Brown /* Set discretization and boundary conditions for each mesh */
5609566063dSJacob Faibussowitsch PetscCall(DMCreateDS(dm));
56129e10dd4SMark Adams PetscCall(DMGetDS(dm, &prob));
56229e10dd4SMark Adams for (f = 0; f < Nf; ++f) PetscCall(PetscDSSetDiscretization(prob, f, (PetscObject)fe[f]));
56329e10dd4SMark Adams PetscCall(SetupProblem(prob, dm, ctx));
56429e10dd4SMark Adams cdm = dm;
565c4762a1bSJed Brown while (cdm) {
5669566063dSJacob Faibussowitsch PetscCall(DMCopyDisc(dm, cdm));
56729e10dd4SMark 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
main(int argc,char ** argv)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;
58129e10dd4SMark Adams AppCtx *ctxarr[] = {&ctx, &ctx, &ctx, &ctx}; // each variable could have a different context
58229e10dd4SMark Adams PetscMPIInt rank;
583c4762a1bSJed Brown
5849566063dSJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, NULL, help));
58529e10dd4SMark Adams PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
58629e10dd4SMark 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));
58929e10dd4SMark Adams PetscCall(DMView(dm, PETSC_VIEWER_STDOUT_WORLD));
5909566063dSJacob Faibussowitsch PetscCall(DMSetApplicationContext(dm, &ctx));
59129e10dd4SMark 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));
60529e10dd4SMark Adams PetscCall(TSSetMaxTime(ts, 15.0));
6069566063dSJacob Faibussowitsch PetscCall(TSSetFromOptions(ts));
60729e10dd4SMark Adams PetscCall(TSMonitorSet(ts, Monitor, &ctx, NULL));
60829e10dd4SMark Adams /* make solution */
6099566063dSJacob Faibussowitsch PetscCall(DMProjectFunction(dm, t, ctx.initialFuncs, (void **)ctxarr, INSERT_ALL_VALUES, u));
61029e10dd4SMark Adams ctx.perturb = 0.0;
6119566063dSJacob Faibussowitsch PetscCall(TSSetSolution(ts, u));
61229e10dd4SMark Adams // solve
6139566063dSJacob Faibussowitsch PetscCall(TSSolve(ts, u));
61429e10dd4SMark 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
62829e10dd4SMark Adams requires: triangle !complex
62929e10dd4SMark Adams nsize: 4
63029e10dd4SMark Adams args: -dm_plex_box_lower -2,-2 -dm_plex_box_upper 2,2 -dm_plex_simplex 1 -dm_refine_hierarchy 2 \
63129e10dd4SMark Adams -eta 0.0001 -ksp_converged_reason -ksp_max_it 50 -ksp_rtol 1e-3 -ksp_type fgmres -mg_coarse_ksp_rtol 1e-1 \
63229e10dd4SMark Adams -mg_coarse_ksp_type fgmres -mg_coarse_mg_levels_ksp_type gmres -mg_coarse_pc_type gamg -mg_levels_ksp_max_it 4 \
63329e10dd4SMark Adams -mg_levels_ksp_type gmres -mg_levels_pc_type jacobi -mu 0.005 -pc_mg_type full -pc_type mg \
63429e10dd4SMark Adams -petscpartitioner_type simple -petscspace_degree 2 -snes_converged_reason -snes_max_it 10 -snes_monitor \
63529e10dd4SMark Adams -snes_rtol 1.e-9 -snes_stol 1.e-9 -ts_adapt_dt_max 0.01 -ts_adapt_monitor -ts_arkimex_type 1bee \
636188af4bfSBarry Smith -ts_time_step 0.001 -ts_max_step_rejections 10 -ts_max_snes_failures unlimited -ts_max_steps 1 -ts_max_time -ts_monitor -ts_type arkimex
63729e10dd4SMark Adams filter: grep -v DM_
638c4762a1bSJed Brown
639c4762a1bSJed Brown TEST*/
640