diff --git a/src/specmicp/io/hdf5_adimensional.cpp b/src/specmicp/io/hdf5_adimensional.cpp index 8dde0f5..c8a945f 100644 --- a/src/specmicp/io/hdf5_adimensional.cpp +++ b/src/specmicp/io/hdf5_adimensional.cpp @@ -1,355 +1,307 @@ /* ============================================================================= Copyright (c) 2014 - 2016 F. Georget Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ============================================================================= */ #include "hdf5_adimensional.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp_common/io/specmicp_hdf5.hpp" #include "specmicp_common/io/hdf5_eigen.hpp" #include "H5Exception.h" #include +#include "specmicp_common/io/hdf5/path.hpp" +#include "specmicp_common/io/hdf5/group.hpp" +#include "specmicp_common/io/hdf5/dataspace.hpp" +#include "specmicp_common/io/hdf5/attribute.hpp" +#include "specmicp_common/io/hdf5/dataset.hpp" + namespace specmicp { namespace io { #define MAIN_VARIABLES_DS "main_variables" #define SECONDARY_MOLALITIES_DS "secondary_molalities" #define LOG_GAMMA_DS "log_gamma" #define GAS_FUGACITIES_DS "gas_fugacities" #define SORBED_MOLALITIES_DS "sorbed_molalities" #define SCALAR_VARS_ATT "scalar_vars" //! \brief Implementation class to save a HDF5 file //! //! \internal class SPECMICP_DLL_LOCAL AdimensionalSystemSolutionHDF5Saver { public: AdimensionalSystemSolutionHDF5Saver( const AdimensionalSystemSolution& solution): m_solution(solution) {} - //! \brief Save the solution into file (in subgroup section/name) + //! \brief Save the solution into the current location + //! + //! Create a new group named 'name' to store the datasets void save( - HDF5File& file, - const std::string& name, - const std::string& section + hdf5::GroupPath& location, + const std::string& name ); - private: - void save_main_variables(HDF5File& file, const std::string& section); - void save_molalities(HDF5File& file, const std::string& section); - void save_loggamma(HDF5File& file, const std::string& section); - void save_gas_fugacities(HDF5File& file, const std::string& section); - void save_sorbed_molalities(HDF5File& file, const std::string& section); + void save_main_variables( hdf5::GroupPath& location); + void save_molalities( hdf5::GroupPath& location); + void save_loggamma( hdf5::GroupPath& location); + void save_gas_fugacities( hdf5::GroupPath& location); + void save_sorbed_molalities( hdf5::GroupPath& location); const AdimensionalSystemSolution& m_solution; }; //! \brief Implementation : read a HDF5 file //! //! \internal namespace AdimensionalSystemSolutionHDF5Reader { //! \brief Save the solution into file (in subgroup section/name) -static void read( - const HDF5File& file, - const std::string& name, - const std::string& section, - AdimensionalSystemSolution& solution); - -//! \brief Save the solution into file (in subgroup section/name) -static void read( - const H5::Group& group, - AdimensionalSystemSolution& solution +static AdimensionalSystemSolution read( + const hdf5::GroupPath& location ); static void read_main_variables( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution& solution); static void read_molalities( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution& solution); static void read_loggamma( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution& solution); static void read_gas_fugacities( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution& solution); static void read_sorbed_molalities( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution& solution); } // end namespace AdimensionalSystemSolutionHDF5Reader - void save_adimensional_system_solution( - HDF5File& file, + hdf5::GroupPath& location, const std::string& name, - const std::string& section, const AdimensionalSystemSolution& solution ) { + if (not solution.is_valid) { + throw std::runtime_error("AdimSolution to save is not valid !" + " Solution " + name + " to be saved in " + + location.get_path() + "."); + } AdimensionalSystemSolutionHDF5Saver saver(solution); - saver.save(file, name, section); + saver.save(location, name); } -void read_adimensional_system_solution( - const HDF5File& file, - const std::string& name, - const std::string& section, - AdimensionalSystemSolution& solution - ) -{ - AdimensionalSystemSolutionHDF5Reader::read(file, name, section, solution); -} -void read_adimensional_system_solution( - const H5::Group& group, - AdimensionalSystemSolution& solution +//! \brief Read a solution from an HDF5 file +AdimensionalSystemSolution SPECMICP_DLL_PUBLIC +read_adimensional_system_solution( + const hdf5::GroupPath& location, + const std::string& name ) { - AdimensionalSystemSolutionHDF5Reader::read(group, solution); + if (not location.has_link(name)) { + throw std::runtime_error("The path " + location.add_to_path(name) + + "does not exist"); + } + hdf5::Group sol_loc = location.open_group(name); + return AdimensionalSystemSolutionHDF5Reader::read(sol_loc); } // Implementation // ============== // Save // ----- void AdimensionalSystemSolutionHDF5Saver::save( - HDF5File& file, - const std::string& name, - const std::string& section + hdf5::GroupPath& location, + const std::string& name ) { - auto complete_sec = file.complete_name(name, section); - auto adim_group = file.create_group(complete_sec); + auto grp = location.create_group(name); - save_main_variables(file, complete_sec); - save_molalities(file, complete_sec); - save_loggamma(file, complete_sec); + save_main_variables(grp); + save_molalities(grp); + save_loggamma(grp); if (m_solution.gas_fugacities.rows() > 0) { - save_gas_fugacities(file, complete_sec); + save_gas_fugacities(grp); } if (m_solution.sorbed_molalities.rows() > 0) { - save_sorbed_molalities(file, complete_sec); + save_sorbed_molalities(grp); } } void AdimensionalSystemSolutionHDF5Saver::save_main_variables( - HDF5File& file, - const std::string §ion + hdf5::GroupPath& location ) { - auto dataset = save_eigen_matrix(file, - MAIN_VARIABLES_DS, section, - m_solution.main_variables - ); - hsize_t dims[] = {2}; - auto dspace = H5::DataSpace(1, dims); - auto attribute = dataset->createAttribute(SCALAR_VARS_ATT, - H5::PredType::NATIVE_DOUBLE, - dspace); - - scalar_t attribute_values[] = {m_solution.inert_volume_fraction, - m_solution.ionic_strength}; - - attribute.write(H5::PredType::NATIVE_DOUBLE, attribute_values); + hdf5::Dataset dataset = location.create_vector_dataset( + MAIN_VARIABLES_DS, + m_solution.main_variables + ); + // save scalar values as attributes + std::array attribute_values = { + m_solution.inert_volume_fraction, + m_solution.ionic_strength + }; + + hdf5::Attribute attr = dataset.create_scalar_attribute( + SCALAR_VARS_ATT, attribute_values); } void AdimensionalSystemSolutionHDF5Saver::save_molalities( - HDF5File& file, - const std::string §ion + hdf5::GroupPath& location ) { - save_eigen_matrix(file, - SECONDARY_MOLALITIES_DS, section, - m_solution.secondary_molalities - ); + location.create_vector_dataset( + SECONDARY_MOLALITIES_DS, + m_solution.secondary_molalities + ); } void AdimensionalSystemSolutionHDF5Saver::save_loggamma( - HDF5File& file, - const std::string §ion + hdf5::GroupPath& location ) { - save_eigen_matrix(file, - LOG_GAMMA_DS, section, - m_solution.log_gamma - ); + location.create_vector_dataset( + LOG_GAMMA_DS, + m_solution.log_gamma + ); } void AdimensionalSystemSolutionHDF5Saver::save_gas_fugacities( - HDF5File& file, - const std::string §ion + hdf5::GroupPath& location ) { - save_eigen_matrix(file, - GAS_FUGACITIES_DS, section, - m_solution.gas_fugacities - ); + location.create_vector_dataset( + GAS_FUGACITIES_DS, + m_solution.gas_fugacities + ); } void AdimensionalSystemSolutionHDF5Saver::save_sorbed_molalities( - HDF5File& file, - const std::string §ion + hdf5::GroupPath& location ) { - save_eigen_matrix(file, - SORBED_MOLALITIES_DS, section, - m_solution.sorbed_molalities - ); + location.create_vector_dataset( + SORBED_MOLALITIES_DS, + m_solution.sorbed_molalities + ); } + // read // ---- namespace AdimensionalSystemSolutionHDF5Reader { -void read( - const HDF5File& file, - const std::string& name, - const std::string& section, - AdimensionalSystemSolution& solution +AdimensionalSystemSolution read( + const hdf5::GroupPath& location ) { - auto group = file.open_group(file.complete_name(name, section)); - read(*group.get(), solution); -} + AdimensionalSystemSolution solution; -void read( - const H5::Group& group, - AdimensionalSystemSolution& solution - ) -{ - solution.is_valid = false; - - read_main_variables(group, solution); - read_molalities(group, solution); - read_loggamma(group, solution); - - H5E_auto_t func_p; - void* client_data = nullptr; - H5::Exception::getAutoPrint(func_p, &client_data); - { // gas - bool has_gas = true; - H5::Exception::dontPrint(); - try { - group.openDataSet(GAS_FUGACITIES_DS); - } - catch (H5::GroupIException _) { - has_gas = false; - } - H5::Exception::setAutoPrint(func_p, client_data); - if (has_gas) { - read_gas_fugacities(group, solution); - } - } - { // sorbed - bool has_sorbed = true; - H5::Exception::dontPrint(); - try { - group.openDataSet(SORBED_MOLALITIES_DS); - } - catch (H5::GroupIException _) { - has_sorbed = false; - } - H5::Exception::setAutoPrint(func_p, client_data); - if (has_sorbed) { - read_sorbed_molalities(group, solution); - } - } + read_main_variables(location, solution); + read_molalities(location, solution); + read_loggamma(location, solution); + read_gas_fugacities(location, solution); + read_sorbed_molalities(location, solution); solution.is_valid = true; + return solution; } void read_main_variables( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution &solution ) { - read_eigen_matrix(group, MAIN_VARIABLES_DS, solution.main_variables); + solution.main_variables = location.read_vector_dataset(MAIN_VARIABLES_DS); - auto dataset = group.openDataSet(MAIN_VARIABLES_DS); - H5::Attribute attr = dataset.openAttribute(SCALAR_VARS_ATT); + // read scalar variables + hdf5::Dataset dset = location.open_dataset(MAIN_VARIABLES_DS); + auto attributes = dset.read_scalar_attribute<2>(SCALAR_VARS_ATT); - double attr_out[2]; - attr.read(H5::PredType::NATIVE_DOUBLE, attr_out); - solution.inert_volume_fraction = attr_out[0]; - solution.ionic_strength = attr_out[1]; + solution.inert_volume_fraction = attributes[0]; + solution.ionic_strength = attributes[1]; } void read_molalities( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution &solution ) { - read_eigen_matrix(group, SECONDARY_MOLALITIES_DS, - solution.secondary_molalities); + solution.secondary_molalities = + location.read_vector_dataset(SECONDARY_MOLALITIES_DS); } void read_loggamma( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution &solution ) { - read_eigen_matrix(group, LOG_GAMMA_DS, - solution.log_gamma); + solution.log_gamma = location.read_vector_dataset(LOG_GAMMA_DS); } void read_gas_fugacities( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution &solution ) { - read_eigen_matrix(group, GAS_FUGACITIES_DS, - solution.gas_fugacities); + if (location.has_link(GAS_FUGACITIES_DS)) { + solution.gas_fugacities = + location.read_vector_dataset(GAS_FUGACITIES_DS); + } } void read_sorbed_molalities( - const H5::Group& group, + const hdf5::GroupPath& location, AdimensionalSystemSolution &solution ) { - read_eigen_matrix(group, SORBED_MOLALITIES_DS, - solution.sorbed_molalities); + if (location.has_link(SORBED_MOLALITIES_DS)) { + solution.sorbed_molalities = + location.read_vector_dataset(SORBED_MOLALITIES_DS); + } } } // end namespace AdimensionalSystemSolutionHDF5Reader } //end namespace io } //end namespace specmicp diff --git a/src/specmicp/io/hdf5_adimensional.hpp b/src/specmicp/io/hdf5_adimensional.hpp index 3409858..c7020b2 100644 --- a/src/specmicp/io/hdf5_adimensional.hpp +++ b/src/specmicp/io/hdf5_adimensional.hpp @@ -1,80 +1,71 @@ /* ============================================================================= Copyright (c) 2014 - 2016 F. Georget Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ============================================================================= */ #ifndef SPECMICP_IO_HDF5_ADIMENSIONAL_HPP #define SPECMICP_IO_HDF5_ADIMENSIONAL_HPP #include "specmicp_common/macros.hpp" #include //! \file specmicp/io/hdf5_adimensional.hpp //! \brief Read and write AdimSolution to HDF5 format -namespace H5 { - class Group; -} //end namespace H5 namespace specmicp { struct AdimensionalSystemSolution; namespace io { -class HDF5File; +namespace hdf5 { + class GroupPath; +} //end namespace hdf5 -//! \brief Save a solution to a HDF5 file +//! \brief Read a solution from an HDF5 file void SPECMICP_DLL_PUBLIC save_adimensional_system_solution( - HDF5File& file, + hdf5::GroupPath& location, const std::string& name, - const std::string& section, const AdimensionalSystemSolution& solution ); - -//! \brief Read a solution from an HDF5 file -void SPECMICP_DLL_PUBLIC read_adimensional_system_solution( - const HDF5File& file, - const std::string& name, - const std::string& section, - AdimensionalSystemSolution& solution - ); //! \brief Read a solution from an HDF5 file -void SPECMICP_DLL_PUBLIC read_adimensional_system_solution( - const H5::Group& group, - AdimensionalSystemSolution& solution +AdimensionalSystemSolution SPECMICP_DLL_PUBLIC +read_adimensional_system_solution( + const hdf5::GroupPath& location, + const std::string& name ); } //end namespace io } //end namespace specmicp #endif // SPECMICP_IO_HDF5_ADIMENSIONAL_HPP diff --git a/tests/specmicp/adim/io_hdf5_adimensional.cpp b/tests/specmicp/adim/io_hdf5_adimensional.cpp index 3e5d41f..7d50fad 100644 --- a/tests/specmicp/adim/io_hdf5_adimensional.cpp +++ b/tests/specmicp/adim/io_hdf5_adimensional.cpp @@ -1,109 +1,104 @@ #include "catch.hpp" #include #include "specmicp_common/log.hpp" #include "specmicp/adimensional/adimensional_system.hpp" #include "specmicp_common/micpsolver/micpsolver.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/adimensional_system_solution_saver.hpp" #include "specmicp_database/database.hpp" -#include "specmicp_common/io/specmicp_hdf5.hpp" #include "specmicp/io/hdf5_adimensional.hpp" +#include "specmicp_common/io/hdf5/file.hpp" +#include "specmicp_common/io/hdf5/path.hpp" -#include using namespace specmicp; using namespace specmicp::io; static specmicp::RawDatabasePtr get_test_simple_database() { specmicp::database::Database thedatabase(TEST_CEMDATA_PATH); std::map swapping ({ {"H[+]","HO[-]"}, }); thedatabase.swap_components(swapping); std::vector to_keep = {"HO[-]", "Ca[2+]"}; thedatabase.keep_only_components(to_keep); thedatabase.remove_half_cell_reactions(std::vector({"H2O", "HO[-]",})) ; return thedatabase.get_database(); } TEST_CASE("Adimensional_hdf5_saver", "[Adimensional],[io],[hdf5]") { specmicp::logger::ErrFile::stream() = &std::cerr; specmicp::stdlog::ReportLevel() = specmicp::logger::Error; specmicp::RawDatabasePtr thedatabase = get_test_simple_database(); auto id_h2o = database::DataContainer::water_index(); auto id_oh = thedatabase->get_id_component("HO[-]"); auto id_ca = thedatabase->get_id_component("Ca[2+]"); auto id_ch = thedatabase->get_id_mineral("Portlandite"); -SECTION("Save and read solution") { - Vector total_concentration = Vector::Zero(thedatabase->nb_component()); total_concentration(id_h2o) = 0.03; total_concentration(id_oh) = 0.02; total_concentration(id_ca) = 0.01; specmicp::Vector x; specmicp::AdimensionalSystemConstraints constraints(total_concentration); specmicp::AdimensionalSystemSolver solver(thedatabase, constraints); solver.initialise_variables(x, 0.8, -2.0); solver.get_options().units_set.length = specmicp::units::LengthUnit::centimeter; solver.get_options().solver_options.maxstep = 10.0; solver.get_options().solver_options.maxiter_maxstep = 100; solver.get_options().solver_options.use_crashing = false; solver.get_options().solver_options.use_scaling = true; solver.get_options().solver_options.disable_descent_direction(); solver.get_options().solver_options.factor_gradient_search_direction = 100; solver.solve(x); - AdimensionalSystemSolution solution = solver.get_raw_solution(x); +SECTION("Save and read solution") { - HDF5File file("test_specmicp_adim_solution", HDF5_OpenMode::CreateTruncate); + AdimensionalSystemSolution solution = solver.get_raw_solution(x); - save_adimensional_system_solution( - file, - "test_solution", - "/", - solution - ); - file.close(); + auto h5file = io::hdf5::File::open("test_specmicp_adim_solution.hdf5", + io::hdf5::OpenMode::CreateTruncate); - file.open("test_specmicp_adim_solution", HDF5_OpenMode::OpenReadOnly); - AdimensionalSystemSolution readto; + save_adimensional_system_solution(h5file, "test_solution", solution); - read_adimensional_system_solution(file, "test_solution", "/", readto); - file.close(); + CHECK(h5file.has_link("test_solution")); + AdimensionalSystemSolution readto = read_adimensional_system_solution( + h5file, + "test_solution" + ); CHECK(readto.is_valid); CHECK(readto.main_variables.rows() == solution.main_variables.rows()); CHECK(readto.main_variables(0) == Approx(solution.main_variables(0))); CHECK(readto.main_variables(3) == Approx(solution.main_variables(3))); CHECK(readto.log_gamma.rows() == solution.log_gamma.rows()); CHECK(readto.log_gamma(2) == Approx(solution.log_gamma(2))); CHECK(readto.secondary_molalities.rows() == solution.secondary_molalities.rows()); CHECK(readto.secondary_molalities(1) == Approx(solution.secondary_molalities(1))); CHECK(readto.ionic_strength == Approx(solution.ionic_strength)); CHECK(readto.inert_volume_fraction == Approx(solution.inert_volume_fraction)); } }