///////////////////////////////////////////////////////////////////////////////// // // 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 "RicExportFractureCompletionsImpl.h" #include "RicWellPathFractureReportItem.h" #include "RiaLogging.h" #include "RiaQDateTimeTools.h" #include "RiaSummaryTools.h" #include "RimEclipseCase.h" #include "RimEclipseResultCase.h" #include "RimEclipseView.h" #include "RimFracture.h" #include "RimFractureContainmentTools.h" #include "RimFractureTemplate.h" #include "RimObservedEclipseUserData.h" #include "RimProject.h" #include "RimSimWellFracture.h" #include "RimSimWellFractureCollection.h" #include "RimSimWellInView.h" #include "RimStimPlanFractureTemplate.h" #include "RimSummaryCase.h" #include "RimSummaryCaseMainCollection.h" #include "RimWellPath.h" #include "RimWellPathCompletions.h" #include "RimWellPathFracture.h" #include "RimWellPathFractureCollection.h" #include "RifEclipseSummaryAddress.h" #include "RifSummaryReaderInterface.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" #include "RigEclipseToStimPlanCalculator.h" #include "RigEclipseToStimPlanCellTransmissibilityCalculator.h" #include "RigFractureCell.h" #include "RigFractureGrid.h" #include "RigFractureTransmissibilityEquations.h" #include "RigMainGrid.h" #include "RigResultAccessorFactory.h" #include "RigSimWellData.h" #include "RigSimulationWellCoordsAndMD.h" #include "RigTransmissibilityCondenser.h" #include "RigTransmissibilityEquations.h" #include "RigWellPath.h" #include "RigWellPathStimplanIntersector.h" #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportFractureCompletionsImpl::generateCompdatValuesForWellPath( RimWellPath* wellPath, RimEclipseCase* caseToApply, std::vector* fractureDataForReport, QTextStream* outputStreamForIntermediateResultsText, PressureDepletionParameters pdParams ) { std::vector fracturesAlongWellPath; for ( auto& frac : wellPath->fractureCollection()->activeFractures() ) { frac->ensureValidNonDarcyProperties(); fracturesAlongWellPath.push_back( frac ); } return generateCompdatValues( caseToApply, wellPath->completions()->wellNameForExport(), wellPath->wellPathGeometry(), fracturesAlongWellPath, fractureDataForReport, outputStreamForIntermediateResultsText, pdParams ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportFractureCompletionsImpl::generateCompdatValuesForSimWell( RimEclipseCase* eclipseCase, const RimSimWellInView* well, QTextStream* outputStreamForIntermediateResultsText, PressureDepletionParameters pdParams ) { std::vector completionData; auto branches = well->wellPipeBranches(); for ( size_t branchIndex = 0; branchIndex < branches.size(); ++branchIndex ) { std::vector fractures; for ( RimSimWellFracture* fracture : well->simwellFractureCollection->simwellFractures() ) { if ( fracture->isChecked() && static_cast( fracture->branchIndex() ) == branchIndex ) { fractures.push_back( fracture ); } } std::vector branchCompletions = generateCompdatValues( eclipseCase, well->name(), branches[branchIndex], fractures, nullptr, outputStreamForIntermediateResultsText, pdParams ); completionData.insert( completionData.end(), branchCompletions.begin(), branchCompletions.end() ); } return completionData; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportFractureCompletionsImpl::generateCompdatValues( RimEclipseCase* caseToApply, const QString& wellNameForExport, const RigWellPath* wellPathGeometry, const std::vector& fractures, std::vector* fractureDataReportItems, QTextStream* outputStreamForIntermediateResultsText, PressureDepletionParameters pdParams ) { std::vector fractureCompletions; if ( !caseToApply || !caseToApply->eclipseCaseData() ) { return fractureCompletions; } auto cellResultsData = caseToApply->results( RiaDefines::MATRIX_MODEL ); if ( !cellResultsData ) { return fractureCompletions; } { // Load the data required by computations to be able to use const access only inside OpenMP loop std::vector resultNames = RigEclipseToStimPlanCellTransmissibilityCalculator::requiredResultNames(); bool loadingSucceeded = RicExportFractureCompletionsImpl::loadResultsByName( cellResultsData, resultNames ); if ( !loadingSucceeded ) { QString msg; msg += "Compdat Export : One or more of the following required data sources are missing :"; for ( const auto& r : resultNames ) { msg += " "; msg += r; } RiaLogging::error( msg ); return fractureCompletions; } } { // Load the data required by fracture summary header std::vector resultNames{"TRANX", "TRANY", "TRANZ"}; RicExportFractureCompletionsImpl::loadResultsByName( cellResultsData, resultNames ); } { // Optional results std::vector resultNames = RigEclipseToStimPlanCellTransmissibilityCalculator::optionalResultNames(); RicExportFractureCompletionsImpl::loadResultsByName( cellResultsData, resultNames ); } if ( pdParams.performScaling ) { RigCaseCellResultsData* results = caseToApply->results( RiaDefines::MATRIX_MODEL ); results->ensureKnownResultLoaded( RigEclipseResultAddress( RiaDefines::DYNAMIC_NATIVE, "PRESSURE" ) ); } return generateCompdatValuesConst( caseToApply, wellNameForExport, wellPathGeometry, fractures, fractureDataReportItems, outputStreamForIntermediateResultsText, pdParams ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportFractureCompletionsImpl::generateCompdatValuesConst( const RimEclipseCase* caseToApply, const QString& wellNameForExport, const RigWellPath* wellPathGeometry, const std::vector& fractures, std::vector* fractureDataReportItems, QTextStream* outputStreamForIntermediateResultsText, PressureDepletionParameters pdParams ) { std::vector fractureCompletions; if ( !caseToApply || !caseToApply->eclipseCaseData() || !wellPathGeometry ) { return fractureCompletions; } double cDarcyInCorrectUnit = RiaEclipseUnitTools::darcysConstant( caseToApply->eclipseCaseData()->unitsType() ); const RigMainGrid* mainGrid = caseToApply->eclipseCaseData()->mainGrid(); const RigCaseCellResultsData* results = caseToApply->results( RiaDefines::MATRIX_MODEL ); const RigActiveCellInfo* actCellInfo = caseToApply->eclipseCaseData()->activeCellInfo( RiaDefines::MATRIX_MODEL ); bool performPressureDepletionScaling = pdParams.performScaling; int initialWellProductionTimeStep = 0; double currentWellPressure = 0; if ( performPressureDepletionScaling ) { double userWBHP = pdParams.userWBHP; double initialWBHPFromSummary = 0.0; double currentWBHPFromSummary = 0.0; // Find well pressures (WBHP) from summary case. getWellPressuresAndInitialProductionTimeStepFromSummaryData( caseToApply, wellNameForExport, pdParams.pressureScalingTimeStep, &initialWellProductionTimeStep, &initialWBHPFromSummary, ¤tWBHPFromSummary ); if ( pdParams.wbhpSource == WBHP_FROM_SUMMARY ) { currentWellPressure = currentWBHPFromSummary; if ( pdParams.pressureScalingTimeStep <= initialWellProductionTimeStep ) { currentWellPressure = userWBHP; } } else { currentWellPressure = userWBHP; } } const std::vector>* pressureResultVector = nullptr; const std::vector* currentMatrixPressures = nullptr; if ( performPressureDepletionScaling ) { pressureResultVector = &results->cellScalarResults( RigEclipseResultAddress( RiaDefines::DYNAMIC_NATIVE, "PRESSURE" ) ); CVF_ASSERT( !pressureResultVector->empty() ); if ( pdParams.pressureScalingTimeStep < static_cast( pressureResultVector->size() ) ) { currentMatrixPressures = &pressureResultVector->at( pdParams.pressureScalingTimeStep ); } else { // Don't perform scaling if the current pressure time step is beyond the case range. performPressureDepletionScaling = false; } } // To handle several fractures in the same eclipse cell we need to keep track of the transmissibility // to the well from each fracture intersecting the cell and sum these transmissibilities at the end. // std::map > // std::map> eclCellIdxToTransPrFractureMap; std::vector> sharedComplForFracture( fractures.size() ); #pragma omp parallel for for ( int i = 0; i < (int)fractures.size(); i++ ) { const RimFracture* fracture = fractures[i]; const RimFractureTemplate* fracTemplate = fracture->fractureTemplate(); if ( !fracTemplate ) continue; const RigFractureGrid* fractureGrid = fracTemplate->fractureGrid(); if ( !fractureGrid ) continue; bool useFiniteConductivityInFracture = ( fracTemplate->conductivityType() == RimFractureTemplate::FINITE_CONDUCTIVITY ); // If finite cond chosen and conductivity not present in stimplan file, do not calculate trans for this fracture if ( useFiniteConductivityInFracture && !checkForStimPlanConductivity( fracTemplate, fracture ) ) { continue; } RigTransmissibilityCondenser transCondenser; ////// // Calculate Matrix To Fracture Trans RigEclipseToStimPlanCalculator eclToFractureCalc( caseToApply, fracture->transformMatrix(), fracTemplate->skinFactor(), cDarcyInCorrectUnit, *fractureGrid, fracture ); eclToFractureCalc.appendDataToTransmissibilityCondenser( useFiniteConductivityInFracture, &transCondenser ); if ( useFiniteConductivityInFracture ) { calculateInternalFractureTransmissibilities( fractureGrid, cDarcyInCorrectUnit, transCondenser ); } if ( useFiniteConductivityInFracture ) { calculateFractureToWellTransmissibilities( fracTemplate, fractureGrid, fracture, cDarcyInCorrectUnit, wellPathGeometry, transCondenser ); } ///// // Insert total transmissibility from eclipse-cell to well for this fracture into the map std::map matrixToWellTrans = calculateMatrixToWellTransmissibilities( transCondenser ); double maxPressureDrop = 0.0, minPressureDrop = 0.0; if ( performPressureDepletionScaling ) { RigTransmissibilityCondenser scaledCondenser = transCondenser; // 1. Scale matrix to fracture transmissibilities by matrix to fracture pressure std::map originalLumpedMatrixToFractureTrans = scaledCondenser.scaleMatrixToFracTransByMatrixWellDP( actCellInfo, currentWellPressure, *currentMatrixPressures, &minPressureDrop, &maxPressureDrop ); // 2: Calculate new external transmissibilities scaledCondenser.calculateCondensedTransmissibilities(); { // 3: H�gst�l correction. // a. Calculate new effective fracture to well transmissiblities std::map fictitiousFractureToWellTransmissibilities = scaledCondenser.calculateFicticiousFractureToWellTransmissibilities(); // b. Calculate new effective matrix to well transmissibilities std::map effectiveMatrixToWellTrans = scaledCondenser .calculateEffectiveMatrixToWellTransmissibilities( originalLumpedMatrixToFractureTrans, fictitiousFractureToWellTransmissibilities ); matrixToWellTrans = effectiveMatrixToWellTrans; } } std::vector allCompletionsForOneFracture = generateCompdatValuesForFracture( matrixToWellTrans, wellNameForExport, caseToApply, fracture, fracTemplate ); if ( fractureDataReportItems ) { RicWellPathFractureReportItem reportItem( wellNameForExport, fracture->name(), fracTemplate->name(), fracture->fractureMD() ); reportItem.setUnitSystem( fracTemplate->fractureTemplateUnit() ); if ( performPressureDepletionScaling ) { QString timeStepString; if ( pdParams.pressureScalingTimeStep < caseToApply->timeStepStrings().size() ) { timeStepString = caseToApply->timeStepStrings()[pdParams.pressureScalingTimeStep]; } reportItem.setPressureDepletionParameters( performPressureDepletionScaling, timeStepString, caf::AppEnum::uiTextFromIndex( pdParams.wbhpSource ), pdParams.userWBHP, currentWellPressure, minPressureDrop, maxPressureDrop ); } RicExportFractureCompletionsImpl::calculateAndSetReportItemData( allCompletionsForOneFracture, eclToFractureCalc, reportItem ); #pragma omp critical( critical_section_fractureDataReportItems ) { fractureDataReportItems->push_back( reportItem ); } } std::copy( allCompletionsForOneFracture.begin(), allCompletionsForOneFracture.end(), std::back_inserter( sharedComplForFracture[i] ) ); if ( outputStreamForIntermediateResultsText ) { #pragma omp critical( critical_section_outputStreamForIntermediateResultsText ) { outputIntermediateResultsText( outputStreamForIntermediateResultsText, fracture, transCondenser, mainGrid, fractureGrid ); } } } for ( const auto& completions : sharedComplForFracture ) { std::copy( completions.begin(), completions.end(), std::back_inserter( fractureCompletions ) ); } return fractureCompletions; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportFractureCompletionsImpl::getWellPressuresAndInitialProductionTimeStepFromSummaryData( const RimEclipseCase* caseToApply, const QString& wellPathName, int currentTimeStep, int* initialCaseTimeStep, double* initialWellPressure, double* currentWellPressure ) { const RimEclipseResultCase* resultCase = dynamic_cast( caseToApply ); if ( resultCase ) { std::vector caseTimeSteps = resultCase->timeStepDates(); QDateTime initialProductionDate; QDateTime currentDate; if ( currentTimeStep < static_cast( caseTimeSteps.size() ) ) { currentDate = caseTimeSteps[currentTimeStep]; } else { currentDate = caseTimeSteps.back(); } RifEclipseSummaryAddress wbhpPressureAddress = RifEclipseSummaryAddress::wellAddress( "WBHP", wellPathName.toStdString() ); RimSummaryCaseMainCollection* mainCollection = RiaSummaryTools::summaryCaseMainCollection(); if ( mainCollection ) { RimSummaryCase* summaryCase = mainCollection->findSummaryCaseFromEclipseResultCase( resultCase ); if ( summaryCase && summaryCase->summaryReader() ) { std::vector values; if ( summaryCase->summaryReader()->values( wbhpPressureAddress, &values ) ) { std::vector summaryTimeSteps = summaryCase->summaryReader()->timeSteps( wbhpPressureAddress ); CVF_ASSERT( values.size() == summaryTimeSteps.size() ); for ( size_t i = 0; i < summaryTimeSteps.size(); ++i ) { QDateTime summaryDate = RiaQDateTimeTools::fromTime_t( summaryTimeSteps[i] ); if ( initialProductionDate.isNull() && values[i] > 0.0 ) { initialProductionDate = summaryDate; *initialWellPressure = values[i]; } if ( summaryDate <= currentDate ) { *currentWellPressure = values[i]; } } } } } if ( initialProductionDate.isValid() ) { for ( size_t i = 0; i < caseTimeSteps.size(); ++i ) { // Pick last time step that isn't bigger than the initial production time. if ( caseTimeSteps[i] < initialProductionDate ) { *initialCaseTimeStep = static_cast( i ); } else { break; } } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RicExportFractureCompletionsImpl::checkForStimPlanConductivity( const RimFractureTemplate* fracTemplate, const RimFracture* fracture ) { auto fracTemplateStimPlan = dynamic_cast( fracTemplate ); if ( fracTemplateStimPlan ) { if ( !fracTemplateStimPlan->hasConductivity() ) { RiaLogging::error( "Trying to export completion data for stimPlan fracture without conductivity data for " + fracture->name() ); RiaLogging::error( "No transmissibilities will be calculated for " + fracture->name() ); return false; } } return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportFractureCompletionsImpl::calculateInternalFractureTransmissibilities( const RigFractureGrid* fractureGrid, double cDarcyInCorrectUnit, RigTransmissibilityCondenser& transCondenser ) { for ( size_t i = 0; i < fractureGrid->iCellCount(); i++ ) { for ( size_t j = 0; j < fractureGrid->jCellCount(); j++ ) { size_t fractureCellIndex = fractureGrid->getGlobalIndexFromIJ( i, j ); const RigFractureCell& fractureCell = fractureGrid->cellFromIndex( fractureCellIndex ); if ( !fractureCell.hasNonZeroConductivity() ) continue; if ( i < fractureGrid->iCellCount() - 1 ) { size_t fractureCellNeighbourXIndex = fractureGrid->getGlobalIndexFromIJ( i + 1, j ); const RigFractureCell& fractureCellNeighbourX = fractureGrid->cellFromIndex( fractureCellNeighbourXIndex ); double horizontalTransToXneigbour = RigFractureTransmissibilityEquations:: centerToCenterFractureCellTrans( fractureCell.getConductivityValue(), fractureCell.cellSizeX(), fractureCell.cellSizeZ(), fractureCellNeighbourX.getConductivityValue(), fractureCellNeighbourX.cellSizeX(), fractureCellNeighbourX.cellSizeZ(), cDarcyInCorrectUnit ); transCondenser.addNeighborTransmissibility( {false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, fractureCellIndex}, {false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, fractureCellNeighbourXIndex}, horizontalTransToXneigbour ); } if ( j < fractureGrid->jCellCount() - 1 ) { size_t fractureCellNeighbourZIndex = fractureGrid->getGlobalIndexFromIJ( i, j + 1 ); const RigFractureCell& fractureCellNeighbourZ = fractureGrid->cellFromIndex( fractureCellNeighbourZIndex ); double verticalTransToZneigbour = RigFractureTransmissibilityEquations:: centerToCenterFractureCellTrans( fractureCell.getConductivityValue(), fractureCell.cellSizeZ(), fractureCell.cellSizeX(), fractureCellNeighbourZ.getConductivityValue(), fractureCellNeighbourZ.cellSizeZ(), fractureCellNeighbourZ.cellSizeX(), cDarcyInCorrectUnit ); transCondenser.addNeighborTransmissibility( {false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, fractureCellIndex}, {false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, fractureCellNeighbourZIndex}, verticalTransToZneigbour ); } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportFractureCompletionsImpl::calculateFractureToWellTransmissibilities( const RimFractureTemplate* fracTemplate, const RigFractureGrid* fractureGrid, const RimFracture* fracture, double cDarcyInCorrectUnit, const RigWellPath* wellPathGeometry, RigTransmissibilityCondenser& transCondenser ) { //// // If fracture has orientation Azimuth or Transverse, assume only radial inflow if ( fracTemplate->orientationType() == RimFractureTemplate::AZIMUTH || fracTemplate->orientationType() == RimFractureTemplate::TRANSVERSE_WELL_PATH ) { std::pair wellCellIJ = fractureGrid->fractureCellAtWellCenter(); size_t wellCellIndex = fractureGrid->getGlobalIndexFromIJ( wellCellIJ.first, wellCellIJ.second ); const RigFractureCell& wellCell = fractureGrid->cellFromIndex( wellCellIndex ); double radialTrans = RigFractureTransmissibilityEquations::fractureCellToWellRadialTrans( wellCell.getConductivityValue(), wellCell.cellSizeX(), wellCell.cellSizeZ(), fracture->wellRadius(), fracTemplate->skinFactor(), cDarcyInCorrectUnit ); transCondenser.addNeighborTransmissibility( {true, RigTransmissibilityCondenser::CellAddress::WELL, 1}, {false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, wellCellIndex}, radialTrans ); } else if ( fracTemplate->orientationType() == RimFractureTemplate::ALONG_WELL_PATH ) { //// // If fracture has orientation along well, linear inflow along well and radial flow at endpoints RigWellPathStimplanIntersector wellFractureIntersector( wellPathGeometry, fracture ); const std::map& fractureWellCells = wellFractureIntersector.intersections(); for ( const auto& fracCellIdxIsectDataPair : fractureWellCells ) { size_t fracWellCellIdx = fracCellIdxIsectDataPair.first; RigWellPathStimplanIntersector::WellCellIntersection intersection = fracCellIdxIsectDataPair.second; const RigFractureCell& fractureWellCell = fractureGrid->cellFromIndex( fracWellCellIdx ); double linearTrans = 0.0; if ( intersection.hlength > 0.0 || intersection.vlength > 0.0 ) { linearTrans = RigFractureTransmissibilityEquations::fractureCellToWellLinearTrans( fractureWellCell .getConductivityValue(), fractureWellCell.cellSizeX(), fractureWellCell.cellSizeZ(), intersection.vlength, intersection.hlength, fracture->perforationEfficiency(), fracTemplate->skinFactor(), cDarcyInCorrectUnit, fracture->wellRadius() ); } transCondenser.addNeighborTransmissibility( {true, RigTransmissibilityCondenser::CellAddress::WELL, 1}, {false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, fracWellCellIdx}, linearTrans ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map RicExportFractureCompletionsImpl::calculateMatrixToWellTransmissibilities( RigTransmissibilityCondenser& transCondenser ) { std::map matrixToWellTransmissibilities; std::set externalCells = transCondenser.externalCells(); for ( RigTransmissibilityCondenser::CellAddress externalCell : externalCells ) { if ( externalCell.m_cellIndexSpace == RigTransmissibilityCondenser::CellAddress::ECLIPSE ) { double trans = transCondenser.condensedTransmissibility( externalCell, {true, RigTransmissibilityCondenser::CellAddress::WELL, 1} ); matrixToWellTransmissibilities.insert( std::make_pair( externalCell.m_globalCellIdx, trans ) ); } } return matrixToWellTransmissibilities; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicExportFractureCompletionsImpl::generateCompdatValuesForFracture( const std::map& matrixToWellTransmissibilites, const QString& wellNameForExport, const RimEclipseCase* caseToApply, const RimFracture* fracture, const RimFractureTemplate* fracTemplate ) { std::vector allCompletionsForOneFracture; for ( const auto& matrixToWellTransmissibility : matrixToWellTransmissibilites ) { size_t globalCellIndex = matrixToWellTransmissibility.first; double trans = matrixToWellTransmissibility.second; RigCompletionData compDat( wellNameForExport, RigCompletionDataGridCell( globalCellIndex, caseToApply->mainGrid() ), fracture->fractureMD() ); double diameter = 2.0 * fracture->wellRadius(); compDat.setFromFracture( trans, fracTemplate->skinFactor(), diameter ); compDat.addMetadata( fracture->name(), QString::number( trans ) ); compDat.setSourcePdmObject( fracture ); allCompletionsForOneFracture.push_back( compDat ); } if ( fracTemplate->isNonDarcyFlowEnabled() ) { computeNonDarcyFlowParameters( fracture, allCompletionsForOneFracture ); } return allCompletionsForOneFracture; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportFractureCompletionsImpl::computeNonDarcyFlowParameters( const RimFracture* fracture, std::vector& allCompletionsForOneFracture ) { double dFactorForFracture = fracture->nonDarcyProperties().dFactor; double khForFracture = fracture->nonDarcyProperties().conductivity; double sumOfTransmissibilitiesInFracture = sumUpTransmissibilities( allCompletionsForOneFracture ); for ( auto& c : allCompletionsForOneFracture ) { // NOTE : What is supposed to happen when the transmissibility is close to zero? double dFactorForOneConnection = dFactorForFracture * sumOfTransmissibilitiesInFracture / c.transmissibility(); c.setDFactor( dFactorForOneConnection ); double khForOneConnection = khForFracture * c.transmissibility() / sumOfTransmissibilitiesInFracture; c.setKh( khForOneConnection ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RicExportFractureCompletionsImpl::sumUpTransmissibilities( const std::vector& allCompletionsForOneFracture ) { double transmissibility = 0.0; for ( const auto& c : allCompletionsForOneFracture ) { transmissibility += c.transmissibility(); } return transmissibility; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportFractureCompletionsImpl::calculateAndSetReportItemData( const std::vector& allCompletionsForOneFracture, const RigEclipseToStimPlanCalculator& eclToFractureCalc, RicWellPathFractureReportItem& reportItem ) { double areaWeightedMatrixPermeability = eclToFractureCalc.areaWeightedMatrixPermeability(); reportItem.setAreaWeightedPermeability( areaWeightedMatrixPermeability ); double totalAreaOpenForFlow = eclToFractureCalc.totalEclipseAreaOpenForFlow(); double areaWeightedConductivity = eclToFractureCalc.areaWeightedConductivity(); if ( totalAreaOpenForFlow > 0.0 ) { double halfLength = 0.0; double height = eclToFractureCalc.longestYSectionOpenForFlow(); if ( height > 0.0 ) { double length = totalAreaOpenForFlow / height; halfLength = length / 2.0; } reportItem.setHeightAndHalfLength( height, halfLength ); } double aggregatedTransmissibility = sumUpTransmissibilities( allCompletionsForOneFracture ); reportItem.setData( aggregatedTransmissibility, allCompletionsForOneFracture.size(), totalAreaOpenForFlow ); reportItem.setWidthAndConductivity( eclToFractureCalc.areaWeightedWidth(), areaWeightedConductivity ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicExportFractureCompletionsImpl::outputIntermediateResultsText( QTextStream* outputStreamForIntermediateResultsText, const RimFracture* fracture, RigTransmissibilityCondenser& transCondenser, const RigMainGrid* mainGrid, const RigFractureGrid* fractureGrid ) { ( *outputStreamForIntermediateResultsText ) << "\n" << "\n" << "\n----------- All Transmissibilities " << fracture->name() << " -------------------- \n\n"; ( *outputStreamForIntermediateResultsText ) << QString::fromStdString( transCondenser.neighborTransDebugOutput( mainGrid, fractureGrid ) ); ( *outputStreamForIntermediateResultsText ) << "\n" << "\n" << "\n----------- Condensed Results " << fracture->name() << " -------------------- \n\n"; ( *outputStreamForIntermediateResultsText ) << QString::fromStdString( transCondenser.condensedTransDebugOutput( mainGrid, fractureGrid ) ); ( *outputStreamForIntermediateResultsText ) << "\n"; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RicExportFractureCompletionsImpl::loadResultsByName( RigCaseCellResultsData* cellResultsData, const std::vector& resultNames ) { const std::vector resultCategorySearchOrder = {RiaDefines::STATIC_NATIVE, RiaDefines::INPUT_PROPERTY, RiaDefines::GENERATED}; bool foundDataForAllResults = true; if ( cellResultsData ) { for ( const auto& resultName : resultNames ) { if ( !cellResultsData->findAndLoadResultByName( resultName, resultCategorySearchOrder ) ) { foundDataForAllResults = false; } } } return foundDataForAllResults; }