Last active
April 8, 2019 06:13
-
-
Save julesghub/0c73c4109328cf435df9eef8e7b64529 to your computer and use it in GitHub Desktop.
Jules attempt at having a reflective condition on the top wall. SNES fails to converge under significant rotations (alpha). Also py3 petsc_gen_xdmf.py attached
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static char help[] = "Poiseuille Flow in 2d and 3d channels with finite elements.\n\ | |
We solve the Poiseuille flow problem in a rectangular\n\ | |
domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\n\n"; | |
/*F | |
A Poiseuille flow is a steady-state isoviscous Stokes flow in a pipe of constant cross-section. We discretize using the | |
finite element method on an unstructured mesh. The weak form equations are | |
\begin{align*} | |
< \nabla v, \nu (\nabla u + {\nabla u}^T) > - < \nabla\cdot v, p > + < v, \Delta \hat n >_{\Gamma_o} = 0 | |
< q, \nabla\cdot u > = 0 | |
\end{align*} | |
where $\nu$ is the kinematic viscosity, $\Delta$ is the pressure drop per unit length, assuming that pressure is 0 on | |
the left edge, and $\Gamma_o$ is the outlet boundary at the right edge of the pipe. The normal velocity will be zero at | |
the wall, but we will allow a fixed tangential velocity $u_0$. | |
In order to test our global to local basis transformation, we will allow the pipe to be at an angle $\alpha$ to the | |
coordinate axes. | |
For visualization, use | |
-dm_view hdf5:$PWD/sol.h5 -sol_vec_view hdf5:$PWD/sol.h5::append -exact_vec_view hdf5:$PWD/sol.h5::append | |
F*/ | |
#include <petscdmplex.h> | |
#include <petscsnes.h> | |
#include <petscds.h> | |
#include <petscbag.h> | |
typedef struct { | |
PetscReal Delta; /* Pressure drop per unit length */ | |
PetscReal nu; /* Kinematic viscosity */ | |
PetscReal u_0; /* Tangential velocity at the wall */ | |
PetscReal alpha; /* Angle of pipe wall to x-axis */ | |
} Parameter; | |
typedef struct { | |
/* Domain and mesh definition */ | |
PetscInt dim; /* The topological mesh dimension */ | |
PetscBool simplex; /* Use simplices or tensor product cells */ | |
PetscInt cells[3]; /* The initial domain division */ | |
/* Problem definition */ | |
PetscBag bag; /* Holds problem parameters */ | |
PetscErrorCode (**exactFuncs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx); | |
} AppCtx; | |
/* | |
In 2D, plane Poiseuille flow has exact solution: | |
u = \Delta/(2 \nu) y (1 - y) + u_0 | |
v = 0 | |
p = -\Delta x | |
f = 0 | |
so that | |
-\nu \Delta u + \nabla p + f = <\Delta, 0> + <-\Delta, 0> + <0, 0> = 0 | |
\nabla \cdot u = 0 + 0 = 0 | |
In 3D we use exact solution: | |
u = \Delta/(4 \nu) (y (1 - y) + z (1 - z)) + u_0 | |
v = 0 | |
w = 0 | |
p = -\Delta x | |
f = 0 | |
so that | |
-\nu \Delta u + \nabla p + f = <Delta, 0, 0> + <-Delta, 0, 0> + <0, 0, 0> = 0 | |
\nabla \cdot u = 0 + 0 + 0 = 0 | |
Note that these functions use coordinates X in the global (rotated) frame | |
*/ | |
PetscErrorCode quadratic_u(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *u, void *ctx) | |
{ | |
Parameter *param = (Parameter *) ctx; | |
PetscReal Delta = param->Delta; | |
PetscReal nu = param->nu; | |
PetscReal u_0 = param->u_0; | |
PetscReal fac = (PetscReal) (dim - 1); | |
PetscInt d; | |
u[0] = u_0; | |
for (d = 1; d < dim; ++d) u[0] += Delta/(fac * 2.0*nu) * X[d] * (1.0 - X[d]); | |
for (d = 1; d < dim; ++d) u[d] = 0.0; | |
return 0; | |
} | |
PetscErrorCode linear_p(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *p, void *ctx) | |
{ | |
Parameter *param = (Parameter *) ctx; | |
PetscReal Delta = param->Delta; | |
p[0] = -Delta * X[0]; | |
return 0; | |
} | |
PetscErrorCode static_wall(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *u, void *ctx) | |
{ | |
Parameter *param = (Parameter *) ctx; | |
PetscInt d; | |
for (d = 0; d < dim; ++d) u[d] = 0.0; | |
return 0; | |
} | |
PetscErrorCode top_wall_velocity(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *u, void *ctx) | |
{ | |
Parameter *param = (Parameter *) ctx; | |
PetscReal u_0 = param->u_0; | |
PetscInt d; | |
//u[0] = u_0; | |
for (d = 1; d < dim; ++d) u[d] = 0.0; | |
return 0; | |
} | |
/* gradU[comp*dim+d] = {u_x, u_y, v_x, v_y} or {u_x, u_y, u_z, v_x, v_y, v_z, w_x, w_y, w_z} | |
u[Ncomp] = {p} */ | |
void f1_u(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[]) | |
{ | |
const PetscReal nu = PetscRealPart(constants[1]); | |
const PetscInt Nc = dim; | |
PetscInt c, d; | |
for (c = 0; c < Nc; ++c) { | |
for (d = 0; d < dim; ++d) { | |
/* f1[c*dim+d] = 0.5*nu*(u_x[c*dim+d] + u_x[d*dim+c]); */ | |
f1[c*dim+d] = nu*u_x[c*dim+d]; | |
} | |
f1[c*dim+c] -= u[uOff[1]]; | |
} | |
} | |
/* gradU[comp*dim+d] = {u_x, u_y, v_x, v_y} or {u_x, u_y, u_z, v_x, v_y, v_z, w_x, w_y, w_z} */ | |
void f0_p(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[]) | |
{ | |
PetscInt d; | |
for (d = 0, f0[0] = 0.0; d < dim; ++d) f0[0] += u_x[d*dim+d]; | |
} | |
/* Residual functions are in reference coordinates */ | |
static void f0_bd_u(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[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) | |
{ | |
const PetscReal Delta = PetscRealPart(constants[0]); | |
PetscReal alpha = PetscRealPart(constants[3]); | |
PetscReal X = PetscCosReal(alpha)*x[0] + PetscSinReal(alpha)*x[1]; | |
PetscInt d; | |
for (d = 0; d < dim; ++d) { | |
f0[d] = -Delta * X * n[d]; | |
} | |
} | |
/* < q, \nabla\cdot u > | |
NcompI = 1, NcompJ = dim */ | |
void g1_pu(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[]) | |
{ | |
PetscInt d; | |
for (d = 0; d < dim; ++d) g1[d*dim+d] = 1.0; /* \frac{\partial\phi^{u_d}}{\partial x_d} */ | |
} | |
/* -< \nabla\cdot v, p > | |
NcompI = dim, NcompJ = 1 */ | |
void g2_up(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 g2[]) | |
{ | |
PetscInt d; | |
for (d = 0; d < dim; ++d) g2[d*dim+d] = -1.0; /* \frac{\partial\psi^{u_d}}{\partial x_d} */ | |
} | |
/* < \nabla v, \nabla u + {\nabla u}^T > | |
This just gives \nabla u, give the perdiagonal for the transpose */ | |
void g3_uu(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[]) | |
{ | |
const PetscReal nu = PetscRealPart(constants[1]); | |
const PetscInt Nc = dim; | |
PetscInt c, d; | |
for (c = 0; c < Nc; ++c) { | |
for (d = 0; d < dim; ++d) { | |
g3[((c*Nc+c)*dim+d)*dim+d] = nu; | |
} | |
} | |
} | |
PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) | |
{ | |
PetscInt n = 3; | |
PetscErrorCode ierr; | |
PetscFunctionBeginUser; | |
options->dim = 2; | |
options->simplex = PETSC_TRUE; | |
options->cells[0] = 3; | |
options->cells[1] = 3; | |
options->cells[2] = 3; | |
ierr = PetscOptionsBegin(comm, "", "Poiseuille Flow Options", "DMPLEX");CHKERRQ(ierr); | |
ierr = PetscOptionsInt("-dim", "The topological mesh dimension", "ex62.c", options->dim, &options->dim, NULL);CHKERRQ(ierr); | |
ierr = PetscOptionsBool("-simplex", "Use simplices or tensor product cells", "ex62.c", options->simplex, &options->simplex, NULL);CHKERRQ(ierr); | |
ierr = PetscOptionsIntArray("-cells", "The initial mesh division", "ex62.c", options->cells, &n, NULL);CHKERRQ(ierr); | |
ierr = PetscOptionsEnd(); | |
PetscFunctionReturn(0); | |
} | |
static PetscErrorCode SetupParameters(AppCtx *user) | |
{ | |
PetscBag bag; | |
Parameter *p; | |
PetscErrorCode ierr; | |
PetscFunctionBeginUser; | |
/* setup PETSc parameter bag */ | |
ierr = PetscBagGetData(user->bag, (void **) &p);CHKERRQ(ierr); | |
ierr = PetscBagSetName(user->bag, "par", "Poiseuille flow parameters");CHKERRQ(ierr); | |
bag = user->bag; | |
ierr = PetscBagRegisterReal(bag, &p->Delta, 1.0, "Delta", "Pressure drop per unit length");CHKERRQ(ierr); | |
ierr = PetscBagRegisterReal(bag, &p->nu, 1.0, "nu", "Kinematic viscosity");CHKERRQ(ierr); | |
ierr = PetscBagRegisterReal(bag, &p->u_0, 0.0, "u_0", "Tangential velocity at the wall");CHKERRQ(ierr); | |
ierr = PetscBagRegisterReal(bag, &p->alpha, 0.0, "alpha", "Angle of pipe wall to x-axis");CHKERRQ(ierr); | |
PetscFunctionReturn(0); | |
} | |
PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) | |
{ | |
PetscInt dim = user->dim; | |
PetscErrorCode ierr; | |
PetscFunctionBeginUser; | |
ierr = DMPlexCreateBoxMesh(comm, dim, user->simplex, user->cells, NULL, NULL, NULL, PETSC_TRUE, dm);CHKERRQ(ierr); | |
{ | |
Parameter *param; | |
Vec coordinates; | |
PetscScalar *coords; | |
PetscReal alpha; | |
PetscInt cdim, N, bs, i; | |
ierr = DMGetCoordinateDim(*dm, &cdim);CHKERRQ(ierr); | |
ierr = DMGetCoordinates(*dm, &coordinates);CHKERRQ(ierr); | |
ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); | |
ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr); | |
if (bs != cdim) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Invalid coordinate blocksize %D != embedding dimension %D", bs, cdim); | |
ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); | |
ierr = PetscBagGetData(user->bag, (void **) ¶m);CHKERRQ(ierr); | |
alpha = param->alpha; | |
for (i = 0; i < N; i += cdim) { | |
PetscScalar x = coords[i+0]; | |
PetscScalar y = coords[i+1]; | |
coords[i+0] = PetscCosReal(alpha)*x - PetscSinReal(alpha)*y; | |
coords[i+1] = PetscSinReal(alpha)*x + PetscCosReal(alpha)*y; | |
#if 0 | |
if ((PetscAbsReal(x - 0.333333333) < 1.0e-7) && (PetscAbsReal(y - 0.333333333) < 1.0e-7)) { | |
coords[i+0] += PetscCosReal(alpha)*0.05; | |
coords[i+1] += PetscSinReal(alpha)*0.05; | |
} | |
#endif | |
} | |
ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); | |
ierr = DMSetCoordinates(*dm, coordinates);CHKERRQ(ierr); | |
} | |
{ | |
DM pdm = NULL; | |
PetscPartitioner part; | |
ierr = DMPlexGetPartitioner(*dm, &part);CHKERRQ(ierr); | |
ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr); | |
ierr = DMPlexDistribute(*dm, 0, NULL, &pdm);CHKERRQ(ierr); | |
if (pdm) { | |
ierr = DMDestroy(dm);CHKERRQ(ierr); | |
*dm = pdm; | |
} | |
} | |
ierr = DMSetFromOptions(*dm);CHKERRQ(ierr); | |
ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr); | |
PetscFunctionReturn(0); | |
} | |
PetscErrorCode SetupProblem(DM dm, AppCtx *user) | |
{ | |
PetscDS prob; | |
Parameter *ctx; | |
PetscInt id; | |
PetscErrorCode ierr; | |
PetscFunctionBeginUser; | |
ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); | |
ierr = PetscDSSetResidual(prob, 0, NULL, f1_u);CHKERRQ(ierr); | |
ierr = PetscDSSetResidual(prob, 1, f0_p, NULL);CHKERRQ(ierr); | |
ierr = PetscDSSetBdResidual(prob, 0, f0_bd_u, NULL);CHKERRQ(ierr); | |
ierr = PetscDSSetJacobian(prob, 0, 0, NULL, NULL, NULL, g3_uu);CHKERRQ(ierr); | |
ierr = PetscDSSetJacobian(prob, 0, 1, NULL, NULL, g2_up, NULL);CHKERRQ(ierr); | |
ierr = PetscDSSetJacobian(prob, 1, 0, NULL, g1_pu, NULL, NULL);CHKERRQ(ierr); | |
/* Setup constants */ | |
{ | |
Parameter *param; | |
PetscScalar constants[4]; | |
ierr = PetscBagGetData(user->bag, (void **) ¶m);CHKERRQ(ierr); | |
constants[0] = param->Delta; | |
constants[1] = param->nu; | |
constants[2] = param->u_0; | |
constants[3] = param->alpha; | |
ierr = PetscDSSetConstants(prob, 4, constants);CHKERRQ(ierr); | |
} | |
/* Setup Boundary Conditions */ | |
ierr = PetscBagGetData(user->bag, (void **) &ctx);CHKERRQ(ierr); | |
PetscInt dofs[2] = {0,1}; | |
/* Top wall conditions */ | |
id = 3; | |
ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "top wall_vy", "marker", 0, 1, &dofs[1], (void (*)(void)) top_wall_velocity, 1, &id, ctx);CHKERRQ(ierr); | |
//ierr = PetscDSAddBoundary(prob, DM_BC_NATURAL, "top wall_vx", "marker", 0, 1, &dofs[0], (void (*)(void)) top_wall_vx, 1, &id, ctx);CHKERRQ(ierr); | |
id = 1; | |
ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "bottom wall", "marker", 0, 0, NULL, (void (*)(void)) static_wall, 1, &id, ctx);CHKERRQ(ierr); | |
id = 2; | |
ierr = PetscDSAddBoundary(prob, DM_BC_NATURAL, "right wall", "marker", 0, 0, NULL, (void (*)(void)) NULL, 1, &id, ctx);CHKERRQ(ierr); | |
/* Setup exact solution */ | |
user->exactFuncs[0] = quadratic_u; | |
user->exactFuncs[1] = linear_p; | |
ierr = PetscDSSetExactSolution(prob, 0, user->exactFuncs[0], ctx);CHKERRQ(ierr); | |
ierr = PetscDSSetExactSolution(prob, 1, user->exactFuncs[1], ctx);CHKERRQ(ierr); | |
PetscFunctionReturn(0); | |
} | |
PetscErrorCode SetupDiscretization(DM dm, AppCtx *user) | |
{ | |
DM cdm = dm; | |
const PetscInt dim = user->dim; | |
PetscFE fe[2]; | |
PetscQuadrature q; | |
Parameter *param; | |
MPI_Comm comm; | |
PetscErrorCode ierr; | |
PetscFunctionBeginUser; | |
/* Create finite element */ | |
ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); | |
ierr = PetscFECreateDefault(comm, dim, dim, user->simplex, "vel_", PETSC_DEFAULT, &fe[0]);CHKERRQ(ierr); | |
ierr = PetscObjectSetName((PetscObject) fe[0], "velocity");CHKERRQ(ierr); | |
ierr = PetscFEGetQuadrature(fe[0], &q);CHKERRQ(ierr); | |
ierr = PetscFECreateDefault(comm, dim, 1, user->simplex, "pres_", PETSC_DEFAULT, &fe[1]);CHKERRQ(ierr); | |
ierr = PetscFESetQuadrature(fe[1], q);CHKERRQ(ierr); | |
ierr = PetscObjectSetName((PetscObject) fe[1], "pressure");CHKERRQ(ierr); | |
/* Set discretization and boundary conditions for each mesh */ | |
ierr = DMSetField(dm, 0, NULL, (PetscObject) fe[0]);CHKERRQ(ierr); | |
ierr = DMSetField(dm, 1, NULL, (PetscObject) fe[1]);CHKERRQ(ierr); | |
ierr = DMCreateDS(dm);CHKERRQ(ierr); | |
ierr = SetupProblem(dm, user);CHKERRQ(ierr); | |
ierr = PetscBagGetData(user->bag, (void **) ¶m);CHKERRQ(ierr); | |
while (cdm) { | |
ierr = DMCopyDisc(dm, cdm);CHKERRQ(ierr); | |
ierr = DMPlexCreateBasisRotation(cdm, param->alpha, 0.0, 0.0);CHKERRQ(ierr); | |
ierr = DMGetCoarseDM(cdm, &cdm);CHKERRQ(ierr); | |
} | |
ierr = PetscFEDestroy(&fe[0]);CHKERRQ(ierr); | |
ierr = PetscFEDestroy(&fe[1]);CHKERRQ(ierr); | |
PetscFunctionReturn(0); | |
} | |
int main(int argc, char **argv) | |
{ | |
SNES snes; /* nonlinear solver */ | |
DM dm; /* problem definition */ | |
Vec u, r; /* solution and residual */ | |
AppCtx user; /* user-defined work context */ | |
PetscErrorCode ierr; | |
ierr = PetscInitialize(&argc, &argv, NULL,help);if (ierr) return ierr; | |
ierr = ProcessOptions(PETSC_COMM_WORLD, &user);CHKERRQ(ierr); | |
ierr = PetscBagCreate(PETSC_COMM_WORLD, sizeof(Parameter), &user.bag);CHKERRQ(ierr); | |
ierr = SetupParameters(&user);CHKERRQ(ierr); | |
ierr = SNESCreate(PETSC_COMM_WORLD, &snes);CHKERRQ(ierr); | |
ierr = CreateMesh(PETSC_COMM_WORLD, &user, &dm);CHKERRQ(ierr); | |
ierr = SNESSetDM(snes, dm);CHKERRQ(ierr); | |
ierr = DMSetApplicationContext(dm, &user);CHKERRQ(ierr); | |
/* Setup problem */ | |
ierr = PetscMalloc(2 * sizeof(void (*)(const PetscReal[], PetscScalar *, void *)), &user.exactFuncs);CHKERRQ(ierr); | |
ierr = SetupDiscretization(dm, &user);CHKERRQ(ierr); | |
ierr = DMPlexCreateClosureIndex(dm, NULL);CHKERRQ(ierr); | |
ierr = DMCreateGlobalVector(dm, &u);CHKERRQ(ierr); | |
ierr = VecDuplicate(u, &r);CHKERRQ(ierr); | |
ierr = DMPlexSetSNESLocalFEM(dm,&user,&user,&user);CHKERRQ(ierr); | |
ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); | |
{ | |
Parameter *param; | |
void *ctxs[2]; | |
ierr = PetscBagGetData(user.bag, (void **) ¶m);CHKERRQ(ierr); | |
ctxs[0] = ctxs[1] = param; | |
ierr = DMProjectFunction(dm, 0.0, user.exactFuncs, ctxs, INSERT_ALL_VALUES, u);CHKERRQ(ierr); | |
ierr = PetscObjectSetName((PetscObject) u, "Exact Solution");CHKERRQ(ierr); | |
ierr = VecViewFromOptions(u, NULL, "-exact_vec_view");CHKERRQ(ierr); | |
} | |
ierr = DMSNESCheckFromOptions(snes, u, NULL, NULL);CHKERRQ(ierr); | |
ierr = VecSet(u, 0.0);CHKERRQ(ierr); | |
ierr = PetscObjectSetName((PetscObject) u, "Solution");CHKERRQ(ierr); | |
ierr = SNESSolve(snes, NULL, u);CHKERRQ(ierr); | |
ierr = VecViewFromOptions(u, NULL, "-sol_vec_view");CHKERRQ(ierr); | |
ierr = VecDestroy(&u);CHKERRQ(ierr); | |
ierr = VecDestroy(&r);CHKERRQ(ierr); | |
ierr = PetscFree(user.exactFuncs);CHKERRQ(ierr); | |
ierr = DMDestroy(&dm);CHKERRQ(ierr); | |
ierr = SNESDestroy(&snes);CHKERRQ(ierr); | |
ierr = PetscBagDestroy(&user.bag);CHKERRQ(ierr); | |
ierr = PetscFinalize(); | |
return ierr; | |
} | |
/*TEST | |
# Convergence | |
test: | |
suffix: 2d_quad_q1_p0_conv | |
requires: !single | |
args: -simplex 0 -dm_plex_separate_marker -dm_refine 1 \ | |
-vel_petscspace_degree 1 -pres_petscspace_degree 0 \ | |
-snes_convergence_estimate -convest_num_refine 2 -snes_error_if_not_converged \ | |
-ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ | |
-pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ | |
-fieldsplit_velocity_pc_type lu \ | |
-fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi | |
test: | |
suffix: 2d_quad_q1_p0_conv_u0 | |
requires: !single | |
args: -simplex 0 -dm_plex_separate_marker -dm_refine 1 -u_0 0.125 \ | |
-vel_petscspace_degree 1 -pres_petscspace_degree 0 \ | |
-snes_convergence_estimate -convest_num_refine 2 -snes_error_if_not_converged \ | |
-ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ | |
-pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ | |
-fieldsplit_velocity_pc_type lu \ | |
-fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi | |
test: | |
suffix: 2d_quad_q1_p0_conv_u0_alpha | |
requires: !single | |
args: -simplex 0 -dm_plex_separate_marker -dm_refine 1 -u_0 0.125 -alpha 0.3927 \ | |
-vel_petscspace_degree 1 -pres_petscspace_degree 0 \ | |
-snes_convergence_estimate -convest_num_refine 2 -snes_error_if_not_converged \ | |
-ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ | |
-pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ | |
-fieldsplit_velocity_pc_type lu \ | |
-fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi | |
test: | |
suffix: 2d_quad_q1_p0_conv_gmg_vanka | |
requires: !single | |
args: -simplex 0 -dm_plex_separate_marker -cells 2,2 -dm_refine_hierarchy 1 \ | |
-vel_petscspace_degree 1 -pres_petscspace_degree 0 \ | |
-snes_convergence_estimate -convest_num_refine 1 -snes_error_if_not_converged \ | |
-ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ | |
-pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ | |
-fieldsplit_velocity_pc_type mg \ | |
-fieldsplit_velocity_mg_levels_pc_type patch -fieldsplit_velocity_mg_levels_pc_patch_partition_of_unity 0 \ | |
-fieldsplit_velocity_mg_levels_pc_patch_construct_codim 0 -fieldsplit_velocity_mg_levels_pc_patch_construct_type vanka \ | |
-fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi | |
test: | |
suffix: 2d_tri_p2_p1_conv | |
requires: triangle !single | |
args: -dm_plex_separate_marker -dm_refine 1 \ | |
-vel_petscspace_degree 2 -pres_petscspace_degree 1 \ | |
-dmsnes_check -snes_error_if_not_converged \ | |
-ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ | |
-pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ | |
-fieldsplit_velocity_pc_type lu \ | |
-fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi | |
test: | |
suffix: 2d_tri_p2_p1_conv_u0_alpha | |
requires: triangle !single | |
args: -dm_plex_separate_marker -dm_refine 0 -u_0 0.125 -alpha 0.3927 \ | |
-vel_petscspace_degree 2 -pres_petscspace_degree 1 \ | |
-dmsnes_check -snes_error_if_not_converged \ | |
-ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ | |
-pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ | |
-fieldsplit_velocity_pc_type lu \ | |
-fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi | |
test: | |
suffix: 2d_tri_p2_p1_conv_gmg_vcycle | |
requires: triangle !single | |
args: -dm_plex_separate_marker -cells 2,2 -dm_refine_hierarchy 1 \ | |
-vel_petscspace_degree 2 -pres_petscspace_degree 1 \ | |
-dmsnes_check -snes_error_if_not_converged \ | |
-ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ | |
-pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ | |
-fieldsplit_velocity_pc_type mg \ | |
-fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi | |
TEST*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import h5py | |
import numpy as np | |
import os, sys | |
class Xdmf: | |
def __init__(self, filename): | |
self.filename = filename | |
self.cellMap = {1 : {1 : 'Polyvertex', 2 : 'Polyline'}, 2 : {3 : 'Triangle', 4 : 'Quadrilateral'}, 3 : {4 : 'Tetrahedron', 6: 'Wedge', 8 : 'Hexahedron'}} | |
self.typeMap = {b'scalar' : 'Scalar', b'vector' : 'Vector', b'tensor' : | |
'Tensor6', b'matrix' : 'Matrix'} | |
self.typeExt = {2 : {b'vector' : ['x', 'y'], b'tensor' : ['xx', 'yy', | |
'xy']}, 3 : {b'vector' : ['x', 'y', 'z'], b'tensor' : ['xx', 'yy', 'zz', 'xy', 'yz', 'xz']}} | |
return | |
def writeHeader(self, fp, hdfFilename): | |
fp.write('''\ | |
<?xml version="1.0" ?> | |
<!DOCTYPE Xdmf SYSTEM "Xdmf.dtd" [ | |
<!ENTITY HeavyData "%s"> | |
]> | |
''' % os.path.basename(hdfFilename)) | |
fp.write('\n<Xdmf>\n <Domain Name="domain">\n') | |
return | |
def writeCells(self, fp, topologyPath, numCells, numCorners): | |
fp.write('''\ | |
<DataItem Name="cells" | |
ItemType="Uniform" | |
Format="HDF" | |
NumberType="Float" Precision="8" | |
Dimensions="%d %d"> | |
&HeavyData;:/%s/cells | |
</DataItem> | |
''' % (numCells, numCorners, topologyPath)) | |
return | |
def writeVertices(self, fp, geometryPath, numVertices, spaceDim): | |
fp.write('''\ | |
<DataItem Name="vertices" | |
Format="HDF" | |
Dimensions="%d %d"> | |
&HeavyData;:/%s/vertices | |
</DataItem> | |
<!-- ============================================================ --> | |
''' % (numVertices, spaceDim, geometryPath)) | |
return | |
def writeLocations(self, fp, numParticles, spaceDim): | |
fp.write('''\ | |
<DataItem Name="xcoord" | |
Format="HDF" | |
Dimensions="%d"> | |
&HeavyData;:/particles/xcoord | |
</DataItem> | |
''' % (numParticles)) | |
if spaceDim == 1: return | |
fp.write('''\ | |
<DataItem Name="ycoord" | |
Format="HDF" | |
Dimensions="%d"> | |
&HeavyData;:/particles/ycoord | |
</DataItem> | |
''' % (numParticles)) | |
if spaceDim == 2: return | |
fp.write('''\ | |
<DataItem Name="zcoord" | |
Format="HDF" | |
Dimensions="%d"> | |
&HeavyData;:/particles/zcoord | |
</DataItem> | |
''' % (numParticles)) | |
return | |
def writeTimeGridHeader(self, fp, time): | |
fp.write('''\ | |
<Grid Name="TimeSeries" GridType="Collection" CollectionType="Temporal"> | |
<Time TimeType="List"> | |
<DataItem Format="XML" NumberType="Float" Dimensions="%d"> | |
''' % (len(time))) | |
fp.write(' '.join([str(float(t)) for t in time])) | |
fp.write(''' | |
</DataItem> | |
</Time> | |
''') | |
return | |
def writeSpaceGridHeader(self, fp, numCells, numCorners, cellDim, spaceDim): | |
fp.write('''\ | |
<Grid Name="domain" GridType="Uniform"> | |
<Topology | |
TopologyType="%s" | |
NumberOfElements="%d"> | |
<DataItem Reference="XML"> | |
/Xdmf/Domain/DataItem[@Name="cells"] | |
</DataItem> | |
</Topology> | |
<Geometry GeometryType="%s"> | |
<DataItem Reference="XML"> | |
/Xdmf/Domain/DataItem[@Name="vertices"] | |
</DataItem> | |
</Geometry> | |
''' % (self.cellMap[cellDim][numCorners], numCells, "XYZ" if spaceDim > 2 else "XY")) | |
return | |
def writeFieldSingle(self, fp, numSteps, timestep, spaceDim, name, f, domain): | |
if len(f[1].shape) > 2: | |
dof = f[1].shape[1] | |
bs = f[1].shape[2] | |
elif len(f[1].shape) > 1: | |
if numSteps > 1: | |
dof = f[1].shape[1] | |
bs = 1 | |
else: | |
dof = f[1].shape[0] | |
bs = f[1].shape[1] | |
else: | |
dof = f[1].shape[0] | |
bs = 1 | |
fp.write('''\ | |
<Attribute | |
Name="%s" | |
Type="%s" | |
Center="%s"> | |
<DataItem ItemType="HyperSlab" | |
Dimensions="1 %d %d" | |
Type="HyperSlab"> | |
<DataItem | |
Dimensions="3 3" | |
Format="XML"> | |
%d 0 0 | |
1 1 1 | |
1 %d %d | |
</DataItem> | |
<DataItem | |
DataType="Float" Precision="8" | |
Dimensions="%d %d %d" | |
Format="HDF"> | |
&HeavyData;:%s | |
</DataItem> | |
</DataItem> | |
</Attribute> | |
''' % (f[0], self.typeMap[f[1].attrs['vector_field_type']], domain, dof, bs, timestep, dof, bs, numSteps, dof, bs, name)) | |
return | |
def writeFieldComponents(self, fp, numSteps, timestep, spaceDim, name, f, domain): | |
vtype = f[1].attrs['vector_field_type'] | |
if len(f[1].shape) > 2: | |
dof = f[1].shape[1] | |
bs = f[1].shape[2] | |
cdims = '1 %d 1' % dof | |
dims = '%d %d %d' % (numSteps, dof, bs) | |
stride = '1 1 1' | |
size = '1 %d 1' % dof | |
else: | |
dof = f[1].shape[0] | |
bs = f[1].shape[1] | |
cdims = '%d 1' % dof | |
dims = '%d %d' % (dof, bs) | |
stride = '1 1' | |
size = '%d 1' % dof | |
for c in range(bs): | |
ext = self.typeExt[spaceDim][vtype][c] | |
if len(f[1].shape) > 2: start = '%d 0 %d' % (timestep, c) | |
else: start = '0 %d' % c | |
fp.write('''\ | |
<Attribute | |
Name="%s" | |
Type="Scalar" | |
Center="%s"> | |
<DataItem ItemType="HyperSlab" | |
Dimensions="%s" | |
Type="HyperSlab"> | |
<DataItem | |
Dimensions="3 %d" | |
Format="XML"> | |
%s | |
%s | |
%s | |
</DataItem> | |
<DataItem | |
DataType="Float" Precision="8" | |
Dimensions="%s" | |
Format="HDF"> | |
&HeavyData;:%s | |
</DataItem> | |
</DataItem> | |
</Attribute> | |
''' % (f[0]+'_'+ext, domain, cdims, len(f[1].shape), start, stride, size, dims, name)) | |
return | |
def writeField(self, fp, numSteps, timestep, cellDim, spaceDim, name, f, domain): | |
ctypes = [b'tensor', b'matrix'] | |
if spaceDim == 2 or cellDim != spaceDim: ctypes.append(b'vector') | |
if f[1].attrs['vector_field_type'] in ctypes: | |
self.writeFieldComponents(fp, numSteps, timestep, spaceDim, name, f, domain) | |
else: | |
self.writeFieldSingle(fp, numSteps, timestep, spaceDim, name, f, domain) | |
return | |
def writeSpaceGridFooter(self, fp): | |
fp.write(' </Grid>\n') | |
return | |
def writeParticleGridHeader(self, fp, numParticles, spaceDim): | |
fp.write('''\ | |
<Grid Name="particle_domain" GridType="Uniform"> | |
<Topology TopologyType="Polyvertex" NodesPerElement="%d" /> | |
<Geometry GeometryType="%s"> | |
<DataItem Reference="XML">/Xdmf/Domain/DataItem[@Name="xcoord"]</DataItem> | |
<DataItem Reference="XML">/Xdmf/Domain/DataItem[@Name="ycoord"]</DataItem> | |
%s | |
</Geometry> | |
''' % (numParticles, "X_Y_Z" if spaceDim > 2 else "X_Y", "<DataItem Reference=\"XML\">/Xdmf/Domain/DataItem[@Name=\"zcoord\"]</DataItem>" if spaceDim > 2 else "")) | |
return | |
def writeParticleField(self, fp, numParticles, spaceDim): | |
fp.write('''\ | |
<Attribute Name="particles/icoord"> | |
<DataItem Name="icoord" | |
Format="HDF" | |
Dimensions="%d"> | |
&HeavyData;:/particles/icoord | |
</DataItem> | |
</Attribute>''' % (numParticles)) | |
return | |
def writeTimeGridFooter(self, fp): | |
fp.write(' </Grid>\n') | |
return | |
def writeFooter(self, fp): | |
fp.write(' </Domain>\n</Xdmf>\n') | |
return | |
def write(self, hdfFilename, topologyPath, numCells, numCorners, cellDim, geometryPath, numVertices, spaceDim, time, vfields, cfields, numParticles): | |
useTime = not (len(time) < 2 and time[0] == -1) | |
with open(self.filename, 'w') as fp: | |
self.writeHeader(fp, hdfFilename) | |
# Field information | |
self.writeCells(fp, topologyPath, numCells, numCorners) | |
self.writeVertices(fp, geometryPath, numVertices, spaceDim) | |
if useTime: self.writeTimeGridHeader(fp, time) | |
for t in range(len(time)): | |
self.writeSpaceGridHeader(fp, numCells, numCorners, cellDim, spaceDim) | |
for vf in vfields: self.writeField(fp, len(time), t, cellDim, spaceDim, '/vertex_fields/'+vf[0], vf, 'Node') | |
for cf in cfields: self.writeField(fp, len(time), t, cellDim, spaceDim, '/cell_fields/'+cf[0], cf, 'Cell') | |
self.writeSpaceGridFooter(fp) | |
if useTime: self.writeTimeGridFooter(fp) | |
if numParticles: | |
self.writeLocations(fp, numParticles, spaceDim) | |
if useTime: self.writeTimeGridHeader(fp, time) | |
for t in range(len(time)): | |
self.writeParticleGridHeader(fp, numParticles, spaceDim) | |
self.writeSpaceGridFooter(fp) | |
if useTime: self.writeTimeGridFooter(fp) | |
self.writeFooter(fp) | |
return | |
def generateXdmf(hdfFilename, xdmfFilename = None): | |
if xdmfFilename is None: | |
xdmfFilename = os.path.splitext(hdfFilename)[0] + '.xmf' | |
# Read mesh | |
h5 = h5py.File(hdfFilename, 'r') | |
if 'viz' in h5 and 'geometry' in h5['viz']: | |
geomPath = 'viz/geometry' | |
geom = h5['viz']['geometry'] | |
else: | |
geomPath = 'geometry' | |
geom = h5['geometry'] | |
if 'viz' in h5 and 'topology' in h5['viz']: | |
topoPath = 'viz/topology' | |
topo = h5['viz']['topology'] | |
else: | |
topoPath = 'topology' | |
topo = h5['topology'] | |
vertices = geom['vertices'] | |
numVertices = vertices.shape[0] | |
spaceDim = vertices.shape[1] | |
cells = topo['cells'] | |
numCells = cells.shape[0] | |
numCorners = cells.shape[1] | |
cellDim = topo['cells'].attrs['cell_dim'] | |
if 'time' in h5: | |
time = np.array(h5['time']).flatten() | |
else: | |
time = [-1] | |
vfields = [] | |
cfields = [] | |
if 'vertex_fields' in h5: vfields = h5['vertex_fields'].items() | |
if 'cell_fields' in h5: cfields = h5['cell_fields'].items() | |
numParticles = 0 | |
if 'particles' in h5: numParticles = h5['particles']['xcoord'].shape[0] | |
''' | |
if 'vertex_fields' in h5: vfields = list(h5['vertex_fields'].items()) | |
if 'cell_fields' in h5: cfields = list(h5['cell_fields'].items()) | |
numParticles = 0 | |
if 'particles' in h5: numParticles = list(h5['particles']['xcoord'].shape[0]) | |
''' | |
# Write Xdmf | |
Xdmf(xdmfFilename).write(hdfFilename, topoPath, numCells, numCorners, cellDim, geomPath, numVertices, spaceDim, time, vfields, cfields, numParticles) | |
h5.close() | |
return | |
if __name__ == '__main__': | |
for f in sys.argv[1:]: | |
generateXdmf(f) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment