diff --git a/dumux/io/container.hh b/dumux/io/container.hh index 7799653c783a7de070492bf60931db55b1a2fedb..a7dea7dd35ff3ce69db7049add933b1c71d20f99 100644 --- a/dumux/io/container.hh +++ b/dumux/io/container.hh @@ -33,6 +33,8 @@ #include <fstream> #include <iterator> +#include <dune/common/exceptions.hh> + namespace Dumux { /*! @@ -55,21 +57,36 @@ void writeContainerToFile(const Container& v, std::copy(v.begin(),v.end(), it); } +/*! + * \brief Read an input stream into a container + * \param stream A standard input stream + * \tparam Container The container type requires begin(), end(), push_back() functions + * and Container::value_type requires operator>>. + */ +template<typename Container> +Container readStreamToContainer(std::istream& stream) +{ + Container v; + std::istream_iterator<typename Container::value_type> it(stream); + std::copy(it, std::istream_iterator<typename Container::value_type>(), std::back_inserter(v)); + return v; +} + /*! * \brief Read a simple text file into a container * \param filename The filename to write to - * \tparam Container The container type, requires begin(), end(), push_back() method + * \tparam Container The container type requires begin(), end(), push_back() functions + * and Container::value_type requires operator>>. * * usage: auto v = readFileToContainer<std::vector<double>>("myvector.txt"); */ template<typename Container> Container readFileToContainer(const std::string& filename) { - Container v; std::ifstream infile(filename, std::ios::in); - std::istream_iterator<typename Container::value_type> it(infile); - std::copy(it, std::istream_iterator<typename Container::value_type>(), std::back_inserter(v)); - return v; + if (!infile) + DUNE_THROW(Dune::IOError, "Could not open file: " << filename); + return readStreamToContainer<Container>(infile); } } // end namespace Dumux diff --git a/dumux/io/vtk/vtkreader.hh b/dumux/io/vtk/vtkreader.hh index d9e71c42adb2cb418302ce5015cf30a0d0daee66..cf2f94bc8c5baa1eac5bb1bf7ba8351785357afe 100644 --- a/dumux/io/vtk/vtkreader.hh +++ b/dumux/io/vtk/vtkreader.hh @@ -36,9 +36,11 @@ #include <dune/common/exceptions.hh> #include <dune/grid/common/capabilities.hh> #include <dune/grid/io/file/vtk/common.hh> -#include <dumux/io/xml/tinyxml2.h> #include <dune/grid/common/gridfactory.hh> +#include <dumux/io/container.hh> +#include <dumux/io/xml/tinyxml2.h> + namespace Dumux { /*! @@ -479,11 +481,8 @@ private: template<class Container> Container parseDataArray_(const tinyxml2::XMLElement* dataArray) const { - Container data; std::stringstream dataStream(dataArray->GetText()); - std::istream_iterator<typename Container::value_type> it(dataStream); - std::copy(it, std::istream_iterator<typename Container::value_type>(), std::back_inserter(data)); - return data; + return readStreamToContainer<Container>(dataStream); } /*! diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index a6346665975c27a9b9545ba87728c25a8bef2747..b2d84016e92485ae8aa074c1d79f1de86172b6c6 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -1,5 +1,6 @@ +add_subdirectory(container) add_subdirectory(gnuplotinterface) add_subdirectory(gridmanager) -add_subdirectory(container) -add_subdirectory(vtk) +add_subdirectory(inputdata) add_subdirectory(rasterimagereader) +add_subdirectory(vtk) diff --git a/test/io/inputdata/CMakeLists.txt b/test/io/inputdata/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ecf567d10832f99a1ae87a8ce813cdb2f0c6d037 --- /dev/null +++ b/test/io/inputdata/CMakeLists.txt @@ -0,0 +1,2 @@ +dune_symlink_to_source_files(FILES config.ini coordinates.txt mydata.xml numbers.txt) +dumux_add_test(SOURCES test_io_data_input.cc LABELS unit io) diff --git a/test/io/inputdata/config.ini b/test/io/inputdata/config.ini new file mode 100644 index 0000000000000000000000000000000000000000..691d2cefa42baae1d636ca451d19c74739a3276e --- /dev/null +++ b/test/io/inputdata/config.ini @@ -0,0 +1,6 @@ +[MyData] +InjectionRate = 0.1 0.2 0.3 0.4 +BoundaryFlags = 3 4 5 6 + +[Problem] +Gravity = false diff --git a/test/io/inputdata/coordinates.txt b/test/io/inputdata/coordinates.txt new file mode 100644 index 0000000000000000000000000000000000000000..4360a73c26fa9daf6d10d0c18a16e0f608859bac --- /dev/null +++ b/test/io/inputdata/coordinates.txt @@ -0,0 +1,4 @@ +0.1 0.1 0.054 +0.2 0.1 0.054 +0.3 0.2 0.054 +0.4 0.1 0.454 diff --git a/test/io/inputdata/mydata.xml b/test/io/inputdata/mydata.xml new file mode 100644 index 0000000000000000000000000000000000000000..64e9b2cff391d87b68c4ed2ba079fa7c2765bab1 --- /dev/null +++ b/test/io/inputdata/mydata.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- Simple custom data file --> +<InputData> + <!-- Injection rates are in kg/s --> + <InjectionRates> + 0.1 0.2 0.3 0.4 + </InjectionRates> + + <!-- BoundaryTypes: -1: no boundary, 0: Dirichlet, 1: Noflow, 2: Infiltration, 3: Outflow --> + <BoundaryTypes> + 0 -1 -1 2 + </BoundaryTypes> +</InputData> diff --git a/test/io/inputdata/numbers.txt b/test/io/inputdata/numbers.txt new file mode 100644 index 0000000000000000000000000000000000000000..c23c5da710efc48cf929a2358caa3f4a3a54d59e --- /dev/null +++ b/test/io/inputdata/numbers.txt @@ -0,0 +1,4 @@ +0.1 +0.2 +0.3 +0.4 diff --git a/test/io/inputdata/test_io_data_input.cc b/test/io/inputdata/test_io_data_input.cc new file mode 100644 index 0000000000000000000000000000000000000000..0be56eb9c3c8193e662653d83e0a29c869fc32d5 --- /dev/null +++ b/test/io/inputdata/test_io_data_input.cc @@ -0,0 +1,112 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \brief Test and example of how to read custom user data in Dumux + */ +#include <config.h> + +#include <algorithm> +#include <vector> +#include <iostream> + +#include <dune/common/exceptions.hh> +#include <dune/common/fvector.hh> +#include <dune/common/parametertreeparser.hh> + +#include <dumux/io/container.hh> +#include <dumux/io/xml/tinyxml2.h> + +//////////////////////// +// the main function +//////////////////////// +int main() +{ + using namespace Dumux; + + { + std::cout << "Reading a simple list of numbers into a vector\n"; + std::cout << "-- Read numbers.txt: \n"; + + // the file extension ".txt" is arbitrary, works with any other extension or none + const auto numbers = readFileToContainer<std::vector<double>>("numbers.txt"); + + std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<double>(std::cout, ", ")); + std::cout << "\n" << std::endl; + } + + { + std::cout << "Reading a three-column list of numbers into a vector\n"; + std::cout << "-- Read coordinates.txt: \n"; + + // the file extension ".txt" is arbitrary, works with any other extension or none + const auto coordinates = readFileToContainer<std::vector<Dune::FieldVector<double, 3>>>("coordinates.txt"); + + std::copy(coordinates.begin(), coordinates.end(), std::ostream_iterator<Dune::FieldVector<double, 3>>(std::cout, ", ")); + std::cout << "\n" << std::endl; + } + + { + std::cout << "Reading a key-value ini-style file into a Dune::ParameterTree\n"; + std::cout << "-- Read config.ini: \n"; + + Dune::ParameterTree config; + // the file extension ".ini" is arbitrary, works with any other extension or none + Dune::ParameterTreeParser::readINITree("config.ini", config); + + config.report(); + std::cout << "\n"; + + std::cout << "-- Parsing MyData.InjectionRate into a vector: \n"; + + const auto injectionRates = config.get<std::vector<double>>("MyData.InjectionRate"); + + std::copy(injectionRates.begin(), injectionRates.end(), std::ostream_iterator<double>(std::cout, " ")); + std::cout << "\n" << std::endl; + } + + { + std::cout << "Reading a XML-formatted data using tiny xml\n"; + + tinyxml2::XMLDocument xmlData; + // the file extension ".xml" is arbitrary, works with any other extension or none + const auto returnCode = xmlData.LoadFile("mydata.xml"); + if (returnCode != tinyxml2::XML_SUCCESS) + DUNE_THROW(Dune::IOError, "Couldn't open XML file."); + const tinyxml2::XMLElement* inputData = xmlData.FirstChildElement("InputData"); + + std::cout << "-- Read InjectionRates field: \n"; + + std::stringstream injectionData(inputData->FirstChildElement("InjectionRates")->GetText()); + const auto injectionRates = readStreamToContainer<std::vector<double>>(injectionData); + + std::copy(injectionRates.begin(), injectionRates.end(), std::ostream_iterator<double>(std::cout, " ")); + std::cout << "\n"; + + std::cout << "-- Read BoundaryTypes field: \n"; + + std::stringstream boundaryData(inputData->FirstChildElement("BoundaryTypes")->GetText()); + const auto boundaryTypes = readStreamToContainer<std::vector<int>>(boundaryData); + + std::copy(boundaryTypes.begin(), boundaryTypes.end(), std::ostream_iterator<int>(std::cout, " ")); + std::cout << "\n" << std::endl; + } + + return 0; +}