diff --git a/dumux/common/basicproperties.hh b/dumux/common/basicproperties.hh index f28fb6848a54eb4f60f1795cab71df80fe7aff21..c2b410fee977d55b9d82ef7a2ac97df2b03a3fa9 100644 --- a/dumux/common/basicproperties.hh +++ b/dumux/common/basicproperties.hh @@ -33,6 +33,7 @@ #include <dumux/common/propertysystem.hh> #include <dumux/common/parameters.hh> +#include <dumux/common/dgfgridcreator.hh> namespace Dumux { @@ -73,6 +74,9 @@ NEW_PROP_TAG(ParameterTree); //! Property which defines the group that is queried for parameters by default NEW_PROP_TAG(ModelParameterGroup); +//! Property which provides a GridCreator (manages grids) +NEW_PROP_TAG(GridCreator); + /////////////////////////////////// // Default values for properties: // @@ -107,9 +111,12 @@ SET_PROP(NumericModel, ParameterTree) }; }; -// use the global group as default for the model's parameter group +//! use the global group as default for the model's parameter group SET_STRING_PROP(NumericModel, ModelParameterGroup, ""); +//! Use the DgfGridCreator by default +SET_TYPE_PROP(NumericModel, GridCreator, Dumux::DgfGridCreator<TypeTag>); + } // namespace Properties } // namespace Dumux diff --git a/dumux/common/dgfgridcreator.hh b/dumux/common/dgfgridcreator.hh new file mode 100644 index 0000000000000000000000000000000000000000..71a7e3c6e30adbbb57f487fb233291b6d9891348 --- /dev/null +++ b/dumux/common/dgfgridcreator.hh @@ -0,0 +1,88 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * Copyright (C) 2012 by Andreas Lauser * + * Institute of Hydraulic Engineering * + * University of Stuttgart, Germany * + * email: <givenname>.<name>@iws.uni-stuttgart.de * + * * + * 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 2 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 Provides a grid creator which reads Dune Grid Format (DGF) files + */ +#ifndef DUMUX_DGF_GRID_CREATOR_HH +#define DUMUX_DGF_GRID_CREATOR_HH + +#include <dune/grid/io/file/dgfparser.hh> + +#include <dumux/common/propertysystem.hh> +#include <dumux/common/parameters.hh> + +namespace Dumux +{ +namespace Properties +{ +NEW_PROP_TAG(Grid); +} + +/*! + * \brief Provides a grid creator which reads Dune Grid Format (DGF) files + */ +template <class TypeTag> +class DgfGridCreator +{ + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef Dune::GridPtr<Grid> GridPointer; + +public: + /*! + * \brief Load the grid from the file. + */ + static void makeGrid() + { + const std::string dgfFileName = GET_RUNTIME_PARAM(TypeTag, std::string, DgfFile); + + gridPtr_ = GridPointer(dgfFileName.c_str()); + }; + + /*! + * \brief Returns a reference to the grid. + */ + static Grid &grid() + { + return *gridPtr_; + }; + + /*! + * \brief Returns a reference to the grid pointer. + * + * This method is specific to the DgfGridCreator! + */ + static GridPointer &gridPtr() + { + return gridPtr_; + }; + +private: + static GridPointer gridPtr_; +}; + +template <class TypeTag> +typename DgfGridCreator<TypeTag>::GridPointer DgfGridCreator<TypeTag>::gridPtr_; + +} // namespace Dumux + +#endif diff --git a/dumux/common/start.hh b/dumux/common/start.hh index b116b8fd9df93ae46016aefdbdb9b442311cee51..4dd073b8bc4f5ee6a6081b7b8a0c23e6b9f53218 100644 --- a/dumux/common/start.hh +++ b/dumux/common/start.hh @@ -36,12 +36,15 @@ #include <dune/common/version.hh> #include <dune/common/parametertreeparser.hh> +#include <sys/ptrace.h> + namespace Dumux { // forward declaration of property tags namespace Properties { NEW_PROP_TAG(Grid); +NEW_PROP_TAG(GridCreator); NEW_PROP_TAG(Problem); NEW_PROP_TAG(TimeManager); } @@ -239,113 +242,247 @@ int startWithGrid(const typename GET_PROP_TYPE(TypeTag, Grid) &grid, return 3; } +std::string readOptions_(int argc, char **argv, Dune::ParameterTree ¶mTree) +{ + for (int i = 1; i < argc; ++i) { + if (argv[i][0] != '-') { + std::ostringstream oss; + oss << "Command line argument " << i << " (='" << argv[i] << "') is invalid."; + return oss.str(); + } + + std::string paramName, paramValue; + + if (argv[i][1] == '-') { + // read a --my-opt=abc option. This gets transformed + // into the parameter "MyOpt" with the value being + // "abc" + std::string s(argv[i] + 2); + if (s.size() == 0 || s[0] == '=') + { + std::ostringstream oss; + oss << "Parameter name of argument " << i << " (='" << argv[i] << "')" + << " is empty."; + return oss.str(); + } + + + // capitalize first letter + s[0] = std::toupper(s[0]); + + // parse argument + int j = 0; + while (true) { + if (j >= s.size()) { + // encountered the end of the string, i.e. we + // have a parameter where the argument is empty + paramName = s; + paramValue = ""; + break; + } + else if (s[j] == '=') { + // we encountered a '=' character. everything + // before is the name of the parameter, + // everything after is the value. + paramName = s.substr(0, j); + paramValue = s.substr(j+1); + break; + } + else if (s[j] == '-') { + // remove all "-" characters and capitalize the + // character after them + s.erase(j, 1); + if (s.size() == j) + { + std::ostringstream oss; + oss << "Parameter name of argument " << i << " (='" << argv[i] << "')" + << " is invalid (ends with a '-' character)."; + return oss.str(); + } + else if (s[j] == '-') + { + std::ostringstream oss; + oss << "Malformed parameter name name in argument " << i << " (='" << argv[i] << "'): " + << "'--' in parameter name."; + return oss.str(); + } + s[j] = toupper(s[j]); + }; + + ++j; + } + } + else { + // read a -MyOpt abc option + paramName = argv[i] + 2; + + if (argc == i + 1 || argv[i+1][0] == '-') { + std::ostringstream oss; + oss << "No argument given for parameter '" << argv[i] << "'!"; + return oss.str(); + } + + paramValue = argv[i+1]; + ++i; + } + + // Put the key=value pair into the parameter tree + paramTree[paramName] = paramValue; + } + return ""; +} + +template <class TypeTag> +int startWithParameters_(int argc, + char **argv, + void (*usage)(const char *, const std::string &)) +{ + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename GET_PROP_TYPE(TypeTag, GridCreator) GridCreator; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + + // initialize MPI, finalize is done automatically on exit + const Dune::MPIHelper &mpiHelper = Dune::MPIHelper::instance(argc, argv); + + //////////////////////////////////////////////////////////// + // parse the command line arguments + //////////////////////////////////////////////////////////// + + // check whether the user did not specify any parameter. in this + // case print the usage message + if (argc == 1) { + usage(argv[0], ""); + return 0; + } + + + // check whether the user wanted to see the help message + for (int i = 1; i < argc; ++i) { + if (std::string("--help") == argv[i] || std::string("-h") == argv[i]) + { + usage(argv[0], ""); + return 0; + } + } + + // fill the parameter tree with the options from the command line + typedef typename GET_PROP(TypeTag, ParameterTree) Params; + std::string s = readOptions_(argc, argv, Params::tree()); + if (!s.empty()) { + usage(argv[0], s); + return 1; + }; + + if (Params::tree().hasKey("OptsFile")) { + // read input file, but do not overwrite options specified + // on the command line, since the latter have preceedence. + std::string inputFileName = GET_RUNTIME_PARAM(TypeTag, std::string, OptsFile); + Dune::ParameterTreeParser::readINITree(inputFileName, + Params::tree(), + /*overwrite=*/false); + } + + + bool printProps = true; + if (Params::tree().hasKey("PrintProperties")) + printProps = GET_RUNTIME_PARAM(TypeTag, bool, PrintProperies); + + if (printProps && mpiHelper.rank() == 0) { + Dumux::Properties::print<TypeTag>(); + } + + // deal with the restart stuff + bool restart = false; + Scalar restartTime = 0; + if (Params::tree().hasKey("Restart")) { + restart = true; + restartTime = GET_RUNTIME_PARAM(TypeTag, Scalar, Restart); + } + + // read the PrintParams parameter + bool printParams = true; + if (Params::tree().hasKey("PrintParameters")) + printParams = GET_RUNTIME_PARAM(TypeTag, bool, PrintParameters); + + try { GridCreator::makeGrid(); } + catch (...) { usage(argv[1], "Creation of the grid failed!"); throw; } + + // read the initial time step and the end time + double tEnd; + double dt; + + try { tEnd = GET_RUNTIME_PARAM(TypeTag, Scalar, TEnd); } + catch (...) { usage(argv[1], "Mandatory parameter '--t-end' not specified!"); throw; } + + try { dt = GET_RUNTIME_PARAM(TypeTag, Scalar, DtInitial); } + catch (...) { usage(argv[1], "Mandatory parameter '--dt-initial' not specified!"); throw; } + + // instantiate and run the concrete problem + TimeManager timeManager; + Problem problem(timeManager); + timeManager.init(problem, 0, dt, tEnd, restart); + if (restart) + problem.restart(restartTime); + timeManager.run(); + + if (printParams && mpiHelper.rank() == 0) { + Dumux::Parameters::print<TypeTag>(); + } + + return 0; +} + /*! * \ingroup Start - * \brief Provides a default main function for simulations requiring - * only a single DGF file as their grid specification. + * + * \brief Returns true if and only if a debugger is attached to the simulation. + */ +bool inDebugger() +{ + return ptrace(PTRACE_TRACEME, 0, NULL, 0) == -1; +} + + +/*! + * \ingroup Start + * + * \brief Provides a main function which reads in parameters from the + * command line and a parameter file. * * \tparam TypeTag The type tag of the problem which needs to be solved * - * \param argc The 'argc' argument of the main function - * \param argv The 'argv' argument of the main function + * \param argc The number of command line arguments of the program + * \param argv The contents of the command line arguments of the program + * \param usage Callback function for printing the usage message */ template <class TypeTag> -int startFromInputFile(int argc, char **argv) +int startWithParameters(int argc, + char **argv, + void (*usage)(const char *, const std::string &)) { -#ifdef NDEBUG - try { -#endif - - typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; - typedef typename GET_PROP(TypeTag, ParameterTree) Params; - typedef Dune::GridPtr<Grid> GridPointer; - - // initialize MPI, finalize is done automatically on exit - static Dune::MPIHelper& mpiHelper = Dune::MPIHelper::instance(argc, argv); - - // parse the command line arguments for the program - if (argc < 2) - printUsageInputFile(argv[0]); - - // deal with the restart stuff - int argIdx = 1; - bool restart = false; - double startTime = 0; - if (std::string("--restart") == argv[argIdx]) { - restart = true; - ++argIdx; - - std::istringstream(argv[argIdx++]) >> startTime; - } - - if (argc - argIdx != 1) { - printUsageInputFile(argv[0]); - } - - std::string inputFileName; - std::istringstream(argv[argIdx++]) >> inputFileName; - - //////////////////////////////////////////////////////////// - // Load the input parameters - //////////////////////////////////////////////////////////// - Dune::ParameterTreeParser::readINITree(inputFileName, Params::tree()); - Params::tree().report(); - - double tEnd = Params::tree().template get<double>("SimulationControl.tEnd", -1.0); - if (tEnd < 0) - DUNE_THROW(Dune::IOError, "no end time SimulationControl.tEnd" - << " specified in parameter file " << inputFileName); - - double dt = Params::tree().template get<double>("SimulationControl.tIni", -1.0); - if (dt < 0) - DUNE_THROW(Dune::IOError, "no initial time step SimulationControl.tIni" - << " specified in parameter file " << inputFileName); - - const std::string dgfFileName = - Params::tree().template get<std::string>("SimulationControl.gridName", ""); - if (dgfFileName == "") - DUNE_THROW(Dune::IOError, "no DGF file name SimulationControl.gridName" - << " specified in parameter file " << inputFileName); - - // create grid - // -> load the grid from file - GridPointer gridPtr(dgfFileName); - if (mpiHelper.size() > 1) { - if (!Dune::Capabilities::isParallel<Grid>::v) { - std::cerr << "DUMUX WARNING: THE PROGRAM IS STARTED USING MPI, BUT THE GRID IMPLEMENTATION\n" - << " YOU HAVE CHOSEN IS NOT PARALLEL!\n"; - } - gridPtr.loadBalance(); - } - - // instantiate and run the concrete problem - TimeManager timeManager; - Problem problem(timeManager, - gridPtr->leafView(), - Params::tree()); - timeManager.init(problem, startTime, dt, tEnd, restart); - - // print all properties - Dumux::Properties::print<TypeTag>(); - - timeManager.run(); - return 0; - -#ifdef NDEBUG - } - catch (Dune::Exception &e) { - std::cerr << "Dune reported error: " << e << std::endl; - } - catch (...) { - std::cerr << "Unknown exception thrown!\n"; - } -#endif - - return 3; + if (!inDebugger()) { + try { + return startWithParameters_<TypeTag>(argc, argv, usage); + } + catch (Dumux::ParameterException &e) { + std::cerr << e << ". Abort!\n"; + return 1; + } + catch (Dune::Exception &e) { + std::cerr << "Dune reported error: " << e << std::endl; + return 2; + } + catch (...) { + std::cerr << "Unknown exception thrown!\n"; + return 3; + } + } + else + return startWithParameters_<TypeTag>(argc, argv, usage); } -} +} // namespace Dumux #endif diff --git a/test/boxmodels/2p2c/injectionproblem.hh b/test/boxmodels/2p2c/injectionproblem.hh index d63c42861e92c28209fc80484dfecd361ffcba20..d22f5e5217f729d8852c80cb90a4b90fa12e70df 100644 --- a/test/boxmodels/2p2c/injectionproblem.hh +++ b/test/boxmodels/2p2c/injectionproblem.hh @@ -135,6 +135,7 @@ class InjectionProblem : public TwoPTwoCProblem<TypeTag> typedef typename GridView::Intersection Intersection; typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, GridCreator) GridCreator; typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; @@ -145,8 +146,8 @@ public: * \param timeManager The time manager * \param gridView The grid view */ - InjectionProblem(TimeManager &timeManager, const GridView &gridView) - : ParentType(timeManager, gridView) + InjectionProblem(TimeManager &timeManager) + : ParentType(timeManager, GridCreator::grid().leafView()) { temperature_ = 273.15 + 40; // [K] depthBOR_ = 2700.0; // [m] diff --git a/test/boxmodels/2p2c/test_2p2c.cc b/test/boxmodels/2p2c/test_2p2c.cc index 5d6385b8ee22dd65c6da2aad08611e43aa4c5b15..841beb724b54da458d67cbf5159fd121cc8539b1 100644 --- a/test/boxmodels/2p2c/test_2p2c.cc +++ b/test/boxmodels/2p2c/test_2p2c.cc @@ -1,7 +1,7 @@ // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /***************************************************************************** - * Copyright (C) 2008 by Klaus Mosthaf * + * Copyright (C) 2008-2012 by Andreas Lauser * * Institute of Hydraulic Engineering * * University of Stuttgart, Germany * * email: <givenname>.<name>@iws.uni-stuttgart.de * @@ -28,8 +28,37 @@ #include "injectionproblem.hh" #include <dumux/common/start.hh> +void usage(const char *progName, const std::string &errorMsg) +{ + if (errorMsg.size() > 0) { + std::cout << errorMsg << "\n" + << "\n"; + } + std::cout + << "Usage: " << progName << " [options]\n" + << "Mandatory options are:\n" + << "\t--t-end=ENDTIME The time of the end of the simlation [s]\n" + << "\t--dt-initial=STEPSIZE The initial time step size [s]\n" + << "\t--dgf-file=FILENAME The file name of the file containing the grid \n" + << "\t definition in DGF format\n" + << "\n" + << "Important optional options include:\n" + << "\t--help,-h Print this usage message and exit\n" + << "\t--print-parameters[=true|false] Print the run-time modifiable parameters _after_ \n" + << "\t the simulation [default: true]\n" + << "\t--print-properties[=true|false] Print the compile-time parameters _before_ \n" + << "\t the simulation [default: true]\n" + << "\t--opts-file=FILENAME File with parameter definitions\n" + << "\t--restart=RESTARTTIME Restart simulation from a restart file\n" + << "\n" + << "If --opts-file is specified parameters can also be defined there. In this case,\n" + << "camel case is used for the parameters (e.g.: --dgf-file becomes DgfFile). Parameters\n" + << "specified on the command line have priority over those in the option file.\n" + << "\n"; +} + int main(int argc, char** argv) { typedef TTAG(InjectionProblem) ProblemTypeTag; - return Dumux::startFromDGF<ProblemTypeTag>(argc, argv); + return Dumux::startWithParameters<ProblemTypeTag>(argc, argv, usage); } diff --git a/test/boxmodels/2p2c/test_2p2c.opts b/test/boxmodels/2p2c/test_2p2c.opts new file mode 100644 index 0000000000000000000000000000000000000000..c80b46f152f23b6222b713b34755b4518a22e131 --- /dev/null +++ b/test/boxmodels/2p2c/test_2p2c.opts @@ -0,0 +1,3 @@ +DtInitial=250 # seconds +TEnd=1e8 # seconds +DgfFile="grids/test_2p2c.dgf"