Example #1
0
    /**
    * 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
    }
Example #2
0
    // 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();
    }
Example #3
0
    /**
     * 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());
        }
    }
Example #4
0
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");
    }
Example #6
0
    // 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();
    }
Example #7
0
    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();
    }
Example #8
0
    /**
     * 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
    }
Example #9
0
    /**
     * 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);
}
Example #13
0
FileFinder OutputFileHandler::FindFile(std::string leafName) const
{
    return FileFinder(GetOutputDirectoryFullPath() + leafName, RelativeTo::Absolute);
}