///////////////////////////////////////////////////////////////////////////////// // // 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 "RicFishbonesTransmissibilityCalculationFeatureImp.h" #include "RicExportCompletionDataSettingsUi.h" #include "RicWellPathExportCompletionDataFeatureImpl.h" #include "RigActiveCellInfo.h" #include "RigCompletionData.h" #include "RigEclipseCaseData.h" #include "RigMainGrid.h" #include "RigWellPath.h" #include "RimFishboneWellPath.h" #include "RimFishboneWellPathCollection.h" #include "RimFishbonesCollection.h" #include "RimFishbonesMultipleSubs.h" #include "RimWellPath.h" #include "RimWellPathCompletions.h" #include "RigWellLogExtractor.h" //================================================================================================== /// //================================================================================================== struct WellBorePartForTransCalc { WellBorePartForTransCalc(cvf::Vec3d lengthsInCell, double wellRadius, double skinFactor, bool isMainBore, QString metaData) : lengthsInCell(lengthsInCell), wellRadius(wellRadius), skinFactor(skinFactor), isMainBore(isMainBore), metaData(metaData) { } cvf::Vec3d lengthsInCell; double wellRadius; double skinFactor; QString metaData; bool isMainBore; }; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicFishbonesTransmissibilityCalculationFeatureImp::findFishboneLateralsWellBoreParts(std::map >& wellBorePartsInCells, const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings) { // Generate data const RigEclipseCaseData* caseData = settings.caseToApply()->eclipseCaseData(); std::vector locations = RicWellPathExportCompletionDataFeatureImpl::findWellSegmentLocations(settings.caseToApply, wellPath); RiaEclipseUnitTools::UnitSystem unitSystem = caseData->unitsType(); bool isMainBore = false; for (const WellSegmentLocation& location : locations) { for (const WellSegmentLateral& lateral : location.laterals) { for (const WellSegmentLateralIntersection& intersection : lateral.intersections) { double diameter = location.fishbonesSubs->holeDiameter(unitSystem); QString completionMetaData = (location.fishbonesSubs->generatedName() + QString(": Sub: %1 Lateral: %2").arg(location.subIndex).arg(lateral.lateralIndex)); WellBorePartForTransCalc wellBorePart = WellBorePartForTransCalc(intersection.lengthsInCell, diameter / 2, location.fishbonesSubs->skinFactor(), isMainBore, completionMetaData); wellBorePartsInCells[intersection.globalCellIndex].push_back(wellBorePart); } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicFishbonesTransmissibilityCalculationFeatureImp::generateFishboneCompdatValuesUsingAdjustedCellVolume(const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings) { std::map > wellBorePartsInCells; //wellBore = main bore or fishbone lateral findFishboneLateralsWellBoreParts(wellBorePartsInCells, wellPath, settings); findFishboneImportedLateralsWellBoreParts(wellBorePartsInCells, wellPath, settings); if (!wellBorePartsInCells.empty()) { findMainWellBoreParts(wellBorePartsInCells, wellPath, settings); } std::vector completionData; const RigActiveCellInfo* activeCellInfo = settings.caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); for (const auto& cellAndWellBoreParts : wellBorePartsInCells) { size_t globalCellIndex = cellAndWellBoreParts.first; const std::vector& wellBoreParts = cellAndWellBoreParts.second; bool cellIsActive = activeCellInfo->isActive(globalCellIndex); if (!cellIsActive) continue; // Find main bore and number of laterals size_t numberOfLaterals = 0; CellDirection mainBoreDirection = DIR_I; for (const auto& wellBorePart : wellBoreParts) { if (!wellBorePart.isMainBore) { numberOfLaterals++; } else { mainBoreDirection = RicWellPathExportCompletionDataFeatureImpl::calculateDirectionInCell(settings.caseToApply, globalCellIndex, wellBorePart.lengthsInCell); } } for (WellBorePartForTransCalc wellBorePart : wellBoreParts) { RigCompletionData completion(wellPath->completions()->wellNameForExport(), RigCompletionDataGridCell(globalCellIndex, settings.caseToApply->mainGrid())); double transmissibility = 0.0; if (wellBorePart.isMainBore) { //No change in transmissibility for main bore transmissibility = RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibility(settings.caseToApply, wellPath, wellBorePart.lengthsInCell, wellBorePart.skinFactor, wellBorePart.wellRadius, globalCellIndex, settings.useLateralNTG); } else { //Adjust transmissibility for fishbone laterals transmissibility = RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibility(settings.caseToApply, wellPath, wellBorePart.lengthsInCell, wellBorePart.skinFactor, wellBorePart.wellRadius, globalCellIndex, settings.useLateralNTG, numberOfLaterals, mainBoreDirection); } CellDirection direction = RicWellPathExportCompletionDataFeatureImpl::calculateDirectionInCell(settings.caseToApply, globalCellIndex, wellBorePart.lengthsInCell); completion.setTransAndWPImultBackgroundDataFromFishbone(transmissibility, wellBorePart.skinFactor, wellBorePart.wellRadius *2, direction, wellBorePart.isMainBore); completion.addMetadata(wellBorePart.metaData, QString::number(transmissibility)); completionData.push_back(completion); } } return completionData; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicFishbonesTransmissibilityCalculationFeatureImp::findFishboneImportedLateralsWellBoreParts(std::map >& wellBorePartsInCells, const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings) { RiaEclipseUnitTools::UnitSystem unitSystem = settings.caseToApply->eclipseCaseData()->unitsType(); std::set wellPathCells = RicWellPathExportCompletionDataFeatureImpl::findIntersectedCells(settings.caseToApply()->eclipseCaseData(), wellPath->wellPathGeometry()->m_wellPathPoints); bool isMainBore = false; double diameter = wellPath->fishbonesCollection()->wellPathCollection()->holeDiameter(unitSystem); for (const RimFishboneWellPath* fishbonesPath : wellPath->fishbonesCollection()->wellPathCollection()->wellPaths()) { std::vector intersectedCells = RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(settings.caseToApply->eclipseCaseData(), fishbonesPath->coordinates(), fishbonesPath->measuredDepths()); for (auto& cell : intersectedCells) { if (wellPathCells.count(cell.globCellIndex) ) continue; double skinFactor = wellPath->fishbonesCollection()->wellPathCollection()->skinFactor(); QString completionMetaData = fishbonesPath->name(); WellBorePartForTransCalc wellBorePart = WellBorePartForTransCalc(cell.intersectionLengthsInCellCS, diameter / 2, skinFactor, isMainBore, completionMetaData); wellBorePartsInCells[cell.globCellIndex].push_back(wellBorePart); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicFishbonesTransmissibilityCalculationFeatureImp::findMainWellBoreParts(std::map>& wellBorePartsInCells, const RimWellPath* wellPath, const RicExportCompletionDataSettingsUi& settings) { RiaEclipseUnitTools::UnitSystem unitSystem = settings.caseToApply->eclipseCaseData()->unitsType(); bool isMainBore = true; double holeDiameter = wellPath->fishbonesCollection()->mainBoreDiameter(unitSystem); std::vector wellPathMD = wellPath->wellPathGeometry()->m_measuredDepths; double wellPathEndMD = 0.0; if (wellPathMD.size() > 1) wellPathEndMD = wellPathMD.back(); std::pair< std::vector, std::vector > fishbonePerfWellPathCoords = wellPath->wellPathGeometry()->clippedPointSubset(wellPath->fishbonesCollection()->startMD(), wellPathEndMD); std::vector intersectedCellsIntersectionInfo = RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(settings.caseToApply->eclipseCaseData(), fishbonePerfWellPathCoords.first, fishbonePerfWellPathCoords.second); for (auto& cell : intersectedCellsIntersectionInfo) { double skinFactor = wellPath->fishbonesCollection()->mainBoreSkinFactor(); QString completionMetaData = wellPath->name() + " main bore"; WellBorePartForTransCalc wellBorePart = WellBorePartForTransCalc(cell.intersectionLengthsInCellCS, holeDiameter / 2, skinFactor, isMainBore, completionMetaData); wellBorePartsInCells[cell.globCellIndex].push_back(wellBorePart); } }