static char help[] = "Verify isoperiodic cone corrections"; #include #include #define EX "ex101.c" // Creates periodic solution on a [0,1] x D domain for D dimension static PetscErrorCode project_function(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) { PetscReal x_tot = 0; PetscFunctionBeginUser; for (PetscInt d = 0; d < dim; d++) x_tot += x[d]; for (PetscInt c = 0; c < Nc; c++) { PetscScalar value = c % 2 ? PetscSinReal(2 * M_PI * x_tot) : PetscCosReal(2 * M_PI * x_tot); if (PetscAbsScalar(value) < 1e-7) value = 0.; u[c] = value; } PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode CreateFEField(DM dm, PetscBool use_natural_fe, PetscInt num_comps) { PetscInt degree; PetscFunctionBeginUser; { // Get degree of the coords section PetscFE fe; PetscSpace basis_space; if (use_natural_fe) { PetscCall(DMGetField(dm, 0, NULL, (PetscObject *)&fe)); } else { DM cdm; PetscCall(DMGetCoordinateDM(dm, &cdm)); PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); } PetscCall(PetscFEGetBasisSpace(fe, &basis_space)); PetscCall(PetscSpaceGetDegree(basis_space, °ree, NULL)); } PetscCall(DMClearFields(dm)); PetscCall(DMSetLocalSection(dm, NULL)); // See https://gitlab.com/petsc/petsc/-/issues/1669 { // Setup fe to load in the initial condition data PetscFE fe; PetscInt dim; PetscCall(DMGetDimension(dm, &dim)); PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, num_comps, PETSC_FALSE, degree, PETSC_DETERMINE, &fe)); PetscCall(DMAddField(dm, NULL, (PetscObject)fe)); PetscCall(DMCreateDS(dm)); PetscCall(PetscFEDestroy(&fe)); } PetscFunctionReturn(PETSC_SUCCESS); } int main(int argc, char **argv) { MPI_Comm comm; DM dm = NULL; Vec V, V_G2L, V_local; PetscReal norm; PetscBool test_cgns_load = PETSC_FALSE; PetscInt num_comps = 1; PetscErrorCode (*funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) = {project_function}; PetscFunctionBeginUser; PetscCall(PetscInitialize(&argc, &argv, NULL, help)); comm = PETSC_COMM_WORLD; PetscOptionsBegin(comm, "", "ex101.c Options", "DMPLEX"); PetscCall(PetscOptionsBool("-test_cgns_load", "Test VecLoad using CGNS file", EX, test_cgns_load, &test_cgns_load, NULL)); PetscCall(PetscOptionsInt("-num_comps", "Number of components in FE field", EX, num_comps, &num_comps, NULL)); PetscOptionsEnd(); PetscCall(DMCreate(comm, &dm)); PetscCall(DMSetType(dm, DMPLEX)); PetscCall(PetscObjectSetName((PetscObject)dm, "ex101_dm")); PetscCall(DMSetFromOptions(dm)); PetscCall(DMViewFromOptions(dm, NULL, "-dm_view")); PetscCall(CreateFEField(dm, PETSC_FALSE, num_comps)); // Verify that projected function on global vector (then projected onto local vector) is equal to projected function onto a local vector PetscCall(DMGetLocalVector(dm, &V_G2L)); PetscCall(DMGetGlobalVector(dm, &V)); PetscCall(DMProjectFunction(dm, 0, &funcs, NULL, INSERT_VALUES, V)); PetscCall(DMGlobalToLocal(dm, V, INSERT_VALUES, V_G2L)); PetscCall(DMGetLocalVector(dm, &V_local)); PetscCall(DMProjectFunctionLocal(dm, 0, &funcs, NULL, INSERT_VALUES, V_local)); PetscCall(VecViewFromOptions(V_local, NULL, "-local_view")); PetscCall(VecAXPY(V_G2L, -1, V_local)); PetscCall(VecNorm(V_G2L, NORM_MAX, &norm)); PetscReal tol = PetscDefined(USE_REAL___FLOAT128) ? 1e-12 : 1e4 * PETSC_MACHINE_EPSILON; if (norm > tol) PetscCall(PetscPrintf(comm, "Error! GlobalToLocal result does not match Local projection by norm %g\n", (double)norm)); if (test_cgns_load) { #if !defined(PETSC_HAVE_CGNS) SETERRQ(comm, PETSC_ERR_SUP, "PETSc not compiled with CGNS support"); #else PetscViewer viewer; DM dm_read, dm_read_output; Vec V_read, V_read_project2local, V_read_output2local; const char *filename = "test_file.cgns"; // Write previous solution to filename PetscCall(PetscViewerCGNSOpen(comm, filename, FILE_MODE_WRITE, &viewer)); PetscCall(VecView(V_local, viewer)); PetscCall(PetscViewerDestroy(&viewer)); // Write DM from written CGNS file PetscCall(DMPlexCreateFromFile(comm, filename, "ex101_dm_read", PETSC_TRUE, &dm_read)); PetscCall(DMSetFromOptions(dm_read)); PetscCall(DMViewFromOptions(dm_read, NULL, "-dm_view")); { // Force isoperiodic point SF to be created to update sfNatural. // Needs to be done before removing the field corresponding to sfNatural PetscSection unused_section; PetscCall(DMGetGlobalSection(dm_read, &unused_section)); } PetscCall(CreateFEField(dm_read, PETSC_TRUE, num_comps)); // Use OutputDM as this doesn't use the isoperiodic pointSF and is compatible with sfNatural PetscCall(DMGetOutputDM(dm_read, &dm_read_output)); PetscCall(DMGetLocalVector(dm_read, &V_read_project2local)); PetscCall(DMGetLocalVector(dm_read, &V_read_output2local)); PetscCall(PetscObjectSetName((PetscObject)V_read_output2local, "V_read_output2local")); PetscCall(PetscObjectSetName((PetscObject)V_read_project2local, "V_read_project2local")); PetscCall(DMProjectFunctionLocal(dm_read_output, 0, &funcs, NULL, INSERT_VALUES, V_read_project2local)); PetscCall(VecViewFromOptions(V_read_project2local, NULL, "-project2local_view")); { // Read solution from file and communicate to local Vec PetscCall(DMGetGlobalVector(dm_read_output, &V_read)); PetscCall(PetscObjectSetName((PetscObject)V_read, "V_read")); PetscCall(PetscViewerCGNSOpen(comm, filename, FILE_MODE_READ, &viewer)); PetscCall(VecLoad(V_read, viewer)); PetscCall(DMGlobalToLocal(dm_read_output, V_read, INSERT_VALUES, V_read_output2local)); PetscCall(PetscViewerDestroy(&viewer)); PetscCall(DMRestoreGlobalVector(dm_read_output, &V_read)); } PetscCall(VecViewFromOptions(V_read_output2local, NULL, "-output2local_view")); PetscCall(VecAXPY(V_read_output2local, -1, V_read_project2local)); PetscCall(VecNorm(V_read_output2local, NORM_MAX, &norm)); if (norm > tol) PetscCall(PetscPrintf(comm, "Error! CGNS VecLoad result does not match Local projection by norm %g\n", (double)norm)); PetscCall(DMRestoreLocalVector(dm_read, &V_read_project2local)); PetscCall(DMRestoreLocalVector(dm_read, &V_read_output2local)); PetscCall(DMDestroy(&dm_read)); #endif } PetscCall(DMRestoreGlobalVector(dm, &V)); PetscCall(DMRestoreLocalVector(dm, &V_G2L)); PetscCall(DMRestoreLocalVector(dm, &V_local)); PetscCall(DMDestroy(&dm)); PetscCall(PetscFinalize()); return 0; } /*TEST test: nsize: 2 args: -dm_plex_shape zbox -dm_plex_simplex 0 -dm_plex_dim 3 -dm_plex_box_faces 1,2,3 -dm_coord_space -dm_coord_petscspace_degree 3 args: -dm_plex_box_bd periodic,periodic,periodic -dm_view ::ascii_info_detail -petscpartitioner_type simple test: requires: cgns suffix: cgns nsize: 3 args: -dm_plex_filename ${DATAFILESPATH}/meshes/2x2x2_Q3_wave.cgns -dm_plex_cgns_parallel -dm_view ::ascii_info_detail -dm_plex_box_label true -dm_plex_box_label_bd periodic,periodic,periodic -petscpartitioner_type simple -test_cgns_load -num_comps 2 test: requires: cgns parmetis suffix: cgns_parmetis nsize: 3 args: -dm_plex_filename ${DATAFILESPATH}/meshes/2x2x2_Q3_wave.cgns -dm_plex_cgns_parallel -dm_plex_box_label true -dm_plex_box_label_bd periodic,periodic,periodic -petscpartitioner_type parmetis -test_cgns_load -num_comps 2 output_file: output/empty.out TEST*/