diff --git a/configure.ac b/configure.ac index 0004cdfa64..acb2274b35 100644 --- a/configure.ac +++ b/configure.ac @@ -87,6 +87,9 @@ AC_CONFIG_LINKS([test/testfiles/test_vtk_cube.vtp:test/testfiles/test_vtk_cube.v AC_CONFIG_LINKS([test/testfiles/test_parallel_file.pvtu:test/testfiles/test_parallel_file.pvtu]) AC_CONFIG_LINKS([test/testfiles/test_parallel_file_0.vtu:test/testfiles/test_parallel_file_0.vtu]) AC_CONFIG_LINKS([test/testfiles/test_parallel_file_1.vtu:test/testfiles/test_parallel_file_1.vtu]) +AC_CONFIG_LINKS([test/testfiles/test_polydata.pvtp:test/testfiles/test_polydata.pvtp]) +AC_CONFIG_LINKS([test/testfiles/test_polydata_0.vtp:test/testfiles/test_polydata_0.vtp]) +AC_CONFIG_LINKS([test/testfiles/test_polydata_1.vtp:test/testfiles/test_polydata_1.vtp]) AC_CONFIG_LINKS([example/IO/cmesh/gmsh/circlesquare_hybrid_hole.msh:example/IO/cmesh/gmsh/circlesquare_hybrid_hole.msh]) AC_CONFIG_FILES([tutorials/features/t8_features_curved_meshes_generate_cmesh.geo:tutorials/features/t8_features_curved_meshes_generate_cmesh.geo]) AC_CONFIG_FILES([tutorials/features/t8_features_curved_meshes_generate_cmesh_2d.geo:tutorials/features/t8_features_curved_meshes_generate_cmesh_2d.geo]) diff --git a/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx b/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx index 95b4a24dc2..77f3aee282 100644 --- a/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx +++ b/example/IO/cmesh/vtk/t8_cmesh_read_from_vtk.cxx @@ -166,9 +166,9 @@ main (int argc, char **argv) "If set, partition the cmesh uniformly."); sc_options_add_int (opt, 't', "type_of_file", &vtk_file_type_int, -1, "Set the type of the data in the file.\n" - "\t\t\t\t\t0 for vtkUnstructuredGrid \n" - "\t\t\t\t\t1 for vtkPolyData\n" - "\t\t\t\t\t2 for pvtu."); + "\t\t\t\t\t0 for vtkUnstructuredGrid,\n" + "\t\t\t\t\t1 for vtkPolyData,\n" + "\t\t\t\t\t2 for pvtu,\n" "\t\t\t\t\t3 for pvtp."); parsed = sc_options_parse (t8_get_package_id (), SC_LP_ERROR, opt, argc, argv); @@ -190,6 +190,9 @@ main (int argc, char **argv) case 2: vtk_file_type = VTK_PARALLEL_UNSTRUCTURED_FILE; break; + case 3: + vtk_file_type = VTK_PARALLEL_POLYDATA_FILE; + break; default: vtk_file_type = VTK_FILE_ERROR; break; diff --git a/scripts/t8indent_custom_datatypes.txt b/scripts/t8indent_custom_datatypes.txt index 1dbbea10c2..d62511537d 100644 --- a/scripts/t8indent_custom_datatypes.txt +++ b/scripts/t8indent_custom_datatypes.txt @@ -40,4 +40,5 @@ t8_shmem_array_t t8_stash_attribute_struct_t t8_stash_t t8_vtk_data_field_t -vtk_file_type_t \ No newline at end of file +vtk_file_type_t +vtk_read_success_t diff --git a/src/t8_vtk/t8_vtk_parallel.cxx b/src/t8_vtk/t8_vtk_parallel.cxx index f3103a889f..06a851fc53 100644 --- a/src/t8_vtk/t8_vtk_parallel.cxx +++ b/src/t8_vtk/t8_vtk_parallel.cxx @@ -24,12 +24,26 @@ along with t8code; if not, write to the Free Software Foundation, Inc., #if T8_WITH_VTK #include +#include #include +#include #include +#include -vtk_read_success_t -t8_read_parallel (const char *filename, vtkSmartPointer < vtkDataSet > grid, - sc_MPI_Comm comm) +/** + * Setup the reader on each process + * + * \param[in] filename The filename of the parallel file to read + * \param[in, out] reader On input a reader, on output a reader linked to \a filename + * \param[in, out] first_piece Arbitrary on input, the index of the first piece to read on output + * \param[in, out] last_piece Arbitrary on input, the (non-included) index of the last piece to read on output + * \param[in] comm The Communicator to use. + * \return vtk_read_success_t + */ +static vtk_read_success_t +setup_reader (const char *filename, + vtkSmartPointer < vtkXMLPDataReader > reader, + int *first_piece, int *last_piece, sc_MPI_Comm comm) { /* Check if we can open the parallel file */ FILE *first_check; @@ -39,9 +53,7 @@ t8_read_parallel (const char *filename, vtkSmartPointer < vtkDataSet > grid, return read_failure; } fclose (first_check); - /* Setup parallel reader. */ - vtkSmartPointer < vtkXMLPUnstructuredGridReader > reader = - vtkSmartPointer < vtkXMLPUnstructuredGridReader >::New (); + if (!reader->CanReadFile (filename)) { t8_errorf ("Unable to read file.\n"); return read_failure; @@ -63,36 +75,97 @@ t8_read_parallel (const char *filename, vtkSmartPointer < vtkDataSet > grid, SC_CHECK_MPI (mpiret); /* Setup number of pieces to read on this proc. */ - int last_piece = -1; - int first_piece = 0; + *last_piece = -1; + *first_piece = 0; + if (mpisize >= total_num_pieces) { /* The first n-procs read a piece each. */ - first_piece = mpirank; - last_piece = first_piece + ((mpirank < mpisize) ? 1 : 0); + *first_piece = mpirank; + *last_piece = *first_piece + ((mpirank < mpisize) ? 1 : 0); } else { - first_piece = total_num_pieces / mpisize * mpirank; - last_piece = first_piece; + *first_piece = total_num_pieces / mpisize * mpirank; + *last_piece = *first_piece; const int prev_proc_first_piece = total_num_pieces / mpisize * (mpirank - 1); - last_piece += - first_piece == prev_proc_first_piece ? 0 : total_num_pieces / mpisize; - if (first_piece == total_num_pieces / mpisize * (mpisize - 1)) { + *last_piece += + *first_piece == prev_proc_first_piece ? 0 : total_num_pieces / mpisize; + if (*first_piece == total_num_pieces / mpisize * (mpisize - 1)) { /* Read the last chunk of data */ - last_piece = total_num_pieces - first_piece; + *last_piece = total_num_pieces - *first_piece; } } + return read_success; +} + +vtk_read_success_t +t8_read_parallel_polyData (const char *filename, + vtkSmartPointer < vtkDataSet > grid, + sc_MPI_Comm comm) +{ + /* Setup parallel reader. */ + vtkSmartPointer < vtkXMLPPolyDataReader > reader = + vtkSmartPointer < vtkXMLPPolyDataReader >::New (); + + vtk_read_success_t read_status = read_failure; - /* Read the pieces if there are any pieces to read on this proc. */ + int first_piece = 0; + int last_piece = -1; + read_status = + setup_reader (filename, reader, &first_piece, &last_piece, comm); + if (read_status == read_failure) { + return read_status; + } + /* Read the pieces if there are any pieces to read on this proc. + * Merge the output of multiple pieces into one grid */ if (first_piece < last_piece) { - vtkNew < vtkAppendFilter > append; + vtkNew < vtkAppendPolyData > append; + const int total_num_pieces = last_piece - first_piece + 1; for (int ipiece = first_piece; ipiece < last_piece; ipiece++) { reader->UpdatePiece (ipiece, total_num_pieces, 0); append->AddInputData (reader->GetOutput ()); } - /* Merge all read grids together */ append->Update (); + grid->ShallowCopy (append->GetOutput ()); + } + else { + /* Initialize the grid, but don't construct any cells. + * simplifies further processing of the grid on multiple procs. */ + grid->Initialize (); + } + return read_success; +} + +vtk_read_success_t +t8_read_parallel_unstructured (const char *filename, + vtkSmartPointer < vtkDataSet > grid, + sc_MPI_Comm comm) +{ + /* Setup parallel reader. */ + vtkSmartPointer < vtkXMLPUnstructuredGridReader > reader = + vtkSmartPointer < vtkXMLPUnstructuredGridReader >::New (); + + vtk_read_success_t read_status = read_failure; + + int first_piece = 0; + int last_piece = -1; + read_status = + setup_reader (filename, reader, &first_piece, &last_piece, comm); + if (read_status == read_failure) { + return read_status; + } + /* Read the pieces if there are any pieces to read on this proc. + * Merge the output of multiple pieces into one grid */ + if (first_piece < last_piece) { + vtkNew < vtkAppendFilter > append; + const int total_num_pieces = last_piece - first_piece + 1; + for (int ipiece = first_piece; ipiece < last_piece; ipiece++) { + reader->UpdatePiece (ipiece, total_num_pieces, 0); + append->AddInputData (reader->GetOutputAsDataSet ()); + } + /* Merge all read grids together */ append->MergePointsOn (); + append->Update (); grid->ShallowCopy (append->GetOutput ()); } else { diff --git a/src/t8_vtk/t8_vtk_parallel.hxx b/src/t8_vtk/t8_vtk_parallel.hxx index 2a4b2e2bdb..32f45a62e3 100644 --- a/src/t8_vtk/t8_vtk_parallel.hxx +++ b/src/t8_vtk/t8_vtk_parallel.hxx @@ -32,16 +32,32 @@ along with t8code; if not, write to the Free Software Foundation, Inc., /** * Given a filename to a parallel vtk file (for example .pvtu) and its data files, - * read a piece of the data files (like .vtu, .vtp, ...). + * read a piece of the data files (like .vtu, ...). * - * \param[in] filename The name of a parallel vtk file (.pvtu for example) + * \param[in] filename The name of a parallel vtk file to a distributed vtkUnstructuredGrid * \param[in] grid On input a vtkSmartPointer, that will hold the grid described * by the pieces read on this proc. * \returns non-zero on success, zero if the reading failed. */ -vtk_read_success_t t8_read_parallel (const char *filename, - vtkSmartPointer < vtkDataSet > grid, - sc_MPI_Comm comm); +/* *INDENT-OFF* */ +vtk_read_success_t t8_read_parallel_unstructured (const char *filename, + vtkSmartPointer + < vtkDataSet > grid, + sc_MPI_Comm comm); +/* *INDENT-ON* */ + +/** + * Given a filename to a parallel vtk file (for example .pvtp) and its data files, + * read a piece of the data files (like .vtp, ...). + * + * \param[in] filename The name of a parallel vtk file to a distributed vtkPolyData + * \param[in] grid On input a vtkSmartPointer, that will hold the grid described + * by the pieces read on this proc. + * \returns non-zero on success, zero if the reading failed. + */ +vtk_read_success_t t8_read_parallel_polyData (const char *filename, + vtkSmartPointer < vtkDataSet > + grid, sc_MPI_Comm comm); #endif /* T8_WITH_VTK */ #endif /* T8_VTK_PARALLEL_HXX */ diff --git a/src/t8_vtk/t8_vtk_polydata.cxx b/src/t8_vtk/t8_vtk_polydata.cxx index c76f5138c0..3aa8b744b6 100644 --- a/src/t8_vtk/t8_vtk_polydata.cxx +++ b/src/t8_vtk/t8_vtk_polydata.cxx @@ -30,10 +30,11 @@ along with t8code; if not, write to the Free Software Foundation, Inc., #include #include #include +#include #include #include -static vtk_read_success_t +static vtk_read_success_t t8_read_poly_ext (const char *filename, vtkSmartPointer < vtkPolyData > grid) { char tmp[BUFSIZ]; @@ -105,6 +106,18 @@ t8_read_poly_ext (const char *filename, vtkSmartPointer < vtkPolyData > grid) grid->ShallowCopy (vtkDataSet::SafeDownCast (reader->GetOutput ())); return read_failure; } + else if (strcmp (extension, "pvtp") == 0) { + vtkSmartPointer < vtkXMLPPolyDataReader > reader = + vtkSmartPointer < vtkXMLPPolyDataReader >::New (); + if (!reader->CanReadFile (filename)) { + t8_errorf ("Unable to read file.\n"); + return read_failure; + } + reader->SetFileName (filename); + reader->Update (); + grid->ShallowCopy (vtkDataSet::SafeDownCast (reader->GetOutput ())); + return read_success; + } else { /* Return NULL if the reader is not used correctly. */ t8_global_errorf ("Please use .ply, .vtp, .obj, .stl, .vtk or .g file\n"); @@ -113,7 +126,7 @@ t8_read_poly_ext (const char *filename, vtkSmartPointer < vtkPolyData > grid) } vtk_read_success_t -t8_read_poly (const char *filename, vtkDataSet * grid) +t8_read_polyData (const char *filename, vtkDataSet * grid) { vtkSmartPointer < vtkPolyData > poly_data = vtkSmartPointer < vtkPolyData >::New (); diff --git a/src/t8_vtk/t8_vtk_polydata.hxx b/src/t8_vtk/t8_vtk_polydata.hxx index 6d8335c7ad..e64d428481 100644 --- a/src/t8_vtk/t8_vtk_polydata.hxx +++ b/src/t8_vtk/t8_vtk_polydata.hxx @@ -47,7 +47,8 @@ along with t8code; if not, write to the Free Software Foundation, Inc., * \returns non-zero on success, zero if the reading failed. * */ -vtk_read_success_t t8_read_poly (const char *filename, vtkDataSet * grid); +vtk_read_success_t t8_read_polyData (const char *filename, + vtkDataSet * grid); #endif /* T8_WITH_VTK */ #endif /* T8_CMESH_VTK_POLYDATA */ diff --git a/src/t8_vtk/t8_vtk_reader.cxx b/src/t8_vtk/t8_vtk_reader.cxx index 2e8aeeacbe..a24347035f 100644 --- a/src/t8_vtk/t8_vtk_reader.cxx +++ b/src/t8_vtk/t8_vtk_reader.cxx @@ -35,6 +35,8 @@ along with t8code; if not, write to the Free Software Foundation, Inc., #include #include #include +#include +#include #include #include #include @@ -137,7 +139,7 @@ t8_file_to_vtkGrid (const char *filename, main_proc_read_successful = t8_read_unstructured (filename, vtkGrid); break; case VTK_POLYDATA_FILE: - main_proc_read_successful = t8_read_poly (filename, vtkGrid); + main_proc_read_successful = t8_read_polyData (filename, vtkGrid); break; case VTK_PARALLEL_UNSTRUCTURED_FILE: if (!partition) { @@ -145,7 +147,17 @@ t8_file_to_vtkGrid (const char *filename, } else { main_proc_read_successful = - t8_read_parallel (filename, vtkGrid, comm); + t8_read_parallel_unstructured (filename, vtkGrid, comm); + break; + } + break; + case VTK_PARALLEL_POLYDATA_FILE: + if (!partition) { + main_proc_read_successful = t8_read_polyData (filename, vtkGrid); + } + else { + main_proc_read_successful = + t8_read_parallel_polyData (filename, vtkGrid, comm); break; } break; @@ -214,8 +226,8 @@ t8_get_dimension (vtkSmartPointer < vtkDataSet > vtkGrid) * the vtkGrid. Each cell in the vtkDataSet becomes a tree in the cmesh. This * function constructs a cmesh on a single process. * - * \param[in] vtkGrid The vtkGrid that gets translated - * \param[in, out] cmesh An empty cmesh that is filled with the data. + * \param[in] vtkGrid The vtkGrid that gets translated + * \param[in, out] cmesh An empty cmesh that is filled with the data. * \param[in] first_tree The global id of the first tree. Will be the global id of the first tree on this proc. * \param[in] comm A communicator. * \return The number of elements that have been read by the process. @@ -473,6 +485,9 @@ t8_vtk_reader (const char *filename, const int partition, case VTK_PARALLEL_UNSTRUCTURED_FILE: vtkGrid = vtkSmartPointer < vtkUnstructuredGrid >::New (); break; + case VTK_PARALLEL_POLYDATA_FILE: + vtkGrid = vtkSmartPointer < vtkPolyData >::New (); + break; default: t8_errorf ("Filetype is not supported.\n"); break; diff --git a/test/t8_IO/t8_gtest_vtk_reader.cxx b/test/t8_IO/t8_gtest_vtk_reader.cxx index cd00ddf0ec..d53427af27 100644 --- a/test/t8_IO/t8_gtest_vtk_reader.cxx +++ b/test/t8_IO/t8_gtest_vtk_reader.cxx @@ -45,6 +45,8 @@ class vtk_reader : public testing::TestWithParam>{ void SetUp() override{ int mpiret = sc_MPI_Comm_size (sc_MPI_COMM_WORLD, &mpisize); SC_CHECK_MPI (mpiret); + mpiret = sc_MPI_Comm_rank (sc_MPI_COMM_WORLD, &mpirank); + SC_CHECK_MPI (mpiret); if (mpisize > T8_VTK_TEST_NUM_PROCS) { GTEST_SKIP (); } @@ -52,15 +54,15 @@ class vtk_reader : public testing::TestWithParam>{ file_type = gtest_vtk_filetypes[file]; partition = std::get<1>(GetParam()); main_proc = std::get<2>(GetParam()); - if((file_type & VTK_PARALLEL_POLYDATA_FILE )&& partition){ - GTEST_SKIP(); - } + distributed = (file_type & VTK_PARALLEL_FILE) && partition; } int file; vtk_file_type_t file_type; int partition; + int distributed; int main_proc; int mpisize; + int mpirank; const char* failing_files[5] = { "no_file", "non-existing-file.vtu", @@ -68,14 +70,15 @@ class vtk_reader : public testing::TestWithParam>{ "non-existing-file.pvtu", "non-existing-file.pvtp" }; - const char* test_files[4] = { + const char* test_files[5] = { "no_file", "test/testfiles/test_vtk_tri.vtu", "test/testfiles/test_vtk_cube.vtp", - "test/testfiles/test_parallel_file.pvtu" + "test/testfiles/test_parallel_file.pvtu", + "test/testfiles/test_polydata.pvtp" }; - const int num_points[4] = {0, 121, 24, 6144}; - const int num_trees[4] = {0, 200, 12, 1024}; + const int num_points[5] = {0, 121, 24, 6144, 900}; + const int num_trees[5] = {0, 200, 12, 1024, 1680}; }; /* *INDENT-ON* */ @@ -95,10 +98,6 @@ TEST_P (vtk_reader, vtk_to_cmesh_fail) TEST_P (vtk_reader, vtk_to_cmesh_success) { #if T8_WITH_VTK - /*TODO: Implement reader for parallel polydata. Delete this if-block */ - if (file_type == VTK_PARALLEL_POLYDATA_FILE) { - GTEST_SKIP (); - } int mpirank; int mpiret = sc_MPI_Comm_rank (sc_MPI_COMM_WORLD, &mpirank); SC_CHECK_MPI (mpiret); @@ -107,15 +106,20 @@ TEST_P (vtk_reader, vtk_to_cmesh_success) sc_MPI_COMM_WORLD, file_type); if (file_type != VTK_FILE_ERROR) { - if (!partition || main_proc == mpirank) { - EXPECT_FALSE (cmesh == NULL); - if (file_type == VTK_PARALLEL_UNSTRUCTURED_FILE && partition) { - t8_gloidx_t local_num_trees = - t8_cmesh_get_num_local_trees (cmesh); - EXPECT_EQ (num_trees[file] / mpisize, local_num_trees); + EXPECT_FALSE (cmesh == NULL); + const int test_num_trees = t8_cmesh_get_num_local_trees (cmesh); + if (distributed) { + /* In this testcase the cmesh should be distributed equally. */ + EXPECT_EQ (num_trees[file] / mpisize, test_num_trees); + } + else { + if (!partition || main_proc == mpirank) { + /* The proc has the complete cmesh */ + EXPECT_EQ (num_trees[file], test_num_trees); } else { - EXPECT_EQ (num_trees[file], t8_cmesh_get_num_local_trees (cmesh)); + /* Every other proc should be empty. */ + EXPECT_EQ (0, test_num_trees); } } t8_cmesh_destroy (&cmesh); @@ -131,16 +135,25 @@ TEST_P (vtk_reader, vtk_to_cmesh_success) TEST_P (vtk_reader, vtk_to_pointSet) { #if T8_WITH_VTK - /*TODO: Implement reader for parallel polydata. Delete this if-block */ - if (file_type == VTK_PARALLEL_POLYDATA_FILE) { - GTEST_SKIP (); - } if (file_type != VTK_FILE_ERROR) { vtkSmartPointer < vtkPointSet > points = - t8_vtk_reader_pointSet (test_files[file], 0, 0, + t8_vtk_reader_pointSet (test_files[file], partition, main_proc, sc_MPI_COMM_WORLD, file_type); int test_points = points->GetNumberOfPoints (); - EXPECT_EQ (num_points[file], test_points); + if (distributed) { + /* The points should be distributed equally in this case. */ + EXPECT_EQ (num_points[file] / mpisize, test_points); + } + else { + if (!partition || main_proc == mpirank) { + /* The proc has all points. */ + EXPECT_EQ (num_points[file], test_points); + } + else { + /* Every other proc should have no points. */ + EXPECT_EQ (0, test_points); + } + } } #else #endif diff --git a/test/testfiles/test_polydata.pvtp b/test/testfiles/test_polydata.pvtp new file mode 100644 index 0000000000..e8651d8b9e --- /dev/null +++ b/test/testfiles/test_polydata.pvtp @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/testfiles/test_polydata_0.vtp b/test/testfiles/test_polydata_0.vtp new file mode 100644 index 0000000000..a4ceecd6ed Binary files /dev/null and b/test/testfiles/test_polydata_0.vtp differ diff --git a/test/testfiles/test_polydata_1.vtp b/test/testfiles/test_polydata_1.vtp new file mode 100644 index 0000000000..fdb50c09f1 Binary files /dev/null and b/test/testfiles/test_polydata_1.vtp differ