diff --git a/opm/core/props/IncompPropertiesShadow.hpp b/opm/core/props/IncompPropertiesShadow.hpp new file mode 100644 index 000000000..d0826af28 --- /dev/null +++ b/opm/core/props/IncompPropertiesShadow.hpp @@ -0,0 +1,207 @@ +/* Copyright (c) 2013 Uni Research AS. + This file is licensed under the GNU General Public License v3.0 or later. */ +#ifndef OPM_INCOMPPROPERTIESSHADOW_HEADER_INCLUDED +#define OPM_INCOMPPROPERTIESSHADOW_HEADER_INCLUDED + +#ifndef OPM_INCOMPPROPERTIESINTERFACE_HEADER_INCLUDED +#include +#endif /* OPM_INCOMPPROPERTIESINTERFACE_HEADER_INCLUDED */ + +namespace Opm +{ + /** + * Override certain properties with values from elsewhere. + * + * This allows mixing of property objects from several sources, + * such as rock and fluid properties from a file but unsaturated + * properties from a function. Care must be taken to setup the + * shadowing so no inconsistencies arise. + * + * @remark + * This object is mutable; if you change some properties + * it will affect all clients that have references to it. + * It is thus recommended to only use the mutable portion + * when constructing the object, before passing it to clients. + * + * @example + * @code{.cpp} + * std::vector poro; + * IncompPropertiesFromDeck fromDeck(deck, grid); + * simulate (IncompPropertiesShadow(fromDeck).usePorosity(poro)); + * @endcode + */ + struct IncompPropertiesShadow : public IncompPropertiesInterface + { + /** + * Shadow another set of properties. If no properties are + * overridden, the values from the original will be used. + */ + IncompPropertiesShadow (const IncompPropertiesInterface& original); + + /** + * Implement all methods from the IncompPropertiesInterface. + */ + virtual int numDimensions () const; + virtual int numCells () const; + virtual const double* porosity () const; + virtual const double* permeability () const; + virtual int numPhases () const; + virtual const double* viscosity () const; + virtual const double* density () const; + virtual const double* surfaceDensity () const; + virtual void relperm (const int n, + const double* s, + const int* cells, + double* kr, + double* dkrds) const; + virtual void capPress (const int n, + const double* s, + const int* cells, + double* pc, + double* dpcds) const; + virtual void satRange (const int n, + const int* cells, + double* smin, + double* smax) const; + + /** + * Use a different set of porosities. + * + * @param poro + * Iterator containing new porosity values. It must contain + * numCells() values. + * @return + * A reference to this object, so it can be used for chaining. + * @remark + * This object does *not* assume ownership of the underlaying + * memory nor makes any copies of it. Hence, the calling code + * must manage the array so that it points to valid memory for + * the lifetime of this object. + */ + IncompPropertiesShadow& usePorosity (const double* poro); + IncompPropertiesShadow& usePorosity (const IncompPropertiesInterface& other); + + /** + * Use a different set of permeabilities. + * + * @param perm + * Iterator containing new permeability values. It must contain + * numCells()*numDimensions()*numDimensions() values. + * @return + * A reference to this object, so it can be used for chaining. + * @remark + * This object does *not* assume ownership of the underlaying + * memory nor makes any copies of it. Hence, the calling code + * must manage the array so that it points to valid memory for + * the lifetime of this object. + */ + IncompPropertiesShadow& usePermeability (const double* perm); + IncompPropertiesShadow& usePermeability (const IncompPropertiesInterface& other); + + /** + * Use a different set of viscosities. + * + * @param visc + * Iterator containing new viscosity values. It must contain + * numPhases() values. + * @return + * A reference to this object, so it can be used for chaining. + * @remark + * This object does *not* assume ownership of the underlaying + * memory nor makes any copies of it. Hence, the calling code + * must manage the array so that it points to valid memory for + * the lifetime of this object. + */ + IncompPropertiesShadow& useViscosity (const double* visc); + IncompPropertiesShadow& useViscosity (const IncompPropertiesInterface& other); + + /** + * Use a different set of densities. + * + * @param dens + * Iterator containing new density values. It must contain + * numPhases() values. + * @return + * A reference to this object, so it can be used for chaining. + * @remark + * This object does *not* assume ownership of the underlaying + * memory nor makes any copies of it. Hence, the calling code + * must manage the array so that it points to valid memory for + * the lifetime of this object. + */ + IncompPropertiesShadow& useDensity (const double* dens); + IncompPropertiesShadow& useDensity (const IncompPropertiesInterface& other); + + /** + * Use a different set of surface densities. + * + * @param surf + * Iterator containing new surface density values. It must + * contain numPhases() values. + * @return + * A reference to this object, so it can be used for chaining. + * @remark + * This object does *not* assume ownership of the underlaying + * memory nor makes any copies of it. Hence, the calling code + * must manage the array so that it points to valid memory for + * the lifetime of this object. + */ + IncompPropertiesShadow& useSurfaceDensity (const double* surf); + IncompPropertiesShadow& useSurfaceDensity (const IncompPropertiesInterface& other); + + /** + * Convenience method to set both porosity and permeability. + */ + IncompPropertiesShadow& useRockProps (const IncompPropertiesInterface& other); + + /** + * Convenience method to set both viscosity and density. + */ + IncompPropertiesShadow& useFluidProps (const IncompPropertiesInterface& other); + + /** + * Convenience method to set both rock and fluid properties. + */ + IncompPropertiesShadow& useRockAndFluidProps (const IncompPropertiesInterface& other); + + private: + /** + * If we haven't set a property explicitly, then retrieve + * them from this. This is a kind of prototype inheritance, + * hence the name of this field. + */ + const IncompPropertiesInterface& prototype; + + /** + * Bitfield which tells us which properties that has been + * shadowed. The others are retrieved from the original + * interface. + */ + int shadowed; + + /** + * Bits that indicates which fields that has been overridden. + */ + static const int POROSITY = 1 << 1; + static const int PERMEABILITY = 1 << 2; + static const int VISCOSITY = 1 << 3; + static const int DENSITY = 1 << 4; + static const int SURFACE_DENSITY = 1 << 5; + + /** + * Pointers to alternative values. These pointers should only + * be assumed to be valid if the corresponding bit in the mask + * is set. No management is done for the memory this points to! + */ + const double* poro_; + const double* perm_; + const double* visc_; + const double* dens_; + const double* surf_; + }; +} /* namespace Opm */ + +// body of inline methods are defined here: +#include + +#endif /* OPM_INCOMPPROPERTIESSHADOW_HEADER_INCLUDED */ diff --git a/opm/core/props/IncompPropertiesShadow_impl.hpp b/opm/core/props/IncompPropertiesShadow_impl.hpp new file mode 100644 index 000000000..0f2f1ebed --- /dev/null +++ b/opm/core/props/IncompPropertiesShadow_impl.hpp @@ -0,0 +1,192 @@ +/* Copyright (c) 2013 Uni Research AS. + This file is licensed under the GNU General Public License v3.0 or later. */ +#ifndef OPM_INCOMPPROPERTIESSHADOW_HEADER_INCLUDED +#error Do not include IncompPropertiesShadow_impl.hpp directly! +#endif /* OPM_INCOMPPROPERTIESSHADOW_HEADER_INCLUDED */ + +namespace Opm +{ + /** + * Initialize so that all properties are retrieved from original. + */ + inline IncompPropertiesShadow::IncompPropertiesShadow (const IncompPropertiesInterface& original) + : prototype (original) + , shadowed (0) + , poro_ (0) + , perm_ (0) + , visc_ (0) + , dens_ (0) + , surf_ (0) + { + } + + /** + * The format of the prototype and the shadow must be the same, + * so these methods should always be forwarded directly. + */ + inline int IncompPropertiesShadow::numDimensions () const + { + return prototype.numDimensions(); + } + + inline int IncompPropertiesShadow::numCells () const + { + return prototype.numCells(); + } + + inline int IncompPropertiesShadow::numPhases () const + { + return prototype.numPhases(); + } + + /** + * These methods are sufficiently advanced (the s parameter is a + * non-integral index) for there not to be a trivial implementation, + * so they are not overridden yet. + */ + inline void IncompPropertiesShadow::relperm (const int n, + const double* s, + const int* cells, + double* kr, + double* dkrds) const + { + prototype.relperm (n, s, cells, kr, dkrds); + } + + inline void IncompPropertiesShadow::capPress (const int n, + const double* s, + const int* cells, + double* pc, + double* dpcds) const + { + prototype.capPress (n, s, cells, pc, dpcds); + } + + inline void IncompPropertiesShadow::satRange (const int n, + const int* cells, + double* smin, + double* smax) const + { + prototype.satRange (n, cells, smin, smax); + } + + /** + * Return the new value if indicated in the bitfield, otherwise + * use the original value from the other object. + */ + inline const double* IncompPropertiesShadow::porosity () const + { + return (shadowed & POROSITY) ? poro_ : prototype.porosity (); + } + + inline const double* IncompPropertiesShadow::permeability () const + { + return (shadowed & PERMEABILITY) ? perm_ : prototype.permeability (); + } + + inline const double* IncompPropertiesShadow::viscosity () const + { + return (shadowed & VISCOSITY) ? visc_ : prototype.viscosity (); + } + + inline const double* IncompPropertiesShadow::density () const + { + return (shadowed & DENSITY) ? dens_ : prototype.density (); + } + + inline const double* IncompPropertiesShadow::surfaceDensity () const + { + return (shadowed & SURFACE_DENSITY) ? surf_ : prototype.surfaceDensity (); + } + + /** + * Store the pointer and indicate that the new value should be used. + */ + inline IncompPropertiesShadow& IncompPropertiesShadow::usePorosity (const double* poro) + { + this->poro_ = poro; + shadowed |= POROSITY; + return *this; + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::usePermeability (const double* perm) + { + this->perm_ = perm; + shadowed |= PERMEABILITY; + return *this; + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::useViscosity (const double* visc) + { + this->visc_ = visc; + shadowed |= VISCOSITY; + return *this; + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::useDensity (const double* dens) + { + this->dens_ = dens; + shadowed |= DENSITY; + return *this; + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::useSurfaceDensity (const double* surf) + { + this->surf_ = surf; + shadowed |= SURFACE_DENSITY; + return *this; + } + + /** + * Copy the pointer from another property interface, after checking + * that they are compatible. + */ + inline IncompPropertiesShadow& IncompPropertiesShadow::usePorosity (const IncompPropertiesInterface& other) + { + assert (prototype.numCells() == other.numCells()); + return usePorosity (other.porosity()); + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::usePermeability (const IncompPropertiesInterface& other) + { + assert (prototype.numCells() == other.numCells()); + assert (prototype.numDimensions() == other.numDimensions()); + return usePermeability (other.permeability()); + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::useViscosity (const IncompPropertiesInterface& other) + { + assert (prototype.numPhases() == other.numPhases()); + return useViscosity (other.viscosity()); + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::useDensity (const IncompPropertiesInterface& other) + { + assert (prototype.numPhases() == other.numPhases()); + return useDensity (other.density()); + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::useSurfaceDensity (const IncompPropertiesInterface& other) + { + assert (prototype.numPhases() == other.numPhases()); + return useSurfaceDensity (other.surfaceDensity()); + } + + /** + * Convenience methods to set several set of properties at once. + */ + inline IncompPropertiesShadow& IncompPropertiesShadow::useRockProps (const IncompPropertiesInterface& other) + { + return usePorosity (other).usePermeability (other); + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::useFluidProps (const IncompPropertiesInterface& other) + { + return useViscosity (other).useDensity (other).useSurfaceDensity (other); + } + + inline IncompPropertiesShadow& IncompPropertiesShadow::useRockAndFluidProps (const IncompPropertiesInterface& other) + { + return useRockProps (other).useFluidProps (other); + } +} /* namespace Opm */ diff --git a/tests/test_shadow.cpp b/tests/test_shadow.cpp new file mode 100644 index 000000000..f41b32775 --- /dev/null +++ b/tests/test_shadow.cpp @@ -0,0 +1,32 @@ +/* Copyright (c) 2013 Uni Research AS. + This file is licensed under the GNU General Public License v3.0 or later. */ +#include + +#if HAVE_DYNAMIC_BOOST_TEST +#define BOOST_TEST_DYN_LINK +#endif +#define NVERBOSE // to suppress our messages when throwing + +#define BOOST_TEST_MODULE ShadowTest +#include + +#include +#include +#include + +using namespace Opm; + +BOOST_AUTO_TEST_CASE(shadowPorosity) +{ + const double defaultPorosity = 1.0; + const double newPorosity = 0.5; + + parameter::ParameterGroup param; + IncompPropertiesBasic basic (param, 2, 1); + IncompPropertiesShadow shadow (basic); + BOOST_CHECK_CLOSE (*(shadow.porosity()), defaultPorosity, 0.001); + shadow.usePorosity (&newPorosity); + BOOST_CHECK_CLOSE (*(shadow.porosity()), newPorosity, 0.001); + shadow.usePorosity (basic); + BOOST_CHECK_CLOSE (*(shadow.porosity()), defaultPorosity, 0.001); +}