mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
* #9773 Refactor ensemble import dialog. * #9773 Add support for ensemble import of StimPlan/Reveal summary data. * #9773 Add method for finding min and max time steps. * #9773 Add option for resampling to hour intervals. * #9773 Add option for resampling to minute intervals. * #9773 Ensemble statistics: determine sub-sampling period dynamically. * Use RiaWeightedMeanCalculator for curve resampling. * Add HOUR and MINUTE to date time app enum. * #9773 Generate better ensembles for StimPlan summaries. * #9773 Fix parameters.txt lookup for StimPlan summaries * Refactor: Improve interface of RicImportSummaryCasesFreature::createSummaryCasesFromFiles Co-authored-by: Magne Sjaastad <magne.sjaastad@ceetronsolutions.com>
820 lines
35 KiB
C++
820 lines
35 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2019- 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.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "RicSummaryPlotFeatureImpl.h"
|
|
|
|
#include "RiaApplication.h"
|
|
#include "RiaColorTables.h"
|
|
#include "RiaDefines.h"
|
|
#include "RiaEclipseFileNameTools.h"
|
|
#include "RiaGuiApplication.h"
|
|
#include "RiaImportEclipseCaseTools.h"
|
|
#include "RiaLogging.h"
|
|
#include "RiaPreferencesSummary.h"
|
|
#include "RiaSummaryStringTools.h"
|
|
#include "RiaTextStringTools.h"
|
|
|
|
#include "PlotBuilderCommands/RicSummaryPlotBuilder.h"
|
|
#include "RicCreateSummaryCaseCollectionFeature.h"
|
|
#include "RicImportGeneralDataFeature.h"
|
|
#include "RicImportSummaryCasesFeature.h"
|
|
#include "WellLogCommands/RicWellLogPlotCurveFeatureImpl.h"
|
|
|
|
#include "RifSummaryReaderInterface.h"
|
|
|
|
#include "RigCaseCellResultsData.h"
|
|
#include "RigEclipseCaseData.h"
|
|
#include "RigEclipseResultAddress.h"
|
|
|
|
#include "RimEclipseCase.h"
|
|
#include "RimEclipseCaseCollection.h"
|
|
#include "RimEclipseResultCase.h"
|
|
#include "RimEnsembleCurveSet.h"
|
|
#include "RimEnsembleCurveSetCollection.h"
|
|
#include "RimGridTimeHistoryCurve.h"
|
|
#include "RimMainPlotCollection.h"
|
|
#include "RimOilField.h"
|
|
#include "RimProject.h"
|
|
#include "RimSummaryCase.h"
|
|
#include "RimSummaryCurve.h"
|
|
#include "RimSummaryMultiPlotCollection.h"
|
|
#include "RimSummaryPlot.h"
|
|
|
|
#include "RiuMainWindow.h"
|
|
#include "RiuPlotMainWindow.h"
|
|
#include "RiuPlotMainWindowTools.h"
|
|
|
|
#include <QFileInfo>
|
|
#include <QRegularExpression>
|
|
#include <QStringList>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimSummaryCurve*> RicSummaryPlotFeatureImpl::addDefaultCurvesToPlot( RimSummaryPlot* plot, RimSummaryCase* summaryCase )
|
|
{
|
|
RiaPreferencesSummary* prefs = RiaPreferencesSummary::current();
|
|
|
|
QString curvesTextFilter = prefs->defaultSummaryCurvesTextFilter();
|
|
QStringList curveFilters = RiaTextStringTools::splitSkipEmptyParts( curvesTextFilter, ";" );
|
|
|
|
bool addHistoryCurve = false;
|
|
|
|
return addCurvesFromAddressFiltersToPlot( curveFilters, plot, summaryCase, addHistoryCurve );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimSummaryCurve* RicSummaryPlotFeatureImpl::createHistoryCurve( const RifEclipseSummaryAddress& addr, RimSummaryCase* summaryCasesToUse )
|
|
{
|
|
RifEclipseSummaryAddress historyAddr = addr;
|
|
historyAddr.setVectorName( historyAddr.vectorName() + "H" );
|
|
if ( summaryCasesToUse->summaryReader()->allResultAddresses().count( historyAddr ) )
|
|
{
|
|
return createCurve( summaryCasesToUse, historyAddr );
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RigGridCellResultAddress> RigGridCellResultAddress::createGridCellAddressesFromFilter( const QString& text )
|
|
{
|
|
std::vector<RigGridCellResultAddress> addresses;
|
|
QStringList addressParts = text.split( ":" );
|
|
|
|
if ( addressParts.size() > 1 )
|
|
{
|
|
QString resultVarName = addressParts[0];
|
|
size_t gridIdx = 0;
|
|
if ( addressParts.size() > 2 )
|
|
{
|
|
gridIdx = addressParts[1].toULong();
|
|
}
|
|
|
|
QString ijkText = addressParts.back();
|
|
QStringList ijkTextParts = ijkText.split( "," );
|
|
if ( ijkTextParts.size() == 3 )
|
|
{
|
|
bool isOk = true;
|
|
bool allOk = true;
|
|
size_t i = ijkTextParts[0].toULong( &isOk );
|
|
allOk &= isOk;
|
|
size_t j = ijkTextParts[1].toULong( &isOk );
|
|
allOk &= isOk;
|
|
size_t k = ijkTextParts[2].toULong( &isOk );
|
|
allOk &= isOk;
|
|
|
|
if ( allOk )
|
|
{
|
|
addresses.emplace_back( RigGridCellResultAddress( gridIdx, i - 1, j - 1, k - 1, RigEclipseResultAddress( resultVarName ) ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return addresses;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimEclipseCase*> openEclipseCasesForCellPlotting( QStringList gridFileNames )
|
|
{
|
|
std::vector<RimEclipseCase*> openedCases;
|
|
|
|
RimEclipseCaseCollection* analysisModels = RimProject::current()->activeOilField()->analysisModels();
|
|
for ( const QString& fileName : gridFileNames )
|
|
{
|
|
QFileInfo gridFileInfo( fileName );
|
|
|
|
if ( !gridFileInfo.exists() ) continue;
|
|
|
|
QString caseName = gridFileInfo.completeBaseName();
|
|
|
|
RimEclipseResultCase* rimResultReservoir = new RimEclipseResultCase();
|
|
rimResultReservoir->setCaseInfo( caseName, fileName );
|
|
|
|
analysisModels->cases.push_back( rimResultReservoir );
|
|
|
|
if ( !rimResultReservoir->openReserviorCase() )
|
|
{
|
|
analysisModels->removeCaseFromAllGroups( rimResultReservoir );
|
|
|
|
delete rimResultReservoir;
|
|
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
openedCases.push_back( rimResultReservoir );
|
|
}
|
|
}
|
|
|
|
analysisModels->updateConnectedEditors();
|
|
|
|
return openedCases;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicSummaryPlotFeatureImpl::createSummaryPlotsFromArgumentLine( const QStringList& arguments )
|
|
{
|
|
// Split arguments in options, vectors and filenames
|
|
|
|
QStringList options;
|
|
QStringList allCurveAddressFilters;
|
|
QStringList summaryFileNames;
|
|
QStringList gridFileNames;
|
|
QString ensembleColoringParameter;
|
|
|
|
std::set<QString> validOptions = { "-help", "-h", "-nl", "-s", "-n", "-e", "-c", "-cl" };
|
|
|
|
for ( int optionIdx = 0; optionIdx < arguments.size(); ++optionIdx )
|
|
{
|
|
if ( arguments[optionIdx].startsWith( "-" ) )
|
|
{
|
|
if ( arguments[optionIdx] == "-help" )
|
|
{
|
|
QString text = RicSummaryPlotFeatureImpl::summaryPlotCommandLineHelpText();
|
|
RiaApplication::instance()->showFormattedTextInMessageBoxOrConsole( text );
|
|
|
|
return;
|
|
}
|
|
|
|
if ( validOptions.count( arguments[optionIdx] ) )
|
|
{
|
|
options.push_back( arguments[optionIdx] );
|
|
|
|
if ( arguments[optionIdx] == "-c" || arguments[optionIdx] == "-cl" )
|
|
{
|
|
optionIdx++;
|
|
if ( optionIdx < arguments.size() ) ensembleColoringParameter = arguments[optionIdx];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RiaLogging::error( "The summaryplot option: \"" + arguments[optionIdx] + "\" is unknown." );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RiaEclipseFileNameTools nameTool( arguments[optionIdx] );
|
|
|
|
for ( const auto& fileName : nameTool.findSummaryFileCandidates() )
|
|
{
|
|
if ( !fileName.isEmpty() ) summaryFileNames.push_back( fileName );
|
|
}
|
|
|
|
QString gridFileName = nameTool.findRelatedGridFile();
|
|
if ( !gridFileName.isEmpty() ) gridFileNames.push_back( gridFileName );
|
|
|
|
if ( summaryFileNames.empty() && gridFileNames.empty() )
|
|
{
|
|
// Remove space from address string https://github.com/OPM/ResInsight/issues/9707
|
|
|
|
QString stringWithoutSpaces = arguments[optionIdx];
|
|
stringWithoutSpaces.remove( " " );
|
|
|
|
allCurveAddressFilters.push_back( stringWithoutSpaces );
|
|
}
|
|
}
|
|
}
|
|
|
|
summaryFileNames.removeDuplicates();
|
|
gridFileNames.removeDuplicates();
|
|
|
|
if ( allCurveAddressFilters.empty() )
|
|
{
|
|
RiaLogging::error( "Needs at least one vector to create a plot." );
|
|
}
|
|
|
|
bool hideLegend = options.contains( "-nl" );
|
|
bool addHistoryCurves = options.contains( "-h" );
|
|
bool isNormalizedY = options.contains( "-n" );
|
|
bool isSinglePlot = options.contains( "-s" );
|
|
|
|
EnsembleColoringType ensembleColoringStyle = EnsembleColoringType::NONE;
|
|
{
|
|
int e_pos = options.lastIndexOf( "-e" );
|
|
int c_pos = options.lastIndexOf( "-c" );
|
|
int cl_pos = options.lastIndexOf( "-cl" );
|
|
|
|
int lastEnsembleOptionPos = -1;
|
|
if ( e_pos > lastEnsembleOptionPos )
|
|
{
|
|
lastEnsembleOptionPos = e_pos;
|
|
ensembleColoringStyle = EnsembleColoringType::SINGLE_COLOR;
|
|
}
|
|
if ( c_pos > lastEnsembleOptionPos )
|
|
{
|
|
lastEnsembleOptionPos = c_pos;
|
|
ensembleColoringStyle = EnsembleColoringType::PARAMETER;
|
|
}
|
|
if ( cl_pos > lastEnsembleOptionPos )
|
|
{
|
|
lastEnsembleOptionPos = cl_pos;
|
|
ensembleColoringStyle = EnsembleColoringType::LOG_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if ( summaryFileNames.empty() )
|
|
{
|
|
RiaLogging::error( "Needs at least one summary case to create a plot." );
|
|
return;
|
|
}
|
|
|
|
bool isEnsembleMode = ensembleColoringStyle != EnsembleColoringType::NONE;
|
|
|
|
RicImportSummaryCasesFeature::CreateConfig createConfig{ .fileType = RiaDefines::FileType::SMSPEC,
|
|
.ensembleOrGroup = isEnsembleMode,
|
|
.allowDialogs = true };
|
|
auto [isOk, summaryCasesToUse] = RicImportSummaryCasesFeature::createSummaryCasesFromFiles( summaryFileNames, createConfig );
|
|
if ( !isOk || summaryCasesToUse.empty() )
|
|
{
|
|
RiaLogging::error( "Needs at least one summary case to create a plot." );
|
|
return;
|
|
}
|
|
|
|
RicImportSummaryCasesFeature::addSummaryCases( summaryCasesToUse );
|
|
|
|
RiaApplication::instance()->setLastUsedDialogDirectory( RiaDefines::defaultDirectoryLabel( RiaDefines::ImportFileType::ECLIPSE_SUMMARY_FILE ),
|
|
QFileInfo( summaryFileNames[0] ).absolutePath() );
|
|
|
|
// Sort in summary and grid curve addresses
|
|
QStringList gridResultAddressFilters;
|
|
QStringList summaryAddressFilters;
|
|
|
|
RimSummaryPlot* lastPlotCreated = nullptr;
|
|
|
|
RiaSummaryStringTools::splitAddressFiltersInGridAndSummary( summaryCasesToUse[0],
|
|
allCurveAddressFilters,
|
|
&summaryAddressFilters,
|
|
&gridResultAddressFilters );
|
|
|
|
if ( summaryAddressFilters.size() )
|
|
{
|
|
RimSummaryCaseCollection* ensemble = nullptr;
|
|
|
|
if ( isEnsembleMode )
|
|
{
|
|
ensemble = RicCreateSummaryCaseCollectionFeature::groupSummaryCases( summaryCasesToUse, "Ensemble", true );
|
|
}
|
|
|
|
if ( isSinglePlot )
|
|
{
|
|
RimSummaryPlot* newPlot = nullptr;
|
|
if ( ensemble )
|
|
{
|
|
newPlot = createSummaryPlotForEnsemble( summaryCasesToUse,
|
|
ensemble,
|
|
summaryAddressFilters,
|
|
addHistoryCurves,
|
|
ensembleColoringStyle,
|
|
ensembleColoringParameter );
|
|
}
|
|
else
|
|
{
|
|
newPlot = createSummaryPlotForCases( summaryCasesToUse, summaryAddressFilters, addHistoryCurves );
|
|
}
|
|
|
|
lastPlotCreated = newPlot;
|
|
|
|
newPlot->setLegendsVisible( !hideLegend );
|
|
newPlot->setNormalizationEnabled( isNormalizedY );
|
|
newPlot->loadDataAndUpdate();
|
|
|
|
RicSummaryPlotBuilder::createAndAppendSingleSummaryMultiPlot( newPlot );
|
|
}
|
|
else // Multiple plots, one for each separate summary address, put them all in a summary multiplot
|
|
{
|
|
std::vector<RimSummaryPlot*> summaryPlots = createMultipleSummaryPlotsFromAddresses( summaryCasesToUse,
|
|
ensemble,
|
|
summaryAddressFilters,
|
|
addHistoryCurves,
|
|
ensembleColoringStyle,
|
|
ensembleColoringParameter );
|
|
|
|
lastPlotCreated = summaryPlots.back();
|
|
|
|
for ( auto summaryPlot : summaryPlots )
|
|
{
|
|
summaryPlot->setLegendsVisible( !hideLegend );
|
|
summaryPlot->setNormalizationEnabled( isNormalizedY );
|
|
summaryPlot->loadDataAndUpdate();
|
|
}
|
|
|
|
RicSummaryPlotBuilder::createAndAppendSummaryMultiPlot( summaryPlots );
|
|
}
|
|
}
|
|
|
|
// Grid Cell Result vectors
|
|
|
|
if ( gridResultAddressFilters.size() )
|
|
{
|
|
// Todo: Use identical grid case import if -e -c or -cl
|
|
|
|
std::vector<RimEclipseCase*> gridCasesToPlotFrom = openEclipseCasesForCellPlotting( gridFileNames );
|
|
|
|
if ( isSinglePlot )
|
|
{
|
|
std::vector<RimGridTimeHistoryCurve*> createdCurves;
|
|
int curveColorIndex = 0;
|
|
for ( const QString& gridAddressFilter : gridResultAddressFilters )
|
|
{
|
|
std::vector<RigGridCellResultAddress> cellResAddrs =
|
|
RigGridCellResultAddress::createGridCellAddressesFromFilter( gridAddressFilter );
|
|
|
|
for ( RigGridCellResultAddress cellResAddr : cellResAddrs )
|
|
{
|
|
for ( RimEclipseCase* eclCase : gridCasesToPlotFrom )
|
|
{
|
|
if ( !( eclCase->eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL ) &&
|
|
eclCase->eclipseCaseData()
|
|
->results( RiaDefines::PorosityModelType::MATRIX_MODEL )
|
|
->resultInfo( cellResAddr.eclipseResultAddress ) ) )
|
|
{
|
|
RiaLogging::warning( "Could not find a restart result property with name: \"" +
|
|
cellResAddr.eclipseResultAddress.resultName() + "\"" );
|
|
continue;
|
|
}
|
|
|
|
RimGridTimeHistoryCurve* newCurve = new RimGridTimeHistoryCurve();
|
|
newCurve->setFromEclipseCellAndResult( eclCase,
|
|
cellResAddr.gridIndex,
|
|
cellResAddr.i,
|
|
cellResAddr.j,
|
|
cellResAddr.k,
|
|
cellResAddr.eclipseResultAddress );
|
|
newCurve->setLineThickness( 2 );
|
|
cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable( curveColorIndex );
|
|
newCurve->setColor( curveColor );
|
|
if ( !isEnsembleMode ) ++curveColorIndex;
|
|
|
|
createdCurves.push_back( newCurve );
|
|
}
|
|
if ( isEnsembleMode ) ++curveColorIndex;
|
|
}
|
|
}
|
|
|
|
if ( createdCurves.size() )
|
|
{
|
|
RimSummaryPlot* newPlot = new RimSummaryPlot();
|
|
newPlot->enableAutoPlotTitle( true );
|
|
|
|
for ( auto curve : createdCurves )
|
|
{
|
|
newPlot->addGridTimeHistoryCurve( curve );
|
|
}
|
|
|
|
newPlot->setLegendsVisible( !hideLegend );
|
|
newPlot->setNormalizationEnabled( isNormalizedY );
|
|
newPlot->loadDataAndUpdate();
|
|
lastPlotCreated = newPlot;
|
|
|
|
RicSummaryPlotBuilder::createAndAppendSingleSummaryMultiPlot( newPlot );
|
|
}
|
|
}
|
|
else // Multiplot
|
|
{
|
|
int curveColorIndex = 0;
|
|
|
|
for ( const QString& gridAddressFilter : gridResultAddressFilters )
|
|
{
|
|
std::vector<RigGridCellResultAddress> cellResAddrs =
|
|
RigGridCellResultAddress::createGridCellAddressesFromFilter( gridAddressFilter );
|
|
for ( RigGridCellResultAddress cellResAddr : cellResAddrs )
|
|
{
|
|
std::vector<RimGridTimeHistoryCurve*> createdCurves;
|
|
for ( RimEclipseCase* eclCase : gridCasesToPlotFrom )
|
|
{
|
|
if ( !( eclCase->eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL ) &&
|
|
eclCase->eclipseCaseData()
|
|
->results( RiaDefines::PorosityModelType::MATRIX_MODEL )
|
|
->resultInfo( cellResAddr.eclipseResultAddress ) ) )
|
|
{
|
|
RiaLogging::warning( "Could not find a restart result property with name: \"" +
|
|
cellResAddr.eclipseResultAddress.resultName() + "\"" );
|
|
continue;
|
|
}
|
|
RimGridTimeHistoryCurve* newCurve = new RimGridTimeHistoryCurve();
|
|
newCurve->setFromEclipseCellAndResult( eclCase,
|
|
cellResAddr.gridIndex,
|
|
cellResAddr.i,
|
|
cellResAddr.j,
|
|
cellResAddr.k,
|
|
cellResAddr.eclipseResultAddress );
|
|
newCurve->setLineThickness( 2 );
|
|
cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable( curveColorIndex );
|
|
newCurve->setColor( curveColor );
|
|
if ( !isEnsembleMode ) ++curveColorIndex;
|
|
createdCurves.push_back( newCurve );
|
|
}
|
|
|
|
if ( isEnsembleMode ) ++curveColorIndex;
|
|
|
|
if ( createdCurves.size() )
|
|
{
|
|
RimSummaryPlot* newPlot = new RimSummaryPlot();
|
|
newPlot->enableAutoPlotTitle( true );
|
|
for ( auto newCurve : createdCurves )
|
|
{
|
|
newPlot->addGridTimeHistoryCurve( newCurve );
|
|
}
|
|
newPlot->setLegendsVisible( !hideLegend );
|
|
newPlot->setNormalizationEnabled( isNormalizedY );
|
|
newPlot->loadDataAndUpdate();
|
|
lastPlotCreated = newPlot;
|
|
|
|
RicSummaryPlotBuilder::createAndAppendSingleSummaryMultiPlot( newPlot );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( lastPlotCreated )
|
|
{
|
|
RimMainPlotCollection::current()->summaryMultiPlotCollection()->updateConnectedEditors();
|
|
|
|
RiuPlotMainWindow* mpw = RiaGuiApplication::instance()->mainPlotWindow();
|
|
// Needed to avoid unnecessary activation of sub windows (plots)
|
|
// which results in population of property editor, and missing deleteLater because we are outside any event
|
|
// loop when switching object. Results in stray widgets.
|
|
mpw->setBlockViewSelectionOnSubWindowActivated( true );
|
|
RiuPlotMainWindowTools::showPlotMainWindow();
|
|
mpw->setBlockViewSelectionOnSubWindowActivated( false );
|
|
RiuPlotMainWindowTools::setExpanded( lastPlotCreated );
|
|
RiuPlotMainWindowTools::selectAsCurrentItem( lastPlotCreated );
|
|
|
|
RiuMainWindow::closeIfOpen();
|
|
}
|
|
}
|
|
|
|
RimSummaryPlot* RicSummaryPlotFeatureImpl::createSummaryPlotForEnsemble( const std::vector<RimSummaryCase*>& summaryCasesToUse,
|
|
RimSummaryCaseCollection* ensemble,
|
|
QStringList summaryAddressFilters,
|
|
bool addHistoryCurves,
|
|
EnsembleColoringType ensembleColoringStyle,
|
|
QString ensembleColoringParameter )
|
|
{
|
|
RimSummaryPlot* newPlot = new RimSummaryPlot();
|
|
newPlot->enableAutoPlotTitle( true );
|
|
|
|
if ( ensemble )
|
|
{
|
|
std::set<RifEclipseSummaryAddress> filteredAdressesFromCases =
|
|
applySummaryAddressFiltersToCases( summaryCasesToUse, summaryAddressFilters );
|
|
|
|
for ( const auto& addr : filteredAdressesFromCases )
|
|
{
|
|
auto curveSet = createCurveSet( ensemble, addr, ensembleColoringStyle, ensembleColoringParameter );
|
|
newPlot->ensembleCurveSetCollection()->addCurveSet( curveSet );
|
|
|
|
if ( addHistoryCurves && !summaryCasesToUse.empty() )
|
|
{
|
|
RimSummaryCurve* historyCurve = createHistoryCurve( addr, summaryCasesToUse[0] );
|
|
|
|
if ( historyCurve ) newPlot->addCurveNoUpdate( historyCurve );
|
|
}
|
|
}
|
|
}
|
|
newPlot->applyDefaultCurveAppearances();
|
|
|
|
return newPlot;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEnsembleCurveSet* RicSummaryPlotFeatureImpl::createCurveSet( RimSummaryCaseCollection* ensemble,
|
|
const RifEclipseSummaryAddress& addr,
|
|
EnsembleColoringType ensembleColoringStyle,
|
|
QString ensembleColoringParameter )
|
|
{
|
|
auto curveSet = new RimEnsembleCurveSet();
|
|
|
|
curveSet->setSummaryCaseCollection( ensemble );
|
|
curveSet->setSummaryAddressAndStatisticsFlag( addr );
|
|
|
|
if ( ensembleColoringStyle == EnsembleColoringType::PARAMETER || ensembleColoringStyle == EnsembleColoringType::LOG_PARAMETER )
|
|
{
|
|
curveSet->setColorMode( RimEnsembleCurveSet::ColorMode::BY_ENSEMBLE_PARAM );
|
|
curveSet->setEnsembleParameter( ensembleColoringParameter );
|
|
|
|
if ( ensembleColoringStyle == EnsembleColoringType::LOG_PARAMETER )
|
|
{
|
|
curveSet->legendConfig()->setMappingMode( RimRegularLegendConfig::MappingType::LOG10_CONTINUOUS );
|
|
}
|
|
}
|
|
|
|
return curveSet;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimSummaryPlot* RicSummaryPlotFeatureImpl::createSummaryPlotForCases( const std::vector<RimSummaryCase*>& summaryCasesToUse,
|
|
QStringList summaryAddressFilters,
|
|
bool addHistoryCurves /*= false */ )
|
|
{
|
|
RimSummaryPlot* newPlot = new RimSummaryPlot();
|
|
newPlot->enableAutoPlotTitle( true );
|
|
|
|
for ( RimSummaryCase* sumCase : summaryCasesToUse )
|
|
{
|
|
RicSummaryPlotFeatureImpl::addCurvesFromAddressFiltersToPlot( summaryAddressFilters, newPlot, sumCase, addHistoryCurves );
|
|
}
|
|
|
|
newPlot->applyDefaultCurveAppearances();
|
|
|
|
return newPlot;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimSummaryPlot*> RicSummaryPlotFeatureImpl::createMultipleSummaryPlotsFromAddresses(
|
|
const std::vector<RimSummaryCase*>& summaryCasesToUse,
|
|
RimSummaryCaseCollection* ensemble,
|
|
QStringList summaryAddressFilters,
|
|
bool addHistoryCurves,
|
|
EnsembleColoringType ensembleColoringStyle /*= EnsembleColoringType::NONE*/,
|
|
QString ensembleColoringParameter /*= "" */ )
|
|
{
|
|
std::vector<RimSummaryPlot*> newSummaryPlots;
|
|
|
|
std::set<RifEclipseSummaryAddress> filteredAdressesFromCases =
|
|
applySummaryAddressFiltersToCases( summaryCasesToUse, summaryAddressFilters );
|
|
|
|
for ( const auto& addr : filteredAdressesFromCases )
|
|
{
|
|
std::vector<RimSummaryCurve*> createdCurves;
|
|
std::vector<RimEnsembleCurveSet*> createdEnsembleCurveSets;
|
|
if ( ensemble )
|
|
{
|
|
auto curveSet = createCurveSet( ensemble, addr, ensembleColoringStyle, ensembleColoringParameter );
|
|
createdEnsembleCurveSets.push_back( curveSet );
|
|
}
|
|
else
|
|
{
|
|
for ( RimSummaryCase* sumCase : summaryCasesToUse )
|
|
{
|
|
const std::set<RifEclipseSummaryAddress>& allAddrsInCase = sumCase->summaryReader()->allResultAddresses();
|
|
if ( allAddrsInCase.count( addr ) )
|
|
{
|
|
auto* newCurve = createCurve( sumCase, addr );
|
|
createdCurves.push_back( newCurve );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( addHistoryCurves )
|
|
{
|
|
RimSummaryCurve* historyCurve = createHistoryCurve( addr, summaryCasesToUse[0] );
|
|
if ( historyCurve ) createdCurves.push_back( historyCurve );
|
|
}
|
|
|
|
if ( createdCurves.size() || createdEnsembleCurveSets.size() )
|
|
{
|
|
RimSummaryPlot* newPlot = new RimSummaryPlot();
|
|
newPlot->enableAutoPlotTitle( true );
|
|
|
|
for ( auto curve : createdCurves )
|
|
{
|
|
newPlot->addCurveNoUpdate( curve );
|
|
}
|
|
|
|
for ( auto curveSet : createdEnsembleCurveSets )
|
|
{
|
|
newPlot->ensembleCurveSetCollection()->addCurveSet( curveSet );
|
|
}
|
|
|
|
newPlot->applyDefaultCurveAppearances();
|
|
newSummaryPlots.push_back( newPlot );
|
|
}
|
|
}
|
|
return newSummaryPlots;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::set<RifEclipseSummaryAddress>
|
|
RicSummaryPlotFeatureImpl::applySummaryAddressFiltersToCases( const std::vector<RimSummaryCase*>& summaryCasesToUse,
|
|
const QStringList& summaryAddressFilters )
|
|
{
|
|
std::set<RifEclipseSummaryAddress> filteredAdressesFromCases;
|
|
for ( RimSummaryCase* sumCase : summaryCasesToUse )
|
|
{
|
|
const std::set<RifEclipseSummaryAddress>& addrs = sumCase->summaryReader()->allResultAddresses();
|
|
std::vector<bool> usedFilters;
|
|
|
|
insertFilteredAddressesInSet( summaryAddressFilters, addrs, &filteredAdressesFromCases, &usedFilters );
|
|
|
|
for ( size_t cfIdx = 0; cfIdx < usedFilters.size(); ++cfIdx )
|
|
{
|
|
if ( !usedFilters[cfIdx] )
|
|
{
|
|
RiaLogging::warning( "Vector filter \"" + summaryAddressFilters[static_cast<int>( cfIdx )] +
|
|
"\" did not match anything in case: \"" + sumCase->nativeCaseName() + "\"" );
|
|
}
|
|
}
|
|
}
|
|
return filteredAdressesFromCases;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimSummaryCurve* RicSummaryPlotFeatureImpl::createCurve( RimSummaryCase* summaryCase, const RifEclipseSummaryAddress& address )
|
|
{
|
|
auto curve = new RimSummaryCurve();
|
|
curve->setSummaryCaseY( summaryCase );
|
|
curve->setSummaryAddressYAndApplyInterpolation( address );
|
|
|
|
return curve;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimSummaryCurve*> RicSummaryPlotFeatureImpl::addCurvesFromAddressFiltersToPlot( const QStringList& curveFilters,
|
|
RimSummaryPlot* plot,
|
|
RimSummaryCase* summaryCase,
|
|
bool addHistoryCurves )
|
|
{
|
|
std::vector<RimSummaryCurve*> createdCurves;
|
|
|
|
if ( !plot ) return createdCurves;
|
|
if ( !summaryCase || !summaryCase->summaryReader() ) return createdCurves;
|
|
|
|
std::set<RifEclipseSummaryAddress> curveAddressesToUse;
|
|
|
|
const std::set<RifEclipseSummaryAddress>& addrs = summaryCase->summaryReader()->allResultAddresses();
|
|
std::vector<bool> usedFilters;
|
|
|
|
insertFilteredAddressesInSet( curveFilters, addrs, &curveAddressesToUse, &usedFilters );
|
|
|
|
for ( size_t cfIdx = 0; cfIdx < usedFilters.size(); ++cfIdx )
|
|
{
|
|
if ( !usedFilters[cfIdx] )
|
|
{
|
|
RiaLogging::warning( "Vector filter \"" + curveFilters[static_cast<int>( cfIdx )] + "\" did not match anything in case: \"" +
|
|
summaryCase->nativeCaseName() + "\"" );
|
|
}
|
|
}
|
|
|
|
if ( addHistoryCurves )
|
|
{
|
|
std::vector<RifEclipseSummaryAddress> historyAddressesToUse;
|
|
for ( RifEclipseSummaryAddress historyAddr : curveAddressesToUse )
|
|
{
|
|
historyAddr.setVectorName( historyAddr.vectorName() + "H" );
|
|
if ( addrs.count( historyAddr ) )
|
|
{
|
|
historyAddressesToUse.push_back( historyAddr );
|
|
}
|
|
}
|
|
curveAddressesToUse.insert( historyAddressesToUse.begin(), historyAddressesToUse.end() );
|
|
}
|
|
|
|
if ( !curveFilters.isEmpty() && curveAddressesToUse.empty() && !addrs.empty() )
|
|
{
|
|
// The curve filter returns no match, use first available address
|
|
|
|
curveAddressesToUse.insert( *addrs.begin() );
|
|
}
|
|
|
|
for ( const auto& addr : curveAddressesToUse )
|
|
{
|
|
auto* newCurve = createCurve( summaryCase, addr );
|
|
|
|
createdCurves.push_back( newCurve );
|
|
plot->addCurveNoUpdate( newCurve );
|
|
}
|
|
|
|
return createdCurves;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RicSummaryPlotFeatureImpl::insertFilteredAddressesInSet( const QStringList& curveFilters,
|
|
const std::set<RifEclipseSummaryAddress>& allAddressesInCase,
|
|
std::set<RifEclipseSummaryAddress>* setToInsertFilteredAddressesIn,
|
|
std::vector<bool>* usedFilters )
|
|
{
|
|
if ( allAddressesInCase.empty() ) return;
|
|
|
|
int curveFilterCount = curveFilters.size();
|
|
|
|
usedFilters->clear();
|
|
usedFilters->resize( curveFilterCount, false );
|
|
|
|
for ( const auto& addr : allAddressesInCase )
|
|
{
|
|
for ( int cfIdx = 0; cfIdx < curveFilterCount; ++cfIdx )
|
|
{
|
|
if ( addr.isUiTextMatchingFilterText( curveFilters[cfIdx] ) )
|
|
{
|
|
setToInsertFilteredAddressesIn->insert( addr );
|
|
( *usedFilters )[cfIdx] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RicSummaryPlotFeatureImpl::summaryPlotCommandLineHelpText()
|
|
{
|
|
// clang-format off
|
|
QString txt =
|
|
"The --summaryplot option has the following syntax:\n"
|
|
"\n"
|
|
"[<plotOptions>] <eclipsesummaryvectorfilters> <eclipsedatafiles>\n"
|
|
"\n"
|
|
"It creates one summary plot for each of the the summary vectors matched by the "
|
|
"<eclipsesummaryvectorfilters> using all the <eclipsedatafiles> in each plot.\n"
|
|
"The <eclipsesummaryvectorfilters> has the syntax <vectorname>[:<item>[:<subitem>[:i,j,k]]] and can be repeated.\n"
|
|
"Wildcards can also be used, eg. \"WOPT:*\" to select the total oil production from all the wells.\n"
|
|
"3D Grid properties from restart files can also be requested in the form <propertyname>:i,j,k.\n"
|
|
"The <eclipsedatafiles> can be written with or without extension.\n"
|
|
"As long as only summary vectors are requested, only the corresponding SMSPEC file will be opened for each case.\n"
|
|
"If a grid property is requested, however (eg. SOIL:20,21,1) the corresponding EGRID and restart data will be loaded as well.\n"
|
|
"\n"
|
|
"The summary plot options are: \n"
|
|
" -help\t Show this help text and ignore the rest of the options.\n"
|
|
" -h\t Include history vectors. Will be read from the summary file if the vectors exist.\n"
|
|
" \t Only history vectors from the first summary case in the project will be included.\n"
|
|
" -nl\t Omit legend in plot.\n"
|
|
" -s\t Create only one plot including all the defined vectors and cases.\n"
|
|
" -n\t Scale all curves into the range 0.0-1.0. Useful when using -s.\n"
|
|
" -e\t Import all the cases as an ensemble, and create ensemble curves sets instead of single curves.\n"
|
|
" -c <parametername>\t Same as -e, but colors the curves by the ensemble parameter <parametername> . \n"
|
|
" -cl <parametername>\t Same as -c, but uses logarithmic legend.\n";
|
|
// clang-format on
|
|
|
|
return txt;
|
|
}
|