From 2f7de9469f5d904aa424807df15218f374370c99 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 9 Oct 2026 14:36:40 +0200 Subject: [PATCH] #13568 MSW export: Optionally export ISEG in COMPSEGS Fixes #13568. --- .../Jobs/RimKeywordFactory.cpp | 13 +++- .../CompletionsMsw/RigMswDataFormatter.cpp | 67 ++++++++++++------- .../CompletionsMsw/RigMswTableRows.h | 2 + 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/ApplicationLibCode/ProjectDataModel/Jobs/RimKeywordFactory.cpp b/ApplicationLibCode/ProjectDataModel/Jobs/RimKeywordFactory.cpp index 5dc5ecf4fe..349b75df4c 100644 --- a/ApplicationLibCode/ProjectDataModel/Jobs/RimKeywordFactory.cpp +++ b/ApplicationLibCode/ProjectDataModel/Jobs/RimKeywordFactory.cpp @@ -320,7 +320,9 @@ Opm::DeckKeyword compsegsKeyword( const RigMswTableData& mswData ) newKw.addRecord( Opm::DeckRecord{ std::move( headerItems ) } ); // data rows - for ( auto& csRow : mswData.compsegsData() ) + const auto& rows = mswData.compsegsData(); + const bool exportSegmentNumbers = std::ranges::any_of( rows, []( const CompsegsRow& row ) { return row.segmentNumber.has_value(); } ); + for ( auto& csRow : rows ) { std::vector items; items.push_back( RifOpmDeckTools::item( Opm::ParserKeywords::COMPSEGS::I::itemName, csRow.i ) ); @@ -330,6 +332,15 @@ Opm::DeckKeyword compsegsKeyword( const RigMswTableData& mswData ) items.push_back( RifOpmDeckTools::item( Opm::ParserKeywords::COMPSEGS::DISTANCE_START::itemName, csRow.distanceStart ) ); items.push_back( RifOpmDeckTools::item( Opm::ParserKeywords::COMPSEGS::DISTANCE_END::itemName, csRow.distanceEnd ) ); + if ( exportSegmentNumbers ) + { + items.push_back( RifOpmDeckTools::defaultItem( Opm::ParserKeywords::COMPSEGS::DIRECTION::itemName ) ); + items.push_back( RifOpmDeckTools::defaultItem( Opm::ParserKeywords::COMPSEGS::END_IJK::itemName ) ); + items.push_back( RifOpmDeckTools::defaultItem( Opm::ParserKeywords::COMPSEGS::CENTER_DEPTH::itemName ) ); + items.push_back( RifOpmDeckTools::defaultItem( Opm::ParserKeywords::COMPSEGS::THERMAL_LENGTH::itemName ) ); + items.push_back( RifOpmDeckTools::optionalItem( Opm::ParserKeywords::COMPSEGS::SEGMENT_NUMBER::itemName, csRow.segmentNumber ) ); + } + newKw.addRecord( Opm::DeckRecord{ std::move( items ) } ); } diff --git a/ApplicationLibCode/ReservoirDataModel/CompletionsMsw/RigMswDataFormatter.cpp b/ApplicationLibCode/ReservoirDataModel/CompletionsMsw/RigMswDataFormatter.cpp index 426d2f407a..573cac0697 100644 --- a/ApplicationLibCode/ReservoirDataModel/CompletionsMsw/RigMswDataFormatter.cpp +++ b/ApplicationLibCode/ReservoirDataModel/CompletionsMsw/RigMswDataFormatter.cpp @@ -23,8 +23,24 @@ #include "RigMswTableData.h" #include "RigMswUnifiedData.h" +#include + namespace { +//-------------------------------------------------------------------------------------------------- +/// COMPSEGS items between the end length and ISEG, written as defaults when ISEG is exported: +/// direction, end of range, connection depth and thermal length +//-------------------------------------------------------------------------------------------------- +constexpr int compsegsItemsBeforeSegmentNumber = 4; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool hasSegmentNumbers( const std::vector& rows ) +{ + return std::ranges::any_of( rows, []( const CompsegsRow& row ) { return row.segmentNumber.has_value(); } ); +} + //-------------------------------------------------------------------------------------------------- /// Helper function to format WELSEGS segment data rows //-------------------------------------------------------------------------------------------------- @@ -55,6 +71,7 @@ void formatWelsegsRows( RifTextDataTableFormatter& formatter, const std::vector< //-------------------------------------------------------------------------------------------------- void formatCompsegsRows( RifTextDataTableFormatter& formatter, const std::vector& rows, bool isLgrData ) { + const bool exportSegmentNumbers = hasSegmentNumbers( rows ); for ( const auto& row : rows ) { if ( isLgrData ) @@ -69,6 +86,19 @@ void formatCompsegsRows( RifTextDataTableFormatter& formatter, const std::vector formatter.add( row.distanceStart ); formatter.add( row.distanceEnd ); + if ( exportSegmentNumbers ) + { + for ( int item = 0; item < compsegsItemsBeforeSegmentNumber; ++item ) + { + formatter.add( formatter.defaultMarker() ); + } + + if ( row.segmentNumber ) + formatter.add( *row.segmentNumber ); + else + formatter.add( formatter.defaultMarker() ); + } + formatter.rowCompleted(); } } @@ -193,33 +223,24 @@ void formatWsegsicdRows( RifTextDataTableFormatter& formatter, const std::vector //-------------------------------------------------------------------------------------------------- /// Helper function to create COMPSEGS headers //-------------------------------------------------------------------------------------------------- -std::vector createCompsegsHeader( bool isLgrData ) +std::vector createCompsegsHeader( bool isLgrData, bool exportSegmentNumbers ) { - if ( isLgrData ) + std::vector header; + if ( isLgrData ) header.emplace_back( "Grid" ); + + for ( const auto* title : { "I", "J", "K", "Branch no", "Start Length", "End Length" } ) { - 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" ) }; + header.emplace_back( title ); } - else + + // Short titles for the defaulted items keep the rows with ISEG within the max data row width + const auto trailingTitles = exportSegmentNumbers ? std::vector{ "Dir", "End", "Depth", "Therm", "ISEG" } + : std::vector{ "Dir Pen", "End Range", "Connection Depth" }; + for ( const auto& title : trailingTitles ) { - 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" ) }; + header.emplace_back( title ); } + return header; } //-------------------------------------------------------------------------------------------------- @@ -418,7 +439,7 @@ void RigMswDataFormatter::formatCompsegsTable( RifTextDataTableFormatter& format formatter.rowCompleted(); } - auto header = createCompsegsHeader( isLgrData ); + auto header = createCompsegsHeader( isLgrData, hasSegmentNumbers( rows ) ); formatter.header( header ); formatCompsegsRows( formatter, rows, isLgrData ); diff --git a/ApplicationLibCode/ReservoirDataModel/CompletionsMsw/RigMswTableRows.h b/ApplicationLibCode/ReservoirDataModel/CompletionsMsw/RigMswTableRows.h index 2d6dad347b..547a71fdbf 100644 --- a/ApplicationLibCode/ReservoirDataModel/CompletionsMsw/RigMswTableRows.h +++ b/ApplicationLibCode/ReservoirDataModel/CompletionsMsw/RigMswTableRows.h @@ -84,6 +84,8 @@ struct CompsegsRow std::string gridName; // Empty for main grid, populated for LGR data + std::optional segmentNumber; // ISEG, written only if set + bool isMainGrid() const { return gridName.empty(); } bool isLgrGrid() const { return !gridName.empty(); } };