2012-06-13 08:46:15 -05:00
/*
Copyright 2012 SINTEF ICT , Applied Mathematics .
This file is part of the Open Porous Media project ( OPM ) .
OPM is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
OPM is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with OPM . If not , see < http : //www.gnu.org/licenses/>.
*/
# if HAVE_CONFIG_H
# include "config.h"
# endif // HAVE_CONFIG_H
# include <opm/polymer/SimulatorPolymer.hpp>
# include <opm/core/utility/parameters/ParameterGroup.hpp>
# include <opm/core/utility/ErrorMacros.hpp>
2012-06-13 12:56:44 -05:00
# include <opm/polymer/IncompTpfaPolymer.hpp>
2012-06-13 08:46:15 -05:00
# include <opm/core/grid.h>
2013-03-18 07:10:32 -05:00
# include <opm/core/wells.h>
2014-01-09 05:06:26 -06:00
# include <opm/core/well_controls.h>
2012-06-13 08:46:15 -05:00
# include <opm/core/pressure/flow_bc.h>
2012-06-14 07:26:29 -05:00
# include <opm/core/simulator/SimulatorReport.hpp>
# include <opm/core/simulator/SimulatorTimer.hpp>
2012-06-13 08:46:15 -05:00
# include <opm/core/utility/StopWatch.hpp>
2013-03-12 05:08:33 -05:00
# include <opm/core/io/vtk/writeVtkData.hpp>
2012-06-13 08:46:15 -05:00
# include <opm/core/utility/miscUtilities.hpp>
2012-10-10 16:19:35 -05:00
# include <opm/core/wells/WellsManager.hpp>
2013-03-14 07:59:31 -05:00
# include <opm/core/props/IncompPropertiesInterface.hpp>
# include <opm/core/props/rock/RockCompressibility.hpp>
2012-06-13 08:46:15 -05:00
2013-03-18 07:10:32 -05:00
# include <opm/core/grid/ColumnExtract.hpp>
2012-06-13 08:46:15 -05:00
# include <opm/core/utility/Units.hpp>
# include <opm/polymer/PolymerState.hpp>
# include <opm/core/simulator/WellState.hpp>
2013-03-15 12:33:41 -05:00
# include <opm/polymer/TransportSolverTwophasePolymer.hpp>
2012-10-04 08:15:32 -05:00
# include <opm/polymer/PolymerInflow.hpp>
2012-06-13 10:51:47 -05:00
# include <opm/polymer/PolymerProperties.hpp>
2012-06-13 14:59:11 -05:00
# include <opm/polymer/polymerUtilities.hpp>
2012-06-13 08:46:15 -05:00
2012-10-15 07:23:13 -05:00
# include <boost/filesystem.hpp>
2012-06-13 08:46:15 -05:00
# include <boost/scoped_ptr.hpp>
# include <boost/lexical_cast.hpp>
# include <numeric>
# include <fstream>
2013-09-05 05:39:11 -05:00
# include <iostream>
2012-06-13 08:46:15 -05:00
2012-11-26 04:01:23 -06:00
# ifdef HAVE_ERT
2013-03-12 05:08:33 -05:00
# include <opm/core/io/eclipse/writeECLData.hpp>
2012-11-26 04:01:23 -06:00
# endif
2012-06-13 08:46:15 -05:00
namespace Opm
{
namespace
{
2012-09-17 00:54:50 -05:00
void outputStateVtk ( const UnstructuredGrid & grid ,
const Opm : : PolymerState & state ,
const int step ,
const std : : string & output_dir ) ;
2012-11-26 04:01:23 -06:00
void outputStateBinary ( const UnstructuredGrid & grid ,
const Opm : : PolymerState & state ,
const SimulatorTimer & simtimer ,
const std : : string & output_dir ) ;
2012-09-17 00:54:50 -05:00
void outputStateMatlab ( const UnstructuredGrid & grid ,
const Opm : : PolymerState & state ,
const int step ,
const std : : string & output_dir ) ;
2012-06-13 08:46:15 -05:00
void outputWaterCut ( const Opm : : Watercut & watercut ,
const std : : string & output_dir ) ;
void outputWellReport ( const Opm : : WellReport & wellreport ,
const std : : string & output_dir ) ;
2012-10-10 16:19:35 -05:00
bool allNeumannBCs ( const FlowBoundaryConditions * bcs ) ;
bool allRateWells ( const Wells * wells ) ;
2012-06-13 08:46:15 -05:00
} // anonymous namespace
class SimulatorPolymer : : Impl
{
public :
Impl ( const parameter : : ParameterGroup & param ,
const UnstructuredGrid & grid ,
const IncompPropertiesInterface & props ,
const PolymerProperties & poly_props ,
const RockCompressibility * rock_comp_props ,
2012-10-10 16:19:35 -05:00
WellsManager & wells_manager ,
2012-10-04 09:00:33 -05:00
const PolymerInflowInterface & polymer_inflow ,
2012-06-13 08:46:15 -05:00
const std : : vector < double > & src ,
const FlowBoundaryConditions * bcs ,
LinearSolverInterface & linsolver ,
const double * gravity ) ;
2012-06-14 06:24:38 -05:00
SimulatorReport run ( SimulatorTimer & timer ,
PolymerState & state ,
WellState & well_state ) ;
2012-06-13 08:46:15 -05:00
private :
// Data.
// Parameters for output.
bool output_ ;
2012-09-17 00:54:50 -05:00
bool output_vtk_ ;
2012-11-26 04:01:23 -06:00
bool output_binary_ ;
2012-06-13 08:46:15 -05:00
std : : string output_dir_ ;
int output_interval_ ;
2012-10-10 16:19:35 -05:00
// Parameters for well control
bool check_well_controls_ ;
int max_well_control_iterations_ ;
2012-06-13 08:46:15 -05:00
// Parameters for transport solver.
int num_transport_substeps_ ;
bool use_segregation_split_ ;
// Observed objects.
const UnstructuredGrid & grid_ ;
const IncompPropertiesInterface & props_ ;
const PolymerProperties & poly_props_ ;
const RockCompressibility * rock_comp_props_ ;
2012-10-10 16:19:35 -05:00
WellsManager & wells_manager_ ;
2012-06-13 08:46:15 -05:00
const Wells * wells_ ;
2012-10-04 09:00:33 -05:00
const PolymerInflowInterface & polymer_inflow_ ;
2012-06-13 08:46:15 -05:00
const std : : vector < double > & src_ ;
const FlowBoundaryConditions * bcs_ ;
// Solvers
2012-06-13 12:56:44 -05:00
IncompTpfaPolymer psolver_ ;
2013-03-15 12:33:41 -05:00
TransportSolverTwophasePolymer tsolver_ ;
2012-06-13 08:46:15 -05:00
// Needed by column-based gravity segregation solver.
std : : vector < std : : vector < int > > columns_ ;
// Misc. data
std : : vector < int > allcells_ ;
} ;
SimulatorPolymer : : SimulatorPolymer ( const parameter : : ParameterGroup & param ,
const UnstructuredGrid & grid ,
const IncompPropertiesInterface & props ,
const PolymerProperties & poly_props ,
const RockCompressibility * rock_comp_props ,
2012-10-10 16:19:35 -05:00
WellsManager & wells_manager ,
2012-10-04 09:00:33 -05:00
const PolymerInflowInterface & polymer_inflow ,
2012-06-13 08:46:15 -05:00
const std : : vector < double > & src ,
const FlowBoundaryConditions * bcs ,
LinearSolverInterface & linsolver ,
const double * gravity )
{
2012-10-04 09:00:33 -05:00
pimpl_ . reset ( new Impl ( param , grid , props , poly_props , rock_comp_props ,
2012-10-10 16:19:35 -05:00
wells_manager , polymer_inflow , src , bcs , linsolver , gravity ) ) ;
2012-06-13 08:46:15 -05:00
}
2012-06-14 07:26:29 -05:00
SimulatorReport SimulatorPolymer : : run ( SimulatorTimer & timer ,
PolymerState & state ,
WellState & well_state )
2012-06-13 08:46:15 -05:00
{
2012-06-14 06:24:38 -05:00
return pimpl_ - > run ( timer , state , well_state ) ;
2012-06-13 08:46:15 -05:00
}
SimulatorPolymer : : Impl : : Impl ( const parameter : : ParameterGroup & param ,
const UnstructuredGrid & grid ,
const IncompPropertiesInterface & props ,
const PolymerProperties & poly_props ,
const RockCompressibility * rock_comp_props ,
2012-10-10 16:19:35 -05:00
WellsManager & wells_manager ,
2012-10-04 09:00:33 -05:00
const PolymerInflowInterface & polymer_inflow ,
2012-06-13 08:46:15 -05:00
const std : : vector < double > & src ,
const FlowBoundaryConditions * bcs ,
LinearSolverInterface & linsolver ,
const double * gravity )
: grid_ ( grid ) ,
props_ ( props ) ,
poly_props_ ( poly_props ) ,
rock_comp_props_ ( rock_comp_props ) ,
2012-10-10 16:19:35 -05:00
wells_manager_ ( wells_manager ) ,
wells_ ( wells_manager . c_wells ( ) ) ,
2012-10-04 09:00:33 -05:00
polymer_inflow_ ( polymer_inflow ) ,
2012-06-13 08:46:15 -05:00
src_ ( src ) ,
bcs_ ( bcs ) ,
2012-06-13 12:56:44 -05:00
psolver_ ( grid , props , rock_comp_props , poly_props , linsolver ,
2012-06-14 06:24:38 -05:00
param . getDefault ( " nl_pressure_residual_tolerance " , 0.0 ) ,
2012-06-13 08:46:15 -05:00
param . getDefault ( " nl_pressure_change_tolerance " , 1.0 ) ,
param . getDefault ( " nl_pressure_maxiter " , 10 ) ,
2012-10-10 16:19:35 -05:00
gravity , wells_manager . c_wells ( ) , src , bcs ) ,
2013-03-15 12:33:41 -05:00
tsolver_ ( grid , props , poly_props , TransportSolverTwophasePolymer : : Bracketing ,
2012-06-13 08:46:15 -05:00
param . getDefault ( " nl_tolerance " , 1e-9 ) ,
2012-10-04 06:38:22 -05:00
param . getDefault ( " nl_maxiter " , 30 ) )
2012-06-13 08:46:15 -05:00
{
// For output.
output_ = param . getDefault ( " output " , true ) ;
if ( output_ ) {
2012-09-17 00:54:50 -05:00
output_vtk_ = param . getDefault ( " output_vtk " , true ) ;
2012-11-26 04:01:23 -06:00
output_binary_ = param . getDefault ( " output_binary " , false ) ;
# ifndef HAVE_ERT
if ( output_binary_ ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Cannot make binary output without ert library support. Reconfigure opm-core and opm-polymer with --with-ert and recompile. " ) ;
2012-11-26 04:01:23 -06:00
}
# endif
2012-06-13 08:46:15 -05:00
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 ( . . . ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Creating directories failed: " < < fpath ) ;
2012-06-13 08:46:15 -05:00
}
output_interval_ = param . getDefault ( " output_interval " , 1 ) ;
}
2012-10-10 16:19:35 -05:00
// Well control related init.
check_well_controls_ = param . getDefault ( " check_well_controls " , false ) ;
max_well_control_iterations_ = param . getDefault ( " max_well_control_iterations " , 10 ) ;
2012-06-13 08:46:15 -05:00
// Transport related init.
2013-03-15 12:33:41 -05:00
TransportSolverTwophasePolymer : : SingleCellMethod method ;
2012-06-13 08:46:15 -05:00
std : : string method_string = param . getDefault ( " single_cell_method " , std : : string ( " Bracketing " ) ) ;
if ( method_string = = " Bracketing " ) {
2013-03-15 12:33:41 -05:00
method = Opm : : TransportSolverTwophasePolymer : : Bracketing ;
2012-06-13 08:46:15 -05:00
} else if ( method_string = = " Newton " ) {
2013-03-15 12:33:41 -05:00
method = Opm : : TransportSolverTwophasePolymer : : Newton ;
2012-06-13 08:46:15 -05:00
} else {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Unknown method: " < < method_string ) ;
2012-06-13 08:46:15 -05:00
}
tsolver_ . setPreferredMethod ( method ) ;
num_transport_substeps_ = param . getDefault ( " num_transport_substeps " , 1 ) ;
use_segregation_split_ = param . getDefault ( " use_segregation_split " , false ) ;
2012-10-15 07:23:13 -05:00
if ( gravity ! = 0 & & use_segregation_split_ ) {
2012-06-13 08:46:15 -05:00
tsolver_ . initGravity ( gravity ) ;
extractColumn ( grid_ , columns_ ) ;
}
// 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 ;
}
}
2012-06-14 07:26:29 -05:00
SimulatorReport SimulatorPolymer : : Impl : : run ( SimulatorTimer & timer ,
PolymerState & state ,
WellState & well_state )
2012-06-13 08:46:15 -05:00
{
2012-10-04 06:38:22 -05:00
std : : vector < double > transport_src ( grid_ . number_of_cells ) ;
std : : vector < double > polymer_inflow_c ( grid_ . number_of_cells ) ;
2012-06-13 08:46:15 -05:00
// 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 ) ;
2012-10-10 16:19:35 -05:00
std : : vector < double > initial_porevol = porevol ;
2012-06-13 08:46:15 -05:00
// Main simulation loop.
Opm : : time : : StopWatch pressure_timer ;
double ptime = 0.0 ;
Opm : : time : : StopWatch transport_timer ;
double ttime = 0.0 ;
Opm : : time : : StopWatch total_timer ;
total_timer . start ( ) ;
double init_satvol [ 2 ] = { 0.0 } ;
double satvol [ 2 ] = { 0.0 } ;
2012-10-04 13:02:34 -05:00
double polymass = computePolymerMass ( porevol , state . saturation ( ) , state . concentration ( ) , poly_props_ . deadPoreVol ( ) ) ;
double polymass_adsorbed = computePolymerAdsorbed ( props_ , poly_props_ , porevol , state . maxconcentration ( ) ) ;
double init_polymass = polymass + polymass_adsorbed ;
2012-06-13 08:46:15 -05:00
double injected [ 2 ] = { 0.0 } ;
double produced [ 2 ] = { 0.0 } ;
double polyinj = 0.0 ;
double polyprod = 0.0 ;
double tot_injected [ 2 ] = { 0.0 } ;
double tot_produced [ 2 ] = { 0.0 } ;
double tot_polyinj = 0.0 ;
double tot_polyprod = 0.0 ;
Opm : : computeSaturatedVol ( porevol , state . saturation ( ) , init_satvol ) ;
std : : cout < < " \n Initial saturations are " < < init_satvol [ 0 ] / tot_porevol_init
< < " " < < init_satvol [ 1 ] / tot_porevol_init < < std : : endl ;
Opm : : Watercut watercut ;
watercut . push ( 0.0 , 0.0 , 0.0 ) ;
Opm : : WellReport wellreport ;
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 ) ;
wellreport . push ( props_ , * wells_ , state . saturation ( ) , 0.0 , well_state . bhp ( ) , well_state . perfRates ( ) ) ;
}
for ( ; ! timer . done ( ) ; + + timer ) {
// Report timestep and (optionally) write state to disk.
timer . report ( std : : cout ) ;
if ( output_ & & ( timer . currentStepNum ( ) % output_interval_ = = 0 ) ) {
2012-09-17 00:54:50 -05:00
if ( output_vtk_ ) {
outputStateVtk ( grid_ , state , timer . currentStepNum ( ) , output_dir_ ) ;
}
2012-11-26 04:01:23 -06:00
if ( output_binary_ ) {
outputStateBinary ( grid_ , state , timer , output_dir_ ) ;
}
2012-09-17 00:54:50 -05:00
outputStateMatlab ( grid_ , state , timer . currentStepNum ( ) , output_dir_ ) ;
2012-06-13 08:46:15 -05:00
}
// Solve pressure.
2012-10-10 16:19:35 -05:00
if ( check_well_controls_ ) {
computeFractionalFlow ( props_ , poly_props_ , allcells_ ,
state . saturation ( ) , state . concentration ( ) , state . maxconcentration ( ) ,
fractional_flows ) ;
wells_manager_ . applyExplicitReinjectionControls ( well_resflows_phase , well_resflows_phase ) ;
}
bool well_control_passed = ! check_well_controls_ ;
int well_control_iteration = 0 ;
2012-06-13 08:46:15 -05:00
do {
2012-10-10 16:19:35 -05:00
// Run solver.
2012-06-13 08:46:15 -05:00
pressure_timer . start ( ) ;
2012-10-10 16:19:35 -05:00
std : : vector < double > initial_pressure = state . pressure ( ) ;
2012-06-13 08:46:15 -05:00
psolver_ . solve ( timer . currentStepLength ( ) , state , well_state ) ;
2012-10-10 16:19:35 -05:00
// Renormalize pressure if rock is incompressible, and
// there are no pressure conditions (bcs or wells).
// It is deemed sufficient for now to renormalize
// using geometric volume instead of pore volume.
if ( ( rock_comp_props_ = = NULL | | ! rock_comp_props_ - > isActive ( ) )
& & allNeumannBCs ( bcs_ ) & & allRateWells ( wells_ ) ) {
// Compute average pressures of previous and last
// step, and total volume.
double av_prev_press = 0.0 ;
double av_press = 0.0 ;
double tot_vol = 0.0 ;
const int num_cells = grid_ . number_of_cells ;
for ( int cell = 0 ; cell < num_cells ; + + cell ) {
av_prev_press + = initial_pressure [ cell ] * grid_ . cell_volumes [ cell ] ;
av_press + = state . pressure ( ) [ cell ] * grid_ . cell_volumes [ cell ] ;
tot_vol + = grid_ . cell_volumes [ cell ] ;
}
// Renormalization constant
const double ren_const = ( av_prev_press - av_press ) / tot_vol ;
for ( int cell = 0 ; cell < num_cells ; + + cell ) {
state . pressure ( ) [ cell ] + = ren_const ;
}
const int num_wells = ( wells_ = = NULL ) ? 0 : wells_ - > number_of_wells ;
for ( int well = 0 ; well < num_wells ; + + well ) {
well_state . bhp ( ) [ well ] + = ren_const ;
}
}
// Stop timer and report.
2012-06-13 08:46:15 -05:00
pressure_timer . stop ( ) ;
double pt = pressure_timer . secsSinceStart ( ) ;
std : : cout < < " Pressure solver took: " < < pt < < " seconds. " < < std : : endl ;
ptime + = pt ;
2012-10-10 16:19:35 -05:00
// 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_ ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Could not satisfy well conditions in " < < max_well_control_iterations_ < < " tries. " ) ;
2012-10-10 16:19:35 -05:00
}
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 ) ;
2012-06-13 08:46:15 -05:00
2012-06-14 14:53:56 -05:00
// Update pore volumes if rock is compressible.
if ( rock_comp_props_ & & rock_comp_props_ - > isActive ( ) ) {
2012-10-10 16:19:35 -05:00
initial_porevol = porevol ;
2012-06-14 14:53:56 -05:00
computePorevolume ( grid_ , props_ . porosity ( ) , * rock_comp_props_ , state . pressure ( ) , porevol ) ;
}
2012-06-13 08:46:15 -05:00
// Process transport sources (to include bdy terms and well flows).
Opm : : computeTransportSource ( grid_ , src_ , state . faceflux ( ) , 1.0 ,
wells_ , well_state . perfRates ( ) , transport_src ) ;
// Find inflow rate.
2014-03-18 06:42:42 -05:00
const double current_time = timer . simulationTimeElapsed ( ) ;
2012-06-13 08:46:15 -05:00
double stepsize = timer . currentStepLength ( ) ;
2012-10-04 09:00:33 -05:00
polymer_inflow_ . getInflowValues ( current_time , current_time + stepsize , polymer_inflow_c ) ;
2012-06-13 08:46:15 -05:00
// Solve transport.
transport_timer . start ( ) ;
if ( num_transport_substeps_ ! = 1 ) {
stepsize / = double ( num_transport_substeps_ ) ;
std : : cout < < " Making " < < num_transport_substeps_ < < " transport substeps. " < < std : : endl ;
}
2012-10-03 07:25:20 -05:00
double substep_injected [ 2 ] = { 0.0 } ;
double substep_produced [ 2 ] = { 0.0 } ;
double substep_polyinj = 0.0 ;
double substep_polyprod = 0.0 ;
injected [ 0 ] = injected [ 1 ] = produced [ 0 ] = produced [ 1 ] = polyinj = polyprod = 0.0 ;
2012-06-13 08:46:15 -05:00
for ( int tr_substep = 0 ; tr_substep < num_transport_substeps_ ; + + tr_substep ) {
2012-10-10 16:19:35 -05:00
tsolver_ . solve ( & state . faceflux ( ) [ 0 ] , & initial_porevol [ 0 ] , & transport_src [ 0 ] , & polymer_inflow_c [ 0 ] , stepsize ,
2012-06-13 08:46:15 -05:00
state . saturation ( ) , state . concentration ( ) , state . maxconcentration ( ) ) ;
Opm : : computeInjectedProduced ( props_ , poly_props_ ,
2012-10-04 15:32:55 -05:00
state ,
2012-10-04 06:38:22 -05:00
transport_src , polymer_inflow_c , stepsize ,
2012-10-03 07:25:20 -05:00
substep_injected , substep_produced , substep_polyinj , substep_polyprod ) ;
injected [ 0 ] + = substep_injected [ 0 ] ;
injected [ 1 ] + = substep_injected [ 1 ] ;
produced [ 0 ] + = substep_produced [ 0 ] ;
produced [ 1 ] + = substep_produced [ 1 ] ;
polyinj + = substep_polyinj ;
polyprod + = substep_polyprod ;
2012-06-13 08:46:15 -05:00
if ( use_segregation_split_ ) {
tsolver_ . solveGravity ( columns_ , & porevol [ 0 ] , stepsize ,
state . saturation ( ) , state . concentration ( ) , state . maxconcentration ( ) ) ;
}
}
transport_timer . stop ( ) ;
double tt = transport_timer . secsSinceStart ( ) ;
std : : cout < < " Transport solver took: " < < tt < < " seconds. " < < std : : endl ;
ttime + = tt ;
// Report volume balances.
Opm : : computeSaturatedVol ( porevol , state . saturation ( ) , satvol ) ;
polymass = Opm : : computePolymerMass ( porevol , state . saturation ( ) , state . concentration ( ) , poly_props_ . deadPoreVol ( ) ) ;
polymass_adsorbed = Opm : : computePolymerAdsorbed ( props_ , poly_props_ , porevol , state . maxconcentration ( ) ) ;
tot_injected [ 0 ] + = injected [ 0 ] ;
tot_injected [ 1 ] + = injected [ 1 ] ;
tot_produced [ 0 ] + = produced [ 0 ] ;
tot_produced [ 1 ] + = produced [ 1 ] ;
tot_polyinj + = polyinj ;
tot_polyprod + = polyprod ;
std : : cout . precision ( 5 ) ;
const int width = 18 ;
std : : cout < < " \n Volume and polymer mass balance: "
" water(pv) oil(pv) polymer(kg) \n " ;
std : : cout < < " Saturated volumes: "
< < std : : setw ( width ) < < satvol [ 0 ] / tot_porevol_init
< < std : : setw ( width ) < < satvol [ 1 ] / tot_porevol_init
< < std : : setw ( width ) < < polymass < < std : : endl ;
std : : cout < < " Adsorbed volumes: "
< < std : : setw ( width ) < < 0.0
< < std : : setw ( width ) < < 0.0
< < std : : setw ( width ) < < polymass_adsorbed < < std : : endl ;
std : : cout < < " Injected volumes: "
< < std : : setw ( width ) < < injected [ 0 ] / tot_porevol_init
< < std : : setw ( width ) < < injected [ 1 ] / tot_porevol_init
< < std : : setw ( width ) < < polyinj < < std : : endl ;
std : : cout < < " Produced volumes: "
< < std : : setw ( width ) < < produced [ 0 ] / tot_porevol_init
< < std : : setw ( width ) < < produced [ 1 ] / tot_porevol_init
< < std : : setw ( width ) < < polyprod < < std : : endl ;
std : : cout < < " Total inj volumes: "
< < std : : setw ( width ) < < tot_injected [ 0 ] / tot_porevol_init
< < std : : setw ( width ) < < tot_injected [ 1 ] / tot_porevol_init
< < std : : setw ( width ) < < tot_polyinj < < std : : endl ;
std : : cout < < " Total prod volumes: "
< < std : : setw ( width ) < < tot_produced [ 0 ] / tot_porevol_init
< < std : : setw ( width ) < < tot_produced [ 1 ] / tot_porevol_init
< < std : : setw ( width ) < < tot_polyprod < < std : : endl ;
std : : cout < < " In-place + prod - inj: "
< < std : : setw ( width ) < < ( satvol [ 0 ] + tot_produced [ 0 ] - tot_injected [ 0 ] ) / tot_porevol_init
< < std : : setw ( width ) < < ( satvol [ 1 ] + tot_produced [ 1 ] - tot_injected [ 1 ] ) / tot_porevol_init
< < std : : setw ( width ) < < ( polymass + tot_polyprod - tot_polyinj + polymass_adsorbed ) < < std : : endl ;
std : : cout < < " Init - now - pr + inj: "
< < std : : setw ( width ) < < ( init_satvol [ 0 ] - satvol [ 0 ] - tot_produced [ 0 ] + tot_injected [ 0 ] ) / tot_porevol_init
< < std : : setw ( width ) < < ( init_satvol [ 1 ] - satvol [ 1 ] - tot_produced [ 1 ] + tot_injected [ 1 ] ) / tot_porevol_init
< < std : : setw ( width ) < < ( init_polymass - polymass - tot_polyprod + tot_polyinj - polymass_adsorbed )
< < std : : endl ;
std : : cout . precision ( 8 ) ;
2014-03-18 06:42:42 -05:00
watercut . push ( timer . simulationTimeElapsed ( ) + timer . currentStepLength ( ) ,
2012-06-13 08:46:15 -05:00
produced [ 0 ] / ( produced [ 0 ] + produced [ 1 ] ) ,
tot_produced [ 0 ] / tot_porevol_init ) ;
if ( wells_ ) {
wellreport . push ( props_ , * wells_ , state . saturation ( ) ,
2014-03-18 06:42:42 -05:00
timer . simulationTimeElapsed ( ) + timer . currentStepLength ( ) ,
2012-06-13 08:46:15 -05:00
well_state . bhp ( ) , well_state . perfRates ( ) ) ;
}
}
if ( output_ ) {
2012-09-17 00:54:50 -05:00
if ( output_vtk_ ) {
outputStateVtk ( grid_ , state , timer . currentStepNum ( ) , output_dir_ ) ;
}
2012-11-26 04:01:23 -06:00
if ( output_binary_ ) {
outputStateBinary ( grid_ , state , timer , output_dir_ ) ;
}
2012-09-17 00:54:50 -05:00
outputStateMatlab ( grid_ , state , timer . currentStepNum ( ) , output_dir_ ) ;
2012-06-13 08:46:15 -05:00
outputWaterCut ( watercut , output_dir_ ) ;
if ( wells_ ) {
outputWellReport ( wellreport , output_dir_ ) ;
}
}
2012-06-14 06:24:38 -05:00
total_timer . stop ( ) ;
SimulatorReport report ;
report . pressure_time = ptime ;
report . transport_time = ttime ;
report . total_time = total_timer . secsSinceStart ( ) ;
return report ;
2012-06-13 08:46:15 -05:00
}
namespace
{
2012-09-17 00:54:50 -05:00
void outputStateVtk ( const UnstructuredGrid & grid ,
const Opm : : PolymerState & state ,
const int step ,
const std : : string & output_dir )
2012-06-13 08:46:15 -05:00
{
// Write data in VTK format.
std : : ostringstream vtkfilename ;
2012-09-17 00:54:50 -05:00
vtkfilename < < output_dir < < " /vtk_files " ;
boost : : filesystem : : path fpath ( vtkfilename . str ( ) ) ;
try {
create_directories ( fpath ) ;
}
catch ( . . . ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Creating directories failed: " < < fpath ) ;
2012-09-17 00:54:50 -05:00
}
2012-11-05 08:37:14 -06:00
vtkfilename < < " /output- " < < std : : setw ( 5 ) < < std : : setfill ( ' 0 ' ) < < step < < " .vtu " ;
2012-06-13 08:46:15 -05:00
std : : ofstream vtkfile ( vtkfilename . str ( ) . c_str ( ) ) ;
if ( ! vtkfile ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Failed to open " < < vtkfilename . str ( ) ) ;
2012-06-13 08:46:15 -05:00
}
Opm : : DataMap dm ;
dm [ " saturation " ] = & state . saturation ( ) ;
dm [ " pressure " ] = & state . pressure ( ) ;
dm [ " concentration " ] = & state . concentration ( ) ;
dm [ " cmax " ] = & state . maxconcentration ( ) ;
std : : vector < double > cell_velocity ;
Opm : : estimateCellVelocity ( grid , state . faceflux ( ) , cell_velocity ) ;
dm [ " velocity " ] = & cell_velocity ;
Opm : : writeVtkData ( grid , dm , vtkfile ) ;
}
2012-09-17 00:54:50 -05:00
void outputStateMatlab ( const UnstructuredGrid & grid ,
const Opm : : PolymerState & state ,
const int step ,
const std : : string & output_dir )
{
Opm : : DataMap dm ;
dm [ " saturation " ] = & state . saturation ( ) ;
dm [ " pressure " ] = & state . pressure ( ) ;
dm [ " concentration " ] = & state . concentration ( ) ;
dm [ " cmax " ] = & state . maxconcentration ( ) ;
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 ( . . . ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Creating directories failed: " < < fpath ) ;
2012-09-17 00:54:50 -05:00
}
2012-11-05 08:37:14 -06:00
fname < < " / " < < std : : setw ( 5 ) < < std : : setfill ( ' 0 ' ) < < step < < " .txt " ;
2012-09-17 00:54:50 -05:00
std : : ofstream file ( fname . str ( ) . c_str ( ) ) ;
if ( ! file ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Failed to open " < < fname . str ( ) ) ;
2012-09-17 00:54:50 -05:00
}
const std : : vector < double > & d = * ( it - > second ) ;
std : : copy ( d . begin ( ) , d . end ( ) , std : : ostream_iterator < double > ( file , " \n " ) ) ;
}
}
2012-06-13 08:46:15 -05:00
2012-11-26 04:01:23 -06:00
void outputStateBinary ( const UnstructuredGrid & grid ,
const Opm : : PolymerState & state ,
const SimulatorTimer & simtimer ,
const std : : string & output_dir )
{
# ifdef HAVE_ERT
Opm : : DataMap dm ;
dm [ " saturation " ] = & state . saturation ( ) ;
dm [ " pressure " ] = & state . pressure ( ) ;
dm [ " concentration " ] = & state . concentration ( ) ;
dm [ " cmax " ] = & state . maxconcentration ( ) ;
std : : vector < double > cell_velocity ;
Opm : : estimateCellVelocity ( grid , state . faceflux ( ) , cell_velocity ) ;
dm [ " velocity " ] = & cell_velocity ;
2014-03-18 06:42:42 -05:00
writeECLData ( grid , dm , simtimer . currentStepNum ( ) , simtimer . simulationTimeElapsed ( ) , simtimer . currentDateTime ( ) ,
2012-11-26 04:01:23 -06:00
output_dir , " polymer_ecl " ) ;
# else
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Cannot call outputStateBinary() without ert library support. Reconfigure with --with-ert and recompile. " ) ;
2012-11-26 04:01:23 -06:00
# endif
}
2012-06-13 08:46:15 -05:00
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 ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Failed to open " < < fname ) ;
2012-06-13 08:46:15 -05:00
}
watercut . write ( os ) ;
}
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 ) {
2013-09-03 08:00:29 -05:00
OPM_THROW ( std : : runtime_error , " Failed to open " < < fname ) ;
2012-06-13 08:46:15 -05:00
}
wellreport . write ( os ) ;
}
2012-10-10 16:19:35 -05:00
bool allNeumannBCs ( const FlowBoundaryConditions * bcs )
{
if ( bcs = = NULL ) {
return true ;
} else {
return std : : find ( bcs - > type , bcs - > type + bcs - > nbc , BC_PRESSURE )
= = bcs - > type + bcs - > nbc ;
}
}
bool allRateWells ( const Wells * wells )
{
if ( wells = = NULL ) {
return true ;
}
const int nw = wells - > number_of_wells ;
for ( int w = 0 ; w < nw ; + + w ) {
const WellControls * wc = wells - > ctrls [ w ] ;
2014-01-09 05:06:26 -06:00
if ( well_controls_get_current ( wc ) > = 0 ) {
if ( well_controls_get_current_type ( wc ) = = BHP ) {
2012-10-10 16:19:35 -05:00
return false ;
}
}
}
return true ;
}
2014-01-09 05:06:26 -06:00
2012-06-13 08:46:15 -05:00
} // anonymous namespace
} // namespace Opm