Files
opm-core/tests/test_wellsmanager.cpp
Andreas Lauser c5a0ea7524 do not explicitly pass the permeability to the well model anymore
this information is already part of the EclipseState. The reason why
this should IMO be avoided is that this enforces an implementation
(ordering of the permeability matrices) the simulator on the well
model. If this needs to be done for performance reasons, IMO it would
be smarter to pass an array of matrices, instead of passing a raw
array of doubles.  I doubt that this is necessary, though: completing
the full Norne deck takes about 0.25 seconds longer on my machine,
that's substantially less than 0.1% of the total runtime.

in order to avoid code duplication, the permeability extraction
function of the RockFromDeck class is now made a public static
function and used as an implementation detail of the WellsManager.

finally, the permfield_valid_ attribute is removed from the
RockFromDeck class because this data was unused and not accessible via
the class' public API.
2017-01-27 12:51:12 +01:00

285 lines
11 KiB
C++

/*
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>
#if HAVE_DYNAMIC_BOOST_TEST
#define BOOST_TEST_DYN_LINK
#endif
#define NVERBOSE // Suppress own messages when throw()ing
#define BOOST_TEST_MODULE WellsManagerTests
#include <boost/test/unit_test.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/core/wells/WellsManager.hpp>
#include <opm/core/wells.h>
#include <opm/core/well_controls.h>
#include <opm/core/grid/GridManager.hpp>
void wells_static_check(const Wells* wells) {
BOOST_CHECK_EQUAL(2, wells->number_of_wells);
BOOST_CHECK_EQUAL(3, wells->number_of_phases);
BOOST_CHECK_EQUAL("INJ1", wells->name[0]);
BOOST_CHECK_EQUAL("PROD1", wells->name[1]);
/* The mapping from well number into the wells->WI and wells->well_cells arrays. */
BOOST_CHECK_EQUAL(0, wells->well_connpos[0]);
BOOST_CHECK_EQUAL(1, wells->well_connpos[1]);
BOOST_CHECK_EQUAL(2, wells->well_connpos[2]);
/* Connection factor */
BOOST_CHECK_CLOSE(1.2279166666666664e-12, wells->WI[0], 0.001);
BOOST_CHECK_CLOSE(1.2279166666666664e-12, wells->WI[1], 0.001);
/* Completed cells */
BOOST_CHECK_EQUAL(0, wells->well_cells[0]);
BOOST_CHECK_EQUAL(9 + 2 * 10 + 2 * 10 * 10, wells->well_cells[1]);
}
/*
The number of controls is determined by looking at which elements
have been given explicit - non-default - values in the WCONxxxx
keyword. Is that at all interesting?
*/
void check_controls_epoch0(struct WellControls ** ctrls) {
// The injector
{
const struct WellControls * ctrls0 = ctrls[0];
BOOST_CHECK_EQUAL(3, well_controls_get_num(ctrls0)); // The number of controls for the injector == 3??
BOOST_CHECK_EQUAL(SURFACE_RATE, well_controls_iget_type(ctrls0, 0));
BOOST_CHECK_EQUAL(RESERVOIR_RATE, well_controls_iget_type(ctrls0, 1));
BOOST_CHECK_EQUAL(BHP, well_controls_iget_type(ctrls0, 2));
// The different targets
BOOST_CHECK_EQUAL(100.0 / 86400, well_controls_iget_target(ctrls0, 0));
BOOST_CHECK_EQUAL(200.0 / 86400, well_controls_iget_target(ctrls0, 1));
BOOST_CHECK_EQUAL(400 * 100000, well_controls_iget_target(ctrls0, 2));
// Which control is active
BOOST_CHECK_EQUAL(0, well_controls_get_current(ctrls0));
// The phase distribution in the active target
{
const double * distr = well_controls_iget_distr(ctrls0, 0);
BOOST_CHECK_EQUAL(0, distr[0]); // Water
BOOST_CHECK_EQUAL(0, distr[1]); // Oil
BOOST_CHECK_EQUAL(1, distr[2]); // Gas
}
}
// The producer
{
const struct WellControls * ctrls1 = ctrls[1];
BOOST_CHECK_EQUAL(2, well_controls_get_num(ctrls1)); // The number of controls for the producer == 2??
BOOST_CHECK_EQUAL(SURFACE_RATE, well_controls_iget_type(ctrls1, 0));
BOOST_CHECK_EQUAL(BHP, well_controls_iget_type(ctrls1, 1));
// The different targets
BOOST_CHECK_EQUAL(-20000.0 / 86400, well_controls_iget_target(ctrls1, 0));
BOOST_CHECK_EQUAL(1000 * 100000, well_controls_iget_target(ctrls1, 1));
// Which control is active
BOOST_CHECK_EQUAL(0, well_controls_get_current(ctrls1));
// The phase distribution in the active target
{
const double * distr = well_controls_iget_distr(ctrls1, 0);
BOOST_CHECK_EQUAL(0, distr[0]); // Water
BOOST_CHECK_EQUAL(1, distr[1]); // Oil
BOOST_CHECK_EQUAL(0, distr[2]); // Gas
}
}
}
void check_controls_epoch1(struct WellControls ** ctrls) {
// The injector
{
const struct WellControls * ctrls0 = ctrls[0];
BOOST_CHECK_EQUAL(3, well_controls_get_num(ctrls0)); // The number of controls for the injector == 3??
BOOST_CHECK_EQUAL(SURFACE_RATE, well_controls_iget_type(ctrls0, 0));
BOOST_CHECK_EQUAL(RESERVOIR_RATE, well_controls_iget_type(ctrls0, 1));
BOOST_CHECK_EQUAL(BHP, well_controls_iget_type(ctrls0, 2));
// The different targets
BOOST_CHECK_CLOSE(10.0 / 86400, well_controls_iget_target(ctrls0, 0), 0.001);
BOOST_CHECK_CLOSE(20.0 / 86400, well_controls_iget_target(ctrls0, 1), 0.001);
BOOST_CHECK_CLOSE(40 * 100000, well_controls_iget_target(ctrls0, 2), 0.001);
// Which control is active
BOOST_CHECK_EQUAL(1, well_controls_get_current(ctrls0));
{
const double * distr = well_controls_iget_distr(ctrls0, 1);
BOOST_CHECK_EQUAL(1, distr[0]); // Water
BOOST_CHECK_EQUAL(0, distr[1]); // Oil
BOOST_CHECK_EQUAL(0, distr[2]); // Gas
}
}
// The producer
{
const struct WellControls * ctrls1 = ctrls[1];
BOOST_CHECK_EQUAL(3, well_controls_get_num(ctrls1)); // The number of controls for the producer - now 3.
BOOST_CHECK_EQUAL(SURFACE_RATE, well_controls_iget_type(ctrls1, 0));
BOOST_CHECK_EQUAL(RESERVOIR_RATE, well_controls_iget_type(ctrls1, 1));
BOOST_CHECK_EQUAL(BHP, well_controls_iget_type(ctrls1, 2));
// The different targets
BOOST_CHECK_CLOSE(-999.0 / 86400, well_controls_iget_target(ctrls1, 0), 0.001);
BOOST_CHECK_CLOSE(-123.0 / 86400, well_controls_iget_target(ctrls1, 1), 0.001);
BOOST_CHECK_CLOSE(100 * 100000, well_controls_iget_target(ctrls1, 2), 0.001);
// Which control is active
BOOST_CHECK_EQUAL(1, well_controls_get_current(ctrls1));
{
const double * distr = well_controls_iget_distr(ctrls1, 1);
BOOST_CHECK_EQUAL(1, distr[0]); // Water
BOOST_CHECK_EQUAL(1, distr[1]); // Oil
BOOST_CHECK_EQUAL(1, distr[2]); // Gas
}
}
}
void check_controls_epoch3(struct WellControls ** ctrls) {
// The new producer
const struct WellControls * ctrls1 = ctrls[1];
// Note: controls include default (1 atm) BHP control.
BOOST_CHECK_EQUAL(6, well_controls_get_num(ctrls1));
}
BOOST_AUTO_TEST_CASE(New_Constructor_Works) {
const std::string filename = "wells_manager_data.data";
Opm::Parser parser;
Opm::ParseContext parseContext;
Opm::Deck deck = parser.parseFile(filename, parseContext);
Opm::EclipseState eclipseState(deck, parseContext);
Opm::GridManager gridManager(eclipseState.getInputGrid());
{
Opm::WellsManager wellsManager(eclipseState, 0, *gridManager.c_grid());
wells_static_check(wellsManager.c_wells());
check_controls_epoch0(wellsManager.c_wells()->ctrls);
}
{
Opm::WellsManager wellsManager(eclipseState, 1, *gridManager.c_grid());
wells_static_check(wellsManager.c_wells());
check_controls_epoch1(wellsManager.c_wells()->ctrls);
}
{
Opm::WellsManager wellsManager(eclipseState, 3, *gridManager.c_grid());
const Wells* wells = wellsManager.c_wells();
// There is 3 wells in total in the deck at the 3rd schedule step.
// PROD1 is shut and should therefore not be counted.
// The new well is therefore the secound well.
BOOST_CHECK_EQUAL(2, wells->number_of_wells);
BOOST_CHECK_EQUAL(wells->name[0], "INJ1");
BOOST_CHECK_EQUAL(wells->name[1], "NEW");
check_controls_epoch3(wellsManager.c_wells()->ctrls);
}
}
BOOST_AUTO_TEST_CASE(WellsEqual) {
const std::string filename = "wells_manager_data.data";
Opm::ParseContext parseContext;
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename, parseContext));
Opm::EclipseState eclipseState(deck, parseContext);
Opm::GridManager gridManager(eclipseState.getInputGrid());
Opm::WellsManager wellsManager0(eclipseState, 0, *gridManager.c_grid());
Opm::WellsManager wellsManager1(eclipseState, 1, *gridManager.c_grid());
BOOST_CHECK(wells_equal( wellsManager0.c_wells() , wellsManager0.c_wells(),false));
BOOST_CHECK(!wells_equal( wellsManager0.c_wells() , wellsManager1.c_wells(),false));
}
BOOST_AUTO_TEST_CASE(ControlsEqual) {
const std::string filename = "wells_manager_data.data";
Opm::ParseContext parseContext;
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename, parseContext));
Opm::EclipseState eclipseState(deck, parseContext);
Opm::GridManager gridManager(eclipseState.getInputGrid());
Opm::WellsManager wellsManager0(eclipseState, 0, *gridManager.c_grid());
Opm::WellsManager wellsManager1(eclipseState, 1, *gridManager.c_grid());
BOOST_CHECK(well_controls_equal( wellsManager0.c_wells()->ctrls[0] , wellsManager0.c_wells()->ctrls[0] , false));
BOOST_CHECK(well_controls_equal( wellsManager0.c_wells()->ctrls[1] , wellsManager0.c_wells()->ctrls[1] , false));
BOOST_CHECK(well_controls_equal( wellsManager1.c_wells()->ctrls[0] , wellsManager1.c_wells()->ctrls[0] , false));
BOOST_CHECK(well_controls_equal( wellsManager1.c_wells()->ctrls[1] , wellsManager1.c_wells()->ctrls[1] , false));
BOOST_CHECK(!well_controls_equal( wellsManager0.c_wells()->ctrls[0] , wellsManager0.c_wells()->ctrls[1] , false));
BOOST_CHECK(!well_controls_equal( wellsManager0.c_wells()->ctrls[1] , wellsManager0.c_wells()->ctrls[0] , false));
BOOST_CHECK(!well_controls_equal( wellsManager1.c_wells()->ctrls[0] , wellsManager0.c_wells()->ctrls[0] , false));
BOOST_CHECK(!well_controls_equal( wellsManager1.c_wells()->ctrls[1] , wellsManager0.c_wells()->ctrls[1] , false));
}
BOOST_AUTO_TEST_CASE(WellShutOK) {
const std::string filename = "wells_manager_data.data";
Opm::ParseContext parseContext;
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename, parseContext));
Opm::EclipseState eclipseState(deck, parseContext);
Opm::GridManager gridManager(eclipseState.getInputGrid());
Opm::WellsManager wellsManager2(eclipseState, 2, *gridManager.c_grid());
// Shut wells are not added to the deck. i.e number of wells should be 2-1
BOOST_CHECK(wellsManager2.c_wells()->number_of_wells == 1);
//BOOST_CHECK_NO_THROW( Opm::WellsManager wellsManager2(eclipseState , 2 , *gridManager.c_grid(), NULL));
}
BOOST_AUTO_TEST_CASE(WellSTOPOK) {
const std::string filename = "wells_manager_data_wellSTOP.data";
Opm::ParseContext parseContext;
Opm::Parser parser;
Opm::Deck deck(parser.parseFile(filename, parseContext));
Opm::EclipseState eclipseState(deck, parseContext);
Opm::GridManager gridManager(eclipseState.getInputGrid());
Opm::WellsManager wellsManager(eclipseState, 0, *gridManager.c_grid());
const Wells* wells = wellsManager.c_wells();
const struct WellControls* ctrls0 = wells->ctrls[0];
const struct WellControls* ctrls1 = wells->ctrls[1];
BOOST_CHECK(well_controls_well_is_stopped(ctrls0)); // The first well is closed
BOOST_CHECK(well_controls_well_is_open(ctrls1)); // The second well is open
}