diff --git a/README b/README
index f0314100..ae7ebe30 100644
--- a/README
+++ b/README
@@ -88,10 +88,25 @@ If you want to contribute, fork OPM/opm-core on github.
BUILDING
--------
+There are two ways to build the opm-core library:
+
+1. As a stand-alone library.
cd opm-core
autoreconf -i
./configure
make
+If you want to install the library:
+ make install
+or (if installing to /usr/local or similar)
+ sudo make install
+
+2. As a dune module.
+ - Put the opm-core directory in the same directory
+ as the other dune modules to be built (e.g. dune-commmon,
+ dune-grid).
+ - Run dunecontrol as normal. For more information on
+ the dune build system, see
+ http://www.dune-project.org/doc/installation-notes.html
DOCUMENTATION
diff --git a/opm/core/newwells.c b/opm/core/newwells.c
index 68037201..c28e8566 100644
--- a/opm/core/newwells.c
+++ b/opm/core/newwells.c
@@ -468,6 +468,8 @@ add_well(enum WellType type ,
struct WellMgmt *m;
+ assert (W != NULL);
+
nw = W->number_of_wells;
nperf_tot = W->well_connpos[nw];
@@ -532,6 +534,7 @@ append_well_controls(enum WellControlType type,
struct WellControlMgmt *m;
assert (W != NULL);
+ assert ((0 <= well_index) && (well_index < W->number_of_wells));
ctrl = W->ctrls[well_index];
np = W->number_of_phases;
@@ -567,8 +570,13 @@ void
set_current_control(int well_index, int current_control, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
+ assert (W != NULL);
+ assert ((0 <= well_index) && (well_index < W->number_of_wells));
+
assert (W->ctrls[well_index] != NULL);
+ assert (current_control < W->ctrls[well_index]->num);
+
W->ctrls[well_index]->current = current_control;
}
@@ -578,7 +586,85 @@ void
clear_well_controls(int well_index, struct Wells *W)
/* ---------------------------------------------------------------------- */
{
+ assert (W != NULL);
+ assert ((0 <= well_index) && (well_index < W->number_of_wells));
+
if (W->ctrls[well_index] != NULL) {
W->ctrls[well_index]->num = 0;
}
}
+
+
+/* ---------------------------------------------------------------------- */
+struct Wells *
+clone_wells(const struct Wells *W)
+/* ---------------------------------------------------------------------- */
+{
+ int c, np, nperf, ok, pos, w;
+ double target;
+ const int *cells;
+ const double *WI, *comp_frac, *distr;
+ enum WellControlType type;
+ const struct WellControls *ctrls;
+
+ struct Wells *ret;
+
+ if (W == NULL) {
+ ret = NULL;
+ }
+ else {
+ np = W->number_of_phases;
+ ret = create_wells(W->number_of_phases, W->number_of_wells,
+ W->well_connpos[ W->number_of_wells ]);
+
+ if (ret != NULL) {
+ pos = W->well_connpos[ 0 ];
+ ok = 1;
+
+ for (w = 0; ok && (w < W->number_of_wells); w++) {
+ nperf = W->well_connpos[w + 1] - pos;
+ cells = W->well_cells + pos;
+
+ WI = W->WI != NULL ? W->WI + pos : NULL;
+ comp_frac = W->comp_frac != NULL ? W->comp_frac + w*np : NULL;
+
+ ok = add_well(W->type[ w ], W->depth_ref[ w ], nperf,
+ comp_frac, cells, WI, W->name[ w ], ret);
+
+ /* Capacity should be sufficient from create_wells() */
+ assert (ok);
+
+ ctrls = W->ctrls[ w ];
+
+ if (ok) {
+ ok = well_controls_reserve(ctrls->num, np, ret->ctrls[ w ]);
+
+ for (c = 0; ok && (c < ctrls->num); c++) {
+ type = ctrls->type [ c ];
+ target = ctrls->target[ c ];
+ distr = & ctrls->distr [ c * np ];
+
+ ok = append_well_controls(type, target, distr, w, ret);
+
+ /* Capacity *should* be sufficient from
+ * well_controls_reserve() */
+ assert (ok);
+ }
+ }
+
+ if (ok) {
+ set_current_control(w, ctrls->current, ret);
+ }
+
+ pos = W->well_connpos[w + 1];
+ }
+
+ if (! ok) {
+ destroy_wells(ret);
+ ret = NULL;
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/opm/core/newwells.h b/opm/core/newwells.h
index f16675b6..20cfce61 100644
--- a/opm/core/newwells.h
+++ b/opm/core/newwells.h
@@ -235,6 +235,19 @@ void
destroy_wells(struct Wells *W);
+/**
+ * Create a deep-copy (i.e., clone) of an existing Wells object, including its
+ * controls.
+ *
+ * @param[in] W Existing Wells object.
+ * @return Complete clone of the input object. Dispose of resources using
+ * function destroy_wells() when no longer needed. Returns @c NULL in case of
+ * allocation failure.
+ */
+struct Wells *
+clone_wells(const struct Wells *W);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/opm/core/simulator/SimulatorCompressibleTwophase.cpp b/opm/core/simulator/SimulatorCompressibleTwophase.cpp
index 6fb475e9..e921db87 100644
--- a/opm/core/simulator/SimulatorCompressibleTwophase.cpp
+++ b/opm/core/simulator/SimulatorCompressibleTwophase.cpp
@@ -407,8 +407,8 @@ namespace Opm
// Optionally, check if well controls are satisfied.
if (check_well_controls_) {
Opm::computePhaseFlowRatesPerWell(*wells_,
- fractional_flows,
well_state.perfRates(),
+ fractional_flows,
well_resflows_phase);
std::cout << "Checking well conditions." << std::endl;
// For testing we set surface := reservoir
diff --git a/opm/core/wells/WellsGroup.cpp b/opm/core/wells/WellsGroup.cpp
index afa17f12..c340c1ae 100644
--- a/opm/core/wells/WellsGroup.cpp
+++ b/opm/core/wells/WellsGroup.cpp
@@ -863,7 +863,7 @@ namespace Opm
return;
}
// We're a producer, so we need to negate the input
- double ntarget = target;
+ double ntarget = -target;
double distr[3] = { 0.0, 0.0, 0.0 };
const int* phase_pos = phaseUsage().phase_pos;
diff --git a/opm/core/wells/WellsManager.cpp b/opm/core/wells/WellsManager.cpp
index 95cb0369..8aaca9e2 100644
--- a/opm/core/wells/WellsManager.cpp
+++ b/opm/core/wells/WellsManager.cpp
@@ -226,6 +226,14 @@ namespace Opm
+ /// Construct from existing wells object.
+ WellsManager::WellsManager(struct Wells* W)
+ : w_(clone_wells(W))
+ {
+ }
+
+
+
/// Construct wells from deck.
WellsManager::WellsManager(const Opm::EclipseGridParser& deck,
const UnstructuredGrid& grid,
diff --git a/opm/core/wells/WellsManager.hpp b/opm/core/wells/WellsManager.hpp
index 6df65ec4..19289c5d 100644
--- a/opm/core/wells/WellsManager.hpp
+++ b/opm/core/wells/WellsManager.hpp
@@ -41,7 +41,14 @@ namespace Opm
{
public:
/// Default constructor -- no wells.
- WellsManager();
+ WellsManager();
+
+ /// Construct from existing wells object.
+ /// WellsManager is not properly initialised in the sense that the logic to
+ /// manage control switching does not exist.
+ ///
+ /// @param[in] W Existing wells object.
+ WellsManager(struct Wells* W);
/// Construct from input deck and grid.
/// The permeability argument may be zero if the input contain
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cb5935bb..6e69ae5c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -23,6 +23,7 @@ test_read_grid \
test_read_vag \
test_readpolymer \
test_sf2p \
+test_wells \
test_writeVtkData \
unit_test
@@ -59,6 +60,9 @@ test_sf2p_SOURCES = test_sf2p.cpp
test_writeVtkData_SOURCES = test_writeVtkData.cpp
+test_wells_SOURCES = test_wells.cpp
+test_wells_LDADD = $(LDADD) $(BOOST_UNIT_TEST_FRAMEWORK_LIB)
+
unit_test_SOURCES = unit_test.cpp
diff --git a/tests/test_wells.cpp b/tests/test_wells.cpp
new file mode 100644
index 00000000..4f8ad7bb
--- /dev/null
+++ b/tests/test_wells.cpp
@@ -0,0 +1,205 @@
+/*
+ Copyright 2012 SINTEF ICT, Applied Mathematics.
+
+ This file is part of the Open Porous Media project (OPM).
+
+ OPM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OPM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OPM. If not, see .
+*/
+
+#include
+
+#if HAVE_DYNAMIC_BOOST_TEST
+#define BOOST_TEST_DYN_LINK
+#endif
+
+#define NVERBOSE // Suppress own messages when throw()ing
+
+#define BOOST_TEST_MODULE WellsModuleTest
+#include
+
+#include
+
+#include
+#include
+#include
+
+BOOST_AUTO_TEST_CASE(Construction)
+{
+ const int nphases = 2;
+ const int nwells = 2;
+ const int nperfs = 2;
+
+ boost::shared_ptr W(create_wells(nphases, nwells, nperfs),
+ destroy_wells);
+
+ if (W) {
+ int cells[] = { 0, 9 };
+ double WI = 1.0;
+ const double ifrac[] = { 1.0, 0.0 };
+
+ const bool ok0 = add_well(INJECTOR, 0.0, 1, &ifrac[0], &cells[0],
+ &WI, "INJECTOR", W.get());
+
+ const double pfrac[] = { 0.0, 0.0 };
+ const bool ok1 = add_well(PRODUCER, 0.0, 1, &pfrac[0], &cells[1],
+ &WI, "PRODUCER", W.get());
+
+ if (ok0 && ok1) {
+ BOOST_CHECK_EQUAL(W->number_of_phases, nphases);
+ BOOST_CHECK_EQUAL(W->number_of_wells , nwells );
+
+ BOOST_CHECK_EQUAL(W->well_connpos[0], 0);
+ BOOST_CHECK_EQUAL(W->well_connpos[1], 1);
+ BOOST_CHECK_EQUAL(W->well_connpos[W->number_of_wells], nperfs);
+
+ BOOST_CHECK_EQUAL(W->well_cells[W->well_connpos[0]], cells[0]);
+ BOOST_CHECK_EQUAL(W->well_cells[W->well_connpos[1]], cells[1]);
+
+ BOOST_CHECK_EQUAL(W->WI[W->well_connpos[0]], WI);
+ BOOST_CHECK_EQUAL(W->WI[W->well_connpos[1]], WI);
+
+ using std::string;
+ BOOST_CHECK_EQUAL(string(W->name[0]), string("INJECTOR"));
+ BOOST_CHECK_EQUAL(string(W->name[1]), string("PRODUCER"));
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE(Controls)
+{
+ const int nphases = 2;
+ const int nwells = 1;
+ const int nperfs = 2;
+
+ boost::shared_ptr W(create_wells(nphases, nwells, nperfs),
+ destroy_wells);
+
+ if (W) {
+ int cells[] = { 0 , 9 };
+ double WI [] = { 1.0, 1.0 };
+ const double ifrac[] = { 1.0, 0.0 };
+
+ const bool ok = add_well(INJECTOR, 0.0, nperfs, &ifrac[0], &cells[0],
+ &WI[0], "INJECTOR", W.get());
+
+ if (ok) {
+ const double distr[] = { 1.0, 0.0 };
+ const bool ok1 = append_well_controls(BHP, 1, &distr[0],
+ 0, W.get());
+ const bool ok2 = append_well_controls(SURFACE_RATE, 1,
+ &distr[0], 0, W.get());
+
+ if (ok1 && ok2) {
+ WellControls* ctrls = W->ctrls[0];
+
+ BOOST_CHECK_EQUAL(ctrls->num , 2);
+ BOOST_CHECK_EQUAL(ctrls->current, -1);
+
+ set_current_control(0, 0, W.get());
+ BOOST_CHECK_EQUAL(ctrls->current, 0);
+
+ set_current_control(0, 1, W.get());
+ BOOST_CHECK_EQUAL(ctrls->current, 1);
+
+ BOOST_CHECK_EQUAL(ctrls->type[0], BHP);
+ BOOST_CHECK_EQUAL(ctrls->type[1], SURFACE_RATE);
+
+ BOOST_CHECK_EQUAL(ctrls->target[0], 1.0);
+ BOOST_CHECK_EQUAL(ctrls->target[1], 1.0);
+ }
+ }
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE(Copy)
+{
+ const int nphases = 2;
+ const int nwells = 2;
+ const int nperfs = 2;
+
+ boost::shared_ptr W1(create_wells(nphases, nwells, nperfs),
+ destroy_wells);
+ boost::shared_ptr W2;
+
+ if (W1) {
+ int cells[] = { 0, 9 };
+ const double WI = 1.0;
+ const double ifrac[] = { 1.0, 0.0 };
+
+ const bool ok0 = add_well(INJECTOR, 0.0, 1, &ifrac[0], &cells[0],
+ &WI, "INJECTOR", W1.get());
+
+ const double pfrac[] = { 0.0, 0.0 };
+ const bool ok1 = add_well(PRODUCER, 0.0, 1, &pfrac[0], &cells[1],
+ &WI, "PRODUCER", W1.get());
+
+ bool ok = ok0 && ok1;
+ for (int w = 0; ok && (w < W1->number_of_wells); ++w) {
+ const double distr[] = { 1.0, 0.0 };
+ const bool okc1 = append_well_controls(BHP, 1, &distr[0],
+ w, W1.get());
+ const bool okc2 = append_well_controls(SURFACE_RATE, 1,
+ &distr[0], w,
+ W1.get());
+
+ ok = okc1 && okc2;
+ }
+
+ if (ok) {
+ W2.reset(clone_wells(W1.get()), destroy_wells);
+ }
+ }
+
+ if (W2) {
+ BOOST_CHECK_EQUAL(W2->number_of_phases, W1->number_of_phases);
+ BOOST_CHECK_EQUAL(W2->number_of_wells , W1->number_of_wells );
+ BOOST_CHECK_EQUAL(W2->well_connpos[0] , W1->well_connpos[0] );
+
+ for (int w = 0; w < W1->number_of_wells; ++w) {
+ using std::string;
+ BOOST_CHECK_EQUAL(string(W2->name[w]), string(W1->name[w]));
+ BOOST_CHECK_EQUAL( W2->type[w] , W1->type[w] );
+
+ BOOST_CHECK_EQUAL(W2->well_connpos[w + 1],
+ W1->well_connpos[w + 1]);
+
+ for (int j = W1->well_connpos[w];
+ j < W1->well_connpos[w + 1]; ++j) {
+ BOOST_CHECK_EQUAL(W2->well_cells[j], W1->well_cells[j]);
+ BOOST_CHECK_EQUAL(W2->WI [j], W1->WI [j]);
+ }
+
+ BOOST_CHECK(W1->ctrls[w] != 0);
+ BOOST_CHECK(W2->ctrls[w] != 0);
+
+ WellControls* c1 = W1->ctrls[w];
+ WellControls* c2 = W2->ctrls[w];
+
+ BOOST_CHECK_EQUAL(c2->num , c1->num );
+ BOOST_CHECK_EQUAL(c2->current, c1->current);
+
+ for (int c = 0; c < c1->num; ++c) {
+ BOOST_CHECK_EQUAL(c2->type [c], c1->type [c]);
+ BOOST_CHECK_EQUAL(c2->target[c], c1->target[c]);
+
+ for (int p = 0; p < W1->number_of_phases; ++p) {
+ BOOST_CHECK_EQUAL(c2->distr[c*W1->number_of_phases + p],
+ c1->distr[c*W1->number_of_phases + p]);
+ }
+ }
+ }
+ }
+}