1c4762a1bSJed Brown static char help[] = "Heat Equation in 2d and 3d with finite elements.\n\ 2c4762a1bSJed Brown We solve the heat equation in a rectangular\n\ 3c4762a1bSJed Brown domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\ 4c4762a1bSJed Brown Contributed by: Julian Andrej <juan@tf.uni-kiel.de>\n\n\n"; 5c4762a1bSJed Brown 6c4762a1bSJed Brown #include <petscdmplex.h> 7c4762a1bSJed Brown #include <petscds.h> 8c4762a1bSJed Brown #include <petscts.h> 9c4762a1bSJed Brown 10c4762a1bSJed Brown /* 11c4762a1bSJed Brown Heat equation: 12c4762a1bSJed Brown 13*a3d0cf85SMatthew G. Knepley du/dt - \Delta u + f = 0 14c4762a1bSJed Brown */ 15c4762a1bSJed Brown 16*a3d0cf85SMatthew G. Knepley typedef enum {SOL_QUADRATIC_LINEAR, SOL_QUADRATIC_TRIG, SOL_TRIG_LINEAR, NUM_SOLUTION_TYPES} SolutionType; 17*a3d0cf85SMatthew G. Knepley const char *solutionTypes[NUM_SOLUTION_TYPES+1] = {"quadratic_linear", "quadratic_trig", "trig_linear", "unknown"}; 18*a3d0cf85SMatthew G. Knepley 19c4762a1bSJed Brown typedef struct { 20*a3d0cf85SMatthew G. Knepley char filename[PETSC_MAX_PATH_LEN]; /* Mesh filename */ 21*a3d0cf85SMatthew G. Knepley char bdfilename[PETSC_MAX_PATH_LEN]; /* Mesh boundary filename */ 22*a3d0cf85SMatthew G. Knepley PetscReal scale; /* Scale factor for mesh */ 23*a3d0cf85SMatthew G. Knepley SolutionType solType; /* Type of exact solution */ 24c4762a1bSJed Brown } AppCtx; 25c4762a1bSJed Brown 26*a3d0cf85SMatthew G. Knepley /* 27*a3d0cf85SMatthew G. Knepley Exact 2D solution: 28*a3d0cf85SMatthew G. Knepley u = 2t + x^2 + y^2 29*a3d0cf85SMatthew G. Knepley F(u) = 2 - (2 + 2) + 2 = 0 30*a3d0cf85SMatthew G. Knepley 31*a3d0cf85SMatthew G. Knepley Exact 3D solution: 32*a3d0cf85SMatthew G. Knepley u = 3t + x^2 + y^2 + z^2 33*a3d0cf85SMatthew G. Knepley F(u) = 3 - (2 + 2 + 2) + 3 = 0 34*a3d0cf85SMatthew G. Knepley */ 35*a3d0cf85SMatthew G. Knepley static PetscErrorCode mms_quad_lin(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 36c4762a1bSJed Brown { 37c4762a1bSJed Brown PetscInt d; 38c4762a1bSJed Brown 39c4762a1bSJed Brown *u = dim*time; 40c4762a1bSJed Brown for (d = 0; d < dim; ++d) *u += x[d]*x[d]; 41c4762a1bSJed Brown return 0; 42c4762a1bSJed Brown } 43c4762a1bSJed Brown 44*a3d0cf85SMatthew G. Knepley static PetscErrorCode mms_quad_lin_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 45*a3d0cf85SMatthew G. Knepley { 46*a3d0cf85SMatthew G. Knepley *u = dim; 47*a3d0cf85SMatthew G. Knepley return 0; 48*a3d0cf85SMatthew G. Knepley } 49*a3d0cf85SMatthew G. Knepley 50*a3d0cf85SMatthew G. Knepley static void f0_quad_lin(PetscInt dim, PetscInt Nf, PetscInt NfAux, 51c4762a1bSJed Brown const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 52c4762a1bSJed Brown const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 53c4762a1bSJed Brown PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 54c4762a1bSJed Brown { 55c4762a1bSJed Brown f0[0] = u_t[0] + (PetscScalar) dim; 56c4762a1bSJed Brown } 57c4762a1bSJed Brown 58*a3d0cf85SMatthew G. Knepley /* 59*a3d0cf85SMatthew G. Knepley Exact 2D solution: 60*a3d0cf85SMatthew G. Knepley u = 2*cos(t) + x^2 + y^2 61*a3d0cf85SMatthew G. Knepley F(u) = -2*sint(t) - (2 + 2) + 2*sin(t) + 4 = 0 62*a3d0cf85SMatthew G. Knepley 63*a3d0cf85SMatthew G. Knepley Exact 3D solution: 64*a3d0cf85SMatthew G. Knepley u = 3*cos(t) + x^2 + y^2 + z^2 65*a3d0cf85SMatthew G. Knepley F(u) = -3*sin(t) - (2 + 2 + 2) + 3*sin(t) + 6 = 0 66*a3d0cf85SMatthew G. Knepley */ 67*a3d0cf85SMatthew G. Knepley static PetscErrorCode mms_quad_trig(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 68*a3d0cf85SMatthew G. Knepley { 69*a3d0cf85SMatthew G. Knepley PetscInt d; 70*a3d0cf85SMatthew G. Knepley 71*a3d0cf85SMatthew G. Knepley *u = dim*PetscCosReal(time); 72*a3d0cf85SMatthew G. Knepley for (d = 0; d < dim; ++d) *u += x[d]*x[d]; 73*a3d0cf85SMatthew G. Knepley return 0; 74*a3d0cf85SMatthew G. Knepley } 75*a3d0cf85SMatthew G. Knepley 76*a3d0cf85SMatthew G. Knepley static PetscErrorCode mms_quad_trig_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 77*a3d0cf85SMatthew G. Knepley { 78*a3d0cf85SMatthew G. Knepley *u = -dim*PetscSinReal(time); 79*a3d0cf85SMatthew G. Knepley return 0; 80*a3d0cf85SMatthew G. Knepley } 81*a3d0cf85SMatthew G. Knepley 82*a3d0cf85SMatthew G. Knepley static void f0_quad_trig(PetscInt dim, PetscInt Nf, PetscInt NfAux, 83*a3d0cf85SMatthew G. Knepley const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 84*a3d0cf85SMatthew G. Knepley const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 85*a3d0cf85SMatthew G. Knepley PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 86*a3d0cf85SMatthew G. Knepley { 87*a3d0cf85SMatthew G. Knepley f0[0] = u_t[0] + dim*(PetscSinReal(t) + 2.0); 88*a3d0cf85SMatthew G. Knepley } 89*a3d0cf85SMatthew G. Knepley 90*a3d0cf85SMatthew G. Knepley /* 91*a3d0cf85SMatthew G. Knepley Exact 2D solution: 92*a3d0cf85SMatthew G. Knepley u = 2\pi^2 t + cos(\pi x) + cos(\pi y) 93*a3d0cf85SMatthew G. Knepley F(u) = 2\pi^2 - \pi^2 (cos(\pi x) + cos(\pi y)) + \pi^2 (cos(\pi x) + cos(\pi y)) - 2\pi^2 = 0 94*a3d0cf85SMatthew G. Knepley 95*a3d0cf85SMatthew G. Knepley Exact 3D solution: 96*a3d0cf85SMatthew G. Knepley u = 3\pi^2 t + cos(\pi x) + cos(\pi y) + cos(\pi z) 97*a3d0cf85SMatthew G. Knepley F(u) = 3\pi^2 - \pi^2 (cos(\pi x) + cos(\pi y) + cos(\pi z)) + \pi^2 (cos(\pi x) + cos(\pi y) + cos(\pi z)) - 3\pi^2 = 0 98*a3d0cf85SMatthew G. Knepley */ 99*a3d0cf85SMatthew G. Knepley static PetscErrorCode mms_trig_lin(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 100*a3d0cf85SMatthew G. Knepley { 101*a3d0cf85SMatthew G. Knepley PetscInt d; 102*a3d0cf85SMatthew G. Knepley 103*a3d0cf85SMatthew G. Knepley *u = dim*PetscSqr(PETSC_PI)*time; 104*a3d0cf85SMatthew G. Knepley for (d = 0; d < dim; ++d) *u += PetscCosReal(PETSC_PI*x[d]); 105*a3d0cf85SMatthew G. Knepley return 0; 106*a3d0cf85SMatthew G. Knepley } 107*a3d0cf85SMatthew G. Knepley 108*a3d0cf85SMatthew G. Knepley static PetscErrorCode mms_trig_lin_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 109*a3d0cf85SMatthew G. Knepley { 110*a3d0cf85SMatthew G. Knepley *u = dim*PetscSqr(PETSC_PI); 111*a3d0cf85SMatthew G. Knepley return 0; 112*a3d0cf85SMatthew G. Knepley } 113*a3d0cf85SMatthew G. Knepley 114*a3d0cf85SMatthew G. Knepley static void f0_trig_lin(PetscInt dim, PetscInt Nf, PetscInt NfAux, 115*a3d0cf85SMatthew G. Knepley const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 116*a3d0cf85SMatthew G. Knepley const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 117*a3d0cf85SMatthew G. Knepley PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 118*a3d0cf85SMatthew G. Knepley { 119*a3d0cf85SMatthew G. Knepley PetscInt d; 120*a3d0cf85SMatthew G. Knepley f0[0] = u_t[0]; 121*a3d0cf85SMatthew G. Knepley for (d = 0; d < dim; ++d) f0[0] += PetscSqr(PETSC_PI)*(PetscCosReal(PETSC_PI*x[d]) - 1.0); 122*a3d0cf85SMatthew G. Knepley } 123*a3d0cf85SMatthew G. Knepley 124c4762a1bSJed Brown static void f1_temp(PetscInt dim, PetscInt Nf, PetscInt NfAux, 125c4762a1bSJed Brown const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 126c4762a1bSJed Brown const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 127c4762a1bSJed Brown PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]) 128c4762a1bSJed Brown { 129c4762a1bSJed Brown PetscInt d; 130*a3d0cf85SMatthew G. Knepley for (d = 0; d < dim; ++d) f1[d] = u_x[d]; 131c4762a1bSJed Brown } 132c4762a1bSJed Brown 133c4762a1bSJed Brown static void g3_temp(PetscInt dim, PetscInt Nf, PetscInt NfAux, 134c4762a1bSJed Brown const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 135c4762a1bSJed Brown const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 136c4762a1bSJed Brown PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]) 137c4762a1bSJed Brown { 138c4762a1bSJed Brown PetscInt d; 139*a3d0cf85SMatthew G. Knepley for (d = 0; d < dim; ++d) g3[d*dim+d] = 1.0; 140c4762a1bSJed Brown } 141c4762a1bSJed Brown 142c4762a1bSJed Brown static void g0_temp(PetscInt dim, PetscInt Nf, PetscInt NfAux, 143c4762a1bSJed Brown const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 144c4762a1bSJed Brown const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 145c4762a1bSJed Brown PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 146c4762a1bSJed Brown { 147c4762a1bSJed Brown g0[0] = u_tShift*1.0; 148c4762a1bSJed Brown } 149c4762a1bSJed Brown 150c4762a1bSJed Brown static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 151c4762a1bSJed Brown { 152*a3d0cf85SMatthew G. Knepley PetscInt sol; 153c4762a1bSJed Brown PetscErrorCode ierr; 154c4762a1bSJed Brown 155c4762a1bSJed Brown PetscFunctionBeginUser; 156*a3d0cf85SMatthew G. Knepley options->filename[0] = '\0'; 157*a3d0cf85SMatthew G. Knepley options->bdfilename[0] = '\0'; 158*a3d0cf85SMatthew G. Knepley options->scale = 0.0; 159*a3d0cf85SMatthew G. Knepley options->solType = SOL_QUADRATIC_LINEAR; 160c4762a1bSJed Brown 161c4762a1bSJed Brown ierr = PetscOptionsBegin(comm, "", "Heat Equation Options", "DMPLEX");CHKERRQ(ierr); 162*a3d0cf85SMatthew G. Knepley ierr = PetscOptionsString("-filename", "The mesh file", "ex45.c", options->filename, options->filename, PETSC_MAX_PATH_LEN, NULL);CHKERRQ(ierr); 163*a3d0cf85SMatthew G. Knepley ierr = PetscOptionsString("-bd_filename", "The mesh boundary file", "ex45.c", options->bdfilename, options->bdfilename, PETSC_MAX_PATH_LEN, NULL);CHKERRQ(ierr); 164*a3d0cf85SMatthew G. Knepley ierr = PetscOptionsReal("-scale", "Scale factor for the mesh", "ex45.c", options->scale, &options->scale, NULL);CHKERRQ(ierr); 165*a3d0cf85SMatthew G. Knepley sol = options->solType; 166*a3d0cf85SMatthew G. Knepley ierr = PetscOptionsEList("-sol_type", "Type of exact solution", "ex45.c", solutionTypes, NUM_SOLUTION_TYPES, solutionTypes[options->solType], &sol, NULL);CHKERRQ(ierr); 167*a3d0cf85SMatthew G. Knepley options->solType = (SolutionType) sol; 168c4762a1bSJed Brown ierr = PetscOptionsEnd();CHKERRQ(ierr); 169c4762a1bSJed Brown PetscFunctionReturn(0); 170c4762a1bSJed Brown } 171c4762a1bSJed Brown 172c4762a1bSJed Brown static PetscErrorCode CreateBCLabel(DM dm, const char name[]) 173c4762a1bSJed Brown { 174408cafa0SMatthew G. Knepley DM plex; 175c4762a1bSJed Brown DMLabel label; 176*a3d0cf85SMatthew G. Knepley PetscBool hasLabel; 177c4762a1bSJed Brown PetscErrorCode ierr; 178c4762a1bSJed Brown 179c4762a1bSJed Brown PetscFunctionBeginUser; 180*a3d0cf85SMatthew G. Knepley ierr = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr); 181*a3d0cf85SMatthew G. Knepley if (hasLabel) PetscFunctionReturn(0); 182c4762a1bSJed Brown ierr = DMCreateLabel(dm, name);CHKERRQ(ierr); 183c4762a1bSJed Brown ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 184408cafa0SMatthew G. Knepley ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr); 185408cafa0SMatthew G. Knepley ierr = DMPlexMarkBoundaryFaces(plex, 1, label);CHKERRQ(ierr); 186408cafa0SMatthew G. Knepley ierr = DMDestroy(&plex);CHKERRQ(ierr); 187c4762a1bSJed Brown PetscFunctionReturn(0); 188c4762a1bSJed Brown } 189c4762a1bSJed Brown 190c4762a1bSJed Brown static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm, AppCtx *ctx) 191c4762a1bSJed Brown { 192*a3d0cf85SMatthew G. Knepley size_t len, lenbd; 193c4762a1bSJed Brown PetscErrorCode ierr; 194c4762a1bSJed Brown 195c4762a1bSJed Brown PetscFunctionBeginUser; 196*a3d0cf85SMatthew G. Knepley ierr = PetscStrlen(ctx->filename, &len);CHKERRQ(ierr); 197*a3d0cf85SMatthew G. Knepley ierr = PetscStrlen(ctx->bdfilename, &lenbd);CHKERRQ(ierr); 198*a3d0cf85SMatthew G. Knepley if (lenbd) { 199*a3d0cf85SMatthew G. Knepley DM bdm; 200*a3d0cf85SMatthew G. Knepley 201*a3d0cf85SMatthew G. Knepley ierr = DMPlexCreateFromFile(comm, ctx->bdfilename, PETSC_TRUE, &bdm);CHKERRQ(ierr); 202*a3d0cf85SMatthew G. Knepley ierr = PetscObjectSetOptionsPrefix((PetscObject) bdm, "bd_");CHKERRQ(ierr); 203*a3d0cf85SMatthew G. Knepley ierr = DMSetFromOptions(bdm);CHKERRQ(ierr); 204*a3d0cf85SMatthew G. Knepley if (ctx->scale != 0.0) { 205*a3d0cf85SMatthew G. Knepley Vec coordinates, coordinatesLocal; 206*a3d0cf85SMatthew G. Knepley 207*a3d0cf85SMatthew G. Knepley ierr = DMGetCoordinates(bdm, &coordinates);CHKERRQ(ierr); 208*a3d0cf85SMatthew G. Knepley ierr = DMGetCoordinatesLocal(bdm, &coordinatesLocal);CHKERRQ(ierr); 209*a3d0cf85SMatthew G. Knepley ierr = VecScale(coordinates, ctx->scale);CHKERRQ(ierr); 210*a3d0cf85SMatthew G. Knepley ierr = VecScale(coordinatesLocal, ctx->scale);CHKERRQ(ierr); 211*a3d0cf85SMatthew G. Knepley } 212*a3d0cf85SMatthew G. Knepley ierr = DMViewFromOptions(bdm, NULL, "-dm_view");CHKERRQ(ierr); 213*a3d0cf85SMatthew G. Knepley ierr = DMPlexGenerate(bdm, NULL, PETSC_TRUE, dm);CHKERRQ(ierr); 214*a3d0cf85SMatthew G. Knepley ierr = DMDestroy(&bdm);CHKERRQ(ierr); 215*a3d0cf85SMatthew G. Knepley } else if (len) { 216*a3d0cf85SMatthew G. Knepley ierr = DMPlexCreateFromFile(comm, ctx->filename, PETSC_TRUE, dm);CHKERRQ(ierr); 217*a3d0cf85SMatthew G. Knepley } else { 218*a3d0cf85SMatthew G. Knepley ierr = DMPlexCreateBoxMesh(comm, 2, PETSC_TRUE, NULL, NULL, NULL, NULL, PETSC_TRUE, dm);CHKERRQ(ierr); 219c4762a1bSJed Brown } 220c4762a1bSJed Brown ierr = DMSetFromOptions(*dm);CHKERRQ(ierr); 221*a3d0cf85SMatthew G. Knepley ierr = PetscObjectSetName((PetscObject) *dm, "Mesh");CHKERRQ(ierr); 222*a3d0cf85SMatthew G. Knepley ierr = CreateBCLabel(*dm, "marker");CHKERRQ(ierr); 223c4762a1bSJed Brown ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr); 224c4762a1bSJed Brown PetscFunctionReturn(0); 225c4762a1bSJed Brown } 226c4762a1bSJed Brown 227c4762a1bSJed Brown static PetscErrorCode SetupProblem(DM dm, AppCtx *ctx) 228c4762a1bSJed Brown { 229*a3d0cf85SMatthew G. Knepley PetscDS ds; 230c4762a1bSJed Brown const PetscInt id = 1; 231c4762a1bSJed Brown PetscErrorCode ierr; 232c4762a1bSJed Brown 233c4762a1bSJed Brown PetscFunctionBeginUser; 234*a3d0cf85SMatthew G. Knepley ierr = DMGetDS(dm, &ds);CHKERRQ(ierr); 235*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetJacobian(ds, 0, 0, g0_temp, NULL, NULL, g3_temp);CHKERRQ(ierr); 236*a3d0cf85SMatthew G. Knepley switch (ctx->solType) { 237*a3d0cf85SMatthew G. Knepley case SOL_QUADRATIC_LINEAR: 238*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetResidual(ds, 0, f0_quad_lin, f1_temp);CHKERRQ(ierr); 239*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetExactSolution(ds, 0, mms_quad_lin, ctx);CHKERRQ(ierr); 240*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetExactSolutionTimeDerivative(ds, 0, mms_quad_lin_t, ctx);CHKERRQ(ierr); 241*a3d0cf85SMatthew G. Knepley ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "marker", 0, 0, NULL, (void (*)(void)) mms_quad_lin, (void (*)(void)) mms_quad_lin_t, 1, &id, ctx);CHKERRQ(ierr); 242*a3d0cf85SMatthew G. Knepley break; 243*a3d0cf85SMatthew G. Knepley case SOL_QUADRATIC_TRIG: 244*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetResidual(ds, 0, f0_quad_trig, f1_temp);CHKERRQ(ierr); 245*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetExactSolution(ds, 0, mms_quad_trig, ctx);CHKERRQ(ierr); 246*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetExactSolutionTimeDerivative(ds, 0, mms_quad_trig_t, ctx);CHKERRQ(ierr); 247*a3d0cf85SMatthew G. Knepley ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "marker", 0, 0, NULL, (void (*)(void)) mms_quad_trig, (void (*)(void)) mms_quad_trig_t, 1, &id, ctx);CHKERRQ(ierr); 248*a3d0cf85SMatthew G. Knepley break; 249*a3d0cf85SMatthew G. Knepley case SOL_TRIG_LINEAR: 250*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetResidual(ds, 0, f0_trig_lin, f1_temp);CHKERRQ(ierr); 251*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetExactSolution(ds, 0, mms_trig_lin, ctx);CHKERRQ(ierr); 252*a3d0cf85SMatthew G. Knepley ierr = PetscDSSetExactSolutionTimeDerivative(ds, 0, mms_trig_lin_t, ctx);CHKERRQ(ierr); 253*a3d0cf85SMatthew G. Knepley ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "marker", 0, 0, NULL, (void (*)(void)) mms_trig_lin, (void (*)(void)) mms_trig_lin_t, 1, &id, ctx);CHKERRQ(ierr); 254*a3d0cf85SMatthew G. Knepley break; 255*a3d0cf85SMatthew G. Knepley default: SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Invalid solution type: %s (%D)", solutionTypes[PetscMin(ctx->solType, NUM_SOLUTION_TYPES)], ctx->solType); 256*a3d0cf85SMatthew G. Knepley } 257c4762a1bSJed Brown PetscFunctionReturn(0); 258c4762a1bSJed Brown } 259c4762a1bSJed Brown 260c4762a1bSJed Brown static PetscErrorCode SetupDiscretization(DM dm, AppCtx* ctx) 261c4762a1bSJed Brown { 262c4762a1bSJed Brown DM cdm = dm; 263c4762a1bSJed Brown PetscFE fe; 264*a3d0cf85SMatthew G. Knepley DMPolytopeType ct; 265*a3d0cf85SMatthew G. Knepley PetscBool simplex; 266*a3d0cf85SMatthew G. Knepley PetscInt dim, cStart; 267c4762a1bSJed Brown PetscErrorCode ierr; 268c4762a1bSJed Brown 269c4762a1bSJed Brown PetscFunctionBeginUser; 270*a3d0cf85SMatthew G. Knepley ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 271*a3d0cf85SMatthew G. Knepley ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr); 272*a3d0cf85SMatthew G. Knepley ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr); 273*a3d0cf85SMatthew G. Knepley simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 274c4762a1bSJed Brown /* Create finite element */ 275*a3d0cf85SMatthew G. Knepley ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "temp_", -1, &fe);CHKERRQ(ierr); 276c4762a1bSJed Brown ierr = PetscObjectSetName((PetscObject) fe, "temperature");CHKERRQ(ierr); 277c4762a1bSJed Brown /* Set discretization and boundary conditions for each mesh */ 278c4762a1bSJed Brown ierr = DMSetField(dm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr); 279c4762a1bSJed Brown ierr = DMCreateDS(dm);CHKERRQ(ierr); 280c4762a1bSJed Brown ierr = SetupProblem(dm, ctx);CHKERRQ(ierr); 281c4762a1bSJed Brown while (cdm) { 282*a3d0cf85SMatthew G. Knepley ierr = CreateBCLabel(cdm, "marker");CHKERRQ(ierr); 283408cafa0SMatthew G. Knepley ierr = DMCopyDisc(dm, cdm);CHKERRQ(ierr); 284c4762a1bSJed Brown ierr = DMGetCoarseDM(cdm, &cdm);CHKERRQ(ierr); 285c4762a1bSJed Brown } 286c4762a1bSJed Brown ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 287c4762a1bSJed Brown PetscFunctionReturn(0); 288c4762a1bSJed Brown } 289c4762a1bSJed Brown 290*a3d0cf85SMatthew G. Knepley static PetscErrorCode SetInitialConditions(TS ts, Vec u) 291*a3d0cf85SMatthew G. Knepley { 292*a3d0cf85SMatthew G. Knepley DM dm; 293*a3d0cf85SMatthew G. Knepley PetscReal t; 294*a3d0cf85SMatthew G. Knepley PetscErrorCode ierr; 295*a3d0cf85SMatthew G. Knepley 296*a3d0cf85SMatthew G. Knepley PetscFunctionBegin; 297*a3d0cf85SMatthew G. Knepley ierr = TSGetDM(ts, &dm);CHKERRQ(ierr); 298*a3d0cf85SMatthew G. Knepley ierr = TSGetTime(ts, &t);CHKERRQ(ierr); 299*a3d0cf85SMatthew G. Knepley ierr = DMComputeExactSolution(dm, t, u, NULL);CHKERRQ(ierr); 300*a3d0cf85SMatthew G. Knepley PetscFunctionReturn(0); 301*a3d0cf85SMatthew G. Knepley } 302*a3d0cf85SMatthew G. Knepley 303c4762a1bSJed Brown int main(int argc, char **argv) 304c4762a1bSJed Brown { 305c4762a1bSJed Brown DM dm; 306c4762a1bSJed Brown TS ts; 307*a3d0cf85SMatthew G. Knepley Vec u; 308*a3d0cf85SMatthew G. Knepley AppCtx ctx; 309c4762a1bSJed Brown PetscErrorCode ierr; 310c4762a1bSJed Brown 311c4762a1bSJed Brown ierr = PetscInitialize(&argc, &argv, NULL, help);if (ierr) return ierr; 312c4762a1bSJed Brown ierr = ProcessOptions(PETSC_COMM_WORLD, &ctx);CHKERRQ(ierr); 313c4762a1bSJed Brown ierr = CreateMesh(PETSC_COMM_WORLD, &dm, &ctx);CHKERRQ(ierr); 314c4762a1bSJed Brown ierr = DMSetApplicationContext(dm, &ctx);CHKERRQ(ierr); 315c4762a1bSJed Brown ierr = SetupDiscretization(dm, &ctx);CHKERRQ(ierr); 316c4762a1bSJed Brown 317c4762a1bSJed Brown ierr = TSCreate(PETSC_COMM_WORLD, &ts);CHKERRQ(ierr); 318c4762a1bSJed Brown ierr = TSSetDM(ts, dm);CHKERRQ(ierr); 319c4762a1bSJed Brown ierr = DMTSSetBoundaryLocal(dm, DMPlexTSComputeBoundary, &ctx);CHKERRQ(ierr); 320c4762a1bSJed Brown ierr = DMTSSetIFunctionLocal(dm, DMPlexTSComputeIFunctionFEM, &ctx);CHKERRQ(ierr); 321c4762a1bSJed Brown ierr = DMTSSetIJacobianLocal(dm, DMPlexTSComputeIJacobianFEM, &ctx);CHKERRQ(ierr); 322*a3d0cf85SMatthew G. Knepley ierr = TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);CHKERRQ(ierr); 323c4762a1bSJed Brown ierr = TSSetFromOptions(ts);CHKERRQ(ierr); 324*a3d0cf85SMatthew G. Knepley ierr = TSSetComputeInitialCondition(ts, SetInitialConditions);CHKERRQ(ierr); 325c4762a1bSJed Brown 326*a3d0cf85SMatthew G. Knepley ierr = DMCreateGlobalVector(dm, &u);CHKERRQ(ierr); 327*a3d0cf85SMatthew G. Knepley ierr = DMTSCheckFromOptions(ts, u);CHKERRQ(ierr); 328*a3d0cf85SMatthew G. Knepley ierr = SetInitialConditions(ts, u);CHKERRQ(ierr); 329*a3d0cf85SMatthew G. Knepley ierr = PetscObjectSetName((PetscObject) u, "temperature");CHKERRQ(ierr); 330c4762a1bSJed Brown ierr = TSSolve(ts, u);CHKERRQ(ierr); 331*a3d0cf85SMatthew G. Knepley ierr = DMTSCheckFromOptions(ts, u);CHKERRQ(ierr); 332c4762a1bSJed Brown 333c4762a1bSJed Brown ierr = VecDestroy(&u);CHKERRQ(ierr); 334c4762a1bSJed Brown ierr = TSDestroy(&ts);CHKERRQ(ierr); 335c4762a1bSJed Brown ierr = DMDestroy(&dm);CHKERRQ(ierr); 336c4762a1bSJed Brown ierr = PetscFinalize(); 337c4762a1bSJed Brown return ierr; 338c4762a1bSJed Brown } 339c4762a1bSJed Brown 340c4762a1bSJed Brown /*TEST 341c4762a1bSJed Brown 342c4762a1bSJed Brown test: 343*a3d0cf85SMatthew G. Knepley suffix: 2d_p1 344c4762a1bSJed Brown requires: triangle 345*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_refine 1 -temp_petscspace_degree 1 -dmts_check .0001 \ 346*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 347c4762a1bSJed Brown test: 348*a3d0cf85SMatthew G. Knepley # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9] 349*a3d0cf85SMatthew G. Knepley suffix: 2d_p1_sconv 350c4762a1bSJed Brown requires: triangle 351*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 352*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 1 -ts_dt 0.00001 -snes_error_if_not_converged -pc_type lu 353c4762a1bSJed Brown test: 354*a3d0cf85SMatthew G. Knepley # -dm_refine 4 -convest_num_refine 3 get L_2 convergence rate: [1.2] 355*a3d0cf85SMatthew G. Knepley suffix: 2d_p1_tconv 356c4762a1bSJed Brown requires: triangle 357*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_trig -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 358*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 4 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 359c4762a1bSJed Brown test: 360*a3d0cf85SMatthew G. Knepley suffix: 2d_p2 361c4762a1bSJed Brown requires: triangle 362*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_refine 0 -temp_petscspace_degree 2 -dmts_check .0001 \ 363*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 364c4762a1bSJed Brown test: 365*a3d0cf85SMatthew G. Knepley # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.9] 366*a3d0cf85SMatthew G. Knepley suffix: 2d_p2_sconv 367*a3d0cf85SMatthew G. Knepley requires: triangle 368*a3d0cf85SMatthew G. Knepley args: -sol_type trig_linear -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 369*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 1 -ts_dt 0.00000001 -snes_error_if_not_converged -pc_type lu 370c4762a1bSJed Brown test: 371*a3d0cf85SMatthew G. Knepley # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 372*a3d0cf85SMatthew G. Knepley suffix: 2d_p2_tconv 373*a3d0cf85SMatthew G. Knepley requires: triangle 374*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_trig -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 375*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 4 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 376c4762a1bSJed Brown test: 377*a3d0cf85SMatthew G. Knepley suffix: 2d_q1 378*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_plex_box_simplex 0 -dm_refine 1 -temp_petscspace_degree 1 -dmts_check .0001 \ 379*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 380c4762a1bSJed Brown test: 381*a3d0cf85SMatthew G. Knepley # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9] 382*a3d0cf85SMatthew G. Knepley suffix: 2d_q1_sconv 383*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_plex_box_simplex 0 -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 384*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 1 -ts_dt 0.00001 -snes_error_if_not_converged -pc_type lu 385c4762a1bSJed Brown test: 386*a3d0cf85SMatthew G. Knepley # -dm_refine 4 -convest_num_refine 3 get L_2 convergence rate: [1.2] 387*a3d0cf85SMatthew G. Knepley suffix: 2d_q1_tconv 388*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_trig -dm_plex_box_simplex 0 -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 389*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 4 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 390*a3d0cf85SMatthew G. Knepley test: 391*a3d0cf85SMatthew G. Knepley suffix: 2d_q2 392*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_plex_box_simplex 0 -dm_refine 0 -temp_petscspace_degree 2 -dmts_check .0001 \ 393*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 394*a3d0cf85SMatthew G. Knepley test: 395*a3d0cf85SMatthew G. Knepley # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.9] 396*a3d0cf85SMatthew G. Knepley suffix: 2d_q2_sconv 397*a3d0cf85SMatthew G. Knepley args: -sol_type trig_linear -dm_plex_box_simplex 0 -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 398*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 1 -ts_dt 0.00000001 -snes_error_if_not_converged -pc_type lu 399*a3d0cf85SMatthew G. Knepley test: 400*a3d0cf85SMatthew G. Knepley # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 401*a3d0cf85SMatthew G. Knepley suffix: 2d_q2_tconv 402*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_trig -dm_plex_box_simplex 0 -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 403*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 4 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 404*a3d0cf85SMatthew G. Knepley 405*a3d0cf85SMatthew G. Knepley test: 406*a3d0cf85SMatthew G. Knepley suffix: 3d_p1 407c4762a1bSJed Brown requires: ctetgen 408*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_refine 1 -temp_petscspace_degree 1 -dmts_check .0001 \ 409*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 410c4762a1bSJed Brown test: 411*a3d0cf85SMatthew G. Knepley # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9] 412*a3d0cf85SMatthew G. Knepley suffix: 3d_p1_sconv 413c4762a1bSJed Brown requires: ctetgen 414*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 415*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 1 -ts_dt 0.00001 -snes_error_if_not_converged -pc_type lu 416c4762a1bSJed Brown test: 417*a3d0cf85SMatthew G. Knepley # -dm_refine 4 -convest_num_refine 3 get L_2 convergence rate: [1.2] 418*a3d0cf85SMatthew G. Knepley suffix: 3d_p1_tconv 419c4762a1bSJed Brown requires: ctetgen 420*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_trig -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 421*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 4 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 422c4762a1bSJed Brown test: 423*a3d0cf85SMatthew G. Knepley suffix: 3d_p2 424c4762a1bSJed Brown requires: ctetgen 425*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_refine 0 -temp_petscspace_degree 2 -dmts_check .0001 \ 426*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 427c4762a1bSJed Brown test: 428*a3d0cf85SMatthew G. Knepley # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.9] 429*a3d0cf85SMatthew G. Knepley suffix: 3d_p2_sconv 430*a3d0cf85SMatthew G. Knepley requires: ctetgen 431*a3d0cf85SMatthew G. Knepley args: -sol_type trig_linear -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 432*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 1 -ts_dt 0.00000001 -snes_error_if_not_converged -pc_type lu 433c4762a1bSJed Brown test: 434*a3d0cf85SMatthew G. Knepley # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 435*a3d0cf85SMatthew G. Knepley suffix: 3d_p2_tconv 436*a3d0cf85SMatthew G. Knepley requires: ctetgen 437*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_trig -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 438*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 4 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 439c4762a1bSJed Brown test: 440*a3d0cf85SMatthew G. Knepley suffix: 3d_q1 441*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_plex_box_simplex 0 -dm_refine 1 -temp_petscspace_degree 1 -dmts_check .0001 \ 442*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 443c4762a1bSJed Brown test: 444*a3d0cf85SMatthew G. Knepley # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9] 445*a3d0cf85SMatthew G. Knepley suffix: 3d_q1_sconv 446*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_plex_box_simplex 0 -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 447*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 1 -ts_dt 0.00001 -snes_error_if_not_converged -pc_type lu 448*a3d0cf85SMatthew G. Knepley test: 449*a3d0cf85SMatthew G. Knepley # -dm_refine 4 -convest_num_refine 3 get L_2 convergence rate: [1.2] 450*a3d0cf85SMatthew G. Knepley suffix: 3d_q1_tconv 451*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_trig -dm_plex_box_simplex 0 -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 452*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 4 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 453*a3d0cf85SMatthew G. Knepley test: 454*a3d0cf85SMatthew G. Knepley suffix: 3d_q2 455*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -dm_plex_box_simplex 0 -dm_refine 0 -temp_petscspace_degree 2 -dmts_check .0001 \ 456*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 457*a3d0cf85SMatthew G. Knepley test: 458*a3d0cf85SMatthew G. Knepley # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.9] 459*a3d0cf85SMatthew G. Knepley suffix: 3d_q2_sconv 460*a3d0cf85SMatthew G. Knepley args: -sol_type trig_linear -dm_plex_box_simplex 0 -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 461*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 1 -ts_dt 0.00000001 -snes_error_if_not_converged -pc_type lu 462*a3d0cf85SMatthew G. Knepley test: 463*a3d0cf85SMatthew G. Knepley # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 464*a3d0cf85SMatthew G. Knepley suffix: 3d_q2_tconv 465*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_trig -dm_plex_box_simplex 0 -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 466*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 4 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 467*a3d0cf85SMatthew G. Knepley 468*a3d0cf85SMatthew G. Knepley test: 469*a3d0cf85SMatthew G. Knepley # For a nice picture, -bd_dm_refine 2 -dm_refine 1 -dm_view hdf5:${PETSC_DIR}/sol.h5 -ts_monitor_solution hdf5:${PETSC_DIR}/sol.h5::append 470*a3d0cf85SMatthew G. Knepley suffix: egads_sphere 471*a3d0cf85SMatthew G. Knepley requires: egads ctetgen 472*a3d0cf85SMatthew G. Knepley args: -sol_type quadratic_linear -bd_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/unit_sphere.egadslite -scale 40 \ 473*a3d0cf85SMatthew G. Knepley -temp_petscspace_degree 2 -dmts_check .0001 \ 474*a3d0cf85SMatthew G. Knepley -ts_type beuler -ts_max_steps 5 -ts_dt 0.1 -snes_error_if_not_converged -pc_type lu 475c4762a1bSJed Brown 476c4762a1bSJed Brown TEST*/ 477