From 251c09a288193aadf6e53d501e9c5db5b43e0bd7 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 30 Mar 2020 00:35:42 +0200 Subject: [PATCH] adding the several pressure drop values to WellState for MSW segpress_ and segrates_ are renamed to help the name style. --- opm/simulators/wells/MultisegmentWell.hpp | 8 +- .../wells/MultisegmentWell_impl.hpp | 39 ++++-- .../wells/WellStateFullyImplicitBlackoil.hpp | 112 ++++++++++++++---- 3 files changed, 119 insertions(+), 40 deletions(-) diff --git a/opm/simulators/wells/MultisegmentWell.hpp b/opm/simulators/wells/MultisegmentWell.hpp index ce90dd99c..8644ae505 100644 --- a/opm/simulators/wells/MultisegmentWell.hpp +++ b/opm/simulators/wells/MultisegmentWell.hpp @@ -380,7 +380,7 @@ namespace Opm const Well::ProductionControls& prod_controls, Opm::DeferredLogger& deferred_logger); - void assemblePressureEq(const int seg) const; + void assemblePressureEq(const int seg, WellState& well_state) const; // hytrostatic pressure loss EvalWell getHydroPressureLoss(const int seg) const; @@ -388,7 +388,7 @@ namespace Opm // frictinal pressure loss EvalWell getFrictionPressureLoss(const int seg) const; - void handleAccelerationPressureLoss(const int seg) const; + void handleAccelerationPressureLoss(const int seg, WellState& well_state) const; // handling the overshooting and undershooting of the fractions void processFractions(const int seg) const; @@ -470,7 +470,7 @@ namespace Opm double maxPerfPress(const Simulator& ebos_simulator) const; - void assembleSICDPressureEq(const int seg) const; + void assembleSICDPressureEq(const int seg, WellState& well_state) const; // TODO: when more ICD devices join, we should have a better interface to do this void calculateSICDFlowScalingFactors(); @@ -478,7 +478,7 @@ namespace Opm EvalWell pressureDropSpiralICD(const int seg) const; // assemble the pressure equation for sub-critical valve (WSEGVALV) - void assembleValvePressureEq(const int seg) const; + void assembleValvePressureEq(const int seg, WellState& well_state) const; EvalWell pressureDropValve(const int seg) const; }; diff --git a/opm/simulators/wells/MultisegmentWell_impl.hpp b/opm/simulators/wells/MultisegmentWell_impl.hpp index af280c2a1..8a33f2a0c 100644 --- a/opm/simulators/wells/MultisegmentWell_impl.hpp +++ b/opm/simulators/wells/MultisegmentWell_impl.hpp @@ -1984,7 +1984,7 @@ namespace Opm template void MultisegmentWell:: - assemblePressureEq(const int seg) const + assemblePressureEq(const int seg, WellState& well_state) const { assert(seg != 0); // not top segment @@ -1993,10 +1993,16 @@ namespace Opm // we need to handle the pressure difference between the two segments // we only consider the hydrostatic pressure loss first - pressure_equation -= getHydroPressureLoss(seg); + // TODO: we might be able to add member variables to store these values, then we update well state + // after converged + const auto hydro_pressure_drop = getHydroPressureLoss(seg); + well_state.segPressDropHydroStatic()[seg] = hydro_pressure_drop.value(); + pressure_equation -= hydro_pressure_drop; if (frictionalPressureLossConsidered()) { - pressure_equation -= getFrictionPressureLoss(seg); + const auto friction_pressure_drop = getFrictionPressureLoss(seg); + pressure_equation -= friction_pressure_drop; + well_state.segPressDropFriction()[seg] = friction_pressure_drop.value(); } resWell_[seg][SPres] = pressure_equation.value(); @@ -2014,7 +2020,7 @@ namespace Opm } if (accelerationalPressureLossConsidered()) { - handleAccelerationPressureLoss(seg); + handleAccelerationPressureLoss(seg, well_state); } } @@ -2061,7 +2067,7 @@ namespace Opm template void MultisegmentWell:: - handleAccelerationPressureLoss(const int seg) const + handleAccelerationPressureLoss(const int seg, WellState& well_state) const { // TODO: this pressure loss is not significant enough to be well tested yet. // handle the out velcocity head @@ -2089,6 +2095,7 @@ namespace Opm const EvalWell inlet_density = segment_densities_[inlet]; const EvalWell inlet_mass_rate = segment_mass_rates_[inlet]; const EvalWell inlet_velocity_head = mswellhelpers::velocityHead(area, inlet_mass_rate, inlet_density); + well_state.segPressDropAcceleration()[seg] = inlet_velocity_head.value(); resWell_[seg][SPres] += inlet_velocity_head.value(); for (int pv_idx = 0; pv_idx < numWellEq; ++pv_idx) { duneD_[seg][inlet][SPres][pv_idx] += inlet_velocity_head.derivative(pv_idx + numEq); @@ -2537,15 +2544,19 @@ namespace Opm // TODO: maybe the following should go to the function assemblePressureEq() switch(segmentSet()[seg].segmentType()) { case Segment::SegmentType::SICD : - assembleSICDPressureEq(seg); + assembleSICDPressureEq(seg, well_state); break; case Segment::SegmentType::VALVE : - assembleValvePressureEq(seg); + assembleValvePressureEq(seg, well_state); break; default : - assemblePressureEq(seg); + assemblePressureEq(seg, well_state); } } + + well_state.segPressDrop()[seg] = well_state.segPressDropHydroStatic()[seg] + + well_state.segPressDropFriction()[seg] + + well_state.segPressDropAcceleration()[seg]; } } @@ -3064,7 +3075,7 @@ namespace Opm template void MultisegmentWell:: - assembleSICDPressureEq(const int seg) const + assembleSICDPressureEq(const int seg, WellState& well_state) const { // TODO: upwinding needs to be taken care of // top segment can not be a spiral ICD device @@ -3076,7 +3087,9 @@ namespace Opm EvalWell pressure_equation = getSegmentPressure(seg); - pressure_equation = pressure_equation - pressureDropSpiralICD(seg); + const auto sicd_pressure_drop = pressureDropSpiralICD(seg); + pressure_equation = pressure_equation - sicd_pressure_drop; + well_state.segPressDropFriction()[seg] = sicd_pressure_drop.value(); resWell_[seg][SPres] = pressure_equation.value(); for (int pv_idx = 0; pv_idx < numWellEq; ++pv_idx) { @@ -3100,7 +3113,7 @@ namespace Opm template void MultisegmentWell:: - assembleValvePressureEq(const int seg) const + assembleValvePressureEq(const int seg, WellState& well_state) const { // TODO: upwinding needs to be taken care of // top segment can not be a spiral ICD device @@ -3116,7 +3129,9 @@ namespace Opm // const int seg_upwind = upwinding_segments_[seg]; - pressure_equation = pressure_equation - pressureDropValve(seg); + const auto valve_pressure_drop = pressureDropValve(seg); + pressure_equation = pressure_equation - valve_pressure_drop; + well_state.segPressDropFriction()[seg] = valve_pressure_drop.value(); resWell_[seg][SPres] = pressure_equation.value(); for (int pv_idx = 0; pv_idx < numWellEq; ++pv_idx) { diff --git a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp index df60feb6b..660a837b3 100644 --- a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp +++ b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp @@ -279,8 +279,13 @@ namespace Opm top_segment_index_[w] = w; seg_number_[w] = 1; // Top segment is segment #1 } - segpress_ = bhp(); - segrates_ = wellRates(); + seg_press_ = bhp(); + seg_rates_ = wellRates(); + + seg_pressdrop_.assign(nw, 0.); + seg_pressdrop_hydorstatic_.assign(nw, 0.); + seg_pressdrop_friction_.assign(nw, 0.); + seg_pressdrop_acceleration_.assign(nw, 0.); } } @@ -584,10 +589,10 @@ namespace Opm top_segment_index_.clear(); top_segment_index_.reserve(nw); - segpress_.clear(); - segpress_.reserve(nw); - segrates_.clear(); - segrates_.reserve(nw * numPhases()); + seg_press_.clear(); + seg_press_.reserve(nw); + seg_rates_.clear(); + seg_rates_.reserve(nw * numPhases()); seg_number_.clear(); nseg_ = 0; @@ -601,10 +606,10 @@ namespace Opm if ( !well_ecl.isMultiSegment() ) { // not multi-segment well nseg_ += 1; seg_number_.push_back(1); // Assign single segment (top) as number 1. - segpress_.push_back(bhp()[w]); + seg_press_.push_back(bhp()[w]); const int np = numPhases(); for (int p = 0; p < np; ++p) { - segrates_.push_back(wellRates()[np * w + p]); + seg_rates_.push_back(wellRates()[np * w + p]); } } else { // it is a multi-segment well const WellSegments& segment_set = well_ecl.getSegments(); @@ -642,7 +647,7 @@ namespace Opm } - // for the segrates_, now it becomes a recursive solution procedure. + // for the seg_rates_, now it becomes a recursive solution procedure. { const int np = numPhases(); const int start_perf = connpos; @@ -668,7 +673,7 @@ namespace Opm perfPhaseRates().begin() + np * start_perf_next_well); // the perforation rates for this well std::vector segment_rates; calculateSegmentRates(segment_inlets, segment_perforations, perforation_rates, np, 0 /* top segment */, segment_rates); - std::copy(segment_rates.begin(), segment_rates.end(), std::back_inserter(segrates_)); + std::copy(segment_rates.begin(), segment_rates.end(), std::back_inserter(seg_rates_)); } // for the segment pressure, the segment pressure is the same with the first perforation belongs to the segment @@ -678,26 +683,32 @@ namespace Opm // improved during the solveWellEq process { // top segment is always the first one, and its pressure is the well bhp - segpress_.push_back(bhp()[w]); + seg_press_.push_back(bhp()[w]); const int top_segment = top_segment_index_[w]; const int start_perf = connpos; for (int seg = 1; seg < well_nseg; ++seg) { if ( !segment_perforations[seg].empty() ) { const int first_perf = segment_perforations[seg][0]; - segpress_.push_back(perfPress()[start_perf + first_perf]); + seg_press_.push_back(perfPress()[start_perf + first_perf]); } else { - // segpress_.push_back(bhp); // may not be a good decision + // seg_press_.push_back(bhp); // may not be a good decision // using the outlet segment pressure // it needs the ordering is correct const int outlet_seg = segment_set[seg].outletSegment(); - segpress_.push_back(segpress_[top_segment + segment_set.segmentNumberToIndex(outlet_seg)]); + seg_press_.push_back( + seg_press_[top_segment + segment_set.segmentNumberToIndex(outlet_seg)]); } } } } connpos += num_perf_this_well; } - assert(int(segpress_.size()) == nseg_); - assert(int(segrates_.size()) == nseg_ * numPhases() ); + assert(int(seg_press_.size()) == nseg_); + assert(int(seg_rates_.size()) == nseg_ * numPhases() ); + + seg_pressdrop_.assign(nseg_, 0.); + seg_pressdrop_hydorstatic_.assign(nseg_, 0.); + seg_pressdrop_friction_.assign(nseg_, 0.); + seg_pressdrop_acceleration_.assign(nseg_, 0.); if (prev_well_state && !prev_well_state->wellMap().empty()) { // copying MS well related @@ -723,11 +734,11 @@ namespace Opm } for (int i = 0; i < number_of_segment * np; ++i) { - segrates_[new_top_segmnet_index * np + i] = prev_well_state->segRates()[old_top_segment_index * np + i]; + seg_rates_[new_top_segmnet_index * np + i] = prev_well_state->segRates()[old_top_segment_index * np + i]; } for (int i = 0; i < number_of_segment; ++i) { - segpress_[new_top_segmnet_index + i] = prev_well_state->segPress()[old_top_segment_index + i]; + seg_press_[new_top_segmnet_index + i] = prev_well_state->segPress()[old_top_segment_index + i]; } } } @@ -810,22 +821,62 @@ namespace Opm const std::vector& segRates() const { - return segrates_; + return seg_rates_; } std::vector& segRates() { - return segrates_; + return seg_rates_; } const std::vector& segPress() const { - return segpress_; + return seg_press_; + } + + std::vector& segPressDrop() + { + return seg_pressdrop_; + } + + const std::vector& segPressDrop() const + { + return seg_pressdrop_; + } + + std::vector& segPressDropFriction() + { + return seg_pressdrop_friction_; + } + + const std::vector& segPressDropFriction() const + { + return seg_pressdrop_friction_; + } + + std::vector& segPressDropHydroStatic() + { + return seg_pressdrop_hydorstatic_; + } + + const std::vector& segPressDropHydroStatic() const + { + return seg_pressdrop_hydorstatic_; + } + + std::vector& segPressDropAcceleration() + { + return seg_pressdrop_acceleration_; + } + + const std::vector& segPressDropAcceleration() const + { + return seg_pressdrop_acceleration_; } std::vector& segPress() { - return segpress_; + return seg_press_; } int numSegment() const @@ -1026,8 +1077,17 @@ namespace Opm // MS well related // for StandardWell, the number of segments will be one - std::vector segrates_; - std::vector segpress_; + std::vector seg_rates_; + std::vector seg_press_; + // The following data are only recorded for output + // pressure drop + std::vector seg_pressdrop_; + // frictional pressure drop + std::vector seg_pressdrop_friction_; + // hydrostatic pressure drop + std::vector seg_pressdrop_hydorstatic_; + // accelerational pressure drop + std::vector seg_pressdrop_acceleration_; // the index of the top segments, which is used to locate the // multisegment well related information in WellState std::vector top_segment_index_; @@ -1063,6 +1123,10 @@ namespace Opm &this->segRates()[seg_dof * this->numPhases()]; seg_res.pressure = this->segPress()[seg_dof]; + seg_res.pressure_drop = this->segPressDrop()[seg_dof]; + seg_res.pressure_drop_hydrostatic = this->segPressDropHydroStatic()[seg_dof]; + seg_res.pressure_drop_friction = this->segPressDropFriction()[seg_dof]; + seg_res.pressure_drop_acceleration = this->segPressDropAcceleration()[seg_dof]; if (pu.phase_used[Water]) { seg_res.rates.set(data::Rates::opt::wat,