mirror of
https://github.com/OPM/opm-simulators.git
synced 2026-10-14 01:42:01 -05:00
move all applications into their top-level directory
thanks to [at]akva2 for the suggestion.
This commit is contained in:
1 parent
67c978fe75
commit
759c2dbdaa
17 files changed
+992
No files matched your search
File renamed without changes.
@@ -0,0 +1,433 @@
|
||||
// -*- 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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.
|
||||
*/
|
||||
#ifndef EWOMS_PARALLELSERIALOUTPUT_HH
|
||||
#define EWOMS_PARALLELSERIALOUTPUT_HH
|
||||
|
||||
//#if HAVE_OPM_GRID
|
||||
#include <dune/grid/common/p2pcommunicator.hh>
|
||||
#include <dune/grid/utility/persistentcontainer.hh>
|
||||
#include <dune/grid/common/gridenums.hh>
|
||||
//#else
|
||||
//#error "This header needs the opm-grid module."
|
||||
//#endif
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/common/Exceptions.hpp>
|
||||
|
||||
#include <dune/grid/common/mcmgmapper.hh>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Ewoms
|
||||
{
|
||||
template < class GridManager >
|
||||
class CollectDataToIORank
|
||||
{
|
||||
public:
|
||||
typedef typename GridManager :: Grid Grid;
|
||||
typedef typename Grid :: CollectiveCommunication CollectiveCommunication;
|
||||
|
||||
// global id
|
||||
class GlobalCellIndex
|
||||
{
|
||||
int globalId_;
|
||||
int localIndex_;
|
||||
bool isInterior_;
|
||||
public:
|
||||
GlobalCellIndex() : globalId_(-1), localIndex_(-1), isInterior_(true) {}
|
||||
void setGhost() { isInterior_ = false; }
|
||||
|
||||
void setId( const int globalId ) { globalId_ = globalId; }
|
||||
void setIndex( const int localIndex ) { localIndex_ = localIndex; }
|
||||
|
||||
int localIndex () const { return localIndex_; }
|
||||
int id () const { return globalId_; }
|
||||
bool isInterior() const { return isInterior_; }
|
||||
};
|
||||
|
||||
typedef typename Dune::PersistentContainer< Grid, GlobalCellIndex > GlobalIndexContainer;
|
||||
|
||||
static const int dimension = Grid :: dimension ;
|
||||
|
||||
typedef typename Grid :: LeafGridView GridView;
|
||||
typedef GridView AllGridView;
|
||||
|
||||
typedef Dune :: Point2PointCommunicator< Dune :: SimpleMessageBuffer > P2PCommunicatorType;
|
||||
typedef typename P2PCommunicatorType :: MessageBufferType MessageBufferType;
|
||||
|
||||
typedef std::vector< GlobalCellIndex > LocalIndexMapType;
|
||||
|
||||
typedef std::vector<int> IndexMapType;
|
||||
typedef std::vector< IndexMapType > IndexMapStorageType;
|
||||
|
||||
class DistributeIndexMapping : public P2PCommunicatorType::DataHandleInterface
|
||||
{
|
||||
protected:
|
||||
const std::vector<int>& distributedGlobalIndex_;
|
||||
IndexMapType& localIndexMap_;
|
||||
IndexMapStorageType& indexMaps_;
|
||||
std::map< const int, const int > globalPosition_;
|
||||
#ifndef NDEBUG
|
||||
std::set< int > checkPosition_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
DistributeIndexMapping( const std::vector<int>& globalIndex,
|
||||
const std::vector<int>& distributedGlobalIndex,
|
||||
IndexMapType& localIndexMap,
|
||||
IndexMapStorageType& indexMaps )
|
||||
: distributedGlobalIndex_( distributedGlobalIndex ),
|
||||
localIndexMap_( localIndexMap ),
|
||||
indexMaps_( indexMaps ),
|
||||
globalPosition_()
|
||||
{
|
||||
const size_t size = globalIndex.size();
|
||||
// create mapping globalIndex --> localIndex
|
||||
for ( size_t index = 0; index < size; ++index )
|
||||
{
|
||||
globalPosition_.insert( std::make_pair( globalIndex[ index ], index ) );
|
||||
}
|
||||
|
||||
// on I/O rank we need to create a mapping from local to global
|
||||
if( ! indexMaps_.empty() )
|
||||
{
|
||||
// for the ioRank create a localIndex to index in global state map
|
||||
IndexMapType& indexMap = indexMaps_.back();
|
||||
const size_t localSize = localIndexMap_.size();
|
||||
indexMap.resize( localSize );
|
||||
for( size_t i=0; i<localSize; ++i )
|
||||
{
|
||||
const int id = distributedGlobalIndex_[ localIndexMap_[ i ] ];
|
||||
indexMap[ i ] = globalPosition_[ id ] ;
|
||||
#ifndef NDEBUG
|
||||
assert( checkPosition_.find( id ) == checkPosition_.end() );
|
||||
checkPosition_.insert( id );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pack( const int link, MessageBufferType& buffer )
|
||||
{
|
||||
// we should only get one link
|
||||
if( link != 0 ) {
|
||||
OPM_THROW(std::logic_error,"link in method pack is not 0 as execpted");
|
||||
}
|
||||
|
||||
// pack all interior global cell id's
|
||||
const int size = localIndexMap_.size();
|
||||
buffer.write( size );
|
||||
|
||||
for( int index = 0; index < size; ++index )
|
||||
{
|
||||
const int globalIdx = distributedGlobalIndex_[ localIndexMap_[ index ] ];
|
||||
buffer.write( globalIdx );
|
||||
}
|
||||
}
|
||||
|
||||
void unpack( const int link, MessageBufferType& buffer )
|
||||
{
|
||||
// get index map for current link
|
||||
IndexMapType& indexMap = indexMaps_[ link ];
|
||||
assert( ! globalPosition_.empty() );
|
||||
|
||||
// unpack all interior global cell id's
|
||||
int numCells = 0;
|
||||
buffer.read( numCells );
|
||||
indexMap.resize( numCells );
|
||||
for( int index = 0; index < numCells; ++index )
|
||||
{
|
||||
int globalId = -1;
|
||||
buffer.read( globalId );
|
||||
assert( globalPosition_.find( globalId ) != globalPosition_.end() );
|
||||
indexMap[ index ] = globalPosition_[ globalId ];
|
||||
#ifndef NDEBUG
|
||||
assert( checkPosition_.find( globalId ) == checkPosition_.end() );
|
||||
checkPosition_.insert( globalId );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum { ioRank = 0 };
|
||||
|
||||
CollectDataToIORank( const GridManager& gridManager )
|
||||
: toIORankComm_( ),
|
||||
isIORank_( gridManager.grid().comm().rank() == ioRank )
|
||||
{
|
||||
typedef typename GridManager::GridView GridView;
|
||||
typedef Dune::MultipleCodimMultipleGeomTypeMapper<GridView, Dune::MCMGElementLayout>
|
||||
ElementMapper;
|
||||
|
||||
const CollectiveCommunication& comm = gridManager.grid().comm();
|
||||
{
|
||||
std::set< int > send, recv;
|
||||
// the I/O rank receives from all other ranks
|
||||
if( isIORank() )
|
||||
{
|
||||
const auto& eclGrid = gridManager.eclGrid();
|
||||
|
||||
// create the ACTNUM array based on the "real" grid which is used for
|
||||
// simulation. Note that this is still an approximation because the simulation
|
||||
// grid may also modify the geometry of cells (e.g. because of the PINCH
|
||||
// keyword), but at least the number of cells is correct, so all values are
|
||||
// hopefully displayed at approximately the correct location.
|
||||
std::vector<int> actnumData(eclGrid->getCartesianSize(), 0);
|
||||
ElementMapper elemMapper(gridManager.gridView());
|
||||
auto elemIt = gridManager.gridView().template begin<0>();
|
||||
const auto& elemEndIt = gridManager.gridView().template end<0>();
|
||||
for (; elemIt != elemEndIt; ++elemIt) {
|
||||
#if DUNE_VERSION_NEWER(DUNE_COMMON, 2,4)
|
||||
int elemIdx = elemMapper.index(*elemIt );
|
||||
#else
|
||||
int elemIdx = elemMapper.map(*elemIt );
|
||||
#endif
|
||||
int cartElemIdx = gridManager.cartesianIndex(elemIdx);
|
||||
actnumData[cartElemIdx] = 1;
|
||||
}
|
||||
|
||||
// the I/O rank needs a picture of the global grid
|
||||
const size_t cartesianSize = eclGrid->getCartesianSize();
|
||||
// reserve memory
|
||||
globalCartesianIndex_.reserve( cartesianSize );
|
||||
globalCartesianIndex_.clear();
|
||||
// get a global cartesian index for each active cell in the eclipse grid
|
||||
for( size_t cartIndex=0; cartIndex<cartesianSize; ++cartIndex )
|
||||
{
|
||||
if( actnumData[cartIndex] > 0 )
|
||||
{
|
||||
globalCartesianIndex_.push_back( cartIndex );
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<comm.size(); ++i)
|
||||
{
|
||||
if( i != ioRank )
|
||||
{
|
||||
recv.insert( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
else // all other simply send to the I/O rank
|
||||
{
|
||||
send.insert( ioRank );
|
||||
}
|
||||
|
||||
localIndexMap_.clear();
|
||||
const size_t gridSize = gridManager.grid().size( 0 );
|
||||
localIndexMap_.reserve( gridSize );
|
||||
|
||||
unsigned int index = 0;
|
||||
auto localView = gridManager.grid().leafGridView();
|
||||
for( auto it = localView.template begin< 0 >(),
|
||||
end = localView.template end< 0 >(); it != end; ++it, ++index )
|
||||
{
|
||||
const auto element = *it ;
|
||||
// only store interior element for collection
|
||||
if( element.partitionType() == Dune :: InteriorEntity )
|
||||
{
|
||||
localIndexMap_.push_back( index );
|
||||
}
|
||||
}
|
||||
|
||||
// insert send and recv linkage to communicator
|
||||
toIORankComm_.insertRequest( send, recv );
|
||||
|
||||
if( isIORank() )
|
||||
{
|
||||
// need an index map for each rank
|
||||
indexMaps_.clear();
|
||||
indexMaps_.resize( comm.size() );
|
||||
}
|
||||
|
||||
// store the local cartesian index
|
||||
IndexMapType distributedCartesianIndex;
|
||||
distributedCartesianIndex.reserve( gridSize );
|
||||
for( size_t cell = 0 ; cell<gridSize; ++cell )
|
||||
distributedCartesianIndex.push_back( gridManager.cartesianIndex( cell ) );
|
||||
|
||||
// distribute global id's to io rank for later association of dof's
|
||||
DistributeIndexMapping distIndexMapping( globalCartesianIndex_, distributedCartesianIndex, localIndexMap_, indexMaps_ );
|
||||
toIORankComm_.exchange( distIndexMapping );
|
||||
}
|
||||
}
|
||||
|
||||
template <class BufferList>
|
||||
class PackUnPackOutputBuffers : public P2PCommunicatorType::DataHandleInterface
|
||||
{
|
||||
BufferList& bufferList_;
|
||||
|
||||
const IndexMapType& localIndexMap_;
|
||||
const IndexMapStorageType& indexMaps_;
|
||||
|
||||
public:
|
||||
PackUnPackOutputBuffers( BufferList& bufferList,
|
||||
const IndexMapType& localIndexMap,
|
||||
const IndexMapStorageType& indexMaps,
|
||||
const size_t globalSize,
|
||||
const bool isIORank )
|
||||
: bufferList_( bufferList ),
|
||||
localIndexMap_( localIndexMap ),
|
||||
indexMaps_( indexMaps )
|
||||
{
|
||||
if( isIORank )
|
||||
{
|
||||
MessageBufferType buffer;
|
||||
pack( 0, buffer );
|
||||
// resize all buffers
|
||||
for (auto it = bufferList_.begin(), end = bufferList_.end(); it != end; ++it )
|
||||
{
|
||||
it->second->resize( globalSize );
|
||||
}
|
||||
// the last index map is the local one
|
||||
doUnpack( indexMaps.back(), buffer );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// pack all data associated with link
|
||||
void pack( const int link, MessageBufferType& buffer )
|
||||
{
|
||||
// we should only get one link
|
||||
if( link != 0 ) {
|
||||
OPM_THROW(std::logic_error,"link in method pack is not 0 as execpted");
|
||||
}
|
||||
|
||||
size_t buffers = bufferList_.size();
|
||||
buffer.write( buffers );
|
||||
for (auto it = bufferList_.begin(), end = bufferList_.end(); it != end; ++it )
|
||||
{
|
||||
write( buffer, localIndexMap_, *(it->second) );
|
||||
}
|
||||
}
|
||||
|
||||
void doUnpack( const IndexMapType& indexMap, MessageBufferType& buffer )
|
||||
{
|
||||
size_t buffers = 0;
|
||||
buffer.read( buffers );
|
||||
assert( buffers == bufferList_.size() );
|
||||
for( auto it = bufferList_.begin(), end = bufferList_.end(); it != end; ++it )
|
||||
{
|
||||
read( buffer, indexMap, *(it->second) );
|
||||
}
|
||||
}
|
||||
|
||||
// unpack all data associated with link
|
||||
void unpack( const int link, MessageBufferType& buffer )
|
||||
{
|
||||
doUnpack( indexMaps_[ link ], buffer );
|
||||
}
|
||||
|
||||
protected:
|
||||
template <class Vector>
|
||||
void write( MessageBufferType& buffer, const IndexMapType& localIndexMap, const Vector& data ) const
|
||||
{
|
||||
const size_t size = localIndexMap.size();
|
||||
assert( size <= data.size() );
|
||||
buffer.write( size );
|
||||
for( size_t i=0; i<size; ++i )
|
||||
{
|
||||
buffer.write( data[ localIndexMap[ i ] ] );
|
||||
}
|
||||
}
|
||||
|
||||
template <class Vector>
|
||||
void read( MessageBufferType& buffer, const IndexMapType& indexMap, Vector& data ) const
|
||||
{
|
||||
size_t size = indexMap.size();
|
||||
assert( size <= data.size() );
|
||||
buffer.read( size );
|
||||
assert( size == indexMap.size() );
|
||||
for( size_t i=0; i<size; ++i )
|
||||
{
|
||||
buffer.read( data[ indexMap[ i ] ] );
|
||||
}
|
||||
}
|
||||
|
||||
void writeString( MessageBufferType& buffer, const std::string& s) const
|
||||
{
|
||||
const int size = s.size();
|
||||
buffer.write( size );
|
||||
for( int i=0; i<size; ++i )
|
||||
{
|
||||
buffer.write( s[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
void readString( MessageBufferType& buffer, std::string& s) const
|
||||
{
|
||||
int size = -1;
|
||||
buffer.read( size );
|
||||
s.resize( size );
|
||||
for( int i=0; i<size; ++i )
|
||||
{
|
||||
buffer.read( s[ i ] );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// gather solution to rank 0 for EclipseWriter
|
||||
template <class BufferList>
|
||||
void collect( BufferList& bufferList ) const
|
||||
{
|
||||
PackUnPackOutputBuffers< BufferList >
|
||||
packUnpack( bufferList,
|
||||
localIndexMap_,
|
||||
indexMaps_,
|
||||
numCells(),
|
||||
isIORank() );
|
||||
|
||||
//toIORankComm_.exchangeCached( packUnpack );
|
||||
toIORankComm_.exchange( packUnpack );
|
||||
#ifndef NDEBUG
|
||||
// mkae sure every process is on the same page
|
||||
toIORankComm_.barrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isIORank() const
|
||||
{
|
||||
return isIORank_;
|
||||
}
|
||||
|
||||
bool isParallel() const
|
||||
{
|
||||
return toIORankComm_.size() > 1;
|
||||
}
|
||||
|
||||
size_t numCells () const { return globalCartesianIndex_.size(); }
|
||||
|
||||
protected:
|
||||
P2PCommunicatorType toIORankComm_;
|
||||
IndexMapType globalCartesianIndex_;
|
||||
IndexMapType localIndexMap_;
|
||||
IndexMapStorageType indexMaps_;
|
||||
// true if we are on I/O rank
|
||||
bool isIORank_;
|
||||
};
|
||||
|
||||
} // end namespace Opm
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
// -*- 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
*
|
||||
* \brief A general-purpose simulator for ECL decks using the black-oil model.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <ewoms/common/quad.hh>
|
||||
#include <ewoms/common/start.hh>
|
||||
|
||||
#include "eclproblem.hh"
|
||||
|
||||
namespace Ewoms {
|
||||
namespace Properties {
|
||||
NEW_TYPE_TAG(EclProblem, INHERITS_FROM(BlackOilModel, EclBaseProblem));
|
||||
}}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
typedef TTAG(EclProblem) ProblemTypeTag;
|
||||
return Ewoms::start<ProblemTypeTag>(argc, argv);
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,160 @@
|
||||
// -*- 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 Ewoms::EclPolyhedralGridManager
|
||||
*/
|
||||
#ifndef EWOMS_ECL_POLYHEDRAL_GRID_MANAGER_HH
|
||||
#define EWOMS_ECL_POLYHEDRAL_GRID_MANAGER_HH
|
||||
|
||||
#include "eclbasegridmanager.hh"
|
||||
|
||||
#include <dune/grid/polyhedralgrid.hh>
|
||||
|
||||
namespace Ewoms {
|
||||
template <class TypeTag>
|
||||
class EclPolyhedralGridManager;
|
||||
|
||||
namespace Properties {
|
||||
NEW_TYPE_TAG(EclPolyhedralGridManager, INHERITS_FROM(EclBaseGridManager));
|
||||
|
||||
// declare the properties
|
||||
SET_TYPE_PROP(EclPolyhedralGridManager, GridManager, Ewoms::EclPolyhedralGridManager<TypeTag>);
|
||||
SET_TYPE_PROP(EclPolyhedralGridManager, Grid, Dune::PolyhedralGrid<3, 3>);
|
||||
SET_TYPE_PROP(EclPolyhedralGridManager, EquilGrid, typename GET_PROP_TYPE(TypeTag, Grid));
|
||||
} // namespace Properties
|
||||
|
||||
/*!
|
||||
* \ingroup EclBlackOilSimulator
|
||||
*
|
||||
* \brief Helper class for grid instantiation of ECL file-format using problems.
|
||||
*
|
||||
* This class uses Dune::PolyhedralGrid as the simulation grid.
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class EclPolyhedralGridManager : public EclBaseGridManager<TypeTag>
|
||||
{
|
||||
friend class EclBaseGridManager<TypeTag>;
|
||||
typedef EclBaseGridManager<TypeTag> ParentType;
|
||||
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
|
||||
public:
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, EquilGrid) EquilGrid;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
|
||||
private:
|
||||
typedef Grid* GridPointer;
|
||||
typedef EquilGrid* EquilGridPointer;
|
||||
typedef Dune::CartesianIndexMapper<Grid> CartesianIndexMapper;
|
||||
typedef CartesianIndexMapper* CartesianIndexMapperPointer;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Inherit the constructors from the base class.
|
||||
*/
|
||||
using EclBaseGridManager<TypeTag>::EclBaseGridManager;
|
||||
|
||||
~EclPolyhedralGridManager()
|
||||
{
|
||||
delete cartesianIndexMapper_;
|
||||
delete grid_;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the simulation grid.
|
||||
*/
|
||||
Grid& grid()
|
||||
{ return *grid_; }
|
||||
|
||||
/*!
|
||||
* \brief Return a reference to the simulation grid.
|
||||
*/
|
||||
const Grid& grid() const
|
||||
{ return *grid_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns a refefence to the grid which should be used by the EQUIL
|
||||
* initialization code.
|
||||
*
|
||||
* The EQUIL keyword is used to specify the initial condition of the reservoir in
|
||||
* hydrostatic equilibrium. Since the code which does this is not accepting arbitrary
|
||||
* DUNE grids (the code is part of the opm-core module), this is not necessarily the
|
||||
* same as the grid which is used for the actual simulation.
|
||||
*/
|
||||
const EquilGrid& equilGrid() const
|
||||
{ return *grid_; }
|
||||
|
||||
/*!
|
||||
* \brief Indicates that the initial condition has been computed and the memory used
|
||||
* by the EQUIL grid can be released.
|
||||
*
|
||||
* Depending on the implementation, subsequent accesses to the EQUIL grid lead to
|
||||
* crashes.
|
||||
*/
|
||||
void releaseEquilGrid()
|
||||
{ /* do nothing: The EQUIL grid is the simulation grid! */ }
|
||||
|
||||
/*!
|
||||
* \brief Distribute the simulation grid over multiple processes
|
||||
*
|
||||
* (For parallel simulation runs.)
|
||||
*/
|
||||
void loadBalance()
|
||||
{ /* do nothing: PolyhedralGrid is not parallel! */ }
|
||||
|
||||
/*!
|
||||
* \brief Returns the object which maps a global element index of the simulation grid
|
||||
* to the corresponding element index of the logically Cartesian index.
|
||||
*/
|
||||
const CartesianIndexMapper& cartesianIndexMapper() const
|
||||
{ return *cartesianIndexMapper_; }
|
||||
|
||||
/*!
|
||||
* \brief Returns mapper from compressed to cartesian indices for the EQUIL grid
|
||||
*
|
||||
* Since PolyhedralGrid is not parallel, that's always the same as
|
||||
* cartesianIndexMapper().
|
||||
*/
|
||||
const CartesianIndexMapper& equilCartesianIndexMapper() const
|
||||
{ return *cartesianIndexMapper_; }
|
||||
|
||||
protected:
|
||||
void createGrids_()
|
||||
{
|
||||
const auto& gridProps = this->eclState()->get3DProperties();
|
||||
const std::vector<double>& porv = gridProps.getDoubleGridProperty("PORV").getData();
|
||||
|
||||
grid_ = new Grid(*(this->deck()), porv);
|
||||
cartesianIndexMapper_ = new CartesianIndexMapper(*grid_);
|
||||
}
|
||||
|
||||
GridPointer grid_;
|
||||
CartesianIndexMapperPointer cartesianIndexMapper_;
|
||||
};
|
||||
|
||||
} // namespace Ewoms
|
||||
|
||||
#endif
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,355 @@
|
||||
// -*- 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 Ewoms::EclWriter
|
||||
*/
|
||||
#ifndef EWOMS_ECL_WRITER_HH
|
||||
#define EWOMS_ECL_WRITER_HH
|
||||
|
||||
#include <opm/material/densead/Evaluation.hpp>
|
||||
|
||||
#include "ertwrappers.hh"
|
||||
#include "collecttoiorank.hh"
|
||||
|
||||
#include <ewoms/disc/ecfv/ecfvdiscretization.hh>
|
||||
#include <ewoms/io/baseoutputwriter.hh>
|
||||
|
||||
#include <opm/material/common/Valgrind.hpp>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/common/Exceptions.hpp>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Ewoms {
|
||||
namespace Properties {
|
||||
NEW_PROP_TAG(EnableEclOutput);
|
||||
}
|
||||
|
||||
template <class TypeTag>
|
||||
class EclWriter;
|
||||
|
||||
template <class TypeTag, class GridManagerType>
|
||||
class EclWriterHelper
|
||||
{
|
||||
friend class EclWriter<TypeTag>;
|
||||
|
||||
static void writeHeaders_(EclWriter<TypeTag>& writer)
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Discretization) Discretization;
|
||||
if (!std::is_same<Discretization, Ewoms::EcfvDiscretization<TypeTag> >::value)
|
||||
OPM_THROW(std::logic_error,
|
||||
"Ecl binary output only works for the element centered "
|
||||
"finite volume discretization.");
|
||||
|
||||
#if ! HAVE_ERT
|
||||
OPM_THROW(std::logic_error,
|
||||
"Ecl binary output requires the ERT libraries");
|
||||
#else
|
||||
// set the index of the first time step written to 0...
|
||||
writer.reportStepIdx_ = 0;
|
||||
|
||||
char* egridRawFileName = ecl_util_alloc_filename(/*outputDir=*/"./",
|
||||
writer.caseName().c_str(),
|
||||
ECL_EGRID_FILE,
|
||||
/*formatted=*/false, // -> write binary output
|
||||
writer.reportStepIdx_);
|
||||
std::string egridFileName(egridRawFileName);
|
||||
std::free(egridRawFileName);
|
||||
|
||||
ErtGrid ertGrid(*writer.simulator_.gridManager().eclGrid(),
|
||||
writer.simulator_.gridManager().grid(),
|
||||
writer.simulator_.gridManager().cartesianIndexMapper(),
|
||||
writer.simulator_.problem().deckUnits());
|
||||
ertGrid.write(egridFileName, writer.reportStepIdx_);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \ingroup EclBlackOilSimulator
|
||||
*
|
||||
* \brief Implements writing Ecl binary output files.
|
||||
*
|
||||
* Caveats:
|
||||
* - For this class to do do anything meaningful, you need to have the
|
||||
* ERT libraries with development headers installed and the ERT
|
||||
* build system test must pass sucessfully.
|
||||
* - The only DUNE grid which is currently supported is Dune::CpGrid
|
||||
* from the OPM module "opm-core". Using another grid won't
|
||||
* fail at compile time but you will provoke a fatal exception as
|
||||
* soon as you try to write an ECL output file.
|
||||
* - This class requires to use the black oil model with the element
|
||||
* centered finite volume discretization.
|
||||
* - MPI-parallel computations are not (yet?) supported.
|
||||
*/
|
||||
template <class TypeTag>
|
||||
class EclWriter : public BaseOutputWriter
|
||||
{
|
||||
typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridManager) GridManager;
|
||||
typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
|
||||
|
||||
|
||||
typedef CollectDataToIORank< GridManager > CollectDataToIORankType;
|
||||
|
||||
typedef BaseOutputWriter::ScalarBuffer ScalarBuffer;
|
||||
typedef BaseOutputWriter::VectorBuffer VectorBuffer;
|
||||
typedef BaseOutputWriter::TensorBuffer TensorBuffer;
|
||||
|
||||
friend class EclWriterHelper<TypeTag, GridManager>;
|
||||
|
||||
public:
|
||||
EclWriter(const Simulator& simulator)
|
||||
: simulator_(simulator)
|
||||
, gridView_(simulator_.gridView())
|
||||
, elementMapper_(gridView_)
|
||||
, vertexMapper_(gridView_)
|
||||
, collectToIORank_( simulator_.gridManager() )
|
||||
{
|
||||
reportStepIdx_ = 0;
|
||||
}
|
||||
|
||||
~EclWriter()
|
||||
{ }
|
||||
|
||||
/*!
|
||||
* \brief Returns the name of the simulation.
|
||||
*
|
||||
* This is the prefix of the files written to disk.
|
||||
*/
|
||||
std::string caseName() const
|
||||
{ return boost::to_upper_copy(simulator_.problem().name()); }
|
||||
|
||||
/*!
|
||||
* \brief Updates the internal data structures after mesh
|
||||
* refinement.
|
||||
*
|
||||
* If the grid changes between two calls of beginWrite(), this
|
||||
* method _must_ be called before the second beginWrite()!
|
||||
*/
|
||||
void gridChanged()
|
||||
{
|
||||
elementMapper_.update();
|
||||
vertexMapper_.update();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called whenever a new time step must be written.
|
||||
*/
|
||||
void beginWrite(double t)
|
||||
{
|
||||
if (enableEclOutput_() && reportStepIdx_ == 0 && collectToIORank_.isIORank() )
|
||||
EclWriterHelper<TypeTag, GridManager>::writeHeaders_(*this);
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Add a vertex-centered scalar field to the output.
|
||||
*
|
||||
* For the EclWriter, this method is a no-op which throws a
|
||||
* std::logic_error exception
|
||||
*/
|
||||
void attachScalarVertexData(ScalarBuffer& buf, std::string name)
|
||||
{
|
||||
OPM_THROW(std::logic_error,
|
||||
"The EclWriter can only write element based quantities!");
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Add a vertex-centered vector field to the output.
|
||||
*
|
||||
* For the EclWriter, this method is a no-op which throws a
|
||||
* std::logic_error exception
|
||||
*/
|
||||
void attachVectorVertexData(VectorBuffer& buf, std::string name)
|
||||
{
|
||||
OPM_THROW(std::logic_error,
|
||||
"The EclWriter can only write element based quantities!");
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Add a vertex-centered tensor field to the output.
|
||||
*/
|
||||
void attachTensorVertexData(TensorBuffer& buf, std::string name)
|
||||
{
|
||||
OPM_THROW(std::logic_error,
|
||||
"The EclWriter can only write element based quantities!");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Add a scalar quantity to the output.
|
||||
*
|
||||
* The buffer must exist at least until the call to endWrite()
|
||||
* finishes. Modifying the buffer between the call to this method
|
||||
* and endWrite() results in _undefined behavior_.
|
||||
*/
|
||||
void attachScalarElementData(ScalarBuffer& buf, std::string name)
|
||||
{
|
||||
attachedBuffers_.push_back(std::pair<std::string, ScalarBuffer*>(name, &buf));
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Add a element-centered vector field to the output.
|
||||
*
|
||||
* For the EclWriter, this method is a no-op which throws a
|
||||
* std::logic_error exception
|
||||
*/
|
||||
void attachVectorElementData(VectorBuffer& buf, std::string name)
|
||||
{
|
||||
OPM_THROW(std::logic_error,
|
||||
"Currently, the EclWriter can only write scalar quantities!");
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Add a element-centered tensor field to the output.
|
||||
*/
|
||||
void attachTensorElementData(TensorBuffer& buf, std::string name)
|
||||
{
|
||||
OPM_THROW(std::logic_error,
|
||||
"Currently, the EclWriter can only write scalar quantities!");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Finalizes the current writer.
|
||||
*
|
||||
* This means that everything will be written to disk, except if
|
||||
* the onlyDiscard argument is true. In this case, no output is
|
||||
* written but the 'janitorial' jobs at the end of a time step are
|
||||
* still done.
|
||||
*/
|
||||
void endWrite(bool onlyDiscard = false)
|
||||
{
|
||||
if (onlyDiscard || !enableEclOutput_() || !simulator_.episodeWillBeOver()) {
|
||||
// detach all buffers
|
||||
attachedBuffers_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
#if !HAVE_ERT
|
||||
OPM_THROW(std::runtime_error,
|
||||
"The ERT libraries must be available to write ECL output!");
|
||||
#else
|
||||
|
||||
// collect all data to I/O rank and store in attachedBuffers_
|
||||
// this also reorders the data such that it fits the underlying eclGrid
|
||||
collectToIORank_.collect( attachedBuffers_ );
|
||||
|
||||
// write output on I/O rank
|
||||
if (collectToIORank_.isIORank()) {
|
||||
ErtRestartFile restartFile(simulator_, reportStepIdx_);
|
||||
restartFile.writeHeader(simulator_, reportStepIdx_);
|
||||
|
||||
ErtSolution solution(restartFile);
|
||||
auto bufIt = attachedBuffers_.begin();
|
||||
const auto& bufEndIt = attachedBuffers_.end();
|
||||
for (; bufIt != bufEndIt; ++ bufIt) {
|
||||
const std::string& name = bufIt->first;
|
||||
const ScalarBuffer& buffer = *bufIt->second;
|
||||
|
||||
std::shared_ptr<const ErtKeyword<float>>
|
||||
bufKeyword(new ErtKeyword<float>(name, buffer));
|
||||
solution.add(bufKeyword);
|
||||
}
|
||||
}
|
||||
|
||||
// detach all buffers
|
||||
attachedBuffers_.clear();
|
||||
|
||||
// next time we take the next report step
|
||||
++ reportStepIdx_;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Write the multi-writer's state to a restart file.
|
||||
*/
|
||||
template <class Restarter>
|
||||
void serialize(Restarter& res)
|
||||
{
|
||||
res.serializeSectionBegin("EclWriter");
|
||||
res.serializeStream() << reportStepIdx_ << "\n";
|
||||
res.serializeSectionEnd();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Read the multi-writer's state from a restart file.
|
||||
*/
|
||||
template <class Restarter>
|
||||
void deserialize(Restarter& res)
|
||||
{
|
||||
res.deserializeSectionBegin("EclWriter");
|
||||
res.deserializeStream() >> reportStepIdx_;
|
||||
res.deserializeSectionEnd();
|
||||
}
|
||||
|
||||
private:
|
||||
static bool enableEclOutput_()
|
||||
{ return EWOMS_GET_PARAM(TypeTag, bool, EnableEclOutput); }
|
||||
|
||||
// make sure the field is well defined if running under valgrind
|
||||
// and make sure that all values can be displayed by paraview
|
||||
void sanitizeBuffer_(std::vector<float>& b)
|
||||
{
|
||||
static bool warningPrinted = false;
|
||||
for (size_t i = 0; i < b.size(); ++i) {
|
||||
Valgrind::CheckDefined(b[i]);
|
||||
|
||||
if (!warningPrinted && !std::isfinite(b[i])) {
|
||||
std::cerr << "WARNING: data field written to disk contains non-finite entries!\n";
|
||||
warningPrinted = true;
|
||||
}
|
||||
|
||||
// set values which are too small to 0 to avoid possible
|
||||
// problems
|
||||
if (std::abs(b[i]) < std::numeric_limits<float>::min()) {
|
||||
b[i] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Simulator& simulator_;
|
||||
const GridView gridView_;
|
||||
|
||||
ElementMapper elementMapper_;
|
||||
VertexMapper vertexMapper_;
|
||||
CollectDataToIORankType collectToIORank_;
|
||||
|
||||
double curTime_;
|
||||
unsigned reportStepIdx_;
|
||||
|
||||
std::list<std::pair<std::string, ScalarBuffer*> > attachedBuffers_;
|
||||
};
|
||||
} // namespace Ewoms
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user