static char help[] = "Tests for ephemeral meshes.\n"; #include #include #include /* Use -ref_dm_view -eph_dm_view to view the concrete and ephemeral meshes from the first transformation, and -ref_dm_sec_view -eph_dm_sec_view for the second. */ // Should remove when I have an API for everything #include typedef struct { DMLabel active; /* Label for transform */ PetscBool second; /* Flag to execute a second transformation */ PetscBool concrete; /* Flag to use the concrete mesh for the second transformation */ } AppCtx; static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) { PetscInt cells[1024], Nc = 1024; PetscBool flg; PetscFunctionBeginUser; options->active = NULL; options->second = PETSC_FALSE; options->concrete = PETSC_FALSE; PetscOptionsBegin(comm, "", "Ephemeral Meshing Options", "DMPLEX"); PetscCall(PetscOptionsIntArray("-cells", "Cells to mark for transformation", "ex57.c", cells, &Nc, &flg)); if (flg) { PetscCall(DMLabelCreate(comm, "active", &options->active)); for (PetscInt c = 0; c < Nc; ++c) PetscCall(DMLabelSetValue(options->active, cells[c], DM_ADAPT_REFINE)); } PetscCall(PetscOptionsBool("-second", "Use a second transformation", "ex57.c", options->second, &options->second, &flg)); PetscCall(PetscOptionsBool("-concrete", "Use concrete mesh for the second transformation", "ex57.c", options->concrete, &options->concrete, &flg)); PetscOptionsEnd(); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm) { PetscFunctionBeginUser; PetscCall(DMCreate(comm, dm)); PetscCall(DMSetType(*dm, DMPLEX)); PetscCall(DMSetFromOptions(*dm)); PetscCall(PetscObjectSetName((PetscObject)*dm, "Mesh")); PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view")); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode CreateTransform(DM dm, DMLabel active, const char prefix[], DMPlexTransform *tr) { PetscFunctionBeginUser; PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), tr)); PetscCall(PetscObjectSetName((PetscObject)*tr, "Transform")); PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*tr, prefix)); PetscCall(DMPlexTransformSetDM(*tr, dm)); PetscCall(DMPlexTransformSetActive(*tr, active)); PetscCall(DMPlexTransformSetFromOptions(*tr)); PetscCall(DMPlexTransformSetUp(*tr)); PetscCall(DMSetApplicationContext(dm, *tr)); PetscCall(PetscObjectViewFromOptions((PetscObject)*tr, NULL, "-dm_plex_transform_view")); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode CreateEphemeralMesh(DMPlexTransform tr, DM *tdm) { PetscFunctionBegin; PetscCall(DMPlexCreateEphemeral(tr, "eph_", tdm)); PetscCall(PetscObjectSetName((PetscObject)*tdm, "Ephemeral Mesh")); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode CreateConcreteMesh(DMPlexTransform tr, DM *rdm) { DM cdm, codm, rcodm; PetscFunctionBegin; PetscCall(DMPlexTransformGetDM(tr, &cdm)); PetscCall(DMPlexTransformApply(tr, cdm, rdm)); PetscCall(DMSetCoarsenLevel(*rdm, cdm->leveldown)); PetscCall(DMSetRefineLevel(*rdm, cdm->levelup + 1)); PetscCall(DMCopyDisc(cdm, *rdm)); PetscCall(DMGetCoordinateDM(cdm, &codm)); PetscCall(DMGetCoordinateDM(*rdm, &rcodm)); PetscCall(DMCopyDisc(codm, rcodm)); PetscCall(DMPlexTransformCreateDiscLabels(tr, *rdm)); PetscCall(DMSetCoarseDM(*rdm, cdm)); PetscCall(DMPlexSetRegularRefinement(*rdm, PETSC_TRUE)); if (rdm) { ((DM_Plex *)(*rdm)->data)->printFEM = ((DM_Plex *)cdm->data)->printFEM; ((DM_Plex *)(*rdm)->data)->printL2 = ((DM_Plex *)cdm->data)->printL2; } PetscCall(PetscObjectSetName((PetscObject)*rdm, "Concrete Mesh")); PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*rdm, "ref_")); PetscFunctionReturn(PETSC_SUCCESS); } // dmA is concrete and dmB is ephemeral static PetscErrorCode CompareMeshes(DM dmA, DM dmB, DM dm) { PetscInt dim, dimB, pStart, pEnd, pStartB, pEndB; MPI_Comm comm; PetscFunctionBegin; PetscCall(PetscObjectGetComm((PetscObject)dmA, &comm)); PetscCall(DMGetDimension(dmA, &dim)); PetscCall(DMGetDimension(dmB, &dimB)); PetscCheck(dim == dimB, comm, PETSC_ERR_ARG_INCOMP, "Dimension from dmA %" PetscInt_FMT " != %" PetscInt_FMT " from dmB", dim, dimB); PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); PetscCheck(pStart == pStartB && pEnd == pEndB, comm, PETSC_ERR_ARG_INCOMP, "Chart from dmA (%" PetscInt_FMT ", %" PetscInt_FMT ") does not match (%" PetscInt_FMT ", %" PetscInt_FMT ") for dmB", pStart, pEnd, pStartB, pEndB); for (PetscInt p = pStart; p < pEnd; ++p) { const PetscInt *cone, *ornt, *coneB, *orntB; PetscInt coneSize, coneSizeB; PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); PetscCheck(coneSize == coneSizeB, comm, PETSC_ERR_ARG_INCOMP, "Cone size for %" PetscInt_FMT " from dmA %" PetscInt_FMT " does not match %" PetscInt_FMT " for dmB", p, coneSize, coneSizeB); PetscCall(DMPlexGetOrientedCone(dmA, p, &cone, &ornt)); PetscCall(DMPlexGetOrientedCone(dmB, p, &coneB, &orntB)); for (PetscInt c = 0; c < coneSize; ++c) { PetscCheck(cone[c] == coneB[c] && ornt[c] == orntB[c], comm, PETSC_ERR_ARG_INCOMP, "Cone point %" PetscInt_FMT " for point %" PetscInt_FMT " from dmA (%" PetscInt_FMT ", %" PetscInt_FMT ") does not match (%" PetscInt_FMT ", %" PetscInt_FMT ") for dmB", c, p, cone[c], ornt[c], coneB[c], orntB[c]); } PetscCall(DMPlexRestoreOrientedCone(dmA, p, &cone, &ornt)); PetscCall(DMPlexRestoreOrientedCone(dmB, p, &coneB, &orntB)); } PetscFunctionReturn(PETSC_SUCCESS); } int main(int argc, char *argv[]) { DM dm, tdm, rdm; DMPlexTransform tr; AppCtx user; MPI_Comm comm; PetscFunctionBeginUser; PetscCall(PetscInitialize(&argc, &argv, NULL, help)); comm = PETSC_COMM_WORLD; PetscCall(ProcessOptions(comm, &user)); PetscCall(CreateMesh(comm, &dm)); PetscCall(CreateTransform(dm, user.active, "first_", &tr)); PetscCall(CreateEphemeralMesh(tr, &tdm)); PetscCall(CreateConcreteMesh(tr, &rdm)); if (user.second) { DMPlexTransform tr2; DM tdm2, rdm2; PetscCall(DMViewFromOptions(rdm, NULL, "-dm_sec_view")); PetscCall(DMViewFromOptions(tdm, NULL, "-dm_sec_view")); if (user.concrete) PetscCall(CreateTransform(rdm, user.active, "second_", &tr2)); else PetscCall(CreateTransform(tdm, user.active, "second_", &tr2)); PetscCall(CreateEphemeralMesh(tr2, &tdm2)); PetscCall(CreateConcreteMesh(tr2, &rdm2)); PetscCall(DMDestroy(&tdm)); PetscCall(DMDestroy(&rdm)); PetscCall(DMPlexTransformDestroy(&tr2)); tdm = tdm2; rdm = rdm2; } PetscCall(DMViewFromOptions(tdm, NULL, "-dm_view")); PetscCall(DMViewFromOptions(rdm, NULL, "-dm_view")); PetscCall(CompareMeshes(rdm, tdm, dm)); PetscCall(DMPlexTransformDestroy(&tr)); PetscCall(DMDestroy(&tdm)); PetscCall(DMDestroy(&rdm)); PetscCall(DMDestroy(&dm)); PetscCall(DMLabelDestroy(&user.active)); PetscCall(PetscFinalize()); return 0; } /*TEST # Tests for regular refinement of whole meshes test: suffix: tri requires: triangle args: -first_dm_plex_transform_view ::ascii_info_detail test: suffix: quad args: -dm_plex_simplex 0 output_file: output/empty.out # Here I am checking that the 'marker' label is correct for the ephemeral mesh test: suffix: tet requires: ctetgen args: -dm_plex_dim 3 -ref_dm_view -eph_dm_view -eph_dm_plex_view_labels marker test: suffix: hex args: -dm_plex_dim 3 -dm_plex_simplex 0 output_file: output/empty.out # Tests for filter patches testset: args: -first_dm_plex_transform_type transform_filter -ref_dm_view test: suffix: tri_patch requires: triangle args: -cells 0,1,2,4 test: suffix: quad_patch args: -dm_plex_simplex 0 -dm_plex_box_faces 3,3 -cells 0,1,3,4 # Tests for refined filter patches testset: args: -first_dm_plex_transform_type transform_filter -ref_dm_view -eph_dm_view -second test: suffix: tri_patch_ref requires: triangle args: -cells 0,1,2,4 test: suffix: tri_patch_ref_concrete requires: triangle args: -cells 0,1,2,4 -concrete -first_dm_plex_transform_view ::ascii_info_detail # Tests for boundary layer refinement test: suffix: quad_bl args: -dm_plex_simplex 0 -dm_plex_dim 1 -dm_plex_box_faces 5 -dm_extrude 2 -cells 0,2,4,6,8 \ -first_dm_plex_transform_type refine_boundary_layer -first_dm_plex_transform_bl_splits 4 \ -ref_dm_view # Tests for extrusion test: suffix: sphere_extruded args: -dm_plex_shape sphere \ -first_dm_plex_transform_type extrude \ -first_dm_plex_transform_extrude_layers 3 \ -first_dm_plex_transform_extrude_use_tensor 0 output_file: output/empty.out TEST*/