///////////////////////////////////////////////////////////////////////////////// // // 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 "RicExportLgrFeature.h" #include "RiaApplication.h" #include "RiaLogging.h" #include "CompletionExportCommands/RicWellPathExportCompletionDataFeature.h" #include "RicExportLgrUi.h" #include "RifTextDataTableFormatter.h" #include "RigCaseCellResultsData.h" #include "RigMainGrid.h" #include "RigResultAccessor.h" #include "RigResultAccessorFactory.h" #include "RigVirtualPerforationTransmissibilities.h" #include "RigWellLogExtractor.h" #include "RigWellPath.h" #include "RigWellPathIntersectionTools.h" #include "RimDialogData.h" #include "RimEclipseCase.h" #include "RimEclipseView.h" #include "RimFishbonesCollection.h" #include "RimPerforationCollection.h" #include "RimProject.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" #include "RimWellPathCompletions.h" #include "RimWellPathFractureCollection.h" #include "RiuPlotMainWindow.h" #include "RimFishbones.h" #include "RimPerforationInterval.h" #include "RimWellPathFracture.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CAF_CMD_SOURCE_INIT( RicExportLgrFeature, "RicExportLgrFeature" ); //-------------------------------------------------------------------------------------------------- // //-------------------------------------------------------------------------------------------------- #define DOUBLE_INF std::numeric_limits::infinity() //-------------------------------------------------------------------------------------------------- /// Internal class //-------------------------------------------------------------------------------------------------- class CellInfo { public: CellInfo( size_t globCellIndex ) : globCellIndex( globCellIndex ) , startMd( DOUBLE_INF ) , endMd( DOUBLE_INF ) { } CellInfo( size_t globCellIndex, double startMd, double endMd ) : globCellIndex( globCellIndex ) , startMd( startMd ) , endMd( endMd ) { } size_t globCellIndex; double startMd; double endMd; bool operator<( const CellInfo& other ) const { return startMd < other.startMd; } }; //-------------------------------------------------------------------------------------------------- /// Internal class //-------------------------------------------------------------------------------------------------- class LgrNameFactory { public: LgrNameFactory(); QString newName( RigCompletionData::CompletionType completionType ); QString newName( const QString& baseName, int number ); private: std::map> m_counters; }; //-------------------------------------------------------------------------------------------------- /// Internal class //-------------------------------------------------------------------------------------------------- class IjkBoundingBox { const size_t MAX_SIZE_T = std::numeric_limits::max(); enum Index { I, J, K }; public: IjkBoundingBox() : m_min( { MAX_SIZE_T, MAX_SIZE_T, MAX_SIZE_T } ) , m_max( { MAX_SIZE_T, MAX_SIZE_T, MAX_SIZE_T } ) { } IjkBoundingBox( const IjkBoundingBox& other ) : m_min( other.m_min ) , m_max( other.m_max ) { } IjkBoundingBox( const caf::VecIjk& minCell, const caf::VecIjk& maxCell ) { m_min[I] = minCell.i(); m_min[J] = minCell.j(); m_min[K] = minCell.k(); m_max[I] = maxCell.i(); m_max[J] = maxCell.j(); m_max[K] = maxCell.k(); } IjkBoundingBox& operator=( const IjkBoundingBox& other ) { m_min = other.m_min; m_max = other.m_max; return *this; } bool isValid() const { return m_min[I] != MAX_SIZE_T && m_min[J] != MAX_SIZE_T && m_min[K] != MAX_SIZE_T && m_max[I] != MAX_SIZE_T && m_max[J] != MAX_SIZE_T && m_max[K] != MAX_SIZE_T; } void addCell( size_t i, size_t j, size_t k ) { if ( !isValid() ) { m_min = m_max = { i, j, k }; } else { if ( i < m_min[I] ) m_min[I] = i; if ( j < m_min[J] ) m_min[J] = j; if ( k < m_min[K] ) m_min[K] = k; if ( i > m_max[I] ) m_max[I] = i; if ( j > m_max[J] ) m_max[J] = j; if ( k > m_max[K] ) m_max[K] = k; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool intersects( const IjkBoundingBox& box ) const { CVF_TIGHT_ASSERT( isValid() ); CVF_TIGHT_ASSERT( box.isValid() ); if ( m_max[I] < box.m_min[I] || m_min[I] > box.m_max[I] ) return false; if ( m_max[J] < box.m_min[J] || m_min[J] > box.m_max[J] ) return false; if ( m_max[K] < box.m_min[K] || m_min[K] > box.m_max[K] ) return false; return true; } caf::VecIjk min() const { return caf::VecIjk( m_min[I], m_min[J], m_min[K] ); } caf::VecIjk max() const { return caf::VecIjk( m_max[I], m_max[J], m_max[K] ); } private: std::array m_min; std::array m_max; }; //-------------------------------------------------------------------------------------------------- // Internal function //-------------------------------------------------------------------------------------------------- // int completionPriority(const RigCompletionData& completion) //{ // return completion.completionType() == RigCompletionData::FRACTURE ? 1 : // completion.completionType() == RigCompletionData::FISHBONES ? 2 : // completion.completionType() == RigCompletionData::PERFORATION ? 3 : 4; //} //-------------------------------------------------------------------------------------------------- // Internal function //-------------------------------------------------------------------------------------------------- std::vector filterCompletionsOnType( const std::vector& completions, const std::set& includedCompletionTypes ) { std::vector filtered; for ( const auto& completion : completions ) { if ( includedCompletionTypes.count( completion.completionType() ) > 0 ) filtered.push_back( completion ); } return filtered; } //-------------------------------------------------------------------------------------------------- // Internal function //-------------------------------------------------------------------------------------------------- QString completionName( const caf::PdmObject* object ) { auto perf = dynamic_cast( object ); auto frac = dynamic_cast( object ); auto fish = dynamic_cast( object ); QString name; if ( perf ) name = perf->name(); else if ( frac ) name = frac->name(); else if ( fish ) name = fish->generatedName(); return name; } //-------------------------------------------------------------------------------------------------- /// Internal function /// Returns the completion having highest priority. /// Pri: 1. Fractures, 2. Fishbones, 3. Perforation intervals //-------------------------------------------------------------------------------------------------- // RigCompletionData findCompletionByPriority(const std::vector& completions) //{ // std::vector sorted = completions; // // std::sort(sorted.begin(), sorted.end(), // [](const RigCompletionData& c1, const RigCompletionData& c2 ) // { // if (completionPriority(c1) == completionPriority(c2)) // { // return completionName(c1.sourcePdmObject()) < completionName(c2.sourcePdmObject()); // } // return completionPriority(c1) < completionPriority(c2); // }); // return sorted.front(); //} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RicExportLgrUi* RicExportLgrFeature::openDialog( const QString& dialogTitle, RimEclipseCase* defaultCase, int defaultTimeStep, bool hideExportFolderField ) { RiaApplication* app = RiaApplication::instance(); RimProject* proj = app->project(); QString startPath = app->lastUsedDialogDirectory( "LGR_EXPORT_DIR" ); if ( startPath.isEmpty() ) { QFileInfo fi( proj->fileName() ); startPath = fi.absolutePath(); } RicExportLgrUi* featureUi = app->project()->dialogData()->exportLgrData(); if ( featureUi->exportFolder().isEmpty() ) { featureUi->setExportFolder( startPath ); } if ( !featureUi->caseToApply() && !defaultCase ) { std::vector cases; app->project()->allCases( cases ); for ( auto c : cases ) { RimEclipseCase* eclipseCase = dynamic_cast( c ); if ( eclipseCase != nullptr ) { featureUi->setCase( eclipseCase ); break; } } } if ( defaultCase ) featureUi->setCase( defaultCase ); featureUi->setTimeStep( defaultTimeStep ); featureUi->hideExportFolderField( hideExportFolderField ); caf::PdmUiPropertyViewDialog propertyDialog( nullptr, featureUi, dialogTitle, "", QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); propertyDialog.resize( QSize( 300, 320 ) ); if ( propertyDialog.exec() == QDialog::Accepted && !featureUi->exportFolder().isEmpty() ) { app->setLastUsedDialogDirectory( "LGR_EXPORT_DIR", featureUi->exportFolder() ); return featureUi; } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RicExportLgrFeature::openFileForExport( const QString& folderName, const QString& fileName, QFile* exportFile ) { QDir exportFolder = QDir( folderName ); if ( !exportFolder.exists() ) { bool createdPath = exportFolder.mkpath( "." ); if ( createdPath ) RiaLogging::info( "Created export folder " + folderName ); } QString filePath = exportFolder.filePath( fileName ); exportFile->setFileName( filePath ); if ( !exportFile->open( QIODevice::WriteOnly | QIODevice::Text ) ) { auto errorMessage = QString( "Export Well Path: Could not open the file: %1" ).arg( filePath ); RiaLogging::error( errorMessage ); return false; } return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportLgrFeature::writeLgrs( QTextStream& stream, const std::vector& lgrInfos ) { for ( auto lgrInfo : lgrInfos ) { { RifTextDataTableFormatter formatter( stream ); formatter.comment( QString( "LGR: " ) + lgrInfo.name ); formatter.keyword( "CARFIN" ); formatter.header( { RifTextDataTableColumn( "Name" ), RifTextDataTableColumn( "I1" ), RifTextDataTableColumn( "I2" ), RifTextDataTableColumn( "J1" ), RifTextDataTableColumn( "J2" ), RifTextDataTableColumn( "K1" ), RifTextDataTableColumn( "K2" ), RifTextDataTableColumn( "NX" ), RifTextDataTableColumn( "NY" ), RifTextDataTableColumn( "NZ" ) } ); formatter.add( lgrInfo.name ); formatter.addOneBasedCellIndex( lgrInfo.mainGridStartCell.i() ); formatter.addOneBasedCellIndex( lgrInfo.mainGridEndCell.i() ); formatter.addOneBasedCellIndex( lgrInfo.mainGridStartCell.j() ); formatter.addOneBasedCellIndex( lgrInfo.mainGridEndCell.j() ); formatter.addOneBasedCellIndex( lgrInfo.mainGridStartCell.k() ); formatter.addOneBasedCellIndex( lgrInfo.mainGridEndCell.k() ); formatter.add( lgrInfo.sizes.i() ); formatter.add( lgrInfo.sizes.j() ); formatter.add( lgrInfo.sizes.k() ); formatter.rowCompleted(); formatter.tableCompleted( "", false ); } { RifTextDataTableFormatter formatter( stream ); formatter.keyword( "ENDFIN" ); formatter.tableCompleted( "", true ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportLgrFeature::exportLgrsForWellPaths( const QString& exportFolder, std::vector wellPaths, RimEclipseCase* eclipseCase, size_t timeStep, caf::VecIjk lgrCellCounts, Lgr::SplitType splitType, const std::set& completionTypes, QStringList* wellsIntersectingOtherLgrs ) { std::vector lgrs; lgrs = buildLgrsForWellPaths( wellPaths, eclipseCase, timeStep, lgrCellCounts, splitType, completionTypes, wellsIntersectingOtherLgrs ); for ( const auto& wellPath : wellPaths ) { std::vector expLgrs; for ( const auto& lgr : lgrs ) { if ( lgr.associatedWellPathName == wellPath->name() ) expLgrs.push_back( lgr ); } if ( !lgrs.empty() ) { exportLgrs( exportFolder, wellPath->name(), expLgrs ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportLgrFeature::exportLgrs( const QString& exportFolder, const QString& wellName, const std::vector& lgrInfos ) { if ( !lgrInfos.empty() ) { // Export QFile file; QString fileName = caf::Utils::makeValidFileBasename( QString( "LGR_%1" ).arg( wellName ) ) + ".dat"; openFileForExport( exportFolder, fileName, &file ); QTextStream stream( &file ); stream.setRealNumberNotation( QTextStream::FixedNotation ); stream.setRealNumberPrecision( 2 ); writeLgrs( stream, lgrInfos ); file.close(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportLgrFeature::buildLgrsForWellPaths( std::vector wellPaths, RimEclipseCase* eclipseCase, size_t timeStep, caf::VecIjk lgrCellCounts, Lgr::SplitType splitType, const std::set& completionTypes, QStringList* wellsIntersectingOtherLgrs ) { std::vector lgrs; LgrNameFactory lgrNameFactory; wellsIntersectingOtherLgrs->clear(); bool isIntersectingOtherLgrs = false; int firstLgrId = firstAvailableLgrId( eclipseCase->mainGrid() ); if ( splitType == Lgr::LGR_PER_CELL ) { for ( const auto& wellPath : wellPaths ) { auto intersectingCells = cellsIntersectingCompletions( eclipseCase, wellPath, timeStep, completionTypes, &isIntersectingOtherLgrs ); if ( intersectingCells.empty() ) { // Find all grid cells intersected by well path intersectingCells = allIntersectedCells( eclipseCase, wellPath ); } auto newLgrs = buildLgrsPerMainCell( firstLgrId + (int)lgrs.size(), eclipseCase, wellPath, intersectingCells, lgrCellCounts, lgrNameFactory ); lgrs.insert( lgrs.end(), newLgrs.begin(), newLgrs.end() ); if ( isIntersectingOtherLgrs ) wellsIntersectingOtherLgrs->push_back( wellPath->name() ); } } else if ( splitType == Lgr::LGR_PER_COMPLETION ) { auto intersectingCells = cellsIntersectingCompletions_PerCompletion( eclipseCase, wellPaths, timeStep, completionTypes, wellsIntersectingOtherLgrs ); if ( !intersectingCells.empty() ) { auto newLgrs = buildLgrsPerCompletion( firstLgrId + (int)lgrs.size(), eclipseCase, intersectingCells, lgrCellCounts, lgrNameFactory ); lgrs.insert( lgrs.end(), newLgrs.begin(), newLgrs.end() ); } } else if ( splitType == Lgr::LGR_PER_WELL ) { for ( const auto& wellPath : wellPaths ) { int lgrId = firstLgrId + (int)lgrs.size(); auto lgrName = lgrNameFactory.newName( "WELL", lgrId ); auto intersectingCells = cellsIntersectingCompletions( eclipseCase, wellPath, timeStep, completionTypes, &isIntersectingOtherLgrs ); if ( intersectingCells.empty() ) { // Find all grid cells intersected by well path intersectingCells = allIntersectedCells( eclipseCase, wellPath ); } if ( !intersectingCells.empty() ) { lgrs.push_back( buildLgr( lgrId, lgrName, eclipseCase, wellPath->name(), intersectingCells, lgrCellCounts ) ); } if ( isIntersectingOtherLgrs ) wellsIntersectingOtherLgrs->push_back( wellPath->name() ); } } return lgrs; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportLgrFeature::buildLgrsPerMainCell( int firstLgrId, RimEclipseCase* eclipseCase, RimWellPath* wellPath, const std::vector& intersectingCells, const caf::VecIjk& lgrSizes, LgrNameFactory& lgrNameFactory ) { std::vector lgrs; int lgrId = firstLgrId; for ( const auto& intersectionCell : intersectingCells ) { auto lgrName = lgrNameFactory.newName( "", lgrId ); lgrs.push_back( buildLgr( lgrId++, lgrName, eclipseCase, wellPath->name(), { intersectionCell }, lgrSizes ) ); } return lgrs; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportLgrFeature::buildLgrsPerCompletion( int firstLgrId, RimEclipseCase* eclipseCase, const std::map>& completionInfo, const caf::VecIjk& lgrSizesPerMainGridCell, LgrNameFactory& lgrNameFactory ) { std::vector lgrs; std::vector> occupiedBbs; for ( const auto& complInfo : completionInfo ) { auto complCells = std::set( complInfo.second.begin(), complInfo.second.end() ); std::vector cellsUsedInBb; while ( !complCells.empty() ) { IjkBoundingBox maxBb; for ( const auto& cell : complCells ) { auto candidateBb = maxBb; candidateBb.addCell( cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK() ); // Test bounding box bool intersectsExistingBb = false; for ( const auto& bb : occupiedBbs ) { if ( candidateBb.intersects( bb.second ) ) { intersectsExistingBb = true; break; } } if ( !intersectsExistingBb ) { maxBb = candidateBb; cellsUsedInBb.push_back( cell ); } } // If bounding box is invalid, all cells are already occupied if ( !maxBb.isValid() ) break; occupiedBbs.emplace_back( complInfo.first, maxBb ); // Remove cells used in bounding box for ( const auto& cell : cellsUsedInBb ) complCells.erase( cell ); } } int lgrId = firstLgrId; for ( auto complInfo : occupiedBbs ) { auto lgrName = lgrNameFactory.newName( complInfo.first.type ); lgrs.push_back( buildLgr( lgrId++, lgrName, eclipseCase, complInfo.first.wellPathName, complInfo.second, lgrSizesPerMainGridCell ) ); } return lgrs; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- LgrInfo RicExportLgrFeature::buildLgr( int lgrId, const QString& lgrName, RimEclipseCase* eclipseCase, const QString& wellPathName, const std::vector& intersectingCells, const caf::VecIjk& lgrSizesPerMainGridCell ) { // Find min and max IJK auto iRange = initRange(); auto jRange = initRange(); auto kRange = initRange(); for ( const auto& cell : intersectingCells ) { iRange.first = std::min( cell.localCellIndexI(), iRange.first ); iRange.second = std::max( cell.localCellIndexI(), iRange.second ); jRange.first = std::min( cell.localCellIndexJ(), jRange.first ); jRange.second = std::max( cell.localCellIndexJ(), jRange.second ); kRange.first = std::min( cell.localCellIndexK(), kRange.first ); kRange.second = std::max( cell.localCellIndexK(), kRange.second ); } caf::VecIjk mainGridStartCell( iRange.first, jRange.first, kRange.first ); caf::VecIjk mainGridEndCell( iRange.second, jRange.second, kRange.second ); IjkBoundingBox boundingBox( mainGridStartCell, mainGridEndCell ); return buildLgr( lgrId, lgrName, eclipseCase, wellPathName, boundingBox, lgrSizesPerMainGridCell ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- LgrInfo RicExportLgrFeature::buildLgr( int lgrId, const QString& lgrName, RimEclipseCase* eclipseCase, const QString& wellPathName, const IjkBoundingBox& boundingBox, const caf::VecIjk& lgrSizesPerMainGridCell ) { caf::VecIjk lgrSizes( ( boundingBox.max().i() - boundingBox.min().i() + 1 ) * lgrSizesPerMainGridCell.i(), ( boundingBox.max().j() - boundingBox.min().j() + 1 ) * lgrSizesPerMainGridCell.j(), ( boundingBox.max().k() - boundingBox.min().k() + 1 ) * lgrSizesPerMainGridCell.k() ); return LgrInfo( lgrId, lgrName, wellPathName, lgrSizes, boundingBox.min(), boundingBox.max() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportLgrFeature::cellsIntersectingCompletions( RimEclipseCase* eclipseCase, const RimWellPath* wellPath, size_t timeStep, const std::set& completionTypes, bool* isIntersectingOtherLgrs ) { std::vector cells; const RigMainGrid* mainGrid = eclipseCase->mainGrid(); *isIntersectingOtherLgrs = false; auto completions = eclipseCase->computeAndGetVirtualPerforationTransmissibilities(); if ( completions ) { auto intCells = completions->multipleCompletionsPerEclipseCell( wellPath, timeStep ); for ( auto intCell : intCells ) { const RigGridBase* grid = hostGrid( mainGrid, intCell.first ); if ( grid != mainGrid ) { *isIntersectingOtherLgrs = true; continue; } auto filteredCompletions = filterCompletionsOnType( intCell.second, completionTypes ); if ( filteredCompletions.empty() ) continue; cells.push_back( RigCompletionDataGridCell( intCell.first, mainGrid ) ); } } return cells; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map> RicExportLgrFeature::cellsIntersectingCompletions_PerCompletion( RimEclipseCase* eclipseCase, const std::vector& wellPaths, size_t timeStep, const std::set& completionTypes, QStringList* wellsIntersectingOtherLgrs ) { const RigMainGrid* mainGrid = eclipseCase->mainGrid(); std::map> completionToCells; wellsIntersectingOtherLgrs->clear(); auto completions = eclipseCase->computeAndGetVirtualPerforationTransmissibilities(); if ( !completions ) return completionToCells; for ( const auto& wellPath : wellPaths ) { bool isIntersectingOtherLgrs = false; const auto& intCells = completions->multipleCompletionsPerEclipseCell( wellPath, timeStep ); for ( const auto& intCell : intCells ) { const RigGridBase* grid = hostGrid( mainGrid, intCell.first ); if ( grid != mainGrid ) { isIntersectingOtherLgrs = true; continue; } for ( const auto& completion : intCell.second ) { auto complName = completionName( completion.sourcePdmObject() ); CompletionInfo ci( completion.completionType(), complName, completion.wellName() ); auto& item = completionToCells[ci]; item.push_back( RigCompletionDataGridCell( intCell.first, mainGrid ) ); } } if ( isIntersectingOtherLgrs ) wellsIntersectingOtherLgrs->push_back( wellPath->name() ); } return completionToCells; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportLgrFeature::allIntersectedCells( RimEclipseCase* eclipseCase, const RimWellPath* wellPath ) { std::vector cells; const RigMainGrid* mainGrid = eclipseCase->mainGrid(); auto globalCellIndices = RigWellPathIntersectionTools::findIntersectedGlobalCellIndices( eclipseCase->eclipseCaseData(), wellPath->wellPathGeometry()->wellPathPoints() ); for ( const auto& globalCellIndex : globalCellIndices ) { cells.push_back( RigCompletionDataGridCell( globalCellIndex, mainGrid ) ); } return cells; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RicExportLgrFeature::isCommandEnabled() { std::vector completions = caf::selectedObjectsByTypeStrict(); std::vector wellPaths = caf::selectedObjectsByTypeStrict(); return !completions.empty() || !wellPaths.empty(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportLgrFeature::onActionTriggered( bool isChecked ) { std::vector wellPaths = selectedWellPaths(); if ( wellPaths.empty() ) return; QString dialogTitle = "Export LGR for Completions"; RimEclipseCase* defaultEclipseCase = nullptr; int defaultTimeStep = 0; auto activeView = dynamic_cast( RiaApplication::instance()->activeGridView() ); if ( activeView ) { defaultEclipseCase = activeView->eclipseCase(); defaultTimeStep = activeView->currentTimeStep(); } auto dialogData = openDialog( dialogTitle, defaultEclipseCase, defaultTimeStep ); if ( dialogData ) { auto eclipseCase = dialogData->caseToApply(); auto lgrCellCounts = dialogData->lgrCellCount(); size_t timeStep = dialogData->timeStep(); QStringList wellsIntersectingOtherLgrs; exportLgrsForWellPaths( dialogData->exportFolder(), wellPaths, eclipseCase, timeStep, lgrCellCounts, dialogData->splitType(), dialogData->completionTypes(), &wellsIntersectingOtherLgrs ); if ( !wellsIntersectingOtherLgrs.empty() ) { auto wellsList = wellsIntersectingOtherLgrs.join( ", " ); RiaLogging::errorInMessageBox( nullptr, "LGR cells intersected", "No export for some wells due to existing intersecting LGR(s). Affected " "wells: " + wellsList ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportLgrFeature::setupActionLook( QAction* actionToSetup ) { actionToSetup->setText( "Export LGR for completions" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportLgrFeature::selectedWellPaths() { std::vector selectedCompletions = caf::selectedObjectsByTypeStrict(); std::vector wellPaths = caf::selectedObjectsByTypeStrict(); for ( auto completion : selectedCompletions ) { RimWellPath* parentWellPath; completion->firstAncestorOrThisOfType( parentWellPath ); if ( parentWellPath ) wellPaths.push_back( parentWellPath ); } return wellPaths; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::pair mainGridCellBoundingBoxFromLgr( const RigGridBase* lgr ) { auto mainGrid = lgr->mainGrid(); // Find min and max IJK auto iRange = RicExportLgrFeature::initRange(); auto jRange = RicExportLgrFeature::initRange(); auto kRange = RicExportLgrFeature::initRange(); for ( size_t c = 0; c < lgr->cellCount(); c++ ) { const auto& cell = lgr->cell( c ); size_t mainGridCellIndex = cell.mainGridCellIndex(); size_t i, j, k; mainGrid->ijkFromCellIndex( mainGridCellIndex, &i, &j, &k ); iRange.first = std::min( i, iRange.first ); iRange.second = std::max( i, iRange.second ); jRange.first = std::min( j, jRange.first ); jRange.second = std::max( j, jRange.second ); kRange.first = std::min( k, kRange.first ); kRange.second = std::max( k, kRange.second ); } caf::VecIjk mainGridStartCell( iRange.first, jRange.first, kRange.first ); caf::VecIjk mainGridEndCell( iRange.second, jRange.second, kRange.second ); return std::make_pair( mainGridStartCell, mainGridEndCell ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map> RicExportLgrFeature::createLgrInfoListForTemporaryLgrs( const RigMainGrid* mainGrid ) { std::map> lgrInfosPerWell; for ( size_t i = 0; i < mainGrid->gridCount(); i++ ) { const auto grid = mainGrid->gridByIndex( i ); if ( !grid->isTempGrid() ) continue; caf::VecIjk lgrSizes( grid->cellCountI(), grid->cellCountJ(), grid->cellCountK() ); std::pair mainGridBoundingBox = mainGridCellBoundingBoxFromLgr( grid ); QString wellName = QString::fromStdString( grid->associatedWellPathName() ); auto& item = lgrInfosPerWell[wellName]; item.emplace_back( LgrInfo( grid->gridId(), QString::fromStdString( grid->gridName() ), QString::fromStdString( grid->associatedWellPathName() ), lgrSizes, mainGridBoundingBox.first, mainGridBoundingBox.second ) ); } return lgrInfosPerWell; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RicExportLgrFeature::firstAvailableLgrId( const RigMainGrid* mainGrid ) { int gridCount = (int)mainGrid->gridCount(); int lastUsedId = 0; for ( int i = 0; i < gridCount; i++ ) { lastUsedId = std::max( lastUsedId, mainGrid->gridByIndex( i )->gridId() ); } return lastUsedId + 1; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RigGridBase* RicExportLgrFeature::hostGrid( const RigMainGrid* mainGrid, size_t reservoirCellIndex ) { size_t dummy = 0; return mainGrid->gridAndGridLocalIdxFromGlobalCellIdx( reservoirCellIndex, &dummy ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- LgrNameFactory::LgrNameFactory() { m_counters = { { RigCompletionData::CompletionType::FRACTURE, { "FRAC", 1 } }, { RigCompletionData::CompletionType::FISHBONES, { "FB", 1 } }, { RigCompletionData::CompletionType::PERFORATION, { "PERF", 1 } } }; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString LgrNameFactory::newName( RigCompletionData::CompletionType completionType ) { switch ( completionType ) { case RigCompletionData::CompletionType::FRACTURE: case RigCompletionData::CompletionType::FISHBONES: case RigCompletionData::CompletionType::PERFORATION: { auto& counter = m_counters[completionType]; QString name = counter.first + "_" + QString::number( counter.second ); counter.second++; return name; } default: return "Unknown type"; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString LgrNameFactory::newName( const QString& baseName, int number ) { QString lgrName; if ( baseName.isEmpty() ) lgrName = "LGR"; lgrName += baseName + "_" + QString::number( number ); return lgrName.replace( " ", "_" ); }