diff --git a/ApplicationCode/CommandFileInterface/RicfExportSimWellCompletions.cpp b/ApplicationCode/CommandFileInterface/RicfExportSimWellCompletions.cpp index 9e70b90452..15f917e0e2 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportSimWellCompletions.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportSimWellCompletions.cpp @@ -35,7 +35,7 @@ #include "RimWellPath.h" #include "RimWellPathCollection.h" -#include "CompletionExportCommands/RicWellPathExportCompletionDataFeature.h" +#include "CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h" CAF_PDM_SOURCE_INIT(RicfExportSimWellCompletions, "exportSimWellCompletions"); diff --git a/ApplicationCode/CommandFileInterface/RicfExportWellPathCompletions.cpp b/ApplicationCode/CommandFileInterface/RicfExportWellPathCompletions.cpp index acbc9f493e..3e89a57d98 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportWellPathCompletions.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportWellPathCompletions.cpp @@ -31,7 +31,7 @@ #include "RimWellPathCollection.h" #include "RimWellPath.h" -#include "CompletionExportCommands/RicWellPathExportCompletionDataFeature.h" +#include "CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h" CAF_PDM_SOURCE_INIT(RicfExportWellPathCompletions, "exportWellPathCompletions"); diff --git a/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake index 0290009c87..647b7d6ba0 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake @@ -7,6 +7,7 @@ endif() set (SOURCE_GROUP_HEADER_FILES ${CEE_CURRENT_LIST_DIR}RicExportCompletionDataSettingsUi.h ${CEE_CURRENT_LIST_DIR}RicWellPathExportCompletionDataFeature.h +${CEE_CURRENT_LIST_DIR}RicWellPathExportCompletionDataFeatureImpl.h ${CEE_CURRENT_LIST_DIR}RicFishbonesTransmissibilityCalculationFeatureImp.h ${CEE_CURRENT_LIST_DIR}RigCompletionData.h ${CEE_CURRENT_LIST_DIR}RigCompletionDataGridCell.h @@ -28,6 +29,7 @@ endif() set (SOURCE_GROUP_SOURCE_FILES ${CEE_CURRENT_LIST_DIR}RicExportCompletionDataSettingsUi.cpp ${CEE_CURRENT_LIST_DIR}RicWellPathExportCompletionDataFeature.cpp +${CEE_CURRENT_LIST_DIR}RicWellPathExportCompletionDataFeatureImpl.cpp ${CEE_CURRENT_LIST_DIR}RicFishbonesTransmissibilityCalculationFeatureImp.cpp ${CEE_CURRENT_LIST_DIR}RigCompletionData.cpp ${CEE_CURRENT_LIST_DIR}RigCompletionDataGridCell.cpp diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h b/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h index 13b8409cc3..fe125abb2c 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h @@ -21,7 +21,7 @@ #include "RifEclipseDataTableFormatter.h" #include "RicCaseAndFileExportSettingsUi.h" -#include "RicWellPathExportCompletionDataFeature.h" +#include "RicWellPathExportCompletionDataFeatureImpl.h" #include "cafCmdFeature.h" diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp index d4e5c2af3b..08acd6925d 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp @@ -19,7 +19,7 @@ #include "RicFishbonesTransmissibilityCalculationFeatureImp.h" #include "RicExportCompletionDataSettingsUi.h" -#include "RicWellPathExportCompletionDataFeature.h" +#include "RicWellPathExportCompletionDataFeatureImpl.h" #include "RigActiveCellInfo.h" #include "RigCompletionData.h" diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp index b0331130aa..6c9f251c14 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp @@ -17,6 +17,7 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RicWellPathExportCompletionDataFeature.h" +#include "RicWellPathExportCompletionDataFeatureImpl.h" #include "RiaApplication.h" #include "RiaLogging.h" @@ -247,1039 +248,3 @@ std::vector RicWellPathExportCompletionDataFeature::selectedS - - - - - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportCompletions(const std::vector& wellPaths, - const std::vector& simWells, - const RicExportCompletionDataSettingsUi& exportSettings) -{ - if (exportSettings.caseToApply() == nullptr) - { - RiaLogging::error("Export Completions Data: Cannot export completions data without specified eclipse case"); - return; - } - - std::vector usedWellPaths; - if (exportSettings.wellSelection == RicExportCompletionDataSettingsUi::ALL_WELLS - || exportSettings.wellSelection == RicExportCompletionDataSettingsUi::SELECTED_WELLS) - { - usedWellPaths = wellPaths; - } - else if (exportSettings.wellSelection == RicExportCompletionDataSettingsUi::CHECKED_WELLS) - { - for (auto wellPath : wellPaths) - { - if (wellPath->showWellPath) - { - usedWellPaths.push_back(wellPath); - } - } - } - - { - bool unitSystemMismatch = false; - for (const RimWellPath* wellPath : usedWellPaths) - { - if (wellPath->unitSystem() != exportSettings.caseToApply->eclipseCaseData()->unitsType()) - { - unitSystemMismatch = true; - break; - } - } - - for (const RimSimWellInView* simWell : simWells) - { - RimEclipseCase* eclipseCase; - simWell->firstAncestorOrThisOfType(eclipseCase); - if (exportSettings.caseToApply->eclipseCaseData()->unitsType() != eclipseCase->eclipseCaseData()->unitsType()) - { - unitSystemMismatch = true; - break; - } - } - if (unitSystemMismatch) - { - RiaLogging::error("Well path unit systems must match unit system of chosen eclipse case."); - return; - } - } - - std::map > completionsPerEclipseCell; - - // FractureTransmissibilityExportInformation - std::unique_ptr fractureTransmissibilityExportInformationStream = nullptr; - - QString fractureTransmisibillityExportInformationPath = QDir(exportSettings.folder).filePath("FractureTransmissibilityExportInformation"); - QFile fractureTransmissibilityExportInformationFile(fractureTransmisibillityExportInformationPath); - - RiaPreferences* prefs = RiaApplication::instance()->preferences(); - if (prefs->includeFractureDebugInfoFile()) - { - if (!fractureTransmissibilityExportInformationFile.open(QIODevice::WriteOnly)) - { - RiaLogging::error(QString("Export Completions Data: Could not open the file: %1").arg(fractureTransmisibillityExportInformationPath)); - return; - } - - fractureTransmissibilityExportInformationStream = std::unique_ptr(new QTextStream(&fractureTransmissibilityExportInformationFile)); - } - - size_t maxProgress = - usedWellPaths.size() * 3 + -#ifdef USE_PROTOTYPE_FEATURE_FRACTURES - simWells.size() + -#endif // USE_PROTOTYPE_FEATURE_FRACTURES - (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL ? usedWellPaths.size() : - exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL_AND_COMPLETION_TYPE ? usedWellPaths.size() * 3 : 1) + - simWells.size(); - - caf::ProgressInfo progress(maxProgress, "Export Completions"); - - progress.setProgressDescription("Read Completion Data"); - for (auto wellPath : usedWellPaths) - { - // Generate completion data - - if (exportSettings.includePerforations) - { - std::vector perforationCompletionData = generatePerforationsCompdatValues(wellPath, exportSettings); - appendCompletionData(&completionsPerEclipseCell, perforationCompletionData); - } - progress.incrementProgress(); - - if (exportSettings.includeFishbones) - { - std::vector fishbonesCompletionData = RicFishbonesTransmissibilityCalculationFeatureImp::generateFishboneCompdatValuesUsingAdjustedCellVolume(wellPath, exportSettings); - appendCompletionData(&completionsPerEclipseCell, fishbonesCompletionData); - } - progress.incrementProgress(); - -#ifdef USE_PROTOTYPE_FEATURE_FRACTURES - if (exportSettings.includeFractures()) - { - std::vector fractureCompletionData = RicExportFractureCompletionsImpl::generateCompdatValuesForWellPath(wellPath, exportSettings, fractureTransmissibilityExportInformationStream.get()); - appendCompletionData(&completionsPerEclipseCell, fractureCompletionData); - } -#endif // USE_PROTOTYPE_FEATURE_FRACTURES - progress.incrementProgress(); - } - -#ifdef USE_PROTOTYPE_FEATURE_FRACTURES - for (auto simWell : simWells) - { - std::vector fractureCompletionData = RicExportFractureCompletionsImpl::generateCompdatValuesForSimWell(exportSettings.caseToApply(), - simWell, - fractureTransmissibilityExportInformationStream.get()); - appendCompletionData(&completionsPerEclipseCell, fractureCompletionData); - progress.incrementProgress(); - } -#endif // USE_PROTOTYPE_FEATURE_FRACTURES - - const QString eclipseCaseName = exportSettings.caseToApply->caseUserDescription(); - - progress.setProgressDescription("Write Export Files"); - if (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::UNIFIED_FILE) - { - std::vector completions; - for (auto& data : completionsPerEclipseCell) - { - completions.push_back(combineEclipseCellCompletions(data.second, exportSettings)); - } - - const QString fileName = QString("UnifiedCompletions_%1").arg(eclipseCaseName); - printCompletionsToFiles(exportSettings.folder, fileName, completions, exportSettings.compdatExport); - progress.incrementProgress(); - } - else if (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL) - { - for (auto wellPath : usedWellPaths) - { - std::map > filteredWellCompletions = getCompletionsForWell(completionsPerEclipseCell, wellPath->completions()->wellNameForExport()); - std::vector completions; - for (auto& data : filteredWellCompletions) - { - completions.push_back(combineEclipseCellCompletions(data.second, exportSettings)); - } - std::vector wellCompletions; - for (auto completion : completions) - { - if (completion.wellName() == wellPath->completions()->wellNameForExport()) - { - wellCompletions.push_back(completion); - } - } - - if (wellCompletions.empty()) continue; - - QString fileName = QString("%1_unifiedCompletions_%2").arg(wellPath->name()).arg(eclipseCaseName); - printCompletionsToFiles(exportSettings.folder, fileName, wellCompletions, exportSettings.compdatExport); - progress.incrementProgress(); - } - } - else if (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL_AND_COMPLETION_TYPE) - { - for (auto wellPath : usedWellPaths) - { - std::map > filteredWellCompletions = getCompletionsForWell(completionsPerEclipseCell, wellPath->completions()->wellNameForExport()); - std::vector completions; - for (auto& data : filteredWellCompletions) - { - completions.push_back(combineEclipseCellCompletions(data.second, exportSettings)); - } - { - std::vector fishbonesCompletions = getCompletionsForWellAndCompletionType(completions, wellPath->completions()->wellNameForExport(), RigCompletionData::FISHBONES); - if (!fishbonesCompletions.empty()) - { - QString fileName = QString("%1_Fishbones_%2").arg(wellPath->name()).arg(eclipseCaseName); - printCompletionsToFiles(exportSettings.folder, fileName, fishbonesCompletions, exportSettings.compdatExport); - } - progress.incrementProgress(); - } - { - std::vector perforationCompletions = getCompletionsForWellAndCompletionType(completions, wellPath->completions()->wellNameForExport(), RigCompletionData::PERFORATION); - if (!perforationCompletions.empty()) - { - QString fileName = QString("%1_Perforations_%2").arg(wellPath->name()).arg(eclipseCaseName); - printCompletionsToFiles(exportSettings.folder, fileName, perforationCompletions, exportSettings.compdatExport); - } - progress.incrementProgress(); - } - { - std::vector fractureCompletions = getCompletionsForWellAndCompletionType(completions, wellPath->completions()->wellNameForExport(), RigCompletionData::FRACTURE); - if (!fractureCompletions.empty()) - { - QString fileName = QString("%1_Fractures_%2").arg(wellPath->name()).arg(eclipseCaseName); - printCompletionsToFiles(exportSettings.folder, fileName, fractureCompletions, exportSettings.compdatExport); - } - progress.incrementProgress(); - } - } - } - - // Export sim wells - if (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL || - exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL_AND_COMPLETION_TYPE) - { - for (auto simWell : simWells) - { - std::map > filteredWellCompletions = getCompletionsForWell(completionsPerEclipseCell, simWell->name()); - std::vector completions; - for (auto& data : filteredWellCompletions) - { - completions.push_back(combineEclipseCellCompletions(data.second, exportSettings)); - } - std::vector wellCompletions; - for (auto completion : completions) - { - if (completion.wellName() == simWell->name()) - { - wellCompletions.push_back(completion); - } - } - - if (wellCompletions.empty()) continue; - - QString fileName = exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL ? - QString("%1_unifiedCompletions_%2").arg(simWell->name()).arg(eclipseCaseName) : - QString("%1_Fractures_%2").arg(simWell->name()).arg(eclipseCaseName); - printCompletionsToFiles(exportSettings.folder, fileName, wellCompletions, exportSettings.compdatExport); - progress.incrementProgress(); - } - } - -} - -//================================================================================================== -/// -//================================================================================================== -RigCompletionData RicWellPathExportCompletionDataFeatureImpl::combineEclipseCellCompletions(const std::vector& completions, - const RicExportCompletionDataSettingsUi& settings) -{ - CVF_ASSERT(!completions.empty()); - QString wellName = completions[0].wellName(); - RigCompletionDataGridCell cellIndexIJK = completions[0].completionDataGridCell(); - RigCompletionData::CompletionType completionType = completions[0].completionType(); - - //completion type, skin factor, well bore diameter and cell direction are taken from (first) main bore, - //if no main bore they are taken from first completion - double skinfactor = completions[0].skinFactor(); - double wellBoreDiameter = completions[0].diameter(); - CellDirection cellDirection = completions[0].direction(); - - for (const RigCompletionData& completion : completions) - { - if (completion.isMainBore()) - { - skinfactor = completion.skinFactor(); - wellBoreDiameter = completion.diameter(); - cellDirection = completion.direction(); - break; - } - } - - - RigCompletionData resultCompletion(wellName, cellIndexIJK); - - double totalTrans = 0.0; - - for (const RigCompletionData& completion : completions) - { - resultCompletion.m_metadata.reserve(resultCompletion.m_metadata.size() + completion.m_metadata.size()); - resultCompletion.m_metadata.insert(resultCompletion.m_metadata.end(), completion.m_metadata.begin(), completion.m_metadata.end()); - - if (completion.completionType() != completions[0].completionType()) - { - QString errorMessage = QString("Cannot combine completions of different types in same cell %1").arg(cellIndexIJK.oneBasedLocalCellIndexString()); - RiaLogging::error(errorMessage); - resultCompletion.addMetadata("ERROR", errorMessage); - return resultCompletion; //Returning empty completion, should not be exported - } - - if (completion.wellName() != completions[0].wellName()) - { - QString errorMessage = QString("Cannot combine completions of different types in same cell %1").arg(cellIndexIJK.oneBasedLocalCellIndexString()); - RiaLogging::error(errorMessage); - resultCompletion.addMetadata("ERROR", errorMessage); - return resultCompletion; //Returning empty completion, should not be exported - } - - if (completion.transmissibility() == HUGE_VAL) - { - QString errorMessage = QString("Transmissibility calculation has failed for cell %1").arg(cellIndexIJK.oneBasedLocalCellIndexString()); - RiaLogging::error(errorMessage); - resultCompletion.addMetadata("ERROR", errorMessage); - return resultCompletion; //Returning empty completion, should not be exported - } - - if (settings.excludeMainBoreForFishbones && completionType == RigCompletionData::FISHBONES && completion.isMainBore()) - { - continue; - } - - totalTrans = totalTrans + completion.transmissibility(); - } - - - if (settings.compdatExport == RicExportCompletionDataSettingsUi::TRANSMISSIBILITIES) - { - resultCompletion.setCombinedValuesExplicitTrans(totalTrans, completionType); - } - else if (settings.compdatExport == RicExportCompletionDataSettingsUi::WPIMULT_AND_DEFAULT_CONNECTION_FACTORS) - { - //calculate trans for main bore - but as Eclipse will do it! - double transmissibilityEclipseCalculation = RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityAsEclipseDoes(settings.caseToApply(), - skinfactor, - wellBoreDiameter / 2, - cellIndexIJK.globalCellIndex(), - cellDirection); - - double wpimult = totalTrans / transmissibilityEclipseCalculation; - resultCompletion.setCombinedValuesImplicitTransWPImult(wpimult, cellDirection, skinfactor, wellBoreDiameter, completionType); - } - - return resultCompletion; -} - - - - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::printCompletionsToFiles(const QString& folderName, - const QString& fileName, - std::vector& completions, - RicExportCompletionDataSettingsUi::CompdatExportType exportType) -{ - // Sort completions based on grid they belong to - std::vector completionsForMainGrid; - - std::map> completionsForSubGrids; - - for (const auto& completion : completions) - { - QString gridName = completion.completionDataGridCell().lgrName(); - if (gridName.isEmpty()) - { - completionsForMainGrid.push_back(completion); - } - else - { - auto it = completionsForSubGrids.find(gridName); - if (it == completionsForSubGrids.end()) - { - completionsForSubGrids.insert(std::pair>(gridName, std::vector{completion})); - } - else - { - it->second.push_back(completion); - } - } - } - - if (!completionsForMainGrid.empty()) - { - std::map> completionsForGrid; - completionsForGrid.insert(std::pair>("", completionsForMainGrid)); - - printCompletionsToFile(folderName, fileName, completionsForGrid, exportType); - } - - if (!completionsForSubGrids.empty()) - { - QString lgrFileName = fileName + "_LGR"; - printCompletionsToFile(folderName, lgrFileName, completionsForSubGrids, exportType); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::printCompletionsToFile(const QString& folderName, - const QString& fileName, - const std::map>& completionsPerGrid, - RicExportCompletionDataSettingsUi::CompdatExportType exportType) -{ - if (completionsPerGrid.empty()) return; - - QDir exportFolder(folderName); - - if (!exportFolder.exists()) - { - bool createdPath = exportFolder.mkpath(folderName); - if (createdPath) RiaLogging::info("Created export folder " + folderName); - 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)) - { - RiaLogging::error(QString("Export Completions Data: Could not open the file: %1").arg(filePath)); - return; - } - - QTextStream stream(&exportFile); - RifEclipseDataTableFormatter formatter(stream); - - for (const auto& gridCompletions : completionsPerGrid) - { - std::vector completions = gridCompletions.second; - - // Sort by well name / cell index - std::sort(completions.begin(), completions.end()); - - // Print completion data - QString gridName = gridCompletions.first; - generateCompdatTable(formatter, gridName, completions); - - if (exportType == RicExportCompletionDataSettingsUi::WPIMULT_AND_DEFAULT_CONNECTION_FACTORS) - { - generateWpimultTable(formatter, gridName, completions); - } - } - - RiaLogging::info(QString("Successfully exported completion data to %1").arg(filePath)); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RicWellPathExportCompletionDataFeatureImpl::getCompletionsForWellAndCompletionType(const std::vector& completions, - const QString& wellName, - RigCompletionData::CompletionType completionType) -{ - std::vector filteredCompletions; - for (auto completion : completions) - { - if (completion.wellName() == wellName && completion.completionType() == completionType) - { - filteredCompletions.push_back(completion); - } - } - return filteredCompletions; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::map > RicWellPathExportCompletionDataFeatureImpl::getCompletionsForWell(const std::map>& cellToCompletionMap, const QString& wellName) -{ - std::map > wellCompletions; - - for (const auto& it : cellToCompletionMap) - { - for (auto& completion : it.second) - { - if (completion.wellName() == wellName) - { - wellCompletions[it.first].push_back(completion); - } - } - } - - return wellCompletions; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateCompdatTable(RifEclipseDataTableFormatter& formatter, const QString& gridName, const std::vector& completionData) -{ - std::vector header; - - if (gridName.isEmpty()) - { - header = { - RifEclipseOutputTableColumn("Well"), - RifEclipseOutputTableColumn("I"), - RifEclipseOutputTableColumn("J"), - RifEclipseOutputTableColumn("K1"), - RifEclipseOutputTableColumn("K2"), - RifEclipseOutputTableColumn("Status"), - RifEclipseOutputTableColumn("SAT"), - RifEclipseOutputTableColumn("TR", RifEclipseOutputTableDoubleFormatting(RifEclipseOutputTableDoubleFormat::RIF_SCIENTIFIC)), - RifEclipseOutputTableColumn("DIAM"), - RifEclipseOutputTableColumn("KH"), - RifEclipseOutputTableColumn("S"), - RifEclipseOutputTableColumn("Df"), - RifEclipseOutputTableColumn("DIR"), - RifEclipseOutputTableColumn("r0") - }; - - formatter.keyword("COMPDAT"); - } - else - { - header = { - RifEclipseOutputTableColumn("Well"), - RifEclipseOutputTableColumn("LgrName"), - RifEclipseOutputTableColumn("I"), - RifEclipseOutputTableColumn("J"), - RifEclipseOutputTableColumn("K1"), - RifEclipseOutputTableColumn("K2"), - RifEclipseOutputTableColumn("Status"), - RifEclipseOutputTableColumn("SAT"), - RifEclipseOutputTableColumn("TR", RifEclipseOutputTableDoubleFormatting(RifEclipseOutputTableDoubleFormat::RIF_SCIENTIFIC)), - RifEclipseOutputTableColumn("DIAM"), - RifEclipseOutputTableColumn("KH"), - RifEclipseOutputTableColumn("S"), - RifEclipseOutputTableColumn("Df"), - RifEclipseOutputTableColumn("DIR"), - RifEclipseOutputTableColumn("r0") - }; - - formatter.keyword("COMPDATL"); - } - formatter.header(header); - - for (const RigCompletionData& data : completionData) - { - if (data.transmissibility() == 0.0 || data.wpimult()==0.0) - { - //Don't export completions without transmissibility - continue; - } - - for (const RigCompletionMetaData& metadata : data.metadata()) - { - formatter.comment(QString("%1 : %2").arg(metadata.name).arg(metadata.comment)); - } - formatter.add(data.wellName()); - - if (!gridName.isEmpty()) - { - formatter.add(gridName); - } - - formatter.addZeroBasedCellIndex(data.completionDataGridCell().localCellIndexI()).addZeroBasedCellIndex(data.completionDataGridCell().localCellIndexJ()).addZeroBasedCellIndex(data.completionDataGridCell().localCellIndexK()).addZeroBasedCellIndex(data.completionDataGridCell().localCellIndexK()); - switch (data.connectionState()) - { - case OPEN: - formatter.add("OPEN"); - break; - case SHUT: - formatter.add("SHUT"); - break; - case AUTO: - formatter.add("AUTO"); - break; - } - if (RigCompletionData::isDefaultValue(data.saturation())) formatter.add("1*"); else formatter.add(data.saturation()); - if (RigCompletionData::isDefaultValue(data.transmissibility())) - { - formatter.add("1*"); // Transmissibility - - if (RigCompletionData::isDefaultValue(data.diameter())) formatter.add("1*"); else formatter.add(data.diameter()); - if (RigCompletionData::isDefaultValue(data.kh())) formatter.add("1*"); else formatter.add(data.kh()); - if (RigCompletionData::isDefaultValue(data.skinFactor())) formatter.add("1*"); else formatter.add(data.skinFactor()); - if (RigCompletionData::isDefaultValue(data.dFactor())) formatter.add("1*"); else formatter.add(data.dFactor()); - - switch (data.direction()) - { - case DIR_I: - formatter.add("'X'"); - break; - case DIR_J: - formatter.add("'Y'"); - break; - case DIR_K: - formatter.add("'Z'"); - break; - default: - formatter.add("'Z'"); - break; - } - } - else - { - formatter.add(data.transmissibility()); - } - - formatter.rowCompleted(); - } - formatter.tableCompleted(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWpimultTable(RifEclipseDataTableFormatter& formatter, - const QString& gridName, - const std::vector& completionData) -{ - std::vector header; - - if (gridName.isEmpty()) - { - header = { - RifEclipseOutputTableColumn("Well"), - RifEclipseOutputTableColumn("Mult"), - RifEclipseOutputTableColumn("I"), - RifEclipseOutputTableColumn("J"), - RifEclipseOutputTableColumn("K"), - }; - formatter.keyword("WPIMULT"); - } - else - { - header = { - RifEclipseOutputTableColumn("Well"), - RifEclipseOutputTableColumn("LgrName"), - RifEclipseOutputTableColumn("Mult"), - RifEclipseOutputTableColumn("I"), - RifEclipseOutputTableColumn("J"), - RifEclipseOutputTableColumn("K"), - }; - formatter.keyword("WPIMULTL"); - } - formatter.header(header); - - for (auto& completion : completionData) - { - if (completion.wpimult() == 0.0 || completion.isDefaultValue(completion.wpimult())) - { - continue; - } - - formatter.add(completion.wellName()); - formatter.add(completion.wpimult()); - - if (!gridName.isEmpty()) - { - formatter.add(gridName); - } - - formatter.addZeroBasedCellIndex(completion.completionDataGridCell().localCellIndexI()).addZeroBasedCellIndex(completion.completionDataGridCell().localCellIndexJ()).addZeroBasedCellIndex(completion.completionDataGridCell().localCellIndexK()); - formatter.rowCompleted(); - } - - formatter.tableCompleted(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RicWellPathExportCompletionDataFeatureImpl::generatePerforationsCompdatValues(const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings) -{ - RiaEclipseUnitTools::UnitSystem unitSystem = settings.caseToApply->eclipseCaseData()->unitsType(); - - std::vector completionData; - const RigActiveCellInfo* activeCellInfo = settings.caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); - - if (wellPath->perforationIntervalCollection()->isChecked()) - { - for (const RimPerforationInterval* interval : wellPath->perforationIntervalCollection()->perforations()) - { - if (!interval->isChecked()) continue; - if (!interval->isActiveOnDate(settings.caseToApply->timeStepDates()[settings.timeStep])) continue; - - using namespace std; - pair, vector > perforationPointsAndMD = wellPath->wellPathGeometry()->clippedPointSubset(interval->startMD(), interval->endMD()); - std::vector intersectedCells = RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(settings.caseToApply->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, settings.caseToApply->mainGrid())); - CellDirection direction = calculateDirectionInCell(settings.caseToApply, cell.globCellIndex, cell.intersectionLengthsInCellCS); - - double transmissibility = RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibility(settings.caseToApply, - wellPath, - cell.intersectionLengthsInCellCS, - interval->skinFactor(), - interval->diameter(unitSystem) / 2, - cell.globCellIndex, - settings.useLateralNTG); - - - - completion.setTransAndWPImultBackgroundDataFromPerforation(transmissibility, - interval->skinFactor(), - interval->diameter(unitSystem), - direction); - completion.addMetadata("Perforation", QString("StartMD: %1 - EndMD: %2").arg(interval->startMD()).arg(interval->endMD()) + QString(" : ") + QString::number(transmissibility)); - completionData.push_back(completion); - } - } - } - - return completionData; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::set RicWellPathExportCompletionDataFeatureImpl::findIntersectedCells(const RigEclipseCaseData* caseData, const std::vector& coords) -{ - std::set cells; - - std::vector intersections = RigWellPathIntersectionTools::findRawHexCellIntersections(caseData->mainGrid(), coords); - for (auto intersection : intersections) - { - cells.insert(intersection.m_hexIndex); - } - - return cells; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicWellPathExportCompletionDataFeatureImpl::wellSegmentLocationOrdering(const WellSegmentLocation& first, const WellSegmentLocation& second) -{ - return first.measuredDepth < second.measuredDepth; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RicWellPathExportCompletionDataFeatureImpl::findWellSegmentLocations(const RimEclipseCase* caseToApply, const RimWellPath* wellPath) -{ - std::vector fishbonesSubs; - - if (wellPath->fishbonesCollection()->isChecked()) - { - for (RimFishbonesMultipleSubs* subs : wellPath->fishbonesCollection()->fishbonesSubs()) - { - if (subs->isActive()) - { - fishbonesSubs.push_back(subs); - } - } - } - - return findWellSegmentLocations(caseToApply, wellPath, fishbonesSubs); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RicWellPathExportCompletionDataFeatureImpl::findWellSegmentLocations(const RimEclipseCase* caseToApply, const RimWellPath* wellPath, const std::vector& fishbonesSubs) -{ - std::vector wellSegmentLocations; - for (RimFishbonesMultipleSubs* subs : fishbonesSubs) - { - for (auto& sub : subs->installedLateralIndices()) - { - double measuredDepth = subs->measuredDepth(sub.subIndex); - cvf::Vec3d position = wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(measuredDepth); - WellSegmentLocation location = WellSegmentLocation(subs, measuredDepth, -position.z(), sub.subIndex); - for (size_t lateralIndex : sub.lateralIndices) - { - location.laterals.push_back(WellSegmentLateral(lateralIndex)); - } - wellSegmentLocations.push_back(location); - } - } - std::sort(wellSegmentLocations.begin(), wellSegmentLocations.end(), wellSegmentLocationOrdering); - - assignLateralIntersectionsAndBranchAndSegmentNumbers(caseToApply, &wellSegmentLocations); - - return wellSegmentLocations; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignLateralIntersections(const RimEclipseCase* caseToApply, - WellSegmentLocation* location, - int* branchNum, - int* segmentNum) -{ - for (WellSegmentLateral& lateral : location->laterals) - { - ++(*branchNum); - lateral.branchNumber = (*branchNum); - - std::vector > lateralCoordMDPairs = location->fishbonesSubs->coordsAndMDForLateral(location->subIndex, lateral.lateralIndex); - - if ( !lateralCoordMDPairs.size() ) - { - 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); - double previousExitMD = lateralMDs.front(); - double previousExitTVD = lateralCoords.front().z(); - - int attachedSegmentNumber = location->icdSegmentNumber; - for (const auto& cellIntInfo: intersections) - { - ++(*segmentNum); - WellSegmentLateralIntersection lateralIntersection((*segmentNum), - attachedSegmentNumber, - cellIntInfo.globCellIndex, - cellIntInfo.endMD - previousExitMD, - cellIntInfo.endPoint.z() - previousExitTVD, - cellIntInfo.intersectionLengthsInCellCS); - - lateral.intersections.push_back(lateralIntersection); - - attachedSegmentNumber = (*segmentNum); - previousExitMD = cellIntInfo.endMD; - previousExitTVD = cellIntInfo.endPoint.z(); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignLateralIntersectionsAndBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, std::vector* locations) -{ - int segmentNumber = 1; - int branchNumber = 1; - - // First loop over the locations so that each segment on the main stem is an incremental number - for (WellSegmentLocation& location : *locations) - { - location.segmentNumber = ++segmentNumber; - location.icdBranchNumber = ++branchNumber; - location.icdSegmentNumber = ++segmentNumber; - } - - // Then assign branch and segment numbers to each lateral parts - for (WellSegmentLocation& location : *locations) - { - assignLateralIntersections(caseToApply, &location, &branchNumber, &segmentNumber); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::appendCompletionData(std::map >* completionData, const std::vector& data) -{ - for (auto& completion : data) - { - auto it = completionData->find(completion.completionDataGridCell()); - if (it != completionData->end()) - { - it->second.push_back(completion); - } - else - { - completionData->insert(std::pair >(completion.completionDataGridCell(), std::vector {completion})); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -CellDirection RicWellPathExportCompletionDataFeatureImpl::calculateDirectionInCell(RimEclipseCase* eclipseCase, size_t globalCellIndex, const cvf::Vec3d& lengthsInCell) -{ - RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); - - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); - cvf::ref dxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); - cvf::ref dyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); - cvf::ref dzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); - - double xLengthFraction = fabs(lengthsInCell.x() / dxAccessObject->cellScalarGlobIdx(globalCellIndex)); - double yLengthFraction = fabs(lengthsInCell.y() / dyAccessObject->cellScalarGlobIdx(globalCellIndex)); - double zLengthFraction = fabs(lengthsInCell.z() / dzAccessObject->cellScalarGlobIdx(globalCellIndex)); - - if (xLengthFraction > yLengthFraction && xLengthFraction > zLengthFraction) - { - return CellDirection::DIR_I; - } - else if (yLengthFraction > xLengthFraction && yLengthFraction > zLengthFraction) - { - return CellDirection::DIR_J; - } - else - { - return CellDirection::DIR_K; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibility(RimEclipseCase* eclipseCase, - const RimWellPath* wellPath, - const cvf::Vec3d& internalCellLengths, - double skinFactor, - double wellRadius, - size_t globalCellIndex, - bool useLateralNTG, - size_t volumeScaleConstant, - CellDirection directionForVolumeScaling) -{ - RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); - - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); - cvf::ref dxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); - cvf::ref dyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); - cvf::ref dzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); - - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMX"); - cvf::ref permxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMY"); - cvf::ref permyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMZ"); - cvf::ref permzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMZ"); - - double ntg = 1.0; - size_t ntgResIdx = eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); - if (ntgResIdx != cvf::UNDEFINED_SIZE_T) - { - cvf::ref ntgAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "NTG"); - ntg = ntgAccessObject->cellScalarGlobIdx(globalCellIndex); - } - double latNtg = useLateralNTG ? ntg : 1.0; - - double dx = dxAccessObject->cellScalarGlobIdx(globalCellIndex); - double dy = dyAccessObject->cellScalarGlobIdx(globalCellIndex); - double dz = dzAccessObject->cellScalarGlobIdx(globalCellIndex); - double permx = permxAccessObject->cellScalarGlobIdx(globalCellIndex); - double permy = permyAccessObject->cellScalarGlobIdx(globalCellIndex); - double permz = permzAccessObject->cellScalarGlobIdx(globalCellIndex); - - double darcy = RiaEclipseUnitTools::darcysConstant(wellPath->unitSystem()); - - if (volumeScaleConstant != 1) - { - if (directionForVolumeScaling == CellDirection::DIR_I) dx = dx / volumeScaleConstant; - if (directionForVolumeScaling == CellDirection::DIR_J) dy = dy / volumeScaleConstant; - if (directionForVolumeScaling == CellDirection::DIR_K) dz = dz / volumeScaleConstant; - } - - double transx = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(internalCellLengths.x() * latNtg, permy, permz, dy, dz, wellRadius, skinFactor, darcy); - double transy = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(internalCellLengths.y() * latNtg, permx, permz, dx, dz, wellRadius, skinFactor, darcy); - double transz = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(internalCellLengths.z() * ntg, permy, permx, dy, dx, wellRadius, skinFactor, darcy); - - return RigTransmissibilityEquations::totalConnectionFactor(transx, transy, transz); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityAsEclipseDoes(RimEclipseCase* eclipseCase, - double skinFactor, - double wellRadius, - size_t globalCellIndex, - CellDirection direction) -{ - RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); - - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); - cvf::ref dxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); - cvf::ref dyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); - cvf::ref dzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); - - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMX"); - cvf::ref permxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMY"); - cvf::ref permyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMZ"); - cvf::ref permzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMZ"); - - double ntg = 1.0; - size_t ntgResIdx = eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); - if (ntgResIdx != cvf::UNDEFINED_SIZE_T) - { - cvf::ref ntgAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "NTG"); - ntg = ntgAccessObject->cellScalarGlobIdx(globalCellIndex); - } - - double dx = dxAccessObject->cellScalarGlobIdx(globalCellIndex); - double dy = dyAccessObject->cellScalarGlobIdx(globalCellIndex); - double dz = dzAccessObject->cellScalarGlobIdx(globalCellIndex); - double permx = permxAccessObject->cellScalarGlobIdx(globalCellIndex); - double permy = permyAccessObject->cellScalarGlobIdx(globalCellIndex); - double permz = permzAccessObject->cellScalarGlobIdx(globalCellIndex); - - RiaEclipseUnitTools::UnitSystem units = eclipseCaseData->unitsType(); - double darcy = RiaEclipseUnitTools::darcysConstant(units); - - double trans = cvf::UNDEFINED_DOUBLE; - if (direction == CellDirection::DIR_I) - { - trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(dx, permy, permz, dy, dz, wellRadius, skinFactor, darcy); - } - else if (direction == CellDirection::DIR_J) - { - trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(dy, permx, permz, dx, dz, wellRadius, skinFactor, darcy); - } - else if (direction == CellDirection::DIR_K) - { - trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(dz * ntg, permy, permx, dy, dx, wellRadius, skinFactor, darcy); - } - - return trans; -} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.h index 314916ffc1..aba8591a30 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.h @@ -39,73 +39,6 @@ class RimFishbonesMultipleSubs; class RimSimWellInView; class RimWellPath; -//================================================================================================== -/// -//================================================================================================== -struct WellSegmentLateralIntersection { - WellSegmentLateralIntersection(int segmentNumber, - int attachedSegmentNumber, - size_t globalCellIndex, - double length, - double depth, - const cvf::Vec3d& lengthsInCell) - : segmentNumber(segmentNumber), - attachedSegmentNumber(attachedSegmentNumber), - globalCellIndex(globalCellIndex), - mdFromPreviousIntersection(length), - tvdChangeFromPreviousIntersection(depth), - lengthsInCell(lengthsInCell), - mainBoreCell(false) - {} - - int segmentNumber; - int attachedSegmentNumber; - size_t globalCellIndex; - bool mainBoreCell; - double mdFromPreviousIntersection; - double tvdChangeFromPreviousIntersection; - cvf::Vec3d lengthsInCell; -}; - -//================================================================================================== -/// -//================================================================================================== -struct WellSegmentLateral { - WellSegmentLateral(size_t lateralIndex) - : lateralIndex(lateralIndex), - branchNumber(0) - {} - - size_t lateralIndex; - int branchNumber; - std::vector intersections; -}; - -//================================================================================================== -/// -//================================================================================================== -struct WellSegmentLocation { - WellSegmentLocation(const RimFishbonesMultipleSubs* subs, double measuredDepth, double trueVerticalDepth, size_t subIndex, int segmentNumber = -1) - : fishbonesSubs(subs), - measuredDepth(measuredDepth), - trueVerticalDepth(trueVerticalDepth), - subIndex(subIndex), - segmentNumber(segmentNumber), - icdBranchNumber(-1), - icdSegmentNumber(-1) - { - } - - const RimFishbonesMultipleSubs* fishbonesSubs; - double measuredDepth; - double trueVerticalDepth; - size_t subIndex; - int segmentNumber; - int icdBranchNumber; - int icdSegmentNumber; - std::vector laterals; -}; - //================================================================================================== /// //================================================================================================== @@ -126,64 +59,3 @@ private: }; - - - -//================================================================================================== -/// -//================================================================================================== -class RicWellPathExportCompletionDataFeatureImpl -{ - -public: - static std::vector findWellSegmentLocations(const RimEclipseCase* caseToApply, const RimWellPath* wellPath); - static std::vector findWellSegmentLocations(const RimEclipseCase* caseToApply, const RimWellPath* wellPath, const std::vector& fishbonesSubs); - - // TODO : Move - static std::set findIntersectedCells(const RigEclipseCaseData* grid, const std::vector& coords); - - static CellDirection calculateDirectionInCell(RimEclipseCase* eclipseCase, size_t globalCellIndex, const cvf::Vec3d& lengthsInCell); - - static double calculateTransmissibility(RimEclipseCase* eclipseCase, - const RimWellPath* wellPath, - const cvf::Vec3d& internalCellLengths, - double skinFactor, - double wellRadius, - size_t globalCellIndex, - bool useLateralNTG, - size_t volumeScaleConstant = 1, - CellDirection directionForVolumeScaling = CellDirection::DIR_I); - - - static void exportCompletions(const std::vector& wellPaths, const std::vector& simWells, const RicExportCompletionDataSettingsUi& exportSettings); - -private: - static double calculateTransmissibilityAsEclipseDoes(RimEclipseCase* eclipseCase, - double skinFactor, - double wellRadius, - size_t globalCellIndex, - CellDirection direction); - - static RigCompletionData combineEclipseCellCompletions(const std::vector& completions, - const RicExportCompletionDataSettingsUi& settings); - - static void printCompletionsToFiles(const QString& exportFolder, const QString& fileName, std::vector& completions, RicExportCompletionDataSettingsUi::CompdatExportType exportType); - - static void printCompletionsToFile(const QString& folderName, const QString& fileName, const std::map>& completionsPerGrid, RicExportCompletionDataSettingsUi::CompdatExportType exportType); - - static std::vector getCompletionsForWellAndCompletionType(const std::vector& completions, const QString& wellName, RigCompletionData::CompletionType completionType); - - static std::map > getCompletionsForWell(const std::map>& cellToCompletionMap, const QString& wellName); - - static void generateCompdatTable(RifEclipseDataTableFormatter& formatter, const QString& gridName, const std::vector& completionData); - static void generateWpimultTable(RifEclipseDataTableFormatter& formatter, const QString& gridName, const std::vector& completionData); - - static std::vector generatePerforationsCompdatValues(const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings); - - static bool wellSegmentLocationOrdering(const WellSegmentLocation& first, const WellSegmentLocation& second); - static void assignLateralIntersections(const RimEclipseCase* caseToApply, WellSegmentLocation* location, int* branchNum, int* segmentNum); - static void assignLateralIntersectionsAndBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, std::vector* locations); - - static void appendCompletionData(std::map >* completionData, const std::vector& data); -}; - diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp new file mode 100644 index 0000000000..07ab32530d --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp @@ -0,0 +1,1103 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicWellPathExportCompletionDataFeatureImpl.h" + +#include "RiaApplication.h" +#include "RiaLogging.h" +#include "RiaPreferences.h" + +#include "RicExportCompletionDataSettingsUi.h" +#include "RicExportFeatureImpl.h" +#include "RicFishbonesTransmissibilityCalculationFeatureImp.h" +#include "RicExportFractureCompletionsImpl.h" + +#include "RigActiveCellInfo.h" +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigMainGrid.h" +#include "RigResultAccessorFactory.h" + +#include "RigTransmissibilityEquations.h" + +#include "RigWellLogExtractionTools.h" +#include "RigWellPath.h" +#include "RigWellPathIntersectionTools.h" + +#include "RimDialogData.h" +#include "RimSimWellInViewCollection.h" +#include "RimFishboneWellPath.h" +#include "RimFishboneWellPathCollection.h" +#include "RimFishbonesCollection.h" +#include "RimFishbonesMultipleSubs.h" +#include "RimPerforationCollection.h" +#include "RimPerforationInterval.h" +#include "RimProject.h" +#include "RimSimWellInView.h" +#include "RimWellPath.h" +#include "RimWellPathCollection.h" +#include "RimWellPathCompletions.h" + +#include "RiuMainWindow.h" + +#include "cafPdmUiPropertyViewDialog.h" +#include "cafProgressInfo.h" +#include "cafSelectionManager.h" + +#include "cvfPlane.h" + +#include +#include +#include +#include +#include "RigWellLogExtractor.h" + + + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportCompletionDataFeatureImpl::exportCompletions(const std::vector& wellPaths, + const std::vector& simWells, + const RicExportCompletionDataSettingsUi& exportSettings) +{ + if (exportSettings.caseToApply() == nullptr) + { + RiaLogging::error("Export Completions Data: Cannot export completions data without specified eclipse case"); + return; + } + + std::vector usedWellPaths; + if (exportSettings.wellSelection == RicExportCompletionDataSettingsUi::ALL_WELLS + || exportSettings.wellSelection == RicExportCompletionDataSettingsUi::SELECTED_WELLS) + { + usedWellPaths = wellPaths; + } + else if (exportSettings.wellSelection == RicExportCompletionDataSettingsUi::CHECKED_WELLS) + { + for (auto wellPath : wellPaths) + { + if (wellPath->showWellPath) + { + usedWellPaths.push_back(wellPath); + } + } + } + + { + bool unitSystemMismatch = false; + for (const RimWellPath* wellPath : usedWellPaths) + { + if (wellPath->unitSystem() != exportSettings.caseToApply->eclipseCaseData()->unitsType()) + { + unitSystemMismatch = true; + break; + } + } + + for (const RimSimWellInView* simWell : simWells) + { + RimEclipseCase* eclipseCase; + simWell->firstAncestorOrThisOfType(eclipseCase); + if (exportSettings.caseToApply->eclipseCaseData()->unitsType() != eclipseCase->eclipseCaseData()->unitsType()) + { + unitSystemMismatch = true; + break; + } + } + if (unitSystemMismatch) + { + RiaLogging::error("Well path unit systems must match unit system of chosen eclipse case."); + return; + } + } + + std::map > completionsPerEclipseCell; + + // FractureTransmissibilityExportInformation + std::unique_ptr fractureTransmissibilityExportInformationStream = nullptr; + + QString fractureTransmisibillityExportInformationPath = QDir(exportSettings.folder).filePath("FractureTransmissibilityExportInformation"); + QFile fractureTransmissibilityExportInformationFile(fractureTransmisibillityExportInformationPath); + + RiaPreferences* prefs = RiaApplication::instance()->preferences(); + if (prefs->includeFractureDebugInfoFile()) + { + if (!fractureTransmissibilityExportInformationFile.open(QIODevice::WriteOnly)) + { + RiaLogging::error(QString("Export Completions Data: Could not open the file: %1").arg(fractureTransmisibillityExportInformationPath)); + return; + } + + fractureTransmissibilityExportInformationStream = std::unique_ptr(new QTextStream(&fractureTransmissibilityExportInformationFile)); + } + + size_t maxProgress = + usedWellPaths.size() * 3 + +#ifdef USE_PROTOTYPE_FEATURE_FRACTURES + simWells.size() + +#endif // USE_PROTOTYPE_FEATURE_FRACTURES + (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL ? usedWellPaths.size() : + exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL_AND_COMPLETION_TYPE ? usedWellPaths.size() * 3 : 1) + + simWells.size(); + + caf::ProgressInfo progress(maxProgress, "Export Completions"); + + progress.setProgressDescription("Read Completion Data"); + for (auto wellPath : usedWellPaths) + { + // Generate completion data + + if (exportSettings.includePerforations) + { + std::vector perforationCompletionData = generatePerforationsCompdatValues(wellPath, exportSettings); + appendCompletionData(&completionsPerEclipseCell, perforationCompletionData); + } + progress.incrementProgress(); + + if (exportSettings.includeFishbones) + { + std::vector fishbonesCompletionData = RicFishbonesTransmissibilityCalculationFeatureImp::generateFishboneCompdatValuesUsingAdjustedCellVolume(wellPath, exportSettings); + appendCompletionData(&completionsPerEclipseCell, fishbonesCompletionData); + } + progress.incrementProgress(); + +#ifdef USE_PROTOTYPE_FEATURE_FRACTURES + if (exportSettings.includeFractures()) + { + std::vector fractureCompletionData = RicExportFractureCompletionsImpl::generateCompdatValuesForWellPath(wellPath, exportSettings, fractureTransmissibilityExportInformationStream.get()); + appendCompletionData(&completionsPerEclipseCell, fractureCompletionData); + } +#endif // USE_PROTOTYPE_FEATURE_FRACTURES + progress.incrementProgress(); + } + +#ifdef USE_PROTOTYPE_FEATURE_FRACTURES + for (auto simWell : simWells) + { + std::vector fractureCompletionData = RicExportFractureCompletionsImpl::generateCompdatValuesForSimWell(exportSettings.caseToApply(), + simWell, + fractureTransmissibilityExportInformationStream.get()); + appendCompletionData(&completionsPerEclipseCell, fractureCompletionData); + progress.incrementProgress(); + } +#endif // USE_PROTOTYPE_FEATURE_FRACTURES + + const QString eclipseCaseName = exportSettings.caseToApply->caseUserDescription(); + + progress.setProgressDescription("Write Export Files"); + if (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::UNIFIED_FILE) + { + std::vector completions; + for (auto& data : completionsPerEclipseCell) + { + completions.push_back(combineEclipseCellCompletions(data.second, exportSettings)); + } + + const QString fileName = QString("UnifiedCompletions_%1").arg(eclipseCaseName); + printCompletionsToFiles(exportSettings.folder, fileName, completions, exportSettings.compdatExport); + progress.incrementProgress(); + } + else if (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL) + { + for (auto wellPath : usedWellPaths) + { + std::map > filteredWellCompletions = getCompletionsForWell(completionsPerEclipseCell, wellPath->completions()->wellNameForExport()); + std::vector completions; + for (auto& data : filteredWellCompletions) + { + completions.push_back(combineEclipseCellCompletions(data.second, exportSettings)); + } + std::vector wellCompletions; + for (auto completion : completions) + { + if (completion.wellName() == wellPath->completions()->wellNameForExport()) + { + wellCompletions.push_back(completion); + } + } + + if (wellCompletions.empty()) continue; + + QString fileName = QString("%1_unifiedCompletions_%2").arg(wellPath->name()).arg(eclipseCaseName); + printCompletionsToFiles(exportSettings.folder, fileName, wellCompletions, exportSettings.compdatExport); + progress.incrementProgress(); + } + } + else if (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL_AND_COMPLETION_TYPE) + { + for (auto wellPath : usedWellPaths) + { + std::map > filteredWellCompletions = getCompletionsForWell(completionsPerEclipseCell, wellPath->completions()->wellNameForExport()); + std::vector completions; + for (auto& data : filteredWellCompletions) + { + completions.push_back(combineEclipseCellCompletions(data.second, exportSettings)); + } + { + std::vector fishbonesCompletions = getCompletionsForWellAndCompletionType(completions, wellPath->completions()->wellNameForExport(), RigCompletionData::FISHBONES); + if (!fishbonesCompletions.empty()) + { + QString fileName = QString("%1_Fishbones_%2").arg(wellPath->name()).arg(eclipseCaseName); + printCompletionsToFiles(exportSettings.folder, fileName, fishbonesCompletions, exportSettings.compdatExport); + } + progress.incrementProgress(); + } + { + std::vector perforationCompletions = getCompletionsForWellAndCompletionType(completions, wellPath->completions()->wellNameForExport(), RigCompletionData::PERFORATION); + if (!perforationCompletions.empty()) + { + QString fileName = QString("%1_Perforations_%2").arg(wellPath->name()).arg(eclipseCaseName); + printCompletionsToFiles(exportSettings.folder, fileName, perforationCompletions, exportSettings.compdatExport); + } + progress.incrementProgress(); + } + { + std::vector fractureCompletions = getCompletionsForWellAndCompletionType(completions, wellPath->completions()->wellNameForExport(), RigCompletionData::FRACTURE); + if (!fractureCompletions.empty()) + { + QString fileName = QString("%1_Fractures_%2").arg(wellPath->name()).arg(eclipseCaseName); + printCompletionsToFiles(exportSettings.folder, fileName, fractureCompletions, exportSettings.compdatExport); + } + progress.incrementProgress(); + } + } + } + + // Export sim wells + if (exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL || + exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL_AND_COMPLETION_TYPE) + { + for (auto simWell : simWells) + { + std::map > filteredWellCompletions = getCompletionsForWell(completionsPerEclipseCell, simWell->name()); + std::vector completions; + for (auto& data : filteredWellCompletions) + { + completions.push_back(combineEclipseCellCompletions(data.second, exportSettings)); + } + std::vector wellCompletions; + for (auto completion : completions) + { + if (completion.wellName() == simWell->name()) + { + wellCompletions.push_back(completion); + } + } + + if (wellCompletions.empty()) continue; + + QString fileName = exportSettings.fileSplit == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL ? + QString("%1_unifiedCompletions_%2").arg(simWell->name()).arg(eclipseCaseName) : + QString("%1_Fractures_%2").arg(simWell->name()).arg(eclipseCaseName); + printCompletionsToFiles(exportSettings.folder, fileName, wellCompletions, exportSettings.compdatExport); + progress.incrementProgress(); + } + } + +} + +//================================================================================================== +/// +//================================================================================================== +RigCompletionData RicWellPathExportCompletionDataFeatureImpl::combineEclipseCellCompletions(const std::vector& completions, + const RicExportCompletionDataSettingsUi& settings) +{ + CVF_ASSERT(!completions.empty()); + QString wellName = completions[0].wellName(); + RigCompletionDataGridCell cellIndexIJK = completions[0].completionDataGridCell(); + RigCompletionData::CompletionType completionType = completions[0].completionType(); + + //completion type, skin factor, well bore diameter and cell direction are taken from (first) main bore, + //if no main bore they are taken from first completion + double skinfactor = completions[0].skinFactor(); + double wellBoreDiameter = completions[0].diameter(); + CellDirection cellDirection = completions[0].direction(); + + for (const RigCompletionData& completion : completions) + { + if (completion.isMainBore()) + { + skinfactor = completion.skinFactor(); + wellBoreDiameter = completion.diameter(); + cellDirection = completion.direction(); + break; + } + } + + + RigCompletionData resultCompletion(wellName, cellIndexIJK); + + double totalTrans = 0.0; + + for (const RigCompletionData& completion : completions) + { + resultCompletion.m_metadata.reserve(resultCompletion.m_metadata.size() + completion.m_metadata.size()); + resultCompletion.m_metadata.insert(resultCompletion.m_metadata.end(), completion.m_metadata.begin(), completion.m_metadata.end()); + + if (completion.completionType() != completions[0].completionType()) + { + QString errorMessage = QString("Cannot combine completions of different types in same cell %1").arg(cellIndexIJK.oneBasedLocalCellIndexString()); + RiaLogging::error(errorMessage); + resultCompletion.addMetadata("ERROR", errorMessage); + return resultCompletion; //Returning empty completion, should not be exported + } + + if (completion.wellName() != completions[0].wellName()) + { + QString errorMessage = QString("Cannot combine completions of different types in same cell %1").arg(cellIndexIJK.oneBasedLocalCellIndexString()); + RiaLogging::error(errorMessage); + resultCompletion.addMetadata("ERROR", errorMessage); + return resultCompletion; //Returning empty completion, should not be exported + } + + if (completion.transmissibility() == HUGE_VAL) + { + QString errorMessage = QString("Transmissibility calculation has failed for cell %1").arg(cellIndexIJK.oneBasedLocalCellIndexString()); + RiaLogging::error(errorMessage); + resultCompletion.addMetadata("ERROR", errorMessage); + return resultCompletion; //Returning empty completion, should not be exported + } + + if (settings.excludeMainBoreForFishbones && completionType == RigCompletionData::FISHBONES && completion.isMainBore()) + { + continue; + } + + totalTrans = totalTrans + completion.transmissibility(); + } + + + if (settings.compdatExport == RicExportCompletionDataSettingsUi::TRANSMISSIBILITIES) + { + resultCompletion.setCombinedValuesExplicitTrans(totalTrans, completionType); + } + else if (settings.compdatExport == RicExportCompletionDataSettingsUi::WPIMULT_AND_DEFAULT_CONNECTION_FACTORS) + { + //calculate trans for main bore - but as Eclipse will do it! + double transmissibilityEclipseCalculation = RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityAsEclipseDoes(settings.caseToApply(), + skinfactor, + wellBoreDiameter / 2, + cellIndexIJK.globalCellIndex(), + cellDirection); + + double wpimult = totalTrans / transmissibilityEclipseCalculation; + resultCompletion.setCombinedValuesImplicitTransWPImult(wpimult, cellDirection, skinfactor, wellBoreDiameter, completionType); + } + + return resultCompletion; +} + + + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportCompletionDataFeatureImpl::printCompletionsToFiles(const QString& folderName, + const QString& fileName, + std::vector& completions, + RicExportCompletionDataSettingsUi::CompdatExportType exportType) +{ + // Sort completions based on grid they belong to + std::vector completionsForMainGrid; + + std::map> completionsForSubGrids; + + for (const auto& completion : completions) + { + QString gridName = completion.completionDataGridCell().lgrName(); + if (gridName.isEmpty()) + { + completionsForMainGrid.push_back(completion); + } + else + { + auto it = completionsForSubGrids.find(gridName); + if (it == completionsForSubGrids.end()) + { + completionsForSubGrids.insert(std::pair>(gridName, std::vector{completion})); + } + else + { + it->second.push_back(completion); + } + } + } + + if (!completionsForMainGrid.empty()) + { + std::map> completionsForGrid; + completionsForGrid.insert(std::pair>("", completionsForMainGrid)); + + printCompletionsToFile(folderName, fileName, completionsForGrid, exportType); + } + + if (!completionsForSubGrids.empty()) + { + QString lgrFileName = fileName + "_LGR"; + printCompletionsToFile(folderName, lgrFileName, completionsForSubGrids, exportType); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportCompletionDataFeatureImpl::printCompletionsToFile(const QString& folderName, + const QString& fileName, + const std::map>& completionsPerGrid, + RicExportCompletionDataSettingsUi::CompdatExportType exportType) +{ + if (completionsPerGrid.empty()) return; + + QDir exportFolder(folderName); + + if (!exportFolder.exists()) + { + bool createdPath = exportFolder.mkpath(folderName); + if (createdPath) RiaLogging::info("Created export folder " + folderName); + 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)) + { + RiaLogging::error(QString("Export Completions Data: Could not open the file: %1").arg(filePath)); + return; + } + + QTextStream stream(&exportFile); + RifEclipseDataTableFormatter formatter(stream); + + for (const auto& gridCompletions : completionsPerGrid) + { + std::vector completions = gridCompletions.second; + + // Sort by well name / cell index + std::sort(completions.begin(), completions.end()); + + // Print completion data + QString gridName = gridCompletions.first; + generateCompdatTable(formatter, gridName, completions); + + if (exportType == RicExportCompletionDataSettingsUi::WPIMULT_AND_DEFAULT_CONNECTION_FACTORS) + { + generateWpimultTable(formatter, gridName, completions); + } + } + + RiaLogging::info(QString("Successfully exported completion data to %1").arg(filePath)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RicWellPathExportCompletionDataFeatureImpl::getCompletionsForWellAndCompletionType(const std::vector& completions, + const QString& wellName, + RigCompletionData::CompletionType completionType) +{ + std::vector filteredCompletions; + for (auto completion : completions) + { + if (completion.wellName() == wellName && completion.completionType() == completionType) + { + filteredCompletions.push_back(completion); + } + } + return filteredCompletions; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map > RicWellPathExportCompletionDataFeatureImpl::getCompletionsForWell(const std::map>& cellToCompletionMap, const QString& wellName) +{ + std::map > wellCompletions; + + for (const auto& it : cellToCompletionMap) + { + for (auto& completion : it.second) + { + if (completion.wellName() == wellName) + { + wellCompletions[it.first].push_back(completion); + } + } + } + + return wellCompletions; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportCompletionDataFeatureImpl::generateCompdatTable(RifEclipseDataTableFormatter& formatter, const QString& gridName, const std::vector& completionData) +{ + std::vector header; + + if (gridName.isEmpty()) + { + header = { + RifEclipseOutputTableColumn("Well"), + RifEclipseOutputTableColumn("I"), + RifEclipseOutputTableColumn("J"), + RifEclipseOutputTableColumn("K1"), + RifEclipseOutputTableColumn("K2"), + RifEclipseOutputTableColumn("Status"), + RifEclipseOutputTableColumn("SAT"), + RifEclipseOutputTableColumn("TR", RifEclipseOutputTableDoubleFormatting(RifEclipseOutputTableDoubleFormat::RIF_SCIENTIFIC)), + RifEclipseOutputTableColumn("DIAM"), + RifEclipseOutputTableColumn("KH"), + RifEclipseOutputTableColumn("S"), + RifEclipseOutputTableColumn("Df"), + RifEclipseOutputTableColumn("DIR"), + RifEclipseOutputTableColumn("r0") + }; + + formatter.keyword("COMPDAT"); + } + else + { + header = { + RifEclipseOutputTableColumn("Well"), + RifEclipseOutputTableColumn("LgrName"), + RifEclipseOutputTableColumn("I"), + RifEclipseOutputTableColumn("J"), + RifEclipseOutputTableColumn("K1"), + RifEclipseOutputTableColumn("K2"), + RifEclipseOutputTableColumn("Status"), + RifEclipseOutputTableColumn("SAT"), + RifEclipseOutputTableColumn("TR", RifEclipseOutputTableDoubleFormatting(RifEclipseOutputTableDoubleFormat::RIF_SCIENTIFIC)), + RifEclipseOutputTableColumn("DIAM"), + RifEclipseOutputTableColumn("KH"), + RifEclipseOutputTableColumn("S"), + RifEclipseOutputTableColumn("Df"), + RifEclipseOutputTableColumn("DIR"), + RifEclipseOutputTableColumn("r0") + }; + + formatter.keyword("COMPDATL"); + } + formatter.header(header); + + for (const RigCompletionData& data : completionData) + { + if (data.transmissibility() == 0.0 || data.wpimult()==0.0) + { + //Don't export completions without transmissibility + continue; + } + + for (const RigCompletionMetaData& metadata : data.metadata()) + { + formatter.comment(QString("%1 : %2").arg(metadata.name).arg(metadata.comment)); + } + formatter.add(data.wellName()); + + if (!gridName.isEmpty()) + { + formatter.add(gridName); + } + + formatter.addZeroBasedCellIndex(data.completionDataGridCell().localCellIndexI()).addZeroBasedCellIndex(data.completionDataGridCell().localCellIndexJ()).addZeroBasedCellIndex(data.completionDataGridCell().localCellIndexK()).addZeroBasedCellIndex(data.completionDataGridCell().localCellIndexK()); + switch (data.connectionState()) + { + case OPEN: + formatter.add("OPEN"); + break; + case SHUT: + formatter.add("SHUT"); + break; + case AUTO: + formatter.add("AUTO"); + break; + } + if (RigCompletionData::isDefaultValue(data.saturation())) formatter.add("1*"); else formatter.add(data.saturation()); + if (RigCompletionData::isDefaultValue(data.transmissibility())) + { + formatter.add("1*"); // Transmissibility + + if (RigCompletionData::isDefaultValue(data.diameter())) formatter.add("1*"); else formatter.add(data.diameter()); + if (RigCompletionData::isDefaultValue(data.kh())) formatter.add("1*"); else formatter.add(data.kh()); + if (RigCompletionData::isDefaultValue(data.skinFactor())) formatter.add("1*"); else formatter.add(data.skinFactor()); + if (RigCompletionData::isDefaultValue(data.dFactor())) formatter.add("1*"); else formatter.add(data.dFactor()); + + switch (data.direction()) + { + case DIR_I: + formatter.add("'X'"); + break; + case DIR_J: + formatter.add("'Y'"); + break; + case DIR_K: + formatter.add("'Z'"); + break; + default: + formatter.add("'Z'"); + break; + } + } + else + { + formatter.add(data.transmissibility()); + } + + formatter.rowCompleted(); + } + formatter.tableCompleted(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportCompletionDataFeatureImpl::generateWpimultTable(RifEclipseDataTableFormatter& formatter, + const QString& gridName, + const std::vector& completionData) +{ + std::vector header; + + if (gridName.isEmpty()) + { + header = { + RifEclipseOutputTableColumn("Well"), + RifEclipseOutputTableColumn("Mult"), + RifEclipseOutputTableColumn("I"), + RifEclipseOutputTableColumn("J"), + RifEclipseOutputTableColumn("K"), + }; + formatter.keyword("WPIMULT"); + } + else + { + header = { + RifEclipseOutputTableColumn("Well"), + RifEclipseOutputTableColumn("LgrName"), + RifEclipseOutputTableColumn("Mult"), + RifEclipseOutputTableColumn("I"), + RifEclipseOutputTableColumn("J"), + RifEclipseOutputTableColumn("K"), + }; + formatter.keyword("WPIMULTL"); + } + formatter.header(header); + + for (auto& completion : completionData) + { + if (completion.wpimult() == 0.0 || completion.isDefaultValue(completion.wpimult())) + { + continue; + } + + formatter.add(completion.wellName()); + formatter.add(completion.wpimult()); + + if (!gridName.isEmpty()) + { + formatter.add(gridName); + } + + formatter.addZeroBasedCellIndex(completion.completionDataGridCell().localCellIndexI()).addZeroBasedCellIndex(completion.completionDataGridCell().localCellIndexJ()).addZeroBasedCellIndex(completion.completionDataGridCell().localCellIndexK()); + formatter.rowCompleted(); + } + + formatter.tableCompleted(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RicWellPathExportCompletionDataFeatureImpl::generatePerforationsCompdatValues(const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings) +{ + RiaEclipseUnitTools::UnitSystem unitSystem = settings.caseToApply->eclipseCaseData()->unitsType(); + + std::vector completionData; + const RigActiveCellInfo* activeCellInfo = settings.caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + + if (wellPath->perforationIntervalCollection()->isChecked()) + { + for (const RimPerforationInterval* interval : wellPath->perforationIntervalCollection()->perforations()) + { + if (!interval->isChecked()) continue; + if (!interval->isActiveOnDate(settings.caseToApply->timeStepDates()[settings.timeStep])) continue; + + using namespace std; + pair, vector > perforationPointsAndMD = wellPath->wellPathGeometry()->clippedPointSubset(interval->startMD(), interval->endMD()); + std::vector intersectedCells = RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(settings.caseToApply->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, settings.caseToApply->mainGrid())); + CellDirection direction = calculateDirectionInCell(settings.caseToApply, cell.globCellIndex, cell.intersectionLengthsInCellCS); + + double transmissibility = RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibility(settings.caseToApply, + wellPath, + cell.intersectionLengthsInCellCS, + interval->skinFactor(), + interval->diameter(unitSystem) / 2, + cell.globCellIndex, + settings.useLateralNTG); + + + + completion.setTransAndWPImultBackgroundDataFromPerforation(transmissibility, + interval->skinFactor(), + interval->diameter(unitSystem), + direction); + completion.addMetadata("Perforation", QString("StartMD: %1 - EndMD: %2").arg(interval->startMD()).arg(interval->endMD()) + QString(" : ") + QString::number(transmissibility)); + completionData.push_back(completion); + } + } + } + + return completionData; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RicWellPathExportCompletionDataFeatureImpl::findIntersectedCells(const RigEclipseCaseData* caseData, const std::vector& coords) +{ + std::set cells; + + std::vector intersections = RigWellPathIntersectionTools::findRawHexCellIntersections(caseData->mainGrid(), coords); + for (auto intersection : intersections) + { + cells.insert(intersection.m_hexIndex); + } + + return cells; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicWellPathExportCompletionDataFeatureImpl::wellSegmentLocationOrdering(const WellSegmentLocation& first, const WellSegmentLocation& second) +{ + return first.measuredDepth < second.measuredDepth; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RicWellPathExportCompletionDataFeatureImpl::findWellSegmentLocations(const RimEclipseCase* caseToApply, const RimWellPath* wellPath) +{ + std::vector fishbonesSubs; + + if (wellPath->fishbonesCollection()->isChecked()) + { + for (RimFishbonesMultipleSubs* subs : wellPath->fishbonesCollection()->fishbonesSubs()) + { + if (subs->isActive()) + { + fishbonesSubs.push_back(subs); + } + } + } + + return findWellSegmentLocations(caseToApply, wellPath, fishbonesSubs); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RicWellPathExportCompletionDataFeatureImpl::findWellSegmentLocations(const RimEclipseCase* caseToApply, const RimWellPath* wellPath, const std::vector& fishbonesSubs) +{ + std::vector wellSegmentLocations; + for (RimFishbonesMultipleSubs* subs : fishbonesSubs) + { + for (auto& sub : subs->installedLateralIndices()) + { + double measuredDepth = subs->measuredDepth(sub.subIndex); + cvf::Vec3d position = wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(measuredDepth); + WellSegmentLocation location = WellSegmentLocation(subs, measuredDepth, -position.z(), sub.subIndex); + for (size_t lateralIndex : sub.lateralIndices) + { + location.laterals.push_back(WellSegmentLateral(lateralIndex)); + } + wellSegmentLocations.push_back(location); + } + } + std::sort(wellSegmentLocations.begin(), wellSegmentLocations.end(), wellSegmentLocationOrdering); + + assignLateralIntersectionsAndBranchAndSegmentNumbers(caseToApply, &wellSegmentLocations); + + return wellSegmentLocations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportCompletionDataFeatureImpl::assignLateralIntersections(const RimEclipseCase* caseToApply, + WellSegmentLocation* location, + int* branchNum, + int* segmentNum) +{ + for (WellSegmentLateral& lateral : location->laterals) + { + ++(*branchNum); + lateral.branchNumber = (*branchNum); + + std::vector > lateralCoordMDPairs = location->fishbonesSubs->coordsAndMDForLateral(location->subIndex, lateral.lateralIndex); + + if ( !lateralCoordMDPairs.size() ) + { + 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); + double previousExitMD = lateralMDs.front(); + double previousExitTVD = lateralCoords.front().z(); + + int attachedSegmentNumber = location->icdSegmentNumber; + for (const auto& cellIntInfo: intersections) + { + ++(*segmentNum); + WellSegmentLateralIntersection lateralIntersection((*segmentNum), + attachedSegmentNumber, + cellIntInfo.globCellIndex, + cellIntInfo.endMD - previousExitMD, + cellIntInfo.endPoint.z() - previousExitTVD, + cellIntInfo.intersectionLengthsInCellCS); + + lateral.intersections.push_back(lateralIntersection); + + attachedSegmentNumber = (*segmentNum); + previousExitMD = cellIntInfo.endMD; + previousExitTVD = cellIntInfo.endPoint.z(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportCompletionDataFeatureImpl::assignLateralIntersectionsAndBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, std::vector* locations) +{ + int segmentNumber = 1; + int branchNumber = 1; + + // First loop over the locations so that each segment on the main stem is an incremental number + for (WellSegmentLocation& location : *locations) + { + location.segmentNumber = ++segmentNumber; + location.icdBranchNumber = ++branchNumber; + location.icdSegmentNumber = ++segmentNumber; + } + + // Then assign branch and segment numbers to each lateral parts + for (WellSegmentLocation& location : *locations) + { + assignLateralIntersections(caseToApply, &location, &branchNumber, &segmentNumber); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportCompletionDataFeatureImpl::appendCompletionData(std::map >* completionData, const std::vector& data) +{ + for (auto& completion : data) + { + auto it = completionData->find(completion.completionDataGridCell()); + if (it != completionData->end()) + { + it->second.push_back(completion); + } + else + { + completionData->insert(std::pair >(completion.completionDataGridCell(), std::vector {completion})); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +CellDirection RicWellPathExportCompletionDataFeatureImpl::calculateDirectionInCell(RimEclipseCase* eclipseCase, size_t globalCellIndex, const cvf::Vec3d& lengthsInCell) +{ + RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); + + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); + cvf::ref dxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); + cvf::ref dyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); + cvf::ref dzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); + + double xLengthFraction = fabs(lengthsInCell.x() / dxAccessObject->cellScalarGlobIdx(globalCellIndex)); + double yLengthFraction = fabs(lengthsInCell.y() / dyAccessObject->cellScalarGlobIdx(globalCellIndex)); + double zLengthFraction = fabs(lengthsInCell.z() / dzAccessObject->cellScalarGlobIdx(globalCellIndex)); + + if (xLengthFraction > yLengthFraction && xLengthFraction > zLengthFraction) + { + return CellDirection::DIR_I; + } + else if (yLengthFraction > xLengthFraction && yLengthFraction > zLengthFraction) + { + return CellDirection::DIR_J; + } + else + { + return CellDirection::DIR_K; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibility(RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + const cvf::Vec3d& internalCellLengths, + double skinFactor, + double wellRadius, + size_t globalCellIndex, + bool useLateralNTG, + size_t volumeScaleConstant, + CellDirection directionForVolumeScaling) +{ + RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); + + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); + cvf::ref dxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); + cvf::ref dyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); + cvf::ref dzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); + + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMX"); + cvf::ref permxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMY"); + cvf::ref permyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMY"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMZ"); + cvf::ref permzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMZ"); + + double ntg = 1.0; + size_t ntgResIdx = eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); + if (ntgResIdx != cvf::UNDEFINED_SIZE_T) + { + cvf::ref ntgAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "NTG"); + ntg = ntgAccessObject->cellScalarGlobIdx(globalCellIndex); + } + double latNtg = useLateralNTG ? ntg : 1.0; + + double dx = dxAccessObject->cellScalarGlobIdx(globalCellIndex); + double dy = dyAccessObject->cellScalarGlobIdx(globalCellIndex); + double dz = dzAccessObject->cellScalarGlobIdx(globalCellIndex); + double permx = permxAccessObject->cellScalarGlobIdx(globalCellIndex); + double permy = permyAccessObject->cellScalarGlobIdx(globalCellIndex); + double permz = permzAccessObject->cellScalarGlobIdx(globalCellIndex); + + double darcy = RiaEclipseUnitTools::darcysConstant(wellPath->unitSystem()); + + if (volumeScaleConstant != 1) + { + if (directionForVolumeScaling == CellDirection::DIR_I) dx = dx / volumeScaleConstant; + if (directionForVolumeScaling == CellDirection::DIR_J) dy = dy / volumeScaleConstant; + if (directionForVolumeScaling == CellDirection::DIR_K) dz = dz / volumeScaleConstant; + } + + double transx = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(internalCellLengths.x() * latNtg, permy, permz, dy, dz, wellRadius, skinFactor, darcy); + double transy = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(internalCellLengths.y() * latNtg, permx, permz, dx, dz, wellRadius, skinFactor, darcy); + double transz = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(internalCellLengths.z() * ntg, permy, permx, dy, dx, wellRadius, skinFactor, darcy); + + return RigTransmissibilityEquations::totalConnectionFactor(transx, transy, transz); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityAsEclipseDoes(RimEclipseCase* eclipseCase, + double skinFactor, + double wellRadius, + size_t globalCellIndex, + CellDirection direction) +{ + RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); + + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); + cvf::ref dxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); + cvf::ref dyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); + cvf::ref dzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); + + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMX"); + cvf::ref permxAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMY"); + cvf::ref permyAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMY"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMZ"); + cvf::ref permzAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMZ"); + + double ntg = 1.0; + size_t ntgResIdx = eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); + if (ntgResIdx != cvf::UNDEFINED_SIZE_T) + { + cvf::ref ntgAccessObject = RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "NTG"); + ntg = ntgAccessObject->cellScalarGlobIdx(globalCellIndex); + } + + double dx = dxAccessObject->cellScalarGlobIdx(globalCellIndex); + double dy = dyAccessObject->cellScalarGlobIdx(globalCellIndex); + double dz = dzAccessObject->cellScalarGlobIdx(globalCellIndex); + double permx = permxAccessObject->cellScalarGlobIdx(globalCellIndex); + double permy = permyAccessObject->cellScalarGlobIdx(globalCellIndex); + double permz = permzAccessObject->cellScalarGlobIdx(globalCellIndex); + + RiaEclipseUnitTools::UnitSystem units = eclipseCaseData->unitsType(); + double darcy = RiaEclipseUnitTools::darcysConstant(units); + + double trans = cvf::UNDEFINED_DOUBLE; + if (direction == CellDirection::DIR_I) + { + trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(dx, permy, permz, dy, dz, wellRadius, skinFactor, darcy); + } + else if (direction == CellDirection::DIR_J) + { + trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(dy, permx, permz, dx, dz, wellRadius, skinFactor, darcy); + } + else if (direction == CellDirection::DIR_K) + { + trans = RigTransmissibilityEquations::wellBoreTransmissibilityComponent(dz * ntg, permy, permx, dy, dx, wellRadius, skinFactor, darcy); + } + + return trans; +} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h new file mode 100644 index 0000000000..ed4b6dfb64 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h @@ -0,0 +1,168 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RifEclipseDataTableFormatter.h" + +#include "RigWellLogExtractionTools.h" +#include "RigWellPathIntersectionTools.h" +#include "RigCompletionData.h" + +#include "RicExportCompletionDataSettingsUi.h" + +#include "cafCmdFeature.h" + +#include "cvfBoundingBox.h" + + +class RigCell; +class RigEclipseCaseData; +class RigMainGrid; +class RimEclipseCase; +class RimFishbonesMultipleSubs; +class RimSimWellInView; +class RimWellPath; + + +//================================================================================================== +/// +//================================================================================================== +struct WellSegmentLateralIntersection { + WellSegmentLateralIntersection(int segmentNumber, + int attachedSegmentNumber, + size_t globalCellIndex, + double length, + double depth, + const cvf::Vec3d& lengthsInCell) + : segmentNumber(segmentNumber), + attachedSegmentNumber(attachedSegmentNumber), + globalCellIndex(globalCellIndex), + mdFromPreviousIntersection(length), + tvdChangeFromPreviousIntersection(depth), + lengthsInCell(lengthsInCell), + mainBoreCell(false) + {} + + int segmentNumber; + int attachedSegmentNumber; + size_t globalCellIndex; + bool mainBoreCell; + double mdFromPreviousIntersection; + double tvdChangeFromPreviousIntersection; + cvf::Vec3d lengthsInCell; +}; + +//================================================================================================== +/// +//================================================================================================== +struct WellSegmentLateral { + WellSegmentLateral(size_t lateralIndex) + : lateralIndex(lateralIndex), + branchNumber(0) + {} + + size_t lateralIndex; + int branchNumber; + std::vector intersections; +}; + +//================================================================================================== +/// +//================================================================================================== +struct WellSegmentLocation { + WellSegmentLocation(const RimFishbonesMultipleSubs* subs, double measuredDepth, double trueVerticalDepth, size_t subIndex, int segmentNumber = -1) + : fishbonesSubs(subs), + measuredDepth(measuredDepth), + trueVerticalDepth(trueVerticalDepth), + subIndex(subIndex), + segmentNumber(segmentNumber), + icdBranchNumber(-1), + icdSegmentNumber(-1) + { + } + + const RimFishbonesMultipleSubs* fishbonesSubs; + double measuredDepth; + double trueVerticalDepth; + size_t subIndex; + int segmentNumber; + int icdBranchNumber; + int icdSegmentNumber; + std::vector laterals; +}; + + +//================================================================================================== +/// +//================================================================================================== +class RicWellPathExportCompletionDataFeatureImpl +{ + +public: + static std::vector findWellSegmentLocations(const RimEclipseCase* caseToApply, const RimWellPath* wellPath); + static std::vector findWellSegmentLocations(const RimEclipseCase* caseToApply, const RimWellPath* wellPath, const std::vector& fishbonesSubs); + + // TODO : Move + static std::set findIntersectedCells(const RigEclipseCaseData* grid, const std::vector& coords); + + static CellDirection calculateDirectionInCell(RimEclipseCase* eclipseCase, size_t globalCellIndex, const cvf::Vec3d& lengthsInCell); + + static double calculateTransmissibility(RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + const cvf::Vec3d& internalCellLengths, + double skinFactor, + double wellRadius, + size_t globalCellIndex, + bool useLateralNTG, + size_t volumeScaleConstant = 1, + CellDirection directionForVolumeScaling = CellDirection::DIR_I); + + + static void exportCompletions(const std::vector& wellPaths, const std::vector& simWells, const RicExportCompletionDataSettingsUi& exportSettings); + +private: + static double calculateTransmissibilityAsEclipseDoes(RimEclipseCase* eclipseCase, + double skinFactor, + double wellRadius, + size_t globalCellIndex, + CellDirection direction); + + static RigCompletionData combineEclipseCellCompletions(const std::vector& completions, + const RicExportCompletionDataSettingsUi& settings); + + static void printCompletionsToFiles(const QString& exportFolder, const QString& fileName, std::vector& completions, RicExportCompletionDataSettingsUi::CompdatExportType exportType); + + static void printCompletionsToFile(const QString& folderName, const QString& fileName, const std::map>& completionsPerGrid, RicExportCompletionDataSettingsUi::CompdatExportType exportType); + + static std::vector getCompletionsForWellAndCompletionType(const std::vector& completions, const QString& wellName, RigCompletionData::CompletionType completionType); + + static std::map > getCompletionsForWell(const std::map>& cellToCompletionMap, const QString& wellName); + + static void generateCompdatTable(RifEclipseDataTableFormatter& formatter, const QString& gridName, const std::vector& completionData); + static void generateWpimultTable(RifEclipseDataTableFormatter& formatter, const QString& gridName, const std::vector& completionData); + + static std::vector generatePerforationsCompdatValues(const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings); + + static bool wellSegmentLocationOrdering(const WellSegmentLocation& first, const WellSegmentLocation& second); + static void assignLateralIntersections(const RimEclipseCase* caseToApply, WellSegmentLocation* location, int* branchNum, int* segmentNum); + static void assignLateralIntersectionsAndBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, std::vector* locations); + + static void appendCompletionData(std::map >* completionData, const std::vector& data); +}; +