mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #4 from atgeirr/fully-implicit
Fully implicit simulator
This commit is contained in:
commit
b0c09f73be
@ -28,10 +28,13 @@
|
||||
list (APPEND MAIN_SOURCE_FILES
|
||||
opm/autodiff/BlackoilPropsAd.cpp
|
||||
opm/autodiff/BlackoilPropsAdInterface.cpp
|
||||
opm/autodiff/FullyImplicitBlackoilSolver.cpp
|
||||
opm/autodiff/ImpesTPFAAD.cpp
|
||||
opm/autodiff/SimulatorCompressibleAd.cpp
|
||||
opm/autodiff/SimulatorFullyImplicitBlackoil.cpp
|
||||
opm/autodiff/SimulatorIncompTwophaseAdfi.cpp
|
||||
opm/autodiff/TransportSolverTwophaseAd.cpp
|
||||
opm/autodiff/BlackoilPropsAdFromDeck.cpp
|
||||
)
|
||||
|
||||
# originally generated with the command:
|
||||
@ -39,6 +42,7 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
list (APPEND TEST_SOURCE_FILES
|
||||
tests/test_block.cpp
|
||||
tests/test_boprops_ad.cpp
|
||||
tests/test_span.cpp
|
||||
tests/test_syntax.cpp
|
||||
)
|
||||
|
||||
@ -50,16 +54,19 @@ list (APPEND TEST_DATA_FILES
|
||||
# find tutorials examples -name '*.c*' -printf '\t%p\n' | sort
|
||||
list (APPEND EXAMPLE_SOURCE_FILES
|
||||
examples/find_zero.cpp
|
||||
examples/sim_fibo_ad.cpp
|
||||
examples/sim_2p_comp_ad.cpp
|
||||
examples/sim_2p_incomp_adfi.cpp
|
||||
examples/sim_simple.cpp
|
||||
examples/test_impestpfa_ad.cpp
|
||||
examples/test_implicit_ad.cpp
|
||||
)
|
||||
|
||||
# programs listed here will not only be compiled, but also marked for
|
||||
# installation
|
||||
list (APPEND PROGRAM_SOURCE_FILES
|
||||
examples/sim_2p_incomp_adfi.cpp
|
||||
examples/sim_fibo_ad.cpp
|
||||
)
|
||||
|
||||
# originally generated with the command:
|
||||
@ -69,10 +76,13 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/autodiff/AutoDiffHelpers.hpp
|
||||
opm/autodiff/AutoDiff.hpp
|
||||
opm/autodiff/BlackoilPropsAd.hpp
|
||||
opm/autodiff/BlackoilPropsAdFromDeck.hpp
|
||||
opm/autodiff/BlackoilPropsAdInterface.hpp
|
||||
opm/autodiff/GeoProps.hpp
|
||||
opm/autodiff/ImpesTPFAAD.hpp
|
||||
opm/autodiff/FullyImplicitBlackoilSolver.hpp
|
||||
opm/autodiff/SimulatorCompressibleAd.hpp
|
||||
opm/autodiff/SimulatorFullyImplicitBlackoil.hpp
|
||||
opm/autodiff/SimulatorIncompTwophaseAdfi.hpp
|
||||
opm/autodiff/TransportSolverTwophaseAd.hpp
|
||||
)
|
||||
|
301
examples/sim_fibo_ad.cpp
Normal file
301
examples/sim_fibo_ad.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <opm/core/pressure/FlowBCManager.hpp>
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/grid/GridManager.hpp>
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/wells/WellsManager.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <opm/core/simulator/initState.hpp>
|
||||
#include <opm/core/simulator/SimulatorReport.hpp>
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
#include <opm/core/utility/miscUtilities.hpp>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
|
||||
#include <opm/core/props/BlackoilPropertiesBasic.hpp>
|
||||
#include <opm/core/props/BlackoilPropertiesFromDeck.hpp>
|
||||
#include <opm/core/props/rock/RockCompressibility.hpp>
|
||||
|
||||
#include <opm/core/linalg/LinearSolverFactory.hpp>
|
||||
|
||||
#include <opm/core/simulator/BlackoilState.hpp>
|
||||
#include <opm/core/simulator/WellState.hpp>
|
||||
|
||||
#include <opm/autodiff/SimulatorFullyImplicitBlackoil.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAd.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdFromDeck.hpp>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
|
||||
|
||||
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 weakly compressible two-phase flow ===============\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<EclipseGridParser> deck;
|
||||
boost::scoped_ptr<GridManager> grid;
|
||||
boost::scoped_ptr<BlackoilPropertiesInterface> props;
|
||||
boost::scoped_ptr<BlackoilPropsAdInterface> new_props;
|
||||
boost::scoped_ptr<RockCompressibility> rock_comp;
|
||||
BlackoilState 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<std::string>("deck_filename");
|
||||
deck.reset(new EclipseGridParser(deck_filename));
|
||||
// Grid init
|
||||
grid.reset(new GridManager(*deck));
|
||||
// Rock and fluid init
|
||||
props.reset(new BlackoilPropertiesFromDeck(*deck, *grid->c_grid(), param));
|
||||
new_props.reset(new BlackoilPropsAdFromDeck(*deck, *grid->c_grid()));
|
||||
// check_well_controls = param.getDefault("check_well_controls", false);
|
||||
// max_well_control_iterations = param.getDefault("max_well_control_iterations", 10);
|
||||
// Rock compressibility.
|
||||
rock_comp.reset(new RockCompressibility(*deck));
|
||||
// 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);
|
||||
initBlackoilSurfvol(*grid->c_grid(), *props, state);
|
||||
enum { Oil = BlackoilPhases::Liquid, Gas = BlackoilPhases::Vapour };
|
||||
const PhaseUsage pu = props->phaseUsage();
|
||||
if (pu.phase_used[Oil] && pu.phase_used[Gas]) {
|
||||
const int np = props->numPhases();
|
||||
const int nc = grid->c_grid()->number_of_cells;
|
||||
for (int c = 0; c < nc; ++c) {
|
||||
state.gasoilratio()[c] = state.surfacevol()[c*np + pu.phase_pos[Gas]]
|
||||
/ state.surfacevol()[c*np + pu.phase_pos[Oil]];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
initBlackoilStateFromDeck(*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 BlackoilPropertiesBasic(param, grid->c_grid()->dimensions, grid->c_grid()->number_of_cells));
|
||||
new_props.reset(new BlackoilPropsAd(*props));
|
||||
// Rock compressibility.
|
||||
rock_comp.reset(new RockCompressibility(param));
|
||||
// Gravity.
|
||||
gravity[2] = param.getDefault("gravity", 0.0);
|
||||
// Init state variables (saturation and pressure).
|
||||
initStateBasic(*grid->c_grid(), *props, param, gravity[2], state);
|
||||
initBlackoilSurfvol(*grid->c_grid(), *props, state);
|
||||
}
|
||||
|
||||
bool use_gravity = (gravity[0] != 0.0 || gravity[1] != 0.0 || gravity[2] != 0.0);
|
||||
const double *grav = use_gravity ? &gravity[0] : 0;
|
||||
|
||||
// Initialising src
|
||||
int num_cells = grid->c_grid()->number_of_cells;
|
||||
std::vector<double> src(num_cells, 0.0);
|
||||
if (use_deck) {
|
||||
// Do nothing, wells will be the driving force, not source terms.
|
||||
} else {
|
||||
// Compute pore volumes, in order to enable specifying injection rate
|
||||
// terms of total pore volume.
|
||||
std::vector<double> porevol;
|
||||
if (rock_comp->isActive()) {
|
||||
computePorevolume(*grid->c_grid(), props->porosity(), *rock_comp, state.pressure(), porevol);
|
||||
} else {
|
||||
computePorevolume(*grid->c_grid(), props->porosity(), porevol);
|
||||
}
|
||||
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<double>("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<int>("pside");
|
||||
double pside_pressure = param.get<double>("pside_pressure");
|
||||
bcs.pressureSide(*grid->c_grid(), FlowBCManager::Side(pside), pside_pressure);
|
||||
}
|
||||
|
||||
// Linear solver.
|
||||
LinearSolverFactory linsolver(param);
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
|
||||
std::cout << "\n\n================ Starting main simulation loop ===============\n"
|
||||
<< " (number of epochs: "
|
||||
<< (use_deck ? deck->numberOfEpochs() : 1) << ")\n\n" << std::flush;
|
||||
|
||||
SimulatorReport rep;
|
||||
if (!use_deck) {
|
||||
// Simple simulation without a deck.
|
||||
WellsManager wells; // no wells.
|
||||
SimulatorFullyImplicitBlackoil simulator(param,
|
||||
*grid->c_grid(),
|
||||
*new_props,
|
||||
rock_comp->isActive() ? rock_comp.get() : 0,
|
||||
wells,
|
||||
src,
|
||||
bcs.c_bcs(),
|
||||
linsolver,
|
||||
grav);
|
||||
SimulatorTimer simtimer;
|
||||
simtimer.init(param);
|
||||
warnIfUnusedParams(param);
|
||||
WellState well_state;
|
||||
well_state.init(0, state);
|
||||
rep = simulator.run(simtimer, state, well_state);
|
||||
} else {
|
||||
// With a deck, we may have more epochs etc.
|
||||
WellState well_state;
|
||||
int step = 0;
|
||||
SimulatorTimer simtimer;
|
||||
// Use timer for last epoch to obtain total time.
|
||||
deck->setCurrentEpoch(deck->numberOfEpochs() - 1);
|
||||
simtimer.init(*deck);
|
||||
const double total_time = simtimer.totalTime();
|
||||
for (int epoch = 0; epoch < deck->numberOfEpochs(); ++epoch) {
|
||||
// Set epoch index.
|
||||
deck->setCurrentEpoch(epoch);
|
||||
|
||||
// Update the timer.
|
||||
if (deck->hasField("TSTEP")) {
|
||||
simtimer.init(*deck);
|
||||
} else {
|
||||
if (epoch != 0) {
|
||||
THROW("No TSTEP in deck for epoch " << epoch);
|
||||
}
|
||||
simtimer.init(param);
|
||||
}
|
||||
simtimer.setCurrentStepNum(step);
|
||||
simtimer.setTotalTime(total_time);
|
||||
|
||||
// Report on start of epoch.
|
||||
std::cout << "\n\n-------------- Starting epoch " << epoch << " --------------"
|
||||
<< "\n (number of steps: "
|
||||
<< simtimer.numSteps() - step << ")\n\n" << std::flush;
|
||||
|
||||
// Create new wells, well_state
|
||||
WellsManager wells(*deck, *grid->c_grid(), props->permeability());
|
||||
// @@@ HACK: we should really make a new well state and
|
||||
// properly transfer old well state to it every epoch,
|
||||
// since number of wells may change etc.
|
||||
if (epoch == 0) {
|
||||
well_state.init(wells.c_wells(), state);
|
||||
}
|
||||
|
||||
// Create and run simulator.
|
||||
SimulatorFullyImplicitBlackoil simulator(param,
|
||||
*grid->c_grid(),
|
||||
*new_props,
|
||||
rock_comp->isActive() ? rock_comp.get() : 0,
|
||||
wells,
|
||||
src,
|
||||
bcs.c_bcs(),
|
||||
linsolver,
|
||||
grav);
|
||||
if (epoch == 0) {
|
||||
warnIfUnusedParams(param);
|
||||
}
|
||||
SimulatorReport epoch_rep = simulator.run(simtimer, state, well_state);
|
||||
if (output) {
|
||||
epoch_rep.reportParam(epoch_os);
|
||||
}
|
||||
// Update total timing report and remember step number.
|
||||
rep += epoch_rep;
|
||||
step = simtimer.currentStepNum();
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n\n================ End of simulation ===============\n\n";
|
||||
rep.report(std::cout);
|
||||
|
||||
if (output) {
|
||||
std::string filename = output_dir + "/walltime.param";
|
||||
std::fstream tot_os(filename.c_str(),std::fstream::trunc | std::fstream::out);
|
||||
rep.reportParam(tot_os);
|
||||
}
|
||||
|
||||
}
|
119
examples/test_implicit_ad.cpp
Normal file
119
examples/test_implicit_ad.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2013 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media Project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <opm/autodiff/FullyImplicitBlackoilSolver.hpp>
|
||||
#include <opm/autodiff/GeoProps.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAd.hpp>
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/wells.h>
|
||||
|
||||
#include <opm/core/grid/GridManager.hpp>
|
||||
|
||||
#include <opm/core/linalg/LinearSolverFactory.hpp>
|
||||
|
||||
#include <opm/core/props/BlackoilPropertiesBasic.hpp>
|
||||
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
|
||||
#include <opm/core/simulator/BlackoilState.hpp>
|
||||
#include <opm/core/simulator/WellState.hpp>
|
||||
#include <opm/core/simulator/initState.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace {
|
||||
boost::shared_ptr<Wells>
|
||||
createWellConfig()
|
||||
{
|
||||
boost::shared_ptr<Wells> wells(create_wells(2, 2, 2),
|
||||
destroy_wells);
|
||||
|
||||
const double inj_frac[] = { 1.0, 0.0 };
|
||||
const double prod_frac[] = { 0.0, 0.0 };
|
||||
const int num_inj = 1;
|
||||
const int inj_cells[num_inj] = { 0 };
|
||||
const int num_prod = 1;
|
||||
const int prod_cells[num_prod] = { 19 };
|
||||
const double WI[3] = { 1e-12, 1e-12, 1e-12 };
|
||||
bool ok = add_well(INJECTOR, 0.0, num_inj, inj_frac, inj_cells, WI, "Inj", wells.get());
|
||||
ok = ok && add_well(PRODUCER, 0.0, num_prod, prod_frac, prod_cells, WI, "Prod", wells.get());
|
||||
ok = ok && append_well_controls(BHP, 500.0*Opm::unit::barsa, 0, 0, wells.get());
|
||||
// ok = ok && append_well_controls(BHP, 200.0*Opm::unit::barsa, 0, 1, wells);
|
||||
double oildistr[2] = { 0.0, 1.0 };
|
||||
ok = ok && append_well_controls(SURFACE_RATE, 1e-3, oildistr, 1, wells.get());
|
||||
if (!ok) {
|
||||
THROW("Something went wrong with well init.");
|
||||
}
|
||||
set_current_control(0, 0, wells.get());
|
||||
set_current_control(1, 0, wells.get());
|
||||
|
||||
return wells;
|
||||
}
|
||||
|
||||
template <class Ostream, typename T, class A>
|
||||
Ostream&
|
||||
operator<<(Ostream& os, const std::vector<T,A>& v)
|
||||
{
|
||||
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(os, " "));
|
||||
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
const Opm::parameter::ParameterGroup param(argc, argv, false);
|
||||
const Opm::GridManager gm(20, 1);
|
||||
|
||||
const UnstructuredGrid* g = gm.c_grid();
|
||||
const int nc = g->number_of_cells;
|
||||
const Opm::BlackoilPropertiesBasic props0(param, 2, nc);
|
||||
const Opm::BlackoilPropsAd props(props0);
|
||||
|
||||
boost::shared_ptr<Wells> wells = createWellConfig();
|
||||
|
||||
double grav[] = { 0.0, 0.0 };
|
||||
Opm::DerivedGeology geo(*g, props, grav);
|
||||
|
||||
Opm::LinearSolverFactory linsolver(param);
|
||||
|
||||
Opm::FullyImplicitBlackoilSolver solver(*g, props, geo, *wells, linsolver);
|
||||
|
||||
Opm::BlackoilState state;
|
||||
initStateBasic(*g, props0, param, 0.0, state);
|
||||
initBlackoilSurfvol(*g, props0, state);
|
||||
|
||||
Opm::WellState well_state;
|
||||
well_state.init(wells.get(), state);
|
||||
|
||||
solver.step(1.0, state, well_state);
|
||||
|
||||
std::cout << state.pressure() << '\n'
|
||||
<< well_state.bhp() << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
@ -98,6 +98,24 @@ namespace AutoDiff
|
||||
return vars;
|
||||
}
|
||||
|
||||
/// Operator +=
|
||||
ForwardBlock& operator+=(const ForwardBlock& rhs)
|
||||
{
|
||||
assert (numBlocks() == rhs.numBlocks());
|
||||
assert (value().size() == rhs.value().size());
|
||||
|
||||
const int num_blocks = numBlocks();
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
assert(jac_[block].rows() == rhs.jac_[block].rows());
|
||||
assert(jac_[block].cols() == rhs.jac_[block].cols());
|
||||
jac_[block] += rhs.jac_[block];
|
||||
}
|
||||
|
||||
val_ += rhs.val_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Operator +
|
||||
ForwardBlock operator+(const ForwardBlock& rhs) const
|
||||
{
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
// -------------------- class HelperOps --------------------
|
||||
|
||||
@ -98,9 +98,8 @@ struct HelperOps
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
#include <cstdio>
|
||||
#endif // !defined(NDEBUG)
|
||||
#include <string>
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
namespace {
|
||||
void
|
||||
printSparseMatrix(const Eigen::SparseMatrix<double>& A,
|
||||
@ -134,6 +133,39 @@ namespace {
|
||||
|
||||
std::fclose(fp);
|
||||
}
|
||||
|
||||
void
|
||||
writeAsMATLAB(const std::vector< Eigen::SparseMatrix<double> >& vA,
|
||||
std::FILE* fp ,
|
||||
const char* const vname)
|
||||
{
|
||||
const int n = static_cast<int>(vA.size());
|
||||
|
||||
fprintf(fp, "%s = cell([1, %d]);\n\n", vname, n);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
fprintf(fp, "%s{%d} = spconvert([\n", vname, i + 1);
|
||||
printSparseMatrix(vA[i], fp);
|
||||
const int rows = vA[i].rows();
|
||||
const int cols = vA[i].cols();
|
||||
fprintf(fp, "%d %d 0.0]);\n\n", rows, cols);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
writeAsMATLAB(const std::vector< Eigen::SparseMatrix<double> >& vA,
|
||||
const char* const fn ,
|
||||
const char* const vname)
|
||||
{
|
||||
std::FILE* fp;
|
||||
|
||||
fp = std::fopen(fn, "w");
|
||||
if (fp != 0) {
|
||||
writeAsMATLAB(vA, fp, vname);
|
||||
}
|
||||
|
||||
std::fclose(fp);
|
||||
}
|
||||
} // anonymous namespace
|
||||
#endif // !defined(NDEBUG)
|
||||
|
||||
@ -424,4 +456,110 @@ vertcat(const AutoDiff::ForwardBlock<double>& x,
|
||||
|
||||
|
||||
|
||||
class Span
|
||||
{
|
||||
public:
|
||||
explicit Span(const int num)
|
||||
: num_(num),
|
||||
stride_(1),
|
||||
start_(0)
|
||||
{
|
||||
}
|
||||
Span(const int num, const int stride, const int start)
|
||||
: num_(num),
|
||||
stride_(stride),
|
||||
start_(start)
|
||||
{
|
||||
}
|
||||
int operator[](const int i) const
|
||||
{
|
||||
ASSERT(i >= 0 && i < num_);
|
||||
return start_ + i*stride_;
|
||||
}
|
||||
int size() const
|
||||
{
|
||||
return num_;
|
||||
}
|
||||
|
||||
|
||||
class SpanIterator
|
||||
{
|
||||
public:
|
||||
SpanIterator(const Span* span, const int index)
|
||||
: span_(span),
|
||||
index_(index)
|
||||
{
|
||||
}
|
||||
SpanIterator operator++()
|
||||
{
|
||||
++index_;
|
||||
return *this;
|
||||
}
|
||||
SpanIterator operator++(int)
|
||||
{
|
||||
SpanIterator before_increment(*this);
|
||||
++index_;
|
||||
return before_increment;
|
||||
}
|
||||
bool operator<(const SpanIterator& rhs) const
|
||||
{
|
||||
ASSERT(span_ == rhs.span_);
|
||||
return index_ < rhs.index_;
|
||||
}
|
||||
bool operator==(const SpanIterator& rhs) const
|
||||
{
|
||||
ASSERT(span_ == rhs.span_);
|
||||
return index_ == rhs.index_;
|
||||
}
|
||||
bool operator!=(const SpanIterator& rhs) const
|
||||
{
|
||||
ASSERT(span_ == rhs.span_);
|
||||
return index_ != rhs.index_;
|
||||
}
|
||||
int operator*()
|
||||
{
|
||||
return (*span_)[index_];
|
||||
}
|
||||
private:
|
||||
const Span* span_;
|
||||
int index_;
|
||||
};
|
||||
|
||||
typedef SpanIterator iterator;
|
||||
typedef SpanIterator const_iterator;
|
||||
|
||||
SpanIterator begin() const
|
||||
{
|
||||
return SpanIterator(this, 0);
|
||||
}
|
||||
|
||||
SpanIterator end() const
|
||||
{
|
||||
return SpanIterator(this, num_);
|
||||
}
|
||||
|
||||
bool operator==(const Span& rhs)
|
||||
{
|
||||
return num_ == rhs.num_ && start_ == rhs.start_ && stride_ == rhs.stride_;
|
||||
}
|
||||
|
||||
private:
|
||||
const int num_;
|
||||
const int stride_;
|
||||
const int start_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Return a vector of (-1.0, 0.0 or 1.0), depending on sign per element.
|
||||
inline Eigen::ArrayXd sign (const Eigen::ArrayXd& x)
|
||||
{
|
||||
const int n = x.size();
|
||||
Eigen::ArrayXd retval(n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
retval[i] = x[i] < 0.0 ? -1.0 : (x[i] > 0.0 ? 1.0 : 0.0);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif // OPM_AUTODIFFHELPERS_HEADER_INCLUDED
|
||||
|
@ -75,6 +75,17 @@ namespace Opm
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
int BlackoilPropsAd::numPhases() const
|
||||
{
|
||||
return props_.numPhases();
|
||||
}
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
PhaseUsage BlackoilPropsAd::phaseUsage() const
|
||||
{
|
||||
return props_.phaseUsage();
|
||||
}
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
@ -160,6 +171,9 @@ namespace Opm
|
||||
ADB BlackoilPropsAd::muWat(const ADB& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
#if 1
|
||||
return ADB::constant(muWat(pw.value(), cells), pw.blockPattern());
|
||||
#else
|
||||
if (!pu_.phase_used[Water]) {
|
||||
THROW("Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
@ -177,6 +191,7 @@ namespace Opm
|
||||
jacs[block] = dmu_diag * pw.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu.col(pu_.phase_pos[Water]), jacs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Oil viscosity.
|
||||
@ -188,6 +203,9 @@ namespace Opm
|
||||
const ADB& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
#if 1
|
||||
return ADB::constant(muOil(po.value(), rs.value(), cells), po.blockPattern());
|
||||
#else
|
||||
if (!pu_.phase_used[Oil]) {
|
||||
THROW("Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
@ -214,6 +232,7 @@ namespace Opm
|
||||
jacs[block] = dmu_diag * po.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu.col(pu_.phase_pos[Oil]), jacs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Gas viscosity.
|
||||
@ -223,6 +242,9 @@ namespace Opm
|
||||
ADB BlackoilPropsAd::muGas(const ADB& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
#if 1
|
||||
return ADB::constant(muGas(pg.value(), cells), pg.blockPattern());
|
||||
#else
|
||||
if (!pu_.phase_used[Gas]) {
|
||||
THROW("Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
@ -240,6 +262,7 @@ namespace Opm
|
||||
jacs[block] = dmu_diag * pg.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu.col(pu_.phase_pos[Gas]), jacs);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -424,7 +447,6 @@ namespace Opm
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// ------ Rs bubble point curve ------
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
@ -434,6 +456,7 @@ namespace Opm
|
||||
V BlackoilPropsAd::rsMax(const V& po,
|
||||
const Cells& cells) const
|
||||
{
|
||||
THROW("Method rsMax() not implemented.");
|
||||
}
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
@ -443,8 +466,8 @@ namespace Opm
|
||||
ADB BlackoilPropsAd::rsMax(const ADB& po,
|
||||
const Cells& cells) const
|
||||
{
|
||||
THROW("Method rsMax() not implemented.");
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
|
@ -71,6 +71,11 @@ namespace Opm
|
||||
typedef ADB::V V;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
virtual int numPhases() const;
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
virtual PhaseUsage phaseUsage() const;
|
||||
|
||||
// ------ Canonical named indices for each phase ------
|
||||
|
||||
@ -184,7 +189,7 @@ namespace Opm
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
#if 0
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
@ -198,7 +203,7 @@ namespace Opm
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
ADB rsMax(const ADB& po,
|
||||
const Cells& cells) const;
|
||||
#endif
|
||||
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
|
682
opm/autodiff/BlackoilPropsAdFromDeck.cpp
Normal file
682
opm/autodiff/BlackoilPropsAdFromDeck.cpp
Normal file
@ -0,0 +1,682 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <opm/autodiff/BlackoilPropsAdFromDeck.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/core/props/BlackoilPropertiesInterface.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtInterface.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtConstCompr.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtDead.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtDeadSpline.hpp>
|
||||
#include <opm/core/props/pvt/SinglePvtLiveOil.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
// Making these typedef to make the code more readable.
|
||||
typedef BlackoilPropsAdFromDeck::ADB ADB;
|
||||
typedef BlackoilPropsAdFromDeck::V V;
|
||||
typedef Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> Block;
|
||||
enum { Aqua = BlackoilPhases::Aqua,
|
||||
Liquid = BlackoilPhases::Liquid,
|
||||
Vapour = BlackoilPhases::Vapour };
|
||||
|
||||
/// Constructor wrapping an opm-core black oil interface.
|
||||
BlackoilPropsAdFromDeck::BlackoilPropsAdFromDeck(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
const bool init_rock)
|
||||
{
|
||||
if (init_rock){
|
||||
rock_.init(deck, grid);
|
||||
}
|
||||
const int samples = 0;
|
||||
const int region_number = 0;
|
||||
|
||||
phase_usage_ = phaseUsageFromDeck(deck);
|
||||
|
||||
// Surface densities. Accounting for different orders in eclipse and our code.
|
||||
if (deck.hasField("DENSITY")) {
|
||||
const std::vector<double>& d = deck.getDENSITY().densities_[region_number];
|
||||
enum { ECL_oil = 0, ECL_water = 1, ECL_gas = 2 };
|
||||
if (phase_usage_.phase_used[Aqua]) {
|
||||
densities_[phase_usage_.phase_pos[Aqua]] = d[ECL_water];
|
||||
}
|
||||
if (phase_usage_.phase_used[Vapour]) {
|
||||
densities_[phase_usage_.phase_pos[Vapour]] = d[ECL_gas];
|
||||
}
|
||||
if (phase_usage_.phase_used[Liquid]) {
|
||||
densities_[phase_usage_.phase_pos[Liquid]] = d[ECL_oil];
|
||||
}
|
||||
} else {
|
||||
THROW("Input is missing DENSITY\n");
|
||||
}
|
||||
|
||||
// Set the properties.
|
||||
props_.resize(phase_usage_.num_phases);
|
||||
// Water PVT
|
||||
if (phase_usage_.phase_used[Aqua]) {
|
||||
if (deck.hasField("PVTW")) {
|
||||
props_[phase_usage_.phase_pos[Aqua]].reset(new SinglePvtConstCompr(deck.getPVTW().pvtw_));
|
||||
} else {
|
||||
// Eclipse 100 default.
|
||||
props_[phase_usage_.phase_pos[Aqua]].reset(new SinglePvtConstCompr(0.5*Opm::prefix::centi*Opm::unit::Poise));
|
||||
}
|
||||
}
|
||||
// Oil PVT
|
||||
if (phase_usage_.phase_used[Liquid]) {
|
||||
if (deck.hasField("PVDO")) {
|
||||
if (samples > 0) {
|
||||
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDeadSpline(deck.getPVDO().pvdo_, samples));
|
||||
} else {
|
||||
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtDead(deck.getPVDO().pvdo_));
|
||||
}
|
||||
} else if (deck.hasField("PVTO")) {
|
||||
|
||||
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtLiveOil(deck.getPVTO().pvto_));
|
||||
} else if (deck.hasField("PVCDO")) {
|
||||
props_[phase_usage_.phase_pos[Liquid]].reset(new SinglePvtConstCompr(deck.getPVCDO().pvcdo_));
|
||||
} else {
|
||||
THROW("Input is missing PVDO or PVTO\n");
|
||||
}
|
||||
}
|
||||
// Gas PVT
|
||||
if (phase_usage_.phase_used[Vapour]) {
|
||||
if (deck.hasField("PVDG")) {
|
||||
if (samples > 0) {
|
||||
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDeadSpline(deck.getPVDG().pvdg_, samples));
|
||||
} else {
|
||||
props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtDead(deck.getPVDG().pvdg_));
|
||||
}
|
||||
// } else if (deck.hasField("PVTG")) {
|
||||
// props_[phase_usage_.phase_pos[Vapour]].reset(new SinglePvtLiveGas(deck.getPVTG().pvtg_));
|
||||
} else {
|
||||
THROW("Input is missing PVDG or PVTG\n");
|
||||
}
|
||||
}
|
||||
|
||||
SaturationPropsFromDeck<SatFuncGwsegNonuniform>* ptr
|
||||
= new SaturationPropsFromDeck<SatFuncGwsegNonuniform>();
|
||||
satprops_.reset(ptr);
|
||||
ptr->init(deck, grid, -1);
|
||||
|
||||
if (phase_usage_.num_phases != satprops_->numPhases()) {
|
||||
THROW("BlackoilPropsAdFromDeck::BlackoilPropsAdFromDeck() - "
|
||||
"Inconsistent number of phases in pvt data (" << phase_usage_.num_phases
|
||||
<< ") and saturation-dependent function data (" << satprops_->numPhases() << ").");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int BlackoilPropsAdFromDeck::numDimensions() const
|
||||
{
|
||||
return rock_.numDimensions();
|
||||
}
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int BlackoilPropsAdFromDeck::numCells() const
|
||||
{
|
||||
return rock_.numCells();
|
||||
}
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* BlackoilPropsAdFromDeck::porosity() const
|
||||
{
|
||||
return rock_.porosity();
|
||||
}
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* BlackoilPropsAdFromDeck::permeability() const
|
||||
{
|
||||
return rock_.permeability();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
int BlackoilPropsAdFromDeck::numPhases() const
|
||||
{
|
||||
return phase_usage_.num_phases;
|
||||
}
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
PhaseUsage BlackoilPropsAdFromDeck::phaseUsage() const
|
||||
{
|
||||
return phase_usage_;
|
||||
}
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
/// \return Array of 3 density values.
|
||||
const double* BlackoilPropsAdFromDeck::surfaceDensity() const
|
||||
{
|
||||
return densities_;
|
||||
}
|
||||
|
||||
|
||||
// ------ Viscosity ------
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAdFromDeck::muWat(const V& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Water]) {
|
||||
THROW("Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(pw.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Water]]->mu(n, pw.data(), rs,
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
return mu;
|
||||
}
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAdFromDeck::muOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
THROW("Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(po.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
|
||||
props_[phase_usage_.phase_pos[Oil]]->mu(n, po.data(), rs.data(),
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
return mu;
|
||||
}
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V BlackoilPropsAdFromDeck::muGas(const V& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Gas]) {
|
||||
THROW("Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(pg.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Gas]]->mu(n, pg.data(), rs,
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
return mu;
|
||||
}
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAdFromDeck::muWat(const ADB& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Water]) {
|
||||
THROW("Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(pw.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Water]]->mu(n, pw.value().data(), rs,
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
ADB::M dmudp_diag = spdiag(dmudp);
|
||||
const int num_blocks = pw.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dmudp_diag * pw.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu, jacs);
|
||||
}
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAdFromDeck::muOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
THROW("Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(po.size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
|
||||
props_[phase_usage_.phase_pos[Oil]]->mu(n, po.value().data(), rs.value().data(),
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
|
||||
ADB::M dmudp_diag = spdiag(dmudp);
|
||||
ADB::M dmudr_diag = spdiag(dmudr);
|
||||
const int num_blocks = po.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dmudp_diag * po.derivative()[block] + dmudr_diag * rs.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu, jacs);
|
||||
}
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB BlackoilPropsAdFromDeck::muGas(const ADB& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Gas]) {
|
||||
THROW("Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(pg.value().size() == n);
|
||||
V mu(n);
|
||||
V dmudp(n);
|
||||
V dmudr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Gas]]->mu(n, pg.value().data(), rs,
|
||||
mu.data(), dmudp.data(), dmudr.data());
|
||||
|
||||
ADB::M dmudp_diag = spdiag(dmudp);
|
||||
const int num_blocks = pg.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dmudp_diag * pg.derivative()[block];
|
||||
}
|
||||
return ADB::function(mu, jacs);
|
||||
}
|
||||
|
||||
|
||||
// ------ Formation volume factor (b) ------
|
||||
|
||||
// These methods all call the matrix() method, after which the variable
|
||||
// (also) called 'matrix' contains, in each row, the A = RB^{-1} matrix for
|
||||
// a cell. For three-phase black oil:
|
||||
// A = [ bw 0 0
|
||||
// 0 bo 0
|
||||
// 0 b0*rs bw ]
|
||||
// Where b = B^{-1}.
|
||||
// Therefore, we extract the correct diagonal element, and are done.
|
||||
// When we need the derivatives (w.r.t. p, since we don't do w.r.t. rs),
|
||||
// we also get the following derivative matrix:
|
||||
// A = [ dbw 0 0
|
||||
// 0 dbo 0
|
||||
// 0 db0*rs dbw ]
|
||||
// Again, we just extract a diagonal element.
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAdFromDeck::bWat(const V& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Water]) {
|
||||
THROW("Cannot call bWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(pw.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Water]]->b(n, pw.data(), rs,
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAdFromDeck::bOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
THROW("Cannot call bOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(po.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
|
||||
props_[phase_usage_.phase_pos[Oil]]->b(n, po.data(), rs.data(),
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V BlackoilPropsAdFromDeck::bGas(const V& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Gas]) {
|
||||
THROW("Cannot call bGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(pg.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Gas]]->b(n, pg.data(), rs,
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAdFromDeck::bWat(const ADB& pw,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Water]) {
|
||||
THROW("Cannot call muWat(): water phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(pw.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Water]]->b(n, pw.value().data(), rs,
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
ADB::M dbdp_diag = spdiag(dbdp);
|
||||
const int num_blocks = pw.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dbdp_diag * pw.derivative()[block];
|
||||
}
|
||||
return ADB::function(b, jacs);
|
||||
}
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAdFromDeck::bOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
THROW("Cannot call muOil(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(po.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
|
||||
props_[phase_usage_.phase_pos[Oil]]->b(n, po.value().data(), rs.value().data(),
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
ADB::M dbdp_diag = spdiag(dbdp);
|
||||
ADB::M dbdr_diag = spdiag(dbdr);
|
||||
const int num_blocks = po.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dbdp_diag * po.derivative()[block] + dbdr_diag * rs.derivative()[block];
|
||||
}
|
||||
return ADB::function(b, jacs);
|
||||
}
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB BlackoilPropsAdFromDeck::bGas(const ADB& pg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Gas]) {
|
||||
THROW("Cannot call muGas(): gas phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(pg.size() == n);
|
||||
|
||||
V b(n);
|
||||
V dbdp(n);
|
||||
V dbdr(n);
|
||||
const double* rs = 0;
|
||||
|
||||
props_[phase_usage_.phase_pos[Gas]]->b(n, pg.value().data(), rs,
|
||||
b.data(), dbdp.data(), dbdr.data());
|
||||
|
||||
ADB::M dbdp_diag = spdiag(dbdp);
|
||||
const int num_blocks = pg.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = dbdp_diag * pg.derivative()[block];
|
||||
}
|
||||
return ADB::function(b, jacs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
V BlackoilPropsAdFromDeck::rsMax(const V& po,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
THROW("Cannot call rsMax(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(po.size() == n);
|
||||
V rbub(n);
|
||||
V drbubdp(n);
|
||||
props_[Oil]->rbub(n, po.data(), rbub.data(), drbubdp.data());
|
||||
return rbub;
|
||||
}
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
ADB BlackoilPropsAdFromDeck::rsMax(const ADB& po,
|
||||
const Cells& cells) const
|
||||
{
|
||||
if (!phase_usage_.phase_used[Oil]) {
|
||||
THROW("Cannot call rsMax(): oil phase not present.");
|
||||
}
|
||||
const int n = cells.size();
|
||||
ASSERT(po.size() == n);
|
||||
V rbub(n);
|
||||
V drbubdp(n);
|
||||
props_[Oil]->rbub(n, po.value().data(), rbub.data(), drbubdp.data());
|
||||
ADB::M drbubdp_diag = spdiag(drbubdp);
|
||||
const int num_blocks = po.numBlocks();
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = drbubdp_diag * po.derivative()[block];
|
||||
}
|
||||
return ADB::function(rbub, jacs);
|
||||
}
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<V> BlackoilPropsAdFromDeck::relperm(const V& sw,
|
||||
const V& so,
|
||||
const V& sg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = numPhases();
|
||||
Block s_all(n, np);
|
||||
if (phase_usage_.phase_used[Water]) {
|
||||
ASSERT(sw.size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Water]) = sw;
|
||||
}
|
||||
if (phase_usage_.phase_used[Oil]) {
|
||||
ASSERT(so.size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Oil]) = so;
|
||||
}
|
||||
if (phase_usage_.phase_used[Gas]) {
|
||||
ASSERT(sg.size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Gas]) = sg;
|
||||
}
|
||||
Block kr(n, np);
|
||||
satprops_->relperm(n, s_all.data(), cells.data(), kr.data(), 0);
|
||||
std::vector<V> relperms;
|
||||
relperms.reserve(3);
|
||||
for (int phase = 0; phase < 3; ++phase) {
|
||||
if (phase_usage_.phase_used[phase]) {
|
||||
relperms.emplace_back(kr.col(phase_usage_.phase_pos[phase]));
|
||||
} else {
|
||||
relperms.emplace_back();
|
||||
}
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<ADB> BlackoilPropsAdFromDeck::relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const
|
||||
{
|
||||
const int n = cells.size();
|
||||
const int np = numPhases();
|
||||
Block s_all(n, np);
|
||||
if (phase_usage_.phase_used[Water]) {
|
||||
ASSERT(sw.value().size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Water]) = sw.value();
|
||||
}
|
||||
if (phase_usage_.phase_used[Oil]) {
|
||||
ASSERT(so.value().size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Oil]) = so.value();
|
||||
} else {
|
||||
THROW("BlackoilPropsAdFromDeck::relperm() assumes oil phase is active.");
|
||||
}
|
||||
if (phase_usage_.phase_used[Gas]) {
|
||||
ASSERT(sg.value().size() == n);
|
||||
s_all.col(phase_usage_.phase_pos[Gas]) = sg.value();
|
||||
}
|
||||
Block kr(n, np);
|
||||
Block dkr(n, np*np);
|
||||
satprops_->relperm(n, s_all.data(), cells.data(), kr.data(), dkr.data());
|
||||
const int num_blocks = so.numBlocks();
|
||||
std::vector<ADB> relperms;
|
||||
relperms.reserve(3);
|
||||
typedef const ADB* ADBPtr;
|
||||
ADBPtr s[3] = { &sw, &so, &sg };
|
||||
for (int phase1 = 0; phase1 < 3; ++phase1) {
|
||||
if (phase_usage_.phase_used[phase1]) {
|
||||
const int phase1_pos = phase_usage_.phase_pos[phase1];
|
||||
std::vector<ADB::M> jacs(num_blocks);
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] = ADB::M(n, s[phase1]->derivative()[block].cols());
|
||||
}
|
||||
for (int phase2 = 0; phase2 < 3; ++phase2) {
|
||||
if (!phase_usage_.phase_used[phase2]) {
|
||||
continue;
|
||||
}
|
||||
const int phase2_pos = phase_usage_.phase_pos[phase2];
|
||||
// Assemble dkr1/ds2.
|
||||
const int column = phase1_pos + np*phase2_pos; // Recall: Fortran ordering from props_.relperm()
|
||||
ADB::M dkr1_ds2_diag = spdiag(dkr.col(column));
|
||||
for (int block = 0; block < num_blocks; ++block) {
|
||||
jacs[block] += dkr1_ds2_diag * s[phase2]->derivative()[block];
|
||||
}
|
||||
}
|
||||
relperms.emplace_back(ADB::function(kr.col(phase1_pos), jacs));
|
||||
} else {
|
||||
relperms.emplace_back(ADB::null());
|
||||
}
|
||||
}
|
||||
return relperms;
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
251
opm/autodiff/BlackoilPropsAdFromDeck.hpp
Normal file
251
opm/autodiff/BlackoilPropsAdFromDeck.hpp
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_BLACKOILPROPSADFROMDECK_HEADER_INCLUDED
|
||||
#define OPM_BLACKOILPROPSADFROMDECK_HEADER_INCLUDED
|
||||
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/core/props/BlackoilPhases.hpp>
|
||||
#include <opm/core/props/satfunc/SaturationPropsFromDeck.hpp>
|
||||
#include <opm/core/io/eclipse/EclipseGridParser.hpp>
|
||||
#include <opm/core/props/rock/RockFromDeck.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
class SinglePvtInterface;
|
||||
|
||||
/// This class is intended to present a fluid interface for
|
||||
/// three-phase black-oil that is easy to use with the AD-using
|
||||
/// simulators.
|
||||
///
|
||||
/// Most methods are available in two overloaded versions, one
|
||||
/// taking a constant vector and returning the same, and one
|
||||
/// taking an AD type and returning the same. Derivatives are not
|
||||
/// returned separately by any method, only implicitly with the AD
|
||||
/// version of the methods.
|
||||
class BlackoilPropsAdFromDeck : public BlackoilPropsAdInterface
|
||||
{
|
||||
public:
|
||||
/// Constructor wrapping an opm-core black oil interface.
|
||||
BlackoilPropsAdFromDeck(const EclipseGridParser& deck,
|
||||
const UnstructuredGrid& grid,
|
||||
const bool init_rock = true );
|
||||
|
||||
////////////////////////////
|
||||
// Rock interface //
|
||||
////////////////////////////
|
||||
|
||||
/// \return D, the number of spatial dimensions.
|
||||
int numDimensions() const;
|
||||
|
||||
/// \return N, the number of cells.
|
||||
int numCells() const;
|
||||
|
||||
/// \return Array of N porosity values.
|
||||
const double* porosity() const;
|
||||
|
||||
/// \return Array of ND^2 permeability values.
|
||||
/// The D^2 permeability values for a cell are organized as a matrix,
|
||||
/// which is symmetric (so ordering does not matter).
|
||||
const double* permeability() const;
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// Fluid interface //
|
||||
////////////////////////////
|
||||
|
||||
typedef AutoDiff::ForwardBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
int numPhases() const;
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
PhaseUsage phaseUsage() const;
|
||||
|
||||
// ------ Canonical named indices for each phase ------
|
||||
|
||||
/// Canonical named indices for each phase.
|
||||
enum PhaseIndex { Water = 0, Oil = 1, Gas = 2 };
|
||||
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
/// \return Array of 3 density values.
|
||||
const double* surfaceDensity() const;
|
||||
|
||||
|
||||
// ------ Viscosity ------
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muWat(const V& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
V muGas(const V& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Water viscosity.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muWat(const ADB& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil viscosity.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas viscosity.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n viscosity values.
|
||||
ADB muGas(const ADB& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Formation volume factor (b) ------
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bWat(const V& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bOil(const V& po,
|
||||
const V& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
V bGas(const V& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Water formation volume factor.
|
||||
/// \param[in] pw Array of n water pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bWat(const ADB& pw,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Oil formation volume factor.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] rs Array of n gas solution factor values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bOil(const ADB& po,
|
||||
const ADB& rs,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Gas formation volume factor.
|
||||
/// \param[in] pg Array of n gas pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n formation volume factor values.
|
||||
ADB bGas(const ADB& pg,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
V rsMax(const V& po,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
/// \return Array of n bubble point values for Rs.
|
||||
ADB rsMax(const ADB& po,
|
||||
const Cells& cells) const;
|
||||
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<V> relperm(const V& sw,
|
||||
const V& so,
|
||||
const V& sg,
|
||||
const Cells& cells) const;
|
||||
|
||||
/// Relative permeabilities for all phases.
|
||||
/// \param[in] sw Array of n water saturation values.
|
||||
/// \param[in] so Array of n oil saturation values.
|
||||
/// \param[in] sg Array of n gas saturation values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the saturation values.
|
||||
/// \return An std::vector with 3 elements, each an array of n relperm values,
|
||||
/// containing krw, kro, krg. Use PhaseIndex for indexing into the result.
|
||||
std::vector<ADB> relperm(const ADB& sw,
|
||||
const ADB& so,
|
||||
const ADB& sg,
|
||||
const Cells& cells) const;
|
||||
|
||||
private:
|
||||
RockFromDeck rock_;
|
||||
boost::scoped_ptr<SaturationPropsInterface> satprops_;
|
||||
PhaseUsage phase_usage_;
|
||||
std::vector<std::tr1::shared_ptr<SinglePvtInterface> > props_;
|
||||
double densities_[BlackoilPhases::MaxNumPhases];
|
||||
};
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_BLACKOILPROPSADFROMDECK_HEADER_INCLUDED
|
@ -69,13 +69,17 @@ namespace Opm
|
||||
typedef ADB::M M;
|
||||
typedef std::vector<int> Cells;
|
||||
|
||||
/// \return Number of active phases (also the number of components).
|
||||
virtual int numPhases() const = 0;
|
||||
|
||||
/// \return Object describing the active phases.
|
||||
virtual PhaseUsage phaseUsage() const = 0;
|
||||
|
||||
// ------ Canonical named indices for each phase ------
|
||||
|
||||
/// Canonical named indices for each phase.
|
||||
enum PhaseIndex { Water = 0, Oil = 1, Gas = 2 };
|
||||
|
||||
|
||||
// ------ Density ------
|
||||
|
||||
/// Densities of stock components at surface conditions.
|
||||
@ -194,7 +198,7 @@ namespace Opm
|
||||
|
||||
|
||||
// ------ Rs bubble point curve ------
|
||||
#if 0
|
||||
|
||||
/// Bubble point curve for Rs as function of oil pressure.
|
||||
/// \param[in] po Array of n oil pressure values.
|
||||
/// \param[in] cells Array of n cell indices to be associated with the pressure values.
|
||||
@ -210,7 +214,6 @@ namespace Opm
|
||||
virtual
|
||||
ADB rsMax(const ADB& po,
|
||||
const Cells& cells) const = 0;
|
||||
#endif
|
||||
|
||||
// ------ Relative permeability ------
|
||||
|
||||
|
1126
opm/autodiff/FullyImplicitBlackoilSolver.cpp
Normal file
1126
opm/autodiff/FullyImplicitBlackoilSolver.cpp
Normal file
File diff suppressed because it is too large
Load Diff
194
opm/autodiff/FullyImplicitBlackoilSolver.hpp
Normal file
194
opm/autodiff/FullyImplicitBlackoilSolver.hpp
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_FULLYIMPLICITBLACKOILSOLVER_HEADER_INCLUDED
|
||||
#define OPM_FULLYIMPLICITBLACKOILSOLVER_HEADER_INCLUDED
|
||||
|
||||
#include <opm/autodiff/AutoDiffBlock.hpp>
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
struct Wells;
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class DerivedGeology;
|
||||
class LinearSolverInterface;
|
||||
class BlackoilState;
|
||||
class WellState;
|
||||
|
||||
|
||||
/// A fully implicit TPFA-based solver for the black-oil problem.
|
||||
class FullyImplicitBlackoilSolver
|
||||
{
|
||||
public:
|
||||
FullyImplicitBlackoilSolver(const UnstructuredGrid& grid ,
|
||||
const BlackoilPropsAdInterface& fluid,
|
||||
const DerivedGeology& geo ,
|
||||
const Wells& wells,
|
||||
const LinearSolverInterface& linsolver);
|
||||
|
||||
/// Take a single forward step, modifiying
|
||||
/// state.pressure()
|
||||
/// state.faceflux()
|
||||
/// state.saturation()
|
||||
/// state.gasoilratio()
|
||||
/// wstate.bhp()
|
||||
void
|
||||
step(const double dt ,
|
||||
BlackoilState& state ,
|
||||
WellState& wstate);
|
||||
|
||||
private:
|
||||
// Types and enums
|
||||
typedef AutoDiff::ForwardBlock<double> ADB;
|
||||
typedef ADB::V V;
|
||||
typedef ADB::M M;
|
||||
typedef Eigen::Array<double,
|
||||
Eigen::Dynamic,
|
||||
Eigen::Dynamic,
|
||||
Eigen::RowMajor> DataBlock;
|
||||
|
||||
struct ReservoirResidualQuant {
|
||||
ReservoirResidualQuant();
|
||||
std::vector<ADB> accum; // Accumulations
|
||||
ADB mflux; // Mass flux (surface conditions)
|
||||
ADB b; // Reciprocal FVF
|
||||
ADB head; // Pressure drop across int. interfaces
|
||||
ADB mob; // Phase mobility (per cell)
|
||||
};
|
||||
|
||||
struct SolutionState {
|
||||
SolutionState(const int np);
|
||||
ADB pressure;
|
||||
std::vector<ADB> saturation;
|
||||
ADB rs;
|
||||
ADB qs;
|
||||
ADB bhp;
|
||||
};
|
||||
|
||||
struct WellOps {
|
||||
WellOps(const Wells& wells);
|
||||
M w2p; // well -> perf (scatter)
|
||||
M p2w; // perf -> well (gather)
|
||||
};
|
||||
|
||||
enum { Water = BlackoilPropsAdInterface::Water,
|
||||
Oil = BlackoilPropsAdInterface::Oil ,
|
||||
Gas = BlackoilPropsAdInterface::Gas };
|
||||
|
||||
// Member data
|
||||
const UnstructuredGrid& grid_;
|
||||
const BlackoilPropsAdInterface& fluid_;
|
||||
const DerivedGeology& geo_;
|
||||
const Wells& wells_;
|
||||
const LinearSolverInterface& linsolver_;
|
||||
// For each canonical phase -> true if active
|
||||
const std::vector<bool> active_;
|
||||
// Size = # active faces. Maps active -> canonical phase indices.
|
||||
const std::vector<int> canph_;
|
||||
const std::vector<int> cells_; // All grid cells
|
||||
HelperOps ops_;
|
||||
const WellOps wops_;
|
||||
const M grav_;
|
||||
|
||||
std::vector<ReservoirResidualQuant> rq_;
|
||||
|
||||
// The mass_balance vector has one element for each active phase,
|
||||
// each of which has size equal to the number of cells.
|
||||
// The well_eq has size equal to the number of wells.
|
||||
struct {
|
||||
std::vector<ADB> mass_balance;
|
||||
ADB rs_or_sg_eq; // Only used if both gas and oil present
|
||||
ADB well_flux_eq;
|
||||
ADB well_eq;
|
||||
} residual_;
|
||||
|
||||
// Private methods.
|
||||
SolutionState
|
||||
constantState(const BlackoilState& x,
|
||||
const WellState& xw);
|
||||
|
||||
SolutionState
|
||||
variableState(const BlackoilState& x,
|
||||
const WellState& xw);
|
||||
|
||||
void
|
||||
computeAccum(const SolutionState& state,
|
||||
const int aix );
|
||||
|
||||
void
|
||||
assemble(const V& dtpv,
|
||||
const BlackoilState& x ,
|
||||
const WellState& xw );
|
||||
|
||||
V solveJacobianSystem() const;
|
||||
|
||||
void updateState(const V& dx,
|
||||
BlackoilState& state,
|
||||
WellState& well_state) const;
|
||||
|
||||
std::vector<ADB>
|
||||
computeRelPerm(const SolutionState& state) const;
|
||||
|
||||
std::vector<ADB>
|
||||
computeRelPermWells(const SolutionState& state,
|
||||
const DataBlock& well_s,
|
||||
const std::vector<int>& well_cells) const;
|
||||
|
||||
void
|
||||
computeMassFlux(const int actph ,
|
||||
const V& transi,
|
||||
const std::vector<ADB>& kr ,
|
||||
const SolutionState& state );
|
||||
|
||||
double
|
||||
residualNorm() const;
|
||||
|
||||
ADB
|
||||
fluidViscosity(const int phase,
|
||||
const ADB& p ,
|
||||
const ADB& rs ,
|
||||
const std::vector<int>& cells) const;
|
||||
|
||||
ADB
|
||||
fluidReciprocFVF(const int phase,
|
||||
const ADB& p ,
|
||||
const ADB& rs ,
|
||||
const std::vector<int>& cells) const;
|
||||
|
||||
ADB
|
||||
fluidDensity(const int phase,
|
||||
const ADB& p ,
|
||||
const ADB& rs ,
|
||||
const std::vector<int>& cells) const;
|
||||
|
||||
V
|
||||
fluidRsMax(const V& p,
|
||||
const std::vector<int>& cells) const;
|
||||
|
||||
ADB
|
||||
fluidRsMax(const ADB& p,
|
||||
const std::vector<int>& cells) const;
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#endif // OPM_FULLYIMPLICITBLACKOILSOLVER_HEADER_INCLUDED
|
@ -363,11 +363,7 @@ namespace Opm {
|
||||
divcontrib_sum = divcontrib_sum - divcontrib/cell_b;
|
||||
cell_residual_ = cell_residual_ - (component_contrib/cell_b);
|
||||
const ADB well_rates = perf_to_well * (perf_flux*perf_b);
|
||||
std::vector<int> well_flow_res_phase_idx(nw);
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
well_flow_res_phase_idx[w] = w + phase*nw;
|
||||
}
|
||||
qs_ = qs_ + superset(well_rates, well_flow_res_phase_idx, nw*np);
|
||||
qs_ = qs_ + superset(well_rates, Span(nw, 1, phase*nw), nw*np);
|
||||
}
|
||||
cell_residual_ = cell_residual_ + divcontrib_sum;
|
||||
// Handling BHP and SURFACE_RATE wells.
|
||||
@ -426,15 +422,11 @@ namespace Opm {
|
||||
THROW("ImpesTPFAAD::solve(): Linear solver convergence failure.");
|
||||
}
|
||||
const V p0 = Eigen::Map<const V>(&state.pressure()[0], nc, 1);
|
||||
const V dp = subset(dx, buildAllCells(nc));
|
||||
const V dp = subset(dx, Span(nc));
|
||||
const V p = p0 - dp;
|
||||
std::copy(&p[0], &p[0] + nc, state.pressure().begin());
|
||||
const V bhp0 = Eigen::Map<const V>(&well_state.bhp()[0], nw, 1);
|
||||
std::vector<int> bhp_dofs(nw);
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
bhp_dofs[w] = nc + w;
|
||||
}
|
||||
ASSERT(bhp_dofs.back() + 1 == total_residual_.size());
|
||||
Span bhp_dofs(nw, 1, nc);
|
||||
const V dbhp = subset(dx, bhp_dofs);
|
||||
const V bhp = bhp0 - dbhp;
|
||||
std::copy(&bhp[0], &bhp[0] + nw, well_state.bhp().begin());
|
||||
|
477
opm/autodiff/SimulatorFullyImplicitBlackoil.cpp
Normal file
477
opm/autodiff/SimulatorFullyImplicitBlackoil.cpp
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <opm/autodiff/SimulatorFullyImplicitBlackoil.hpp>
|
||||
#include <opm/core/utility/parameters/ParameterGroup.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
|
||||
#include <opm/autodiff/GeoProps.hpp>
|
||||
#include <opm/autodiff/FullyImplicitBlackoilSolver.hpp>
|
||||
#include <opm/autodiff/BlackoilPropsAdInterface.hpp>
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/wells.h>
|
||||
#include <opm/core/pressure/flow_bc.h>
|
||||
|
||||
#include <opm/core/simulator/SimulatorReport.hpp>
|
||||
#include <opm/core/simulator/SimulatorTimer.hpp>
|
||||
#include <opm/core/utility/StopWatch.hpp>
|
||||
#include <opm/core/io/vtk/writeVtkData.hpp>
|
||||
#include <opm/core/utility/miscUtilities.hpp>
|
||||
#include <opm/core/utility/miscUtilitiesBlackoil.hpp>
|
||||
|
||||
#include <opm/core/wells/WellsManager.hpp>
|
||||
|
||||
#include <opm/core/props/rock/RockCompressibility.hpp>
|
||||
|
||||
#include <opm/core/grid/ColumnExtract.hpp>
|
||||
#include <opm/core/simulator/BlackoilState.hpp>
|
||||
#include <opm/core/simulator/WellState.hpp>
|
||||
#include <opm/core/transport/reorder/TransportSolverCompressibleTwophaseReorder.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <numeric>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
class SimulatorFullyImplicitBlackoil::Impl
|
||||
{
|
||||
public:
|
||||
Impl(const parameter::ParameterGroup& param,
|
||||
const UnstructuredGrid& grid,
|
||||
const BlackoilPropsAdInterface& props,
|
||||
const RockCompressibility* rock_comp_props,
|
||||
WellsManager& wells_manager,
|
||||
const std::vector<double>& src,
|
||||
const FlowBoundaryConditions* bcs,
|
||||
LinearSolverInterface& linsolver,
|
||||
const double* gravity);
|
||||
|
||||
SimulatorReport run(SimulatorTimer& timer,
|
||||
BlackoilState& state,
|
||||
WellState& well_state);
|
||||
|
||||
private:
|
||||
// Data.
|
||||
|
||||
// Parameters for output.
|
||||
bool output_;
|
||||
bool output_vtk_;
|
||||
std::string output_dir_;
|
||||
int output_interval_;
|
||||
// Parameters for well control
|
||||
bool check_well_controls_;
|
||||
int max_well_control_iterations_;
|
||||
// Parameters for transport solver.
|
||||
int num_transport_substeps_;
|
||||
bool use_segregation_split_;
|
||||
// Observed objects.
|
||||
const UnstructuredGrid& grid_;
|
||||
const BlackoilPropsAdInterface& props_;
|
||||
const RockCompressibility* rock_comp_props_;
|
||||
WellsManager& wells_manager_;
|
||||
const Wells* wells_;
|
||||
const std::vector<double>& src_;
|
||||
const FlowBoundaryConditions* bcs_;
|
||||
const double* gravity_;
|
||||
// Solvers
|
||||
DerivedGeology geo_;
|
||||
FullyImplicitBlackoilSolver solver_;
|
||||
// Misc. data
|
||||
std::vector<int> allcells_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
SimulatorFullyImplicitBlackoil::SimulatorFullyImplicitBlackoil(const parameter::ParameterGroup& param,
|
||||
const UnstructuredGrid& grid,
|
||||
const BlackoilPropsAdInterface& props,
|
||||
const RockCompressibility* rock_comp_props,
|
||||
WellsManager& wells_manager,
|
||||
const std::vector<double>& src,
|
||||
const FlowBoundaryConditions* bcs,
|
||||
LinearSolverInterface& linsolver,
|
||||
const double* gravity)
|
||||
{
|
||||
pimpl_.reset(new Impl(param, grid, props, rock_comp_props, wells_manager, src, bcs, linsolver, gravity));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SimulatorReport SimulatorFullyImplicitBlackoil::run(SimulatorTimer& timer,
|
||||
BlackoilState& state,
|
||||
WellState& well_state)
|
||||
{
|
||||
return pimpl_->run(timer, state, well_state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void outputStateVtk(const UnstructuredGrid& grid,
|
||||
const Opm::BlackoilState& state,
|
||||
const int step,
|
||||
const std::string& output_dir)
|
||||
{
|
||||
// Write data in VTK format.
|
||||
std::ostringstream vtkfilename;
|
||||
vtkfilename << output_dir << "/vtk_files";
|
||||
boost::filesystem::path fpath(vtkfilename.str());
|
||||
try {
|
||||
create_directories(fpath);
|
||||
}
|
||||
catch (...) {
|
||||
THROW("Creating directories failed: " << fpath);
|
||||
}
|
||||
vtkfilename << "/output-" << std::setw(3) << std::setfill('0') << step << ".vtu";
|
||||
std::ofstream vtkfile(vtkfilename.str().c_str());
|
||||
if (!vtkfile) {
|
||||
THROW("Failed to open " << vtkfilename.str());
|
||||
}
|
||||
Opm::DataMap dm;
|
||||
dm["saturation"] = &state.saturation();
|
||||
dm["pressure"] = &state.pressure();
|
||||
std::vector<double> cell_velocity;
|
||||
Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
|
||||
dm["velocity"] = &cell_velocity;
|
||||
Opm::writeVtkData(grid, dm, vtkfile);
|
||||
}
|
||||
|
||||
|
||||
static void outputStateMatlab(const UnstructuredGrid& grid,
|
||||
const Opm::BlackoilState& state,
|
||||
const int step,
|
||||
const std::string& output_dir)
|
||||
{
|
||||
Opm::DataMap dm;
|
||||
dm["saturation"] = &state.saturation();
|
||||
dm["pressure"] = &state.pressure();
|
||||
dm["surfvolume"] = &state.surfacevol();
|
||||
std::vector<double> cell_velocity;
|
||||
Opm::estimateCellVelocity(grid, state.faceflux(), cell_velocity);
|
||||
dm["velocity"] = &cell_velocity;
|
||||
|
||||
// Write data (not grid) in Matlab format
|
||||
for (Opm::DataMap::const_iterator it = dm.begin(); it != dm.end(); ++it) {
|
||||
std::ostringstream fname;
|
||||
fname << output_dir << "/" << it->first;
|
||||
boost::filesystem::path fpath = fname.str();
|
||||
try {
|
||||
create_directories(fpath);
|
||||
}
|
||||
catch (...) {
|
||||
THROW("Creating directories failed: " << fpath);
|
||||
}
|
||||
fname << "/" << std::setw(3) << std::setfill('0') << step << ".txt";
|
||||
std::ofstream file(fname.str().c_str());
|
||||
if (!file) {
|
||||
THROW("Failed to open " << fname.str());
|
||||
}
|
||||
file.precision(15);
|
||||
const std::vector<double>& d = *(it->second);
|
||||
std::copy(d.begin(), d.end(), std::ostream_iterator<double>(file, "\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void outputWaterCut(const Opm::Watercut& watercut,
|
||||
const std::string& output_dir)
|
||||
{
|
||||
// Write water cut curve.
|
||||
std::string fname = output_dir + "/watercut.txt";
|
||||
std::ofstream os(fname.c_str());
|
||||
if (!os) {
|
||||
THROW("Failed to open " << fname);
|
||||
}
|
||||
watercut.write(os);
|
||||
}
|
||||
|
||||
static void outputWellReport(const Opm::WellReport& wellreport,
|
||||
const std::string& output_dir)
|
||||
{
|
||||
// Write well report.
|
||||
std::string fname = output_dir + "/wellreport.txt";
|
||||
std::ofstream os(fname.c_str());
|
||||
if (!os) {
|
||||
THROW("Failed to open " << fname);
|
||||
}
|
||||
wellreport.write(os);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// \TODO: make CompressibleTpfa take src and bcs.
|
||||
SimulatorFullyImplicitBlackoil::Impl::Impl(const parameter::ParameterGroup& param,
|
||||
const UnstructuredGrid& grid,
|
||||
const BlackoilPropsAdInterface& props,
|
||||
const RockCompressibility* rock_comp_props,
|
||||
WellsManager& wells_manager,
|
||||
const std::vector<double>& src,
|
||||
const FlowBoundaryConditions* bcs,
|
||||
LinearSolverInterface& linsolver,
|
||||
const double* gravity)
|
||||
: grid_(grid),
|
||||
props_(props),
|
||||
rock_comp_props_(rock_comp_props),
|
||||
wells_manager_(wells_manager),
|
||||
wells_(wells_manager.c_wells()),
|
||||
src_(src),
|
||||
bcs_(bcs),
|
||||
gravity_(gravity),
|
||||
geo_(grid_, props_, gravity_),
|
||||
solver_(grid_, props_, geo_, *wells_manager.c_wells(), linsolver)
|
||||
/* param.getDefault("nl_pressure_residual_tolerance", 0.0),
|
||||
param.getDefault("nl_pressure_change_tolerance", 1.0),
|
||||
param.getDefault("nl_pressure_maxiter", 10),
|
||||
gravity, */
|
||||
{
|
||||
// For output.
|
||||
output_ = param.getDefault("output", true);
|
||||
if (output_) {
|
||||
output_vtk_ = param.getDefault("output_vtk", true);
|
||||
output_dir_ = param.getDefault("output_dir", std::string("output"));
|
||||
// Ensure that output dir exists
|
||||
boost::filesystem::path fpath(output_dir_);
|
||||
try {
|
||||
create_directories(fpath);
|
||||
}
|
||||
catch (...) {
|
||||
THROW("Creating directories failed: " << fpath);
|
||||
}
|
||||
output_interval_ = param.getDefault("output_interval", 1);
|
||||
}
|
||||
|
||||
// Well control related init.
|
||||
check_well_controls_ = param.getDefault("check_well_controls", false);
|
||||
max_well_control_iterations_ = param.getDefault("max_well_control_iterations", 10);
|
||||
|
||||
// Misc init.
|
||||
const int num_cells = grid.number_of_cells;
|
||||
allcells_.resize(num_cells);
|
||||
for (int cell = 0; cell < num_cells; ++cell) {
|
||||
allcells_[cell] = cell;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
SimulatorReport SimulatorFullyImplicitBlackoil::Impl::run(SimulatorTimer& timer,
|
||||
BlackoilState& state,
|
||||
WellState& well_state)
|
||||
{
|
||||
// Initialisation.
|
||||
std::vector<double> porevol;
|
||||
if (rock_comp_props_ && rock_comp_props_->isActive()) {
|
||||
computePorevolume(grid_, props_.porosity(), *rock_comp_props_, state.pressure(), porevol);
|
||||
} else {
|
||||
computePorevolume(grid_, props_.porosity(), porevol);
|
||||
}
|
||||
// const double tot_porevol_init = std::accumulate(porevol.begin(), porevol.end(), 0.0);
|
||||
std::vector<double> initial_porevol = porevol;
|
||||
|
||||
// Main simulation loop.
|
||||
Opm::time::StopWatch solver_timer;
|
||||
double stime = 0.0;
|
||||
Opm::time::StopWatch step_timer;
|
||||
Opm::time::StopWatch total_timer;
|
||||
total_timer.start();
|
||||
#if 0
|
||||
// These must be changed for three-phase.
|
||||
double init_surfvol[2] = { 0.0 };
|
||||
double inplace_surfvol[2] = { 0.0 };
|
||||
double tot_injected[2] = { 0.0 };
|
||||
double tot_produced[2] = { 0.0 };
|
||||
Opm::computeSaturatedVol(porevol, state.surfacevol(), init_surfvol);
|
||||
Opm::Watercut watercut;
|
||||
watercut.push(0.0, 0.0, 0.0);
|
||||
Opm::WellReport wellreport;
|
||||
#endif
|
||||
std::vector<double> fractional_flows;
|
||||
std::vector<double> well_resflows_phase;
|
||||
if (wells_) {
|
||||
well_resflows_phase.resize((wells_->number_of_phases)*(wells_->number_of_wells), 0.0);
|
||||
#if 0
|
||||
wellreport.push(props_, *wells_,
|
||||
state.pressure(), state.surfacevol(), state.saturation(),
|
||||
0.0, well_state.bhp(), well_state.perfRates());
|
||||
#endif
|
||||
}
|
||||
std::fstream tstep_os;
|
||||
if (output_) {
|
||||
std::string filename = output_dir_ + "/step_timing.param";
|
||||
tstep_os.open(filename.c_str(), std::fstream::out | std::fstream::app);
|
||||
}
|
||||
for (; !timer.done(); ++timer) {
|
||||
// Report timestep and (optionally) write state to disk.
|
||||
step_timer.start();
|
||||
timer.report(std::cout);
|
||||
if (output_ && (timer.currentStepNum() % output_interval_ == 0)) {
|
||||
if (output_vtk_) {
|
||||
outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
|
||||
}
|
||||
outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
|
||||
}
|
||||
|
||||
SimulatorReport sreport;
|
||||
|
||||
// Solve pressure equation.
|
||||
// if (check_well_controls_) {
|
||||
// computeFractionalFlow(props_, allcells_,
|
||||
// state.pressure(), state.surfacevol(), state.saturation(),
|
||||
// fractional_flows);
|
||||
// wells_manager_.applyExplicitReinjectionControls(well_resflows_phase, well_resflows_phase);
|
||||
// }
|
||||
bool well_control_passed = !check_well_controls_;
|
||||
int well_control_iteration = 0;
|
||||
do {
|
||||
// Run solver.
|
||||
solver_timer.start();
|
||||
std::vector<double> initial_pressure = state.pressure();
|
||||
solver_.step(timer.currentStepLength(), state, well_state);
|
||||
|
||||
// Stop timer and report.
|
||||
solver_timer.stop();
|
||||
const double st = solver_timer.secsSinceStart();
|
||||
std::cout << "Fully implicit solver took: " << st << " seconds." << std::endl;
|
||||
stime += st;
|
||||
sreport.pressure_time = st;
|
||||
|
||||
// Optionally, check if well controls are satisfied.
|
||||
if (check_well_controls_) {
|
||||
Opm::computePhaseFlowRatesPerWell(*wells_,
|
||||
well_state.perfRates(),
|
||||
fractional_flows,
|
||||
well_resflows_phase);
|
||||
std::cout << "Checking well conditions." << std::endl;
|
||||
// For testing we set surface := reservoir
|
||||
well_control_passed = wells_manager_.conditionsMet(well_state.bhp(), well_resflows_phase, well_resflows_phase);
|
||||
++well_control_iteration;
|
||||
if (!well_control_passed && well_control_iteration > max_well_control_iterations_) {
|
||||
THROW("Could not satisfy well conditions in " << max_well_control_iterations_ << " tries.");
|
||||
}
|
||||
if (!well_control_passed) {
|
||||
std::cout << "Well controls not passed, solving again." << std::endl;
|
||||
} else {
|
||||
std::cout << "Well conditions met." << std::endl;
|
||||
}
|
||||
}
|
||||
} while (!well_control_passed);
|
||||
|
||||
// Update pore volumes if rock is compressible.
|
||||
if (rock_comp_props_ && rock_comp_props_->isActive()) {
|
||||
initial_porevol = porevol;
|
||||
computePorevolume(grid_, props_.porosity(), *rock_comp_props_, state.pressure(), porevol);
|
||||
}
|
||||
|
||||
// The reports below are geared towards two phases only.
|
||||
#if 0
|
||||
// Report mass balances.
|
||||
double injected[2] = { 0.0 };
|
||||
double produced[2] = { 0.0 };
|
||||
Opm::computeInjectedProduced(props_, state, transport_src, stepsize,
|
||||
injected, produced);
|
||||
Opm::computeSaturatedVol(porevol, state.surfacevol(), inplace_surfvol);
|
||||
tot_injected[0] += injected[0];
|
||||
tot_injected[1] += injected[1];
|
||||
tot_produced[0] += produced[0];
|
||||
tot_produced[1] += produced[1];
|
||||
std::cout.precision(5);
|
||||
const int width = 18;
|
||||
std::cout << "\nMass balance report.\n";
|
||||
std::cout << " Injected surface volumes: "
|
||||
<< std::setw(width) << injected[0]
|
||||
<< std::setw(width) << injected[1] << std::endl;
|
||||
std::cout << " Produced surface volumes: "
|
||||
<< std::setw(width) << produced[0]
|
||||
<< std::setw(width) << produced[1] << std::endl;
|
||||
std::cout << " Total inj surface volumes: "
|
||||
<< std::setw(width) << tot_injected[0]
|
||||
<< std::setw(width) << tot_injected[1] << std::endl;
|
||||
std::cout << " Total prod surface volumes: "
|
||||
<< std::setw(width) << tot_produced[0]
|
||||
<< std::setw(width) << tot_produced[1] << std::endl;
|
||||
const double balance[2] = { init_surfvol[0] - inplace_surfvol[0] - tot_produced[0] + tot_injected[0],
|
||||
init_surfvol[1] - inplace_surfvol[1] - tot_produced[1] + tot_injected[1] };
|
||||
std::cout << " Initial - inplace + inj - prod: "
|
||||
<< std::setw(width) << balance[0]
|
||||
<< std::setw(width) << balance[1]
|
||||
<< std::endl;
|
||||
std::cout << " Relative mass error: "
|
||||
<< std::setw(width) << balance[0]/(init_surfvol[0] + tot_injected[0])
|
||||
<< std::setw(width) << balance[1]/(init_surfvol[1] + tot_injected[1])
|
||||
<< std::endl;
|
||||
std::cout.precision(8);
|
||||
|
||||
// Make well reports.
|
||||
watercut.push(timer.currentTime() + timer.currentStepLength(),
|
||||
produced[0]/(produced[0] + produced[1]),
|
||||
tot_produced[0]/tot_porevol_init);
|
||||
if (wells_) {
|
||||
wellreport.push(props_, *wells_,
|
||||
state.pressure(), state.surfacevol(), state.saturation(),
|
||||
timer.currentTime() + timer.currentStepLength(),
|
||||
well_state.bhp(), well_state.perfRates());
|
||||
}
|
||||
#endif
|
||||
sreport.total_time = step_timer.secsSinceStart();
|
||||
if (output_) {
|
||||
sreport.reportParam(tstep_os);
|
||||
}
|
||||
}
|
||||
|
||||
if (output_) {
|
||||
if (output_vtk_) {
|
||||
outputStateVtk(grid_, state, timer.currentStepNum(), output_dir_);
|
||||
}
|
||||
outputStateMatlab(grid_, state, timer.currentStepNum(), output_dir_);
|
||||
#if 0
|
||||
outputWaterCut(watercut, output_dir_);
|
||||
if (wells_) {
|
||||
outputWellReport(wellreport, output_dir_);
|
||||
}
|
||||
#endif
|
||||
tstep_os.close();
|
||||
}
|
||||
|
||||
total_timer.stop();
|
||||
|
||||
SimulatorReport report;
|
||||
report.pressure_time = stime;
|
||||
report.transport_time = 0.0;
|
||||
report.total_time = total_timer.secsSinceStart();
|
||||
return report;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Opm
|
99
opm/autodiff/SimulatorFullyImplicitBlackoil.hpp
Normal file
99
opm/autodiff/SimulatorFullyImplicitBlackoil.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_SIMULATORFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
|
||||
#define OPM_SIMULATORFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <vector>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
struct Wells;
|
||||
struct FlowBoundaryConditions;
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
namespace parameter { class ParameterGroup; }
|
||||
class BlackoilPropsAdInterface;
|
||||
class RockCompressibility;
|
||||
class WellsManager;
|
||||
class LinearSolverInterface;
|
||||
class SimulatorTimer;
|
||||
class BlackoilState;
|
||||
class WellState;
|
||||
struct SimulatorReport;
|
||||
|
||||
/// Class collecting all necessary components for a two-phase simulation.
|
||||
class SimulatorFullyImplicitBlackoil
|
||||
{
|
||||
public:
|
||||
/// Initialise from parameters and objects to observe.
|
||||
/// \param[in] param parameters, this class accepts the following:
|
||||
/// parameter (default) effect
|
||||
/// -----------------------------------------------------------
|
||||
/// output (true) write output to files?
|
||||
/// output_dir ("output") output directoty
|
||||
/// output_interval (1) output every nth step
|
||||
/// nl_pressure_residual_tolerance (0.0) pressure solver residual tolerance (in Pascal)
|
||||
/// nl_pressure_change_tolerance (1.0) pressure solver change tolerance (in Pascal)
|
||||
/// nl_pressure_maxiter (10) max nonlinear iterations in pressure
|
||||
/// nl_maxiter (30) max nonlinear iterations in transport
|
||||
/// nl_tolerance (1e-9) transport solver absolute residual tolerance
|
||||
/// num_transport_substeps (1) number of transport steps per pressure step
|
||||
/// use_segregation_split (false) solve for gravity segregation (if false,
|
||||
/// segregation is ignored).
|
||||
///
|
||||
/// \param[in] grid grid data structure
|
||||
/// \param[in] props fluid and rock properties
|
||||
/// \param[in] rock_comp_props if non-null, rock compressibility properties
|
||||
/// \param[in] well_manager well manager, may manage no (null) wells
|
||||
/// \param[in] src source terms
|
||||
/// \param[in] bcs boundary conditions, treat as all noflow if null
|
||||
/// \param[in] linsolver linear solver
|
||||
/// \param[in] gravity if non-null, gravity vector
|
||||
SimulatorFullyImplicitBlackoil(const parameter::ParameterGroup& param,
|
||||
const UnstructuredGrid& grid,
|
||||
const BlackoilPropsAdInterface& props,
|
||||
const RockCompressibility* rock_comp_props,
|
||||
WellsManager& wells_manager,
|
||||
const std::vector<double>& src,
|
||||
const FlowBoundaryConditions* bcs,
|
||||
LinearSolverInterface& linsolver,
|
||||
const double* gravity);
|
||||
|
||||
/// Run the simulation.
|
||||
/// This will run succesive timesteps until timer.done() is true. It will
|
||||
/// modify the reservoir and well states.
|
||||
/// \param[in,out] timer governs the requested reporting timesteps
|
||||
/// \param[in,out] state state of reservoir: pressure, fluxes
|
||||
/// \param[in,out] well_state state of wells: bhp, perforation rates
|
||||
/// \return simulation report, with timing data
|
||||
SimulatorReport run(SimulatorTimer& timer,
|
||||
BlackoilState& state,
|
||||
WellState& well_state);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
// Using shared_ptr instead of scoped_ptr since scoped_ptr requires complete type for Impl.
|
||||
boost::shared_ptr<Impl> pimpl_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_SIMULATORFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
|
68
tests/test_span.cpp
Normal file
68
tests/test_span.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2013 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if HAVE_DYNAMIC_BOOST_TEST
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
#endif
|
||||
|
||||
#define BOOST_TEST_MODULE SpanTest
|
||||
|
||||
#include <opm/autodiff/AutoDiffHelpers.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(OneArgConstr)
|
||||
{
|
||||
const int num = 4;
|
||||
const Span s(num);
|
||||
BOOST_CHECK_EQUAL(s.size(), num);
|
||||
for (int i = 0; i < num; ++i) {
|
||||
BOOST_CHECK_EQUAL(s[i], i);
|
||||
}
|
||||
int count = 0;
|
||||
for (Span::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
BOOST_CHECK_EQUAL(*it, count);
|
||||
++count;
|
||||
}
|
||||
BOOST_CHECK_EQUAL(count, num);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ThreeArgConstr)
|
||||
{
|
||||
const int num = 3;
|
||||
const int stride = 7;
|
||||
const int start = 5;
|
||||
const int seq[num] = { start, start + 1*stride, start + 2*stride };
|
||||
|
||||
const Span s(num, stride, start);
|
||||
BOOST_CHECK_EQUAL(s.size(), num);
|
||||
for (int i = 0; i < num; ++i) {
|
||||
BOOST_CHECK_EQUAL(s[i], seq[i]);
|
||||
}
|
||||
int count = 0;
|
||||
for (Span::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
BOOST_CHECK_EQUAL(*it, seq[count]);
|
||||
++count;
|
||||
}
|
||||
BOOST_CHECK_EQUAL(count, num);
|
||||
}
|
Loading…
Reference in New Issue
Block a user