/** * This tests the HDF5 to XDMF converter */ void TestHdf5ToXdmfConverter() throw(Exception) { #ifndef _MSC_VER std::string working_directory = "TestHdf5Converters_TestHdf5ToXdmfConverter"; CopyToTestOutputDirectory("pde/test/data/cube_2mm_12_elements.h5", working_directory); TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_2mm_12_elements"); TetrahedralMesh<3,3> mesh; mesh.ConstructFromMeshReader(mesh_reader); // Convert Hdf5ToXdmfConverter<3,3> converter(FileFinder(working_directory, RelativeTo::ChasteTestOutput), "cube_2mm_12_elements", &mesh); std::vector<std::string> files_to_compare; files_to_compare.push_back("cube_2mm_12_elements.xdmf"); files_to_compare.push_back("cube_2mm_12_elements_geometry_0.xml"); files_to_compare.push_back("cube_2mm_12_elements_topology_0.xml"); for (unsigned i=0; i<files_to_compare.size(); i++) { std::cout << "Comparing generated and reference " << files_to_compare[i] << std::endl; FileFinder generated_file(working_directory +"/xdmf_output/" + files_to_compare[i], RelativeTo::ChasteTestOutput); FileFinder reference_file("pde/test/data/xdmf_output/" + files_to_compare[i], RelativeTo::ChasteSourceRoot); FileComparison comparer(generated_file, reference_file); TS_ASSERT(comparer.CompareFiles()); } #endif // _MSC_VER }
// This test covers the case when the hdf5 file contains 3 variables (e.g., after solving a problem with PROBLEM_DIM=3) void TestMeshalyzerConversion3Variables() throw(Exception) { /* * Firstly, copy the .h5 file to CHASTE_TEST_OUTPUT/TestHdf5ToMeshalyzerConverter, * as that is where the reader reads from. */ std::string output_folder("TestHdf5Converters_TestMeshalyzerConversion3Variables"); CopyToTestOutputDirectory("heart/test/data/three_variables/3_vars.h5", output_folder); TrianglesMeshReader<1,1> mesh_reader("mesh/test/data/1D_0_to_1_100_elements"); TetrahedralMesh<1,1> mesh; mesh.ConstructFromMeshReader(mesh_reader); // Convert Hdf5ToMeshalyzerConverter<1,1> converter(FileFinder(output_folder, RelativeTo::ChasteTestOutput), "3_vars", &mesh, true); // Compare the first voltage file std::string test_output_directory = OutputFileHandler::GetChasteTestOutputDirectory(); NumericFileComparison(test_output_directory + output_folder + "/output/3_vars_Vm_1.dat", "heart/test/data/three_variables/extended_bidomain_Vm_1.dat").CompareFiles(); // Compare the second voltage file NumericFileComparison(test_output_directory + output_folder +"/output/3_vars_Vm_2.dat", "heart/test/data/three_variables/extended_bidomain_Vm_2.dat").CompareFiles(); // Compare the Phi_e file NumericFileComparison(test_output_directory + output_folder + "/output/3_vars_Phi_e.dat", "heart/test/data/three_variables/extended_bidomain_Phi_e.dat").CompareFiles(); // Compare the time information file FileComparison(test_output_directory + output_folder + "/output/3_vars_times.info", "heart/test/data/three_variables/extended_bidomain_times.info").CompareFiles(); }
/** * This tests the HDF5 to .txt converter using a 3D example * taken from a bidomain simulation. */ void TestBidomainTxtConversion3D() throw(Exception) { std::string working_directory = "TestHdf5ToTxtConverter_bidomain"; /* * Firstly, copy the .h5 file to CHASTE_TEST_OUTPUT/TestHdf5ToTxtConverter_bidomain, * as that is where the reader reads from. */ CopyToTestOutputDirectory("pde/test/data/cube_2mm_12_elements.h5", working_directory); TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_2mm_12_elements"); TetrahedralMesh<3,3> mesh; mesh.ConstructFromMeshReader(mesh_reader); // Convert Hdf5ToTxtConverter<3,3> converter(FileFinder(working_directory, RelativeTo::ChasteTestOutput), "cube_2mm_12_elements", &mesh); std::vector<std::string> files_to_compare; files_to_compare.push_back("cube_2mm_12_elements_V_0.txt"); files_to_compare.push_back("cube_2mm_12_elements_V_1.txt"); files_to_compare.push_back("cube_2mm_12_elements_Phi_e_0.txt"); files_to_compare.push_back("cube_2mm_12_elements_Phi_e_1.txt"); for (unsigned i=0; i<files_to_compare.size(); i++) { std::cout << "Comparing generated and reference " << files_to_compare[i] << std::endl; FileFinder generated_file(working_directory +"/txt_output/" + files_to_compare[i], RelativeTo::ChasteTestOutput); FileFinder reference_file("pde/test/data/" + files_to_compare[i], RelativeTo::ChasteSourceRoot); NumericFileComparison comparer(generated_file, reference_file); TS_ASSERT(comparer.CompareFiles()); } }
FileFinder OutputFileHandler::CopyFileTo(const FileFinder& rSourceFile) const { if (!rSourceFile.IsFile()) { EXCEPTION("Can only copy single files:\n" << rSourceFile.GetAbsolutePath() << " is not a file."); } fs::path from_path(rSourceFile.GetAbsolutePath()); fs::path to_path(GetOutputDirectoryFullPath()); to_path /= from_path.leaf(); if (PetscTools::AmMaster()) { try { fs::copy_file(from_path, to_path); } // LCOV_EXCL_START catch (const fs::filesystem_error& e) { TERMINATE("Error copying file '" << rSourceFile.GetAbsolutePath() << "': " << e.what()); } // LCOV_EXCL_STOP } PetscTools::Barrier("OutputFileHandler::CopyFileTo"); return FileFinder(to_path.string(), RelativeTo::Absolute); }
// This test relies on TestArchiveOpenerReadAndWrite succeeding void TestArchiveOpenerExceptions() throw(Exception) { OutputFileHandler handler(mArchiveDir, false); handler.SetArchiveDirectory(); FileFinder archive_dir_finder(mArchiveDir, RelativeTo::ChasteTestOutput); std::string archive_base_name = "archive_opener.arch"; // Remove the process-specific archive for this process FileFinder(ArchiveLocationInfo::GetProcessUniqueFilePath(archive_base_name)).Remove(); TS_ASSERT_THROWS_CONTAINS(InputArchiveOpener archive_opener_in(archive_dir_finder, archive_base_name), "Cannot load secondary archive file: "); PetscTools::Barrier("TestArchiveOpenerExceptions-1"); // Remove the main archive if (PetscTools::AmMaster()) { ABORT_IF_THROWS(handler.FindFile(archive_base_name).Remove()); } PetscTools::Barrier("TestArchiveOpenerExceptions-2"); TS_ASSERT_THROWS_CONTAINS(InputArchiveOpener archive_opener_in(archive_dir_finder, archive_base_name), "Cannot load main archive file: "); // Remove write permissions on the archive dir //Note: changing *directory* permissions and other attributes does not work on Windows //See http://support.microsoft.com/kb/326549 #ifndef _MSC_VER if (PetscTools::AmMaster()) { chmod(handler.GetOutputDirectoryFullPath().c_str(), CHASTE_READONLY); } PetscTools::Barrier("TestArchiveOpenerExceptions-3"); /* * Now neither the master nor the slaves can write to their output files. * This avoids hitting a PetscBarrier() in the ~ArchiveOpener() because they * all throw an error first. * * If this test starts hanging it is because these TS_ASSERT_THROWS_CONTAINS * are not being thrown (rather than a real parallel calling problem). */ if (PetscTools::AmMaster()) { TS_ASSERT_THROWS_CONTAINS(OutputArchiveOpener archive_opener_out(archive_dir_finder, archive_base_name), "Failed to open main archive file for writing: "); } else { TS_ASSERT_THROWS_CONTAINS(OutputArchiveOpener archive_opener_out(archive_dir_finder, archive_base_name), "Failed to open secondary archive file for writing: "); } PetscTools::Barrier("TestArchiveOpenerExceptions-4"); if (PetscTools::AmMaster()) { // Restore permissions on the folder before allowing processes to continue. chmod(handler.GetOutputDirectoryFullPath().c_str(), CHASTE_READ_WRITE_EXECUTE); } #endif // _MSC_VER PetscTools::Barrier("TestArchiveOpenerExceptions-5"); }
// This test covers the case when the hdf5 file contains more than 3 variables void TestMeshalyzerConversionLotsOfVariables() throw(Exception) { std::string output_dir = "TestHdf5Converters_TestMeshalyzerConversionLotsOfVariables"; /* * Firstly, copy the .h5 file to CHASTE_TEST_OUTPUT/TestHdf5ToMeshalyzerConverter, * as that is where the reader reads from. */ CopyToTestOutputDirectory("heart/test/data/many_variables/many_variables.h5", output_dir); TrianglesMeshReader<1,1> mesh_reader("heart/test/data/many_variables/1D_65_elements"); TetrahedralMesh<1,1> mesh; mesh.ConstructFromMeshReader(mesh_reader); // Convert Hdf5ToMeshalyzerConverter<1,1> converter(FileFinder(output_dir, RelativeTo::ChasteTestOutput), "many_variables", &mesh, true); std::vector<std::string> variable_names; variable_names.push_back("V"); variable_names.push_back("I_ks"); variable_names.push_back("I_kr"); variable_names.push_back("I_Ca_tot"); variable_names.push_back("I_tot"); variable_names.push_back("I_Na_tot"); std::string test_output_directory = OutputFileHandler::GetChasteTestOutputDirectory(); for (unsigned i=0; i<variable_names.size(); i++) { // Compare the results files FileComparison(test_output_directory + "/" + output_dir + "/output/many_variables_" + variable_names[i] + ".dat", "heart/test/data/many_variables/many_variables_" + variable_names[i] + ".dat").CompareFiles(); } // Compare the time information file FileComparison(test_output_directory + output_dir + "/output/many_variables_times.info", "heart/test/data/many_variables/many_variables_times.info").CompareFiles(); }
void TestMonodomainMeshalyzerConversion() throw(Exception) { // Firstly, copy ./heart/test/data/MonoDg01d/*.h5 to CHASTE_TEST_OUTPUT/TestHdf5ToMeshalyzerConverter, // as that is where the reader reads from. std::string output_folder("TestHdf5Converters_TestMonodomainMeshalyzerConversion"); CopyToTestOutputDirectory("heart/test/data/Monodomain1d/MonodomainLR91_1d.h5", output_folder); TrianglesMeshReader<1,1> mesh_reader("mesh/test/data/1D_0_to_1_100_elements"); TetrahedralMesh<1,1> mesh; mesh.ConstructFromMeshReader(mesh_reader); // Convert Hdf5ToMeshalyzerConverter<1,1> converter(FileFinder(output_folder,RelativeTo::ChasteTestOutput), "MonodomainLR91_1d", &mesh, true, 10 /* precision specified for coverage */); // Compare the voltage file with a correct version std::string test_output_directory = OutputFileHandler::GetChasteTestOutputDirectory(); FileComparison(test_output_directory + output_folder + "/output/MonodomainLR91_1d_V.dat", "heart/test/data/Monodomain1d/MonodomainLR91_1d_V.dat").CompareFiles(); FileComparison(test_output_directory + output_folder + "/output/MonodomainLR91_1d_times.info", "heart/test/data/Monodomain1d/MonodomainLR91_1d_times.info").CompareFiles(); }
/** * This tests the HDF5 to VTK converter using a 3D example * taken from a bidomain simulation. */ void TestBidomainVtkConversion3D() throw(Exception) { #ifdef CHASTE_VTK // Requires "sudo aptitude install libvtk5-dev" or similar std::string working_directory = "TestHdf5ToVtkConverter_bidomain"; std::string working_directory2 = "TestHdf5ToVtkConverter_bidomain2"; /* * Firstly, copy the .h5 file to CHASTE_TEST_OUTPUT/TestHdf5ToVtkConverter_bidomain, * as that is where the reader reads from. */ CopyToTestOutputDirectory("pde/test/data/cube_2mm_12_elements.h5", working_directory); TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_2mm_12_elements"); TetrahedralMesh<3,3> mesh; mesh.ConstructFromMeshReader(mesh_reader); // Convert Hdf5ToVtkConverter<3,3> converter(FileFinder(working_directory, RelativeTo::ChasteTestOutput), "cube_2mm_12_elements", &mesh, false, true); std::string test_output_directory = OutputFileHandler::GetChasteTestOutputDirectory(); // Now do something else before reading back... { //NOTE: Interleaved test // Show that trying to write .pvtu files from a TetrahedralMesh gives a warning (but writes anyway) CopyToTestOutputDirectory("pde/test/data/cube_2mm_12_elements.h5", working_directory2); Hdf5ToVtkConverter<3,3> converter2(FileFinder(working_directory2, RelativeTo::ChasteTestOutput), "cube_2mm_12_elements", &mesh, true, true); //The reading part of this test is below } /* * Note that VTK is not thread-safe. The master process has spawned * a child to write the mesh and may still be writing! This barrier * just slows things down a bit. */ PetscTools::Barrier(); VtkMeshReader<3,3> vtk_mesh_reader(test_output_directory + working_directory + "/vtk_output/cube_2mm_12_elements.vtu"); TS_ASSERT_EQUALS(vtk_mesh_reader.GetNumNodes(), 12u); TS_ASSERT_EQUALS(vtk_mesh_reader.GetNumElements(), 12u); std::vector<double> first_node = vtk_mesh_reader.GetNextNode(); TS_ASSERT_DELTA(first_node[0], 0.0, 1e-6); TS_ASSERT_DELTA(first_node[1], 0.0, 1e-6); TS_ASSERT_DELTA(first_node[2], 0.0, 1e-6); std::vector<double> next_node = vtk_mesh_reader.GetNextNode(); TS_ASSERT_DELTA(next_node[0], 0.2, 1e-6); TS_ASSERT_DELTA(next_node[1], 0.0, 1e-6); TS_ASSERT_DELTA(next_node[2], 0.0, 1e-6); // V_m and phi_e samples std::vector<double> v_at_last, phi_at_last; vtk_mesh_reader.GetPointData("V_000001", v_at_last); TS_ASSERT_DELTA(v_at_last[0], -46.3761, 1e-3); TS_ASSERT_DELTA(v_at_last[6], -46.3761, 1e-3); TS_ASSERT_DELTA(v_at_last[11], -46.3760, 1e-3); vtk_mesh_reader.GetPointData("Phi_e_000001", phi_at_last); TS_ASSERT_DELTA(phi_at_last[0], 0.0, 1e-3); TS_ASSERT_DELTA(phi_at_last[6], 0.0, 1e-3); TS_ASSERT_DELTA(phi_at_last[11], 0.0, 1e-3); { //NOTE: Interleaved test //The writing part of this test is above VtkMeshReader<3,3> vtk_mesh_reader2(test_output_directory + working_directory2 + "/vtk_output/cube_2mm_12_elements.vtu"); TS_ASSERT_EQUALS(vtk_mesh_reader2.GetNumNodes(), 12u); } #else std::cout << "This test was not run, as VTK is not enabled." << std::endl; std::cout << "If required please install and alter your hostconfig settings to switch on chaste VTK support." << std::endl; #endif //CHASTE_VTK }
/** * This tests the HDF5 to VTK converter in parallel using a 2D example * taken from a monodomain simulation. */ void TestMonodomainParallelVtkConversion2D() throw(Exception) { #ifdef CHASTE_VTK // Requires "sudo aptitude install libvtk5-dev" or similar std::string working_directory = "TestHdf5ToVtkConverter_monodomain2D"; /* * Firstly, copy the .h5 file to CHASTE_TEST_OUTPUT/TestHdf5ToVtkConverter_monodomain2D, * as that is where the reader reads from. */ CopyToTestOutputDirectory("pde/test/data/2D_0_to_1mm_400_elements.h5", working_directory); TrianglesMeshReader<2,2> mesh_reader("mesh/test/data/2D_0_to_1mm_400_elements"); DistributedTetrahedralMesh<2,2> mesh(DistributedTetrahedralMeshPartitionType::DUMB); mesh.ConstructFromMeshReader(mesh_reader); // Convert Hdf5ToVtkConverter<2,2> converter(FileFinder(working_directory, RelativeTo::ChasteTestOutput), "2D_0_to_1mm_400_elements", &mesh, true, false); /* * Note that VTK is not thread-safe. The master process has spawned * a child to write the mesh and may still be writing! This barrier * just slows things down a bit. */ PetscTools::Barrier(); std::string test_output_directory = OutputFileHandler::GetChasteTestOutputDirectory(); std::stringstream filepath; filepath << test_output_directory << working_directory << "/vtk_output/2D_0_to_1mm_400_elements"; if (!PetscTools::IsSequential()) { filepath << "_" << PetscTools::GetMyRank(); } filepath << ".vtu"; VtkMeshReader<2,2> vtk_mesh_reader(filepath.str()); TS_ASSERT_EQUALS(vtk_mesh_reader.GetNumNodes(), mesh.GetNumLocalNodes() + mesh.GetNumHaloNodes()); // 221 in total TS_ASSERT_EQUALS(vtk_mesh_reader.GetNumElements(), mesh.GetNumLocalElements()); // 400 in total if (PetscTools::IsSequential()) { std::vector<double> first_node = vtk_mesh_reader.GetNextNode(); TS_ASSERT_DELTA(first_node[0], 0.0 , 1e-6); TS_ASSERT_DELTA(first_node[1], 0.0, 1e-6); TS_ASSERT_DELTA(first_node[2], 0.0 , 1e-6); // 2d VTK files still carry z-coordinate std::vector<double> next_node = vtk_mesh_reader.GetNextNode(); TS_ASSERT_DELTA(next_node[0], 0.01, 1e-6); TS_ASSERT_DELTA(next_node[1], 0.0 , 1e-6); TS_ASSERT_DELTA(next_node[2], 0.0 , 1e-6); // 2d VTK files still carry z-coordinate } // V_m samples std::vector<double> v_at_last; vtk_mesh_reader.GetPointData("V_000020", v_at_last); if (PetscTools::IsSequential()) { TS_ASSERT_DELTA(v_at_last[0], -83.8534, 1e-3); TS_ASSERT_DELTA(v_at_last[110], -83.8534, 1e-3); TS_ASSERT_DELTA(v_at_last[220], -83.8530, 1e-3); } // Show that trying to write .pvtu files with original node ordering gives a warning (but writes anyway) Hdf5ToVtkConverter<2,2> converter2(FileFinder(working_directory, RelativeTo::ChasteTestOutput), "2D_0_to_1mm_400_elements", &mesh, true, true); /* * Note that VTK is not thread-safe. The master process has spawned * a child to write the mesh and may still be writing! This barrier * just slows things down a bit. */ PetscTools::Barrier(); VtkMeshReader<2,2> vtk_mesh_reader2(test_output_directory + working_directory + "/vtk_output/2D_0_to_1mm_400_elements.vtu"); TS_ASSERT_EQUALS(vtk_mesh_reader2.GetNumNodes(), 221u); #else std::cout << "This test was not run, as VTK is not enabled." << std::endl; std::cout << "If required please install and alter your hostconfig settings to switch on chaste VTK support." << std::endl; #endif //CHASTE_VTK }
void TestHandler() throw(Exception) { // Test that CHASTE_TEST_OUTPUT always has a trailing slash even before // a class object is instantiated const std::string chaste_test_output(OutputFileHandler::GetChasteTestOutputDirectory()); TS_ASSERT_EQUALS( *(chaste_test_output.end()-1), '/'); // Make a handler that points straight to the CHASTE_TEST_OUTPUT directory. OutputFileHandler handler(""); const std::string handler_path(handler.GetOutputDirectoryFullPath()); TS_ASSERT(handler_path.length() > 0); TS_ASSERT_EQUALS(handler_path, handler.GetChasteTestOutputDirectory()); TS_ASSERT_EQUALS(handler.GetRelativePath(), ""); // Test that CHASTE_TEST_OUTPUT always has a trailing slash TS_ASSERT_EQUALS( *(handler_path.end()-1), '/'); // Make a handler that points to a sub-directory. std::string dir = "testhandler"; OutputFileHandler handler2(dir); std::string full_dir = handler2.GetOutputDirectoryFullPath(); TS_ASSERT_EQUALS(full_dir.substr(full_dir.length()-dir.length()-1), dir+"/"); TS_ASSERT_EQUALS(full_dir.substr(0, full_dir.length()-dir.length()-1), handler_path); TS_ASSERT_EQUALS(handler2.GetRelativePath(), dir); // We can also create handlers from a FileFinder (provided it points to a location in CHASTE_TEST_OUTPUT) OutputFileHandler handler3(handler.FindFile("testhandler2")); full_dir = handler3.GetOutputDirectoryFullPath(); TS_ASSERT_EQUALS(full_dir.substr(full_dir.length()-dir.length()-2), dir+"2/"); TS_ASSERT_EQUALS(full_dir.substr(0, full_dir.length()-dir.length()-2), handler_path); TS_ASSERT_EQUALS(handler3.GetRelativePath(), "testhandler2"); // Check that all three handlers can create files out_stream p_file_stream; p_file_stream = handler.OpenOutputFile("test_file", std::ios::out); TS_ASSERT(FileFinder(handler_path + "test_file").Exists()); p_file_stream = handler.OpenOutputFile("test_file2"); TS_ASSERT(FileFinder(handler_path + "test_file2").Exists()); p_file_stream = handler2.OpenOutputFile("test_file"); TS_ASSERT(FileFinder(handler2.GetOutputDirectoryFullPath() + "test_file").Exists()); p_file_stream = handler2.OpenOutputFile("test_", 34, ".txt"); TS_ASSERT(FileFinder(handler2.GetOutputDirectoryFullPath() + "test_34.txt").Exists()); p_file_stream = handler3.OpenOutputFile("test_file"); TS_ASSERT(FileFinder(handler3.GetOutputDirectoryFullPath() + "test_file").Exists()); // This should try to write files to /, which isn't allowed (we hope!) TS_ASSERT_THROWS_CONTAINS(OutputFileHandler bad_handler("../../../../../../../../../../../../../../../", false), "due to it potentially being above, and cleaning, CHASTE_TEST_OUTPUT."); TS_ASSERT_THROWS_CONTAINS(OutputFileHandler bad_handler("/", false), "The constructor argument to OutputFileHandler must be a relative path"); TS_ASSERT_THROWS_CONTAINS(OutputFileHandler bad_handler(FileFinder("/"), false), "The location provided to OutputFileHandler must be inside CHASTE_TEST_OUTPUT"); // Check the CopyFileTo method FileFinder source_file("global/test/TestOutputFileHandler.hpp", RelativeTo::ChasteSourceRoot); TS_ASSERT(!handler2.FindFile("TestOutputFileHandler.hpp").Exists()); PetscTools::Barrier("TestOutputFileHandler-0"); FileFinder dest_file = handler2.CopyFileTo(source_file); TS_ASSERT(dest_file.Exists()); FileFinder missing_file("global/no_file", RelativeTo::ChasteSourceRoot); TS_ASSERT_THROWS_CONTAINS(handler2.CopyFileTo(missing_file), "Can only copy single files"); FileFinder global_dir("global", RelativeTo::ChasteSourceRoot); TS_ASSERT_THROWS_CONTAINS(handler2.CopyFileTo(global_dir), "Can only copy single files"); // We don't want other people using CHASTE_TEST_OUTPUT whilst we are messing with it! PetscTools::Barrier("TestOutputFileHandler-1"); // Test that the environment variable actually influences the location of files { setenv("CHASTE_TEST_OUTPUT", "", 1/*Overwrite*/); // Check this folder is not present FileFinder test_folder("testoutput/whatever", RelativeTo::ChasteSourceRoot); TS_ASSERT(!test_folder.Exists()); PetscTools::Barrier("TestOutputFileHandler-2"); // Make a folder and erase it - NB only master can erase files and check it is successful! OutputFileHandler handler4("whatever"); TS_ASSERT(test_folder.Exists()); PetscTools::Barrier("TestOutputFileHandler-2b"); if (PetscTools::AmMaster()) { test_folder.Remove(); // If we've not written anything else to the testoutput folder, remove that too // rather than leaving an empty folder lieing around in the source tree! FileFinder output_root("", RelativeTo::ChasteTestOutput); if (output_root.IsEmpty()) { output_root.DangerousRemove(); } } PetscTools::Barrier("TestOutputFileHandler-2c"); } { setenv("CHASTE_TEST_OUTPUT", "config__cyborg__T800__cooper", 1/*Overwrite*/); // Test that CHASTE_TEST_OUTPUT always has a trailing slash even before // a class object is instantiated and when the directory does not exist const std::string nonexistent_test_path(OutputFileHandler::GetChasteTestOutputDirectory()); TS_ASSERT_EQUALS( *(nonexistent_test_path.end()-1), '/'); } { // Check this folder is not present std::string test_folder("somewhere_without_trailing_forward_slash"); TS_ASSERT(!FileFinder(test_folder, RelativeTo::CWD).Exists()); PetscTools::Barrier("TestOutputFileHandler-3"); setenv("CHASTE_TEST_OUTPUT", test_folder.c_str(), 1/*Overwrite*/); // Make a folder using a FileFinder, for coverage of the case where the root output folder doesn't exist FileFinder sub_folder("test_folder", RelativeTo::ChasteTestOutput); TS_ASSERT(!sub_folder.Exists()); PetscTools::Barrier("TestOutputFileHandler-3a"); OutputFileHandler creating_handler(sub_folder); TS_ASSERT(sub_folder.Exists()); // Make a folder OutputFileHandler handler5("whatever"); TS_ASSERT(FileFinder(test_folder, RelativeTo::CWD).Exists()); PetscTools::Barrier("TestOutputFileHandler-3b"); // Erase it if (PetscTools::AmMaster()) { FileFinder(test_folder).DangerousRemove(); } } // Reset the location of CHASTE_TEST_OUTPUT setenv("CHASTE_TEST_OUTPUT", chaste_test_output.c_str(), 1/*Overwrite*/); // We don't want other people using CHASTE_TEST_OUTPUT while we are messing with it! PetscTools::Barrier("TestOutputFileHandler-4"); // Coverage of the case where we can't open a file for writing OutputFileHandler handler6("no_write_access"); if (PetscTools::AmMaster()) { std::string dir_path = handler6.GetOutputDirectoryFullPath(); #ifndef _MSC_VER // This test can never pass on modern Windows OS! See: http://support.microsoft.com/kb/326549 // You can't change DIRECTORY attributes chmod(dir_path.c_str(), CHASTE_READONLY); TS_ASSERT_THROWS_CONTAINS(p_file_stream = handler6.OpenOutputFile("test_file"), "Could not open file"); #endif chmod(dir_path.c_str(), CHASTE_READ_WRITE_EXECUTE); fs::remove(dir_path + ".chaste_deletable_folder"); fs::remove(dir_path); } // Check behaviour of FindFile("") FileFinder handler_self = handler.FindFile(""); TS_ASSERT_EQUALS(handler_self.GetAbsolutePath(), handler.GetOutputDirectoryFullPath()); }
Vec AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::Solve() { // Begin by checking that everything has been set up correctly if (!mTimesSet) { EXCEPTION("SetTimes() has not been called"); } if ((mIdealTimeStep <= 0.0) && (mpTimeAdaptivityController==NULL)) { EXCEPTION("SetTimeStep() has not been called"); } if (mInitialCondition == NULL) { EXCEPTION("SetInitialCondition() has not been called"); } // If required, initialise HDF5 writer and output initial condition to HDF5 file bool print_output = (mOutputToVtk || mOutputToParallelVtk || mOutputToTxt); if (print_output) { InitialiseHdf5Writer(); WriteOneStep(mTstart, mInitialCondition); mpHdf5Writer->AdvanceAlongUnlimitedDimension(); } this->InitialiseForSolve(mInitialCondition); if (mIdealTimeStep < 0) // hasn't been set, so a controller must have been given { mIdealTimeStep = mpTimeAdaptivityController->GetNextTimeStep(mTstart, mInitialCondition); } /* * Note: we use the mIdealTimeStep here (the original timestep that was passed in, or * the last timestep suggested by the controller), rather than the last timestep used * (mLastWorkingTimeStep), because the timestep will be very slightly altered by the * stepper in the final timestep of the last printing-timestep-loop, and these floating * point errors can add up and eventually cause exceptions being thrown. */ TimeStepper stepper(mTstart, mTend, mIdealTimeStep, mMatrixIsConstant); Vec solution = mInitialCondition; Vec next_solution; while (!stepper.IsTimeAtEnd()) { bool timestep_changed = false; PdeSimulationTime::SetTime(stepper.GetTime()); // Determine timestep to use double new_dt; if (mpTimeAdaptivityController) { // Get the timestep the controller wants to use and store it as the ideal timestep mIdealTimeStep = mpTimeAdaptivityController->GetNextTimeStep(stepper.GetTime(), solution); // Tell the stepper to use this timestep from now on... stepper.ResetTimeStep(mIdealTimeStep); // ..but now get the timestep from the stepper, as the stepper might need // to trim the timestep if it would take us over the end time new_dt = stepper.GetNextTimeStep(); // Changes in timestep bigger than 0.001% will trigger matrix re-computation timestep_changed = (fabs(new_dt/mLastWorkingTimeStep - 1.0) > 1e-5); } else { new_dt = stepper.GetNextTimeStep(); //new_dt should be roughly the same size as mIdealTimeStep - we should never need to take a tiny step if (mMatrixIsConstant && fabs(new_dt/mIdealTimeStep - 1.0) > 1e-5) { // Here we allow for changes of up to 0.001% // Note that the TimeStepper guarantees that changes in dt are no bigger than DBL_EPSILON*current_time NEVER_REACHED; } } // Save the timestep as the last one use, and also put it in PdeSimulationTime // so everyone can see it mLastWorkingTimeStep = new_dt; PdeSimulationTime::SetPdeTimeStepAndNextTime(new_dt, stepper.GetNextTime()); // Solve try { // (This runs the cell ODE models in heart simulations) this->PrepareForSetupLinearSystem(solution); } catch(Exception& e) { // We only need to clean up memory if we are NOT on the first PDE time step, // as someone else cleans up the mInitialCondition vector in higher classes. if (solution != mInitialCondition) { HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION); PetscTools::Destroy(solution); HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION); } throw e; } bool compute_matrix = (!mMatrixIsConstant || !mMatrixIsAssembled || timestep_changed); this->SetupLinearSystem(solution, compute_matrix); this->FinaliseLinearSystem(solution); if (compute_matrix) { this->mpLinearSystem->ResetKspSolver(); } next_solution = this->mpLinearSystem->Solve(solution); if (mMatrixIsConstant) { mMatrixIsAssembled = true; } this->FollowingSolveLinearSystem(next_solution); stepper.AdvanceOneTimeStep(); // Avoid memory leaks if (solution != mInitialCondition) { HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION); PetscTools::Destroy(solution); HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION); } solution = next_solution; // If required, output next solution to HDF5 file if (print_output && (stepper.GetTotalTimeStepsTaken()%mPrintingTimestepMultiple == 0) ) { WriteOneStep(stepper.GetTime(), solution); mpHdf5Writer->AdvanceAlongUnlimitedDimension(); } } // Avoid memory leaks if (mpHdf5Writer != NULL) { delete mpHdf5Writer; mpHdf5Writer = NULL; } // Convert HDF5 output to other formats as required if (mOutputToVtk) { Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(FileFinder(mOutputDirectory, RelativeTo::ChasteTestOutput), mFilenamePrefix, this->mpMesh, false, false); } if (mOutputToParallelVtk) { Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(FileFinder(mOutputDirectory, RelativeTo::ChasteTestOutput), mFilenamePrefix, this->mpMesh, true, false); } if (mOutputToTxt) { Hdf5ToTxtConverter<ELEMENT_DIM,SPACE_DIM> converter(FileFinder(mOutputDirectory, RelativeTo::ChasteTestOutput), mFilenamePrefix, this->mpMesh); } return solution; }
VoltageInterpolaterOntoMechanicsMesh<DIM>::VoltageInterpolaterOntoMechanicsMesh( TetrahedralMesh<DIM,DIM>& rElectricsMesh, QuadraticMesh<DIM>& rMechanicsMesh, std::vector<std::string>& rVariableNames, std::string directory, std::string inputFileNamePrefix) { // Read the data from the HDF5 file Hdf5DataReader reader(directory,inputFileNamePrefix); unsigned num_timesteps = reader.GetUnlimitedDimensionValues().size(); // set up the elements and weights for the coarse nodes in the fine mesh FineCoarseMeshPair<DIM> mesh_pair(rElectricsMesh, rMechanicsMesh); mesh_pair.SetUpBoxesOnFineMesh(); mesh_pair.ComputeFineElementsAndWeightsForCoarseNodes(true); assert(mesh_pair.rGetElementsAndWeights().size()==rMechanicsMesh.GetNumNodes()); // create and setup a writer Hdf5DataWriter* p_writer = new Hdf5DataWriter(*rMechanicsMesh.GetDistributedVectorFactory(), directory, "voltage_mechanics_mesh", false, //don't clean false); std::vector<int> columns_id; for (unsigned var_index = 0; var_index < rVariableNames.size(); var_index++) { std::string var_name = rVariableNames[var_index]; columns_id.push_back( p_writer->DefineVariable(var_name,"mV") ); } p_writer->DefineUnlimitedDimension("Time","msecs", num_timesteps); p_writer->DefineFixedDimension( rMechanicsMesh.GetNumNodes() ); p_writer->EndDefineMode(); assert(columns_id.size() == rVariableNames.size()); // set up a vector to read into DistributedVectorFactory factory(rElectricsMesh.GetNumNodes()); Vec voltage = factory.CreateVec(); std::vector<double> interpolated_voltages(rMechanicsMesh.GetNumNodes()); Vec voltage_coarse = NULL; for(unsigned time_step=0; time_step<num_timesteps; time_step++) { for (unsigned var_index = 0; var_index < rVariableNames.size(); var_index++) { std::string var_name = rVariableNames[var_index]; // read reader.GetVariableOverNodes(voltage, var_name, time_step); ReplicatableVector voltage_repl(voltage); // interpolate for(unsigned i=0; i<mesh_pair.rGetElementsAndWeights().size(); i++) { double interpolated_voltage = 0; Element<DIM,DIM>& element = *(rElectricsMesh.GetElement(mesh_pair.rGetElementsAndWeights()[i].ElementNum)); for(unsigned node_index = 0; node_index<element.GetNumNodes(); node_index++) { unsigned global_node_index = element.GetNodeGlobalIndex(node_index); interpolated_voltage += voltage_repl[global_node_index]*mesh_pair.rGetElementsAndWeights()[i].Weights(node_index); } interpolated_voltages[i] = interpolated_voltage; } if(voltage_coarse!=NULL) { PetscTools::Destroy(voltage_coarse); } voltage_coarse = PetscTools::CreateVec(interpolated_voltages); // write p_writer->PutVector(columns_id[var_index], voltage_coarse); } p_writer->PutUnlimitedVariable(time_step); p_writer->AdvanceAlongUnlimitedDimension(); } if(voltage_coarse!=NULL) { PetscTools::Destroy(voltage); PetscTools::Destroy(voltage_coarse); } // delete to flush delete p_writer; // Convert the new data to CMGUI format. // alter the directory in HeartConfig as that is where Hdf5ToCmguiConverter decides // where to output std::string config_directory = HeartConfig::Instance()->GetOutputDirectory(); HeartConfig::Instance()->SetOutputDirectory(directory); Hdf5ToCmguiConverter<DIM,DIM> converter(FileFinder(directory, RelativeTo::ChasteTestOutput), "voltage_mechanics_mesh", &rMechanicsMesh, false); HeartConfig::Instance()->SetOutputDirectory(config_directory); }
FileFinder OutputFileHandler::FindFile(std::string leafName) const { return FileFinder(GetOutputDirectoryFullPath() + leafName, RelativeTo::Absolute); }