obtaining the depth for the completions based on segment information
This commit is contained in:
@@ -53,6 +53,7 @@ namespace Opm {
|
||||
Completion(const Completion&, WellCompletion::StateEnum newStatus);
|
||||
Completion(const Completion&, double wellPi);
|
||||
Completion(const Completion&, int complnum );
|
||||
Completion(const Completion& completion_initial, int segment_number, double center_depth);
|
||||
|
||||
bool sameCoordinate(const Completion& other) const;
|
||||
bool sameCoordinate(const int i, const int j, const int k) const;
|
||||
@@ -72,7 +73,6 @@ namespace Opm {
|
||||
void shift_complnum( int );
|
||||
int getSegmentNumber() const;
|
||||
double getCenterDepth() const;
|
||||
void attachSegment(const int segmentNumber , const double centerDepth);
|
||||
bool attachedToSegment() const;
|
||||
|
||||
WellCompletion::DirectionEnum getDirection() const;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define SEGMENT_HPP_HEADER_INCLUDED
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
@@ -45,6 +46,9 @@ namespace Opm {
|
||||
void setVolume(const double volume_in);
|
||||
void setDepthAndLength(const double depth_in, const double length_in);
|
||||
|
||||
const std::vector<int>& inletSegments() const;
|
||||
void addInletSegment(const int segment_number);
|
||||
|
||||
static double invalidValue();
|
||||
|
||||
bool operator==( const Segment& ) const;
|
||||
@@ -61,6 +65,8 @@ namespace Opm {
|
||||
// the outlet junction segment
|
||||
// for top segment, it should be -1
|
||||
int m_outlet_segment;
|
||||
// the segments whose outlet segments are the current segment
|
||||
std::vector<int> m_inlet_segments;
|
||||
// length of the segment node to the bhp reference point.
|
||||
// when reading in from deck, with 'INC',
|
||||
// it will be incremental length before processing.
|
||||
|
||||
@@ -45,11 +45,15 @@ namespace Opm {
|
||||
WellSegment::CompPressureDropEnum compPressureDrop() const;
|
||||
WellSegment::MultiPhaseModelEnum multiPhaseModel() const;
|
||||
|
||||
int numberToLocation(const int segment_number) const;
|
||||
// mapping the segment number to the index in the vector of segments
|
||||
int segmentNumberToIndex(const int segment_number) const;
|
||||
|
||||
void addSegment(Segment new_segment);
|
||||
|
||||
void segmentsFromWELSEGSKeyword( const DeckKeyword& welsegsKeyword);
|
||||
|
||||
const Segment& getFromSegmentNumber(const int segment_number) const;
|
||||
|
||||
const Segment& operator[](size_t idx) const;
|
||||
void orderSegments();
|
||||
void processABS();
|
||||
@@ -86,8 +90,8 @@ namespace Opm {
|
||||
|
||||
std::vector< Segment > m_segments;
|
||||
// the mapping from the segment number to the
|
||||
// storage location in the vector
|
||||
std::map<int, int> m_number_to_location;
|
||||
// storage index in the vector
|
||||
std::map<int, int> m_segment_number_to_index;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef UPDATING_COMPLETIONS_WITH_SEGMENTS
|
||||
#define UPDATING_COMPLETIONS_WITH_SEGMENTS
|
||||
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
|
||||
|
||||
namespace Opm {
|
||||
CompletionSet updatingCompletionsWithSegments(const DeckKeyword& compsegs, const CompletionSet& input_completions, const SegmentSet& segments);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -82,6 +82,7 @@ set(opmparser_SOURCES Deck/Deck.cpp
|
||||
EclipseState/Schedule/MSW/Compsegs.cpp
|
||||
EclipseState/Schedule/MSW/Segment.cpp
|
||||
EclipseState/Schedule/MSW/SegmentSet.cpp
|
||||
EclipseState/Schedule/MSW/updatingCompletionsWithSegments.cpp
|
||||
EclipseState/Schedule/OilVaporizationProperties.cpp
|
||||
EclipseState/Schedule/Schedule.cpp
|
||||
EclipseState/Schedule/ScheduleEnums.cpp
|
||||
@@ -229,6 +230,7 @@ foreach(test ADDREGTests
|
||||
MessageContainerTest
|
||||
MessageLimitTests
|
||||
MultiRegTests
|
||||
MultisegmentWellTests
|
||||
MULTREGTScannerTests
|
||||
OrderedMapTests
|
||||
ParseContextTests
|
||||
|
||||
@@ -77,6 +77,14 @@ namespace Opm {
|
||||
this->m_complnum = num;
|
||||
}
|
||||
|
||||
Completion::Completion(const Completion& completion_initial, int segment_number, double center_depth)
|
||||
: Completion(completion_initial)
|
||||
{
|
||||
assert(segment_number > 0);
|
||||
this->m_segment_number = segment_number;
|
||||
this->m_center_depth = center_depth;
|
||||
}
|
||||
|
||||
bool Completion::sameCoordinate(const Completion& other) const {
|
||||
if ((m_i == other.m_i) &&
|
||||
(m_j == other.m_j) &&
|
||||
@@ -301,13 +309,6 @@ namespace Opm {
|
||||
return m_center_depth;
|
||||
}
|
||||
|
||||
void Completion::attachSegment(int segmentNumber , double centerDepth) {
|
||||
assert(segmentNumber > 0);
|
||||
|
||||
m_segment_number = segmentNumber;
|
||||
m_center_depth = centerDepth;
|
||||
}
|
||||
|
||||
bool Completion::attachedToSegment() const {
|
||||
return (m_segment_number > 0);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.hpp>
|
||||
#include "Compsegs.hpp"
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
#include <opm/parser/eclipse/Parser/ParserKeywords/C.hpp>
|
||||
@@ -168,18 +168,66 @@ namespace Opm {
|
||||
}
|
||||
|
||||
compseg.m_segment_number = segment_number;
|
||||
|
||||
// when depth is default or zero, we obtain the depth of the completion based on the information
|
||||
// of the related segments
|
||||
if (compseg.m_center_depth == 0.) {
|
||||
// using the depth of the segment node as the depth of the completion
|
||||
// TODO: now only one completion for one segment is hanlded,
|
||||
// TODO: later we will try to handle more than one completion for each segment,
|
||||
// TODO: which will be a linear interpolation based on the segment node depth
|
||||
// TODO: in the same branch, while the actually way is not clear yet
|
||||
const int segment_location = segment_set.numberToLocation(segment_number);
|
||||
compseg.m_center_depth = segment_set[segment_location].depth();
|
||||
compseg.calculateCenterDepthWithSegments(segment_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Compsegs::calculateCenterDepthWithSegments(const SegmentSet& segment_set) {
|
||||
|
||||
// the depth and distance of the segment to the well head
|
||||
const Segment& segment = segment_set.getFromSegmentNumber(m_segment_number);
|
||||
const double segment_depth = segment.depth();
|
||||
const double segment_distance = segment.totalLength();
|
||||
|
||||
// for top segment, no interpolation is needed
|
||||
if (m_segment_number == 1) {
|
||||
m_center_depth = segment_depth;
|
||||
return;
|
||||
}
|
||||
|
||||
// for other cases, interpolation between two segments is needed.
|
||||
// looking for the other segment needed for interpolation
|
||||
// by default, it uses the outlet segment to do the interpolation
|
||||
int interpolation_segment_number = segment.outletSegment();
|
||||
|
||||
const double center_distance = (m_distance_start + m_distance_end) / 2.0;
|
||||
// if the perforation is further than the segment and the segment has inlet segments in the same branch
|
||||
// we use the inlet segment to do the interpolation
|
||||
if (center_distance > segment_distance) {
|
||||
for (const int inlet : segment.inletSegments()) {
|
||||
const int inlet_index = segment_set.segmentNumberToIndex(inlet);
|
||||
if (segment_set[inlet_index].branchNumber() == m_branch_number) {
|
||||
interpolation_segment_number = inlet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interpolation_segment_number == 0) {
|
||||
throw std::runtime_error("Failed in finding a segment to do the interpolation with segment "
|
||||
+ std::to_string(m_segment_number));
|
||||
}
|
||||
|
||||
// performing the interpolation
|
||||
const Segment& interpolation_segment = segment_set.getFromSegmentNumber(interpolation_segment_number);
|
||||
const double interpolation_detph = interpolation_segment.depth();
|
||||
const double interpolation_distance = interpolation_segment.totalLength();
|
||||
|
||||
const double depth_change_segment = segment_depth - interpolation_detph;
|
||||
const double segment_length = segment_distance - interpolation_distance;
|
||||
|
||||
if (segment_length == 0.) {
|
||||
throw std::runtime_error("Zero segment length is botained when doing interpolation between segment "
|
||||
+ std::to_string(m_segment_number) + " and segment " + std::to_string(interpolation_segment_number) );
|
||||
}
|
||||
|
||||
m_center_depth = segment_depth + (center_distance - segment_distance) / segment_length * depth_change_segment;
|
||||
}
|
||||
|
||||
void Compsegs::updateCompletionsWithSegment(const std::vector< Compsegs >& compsegs,
|
||||
CompletionSet& completion_set) {
|
||||
@@ -189,9 +237,8 @@ namespace Opm {
|
||||
const int j = compseg.m_j;
|
||||
const int k = compseg.m_k;
|
||||
|
||||
auto new_completion = completion_set.getFromIJK( i, j, k );
|
||||
new_completion.attachSegment(compseg.m_segment_number, compseg.m_center_depth);
|
||||
completion_set.add(new_completion);
|
||||
const Completion& completion = completion_set.getFromIJK( i, j, k );
|
||||
completion_set.add(Completion(completion, compseg.m_segment_number, compseg.m_center_depth) );
|
||||
}
|
||||
|
||||
for (size_t ic = 0; ic < completion_set.size(); ++ic) {
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace Opm {
|
||||
Compsegs(int i_in, int j_in, int k_in, int branch_number_in, double distance_start_in, double distance_end_in,
|
||||
WellCompletion::DirectionEnum dir_in, double center_depth_in, int segment_number_in);
|
||||
|
||||
void calculateCenterDepthWithSegments(const SegmentSet& segment_set);
|
||||
|
||||
static std::vector< Compsegs > compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword );
|
||||
|
||||
// get the segment number information and depth information based on the information from SegmentSet
|
||||
@@ -109,6 +109,14 @@ namespace Opm {
|
||||
m_volume = volume_in;
|
||||
}
|
||||
|
||||
const std::vector<int>& Segment::inletSegments() const {
|
||||
return m_inlet_segments;
|
||||
}
|
||||
|
||||
void Segment::addInletSegment(const int segment_number) {
|
||||
m_inlet_segments.push_back(segment_number);
|
||||
}
|
||||
|
||||
double Segment::invalidValue() {
|
||||
return invalid_value;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <map>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _USE_MATH_DEFINES
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
@@ -75,9 +75,9 @@ namespace Opm {
|
||||
return m_segments[idx];
|
||||
}
|
||||
|
||||
int SegmentSet::numberToLocation(const int segment_number) const {
|
||||
auto it = m_number_to_location.find(segment_number);
|
||||
if (it != m_number_to_location.end()) {
|
||||
int SegmentSet::segmentNumberToIndex(const int segment_number) const {
|
||||
const auto it = m_segment_number_to_index.find(segment_number);
|
||||
if (it != m_segment_number_to_index.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return -1;
|
||||
@@ -86,15 +86,15 @@ namespace Opm {
|
||||
|
||||
void SegmentSet::addSegment( Segment new_segment ) {
|
||||
// decide whether to push_back or insert
|
||||
int segment_number = new_segment.segmentNumber();
|
||||
const int segment_number = new_segment.segmentNumber();
|
||||
|
||||
const int segment_location = numberToLocation(segment_number);
|
||||
const int segment_index = segmentNumberToIndex(segment_number);
|
||||
|
||||
if (segment_location < 0) { // it is a new segment
|
||||
m_number_to_location[segment_number] = numberSegment();
|
||||
if (segment_index < 0) { // it is a new segment
|
||||
m_segment_number_to_index[segment_number] = numberSegment();
|
||||
m_segments.push_back(new_segment);
|
||||
} else { // the segment already exists
|
||||
m_segments[segment_location] = new_segment;
|
||||
m_segments[segment_index] = new_segment;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,15 +197,35 @@ namespace Opm {
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i_segment = 0; i_segment < m_segments.size(); ++i_segment){
|
||||
for (size_t i_segment = 0; i_segment < m_segments.size(); ++i_segment) {
|
||||
const int segment_number = m_segments[i_segment].segmentNumber();
|
||||
const int location = numberToLocation(segment_number);
|
||||
if (location >= 0) { // found in the existing m_segments already
|
||||
const int index = segmentNumberToIndex(segment_number);
|
||||
if (index >= 0) { // found in the existing m_segments already
|
||||
throw std::logic_error("Segments with same segment number are found!\n");
|
||||
}
|
||||
m_number_to_location[segment_number] = i_segment;
|
||||
m_segment_number_to_index[segment_number] = i_segment;
|
||||
}
|
||||
|
||||
for (size_t i_segment = 0; i_segment < m_segments.size(); ++i_segment) {
|
||||
const int segment_number = m_segments[i_segment].segmentNumber();
|
||||
const int outlet_segment = m_segments[i_segment].outletSegment();
|
||||
if (outlet_segment <= 0) { // no outlet segment
|
||||
continue;
|
||||
}
|
||||
const int outlet_segment_index = m_segment_number_to_index[outlet_segment];
|
||||
m_segments[outlet_segment_index].addInletSegment(segment_number);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Segment& SegmentSet::getFromSegmentNumber(const int segment_number) const {
|
||||
// the index of segment in the vector of segments
|
||||
const int segment_index = segmentNumberToIndex(segment_number);
|
||||
if (segment_index < 0) {
|
||||
throw std::runtime_error("Could not indexate the segment " + std::to_string(segment_number)
|
||||
+ " when trying to get the segment ");
|
||||
}
|
||||
return m_segments[segment_index];
|
||||
}
|
||||
|
||||
void SegmentSet::processABS() {
|
||||
@@ -213,18 +233,18 @@ namespace Opm {
|
||||
|
||||
orderSegments();
|
||||
|
||||
int current_loc = 1;
|
||||
while (current_loc < numberSegment()) {
|
||||
if (m_segments[current_loc].dataReady()) {
|
||||
current_loc ++;
|
||||
int current_index= 1;
|
||||
while (current_index< numberSegment()) {
|
||||
if (m_segments[current_index].dataReady()) {
|
||||
current_index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const int range_begin = current_loc;
|
||||
const int range_begin = current_index;
|
||||
const int outlet_segment = m_segments[range_begin].outletSegment();
|
||||
const int outlet_loc = numberToLocation(outlet_segment);
|
||||
const int outlet_index= segmentNumberToIndex(outlet_segment);
|
||||
|
||||
assert(m_segments[outlet_loc].dataReady() == true);
|
||||
assert(m_segments[outlet_index].dataReady() == true);
|
||||
|
||||
int range_end = range_begin + 1;
|
||||
for (; range_end < numberSegment(); ++range_end) {
|
||||
@@ -241,8 +261,8 @@ namespace Opm {
|
||||
int number_segments = range_end - range_begin + 1;
|
||||
assert(number_segments > 1); //if only 1, the information should be complete
|
||||
|
||||
const double length_outlet = m_segments[outlet_loc].totalLength();
|
||||
const double depth_outlet = m_segments[outlet_loc].depth();
|
||||
const double length_outlet = m_segments[outlet_index].totalLength();
|
||||
const double depth_outlet = m_segments[outlet_index].depth();
|
||||
|
||||
const double length_last = m_segments[range_end].totalLength();
|
||||
const double depth_last = m_segments[range_end].depth();
|
||||
@@ -265,7 +285,7 @@ namespace Opm {
|
||||
}
|
||||
addSegment(new_segment);
|
||||
}
|
||||
current_loc = range_end + 1;
|
||||
current_index= range_end + 1;
|
||||
}
|
||||
|
||||
// then update the volume for all the segments except the top segment
|
||||
@@ -275,8 +295,8 @@ namespace Opm {
|
||||
if (m_segments[i].volume() == invalid_value) {
|
||||
Segment new_segment = m_segments[i];
|
||||
const int outlet_segment = m_segments[i].outletSegment();
|
||||
const int outlet_location = numberToLocation(outlet_segment);
|
||||
const double segment_length = m_segments[i].totalLength() - m_segments[outlet_location].totalLength();
|
||||
const int outlet_index = segmentNumberToIndex(outlet_segment);
|
||||
const double segment_length = m_segments[i].totalLength() - m_segments[outlet_index].totalLength();
|
||||
const double segment_volume = m_segments[i].crossArea() * segment_length;
|
||||
new_segment.setVolume(segment_volume);
|
||||
addSegment(new_segment);
|
||||
@@ -296,24 +316,24 @@ namespace Opm {
|
||||
orderSegments();
|
||||
|
||||
// begin with the second segment
|
||||
for (int i_loc = 1; i_loc < numberSegment(); ++i_loc) {
|
||||
if( m_segments[i_loc].dataReady() ) continue;
|
||||
for (int i_index= 1; i_index< numberSegment(); ++i_index) {
|
||||
if( m_segments[i_index].dataReady() ) continue;
|
||||
|
||||
// find its outlet segment
|
||||
const int outlet_segment = m_segments[i_loc].outletSegment();
|
||||
const int outlet_loc = numberToLocation(outlet_segment);
|
||||
const int outlet_segment = m_segments[i_index].outletSegment();
|
||||
const int outlet_index= segmentNumberToIndex(outlet_segment);
|
||||
|
||||
// assert some information of the outlet_segment
|
||||
assert(outlet_loc >= 0);
|
||||
assert(m_segments[outlet_loc].dataReady());
|
||||
assert(outlet_index>= 0);
|
||||
assert(m_segments[outlet_index].dataReady());
|
||||
|
||||
const double outlet_depth = m_segments[outlet_loc].depth();
|
||||
const double outlet_length = m_segments[outlet_loc].totalLength();
|
||||
const double temp_depth = outlet_depth + m_segments[i_loc].depth();
|
||||
const double temp_length = outlet_length + m_segments[i_loc].totalLength();
|
||||
const double outlet_depth = m_segments[outlet_index].depth();
|
||||
const double outlet_length = m_segments[outlet_index].totalLength();
|
||||
const double temp_depth = outlet_depth + m_segments[i_index].depth();
|
||||
const double temp_length = outlet_length + m_segments[i_index].totalLength();
|
||||
|
||||
// applying the calculated length and depth to the current segment
|
||||
Segment new_segment = this->m_segments[i_loc];
|
||||
Segment new_segment = this->m_segments[i_index];
|
||||
new_segment.setDepthAndLength(temp_depth, temp_length);
|
||||
addSegment(new_segment);
|
||||
}
|
||||
@@ -322,39 +342,39 @@ namespace Opm {
|
||||
void SegmentSet::orderSegments() {
|
||||
// re-ordering the segments to make later use easier.
|
||||
// two principles
|
||||
// 1. the location of the outlet segment will be stored in the lower location than the segment.
|
||||
// 1. the index of the outlet segment will be stored in the lower index than the segment.
|
||||
// 2. the segments belong to the same branch will be continuously stored.
|
||||
|
||||
// top segment will always be the first one
|
||||
// before this location, the reordering is done.
|
||||
int current_loc = 1;
|
||||
// before this index, the reordering is done.
|
||||
int current_index= 1;
|
||||
|
||||
// clear the mapping from segment number to store location
|
||||
m_number_to_location.clear();
|
||||
// clear the mapping from segment number to store index
|
||||
m_segment_number_to_index.clear();
|
||||
// for the top segment
|
||||
m_number_to_location[1] = 0;
|
||||
m_segment_number_to_index[1] = 0;
|
||||
|
||||
while (current_loc < numberSegment()) {
|
||||
while (current_index< numberSegment()) {
|
||||
// the branch number of the last segment that is done re-ordering
|
||||
const int last_branch_number = m_segments[current_loc-1].branchNumber();
|
||||
// the one need to be swapped to the current_loc.
|
||||
int target_segment_loc = -1;
|
||||
const int last_branch_number = m_segments[current_index-1].branchNumber();
|
||||
// the one need to be swapped to the current_index.
|
||||
int target_segment_index= -1;
|
||||
|
||||
// looking for target_segment_loc
|
||||
for (int i_loc = current_loc; i_loc < numberSegment(); ++i_loc) {
|
||||
const int outlet_segment_number = m_segments[i_loc].outletSegment();
|
||||
const int outlet_segment_location = numberToLocation(outlet_segment_number);
|
||||
if (outlet_segment_location < 0) { // not found the outlet_segment in the done re-ordering segments
|
||||
// looking for target_segment_index
|
||||
for (int i_index= current_index; i_index< numberSegment(); ++i_index) {
|
||||
const int outlet_segment_number = m_segments[i_index].outletSegment();
|
||||
const int outlet_segment_index = segmentNumberToIndex(outlet_segment_number);
|
||||
if (outlet_segment_index < 0) { // not found the outlet_segment in the done re-ordering segments
|
||||
continue;
|
||||
}
|
||||
if (target_segment_loc < 0) { // first time found a candidate
|
||||
target_segment_loc = i_loc;
|
||||
if (target_segment_index< 0) { // first time found a candidate
|
||||
target_segment_index= i_index;
|
||||
} else { // there is already a candidate, chosing the one with the same branch number with last_branch_number
|
||||
const int old_target_segment_loc_branch = m_segments[target_segment_loc].branchNumber();
|
||||
const int new_target_segment_loc_branch = m_segments[i_loc].branchNumber();
|
||||
if (new_target_segment_loc_branch == last_branch_number) {
|
||||
if (old_target_segment_loc_branch != last_branch_number) {
|
||||
target_segment_loc = i_loc;
|
||||
const int old_target_segment_index_branch = m_segments[target_segment_index].branchNumber();
|
||||
const int new_target_segment_index_branch = m_segments[i_index].branchNumber();
|
||||
if (new_target_segment_index_branch == last_branch_number) {
|
||||
if (old_target_segment_index_branch != last_branch_number) {
|
||||
target_segment_index= i_index;
|
||||
} else {
|
||||
throw std::logic_error("two segments in the same branch share the same outlet segment !!\n");
|
||||
}
|
||||
@@ -362,16 +382,16 @@ namespace Opm {
|
||||
}
|
||||
}
|
||||
|
||||
if (target_segment_loc < 0) {
|
||||
if (target_segment_index< 0) {
|
||||
throw std::logic_error("could not find candidate segment to swap in before the re-odering process get done !!\n");
|
||||
}
|
||||
assert(target_segment_loc >= current_loc);
|
||||
if (target_segment_loc > current_loc) {
|
||||
std::swap(m_segments[current_loc], m_segments[target_segment_loc]);
|
||||
assert(target_segment_index>= current_index);
|
||||
if (target_segment_index> current_index) {
|
||||
std::swap(m_segments[current_index], m_segments[target_segment_index]);
|
||||
}
|
||||
const int segment_number = m_segments[current_loc].segmentNumber();
|
||||
m_number_to_location[segment_number] = current_loc;
|
||||
current_loc++;
|
||||
const int segment_number = m_segments[current_index].segmentNumber();
|
||||
m_segment_number_to_index[segment_number] = current_index;
|
||||
current_index++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,13 +405,13 @@ namespace Opm {
|
||||
&& this->m_comp_pressure_drop == rhs.m_comp_pressure_drop
|
||||
&& this->m_multiphase_model == rhs.m_multiphase_model
|
||||
&& this->m_segments.size() == rhs.m_segments.size()
|
||||
&& this->m_number_to_location.size() == rhs.m_number_to_location.size()
|
||||
&& this->m_segment_number_to_index.size() == rhs.m_segment_number_to_index.size()
|
||||
&& std::equal( this->m_segments.begin(),
|
||||
this->m_segments.end(),
|
||||
rhs.m_segments.begin() )
|
||||
&& std::equal( this->m_number_to_location.begin(),
|
||||
this->m_number_to_location.end(),
|
||||
rhs.m_number_to_location.begin() );
|
||||
&& std::equal( this->m_segment_number_to_index.begin(),
|
||||
this->m_segment_number_to_index.end(),
|
||||
rhs.m_segment_number_to_index.begin() );
|
||||
}
|
||||
|
||||
bool SegmentSet::operator!=( const SegmentSet& rhs ) const {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
|
||||
|
||||
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 <opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.hpp>
|
||||
#include "Compsegs.hpp"
|
||||
|
||||
|
||||
namespace Opm {
|
||||
|
||||
CompletionSet updatingCompletionsWithSegments(const DeckKeyword& compsegs,
|
||||
const CompletionSet& input_completions,
|
||||
const SegmentSet& segment_set)
|
||||
{
|
||||
CompletionSet new_completion_set(input_completions);
|
||||
|
||||
std::vector<Compsegs> compsegs_vector = Compsegs::compsegsFromCOMPSEGSKeyword( compsegs );
|
||||
Compsegs::processCOMPSEGS(compsegs_vector, segment_set);
|
||||
Compsegs::updateCompletionsWithSegment(compsegs_vector, new_completion_set);
|
||||
return new_completion_set;
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,8 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Events.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/SegmentSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/OilVaporizationProperties.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
@@ -1254,15 +1254,11 @@ namespace Opm {
|
||||
const std::string& well_name = record1.getItem("WELL").getTrimmedString(0);
|
||||
auto& well = this->m_wells.get( well_name );
|
||||
|
||||
auto compsegs_vector = Compsegs::compsegsFromCOMPSEGSKeyword( keyword );
|
||||
const auto& segment_set = well.getSegmentSet(currentStep);
|
||||
const auto& completion_set = well.getCompletions( currentStep );
|
||||
const CompletionSet new_completion_set = updatingCompletionsWithSegments(keyword, completion_set, segment_set);
|
||||
|
||||
const auto& current_segmentSet = well.getSegmentSet(currentStep);
|
||||
Compsegs::processCOMPSEGS(compsegs_vector, current_segmentSet);
|
||||
|
||||
// it is necessary to update the segment related information for some completions.
|
||||
auto new_completionSet = well.getCompletions( currentStep );
|
||||
Compsegs::updateCompletionsWithSegment(compsegs_vector, new_completionSet);
|
||||
well.addCompletionSet(currentStep, new_completionSet);
|
||||
well.addCompletionSet(currentStep, new_completion_set);
|
||||
}
|
||||
|
||||
void Schedule::handleWGRUPCON( const DeckKeyword& keyword, size_t currentStep) {
|
||||
|
||||
123
tests/parser/MultisegmentWellTests.cpp
Normal file
123
tests/parser/MultisegmentWellTests.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
|
||||
|
||||
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 <stdexcept>
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE CompletionSetTests
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Completion.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/CompletionSet.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/ScheduleEnums.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/Parser/Parser.hpp>
|
||||
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
|
||||
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/MSW/updatingCompletionsWithSegments.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MultisegmentWellTest) {
|
||||
Opm::CompletionSet completion_set;
|
||||
completion_set.add(Opm::Completion( 19, 0, 0, 1, 0.0, Opm::WellCompletion::OPEN , Opm::Value<double>("ConnectionTransmissibilityFactor", 200.), Opm::Value<double>("D", 0.5), Opm::Value<double>("SKIN", 0.), 0) );
|
||||
completion_set.add(Opm::Completion( 19, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , Opm::Value<double>("ConnectionTransmissibilityFactor", 200.), Opm::Value<double>("D", 0.5), Opm::Value<double>("SKIN", 0.), 0) );
|
||||
completion_set.add(Opm::Completion( 19, 0, 2, 1, 0.0, Opm::WellCompletion::OPEN , Opm::Value<double>("ConnectionTransmissibilityFactor", 200.), Opm::Value<double>("D", 0.4), Opm::Value<double>("SKIN", 0.), 0) );
|
||||
completion_set.add(Opm::Completion( 18, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , Opm::Value<double>("ConnectionTransmissibilityFactor", 200.), Opm::Value<double>("D", 0.4), Opm::Value<double>("SKIN", 0.), 0, Opm::WellCompletion::DirectionEnum::X) );
|
||||
completion_set.add(Opm::Completion( 17, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , Opm::Value<double>("ConnectionTransmissibilityFactor", 200.), Opm::Value<double>("D", 0.4), Opm::Value<double>("SKIN", 0.), 0, Opm::WellCompletion::DirectionEnum::X) );
|
||||
completion_set.add(Opm::Completion( 16, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , Opm::Value<double>("ConnectionTransmissibilityFactor", 200.), Opm::Value<double>("D", 0.4), Opm::Value<double>("SKIN", 0.), 0, Opm::WellCompletion::DirectionEnum::X) );
|
||||
completion_set.add(Opm::Completion( 15, 0, 1, 1, 0.0, Opm::WellCompletion::OPEN , Opm::Value<double>("ConnectionTransmissibilityFactor", 200.), Opm::Value<double>("D", 0.4), Opm::Value<double>("SKIN", 0.), 0, Opm::WellCompletion::DirectionEnum::X) );
|
||||
|
||||
BOOST_CHECK_EQUAL( 7U , completion_set.size() );
|
||||
|
||||
const std::string compsegs_string =
|
||||
"WELSEGS \n"
|
||||
"'PROD01' 2512.5 2512.5 1.0e-5 'ABS' 'H--' 'HO' /\n"
|
||||
"2 2 1 1 2537.5 2537.5 0.3 0.00010 /\n"
|
||||
"3 3 1 2 2562.5 2562.5 0.2 0.00010 /\n"
|
||||
"4 4 2 2 2737.5 2537.5 0.2 0.00010 /\n"
|
||||
"6 6 2 4 3037.5 2539.5 0.2 0.00010 /\n"
|
||||
"7 7 2 6 3337.5 2534.5 0.2 0.00010 /\n"
|
||||
"/\n"
|
||||
"\n"
|
||||
"COMPSEGS\n"
|
||||
"PROD01 / \n"
|
||||
"20 1 1 1 2512.5 2525.0 /\n"
|
||||
"20 1 2 1 2525.0 2550.0 /\n"
|
||||
"20 1 3 1 2550.0 2575.0 /\n"
|
||||
"19 1 2 2 2637.5 2837.5 /\n"
|
||||
"18 1 2 2 2837.5 3037.5 /\n"
|
||||
"17 1 2 2 3037.5 3237.5 /\n"
|
||||
"16 1 2 2 3237.5 3437.5 /\n"
|
||||
"/\n";
|
||||
|
||||
Opm::Parser parser;
|
||||
Opm::Deck deck = parser.parseString(compsegs_string, Opm::ParseContext());
|
||||
|
||||
const Opm::DeckKeyword compsegs = deck.getKeyword("COMPSEGS");
|
||||
BOOST_CHECK_EQUAL( 8U, compsegs.size() );
|
||||
|
||||
Opm::SegmentSet segment_set;
|
||||
const Opm::DeckKeyword welsegs = deck.getKeyword("WELSEGS");
|
||||
segment_set.segmentsFromWELSEGSKeyword(welsegs);
|
||||
|
||||
BOOST_CHECK_EQUAL(6U, segment_set.numberSegment());
|
||||
|
||||
const Opm::CompletionSet new_completion_set = Opm::updatingCompletionsWithSegments(compsegs, completion_set, segment_set);
|
||||
|
||||
BOOST_CHECK_EQUAL(7U, new_completion_set.size());
|
||||
|
||||
const Opm::Completion& completion1 = new_completion_set.get(0);
|
||||
const int segment_number_completion1 = completion1.getSegmentNumber();
|
||||
const double center_depth_completion1 = completion1.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(segment_number_completion1, 1);
|
||||
BOOST_CHECK_EQUAL(center_depth_completion1, 2512.5);
|
||||
|
||||
const Opm::Completion& completion3 = new_completion_set.get(2);
|
||||
const int segment_number_completion3 = completion3.getSegmentNumber();
|
||||
const double center_depth_completion3 = completion3.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(segment_number_completion3, 3);
|
||||
BOOST_CHECK_EQUAL(center_depth_completion3, 2562.5);
|
||||
|
||||
const Opm::Completion& completion5 = new_completion_set.get(4);
|
||||
const int segment_number_completion5 = completion5.getSegmentNumber();
|
||||
const double center_depth_completion5 = completion5.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(segment_number_completion5, 6);
|
||||
BOOST_CHECK_CLOSE(center_depth_completion5, 2538.83, 0.001);
|
||||
|
||||
const Opm::Completion& completion6 = new_completion_set.get(5);
|
||||
const int segment_number_completion6 = completion6.getSegmentNumber();
|
||||
const double center_depth_completion6 = completion6.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(segment_number_completion6, 6);
|
||||
BOOST_CHECK_CLOSE(center_depth_completion6, 2537.83, 0.001);
|
||||
|
||||
const Opm::Completion& completion7 = new_completion_set.get(6);
|
||||
const int segment_number_completion7 = completion7.getSegmentNumber();
|
||||
const double center_depth_completion7 = completion7.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(segment_number_completion7, 7);
|
||||
BOOST_CHECK_EQUAL(center_depth_completion7, 2534.5);
|
||||
}
|
||||
|
||||
@@ -4,9 +4,31 @@
|
||||
-- License: http://opendatacommons.org/licenses/dbcl/1.0/
|
||||
|
||||
-- Copyright (C) 2015 SINTEF ICT, Applied Mathematics
|
||||
|
||||
RUNSPEC
|
||||
|
||||
DIMENS
|
||||
20 1 5 /
|
||||
|
||||
START
|
||||
06 'NOV' 2011 /
|
||||
|
||||
GRID
|
||||
|
||||
DX
|
||||
100*200 /
|
||||
DY
|
||||
100*200 /
|
||||
DZ
|
||||
100*25 /
|
||||
|
||||
TOPS
|
||||
20*2500
|
||||
20*2525
|
||||
20*2550
|
||||
20*2575
|
||||
20*2600 /
|
||||
|
||||
SCHEDULE
|
||||
|
||||
WELSPECS
|
||||
@@ -22,6 +44,7 @@ COMPDAT
|
||||
'PROD01' 19 1 2 2 'OPEN' 1* 200. 0.4 /
|
||||
'PROD01' 18 1 2 2 'OPEN' 1* 200. 0.4 /
|
||||
'PROD01' 17 1 2 2 'OPEN' 1* 200. 0.4 /
|
||||
'PROD01' 16 1 2 2 'OPEN' 1* 200. 0.4 /
|
||||
/
|
||||
|
||||
WELSEGS
|
||||
@@ -29,8 +52,8 @@ WELSEGS
|
||||
2 2 1 1 2537.5 2537.5 0.3 0.00010 /
|
||||
3 3 1 2 2562.5 2562.5 0.2 0.00010 /
|
||||
4 4 2 2 2737.5 2537.5 0.2 0.00010 /
|
||||
5 5 2 4 2937.5 2537.5 0.2 0.00010 /
|
||||
6 6 2 5 3137.5 2537.5 0.2 0.00010 /
|
||||
6 6 2 4 3037.5 2539.5 0.2 0.00010 /
|
||||
7 7 2 6 3337.5 2534.5 0.2 0.00010 /
|
||||
/
|
||||
|
||||
COMPSEGS
|
||||
@@ -41,4 +64,5 @@ COMPSEGS
|
||||
19 1 2 2 2637.5 2837.5 /
|
||||
18 1 2 2 2837.5 3037.5 /
|
||||
17 1 2 2 3037.5 3237.5 /
|
||||
16 1 2 2 3237.5 3437.5 /
|
||||
/
|
||||
|
||||
@@ -440,9 +440,16 @@ BOOST_AUTO_TEST_CASE( MULTREGT_ECLIPSE_STATE ) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( MULTISEGMENT_ABS ) {
|
||||
Parser parser;
|
||||
std::string deckFile(pathprefix() + "SCHEDULE/SCHEDULE_MULTISEGMENT_WELL");
|
||||
auto deck = parser.parseFile(deckFile, ParseContext());
|
||||
const Parser parser;
|
||||
const std::string deckFile(pathprefix() + "SCHEDULE/SCHEDULE_MULTISEGMENT_WELL");
|
||||
const auto deck = parser.parseFile(deckFile, ParseContext());
|
||||
const ParseContext parseContext;
|
||||
const EclipseState state(deck, parseContext);
|
||||
const auto& grid = state.getInputGrid();
|
||||
const TableManager table ( deck );
|
||||
const Eclipse3DProperties eclipseProperties ( deck , table, grid);
|
||||
const Schedule sched(parseContext, grid, eclipseProperties, deck, Phases(true, true, true) );
|
||||
|
||||
// for WELSEGS keyword
|
||||
const auto& kw = deck.getKeyword("WELSEGS");
|
||||
|
||||
@@ -495,7 +502,7 @@ BOOST_AUTO_TEST_CASE( MULTISEGMENT_ABS ) {
|
||||
}
|
||||
|
||||
{
|
||||
const auto& rec6 = kw.getRecord(5);
|
||||
const auto& rec6 = kw.getRecord(4);
|
||||
const int segment1 = rec6.getItem("SEGMENT2").get< int >(0);
|
||||
const int segment2 = rec6.getItem("SEGMENT2").get< int >(0);
|
||||
BOOST_CHECK_EQUAL( 6, segment1 );
|
||||
@@ -507,9 +514,9 @@ BOOST_AUTO_TEST_CASE( MULTISEGMENT_ABS ) {
|
||||
const double diameter = rec6.getItem("DIAMETER").get< double >(0);
|
||||
const double roughness = rec6.getItem("ROUGHNESS").get< double >(0);
|
||||
BOOST_CHECK_EQUAL( 2, branch );
|
||||
BOOST_CHECK_EQUAL( 5, outlet_segment );
|
||||
BOOST_CHECK_EQUAL( 3137.5, segment_length );
|
||||
BOOST_CHECK_EQUAL( 2537.5, depth_change );
|
||||
BOOST_CHECK_EQUAL( 4, outlet_segment );
|
||||
BOOST_CHECK_EQUAL( 3037.5, segment_length );
|
||||
BOOST_CHECK_EQUAL( 2539.5, depth_change );
|
||||
BOOST_CHECK_EQUAL( 0.2, diameter );
|
||||
BOOST_CHECK_EQUAL( 0.0001, roughness );
|
||||
}
|
||||
@@ -517,7 +524,7 @@ BOOST_AUTO_TEST_CASE( MULTISEGMENT_ABS ) {
|
||||
// for COMPSEG keyword
|
||||
const auto& kw1 = deck.getKeyword("COMPSEGS");
|
||||
// check the size of the keywords
|
||||
BOOST_CHECK_EQUAL( 7, kw1.size() );
|
||||
BOOST_CHECK_EQUAL( 8, kw1.size() );
|
||||
// first record only contains the well name
|
||||
{
|
||||
const auto& rec1 = kw1.getRecord(0);
|
||||
@@ -559,6 +566,39 @@ BOOST_AUTO_TEST_CASE( MULTISEGMENT_ABS ) {
|
||||
BOOST_CHECK_EQUAL( 3037.5, distance_start );
|
||||
BOOST_CHECK_EQUAL( 3237.5, distance_end );
|
||||
}
|
||||
|
||||
// checking the relation between segments and completions
|
||||
// and also the depth of completions
|
||||
{
|
||||
BOOST_CHECK(sched.hasWell("PROD01"));
|
||||
const auto* well = sched.getWell("PROD01");
|
||||
const auto& completions = well->getCompletions(0);
|
||||
BOOST_CHECK_EQUAL(7U, completions.size());
|
||||
|
||||
const Completion& completion5 = completions.get(4);
|
||||
const int seg_number_completion5 = completion5.getSegmentNumber();
|
||||
const double completion5_depth = completion5.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(seg_number_completion5, 6);
|
||||
BOOST_CHECK_CLOSE(completion5_depth, 2538.83, 0.001);
|
||||
|
||||
const Completion& completion6 = completions.get(5);
|
||||
const int seg_number_completion6 = completion6.getSegmentNumber();
|
||||
const double completion6_depth = completion6.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(seg_number_completion6, 6);
|
||||
BOOST_CHECK_CLOSE(completion6_depth, 2537.83, 0.001);
|
||||
|
||||
const Completion& completion1 = completions.get(0);
|
||||
const int seg_number_completion1 = completion1.getSegmentNumber();
|
||||
const double completion1_depth = completion1.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(seg_number_completion1, 1);
|
||||
BOOST_CHECK_EQUAL(completion1_depth, 2512.5);
|
||||
|
||||
const Completion& completion3 = completions.get(2);
|
||||
const int seg_number_completion3 = completion3.getSegmentNumber();
|
||||
const double completion3_depth = completion3.getCenterDepth();
|
||||
BOOST_CHECK_EQUAL(seg_number_completion3, 3);
|
||||
BOOST_CHECK_EQUAL(completion3_depth, 2562.5);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( PLYADS ) {
|
||||
|
||||
Reference in New Issue
Block a user