diff --git a/ApplicationCode/CommandFileInterface/RicfExportMsw.cpp b/ApplicationCode/CommandFileInterface/RicfExportMsw.cpp index 5e83e13528..8504eb259e 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportMsw.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportMsw.cpp @@ -33,7 +33,8 @@ #include "RimFishbonesCollection.h" #include "RimFishbonesMultipleSubs.h" -#include "CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h" +#include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h" +#include "CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h" CAF_PDM_SOURCE_INIT(RicfExportMsw, "exportMsw"); @@ -44,6 +45,10 @@ RicfExportMsw::RicfExportMsw() { RICF_InitField(&m_caseId, "caseId", -1, "Case ID", "", "", ""); RICF_InitField(&m_wellPathName, "wellPath", QString(), "Well Path Name", "", "", ""); + RICF_InitField(&m_includePerforations, "includePerforations", true, "Include Perforations", "", "", ""); + RICF_InitField(&m_includeFishbones, "includeFishbones", true, "Include Fishbones", "", "", ""); + RICF_InitField(&m_includeFractures, "includeFractures", true, "Include Fractures", "", "", ""); + } //-------------------------------------------------------------------------------------------------- @@ -53,7 +58,7 @@ void RicfExportMsw::execute() { using TOOLS = RicfApplicationTools; - RicCaseAndFileExportSettingsUi exportSettings; + RicExportCompletionDataSettingsUi exportSettings; auto eclipseCase = TOOLS::caseFromId(m_caseId()); if (!eclipseCase) @@ -67,7 +72,11 @@ void RicfExportMsw::execute() { exportFolder = RiaApplication::instance()->createAbsolutePathFromProjectRelativePath("completions"); } + exportSettings.caseToApply = eclipseCase; exportSettings.folder = exportFolder; + exportSettings.includePerforations = m_includePerforations; + exportSettings.includeFishbones = m_includeFishbones; + exportSettings.includeFractures = m_includeFractures; RimWellPath* wellPath = RiaApplication::instance()->project()->wellPathByName(m_wellPathName); if (!wellPath) @@ -76,8 +85,5 @@ void RicfExportMsw::execute() return; } - if (!wellPath->fishbonesCollection()->activeFishbonesSubs().empty()) - { - RicExportFishbonesWellSegmentsFeature::exportWellSegments(wellPath, wellPath->fishbonesCollection()->activeFishbonesSubs(), exportSettings); - } + RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions(exportSettings, { wellPath }); } diff --git a/ApplicationCode/CommandFileInterface/RicfExportMsw.h b/ApplicationCode/CommandFileInterface/RicfExportMsw.h index f807440c04..078032f526 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportMsw.h +++ b/ApplicationCode/CommandFileInterface/RicfExportMsw.h @@ -39,4 +39,7 @@ public: private: caf::PdmField m_caseId; caf::PdmField m_wellPathName; + caf::PdmField m_includePerforations; + caf::PdmField m_includeFishbones; + caf::PdmField m_includeFractures; }; \ No newline at end of file diff --git a/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake index afb36783e7..ba757cea64 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake @@ -3,9 +3,10 @@ set (SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionDataSettingsUi.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionDataFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionDataFeatureImpl.h +${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswCompletionsImpl.h +${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionsFileTools.h ${CMAKE_CURRENT_LIST_DIR}/RicFishbonesTransmissibilityCalculationFeatureImp.h -${CMAKE_CURRENT_LIST_DIR}/RicExportFishbonesWellSegmentsFeature.h -${CMAKE_CURRENT_LIST_DIR}/RicExportFracturesWellSegmentsFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsWellSegmentsFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicCaseAndFileExportSettingsUi.h ${CMAKE_CURRENT_LIST_DIR}/RicExportFractureCompletionsImpl.h ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForVisibleWellPathsFeature.h @@ -24,9 +25,10 @@ set (SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionDataSettingsUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionDataFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionDataFeatureImpl.cpp +${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswCompletionsImpl.cpp +${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionsFileTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RicFishbonesTransmissibilityCalculationFeatureImp.cpp -${CMAKE_CURRENT_LIST_DIR}/RicExportFishbonesWellSegmentsFeature.cpp -${CMAKE_CURRENT_LIST_DIR}/RicExportFracturesWellSegmentsFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsWellSegmentsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicCaseAndFileExportSettingsUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportFractureCompletionsImpl.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForVisibleWellPathsFeature.cpp diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp similarity index 55% rename from ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.cpp rename to ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp index 19d69c5bcb..134f966661 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp @@ -16,7 +16,7 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RicExportFishbonesWellSegmentsFeature.h" +#include "RicExportCompletionsWellSegmentsFeature.h" #include "RiaApplication.h" #include "RiaLogging.h" @@ -26,12 +26,16 @@ #include "RicExportFeatureImpl.h" #include "RicMswExportInfo.h" #include "RicWellPathExportCompletionDataFeatureImpl.h" +#include "RicWellPathExportMswCompletionsImpl.h" +#include "RicWellPathExportCompletionsFileTools.h" #include "RimProject.h" #include "RimFishboneWellPathCollection.h" #include "RimFishbonesCollection.h" #include "RimFishbonesMultipleSubs.h" +#include "RimPerforationCollection.h" #include "RimWellPath.h" +#include "RimWellPathFractureCollection.h" #include "RimEclipseCase.h" #include "RigMainGrid.h" @@ -50,18 +54,25 @@ #include -CAF_CMD_SOURCE_INIT(RicExportFishbonesWellSegmentsFeature, "RicExportFishbonesWellSegmentsFeature"); +CAF_CMD_SOURCE_INIT(RicExportCompletionsWellSegmentsFeature, "RicExportCompletionsWellSegmentsFeature"); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicExportFishbonesWellSegmentsFeature::onActionTriggered(bool isChecked) +void RicExportCompletionsWellSegmentsFeature::onActionTriggered(bool isChecked) { - RimFishbonesCollection* fishbonesCollection = caf::SelectionManager::instance()->selectedItemAncestorOfType(); RimWellPath* wellPath = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - CVF_ASSERT(fishbonesCollection); CVF_ASSERT(wellPath); + RimFishbonesCollection* fishbonesCollection = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + RimWellPathFractureCollection* fractureCollection = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + RimPerforationCollection* perforationCollection = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + + CVF_ASSERT(fishbonesCollection || fractureCollection || perforationCollection); + RiaApplication* app = RiaApplication::instance(); QString defaultDir = RiaApplication::instance()->lastUsedDialogDirectoryWithFallbackToProjectFolder("COMPLETIONS"); @@ -87,18 +98,22 @@ void RicExportFishbonesWellSegmentsFeature::onActionTriggered(bool isChecked) if (propertyDialog.exec() == QDialog::Accepted) { RiaApplication::instance()->setLastUsedDialogDirectory("COMPLETIONS", QFileInfo(exportSettings.folder).absolutePath()); + RicExportCompletionDataSettingsUi completionExportSettings; + completionExportSettings.caseToApply.setValue(exportSettings.caseToApply); + completionExportSettings.folder.setValue(exportSettings.folder); - if (!fishbonesCollection->activeFishbonesSubs().empty()) - { - exportWellSegments(wellPath, fishbonesCollection->activeFishbonesSubs(), exportSettings); - } + completionExportSettings.includeFishbones = fishbonesCollection != nullptr && !fishbonesCollection->activeFishbonesSubs().empty(); + completionExportSettings.includeFractures = fractureCollection != nullptr && !fractureCollection->activeFractures().empty(); + completionExportSettings.includePerforations = perforationCollection != nullptr && !perforationCollection->activePerforations().empty(); + + RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions(completionExportSettings, { wellPath }); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicExportFishbonesWellSegmentsFeature::setupActionLook(QAction* actionToSetup) +void RicExportCompletionsWellSegmentsFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Export Well Segments"); } @@ -106,55 +121,20 @@ void RicExportFishbonesWellSegmentsFeature::setupActionLook(QAction* actionToSet //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RicExportFishbonesWellSegmentsFeature::isCommandEnabled() +bool RicExportCompletionsWellSegmentsFeature::isCommandEnabled() { if (caf::SelectionManager::instance()->selectedItemAncestorOfType()) { return true; } + else if (caf::SelectionManager::instance()->selectedItemAncestorOfType()) + { + return true; + } + else if (caf::SelectionManager::instance()->selectedItemAncestorOfType()) + { + return true; + } return false; } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFishbonesWellSegmentsFeature::exportWellSegments(const RimWellPath* wellPath, const std::vector& fishbonesSubs, const RicCaseAndFileExportSettingsUi& settings) -{ - if (fishbonesSubs.empty()) return; - - if (settings.caseToApply() == nullptr) - { - RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - QString fileName = QString("%1-Welsegs").arg(settings.caseToApply()->caseUserDescription()); - fileName = caf::Utils::makeValidFileBasename(fileName); - - QDir exportFolder(settings.folder()); - if (!exportFolder.exists()) - { - bool createdPath = exportFolder.mkpath("."); - if (createdPath) - RiaLogging::info("Created export folder " + settings.folder()); - else - RiaLogging::error("Selected output folder does not exist, and could not be created."); - } - - QString filePath = exportFolder.filePath(fileName); - QFile exportFile(filePath); - if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) - { - RiaLogging::error(QString("Export Well Segments: Could not open the file: %1").arg(filePath)); - return; - } - - RicMswExportInfo exportInfo = RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo(settings.caseToApply, wellPath, fishbonesSubs, true); - - QTextStream stream(&exportFile); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable (formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateWsegvalvTable(formatter, exportInfo); -} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.h b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.h similarity index 80% rename from ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.h rename to ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.h index aac083976f..7e4f477001 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.h @@ -22,22 +22,22 @@ #include "cafCmdFeature.h" +class RimFishbonesCollection; +class RimFishbonesMultipleSubs; class RimWellPath; -class RimWellPathFracture; -class RimWellPathFractureCollection; + + //================================================================================================== /// //================================================================================================== -class RicExportFracturesWellSegmentsFeature : public caf::CmdFeature +class RicExportCompletionsWellSegmentsFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; -public: - static void exportWellSegments(const RimWellPath* wellPath, const std::vector& fractures, const RicCaseAndFileExportSettingsUi& settings); - protected: void onActionTriggered(bool isChecked) override; void setupActionLook(QAction* actionToSetup) override; bool isCommandEnabled() override; + }; diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h b/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h deleted file mode 100644 index a8ba80aa1c..0000000000 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h +++ /dev/null @@ -1,47 +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 "RicCaseAndFileExportSettingsUi.h" - -#include "cafCmdFeature.h" - -class RimFishbonesCollection; -class RimFishbonesMultipleSubs; -class RimWellPath; - - - -//================================================================================================== -/// -//================================================================================================== -class RicExportFishbonesWellSegmentsFeature : public caf::CmdFeature -{ - CAF_CMD_HEADER_INIT; - -protected: - void onActionTriggered(bool isChecked) override; - void setupActionLook(QAction* actionToSetup) override; - bool isCommandEnabled() override; - -public: - static void exportWellSegments(const RimWellPath* wellPath, - const std::vector& fishbonesSubs, - const RicCaseAndFileExportSettingsUi& settings); -}; diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.cpp deleted file mode 100644 index b1e8fc5eb8..0000000000 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.cpp +++ /dev/null @@ -1,168 +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 "RicExportFracturesWellSegmentsFeature.h" - -#include "RiaApplication.h" -#include "RiaLogging.h" - -#include "RicCaseAndFileExportSettingsUi.h" -#include "RicExportFeatureImpl.h" -#include "RicMswExportInfo.h" -#include "RicWellPathExportCompletionDataFeatureImpl.h" - -#include "RimProject.h" -#include "RimWellPath.h" -#include "RimWellPathFracture.h" -#include "RimWellPathFractureCollection.h" - -#include "RifEclipseDataTableFormatter.h" - -#include "Riu3DMainWindowTools.h" - -#include "cafSelectionManager.h" -#include "cafPdmUiPropertyViewDialog.h" -#include "cafUtils.h" - -#include -#include - - -CAF_CMD_SOURCE_INIT(RicExportFracturesWellSegmentsFeature, "RicExportFracturesWellSegmentsFeature"); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFracturesWellSegmentsFeature::exportWellSegments(const RimWellPath* wellPath, const std::vector& fractures, const RicCaseAndFileExportSettingsUi& settings) -{ - if (settings.caseToApply() == nullptr) - { - RiaLogging::error("Export Fracture Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - QString fileName = QString("%1-Fracture-Welsegs").arg(settings.caseToApply()->caseUserDescription()); - fileName = caf::Utils::makeValidFileBasename(fileName); - - QDir exportFolder(settings.folder()); - if (!exportFolder.exists()) - { - bool createdPath = exportFolder.mkpath("."); - if (createdPath) - RiaLogging::info("Export Fracture Well Segments: Created export folder " + settings.folder()); - else - RiaLogging::error("Export Fracture Well Segments: Selected output folder does not exist, and could not be created."); - } - - QString filePath = exportFolder.filePath(fileName); - QFile exportFile(filePath); - if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) - { - RiaLogging::error(QString("Export Fracture Well Segments: Could not open the file: %1").arg(filePath)); - return; - } - - RicMswExportInfo exportInfo = RicWellPathExportCompletionDataFeatureImpl::generateFracturesMswExportInfo(settings.caseToApply, wellPath, fractures); - - QTextStream stream(&exportFile); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFracturesWellSegmentsFeature::onActionTriggered(bool isChecked) -{ - RimWellPath* wellPath = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - RimWellPathFracture* fracture = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - RimWellPathFractureCollection* collection = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - - CVF_ASSERT(wellPath); - CVF_ASSERT(collection); - - RiaApplication* app = RiaApplication::instance(); - - QString defaultDir = RiaApplication::instance()->lastUsedDialogDirectoryWithFallbackToProjectFolder("COMPLETIONS"); - - RicCaseAndFileExportSettingsUi exportSettings; - std::vector cases; - app->project()->allCases(cases); - for (auto c : cases) - { - RimEclipseCase* eclipseCase = dynamic_cast(c); - if (eclipseCase != nullptr) - { - exportSettings.caseToApply = eclipseCase; - break; - } - } - - exportSettings.folder = defaultDir; - - caf::PdmUiPropertyViewDialog propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), &exportSettings, "Export Fractures as Multi Segment Wells", ""); - RicExportFeatureImpl::configureForExport(&propertyDialog); - - if (propertyDialog.exec() == QDialog::Accepted) - { - RiaApplication::instance()->setLastUsedDialogDirectory("COMPLETIONS", QFileInfo(exportSettings.folder).absolutePath()); - std::vector fractures; - if (fracture) - { - fractures.push_back(fracture); - } - else - { - for (RimWellPathFracture* activeFracture : collection->activeFractures()) - { - fractures.push_back(activeFracture); - } - } - - exportWellSegments(wellPath, fractures, exportSettings); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFracturesWellSegmentsFeature::setupActionLook(QAction* actionToSetup) -{ - if (caf::SelectionManager::instance()->selectedItemOfType()) - { - actionToSetup->setText("Export Fracture as Multi Segment Well"); - } - else - { - actionToSetup->setText("Export Fractures as Multi Segment Well"); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicExportFracturesWellSegmentsFeature::isCommandEnabled() -{ - if (RiaApplication::enableDevelopmentFeatures() && caf::SelectionManager::instance()->selectedItemAncestorOfType()) - { - return true; - } - - return false; -} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp index e226d76a6c..acfe77e79d 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp @@ -19,7 +19,9 @@ #include "RicFishbonesTransmissibilityCalculationFeatureImp.h" #include "RicExportCompletionDataSettingsUi.h" +#include "RicMswExportInfo.h" #include "RicWellPathExportCompletionDataFeatureImpl.h" +#include "RicWellPathExportMswCompletionsImpl.h" #include "RigActiveCellInfo.h" #include "RigCompletionData.h" @@ -187,7 +189,7 @@ void RicFishbonesTransmissibilityCalculationFeatureImp::findFishboneLateralsWell // Generate data const RigEclipseCaseData* caseData = settings.caseToApply()->eclipseCaseData(); RicMswExportInfo exportInfo = - RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo(settings.caseToApply(), wellPath, false); + RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo(settings.caseToApply(), wellPath, false); RiaEclipseUnitTools::UnitSystem unitSystem = caseData->unitsType(); bool isMainBore = false; diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp index 2469dc7a50..facfeec7fd 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp @@ -32,6 +32,7 @@ #include "RicFishbonesTransmissibilityCalculationFeatureImp.h" #include "RicWellPathFractureReportItem.h" #include "RicWellPathFractureTextReportFeatureImpl.h" +#include "RicWellPathExportMswCompletionsImpl.h" #include "RifEclipseDataTableFormatter.h" @@ -76,55 +77,8 @@ #include #include #include +#include "RicWellPathExportCompletionsFileTools.h" -//-------------------------------------------------------------------------------------------------- -/// Internal definitions -//-------------------------------------------------------------------------------------------------- -class SubSegmentIntersectionInfo -{ -public: - SubSegmentIntersectionInfo(size_t globCellIndex, - double startTVD, - double endTVD, - double startMD, - double endMD, - cvf::Vec3d lengthsInCell) - : globCellIndex(globCellIndex) - , startTVD(startTVD) - , endTVD(endTVD) - , startMD(startMD) - , endMD(endMD) - , intersectionLengthsInCellCS(lengthsInCell) - { - } - - size_t globCellIndex; - double startTVD; - double endTVD; - double startMD; - double endMD; - cvf::Vec3d intersectionLengthsInCellCS; -}; - -const RimWellPath* findWellPathFromExportName(const QString& wellNameForExport); -std::vector - spiltIntersectionSegmentsToMaxLength(const RigWellPath* pathGeometry, - const std::vector& intersections, - double maxSegmentLength); -int numberOfSplittedSegments(double startMd, double endMd, double maxSegmentLength); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -class OpenFileException -{ -public: - OpenFileException(const QString& message) - : message(message) - { - } - QString message; -}; //-------------------------------------------------------------------------------------------------- /// @@ -458,77 +412,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions(const std::ve if (exportSettings.includeMsw) { - if (exportSettings.includeFractures()) - { - bool anyActiveFractures = false; - - for (const auto& wellPath : wellPaths) - { - if (!wellPath->fractureCollection()->activeFractures().empty()) - { - anyActiveFractures = true; - } - } - - if (anyActiveFractures) - { - QString fileName = QString("%1-Fracture-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); - QFilePtr exportFile = openFileForExport(exportSettings.folder, fileName); - - for (const auto wellPath : wellPaths) - { - auto fractures = wellPath->fractureCollection()->activeFractures(); - if (!fractures.empty()) - { - exportWellSegments(exportSettings.caseToApply, exportFile, wellPath, fractures); - } - } - exportFile->close(); - } - } - - if (exportSettings.includeFishbones()) - { - bool anyFishbones = false; - - for (const auto& wellPath : wellPaths) - { - if (!wellPath->fishbonesCollection()->activeFishbonesSubs().empty()) - { - anyFishbones = true; - } - } - - if (anyFishbones) - { - QString fileName = QString("%1-Fishbone-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); - QFilePtr exportFile = openFileForExport(exportSettings.folder, fileName); - - for (const auto wellPath : wellPaths) - { - auto fishbones = wellPath->fishbonesCollection()->activeFishbonesSubs(); - if (!fishbones.empty()) - { - exportWellSegments(exportSettings.caseToApply, exportFile, wellPath, fishbones); - } - } - - exportFile->close(); - } - } - - if (exportSettings.includePerforations()) - { - QString fileName = QString("%1-Perforation-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); - QFilePtr exportFile = openFileForExport(exportSettings.folder, fileName); - - for (const auto wellPath : wellPaths) - { - auto perforations = wellPath->perforationIntervalCollection()->perforations(); - exportWellSegments(exportSettings, exportFile, wellPath, perforations); - } - exportFile->close(); - } + RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions(exportSettings, wellPaths); } } @@ -595,430 +479,6 @@ std::vector return completionsPerEclipseCell; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo) -{ - formatter.keyword("WELSEGS"); - - double startMD = exportInfo.initialMD(); - double startTVD = exportInfo.initialTVD(); - - { - std::vector header = { - RifEclipseOutputTableColumn("Name"), - RifEclipseOutputTableColumn("Dep 1"), - RifEclipseOutputTableColumn("Tlen 1"), - RifEclipseOutputTableColumn("Vol 1"), - RifEclipseOutputTableColumn("Len&Dep"), - RifEclipseOutputTableColumn("PresDrop"), - }; - formatter.header(header); - - formatter.add(exportInfo.wellPath()->name()); - formatter.add(startTVD); - formatter.add(startMD); - formatter.addValueOrDefaultMarker(exportInfo.topWellBoreVolume(), RicMswExportInfo::defaultDoubleValue()); - formatter.add(exportInfo.lengthAndDepthText()); - formatter.add(exportInfo.pressureDropText()); - - formatter.rowCompleted(); - } - - { - std::vector header = { - RifEclipseOutputTableColumn("First Seg"), - RifEclipseOutputTableColumn("Last Seg"), - RifEclipseOutputTableColumn("Branch Num"), - RifEclipseOutputTableColumn("Outlet Seg"), - RifEclipseOutputTableColumn("Length"), - RifEclipseOutputTableColumn("Depth Change"), - RifEclipseOutputTableColumn("Diam"), - RifEclipseOutputTableColumn("Rough"), - }; - formatter.header(header); - } - - { - double prevMD = exportInfo.initialMD(); - double prevTVD = exportInfo.initialTVD(); - formatter.comment("Main Stem Segments"); - for (std::shared_ptr location : exportInfo.wellSegmentLocations()) - { - double depth = 0; - double length = 0; - - if (exportInfo.lengthAndDepthText() == QString("INC")) - { - depth = location->endTVD() - prevTVD; - length = location->endMD() - prevMD; - } - else - { - depth = location->endTVD(); - length = location->endMD(); - } - - if (location->subIndex() != cvf::UNDEFINED_SIZE_T) - { - QString comment = location->label() + QString(", sub %1").arg(location->subIndex()); - formatter.comment(comment); - } - - formatter.add(location->segmentNumber()).add(location->segmentNumber()); - formatter.add(1); // All segments on main stem are branch 1 - formatter.add(location->segmentNumber() - 1); // All main stem segments are connected to the segment below them - formatter.add(length); - formatter.add(depth); - formatter.add(exportInfo.linerDiameter()); - formatter.add(exportInfo.roughnessFactor()); - formatter.rowCompleted(); - prevMD = location->endMD(); - prevTVD = location->endTVD(); - } - } - - { - generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::FISHBONES_ICD, RigCompletionData::FISHBONES}); - generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::FRACTURE}); - generateWelsegsSegments(formatter, exportInfo, { RigCompletionData::PERFORATION_ICD }); - } - - formatter.tableCompleted(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWelsegsSegments( - RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - const std::set& exportCompletionTypes) -{ - bool generatedHeader = false; - for (std::shared_ptr segment : exportInfo.wellSegmentLocations()) - { - for (std::shared_ptr completion : segment->completions()) - { - if (exportCompletionTypes.count(completion->completionType())) - { - if (!generatedHeader) - { - generateWelsegsCompletionCommentHeader(formatter, completion->completionType()); - generatedHeader = true; - } - - if (completion->completionType() == RigCompletionData::FISHBONES_ICD || - completion->completionType() == RigCompletionData::PERFORATION_ICD) // Found ICD - { - if (!completion->subSegments().empty()) - { - formatter.comment(completion->label()); - - formatter.add(completion->subSegments().front()->segmentNumber()); - formatter.add(completion->subSegments().front()->segmentNumber()); - formatter.add(completion->branchNumber()); - formatter.add(segment->segmentNumber()); - formatter.add(0.1); // ICDs have 0.1 length - formatter.add(0); // Depth change - formatter.add(exportInfo.linerDiameter()); - formatter.add(exportInfo.roughnessFactor()); - formatter.rowCompleted(); - } - } - else - { - if (completion->completionType() == RigCompletionData::FISHBONES) - { - formatter.comment(QString("%1 : Sub index %2 - %3") - .arg(segment->label()) - .arg(segment->subIndex()) - .arg(completion->label())); - } - else if (completion->completionType() == RigCompletionData::FRACTURE) - { - formatter.comment(QString("%1 connected to %2").arg(completion->label()).arg(segment->label())); - } - - for (std::shared_ptr subSegment : completion->subSegments()) - { - double depth = 0; - double length = 0; - - if (exportInfo.lengthAndDepthText() == QString("INC")) - { - depth = subSegment->deltaTVD(); - length = subSegment->deltaMD(); - } - else - { - depth = subSegment->startTVD() + subSegment->deltaTVD(); - length = subSegment->startMD() + subSegment->deltaMD(); - } - double diameter = segment->effectiveDiameter(); - formatter.add(subSegment->segmentNumber()); - formatter.add(subSegment->segmentNumber()); - formatter.add(completion->branchNumber()); - formatter.add(subSegment->attachedSegmentNumber()); - formatter.add(length); - formatter.add(depth); - formatter.add(diameter); - formatter.add(segment->openHoleRoughnessFactor()); - formatter.rowCompleted(); - } - } - } - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWelsegsCompletionCommentHeader( - RifEclipseDataTableFormatter& formatter, - RigCompletionData::CompletionType completionType) -{ - if (completionType == RigCompletionData::CT_UNDEFINED) - { - formatter.comment("Main stem"); - } - else if (completionType == RigCompletionData::FISHBONES_ICD) - { - formatter.comment("Fishbones segments"); - formatter.comment("Diam: MSW - Tubing Radius"); - formatter.comment("Rough: MSW - Open Hole Roughness Factor"); - } - else if (completionType == RigCompletionData::PERFORATION_ICD) - { - formatter.comment("Perforation valve segments"); - formatter.comment("Diam: MSW - Tubing Radius"); - formatter.comment("Rough: MSW - Open Hole Roughness Factor"); - } - else if (completionType == RigCompletionData::FRACTURE) - { - formatter.comment("Fracture Segments"); - formatter.comment("Diam: MSW - Default Dummy"); - formatter.comment("Rough: MSW - Default Dummy"); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(RifEclipseDataTableFormatter& formatter, - const 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 fishbonesTypes = {RigCompletionData::FISHBONES_ICD, - RigCompletionData::FISHBONES}; - generateCompsegTable(formatter, exportInfo, false, fishbonesTypes); - if (exportInfo.hasSubGridIntersections()) - { - generateCompsegTable(formatter, exportInfo, true, fishbonesTypes); - } - } - - { - std::set fractureTypes = {RigCompletionData::FRACTURE}; - generateCompsegTable(formatter, exportInfo, false, fractureTypes); - if (exportInfo.hasSubGridIntersections()) - { - generateCompsegTable(formatter, exportInfo, true, fractureTypes); - } - } - - { - std::set perforationTypes = {RigCompletionData::PERFORATION, - RigCompletionData::PERFORATION_ICD}; - generateCompsegTable(formatter, exportInfo, false, perforationTypes); - if (exportInfo.hasSubGridIntersections()) - { - generateCompsegTable(formatter, exportInfo, true, perforationTypes); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateCompsegTable( - RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - bool exportSubGridIntersections, - const std::set& exportCompletionTypes) -{ - bool generatedHeader = false; - - for (std::shared_ptr location : exportInfo.wellSegmentLocations()) - { - double startMD = location->startMD(); - - for (std::shared_ptr completion : location->completions()) - { - if (!completion->subSegments().empty() && exportCompletionTypes.count(completion->completionType())) - { - if (!generatedHeader) - { - generateCompsegHeader(formatter, exportInfo, completion->completionType(), exportSubGridIntersections); - generatedHeader = true; - } - - for (std::shared_ptr segment : completion->subSegments()) - { - if (completion->completionType() == RigCompletionData::FISHBONES_ICD) - { - startMD = segment->startMD(); - } - - for (std::shared_ptr intersection : segment->intersections()) - { - bool isSubGridIntersection = !intersection->gridName().isEmpty(); - if (isSubGridIntersection == exportSubGridIntersections) - { - if (exportSubGridIntersections) - { - formatter.add(intersection->gridName()); - } - cvf::Vec3st ijk = intersection->gridLocalCellIJK(); - formatter.addOneBasedCellIndex(ijk.x()).addOneBasedCellIndex(ijk.y()).addOneBasedCellIndex(ijk.z()); - formatter.add(completion->branchNumber()); - - double startLength = segment->startMD(); - if (exportInfo.lengthAndDepthText() == QString("INC") && - completion->completionType() != RigCompletionData::PERFORATION) - { - startLength -= startMD; - } - formatter.add(startLength); - formatter.add(startLength + segment->deltaMD()); - - formatter.rowCompleted(); - } - } - } - } - } - } - if (generatedHeader) - { - formatter.tableCompleted(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateCompsegHeader(RifEclipseDataTableFormatter& formatter, - const 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 = {RifEclipseOutputTableColumn("Name")}; - formatter.header(header); - formatter.add(exportInfo.wellPath()->name()); - formatter.rowCompleted(); - } - - { - std::vector allHeaders; - if (exportSubGridIntersections) - { - allHeaders.push_back(RifEclipseOutputTableColumn("Grid")); - } - - std::vector commonHeaders = {RifEclipseOutputTableColumn("I"), - RifEclipseOutputTableColumn("J"), - RifEclipseOutputTableColumn("K"), - RifEclipseOutputTableColumn("Branch no"), - RifEclipseOutputTableColumn("Start Length"), - RifEclipseOutputTableColumn("End Length"), - RifEclipseOutputTableColumn("Dir Pen"), - RifEclipseOutputTableColumn("End Range"), - RifEclipseOutputTableColumn("Connection Depth")}; - allHeaders.insert(allHeaders.end(), commonHeaders.begin(), commonHeaders.end()); - formatter.header(allHeaders); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWsegvalvTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo) -{ - bool foundValve = false; - - for (std::shared_ptr location : exportInfo.wellSegmentLocations()) - { - for (std::shared_ptr completion : location->completions()) - { - if (completion->completionType() == RigCompletionData::FISHBONES_ICD || - completion->completionType() == RigCompletionData::PERFORATION_ICD) - { - if (!foundValve) - { - formatter.keyword("WSEGVALV"); - std::vector header = { - RifEclipseOutputTableColumn("Well Name"), - RifEclipseOutputTableColumn("Seg No"), - RifEclipseOutputTableColumn("Cv"), - RifEclipseOutputTableColumn("Ac"), - }; - formatter.header(header); - - foundValve = true; - } - if (completion->completionType() == RigCompletionData::FISHBONES_ICD || - completion->completionType() == RigCompletionData::PERFORATION_ICD) - { - std::shared_ptr icd = std::static_pointer_cast(completion); - if (!icd->subSegments().empty()) - { - CVF_ASSERT(icd->subSegments().size() == 1u); - formatter.comment(icd->label()); - formatter.add(exportInfo.wellPath()->name()); - formatter.add(icd->subSegments().front()->segmentNumber()); - formatter.add(icd->flowCoefficient()); - formatter.add(QString("%1").arg(icd->area(), 8, 'g', 4)); - formatter.rowCompleted(); - } - } - } - } - } - if (foundValve) - { - formatter.tableCompleted(); - } -} - //================================================================================================== /// //================================================================================================== @@ -1141,45 +601,6 @@ RigCompletionData return resultCompletion; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QFilePtr RicWellPathExportCompletionDataFeatureImpl::openFileForExport(const QString& fullFileName) -{ - std::pair folderAndFileName = RiaFilePathTools::toFolderAndFileName(fullFileName); - return openFileForExport(folderAndFileName.first, folderAndFileName.second); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QFilePtr RicWellPathExportCompletionDataFeatureImpl::openFileForExport(const QString& folderName, const QString& fileName) -{ - QDir exportFolder = QDir(folderName); - if (!exportFolder.exists()) - { - bool createdPath = exportFolder.mkpath("."); - if (createdPath) - RiaLogging::info("Created export folder " + folderName); - else - { - auto errorMessage = QString("Selected output folder does not exist, and could not be created."); - RiaLogging::error(errorMessage); - throw OpenFileException(errorMessage); - } - } - - QString filePath = exportFolder.filePath(fileName); - QFilePtr exportFile(new QFile(filePath)); - if (!exportFile->open(QIODevice::WriteOnly | QIODevice::Text)) - { - auto errorMessage = QString("Export Completions Data: Could not open the file: %1").arg(filePath); - RiaLogging::error(errorMessage); - throw OpenFileException(errorMessage); - } - return exportFile; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1306,7 +727,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspecsToFile(RimEclipse // Build list of unique RimWellPath for (const auto& completion : completions) { - const auto wellPath = findWellPathFromExportName(completion.wellName()); + const auto wellPath = RicWellPathExportCompletionsFileTools::findWellPathFromExportName(completion.wellName()); if (wellPath) { wellPathSet.insert(wellPath); @@ -1361,7 +782,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspeclToFile( { for (const auto& completion : completionsForLgr.second) { - const auto wellPath = findWellPathFromExportName(completion.wellName()); + const auto wellPath = RicWellPathExportCompletionsFileTools::findWellPathFromExportName(completion.wellName()); auto item = wellPathToLgrNameMap.find(wellPath); wellPathToLgrNameMap[wellPath].insert(completionsForLgr.first); } @@ -1426,7 +847,7 @@ void RicWellPathExportCompletionDataFeatureImpl::sortAndExportCompletionsToFile( { try { - QFilePtr exportFile = openFileForExport(folderName, fileName); + std::shared_ptr exportFile = RicWellPathExportCompletionsFileTools::openFileForExport(folderName, fileName); std::map> completionsForGrid; completionsForGrid.insert(std::pair>("", completionsForMainGrid)); @@ -1435,7 +856,7 @@ void RicWellPathExportCompletionDataFeatureImpl::sortAndExportCompletionsToFile( exportWelspecsToFile(eclipseCase, exportFile, completionsForMainGrid); exportCompdatAndWpimultTables(eclipseCase, exportFile, completionsForGrid, exportType); } - catch (OpenFileException) + catch (RicWellPathExportCompletionsFileTools::OpenFileException) { } } @@ -1445,13 +866,13 @@ void RicWellPathExportCompletionDataFeatureImpl::sortAndExportCompletionsToFile( try { QString lgrFileName = fileName + "_LGR"; - QFilePtr exportFile = openFileForExport(folderName, lgrFileName); + std::shared_ptr exportFile = RicWellPathExportCompletionsFileTools::openFileForExport(folderName, lgrFileName); exportWellPathFractureReport(eclipseCase, exportFile, wellPathFractureReportItems); exportWelspeclToFile(eclipseCase, exportFile, completionsForSubGrids); exportCompdatAndWpimultTables(eclipseCase, exportFile, completionsForSubGrids, exportType); } - catch (OpenFileException) + catch (RicWellPathExportCompletionsFileTools::OpenFileException) { } } @@ -1783,724 +1204,6 @@ std::vector RicWellPathExportCompletionDataFeatureImpl::gener return completionData; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - bool enableSegmentSplitting) -{ - std::vector fishbonesSubs = wellPath->fishbonesCollection()->activeFishbonesSubs(); - - return generateFishbonesMswExportInfo(caseToApply, wellPath, fishbonesSubs, enableSegmentSplitting); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo( - const RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fishbonesSubs, - bool enableSegmentSplitting) -{ - RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); - - RicMswExportInfo exportInfo(wellPath, - unitSystem, - wellPath->fishbonesCollection()->startMD(), - wellPath->fishbonesCollection()->mswParameters()->lengthAndDepth().text(), - wellPath->fishbonesCollection()->mswParameters()->pressureDrop().text()); - exportInfo.setLinerDiameter(wellPath->fishbonesCollection()->mswParameters()->linerDiameter(unitSystem)); - exportInfo.setRoughnessFactor(wellPath->fishbonesCollection()->mswParameters()->roughnessFactor(unitSystem)); - - double maxSegmentLength = enableSegmentSplitting ? wellPath->fishbonesCollection()->mswParameters()->maxSegmentLength() - : std::numeric_limits::infinity(); - bool foundSubGridIntersections = false; - double subStartMD = wellPath->fishbonesCollection()->startMD(); - for (RimFishbonesMultipleSubs* subs : fishbonesSubs) - { - for (auto& sub : subs->installedLateralIndices()) - { - double subEndMD = subs->measuredDepth(sub.subIndex); - double subEndTVD = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(subEndMD).z(); - int subSegCount = numberOfSplittedSegments(subStartMD, subEndMD, maxSegmentLength); - double subSegLen = (subEndMD - subStartMD) / subSegCount; - - double startMd = subStartMD; - double startTvd = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(startMd).z(); - for (int ssi = 0; ssi < subSegCount; ssi++) - { - double endMd = startMd + subSegLen; - double endTvd = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(endMd).z(); - - std::shared_ptr location (new RicMswSegment(subs->generatedName(), startMd, endMd, startTvd, endTvd, sub.subIndex)); - location->setEffectiveDiameter(subs->effectiveDiameter(unitSystem)); - location->setHoleDiameter(subs->holeDiameter(unitSystem)); - location->setOpenHoleRoughnessFactor(subs->openHoleRoughnessFactor(unitSystem)); - location->setSkinFactor(subs->skinFactor()); - location->setSourcePdmObject(subs); - - if (ssi == 0) - { - // Add completion for ICD - std::shared_ptr icdCompletion(new RicMswFishbonesICD(QString("ICD"))); - std::shared_ptr icdSegment(new RicMswSubSegment(subEndMD, 0.1, subEndTVD, 0.0)); - icdCompletion->setFlowCoefficient(subs->icdFlowCoefficient()); - double icdOrificeRadius = subs->icdOrificeDiameter(unitSystem) / 2; - icdCompletion->setArea(icdOrificeRadius * icdOrificeRadius * cvf::PI_D * subs->icdCount()); - - icdCompletion->addSubSegment(icdSegment); - location->addCompletion(icdCompletion); - - for (size_t lateralIndex : sub.lateralIndices) - { - QString label = QString("Lateral %1").arg(lateralIndex); - location->addCompletion(std::make_shared(label, lateralIndex)); - } - assignFishbonesLateralIntersections( - caseToApply, subs, location, &foundSubGridIntersections, maxSegmentLength); - } - - exportInfo.addWellSegment(location); - - startMd = endMd; - startTvd = endTvd; - } - - subStartMD = subEndMD; - } - } - exportInfo.setHasSubGridIntersections(foundSubGridIntersections); - exportInfo.sortLocations(); - - assignBranchAndSegmentNumbers(caseToApply, &exportInfo); - - return exportInfo; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportCompletionDataFeatureImpl::generateFracturesMswExportInfo(RimEclipseCase* caseToApply, - const RimWellPath* wellPath) -{ - std::vector fractures = wellPath->fractureCollection()->activeFractures(); - - return generateFracturesMswExportInfo(caseToApply, wellPath, fractures); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo - RicWellPathExportCompletionDataFeatureImpl::generateFracturesMswExportInfo(RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fractures) -{ - const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); - const RigActiveCellInfo* activeCellInfo = caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); - RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); - - const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry(); - const std::vector& coords = wellPathGeometry->wellPathPoints(); - const std::vector& mds = wellPathGeometry->measureDepths(); - CVF_ASSERT(!coords.empty() && !mds.empty()); - - std::vector intersections = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(caseToApply->eclipseCaseData(), coords, mds); - - double maxSegmentLength = wellPath->fractureCollection()->mswParameters()->maxSegmentLength(); - std::vector subSegIntersections = - spiltIntersectionSegmentsToMaxLength(wellPathGeometry, intersections, maxSegmentLength); - - double initialMD = 0.0; - if (wellPath->fractureCollection()->referenceMDType() == RimWellPathFractureCollection::MANUAL_REFERENCE_MD) - { - initialMD = wellPath->fractureCollection()->manualReferenceMD(); - } - else - { - for (WellPathCellIntersectionInfo intersection : intersections) - { - if (activeCellInfo->isActive(intersection.globCellIndex)) - { - initialMD = intersection.startMD; - break; - } - } - } - - RicMswExportInfo exportInfo(wellPath, - unitSystem, - initialMD, - wellPath->fractureCollection()->mswParameters()->lengthAndDepth().text(), - wellPath->fractureCollection()->mswParameters()->pressureDrop().text()); - - exportInfo.setLinerDiameter(wellPath->fractureCollection()->mswParameters()->linerDiameter(unitSystem)); - exportInfo.setRoughnessFactor(wellPath->fractureCollection()->mswParameters()->roughnessFactor(unitSystem)); - - bool foundSubGridIntersections = false; - - // Main bore - int mainBoreSegment = 1; - for (const auto& cellIntInfo : subSegIntersections) - { - double startTVD = cellIntInfo.startTVD; - double endTVD = cellIntInfo.endTVD; - - size_t localGridIdx = 0u; - const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); - QString gridName; - if (localGrid != grid) - { - gridName = QString::fromStdString(localGrid->gridName()); - foundSubGridIntersections = true; - } - - size_t i = 0u, j = 0u, k = 0u; - localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); - QString label = QString("Main stem segment %1").arg(++mainBoreSegment); - std::shared_ptr location(new RicMswSegment(label, cellIntInfo.startMD, cellIntInfo.endMD, startTVD, endTVD)); - - // Check if fractures are to be assigned to current main bore segment - for (RimWellPathFracture* fracture : fractures) - { - double fractureStartMD = fracture->fractureMD(); - if (fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH) - { - double perforationLength = fracture->fractureTemplate()->perforationLength(); - fractureStartMD -= 0.5 * perforationLength; - } - - if (cvf::Math::valueInRange(fractureStartMD, cellIntInfo.startMD, cellIntInfo.endMD)) - { - std::vector completionData = - RicExportFractureCompletionsImpl::generateCompdatValues(caseToApply, - wellPath->completions()->wellNameForExport(), - wellPath->wellPathGeometry(), - {fracture}, - nullptr, - nullptr); - - assignFractureIntersections(caseToApply, fracture, completionData, location, &foundSubGridIntersections); - } - } - - exportInfo.addWellSegment(location); - } - exportInfo.setHasSubGridIntersections(foundSubGridIntersections); - exportInfo.sortLocations(); - assignBranchAndSegmentNumbers(caseToApply, &exportInfo); - - return exportInfo; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportCompletionDataFeatureImpl::generatePerforationsMswExportInfo( - const RicExportCompletionDataSettingsUi& exportSettings, - const RimWellPath* wellPath, - const std::vector& perforationIntervals) -{ - const RimEclipseCase* caseToApply = exportSettings.caseToApply; - const RigActiveCellInfo* activeCellInfo = caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); - RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); - - const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry(); - const std::vector& coords = wellPathGeometry->wellPathPoints(); - const std::vector& mds = wellPathGeometry->measureDepths(); - CVF_ASSERT(!coords.empty() && !mds.empty()); - - std::vector intersections = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(caseToApply->eclipseCaseData(), coords, mds); - - double maxSegmentLength = wellPath->perforationIntervalCollection()->mswParameters()->maxSegmentLength(); - std::vector subSegIntersections = - spiltIntersectionSegmentsToMaxLength(wellPathGeometry, intersections, maxSegmentLength); - - double initialMD = 0.0; - for (WellPathCellIntersectionInfo intersection : intersections) - { - if (activeCellInfo->isActive(intersection.globCellIndex)) - { - initialMD = intersection.startMD; - break; - } - } - - RicMswExportInfo exportInfo(wellPath, - unitSystem, - initialMD, - wellPath->perforationIntervalCollection()->mswParameters()->lengthAndDepth().text(), - wellPath->perforationIntervalCollection()->mswParameters()->pressureDrop().text()); - - exportInfo.setLinerDiameter(wellPath->perforationIntervalCollection()->mswParameters()->linerDiameter(unitSystem)); - exportInfo.setRoughnessFactor(wellPath->perforationIntervalCollection()->mswParameters()->roughnessFactor(unitSystem)); - - bool foundSubGridIntersections = false; - - MainBoreSegments mainBoreSegments = createMainBoreSegments(subSegIntersections, perforationIntervals, wellPath, exportSettings, &foundSubGridIntersections); - - assignSuperValveCompletions(mainBoreSegments, perforationIntervals); - assignValveContributionsToSuperValves(mainBoreSegments, perforationIntervals, unitSystem); - moveIntersectionsToSuperValves(mainBoreSegments); - - for (std::shared_ptr segment : mainBoreSegments) - { - exportInfo.addWellSegment(segment); - } - - exportInfo.setHasSubGridIntersections(foundSubGridIntersections); - exportInfo.sortLocations(); - assignBranchAndSegmentNumbers(caseToApply, &exportInfo); - - return exportInfo; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicWellPathExportCompletionDataFeatureImpl::MainBoreSegments -RicWellPathExportCompletionDataFeatureImpl::createMainBoreSegments( - const std::vector& subSegIntersections, - const std::vector& perforationIntervals, - const RimWellPath* wellPath, - const RicExportCompletionDataSettingsUi& exportSettings, - bool* foundSubGridIntersections) -{ - MainBoreSegments mainBoreSegments; - - for (const auto& cellIntInfo : subSegIntersections) - { - if (std::fabs(cellIntInfo.endMD - cellIntInfo.startMD) > 1.0e-8) - { - QString label = QString("Main stem segment %1").arg(mainBoreSegments.size() + 2); - std::shared_ptr segment( - new RicMswSegment(label, cellIntInfo.startMD, cellIntInfo.endMD, cellIntInfo.startTVD, cellIntInfo.endTVD)); - - for (const RimPerforationInterval* interval : perforationIntervals) - { - double overlapStart = std::max(interval->startMD(), segment->startMD()); - double overlapEnd = std::min(interval->endMD(), segment->endMD()); - double overlap = std::max(0.0, overlapEnd - overlapStart); - if (overlap > 0.0) - { - std::shared_ptr intervalCompletion( - new RicMswPerforation(interval->name())); - std::vector completionData = - generatePerforationsCompdatValues(wellPath, {interval}, exportSettings); - assignPerforationIntervalIntersections( - completionData, intervalCompletion, cellIntInfo, foundSubGridIntersections); - segment->addCompletion(intervalCompletion); - } - } - mainBoreSegments.push_back(segment); - } - } - return mainBoreSegments; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignSuperValveCompletions( - std::vector>& mainBoreSegments, - const std::vector& perforationIntervals) -{ - for (size_t nMainSegment = 0u; nMainSegment < mainBoreSegments.size(); ++nMainSegment) - { - std::shared_ptr segment = mainBoreSegments[nMainSegment]; - - std::shared_ptr superValve; - for (const RimPerforationInterval* interval : perforationIntervals) - { - std::vector perforationValves; - interval->descendantsIncludingThisOfType(perforationValves); - - for (const RimWellPathValve* valve : perforationValves) - { - for (size_t nSubValve = 0u; nSubValve < valve->valveLocations().size(); ++nSubValve) - { - double valveMD = valve->valveLocations()[nSubValve]; - - std::pair valveSegment = valve->valveSegments()[nSubValve]; - double overlapStart = std::max(valveSegment.first, segment->startMD()); - double overlapEnd = std::min(valveSegment.second, segment->endMD()); - double overlap = std::max(0.0, overlapEnd - overlapStart); - - if (segment->startMD() <= valveMD && valveMD < segment->endMD()) - { - QString valveLabel = QString("%1 #%2").arg("Combined Valve for segment").arg(nMainSegment + 2); - superValve.reset(new RicMswPerforationICD(valveLabel)); - std::shared_ptr subSegment(new RicMswSubSegment(valveMD, 0.1, 0.0, 0.0)); - superValve->addSubSegment(subSegment); - } - else if (overlap > 0.0 && !superValve) - { - QString valveLabel = QString("%1 #%2").arg("Combined Valve for segment").arg(nMainSegment + 2); - superValve.reset(new RicMswPerforationICD(valveLabel)); - std::shared_ptr subSegment(new RicMswSubSegment(overlapStart, 0.1, 0.0, 0.0)); - superValve->addSubSegment(subSegment); - } - } - } - } - - if (superValve) - { - segment->addCompletion(superValve); - } - - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignValveContributionsToSuperValves( - const std::vector>& mainBoreSegments, - const std::vector& perforationIntervals, - RiaEclipseUnitTools::UnitSystem unitSystem) -{ - ValveContributionMap assignedRegularValves; - for (std::shared_ptr segment : mainBoreSegments) - { - std::shared_ptr superValve; - for (auto completion : segment->completions()) - { - std::shared_ptr valve = std::dynamic_pointer_cast(completion); - if (valve) - { - superValve = valve; - break; - } - } - - if (!superValve) continue; - - double totalIcdArea = 0.0; - RiaWeightedMeanCalculator coeffMeanCalc; - - for (const RimPerforationInterval* interval : perforationIntervals) - { - std::vector perforationValves; - interval->descendantsIncludingThisOfType(perforationValves); - - for (const RimWellPathValve* valve : perforationValves) - { - for (size_t nSubValve = 0u; nSubValve < valve->valveSegments().size(); ++nSubValve) - { - std::pair valveSegment = valve->valveSegments()[nSubValve]; - double valveSegmentLength = valveSegment.second - valveSegment.first; - double overlapStart = std::max(valveSegment.first, segment->startMD()); - double overlapEnd = std::min(valveSegment.second, segment->endMD()); - double overlap = std::max(0.0, overlapEnd - overlapStart); - - if (overlap > 0.0) - { - assignedRegularValves[superValve].insert(std::make_pair(valve, nSubValve)); - double icdOrificeRadius = valve->orificeDiameter(unitSystem) / 2; - double icdArea = icdOrificeRadius * icdOrificeRadius * cvf::PI_D * overlap / valveSegmentLength; - totalIcdArea += icdArea; - coeffMeanCalc.addValueAndWeight(valve->flowCoefficient(), icdArea); - } - } - } - } - superValve->setArea(totalIcdArea); - if (coeffMeanCalc.validAggregatedWeight()) - { - superValve->setFlowCoefficient(coeffMeanCalc.weightedMean()); - } - } - - for (auto regularValvePair : assignedRegularValves) - { - if (regularValvePair.second.size()) - { - QStringList valveLabels; - for (std::pair regularValve : regularValvePair.second) - { - QString valveLabel = QString("%1 #%2").arg(regularValve.first->name()).arg(regularValve.second + 1); - valveLabels.push_back(valveLabel); - } - QString valveContribLabel = QString(" with contribution from: %1").arg(valveLabels.join(", ")); - regularValvePair.first->setLabel(regularValvePair.first->label() + valveContribLabel); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::moveIntersectionsToSuperValves(MainBoreSegments mainBoreSegments) -{ - for (auto segmentPtr : mainBoreSegments) - { - std::shared_ptr superValve; - std::vector> perforations; - for (auto completionPtr : segmentPtr->completions()) - { - if (completionPtr->completionType() == RigCompletionData::PERFORATION_ICD) - { - superValve = completionPtr; - } - else - { - CVF_ASSERT(completionPtr->completionType() == RigCompletionData::PERFORATION); - perforations.push_back(completionPtr); - } - } - - if (superValve == nullptr) continue; - - CVF_ASSERT(superValve->subSegments().size() == 1u); - segmentPtr->completions().clear(); - segmentPtr->addCompletion(superValve); - for (auto perforationPtr : perforations) - { - for (auto subSegmentPtr : perforationPtr->subSegments()) - { - for (auto intersectionPtr : subSegmentPtr->intersections()) - { - superValve->subSegments()[0]->addIntersection(intersectionPtr); - } - } - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignFishbonesLateralIntersections( - const RimEclipseCase* caseToApply, - const RimFishbonesMultipleSubs* fishbonesSubs, - std::shared_ptr location, - bool* foundSubGridIntersections, - double maxSegmentLength) -{ - CVF_ASSERT(foundSubGridIntersections != nullptr); - - const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); - - for (std::shared_ptr completion : location->completions()) - { - if (completion->completionType() != RigCompletionData::FISHBONES) - { - continue; - } - - std::vector> lateralCoordMDPairs = - fishbonesSubs->coordsAndMDForLateral(location->subIndex(), completion->index()); - - if (lateralCoordMDPairs.empty()) - { - continue; - } - - std::vector lateralCoords; - std::vector lateralMDs; - - lateralCoords.reserve(lateralCoordMDPairs.size()); - lateralMDs.reserve(lateralCoordMDPairs.size()); - - for (auto& coordMD : lateralCoordMDPairs) - { - lateralCoords.push_back(coordMD.first); - lateralMDs.push_back(coordMD.second); - } - - std::vector intersections = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( - caseToApply->eclipseCaseData(), lateralCoords, lateralMDs); - - RigWellPath pathGeometry; - pathGeometry.m_wellPathPoints = lateralCoords; - pathGeometry.m_measuredDepths = lateralMDs; - std::vector subSegIntersections = - spiltIntersectionSegmentsToMaxLength(&pathGeometry, intersections, maxSegmentLength); - - double previousExitMD = lateralMDs.front(); - double previousExitTVD = -lateralCoords.front().z(); - - for (const auto& cellIntInfo : subSegIntersections) - { - size_t localGridIdx = 0u; - const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); - QString gridName; - if (localGrid != grid) - { - gridName = QString::fromStdString(localGrid->gridName()); - *foundSubGridIntersections = true; - } - - size_t i = 0u, j = 0u, k = 0u; - localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); - std::shared_ptr subSegment(new RicMswSubSegment( - previousExitMD, cellIntInfo.endMD - previousExitMD, previousExitTVD, cellIntInfo.endTVD - previousExitTVD)); - - std::shared_ptr intersection(new RicMswSubSegmentCellIntersection( - gridName, cellIntInfo.globCellIndex, cvf::Vec3st(i, j, k), cellIntInfo.intersectionLengthsInCellCS)); - subSegment->addIntersection(intersection); - completion->addSubSegment(subSegment); - - previousExitMD = cellIntInfo.endMD; - previousExitTVD = cellIntInfo.endTVD; - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignFractureIntersections(const RimEclipseCase* caseToApply, - const RimWellPathFracture* fracture, - const std::vector& completionData, - std::shared_ptr location, - bool* foundSubGridIntersections) -{ - CVF_ASSERT(foundSubGridIntersections != nullptr); - - std::shared_ptr fractureCompletion(new RicMswFracture(fracture->name())); - double position = fracture->fractureMD(); - double width = fracture->fractureTemplate()->computeFractureWidth(fracture); - - if (fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH) - { - double perforationLength = fracture->fractureTemplate()->perforationLength(); - position -= 0.5 * perforationLength; - width = perforationLength; - } - - std::shared_ptr subSegment(new RicMswSubSegment(position, width, 0.0, 0.0)); - for (const RigCompletionData& compIntersection : completionData) - { - const RigCompletionDataGridCell& cell = compIntersection.completionDataGridCell(); - cvf::Vec3st localIJK(cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK()); - - std::shared_ptr intersection(new RicMswSubSegmentCellIntersection(cell.lgrName(), cell.globalCellIndex(), localIJK, cvf::Vec3d::ZERO)); - subSegment->addIntersection(intersection); - } - fractureCompletion->addSubSegment(subSegment); - location->addCompletion(fractureCompletion); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignPerforationIntervalIntersections( - const std::vector& completionData, - std::shared_ptr perforationCompletion, - const SubSegmentIntersectionInfo& cellIntInfo, - bool* foundSubGridIntersections) -{ - size_t currCellId = cellIntInfo.globCellIndex; - - std::shared_ptr subSegment(new RicMswSubSegment(cellIntInfo.startMD, - cellIntInfo.endMD - cellIntInfo.startMD, - cellIntInfo.startTVD, - cellIntInfo.endTVD - cellIntInfo.startTVD)); - for (const RigCompletionData& compIntersection : completionData) - { - const RigCompletionDataGridCell& cell = compIntersection.completionDataGridCell(); - if (!cell.isMainGridCell()) - { - *foundSubGridIntersections = true; - } - - if (cell.globalCellIndex() != currCellId) continue; - - cvf::Vec3st localIJK(cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK()); - - std::shared_ptr intersection(new RicMswSubSegmentCellIntersection( - cell.lgrName(), cell.globalCellIndex(), localIJK, cellIntInfo.intersectionLengthsInCellCS)); - subSegment->addIntersection(intersection); - } - perforationCompletion->addSubSegment(subSegment); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, - std::shared_ptr location, - int* branchNum, - int* segmentNum) -{ - int icdSegmentNumber = cvf::UNDEFINED_INT; - for (std::shared_ptr completion : location->completions()) - { - if (completion->completionType() == RigCompletionData::PERFORATION) - { - completion->setBranchNumber(1); - } - else if (completion->completionType() != RigCompletionData::FISHBONES_ICD) - { - ++(*branchNum); - completion->setBranchNumber(*branchNum); - } - - int attachedSegmentNumber = location->segmentNumber(); - if (icdSegmentNumber != cvf::UNDEFINED_INT) - { - attachedSegmentNumber = icdSegmentNumber; - } - - for (auto subSegment : completion->subSegments()) - { - if (completion->completionType() == RigCompletionData::FISHBONES_ICD) - { - subSegment->setSegmentNumber(location->segmentNumber() + 1); - icdSegmentNumber = subSegment->segmentNumber(); - } - else if (completion->completionType() != RigCompletionData::PERFORATION) - { - ++(*segmentNum); - subSegment->setSegmentNumber(*segmentNum); - } - subSegment->setAttachedSegmentNumber(attachedSegmentNumber); - attachedSegmentNumber = *segmentNum; - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, - RicMswExportInfo* exportInfo) -{ - int segmentNumber = 1; - int branchNumber = 1; - - // First loop over the locations so that each segment on the main stem is an incremental number - for (auto location : exportInfo->wellSegmentLocations()) - { - location->setSegmentNumber(++segmentNumber); - for (auto completion : location->completions()) - { - if (completion->completionType() == RigCompletionData::FISHBONES_ICD) - { - ++segmentNumber; // Skip a segment number because we need one for the ICD - if (completion->completionType() == RigCompletionData::FISHBONES_ICD) - { - completion->setBranchNumber(++branchNumber); - } - } - } - } - - // Then assign branch and segment numbers to each completion sub segment - for (auto location : exportInfo->wellSegmentLocations()) - { - assignBranchAndSegmentNumbers(caseToApply, location, &branchNumber, &segmentNumber); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -2816,73 +1519,18 @@ std::pair //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportWellSegments(RimEclipseCase* eclipseCase, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& fractures) +bool RicWellPathExportCompletionDataFeatureImpl::isCompletionWellPathEqual(const RigCompletionData& completion, + const RimWellPath* wellPath) { - if (eclipseCase == nullptr) + if (!wellPath) return false; + + RimWellPath* parentWellPath = nullptr; + if (completion.sourcePdmObject()) { - RiaLogging::error("Export Fracture Well Segments: Cannot export completions data without specified eclipse case"); - return; + completion.sourcePdmObject()->firstAncestorOrThisOfType(parentWellPath); } - RicMswExportInfo exportInfo = - RicWellPathExportCompletionDataFeatureImpl::generateFracturesMswExportInfo(eclipseCase, wellPath, fractures); - - QTextStream stream(exportFile.get()); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportWellSegments(RimEclipseCase* eclipseCase, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& fishbonesSubs) -{ - if (eclipseCase == nullptr) - { - RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - RicMswExportInfo exportInfo = - RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo(eclipseCase, wellPath, fishbonesSubs, true); - - QTextStream stream(exportFile.get()); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateWsegvalvTable(formatter, exportInfo); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportWellSegments( - const RicExportCompletionDataSettingsUi& exportSettings, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& perforationIntervals) -{ - if (exportSettings.caseToApply == nullptr) - { - RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - RicMswExportInfo exportInfo = RicWellPathExportCompletionDataFeatureImpl::generatePerforationsMswExportInfo( - exportSettings, wellPath, perforationIntervals); - - QTextStream stream(exportFile.get()); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateWsegvalvTable(formatter, exportInfo); + return (parentWellPath == wellPath); } //-------------------------------------------------------------------------------------------------- @@ -2900,100 +1548,4 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCarfinForTemporaryLgrs(co { RicExportLgrFeature::exportLgrs(folder, lgrInfoForWell.first, lgrInfoForWell.second); } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicWellPathExportCompletionDataFeatureImpl::isCompletionWellPathEqual(const RigCompletionData& completion, - const RimWellPath* wellPath) -{ - if (!wellPath) return false; - - RimWellPath* parentWellPath = nullptr; - if (completion.sourcePdmObject()) - { - completion.sourcePdmObject()->firstAncestorOrThisOfType(parentWellPath); - } - - return (parentWellPath == wellPath); -} - -//-------------------------------------------------------------------------------------------------- -/// Internal function -//-------------------------------------------------------------------------------------------------- -const RimWellPath* findWellPathFromExportName(const QString& wellNameForExport) -{ - auto allWellPaths = RiaApplication::instance()->project()->allWellPaths(); - - for (const auto wellPath : allWellPaths) - { - if (wellPath->completions()->wellNameForExport() == wellNameForExport) return wellPath; - } - return nullptr; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector - spiltIntersectionSegmentsToMaxLength(const RigWellPath* pathGeometry, - const std::vector& intersections, - double maxSegmentLength) -{ - std::vector out; - - if (!pathGeometry) return out; - - for (size_t i = 0; i < intersections.size(); i++) - { - const auto& intersection = intersections[i]; - double segLen = intersection.endMD - intersection.startMD; - int segCount = (int)std::trunc(segLen / maxSegmentLength) + 1; - - // Calc effective max length - double effectiveMaxSegLen = segLen / segCount; - - if (segCount == 1) - { - out.push_back(SubSegmentIntersectionInfo(intersection.globCellIndex, - -intersection.startPoint.z(), - -intersection.endPoint.z(), - intersection.startMD, - intersection.endMD, - intersection.intersectionLengthsInCellCS)); - } - else - { - double currStartMd = intersection.startMD; - double currEndMd = currStartMd; - double lastTvd = -intersection.startPoint.z(); - - for (int segIndex = 0; segIndex < segCount; segIndex++) - { - bool lasti = segIndex == (segCount - 1); - currEndMd = currStartMd + effectiveMaxSegLen; - - cvf::Vec3d segEndPoint = pathGeometry->interpolatedPointAlongWellPath(currEndMd); - out.push_back(SubSegmentIntersectionInfo(intersection.globCellIndex, - lastTvd, - lasti ? -intersection.endPoint.z() : -segEndPoint.z(), - currStartMd, - lasti ? intersection.endMD : currEndMd, - intersection.intersectionLengthsInCellCS / segCount)); - - currStartMd = currEndMd; - lastTvd = -segEndPoint.z(); - } - } - } - return out; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int numberOfSplittedSegments(double startMd, double endMd, double maxSegmentLength) -{ - return (int)(std::trunc((endMd - startMd) / maxSegmentLength) + 1); -} +} \ No newline at end of file diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h index 1e4f5aff08..cd3f190357 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h @@ -21,7 +21,6 @@ #include "RigCompletionData.h" #include "RicExportCompletionDataSettingsUi.h" -#include "RicMswExportInfo.h" #include "RicWellPathFractureReportItem.h" #include @@ -114,25 +113,6 @@ class RicWellPathExportCompletionDataFeatureImpl { public: - static RicMswExportInfo generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - bool enableSegmentSplitting); - - static RicMswExportInfo generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fishbonesSubs, - bool enableSegmentSplitting); - - static RicMswExportInfo generateFracturesMswExportInfo(RimEclipseCase* caseToApply, - const RimWellPath* wellPath); - - static RicMswExportInfo generateFracturesMswExportInfo(RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fractures); - - static RicMswExportInfo generatePerforationsMswExportInfo(const RicExportCompletionDataSettingsUi& exportSettings, - const RimWellPath* wellPath, - const std::vector& perforationIntervals); static CellDirection calculateCellMainDirection(RimEclipseCase* eclipseCase, size_t globalCellIndex, @@ -166,45 +146,11 @@ public: RimEclipseCase* eclipseCase, size_t timeStepIndex); - static void generateWelsegsTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo); - - static void generateWelsegsSegments(RifEclipseDataTableFormatter &formatter, - const RicMswExportInfo &exportInfo, - const std::set& exportCompletionTypes); - static void generateWelsegsCompletionCommentHeader(RifEclipseDataTableFormatter &formatter, - RigCompletionData::CompletionType completionType); - static void generateCompsegTables(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo); - static void generateCompsegTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - bool exportSubGridIntersections, - const std::set& exportCompletionTypes); - static void generateCompsegHeader(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - RigCompletionData::CompletionType completionType, - bool exportSubGridIntersections); - static void generateWsegvalvTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo); + static std::vector generatePerforationsCompdatValues(const RimWellPath* wellPath, + const std::vector& intervals, + const RicExportCompletionDataSettingsUi& settings); private: - typedef std::vector> MainBoreSegments; - typedef std::map , std::set>> ValveContributionMap; - - static MainBoreSegments createMainBoreSegments(const std::vector& subSegIntersections, - const std::vector& perforationIntervals, - const RimWellPath* wellPath, - const RicExportCompletionDataSettingsUi& exportSettings, - bool* foundSubGridIntersections); - - static void assignSuperValveCompletions(std::vector>& mainBoreSegments, - const std::vector& perforationIntervals); - - static void assignValveContributionsToSuperValves(const std::vector>& mainBoreSegments, - const std::vector& perforationIntervals, - RiaEclipseUnitTools::UnitSystem unitSystem); - - static void moveIntersectionsToSuperValves(MainBoreSegments mainBoreSegments); static double calculateTransmissibilityAsEclipseDoes(RimEclipseCase* eclipseCase, double skinFactor, @@ -215,11 +161,6 @@ private: static RigCompletionData combineEclipseCellCompletions(const std::vector& completions, const RicExportCompletionDataSettingsUi& settings); - static QFilePtr openFileForExport(const QString& fullFileName); - - static QFilePtr openFileForExport(const QString& folderName, - const QString& fileName); - static std::vector mainGridCompletions(std::vector& allCompletions); static std::map> subGridsCompletions(std::vector& allCompletions); @@ -256,34 +197,6 @@ private: const QString& gridName, const std::vector& completionData); - static std::vector generatePerforationsCompdatValues(const RimWellPath* wellPath, - const std::vector& intervals, - const RicExportCompletionDataSettingsUi& settings); - - static void assignFishbonesLateralIntersections(const RimEclipseCase* caseToApply, - const RimFishbonesMultipleSubs* fishbonesSubs, - std::shared_ptr location, - bool* foundSubGridIntersections, - double maxSegmentLength); - - static void assignFractureIntersections(const RimEclipseCase* caseToApply, - const RimWellPathFracture* fracture, - const std::vector& completionData, - std::shared_ptr location, - bool* foundSubGridIntersections); - - static void assignPerforationIntervalIntersections(const std::vector& completionData, - std::shared_ptr perforationCompletion, - const SubSegmentIntersectionInfo& cellIntInfo, - bool* foundSubGridIntersections); - - static void assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, - std::shared_ptr location, - int* branchNum, - int* segmentNum); - static void assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, - RicMswExportInfo* exportInfo); - static void appendCompletionData(std::map>* completionData, const std::vector& data); @@ -291,21 +204,6 @@ private: const RimWellPath* wellPath, const QString& gridName = ""); - static void exportWellSegments(RimEclipseCase* eclipseCase, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& fractures); - - static void exportWellSegments(RimEclipseCase* eclipseCase, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& fishbonesSubs); - - static void exportWellSegments(const RicExportCompletionDataSettingsUi& exportSettings, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& perforationIntervals); - static void exportCarfinForTemporaryLgrs(const RimEclipseCase* sourceCase, const QString& folder); static bool isCompletionWellPathEqual(const RigCompletionData& completion, const RimWellPath* wellPath); diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.cpp new file mode 100644 index 0000000000..2942646edc --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.cpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicWellPathExportCompletionsFileTools.h" + +#include "RiaApplication.h" +#include "RiaFilePathTools.h" +#include "RiaLogging.h" + +#include "RimProject.h" +#include "RimWellPath.h" +#include "RimWellPathCompletions.h" + +#include "cafUtils.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellPathExportCompletionsFileTools::OpenFileException::OpenFileException(const QString& message) + : message(message) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::shared_ptr RicWellPathExportCompletionsFileTools::openFileForExport(const QString& fullFileName) +{ + std::pair folderAndFileName = RiaFilePathTools::toFolderAndFileName(fullFileName); + return openFileForExport(folderAndFileName.first, folderAndFileName.second); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::shared_ptr RicWellPathExportCompletionsFileTools::openFileForExport(const QString& folderName, const QString& fileName) +{ + QString validFileName = caf::Utils::makeValidFileBasename(fileName); + + QDir exportFolder = QDir(folderName); + if (!exportFolder.exists()) + { + bool createdPath = exportFolder.mkpath("."); + if (createdPath) + RiaLogging::info("Created export folder " + folderName); + else + { + auto errorMessage = QString("Selected output folder does not exist, and could not be created."); + RiaLogging::error(errorMessage); + throw OpenFileException(errorMessage); + } + } + + QString filePath = exportFolder.filePath(validFileName); + std::shared_ptr exportFile(new QFile(filePath)); + if (!exportFile->open(QIODevice::WriteOnly | QIODevice::Text)) + { + auto errorMessage = QString("Export Completions Data: Could not open the file: %1").arg(filePath); + RiaLogging::error(errorMessage); + throw OpenFileException(errorMessage); + } + return exportFile; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimWellPath* RicWellPathExportCompletionsFileTools::findWellPathFromExportName(const QString& wellNameForExport) +{ + auto allWellPaths = RiaApplication::instance()->project()->allWellPaths(); + + for (const auto wellPath : allWellPaths) + { + if (wellPath->completions()->wellNameForExport() == wellNameForExport) return wellPath; + } + return nullptr; +} + diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.h new file mode 100644 index 0000000000..51495516a0 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.h @@ -0,0 +1,42 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 +#include + +#include + +class RimWellPath; + +class RicWellPathExportCompletionsFileTools +{ +public: + class OpenFileException + { + public: + OpenFileException(const QString& message); + QString message; + }; + + static std::shared_ptr openFileForExport(const QString& folderName, const QString& fileName); + static std::shared_ptr openFileForExport(const QString& fullFileName); + static const RimWellPath* findWellPathFromExportName(const QString& wellNameForExport); + +}; \ No newline at end of file diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp new file mode 100644 index 0000000000..b18baf6cc8 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp @@ -0,0 +1,1507 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicWellPathExportMswCompletionsImpl.h" + +#include "RiaLogging.h" +#include "RiaWeightedMeanCalculator.h" + +#include "RicExportCompletionDataSettingsUi.h" +#include "RicExportFractureCompletionsImpl.h" +#include "RicMswExportInfo.h" +#include "RicWellPathExportCompletionsFileTools.h" + +#include "RifEclipseDataTableFormatter.h" + +#include "RigActiveCellInfo.h" +#include "RigEclipseCaseData.h" +#include "RigGridBase.h" +#include "RigMainGrid.h" +#include "RigWellLogExtractor.h" +#include "RigWellPath.h" +#include "RigWellPathIntersectionTools.h" + +#include "RimEclipseCase.h" +#include "RimFishbonesCollection.h" +#include "RimFishbonesMultipleSubs.h" +#include "RimFractureTemplate.h" +#include "RimPerforationCollection.h" +#include "RimPerforationInterval.h" +#include "RimWellPath.h" +#include "RimWellPathCompletions.h" +#include "RimWellPathFracture.h" +#include "RimWellPathFractureCollection.h" +#include "RimWellPathValve.h" + +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// Internal definitions +//-------------------------------------------------------------------------------------------------- +class SubSegmentIntersectionInfo +{ +public: + SubSegmentIntersectionInfo(size_t globCellIndex, + double startTVD, + double endTVD, + double startMD, + double endMD, + cvf::Vec3d lengthsInCell); + static std::vector + spiltIntersectionSegmentsToMaxLength(const RigWellPath* pathGeometry, + const std::vector& intersections, + double maxSegmentLength); + static int numberOfSplittedSegments(double startMd, double endMd, double maxSegmentLength); + + size_t globCellIndex; + double startTVD; + double endTVD; + double startMD; + double endMD; + cvf::Vec3d intersectionLengthsInCellCS; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions(const RicExportCompletionDataSettingsUi& exportSettings, + const std::vector& wellPaths) +{ + if (exportSettings.includeFractures()) + { + bool anyActiveFractures = false; + + for (const auto& wellPath : wellPaths) + { + if (!wellPath->fractureCollection()->activeFractures().empty()) + { + anyActiveFractures = true; + } + } + + if (anyActiveFractures) + { + QString fileName = QString("%1-Fracture-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); + std::shared_ptr exportFile = + RicWellPathExportCompletionsFileTools::openFileForExport(exportSettings.folder, fileName); + + for (const auto wellPath : wellPaths) + { + auto fractures = wellPath->fractureCollection()->activeFractures(); + if (!fractures.empty()) + { + exportWellSegmentsForFractures(exportSettings.caseToApply, exportFile, wellPath, fractures); + } + } + exportFile->close(); + } + } + + if (exportSettings.includeFishbones()) + { + bool anyFishbones = false; + + for (const auto& wellPath : wellPaths) + { + if (!wellPath->fishbonesCollection()->activeFishbonesSubs().empty()) + { + anyFishbones = true; + } + } + + if (anyFishbones) + { + QString fileName = QString("%1-Fishbone-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); + std::shared_ptr exportFile = + RicWellPathExportCompletionsFileTools::openFileForExport(exportSettings.folder, fileName); + + for (const auto wellPath : wellPaths) + { + auto fishbones = wellPath->fishbonesCollection()->activeFishbonesSubs(); + if (!fishbones.empty()) + { + exportWellSegmentsForFishbones(exportSettings.caseToApply, exportFile, wellPath, fishbones); + } + } + + exportFile->close(); + } + } + + if (exportSettings.includePerforations()) + { + bool anyPerforations = false; + for (const auto& wellPath : wellPaths) + { + if (!wellPath->perforationIntervalCollection()->activePerforations().empty()) + { + anyPerforations = true; + } + } + if (anyPerforations) + { + QString fileName = QString("%1-Perforation-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); + std::shared_ptr exportFile = + RicWellPathExportCompletionsFileTools::openFileForExport(exportSettings.folder, fileName); + + for (const auto wellPath : wellPaths) + { + auto perforations = wellPath->perforationIntervalCollection()->activePerforations(); + exportWellSegmentsForPerforations(exportSettings.caseToApply, exportFile, wellPath, exportSettings.timeStep, perforations); + } + exportFile->close(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFractures(RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + const std::vector& fractures) +{ + if (eclipseCase == nullptr) + { + RiaLogging::error("Export Fracture Well Segments: Cannot export completions data without specified eclipse case"); + return; + } + + RicMswExportInfo exportInfo = generateFracturesMswExportInfo(eclipseCase, wellPath, fractures); + + QTextStream stream(exportFile.get()); + RifEclipseDataTableFormatter formatter(stream); + generateWelsegsTable(formatter, exportInfo); + generateCompsegTables(formatter, exportInfo); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFishbones( + RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + const std::vector& fishbonesSubs) +{ + if (eclipseCase == nullptr) + { + RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); + return; + } + + RicMswExportInfo exportInfo = generateFishbonesMswExportInfo(eclipseCase, wellPath, fishbonesSubs, true); + + QTextStream stream(exportFile.get()); + RifEclipseDataTableFormatter formatter(stream); + + generateWelsegsTable(formatter, exportInfo); + generateCompsegTables(formatter, exportInfo); + generateWsegvalvTable(formatter, exportInfo); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForPerforations( + RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + int timeStep, + const std::vector& perforationIntervals) +{ + if (eclipseCase == nullptr) + { + RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); + return; + } + + RicMswExportInfo exportInfo = generatePerforationsMswExportInfo( + eclipseCase, wellPath, timeStep, perforationIntervals); + + QTextStream stream(exportFile.get()); + RifEclipseDataTableFormatter formatter(stream); + + generateWelsegsTable(formatter, exportInfo); + generateCompsegTables(formatter, exportInfo); + generateWsegvalvTable(formatter, exportInfo); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWelsegsTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo) +{ + formatter.keyword("WELSEGS"); + + double startMD = exportInfo.initialMD(); + double startTVD = exportInfo.initialTVD(); + + { + std::vector header = { + RifEclipseOutputTableColumn("Name"), + RifEclipseOutputTableColumn("Dep 1"), + RifEclipseOutputTableColumn("Tlen 1"), + RifEclipseOutputTableColumn("Vol 1"), + RifEclipseOutputTableColumn("Len&Dep"), + RifEclipseOutputTableColumn("PresDrop"), + }; + formatter.header(header); + + formatter.add(exportInfo.wellPath()->name()); + formatter.add(startTVD); + formatter.add(startMD); + formatter.addValueOrDefaultMarker(exportInfo.topWellBoreVolume(), RicMswExportInfo::defaultDoubleValue()); + formatter.add(exportInfo.lengthAndDepthText()); + formatter.add(exportInfo.pressureDropText()); + + formatter.rowCompleted(); + } + + { + std::vector header = { + RifEclipseOutputTableColumn("First Seg"), + RifEclipseOutputTableColumn("Last Seg"), + RifEclipseOutputTableColumn("Branch Num"), + RifEclipseOutputTableColumn("Outlet Seg"), + RifEclipseOutputTableColumn("Length"), + RifEclipseOutputTableColumn("Depth Change"), + RifEclipseOutputTableColumn("Diam"), + RifEclipseOutputTableColumn("Rough"), + }; + formatter.header(header); + } + + { + double prevMD = exportInfo.initialMD(); + double prevTVD = exportInfo.initialTVD(); + formatter.comment("Main Stem Segments"); + for (std::shared_ptr location : exportInfo.wellSegmentLocations()) + { + double depth = 0; + double length = 0; + + if (exportInfo.lengthAndDepthText() == QString("INC")) + { + depth = location->endTVD() - prevTVD; + length = location->endMD() - prevMD; + } + else + { + depth = location->endTVD(); + length = location->endMD(); + } + + if (location->subIndex() != cvf::UNDEFINED_SIZE_T) + { + QString comment = location->label() + QString(", sub %1").arg(location->subIndex()); + formatter.comment(comment); + } + + formatter.add(location->segmentNumber()).add(location->segmentNumber()); + formatter.add(1); // All segments on main stem are branch 1 + formatter.add(location->segmentNumber() - 1); // All main stem segments are connected to the segment below them + formatter.add(length); + formatter.add(depth); + formatter.add(exportInfo.linerDiameter()); + formatter.add(exportInfo.roughnessFactor()); + formatter.rowCompleted(); + prevMD = location->endMD(); + prevTVD = location->endTVD(); + } + } + + { + generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::FISHBONES_ICD, RigCompletionData::FISHBONES}); + generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::FRACTURE}); + generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::PERFORATION_ICD}); + } + + formatter.tableCompleted(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWelsegsSegments( + RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + const std::set& exportCompletionTypes) +{ + bool generatedHeader = false; + for (std::shared_ptr segment : exportInfo.wellSegmentLocations()) + { + for (std::shared_ptr completion : segment->completions()) + { + if (exportCompletionTypes.count(completion->completionType())) + { + if (!generatedHeader) + { + generateWelsegsCompletionCommentHeader(formatter, completion->completionType()); + generatedHeader = true; + } + + if (completion->completionType() == RigCompletionData::FISHBONES_ICD || + completion->completionType() == RigCompletionData::PERFORATION_ICD) // Found ICD + { + if (!completion->subSegments().empty()) + { + formatter.comment(completion->label()); + + formatter.add(completion->subSegments().front()->segmentNumber()); + formatter.add(completion->subSegments().front()->segmentNumber()); + formatter.add(completion->branchNumber()); + formatter.add(segment->segmentNumber()); + formatter.add(0.1); // ICDs have 0.1 length + formatter.add(0); // Depth change + formatter.add(exportInfo.linerDiameter()); + formatter.add(exportInfo.roughnessFactor()); + formatter.rowCompleted(); + } + } + else + { + if (completion->completionType() == RigCompletionData::FISHBONES) + { + formatter.comment(QString("%1 : Sub index %2 - %3") + .arg(segment->label()) + .arg(segment->subIndex()) + .arg(completion->label())); + } + else if (completion->completionType() == RigCompletionData::FRACTURE) + { + formatter.comment(QString("%1 connected to %2").arg(completion->label()).arg(segment->label())); + } + + for (std::shared_ptr subSegment : completion->subSegments()) + { + double depth = 0; + double length = 0; + + if (exportInfo.lengthAndDepthText() == QString("INC")) + { + depth = subSegment->deltaTVD(); + length = subSegment->deltaMD(); + } + else + { + depth = subSegment->startTVD() + subSegment->deltaTVD(); + length = subSegment->startMD() + subSegment->deltaMD(); + } + double diameter = segment->effectiveDiameter(); + formatter.add(subSegment->segmentNumber()); + formatter.add(subSegment->segmentNumber()); + formatter.add(completion->branchNumber()); + formatter.add(subSegment->attachedSegmentNumber()); + formatter.add(length); + formatter.add(depth); + formatter.add(diameter); + formatter.add(segment->openHoleRoughnessFactor()); + formatter.rowCompleted(); + } + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWelsegsCompletionCommentHeader(RifEclipseDataTableFormatter& formatter, + RigCompletionData::CompletionType completionType) +{ + if (completionType == RigCompletionData::CT_UNDEFINED) + { + formatter.comment("Main stem"); + } + else if (completionType == RigCompletionData::FISHBONES_ICD) + { + formatter.comment("Fishbone Laterals"); + formatter.comment("Diam: MSW - Tubing Radius"); + formatter.comment("Rough: MSW - Open Hole Roughness Factor"); + } + else if (completionType == RigCompletionData::PERFORATION_ICD) + { + formatter.comment("Perforation Valve Segments"); + formatter.comment("Diam: MSW - Tubing Radius"); + formatter.comment("Rough: MSW - Open Hole Roughness Factor"); + } + else if (completionType == RigCompletionData::FRACTURE) + { + formatter.comment("Fracture Segments"); + formatter.comment("Diam: MSW - Default Dummy"); + formatter.comment("Rough: MSW - Default Dummy"); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateCompsegTables(RifEclipseDataTableFormatter& formatter, + const 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 fishbonesTypes = {RigCompletionData::FISHBONES_ICD, + RigCompletionData::FISHBONES}; + generateCompsegTable(formatter, exportInfo, false, fishbonesTypes); + if (exportInfo.hasSubGridIntersections()) + { + generateCompsegTable(formatter, exportInfo, true, fishbonesTypes); + } + } + + { + std::set fractureTypes = {RigCompletionData::FRACTURE}; + generateCompsegTable(formatter, exportInfo, false, fractureTypes); + if (exportInfo.hasSubGridIntersections()) + { + generateCompsegTable(formatter, exportInfo, true, fractureTypes); + } + } + + { + std::set perforationTypes = {RigCompletionData::PERFORATION, + RigCompletionData::PERFORATION_ICD}; + generateCompsegTable(formatter, exportInfo, false, perforationTypes); + if (exportInfo.hasSubGridIntersections()) + { + generateCompsegTable(formatter, exportInfo, true, perforationTypes); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateCompsegTable( + RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + bool exportSubGridIntersections, + const std::set& exportCompletionTypes) +{ + bool generatedHeader = false; + + for (std::shared_ptr location : exportInfo.wellSegmentLocations()) + { + double startMD = location->startMD(); + + for (std::shared_ptr completion : location->completions()) + { + if (!completion->subSegments().empty() && exportCompletionTypes.count(completion->completionType())) + { + if (!generatedHeader) + { + generateCompsegHeader(formatter, exportInfo, completion->completionType(), exportSubGridIntersections); + generatedHeader = true; + } + + for (std::shared_ptr segment : completion->subSegments()) + { + if (completion->completionType() == RigCompletionData::FISHBONES_ICD) + { + startMD = segment->startMD(); + } + + for (std::shared_ptr intersection : segment->intersections()) + { + bool isSubGridIntersection = !intersection->gridName().isEmpty(); + if (isSubGridIntersection == exportSubGridIntersections) + { + if (exportSubGridIntersections) + { + formatter.add(intersection->gridName()); + } + cvf::Vec3st ijk = intersection->gridLocalCellIJK(); + formatter.addOneBasedCellIndex(ijk.x()).addOneBasedCellIndex(ijk.y()).addOneBasedCellIndex(ijk.z()); + formatter.add(completion->branchNumber()); + + double startLength = segment->startMD(); + if (exportInfo.lengthAndDepthText() == QString("INC") && + completion->completionType() != RigCompletionData::PERFORATION) + { + startLength -= startMD; + } + formatter.add(startLength); + formatter.add(startLength + segment->deltaMD()); + + formatter.rowCompleted(); + } + } + } + } + } + } + if (generatedHeader) + { + formatter.tableCompleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateCompsegHeader(RifEclipseDataTableFormatter& formatter, + const 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 = {RifEclipseOutputTableColumn("Name")}; + formatter.header(header); + formatter.add(exportInfo.wellPath()->name()); + formatter.rowCompleted(); + } + + { + std::vector allHeaders; + if (exportSubGridIntersections) + { + allHeaders.push_back(RifEclipseOutputTableColumn("Grid")); + } + + std::vector commonHeaders = {RifEclipseOutputTableColumn("I"), + RifEclipseOutputTableColumn("J"), + RifEclipseOutputTableColumn("K"), + RifEclipseOutputTableColumn("Branch no"), + RifEclipseOutputTableColumn("Start Length"), + RifEclipseOutputTableColumn("End Length"), + RifEclipseOutputTableColumn("Dir Pen"), + RifEclipseOutputTableColumn("End Range"), + RifEclipseOutputTableColumn("Connection Depth")}; + allHeaders.insert(allHeaders.end(), commonHeaders.begin(), commonHeaders.end()); + formatter.header(allHeaders); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWsegvalvTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo) +{ + bool foundValve = false; + + for (std::shared_ptr location : exportInfo.wellSegmentLocations()) + { + for (std::shared_ptr completion : location->completions()) + { + if (completion->completionType() == RigCompletionData::FISHBONES_ICD || + completion->completionType() == RigCompletionData::PERFORATION_ICD) + { + if (!foundValve) + { + formatter.keyword("WSEGVALV"); + std::vector header = { + RifEclipseOutputTableColumn("Well Name"), + RifEclipseOutputTableColumn("Seg No"), + RifEclipseOutputTableColumn("Cv"), + RifEclipseOutputTableColumn("Ac"), + }; + formatter.header(header); + + foundValve = true; + } + if (completion->completionType() == RigCompletionData::FISHBONES_ICD || + completion->completionType() == RigCompletionData::PERFORATION_ICD) + { + std::shared_ptr icd = std::static_pointer_cast(completion); + if (!icd->subSegments().empty()) + { + CVF_ASSERT(icd->subSegments().size() == 1u); + if (icd->completionType() == RigCompletionData::PERFORATION_ICD) + { + formatter.comment(icd->label()); + } + formatter.add(exportInfo.wellPath()->name()); + formatter.add(icd->subSegments().front()->segmentNumber()); + formatter.add(icd->flowCoefficient()); + formatter.add(QString("%1").arg(icd->area(), 8, 'g', 4)); + formatter.rowCompleted(); + } + } + } + } + } + if (foundValve) + { + formatter.tableCompleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + bool enableSegmentSplitting) +{ + std::vector fishbonesSubs = wellPath->fishbonesCollection()->activeFishbonesSubs(); + + return generateFishbonesMswExportInfo(caseToApply, wellPath, fishbonesSubs, enableSegmentSplitting); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( + const RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + const std::vector& fishbonesSubs, + bool enableSegmentSplitting) +{ + RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); + + RicMswExportInfo exportInfo(wellPath, + unitSystem, + wellPath->fishbonesCollection()->startMD(), + wellPath->fishbonesCollection()->mswParameters()->lengthAndDepth().text(), + wellPath->fishbonesCollection()->mswParameters()->pressureDrop().text()); + exportInfo.setLinerDiameter(wellPath->fishbonesCollection()->mswParameters()->linerDiameter(unitSystem)); + exportInfo.setRoughnessFactor(wellPath->fishbonesCollection()->mswParameters()->roughnessFactor(unitSystem)); + + double maxSegmentLength = enableSegmentSplitting ? wellPath->fishbonesCollection()->mswParameters()->maxSegmentLength() + : std::numeric_limits::infinity(); + bool foundSubGridIntersections = false; + double subStartMD = wellPath->fishbonesCollection()->startMD(); + for (RimFishbonesMultipleSubs* subs : fishbonesSubs) + { + for (auto& sub : subs->installedLateralIndices()) + { + double subEndMD = subs->measuredDepth(sub.subIndex); + double subEndTVD = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(subEndMD).z(); + int subSegCount = SubSegmentIntersectionInfo::numberOfSplittedSegments(subStartMD, subEndMD, maxSegmentLength); + double subSegLen = (subEndMD - subStartMD) / subSegCount; + + double startMd = subStartMD; + double startTvd = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(startMd).z(); + for (int ssi = 0; ssi < subSegCount; ssi++) + { + double endMd = startMd + subSegLen; + double endTvd = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(endMd).z(); + + std::shared_ptr location( + new RicMswSegment(subs->generatedName(), startMd, endMd, startTvd, endTvd, sub.subIndex)); + location->setEffectiveDiameter(subs->effectiveDiameter(unitSystem)); + location->setHoleDiameter(subs->holeDiameter(unitSystem)); + location->setOpenHoleRoughnessFactor(subs->openHoleRoughnessFactor(unitSystem)); + location->setSkinFactor(subs->skinFactor()); + location->setSourcePdmObject(subs); + + if (ssi == 0) + { + // Add completion for ICD + std::shared_ptr icdCompletion(new RicMswFishbonesICD(QString("ICD"))); + std::shared_ptr icdSegment(new RicMswSubSegment(subEndMD, 0.1, subEndTVD, 0.0)); + icdCompletion->setFlowCoefficient(subs->icdFlowCoefficient()); + double icdOrificeRadius = subs->icdOrificeDiameter(unitSystem) / 2; + icdCompletion->setArea(icdOrificeRadius * icdOrificeRadius * cvf::PI_D * subs->icdCount()); + + icdCompletion->addSubSegment(icdSegment); + location->addCompletion(icdCompletion); + + for (size_t lateralIndex : sub.lateralIndices) + { + QString label = QString("Lateral %1").arg(lateralIndex); + location->addCompletion(std::make_shared(label, lateralIndex)); + } + assignFishbonesLateralIntersections( + caseToApply, subs, location, &foundSubGridIntersections, maxSegmentLength); + } + + exportInfo.addWellSegment(location); + + startMd = endMd; + startTvd = endTvd; + } + + subStartMD = subEndMD; + } + } + exportInfo.setHasSubGridIntersections(foundSubGridIntersections); + exportInfo.sortLocations(); + + assignBranchAndSegmentNumbers(caseToApply, &exportInfo); + + return exportInfo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo RicWellPathExportMswCompletionsImpl::generateFracturesMswExportInfo(RimEclipseCase* caseToApply, + const RimWellPath* wellPath) +{ + std::vector fractures = wellPath->fractureCollection()->activeFractures(); + + return generateFracturesMswExportInfo(caseToApply, wellPath, fractures); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo + RicWellPathExportMswCompletionsImpl::generateFracturesMswExportInfo(RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + const std::vector& fractures) +{ + const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); + const RigActiveCellInfo* activeCellInfo = caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); + + const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry(); + const std::vector& coords = wellPathGeometry->wellPathPoints(); + const std::vector& mds = wellPathGeometry->measureDepths(); + CVF_ASSERT(!coords.empty() && !mds.empty()); + + std::vector intersections = + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(caseToApply->eclipseCaseData(), coords, mds); + + double maxSegmentLength = wellPath->fractureCollection()->mswParameters()->maxSegmentLength(); + std::vector subSegIntersections = + SubSegmentIntersectionInfo::spiltIntersectionSegmentsToMaxLength(wellPathGeometry, intersections, maxSegmentLength); + + double initialMD = 0.0; + if (wellPath->fractureCollection()->referenceMDType() == RimWellPathFractureCollection::MANUAL_REFERENCE_MD) + { + initialMD = wellPath->fractureCollection()->manualReferenceMD(); + } + else + { + for (WellPathCellIntersectionInfo intersection : intersections) + { + if (activeCellInfo->isActive(intersection.globCellIndex)) + { + initialMD = intersection.startMD; + break; + } + } + } + + RicMswExportInfo exportInfo(wellPath, + unitSystem, + initialMD, + wellPath->fractureCollection()->mswParameters()->lengthAndDepth().text(), + wellPath->fractureCollection()->mswParameters()->pressureDrop().text()); + + exportInfo.setLinerDiameter(wellPath->fractureCollection()->mswParameters()->linerDiameter(unitSystem)); + exportInfo.setRoughnessFactor(wellPath->fractureCollection()->mswParameters()->roughnessFactor(unitSystem)); + + bool foundSubGridIntersections = false; + + // Main bore + int mainBoreSegment = 1; + for (const auto& cellIntInfo : subSegIntersections) + { + double startTVD = cellIntInfo.startTVD; + double endTVD = cellIntInfo.endTVD; + + size_t localGridIdx = 0u; + const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); + QString gridName; + if (localGrid != grid) + { + gridName = QString::fromStdString(localGrid->gridName()); + foundSubGridIntersections = true; + } + + size_t i = 0u, j = 0u, k = 0u; + localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); + QString label = QString("Main stem segment %1").arg(++mainBoreSegment); + std::shared_ptr location( + new RicMswSegment(label, cellIntInfo.startMD, cellIntInfo.endMD, startTVD, endTVD)); + + // Check if fractures are to be assigned to current main bore segment + for (RimWellPathFracture* fracture : fractures) + { + double fractureStartMD = fracture->fractureMD(); + if (fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH) + { + double perforationLength = fracture->fractureTemplate()->perforationLength(); + fractureStartMD -= 0.5 * perforationLength; + } + + if (cvf::Math::valueInRange(fractureStartMD, cellIntInfo.startMD, cellIntInfo.endMD)) + { + std::vector completionData = + RicExportFractureCompletionsImpl::generateCompdatValues(caseToApply, + wellPath->completions()->wellNameForExport(), + wellPath->wellPathGeometry(), + {fracture}, + nullptr, + nullptr); + + assignFractureIntersections(caseToApply, fracture, completionData, location, &foundSubGridIntersections); + } + } + + exportInfo.addWellSegment(location); + } + exportInfo.setHasSubGridIntersections(foundSubGridIntersections); + exportInfo.sortLocations(); + assignBranchAndSegmentNumbers(caseToApply, &exportInfo); + + return exportInfo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo RicWellPathExportMswCompletionsImpl::generatePerforationsMswExportInfo( + RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + int timeStep, + const std::vector& perforationIntervals) +{ + const RigActiveCellInfo* activeCellInfo = eclipseCase->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + RiaEclipseUnitTools::UnitSystem unitSystem = eclipseCase->eclipseCaseData()->unitsType(); + + const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry(); + const std::vector& coords = wellPathGeometry->wellPathPoints(); + const std::vector& mds = wellPathGeometry->measureDepths(); + CVF_ASSERT(!coords.empty() && !mds.empty()); + + std::vector intersections = + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(eclipseCase->eclipseCaseData(), coords, mds); + + double maxSegmentLength = wellPath->perforationIntervalCollection()->mswParameters()->maxSegmentLength(); + std::vector subSegIntersections = + SubSegmentIntersectionInfo::spiltIntersectionSegmentsToMaxLength(wellPathGeometry, intersections, maxSegmentLength); + + double initialMD = 0.0; + for (WellPathCellIntersectionInfo intersection : intersections) + { + if (activeCellInfo->isActive(intersection.globCellIndex)) + { + initialMD = intersection.startMD; + break; + } + } + + RicMswExportInfo exportInfo(wellPath, + unitSystem, + initialMD, + wellPath->perforationIntervalCollection()->mswParameters()->lengthAndDepth().text(), + wellPath->perforationIntervalCollection()->mswParameters()->pressureDrop().text()); + + exportInfo.setLinerDiameter(wellPath->perforationIntervalCollection()->mswParameters()->linerDiameter(unitSystem)); + exportInfo.setRoughnessFactor(wellPath->perforationIntervalCollection()->mswParameters()->roughnessFactor(unitSystem)); + + bool foundSubGridIntersections = false; + + MainBoreSegments mainBoreSegments = createMainBoreSegmentsForPerforations( + subSegIntersections, perforationIntervals, wellPath, timeStep, eclipseCase, &foundSubGridIntersections); + + assignSuperValveCompletions(mainBoreSegments, perforationIntervals); + assignValveContributionsToSuperValves(mainBoreSegments, perforationIntervals, unitSystem); + moveIntersectionsToSuperValves(mainBoreSegments); + + for (std::shared_ptr segment : mainBoreSegments) + { + exportInfo.addWellSegment(segment); + } + + exportInfo.setHasSubGridIntersections(foundSubGridIntersections); + exportInfo.sortLocations(); + assignBranchAndSegmentNumbers(eclipseCase, &exportInfo); + + return exportInfo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellPathExportMswCompletionsImpl::MainBoreSegments RicWellPathExportMswCompletionsImpl::createMainBoreSegmentsForPerforations( + const std::vector& subSegIntersections, + const std::vector& perforationIntervals, + const RimWellPath* wellPath, + int timeStep, + RimEclipseCase* eclipseCase, + bool* foundSubGridIntersections) +{ + MainBoreSegments mainBoreSegments; + + for (const auto& cellIntInfo : subSegIntersections) + { + if (std::fabs(cellIntInfo.endMD - cellIntInfo.startMD) > 1.0e-8) + { + QString label = QString("Main stem segment %1").arg(mainBoreSegments.size() + 2); + std::shared_ptr segment( + new RicMswSegment(label, cellIntInfo.startMD, cellIntInfo.endMD, cellIntInfo.startTVD, cellIntInfo.endTVD)); + + for (const RimPerforationInterval* interval : perforationIntervals) + { + double overlapStart = std::max(interval->startMD(), segment->startMD()); + double overlapEnd = std::min(interval->endMD(), segment->endMD()); + double overlap = std::max(0.0, overlapEnd - overlapStart); + if (overlap > 0.0) + { + std::shared_ptr intervalCompletion(new RicMswPerforation(interval->name())); + std::vector completionData = + generatePerforationIntersections(wellPath, interval, timeStep, eclipseCase); + assignPerforationIntersections(completionData, intervalCompletion, cellIntInfo, foundSubGridIntersections); + segment->addCompletion(intervalCompletion); + } + } + mainBoreSegments.push_back(segment); + } + } + return mainBoreSegments; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignSuperValveCompletions( + std::vector>& mainBoreSegments, + const std::vector& perforationIntervals) +{ + for (size_t nMainSegment = 0u; nMainSegment < mainBoreSegments.size(); ++nMainSegment) + { + std::shared_ptr segment = mainBoreSegments[nMainSegment]; + + std::shared_ptr superValve; + for (const RimPerforationInterval* interval : perforationIntervals) + { + std::vector perforationValves; + interval->descendantsIncludingThisOfType(perforationValves); + + for (const RimWellPathValve* valve : perforationValves) + { + for (size_t nSubValve = 0u; nSubValve < valve->valveLocations().size(); ++nSubValve) + { + double valveMD = valve->valveLocations()[nSubValve]; + + std::pair valveSegment = valve->valveSegments()[nSubValve]; + double overlapStart = std::max(valveSegment.first, segment->startMD()); + double overlapEnd = std::min(valveSegment.second, segment->endMD()); + double overlap = std::max(0.0, overlapEnd - overlapStart); + + if (segment->startMD() <= valveMD && valveMD < segment->endMD()) + { + QString valveLabel = QString("%1 #%2").arg("Combined Valve for segment").arg(nMainSegment + 2); + superValve.reset(new RicMswPerforationICD(valveLabel)); + std::shared_ptr subSegment(new RicMswSubSegment(valveMD, 0.1, 0.0, 0.0)); + superValve->addSubSegment(subSegment); + } + else if (overlap > 0.0 && !superValve) + { + QString valveLabel = QString("%1 #%2").arg("Combined Valve for segment").arg(nMainSegment + 2); + superValve.reset(new RicMswPerforationICD(valveLabel)); + std::shared_ptr subSegment(new RicMswSubSegment(overlapStart, 0.1, 0.0, 0.0)); + superValve->addSubSegment(subSegment); + } + } + } + } + + if (superValve) + { + segment->addCompletion(superValve); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignValveContributionsToSuperValves( + const std::vector>& mainBoreSegments, + const std::vector& perforationIntervals, + RiaEclipseUnitTools::UnitSystem unitSystem) +{ + ValveContributionMap assignedRegularValves; + for (std::shared_ptr segment : mainBoreSegments) + { + std::shared_ptr superValve; + for (auto completion : segment->completions()) + { + std::shared_ptr valve = std::dynamic_pointer_cast(completion); + if (valve) + { + superValve = valve; + break; + } + } + + if (!superValve) continue; + + double totalIcdArea = 0.0; + RiaWeightedMeanCalculator coeffMeanCalc; + + for (const RimPerforationInterval* interval : perforationIntervals) + { + std::vector perforationValves; + interval->descendantsIncludingThisOfType(perforationValves); + + for (const RimWellPathValve* valve : perforationValves) + { + for (size_t nSubValve = 0u; nSubValve < valve->valveSegments().size(); ++nSubValve) + { + std::pair valveSegment = valve->valveSegments()[nSubValve]; + double valveSegmentLength = valveSegment.second - valveSegment.first; + double overlapStart = std::max(valveSegment.first, segment->startMD()); + double overlapEnd = std::min(valveSegment.second, segment->endMD()); + double overlap = std::max(0.0, overlapEnd - overlapStart); + + if (overlap > 0.0) + { + assignedRegularValves[superValve].insert(std::make_pair(valve, nSubValve)); + double icdOrificeRadius = valve->orificeDiameter(unitSystem) / 2; + double icdArea = icdOrificeRadius * icdOrificeRadius * cvf::PI_D * overlap / valveSegmentLength; + totalIcdArea += icdArea; + coeffMeanCalc.addValueAndWeight(valve->flowCoefficient(), icdArea); + } + } + } + } + superValve->setArea(totalIcdArea); + if (coeffMeanCalc.validAggregatedWeight()) + { + superValve->setFlowCoefficient(coeffMeanCalc.weightedMean()); + } + } + + for (auto regularValvePair : assignedRegularValves) + { + if (regularValvePair.second.size()) + { + QStringList valveLabels; + for (std::pair regularValve : regularValvePair.second) + { + QString valveLabel = QString("%1 #%2").arg(regularValve.first->name()).arg(regularValve.second + 1); + valveLabels.push_back(valveLabel); + } + QString valveContribLabel = QString(" with contribution from: %1").arg(valveLabels.join(", ")); + regularValvePair.first->setLabel(regularValvePair.first->label() + valveContribLabel); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::moveIntersectionsToSuperValves(MainBoreSegments mainBoreSegments) +{ + for (auto segmentPtr : mainBoreSegments) + { + std::shared_ptr superValve; + std::vector> perforations; + for (auto completionPtr : segmentPtr->completions()) + { + if (completionPtr->completionType() == RigCompletionData::PERFORATION_ICD) + { + superValve = completionPtr; + } + else + { + CVF_ASSERT(completionPtr->completionType() == RigCompletionData::PERFORATION); + perforations.push_back(completionPtr); + } + } + + if (superValve == nullptr) continue; + + CVF_ASSERT(superValve->subSegments().size() == 1u); + segmentPtr->completions().clear(); + segmentPtr->addCompletion(superValve); + for (auto perforationPtr : perforations) + { + for (auto subSegmentPtr : perforationPtr->subSegments()) + { + for (auto intersectionPtr : subSegmentPtr->intersections()) + { + superValve->subSegments()[0]->addIntersection(intersectionPtr); + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignFishbonesLateralIntersections(const RimEclipseCase* caseToApply, + const RimFishbonesMultipleSubs* fishbonesSubs, + std::shared_ptr location, + bool* foundSubGridIntersections, + double maxSegmentLength) +{ + CVF_ASSERT(foundSubGridIntersections != nullptr); + + const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); + + for (std::shared_ptr completion : location->completions()) + { + if (completion->completionType() != RigCompletionData::FISHBONES) + { + continue; + } + + std::vector> lateralCoordMDPairs = + fishbonesSubs->coordsAndMDForLateral(location->subIndex(), completion->index()); + + if (lateralCoordMDPairs.empty()) + { + continue; + } + + std::vector lateralCoords; + std::vector lateralMDs; + + lateralCoords.reserve(lateralCoordMDPairs.size()); + lateralMDs.reserve(lateralCoordMDPairs.size()); + + for (auto& coordMD : lateralCoordMDPairs) + { + lateralCoords.push_back(coordMD.first); + lateralMDs.push_back(coordMD.second); + } + + std::vector intersections = + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( + caseToApply->eclipseCaseData(), lateralCoords, lateralMDs); + + RigWellPath pathGeometry; + pathGeometry.m_wellPathPoints = lateralCoords; + pathGeometry.m_measuredDepths = lateralMDs; + std::vector subSegIntersections = + SubSegmentIntersectionInfo::spiltIntersectionSegmentsToMaxLength(&pathGeometry, intersections, maxSegmentLength); + + double previousExitMD = lateralMDs.front(); + double previousExitTVD = -lateralCoords.front().z(); + + for (const auto& cellIntInfo : subSegIntersections) + { + size_t localGridIdx = 0u; + const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); + QString gridName; + if (localGrid != grid) + { + gridName = QString::fromStdString(localGrid->gridName()); + *foundSubGridIntersections = true; + } + + size_t i = 0u, j = 0u, k = 0u; + localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); + std::shared_ptr subSegment(new RicMswSubSegment( + previousExitMD, cellIntInfo.endMD - previousExitMD, previousExitTVD, cellIntInfo.endTVD - previousExitTVD)); + + std::shared_ptr intersection(new RicMswSubSegmentCellIntersection( + gridName, cellIntInfo.globCellIndex, cvf::Vec3st(i, j, k), cellIntInfo.intersectionLengthsInCellCS)); + subSegment->addIntersection(intersection); + completion->addSubSegment(subSegment); + + previousExitMD = cellIntInfo.endMD; + previousExitTVD = cellIntInfo.endTVD; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignFractureIntersections(const RimEclipseCase* caseToApply, + const RimWellPathFracture* fracture, + const std::vector& completionData, + std::shared_ptr location, + bool* foundSubGridIntersections) +{ + CVF_ASSERT(foundSubGridIntersections != nullptr); + + std::shared_ptr fractureCompletion(new RicMswFracture(fracture->name())); + double position = fracture->fractureMD(); + double width = fracture->fractureTemplate()->computeFractureWidth(fracture); + + if (fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH) + { + double perforationLength = fracture->fractureTemplate()->perforationLength(); + position -= 0.5 * perforationLength; + width = perforationLength; + } + + std::shared_ptr subSegment(new RicMswSubSegment(position, width, 0.0, 0.0)); + for (const RigCompletionData& compIntersection : completionData) + { + const RigCompletionDataGridCell& cell = compIntersection.completionDataGridCell(); + cvf::Vec3st localIJK(cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK()); + + std::shared_ptr intersection( + new RicMswSubSegmentCellIntersection(cell.lgrName(), cell.globalCellIndex(), localIJK, cvf::Vec3d::ZERO)); + subSegment->addIntersection(intersection); + } + fractureCompletion->addSubSegment(subSegment); + location->addCompletion(fractureCompletion); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector + RicWellPathExportMswCompletionsImpl::generatePerforationIntersections(const RimWellPath* wellPath, + const RimPerforationInterval* perforationInterval, + int timeStep, + RimEclipseCase* eclipseCase) +{ + std::vector completionData; + const RigActiveCellInfo* activeCellInfo = eclipseCase->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + + if (wellPath->perforationIntervalCollection()->isChecked() && perforationInterval->isChecked() && + perforationInterval->isActiveOnDate(eclipseCase->timeStepDates()[timeStep])) + { + std::pair, std::vector> perforationPointsAndMD = + wellPath->wellPathGeometry()->clippedPointSubset(perforationInterval->startMD(), perforationInterval->endMD()); + + std::vector intersectedCells = + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( + eclipseCase->eclipseCaseData(), perforationPointsAndMD.first, perforationPointsAndMD.second); + + for (auto& cell : intersectedCells) + { + bool cellIsActive = activeCellInfo->isActive(cell.globCellIndex); + if (!cellIsActive) continue; + + RigCompletionData completion(wellPath->completions()->wellNameForExport(), + RigCompletionDataGridCell(cell.globCellIndex, eclipseCase->mainGrid()), + cell.startMD); + + completion.setSourcePdmObject(perforationInterval); + completionData.push_back(completion); + } + } + + return completionData; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignPerforationIntersections(const std::vector& completionData, + std::shared_ptr perforationCompletion, + const SubSegmentIntersectionInfo& cellIntInfo, + bool* foundSubGridIntersections) +{ + size_t currCellId = cellIntInfo.globCellIndex; + + std::shared_ptr subSegment(new RicMswSubSegment(cellIntInfo.startMD, + cellIntInfo.endMD - cellIntInfo.startMD, + cellIntInfo.startTVD, + cellIntInfo.endTVD - cellIntInfo.startTVD)); + for (const RigCompletionData& compIntersection : completionData) + { + const RigCompletionDataGridCell& cell = compIntersection.completionDataGridCell(); + if (!cell.isMainGridCell()) + { + *foundSubGridIntersections = true; + } + + if (cell.globalCellIndex() != currCellId) continue; + + cvf::Vec3st localIJK(cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK()); + + std::shared_ptr intersection(new RicMswSubSegmentCellIntersection( + cell.lgrName(), cell.globalCellIndex(), localIJK, cellIntInfo.intersectionLengthsInCellCS)); + subSegment->addIntersection(intersection); + } + perforationCompletion->addSubSegment(subSegment); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, + std::shared_ptr location, + int* branchNum, + int* segmentNum) +{ + int icdSegmentNumber = cvf::UNDEFINED_INT; + for (std::shared_ptr completion : location->completions()) + { + if (completion->completionType() == RigCompletionData::PERFORATION) + { + completion->setBranchNumber(1); + } + else if (completion->completionType() != RigCompletionData::FISHBONES_ICD) + { + ++(*branchNum); + completion->setBranchNumber(*branchNum); + } + + int attachedSegmentNumber = location->segmentNumber(); + if (icdSegmentNumber != cvf::UNDEFINED_INT) + { + attachedSegmentNumber = icdSegmentNumber; + } + + for (auto subSegment : completion->subSegments()) + { + if (completion->completionType() == RigCompletionData::FISHBONES_ICD) + { + subSegment->setSegmentNumber(location->segmentNumber() + 1); + icdSegmentNumber = subSegment->segmentNumber(); + } + else if (completion->completionType() != RigCompletionData::PERFORATION) + { + ++(*segmentNum); + subSegment->setSegmentNumber(*segmentNum); + } + subSegment->setAttachedSegmentNumber(attachedSegmentNumber); + attachedSegmentNumber = *segmentNum; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, + RicMswExportInfo* exportInfo) +{ + int segmentNumber = 1; + int branchNumber = 1; + + // First loop over the locations so that each segment on the main stem is an incremental number + for (auto location : exportInfo->wellSegmentLocations()) + { + location->setSegmentNumber(++segmentNumber); + for (auto completion : location->completions()) + { + if (completion->completionType() == RigCompletionData::FISHBONES_ICD) + { + ++segmentNumber; // Skip a segment number because we need one for the ICD + if (completion->completionType() == RigCompletionData::FISHBONES_ICD) + { + completion->setBranchNumber(++branchNumber); + } + } + } + } + + // Then assign branch and segment numbers to each completion sub segment + for (auto location : exportInfo->wellSegmentLocations()) + { + assignBranchAndSegmentNumbers(caseToApply, location, &branchNumber, &segmentNumber); + } +} + +SubSegmentIntersectionInfo::SubSegmentIntersectionInfo(size_t globCellIndex, + double startTVD, + double endTVD, + double startMD, + double endMD, + cvf::Vec3d lengthsInCell) + : globCellIndex(globCellIndex) + , startTVD(startTVD) + , endTVD(endTVD) + , startMD(startMD) + , endMD(endMD) + , intersectionLengthsInCellCS(lengthsInCell) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector SubSegmentIntersectionInfo::spiltIntersectionSegmentsToMaxLength( + const RigWellPath* pathGeometry, + const std::vector& intersections, + double maxSegmentLength) +{ + std::vector out; + + if (!pathGeometry) return out; + + for (size_t i = 0; i < intersections.size(); i++) + { + const auto& intersection = intersections[i]; + double segLen = intersection.endMD - intersection.startMD; + int segCount = (int)std::trunc(segLen / maxSegmentLength) + 1; + + // Calc effective max length + double effectiveMaxSegLen = segLen / segCount; + + if (segCount == 1) + { + out.push_back(SubSegmentIntersectionInfo(intersection.globCellIndex, + -intersection.startPoint.z(), + -intersection.endPoint.z(), + intersection.startMD, + intersection.endMD, + intersection.intersectionLengthsInCellCS)); + } + else + { + double currStartMd = intersection.startMD; + double currEndMd = currStartMd; + double lastTvd = -intersection.startPoint.z(); + + for (int segIndex = 0; segIndex < segCount; segIndex++) + { + bool lasti = segIndex == (segCount - 1); + currEndMd = currStartMd + effectiveMaxSegLen; + + cvf::Vec3d segEndPoint = pathGeometry->interpolatedPointAlongWellPath(currEndMd); + out.push_back(SubSegmentIntersectionInfo(intersection.globCellIndex, + lastTvd, + lasti ? -intersection.endPoint.z() : -segEndPoint.z(), + currStartMd, + lasti ? intersection.endMD : currEndMd, + intersection.intersectionLengthsInCellCS / segCount)); + + currStartMd = currEndMd; + lastTvd = -segEndPoint.z(); + } + } + } + return out; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int SubSegmentIntersectionInfo::numberOfSplittedSegments(double startMd, double endMd, double maxSegmentLength) +{ + return (int)(std::trunc((endMd - startMd) / maxSegmentLength) + 1); +} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h new file mode 100644 index 0000000000..f39e425335 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicMswExportInfo.h" +#include "RigCompletionData.h" + +class RicExportCompletionDataSettingsUi; +class RifEclipseDataTableFormatter; +class RimEclipseCase; +class RimFishbonesMultipleSubs; +class RimPerforationInterval; +class RimWellPath; +class RimWellPathValve; +class RimWellPathFracture; +class SubSegmentIntersectionInfo; + +class QFile; + +class RicWellPathExportMswCompletionsImpl +{ +public: + static void exportWellSegmentsForAllCompletions(const RicExportCompletionDataSettingsUi& exportSettings, + const std::vector& wellPaths); + + static void exportWellSegmentsForFractures(RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + const std::vector& fractures); + + static void exportWellSegmentsForFishbones(RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + const std::vector& fishbonesSubs); + + static void exportWellSegmentsForPerforations(RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + int timeStep, + const std::vector& perforationIntervals); + + static RicMswExportInfo generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + bool enableSegmentSplitting); + +private: + static RicMswExportInfo generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + const std::vector& fishbonesSubs, + bool enableSegmentSplitting); + + static RicMswExportInfo generateFracturesMswExportInfo(RimEclipseCase* caseToApply, + const RimWellPath* wellPath); + + static RicMswExportInfo generateFracturesMswExportInfo(RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + const std::vector& fractures); + + static RicMswExportInfo generatePerforationsMswExportInfo(RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + int timeStep, + const std::vector& perforationIntervals); + + static void generateWelsegsTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo); + + static void generateWelsegsSegments(RifEclipseDataTableFormatter &formatter, + const RicMswExportInfo &exportInfo, + const std::set& exportCompletionTypes); + static void generateWelsegsCompletionCommentHeader(RifEclipseDataTableFormatter &formatter, + RigCompletionData::CompletionType completionType); + static void generateCompsegTables(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo); + static void generateCompsegTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + bool exportSubGridIntersections, + const std::set& exportCompletionTypes); + static void generateCompsegHeader(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + RigCompletionData::CompletionType completionType, + bool exportSubGridIntersections); + static void generateWsegvalvTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo); +private: + typedef std::vector> MainBoreSegments; + typedef std::map, std::set>> + ValveContributionMap; + + static MainBoreSegments createMainBoreSegmentsForPerforations(const std::vector& subSegIntersections, + const std::vector& perforationIntervals, + const RimWellPath* wellPath, + int timeStep, + RimEclipseCase* eclipseCase, + bool* foundSubGridIntersections); + + static void assignSuperValveCompletions(std::vector>& mainBoreSegments, + const std::vector& perforationIntervals); + + static void assignValveContributionsToSuperValves(const std::vector>& mainBoreSegments, + const std::vector& perforationIntervals, + RiaEclipseUnitTools::UnitSystem unitSystem); + + static void moveIntersectionsToSuperValves(MainBoreSegments mainBoreSegments); + + static void assignFishbonesLateralIntersections(const RimEclipseCase* caseToApply, + const RimFishbonesMultipleSubs* fishbonesSubs, + std::shared_ptr location, + bool* foundSubGridIntersections, + double maxSegmentLength); + + static void assignFractureIntersections(const RimEclipseCase* caseToApply, + const RimWellPathFracture* fracture, + const std::vector& completionData, + std::shared_ptr location, + bool* foundSubGridIntersections); + + static std::vector generatePerforationIntersections(const RimWellPath* wellPath, + const RimPerforationInterval* perforationInterval, + int timeStep, + RimEclipseCase* eclipseCase); + + static void assignPerforationIntersections(const std::vector& completionData, + std::shared_ptr perforationCompletion, + const SubSegmentIntersectionInfo& cellIntInfo, + bool* foundSubGridIntersections); + + static void assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, + std::shared_ptr location, + int* branchNum, + int* segmentNum); + static void assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, RicMswExportInfo* exportInfo); + +}; \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.cpp b/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.cpp index 303e9f49f3..61a4a42a1f 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.cpp @@ -185,3 +185,21 @@ std::vector RimPerforationCollection::perforation return myPerforations; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimPerforationCollection::activePerforations() const +{ + std::vector myActivePerforations; + + for (const auto& perforation : m_perforations) + { + if (perforation->isChecked()) + { + myActivePerforations.push_back(perforation); + } + } + + return myActivePerforations; +} + diff --git a/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.h b/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.h index 4accf24bac..09c5e853bc 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.h @@ -48,6 +48,7 @@ public: void setUnitSystemSpecificDefaults(); void appendPerforation(RimPerforationInterval* perforation); std::vector perforations() const; + std::vector activePerforations() const; private: void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp index e73f8abc57..ad656f1b51 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -747,8 +747,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicEditPerforationCollectionFeature"; menuBuilder << "RicExportFishbonesLateralsFeature"; - menuBuilder << "RicExportFishbonesWellSegmentsFeature"; - menuBuilder << "RicExportFracturesWellSegmentsFeature"; + menuBuilder << "RicExportCompletionsWellSegmentsFeature"; { QStringList candidates;