// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /* This file is part of the Open Porous Media project (OPM). OPM 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. OPM 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 OPM. If not, see . Consult the COPYING file in the top-level source directory of this module for the precise wording of the license and the list of copyright holders. */ /*! * \file * \copydoc checkFluidSystem */ #ifndef OPM_CHECK_FLUIDSYSTEM_HPP #define OPM_CHECK_FLUIDSYSTEM_HPP #include // include all fluid systems in opm-material #include #include #include #include #include #include #include #include // include all fluid states #include #include #include #include #include #include #include #include #include /*! * \brief This is a fluid state which makes sure that only the quantities * allowed are accessed. */ template > class HairSplittingFluidState : protected BaseFluidState { public: enum { numPhases = FluidSystem::numPhases }; enum { numComponents = FluidSystem::numComponents }; typedef ScalarT Scalar; HairSplittingFluidState() { // initially, do not allow anything allowTemperature(false); allowPressure(false); allowComposition(false); allowDensity(false); // do not allow accessing any phase restrictToPhase(1000); } void allowTemperature(bool yesno) { allowTemperature_ = yesno; } void allowPressure(bool yesno) { allowPressure_ = yesno; } void allowComposition(bool yesno) { allowComposition_ = yesno; } void allowDensity(bool yesno) { allowDensity_ = yesno; } void restrictToPhase(int phaseIdx) { restrictPhaseIdx_ = phaseIdx; } BaseFluidState& base() { return *static_cast(this); } const BaseFluidState& base() const { return *static_cast(this); } auto temperature(unsigned phaseIdx) const -> decltype(this->base().temperature(phaseIdx)) { assert(allowTemperature_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().temperature(phaseIdx); } auto pressure(unsigned phaseIdx) const -> decltype(this->base().pressure(phaseIdx)) { assert(allowPressure_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().pressure(phaseIdx); } auto moleFraction(unsigned phaseIdx, unsigned compIdx) const -> decltype(this->base().moleFraction(phaseIdx, compIdx)) { assert(allowComposition_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().moleFraction(phaseIdx, compIdx); } auto massFraction(unsigned phaseIdx, unsigned compIdx) const -> decltype(this->base().massFraction(phaseIdx, compIdx)) { assert(allowComposition_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().massFraction(phaseIdx, compIdx); } auto averageMolarMass(unsigned phaseIdx) const -> decltype(this->base().averageMolarMass(phaseIdx)) { assert(allowComposition_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().averageMolarMass(phaseIdx); } auto molarity(unsigned phaseIdx, unsigned compIdx) const -> decltype(this->base().molarity(phaseIdx, compIdx)) { assert(allowDensity_ && allowComposition_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().molarity(phaseIdx, compIdx); } auto molarDensity(unsigned phaseIdx) const -> decltype(this->base().molarDensity(phaseIdx)) { assert(allowDensity_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().molarDensity(phaseIdx); } auto molarVolume(unsigned phaseIdx) const -> decltype(this->base().molarVolume(phaseIdx)) { assert(allowDensity_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().molarVolume(phaseIdx); } auto density(unsigned phaseIdx) const -> decltype(this->base().density(phaseIdx)) { assert(allowDensity_); assert(restrictPhaseIdx_ < 0 || restrictPhaseIdx_ == static_cast(phaseIdx)); return this->base().density(phaseIdx); } auto saturation(unsigned phaseIdx) const -> decltype(this->base().saturation(phaseIdx)) { assert(false); return this->base().saturation(phaseIdx); } auto fugacity(unsigned phaseIdx, unsigned compIdx) const -> decltype(this->base().fugacity(phaseIdx, compIdx)) { assert(false); return this->base().fugacity(phaseIdx, compIdx); } auto fugacityCoefficient(unsigned phaseIdx, unsigned compIdx) const -> decltype(this->base().fugacityCoefficient(phaseIdx, compIdx)) { assert(false); return this->base().fugacityCoefficient(phaseIdx, compIdx); } auto enthalpy(unsigned phaseIdx) const -> decltype(this->base().enthalpy(phaseIdx)) { assert(false); return this->base().enthalpy(phaseIdx); } auto internalEnergy(unsigned phaseIdx) const -> decltype(this->base().internalEnergy(phaseIdx)) { assert(false); return this->base().internalEnergy(phaseIdx); } auto viscosity(unsigned phaseIdx) const -> decltype(this->base().viscosity(phaseIdx)) { assert(false); return this->base().viscosity(phaseIdx); } private: bool allowSaturation_; bool allowTemperature_; bool allowPressure_; bool allowComposition_; bool allowDensity_; int restrictPhaseIdx_; }; template void checkFluidState(const BaseFluidState& fs) { // fluid states must be copy-able [[maybe_unused]] BaseFluidState tmpFs(fs); tmpFs = fs; // a fluid state must provide a checkDefined() method fs.checkDefined(); // fluid states must export the types which they use as Scalars typedef typename BaseFluidState::Scalar FsScalar; static_assert(std::is_same::value, "Fluid states must export the type they are given as scalar in an unmodified way"); // make sure the fluid state provides all mandatory methods while (false) { Scalar val = 1.0; val = 2*val; // get rid of GCC warning (only occurs with paranoid warning flags) val = fs.temperature(/*phaseIdx=*/0); val = fs.pressure(/*phaseIdx=*/0); val = fs.moleFraction(/*phaseIdx=*/0, /*compIdx=*/0); val = fs.massFraction(/*phaseIdx=*/0, /*compIdx=*/0); val = fs.averageMolarMass(/*phaseIdx=*/0); val = fs.molarity(/*phaseIdx=*/0, /*compIdx=*/0); val = fs.molarDensity(/*phaseIdx=*/0); val = fs.molarVolume(/*phaseIdx=*/0); val = fs.density(/*phaseIdx=*/0); val = fs.saturation(/*phaseIdx=*/0); val = fs.fugacity(/*phaseIdx=*/0, /*compIdx=*/0); val = fs.fugacityCoefficient(/*phaseIdx=*/0, /*compIdx=*/0); val = fs.enthalpy(/*phaseIdx=*/0); val = fs.internalEnergy(/*phaseIdx=*/0); val = fs.viscosity(/*phaseIdx=*/0); }; } /*! * \brief Checks whether a fluid system adheres to the specification. */ template void checkFluidSystem() { std::cout << "Testing fluid system '" << Opm::demangle(typeid(FluidSystem).name()) << ", RhsEval = " << Opm::demangle(typeid(RhsEval).name()) << ", LhsEval = " << Opm::demangle(typeid(LhsEval).name()) << "'\n"; // make sure the fluid system provides the number of phases and // the number of components enum { numPhases = FluidSystem::numPhases }; enum { numComponents = FluidSystem::numComponents }; typedef HairSplittingFluidState FluidState; FluidState fs; fs.allowTemperature(true); fs.allowPressure(true); fs.allowComposition(true); fs.restrictToPhase(-1); // initialize memory the fluid state fs.base().setTemperature(273.15 + 20.0); for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { fs.base().setPressure(phaseIdx, 1e5); fs.base().setSaturation(phaseIdx, 1.0/numPhases); for (int compIdx = 0; compIdx < numComponents; ++ compIdx) { fs.base().setMoleFraction(phaseIdx, compIdx, 1.0/numComponents); } } static_assert(std::is_same::value, "The type used for floating point used by the fluid system must be the same" " as the one passed to the checkFluidSystem() function"); // check whether the parameter cache adheres to the API typedef typename FluidSystem::template ParameterCache ParameterCache; ParameterCache paramCache; try { paramCache.updateAll(fs); } catch (...) {}; try { paramCache.updateAll(fs, /*except=*/ParameterCache::None); } catch (...) {}; try { paramCache.updateAll(fs, /*except=*/ParameterCache::Temperature | ParameterCache::Pressure | ParameterCache::Composition); } catch (...) {}; try { paramCache.updateAllPressures(fs); } catch (...) {}; for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { fs.restrictToPhase(static_cast(phaseIdx)); try { paramCache.updatePhase(fs, phaseIdx); } catch (...) {}; try { paramCache.updatePhase(fs, phaseIdx, /*except=*/ParameterCache::None); } catch (...) {}; try { paramCache.updatePhase(fs, phaseIdx, /*except=*/ParameterCache::Temperature | ParameterCache::Pressure | ParameterCache::Composition); } catch (...) {}; try { paramCache.updateTemperature(fs, phaseIdx); } catch (...) {}; try { paramCache.updatePressure(fs, phaseIdx); } catch (...) {}; try { paramCache.updateComposition(fs, phaseIdx); } catch (...) {}; try { paramCache.updateSingleMoleFraction(fs, phaseIdx, /*compIdx=*/0); } catch (...) {}; } // some value to make sure the return values of the fluid system // are convertible to scalars LhsEval val = 0.0; Scalar scalarVal = 0.0; scalarVal = 2*scalarVal; // get rid of GCC warning (only occurs with paranoid warning flags) val = 2*val; // get rid of GCC warning (only occurs with paranoid warning flags) // actually check the fluid system API try { FluidSystem::init(); } catch (...) {}; for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { fs.restrictToPhase(static_cast(phaseIdx)); fs.allowPressure(FluidSystem::isCompressible(phaseIdx)); fs.allowComposition(true); fs.allowDensity(false); try { [[maybe_unused]] auto tmpVal = FluidSystem::density(fs, paramCache, phaseIdx); static_assert(std::is_same::value, "The default return value must be the scalar used by the fluid state!"); } catch (...) {}; try { val = FluidSystem::template density(fs, paramCache, phaseIdx); } catch (...) {}; try { scalarVal = FluidSystem::template density(fs, paramCache, phaseIdx); } catch (...) {}; fs.allowPressure(true); fs.allowDensity(true); try { [[maybe_unused]] auto tmpVal = FluidSystem::viscosity(fs, paramCache, phaseIdx); static_assert(std::is_same::value, "The default return value must be the scalar used by the fluid state!"); } catch (...) {}; try { [[maybe_unused]] auto tmpVal = FluidSystem::enthalpy(fs, paramCache, phaseIdx); static_assert(std::is_same::value, "The default return value must be the scalar used by the fluid state!"); } catch (...) {}; try { [[maybe_unused]] auto tmpVal = FluidSystem::heatCapacity(fs, paramCache, phaseIdx); static_assert(std::is_same::value, "The default return value must be the scalar used by the fluid state!"); } catch (...) {}; try { [[maybe_unused]] auto tmpVal = FluidSystem::thermalConductivity(fs, paramCache, phaseIdx); static_assert(std::is_same::value, "The default return value must be the scalar used by the fluid state!"); } catch (...) {}; try { val = FluidSystem::template viscosity(fs, paramCache, phaseIdx); } catch (...) {}; try { val = FluidSystem::template enthalpy(fs, paramCache, phaseIdx); } catch (...) {}; try { val = FluidSystem::template heatCapacity(fs, paramCache, phaseIdx); } catch (...) {}; try { val = FluidSystem::template thermalConductivity(fs, paramCache, phaseIdx); } catch (...) {}; try { scalarVal = FluidSystem::template viscosity(fs, paramCache, phaseIdx); } catch (...) {}; try { scalarVal = FluidSystem::template enthalpy(fs, paramCache, phaseIdx); } catch (...) {}; try { scalarVal = FluidSystem::template heatCapacity(fs, paramCache, phaseIdx); } catch (...) {}; try { scalarVal = FluidSystem::template thermalConductivity(fs, paramCache, phaseIdx); } catch (...) {}; for (unsigned compIdx = 0; compIdx < numComponents; ++ compIdx) { fs.allowComposition(!FluidSystem::isIdealMixture(phaseIdx)); try { [[maybe_unused]] auto tmpVal = FluidSystem::fugacityCoefficient(fs, paramCache, phaseIdx, compIdx); static_assert(std::is_same::value, "The default return value must be the scalar used by the fluid state!"); } catch (...) {}; try { val = FluidSystem::template fugacityCoefficient(fs, paramCache, phaseIdx, compIdx); } catch (...) {}; try { scalarVal = FluidSystem::template fugacityCoefficient(fs, paramCache, phaseIdx, compIdx); } catch (...) {}; fs.allowComposition(true); try { [[maybe_unused]] auto tmpVal = FluidSystem::diffusionCoefficient(fs, paramCache, phaseIdx, compIdx); static_assert(std::is_same::value, "The default return value must be the scalar used by the fluid state!"); } catch (...) {}; try { val = FluidSystem::template diffusionCoefficient(fs, paramCache, phaseIdx, compIdx); } catch (...) {}; try { scalarVal = FluidSystem::template fugacityCoefficient(fs, paramCache, phaseIdx, compIdx); } catch (...) {}; } } // test for phaseName(), isLiquid() and isIdealGas() for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { [[maybe_unused]] std::string name = FluidSystem::phaseName(phaseIdx); bool bVal = FluidSystem::isLiquid(phaseIdx); bVal = FluidSystem::isIdealGas(phaseIdx); bVal = !bVal; // get rid of GCC warning (only occurs with paranoid warning flags) } // test for molarMass() and componentName() for (unsigned compIdx = 0; compIdx < numComponents; ++ compIdx) { val = FluidSystem::molarMass(compIdx); std::string name = FluidSystem::componentName(compIdx); } } #endif