From 55e452c605c0f4218f501d120d6f1915f940c0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 15 Oct 2018 19:52:54 +0200 Subject: [PATCH] Well State FIBO: Report() Segment Results by Seg-Numbers This commit adds a new data member, seg_number_, that maps a linear segment index (0 .. #segments - 1) to the appropriate segment number (segment ID). This ensures that member function report() is able to produce segment results in terms of user-assigned segment numbers rather than linear indices internal to the simulator and its state variables. This, in turn, decouples the well state object from the output (summary/restart) code and makes the restart facility more self contained. Rewrite the unit test for WellStateFullyImplicitBlackoil to account for the new indexing scheme when assigning the synthetic segment results. While here, also abide by the file's naming convention for data members and locals. --- .../WellStateFullyImplicitBlackoil.hpp | 74 +++++++++++++------ tests/test_wellstatefullyimplicitblackoil.cpp | 50 ++++++++----- 2 files changed, 82 insertions(+), 42 deletions(-) diff --git a/opm/autodiff/WellStateFullyImplicitBlackoil.hpp b/opm/autodiff/WellStateFullyImplicitBlackoil.hpp index c2aa6e828..353ff201b 100644 --- a/opm/autodiff/WellStateFullyImplicitBlackoil.hpp +++ b/opm/autodiff/WellStateFullyImplicitBlackoil.hpp @@ -281,9 +281,12 @@ namespace Opm // we need to create a trival segment related values to avoid there will be some // multi-segment wells added later. nseg_ = nw; + seg_number_.clear(); top_segment_index_.reserve(nw); + seg_number_.reserve(nw); for (int w = 0; w < nw; ++w) { top_segment_index_.push_back(w); + seg_number_.push_back(1); // Top segment is segment #1 } segpress_ = bhp(); segrates_ = wellRates(); @@ -581,10 +584,11 @@ namespace Opm } assert(local_comp_index == this->wells_->well_connpos[ w + 1 ] - this->wells_->well_connpos[ w ]); - const auto nSeg = this->numSegments(w); - for (auto segID = 0*nSeg; segID < nSeg; ++segID) { - well.segments[segID + 1] = - this->reportSegmentResults(pu, w, segID); + const auto nseg = this->numSegments(w); + for (auto seg_ix = 0*nseg; seg_ix < nseg; ++seg_ix) { + const auto seg_no = this->segmentNumber(w, seg_ix); + well.segments[seg_no] = + this->reportSegmentResults(pu, w, seg_ix, seg_no); } } @@ -609,6 +613,7 @@ namespace Opm segpress_.reserve(nw); segrates_.clear(); segrates_.reserve(nw * numPhases()); + seg_number_.clear(); nseg_ = 0; // in the init function, the well rates and perforation rates have been initialized or copied from prevState @@ -632,6 +637,7 @@ namespace Opm top_segment_index_.push_back(nseg_); if ( !well_ecl->isMultiSegment(time_step) ) { // not multi-segment well nseg_ += 1; + seg_number_.push_back(1); // Assign single segment (top) as number 1. segpress_.push_back(bhp()[w]); const int np = numPhases(); for (int p = 0; p < np; ++p) { @@ -645,6 +651,9 @@ namespace Opm const int well_nseg = segment_set.size(); const int nperf = completion_set.size(); nseg_ += well_nseg; + for (auto segID = 0*well_nseg; segID < well_nseg; ++segID) { + this->seg_number_.push_back(segment_set[segID].segmentNumber()); + } // we need to know for each segment, how many perforation it has and how many segments using it as outlet_segment // that is why I think we should use a well model to initialize the WellState here std::vector> segment_perforations(well_nseg); @@ -942,48 +951,65 @@ namespace Opm // Well potentials std::vector well_potentials_; + /// Map segment index to segment number, mostly for MS wells. + /// + /// Segment number (one-based) of j-th segment in i-th well is + /// \code + /// const auto top = topSegmentIndex(i); + /// const auto seg_No = seg_number_[top + j]; + /// \end + std::vector seg_number_; + ::Opm::data::Segment reportSegmentResults(const PhaseUsage& pu, - const int wellID, - const int segmentID) const + const int well_id, + const int seg_ix, + const int seg_no) const { - auto segRes = ::Opm::data::Segment{}; + auto seg_res = ::Opm::data::Segment{}; - const auto segDoF = - this->topSegmentIndex(wellID) + segmentID; + const auto seg_dof = + this->topSegmentIndex(well_id) + seg_ix; const auto* rate = - &this->segRates()[segDoF * this->numPhases()]; + &this->segRates()[seg_dof * this->numPhases()]; - segRes.pressure = this->segPress()[segDoF]; + seg_res.pressure = this->segPress()[seg_dof]; if (pu.phase_used[Water]) { - segRes.rates.set(data::Rates::opt::wat, - rate[pu.phase_pos[Water]]); + seg_res.rates.set(data::Rates::opt::wat, + rate[pu.phase_pos[Water]]); } if (pu.phase_used[Oil]) { - segRes.rates.set(data::Rates::opt::oil, - rate[pu.phase_pos[Oil]]); + seg_res.rates.set(data::Rates::opt::oil, + rate[pu.phase_pos[Oil]]); } if (pu.phase_used[Gas]) { - segRes.rates.set(data::Rates::opt::gas, - rate[pu.phase_pos[Gas]]); + seg_res.rates.set(data::Rates::opt::gas, + rate[pu.phase_pos[Gas]]); } - segRes.segNumber = segmentID + 1; + seg_res.segNumber = seg_no; - return segRes; + return seg_res; } - int numSegments(const int wellID) const + int numSegments(const int well_id) const { - const auto topSeg = this->topSegmentIndex(wellID); + const auto topseg = this->topSegmentIndex(well_id); - return (wellID + 1 == this->numWells()) // Last well? - ? (this->numSegment() - topSeg) - : (this->topSegmentIndex(wellID + 1) - topSeg); + return (well_id + 1 == this->numWells()) // Last well? + ? (this->numSegment() - topseg) + : (this->topSegmentIndex(well_id + 1) - topseg); + } + + int segmentNumber(const int well_id, const int seg_id) const + { + const auto top_offset = this->topSegmentIndex(well_id); + + return this->seg_number_[top_offset + seg_id]; } }; diff --git a/tests/test_wellstatefullyimplicitblackoil.cpp b/tests/test_wellstatefullyimplicitblackoil.cpp index 92fd41e64..651cd1cd6 100644 --- a/tests/test_wellstatefullyimplicitblackoil.cpp +++ b/tests/test_wellstatefullyimplicitblackoil.cpp @@ -98,16 +98,21 @@ namespace { const auto topSegIx = wstate.topSegmentIndex(wellID); const auto pressTop = 100.0 * wellID; - segPress[topSegIx] = pressTop; + auto* press = &segPress[topSegIx]; + + press[0] = pressTop; if (! well->isMultiSegment(tstep)) { continue; } - const auto nSeg = well->getWellSegments(tstep).size(); + const auto& segSet = well->getWellSegments(tstep); + const auto nSeg = segSet.size(); for (auto segID = 0*nSeg + 1; segID < nSeg; ++segID) { - segPress[topSegIx + segID] = pressTop + 1.0*segID; + // One-based numbering scheme for segments. + const auto segNo = segSet[segID].segmentNumber(); + press[segNo - 1] = pressTop + 1.0*(segNo - 1); } } } @@ -136,7 +141,7 @@ namespace { for (auto wellID = 0*nWell; wellID < nWell; ++wellID) { const auto* well = wells[wellID]; const auto topSegIx = wstate.topSegmentIndex(wellID); - const auto rateTop = 1000.0 * wellID; + const auto rateTop = 1000.0 * wellID; if (wat) { segRates[np*topSegIx + iw] = rateTop; } if (oil) { segRates[np*topSegIx + io] = rateTop; } @@ -146,14 +151,18 @@ namespace { continue; } - const auto nSeg = well->getWellSegments(tstep).size(); + const auto& segSet = well->getWellSegments(tstep); + const auto nSeg = segSet.size(); for (auto segID = 0*nSeg + 1; segID < nSeg; ++segID) { - auto* rates = &segRates[(topSegIx + segID) * np]; + // One-based numbering scheme for segments. + const auto segNo = segSet[segID].segmentNumber(); - if (wat) { rates[iw] = rateTop + 100.0*segID; } - if (oil) { rates[io] = rateTop + 200.0*segID; } - if (gas) { rates[ig] = rateTop + 400.0*segID; } + auto* rates = &segRates[(topSegIx + segNo - 1) * np]; + + if (wat) { rates[iw] = rateTop + 100.0*(segNo - 1); } + if (oil) { rates[io] = rateTop + 200.0*(segNo - 1); } + if (gas) { rates[ig] = rateTop + 400.0*(segNo - 1); } } } } @@ -260,9 +269,14 @@ BOOST_AUTO_TEST_CASE(Rates) const auto& xseg = xw.segments.at(1); BOOST_CHECK_EQUAL(xseg.segNumber, 1); - BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::wat), rateTop, 1.0e-10); - BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::oil), rateTop, 1.0e-10); - BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::gas), rateTop, 1.0e-10); + BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::wat), + rateTop, 1.0e-10); + + BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::oil), + rateTop, 1.0e-10); + + BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::gas), + rateTop, 1.0e-10); } { @@ -273,19 +287,19 @@ BOOST_AUTO_TEST_CASE(Rates) const auto rateTop = prod01_first ? 0.0 : 1000.0; - for (auto segID = 0; segID < expect_nSeg; ++segID) { - const auto& xseg = xw.segments.at(segID + 1); + for (auto segNum = 1; segNum <= expect_nSeg; ++segNum) { + const auto& xseg = xw.segments.at(segNum); - BOOST_CHECK_EQUAL(xseg.segNumber, segID + 1); + BOOST_CHECK_EQUAL(xseg.segNumber, segNum); BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::wat), - rateTop + 100.0*segID, 1.0e-10); + rateTop + 100.0*(segNum - 1), 1.0e-10); BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::oil), - rateTop + 200.0*segID, 1.0e-10); + rateTop + 200.0*(segNum - 1), 1.0e-10); BOOST_CHECK_CLOSE(xseg.rates.get(Opm::data::Rates::opt::gas), - rateTop + 400.0*segID, 1.0e-10); + rateTop + 400.0*(segNum - 1), 1.0e-10); } } }