obtaining the depth for the completions based on segment information

This commit is contained in:
Kai Bao
2017-10-16 21:51:21 +02:00
parent f9973c5cf0
commit 4e6bf8f019
15 changed files with 452 additions and 110 deletions

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;
};
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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 {

View File

@@ -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;
}
}

View File

@@ -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) {

View 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);
}

View File

@@ -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 /
/

View File

@@ -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 ) {