Merge branch 'refactor-for-cpgrid-support' into master-refactor-for-cpgrid-support
Manually resolved conflicts in: opm/core/props/BlackoilPropertiesFromDeck.cpp opm/core/wells/WellsManager.cpp
This commit is contained in:
commit
eeb0039683
@ -29,6 +29,7 @@
|
||||
# originally generated with the command:
|
||||
# find opm -name '*.c*' -printf '\t%p\n' | sort
|
||||
list (APPEND MAIN_SOURCE_FILES
|
||||
opm/core/grid/GridHelpers.cpp
|
||||
opm/core/grid/GridManager.cpp
|
||||
opm/core/grid/grid.c
|
||||
opm/core/grid/cart_grid.c
|
||||
@ -74,6 +75,7 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
opm/core/pressure/tpfa/compr_quant_general.c
|
||||
opm/core/pressure/tpfa/compr_source.c
|
||||
opm/core/pressure/tpfa/ifs_tpfa.c
|
||||
opm/core/pressure/tpfa/TransTpfa.cpp
|
||||
opm/core/pressure/tpfa/trans_tpfa.c
|
||||
opm/core/pressure/legacy_well.c
|
||||
opm/core/props/BlackoilPropertiesBasic.cpp
|
||||
@ -235,6 +237,7 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/core/grid/CellQuadrature.hpp
|
||||
opm/core/grid/ColumnExtract.hpp
|
||||
opm/core/grid/FaceQuadrature.hpp
|
||||
opm/core/grid/GridHelpers.hpp
|
||||
opm/core/grid/GridManager.hpp
|
||||
opm/core/grid/cart_grid.h
|
||||
opm/core/grid/cornerpoint_grid.h
|
||||
@ -287,10 +290,13 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/core/pressure/tpfa/compr_quant_general.h
|
||||
opm/core/pressure/tpfa/compr_source.h
|
||||
opm/core/pressure/tpfa/ifs_tpfa.h
|
||||
opm/core/pressure/tpfa/TransTpfa.hpp
|
||||
opm/core/pressure/tpfa/TransTpfa_impl.hpp
|
||||
opm/core/pressure/tpfa/trans_tpfa.h
|
||||
opm/core/props/BlackoilPhases.hpp
|
||||
opm/core/props/BlackoilPropertiesBasic.hpp
|
||||
opm/core/props/BlackoilPropertiesFromDeck.hpp
|
||||
opm/core/props/BlackoilPropertiesFromDeck_impl.hpp
|
||||
opm/core/props/BlackoilPropertiesInterface.hpp
|
||||
opm/core/props/IncompPropertiesBasic.hpp
|
||||
opm/core/props/IncompPropertiesFromDeck.hpp
|
||||
@ -379,6 +385,7 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/core/utility/have_boost_redef.hpp
|
||||
opm/core/utility/linearInterpolation.hpp
|
||||
opm/core/utility/miscUtilities.hpp
|
||||
opm/core/utility/miscUtilities_impl.hpp
|
||||
opm/core/utility/miscUtilitiesBlackoil.hpp
|
||||
opm/core/utility/parameters/Parameter.hpp
|
||||
opm/core/utility/parameters/ParameterGroup.hpp
|
||||
@ -397,4 +404,5 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/core/wells/WellCollection.hpp
|
||||
opm/core/wells/WellsGroup.hpp
|
||||
opm/core/wells/WellsManager.hpp
|
||||
opm/core/wells/WellsManager_impl.hpp
|
||||
)
|
||||
|
81
opm/core/grid/GridHelpers.cpp
Normal file
81
opm/core/grid/GridHelpers.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include "config.h"
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
namespace Opm
|
||||
{
|
||||
namespace UgGridHelpers
|
||||
{
|
||||
int numCells(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.number_of_cells;
|
||||
}
|
||||
|
||||
int numFaces(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.number_of_faces;
|
||||
}
|
||||
int dimensions(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.dimensions;
|
||||
}
|
||||
int numCellFaces(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.cell_facepos[grid.number_of_cells];
|
||||
}
|
||||
|
||||
const int* globalCell(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.global_cell;
|
||||
}
|
||||
|
||||
const int* cartDims(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.cartdims;
|
||||
}
|
||||
|
||||
const double* beginCellCentroids(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.cell_centroids;
|
||||
}
|
||||
|
||||
double cellCentroidCoordinate(const UnstructuredGrid& grid, int cell_index,
|
||||
int coordinate)
|
||||
{
|
||||
return grid.cell_centroids[grid.dimensions*cell_index+coordinate];
|
||||
}
|
||||
|
||||
const double* beginFaceCentroids(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.face_centroids;
|
||||
}
|
||||
|
||||
const double* faceCentroid(const UnstructuredGrid& grid, int face_index)
|
||||
{
|
||||
return grid.face_centroids+face_index*grid.dimensions;
|
||||
}
|
||||
|
||||
const double* faceNormal(const UnstructuredGrid& grid, int face_index)
|
||||
{
|
||||
return grid.face_normals+face_index*grid.dimensions;
|
||||
}
|
||||
|
||||
double faceArea(const UnstructuredGrid& grid, int face_index)
|
||||
{
|
||||
return grid.face_areas[face_index];
|
||||
}
|
||||
|
||||
SparseTableView cell2Faces(const UnstructuredGrid& grid)
|
||||
{
|
||||
return SparseTableView(grid.cell_faces, grid.cell_facepos, numCells(grid));
|
||||
}
|
||||
|
||||
double cellVolume(const UnstructuredGrid& grid, int cell_index)
|
||||
{
|
||||
return grid.cell_volumes[cell_index];
|
||||
}
|
||||
|
||||
FaceCellTraits<UnstructuredGrid>::Type faceCells(const UnstructuredGrid& grid)
|
||||
{
|
||||
return FaceCellsProxy(grid);
|
||||
}
|
||||
}
|
||||
}
|
277
opm/core/grid/GridHelpers.hpp
Normal file
277
opm/core/grid/GridHelpers.hpp
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
Copyright 2014 Dr. Markus Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2014 Statoil AS
|
||||
|
||||
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 3 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/>.
|
||||
*/
|
||||
#ifndef OPM_CORE_GRIDHELPERS_HEADER_INCLUDED
|
||||
#define OPM_CORE_GRIDHELPERS_HEADER_INCLUDED
|
||||
#include <opm/core/grid.h>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
namespace UgGridHelpers
|
||||
{
|
||||
|
||||
/// \brief Allows viewing a sparse table consisting out of C-array
|
||||
///
|
||||
/// This class can be used to convert two int array (like they are
|
||||
/// in UnstructuredGrid for representing the cell to faces mapping
|
||||
/// as a sparse table object.
|
||||
class SparseTableView
|
||||
{
|
||||
public:
|
||||
class IntRange : public boost::iterator_range<const int*>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_range<const int*> BaseRowType;
|
||||
typedef BaseRowType::size_type size_type;
|
||||
typedef int value_type;
|
||||
|
||||
IntRange(const int* start, const int* end)
|
||||
: BaseRowType(start, end)
|
||||
{}
|
||||
};
|
||||
/// \brief The type of the roww.
|
||||
typedef boost::iterator_range<const int*> row_type;
|
||||
|
||||
/// \brief Creates a sparse table view
|
||||
/// \param data The array with data of the table.
|
||||
/// \param offset The offsets of the rows. Row i starts
|
||||
/// at offset[i] and ends a offset[i+1]
|
||||
/// \param size The number of entries/rows of the table
|
||||
SparseTableView(int* data, int *offset, std::size_t size)
|
||||
: data_(data), offset_(offset), size_(size)
|
||||
{}
|
||||
|
||||
/// \brief Get a row of the the table.
|
||||
/// \param row The row index.
|
||||
/// \return The corresponding row.
|
||||
row_type operator[](std::size_t row) const
|
||||
{
|
||||
assert(row<=size());
|
||||
return row_type(data_ + offset_[row], data_ + offset_[row+1]);
|
||||
}
|
||||
|
||||
/// \brief Get the size of the table.
|
||||
/// \return the number rows.
|
||||
std::size_t size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
/// \brief Get the number of non-zero entries.
|
||||
std::size_t noEntries() const
|
||||
{
|
||||
return offset_[size_];
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief The array with data of the table.
|
||||
const int* data_;
|
||||
/// \brief offset The offsets of the rows.
|
||||
///
|
||||
/// Row i starts at offset[i] and ends a offset[i+1]
|
||||
const int* offset_;
|
||||
/// \brief The size, i.e. the number of rows.
|
||||
std::size_t size_;
|
||||
};
|
||||
|
||||
/// \brief Get the number of cells of a grid.
|
||||
int numCells(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the number of faces of a grid.
|
||||
int numFaces(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the dimensions of a grid
|
||||
int dimensions(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the number of faces, where each face counts as many times as there are adjacent faces
|
||||
int numCellFaces(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the cartesion dimension of the underlying structured grid.
|
||||
const int* cartDims(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the local to global index mapping.
|
||||
///
|
||||
/// The global index is the index of the active cell
|
||||
/// in the underlying structured grid.
|
||||
const int* globalCell(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Traits of the cell centroids of a grid.
|
||||
///
|
||||
/// This class exports two types: IteratorType, the type of the iterator
|
||||
/// over the cell centroids, and the ValueTpe, the type of the cell centroid.
|
||||
/// \tpatam G The type of the grid.
|
||||
template<class G>
|
||||
struct CellCentroidTraits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CellCentroidTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef const double* IteratorType;
|
||||
typedef const double* ValueType;
|
||||
};
|
||||
|
||||
/// \brief Get an iterator over the cell centroids positioned at the first cell.
|
||||
///
|
||||
/// The return type needs to be usable with the functions increment, and
|
||||
/// getCoordinate.
|
||||
CellCentroidTraits<UnstructuredGrid>::IteratorType
|
||||
beginCellCentroids(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get a coordinate of a specific cell centroid.
|
||||
/// \brief grid The grid.
|
||||
/// \brief cell_index The index of the specific cell.
|
||||
/// \breif coordinate The coordinate index.
|
||||
double cellCentroidCoordinate(const UnstructuredGrid& grid, int cell_index,
|
||||
int coordinate);
|
||||
|
||||
/// \brief Traits of the face centroids of a grid.
|
||||
///
|
||||
/// This class exports two types: IteratorType, the type of the iterator
|
||||
/// over the face centroids, and the ValueTpe, the type of the face centroid.
|
||||
/// \tpatam G The type of the grid.
|
||||
template<class G>
|
||||
struct FaceCentroidTraits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FaceCentroidTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef const double* IteratorType;
|
||||
typedef const double* ValueType;
|
||||
};
|
||||
|
||||
/// \brief Get an iterator over the face centroids positioned at the first cell.
|
||||
FaceCentroidTraits<UnstructuredGrid>::IteratorType
|
||||
beginFaceCentroids(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get a coordinate of a specific face centroid.
|
||||
/// \param grid The grid.
|
||||
/// \param face_index The index of the specific face.
|
||||
/// \param coordinate The coordinate index.
|
||||
FaceCentroidTraits<UnstructuredGrid>::ValueType
|
||||
faceCentroid(const UnstructuredGrid& grid, int face_index);
|
||||
|
||||
/// \brief Get the normal of a face.
|
||||
/// \param grid The grid that the face is part of.
|
||||
/// \param face_index The index of the face in the grid.
|
||||
const double* faceNormal(const UnstructuredGrid& grid, int face_index);
|
||||
|
||||
/// \brief Get the area of a face
|
||||
/// \param grid The grid that the face is part of.
|
||||
/// \param face_index The index of the face in the grid.
|
||||
double faceArea(const UnstructuredGrid& grid, int face_index);
|
||||
|
||||
/// \brief Maps the grid type to the associated type of the cell to faces mapping.
|
||||
///
|
||||
/// Provides a type named Type.
|
||||
/// \tparam T The type of the grid.
|
||||
template<class T>
|
||||
struct Cell2FacesTraits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Cell2FacesTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef SparseTableView Type;
|
||||
};
|
||||
|
||||
/// \brief Get the cell to faces mapping of a grid.
|
||||
Cell2FacesTraits<UnstructuredGrid>::Type
|
||||
cell2Faces(const UnstructuredGrid& grid);
|
||||
|
||||
class FaceCellsProxy
|
||||
{
|
||||
public:
|
||||
FaceCellsProxy(const UnstructuredGrid& grid)
|
||||
: face_cells_(grid.face_cells)
|
||||
{}
|
||||
int operator()(int cell_index, int local_index)
|
||||
{
|
||||
return face_cells_[2*cell_index+local_index];
|
||||
}
|
||||
private:
|
||||
const int* face_cells_;
|
||||
};
|
||||
|
||||
/// \brief Traits of the face to attached cell mappping of a grid.
|
||||
///
|
||||
/// Exports the type Type, the type of the mapping
|
||||
/// \tparam T The type of the grid
|
||||
template<class T>
|
||||
struct FaceCellTraits
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct FaceCellTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef FaceCellsProxy Type;
|
||||
};
|
||||
|
||||
/// \brief Get the face to cell mapping of a grid.
|
||||
FaceCellTraits<UnstructuredGrid>::Type faceCells(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Increment an iterator over an array that reresents a dense row-major
|
||||
/// matrix with dims columns
|
||||
/// \param cc The iterator.
|
||||
/// \param i The nzumber of rows to increment
|
||||
/// \param dim The number of columns of the matrix.
|
||||
template<class T>
|
||||
T* increment(T* cc, int i, int dim)
|
||||
{
|
||||
return cc+(i*dim);
|
||||
}
|
||||
/// \brief Increment an iterator over an array that reresents a dense row-major
|
||||
/// matrix with dims columns
|
||||
/// \param cc The iterator.
|
||||
/// \param i The nzumber of rows to increment
|
||||
template<class T>
|
||||
T increment(const T& t, int i, int)
|
||||
{
|
||||
return t+i;
|
||||
}
|
||||
|
||||
/// \brief Get the i-th corrdinate of a centroid.
|
||||
/// \param cc The array with the coordinates.
|
||||
/// \param i The index of the coordinate.
|
||||
/// \tparam T The type of the coordinate of the centroid.
|
||||
template<class T>
|
||||
double getCoordinate(T* cc, int i)
|
||||
{
|
||||
return cc[i];
|
||||
}
|
||||
|
||||
/// \brief Get the i-th corrdinate of an array.
|
||||
/// \param t The iterator over the centroids
|
||||
/// \brief i The index of the coordinate.
|
||||
/// \tparam T The type of the iterator representing the centroid.
|
||||
/// Its value_type has to provide an operator[] to access the coordinates.
|
||||
template<class T>
|
||||
double getCoordinate(T t, int i)
|
||||
{
|
||||
return (*t)[i];
|
||||
}
|
||||
|
||||
} // end namespace UGGridHelpers
|
||||
} // end namespace OPM
|
||||
#endif
|
@ -378,22 +378,24 @@ private:
|
||||
};
|
||||
|
||||
// enclosure of the current grid in a Cartesian space
|
||||
int cart_size (const UnstructuredGrid& grid) {
|
||||
const int nx = grid.cartdims[0];
|
||||
const int ny = grid.cartdims[1];
|
||||
const int nz = grid.cartdims[2];
|
||||
int cart_size (const int* cartdims) {
|
||||
const int nx = cartdims[0];
|
||||
const int ny = cartdims[1];
|
||||
const int nz = cartdims[2];
|
||||
return nx * ny * nz;
|
||||
}
|
||||
|
||||
void active_cells (const UnstructuredGrid& grid,
|
||||
void active_cells (int number_of_cells,
|
||||
const int* cartdims,
|
||||
const int* global_cell,
|
||||
std::vector <int>& actnum) {
|
||||
// we must fill the Cartesian grid with flags
|
||||
const int size = cart_size (grid);
|
||||
const int size = cart_size (cartdims);
|
||||
|
||||
// if we don't have a global_cells field, then assume that all
|
||||
// grid cells is active
|
||||
if (!grid.global_cell) {
|
||||
if (grid.number_of_cells != size) {
|
||||
if (!global_cell) {
|
||||
if (number_of_cells != size) {
|
||||
OPM_THROW (std::runtime_error,
|
||||
"No ACTNUM map but grid size != Cartesian size");
|
||||
}
|
||||
@ -404,8 +406,8 @@ void active_cells (const UnstructuredGrid& grid,
|
||||
actnum.assign (size, 0);
|
||||
|
||||
// activate those cells that are actually there
|
||||
for (int i = 0; i < grid.number_of_cells; ++i) {
|
||||
actnum[grid.global_cell[i]] = 1;
|
||||
for (int i = 0; i < number_of_cells; ++i) {
|
||||
actnum[global_cell[i]] = 1;
|
||||
}
|
||||
}
|
||||
} // active_cells
|
||||
@ -416,7 +418,9 @@ void active_cells (const UnstructuredGrid& grid,
|
||||
struct EclipseGrid : public EclipseHandle <ecl_grid_type> {
|
||||
/// Create a grid based on the keywords available in input file
|
||||
static EclipseGrid make (const EclipseGridParser& parser,
|
||||
const UnstructuredGrid& grid) {
|
||||
int number_of_cells,
|
||||
const int* cart_dims,
|
||||
const int* global_cell) {
|
||||
if (parser.hasField("DXV")) {
|
||||
// make sure that the DYV and DZV keywords are present if the
|
||||
// DXV keyword is used in the deck...
|
||||
@ -437,7 +441,7 @@ struct EclipseGrid : public EclipseHandle <ecl_grid_type> {
|
||||
|
||||
// get the actually active cells, after processing
|
||||
std::vector <int> actnum;
|
||||
active_cells (grid, actnum);
|
||||
active_cells (number_of_cells, cart_dims, global_cell, actnum);
|
||||
EclipseKeyword<int> actnum_kw (ACTNUM_KW, actnum);
|
||||
|
||||
EclipseKeyword<float> mapaxes_kw (MAPAXES_KW);
|
||||
@ -959,7 +963,8 @@ void EclipseWriter::writeInit(const SimulatorTimer &timer,
|
||||
const SimulatorState& reservoirState,
|
||||
const WellState& wellState) {
|
||||
/* Grid files */
|
||||
EclipseGrid ecl_grid = EclipseGrid::make (*parser_, *grid_);
|
||||
EclipseGrid ecl_grid = EclipseGrid::make (*parser_, number_of_cells_,
|
||||
cart_dims_, global_cell_);
|
||||
ecl_grid.write (outputDir_, baseName_, timer);
|
||||
|
||||
EclipseInit fortio = EclipseInit::make (outputDir_, baseName_, timer);
|
||||
@ -1059,15 +1064,37 @@ void EclipseWriter::writeTimeStep(
|
||||
}
|
||||
|
||||
#endif // HAVE_ERT
|
||||
|
||||
EclipseWriter::EclipseWriter (
|
||||
const ParameterGroup& params,
|
||||
std::shared_ptr <const EclipseGridParser> parser,
|
||||
std::shared_ptr <const UnstructuredGrid> grid)
|
||||
: parser_ (parser)
|
||||
, grid_ (grid)
|
||||
, number_of_cells_(grid->number_of_cells)
|
||||
, dimensions_(grid->dimensions)
|
||||
, cart_dims_(grid->cartdims)
|
||||
, global_cell_(grid->global_cell)
|
||||
, uses_ (phaseUsageFromDeck (*parser)) {
|
||||
|
||||
init(params);
|
||||
}
|
||||
|
||||
EclipseWriter::EclipseWriter (
|
||||
const ParameterGroup& params,
|
||||
std::shared_ptr <const EclipseGridParser> parser,
|
||||
int number_of_cells, const int* global_cell, const int* cart_dims,
|
||||
int dimensions)
|
||||
: parser_ (parser)
|
||||
, number_of_cells_(number_of_cells)
|
||||
, dimensions_(dimensions)
|
||||
, cart_dims_(cart_dims)
|
||||
, global_cell_(global_cell)
|
||||
, uses_ (phaseUsageFromDeck (*parser)) {
|
||||
|
||||
init(params);
|
||||
}
|
||||
|
||||
void EclipseWriter::init(const ParameterGroup& params)
|
||||
{
|
||||
// get the base name from the name of the deck
|
||||
using boost::filesystem::path;
|
||||
path deck (params.get <std::string> ("deck_filename"));
|
||||
|
@ -60,6 +60,11 @@ public:
|
||||
std::shared_ptr <const EclipseGridParser> parser,
|
||||
std::shared_ptr <const UnstructuredGrid> grid);
|
||||
|
||||
EclipseWriter (const parameter::ParameterGroup& params,
|
||||
std::shared_ptr <const EclipseGridParser> parser,
|
||||
int number_of_cells, const int* global_cell, const int* cart_dims,
|
||||
int dimension);
|
||||
|
||||
/**
|
||||
* We need a destructor in the compilation unit to avoid the
|
||||
* EclipseSummary being a complete type here.
|
||||
@ -87,7 +92,10 @@ public:
|
||||
|
||||
private:
|
||||
std::shared_ptr <const EclipseGridParser> parser_;
|
||||
std::shared_ptr <const UnstructuredGrid> grid_;
|
||||
int number_of_cells_;
|
||||
int dimensions_;
|
||||
const int* cart_dims_;
|
||||
const int* global_cell_;
|
||||
std::string outputDir_;
|
||||
std::string baseName_;
|
||||
PhaseUsage uses_; // active phases in the input deck
|
||||
@ -97,6 +105,8 @@ private:
|
||||
void writeSolution (const SimulatorTimer& timer,
|
||||
const SimulatorState& reservoirState,
|
||||
const WellState& wellState);
|
||||
|
||||
void init(const parameter::ParameterGroup& params);
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
|
10
opm/core/pressure/tpfa/TransTpfa.cpp
Normal file
10
opm/core/pressure/tpfa/TransTpfa.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "TransTpfa.hpp"
|
||||
#include <opm/core/grid.h>
|
||||
|
||||
/* Ecplicitly initialize UnstructuredGrid versions */
|
||||
|
||||
template void tpfa_htrans_compute(const UnstructuredGrid*, const double*, double*);
|
||||
|
||||
template void tpfa_trans_compute(const UnstructuredGrid*, const double*, double*);
|
||||
|
||||
template void tpfa_eff_trans_compute(const UnstructuredGrid*, const double*, const double*, double*);
|
179
opm/core/pressure/tpfa/TransTpfa_impl.hpp
Normal file
179
opm/core/pressure/tpfa/TransTpfa_impl.hpp
Normal file
@ -0,0 +1,179 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <opm/core/linalg/blas_lapack.h>
|
||||
#include <opm/core/pressure/tpfa/trans_tpfa.h>
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
|
||||
namespace Dune
|
||||
{
|
||||
class CpGrid;
|
||||
}
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
namespace UgGridHelpers
|
||||
{
|
||||
int dimensions(const Dune::CpGrid&);
|
||||
|
||||
double faceArea(const Dune::CpGrid&, int);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const double* multiplyFaceNormalWithArea(const Dune::CpGrid& grid, int face_index, const double* in)
|
||||
{
|
||||
int d=Opm::UgGridHelpers::dimensions(grid);
|
||||
double* out=new double[d];
|
||||
double area=Opm::UgGridHelpers::faceArea(grid, face_index);
|
||||
|
||||
for(int i=0;i<d;++i)
|
||||
out[i]=in[i]*area;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline const double* multiplyFaceNormalWithArea(const UnstructuredGrid& grid, int face_index, const double* in)
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
||||
inline void maybeFreeFaceNormal(const Dune::CpGrid&, const double* array)
|
||||
{
|
||||
delete[] array;
|
||||
}
|
||||
|
||||
inline void maybeFreeFaceNormal(const UnstructuredGrid&, const double*)
|
||||
{}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* htrans <- sum(C(:,i) .* K(cellNo,:) .* N(:,j), 2) ./ sum(C.*C, 2) */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
template<class Grid>
|
||||
void
|
||||
tpfa_htrans_compute(const Grid* G, const double *perm, double *htrans)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
using namespace Opm::UgGridHelpers;
|
||||
int d, j;
|
||||
double s, dist, denom;
|
||||
|
||||
double Kn[3];
|
||||
typename CellCentroidTraits<Grid>::IteratorType cc = beginCellCentroids(*G);
|
||||
typename Cell2FacesTraits<Grid>::Type c2f = cell2Faces(*G);
|
||||
typename FaceCellTraits<Grid>::Type face_cells = faceCells(*G);
|
||||
|
||||
const double *n;
|
||||
const double *K;
|
||||
|
||||
MAT_SIZE_T nrows, ncols, ldA, incx, incy;
|
||||
double a1, a2;
|
||||
|
||||
d = dimensions(*G);
|
||||
|
||||
nrows = ncols = ldA = d;
|
||||
incx = incy = 1 ;
|
||||
a1 = 1.0; a2 = 0.0 ;
|
||||
|
||||
for (int c =0, i = 0; c < numCells(*G); c++) {
|
||||
K = perm + (c * d * d);
|
||||
|
||||
typedef typename Cell2FacesTraits<Grid>::Type::row_type FaceRow;
|
||||
FaceRow faces = c2f[c];
|
||||
|
||||
for(typename FaceRow::const_iterator f=faces.begin(), end=faces.end();
|
||||
f!=end; ++f, ++i)
|
||||
{
|
||||
s = 2.0*(face_cells(*f, 0) == c) - 1.0;
|
||||
n = faceNormal(*G, *f);
|
||||
const double* nn=multiplyFaceNormalWithArea(*G, *f, n);
|
||||
const double* fc = &(faceCentroid(*G, *f)[0]);
|
||||
dgemv_("No Transpose", &nrows, &ncols,
|
||||
&a1, K, &ldA, nn, &incx, &a2, &Kn[0], &incy);
|
||||
maybeFreeFaceNormal(*G, nn);
|
||||
|
||||
htrans[i] = denom = 0.0;
|
||||
for (j = 0; j < d; j++) {
|
||||
dist = fc[j] - getCoordinate(cc, j);
|
||||
|
||||
htrans[i] += s * dist * Kn[j];
|
||||
denom += dist * dist;
|
||||
}
|
||||
|
||||
assert (denom > 0);
|
||||
htrans[i] /= denom;
|
||||
htrans[i] = fabs(htrans[i]);
|
||||
}
|
||||
// Move to next cell centroid.
|
||||
cc = increment(cc, 1, d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
template<class Grid>
|
||||
void
|
||||
tpfa_trans_compute(const Grid* G, const double *htrans, double *trans)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
using namespace Opm::UgGridHelpers;
|
||||
|
||||
for (int f = 0; f < numFaces(*G); f++) {
|
||||
trans[f] = 0.0;
|
||||
}
|
||||
|
||||
typename Cell2FacesTraits<Grid>::Type c2f = cell2Faces(*G);
|
||||
|
||||
for (int c = 0, i = 0; c < numCells(*G); c++) {
|
||||
typedef typename Cell2FacesTraits<Grid>::Type::row_type FaceRow;
|
||||
FaceRow faces = c2f[c];
|
||||
|
||||
for(typename FaceRow::const_iterator f=faces.begin(), end=faces.end();
|
||||
f!=end; ++f, ++i)
|
||||
{
|
||||
trans[*f] += 1.0 / htrans[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int f = 0; f < numFaces(*G); f++) {
|
||||
trans[f] = 1.0 / trans[f];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
template<class Grid>
|
||||
void
|
||||
tpfa_eff_trans_compute(const Grid* G,
|
||||
const double *totmob,
|
||||
const double *htrans,
|
||||
double *trans)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
using namespace Opm::UgGridHelpers;
|
||||
|
||||
for (int f = 0; f < numFaces(*G); f++) {
|
||||
trans[f] = 0.0;
|
||||
}
|
||||
|
||||
typename Cell2FacesTraits<Grid>::Type c2f = cell2Faces(*G);
|
||||
|
||||
for (int c = 0, i = 0; c < numCells(*G); c++) {
|
||||
typedef typename Cell2FacesTraits<Grid>::Type::row_type FaceRow;
|
||||
FaceRow faces = c2f[c];
|
||||
|
||||
for(typename FaceRow::const_iterator f=faces.begin(), end=faces.end();
|
||||
f!=end; ++f, ++i)
|
||||
{
|
||||
trans[*f] += 1.0 / (totmob[c] * htrans[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int f = 0; f < numFaces(*G); f++) {
|
||||
trans[f] = 1.0 / trans[f];
|
||||
}
|
||||
}
|
@ -7,6 +7,11 @@
|
||||
#include <opm/core/linalg/blas_lapack.h>
|
||||
#include <opm/core/pressure/tpfa/trans_tpfa.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "TransTpfa.hpp"
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* htrans <- sum(C(:,i) .* K(cellNo,:) .* N(:,j), 2) ./ sum(C.*C, 2) */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
@ -14,6 +19,10 @@ void
|
||||
tpfa_htrans_compute(struct UnstructuredGrid *G, const double *perm, double *htrans)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
return tpfa_htrans_compute<UnstructuredGrid>(G, totmob, htrans, trans);
|
||||
#endif
|
||||
|
||||
int c, d, f, i, j;
|
||||
double s, dist, denom;
|
||||
|
||||
@ -65,6 +74,10 @@ void
|
||||
tpfa_trans_compute(struct UnstructuredGrid *G, const double *htrans, double *trans)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
return tpfa_trans_compute<UnstructuredGrid>(G, totmob, htrans, trans);
|
||||
#endif
|
||||
|
||||
int c, i, f;
|
||||
|
||||
for (f = 0; f < G->number_of_faces; f++) {
|
||||
@ -93,6 +106,10 @@ tpfa_eff_trans_compute(struct UnstructuredGrid *G,
|
||||
double *trans)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
return tpfa_eff_trans_compute<UnstructuredGrid>(G, totmob, htrans, trans);
|
||||
#endif
|
||||
|
||||
int c, i, f;
|
||||
|
||||
for (f = 0; f < G->number_of_faces; f++) {
|
||||
|
@ -27,38 +27,17 @@ namespace Opm
|
||||
const UnstructuredGrid& grid,
|
||||
bool init_rock)
|
||||
{
|
||||
if (init_rock){
|
||||
rock_.init(deck, grid);
|
||||
}
|
||||
pvt_.init(deck, 0);
|
||||
SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, 0);
|
||||
|
||||
if (pvt_.numPhases() != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
init(deck, grid.number_of_cells, grid.global_cell, grid.cartdims, grid.cell_centroids,
|
||||
grid.dimensions, init_rock);
|
||||
}
|
||||
|
||||
|
||||
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid,
|
||||
bool init_rock)
|
||||
{
|
||||
if (init_rock){
|
||||
rock_.init(newParserDeck, grid);
|
||||
}
|
||||
pvt_.init(newParserDeck, /*numSamples=*/200);
|
||||
SaturationPropsFromDeck<SatFuncSimpleUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, grid, /*numSamples=*/200);
|
||||
|
||||
if (pvt_.numPhases() != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
init(newParserDeck, grid.number_of_cells, grid.global_cell, grid.cartdims,
|
||||
grid.cell_centroids, grid.dimensions, init_rock);
|
||||
}
|
||||
|
||||
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
|
||||
@ -66,63 +45,8 @@ namespace Opm
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock)
|
||||
{
|
||||
if(init_rock){
|
||||
rock_.init(deck, grid);
|
||||
}
|
||||
|
||||
const int pvt_samples = param.getDefault("pvt_tab_size", 0);
|
||||
pvt_.init(deck, pvt_samples);
|
||||
|
||||
// Unfortunate lack of pointer smartness here...
|
||||
const int sat_samples = param.getDefault("sat_tab_size", 0);
|
||||
std::string threephase_model = param.getDefault<std::string>("threephase_model", "simple");
|
||||
if (deck.hasField("ENDSCALE") && threephase_model != "gwseg") {
|
||||
OPM_THROW(std::runtime_error, "Sorry, end point scaling currently available for the 'gwseg' model only.");
|
||||
}
|
||||
if (sat_samples > 1) {
|
||||
if (threephase_model == "stone2") {
|
||||
SaturationPropsFromDeck<SatFuncStone2Uniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncStone2Uniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, sat_samples);
|
||||
} else if (threephase_model == "simple") {
|
||||
SaturationPropsFromDeck<SatFuncSimpleUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, sat_samples);
|
||||
} else if (threephase_model == "gwseg") {
|
||||
SaturationPropsFromDeck<SatFuncGwsegUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, sat_samples);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
|
||||
}
|
||||
} else {
|
||||
if (threephase_model == "stone2") {
|
||||
SaturationPropsFromDeck<SatFuncStone2Nonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncStone2Nonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, sat_samples);
|
||||
} else if (threephase_model == "simple") {
|
||||
SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, sat_samples);
|
||||
} else if (threephase_model == "gwseg") {
|
||||
SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, sat_samples);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
|
||||
}
|
||||
}
|
||||
|
||||
if (pvt_.numPhases() != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
init(deck, grid.number_of_cells, grid.global_cell, grid.cartdims, grid.cell_centroids,
|
||||
grid.dimensions, param, init_rock);
|
||||
}
|
||||
|
||||
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(Opm::DeckConstPtr newParserDeck,
|
||||
@ -130,63 +54,8 @@ namespace Opm
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock)
|
||||
{
|
||||
if(init_rock){
|
||||
rock_.init(newParserDeck, grid);
|
||||
}
|
||||
|
||||
const int pvt_samples = param.getDefault("pvt_tab_size", 200);
|
||||
pvt_.init(newParserDeck, pvt_samples);
|
||||
|
||||
// Unfortunate lack of pointer smartness here...
|
||||
const int sat_samples = param.getDefault("sat_tab_size", 200);
|
||||
std::string threephase_model = param.getDefault<std::string>("threephase_model", "simple");
|
||||
if (newParserDeck->hasKeyword("ENDSCALE") && threephase_model != "simple") {
|
||||
OPM_THROW(std::runtime_error, "Sorry, end point scaling currently available for the 'simple' model only.");
|
||||
}
|
||||
if (sat_samples > 1) {
|
||||
if (threephase_model == "stone2") {
|
||||
SaturationPropsFromDeck<SatFuncStone2Uniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncStone2Uniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, grid, sat_samples);
|
||||
} else if (threephase_model == "simple") {
|
||||
SaturationPropsFromDeck<SatFuncSimpleUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, grid, sat_samples);
|
||||
} else if (threephase_model == "gwseg") {
|
||||
SaturationPropsFromDeck<SatFuncGwsegUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, grid, sat_samples);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
|
||||
}
|
||||
} else {
|
||||
if (threephase_model == "stone2") {
|
||||
SaturationPropsFromDeck<SatFuncStone2Nonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncStone2Nonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, grid, sat_samples);
|
||||
} else if (threephase_model == "simple") {
|
||||
SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, grid, sat_samples);
|
||||
} else if (threephase_model == "gwseg") {
|
||||
SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, grid, sat_samples);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
|
||||
}
|
||||
}
|
||||
|
||||
if (pvt_.numPhases() != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
init(newParserDeck, grid.number_of_cells, grid.global_cell, grid.cartdims, grid.cell_centroids,
|
||||
grid.dimensions, param, init_rock);
|
||||
}
|
||||
|
||||
BlackoilPropertiesFromDeck::~BlackoilPropertiesFromDeck()
|
||||
|
@ -90,6 +90,45 @@ namespace Opm
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock=true);
|
||||
|
||||
template<class T>
|
||||
BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
bool init_rock=true);
|
||||
|
||||
|
||||
template<class T>
|
||||
BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock=true);
|
||||
|
||||
template<class T>
|
||||
BlackoilPropertiesFromDeck(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
bool init_rock=true);
|
||||
|
||||
template<class T>
|
||||
BlackoilPropertiesFromDeck(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock=true);
|
||||
|
||||
/// Destructor.
|
||||
virtual ~BlackoilPropertiesFromDeck();
|
||||
|
||||
@ -211,6 +250,41 @@ namespace Opm
|
||||
double* smax) const;
|
||||
|
||||
private:
|
||||
template<class T>
|
||||
void init(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
bool init_rock);
|
||||
template<class T>
|
||||
void init(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock);
|
||||
|
||||
template<class T>
|
||||
void init(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
bool init_rock);
|
||||
template<class T>
|
||||
void init(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock);
|
||||
RockFromDeck rock_;
|
||||
BlackoilPvtProperties pvt_;
|
||||
std::unique_ptr<SaturationPropsInterface> satprops_;
|
||||
@ -224,5 +298,6 @@ namespace Opm
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#include "BlackoilPropertiesFromDeck_impl.hpp"
|
||||
|
||||
#endif // OPM_BLACKOILPROPERTIESFROMDECK_HEADER_INCLUDED
|
||||
|
260
opm/core/props/BlackoilPropertiesFromDeck_impl.hpp
Normal file
260
opm/core/props/BlackoilPropertiesFromDeck_impl.hpp
Normal file
@ -0,0 +1,260 @@
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
|
||||
template<class T>
|
||||
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
bool init_rock)
|
||||
{
|
||||
init(deck, number_of_cells, global_cell, cart_dims, begin_cell_centroids, dimension,
|
||||
init_rock);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock)
|
||||
{
|
||||
init(deck, number_of_cells, global_cell, cart_dims, begin_cell_centroids, dimension,
|
||||
param, init_rock);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
bool init_rock)
|
||||
{
|
||||
init(newParserDeck, number_of_cells, global_cell, cart_dims, begin_cell_centroids, dimension,
|
||||
init_rock);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock)
|
||||
{
|
||||
init(newParserDeck, number_of_cells, global_cell, cart_dims, begin_cell_centroids, dimension,
|
||||
param, init_rock);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void BlackoilPropertiesFromDeck::init(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
bool init_rock)
|
||||
{
|
||||
if (init_rock){
|
||||
rock_.init(deck, number_of_cells, global_cell, cart_dims);
|
||||
}
|
||||
pvt_.init(deck, 0);
|
||||
SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, number_of_cells, global_cell, begin_cell_centroids, dimension, 200);
|
||||
|
||||
if (pvt_.numPhases() != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void BlackoilPropertiesFromDeck::init(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
bool init_rock)
|
||||
{
|
||||
if (init_rock){
|
||||
rock_.init(newParserDeck, number_of_cells, global_cell, cart_dims);
|
||||
}
|
||||
pvt_.init(newParserDeck, /*numSamples=*/0);
|
||||
SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, number_of_cells, global_cell, begin_cell_centroids, dimension,
|
||||
/*numSamples=*/0);
|
||||
|
||||
if (pvt_.numPhases() != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void BlackoilPropertiesFromDeck::init(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock)
|
||||
{
|
||||
if(init_rock){
|
||||
rock_.init(deck, number_of_cells, global_cell, cart_dims);
|
||||
}
|
||||
|
||||
const int pvt_samples = param.getDefault("pvt_tab_size", 0);
|
||||
pvt_.init(deck, pvt_samples);
|
||||
|
||||
// Unfortunate lack of pointer smartness here...
|
||||
const int sat_samples = param.getDefault("sat_tab_size", 0);
|
||||
std::string threephase_model = param.getDefault<std::string>("threephase_model", "simple");
|
||||
if (deck.hasField("ENDSCALE") && threephase_model != "simple") {
|
||||
OPM_THROW(std::runtime_error, "Sorry, end point scaling currently available for the 'simple' model only.");
|
||||
}
|
||||
if (sat_samples > 1) {
|
||||
if (threephase_model == "stone2") {
|
||||
SaturationPropsFromDeck<SatFuncStone2Uniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncStone2Uniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, number_of_cells, global_cell, begin_cell_centroids, dimension,
|
||||
sat_samples);
|
||||
} else if (threephase_model == "simple") {
|
||||
SaturationPropsFromDeck<SatFuncSimpleUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, number_of_cells, global_cell, begin_cell_centroids, dimension,
|
||||
sat_samples);
|
||||
} else if (threephase_model == "gwseg") {
|
||||
SaturationPropsFromDeck<SatFuncGwsegUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, number_of_cells, global_cell, begin_cell_centroids, dimension,
|
||||
sat_samples);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
|
||||
}
|
||||
} else {
|
||||
if (threephase_model == "stone2") {
|
||||
SaturationPropsFromDeck<SatFuncStone2Nonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncStone2Nonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, number_of_cells, global_cell, begin_cell_centroids, dimension,
|
||||
sat_samples);
|
||||
} else if (threephase_model == "simple") {
|
||||
SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, number_of_cells, global_cell, begin_cell_centroids, dimension,
|
||||
sat_samples);
|
||||
} else if (threephase_model == "gwseg") {
|
||||
SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, number_of_cells, global_cell, begin_cell_centroids, dimension,
|
||||
sat_samples);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
|
||||
}
|
||||
}
|
||||
|
||||
if (pvt_.numPhases() != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void BlackoilPropertiesFromDeck::init(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const parameter::ParameterGroup& param,
|
||||
bool init_rock)
|
||||
{
|
||||
|
||||
if(init_rock){
|
||||
rock_.init(newParserDeck, number_of_cells, global_cell, cart_dims);
|
||||
}
|
||||
|
||||
const int pvt_samples = param.getDefault("pvt_tab_size", 200);
|
||||
pvt_.init(newParserDeck, pvt_samples);
|
||||
|
||||
// Unfortunate lack of pointer smartness here...
|
||||
const int sat_samples = param.getDefault("sat_tab_size", 200);
|
||||
std::string threephase_model = param.getDefault<std::string>("threephase_model", "simple");
|
||||
if (newParserDeck->hasKeyword("ENDSCALE") && threephase_model != "simple") {
|
||||
OPM_THROW(std::runtime_error, "Sorry, end point scaling currently available for the 'simple' model only.");
|
||||
}
|
||||
if (sat_samples > 1) {
|
||||
if (threephase_model == "stone2") {
|
||||
SaturationPropsFromDeck<SatFuncStone2Uniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncStone2Uniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimension, sat_samples);
|
||||
} else if (threephase_model == "simple") {
|
||||
SaturationPropsFromDeck<SatFuncSimpleUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimension, sat_samples);
|
||||
} else if (threephase_model == "gwseg") {
|
||||
SaturationPropsFromDeck<SatFuncGwsegUniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegUniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimension, sat_samples);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
|
||||
}
|
||||
} else {
|
||||
if (threephase_model == "stone2") {
|
||||
SaturationPropsFromDeck<SatFuncStone2Nonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncStone2Nonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimension, sat_samples);
|
||||
} else if (threephase_model == "simple") {
|
||||
SaturationPropsFromDeck<SatFuncSimpleNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncSimpleNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimension, sat_samples);
|
||||
} else if (threephase_model == "gwseg") {
|
||||
SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(newParserDeck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimension, sat_samples);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown threephase_model: " << threephase_model);
|
||||
}
|
||||
}
|
||||
|
||||
if (pvt_.numPhases() != satprops_->numPhases()) {
|
||||
OPM_THROW(std::runtime_error, "BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
|
||||
<< pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,45 +65,58 @@ namespace Opm
|
||||
void RockFromDeck::init(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid)
|
||||
{
|
||||
assignPorosity(deck, grid);
|
||||
permfield_valid_.assign(grid.number_of_cells, false);
|
||||
init(deck, grid.number_of_cells, grid.global_cell, grid.cartdims);
|
||||
}
|
||||
|
||||
/// Initialize from deck and cell mapping.
|
||||
/// \param deck Deck input parser
|
||||
/// \param number_of_cells The number of cells in the grid.
|
||||
/// \param global_cell The mapping fom local to global cell indices.
|
||||
/// global_cell[i] is the corresponding global index of i.
|
||||
/// \param cart_dims The size of the underlying cartesian grid.
|
||||
void RockFromDeck::init(const EclipseGridParser& deck,
|
||||
int number_of_cells, const int* global_cell,
|
||||
const int* cart_dims)
|
||||
{
|
||||
assignPorosity(deck, number_of_cells, global_cell);
|
||||
permfield_valid_.assign(number_of_cells, false);
|
||||
const double perm_threshold = 0.0; // Maybe turn into parameter?
|
||||
assignPermeability(deck, grid, perm_threshold);
|
||||
assignPermeability(deck, number_of_cells, global_cell, cart_dims, perm_threshold);
|
||||
}
|
||||
|
||||
void RockFromDeck::init(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid)
|
||||
int number_of_cells, const int* global_cell,
|
||||
const int* cart_dims)
|
||||
{
|
||||
assignPorosity(newParserDeck, grid);
|
||||
permfield_valid_.assign(grid.number_of_cells, false);
|
||||
assignPorosity(newParserDeck, number_of_cells, global_cell);
|
||||
permfield_valid_.assign(number_of_cells, false);
|
||||
const double perm_threshold = 0.0; // Maybe turn into parameter?
|
||||
assignPermeability(newParserDeck, grid, perm_threshold);
|
||||
assignPermeability(newParserDeck, number_of_cells, global_cell, cart_dims,
|
||||
perm_threshold);
|
||||
}
|
||||
|
||||
|
||||
void RockFromDeck::assignPorosity(const EclipseGridParser& parser,
|
||||
const UnstructuredGrid& grid)
|
||||
int number_of_cells, const int* global_cell)
|
||||
{
|
||||
porosity_.assign(grid.number_of_cells, 1.0);
|
||||
const int* gc = grid.global_cell;
|
||||
porosity_.assign(number_of_cells, 1.0);
|
||||
if (parser.hasField("PORO")) {
|
||||
const std::vector<double>& poro = parser.getFloatingPointValue("PORO");
|
||||
for (int c = 0; c < int(porosity_.size()); ++c) {
|
||||
const int deck_pos = (gc == NULL) ? c : gc[c];
|
||||
const int deck_pos = (global_cell == NULL) ? c : global_cell[c];
|
||||
porosity_[c] = poro[deck_pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RockFromDeck::assignPorosity(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid)
|
||||
int number_of_cells, const int* global_cell)
|
||||
{
|
||||
porosity_.assign(grid.number_of_cells, 1.0);
|
||||
const int* gc = grid.global_cell;
|
||||
porosity_.assign(number_of_cells, 1.0);
|
||||
if (newParserDeck->hasKeyword("PORO")) {
|
||||
const std::vector<double>& poro = newParserDeck->getKeyword("PORO")->getSIDoubleData();
|
||||
for (int c = 0; c < int(porosity_.size()); ++c) {
|
||||
const int deck_pos = (gc == NULL) ? c : gc[c];
|
||||
const int deck_pos = (global_cell == NULL) ? c : global_cell[c];
|
||||
assert(0 <= c && c < (int) porosity_.size());
|
||||
assert(0 <= deck_pos && deck_pos < (int) poro.size());
|
||||
porosity_[c] = poro[deck_pos];
|
||||
@ -113,16 +126,17 @@ namespace Opm
|
||||
|
||||
|
||||
void RockFromDeck::assignPermeability(const EclipseGridParser& parser,
|
||||
const UnstructuredGrid& grid,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cartdims,
|
||||
double perm_threshold)
|
||||
{
|
||||
const int dim = 3;
|
||||
const int num_global_cells = grid.cartdims[0]*grid.cartdims[1]*grid.cartdims[2];
|
||||
const int nc = grid.number_of_cells;
|
||||
const int num_global_cells = cartdims[0]*cartdims[1]*cartdims[2];
|
||||
|
||||
assert(num_global_cells > 0);
|
||||
|
||||
permeability_.assign(dim * dim * nc, 0.0);
|
||||
permeability_.assign(dim * dim * number_of_cells, 0.0);
|
||||
|
||||
std::vector<const std::vector<double>*> tensor;
|
||||
tensor.reserve(10);
|
||||
@ -144,13 +158,12 @@ namespace Opm
|
||||
// chosen) default value...
|
||||
//
|
||||
if (tensor.size() > 1) {
|
||||
const int* gc = grid.global_cell;
|
||||
int off = 0;
|
||||
|
||||
for (int c = 0; c < nc; ++c, off += dim*dim) {
|
||||
for (int c = 0; c < number_of_cells; ++c, off += dim*dim) {
|
||||
// SharedPermTensor K(dim, dim, &permeability_[off]);
|
||||
int kix = 0;
|
||||
const int glob = (gc == NULL) ? c : gc[c];
|
||||
const int glob = (global_cell == NULL) ? c : global_cell[c];
|
||||
|
||||
for (int i = 0; i < dim; ++i) {
|
||||
for (int j = 0; j < dim; ++j, ++kix) {
|
||||
@ -167,12 +180,14 @@ namespace Opm
|
||||
}
|
||||
|
||||
void RockFromDeck::assignPermeability(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cartdims,
|
||||
double perm_threshold)
|
||||
{
|
||||
const int dim = 3;
|
||||
const int num_global_cells = grid.cartdims[0]*grid.cartdims[1]*grid.cartdims[2];
|
||||
const int nc = grid.number_of_cells;
|
||||
const int num_global_cells = cartdims[0]*cartdims[1]*cartdims[2];
|
||||
const int nc = number_of_cells;
|
||||
|
||||
assert(num_global_cells > 0);
|
||||
|
||||
@ -198,7 +213,7 @@ namespace Opm
|
||||
// chosen) default value...
|
||||
//
|
||||
if (tensor.size() > 1) {
|
||||
const int* gc = grid.global_cell;
|
||||
const int* gc = global_cell;
|
||||
int off = 0;
|
||||
|
||||
for (int c = 0; c < nc; ++c, off += dim*dim) {
|
||||
|
@ -46,13 +46,24 @@ namespace Opm
|
||||
void init(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid);
|
||||
|
||||
/// Initialize from deck and grid.
|
||||
/// \param newParserDeck Deck produced by the opm-parser code
|
||||
/// \param grid Grid to which property object applies, needed for the
|
||||
/// mapping from cell indices (typically from a processed grid)
|
||||
/// to logical cartesian indices consistent with the deck.
|
||||
/// Initialize from deck and cell mapping.
|
||||
/// \param deck Deck input parser
|
||||
/// \param number_of_cells The number of cells in the grid.
|
||||
/// \param global_cell The mapping fom local to global cell indices.
|
||||
/// global_cell[i] is the corresponding global index of i.
|
||||
/// \param cart_dims The size of the underlying cartesian grid.
|
||||
void init(const EclipseGridParser& deck,
|
||||
int number_of_cells, const int* global_cell,
|
||||
const int* cart_dims);
|
||||
/// Initialize from deck and cell mapping.
|
||||
/// \param newParserDeck Deck produced by the opm-parser code
|
||||
/// \param number_of_cells The number of cells in the grid.
|
||||
/// \param global_cell The mapping fom local to global cell indices.
|
||||
/// global_cell[i] is the corresponding global index of i.
|
||||
/// \param cart_dims The size of the underlying cartesian grid.
|
||||
void init(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid);
|
||||
int number_of_cells, const int* global_cell,
|
||||
const int* cart_dims);
|
||||
|
||||
/// \return D, the number of spatial dimensions. Always 3 for deck input.
|
||||
int numDimensions() const
|
||||
@ -82,14 +93,20 @@ namespace Opm
|
||||
|
||||
private:
|
||||
void assignPorosity(const EclipseGridParser& parser,
|
||||
const UnstructuredGrid& grid);
|
||||
int number_of_cells,
|
||||
const int* global_cell);
|
||||
void assignPorosity(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid);
|
||||
int number_of_cells,
|
||||
const int* global_cell);
|
||||
void assignPermeability(const EclipseGridParser& parser,
|
||||
const UnstructuredGrid& grid,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
const double perm_threshold);
|
||||
void assignPermeability(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
double perm_threshold);
|
||||
|
||||
std::vector<double> porosity_;
|
||||
|
@ -64,7 +64,29 @@ namespace Opm
|
||||
const int samples);
|
||||
|
||||
/// Initialize from deck and grid.
|
||||
/// \param[in] deck Deck input parser
|
||||
/// \param[in] deck Deck input parser
|
||||
/// \param[in] number_of_cells The number of cells of the grid to which property
|
||||
/// object applies, needed for the
|
||||
/// mapping from cell indices (typically from a processed
|
||||
/// grid) to logical cartesian indices consistent with the
|
||||
/// deck.
|
||||
/// \param[in] global_cell The mapping from local cell indices of the grid to
|
||||
/// global cell indices used in the deck.
|
||||
/// \param[in] begin_cell_centroids Pointer to the first cell_centroid of the grid.
|
||||
/// \param[in] dimensions The dimensions of the grid.
|
||||
/// \param[in] samples Number of uniform sample points for saturation tables.
|
||||
/// \tparam T The iterator Type for the cell centroids.
|
||||
/// NOTE: samples will only be used with the SatFuncSetUniform template argument.
|
||||
template<class T>
|
||||
void init(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions,
|
||||
const int samples);
|
||||
|
||||
/// Initialize from deck and grid.
|
||||
/// \param[in] newParserDeck Deck input parser
|
||||
/// \param[in] grid Grid to which property object applies, needed for the
|
||||
/// mapping from cell indices (typically from a processed grid)
|
||||
/// to logical cartesian indices consistent with the deck.
|
||||
@ -74,6 +96,27 @@ namespace Opm
|
||||
const UnstructuredGrid& grid,
|
||||
const int samples);
|
||||
|
||||
/// Initialize from deck and grid.
|
||||
/// \param[in] newParserDeck Deck input parser
|
||||
/// \param[in] number_of_cells The number of cells of the grid to which property
|
||||
/// object applies, needed for the
|
||||
/// mapping from cell indices (typically from a processed
|
||||
/// grid) to logical cartesian indices consistent with the
|
||||
/// deck.
|
||||
/// \param[in] global_cell The mapping from local cell indices of the grid to
|
||||
/// global cell indices used in the deck.
|
||||
/// \param[in] begin_cell_centroids Pointer to the first cell_centroid of the grid.
|
||||
/// \param[in] dimensions The dimensions of the grid.
|
||||
/// \param[in] samples Number of uniform sample points for saturation tables.
|
||||
/// NOTE: samples will only be used with the SatFuncSetUniform template argument.
|
||||
template<class T>
|
||||
void init(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions,
|
||||
const int samples);
|
||||
|
||||
/// \return P, the number of phases.
|
||||
int numPhases() const;
|
||||
|
||||
@ -138,20 +181,45 @@ namespace Opm
|
||||
typedef SatFuncSet Funcs;
|
||||
|
||||
const Funcs& funcForCell(const int cell) const;
|
||||
|
||||
template<class T>
|
||||
void initEPS(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid);
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions);
|
||||
template<class T>
|
||||
void initEPSHyst(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid);
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions);
|
||||
template<class T>
|
||||
void initEPSKey(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions,
|
||||
const std::string& keyword,
|
||||
std::vector<double>& scaleparam);
|
||||
template<class T>
|
||||
void initEPS(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid);
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions);
|
||||
template<class T>
|
||||
void initEPSHyst(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid);
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions);
|
||||
template<class T>
|
||||
void initEPSKey(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions,
|
||||
const std::string& keyword,
|
||||
std::vector<double>& scaleparam);
|
||||
void initEPSParam(const int cell,
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <opm/core/utility/NonuniformTableLinear.hpp>
|
||||
#include <opm/core/props/phaseUsageFromDeck.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Utility/EndscaleWrapper.hpp>
|
||||
#include <opm/parser/eclipse/Utility/ScalecrsWrapper.hpp>
|
||||
@ -51,6 +52,20 @@ namespace Opm
|
||||
void SaturationPropsFromDeck<SatFuncSet>::init(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
const int samples)
|
||||
{
|
||||
init(deck, grid.number_of_cells, grid.global_cell, grid.cell_centroids,
|
||||
grid.dimensions, samples);
|
||||
}
|
||||
|
||||
/// Initialize from deck.
|
||||
template <class SatFuncSet>
|
||||
template< class T>
|
||||
void SaturationPropsFromDeck<SatFuncSet>::init(const EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions,
|
||||
const int samples)
|
||||
{
|
||||
phase_usage_ = phaseUsageFromDeck(deck);
|
||||
|
||||
@ -66,11 +81,9 @@ namespace Opm
|
||||
if (deck.hasField("SATNUM")) {
|
||||
const std::vector<int>& satnum = deck.getIntegerValue("SATNUM");
|
||||
satfuncs_expected = *std::max_element(satnum.begin(), satnum.end());
|
||||
const int num_cells = grid.number_of_cells;
|
||||
cell_to_func_.resize(num_cells);
|
||||
const int* gc = grid.global_cell;
|
||||
for (int cell = 0; cell < num_cells; ++cell) {
|
||||
const int deck_pos = (gc == NULL) ? cell : gc[cell];
|
||||
cell_to_func_.resize(number_of_cells);
|
||||
for (int cell = 0; cell < number_of_cells; ++cell) {
|
||||
const int deck_pos = (global_cell == NULL) ? cell : global_cell[cell];
|
||||
cell_to_func_[cell] = satnum[deck_pos] - 1;
|
||||
}
|
||||
}
|
||||
@ -124,8 +137,7 @@ namespace Opm
|
||||
}
|
||||
}
|
||||
do_eps_ = true;
|
||||
|
||||
initEPS(deck, grid);
|
||||
initEPS(deck, number_of_cells, global_cell, begin_cell_centroids, dimensions);
|
||||
|
||||
// For now, a primitive detection of hysteresis. TODO: SATOPTS HYSTER/ and EHYSTR
|
||||
do_hyst_ = deck.hasField("ISWL") || deck.hasField("ISWU") || deck.hasField("ISWCR") || deck.hasField("ISGL") ||
|
||||
@ -137,7 +149,8 @@ namespace Opm
|
||||
deck.hasField("IKRGR") || deck.hasField("IKRORW") || deck.hasField("IKRORG") ) {
|
||||
OPM_THROW(std::runtime_error, "SaturationPropsFromDeck::init() -- ENDSCALE: Currently hysteresis and relperm value scaling can not be combined.");
|
||||
}
|
||||
initEPSHyst(deck, grid);
|
||||
initEPSHyst(deck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimensions);
|
||||
}
|
||||
|
||||
//OPM_THROW(std::runtime_error, "SaturationPropsFromDeck::init() -- ENDSCALE: Under construction ...");
|
||||
@ -150,6 +163,21 @@ namespace Opm
|
||||
void SaturationPropsFromDeck<SatFuncSet>::init(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid,
|
||||
const int samples)
|
||||
{
|
||||
this->template init<SatFuncSet>(newParserDeck, grid.number_of_cells,
|
||||
grid.global_cell, grid.cell_centroids,
|
||||
grid.dimensions, samples);
|
||||
}
|
||||
|
||||
/// Initialize from deck.
|
||||
template <class SatFuncSet>
|
||||
template<class T>
|
||||
void SaturationPropsFromDeck<SatFuncSet>::init(Opm::DeckConstPtr newParserDeck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroids,
|
||||
int dimensions,
|
||||
const int samples)
|
||||
{
|
||||
phase_usage_ = phaseUsageFromDeck(newParserDeck);
|
||||
|
||||
@ -165,9 +193,9 @@ namespace Opm
|
||||
if (newParserDeck->hasKeyword("SATNUM")) {
|
||||
const std::vector<int>& satnum = newParserDeck->getKeyword("SATNUM")->getIntData();
|
||||
satfuncs_expected = *std::max_element(satnum.begin(), satnum.end());
|
||||
const int num_cells = grid.number_of_cells;
|
||||
const int num_cells = number_of_cells;
|
||||
cell_to_func_.resize(num_cells);
|
||||
const int* gc = grid.global_cell;
|
||||
const int* gc = global_cell;
|
||||
for (int cell = 0; cell < num_cells; ++cell) {
|
||||
const int newParserDeck_pos = (gc == NULL) ? cell : gc[cell];
|
||||
cell_to_func_[cell] = satnum[newParserDeck_pos] - 1;
|
||||
@ -225,7 +253,8 @@ namespace Opm
|
||||
}
|
||||
do_eps_ = true;
|
||||
|
||||
initEPS(newParserDeck, grid);
|
||||
initEPS(newParserDeck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimensions);
|
||||
|
||||
// For now, a primitive detection of hysteresis. TODO: SATOPTS HYSTER/ and EHYSTR
|
||||
do_hyst_ =
|
||||
@ -257,7 +286,8 @@ namespace Opm
|
||||
"Currently hysteresis and relperm value scaling "
|
||||
"cannot be combined.");
|
||||
}
|
||||
initEPSHyst(newParserDeck, grid);
|
||||
initEPSHyst(newParserDeck, number_of_cells, global_cell, begin_cell_centroids,
|
||||
dimensions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -441,31 +471,51 @@ namespace Opm
|
||||
return cell_to_func_.empty() ? satfuncset_[0] : satfuncset_[cell_to_func_[cell]];
|
||||
}
|
||||
|
||||
// Initialize saturation scaling parameters
|
||||
|
||||
// Initialize saturation scaling parameter
|
||||
template <class SatFuncSet>
|
||||
template <class T>
|
||||
void SaturationPropsFromDeck<SatFuncSet>::initEPS(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid)
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroid,
|
||||
int dimensions)
|
||||
{
|
||||
std::vector<double> swl, swcr, swu, sgl, sgcr, sgu, sowcr, sogcr;
|
||||
std::vector<double> krw, krg, kro, krwr, krgr, krorw, krorg;
|
||||
// Initialize saturation scaling parameter
|
||||
initEPSKey(deck, grid, std::string("SWL"), swl);
|
||||
initEPSKey(deck, grid, std::string("SWU"), swu);
|
||||
initEPSKey(deck, grid, std::string("SWCR"), swcr);
|
||||
initEPSKey(deck, grid, std::string("SGL"), sgl);
|
||||
initEPSKey(deck, grid, std::string("SGU"), sgu);
|
||||
initEPSKey(deck, grid, std::string("SGCR"), sgcr);
|
||||
initEPSKey(deck, grid, std::string("SOWCR"), sowcr);
|
||||
initEPSKey(deck, grid, std::string("SOGCR"), sogcr);
|
||||
initEPSKey(deck, grid, std::string("KRW"), krw);
|
||||
initEPSKey(deck, grid, std::string("KRG"), krg);
|
||||
initEPSKey(deck, grid, std::string("KRO"), kro);
|
||||
initEPSKey(deck, grid, std::string("KRWR"), krwr);
|
||||
initEPSKey(deck, grid, std::string("KRGR"), krgr);
|
||||
initEPSKey(deck, grid, std::string("KRORW"), krorw);
|
||||
initEPSKey(deck, grid, std::string("KRORG"), krorg);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SWL"), swl);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SWU"), swu);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SWCR"), swcr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SGL"), sgl);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SGU"), sgu);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SGCR"), sgcr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SOWCR"), sowcr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SOGCR"), sogcr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRW"), krw);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRG"), krg);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRO"), kro);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRWR"), krwr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRGR"), krgr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRORW"), krorw);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRORG"), krorg);
|
||||
|
||||
eps_transf_.resize(grid.number_of_cells);
|
||||
eps_transf_.resize(number_of_cells);
|
||||
|
||||
const int wpos = phase_usage_.phase_pos[BlackoilPhases::Aqua];
|
||||
const int gpos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
|
||||
@ -473,7 +523,7 @@ namespace Opm
|
||||
const bool oilGas = !phase_usage_.phase_used[Aqua] && phase_usage_.phase_used[Liquid] && phase_usage_.phase_used[Vapour];
|
||||
const bool threephase = phase_usage_.phase_used[Aqua] && phase_usage_.phase_used[Liquid] && phase_usage_.phase_used[Vapour];
|
||||
|
||||
for (int cell = 0; cell < grid.number_of_cells; ++cell) {
|
||||
for (int cell = 0; cell < number_of_cells; ++cell) {
|
||||
if (oilWater) {
|
||||
// ### krw
|
||||
initEPSParam(cell, eps_transf_[cell].wat, false, funcForCell(cell).smin_[wpos], funcForCell(cell).swcr_, funcForCell(cell).smax_[wpos],
|
||||
@ -507,29 +557,48 @@ namespace Opm
|
||||
|
||||
// Initialize saturation scaling parameters
|
||||
template <class SatFuncSet>
|
||||
template<class T>
|
||||
void SaturationPropsFromDeck<SatFuncSet>::initEPS(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid)
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroid,
|
||||
int dimensions)
|
||||
{
|
||||
std::vector<double> swl, swcr, swu, sgl, sgcr, sgu, sowcr, sogcr;
|
||||
std::vector<double> krw, krg, kro, krwr, krgr, krorw, krorg;
|
||||
// Initialize saturation scaling parameter
|
||||
initEPSKey(newParserDeck, grid, std::string("SWL"), swl);
|
||||
initEPSKey(newParserDeck, grid, std::string("SWU"), swu);
|
||||
initEPSKey(newParserDeck, grid, std::string("SWCR"), swcr);
|
||||
initEPSKey(newParserDeck, grid, std::string("SGL"), sgl);
|
||||
initEPSKey(newParserDeck, grid, std::string("SGU"), sgu);
|
||||
initEPSKey(newParserDeck, grid, std::string("SGCR"), sgcr);
|
||||
initEPSKey(newParserDeck, grid, std::string("SOWCR"), sowcr);
|
||||
initEPSKey(newParserDeck, grid, std::string("SOGCR"), sogcr);
|
||||
initEPSKey(newParserDeck, grid, std::string("KRW"), krw);
|
||||
initEPSKey(newParserDeck, grid, std::string("KRG"), krg);
|
||||
initEPSKey(newParserDeck, grid, std::string("KRO"), kro);
|
||||
initEPSKey(newParserDeck, grid, std::string("KRWR"), krwr);
|
||||
initEPSKey(newParserDeck, grid, std::string("KRGR"), krgr);
|
||||
initEPSKey(newParserDeck, grid, std::string("KRORW"), krorw);
|
||||
initEPSKey(newParserDeck, grid, std::string("KRORG"), krorg);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SWL"), swl);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SWU"), swu);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SWCR"), swcr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SGL"), sgl);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SGU"), sgu);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SGCR"), sgcr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SOWCR"), sowcr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("SOGCR"), sogcr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRW"), krw);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRG"), krg);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRO"), kro);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRWR"), krwr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRGR"), krgr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRORW"), krorw);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("KRORG"), krorg);
|
||||
|
||||
eps_transf_.resize(grid.number_of_cells);
|
||||
eps_transf_.resize(number_of_cells);
|
||||
|
||||
const int wpos = phase_usage_.phase_pos[BlackoilPhases::Aqua];
|
||||
const int gpos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
|
||||
@ -537,7 +606,7 @@ namespace Opm
|
||||
const bool oilGas = !phase_usage_.phase_used[Aqua] && phase_usage_.phase_used[Liquid] && phase_usage_.phase_used[Vapour];
|
||||
const bool threephase = phase_usage_.phase_used[Aqua] && phase_usage_.phase_used[Liquid] && phase_usage_.phase_used[Vapour];
|
||||
|
||||
for (int cell = 0; cell < grid.number_of_cells; ++cell) {
|
||||
for (int cell = 0; cell < number_of_cells; ++cell) {
|
||||
if (oilWater) {
|
||||
// ### krw
|
||||
initEPSParam(cell, eps_transf_[cell].wat, false, funcForCell(cell).smin_[wpos], funcForCell(cell).swcr_, funcForCell(cell).smax_[wpos],
|
||||
@ -571,31 +640,50 @@ namespace Opm
|
||||
|
||||
// Initialize hysteresis saturation scaling parameters
|
||||
template <class SatFuncSet>
|
||||
template<class T>
|
||||
void SaturationPropsFromDeck<SatFuncSet>::initEPSHyst(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid)
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroid,
|
||||
int dimensions)
|
||||
{
|
||||
std::vector<double> iswl, iswcr, iswu, isgl, isgcr, isgu, isowcr, isogcr;
|
||||
std::vector<double> ikrw, ikrg, ikro, ikrwr, ikrgr, ikrorw, ikrorg;
|
||||
// Initialize hysteresis saturation scaling parameters
|
||||
initEPSKey(deck, grid, std::string("ISWL"), iswl);
|
||||
initEPSKey(deck, grid, std::string("ISWU"), iswu);
|
||||
initEPSKey(deck, grid, std::string("ISWCR"), iswcr);
|
||||
initEPSKey(deck, grid, std::string("ISGL"), isgl);
|
||||
initEPSKey(deck, grid, std::string("ISGU"), isgu);
|
||||
initEPSKey(deck, grid, std::string("ISGCR"), isgcr);
|
||||
initEPSKey(deck, grid, std::string("ISOWCR"), isowcr);
|
||||
initEPSKey(deck, grid, std::string("ISOGCR"), isogcr);
|
||||
initEPSKey(deck, grid, std::string("IKRW"), ikrw);
|
||||
initEPSKey(deck, grid, std::string("IKRG"), ikrg);
|
||||
initEPSKey(deck, grid, std::string("IKRO"), ikro);
|
||||
initEPSKey(deck, grid, std::string("IKRWR"), ikrwr);
|
||||
initEPSKey(deck, grid, std::string("IKRGR"), ikrgr);
|
||||
initEPSKey(deck, grid, std::string("IKRORW"), ikrorw);
|
||||
initEPSKey(deck, grid, std::string("IKRORG"), ikrorg);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISWL"), iswl);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISWU"), iswu);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISWCR"), iswcr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISGL"), isgl);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISGU"), isgu);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISGCR"), isgcr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISOWCR"), isowcr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISOGCR"), isogcr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRW"), ikrw);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRG"), ikrg);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRO"), ikro);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRWR"), ikrwr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRGR"), ikrgr);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRORW"), ikrorw);
|
||||
initEPSKey(deck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRORG"), ikrorg);
|
||||
|
||||
|
||||
eps_transf_hyst_.resize(grid.number_of_cells);
|
||||
sat_hyst_.resize(grid.number_of_cells);
|
||||
eps_transf_hyst_.resize(number_of_cells);
|
||||
sat_hyst_.resize(number_of_cells);
|
||||
|
||||
const int wpos = phase_usage_.phase_pos[BlackoilPhases::Aqua];
|
||||
const int gpos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
|
||||
@ -603,7 +691,7 @@ namespace Opm
|
||||
const bool oilGas = !phase_usage_.phase_used[Aqua] && phase_usage_.phase_used[Liquid] && phase_usage_.phase_used[Vapour];
|
||||
const bool threephase = phase_usage_.phase_used[Aqua] && phase_usage_.phase_used[Liquid] && phase_usage_.phase_used[Vapour];
|
||||
|
||||
for (int cell = 0; cell < grid.number_of_cells; ++cell) {
|
||||
for (int cell = 0; cell < number_of_cells; ++cell) {
|
||||
if (oilWater) {
|
||||
// ### krw
|
||||
initEPSParam(cell, eps_transf_hyst_[cell].wat, false, funcForCell(cell).smin_[wpos], funcForCell(cell).swcr_, funcForCell(cell).smax_[wpos],
|
||||
@ -637,30 +725,49 @@ namespace Opm
|
||||
|
||||
// Initialize hysteresis saturation scaling parameters
|
||||
template <class SatFuncSet>
|
||||
template<class T>
|
||||
void SaturationPropsFromDeck<SatFuncSet>::initEPSHyst(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid)
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroid,
|
||||
int dimensions)
|
||||
{
|
||||
std::vector<double> iswl, iswcr, iswu, isgl, isgcr, isgu, isowcr, isogcr;
|
||||
std::vector<double> ikrw, ikrg, ikro, ikrwr, ikrgr, ikrorw, ikrorg;
|
||||
// Initialize hysteresis saturation scaling parameters
|
||||
initEPSKey(newParserDeck, grid, std::string("ISWL"), iswl);
|
||||
initEPSKey(newParserDeck, grid, std::string("ISWU"), iswu);
|
||||
initEPSKey(newParserDeck, grid, std::string("ISWCR"), iswcr);
|
||||
initEPSKey(newParserDeck, grid, std::string("ISGL"), isgl);
|
||||
initEPSKey(newParserDeck, grid, std::string("ISGU"), isgu);
|
||||
initEPSKey(newParserDeck, grid, std::string("ISGCR"), isgcr);
|
||||
initEPSKey(newParserDeck, grid, std::string("ISOWCR"), isowcr);
|
||||
initEPSKey(newParserDeck, grid, std::string("ISOGCR"), isogcr);
|
||||
initEPSKey(newParserDeck, grid, std::string("IKRW"), ikrw);
|
||||
initEPSKey(newParserDeck, grid, std::string("IKRG"), ikrg);
|
||||
initEPSKey(newParserDeck, grid, std::string("IKRO"), ikro);
|
||||
initEPSKey(newParserDeck, grid, std::string("IKRWR"), ikrwr);
|
||||
initEPSKey(newParserDeck, grid, std::string("IKRGR"), ikrgr);
|
||||
initEPSKey(newParserDeck, grid, std::string("IKRORW"), ikrorw);
|
||||
initEPSKey(newParserDeck, grid, std::string("IKRORG"), ikrorg);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISWL"), iswl);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISWU"), iswu);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISWCR"), iswcr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISGL"), isgl);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISGU"), isgu);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISGCR"), isgcr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISOWCR"), isowcr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("ISOGCR"), isogcr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRW"), ikrw);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRG"), ikrg);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRO"), ikro);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRWR"), ikrwr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRGR"), ikrgr);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRORW"), ikrorw);
|
||||
initEPSKey(newParserDeck, number_of_cells, global_cell, begin_cell_centroid, dimensions,
|
||||
std::string("IKRORG"), ikrorg);
|
||||
|
||||
eps_transf_hyst_.resize(grid.number_of_cells);
|
||||
sat_hyst_.resize(grid.number_of_cells);
|
||||
eps_transf_hyst_.resize(number_of_cells);
|
||||
sat_hyst_.resize(number_of_cells);
|
||||
|
||||
const int wpos = phase_usage_.phase_pos[BlackoilPhases::Aqua];
|
||||
const int gpos = phase_usage_.phase_pos[BlackoilPhases::Vapour];
|
||||
@ -668,7 +775,7 @@ namespace Opm
|
||||
const bool oilGas = !phase_usage_.phase_used[Aqua] && phase_usage_.phase_used[Liquid] && phase_usage_.phase_used[Vapour];
|
||||
const bool threephase = phase_usage_.phase_used[Aqua] && phase_usage_.phase_used[Liquid] && phase_usage_.phase_used[Vapour];
|
||||
|
||||
for (int cell = 0; cell < grid.number_of_cells; ++cell) {
|
||||
for (int cell = 0; cell < number_of_cells; ++cell) {
|
||||
if (oilWater) {
|
||||
// ### krw
|
||||
initEPSParam(cell, eps_transf_hyst_[cell].wat, false, funcForCell(cell).smin_[wpos], funcForCell(cell).swcr_, funcForCell(cell).smax_[wpos],
|
||||
@ -702,8 +809,12 @@ namespace Opm
|
||||
|
||||
// Initialize saturation scaling parameter
|
||||
template <class SatFuncSet>
|
||||
template<class T>
|
||||
void SaturationPropsFromDeck<SatFuncSet>::initEPSKey(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroid,
|
||||
int dimensions,
|
||||
const std::string& keyword,
|
||||
std::vector<double>& scaleparam)
|
||||
{
|
||||
@ -724,57 +835,57 @@ namespace Opm
|
||||
if (keyword == std::string("SWL") || keyword == std::string("ISWL") ) {
|
||||
if (useAqua && (useKeyword || deck.getENPTVD().mask_[0])) {
|
||||
itab = 1;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).smin_[phase_pos_aqua];
|
||||
}
|
||||
} else if (keyword == std::string("SWCR") || keyword == std::string("ISWCR") ) {
|
||||
if (useAqua && (useKeyword || deck.getENPTVD().mask_[1])) {
|
||||
itab = 2;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).swcr_;
|
||||
}
|
||||
} else if (keyword == std::string("SWU") || keyword == std::string("ISWU") ) {
|
||||
if (useAqua && (useKeyword || deck.getENPTVD().mask_[2])) {
|
||||
itab = 3;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).smax_[phase_pos_aqua];
|
||||
}
|
||||
} else if (keyword == std::string("SGL") || keyword == std::string("ISGL") ) {
|
||||
if (useVapour && (useKeyword || deck.getENPTVD().mask_[3])) {
|
||||
itab = 4;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).smin_[phase_pos_vapour];
|
||||
}
|
||||
} else if (keyword == std::string("SGCR") || keyword == std::string("ISGCR") ) {
|
||||
if (useVapour && (useKeyword || deck.getENPTVD().mask_[4])) {
|
||||
itab = 5;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).sgcr_;
|
||||
}
|
||||
} else if (keyword == std::string("SGU") || keyword == std::string("ISGU") ) {
|
||||
if (useVapour && (useKeyword || deck.getENPTVD().mask_[5])) {
|
||||
itab = 6;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).smax_[phase_pos_vapour];
|
||||
}
|
||||
} else if (keyword == std::string("SOWCR") || keyword == std::string("ISOWCR") ) {
|
||||
if (useAqua && (useKeyword || deck.getENPTVD().mask_[6])) {
|
||||
itab = 7;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).sowcr_;
|
||||
}
|
||||
} else if (keyword == std::string("SOGCR") || keyword == std::string("ISOGCR") ) {
|
||||
if (useVapour && (useKeyword || deck.getENPTVD().mask_[7])) {
|
||||
itab = 8;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).sogcr_;
|
||||
}
|
||||
} else {
|
||||
@ -787,50 +898,50 @@ namespace Opm
|
||||
if (keyword == std::string("KRW") || keyword == std::string("IKRW") ) {
|
||||
if (useAqua && (useKeyword || deck.getENKRVD().mask_[0])) {
|
||||
itab = 1;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krwmax_;
|
||||
}
|
||||
} else if (keyword == std::string("KRG") || keyword == std::string("IKRG") ) {
|
||||
if (useVapour && (useKeyword || deck.getENKRVD().mask_[1])) {
|
||||
itab = 2;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krgmax_;
|
||||
}
|
||||
} else if (keyword == std::string("KRO") || keyword == std::string("IKRO") ) {
|
||||
if (useLiquid && (useKeyword || deck.getENKRVD().mask_[2])) {
|
||||
itab = 3;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).kromax_;
|
||||
}
|
||||
} else if (keyword == std::string("KRWR") || keyword == std::string("IKRWR") ) {
|
||||
if (useAqua && (useKeyword || deck.getENKRVD().mask_[3])) {
|
||||
itab = 4;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krwr_;
|
||||
}
|
||||
} else if (keyword == std::string("KRGR") || keyword == std::string("IKRGR") ) {
|
||||
if (useVapour && (useKeyword || deck.getENKRVD().mask_[4])) {
|
||||
itab = 5;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krgr_;
|
||||
}
|
||||
} else if (keyword == std::string("KRORW") || keyword == std::string("IKRORW") ) {
|
||||
if (useAqua && (useKeyword || deck.getENKRVD().mask_[5])) {
|
||||
itab = 6;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krorw_;
|
||||
}
|
||||
} else if (keyword == std::string("KRORG") || keyword == std::string("IKRORG") ) {
|
||||
if (useVapour && (useKeyword || deck.getENKRVD().mask_[6])) {
|
||||
itab = 7;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krorg_;
|
||||
}
|
||||
} else {
|
||||
@ -846,10 +957,9 @@ namespace Opm
|
||||
} else if (useKeyword) {
|
||||
// Keyword values from deck
|
||||
std::cout << "--- Scaling parameter '" << keyword << "' assigned." << std::endl;
|
||||
const int* gc = grid.global_cell;
|
||||
const std::vector<double>& val = deck.getFloatingPointValue(keyword);
|
||||
for (int c = 0; c < int(scaleparam.size()); ++c) {
|
||||
const int deck_pos = (gc == NULL) ? c : gc[c];
|
||||
const int deck_pos = (global_cell == NULL) ? c : global_cell[c];
|
||||
scaleparam[c] = val[deck_pos];
|
||||
}
|
||||
} else {
|
||||
@ -858,14 +968,15 @@ namespace Opm
|
||||
deck.getENPTVD().write(std::cout);
|
||||
else
|
||||
deck.getENKRVD().write(std::cout);
|
||||
const double* cc = grid.cell_centroids;
|
||||
const int dim = grid.dimensions;
|
||||
for (int cell = 0; cell < grid.number_of_cells; ++cell) {
|
||||
for (int cell = 0; cell < number_of_cells; ++cell) {
|
||||
int jtab = cell_to_func_.empty() ? 0 : cell_to_func_[cell];
|
||||
if (table[itab][jtab][0] != -1.0) {
|
||||
std::vector<double>& depth = table[0][jtab];
|
||||
std::vector<double>& val = table[itab][jtab];
|
||||
double zc = cc[dim*cell+dim-1];
|
||||
double zc = UgGridHelpers
|
||||
::getCoordinate(UgGridHelpers::increment(begin_cell_centroid, cell,
|
||||
dimensions),
|
||||
dimensions-1);
|
||||
if (zc >= depth.front() && zc <= depth.back()) { //don't want extrap outside depth interval
|
||||
scaleparam[cell] = linearInterpolation(depth, val, zc);
|
||||
}
|
||||
@ -876,8 +987,12 @@ namespace Opm
|
||||
|
||||
// Initialize saturation scaling parameter
|
||||
template <class SatFuncSet>
|
||||
template<class T>
|
||||
void SaturationPropsFromDeck<SatFuncSet>::initEPSKey(Opm::DeckConstPtr newParserDeck,
|
||||
const UnstructuredGrid& grid,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const T& begin_cell_centroid,
|
||||
int dimensions,
|
||||
const std::string& keyword,
|
||||
std::vector<double>& scaleparam)
|
||||
{
|
||||
@ -898,57 +1013,57 @@ namespace Opm
|
||||
if (keyword == std::string("SWL") || keyword == std::string("ISWL") ) {
|
||||
if (useAqua && (useKeyword || columnIsMasked_(newParserDeck, "ENPTVD", 0))) {
|
||||
itab = 1;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).smin_[phase_pos_aqua];
|
||||
}
|
||||
} else if (keyword == std::string("SWCR") || keyword == std::string("ISWCR") ) {
|
||||
if (useAqua && (useKeyword || columnIsMasked_(newParserDeck, "ENPTVD", 1))) {
|
||||
itab = 2;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).swcr_;
|
||||
}
|
||||
} else if (keyword == std::string("SWU") || keyword == std::string("ISWU") ) {
|
||||
if (useAqua && (useKeyword || columnIsMasked_(newParserDeck, "ENPTVD", 2))) {
|
||||
itab = 3;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).smax_[phase_pos_aqua];
|
||||
}
|
||||
} else if (keyword == std::string("SGL") || keyword == std::string("ISGL") ) {
|
||||
if (useVapour && (useKeyword || columnIsMasked_(newParserDeck, "ENPTVD", 3))) {
|
||||
itab = 4;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).smin_[phase_pos_vapour];
|
||||
}
|
||||
} else if (keyword == std::string("SGCR") || keyword == std::string("ISGCR") ) {
|
||||
if (useVapour && (useKeyword || columnIsMasked_(newParserDeck, "ENPTVD", 4))) {
|
||||
itab = 5;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).sgcr_;
|
||||
}
|
||||
} else if (keyword == std::string("SGU") || keyword == std::string("ISGU") ) {
|
||||
if (useVapour && (useKeyword || columnIsMasked_(newParserDeck, "ENPTVD", 5))) {
|
||||
itab = 6;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).smax_[phase_pos_vapour];
|
||||
}
|
||||
} else if (keyword == std::string("SOWCR") || keyword == std::string("ISOWCR") ) {
|
||||
if (useAqua && (useKeyword || columnIsMasked_(newParserDeck, "ENPTVD", 6))) {
|
||||
itab = 7;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).sowcr_;
|
||||
}
|
||||
} else if (keyword == std::string("SOGCR") || keyword == std::string("ISOGCR") ) {
|
||||
if (useVapour && (useKeyword || columnIsMasked_(newParserDeck, "ENPTVD", 7))) {
|
||||
itab = 8;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).sogcr_;
|
||||
}
|
||||
} else {
|
||||
@ -977,49 +1092,49 @@ namespace Opm
|
||||
if (keyword == std::string("KRW") || keyword == std::string("IKRW") ) {
|
||||
if (useAqua && (useKeyword || columnIsMasked_(newParserDeck, "ENKRVD", 0))) {
|
||||
itab = 1;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krwmax_;
|
||||
}
|
||||
} else if (keyword == std::string("KRG") || keyword == std::string("IKRG") ) {
|
||||
if (useVapour && (useKeyword || columnIsMasked_(newParserDeck, "ENKRVD", 1))) {
|
||||
itab = 2;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krgmax_;
|
||||
}
|
||||
if (useLiquid && (useKeyword || columnIsMasked_(newParserDeck, "ENKRVD", 2))) {
|
||||
itab = 3;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).kromax_;
|
||||
}
|
||||
} else if (keyword == std::string("KRWR") || keyword == std::string("IKRWR") ) {
|
||||
if (useAqua && (useKeyword || columnIsMasked_(newParserDeck, "ENKRVD", 3))) {
|
||||
itab = 4;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krwr_;
|
||||
}
|
||||
} else if (keyword == std::string("KRGR") || keyword == std::string("IKRGR") ) {
|
||||
if (useVapour && (useKeyword || columnIsMasked_(newParserDeck, "ENKRVD", 4))) {
|
||||
itab = 5;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krgr_;
|
||||
}
|
||||
} else if (keyword == std::string("KRORW") || keyword == std::string("IKRORW") ) {
|
||||
if (useAqua && (useKeyword || columnIsMasked_(newParserDeck, "ENKRVD", 5))) {
|
||||
itab = 6;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krorw_;
|
||||
}
|
||||
} else if (keyword == std::string("KRORG") || keyword == std::string("IKRORG") ) {
|
||||
if (useVapour && (useKeyword || columnIsMasked_(newParserDeck, "ENKRVD", 6))) {
|
||||
itab = 7;
|
||||
scaleparam.resize(grid.number_of_cells);
|
||||
for (int i=0; i<grid.number_of_cells; ++i)
|
||||
scaleparam.resize(number_of_cells);
|
||||
for (int i=0; i<number_of_cells; ++i)
|
||||
scaleparam[i] = funcForCell(i).krorg_;
|
||||
}
|
||||
} else {
|
||||
@ -1050,7 +1165,7 @@ namespace Opm
|
||||
} else if (useKeyword) {
|
||||
// Keyword values from deck
|
||||
std::cout << "--- Scaling parameter '" << keyword << "' assigned." << std::endl;
|
||||
const int* gc = grid.global_cell;
|
||||
const int* gc = global_cell;
|
||||
const std::vector<double>& val = newParserDeck->getKeyword(keyword)->getSIDoubleData();
|
||||
for (int c = 0; c < int(scaleparam.size()); ++c) {
|
||||
const int deck_pos = (gc == NULL) ? c : gc[c];
|
||||
@ -1065,9 +1180,9 @@ namespace Opm
|
||||
else
|
||||
newParserDeck.getENKRVD().write(std::cout);
|
||||
*/
|
||||
const double* cc = grid.cell_centroids;
|
||||
const int dim = grid.dimensions;
|
||||
for (int cell = 0; cell < grid.number_of_cells; ++cell) {
|
||||
const double* cc = begin_cell_centroid;
|
||||
const int dim = dimensions;
|
||||
for (int cell = 0; cell < number_of_cells; ++cell) {
|
||||
int jtab = cell_to_func_.empty() ? 0 : cell_to_func_[cell];
|
||||
if (table[itab][jtab][0] != -1.0) {
|
||||
std::vector<double>& depth = table[0][jtab];
|
||||
|
@ -4,13 +4,18 @@
|
||||
using namespace Opm;
|
||||
|
||||
void
|
||||
BlackoilState::init(const UnstructuredGrid& g, int num_phases) {
|
||||
SimulatorState::init(g, num_phases);
|
||||
gor_.resize(g.number_of_cells, 0.) ;
|
||||
rv_.resize(g.number_of_cells,0.);
|
||||
BlackoilState::init(int number_of_cells, int number_of_phases, int num_phases) {
|
||||
SimulatorState::init(number_of_cells, number_of_phases, num_phases);
|
||||
gor_.resize(number_of_cells, 0.) ;
|
||||
rv_.resize(number_of_cells,0.);
|
||||
// surfvol_ intentionally empty, left to initBlackoilSurfvol
|
||||
}
|
||||
|
||||
void
|
||||
BlackoilState::init(const UnstructuredGrid& g, int num_phases)
|
||||
{
|
||||
init(g.number_of_cells, g.number_of_faces, num_phases);
|
||||
}
|
||||
/// Set the first saturation to either its min or max value in
|
||||
/// the indicated cells. The second saturation value s2 is set
|
||||
/// to (1.0 - s1) for each cell. Any further saturation values
|
||||
|
@ -32,7 +32,9 @@ namespace Opm
|
||||
class BlackoilState : public SimulatorState
|
||||
{
|
||||
public:
|
||||
virtual void init(const UnstructuredGrid& g, int num_phases);
|
||||
virtual void init(const UnstructuredGrid& grid, int num_phases);
|
||||
|
||||
virtual void init(int number_of_cells, int number_of_faces, int num_phases);
|
||||
|
||||
/// Set the first saturation to either its min or max value in
|
||||
/// the indicated cells. The second saturation value s2 is set
|
||||
|
@ -40,13 +40,18 @@ SimulatorState::vectorApproxEqual(const std::vector<double>& v1,
|
||||
|
||||
void
|
||||
SimulatorState::init(const UnstructuredGrid& g, int num_phases)
|
||||
{
|
||||
init(g.number_of_cells, g.number_of_faces, num_phases);
|
||||
}
|
||||
void
|
||||
SimulatorState::init(int number_of_cells, int number_of_faces, int num_phases)
|
||||
{
|
||||
num_phases_ = num_phases;
|
||||
press_.resize(g.number_of_cells, 0.0);
|
||||
fpress_.resize(g.number_of_faces, 0.0);
|
||||
flux_.resize(g.number_of_faces, 0.0);
|
||||
sat_.resize(num_phases_ * g.number_of_cells, 0.0);
|
||||
for (int cell = 0; cell < g.number_of_cells; ++cell) {
|
||||
press_.resize(number_of_cells, 0.0);
|
||||
fpress_.resize(number_of_faces, 0.0);
|
||||
flux_.resize(number_of_faces, 0.0);
|
||||
sat_.resize(num_phases_ * number_of_cells, 0.0);
|
||||
for (int cell = 0; cell < number_of_cells; ++cell) {
|
||||
// Defaulting the second saturation to 1.0.
|
||||
// This will usually be oil in a water-oil case,
|
||||
// gas in an oil-gas case.
|
||||
|
@ -17,6 +17,8 @@ namespace Opm
|
||||
|
||||
virtual void init(const UnstructuredGrid& g, int num_phases);
|
||||
|
||||
virtual void init(int number_of_cells, int number_of_phases, int num_phases);
|
||||
|
||||
enum ExtremalSat { MinSat, MaxSat };
|
||||
|
||||
protected:
|
||||
|
@ -65,6 +65,44 @@ namespace Opm
|
||||
const double gravity,
|
||||
State& state);
|
||||
|
||||
/// Initialize a two-phase state from parameters.
|
||||
/// The following parameters are accepted (defaults):
|
||||
/// - convection_testcase (false) -- Water in the 'left' part of the grid.
|
||||
/// - ref_pressure (100) -- Initial pressure in bar for all cells
|
||||
/// (if convection_testcase is true),
|
||||
/// or pressure at woc depth.
|
||||
/// - segregation_testcase (false) -- Water above the woc instead of below.
|
||||
/// - water_oil_contact (none) -- Depth of water-oil contact (woc).
|
||||
/// - init_saturation (none) -- Initial water saturation for all cells.
|
||||
///
|
||||
/// If convection_testcase is true, the saturation is initialised
|
||||
/// as indicated, and pressure is initialised to a constant value
|
||||
/// ('ref_pressure').
|
||||
/// If segregation_testcase is true, the saturation is initialised
|
||||
/// as indicated, and pressure is initialised hydrostatically.
|
||||
/// Otherwise we have 3 cases:
|
||||
/// 1. If 'water_oil_contact' is given, saturation is initialised
|
||||
/// accordingly.
|
||||
/// 2. If 'water_oil_contact' is not given, but 'init_saturation'
|
||||
/// is given, water saturation is set to that value everywhere.
|
||||
/// 3. If neither are given, water saturation is set to minimum.
|
||||
///
|
||||
/// In all three cases, pressure is initialised hydrostatically.
|
||||
/// In case 2) and 3), the depth of the first cell is used as reference depth.
|
||||
template <class FaceCells, class CCI, class FCI, class State>
|
||||
void initStateBasic(int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cartdims,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
int dimensions,
|
||||
const IncompPropertiesInterface& props,
|
||||
const parameter::ParameterGroup& param,
|
||||
const double gravity,
|
||||
State& state);
|
||||
|
||||
/// Initialize a blackoil state from parameters.
|
||||
/// The following parameters are accepted (defaults):
|
||||
/// - convection_testcase (false) -- Water in the 'left' part of the grid.
|
||||
@ -88,6 +126,36 @@ namespace Opm
|
||||
const double gravity,
|
||||
State& state);
|
||||
|
||||
/// Initialize a blackoil state from parameters.
|
||||
/// The following parameters are accepted (defaults):
|
||||
/// - convection_testcase (false) -- Water in the 'left' part of the grid.
|
||||
/// - ref_pressure (100) -- Initial pressure in bar for all cells
|
||||
/// (if convection_testcase is true),
|
||||
/// or pressure at woc depth.
|
||||
/// - water_oil_contact (none) -- Depth of water-oil contact (woc).
|
||||
/// If convection_testcase is true, the saturation is initialised
|
||||
/// as indicated, and pressure is initialised to a constant value
|
||||
/// ('ref_pressure').
|
||||
/// Otherwise we have 2 cases:
|
||||
/// 1. If 'water_oil_contact' is given, saturation is initialised
|
||||
/// accordingly.
|
||||
/// 2. Water saturation is set to minimum.
|
||||
/// In both cases, pressure is initialised hydrostatically.
|
||||
/// In case 2., the depth of the first cell is used as reference depth.
|
||||
template <class FaceCells, class FCI, class CCI, class State>
|
||||
void initStateBasic(int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cartdims,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
int dimensions,
|
||||
const BlackoilPropertiesInterface& props,
|
||||
const parameter::ParameterGroup& param,
|
||||
const double gravity,
|
||||
State& state);
|
||||
|
||||
/// Initialize a two-phase state from input deck.
|
||||
/// If EQUIL is present:
|
||||
/// - saturation is set according to the water-oil contact,
|
||||
@ -102,6 +170,27 @@ namespace Opm
|
||||
const double gravity,
|
||||
State& state);
|
||||
|
||||
/// Initialize a two-phase state from input deck.
|
||||
/// If EQUIL is present:
|
||||
/// - saturation is set according to the water-oil contact,
|
||||
/// - pressure is set to hydrostatic equilibrium.
|
||||
/// Otherwise:
|
||||
/// - saturation is set according to SWAT,
|
||||
/// - pressure is set according to PRESSURE.
|
||||
template <class FaceCells, class FCI, class CCI, class Props, class State>
|
||||
void initStateFromDeck(int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cartdims,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
int dimensions,
|
||||
const Props& props,
|
||||
const EclipseGridParser& deck,
|
||||
const double gravity,
|
||||
State& state);
|
||||
|
||||
/// Initialize a two-phase water-oil blackoil state from input deck.
|
||||
/// If EQUIL is present:
|
||||
/// - saturation is set according to the water-oil contact,
|
||||
@ -117,7 +206,26 @@ namespace Opm
|
||||
const double gravity,
|
||||
State& state);
|
||||
|
||||
|
||||
/// Initialize a two-phase water-oil blackoil state from input deck.
|
||||
/// If EQUIL is present:
|
||||
/// - saturation is set according to the water-oil contact,
|
||||
/// - pressure is set to hydrostatic equilibrium.
|
||||
/// Otherwise:
|
||||
/// - saturation is set according to SWAT,
|
||||
/// - pressure is set according to PRESSURE.
|
||||
/// In addition, this function sets surfacevol.
|
||||
template <class FaceCells, class FCI, class CCI, class Props, class State>
|
||||
void initBlackoilStateFromDeck(int number_of_cells,
|
||||
const int* global_cell,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
int dimensions,
|
||||
const Props& props,
|
||||
const EclipseGridParser& deck,
|
||||
const double gravity,
|
||||
State& state);
|
||||
} // namespace Opm
|
||||
|
||||
#include <opm/core/simulator/initState_impl.hpp>
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
#include <opm/core/io/eclipse/EclipseGridParser.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <opm/core/utility/MonotCubicInterpolator.hpp>
|
||||
@ -49,17 +50,21 @@ namespace Opm
|
||||
// Find the cells that are below and above a depth.
|
||||
// TODO: add 'anitialiasing', obtaining a more precise split
|
||||
// by f. ex. subdividing cells cut by the split depths.
|
||||
void cellsBelowAbove(const UnstructuredGrid& grid,
|
||||
template<class T>
|
||||
void cellsBelowAbove(int number_of_cells,
|
||||
T begin_cell_centroids,
|
||||
int dimension,
|
||||
const double depth,
|
||||
std::vector<int>& below,
|
||||
std::vector<int>& above)
|
||||
{
|
||||
const int num_cells = grid.number_of_cells;
|
||||
below.reserve(num_cells);
|
||||
above.reserve(num_cells);
|
||||
const int dim = grid.dimensions;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
const double z = grid.cell_centroids[dim*c + dim - 1];
|
||||
below.reserve(number_of_cells);
|
||||
above.reserve(number_of_cells);
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
const double z = UgGridHelpers
|
||||
::getCoordinate(UgGridHelpers::increment(begin_cell_centroids, c,
|
||||
dimension),
|
||||
dimension-1);
|
||||
if (z > depth) {
|
||||
below.push_back(c);
|
||||
} else {
|
||||
@ -76,8 +81,10 @@ namespace Opm
|
||||
// Initialize saturations so that there is water below woc,
|
||||
// and oil above.
|
||||
// If invert is true, water is instead above, oil below.
|
||||
template <class Props, class State>
|
||||
void initWaterOilContact(const UnstructuredGrid& grid,
|
||||
template <class T, class Props, class State>
|
||||
void initWaterOilContact(int number_of_cells,
|
||||
T begin_cell_centroids,
|
||||
int dimensions,
|
||||
const Props& props,
|
||||
const double woc,
|
||||
const WaterInit waterinit,
|
||||
@ -93,10 +100,12 @@ namespace Opm
|
||||
// }
|
||||
switch (waterinit) {
|
||||
case WaterBelow:
|
||||
cellsBelowAbove(grid, woc, water, oil);
|
||||
cellsBelowAbove(number_of_cells, begin_cell_centroids, dimensions,
|
||||
woc, water, oil);
|
||||
break;
|
||||
case WaterAbove:
|
||||
cellsBelowAbove(grid, woc, oil, water);
|
||||
cellsBelowAbove(number_of_cells, begin_cell_centroids, dimensions,
|
||||
woc, oil, water);
|
||||
}
|
||||
// Set saturations.
|
||||
state.setFirstSat(oil, props, State::MinSat);
|
||||
@ -115,8 +124,10 @@ namespace Opm
|
||||
// Note that by manipulating the densities parameter,
|
||||
// it is possible to initialise with water on top instead of
|
||||
// on the bottom etc.
|
||||
template <class State>
|
||||
void initHydrostaticPressure(const UnstructuredGrid& grid,
|
||||
template <class T, class State>
|
||||
void initHydrostaticPressure(int number_of_cells,
|
||||
T begin_cell_centroids,
|
||||
int dimensions,
|
||||
const double* densities,
|
||||
const double woc,
|
||||
const double gravity,
|
||||
@ -125,14 +136,14 @@ namespace Opm
|
||||
State& state)
|
||||
{
|
||||
std::vector<double>& p = state.pressure();
|
||||
const int num_cells = grid.number_of_cells;
|
||||
const int dim = grid.dimensions;
|
||||
// Compute pressure at woc
|
||||
const double rho_datum = datum_z > woc ? densities[0] : densities[1];
|
||||
const double woc_p = datum_p + (woc - datum_z)*gravity*rho_datum;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
// Compute pressure as delta from woc pressure.
|
||||
const double z = grid.cell_centroids[dim*c + dim - 1];
|
||||
const double z = UgGridHelpers::
|
||||
getCoordinate(UgGridHelpers::increment(begin_cell_centroids, c, dimensions),
|
||||
dimensions-1);
|
||||
const double rho = z > woc ? densities[0] : densities[1];
|
||||
p[c] = woc_p + (z - woc)*gravity*rho;
|
||||
}
|
||||
@ -141,8 +152,10 @@ namespace Opm
|
||||
|
||||
// Facade to initHydrostaticPressure() taking a property object,
|
||||
// for similarity to initHydrostaticPressure() for compressible fluids.
|
||||
template <class State>
|
||||
void initHydrostaticPressure(const UnstructuredGrid& grid,
|
||||
template <class T, class State>
|
||||
void initHydrostaticPressure(int number_of_cells,
|
||||
T begin_cell_centroids,
|
||||
int dimensions,
|
||||
const IncompPropertiesInterface& props,
|
||||
const double woc,
|
||||
const double gravity,
|
||||
@ -151,7 +164,8 @@ namespace Opm
|
||||
State& state)
|
||||
{
|
||||
const double* densities = props.density();
|
||||
initHydrostaticPressure(grid, densities, woc, gravity, datum_z, datum_p, state);
|
||||
initHydrostaticPressure(number_of_cells, begin_cell_centroids, dimensions,
|
||||
densities, woc, gravity, datum_z, datum_p, state);
|
||||
}
|
||||
|
||||
|
||||
@ -183,8 +197,10 @@ namespace Opm
|
||||
// where rho is the oil density above the woc, water density
|
||||
// below woc. Note that even if there is (immobile) water in
|
||||
// the oil zone, it does not contribute to the pressure there.
|
||||
template <class State>
|
||||
void initHydrostaticPressure(const UnstructuredGrid& grid,
|
||||
template <class T, class State>
|
||||
void initHydrostaticPressure(int number_of_cells,
|
||||
T begin_cell_centroids,
|
||||
int dimensions,
|
||||
const BlackoilPropertiesInterface& props,
|
||||
const double woc,
|
||||
const double gravity,
|
||||
@ -195,11 +211,11 @@ namespace Opm
|
||||
assert(props.numPhases() == 2);
|
||||
|
||||
// Obtain max and min z for which we will need to compute p.
|
||||
const int num_cells = grid.number_of_cells;
|
||||
const int dim = grid.dimensions;
|
||||
double zlim[2] = { 1e100, -1e100 };
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
const double z = grid.cell_centroids[dim*c + dim - 1];
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
const double z = UgGridHelpers::
|
||||
getCoordinate(UgGridHelpers::increment(begin_cell_centroids, c, dimensions),
|
||||
dimensions-1);;
|
||||
zlim[0] = std::min(zlim[0], z);
|
||||
zlim[1] = std::max(zlim[1], z);
|
||||
}
|
||||
@ -268,30 +284,42 @@ namespace Opm
|
||||
|
||||
// Evaluate pressure at each cell centroid.
|
||||
std::vector<double>& p = state.pressure();
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
const double z = grid.cell_centroids[dim*c + dim - 1];
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
const double z = UgGridHelpers::
|
||||
getCoordinate(UgGridHelpers::increment(begin_cell_centroids, c, dimensions),
|
||||
dimensions-1);
|
||||
p[c] = press(z);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize face pressures to distance-weighted average of adjacent cell pressures.
|
||||
template <class State>
|
||||
void initFacePressure(const UnstructuredGrid& grid,
|
||||
template <class State, class FaceCells, class FCI, class CCI>
|
||||
void initFacePressure(int dimensions,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
State& state)
|
||||
{
|
||||
const int dim = grid.dimensions;
|
||||
const std::vector<double>& cp = state.pressure();
|
||||
std::vector<double>& fp = state.facepressure();
|
||||
for (int f = 0; f < grid.number_of_faces; ++f) {
|
||||
for (int f = 0; f < number_of_faces; ++f) {
|
||||
double dist[2] = { 0.0, 0.0 };
|
||||
double press[2] = { 0.0, 0.0 };
|
||||
int bdy_idx = -1;
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
const int c = grid.face_cells[2*f + j];
|
||||
const int c = face_cells(f, j);
|
||||
if (c >= 0) {
|
||||
dist[j] = 0.0;
|
||||
for (int dd = 0; dd < dim; ++dd) {
|
||||
double diff = grid.face_centroids[dim*f + dd] - grid.cell_centroids[dim*c + dd];
|
||||
for (int dd = 0; dd < dimensions; ++dd) {
|
||||
double diff = UgGridHelpers::
|
||||
getCoordinate(UgGridHelpers::increment(begin_face_centroids, f,
|
||||
dimensions),
|
||||
dd)
|
||||
- UgGridHelpers::
|
||||
getCoordinate(UgGridHelpers::increment(begin_cell_centroids, c,
|
||||
dimensions),
|
||||
dd);
|
||||
dist[j] += diff*diff;
|
||||
}
|
||||
dist[j] = std::sqrt(dist[j]);
|
||||
@ -320,11 +348,32 @@ namespace Opm
|
||||
const double gravity,
|
||||
State& state)
|
||||
{
|
||||
initStateBasic(grid.number_of_cells, grid.global_cell, grid.cartdims,
|
||||
grid.number_of_faces, UgGridHelpers::faceCells(grid),
|
||||
grid.face_centroids, grid.cell_centroids,
|
||||
grid.dimensions, props, param,
|
||||
gravity, state);
|
||||
}
|
||||
|
||||
template <class FaceCells, class CCI, class FCI, class State>
|
||||
void initStateBasic(int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cartdims,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
int dimensions,
|
||||
const IncompPropertiesInterface& props,
|
||||
const parameter::ParameterGroup& param,
|
||||
const double gravity,
|
||||
State& state)
|
||||
{
|
||||
const int num_phases = props.numPhases();
|
||||
if (num_phases != 2) {
|
||||
OPM_THROW(std::runtime_error, "initStateTwophaseBasic(): currently handling only two-phase scenarios.");
|
||||
}
|
||||
state.init(grid, num_phases);
|
||||
state.init(number_of_cells, number_of_faces, num_phases);
|
||||
const int num_cells = props.numCells();
|
||||
// By default: initialise water saturation to minimum everywhere.
|
||||
std::vector<int> all_cells(num_cells);
|
||||
@ -338,11 +387,9 @@ namespace Opm
|
||||
// Initialise water saturation to max in the 'left' part.
|
||||
std::vector<int> left_cells;
|
||||
left_cells.reserve(num_cells/2);
|
||||
const int *glob_cell = grid.global_cell;
|
||||
const int* cd = grid.cartdims;
|
||||
for (int cell = 0; cell < num_cells; ++cell) {
|
||||
const int gc = glob_cell == 0 ? cell : glob_cell[cell];
|
||||
bool left = (gc % cd[0]) < cd[0]/2;
|
||||
const int gc = global_cell == 0 ? cell : global_cell[cell];
|
||||
bool left = (gc % cartdims[0]) < cartdims[0]/2;
|
||||
if (left) {
|
||||
left_cells.push_back(cell);
|
||||
}
|
||||
@ -355,30 +402,34 @@ namespace Opm
|
||||
if (gravity == 0.0) {
|
||||
std::cout << "**** Warning: running gravity segregation scenario, but gravity is zero." << std::endl;
|
||||
}
|
||||
if (grid.cartdims[2] <= 1) {
|
||||
if (cartdims[2] <= 1) {
|
||||
std::cout << "**** Warning: running gravity segregation scenario, which expects nz > 1." << std::endl;
|
||||
}
|
||||
// Initialise water saturation to max *above* water-oil contact.
|
||||
const double woc = param.get<double>("water_oil_contact");
|
||||
initWaterOilContact(grid, props, woc, WaterAbove, state);
|
||||
initWaterOilContact(number_of_cells, begin_cell_centroids, dimensions,
|
||||
props, woc, WaterAbove, state);
|
||||
// Initialise pressure to hydrostatic state.
|
||||
const double ref_p = param.getDefault("ref_pressure", 100.0)*unit::barsa;
|
||||
double dens[2] = { props.density()[1], props.density()[0] };
|
||||
initHydrostaticPressure(grid, dens, woc, gravity, woc, ref_p, state);
|
||||
initHydrostaticPressure(number_of_cells, begin_cell_centroids, dimensions,
|
||||
dens, woc, gravity, woc, ref_p, state);
|
||||
} else if (param.has("water_oil_contact")) {
|
||||
// Warn against error-prone usage.
|
||||
if (gravity == 0.0) {
|
||||
std::cout << "**** Warning: running gravity convection scenario, but gravity is zero." << std::endl;
|
||||
}
|
||||
if (grid.cartdims[2] <= 1) {
|
||||
if (cartdims[2] <= 1) {
|
||||
std::cout << "**** Warning: running gravity convection scenario, which expects nz > 1." << std::endl;
|
||||
}
|
||||
// Initialise water saturation to max below water-oil contact.
|
||||
const double woc = param.get<double>("water_oil_contact");
|
||||
initWaterOilContact(grid, props, woc, WaterBelow, state);
|
||||
initWaterOilContact(number_of_cells, begin_cell_centroids, dimensions,
|
||||
props, woc, WaterBelow, state);
|
||||
// Initialise pressure to hydrostatic state.
|
||||
const double ref_p = param.getDefault("ref_pressure", 100.0)*unit::barsa;
|
||||
initHydrostaticPressure(grid, props.density(), woc, gravity, woc, ref_p, state);
|
||||
initHydrostaticPressure(number_of_cells, begin_cell_centroids, dimensions,
|
||||
props.density(), woc, gravity, woc, ref_p, state);
|
||||
} else if (param.has("init_saturation")) {
|
||||
// Initialise water saturation to init_saturation parameter.
|
||||
const double init_saturation = param.get<double>("init_saturation");
|
||||
@ -390,20 +441,23 @@ namespace Opm
|
||||
const double ref_p = param.getDefault("ref_pressure", 100.0)*unit::barsa;
|
||||
const double rho = props.density()[0]*init_saturation + props.density()[1]*(1.0 - init_saturation);
|
||||
const double dens[2] = { rho, rho };
|
||||
const double ref_z = grid.cell_centroids[0 + grid.dimensions - 1];
|
||||
initHydrostaticPressure(grid, dens, ref_z, gravity, ref_z, ref_p, state);
|
||||
const double ref_z = UgGridHelpers::getCoordinate(begin_cell_centroids, dimensions - 1);
|
||||
initHydrostaticPressure(number_of_cells, begin_cell_centroids, dimensions,
|
||||
dens, ref_z, gravity, ref_z, ref_p, state);
|
||||
} else {
|
||||
// Use default: water saturation is minimum everywhere.
|
||||
// Initialise pressure to hydrostatic state.
|
||||
const double ref_p = param.getDefault("ref_pressure", 100.0)*unit::barsa;
|
||||
const double rho = props.density()[1];
|
||||
const double dens[2] = { rho, rho };
|
||||
const double ref_z = grid.cell_centroids[0 + grid.dimensions - 1];
|
||||
initHydrostaticPressure(grid, dens, ref_z, gravity, ref_z, ref_p, state);
|
||||
const double ref_z = UgGridHelpers::getCoordinate(begin_cell_centroids, dimensions - 1);
|
||||
initHydrostaticPressure(number_of_cells, begin_cell_centroids, dimensions,
|
||||
dens, ref_z, gravity, ref_z, ref_p, state);
|
||||
}
|
||||
|
||||
// Finally, init face pressures.
|
||||
initFacePressure(grid, state);
|
||||
initFacePressure(dimensions, number_of_faces, face_cells, begin_face_centroids,
|
||||
begin_cell_centroids, state);
|
||||
}
|
||||
|
||||
|
||||
@ -414,13 +468,33 @@ namespace Opm
|
||||
const parameter::ParameterGroup& param,
|
||||
const double gravity,
|
||||
State& state)
|
||||
{
|
||||
initStateBasic(grid.number_of_cells, grid.global_cell, grid.cartdims,
|
||||
grid.number_of_faces, UgGridHelpers::faceCells(grid),
|
||||
grid.face_centroids, grid.cell_centroids, grid.dimensions,
|
||||
props, param, gravity, state);
|
||||
}
|
||||
|
||||
template <class FaceCells, class FCI, class CCI, class State>
|
||||
void initStateBasic(int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cartdims,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
int dimensions,
|
||||
const BlackoilPropertiesInterface& props,
|
||||
const parameter::ParameterGroup& param,
|
||||
const double gravity,
|
||||
State& state)
|
||||
{
|
||||
// TODO: Refactor to exploit similarity with IncompProp* case.
|
||||
const int num_phases = props.numPhases();
|
||||
if (num_phases != 2) {
|
||||
OPM_THROW(std::runtime_error, "initStateTwophaseBasic(): currently handling only two-phase scenarios.");
|
||||
}
|
||||
state.init(grid, num_phases);
|
||||
state.init(number_of_cells, number_of_faces, num_phases);
|
||||
const int num_cells = props.numCells();
|
||||
// By default: initialise water saturation to minimum everywhere.
|
||||
std::vector<int> all_cells(num_cells);
|
||||
@ -433,11 +507,9 @@ namespace Opm
|
||||
// Initialise water saturation to max in the 'left' part.
|
||||
std::vector<int> left_cells;
|
||||
left_cells.reserve(num_cells/2);
|
||||
const int *glob_cell = grid.global_cell;
|
||||
const int* cd = grid.cartdims;
|
||||
for (int cell = 0; cell < num_cells; ++cell) {
|
||||
const int gc = glob_cell == 0 ? cell : glob_cell[cell];
|
||||
bool left = (gc % cd[0]) < cd[0]/2;
|
||||
const int gc = global_cell == 0 ? cell : global_cell[cell];
|
||||
bool left = (gc % cartdims[0]) < cartdims[0]/2;
|
||||
if (left) {
|
||||
left_cells.push_back(cell);
|
||||
}
|
||||
@ -450,26 +522,30 @@ namespace Opm
|
||||
if (gravity == 0.0) {
|
||||
std::cout << "**** Warning: running gravity convection scenario, but gravity is zero." << std::endl;
|
||||
}
|
||||
if (grid.cartdims[2] <= 1) {
|
||||
if (cartdims[2] <= 1) {
|
||||
std::cout << "**** Warning: running gravity convection scenario, which expects nz > 1." << std::endl;
|
||||
}
|
||||
// Initialise water saturation to max below water-oil contact.
|
||||
const double woc = param.get<double>("water_oil_contact");
|
||||
initWaterOilContact(grid, props, woc, WaterBelow, state);
|
||||
initWaterOilContact(number_of_cells, begin_cell_centroids, dimensions,
|
||||
props, woc, WaterBelow, state);
|
||||
// Initialise pressure to hydrostatic state.
|
||||
const double ref_p = param.getDefault("ref_pressure", 100.0)*unit::barsa;
|
||||
initHydrostaticPressure(grid, props, woc, gravity, woc, ref_p, state);
|
||||
initHydrostaticPressure(number_of_cells, begin_cell_centroids, dimensions,
|
||||
props, woc, gravity, woc, ref_p, state);
|
||||
} else {
|
||||
// Use default: water saturation is minimum everywhere.
|
||||
// Initialise pressure to hydrostatic state.
|
||||
const double ref_p = param.getDefault("ref_pressure", 100.0)*unit::barsa;
|
||||
const double ref_z = grid.cell_centroids[0 + grid.dimensions - 1];
|
||||
const double ref_z = UgGridHelpers::getCoordinate(begin_cell_centroids, dimensions - 1);
|
||||
const double woc = -1e100;
|
||||
initHydrostaticPressure(grid, props, woc, gravity, ref_z, ref_p, state);
|
||||
initHydrostaticPressure(number_of_cells, begin_cell_centroids, dimensions,
|
||||
props, woc, gravity, ref_z, ref_p, state);
|
||||
}
|
||||
|
||||
// Finally, init face pressures.
|
||||
initFacePressure(grid, state);
|
||||
initFacePressure(dimensions, number_of_faces, face_cells, begin_face_centroids,
|
||||
begin_cell_centroids, state);
|
||||
}
|
||||
|
||||
|
||||
@ -577,6 +653,26 @@ namespace Opm
|
||||
const EclipseGridParser& deck,
|
||||
const double gravity,
|
||||
State& state)
|
||||
{
|
||||
initStateFromDeck(grid.number_of_cells, grid.global_cell,
|
||||
grid.number_of_faces, UgGridHelpers::faceCells(grid),
|
||||
grid.face_centroids, grid.cell_centroids,
|
||||
grid.dimensions, props, deck,
|
||||
gravity, state);
|
||||
}
|
||||
|
||||
template <class FaceCells, class FCI, class CCI, class Props, class State>
|
||||
void initStateFromDeck(int number_of_cells,
|
||||
const int* global_cell,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
int dimensions,
|
||||
const Props& props,
|
||||
const EclipseGridParser& deck,
|
||||
const double gravity,
|
||||
State& state)
|
||||
{
|
||||
const int num_phases = props.numPhases();
|
||||
const PhaseUsage pu = phaseUsageFromDeck(deck);
|
||||
@ -584,7 +680,7 @@ namespace Opm
|
||||
OPM_THROW(std::runtime_error, "initStateFromDeck(): user specified property object with " << num_phases << " phases, "
|
||||
"found " << pu.num_phases << " phases in deck.");
|
||||
}
|
||||
state.init(grid, num_phases);
|
||||
state.init(number_of_cells, number_of_faces, num_phases);
|
||||
if (deck.hasField("EQUIL")) {
|
||||
if (num_phases != 2) {
|
||||
OPM_THROW(std::runtime_error, "initStateFromDeck(): EQUIL-based init currently handling only two-phase scenarios.");
|
||||
@ -598,17 +694,18 @@ namespace Opm
|
||||
OPM_THROW(std::runtime_error, "initStateFromDeck(): No region support yet.");
|
||||
}
|
||||
const double woc = equil.equil[0].water_oil_contact_depth_;
|
||||
initWaterOilContact(grid, props, woc, WaterBelow, state);
|
||||
initWaterOilContact(number_of_cells, begin_cell_centroids, dimensions,
|
||||
props, woc, WaterBelow, state);
|
||||
// Set pressure depending on densities and depths.
|
||||
const double datum_z = equil.equil[0].datum_depth_;
|
||||
const double datum_p = equil.equil[0].datum_depth_pressure_;
|
||||
initHydrostaticPressure(grid, props, woc, gravity, datum_z, datum_p, state);
|
||||
initHydrostaticPressure(number_of_cells, begin_cell_centroids, dimensions,
|
||||
props, woc, gravity, datum_z, datum_p, state);
|
||||
} else if (deck.hasField("PRESSURE")) {
|
||||
// Set saturations from SWAT/SGAS, pressure from PRESSURE.
|
||||
std::vector<double>& s = state.saturation();
|
||||
std::vector<double>& p = state.pressure();
|
||||
const std::vector<double>& p_deck = deck.getFloatingPointValue("PRESSURE");
|
||||
const int num_cells = grid.number_of_cells;
|
||||
if (num_phases == 2) {
|
||||
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||
// oil-gas: we require SGAS
|
||||
@ -618,8 +715,8 @@ namespace Opm
|
||||
const std::vector<double>& sg_deck = deck.getFloatingPointValue("SGAS");
|
||||
const int gpos = pu.phase_pos[BlackoilPhases::Vapour];
|
||||
const int opos = pu.phase_pos[BlackoilPhases::Liquid];
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c];
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
int c_deck = (global_cell == NULL) ? c : global_cell[c];
|
||||
s[2*c + gpos] = sg_deck[c_deck];
|
||||
s[2*c + opos] = 1.0 - sg_deck[c_deck];
|
||||
p[c] = p_deck[c_deck];
|
||||
@ -632,8 +729,8 @@ namespace Opm
|
||||
const std::vector<double>& sw_deck = deck.getFloatingPointValue("SWAT");
|
||||
const int wpos = pu.phase_pos[BlackoilPhases::Aqua];
|
||||
const int nwpos = (wpos + 1) % 2;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c];
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
int c_deck = (global_cell == NULL) ? c : global_cell[c];
|
||||
s[2*c + wpos] = sw_deck[c_deck];
|
||||
s[2*c + nwpos] = 1.0 - sw_deck[c_deck];
|
||||
p[c] = p_deck[c_deck];
|
||||
@ -649,8 +746,8 @@ namespace Opm
|
||||
const int opos = pu.phase_pos[BlackoilPhases::Liquid];
|
||||
const std::vector<double>& sw_deck = deck.getFloatingPointValue("SWAT");
|
||||
const std::vector<double>& sg_deck = deck.getFloatingPointValue("SGAS");
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c];
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
int c_deck = (global_cell == NULL) ? c : global_cell[c];
|
||||
s[3*c + wpos] = sw_deck[c_deck];
|
||||
s[3*c + opos] = 1.0 - (sw_deck[c_deck] + sg_deck[c_deck]);
|
||||
s[3*c + gpos] = sg_deck[c_deck];
|
||||
@ -664,7 +761,8 @@ namespace Opm
|
||||
}
|
||||
|
||||
// Finally, init face pressures.
|
||||
initFacePressure(grid, state);
|
||||
initFacePressure(dimensions, number_of_faces, face_cells, begin_face_centroids,
|
||||
begin_cell_centroids, state);
|
||||
}
|
||||
|
||||
/// Initialize surface volume from pressure and saturation by z = As.
|
||||
@ -674,10 +772,18 @@ namespace Opm
|
||||
void initBlackoilSurfvol(const UnstructuredGrid& grid,
|
||||
const Props& props,
|
||||
State& state)
|
||||
{
|
||||
initBlackoilSurfvol(grid.number_of_cells, props, state);
|
||||
}
|
||||
|
||||
template <class Props, class State>
|
||||
void initBlackoilSurfvol(int number_of_cells,
|
||||
const Props& props,
|
||||
State& state)
|
||||
{
|
||||
state.surfacevol() = state.saturation();
|
||||
const int np = props.numPhases();
|
||||
const int nc = grid.number_of_cells;
|
||||
const int nc = number_of_cells;
|
||||
std::vector<double> allA(nc*np*np);
|
||||
std::vector<int> allcells(nc);
|
||||
for (int c = 0; c < nc; ++c) {
|
||||
@ -711,6 +817,15 @@ namespace Opm
|
||||
const Props& props,
|
||||
State& state)
|
||||
{
|
||||
initBlackoilSurfvolUsingRSorRV(grid.number_of_cells, props, state);
|
||||
}
|
||||
|
||||
template <class Props, class State>
|
||||
void initBlackoilSurfvolUsingRSorRV(int number_of_cells,
|
||||
const Props& props,
|
||||
State& state)
|
||||
{
|
||||
|
||||
if (props.numPhases() != 3) {
|
||||
OPM_THROW(std::runtime_error, "initBlackoilSurfvol() is only supported in three-phase simulations.");
|
||||
}
|
||||
@ -722,27 +837,26 @@ namespace Opm
|
||||
const PhaseUsage pu = props.phaseUsage();
|
||||
|
||||
const int np = props.numPhases();
|
||||
const int nc = grid.number_of_cells;
|
||||
|
||||
std::vector<double> allA_a(nc*np*np);
|
||||
std::vector<double> allA_l(nc*np*np);
|
||||
std::vector<double> allA_v(nc*np*np);
|
||||
std::vector<double> allA_a(number_of_cells*np*np);
|
||||
std::vector<double> allA_l(number_of_cells*np*np);
|
||||
std::vector<double> allA_v(number_of_cells*np*np);
|
||||
|
||||
std::vector<int> allcells(nc);
|
||||
std::vector<double> z_init(nc*np);
|
||||
std::vector<int> allcells(number_of_cells);
|
||||
std::vector<double> z_init(number_of_cells*np);
|
||||
std::fill(z_init.begin(),z_init.end(),0.0);
|
||||
|
||||
for (int c = 0; c < nc; ++c) {
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
allcells[c] = c;
|
||||
}
|
||||
|
||||
std::vector<double> capPressures(nc*np);
|
||||
props.capPress(nc,&state.saturation()[0],&allcells[0],&capPressures[0],NULL);
|
||||
std::vector<double> capPressures(number_of_cells*np);
|
||||
props.capPress(number_of_cells,&state.saturation()[0],&allcells[0],&capPressures[0],NULL);
|
||||
|
||||
std::vector<double> Pw(nc);
|
||||
std::vector<double> Pg(nc);
|
||||
std::vector<double> Pw(number_of_cells);
|
||||
std::vector<double> Pg(number_of_cells);
|
||||
|
||||
for (int c = 0; c < nc; ++c){
|
||||
for (int c = 0; c < number_of_cells; ++c){
|
||||
Pw[c] = state.pressure()[c] + capPressures[c*np + BlackoilPhases::Aqua];
|
||||
Pg[c] = state.pressure()[c] + capPressures[c*np + BlackoilPhases::Vapour];
|
||||
}
|
||||
@ -752,7 +866,7 @@ namespace Opm
|
||||
|
||||
// Water phase
|
||||
if(pu.phase_used[BlackoilPhases::Aqua])
|
||||
for (int c = 0; c < nc ; ++c){
|
||||
for (int c = 0; c < number_of_cells ; ++c){
|
||||
for (int p = 0; p < np ; ++p){
|
||||
if (p == BlackoilPhases::Aqua)
|
||||
z_tmp = 1;
|
||||
@ -762,11 +876,11 @@ namespace Opm
|
||||
z_init[c*np + p] = z_tmp;
|
||||
}
|
||||
}
|
||||
props.matrix(nc, &state.pressure()[0], &z_init[0], &allcells[0], &allA_a[0], 0);
|
||||
props.matrix(number_of_cells, &state.pressure()[0], &z_init[0], &allcells[0], &allA_a[0], 0);
|
||||
|
||||
// Liquid phase
|
||||
if(pu.phase_used[BlackoilPhases::Liquid]){
|
||||
for (int c = 0; c < nc ; ++c){
|
||||
for (int c = 0; c < number_of_cells ; ++c){
|
||||
for (int p = 0; p < np ; ++p){
|
||||
if(p == BlackoilPhases::Vapour){
|
||||
if(state.saturation()[np*c + p] > 0)
|
||||
@ -784,10 +898,10 @@ namespace Opm
|
||||
}
|
||||
}
|
||||
}
|
||||
props.matrix(nc, &state.pressure()[0], &z_init[0], &allcells[0], &allA_l[0], 0);
|
||||
props.matrix(number_of_cells, &state.pressure()[0], &z_init[0], &allcells[0], &allA_l[0], 0);
|
||||
|
||||
if(pu.phase_used[BlackoilPhases::Vapour]){
|
||||
for (int c = 0; c < nc ; ++c){
|
||||
for (int c = 0; c < number_of_cells ; ++c){
|
||||
for (int p = 0; p < np ; ++p){
|
||||
if(p == BlackoilPhases::Liquid){
|
||||
if(state.saturation()[np*c + p] > 0)
|
||||
@ -805,9 +919,9 @@ namespace Opm
|
||||
}
|
||||
}
|
||||
}
|
||||
props.matrix(nc, &state.pressure()[0], &z_init[0], &allcells[0], &allA_v[0], 0);
|
||||
props.matrix(number_of_cells, &state.pressure()[0], &z_init[0], &allcells[0], &allA_v[0], 0);
|
||||
|
||||
for (int c = 0; c < nc; ++c) {
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
// Using z = As
|
||||
double* z = &state.surfacevol()[c*np];
|
||||
const double* s = &state.saturation()[c*np];
|
||||
@ -839,24 +953,43 @@ namespace Opm
|
||||
const double gravity,
|
||||
State& state)
|
||||
{
|
||||
initStateFromDeck(grid, props, deck, gravity, state);
|
||||
initBlackoilStateFromDeck(grid.number_of_cells, grid.global_cell,
|
||||
grid.number_of_faces, UgGridHelpers::faceCells(grid),
|
||||
grid.face_centroids, grid.cell_centroids,grid.dimensions,
|
||||
props, deck, gravity, state);
|
||||
}
|
||||
|
||||
template <class FaceCells, class FCI, class CCI, class Props, class State>
|
||||
void initBlackoilStateFromDeck(int number_of_cells,
|
||||
const int* global_cell,
|
||||
int number_of_faces,
|
||||
FaceCells face_cells,
|
||||
FCI begin_face_centroids,
|
||||
CCI begin_cell_centroids,
|
||||
int dimensions,
|
||||
const Props& props,
|
||||
const EclipseGridParser& deck,
|
||||
const double gravity,
|
||||
State& state)
|
||||
{
|
||||
initStateFromDeck(number_of_cells, global_cell, number_of_faces,
|
||||
face_cells, begin_face_centroids, begin_cell_centroids,
|
||||
dimensions, props, deck, gravity, state);
|
||||
if (deck.hasField("RS")) {
|
||||
const std::vector<double>& rs_deck = deck.getFloatingPointValue("RS");
|
||||
const int num_cells = grid.number_of_cells;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c];
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
int c_deck = (global_cell == NULL) ? c : global_cell[c];
|
||||
state.gasoilratio()[c] = rs_deck[c_deck];
|
||||
}
|
||||
initBlackoilSurfvolUsingRSorRV(grid, props, state);
|
||||
initBlackoilSurfvolUsingRSorRV(number_of_cells, props, state);
|
||||
computeSaturation(props,state);
|
||||
} else if (deck.hasField("RV")){
|
||||
const std::vector<double>& rv_deck = deck.getFloatingPointValue("RV");
|
||||
const int num_cells = grid.number_of_cells;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
int c_deck = (grid.global_cell == NULL) ? c : grid.global_cell[c];
|
||||
for (int c = 0; c < number_of_cells; ++c) {
|
||||
int c_deck = (global_cell == NULL) ? c : global_cell[c];
|
||||
state.rv()[c] = rv_deck[c_deck];
|
||||
}
|
||||
initBlackoilSurfvolUsingRSorRV(grid, props, state);
|
||||
initBlackoilSurfvolUsingRSorRV(number_of_cells, props, state);
|
||||
computeSaturation(props,state);
|
||||
}
|
||||
|
||||
|
@ -45,15 +45,10 @@ namespace Opm
|
||||
const double* porosity,
|
||||
std::vector<double>& porevol)
|
||||
{
|
||||
int num_cells = grid.number_of_cells;
|
||||
porevol.resize(num_cells);
|
||||
std::transform(porosity, porosity + num_cells,
|
||||
grid.cell_volumes,
|
||||
porevol.begin(),
|
||||
std::multiplies<double>());
|
||||
computePorevolume(grid.number_of_cells, grid.cell_volumes,
|
||||
porosity, porevol);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Computes pore volume of all cells in a grid, with rock compressibility effects.
|
||||
/// @param[in] grid a grid
|
||||
/// @param[in] porosity array of grid.number_of_cells porosity values
|
||||
@ -66,13 +61,11 @@ namespace Opm
|
||||
const std::vector<double>& pressure,
|
||||
std::vector<double>& porevol)
|
||||
{
|
||||
int num_cells = grid.number_of_cells;
|
||||
porevol.resize(num_cells);
|
||||
for (int i = 0; i < num_cells; ++i) {
|
||||
porevol[i] = porosity[i]*grid.cell_volumes[i]*rock_comp.poroMult(pressure[i]);
|
||||
}
|
||||
computePorevolume(grid.number_of_cells, grid.cell_volumes, porosity, rock_comp, pressure,
|
||||
porevol);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Computes porosity of all cells in a grid, with rock compressibility effects.
|
||||
/// @param[in] grid a grid
|
||||
/// @param[in] porosity_standard array of grid.number_of_cells porosity values (at standard conditions)
|
||||
@ -401,24 +394,16 @@ namespace Opm
|
||||
const std::vector<double>& face_flux,
|
||||
std::vector<double>& cell_velocity)
|
||||
{
|
||||
const int dim = grid.dimensions;
|
||||
cell_velocity.clear();
|
||||
cell_velocity.resize(grid.number_of_cells*dim, 0.0);
|
||||
for (int face = 0; face < grid.number_of_faces; ++face) {
|
||||
int c[2] = { grid.face_cells[2*face], grid.face_cells[2*face + 1] };
|
||||
const double* fc = &grid.face_centroids[face*dim];
|
||||
double flux = face_flux[face];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (c[i] >= 0) {
|
||||
const double* cc = &grid.cell_centroids[c[i]*dim];
|
||||
for (int d = 0; d < dim; ++d) {
|
||||
double v_contrib = fc[d] - cc[d];
|
||||
v_contrib *= flux/grid.cell_volumes[c[i]];
|
||||
cell_velocity[c[i]*dim + d] += (i == 0) ? v_contrib : -v_contrib;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
estimateCellVelocity(grid.number_of_cells,
|
||||
grid.number_of_faces,
|
||||
grid.face_centroids,
|
||||
UgGridHelpers::faceCells(grid),
|
||||
grid.cell_centroids,
|
||||
grid.cell_volumes,
|
||||
grid.dimensions,
|
||||
face_flux,
|
||||
cell_velocity);
|
||||
|
||||
}
|
||||
|
||||
/// Extract a vector of water saturations from a vector of
|
||||
@ -490,44 +475,8 @@ namespace Opm
|
||||
const double* densities, const double gravity, const bool per_grid_cell,
|
||||
std::vector<double>& wdp)
|
||||
{
|
||||
const int nw = wells.number_of_wells;
|
||||
const size_t np = per_grid_cell ?
|
||||
saturations.size()/grid.number_of_cells
|
||||
: saturations.size()/wells.well_connpos[nw];
|
||||
// Simple for now:
|
||||
for (int i = 0; i < nw; i++) {
|
||||
double depth_ref = wells.depth_ref[i];
|
||||
for (int j = wells.well_connpos[i]; j < wells.well_connpos[i + 1]; j++) {
|
||||
int cell = wells.well_cells[j];
|
||||
|
||||
// Is this correct wrt. depth_ref?
|
||||
double cell_depth = grid.cell_centroids[3 * cell + 2];
|
||||
|
||||
double saturation_sum = 0.0;
|
||||
for (size_t p = 0; p < np; p++) {
|
||||
if (!per_grid_cell) {
|
||||
saturation_sum += saturations[j * np + p];
|
||||
} else {
|
||||
saturation_sum += saturations[np * cell + p];
|
||||
}
|
||||
}
|
||||
if (saturation_sum == 0) {
|
||||
saturation_sum = 1.0;
|
||||
}
|
||||
double density = 0.0;
|
||||
for (size_t p = 0; p < np; p++) {
|
||||
if (!per_grid_cell) {
|
||||
density += saturations[j * np + p] * densities[p] / saturation_sum;
|
||||
} else {
|
||||
// Is this a smart way of doing it?
|
||||
density += saturations[np * cell + p] * densities[p] / saturation_sum;
|
||||
}
|
||||
}
|
||||
|
||||
// Is the sign correct?
|
||||
wdp.push_back(density * (cell_depth - depth_ref) * gravity);
|
||||
}
|
||||
}
|
||||
computeWDP(wells, grid.number_of_cells, grid.cell_centroids, saturations, densities,
|
||||
gravity, per_grid_cell, wdp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,6 +41,16 @@ namespace Opm
|
||||
const double* porosity,
|
||||
std::vector<double>& porevol);
|
||||
|
||||
/// @brief Computes pore volume of all cells in a grid.
|
||||
/// @param[in] number_of_cells The number of cells of the grid.
|
||||
/// @param[in] begin_cell_volume Iterator to the volume of the first cell.
|
||||
/// @param[in] porosity array of grid.number_of_cells porosity values
|
||||
/// @param[out] porevol the pore volume by cell.
|
||||
template<class T>
|
||||
void computePorevolume(int number_of_cells,
|
||||
T begin_cell_volume,
|
||||
const double* porosity,
|
||||
std::vector<double>& porevol);
|
||||
|
||||
/// @brief Computes pore volume of all cells in a grid, with rock compressibility effects.
|
||||
/// @param[in] grid a grid
|
||||
@ -54,6 +64,21 @@ namespace Opm
|
||||
const std::vector<double>& pressure,
|
||||
std::vector<double>& porevol);
|
||||
|
||||
/// @brief Computes pore volume of all cells in a grid, with rock compressibility effects.
|
||||
/// @param[in] number_of_cells The number of cells of the grid.
|
||||
/// @param[in] Pointer to/ Iterator at the first cell volume.
|
||||
/// @param[in] porosity array of grid.number_of_cells porosity values
|
||||
/// @param[in] rock_comp rock compressibility properties
|
||||
/// @param[in] pressure pressure by cell
|
||||
/// @param[out] porevol the pore volume by cell.
|
||||
template<class T>
|
||||
void computePorevolume(int number_of_cells,
|
||||
T begin_cell_volume,
|
||||
const double* porosity,
|
||||
const RockCompressibility& rock_comp,
|
||||
const std::vector<double>& pressure,
|
||||
std::vector<double>& porevol);
|
||||
|
||||
/// @brief Computes porosity of all cells in a grid, with rock compressibility effects.
|
||||
/// @param[in] grid a grid
|
||||
/// @param[in] porosity_standard array of grid.number_of_cells porosity values (at reference presure)
|
||||
@ -188,6 +213,26 @@ namespace Opm
|
||||
const std::vector<double>& face_flux,
|
||||
std::vector<double>& cell_velocity);
|
||||
|
||||
/// @brief Estimates a scalar cell velocity from face fluxes.
|
||||
/// @param[in] number_of_cells The number of cells of the grid
|
||||
/// @param[in] number_of_faces The number of cells of the grid
|
||||
/// @param[in] begin_face_centroids Iterator pointing to first face centroid.
|
||||
/// @param[in] face_cells Mapping from faces to connected cells.
|
||||
/// @param[in] dimensions The dimensions of the grid.
|
||||
/// @param[in] begin_cell_centroids Iterator pointing to first cell centroid.
|
||||
/// @param[in] face_flux signed per-face fluxes
|
||||
/// @param[out] cell_velocity the estimated velocities.
|
||||
template<class CC, class FC, class FC1, class CV>
|
||||
void estimateCellVelocity(int number_of_cells,
|
||||
int number_of_faces,
|
||||
FC begin_face_centroids,
|
||||
FC1 face_cells,
|
||||
CC begin_cell_centroids,
|
||||
CV begin_cell_volumes,
|
||||
int dimension,
|
||||
const std::vector<double>& face_flux,
|
||||
std::vector<double>& cell_velocity);
|
||||
|
||||
/// Extract a vector of water saturations from a vector of
|
||||
/// interleaved water and oil saturations.
|
||||
void toWaterSat(const std::vector<double>& sboth,
|
||||
@ -218,6 +263,24 @@ namespace Opm
|
||||
const double* densities, const double gravity, const bool per_grid_cell,
|
||||
std::vector<double>& wdp);
|
||||
|
||||
/// Computes the WDP for each well.
|
||||
/// \param[in] wells Wells that need their wdp calculated.
|
||||
/// \param[in] number_of_cells The number of cells in the grid.
|
||||
/// \param[in] begin_cell_centroids Pointer/Iterator to the first cell centroid.
|
||||
/// \param[in] saturations A vector of weights for each cell for each phase
|
||||
/// in the grid (or well, see per_grid_cell parameter). So for cell i,
|
||||
/// saturations[i*densities.size() + p] should give the weight
|
||||
/// of phase p in cell i.
|
||||
/// \param[in] densities Density for each phase.
|
||||
/// \param[out] wdp Will contain, for each well, the wdp of the well.
|
||||
/// \param[in] per_grid_cell Whether or not the saturations are per grid cell or per
|
||||
/// well cell.
|
||||
template<class T>
|
||||
void computeWDP(const Wells& wells, int number_of_cells, T begin_cell_centroids,
|
||||
const std::vector<double>& saturations,
|
||||
const double* densities, const double gravity, const bool per_grid_cell,
|
||||
std::vector<double>& wdp);
|
||||
|
||||
/// Computes (sums) the flow rate for each well.
|
||||
/// \param[in] wells The wells for which the flow rate should be computed.
|
||||
/// \param[in] flow_rates_per_cell Flow rates per well cells. Should ordered the same way as
|
||||
@ -320,4 +383,5 @@ namespace Opm
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#include "miscUtilities_impl.hpp"
|
||||
#endif // OPM_MISCUTILITIES_HEADER_INCLUDED
|
||||
|
123
opm/core/utility/miscUtilities_impl.hpp
Normal file
123
opm/core/utility/miscUtilities_impl.hpp
Normal file
@ -0,0 +1,123 @@
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/props/rock/RockCompressibility.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// @brief Estimates a scalar cell velocity from face fluxes.
|
||||
/// @param[in] number_of_cells The number of cells of the grid
|
||||
/// @param[in] begin_face_centroids Iterator pointing to first face centroid.
|
||||
/// @param[in] face_cells Mapping from faces to connected cells.
|
||||
/// @param[in] dimensions The dimensions of the grid.
|
||||
/// @param[in] begin_cell_centroids Iterator pointing to first cell centroid.
|
||||
/// @param[in] face_flux signed per-face fluxes
|
||||
/// @param[out] cell_velocity the estimated velocities.
|
||||
template<class CC, class FC, class FC1, class CV>
|
||||
void estimateCellVelocity(int number_of_cells,
|
||||
int number_of_faces,
|
||||
FC begin_face_centroids,
|
||||
FC1 face_cells,
|
||||
CC begin_cell_centroids,
|
||||
CV begin_cell_volumes,
|
||||
int dimension,
|
||||
const std::vector<double>& face_flux,
|
||||
std::vector<double>& cell_velocity)
|
||||
{
|
||||
cell_velocity.clear();
|
||||
cell_velocity.resize(number_of_cells*dimension, 0.0);
|
||||
for (int face = 0; face < number_of_faces; ++face) {
|
||||
int c[2] = { face_cells(face, 0), face_cells(face, 1) };
|
||||
FC fc = UgGridHelpers::increment(begin_face_centroids, face, dimension);
|
||||
double flux = face_flux[face];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (c[i] >= 0) {
|
||||
CC cc = UgGridHelpers::increment(begin_cell_centroids, c[i], dimension);
|
||||
for (int d = 0; d < dimension; ++d) {
|
||||
double v_contrib = UgGridHelpers::getCoordinate(fc, d) - UgGridHelpers::getCoordinate(cc, d);
|
||||
v_contrib *= flux/begin_cell_volumes[c[i]];
|
||||
cell_velocity[c[i]*dimension + d] += (i == 0) ? v_contrib : -v_contrib;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void computePorevolume(int number_of_cells,
|
||||
T begin_cell_volume,
|
||||
const double* porosity,
|
||||
std::vector<double>& porevol)
|
||||
{
|
||||
porevol.resize(number_of_cells);
|
||||
std::transform(porosity, porosity + number_of_cells,
|
||||
begin_cell_volume,
|
||||
porevol.begin(),
|
||||
std::multiplies<double>());
|
||||
}
|
||||
|
||||
/// @brief Computes pore volume of all cells in a grid, with rock compressibility effects.
|
||||
/// @param[in] number_of_cells The number of cells of the grid.
|
||||
/// @param[in] porosity array of grid.number_of_cells porosity values
|
||||
/// @param[in] rock_comp rock compressibility properties
|
||||
/// @param[in] pressure pressure by cell
|
||||
/// @param[out] porevol the pore volume by cell.
|
||||
template<class T>
|
||||
void computePorevolume(int number_of_cells,
|
||||
T begin_cell_volumes,
|
||||
const double* porosity,
|
||||
const RockCompressibility& rock_comp,
|
||||
const std::vector<double>& pressure,
|
||||
std::vector<double>& porevol)
|
||||
{
|
||||
porevol.resize(number_of_cells);
|
||||
for (int i = 0; i < number_of_cells; ++i) {
|
||||
porevol[i] = porosity[i]*begin_cell_volumes[i]*rock_comp.poroMult(pressure[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void computeWDP(const Wells& wells, int number_of_cells, T begin_cell_centroids, const std::vector<double>& saturations,
|
||||
const double* densities, const double gravity, const bool per_grid_cell,
|
||||
std::vector<double>& wdp)
|
||||
{
|
||||
const int nw = wells.number_of_wells;
|
||||
const size_t np = per_grid_cell ?
|
||||
saturations.size()/number_of_cells
|
||||
: saturations.size()/wells.well_connpos[nw];
|
||||
// Simple for now:
|
||||
for (int i = 0; i < nw; i++) {
|
||||
double depth_ref = wells.depth_ref[i];
|
||||
for (int j = wells.well_connpos[i]; j < wells.well_connpos[i + 1]; j++) {
|
||||
int cell = wells.well_cells[j];
|
||||
|
||||
// Is this correct wrt. depth_ref?
|
||||
double cell_depth = UgGridHelpers
|
||||
::getCoordinate(UgGridHelpers::increment(begin_cell_centroids, cell, 3), 2);
|
||||
|
||||
double saturation_sum = 0.0;
|
||||
for (size_t p = 0; p < np; p++) {
|
||||
if (!per_grid_cell) {
|
||||
saturation_sum += saturations[j * np + p];
|
||||
} else {
|
||||
saturation_sum += saturations[np * cell + p];
|
||||
}
|
||||
}
|
||||
if (saturation_sum == 0) {
|
||||
saturation_sum = 1.0;
|
||||
}
|
||||
double density = 0.0;
|
||||
for (size_t p = 0; p < np; p++) {
|
||||
if (!per_grid_cell) {
|
||||
density += saturations[j * np + p] * densities[p] / saturation_sum;
|
||||
} else {
|
||||
// Is this a smart way of doing it?
|
||||
density += saturations[np * cell + p] * densities[p] / saturation_sum;
|
||||
}
|
||||
}
|
||||
|
||||
// Is the sign correct?
|
||||
wdp.push_back(density * (cell_depth - depth_ref) * gravity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -26,13 +26,11 @@
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/well_controls.h>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/core/wells/WellCollection.hpp>
|
||||
#include <opm/core/props/phaseUsageFromDeck.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
@ -44,17 +42,13 @@
|
||||
|
||||
|
||||
// Helper structs and functions for the implementation.
|
||||
namespace
|
||||
namespace WellsManagerDetail
|
||||
{
|
||||
|
||||
|
||||
|
||||
namespace ProductionControl
|
||||
{
|
||||
enum Mode { ORAT, WRAT, GRAT,
|
||||
LRAT, CRAT, RESV,
|
||||
BHP , THP , GRUP };
|
||||
|
||||
namespace Details {
|
||||
std::map<std::string, Mode>
|
||||
init_mode_map() {
|
||||
@ -122,8 +116,6 @@ namespace
|
||||
|
||||
namespace InjectionControl
|
||||
{
|
||||
enum Mode { RATE, RESV, BHP,
|
||||
THP, GRUP };
|
||||
|
||||
namespace Details {
|
||||
std::map<std::string, Mode>
|
||||
@ -177,28 +169,6 @@ namespace
|
||||
|
||||
} // namespace InjectionControl
|
||||
|
||||
|
||||
std::array<double, 3> getCubeDim(const UnstructuredGrid& grid, int cell)
|
||||
{
|
||||
using namespace std;
|
||||
std::array<double, 3> cube;
|
||||
int num_local_faces = grid.cell_facepos[cell + 1] - grid.cell_facepos[cell];
|
||||
vector<double> x(num_local_faces);
|
||||
vector<double> y(num_local_faces);
|
||||
vector<double> z(num_local_faces);
|
||||
for (int lf=0; lf<num_local_faces; ++ lf) {
|
||||
int face = grid.cell_faces[grid.cell_facepos[cell] + lf];
|
||||
const double* centroid = &grid.face_centroids[grid.dimensions*face];
|
||||
x[lf] = centroid[0];
|
||||
y[lf] = centroid[1];
|
||||
z[lf] = centroid[2];
|
||||
}
|
||||
cube[0] = *max_element(x.begin(), x.end()) - *min_element(x.begin(), x.end());
|
||||
cube[1] = *max_element(y.begin(), y.end()) - *min_element(y.begin(), y.end());
|
||||
cube[2] = *max_element(z.begin(), z.end()) - *min_element(z.begin(), z.end());
|
||||
return cube;
|
||||
}
|
||||
|
||||
// Use the Peaceman well model to compute well indices.
|
||||
// radius is the radius of the well.
|
||||
// cubical contains [dx, dy, dz] of the cell.
|
||||
@ -263,8 +233,8 @@ namespace Opm
|
||||
|
||||
|
||||
/// Construct from existing wells object.
|
||||
WellsManager::WellsManager(struct Wells* W)
|
||||
: w_(clone_wells(W))
|
||||
WellsManager::WellsManager(struct Wells* W, bool checkCellExistence)
|
||||
: w_(clone_wells(W)), checkCellExistence_(checkCellExistence)
|
||||
{
|
||||
}
|
||||
|
||||
@ -272,10 +242,11 @@ namespace Opm
|
||||
WellsManager::WellsManager(const Opm::EclipseStateConstPtr eclipseState,
|
||||
const size_t timeStep,
|
||||
const UnstructuredGrid& grid,
|
||||
const double* permeability)
|
||||
: w_(0)
|
||||
const double* permeability,
|
||||
bool checkCellExistence)
|
||||
: w_(0), checkCellExistence_(checkCellExistence)
|
||||
{
|
||||
if (grid.dimensions != 3) {
|
||||
if (UgGridHelpers::dimensions(grid) != 3) {
|
||||
OPM_THROW(std::runtime_error, "We cannot initialize wells from a deck unless the corresponding grid is 3-dimensional.");
|
||||
}
|
||||
|
||||
@ -285,7 +256,8 @@ namespace Opm
|
||||
}
|
||||
|
||||
std::map<int,int> cartesian_to_compressed;
|
||||
setupCompressedToCartesian(grid, cartesian_to_compressed);
|
||||
setupCompressedToCartesian(UgGridHelpers::globalCell(grid),
|
||||
UgGridHelpers::numCells(grid), cartesian_to_compressed);
|
||||
|
||||
// Obtain phase usage data.
|
||||
PhaseUsage pu = phaseUsageFromDeck(eclipseState);
|
||||
@ -305,7 +277,12 @@ namespace Opm
|
||||
well_names.reserve(wells.size());
|
||||
well_data.reserve(wells.size());
|
||||
|
||||
createWellsFromSpecs(wells, timeStep, grid, well_names, well_data, well_names_to_index, pu, cartesian_to_compressed, permeability);
|
||||
createWellsFromSpecs(wells, timeStep, UgGridHelpers::cell2Faces(grid),
|
||||
UgGridHelpers::cartDims(grid),
|
||||
UgGridHelpers::beginFaceCentroids(grid),
|
||||
UgGridHelpers::beginCellCentroids(grid),
|
||||
UgGridHelpers::dimensions(grid),
|
||||
well_names, well_data, well_names_to_index, pu, cartesian_to_compressed, permeability);
|
||||
setupWellControls(wells, timeStep, well_names, pu);
|
||||
|
||||
{
|
||||
@ -352,586 +329,16 @@ namespace Opm
|
||||
/// Construct wells from deck.
|
||||
WellsManager::WellsManager(const Opm::EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
const double* permeability)
|
||||
: w_(0)
|
||||
const double* permeability,
|
||||
bool checkCellExistence)
|
||||
: w_(0), checkCellExistence_(checkCellExistence)
|
||||
{
|
||||
if (grid.dimensions != 3) {
|
||||
OPM_THROW(std::runtime_error, "We cannot initialize wells from a deck unless the corresponding grid is 3-dimensional.");
|
||||
}
|
||||
// NOTE: Implementation copied and modified from dune-porsol's class BlackoilWells.
|
||||
std::vector<std::string> keywords;
|
||||
keywords.push_back("WELSPECS");
|
||||
keywords.push_back("COMPDAT");
|
||||
// keywords.push_back("WELTARG");
|
||||
if (!deck.hasFields(keywords)) {
|
||||
OPM_MESSAGE("Missing well keywords in deck, initializing no wells.");
|
||||
return;
|
||||
}
|
||||
if (!(deck.hasField("WCONINJE") || deck.hasField("WCONPROD")) ) {
|
||||
OPM_THROW(std::runtime_error, "Needed field is missing in file");
|
||||
}
|
||||
|
||||
// Obtain phase usage data.
|
||||
PhaseUsage pu = phaseUsageFromDeck(deck);
|
||||
|
||||
// These data structures will be filled in this constructor,
|
||||
// then used to initialize the Wells struct.
|
||||
std::vector<std::string> well_names;
|
||||
std::vector<WellData> well_data;
|
||||
std::vector<std::vector<PerfData> > wellperf_data;
|
||||
|
||||
// For easy lookup:
|
||||
std::map<std::string, int> well_names_to_index;
|
||||
typedef std::map<std::string, int>::const_iterator WNameIt;
|
||||
|
||||
// Get WELSPECS data.
|
||||
// It is allowed to have multiple lines corresponding to
|
||||
// the same well, in which case the last one encountered
|
||||
// is the one used.
|
||||
const WELSPECS& welspecs = deck.getWELSPECS();
|
||||
const int num_welspecs = welspecs.welspecs.size();
|
||||
well_names.reserve(num_welspecs);
|
||||
well_data.reserve(num_welspecs);
|
||||
for (int w = 0; w < num_welspecs; ++w) {
|
||||
// First check if this well has already been encountered.
|
||||
// If so, we modify it's data instead of appending a new well
|
||||
// to the well_data and well_names vectors.
|
||||
const std::string& name = welspecs.welspecs[w].name_;
|
||||
const double refdepth = welspecs.welspecs[w].datum_depth_BHP_;
|
||||
WNameIt wit = well_names_to_index.find(name);
|
||||
if (wit == well_names_to_index.end()) {
|
||||
// New well, append data.
|
||||
well_names_to_index[welspecs.welspecs[w].name_] = well_data.size();
|
||||
well_names.push_back(name);
|
||||
WellData wd;
|
||||
// If negative (defaulted), set refdepth to a marker
|
||||
// value, will be changed after getting perforation
|
||||
// data to the centroid of the cell of the top well
|
||||
// perforation.
|
||||
wd.reference_bhp_depth = (refdepth < 0.0) ? -1e100 : refdepth;
|
||||
wd.welspecsline = w;
|
||||
well_data.push_back(wd);
|
||||
} else {
|
||||
// Existing well, change data.
|
||||
const int wix = wit->second;
|
||||
well_data[wix].reference_bhp_depth = (refdepth < 0.0) ? -1e100 : refdepth;
|
||||
well_data[wix].welspecsline = w;
|
||||
}
|
||||
}
|
||||
const int num_wells = well_data.size();
|
||||
wellperf_data.resize(num_wells);
|
||||
|
||||
|
||||
// global_cell is a map from compressed cells to Cartesian grid cells.
|
||||
// We must make the inverse lookup.
|
||||
const int* global_cell = grid.global_cell;
|
||||
const int* cpgdim = grid.cartdims;
|
||||
std::map<int,int> cartesian_to_compressed;
|
||||
|
||||
if (global_cell) {
|
||||
for (int i = 0; i < grid.number_of_cells; ++i) {
|
||||
cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < grid.number_of_cells; ++i) {
|
||||
cartesian_to_compressed.insert(std::make_pair(i, i));
|
||||
}
|
||||
}
|
||||
|
||||
// Get COMPDAT data
|
||||
// It is *not* allowed to have multiple lines corresponding to
|
||||
// the same perforation!
|
||||
const COMPDAT& compdat = deck.getCOMPDAT();
|
||||
const int num_compdat = compdat.compdat.size();
|
||||
for (int kw = 0; kw < num_compdat; ++kw) {
|
||||
// Extract well name, or the part of the well name that
|
||||
// comes before the '*'.
|
||||
std::string name = compdat.compdat[kw].well_;
|
||||
std::string::size_type len = name.find('*');
|
||||
if (len != std::string::npos) {
|
||||
name = name.substr(0, len);
|
||||
}
|
||||
// Look for well with matching name.
|
||||
bool found = false;
|
||||
for (int wix = 0; wix < num_wells; ++wix) {
|
||||
if (well_names[wix].compare(0,len, name) == 0) { // equal
|
||||
// Extract corresponding WELSPECS defintion for
|
||||
// purpose of default location specification.
|
||||
const WelspecsLine& wspec = welspecs.welspecs[well_data[wix].welspecsline];
|
||||
|
||||
// We have a matching name.
|
||||
int ix = compdat.compdat[kw].grid_ind_[0] - 1;
|
||||
int jy = compdat.compdat[kw].grid_ind_[1] - 1;
|
||||
int kz1 = compdat.compdat[kw].grid_ind_[2] - 1;
|
||||
int kz2 = compdat.compdat[kw].grid_ind_[3] - 1;
|
||||
|
||||
if (ix < 0) {
|
||||
// Defaulted I location. Extract from WELSPECS.
|
||||
ix = wspec.I_ - 1;
|
||||
}
|
||||
if (jy < 0) {
|
||||
// Defaulted J location. Extract from WELSPECS.
|
||||
jy = wspec.J_ - 1;
|
||||
}
|
||||
if (kz1 < 0) {
|
||||
// Defaulted KZ1. Use top layer.
|
||||
kz1 = 0;
|
||||
}
|
||||
if (kz2 < 0) {
|
||||
// Defaulted KZ2. Use bottom layer.
|
||||
kz2 = cpgdim[2] - 1;
|
||||
}
|
||||
|
||||
for (int kz = kz1; kz <= kz2; ++kz) {
|
||||
int cart_grid_indx = ix + cpgdim[0]*(jy + cpgdim[1]*kz);
|
||||
std::map<int, int>::const_iterator cgit =
|
||||
cartesian_to_compressed.find(cart_grid_indx);
|
||||
if (cgit == cartesian_to_compressed.end()) {
|
||||
OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << ix << ' ' << jy << ' '
|
||||
<< kz << " not found in grid (well = " << name << ')');
|
||||
}
|
||||
int cell = cgit->second;
|
||||
PerfData pd;
|
||||
pd.cell = cell;
|
||||
if (compdat.compdat[kw].connect_trans_fac_ > 0.0) {
|
||||
pd.well_index = compdat.compdat[kw].connect_trans_fac_;
|
||||
} else {
|
||||
double radius = 0.5*compdat.compdat[kw].diameter_;
|
||||
if (radius <= 0.0) {
|
||||
radius = 0.5*unit::feet;
|
||||
OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius);
|
||||
}
|
||||
std::array<double, 3> cubical = getCubeDim(grid, cell);
|
||||
const double* cell_perm = &permeability[grid.dimensions*grid.dimensions*cell];
|
||||
pd.well_index = computeWellIndex(radius, cubical, cell_perm,
|
||||
compdat.compdat[kw].skin_factor_);
|
||||
}
|
||||
wellperf_data[wix].push_back(pd);
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
OPM_THROW(std::runtime_error, "Undefined well name: " << compdat.compdat[kw].well_
|
||||
<< " in COMPDAT");
|
||||
}
|
||||
}
|
||||
|
||||
// Set up reference depths that were defaulted. Count perfs.
|
||||
int num_perfs = 0;
|
||||
assert(grid.dimensions == 3);
|
||||
for (int w = 0; w < num_wells; ++w) {
|
||||
num_perfs += wellperf_data[w].size();
|
||||
if (well_data[w].reference_bhp_depth < 0.0) {
|
||||
// It was defaulted. Set reference depth to minimum perforation depth.
|
||||
double min_depth = 1e100;
|
||||
int num_wperfs = wellperf_data[w].size();
|
||||
for (int perf = 0; perf < num_wperfs; ++perf) {
|
||||
double depth = grid.cell_centroids[3*wellperf_data[w][perf].cell + 2];
|
||||
min_depth = std::min(min_depth, depth);
|
||||
}
|
||||
well_data[w].reference_bhp_depth = min_depth;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the well data structures.
|
||||
w_ = create_wells(pu.num_phases, num_wells, num_perfs);
|
||||
if (!w_) {
|
||||
OPM_THROW(std::runtime_error, "Failed creating Wells struct.");
|
||||
}
|
||||
|
||||
// Classify wells
|
||||
if (deck.hasField("WCONINJE")) {
|
||||
const std::vector<WconinjeLine>& lines = deck.getWCONINJE().wconinje;
|
||||
for (size_t i = 0 ; i < lines.size(); ++i) {
|
||||
const std::map<std::string, int>::const_iterator it = well_names_to_index.find(lines[i].well_);
|
||||
if (it != well_names_to_index.end()) {
|
||||
const int well_index = it->second;
|
||||
well_data[well_index].type = INJECTOR;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unseen well name: " << lines[i].well_ << " first seen in WCONINJE");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deck.hasField("WCONPROD")) {
|
||||
const std::vector<WconprodLine>& lines = deck.getWCONPROD().wconprod;
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
const std::map<std::string, int>::const_iterator it = well_names_to_index.find(lines[i].well_);
|
||||
if (it != well_names_to_index.end()) {
|
||||
const int well_index = it->second;
|
||||
well_data[well_index].type = PRODUCER;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unseen well name: " << lines[i].well_ << " first seen in WCONPROD");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Add wells.
|
||||
for (int w = 0; w < num_wells; ++w) {
|
||||
const int w_num_perf = wellperf_data[w].size();
|
||||
std::vector<int> perf_cells(w_num_perf);
|
||||
std::vector<double> perf_prodind(w_num_perf);
|
||||
for (int perf = 0; perf < w_num_perf; ++perf) {
|
||||
perf_cells[perf] = wellperf_data[w][perf].cell;
|
||||
perf_prodind[perf] = wellperf_data[w][perf].well_index;
|
||||
}
|
||||
const double* comp_frac = NULL;
|
||||
// We initialize all wells with a null component fraction,
|
||||
// and must (for injection wells) overwrite it later.
|
||||
int ok = add_well(well_data[w].type, well_data[w].reference_bhp_depth, w_num_perf,
|
||||
comp_frac, &perf_cells[0], &perf_prodind[0], well_names[w].c_str(), w_);
|
||||
if (!ok) {
|
||||
OPM_THROW(std::runtime_error, "Failed adding well " << well_names[w] << " to Wells data structure.");
|
||||
}
|
||||
}
|
||||
|
||||
// Get WCONINJE data, add injection controls to wells.
|
||||
// It is allowed to have multiple lines corresponding to
|
||||
// the same well, in which case the last one encountered
|
||||
// is the one used.
|
||||
if (deck.hasField("WCONINJE")) {
|
||||
const WCONINJE& wconinjes = deck.getWCONINJE();
|
||||
const int num_wconinjes = wconinjes.wconinje.size();
|
||||
for (int kw = 0; kw < num_wconinjes; ++kw) {
|
||||
const WconinjeLine& wci_line = wconinjes.wconinje[kw];
|
||||
// Extract well name, or the part of the well name that
|
||||
// comes before the '*'.
|
||||
std::string name = wci_line.well_;
|
||||
std::string::size_type len = name.find('*');
|
||||
if (len != std::string::npos) {
|
||||
name = name.substr(0, len);
|
||||
}
|
||||
bool well_found = false;
|
||||
for (int wix = 0; wix < num_wells; ++wix) {
|
||||
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
||||
well_found = true;
|
||||
assert(well_data[wix].type == w_->type[wix]);
|
||||
if (well_data[wix].type != INJECTOR) {
|
||||
OPM_THROW(std::runtime_error, "Found WCONINJE entry for a non-injector well: " << well_names[wix]);
|
||||
}
|
||||
|
||||
// Add all controls that are present in well.
|
||||
// First we must clear existing controls, in case the
|
||||
// current WCONINJE line is modifying earlier controls.
|
||||
clear_well_controls(wix, w_);
|
||||
int ok = 1;
|
||||
int control_pos[5] = { -1, -1, -1, -1, -1 };
|
||||
if (ok && wci_line.surface_flow_max_rate_ >= 0.0) {
|
||||
control_pos[InjectionControl::RATE] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
if (wci_line.injector_type_ == "WATER") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
} else if (wci_line.injector_type_ == "OIL") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
} else if (wci_line.injector_type_ == "GAS") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Injector type " << wci_line.injector_type_ << " not supported."
|
||||
"WellsManager only supports WATER, OIL and GAS injector types.");
|
||||
}
|
||||
ok = append_well_controls(SURFACE_RATE, wci_line.surface_flow_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wci_line.reservoir_flow_max_rate_ >= 0.0) {
|
||||
control_pos[InjectionControl::RESV] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
if (wci_line.injector_type_ == "WATER") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
} else if (wci_line.injector_type_ == "OIL") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
} else if (wci_line.injector_type_ == "GAS") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Injector type " << wci_line.injector_type_ << " not supported."
|
||||
"WellsManager only supports WATER, OIL and GAS injector types.");
|
||||
}
|
||||
ok = append_well_controls(RESERVOIR_RATE, wci_line.reservoir_flow_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wci_line.BHP_limit_ > 0.0) {
|
||||
control_pos[InjectionControl::BHP] = well_controls_get_num(w_->ctrls[wix]);
|
||||
ok = append_well_controls(BHP, wci_line.BHP_limit_,
|
||||
NULL, wix, w_);
|
||||
}
|
||||
if (ok && wci_line.THP_limit_ > 0.0) {
|
||||
OPM_THROW(std::runtime_error, "We cannot handle THP limit for well " << well_names[wix]);
|
||||
}
|
||||
if (!ok) {
|
||||
OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[wix]);
|
||||
}
|
||||
InjectionControl::Mode mode = InjectionControl::mode(wci_line.control_mode_);
|
||||
int cpos = control_pos[mode];
|
||||
if (cpos == -1 && mode != InjectionControl::GRUP) {
|
||||
OPM_THROW(std::runtime_error, "Control for " << wci_line.control_mode_ << " not specified in well " << well_names[wix]);
|
||||
}
|
||||
// We need to check if the well is shut or not
|
||||
if (wci_line.open_shut_flag_ == "SHUT") {
|
||||
cpos = ~cpos;
|
||||
}
|
||||
set_current_control(wix, cpos, w_);
|
||||
|
||||
// Set well component fraction.
|
||||
double cf[3] = { 0.0, 0.0, 0.0 };
|
||||
if (wci_line.injector_type_[0] == 'W') {
|
||||
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||
OPM_THROW(std::runtime_error, "Water phase not used, yet found water-injecting well.");
|
||||
}
|
||||
cf[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
} else if (wci_line.injector_type_[0] == 'O') {
|
||||
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil-injecting well.");
|
||||
}
|
||||
cf[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
} else if (wci_line.injector_type_[0] == 'G') {
|
||||
if (!pu.phase_used[BlackoilPhases::Vapour]) {
|
||||
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas-injecting well.");
|
||||
}
|
||||
cf[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
}
|
||||
std::copy(cf, cf + pu.num_phases, w_->comp_frac + wix*pu.num_phases);
|
||||
}
|
||||
}
|
||||
if (!well_found) {
|
||||
OPM_THROW(std::runtime_error, "Undefined well name: " << wci_line.well_
|
||||
<< " in WCONINJE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get WCONPROD data
|
||||
// It is allowed to have multiple lines corresponding to
|
||||
// the same well, in which case the last one encountered
|
||||
// is the one used.
|
||||
if (deck.hasField("WCONPROD")) {
|
||||
const WCONPROD& wconprods = deck.getWCONPROD();
|
||||
const int num_wconprods = wconprods.wconprod.size();
|
||||
for (int kw = 0; kw < num_wconprods; ++kw) {
|
||||
const WconprodLine& wcp_line = wconprods.wconprod[kw];
|
||||
std::string name = wcp_line.well_;
|
||||
std::string::size_type len = name.find('*');
|
||||
if (len != std::string::npos) {
|
||||
name = name.substr(0, len);
|
||||
}
|
||||
bool well_found = false;
|
||||
for (int wix = 0; wix < num_wells; ++wix) {
|
||||
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
||||
well_found = true;
|
||||
assert(well_data[wix].type == w_->type[wix]);
|
||||
if (well_data[wix].type != PRODUCER) {
|
||||
OPM_THROW(std::runtime_error, "Found WCONPROD entry for a non-producer well: " << well_names[wix]);
|
||||
}
|
||||
// Add all controls that are present in well.
|
||||
// First we must clear existing controls, in case the
|
||||
// current WCONPROD line is modifying earlier controls.
|
||||
clear_well_controls(wix, w_);
|
||||
int control_pos[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
int ok = 1;
|
||||
if (ok && wcp_line.oil_max_rate_ >= 0.0) {
|
||||
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||
OPM_THROW(std::runtime_error, "Oil phase not active and ORAT control specified.");
|
||||
}
|
||||
control_pos[ProductionControl::ORAT] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE, -wcp_line.oil_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.water_max_rate_ >= 0.0) {
|
||||
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||
OPM_THROW(std::runtime_error, "Water phase not active and WRAT control specified.");
|
||||
}
|
||||
control_pos[ProductionControl::WRAT] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE, -wcp_line.water_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.gas_max_rate_ >= 0.0) {
|
||||
if (!pu.phase_used[BlackoilPhases::Vapour]) {
|
||||
OPM_THROW(std::runtime_error, "Gas phase not active and GRAT control specified.");
|
||||
}
|
||||
control_pos[ProductionControl::GRAT] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE, -wcp_line.gas_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.liquid_max_rate_ >= 0.0) {
|
||||
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||
OPM_THROW(std::runtime_error, "Water phase not active and LRAT control specified.");
|
||||
}
|
||||
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||
OPM_THROW(std::runtime_error, "Oil phase not active and LRAT control specified.");
|
||||
}
|
||||
control_pos[ProductionControl::LRAT] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE, -wcp_line.liquid_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.reservoir_flow_max_rate_ >= 0.0) {
|
||||
control_pos[ProductionControl::RESV] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 1.0, 1.0, 1.0 };
|
||||
ok = append_well_controls(RESERVOIR_RATE, -wcp_line.reservoir_flow_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.BHP_limit_ > 0.0) {
|
||||
control_pos[ProductionControl::BHP] = well_controls_get_num(w_->ctrls[wix]);
|
||||
ok = append_well_controls(BHP, wcp_line.BHP_limit_,
|
||||
NULL, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.THP_limit_ > 0.0) {
|
||||
OPM_THROW(std::runtime_error, "We cannot handle THP limit for well " << well_names[wix]);
|
||||
}
|
||||
if (!ok) {
|
||||
OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[wix]);
|
||||
}
|
||||
ProductionControl::Mode mode = ProductionControl::mode(wcp_line.control_mode_);
|
||||
int cpos = control_pos[mode];
|
||||
if (cpos == -1 && mode != ProductionControl::GRUP) {
|
||||
OPM_THROW(std::runtime_error, "Control mode type " << mode << " not present in well " << well_names[wix]);
|
||||
}
|
||||
// If it's shut, we complement the cpos
|
||||
if (wcp_line.open_shut_flag_ == "SHUT") {
|
||||
cpos = ~cpos; // So we can easily retrieve the cpos later
|
||||
}
|
||||
set_current_control(wix, cpos, w_);
|
||||
}
|
||||
}
|
||||
if (!well_found) {
|
||||
OPM_THROW(std::runtime_error, "Undefined well name: " << wcp_line.well_
|
||||
<< " in WCONPROD");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get WELTARG data
|
||||
if (deck.hasField("WELTARG")) {
|
||||
OPM_THROW(std::runtime_error, "We currently do not handle WELTARG.");
|
||||
/*
|
||||
const WELTARG& weltargs = deck.getWELTARG();
|
||||
const int num_weltargs = weltargs.weltarg.size();
|
||||
for (int kw = 0; kw < num_weltargs; ++kw) {
|
||||
std::string name = weltargs.weltarg[kw].well_;
|
||||
std::string::size_type len = name.find('*');
|
||||
if (len != std::string::npos) {
|
||||
name = name.substr(0, len);
|
||||
}
|
||||
bool well_found = false;
|
||||
for (int wix = 0; wix < num_wells; ++wix) {
|
||||
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
||||
well_found = true;
|
||||
well_data[wix].target = weltargs.weltarg[kw].new_value_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!well_found) {
|
||||
OPM_THROW(std::runtime_error, "Undefined well name: " << weltargs.weltarg[kw].well_
|
||||
<< " in WELTARG");
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Debug output.
|
||||
#define EXTRA_OUTPUT
|
||||
#ifdef EXTRA_OUTPUT
|
||||
/*
|
||||
std::cout << "\t WELL DATA" << std::endl;
|
||||
for(int i = 0; i< num_wells; ++i) {
|
||||
std::cout << i << ": " << well_data[i].type << " "
|
||||
<< well_data[i].control << " " << well_data[i].target
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
std::cout << "\n\t PERF DATA" << std::endl;
|
||||
for(int i=0; i< int(wellperf_data.size()); ++i) {
|
||||
for(int j=0; j< int(wellperf_data[i].size()); ++j) {
|
||||
std::cout << i << ": " << wellperf_data[i][j].cell << " "
|
||||
<< wellperf_data[i][j].well_index << std::endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
if (deck.hasField("WELOPEN")) {
|
||||
const WELOPEN& welopen = deck.getWELOPEN();
|
||||
for (size_t i = 0; i < welopen.welopen.size(); ++i) {
|
||||
WelopenLine line = welopen.welopen[i];
|
||||
std::string wellname = line.well_;
|
||||
std::map<std::string, int>::const_iterator it = well_names_to_index.find(wellname);
|
||||
if (it == well_names_to_index.end()) {
|
||||
OPM_THROW(std::runtime_error, "Trying to open/shut well with name: \"" << wellname<<"\" but it's not registered under WELSPECS.");
|
||||
}
|
||||
const int index = it->second;
|
||||
if (line.openshutflag_ == "SHUT") {
|
||||
well_controls_shut_well( w_->ctrls[index] );
|
||||
} else if (line.openshutflag_ == "OPEN") {
|
||||
well_controls_open_well( w_->ctrls[index] );
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown Open/close keyword: \"" << line.openshutflag_<< "\". Allowed values: OPEN, SHUT.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the well_collection_ well group hierarchy.
|
||||
if (deck.hasField("GRUPTREE")) {
|
||||
std::cout << "Found gruptree" << std::endl;
|
||||
const GRUPTREE& gruptree = deck.getGRUPTREE();
|
||||
std::map<std::string, std::string>::const_iterator it = gruptree.tree.begin();
|
||||
for( ; it != gruptree.tree.end(); ++it) {
|
||||
well_collection_.addChild(it->first, it->second, deck);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < welspecs.welspecs.size(); ++i) {
|
||||
WelspecsLine line = welspecs.welspecs[i];
|
||||
well_collection_.addChild(line.name_, line.group_, deck);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Set the guide rates:
|
||||
if (deck.hasField("WGRUPCON")) {
|
||||
std::cout << "Found Wgrupcon" << std::endl;
|
||||
WGRUPCON wgrupcon = deck.getWGRUPCON();
|
||||
const std::vector<WgrupconLine>& lines = wgrupcon.wgrupcon;
|
||||
std::cout << well_collection_.getLeafNodes().size() << std::endl;
|
||||
for (size_t i = 0; i < lines.size(); i++) {
|
||||
std::string name = lines[i].well_;
|
||||
const int wix = well_names_to_index[name];
|
||||
WellNode& wellnode = *well_collection_.getLeafNodes()[wix];
|
||||
assert(wellnode.name() == name);
|
||||
if (well_data[wix].type == PRODUCER) {
|
||||
wellnode.prodSpec().guide_rate_ = lines[i].guide_rate_;
|
||||
if (lines[i].phase_ == "OIL") {
|
||||
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::OIL;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Guide rate type " << lines[i].phase_ << " specified for producer "
|
||||
<< name << " in WGRUPCON, cannot handle.");
|
||||
}
|
||||
} else if (well_data[wix].type == INJECTOR) {
|
||||
wellnode.injSpec().guide_rate_ = lines[i].guide_rate_;
|
||||
if (lines[i].phase_ == "RAT") {
|
||||
wellnode.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Guide rate type " << lines[i].phase_ << " specified for injector "
|
||||
<< name << " in WGRUPCON, cannot handle.");
|
||||
}
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown well type " << well_data[wix].type << " for well " << name);
|
||||
}
|
||||
}
|
||||
}
|
||||
well_collection_.setWellsPointer(w_);
|
||||
well_collection_.applyGroupControls();
|
||||
init(deck, grid.number_of_cells, grid.global_cell, grid.cartdims, grid.dimensions,
|
||||
grid.cell_centroids, UgGridHelpers::cell2Faces(grid), grid.face_centroids,
|
||||
permeability);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Destructor.
|
||||
WellsManager::~WellsManager()
|
||||
{
|
||||
@ -985,141 +392,25 @@ namespace Opm
|
||||
well_collection_.applyExplicitReinjectionControls(well_reservoirrates_phase, well_surfacerates_phase);
|
||||
}
|
||||
|
||||
void WellsManager::setupCompressedToCartesian(const UnstructuredGrid& grid, std::map<int,int>& cartesian_to_compressed ) {
|
||||
void WellsManager::setupCompressedToCartesian(const int* global_cell, int number_of_cells,
|
||||
std::map<int,int>& cartesian_to_compressed ) {
|
||||
// global_cell is a map from compressed cells to Cartesian grid cells.
|
||||
// We must make the inverse lookup.
|
||||
const int* global_cell = grid.global_cell;
|
||||
|
||||
if (global_cell) {
|
||||
for (int i = 0; i < grid.number_of_cells; ++i) {
|
||||
for (int i = 0; i < number_of_cells; ++i) {
|
||||
cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < grid.number_of_cells; ++i) {
|
||||
for (int i = 0; i < number_of_cells; ++i) {
|
||||
cartesian_to_compressed.insert(std::make_pair(i, i));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WellsManager::createWellsFromSpecs(std::vector<WellConstPtr>& wells, size_t timeStep,
|
||||
const UnstructuredGrid& grid,
|
||||
std::vector<std::string>& well_names,
|
||||
std::vector<WellData>& well_data,
|
||||
std::map<std::string, int>& well_names_to_index,
|
||||
const PhaseUsage& phaseUsage,
|
||||
std::map<int,int> cartesian_to_compressed,
|
||||
const double* permeability)
|
||||
{
|
||||
std::vector<std::vector<PerfData> > wellperf_data;
|
||||
wellperf_data.resize(wells.size());
|
||||
|
||||
int well_index = 0;
|
||||
for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
|
||||
WellConstPtr well = (*wellIter);
|
||||
{ // WELSPECS handling
|
||||
well_names_to_index[well->name()] = well_index;
|
||||
well_names.push_back(well->name());
|
||||
{
|
||||
WellData wd;
|
||||
// If negative (defaulted), set refdepth to a marker
|
||||
// value, will be changed after getting perforation
|
||||
// data to the centroid of the cell of the top well
|
||||
// perforation.
|
||||
wd.reference_bhp_depth = (well->getRefDepth() < 0.0) ? -1e100 : well->getRefDepth();
|
||||
wd.welspecsline = -1;
|
||||
if (well->isInjector( timeStep ))
|
||||
wd.type = INJECTOR;
|
||||
else
|
||||
wd.type = PRODUCER;
|
||||
well_data.push_back(wd);
|
||||
}
|
||||
}
|
||||
|
||||
{ // COMPDAT handling
|
||||
CompletionSetConstPtr completionSet = well->getCompletions(timeStep);
|
||||
for (size_t c=0; c<completionSet->size(); c++) {
|
||||
CompletionConstPtr completion = completionSet->get(c);
|
||||
int i = completion->getI();
|
||||
int j = completion->getJ();
|
||||
int k = completion->getK();
|
||||
|
||||
const int* cpgdim = grid.cartdims;
|
||||
int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
|
||||
std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx);
|
||||
if (cgit == cartesian_to_compressed.end()) {
|
||||
OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
|
||||
<< k << " not found in grid (well = " << well->name() << ')');
|
||||
}
|
||||
int cell = cgit->second;
|
||||
PerfData pd;
|
||||
pd.cell = cell;
|
||||
if (completion->getCF() > 0.0) {
|
||||
pd.well_index = completion->getCF();
|
||||
} else {
|
||||
double radius = 0.5*completion->getDiameter();
|
||||
if (radius <= 0.0) {
|
||||
radius = 0.5*unit::feet;
|
||||
OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius);
|
||||
}
|
||||
std::array<double, 3> cubical = getCubeDim(grid, cell);
|
||||
const double* cell_perm = &permeability[grid.dimensions*grid.dimensions*cell];
|
||||
pd.well_index = computeWellIndex(radius, cubical, cell_perm, completion->getDiameter());
|
||||
}
|
||||
wellperf_data[well_index].push_back(pd);
|
||||
}
|
||||
}
|
||||
well_index++;
|
||||
}
|
||||
|
||||
// Set up reference depths that were defaulted. Count perfs.
|
||||
|
||||
const int num_wells = well_data.size();
|
||||
|
||||
int num_perfs = 0;
|
||||
assert(grid.dimensions == 3);
|
||||
for (int w = 0; w < num_wells; ++w) {
|
||||
num_perfs += wellperf_data[w].size();
|
||||
if (well_data[w].reference_bhp_depth < 0.0) {
|
||||
// It was defaulted. Set reference depth to minimum perforation depth.
|
||||
double min_depth = 1e100;
|
||||
int num_wperfs = wellperf_data[w].size();
|
||||
for (int perf = 0; perf < num_wperfs; ++perf) {
|
||||
double depth = grid.cell_centroids[3*wellperf_data[w][perf].cell + 2];
|
||||
min_depth = std::min(min_depth, depth);
|
||||
}
|
||||
well_data[w].reference_bhp_depth = min_depth;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the well data structures.
|
||||
w_ = create_wells(phaseUsage.num_phases, num_wells, num_perfs);
|
||||
if (!w_) {
|
||||
OPM_THROW(std::runtime_error, "Failed creating Wells struct.");
|
||||
}
|
||||
|
||||
|
||||
// Add wells.
|
||||
for (int w = 0; w < num_wells; ++w) {
|
||||
const int w_num_perf = wellperf_data[w].size();
|
||||
std::vector<int> perf_cells(w_num_perf);
|
||||
std::vector<double> perf_prodind(w_num_perf);
|
||||
for (int perf = 0; perf < w_num_perf; ++perf) {
|
||||
perf_cells[perf] = wellperf_data[w][perf].cell;
|
||||
perf_prodind[perf] = wellperf_data[w][perf].well_index;
|
||||
}
|
||||
const double* comp_frac = NULL;
|
||||
// We initialize all wells with a null component fraction,
|
||||
// and must (for injection wells) overwrite it later.
|
||||
int ok = add_well(well_data[w].type, well_data[w].reference_bhp_depth, w_num_perf,
|
||||
comp_frac, &perf_cells[0], &perf_prodind[0], well_names[w].c_str(), w_);
|
||||
if (!ok) {
|
||||
OPM_THROW(std::runtime_error, "Failed adding well " << well_names[w] << " to Wells data structure.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WellsManager::setupWellControls(std::vector<WellConstPtr>& wells, size_t timeStep,
|
||||
std::vector<std::string>& well_names, const PhaseUsage& phaseUsage) {
|
||||
@ -1137,7 +428,7 @@ namespace Opm
|
||||
int control_pos[5] = { -1, -1, -1, -1, -1 };
|
||||
|
||||
if (well->hasInjectionControl(timeStep , WellInjector::RATE)) {
|
||||
control_pos[InjectionControl::RATE] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::InjectionControl::RATE] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
WellInjector::TypeEnum injectorType = well->getInjectorType(timeStep);
|
||||
|
||||
@ -1157,7 +448,7 @@ namespace Opm
|
||||
}
|
||||
|
||||
if (ok && well->hasInjectionControl(timeStep , WellInjector::RESV)) {
|
||||
control_pos[InjectionControl::RESV] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::InjectionControl::RESV] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
WellInjector::TypeEnum injectorType = well->getInjectorType(timeStep);
|
||||
|
||||
@ -1177,7 +468,7 @@ namespace Opm
|
||||
}
|
||||
|
||||
if (ok && well->hasInjectionControl(timeStep , WellInjector::BHP)) {
|
||||
control_pos[InjectionControl::BHP] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::InjectionControl::BHP] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
ok = append_well_controls(BHP,
|
||||
well->getBHPLimit(timeStep),
|
||||
NULL,
|
||||
@ -1196,9 +487,9 @@ namespace Opm
|
||||
|
||||
|
||||
{
|
||||
InjectionControl::Mode mode = InjectionControl::mode( well->getInjectorControlMode(timeStep) );
|
||||
WellsManagerDetail::InjectionControl::Mode mode = WellsManagerDetail::InjectionControl::mode( well->getInjectorControlMode(timeStep) );
|
||||
int cpos = control_pos[mode];
|
||||
if (cpos == -1 && mode != InjectionControl::GRUP) {
|
||||
if (cpos == -1 && mode != WellsManagerDetail::InjectionControl::GRUP) {
|
||||
OPM_THROW(std::runtime_error, "Control not specified in well " << well_names[well_index]);
|
||||
}
|
||||
|
||||
@ -1244,7 +535,7 @@ namespace Opm
|
||||
OPM_THROW(std::runtime_error, "Oil phase not active and ORAT control specified.");
|
||||
}
|
||||
|
||||
control_pos[ProductionControl::ORAT] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::ProductionControl::ORAT] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[phaseUsage.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE,
|
||||
@ -1258,7 +549,7 @@ namespace Opm
|
||||
if (!phaseUsage.phase_used[BlackoilPhases::Aqua]) {
|
||||
OPM_THROW(std::runtime_error, "Water phase not active and WRAT control specified.");
|
||||
}
|
||||
control_pos[ProductionControl::WRAT] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::ProductionControl::WRAT] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[phaseUsage.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE,
|
||||
@ -1272,7 +563,7 @@ namespace Opm
|
||||
if (!phaseUsage.phase_used[BlackoilPhases::Vapour]) {
|
||||
OPM_THROW(std::runtime_error, "Gas phase not active and GRAT control specified.");
|
||||
}
|
||||
control_pos[ProductionControl::GRAT] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::ProductionControl::GRAT] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[phaseUsage.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE,
|
||||
@ -1289,7 +580,7 @@ namespace Opm
|
||||
if (!phaseUsage.phase_used[BlackoilPhases::Liquid]) {
|
||||
OPM_THROW(std::runtime_error, "Oil phase not active and LRAT control specified.");
|
||||
}
|
||||
control_pos[ProductionControl::LRAT] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::ProductionControl::LRAT] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[phaseUsage.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
distr[phaseUsage.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
@ -1301,7 +592,7 @@ namespace Opm
|
||||
}
|
||||
|
||||
if (ok && well->hasProductionControl(timeStep , WellProducer::RESV)) {
|
||||
control_pos[ProductionControl::RESV] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::ProductionControl::RESV] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
double distr[3] = { 1.0, 1.0, 1.0 };
|
||||
ok = append_well_controls(RESERVOIR_RATE,
|
||||
-well->getResVRate(timeStep),
|
||||
@ -1311,7 +602,7 @@ namespace Opm
|
||||
}
|
||||
|
||||
if (ok && well->hasProductionControl(timeStep , WellProducer::BHP)) {
|
||||
control_pos[ProductionControl::BHP] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
control_pos[WellsManagerDetail::ProductionControl::BHP] = well_controls_get_num(w_->ctrls[well_index]);
|
||||
ok = append_well_controls(BHP,
|
||||
well->getBHPLimit( timeStep ) ,
|
||||
NULL,
|
||||
@ -1327,9 +618,9 @@ namespace Opm
|
||||
OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[well_index]);
|
||||
}
|
||||
|
||||
ProductionControl::Mode mode = ProductionControl::mode(well->getProducerControlMode(timeStep));
|
||||
WellsManagerDetail::ProductionControl::Mode mode = WellsManagerDetail::ProductionControl::mode(well->getProducerControlMode(timeStep));
|
||||
int cpos = control_pos[mode];
|
||||
if (cpos == -1 && mode != ProductionControl::GRUP) {
|
||||
if (cpos == -1 && mode != WellsManagerDetail::ProductionControl::GRUP) {
|
||||
OPM_THROW(std::runtime_error, "Control mode type " << mode << " not present in well " << well_names[well_index]);
|
||||
}
|
||||
// If it's shut, we complement the cpos
|
||||
|
@ -66,7 +66,7 @@ namespace Opm
|
||||
/// manage control switching does not exist.
|
||||
///
|
||||
/// @param[in] W Existing wells object.
|
||||
WellsManager(struct Wells* W);
|
||||
WellsManager(struct Wells* W, bool checkCellExistence=true);
|
||||
|
||||
/// Construct from input deck and grid.
|
||||
/// The permeability argument may be zero if the input contain
|
||||
@ -74,13 +74,27 @@ namespace Opm
|
||||
/// order to approximate these by the Peaceman formula.
|
||||
WellsManager(const Opm::EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
const double* permeability);
|
||||
const double* permeability,
|
||||
bool checkCellExistence=true);
|
||||
|
||||
|
||||
template<class CC, class F2C, class FC>
|
||||
WellsManager(const Opm::EclipseGridParser& deck,
|
||||
int num_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
int dimensions,
|
||||
CC begin_cell_centroids,
|
||||
const F2C& f2c,
|
||||
FC begin_face_centroids,
|
||||
const double* permeability,
|
||||
bool checkCellExistence=true);
|
||||
|
||||
WellsManager(const Opm::EclipseStateConstPtr eclipseState,
|
||||
const size_t timeStep,
|
||||
const UnstructuredGrid& grid,
|
||||
const double* permeability);
|
||||
const double* permeability,
|
||||
bool checkCellExistence=true);
|
||||
|
||||
/// Destructor.
|
||||
~WellsManager();
|
||||
@ -134,15 +148,29 @@ namespace Opm
|
||||
|
||||
|
||||
private:
|
||||
template<class CC, class F2C, class FC>
|
||||
void init(const Opm::EclipseGridParser& deck,
|
||||
int num_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
int dimensions,
|
||||
CC begin_cell_centroids,
|
||||
const F2C& f2c,
|
||||
FC begin_face_centroids,
|
||||
const double* permeability);
|
||||
// Disable copying and assignment.
|
||||
WellsManager(const WellsManager& other);
|
||||
WellsManager(const WellsManager& other, bool checkCellExistence=true);
|
||||
WellsManager& operator=(const WellsManager& other);
|
||||
static void setupCompressedToCartesian(const UnstructuredGrid& grid, std::map<int,int>& cartesian_to_compressed );
|
||||
static void setupCompressedToCartesian(const int* global_cell, int number_of_cells, std::map<int,int>& cartesian_to_compressed );
|
||||
void setupWellControls(std::vector<WellConstPtr>& wells, size_t timeStep,
|
||||
std::vector<std::string>& well_names, const PhaseUsage& phaseUsage);
|
||||
|
||||
template<class C2F, class CC, class FC>
|
||||
void createWellsFromSpecs( std::vector<WellConstPtr>& wells, size_t timeStep,
|
||||
const UnstructuredGrid& grid,
|
||||
const C2F& c2f,
|
||||
const int* cart_dims,
|
||||
FC begin_face_centroids,
|
||||
CC begin_cell_centroids,
|
||||
int dimensions,
|
||||
std::vector<std::string>& well_names,
|
||||
std::vector<WellData>& well_data,
|
||||
std::map<std::string, int> & well_names_to_index,
|
||||
@ -157,9 +185,10 @@ namespace Opm
|
||||
// Data
|
||||
Wells* w_;
|
||||
WellCollection well_collection_;
|
||||
bool checkCellExistence_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#include "WellsManager_impl.hpp"
|
||||
#endif // OPM_WELLSMANAGER_HEADER_INCLUDED
|
||||
|
819
opm/core/wells/WellsManager_impl.hpp
Normal file
819
opm/core/wells/WellsManager_impl.hpp
Normal file
@ -0,0 +1,819 @@
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace WellsManagerDetail
|
||||
{
|
||||
|
||||
|
||||
namespace ProductionControl
|
||||
{
|
||||
enum Mode { ORAT, WRAT, GRAT,
|
||||
LRAT, CRAT, RESV,
|
||||
BHP , THP , GRUP };
|
||||
/*
|
||||
namespace Details {
|
||||
std::map<std::string, Mode>
|
||||
init_mode_map();
|
||||
} // namespace Details
|
||||
*/
|
||||
Mode mode(const std::string& control);
|
||||
|
||||
|
||||
Mode mode(Opm::WellProducer::ControlModeEnum controlMode);
|
||||
} // namespace ProductionControl
|
||||
|
||||
|
||||
namespace InjectionControl
|
||||
{
|
||||
enum Mode { RATE, RESV, BHP,
|
||||
THP, GRUP };
|
||||
/*
|
||||
namespace Details {
|
||||
std::map<std::string, Mode>
|
||||
init_mode_map();
|
||||
} // namespace Details
|
||||
*/
|
||||
Mode mode(const std::string& control);
|
||||
|
||||
Mode mode(Opm::WellInjector::ControlModeEnum controlMode);
|
||||
|
||||
} // namespace InjectionControl
|
||||
|
||||
double computeWellIndex(const double radius,
|
||||
const std::array<double, 3>& cubical,
|
||||
const double* cell_permeability,
|
||||
const double skin_factor);
|
||||
|
||||
template<class C2F, class FC>
|
||||
std::array<double, 3> getCubeDim(const C2F& c2f, FC begin_face_centroids, int dimensions,
|
||||
int cell)
|
||||
{
|
||||
using namespace std;
|
||||
std::array<double, 3> cube;
|
||||
//typedef Opm::UgGridHelpers::Cell2FacesTraits<UnstructuredGrid>::Type Cell2Faces;
|
||||
//Cell2Faces c2f=Opm::UgGridHelpers::cell2Faces(grid);
|
||||
typedef typename C2F::row_type FaceRow;
|
||||
FaceRow faces=c2f[cell];
|
||||
typename FaceRow::const_iterator face=faces.begin();
|
||||
int num_local_faces = faces.end()-face;
|
||||
vector<double> x(num_local_faces);
|
||||
vector<double> y(num_local_faces);
|
||||
vector<double> z(num_local_faces);
|
||||
for (int lf=0; lf<num_local_faces; ++ lf, ++face) {
|
||||
FC centroid = Opm::UgGridHelpers::increment(begin_face_centroids, *face, dimensions);
|
||||
x[lf] = Opm::UgGridHelpers::getCoordinate(centroid, 0);
|
||||
y[lf] = Opm::UgGridHelpers::getCoordinate(centroid, 1);
|
||||
z[lf] = Opm::UgGridHelpers::getCoordinate(centroid, 2);
|
||||
}
|
||||
cube[0] = *max_element(x.begin(), x.end()) - *min_element(x.begin(), x.end());
|
||||
cube[1] = *max_element(y.begin(), y.end()) - *min_element(y.begin(), y.end());
|
||||
cube[2] = *max_element(z.begin(), z.end()) - *min_element(z.begin(), z.end());
|
||||
return cube;
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
template<class C2F, class CC, class FC>
|
||||
void WellsManager::createWellsFromSpecs(std::vector<WellConstPtr>& wells, size_t timeStep,
|
||||
const C2F& c2f,
|
||||
const int* cart_dims,
|
||||
FC begin_face_centroids,
|
||||
CC begin_cell_centroids,
|
||||
int dimensions,
|
||||
std::vector<std::string>& well_names,
|
||||
std::vector<WellData>& well_data,
|
||||
std::map<std::string, int>& well_names_to_index,
|
||||
const PhaseUsage& phaseUsage,
|
||||
std::map<int,int> cartesian_to_compressed,
|
||||
const double* permeability)
|
||||
{
|
||||
std::vector<std::vector<PerfData> > wellperf_data;
|
||||
wellperf_data.resize(wells.size());
|
||||
|
||||
int well_index = 0;
|
||||
for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
|
||||
WellConstPtr well = (*wellIter);
|
||||
{ // WELSPECS handling
|
||||
well_names_to_index[well->name()] = well_index;
|
||||
well_names.push_back(well->name());
|
||||
{
|
||||
WellData wd;
|
||||
// If negative (defaulted), set refdepth to a marker
|
||||
// value, will be changed after getting perforation
|
||||
// data to the centroid of the cell of the top well
|
||||
// perforation.
|
||||
wd.reference_bhp_depth = (well->getRefDepth() < 0.0) ? -1e100 : well->getRefDepth();
|
||||
wd.welspecsline = -1;
|
||||
if (well->isInjector( timeStep ))
|
||||
wd.type = INJECTOR;
|
||||
else
|
||||
wd.type = PRODUCER;
|
||||
well_data.push_back(wd);
|
||||
}
|
||||
}
|
||||
|
||||
{ // COMPDAT handling
|
||||
CompletionSetConstPtr completionSet = well->getCompletions(timeStep);
|
||||
for (size_t c=0; c<completionSet->size(); c++) {
|
||||
CompletionConstPtr completion = completionSet->get(c);
|
||||
int i = completion->getI();
|
||||
int j = completion->getJ();
|
||||
int k = completion->getK();
|
||||
|
||||
const int* cpgdim = cart_dims;
|
||||
int cart_grid_indx = i + cpgdim[0]*(j + cpgdim[1]*k);
|
||||
std::map<int, int>::const_iterator cgit = cartesian_to_compressed.find(cart_grid_indx);
|
||||
if (cgit == cartesian_to_compressed.end()) {
|
||||
if (checkCellExistence_)
|
||||
OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
|
||||
<< k << " not found in grid (well = " << well->name() << ')');
|
||||
continue;
|
||||
}
|
||||
int cell = cgit->second;
|
||||
PerfData pd;
|
||||
pd.cell = cell;
|
||||
if (completion->getCF() > 0.0) {
|
||||
pd.well_index = completion->getCF();
|
||||
} else {
|
||||
double radius = 0.5*completion->getDiameter();
|
||||
if (radius <= 0.0) {
|
||||
radius = 0.5*unit::feet;
|
||||
OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius);
|
||||
}
|
||||
std::array<double, 3> cubical = WellsManagerDetail::getCubeDim(c2f, begin_face_centroids,
|
||||
dimensions, cell);
|
||||
const double* cell_perm = &permeability[dimensions*dimensions*cell];
|
||||
pd.well_index = WellsManagerDetail::computeWellIndex(radius, cubical, cell_perm, completion->getDiameter());
|
||||
}
|
||||
wellperf_data[well_index].push_back(pd);
|
||||
}
|
||||
}
|
||||
well_index++;
|
||||
}
|
||||
|
||||
// Set up reference depths that were defaulted. Count perfs.
|
||||
|
||||
const int num_wells = well_data.size();
|
||||
|
||||
int num_perfs = 0;
|
||||
assert(dimensions == 3);
|
||||
for (int w = 0; w < num_wells; ++w) {
|
||||
num_perfs += wellperf_data[w].size();
|
||||
if (well_data[w].reference_bhp_depth < 0.0) {
|
||||
// It was defaulted. Set reference depth to minimum perforation depth.
|
||||
double min_depth = 1e100;
|
||||
int num_wperfs = wellperf_data[w].size();
|
||||
for (int perf = 0; perf < num_wperfs; ++perf) {
|
||||
double depth = UgGridHelpers
|
||||
::getCoordinate(UgGridHelpers::increment(begin_cell_centroids,
|
||||
wellperf_data[w][perf].cell,
|
||||
dimensions),
|
||||
2);
|
||||
min_depth = std::min(min_depth, depth);
|
||||
}
|
||||
well_data[w].reference_bhp_depth = min_depth;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the well data structures.
|
||||
w_ = create_wells(phaseUsage.num_phases, num_wells, num_perfs);
|
||||
if (!w_) {
|
||||
OPM_THROW(std::runtime_error, "Failed creating Wells struct.");
|
||||
}
|
||||
|
||||
|
||||
// Add wells.
|
||||
for (int w = 0; w < num_wells; ++w) {
|
||||
const int w_num_perf = wellperf_data[w].size();
|
||||
std::vector<int> perf_cells(w_num_perf);
|
||||
std::vector<double> perf_prodind(w_num_perf);
|
||||
for (int perf = 0; perf < w_num_perf; ++perf) {
|
||||
perf_cells[perf] = wellperf_data[w][perf].cell;
|
||||
perf_prodind[perf] = wellperf_data[w][perf].well_index;
|
||||
}
|
||||
const double* comp_frac = NULL;
|
||||
// We initialize all wells with a null component fraction,
|
||||
// and must (for injection wells) overwrite it later.
|
||||
int ok = add_well(well_data[w].type, well_data[w].reference_bhp_depth, w_num_perf,
|
||||
comp_frac, &perf_cells[0], &perf_prodind[0], well_names[w].c_str(), w_);
|
||||
if (!ok) {
|
||||
OPM_THROW(std::runtime_error, "Failed adding well " << well_names[w] << " to Wells data structure.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class CC, class C2F, class FC>
|
||||
WellsManager::WellsManager(const Opm::EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
int dimensions,
|
||||
CC begin_cell_centroids,
|
||||
const C2F& c2f,
|
||||
FC begin_face_centroids,
|
||||
const double* permeability,
|
||||
bool checkCellExistence)
|
||||
: w_(0), checkCellExistence_(checkCellExistence)
|
||||
{
|
||||
init(deck, number_of_cells, global_cell, cart_dims, dimensions,
|
||||
begin_cell_centroids, c2f, begin_face_centroids, permeability);
|
||||
}
|
||||
|
||||
/// Construct wells from deck.
|
||||
template<class CC, class C2F, class FC>
|
||||
void WellsManager::init(const Opm::EclipseGridParser& deck,
|
||||
int number_of_cells,
|
||||
const int* global_cell,
|
||||
const int* cart_dims,
|
||||
int dimensions,
|
||||
CC begin_cell_centroids,
|
||||
const C2F& c2f,
|
||||
FC begin_face_centroids,
|
||||
const double* permeability)
|
||||
{
|
||||
if (dimensions != 3) {
|
||||
OPM_THROW(std::runtime_error, "We cannot initialize wells from a deck unless the corresponding grid is 3-dimensional.");
|
||||
}
|
||||
// NOTE: Implementation copied and modified from dune-porsol's class BlackoilWells.
|
||||
std::vector<std::string> keywords;
|
||||
keywords.push_back("WELSPECS");
|
||||
keywords.push_back("COMPDAT");
|
||||
// keywords.push_back("WELTARG");
|
||||
if (!deck.hasFields(keywords)) {
|
||||
OPM_MESSAGE("Missing well keywords in deck, initializing no wells.");
|
||||
return;
|
||||
}
|
||||
if (!(deck.hasField("WCONINJE") || deck.hasField("WCONPROD")) ) {
|
||||
OPM_THROW(std::runtime_error, "Needed field is missing in file");
|
||||
}
|
||||
|
||||
// Obtain phase usage data.
|
||||
PhaseUsage pu = phaseUsageFromDeck(deck);
|
||||
|
||||
// These data structures will be filled in this constructor,
|
||||
// then used to initialize the Wells struct.
|
||||
std::vector<std::string> well_names;
|
||||
std::vector<WellData> well_data;
|
||||
std::vector<std::vector<PerfData> > wellperf_data;
|
||||
|
||||
// For easy lookup:
|
||||
std::map<std::string, int> well_names_to_index;
|
||||
typedef std::map<std::string, int>::const_iterator WNameIt;
|
||||
|
||||
// Get WELSPECS data.
|
||||
// It is allowed to have multiple lines corresponding to
|
||||
// the same well, in which case the last one encountered
|
||||
// is the one used.
|
||||
const WELSPECS& welspecs = deck.getWELSPECS();
|
||||
const int num_welspecs = welspecs.welspecs.size();
|
||||
well_names.reserve(num_welspecs);
|
||||
well_data.reserve(num_welspecs);
|
||||
for (int w = 0; w < num_welspecs; ++w) {
|
||||
// First check if this well has already been encountered.
|
||||
// If so, we modify it's data instead of appending a new well
|
||||
// to the well_data and well_names vectors.
|
||||
const std::string& name = welspecs.welspecs[w].name_;
|
||||
const double refdepth = welspecs.welspecs[w].datum_depth_BHP_;
|
||||
WNameIt wit = well_names_to_index.find(name);
|
||||
if (wit == well_names_to_index.end()) {
|
||||
// New well, append data.
|
||||
well_names_to_index[welspecs.welspecs[w].name_] = well_data.size();
|
||||
well_names.push_back(name);
|
||||
WellData wd;
|
||||
// If negative (defaulted), set refdepth to a marker
|
||||
// value, will be changed after getting perforation
|
||||
// data to the centroid of the cell of the top well
|
||||
// perforation.
|
||||
wd.reference_bhp_depth = (refdepth < 0.0) ? -1e100 : refdepth;
|
||||
wd.welspecsline = w;
|
||||
well_data.push_back(wd);
|
||||
} else {
|
||||
// Existing well, change data.
|
||||
const int wix = wit->second;
|
||||
well_data[wix].reference_bhp_depth = (refdepth < 0.0) ? -1e100 : refdepth;
|
||||
well_data[wix].welspecsline = w;
|
||||
}
|
||||
}
|
||||
const int num_wells = well_data.size();
|
||||
wellperf_data.resize(num_wells);
|
||||
|
||||
|
||||
// global_cell is a map from compressed cells to Cartesian grid cells.
|
||||
// We must make the inverse lookup.
|
||||
const int* cpgdim = cart_dims;
|
||||
std::map<int,int> cartesian_to_compressed;
|
||||
|
||||
if (global_cell) {
|
||||
for (int i = 0; i < number_of_cells; ++i) {
|
||||
cartesian_to_compressed.insert(std::make_pair(global_cell[i], i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < number_of_cells; ++i) {
|
||||
cartesian_to_compressed.insert(std::make_pair(i, i));
|
||||
}
|
||||
}
|
||||
|
||||
// Get COMPDAT data
|
||||
// It is *not* allowed to have multiple lines corresponding to
|
||||
// the same perforation!
|
||||
const COMPDAT& compdat = deck.getCOMPDAT();
|
||||
const int num_compdat = compdat.compdat.size();
|
||||
for (int kw = 0; kw < num_compdat; ++kw) {
|
||||
// Extract well name, or the part of the well name that
|
||||
// comes before the '*'.
|
||||
std::string name = compdat.compdat[kw].well_;
|
||||
std::string::size_type len = name.find('*');
|
||||
if (len != std::string::npos) {
|
||||
name = name.substr(0, len);
|
||||
}
|
||||
// Look for well with matching name.
|
||||
bool found = false;
|
||||
for (int wix = 0; wix < num_wells; ++wix) {
|
||||
if (well_names[wix].compare(0,len, name) == 0) { // equal
|
||||
// Extract corresponding WELSPECS defintion for
|
||||
// purpose of default location specification.
|
||||
const WelspecsLine& wspec = welspecs.welspecs[well_data[wix].welspecsline];
|
||||
|
||||
// We have a matching name.
|
||||
int ix = compdat.compdat[kw].grid_ind_[0] - 1;
|
||||
int jy = compdat.compdat[kw].grid_ind_[1] - 1;
|
||||
int kz1 = compdat.compdat[kw].grid_ind_[2] - 1;
|
||||
int kz2 = compdat.compdat[kw].grid_ind_[3] - 1;
|
||||
|
||||
if (ix < 0) {
|
||||
// Defaulted I location. Extract from WELSPECS.
|
||||
ix = wspec.I_ - 1;
|
||||
}
|
||||
if (jy < 0) {
|
||||
// Defaulted J location. Extract from WELSPECS.
|
||||
jy = wspec.J_ - 1;
|
||||
}
|
||||
if (kz1 < 0) {
|
||||
// Defaulted KZ1. Use top layer.
|
||||
kz1 = 0;
|
||||
}
|
||||
if (kz2 < 0) {
|
||||
// Defaulted KZ2. Use bottom layer.
|
||||
kz2 = cpgdim[2] - 1;
|
||||
}
|
||||
|
||||
for (int kz = kz1; kz <= kz2; ++kz) {
|
||||
int cart_grid_indx = ix + cpgdim[0]*(jy + cpgdim[1]*kz);
|
||||
std::map<int, int>::const_iterator cgit =
|
||||
cartesian_to_compressed.find(cart_grid_indx);
|
||||
if (cgit == cartesian_to_compressed.end()) {
|
||||
if(checkCellExistence_)
|
||||
OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << ix << ' ' << jy << ' '
|
||||
<< kz << " not found in grid (well = " << name << ')');
|
||||
continue;
|
||||
}
|
||||
int cell = cgit->second;
|
||||
PerfData pd;
|
||||
pd.cell = cell;
|
||||
if (compdat.compdat[kw].connect_trans_fac_ > 0.0) {
|
||||
pd.well_index = compdat.compdat[kw].connect_trans_fac_;
|
||||
} else {
|
||||
double radius = 0.5*compdat.compdat[kw].diameter_;
|
||||
if (radius <= 0.0) {
|
||||
radius = 0.5*unit::feet;
|
||||
OPM_MESSAGE("**** Warning: Well bore internal radius set to " << radius);
|
||||
}
|
||||
std::array<double, 3> cubical = WellsManagerDetail::getCubeDim(c2f,
|
||||
begin_face_centroids,
|
||||
dimensions,
|
||||
cell);
|
||||
const double* cell_perm = &permeability[dimensions*dimensions*cell];
|
||||
pd.well_index = WellsManagerDetail::computeWellIndex(radius, cubical, cell_perm,
|
||||
compdat.compdat[kw].skin_factor_);
|
||||
}
|
||||
wellperf_data[wix].push_back(pd);
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
OPM_THROW(std::runtime_error, "Undefined well name: " << compdat.compdat[kw].well_
|
||||
<< " in COMPDAT");
|
||||
}
|
||||
}
|
||||
|
||||
// Set up reference depths that were defaulted. Count perfs.
|
||||
int num_perfs = 0;
|
||||
assert(dimensions == 3);
|
||||
for (int w = 0; w < num_wells; ++w) {
|
||||
num_perfs += wellperf_data[w].size();
|
||||
if (well_data[w].reference_bhp_depth < 0.0) {
|
||||
// It was defaulted. Set reference depth to minimum perforation depth.
|
||||
double min_depth = 1e100;
|
||||
int num_wperfs = wellperf_data[w].size();
|
||||
for (int perf = 0; perf < num_wperfs; ++perf) {
|
||||
double depth = UgGridHelpers::
|
||||
getCoordinate(UgGridHelpers::increment(begin_cell_centroids,
|
||||
wellperf_data[w][perf].cell,
|
||||
dimensions), 2);
|
||||
min_depth = std::min(min_depth, depth);
|
||||
}
|
||||
well_data[w].reference_bhp_depth = min_depth;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the well data structures.
|
||||
w_ = create_wells(pu.num_phases, num_wells, num_perfs);
|
||||
if (!w_) {
|
||||
OPM_THROW(std::runtime_error, "Failed creating Wells struct.");
|
||||
}
|
||||
|
||||
// Classify wells
|
||||
if (deck.hasField("WCONINJE")) {
|
||||
const std::vector<WconinjeLine>& lines = deck.getWCONINJE().wconinje;
|
||||
for (size_t i = 0 ; i < lines.size(); ++i) {
|
||||
const std::map<std::string, int>::const_iterator it = well_names_to_index.find(lines[i].well_);
|
||||
if (it != well_names_to_index.end()) {
|
||||
const int well_index = it->second;
|
||||
well_data[well_index].type = INJECTOR;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unseen well name: " << lines[i].well_ << " first seen in WCONINJE");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deck.hasField("WCONPROD")) {
|
||||
const std::vector<WconprodLine>& lines = deck.getWCONPROD().wconprod;
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
const std::map<std::string, int>::const_iterator it = well_names_to_index.find(lines[i].well_);
|
||||
if (it != well_names_to_index.end()) {
|
||||
const int well_index = it->second;
|
||||
well_data[well_index].type = PRODUCER;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unseen well name: " << lines[i].well_ << " first seen in WCONPROD");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Add wells.
|
||||
for (int w = 0; w < num_wells; ++w) {
|
||||
const int w_num_perf = wellperf_data[w].size();
|
||||
std::vector<int> perf_cells(w_num_perf);
|
||||
std::vector<double> perf_prodind(w_num_perf);
|
||||
for (int perf = 0; perf < w_num_perf; ++perf) {
|
||||
perf_cells[perf] = wellperf_data[w][perf].cell;
|
||||
perf_prodind[perf] = wellperf_data[w][perf].well_index;
|
||||
}
|
||||
const double* comp_frac = NULL;
|
||||
// We initialize all wells with a null component fraction,
|
||||
// and must (for injection wells) overwrite it later.
|
||||
int ok = add_well(well_data[w].type, well_data[w].reference_bhp_depth, w_num_perf,
|
||||
comp_frac, &perf_cells[0], &perf_prodind[0], well_names[w].c_str(), w_);
|
||||
if (!ok) {
|
||||
OPM_THROW(std::runtime_error, "Failed adding well " << well_names[w] << " to Wells data structure.");
|
||||
}
|
||||
}
|
||||
|
||||
// Get WCONINJE data, add injection controls to wells.
|
||||
// It is allowed to have multiple lines corresponding to
|
||||
// the same well, in which case the last one encountered
|
||||
// is the one used.
|
||||
if (deck.hasField("WCONINJE")) {
|
||||
const WCONINJE& wconinjes = deck.getWCONINJE();
|
||||
const int num_wconinjes = wconinjes.wconinje.size();
|
||||
for (int kw = 0; kw < num_wconinjes; ++kw) {
|
||||
const WconinjeLine& wci_line = wconinjes.wconinje[kw];
|
||||
// Extract well name, or the part of the well name that
|
||||
// comes before the '*'.
|
||||
std::string name = wci_line.well_;
|
||||
std::string::size_type len = name.find('*');
|
||||
if (len != std::string::npos) {
|
||||
name = name.substr(0, len);
|
||||
}
|
||||
bool well_found = false;
|
||||
for (int wix = 0; wix < num_wells; ++wix) {
|
||||
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
||||
well_found = true;
|
||||
assert(well_data[wix].type == w_->type[wix]);
|
||||
if (well_data[wix].type != INJECTOR) {
|
||||
OPM_THROW(std::runtime_error, "Found WCONINJE entry for a non-injector well: " << well_names[wix]);
|
||||
}
|
||||
|
||||
// Add all controls that are present in well.
|
||||
// First we must clear existing controls, in case the
|
||||
// current WCONINJE line is modifying earlier controls.
|
||||
clear_well_controls(wix, w_);
|
||||
int ok = 1;
|
||||
int control_pos[5] = { -1, -1, -1, -1, -1 };
|
||||
if (ok && wci_line.surface_flow_max_rate_ >= 0.0) {
|
||||
control_pos[WellsManagerDetail::InjectionControl::RATE] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
if (wci_line.injector_type_ == "WATER") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
} else if (wci_line.injector_type_ == "OIL") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
} else if (wci_line.injector_type_ == "GAS") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Injector type " << wci_line.injector_type_ << " not supported."
|
||||
"WellsManager only supports WATER, OIL and GAS injector types.");
|
||||
}
|
||||
ok = append_well_controls(SURFACE_RATE, wci_line.surface_flow_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wci_line.reservoir_flow_max_rate_ >= 0.0) {
|
||||
control_pos[WellsManagerDetail::InjectionControl::RESV] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
if (wci_line.injector_type_ == "WATER") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
} else if (wci_line.injector_type_ == "OIL") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
} else if (wci_line.injector_type_ == "GAS") {
|
||||
distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Injector type " << wci_line.injector_type_ << " not supported."
|
||||
"WellsManager only supports WATER, OIL and GAS injector types.");
|
||||
}
|
||||
ok = append_well_controls(RESERVOIR_RATE, wci_line.reservoir_flow_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wci_line.BHP_limit_ > 0.0) {
|
||||
control_pos[WellsManagerDetail::InjectionControl::BHP] = well_controls_get_num(w_->ctrls[wix]);
|
||||
ok = append_well_controls(BHP, wci_line.BHP_limit_,
|
||||
NULL, wix, w_);
|
||||
}
|
||||
if (ok && wci_line.THP_limit_ > 0.0) {
|
||||
OPM_THROW(std::runtime_error, "We cannot handle THP limit for well " << well_names[wix]);
|
||||
}
|
||||
if (!ok) {
|
||||
OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[wix]);
|
||||
}
|
||||
WellsManagerDetail::InjectionControl::Mode mode = WellsManagerDetail::InjectionControl::mode(wci_line.control_mode_);
|
||||
int cpos = control_pos[mode];
|
||||
if (cpos == -1 && mode != WellsManagerDetail::InjectionControl::GRUP) {
|
||||
OPM_THROW(std::runtime_error, "Control for " << wci_line.control_mode_ << " not specified in well " << well_names[wix]);
|
||||
}
|
||||
// We need to check if the well is shut or not
|
||||
if (wci_line.open_shut_flag_ == "SHUT") {
|
||||
cpos = ~cpos;
|
||||
}
|
||||
set_current_control(wix, cpos, w_);
|
||||
|
||||
// Set well component fraction.
|
||||
double cf[3] = { 0.0, 0.0, 0.0 };
|
||||
if (wci_line.injector_type_[0] == 'W') {
|
||||
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||
OPM_THROW(std::runtime_error, "Water phase not used, yet found water-injecting well.");
|
||||
}
|
||||
cf[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
} else if (wci_line.injector_type_[0] == 'O') {
|
||||
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||
OPM_THROW(std::runtime_error, "Oil phase not used, yet found oil-injecting well.");
|
||||
}
|
||||
cf[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
} else if (wci_line.injector_type_[0] == 'G') {
|
||||
if (!pu.phase_used[BlackoilPhases::Vapour]) {
|
||||
OPM_THROW(std::runtime_error, "Gas phase not used, yet found gas-injecting well.");
|
||||
}
|
||||
cf[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
}
|
||||
std::copy(cf, cf + pu.num_phases, w_->comp_frac + wix*pu.num_phases);
|
||||
}
|
||||
}
|
||||
if (!well_found) {
|
||||
OPM_THROW(std::runtime_error, "Undefined well name: " << wci_line.well_
|
||||
<< " in WCONINJE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get WCONPROD data
|
||||
// It is allowed to have multiple lines corresponding to
|
||||
// the same well, in which case the last one encountered
|
||||
// is the one used.
|
||||
if (deck.hasField("WCONPROD")) {
|
||||
const WCONPROD& wconprods = deck.getWCONPROD();
|
||||
const int num_wconprods = wconprods.wconprod.size();
|
||||
for (int kw = 0; kw < num_wconprods; ++kw) {
|
||||
const WconprodLine& wcp_line = wconprods.wconprod[kw];
|
||||
std::string name = wcp_line.well_;
|
||||
std::string::size_type len = name.find('*');
|
||||
if (len != std::string::npos) {
|
||||
name = name.substr(0, len);
|
||||
}
|
||||
bool well_found = false;
|
||||
for (int wix = 0; wix < num_wells; ++wix) {
|
||||
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
||||
well_found = true;
|
||||
assert(well_data[wix].type == w_->type[wix]);
|
||||
if (well_data[wix].type != PRODUCER) {
|
||||
OPM_THROW(std::runtime_error, "Found WCONPROD entry for a non-producer well: " << well_names[wix]);
|
||||
}
|
||||
// Add all controls that are present in well.
|
||||
// First we must clear existing controls, in case the
|
||||
// current WCONPROD line is modifying earlier controls.
|
||||
clear_well_controls(wix, w_);
|
||||
int control_pos[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
int ok = 1;
|
||||
if (ok && wcp_line.oil_max_rate_ >= 0.0) {
|
||||
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||
OPM_THROW(std::runtime_error, "Oil phase not active and ORAT control specified.");
|
||||
}
|
||||
control_pos[WellsManagerDetail::ProductionControl::ORAT] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE, -wcp_line.oil_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.water_max_rate_ >= 0.0) {
|
||||
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||
OPM_THROW(std::runtime_error, "Water phase not active and WRAT control specified.");
|
||||
}
|
||||
control_pos[WellsManagerDetail::ProductionControl::WRAT] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE, -wcp_line.water_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.gas_max_rate_ >= 0.0) {
|
||||
if (!pu.phase_used[BlackoilPhases::Vapour]) {
|
||||
OPM_THROW(std::runtime_error, "Gas phase not active and GRAT control specified.");
|
||||
}
|
||||
control_pos[WellsManagerDetail::ProductionControl::GRAT] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[pu.phase_pos[BlackoilPhases::Vapour]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE, -wcp_line.gas_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.liquid_max_rate_ >= 0.0) {
|
||||
if (!pu.phase_used[BlackoilPhases::Aqua]) {
|
||||
OPM_THROW(std::runtime_error, "Water phase not active and LRAT control specified.");
|
||||
}
|
||||
if (!pu.phase_used[BlackoilPhases::Liquid]) {
|
||||
OPM_THROW(std::runtime_error, "Oil phase not active and LRAT control specified.");
|
||||
}
|
||||
control_pos[WellsManagerDetail::ProductionControl::LRAT] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 0.0, 0.0, 0.0 };
|
||||
distr[pu.phase_pos[BlackoilPhases::Aqua]] = 1.0;
|
||||
distr[pu.phase_pos[BlackoilPhases::Liquid]] = 1.0;
|
||||
ok = append_well_controls(SURFACE_RATE, -wcp_line.liquid_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.reservoir_flow_max_rate_ >= 0.0) {
|
||||
control_pos[WellsManagerDetail::ProductionControl::RESV] = well_controls_get_num(w_->ctrls[wix]);
|
||||
double distr[3] = { 1.0, 1.0, 1.0 };
|
||||
ok = append_well_controls(RESERVOIR_RATE, -wcp_line.reservoir_flow_max_rate_,
|
||||
distr, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.BHP_limit_ > 0.0) {
|
||||
control_pos[WellsManagerDetail::ProductionControl::BHP] = well_controls_get_num(w_->ctrls[wix]);
|
||||
ok = append_well_controls(BHP, wcp_line.BHP_limit_,
|
||||
NULL, wix, w_);
|
||||
}
|
||||
if (ok && wcp_line.THP_limit_ > 0.0) {
|
||||
OPM_THROW(std::runtime_error, "We cannot handle THP limit for well " << well_names[wix]);
|
||||
}
|
||||
if (!ok) {
|
||||
OPM_THROW(std::runtime_error, "Failure occured appending controls for well " << well_names[wix]);
|
||||
}
|
||||
WellsManagerDetail::ProductionControl::Mode mode = WellsManagerDetail::ProductionControl::mode(wcp_line.control_mode_);
|
||||
int cpos = control_pos[mode];
|
||||
if (cpos == -1 && mode != WellsManagerDetail::ProductionControl::GRUP) {
|
||||
OPM_THROW(std::runtime_error, "Control mode type " << mode << " not present in well " << well_names[wix]);
|
||||
}
|
||||
// If it's shut, we complement the cpos
|
||||
if (wcp_line.open_shut_flag_ == "SHUT") {
|
||||
cpos = ~cpos; // So we can easily retrieve the cpos later
|
||||
}
|
||||
set_current_control(wix, cpos, w_);
|
||||
}
|
||||
}
|
||||
if (!well_found) {
|
||||
OPM_THROW(std::runtime_error, "Undefined well name: " << wcp_line.well_
|
||||
<< " in WCONPROD");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get WELTARG data
|
||||
if (deck.hasField("WELTARG")) {
|
||||
OPM_THROW(std::runtime_error, "We currently do not handle WELTARG.");
|
||||
/*
|
||||
const WELTARG& weltargs = deck.getWELTARG();
|
||||
const int num_weltargs = weltargs.weltarg.size();
|
||||
for (int kw = 0; kw < num_weltargs; ++kw) {
|
||||
std::string name = weltargs.weltarg[kw].well_;
|
||||
std::string::size_type len = name.find('*');
|
||||
if (len != std::string::npos) {
|
||||
name = name.substr(0, len);
|
||||
}
|
||||
bool well_found = false;
|
||||
for (int wix = 0; wix < num_wells; ++wix) {
|
||||
if (well_names[wix].compare(0,len, name) == 0) { //equal
|
||||
well_found = true;
|
||||
well_data[wix].target = weltargs.weltarg[kw].new_value_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!well_found) {
|
||||
OPM_THROW(std::runtime_error, "Undefined well name: " << weltargs.weltarg[kw].well_
|
||||
<< " in WELTARG");
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Debug output.
|
||||
#define EXTRA_OUTPUT
|
||||
#ifdef EXTRA_OUTPUT
|
||||
/*
|
||||
std::cout << "\t WELL DATA" << std::endl;
|
||||
for(int i = 0; i< num_wells; ++i) {
|
||||
std::cout << i << ": " << well_data[i].type << " "
|
||||
<< well_data[i].control << " " << well_data[i].target
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
std::cout << "\n\t PERF DATA" << std::endl;
|
||||
for(int i=0; i< int(wellperf_data.size()); ++i) {
|
||||
for(int j=0; j< int(wellperf_data[i].size()); ++j) {
|
||||
std::cout << i << ": " << wellperf_data[i][j].cell << " "
|
||||
<< wellperf_data[i][j].well_index << std::endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
if (deck.hasField("WELOPEN")) {
|
||||
const WELOPEN& welopen = deck.getWELOPEN();
|
||||
for (size_t i = 0; i < welopen.welopen.size(); ++i) {
|
||||
WelopenLine line = welopen.welopen[i];
|
||||
std::string wellname = line.well_;
|
||||
std::map<std::string, int>::const_iterator it = well_names_to_index.find(wellname);
|
||||
if (it == well_names_to_index.end()) {
|
||||
OPM_THROW(std::runtime_error, "Trying to open/shut well with name: \"" << wellname<<"\" but it's not registered under WELSPECS.");
|
||||
}
|
||||
const int index = it->second;
|
||||
if (line.openshutflag_ == "SHUT") {
|
||||
well_controls_shut_well( w_->ctrls[index] );
|
||||
} else if (line.openshutflag_ == "OPEN") {
|
||||
well_controls_open_well( w_->ctrls[index] );
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown Open/close keyword: \"" << line.openshutflag_<< "\". Allowed values: OPEN, SHUT.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the well_collection_ well group hierarchy.
|
||||
if (deck.hasField("GRUPTREE")) {
|
||||
std::cout << "Found gruptree" << std::endl;
|
||||
const GRUPTREE& gruptree = deck.getGRUPTREE();
|
||||
std::map<std::string, std::string>::const_iterator it = gruptree.tree.begin();
|
||||
for( ; it != gruptree.tree.end(); ++it) {
|
||||
well_collection_.addChild(it->first, it->second, deck);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < welspecs.welspecs.size(); ++i) {
|
||||
WelspecsLine line = welspecs.welspecs[i];
|
||||
well_collection_.addChild(line.name_, line.group_, deck);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Set the guide rates:
|
||||
if (deck.hasField("WGRUPCON")) {
|
||||
std::cout << "Found Wgrupcon" << std::endl;
|
||||
WGRUPCON wgrupcon = deck.getWGRUPCON();
|
||||
const std::vector<WgrupconLine>& lines = wgrupcon.wgrupcon;
|
||||
std::cout << well_collection_.getLeafNodes().size() << std::endl;
|
||||
for (size_t i = 0; i < lines.size(); i++) {
|
||||
std::string name = lines[i].well_;
|
||||
const int wix = well_names_to_index[name];
|
||||
WellNode& wellnode = *well_collection_.getLeafNodes()[wix];
|
||||
assert(wellnode.name() == name);
|
||||
if (well_data[wix].type == PRODUCER) {
|
||||
wellnode.prodSpec().guide_rate_ = lines[i].guide_rate_;
|
||||
if (lines[i].phase_ == "OIL") {
|
||||
wellnode.prodSpec().guide_rate_type_ = ProductionSpecification::OIL;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Guide rate type " << lines[i].phase_ << " specified for producer "
|
||||
<< name << " in WGRUPCON, cannot handle.");
|
||||
}
|
||||
} else if (well_data[wix].type == INJECTOR) {
|
||||
wellnode.injSpec().guide_rate_ = lines[i].guide_rate_;
|
||||
if (lines[i].phase_ == "RAT") {
|
||||
wellnode.injSpec().guide_rate_type_ = InjectionSpecification::RAT;
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Guide rate type " << lines[i].phase_ << " specified for injector "
|
||||
<< name << " in WGRUPCON, cannot handle.");
|
||||
}
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Unknown well type " << well_data[wix].type << " for well " << name);
|
||||
}
|
||||
}
|
||||
}
|
||||
well_collection_.setWellsPointer(w_);
|
||||
well_collection_.applyGroupControls();
|
||||
}
|
||||
|
||||
} // end namespace Opm
|
Loading…
Reference in New Issue
Block a user