diff --git a/ApplicationLibCode/Commands/CompletionCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/CompletionCommands/CMakeLists_files.cmake index fe25a31b91..e1fdfbe6ff 100644 --- a/ApplicationLibCode/Commands/CompletionCommands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/CompletionCommands/CMakeLists_files.cmake @@ -10,7 +10,6 @@ ${CMAKE_CURRENT_LIST_DIR}/RicNewValveFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewValveTemplateFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewValveAtMeasuredDepthFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicDeleteValveTemplateFeature.h -${CMAKE_CURRENT_LIST_DIR}/RicWellPathImportCompletionsFileFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathImportPerforationIntervalsFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewStimPlanModelPlotFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicImportEnsembleFractureStatisticsFeature.h @@ -27,7 +26,6 @@ ${CMAKE_CURRENT_LIST_DIR}/RicNewValveFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewValveTemplateFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewValveAtMeasuredDepthFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicDeleteValveTemplateFeature.cpp -${CMAKE_CURRENT_LIST_DIR}/RicWellPathImportCompletionsFileFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathImportPerforationIntervalsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewStimPlanModelPlotFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicImportEnsembleFractureStatisticsFeature.cpp diff --git a/ApplicationLibCode/Commands/CompletionCommands/RicNewFishbonesSubsFeature.cpp b/ApplicationLibCode/Commands/CompletionCommands/RicNewFishbonesSubsFeature.cpp index 77255a5e80..15c4aa7798 100644 --- a/ApplicationLibCode/Commands/CompletionCommands/RicNewFishbonesSubsFeature.cpp +++ b/ApplicationLibCode/Commands/CompletionCommands/RicNewFishbonesSubsFeature.cpp @@ -27,7 +27,6 @@ #include "Rim3dView.h" #include "RimFishbones.h" #include "RimFishbonesCollection.h" -#include "RimImportedFishboneLateralsCollection.h" #include "RimProject.h" #include "RimWellPathCollection.h" #include "RimWellPathCompletions.h" diff --git a/ApplicationLibCode/Commands/CompletionCommands/RicWellPathImportCompletionsFileFeature.cpp b/ApplicationLibCode/Commands/CompletionCommands/RicWellPathImportCompletionsFileFeature.cpp deleted file mode 100644 index adaea708b5..0000000000 --- a/ApplicationLibCode/Commands/CompletionCommands/RicWellPathImportCompletionsFileFeature.cpp +++ /dev/null @@ -1,128 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2017 Statoil 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RicWellPathImportCompletionsFileFeature.h" - -#include "RiaApplication.h" - -#include "RimFishbonesCollection.h" -#include "RimImportedFishboneLateralsCollection.h" -#include "RimProject.h" -#include "RimWellPath.h" -#include "RimWellPathCollection.h" -#include "RimWellPathCompletions.h" - -#include "Riu3DMainWindowTools.h" -#include "RiuFileDialogTools.h" - -#include "cafSelectionManager.h" - -#include -#include - -CAF_CMD_SOURCE_INIT( RicWellPathImportCompletionsFileFeature, "RicWellPathImportCompletionsFileFeature" ); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicWellPathImportCompletionsFileFeature::isCommandEnabled() -{ - if ( RicWellPathImportCompletionsFileFeature::selectedWellPathCollection() != nullptr ) - { - return true; - } - - return false; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathImportCompletionsFileFeature::onActionTriggered( bool isChecked ) -{ - RimImportedFishboneLateralsCollection* fishbonesWellPathCollection = - RicWellPathImportCompletionsFileFeature::selectedWellPathCollection(); - CVF_ASSERT( fishbonesWellPathCollection ); - - // Open dialog box to select well path files - RiaApplication* app = RiaApplication::instance(); - QString defaultDir = app->lastUsedDialogDirectory( "WELLPATH_DIR" ); - QStringList wellPathFilePaths = RiuFileDialogTools::getOpenFileNames( Riu3DMainWindowTools::mainWindowWidget(), - "Import Fishbone Laterals", - defaultDir, - "Well Path Laterals (*.json *.asc *.asci " - "*.ascii *.dev);;All Files (*.*)" ); - - if ( wellPathFilePaths.size() < 1 ) return; - - // Remember the path to next time - app->setLastUsedDialogDirectory( "WELLPATH_DIR", QFileInfo( wellPathFilePaths.last() ).absolutePath() ); - - fishbonesWellPathCollection->importCompletionsFromFile( wellPathFilePaths ); - - RimWellPathCollection* wellPathCollection; - fishbonesWellPathCollection->firstAncestorOrThisOfType( wellPathCollection ); - if ( wellPathCollection ) - { - wellPathCollection->updateConnectedEditors(); - } - - if ( app->project() ) - { - app->project()->scheduleCreateDisplayModelAndRedrawAllViews(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathImportCompletionsFileFeature::setupActionLook( QAction* actionToSetup ) -{ - actionToSetup->setText( "Import Fishbone Laterals" ); - actionToSetup->setIcon( QIcon( ":/FishBoneGroupFromFile16x16.png" ) ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimImportedFishboneLateralsCollection* RicWellPathImportCompletionsFileFeature::selectedWellPathCollection() -{ - RimFishbonesCollection* objToFind = nullptr; - caf::PdmUiItem* pdmUiItem = caf::SelectionManager::instance()->selectedItem(); - caf::PdmObjectHandle* objHandle = dynamic_cast( pdmUiItem ); - if ( objHandle ) - { - objHandle->firstAncestorOrThisOfType( objToFind ); - } - - if ( objToFind == nullptr ) - { - std::vector wellPaths; - caf::SelectionManager::instance()->objectsByType( &wellPaths ); - if ( !wellPaths.empty() ) - { - return wellPaths[0]->fishbonesCollection()->wellPathCollection(); - } - } - else - { - return objToFind->wellPathCollection(); - } - - return nullptr; -} diff --git a/ApplicationLibCode/Commands/CompletionCommands/RicWellPathImportCompletionsFileFeature.h b/ApplicationLibCode/Commands/CompletionCommands/RicWellPathImportCompletionsFileFeature.h deleted file mode 100644 index f52a9870fe..0000000000 --- a/ApplicationLibCode/Commands/CompletionCommands/RicWellPathImportCompletionsFileFeature.h +++ /dev/null @@ -1,40 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2017 Statoil 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "cafCmdFeature.h" - -class RimImportedFishboneLateralsCollection; - -//================================================================================================== -/// -//================================================================================================== -class RicWellPathImportCompletionsFileFeature : public caf::CmdFeature -{ - CAF_CMD_HEADER_INIT; - -protected: - // Overrides - bool isCommandEnabled() override; - void onActionTriggered( bool isChecked ) override; - void setupActionLook( QAction* actionToSetup ) override; - -private: - static RimImportedFishboneLateralsCollection* selectedWellPathCollection(); -}; diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/CompletionExportCommands/CMakeLists_files.cmake index 6d4e6f8844..0ca9d8905a 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/CompletionExportCommands/CMakeLists_files.cmake @@ -21,6 +21,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicMswValveAccumulators.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureTextReportFeatureImpl.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureReportItem.h ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForTemporaryLgrsFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicMswTableFormatterTools.h ) @@ -46,6 +47,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicMswValveAccumulators.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureTextReportFeatureImpl.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureReportItem.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForTemporaryLgrsFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicMswTableFormatterTools.cpp ) list(APPEND COMMAND_CODE_HEADER_FILES diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.cpp index c2f9ae8020..35f3a7b00e 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.cpp @@ -83,7 +83,7 @@ RicExportCompletionDataSettingsUi::RicExportCompletionDataSettingsUi() CAF_PDM_InitField( &timeStep, "TimeStepIndex", 0, " Time Step", "", "", "" ); - CAF_PDM_InitField( &includeMsw, "IncludeMSW", true, "Include Multi Segment Well Model", "", "", "" ); + CAF_PDM_InitField( &includeMsw, "IncludeMSW", true, "Multi Segment Well Model", "", "", "" ); CAF_PDM_InitField( &useLateralNTG, "UseLateralNTG", false, "Use NTG Horizontally", "", "", "" ); @@ -112,16 +112,17 @@ RicExportCompletionDataSettingsUi::RicExportCompletionDataSettingsUi() "", "" ); - CAF_PDM_InitField( &m_exportDataSourceAsComment, - "ExportDataSourceAsComment", - true, - "Export Data Source In Comment", + CAF_PDM_InitField( &m_exportDataSourceAsComment, "ExportDataSourceAsComment", true, "Comment", "", "", "" ); + + CAF_PDM_InitField( &m_exportWelspec, "ExportWelspec", true, "WELSPEC keyword", "", "", "" ); + CAF_PDM_InitField( &m_completionWelspecAfterMainBore, + "CompletionWelspecAfterMainBore", + false, + "WELSEGS per Completion Type", "", "", "" ); - CAF_PDM_InitField( &m_exportWelspec, "ExportWelspec", true, "Export WELSPEC keyword", "", "", "" ); - m_displayForSimWell = true; m_fracturesEnabled = true; @@ -217,6 +218,14 @@ bool RicExportCompletionDataSettingsUi::exportWelspec() const return m_exportWelspec; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicExportCompletionDataSettingsUi::exportCompletionWelspecAfterMainBore() const +{ + return m_completionWelspecAfterMainBore(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -329,9 +338,10 @@ void RicExportCompletionDataSettingsUi::defineUiOrdering( QString uiConfigName, group->add( &compdatExport ); group->add( &caseToApply ); group->add( &useLateralNTG ); - group->add( &includeMsw ); group->add( &m_exportDataSourceAsComment ); group->add( &m_exportWelspec ); + group->add( &includeMsw ); + group->add( &m_completionWelspecAfterMainBore ); } { diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.h b/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.h index 32f0c276e5..973cd9b152 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.h +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.h @@ -98,6 +98,7 @@ public: bool reportCompletionsTypesIndividually() const; bool exportDataSourceAsComment() const; bool exportWelspec() const; + bool exportCompletionWelspecAfterMainBore() const; void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; @@ -112,6 +113,7 @@ private: caf::PdmField m_reportCompletionTypesSeparately; caf::PdmField m_exportDataSourceAsComment; caf::PdmField m_exportWelspec; + caf::PdmField m_completionWelspecAfterMainBore; bool m_displayForSimWell; bool m_fracturesEnabled; diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp index 538d376a53..dfdf372fac 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp @@ -32,7 +32,6 @@ #include "RimEclipseCase.h" #include "RimFishbones.h" #include "RimFishbonesCollection.h" -#include "RimImportedFishboneLateralsCollection.h" #include "RimPerforationCollection.h" #include "RimProject.h" #include "RimWellPath.h" diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp index 152a3e4620..cba403253a 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp @@ -30,14 +30,12 @@ #include "RigCompletionData.h" #include "RigEclipseCaseData.h" #include "RigMainGrid.h" +#include "RigWellLogExtractor.h" #include "RigWellPath.h" #include "RigWellPathIntersectionTools.h" -#include "RigWellLogExtractor.h" #include "RimFishbones.h" #include "RimFishbonesCollection.h" -#include "RimImportedFishboneLaterals.h" -#include "RimImportedFishboneLateralsCollection.h" #include "RimWellPath.h" #include "RimWellPathCompletions.h" @@ -98,7 +96,6 @@ std::vector std::map> wellBorePartsInCells; // wellBore = main bore or fishbone // lateral findFishboneLateralsWellBoreParts( wellBorePartsInCells, wellPath, settings ); - findFishboneImportedLateralsWellBoreParts( wellBorePartsInCells, wellPath, settings ); const RigActiveCellInfo* activeCellInfo = settings.caseToApply->eclipseCaseData()->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL ); @@ -221,40 +218,44 @@ void RicFishbonesTransmissibilityCalculationFeatureImp::findFishboneLateralsWell exportInfo.setLinerDiameter( mswParameters->linerDiameter( unitSystem ) ); exportInfo.setRoughnessFactor( mswParameters->roughnessFactor( unitSystem ) ); - RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( settings.caseToApply(), - wellPath, - 0.0, - {}, - false, - &exportInfo, - exportInfo.mainBoreBranch() ); + RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfoForWell( settings.caseToApply(), + wellPath, + &exportInfo, + exportInfo.mainBoreBranch() ); bool isMainBore = false; - for ( auto segment : exportInfo.mainBoreBranch()->segments() ) + for ( auto mainBoreSegment : exportInfo.mainBoreBranch()->segments() ) { - for ( auto completion : segment->completions() ) + for ( auto mainBoreCompletion : mainBoreSegment->completions() ) { - for ( auto completionSegment : completion->segments() ) + for ( auto completionSegment : mainBoreCompletion->segments() ) { - for ( std::shared_ptr intersection : completionSegment->intersections() ) + for ( auto completion : completionSegment->completions() ) { - double diameter = segment->holeDiameter(); - QString completionMetaData = - ( segment->label() + - QString( ": Sub: %1 Lateral: %2" ).arg( segment->subIndex() ).arg( completion->index() ) ); + for ( auto segment : completion->segments() ) + { + for ( auto intersection : segment->intersections() ) + { + double diameter = segment->holeDiameter(); + QString completionMetaData = ( segment->label() + QString( ": Sub: %1 Lateral: %2" ) + .arg( segment->subIndex() + 1 ) + .arg( completion->index() + 1 ) ); - WellBorePartForTransCalc wellBorePart = WellBorePartForTransCalc( intersection->lengthsInCell(), - diameter / 2.0, - segment->skinFactor(), - isMainBore, - completionMetaData ); + WellBorePartForTransCalc wellBorePart = + WellBorePartForTransCalc( intersection->lengthsInCell(), + diameter / 2.0, + segment->skinFactor(), + isMainBore, + completionMetaData ); - wellBorePart.intersectionWithWellMeasuredDepth = segment->endMD(); - wellBorePart.lateralIndex = completion->index(); - wellBorePart.setSourcePdmObject( segment->sourcePdmObject() ); + wellBorePart.intersectionWithWellMeasuredDepth = segment->endMD(); + wellBorePart.lateralIndex = completion->index(); + wellBorePart.setSourcePdmObject( segment->sourcePdmObject() ); - wellBorePartsInCells[intersection->globalCellIndex()].push_back( wellBorePart ); + wellBorePartsInCells[intersection->globalCellIndex()].push_back( wellBorePart ); + } + } } } } @@ -262,8 +263,8 @@ void RicFishbonesTransmissibilityCalculationFeatureImp::findFishboneLateralsWell { // Note that it is not supported to export main bore perforation intervals for Imported Laterals, only for - // fishbones defined by ResInsight. It is not trivial to define the open section of the main bore for imported - // laterals. + // fishbones defined by ResInsight. It is not trivial to define the open section of the main bore for + // imported laterals. if ( wellPath->fishbonesCollection()->isChecked() ) { @@ -295,56 +296,6 @@ void RicFishbonesTransmissibilityCalculationFeatureImp::findFishboneLateralsWell } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicFishbonesTransmissibilityCalculationFeatureImp::findFishboneImportedLateralsWellBoreParts( - std::map>& wellBorePartsInCells, - const RimWellPath* wellPath, - const RicExportCompletionDataSettingsUi& settings ) -{ - RiaDefines::EclipseUnitSystem unitSystem = settings.caseToApply->eclipseCaseData()->unitsType(); - - if ( !wellPath ) return; - if ( !wellPath->wellPathGeometry() ) return; - - bool isMainBore = false; - double holeRadius = wellPath->fishbonesCollection()->wellPathCollection()->holeDiameter( unitSystem ) / 2.0; - double skinFactor = wellPath->fishbonesCollection()->wellPathCollection()->skinFactor(); - - for ( const RimImportedFishboneLaterals* fishbonesPath : - wellPath->fishbonesCollection()->wellPathCollection()->wellPaths() ) - { - if ( !fishbonesPath->isChecked() ) - { - continue; - } - - std::vector intersectedCells = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( settings.caseToApply->eclipseCaseData(), - wellPath->name(), - fishbonesPath->coordinates(), - fishbonesPath->measuredDepths() ); - - for ( const auto& cellIntersectionInfo : intersectedCells ) - { - QString completionMetaData = fishbonesPath->name(); - WellBorePartForTransCalc wellBorePart = - WellBorePartForTransCalc( cellIntersectionInfo.intersectionLengthsInCellCS, - holeRadius, - skinFactor, - isMainBore, - completionMetaData ); - wellBorePart.intersectionWithWellMeasuredDepth = cellIntersectionInfo.startMD; - - wellBorePartsInCells[cellIntersectionInfo.globCellIndex].push_back( wellBorePart ); - } - } - - // Note that it is not supported to export main bore perforation intervals for Imported Laterals, only for fishbones - // defined by ResInsight -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.h b/ApplicationLibCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.h index 05d55ec8ca..5d1f56e9cb 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.h +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.h @@ -48,11 +48,6 @@ private: const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings ); - static void - findFishboneImportedLateralsWellBoreParts( std::map>& wellBorePartsInCells, - const RimWellPath* wellPath, - const RicExportCompletionDataSettingsUi& settings ); - static void appendMainWellBoreParts( std::map>& wellBorePartsInCells, const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings, diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.cpp index 722261458c..1350a58540 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.cpp @@ -1,3 +1,21 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021- 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + #include "RicMswBranch.h" #include "RicMswCompletions.h" @@ -139,6 +157,39 @@ std::vector RicMswBranch::segments() return allSegments; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswSegment* RicMswBranch::findClosestSegmentByMidpoint( double measuredDepthLocation ) +{ + if ( measuredDepthLocation < startMD() ) + { + return segmentCount() > 0 ? segments().front() : nullptr; + } + + if ( measuredDepthLocation > endMD() ) + { + return segmentCount() > 0 ? segments().back() : nullptr; + } + + RicMswSegment* closestSegment = nullptr; + double smallestDistance = std::numeric_limits::infinity(); + + for ( auto seg : segments() ) + { + double midpointMD = 0.5 * ( seg->startMD() + seg->endMD() ); + + double candidateDistance = std::abs( midpointMD - measuredDepthLocation ); + if ( candidateDistance < smallestDistance ) + { + closestSegment = seg; + smallestDistance = candidateDistance; + } + } + + return closestSegment; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.h b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.h index 4fddc9e7e7..4fd464835f 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.h +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.h @@ -53,6 +53,8 @@ public: std::vector segments() const; std::vector segments(); + RicMswSegment* findClosestSegmentByMidpoint( double measuredDepth ); + size_t segmentCount() const; std::vector branches() const; diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswCompletions.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswCompletions.cpp index 9274d92593..5936f47092 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswCompletions.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswCompletions.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Equinor ASA +// Copyright (C) 2021- 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 @@ -18,9 +18,11 @@ #include "RicMswCompletions.h" +#include "RiaLogging.h" #include "RicMswSegmentCellIntersection.h" - +#include "RimWellPath.h" #include "RimWellPathValve.h" + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -123,30 +125,22 @@ void RicMswValve::setIsValid( bool valid ) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::unique_ptr RicMswValve::createExportValve( const QString& label, - const RimWellPath* wellPath, - double startMD, - double startTVD, - const RimWellPathValve* wellPathValve ) +std::unique_ptr RicMswValve::createTieInValve( const QString& label, + const RimWellPath* wellPath, + double startMD, + double startTVD, + const RimWellPathValve* wellPathValve ) { - std::unique_ptr outletValve; - if ( wellPathValve->componentType() == RiaDefines::WellPathComponentType::ICD ) + if ( wellPathValve->componentType() != RiaDefines::WellPathComponentType::ICV ) { - outletValve = std::make_unique( label, wellPath, startMD, startTVD, wellPathValve ); + RiaLogging::error( "MSW export: The outlet valve must be of type ICV" ); + return nullptr; } - else if ( wellPathValve->componentType() == RiaDefines::WellPathComponentType::ICV ) - { - outletValve = std::make_unique( label, wellPath, startMD, startTVD, wellPathValve ); - } - else if ( wellPathValve->componentType() == RiaDefines::WellPathComponentType::AICD ) - { - outletValve = std::make_unique( label, wellPath, startMD, startTVD, wellPathValve ); - } - else - { - CAF_ASSERT( false && "Valve needs to be either an ICD, ICVF or AICD" ); - } - return outletValve; + + std::unique_ptr tieInValve = + std::make_unique( label, wellPath, startMD, startTVD, wellPathValve ); + + return tieInValve; } //-------------------------------------------------------------------------------------------------- @@ -247,6 +241,10 @@ RicMswPerforationICV::RicMswPerforationICV( const QString& label, : RicMswWsegValve( label, wellPath, startMD, startTVD, wellPathValve ) { setIsValid( true ); + + setFlowCoefficient( wellPathValve->flowCoefficient() ); + double orificeRadius = wellPathValve->orificeDiameter( wellPath->unitSystem() ) / 2; + setArea( orificeRadius * orificeRadius * cvf::PI_D ); } //------------------------------------------------------------------- @@ -270,6 +268,7 @@ RicMswPerforationAICD::RicMswPerforationAICD( const QString& label, , m_length( 0.0 ) , m_flowScalingFactor( 0.0 ) { + m_parameters.fill( std::numeric_limits::infinity() ); } //-------------------------------------------------------------------------------------------------- @@ -343,3 +342,28 @@ std::array& RicMswPerforationAICD::values() { return m_parameters; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswTieInICV::RicMswTieInICV( const QString& label, + const RimWellPath* wellPath, + double startMD, + double startTVD, + const RimWellPathValve* wellPathValve ) + : RicMswWsegValve( label, wellPath, startMD, startTVD, wellPathValve ) +{ + setIsValid( true ); + + setFlowCoefficient( wellPathValve->flowCoefficient() ); + double orificeRadius = wellPathValve->orificeDiameter( wellPath->unitSystem() ) / 2; + setArea( orificeRadius * orificeRadius * cvf::PI_D ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCompletionData::CompletionType RicMswTieInICV::completionType() const +{ + return RigCompletionData::PERFORATION_ICV; +} diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswCompletions.h b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswCompletions.h index 5a5fc36e9c..42d44ac51e 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswCompletions.h +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswCompletions.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Equinor ASA +// Copyright (C) 2021- 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 @@ -15,6 +15,7 @@ // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #pragma once #include "RicMswBranch.h" @@ -26,6 +27,7 @@ #include "cvfMath.h" #include + #include class RimWellPathValve; @@ -49,6 +51,9 @@ private: size_t m_index; }; +//================================================================================================== +/// +//================================================================================================== class RicMswFishbones : public RicMswCompletion { public: @@ -111,11 +116,11 @@ public: bool isValid() const; void setIsValid( bool valid ); - static std::unique_ptr createExportValve( const QString& label, - const RimWellPath* wellPath, - double startMD, - double startTVD, - const RimWellPathValve* wellPathValve ); + static std::unique_ptr createTieInValve( const QString& label, + const RimWellPath* wellPath, + double startMD, + double startTVD, + const RimWellPathValve* wellPathValve ); private: bool m_valid; @@ -186,6 +191,22 @@ public: RigCompletionData::CompletionType completionType() const override; }; +//================================================================================================== +// This object is representing the optional tie-in valve used to limit the inflow from a branch +// into the parent branch +// ICV valve is the only supported valve for this MSW item +//================================================================================================== +class RicMswTieInICV : public RicMswWsegValve +{ +public: + RicMswTieInICV( const QString& label, + const RimWellPath* wellPath, + double startMD, + double startTVD, + const RimWellPathValve* wellPathValve ); + RigCompletionData::CompletionType completionType() const override; +}; + //================================================================================================== /// //================================================================================================== diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswItem.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswItem.cpp index e7d5b03292..9b9260880d 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswItem.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswItem.cpp @@ -1,3 +1,21 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021- 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + #include "RicMswItem.h" //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.cpp index c14dd7b9f0..69caa0e069 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.cpp @@ -40,7 +40,7 @@ RicMswSegment::RicMswSegment( const QString& label, , m_endTVD( endTVD ) , m_outputMD( 0.0 ) , m_outputTVD( 0.0 ) - , m_effectiveDiameter( 0.15 ) + , m_equivalentDiameter( 0.15 ) , m_holeDiameter( RicMswExportInfo::defaultDoubleValue() ) , m_openHoleRoughnessFactor( 5.0e-5 ) , m_skinFactor( RicMswExportInfo::defaultDoubleValue() ) @@ -116,9 +116,9 @@ double RicMswSegment::outputTVD() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double RicMswSegment::effectiveDiameter() const +double RicMswSegment::equivalentDiameter() const { - return m_effectiveDiameter; + return m_equivalentDiameter; } //-------------------------------------------------------------------------------------------------- @@ -198,9 +198,9 @@ void RicMswSegment::setLabel( const QString& label ) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicMswSegment::setEffectiveDiameter( double effectiveDiameter ) +void RicMswSegment::setEquivalentDiameter( double effectiveDiameter ) { - m_effectiveDiameter = effectiveDiameter; + m_equivalentDiameter = effectiveDiameter; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.h b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.h index c666b2633d..4ce7ca9515 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.h +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.h @@ -53,7 +53,7 @@ public: void setOutputTVD( double outputTVD ); double outputTVD() const; - double effectiveDiameter() const; + double equivalentDiameter() const; double holeDiameter() const; double openHoleRoughnessFactor() const; double skinFactor() const; @@ -65,7 +65,7 @@ public: std::vector completions(); void setLabel( const QString& label ); - void setEffectiveDiameter( double effectiveDiameter ); + void setEquivalentDiameter( double diameter ); void setHoleDiameter( double holeDiameter ); void setOpenHoleRoughnessFactor( double roughnessFactor ); void setSkinFactor( double skinFactor ); @@ -88,10 +88,10 @@ private: double m_startTVD; double m_endTVD; - double m_outputMD; - double m_outputTVD; + double m_outputMD; + double m_outputTVD; - double m_effectiveDiameter; + double m_equivalentDiameter; double m_holeDiameter; double m_openHoleRoughnessFactor; double m_skinFactor; diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableFormatterTools.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableFormatterTools.cpp new file mode 100644 index 0000000000..7e3d17990d --- /dev/null +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableFormatterTools.cpp @@ -0,0 +1,998 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicMswTableFormatterTools.h" + +#include "RiaLogging.h" + +#include "RicMswCompletions.h" +#include "RicMswExportInfo.h" + +#include "RifTextDataTableFormatter.h" + +#include "RigWellPath.h" + +#include "RimWellPath.h" // TODO: Consider adding wellnameforexport to RicMswExportInfo to avoid these includes +#include "RimWellPathCompletionSettings.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::generateWelsegsTable( RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + bool exportCompletionSegmentsAfterMainBore ) +{ + formatter.keyword( "WELSEGS" ); + + double startMD = exportInfo.mainBoreBranch()->startMD(); + double startTVD = exportInfo.mainBoreBranch()->startTVD(); + + { + std::vector header = { + RifTextDataTableColumn( "Name" ), + RifTextDataTableColumn( "Dep 1" ), + RifTextDataTableColumn( "Tlen 1" ), + RifTextDataTableColumn( "Vol 1" ), + RifTextDataTableColumn( "Len&Dep" ), + RifTextDataTableColumn( "PresDrop" ), + }; + formatter.header( header ); + + formatter.add( exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport() ); + formatter.add( startTVD ); + formatter.add( startMD ); + formatter.addValueOrDefaultMarker( exportInfo.topWellBoreVolume(), RicMswExportInfo::defaultDoubleValue() ); + formatter.add( exportInfo.lengthAndDepthText() ); + formatter.add( QString( "'%1'" ).arg( exportInfo.pressureDropText() ) ); + + formatter.rowCompleted(); + } + + { + std::vector header = + { RifTextDataTableColumn( "First Seg" ), + RifTextDataTableColumn( "Last Seg" ), + RifTextDataTableColumn( "Branch Num" ), + RifTextDataTableColumn( "Outlet Seg" ), + RifTextDataTableColumn( "Length" ), + RifTextDataTableColumn( "Depth Change" ), + RifTextDataTableColumn( "Diam" ), + RifTextDataTableColumn( "Rough", RifTextDataTableDoubleFormatting( RIF_FLOAT, 7 ) ) }; + formatter.header( header ); + } + + int segmentNumber = 2; // There's an implicit segment number 1. + + RicMswSegment* parentSegment = nullptr; + writeWelsegsSegmentsRecursively( formatter, + exportInfo, + exportInfo.mainBoreBranch(), + &segmentNumber, + maxSegmentLength, + exportCompletionSegmentsAfterMainBore, + parentSegment ); + + formatter.tableCompleted(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::writeWelsegsSegmentsRecursively( RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + gsl::not_null branch, + gsl::not_null segmentNumber, + double maxSegmentLength, + bool exportCompletionSegmentsAfterMainBore, + RicMswSegment* connectedToSegment ) +{ + auto outletSegment = connectedToSegment; + + RicMswValve* outletValve = nullptr; + + auto branchSegments = branch->segments(); + auto it = branchSegments.begin(); + if ( outletValve = dynamic_cast( branch.get() ); outletValve != nullptr ) + { + writeValveWelsegsSegment( outletSegment, outletValve, formatter, exportInfo, maxSegmentLength, segmentNumber ); + + auto valveSegments = outletValve->segments(); + outletSegment = valveSegments.front(); + + *segmentNumber = outletSegment->segmentNumber() + 1; + ++it; // skip segment below + } + + formatter.addOptionalComment( QString( "Segments on branch %1" ).arg( branch->label() ) ); + + auto branchStartSegmentIterator = it; + for ( ; it != branchSegments.end(); ++it ) + { + auto segment = *it; + segment->setSegmentNumber( *segmentNumber ); + + if ( segment->subIndex() != cvf::UNDEFINED_SIZE_T ) + { + QString comment = segment->label() + QString( ", sub %1" ).arg( segment->subIndex() + 1 ); + formatter.addOptionalComment( comment ); + } + + writeWelsegsSegment( segment, outletSegment, formatter, exportInfo, maxSegmentLength, branch, segmentNumber ); + outletSegment = segment; + + if ( !exportCompletionSegmentsAfterMainBore ) + { + writeCompletionsForSegment( outletSegment, segment, &outletValve, formatter, exportInfo, maxSegmentLength, segmentNumber ); + } + } + + if ( exportCompletionSegmentsAfterMainBore ) + { + it = branchStartSegmentIterator; + + for ( ; it != branchSegments.end(); ++it ) + { + auto segment = *it; + + writeCompletionsForSegment( outletSegment, segment, &outletValve, formatter, exportInfo, maxSegmentLength, segmentNumber ); + } + } + + for ( auto childBranch : branch->branches() ) + { + RicMswSegment* outletSegmentForChildBranch = outletSegment; + + RicMswSegment* tieInSegmentOnParentBranch = branch->findClosestSegmentByMidpoint( childBranch->startMD() ); + if ( tieInSegmentOnParentBranch ) outletSegmentForChildBranch = tieInSegmentOnParentBranch; + + writeWelsegsSegmentsRecursively( formatter, + exportInfo, + childBranch, + segmentNumber, + maxSegmentLength, + exportCompletionSegmentsAfterMainBore, + outletSegmentForChildBranch ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::writeWelsegsCompletionCommentHeader( RifTextDataTableFormatter& formatter, + RigCompletionData::CompletionType completionType ) +{ + QString optionalCommentText; + + switch ( completionType ) + { + case RigCompletionData::FISHBONES: + break; + case RigCompletionData::FRACTURE: + optionalCommentText = "Fracture Segments"; + break; + case RigCompletionData::PERFORATION: + optionalCommentText = "Perforation Segments"; + break; + case RigCompletionData::FISHBONES_ICD: + optionalCommentText = "Fishbones Segments - ICD"; + break; + case RigCompletionData::PERFORATION_ICD: + optionalCommentText = "Perforation Segments - ICD"; + break; + case RigCompletionData::PERFORATION_AICD: + optionalCommentText = "Perforation Segments - AICD"; + break; + case RigCompletionData::PERFORATION_ICV: + optionalCommentText = "Perforation Segments - ICV"; + break; + case RigCompletionData::CT_UNDEFINED: + optionalCommentText = "Main Stem"; + break; + default: + break; + } + + if ( !optionalCommentText.isEmpty() ) + { + formatter.addOptionalComment( optionalCommentText ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::generateCompsegTables( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ) +{ + /* + * TODO: Creating the regular perforation COMPSEGS table should come in here, before the others + * should take precedence by appearing later in the output. See #3230. + */ + + std::set intersectedCells; + + { + std::set perforationTypes = { RigCompletionData::PERFORATION, + RigCompletionData::PERFORATION_ICD, + RigCompletionData::PERFORATION_ICV, + RigCompletionData::PERFORATION_AICD }; + + { + bool headerGenerated = false; + generateCompsegTable( formatter, + exportInfo, + exportInfo.mainBoreBranch(), + false, + perforationTypes, + &headerGenerated, + &intersectedCells ); + + if ( headerGenerated ) formatter.tableCompleted(); + } + + if ( exportInfo.hasSubGridIntersections() ) + { + bool headerGenerated = false; + generateCompsegTable( formatter, + exportInfo, + exportInfo.mainBoreBranch(), + true, + perforationTypes, + &headerGenerated, + &intersectedCells ); + if ( headerGenerated ) formatter.tableCompleted(); + } + } + + { + std::set fishbonesTypes = { RigCompletionData::FISHBONES_ICD, + RigCompletionData::FISHBONES }; + { + bool headerGenerated = false; + generateCompsegTable( formatter, + exportInfo, + exportInfo.mainBoreBranch(), + false, + fishbonesTypes, + &headerGenerated, + &intersectedCells ); + if ( headerGenerated ) formatter.tableCompleted(); + } + if ( exportInfo.hasSubGridIntersections() ) + { + bool headerGenerated = false; + generateCompsegTable( formatter, + exportInfo, + exportInfo.mainBoreBranch(), + true, + fishbonesTypes, + &headerGenerated, + &intersectedCells ); + if ( headerGenerated ) formatter.tableCompleted(); + } + } + + { + std::set fractureTypes = { RigCompletionData::FRACTURE }; + + { + bool headerGenerated = false; + generateCompsegTable( formatter, + exportInfo, + exportInfo.mainBoreBranch(), + false, + fractureTypes, + &headerGenerated, + &intersectedCells ); + if ( headerGenerated ) formatter.tableCompleted(); + } + + if ( exportInfo.hasSubGridIntersections() ) + { + bool headerGenerated = false; + generateCompsegTable( formatter, + exportInfo, + exportInfo.mainBoreBranch(), + true, + fractureTypes, + &headerGenerated, + &intersectedCells ); + if ( headerGenerated ) formatter.tableCompleted(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::generateCompsegTable( RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + gsl::not_null branch, + bool exportSubGridIntersections, + const std::set& exportCompletionTypes, + gsl::not_null headerGenerated, + gsl::not_null*> intersectedCells ) +{ + for ( auto segment : branch->segments() ) + { + auto completion = dynamic_cast( 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::PERFORATION_ICD || + completion->completionType() == RigCompletionData::PERFORATION_AICD || + completion->completionType() == RigCompletionData::PERFORATION_ICV; + + if ( isPerforationValve ) + { + startLength = segment->startMD(); + endLength = segment->endMD(); + } + } + + size_t globalCellIndex = intersection->globalCellIndex(); + + // Here we 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 ) ) + { + if ( exportSubGridIntersections ) + { + formatter.add( intersection->gridName() ); + } + + cvf::Vec3st ijk = intersection->gridLocalCellIJK(); + formatter.addOneBasedCellIndex( ijk.x() ).addOneBasedCellIndex( ijk.y() ).addOneBasedCellIndex( ijk.z() ); + + int branchNumber = -1; + if ( completion ) branchNumber = completion->branchNumber(); + formatter.add( branchNumber ); + + formatter.add( startLength ); + formatter.add( endLength ); + + formatter.rowCompleted(); + 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; + + if ( !*headerGenerated ) + { + generateCompsegHeader( formatter, exportInfo, completion->completionType(), exportSubGridIntersections ); + *headerGenerated = true; + } + + generateCompsegTable( formatter, + exportInfo, + completion, + exportSubGridIntersections, + exportCompletionTypes, + headerGenerated, + intersectedCells ); + } + } + + for ( auto childBranch : branch->branches() ) + { + generateCompsegTable( formatter, + exportInfo, + childBranch, + exportSubGridIntersections, + exportCompletionTypes, + headerGenerated, + intersectedCells ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::generateCompsegHeader( RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + RigCompletionData::CompletionType completionType, + bool exportSubGridIntersections ) +{ + if ( exportSubGridIntersections ) + { + formatter.keyword( "COMPSEGL" ); + } + else + { + formatter.keyword( "COMPSEGS" ); + } + + if ( completionType == RigCompletionData::FISHBONES_ICD ) + { + formatter.comment( "Fishbones" ); + } + else if ( completionType == RigCompletionData::FRACTURE ) + { + formatter.comment( "Fractures" ); + } + + { + std::vector header = { RifTextDataTableColumn( "Name" ) }; + formatter.header( header ); + formatter.add( exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport() ); + formatter.rowCompleted(); + } + + { + std::vector allHeaders; + if ( exportSubGridIntersections ) + { + allHeaders.push_back( RifTextDataTableColumn( "Grid" ) ); + } + + std::vector commonHeaders = { RifTextDataTableColumn( "I" ), + RifTextDataTableColumn( "J" ), + RifTextDataTableColumn( "K" ), + RifTextDataTableColumn( "Branch no" ), + RifTextDataTableColumn( "Start Length" ), + RifTextDataTableColumn( "End Length" ), + RifTextDataTableColumn( "Dir Pen" ), + RifTextDataTableColumn( "End Range" ), + RifTextDataTableColumn( "Connection Depth" ) }; + allHeaders.insert( allHeaders.end(), commonHeaders.begin(), commonHeaders.end() ); + formatter.header( allHeaders ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::generateWsegvalvTable( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ) +{ + bool foundValve = false; + + generateWsegvalvTableRecursively( formatter, + exportInfo.mainBoreBranch(), + foundValve, + exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport() ); + + if ( foundValve ) + { + formatter.tableCompleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::generateWsegvalvTableRecursively( RifTextDataTableFormatter& formatter, + gsl::not_null branch, + bool& isHeaderWritten, + const QString& wellNameForExport ) +{ + { + auto tieInValve = dynamic_cast( branch.get() ); + if ( tieInValve && !tieInValve->segments().empty() ) + { + if ( !isHeaderWritten ) + { + writeWsegvalHeader( formatter ); + + isHeaderWritten = true; + } + + auto firstSubSegment = tieInValve->segments().front(); + CAF_ASSERT( tieInValve->completionType() == RigCompletionData::PERFORATION_ICV ); + { + formatter.addOptionalComment( tieInValve->label() ); + } + formatter.add( wellNameForExport ); + formatter.add( firstSubSegment->segmentNumber() ); + formatter.add( tieInValve->flowCoefficient() ); + formatter.add( QString( "%1" ).arg( tieInValve->area(), 8, 'g', 4 ) ); + formatter.rowCompleted(); + } + } + + for ( auto segment : branch->segments() ) + { + for ( auto completion : segment->completions() ) + { + if ( RigCompletionData::isWsegValveTypes( completion->completionType() ) ) + { + if ( !isHeaderWritten ) + { + writeWsegvalHeader( formatter ); + + isHeaderWritten = true; + } + + auto wsegValve = static_cast( completion ); + if ( !wsegValve->segments().empty() ) + { + CVF_ASSERT( wsegValve->segments().size() == 1u ); + + auto firstSubSegment = wsegValve->segments().front(); + + // TODO: The following line was blocking export of valves for fishbones + // Unclear why this line was included. Remove when MSW export has ben verified correctly + // if ( !firstSubSegment->intersections().empty() ) + { + if ( wsegValve->completionType() == RigCompletionData::PERFORATION_ICD || + wsegValve->completionType() == RigCompletionData::PERFORATION_ICV ) + { + formatter.addOptionalComment( wsegValve->label() ); + } + formatter.add( wellNameForExport ); + formatter.add( firstSubSegment->segmentNumber() ); + formatter.add( wsegValve->flowCoefficient() ); + formatter.add( QString( "%1" ).arg( wsegValve->area(), 8, 'g', 4 ) ); + formatter.rowCompleted(); + } + } + } + } + } + + for ( auto childBranch : branch->branches() ) + { + generateWsegvalvTableRecursively( formatter, childBranch, isHeaderWritten, wellNameForExport ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::generateWsegAicdTable( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ) +{ + RifTextDataTableFormatter tighterFormatter( formatter ); + tighterFormatter.setColumnSpacing( 1 ); + tighterFormatter.setTableRowPrependText( " " ); + + bool foundValve = false; + + for ( auto segment : exportInfo.mainBoreBranch()->segments() ) + { + for ( auto completion : segment->completions() ) + { + if ( completion->completionType() == RigCompletionData::PERFORATION_AICD ) + { + auto aicd = static_cast( completion ); + if ( aicd->isValid() ) + { + if ( !foundValve ) + { + std::vector columnDescriptions = + { "Well Name", + "Segment Number", + "Segment Number", + "Strength of AICD", + "Flow Scaling Factor for AICD", + "Density of Calibration Fluid", + "Viscosity of Calibration Fluid", + "Critical water in liquid fraction for emulsions viscosity model", + "Emulsion viscosity transition region", + "Max ratio of emulsion viscosity to continuous phase viscosity", + "Flow scaling factor method", + "Maximum flow rate for AICD device", + "Volume flow rate exponent, x", + "Viscosity function exponent, y", + "Device OPEN/SHUT", + "Exponent of the oil flowing fraction in the density mixture calculation", + "Exponent of the water flowing fraction in the density mixture calculation", + "Exponent of the gas flowing fraction in the density mixture calculation", + "Exponent of the oil flowing fraction in the density viscosity calculation", + "Exponent of the water flowing fraction in the density viscosity calculation", + "Exponent of the gas flowing fraction in the density viscosity calculation" }; + + tighterFormatter.keyword( "WSEGAICD" ); + tighterFormatter.comment( "Column Overview:" ); + for ( size_t i = 0; i < columnDescriptions.size(); ++i ) + { + tighterFormatter.comment( + QString( "%1: %2" ).arg( i + 1, 2, 10, QChar( '0' ) ).arg( columnDescriptions[i] ) ); + } + + std::vector header; + for ( size_t i = 1; i <= 21; ++i ) + { + QString cName = QString( "%1" ).arg( i, 2, 10, QChar( '0' ) ); + RifTextDataTableColumn col( cName, + RifTextDataTableDoubleFormatting( + RifTextDataTableDoubleFormat::RIF_CONSISE ), + RIGHT ); + header.push_back( col ); + } + tighterFormatter.header( header ); + + foundValve = true; + } + if ( !aicd->segments().empty() ) + { + CVF_ASSERT( aicd->segments().size() == 1u ); + tighterFormatter.comment( aicd->label() ); + tighterFormatter.add( + exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport() ); // #1 + tighterFormatter.add( aicd->segments().front()->segmentNumber() ); + tighterFormatter.add( aicd->segments().front()->segmentNumber() ); + + std::array values = aicd->values(); + tighterFormatter.add( values[AICD_STRENGTH] ); + + tighterFormatter.add( aicd->flowScalingFactor() ); // #5 Flow scaling factor used when item + // #11 is set to '1' + + tighterFormatter.add( values[AICD_DENSITY_CALIB_FLUID] ); + tighterFormatter.add( values[AICD_VISCOSITY_CALIB_FLUID] ); + tighterFormatter.addValueOrDefaultMarker( values[AICD_CRITICAL_WATER_IN_LIQUID_FRAC], + RicMswExportInfo::defaultDoubleValue() ); + tighterFormatter.addValueOrDefaultMarker( values[AICD_EMULSION_VISC_TRANS_REGION], + RicMswExportInfo::defaultDoubleValue() ); + tighterFormatter.addValueOrDefaultMarker( values[AICD_MAX_RATIO_EMULSION_VISC], + RicMswExportInfo::defaultDoubleValue() ); // #10 + + tighterFormatter.add( 1 ); // #11 : Always use method "b. Scale factor". The value of the + // scale factor is given in item #5 + + tighterFormatter.addValueOrDefaultMarker( values[AICD_MAX_FLOW_RATE], + RicMswExportInfo::defaultDoubleValue() ); + tighterFormatter.add( values[AICD_VOL_FLOW_EXP] ); + tighterFormatter.add( values[AICD_VISOSITY_FUNC_EXP] ); + tighterFormatter.add( aicd->isOpen() ? "OPEN" : "SHUT" ); // #15 + tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_OIL_FRAC_DENSITY], + RicMswExportInfo::defaultDoubleValue() ); + tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_WATER_FRAC_DENSITY], + RicMswExportInfo::defaultDoubleValue() ); + tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_GAS_FRAC_DENSITY], + RicMswExportInfo::defaultDoubleValue() ); + tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_OIL_FRAC_VISCOSITY], + RicMswExportInfo::defaultDoubleValue() ); + tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_WATER_FRAC_VISCOSITY], + RicMswExportInfo::defaultDoubleValue() ); // #20 + tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_GAS_FRAC_VISCOSITY], + RicMswExportInfo::defaultDoubleValue() ); + tighterFormatter.rowCompleted(); + } + } + else + { + RiaLogging::error( QString( "Export AICD Valve (%1): Valve is invalid. At least one required " + "template parameter is not set." ) + .arg( aicd->label() ) ); + } + } + } + } + if ( foundValve ) + { + tighterFormatter.tableCompleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::writeWelsegsSegment( RicMswSegment* segment, + const RicMswSegment* previousSegment, + RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + gsl::not_null branch, + int* segmentNumber ) +{ + CVF_ASSERT( segment && segmentNumber ); + + double startMD = segment->startMD(); + double endMD = segment->endMD(); + + std::vector> segments = createSubSegmentMDPairs( startMD, endMD, maxSegmentLength ); + + CVF_ASSERT( branch->wellPath() ); + auto wellPathGeometry = branch->wellPath()->wellPathGeometry(); + CVF_ASSERT( wellPathGeometry ); + + double prevOutMD = branch->startMD(); + double prevOutTVD = branch->startTVD(); + if ( previousSegment ) + { + prevOutMD = previousSegment->outputMD(); + prevOutTVD = previousSegment->outputTVD(); + } + + auto outletSegment = previousSegment; + for ( const auto& [subStartMD, subEndMD] : segments ) + { + double depth = 0; + double length = 0; + + double midPointMD = 0.5 * ( subStartMD + subEndMD ); + double midPointTVD = tvdFromMeasuredDepth( branch->wellPath(), midPointMD ); + + if ( exportInfo.lengthAndDepthText() == QString( "INC" ) ) + { + depth = midPointTVD - prevOutTVD; + length = midPointMD - prevOutMD; + } + else + { + depth = midPointTVD; + length = midPointMD; + } + segment->setOutputMD( midPointMD ); + segment->setOutputTVD( midPointTVD ); + segment->setSegmentNumber( *segmentNumber ); + + formatter.add( *segmentNumber ).add( *segmentNumber ); + formatter.add( branch->branchNumber() ); + if ( outletSegment ) + formatter.add( outletSegment->segmentNumber() ); + else + formatter.add( 1 ); + formatter.add( length ); + formatter.add( depth ); + formatter.add( exportInfo.linerDiameter() ); + formatter.add( exportInfo.roughnessFactor() ); + formatter.rowCompleted(); + ( *segmentNumber )++; + outletSegment = segment; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::writeValveWelsegsSegment( const RicMswSegment* outletSegment, + RicMswValve* valve, + RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + int* segmentNumber ) +{ + CVF_ASSERT( valve ); + if ( !valve->isValid() ) return; + + CVF_ASSERT( !valve->label().isEmpty() ); + CVF_ASSERT( valve->wellPath() ); + + formatter.addOptionalComment( valve->label() ); + + auto segments = valve->segments(); + + auto subSegment = segments.front(); + subSegment->setSegmentNumber( *segmentNumber ); + + double startMD = subSegment->startMD(); + double endMD = subSegment->endMD(); + + double midPointMD = 0.5 * ( startMD + endMD ); + double midPointTVD = tvdFromMeasuredDepth( valve->wellPath(), midPointMD ); + + subSegment->setOutputMD( midPointMD ); + subSegment->setOutputTVD( midPointTVD ); + + std::vector> splitSegments = createSubSegmentMDPairs( startMD, endMD, maxSegmentLength ); + + auto wellPathGeometry = valve->wellPath()->wellPathGeometry(); + CVF_ASSERT( wellPathGeometry ); + + for ( const auto& [subStartMD, subEndMD] : splitSegments ) + { + int subSegmentNumber = ( *segmentNumber )++; + + double subStartTVD = tvdFromMeasuredDepth( valve->wellPath(), subStartMD ); + double subEndTVD = tvdFromMeasuredDepth( valve->wellPath(), subEndMD ); + + double depth = 0; + double length = 0; + + if ( exportInfo.lengthAndDepthText() == QString( "INC" ) ) + { + depth = subEndTVD - subStartTVD; + length = subEndMD - subStartMD; + } + else + { + depth = subEndTVD; + length = subEndMD; + } + + formatter.add( subSegmentNumber ); + formatter.add( subSegmentNumber ); + formatter.add( valve->branchNumber() ); + formatter.add( outletSegment->segmentNumber() ); + + formatter.add( length ); + formatter.add( depth ); + formatter.add( exportInfo.linerDiameter() ); + formatter.add( exportInfo.roughnessFactor() ); + formatter.rowCompleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::writeCompletionWelsegsSegments( gsl::not_null outletSegment, + gsl::not_null completion, + RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + int* segmentNumber ) +{ + writeWelsegsCompletionCommentHeader( formatter, completion->completionType() ); + + if ( completion->completionType() == RigCompletionData::FISHBONES ) + { + formatter.addOptionalComment( + QString( "Sub index %1 - %2" ).arg( outletSegment->subIndex() + 1 ).arg( completion->label() ) ); + } + else if ( completion->completionType() == RigCompletionData::FRACTURE ) + { + formatter.addOptionalComment( + QString( "%1 connected to segment %2" ).arg( completion->label() ).arg( outletSegment->segmentNumber() ) ); + } + + CVF_ASSERT( completion->wellPath() ); + + int outletSegmentNumber = outletSegment->segmentNumber(); + + for ( auto segment : completion->segments() ) + { + double startMD = segment->startMD(); + double endMD = segment->endMD(); + + std::vector> splitSegments = createSubSegmentMDPairs( startMD, endMD, maxSegmentLength ); + + for ( const auto& [subStartMD, subEndMD] : splitSegments ) + { + int subSegmentNumber = ( *segmentNumber )++; + + double subStartTVD = tvdFromMeasuredDepth( completion->wellPath(), subStartMD ); + double subEndTVD = tvdFromMeasuredDepth( completion->wellPath(), subEndMD ); + + double depth = 0; + double length = 0; + + if ( exportInfo.lengthAndDepthText() == QString( "INC" ) ) + { + depth = subEndTVD - subStartTVD; + length = subEndMD - subStartMD; + } + else + { + depth = subEndTVD; + length = subEndMD; + } + formatter.add( subSegmentNumber ); + formatter.add( subSegmentNumber ); + formatter.add( completion->branchNumber() ); + formatter.add( outletSegmentNumber ); + formatter.add( length ); + formatter.add( depth ); + formatter.add( segment->equivalentDiameter() ); + formatter.add( segment->openHoleRoughnessFactor() ); + formatter.rowCompleted(); + outletSegmentNumber = subSegmentNumber; + } + + for ( auto completionSegment : completion->segments() ) + { + auto noConst = const_cast( completionSegment ); + noConst->setSegmentNumber( outletSegmentNumber ); + for ( auto comp : completionSegment->completions() ) + { + writeCompletionWelsegsSegments( completionSegment, comp, formatter, exportInfo, maxSegmentLength, segmentNumber ); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::writeCompletionsForSegment( gsl::not_null outletSegment, + gsl::not_null segment, + RicMswValve** outletValve, + RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + int* segmentNumber ) +{ + for ( auto& completion : segment->completions() ) + { + // For a well with perforation intervals, the WELSEGS segments are reported twice if if we include the + // RicMswPerforation completions. Investigate when this class is intended to be exported to file + auto performationMsw = dynamic_cast( completion ); + if ( performationMsw ) continue; + + auto segmentValve = dynamic_cast( completion ); + auto fishboneIcd = dynamic_cast( completion ); + if ( !fishboneIcd && segmentValve != nullptr ) + { + writeValveWelsegsSegment( segment, segmentValve, formatter, exportInfo, maxSegmentLength, segmentNumber ); + *outletValve = segmentValve; + } + else + { + // If we have a valve, the outlet segment is the valve's segment + RicMswSegment* outletSegment = *outletValve && ( *outletValve )->segmentCount() > 0 + ? ( *outletValve )->segments().front() + : segment.get(); + writeCompletionWelsegsSegments( outletSegment, completion, formatter, exportInfo, maxSegmentLength, segmentNumber ); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> + RicMswTableFormatterTools::createSubSegmentMDPairs( double startMD, double endMD, double maxSegmentLength ) +{ + int subSegmentCount = (int)( std::trunc( ( endMD - startMD ) / maxSegmentLength ) + 1 ); + + double subSegmentLength = ( endMD - startMD ) / subSegmentCount; + + std::vector> subSegmentMDPairs; + + double subStartMD = startMD; + double subEndMD = startMD + subSegmentLength; + for ( int i = 0; i < subSegmentCount; ++i ) + { + subSegmentMDPairs.push_back( std::make_pair( subStartMD, subEndMD ) ); + subStartMD += subSegmentLength; + subEndMD += std::min( subSegmentLength, endMD ); + } + return subSegmentMDPairs; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswTableFormatterTools::tvdFromMeasuredDepth( gsl::not_null wellPath, double measuredDepth ) +{ + auto wellPathGeometry = wellPath->wellPathGeometry(); + CVF_ASSERT( wellPathGeometry ); + + double tvdValue = -wellPathGeometry->interpolatedPointAlongWellPath( measuredDepth ).z(); + + return tvdValue; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswTableFormatterTools::writeWsegvalHeader( RifTextDataTableFormatter& formatter ) +{ + formatter.keyword( "WSEGVALV" ); + std::vector header = { + RifTextDataTableColumn( "Well Name" ), + RifTextDataTableColumn( "Seg No" ), + RifTextDataTableColumn( "Cv" ), + RifTextDataTableColumn( "Ac" ), + }; + formatter.header( header ); +} diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableFormatterTools.h b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableFormatterTools.h new file mode 100644 index 0000000000..7512b1dc1a --- /dev/null +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableFormatterTools.h @@ -0,0 +1,130 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RigCompletionData.h" + +#include "cvfVector3.h" + +#include + +class RicMswExportInfo; +class RifTextDataTableFormatter; +class RicMswBranch; +class RicMswSegment; +class RicMswValve; +class RicMswCompletion; +class RimWellPath; + +namespace RicMswTableFormatterTools +{ +class CvfVec3stComparator +{ +public: + bool operator()( const cvf::Vec3st& lhs, const cvf::Vec3st& rhs ) const + { + if ( lhs.z() == rhs.z() ) + { + if ( lhs.y() == rhs.y() ) + { + return lhs.x() < rhs.x(); + } + return lhs.y() < rhs.y(); + } + return lhs.z() < rhs.z(); + } +}; + +void generateWelsegsTable( RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + bool exportCompletionSegmentsAfterMainBore ); + +void writeWelsegsSegmentsRecursively( RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + gsl::not_null branch, + gsl::not_null segmentNumber, + double maxSegmentLength, + bool exportCompletionSegmentsAfterMainBore, + RicMswSegment* connectedToSegment ); + +void writeWelsegsSegment( RicMswSegment* segment, + const RicMswSegment* previousSegment, + RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + gsl::not_null branch, + int* segmentNumber ); + +void writeValveWelsegsSegment( const RicMswSegment* outletSegment, + RicMswValve* valve, + RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + int* segmentNumber ); + +void writeCompletionWelsegsSegments( gsl::not_null outletSegment, + gsl::not_null completion, + RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + int* segmentNumber ); + +void writeCompletionsForSegment( gsl::not_null outletSegment, + gsl::not_null segment, + RicMswValve** outletValve, + RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + double maxSegmentLength, + int* segmentNumber ); + +void writeWelsegsCompletionCommentHeader( RifTextDataTableFormatter& formatter, + RigCompletionData::CompletionType completionType ); + +void generateCompsegTables( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ); + +void generateCompsegTable( RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + gsl::not_null branch, + bool exportSubGridIntersections, + const std::set& exportCompletionTypes, + gsl::not_null headerGenerated, + gsl::not_null*> intersectedCells ); + +void generateCompsegHeader( RifTextDataTableFormatter& formatter, + RicMswExportInfo& exportInfo, + RigCompletionData::CompletionType completionType, + bool exportSubGridIntersections ); + +void generateWsegvalvTable( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ); + +void generateWsegvalvTableRecursively( RifTextDataTableFormatter& formatter, + gsl::not_null branch, + bool& isHeaderWritten, + const QString& wellNameForExport ); + +void generateWsegAicdTable( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ); + +std::vector> createSubSegmentMDPairs( double startMD, double endMD, double maxSegmentLength ); + +double tvdFromMeasuredDepth( gsl::not_null wellPath, double measuredDepth ); + +void writeWsegvalHeader( RifTextDataTableFormatter& formatter ); + +} // namespace RicMswTableFormatterTools diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp index 3b709a1496..1797824b10 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp @@ -99,7 +99,33 @@ void RicWellPathExportCompletionDataFeature::prepareExportSettingsAndExportCompl s->descendantsIncludingThisOfType( simWellFractures ); } - for ( auto w : wellPaths ) + std::vector topLevelWells; + { + std::set myWells; + + for ( auto w : wellPaths ) + { + myWells.insert( w->topLevelWellPath() ); + } + + topLevelWells.assign( myWells.begin(), myWells.end() ); + } + + std::vector allLaterals; + { + std::set laterals; + + for ( auto t : topLevelWells ) + { + auto laterals = t->wellPathLateralsRecursively(); + for ( auto l : laterals ) + { + allLaterals.push_back( l ); + } + } + } + + for ( auto w : allLaterals ) { w->descendantsIncludingThisOfType( wellPathFractures ); w->descendantsIncludingThisOfType( wellPathFishbones ); @@ -162,7 +188,7 @@ void RicWellPathExportCompletionDataFeature::prepareExportSettingsAndExportCompl RiaApplication::instance()->setLastUsedDialogDirectory( "COMPLETIONS", exportSettings->folder ); - RicWellPathExportCompletionDataFeatureImpl::exportCompletions( wellPaths, simWells, *exportSettings ); + RicWellPathExportCompletionDataFeatureImpl::exportCompletions( topLevelWells, simWells, *exportSettings ); } } @@ -220,25 +246,5 @@ std::vector RicWellPathExportCompletionDataFeature::selectedWellPa std::vector wellPaths; caf::SelectionManager::instance()->objectsByType( &wellPaths ); - std::set uniqueWellPaths( wellPaths.begin(), wellPaths.end() ); - wellPaths.assign( uniqueWellPaths.begin(), uniqueWellPaths.end() ); - - if ( wellPaths.empty() ) - { - RimWellPathCompletions* completions = - caf::SelectionManager::instance()->selectedItemAncestorOfType(); - if ( completions ) - { - RimWellPath* wellPath = nullptr; - completions->firstAncestorOrThisOfTypeAsserted( wellPath ); - wellPaths.push_back( wellPath ); - } - } - - wellPaths.erase( std::remove_if( wellPaths.begin(), - wellPaths.end(), - []( auto wellPath ) { return !wellPath->isTopLevelWellPath(); } ), - wellPaths.end() ); - return wellPaths; } diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp index 0b1418d0ba..744c29e904 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp @@ -85,7 +85,7 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportCompletions( const std::vector& wellPaths, +void RicWellPathExportCompletionDataFeatureImpl::exportCompletions( const std::vector& topLevelWellPaths, const std::vector& simWells, const RicExportCompletionDataSettingsUi& exportSettings ) { @@ -111,12 +111,16 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions( const std::v if ( exportSettings.compdatExport == RicExportCompletionDataSettingsUi::TRANSMISSIBILITIES || exportSettings.compdatExport == RicExportCompletionDataSettingsUi::WPIMULT_AND_DEFAULT_CONNECTION_FACTORS ) { - std::vector usedWellPaths; - for ( RimWellPath* wellPath : wellPaths ) + std::vector allWellPathLaterals; + for ( RimWellPath* wellPath : topLevelWellPaths ) { if ( wellPath->unitSystem() == exportSettings.caseToApply->eclipseCaseData()->unitsType() ) { - usedWellPaths.push_back( wellPath ); + auto tieInWells = wellPath->wellPathLateralsRecursively(); + for ( auto w : tieInWells ) + { + allWellPathLaterals.push_back( w ); + } } else { @@ -162,11 +166,11 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions( const std::v } size_t maxProgress = - usedWellPaths.size() * 3 + simWells.size() + + allWellPathLaterals.size() * 3 + simWells.size() + ( exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL - ? usedWellPaths.size() + ? allWellPathLaterals.size() : exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL_AND_COMPLETION_TYPE - ? usedWellPaths.size() * 3 + ? allWellPathLaterals.size() * 3 : 1 ) + simWells.size(); @@ -176,7 +180,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions( const std::v std::vector completions; - for ( auto wellPath : usedWellPaths ) + for ( auto wellPath : allWellPathLaterals ) { std::map> completionsPerEclipseCellAllCompletionTypes; std::map> completionsPerEclipseCellFishbones; @@ -297,12 +301,12 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions( const std::v } else if ( exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL ) { - for ( auto wellPath : usedWellPaths ) + for ( auto wellPath : topLevelWellPaths ) { std::vector completionsForWell; for ( const auto& completion : completions ) { - if ( RicWellPathExportCompletionDataFeatureImpl::isCompletionWellPathEqual( completion, wellPath ) ) + if ( wellPath == topLevelWellPath( completion ) ) { completionsForWell.push_back( completion ); } @@ -340,15 +344,14 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions( const std::v for ( const auto& completionType : completionTypes ) { - for ( auto wellPath : usedWellPaths ) + for ( auto wellPath : topLevelWellPaths ) { std::vector completionsForWell; for ( const auto& completion : completions ) { if ( completionType == completion.completionType() ) { - if ( RicWellPathExportCompletionDataFeatureImpl::isCompletionWellPathEqual( completion, - wellPath ) ) + if ( wellPath == topLevelWellPath( completion ) ) { completionsForWell.push_back( completion ); } @@ -439,7 +442,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions( const std::v if ( exportSettings.includeMsw ) { - RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions( exportSettings, wellPaths ); + RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions( exportSettings, topLevelWellPaths ); } } @@ -1746,18 +1749,20 @@ std::pair RicWellPathExportCompletionDataFeatureImpl::wellPa //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RicWellPathExportCompletionDataFeatureImpl::isCompletionWellPathEqual( const RigCompletionData& completion, - const RimWellPath* wellPath ) +RimWellPath* RicWellPathExportCompletionDataFeatureImpl::topLevelWellPath( const RigCompletionData& completion ) { - if ( !wellPath ) return false; - RimWellPath* parentWellPath = nullptr; if ( completion.sourcePdmObject() ) { completion.sourcePdmObject()->firstAncestorOrThisOfType( parentWellPath ); } - return ( parentWellPath == wellPath ); + if ( parentWellPath ) + { + return parentWellPath->topLevelWellPath(); + } + + return nullptr; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h index 85fbcec2c4..ce4bbc6873 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h @@ -194,5 +194,5 @@ private: static void exportCarfinForTemporaryLgrs( const RimEclipseCase* sourceCase, const QString& folder ); - static bool isCompletionWellPathEqual( const RigCompletionData& completion, const RimWellPath* wellPath ); + static RimWellPath* topLevelWellPath( const RigCompletionData& completion ); }; diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp index 547e510076..f4782510b1 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp @@ -24,6 +24,7 @@ #include "RicExportCompletionDataSettingsUi.h" #include "RicExportFractureCompletionsImpl.h" #include "RicMswExportInfo.h" +#include "RicMswTableFormatterTools.h" #include "RicMswValveAccumulators.h" #include "RicWellPathExportCompletionsFileTools.h" @@ -41,13 +42,15 @@ #include "RimFishbones.h" #include "RimFishbonesCollection.h" #include "RimFractureTemplate.h" +#include "RimModeledWellPath.h" #include "RimPerforationCollection.h" #include "RimPerforationInterval.h" +#include "RimProject.h" #include "RimWellPath.h" #include "RimWellPathCompletions.h" #include "RimWellPathFracture.h" #include "RimWellPathFractureCollection.h" -#include "RimWellPathGroup.h" +#include "RimWellPathTieIn.h" #include "RimWellPathValve.h" #include @@ -74,18 +77,13 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions( { std::shared_ptr unifiedWellPathFile; - auto allCompletions = wellPath->allCompletionsRecursively(); + auto allCompletions = wellPath->allCompletionsRecursively(); + bool exportFractures = exportSettings.includeFractures() && std::any_of( allCompletions.begin(), allCompletions.end(), []( auto completion ) { return completion->isEnabled() && completion->componentType() == RiaDefines::WellPathComponentType::FRACTURE; } ); - bool exportPerforations = exportSettings.includePerforations() && - std::any_of( allCompletions.begin(), allCompletions.end(), []( auto completion ) { - return completion->isEnabled() && - completion->componentType() == - RiaDefines::WellPathComponentType::PERFORATION_INTERVAL; - } ); bool exportFishbones = exportSettings.includeFishbones() && std::any_of( allCompletions.begin(), allCompletions.end(), []( auto completion ) { @@ -93,9 +91,7 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions( completion->componentType() == RiaDefines::WellPathComponentType::FISHBONES; } ); - bool exportAnyCompletion = exportFractures || exportPerforations || exportFishbones; - if ( exportAnyCompletion && exportSettings.fileSplit() == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL && - !unifiedWellPathFile ) + if ( exportSettings.fileSplit() == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL && !unifiedWellPathFile ) { QString wellFileName = QString( "%1_UnifiedCompletions_MSW_%2" ) .arg( wellPath->name(), exportSettings.caseToApply->caseUserDescription() ); @@ -103,6 +99,39 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions( RicWellPathExportCompletionsFileTools::openFileForExport( exportSettings.folder, wellFileName ); } + { + // Always use perforation functions to export well segments along well path. + // If no perforations are present, skip Perforation from file name + + std::shared_ptr perforationsExportFile; + if ( unifiedExportFile ) + perforationsExportFile = unifiedExportFile; + else if ( unifiedWellPathFile ) + perforationsExportFile = unifiedWellPathFile; + else + { + bool anyPerforationsPresent = + exportSettings.includeFractures() && + std::any_of( allCompletions.begin(), allCompletions.end(), []( auto completion ) { + return completion->isEnabled() && + completion->componentType() == RiaDefines::WellPathComponentType::PERFORATION_INTERVAL; + } ); + + QString perforationText = anyPerforationsPresent ? "Perforation_" : ""; + QString fileName = + QString( "%1_%2MSW_%3" ) + .arg( wellPath->name(), perforationText, exportSettings.caseToApply->caseUserDescription() ); + perforationsExportFile = + RicWellPathExportCompletionsFileTools::openFileForExport( exportSettings.folder, fileName ); + } + exportWellSegmentsForPerforations( exportSettings.caseToApply, + perforationsExportFile, + wellPath, + exportSettings.timeStep, + exportSettings.exportDataSourceAsComment(), + exportSettings.exportCompletionWelspecAfterMainBore() ); + } + if ( exportFractures ) { std::shared_ptr fractureExportFile; @@ -120,28 +149,8 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions( exportWellSegmentsForFractures( exportSettings.caseToApply, fractureExportFile, wellPath, - exportSettings.exportDataSourceAsComment() ); - } - - if ( exportPerforations ) - { - std::shared_ptr perforationsExportFile; - if ( unifiedExportFile ) - perforationsExportFile = unifiedExportFile; - else if ( unifiedWellPathFile ) - perforationsExportFile = unifiedWellPathFile; - else - { - QString fileName = QString( "%1_Perforation_MSW_%2" ) - .arg( wellPath->name(), exportSettings.caseToApply->caseUserDescription() ); - perforationsExportFile = - RicWellPathExportCompletionsFileTools::openFileForExport( exportSettings.folder, fileName ); - } - exportWellSegmentsForPerforations( exportSettings.caseToApply, - perforationsExportFile, - wellPath, - exportSettings.timeStep, - exportSettings.exportDataSourceAsComment() ); + exportSettings.exportDataSourceAsComment(), + exportSettings.exportCompletionWelspecAfterMainBore() ); } if ( exportFishbones ) @@ -161,20 +170,79 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions( exportWellSegmentsForFishbones( exportSettings.caseToApply, fishbonesExportFile, wellPath, - exportSettings.exportDataSourceAsComment() ); + exportSettings.exportDataSourceAsComment(), + exportSettings.exportCompletionWelspecAfterMainBore() ); } } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForPerforations( RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + int timeStep, + bool exportDataSourceAsComment, + bool completionSegmentsAfterMainBore ) +{ + RiaDefines::EclipseUnitSystem unitSystem = eclipseCase->eclipseCaseData()->unitsType(); + + auto mswParameters = wellPath->perforationIntervalCollection()->mswParameters(); + + if ( !mswParameters ) return; + + double initialMD = 0.0; // Start measured depth location to export MSW data for. Either based on first intersection + // with active grid, or user defined value. + + auto cellIntersections = generateCellSegments( eclipseCase, wellPath, mswParameters, &initialMD ); + + RicMswExportInfo exportInfo( wellPath, + unitSystem, + initialMD, + mswParameters->lengthAndDepth().text(), + mswParameters->pressureDrop().text() ); + + exportInfo.setLinerDiameter( mswParameters->linerDiameter( unitSystem ) ); + exportInfo.setRoughnessFactor( mswParameters->roughnessFactor( unitSystem ) ); + + if ( generatePerforationsMswExportInfo( eclipseCase, + wellPath, + timeStep, + initialMD, + cellIntersections, + &exportInfo, + exportInfo.mainBoreBranch() ) ) + { + int branchNumber = 1; + + assignBranchNumbersToBranch( eclipseCase, &exportInfo, exportInfo.mainBoreBranch(), &branchNumber ); + + QTextStream stream( exportFile.get() ); + RifTextDataTableFormatter formatter( stream ); + + double maxSegmentLength = mswParameters->maxSegmentLength(); + + RicMswTableFormatterTools::generateWelsegsTable( formatter, + exportInfo, + maxSegmentLength, + completionSegmentsAfterMainBore ); + RicMswTableFormatterTools::generateCompsegTables( formatter, exportInfo ); + RicMswTableFormatterTools::generateWsegvalvTable( formatter, exportInfo ); + RicMswTableFormatterTools::generateWsegAicdTable( formatter, exportInfo ); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFractures( RimEclipseCase* eclipseCase, std::shared_ptr exportFile, const RimWellPath* wellPath, - bool exportDataSourceAsComment ) + bool exportDataSourceAsComment, + bool completionSegmentsAfterMainBore ) { - auto fractures = wellPath->fractureCollection()->activeFractures(); + RiaDefines::EclipseUnitSystem unitSystem = eclipseCase->eclipseCaseData()->unitsType(); if ( eclipseCase == nullptr ) { @@ -183,7 +251,33 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFractures( RimEcl return; } - RicMswExportInfo exportInfo = generateFracturesMswExportInfo( eclipseCase, wellPath, fractures ); + auto mswParameters = wellPath->fractureCollection()->mswParameters(); + + if ( !mswParameters ) return; + + double initialMD = 0.0; // Start measured depth location to export MSW data for. Either based on first intersection + // with active grid, or user defined value. + + auto cellIntersections = generateCellSegments( eclipseCase, wellPath, mswParameters, &initialMD ); + + RicMswExportInfo exportInfo( wellPath, + unitSystem, + initialMD, + mswParameters->lengthAndDepth().text(), + mswParameters->pressureDrop().text() ); + + exportInfo.setLinerDiameter( mswParameters->linerDiameter( unitSystem ) ); + exportInfo.setRoughnessFactor( mswParameters->roughnessFactor( unitSystem ) ); + + generateFracturesMswExportInfo( eclipseCase, + wellPath, + initialMD, + cellIntersections, + &exportInfo, + exportInfo.mainBoreBranch() ); + + int branchNumber = 1; + assignBranchNumbersToBranch( eclipseCase, &exportInfo, exportInfo.mainBoreBranch(), &branchNumber ); QTextStream stream( exportFile.get() ); RifTextDataTableFormatter formatter( stream ); @@ -191,8 +285,8 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFractures( RimEcl double maxSegmentLength = wellPath->fractureCollection()->mswParameters()->maxSegmentLength(); - generateWelsegsTable( formatter, exportInfo, maxSegmentLength ); - generateCompsegTables( formatter, exportInfo ); + RicMswTableFormatterTools::generateWelsegsTable( formatter, exportInfo, maxSegmentLength, completionSegmentsAfterMainBore ); + RicMswTableFormatterTools::generateCompsegTables( formatter, exportInfo ); } //-------------------------------------------------------------------------------------------------- @@ -201,7 +295,8 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFractures( RimEcl void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFishbones( RimEclipseCase* eclipseCase, std::shared_ptr exportFile, const RimWellPath* wellPath, - bool exportDataSourceAsComment ) + bool exportDataSourceAsComment, + bool completionSegmentsAfterMainBore ) { auto fishbonesSubs = wellPath->fishbonesCollection()->activeFishbonesSubs(); @@ -246,680 +341,16 @@ void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFishbones( RimEcl double maxSegmentLength = wellPath->fishbonesCollection()->mswParameters()->maxSegmentLength(); - generateWelsegsTable( formatter, exportInfo, maxSegmentLength ); - generateCompsegTables( formatter, exportInfo ); - generateWsegvalvTable( formatter, exportInfo ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForPerforations( RimEclipseCase* eclipseCase, - std::shared_ptr exportFile, - const RimWellPath* wellPath, - int timeStep, - bool exportDataSourceAsComment ) -{ - RiaDefines::EclipseUnitSystem unitSystem = eclipseCase->eclipseCaseData()->unitsType(); - - auto mswParameters = wellPath->perforationIntervalCollection()->mswParameters(); - - if ( !mswParameters ) return; - - double initialMD = 0.0; // Start measured depth location to export MSW data for. Either based on first intersection - // with active grid, or user defined value. - - auto cellIntersections = generateCellSegments( eclipseCase, wellPath, mswParameters, &initialMD ); - - RicMswExportInfo exportInfo( wellPath, - unitSystem, - initialMD, - mswParameters->lengthAndDepth().text(), - mswParameters->pressureDrop().text() ); - - exportInfo.setLinerDiameter( mswParameters->linerDiameter( unitSystem ) ); - exportInfo.setRoughnessFactor( mswParameters->roughnessFactor( unitSystem ) ); - - if ( generatePerforationsMswExportInfo( eclipseCase, - wellPath, - timeStep, - initialMD, - cellIntersections, - &exportInfo, - exportInfo.mainBoreBranch() ) ) - { - int branchNumber = 1; - - assignBranchNumbersToBranch( eclipseCase, &exportInfo, exportInfo.mainBoreBranch(), &branchNumber ); - - QTextStream stream( exportFile.get() ); - RifTextDataTableFormatter formatter( stream ); - - double maxSegmentLength = mswParameters->maxSegmentLength(); - - generateWelsegsTable( formatter, exportInfo, maxSegmentLength ); - generateCompsegTables( formatter, exportInfo ); - generateWsegvalvTable( formatter, exportInfo ); - generateWsegAicdTable( formatter, exportInfo ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::generateWelsegsTable( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - double maxSegmentLength ) -{ - formatter.keyword( "WELSEGS" ); - - double startMD = exportInfo.mainBoreBranch()->startMD(); - double startTVD = exportInfo.mainBoreBranch()->startTVD(); - - { - std::vector header = { - RifTextDataTableColumn( "Name" ), - RifTextDataTableColumn( "Dep 1" ), - RifTextDataTableColumn( "Tlen 1" ), - RifTextDataTableColumn( "Vol 1" ), - RifTextDataTableColumn( "Len&Dep" ), - RifTextDataTableColumn( "PresDrop" ), - }; - formatter.header( header ); - - formatter.add( exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport() ); - formatter.add( startTVD ); - formatter.add( startMD ); - formatter.addValueOrDefaultMarker( exportInfo.topWellBoreVolume(), RicMswExportInfo::defaultDoubleValue() ); - formatter.add( exportInfo.lengthAndDepthText() ); - formatter.add( QString( "'%1'" ).arg( exportInfo.pressureDropText() ) ); - - formatter.rowCompleted(); - } - - { - std::vector header = - { RifTextDataTableColumn( "First Seg" ), - RifTextDataTableColumn( "Last Seg" ), - RifTextDataTableColumn( "Branch Num" ), - RifTextDataTableColumn( "Outlet Seg" ), - RifTextDataTableColumn( "Length" ), - RifTextDataTableColumn( "Depth Change" ), - RifTextDataTableColumn( "Diam" ), - RifTextDataTableColumn( "Rough", RifTextDataTableDoubleFormatting( RIF_FLOAT, 7 ) ) }; - formatter.header( header ); - } - - int segmentNumber = 2; // There's an implicit segment number 1. - - writeWelsegsSegmentsRecursively( formatter, exportInfo, exportInfo.mainBoreBranch(), &segmentNumber, maxSegmentLength ); - - formatter.tableCompleted(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::writeWelsegsSegmentsRecursively( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - gsl::not_null branch, - gsl::not_null segmentNumber, - double maxSegmentLength, - RicMswSegment* connectedToSegment ) -{ - auto outletSegment = connectedToSegment; - - RicMswValve* outletValve = nullptr; - - auto branchSegments = branch->segments(); - auto it = branchSegments.begin(); - if ( outletValve = dynamic_cast( branch.get() ); outletValve != nullptr ) - { - writeValveWelsegsSegment( outletSegment, outletValve, formatter, exportInfo, maxSegmentLength, segmentNumber ); - - auto valveSegments = outletValve->segments(); - outletSegment = valveSegments.front(); - *segmentNumber = outletSegment->segmentNumber() + 1; - ++it; // skip segment below - } - - formatter.addOptionalComment( QString( "Segments on branch %1" ).arg( branch->label() ) ); - - for ( ; it != branchSegments.end(); ++it ) - { - auto segment = *it; - segment->setSegmentNumber( *segmentNumber ); - - if ( segment->subIndex() != cvf::UNDEFINED_SIZE_T ) - { - QString comment = segment->label() + QString( ", sub %1" ).arg( segment->subIndex() ); - formatter.addOptionalComment( comment ); - } - - writeWelsegsSegment( segment, outletSegment, formatter, exportInfo, maxSegmentLength, branch, segmentNumber ); - outletSegment = segment; - - for ( auto& completion : segment->completions() ) - { - // For a well with perforation intervals, the WELSEGS segments are reported twice if if we include the - // RicMswPerforation completions. Investigate when this class is intended to be exported to file - auto performationMsw = dynamic_cast( completion ); - if ( performationMsw ) continue; - - auto segmentValve = dynamic_cast( completion ); - if ( segmentValve != nullptr ) - { - writeValveWelsegsSegment( segment, segmentValve, formatter, exportInfo, maxSegmentLength, segmentNumber ); - outletValve = segmentValve; - outletSegment = segment; - } - else - { - // If we have a valve, the outlet segment is the valve's segment - RicMswSegment* outletSegment = - outletValve && outletValve->segmentCount() > 0 ? outletValve->segments().front() : segment; - writeCompletionWelsegsSegments( outletSegment, completion, formatter, exportInfo, maxSegmentLength, segmentNumber ); - } - } - } - - for ( auto childBranch : branch->branches() ) - { - writeWelsegsSegmentsRecursively( formatter, exportInfo, childBranch, segmentNumber, maxSegmentLength, outletSegment ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::writeWelsegsCompletionCommentHeader( RifTextDataTableFormatter& formatter, - RigCompletionData::CompletionType completionType ) -{ - if ( completionType == RigCompletionData::CT_UNDEFINED ) - { - formatter.addOptionalComment( "Main stem" ); - } - else if ( completionType == RigCompletionData::FISHBONES_ICD ) - { - formatter.addOptionalComment( "Fishbone Laterals" ); - formatter.addOptionalComment( "Diam: MSW - Tubing Radius" ); - formatter.addOptionalComment( "Rough: MSW - Open Hole Roughness Factor" ); - } - else if ( RigCompletionData::isPerforationValve( completionType ) ) - { - formatter.addOptionalComment( "Perforation Valve Segments" ); - formatter.addOptionalComment( "Diam: MSW - Tubing Radius" ); - formatter.addOptionalComment( "Rough: MSW - Open Hole Roughness Factor" ); - } - else if ( completionType == RigCompletionData::FRACTURE ) - { - formatter.addOptionalComment( "Fracture Segments" ); - formatter.addOptionalComment( "Diam: MSW - Default Dummy" ); - formatter.addOptionalComment( "Rough: MSW - Default Dummy" ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::generateCompsegTables( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo ) -{ - /* - * TODO: Creating the regular perforation COMPSEGS table should come in here, before the others - * should take precedence by appearing later in the output. See #3230. - */ - - bool headerGenerated = false; - - std::set intersectedCells; - - { - std::set perforationTypes = { RigCompletionData::PERFORATION, - RigCompletionData::PERFORATION_ICD, - RigCompletionData::PERFORATION_ICV, - RigCompletionData::PERFORATION_AICD }; - generateCompsegTable( formatter, - exportInfo, - exportInfo.mainBoreBranch(), - false, - perforationTypes, - &headerGenerated, - &intersectedCells ); - if ( exportInfo.hasSubGridIntersections() ) - { - generateCompsegTable( formatter, - exportInfo, - exportInfo.mainBoreBranch(), - true, - perforationTypes, - &headerGenerated, - &intersectedCells ); - } - } - - { - std::set fishbonesTypes = { RigCompletionData::FISHBONES_ICD, - RigCompletionData::FISHBONES }; - generateCompsegTable( formatter, - exportInfo, - exportInfo.mainBoreBranch(), - false, - fishbonesTypes, - &headerGenerated, - &intersectedCells ); - if ( exportInfo.hasSubGridIntersections() ) - { - generateCompsegTable( formatter, - exportInfo, - exportInfo.mainBoreBranch(), - true, - fishbonesTypes, - &headerGenerated, - &intersectedCells ); - } - } - - { - std::set fractureTypes = { RigCompletionData::FRACTURE }; - generateCompsegTable( formatter, - exportInfo, - exportInfo.mainBoreBranch(), - false, - fractureTypes, - &headerGenerated, - &intersectedCells ); - if ( exportInfo.hasSubGridIntersections() ) - { - generateCompsegTable( formatter, - exportInfo, - exportInfo.mainBoreBranch(), - true, - fractureTypes, - &headerGenerated, - &intersectedCells ); - } - } - - if ( headerGenerated ) - { - formatter.tableCompleted(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::generateCompsegTable( - RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - gsl::not_null branch, - bool exportSubGridIntersections, - const std::set& exportCompletionTypes, - gsl::not_null headerGenerated, - gsl::not_null*> intersectedCells ) -{ - for ( auto segment : branch->segments() ) - { - for ( auto completion : segment->completions() ) - { - if ( completion->segments().empty() || !exportCompletionTypes.count( completion->completionType() ) ) - continue; - - if ( !*headerGenerated ) - { - generateCompsegHeader( formatter, exportInfo, completion->completionType(), exportSubGridIntersections ); - *headerGenerated = true; - } - - bool isPerforationValve = completion->completionType() == RigCompletionData::PERFORATION_ICD || - completion->completionType() == RigCompletionData::PERFORATION_AICD || - completion->completionType() == RigCompletionData::PERFORATION_ICV; - - for ( auto subSegment : completion->segments() ) - { - for ( auto intersection : subSegment->intersections() ) - { - bool isSubGridIntersection = !intersection->gridName().isEmpty(); - if ( isSubGridIntersection != exportSubGridIntersections ) continue; - - double startLength = subSegment->startMD(); - double endLength = subSegment->endMD(); - if ( isPerforationValve ) - { - startLength = segment->startMD(); - endLength = segment->endMD(); - } - - cvf::Vec3st ijk = intersection->gridLocalCellIJK(); - if ( !intersectedCells->count( ijk ) ) - { - if ( exportSubGridIntersections ) - { - formatter.add( intersection->gridName() ); - } - - formatter.addOneBasedCellIndex( ijk.x() ).addOneBasedCellIndex( ijk.y() ).addOneBasedCellIndex( - ijk.z() ); - formatter.add( completion->branchNumber() ); - - formatter.add( startLength ); - formatter.add( endLength ); - - formatter.rowCompleted(); - intersectedCells->insert( ijk ); - } - } - } - } - } - - for ( auto childBranch : branch->branches() ) - { - generateCompsegTable( formatter, - exportInfo, - childBranch, - exportSubGridIntersections, - exportCompletionTypes, - headerGenerated, - intersectedCells ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::generateCompsegHeader( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - RigCompletionData::CompletionType completionType, - bool exportSubGridIntersections ) -{ - if ( exportSubGridIntersections ) - { - formatter.keyword( "COMPSEGL" ); - } - else - { - formatter.keyword( "COMPSEGS" ); - } - - if ( completionType == RigCompletionData::FISHBONES_ICD ) - { - formatter.comment( "Fishbones" ); - } - else if ( completionType == RigCompletionData::FRACTURE ) - { - formatter.comment( "Fractures" ); - } - - { - std::vector header = { RifTextDataTableColumn( "Name" ) }; - formatter.header( header ); - formatter.add( exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport() ); - formatter.rowCompleted(); - } - - { - std::vector allHeaders; - if ( exportSubGridIntersections ) - { - allHeaders.push_back( RifTextDataTableColumn( "Grid" ) ); - } - - std::vector commonHeaders = { RifTextDataTableColumn( "I" ), - RifTextDataTableColumn( "J" ), - RifTextDataTableColumn( "K" ), - RifTextDataTableColumn( "Branch no" ), - RifTextDataTableColumn( "Start Length" ), - RifTextDataTableColumn( "End Length" ), - RifTextDataTableColumn( "Dir Pen" ), - RifTextDataTableColumn( "End Range" ), - RifTextDataTableColumn( "Connection Depth" ) }; - allHeaders.insert( allHeaders.end(), commonHeaders.begin(), commonHeaders.end() ); - formatter.header( allHeaders ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::generateWsegvalvTable( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo ) -{ - bool foundValve = false; - - for ( auto segment : exportInfo.mainBoreBranch()->segments() ) - { - for ( auto completion : segment->completions() ) - { - if ( RigCompletionData::isWsegValveTypes( completion->completionType() ) ) - { - if ( !foundValve ) - { - formatter.keyword( "WSEGVALV" ); - std::vector header = { - RifTextDataTableColumn( "Well Name" ), - RifTextDataTableColumn( "Seg No" ), - RifTextDataTableColumn( "Cv" ), - RifTextDataTableColumn( "Ac" ), - }; - formatter.header( header ); - - foundValve = true; - } - - auto wsegValve = static_cast( completion ); - if ( !wsegValve->segments().empty() ) - { - CVF_ASSERT( wsegValve->segments().size() == 1u ); - - auto firstSubSegment = wsegValve->segments().front(); - if ( !firstSubSegment->intersections().empty() ) - { - if ( wsegValve->completionType() == RigCompletionData::PERFORATION_ICD || - wsegValve->completionType() == RigCompletionData::PERFORATION_ICV ) - { - formatter.addOptionalComment( wsegValve->label() ); - } - formatter.add( exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport() ); - formatter.add( firstSubSegment->segmentNumber() ); - formatter.add( wsegValve->flowCoefficient() ); - formatter.add( QString( "%1" ).arg( wsegValve->area(), 8, 'g', 4 ) ); - formatter.rowCompleted(); - } - } - } - } - } - if ( foundValve ) - { - formatter.tableCompleted(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::generateWsegAicdTable( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo ) -{ - RifTextDataTableFormatter tighterFormatter( formatter ); - tighterFormatter.setColumnSpacing( 1 ); - tighterFormatter.setTableRowPrependText( " " ); - - bool foundValve = false; - - for ( auto segment : exportInfo.mainBoreBranch()->segments() ) - { - for ( auto completion : segment->completions() ) - { - if ( completion->completionType() == RigCompletionData::PERFORATION_AICD ) - { - auto aicd = static_cast( completion ); - if ( aicd->isValid() ) - { - if ( !foundValve ) - { - std::vector columnDescriptions = - { "Well Name", - "Segment Number", - "Segment Number", - "Strength of AICD", - "Flow Scaling Factor for AICD", - "Density of Calibration Fluid", - "Viscosity of Calibration Fluid", - "Critical water in liquid fraction for emulsions viscosity model", - "Emulsion viscosity transition region", - "Max ratio of emulsion viscosity to continuous phase viscosity", - "Flow scaling factor method", - "Maximum flow rate for AICD device", - "Volume flow rate exponent, x", - "Viscosity function exponent, y", - "Device OPEN/SHUT", - "Exponent of the oil flowing fraction in the density mixture calculation", - "Exponent of the water flowing fraction in the density mixture calculation", - "Exponent of the gas flowing fraction in the density mixture calculation", - "Exponent of the oil flowing fraction in the density viscosity calculation", - "Exponent of the water flowing fraction in the density viscosity calculation", - "Exponent of the gas flowing fraction in the density viscosity calculation" }; - - tighterFormatter.keyword( "WSEGAICD" ); - tighterFormatter.comment( "Column Overview:" ); - for ( size_t i = 0; i < columnDescriptions.size(); ++i ) - { - tighterFormatter.comment( - QString( "%1: %2" ).arg( i + 1, 2, 10, QChar( '0' ) ).arg( columnDescriptions[i] ) ); - } - - std::vector header; - for ( size_t i = 1; i <= 21; ++i ) - { - QString cName = QString( "%1" ).arg( i, 2, 10, QChar( '0' ) ); - RifTextDataTableColumn col( cName, - RifTextDataTableDoubleFormatting( - RifTextDataTableDoubleFormat::RIF_CONSISE ), - RIGHT ); - header.push_back( col ); - } - tighterFormatter.header( header ); - - foundValve = true; - } - if ( !aicd->segments().empty() ) - { - CVF_ASSERT( aicd->segments().size() == 1u ); - tighterFormatter.comment( aicd->label() ); - tighterFormatter.add( - exportInfo.mainBoreBranch()->wellPath()->completionSettings()->wellNameForExport() ); // #1 - tighterFormatter.add( aicd->segments().front()->segmentNumber() ); - tighterFormatter.add( aicd->segments().front()->segmentNumber() ); - - std::array values = aicd->values(); - tighterFormatter.add( values[AICD_STRENGTH] ); - - tighterFormatter.add( aicd->flowScalingFactor() ); // #5 Flow scaling factor used when item - // #11 is set to '1' - - tighterFormatter.add( values[AICD_DENSITY_CALIB_FLUID] ); - tighterFormatter.add( values[AICD_VISCOSITY_CALIB_FLUID] ); - tighterFormatter.addValueOrDefaultMarker( values[AICD_CRITICAL_WATER_IN_LIQUID_FRAC], - RicMswExportInfo::defaultDoubleValue() ); - tighterFormatter.addValueOrDefaultMarker( values[AICD_EMULSION_VISC_TRANS_REGION], - RicMswExportInfo::defaultDoubleValue() ); - tighterFormatter.addValueOrDefaultMarker( values[AICD_MAX_RATIO_EMULSION_VISC], - RicMswExportInfo::defaultDoubleValue() ); // #10 - - tighterFormatter.add( 1 ); // #11 : Always use method "b. Scale factor". The value of the - // scale factor is given in item #5 - - tighterFormatter.addValueOrDefaultMarker( values[AICD_MAX_FLOW_RATE], - RicMswExportInfo::defaultDoubleValue() ); - tighterFormatter.add( values[AICD_VOL_FLOW_EXP] ); - tighterFormatter.add( values[AICD_VISOSITY_FUNC_EXP] ); - tighterFormatter.add( aicd->isOpen() ? "OPEN" : "SHUT" ); // #15 - tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_OIL_FRAC_DENSITY], - RicMswExportInfo::defaultDoubleValue() ); - tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_WATER_FRAC_DENSITY], - RicMswExportInfo::defaultDoubleValue() ); - tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_GAS_FRAC_DENSITY], - RicMswExportInfo::defaultDoubleValue() ); - tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_OIL_FRAC_VISCOSITY], - RicMswExportInfo::defaultDoubleValue() ); - tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_WATER_FRAC_VISCOSITY], - RicMswExportInfo::defaultDoubleValue() ); // #20 - tighterFormatter.addValueOrDefaultMarker( values[AICD_EXP_GAS_FRAC_VISCOSITY], - RicMswExportInfo::defaultDoubleValue() ); - tighterFormatter.rowCompleted(); - } - } - else - { - RiaLogging::error( QString( "Export AICD Valve (%1): Valve is invalid. At least one required " - "template parameter is not set." ) - .arg( aicd->label() ) ); - } - } - } - } - if ( foundValve ) - { - tighterFormatter.tableCompleted(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector> - RicWellPathExportMswCompletionsImpl::createSubSegmentMDPairs( double startMD, double endMD, double maxSegmentLength ) -{ - int subSegmentCount = (int)( std::trunc( ( endMD - startMD ) / maxSegmentLength ) + 1 ); - - double subSegmentLength = ( endMD - startMD ) / subSegmentCount; - - std::vector> subSegmentMDPairs; - - double subStartMD = startMD; - double subEndMD = startMD + subSegmentLength; - for ( int i = 0; i < subSegmentCount; ++i ) - { - subSegmentMDPairs.push_back( std::make_pair( subStartMD, subEndMD ) ); - subStartMD += subSegmentLength; - subEndMD += std::min( subSegmentLength, endMD ); - } - return subSegmentMDPairs; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::pair RicWellPathExportMswCompletionsImpl::calculateOverlapWithActiveCells( - double startMD, - double endMD, - const std::vector& wellPathIntersections, - const RigActiveCellInfo* activeCellInfo ) -{ - for ( const WellPathCellIntersectionInfo& intersection : wellPathIntersections ) - { - if ( intersection.globCellIndex < activeCellInfo->reservoirCellCount() && - activeCellInfo->isActive( intersection.globCellIndex ) ) - { - double overlapStart = std::max( startMD, intersection.startMD ); - double overlapEnd = std::min( endMD, intersection.endMD ); - if ( overlapEnd > overlapStart ) - { - return std::make_pair( overlapStart, overlapEnd ); - } - } - } - return std::make_pair( 0.0, 0.0 ); + RicMswTableFormatterTools::generateWelsegsTable( formatter, exportInfo, maxSegmentLength, completionSegmentsAfterMainBore ); + RicMswTableFormatterTools::generateCompsegTables( formatter, exportInfo ); + RicMswTableFormatterTools::generateWsegvalvTable( formatter, exportInfo ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( - const RimEclipseCase* caseToApply, + const RimEclipseCase* eclipseCase, const RimWellPath* wellPath, double initialMD, const std::vector& cellIntersections, @@ -928,8 +359,9 @@ void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( gsl::not_null branch ) { std::vector fishbonesSubs = wellPath->fishbonesCollection()->activeFishbonesSubs(); + if ( fishbonesSubs.empty() ) return; - generateFishbonesMswExportInfo( caseToApply, + generateFishbonesMswExportInfo( eclipseCase, wellPath, initialMD, cellIntersections, @@ -943,7 +375,7 @@ void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( /// //-------------------------------------------------------------------------------------------------- void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( - const RimEclipseCase* caseToApply, + const RimEclipseCase* eclipseCase, const RimWellPath* wellPath, double initialMD, const std::vector& cellIntersections, @@ -953,7 +385,7 @@ void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( gsl::not_null branch ) { std::vector filteredIntersections = - filterIntersections( cellIntersections, initialMD, wellPath->wellPathGeometry(), caseToApply ); + filterIntersections( cellIntersections, initialMD, wellPath->wellPathGeometry(), eclipseCase ); auto mswParameters = wellPath->fishbonesCollection()->mswParameters(); @@ -961,15 +393,14 @@ void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( // Create a dummy perforation interval RimPerforationInterval perfInterval; - perfInterval.setStartAndEndMD( wellPath->fishbonesCollection()->startMD(), wellPath->fishbonesCollection()->endMD() ); - createWellPathSegments( branch, filteredIntersections, { &perfInterval }, wellPath, -1, caseToApply, &foundSubGridIntersections ); + createWellPathSegments( branch, filteredIntersections, { &perfInterval }, wellPath, -1, eclipseCase, &foundSubGridIntersections ); double maxSegmentLength = enableSegmentSplitting ? mswParameters->maxSegmentLength() : std::numeric_limits::infinity(); double subStartMD = wellPath->fishbonesCollection()->startMD(); - double subStartTVD = RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( branch->wellPath(), subStartMD ); + double subStartTVD = RicMswTableFormatterTools::tvdFromMeasuredDepth( branch->wellPath(), subStartMD ); auto unitSystem = exportInfo->unitSystem(); @@ -981,50 +412,108 @@ void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( subAndLateralIndices[subIndex].push_back( lateralIndex ); } + // Find cell intersections closest to each sub location + std::map> subAndCellIntersectionIndices; + { + auto fishboneSectionStart = subs->startMD(); + auto fishboneSectionEnd = subs->endMD(); + + for ( size_t intersectionIndex = 0; intersectionIndex < filteredIntersections.size(); intersectionIndex++ ) + { + auto cellIntersection = filteredIntersections[intersectionIndex]; + if ( fishboneSectionStart <= cellIntersection.startMD && cellIntersection.startMD < fishboneSectionEnd ) + { + double intersectionMidpoint = 0.5 * ( cellIntersection.startMD + cellIntersection.endMD ); + size_t closestSubIndex = 0; + double closestDistance = std::numeric_limits::infinity(); + for ( const auto& sub : subAndLateralIndices ) + { + double subMD = subs->measuredDepth( sub.first ); + + auto distanceCandicate = std::abs( subMD - intersectionMidpoint ); + if ( distanceCandicate < closestDistance ) + { + closestDistance = distanceCandicate; + closestSubIndex = sub.first; + } + } + + subAndCellIntersectionIndices[closestSubIndex].push_back( intersectionIndex ); + } + } + } + for ( const auto& sub : subAndLateralIndices ) { double subEndMD = subs->measuredDepth( sub.first ); - double subEndTVD = RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( branch->wellPath(), subEndMD ); + double subEndTVD = RicMswTableFormatterTools::tvdFromMeasuredDepth( branch->wellPath(), subEndMD ); { - auto segment = std::make_unique( subs->generatedName(), - subStartMD, - subEndMD, - subStartTVD, - subEndTVD, - sub.first ); - segment->setEffectiveDiameter( subs->effectiveDiameter( unitSystem ) ); - segment->setHoleDiameter( subs->holeDiameter( unitSystem ) ); - segment->setOpenHoleRoughnessFactor( subs->openHoleRoughnessFactor( unitSystem ) ); - segment->setSkinFactor( subs->skinFactor() ); - segment->setSourcePdmObject( subs ); - // Add completion for ICD - auto icdCompletion = - std::make_unique( QString( "ICD" ), wellPath, subEndMD, subEndTVD, nullptr ); auto icdSegment = std::make_unique( "ICD segment", subEndMD, subEndMD + 0.1, subEndTVD, subEndTVD, sub.first ); + + for ( auto lateralIndex : sub.second ) + { + QString label = QString( "Lateral %1" ).arg( lateralIndex + 1 ); + icdSegment->addCompletion( + std::make_unique( label, wellPath, subEndMD, subEndTVD, lateralIndex ) ); + } + + assignFishbonesLateralIntersections( eclipseCase, + branch->wellPath(), + subs, + icdSegment.get(), + &foundSubGridIntersections, + maxSegmentLength, + unitSystem ); + + auto icdCompletion = + std::make_unique( QString( "ICD" ), wellPath, subEndMD, subEndTVD, nullptr ); icdCompletion->setFlowCoefficient( subs->icdFlowCoefficient() ); double icdOrificeRadius = subs->icdOrificeDiameter( unitSystem ) / 2; icdCompletion->setArea( icdOrificeRadius * icdOrificeRadius * cvf::PI_D * subs->icdCount() ); - icdCompletion->addSegment( std::move( icdSegment ) ); - segment->addCompletion( std::move( icdCompletion ) ); - - for ( auto lateralIndex : sub.second ) + // assign open hole segments to sub { - QString label = QString( "Lateral %1" ).arg( lateralIndex ); - segment->addCompletion( - std::make_unique( label, wellPath, subEndMD, subEndTVD, lateralIndex ) ); - } - assignFishbonesLateralIntersections( caseToApply, - branch->wellPath(), - subs, - segment.get(), - &foundSubGridIntersections, - maxSegmentLength ); + const RigMainGrid* mainGrid = eclipseCase->mainGrid(); - exportInfo->mainBoreBranch()->addSegment( std::move( segment ) ); + for ( auto intersectionIndex : subAndCellIntersectionIndices[sub.first] ) + { + auto intersection = filteredIntersections[intersectionIndex]; + if ( intersection.globCellIndex >= mainGrid->globalCellArray().size() ) continue; + + size_t localGridCellIndex = 0u; + const RigGridBase* localGrid = + mainGrid->gridAndGridLocalIdxFromGlobalCellIdx( intersection.globCellIndex, + &localGridCellIndex ); + QString gridName; + if ( localGrid != mainGrid ) + { + gridName = QString::fromStdString( localGrid->gridName() ); + foundSubGridIntersections = true; + } + + size_t i, j, k; + localGrid->ijkFromCellIndex( localGridCellIndex, &i, &j, &k ); + cvf::Vec3st localIJK( i, j, k ); + + auto mswIntersect = + std::make_shared( gridName, + intersection.globCellIndex, + localIJK, + intersection.intersectionLengthsInCellCS ); + icdSegment->addIntersection( mswIntersect ); + } + } + + icdCompletion->addSegment( std::move( icdSegment ) ); + + RicMswSegment* segmentOnParentBranch = branch->findClosestSegmentByMidpoint( subEndMD ); + if ( segmentOnParentBranch ) + { + segmentOnParentBranch->addCompletion( std::move( icdCompletion ) ); + } } subStartMD = subEndMD; @@ -1032,136 +521,79 @@ void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( } } exportInfo->setHasSubGridIntersections( exportInfo->hasSubGridIntersections() || foundSubGridIntersections ); - exportInfo->mainBoreBranch()->sortSegments(); + // branch->sortSegments(); - if ( auto wellPathGroup = dynamic_cast( wellPath ); wellPathGroup != nullptr ) + std::vector connectedWellPaths = wellPathsWithTieIn( wellPath ); + for ( auto childWellPath : connectedWellPaths ) { - auto initialChildMD = wellPathGroup->uniqueEndMD(); - auto initialChildTVD = tvdFromMeasuredDepth( wellPathGroup, initialMD ); - for ( auto childWellPath : wellPathGroup->childWellPaths() ) - { - auto childCellIntersections = - generateCellSegments( caseToApply, childWellPath, mswParameters, &initialChildMD ); - auto childBranch = - std::make_unique( childWellPath->name(), childWellPath, initialChildMD, initialChildTVD ); + auto childMswBranch = createChildMswBranch( childWellPath ); + auto mswParameters = childWellPath->perforationIntervalCollection()->mswParameters(); - if ( wellPathGroup->outletValve() ) - { - childBranch = RicMswValve::createExportValve( QString( "%1 valve for %2" ) - .arg( wellPathGroup->outletValve()->componentLabel() ) - .arg( childWellPath->name() ), - childWellPath, - initialChildMD, - initialChildTVD, - wellPathGroup->outletValve() ); - auto dummySegment = std::make_unique< - RicMswSegment>( QString( "%1 segment" ).arg( wellPathGroup->outletValve()->componentLabel() ), - initialChildMD, - initialChildMD + 0.1, - initialChildTVD, - RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( wellPath, - initialChildMD + 0.1 ) ); - childBranch->addSegment( std::move( dummySegment ) ); - } + double startOfChildMD = 0.0; // this is currently not used, as the tie-in MD is used + auto childCellIntersections = generateCellSegments( eclipseCase, childWellPath, mswParameters, &startOfChildMD ); + auto initialChildMD = childWellPath->wellPathTieIn()->tieInMeasuredDepth(); - generateFishbonesMswExportInfo( caseToApply, - childWellPath, - initialChildMD, - childCellIntersections, - enableSegmentSplitting, - exportInfo, - childBranch.get() ); - branch->addChildBranch( std::move( childBranch ) ); - } + generateFishbonesMswExportInfo( eclipseCase, + childWellPath, + initialChildMD, + childCellIntersections, + enableSegmentSplitting, + exportInfo, + childMswBranch.get() ); + + branch->addChildBranch( std::move( childMswBranch ) ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportMswCompletionsImpl::generateFracturesMswExportInfo( RimEclipseCase* caseToApply, - const RimWellPath* wellPath ) +void RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfoForWell( const RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + gsl::not_null exportInfo, + gsl::not_null branch ) { - std::vector fractures = wellPath->fractureCollection()->activeFractures(); + double initialMD = 0.0; // Start measured depth location to export MSW data for. Either based on first intersection + // with active grid, or user defined value. - return generateFracturesMswExportInfo( caseToApply, wellPath, fractures ); + auto mswParameters = wellPath->fishbonesCollection()->mswParameters(); + auto cellIntersections = generateCellSegments( eclipseCase, wellPath, mswParameters, &initialMD ); + + RiaDefines::EclipseUnitSystem unitSystem = eclipseCase->eclipseCaseData()->unitsType(); + + bool enableSegmentSplitting = false; + generateFishbonesMswExportInfo( eclipseCase, wellPath, initialMD, cellIntersections, enableSegmentSplitting, exportInfo, branch ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RicMswExportInfo - RicWellPathExportMswCompletionsImpl::generateFracturesMswExportInfo( RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fractures ) +bool RicWellPathExportMswCompletionsImpl::generateFracturesMswExportInfo( + RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + double initialMD, + const std::vector& cellIntersections, + gsl::not_null exportInfo, + gsl::not_null branch ) { - const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); - const RigActiveCellInfo* activeCellInfo = - caseToApply->eclipseCaseData()->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL ); - RiaDefines::EclipseUnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); - - auto wellPathGeometry = wellPath->wellPathGeometry(); - CVF_ASSERT( wellPathGeometry ); - - const std::vector& coords = wellPathGeometry->wellPathPoints(); - const std::vector& mds = wellPathGeometry->measuredDepths(); - CVF_ASSERT( !coords.empty() && !mds.empty() ); - - std::vector intersections = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( caseToApply->eclipseCaseData(), - wellPath->name(), - coords, - mds ); - auto mswParameters = wellPath->fractureCollection()->mswParameters(); + auto fractures = wellPath->fractureCollection()->activeFractures(); - double initialMD = 0.0; - if ( mswParameters->referenceMDType() == RimMswCompletionParameters::MANUAL_REFERENCE_MD ) - { - initialMD = mswParameters->manualReferenceMD(); - } - else - { - for ( const WellPathCellIntersectionInfo& intersection : intersections ) - { - if ( activeCellInfo->isActive( intersection.globCellIndex ) ) - { - initialMD = intersection.startMD; - break; - } - } - - double startOfFirstCompletion = std::numeric_limits::infinity(); - { - for ( auto* fracture : fractures ) - { - if ( fracture->isEnabled() && fracture->startMD() < startOfFirstCompletion ) - { - startOfFirstCompletion = fracture->startMD(); - } - } - } - - // Initial MD is the lowest MD based on grid intersection and start of fracture completions - // https://github.com/OPM/ResInsight/issues/6071 - initialMD = std::min( initialMD, startOfFirstCompletion ); - } - - RicMswExportInfo exportInfo( wellPath, - unitSystem, - initialMD, - mswParameters->lengthAndDepth().text(), - mswParameters->pressureDrop().text() ); - - exportInfo.setLinerDiameter( mswParameters->linerDiameter( unitSystem ) ); - exportInfo.setRoughnessFactor( mswParameters->roughnessFactor( unitSystem ) ); + std::vector filteredIntersections = + filterIntersections( cellIntersections, initialMD, wellPath->wellPathGeometry(), eclipseCase ); bool foundSubGridIntersections = false; // Main bore - int mainBoreSegment = 1; - for ( const auto& cellIntInfo : intersections ) + const RigMainGrid* grid = eclipseCase->eclipseCaseData()->mainGrid(); + + for ( const auto& cellIntInfo : filteredIntersections ) { + if ( cellIntInfo.globCellIndex >= grid->globalCellArray().size() ) + { + continue; + } + size_t localGridIdx = 0u; const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx( cellIntInfo.globCellIndex, &localGridIdx ); @@ -1193,14 +625,14 @@ RicMswExportInfo if ( cvf::Math::valueInRange( fractureStartMD, cellIntInfo.startMD, cellIntInfo.endMD ) ) { std::vector completionData = - RicExportFractureCompletionsImpl::generateCompdatValues( caseToApply, + RicExportFractureCompletionsImpl::generateCompdatValues( eclipseCase, wellPath->completionSettings()->wellNameForExport(), wellPath->wellPathGeometry(), { fracture }, nullptr, nullptr ); - assignFractureCompletionsToCellSegment( caseToApply, + assignFractureCompletionsToCellSegment( eclipseCase, wellPath, fracture, completionData, @@ -1209,17 +641,34 @@ RicMswExportInfo } } - exportInfo.mainBoreBranch()->addSegment( std::move( segment ) ); + branch->addSegment( std::move( segment ) ); } - exportInfo.setHasSubGridIntersections( foundSubGridIntersections ); - exportInfo.mainBoreBranch()->sortSegments(); + exportInfo->setHasSubGridIntersections( foundSubGridIntersections ); + branch->sortSegments(); - int branchNumber = 1; - assignBranchNumbersToBranch( caseToApply, &exportInfo, exportInfo.mainBoreBranch(), &branchNumber ); + std::vector connectedWellPaths = wellPathsWithTieIn( wellPath ); + for ( auto childWellPath : connectedWellPaths ) + { + auto childMswBranch = createChildMswBranch( childWellPath ); + auto mswParameters = childWellPath->perforationIntervalCollection()->mswParameters(); - return exportInfo; + double startOfChildMD = 0.0; // this is currently not used, as the tie-in MD is used + auto childCellIntersections = generateCellSegments( eclipseCase, childWellPath, mswParameters, &startOfChildMD ); + auto initialChildMD = childWellPath->wellPathTieIn()->tieInMeasuredDepth(); + + if ( generateFracturesMswExportInfo( eclipseCase, + childWellPath, + initialChildMD, + childCellIntersections, + exportInfo, + childMswBranch.get() ) ) + { + branch->addChildBranch( std::move( childMswBranch ) ); + } + } + + return true; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1293,57 +742,29 @@ bool RicWellPathExportMswCompletionsImpl::generatePerforationsMswExportInfo( exportInfo->setHasSubGridIntersections( exportInfo->hasSubGridIntersections() || foundSubGridIntersections ); branch->sortSegments(); - if ( auto wellPathGroup = dynamic_cast( wellPath ); wellPathGroup != nullptr ) + std::vector connectedWellPaths = wellPathsWithTieIn( wellPath ); + + for ( auto childWellPath : connectedWellPaths ) { - auto mswParameters = wellPath->perforationIntervalCollection()->mswParameters(); + auto childMswBranch = createChildMswBranch( childWellPath ); + auto mswParameters = childWellPath->perforationIntervalCollection()->mswParameters(); - if ( !mswParameters ) + double startOfChildMD = 0.0; // this is currently not used, as the tie-in MD is used + auto childCellIntersections = generateCellSegments( eclipseCase, childWellPath, mswParameters, &startOfChildMD ); + auto initialChildMD = childWellPath->wellPathTieIn()->tieInMeasuredDepth(); + + if ( generatePerforationsMswExportInfo( eclipseCase, + childWellPath, + timeStep, + initialChildMD, + childCellIntersections, + exportInfo, + childMswBranch.get() ) ) { - RiaLogging::error( "generatePerforationsMswExportInfo: No mswParameters object found, aborting export" ); - } - else - { - auto initialChildMD = wellPathGroup->uniqueEndMD(); - auto initialChildTVD = -wellPathGroup->wellPathGeometry()->interpolatedPointAlongWellPath( initialMD ).z(); - for ( auto childWellPath : wellPathGroup->childWellPaths() ) - { - auto childCellIntersections = - generateCellSegments( eclipseCase, childWellPath, mswParameters, &initialChildMD ); - auto childBranch = - std::make_unique( childWellPath->name(), childWellPath, initialChildMD, initialChildTVD ); - - if ( wellPathGroup->outletValve() ) - { - childBranch = RicMswValve::createExportValve( QString( "%1 valve for %2" ) - .arg( wellPathGroup->outletValve()->componentLabel() ) - .arg( childWellPath->name() ), - childWellPath, - initialChildMD, - initialChildTVD, - wellPathGroup->outletValve() ); - auto dummySegment = std::make_unique< - RicMswSegment>( QString( "%1 segment" ).arg( wellPathGroup->outletValve()->componentLabel() ), - initialChildMD, - initialChildMD + 0.1, - initialChildTVD, - RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( wellPath, - initialChildMD + 0.1 ) ); - childBranch->addSegment( std::move( dummySegment ) ); - } - - if ( generatePerforationsMswExportInfo( eclipseCase, - childWellPath, - timeStep, - initialChildMD, - childCellIntersections, - exportInfo, - childBranch.get() ) ) - { - branch->addChildBranch( std::move( childBranch ) ); - } - } + branch->addChildBranch( std::move( childMswBranch ) ); } } + return true; } @@ -1373,6 +794,8 @@ std::vector wellPath->name(), coords, mds ); + if ( allIntersections.empty() ) return {}; + std::vector continuousIntersections = RigWellPathIntersectionTools::buildContinuousIntersections( allIntersections, mainGrid ); @@ -1602,15 +1025,11 @@ void RicWellPathExportMswCompletionsImpl::createValveCompletions( double exportStartMD = valveMD; double exportEndMD = valveMD + 0.1; - double exportStartTVD = - RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( wellPath, exportStartMD ); - double exportEndTVD = - RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( wellPath, exportEndMD ); + double exportStartTVD = RicMswTableFormatterTools::tvdFromMeasuredDepth( wellPath, exportStartMD ); + double exportEndTVD = RicMswTableFormatterTools::tvdFromMeasuredDepth( wellPath, exportEndMD ); - double overlapStartTVD = - RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( wellPath, overlapStart ); - double overlapEndTVD = - RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( wellPath, overlapEnd ); + double overlapStartTVD = RicMswTableFormatterTools::tvdFromMeasuredDepth( wellPath, overlapStart ); + double overlapEndTVD = RicMswTableFormatterTools::tvdFromMeasuredDepth( wellPath, overlapEnd ); if ( segment->startMD() <= valveMD && valveMD < segment->endMD() ) { @@ -1664,9 +1083,6 @@ void RicWellPathExportMswCompletionsImpl::createValveCompletions( exportStartTVD, valve ); ICV->addSegment( std::move( subSegment ) ); - ICV->setFlowCoefficient( valve->flowCoefficient() ); - double orificeRadius = valve->orificeDiameter( unitSystem ) / 2; - ICV->setArea( orificeRadius * orificeRadius * cvf::PI_D ); } } else if ( overlap > 0.0 && @@ -1926,214 +1342,6 @@ void RicWellPathExportMswCompletionsImpl::moveIntersectionsToICVs( } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::writeWelsegsSegment( RicMswSegment* segment, - const RicMswSegment* previousSegment, - RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - double maxSegmentLength, - gsl::not_null branch, - int* segmentNumber ) -{ - CVF_ASSERT( segment && segmentNumber ); - - double startMD = segment->startMD(); - double endMD = segment->endMD(); - - std::vector> segments = createSubSegmentMDPairs( startMD, endMD, maxSegmentLength ); - - CVF_ASSERT( branch->wellPath() ); - auto wellPathGeometry = branch->wellPath()->wellPathGeometry(); - CVF_ASSERT( wellPathGeometry ); - - double prevOutMD = branch->startMD(); - double prevOutTVD = branch->startTVD(); - if ( previousSegment ) - { - prevOutMD = previousSegment->outputMD(); - prevOutTVD = previousSegment->outputTVD(); - } - - auto outletSegment = previousSegment; - for ( const auto& [subStartMD, subEndMD] : segments ) - { - double depth = 0; - double length = 0; - - double midPointMD = 0.5 * ( subStartMD + subEndMD ); - double midPointTVD = tvdFromMeasuredDepth( branch->wellPath(), midPointMD ); - - if ( exportInfo.lengthAndDepthText() == QString( "INC" ) ) - { - depth = midPointTVD - prevOutTVD; - length = midPointMD - prevOutMD; - } - else - { - depth = midPointTVD; - length = midPointMD; - } - segment->setOutputMD( midPointMD ); - segment->setOutputTVD( midPointTVD ); - segment->setSegmentNumber( *segmentNumber ); - - formatter.add( *segmentNumber ).add( *segmentNumber ); - formatter.add( branch->branchNumber() ); - if ( outletSegment ) - formatter.add( outletSegment->segmentNumber() ); - else - formatter.add( 1 ); - formatter.add( length ); - formatter.add( depth ); - formatter.add( exportInfo.linerDiameter() ); - formatter.add( exportInfo.roughnessFactor() ); - formatter.rowCompleted(); - ( *segmentNumber )++; - outletSegment = segment; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::writeValveWelsegsSegment( const RicMswSegment* outletSegment, - RicMswValve* valve, - RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - double maxSegmentLength, - int* segmentNumber ) -{ - CVF_ASSERT( valve ); - if ( !valve->isValid() ) return; - - CVF_ASSERT( !valve->label().isEmpty() ); - CVF_ASSERT( valve->wellPath() ); - - formatter.addOptionalComment( valve->label() ); - - auto segments = valve->segments(); - - auto subSegment = segments.front(); - subSegment->setSegmentNumber( *segmentNumber ); - - double startMD = subSegment->startMD(); - double endMD = subSegment->endMD(); - - double midPointMD = 0.5 * ( startMD + endMD ); - double midPointTVD = tvdFromMeasuredDepth( valve->wellPath(), midPointMD ); - - subSegment->setOutputMD( midPointMD ); - subSegment->setOutputTVD( midPointTVD ); - - std::vector> splitSegments = createSubSegmentMDPairs( startMD, endMD, maxSegmentLength ); - - auto wellPathGeometry = valve->wellPath()->wellPathGeometry(); - CVF_ASSERT( wellPathGeometry ); - - for ( const auto& [subStartMD, subEndMD] : splitSegments ) - { - int subSegmentNumber = ( *segmentNumber )++; - - double subStartTVD = tvdFromMeasuredDepth( valve->wellPath(), subStartMD ); - double subEndTVD = tvdFromMeasuredDepth( valve->wellPath(), subEndMD ); - - double depth = 0; - double length = 0; - - if ( exportInfo.lengthAndDepthText() == QString( "INC" ) ) - { - depth = subEndTVD - subStartTVD; - length = subEndMD - subStartMD; - } - else - { - depth = subEndTVD; - length = subEndMD; - } - - formatter.add( subSegmentNumber ); - formatter.add( subSegmentNumber ); - formatter.add( valve->branchNumber() ); - formatter.add( outletSegment->segmentNumber() ); - - formatter.add( length ); - formatter.add( depth ); - formatter.add( exportInfo.linerDiameter() ); - formatter.add( exportInfo.roughnessFactor() ); - formatter.rowCompleted(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::writeCompletionWelsegsSegments( gsl::not_null outletSegment, - gsl::not_null completion, - RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - double maxSegmentLength, - int* segmentNumber ) -{ - writeWelsegsCompletionCommentHeader( formatter, completion->completionType() ); - - if ( completion->completionType() == RigCompletionData::FISHBONES ) - { - formatter.addOptionalComment( - QString( "Sub index %1 - %2" ).arg( outletSegment->subIndex() ).arg( completion->label() ) ); - } - else if ( completion->completionType() == RigCompletionData::FRACTURE ) - { - formatter.addOptionalComment( - QString( "%1 connected to segment %2" ).arg( completion->label() ).arg( outletSegment->segmentNumber() ) ); - } - - CVF_ASSERT( completion->wellPath() ); - - int outletSegmentNumber = outletSegment->segmentNumber(); - - for ( auto segment : completion->segments() ) - { - double startMD = segment->startMD(); - double endMD = segment->endMD(); - - std::vector> splitSegments = createSubSegmentMDPairs( startMD, endMD, maxSegmentLength ); - - for ( const auto& [subStartMD, subEndMD] : splitSegments ) - { - int subSegmentNumber = ( *segmentNumber )++; - - double subStartTVD = tvdFromMeasuredDepth( completion->wellPath(), subStartMD ); - double subEndTVD = tvdFromMeasuredDepth( completion->wellPath(), subEndMD ); - - double depth = 0; - double length = 0; - - if ( exportInfo.lengthAndDepthText() == QString( "INC" ) ) - { - depth = subEndTVD - subStartTVD; - length = subEndMD - subStartMD; - } - else - { - depth = subEndTVD; - length = subEndMD; - } - formatter.add( subSegmentNumber ); - formatter.add( subSegmentNumber ); - formatter.add( completion->branchNumber() ); - formatter.add( outletSegmentNumber ); - formatter.add( length ); - formatter.add( depth ); - formatter.add( outletSegment->effectiveDiameter() ); - formatter.add( outletSegment->openHoleRoughnessFactor() ); - formatter.rowCompleted(); - outletSegmentNumber = subSegmentNumber; - } - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -2180,16 +1388,17 @@ void RicWellPathExportMswCompletionsImpl::moveIntersectionsToSuperICDsOrAICDs( g //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::assignFishbonesLateralIntersections( const RimEclipseCase* caseToApply, +void RicWellPathExportMswCompletionsImpl::assignFishbonesLateralIntersections( const RimEclipseCase* eclipseCase, const RimWellPath* wellPath, const RimFishbones* fishbonesSubs, gsl::not_null segment, bool* foundSubGridIntersections, - double maxSegmentLength ) + double maxSegmentLength, + RiaDefines::EclipseUnitSystem unitSystem ) { CVF_ASSERT( foundSubGridIntersections != nullptr ); - const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); + const RigMainGrid* grid = eclipseCase->eclipseCaseData()->mainGrid(); for ( auto completion : segment->completions() ) { @@ -2219,7 +1428,7 @@ void RicWellPathExportMswCompletionsImpl::assignFishbonesLateralIntersections( c } std::vector intersections = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( caseToApply->eclipseCaseData(), + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( eclipseCase->eclipseCaseData(), wellPath->name(), lateralCoords, lateralMDs ); @@ -2231,9 +1440,9 @@ void RicWellPathExportMswCompletionsImpl::assignFishbonesLateralIntersections( c for ( const auto& cellIntInfo : intersections ) { - size_t localGridIdx = 0u; + size_t localGridCellIndex = 0u; const RigGridBase* localGrid = - grid->gridAndGridLocalIdxFromGlobalCellIdx( cellIntInfo.globCellIndex, &localGridIdx ); + grid->gridAndGridLocalIdxFromGlobalCellIdx( cellIntInfo.globCellIndex, &localGridCellIndex ); QString gridName; if ( localGrid != grid ) { @@ -2242,12 +1451,19 @@ void RicWellPathExportMswCompletionsImpl::assignFishbonesLateralIntersections( c } size_t i = 0u, j = 0u, k = 0u; - localGrid->ijkFromCellIndex( localGridIdx, &i, &j, &k ); + localGrid->ijkFromCellIndex( localGridCellIndex, &i, &j, &k ); auto subSegment = std::make_unique( "Sub segment", previousExitMD, cellIntInfo.endMD, previousExitTVD, - cellIntInfo.endTVD() ); + cellIntInfo.endTVD(), + segment->subIndex() ); + + subSegment->setEquivalentDiameter( fishbonesSubs->equivalentDiameter( unitSystem ) ); + subSegment->setHoleDiameter( fishbonesSubs->holeDiameter( unitSystem ) ); + subSegment->setOpenHoleRoughnessFactor( fishbonesSubs->openHoleRoughnessFactor( unitSystem ) ); + subSegment->setSkinFactor( fishbonesSubs->skinFactor() ); + subSegment->setSourcePdmObject( fishbonesSubs ); auto intersection = std::make_shared( gridName, cellIntInfo.globCellIndex, @@ -2265,7 +1481,7 @@ void RicWellPathExportMswCompletionsImpl::assignFishbonesLateralIntersections( c //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::assignFractureCompletionsToCellSegment( const RimEclipseCase* caseToApply, +void RicWellPathExportMswCompletionsImpl::assignFractureCompletionsToCellSegment( const RimEclipseCase* eclipseCase, const RimWellPath* wellPath, const RimWellPathFracture* fracture, const std::vector& completionData, @@ -2390,7 +1606,7 @@ void RicWellPathExportMswCompletionsImpl::assignPerforationIntersections( //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToPerforations( const RimEclipseCase* caseToApply, +void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToPerforations( const RimEclipseCase* eclipseCase, gsl::not_null segment, gsl::not_null branchNumber ) { @@ -2406,7 +1622,7 @@ void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToPerforations( con //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToOtherCompletions( const RimEclipseCase* caseToApply, +void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToOtherCompletions( const RimEclipseCase* eclipseCase, gsl::not_null segment, gsl::not_null branchNumber ) { @@ -2415,6 +1631,11 @@ void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToOtherCompletions( if ( completion->completionType() != RigCompletionData::PERFORATION ) { completion->setBranchNumber( ++( *branchNumber ) ); + + for ( auto seg : completion->segments() ) + { + assignBranchNumbersToOtherCompletions( eclipseCase, seg, branchNumber ); + } } } } @@ -2422,7 +1643,7 @@ void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToOtherCompletions( //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToBranch( const RimEclipseCase* caseToApply, +void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToBranch( const RimEclipseCase* eclipseCase, RicMswExportInfo* exportInfo, gsl::not_null branch, gsl::not_null branchNumber ) @@ -2432,33 +1653,105 @@ void RicWellPathExportMswCompletionsImpl::assignBranchNumbersToBranch( const Rim // Assign perforations first to ensure the same branch number as the segment for ( auto segment : branch->segments() ) { - assignBranchNumbersToPerforations( caseToApply, segment, branchNumber ); + assignBranchNumbersToPerforations( eclipseCase, segment, branchNumber ); } // Assign other completions with an incremented branch number for ( auto segment : branch->segments() ) { - assignBranchNumbersToOtherCompletions( caseToApply, segment, branchNumber ); + assignBranchNumbersToOtherCompletions( eclipseCase, segment, branchNumber ); } ( *branchNumber )++; for ( auto childBranch : branch->branches() ) { - assignBranchNumbersToBranch( caseToApply, exportInfo, childBranch, branchNumber ); + assignBranchNumbersToBranch( eclipseCase, exportInfo, childBranch, branchNumber ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double RicWellPathExportMswCompletionsImpl::tvdFromMeasuredDepth( gsl::not_null wellPath, - double measuredDepth ) +std::unique_ptr + RicWellPathExportMswCompletionsImpl::createChildMswBranch( const RimModeledWellPath* childWellPath ) { - auto wellPathGeometry = wellPath->wellPathGeometry(); - CVF_ASSERT( wellPathGeometry ); + auto initialChildMD = childWellPath->wellPathTieIn()->tieInMeasuredDepth(); + auto initialChildTVD = -childWellPath->wellPathGeometry()->interpolatedPointAlongWellPath( initialChildMD ).z(); - double tvdValue = -wellPathGeometry->interpolatedPointAlongWellPath( measuredDepth ).z(); + const RimWellPathValve* outletValve = childWellPath->wellPathTieIn()->outletValve(); + if ( outletValve ) + { + auto branchStartingWithValve = RicMswValve::createTieInValve( QString( "%1 valve for %2" ) + .arg( outletValve->componentLabel() ) + .arg( childWellPath->name() ), + childWellPath, + initialChildMD, + initialChildTVD, + outletValve ); + if ( branchStartingWithValve ) + { + auto dummySegment = + std::make_unique( QString( "%1 segment" ).arg( outletValve->componentLabel() ), + initialChildMD, + initialChildMD + 0.1, + initialChildTVD, + RicMswTableFormatterTools::tvdFromMeasuredDepth( childWellPath, + initialChildMD + 0.1 ) ); + branchStartingWithValve->addSegment( std::move( dummySegment ) ); - return tvdValue; + return branchStartingWithValve; + } + } + + auto childBranch = + std::make_unique( childWellPath->name(), childWellPath, initialChildMD, initialChildTVD ); + + return childBranch; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RicWellPathExportMswCompletionsImpl::wellPathsWithTieIn( const RimWellPath* wellPath ) +{ + std::vector connectedWellPaths; + { + auto wellPaths = RimProject::current()->allWellPaths(); + for ( auto w : wellPaths ) + { + auto modelWellPath = dynamic_cast( w ); + if ( modelWellPath && modelWellPath->wellPathTieIn() && modelWellPath->wellPathTieIn()->parentWell() == wellPath ) + { + connectedWellPaths.push_back( modelWellPath ); + } + } + } + + return connectedWellPaths; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RicWellPathExportMswCompletionsImpl::calculateOverlapWithActiveCells( + double startMD, + double endMD, + const std::vector& wellPathIntersections, + const RigActiveCellInfo* activeCellInfo ) +{ + for ( const WellPathCellIntersectionInfo& intersection : wellPathIntersections ) + { + if ( intersection.globCellIndex < activeCellInfo->reservoirCellCount() && + activeCellInfo->isActive( intersection.globCellIndex ) ) + { + double overlapStart = std::max( startMD, intersection.startMD ); + double overlapEnd = std::min( endMD, intersection.endMD ); + if ( overlapEnd > overlapStart ) + { + return std::make_pair( overlapStart, overlapEnd ); + } + } + } + return std::make_pair( 0.0, 0.0 ); } diff --git a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h index 6928e28b40..d87232be90 100644 --- a/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h +++ b/ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h @@ -21,24 +21,21 @@ #include "RicMswCompletions.h" #include "RicMswExportInfo.h" #include "RicMswSegment.h" -#include "RigCompletionData.h" #include #include class RicExportCompletionDataSettingsUi; -class RifTextDataTableFormatter; class RigActiveCellInfo; class RimEclipseCase; class RimFishbones; class RimPerforationInterval; class RimWellPath; -class RimWellPathValve; class RimWellPathFracture; class RimMswCompletionParameters; -class SubSegmentIntersectionInfo; class RigWellPath; +class RimModeledWellPath; struct WellPathCellIntersectionInfo; @@ -47,23 +44,6 @@ class QFile; class RicWellPathExportMswCompletionsImpl { private: - class CvfVec3stComparator - { - public: - bool operator()( const cvf::Vec3st& lhs, const cvf::Vec3st& rhs ) const - { - if ( lhs.z() == rhs.z() ) - { - if ( lhs.y() == rhs.y() ) - { - return lhs.x() < rhs.x(); - } - return lhs.y() < rhs.y(); - } - return lhs.z() < rhs.z(); - } - }; - public: static void exportWellSegmentsForAllCompletions( const RicExportCompletionDataSettingsUi& exportSettings, const std::vector& wellPaths ); @@ -71,20 +51,29 @@ public: static void exportWellSegmentsForFractures( RimEclipseCase* eclipseCase, std::shared_ptr exportFile, const RimWellPath* wellPath, - bool exportDataSourceAsComment ); + bool exportDataSourceAsComment, + bool completionSegmentsAfterMainBore ); static void exportWellSegmentsForFishbones( RimEclipseCase* eclipseCase, std::shared_ptr exportFile, const RimWellPath* wellPath, - bool exportDataSourceAsComment ); + bool exportDataSourceAsComment, + bool completionSegmentsAfterMainBore ); static void exportWellSegmentsForPerforations( RimEclipseCase* eclipseCase, std::shared_ptr exportFile, const RimWellPath* wellPath, int timeStep, - bool exportDataSourceAsComment ); + bool exportDataSourceAsComment, + bool completionSegmentsAfterMainBore ); - static void generateFishbonesMswExportInfo( const RimEclipseCase* caseToApply, + static void generateFishbonesMswExportInfoForWell( const RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + gsl::not_null exportInfo, + gsl::not_null branch ); + +private: + static void generateFishbonesMswExportInfo( const RimEclipseCase* eclipseCase, const RimWellPath* wellPath, double initialMD, const std::vector& cellIntersections, @@ -92,8 +81,7 @@ public: gsl::not_null exportInfo, gsl::not_null branch ); -private: - static void generateFishbonesMswExportInfo( const RimEclipseCase* caseToApply, + static void generateFishbonesMswExportInfo( const RimEclipseCase* eclipseCase, const RimWellPath* wellPath, double initialMD, const std::vector& cellIntersections, @@ -102,11 +90,12 @@ private: gsl::not_null exportInfo, gsl::not_null branch ); - static RicMswExportInfo generateFracturesMswExportInfo( RimEclipseCase* caseToApply, const RimWellPath* wellPath ); - - static RicMswExportInfo generateFracturesMswExportInfo( RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fractures ); + static bool generateFracturesMswExportInfo( RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + double initialMD, + const std::vector& cellIntersections, + gsl::not_null exportInfo, + gsl::not_null branch ); static bool generatePerforationsMswExportInfo( RimEclipseCase* eclipseCase, const RimWellPath* wellPath, @@ -127,64 +116,12 @@ private: gsl::not_null wellPathGeometry, gsl::not_null eclipseCase ); - static void generateWelsegsTable( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - double maxSegmentLength ); - - static void writeWelsegsSegmentsRecursively( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - gsl::not_null branch, - gsl::not_null segmentNumber, - double maxSegmentLength, - RicMswSegment* connectedToSegment = nullptr ); - - static void writeWelsegsSegment( RicMswSegment* segment, - const RicMswSegment* previousSegment, - RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - double maxSegmentLength, - gsl::not_null branch, - int* segmentNumber ); - static void writeValveWelsegsSegment( const RicMswSegment* outletSegment, - RicMswValve* valve, - RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - double maxSegmentLength, - int* segmentNumber ); - static void writeCompletionWelsegsSegments( gsl::not_null outletSegment, - gsl::not_null completion, - RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - double maxSegmentLength, - int* segmentNumber ); - - static void writeWelsegsCompletionCommentHeader( RifTextDataTableFormatter& formatter, - RigCompletionData::CompletionType completionType ); - static void generateCompsegTables( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ); - static void generateCompsegTable( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - gsl::not_null branch, - bool exportSubGridIntersections, - const std::set& exportCompletionTypes, - gsl::not_null headerGenerated, - gsl::not_null*> intersectedCells ); - static void generateCompsegHeader( RifTextDataTableFormatter& formatter, - RicMswExportInfo& exportInfo, - RigCompletionData::CompletionType completionType, - bool exportSubGridIntersections ); - static void generateWsegvalvTable( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ); - static void generateWsegAicdTable( RifTextDataTableFormatter& formatter, RicMswExportInfo& exportInfo ); - static std::pair calculateOverlapWithActiveCells( double startMD, double endMD, const std::vector& wellPathIntersections, const RigActiveCellInfo* activeCellInfo ); -private: - static std::vector> - createSubSegmentMDPairs( double startMD, double endMD, double maxSegmentLength ); - static void createWellPathSegments( gsl::not_null branch, const std::vector& cellSegmentIntersections, const std::vector& perforationIntervals, @@ -211,14 +148,15 @@ private: static void moveIntersectionsToSuperICDsOrAICDs( gsl::not_null branch ); - static void assignFishbonesLateralIntersections( const RimEclipseCase* caseToApply, + static void assignFishbonesLateralIntersections( const RimEclipseCase* eclipseCase, const RimWellPath* wellPath, const RimFishbones* fishbonesSubs, gsl::not_null segment, bool* foundSubGridIntersections, - double maxSegmentLength ); + double maxSegmentLength, + RiaDefines::EclipseUnitSystem unitSystem ); - static void assignFractureCompletionsToCellSegment( const RimEclipseCase* caseToApply, + static void assignFractureCompletionsToCellSegment( const RimEclipseCase* eclipseCase, const RimWellPath* wellPath, const RimWellPathFracture* fracture, const std::vector& completionData, @@ -238,17 +176,19 @@ private: double overlapEnd, bool* foundSubGridIntersections ); - static void assignBranchNumbersToPerforations( const RimEclipseCase* caseToApply, + static void assignBranchNumbersToPerforations( const RimEclipseCase* eclipseCase, gsl::not_null segment, gsl::not_null branchNumber ); - static void assignBranchNumbersToOtherCompletions( const RimEclipseCase* caseToApply, + static void assignBranchNumbersToOtherCompletions( const RimEclipseCase* eclipseCase, gsl::not_null segment, gsl::not_null branchNumber ); - static void assignBranchNumbersToBranch( const RimEclipseCase* caseToApply, + static void assignBranchNumbersToBranch( const RimEclipseCase* eclipseCase, RicMswExportInfo* exportInfo, gsl::not_null branch, gsl::not_null branchNumber ); - static double tvdFromMeasuredDepth( gsl::not_null wellPath, double measuredDepth ); + static std::unique_ptr createChildMswBranch( const RimModeledWellPath* childWellPath ); + + static std::vector wellPathsWithTieIn( const RimWellPath* wellPath ); }; diff --git a/ApplicationLibCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp b/ApplicationLibCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp index 86bb0e14b8..cc655973a7 100644 --- a/ApplicationLibCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp +++ b/ApplicationLibCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp @@ -143,7 +143,8 @@ void RicEclipseCellResultToFileImpl::writeDataToTextFile( QFile* textstream << "\n"; textstream << "-- Exported from ResInsight" << "\n"; - textstream << eclipseKeyword << "\n" << right << qSetFieldWidth( 16 ); + textstream << eclipseKeyword << "\n" << qSetFieldWidth( 16 ); + textstream.setFieldAlignment( QTextStream::AlignRight ); caf::ProgressInfo pi( resultData.size(), QString( "Writing data to file %1" ).arg( file->fileName() ) ); size_t progressSteps = resultData.size() / 20; diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicNewWellPathLateralAtDepthFeature.cpp b/ApplicationLibCode/Commands/WellPathCommands/RicNewWellPathLateralAtDepthFeature.cpp index 8c9065e651..369911ac11 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicNewWellPathLateralAtDepthFeature.cpp +++ b/ApplicationLibCode/Commands/WellPathCommands/RicNewWellPathLateralAtDepthFeature.cpp @@ -15,6 +15,7 @@ // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #include "RicNewWellPathLateralAtDepthFeature.h" #include "WellPathCommands/RicWellPathsUnitSystemSettingsImpl.h" @@ -23,12 +24,11 @@ #include "RimFishbones.h" #include "RimFishbonesCollection.h" #include "RimModeledWellPath.h" -#include "RimOilField.h" #include "RimProject.h" +#include "RimTools.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" #include "RimWellPathGeometryDef.h" -#include "RimWellPathGroup.h" #include "RimWellPathTarget.h" #include "Riu3DMainWindowTools.h" @@ -38,6 +38,7 @@ #include +#include "RiaTextStringTools.h" #include CAF_CMD_SOURCE_INIT( RicNewWellPathLateralAtDepthFeature, "RicNewWellPathLateralAtDepthFeature" ); @@ -63,56 +64,44 @@ void RicNewWellPathLateralAtDepthFeature::onActionTriggered( bool isChecked ) RiuWellPathSelectionItem* wellPathSelItem = wellPathSelectionItem(); CVF_ASSERT( wellPathSelItem ); - RimWellPath* wellPath = wellPathSelItem->m_wellpath; - CVF_ASSERT( wellPath ); - RimWellPathGroup* wellPathGroup = nullptr; - wellPath->firstAncestorOrThisOfType( wellPathGroup ); + RimWellPath* parentWellPath = wellPathSelItem->m_wellpath; + CVF_ASSERT( parentWellPath ); - RimProject* project = RimProject::current(); - if ( project && RimProject::current()->activeOilField() ) + RimProject* project = RimProject::current(); + RimWellPathCollection* wellPathColl = RimTools::wellPathCollection(); + if ( project && wellPathColl ) { - RimWellPathCollection* wellPathCollection = RimProject::current()->activeOilField()->wellPathCollection(); + double parentWellMD = wellPathSelItem->m_measuredDepth; - if ( wellPathCollection ) - { - auto newModeledWellPath = new RimModeledWellPath(); + auto newModeledWellPath = new RimModeledWellPath(); - auto [pointVector, measuredDepths] = - wellPath->wellPathGeometry()->clippedPointSubset( wellPath->wellPathGeometry()->measuredDepths().front(), - wellPathSelItem->m_measuredDepth ); - if ( pointVector.size() < 2u ) return; - newModeledWellPath->geometryDefinition()->setMdAtFirstTarget( measuredDepths.back() ); - newModeledWellPath->geometryDefinition()->setUseAutoGeneratedTargetAtSeaLevel( false ); - newModeledWellPath->geometryDefinition()->setFixedWellPathPoints( pointVector ); - newModeledWellPath->geometryDefinition()->setFixedMeasuredDepths( measuredDepths ); - newModeledWellPath->setName( wellPath->name() + QString( " md=%1" ).arg( wellPathSelItem->m_measuredDepth ) ); + auto [pointVector, measuredDepths] = + parentWellPath->wellPathGeometry() + ->clippedPointSubset( parentWellPath->wellPathGeometry()->measuredDepths().front(), parentWellMD ); + if ( pointVector.size() < 2u ) return; - { - RimWellPathTarget* newTarget = newModeledWellPath->geometryDefinition()->appendTarget(); - auto lastPoint = pointVector.back(); - auto tangent = lastPoint - pointVector[pointVector.size() - 2]; - newTarget->setAsPointXYZAndTangentTarget( { lastPoint[0], lastPoint[1], lastPoint[2] }, tangent ); - } + newModeledWellPath->geometryDefinition()->setIsAttachedToParentWell( true ); + newModeledWellPath->geometryDefinition()->setMdAtFirstTarget( measuredDepths.back() ); + newModeledWellPath->geometryDefinition()->setUseAutoGeneratedTargetAtSeaLevel( false ); + newModeledWellPath->geometryDefinition()->setFixedWellPathPoints( pointVector ); + newModeledWellPath->geometryDefinition()->setFixedMeasuredDepths( measuredDepths ); - newModeledWellPath->geometryDefinition()->enableTargetPointPicking( true ); + auto nameOfNewWell = updateNameOfParentAndFindNameOfSideStep( parentWellPath ); + newModeledWellPath->setName( nameOfNewWell ); + newModeledWellPath->connectWellPaths( parentWellPath, parentWellMD ); - newModeledWellPath->createWellPathGeometry(); - if ( wellPathGroup ) - { - wellPathGroup->addChildWellPath( newModeledWellPath ); - } - else - { - bool importedWellPath = false; - wellPathCollection->addWellPath( newModeledWellPath, importedWellPath ); - wellPathCollection->groupWellPaths( { wellPath, newModeledWellPath } ); - } - newModeledWellPath->firstAncestorOrThisOfTypeAsserted( wellPathGroup ); - wellPathGroup->updateAllRequiredEditors(); - project->scheduleCreateDisplayModelAndRedrawAllViews(); + newModeledWellPath->geometryDefinition()->enableTargetPointPicking( true ); + newModeledWellPath->setUnitSystem( parentWellPath->unitSystem() ); - Riu3DMainWindowTools::selectAsCurrentItem( newModeledWellPath->geometryDefinition() ); - } + newModeledWellPath->createWellPathGeometry(); + + bool importGrouped = false; + wellPathColl->addWellPath( newModeledWellPath, importGrouped ); + wellPathColl->updateAllRequiredEditors(); + + project->scheduleCreateDisplayModelAndRedrawAllViews(); + + Riu3DMainWindowTools::selectAsCurrentItem( newModeledWellPath->geometryDefinition() ); } } @@ -137,3 +126,76 @@ RiuWellPathSelectionItem* RicNewWellPathLateralAtDepthFeature::wellPathSelection return wellPathItem; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicNewWellPathLateralAtDepthFeature::updateNameOfParentAndFindNameOfSideStep( RimWellPath* parentwWellPath ) +{ + if ( !parentwWellPath ) return ""; + + QString nameOfNewWell; + + auto topLevelWell = parentwWellPath->topLevelWellPath(); + + QStringList allNames; + { + RimProject* proj = RimProject::current(); + const std::vector& wellPaths = proj->allWellPaths(); + + for ( auto wellPath : wellPaths ) + { + if ( wellPath ) + { + auto currentTopLevelWell = wellPath->topLevelWellPath(); + if ( topLevelWell == currentTopLevelWell ) + { + allNames.push_back( wellPath->name() ); + } + } + } + } + + if ( allNames.size() == 1 ) + { + QString name = parentwWellPath->name(); + + if ( name.contains( "Y1" ) ) + { + nameOfNewWell = name.replace( "Y1", "Y2" ); + } + else + { + parentwWellPath->setNameNoUpdateOfExportName( name + " Y1" ); + nameOfNewWell = name + " Y2"; + } + + return nameOfNewWell; + } + + { + QString commonRoot = RiaTextStringTools::commonRoot( allNames ); + QString trimmedCommonRoot = RiaTextStringTools::trimNonAlphaNumericCharacters( commonRoot ); + + // Remove side step prefix + trimmedCommonRoot.replace( " Y", "" ); + + int maxYValue = 0; + for ( auto n : allNames ) + { + auto suffix = n.replace( trimmedCommonRoot, "" ); + + int candidate = suffix.toInt(); + maxYValue = std::max( maxYValue, candidate ); + } + + if ( !trimmedCommonRoot.isEmpty() && trimmedCommonRoot.endsWith( "Y" ) ) + { + trimmedCommonRoot = trimmedCommonRoot.left( trimmedCommonRoot.size() - 1 ).trimmed(); + } + + nameOfNewWell = QString( "%1 Y%2" ).arg( trimmedCommonRoot ).arg( maxYValue + 1 ); + } + + return nameOfNewWell; +} diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicNewWellPathLateralAtDepthFeature.h b/ApplicationLibCode/Commands/WellPathCommands/RicNewWellPathLateralAtDepthFeature.h index 02333ddffd..89659b8e86 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicNewWellPathLateralAtDepthFeature.h +++ b/ApplicationLibCode/Commands/WellPathCommands/RicNewWellPathLateralAtDepthFeature.h @@ -21,6 +21,7 @@ #include "cafCmdFeature.h" class RiuWellPathSelectionItem; +class RimWellPath; //================================================================================================== /// @@ -37,4 +38,5 @@ protected: private: static RiuWellPathSelectionItem* wellPathSelectionItem(); + QString updateNameOfParentAndFindNameOfSideStep( RimWellPath* parentwWellPath ); }; diff --git a/ApplicationLibCode/FileInterface/RifEclipseInputFileTools.cpp b/ApplicationLibCode/FileInterface/RifEclipseInputFileTools.cpp index 50581be4bc..4e6be80240 100644 --- a/ApplicationLibCode/FileInterface/RifEclipseInputFileTools.cpp +++ b/ApplicationLibCode/FileInterface/RifEclipseInputFileTools.cpp @@ -562,12 +562,12 @@ void RifEclipseInputFileTools::saveFault( QString } QTextStream stream( &exportFile ); - stream << "FAULTS" << endl; + stream << "FAULTS" << '\n'; - stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << endl; + stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << '\n'; saveFault( stream, mainGrid, faultFaces, faultName, min, maxIn, refinement ); - stream << "/" << endl; + stream << "/" << '\n'; } //-------------------------------------------------------------------------------------------------- @@ -744,9 +744,9 @@ void RifEclipseInputFileTools::saveFaults( QTextStream& stream, const cvf::Vec3st& max /*= cvf::Vec3st::UNDEFINED*/, const cvf::Vec3st& refinement /*= cvf::Vec3st(1, 1, 1)*/ ) { - stream << "FAULTS" << endl; + stream << "FAULTS" << '\n'; - stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << endl; + stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << '\n'; const cvf::Collection& faults = mainGrid->faults(); for ( const auto& fault : faults ) @@ -757,7 +757,7 @@ void RifEclipseInputFileTools::saveFaults( QTextStream& stream, saveFault( stream, mainGrid, fault->faultFaces(), fault->name(), min, max, refinement ); } } - stream << "/" << endl; + stream << "/" << '\n'; } //-------------------------------------------------------------------------------------------------- @@ -1319,7 +1319,7 @@ void RifEclipseInputFileTools::writeFaultLine( QTextStream& stream << "'" << faultName << "'" << " " << i << " " << i << " " << j << " " << j << " " << startK << " " << endK << " " << faultFaceText( faceType ) << " / "; - stream << endl; + stream << '\n'; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/FileInterface/RifStimPlanModelAsymmetricFrkExporter.cpp b/ApplicationLibCode/FileInterface/RifStimPlanModelAsymmetricFrkExporter.cpp index eaff6fbb60..f9042c54e3 100644 --- a/ApplicationLibCode/FileInterface/RifStimPlanModelAsymmetricFrkExporter.cpp +++ b/ApplicationLibCode/FileInterface/RifStimPlanModelAsymmetricFrkExporter.cpp @@ -62,7 +62,7 @@ bool RifStimPlanModelAsymmetricFrkExporter::writeToFile( RimStimPlanModel* stimP //-------------------------------------------------------------------------------------------------- void RifStimPlanModelAsymmetricFrkExporter::appendHeaderToStream( QTextStream& stream ) { - stream << "" << endl << "" << endl; + stream << "" << '\n' << "" << '\n'; } //-------------------------------------------------------------------------------------------------- @@ -75,21 +75,21 @@ void RifStimPlanModelAsymmetricFrkExporter::appendBarrierDataToStream( QTextStre double barrierDipDeg, int wellPenetrationLayer ) { - stream << "" << endl - << bedDipDeg << endl - << "" << endl - << "" << endl - << static_cast( hasBarrier ) << endl - << "" << endl - << "" << endl - << barrierDipDeg << endl - << "" << endl - << "" << endl - << distanceToBarrier << endl - << "" << endl - << "" << endl - << wellPenetrationLayer << endl - << "" << endl; + stream << "" << '\n' + << bedDipDeg << '\n' + << "" << '\n' + << "" << '\n' + << static_cast( hasBarrier ) << '\n' + << "" << '\n' + << "" << '\n' + << barrierDipDeg << '\n' + << "" << '\n' + << "" << '\n' + << distanceToBarrier << '\n' + << "" << '\n' + << "" << '\n' + << wellPenetrationLayer << '\n' + << "" << '\n'; } //-------------------------------------------------------------------------------------------------- @@ -97,5 +97,5 @@ void RifStimPlanModelAsymmetricFrkExporter::appendBarrierDataToStream( QTextStre //-------------------------------------------------------------------------------------------------- void RifStimPlanModelAsymmetricFrkExporter::appendFooterToStream( QTextStream& stream ) { - stream << "" << endl; + stream << "" << '\n'; } diff --git a/ApplicationLibCode/FileInterface/RifStimPlanModelDeviationFrkExporter.cpp b/ApplicationLibCode/FileInterface/RifStimPlanModelDeviationFrkExporter.cpp index 4465756e38..8736b9dcac 100644 --- a/ApplicationLibCode/FileInterface/RifStimPlanModelDeviationFrkExporter.cpp +++ b/ApplicationLibCode/FileInterface/RifStimPlanModelDeviationFrkExporter.cpp @@ -75,7 +75,7 @@ bool RifStimPlanModelDeviationFrkExporter::writeToFile( RimStimPlanModel* stimPl //-------------------------------------------------------------------------------------------------- void RifStimPlanModelDeviationFrkExporter::appendHeaderToStream( QTextStream& stream ) { - stream << "" << endl << "" << endl; + stream << "" << '\n' << "" << '\n'; } //-------------------------------------------------------------------------------------------------- @@ -86,23 +86,23 @@ void RifStimPlanModelDeviationFrkExporter::appendToStream( QTextStream& const std::vector& values ) { stream.setRealNumberPrecision( 20 ); - stream << "" << endl - << "" << endl - << label << endl - << "" << endl - << "" << endl - << 1 << endl - << "" << endl - << "" << endl - << values.size() << endl - << "" << endl - << "" << endl; + stream << "" << '\n' + << "" << '\n' + << label << '\n' + << "" << '\n' + << "" << '\n' + << 1 << '\n' + << "" << '\n' + << "" << '\n' + << values.size() << '\n' + << "" << '\n' + << "" << '\n'; for ( auto val : values ) { - stream << val << endl; + stream << val << '\n'; } - stream << "" << endl << "" << endl; + stream << "" << '\n' << "" << '\n'; } //-------------------------------------------------------------------------------------------------- @@ -110,7 +110,7 @@ void RifStimPlanModelDeviationFrkExporter::appendToStream( QTextStream& //-------------------------------------------------------------------------------------------------- void RifStimPlanModelDeviationFrkExporter::appendFooterToStream( QTextStream& stream ) { - stream << "" << endl; + stream << "" << '\n'; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.cpp b/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.cpp index e76ed01dfe..d2794aa3d5 100644 --- a/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.cpp +++ b/ApplicationLibCode/FileInterface/RifStimPlanModelGeologicalFrkExporter.cpp @@ -234,7 +234,7 @@ bool RifStimPlanModelGeologicalFrkExporter::writeToCsvFile( const QString& //-------------------------------------------------------------------------------------------------- void RifStimPlanModelGeologicalFrkExporter::appendHeaderToStream( QTextStream& stream ) { - stream << "" << endl << "" << endl; + stream << "" << '\n' << "" << endl; } //-------------------------------------------------------------------------------------------------- @@ -260,7 +260,7 @@ void RifStimPlanModelGeologicalFrkExporter::appendToStream( QTextStream& stream << val << endl; } - stream << "" << endl << "" << endl; + stream << "" << '\n' << "" << endl; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.cpp b/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.cpp index cfc52dad77..9df42a1975 100644 --- a/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.cpp +++ b/ApplicationLibCode/FileInterface/RifStimPlanModelPerfsFrkExporter.cpp @@ -80,7 +80,7 @@ bool RifStimPlanModelPerfsFrkExporter::writeToFile( RimStimPlanModel* stimPlanMo //-------------------------------------------------------------------------------------------------- void RifStimPlanModelPerfsFrkExporter::appendHeaderToStream( QTextStream& stream ) { - stream << "" << endl << "" << endl; + stream << "" << '\n' << "" << endl; } //-------------------------------------------------------------------------------------------------- @@ -88,7 +88,7 @@ void RifStimPlanModelPerfsFrkExporter::appendHeaderToStream( QTextStream& stream //-------------------------------------------------------------------------------------------------- void RifStimPlanModelPerfsFrkExporter::appendFractureOrientationToStream( QTextStream& stream, bool isTransverse ) { - stream << "" << endl << static_cast( isTransverse ) << endl << "" << endl; + stream << "" << '\n' << static_cast( isTransverse ) << '\n' << "" << endl; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ModelVisualization/RivWellPathPartMgr.cpp b/ApplicationLibCode/ModelVisualization/RivWellPathPartMgr.cpp index 6a30522403..0655793a95 100644 --- a/ApplicationLibCode/ModelVisualization/RivWellPathPartMgr.cpp +++ b/ApplicationLibCode/ModelVisualization/RivWellPathPartMgr.cpp @@ -32,8 +32,7 @@ #include "RimEclipseView.h" #include "RimFishbones.h" #include "RimFishbonesCollection.h" -#include "RimImportedFishboneLaterals.h" -#include "RimImportedFishboneLateralsCollection.h" +#include "RimModeledWellPath.h" #include "RimPerforationCollection.h" #include "RimPerforationInterval.h" #include "RimRegularLegendConfig.h" @@ -49,6 +48,8 @@ #include "RimWellPathCollection.h" #include "RimWellPathFracture.h" #include "RimWellPathFractureCollection.h" +#include "RimWellPathGeometryDef.h" +#include "RimWellPathTarget.h" #include "RimWellPathValve.h" #include "Riv3dWellLogPlanePartMgr.h" @@ -67,12 +68,18 @@ #include "cafDisplayCoordTransform.h" #include "cafEffectGenerator.h" + #include "cvfDrawableGeo.h" #include "cvfDrawableText.h" +#include "cvfDrawableVectors.h" #include "cvfFont.h" +#include "cvfGeometryBuilderTriangles.h" +#include "cvfGeometryUtils.h" #include "cvfModelBasicList.h" +#include "cvfOpenGLResourceManager.h" #include "cvfPart.h" #include "cvfScalarMapperContinuousLinear.h" +#include "cvfShaderProgram.h" #include "cvfTransform.h" #include "cvfqtUtils.h" @@ -362,40 +369,6 @@ void RivWellPathPartMgr::appendWellMeasurementsToModel( cvf::ModelBasicList* } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RivWellPathPartMgr::appendImportedFishbonesToModel( cvf::ModelBasicList* model, - const caf::DisplayCoordTransform* displayCoordTransform, - double characteristicCellSize ) -{ - if ( !m_rimWellPath || !m_rimWellPath->fishbonesCollection()->wellPathCollection()->isChecked() ) return; - - RivPipeGeometryGenerator geoGenerator; - std::vector fishbonesWellPaths; - m_rimWellPath->descendantsIncludingThisOfType( fishbonesWellPaths ); - for ( RimImportedFishboneLaterals* fbWellPath : fishbonesWellPaths ) - { - if ( !fbWellPath->isChecked() ) continue; - - std::vector displayCoords = - displayCoordTransform->transformToDisplayCoords( fbWellPath->coordinates() ); - - cvf::ref objectSourceInfo = new RivObjectSourceInfo( fbWellPath ); - - cvf::Collection parts; - geoGenerator.cylinderWithCenterLineParts( &parts, - displayCoords, - m_rimWellPath->wellPathColor(), - m_rimWellPath->combinedScaleFactor() * characteristicCellSize * 0.5 ); - for ( auto part : parts ) - { - part->setSourceInfo( objectSourceInfo.p() ); - model->addPart( part.p() ); - } - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -783,6 +756,73 @@ void RivWellPathPartMgr::buildWellPathParts( const caf::DisplayCoordTransform* d m_wellLabelPart = part; } + + auto modeledWellPath = dynamic_cast( m_rimWellPath.p() ); + if ( modeledWellPath ) + { + bool showWellTargetSpheres = modeledWellPath->geometryDefinition()->showSpheres(); + + if ( showWellTargetSpheres ) + { + auto geoDef = modeledWellPath->geometryDefinition(); + + auto sphereColor = geoDef->sphereColor(); + double sphereRadiusFactor = geoDef->sphereRadiusFactor(); + + cvf::ref vertices = new cvf::Vec3fArray; + cvf::ref vecRes = new cvf::Vec3fArray; + cvf::ref colors = new cvf::Color3fArray; + + auto wellTargets = geoDef->activeWellTargets(); + + size_t pointCount = wellTargets.size(); + vertices->reserve( pointCount ); + vecRes->reserve( pointCount ); + colors->reserve( pointCount ); + + for ( const auto target : wellTargets ) + { + auto domainCoord = target->targetPointXYZ() + modeledWellPath->geometryDefinition()->anchorPointXyz(); + auto displayCoord = displayCoordTransform->transformToDisplayCoord( domainCoord ); + vertices->add( cvf::Vec3f( displayCoord ) ); + vecRes->add( cvf::Vec3f::X_AXIS ); + colors->add( sphereColor ); + } + + cvf::ref vectorDrawable; + if ( RiaGuiApplication::instance()->useShaders() ) + { + vectorDrawable = new cvf::DrawableVectors( "u_transformationMatrix", "u_color" ); + } + else + { + vectorDrawable = new cvf::DrawableVectors(); + } + + vectorDrawable->setVectors( vertices.p(), vecRes.p() ); + vectorDrawable->setColors( colors.p() ); + + double cellRadius = 15.0; + auto eclipseView = dynamic_cast( m_rimView.p() ); + if ( eclipseView ) + { + double characteristicCellSize = eclipseView->mainGrid()->characteristicIJCellSize(); + cellRadius = sphereRadiusFactor * characteristicCellSize; + } + + cvf::GeometryBuilderTriangles builder; + cvf::GeometryUtils::createSphere( cellRadius, 15, 15, &builder ); + vectorDrawable->setGlyph( builder.trianglesUShort().p(), builder.vertices().p() ); + + cvf::ref part = new cvf::Part; + part->setName( "RivWellPathPartMgr_WellTargetSpheres" ); + part->setDrawable( vectorDrawable.p() ); + + part->setEffect( new cvf::Effect() ); + + m_spherePart = part; + } + } } //-------------------------------------------------------------------------------------------------- @@ -813,8 +853,12 @@ void RivWellPathPartMgr::appendStaticGeometryPartsToModel( cvf::ModelBasicList* model->addPart( m_wellLabelPart.p() ); } + if ( m_spherePart.notNull() ) + { + model->addPart( m_spherePart.p() ); + } + appendFishboneSubsPartsToModel( model, displayCoordTransform, characteristicCellSize ); - appendImportedFishbonesToModel( model, displayCoordTransform, characteristicCellSize ); appendWellPathAttributesToModel( model, displayCoordTransform, characteristicCellSize ); RimGridView* gridView = dynamic_cast( m_rimView.p() ); @@ -852,6 +896,11 @@ void RivWellPathPartMgr::appendFlattenedStaticGeometryPartsToModel( cvf::ModelBa { model->addPart( m_wellLabelPart.p() ); } + + if ( m_spherePart.notNull() ) + { + model->addPart( m_spherePart.p() ); + } } //-------------------------------------------------------------------------------------------------- @@ -923,6 +972,7 @@ void RivWellPathPartMgr::clearAllBranchData() m_centerLinePart = nullptr; m_centerLineDrawable = nullptr; m_wellLabelPart = nullptr; + m_spherePart = nullptr; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ModelVisualization/RivWellPathPartMgr.h b/ApplicationLibCode/ModelVisualization/RivWellPathPartMgr.h index df6c82bf06..b63d846426 100644 --- a/ApplicationLibCode/ModelVisualization/RivWellPathPartMgr.h +++ b/ApplicationLibCode/ModelVisualization/RivWellPathPartMgr.h @@ -98,9 +98,6 @@ private: const caf::DisplayCoordTransform* displayCoordTransform, double characteristicCellSize ); - void appendImportedFishbonesToModel( cvf::ModelBasicList* model, - const caf::DisplayCoordTransform* displayCoordTransform, - double characteristicCellSize ); void appendPerforationsToModel( cvf::ModelBasicList* model, size_t timeStepIndex, @@ -147,6 +144,7 @@ private: cvf::ref m_centerLinePart; cvf::ref m_centerLineDrawable; cvf::ref m_wellLabelPart; + cvf::ref m_spherePart; cvf::ref m_3dWellLogPlanePartMgr; cvf::ref m_wellConnectionFactorPartMgr; diff --git a/ApplicationLibCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/CMakeLists_files.cmake index f32d11f6d4..7b4acd5715 100644 --- a/ApplicationLibCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationLibCode/ProjectDataModel/CMakeLists_files.cmake @@ -152,6 +152,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimCustomObjectiveFunctionWeight.h ${CMAKE_CURRENT_LIST_DIR}/RimEquilibriumAxisAnnotation.h ${CMAKE_CURRENT_LIST_DIR}/RimTimeAxisAnnotation.h ${CMAKE_CURRENT_LIST_DIR}/RimPolylinesDataInterface.h +${CMAKE_CURRENT_LIST_DIR}/RimWellPathTieIn.h ) @@ -304,6 +305,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimCustomObjectiveFunction.cpp ${CMAKE_CURRENT_LIST_DIR}/RimCustomObjectiveFunctionWeight.cpp ${CMAKE_CURRENT_LIST_DIR}/RimEquilibriumAxisAnnotation.cpp ${CMAKE_CURRENT_LIST_DIR}/RimTimeAxisAnnotation.cpp +${CMAKE_CURRENT_LIST_DIR}/RimWellPathTieIn.cpp ) if(Qt5Charts_FOUND) diff --git a/ApplicationLibCode/ProjectDataModel/Completions/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/Completions/CMakeLists_files.cmake index 29449a5a82..1b4895bb55 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/CMakeLists_files.cmake +++ b/ApplicationLibCode/ProjectDataModel/Completions/CMakeLists_files.cmake @@ -42,8 +42,6 @@ ${CMAKE_CURRENT_LIST_DIR}/RimCompletionCellIntersectionCalc.cpp ${CMAKE_CURRENT_LIST_DIR}/RimFishbonesCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimFishbones.cpp ${CMAKE_CURRENT_LIST_DIR}/RimFishbonesPipeProperties.cpp -${CMAKE_CURRENT_LIST_DIR}/RimImportedFishboneLaterals.cpp -${CMAKE_CURRENT_LIST_DIR}/RimImportedFishboneLateralsCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimPerforationCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimPerforationInterval.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellPathCompletions.cpp diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimFishbones.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimFishbones.cpp index 071726fb54..b995b3f6dd 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimFishbones.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimFishbones.cpp @@ -24,6 +24,7 @@ #include "RigFishbonesGeometry.h" #include "RigWellPath.h" #include "RimFishbonesCollection.h" +#include "RimFishbonesPipeProperties.h" #include "RimMultipleValveLocations.h" #include "RimProject.h" #include "RimWellPath.h" @@ -185,7 +186,7 @@ QString RimFishbones::generatedName() const dynamic_cast*>( this->parentField() ); CVF_ASSERT( container ); - size_t index = container->index( this ); + size_t index = container->index( this ) + 1; return QString( "Fishbone %1" ).arg( index ); } @@ -278,7 +279,17 @@ double RimFishbones::tubingDiameter( RiaDefines::EclipseUnitSystem unitSystem ) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double RimFishbones::effectiveDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const +double RimFishbones::holeDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const +{ + return m_pipeProperties()->holeDiameter( unitSystem ); +} + +//-------------------------------------------------------------------------------------------------- +/// Compute the equivalent diameter based on the area between two cylinders +// +// http://www.fekete.com/san/webhelp/feketeharmony/harmony_webhelp/content/html_files/reference_material/calculations_and_correlations/annular_diameters.htm +//-------------------------------------------------------------------------------------------------- +double RimFishbones::equivalentDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const { double innerRadius = tubingDiameter( unitSystem ) / 2; double outerRadius = holeDiameter( unitSystem ) / 2; @@ -286,12 +297,20 @@ double RimFishbones::effectiveDiameter( RiaDefines::EclipseUnitSystem unitSystem double innerArea = cvf::PI_D * innerRadius * innerRadius; double outerArea = cvf::PI_D * outerRadius * outerRadius; - double effectiveArea = outerArea - innerArea; + double equivalentArea = outerArea - innerArea; - double effectiveRadius = cvf::Math::sqrt( effectiveArea / cvf::PI_D ); + double effectiveRadius = cvf::Math::sqrt( equivalentArea / cvf::PI_D ); return effectiveRadius * 2; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimFishbones::skinFactor() const +{ + return m_pipeProperties()->skinFactor(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -382,6 +401,14 @@ void RimFishbones::geometryUpdated() proj->reloadCompletionTypeResultsInAllViews(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RimFishbones::installedLateralIndices() const +{ + return m_subLateralIndices; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -613,13 +640,13 @@ void RimFishbones::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& u } { - caf::PdmUiGroup* wellGroup = uiOrdering.addNewGroup( "Well Properties" ); + caf::PdmUiGroup* wellGroup = uiOrdering.addNewGroup( "Lateral Properties" ); m_pipeProperties->uiOrdering( uiConfigName, *wellGroup ); } { - caf::PdmUiGroup* mswGroup = uiOrdering.addNewGroup( "Multi Segment Wells" ); + caf::PdmUiGroup* mswGroup = uiOrdering.addNewGroup( "Lateral Multi Segment Wells" ); mswGroup->setCollapsedByDefault( true ); mswGroup->add( &m_lateralTubingDiameter ); mswGroup->add( &m_lateralOpenHoleRoghnessFactor ); diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimFishbones.h b/ApplicationLibCode/ProjectDataModel/Completions/RimFishbones.h index c50591341a..2db3ca82c6 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimFishbones.h +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimFishbones.h @@ -22,7 +22,6 @@ #include "Rim3dPropertiesInterface.h" #include "RimCheckableNamedObject.h" -#include "RimFishbonesPipeProperties.h" #include "RimWellPathComponentInterface.h" #include "cvfColor3.h" @@ -37,6 +36,7 @@ #include class RigFisbonesGeometry; +class RimFishbonesPipeProperties; class RimMultipleValveLocations; //================================================================================================== @@ -79,13 +79,10 @@ public: double exitAngle() const; double buildAngle() const; - double tubingDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const; - double holeDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const - { - return m_pipeProperties()->holeDiameter( unitSystem ); - } - double effectiveDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const; - double skinFactor() const { return m_pipeProperties()->skinFactor(); } + double tubingDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const; + double holeDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const; + double equivalentDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const; + double skinFactor() const; double openHoleRoughnessFactor( RiaDefines::EclipseUnitSystem unitSystem ) const; double icdOrificeDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const; double icdFlowCoefficient() const; @@ -94,7 +91,7 @@ public: void geometryUpdated(); - const std::vector& installedLateralIndices() const { return m_subLateralIndices; }; + const std::vector& installedLateralIndices() const; std::vector coordsForLateral( size_t subIndex, size_t lateralIndex ) const; std::vector> coordsAndMDForLateral( size_t subIndex, size_t lateralIndex ) const; void recomputeLateralLocations(); diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimFishbonesCollection.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimFishbonesCollection.cpp index d8ad8cc3d4..cbca5e6b62 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimFishbonesCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimFishbonesCollection.cpp @@ -25,7 +25,6 @@ #include "RigWellPath.h" #include "RimFishbones.h" -#include "RimImportedFishboneLateralsCollection.h" #include "RimProject.h" #include "RimWellPath.h" @@ -50,10 +49,6 @@ RimFishbonesCollection::RimFishbonesCollection() m_fishbones.uiCapability()->setUiHidden( true ); - CAF_PDM_InitFieldNoDefault( &m_wellPathCollection, "WellPathCollection", "Imported Laterals", "", "", "" ); - m_wellPathCollection = new RimImportedFishboneLateralsCollection; - m_wellPathCollection.uiCapability()->setUiHidden( true ); - CAF_PDM_InitField( &m_startMD, "StartMD", HUGE_VAL, "Start MD", "", "", "" ); CAF_PDM_InitField( &m_mainBoreDiameter, "MainBoreDiameter", 0.216, "Main Bore Diameter", "", "", "" ); CAF_PDM_InitField( &m_skinFactor, "MainBoreSkinFactor", 0., "Main Bore Skin Factor [0..1]", "", "", "" ); @@ -74,16 +69,6 @@ RimFishbonesCollection::RimFishbonesCollection() m_lengthAndDepth_OBSOLETE.xmlCapability()->setIOWritable( false ); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimImportedFishboneLateralsCollection* RimFishbonesCollection::wellPathCollection() const -{ - CVF_ASSERT( m_wellPathCollection ); - - return m_wellPathCollection(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -268,14 +253,6 @@ void RimFishbonesCollection::recalculateStartMD() } } - for ( const RimImportedFishboneLaterals* wellPath : m_wellPathCollection->wellPaths() ) - { - if ( wellPath->measuredDepths().size() > 0 ) - { - minStartMD = std::min( minStartMD, wellPath->measuredDepths()[0] - 13.0 ); - } - } - if ( !manuallyModifiedStartMD || minStartMD < m_startMD() ) { m_startMD = minStartMD; @@ -342,7 +319,5 @@ void RimFishbonesCollection::setUnitSystemSpecificDefaults() { m_mainBoreDiameter = 0.708; } - - m_wellPathCollection->setUnitSystemSpecificDefaults(); } } diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimFishbonesCollection.h b/ApplicationLibCode/ProjectDataModel/Completions/RimFishbonesCollection.h index 3f70b87be2..6d833ce4f9 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimFishbonesCollection.h +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimFishbonesCollection.h @@ -30,7 +30,6 @@ #include "cvfColor3.h" class RimFishbones; -class RimImportedFishboneLateralsCollection; //================================================================================================== // @@ -44,9 +43,8 @@ class RimFishbonesCollection : public RimCheckableNamedObject public: RimFishbonesCollection(); - RimImportedFishboneLateralsCollection* wellPathCollection() const; - void appendFishbonesSubs( RimFishbones* subs ); - const RimMswCompletionParameters* mswParameters() const; + void appendFishbonesSubs( RimFishbones* subs ); + const RimMswCompletionParameters* mswParameters() const; bool hasFishbones() const; std::vector activeFishbonesSubs() const; @@ -68,9 +66,8 @@ private: cvf::Color3f nextFishbonesColor() const; private: - caf::PdmChildArrayField m_fishbones; - caf::PdmChildField m_wellPathCollection; - caf::PdmChildField m_mswParameters; + caf::PdmChildArrayField m_fishbones; + caf::PdmChildField m_mswParameters; caf::PdmField m_startMD; caf::PdmField m_skinFactor; diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLaterals.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLaterals.cpp deleted file mode 100644 index 643ae2149b..0000000000 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLaterals.cpp +++ /dev/null @@ -1,117 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2011- Statoil ASA -// Copyright (C) 2013- Ceetron Solutions AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RimImportedFishboneLaterals.h" - -#include "RimProject.h" - -#include "cafPdmUiListEditor.h" -#include "cafPdmUiTextEditor.h" - -CAF_PDM_SOURCE_INIT( RimImportedFishboneLaterals, "WellPathCompletion" ); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimImportedFishboneLaterals::RimImportedFishboneLaterals() -{ - CAF_PDM_InitObject( "WellPathCompletion", ":/FishBoneLateralFromFile16x16.png", "", "" ); - CAF_PDM_InitFieldNoDefault( &m_coordinates, "Coordinates", "Coordinates", "", "", "" ); - m_coordinates.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitFieldNoDefault( &m_measuredDepths, "MeasuredDepth", "MeasuredDepth", "", "", "" ); - m_measuredDepths.uiCapability()->setUiHidden( true ); - - userDescriptionField()->uiCapability()->setUiHidden( true ); - - CAF_PDM_InitFieldNoDefault( &m_displayCoordinates, "DisplayCoordinates", "Coordinates", "", "", "" ); - m_displayCoordinates.registerGetMethod( this, &RimImportedFishboneLaterals::displayCoordinates ); - m_displayCoordinates.uiCapability()->setUiReadOnly( true ); - m_displayCoordinates.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() ); - m_displayCoordinates.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosType::TOP ); - - setDeletable( true ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimImportedFishboneLaterals::~RimImportedFishboneLaterals() -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLaterals::setCoordinates( std::vector coordinates ) -{ - m_coordinates = coordinates; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLaterals::setMeasuredDepths( std::vector measuredDepths ) -{ - m_measuredDepths = measuredDepths; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLaterals::fieldChangedByUi( const caf::PdmFieldHandle* changedField, - const QVariant& oldValue, - const QVariant& newValue ) -{ - RimProject* proj; - this->firstAncestorOrThisOfType( proj ); - if ( proj ) proj->scheduleCreateDisplayModelAndRedrawAllViews(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLaterals::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) -{ - uiOrdering.add( &m_displayCoordinates ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimImportedFishboneLaterals::displayCoordinates() const -{ - CVF_ASSERT( m_coordinates().size() == m_measuredDepths().size() ); - - QStringList displayValues; - - displayValues.push_back( QString( "X\tY\tZ\tMD" ) ); - for ( size_t i = 0; i < m_coordinates().size(); i++ ) - { - const cvf::Vec3d& coords = m_coordinates()[i]; - const double& measuredDepth = m_measuredDepths()[i]; - displayValues.push_back( QString( "%1\t%2\t%3\t%4" ) - .arg( coords.x(), 0, 'f', 2 ) - .arg( coords.y(), 0, 'f', 2 ) - .arg( coords.z(), 0, 'f', 2 ) - .arg( measuredDepth, 0, 'f', 2 ) ); - } - - return displayValues.join( "\n" ); -} diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLaterals.h b/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLaterals.h deleted file mode 100644 index 2eeb544941..0000000000 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLaterals.h +++ /dev/null @@ -1,66 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2011- Statoil ASA -// Copyright (C) 2013- Ceetron Solutions AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RimCheckableNamedObject.h" - -#include "cafAppEnum.h" -#include "cafPdmChildField.h" -#include "cafPdmField.h" -#include "cafPdmObject.h" -#include "cafPdmPointer.h" - -// Include to make Pdm work for cvf::Color -#include "cafPdmChildArrayField.h" -#include "cafPdmFieldCvfColor.h" -#include "cafPdmFieldCvfVec3d.h" -#include "cafPdmProxyValueField.h" - -#include "cvfObject.h" -#include "cvfVector3.h" - -//================================================================================================== -/// -/// -//================================================================================================== -class RimImportedFishboneLaterals : public RimCheckableNamedObject -{ - CAF_PDM_HEADER_INIT; - -public: - RimImportedFishboneLaterals(); - ~RimImportedFishboneLaterals() override; - - void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; - void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; - - void setCoordinates( std::vector coordinates ); - void setMeasuredDepths( std::vector measuredDepths ); - - std::vector coordinates() const { return m_coordinates(); } - std::vector measuredDepths() const { return m_measuredDepths(); } - -private: - QString displayCoordinates() const; - - caf::PdmField> m_coordinates; - caf::PdmField> m_measuredDepths; - caf::PdmProxyValueField m_displayCoordinates; -}; diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLateralsCollection.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLateralsCollection.cpp deleted file mode 100644 index 0b4d2f7f02..0000000000 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLateralsCollection.cpp +++ /dev/null @@ -1,149 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2015- Statoil ASA -// Copyright (C) 2015- Ceetron Solutions AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RimImportedFishboneLateralsCollection.h" - -#include "Rim3dView.h" -#include "RimFishbonesCollection.h" -#include "RimImportedFishboneLaterals.h" -#include "RimProject.h" - -#include "RigWellPath.h" - -#include "RifWellPathImporter.h" - -#include "Riu3DMainWindowTools.h" - -// The more general term WellPathCompletionCollection was unfortunately used in this more specific case of fishbones -// In order to preserve compatibility, the old keyword is kept as an alias, but could be removed in the future. -CAF_PDM_SOURCE_INIT( RimImportedFishboneLateralsCollection, "FishboneWellPathCollection", "WellPathCompletionCollection" ); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimImportedFishboneLateralsCollection::RimImportedFishboneLateralsCollection() -{ - CAF_PDM_InitObject( "WellPathCompletions", ":/FishBoneGroupFromFile16x16.png", "", "" ); - - nameField()->uiCapability()->setUiHidden( true ); - this->setName( "Imported Laterals" ); - - CAF_PDM_InitFieldNoDefault( &m_wellPaths, "WellPaths", "Imported Laterals", "", "", "" ); - m_wellPaths.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitFieldNoDefault( &m_pipeProperties, "PipeProperties", "Pipe Properties", "", "", "" ); - m_pipeProperties.uiCapability()->setUiHidden( true ); - m_pipeProperties.uiCapability()->setUiTreeHidden( true ); - m_pipeProperties.uiCapability()->setUiTreeChildrenHidden( true ); - m_pipeProperties = new RimFishbonesPipeProperties; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLateralsCollection::importCompletionsFromFile( const QStringList& filePaths ) -{ - RifWellPathImporter wellPathImporter; - - for ( const QString& filePath : filePaths ) - { - size_t wellDataCount = wellPathImporter.wellDataCount( filePath ); - - for ( size_t i = 0; i < wellDataCount; ++i ) - { - RifWellPathImporter::WellData wellData = wellPathImporter.readWellData( filePath, i ); - RimImportedFishboneLaterals* wellCompletion = new RimImportedFishboneLaterals(); - wellCompletion->setName( wellData.m_name ); - wellCompletion->setCoordinates( wellData.m_wellPathGeometry->uniqueWellPathPoints() ); - wellCompletion->setMeasuredDepths( wellData.m_wellPathGeometry->uniqueMeasuredDepths() ); - appendCompletion( wellCompletion ); - } - } - - RimFishbonesCollection* fishbonesCollection; - firstAncestorOrThisOfType( fishbonesCollection ); - if ( fishbonesCollection != nullptr ) - { - fishbonesCollection->recalculateStartMD(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLateralsCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField, - const QVariant& oldValue, - const QVariant& newValue ) -{ - RimProject* proj; - this->firstAncestorOrThisOfTypeAsserted( proj ); - proj->scheduleCreateDisplayModelAndRedrawAllViews(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimImportedFishboneLateralsCollection::wellPaths() const -{ - std::vector paths; - - for ( const RimImportedFishboneLaterals* path : m_wellPaths ) - { - paths.push_back( path ); - } - - return paths; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLateralsCollection::setUnitSystemSpecificDefaults() -{ - m_pipeProperties->setUnitSystemSpecificDefaults(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLateralsCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) -{ - caf::PdmUiGroup* wellPropertiesGroup = uiOrdering.addNewGroup( "Well Properties" ); - m_pipeProperties->uiOrdering( uiConfigName, *wellPropertiesGroup ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimImportedFishboneLateralsCollection::appendCompletion( RimImportedFishboneLaterals* completion ) -{ - m_wellPaths.push_back( completion ); - - updateConnectedEditors(); - Riu3DMainWindowTools::selectAsCurrentItem( completion ); - - uiCapability()->setUiHidden( !m_wellPaths.empty() ); - - RimProject* project = nullptr; - firstAncestorOrThisOfTypeAsserted( project ); - if ( project ) - { - project->reloadCompletionTypeResultsInAllViews(); - } -} diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLateralsCollection.h b/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLateralsCollection.h deleted file mode 100644 index a4c086ebdc..0000000000 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimImportedFishboneLateralsCollection.h +++ /dev/null @@ -1,67 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2015- Statoil ASA -// Copyright (C) 2015- Ceetron Solutions AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RimCheckableNamedObject.h" -#include "RimFishbonesPipeProperties.h" -#include "RimImportedFishboneLaterals.h" - -#include "RiaDefines.h" - -#include "cafPdmChildArrayField.h" -#include "cafPdmChildField.h" -#include "cafPdmField.h" -#include "cafPdmObject.h" - -//================================================================================================== -// -// -// -//================================================================================================== -class RimImportedFishboneLateralsCollection : public RimCheckableNamedObject -{ - CAF_PDM_HEADER_INIT; - -public: - RimImportedFishboneLateralsCollection(); - - void importCompletionsFromFile( const QStringList& filePaths ); - - void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; - - std::vector wellPaths() const; - double holeDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const - { - return m_pipeProperties->holeDiameter( unitSystem ); - } - double skinFactor() const { return m_pipeProperties->skinFactor(); } - - void setUnitSystemSpecificDefaults(); - -protected: - void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; - -private: - void appendCompletion( RimImportedFishboneLaterals* completion ); - -private: - caf::PdmChildArrayField m_wellPaths; - caf::PdmChildField m_pipeProperties; -}; diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimMswCompletionParameters.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimMswCompletionParameters.cpp index 41e365ea39..67c27f34e6 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimMswCompletionParameters.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimMswCompletionParameters.cpp @@ -49,7 +49,7 @@ void RimMswCompletionParameters::LengthAndDepthEnum::setUp() { addItem( RimMswCompletionParameters::INC, "INC", "Incremental" ); addItem( RimMswCompletionParameters::ABS, "ABS", "Absolute" ); - setDefault( RimMswCompletionParameters::INC ); + setDefault( RimMswCompletionParameters::ABS ); } } // namespace caf diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp index 635ca92990..2a53f07946 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp @@ -309,13 +309,7 @@ void RimWellPathCompletionSettings::defineEditorAttribute( const caf::PdmFieldHa caf::PdmUiEditorAttribute* attribute ) { caf::PdmUiLineEditorAttribute* lineEditorAttr = dynamic_cast( attribute ); - if ( field == &m_wellNameForExport && lineEditorAttr ) - { - QRegExpValidator* validator = new QRegExpValidator( nullptr ); - validator->setRegExp( wellNameForExportRegExp() ); - lineEditorAttr->validator = validator; - } - else if ( field == &m_drainageRadiusForPI && lineEditorAttr ) + if ( field == &m_drainageRadiusForPI && lineEditorAttr ) { caf::PdmDoubleStringValidator* validator = new caf::PdmDoubleStringValidator( "1*" ); lineEditorAttr->validator = validator; diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletions.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletions.cpp index fad009ea4f..80ca93b082 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletions.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletions.cpp @@ -22,7 +22,6 @@ #include "RimFishbones.h" #include "RimFishbonesCollection.h" -#include "RimImportedFishboneLateralsCollection.h" #include "RimPerforationCollection.h" #include "RimPerforationInterval.h" #include "RimProject.h" @@ -211,9 +210,7 @@ bool RimWellPathCompletions::hasCompletions() const return true; } - return !m_fishbonesCollection->allFishbonesSubs().empty() || - !m_fishbonesCollection->wellPathCollection()->wellPaths().empty() || - !m_perforationCollection->perforations().empty(); + return !m_fishbonesCollection->allFishbonesSubs().empty() || !m_perforationCollection->perforations().empty(); } //-------------------------------------------------------------------------------------------------- @@ -244,8 +241,7 @@ void RimWellPathCompletions::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTre uiTreeOrdering.add( &m_perforationCollection ); } - if ( !m_fishbonesCollection->allFishbonesSubs().empty() || - !m_fishbonesCollection->wellPathCollection()->wellPaths().empty() ) + if ( !m_fishbonesCollection->allFishbonesSubs().empty() ) { uiTreeOrdering.add( &m_fishbonesCollection ); } diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathValve.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathValve.cpp index 3875edf6ef..c6c0c2871d 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathValve.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathValve.cpp @@ -304,6 +304,14 @@ std::vector> RimWellPathValve::valveSegments() const return segments; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathValve::setComponentTypeFilter( const std::set& filter ) +{ + m_componentTypeFilter = filter; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -456,6 +464,11 @@ QList RimWellPathValve::calculateValueOptions( const caf std::vector allTemplates = project->allValveTemplates(); for ( RimValveTemplate* valveTemplate : allTemplates ) { + if ( !m_componentTypeFilter.empty() ) + { + if ( m_componentTypeFilter.count( valveTemplate->type() ) == 0 ) continue; + } + options.push_back( caf::PdmOptionItemInfo( valveTemplate->name(), valveTemplate ) ); } diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathValve.h b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathValve.h index e34fc5b38c..27a19eea79 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathValve.h +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathValve.h @@ -65,6 +65,8 @@ public: std::vector> valveSegments() const; + void setComponentTypeFilter( const std::set& filter ); + // Overrides from RimWellPathCompletionInterface bool isEnabled() const override; RiaDefines::WellPathComponentType componentType() const override; @@ -92,4 +94,6 @@ private: caf::PdmChildField m_multipleValveLocations; caf::PdmField m_editValveTemplate; caf::PdmField m_createValveTemplate; + + std::set m_componentTypeFilter; }; diff --git a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp index 54c373e873..ef9bf2c24a 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -88,7 +88,6 @@ #include "RimGridCrossPlotCollection.h" #include "RimGridCrossPlotDataSet.h" #include "RimIdenticalGridCaseGroup.h" -#include "RimImportedFishboneLateralsCollection.h" #include "RimIntersectionCollection.h" #include "RimIntersectionResultDefinition.h" #include "RimIntersectionResultsDefinitionCollection.h" @@ -336,7 +335,6 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicReloadWellPathFormationNamesFeature"; menuBuilder.addSeparator(); menuBuilder << "RicWellPathImportPerforationIntervalsFeature"; - menuBuilder << "RicWellPathImportCompletionsFileFeature"; menuBuilder << "RicImportWellMeasurementsFeature"; menuBuilder.subMenuEnd(); menuBuilder.addSeparator(); @@ -392,10 +390,6 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicShowWellPlanFeature"; } } - else if ( dynamic_cast( firstUiItem ) ) - { - appendImportMenu( menuBuilder ); - } else if ( dynamic_cast( firstUiItem ) ) { menuBuilder.subMenuStart( "Create Completions", QIcon( ":/CompletionsSymbol16x16.png" ) ); @@ -418,8 +412,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder.addSeparator(); appendExportCompletions( menuBuilder ); } - else if ( dynamic_cast( firstUiItem ) || dynamic_cast( firstUiItem ) || - dynamic_cast( firstUiItem ) ) + else if ( dynamic_cast( firstUiItem ) || dynamic_cast( firstUiItem ) ) { menuBuilder << "RicNewFishbonesSubsFeature"; appendExportCompletions( menuBuilder ); @@ -1335,8 +1328,6 @@ int RimContextCommandBuilder::appendImportMenu( caf::CmdFeatureMenuBuilder& menu candidates << "RicWellPathFormationsImportFileFeature"; candidates << "RicWellLogsImportFileFeature"; candidates << "RicReloadWellPathFormationNamesFeature"; - candidates << "Separator"; - candidates << "RicWellPathImportCompletionsFileFeature"; return appendSubMenuWithCommands( menuBuilder, candidates, "Import", QIcon(), addSeparatorBeforeMenu ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimModeledWellPath.cpp b/ApplicationLibCode/ProjectDataModel/RimModeledWellPath.cpp index e84a10a38f..e4124b4371 100644 --- a/ApplicationLibCode/ProjectDataModel/RimModeledWellPath.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimModeledWellPath.cpp @@ -18,21 +18,24 @@ #include "RimModeledWellPath.h" +#include "RiaCompletionTypeCalculationScheduler.h" #include "RicfCommandObject.h" -#include "RimProject.h" -#include "RimWellPathGeometryDef.h" - +#include "RifTextDataTableFormatter.h" #include "RigWellPath.h" -#include "RiaCompletionTypeCalculationScheduler.h" -#include "RifTextDataTableFormatter.h" #include "RimExtrudedCurveIntersection.h" #include "RimPlotCurve.h" +#include "RimProject.h" +#include "RimTools.h" #include "RimWellPath.h" #include "RimWellPathFracture.h" #include "RimWellPathFractureCollection.h" +#include "RimWellPathGeometryDef.h" +#include "RimWellPathTarget.h" +#include "RimWellPathTieIn.h" #include "cafPdmFieldScriptingCapability.h" +#include "cafPdmUiDoubleValueEditor.h" #include "cafPdmUiTreeOrdering.h" CAF_PDM_SOURCE_INIT( RimModeledWellPath, "ModeledWellPath" ); @@ -191,6 +194,7 @@ void RimModeledWellPath::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrd void RimModeledWellPath::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { uiOrdering.add( &m_name ); + RimWellPath::defineUiOrdering( uiConfigName, uiOrdering ); } @@ -198,10 +202,95 @@ void RimModeledWellPath::defineUiOrdering( QString uiConfigName, caf::PdmUiOrder /// //-------------------------------------------------------------------------------------------------- void RimModeledWellPath::onGeometryDefinitionChanged( const caf::SignalEmitter* emitter, bool fullUpdate ) +{ + updateGeometry( fullUpdate ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimModeledWellPath::fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) +{ + // TODO remove if nothing happens here + + RimWellPath::fieldChangedByUi( changedField, oldValue, newValue ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimModeledWellPath::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly ) +{ + QList options; + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimModeledWellPath::updateGeometry( bool fullUpdate ) { updateWellPathVisualization(); + + std::vector tieInObjects; + objectsWithReferringPtrFieldsOfType( tieInObjects ); + for ( auto tieIn : tieInObjects ) + { + if ( tieIn->parentWell() == this ) + { + tieIn->updateChildWellGeometry(); + } + } + if ( fullUpdate ) { scheduleUpdateOfDependentVisualization(); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimModeledWellPath::updateTieInLocationFromParentWell() +{ + RimWellPath* parentWellPath = nullptr; + + RimWellPathTieIn* tieIn = wellPathTieIn(); + if ( tieIn ) + { + parentWellPath = tieIn->parentWell(); + + auto targets = m_geometryDefinition->activeWellTargets(); + if ( parentWellPath && !targets.empty() ) + { + auto [pointVector, measuredDepths] = + parentWellPath->wellPathGeometry() + ->clippedPointSubset( parentWellPath->wellPathGeometry()->measuredDepths().front(), + tieIn->tieInMeasuredDepth() ); + + if ( pointVector.size() > 2u ) + { + auto firstTarget = targets.front(); + firstTarget->setPointXYZ( pointVector.back() ); + + m_geometryDefinition->setIsAttachedToParentWell( true ); + m_geometryDefinition->setMdAtFirstTarget( measuredDepths.back() ); + m_geometryDefinition->setFixedWellPathPoints( pointVector ); + m_geometryDefinition->setFixedMeasuredDepths( measuredDepths ); + + updateGeometry( true ); + } + } + } + + if ( !parentWellPath ) + { + m_geometryDefinition->setIsAttachedToParentWell( false ); + m_geometryDefinition->setFixedWellPathPoints( {} ); + m_geometryDefinition->setFixedMeasuredDepths( {} ); + } +} diff --git a/ApplicationLibCode/ProjectDataModel/RimModeledWellPath.h b/ApplicationLibCode/ProjectDataModel/RimModeledWellPath.h index 7b13f3a391..3f6f23c0e2 100644 --- a/ApplicationLibCode/ProjectDataModel/RimModeledWellPath.h +++ b/ApplicationLibCode/ProjectDataModel/RimModeledWellPath.h @@ -20,6 +20,7 @@ #include "RimWellPath.h" #include "cafPdmChildField.h" +#include "cafPdmPtrField.h" class RimWellPathTarget; class RimWellPath; @@ -38,11 +39,20 @@ public: void scheduleUpdateOfDependentVisualization(); RimWellPathGeometryDef* geometryDefinition() const; QString wellPlanText(); + void updateTieInLocationFromParentWell(); private: void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName ) override; void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; void onGeometryDefinitionChanged( const caf::SignalEmitter* emitter, bool fullUpdate ); + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly ) override; + + void updateGeometry( bool fullUpdate ); + +private: caf::PdmChildField m_geometryDefinition; }; diff --git a/ApplicationLibCode/ProjectDataModel/RimTools.cpp b/ApplicationLibCode/ProjectDataModel/RimTools.cpp index f7cb03eb6e..305aebc686 100644 --- a/ApplicationLibCode/ProjectDataModel/RimTools.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimTools.cpp @@ -234,19 +234,43 @@ QString RimTools::relocateFile( const QString& originalFileName, //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimTools::wellPathOptionItems( QList* options ) +void RimTools::wellPathOptionItemsSubset( const std::vector& wellPathsToExclude, + QList* options ) { - CVF_ASSERT( options ); if ( !options ) return; auto wellPathColl = RimTools::wellPathCollection(); if ( wellPathColl ) { - caf::IconProvider wellIcon( ":/Well.svg" ); - for ( auto wellPath : wellPathColl->allWellPaths() ) + std::vector wellPathsToInclude; + + auto all = wellPathColl->allWellPaths(); + for ( auto w : all ) { - options->push_back( caf::PdmOptionItemInfo( wellPath->name(), wellPath, false, wellIcon ) ); + bool include = true; + for ( auto exclude : wellPathsToExclude ) + { + if ( w == exclude ) include = false; + } + + if ( include ) wellPathsToInclude.push_back( w ); } + + optionItemsForSpecifiedWellPaths( wellPathsToInclude, options ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTools::wellPathOptionItems( QList* options ) +{ + if ( !options ) return; + + auto wellPathColl = RimTools::wellPathCollection(); + if ( wellPathColl ) + { + optionItemsForSpecifiedWellPaths( wellPathColl->allWellPaths(), options ); } } @@ -255,17 +279,12 @@ void RimTools::wellPathOptionItems( QList* options ) //-------------------------------------------------------------------------------------------------- void RimTools::wellPathWithFormationsOptionItems( QList* options ) { - CVF_ASSERT( options ); if ( !options ) return; std::vector wellPaths; RimTools::wellPathWithFormations( &wellPaths ); - caf::IconProvider wellIcon( ":/Well.svg" ); - for ( auto wellPath : wellPaths ) - { - options->push_back( caf::PdmOptionItemInfo( wellPath->name(), wellPath, false, wellIcon ) ); - } + optionItemsForSpecifiedWellPaths( wellPaths, options ); } //-------------------------------------------------------------------------------------------------- @@ -291,7 +310,6 @@ void RimTools::wellPathWithFormations( std::vector* wellPaths ) //-------------------------------------------------------------------------------------------------- void RimTools::caseOptionItems( QList* options ) { - CVF_ASSERT( options ); if ( !options ) return; RimProject* proj = RimProject::current(); @@ -312,7 +330,6 @@ void RimTools::caseOptionItems( QList* options ) //-------------------------------------------------------------------------------------------------- void RimTools::eclipseCaseOptionItems( QList* options ) { - CVF_ASSERT( options ); if ( !options ) return; RimProject* proj = RimProject::current(); @@ -337,7 +354,6 @@ void RimTools::eclipseCaseOptionItems( QList* options ) //-------------------------------------------------------------------------------------------------- void RimTools::geoMechCaseOptionItems( QList* options ) { - CVF_ASSERT( options ); if ( !options ) return; RimProject* proj = RimProject::current(); @@ -362,7 +378,6 @@ void RimTools::geoMechCaseOptionItems( QList* options ) //-------------------------------------------------------------------------------------------------- void RimTools::colorLegendOptionItems( QList* options ) { - CVF_ASSERT( options ); if ( !options ) return; RimProject* project = RimProject::current(); @@ -407,3 +422,18 @@ void RimTools::timeStepsForCase( RimCase* gridCase, QListpush_back( caf::PdmOptionItemInfo( timeStepNames[i], i ) ); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTools::optionItemsForSpecifiedWellPaths( const std::vector& wellPaths, + QList* options ) +{ + if ( !options ) return; + + caf::IconProvider wellIcon( ":/Well.svg" ); + for ( auto wellPath : wellPaths ) + { + options->push_back( caf::PdmOptionItemInfo( wellPath->name(), wellPath, false, wellIcon ) ); + } +} diff --git a/ApplicationLibCode/ProjectDataModel/RimTools.h b/ApplicationLibCode/ProjectDataModel/RimTools.h index b2dab42a32..e0413fb38c 100644 --- a/ApplicationLibCode/ProjectDataModel/RimTools.h +++ b/ApplicationLibCode/ProjectDataModel/RimTools.h @@ -51,6 +51,8 @@ public: bool* foundFile, std::vector* searchedPaths ); + static void wellPathOptionItemsSubset( const std::vector& wellPathsToExclude, + QList* options ); static void wellPathOptionItems( QList* options ); static void wellPathWithFormationsOptionItems( QList* options ); static void wellPathWithFormations( std::vector* wellPaths ); @@ -61,4 +63,8 @@ public: static RimWellPathCollection* wellPathCollection(); static void timeStepsForCase( RimCase* gridCase, QList* options ); + +private: + static void optionItemsForSpecifiedWellPaths( const std::vector& wellPaths, + QList* options ); }; diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPath.cpp b/ApplicationLibCode/ProjectDataModel/RimWellPath.cpp index 557cc06af0..73505b58bd 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPath.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimWellPath.cpp @@ -50,6 +50,7 @@ #include "RimWellPathCompletions.h" #include "RimWellPathFracture.h" #include "RimWellPathFractureCollection.h" +#include "RimWellPathTieIn.h" #include "RiuMainWindow.h" @@ -131,6 +132,8 @@ RimWellPath::RimWellPath() m_wellPathAttributes = new RimWellPathAttributeCollection; m_wellPathAttributes->uiCapability()->setUiTreeHidden( true ); + CAF_PDM_InitFieldNoDefault( &m_wellPathTieIn, "WellPathTieIn", "well Path Tie-In", "", "", "" ); + this->setDeletable( true ); } @@ -285,7 +288,9 @@ const RimWellPathCompletions* RimWellPath::completions() const //-------------------------------------------------------------------------------------------------- const RimWellPathCompletionSettings* RimWellPath::completionSettings() const { - return m_completionSettings(); + if ( isTopLevelWellPath() ) return m_completionSettings(); + + return topLevelWellPath()->completionSettings(); } //-------------------------------------------------------------------------------------------------- @@ -293,7 +298,9 @@ const RimWellPathCompletionSettings* RimWellPath::completionSettings() const //-------------------------------------------------------------------------------------------------- RimWellPathCompletionSettings* RimWellPath::completionSettings() { - return m_completionSettings(); + if ( isTopLevelWellPath() ) return m_completionSettings(); + + return topLevelWellPath()->completionSettings(); } //-------------------------------------------------------------------------------------------------- @@ -612,6 +619,11 @@ void RimWellPath::setWellPathGeometry( RigWellPath* wellPathModel ) //-------------------------------------------------------------------------------------------------- void RimWellPath::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { + if ( m_wellPathTieIn() ) + { + m_wellPathTieIn->uiOrdering( uiConfigName, uiOrdering ); + } + if ( m_simWellName().isEmpty() ) { // Try to set default simulation well name @@ -961,12 +973,18 @@ std::vector RimWellPath::allCompletionsRec { std::vector allCompletions; - std::vector completionCollections; - this->descendantsOfType( completionCollections ); - for ( auto collection : completionCollections ) + auto tieInWells = wellPathLateralsRecursively(); + tieInWells.push_back( const_cast( this ) ); + + for ( auto w : tieInWells ) { - std::vector completions = collection->allCompletions(); - allCompletions.insert( allCompletions.end(), completions.begin(), completions.end() ); + std::vector completionCollections; + w->descendantsOfType( completionCollections ); + for ( auto collection : completionCollections ) + { + std::vector completions = collection->allCompletions(); + allCompletions.insert( allCompletions.end(), completions.begin(), completions.end() ); + } } return allCompletions; @@ -1048,12 +1066,27 @@ bool RimWellPath::isMultiLateralWellPath() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellPath* RimWellPath::topLevelWellPath() const +RimWellPath* RimWellPath::topLevelWellPath() { - std::vector wellPathHierarchy; - this->allAncestorsOrThisOfType( wellPathHierarchy ); - RimWellPath* wellPath = wellPathHierarchy.back(); - return wellPath; + if ( m_wellPathTieIn() && m_wellPathTieIn->parentWell() ) + { + return m_wellPathTieIn()->parentWell()->topLevelWellPath(); + } + + return this; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimWellPath* RimWellPath::topLevelWellPath() const +{ + if ( m_wellPathTieIn() && m_wellPathTieIn->parentWell() ) + { + return m_wellPathTieIn()->parentWell()->topLevelWellPath(); + } + + return this; } //-------------------------------------------------------------------------------------------------- @@ -1062,3 +1095,46 @@ RimWellPath* RimWellPath::topLevelWellPath() const void RimWellPath::updateAfterAddingToWellPathGroup() { } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimWellPath::wellPathLateralsRecursively() const +{ + std::vector tieInWells; + + auto wellPathColl = RimTools::wellPathCollection(); + if ( wellPathColl ) + { + wellPathColl->allWellPaths(); + + for ( auto w : wellPathColl->allWellPaths() ) + { + if ( w->topLevelWellPath() == this ) + { + tieInWells.push_back( w ); + } + } + } + + return tieInWells; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellPathTieIn* RimWellPath::wellPathTieIn() const +{ + return m_wellPathTieIn(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPath::connectWellPaths( RimWellPath* parentWell, double parentTieInMeasuredDepth ) +{ + if ( !m_wellPathTieIn() ) m_wellPathTieIn = new RimWellPathTieIn; + + m_wellPathTieIn->connectWellPaths( parentWell, this, parentTieInMeasuredDepth ); + m_wellPathTieIn->updateFirstTargetFromParentWell(); +} diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPath.h b/ApplicationLibCode/ProjectDataModel/RimWellPath.h index 822d13c77f..a3c7ddcbef 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPath.h +++ b/ApplicationLibCode/ProjectDataModel/RimWellPath.h @@ -54,10 +54,10 @@ class RimPerforationCollection; class RimWellPathAttributeCollection; class RimWellPathCompletions; class RimWellPathCompletionSettings; - class RimWellPathFractureCollection; class Rim3dWellLogCurve; class Rim3dWellLogCurveCollection; +class RimWellPathTieIn; //================================================================================================== /// @@ -154,10 +154,15 @@ public: void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector& referringObjects ) override; - bool isTopLevelWellPath() const; - bool isMultiLateralWellPath() const; - RimWellPath* topLevelWellPath() const; - void updateAfterAddingToWellPathGroup(); + bool isTopLevelWellPath() const; + bool isMultiLateralWellPath() const; + RimWellPath* topLevelWellPath(); + const RimWellPath* topLevelWellPath() const; + void updateAfterAddingToWellPathGroup(); + std::vector wellPathLateralsRecursively() const; + + RimWellPathTieIn* wellPathTieIn() const; + void connectWellPaths( RimWellPath* childWell, double tieInMeasuredDepth ); protected: // Override PdmObject @@ -201,6 +206,8 @@ private: caf::PdmChildField m_completions; caf::PdmChildField m_wellPathAttributes; + caf::PdmChildField m_wellPathTieIn; + private: static size_t simulationWellBranchCount( const QString& simWellName ); diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathGeometryDef.cpp b/ApplicationLibCode/ProjectDataModel/RimWellPathGeometryDef.cpp index 37882a953e..4abd9ccc9e 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPathGeometryDef.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathGeometryDef.cpp @@ -74,7 +74,10 @@ RimWellPathGeometryDef::RimWellPathGeometryDef() CAF_PDM_InitScriptableField( &m_airGap, "AirGap", 0.0, "Air Gap", "", "", "" ); m_airGap.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); + CAF_PDM_InitScriptableField( &m_mdAtFirstTarget, "MdAtFirstTarget", 0.0, "MD at First Target", "", "", "" ); + m_mdAtFirstTarget.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); + CAF_PDM_InitScriptableFieldNoDefault( &m_wellTargets, "WellPathTargets", "Well Targets", "", "", "" ); m_wellTargets.uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() ); m_wellTargets.uiCapability()->setUiTreeChildrenHidden( true ); @@ -93,11 +96,16 @@ RimWellPathGeometryDef::RimWellPathGeometryDef() m_autoTargetAtSeaLevel = new RimWellPathTarget; m_autoTargetAtSeaLevel->setEnabled( false ); + CAF_PDM_InitScriptableField( &m_isAttachedToParentWell, "AttachedToParentWell", false, "Attached to Parent Well", "", "", "" ); CAF_PDM_InitFieldNoDefault( &m_fixedWellPathPoints, "FixedWellPathPoints", "", "", "", "" ); CAF_PDM_InitFieldNoDefault( &m_fixedMeasuredDepths, "FixedMeasuredDepths", "", "", "", "" ); CAF_PDM_InitField( &m_pickPointsEnabled, "m_pickPointsEnabled", false, "", "", "", "" ); caf::PdmUiPushButtonEditor::configureEditorForField( &m_pickPointsEnabled ); + + CAF_PDM_InitScriptableField( &m_showSpheres, "ShowSpheres", false, "Spheres", "", "", "" ); + CAF_PDM_InitField( &m_sphereColor, "SphereColor", cvf::Color3f( cvf::Color3f::CEETRON ), "Sphere Color", "", "", "" ); + CAF_PDM_InitField( &m_sphereRadiusFactor, "SphereRadiusFactor", 0.15, "Sphere Radius Factor", "", "", "" ); } //-------------------------------------------------------------------------------------------------- @@ -159,6 +167,14 @@ void RimWellPathGeometryDef::setMdAtFirstTarget( double md ) m_mdAtFirstTarget = md; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathGeometryDef::setIsAttachedToParentWell( bool isAttached ) +{ + m_isAttachedToParentWell = isAttached; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -244,6 +260,30 @@ std::vector RimWellPathGeometryDef::well return wpCalc.wellPlan(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimWellPathGeometryDef::showSpheres() const +{ + return m_showSpheres(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RimWellPathGeometryDef::sphereColor() const +{ + return m_sphereColor(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimWellPathGeometryDef::sphereRadiusFactor() const +{ + return m_sphereRadiusFactor(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -406,10 +446,19 @@ void RimWellPathGeometryDef::fieldChangedByUi( const caf::PdmFieldHandle* change //-------------------------------------------------------------------------------------------------- void RimWellPathGeometryDef::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { - uiOrdering.add( &m_referencePointUtmXyd ); - uiOrdering.add( &m_airGap ); - uiOrdering.add( &m_mdAtFirstTarget ); - uiOrdering.add( &m_useAutoGeneratedTargetAtSeaLevel ); + if ( !m_isAttachedToParentWell ) + { + uiOrdering.add( &m_referencePointUtmXyd ); + uiOrdering.add( &m_airGap ); + uiOrdering.add( &m_mdAtFirstTarget ); + uiOrdering.add( &m_useAutoGeneratedTargetAtSeaLevel ); + } + + auto group = uiOrdering.addNewGroup( "Well Target Appearance" ); + group->add( &m_showSpheres ); + group->add( &m_sphereColor ); + group->add( &m_sphereRadiusFactor ); + uiOrdering.add( &m_wellTargets ); uiOrdering.add( &m_pickPointsEnabled ); diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathGeometryDef.h b/ApplicationLibCode/ProjectDataModel/RimWellPathGeometryDef.h index 8ee5bd89b4..6dc33f680a 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPathGeometryDef.h +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathGeometryDef.h @@ -28,6 +28,7 @@ #include "cafPdmObject.h" #include "cafPdmPtrField.h" +#include "cvfColor3.h" #include "cvfObject.h" class RimWellPath; @@ -55,6 +56,7 @@ public: double mdAtFirstTarget() const; void setMdAtFirstTarget( double mdrkb ); + void setIsAttachedToParentWell( bool isAttached ); void setFixedWellPathPoints( const std::vector& points ); void setFixedMeasuredDepths( const std::vector& mds ); @@ -80,6 +82,11 @@ public: std::vector wellPlan() const; + // Well target appearance + bool showSpheres() const; + cvf::Color3f sphereColor() const; + double sphereRadiusFactor() const; + protected: void defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget ) override; @@ -116,5 +123,11 @@ private: caf::PdmField> m_fixedWellPathPoints; caf::PdmField> m_fixedMeasuredDepths; + caf::PdmField m_isAttachedToParentWell; + + caf::PdmField m_showSpheres; + caf::PdmField m_sphereColor; + caf::PdmField m_sphereRadiusFactor; + std::shared_ptr m_pickTargetsEventHandler; }; diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.cpp b/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.cpp index 363e18287c..652a76ff37 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.cpp @@ -96,6 +96,14 @@ bool RimWellPathTarget::isEnabled() const return m_isEnabled; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathTarget::setPointXYZ( const cvf::Vec3d& point ) +{ + m_targetPoint = { point.x(), point.y(), -point.z() }; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.h b/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.h index 787266d601..88780b709e 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.h +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.h @@ -42,8 +42,9 @@ public: void setEnabled( bool enable ); bool isEnabled() const; + void setPointXYZ( const cvf::Vec3d& point ); void setAsPointTargetXYD( const cvf::Vec3d& point ); - void setAsPointTargetXYZ( const cvf::Vec3d& point); + void setAsPointTargetXYZ( const cvf::Vec3d& point ); void setAsPointXYZAndTangentTarget( const cvf::Vec3d& point, const cvf::Vec3d& tangent ); void setAsPointXYZAndTangentTarget( const cvf::Vec3d& point, double azimuth, double inclination ); void setDerivedTangent( double azimuth, double inclination ); diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathTieIn.cpp b/ApplicationLibCode/ProjectDataModel/RimWellPathTieIn.cpp new file mode 100644 index 0000000000..7e58d0bb3b --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathTieIn.cpp @@ -0,0 +1,205 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimWellPathTieIn.h" + +#include "RigWellPath.h" + +#include "RimModeledWellPath.h" +#include "RimTools.h" +#include "RimWellPathCollection.h" +#include "RimWellPathGeometryDef.h" +#include "RimWellPathTarget.h" +#include "RimWellPathValve.h" + +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmObjectScriptingCapability.h" +#include "cafPdmUiDoubleValueEditor.h" + +CAF_PDM_SOURCE_INIT( RimWellPathTieIn, "RimWellPathTieIn" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellPathTieIn::RimWellPathTieIn() +{ + CAF_PDM_InitObject( "Well Path Tie In", ":/NotDefined.png", "", "Well Path Tie In description" ); + + CAF_PDM_InitFieldNoDefault( &m_parentWell, "ParentWellPath", "ParentWellPath", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_childWell, "ChildWellPath", "ChildWellPath", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_tieInMeasuredDepth, "TieInMeasuredDepth", "TieInMeasuredDepth", "", "", "" ); + m_tieInMeasuredDepth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); + + CAF_PDM_InitScriptableField( &m_addValveAtConnection, + "AddValveAtConnection", + false, + "Add Outlet Valve for Branches", + "", + "", + "" ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_valve, "Valve", "Branch Outlet Valve", "", "", "" ); + + m_valve = new RimWellPathValve; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathTieIn::connectWellPaths( RimWellPath* parentWell, RimWellPath* childWell, double tieInMeasuredDepth ) +{ + m_parentWell = parentWell; + m_childWell = childWell; + m_tieInMeasuredDepth = tieInMeasuredDepth; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellPath* RimWellPathTieIn::parentWell() const +{ + return m_parentWell(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimWellPathTieIn::tieInMeasuredDepth() const +{ + return m_tieInMeasuredDepth(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellPath* RimWellPathTieIn::childWell() const +{ + return m_childWell(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathTieIn::updateChildWellGeometry() +{ + auto modeledWellPath = dynamic_cast( m_childWell() ); + if ( modeledWellPath ) + { + modeledWellPath->updateTieInLocationFromParentWell(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathTieIn::updateFirstTargetFromParentWell() +{ + auto parentWellPath = m_parentWell(); + if ( !parentWellPath ) return; + + auto modeledWellPath = dynamic_cast( m_childWell() ); + if ( modeledWellPath && modeledWellPath->geometryDefinition() ) + { + auto [pointVector, measuredDepths] = + parentWellPath->wellPathGeometry() + ->clippedPointSubset( parentWellPath->wellPathGeometry()->measuredDepths().front(), m_tieInMeasuredDepth ); + if ( pointVector.size() < 2u ) return; + + RimWellPathTarget* newTarget = nullptr; + + if ( modeledWellPath->geometryDefinition()->activeWellTargets().empty() ) + { + newTarget = modeledWellPath->geometryDefinition()->appendTarget(); + } + else + { + newTarget = modeledWellPath->geometryDefinition()->activeWellTargets().front(); + } + + auto lastPoint = pointVector.back(); + auto tangent = lastPoint - pointVector[pointVector.size() - 2]; + newTarget->setAsPointXYZAndTangentTarget( { lastPoint[0], lastPoint[1], lastPoint[2] }, tangent ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimWellPathValve* RimWellPathTieIn::outletValve() const +{ + return m_addValveAtConnection() && m_valve() && m_valve->valveTemplate() ? m_valve() : nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathTieIn::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + auto tieInGroup = uiOrdering.addNewGroup( "Tie In Settings" ); + tieInGroup->add( &m_parentWell ); + tieInGroup->add( &m_tieInMeasuredDepth ); + tieInGroup->add( &m_addValveAtConnection ); + + // Display only ICV valves + m_valve->setComponentTypeFilter( { RiaDefines::WellPathComponentType::ICV } ); + + if ( m_addValveAtConnection ) + { + m_valve->uiOrdering( "TemplateOnly", *tieInGroup ); + } + + uiOrdering.skipRemainingFields(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathTieIn::fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) +{ + if ( changedField == &m_parentWell ) + { + updateFirstTargetFromParentWell(); + } + + updateChildWellGeometry(); + + // Update all well paths to make sure the visibility of completion settings is updated + // Completions settings is only visible for top-level wells, not for tie-in wells + RimTools::wellPathCollection()->updateAllRequiredEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimWellPathTieIn::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly ) +{ + QList options; + + if ( fieldNeedingOptions == &m_parentWell ) + { + std::vector wellPathsToExclude = { m_childWell() }; + RimTools::wellPathOptionItemsSubset( wellPathsToExclude, &options ); + + options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) ); + } + + return options; +} diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathTieIn.h b/ApplicationLibCode/ProjectDataModel/RimWellPathTieIn.h new file mode 100644 index 0000000000..0edc980799 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathTieIn.h @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmChildField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPtrField.h" + +class RimWellPath; +class RimWellPathValve; + +class RimWellPathTieIn : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimWellPathTieIn(); + + void connectWellPaths( RimWellPath* parentWell, RimWellPath* childWell, double tieInMeasuredDepth ); + RimWellPath* parentWell() const; + double tieInMeasuredDepth() const; + + RimWellPath* childWell() const; + void updateChildWellGeometry(); + + void updateFirstTargetFromParentWell(); + + const RimWellPathValve* outletValve() const; + +private: + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly ) override; + +private: + caf::PdmPtrField m_parentWell; + caf::PdmPtrField m_childWell; + caf::PdmField m_tieInMeasuredDepth; + + caf::PdmField m_addValveAtConnection; + caf::PdmChildField m_valve; +}; diff --git a/ApplicationLibCode/ReservoirDataModel/RigWellPathIntersectionTools.cpp b/ApplicationLibCode/ReservoirDataModel/RigWellPathIntersectionTools.cpp index 0eb8592453..7ddc9e2c47 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigWellPathIntersectionTools.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigWellPathIntersectionTools.cpp @@ -159,6 +159,8 @@ std::vector RigWellPathIntersectionTools::buildCon { std::vector intersectionsNoGap; + if ( originalIntersections.empty() ) return intersectionsNoGap; + for ( size_t i = 0; i < originalIntersections.size() - 1; i++ ) { const WellPathCellIntersectionInfo& current = originalIntersections[i]; diff --git a/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp b/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp index db9e2777f1..eac3df615d 100644 --- a/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp @@ -531,7 +531,6 @@ void RiuViewerCommands::displayContextMenu( QMouseEvent* event ) menuBuilder << "RicNewWellPathStimPlanModelAtPosFeature"; menuBuilder.addSeparator(); menuBuilder << "RicNewWellPathAttributeFeature"; - menuBuilder << "RicWellPathImportCompletionsFileFeature"; menuBuilder.subMenuEnd(); diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 70036125a0..c9130e6846 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -10,7 +10,7 @@ set(RESINSIGHT_VERSION_TEXT "-dev") # Must be unique and increasing within one combination of major/minor/patch version # The uniqueness of this text is independent of RESINSIGHT_VERSION_TEXT # Format of text must be ".xx" -set(RESINSIGHT_DEV_VERSION ".02") +set(RESINSIGHT_DEV_VERSION ".11") # https://github.com/CRAVA/crava/tree/master/libs/nrlib set(NRLIB_GITHUB_SHA "ba35d4359882f1c6f5e9dc30eb95fe52af50fd6f")