static char help[] = "Demonstration of creating and viewing DMFields objects.\n\n"; #include #include #include static PetscErrorCode ViewResults(PetscViewer viewer, PetscInt N, PetscInt dim, PetscScalar *B, PetscScalar *D, PetscScalar *H, PetscReal *rB, PetscReal *rD, PetscReal *rH) { PetscFunctionBegin; PetscCall(PetscViewerASCIIPrintf(viewer, "B:\n")); PetscCall(PetscScalarView(N, B, viewer)); PetscCall(PetscViewerASCIIPrintf(viewer, "D:\n")); PetscCall(PetscScalarView(N * dim, D, viewer)); PetscCall(PetscViewerASCIIPrintf(viewer, "H:\n")); PetscCall(PetscScalarView(N * dim * dim, H, viewer)); PetscCall(PetscViewerASCIIPrintf(viewer, "rB:\n")); PetscCall(PetscRealView(N, rB, viewer)); PetscCall(PetscViewerASCIIPrintf(viewer, "rD:\n")); PetscCall(PetscRealView(N * dim, rD, viewer)); PetscCall(PetscViewerASCIIPrintf(viewer, "rH:\n")); PetscCall(PetscRealView(N * dim * dim, rH, viewer)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode TestEvaluate(DMField field, PetscInt n, PetscRandom rand) { DM dm; PetscInt dim, i, nc; PetscScalar *B, *D, *H; PetscReal *rB, *rD, *rH; Vec points; PetscScalar *array; PetscViewer viewer; MPI_Comm comm; PetscFunctionBegin; comm = PetscObjectComm((PetscObject)field); PetscCall(DMFieldGetNumComponents(field, &nc)); PetscCall(DMFieldGetDM(field, &dm)); PetscCall(DMGetDimension(dm, &dim)); PetscCall(VecCreateFromOptions(PetscObjectComm((PetscObject)field), NULL, 1, n * dim, PETSC_DETERMINE, &points)); PetscCall(VecSetBlockSize(points, dim)); PetscCall(VecGetArray(points, &array)); for (i = 0; i < n * dim; i++) PetscCall(PetscRandomGetValue(rand, &array[i])); PetscCall(VecRestoreArray(points, &array)); PetscCall(PetscMalloc6(n * nc, &B, n * nc, &rB, n * nc * dim, &D, n * nc * dim, &rD, n * nc * dim * dim, &H, n * nc * dim * dim, &rH)); PetscCall(DMFieldEvaluate(field, points, PETSC_SCALAR, B, D, H)); PetscCall(DMFieldEvaluate(field, points, PETSC_REAL, rB, rD, rH)); viewer = PETSC_VIEWER_STDOUT_(comm); PetscCall(PetscObjectSetName((PetscObject)points, "Test Points")); PetscCall(VecView(points, viewer)); PetscCall(ViewResults(viewer, n * nc, dim, B, D, H, rB, rD, rH)); PetscCall(PetscFree6(B, rB, D, rD, H, rH)); PetscCall(VecDestroy(&points)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode TestEvaluateFE(DMField field, PetscInt n, PetscInt cStart, PetscInt cEnd, PetscQuadrature quad, PetscRandom rand) { DM dm; PetscInt dim, i, nc, nq; PetscInt N; PetscScalar *B, *D, *H; PetscReal *rB, *rD, *rH; PetscInt *cells; IS cellIS; PetscViewer viewer; MPI_Comm comm; PetscFunctionBegin; comm = PetscObjectComm((PetscObject)field); PetscCall(DMFieldGetNumComponents(field, &nc)); PetscCall(DMFieldGetDM(field, &dm)); PetscCall(DMGetDimension(dm, &dim)); PetscCall(PetscRandomSetInterval(rand, (PetscScalar)cStart, (PetscScalar)cEnd)); PetscCall(PetscMalloc1(n, &cells)); for (i = 0; i < n; i++) { PetscReal rc; PetscCall(PetscRandomGetValueReal(rand, &rc)); cells[i] = PetscFloorReal(rc); } PetscCall(ISCreateGeneral(comm, n, cells, PETSC_OWN_POINTER, &cellIS)); PetscCall(PetscObjectSetName((PetscObject)cellIS, "FE Test Cells")); PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &nq, NULL, NULL)); N = n * nq * nc; PetscCall(PetscMalloc6(N, &B, N, &rB, N * dim, &D, N * dim, &rD, N * dim * dim, &H, N * dim * dim, &rH)); PetscCall(DMFieldEvaluateFE(field, cellIS, quad, PETSC_SCALAR, B, D, H)); PetscCall(DMFieldEvaluateFE(field, cellIS, quad, PETSC_REAL, rB, rD, rH)); viewer = PETSC_VIEWER_STDOUT_(comm); PetscCall(PetscObjectSetName((PetscObject)quad, "Test quadrature")); PetscCall(PetscQuadratureView(quad, viewer)); PetscCall(ISView(cellIS, viewer)); PetscCall(ViewResults(viewer, N, dim, B, D, H, rB, rD, rH)); PetscCall(PetscFree6(B, rB, D, rD, H, rH)); PetscCall(ISDestroy(&cellIS)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode TestEvaluateFV(DMField field, PetscInt n, PetscInt cStart, PetscInt cEnd, PetscRandom rand) { DM dm; PetscInt dim, i, nc; PetscInt N; PetscScalar *B, *D, *H; PetscReal *rB, *rD, *rH; PetscInt *cells; IS cellIS; PetscViewer viewer; MPI_Comm comm; PetscFunctionBegin; comm = PetscObjectComm((PetscObject)field); PetscCall(DMFieldGetNumComponents(field, &nc)); PetscCall(DMFieldGetDM(field, &dm)); PetscCall(DMGetDimension(dm, &dim)); PetscCall(PetscRandomSetInterval(rand, (PetscScalar)cStart, (PetscScalar)cEnd)); PetscCall(PetscMalloc1(n, &cells)); for (i = 0; i < n; i++) { PetscReal rc; PetscCall(PetscRandomGetValueReal(rand, &rc)); cells[i] = PetscFloorReal(rc); } PetscCall(ISCreateGeneral(comm, n, cells, PETSC_OWN_POINTER, &cellIS)); PetscCall(PetscObjectSetName((PetscObject)cellIS, "FV Test Cells")); N = n * nc; PetscCall(PetscMalloc6(N, &B, N, &rB, N * dim, &D, N * dim, &rD, N * dim * dim, &H, N * dim * dim, &rH)); PetscCall(DMFieldEvaluateFV(field, cellIS, PETSC_SCALAR, B, D, H)); PetscCall(DMFieldEvaluateFV(field, cellIS, PETSC_REAL, rB, rD, rH)); viewer = PETSC_VIEWER_STDOUT_(comm); PetscCall(ISView(cellIS, viewer)); PetscCall(ViewResults(viewer, N, dim, B, D, H, rB, rD, rH)); PetscCall(PetscFree6(B, rB, D, rD, H, rH)); PetscCall(ISDestroy(&cellIS)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode radiusSquared(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], PetscCtx ctx) { PetscInt i; PetscReal r2 = 0.; PetscFunctionBegin; for (i = 0; i < dim; i++) r2 += PetscSqr(x[i]); for (i = 0; i < Nf; i++) u[i] = (i + 1) * r2; PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode TestShellEvaluate(DMField field, Vec points, PetscDataType type, void *B, void *D, void *H) { Vec ctxVec = NULL; const PetscScalar *mult; PetscInt dim; const PetscScalar *x; PetscInt Nc, n, i, j, k, l; PetscFunctionBegin; PetscCall(DMFieldGetNumComponents(field, &Nc)); PetscCall(DMFieldShellGetContext(field, &ctxVec)); PetscCall(VecGetBlockSize(points, &dim)); PetscCall(VecGetLocalSize(points, &n)); n /= Nc; PetscCall(VecGetArrayRead(ctxVec, &mult)); PetscCall(VecGetArrayRead(points, &x)); for (i = 0; i < n; i++) { PetscReal r2 = 0.; for (j = 0; j < dim; j++) r2 += PetscSqr(PetscRealPart(x[i * dim + j])); for (j = 0; j < Nc; j++) { PetscReal m = PetscRealPart(mult[j]); if (B) { if (type == PETSC_SCALAR) { ((PetscScalar *)B)[i * Nc + j] = m * r2; } else { ((PetscReal *)B)[i * Nc + j] = m * r2; } } if (D) { if (type == PETSC_SCALAR) { for (k = 0; k < dim; k++) ((PetscScalar *)D)[(i * Nc + j) * dim + k] = 2. * m * x[i * dim + k]; } else { for (k = 0; k < dim; k++) ((PetscReal *)D)[(i * Nc + j) * dim + k] = 2. * m * PetscRealPart(x[i * dim + k]); } } if (H) { if (type == PETSC_SCALAR) { for (k = 0; k < dim; k++) for (l = 0; l < dim; l++) ((PetscScalar *)H)[((i * Nc + j) * dim + k) * dim + l] = (k == l) ? 2. * m : 0.; } else { for (k = 0; k < dim; k++) for (l = 0; l < dim; l++) ((PetscReal *)H)[((i * Nc + j) * dim + k) * dim + l] = (k == l) ? 2. * m : 0.; } } } } PetscCall(VecRestoreArrayRead(points, &x)); PetscCall(VecRestoreArrayRead(ctxVec, &mult)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode TestShellDestroy(DMField field) { Vec ctxVec = NULL; PetscFunctionBegin; PetscCall(DMFieldShellGetContext(field, &ctxVec)); PetscCall(VecDestroy(&ctxVec)); PetscFunctionReturn(PETSC_SUCCESS); } int main(int argc, char **argv) { DM dm = NULL; MPI_Comm comm; char type[256] = DMPLEX; PetscBool isda, isplex; PetscInt dim = 2; DMField field = NULL; PetscInt nc = 1; PetscInt cStart = -1, cEnd = -1; PetscRandom rand; PetscQuadrature quad = NULL; PetscInt pointsPerEdge = 2; PetscInt numPoint = 0, numFE = 0, numFV = 0; PetscBool testShell = PETSC_FALSE; PetscFunctionBeginUser; PetscCall(PetscInitialize(&argc, &argv, NULL, help)); comm = PETSC_COMM_WORLD; PetscOptionsBegin(comm, "", "DMField Tutorial Options", "DM"); PetscCall(PetscOptionsFList("-dm_type", "DM implementation on which to define field", "ex1.c", DMList, type, type, 256, NULL)); PetscCall(PetscOptionsRangeInt("-dim", "DM intrinsic dimension", "ex1.c", dim, &dim, NULL, 1, 3)); PetscCall(PetscOptionsBoundedInt("-num_components", "Number of components in field", "ex1.c", nc, &nc, NULL, 1)); PetscCall(PetscOptionsBoundedInt("-num_quad_points", "Number of quadrature points per dimension", "ex1.c", pointsPerEdge, &pointsPerEdge, NULL, 1)); PetscCall(PetscOptionsBoundedInt("-num_point_tests", "Number of test points for DMFieldEvaluate()", "ex1.c", numPoint, &numPoint, NULL, 0)); PetscCall(PetscOptionsBoundedInt("-num_fe_tests", "Number of test cells for DMFieldEvaluateFE()", "ex1.c", numFE, &numFE, NULL, 0)); PetscCall(PetscOptionsBoundedInt("-num_fv_tests", "Number of test cells for DMFieldEvaluateFV()", "ex1.c", numFV, &numFV, NULL, 0)); PetscCall(PetscOptionsBool("-test_shell", "Test the DMFIELDSHELL implementation of DMField", "ex1.c", testShell, &testShell, NULL)); PetscOptionsEnd(); PetscCheck(dim <= 3, comm, PETSC_ERR_ARG_OUTOFRANGE, "This examples works for dim <= 3, not %" PetscInt_FMT, dim); PetscCall(PetscStrncmp(type, DMPLEX, 256, &isplex)); PetscCall(PetscStrncmp(type, DMDA, 256, &isda)); PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &rand)); PetscCall(PetscRandomSetFromOptions(rand)); if (isplex) { PetscInt overlap = 0; Vec fieldvec; PetscInt cells[3] = {3, 3, 3}; PetscBool simplex; PetscFE fe; PetscOptionsBegin(comm, "", "DMField DMPlex Options", "DM"); PetscCall(PetscOptionsBoundedInt("-overlap", "DMPlex parallel overlap", "ex1.c", overlap, &overlap, NULL, 0)); PetscOptionsEnd(); if (0) { PetscCall(DMPlexCreateBoxMesh(comm, 2, PETSC_TRUE, cells, NULL, NULL, NULL, PETSC_TRUE, 0, PETSC_TRUE, &dm)); } else { PetscCall(DMCreate(comm, &dm)); PetscCall(DMSetType(dm, DMPLEX)); PetscCall(DMSetFromOptions(dm)); CHKMEMQ; } PetscCall(DMGetDimension(dm, &dim)); PetscCall(DMPlexIsSimplex(dm, &simplex)); if (simplex) PetscCall(PetscDTStroudConicalQuadrature(dim, 1, pointsPerEdge, -1.0, 1.0, &quad)); else PetscCall(PetscDTGaussTensorQuadrature(dim, 1, pointsPerEdge, -1.0, 1.0, &quad)); PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); if (testShell) { Vec ctxVec; PetscInt i; PetscScalar *array; PetscCall(VecCreateSeq(PETSC_COMM_SELF, nc, &ctxVec)); PetscCall(VecSetUp(ctxVec)); PetscCall(VecGetArray(ctxVec, &array)); for (i = 0; i < nc; i++) array[i] = i + 1.; PetscCall(VecRestoreArray(ctxVec, &array)); PetscCall(DMFieldCreateShell(dm, nc, DMFIELD_VERTEX, (void *)ctxVec, &field)); PetscCall(DMFieldShellSetEvaluate(field, TestShellEvaluate)); PetscCall(DMFieldShellSetDestroy(field, TestShellDestroy)); } else { PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, nc, simplex, NULL, PETSC_DEFAULT, &fe)); PetscCall(PetscFESetName(fe, "MyPetscFE")); PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fe)); PetscCall(PetscFEDestroy(&fe)); PetscCall(DMCreateDS(dm)); PetscCall(DMCreateLocalVector(dm, &fieldvec)); { PetscErrorCode (*func[1])(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *); PetscCtx ctxs[1]; func[0] = radiusSquared; ctxs[0] = NULL; PetscCall(DMProjectFunctionLocal(dm, 0.0, func, ctxs, INSERT_ALL_VALUES, fieldvec)); } PetscCall(DMFieldCreateDS(dm, 0, fieldvec, &field)); PetscCall(VecDestroy(&fieldvec)); } } else if (isda) { PetscInt i; PetscScalar *cv; switch (dim) { case 1: PetscCall(DMDACreate1d(comm, DM_BOUNDARY_NONE, 3, 1, 1, NULL, &dm)); break; case 2: PetscCall(DMDACreate2d(comm, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, 3, 3, PETSC_DETERMINE, PETSC_DETERMINE, 1, 1, NULL, NULL, &dm)); break; default: PetscCall(DMDACreate3d(comm, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, 3, 3, 3, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_DETERMINE, 1, 1, NULL, NULL, NULL, &dm)); break; } PetscCall(DMSetUp(dm)); PetscCall(DMDAGetHeightStratum(dm, 0, &cStart, &cEnd)); PetscCall(PetscMalloc1(nc * (1 << dim), &cv)); for (i = 0; i < nc * (1 << dim); i++) { PetscReal rv; PetscCall(PetscRandomGetValueReal(rand, &rv)); cv[i] = rv; } PetscCall(DMFieldCreateDA(dm, nc, cv, &field)); PetscCall(PetscFree(cv)); PetscCall(PetscDTGaussTensorQuadrature(dim, 1, pointsPerEdge, -1.0, 1.0, &quad)); } else SETERRQ(comm, PETSC_ERR_SUP, "This test does not run for DM type %s", type); PetscCall(PetscObjectSetName((PetscObject)dm, "mesh")); PetscCall(DMViewFromOptions(dm, NULL, "-dm_view")); PetscCall(DMDestroy(&dm)); PetscCall(PetscObjectSetName((PetscObject)field, "field")); PetscCall(PetscObjectViewFromOptions((PetscObject)field, NULL, "-dmfield_view")); if (numPoint) PetscCall(TestEvaluate(field, numPoint, rand)); if (numFE) PetscCall(TestEvaluateFE(field, numFE, cStart, cEnd, quad, rand)); if (numFV) PetscCall(TestEvaluateFV(field, numFV, cStart, cEnd, rand)); PetscCall(DMFieldDestroy(&field)); PetscCall(PetscQuadratureDestroy(&quad)); PetscCall(PetscRandomDestroy(&rand)); PetscCall(PetscFinalize()); return 0; } /*TEST test: suffix: da requires: !complex args: -dm_type da -dim 2 -num_components 2 -num_point_tests 2 -num_fe_tests 2 -num_fv_tests 2 -dmfield_view test: suffix: da_1 requires: !complex args: -dm_type da -dim 1 -num_fe_tests 2 test: suffix: da_2 requires: !complex args: -dm_type da -dim 2 -num_fe_tests 2 test: suffix: da_3 requires: !complex args: -dm_type da -dim 3 -num_fe_tests 2 test: suffix: ds requires: !complex triangle args: -dm_type plex -dm_plex_dim 2 -dm_plex_box_faces 3,3 -num_components 2 -num_point_tests 2 -num_fe_tests 2 -num_fv_tests 2 -dmfield_view -petscspace_degree 2 -num_quad_points 1 test: suffix: ds_simplex_0 requires: !complex triangle args: -dm_type plex -dm_plex_dim 2 -dm_plex_box_faces 3,3 -num_fe_tests 2 -petscspace_degree 0 test: suffix: ds_simplex_1 requires: !complex triangle args: -dm_type plex -dm_plex_dim 2 -dm_plex_box_faces 3,3 -num_fe_tests 2 -petscspace_degree 1 test: suffix: ds_simplex_2 requires: !complex triangle args: -dm_type plex -dm_plex_dim 2 -dm_plex_box_faces 3,3 -num_fe_tests 2 -petscspace_degree 2 test: suffix: ds_tensor_2_0 requires: !complex args: -dm_type plex -dm_plex_dim 2 -dm_plex_box_faces 3,3 -num_fe_tests 2 -petscspace_poly_tensor 1 -petscspace_degree 0 -dm_plex_simplex 0 test: suffix: ds_tensor_2_1 requires: !complex args: -dm_type plex -dm_plex_dim 2 -dm_plex_box_faces 3,3 -num_fe_tests 2 -petscspace_poly_tensor 1 -petscspace_degree 1 -dm_plex_simplex 0 test: suffix: ds_tensor_2_2 requires: !complex args: -dm_type plex -dm_plex_dim 2 -dm_plex_box_faces 3,3 -num_fe_tests 2 -petscspace_poly_tensor 1 -petscspace_degree 2 -dm_plex_simplex 0 test: suffix: ds_tensor_3_0 requires: !complex args: -dm_type plex -dm_plex_dim 3 -dm_plex_box_faces 3,3,3 -num_fe_tests 2 -petscspace_poly_tensor 1 -petscspace_degree 0 -dm_plex_simplex 0 test: suffix: ds_tensor_3_1 requires: !complex args: -dm_type plex -dm_plex_dim 3 -dm_plex_box_faces 3,3,3 -num_fe_tests 2 -petscspace_poly_tensor 1 -petscspace_degree 1 -dm_plex_simplex 0 test: suffix: ds_tensor_3_2 requires: !complex args: -dm_type plex -dm_plex_dim 3 -dm_plex_box_faces 3,3,3 -num_fe_tests 2 -petscspace_poly_tensor 1 -petscspace_degree 2 -dm_plex_simplex 0 test: suffix: shell requires: !complex triangle args: -dm_coord_space 0 -dm_type plex -dm_plex_dim 2 -dm_plex_box_faces 3,3 -num_components 2 -num_point_tests 2 -num_fe_tests 2 -num_fv_tests 2 -dmfield_view -num_quad_points 1 -test_shell TEST*/