Deleted all files in opm/core/io
This removes OutputWriter and eclipse, vtk, vag as this functionality has moved to opm-output.
This commit is contained in:
parent
03d5a5ba25
commit
8e68a4d815
@ -45,14 +45,6 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
opm/core/grid/cpgpreprocess/uniquepoints.c
|
||||
opm/core/grid/grid.c
|
||||
opm/core/grid/grid_equal.cpp
|
||||
opm/core/io/OutputWriter.cpp
|
||||
opm/core/io/eclipse/EclipseGridInspector.cpp
|
||||
opm/core/io/eclipse/EclipseReader.cpp
|
||||
opm/core/io/eclipse/EclipseWriteRFTHandler.cpp
|
||||
opm/core/io/eclipse/EclipseWriter.cpp
|
||||
opm/core/io/eclipse/writeECLData.cpp
|
||||
opm/core/io/vag/vag.cpp
|
||||
opm/core/io/vtk/writeVtkData.cpp
|
||||
opm/core/linalg/LinearSolverFactory.cpp
|
||||
opm/core/linalg/LinearSolverInterface.cpp
|
||||
opm/core/linalg/LinearSolverIstl.cpp
|
||||
@ -151,10 +143,6 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
# originally generated with the command:
|
||||
# find tests -name '*.cpp' -a ! -wholename '*/not-unit/*' -printf '\t%p\n' | sort
|
||||
list (APPEND TEST_SOURCE_FILES
|
||||
tests/test_writenumwells.cpp
|
||||
tests/test_writeReadRestartFile.cpp
|
||||
tests/test_EclipseWriter.cpp
|
||||
tests/test_EclipseWriteRFTHandler.cpp
|
||||
tests/test_compressedpropertyaccess.cpp
|
||||
tests/test_dgbasis.cpp
|
||||
tests/test_cartgrid.cpp
|
||||
@ -220,7 +208,6 @@ list (APPEND TEST_DATA_FILES
|
||||
tests/satfuncEPS_D.DATA
|
||||
tests/testBlackoilState1.DATA
|
||||
tests/testBlackoilState2.DATA
|
||||
tests/testBlackoilState3.DATA
|
||||
tests/testPinch1.DATA
|
||||
tests/wells_manager_data.data
|
||||
tests/wells_manager_data_expanded.data
|
||||
@ -294,17 +281,6 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/core/grid/cpgpreprocess/geometry.h
|
||||
opm/core/grid/cpgpreprocess/preprocess.h
|
||||
opm/core/grid/cpgpreprocess/uniquepoints.h
|
||||
opm/core/io/OutputWriter.hpp
|
||||
opm/core/io/eclipse/CornerpointChopper.hpp
|
||||
opm/core/io/eclipse/EclipseGridInspector.hpp
|
||||
opm/core/io/eclipse/EclipseIOUtil.hpp
|
||||
opm/core/io/eclipse/EclipseReader.hpp
|
||||
opm/core/io/eclipse/EclipseUnits.hpp
|
||||
opm/core/io/eclipse/EclipseWriteRFTHandler.hpp
|
||||
opm/core/io/eclipse/EclipseWriter.hpp
|
||||
opm/core/io/eclipse/writeECLData.hpp
|
||||
opm/core/io/vag/vag.hpp
|
||||
opm/core/io/vtk/writeVtkData.hpp
|
||||
opm/core/linalg/LinearSolverFactory.hpp
|
||||
opm/core/linalg/LinearSolverInterface.hpp
|
||||
opm/core/linalg/LinearSolverIstl.hpp
|
||||
|
@ -1,103 +0,0 @@
|
||||
#include "OutputWriter.hpp"
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/io/eclipse/EclipseWriter.hpp>
|
||||
#include <opm/core/utility/parameters/Parameter.hpp>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
|
||||
#include <forward_list>
|
||||
#include <map>
|
||||
#include <memory> // unique_ptr
|
||||
|
||||
using namespace std;
|
||||
using namespace Opm;
|
||||
using namespace Opm::parameter;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Multiplexer over a list of output writers
|
||||
struct MultiWriter : public OutputWriter {
|
||||
/// Shorthand for a list of owned output writers
|
||||
typedef forward_list <unique_ptr <OutputWriter> > writers_t;
|
||||
typedef writers_t::iterator it_t;
|
||||
typedef unique_ptr <writers_t> ptr_t;
|
||||
|
||||
/// Adopt a list of writers
|
||||
MultiWriter (ptr_t writers) : writers_ (std::move (writers)) { }
|
||||
|
||||
/// Forward the call to all writers
|
||||
virtual void writeInit(const SimulatorTimerInterface &timer) {
|
||||
for (it_t it = writers_->begin (); it != writers_->end (); ++it) {
|
||||
(*it)->writeInit (timer);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void writeTimeStep(const SimulatorTimerInterface& timer,
|
||||
const SimulationDataContainer& reservoirState,
|
||||
const WellState& wellState,
|
||||
bool isSubstep) {
|
||||
for (it_t it = writers_->begin (); it != writers_->end(); ++it) {
|
||||
(*it)->writeTimeStep (timer, reservoirState, wellState, isSubstep);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ptr_t writers_;
|
||||
};
|
||||
|
||||
/// Psuedo-constructor, can appear in template
|
||||
template <typename Format> unique_ptr <OutputWriter>
|
||||
create (const ParameterGroup& params,
|
||||
std::shared_ptr <const EclipseState> eclipseState,
|
||||
const Opm::PhaseUsage &phaseUsage,
|
||||
std::shared_ptr <const UnstructuredGrid> grid) {
|
||||
return unique_ptr <OutputWriter> (new Format (params,
|
||||
eclipseState,
|
||||
phaseUsage,
|
||||
grid->number_of_cells,
|
||||
grid->global_cell));
|
||||
}
|
||||
|
||||
/// Map between keyword in configuration and the corresponding
|
||||
/// constructor function (type) that should be called when detected.
|
||||
/// The writer must have a constructor which takes params and parser.
|
||||
///
|
||||
/// If you want to add more possible writer formats, just add them
|
||||
/// to the list below!
|
||||
typedef map <const char*, unique_ptr <OutputWriter> (*)(
|
||||
const ParameterGroup&,
|
||||
std::shared_ptr <const EclipseState> eclipseState,
|
||||
const Opm::PhaseUsage &phaseUsage,
|
||||
std::shared_ptr <const UnstructuredGrid>)> map_t;
|
||||
map_t FORMATS = {
|
||||
{ "output_ecl", &create <EclipseWriter> },
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
unique_ptr <OutputWriter>
|
||||
OutputWriter::create (const ParameterGroup& params,
|
||||
std::shared_ptr <const EclipseState> eclipseState,
|
||||
const Opm::PhaseUsage &phaseUsage,
|
||||
std::shared_ptr <const UnstructuredGrid> grid) {
|
||||
// allocate a list which will be filled with writers. this list
|
||||
// is initially empty (no output).
|
||||
MultiWriter::ptr_t list (new MultiWriter::writers_t ());
|
||||
|
||||
// loop through the map and see if we can find the key that is
|
||||
// specified there
|
||||
typedef map_t::iterator map_it_t;
|
||||
for (map_it_t it = FORMATS.begin (); it != FORMATS.end(); ++it) {
|
||||
// keyword which would indicate that this format should be used
|
||||
const std::string name (it->first);
|
||||
|
||||
// invoke the constructor for the type if we found the keyword
|
||||
// and put the pointer to this writer onto the list
|
||||
if (params.getDefault <bool> (name, false)) {
|
||||
list->push_front (it->second (params, eclipseState, phaseUsage, grid));
|
||||
}
|
||||
}
|
||||
|
||||
// create a multiplexer from the list of formats we found
|
||||
return unique_ptr <OutputWriter> (new MultiWriter (std::move (list)));
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013 Uni Research 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_OUTPUT_WRITER_HPP
|
||||
#define OPM_OUTPUT_WRITER_HPP
|
||||
|
||||
#include <memory> // unique_ptr, shared_ptr
|
||||
#include <opm/core/simulator/SimulatorTimerInterface.hpp>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
|
||||
namespace Opm {
|
||||
|
||||
// forward declaration
|
||||
class EclipseState;
|
||||
namespace parameter { class ParameterGroup; }
|
||||
class SimulationDataContainer;
|
||||
class WellState;
|
||||
struct PhaseUsage;
|
||||
|
||||
/*!
|
||||
* Interface for writing non-compositional (blackoil, two-phase) simulation
|
||||
* state to files.
|
||||
*
|
||||
* Use the create() function to setup a chain of writer based on the
|
||||
* configuration values, e.g.
|
||||
*
|
||||
* \example
|
||||
* \code{.cpp}
|
||||
* ParameterGroup params (argc, argv, false);
|
||||
* auto parser = std::make_shared <const Deck> (
|
||||
* params.get <string> ("deck_filename"));
|
||||
*
|
||||
* std::unique_ptr <OutputWriter> writer =
|
||||
* OutputWriter::create (params, parser);
|
||||
*
|
||||
* // before the first timestep
|
||||
* writer->writeInit (timer);
|
||||
*
|
||||
* // after each timestep
|
||||
* writer->writeTimeStep (timer, state, wellState);
|
||||
*
|
||||
* \endcode
|
||||
*/
|
||||
class OutputWriter {
|
||||
public:
|
||||
/// Allow derived classes to be used in the unique_ptr that is returned
|
||||
/// from the create() method. (Every class that should be delete'd should
|
||||
/// have a proper constructor, and if the base class isn't virtual then
|
||||
/// the compiler won't call the right one when the unique_ptr goes out of
|
||||
/// scope).
|
||||
virtual ~OutputWriter () { }
|
||||
|
||||
/**
|
||||
* Write the static data (grid, PVT curves, etc) to disk.
|
||||
*
|
||||
* This routine should be called before the first timestep (i.e. when
|
||||
* timer.currentStepNum () == 0)
|
||||
*/
|
||||
virtual void writeInit(const SimulatorTimerInterface &timer) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Write a blackoil reservoir state to disk for later inspection with
|
||||
* visualization tools like ResInsight
|
||||
*
|
||||
* \param[in] timer The timer providing time, time step, etc. information
|
||||
* \param[in] reservoirState The thermodynamic state of the reservoir
|
||||
* \param[in] wellState The production/injection data for all wells
|
||||
*
|
||||
* This routine should be called after the timestep has been advanced,
|
||||
* i.e. timer.currentStepNum () > 0.
|
||||
*/
|
||||
virtual void writeTimeStep(const SimulatorTimerInterface& timer,
|
||||
const SimulationDataContainer& reservoirState,
|
||||
const WellState& wellState,
|
||||
bool isSubstep) = 0;
|
||||
|
||||
/*!
|
||||
* Create a suitable set of output formats based on configuration.
|
||||
*
|
||||
* @param params Configuration properties. This function will setup a
|
||||
* multiplexer of applicable output formats based on the
|
||||
* desired configuration values.
|
||||
*
|
||||
* @param deck Input deck used to set up the simulation.
|
||||
*
|
||||
* @param eclipseState The internalized input deck.
|
||||
*
|
||||
* @return Pointer to a multiplexer to all applicable output formats.
|
||||
*
|
||||
* @see Opm::share_obj
|
||||
*/
|
||||
static std::unique_ptr <OutputWriter>
|
||||
create (const parameter::ParameterGroup& params,
|
||||
std::shared_ptr <const EclipseState> eclipseState,
|
||||
const Opm::PhaseUsage &phaseUsage,
|
||||
std::shared_ptr <const UnstructuredGrid> grid);
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif /* OPM_OUTPUT_WRITER_HPP */
|
@ -1,457 +0,0 @@
|
||||
/*
|
||||
Copyright 2010 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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_CORNERPOINTCHOPPER_HEADER_INCLUDED
|
||||
#define OPM_CORNERPOINTCHOPPER_HEADER_INCLUDED
|
||||
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
class CornerPointChopper
|
||||
{
|
||||
public:
|
||||
CornerPointChopper(const std::string& file)
|
||||
{
|
||||
Opm::ParseContext parseContext;
|
||||
Opm::ParserPtr parser(new Opm::Parser());
|
||||
deck_ = parser->parseFile(file , parseContext);
|
||||
|
||||
metricUnits_.reset(Opm::UnitSystem::newMETRIC());
|
||||
|
||||
const auto& specgridRecord = deck_->getKeyword("SPECGRID").getRecord(0);
|
||||
dims_[0] = specgridRecord.getItem("NX").get< int >(0);
|
||||
dims_[1] = specgridRecord.getItem("NY").get< int >(0);
|
||||
dims_[2] = specgridRecord.getItem("NZ").get< int >(0);
|
||||
|
||||
int layersz = 8*dims_[0]*dims_[1];
|
||||
const std::vector<double>& ZCORN = deck_->getKeyword("ZCORN").getRawDoubleData();
|
||||
botmax_ = *std::max_element(ZCORN.begin(), ZCORN.begin() + layersz/2);
|
||||
topmin_ = *std::min_element(ZCORN.begin() + dims_[2]*layersz - layersz/2,
|
||||
ZCORN.begin() + dims_[2]*layersz);
|
||||
|
||||
abszmax_ = *std::max_element(ZCORN.begin(), ZCORN.end());
|
||||
abszmin_ = *std::min_element(ZCORN.begin(), ZCORN.end());
|
||||
|
||||
std::cout << "Parsed grdecl file with dimensions ("
|
||||
<< dims_[0] << ", " << dims_[1] << ", " << dims_[2] << ")" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const int* dimensions() const
|
||||
{
|
||||
return dims_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const int* newDimensions() const
|
||||
{
|
||||
return new_dims_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const std::pair<double, double> zLimits() const
|
||||
{
|
||||
return std::make_pair(botmax_, topmin_);
|
||||
}
|
||||
|
||||
const std::pair<double, double> abszLimits() const
|
||||
{
|
||||
return std::make_pair(abszmin_, abszmax_);
|
||||
}
|
||||
|
||||
|
||||
void verifyInscribedShoebox(int imin, int ilen, int imax,
|
||||
int jmin, int jlen, int jmax,
|
||||
double zmin, double zlen, double zmax)
|
||||
{
|
||||
if (imin < 0) {
|
||||
std::cerr << "Error! imin < 0 (imin = " << imin << ")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
if (ilen > dims_[0]) {
|
||||
std::cerr << "Error! ilen larger than grid (ilen = " << ilen <<")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
if (imax > dims_[0]) {
|
||||
std::cerr << "Error! imax larger than input grid (imax = " << imax << ")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
if (jmin < 0) {
|
||||
std::cerr << "Error! jmin < 0 (jmin = " << jmin << ")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
if (jlen > dims_[1]) {
|
||||
std::cerr << "Error! jlen larger than grid (jlen = " << jlen <<")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
if (jmax > dims_[1]) {
|
||||
std::cerr << "Error! jmax larger than input grid (jmax = " << jmax << ")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
if (zmin < abszmin_) {
|
||||
std::cerr << "Error! zmin ("<< zmin << ") less than minimum ZCORN value ("<< abszmin_ << ")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
if (zmax > abszmax_) {
|
||||
std::cerr << "Error! zmax ("<< zmax << ") larger than maximal ZCORN value ("<< abszmax_ << ")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
if (zlen > (abszmax_ - abszmin_)) {
|
||||
std::cerr << "Error! zlen ("<< zlen <<") larger than maximal ZCORN (" << abszmax_ << ") minus minimal ZCORN ("<< abszmin_ <<")\n";
|
||||
throw std::runtime_error("Inconsistent user input.");
|
||||
}
|
||||
}
|
||||
|
||||
void chop(int imin, int imax, int jmin, int jmax, double zmin, double zmax, bool resettoorigin=true)
|
||||
{
|
||||
new_dims_[0] = imax - imin;
|
||||
new_dims_[1] = jmax - jmin;
|
||||
|
||||
// Filter the coord field
|
||||
const std::vector<double>& COORD = deck_->getKeyword("COORD").getRawDoubleData();
|
||||
int num_coord = COORD.size();
|
||||
if (num_coord != 6*(dims_[0] + 1)*(dims_[1] + 1)) {
|
||||
std::cerr << "Error! COORD size (" << COORD.size() << ") not consistent with SPECGRID\n";
|
||||
throw std::runtime_error("Inconsistent COORD and SPECGRID.");
|
||||
}
|
||||
int num_new_coord = 6*(new_dims_[0] + 1)*(new_dims_[1] + 1);
|
||||
double x_correction = COORD[6*((dims_[0] + 1)*jmin + imin)];
|
||||
double y_correction = COORD[6*((dims_[0] + 1)*jmin + imin) + 1];
|
||||
new_COORD_.resize(num_new_coord, 1e100);
|
||||
for (int j = jmin; j < jmax + 1; ++j) {
|
||||
for (int i = imin; i < imax + 1; ++i) {
|
||||
int pos = (dims_[0] + 1)*j + i;
|
||||
int new_pos = (new_dims_[0] + 1)*(j-jmin) + (i-imin);
|
||||
// Copy all 6 coordinates for a pillar.
|
||||
std::copy(COORD.begin() + 6*pos, COORD.begin() + 6*(pos + 1), new_COORD_.begin() + 6*new_pos);
|
||||
if (resettoorigin) {
|
||||
// Substract lowest x value from all X-coords, similarly for y, and truncate in z-direction
|
||||
new_COORD_[6*new_pos] -= x_correction;
|
||||
new_COORD_[6*new_pos + 1] -= y_correction;
|
||||
new_COORD_[6*new_pos + 2] = 0;
|
||||
new_COORD_[6*new_pos + 3] -= x_correction;
|
||||
new_COORD_[6*new_pos + 4] -= y_correction;
|
||||
new_COORD_[6*new_pos + 5] = zmax-zmin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the z limits, check if they must be changed to make a shoe-box.
|
||||
// This means that zmin must be greater than or equal to the highest
|
||||
// coordinate of the bottom surface, while zmax must be less than or
|
||||
// equal to the lowest coordinate of the top surface.
|
||||
int layersz = 8*dims_[0]*dims_[1];
|
||||
const std::vector<double>& ZCORN = deck_->getKeyword("ZCORN").getRawDoubleData();
|
||||
int num_zcorn = ZCORN.size();
|
||||
if (num_zcorn != layersz*dims_[2]) {
|
||||
std::cerr << "Error! ZCORN size (" << ZCORN.size() << ") not consistent with SPECGRID\n";
|
||||
throw std::runtime_error("Inconsistent ZCORN and SPECGRID.");
|
||||
}
|
||||
|
||||
zmin = std::max(zmin, botmax_);
|
||||
zmax = std::min(zmax, topmin_);
|
||||
if (zmin >= zmax) {
|
||||
std::cerr << "Error: zmin >= zmax (zmin = " << zmin << ", zmax = " << zmax << ")\n";
|
||||
throw std::runtime_error("zmin >= zmax");
|
||||
}
|
||||
std::cout << "Chopping subsample, i: (" << imin << "--" << imax << ") j: (" << jmin << "--" << jmax << ") z: (" << zmin << "--" << zmax << ")" << std::endl;
|
||||
|
||||
// We must find the maximum and minimum k value for the given z limits.
|
||||
// First, find the first layer with a z-coordinate strictly above zmin.
|
||||
int kmin = -1;
|
||||
for (int k = 0; k < dims_[2]; ++k) {
|
||||
double layer_max = *std::max_element(ZCORN.begin() + k*layersz, ZCORN.begin() + (k + 1)*layersz);
|
||||
if (layer_max > zmin) {
|
||||
kmin = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Then, find the last layer with a z-coordinate strictly below zmax.
|
||||
int kmax = -1;
|
||||
for (int k = dims_[2]; k > 0; --k) {
|
||||
double layer_min = *std::min_element(ZCORN.begin() + (k - 1)*layersz, ZCORN.begin() + k*layersz);
|
||||
if (layer_min < zmax) {
|
||||
kmax = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_dims_[2] = kmax - kmin;
|
||||
|
||||
// Filter the ZCORN field, build mapping from new to old cells.
|
||||
double z_origin_correction = 0.0;
|
||||
if (resettoorigin) {
|
||||
z_origin_correction = zmin;
|
||||
}
|
||||
new_ZCORN_.resize(8*new_dims_[0]*new_dims_[1]*new_dims_[2], 1e100);
|
||||
new_to_old_cell_.resize(new_dims_[0]*new_dims_[1]*new_dims_[2], -1);
|
||||
int cellcount = 0;
|
||||
int delta[3] = { 1, 2*dims_[0], 4*dims_[0]*dims_[1] };
|
||||
int new_delta[3] = { 1, 2*new_dims_[0], 4*new_dims_[0]*new_dims_[1] };
|
||||
for (int k = kmin; k < kmax; ++k) {
|
||||
for (int j = jmin; j < jmax; ++j) {
|
||||
for (int i = imin; i < imax; ++i) {
|
||||
new_to_old_cell_[cellcount++] = dims_[0]*dims_[1]*k + dims_[0]*j + i;
|
||||
int old_ix = 2*(i*delta[0] + j*delta[1] + k*delta[2]);
|
||||
int new_ix = 2*((i-imin)*new_delta[0] + (j-jmin)*new_delta[1] + (k-kmin)*new_delta[2]);
|
||||
int old_indices[8] = { old_ix, old_ix + delta[0],
|
||||
old_ix + delta[1], old_ix + delta[1] + delta[0],
|
||||
old_ix + delta[2], old_ix + delta[2] + delta[0],
|
||||
old_ix + delta[2] + delta[1], old_ix + delta[2] + delta[1] + delta[0] };
|
||||
int new_indices[8] = { new_ix, new_ix + new_delta[0],
|
||||
new_ix + new_delta[1], new_ix + new_delta[1] + new_delta[0],
|
||||
new_ix + new_delta[2], new_ix + new_delta[2] + new_delta[0],
|
||||
new_ix + new_delta[2] + new_delta[1], new_ix + new_delta[2] + new_delta[1] + new_delta[0] };
|
||||
for (int cc = 0; cc < 8; ++cc) {
|
||||
new_ZCORN_[new_indices[cc]] = std::min(zmax, std::max(zmin, ZCORN[old_indices[cc]])) - z_origin_correction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterIntegerField("ACTNUM", new_ACTNUM_);
|
||||
filterDoubleField("PORO", new_PORO_);
|
||||
filterDoubleField("NTG", new_NTG_);
|
||||
filterDoubleField("SWCR", new_SWCR_);
|
||||
filterDoubleField("SOWCR", new_SOWCR_);
|
||||
filterDoubleField("PERMX", new_PERMX_);
|
||||
filterDoubleField("PERMY", new_PERMY_);
|
||||
filterDoubleField("PERMZ", new_PERMZ_);
|
||||
filterIntegerField("SATNUM", new_SATNUM_);
|
||||
}
|
||||
|
||||
/// Return a sub-deck with fields corresponding to the selected subset.
|
||||
Opm::DeckConstPtr subDeck()
|
||||
{
|
||||
Opm::DeckPtr subDeck(new Opm::Deck);
|
||||
|
||||
Opm::DeckKeyword specGridKw("SPECGRID");
|
||||
Opm::DeckRecord specGridRecord;
|
||||
|
||||
auto nxItem = Opm::DeckItem::make< int >("NX");
|
||||
auto nyItem = Opm::DeckItem::make< int >("NY");
|
||||
auto nzItem = Opm::DeckItem::make< int >("NZ");
|
||||
auto numresItem = Opm::DeckItem::make< int >("NUMRES");
|
||||
auto coordTypeItem = Opm::DeckItem::make< std::string >("COORD_TYPE");
|
||||
|
||||
nxItem.push_back(new_dims_[0]);
|
||||
nyItem.push_back(new_dims_[1]);
|
||||
nzItem.push_back(new_dims_[2]);
|
||||
numresItem.push_back(1);
|
||||
coordTypeItem.push_back("F");
|
||||
|
||||
specGridRecord.addItem(std::move(nxItem));
|
||||
specGridRecord.addItem(std::move(nyItem));
|
||||
specGridRecord.addItem(std::move(nzItem));
|
||||
specGridRecord.addItem(std::move(numresItem));
|
||||
specGridRecord.addItem(std::move(coordTypeItem));
|
||||
|
||||
specGridKw.addRecord(std::move(specGridRecord));
|
||||
|
||||
subDeck->addKeyword(std::move(specGridKw));
|
||||
addDoubleKeyword_(subDeck, "COORD", /*dimension=*/"Length", new_COORD_);
|
||||
addDoubleKeyword_(subDeck, "ZCORN", /*dimension=*/"Length", new_ZCORN_);
|
||||
addIntKeyword_(subDeck, "ACTNUM", new_ACTNUM_);
|
||||
addDoubleKeyword_(subDeck, "PORO", /*dimension=*/"1", new_PORO_);
|
||||
addDoubleKeyword_(subDeck, "NTG", /*dimension=*/"1", new_NTG_);
|
||||
addDoubleKeyword_(subDeck, "SWCR", /*dimension=*/"1", new_SWCR_);
|
||||
addDoubleKeyword_(subDeck, "SOWCR", /*dimension=*/"1", new_SOWCR_);
|
||||
addDoubleKeyword_(subDeck, "PERMX", /*dimension=*/"Permeability", new_PERMX_);
|
||||
addDoubleKeyword_(subDeck, "PERMY", /*dimension=*/"Permeability", new_PERMY_);
|
||||
addDoubleKeyword_(subDeck, "PERMZ", /*dimension=*/"Permeability", new_PERMZ_);
|
||||
addIntKeyword_(subDeck, "SATNUM", new_SATNUM_);
|
||||
return subDeck;
|
||||
}
|
||||
void writeGrdecl(const std::string& filename)
|
||||
{
|
||||
// Output new versions of SPECGRID, COORD, ZCORN, ACTNUM, PERMX, PORO, SATNUM.
|
||||
std::ofstream out(filename.c_str());
|
||||
if (!out) {
|
||||
std::cerr << "Could not open file " << filename << "\n";
|
||||
throw std::runtime_error("Could not open output file.");
|
||||
}
|
||||
out << "SPECGRID\n" << new_dims_[0] << ' ' << new_dims_[1] << ' ' << new_dims_[2]
|
||||
<< " 1 F\n/\n\n";
|
||||
|
||||
out.precision(15);
|
||||
out.setf(std::ios::scientific);
|
||||
|
||||
outputField(out, new_COORD_, "COORD", /* nl = */ 3);
|
||||
outputField(out, new_ZCORN_, "ZCORN", /* nl = */ 4);
|
||||
outputField(out, new_ACTNUM_, "ACTNUM");
|
||||
outputField(out, new_PORO_, "PORO", 4);
|
||||
if (hasNTG()) {outputField(out, new_NTG_, "NTG", 4);}
|
||||
if (hasSWCR()) {outputField(out, new_SWCR_, "SWCR", 4);}
|
||||
if (hasSOWCR()) {outputField(out, new_SOWCR_, "SOWCR", 4);}
|
||||
outputField(out, new_PERMX_, "PERMX", 4);
|
||||
outputField(out, new_PERMY_, "PERMY", 4);
|
||||
outputField(out, new_PERMZ_, "PERMZ", 4);
|
||||
outputField(out, new_SATNUM_, "SATNUM");
|
||||
}
|
||||
bool hasNTG() const {return !new_NTG_.empty(); }
|
||||
bool hasSWCR() const {return !new_SWCR_.empty(); }
|
||||
bool hasSOWCR() const {return !new_SOWCR_.empty(); }
|
||||
|
||||
private:
|
||||
Opm::DeckConstPtr deck_;
|
||||
std::shared_ptr<Opm::UnitSystem> metricUnits_;
|
||||
|
||||
double botmax_;
|
||||
double topmin_;
|
||||
double abszmin_;
|
||||
double abszmax_;
|
||||
std::vector<double> new_COORD_;
|
||||
std::vector<double> new_ZCORN_;
|
||||
std::vector<int> new_ACTNUM_;
|
||||
std::vector<double> new_PORO_;
|
||||
std::vector<double> new_NTG_;
|
||||
std::vector<double> new_SWCR_;
|
||||
std::vector<double> new_SOWCR_;
|
||||
std::vector<double> new_PERMX_;
|
||||
std::vector<double> new_PERMY_;
|
||||
std::vector<double> new_PERMZ_;
|
||||
std::vector<int> new_SATNUM_;
|
||||
int dims_[3];
|
||||
int new_dims_[3];
|
||||
std::vector<int> new_to_old_cell_;
|
||||
|
||||
void addDoubleKeyword_(Opm::DeckPtr subDeck,
|
||||
const std::string& keywordName,
|
||||
const std::string& dimensionString,
|
||||
const std::vector<double>& data)
|
||||
{
|
||||
if (data.empty())
|
||||
return;
|
||||
|
||||
Opm::DeckKeyword dataKw(keywordName);
|
||||
Opm::DeckRecord dataRecord;
|
||||
auto dataItem = Opm::DeckItem::make< double >("DATA");
|
||||
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
dataItem.push_back(data[i]);
|
||||
}
|
||||
|
||||
std::shared_ptr<const Dimension> dimension = metricUnits_->parse(dimensionString);
|
||||
dataItem.push_backDimension(/*active=*/dimension, /*default=*/dimension);
|
||||
|
||||
dataRecord.addItem(std::move(dataItem));
|
||||
dataKw.addRecord(std::move(dataRecord));
|
||||
subDeck->addKeyword(std::move(dataKw));
|
||||
}
|
||||
|
||||
void addIntKeyword_(Opm::DeckPtr subDeck,
|
||||
const std::string& keywordName,
|
||||
const std::vector<int>& data)
|
||||
{
|
||||
if (data.empty())
|
||||
return;
|
||||
|
||||
Opm::DeckKeyword dataKw(keywordName);
|
||||
Opm::DeckRecord dataRecord;
|
||||
auto dataItem = Opm::DeckItem::make< int >("DATA");
|
||||
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
dataItem.push_back(data[i]);
|
||||
}
|
||||
|
||||
dataRecord.addItem(std::move(dataItem));
|
||||
dataKw.addRecord(std::move(dataRecord));
|
||||
subDeck->addKeyword(std::move(dataKw));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void outputField(std::ostream& os,
|
||||
const std::vector<T>& field,
|
||||
const std::string& keyword,
|
||||
const typename std::vector<T>::size_type nl = 20)
|
||||
{
|
||||
if (field.empty()) return;
|
||||
|
||||
os << keyword << '\n';
|
||||
|
||||
typedef typename std::vector<T>::size_type sz_t;
|
||||
|
||||
const sz_t n = field.size();
|
||||
for (sz_t i = 0; i < n; ++i) {
|
||||
os << field[i]
|
||||
<< (((i + 1) % nl == 0) ? '\n' : ' ');
|
||||
}
|
||||
if (n % nl != 0) {
|
||||
os << '\n';
|
||||
}
|
||||
os << "/\n\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void filterField(const std::vector<T>& field,
|
||||
std::vector<T>& output_field)
|
||||
{
|
||||
int sz = new_to_old_cell_.size();
|
||||
output_field.resize(sz);
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
output_field[i] = field[new_to_old_cell_[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void filterDoubleField(const std::string& keyword, std::vector<double>& output_field)
|
||||
{
|
||||
if (deck_->hasKeyword(keyword)) {
|
||||
const std::vector<double>& field = deck_->getKeyword(keyword).getRawDoubleData();
|
||||
filterField(field, output_field);
|
||||
}
|
||||
}
|
||||
|
||||
void filterIntegerField(const std::string& keyword, std::vector<int>& output_field)
|
||||
{
|
||||
if (deck_->hasKeyword(keyword)) {
|
||||
const std::vector<int>& field = deck_->getKeyword(keyword).getIntData();
|
||||
filterField(field, output_field);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // OPM_CORNERPOINTCHOPPER_HEADER_INCLUDED
|
@ -1,350 +0,0 @@
|
||||
//===========================================================================
|
||||
//
|
||||
// File: EclipseGridInspector.C
|
||||
//
|
||||
// Created: Mon Jun 2 12:17:51 2008
|
||||
//
|
||||
// Author: Atgeirr F Rasmussen <atgeirr@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
// Revision: $Id: EclipseGridInspector.C,v 1.2 2008/08/18 14:16:13 atgeirr Exp $
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <opm/core/io/eclipse/EclipseGridInspector.hpp>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
#include <stdexcept>
|
||||
#include <numeric>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
EclipseGridInspector::EclipseGridInspector(Opm::DeckConstPtr deck)
|
||||
: deck_(deck)
|
||||
{
|
||||
init_();
|
||||
}
|
||||
|
||||
void EclipseGridInspector::init_()
|
||||
{
|
||||
if (!deck_->hasKeyword("COORD")) {
|
||||
OPM_THROW(std::runtime_error, "Needed field \"COORD\" is missing in file");
|
||||
}
|
||||
if (!deck_->hasKeyword("ZCORN")) {
|
||||
OPM_THROW(std::runtime_error, "Needed field \"ZCORN\" is missing in file");
|
||||
}
|
||||
|
||||
if (deck_->hasKeyword("SPECGRID")) {
|
||||
const auto& specgridRecord =
|
||||
deck_->getKeyword("SPECGRID").getRecord(0);
|
||||
logical_gridsize_[0] = specgridRecord.getItem("NX").get< int >(0);
|
||||
logical_gridsize_[1] = specgridRecord.getItem("NY").get< int >(0);
|
||||
logical_gridsize_[2] = specgridRecord.getItem("NZ").get< int >(0);
|
||||
} else if (deck_->hasKeyword("DIMENS")) {
|
||||
const auto& dimensRecord =
|
||||
deck_->getKeyword("DIMENS").getRecord(0);
|
||||
logical_gridsize_[0] = dimensRecord.getItem("NX").get< int >(0);
|
||||
logical_gridsize_[1] = dimensRecord.getItem("NY").get< int >(0);
|
||||
logical_gridsize_[2] = dimensRecord.getItem("NZ").get< int >(0);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Found neither SPECGRID nor DIMENS in file. At least one is needed.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Return the dip slopes for the cell relative to xy-plane in x- and y- direction.
|
||||
Dip slope is average rise in positive x-direction over cell length in x-direction.
|
||||
Similarly for y.
|
||||
|
||||
Current implementation is for vertical pillars, but is not difficult to fix.
|
||||
|
||||
@returns a std::pair<double,double> with x-dip in first component and y-dip in second.
|
||||
*/
|
||||
std::pair<double,double> EclipseGridInspector::cellDips(int i, int j, int k) const
|
||||
{
|
||||
checkLogicalCoords(i, j, k);
|
||||
const std::vector<double>& pillc =
|
||||
deck_->getKeyword("COORD").getSIDoubleData();
|
||||
int num_pillars = (logical_gridsize_[0] + 1)*(logical_gridsize_[1] + 1);
|
||||
if (6*num_pillars != int(pillc.size())) {
|
||||
throw std::runtime_error("Wrong size of COORD field.");
|
||||
}
|
||||
const std::vector<double>& z =
|
||||
deck_->getKeyword("ZCORN").getSIDoubleData();
|
||||
int num_cells = logical_gridsize_[0]*logical_gridsize_[1]*logical_gridsize_[2];
|
||||
if (8*num_cells != int(z.size())) {
|
||||
throw std::runtime_error("Wrong size of ZCORN field");
|
||||
}
|
||||
|
||||
// Pick ZCORN-value for all 8 corners of the given cell
|
||||
std::array<double, 8> cellz = cellZvals(i, j, k);
|
||||
|
||||
// Compute rise in positive x-direction for all four edges (and then find mean)
|
||||
// Current implementation is for regularly placed and vertical pillars!
|
||||
int numxpill = logical_gridsize_[0] + 1;
|
||||
int pix = i + j*numxpill;
|
||||
double cell_xlength = pillc[6*(pix + 1)] - pillc[6*pix];
|
||||
flush(std::cout);
|
||||
double xrise[4] = { (cellz[1] - cellz[0])/cell_xlength, // LLL -> HLL
|
||||
(cellz[3] - cellz[2])/cell_xlength, // LHL -> HHL
|
||||
(cellz[5] - cellz[4])/cell_xlength, // LLH -> HLH
|
||||
(cellz[7] - cellz[6])/cell_xlength}; // LHH -> HHH
|
||||
|
||||
double cell_ylength = pillc[6*(pix + numxpill) + 1] - pillc[6*pix + 1];
|
||||
double yrise[4] = { (cellz[2] - cellz[0])/cell_ylength, // LLL -> LHL
|
||||
(cellz[3] - cellz[1])/cell_ylength, // HLL -> HHL
|
||||
(cellz[6] - cellz[4])/cell_ylength, // LLH -> LHH
|
||||
(cellz[7] - cellz[5])/cell_ylength}; // HLH -> HHH
|
||||
|
||||
|
||||
// Now ignore those edges that touch the global top or bottom surface
|
||||
// of the entire grdecl model. This is to avoid bias, as these edges probably
|
||||
// don't follow an overall dip for the model if it exists.
|
||||
int x_edges = 4;
|
||||
int y_edges = 4;
|
||||
std::array<double, 6> gridlimits = getGridLimits();
|
||||
double zmin = gridlimits[4];
|
||||
double zmax = gridlimits[5];
|
||||
// LLL -> HLL
|
||||
if ((cellz[1] == zmin) || (cellz[0] == zmin)) {
|
||||
xrise[0] = 0; x_edges--;
|
||||
}
|
||||
// LHL -> HHL
|
||||
if ((cellz[2] == zmin) || (cellz[3] == zmin)) {
|
||||
xrise[1] = 0; x_edges--;
|
||||
}
|
||||
// LLH -> HLH
|
||||
if ((cellz[4] == zmax) || (cellz[5] == zmax)) {
|
||||
xrise[2] = 0; x_edges--;
|
||||
}
|
||||
// LHH -> HHH
|
||||
if ((cellz[6] == zmax) || (cellz[7] == zmax)) {
|
||||
xrise[3] = 0; x_edges--;
|
||||
}
|
||||
// LLL -> LHL
|
||||
if ((cellz[0] == zmin) || (cellz[2] == zmin)) {
|
||||
yrise[0] = 0; y_edges--;
|
||||
}
|
||||
// HLL -> HHL
|
||||
if ((cellz[1] == zmin) || (cellz[3] == zmin)) {
|
||||
yrise[1] = 0; y_edges--;
|
||||
}
|
||||
// LLH -> LHH
|
||||
if ((cellz[6] == zmax) || (cellz[4] == zmax)) {
|
||||
yrise[2] = 0; y_edges--;
|
||||
}
|
||||
// HLH -> HHH
|
||||
if ((cellz[7] == zmax) || (cellz[5] == zmax)) {
|
||||
yrise[3] = 0; y_edges--;
|
||||
}
|
||||
|
||||
return std::make_pair( (xrise[0] + xrise[1] + xrise[2] + xrise[3])/x_edges,
|
||||
(yrise[0] + yrise[1] + yrise[2] + yrise[3])/y_edges);
|
||||
}
|
||||
/**
|
||||
Wrapper for cellDips(i, j, k).
|
||||
*/
|
||||
std::pair<double,double> EclipseGridInspector::cellDips(int cell_idx) const
|
||||
{
|
||||
std::array<int, 3> idxs = cellIdxToLogicalCoords(cell_idx);
|
||||
return cellDips(idxs[0], idxs[1], idxs[2]);
|
||||
}
|
||||
|
||||
std::array<int, 3> EclipseGridInspector::cellIdxToLogicalCoords(int cell_idx) const
|
||||
{
|
||||
|
||||
int i,j,k; // Position of cell in cell hierarchy
|
||||
int horIdx = (cell_idx+1) - int(std::floor(((double)(cell_idx+1))/((double)(logical_gridsize_[0]*logical_gridsize_[1]))))*logical_gridsize_[0]*logical_gridsize_[1]; // index in the corresponding horizon
|
||||
if (horIdx == 0) {
|
||||
horIdx = logical_gridsize_[0]*logical_gridsize_[1];
|
||||
}
|
||||
i = horIdx - int(std::floor(((double)horIdx)/((double)logical_gridsize_[0])))*logical_gridsize_[0];
|
||||
if (i == 0) {
|
||||
i = logical_gridsize_[0];
|
||||
}
|
||||
j = (horIdx-i)/logical_gridsize_[0]+1;
|
||||
k = ((cell_idx+1)-logical_gridsize_[0]*(j-1)-1)/(logical_gridsize_[0]*logical_gridsize_[1])+1;
|
||||
|
||||
std::array<int, 3> a = {{i-1, j-1, k-1}};
|
||||
return a; //std::array<int, 3> {{i-1, j-1, k-1}};
|
||||
}
|
||||
|
||||
double EclipseGridInspector::cellVolumeVerticalPillars(int i, int j, int k) const
|
||||
{
|
||||
// Checking parameters and obtaining values from parser.
|
||||
checkLogicalCoords(i, j, k);
|
||||
const std::vector<double>& pillc =
|
||||
deck_->getKeyword("COORD").getSIDoubleData();
|
||||
int num_pillars = (logical_gridsize_[0] + 1)*(logical_gridsize_[1] + 1);
|
||||
if (6*num_pillars != int(pillc.size())) {
|
||||
throw std::runtime_error("Wrong size of COORD field.");
|
||||
}
|
||||
const std::vector<double>& z =
|
||||
deck_->getKeyword("ZCORN").getSIDoubleData();
|
||||
int num_cells = logical_gridsize_[0]*logical_gridsize_[1]*logical_gridsize_[2];
|
||||
if (8*num_cells != int(z.size())) {
|
||||
throw std::runtime_error("Wrong size of ZCORN field");
|
||||
}
|
||||
|
||||
// Computing the base area as half the 2d cross product of the diagonals.
|
||||
int numxpill = logical_gridsize_[0] + 1;
|
||||
int pix = i + j*numxpill;
|
||||
double px[4] = { pillc[6*pix],
|
||||
pillc[6*(pix + 1)],
|
||||
pillc[6*(pix + numxpill)],
|
||||
pillc[6*(pix + numxpill + 1)] };
|
||||
double py[4] = { pillc[6*pix + 1],
|
||||
pillc[6*(pix + 1) + 1],
|
||||
pillc[6*(pix + numxpill) + 1],
|
||||
pillc[6*(pix + numxpill + 1) + 1] };
|
||||
double diag1[2] = { px[3] - px[0], py[3] - py[0] };
|
||||
double diag2[2] = { px[2] - px[1], py[2] - py[1] };
|
||||
double area = 0.5*(diag1[0]*diag2[1] - diag1[1]*diag2[0]);
|
||||
|
||||
// Computing the average of the z-differences along each pillar.
|
||||
int delta[3] = { 1,
|
||||
2*logical_gridsize_[0],
|
||||
4*logical_gridsize_[0]*logical_gridsize_[1] };
|
||||
int ix = 2*(i*delta[0] + j*delta[1] + k*delta[2]);
|
||||
double cellz[8] = { z[ix], z[ix + delta[0]],
|
||||
z[ix + delta[1]], z[ix + delta[1] + delta[0]],
|
||||
z[ix + delta[2]], z[ix + delta[2] + delta[0]],
|
||||
z[ix + delta[2] + delta[1]], z[ix + delta[2] + delta[1] + delta[0]] };
|
||||
double diffz[4] = { cellz[4] - cellz[0],
|
||||
cellz[5] - cellz[1],
|
||||
cellz[6] - cellz[2],
|
||||
cellz[7] - cellz[3] };
|
||||
double averzdiff = 0.25*std::accumulate(diffz, diffz + 4, 0.0);
|
||||
return averzdiff*area;
|
||||
}
|
||||
|
||||
|
||||
double EclipseGridInspector::cellVolumeVerticalPillars(int cell_idx) const
|
||||
{
|
||||
std::array<int, 3> idxs = cellIdxToLogicalCoords(cell_idx);
|
||||
return cellVolumeVerticalPillars(idxs[0], idxs[1], idxs[2]);
|
||||
}
|
||||
|
||||
void EclipseGridInspector::checkLogicalCoords(int i, int j, int k) const
|
||||
{
|
||||
if (i < 0 || i >= logical_gridsize_[0])
|
||||
throw std::runtime_error("First coordinate out of bounds");
|
||||
if (j < 0 || j >= logical_gridsize_[1])
|
||||
throw std::runtime_error("Second coordinate out of bounds");
|
||||
if (k < 0 || k >= logical_gridsize_[2])
|
||||
throw std::runtime_error("Third coordinate out of bounds");
|
||||
}
|
||||
|
||||
|
||||
std::array<double, 6> EclipseGridInspector::getGridLimits() const
|
||||
{
|
||||
if (! (deck_->hasKeyword("COORD") && deck_->hasKeyword("ZCORN") && deck_->hasKeyword("SPECGRID")) ) {
|
||||
throw std::runtime_error("EclipseGridInspector: Grid does not have SPECGRID, COORD, and ZCORN, can't find dimensions.");
|
||||
}
|
||||
|
||||
std::vector<double> coord = deck_->getKeyword("COORD").getSIDoubleData();
|
||||
std::vector<double> zcorn = deck_->getKeyword("ZCORN").getSIDoubleData();
|
||||
|
||||
double xmin = +DBL_MAX;
|
||||
double xmax = -DBL_MAX;
|
||||
double ymin = +DBL_MAX;
|
||||
double ymax = -DBL_MAX;
|
||||
|
||||
|
||||
int pillars = (logical_gridsize_[0]+1) * (logical_gridsize_[1]+1);
|
||||
|
||||
for (int pillarindex = 0; pillarindex < pillars; ++pillarindex) {
|
||||
if (coord[pillarindex * 6 + 0] > xmax)
|
||||
xmax = coord[pillarindex * 6 + 0];
|
||||
if (coord[pillarindex * 6 + 0] < xmin)
|
||||
xmin = coord[pillarindex * 6 + 0];
|
||||
if (coord[pillarindex * 6 + 1] > ymax)
|
||||
ymax = coord[pillarindex * 6 + 1];
|
||||
if (coord[pillarindex * 6 + 1] < ymin)
|
||||
ymin = coord[pillarindex * 6 + 1];
|
||||
if (coord[pillarindex * 6 + 3] > xmax)
|
||||
xmax = coord[pillarindex * 6 + 3];
|
||||
if (coord[pillarindex * 6 + 3] < xmin)
|
||||
xmin = coord[pillarindex * 6 + 3];
|
||||
if (coord[pillarindex * 6 + 4] > ymax)
|
||||
ymax = coord[pillarindex * 6 + 4];
|
||||
if (coord[pillarindex * 6 + 4] < ymin)
|
||||
ymin = coord[pillarindex * 6 + 4];
|
||||
}
|
||||
|
||||
std::array<double, 6> gridlimits = {{ xmin, xmax, ymin, ymax,
|
||||
*min_element(zcorn.begin(), zcorn.end()),
|
||||
*max_element(zcorn.begin(), zcorn.end()) }};
|
||||
return gridlimits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::array<int, 3> EclipseGridInspector::gridSize() const
|
||||
{
|
||||
std::array<int, 3> retval = {{ logical_gridsize_[0],
|
||||
logical_gridsize_[1],
|
||||
logical_gridsize_[2] }};
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
std::array<double, 8> EclipseGridInspector::cellZvals(int i, int j, int k) const
|
||||
{
|
||||
// Get the zcorn field.
|
||||
const std::vector<double>& z = deck_->getKeyword("ZCORN").getSIDoubleData();
|
||||
int num_cells = logical_gridsize_[0]*logical_gridsize_[1]*logical_gridsize_[2];
|
||||
if (8*num_cells != int(z.size())) {
|
||||
throw std::runtime_error("Wrong size of ZCORN field");
|
||||
}
|
||||
|
||||
// Make the coordinate array.
|
||||
int delta[3] = { 1,
|
||||
2*logical_gridsize_[0],
|
||||
4*logical_gridsize_[0]*logical_gridsize_[1] };
|
||||
int ix = 2*(i*delta[0] + j*delta[1] + k*delta[2]);
|
||||
std::array<double, 8> cellz = {{ z[ix], z[ix + delta[0]],
|
||||
z[ix + delta[1]], z[ix + delta[1] + delta[0]],
|
||||
z[ix + delta[2]], z[ix + delta[2] + delta[0]],
|
||||
z[ix + delta[2] + delta[1]], z[ix + delta[2] + delta[1] + delta[0]] }};
|
||||
return cellz;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Opm
|
@ -1,103 +0,0 @@
|
||||
//===========================================================================
|
||||
//
|
||||
// File: EclipseGridInspector.h
|
||||
//
|
||||
// Created: Mon Jun 2 09:46:08 2008
|
||||
//
|
||||
// Author: Atgeirr F Rasmussen <atgeirr@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// Revision: $Id: EclipseGridInspector.h,v 1.2 2008/08/18 14:16:12 atgeirr Exp $
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
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_ECLIPSEGRIDINSPECTOR_HEADER
|
||||
#define OPM_ECLIPSEGRIDINSPECTOR_HEADER
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/**
|
||||
@brief A class for inspecting the contents of an eclipse file.
|
||||
|
||||
Given an Eclipse deck, this class may be used to answer certain
|
||||
queries about its contents.
|
||||
|
||||
@author Atgeirr F. Rasmussen <atgeirr@sintef.no>
|
||||
@date 2008/06/02 09:46:08
|
||||
*/
|
||||
class EclipseGridInspector
|
||||
{
|
||||
public:
|
||||
/// Constructor taking a parser as argument.
|
||||
/// The parser must already have read an Eclipse file.
|
||||
EclipseGridInspector(Opm::DeckConstPtr deck);
|
||||
|
||||
/// Assuming that the pillars are vertical, compute the
|
||||
/// volume of the cell given by logical coordinates (i, j, k).
|
||||
double cellVolumeVerticalPillars(int i, int j, int k) const;
|
||||
|
||||
/// Assuming that the pillars are vertical, compute the
|
||||
/// volume of the cell given by the cell index
|
||||
double cellVolumeVerticalPillars(int cell_idx) const;
|
||||
|
||||
/// Compute the average dip in x- and y-direction of the
|
||||
/// cell tops and bottoms relative to the xy-plane
|
||||
std::pair<double,double> cellDips(int i, int j, int k) const;
|
||||
std::pair<double,double> cellDips(int cell_idx) const;
|
||||
|
||||
// Convert global cell index to logical ijk-coordinates
|
||||
std::array<int, 3> cellIdxToLogicalCoords(int cell_idx) const;
|
||||
|
||||
/// Returns a vector with the outer limits of grid (in the grid's unit).
|
||||
/// The vector contains [xmin, xmax, ymin, ymax, zmin, zmax], as
|
||||
/// read from COORDS and ZCORN
|
||||
std::array<double, 6> getGridLimits() const;
|
||||
|
||||
/// Returns the extent of the logical cartesian grid
|
||||
/// as number of cells in the (i, j, k) directions.
|
||||
std::array<int, 3> gridSize() const;
|
||||
|
||||
/// Returns the eight z-values associated with a given cell.
|
||||
/// The ordering is such that i runs fastest. That is, with
|
||||
/// L = low and H = high:
|
||||
/// {LLL, HLL, LHL, HHL, LLH, HLH, LHH, HHH }.
|
||||
std::array<double, 8> cellZvals(int i, int j, int k) const;
|
||||
|
||||
private:
|
||||
Opm::DeckConstPtr deck_;
|
||||
int logical_gridsize_[3];
|
||||
void init_();
|
||||
void checkLogicalCoords(int i, int j, int k) const;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_ECLIPSEGRIDINSPECTOR_HEADER
|
||||
|
@ -1,34 +0,0 @@
|
||||
#ifndef ECLIPSE_IO_UTIL_HPP
|
||||
#define ECLIPSE_IO_UTIL_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
namespace EclipseIOUtil
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
void addToStripedData(const std::vector<T>& data, std::vector<T>& result, size_t offset, size_t stride) {
|
||||
int dataindex = 0;
|
||||
for (size_t index = offset; index < result.size(); index += stride) {
|
||||
result[index] = data[dataindex];
|
||||
++dataindex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void extractFromStripedData(const std::vector<T>& data, std::vector<T>& result, size_t offset, size_t stride) {
|
||||
for (size_t index = offset; index < data.size(); index += stride) {
|
||||
result.push_back(data[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} //namespace EclipseIOUtil
|
||||
} //namespace Opm
|
||||
|
||||
#endif //ECLIPSE_IO_UTIL_HPP
|
@ -1,247 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 Statoil ASA.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include "EclipseReader.hpp"
|
||||
#include <opm/core/simulator/WellState.hpp>
|
||||
#include <opm/core/simulator/BlackoilState.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
#include <opm/core/io/eclipse/EclipseIOUtil.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/InitConfig/InitConfig.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/SimulationConfig/SimulationConfig.hpp>
|
||||
#include <opm/parser/eclipse/Units/Dimension.hpp>
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <ert/ecl/ecl_file.h>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
static void restoreTemperatureData(const ecl_file_type* file,
|
||||
EclipseStateConstPtr eclipse_state,
|
||||
int numcells,
|
||||
SimulationDataContainer& simulator_state) {
|
||||
const char* temperature = "TEMP";
|
||||
|
||||
if (ecl_file_has_kw(file , temperature)) {
|
||||
ecl_kw_type* temperature_kw = ecl_file_iget_named_kw(file, temperature, 0);
|
||||
|
||||
if (ecl_kw_get_size(temperature_kw) != numcells) {
|
||||
throw std::runtime_error("Read of restart file: Could not restore temperature data, length of data from file not equal number of cells");
|
||||
}
|
||||
|
||||
float* temperature_data = ecl_kw_get_float_ptr(temperature_kw);
|
||||
|
||||
// factor and offset from the temperature values given in the deck to Kelvin
|
||||
double scaling = eclipse_state->getDeckUnitSystem().parse("Temperature")->getSIScaling();
|
||||
double offset = eclipse_state->getDeckUnitSystem().parse("Temperature")->getSIOffset();
|
||||
|
||||
for (size_t index = 0; index < simulator_state.temperature().size(); ++index) {
|
||||
simulator_state.temperature()[index] = unit::convert::from((double)temperature_data[index] - offset, scaling);
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Read of restart file: File does not contain TEMP data\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void restorePressureData(const ecl_file_type* file,
|
||||
EclipseStateConstPtr eclipse_state,
|
||||
int numcells,
|
||||
SimulationDataContainer& simulator_state) {
|
||||
const char* pressure = "PRESSURE";
|
||||
|
||||
if (ecl_file_has_kw(file , pressure)) {
|
||||
|
||||
ecl_kw_type* pressure_kw = ecl_file_iget_named_kw(file, pressure, 0);
|
||||
|
||||
if (ecl_kw_get_size(pressure_kw) != numcells) {
|
||||
throw std::runtime_error("Read of restart file: Could not restore pressure data, length of data from file not equal number of cells");
|
||||
}
|
||||
|
||||
float* pressure_data = ecl_kw_get_float_ptr(pressure_kw);
|
||||
const double deck_pressure_unit = (eclipse_state->getDeckUnitSystem().getType() == UnitSystem::UNIT_TYPE_METRIC) ? Opm::unit::barsa : Opm::unit::psia;
|
||||
for (size_t index = 0; index < simulator_state.pressure().size(); ++index) {
|
||||
simulator_state.pressure()[index] = unit::convert::from((double)pressure_data[index], deck_pressure_unit);
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Read of restart file: File does not contain PRESSURE data\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void restoreSaturation(const ecl_file_type* file_type,
|
||||
const PhaseUsage& phaseUsage,
|
||||
int numcells,
|
||||
SimulationDataContainer& simulator_state) {
|
||||
|
||||
float* sgas_data = NULL;
|
||||
float* swat_data = NULL;
|
||||
|
||||
if (phaseUsage.phase_used[BlackoilPhases::Aqua]) {
|
||||
const char* swat = "SWAT";
|
||||
if (ecl_file_has_kw(file_type, swat)) {
|
||||
ecl_kw_type* swat_kw = ecl_file_iget_named_kw(file_type , swat, 0);
|
||||
swat_data = ecl_kw_get_float_ptr(swat_kw);
|
||||
std::vector<double> swat_datavec(&swat_data[0], &swat_data[numcells]);
|
||||
EclipseIOUtil::addToStripedData(swat_datavec, simulator_state.saturation(), phaseUsage.phase_pos[BlackoilPhases::Aqua], phaseUsage.num_phases);
|
||||
} else {
|
||||
std::string error_str = "Restart file is missing SWAT data!\n";
|
||||
throw std::runtime_error(error_str);
|
||||
}
|
||||
}
|
||||
|
||||
if (phaseUsage.phase_used[BlackoilPhases::Vapour]) {
|
||||
const char* sgas = "SGAS";
|
||||
if (ecl_file_has_kw(file_type, sgas)) {
|
||||
ecl_kw_type* sgas_kw = ecl_file_iget_named_kw(file_type , sgas, 0);
|
||||
sgas_data = ecl_kw_get_float_ptr(sgas_kw);
|
||||
std::vector<double> sgas_datavec(&sgas_data[0], &sgas_data[numcells]);
|
||||
EclipseIOUtil::addToStripedData(sgas_datavec, simulator_state.saturation(), phaseUsage.phase_pos[BlackoilPhases::Vapour], phaseUsage.num_phases);
|
||||
} else {
|
||||
std::string error_str = "Restart file is missing SGAS data!\n";
|
||||
throw std::runtime_error(error_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void restoreRSandRV(const ecl_file_type* file_type,
|
||||
SimulationConfigConstPtr sim_config,
|
||||
int numcells,
|
||||
SimulationDataContainer& simulator_state) {
|
||||
|
||||
if (sim_config->hasDISGAS()) {
|
||||
const char* RS = "RS";
|
||||
if (ecl_file_has_kw(file_type, RS)) {
|
||||
ecl_kw_type* rs_kw = ecl_file_iget_named_kw(file_type, RS, 0);
|
||||
float* rs_data = ecl_kw_get_float_ptr(rs_kw);
|
||||
auto& rs = simulator_state.getCellData( BlackoilState::GASOILRATIO );
|
||||
for (int i = 0; i < ecl_kw_get_size( rs_kw ); i++) {
|
||||
rs[i] = rs_data[i];
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Restart file is missing RS data!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (sim_config->hasVAPOIL()) {
|
||||
const char* RV = "RV";
|
||||
if (ecl_file_has_kw(file_type, RV)) {
|
||||
ecl_kw_type* rv_kw = ecl_file_iget_named_kw(file_type, RV, 0);
|
||||
float* rv_data = ecl_kw_get_float_ptr(rv_kw);
|
||||
auto& rv = simulator_state.getCellData( BlackoilState::RV );
|
||||
for (int i = 0; i < ecl_kw_get_size( rv_kw ); i++) {
|
||||
rv[i] = rv_data[i];
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Restart file is missing RV data!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void restoreSOLUTION(const std::string& restart_filename,
|
||||
int reportstep,
|
||||
bool unified,
|
||||
EclipseStateConstPtr eclipseState,
|
||||
int numcells,
|
||||
const PhaseUsage& phaseUsage,
|
||||
SimulationDataContainer& simulator_state)
|
||||
{
|
||||
const char* filename = restart_filename.c_str();
|
||||
ecl_file_type* file_type = ecl_file_open(filename, 0);
|
||||
|
||||
if (file_type) {
|
||||
bool block_selected = unified ? ecl_file_select_rstblock_report_step(file_type , reportstep) : true;
|
||||
|
||||
if (block_selected) {
|
||||
restorePressureData(file_type, eclipseState, numcells, simulator_state);
|
||||
restoreTemperatureData(file_type, eclipseState, numcells, simulator_state);
|
||||
restoreSaturation(file_type, phaseUsage, numcells, simulator_state);
|
||||
if (simulator_state.hasCellData( BlackoilState::RV )) {
|
||||
SimulationConfigConstPtr sim_config = eclipseState->getSimulationConfig();
|
||||
restoreRSandRV(file_type, sim_config, numcells, simulator_state );
|
||||
}
|
||||
} else {
|
||||
std::string error_str = "Restart file " + restart_filename + " does not contain data for report step " + std::to_string(reportstep) + "!\n";
|
||||
throw std::runtime_error(error_str);
|
||||
}
|
||||
ecl_file_close(file_type);
|
||||
} else {
|
||||
std::string error_str = "Restart file " + restart_filename + " not found!\n";
|
||||
throw std::runtime_error(error_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void restoreOPM_XWELKeyword(const std::string& restart_filename, int reportstep, bool unified, WellState& wellstate)
|
||||
{
|
||||
const char * keyword = "OPM_XWEL";
|
||||
const char* filename = restart_filename.c_str();
|
||||
ecl_file_type* file_type = ecl_file_open(filename, 0);
|
||||
|
||||
if (file_type != NULL) {
|
||||
|
||||
bool block_selected = unified ? ecl_file_select_rstblock_report_step(file_type , reportstep) : true;
|
||||
|
||||
if (block_selected) {
|
||||
ecl_kw_type* xwel = ecl_file_iget_named_kw(file_type , keyword, 0);
|
||||
const double* xwel_data = ecl_kw_get_double_ptr(xwel);
|
||||
std::copy_n(xwel_data + wellstate.getRestartTemperatureOffset(), wellstate.temperature().size(), wellstate.temperature().begin());
|
||||
std::copy_n(xwel_data + wellstate.getRestartBhpOffset(), wellstate.bhp().size(), wellstate.bhp().begin());
|
||||
std::copy_n(xwel_data + wellstate.getRestartPerfPressOffset(), wellstate.perfPress().size(), wellstate.perfPress().begin());
|
||||
std::copy_n(xwel_data + wellstate.getRestartPerfRatesOffset(), wellstate.perfRates().size(), wellstate.perfRates().begin());
|
||||
std::copy_n(xwel_data + wellstate.getRestartWellRatesOffset(), wellstate.wellRates().size(), wellstate.wellRates().begin());
|
||||
} else {
|
||||
std::string error_str = "Restart file " + restart_filename + " does not contain data for report step " + std::to_string(reportstep) + "!\n";
|
||||
throw std::runtime_error(error_str);
|
||||
}
|
||||
ecl_file_close(file_type);
|
||||
} else {
|
||||
std::string error_str = "Restart file " + restart_filename + " not found!\n";
|
||||
throw std::runtime_error(error_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void init_from_restart_file(EclipseStateConstPtr eclipse_state,
|
||||
int numcells,
|
||||
const PhaseUsage& phase_usage,
|
||||
SimulationDataContainer& simulator_state,
|
||||
WellState& wellstate) {
|
||||
|
||||
InitConfigConstPtr initConfig = eclipse_state->getInitConfig();
|
||||
IOConfigConstPtr ioConfig = eclipse_state->getIOConfig();
|
||||
int restart_step = initConfig->getRestartStep();
|
||||
const std::string& restart_file_root = initConfig->getRestartRootName();
|
||||
bool output = false;
|
||||
const std::string& restart_file_name = ioConfig->getRestartFileName(restart_file_root, restart_step, output);
|
||||
|
||||
Opm::restoreSOLUTION(restart_file_name, restart_step, ioConfig->getUNIFIN(), eclipse_state, numcells, phase_usage, simulator_state);
|
||||
Opm::restoreOPM_XWELKeyword(restart_file_name, restart_step, ioConfig->getUNIFIN(), wellstate);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Opm
|
@ -1,39 +0,0 @@
|
||||
#ifndef ECLIPSEREADER_HPP
|
||||
#define ECLIPSEREADER_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <opm/core/simulator/WellState.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
///
|
||||
/// \brief init_from_restart_file
|
||||
/// Reading from the restart file, information stored under the OPM_XWEL keyword and SOLUTION data is in this method filled into
|
||||
/// an instance of a wellstate object and a SimulatorState object.
|
||||
/// \param grid
|
||||
/// UnstructuredGrid reference
|
||||
/// \param pu
|
||||
/// PhaseUsage reference
|
||||
/// \param simulator_state
|
||||
/// An instance of a SimulatorState object
|
||||
/// \param wellstate
|
||||
/// An instance of a WellState object, with correct size for each of the 5 contained std::vector<double> objects
|
||||
///
|
||||
|
||||
class SimulationDataContainer;
|
||||
|
||||
void init_from_restart_file(EclipseStateConstPtr eclipse_state,
|
||||
int numcells,
|
||||
const PhaseUsage& pu,
|
||||
SimulationDataContainer& simulator_state,
|
||||
WellState& wellstate);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // ECLIPSEREADER_HPP
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
Copyright 2010 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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_ECLIPSEUNITS_HEADER_INCLUDED
|
||||
#define OPM_ECLIPSEUNITS_HEADER_INCLUDED
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
struct EclipseUnits
|
||||
{
|
||||
double length;
|
||||
double time;
|
||||
double density;
|
||||
double polymer_density;
|
||||
double pressure;
|
||||
double compressibility;
|
||||
double viscosity;
|
||||
double permeability;
|
||||
double liqvol_s;
|
||||
double liqvol_r;
|
||||
double gasvol_s;
|
||||
double gasvol_r;
|
||||
double transmissibility;
|
||||
|
||||
void setToOne()
|
||||
{
|
||||
length = 1.0;
|
||||
time = 1.0;
|
||||
density = 1.0;
|
||||
polymer_density = 1.0;
|
||||
pressure = 1.0;
|
||||
compressibility = 1.0;
|
||||
viscosity = 1.0;
|
||||
permeability = 1.0;
|
||||
liqvol_s = 1.0;
|
||||
liqvol_r = 1.0;
|
||||
gasvol_s = 1.0;
|
||||
gasvol_r = 1.0;
|
||||
transmissibility = 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#endif // OPM_ECLIPSEUNITS_HEADER_INCLUDED
|
@ -1,144 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 Statoil ASA.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <opm/core/io/eclipse/EclipseWriteRFTHandler.hpp>
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/core/utility/miscUtilities.hpp>
|
||||
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/WellSet.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
|
||||
|
||||
#include <ert/ecl/ecl_rft_node.h>
|
||||
#include <ert/ecl/ecl_rft_file.h>
|
||||
|
||||
|
||||
|
||||
namespace Opm {
|
||||
namespace EclipseWriterDetails {
|
||||
|
||||
EclipseWriteRFTHandler::EclipseWriteRFTHandler(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize) {
|
||||
initGlobalToActiveIndex(compressedToCartesianCellIdx, numCells, cartesianSize);
|
||||
}
|
||||
|
||||
void EclipseWriteRFTHandler::writeTimeStep(const std::string& filename,
|
||||
const ert_ecl_unit_enum ecl_unit,
|
||||
const SimulatorTimerInterface& simulatorTimer,
|
||||
std::vector<WellConstPtr>& wells,
|
||||
EclipseGridConstPtr eclipseGrid,
|
||||
std::vector<double>& pressure,
|
||||
std::vector<double>& swat,
|
||||
std::vector<double>& sgas) {
|
||||
|
||||
|
||||
|
||||
std::vector<ecl_rft_node_type *> rft_nodes;
|
||||
for (std::vector<WellConstPtr>::const_iterator ci = wells.begin(); ci != wells.end(); ++ci) {
|
||||
WellConstPtr well = *ci;
|
||||
if ((well->getRFTActive(simulatorTimer.reportStepNum())) || (well->getPLTActive(simulatorTimer.reportStepNum()))) {
|
||||
ecl_rft_node_type * ecl_node = createEclRFTNode(well,
|
||||
simulatorTimer,
|
||||
eclipseGrid,
|
||||
pressure,
|
||||
swat,
|
||||
sgas);
|
||||
|
||||
// TODO: replace this silenced warning with an appropriate
|
||||
// use of the OpmLog facilities.
|
||||
// if (well->getPLTActive(simulatorTimer.reportStepNum())) {
|
||||
// std::cerr << "PLT not supported, writing RFT data" << std::endl;
|
||||
// }
|
||||
|
||||
rft_nodes.push_back(ecl_node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rft_nodes.size() > 0) {
|
||||
ecl_rft_file_update(filename.c_str(), rft_nodes.data(), rft_nodes.size(), ecl_unit);
|
||||
}
|
||||
|
||||
//Cleanup: The ecl_rft_file_update method takes care of freeing the ecl_rft_nodes that it receives.
|
||||
// Each ecl_rft_node is again responsible for freeing it's cells.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ecl_rft_node_type * EclipseWriteRFTHandler::createEclRFTNode(WellConstPtr well,
|
||||
const SimulatorTimerInterface& simulatorTimer,
|
||||
EclipseGridConstPtr eclipseGrid,
|
||||
const std::vector<double>& pressure,
|
||||
const std::vector<double>& swat,
|
||||
const std::vector<double>& sgas) {
|
||||
|
||||
|
||||
const std::string& well_name = well->name();
|
||||
size_t timestep = (size_t)simulatorTimer.reportStepNum();
|
||||
time_t recording_date = simulatorTimer.currentPosixTime();
|
||||
double days = Opm::unit::convert::to(simulatorTimer.simulationTimeElapsed(), Opm::unit::day);
|
||||
|
||||
std::string type = "RFT";
|
||||
ecl_rft_node_type * ecl_rft_node = ecl_rft_node_alloc_new(well_name.c_str(), type.c_str(), recording_date, days);
|
||||
|
||||
CompletionSetConstPtr completionsSet = well->getCompletions(timestep);
|
||||
for (size_t index = 0; index < completionsSet->size(); ++index) {
|
||||
CompletionConstPtr completion = completionsSet->get(index);
|
||||
size_t i = (size_t)completion->getI();
|
||||
size_t j = (size_t)completion->getJ();
|
||||
size_t k = (size_t)completion->getK();
|
||||
|
||||
size_t global_index = eclipseGrid->getGlobalIndex(i,j,k);
|
||||
int active_index = globalToActiveIndex_[global_index];
|
||||
|
||||
if (active_index > -1) {
|
||||
double depth = eclipseGrid->getCellDepth(i,j,k);
|
||||
double completion_pressure = pressure.size() > 0 ? pressure[active_index] : 0.0;
|
||||
double saturation_water = swat.size() > 0 ? swat[active_index] : 0.0;
|
||||
double saturation_gas = sgas.size() > 0 ? sgas[active_index] : 0.0;
|
||||
|
||||
ecl_rft_cell_type * ecl_rft_cell = ecl_rft_cell_alloc_RFT( i ,j, k , depth, completion_pressure, saturation_water, saturation_gas);
|
||||
ecl_rft_node_append_cell( ecl_rft_node , ecl_rft_cell);
|
||||
}
|
||||
}
|
||||
|
||||
return ecl_rft_node;
|
||||
}
|
||||
|
||||
|
||||
void EclipseWriteRFTHandler::initGlobalToActiveIndex(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize) {
|
||||
globalToActiveIndex_.resize(cartesianSize, -1);
|
||||
for (size_t active_index = 0; active_index < numCells; ++active_index) {
|
||||
//If compressedToCartesianCellIdx is NULL, assume no compressed to cartesian mapping, set global equal to active index
|
||||
int global_index = (NULL != compressedToCartesianCellIdx) ? compressedToCartesianCellIdx[active_index] : active_index;
|
||||
globalToActiveIndex_[global_index] = active_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}//namespace EclipseWriterDetails
|
||||
}//namespace Opm
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 Statoil ASA.
|
||||
|
||||
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_ECLIPSE_WRITE_RFT_HANDLER_HPP
|
||||
#define OPM_ECLIPSE_WRITE_RFT_HANDLER_HPP
|
||||
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <ert/ecl/ecl_rft_node.h>
|
||||
#include <ert/ecl/ecl_util.h>
|
||||
|
||||
|
||||
namespace Opm {
|
||||
class EclipseGrid;
|
||||
class Well;
|
||||
|
||||
namespace EclipseWriterDetails {
|
||||
|
||||
|
||||
class EclipseWriteRFTHandler {
|
||||
|
||||
public:
|
||||
EclipseWriteRFTHandler(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize);
|
||||
|
||||
|
||||
void writeTimeStep(const std::string& filename,
|
||||
const ert_ecl_unit_enum ecl_unit,
|
||||
const SimulatorTimerInterface& simulatorTimer,
|
||||
std::vector<std::shared_ptr< const Well >>& wells,
|
||||
std::shared_ptr< const EclipseGrid > eclipseGrid,
|
||||
std::vector<double>& pressure,
|
||||
std::vector<double>& swat,
|
||||
std::vector<double>& sgas);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
ecl_rft_node_type * createEclRFTNode(std::shared_ptr< const Well > well,
|
||||
const SimulatorTimerInterface& simulatorTimer,
|
||||
std::shared_ptr< const EclipseGrid > eclipseGrid,
|
||||
const std::vector<double>& pressure,
|
||||
const std::vector<double>& swat,
|
||||
const std::vector<double>& sgas);
|
||||
|
||||
void initGlobalToActiveIndex(const int * compressedToCartesianCellIdx, size_t numCells, size_t cartesianSize);
|
||||
|
||||
std::vector<int> globalToActiveIndex_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}//namespace EclipseWriterDetails
|
||||
}//namespace Opm
|
||||
|
||||
|
||||
#endif //OPM_ECLIPSE_WRITE_RFT_HANDLER_HPP
|
File diff suppressed because it is too large
Load Diff
@ -1,139 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013 Andreas Lauser
|
||||
Copyright (c) 2013 Uni Research AS
|
||||
Copyright (c) 2014 IRIS 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_ECLIPSE_WRITER_HPP
|
||||
#define OPM_ECLIPSE_WRITER_HPP
|
||||
|
||||
#include <opm/core/io/OutputWriter.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
#include <opm/core/wells.h> // WellType
|
||||
#include <opm/core/simulator/SimulatorTimerInterface.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Well.hpp>
|
||||
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
|
||||
|
||||
#include <ert/ecl/ecl_util.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
|
||||
namespace Opm {
|
||||
|
||||
// forward declarations
|
||||
namespace EclipseWriterDetails {
|
||||
class Summary;
|
||||
}
|
||||
|
||||
class SimulationDataContainer;
|
||||
class WellState;
|
||||
|
||||
namespace parameter { class ParameterGroup; }
|
||||
|
||||
/*!
|
||||
* \brief A class to write the reservoir state and the well state of a
|
||||
* blackoil simulation to disk using the Eclipse binary format.
|
||||
*
|
||||
* This class only writes files if the 'write_output' parameter is set
|
||||
* to 1. It needs the ERT libraries to write to disk, so if the
|
||||
* 'write_output' parameter is set but ERT is not available, all
|
||||
* methods throw a std::runtime_error.
|
||||
*/
|
||||
class EclipseWriter : public OutputWriter
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Sets the common attributes required to write eclipse
|
||||
* binary files using ERT.
|
||||
*/
|
||||
EclipseWriter(const parameter::ParameterGroup& params,
|
||||
Opm::EclipseStateConstPtr eclipseState,
|
||||
const Opm::PhaseUsage &phaseUsage,
|
||||
int numCells,
|
||||
const int* compressedToCartesianCellIdx);
|
||||
|
||||
/**
|
||||
* We need a destructor in the compilation unit to avoid the
|
||||
* EclipseSummary being a complete type here.
|
||||
*/
|
||||
virtual ~EclipseWriter ();
|
||||
|
||||
/**
|
||||
* Write the static eclipse data (grid, PVT curves, etc) to disk.
|
||||
*/
|
||||
virtual void writeInit(const SimulatorTimerInterface &timer);
|
||||
|
||||
/*!
|
||||
* \brief Write a reservoir state and summary information to disk.
|
||||
*
|
||||
*
|
||||
* The reservoir state can be inspected with visualization tools like
|
||||
* ResInsight.
|
||||
*
|
||||
* The summary information can then be visualized using tools from
|
||||
* ERT or ECLIPSE. Note that calling this method is only
|
||||
* meaningful after the first time step has been completed.
|
||||
*
|
||||
* \param[in] timer The timer providing time step and time information
|
||||
* \param[in] reservoirState The thermodynamic state of the reservoir
|
||||
* \param[in] wellState The production/injection data for all wells
|
||||
*/
|
||||
virtual void writeTimeStep(const SimulatorTimerInterface& timer,
|
||||
const SimulationDataContainer& reservoirState,
|
||||
const WellState& wellState,
|
||||
bool isSubstep);
|
||||
|
||||
|
||||
static int eclipseWellTypeMask(WellType wellType, WellInjector::TypeEnum injectorType);
|
||||
static int eclipseWellStatusMask(WellCommon::StatusEnum wellStatus);
|
||||
static ert_ecl_unit_enum convertUnitTypeErtEclUnitEnum(UnitSystem::UnitType unit);
|
||||
|
||||
private:
|
||||
Opm::EclipseStateConstPtr eclipseState_;
|
||||
int numCells_;
|
||||
std::array<int, 3> cartesianSize_;
|
||||
const int* compressedToCartesianCellIdx_;
|
||||
std::vector< int > gridToEclipseIdx_;
|
||||
double deckToSiPressure_;
|
||||
double deckToSiTemperatureFactor_;
|
||||
double deckToSiTemperatureOffset_;
|
||||
bool enableOutput_;
|
||||
int writeStepIdx_;
|
||||
int reportStepIdx_;
|
||||
std::string outputDir_;
|
||||
std::string baseName_;
|
||||
PhaseUsage phaseUsage_; // active phases in the input deck
|
||||
std::shared_ptr<EclipseWriterDetails::Summary> summary_;
|
||||
|
||||
void init(const parameter::ParameterGroup& params);
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<EclipseWriter> EclipseWriterPtr;
|
||||
typedef std::shared_ptr<const EclipseWriter> EclipseWriterConstPtr;
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#endif // OPM_ECLIPSE_WRITER_HPP
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2012 Statoil ASA.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/io/eclipse/writeECLData.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef HAVE_ERT // This one goes almost to the bottom of the file
|
||||
|
||||
#include <ert/ecl/ecl_grid.h>
|
||||
#include <ert/ecl/ecl_util.h>
|
||||
#include <ert/ecl/ecl_rst_file.h>
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
static ecl_kw_type * ecl_kw_wrapper( const UnstructuredGrid& grid,
|
||||
const std::string& kw_name ,
|
||||
const std::vector<double> * data ,
|
||||
int offset ,
|
||||
int stride ) {
|
||||
|
||||
if (stride <= 0)
|
||||
OPM_THROW(std::runtime_error, "Vector strides must be positive. Got stride = " << stride);
|
||||
if ((stride * std::vector<double>::size_type(grid.number_of_cells)) != data->size())
|
||||
OPM_THROW(std::runtime_error, "Internal mismatch grid.number_of_cells: " << grid.number_of_cells << " data size: " << data->size() / stride);
|
||||
{
|
||||
ecl_kw_type * ecl_kw = ecl_kw_alloc( kw_name.c_str() , grid.number_of_cells , ECL_FLOAT_TYPE );
|
||||
for (int i=0; i < grid.number_of_cells; i++)
|
||||
ecl_kw_iset_float( ecl_kw , i , (*data)[i*stride + offset]);
|
||||
return ecl_kw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function will write the data solution data in the DataMap
|
||||
@data as an ECLIPSE restart file, in addition to the solution
|
||||
fields the ECLIPSE restart file will have a minimum (hopefully
|
||||
sufficient) amount of header information.
|
||||
|
||||
The ECLIPSE restart files come in two varietes; unified restart
|
||||
files which have all the report steps lumped together in one large
|
||||
chunk and non-unified restart files which are one file for each
|
||||
report step. In addition the files can be either formatted
|
||||
(i.e. ASCII) or unformatted (i.e. binary).
|
||||
|
||||
The writeECLData() function has two hardcoded settings:
|
||||
'file_type' and 'fmt_file' which regulate which type of files the
|
||||
should be created. The extension of the files follow a convention:
|
||||
|
||||
Unified, formatted : .FUNRST
|
||||
Unified, unformatted : .UNRST
|
||||
Multiple, formatted : .Fnnnn
|
||||
Multiple, unformatted : .Xnnnn
|
||||
|
||||
For the multiple files the 'nnnn' part is the report number,
|
||||
formatted with '%04d' format specifier. The writeECLData()
|
||||
function will use the ecl_util_alloc_filename() function to create
|
||||
an ECLIPSE filename according to this conventions.
|
||||
*/
|
||||
|
||||
void writeECLData(const UnstructuredGrid& grid,
|
||||
const DataMap& data,
|
||||
const int current_step,
|
||||
const double current_time,
|
||||
const boost::posix_time::ptime& current_date_time,
|
||||
const std::string& output_dir,
|
||||
const std::string& base_name) {
|
||||
|
||||
ecl_file_enum file_type = ECL_UNIFIED_RESTART_FILE; // Alternatively ECL_RESTART_FILE for multiple restart files.
|
||||
bool fmt_file = false;
|
||||
|
||||
char * filename = ecl_util_alloc_filename(output_dir.c_str() , base_name.c_str() , file_type , fmt_file , current_step );
|
||||
int phases = ECL_OIL_PHASE + ECL_WATER_PHASE;
|
||||
time_t date = 0;
|
||||
int nx = grid.cartdims[0];
|
||||
int ny = grid.cartdims[1];
|
||||
int nz = grid.cartdims[2];
|
||||
int nactive = grid.number_of_cells;
|
||||
ecl_rst_file_type * rst_file;
|
||||
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
ptime t0( boost::gregorian::date(1970 , 1 ,1) );
|
||||
time_duration::sec_type seconds = (current_date_time - t0).total_seconds();
|
||||
|
||||
date = time_t( seconds );
|
||||
}
|
||||
|
||||
if (current_step > 0 && file_type == ECL_UNIFIED_RESTART_FILE)
|
||||
rst_file = ecl_rst_file_open_append( filename );
|
||||
else
|
||||
rst_file = ecl_rst_file_open_write( filename );
|
||||
|
||||
{
|
||||
ecl_rsthead_type rsthead_data = {};
|
||||
|
||||
const int num_wells = 0;
|
||||
const int niwelz = 0;
|
||||
const int nzwelz = 0;
|
||||
const int niconz = 0;
|
||||
const int ncwmax = 0;
|
||||
|
||||
rsthead_data.nx = nx;
|
||||
rsthead_data.ny = ny;
|
||||
rsthead_data.nz = nz;
|
||||
rsthead_data.nwells = num_wells;
|
||||
rsthead_data.niwelz = niwelz;
|
||||
rsthead_data.nzwelz = nzwelz;
|
||||
rsthead_data.niconz = niconz;
|
||||
rsthead_data.ncwmax = ncwmax;
|
||||
rsthead_data.nactive = nactive;
|
||||
rsthead_data.phase_sum = phases;
|
||||
rsthead_data.sim_time = date;
|
||||
|
||||
rsthead_data.sim_days = Opm::unit::convert::to(current_time, Opm::unit::day); //Data for doubhead
|
||||
|
||||
ecl_rst_file_fwrite_header( rst_file , current_step , &rsthead_data);
|
||||
}
|
||||
|
||||
ecl_rst_file_start_solution( rst_file );
|
||||
|
||||
{
|
||||
DataMap::const_iterator i = data.find("pressure");
|
||||
if (i != data.end()) {
|
||||
ecl_kw_type * pressure_kw = ecl_kw_wrapper( grid , "PRESSURE" , i->second , 0 , 1);
|
||||
ecl_rst_file_add_kw( rst_file , pressure_kw );
|
||||
ecl_kw_free( pressure_kw );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
DataMap::const_iterator i = data.find("saturation");
|
||||
if (i != data.end()) {
|
||||
if (int(i->second->size()) != 2 * grid.number_of_cells) {
|
||||
OPM_THROW(std::runtime_error, "writeECLData() requires saturation field to have two phases.");
|
||||
}
|
||||
ecl_kw_type * swat_kw = ecl_kw_wrapper( grid , "SWAT" , i->second , 0 , 2);
|
||||
ecl_rst_file_add_kw( rst_file , swat_kw );
|
||||
ecl_kw_free( swat_kw );
|
||||
}
|
||||
}
|
||||
|
||||
ecl_rst_file_end_solution( rst_file );
|
||||
ecl_rst_file_close( rst_file );
|
||||
free(filename);
|
||||
}
|
||||
}
|
||||
|
||||
#else // that is, we have not defined HAVE_ERT
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
void writeECLData(const UnstructuredGrid&,
|
||||
const DataMap&,
|
||||
const int,
|
||||
const double,
|
||||
const boost::posix_time::ptime&,
|
||||
const std::string&,
|
||||
const std::string&)
|
||||
{
|
||||
OPM_THROW(std::runtime_error, "Cannot call writeECLData() without ERT library support. Reconfigure opm-core with ERT support and recompile.");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2012 Statoil ASA.
|
||||
|
||||
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_WRITEECLDATA_HEADER_INCLUDED
|
||||
#define OPM_WRITEECLDATA_HEADER_INCLUDED
|
||||
|
||||
|
||||
#include <opm/core/utility/DataMap.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
// ECLIPSE output for general grids.
|
||||
void writeECLData(const UnstructuredGrid& grid,
|
||||
const DataMap& data,
|
||||
const int current_step,
|
||||
const double current_time,
|
||||
const boost::posix_time::ptime& current_date_time,
|
||||
const std::string& output_dir,
|
||||
const std::string& base_name);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,408 +0,0 @@
|
||||
/*===========================================================================
|
||||
//
|
||||
// File: vag.cpp
|
||||
//
|
||||
// Created: 2012-06-08 15:45:53+0200
|
||||
//
|
||||
// Authors: Knut-Andreas Lie <Knut-Andreas.Lie@sintef.no>
|
||||
// Halvor M. Nilsen <HalvorMoll.Nilsen@sintef.no>
|
||||
// Atgeirr F. Rasmussen <atgeirr@sintef.no>
|
||||
// Xavier Raynaud <Xavier.Raynaud@sintef.no>
|
||||
// Bård Skaflestad <Bard.Skaflestad@sintef.no>
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2012 Statoil ASA.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <opm/core/io/vag/vag.hpp>
|
||||
#include <opm/core/grid/cornerpoint_grid.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
namespace Opm
|
||||
{
|
||||
void readPosStruct(std::istream& is,int n,PosStruct& pos_struct){
|
||||
using namespace std;
|
||||
//PosStruct pos_struct;
|
||||
pos_struct.pos.resize(n+1);
|
||||
pos_struct.pos[0]=0;
|
||||
for(int i=0;i< n;++i){
|
||||
int number;
|
||||
is >> number ;
|
||||
//cout <<number << endl;
|
||||
pos_struct.pos[i+1]=pos_struct.pos[i]+number;
|
||||
for(int j=0;j< number;++j){
|
||||
int value;
|
||||
is >> value;
|
||||
// cout << value << " ";
|
||||
pos_struct.value.push_back(value);
|
||||
}
|
||||
//cout << endl;
|
||||
}
|
||||
if(int(pos_struct.value.size()) != pos_struct.pos[n]){
|
||||
cerr << "Failed to read pos structure" << endl;
|
||||
cerr << "pos_struct.value.size()" << pos_struct.value.size() << endl;
|
||||
cerr << "pos_struct.pos[n+1]" << pos_struct.pos[n] << endl;
|
||||
}
|
||||
}
|
||||
void writePosStruct(std::ostream& os,PosStruct& pos_struct){
|
||||
using namespace std;
|
||||
//PosStruct pos_struct;
|
||||
if(pos_struct.pos.size()==0){
|
||||
return;
|
||||
}
|
||||
int n=pos_struct.pos.size()-1;
|
||||
pos_struct.pos.resize(n+1);
|
||||
pos_struct.pos[0]=0;
|
||||
for(int i=0;i< n;++i){
|
||||
int number=pos_struct.pos[i+1]-pos_struct.pos[i];
|
||||
os << number << " ";
|
||||
for(int j=0;j< number;++j){
|
||||
os << pos_struct.value[pos_struct.pos[i]+j] << " ";
|
||||
}
|
||||
os << endl;
|
||||
}
|
||||
}
|
||||
void readVagGrid(std::istream& is,Opm::VAG& vag_grid){
|
||||
using namespace std;
|
||||
using namespace Opm;
|
||||
while (!is.eof()) {
|
||||
string keyword;
|
||||
is >> keyword;
|
||||
//cout << keyword<< endl;
|
||||
if(keyword == "Number"){
|
||||
string stmp;
|
||||
is >> stmp;
|
||||
if(stmp == "of"){
|
||||
string entity;
|
||||
is >> entity;
|
||||
getline(is,stmp);
|
||||
int number;
|
||||
is >> number;
|
||||
if(entity=="vertices"){
|
||||
vag_grid.number_of_vertices=number;
|
||||
}else if((entity=="volumes") || (entity=="control")){
|
||||
vag_grid.number_of_volumes=number;
|
||||
}else if(entity=="faces"){
|
||||
vag_grid.number_of_faces=number;
|
||||
}else if(entity=="edges"){
|
||||
vag_grid.number_of_edges=number;
|
||||
}
|
||||
cout << "Found Number of: " << entity <<" " << number << endl;
|
||||
} else {
|
||||
cerr << "Wrong format: Not of after Number" << endl;
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
// read geometry defined by vertices
|
||||
if(keyword=="Vertices"){
|
||||
int number;
|
||||
is >> number;
|
||||
vag_grid.vertices.resize(3*number);// assume 3d data
|
||||
readVector(is,vag_grid.vertices);
|
||||
}
|
||||
// here starts the reding of all pos structures
|
||||
else if(keyword=="Volumes->Faces" || keyword=="Volumes->faces"){
|
||||
//vag_grid.volumes_to_faces=
|
||||
int number;
|
||||
is >> number;
|
||||
readPosStruct(is,number,vag_grid.volumes_to_faces);
|
||||
cout << "Volumes->Faces: Number of " << number << endl;
|
||||
}else if(keyword=="Faces->edges" || keyword=="Faces->Edges" || keyword=="Faces->Edgess"){
|
||||
int number;
|
||||
is >> number;
|
||||
//vag_grid.volumes_to_faces=
|
||||
readPosStruct(is,number,vag_grid.faces_to_edges);
|
||||
cout << "Faces->edges: Number of " << number << endl;
|
||||
}else if(keyword=="Faces->Vertices" || keyword=="Faces->vertices"){
|
||||
int number;
|
||||
is >> number;
|
||||
//vag_grid.volumes_to_faces=
|
||||
readPosStruct(is,number,vag_grid.faces_to_vertices);
|
||||
cout << "Faces->Vertices: Number of " << number << endl;
|
||||
}else if(keyword=="Volumes->Vertices" || keyword=="Volumes->Verticess"){
|
||||
int number;
|
||||
is >> number;
|
||||
//vag_grid.volumes_to_faces=
|
||||
readPosStruct(is,number,vag_grid.volumes_to_vertices);
|
||||
cout << "Volumes->Vertices: Number of " << number << endl;
|
||||
}
|
||||
|
||||
// read simple mappings
|
||||
else if(keyword=="Edge" || keyword=="Edges"){
|
||||
int number;
|
||||
is >> number;
|
||||
vag_grid.edges.resize(2*number);
|
||||
readVector(is,vag_grid.edges);
|
||||
cout << "Edges: Number of " << number << endl;
|
||||
}else if(keyword=="Faces->Volumes" || keyword=="Faces->Control"){
|
||||
int number;
|
||||
if(keyword=="Faces->Control"){
|
||||
string vol;
|
||||
is >> vol;
|
||||
}
|
||||
is >> number;
|
||||
vag_grid.faces_to_volumes.resize(2*number);
|
||||
readVector(is,vag_grid.faces_to_volumes);
|
||||
cout << "Faces->Volumes: Number of " << number << endl;
|
||||
}
|
||||
// read material
|
||||
else if(keyword=="Material"){
|
||||
string snum;
|
||||
is >> snum;
|
||||
int number;
|
||||
is >> number;
|
||||
cout << "Material number " << number << endl;
|
||||
// we read all the rest into doubles
|
||||
while(!is.eof()){
|
||||
double value;
|
||||
is >> value;
|
||||
//cout << value << endl;
|
||||
vag_grid.material.push_back(value);
|
||||
}
|
||||
}else{
|
||||
//cout << "keyword;
|
||||
}
|
||||
//cout << "Found" << keyword << "Number of " << number << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
void vagToUnstructuredGrid(Opm::VAG& vag_grid,UnstructuredGrid& grid){
|
||||
using namespace std;
|
||||
using namespace Opm;
|
||||
cout << "Converting grid" << endl;
|
||||
cout << "Warning:: orignial grid may not be edge confomal" << endl;
|
||||
cout << " inverse mappings from edges will be wrong" << endl;
|
||||
grid.dimensions=3;
|
||||
grid.number_of_cells=vag_grid.number_of_volumes;
|
||||
grid.number_of_faces=vag_grid.number_of_faces;
|
||||
grid.number_of_nodes=vag_grid.number_of_vertices;
|
||||
|
||||
// fill face_nodes
|
||||
for(int i=0;i< int(vag_grid.faces_to_vertices.pos.size());++i){
|
||||
grid.face_nodepos[i] = vag_grid.faces_to_vertices.pos[i];
|
||||
}
|
||||
for(int i=0;i< int(vag_grid.faces_to_vertices.value.size());++i){
|
||||
grid.face_nodes[i] = vag_grid.faces_to_vertices.value[i]-1;
|
||||
}
|
||||
// fill cell_face
|
||||
for(int i=0;i< int(vag_grid.volumes_to_faces.pos.size());++i){
|
||||
grid.cell_facepos[i] = vag_grid.volumes_to_faces.pos[i];
|
||||
}
|
||||
for(int i=0;i< int(vag_grid.volumes_to_faces.value.size());++i){
|
||||
grid.cell_faces[i] = vag_grid.volumes_to_faces.value[i]-1;
|
||||
}
|
||||
// fill face_cells
|
||||
for(int i=0;i< int(vag_grid.faces_to_volumes.size());++i){
|
||||
grid.face_cells[i] = vag_grid.faces_to_volumes[i]-1;
|
||||
}
|
||||
|
||||
// fill node_cordinates. This is the only geometry given in the vag
|
||||
for(int i=0;i< int(vag_grid.vertices.size());++i){
|
||||
grid.node_coordinates[i] = vag_grid.vertices[i];
|
||||
}
|
||||
// informations in edges, faces_to_eges, faces_to_vertices, volume_to_vertices and materials
|
||||
// is not used
|
||||
cout << "Computing geometry" << endl;
|
||||
compute_geometry(&grid);
|
||||
|
||||
}
|
||||
|
||||
void unstructuredGridToVag(UnstructuredGrid& grid,Opm::VAG& vag_grid){
|
||||
using namespace std;
|
||||
using namespace Opm;
|
||||
cout << "Converting grid" << endl;
|
||||
// grid.dimensions=3;
|
||||
vag_grid.number_of_volumes=grid.number_of_cells;
|
||||
vag_grid.number_of_faces=grid.number_of_faces;
|
||||
vag_grid.number_of_vertices=grid.number_of_nodes;
|
||||
|
||||
// resizing vectors
|
||||
vag_grid.vertices.resize(grid.number_of_nodes*3);
|
||||
vag_grid.faces_to_vertices.pos.resize(grid.number_of_faces+1);
|
||||
vag_grid.faces_to_vertices.value.resize(grid.face_nodepos[grid.number_of_faces]);
|
||||
vag_grid.faces_to_volumes.resize(2*grid.number_of_faces);
|
||||
vag_grid.volumes_to_faces.pos.resize(grid.number_of_cells+1);
|
||||
vag_grid.volumes_to_faces.value.resize(grid.cell_facepos[grid.number_of_cells]);//not known
|
||||
|
||||
|
||||
|
||||
|
||||
// fill face_nodes
|
||||
for(int i=0;i< int(vag_grid.faces_to_vertices.pos.size());++i){
|
||||
vag_grid.faces_to_vertices.pos[i] = grid.face_nodepos[i];
|
||||
}
|
||||
|
||||
for(int i=0;i< int(vag_grid.faces_to_vertices.value.size());++i){
|
||||
vag_grid.faces_to_vertices.value[i] = grid.face_nodes[i] +1;
|
||||
}
|
||||
|
||||
// fill cell_face
|
||||
for(int i=0;i< int(vag_grid.volumes_to_faces.pos.size());++i){
|
||||
vag_grid.volumes_to_faces.pos[i] = grid.cell_facepos[i];
|
||||
}
|
||||
for(int i=0;i< int(vag_grid.volumes_to_faces.value.size());++i){
|
||||
vag_grid.volumes_to_faces.value[i] = grid.cell_faces[i] +1;
|
||||
}
|
||||
// fill face_cells
|
||||
for(int i=0;i< int(vag_grid.faces_to_volumes.size());++i){
|
||||
vag_grid.faces_to_volumes[i] = grid.face_cells[i] +1;
|
||||
}
|
||||
|
||||
// fill node_cordinates. This is the only geometry given in the vag
|
||||
for(int i=0;i< int(vag_grid.vertices.size());++i){
|
||||
vag_grid.vertices[i] = grid.node_coordinates[i];
|
||||
}
|
||||
|
||||
|
||||
// The missing field need to be constructed
|
||||
// gennerate volume to vertice mapping
|
||||
std::vector< std::set<int> > volumes_to_vertices(grid.number_of_cells);
|
||||
for(int i=0;i < grid.number_of_cells; ++i){
|
||||
int nlf=grid.cell_facepos[i+1]-grid.cell_facepos[i];
|
||||
std::set<int> nodes;
|
||||
for(int j=0; j < nlf; ++j){
|
||||
int face = grid.cell_faces[grid.cell_facepos[i]+j];
|
||||
int nlv = grid.face_nodepos[face+1]-grid.face_nodepos[face];
|
||||
for(int k=0; k< nlv; ++k){
|
||||
int node = grid.face_nodes[grid.face_nodepos[face]+k]+1;
|
||||
nodes.insert(node);
|
||||
}
|
||||
}
|
||||
volumes_to_vertices[i]=nodes;
|
||||
}
|
||||
|
||||
// fill volume to vertice map
|
||||
vag_grid.volumes_to_vertices.pos.resize(grid.number_of_cells+1);
|
||||
vag_grid.volumes_to_vertices.value.resize(0);
|
||||
vag_grid.volumes_to_vertices.pos[0]=0;
|
||||
for(int i=0;i < grid.number_of_cells;++i){
|
||||
int nv=volumes_to_vertices[i].size();
|
||||
vag_grid.volumes_to_vertices.pos[i+1]=vag_grid.volumes_to_vertices.pos[i]+nv;
|
||||
std::set<int>::iterator it;
|
||||
for(it=volumes_to_vertices[i].begin();it!=volumes_to_vertices[i].end();++it){
|
||||
vag_grid.volumes_to_vertices.value.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
std::set< std::set<int> > edges;
|
||||
std::vector< std::vector< std::set<int> > > faces_spares;
|
||||
int nfe=0;
|
||||
faces_spares.resize(grid.number_of_faces);
|
||||
for(int i=0;i < grid.number_of_faces;++i){
|
||||
int ne=grid.face_nodepos[i+1]-grid.face_nodepos[i];
|
||||
nfe=nfe+ne;
|
||||
|
||||
for(int j=0; j < ne-1;++j){
|
||||
int node1=grid.face_nodes[grid.face_nodepos[i]+j]+1;
|
||||
int node2=grid.face_nodes[grid.face_nodepos[i]+j+1]+1;
|
||||
std::set<int> spair;
|
||||
spair.insert(node1);
|
||||
spair.insert(node2);
|
||||
edges.insert(spair);
|
||||
faces_spares[i].push_back(spair);
|
||||
}
|
||||
// add end segment
|
||||
{
|
||||
std::set<int> spair;
|
||||
int node1=grid.face_nodes[grid.face_nodepos[i]+ne-1]+1;
|
||||
int node2=grid.face_nodes[grid.face_nodepos[i]]+1;
|
||||
spair.insert(node1);
|
||||
spair.insert(node2);
|
||||
edges.insert(spair);
|
||||
faces_spares[i].push_back(spair);
|
||||
}
|
||||
}
|
||||
|
||||
// make edge numbering and fill edges
|
||||
std::map<std::set<int>, int> edge_map;
|
||||
std::set< std::set<int> >::iterator it;
|
||||
vag_grid.edges.resize(0);
|
||||
int k=0;
|
||||
for(it=edges.begin(); it!=edges.end();++it){
|
||||
edge_map.insert(std::pair< std::set<int> , int >(*it,k));
|
||||
k=k+1;
|
||||
std::set<int>::iterator sit;
|
||||
for(sit=(*it).begin();sit!=(*it).end();++sit){
|
||||
vag_grid.edges.push_back(*sit);
|
||||
}
|
||||
}
|
||||
// fill face_to_egdes
|
||||
vag_grid.number_of_edges=edges.size();
|
||||
vag_grid.faces_to_edges.pos.resize(vag_grid.number_of_faces+1);
|
||||
for(int i=0;i < grid.number_of_faces;++i){
|
||||
int ne=grid.face_nodepos[i+1]-grid.face_nodepos[i];
|
||||
vag_grid.faces_to_edges.pos[i+1]=vag_grid.faces_to_edges.pos[i]+ne;
|
||||
for(int j=0;j<int(faces_spares[i].size());++j){
|
||||
int edge_num=edge_map[faces_spares[i][j]];
|
||||
vag_grid.faces_to_edges.value.push_back(edge_num+1);
|
||||
}
|
||||
}
|
||||
// vag_grid.edges(0);//not known
|
||||
// vag_grid.faces_to_edges// not known
|
||||
|
||||
// material // can not be extracted from the grid
|
||||
}
|
||||
|
||||
void writeVagFormat(std::ostream& os,Opm::VAG& vag_grid){
|
||||
using namespace std;
|
||||
os << "File in the Vag grid format\n";
|
||||
os << "Number of vertices " ;
|
||||
os << vag_grid.number_of_vertices << endl;;
|
||||
os <<"Number of control volume ";
|
||||
os << vag_grid.number_of_volumes << endl;
|
||||
os <<"Number of faces " ;
|
||||
os << vag_grid.number_of_faces << endl;
|
||||
os <<"Number of edges " ;
|
||||
os << vag_grid.number_of_edges << endl;
|
||||
os <<"Vertices " << vag_grid.vertices.size() << endl;
|
||||
writeVector(os, vag_grid.vertices,3);
|
||||
os << "Volumes->faces " << vag_grid.volumes_to_faces.pos.size()-1 << endl;
|
||||
writePosStruct(os, vag_grid.volumes_to_faces);
|
||||
os << "Volumes->Vertices " << vag_grid.volumes_to_vertices.pos.size()-1 << endl;
|
||||
writePosStruct(os, vag_grid.volumes_to_vertices);
|
||||
os << "Faces->edges " << vag_grid.faces_to_edges.pos.size()-1 << endl;
|
||||
writePosStruct(os, vag_grid.faces_to_edges);
|
||||
os << "Faces->vertices " << vag_grid.faces_to_vertices.pos.size()-1 << endl;
|
||||
writePosStruct(os, vag_grid.faces_to_vertices);
|
||||
os << "Faces->Control volumes " << floor(vag_grid.faces_to_volumes.size()/2) << endl;
|
||||
writeVector(os,vag_grid.faces_to_volumes,2);
|
||||
os << "Edges " << floor(vag_grid.edges.size()/2) << endl;
|
||||
writeVector(os,vag_grid.edges,2);
|
||||
/*
|
||||
assert(vag_grid.material.size()%vag_grid.number_of_volumes==0);
|
||||
int lines= floor(vag_grid.material.size()/vag_grid.number_of_volumes);
|
||||
os << "Material number " << 1 << endl;
|
||||
writeVector(os,vag_grid.material,lines);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
/*===========================================================================
|
||||
//
|
||||
// File: vag.hpp
|
||||
//
|
||||
// Created: 2012-06-08 15:46:23+0200
|
||||
//
|
||||
// Authors: Knut-Andreas Lie <Knut-Andreas.Lie@sintef.no>
|
||||
// Halvor M. Nilsen <HalvorMoll.Nilsen@sintef.no>
|
||||
// Atgeirr F. Rasmussen <atgeirr@sintef.no>
|
||||
// Xavier Raynaud <Xavier.Raynaud@sintef.no>
|
||||
// Bård Skaflestad <Bard.Skaflestad@sintef.no>
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2012 Statoil ASA.
|
||||
|
||||
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_VAG_HPP_HEADER
|
||||
#define OPM_VAG_HPP_HEADER
|
||||
|
||||
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/**
|
||||
Struct to hold mapping from the natural numbers less than pos.size()-1 to
|
||||
a set of integers. value(pos(i):pos(i+1)-1) hold the integers corresponding to i.
|
||||
pos(end)-1==value.size();
|
||||
*/
|
||||
struct PosStruct{
|
||||
std::vector<int> pos;
|
||||
std::vector<int> value;
|
||||
};
|
||||
/**
|
||||
Structure to represent the unstructured vag grid format. The format is only for
|
||||
3D grids.
|
||||
*/
|
||||
struct VAG{
|
||||
int number_of_vertices;
|
||||
int number_of_volumes;
|
||||
int number_of_faces;
|
||||
int number_of_edges;
|
||||
/** Vertices. The coordinates of vertice i is [vetices[3*i:3*i+2]*/
|
||||
std::vector<double> vertices;
|
||||
/** Mapping from volumes to faces */
|
||||
PosStruct volumes_to_faces;
|
||||
/** Mapping from volumes to vertices */
|
||||
PosStruct volumes_to_vertices;
|
||||
/** Mapping from faces to edges */
|
||||
PosStruct faces_to_edges;
|
||||
/** Mapping from faces to vertices */
|
||||
PosStruct faces_to_vertices;
|
||||
/** The edge i is given by the nodes edges[2*i:2*i+1] */
|
||||
std::vector<int> edges;
|
||||
/** The two neigbours of the face i is faces_to_volumes[2*i:2*i+1] */
|
||||
std::vector<int> faces_to_volumes;
|
||||
/** A vector containing information of each volume. The size is n*number_of_volumes.
|
||||
For each i this is the information:
|
||||
material[n*i] is the volume number and should be transformed to integer
|
||||
material[n*i+1] is a tag and should be transformed to integer
|
||||
material[n*i+2:n*(i+1)-1] represent propertices.
|
||||
*/
|
||||
std::vector<double> material;
|
||||
};
|
||||
/**
|
||||
Function the vag grid format and make a vag_grid struct. This structure
|
||||
is intended to be converted to a grid.
|
||||
\param[in] is is is stream of the file.
|
||||
\param[out] vag_grid is a reference to a vag_grid struct.
|
||||
*/
|
||||
void readVagGrid(std::istream& is,Opm::VAG& vag_grid);
|
||||
/**
|
||||
Function to write vag format.
|
||||
\param[out] is is is stream of the file.
|
||||
\param[in] vag_grid is a reference to a vag_grid struct.
|
||||
|
||||
*/
|
||||
void writeVagFormat(std::ostream& os,Opm::VAG& vag_grid);
|
||||
/**
|
||||
Function to read a vector of some type from a stream.
|
||||
\param[in] os is is stream of the file.
|
||||
\param[out] vag_grid is a resized and filled vector containing the quantiy read.
|
||||
*/
|
||||
template <typename T>
|
||||
void readVector(std::istream& is,std::vector<T>& vec){
|
||||
using namespace std;
|
||||
for(int i=0;i< int(vec.size());++i){
|
||||
is >> vec[i];
|
||||
}
|
||||
}
|
||||
/**
|
||||
Function to write a vector of some type from a stream.
|
||||
\param[in] os is is stream of the file.
|
||||
\param[out] vag_grid is a resized and filled vector containing the quantiy read.
|
||||
\param[in] n number of doubles on each line.
|
||||
*/
|
||||
template <typename T>
|
||||
void writeVector(std::ostream& os,std::vector<T>& vec,int n){
|
||||
typedef typename std::vector<T>::size_type sz_t;
|
||||
|
||||
const sz_t nn = n;
|
||||
|
||||
for (sz_t i = 0; i < vec.size(); ++i) {
|
||||
os << vec[i] << (((i % nn) == 0) ? '\n' : ' ');
|
||||
}
|
||||
|
||||
if ((vec.size() % nn) != 0) {
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Read pos struct type mapping from a stream
|
||||
\param[in] is is stream
|
||||
\param[in] n number of lines to read
|
||||
\param[out] pos_struct reference to PosStruct
|
||||
*/
|
||||
void readPosStruct(std::istream& is,int n,PosStruct& pos_struct);
|
||||
/**
|
||||
Read pos struct type mapping from a stream
|
||||
\param[in] os is stream to write to
|
||||
\param[in] pos_struct to write
|
||||
*/
|
||||
void writePosStruct(std::ostream& os,PosStruct& pos_struct);
|
||||
|
||||
/**
|
||||
Fill a UnstructuredGrid from a vag_grid.
|
||||
\param[out] vag_grid s is a valid vag_grid struct.
|
||||
\param[in] grid is a grid with have allocated correct size to each pointer.
|
||||
*/
|
||||
void vagToUnstructuredGrid(Opm::VAG& vag_grid,UnstructuredGrid& grid);
|
||||
|
||||
/**
|
||||
Fill a vag_grid from UnstructuredGrid
|
||||
\param[out] vag_grid s is a valid vag_grid struct.
|
||||
\param[in] grid is a grid with have allocated correct size to each pointer.
|
||||
*/
|
||||
void unstructuredGridToVag(UnstructuredGrid& grid, Opm::VAG& vag_grid);
|
||||
}
|
||||
#endif /* OPM_VAG_HPP_HEADER */
|
||||
|
@ -1,319 +0,0 @@
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <opm/core/io/vtk/writeVtkData.hpp>
|
||||
#include <opm/core/utility/DataMap.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
void writeVtkData(const std::array<int, 3>& dims,
|
||||
const std::array<double, 3>& cell_size,
|
||||
const DataMap& data,
|
||||
std::ostream& os)
|
||||
{
|
||||
// Dimension is hardcoded in the prototype and the next two lines,
|
||||
// but the rest is flexible (allows dimension == 2 or 3).
|
||||
int dimension = 3;
|
||||
int num_cells = dims[0]*dims[1]*dims[2];
|
||||
|
||||
assert(dimension == 2 || dimension == 3);
|
||||
assert(num_cells == dims[0]*dims[1]* (dimension == 2 ? 1 : dims[2]));
|
||||
|
||||
os << "# vtk DataFile Version 2.0\n";
|
||||
os << "Structured Grid\n \n";
|
||||
os << "ASCII \n";
|
||||
os << "DATASET STRUCTURED_POINTS\n";
|
||||
|
||||
os << "DIMENSIONS "
|
||||
<< dims[0] + 1 << " "
|
||||
<< dims[1] + 1 << " ";
|
||||
if (dimension == 3) {
|
||||
os << dims[2] + 1;
|
||||
} else {
|
||||
os << 1;
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
os << "ORIGIN " << 0.0 << " " << 0.0 << " " << 0.0 << "\n";
|
||||
|
||||
os << "SPACING " << cell_size[0] << " " << cell_size[1];
|
||||
if (dimension == 3) {
|
||||
os << " " << cell_size[2];
|
||||
} else {
|
||||
os << " " << 0.0;
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
os << "\nCELL_DATA " << num_cells << '\n';
|
||||
for (DataMap::const_iterator dit = data.begin(); dit != data.end(); ++dit) {
|
||||
std::string name = dit->first;
|
||||
os << "SCALARS " << name << " float" << '\n';
|
||||
os << "LOOKUP_TABLE " << name << "_table " << '\n';
|
||||
const std::vector<double>& field = *(dit->second);
|
||||
// We always print only the first data item for every
|
||||
// cell, using 'stride'.
|
||||
// This is a hack to get water saturation nicely.
|
||||
// \TODO: Extend to properly printing vector data.
|
||||
const int stride = field.size()/num_cells;
|
||||
const int num_per_line = 5;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
os << field[stride*c] << ' ';
|
||||
if (c % num_per_line == num_per_line - 1
|
||||
|| c == num_cells - 1) {
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::map<std::string, std::string> PMap;
|
||||
|
||||
|
||||
struct Tag
|
||||
{
|
||||
Tag(const std::string& tag, const PMap& props, std::ostream& os)
|
||||
: name_(tag), os_(os)
|
||||
{
|
||||
indent(os);
|
||||
os << "<" << tag;
|
||||
for (PMap::const_iterator it = props.begin(); it != props.end(); ++it) {
|
||||
os << " " << it->first << "=\"" << it->second << "\"";
|
||||
}
|
||||
os << ">\n";
|
||||
++indent_;
|
||||
}
|
||||
Tag(const std::string& tag, std::ostream& os)
|
||||
: name_(tag), os_(os)
|
||||
{
|
||||
indent(os);
|
||||
os << "<" << tag << ">\n";
|
||||
++indent_;
|
||||
}
|
||||
~Tag()
|
||||
{
|
||||
--indent_;
|
||||
indent(os_);
|
||||
os_ << "</" << name_ << ">\n";
|
||||
}
|
||||
static void indent(std::ostream& os)
|
||||
{
|
||||
for (int i = 0; i < indent_; ++i) {
|
||||
os << " ";
|
||||
}
|
||||
}
|
||||
private:
|
||||
static int indent_;
|
||||
std::string name_;
|
||||
std::ostream& os_;
|
||||
};
|
||||
|
||||
int Tag::indent_ = 0;
|
||||
|
||||
|
||||
void writeVtkData(const UnstructuredGrid& grid,
|
||||
const DataMap& data,
|
||||
std::ostream& os)
|
||||
{
|
||||
if (grid.dimensions != 3) {
|
||||
OPM_THROW(std::runtime_error, "Vtk output for 3d grids only");
|
||||
}
|
||||
os.precision(12);
|
||||
os << "<?xml version=\"1.0\"?>\n";
|
||||
PMap pm;
|
||||
pm["type"] = "UnstructuredGrid";
|
||||
Tag vtkfiletag("VTKFile", pm, os);
|
||||
Tag ugtag("UnstructuredGrid", os);
|
||||
int num_pts = grid.number_of_nodes;
|
||||
int num_cells = grid.number_of_cells;
|
||||
pm.clear();
|
||||
pm["NumberOfPoints"] = boost::lexical_cast<std::string>(num_pts);
|
||||
pm["NumberOfCells"] = boost::lexical_cast<std::string>(num_cells);
|
||||
Tag piecetag("Piece", pm, os);
|
||||
{
|
||||
Tag pointstag("Points", os);
|
||||
pm.clear();
|
||||
pm["type"] = "Float64";
|
||||
pm["Name"] = "Coordinates";
|
||||
pm["NumberOfComponents"] = "3";
|
||||
pm["format"] = "ascii";
|
||||
Tag datag("DataArray", pm, os);
|
||||
for (int i = 0; i < num_pts; ++i) {
|
||||
Tag::indent(os);
|
||||
os << grid.node_coordinates[3*i + 0] << ' '
|
||||
<< grid.node_coordinates[3*i + 1] << ' '
|
||||
<< grid.node_coordinates[3*i + 2] << '\n';
|
||||
}
|
||||
}
|
||||
{
|
||||
Tag cellstag("Cells", os);
|
||||
pm.clear();
|
||||
pm["type"] = "Int32";
|
||||
pm["NumberOfComponents"] = "1";
|
||||
pm["format"] = "ascii";
|
||||
std::vector<int> cell_numpts;
|
||||
cell_numpts.reserve(num_cells);
|
||||
{
|
||||
pm["Name"] = "connectivity";
|
||||
Tag t("DataArray", pm, os);
|
||||
int hf = 0;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
std::set<int> cell_pts;
|
||||
for (; hf < grid.cell_facepos[c+1]; ++hf) {
|
||||
int f = grid.cell_faces[hf];
|
||||
const int* fnbeg = grid.face_nodes + grid.face_nodepos[f];
|
||||
const int* fnend = grid.face_nodes + grid.face_nodepos[f+1];
|
||||
cell_pts.insert(fnbeg, fnend);
|
||||
}
|
||||
cell_numpts.push_back(cell_pts.size());
|
||||
Tag::indent(os);
|
||||
std::copy(cell_pts.begin(), cell_pts.end(),
|
||||
std::ostream_iterator<int>(os, " "));
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
{
|
||||
pm["Name"] = "offsets";
|
||||
Tag t("DataArray", pm, os);
|
||||
int offset = 0;
|
||||
const int num_per_line = 10;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
if (c % num_per_line == 0) {
|
||||
Tag::indent(os);
|
||||
}
|
||||
offset += cell_numpts[c];
|
||||
os << offset << ' ';
|
||||
if (c % num_per_line == num_per_line - 1
|
||||
|| c == num_cells - 1) {
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<int> cell_foffsets;
|
||||
cell_foffsets.reserve(num_cells);
|
||||
{
|
||||
pm["Name"] = "faces";
|
||||
Tag t("DataArray", pm, os);
|
||||
const int* fp = grid.cell_facepos;
|
||||
int offset = 0;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
Tag::indent(os);
|
||||
os << fp[c+1] - fp[c] << '\n';
|
||||
++offset;
|
||||
for (int hf = fp[c]; hf < fp[c+1]; ++hf) {
|
||||
int f = grid.cell_faces[hf];
|
||||
const int* np = grid.face_nodepos;
|
||||
int f_num_pts = np[f+1] - np[f];
|
||||
Tag::indent(os);
|
||||
os << f_num_pts << ' ';
|
||||
++offset;
|
||||
std::copy(grid.face_nodes + np[f],
|
||||
grid.face_nodes + np[f+1],
|
||||
std::ostream_iterator<int>(os, " "));
|
||||
os << '\n';
|
||||
offset += f_num_pts;
|
||||
}
|
||||
cell_foffsets.push_back(offset);
|
||||
}
|
||||
}
|
||||
{
|
||||
pm["Name"] = "faceoffsets";
|
||||
Tag t("DataArray", pm, os);
|
||||
const int num_per_line = 10;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
if (c % num_per_line == 0) {
|
||||
Tag::indent(os);
|
||||
}
|
||||
os << cell_foffsets[c] << ' ';
|
||||
if (c % num_per_line == num_per_line - 1
|
||||
|| c == num_cells - 1) {
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
pm["type"] = "UInt8";
|
||||
pm["Name"] = "types";
|
||||
Tag t("DataArray", pm, os);
|
||||
const int num_per_line = 10;
|
||||
for (int c = 0; c < num_cells; ++c) {
|
||||
if (c % num_per_line == 0) {
|
||||
Tag::indent(os);
|
||||
}
|
||||
os << "42 ";
|
||||
if (c % num_per_line == num_per_line - 1
|
||||
|| c == num_cells - 1) {
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
pm.clear();
|
||||
if (data.find("saturation") != data.end()) {
|
||||
pm["Scalars"] = "saturation";
|
||||
} else if (data.find("pressure") != data.end()) {
|
||||
pm["Scalars"] = "pressure";
|
||||
}
|
||||
Tag celldatatag("CellData", pm, os);
|
||||
pm.clear();
|
||||
pm["NumberOfComponents"] = "1";
|
||||
pm["format"] = "ascii";
|
||||
pm["type"] = "Float64";
|
||||
for (DataMap::const_iterator dit = data.begin(); dit != data.end(); ++dit) {
|
||||
pm["Name"] = dit->first;
|
||||
const std::vector<double>& field = *(dit->second);
|
||||
const int num_comps = field.size()/grid.number_of_cells;
|
||||
pm["NumberOfComponents"] = boost::lexical_cast<std::string>(num_comps);
|
||||
Tag ptag("DataArray", pm, os);
|
||||
const int num_per_line = num_comps == 1 ? 5 : num_comps;
|
||||
for (int item = 0; item < num_cells*num_comps; ++item) {
|
||||
if (item % num_per_line == 0) {
|
||||
Tag::indent(os);
|
||||
}
|
||||
double value = field[item];
|
||||
if (std::fabs(value) < std::numeric_limits<double>::min()) {
|
||||
// Avoiding denormal numbers to work around
|
||||
// bug in Paraview.
|
||||
value = 0.0;
|
||||
}
|
||||
os << value << ' ';
|
||||
if (item % num_per_line == num_per_line - 1
|
||||
|| item == num_cells - 1) {
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
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_WRITEVTKDATA_HEADER_INCLUDED
|
||||
#define OPM_WRITEVTKDATA_HEADER_INCLUDED
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <iosfwd>
|
||||
#include <opm/core/utility/DataMap.hpp>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// Vtk output for cartesian grids.
|
||||
void writeVtkData(const std::array<int, 3>& dims,
|
||||
const std::array<double, 3>& cell_size,
|
||||
const DataMap& data,
|
||||
std::ostream& os);
|
||||
|
||||
/// Vtk output for general grids.
|
||||
void writeVtkData(const UnstructuredGrid& grid,
|
||||
const DataMap& data,
|
||||
std::ostream& os);
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_WRITEVTKDATA_HEADER_INCLUDED
|
Loading…
Reference in New Issue
Block a user