2017-05-29 08:39:37 -05:00
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
# include "RicExportFishbonesWellSegmentsFeature.h"
# include "RiaApplication.h"
# include "RiaLogging.h"
2017-06-28 03:13:59 -05:00
# include "RicExportFeatureImpl.h"
2017-05-29 08:39:37 -05:00
# include "RimProject.h"
# include "RimFishboneWellPathCollection.h"
# include "RimFishbonesCollection.h"
# include "RimFishbonesMultipleSubs.h"
# include "RimWellPath.h"
# include "RimEclipseCase.h"
# include "RigMainGrid.h"
# include "RigEclipseCaseData.h"
2017-06-02 08:37:58 -05:00
# include "RigWellPath.h"
2017-05-29 08:39:37 -05:00
# include "RiuMainWindow.h"
# include "cafSelectionManager.h"
# include "cafPdmUiPropertyViewDialog.h"
2017-08-29 02:39:33 -05:00
# include "cafUtils.h"
2017-05-29 08:39:37 -05:00
2017-06-02 05:50:16 -05:00
# include "cvfMath.h"
2017-05-29 08:39:37 -05:00
# include <QAction>
# include <QMessageBox>
# include <QDir>
CAF_CMD_SOURCE_INIT ( RicExportFishbonesWellSegmentsFeature , " RicExportFishbonesWellSegmentsFeature " ) ;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicExportFishbonesWellSegmentsFeature : : onActionTriggered ( bool isChecked )
{
RimFishbonesCollection * fishbonesCollection = selectedFishbonesCollection ( ) ;
RimWellPath * wellPath = selectedWellPath ( ) ;
CVF_ASSERT ( fishbonesCollection ) ;
CVF_ASSERT ( wellPath ) ;
RiaApplication * app = RiaApplication : : instance ( ) ;
QString projectFolder = app - > currentProjectPath ( ) ;
QString defaultDir = RiaApplication : : instance ( ) - > lastUsedDialogDirectoryWithFallback ( " COMPLETIONS " , projectFolder ) ;
2017-06-28 13:51:16 -05:00
RicCaseAndFileExportSettingsUi exportSettings ;
2017-05-29 08:39:37 -05:00
std : : vector < RimCase * > cases ;
app - > project ( ) - > allCases ( cases ) ;
for ( auto c : cases )
{
RimEclipseCase * eclipseCase = dynamic_cast < RimEclipseCase * > ( c ) ;
if ( eclipseCase ! = nullptr )
{
exportSettings . caseToApply = eclipseCase ;
break ;
}
}
2017-06-15 04:21:37 -05:00
exportSettings . folder = defaultDir ;
2017-05-29 08:39:37 -05:00
2017-06-28 03:11:56 -05:00
caf : : PdmUiPropertyViewDialog propertyDialog ( RiuMainWindow : : instance ( ) , & exportSettings , " Export Well Segments " , " " ) ;
2017-06-28 03:13:59 -05:00
RicExportFeatureImpl : : configureForExport ( & propertyDialog ) ;
2017-05-29 08:39:37 -05:00
if ( propertyDialog . exec ( ) = = QDialog : : Accepted )
{
2017-06-15 04:21:37 -05:00
RiaApplication : : instance ( ) - > setLastUsedDialogDirectory ( " COMPLETIONS " , QFileInfo ( exportSettings . folder ) . absolutePath ( ) ) ;
2017-05-29 08:39:37 -05:00
std : : vector < RimFishbonesMultipleSubs * > fishbonesSubs ;
for ( RimFishbonesMultipleSubs * subs : fishbonesCollection - > fishbonesSubs )
{
fishbonesSubs . push_back ( subs ) ;
}
exportWellSegments ( wellPath , fishbonesSubs , exportSettings ) ;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFishbonesCollection * RicExportFishbonesWellSegmentsFeature : : selectedFishbonesCollection ( )
{
RimFishbonesCollection * objToFind = nullptr ;
caf : : PdmUiItem * pdmUiItem = caf : : SelectionManager : : instance ( ) - > selectedItem ( ) ;
caf : : PdmObjectHandle * objHandle = dynamic_cast < caf : : PdmObjectHandle * > ( pdmUiItem ) ;
if ( objHandle )
{
objHandle - > firstAncestorOrThisOfType ( objToFind ) ;
}
return objToFind ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellPath * RicExportFishbonesWellSegmentsFeature : : selectedWellPath ( )
{
RimWellPath * objToFind = nullptr ;
caf : : PdmUiItem * pdmUiItem = caf : : SelectionManager : : instance ( ) - > selectedItem ( ) ;
caf : : PdmObjectHandle * objHandle = dynamic_cast < caf : : PdmObjectHandle * > ( pdmUiItem ) ;
if ( objHandle )
{
objHandle - > firstAncestorOrThisOfType ( objToFind ) ;
}
return objToFind ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicExportFishbonesWellSegmentsFeature : : setupActionLook ( QAction * actionToSetup )
{
actionToSetup - > setText ( " Export Well Segments " ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicExportFishbonesWellSegmentsFeature : : isCommandEnabled ( )
{
if ( selectedFishbonesCollection ( ) )
{
return true ;
}
return false ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-28 13:51:16 -05:00
void RicExportFishbonesWellSegmentsFeature : : exportWellSegments ( const RimWellPath * wellPath , const std : : vector < RimFishbonesMultipleSubs * > & fishbonesSubs , const RicCaseAndFileExportSettingsUi & settings )
2017-05-29 08:39:37 -05:00
{
if ( settings . caseToApply ( ) = = nullptr )
{
RiaLogging : : error ( " Export Well Segments: Cannot export completions data without specified eclipse case " ) ;
return ;
}
2017-08-29 02:39:33 -05:00
QString fileName = QString ( " %1-Welsegs " ) . arg ( settings . caseToApply ( ) - > caseUserDescription ( ) ) ;
fileName = caf : : Utils : : makeValidFileBasename ( fileName ) ;
QString filePath = QDir ( settings . folder ( ) ) . filePath ( fileName ) ;
QFile exportFile ( filePath ) ;
2017-05-29 08:39:37 -05:00
if ( ! exportFile . open ( QIODevice : : WriteOnly ) )
{
2017-06-15 04:21:37 -05:00
RiaLogging : : error ( QString ( " Export Well Segments: Could not open the file: %1 " ) . arg ( filePath ) ) ;
2017-05-29 08:39:37 -05:00
return ;
}
std : : vector < WellSegmentLocation > locations = RicWellPathExportCompletionDataFeature : : findWellSegmentLocations ( settings . caseToApply , wellPath , fishbonesSubs ) ;
QTextStream stream ( & exportFile ) ;
2017-05-30 08:00:14 -05:00
RifEclipseDataTableFormatter formatter ( stream ) ;
2017-05-29 08:39:37 -05:00
generateWelsegsTable ( formatter , wellPath , settings , locations ) ;
generateCompsegsTable ( formatter , wellPath , settings , locations ) ;
2017-06-02 05:50:16 -05:00
generateWsegvalvTable ( formatter , wellPath , settings , locations ) ;
2017-05-29 08:39:37 -05:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-02 05:50:16 -05:00
void RicExportFishbonesWellSegmentsFeature : : generateWelsegsTable ( RifEclipseDataTableFormatter & formatter ,
const RimWellPath * wellPath ,
2017-06-28 13:51:16 -05:00
const RicCaseAndFileExportSettingsUi & settings ,
2017-06-02 05:50:16 -05:00
const std : : vector < WellSegmentLocation > & locations )
2017-05-29 08:39:37 -05:00
{
2017-06-20 03:40:39 -05:00
RiaEclipseUnitTools : : UnitSystem unitSystem = settings . caseToApply - > eclipseCaseData ( ) - > unitsType ( ) ;
2017-05-29 08:39:37 -05:00
formatter . keyword ( " WELSEGS " ) ;
2017-06-02 08:37:58 -05:00
double startMD = wellPath - > fishbonesCollection ( ) - > startMD ( ) ;
double startTVD = - wellPath - > wellPathGeometry ( ) - > interpolatedPointAlongWellPath ( startMD ) . z ( ) ;
2017-05-29 08:39:37 -05:00
{
std : : vector < RifEclipseOutputTableColumn > header = {
RifEclipseOutputTableColumn ( " Name " ) ,
RifEclipseOutputTableColumn ( " Dep 1 " ) ,
RifEclipseOutputTableColumn ( " Tlen 1 " ) ,
RifEclipseOutputTableColumn ( " Vol 1 " ) ,
RifEclipseOutputTableColumn ( " Len&Dep " ) ,
RifEclipseOutputTableColumn ( " PresDrop " ) ,
} ;
formatter . header ( header ) ;
formatter . add ( wellPath - > name ( ) ) ;
2017-06-02 08:37:58 -05:00
formatter . add ( startTVD ) ;
formatter . add ( startMD ) ;
2017-05-29 08:39:37 -05:00
formatter . add ( " 1* " ) ;
2017-06-28 13:51:16 -05:00
formatter . add ( wellPath - > fishbonesCollection ( ) - > lengthAndDepth ( ) . text ( ) ) ;
formatter . add ( wellPath - > fishbonesCollection ( ) - > pressureDrop ( ) . text ( ) ) ;
2017-05-29 08:39:37 -05:00
formatter . rowCompleted ( ) ;
}
{
std : : vector < RifEclipseOutputTableColumn > header = {
RifEclipseOutputTableColumn ( " First Seg " ) ,
RifEclipseOutputTableColumn ( " Last Seg " ) ,
RifEclipseOutputTableColumn ( " Branch Num " ) ,
RifEclipseOutputTableColumn ( " Outlet Seg " ) ,
RifEclipseOutputTableColumn ( " Length " ) ,
RifEclipseOutputTableColumn ( " Depth Change " ) ,
RifEclipseOutputTableColumn ( " Diam " ) ,
RifEclipseOutputTableColumn ( " Rough " ) ,
} ;
formatter . header ( header ) ;
}
{
formatter . comment ( " Main stem " ) ;
double depth = 0 ;
double length = 0 ;
2017-06-02 08:37:58 -05:00
double previousMD = startMD ;
double previousTVD = startTVD ;
2017-05-29 08:39:37 -05:00
2017-06-02 08:37:58 -05:00
for ( const WellSegmentLocation & location : locations )
2017-05-29 08:39:37 -05:00
{
2017-06-28 13:51:16 -05:00
if ( wellPath - > fishbonesCollection ( ) - > lengthAndDepth ( ) = = RimFishbonesCollection : : INC )
2017-05-29 08:39:37 -05:00
{
2017-06-02 08:37:58 -05:00
depth = location . trueVerticalDepth - previousTVD ;
length = location . fishbonesSubs - > measuredDepth ( location . subIndex ) - previousMD ;
2017-05-29 08:39:37 -05:00
}
else
{
2017-06-02 08:37:58 -05:00
depth + = location . trueVerticalDepth - previousTVD ;
length + = location . fishbonesSubs - > measuredDepth ( location . subIndex ) - previousMD ;
2017-05-29 08:39:37 -05:00
}
formatter . comment ( QString ( " Segment for sub %1 " ) . arg ( location . subIndex ) ) ;
formatter . add ( location . segmentNumber ) . add ( location . segmentNumber ) ;
formatter . add ( 1 ) ; // All segments on main stem are branch 1
formatter . add ( location . segmentNumber - 1 ) ; // All main stem segments are connected to the segment below them
formatter . add ( length ) ;
formatter . add ( depth ) ;
2017-06-26 04:45:20 -05:00
formatter . add ( wellPath - > fishbonesCollection ( ) - > linerDiameter ( unitSystem ) ) ;
2017-06-20 03:40:39 -05:00
formatter . add ( wellPath - > fishbonesCollection ( ) - > roughnessFactor ( unitSystem ) ) ;
2017-05-29 08:39:37 -05:00
formatter . rowCompleted ( ) ;
2017-06-02 08:37:58 -05:00
previousMD = location . measuredDepth ;
previousTVD = location . trueVerticalDepth ;
2017-05-29 08:39:37 -05:00
}
}
{
formatter . comment ( " Laterals " ) ;
formatter . comment ( " Diam: MSW - Tubing Radius " ) ;
formatter . comment ( " Rough: MSW - Open Hole Roughness Factor " ) ;
for ( const WellSegmentLocation & location : locations )
{
2017-06-02 05:50:16 -05:00
formatter . comment ( " ICD " ) ;
formatter . add ( location . icdSegmentNumber ) . add ( location . icdSegmentNumber ) ;
formatter . add ( location . icdBranchNumber ) ;
formatter . add ( location . segmentNumber ) ;
formatter . add ( 0.1 ) ; // ICDs have 0.1 length
formatter . add ( 0 ) ; // Depth change
2017-06-26 04:45:20 -05:00
formatter . add ( wellPath - > fishbonesCollection ( ) - > linerDiameter ( unitSystem ) ) ;
2017-06-20 03:40:39 -05:00
formatter . add ( wellPath - > fishbonesCollection ( ) - > roughnessFactor ( unitSystem ) ) ;
2017-06-02 05:50:16 -05:00
formatter . rowCompleted ( ) ;
2017-05-29 08:39:37 -05:00
for ( const WellSegmentLateral & lateral : location . laterals )
{
2017-12-19 04:00:26 -06:00
formatter . comment ( QString ( " %1 : Sub index %2 - Lateral %3 " ) . arg ( location . fishbonesSubs - > generatedName ( ) ) . arg ( location . subIndex ) . arg ( lateral . lateralIndex ) ) ;
2017-05-29 08:39:37 -05:00
double depth = 0 ;
double length = 0 ;
for ( const WellSegmentLateralIntersection & intersection : lateral . intersections )
{
2017-06-28 13:51:16 -05:00
if ( wellPath - > fishbonesCollection ( ) - > lengthAndDepth ( ) = = RimFishbonesCollection : : INC )
2017-05-29 08:39:37 -05:00
{
2017-12-12 05:47:05 -06:00
depth = intersection . tvdChangeFromPreviousIntersection ;
length = intersection . mdFromPreviousIntersection ;
2017-05-29 08:39:37 -05:00
}
else
{
2017-12-12 05:47:05 -06:00
depth + = intersection . tvdChangeFromPreviousIntersection ;
length + = intersection . mdFromPreviousIntersection ;
2017-05-29 08:39:37 -05:00
}
2017-06-20 03:40:39 -05:00
double diameter = computeEffectiveDiameter ( location . fishbonesSubs - > tubingDiameter ( unitSystem ) , location . fishbonesSubs - > holeDiameter ( unitSystem ) ) ;
2017-05-29 08:39:37 -05:00
formatter . add ( intersection . segmentNumber ) ;
formatter . add ( intersection . segmentNumber ) ;
formatter . add ( lateral . branchNumber ) ;
formatter . add ( intersection . attachedSegmentNumber ) ;
formatter . add ( length ) ;
formatter . add ( depth ) ;
2017-06-09 05:08:15 -05:00
formatter . add ( diameter ) ;
2017-06-20 03:40:39 -05:00
formatter . add ( location . fishbonesSubs - > openHoleRoughnessFactor ( unitSystem ) ) ;
2017-05-29 08:39:37 -05:00
formatter . rowCompleted ( ) ;
}
}
}
}
formatter . tableCompleted ( ) ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
2017-06-02 05:50:16 -05:00
void RicExportFishbonesWellSegmentsFeature : : generateCompsegsTable ( RifEclipseDataTableFormatter & formatter ,
const RimWellPath * wellPath ,
2017-06-28 13:51:16 -05:00
const RicCaseAndFileExportSettingsUi & settings ,
2017-06-02 05:50:16 -05:00
const std : : vector < WellSegmentLocation > & locations )
2017-05-29 08:39:37 -05:00
{
RigMainGrid * grid = settings . caseToApply - > eclipseCaseData ( ) - > mainGrid ( ) ;
formatter . keyword ( " COMPSEGS " ) ;
{
std : : vector < RifEclipseOutputTableColumn > header = {
RifEclipseOutputTableColumn ( " Name " )
} ;
formatter . header ( header ) ;
formatter . add ( wellPath - > name ( ) ) ;
formatter . rowCompleted ( ) ;
}
{
std : : vector < RifEclipseOutputTableColumn > header = {
RifEclipseOutputTableColumn ( " I " ) ,
RifEclipseOutputTableColumn ( " J " ) ,
RifEclipseOutputTableColumn ( " K " ) ,
RifEclipseOutputTableColumn ( " Branch no " ) ,
RifEclipseOutputTableColumn ( " Start Length " ) ,
RifEclipseOutputTableColumn ( " End Length " ) ,
RifEclipseOutputTableColumn ( " Dir Pen " ) ,
RifEclipseOutputTableColumn ( " End Range " ) ,
RifEclipseOutputTableColumn ( " Connection Depth " )
} ;
formatter . header ( header ) ;
}
for ( const WellSegmentLocation & location : locations )
{
for ( const WellSegmentLateral & lateral : location . laterals )
{
2017-06-02 04:42:41 -05:00
double aggregatedLength = 0 ;
2017-05-29 08:39:37 -05:00
for ( const WellSegmentLateralIntersection & intersection : lateral . intersections )
{
size_t i , j , k ;
2018-01-29 08:27:17 -06:00
grid - > ijkFromCellIndex ( intersection . globalCellIndex , & i , & j , & k ) ;
2017-05-29 08:39:37 -05:00
formatter . addZeroBasedCellIndex ( i ) . addZeroBasedCellIndex ( j ) . addZeroBasedCellIndex ( k ) ;
formatter . add ( lateral . branchNumber ) ;
2017-06-02 04:42:41 -05:00
formatter . add ( aggregatedLength ) ;
2017-12-12 05:47:05 -06:00
formatter . add ( aggregatedLength + intersection . mdFromPreviousIntersection ) ;
2017-05-29 08:39:37 -05:00
formatter . rowCompleted ( ) ;
2017-06-02 04:42:41 -05:00
2017-12-12 05:47:05 -06:00
aggregatedLength + = intersection . mdFromPreviousIntersection ;
2017-05-29 08:39:37 -05:00
}
}
}
formatter . tableCompleted ( ) ;
}
2017-06-02 05:50:16 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicExportFishbonesWellSegmentsFeature : : generateWsegvalvTable ( RifEclipseDataTableFormatter & formatter ,
const RimWellPath * wellPath ,
2017-06-28 13:51:16 -05:00
const RicCaseAndFileExportSettingsUi & settings ,
2017-06-02 05:50:16 -05:00
const std : : vector < WellSegmentLocation > & locations )
{
2017-06-20 03:40:39 -05:00
RiaEclipseUnitTools : : UnitSystem unitSystem = settings . caseToApply - > eclipseCaseData ( ) - > unitsType ( ) ;
2017-06-02 05:50:16 -05:00
{
formatter . keyword ( " WSEGVALV " ) ;
std : : vector < RifEclipseOutputTableColumn > header = {
RifEclipseOutputTableColumn ( " Well Name " ) ,
RifEclipseOutputTableColumn ( " Seg No " ) ,
RifEclipseOutputTableColumn ( " Cv " ) ,
RifEclipseOutputTableColumn ( " Ac " ) ,
} ;
formatter . header ( header ) ;
}
for ( const WellSegmentLocation & location : locations )
{
formatter . add ( wellPath - > name ( ) ) ;
formatter . add ( location . icdSegmentNumber ) ;
formatter . add ( location . fishbonesSubs - > icdFlowCoefficient ( ) ) ;
2017-06-20 03:40:39 -05:00
double icdOrificeRadius = location . fishbonesSubs - > icdOrificeDiameter ( unitSystem ) / 2 ;
2017-06-02 05:50:16 -05:00
double icdArea = icdOrificeRadius * icdOrificeRadius * cvf : : PI_D ;
formatter . add ( icdArea * static_cast < double > ( location . fishbonesSubs - > icdCount ( ) ) ) ;
formatter . rowCompleted ( ) ;
}
formatter . tableCompleted ( ) ;
}
2017-06-09 05:08:15 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RicExportFishbonesWellSegmentsFeature : : computeEffectiveDiameter ( double innerDiameter , double outerDiameter )
{
double innerRadius = innerDiameter / 2 ;
double innerArea = cvf : : PI_D * innerRadius * innerRadius ;
double outerRadius = outerDiameter / 2 ;
double outerArea = cvf : : PI_D * outerRadius * outerRadius ;
double effectiveArea = outerArea - innerArea ;
2017-06-09 05:27:21 -05:00
double effectiveRadius = cvf : : Math : : sqrt ( effectiveArea / cvf : : PI_D ) ;
2017-06-09 05:08:15 -05:00
return effectiveRadius * 2 ;
}