Ability to pass misc values to summary writer.

This commit is contained in:
Joakim Hove 2017-06-06 13:02:46 +02:00
parent ac70c34c68
commit 9120c67cf8
9 changed files with 193 additions and 89 deletions

View File

@ -122,9 +122,9 @@ public:
* can be added here are represented with mnenonics in the RPTRST
* keyword.
*
* The extra argument is an optional aergument which can be used
* to store arbitrary double vectors in the restart file. The
* following rules apply for the extra data:
* The extra_restart argument is an optional aergument which can
* be used to store arbitrary double vectors in the restart
* file. The following rules apply for the extra data:
*
* 1. There is no size constraints.
*
@ -139,6 +139,20 @@ public:
* precision. OPM can load and restart from files with double
* precision keywords, but this is non-standard, and other third
* party applications might choke on those.
*
* The misc_summary_values argument is used to pass pass various
* summary values which are of type 'ECL_SMSPEC_MISC_VAR' to the
* summary writer. The ability to pass miscellanous values to the
* summary writer is not very flexible:
*
* 1. The keyword must be an already well defined ECLIPSE keyword
* like e.g. one of the performance related keywords.
*
* 2. The keyword must have been requested in the SUMMARY section
* of the input deck.
*
* 3. The dimension of the keyword must have specified in the
* hardcoded static map misc_units in Summary.cpp.
*/
void writeTimeStep( int report_step,
@ -146,7 +160,8 @@ public:
double seconds_elapsed,
data::Solution,
data::Wells,
std::map<std::string, std::vector<double>> extra = {},
std::map<std::string, double> misc_summary_values,
std::map<std::string, std::vector<double>> extra_restart = {},
bool write_double = false);

View File

@ -53,7 +53,8 @@ class Summary {
double secs_elapsed,
const EclipseState& es,
const data::Wells&,
const data::Solution& );
const data::Solution&,
const std::map<std::string, double>& misc_values);
void set_initial( const data::Solution& );
void write();

View File

@ -380,7 +380,8 @@ void EclipseIO::writeTimeStep(int report_step,
double secs_elapsed,
data::Solution cells,
data::Wells wells,
std::map<std::string, std::vector<double>> extra,
std::map<std::string, double> misc_summary_values,
std::map<std::string, std::vector<double>> extra_restart,
bool write_double)
{
@ -404,7 +405,8 @@ void EclipseIO::writeTimeStep(int report_step,
secs_elapsed,
es,
wells ,
cells );
cells ,
misc_summary_values );
this->impl->summary.write();
}
@ -422,7 +424,7 @@ void EclipseIO::writeTimeStep(int report_step,
report_step,
ioConfig.getFMTOUT() );
RestartIO::save( filename , report_step, secs_elapsed, cells, wells, es , grid , extra , write_double);
RestartIO::save( filename , report_step, secs_elapsed, cells, wells, es , grid , extra_restart , write_double);
}

View File

@ -479,9 +479,6 @@ quantity bsgas( const fn_args& args) {
}
quantity extra_time( const fn_args& args) {
return { 0.0, measure::time };
}
template< typename F, typename G >
@ -736,12 +733,26 @@ static const std::unordered_map< std::string, ofun > funs = {
{"BWSAT" , bswat},
{"BSGAS" , bsgas},
{"BGSAS" , bsgas},
/* Misc keywords, the 'extra' handlers will only set the value 0 - with the correct dimension*/
{"TCPU" , extra_time}
};
static const std::unordered_map< std::string, UnitSystem::measure> misc_units = {
{"TCPU" , UnitSystem::measure::identity },
{"ELAPSED" , UnitSystem::measure::identity },
{"NEWTON" , UnitSystem::measure::identity },
{"NLINERS" , UnitSystem::measure::identity },
{"NLINSMIN" , UnitSystem::measure::identity },
{"NLINSMAX" , UnitSystem::measure::identity },
{"MLINEARS" , UnitSystem::measure::identity },
{"MSUMLINS" , UnitSystem::measure::identity },
{"MSUMNEWT" , UnitSystem::measure::identity },
{"TCPUTS" , UnitSystem::measure::identity },
{"TIMESTEP" , UnitSystem::measure::time },
{"TCPUDAY" , UnitSystem::measure::time },
{"STEPTYPE" , UnitSystem::measure::identity },
{"TELAPLIN" , UnitSystem::measure::time }
};
inline std::vector< const Well* > find_wells( const Schedule& schedule,
const smspec_node_type* node,
size_t timestep ) {
@ -784,6 +795,7 @@ class Summary::keyword_handlers {
public:
using fn = ofun;
std::vector< std::pair< smspec_node_type*, fn > > handlers;
std::map< std::string, smspec_node_type* > misc_nodes;
};
Summary::Summary( const EclipseState& st,
@ -826,35 +838,60 @@ Summary::Summary( const EclipseState& st,
*/
for( const auto& node : sum ) {
const auto* keyword = node.keyword();
if( funs.find( keyword ) == funs.end() ) continue;
if ((node.type() == ECL_SMSPEC_COMPLETION_VAR) || (node.type() == ECL_SMSPEC_BLOCK_VAR)) {
int global_index = node.num() - 1;
if (!this->grid.cellActive(global_index))
continue;
}
/*
All summary values of the type ECL_SMSPEC_MISC_VAR must be
passed explicitly in the misc_values map when calling
add_timestep.
*/
if (node.type() == ECL_SMSPEC_MISC_VAR) {
const auto pair = misc_units.find( keyword );
if (pair == misc_units.end())
continue;
/* get unit strings by calling each function with dummy input */
const auto handle = funs.find( keyword )->second;
const std::vector< const Well* > dummy_wells;
auto* nodeptr = ecl_sum_add_var( this->ecl_sum.get(),
keyword,
node.wgname(),
node.num(),
st.getUnits().name( pair->second ),
0 );
const fn_args no_args { dummy_wells, // Wells from Schedule object
0, // Duration of time step
0, // Timestep number
node.num(), // NUMS value for the summary output.
{}, // Well results - data::Wells
{}, // Solution::State
{}, // Region <-> cell mappings.
this->grid,
this->initial_oip,
{} };
this->handlers->misc_nodes.emplace( keyword, nodeptr );
} else {
if( funs.find( keyword ) == funs.end() ) continue;
const auto val = handle( no_args );
const auto* unit = st.getUnits().name( val.unit );
if ((node.type() == ECL_SMSPEC_COMPLETION_VAR) || (node.type() == ECL_SMSPEC_BLOCK_VAR)) {
int global_index = node.num() - 1;
if (!this->grid.cellActive(global_index))
continue;
}
auto* nodeptr = ecl_sum_add_var( this->ecl_sum.get(), keyword,
node.wgname(), node.num(), unit, 0 );
this->handlers->handlers.emplace_back( nodeptr, handle );
/* get unit strings by calling each function with dummy input */
const auto handle = funs.find( keyword )->second;
const std::vector< const Well* > dummy_wells;
const fn_args no_args { dummy_wells, // Wells from Schedule object
0, // Duration of time step
0, // Timestep number
node.num(), // NUMS value for the summary output.
{}, // Well results - data::Wells
{}, // Solution::State
{}, // Region <-> cell mappings.
this->grid,
this->initial_oip,
{} };
const auto val = handle( no_args );
auto* nodeptr = ecl_sum_add_var( this->ecl_sum.get(),
keyword,
node.wgname(),
node.num(),
st.getUnits().name( val.unit ),
0 );
this->handlers->handlers.emplace_back( nodeptr, handle );
}
}
}
@ -862,7 +899,8 @@ void Summary::add_timestep( int report_step,
double secs_elapsed,
const EclipseState& es,
const data::Wells& wells ,
const data::Solution& state) {
const data::Solution& state,
const std::map<std::string, double>& misc_values) {
auto* tstep = ecl_sum_add_tstep( this->ecl_sum.get(), report_step, secs_elapsed );
const double duration = secs_elapsed - this->prev_time_elapsed;
@ -891,7 +929,20 @@ void Summary::add_timestep( int report_step,
? ecl_sum_tstep_get_from_key( prev_tstep, genkey ) + unit_applied_val
: unit_applied_val;
ecl_sum_tstep_set_from_node( tstep, f.first, res );
ecl_sum_tstep_set_from_node( tstep, f.first, res );
}
for( const auto& value_pair : misc_values ) {
const std::string key = value_pair.first;
const auto node_pair = this->handlers->misc_nodes.find( key );
if (node_pair != this->handlers->misc_nodes.end()) {
const auto * nodeptr = node_pair->second;
const auto unit = misc_units.at( key );
double si_value = value_pair.second;
double output_value = es.getUnits().from_si(unit , si_value );
ecl_sum_tstep_set_from_node( tstep, nodeptr , output_value );
}
}
this->prev_tstep = tstep;

View File

@ -324,10 +324,12 @@ BOOST_AUTO_TEST_CASE(EclipseIOIntegration) {
auto first_step = ecl_util_make_date( 10 + i, 11, 2008 );
eclWriter.writeTimeStep( i,
false,
first_step - start_time,
sol,
wells);
false,
first_step - start_time,
sol,
wells,
{});
checkRestartFile( i );

View File

@ -142,7 +142,8 @@ BOOST_AUTO_TEST_CASE(test_RFT) {
false,
step_time - start_time,
createBlackoilState( 2, numCells ),
wells);
wells,
{});
}
verifyRFTFile("TESTRFT.RFT");

View File

@ -360,7 +360,7 @@ RestartValue first_sim(const EclipseState& es, EclipseIO& eclWriter, bool write_
eclWriter.writeTimeStep( 1,
false,
first_step - start_time,
sol, wells , {}, write_double);
sol, wells , {}, {}, write_double);
return { sol, wells , {}};
}

View File

@ -238,9 +238,9 @@ BOOST_AUTO_TEST_CASE(well_keywords) {
cfg.name = "PATH/CASE";
out::Summary writer( cfg.es, cfg.config, cfg.grid , cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution , {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution , {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution , {});
writer.write();
auto res = readsum( cfg.name );
@ -374,9 +374,9 @@ BOOST_AUTO_TEST_CASE(group_keywords) {
setup cfg( "test_Summary_group" );
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution , {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution , {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution , {});
writer.write();
auto res = readsum( cfg.name );
@ -472,9 +472,9 @@ BOOST_AUTO_TEST_CASE(completion_kewords) {
setup cfg( "test_Summary_completion" );
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
@ -525,9 +525,9 @@ BOOST_AUTO_TEST_CASE(field_keywords) {
setup cfg( "test_Summary_field" );
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
@ -623,9 +623,9 @@ BOOST_AUTO_TEST_CASE(foe_test) {
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.set_initial( sol );
writer.add_timestep( 1, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 5 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 10 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 5 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 10 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
@ -643,9 +643,9 @@ BOOST_AUTO_TEST_CASE(report_steps_time) {
setup cfg( "test_Summary_report_steps_time" );
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 1, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 5 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 10 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 5 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 10 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
@ -665,9 +665,9 @@ BOOST_AUTO_TEST_CASE(skip_unknown_var) {
setup cfg( "test_Summary_skip_unknown_var" );
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 1, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 5 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 10 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 5 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 10 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
@ -685,9 +685,9 @@ BOOST_AUTO_TEST_CASE(region_vars) {
{
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 1, 2 * day, cfg.es, cfg.wells, cfg.solution);
writer.add_timestep( 1, 5 * day, cfg.es, cfg.wells, cfg.solution);
writer.add_timestep( 2, 10 * day, cfg.es, cfg.wells, cfg.solution);
writer.add_timestep( 1, 2 * day, cfg.es, cfg.wells, cfg.solution, {});
writer.add_timestep( 1, 5 * day, cfg.es, cfg.wells, cfg.solution, {});
writer.add_timestep( 2, 10 * day, cfg.es, cfg.wells, cfg.solution, {});
writer.write();
}
@ -732,9 +732,9 @@ BOOST_AUTO_TEST_CASE(region_production) {
{
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
}
@ -760,9 +760,9 @@ BOOST_AUTO_TEST_CASE(region_injection) {
setup cfg( "region_injection" );
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
@ -789,9 +789,9 @@ BOOST_AUTO_TEST_CASE(BLOCK_VARIABLES) {
setup cfg( "region_injection" );
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
@ -855,9 +855,9 @@ BOOST_AUTO_TEST_CASE(fpr) {
setup cfg( "test_fpr", "summary_deck_non_constant_porosity.DATA");
out::Summary writer( cfg.es, cfg.config, cfg.grid, cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
@ -884,9 +884,9 @@ BOOST_AUTO_TEST_CASE(fpr) {
}
out::Summary writer2( cfg.es, cfg.config, cfg.grid, cfg.name );
writer2.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer2.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer2.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer2.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, {});
writer2.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, {});
writer2.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer2.write();
auto res2 = readsum( cfg.name );
@ -904,12 +904,43 @@ BOOST_AUTO_TEST_CASE(MISC) {
setup cfg( "test_MISC");
out::Summary writer( cfg.es, cfg.config, cfg.grid , cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution);
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, {});
writer.write();
auto res = readsum( cfg.name );
const auto* resp = res.get();
BOOST_CHECK( ecl_sum_has_key( resp , "TCPU" ));
}
BOOST_AUTO_TEST_CASE(EXTRA) {
setup cfg( "test_EXTRA");
{
out::Summary writer( cfg.es, cfg.config, cfg.grid , cfg.name );
writer.add_timestep( 0, 0 * day, cfg.es, cfg.wells , cfg.solution, { {"TCPU" , 0 }});
writer.add_timestep( 1, 1 * day, cfg.es, cfg.wells , cfg.solution, { {"TCPU" , 1 }});
writer.add_timestep( 2, 2 * day, cfg.es, cfg.wells , cfg.solution, { {"TCPU" , 2}});
/* Add a not-recognized key; that is OK */
BOOST_CHECK_NO_THROW( writer.add_timestep( 3, 3 * day, cfg.es, cfg.wells , cfg.solution, { {"MISSING" , 2 }}));
/* Override a NOT MISC variable - ignored. */
writer.add_timestep( 4, 4 * day, cfg.es, cfg.wells , cfg.solution, { {"FOPR" , -1 }});
writer.write();
}
auto res = readsum( cfg.name );
const auto* resp = res.get();
BOOST_CHECK( ecl_sum_has_key( resp , "TCPU" ));
BOOST_CHECK_CLOSE( 1 , ecl_sum_get_general_var( resp , 1 , "TCPU") , 0.001);
BOOST_CHECK_CLOSE( 2 , ecl_sum_get_general_var( resp , 2 , "TCPU") , 0.001);
/* Not passed - should be zero. */
BOOST_CHECK_CLOSE( 0 , ecl_sum_get_general_var( resp , 4 , "TCPU") , 0.001);
/* Override a NOT MISC variable - ignored. */
BOOST_CHECK( ecl_sum_get_general_var( resp , 4 , "FOPR") > 0.0 );
}

View File

@ -155,7 +155,8 @@ BOOST_AUTO_TEST_CASE(EclipseWriteRestartWellInfo) {
false,
timestep,
solution,
wells );
wells ,
{} );
}
verifyWellState(eclipse_restart_filename, es.getInputGrid(), es.getSchedule());