mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-01-27 21:56:27 -06:00
move all applications into their top-level directory
thanks to [at]akva2 for the suggestion.
This commit is contained in:
parent
67c978fe75
commit
759c2dbdaa
433
ebos/collecttoiorank.hh
Normal file
433
ebos/collecttoiorank.hh
Normal file
@ -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
|
44
ebos/ebos.cc
Normal file
44
ebos/ebos.cc
Normal file
@ -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);
|
||||
}
|
160
ebos/eclpolyhedralgridmanager.hh
Normal file
160
ebos/eclpolyhedralgridmanager.hh
Normal file
@ -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
|
355
ebos/eclwriter.hh
Normal file
355
ebos/eclwriter.hh
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user