mirror of
https://github.com/OPM/ResInsight.git
synced 2026-11-01 16:43:03 -06:00
Adds MSW table data preparation tools
Introduces new classes and functions to prepare MSW table data for export.
This commit is contained in:
1 parent
8b9d6aa42c
commit
a88fecdaa4
9 files changed
+4069
No files matched your search
@@ -20,6 +20,10 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureReportItem.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForTemporaryLgrsFeature.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicMswTableFormatterTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicMswUnifiedData.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigMswDataFormatter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswTableData.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicMswTableDataTools.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@@ -44,6 +48,10 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureReportItem.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForTemporaryLgrsFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicMswTableFormatterTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicMswUnifiedData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigMswDataFormatter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswTableData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicMswTableDataTools.cpp
|
||||
)
|
||||
|
||||
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
||||
@@ -0,0 +1,604 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RicMswTableDataTools.h"
|
||||
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "CompletionsMsw/RigMswTableData.h"
|
||||
#include "RicMswCompletions.h"
|
||||
#include "RicMswExportInfo.h"
|
||||
#include "RicMswTableFormatterTools.h"
|
||||
|
||||
#include "RifTextDataTableFormatter.h"
|
||||
|
||||
#include "Well/RigWellPath.h"
|
||||
|
||||
#include "RimMswCompletionParameters.h"
|
||||
#include "RimWellPath.h"
|
||||
#include "RimWellPathCompletionSettings.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWelsegsData( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
bool exportCompletionSegmentsAfterMainBore )
|
||||
{
|
||||
// Set up WELSEGS header
|
||||
WelsegsHeader header;
|
||||
header.wellName = exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport().toStdString();
|
||||
header.topMD = exportInfo.mainBoreBranch()->startMD();
|
||||
header.topTVD = exportInfo.mainBoreBranch()->startTVD();
|
||||
header.volume = exportInfo.topWellBoreVolume();
|
||||
header.lengthAndDepthText = exportInfo.lengthAndDepthText().toStdString();
|
||||
header.pressureDropText = exportInfo.pressureDropText().toStdString();
|
||||
|
||||
tableData.setWelsegsHeader( header );
|
||||
|
||||
int segmentNumber = 2; // There's an implicit segment number 1.
|
||||
|
||||
// Collect segment data recursively
|
||||
collectWelsegsDataRecursively( tableData,
|
||||
exportInfo,
|
||||
exportInfo.mainBoreBranch(),
|
||||
&segmentNumber,
|
||||
maxSegmentLength,
|
||||
exportCompletionSegmentsAfterMainBore,
|
||||
nullptr );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWelsegsDataRecursively( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
gsl::not_null<int*> segmentNumber,
|
||||
double maxSegmentLength,
|
||||
bool exportCompletionSegmentsAfterMainBore,
|
||||
RicMswSegment* connectedToSegment )
|
||||
{
|
||||
auto outletSegment = connectedToSegment;
|
||||
RicMswValve* outletValve = nullptr;
|
||||
|
||||
auto branchSegments = branch->segments();
|
||||
auto it = branchSegments.begin();
|
||||
|
||||
// Handle tie-in ICV at the beginning of branch
|
||||
if ( outletValve = dynamic_cast<RicMswTieInICV*>( branch.get() ); outletValve != nullptr )
|
||||
{
|
||||
collectValveWelsegsSegment( tableData, outletSegment, outletValve, exportInfo, maxSegmentLength, segmentNumber );
|
||||
|
||||
auto valveSegments = outletValve->segments();
|
||||
outletSegment = valveSegments.front();
|
||||
|
||||
*segmentNumber = outletSegment->segmentNumber() + 1;
|
||||
++it; // skip segment below
|
||||
}
|
||||
|
||||
auto branchStartSegmentIterator = it;
|
||||
for ( ; it != branchSegments.end(); ++it )
|
||||
{
|
||||
auto segment = *it;
|
||||
segment->setSegmentNumber( *segmentNumber );
|
||||
|
||||
QString branchDescription;
|
||||
if ( it == branchSegments.begin() )
|
||||
{
|
||||
branchDescription = QString( "Segments on branch %1" ).arg( branch->label() );
|
||||
}
|
||||
|
||||
collectWelsegsSegment( tableData, segment, outletSegment, exportInfo, maxSegmentLength, branch, segmentNumber, branchDescription );
|
||||
outletSegment = segment;
|
||||
|
||||
if ( !exportCompletionSegmentsAfterMainBore )
|
||||
{
|
||||
collectCompletionsForSegment( tableData, outletSegment, segment, &outletValve, exportInfo, maxSegmentLength, segmentNumber );
|
||||
}
|
||||
}
|
||||
|
||||
if ( exportCompletionSegmentsAfterMainBore )
|
||||
{
|
||||
it = branchStartSegmentIterator;
|
||||
|
||||
for ( ; it != branchSegments.end(); ++it )
|
||||
{
|
||||
auto segment = *it;
|
||||
collectCompletionsForSegment( tableData, outletSegment, segment, &outletValve, exportInfo, maxSegmentLength, segmentNumber );
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto childBranch : branch->branches() )
|
||||
{
|
||||
RicMswSegment* outletSegmentForChildBranch = outletSegment;
|
||||
|
||||
RicMswSegment* tieInSegmentOnParentBranch = branch->findClosestSegmentWithLowerMD( childBranch->startMD() );
|
||||
if ( tieInSegmentOnParentBranch ) outletSegmentForChildBranch = tieInSegmentOnParentBranch;
|
||||
|
||||
collectWelsegsDataRecursively( tableData,
|
||||
exportInfo,
|
||||
childBranch,
|
||||
segmentNumber,
|
||||
maxSegmentLength,
|
||||
exportCompletionSegmentsAfterMainBore,
|
||||
outletSegmentForChildBranch );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect WELSEGS data for a single segment with sub-segmentation
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWelsegsSegment( RigMswTableData& tableData,
|
||||
RicMswSegment* segment,
|
||||
const RicMswSegment* previousSegment,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
int* segmentNumber,
|
||||
QString branchDescription )
|
||||
{
|
||||
CVF_ASSERT( segment && segmentNumber );
|
||||
|
||||
double startMD = segment->startMD();
|
||||
double endMD = segment->endMD();
|
||||
|
||||
std::vector<std::pair<double, double>> segments = RicMswTableFormatterTools::createSubSegmentMDPairs( startMD, endMD, maxSegmentLength );
|
||||
|
||||
CVF_ASSERT( branch->wellPath() );
|
||||
|
||||
double prevOutMD = branch->startMD();
|
||||
double prevOutTVD = branch->startTVD();
|
||||
if ( previousSegment )
|
||||
{
|
||||
prevOutMD = previousSegment->outputMD();
|
||||
prevOutTVD = previousSegment->outputTVD();
|
||||
}
|
||||
|
||||
bool setDescription = true;
|
||||
|
||||
auto outletSegment = previousSegment;
|
||||
for ( const auto& [subStartMD, subEndMD] : segments )
|
||||
{
|
||||
double depth = 0;
|
||||
double length = 0;
|
||||
|
||||
double midPointMD = 0.5 * ( subStartMD + subEndMD );
|
||||
double midPointTVD = RicMswTableFormatterTools::tvdFromMeasuredDepth( branch->wellPath(), midPointMD );
|
||||
|
||||
if ( midPointMD < prevOutMD )
|
||||
{
|
||||
// The first segment of parent branch may sometimes have a MD that is larger than the first segment on the
|
||||
// lateral. If this is the case, use the startMD of the branch instead
|
||||
prevOutMD = branch->startMD();
|
||||
prevOutTVD = branch->startTVD();
|
||||
}
|
||||
|
||||
if ( exportInfo.lengthAndDepthText() == "INC" )
|
||||
{
|
||||
depth = midPointTVD - prevOutTVD;
|
||||
length = midPointMD - prevOutMD;
|
||||
}
|
||||
else
|
||||
{
|
||||
depth = midPointTVD;
|
||||
length = midPointMD;
|
||||
}
|
||||
|
||||
const auto linerDiameter = branch->wellPath()->mswCompletionParameters()->getDiameterAtMD( midPointMD, exportInfo.unitSystem() );
|
||||
const auto roughnessFactor = branch->wellPath()->mswCompletionParameters()->getRoughnessAtMD( midPointMD, exportInfo.unitSystem() );
|
||||
|
||||
WelsegsRow row;
|
||||
row.segmentNumber = segment->segmentNumber();
|
||||
row.outletSegmentNumber = outletSegment ? outletSegment->segmentNumber() : 1;
|
||||
row.branchNumber = branch->branchNumber();
|
||||
row.length = length;
|
||||
row.depth = depth;
|
||||
row.diameter = linerDiameter;
|
||||
row.roughness = roughnessFactor;
|
||||
if ( setDescription )
|
||||
{
|
||||
row.description = branchDescription.toStdString();
|
||||
setDescription = false;
|
||||
}
|
||||
|
||||
tableData.addWelsegsRow( row );
|
||||
|
||||
if ( segments.size() > 1 )
|
||||
{
|
||||
( *segmentNumber )++;
|
||||
segment->setSegmentNumber( *segmentNumber );
|
||||
}
|
||||
|
||||
segment->setOutputMD( midPointMD );
|
||||
segment->setOutputTVD( midPointTVD );
|
||||
segment->setSegmentNumber( *segmentNumber );
|
||||
|
||||
outletSegment = segment;
|
||||
prevOutMD = midPointMD;
|
||||
prevOutTVD = midPointTVD;
|
||||
}
|
||||
|
||||
if ( segments.size() <= 1 )
|
||||
{
|
||||
( *segmentNumber )++;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect WELSEGS data for valve completions
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectValveWelsegsSegment( RigMswTableData& tableData,
|
||||
const RicMswSegment* outletSegment,
|
||||
RicMswValve* valve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber )
|
||||
{
|
||||
for ( auto valveSegment : valve->segments() )
|
||||
{
|
||||
valveSegment->setSegmentNumber( *segmentNumber );
|
||||
|
||||
WelsegsRow row;
|
||||
row.segmentNumber = valveSegment->segmentNumber();
|
||||
row.outletSegmentNumber = outletSegment ? outletSegment->segmentNumber() : 1;
|
||||
row.branchNumber = valve->branchNumber();
|
||||
row.length = valveSegment->startMD();
|
||||
row.depth = valveSegment->startTVD();
|
||||
row.diameter = valveSegment->equivalentDiameter();
|
||||
row.roughness = valveSegment->openHoleRoughnessFactor();
|
||||
// row.description = QString( "Valve %1" ).arg( valve->label() );
|
||||
|
||||
tableData.addWelsegsRow( row );
|
||||
|
||||
( *segmentNumber )++;
|
||||
outletSegment = valveSegment;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect WELSEGS data for completions on a segment
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectCompletionsForSegment( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
RicMswValve** outletValve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber )
|
||||
{
|
||||
for ( auto& completion : segment->completions() )
|
||||
{
|
||||
// For a well with perforation intervals, the WELSEGS segments are reported twice if we include the
|
||||
// RicMswPerforation completions. Investigate when this class is intended to be exported to file
|
||||
auto performationMsw = dynamic_cast<RicMswPerforation*>( completion );
|
||||
if ( performationMsw ) continue;
|
||||
|
||||
auto segmentValve = dynamic_cast<RicMswValve*>( completion );
|
||||
auto fishboneIcd = dynamic_cast<RicMswFishbonesICD*>( completion );
|
||||
if ( !fishboneIcd && segmentValve != nullptr )
|
||||
{
|
||||
collectValveWelsegsSegment( tableData, segment, segmentValve, exportInfo, maxSegmentLength, segmentNumber );
|
||||
*outletValve = segmentValve;
|
||||
}
|
||||
else if ( dynamic_cast<RicMswTieInICV*>( completion ) )
|
||||
{
|
||||
// Special handling for Tie-in ICVs
|
||||
RicMswSegment* outletSegmentForCompletion =
|
||||
*outletValve && ( *outletValve )->segmentCount() > 0 ? ( *outletValve )->segments().front() : segment.get();
|
||||
collectCompletionWelsegsSegments( tableData, outletSegmentForCompletion, completion, exportInfo, maxSegmentLength, segmentNumber );
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the default case for completions that are not valves
|
||||
collectCompletionWelsegsSegments( tableData, segment, completion, exportInfo, maxSegmentLength, segmentNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect WELSEGS data for a completion's segments
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectCompletionWelsegsSegments( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswCompletion*> completion,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber )
|
||||
{
|
||||
bool isDescriptionAdded = false;
|
||||
|
||||
auto outletNumber = outletSegment->segmentNumber();
|
||||
|
||||
for ( auto completionSegment : completion->segments() )
|
||||
{
|
||||
completionSegment->setSegmentNumber( *segmentNumber );
|
||||
|
||||
WelsegsRow row;
|
||||
row.segmentNumber = completionSegment->segmentNumber();
|
||||
row.outletSegmentNumber = outletNumber;
|
||||
row.branchNumber = completion->branchNumber();
|
||||
row.length = completionSegment->startMD();
|
||||
row.depth = completionSegment->startTVD();
|
||||
row.diameter = completionSegment->equivalentDiameter();
|
||||
row.roughness = completionSegment->openHoleRoughnessFactor();
|
||||
|
||||
if ( !isDescriptionAdded )
|
||||
{
|
||||
row.description = completion->label().toStdString();
|
||||
isDescriptionAdded = true;
|
||||
}
|
||||
|
||||
tableData.addWelsegsRow( row );
|
||||
|
||||
outletNumber = *segmentNumber;
|
||||
( *segmentNumber )++;
|
||||
|
||||
for ( auto comp : completionSegment->completions() )
|
||||
{
|
||||
collectCompletionWelsegsSegments( tableData, completionSegment, comp, exportInfo, maxSegmentLength, segmentNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectCompsegData( RigMswTableData& tableData, RicMswExportInfo& exportInfo, bool exportSubGridIntersections )
|
||||
{
|
||||
// Define completion types to export
|
||||
std::set<RigCompletionData::CompletionType> perforationTypes = { RigCompletionData::CompletionType::PERFORATION,
|
||||
RigCompletionData::CompletionType::PERFORATION_ICD,
|
||||
RigCompletionData::CompletionType::PERFORATION_ICV,
|
||||
RigCompletionData::CompletionType::PERFORATION_AICD };
|
||||
|
||||
std::set<RigCompletionData::CompletionType> fishbonesTypes = { RigCompletionData::CompletionType::FISHBONES_ICD,
|
||||
RigCompletionData::CompletionType::FISHBONES };
|
||||
|
||||
std::set<RigCompletionData::CompletionType> fractureTypes = { RigCompletionData::CompletionType::FRACTURE };
|
||||
|
||||
std::set<size_t> intersectedCells;
|
||||
|
||||
// Collect in order: perforations, fishbones, fractures
|
||||
collectCompsegDataByType( tableData, exportInfo, exportInfo.mainBoreBranch(), exportSubGridIntersections, perforationTypes, &intersectedCells );
|
||||
collectCompsegDataByType( tableData, exportInfo, exportInfo.mainBoreBranch(), exportSubGridIntersections, fishbonesTypes, &intersectedCells );
|
||||
collectCompsegDataByType( tableData, exportInfo, exportInfo.mainBoreBranch(), exportSubGridIntersections, fractureTypes, &intersectedCells );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect COMPSEGS data for specific completion types
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectCompsegDataByType( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<const RicMswBranch*> branch,
|
||||
bool exportSubGridIntersections,
|
||||
const std::set<RigCompletionData::CompletionType>& exportCompletionTypes,
|
||||
gsl::not_null<std::set<size_t>*> intersectedCells )
|
||||
{
|
||||
for ( auto segment : branch->segments() )
|
||||
{
|
||||
auto completion = dynamic_cast<const RicMswCompletion*>( branch.get() );
|
||||
|
||||
for ( auto intersection : segment->intersections() )
|
||||
{
|
||||
bool isSubGridIntersection = !intersection->gridName().isEmpty();
|
||||
if ( isSubGridIntersection != exportSubGridIntersections ) continue;
|
||||
|
||||
double startLength = segment->startMD();
|
||||
double endLength = segment->endMD();
|
||||
|
||||
if ( completion )
|
||||
{
|
||||
bool isPerforationValve = completion->completionType() == RigCompletionData::CompletionType::PERFORATION_ICD ||
|
||||
completion->completionType() == RigCompletionData::CompletionType::PERFORATION_AICD ||
|
||||
completion->completionType() == RigCompletionData::CompletionType::PERFORATION_ICV;
|
||||
|
||||
if ( isPerforationValve )
|
||||
{
|
||||
startLength = segment->startMD();
|
||||
endLength = segment->endMD();
|
||||
}
|
||||
}
|
||||
|
||||
size_t globalCellIndex = intersection->globalCellIndex();
|
||||
|
||||
// Check if the cell is already reported. Make sure we report intersections before other completions
|
||||
// on the segment to be able to connect the branch with most flow
|
||||
if ( !intersectedCells->count( globalCellIndex ) )
|
||||
{
|
||||
CompsegsRow row;
|
||||
|
||||
cvf::Vec3st ijk = intersection->gridLocalCellIJK();
|
||||
row.cellI = ijk.x() + 1; // Convert to 1-based
|
||||
row.cellJ = ijk.y() + 1;
|
||||
row.cellK = ijk.z() + 1;
|
||||
|
||||
int branchNumber = -1;
|
||||
if ( completion ) branchNumber = completion->branchNumber();
|
||||
row.branchNumber = branchNumber;
|
||||
|
||||
row.startLength = startLength;
|
||||
row.endLength = endLength;
|
||||
row.gridName = exportSubGridIntersections ? intersection->gridName().toStdString() : "";
|
||||
|
||||
tableData.addCompsegsRow( row );
|
||||
intersectedCells->insert( globalCellIndex );
|
||||
}
|
||||
}
|
||||
|
||||
// Report connected completions after the intersection on current segment has been reported
|
||||
for ( auto completion : segment->completions() )
|
||||
{
|
||||
if ( completion->segments().empty() || !exportCompletionTypes.count( completion->completionType() ) ) continue;
|
||||
|
||||
collectCompsegDataByType( tableData, exportInfo, completion, exportSubGridIntersections, exportCompletionTypes, intersectedCells );
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto childBranch : branch->branches() )
|
||||
{
|
||||
collectCompsegDataByType( tableData, exportInfo, childBranch, exportSubGridIntersections, exportCompletionTypes, intersectedCells );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWsegvalvData( RigMswTableData& tableData, RicMswExportInfo& exportInfo )
|
||||
{
|
||||
QString wellNameForExport = exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport();
|
||||
collectWsegvalvDataRecursively( tableData, exportInfo.mainBoreBranch(), wellNameForExport.toStdString() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect WSEGVALV data recursively through branches
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWsegvalvDataRecursively( RigMswTableData& tableData,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
const std::string& wellNameForExport )
|
||||
{
|
||||
// Handle tie-in ICV at branch level
|
||||
{
|
||||
auto tieInValve = dynamic_cast<RicMswTieInICV*>( branch.get() );
|
||||
if ( tieInValve && !tieInValve->segments().empty() )
|
||||
{
|
||||
auto firstSubSegment = tieInValve->segments().front();
|
||||
CAF_ASSERT( tieInValve->completionType() == RigCompletionData::CompletionType::PERFORATION_ICV );
|
||||
|
||||
auto flowCoefficient = tieInValve->flowCoefficient();
|
||||
|
||||
WsegvalvRow row;
|
||||
row.wellName = wellNameForExport;
|
||||
row.segmentNumber = firstSubSegment->segmentNumber();
|
||||
row.flowCoefficient = flowCoefficient;
|
||||
row.area = tieInValve->area();
|
||||
|
||||
tableData.addWsegvalvRow( row );
|
||||
}
|
||||
}
|
||||
|
||||
// Process segments and their completions
|
||||
for ( auto segment : branch->segments() )
|
||||
{
|
||||
for ( auto completion : segment->completions() )
|
||||
{
|
||||
if ( RigCompletionData::isWsegValveTypes( completion->completionType() ) )
|
||||
{
|
||||
auto wsegValve = static_cast<RicMswWsegValve*>( completion );
|
||||
int segmentNumber = -1;
|
||||
|
||||
for ( auto seg : wsegValve->segments() )
|
||||
{
|
||||
if ( seg->segmentNumber() > -1 ) segmentNumber = seg->segmentNumber();
|
||||
if ( seg->intersections().empty() ) continue;
|
||||
|
||||
QString comment;
|
||||
if ( wsegValve->completionType() == RigCompletionData::CompletionType::PERFORATION_ICD ||
|
||||
wsegValve->completionType() == RigCompletionData::CompletionType::PERFORATION_ICV )
|
||||
{
|
||||
comment = wsegValve->label();
|
||||
}
|
||||
|
||||
WsegvalvRow row;
|
||||
row.wellName = wellNameForExport;
|
||||
row.segmentNumber = segmentNumber;
|
||||
row.flowCoefficient = wsegValve->flowCoefficient();
|
||||
row.area = wsegValve->area();
|
||||
|
||||
tableData.addWsegvalvRow( row );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into child branches
|
||||
for ( auto childBranch : branch->branches() )
|
||||
{
|
||||
collectWsegvalvDataRecursively( tableData, childBranch, wellNameForExport );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWsegAicdData( RigMswTableData& tableData, RicMswExportInfo& exportInfo )
|
||||
{
|
||||
collectWsegAicdDataRecursively( tableData, exportInfo, exportInfo.mainBoreBranch() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to collect WSEGAICD data recursively through branches
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswTableDataTools::collectWsegAicdDataRecursively( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<const RicMswBranch*> branch )
|
||||
{
|
||||
for ( auto segment : branch->segments() )
|
||||
{
|
||||
for ( auto completion : segment->completions() )
|
||||
{
|
||||
if ( completion->completionType() == RigCompletionData::CompletionType::PERFORATION_AICD )
|
||||
{
|
||||
auto aicd = static_cast<const RicMswPerforationAICD*>( completion );
|
||||
if ( aicd->isValid() )
|
||||
{
|
||||
int segmentNumber = -1;
|
||||
for ( auto seg : aicd->segments() )
|
||||
{
|
||||
if ( seg->segmentNumber() > -1 ) segmentNumber = seg->segmentNumber();
|
||||
if ( seg->intersections().empty() ) continue;
|
||||
|
||||
auto wellName = exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport();
|
||||
auto comment = aicd->label();
|
||||
|
||||
WsegaicdRow row;
|
||||
row.wellName = wellName.toStdString();
|
||||
row.segmentNumber = segmentNumber;
|
||||
row.flowCoefficient = aicd->flowScalingFactor();
|
||||
row.deviceType = comment.toStdString();
|
||||
|
||||
// Extract AICD-specific parameters from the values array
|
||||
auto values = aicd->values();
|
||||
if ( values.size() >= 3 )
|
||||
{
|
||||
row.oilViscosityParameter = values[0];
|
||||
row.waterViscosityParameter = values[1];
|
||||
row.gasViscosityParameter = values[2];
|
||||
}
|
||||
|
||||
tableData.addWsegaicdRow( row );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RiaLogging::error( QString( "Export AICD Valve (%1): Valve is invalid. At least one required "
|
||||
"template parameter is not set." )
|
||||
.arg( aicd->label() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto childBranch : branch->branches() )
|
||||
{
|
||||
collectWsegAicdDataRecursively( tableData, exportInfo, childBranch );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RigCompletionData.h"
|
||||
|
||||
#include "cvfVector3.h"
|
||||
|
||||
#include <gsl/gsl>
|
||||
|
||||
class RicMswExportInfo;
|
||||
class RigMswTableData;
|
||||
class RifTextDataTableFormatter;
|
||||
class RicMswBranch;
|
||||
class RicMswSegment;
|
||||
class RicMswValve;
|
||||
class RicMswCompletion;
|
||||
class RimWellPath;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// WIP
|
||||
/// This is a helper class namespace for functions to generate MSW table data for well segments and completions
|
||||
/// This class is based on the existing RicMswTableFormatterTools, but with functions to collect data into RigMswTableData
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
namespace RicMswTableDataTools
|
||||
{
|
||||
|
||||
// New data collection functions (replace formatter versions)
|
||||
void collectWelsegsData( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
bool exportCompletionSegmentsAfterMainBore );
|
||||
|
||||
void collectWelsegsDataRecursively( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
gsl::not_null<int*> segmentNumber,
|
||||
double maxSegmentLength,
|
||||
bool exportCompletionSegmentsAfterMainBore,
|
||||
RicMswSegment* connectedToSegment );
|
||||
|
||||
void collectCompsegData( RigMswTableData& tableData, RicMswExportInfo& exportInfo, bool exportSubGridIntersections );
|
||||
|
||||
void collectCompsegDataByType( RigMswTableData& tableData,
|
||||
RicMswExportInfo& exportInfo,
|
||||
gsl::not_null<const RicMswBranch*> branch,
|
||||
bool exportSubGridIntersections,
|
||||
const std::set<RigCompletionData::CompletionType>& exportCompletionTypes,
|
||||
gsl::not_null<std::set<size_t>*> intersectedCells );
|
||||
|
||||
void collectWsegvalvData( RigMswTableData& tableData, RicMswExportInfo& exportInfo );
|
||||
|
||||
void collectWsegvalvDataRecursively( RigMswTableData& tableData, gsl::not_null<RicMswBranch*> branch, const std::string& wellNameForExport );
|
||||
|
||||
void collectWsegAicdData( RigMswTableData& tableData, RicMswExportInfo& exportInfo );
|
||||
|
||||
void collectWsegAicdDataRecursively( RigMswTableData& tableData, RicMswExportInfo& exportInfo, gsl::not_null<const RicMswBranch*> branch );
|
||||
|
||||
// Helper functions for data collection
|
||||
void collectWelsegsSegment( RigMswTableData& tableData,
|
||||
RicMswSegment* segment,
|
||||
const RicMswSegment* previousSegment,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
int* segmentNumber,
|
||||
QString branchDescription );
|
||||
|
||||
void collectValveWelsegsSegment( RigMswTableData& tableData,
|
||||
const RicMswSegment* outletSegment,
|
||||
RicMswValve* valve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber );
|
||||
|
||||
void collectCompletionsForSegment( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
RicMswValve** outletValve,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber );
|
||||
|
||||
void collectCompletionWelsegsSegments( RigMswTableData& tableData,
|
||||
gsl::not_null<const RicMswSegment*> outletSegment,
|
||||
gsl::not_null<RicMswCompletion*> completion,
|
||||
RicMswExportInfo& exportInfo,
|
||||
double maxSegmentLength,
|
||||
int* segmentNumber );
|
||||
|
||||
} // namespace RicMswTableDataTools
|
||||
@@ -0,0 +1,240 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RicMswUnifiedData.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswUnifiedDataWIP::addWellData( RigMswTableData wellData )
|
||||
{
|
||||
// Check if well name already exists
|
||||
const std::string& wellName = wellData.wellName();
|
||||
auto it = std::find_if( m_wellDataList.begin(),
|
||||
m_wellDataList.end(),
|
||||
[&wellName]( const RigMswTableData& data ) { return data.wellName() == wellName; } );
|
||||
|
||||
if ( it != m_wellDataList.end() )
|
||||
{
|
||||
// Replace existing data
|
||||
*it = std::move( wellData );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add new data
|
||||
m_wellDataList.push_back( std::move( wellData ) );
|
||||
}
|
||||
|
||||
updateIndex();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswUnifiedDataWIP::clear()
|
||||
{
|
||||
m_wellDataList.clear();
|
||||
m_wellNameToIndex.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const RigMswTableData* RicMswUnifiedDataWIP::getWellData( const std::string& wellName ) const
|
||||
{
|
||||
auto it = m_wellNameToIndex.find( wellName );
|
||||
if ( it != m_wellNameToIndex.end() && it->second < m_wellDataList.size() )
|
||||
{
|
||||
return &m_wellDataList[it->second];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<WelsegsHeader> RicMswUnifiedDataWIP::getAllWelsegsHeaders() const
|
||||
{
|
||||
std::vector<WelsegsHeader> allHeaders;
|
||||
|
||||
for ( const auto& wellData : m_wellDataList )
|
||||
{
|
||||
allHeaders.push_back( wellData.welsegsHeader() );
|
||||
}
|
||||
|
||||
return allHeaders;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<WelsegsRow> RicMswUnifiedDataWIP::getAllWelsegsRows() const
|
||||
{
|
||||
std::vector<WelsegsRow> allRows;
|
||||
|
||||
for ( const auto& wellData : m_wellDataList )
|
||||
{
|
||||
const auto& wellRows = wellData.welsegsData();
|
||||
allRows.insert( allRows.end(), wellRows.begin(), wellRows.end() );
|
||||
}
|
||||
|
||||
return allRows;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<CompsegsRow> RicMswUnifiedDataWIP::getAllCompsegsRows( bool lgrOnly ) const
|
||||
{
|
||||
std::vector<CompsegsRow> allRows;
|
||||
|
||||
for ( const auto& wellData : m_wellDataList )
|
||||
{
|
||||
std::vector<CompsegsRow> wellRows;
|
||||
|
||||
if ( lgrOnly )
|
||||
{
|
||||
wellRows = wellData.lgrCompsegsData();
|
||||
}
|
||||
else
|
||||
{
|
||||
wellRows = wellData.mainGridCompsegsData();
|
||||
}
|
||||
|
||||
allRows.insert( allRows.end(), wellRows.begin(), wellRows.end() );
|
||||
}
|
||||
|
||||
return allRows;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<WsegvalvRow> RicMswUnifiedDataWIP::getAllWsegvalvRows() const
|
||||
{
|
||||
std::vector<WsegvalvRow> allRows;
|
||||
|
||||
for ( const auto& wellData : m_wellDataList )
|
||||
{
|
||||
const auto& wellRows = wellData.wsegvalvData();
|
||||
allRows.insert( allRows.end(), wellRows.begin(), wellRows.end() );
|
||||
}
|
||||
|
||||
return allRows;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<WsegaicdRow> RicMswUnifiedDataWIP::getAllWsegaicdRows() const
|
||||
{
|
||||
std::vector<WsegaicdRow> allRows;
|
||||
|
||||
for ( const auto& wellData : m_wellDataList )
|
||||
{
|
||||
const auto& wellRows = wellData.wsegaicdData();
|
||||
allRows.insert( allRows.end(), wellRows.begin(), wellRows.end() );
|
||||
}
|
||||
|
||||
return allRows;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicMswUnifiedDataWIP::hasAnyLgrData() const
|
||||
{
|
||||
return std::any_of( m_wellDataList.begin(), m_wellDataList.end(), []( const RigMswTableData& wellData ) { return wellData.hasLgrData(); } );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::string> RicMswUnifiedDataWIP::wellNames() const
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
names.reserve( m_wellDataList.size() );
|
||||
|
||||
std::transform( m_wellDataList.begin(),
|
||||
m_wellDataList.end(),
|
||||
std::back_inserter( names ),
|
||||
[]( const RigMswTableData& wellData ) { return wellData.wellName(); } );
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicMswUnifiedDataWIP::isValid() const
|
||||
{
|
||||
return validationErrors().empty();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RicMswUnifiedDataWIP::validationErrors() const
|
||||
{
|
||||
std::vector<QString> errors;
|
||||
|
||||
if ( m_wellDataList.empty() )
|
||||
{
|
||||
errors.push_back( "No well data available" );
|
||||
return errors;
|
||||
}
|
||||
|
||||
// Check each well's data validity
|
||||
for ( const auto& wellData : m_wellDataList )
|
||||
{
|
||||
if ( !wellData.isValid() )
|
||||
{
|
||||
auto wellErrors = wellData.validationErrors();
|
||||
for ( const auto& error : wellErrors )
|
||||
{
|
||||
errors.push_back( QString( "%1: %2" ).arg( QString::fromStdString( wellData.wellName() ), error ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for duplicate well names
|
||||
std::vector<std::string> names = wellNames();
|
||||
std::sort( names.begin(), names.end() );
|
||||
auto it = std::adjacent_find( names.begin(), names.end() );
|
||||
if ( it != names.end() )
|
||||
{
|
||||
errors.push_back( QString( "Duplicate well name: %1" ).arg( QString::fromStdString( *it ) ) );
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicMswUnifiedDataWIP::updateIndex()
|
||||
{
|
||||
m_wellNameToIndex.clear();
|
||||
|
||||
for ( size_t i = 0; i < m_wellDataList.size(); ++i )
|
||||
{
|
||||
m_wellNameToIndex[m_wellDataList[i].wellName()] = i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CompletionsMsw/RigMswTableData.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
//==================================================================================================
|
||||
/// Container class for unified MSW table data from multiple wells
|
||||
//==================================================================================================
|
||||
class RicMswUnifiedDataWIP
|
||||
{
|
||||
public:
|
||||
RicMswUnifiedDataWIP() = default;
|
||||
|
||||
// Data modification
|
||||
void addWellData( RigMswTableData wellData );
|
||||
void clear();
|
||||
|
||||
// Data access
|
||||
const std::vector<RigMswTableData>& wellDataList() const { return m_wellDataList; }
|
||||
const RigMswTableData* getWellData( const std::string& wellName ) const;
|
||||
|
||||
// Aggregated data access - combines data from all wells
|
||||
std::vector<WelsegsHeader> getAllWelsegsHeaders() const;
|
||||
std::vector<WelsegsRow> getAllWelsegsRows() const;
|
||||
std::vector<CompsegsRow> getAllCompsegsRows( bool lgrOnly = false ) const;
|
||||
std::vector<WsegvalvRow> getAllWsegvalvRows() const;
|
||||
std::vector<WsegaicdRow> getAllWsegaicdRows() const;
|
||||
|
||||
// Metadata and analysis
|
||||
bool isEmpty() const { return m_wellDataList.empty(); }
|
||||
bool hasAnyLgrData() const;
|
||||
size_t wellCount() const { return m_wellDataList.size(); }
|
||||
std::vector<std::string> wellNames() const;
|
||||
|
||||
// Data validation
|
||||
bool isValid() const;
|
||||
std::vector<QString> validationErrors() const;
|
||||
|
||||
// Iterator support for range-based loops
|
||||
auto begin() const { return m_wellDataList.begin(); }
|
||||
auto end() const { return m_wellDataList.end(); }
|
||||
auto begin() { return m_wellDataList.begin(); }
|
||||
auto end() { return m_wellDataList.end(); }
|
||||
|
||||
private:
|
||||
std::vector<RigMswTableData> m_wellDataList;
|
||||
std::map<std::string, size_t> m_wellNameToIndex;
|
||||
|
||||
void updateIndex();
|
||||
};
|
||||
+2363
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,234 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma once
|
||||
|
||||
#include "RicMswBranch.h"
|
||||
#include "RicMswCompletions.h"
|
||||
#include "RicMswExportInfo.h"
|
||||
#include "RicMswSegment.h"
|
||||
|
||||
#include <gsl/gsl>
|
||||
|
||||
#include <expected>
|
||||
#include <set>
|
||||
|
||||
class RicExportCompletionDataSettingsUi;
|
||||
class RigActiveCellInfo;
|
||||
class RimEclipseCase;
|
||||
class RimFishbones;
|
||||
class RimPerforationInterval;
|
||||
class RimWellPath;
|
||||
class RigMswTableData;
|
||||
class RicMswUnifiedDataWIP;
|
||||
class RimWellPathFracture;
|
||||
class RimMswCompletionParameters;
|
||||
class RigWellPath;
|
||||
class RimModeledWellPath;
|
||||
|
||||
struct WellPathCellIntersectionInfo;
|
||||
|
||||
class QFile;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// This class is responsible for exporting well path MSW table data
|
||||
/// This class is based on RicWellPathExportMswCompletionsImpl
|
||||
///
|
||||
/// TODO
|
||||
/// - remove all functions not used by extractSingleWellMswData()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RicWellPathExportMswTableData
|
||||
{
|
||||
public:
|
||||
static std::expected<RigMswTableData, std::string>
|
||||
extractSingleWellMswData( RimEclipseCase* eclipseCase, RimWellPath* wellPath, int timeStep );
|
||||
|
||||
private:
|
||||
static void exportWellSegmentsForAllCompletions( const RicExportCompletionDataSettingsUi& exportSettings,
|
||||
const std::vector<RimWellPath*>& wellPaths );
|
||||
|
||||
static void exportWellSegmentsForFractures( RimEclipseCase* eclipseCase,
|
||||
std::shared_ptr<QFile> exportFile,
|
||||
std::shared_ptr<QFile> lgrExportFile,
|
||||
const RimWellPath* wellPath,
|
||||
bool exportDataSourceAsComment,
|
||||
bool completionSegmentsAfterMainBore );
|
||||
|
||||
static void exportWellSegmentsForFishbones( RimEclipseCase* eclipseCase,
|
||||
std::shared_ptr<QFile> exportFile,
|
||||
std::shared_ptr<QFile> lgrExportFile,
|
||||
const RimWellPath* wellPath,
|
||||
bool exportDataSourceAsComment,
|
||||
bool completionSegmentsAfterMainBore );
|
||||
|
||||
static void updateDataForMultipleItemsInSameGridCell( gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
static void exportWellSegmentsForPerforations( RimEclipseCase* eclipseCase,
|
||||
std::shared_ptr<QFile> exportFile,
|
||||
std::shared_ptr<QFile> lgrExportFile,
|
||||
const RimWellPath* wellPath,
|
||||
int timeStep,
|
||||
bool exportDataSourceAsComment,
|
||||
bool completionSegmentsAfterMainBore );
|
||||
|
||||
static void generateFishbonesMswExportInfoForWell( const RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
gsl::not_null<RicMswExportInfo*> exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
private:
|
||||
static void exportUnifiedWellSegments( const RicExportCompletionDataSettingsUi& exportSettings, const std::vector<RimWellPath*>& wellPaths );
|
||||
|
||||
static void exportUnifiedMswData( const RicExportCompletionDataSettingsUi& exportSettings, const std::vector<RimWellPath*>& wellPaths );
|
||||
static void exportSplitMswData( const RicExportCompletionDataSettingsUi& exportSettings, const std::vector<RimWellPath*>& wellPaths );
|
||||
|
||||
// New data extraction functions
|
||||
static RicMswUnifiedDataWIP extractUnifiedMswData( const RicExportCompletionDataSettingsUi& exportSettings,
|
||||
const std::vector<RimWellPath*>& wellPaths );
|
||||
|
||||
static void generateFishbonesMswExportInfo( const RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
double initialMD,
|
||||
const std::vector<WellPathCellIntersectionInfo>& cellIntersections,
|
||||
bool enableSegmentSplitting,
|
||||
gsl::not_null<RicMswExportInfo*> exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
static void appendFishbonesMswExportInfo( const RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
double initialMD,
|
||||
const std::vector<WellPathCellIntersectionInfo>& cellIntersections,
|
||||
bool enableSegmentSplitting,
|
||||
gsl::not_null<RicMswExportInfo*> exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
static void generateFishbonesMswExportInfo( const RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
double initialMD,
|
||||
const std::vector<WellPathCellIntersectionInfo>& cellIntersections,
|
||||
const std::vector<RimFishbones*>& fishbonesSubs,
|
||||
bool enableSegmentSplitting,
|
||||
gsl::not_null<RicMswExportInfo*> exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
static bool generateFracturesMswExportInfo( RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
double initialMD,
|
||||
const std::vector<WellPathCellIntersectionInfo>& cellIntersections,
|
||||
gsl::not_null<RicMswExportInfo*> exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
static bool appendFracturesMswExportInfo( RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
double initialMD,
|
||||
const std::vector<WellPathCellIntersectionInfo>& cellIntersections,
|
||||
gsl::not_null<RicMswExportInfo*> exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
static bool generatePerforationsMswExportInfo( RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
int timeStep,
|
||||
double initialMD,
|
||||
const std::vector<WellPathCellIntersectionInfo>& cellIntersections,
|
||||
gsl::not_null<RicMswExportInfo*> exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
static std::vector<WellPathCellIntersectionInfo> generateCellSegments( const RimEclipseCase* eclipseCase, const RimWellPath* wellPath );
|
||||
|
||||
static double computeIntitialMeasuredDepth( const RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
const RimMswCompletionParameters* mswParameters,
|
||||
const std::vector<WellPathCellIntersectionInfo>& allIntersections );
|
||||
|
||||
static std::vector<WellPathCellIntersectionInfo> filterIntersections( const std::vector<WellPathCellIntersectionInfo>& intersections,
|
||||
double initialMD,
|
||||
gsl::not_null<const RigWellPath*> wellPathGeometry,
|
||||
gsl::not_null<const RimEclipseCase*> eclipseCase );
|
||||
|
||||
static std::pair<double, double> calculateOverlapWithActiveCells( double startMD,
|
||||
double endMD,
|
||||
const std::vector<WellPathCellIntersectionInfo>& wellPathIntersections,
|
||||
const RigActiveCellInfo* activeCellInfo );
|
||||
|
||||
static void createWellPathSegments( gsl::not_null<RicMswBranch*> branch,
|
||||
const std::vector<WellPathCellIntersectionInfo>& cellSegmentIntersections,
|
||||
const std::vector<const RimPerforationInterval*>& perforationIntervals,
|
||||
const RimWellPath* wellPath,
|
||||
int timeStep,
|
||||
const RimEclipseCase* eclipseCase,
|
||||
bool* foundSubGridIntersections );
|
||||
|
||||
static void createValveCompletions( gsl::not_null<RicMswBranch*> branch,
|
||||
const std::vector<const RimPerforationInterval*>& perforationIntervals,
|
||||
const RimWellPath* wellPath,
|
||||
RiaDefines::EclipseUnitSystem unitSystem );
|
||||
|
||||
static void assignValveContributionsToSuperICDsOrAICDs( gsl::not_null<RicMswBranch*> branch,
|
||||
const std::vector<const RimPerforationInterval*>& perforationIntervals,
|
||||
const std::vector<WellPathCellIntersectionInfo>& wellPathIntersections,
|
||||
const RigActiveCellInfo* activeCellInfo,
|
||||
RiaDefines::EclipseUnitSystem unitSystem );
|
||||
|
||||
static void moveIntersectionsToICVs( gsl::not_null<RicMswBranch*> branch,
|
||||
const std::vector<const RimPerforationInterval*>& perforationIntervals,
|
||||
RiaDefines::EclipseUnitSystem unitSystem );
|
||||
|
||||
static void moveIntersectionsToSuperICDsOrAICDs( gsl::not_null<RicMswBranch*> branch );
|
||||
|
||||
static void assignFishbonesLateralIntersections( const RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
const RimFishbones* fishbonesSubs,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
bool* foundSubGridIntersections,
|
||||
double maxSegmentLength,
|
||||
RiaDefines::EclipseUnitSystem unitSystem );
|
||||
|
||||
static void assignFractureCompletionsToCellSegment( const RimEclipseCase* eclipseCase,
|
||||
const RimWellPath* wellPath,
|
||||
const RimWellPathFracture* fracture,
|
||||
const std::vector<RigCompletionData>& completionData,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
bool* foundSubGridIntersections );
|
||||
|
||||
static std::vector<RigCompletionData> generatePerforationIntersections( gsl::not_null<const RimWellPath*> wellPath,
|
||||
gsl::not_null<const RimPerforationInterval*> perforationInterval,
|
||||
int timeStep,
|
||||
gsl::not_null<const RimEclipseCase*> eclipseCase );
|
||||
|
||||
static void assignPerforationIntersections( const std::vector<RigCompletionData>& completionData,
|
||||
gsl::not_null<RicMswCompletion*> perforationCompletion,
|
||||
const WellPathCellIntersectionInfo& cellIntInfo,
|
||||
double overlapStart,
|
||||
double overlapEnd,
|
||||
bool* foundSubGridIntersections );
|
||||
|
||||
static void assignBranchNumbersToPerforations( const RimEclipseCase* eclipseCase,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
gsl::not_null<int*> branchNumber );
|
||||
static void assignBranchNumbersToOtherCompletions( const RimEclipseCase* eclipseCase,
|
||||
gsl::not_null<RicMswSegment*> segment,
|
||||
gsl::not_null<int*> branchNumber );
|
||||
|
||||
static void assignBranchNumbersToBranch( const RimEclipseCase* eclipseCase,
|
||||
RicMswExportInfo* exportInfo,
|
||||
gsl::not_null<RicMswBranch*> branch,
|
||||
gsl::not_null<int*> branchNumber );
|
||||
|
||||
static std::unique_ptr<RicMswBranch> createChildMswBranch( const RimWellPath* childWellPath );
|
||||
|
||||
static std::vector<RimWellPath*> wellPathsWithTieIn( const RimWellPath* wellPath );
|
||||
};
|
||||
@@ -0,0 +1,402 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RigMswDataFormatter.h"
|
||||
|
||||
#include "CompletionsMsw/RigMswTableData.h"
|
||||
#include "RicMswExportInfo.h"
|
||||
#include "RicMswUnifiedData.h"
|
||||
#include "RifTextDataTableFormatter.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to format WELSEGS segment data rows
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename RowContainer>
|
||||
void formatWelsegsRows( RifTextDataTableFormatter& formatter, const RowContainer& rows )
|
||||
{
|
||||
for ( const auto& row : rows )
|
||||
{
|
||||
formatter.add( row.segmentNumber );
|
||||
formatter.add( row.segmentNumber );
|
||||
formatter.add( row.branchNumber );
|
||||
formatter.add( row.outletSegmentNumber );
|
||||
formatter.add( row.length );
|
||||
|
||||
formatter.addOptionalValue( row.depth );
|
||||
formatter.addOptionalValue( row.diameter );
|
||||
formatter.addOptionalValue( row.roughness );
|
||||
|
||||
formatter.addOptionalComment( QString::fromStdString( row.description ) );
|
||||
formatter.rowCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to format COMPSEGS data rows
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename RowContainer>
|
||||
void formatCompsegsRows( RifTextDataTableFormatter& formatter, const RowContainer& rows, bool isLgrData )
|
||||
{
|
||||
for ( const auto& row : rows )
|
||||
{
|
||||
if ( isLgrData )
|
||||
{
|
||||
formatter.addStdString( row.gridName );
|
||||
}
|
||||
|
||||
formatter.add( row.cellI );
|
||||
formatter.add( row.cellJ );
|
||||
formatter.add( row.cellK );
|
||||
formatter.add( row.branchNumber );
|
||||
formatter.add( row.startLength );
|
||||
formatter.add( row.endLength );
|
||||
|
||||
formatter.addOptionalValue( row.direction );
|
||||
formatter.addOptionalValue( row.endRange );
|
||||
formatter.addOptionalValue( row.connectionDepth );
|
||||
|
||||
formatter.rowCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to format WSEGVALV data rows
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename RowContainer>
|
||||
void formatWsegvalvRows( RifTextDataTableFormatter& formatter, const RowContainer& rows )
|
||||
{
|
||||
for ( const auto& row : rows )
|
||||
{
|
||||
formatter.addStdString( row.wellName );
|
||||
formatter.add( row.segmentNumber );
|
||||
formatter.add( row.flowCoefficient );
|
||||
formatter.addOptionalValue( row.area );
|
||||
|
||||
formatter.rowCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to format WSEGAICD data rows
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename RowContainer>
|
||||
void formatWsegaicdRows( RifTextDataTableFormatter& formatter, const RowContainer& rows )
|
||||
{
|
||||
for ( const auto& row : rows )
|
||||
{
|
||||
formatter.addStdString( row.wellName );
|
||||
formatter.add( row.segmentNumber );
|
||||
formatter.add( row.flowCoefficient );
|
||||
formatter.addOptionalValue( row.area );
|
||||
formatter.addOptionalValue( row.oilViscosityParameter );
|
||||
formatter.addOptionalValue( row.waterViscosityParameter );
|
||||
formatter.addOptionalValue( row.gasViscosityParameter );
|
||||
formatter.addStdString( row.deviceType );
|
||||
|
||||
formatter.rowCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to create COMPSEGS headers
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RifTextDataTableColumn> createCompsegsHeader( bool isLgrData )
|
||||
{
|
||||
if ( isLgrData )
|
||||
{
|
||||
return { RifTextDataTableColumn( "Grid" ),
|
||||
RifTextDataTableColumn( "I" ),
|
||||
RifTextDataTableColumn( "J" ),
|
||||
RifTextDataTableColumn( "K" ),
|
||||
RifTextDataTableColumn( "Branch no" ),
|
||||
RifTextDataTableColumn( "Start Length" ),
|
||||
RifTextDataTableColumn( "End Length" ),
|
||||
RifTextDataTableColumn( "Dir Pen" ),
|
||||
RifTextDataTableColumn( "End Range" ),
|
||||
RifTextDataTableColumn( "Connection Depth" ) };
|
||||
}
|
||||
else
|
||||
{
|
||||
return { RifTextDataTableColumn( "I" ),
|
||||
RifTextDataTableColumn( "J" ),
|
||||
RifTextDataTableColumn( "K" ),
|
||||
RifTextDataTableColumn( "Branch no" ),
|
||||
RifTextDataTableColumn( "Start Length" ),
|
||||
RifTextDataTableColumn( "End Length" ),
|
||||
RifTextDataTableColumn( "Dir Pen" ),
|
||||
RifTextDataTableColumn( "End Range" ),
|
||||
RifTextDataTableColumn( "Connection Depth" ) };
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to create WSEGVALV headers
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RifTextDataTableColumn> createWsegvalvHeader()
|
||||
{
|
||||
return { RifTextDataTableColumn( "Well" ),
|
||||
RifTextDataTableColumn( "Seg No" ),
|
||||
RifTextDataTableColumn( "Cv" ),
|
||||
RifTextDataTableColumn( "Ac", RifTextDataTableDoubleFormatting( RIF_CONSISE, 4 ) ) };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to create WSEGAICD headers
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RifTextDataTableColumn> createWsegaicdHeader()
|
||||
{
|
||||
return { RifTextDataTableColumn( "Well" ),
|
||||
RifTextDataTableColumn( "Seg No" ),
|
||||
RifTextDataTableColumn( "Flow Coeff" ),
|
||||
RifTextDataTableColumn( "Area" ),
|
||||
RifTextDataTableColumn( "Oil Visc" ),
|
||||
RifTextDataTableColumn( "Water Visc" ),
|
||||
RifTextDataTableColumn( "Gas Visc" ),
|
||||
RifTextDataTableColumn( "Device Type" ) };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Helper function to create WELSEGS segment headers
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RifTextDataTableColumn> createWelsegsSegmentHeader()
|
||||
{
|
||||
return { RifTextDataTableColumn( "First Seg" ),
|
||||
RifTextDataTableColumn( "Last Seg" ),
|
||||
RifTextDataTableColumn( "Branch No" ),
|
||||
RifTextDataTableColumn( "Outlet Seg" ),
|
||||
RifTextDataTableColumn( "Length" ),
|
||||
RifTextDataTableColumn( "Depth Change" ),
|
||||
RifTextDataTableColumn( "Diam" ),
|
||||
RifTextDataTableColumn( "Rough", RifTextDataTableDoubleFormatting( RIF_FLOAT, 7 ) ) };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format WELSEGS table for a single well
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatWelsegsTable( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData )
|
||||
{
|
||||
if ( !tableData.hasWelsegsData() ) return;
|
||||
|
||||
const auto& welsegsHeader = tableData.welsegsHeader();
|
||||
formatter.keyword( "WELSEGS" );
|
||||
std::vector<RifTextDataTableColumn> tableHeader = {
|
||||
RifTextDataTableColumn( "Well" ),
|
||||
RifTextDataTableColumn( "Dep 1" ),
|
||||
RifTextDataTableColumn( "Tlen 1" ),
|
||||
RifTextDataTableColumn( "Vol 1" ),
|
||||
RifTextDataTableColumn( "Len&Dep" ),
|
||||
RifTextDataTableColumn( "PresDrop" ),
|
||||
};
|
||||
formatter.header( tableHeader );
|
||||
|
||||
// Write header row
|
||||
formatter.addStdString( welsegsHeader.wellName );
|
||||
formatter.add( welsegsHeader.topTVD );
|
||||
formatter.add( welsegsHeader.topMD );
|
||||
formatter.addOptionalValue( welsegsHeader.volume );
|
||||
formatter.addStdString( welsegsHeader.lengthAndDepthText );
|
||||
formatter.addStdString( welsegsHeader.pressureDropText );
|
||||
formatter.rowCompleted();
|
||||
|
||||
// Column headers for segment data
|
||||
auto segmentHeader = createWelsegsSegmentHeader();
|
||||
formatter.header( segmentHeader );
|
||||
|
||||
// Write segment data using helper function
|
||||
formatWelsegsRows( formatter, tableData.welsegsData() );
|
||||
formatter.tableCompleted();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format COMPSEGS table for a single well
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatCompsegsTable( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData, bool isLgrData )
|
||||
{
|
||||
std::vector<CompsegsRow> rows;
|
||||
if ( isLgrData )
|
||||
{
|
||||
rows = tableData.lgrCompsegsData();
|
||||
}
|
||||
else
|
||||
{
|
||||
rows = tableData.mainGridCompsegsData();
|
||||
}
|
||||
|
||||
if ( rows.empty() ) return;
|
||||
|
||||
formatter.keyword( "COMPSEGS" );
|
||||
|
||||
// Add well name
|
||||
{
|
||||
std::vector<RifTextDataTableColumn> header = { RifTextDataTableColumn( "Name" ) };
|
||||
formatter.header( header );
|
||||
formatter.addStdString( tableData.wellName() );
|
||||
formatter.rowCompleted();
|
||||
}
|
||||
|
||||
auto header = createCompsegsHeader( isLgrData );
|
||||
formatter.header( header );
|
||||
|
||||
formatCompsegsRows( formatter, rows, isLgrData );
|
||||
formatter.tableCompleted();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format WSEGVALV table for a single well
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatWsegvalvTable( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData )
|
||||
{
|
||||
if ( !tableData.hasWsegvalvData() ) return;
|
||||
|
||||
formatter.keyword( "WSEGVALV" );
|
||||
auto header = createWsegvalvHeader();
|
||||
formatter.header( header );
|
||||
|
||||
formatWsegvalvRows( formatter, tableData.wsegvalvData() );
|
||||
formatter.tableCompleted();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format WSEGAICD table for a single well
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatWsegaicdTable( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData )
|
||||
{
|
||||
if ( !tableData.hasWsegaicdData() ) return;
|
||||
|
||||
formatter.keyword( "WSEGAICD" );
|
||||
auto header = createWsegaicdHeader();
|
||||
formatter.header( header );
|
||||
|
||||
formatWsegaicdRows( formatter, tableData.wsegaicdData() );
|
||||
formatter.tableCompleted();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format WELSEGS table for unified data (multiple wells)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatWelsegsTable( RifTextDataTableFormatter& formatter, const RicMswUnifiedDataWIP& unifiedData )
|
||||
{
|
||||
if ( unifiedData.isEmpty() ) return;
|
||||
|
||||
auto headers = unifiedData.getAllWelsegsHeaders();
|
||||
auto rows = unifiedData.getAllWelsegsRows();
|
||||
|
||||
if ( headers.empty() && rows.empty() ) return;
|
||||
|
||||
formatter.keyword( "WELSEGS" );
|
||||
std::vector<RifTextDataTableColumn> unifiedWelsegsHeader = { RifTextDataTableColumn( "Well" ),
|
||||
RifTextDataTableColumn( "Dep 1" ),
|
||||
RifTextDataTableColumn( "Tlen 1" ),
|
||||
RifTextDataTableColumn( "Vol 1" ),
|
||||
RifTextDataTableColumn( "Len&Dep" ),
|
||||
RifTextDataTableColumn( "PresDrop" ) };
|
||||
formatter.header( unifiedWelsegsHeader );
|
||||
|
||||
// Write headers for all wells
|
||||
for ( const auto& header : headers )
|
||||
{
|
||||
formatter.addStdString( header.wellName );
|
||||
formatter.add( header.topTVD );
|
||||
formatter.add( header.topMD );
|
||||
formatter.addOptionalValue( header.volume );
|
||||
formatter.addStdString( header.lengthAndDepthText );
|
||||
formatter.addStdString( header.pressureDropText );
|
||||
formatter.rowCompleted();
|
||||
}
|
||||
|
||||
// Column headers for segment data
|
||||
auto segmentHeader = createWelsegsSegmentHeader();
|
||||
formatter.header( segmentHeader );
|
||||
|
||||
// Write all segment data using helper function
|
||||
formatWelsegsRows( formatter, rows );
|
||||
|
||||
formatter.tableCompleted();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format WSEGVALV table for unified data (multiple wells)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatWsegvalvTable( RifTextDataTableFormatter& formatter, const RicMswUnifiedDataWIP& unifiedData )
|
||||
{
|
||||
auto rows = unifiedData.getAllWsegvalvRows();
|
||||
if ( rows.empty() ) return;
|
||||
|
||||
formatter.keyword( "WSEGVALV" );
|
||||
auto header = createWsegvalvHeader();
|
||||
formatter.header( header );
|
||||
|
||||
formatWsegvalvRows( formatter, rows );
|
||||
|
||||
formatter.tableCompleted();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format WSEGAICD table for unified data (multiple wells)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatWsegaicdTable( RifTextDataTableFormatter& formatter, const RicMswUnifiedDataWIP& unifiedData )
|
||||
{
|
||||
auto rows = unifiedData.getAllWsegaicdRows();
|
||||
if ( rows.empty() ) return;
|
||||
|
||||
formatter.keyword( "WSEGAICD" );
|
||||
auto header = createWsegaicdHeader();
|
||||
formatter.header( header );
|
||||
|
||||
formatWsegaicdRows( formatter, rows );
|
||||
|
||||
formatter.tableCompleted();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format all MSW tables for a single well
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatMswTables( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData )
|
||||
{
|
||||
formatWelsegsTable( formatter, tableData );
|
||||
formatCompsegsTable( formatter, tableData, false ); // Main grid
|
||||
|
||||
if ( tableData.hasLgrData() )
|
||||
{
|
||||
formatCompsegsTable( formatter, tableData, true ); // LGR data
|
||||
}
|
||||
|
||||
formatWsegvalvTable( formatter, tableData );
|
||||
formatWsegaicdTable( formatter, tableData );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Format all MSW tables for unified data (multiple wells)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigMswDataFormatter::formatMswTables( RifTextDataTableFormatter& formatter, const RicMswUnifiedDataWIP& unifiedData )
|
||||
{
|
||||
formatWelsegsTable( formatter, unifiedData );
|
||||
|
||||
for ( const auto& wellData : unifiedData.wellDataList() )
|
||||
{
|
||||
bool isLgrData = false;
|
||||
formatCompsegsTable( formatter, wellData, isLgrData ); // Main grid, LGR is handeled separately
|
||||
}
|
||||
|
||||
formatWsegvalvTable( formatter, unifiedData );
|
||||
formatWsegaicdTable( formatter, unifiedData );
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 Equinor ASA
|
||||
//
|
||||
// ResInsight 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.
|
||||
//
|
||||
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma once
|
||||
|
||||
class RifTextDataTableFormatter;
|
||||
class RigMswTableData;
|
||||
class RicMswUnifiedDataWIP;
|
||||
|
||||
//==================================================================================================
|
||||
/// Formatter functions that convert MSW data structures to file output using RifTextDataTableFormatter
|
||||
//==================================================================================================
|
||||
namespace RigMswDataFormatter
|
||||
{
|
||||
// Consolidated data formatting - works with any compatible data source
|
||||
void formatCompsegsTable( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData, bool isLgrData = false );
|
||||
void formatWsegvalvTable( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData );
|
||||
void formatWsegvalvTable( RifTextDataTableFormatter& formatter, const RicMswUnifiedDataWIP& unifiedData );
|
||||
void formatWsegaicdTable( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData );
|
||||
void formatWsegaicdTable( RifTextDataTableFormatter& formatter, const RicMswUnifiedDataWIP& unifiedData );
|
||||
void formatWelsegsTable( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData );
|
||||
void formatWelsegsTable( RifTextDataTableFormatter& formatter, const RicMswUnifiedDataWIP& unifiedData );
|
||||
|
||||
// Complete MSW export
|
||||
void formatMswTables( RifTextDataTableFormatter& formatter, const RigMswTableData& tableData );
|
||||
void formatMswTables( RifTextDataTableFormatter& formatter, const RicMswUnifiedDataWIP& unifiedData );
|
||||
} // namespace RigMswDataFormatter
|
||||
Reference in new issue
Block a user