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