ResInsight/ApplicationLibCode/ProjectDataModel/Summary/RimDerivedEnsembleCaseCollection.cpp

618 lines
23 KiB
C++
Raw Normal View History

2018-06-25 08:14:47 -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 "RiaQDateTimeTools.h"
2018-06-25 08:14:47 -05:00
#include "SummaryPlotCommands/RicNewDerivedEnsembleFeature.h"
#include "RimDerivedEnsembleCaseCollection.h"
#include "RimDerivedSummaryCase.h"
2018-06-25 08:14:47 -05:00
#include "RimProject.h"
#include "RimSummaryCaseCollection.h"
#include "RimSummaryCaseMainCollection.h"
#include "RifSummaryReaderInterface.h"
#include "cafPdmUiPushButtonEditor.h"
#include "cafPdmUiTreeSelectionEditor.h"
2018-06-25 08:14:47 -05:00
#include <QDateTime>
2018-06-25 08:14:47 -05:00
#include <cmath>
namespace caf
{
template <>
void caf::AppEnum<RimDerivedEnsembleCaseCollection::FixedTimeStepMode>::setUp()
{
addItem( RimDerivedEnsembleCaseCollection::FixedTimeStepMode::FIXED_TIME_STEP_NONE, "FIXED_TIME_STEP_NONE", "None" );
addItem( RimDerivedEnsembleCaseCollection::FixedTimeStepMode::FIXED_TIME_STEP_CASE_1, "FIXED_TIME_STEP_CASE_1", "Ensemble 1" );
addItem( RimDerivedEnsembleCaseCollection::FixedTimeStepMode::FIXED_TIME_STEP_CASE_2, "FIXED_TIME_STEP_CASE_2", "Ensemble 2" );
setDefault( RimDerivedEnsembleCaseCollection::FixedTimeStepMode::FIXED_TIME_STEP_NONE );
}
} // namespace caf
CAF_PDM_SOURCE_INIT( RimDerivedEnsembleCaseCollection, "RimDerivedEnsembleCaseCollection" );
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDerivedEnsembleCaseCollection::RimDerivedEnsembleCaseCollection()
{
CAF_PDM_InitObject( "Delta Ensemble", ":/SummaryEnsemble.svg" );
2018-06-25 08:14:47 -05:00
CAF_PDM_InitFieldNoDefault( &m_ensemble1, "Ensemble1", "Ensemble 1" );
m_ensemble1.uiCapability()->setUiTreeChildrenHidden( true );
m_ensemble1.uiCapability()->setAutoAddingOptionFromValue( false );
2018-06-25 08:14:47 -05:00
CAF_PDM_InitFieldNoDefault( &m_ensemble2, "Ensemble2", "Ensemble 2" );
m_ensemble1.uiCapability()->setUiTreeChildrenHidden( true );
m_ensemble2.uiCapability()->setAutoAddingOptionFromValue( false );
2018-06-25 08:14:47 -05:00
CAF_PDM_InitFieldNoDefault( &m_operator, "Operator", "Operator" );
2018-06-25 08:14:47 -05:00
CAF_PDM_InitField( &m_swapEnsemblesButton, "SwapEnsembles", false, "SwapEnsembles" );
m_swapEnsemblesButton.uiCapability()->setUiEditorTypeName( caf::PdmUiPushButtonEditor::uiEditorTypeName() );
m_swapEnsemblesButton.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
2018-06-25 08:14:47 -05:00
m_swapEnsemblesButton.xmlCapability()->disableIO();
CAF_PDM_InitField( &m_caseCount, "CaseCount", QString( "" ), "Matching Cases" );
m_caseCount.uiCapability()->setUiReadOnly( true );
2018-06-25 08:14:47 -05:00
CAF_PDM_InitField( &m_matchOnParameters, "MatchOnParameters", false, "Match On Parameters" );
CAF_PDM_InitFieldNoDefault( &m_useFixedTimeStep, "UseFixedTimeStep", "Use Fixed Time Step" );
CAF_PDM_InitField( &m_fixedTimeStepIndex, "FixedTimeStepIndex", 0, "Time Step" );
m_fixedTimeStepIndex.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
m_fixedTimeStepIndex.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
setName( "Delta Ensemble" );
setAsEnsemble( true );
setDeletable( true );
2018-06-25 08:14:47 -05:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDerivedEnsembleCaseCollection::~RimDerivedEnsembleCaseCollection()
{
}
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::setEnsemble1( RimSummaryCaseCollection* ensemble )
2018-06-25 08:14:47 -05:00
{
m_ensemble1 = ensemble;
updateAutoName();
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::setEnsemble2( RimSummaryCaseCollection* ensemble )
2018-06-25 08:14:47 -05:00
{
m_ensemble2 = ensemble;
updateAutoName();
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCase*> RimDerivedEnsembleCaseCollection::allSummaryCases() const
{
std::vector<RimSummaryCase*> cases;
for ( auto sumCase : allDerivedCases( true ) )
cases.push_back( sumCase );
2018-06-25 08:14:47 -05:00
return cases;
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseSummaryAddress> RimDerivedEnsembleCaseCollection::ensembleSummaryAddresses() const
2018-06-25 08:14:47 -05:00
{
std::set<RifEclipseSummaryAddress> addresses;
if ( !m_ensemble1 || !m_ensemble2 ) return addresses;
2018-06-25 08:14:47 -05:00
addresses = m_ensemble1->ensembleSummaryAddresses();
auto addrs2 = m_ensemble2->ensembleSummaryAddresses();
addresses.insert( addrs2.begin(), addrs2.end() );
2018-06-25 08:14:47 -05:00
return addresses;
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::createDerivedEnsembleCases()
2018-06-25 08:14:47 -05:00
{
if ( !m_ensemble1 || !m_ensemble2 ) return;
2018-06-25 08:14:47 -05:00
setAllCasesNotInUse();
const auto cases1 = m_ensemble1->allSummaryCases();
const auto cases2 = m_ensemble2->allSummaryCases();
for ( auto& sumCase1 : cases1 )
2018-06-25 08:14:47 -05:00
{
auto crp = sumCase1->caseRealizationParameters();
if ( !crp ) continue;
2018-06-25 08:14:47 -05:00
RimSummaryCase* summaryCase2 = nullptr;
if ( m_matchOnParameters )
{
summaryCase2 = findCaseByParametersHash( cases2, crp->parametersHash() );
}
else
{
summaryCase2 = findCaseByRealizationNumber( cases2, crp->realizationNumber() );
}
if ( !summaryCase2 ) continue;
2018-06-25 08:14:47 -05:00
auto derivedCase = firstCaseNotInUse();
derivedCase->setSummaryCases( sumCase1, summaryCase2 );
derivedCase->setOperator( m_operator() );
int fixedTimeStepCase1 = -1;
int fixedTimeStepCase2 = -1;
if ( m_useFixedTimeStep == FixedTimeStepMode::FIXED_TIME_STEP_CASE_1 )
{
fixedTimeStepCase1 = m_fixedTimeStepIndex;
}
else if ( m_useFixedTimeStep == FixedTimeStepMode::FIXED_TIME_STEP_CASE_2 )
{
fixedTimeStepCase2 = m_fixedTimeStepIndex;
}
derivedCase->setFixedTimeSteps( fixedTimeStepCase1, fixedTimeStepCase2 );
derivedCase->createSummaryReaderInterface();
derivedCase->setCaseRealizationParameters( crp );
derivedCase->setInUse( true );
derivedCase->updateDisplayNameFromCases();
2018-06-25 08:14:47 -05:00
}
// If other derived ensembles are referring to this ensemble, update their cases as well
for ( auto referring : findReferringEnsembles() )
2018-06-25 08:14:47 -05:00
{
referring->createDerivedEnsembleCases();
2018-06-25 08:14:47 -05:00
}
deleteCasesNoInUse();
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
bool RimDerivedEnsembleCaseCollection::hasCaseReference( const RimSummaryCase* sumCase ) const
2018-06-25 08:14:47 -05:00
{
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
if ( m_ensemble1 )
2018-06-25 08:14:47 -05:00
{
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
for ( auto currCase : m_ensemble1->allSummaryCases() )
{
if ( currCase == sumCase ) return true;
}
2018-06-25 08:14:47 -05:00
}
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
if ( m_ensemble2 )
2018-06-25 08:14:47 -05:00
{
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
for ( auto currCase : m_ensemble2->allSummaryCases() )
{
if ( currCase == sumCase ) return true;
}
2018-06-25 08:14:47 -05:00
}
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
2018-06-25 08:14:47 -05:00
return false;
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::onLoadDataAndUpdate()
{
updateDerivedEnsembleCases();
updateReferringCurveSets();
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimDerivedEnsembleCaseCollection::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
2018-06-25 08:14:47 -05:00
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_ensemble1 || fieldNeedingOptions == &m_ensemble2 )
2018-06-25 08:14:47 -05:00
{
for ( auto ensemble : allEnsembles() )
2018-06-25 08:14:47 -05:00
{
if ( ensemble != this ) options.push_back( caf::PdmOptionItemInfo( ensemble->name(), ensemble ) );
2018-06-25 08:14:47 -05:00
}
}
else if ( fieldNeedingOptions == &m_caseCount )
2018-06-25 08:14:47 -05:00
{
size_t caseCount1 = m_ensemble1 ? m_ensemble1->allSummaryCases().size() : 0;
size_t caseCount2 = m_ensemble2 ? m_ensemble2->allSummaryCases().size() : 0;
m_caseCount = QString( "%1 / %2" ).arg( (int)m_cases.size() ).arg( std::max( caseCount1, caseCount2 ) );
2018-06-25 08:14:47 -05:00
}
if ( fieldNeedingOptions == &m_fixedTimeStepIndex )
{
RimSummaryCaseCollection* sourceEnsemble = nullptr;
if ( m_useFixedTimeStep() == FixedTimeStepMode::FIXED_TIME_STEP_CASE_1 )
{
sourceEnsemble = m_ensemble1;
}
else if ( m_useFixedTimeStep() == FixedTimeStepMode::FIXED_TIME_STEP_CASE_2 )
{
sourceEnsemble = m_ensemble2;
}
if ( sourceEnsemble && !sourceEnsemble->allSummaryCases().empty() )
{
auto firstCase = sourceEnsemble->allSummaryCases().front();
auto summaryReader = firstCase->summaryReader();
const std::vector<time_t>& timeSteps = summaryReader->timeSteps( RifEclipseSummaryAddress() );
options = RiaQDateTimeTools::createOptionItems( timeSteps );
}
}
2018-06-25 08:14:47 -05:00
return options;
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
2018-06-25 08:14:47 -05:00
{
RimSummaryCaseCollection::defineUiOrdering( uiConfigName, uiOrdering );
2018-06-25 08:14:47 -05:00
uiOrdering.add( &m_caseCount );
uiOrdering.add( &m_ensemble1 );
uiOrdering.add( &m_operator );
uiOrdering.add( &m_ensemble2 );
uiOrdering.add( &m_swapEnsemblesButton );
uiOrdering.add( &m_matchOnParameters );
2018-06-25 08:14:47 -05:00
uiOrdering.add( &m_useFixedTimeStep );
if ( m_useFixedTimeStep() != RimDerivedEnsembleCaseCollection::FixedTimeStepMode::FIXED_TIME_STEP_NONE )
{
uiOrdering.add( &m_fixedTimeStepIndex );
}
uiOrdering.skipRemainingFields( true );
updateAutoName();
if ( !isValid() ) m_caseCount = "";
2018-06-25 08:14:47 -05:00
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
2018-06-25 08:14:47 -05:00
{
bool doUpdate = false;
2018-06-25 08:14:47 -05:00
bool doUpdateCases = false;
bool doShowDialog = false;
2018-06-25 08:14:47 -05:00
if ( changedField == &m_ensemble1 || changedField == &m_ensemble2 || changedField == &m_matchOnParameters )
2018-06-25 08:14:47 -05:00
{
doUpdate = true;
2018-06-25 08:14:47 -05:00
doUpdateCases = true;
doShowDialog = true;
2018-06-25 08:14:47 -05:00
}
else if ( changedField == &m_operator || changedField == &m_useFixedTimeStep || changedField == &m_fixedTimeStepIndex )
2018-06-25 08:14:47 -05:00
{
doUpdate = true;
2018-06-25 08:14:47 -05:00
doUpdateCases = true;
doShowDialog = false;
2018-06-25 08:14:47 -05:00
}
else if ( changedField == &m_swapEnsemblesButton )
2018-06-25 08:14:47 -05:00
{
m_swapEnsemblesButton = false;
auto temp = m_ensemble1();
m_ensemble1 = m_ensemble2();
m_ensemble2 = temp;
2018-06-25 08:14:47 -05:00
doUpdate = true;
2018-06-25 08:14:47 -05:00
doUpdateCases = true;
doShowDialog = false;
2018-06-25 08:14:47 -05:00
}
if ( doUpdate )
2018-06-25 08:14:47 -05:00
{
updateAutoName();
if ( doUpdateCases )
2018-06-25 08:14:47 -05:00
{
createDerivedEnsembleCases();
2018-06-25 08:14:47 -05:00
updateConnectedEditors();
if ( doShowDialog && m_ensemble1 != nullptr && m_ensemble2 != nullptr && allSummaryCases().empty() )
{
RicNewDerivedEnsembleFeature::showWarningDialog();
}
2018-06-25 08:14:47 -05:00
}
updateReferringCurveSets();
// If other derived ensembles are referring to this ensemble, update their cases as well
for ( auto refering : findReferringEnsembles() )
2018-06-25 08:14:47 -05:00
{
refering->updateReferringCurveSets();
}
}
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute )
2018-06-25 08:14:47 -05:00
{
if ( field == &m_swapEnsemblesButton )
2018-06-25 08:14:47 -05:00
{
caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
if ( attrib )
2018-06-25 08:14:47 -05:00
{
attrib->m_buttonText = "Swap Ensembles";
}
}
if ( &m_fixedTimeStepIndex == field )
{
auto a = dynamic_cast<caf::PdmUiTreeSelectionEditorAttribute*>( attribute );
if ( a )
{
a->singleSelectionMode = true;
a->showTextFilter = true;
}
}
2018-06-25 08:14:47 -05:00
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::setAllCasesNotInUse()
{
for ( auto derCase : allDerivedCases( true ) )
derCase->setInUse( false );
2018-06-25 08:14:47 -05:00
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::deleteCasesNoInUse()
{
std::vector<RimDerivedSummaryCase*> inactiveCases;
auto allCases = allDerivedCases( false );
std::copy_if( allCases.begin(),
allCases.end(),
std::back_inserter( inactiveCases ),
[]( RimDerivedSummaryCase* derCase ) { return !derCase->isInUse(); } );
2018-06-25 08:14:47 -05:00
for ( auto derCase : inactiveCases )
2018-06-25 08:14:47 -05:00
{
removeCase( derCase );
2018-06-25 08:14:47 -05:00
delete derCase;
}
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
RimDerivedSummaryCase* RimDerivedEnsembleCaseCollection::firstCaseNotInUse()
2018-06-25 08:14:47 -05:00
{
auto allCases = allDerivedCases( false );
auto itr = std::find_if( allCases.begin(), allCases.end(), []( RimDerivedSummaryCase* derCase ) { return !derCase->isInUse(); } );
if ( itr != allCases.end() )
2018-06-25 08:14:47 -05:00
{
return *itr;
}
// If no active case was found, add a new case to the collection
auto newCase = new RimDerivedSummaryCase();
m_cases.push_back( newCase );
2018-06-25 08:14:47 -05:00
return newCase;
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
std::vector<RimDerivedSummaryCase*> RimDerivedEnsembleCaseCollection::allDerivedCases( bool activeOnly ) const
2018-06-25 08:14:47 -05:00
{
std::vector<RimDerivedSummaryCase*> activeCases;
for ( auto sumCase : RimSummaryCaseCollection::allSummaryCases() )
2018-06-25 08:14:47 -05:00
{
auto derivedCase = dynamic_cast<RimDerivedSummaryCase*>( sumCase );
if ( derivedCase && ( !activeOnly || derivedCase->isInUse() ) )
2018-06-25 08:14:47 -05:00
{
activeCases.push_back( derivedCase );
2018-06-25 08:14:47 -05:00
}
}
return activeCases;
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::updateAutoName()
{
QString timeStepString;
{
RimSummaryCaseCollection* sourceEnsemble = nullptr;
if ( m_useFixedTimeStep() == FixedTimeStepMode::FIXED_TIME_STEP_CASE_1 )
{
sourceEnsemble = m_ensemble1;
}
else if ( m_useFixedTimeStep() == FixedTimeStepMode::FIXED_TIME_STEP_CASE_2 )
{
sourceEnsemble = m_ensemble2;
}
if ( sourceEnsemble && !sourceEnsemble->allSummaryCases().empty() )
{
auto firstCase = sourceEnsemble->allSummaryCases().front();
auto summaryReader = firstCase->summaryReader();
if ( summaryReader )
{
const std::vector<time_t>& timeSteps = summaryReader->timeSteps( RifEclipseSummaryAddress() );
2020-04-24 12:55:54 -05:00
if ( m_fixedTimeStepIndex >= 0 && m_fixedTimeStepIndex < static_cast<int>( timeSteps.size() ) )
{
time_t selectedTime = timeSteps[m_fixedTimeStepIndex];
QDateTime dt = RiaQDateTimeTools::fromTime_t( selectedTime );
2020-11-06 03:46:38 -06:00
QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates( { dt } );
timeStepString = RiaQDateTimeTools::toStringUsingApplicationLocale( dt, formatString );
}
}
}
}
QString nameCase1 = "None";
if ( m_ensemble1 )
{
nameCase1 = m_ensemble1->name();
if ( m_useFixedTimeStep() == FixedTimeStepMode::FIXED_TIME_STEP_CASE_1 ) nameCase1 += "@" + timeStepString;
}
QString nameCase2 = "None";
if ( m_ensemble2 )
{
nameCase2 = m_ensemble2->name();
if ( m_useFixedTimeStep() == FixedTimeStepMode::FIXED_TIME_STEP_CASE_2 ) nameCase2 += "@" + timeStepString;
}
QString operatorText;
if ( m_operator() == DerivedSummaryOperator::DERIVED_OPERATOR_SUB )
operatorText = "Delta";
else if ( m_operator() == DerivedSummaryOperator::DERIVED_OPERATOR_ADD )
operatorText = "Sum";
QString name = operatorText + QString( "(%1 , %2)" ).arg( nameCase1, nameCase2 );
setName( name );
2018-06-25 08:14:47 -05:00
// If other derived ensembles are referring to this ensemble, update theirs name as well
for ( auto refering : findReferringEnsembles() )
2018-06-25 08:14:47 -05:00
{
refering->updateAutoName();
refering->updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::updateDerivedEnsembleCases()
{
for ( auto& derivedCase : allDerivedCases( true ) )
{
derivedCase->createSummaryReaderInterface();
auto crp = derivedCase->summaryCase1()->caseRealizationParameters();
if ( !crp ) continue;
derivedCase->setCaseRealizationParameters( crp );
}
// If other derived ensembles are referring to this ensemble, update their cases as well
for ( auto referring : findReferringEnsembles() )
{
referring->updateDerivedEnsembleCases();
}
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
RimSummaryCase* RimDerivedEnsembleCaseCollection::findCaseByParametersHash( const std::vector<RimSummaryCase*>& cases, size_t hash ) const
2018-06-25 08:14:47 -05:00
{
for ( auto sumCase : cases )
2018-06-25 08:14:47 -05:00
{
auto ensembleParameters = sumCase->caseRealizationParameters();
if ( ensembleParameters && ensembleParameters->parametersHash() == hash ) return sumCase;
2018-06-25 08:14:47 -05:00
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryCase* RimDerivedEnsembleCaseCollection::findCaseByRealizationNumber( const std::vector<RimSummaryCase*>& cases,
int realizationNumber ) const
{
for ( auto sumCase : cases )
{
auto ensembleParameters = sumCase->caseRealizationParameters();
if ( ensembleParameters && ensembleParameters->realizationNumber() == realizationNumber ) return sumCase;
}
return nullptr;
}
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
std::vector<RimDerivedEnsembleCaseCollection*> RimDerivedEnsembleCaseCollection::findReferringEnsembles() const
{
std::vector<RimDerivedEnsembleCaseCollection*> referringEnsembles;
auto mainColl = firstAncestorOrThisOfType<RimSummaryCaseMainCollection>();
if ( mainColl )
2018-06-25 08:14:47 -05:00
{
for ( auto group : mainColl->summaryCaseCollections() )
2018-06-25 08:14:47 -05:00
{
auto derivedEnsemble = dynamic_cast<RimDerivedEnsembleCaseCollection*>( group );
if ( derivedEnsemble )
2018-06-25 08:14:47 -05:00
{
if ( derivedEnsemble->m_ensemble1() == this || derivedEnsemble->m_ensemble2() == this )
2018-06-25 08:14:47 -05:00
{
referringEnsembles.push_back( derivedEnsemble );
2018-06-25 08:14:47 -05:00
}
}
}
}
return referringEnsembles;
}
//--------------------------------------------------------------------------------------------------
///
2018-06-25 08:14:47 -05:00
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCaseCollection*> RimDerivedEnsembleCaseCollection::allEnsembles() const
{
std::vector<RimSummaryCaseCollection*> ensembles;
auto project = RimProject::current();
2018-06-25 08:14:47 -05:00
for ( auto group : project->summaryGroups() )
2018-06-25 08:14:47 -05:00
{
if ( group == this ) continue;
if ( !group->isEnsemble() ) continue;
auto derivedEnsemble = dynamic_cast<const RimDerivedEnsembleCaseCollection*>( group );
if ( derivedEnsemble && !derivedEnsemble->isValid() ) continue;
ensembles.push_back( group );
2018-06-25 08:14:47 -05:00
}
return ensembles;
}