diff --git a/dumux/material/components/air.hh b/dumux/material/components/air.hh index 6b49313dc1c50b9b9235b401bd143b9cc787b646..ae0264b97b573549bfa3b2e97c39a76aecfb1092 100644 --- a/dumux/material/components/air.hh +++ b/dumux/material/components/air.hh @@ -40,7 +40,8 @@ namespace Components { * \tparam Scalar The type used for scalar values */ template <class Scalar> -class Air : public Component<Scalar, Air<Scalar> > +class Air : public Components::Base<Scalar, Air<Scalar> >, + public Components::Gas<Scalar, Air<Scalar> > { using IdealGas = Dumux::IdealGas<Scalar>; diff --git a/dumux/material/components/base.hh b/dumux/material/components/base.hh index 8605839dab351c5a19b36e80e60a8bd1f560bb63..48213dd5b5b9f7faf58cb3098da6532129c4009c 100644 --- a/dumux/material/components/base.hh +++ b/dumux/material/components/base.hh @@ -39,11 +39,16 @@ namespace Dumux { namespace Components { -template <class Scalar, class Implementation> +template <class ScalarType, class Component> class Base { public: - static const bool isTabulated = false; + + //! export the scalar type used by the component + using Scalar = ScalarType; + + //! if the component relies on tabulated values + static constexpr bool isTabulated = false; /*! * \brief A default routine for initialization, not needed for components and must not be called. @@ -65,7 +70,7 @@ public: * \brief A human readable name for the component. * \note Mandatory for all components */ - template<class C = Implementation> + template<class C = Component> static std::string name() { static_assert(AlwaysFalse<C>::value, "Mandatory function not implemented: name()"); @@ -75,7 +80,7 @@ public: /*! * \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of the component. */ - template<class C = Implementation> + template<class C = Component> static constexpr Scalar molarMass() { static_assert(AlwaysFalse<C>::value, "Mandatory function not implemented: molarMass()"); @@ -85,7 +90,7 @@ public: /*! * \brief Returns the critical temperature in \f$\mathrm{[K]}\f$ of the component. */ - template<class C = Implementation> + template<class C = Component> static constexpr Scalar criticalTemperature() { static_assert(AlwaysFalse<C>::value, "Mandatory function not implemented: criticalTemperature()"); @@ -95,7 +100,7 @@ public: /*! * \brief Returns the critical pressure in \f$\mathrm{[Pa]}\f$ of the component. */ - template<class C = Implementation> + template<class C = Component> static constexpr Scalar criticalPressure() { static_assert(AlwaysFalse<C>::value, "Mandatory function not implemented: criticalPressure()"); @@ -105,7 +110,7 @@ public: /*! * \brief Returns the temperature in \f$\mathrm{[K]}\f$ at the component's triple point. */ - template<class C = Implementation> + template<class C = Component> static constexpr Scalar tripleTemperature() { static_assert(AlwaysFalse<C>::value, "Mandatory function not implemented: tripleTemperature()"); @@ -115,7 +120,7 @@ public: /*! * \brief Returns the pressure in \f$\mathrm{[Pa]}\f$ at the component's triple point. */ - template<class C = Implementation> + template<class C = Component> static constexpr Scalar triplePressure() { static_assert(AlwaysFalse<C>::value, "Mandatory function not implemented: triplePressure()"); @@ -128,7 +133,7 @@ public: * * \param T temperature of the component in \f$\mathrm{[K]}\f$ */ - template<class C = Implementation> + template<class C = Component> static Scalar vaporPressure(Scalar t) { static_assert(AlwaysFalse<C>::value, "Mandatory function not implemented: vaporPressure(t)"); diff --git a/dumux/material/components/componenttraits.hh b/dumux/material/components/componenttraits.hh new file mode 100644 index 0000000000000000000000000000000000000000..27cfa721b5dca13ecb5fb0b73fa6ac1a5291b6d8 --- /dev/null +++ b/dumux/material/components/componenttraits.hh @@ -0,0 +1,53 @@ +// -*- 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 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 + * \ingroup Components + * \brief Component traits, i.e. information extracted from components + */ +#ifndef DUMUX_COMPONENT_TRAITS_HH +#define DUMUX_COMPONENT_TRAITS_HH + +#include <type_traits> + +#include <dumux/material/components/solid.hh> +#include <dumux/material/components/liquid.hh> +#include <dumux/material/components/gas.hh> + +namespace Dumux { + +template<class Component> +struct ComponentTraits +{ + using Scalar = typename Component::Scalar; + + //! if the component implements a solid state + static constexpr bool hasSolidState = std::is_base_of<Components::Solid<Scalar, Component>, Component>::value; + + //! if the component implements a liquid state + static constexpr bool hasLiquidState = std::is_base_of<Components::Liquid<Scalar, Component>, Component>::value; + + //! if the component implements a gaseous state + static constexpr bool hasGasState = std::is_base_of<Components::Gas<Scalar, Component>, Component>::value; +}; + +} // end namespace Dumux + +#endif diff --git a/dumux/material/components/gas.hh b/dumux/material/components/gas.hh index 821f4173b8bb7278aa71d75e7cd470386de833b6..0dea8837a51be446067dbd08899d07328fdafed8 100644 --- a/dumux/material/components/gas.hh +++ b/dumux/material/components/gas.hh @@ -36,12 +36,6 @@ template<class Scalar, class Component> class Gas { public: - /*! - * \brief the component has a gas state if it derives from Gas - */ - static constexpr bool hasGasState() - { return true; } - /*! * \brief Returns true if the gas phase is assumed to be compressible */ diff --git a/dumux/material/components/liquid.hh b/dumux/material/components/liquid.hh index 6738635c8a514f8bf24f06fb2a992f27f6fe254f..171cae6a692880405d8e0e8b1d86921cedca7783 100644 --- a/dumux/material/components/liquid.hh +++ b/dumux/material/components/liquid.hh @@ -36,12 +36,6 @@ template<class Scalar, class Component> class Liquid { public: - /*! - * \brief the component has a liquid state if it derives from Liquid - */ - static constexpr bool hasLiquidState() - { return true; } - /*! * \brief Returns true if the liquid phase is assumed to be compressible */ diff --git a/dumux/material/components/solid.hh b/dumux/material/components/solid.hh index 84b9a3b314f7bb2aeafd343909a736f8fd4466a1..62bb74099bdfee762f7800870bcbfa1c1aaf279b 100644 --- a/dumux/material/components/solid.hh +++ b/dumux/material/components/solid.hh @@ -36,12 +36,6 @@ template<class Scalar, class Component> class Solid { public: - /*! - * \brief the component has a solid state if it derives from Solid - */ - static constexpr bool hasSolidState() - { return true; } - /*! * \brief Returns true if the solid phase is assumed to be compressible */ diff --git a/test/material/components/CMakeLists.txt b/test/material/components/CMakeLists.txt index ee9e5e00d3462825e572d72878a767f75681e1fa..3ca8fcc7aad34a43c05124d5b0bf989be870b06c 100644 --- a/test/material/components/CMakeLists.txt +++ b/test/material/components/CMakeLists.txt @@ -1,3 +1,6 @@ +dune_add_test(SOURCES test_componenttraits.cc + COMPILE_ONLY) + add_executable(plot_component plotproperties.cc) dune_add_test(NAME plot_air diff --git a/test/material/components/plotproperties.cc b/test/material/components/plotproperties.cc index 51908570a6299a91d1859f2b6d33c9eba8d9e3f9..09b9cf2d490cace4722878b8cdac34377764fbac 100644 --- a/test/material/components/plotproperties.cc +++ b/test/material/components/plotproperties.cc @@ -46,6 +46,7 @@ #include <dumux/material/components/simpleh2o.hh> #include <dumux/material/components/trichloroethene.hh> #include <dumux/material/components/xylene.hh> +#include <dumux/material/components/componenttraits.hh> using namespace std; using namespace Dumux; @@ -108,7 +109,7 @@ void plot(Functor&& f, //! Plot properties if overloads compile template<class C, class hasNoDensityOverload = checkLiqDen> auto plotLiquidDensity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoDensityOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoDensityOverload{})(declval<C>()))::value && ComponentTraits<C>::hasLiquidState, void> { auto f = [] (auto T, auto p) { return C::liquidDensity(T, p); }; plot(f, T, p, C::name(), "liquid", "density", "[kg/^3]", openPlot); @@ -116,7 +117,7 @@ auto plotLiquidDensity(const vector<double>& T, double p, bool openPlot) template<class C, class hasNoEnthalpyOverload = checkLiqEnth> auto plotLiquidEnthalpy(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoEnthalpyOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoEnthalpyOverload{})(declval<C>()))::value && ComponentTraits<C>::hasLiquidState, void> { auto f = [] (auto T, auto p) { return C::liquidEnthalpy(T, p); }; plot(f, T, p, C::name(), "liquid", "enthalpy", "[J/(kg)]", openPlot); @@ -124,7 +125,7 @@ auto plotLiquidEnthalpy(const vector<double>& T, double p, bool openPlot) template<class C, class hasNoHeatCapOverload = checkLiqHeatCap> auto plotLiquidHeatCapacity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoHeatCapOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoHeatCapOverload{})(declval<C>()))::value && ComponentTraits<C>::hasLiquidState, void> { auto f = [] (auto T, auto p) { return C::liquidHeatCapacity(T, p); }; plot(f, T, p, C::name(), "liquid", "heat capacity", "[J/(kg*K)]", openPlot); @@ -132,7 +133,7 @@ auto plotLiquidHeatCapacity(const vector<double>& T, double p, bool openPlot) template<class C, class hasNoViscOverload = checkLiqVisc> auto plotLiquidViscosity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoViscOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoViscOverload{})(declval<C>()))::value && ComponentTraits<C>::hasLiquidState, void> { auto f = [] (auto T, auto p) { return C::liquidViscosity(T, p); }; plot(f, T, p, C::name(), "liquid", "viscosity", "[Pa*s]", openPlot); @@ -140,7 +141,7 @@ auto plotLiquidViscosity(const vector<double>& T, double p, bool openPlot) template<class C, class hasNoThermCondOverload = checkLiqThermCond> auto plotLiquidThermalConductivity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoThermCondOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoThermCondOverload{})(declval<C>()))::value && ComponentTraits<C>::hasLiquidState, void> { auto f = [] (auto T, auto p) { return C::liquidThermalConductivity(T, p); }; plot(f, T, p, C::name(), "liquid", "thermal conductivity", "[J/(kg*K)]", openPlot); @@ -148,7 +149,7 @@ auto plotLiquidThermalConductivity(const vector<double>& T, double p, bool openP template<class C, class hasNoDensityOverload = checkGasDen> auto plotGasDensity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoDensityOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoDensityOverload{})(declval<C>()))::value && ComponentTraits<C>::hasGasState, void> { auto f = [] (auto T, auto p) { return C::gasDensity(T, p); }; plot(f, T, p, C::name(), "gas", "density", "[kg/^3]", openPlot); @@ -156,7 +157,7 @@ auto plotGasDensity(const vector<double>& T, double p, bool openPlot) template<class C, class hasNoEnthalpyOverload = checkGasEnth> auto plotGasEnthalpy(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoEnthalpyOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoEnthalpyOverload{})(declval<C>()))::value && ComponentTraits<C>::hasGasState, void> { auto f = [] (auto T, auto p) { return C::gasEnthalpy(T, p); }; plot(f, T, p, C::name(), "gas", "enthalpy", "[J/(kg)]", openPlot); @@ -164,7 +165,7 @@ auto plotGasEnthalpy(const vector<double>& T, double p, bool openPlot) template<class C, class hasNoHeatCapOverload = checkGasHeatCap> auto plotGasHeatCapacity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoHeatCapOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoHeatCapOverload{})(declval<C>()))::value && ComponentTraits<C>::hasGasState, void> { auto f = [] (auto T, auto p) { return C::gasHeatCapacity(T, p); }; plot(f, T, p, C::name(), "gas", "heat capacity", "[J/(kg*K)]", openPlot); @@ -172,7 +173,7 @@ auto plotGasHeatCapacity(const vector<double>& T, double p, bool openPlot) template<class C, class hasNoViscOverload = checkGasVisc> auto plotGasViscosity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoViscOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoViscOverload{})(declval<C>()))::value && ComponentTraits<C>::hasGasState, void> { auto f = [] (auto T, auto p) { return C::gasViscosity(T, p); }; plot(f, T, p, C::name(), "gas", "viscosity", "[Pa*s]", openPlot); @@ -180,7 +181,7 @@ auto plotGasViscosity(const vector<double>& T, double p, bool openPlot) template<class C, class hasNoThermCondOverload = checkGasThermCond> auto plotGasThermalConductivity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<!decltype(isValid(hasNoThermCondOverload{})(declval<C>()))::value, void> +-> typename std::enable_if_t<!decltype(isValid(hasNoThermCondOverload{})(declval<C>()))::value && ComponentTraits<C>::hasGasState, void> { auto f = [] (auto T, auto p) { return C::gasThermalConductivity(T, p); }; plot(f, T, p, C::name(), "gas", "thermal conductivity", "[J/(kg*K)]", openPlot); @@ -189,43 +190,43 @@ auto plotGasThermalConductivity(const vector<double>& T, double p, bool openPlot //! Do not plot properties if overloads don't compile template<class C, class hasNoDensityOverload = checkLiqDen> auto plotLiquidDensity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoDensityOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoDensityOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasLiquidState, void> {} template<class C, class hasNoEnthalpyOverload = checkLiqEnth> auto plotLiquidEnthalpy(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoEnthalpyOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoEnthalpyOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasLiquidState, void> {} template<class C, class hasNoHeatCapOverload = checkLiqHeatCap> auto plotLiquidHeatCapacity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoHeatCapOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoHeatCapOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasLiquidState, void> {} template<class C, class hasNoViscOverload = checkLiqVisc> auto plotLiquidViscosity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoViscOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoViscOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasLiquidState, void> {} template<class C, class hasNoThermCondOverload = checkLiqThermCond> auto plotLiquidThermalConductivity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoThermCondOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoThermCondOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasLiquidState, void> {} template<class C, class hasNoDensityOverload = checkGasDen> auto plotGasDensity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoDensityOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoDensityOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasGasState, void> {} template<class C, class hasNoEnthalpyOverload = checkGasEnth> auto plotGasEnthalpy(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoEnthalpyOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoEnthalpyOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasGasState, void> {} template<class C, class hasNoHeatCapOverload = checkGasHeatCap> auto plotGasHeatCapacity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoHeatCapOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoHeatCapOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasGasState, void> {} template<class C, class hasNoViscOverload = checkGasVisc> auto plotGasViscosity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoViscOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoViscOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasGasState, void> {} template<class C, class hasNoThermCondOverload = checkGasThermCond> auto plotGasThermalConductivity(const vector<double>& T, double p, bool openPlot) --> typename std::enable_if_t<decltype(isValid(hasNoThermCondOverload{})(declval<C>()))::value, void> {} +-> typename std::enable_if_t<decltype(isValid(hasNoThermCondOverload{})(declval<C>()))::value || !ComponentTraits<C>::hasGasState, void> {} //! a number of properties of a component template<class Component> diff --git a/test/material/components/test_componenttraits.cc b/test/material/components/test_componenttraits.cc new file mode 100644 index 0000000000000000000000000000000000000000..976370946ab7416229b73a7f8e724258de2a97c9 --- /dev/null +++ b/test/material/components/test_componenttraits.cc @@ -0,0 +1,41 @@ +// -*- 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 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 Test the compoent traits + */ + +#include "config.h" + +#include <type_traits> + +#include <dumux/material/components/air.hh> +#include <dumux/material/components/componenttraits.hh> + +int main(int argc, char *argv[]) +{ + using namespace Dumux; + + using Traits = ComponentTraits<Components::Air<double>>; + static_assert(Traits::hasGasState, "Air component is reported to have no gas state?!"); + static_assert(!Traits::hasSolidState, "Air component is reported to implement a solid state?!"); + static_assert(!Traits::hasLiquidState, "Air component is reported to implement a liquid state?!"); + static_assert(std::is_same<double, Traits::Scalar>::value, "Scalar type not correctly reported!"); +}