2021-03-15 10:23:57 -05:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Copyright (C) 2021 - Equinor 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.
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2021-04-09 06:08:35 -05:00
|
|
|
#include "RimEnsembleFractureStatistics.h"
|
2021-03-15 10:23:57 -05:00
|
|
|
|
2021-03-26 04:01:36 -05:00
|
|
|
#include "RiaDefines.h"
|
2021-03-17 13:04:04 -05:00
|
|
|
#include "RiaLogging.h"
|
|
|
|
#include "RiaPreferences.h"
|
|
|
|
|
|
|
|
#include "RigFractureGrid.h"
|
|
|
|
#include "RigSlice2D.h"
|
|
|
|
#include "RigStatisticsMath.h"
|
|
|
|
#include "RigStimPlanFractureDefinition.h"
|
|
|
|
|
|
|
|
#include "RifCsvDataTableFormatter.h"
|
2021-04-09 06:08:35 -05:00
|
|
|
#include "RifEnsembleFractureStatisticsExporter.h"
|
2021-03-17 13:04:04 -05:00
|
|
|
#include "RifStimPlanXmlReader.h"
|
|
|
|
|
2021-03-26 08:56:29 -05:00
|
|
|
#include "FractureCommands/RicNewStimPlanFractureTemplateFeature.h"
|
|
|
|
|
2021-03-24 06:03:19 -05:00
|
|
|
#include "cafAppEnum.h"
|
2021-03-15 10:23:57 -05:00
|
|
|
#include "cafPdmUiTextEditor.h"
|
2021-03-26 08:56:29 -05:00
|
|
|
#include "cafPdmUiToolButtonEditor.h"
|
2021-04-09 11:56:57 -05:00
|
|
|
#include "cafPdmUiTreeSelectionEditor.h"
|
2021-03-15 10:23:57 -05:00
|
|
|
|
2021-03-17 13:04:04 -05:00
|
|
|
#include <cmath>
|
|
|
|
|
2021-03-26 04:01:36 -05:00
|
|
|
#include <QDir>
|
2021-03-17 13:04:04 -05:00
|
|
|
#include <QFile>
|
|
|
|
|
2021-03-24 06:03:19 -05:00
|
|
|
namespace caf
|
|
|
|
{
|
|
|
|
template <>
|
2021-04-09 06:08:35 -05:00
|
|
|
void caf::AppEnum<RimEnsembleFractureStatistics::StatisticsType>::setUp()
|
2021-03-24 06:03:19 -05:00
|
|
|
{
|
2021-04-09 06:08:35 -05:00
|
|
|
addItem( RimEnsembleFractureStatistics::StatisticsType::MEAN, "MEAN", "Mean" );
|
|
|
|
addItem( RimEnsembleFractureStatistics::StatisticsType::MIN, "MIN", "Minimum" );
|
|
|
|
addItem( RimEnsembleFractureStatistics::StatisticsType::MAX, "MAX", "Maximum" );
|
|
|
|
addItem( RimEnsembleFractureStatistics::StatisticsType::P10, "P10", "P10" );
|
|
|
|
addItem( RimEnsembleFractureStatistics::StatisticsType::P50, "P50", "P50" );
|
|
|
|
addItem( RimEnsembleFractureStatistics::StatisticsType::P90, "P90", "P90" );
|
|
|
|
addItem( RimEnsembleFractureStatistics::StatisticsType::OCCURRENCE, "OCCURRENCE", "Occurrence" );
|
|
|
|
setDefault( RimEnsembleFractureStatistics::StatisticsType::MEAN );
|
2021-03-24 06:03:19 -05:00
|
|
|
}
|
|
|
|
|
2021-04-14 08:59:28 -05:00
|
|
|
template <>
|
|
|
|
void caf::AppEnum<RimEnsembleFractureStatistics::MeshType>::setUp()
|
|
|
|
{
|
|
|
|
addItem( RimEnsembleFractureStatistics::MeshType::ADAPTIVE, "ADAPTIVE", "Adaptive" );
|
|
|
|
addItem( RimEnsembleFractureStatistics::MeshType::UNIFORM, "UNIFORM", "Uniform" );
|
|
|
|
setDefault( RimEnsembleFractureStatistics::MeshType::ADAPTIVE );
|
|
|
|
}
|
|
|
|
|
2021-03-24 06:03:19 -05:00
|
|
|
} // namespace caf
|
|
|
|
|
2021-04-09 06:08:35 -05:00
|
|
|
CAF_PDM_SOURCE_INIT( RimEnsembleFractureStatistics, "EnsembleFractureStatistics" );
|
2021-03-15 10:23:57 -05:00
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
RimEnsembleFractureStatistics::RimEnsembleFractureStatistics()
|
2021-03-15 10:23:57 -05:00
|
|
|
{
|
2021-04-09 06:08:35 -05:00
|
|
|
CAF_PDM_InitObject( "Ensemble Fracture Statistics", ":/FractureTemplate16x16.png", "", "" );
|
2021-03-15 10:23:57 -05:00
|
|
|
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_filePaths, "FilePaths", "", "", "", "" );
|
|
|
|
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_filePathsTable, "FilePathsTable", "File Paths Table", "", "", "" );
|
|
|
|
m_filePathsTable.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
|
|
|
|
m_filePathsTable.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
|
|
|
|
m_filePathsTable.uiCapability()->setUiReadOnly( true );
|
|
|
|
m_filePathsTable.xmlCapability()->disableIO();
|
2021-03-26 08:56:29 -05:00
|
|
|
|
2021-04-14 08:59:28 -05:00
|
|
|
CAF_PDM_InitFieldNoDefault( &m_meshType, "MeshType", "Mesh Type", "", "", "" );
|
2021-04-09 11:56:57 -05:00
|
|
|
CAF_PDM_InitField( &m_numSamplesX, "NumberOfSamplesX", 100, "X", "", "", "" );
|
|
|
|
CAF_PDM_InitField( &m_numSamplesY, "NumberOfSamplesY", 200, "Y", "", "", "" );
|
|
|
|
|
|
|
|
std::vector<caf::AppEnum<RimEnsembleFractureStatistics::StatisticsType>> defaultStatisticsTypes = {
|
|
|
|
caf::AppEnum<RimEnsembleFractureStatistics::StatisticsType>( RimEnsembleFractureStatistics::StatisticsType::MEAN ) };
|
|
|
|
|
|
|
|
CAF_PDM_InitField( &m_selectedStatisticsType, "SelectedStatisticsType", defaultStatisticsTypes, "Statistics Type", "", "", "" );
|
|
|
|
m_selectedStatisticsType.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
|
|
|
|
m_selectedStatisticsType.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP );
|
|
|
|
|
2021-04-14 08:59:28 -05:00
|
|
|
CAF_PDM_InitFieldNoDefault( &m_computeStatistics, "ComputeStatistics", "Compute Templates", "", "", "" );
|
2021-03-26 08:56:29 -05:00
|
|
|
m_computeStatistics.uiCapability()->setUiEditorTypeName( caf::PdmUiToolButtonEditor::uiEditorTypeName() );
|
|
|
|
m_computeStatistics.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
|
|
|
|
|
|
|
|
setDeletable( true );
|
2021-03-15 10:23:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
RimEnsembleFractureStatistics::~RimEnsembleFractureStatistics()
|
2021-03-15 10:23:57 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
void RimEnsembleFractureStatistics::addFilePath( const QString& filePath )
|
2021-03-15 10:23:57 -05:00
|
|
|
{
|
|
|
|
m_filePaths.v().push_back( filePath );
|
|
|
|
m_filePathsTable = generateFilePathsTable();
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
QString RimEnsembleFractureStatistics::generateFilePathsTable()
|
2021-03-15 10:23:57 -05:00
|
|
|
{
|
|
|
|
QString body;
|
|
|
|
for ( auto prop : m_filePaths.v() )
|
|
|
|
{
|
|
|
|
body.append( prop.path() + "<br>" );
|
|
|
|
}
|
|
|
|
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
2021-04-09 11:56:57 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
QList<caf::PdmOptionItemInfo>
|
|
|
|
RimEnsembleFractureStatistics::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
|
|
|
|
bool* useOptionsOnly )
|
|
|
|
{
|
|
|
|
QList<caf::PdmOptionItemInfo> options;
|
|
|
|
if ( fieldNeedingOptions == &m_selectedStatisticsType )
|
|
|
|
{
|
|
|
|
for ( size_t i = 0; i < caf::AppEnum<RimEnsembleFractureStatistics::StatisticsType>::size(); ++i )
|
|
|
|
{
|
|
|
|
caf::AppEnum<RimEnsembleFractureStatistics::StatisticsType> t =
|
|
|
|
caf::AppEnum<RimEnsembleFractureStatistics::StatisticsType>::fromIndex( i );
|
|
|
|
t.uiText();
|
|
|
|
|
|
|
|
options.push_back( caf::PdmOptionItemInfo( t.uiText(), t.value() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return options;
|
|
|
|
}
|
|
|
|
|
2021-03-15 10:23:57 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
void RimEnsembleFractureStatistics::defineEditorAttribute( const caf::PdmFieldHandle* field,
|
|
|
|
QString uiConfigName,
|
|
|
|
caf::PdmUiEditorAttribute* attribute )
|
2021-03-15 10:23:57 -05:00
|
|
|
{
|
|
|
|
if ( field == &m_filePathsTable )
|
|
|
|
{
|
|
|
|
auto myAttr = dynamic_cast<caf::PdmUiTextEditorAttribute*>( attribute );
|
|
|
|
if ( myAttr )
|
|
|
|
{
|
|
|
|
myAttr->wrapMode = caf::PdmUiTextEditorAttribute::NoWrap;
|
|
|
|
myAttr->textMode = caf::PdmUiTextEditorAttribute::HTML;
|
|
|
|
}
|
|
|
|
}
|
2021-04-09 11:56:57 -05:00
|
|
|
else if ( field == &m_selectedStatisticsType )
|
|
|
|
{
|
|
|
|
caf::PdmUiTreeSelectionEditorAttribute* attrib = dynamic_cast<caf::PdmUiTreeSelectionEditorAttribute*>( attribute );
|
|
|
|
if ( attrib )
|
|
|
|
{
|
|
|
|
attrib->showTextFilter = false;
|
|
|
|
attrib->showToggleAllCheckbox = false;
|
|
|
|
attrib->singleSelectionMode = false;
|
|
|
|
}
|
|
|
|
}
|
2021-03-15 10:23:57 -05:00
|
|
|
}
|
|
|
|
|
2021-03-26 08:56:29 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
void RimEnsembleFractureStatistics::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
|
|
|
|
const QVariant& oldValue,
|
|
|
|
const QVariant& newValue )
|
2021-03-26 08:56:29 -05:00
|
|
|
{
|
|
|
|
if ( changedField == &m_computeStatistics )
|
|
|
|
{
|
|
|
|
m_computeStatistics = false;
|
|
|
|
std::vector<QString> filePaths = computeStatistics();
|
|
|
|
RicNewStimPlanFractureTemplateFeature::createNewTemplatesFromFiles( filePaths );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-14 08:59:28 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
void RimEnsembleFractureStatistics::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
|
|
|
{
|
|
|
|
uiOrdering.add( nameField() );
|
|
|
|
uiOrdering.add( &m_filePathsTable );
|
|
|
|
uiOrdering.add( &m_meshType );
|
|
|
|
uiOrdering.add( &m_numSamplesX );
|
|
|
|
uiOrdering.add( &m_numSamplesY );
|
|
|
|
bool isUniformMesh = m_meshType() == MeshType::UNIFORM;
|
|
|
|
m_numSamplesX.uiCapability()->setUiHidden( !isUniformMesh );
|
|
|
|
m_numSamplesY.uiCapability()->setUiHidden( !isUniformMesh );
|
|
|
|
|
|
|
|
uiOrdering.add( &m_selectedStatisticsType );
|
|
|
|
uiOrdering.add( &m_computeStatistics );
|
|
|
|
}
|
|
|
|
|
2021-03-15 10:23:57 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
void RimEnsembleFractureStatistics::loadAndUpdateData()
|
2021-03-15 10:23:57 -05:00
|
|
|
{
|
|
|
|
m_filePathsTable = generateFilePathsTable();
|
2021-03-17 13:04:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
std::vector<QString> RimEnsembleFractureStatistics::computeStatistics()
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
|
|
|
auto unitSystem = RiaDefines::EclipseUnitSystem::UNITS_METRIC;
|
|
|
|
|
|
|
|
std::vector<cvf::ref<RigStimPlanFractureDefinition>> stimPlanFractureDefinitions =
|
|
|
|
readFractureDefinitions( m_filePaths.v(), unitSystem );
|
|
|
|
|
2021-03-26 04:01:36 -05:00
|
|
|
std::set<std::pair<QString, QString>> availableResults = findAllResultNames( stimPlanFractureDefinitions );
|
2021-03-17 13:04:04 -05:00
|
|
|
|
2021-04-09 06:08:35 -05:00
|
|
|
std::map<std::pair<RimEnsembleFractureStatistics::StatisticsType, QString>, std::shared_ptr<RigSlice2D>> statisticsGridsAll;
|
2021-03-17 13:04:04 -05:00
|
|
|
|
2021-04-09 11:56:57 -05:00
|
|
|
auto selectedStatistics = m_selectedStatisticsType.value();
|
|
|
|
|
2021-03-24 09:06:42 -05:00
|
|
|
// TODO: take from an incoming xml?
|
2021-04-07 08:00:52 -05:00
|
|
|
double timeStep = 1.0;
|
|
|
|
|
|
|
|
double referenceDepth = 0.0;
|
|
|
|
for ( auto definition : stimPlanFractureDefinitions )
|
|
|
|
{
|
|
|
|
referenceDepth += computeDepthOfWellPathAtFracture( definition );
|
|
|
|
}
|
|
|
|
referenceDepth /= stimPlanFractureDefinitions.size();
|
2021-03-24 09:06:42 -05:00
|
|
|
|
2021-04-14 09:16:06 -05:00
|
|
|
std::vector<double> gridXs;
|
|
|
|
std::vector<double> gridYs;
|
2021-03-24 09:06:42 -05:00
|
|
|
|
2021-03-24 13:42:00 -05:00
|
|
|
for ( auto result : availableResults )
|
2021-03-24 09:06:42 -05:00
|
|
|
{
|
2021-03-26 04:01:36 -05:00
|
|
|
RiaLogging::info( QString( "Creating statistics for result: %1" ).arg( result.first ) );
|
2021-03-24 13:42:00 -05:00
|
|
|
|
|
|
|
std::vector<cvf::cref<RigFractureGrid>> fractureGrids =
|
2021-03-26 04:01:36 -05:00
|
|
|
createFractureGrids( stimPlanFractureDefinitions, unitSystem, result.first );
|
2021-03-24 13:42:00 -05:00
|
|
|
|
|
|
|
auto [minX, maxX, minY, maxY] = findExtentsOfGrids( fractureGrids );
|
|
|
|
RiaLogging::info(
|
2021-04-09 06:08:35 -05:00
|
|
|
QString( "Ensemble Fracture Size: X = [%1, %2] Y = [%3, %4]" ).arg( minX ).arg( maxX ).arg( minY ).arg( maxY ) );
|
2021-03-24 13:42:00 -05:00
|
|
|
|
2021-04-14 09:16:06 -05:00
|
|
|
if ( m_meshType() == MeshType::UNIFORM )
|
2021-03-24 13:42:00 -05:00
|
|
|
{
|
2021-04-14 09:16:06 -05:00
|
|
|
gridXs.clear();
|
|
|
|
gridYs.clear();
|
2021-03-24 13:42:00 -05:00
|
|
|
|
2021-04-14 09:16:06 -05:00
|
|
|
int numSamplesX = m_numSamplesX();
|
|
|
|
int numSamplesY = m_numSamplesY();
|
|
|
|
|
|
|
|
double sampleDistanceX = ( maxX - minX ) / numSamplesX;
|
|
|
|
double sampleDistanceY = ( maxY - minY ) / numSamplesY;
|
|
|
|
|
|
|
|
RiaLogging::info(
|
|
|
|
QString( "Uniform Mesh. Output size: %1x%2. Sampling Distance X = %3 Sampling Distance Y = %4" )
|
|
|
|
.arg( numSamplesX )
|
|
|
|
.arg( numSamplesY )
|
|
|
|
.arg( sampleDistanceX )
|
|
|
|
.arg( sampleDistanceY ) );
|
|
|
|
|
|
|
|
for ( int y = 0; y < numSamplesY; y++ )
|
|
|
|
{
|
|
|
|
double posY = minY + y * sampleDistanceY + sampleDistanceY * 0.5;
|
|
|
|
gridYs.push_back( posY );
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( int x = 0; x < numSamplesX; x++ )
|
|
|
|
{
|
|
|
|
double posX = minX + x * sampleDistanceX + sampleDistanceX * 0.5;
|
|
|
|
gridXs.push_back( posX );
|
|
|
|
}
|
2021-03-24 13:42:00 -05:00
|
|
|
}
|
2021-03-24 09:06:42 -05:00
|
|
|
|
2021-04-14 09:16:06 -05:00
|
|
|
std::vector<std::vector<double>> samples( gridXs.size() * gridYs.size() );
|
|
|
|
sampleAllGrids( fractureGrids, gridXs, gridYs, samples );
|
2021-03-17 13:04:04 -05:00
|
|
|
|
2021-04-09 06:08:35 -05:00
|
|
|
std::map<RimEnsembleFractureStatistics::StatisticsType, std::shared_ptr<RigSlice2D>> statisticsGrids;
|
2021-04-14 09:16:06 -05:00
|
|
|
generateStatisticsGrids( samples, gridXs.size(), gridYs.size(), statisticsGrids, selectedStatistics );
|
2021-03-24 13:42:00 -05:00
|
|
|
|
|
|
|
for ( auto [statType, slice] : statisticsGrids )
|
|
|
|
{
|
2021-03-26 04:01:36 -05:00
|
|
|
auto key = std::make_pair( statType, result.first );
|
2021-03-24 13:42:00 -05:00
|
|
|
statisticsGridsAll[key] = slice;
|
|
|
|
}
|
|
|
|
}
|
2021-03-17 13:04:04 -05:00
|
|
|
|
2021-03-26 08:56:29 -05:00
|
|
|
std::vector<QString> xmlFilePaths;
|
|
|
|
|
|
|
|
// Save images in snapshot catalog relative to project directory
|
|
|
|
RiaApplication* app = RiaApplication::instance();
|
|
|
|
QString outputDirectoryPath = app->createAbsolutePathFromProjectRelativePath( "fracturestats" );
|
|
|
|
QDir outputDirectory( outputDirectoryPath );
|
|
|
|
if ( !outputDirectory.exists() )
|
|
|
|
{
|
|
|
|
outputDirectory.mkpath( outputDirectoryPath );
|
|
|
|
}
|
|
|
|
|
2021-04-09 11:56:57 -05:00
|
|
|
for ( auto t : selectedStatistics )
|
2021-03-24 06:03:19 -05:00
|
|
|
{
|
|
|
|
QString text = t.text();
|
2021-03-24 13:42:00 -05:00
|
|
|
|
|
|
|
// Get the all the properties for this statistics type
|
|
|
|
std::vector<std::shared_ptr<RigSlice2D>> statisticsSlices;
|
2021-03-26 04:01:36 -05:00
|
|
|
std::vector<std::pair<QString, QString>> properties;
|
2021-03-24 13:42:00 -05:00
|
|
|
for ( auto result : availableResults )
|
|
|
|
{
|
|
|
|
properties.push_back( result );
|
2021-03-26 04:01:36 -05:00
|
|
|
std::shared_ptr<RigSlice2D> slice = statisticsGridsAll[std::make_pair( t.value(), result.first )];
|
2021-03-24 13:42:00 -05:00
|
|
|
statisticsSlices.push_back( slice );
|
|
|
|
|
2021-03-26 08:56:29 -05:00
|
|
|
QString csvFilePath = outputDirectoryPath + "/" + text + "-" + result.first + ".csv";
|
|
|
|
writeStatisticsToCsv( csvFilePath, *slice );
|
2021-03-24 13:42:00 -05:00
|
|
|
}
|
2021-03-24 09:06:42 -05:00
|
|
|
|
2021-03-26 08:56:29 -05:00
|
|
|
QString xmlFilePath = outputDirectoryPath + "/" + name() + "-" + text + ".xml";
|
|
|
|
|
2021-04-14 09:16:06 -05:00
|
|
|
// TODO: add offset for grid ys
|
|
|
|
std::vector<double> gridYsWithOffset;
|
|
|
|
for ( double depth : gridYs )
|
|
|
|
gridYsWithOffset.push_back( referenceDepth - depth );
|
|
|
|
|
2021-03-26 08:56:29 -05:00
|
|
|
RiaLogging::info( QString( "Writing fracture group statistics to: %1" ).arg( xmlFilePath ) );
|
2021-04-09 06:08:35 -05:00
|
|
|
RifEnsembleFractureStatisticsExporter::writeAsStimPlanXml( statisticsSlices,
|
|
|
|
properties,
|
|
|
|
xmlFilePath,
|
|
|
|
gridXs,
|
2021-04-14 09:16:06 -05:00
|
|
|
gridYsWithOffset,
|
2021-04-09 06:08:35 -05:00
|
|
|
timeStep,
|
|
|
|
unitSystem );
|
2021-03-26 08:56:29 -05:00
|
|
|
|
|
|
|
xmlFilePaths.push_back( xmlFilePath );
|
2021-03-24 06:03:19 -05:00
|
|
|
}
|
2021-03-26 08:56:29 -05:00
|
|
|
|
|
|
|
return xmlFilePaths;
|
2021-03-17 13:04:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
std::vector<cvf::ref<RigStimPlanFractureDefinition>>
|
2021-04-09 06:08:35 -05:00
|
|
|
RimEnsembleFractureStatistics::readFractureDefinitions( const std::vector<caf::FilePath>& filePaths,
|
|
|
|
RiaDefines::EclipseUnitSystem unitSystem ) const
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
|
|
|
double conductivityScaleFactor = 1.0;
|
|
|
|
|
|
|
|
std::vector<cvf::ref<RigStimPlanFractureDefinition>> results;
|
|
|
|
for ( auto filePath : m_filePaths.v() )
|
|
|
|
{
|
|
|
|
RiaLogging::info( QString( "Loading file: %1" ).arg( filePath.path() ) );
|
|
|
|
QString errorMessage;
|
|
|
|
cvf::ref<RigStimPlanFractureDefinition> stimPlanFractureDefinitionData =
|
|
|
|
RifStimPlanXmlReader::readStimPlanXMLFile( filePath.path(),
|
|
|
|
conductivityScaleFactor,
|
|
|
|
RifStimPlanXmlReader::MirrorMode::MIRROR_AUTO,
|
|
|
|
unitSystem,
|
|
|
|
&errorMessage );
|
|
|
|
if ( !errorMessage.isEmpty() )
|
|
|
|
{
|
|
|
|
RiaLogging::error( QString( "Error when reading file: '%1'" ).arg( errorMessage ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( stimPlanFractureDefinitionData.notNull() )
|
|
|
|
{
|
|
|
|
results.push_back( stimPlanFractureDefinitionData );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
std::set<std::pair<QString, QString>> RimEnsembleFractureStatistics::findAllResultNames(
|
2021-03-17 13:04:04 -05:00
|
|
|
const std::vector<cvf::ref<RigStimPlanFractureDefinition>>& stimPlanFractureDefinitions )
|
|
|
|
{
|
2021-03-26 04:01:36 -05:00
|
|
|
std::set<std::pair<QString, QString>> resultNames;
|
2021-03-17 13:04:04 -05:00
|
|
|
for ( auto stimPlanFractureDefinitionData : stimPlanFractureDefinitions )
|
|
|
|
{
|
2021-03-26 04:01:36 -05:00
|
|
|
for ( auto propertyNameWithUnit : stimPlanFractureDefinitionData->getStimPlanPropertyNamesUnits() )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
2021-03-26 04:01:36 -05:00
|
|
|
resultNames.insert( propertyNameWithUnit );
|
2021-03-17 13:04:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return resultNames;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
std::vector<cvf::cref<RigFractureGrid>> RimEnsembleFractureStatistics::createFractureGrids(
|
2021-03-17 13:04:04 -05:00
|
|
|
const std::vector<cvf::ref<RigStimPlanFractureDefinition>>& stimPlanFractureDefinitions,
|
2021-03-24 13:42:00 -05:00
|
|
|
RiaDefines::EclipseUnitSystem unitSystem,
|
|
|
|
const QString& resultNameOnFile )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
|
|
|
// Defaults to avoid scaling
|
|
|
|
double halfLengthScaleFactor = 1.0;
|
|
|
|
double heightScaleFactor = 1.0;
|
|
|
|
|
|
|
|
std::vector<cvf::cref<RigFractureGrid>> fractureGrids;
|
|
|
|
for ( auto stimPlanFractureDefinitionData : stimPlanFractureDefinitions )
|
|
|
|
{
|
|
|
|
double wellPathDepthAtFracture = computeDepthOfWellPathAtFracture( stimPlanFractureDefinitionData );
|
|
|
|
|
|
|
|
// Always use last time steps
|
|
|
|
std::vector<double> timeSteps = stimPlanFractureDefinitionData->timeSteps();
|
|
|
|
int activeTimeStepIndex = timeSteps.size() - 1;
|
|
|
|
|
|
|
|
cvf::cref<RigFractureGrid> fractureGrid =
|
2021-03-24 13:42:00 -05:00
|
|
|
stimPlanFractureDefinitionData->createFractureGrid( resultNameOnFile,
|
2021-03-17 13:04:04 -05:00
|
|
|
activeTimeStepIndex,
|
|
|
|
halfLengthScaleFactor,
|
|
|
|
heightScaleFactor,
|
|
|
|
wellPathDepthAtFracture,
|
|
|
|
unitSystem );
|
|
|
|
|
|
|
|
if ( fractureGrid.notNull() )
|
|
|
|
{
|
|
|
|
fractureGrids.push_back( fractureGrid );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return fractureGrids;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
std::tuple<double, double, double, double>
|
2021-04-09 06:08:35 -05:00
|
|
|
RimEnsembleFractureStatistics::findExtentsOfGrids( const std::vector<cvf::cref<RigFractureGrid>>& fractureGrids )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
|
|
|
// Find min and max extent of all the grids
|
|
|
|
double minX = std::numeric_limits<double>::max();
|
|
|
|
double maxX = -std::numeric_limits<double>::max();
|
|
|
|
double minY = std::numeric_limits<double>::max();
|
|
|
|
double maxY = -std::numeric_limits<double>::max();
|
|
|
|
|
|
|
|
for ( auto fractureGrid : fractureGrids )
|
|
|
|
{
|
|
|
|
for ( auto fractureCell : fractureGrid->fractureCells() )
|
|
|
|
{
|
|
|
|
for ( auto polygon : fractureCell.getPolygon() )
|
|
|
|
{
|
|
|
|
minX = std::min( minX, polygon.x() );
|
|
|
|
maxX = std::max( maxX, polygon.x() );
|
|
|
|
minY = std::min( minY, polygon.y() );
|
|
|
|
maxY = std::max( maxY, polygon.y() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_tuple( minX, maxX, minY, maxY );
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
bool RimEnsembleFractureStatistics::isCoordinateInsideFractureCell( double x, double y, const RigFractureCell& cell )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
|
|
|
const cvf::Vec3d& minPoint = cell.getPolygon()[0];
|
|
|
|
const cvf::Vec3d& maxPoint = cell.getPolygon()[2];
|
|
|
|
// TODO: Investigate strange ordering for y coords.
|
|
|
|
return ( x > minPoint.x() && x <= maxPoint.x() && y <= minPoint.y() && y > maxPoint.y() );
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
double RimEnsembleFractureStatistics::computeDepthOfWellPathAtFracture(
|
2021-03-17 13:04:04 -05:00
|
|
|
cvf::ref<RigStimPlanFractureDefinition> stimPlanFractureDefinitionData )
|
|
|
|
{
|
|
|
|
double firstTvd = stimPlanFractureDefinitionData->topPerfTvd();
|
|
|
|
double lastTvd = stimPlanFractureDefinitionData->bottomPerfTvd();
|
|
|
|
|
|
|
|
if ( firstTvd != HUGE_VAL && lastTvd != HUGE_VAL )
|
|
|
|
{
|
|
|
|
return ( firstTvd + lastTvd ) / 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
firstTvd = stimPlanFractureDefinitionData->minDepth();
|
|
|
|
lastTvd = stimPlanFractureDefinitionData->maxDepth();
|
|
|
|
return ( firstTvd + lastTvd ) / 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
void RimEnsembleFractureStatistics::sampleAllGrids( const std::vector<cvf::cref<RigFractureGrid>>& fractureGrids,
|
2021-04-14 09:16:06 -05:00
|
|
|
const std::vector<double>& samplesX,
|
|
|
|
const std::vector<double>& samplesY,
|
|
|
|
std::vector<std::vector<double>>& samples )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
2021-04-14 09:16:06 -05:00
|
|
|
for ( size_t y = 0; y < samplesY.size(); y++ )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
2021-04-14 09:16:06 -05:00
|
|
|
for ( size_t x = 0; x < samplesX.size(); x++ )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
2021-04-14 09:16:06 -05:00
|
|
|
double posX = samplesX[x];
|
|
|
|
double posY = samplesY[y];
|
2021-03-17 13:04:04 -05:00
|
|
|
|
|
|
|
for ( auto fractureGrid : fractureGrids )
|
|
|
|
{
|
|
|
|
for ( auto fractureCell : fractureGrid->fractureCells() )
|
|
|
|
{
|
|
|
|
if ( isCoordinateInsideFractureCell( posX, posY, fractureCell ) )
|
|
|
|
{
|
2021-04-14 09:16:06 -05:00
|
|
|
size_t idx = y * samplesX.size() + x;
|
2021-03-17 13:04:04 -05:00
|
|
|
samples[idx].push_back( fractureCell.getConductivityValue() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
bool RimEnsembleFractureStatistics::writeStatisticsToCsv( const QString& filePath, const RigSlice2D& samples )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
|
|
|
QFile data( filePath );
|
|
|
|
if ( !data.open( QFile::WriteOnly | QFile::Truncate ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QTextStream stream( &data );
|
|
|
|
QString fieldSeparator = RiaPreferences::current()->csvTextExportFieldSeparator;
|
|
|
|
RifCsvDataTableFormatter formatter( stream, fieldSeparator );
|
|
|
|
|
|
|
|
std::vector<RifTextDataTableColumn> header;
|
|
|
|
for ( size_t y = 0; y < samples.ny(); y++ )
|
|
|
|
header.push_back( RifTextDataTableColumn( "", RifTextDataTableDoubleFormat::RIF_FLOAT ) );
|
|
|
|
formatter.header( header );
|
|
|
|
|
|
|
|
for ( size_t y = 0; y < samples.ny(); y++ )
|
|
|
|
{
|
|
|
|
for ( size_t x = 0; x < samples.nx(); x++ )
|
|
|
|
{
|
|
|
|
formatter.add( samples.getValue( x, y ) );
|
|
|
|
}
|
|
|
|
formatter.rowCompleted();
|
|
|
|
}
|
|
|
|
formatter.tableCompleted();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-04-09 06:08:35 -05:00
|
|
|
void RimEnsembleFractureStatistics::generateStatisticsGrids(
|
|
|
|
const std::vector<std::vector<double>>& samples,
|
2021-04-14 09:16:06 -05:00
|
|
|
size_t numSamplesX,
|
|
|
|
size_t numSamplesY,
|
2021-04-09 11:56:57 -05:00
|
|
|
std::map<RimEnsembleFractureStatistics::StatisticsType, std::shared_ptr<RigSlice2D>>& statisticsGrids,
|
|
|
|
const std::vector<caf::AppEnum<RimEnsembleFractureStatistics::StatisticsType>>& statisticsTypes )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
2021-04-09 11:56:57 -05:00
|
|
|
for ( auto t : statisticsTypes )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
|
|
|
std::shared_ptr<RigSlice2D> grid = std::make_shared<RigSlice2D>( numSamplesX, numSamplesY );
|
2021-04-09 11:56:57 -05:00
|
|
|
statisticsGrids[t.value()] = grid;
|
2021-03-17 13:04:04 -05:00
|
|
|
}
|
|
|
|
|
2021-04-09 11:56:57 -05:00
|
|
|
auto isCalculationEnabled = []( StatisticsType t, auto statisticsTypes ) {
|
|
|
|
return std::find( statisticsTypes.begin(), statisticsTypes.end(), t ) != statisticsTypes.end();
|
|
|
|
};
|
|
|
|
|
|
|
|
bool calculateMin = isCalculationEnabled( StatisticsType::MIN, statisticsTypes );
|
|
|
|
bool calculateMax = isCalculationEnabled( StatisticsType::MAX, statisticsTypes );
|
|
|
|
bool calculateMean = isCalculationEnabled( StatisticsType::MEAN, statisticsTypes );
|
|
|
|
bool calculateP10 = isCalculationEnabled( StatisticsType::P10, statisticsTypes );
|
|
|
|
bool calculateP50 = isCalculationEnabled( StatisticsType::P50, statisticsTypes );
|
|
|
|
bool calculateP90 = isCalculationEnabled( StatisticsType::P90, statisticsTypes );
|
|
|
|
bool calculateOccurrence = isCalculationEnabled( StatisticsType::OCCURRENCE, statisticsTypes );
|
|
|
|
|
2021-04-14 09:16:06 -05:00
|
|
|
for ( size_t y = 0; y < numSamplesY; y++ )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
2021-04-14 09:16:06 -05:00
|
|
|
for ( size_t x = 0; x < numSamplesX; x++ )
|
2021-03-17 13:04:04 -05:00
|
|
|
{
|
|
|
|
size_t idx = y * numSamplesX + x;
|
2021-04-09 11:56:57 -05:00
|
|
|
|
|
|
|
if ( calculateMin || calculateMax || calculateMean )
|
|
|
|
{
|
|
|
|
double min;
|
|
|
|
double max;
|
|
|
|
double sum;
|
|
|
|
double range;
|
|
|
|
double mean;
|
|
|
|
double dev;
|
|
|
|
RigStatisticsMath::calculateBasicStatistics( samples[idx], &min, &max, &sum, &range, &mean, &dev );
|
|
|
|
|
|
|
|
if ( calculateMean )
|
|
|
|
statisticsGrids[RimEnsembleFractureStatistics::StatisticsType::MEAN]->setValue( x, y, mean );
|
|
|
|
|
|
|
|
if ( calculateMin )
|
|
|
|
statisticsGrids[RimEnsembleFractureStatistics::StatisticsType::MIN]->setValue( x, y, min );
|
|
|
|
|
|
|
|
if ( calculateMax )
|
|
|
|
statisticsGrids[RimEnsembleFractureStatistics::StatisticsType::MAX]->setValue( x, y, max );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( calculateP10 || calculateP50 || calculateP90 )
|
|
|
|
{
|
|
|
|
double p10;
|
|
|
|
double p50;
|
|
|
|
double p90;
|
|
|
|
double mean;
|
|
|
|
RigStatisticsMath::calculateStatisticsCurves( samples[idx], &p10, &p50, &p90, &mean );
|
|
|
|
|
|
|
|
if ( calculateP10 )
|
|
|
|
statisticsGrids[RimEnsembleFractureStatistics::StatisticsType::P10]->setValue( x, y, p10 );
|
|
|
|
|
|
|
|
if ( calculateP50 )
|
|
|
|
statisticsGrids[RimEnsembleFractureStatistics::StatisticsType::P50]->setValue( x, y, p50 );
|
|
|
|
|
|
|
|
if ( calculateP90 )
|
|
|
|
statisticsGrids[RimEnsembleFractureStatistics::StatisticsType::P90]->setValue( x, y, p90 );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( calculateOccurrence )
|
|
|
|
{
|
|
|
|
statisticsGrids[RimEnsembleFractureStatistics::StatisticsType::OCCURRENCE]->setValue( x,
|
|
|
|
y,
|
|
|
|
samples[idx].size() );
|
|
|
|
}
|
2021-03-17 13:04:04 -05:00
|
|
|
}
|
|
|
|
}
|
2021-03-15 10:23:57 -05:00
|
|
|
}
|