diff --git a/.gitignore b/.gitignore
index d124eee7..12188671 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
*~
.\#*
*.o
+*.mod
*.lo
*.la
.libs
@@ -29,19 +30,30 @@ ltmain.sh
m4/libtool.m4
m4/lt*.m4
missing
+ar-lib
tutorials/tutorial[1-4]
+opmcore-config.cmake
+
+# in-tree build with CMake
+CMakeCache.txt
+CMakeFiles/
+cmake_install.cmake
# Ignoring executables
*_test
+examples/compute_tof
examples/scaneclipsedeck
examples/spu_2p
examples/reorder-qfs
examples/refine_wells
examples/sim_2p_incomp_reorder
+examples/sim_2p_comp_reorder
examples/sim_wateroil
examples/wells_example
+tests/test_agmg
tests/test_cfs_tpfa
tests/test_jacsys
+tests/test_read_grid
tests/test_readvector
tests/test_sf2p
tests/bo_fluid_p_and_z_deps
@@ -51,4 +63,6 @@ tests/test_column_extract
tests/test_lapack
tests/test_read_vag
tests/test_readpolymer
+tests/test_velocityinterpolation
+tests/test_wells
tests/test_writeVtkData
diff --git a/Makefile.am b/Makefile.am
index a477f733..5a23deac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,9 @@ lib_LTLIBRARIES = lib/libopmcore.la
# Build-time flags needed to build libopmcore.la
AM_CPPFLAGS = \
-$(OPM_BOOST_CPPFLAGS)
+$(ERT_CPPFLAGS) \
+$(OPM_BOOST_CPPFLAGS) \
+$(SUPERLU_CPPFLAGS)
# ----------------------------------------------------------------------
# Link-time flags needed both to successfully link the library and to
@@ -20,14 +22,17 @@ $(OPM_BOOST_CPPFLAGS)
lib_libopmcore_la_LDFLAGS = \
-R $(OPM_BOOST_LIBDIR) \
-$(OPM_BOOST_LDFLAGS)
+$(OPM_BOOST_LDFLAGS) \
+$(ERT_LDFLAGS) \
+$(SUPERLU_LDFLAGS)
lib_libopmcore_la_LIBADD = \
$(BOOST_FILESYSTEM_LIB) \
$(BOOST_SYSTEM_LIB) \
$(BOOST_DATE_TIME_LIB) \
$(BOOST_UNIT_TEST_FRAMEWORK_LIB) \
-$(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS)
+$(ERT_LIBS) \
+$(LAPACK_LIBS) $(SUPERLU_LIBS) $(BLAS_LIBS) $(LIBS)
# ----------------------------------------------------------------------
# Library constituents. SOURCES followed by HEADERS.
@@ -53,10 +58,12 @@ opm/core/fluid/RockCompressibility.cpp \
opm/core/fluid/RockFromDeck.cpp \
opm/core/fluid/SaturationPropsBasic.cpp \
opm/core/fluid/SaturationPropsFromDeck.cpp \
+opm/core/fluid/SatFuncGwseg.cpp \
opm/core/fluid/SatFuncStone2.cpp \
opm/core/fluid/SatFuncSimple.cpp \
opm/core/fluid/blackoil/BlackoilPvtProperties.cpp \
opm/core/fluid/blackoil/SinglePvtDead.cpp \
+opm/core/fluid/blackoil/SinglePvtDeadSpline.cpp \
opm/core/fluid/blackoil/SinglePvtInterface.cpp \
opm/core/fluid/blackoil/SinglePvtLiveGas.cpp \
opm/core/fluid/blackoil/SinglePvtLiveOil.cpp \
@@ -103,6 +110,8 @@ opm/core/simulator/SimulatorReport.cpp \
opm/core/simulator/SimulatorTimer.cpp \
opm/core/transport/reorder/TransportModelCompressibleTwophase.cpp \
opm/core/transport/reorder/TransportModelInterface.cpp \
+opm/core/transport/reorder/TransportModelTracerTof.cpp \
+opm/core/transport/reorder/TransportModelTracerTofDiscGal.cpp \
opm/core/transport/reorder/TransportModelTwophase.cpp \
opm/core/transport/reorder/nlsolvers.c \
opm/core/transport/reorder/reordersequence.cpp \
@@ -112,6 +121,8 @@ opm/core/transport/spu_implicit.c \
opm/core/transport/transport_source.c \
opm/core/utility/MonotCubicInterpolator.cpp \
opm/core/utility/StopWatch.cpp \
+opm/core/utility/VelocityInterpolation.cpp \
+opm/core/utility/WachspressCoord.cpp \
opm/core/utility/miscUtilities.cpp \
opm/core/utility/miscUtilitiesBlackoil.cpp \
opm/core/utility/parameters/Parameter.cpp \
@@ -150,15 +161,19 @@ opm/core/fluid/PvtPropertiesIncompFromDeck.hpp \
opm/core/fluid/RockBasic.hpp \
opm/core/fluid/RockCompressibility.hpp \
opm/core/fluid/RockFromDeck.hpp \
-opm/core/fluid/SaturationPropsBasic.hpp \
-opm/core/fluid/SaturationPropsFromDeck.hpp \
+opm/core/fluid/SatFuncGwseg.hpp \
opm/core/fluid/SatFuncStone2.hpp \
opm/core/fluid/SatFuncSimple.hpp \
+opm/core/fluid/SaturationPropsBasic.hpp \
+opm/core/fluid/SaturationPropsFromDeck.hpp \
+opm/core/fluid/SaturationPropsFromDeck_impl.hpp \
+opm/core/fluid/SaturationPropsInterface.hpp \
opm/core/fluid/SimpleFluid2p.hpp \
opm/core/fluid/blackoil/BlackoilPhases.hpp \
opm/core/fluid/blackoil/BlackoilPvtProperties.hpp \
opm/core/fluid/blackoil/SinglePvtConstCompr.hpp \
opm/core/fluid/blackoil/SinglePvtDead.hpp \
+opm/core/fluid/blackoil/SinglePvtDeadSpline.hpp \
opm/core/fluid/blackoil/SinglePvtInterface.hpp \
opm/core/fluid/blackoil/SinglePvtLiveGas.hpp \
opm/core/fluid/blackoil/SinglePvtLiveOil.hpp \
@@ -221,6 +236,8 @@ opm/core/transport/SimpleFluid2pWrapper.hpp \
opm/core/transport/SinglePointUpwindTwoPhase.hpp \
opm/core/transport/reorder/TransportModelCompressibleTwophase.hpp \
opm/core/transport/reorder/TransportModelInterface.hpp \
+opm/core/transport/reorder/TransportModelTracerTof.hpp \
+opm/core/transport/reorder/TransportModelTracerTofDiscGal.hpp \
opm/core/transport/reorder/TransportModelTwophase.hpp \
opm/core/transport/reorder/nlsolvers.h \
opm/core/transport/reorder/reordersequence.h \
@@ -230,15 +247,19 @@ opm/core/transport/spu_implicit.h \
opm/core/transport/transport_source.h \
opm/core/utility/Average.hpp \
opm/core/utility/ColumnExtract.hpp \
+opm/core/utility/DataMap.hpp \
opm/core/utility/ErrorMacros.hpp \
opm/core/utility/Factory.hpp \
opm/core/utility/MonotCubicInterpolator.hpp \
+opm/core/utility/NonuniformTableLinear.hpp \
opm/core/utility/RootFinders.hpp \
opm/core/utility/SparseTable.hpp \
opm/core/utility/SparseVector.hpp \
opm/core/utility/StopWatch.hpp \
opm/core/utility/UniformTableLinear.hpp \
opm/core/utility/Units.hpp \
+opm/core/utility/VelocityInterpolation.hpp \
+opm/core/utility/WachspressCoord.hpp \
opm/core/utility/buildUniformMonotoneTable.hpp \
opm/core/utility/initState.hpp \
opm/core/utility/initState_impl.hpp \
@@ -279,6 +300,15 @@ opm/core/linalg/LinearSolverUmfpack.hpp
endif
+if HAVE_ERT
+lib_libopmcore_la_SOURCES += \
+opm/core/utility/writeECLData.cpp
+
+nobase_include_HEADERS += \
+opm/core/utility/writeECLData.hpp
+endif
+
+
if DUNE_ISTL
lib_libopmcore_la_SOURCES += \
opm/core/linalg/LinearSolverIstl.cpp
@@ -302,3 +332,6 @@ opm/core/linalg/LinearSolverAGMG.hpp
lib_libopmcore_la_LDFLAGS += \
$(FCLIBS)
endif
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = lib/pkgconfig/opm-core.pc
diff --git a/README b/README
index 8c7c522f..72427507 100644
--- a/README
+++ b/README
@@ -46,46 +46,39 @@ sudo apt-get install -y build-essential gfortran pkg-config libtool \
sudo apt-get install -y doxygen ghostscript texlive-latex-recommended pgf
# packages necessary for version control
-sudo apt-get install -y git-core git-svn subversion
+sudo apt-get install -y git-core
-# libraries necessary for DUNE
+# basic libraries necessary for both DUNE and OPM
sudo apt-get install -y libboost-all-dev libsuperlu3-dev libsuitesparse-dev
-# libraries necessary for OPM
-sudo apt-get install -y libxml0-dev
+# for server edition of Ubuntu add-apt-repository depends on
+sudo apt-get install python-software-properties
+# add this repository for necessary backports (required for Ubuntu Precise)
+sudo add-apt-repository -y ppa:opm/ppa
+sudo apt-get update
+
+# parts of DUNE needed
+sudo apt-get install libdune-common-dev libdune-istl-dev libdune-grid-dev
+
+# libraries necessary for OPM
+sudo apt-get install -y libxml2-dev
+
+Note: You should compile the OPM modules using the same toolchain that
+ was used to build DUNE. Otherwise, you can get strange ABI errors.
DEPENDENCIES FOR SUSE BASED DISTRIBUTIONS
-----------------------------------------
# libraries
-sudo zypper install blas libblas3 lapack liblapack3 libboost libxml2 umfpack
+sudo zypper in blas libblas3 lapack liblapack3 libboost libxml2 umfpack
# tools
-sudo zypper install gcc automake autoconf git doxygen
+sudo zypper in gcc automake autoconf git doxygen
-
-RETRIEVING AND BUILDING DUNE PREREQUISITES
-------------------------------------------
-
-(only necessary if you want to use opm-core as a dune module)
-
-# trust DUNE certificate (sic)
-echo p | svn list https://svn.dune-project.org/svn/dune-common
-
-# checkout DUNE libraries
-for module in common istl geometry grid localfunctions; do
- git svn clone -s \
- https://svn.dune-project.org/svn/dune-$module/branches/release-2.2/ \
- dune-$module
-done
-
-# building DUNE libraries
-for module in common istl geometry grid localfunctions; do
- env CCACHE_DISABLE=1 dune-common/bin/dunecontrol --only=dune-$module \
- --configure-opts="--enable-fieldvector-size-is-method" \
- --make-opts="-j -l 0.8" autogen : configure : make
-done
+# DUNE libraries
+sudo zypper ar http://download.opensuse.org/repositories/science/openSUSE_12.2/science.repo
+sudo zypper in dune-common dune-istl
DOWNLOADING
@@ -100,20 +93,26 @@ If you want to contribute, fork OPM/opm-core on github.
BUILDING
--------
-(standalone opm-core:)
+There are two ways to build the opm-core library:
- cd ../opm-core
+1. As a stand-alone library.
+ cd opm-core
autoreconf -i
./configure
- make
+ make -j -l 0.9
+If you want to install the library:
+ make install
+or (if installing to /usr/local or similar)
sudo make install
-(using opm-core as a dune module:)
-
- # note: this is done from the parent directory of opm-core
- env CCACHE_DISABLE=1 dune-common/bin/dunecontrol --only=opm-core \
- --configure-opts="" --make-opts="-j -l 0.8" autogen : configure : make
-
+2. As a dune module.
+ - Put the opm-core directory in the same directory
+ as the other dune modules to be built (e.g. dune-commmon,
+ dune-grid). Note that for Ubuntu you can install Dune
+ from the ppa as outlined above.
+ - Run dunecontrol as normal. For more information on
+ the dune build system, see
+ http://www.dune-project.org/doc/installation-notes.html
DOCUMENTATION
diff --git a/configure.ac b/configure.ac
index cc4b92e1..856a9920 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.59])
-AC_INIT([OPM Core Library], [0.1], [atgeirr@sintef.no],dnl
+AC_INIT([OPM Core Library], [0.1], [atgeirr@sintef.no],
[opmcore], [https://public.ict.sintef.no/opm/hg/opmcore])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
@@ -20,8 +20,11 @@ AC_CONFIG_HEADERS([config.h])
AC_PROG_CC
AM_PROG_CC_C_O
+dnl Initialize libtool; the funny indentation here is to
+dnl satisfy libtoolize' check for the presence of this macro
m4_ifdef([LT_INIT],
- [LT_INIT[]dnl
+ [
+ LT_INIT[]dnl
LT_LANG([C++])dnl
LT_LANG([Fortran 77])dnl
LT_LANG([Fortran])dnl
@@ -36,6 +39,8 @@ OPM_CORE_CHECKS
OPM_DYNLINK_BOOST_TEST
+ERT
+
dnl Substitute Autoconf's abs_*dir variables into the Makefiles for the
dnl benefit of external code that uses these variables to derive
dnl locations (e.g., Dune's DUNE_CHECK_MODULES macro). Automakes prior
@@ -51,6 +56,9 @@ AC_CONFIG_FILES([
tests/Makefile
examples/Makefile
tutorials/Makefile
+ opm-core.pc
+ lib/pkgconfig/opm-core.pc
+ opmcore-config.cmake
])
AC_OUTPUT
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 38d41e22..043a44c3 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -1,24 +1,48 @@
# Build-time flags needed to form example programs
-AM_CPPFLAGS = \
--I$(top_srcdir) \
+ERT_INCLUDE_PATH = $(ERT_ROOT)/include
+
+AM_CPPFLAGS = \
+-I$(top_srcdir) \
+-I$(ERT_INCLUDE_PATH) \
$(OPM_BOOST_CPPFLAGS)
# All targets link to the library
-LDADD = \
+LDADD = \
$(top_builddir)/lib/libopmcore.la
+# Convenience definition for targets that use Boost.Filesystem directly.
+# While libopmcore depends on (and references) Boost.Filesystem (through
+# the $(BOOST_FILESYSTEM_LIB) macro) this indirect dependency is not
+# sufficient to satisfy the requirements of targets that use the indirect
+# libraries directly.
+#
+# Additional details at
+# https://fedoraproject.org/wiki/UnderstandingDSOLinkChange
+#
+LINK_BOOST_FILESYSTEM = \
+$(OPM_BOOST_LDFLAGS) \
+$(BOOST_FILESYSTEM_LIB) \
+$(BOOST_SYSTEM_LIB)
+
# ----------------------------------------------------------------------
# Declare products (i.e., the example programs).
#
# Please keep the list sorted.
-noinst_PROGRAMS = \
-refine_wells \
-scaneclipsedeck \
-sim_2p_comp_reorder \
-sim_2p_incomp_reorder \
-sim_wateroil \
-wells_example
+noinst_PROGRAMS = \
+compute_tof \
+refine_wells \
+scaneclipsedeck \
+sim_2p_comp_reorder \
+sim_2p_incomp_reorder \
+sim_wateroil \
+wells_example
+
+if HAVE_ERT
+noinst_PROGRAMS += import_rewrite
+endif
+
+
# ----------------------------------------------------------------------
# Product constituents. Must be specified for every product that's
@@ -27,10 +51,25 @@ wells_example
#
# Please maintain sort order from "noinst_PROGRAMS".
+compute_tof_SOURCES = compute_tof.cpp
+compute_tof_LDADD = $(LDADD) $(LINK_BOOST_FILESYSTEM)
+
refine_wells_SOURCES = refine_wells.cpp
+
+if HAVE_ERT
+ import_rewrite_SOURCES = import_rewrite.cpp
+ import_rewrite_LDADD = $(LDADD) $(LINK_BOOST_FILESYSTEM)
+endif
+
sim_2p_comp_reorder_SOURCES = sim_2p_comp_reorder.cpp
+sim_2p_comp_reorder_LDADD = $(LDADD) $(LINK_BOOST_FILESYSTEM)
+
sim_2p_incomp_reorder_SOURCES = sim_2p_incomp_reorder.cpp
+sim_2p_incomp_reorder_LDADD = $(LDADD) $(LINK_BOOST_FILESYSTEM)
+
sim_wateroil_SOURCES = sim_wateroil.cpp
+sim_wateroil_LDADD = $(LDADD) $(LINK_BOOST_FILESYSTEM)
+
wells_example_SOURCES = wells_example.cpp
# ----------------------------------------------------------------------
@@ -40,7 +79,8 @@ if UMFPACK
noinst_PROGRAMS += spu_2p
spu_2p_SOURCES = spu_2p.cpp
-spu_2p_LDADD = \
-$(LDADD) \
+spu_2p_LDADD = \
+$(LDADD) \
+$(LINK_BOOST_FILESYSTEM) \
$(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS)
endif
diff --git a/examples/compute_tof.cpp b/examples/compute_tof.cpp
new file mode 100644
index 00000000..ce04aa59
--- /dev/null
+++ b/examples/compute_tof.cpp
@@ -0,0 +1,255 @@
+/*
+ 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 .
+*/
+
+
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+
+namespace
+{
+ void warnIfUnusedParams(const Opm::parameter::ParameterGroup& param)
+ {
+ if (param.anyUnused()) {
+ std::cout << "-------------------- Unused parameters: --------------------\n";
+ param.displayUsage();
+ std::cout << "----------------------------------------------------------------" << std::endl;
+ }
+ }
+} // anon namespace
+
+
+
+// ----------------- Main program -----------------
+int
+main(int argc, char** argv)
+{
+ using namespace Opm;
+
+ std::cout << "\n================ Test program for incompressible tof computations ===============\n\n";
+ parameter::ParameterGroup param(argc, argv, false);
+ std::cout << "--------------- Reading parameters ---------------" << std::endl;
+
+ // If we have a "deck_filename", grid and props will be read from that.
+ bool use_deck = param.has("deck_filename");
+ boost::scoped_ptr deck;
+ boost::scoped_ptr grid;
+ boost::scoped_ptr props;
+ boost::scoped_ptr wells;
+ TwophaseState state;
+ // bool check_well_controls = false;
+ // int max_well_control_iterations = 0;
+ double gravity[3] = { 0.0 };
+ if (use_deck) {
+ std::string deck_filename = param.get("deck_filename");
+ deck.reset(new EclipseGridParser(deck_filename));
+ // Grid init
+ grid.reset(new GridManager(*deck));
+ // Rock and fluid init
+ props.reset(new IncompPropertiesFromDeck(*deck, *grid->c_grid()));
+ // Wells init.
+ wells.reset(new Opm::WellsManager(*deck, *grid->c_grid(), props->permeability()));
+ // Gravity.
+ gravity[2] = deck->hasField("NOGRAV") ? 0.0 : unit::gravity;
+ // Init state variables (saturation and pressure).
+ if (param.has("init_saturation")) {
+ initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
+ } else {
+ initStateFromDeck(*grid->c_grid(), *props, *deck, gravity[2], state);
+ }
+ } else {
+ // Grid init.
+ const int nx = param.getDefault("nx", 100);
+ const int ny = param.getDefault("ny", 100);
+ const int nz = param.getDefault("nz", 1);
+ const double dx = param.getDefault("dx", 1.0);
+ const double dy = param.getDefault("dy", 1.0);
+ const double dz = param.getDefault("dz", 1.0);
+ grid.reset(new GridManager(nx, ny, nz, dx, dy, dz));
+ // Rock and fluid init.
+ props.reset(new IncompPropertiesBasic(param, grid->c_grid()->dimensions, grid->c_grid()->number_of_cells));
+ // Wells init.
+ wells.reset(new Opm::WellsManager());
+ // Gravity.
+ gravity[2] = param.getDefault("gravity", 0.0);
+ // Init state variables (saturation and pressure).
+ initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
+ }
+
+ // Warn if gravity but no density difference.
+ bool use_gravity = (gravity[0] != 0.0 || gravity[1] != 0.0 || gravity[2] != 0.0);
+ if (use_gravity) {
+ if (props->density()[0] == props->density()[1]) {
+ std::cout << "**** Warning: nonzero gravity, but zero density difference." << std::endl;
+ }
+ }
+ const double *grav = use_gravity ? &gravity[0] : 0;
+
+ // Initialising src
+ std::vector porevol;
+ computePorevolume(*grid->c_grid(), props->porosity(), porevol);
+ int num_cells = grid->c_grid()->number_of_cells;
+ std::vector src(num_cells, 0.0);
+ if (use_deck) {
+ // Do nothing, wells will be the driving force, not source terms.
+ } else {
+ const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
+ const double default_injection = use_gravity ? 0.0 : 0.1;
+ const double flow_per_sec = param.getDefault("injected_porevolumes_per_day", default_injection)
+ *tot_porevol_init/unit::day;
+ src[0] = flow_per_sec;
+ src[num_cells - 1] = -flow_per_sec;
+ }
+
+ // Boundary conditions.
+ FlowBCManager bcs;
+ if (param.getDefault("use_pside", false)) {
+ int pside = param.get("pside");
+ double pside_pressure = param.get("pside_pressure");
+ bcs.pressureSide(*grid->c_grid(), FlowBCManager::Side(pside), pside_pressure);
+ }
+
+ // Linear solver.
+ LinearSolverFactory linsolver(param);
+
+ // Pressure solver.
+ Opm::IncompTpfa psolver(*grid->c_grid(), *props, 0, linsolver,
+ 0.0, 0.0, 0,
+ grav, wells->c_wells(), src, bcs.c_bcs());
+
+ // Choice of tof solver.
+ bool use_dg = param.getDefault("use_dg", false);
+ int dg_degree = -1;
+ if (use_dg) {
+ dg_degree = param.getDefault("dg_degree", 0);
+ }
+
+ // Write parameters used for later reference.
+ bool output = param.getDefault("output", true);
+ std::ofstream epoch_os;
+ std::string output_dir;
+ if (output) {
+ output_dir =
+ param.getDefault("output_dir", std::string("output"));
+ boost::filesystem::path fpath(output_dir);
+ try {
+ create_directories(fpath);
+ }
+ catch (...) {
+ THROW("Creating directories failed: " << fpath);
+ }
+ std::string filename = output_dir + "/epoch_timing.param";
+ epoch_os.open(filename.c_str(), std::fstream::trunc | std::fstream::out);
+ // open file to clean it. The file is appended to in SimulatorTwophase
+ filename = output_dir + "/step_timing.param";
+ std::fstream step_os(filename.c_str(), std::fstream::trunc | std::fstream::out);
+ step_os.close();
+ param.writeParam(output_dir + "/simulation.param");
+ }
+
+ // Init wells.
+ Opm::WellState well_state;
+ well_state.init(wells->c_wells(), state);
+
+ // Main solvers.
+ Opm::time::StopWatch pressure_timer;
+ double ptime = 0.0;
+ Opm::time::StopWatch transport_timer;
+ double ttime = 0.0;
+ Opm::time::StopWatch total_timer;
+ total_timer.start();
+ std::cout << "\n\n================ Starting main solvers ===============" << std::endl;
+
+ // Solve pressure.
+ pressure_timer.start();
+ psolver.solve(1.0, state, well_state);
+ pressure_timer.stop();
+ double pt = pressure_timer.secsSinceStart();
+ std::cout << "Pressure solver took: " << pt << " seconds." << std::endl;
+ ptime += pt;
+
+ // Process transport sources (to include bdy terms and well flows).
+ std::vector transport_src;
+ Opm::computeTransportSource(*grid->c_grid(), src, state.faceflux(), 1.0,
+ wells->c_wells(), well_state.perfRates(), transport_src);
+
+ // Solve time-of-flight.
+ std::vector tof;
+ if (use_dg) {
+ bool use_cvi = param.getDefault("use_cvi", false);
+ Opm::TransportModelTracerTofDiscGal tofsolver(*grid->c_grid(), use_cvi);
+ transport_timer.start();
+ tofsolver.solveTof(&state.faceflux()[0], &porevol[0], &transport_src[0], dg_degree, tof);
+ transport_timer.stop();
+ } else {
+ Opm::TransportModelTracerTof tofsolver(*grid->c_grid());
+ transport_timer.start();
+ tofsolver.solveTof(&state.faceflux()[0], &porevol[0], &transport_src[0], tof);
+ transport_timer.stop();
+ }
+ double tt = transport_timer.secsSinceStart();
+ std::cout << "Transport solver took: " << tt << " seconds." << std::endl;
+ ttime += tt;
+ total_timer.stop();
+
+ // Output.
+ if (output) {
+ std::string tof_filename = output_dir + "/tof.txt";
+ std::ofstream tof_stream(tof_filename.c_str());
+ std::copy(tof.begin(), tof.end(), std::ostream_iterator(tof_stream, "\n"));
+ }
+
+ std::cout << "\n\n================ End of simulation ===============\n"
+ << "Total time taken: " << total_timer.secsSinceStart()
+ << "\n Pressure time: " << ptime
+ << "\n Transport time: " << ttime << std::endl;
+}
diff --git a/examples/import_rewrite.cpp b/examples/import_rewrite.cpp
new file mode 100644
index 00000000..edf708e0
--- /dev/null
+++ b/examples/import_rewrite.cpp
@@ -0,0 +1,252 @@
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include
+
+#include
+
+#ifdef HAVE_ERT
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+/*
+ Small utility to read through an ECLIPSE input deck and replace
+ occurences of (large) numerical fields like COORD and ZCORN with
+ IMPORT statements of a binary versions of the relevant keywords. The
+ program will follow INCLUDE statements.
+
+ Usage: import_rewrite eclipse_case.data
+*/
+
+
+/*
+ The numerical keywords in the ECLIPSE datafile like e.g. PORO and
+ COORD are not annoted with type information; however when read and
+ written in binary form they are of type float. If the updated
+ datafile should be used with ECLIPSE these float values must be
+ exported as float; this is achieved by setting the outputFloatType
+ variable to ECL_FLOAT_TYPE.
+
+ In OPM all numerical fields are treated as double, hence if the OPM
+ EclipseParser meets an import of a float keyword it will be
+ converted to double. If the output from this little utility will
+ only be used from OPM the output can be saved as double directly by
+ setting the outputFloatType to ECL_DOUBLE_TYPE.
+*/
+const ecl_type_enum outputFloatType = ECL_DOUBLE_TYPE;
+
+
+/*
+ Only keywords which have more >= minImportSize elements are
+ converted to binary form. This is to avoid convertion short keywords
+ like MAPAXES and TABDIMS.
+*/
+const int minImportSize = 10;
+
+
+using namespace Opm;
+
+
+static void skipKeyword( std::ifstream& is) {
+ std::string keyword;
+ EclipseGridParser::readKeyword( is , keyword );
+ while (true) {
+ std::ios::pos_type pos = is.tellg();
+
+ if (EclipseGridParser::readKeyword( is , keyword )) {
+ is.seekg( pos ); // Repos to start of keyword for next read.
+ break;
+ } else
+ is >> ignoreLine;
+
+ if (!is.good()) {
+ is.clear();
+ is.seekg( 0 , std::ios::end );
+ break;
+ }
+ }
+}
+
+
+static void copyKeyword( std::ifstream& is , std::ofstream& os) {
+ std::ios::pos_type start_pos = is.tellg();
+ skipKeyword( is );
+ {
+ std::ios::pos_type end_pos = is.tellg();
+ long length = end_pos - start_pos;
+
+ {
+ char * buffer = new char[length];
+ {
+ is.seekg( start_pos );
+ is.read( buffer , length );
+ }
+ os.write( buffer , length );
+ delete[] buffer;
+ }
+ }
+}
+
+
+
+static ecl_kw_type * loadFromcstdio( const std::string& filename , std::ios::pos_type& offset , ecl_type_enum ecl_type) {
+ ecl_kw_type * ecl_kw;
+
+ FILE * cstream = util_fopen( filename.c_str() , "r");
+ fseek( cstream , offset , SEEK_SET);
+ ecl_kw = ecl_kw_fscanf_alloc_current_grdecl( cstream , ecl_type );
+ offset = ftell( cstream );
+ fclose( cstream );
+
+ return ecl_kw;
+}
+
+
+
+static bool convertKeyword( const std::string& inputFile , const std::string& outputPath , std::ifstream& is , FieldType fieldType , std::ofstream& os ) {
+ bool convert = true;
+ ecl_type_enum ecl_type;
+
+ if (fieldType == Integer)
+ ecl_type = ECL_INT_TYPE;
+ else
+ ecl_type = outputFloatType;
+
+ {
+ std::ios::pos_type inputPos = is.tellg();
+ ecl_kw_type * ecl_kw = loadFromcstdio( inputFile , inputPos , ecl_type );
+
+ if (ecl_kw_get_size( ecl_kw ) >= minImportSize) {
+ {
+ std::string outputFile = outputPath + "/" + ecl_kw_get_header( ecl_kw );
+ fortio_type * fortio = fortio_open_writer( outputFile.c_str() , false , ECL_ENDIAN_FLIP );
+ ecl_kw_fwrite( ecl_kw , fortio );
+ fortio_fclose( fortio );
+
+ os << "IMPORT" << std::endl << " '" << outputFile << "' /" << std::endl << std::endl;
+ }
+ is.seekg( inputPos );
+ } else {
+ copyKeyword( is , os );
+ convert = false;
+ }
+
+
+ ecl_kw_free( ecl_kw );
+ }
+ return convert;
+}
+
+
+
+
+
+static bool parseFile(const std::string& inputFile, std::string& outputFile, const std::string& indent = "") {
+ bool updateFile = false;
+ std::cout << indent << "Parsing " << inputFile << "\n";
+ {
+ std::ifstream is(inputFile.c_str());
+ if (is) {
+ std::ofstream os;
+ std::string keyword;
+ std::string path;
+ {
+ boost::filesystem::path inputPath(inputFile);
+ path = inputPath.parent_path().string();
+ }
+
+ {
+ std::string basename;
+ std::string extension;
+
+ outputFile = inputFile;
+ size_t ext_pos = inputFile.rfind(".");
+ if (ext_pos == std::string::npos) {
+ basename = outputFile.substr();
+ extension = "";
+ } else {
+ basename = outputFile.substr(0,ext_pos);
+ extension = outputFile.substr(ext_pos);
+ }
+
+ outputFile = basename + "_import" + extension;
+ }
+ os.open( outputFile.c_str() );
+
+ while(is.good()) {
+ is >> ignoreWhitespace;
+ {
+ std::ios::pos_type start_pos = is.tellg();
+ if (EclipseGridParser::readKeyword( is , keyword )) {
+ FieldType fieldType = EclipseGridParser::classifyKeyword( keyword );
+ switch (fieldType) {
+ case(Integer):
+ case(FloatingPoint):
+ {
+ is.seekg( start_pos );
+ if (convertKeyword( inputFile , path , is , fieldType , os )) {
+ std::cout << indent + " " << "Writing binary file: " << path << "/" << keyword << std::endl;
+ updateFile = true;
+ }
+ break;
+ }
+ case(Include):
+ {
+ std::string includeFile = readString(is);
+ if (!path.empty()) {
+ includeFile = path + '/' + includeFile;
+ }
+ {
+ std::string __outputFile;
+ bool updateInclude = parseFile( includeFile , __outputFile , indent + " ");
+ if (updateInclude) {
+ is.seekg( start_pos );
+ skipKeyword( is );
+ os << "INCLUDE" << std::endl << " '" << __outputFile << "' /" << std::endl << std::endl;
+ }
+ updateFile |= updateInclude;
+ }
+ break;
+ }
+ default:
+ {
+ is.seekg( start_pos );
+ copyKeyword( is , os);
+ break;
+ }
+ }
+ } else
+ is >> ignoreLine; // Not at a valid keyword
+ }
+ }
+
+ os.close();
+ is.close();
+ if (updateFile)
+ std::cout << indent << "Written updated include file: " << outputFile << std::endl;
+ else
+ remove( outputFile.c_str() );
+ } else
+ std::cerr << indent << "** WARNING: Failed to open include file: " << inputFile << " for reading **" << std::endl;
+ }
+ return updateFile;
+}
+
+
+
+int
+main(int argc, char** argv)
+{
+ if (argc != 2)
+ THROW("Need the name of ECLIPSE file on command line");
+ {
+ std::string outputFile;
+ parseFile(argv[1] , outputFile);
+ }
+}
diff --git a/examples/sim_2p_comp_reorder.cpp b/examples/sim_2p_comp_reorder.cpp
index 9f2b516b..4ca75be5 100644
--- a/examples/sim_2p_comp_reorder.cpp
+++ b/examples/sim_2p_comp_reorder.cpp
@@ -32,7 +32,6 @@
#include
#include
#include
-#include
#include
#include
@@ -94,7 +93,7 @@ main(int argc, char** argv)
// Grid init
grid.reset(new GridManager(*deck));
// Rock and fluid init
- props.reset(new BlackoilPropertiesFromDeck(*deck, *grid->c_grid()));
+ props.reset(new BlackoilPropertiesFromDeck(*deck, *grid->c_grid(), param));
// check_well_controls = param.getDefault("check_well_controls", false);
// max_well_control_iterations = param.getDefault("max_well_control_iterations", 10);
// Rock compressibility.
diff --git a/examples/sim_wateroil.cpp b/examples/sim_wateroil.cpp
index f7e0172f..0fe1f51c 100644
--- a/examples/sim_wateroil.cpp
+++ b/examples/sim_wateroil.cpp
@@ -175,7 +175,7 @@ main(int argc, char** argv)
// Grid init
grid.reset(new Opm::GridManager(deck));
// Rock and fluid init
- props.reset(new Opm::BlackoilPropertiesFromDeck(deck, *grid->c_grid()));
+ props.reset(new BlackoilPropertiesFromDeck(deck, *grid->c_grid(), param));
// Wells init.
wells.reset(new Opm::WellsManager(deck, *grid->c_grid(), props->permeability()));
check_well_controls = param.getDefault("check_well_controls", false);
@@ -408,7 +408,7 @@ main(int argc, char** argv)
state.saturation(), state.surfacevol());
// Opm::computeInjectedProduced(*props, state.saturation(), reorder_src, stepsize, injected, produced);
if (use_segregation_split) {
- reorder_model.solveGravity(columns, &state.pressure()[0], &initial_porevol[0],
+ reorder_model.solveGravity(columns,
stepsize, state.saturation(), state.surfacevol());
}
}
diff --git a/examples/spu_2p.cpp b/examples/spu_2p.cpp
index 25cd3f6f..755ef202 100644
--- a/examples/spu_2p.cpp
+++ b/examples/spu_2p.cpp
@@ -94,14 +94,19 @@
#include
+#ifdef HAVE_ERT
+#include
+#endif
+
static void outputState(const UnstructuredGrid& grid,
const Opm::TwophaseState& state,
- const int step,
+ const Opm::SimulatorTimer& simtimer,
const std::string& output_dir)
{
// Write data in VTK format.
+ int step = simtimer.currentStepNum();
std::ostringstream vtkfilename;
vtkfilename << output_dir << "/output-" << std::setw(3) << std::setfill('0') << step << ".vtu";
std::ofstream vtkfile(vtkfilename.str().c_str());
@@ -115,6 +120,9 @@ static void outputState(const UnstructuredGrid& grid,
Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
dm["velocity"] = &cell_velocity;
Opm::writeVtkData(grid, dm, vtkfile);
+#ifdef HAVE_ERT
+ Opm::writeECLData(grid , dm , simtimer , output_dir , "OPM" );
+#endif
// Write data (not grid) in Matlab format
for (Opm::DataMap::const_iterator it = dm.begin(); it != dm.end(); ++it) {
@@ -530,7 +538,7 @@ main(int argc, char** argv)
// Report timestep and (optionally) write state to disk.
simtimer.report(std::cout);
if (output && (simtimer.currentStepNum() % output_interval == 0)) {
- outputState(*grid->c_grid(), state, simtimer.currentStepNum(), output_dir);
+ outputState(*grid->c_grid(), state, simtimer , output_dir);
}
// Solve pressure.
@@ -699,7 +707,7 @@ main(int argc, char** argv)
<< "\n Transport time: " << ttime << std::endl;
if (output) {
- outputState(*grid->c_grid(), state, simtimer.currentStepNum(), output_dir);
+ outputState(*grid->c_grid(), state, simtimer, output_dir);
outputWaterCut(watercut, output_dir);
if (wells->c_wells()) {
outputWellReport(wellreport, output_dir);
diff --git a/lib/pkgconfig/opm-core.pc.in b/lib/pkgconfig/opm-core.pc.in
new file mode 100644
index 00000000..2f1d70da
--- /dev/null
+++ b/lib/pkgconfig/opm-core.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@
+Description: @PACKAGE_STRING@
+Version: @PACKAGE_VERSION@
+URL: @PACKAGE_URL@
+Libs: -L${libdir} -l@PACKAGE@
+Cflags: -I${includedir}
diff --git a/m4/ax_blas.m4 b/m4/ax_blas.m4
index e4f96cbe..7e6fd549 100644
--- a/m4/ax_blas.m4
+++ b/m4/ax_blas.m4
@@ -98,6 +98,11 @@ if test "x$BLAS_LIBS" != x; then
fi
fi
+# don't probe if explicitly defined; by bailing out here if the
+# argument is set, we guard against typo, incompatible libs. etc.
+# being inadvertedly overrided by another (random) implementation
+if test "x$with_blas" == x; then
+
# BLAS linked to by default? (happens on some supercomputers)
if test $ax_blas_ok = no; then
save_LIBS="$LIBS"; LIBS="$LIBS"
@@ -186,6 +191,9 @@ if test $ax_blas_ok = no; then
AC_CHECK_LIB(blas, $sgemm, [ax_blas_ok=yes; BLAS_LIBS="-lblas"])
fi
+# end of guard against automatic overriding explicit definitions
+fi
+
AC_SUBST(BLAS_LIBS)
LIBS="$ax_blas_save_LIBS"
diff --git a/m4/ax_lapack.m4 b/m4/ax_lapack.m4
index 6aa16aaf..b642c38c 100644
--- a/m4/ax_lapack.m4
+++ b/m4/ax_lapack.m4
@@ -101,6 +101,11 @@ if test "x$LAPACK_LIBS" != x; then
fi
fi
+# don't probe if explicitly defined; by bailing out here if the
+# argument is set, we guard against typo, incompatible libs. etc.
+# being inadvertedly overrided by another (random) implementation
+if test "x$with_lapack" = x; then
+
# LAPACK linked to by default? (is sometimes included in BLAS lib)
if test $ax_lapack_ok = no; then
save_LIBS="$LIBS"; LIBS="$LIBS $BLAS_LIBS $FLIBS"
@@ -118,6 +123,9 @@ for lapack in lapack lapack_rs6k; do
fi
done
+# end of guard against automatic overriding explicit definitions
+fi
+
AC_SUBST(LAPACK_LIBS)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
diff --git a/m4/cxx0x_compiler.m4 b/m4/cxx0x_compiler.m4
new file mode 100644
index 00000000..47a7e90c
--- /dev/null
+++ b/m4/cxx0x_compiler.m4
@@ -0,0 +1,66 @@
+# whether compiler accepts -std=c++11 or -std=c++0x
+# can be disabled by --disable-gxx0xcheck
+
+AC_DEFUN([GXX0X],[
+ save_CXX="$CXX"
+
+ # put this check first, so we get disable C++11 if C++0x is
+ AC_ARG_ENABLE(gxx0xcheck,
+ AC_HELP_STRING([--disable-gxx0xcheck],
+ [try flag -std=c++0x to enable C++0x features [[default=yes]]]),
+ [gxx0xcheck=$enableval],
+ [gxx0xcheck=yes])
+ AC_ARG_ENABLE(gxx11check,
+ AC_HELP_STRING([--disable-gxx11check],
+ [try flag -std=c++11 to enable C++11 features [[default=yes]]]),
+ [gxx11check=$enableval],
+ [gxx11check=yes])
+
+ # try flag -std=c++11
+ AC_CACHE_CHECK([whether $CXX accepts -std=c++11], dune_cv_gplusplus_accepts_cplusplus11, [
+ AC_REQUIRE([AC_PROG_CXX])
+ if test "x$GXX" = xyes && test "x$gxx11check" = xyes && test "x$gxx0xcheck" = xyes ; then
+ AC_LANG_PUSH([C++])
+ CXX="$CXX -std=c++11"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+ #include
+ #include
+ ],)],
+ [dune_cv_gplusplus_accepts_cplusplus11=yes],
+ [dune_cv_gplusplus_accepts_cplusplus11=no])
+ AC_LANG_POP([C++])
+ else
+ dune_cv_gplusplus_accepts_cplusplus11=disabled
+ fi
+ ])
+ if test "x$dune_cv_gplusplus_accepts_cplusplus11" = "xyes" ; then
+ CXX="$save_CXX -std=c++11"
+ CXXCPP="$CXXCPP -std=c++11"
+ else
+ CXX="$save_CXX"
+
+ # try flag -std=c++0x instead
+ AC_CACHE_CHECK([whether $CXX accepts -std=c++0x], dune_cv_gplusplus_accepts_cplusplus0x, [
+ AC_REQUIRE([AC_PROG_CXX])
+ if test "x$GXX" = xyes && test "x$gxx0xcheck" = xyes; then
+ AC_LANG_PUSH([C++])
+ CXX="$CXX -std=c++0x"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+ #include
+ #include
+ ],)],
+ [dune_cv_gplusplus_accepts_cplusplus0x=yes],
+ [dune_cv_gplusplus_accepts_cplusplus0x=no])
+ AC_LANG_POP([C++])
+ else
+ dune_cv_gplusplus_accepts_cplusplus0x=disabled
+ fi
+ ])
+ if test "x$dune_cv_gplusplus_accepts_cplusplus0x" = "xyes" ; then
+ CXX="$save_CXX -std=c++0x"
+ CXXCPP="$CXXCPP -std=c++0x"
+ else
+ CXX="$save_CXX"
+ fi
+ fi
+])
diff --git a/m4/cxx0x_nullptr.m4 b/m4/cxx0x_nullptr.m4
new file mode 100644
index 00000000..18d44451
--- /dev/null
+++ b/m4/cxx0x_nullptr.m4
@@ -0,0 +1,17 @@
+AC_DEFUN([NULLPTR_CHECK],[
+ AC_CACHE_CHECK([whether nullptr is supported], dune_cv_nullptr_support, [
+ AC_REQUIRE([AC_PROG_CXX])
+ AC_REQUIRE([GXX0X])
+ AC_LANG_PUSH([C++])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
+ char* ch = nullptr;
+ if(ch!=nullptr) { ; }
+ ])],
+ [dune_cv_nullptr_support=yes],
+ [dune_cv_nullptr_support=no])
+ AC_LANG_POP
+ ])
+ if test "x$dune_cv_nullptr_support" = xyes; then
+ AC_DEFINE(HAVE_NULLPTR, 1, [Define to 1 if nullptr is supported])
+ fi
+])
diff --git a/m4/cxx0x_static_assert.m4 b/m4/cxx0x_static_assert.m4
new file mode 100644
index 00000000..b68d155b
--- /dev/null
+++ b/m4/cxx0x_static_assert.m4
@@ -0,0 +1,14 @@
+AC_DEFUN([STATIC_ASSERT_CHECK],[
+ AC_CACHE_CHECK([whether static_assert is supported], dune_cv_static_assert_support, [
+ AC_REQUIRE([AC_PROG_CXX])
+ AC_REQUIRE([GXX0X])
+ AC_LANG_PUSH([C++])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[static_assert(true,"MSG")])],
+ [dune_cv_static_assert_support=yes],
+ [dune_cv_static_assert_support=no])
+ AC_LANG_POP
+ ])
+ if test "x$dune_cv_static_assert_support" = xyes; then
+ AC_DEFINE(HAVE_STATIC_ASSERT, 1, [Define to 1 if static_assert is supported])
+ fi
+])
diff --git a/m4/ert.m4 b/m4/ert.m4
new file mode 100644
index 00000000..b1ea21a6
--- /dev/null
+++ b/m4/ert.m4
@@ -0,0 +1,67 @@
+AC_DEFUN([_ERT_SOURCE_TEXT],
+[
+AC_LANG_PROGRAM(
+[[
+#include
+#include
+]],dnl
+[[
+int sz;
+sz = ecl_util_get_sizeof_ctype(ECL_INT_TYPE);
+]])[]dnl
+])[]dnl
+
+# ----------------------------------------------------------------------
+
+AC_DEFUN([ERT],
+[
+AC_ARG_WITH([ert],
+ [AS_HELP_STRING([--with-ert=], [Use ERT libraries])],
+ [], [with_ert=no])
+
+use_ert=no
+
+AS_IF([test x"${with_ert}" != x"no"],
+[
+ _ert_LDFLAGS_SAVE="${LDFLAGS}"
+ _ert_LIBS_SAVE="${LIBS}"
+ _ert_CPPFLAGS_SAVE="${CPPFLAGS}"
+ _ert_CFLAGS_SAVE="${CFLAGS}"
+
+ ERT_CPPFLAGS=
+ ERT_LDFLAGS=
+ ERT_LIBS="-lecl -lgeometry -lert_util -lpthread -lz -lgomp"
+ AS_IF([test x"${with_ert}" != x"yes"],
+ [ERT_LDFLAGS="-L${with_ert}/lib"
+ ERT_CPPFLAGS="-I${with_ert}/include"], [:])[]dnl
+
+ CFLAGS="-std=gnu99"
+ CPPFLAGS="${ERT_CPPFLAGS} ${CPPFLAGS}"
+ LDFLAGS="${ERT_LDFLAGS} ${LDFLAGS}"
+ LIBS="${ERT_LIBS} ${LIBS}"
+
+ AC_LINK_IFELSE([_ERT_SOURCE_TEXT],
+ [use_ert=yes], [use_ert=no])
+
+ LIBS="${_ert_LIBS_SAVE}"
+ CPPFLAGS="${_ert_CPPFLAGS_SAVE}"
+ LDFLAGS="${_ert_LDFLAGS_SAVE}"
+ CFLAGS="${_ert_CFLAGS_SAVE}"
+
+ AS_IF([test x"${use_ert}" = x"yes"],
+ [AC_SUBST([ERT_CPPFLAGS])
+ AC_SUBST([ERT_LDFLAGS])
+ AC_SUBST([ERT_LIBS])
+ AC_DEFINE([HAVE_ERT], [1],
+ [Are the ERT libraries available for reading and writing ECLIPSE files.])],dnl
+ [:])[]dnl
+], [:])[]dnl
+
+AM_CONDITIONAL([HAVE_ERT], [test x"${use_ert}" != x"no"])
+
+# AC_MSG_ERROR(
+# [**** ERT_CPPFLAGS = ${ERT_CPPFLAGS} ****
+# **** ERT_LDFLAGS = ${ERT_LDFLAGS} ****
+# **** ERT_LIBS = ${ERT_LIBS} ****
+# ])
+])
diff --git a/m4/opm_core.m4 b/m4/opm_core.m4
index efb75c13..a5b24a0c 100644
--- a/m4/opm_core.m4
+++ b/m4/opm_core.m4
@@ -5,6 +5,11 @@ dnl -*- autoconf -*-
AC_DEFUN([OPM_CORE_CHECKS],
[
+# Language features
+GXX0X
+STATIC_ASSERT_CHECK
+NULLPTR_CHECK
+
# Checks for libraries.
# Bring in numerics support (standard library component)
@@ -17,8 +22,8 @@ AX_BOOST_SYSTEM
AX_BOOST_DATE_TIME
AX_BOOST_FILESYSTEM
AX_BOOST_UNIT_TEST_FRAMEWORK
-
AX_DUNE_ISTL
+OPM_PATH_SUPERLU
OPM_AGMG
# Checks for header files.
diff --git a/m4/opm_lapack.m4 b/m4/opm_lapack.m4
index b5fa5ca5..083ecf0b 100644
--- a/m4/opm_lapack.m4
+++ b/m4/opm_lapack.m4
@@ -1,4 +1,7 @@
AC_DEFUN([OPM_LAPACK],
[AC_REQUIRE([AC_F77_WRAPPERS])dnl
AC_REQUIRE([AX_LAPACK])dnl
+ if test x"$ax_lapack_ok" != xyes; then
+ AC_MSG_ERROR([BLAS/LAPACK required, but not found.])
+ fi
])[]dnl
diff --git a/m4/opm_superlu.m4 b/m4/opm_superlu.m4
new file mode 100644
index 00000000..ff4aff8e
--- /dev/null
+++ b/m4/opm_superlu.m4
@@ -0,0 +1,334 @@
+## -*- autoconf -*-
+# $Id: superlu.m4 5908 2010-02-23 16:46:05Z joe $
+# searches for SuperLU headers and libs
+
+# _slu_lib_path(SUPERLU_ROOT, HEADER)
+#
+# Try to find the subpath unter SUPERLU_ROOT containing HEADER. Try
+# SUPERLU_ROOT/"include/superlu", SUPERLU_ROOT/"include", and
+# SUPERLU_ROOT/"SRC", in that order. Set the subpath for the library to
+# "lib". If HEADER was found in SUPERLU_ROOT/"SRC", check whether
+# SUPERLU_ROOT/"lib" is a directory, and set the subpath for the library to
+# the empty string "" if it isn't.
+#
+# Shell variables:
+# my_include_path
+# The subpath HEADER was found in: "include/superlu", "include", or
+# "SRC". Contents is only meaningful for my_slu_found=yes.
+# my_lib_path
+# The subpath for the library: "lib" or "". Contents is only meaningful
+# for my_slu_found=yes.
+# my_slu_found
+# Whether HEADER was found at all. Either "yes" or "no".
+AC_DEFUN([_slu_lib_path],
+ [
+ my_include_path=include/superlu
+ my_lib_path=lib
+ my_slu_found=yes
+ if test ! -f "$1/$my_include_path/$2" ; then
+ #Try to find headers under superlu
+ my_include_path=include
+ if test ! -f "$1/$my_include_path/$2" ; then
+ my_include_path=SRC
+ if test ! -f "$1/$my_include_path/$2"; then
+ my_slu_found=no
+ else
+ if ! test -d "$1/$my_lib_path"; then
+ my_lib_path=""
+ fi
+ fi
+ fi
+ fi
+ ]
+)
+
+# _slu_search_versions(SUPERLU_ROOT)
+#
+# Search for either "slu_ddefs.h" or "dsp_defs.h" using _slu_lib_path().
+#
+# Shell variables:
+# my_slu_header
+# The name of the header that was found: first of "slu_ddefs.h" or
+# "dsp_defs.h". Contents is only meaningful for my_slu_found=yes.
+# my_include_path
+# The subpath the header was found in: "include/superlu", "include", or
+# "SRC". Contents is only meaningful for my_slu_found=yes.
+# my_lib_path
+# The subpath for the library: "lib" or "". Contents is only meaningful
+# for my_slu_found=yes.
+# my_slu_found
+# Whether any of the headers. Either "yes" or "no".
+AC_DEFUN([_slu_search_versions],
+ [
+ my_slu_header=slu_ddefs.h
+ _slu_lib_path($1, $my_slu_header)
+ if test "$my_slu_found" != "yes"; then
+ my_slu_header="dsp_defs.h"
+ _slu_lib_path($1, $my_slu_header)
+ fi
+ ]
+)
+
+
+# _slu_search_default()
+#
+# Search for SuperLU in the default locations "/usr" and "/usr/local".
+#
+# Shell variables:
+# with_superlu
+# Root of the SuperLU installation: first of "/usr" and "/usr/local".
+# Contents is only meaningful for my_slu_found=yes.
+# For other output variables see documentation of _slu_search_versions().
+AC_DEFUN([_slu_search_default],
+ [
+ with_superlu=/usr
+ _slu_search_versions($with_superlu)
+
+ if test "$my_slu_found" = "no"; then
+ with_superlu=/usr/local
+ _slu_search_versions($with_superlu)
+ fi
+ ]
+)
+
+
+# OPM_PATH_SUPERLU()
+#
+# REQUIRES: AC_PROG_CC, AX_BLAS
+#
+# Shell variables:
+# with_superlu
+# "no", "yes (version 4.3 or newer)", "yes (version 4.2 or older, post 2005)" or "yes (pre 2005)"
+# direct_SUPERLU_CPPFLAGS
+# direct_SUPERLU_LIBS
+# CPPFLAGS and LIBS necessary to link against SuperLU. This variable
+# contains no indirect references and is suitable for use inside
+# configure. Guaranteed empty if SuperLU was not found.
+# SUPERLU_CPPFLAGS
+# SUPERLU_LIBS
+# CPPFLAGS and LIBS necessary to link against SuperLU. This variable may
+# contain indirect references and is suitable for use inside makefiles.
+# Guaranteed empty if SuperLU was not found.
+# HAVE_SUPERLU
+# "0" or "1" depending on whether SuperLU was found.
+#
+# Substitutions:
+# SUPERLU_LIBS
+# SUPERLU_CPPFLAGS
+# Substitutes the values of the corresponding shell variables.
+# ALL_PKG_LIBS
+# ALL_PKG_CPPFLAGS
+# Adds references to SuperLU's substitutions.
+#
+# Defines:
+# HAVE_SUPERLU
+# ENABLE_SUPERLU or undefined. Whether SuperLU was found. The correct
+# way to check this is "#if HAVE_SUPERLU": This way SuperLU features will
+# be disabled unless $(SUPERLU_CPPFLAGS) was given when compiling.
+# SUPERLU_POST_2005_VERSION
+# 1 or undefined. A post-2005 version of SuperLU uses the header
+# "slu_ddefs.h" while earlier versions use "dsp_defs.h".
+# SUPERLU_MIN_VERSION_4_3
+# 1 or undefined. SuperLU version 4.3 or newer uses the symbol
+# "SLU_DOUBLE" while earlier versions use "DOUBLE".
+# HAVE_MEM_USAGE_T_EXPANSIONS
+# 1 or undefined. Whether "mem_usage_t.expansions" was found in
+# "slu_ddefs.h" or "dsp_defs.h" as apropriate.
+#
+# Conditionals:
+# SUPERLU
+AC_DEFUN([OPM_PATH_SUPERLU],[
+ AC_REQUIRE([AC_PROG_CC])
+ # we need this for FLIBS
+ AC_REQUIRE([AC_F77_LIBRARY_LDFLAGS])
+ AC_REQUIRE([AX_BLAS])
+
+ #
+ # User hints ...
+ #
+ my_lib_path=""
+ my_include_path=""
+ AC_ARG_WITH([superlu],
+ [AC_HELP_STRING([--with-superlu],[user defined path to SuperLU library])],
+ [dnl
+ if test x"$withval" != xno ; then
+ # get absolute path
+ with_superlu=`eval cd $withval > /dev/null 2>&1 && pwd`
+ if test x"$withval" = xyes; then
+ # Search in default locations
+ _slu_search_default
+ else
+ # Search for the headers in the specified location
+ _slu_search_versions(["$with_superlu"])
+ fi
+ fi
+ ], [dnl
+ # Search in default locations
+ _slu_search_default
+ ])
+
+ AC_ARG_WITH([superlu-lib],
+ [AC_HELP_STRING([--with-superlu-lib],
+ [The name of the static SuperLU library to link to. By default
+ the static library with the name superlu.a is tried, but
+ only if shared linking has failed first. Giving this
+ options forces static linking for SuperLU.])],
+ [
+ if test x"$withval" = xno ; then
+ with_superlu_lib=
+ fi
+ ])
+
+ AC_ARG_WITH([superlu-blaslib],
+ [AC_HELP_STRING([--with-superlu-blaslib],
+ [The name of the static blas library to link to. By default
+ we try to link to the systems blas library (see
+ --with-blas). Giving this options forces static linking
+ for SuperLU.])],
+ [
+ if test "$withval" = no ; then
+ with_superlu_blaslib=
+ fi
+ ])
+
+ # store old values
+ ac_save_LDFLAGS="$LDFLAGS"
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ ac_save_LIBS="$LIBS"
+
+ # do nothing if --without-superlu is used
+ if test x"$with_superlu" != x"no" ; then
+ # defaultpath
+ SUPERLU_LIB_PATH="$with_superlu/$my_lib_path"
+ SUPERLU_INCLUDE_PATH="$with_superlu/$my_include_path"
+
+ # set variables so that tests can use them
+ direct_SUPERLU_CPPFLAGS="-I$SUPERLU_INCLUDE_PATH -DENABLE_SUPERLU"
+ SUPERLU_CPPFLAGS="-I$SUPERLU_INCLUDE_PATH -DENABLE_SUPERLU"
+ CPPFLAGS="$CPPFLAGS $direct_SUPERLU_CPPFLAGS"
+
+ # check for central header
+ AC_CHECK_HEADER([$my_slu_header],
+ [HAVE_SUPERLU="1"],
+ [
+ HAVE_SUPERLU="0"
+ AC_MSG_WARN([$my_slu_header not found in $SUPERLU_INCLUDE_PATH with $CPPFLAGS])
+ ])
+
+ # if header is found check for the libs
+ if test x$HAVE_SUPERLU = x1 ; then
+ HAVE_SUPERLU=0
+
+ # if neither --with-superlu-lib nor --with-superlu-blaslib was
+ # given, try to link dynamically or with properly names static libs
+ if test x"$with_superlu_lib$with_superlu_blaslib" = x; then
+ LDFLAGS="$ac_save_LDFLAGS -L$SUPERLU_LIB_PATH"
+ LIBS="$ac_save_LIBS"
+ AC_CHECK_LIB([superlu], [dgssvx],
+ [
+ direct_SUPERLU_LIBS="-L$SUPERLU_LIB_PATH -lsuperlu $BLAS_LIBS $FLIBS"
+ SUPERLU_LIBS="-L$SUPERLU_LIB_PATH -lsuperlu \${BLAS_LIBS} \${FLIBS}"
+ HAVE_SUPERLU="1"
+ ], [], [$BLAS_LIBS $FLIBS])
+ fi
+
+ if test $HAVE_SUPERLU = 0 && test x"$with_superlu_lib" = x; then
+ # set the default
+ with_superlu_lib=superlu.a
+ fi
+
+ if test $HAVE_SUPERLU = 0 &&
+ test x"$with_superlu_blaslib" = x; then
+ # try system blas
+ LDFLAGS="$ac_save_LDFLAGS"
+ LIBS="$SUPERLU_LIB_PATH/$with_superlu_lib $BLAS_LIBS $FLIBS $ac_save_LIBS"
+ AC_CHECK_FUNC([dgssvx],
+ [
+ direct_SUPERLU_LIBS="$SUPERLU_LIB_PATH/$with_superlu_lib $BLAS_LIBS $FLIBS"
+ SUPERLU_LIBS="$SUPERLU_LIB_PATH/$with_superlu_lib \${BLAS_LIBS} \${FLIBS}"
+ HAVE_SUPERLU="1"
+ ])
+ fi
+
+ # No default for with_superlu_blaslib
+
+ if test $HAVE_SUPERLU = 0 &&
+ test x"$with_superlu_blaslib" != x; then
+ # try internal blas
+ LDFLAGS="$ac_save_LDFLAGS"
+ LIBS="$SUPERLU_LIB_PATH/$with_superlu_lib $SUPERLU_LIB_PATH/$with_superlu_blaslib $FLIBS $ac_save_LIBS"
+ AC_CHECK_FUNC([dgssvx],
+ [
+ direct_SUPERLU_LIBS="$SUPERLU_LIB_PATH/$with_superlu_lib $SUPERLU_LIB_PATH/$with_superlu_blaslib $FLIBS"
+ SUPERLU_LIBS="$SUPERLU_LIB_PATH/$with_superlu_lib $SUPERLU_LIB_PATH/$with_superlu_blaslib \${FLIBS}"
+ HAVE_SUPERLU="1"
+ ])
+ fi
+
+ # test whether SuperLU version is at least 4.3
+ if test $HAVE_SUPERLU = "1" ; then
+ AC_CHECK_DECL([SLU_DOUBLE], [SUPERLU_MIN_VERSION_4_3="1"], [], [#include <$my_slu_header>])
+ fi
+ fi
+
+ else # $with_superlu = no
+ HAVE_SUPERLU=0
+ fi
+
+ # Inform the user whether SuperLU was sucessfully found
+ AC_MSG_CHECKING([SuperLU])
+ if test x$HAVE_SUPERLU = x1 ; then
+ if test "$my_slu_header" = "slu_ddefs.h"; then
+ if test x$SUPERLU_MIN_VERSION_4_3 = x1 ; then
+ with_superlu="yes (version 4.3 or newer)"
+ else
+ with_superlu="yes (version 4.2 or older, post 2005)"
+ fi
+ else
+ with_superlu="yes (pre 2005)"
+ fi
+ else
+ with_superlu="no"
+ fi
+ AC_MSG_RESULT([$with_superlu])
+
+ # check for optional member
+ if test $HAVE_SUPERLU = 1 ; then
+ if test "$my_slu_header" = "slu_ddefs.h"; then
+ AC_CHECK_MEMBERS([mem_usage_t.expansions],[],[],[#include "slu_ddefs.h"])
+ else
+ AC_CHECK_MEMBERS([mem_usage_t.expansions],[],[],[#include "dsp_defs.h"])
+ fi
+ fi
+
+ # substitute variables
+ if test x$HAVE_SUPERLU = x0 ; then
+ SUPERLU_LIBS=
+ SUPERLU_CPPFLAGS=
+ fi
+ AC_SUBST([SUPERLU_LIBS])
+ AC_SUBST([SUPERLU_CPPFLAGS])
+ #DUNE_ADD_ALL_PKG([SUPERLU], [\$(SUPERLU_CPPFLAGS)], [], [\$(SUPERLU_LIBS)])
+
+ # tell automake
+ AM_CONDITIONAL(SUPERLU, test x$HAVE_SUPERLU = x1)
+
+ # tell the preprocessor
+ if test x$HAVE_SUPERLU = x1 ; then
+ AC_DEFINE([HAVE_SUPERLU], [ENABLE_SUPERLU], [Define to ENABLE_SUPERLU if SUPERLU is found])
+ if test "$my_slu_header" = "slu_ddefs.h"; then
+ AC_DEFINE([SUPERLU_POST_2005_VERSION], 1, [define to 1 if there is a header slu_ddefs.h in SuperLU])
+ if test x$SUPERLU_MIN_VERSION_4_3 = x1 ; then
+ AC_DEFINE([SUPERLU_MIN_VERSION_4_3], 1, [define to 1 if there SLU_DOUBLE imported by header slu_ddefs.h from SuperLU])
+ fi
+ fi
+ fi
+
+ # summary
+ #DUNE_ADD_SUMMARY_ENTRY([SuperLU],[$with_superlu])
+
+ # restore variables
+ LDFLAGS="$ac_save_LDFLAGS"
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBS="$ac_save_LIBS"
+])
diff --git a/opm-core.pc.in b/opm-core.pc.in
new file mode 100644
index 00000000..1dd258f7
--- /dev/null
+++ b/opm-core.pc.in
@@ -0,0 +1,18 @@
+# This is the configuration for local builds. Use this by putting the
+# compilation output path (the directory in which you ran ./configure)
+# into the environment variable PKG_CONFIG_PATH. This will enable you
+# to use pkg-config in your code while making changes to opm-core.
+
+# This is NOT the file that is installed in the system directories when
+# you do `make install`. That is the one in lib/pkgconfig. However, if
+# you make changes here, you should consider that one as well.
+
+libdir=@abs_top_builddir@/lib/.libs
+includedir=@abs_top_srcdir@
+
+Name: @PACKAGE_NAME@
+Description: @PACKAGE_STRING@
+Version: @PACKAGE_VERSION@
+URL: @PACKAGE_URL@
+Libs: -L${libdir} -l@PACKAGE@
+Cflags: -I${includedir}
diff --git a/opm/core/GridManager.cpp b/opm/core/GridManager.cpp
index 04d8cd04..d286e504 100644
--- a/opm/core/GridManager.cpp
+++ b/opm/core/GridManager.cpp
@@ -37,7 +37,8 @@ namespace Opm
{
// We accept two different ways to specify the grid.
// 1. Corner point format.
- // Requires ZCORN, COORDS, DIMENS or SPECGRID, optionally ACTNUM.
+ // Requires ZCORN, COORDS, DIMENS or SPECGRID, optionally
+ // ACTNUM, optionally MAPAXES.
// For this format, we will verify that DXV, DYV, DZV,
// DEPTHZ and TOPS are not present.
// 2. Tensor grid format.
@@ -119,29 +120,8 @@ namespace Opm
void GridManager::initFromDeckCornerpoint(const Opm::EclipseGridParser& deck)
{
// Extract data from deck.
- const std::vector& zcorn = deck.getFloatingPointValue("ZCORN");
- const std::vector& coord = deck.getFloatingPointValue("COORD");
- const int* actnum = 0;
- if (deck.hasField("ACTNUM")) {
- actnum = &(deck.getIntegerValue("ACTNUM")[0]);
- }
- std::vector dims;
- if (deck.hasField("DIMENS")) {
- dims = deck.getIntegerValue("DIMENS");
- } else if (deck.hasField("SPECGRID")) {
- dims = deck.getSPECGRID().dimensions;
- } else {
- THROW("Deck must have either DIMENS or SPECGRID.");
- }
-
// Collect in input struct for preprocessing.
- struct grdecl grdecl;
- grdecl.zcorn = &zcorn[0];
- grdecl.coord = &coord[0];
- grdecl.actnum = actnum;
- grdecl.dims[0] = dims[0];
- grdecl.dims[1] = dims[1];
- grdecl.dims[2] = dims[2];
+ struct grdecl grdecl = deck.get_grdecl();
// Process grid.
ug_ = create_grid_cornerpoint(&grdecl, 0.0);
diff --git a/opm/core/eclipse/EclipseGridParser.cpp b/opm/core/eclipse/EclipseGridParser.cpp
index b4ea9ee3..5af1e2ec 100644
--- a/opm/core/eclipse/EclipseGridParser.cpp
+++ b/opm/core/eclipse/EclipseGridParser.cpp
@@ -47,8 +47,19 @@
#include
#include
#include
-#include
#include
+#include
+#include
+
+#ifdef HAVE_ERT
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
using namespace std;
@@ -86,7 +97,7 @@ namespace EclipseKeywords
string("MULTPV"), string("PRESSURE"), string("SGAS"),
string("SWAT"), string("SOIL"), string("RS"),
string("DXV"), string("DYV"), string("DZV"),
- string("DEPTHZ"), string("TOPS")
+ string("DEPTHZ"), string("TOPS"), string("MAPAXES")
};
const int num_floating_fields = sizeof(floating_fields) / sizeof(floating_fields[0]);
@@ -114,7 +125,7 @@ namespace EclipseKeywords
const int num_special_fields = sizeof(special_fields) / sizeof(special_fields[0]);
string ignore_with_data[] =
- { string("MAPUNITS"), string("MAPAXES"), string("GRIDUNIT"),
+ { string("MAPUNITS"), string("GRIDUNIT"),
string("NTG"), string("REGDIMS"), string("WELLDIMS"),
string("NSTACK"), string("SATNUM"),
string("RPTRST"), string("ROIP"), string("RWIP"),
@@ -141,44 +152,14 @@ namespace EclipseKeywords
string include_keywords[] = { string("INCLUDE") };
const int num_include_keywords = sizeof(include_keywords) / sizeof(include_keywords[0]);
+ string import_keywords[] = { string("IMPORT") };
+ const int num_import_keywords = sizeof(import_keywords) / sizeof(import_keywords[0]);
+
} // namespace EclipseKeywords
namespace {
- enum FieldType {
- Integer,
- FloatingPoint,
- Timestepping,
- SpecialField,
- IgnoreWithData,
- IgnoreNoData,
- Include,
- Unknown
- };
-
- inline FieldType classifyKeyword(const string& keyword)
- {
- using namespace EclipseKeywords;
- if (count(integer_fields, integer_fields + num_integer_fields, keyword)) {
- return Integer;
- } else if (count(floating_fields, floating_fields + num_floating_fields, keyword)) {
- return FloatingPoint;
- } else if (keyword == "TSTEP" || keyword == "DATES") {
- return Timestepping;
- } else if (count(special_fields, special_fields + num_special_fields, keyword)) {
- return SpecialField;
- } else if (count(ignore_with_data, ignore_with_data + num_ignore_with_data, keyword)) {
- return IgnoreWithData;
- } else if (count(ignore_no_data, ignore_no_data + num_ignore_no_data, keyword)) {
- return IgnoreNoData;
- } else if (count(include_keywords, include_keywords + num_include_keywords, keyword)) {
- return Include;
- } else {
- return Unknown;
- }
- }
-
inline std::string upcase(const std::string& s)
{
std::string us(s);
@@ -191,71 +172,7 @@ namespace {
return us;
}
- inline bool readKeyword(std::istream& is, std::string& keyword)
- {
- char buf[9];
- int i, j;
- char c;
- /* Clear buf */
- for (i=0; i<9; ++i) {
- buf[i] = '\0';
- }
-
- /* Read first character and check if it is uppercase*/
- //buf[0] = fgetc(fp);
- is.get(buf[0]);
- if ( !isupper( buf[0] ) ) {
- is.unget();
- return false; /* NOT VALID CHARACTER */
- }
-
- /* Scan as much as possible possible keyword, 8 characters long */
- i = 1;
- is.get(c);
- while ( (is.good()) &&
- (c != EOF ) &&
- (!isblank(c) ) &&
- (isupper(c) || isdigit(c)) &&
- (c != '\n' ) &&
- (c != '/' ) &&
- (i < 8 )) {
- buf[i++] = c;
- is.get(c);
- }
-
- /* Skip rest of line */
- if (c != '\n'){
- is.get(c);
- while ( (is.good()) &&
- (c != EOF ) &&
- (c != '\n' )) {
- is.get(c);
- }
- }
- if(c == '\n') {
- is.unget();
- }
-
- /* Find first non-uppercase or non-digit character */
- for (i=0; i<8; ++i) {
- if ( !(isupper(buf[i]) || isdigit(buf[i])) ) {
- break;
- }
- }
-
- /* Check if remaining characters are blank */
- for (j = i; j<8; ++j) {
- if(!isspace(buf[j]) && buf[j] != '\0') {
- return false; /* CHARACTER AFTER SPACE OR INVALID CHARACTER */
- }
- buf[j] = '\0';
- }
- keyword = std::string(buf);
- std::string::size_type end = keyword.find_last_of('\0');
- if(end != keyword.npos)
- keyword = keyword.substr(0, end+1);
- return true;
- }
+
} // anon namespace
@@ -298,6 +215,98 @@ EclipseGridParser::EclipseGridParser(const string& filename, bool convert_to_SI)
}
+ FieldType EclipseGridParser::classifyKeyword(const string& keyword)
+ {
+ using namespace EclipseKeywords;
+ if (count(integer_fields, integer_fields + num_integer_fields, keyword)) {
+ return Integer;
+ } else if (count(floating_fields, floating_fields + num_floating_fields, keyword)) {
+ return FloatingPoint;
+ } else if (keyword == "TSTEP" || keyword == "DATES") {
+ return Timestepping;
+ } else if (count(special_fields, special_fields + num_special_fields, keyword)) {
+ return SpecialField;
+ } else if (count(ignore_with_data, ignore_with_data + num_ignore_with_data, keyword)) {
+ return IgnoreWithData;
+ } else if (count(ignore_no_data, ignore_no_data + num_ignore_no_data, keyword)) {
+ return IgnoreNoData;
+ } else if (count(include_keywords, include_keywords + num_include_keywords, keyword)) {
+ return Include;
+ } else if (count(import_keywords, import_keywords + num_import_keywords, keyword)) {
+ return Import;
+ } else {
+ return Unknown;
+ }
+ }
+
+
+bool EclipseGridParser::readKeyword(std::istream& is, std::string& keyword)
+{
+ char buf[9];
+ int i, j;
+ char c;
+ /* Clear buf */
+ for (i=0; i<9; ++i) {
+ buf[i] = '\0';
+ }
+
+ /* Read first character and check if it is uppercase*/
+ //buf[0] = fgetc(fp);
+ is.get(buf[0]);
+ if ( !isupper( buf[0] ) ) {
+ is.unget();
+ return false; /* NOT VALID CHARACTER */
+ }
+
+ /* Scan as much as possible possible keyword, 8 characters long */
+ i = 1;
+ is.get(c);
+ while ( (is.good()) &&
+ (c != EOF ) &&
+ (!isblank(c) ) &&
+ (isupper(c) || isdigit(c)) &&
+ (c != '\n' ) &&
+ (c != '/' ) &&
+ (i < 8 )) {
+ buf[i++] = c;
+ is.get(c);
+ }
+
+ /* Skip rest of line */
+ if (c != '\n'){
+ is.get(c);
+ while ( (is.good()) &&
+ (c != EOF ) &&
+ (c != '\n' )) {
+ is.get(c);
+ }
+ }
+ if(c == '\n') {
+ is.unget();
+ }
+
+ /* Find first non-uppercase or non-digit character */
+ for (i=0; i<8; ++i) {
+ if ( !(isupper(buf[i]) || isdigit(buf[i])) ) {
+ break;
+ }
+ }
+
+ /* Check if remaining characters are blank */
+ for (j = i; j<8; ++j) {
+ if(!isspace(buf[j]) && buf[j] != '\0') {
+ return false; /* CHARACTER AFTER SPACE OR INVALID CHARACTER */
+ }
+ buf[j] = '\0';
+ }
+ keyword = std::string(buf);
+ std::string::size_type end = keyword.find_last_of('\0');
+ if(end != keyword.npos)
+ keyword = keyword.substr(0, end+1);
+ return true;
+}
+
+
/// Read the given stream, overwriting any previous data.
//---------------------------------------------------------------------------
void EclipseGridParser::read(istream& is, bool convert_to_SI)
@@ -488,6 +497,14 @@ void EclipseGridParser::readImpl(istream& is)
// is >> ignoreSlashLine;
break;
}
+ case Import: {
+ string import_filename = readString(is);
+ if (!directory_.empty()) {
+ import_filename = directory_ + '/' + import_filename;
+ }
+ getNumericErtFields(import_filename);
+ break;
+ }
case Unknown:
default:
ignored_fields_.insert(keyword);
@@ -542,6 +559,9 @@ void EclipseGridParser::convertToSI()
do_convert = false; // Dimensionless keywords...
} else if (key == "PRESSURE") {
unit = units_.pressure;
+ } else if (key == "MAPAXES") {
+ MESSAGE("Not applying units to MAPAXES yet!");
+ unit = 1.0;
} else {
THROW("Units for field " << key << " not specified. Cannon convert to SI.");
}
@@ -800,5 +820,311 @@ void EclipseGridParser::computeUnits()
THROW("Unknown unit family " << unit_family);
}
}
+
+
+struct grdecl EclipseGridParser::get_grdecl() const {
+ struct grdecl grdecl;
+
+ // Extract data from deck.
+ const std::vector& zcorn = getFloatingPointValue("ZCORN");
+ const std::vector& coord = getFloatingPointValue("COORD");
+ const int* actnum = NULL;
+ if (hasField("ACTNUM")) {
+ actnum = &(getIntegerValue("ACTNUM")[0]);
+ }
+
+ std::vector dims;
+ if (hasField("DIMENS")) {
+ dims = getIntegerValue("DIMENS");
+ } else if (hasField("SPECGRID")) {
+ dims = getSPECGRID().dimensions;
+ } else {
+ THROW("Deck must have either DIMENS or SPECGRID.");
+ }
+
+ // Collect in input struct for preprocessing.
+
+ grdecl.zcorn = &zcorn[0];
+ grdecl.coord = &coord[0];
+ grdecl.actnum = actnum;
+ grdecl.dims[0] = dims[0];
+ grdecl.dims[1] = dims[1];
+ grdecl.dims[2] = dims[2];
+
+ if (hasField("MAPAXES")) {
+ const std::vector &mapaxes = getFloatingPointValue("MAPAXES");
+ grdecl.mapaxes = &mapaxes[0];
+ } else
+ grdecl.mapaxes = NULL;
+
+
+ return grdecl;
+}
+
+
+#ifdef HAVE_ERT
+/*
+ This function will create a ecl_kw instance filled with the data
+ from input argument @keyword. The ecl_kw will get it's own copy of
+ the data.
+
+ If the input type ecl_type == ECL_INT_TYPE the function will use the
+ getIntegerValue() method to get the keyword data, if ecl_type ==
+ ECL_DOUBLE_TYPE || ECL_FLOAT_TYPE the getFloatingPointValue()
+ function is invoked. If ecl_type == ECL_FLOAT_TYPE the data will be
+ converted to when inserting into the ecl_kw.
+
+ When the ecl_kw instance is no longer needed it should be discarded
+ with a call to ecl_kw_free( ).
+
+ If you are asking for a non-existent field the function will return NULL
+*/
+
+ecl_kw_type * EclipseGridParser::newEclKW(const std::string &keyword , ecl_type_enum ecl_type) const {
+ ecl_kw_type * ecl_kw = NULL;
+ if (hasField(keyword)) {
+ if (ecl_type == ECL_INT_TYPE) {
+ std::vector data = getIntegerValue( keyword );
+ ecl_kw = ecl_kw_alloc( keyword.c_str() , data.size() , ecl_type );
+ ecl_kw_set_memcpy_data( ecl_kw , &data[0]);
+ } else {
+ std::vector data = getFloatingPointValue( keyword );
+ if (ecl_type == ECL_DOUBLE_TYPE) {
+ ecl_kw = ecl_kw_alloc( keyword.c_str() , data.size() , ecl_type );
+ ecl_kw_set_memcpy_data( ecl_kw , &data[0]);
+ } else if (ecl_type == ECL_FLOAT_TYPE) {
+ ecl_kw = ecl_kw_alloc( keyword.c_str() , data.size() , ecl_type );
+ for (std::vector::size_type i=0; i < data.size(); i++)
+ ecl_kw_iset_float( ecl_kw , i , data[i] );
+ }
+ }
+ }
+ return ecl_kw;
+}
+
+
+/**
+ This function will extract the COORD, ZCORN, ACTNUM and optionaly
+ MAPAXES keywords from the eclipse deck and create an ecl_grid
+ instance.
+
+ When you are finished working with the ecl_grid instance it should
+ be disposed with ecl_grid_free( ).
+*/
+
+ecl_grid_type * EclipseGridParser::newGrid( ) {
+ struct grdecl grdecl = get_grdecl();
+ ecl_kw_type * coord_kw = newEclKW( COORD_KW , ECL_FLOAT_TYPE );
+ ecl_kw_type * zcorn_kw = newEclKW( ZCORN_KW , ECL_FLOAT_TYPE );
+ ecl_kw_type * actnum_kw = newEclKW( ACTNUM_KW , ECL_INT_TYPE );
+ ecl_kw_type * mapaxes_kw = NULL;
+
+ ecl_grid_type * grid ;
+ if (grdecl.mapaxes != NULL)
+ mapaxes_kw = newEclKW( MAPAXES_KW , ECL_FLOAT_TYPE );
+
+ grid = ecl_grid_alloc_GRDECL_kw( grdecl.dims[0] , grdecl.dims[1] , grdecl.dims[2] , zcorn_kw , coord_kw , actnum_kw , mapaxes_kw );
+
+ ecl_kw_free( coord_kw );
+ ecl_kw_free( zcorn_kw );
+ ecl_kw_free( actnum_kw );
+ if (mapaxes_kw != NULL)
+ ecl_kw_free( mapaxes_kw );
+
+ return grid;
+}
+
+
+
+/**
+ This function will save an EGRID file based on the COORD, ZCORN,
+ ACTNUM and optionally MAPAXES keywords included in the deck.
+
+ This function creates the EGRID file without going through a
+ ecl_grid instance; this is obviously somewhat faster and less
+ memory demanding. Alternatively you can create a ecl_grid instance
+ and then subsequently store that grid as an EGRID file:
+
+ {
+ ecl_grid_type * grid = newGRID( );
+ ecl_grid_fwrite_EGRID( grid , filename );
+ ecl_grid_free( grid );
+ }
+*/
+
+void EclipseGridParser::saveEGRID( const std::string & filename) {
+ bool endian_flip = true;//ECL_ENDIAN_FLIP;
+ bool fmt_file = ecl_util_fmt_file( filename.c_str() );
+ struct grdecl grdecl = get_grdecl();
+ fortio_type * fortio = fortio_open_writer( filename.c_str() , fmt_file , endian_flip );
+ {
+ float * mapaxes = NULL;
+ if (grdecl.mapaxes != NULL) {
+ mapaxes = new float[6];
+ for (int i=0; i < 6; i++)
+ mapaxes[i]= grdecl.mapaxes[i];
+ }
+
+ ecl_grid_fwrite_EGRID_header( grdecl.dims , mapaxes , fortio );
+
+ if (grdecl.mapaxes != NULL)
+ delete[] mapaxes;
+ }
+ {
+ ecl_kw_type * coord_kw = newEclKW( COORD_KW , ECL_FLOAT_TYPE );
+ ecl_kw_type * zcorn_kw = newEclKW( ZCORN_KW , ECL_FLOAT_TYPE );
+ ecl_kw_type * actnum_kw = newEclKW( ACTNUM_KW , ECL_INT_TYPE );
+ ecl_kw_type * endgrid_kw = ecl_kw_alloc( ENDGRID_KW , 0 , ECL_INT_TYPE );
+
+ ecl_kw_fwrite( coord_kw , fortio );
+ ecl_kw_fwrite( zcorn_kw , fortio );
+ ecl_kw_fwrite( actnum_kw , fortio );
+ ecl_kw_fwrite( endgrid_kw , fortio );
+
+ ecl_kw_free( coord_kw );
+ ecl_kw_free( zcorn_kw );
+ ecl_kw_free( actnum_kw );
+ ecl_kw_free( endgrid_kw );
+ }
+ fortio_fclose( fortio );
+}
+
+/**
+ Will query the deck for keyword @kw; and save it to the @fortio
+ instance if the keyword can be found.
+*/
+void EclipseGridParser::save_kw( fortio_type * fortio , const std::string & kw , ecl_type_enum ecl_type) {
+ ecl_kw_type * ecl_kw = newEclKW( kw , ecl_type );
+ if (ecl_kw != NULL) {
+ ecl_kw_fwrite( ecl_kw , fortio );
+ ecl_kw_free( ecl_kw );
+ }
+}
+
+
+/**
+ Will save an ECLIPSE INIT file to @filename. Observe that the main
+ focus of this function is to store grid properties like PERMX and
+ PORO, various tabular properties like e.g. relperm tables and
+ thermodynamic properties are ignored.
+*/
+
+void EclipseGridParser::saveINIT( const std::string & filename , const ecl_grid_type * ecl_grid) {
+ int phases = ECL_OIL_PHASE + ECL_WATER_PHASE;
+ bool fmt_file = ecl_util_fmt_file( filename.c_str() );
+ bool endian_flip = true;//ECL_ENDIAN_FLIP;
+ fortio_type * fortio = fortio_open_writer( filename.c_str() , fmt_file , endian_flip );
+ {
+ ecl_kw_type * poro_kw = newEclKW( PORO_KW , ECL_FLOAT_TYPE );
+ time_t start_date;
+
+ {
+ tm td_tm = to_tm( start_date_ );
+ start_date = mktime( &td_tm );
+ }
+
+ ecl_init_file_fwrite_header( fortio , ecl_grid , poro_kw , phases , start_date );
+ ecl_kw_free( poro_kw );
+ }
+
+ /* This collection of keywords is somewhat arbitrary and random. */
+ save_kw( fortio , "PERMX" , ECL_FLOAT_TYPE);
+ save_kw( fortio , "PERMY" , ECL_FLOAT_TYPE);
+ save_kw( fortio , "PERMZ" , ECL_FLOAT_TYPE);
+
+ save_kw( fortio , "FIPNUM" , ECL_INT_TYPE);
+ save_kw( fortio , "SATNUM" , ECL_INT_TYPE);
+ save_kw( fortio , "EQLNUM" , ECL_INT_TYPE);
+
+ fortio_fclose( fortio );
+}
+
+
+/**
+ This is the main function used to save the state of the ECLIPSE
+ deck in ECLIPSE format. The function will save an INIT file and an
+ EGRID file.
+
+ The input arguments are the output directory to store files in, and
+ the basename to use for the files; the function will build up a
+ ECLIPSE standard filename internally.
+*/
+
+void EclipseGridParser::saveEGRID_INIT( const std::string& output_dir , const std::string& basename, bool fmt_file) {
+ ecl_grid_type * ecl_grid = newGrid();
+ char * egrid_file = ecl_util_alloc_filename( output_dir.c_str() , basename.c_str() , ECL_EGRID_FILE , fmt_file , 0);
+ char * init_file = ecl_util_alloc_filename( output_dir.c_str() , basename.c_str() , ECL_INIT_FILE , fmt_file , 0);
+
+ ecl_grid_fwrite_EGRID( ecl_grid , egrid_file );
+ saveINIT( init_file , ecl_grid );
+
+ free( init_file );
+ free( egrid_file );
+ ecl_grid_free( ecl_grid );
+}
+#endif
+
+// Read an imported fortio data file using Ert.
+// Data stored in 'integer_field_map_' and 'floating_field_map_'.
+void EclipseGridParser::getNumericErtFields(const string& filename)
+{
+#ifdef HAVE_ERT
+ // Read file
+ ecl_file_type * ecl_file = ecl_file_open(filename.c_str());
+ if (ecl_file == NULL) {
+ THROW("Could not open IMPORTed file " << filename);
+ }
+ const int num_kw = ecl_file_get_size(ecl_file);
+ std::vector double_vec;
+ std::vector int_vec;
+ for (int i=0; i.
#include
#include
+#include
+#ifdef HAVE_ERT
+#include
+#include
+#endif
+
+
namespace Opm
{
@@ -64,9 +71,23 @@ namespace Opm
*/
-class EclipseGridParser
-{
-public:
+ enum FieldType {
+ Integer,
+ FloatingPoint,
+ Timestepping,
+ SpecialField,
+ IgnoreWithData,
+ IgnoreNoData,
+ Include,
+ Import,
+ Unknown
+ };
+
+
+
+ class EclipseGridParser
+ {
+ public:
/// Default constructor.
EclipseGridParser();
/// Constructor taking an eclipse filename. Unless the second
@@ -74,6 +95,11 @@ public:
/// converted to SI units.
explicit EclipseGridParser(const std::string& filename, bool convert_to_SI = true);
+
+ static FieldType classifyKeyword(const std::string& keyword);
+ static bool readKeyword(std::istream& is, std::string& keyword);
+
+
/// Read the given stream, overwriting any previous data. Unless
/// the second argument 'convert_to_SI' is false, all fields will
/// be converted to SI units.
@@ -191,11 +217,28 @@ public:
/// The units specified by the eclipse file read.
const EclipseUnits& units() const;
+ struct grdecl get_grdecl() const;
+
+#ifdef HAVE_ERT
+ void saveEGRID_INIT( const std::string& output_dir , const std::string& basename, bool fmt_file = false);
+ void saveEGRID( const std::string & filename );
+ void saveINIT( const std::string & filename , const ecl_grid_type * ecl_grid);
+ ecl_grid_type * newGrid( );
+#endif
+
+
private:
+
+#ifdef HAVE_ERT
+ ecl_kw_type * newEclKW(const std::string &keyword , ecl_type_enum ecl_type) const;
+ void save_kw( fortio_type * fortio , const std::string & kw , ecl_type_enum ecl_type);
+#endif
+
SpecialFieldPtr createSpecialField(std::istream& is, const std::string& fieldname);
SpecialFieldPtr cloneSpecialField(const std::string& fieldname,
const std::tr1::shared_ptr original);
void readImpl(std::istream& is);
+ void getNumericErtFields(const std::string& filename);
std::string directory_;
@@ -216,6 +259,7 @@ private:
};
+
} // namespace Opm
#endif // SINTEF_ECLIPSEGRIDPARSER_HEADER
diff --git a/opm/core/eclipse/EclipseGridParserHelpers.hpp b/opm/core/eclipse/EclipseGridParserHelpers.hpp
index 6ab5fb78..7bc0e003 100644
--- a/opm/core/eclipse/EclipseGridParserHelpers.hpp
+++ b/opm/core/eclipse/EclipseGridParserHelpers.hpp
@@ -398,10 +398,18 @@ namespace
yv.push_back(table[k][i]);
}
}
- // Interpolate
- for (int i=0; i double_data(10, -1.0E20);
- const int num_to_read = 10;
+ const int num_to_read = 4;
int num_read = readDefaultedVectorData(is, double_data, num_to_read);
gconinje_line.surface_flow_max_rate_ = double_data[0];
gconinje_line.resv_flow_max_rate_ = double_data[1];
diff --git a/opm/core/fluid/BlackoilPropertiesBasic.cpp b/opm/core/fluid/BlackoilPropertiesBasic.cpp
index be8211c1..2496d98e 100644
--- a/opm/core/fluid/BlackoilPropertiesBasic.cpp
+++ b/opm/core/fluid/BlackoilPropertiesBasic.cpp
@@ -26,20 +26,20 @@ namespace Opm
{
BlackoilPropertiesBasic::BlackoilPropertiesBasic(const parameter::ParameterGroup& param,
- const int dim,
- const int num_cells)
+ const int dim,
+ const int num_cells)
{
- double poro = param.getDefault("porosity", 1.0);
- using namespace Opm::unit;
- using namespace Opm::prefix;
- double perm = param.getDefault("permeability", 100.0)*milli*darcy;
+ double poro = param.getDefault("porosity", 1.0);
+ using namespace Opm::unit;
+ using namespace Opm::prefix;
+ double perm = param.getDefault("permeability", 100.0)*milli*darcy;
rock_.init(dim, num_cells, poro, perm);
- pvt_.init(param);
+ pvt_.init(param);
satprops_.init(param);
- if (pvt_.numPhases() != satprops_.numPhases()) {
- THROW("BlackoilPropertiesBasic::BlackoilPropertiesBasic() - Inconsistent number of phases in pvt data ("
- << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
- }
+ if (pvt_.numPhases() != satprops_.numPhases()) {
+ THROW("BlackoilPropertiesBasic::BlackoilPropertiesBasic() - Inconsistent number of phases in pvt data ("
+ << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
+ }
}
BlackoilPropertiesBasic::~BlackoilPropertiesBasic()
@@ -90,11 +90,11 @@ namespace Opm
/// \param[out] dmudp If non-null: array of nP viscosity derivative values,
/// array must be valid before calling.
void BlackoilPropertiesBasic::viscosity(const int n,
- const double* p,
- const double* z,
- const int* /*cells*/,
- double* mu,
- double* dmudp) const
+ const double* p,
+ const double* z,
+ const int* /*cells*/,
+ double* mu,
+ double* dmudp) const
{
if (dmudp) {
THROW("BlackoilPropertiesBasic::viscosity() -- derivatives of viscosity not yet implemented.");
@@ -114,16 +114,16 @@ namespace Opm
/// array must be valid before calling. The matrices are output
/// in Fortran order.
void BlackoilPropertiesBasic::matrix(const int n,
- const double* /*p*/,
- const double* /*z*/,
- const int* /*cells*/,
- double* A,
- double* dAdp) const
+ const double* /*p*/,
+ const double* /*z*/,
+ const int* /*cells*/,
+ double* A,
+ double* dAdp) const
{
- const int np = numPhases();
- ASSERT(np <= 2);
- double B[2]; // Must be enough since component classes do not handle more than 2.
- pvt_.B(1, 0, 0, B);
+ const int np = numPhases();
+ ASSERT(np <= 2);
+ double B[2]; // Must be enough since component classes do not handle more than 2.
+ pvt_.B(1, 0, 0, B);
// Compute A matrix
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
@@ -152,8 +152,8 @@ namespace Opm
/// of a call to the method matrix().
/// \param[out] rho Array of nP density values, array must be valid before calling.
void BlackoilPropertiesBasic::density(const int n,
- const double* A,
- double* rho) const
+ const double* A,
+ double* rho) const
{
const int np = numPhases();
const double* sdens = pvt_.surfaceDensities();
@@ -186,10 +186,10 @@ namespace Opm
/// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
void BlackoilPropertiesBasic::relperm(const int n,
- const double* s,
- const int* /*cells*/,
- double* kr,
- double* dkrds) const
+ const double* s,
+ const int* /*cells*/,
+ double* kr,
+ double* dkrds) const
{
satprops_.relperm(n, s, kr, dkrds);
}
@@ -205,10 +205,10 @@ namespace Opm
/// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m01 ...)
void BlackoilPropertiesBasic::capPress(const int n,
- const double* s,
- const int* /*cells*/,
- double* pc,
- double* dpcds) const
+ const double* s,
+ const int* /*cells*/,
+ double* pc,
+ double* dpcds) const
{
satprops_.capPress(n, s, pc, dpcds);
}
@@ -226,7 +226,7 @@ namespace Opm
double* smin,
double* smax) const
{
- satprops_.satRange(n, smin, smax);
+ satprops_.satRange(n, smin, smax);
}
diff --git a/opm/core/fluid/BlackoilPropertiesBasic.hpp b/opm/core/fluid/BlackoilPropertiesBasic.hpp
index d879036e..44a76013 100644
--- a/opm/core/fluid/BlackoilPropertiesBasic.hpp
+++ b/opm/core/fluid/BlackoilPropertiesBasic.hpp
@@ -35,16 +35,16 @@ namespace Opm
{
public:
/// Construct from parameters.
- /// The following parameters are accepted (defaults):
- /// num_phases (2) Must be 1 or 2.
- /// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic".
- /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
- /// mu1 [mu2, mu3] (1.0) Viscosity in cP
- /// porosity (1.0) Porosity
- /// permeability (100.0) Permeability in mD
+ /// The following parameters are accepted (defaults):
+ /// num_phases (2) Must be 1 or 2.
+ /// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic".
+ /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
+ /// mu1 [mu2, mu3] (1.0) Viscosity in cP
+ /// porosity (1.0) Porosity
+ /// permeability (100.0) Permeability in mD
BlackoilPropertiesBasic(const parameter::ParameterGroup& param,
- const int dim,
- const int num_cells);
+ const int dim,
+ const int num_cells);
/// Destructor.
virtual ~BlackoilPropertiesBasic();
@@ -151,7 +151,7 @@ namespace Opm
double* dpcds) const;
- /// Obtain the range of allowable saturation values.
+/// Obtain the range of allowable saturation values.
/// In cell cells[i], saturation of phase p is allowed to be
/// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points.
diff --git a/opm/core/fluid/BlackoilPropertiesFromDeck.cpp b/opm/core/fluid/BlackoilPropertiesFromDeck.cpp
index 1f34e89e..0eba8ffb 100644
--- a/opm/core/fluid/BlackoilPropertiesFromDeck.cpp
+++ b/opm/core/fluid/BlackoilPropertiesFromDeck.cpp
@@ -19,6 +19,7 @@
#include
#include
+
namespace Opm
{
@@ -26,15 +27,19 @@ namespace Opm
const UnstructuredGrid& grid,
bool init_rock)
{
- if (init_rock){
+ if (init_rock){
rock_.init(deck, grid);
}
- pvt_.init(deck);
- satprops_.init(deck, grid);
- if (pvt_.numPhases() != satprops_.numPhases()) {
- THROW("BlackoilPropertiesBasic::BlackoilPropertiesBasic() - Inconsistent number of phases in pvt data ("
- << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
- }
+ pvt_.init(deck, 200);
+ SaturationPropsFromDeck* ptr
+ = new SaturationPropsFromDeck();
+ satprops_.reset(ptr);
+ ptr->init(deck, grid, 200);
+
+ if (pvt_.numPhases() != satprops_->numPhases()) {
+ THROW("BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
+ << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
+ }
}
BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
@@ -45,13 +50,56 @@ namespace Opm
if(init_rock){
rock_.init(deck, grid);
}
- const int samples = param.getDefault("dead_tab_size", 1025);
- pvt_.init(deck, samples);
- satprops_.init(deck, grid, param);
- if (pvt_.numPhases() != satprops_.numPhases()) {
- THROW("BlackoilPropertiesBasic::BlackoilPropertiesBasic() - Inconsistent number of phases in pvt data ("
- << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
+ const int pvt_samples = param.getDefault("pvt_tab_size", 200);
+ pvt_.init(deck, pvt_samples);
+
+ // Unfortunate lack of pointer smartness here...
+ const int sat_samples = param.getDefault("sat_tab_size", 200);
+ std::string threephase_model = param.getDefault("threephase_model", "simple");
+ if (sat_samples > 1) {
+ if (threephase_model == "stone2") {
+ SaturationPropsFromDeck* ptr
+ = new SaturationPropsFromDeck();
+ satprops_.reset(ptr);
+ ptr->init(deck, grid, sat_samples);
+ } else if (threephase_model == "simple") {
+ SaturationPropsFromDeck* ptr
+ = new SaturationPropsFromDeck();
+ satprops_.reset(ptr);
+ ptr->init(deck, grid, sat_samples);
+ } else if (threephase_model == "gwseg") {
+ SaturationPropsFromDeck* ptr
+ = new SaturationPropsFromDeck();
+ satprops_.reset(ptr);
+ ptr->init(deck, grid, sat_samples);
+ } else {
+ THROW("Unknown threephase_model: " << threephase_model);
+ }
+ } else {
+ if (threephase_model == "stone2") {
+ SaturationPropsFromDeck* ptr
+ = new SaturationPropsFromDeck();
+ satprops_.reset(ptr);
+ ptr->init(deck, grid, sat_samples);
+ } else if (threephase_model == "simple") {
+ SaturationPropsFromDeck* ptr
+ = new SaturationPropsFromDeck();
+ satprops_.reset(ptr);
+ ptr->init(deck, grid, sat_samples);
+ } else if (threephase_model == "gwseg") {
+ SaturationPropsFromDeck* ptr
+ = new SaturationPropsFromDeck();
+ satprops_.reset(ptr);
+ ptr->init(deck, grid, sat_samples);
+ } else {
+ THROW("Unknown threephase_model: " << threephase_model);
+ }
+ }
+
+ if (pvt_.numPhases() != satprops_->numPhases()) {
+ THROW("BlackoilPropertiesFromDeck::BlackoilPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
+ << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
}
}
@@ -256,7 +304,7 @@ namespace Opm
double* kr,
double* dkrds) const
{
- satprops_.relperm(n, s, cells, kr, dkrds);
+ satprops_->relperm(n, s, cells, kr, dkrds);
}
@@ -275,7 +323,7 @@ namespace Opm
double* pc,
double* dpcds) const
{
- satprops_.capPress(n, s, cells, pc, dpcds);
+ satprops_->capPress(n, s, cells, pc, dpcds);
}
@@ -291,7 +339,7 @@ namespace Opm
double* smin,
double* smax) const
{
- satprops_.satRange(n, cells, smin, smax);
+ satprops_->satRange(n, cells, smin, smax);
}
diff --git a/opm/core/fluid/BlackoilPropertiesFromDeck.hpp b/opm/core/fluid/BlackoilPropertiesFromDeck.hpp
index 782407dc..f78e2cd7 100644
--- a/opm/core/fluid/BlackoilPropertiesFromDeck.hpp
+++ b/opm/core/fluid/BlackoilPropertiesFromDeck.hpp
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
struct UnstructuredGrid;
@@ -40,7 +41,7 @@ namespace Opm
public:
/// Initialize from deck and grid.
/// \param[in] deck Deck input parser
- /// \param[in] grid Grid to which property object applies, needed for the
+ /// \param[in] grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck.
BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
@@ -48,12 +49,15 @@ namespace Opm
/// Initialize from deck, grid and parameters.
/// \param[in] deck Deck input parser
- /// \param[in] grid Grid to which property object applies, needed for the
+ /// \param[in] grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck.
/// \param[in] param Parameters. Accepted parameters include:
- /// dead_tab_size (1025) number of uniform sample points for dead-oil pvt tables.
- /// tab_size_kr (200) number of uniform sample points for saturation tables.
+ /// pvt_tab_size (200) number of uniform sample points for dead-oil pvt tables.
+ /// sat_tab_size (200) number of uniform sample points for saturation tables.
+ /// threephase_model("simple") three-phase relperm model (accepts "simple" and "stone2").
+ /// For both size parameters, a 0 or negative value indicates that no spline fitting is to
+ /// be done, and the input fluid data used directly for linear interpolation.
BlackoilPropertiesFromDeck(const EclipseGridParser& deck,
const UnstructuredGrid& grid,
const parameter::ParameterGroup& param,
@@ -164,9 +168,9 @@ namespace Opm
double* dpcds) const;
- /// Obtain the range of allowable saturation values.
- /// In cell cells[i], saturation of phase p is allowed to be
- /// in the interval [smin[i*P + p], smax[i*P + p]].
+ /// Obtain the range of allowable saturation values.
+ /// In cell cells[i], saturation of phase p is allowed to be
+ /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
@@ -179,7 +183,7 @@ namespace Opm
private:
RockFromDeck rock_;
BlackoilPvtProperties pvt_;
- SaturationPropsFromDeck satprops_;
+ boost::scoped_ptr satprops_;
mutable std::vector B_;
mutable std::vector dB_;
mutable std::vector R_;
diff --git a/opm/core/fluid/BlackoilPropertiesInterface.hpp b/opm/core/fluid/BlackoilPropertiesInterface.hpp
index dd8a857f..501c8a40 100644
--- a/opm/core/fluid/BlackoilPropertiesInterface.hpp
+++ b/opm/core/fluid/BlackoilPropertiesInterface.hpp
@@ -138,9 +138,9 @@ namespace Opm
double* dpcds) const = 0;
- /// Obtain the range of allowable saturation values.
- /// In cell cells[i], saturation of phase p is allowed to be
- /// in the interval [smin[i*P + p], smax[i*P + p]].
+ /// Obtain the range of allowable saturation values.
+ /// In cell cells[i], saturation of phase p is allowed to be
+ /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
diff --git a/opm/core/fluid/IncompPropertiesBasic.cpp b/opm/core/fluid/IncompPropertiesBasic.cpp
index 0ce3c88a..ab68017c 100644
--- a/opm/core/fluid/IncompPropertiesBasic.cpp
+++ b/opm/core/fluid/IncompPropertiesBasic.cpp
@@ -28,22 +28,22 @@ namespace Opm
{
IncompPropertiesBasic::IncompPropertiesBasic(const parameter::ParameterGroup& param,
- const int dim,
- const int num_cells)
+ const int dim,
+ const int num_cells)
{
- double poro = param.getDefault("porosity", 1.0);
- using namespace Opm::unit;
- using namespace Opm::prefix;
- double perm = param.getDefault("permeability", 100.0)*milli*darcy;
+ double poro = param.getDefault("porosity", 1.0);
+ using namespace Opm::unit;
+ using namespace Opm::prefix;
+ double perm = param.getDefault("permeability", 100.0)*milli*darcy;
rock_.init(dim, num_cells, poro, perm);
- pvt_.init(param);
+ pvt_.init(param);
satprops_.init(param);
- if (pvt_.numPhases() != satprops_.numPhases()) {
- THROW("IncompPropertiesBasic::IncompPropertiesBasic() - Inconsistent number of phases in pvt data ("
- << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
- }
- viscosity_.resize(pvt_.numPhases());
- pvt_.mu(1, 0, 0, &viscosity_[0]);
+ if (pvt_.numPhases() != satprops_.numPhases()) {
+ THROW("IncompPropertiesBasic::IncompPropertiesBasic() - Inconsistent number of phases in pvt data ("
+ << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
+ }
+ viscosity_.resize(pvt_.numPhases());
+ pvt_.mu(1, 0, 0, &viscosity_[0]);
}
IncompPropertiesBasic::IncompPropertiesBasic(const int num_phases,
@@ -56,14 +56,14 @@ namespace Opm
const int num_cells)
{
rock_.init(dim, num_cells, por, perm);
- pvt_.init(num_phases, rho, mu);
+ pvt_.init(num_phases, rho, mu);
satprops_.init(num_phases, relpermfunc);
- if (pvt_.numPhases() != satprops_.numPhases()) {
- THROW("IncompPropertiesBasic::IncompPropertiesBasic() - Inconsistent number of phases in pvt data ("
- << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
- }
- viscosity_.resize(pvt_.numPhases());
- pvt_.mu(1, 0, 0, &viscosity_[0]);
+ if (pvt_.numPhases() != satprops_.numPhases()) {
+ THROW("IncompPropertiesBasic::IncompPropertiesBasic() - Inconsistent number of phases in pvt data ("
+ << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
+ }
+ viscosity_.resize(pvt_.numPhases());
+ pvt_.mu(1, 0, 0, &viscosity_[0]);
}
IncompPropertiesBasic::~IncompPropertiesBasic()
@@ -109,7 +109,7 @@ namespace Opm
/// \return Array of P viscosity values.
const double* IncompPropertiesBasic::viscosity() const
{
- return &viscosity_[0];
+ return &viscosity_[0];
}
/// \return Array of P density values.
@@ -117,7 +117,7 @@ namespace Opm
{
// No difference between reservoir and surface densities
// modelled by this class.
- return pvt_.surfaceDensities();
+ return pvt_.surfaceDensities();
}
/// \return Array of P density values.
@@ -125,7 +125,7 @@ namespace Opm
{
// No difference between reservoir and surface densities
// modelled by this class.
- return pvt_.surfaceDensities();
+ return pvt_.surfaceDensities();
}
/// \param[in] n Number of data points.
@@ -138,10 +138,10 @@ namespace Opm
/// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m_01 ...)
void IncompPropertiesBasic::relperm(const int n,
- const double* s,
- const int* /*cells*/,
- double* kr,
- double* dkrds) const
+ const double* s,
+ const int* /*cells*/,
+ double* kr,
+ double* dkrds) const
{
satprops_.relperm(n, s, kr, dkrds);
}
@@ -157,10 +157,10 @@ namespace Opm
/// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m_01 ...)
void IncompPropertiesBasic::capPress(const int n,
- const double* s,
- const int* /*cells*/,
- double* pc,
- double* dpcds) const
+ const double* s,
+ const int* /*cells*/,
+ double* pc,
+ double* dpcds) const
{
satprops_.capPress(n, s, pc, dpcds);
}
@@ -174,11 +174,11 @@ namespace Opm
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling.
void IncompPropertiesBasic::satRange(const int n,
- const int* /*cells*/,
- double* smin,
- double* smax) const
+ const int* /*cells*/,
+ double* smin,
+ double* smax) const
{
- satprops_.satRange(n, smin, smax);
+ satprops_.satRange(n, smin, smax);
}
} // namespace Opm
diff --git a/opm/core/fluid/IncompPropertiesBasic.hpp b/opm/core/fluid/IncompPropertiesBasic.hpp
index b90b0876..72c39b1b 100644
--- a/opm/core/fluid/IncompPropertiesBasic.hpp
+++ b/opm/core/fluid/IncompPropertiesBasic.hpp
@@ -42,29 +42,29 @@ namespace Opm
{
public:
/// Construct from parameters.
- /// The following parameters are accepted (defaults):
- /// num_phases (2) Must be 1 or 2.
- /// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic".
- /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
- /// mu1 [mu2, mu3] (1.0) Viscosity in cP
- /// porosity (1.0) Porosity
- /// permeability (100.0) Permeability in mD
+ /// The following parameters are accepted (defaults):
+ /// num_phases (2) Must be 1 or 2.
+ /// relperm_func ("Linear") Must be "Constant", "Linear" or "Quadratic".
+ /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
+ /// mu1 [mu2, mu3] (1.0) Viscosity in cP
+ /// porosity (1.0) Porosity
+ /// permeability (100.0) Permeability in mD
IncompPropertiesBasic(const parameter::ParameterGroup& param,
- const int dim,
- const int num_cells);
+ const int dim,
+ const int num_cells);
/// Construct from arguments a basic two phase fluid.
IncompPropertiesBasic(const int num_phases,
const SaturationPropsBasic::RelPermFunc& relpermfunc,
const std::vector& rho,
- const std::vector& mu,
+ const std::vector& mu,
const double porosity,
const double permeability,
const int dim,
- const int num_cells);
+ const int num_cells);
- /// Destructor.
+ /// Destructor.
virtual ~IncompPropertiesBasic();
// ---- Rock interface ----
@@ -132,9 +132,9 @@ namespace Opm
double* dpcds) const;
- /// Obtain the range of allowable saturation values.
- /// In cell cells[i], saturation of phase p is allowed to be
- /// in the interval [smin[i*P + p], smax[i*P + p]].
+ /// Obtain the range of allowable saturation values.
+ /// In cell cells[i], saturation of phase p is allowed to be
+ /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
@@ -145,9 +145,9 @@ namespace Opm
double* smax) const;
private:
RockBasic rock_;
- PvtPropertiesBasic pvt_;
+ PvtPropertiesBasic pvt_;
SaturationPropsBasic satprops_;
- std::vector viscosity_;
+ std::vector viscosity_;
};
diff --git a/opm/core/fluid/IncompPropertiesFromDeck.cpp b/opm/core/fluid/IncompPropertiesFromDeck.cpp
index 570154bf..9aa69098 100644
--- a/opm/core/fluid/IncompPropertiesFromDeck.cpp
+++ b/opm/core/fluid/IncompPropertiesFromDeck.cpp
@@ -27,15 +27,15 @@ namespace Opm
{
IncompPropertiesFromDeck::IncompPropertiesFromDeck(const EclipseGridParser& deck,
- const UnstructuredGrid& grid)
+ const UnstructuredGrid& grid)
{
rock_.init(deck, grid);
- pvt_.init(deck);
- satprops_.init(deck, grid);
- if (pvt_.numPhases() != satprops_.numPhases()) {
- THROW("IncompPropertiesFromDeck::IncompPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
- << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
- }
+ pvt_.init(deck);
+ satprops_.init(deck, grid, 200);
+ if (pvt_.numPhases() != satprops_.numPhases()) {
+ THROW("IncompPropertiesFromDeck::IncompPropertiesFromDeck() - Inconsistent number of phases in pvt data ("
+ << pvt_.numPhases() << ") and saturation-dependent function data (" << satprops_.numPhases() << ").");
+ }
}
IncompPropertiesFromDeck::~IncompPropertiesFromDeck()
@@ -81,19 +81,19 @@ namespace Opm
/// \return Array of P viscosity values.
const double* IncompPropertiesFromDeck::viscosity() const
{
- return pvt_.viscosity();
+ return pvt_.viscosity();
}
/// \return Array of P density values.
const double* IncompPropertiesFromDeck::density() const
{
- return pvt_.reservoirDensities();
+ return pvt_.reservoirDensities();
}
/// \return Array of P density values.
const double* IncompPropertiesFromDeck::surfaceDensity() const
{
- return pvt_.surfaceDensities();
+ return pvt_.surfaceDensities();
}
/// \param[in] n Number of data points.
@@ -106,10 +106,10 @@ namespace Opm
/// m_{ij} = \frac{dkr_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m_01 ...)
void IncompPropertiesFromDeck::relperm(const int n,
- const double* s,
- const int* cells,
- double* kr,
- double* dkrds) const
+ const double* s,
+ const int* cells,
+ double* kr,
+ double* dkrds) const
{
satprops_.relperm(n, s, cells, kr, dkrds);
}
@@ -125,10 +125,10 @@ namespace Opm
/// m_{ij} = \frac{dpc_i}{ds^j},
/// and is output in Fortran order (m_00 m_10 m_20 m_01 ...)
void IncompPropertiesFromDeck::capPress(const int n,
- const double* s,
- const int* cells,
- double* pc,
- double* dpcds) const
+ const double* s,
+ const int* cells,
+ double* pc,
+ double* dpcds) const
{
satprops_.capPress(n, s, cells, pc, dpcds);
}
@@ -142,11 +142,11 @@ namespace Opm
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
/// \param[out] smax Array of nP maximum s values, array must be valid before calling.
void IncompPropertiesFromDeck::satRange(const int n,
- const int* cells,
- double* smin,
- double* smax) const
+ const int* cells,
+ double* smin,
+ double* smax) const
{
- satprops_.satRange(n, cells, smin, smax);
+ satprops_.satRange(n, cells, smin, smax);
}
} // namespace Opm
diff --git a/opm/core/fluid/IncompPropertiesFromDeck.hpp b/opm/core/fluid/IncompPropertiesFromDeck.hpp
index 68623e5c..6680eaa4 100644
--- a/opm/core/fluid/IncompPropertiesFromDeck.hpp
+++ b/opm/core/fluid/IncompPropertiesFromDeck.hpp
@@ -47,13 +47,13 @@ namespace Opm
public:
/// Initialize from deck and grid.
/// \param deck Deck input parser
- /// \param grid Grid to which property object applies, needed for the
+ /// \param grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck.
IncompPropertiesFromDeck(const EclipseGridParser& deck,
- const UnstructuredGrid& grid);
+ const UnstructuredGrid& grid);
- /// Destructor.
+ /// Destructor.
virtual ~IncompPropertiesFromDeck();
// ---- Rock interface ----
@@ -121,9 +121,9 @@ namespace Opm
double* dpcds) const;
- /// Obtain the range of allowable saturation values.
- /// In cell cells[i], saturation of phase p is allowed to be
- /// in the interval [smin[i*P + p], smax[i*P + p]].
+ /// Obtain the range of allowable saturation values.
+ /// In cell cells[i], saturation of phase p is allowed to be
+ /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
@@ -134,8 +134,8 @@ namespace Opm
double* smax) const;
private:
RockFromDeck rock_;
- PvtPropertiesIncompFromDeck pvt_;
- SaturationPropsFromDeck satprops_;
+ PvtPropertiesIncompFromDeck pvt_;
+ SaturationPropsFromDeck satprops_;
};
diff --git a/opm/core/fluid/IncompPropertiesInterface.hpp b/opm/core/fluid/IncompPropertiesInterface.hpp
index a5025e8a..d3aaaa7b 100644
--- a/opm/core/fluid/IncompPropertiesInterface.hpp
+++ b/opm/core/fluid/IncompPropertiesInterface.hpp
@@ -62,7 +62,7 @@ namespace Opm
/// \return Array of P viscosity values.
virtual const double* viscosity() const = 0;
- /// Densities of fluid phases at surface conditions.
+ /// Densities of fluid phases at reservoir conditions.
/// \return Array of P density values.
virtual const double* density() const = 0;
@@ -109,9 +109,9 @@ namespace Opm
double* pc,
double* dpcds) const = 0;
- /// Obtain the range of allowable saturation values.
- /// In cell cells[i], saturation of phase p is allowed to be
- /// in the interval [smin[i*P + p], smax[i*P + p]].
+ /// Obtain the range of allowable saturation values.
+ /// In cell cells[i], saturation of phase p is allowed to be
+ /// in the interval [smin[i*P + p], smax[i*P + p]].
/// \param[in] n Number of data points.
/// \param[in] cells Array of n cell indices.
/// \param[out] smin Array of nP minimum s values, array must be valid before calling.
diff --git a/opm/core/fluid/PvtPropertiesBasic.cpp b/opm/core/fluid/PvtPropertiesBasic.cpp
index 3d7d7bb2..5220502a 100644
--- a/opm/core/fluid/PvtPropertiesBasic.cpp
+++ b/opm/core/fluid/PvtPropertiesBasic.cpp
@@ -34,41 +34,41 @@ namespace Opm
void PvtPropertiesBasic::init(const parameter::ParameterGroup& param)
{
- int num_phases = param.getDefault("num_phases", 2);
- if (num_phases > 3 || num_phases < 1) {
- THROW("PvtPropertiesBasic::init() illegal num_phases: " << num_phases);
- }
- density_.resize(num_phases);
- viscosity_.resize(num_phases);
- // We currently do not allow the user to set B.
- formation_volume_factor_.clear();
- formation_volume_factor_.resize(num_phases, 1.0);
+ int num_phases = param.getDefault("num_phases", 2);
+ if (num_phases > 3 || num_phases < 1) {
+ THROW("PvtPropertiesBasic::init() illegal num_phases: " << num_phases);
+ }
+ density_.resize(num_phases);
+ viscosity_.resize(num_phases);
+ // We currently do not allow the user to set B.
+ formation_volume_factor_.clear();
+ formation_volume_factor_.resize(num_phases, 1.0);
- // Setting mu and rho from parameters
- using namespace Opm::prefix;
- using namespace Opm::unit;
- const double kgpm3 = kilogram/cubic(meter);
- const double cP = centi*Poise;
- std::string rname[3] = { "rho1", "rho2", "rho3" };
- double rdefault[3] = { 1.0e3, 1.0e3, 1.0e3 };
- std::string vname[3] = { "mu1", "mu2", "mu3" };
- double vdefault[3] = { 1.0, 1.0, 1.0 };
- for (int phase = 0; phase < num_phases; ++phase) {
- density_[phase] = kgpm3*param.getDefault(rname[phase], rdefault[phase]);
- viscosity_[phase] = cP*param.getDefault(vname[phase], vdefault[phase]);
- }
+ // Setting mu and rho from parameters
+ using namespace Opm::prefix;
+ using namespace Opm::unit;
+ const double kgpm3 = kilogram/cubic(meter);
+ const double cP = centi*Poise;
+ std::string rname[3] = { "rho1", "rho2", "rho3" };
+ double rdefault[3] = { 1.0e3, 1.0e3, 1.0e3 };
+ std::string vname[3] = { "mu1", "mu2", "mu3" };
+ double vdefault[3] = { 1.0, 1.0, 1.0 };
+ for (int phase = 0; phase < num_phases; ++phase) {
+ density_[phase] = kgpm3*param.getDefault(rname[phase], rdefault[phase]);
+ viscosity_[phase] = cP*param.getDefault(vname[phase], vdefault[phase]);
+ }
}
void PvtPropertiesBasic::init(const int num_phases,
const std::vector& rho,
const std::vector& visc)
{
- if (num_phases > 3 || num_phases < 1) {
- THROW("PvtPropertiesBasic::init() illegal num_phases: " << num_phases);
- }
- // We currently do not allow the user to set B.
- formation_volume_factor_.clear();
- formation_volume_factor_.resize(num_phases, 1.0);
+ if (num_phases > 3 || num_phases < 1) {
+ THROW("PvtPropertiesBasic::init() illegal num_phases: " << num_phases);
+ }
+ // We currently do not allow the user to set B.
+ formation_volume_factor_.clear();
+ formation_volume_factor_.resize(num_phases, 1.0);
density_ = rho;
viscosity_ = visc;
}
@@ -87,69 +87,69 @@ namespace Opm
void PvtPropertiesBasic::mu(const int n,
- const double* /*p*/,
- const double* /*z*/,
- double* output_mu) const
+ const double* /*p*/,
+ const double* /*z*/,
+ double* output_mu) const
{
- const int np = numPhases();
+ const int np = numPhases();
for (int phase = 0; phase < np; ++phase) {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
output_mu[np*i + phase] = viscosity_[phase];
}
- }
+ }
}
void PvtPropertiesBasic::B(const int n,
- const double* /*p*/,
- const double* /*z*/,
- double* output_B) const
+ const double* /*p*/,
+ const double* /*z*/,
+ double* output_B) const
{
- const int np = numPhases();
+ const int np = numPhases();
for (int phase = 0; phase < np; ++phase) {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
output_B[np*i + phase] = formation_volume_factor_[phase];
}
- }
+ }
}
void PvtPropertiesBasic::dBdp(const int n,
- const double* /*p*/,
- const double* /*z*/,
- double* output_B,
- double* output_dBdp) const
+ const double* /*p*/,
+ const double* /*z*/,
+ double* output_B,
+ double* output_dBdp) const
{
- const int np = numPhases();
+ const int np = numPhases();
for (int phase = 0; phase < np; ++phase) {
// #pragma omp parallel for
for (int i = 0; i < n; ++i) {
output_B[np*i + phase] = formation_volume_factor_[phase];
output_dBdp[np*i + phase] = 0.0;
}
- }
+ }
}
void PvtPropertiesBasic::R(const int n,
- const double* /*p*/,
- const double* /*z*/,
- double* output_R) const
+ const double* /*p*/,
+ const double* /*z*/,
+ double* output_R) const
{
- const int np = numPhases();
- std::fill(output_R, output_R + n*np, 0.0);
+ const int np = numPhases();
+ std::fill(output_R, output_R + n*np, 0.0);
}
void PvtPropertiesBasic::dRdp(const int n,
- const double* /*p*/,
- const double* /*z*/,
- double* output_R,
- double* output_dRdp) const
+ const double* /*p*/,
+ const double* /*z*/,
+ double* output_R,
+ double* output_dRdp) const
{
- const int np = numPhases();
- std::fill(output_R, output_R + n*np, 0.0);
- std::fill(output_dRdp, output_dRdp + n*np, 0.0);
+ const int np = numPhases();
+ std::fill(output_R, output_R + n*np, 0.0);
+ std::fill(output_dRdp, output_dRdp + n*np, 0.0);
}
} // namespace Opm
diff --git a/opm/core/fluid/PvtPropertiesBasic.hpp b/opm/core/fluid/PvtPropertiesBasic.hpp
index d1a3e9f3..3e30e807 100644
--- a/opm/core/fluid/PvtPropertiesBasic.hpp
+++ b/opm/core/fluid/PvtPropertiesBasic.hpp
@@ -38,11 +38,11 @@ namespace Opm
PvtPropertiesBasic();
/// Initialize from parameters.
- /// The following parameters are accepted (defaults):
- /// num_phases (2) Must be 1, 2 or 3.
- /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
- /// mu1 [mu2, mu3] (1.0) Viscosity in cP
- void init(const parameter::ParameterGroup& param);
+ /// The following parameters are accepted (defaults):
+ /// num_phases (2) Must be 1, 2 or 3.
+ /// rho1 [rho2, rho3] (1.0e3) Density in kg/m^3
+ /// mu1 [mu2, mu3] (1.0) Viscosity in cP
+ void init(const parameter::ParameterGroup& param);
/// Initialize from arguments.
/// Basic multi phase fluid pvt properties.
@@ -55,7 +55,7 @@ namespace Opm
/// Densities of stock components at surface conditions.
/// \return Array of size numPhases().
- const double* surfaceDensities() const;
+ const double* surfaceDensities() const;
/// Viscosity as a function of p and z.
void mu(const int n,
@@ -90,9 +90,9 @@ namespace Opm
double* output_dRdp) const;
private:
- std::vector density_;
- std::vector viscosity_;
- std::vector formation_volume_factor_;
+ std::vector density_;
+ std::vector viscosity_;
+ std::vector formation_volume_factor_;
};
}
diff --git a/opm/core/fluid/PvtPropertiesIncompFromDeck.cpp b/opm/core/fluid/PvtPropertiesIncompFromDeck.cpp
index 62cc1b23..34a4ba00 100644
--- a/opm/core/fluid/PvtPropertiesIncompFromDeck.cpp
+++ b/opm/core/fluid/PvtPropertiesIncompFromDeck.cpp
@@ -38,54 +38,54 @@ namespace Opm
{
typedef std::vector > > table_t;
// If we need multiple regions, this class and the SinglePvt* classes must change.
- int region_number = 0;
+ int region_number = 0;
PhaseUsage phase_usage = phaseUsageFromDeck(deck);
- if (phase_usage.phase_used[PhaseUsage::Vapour] ||
- !phase_usage.phase_used[PhaseUsage::Aqua] ||
- !phase_usage.phase_used[PhaseUsage::Liquid]) {
- THROW("PvtPropertiesIncompFromDeck::init() -- must have gas and oil phases (only) in deck input.\n");
- }
+ if (phase_usage.phase_used[PhaseUsage::Vapour] ||
+ !phase_usage.phase_used[PhaseUsage::Aqua] ||
+ !phase_usage.phase_used[PhaseUsage::Liquid]) {
+ THROW("PvtPropertiesIncompFromDeck::init() -- must have gas and oil phases (only) in deck input.\n");
+ }
- // Surface densities. Accounting for different orders in eclipse and our code.
- if (deck.hasField("DENSITY")) {
- const std::vector& d = deck.getDENSITY().densities_[region_number];
- enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 };
- surface_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] = d[ECL_water];
- surface_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] = d[ECL_oil];
- } else {
- THROW("Input is missing DENSITY\n");
- }
+ // Surface densities. Accounting for different orders in eclipse and our code.
+ if (deck.hasField("DENSITY")) {
+ const std::vector& d = deck.getDENSITY().densities_[region_number];
+ enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 };
+ surface_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] = d[ECL_water];
+ surface_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] = d[ECL_oil];
+ } else {
+ THROW("Input is missing DENSITY\n");
+ }
// Make reservoir densities the same as surface densities initially.
// We will modify them with formation volume factors if found.
reservoir_density_ = surface_density_;
// Water viscosity.
- if (deck.hasField("PVTW")) {
- const std::vector& pvtw = deck.getPVTW().pvtw_[region_number];
- if (pvtw[2] != 0.0 || pvtw[4] != 0.0) {
- MESSAGE("Compressibility effects in PVTW are ignored.");
- }
+ if (deck.hasField("PVTW")) {
+ const std::vector& pvtw = deck.getPVTW().pvtw_[region_number];
+ if (pvtw[2] != 0.0 || pvtw[4] != 0.0) {
+ MESSAGE("Compressibility effects in PVTW are ignored.");
+ }
reservoir_density_[phase_usage.phase_pos[PhaseUsage::Aqua]] /= pvtw[1];
- viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = pvtw[3];
- } else {
- // Eclipse 100 default.
- // viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = 0.5*Opm::prefix::centi*Opm::unit::Poise;
- THROW("Input is missing PVTW\n");
- }
+ viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = pvtw[3];
+ } else {
+ // Eclipse 100 default.
+ // viscosity_[phase_usage.phase_pos[PhaseUsage::Aqua]] = 0.5*Opm::prefix::centi*Opm::unit::Poise;
+ THROW("Input is missing PVTW\n");
+ }
// Oil viscosity.
- if (deck.hasField("PVCDO")) {
- const std::vector& pvcdo = deck.getPVCDO().pvcdo_[region_number];
- if (pvcdo[2] != 0.0 || pvcdo[4] != 0.0) {
- MESSAGE("Compressibility effects in PVCDO are ignored.");
- }
+ if (deck.hasField("PVCDO")) {
+ const std::vector& pvcdo = deck.getPVCDO().pvcdo_[region_number];
+ if (pvcdo[2] != 0.0 || pvcdo[4] != 0.0) {
+ MESSAGE("Compressibility effects in PVCDO are ignored.");
+ }
reservoir_density_[phase_usage.phase_pos[PhaseUsage::Liquid]] /= pvcdo[1];
- viscosity_[phase_usage.phase_pos[PhaseUsage::Liquid]] = pvcdo[3];
- } else {
- THROW("Input is missing PVCDO\n");
- }
+ viscosity_[phase_usage.phase_pos[PhaseUsage::Liquid]] = pvcdo[3];
+ } else {
+ THROW("Input is missing PVCDO\n");
+ }
}
const double* PvtPropertiesIncompFromDeck::surfaceDensities() const
diff --git a/opm/core/fluid/PvtPropertiesIncompFromDeck.hpp b/opm/core/fluid/PvtPropertiesIncompFromDeck.hpp
index acbabaa4..01bbeed1 100644
--- a/opm/core/fluid/PvtPropertiesIncompFromDeck.hpp
+++ b/opm/core/fluid/PvtPropertiesIncompFromDeck.hpp
@@ -39,14 +39,14 @@ namespace Opm
PvtPropertiesIncompFromDeck();
/// Initialize from deck.
- void init(const EclipseGridParser& deck);
+ void init(const EclipseGridParser& deck);
/// Number of active phases.
int numPhases() const;
/// Densities of stock components at surface conditions.
/// \return Array of size numPhases().
- const double* surfaceDensities() const;
+ const double* surfaceDensities() const;
/// Densities of stock components at reservoir conditions.
/// Note: a reasonable question to ask is why there can be
@@ -58,15 +58,15 @@ namespace Opm
/// reporting and using data given in terms of surface values,
/// we need to handle this difference.
/// \return Array of size numPhases().
- const double* reservoirDensities() const;
+ const double* reservoirDensities() const;
/// Viscosities.
const double* viscosity() const;
private:
- std::tr1::array surface_density_;
- std::tr1::array reservoir_density_;
- std::tr1::array viscosity_;
+ std::tr1::array surface_density_;
+ std::tr1::array reservoir_density_;
+ std::tr1::array viscosity_;
};
}
diff --git a/opm/core/fluid/RockBasic.cpp b/opm/core/fluid/RockBasic.cpp
index a1423b76..b66cccce 100644
--- a/opm/core/fluid/RockBasic.cpp
+++ b/opm/core/fluid/RockBasic.cpp
@@ -25,29 +25,29 @@ namespace Opm
/// Default constructor.
RockBasic::RockBasic()
- : dimensions_(-1)
+ : dimensions_(-1)
{
}
/// Initialize with homogenous porosity and permeability.
void RockBasic::init(const int dimensions,
- const int num_cells,
- const double poro,
- const double perm)
+ const int num_cells,
+ const double poro,
+ const double perm)
{
- dimensions_ = dimensions;
- porosity_.clear();
- porosity_.resize(num_cells, poro);
- permeability_.clear();
- const int dsq = dimensions*dimensions;
- permeability_.resize(num_cells*dsq, 0.0);
+ dimensions_ = dimensions;
+ porosity_.clear();
+ porosity_.resize(num_cells, poro);
+ permeability_.clear();
+ const int dsq = dimensions*dimensions;
+ permeability_.resize(num_cells*dsq, 0.0);
// #pragma omp parallel for
- for (int i = 0; i < num_cells; ++i) {
- for (int d = 0; d < dimensions; ++d) {
- permeability_[dsq*i + dimensions*d + d] = perm;
- }
- }
+ for (int i = 0; i < num_cells; ++i) {
+ for (int d = 0; d < dimensions; ++d) {
+ permeability_[dsq*i + dimensions*d + d] = perm;
+ }
+ }
}
diff --git a/opm/core/fluid/RockBasic.hpp b/opm/core/fluid/RockBasic.hpp
index 96563780..2adc3ffd 100644
--- a/opm/core/fluid/RockBasic.hpp
+++ b/opm/core/fluid/RockBasic.hpp
@@ -35,9 +35,9 @@ namespace Opm
/// Initialize with homogenous porosity and permeability.
void init(const int dimensions,
- const int num_cells,
- const double poro,
- const double perm);
+ const int num_cells,
+ const double poro,
+ const double perm);
/// \return D, the number of spatial dimensions.
int numDimensions() const
@@ -66,7 +66,7 @@ namespace Opm
}
private:
- int dimensions_;
+ int dimensions_;
std::vector porosity_;
std::vector permeability_;
};
diff --git a/opm/core/fluid/RockCompressibility.cpp b/opm/core/fluid/RockCompressibility.cpp
index 10486101..af65d852 100644
--- a/opm/core/fluid/RockCompressibility.cpp
+++ b/opm/core/fluid/RockCompressibility.cpp
@@ -69,8 +69,8 @@ namespace Opm
const double cpnorm = rock_comp_*(pressure - pref_);
return (1.0 + cpnorm + 0.5*cpnorm*cpnorm);
} else {
- // return Opm::linearInterpolation(p_, poromult_, pressure);
- return Opm::linearInterpolationExtrap(p_, poromult_, pressure);
+ // return Opm::linearInterpolation(p_, poromult_, pressure);
+ return Opm::linearInterpolationExtrap(p_, poromult_, pressure);
}
}
@@ -81,7 +81,7 @@ namespace Opm
} else {
//const double poromult = Opm::linearInterpolation(p_, poromult_, pressure);
//const double dporomultdp = Opm::linearInterpolationDerivative(p_, poromult_, pressure);
- const double poromult = Opm::linearInterpolationExtrap(p_, poromult_, pressure);
+ const double poromult = Opm::linearInterpolationExtrap(p_, poromult_, pressure);
const double dporomultdp = Opm::linearInterpolationDerivativeExtrap(p_, poromult_, pressure);
return dporomultdp/poromult;
diff --git a/opm/core/fluid/RockFromDeck.cpp b/opm/core/fluid/RockFromDeck.cpp
index 7ba8903f..ec7db9a6 100644
--- a/opm/core/fluid/RockFromDeck.cpp
+++ b/opm/core/fluid/RockFromDeck.cpp
@@ -51,7 +51,7 @@ namespace Opm
/// Initialize from deck and cell mapping.
/// \param deck Deck input parser
- /// \param grid grid to which property object applies, needed for the
+ /// \param grid grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck.
void RockFromDeck::init(const EclipseGridParser& deck,
diff --git a/opm/core/fluid/RockFromDeck.hpp b/opm/core/fluid/RockFromDeck.hpp
index 65027e42..63e71a6e 100644
--- a/opm/core/fluid/RockFromDeck.hpp
+++ b/opm/core/fluid/RockFromDeck.hpp
@@ -37,7 +37,7 @@ namespace Opm
/// Initialize from deck and grid.
/// \param deck Deck input parser
- /// \param grid Grid to which property object applies, needed for the
+ /// \param grid Grid to which property object applies, needed for the
/// mapping from cell indices (typically from a processed grid)
/// to logical cartesian indices consistent with the deck.
void init(const EclipseGridParser& deck,
diff --git a/opm/core/fluid/SatFuncGwseg.cpp b/opm/core/fluid/SatFuncGwseg.cpp
new file mode 100644
index 00000000..cd97e9af
--- /dev/null
+++ b/opm/core/fluid/SatFuncGwseg.cpp
@@ -0,0 +1,440 @@
+/*
+ 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 .
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Opm
+{
+
+
+
+
+ void SatFuncGwsegUniform::init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int samples)
+ {
+ phase_usage = phase_usg;
+ double swco = 0.0;
+ double swmax = 1.0;
+ if (phase_usage.phase_used[Aqua]) {
+ const SWOF::table_t& swof_table = deck.getSWOF().swof_;
+ const std::vector& sw = swof_table[table_num][0];
+ const std::vector& krw = swof_table[table_num][1];
+ const std::vector& krow = swof_table[table_num][2];
+ const std::vector& pcow = swof_table[table_num][3];
+ buildUniformMonotoneTable(sw, krw, samples, krw_);
+ buildUniformMonotoneTable(sw, krow, samples, krow_);
+ buildUniformMonotoneTable(sw, pcow, samples, pcow_);
+ krocw_ = krow[0]; // At connate water -> ecl. SWOF
+ swco = sw[0];
+ smin_[phase_usage.phase_pos[Aqua]] = sw[0];
+ swmax = sw.back();
+ smax_[phase_usage.phase_pos[Aqua]] = sw.back();
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
+ const std::vector& sg = sgof_table[table_num][0];
+ const std::vector& krg = sgof_table[table_num][1];
+ const std::vector& krog = sgof_table[table_num][2];
+ const std::vector& pcog = sgof_table[table_num][3];
+ buildUniformMonotoneTable(sg, krg, samples, krg_);
+ buildUniformMonotoneTable(sg, krog, samples, krog_);
+ buildUniformMonotoneTable(sg, pcog, samples, pcog_);
+ smin_[phase_usage.phase_pos[Vapour]] = sg[0];
+ if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
+ THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
+ ", should equal (1.0 - connate water sat) = " << (1.0 - swco));
+ }
+ smax_[phase_usage.phase_pos[Vapour]] = sg.back();
+ }
+ // These only consider water min/max sats. Consider gas sats?
+ smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
+ smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
+ }
+
+
+ void SatFuncGwsegUniform::evalKr(const double* s, double* kr) const
+ {
+ if (phase_usage.num_phases == 3) {
+ // Relative permeability model based on segregation of water
+ // and gas, with oil present in both water and gas zones.
+ const double swco = smin_[phase_usage.phase_pos[Aqua]];
+ const double sw = std::max(s[Aqua], swco);
+ const double sg = s[Vapour];
+ // xw and xg are the fractions occupied by water and gas zones.
+ const double eps = 1e-6;
+ const double xw = (sw - swco) / std::max(sg + sw - swco, eps);
+ const double xg = 1 - xw;
+ const double ssw = sg + sw;
+ const double ssg = sw - swco + sg;
+ const double krw = krw_(ssw);
+ const double krg = krg_(ssg);
+ const double krow = krow_(ssw);
+ const double krog = krog_(ssg);
+ kr[Aqua] = xw*krw;
+ kr[Vapour] = xg*krg;
+ kr[Liquid] = xw*krow + xg*krog;
+ return;
+ }
+ // We have a two-phase situation. We know that oil is active.
+ if (phase_usage.phase_used[Aqua]) {
+ int wpos = phase_usage.phase_pos[Aqua];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sw = s[wpos];
+ double krw = krw_(sw);
+ double krow = krow_(sw);
+ kr[wpos] = krw;
+ kr[opos] = krow;
+ } else {
+ ASSERT(phase_usage.phase_used[Vapour]);
+ int gpos = phase_usage.phase_pos[Vapour];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sg = s[gpos];
+ double krg = krg_(sg);
+ double krog = krog_(sg);
+ kr[gpos] = krg;
+ kr[opos] = krog;
+ }
+ }
+
+
+ void SatFuncGwsegUniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
+ {
+ const int np = phase_usage.num_phases;
+ std::fill(dkrds, dkrds + np*np, 0.0);
+
+ if (np == 3) {
+ // Relative permeability model based on segregation of water
+ // and gas, with oil present in both water and gas zones.
+ const double swco = smin_[phase_usage.phase_pos[Aqua]];
+ const double sw = std::max(s[Aqua], swco);
+ const double sg = s[Vapour];
+ // xw and xg are the fractions occupied by water and gas zones.
+ const double eps = 1e-6;
+ const double xw = (sw - swco) / std::max(sg + sw - swco, eps);
+ const double xg = 1 - xw;
+ const double ssw = sg + sw;
+ const double ssg = sw - swco + sg;
+ const double krw = krw_(ssw);
+ const double krg = krg_(ssg);
+ const double krow = krow_(ssw);
+ const double krog = krog_(ssg);
+ kr[Aqua] = xw*krw;
+ kr[Vapour] = xg*krg;
+ kr[Liquid] = xw*krow + xg*krog;
+
+ // Derivatives.
+ const double dkrww = krw_.derivative(ssw);
+ const double dkrgg = krg_.derivative(ssg);
+ const double dkrow = krow_.derivative(ssw);
+ const double dkrog = krog_.derivative(ssg);
+ const double d = ssg; // = sw - swco + sg (using 'd' for consistency with mrst docs).
+ dkrds[Aqua + Aqua*np] = (xg/d)*krw + xw*dkrww;
+ dkrds[Aqua + Vapour*np] = -(xw/d)*krw + xw*dkrww;
+ dkrds[Liquid + Aqua*np] = (xg/d)*krow + xw*dkrow - (xg/d)*krog + xg*dkrog;
+ dkrds[Liquid + Vapour*np] = -(xw/d)*krow + xw*dkrow + (xw/d)*krog + xg*dkrog;
+ dkrds[Vapour + Aqua*np] = -(xg/d)*krg + xg*dkrgg;
+ dkrds[Vapour + Vapour*np] = (xw/d)*krg + xg*dkrgg;
+ return;
+ }
+ // We have a two-phase situation. We know that oil is active.
+ if (phase_usage.phase_used[Aqua]) {
+ int wpos = phase_usage.phase_pos[Aqua];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sw = s[wpos];
+ double krw = krw_(sw);
+ double dkrww = krw_.derivative(sw);
+ double krow = krow_(sw);
+ double dkrow = krow_.derivative(sw);
+ kr[wpos] = krw;
+ kr[opos] = krow;
+ dkrds[wpos + wpos*np] = dkrww;
+ dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
+ } else {
+ ASSERT(phase_usage.phase_used[Vapour]);
+ int gpos = phase_usage.phase_pos[Vapour];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sg = s[gpos];
+ double krg = krg_(sg);
+ double dkrgg = krg_.derivative(sg);
+ double krog = krog_(sg);
+ double dkrog = krog_.derivative(sg);
+ kr[gpos] = krg;
+ kr[opos] = krog;
+ dkrds[gpos + gpos*np] = dkrgg;
+ dkrds[opos + gpos*np] = dkrog;
+ }
+
+ }
+
+
+ void SatFuncGwsegUniform::evalPc(const double* s, double* pc) const
+ {
+ pc[phase_usage.phase_pos[Liquid]] = 0.0;
+ if (phase_usage.phase_used[Aqua]) {
+ int pos = phase_usage.phase_pos[Aqua];
+ pc[pos] = pcow_(s[pos]);
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ int pos = phase_usage.phase_pos[Vapour];
+ pc[pos] = pcog_(s[pos]);
+ }
+ }
+
+ void SatFuncGwsegUniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
+ {
+ // The problem of determining three-phase capillary pressures
+ // is very hard experimentally, usually one extends two-phase
+ // data (as for relative permeability).
+ // In our approach the derivative matrix is quite sparse, only
+ // the diagonal elements corresponding to non-oil phases are
+ // (potentially) nonzero.
+ const int np = phase_usage.num_phases;
+ std::fill(dpcds, dpcds + np*np, 0.0);
+ pc[phase_usage.phase_pos[Liquid]] = 0.0;
+ if (phase_usage.phase_used[Aqua]) {
+ int pos = phase_usage.phase_pos[Aqua];
+ pc[pos] = pcow_(s[pos]);
+ dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ int pos = phase_usage.phase_pos[Vapour];
+ pc[pos] = pcog_(s[pos]);
+ dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
+ }
+ }
+
+
+
+
+ // ====== Methods for SatFuncGwsegNonuniform ======
+
+
+
+
+
+ void SatFuncGwsegNonuniform::init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int /*samples*/)
+ {
+ phase_usage = phase_usg;
+ double swco = 0.0;
+ double swmax = 1.0;
+ if (phase_usage.phase_used[Aqua]) {
+ const SWOF::table_t& swof_table = deck.getSWOF().swof_;
+ const std::vector& sw = swof_table[table_num][0];
+ const std::vector& krw = swof_table[table_num][1];
+ const std::vector& krow = swof_table[table_num][2];
+ const std::vector& pcow = swof_table[table_num][3];
+ krw_ = NonuniformTableLinear(sw, krw);
+ krow_ = NonuniformTableLinear(sw, krow);
+ pcow_ = NonuniformTableLinear(sw, pcow);
+ krocw_ = krow[0]; // At connate water -> ecl. SWOF
+ swco = sw[0];
+ smin_[phase_usage.phase_pos[Aqua]] = sw[0];
+ swmax = sw.back();
+ smax_[phase_usage.phase_pos[Aqua]] = sw.back();
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
+ const std::vector& sg = sgof_table[table_num][0];
+ const std::vector& krg = sgof_table[table_num][1];
+ const std::vector& krog = sgof_table[table_num][2];
+ const std::vector& pcog = sgof_table[table_num][3];
+ krg_ = NonuniformTableLinear(sg, krg);
+ krog_ = NonuniformTableLinear(sg, krog);
+ pcog_ = NonuniformTableLinear(sg, pcog);
+ smin_[phase_usage.phase_pos[Vapour]] = sg[0];
+ if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
+ THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
+ ", should equal (1.0 - connate water sat) = " << (1.0 - swco));
+ }
+ smax_[phase_usage.phase_pos[Vapour]] = sg.back();
+ }
+ // These only consider water min/max sats. Consider gas sats?
+ smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
+ smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
+ }
+
+
+ void SatFuncGwsegNonuniform::evalKr(const double* s, double* kr) const
+ {
+ if (phase_usage.num_phases == 3) {
+ // Relative permeability model based on segregation of water
+ // and gas, with oil present in both water and gas zones.
+ const double swco = smin_[phase_usage.phase_pos[Aqua]];
+ const double sw = std::max(s[Aqua], swco);
+ const double sg = s[Vapour];
+ // xw and xg are the fractions occupied by water and gas zones.
+ const double eps = 1e-6;
+ const double xw = (sw - swco) / std::max(sg + sw - swco, eps);
+ const double xg = 1 - xw;
+ const double ssw = sg + sw;
+ const double ssg = sw - swco + sg;
+ const double krw = krw_(ssw);
+ const double krg = krg_(ssg);
+ const double krow = krow_(ssw);
+ const double krog = krog_(ssg);
+ kr[Aqua] = xw*krw;
+ kr[Vapour] = xg*krg;
+ kr[Liquid] = xw*krow + xg*krog;
+ return;
+ }
+ // We have a two-phase situation. We know that oil is active.
+ if (phase_usage.phase_used[Aqua]) {
+ int wpos = phase_usage.phase_pos[Aqua];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sw = s[wpos];
+ double krw = krw_(sw);
+ double krow = krow_(sw);
+ kr[wpos] = krw;
+ kr[opos] = krow;
+ } else {
+ ASSERT(phase_usage.phase_used[Vapour]);
+ int gpos = phase_usage.phase_pos[Vapour];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sg = s[gpos];
+ double krg = krg_(sg);
+ double krog = krog_(sg);
+ kr[gpos] = krg;
+ kr[opos] = krog;
+ }
+ }
+
+
+ void SatFuncGwsegNonuniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
+ {
+ const int np = phase_usage.num_phases;
+ std::fill(dkrds, dkrds + np*np, 0.0);
+
+ if (np == 3) {
+ // Relative permeability model based on segregation of water
+ // and gas, with oil present in both water and gas zones.
+ const double swco = smin_[phase_usage.phase_pos[Aqua]];
+ const double sw = std::max(s[Aqua], swco);
+ const double sg = s[Vapour];
+ // xw and xg are the fractions occupied by water and gas zones.
+ const double eps = 1e-6;
+ const double xw = (sw - swco) / std::max(sg + sw - swco, eps);
+ const double xg = 1 - xw;
+ const double ssw = sg + sw;
+ const double ssg = sw - swco + sg;
+ const double krw = krw_(ssw);
+ const double krg = krg_(ssg);
+ const double krow = krow_(ssw);
+ const double krog = krog_(ssg);
+ kr[Aqua] = xw*krw;
+ kr[Vapour] = xg*krg;
+ kr[Liquid] = xw*krow + xg*krog;
+
+ // Derivatives.
+ const double dkrww = krw_.derivative(ssw);
+ const double dkrgg = krg_.derivative(ssg);
+ const double dkrow = krow_.derivative(ssw);
+ const double dkrog = krog_.derivative(ssg);
+ const double d = ssg; // = sw - swco + sg (using 'd' for consistency with mrst docs).
+ dkrds[Aqua + Aqua*np] = (xg/d)*krw + xw*dkrww;
+ dkrds[Aqua + Vapour*np] = -(xw/d)*krw + xw*dkrww;
+ dkrds[Liquid + Aqua*np] = (xg/d)*krow + xw*dkrow - (xg/d)*krog + xg*dkrog;
+ dkrds[Liquid + Vapour*np] = -(xw/d)*krow + xw*dkrow + (xw/d)*krog + xg*dkrog;
+ dkrds[Vapour + Aqua*np] = -(xg/d)*krg + xg*dkrgg;
+ dkrds[Vapour + Vapour*np] = (xw/d)*krg + xg*dkrgg;
+ return;
+ }
+ // We have a two-phase situation. We know that oil is active.
+ if (phase_usage.phase_used[Aqua]) {
+ int wpos = phase_usage.phase_pos[Aqua];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sw = s[wpos];
+ double krw = krw_(sw);
+ double dkrww = krw_.derivative(sw);
+ double krow = krow_(sw);
+ double dkrow = krow_.derivative(sw);
+ kr[wpos] = krw;
+ kr[opos] = krow;
+ dkrds[wpos + wpos*np] = dkrww;
+ dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
+ } else {
+ ASSERT(phase_usage.phase_used[Vapour]);
+ int gpos = phase_usage.phase_pos[Vapour];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sg = s[gpos];
+ double krg = krg_(sg);
+ double dkrgg = krg_.derivative(sg);
+ double krog = krog_(sg);
+ double dkrog = krog_.derivative(sg);
+ kr[gpos] = krg;
+ kr[opos] = krog;
+ dkrds[gpos + gpos*np] = dkrgg;
+ dkrds[opos + gpos*np] = dkrog;
+ }
+
+ }
+
+
+ void SatFuncGwsegNonuniform::evalPc(const double* s, double* pc) const
+ {
+ pc[phase_usage.phase_pos[Liquid]] = 0.0;
+ if (phase_usage.phase_used[Aqua]) {
+ int pos = phase_usage.phase_pos[Aqua];
+ pc[pos] = pcow_(s[pos]);
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ int pos = phase_usage.phase_pos[Vapour];
+ pc[pos] = pcog_(s[pos]);
+ }
+ }
+
+ void SatFuncGwsegNonuniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
+ {
+ // The problem of determining three-phase capillary pressures
+ // is very hard experimentally, usually one extends two-phase
+ // data (as for relative permeability).
+ // In our approach the derivative matrix is quite sparse, only
+ // the diagonal elements corresponding to non-oil phases are
+ // (potentially) nonzero.
+ const int np = phase_usage.num_phases;
+ std::fill(dpcds, dpcds + np*np, 0.0);
+ pc[phase_usage.phase_pos[Liquid]] = 0.0;
+ if (phase_usage.phase_used[Aqua]) {
+ int pos = phase_usage.phase_pos[Aqua];
+ pc[pos] = pcow_(s[pos]);
+ dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ int pos = phase_usage.phase_pos[Vapour];
+ pc[pos] = pcog_(s[pos]);
+ dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
+ }
+ }
+
+
+
+
+
+} // namespace Opm
diff --git a/opm/core/fluid/SatFuncGwseg.hpp b/opm/core/fluid/SatFuncGwseg.hpp
new file mode 100644
index 00000000..1932e7f0
--- /dev/null
+++ b/opm/core/fluid/SatFuncGwseg.hpp
@@ -0,0 +1,80 @@
+/*
+ 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 .
+*/
+#ifndef SATFUNCGWSEG_HPP
+#define SATFUNCGWSEG_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+namespace Opm
+{
+ class SatFuncGwsegUniform : public BlackoilPhases
+ {
+ public:
+ void init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int samples);
+ void evalKr(const double* s, double* kr) const;
+ void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
+ void evalPc(const double* s, double* pc) const;
+ void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
+ double smin_[PhaseUsage::MaxNumPhases];
+ double smax_[PhaseUsage::MaxNumPhases];
+ private:
+ PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
+ UniformTableLinear krw_;
+ UniformTableLinear krow_;
+ UniformTableLinear pcow_;
+ UniformTableLinear krg_;
+ UniformTableLinear krog_;
+ UniformTableLinear pcog_;
+ double krocw_; // = krow_(s_wc)
+ };
+
+
+ class SatFuncGwsegNonuniform : public BlackoilPhases
+ {
+ public:
+ void init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int samples);
+ void evalKr(const double* s, double* kr) const;
+ void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
+ void evalPc(const double* s, double* pc) const;
+ void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
+ double smin_[PhaseUsage::MaxNumPhases];
+ double smax_[PhaseUsage::MaxNumPhases];
+ private:
+ PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
+ NonuniformTableLinear krw_;
+ NonuniformTableLinear krow_;
+ NonuniformTableLinear pcow_;
+ NonuniformTableLinear krg_;
+ NonuniformTableLinear krog_;
+ NonuniformTableLinear pcog_;
+ double krocw_; // = krow_(s_wc)
+ };
+
+} // namespace Opm
+#endif // SATFUNCGWSEG_HPP
diff --git a/opm/core/fluid/SatFuncSimple.cpp b/opm/core/fluid/SatFuncSimple.cpp
index 740af43c..7e226a4a 100644
--- a/opm/core/fluid/SatFuncSimple.cpp
+++ b/opm/core/fluid/SatFuncSimple.cpp
@@ -1,3 +1,22 @@
+/*
+ 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 .
+*/
+
#include
#include
#include
@@ -6,21 +25,14 @@
#include
#include
#include
+
namespace Opm
{
- void SatFuncSimple::init(const EclipseGridParser& deck,
- const int table_num,
- const PhaseUsage phase_usg)
- {
- init(deck, table_num, phase_usg, 200);
- }
-
-
- void SatFuncSimple::init(const EclipseGridParser& deck,
+ void SatFuncSimpleUniform::init(const EclipseGridParser& deck,
const int table_num,
const PhaseUsage phase_usg,
const int samples)
@@ -65,7 +77,7 @@ namespace Opm
}
- void SatFuncSimple::evalKr(const double* s, double* kr) const
+ void SatFuncSimpleUniform::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// A simplified relative permeability model.
@@ -106,7 +118,7 @@ namespace Opm
}
- void SatFuncSimple::evalKrDeriv(const double* s, double* kr, double* dkrds) const
+ void SatFuncSimpleUniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
@@ -172,7 +184,7 @@ namespace Opm
}
- void SatFuncSimple::evalPc(const double* s, double* pc) const
+ void SatFuncSimpleUniform::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
@@ -185,7 +197,206 @@ namespace Opm
}
}
- void SatFuncSimple::evalPcDeriv(const double* s, double* pc, double* dpcds) const
+ void SatFuncSimpleUniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
+ {
+ // The problem of determining three-phase capillary pressures
+ // is very hard experimentally, usually one extends two-phase
+ // data (as for relative permeability).
+ // In our approach the derivative matrix is quite sparse, only
+ // the diagonal elements corresponding to non-oil phases are
+ // (potentially) nonzero.
+ const int np = phase_usage.num_phases;
+ std::fill(dpcds, dpcds + np*np, 0.0);
+ pc[phase_usage.phase_pos[Liquid]] = 0.0;
+ if (phase_usage.phase_used[Aqua]) {
+ int pos = phase_usage.phase_pos[Aqua];
+ pc[pos] = pcow_(s[pos]);
+ dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ int pos = phase_usage.phase_pos[Vapour];
+ pc[pos] = pcog_(s[pos]);
+ dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
+ }
+ }
+
+
+
+
+
+ // ====== Methods for SatFuncSimpleNonuniform ======
+
+
+
+
+
+
+ void SatFuncSimpleNonuniform::init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int /*samples*/)
+ {
+ phase_usage = phase_usg;
+ double swco = 0.0;
+ double swmax = 1.0;
+ if (phase_usage.phase_used[Aqua]) {
+ const SWOF::table_t& swof_table = deck.getSWOF().swof_;
+ const std::vector& sw = swof_table[table_num][0];
+ const std::vector& krw = swof_table[table_num][1];
+ const std::vector& krow = swof_table[table_num][2];
+ const std::vector& pcow = swof_table[table_num][3];
+ krw_ = NonuniformTableLinear(sw, krw);
+ krow_ = NonuniformTableLinear(sw, krow);
+ pcow_ = NonuniformTableLinear(sw, pcow);
+ krocw_ = krow[0]; // At connate water -> ecl. SWOF
+ swco = sw[0];
+ smin_[phase_usage.phase_pos[Aqua]] = sw[0];
+ swmax = sw.back();
+ smax_[phase_usage.phase_pos[Aqua]] = sw.back();
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
+ const std::vector& sg = sgof_table[table_num][0];
+ const std::vector& krg = sgof_table[table_num][1];
+ const std::vector& krog = sgof_table[table_num][2];
+ const std::vector& pcog = sgof_table[table_num][3];
+ krg_ = NonuniformTableLinear(sg, krg);
+ krog_ = NonuniformTableLinear(sg, krog);
+ pcog_ = NonuniformTableLinear(sg, pcog);
+ smin_[phase_usage.phase_pos[Vapour]] = sg[0];
+ if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
+ THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
+ ", should equal (1.0 - connate water sat) = " << (1.0 - swco));
+ }
+ smax_[phase_usage.phase_pos[Vapour]] = sg.back();
+ }
+ // These only consider water min/max sats. Consider gas sats?
+ smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
+ smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
+ }
+
+
+ void SatFuncSimpleNonuniform::evalKr(const double* s, double* kr) const
+ {
+ if (phase_usage.num_phases == 3) {
+ // A simplified relative permeability model.
+ double sw = s[Aqua];
+ double sg = s[Vapour];
+ double krw = krw_(sw);
+ double krg = krg_(sg);
+ double krow = krow_(sw + sg); // = 1 - so
+ // double krog = krog_(sg); // = 1 - so - sw
+ // double krocw = krocw_;
+ kr[Aqua] = krw;
+ kr[Vapour] = krg;
+ kr[Liquid] = krow;
+ if (kr[Liquid] < 0.0) {
+ kr[Liquid] = 0.0;
+ }
+ return;
+ }
+ // We have a two-phase situation. We know that oil is active.
+ if (phase_usage.phase_used[Aqua]) {
+ int wpos = phase_usage.phase_pos[Aqua];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sw = s[wpos];
+ double krw = krw_(sw);
+ double krow = krow_(sw);
+ kr[wpos] = krw;
+ kr[opos] = krow;
+ } else {
+ ASSERT(phase_usage.phase_used[Vapour]);
+ int gpos = phase_usage.phase_pos[Vapour];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sg = s[gpos];
+ double krg = krg_(sg);
+ double krog = krog_(sg);
+ kr[gpos] = krg;
+ kr[opos] = krog;
+ }
+ }
+
+
+ void SatFuncSimpleNonuniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
+ {
+ const int np = phase_usage.num_phases;
+ std::fill(dkrds, dkrds + np*np, 0.0);
+
+ if (np == 3) {
+ // A simplified relative permeability model.
+ double sw = s[Aqua];
+ double sg = s[Vapour];
+ double krw = krw_(sw);
+ double dkrww = krw_.derivative(sw);
+ double krg = krg_(sg);
+ double dkrgg = krg_.derivative(sg);
+ double krow = krow_(sw + sg);
+ double dkrow = krow_.derivative(sw + sg);
+ // double krog = krog_(sg);
+ // double dkrog = krog_.derivative(sg);
+ // double krocw = krocw_;
+ kr[Aqua] = krw;
+ kr[Vapour] = krg;
+ kr[Liquid] = krow;
+ //krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
+ if (kr[Liquid] < 0.0) {
+ kr[Liquid] = 0.0;
+ }
+ dkrds[Aqua + Aqua*np] = dkrww;
+ dkrds[Vapour + Vapour*np] = dkrgg;
+ //dkrds[Liquid + Aqua*np] = dkrow;
+ dkrds[Liquid + Liquid*np] = -dkrow;
+ //krocw*((dkrow/krocw + dkrww)*(krog/krocw + krg) - dkrww);
+ dkrds[Liquid + Vapour*np] = 0.0;
+ //krocw*((krow/krocw + krw)*(dkrog/krocw + dkrgg) - dkrgg)
+ //+ krocw*((dkrow/krocw + krw)*(krog/krocw + krg) - dkrgg);
+ return;
+ }
+ // We have a two-phase situation. We know that oil is active.
+ if (phase_usage.phase_used[Aqua]) {
+ int wpos = phase_usage.phase_pos[Aqua];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sw = s[wpos];
+ double krw = krw_(sw);
+ double dkrww = krw_.derivative(sw);
+ double krow = krow_(sw);
+ double dkrow = krow_.derivative(sw);
+ kr[wpos] = krw;
+ kr[opos] = krow;
+ dkrds[wpos + wpos*np] = dkrww;
+ dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
+ } else {
+ ASSERT(phase_usage.phase_used[Vapour]);
+ int gpos = phase_usage.phase_pos[Vapour];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sg = s[gpos];
+ double krg = krg_(sg);
+ double dkrgg = krg_.derivative(sg);
+ double krog = krog_(sg);
+ double dkrog = krog_.derivative(sg);
+ kr[gpos] = krg;
+ kr[opos] = krog;
+ dkrds[gpos + gpos*np] = dkrgg;
+ dkrds[opos + gpos*np] = dkrog;
+ }
+
+ }
+
+
+ void SatFuncSimpleNonuniform::evalPc(const double* s, double* pc) const
+ {
+ pc[phase_usage.phase_pos[Liquid]] = 0.0;
+ if (phase_usage.phase_used[Aqua]) {
+ int pos = phase_usage.phase_pos[Aqua];
+ pc[pos] = pcow_(s[pos]);
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ int pos = phase_usage.phase_pos[Vapour];
+ pc[pos] = pcog_(s[pos]);
+ }
+ }
+
+ void SatFuncSimpleNonuniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
diff --git a/opm/core/fluid/SatFuncSimple.hpp b/opm/core/fluid/SatFuncSimple.hpp
index a3388848..338a359e 100644
--- a/opm/core/fluid/SatFuncSimple.hpp
+++ b/opm/core/fluid/SatFuncSimple.hpp
@@ -18,17 +18,21 @@
*/
#ifndef SATFUNCSIMPLE_HPP
#define SATFUNCSIMPLE_HPP
+
#include
#include
+#include
#include
#include
+
namespace Opm
{
- class SatFuncSimple: public BlackoilPhases
+ class SatFuncSimpleUniform : public BlackoilPhases
{
public:
- void init(const EclipseGridParser& deck, const int table_num, PhaseUsage phase_usg);
- void init(const EclipseGridParser& deck, const int table_num, PhaseUsage phase_usg,
+ void init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
const int samples);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
@@ -46,5 +50,31 @@ namespace Opm
UniformTableLinear pcog_;
double krocw_; // = krow_(s_wc)
};
+
+
+ class SatFuncSimpleNonuniform : public BlackoilPhases
+ {
+ public:
+ void init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int samples);
+ void evalKr(const double* s, double* kr) const;
+ void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
+ void evalPc(const double* s, double* pc) const;
+ void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
+ double smin_[PhaseUsage::MaxNumPhases];
+ double smax_[PhaseUsage::MaxNumPhases];
+ private:
+ PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
+ NonuniformTableLinear krw_;
+ NonuniformTableLinear krow_;
+ NonuniformTableLinear pcow_;
+ NonuniformTableLinear krg_;
+ NonuniformTableLinear krog_;
+ NonuniformTableLinear pcog_;
+ double krocw_; // = krow_(s_wc)
+ };
+
} // namespace Opm
#endif // SATFUNCSIMPLE_HPP
diff --git a/opm/core/fluid/SatFuncStone2.cpp b/opm/core/fluid/SatFuncStone2.cpp
index a03bfb66..07b25214 100644
--- a/opm/core/fluid/SatFuncStone2.cpp
+++ b/opm/core/fluid/SatFuncStone2.cpp
@@ -1,3 +1,22 @@
+/*
+ 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 .
+*/
+
#include
#include
#include
@@ -6,23 +25,17 @@
#include
#include
#include
+
namespace Opm
{
- void SatFuncStone2::init(const EclipseGridParser& deck,
- const int table_num,
- const PhaseUsage phase_usg)
- {
- init(deck, table_num, phase_usg, 200);
- }
-
- void SatFuncStone2::init(const EclipseGridParser& deck,
- const int table_num,
- const PhaseUsage phase_usg,
- const int samples)
+ void SatFuncStone2Uniform::init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int samples)
{
phase_usage = phase_usg;
double swco = 0.0;
@@ -64,7 +77,7 @@ namespace Opm
}
- void SatFuncStone2::evalKr(const double* s, double* kr) const
+ void SatFuncStone2Uniform::evalKr(const double* s, double* kr) const
{
if (phase_usage.num_phases == 3) {
// Stone-II relative permeability model.
@@ -105,7 +118,7 @@ namespace Opm
}
- void SatFuncStone2::evalKrDeriv(const double* s, double* kr, double* dkrds) const
+ void SatFuncStone2Uniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
{
const int np = phase_usage.num_phases;
std::fill(dkrds, dkrds + np*np, 0.0);
@@ -167,7 +180,7 @@ namespace Opm
}
- void SatFuncStone2::evalPc(const double* s, double* pc) const
+ void SatFuncStone2Uniform::evalPc(const double* s, double* pc) const
{
pc[phase_usage.phase_pos[Liquid]] = 0.0;
if (phase_usage.phase_used[Aqua]) {
@@ -180,7 +193,7 @@ namespace Opm
}
}
- void SatFuncStone2::evalPcDeriv(const double* s, double* pc, double* dpcds) const
+ void SatFuncStone2Uniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
{
// The problem of determining three-phase capillary pressures
// is very hard experimentally, usually one extends two-phase
@@ -206,4 +219,199 @@ namespace Opm
+
+
+ // ====== Methods for SatFuncStone2Nonuniform ======
+
+
+
+
+ void SatFuncStone2Nonuniform::init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int /*samples*/)
+ {
+ phase_usage = phase_usg;
+ double swco = 0.0;
+ double swmax = 1.0;
+ if (phase_usage.phase_used[Aqua]) {
+ const SWOF::table_t& swof_table = deck.getSWOF().swof_;
+ const std::vector& sw = swof_table[table_num][0];
+ const std::vector& krw = swof_table[table_num][1];
+ const std::vector& krow = swof_table[table_num][2];
+ const std::vector& pcow = swof_table[table_num][3];
+ krw_ = NonuniformTableLinear(sw, krw);
+ krow_ = NonuniformTableLinear(sw, krow);
+ pcow_ = NonuniformTableLinear(sw, pcow);
+ krocw_ = krow[0]; // At connate water -> ecl. SWOF
+ swco = sw[0];
+ smin_[phase_usage.phase_pos[Aqua]] = sw[0];
+ swmax = sw.back();
+ smax_[phase_usage.phase_pos[Aqua]] = sw.back();
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ const SGOF::table_t& sgof_table = deck.getSGOF().sgof_;
+ const std::vector& sg = sgof_table[table_num][0];
+ const std::vector& krg = sgof_table[table_num][1];
+ const std::vector& krog = sgof_table[table_num][2];
+ const std::vector& pcog = sgof_table[table_num][3];
+ krg_ = NonuniformTableLinear(sg, krg);
+ krog_ = NonuniformTableLinear(sg, krog);
+ pcog_ = NonuniformTableLinear(sg, pcog);
+ smin_[phase_usage.phase_pos[Vapour]] = sg[0];
+ if (std::fabs(sg.back() + swco - 1.0) > 1e-3) {
+ THROW("Gas maximum saturation in SGOF table = " << sg.back() <<
+ ", should equal (1.0 - connate water sat) = " << (1.0 - swco));
+ }
+ smax_[phase_usage.phase_pos[Vapour]] = sg.back();
+ }
+ // These only consider water min/max sats. Consider gas sats?
+ smin_[phase_usage.phase_pos[Liquid]] = 1.0 - swmax;
+ smax_[phase_usage.phase_pos[Liquid]] = 1.0 - swco;
+ }
+
+
+ void SatFuncStone2Nonuniform::evalKr(const double* s, double* kr) const
+ {
+ if (phase_usage.num_phases == 3) {
+ // Stone-II relative permeability model.
+ double sw = s[Aqua];
+ double sg = s[Vapour];
+ double krw = krw_(sw);
+ double krg = krg_(sg);
+ double krow = krow_(sw + sg); // = 1 - so
+ double krog = krog_(sg); // = 1 - so - sw
+ double krocw = krocw_;
+ kr[Aqua] = krw;
+ kr[Vapour] = krg;
+ kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
+ if (kr[Liquid] < 0.0) {
+ kr[Liquid] = 0.0;
+ }
+ return;
+ }
+ // We have a two-phase situation. We know that oil is active.
+ if (phase_usage.phase_used[Aqua]) {
+ int wpos = phase_usage.phase_pos[Aqua];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sw = s[wpos];
+ double krw = krw_(sw);
+ double krow = krow_(sw);
+ kr[wpos] = krw;
+ kr[opos] = krow;
+ } else {
+ ASSERT(phase_usage.phase_used[Vapour]);
+ int gpos = phase_usage.phase_pos[Vapour];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sg = s[gpos];
+ double krg = krg_(sg);
+ double krog = krog_(sg);
+ kr[gpos] = krg;
+ kr[opos] = krog;
+ }
+ }
+
+
+ void SatFuncStone2Nonuniform::evalKrDeriv(const double* s, double* kr, double* dkrds) const
+ {
+ const int np = phase_usage.num_phases;
+ std::fill(dkrds, dkrds + np*np, 0.0);
+
+ if (np == 3) {
+ // Stone-II relative permeability model.
+ double sw = s[Aqua];
+ double sg = s[Vapour];
+ double krw = krw_(sw);
+ double dkrww = krw_.derivative(sw);
+ double krg = krg_(sg);
+ double dkrgg = krg_.derivative(sg);
+ double krow = krow_(sw + sg);
+ double dkrow = krow_.derivative(sw + sg);
+ double krog = krog_(sg);
+ double dkrog = krog_.derivative(sg);
+ double krocw = krocw_;
+ kr[Aqua] = krw;
+ kr[Vapour] = krg;
+ kr[Liquid] = krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg);
+ if (kr[Liquid] < 0.0) {
+ kr[Liquid] = 0.0;
+ }
+ dkrds[Aqua + Aqua*np] = dkrww;
+ dkrds[Vapour + Vapour*np] = dkrgg;
+ dkrds[Liquid + Aqua*np] = krocw*((dkrow/krocw + dkrww)*(krog/krocw + krg) - dkrww);
+ dkrds[Liquid + Vapour*np] = krocw*((krow/krocw + krw)*(dkrog/krocw + dkrgg) - dkrgg)
+ + krocw*((dkrow/krocw + krw)*(krog/krocw + krg) - dkrgg);
+ return;
+ }
+ // We have a two-phase situation. We know that oil is active.
+ if (phase_usage.phase_used[Aqua]) {
+ int wpos = phase_usage.phase_pos[Aqua];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sw = s[wpos];
+ double krw = krw_(sw);
+ double dkrww = krw_.derivative(sw);
+ double krow = krow_(sw);
+ double dkrow = krow_.derivative(sw);
+ kr[wpos] = krw;
+ kr[opos] = krow;
+ dkrds[wpos + wpos*np] = dkrww;
+ dkrds[opos + wpos*np] = dkrow; // Row opos, column wpos, fortran order.
+ } else {
+ ASSERT(phase_usage.phase_used[Vapour]);
+ int gpos = phase_usage.phase_pos[Vapour];
+ int opos = phase_usage.phase_pos[Liquid];
+ double sg = s[gpos];
+ double krg = krg_(sg);
+ double dkrgg = krg_.derivative(sg);
+ double krog = krog_(sg);
+ double dkrog = krog_.derivative(sg);
+ kr[gpos] = krg;
+ kr[opos] = krog;
+ dkrds[gpos + gpos*np] = dkrgg;
+ dkrds[opos + gpos*np] = dkrog;
+ }
+
+ }
+
+
+ void SatFuncStone2Nonuniform::evalPc(const double* s, double* pc) const
+ {
+ pc[phase_usage.phase_pos[Liquid]] = 0.0;
+ if (phase_usage.phase_used[Aqua]) {
+ int pos = phase_usage.phase_pos[Aqua];
+ pc[pos] = pcow_(s[pos]);
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ int pos = phase_usage.phase_pos[Vapour];
+ pc[pos] = pcog_(s[pos]);
+ }
+ }
+
+ void SatFuncStone2Nonuniform::evalPcDeriv(const double* s, double* pc, double* dpcds) const
+ {
+ // The problem of determining three-phase capillary pressures
+ // is very hard experimentally, usually one extends two-phase
+ // data (as for relative permeability).
+ // In our approach the derivative matrix is quite sparse, only
+ // the diagonal elements corresponding to non-oil phases are
+ // (potentially) nonzero.
+ const int np = phase_usage.num_phases;
+ std::fill(dpcds, dpcds + np*np, 0.0);
+ pc[phase_usage.phase_pos[Liquid]] = 0.0;
+ if (phase_usage.phase_used[Aqua]) {
+ int pos = phase_usage.phase_pos[Aqua];
+ pc[pos] = pcow_(s[pos]);
+ dpcds[np*pos + pos] = pcow_.derivative(s[pos]);
+ }
+ if (phase_usage.phase_used[Vapour]) {
+ int pos = phase_usage.phase_pos[Vapour];
+ pc[pos] = pcog_(s[pos]);
+ dpcds[np*pos + pos] = pcog_.derivative(s[pos]);
+ }
+ }
+
+
+
+
+
} // namespace Opm
diff --git a/opm/core/fluid/SatFuncStone2.hpp b/opm/core/fluid/SatFuncStone2.hpp
index ae4a6d38..532bf7ce 100644
--- a/opm/core/fluid/SatFuncStone2.hpp
+++ b/opm/core/fluid/SatFuncStone2.hpp
@@ -18,17 +18,21 @@
*/
#ifndef SATFUNCSTONE2_HPP
#define SATFUNCSTONE2_HPP
+
#include
#include
+#include
#include
#include
+
namespace Opm
{
- class SatFuncStone2: public BlackoilPhases
+ class SatFuncStone2Uniform : public BlackoilPhases
{
public:
- void init(const EclipseGridParser& deck, const int table_num, PhaseUsage phase_usg);
- void init(const EclipseGridParser& deck, const int table_num, PhaseUsage phase_usg,
+ void init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
const int samples);
void evalKr(const double* s, double* kr) const;
void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
@@ -46,5 +50,31 @@ namespace Opm
UniformTableLinear pcog_;
double krocw_; // = krow_(s_wc)
};
+
+
+ class SatFuncStone2Nonuniform : public BlackoilPhases
+ {
+ public:
+ void init(const EclipseGridParser& deck,
+ const int table_num,
+ const PhaseUsage phase_usg,
+ const int samples);
+ void evalKr(const double* s, double* kr) const;
+ void evalKrDeriv(const double* s, double* kr, double* dkrds) const;
+ void evalPc(const double* s, double* pc) const;
+ void evalPcDeriv(const double* s, double* pc, double* dpcds) const;
+ double smin_[PhaseUsage::MaxNumPhases];
+ double smax_[PhaseUsage::MaxNumPhases];
+ private:
+ PhaseUsage phase_usage; // A copy of the outer class' phase_usage_.
+ NonuniformTableLinear krw_;
+ NonuniformTableLinear krow_;
+ NonuniformTableLinear