#5707 Delta Ensemble Case : Add user option to select time step

This commit is contained in:
Magne Sjaastad 2020-03-29 13:49:55 +02:00
parent 69d36ed9a9
commit ff5cc86935
7 changed files with 313 additions and 21 deletions

View File

@ -23,6 +23,8 @@
#include <QString>
#include "cafAppEnum.h"
#include "cafPdmUiItem.h"
#include <cvfAssert.h>
#include <cmath>
@ -506,4 +508,31 @@ QString RiaQDateTimeTools::timeFormatString( const QString& fullTimeFormat, Time
}
CVF_ASSERT( false && "Time format string is malformed" );
return "";
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RiaQDateTimeTools::createOptionItems( const std::vector<time_t>& timeSteps )
{
QList<caf::PdmOptionItemInfo> options;
std::vector<QDateTime> dateTimes;
for ( time_t timeT : timeSteps )
{
QDateTime dateTime = RiaQDateTimeTools::fromTime_t( timeT );
dateTimes.push_back( dateTime );
}
QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates( dateTimes );
for ( size_t i = 0; i < dateTimes.size(); i++ )
{
const auto& dt = dateTimes[i];
QString text = RiaQDateTimeTools::toStringUsingApplicationLocale( dt, formatString );
options.push_back( {text, i} );
}
return options;
}

View File

@ -35,6 +35,11 @@ class QDate;
class QTime;
class DateTimeSpan;
namespace caf
{
class PdmOptionItemInfo;
};
//==================================================================================================
//
//==================================================================================================
@ -135,6 +140,8 @@ public:
static QString dateFormatString( const QString& fullDateFormat, DateFormatComponents dateComponents );
static QString timeFormatString( const QString& fullTimeFormat, TimeFormatComponents timeComponents );
static QList<caf::PdmOptionItemInfo> createOptionItems( const std::vector<time_t>& timeSteps );
private:
static quint64 secondsInDay();
static quint64 secondsInYear();

View File

@ -17,6 +17,7 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RiaApplication.h"
#include "RiaQDateTimeTools.h"
#include "SummaryPlotCommands/RicNewDerivedEnsembleFeature.h"
@ -28,10 +29,27 @@
#include "RifSummaryReaderInterface.h"
#include <cafPdmUiPushButtonEditor.h>
#include "cafPdmUiPushButtonEditor.h"
#include "cafPdmUiTreeSelectionEditor.h"
#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" );
//--------------------------------------------------------------------------------------------------
@ -61,6 +79,11 @@ RimDerivedEnsembleCaseCollection::RimDerivedEnsembleCaseCollection()
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 );
// Do not show child cases
uiCapability()->setUiTreeChildrenHidden( true );
@ -152,6 +175,19 @@ void RimDerivedEnsembleCaseCollection::updateDerivedEnsembleCases()
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 );
@ -215,6 +251,30 @@ QList<caf::PdmOptionItemInfo>
m_caseCount = QString( "%1 / %2" ).arg( (int)m_cases.size() ).arg( std::max( caseCount1, caseCount2 ) );
}
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 );
}
}
return options;
}
@ -232,6 +292,12 @@ void RimDerivedEnsembleCaseCollection::defineUiOrdering( QString uiConfigName, c
uiOrdering.add( &m_swapEnsemblesButton );
uiOrdering.add( &m_matchOnParameters );
uiOrdering.add( &m_useFixedTimeStep );
if ( m_useFixedTimeStep() != RimDerivedEnsembleCaseCollection::FixedTimeStepMode::FIXED_TIME_STEP_NONE )
{
uiOrdering.add( &m_fixedTimeStepIndex );
}
uiOrdering.skipRemainingFields( true );
updateAutoName();
@ -255,7 +321,7 @@ void RimDerivedEnsembleCaseCollection::fieldChangedByUi( const caf::PdmFieldHand
doUpdateCases = true;
doShowDialog = true;
}
else if ( changedField == &m_operator )
else if ( changedField == &m_operator || changedField == &m_useFixedTimeStep || changedField == &m_fixedTimeStepIndex )
{
doUpdate = true;
doUpdateCases = true;
@ -313,6 +379,15 @@ void RimDerivedEnsembleCaseCollection::defineEditorAttribute( const caf::PdmFiel
attrib->m_buttonText = "Swap Ensembles";
}
}
if ( &m_fixedTimeStepIndex == field )
{
auto a = dynamic_cast<caf::PdmUiTreeSelectionEditorAttribute*>( attribute );
if ( a )
{
a->singleSelectionMode = true;
a->showTextFilter = true;
}
}
}
//--------------------------------------------------------------------------------------------------
@ -385,16 +460,59 @@ std::vector<RimDerivedSummaryCase*> RimDerivedEnsembleCaseCollection::allDerived
//--------------------------------------------------------------------------------------------------
void RimDerivedEnsembleCaseCollection::updateAutoName()
{
QString op = caf::AppEnum<DerivedSummaryOperator>::uiText( m_operator() );
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;
}
auto derivedEnsemble1 = dynamic_cast<RimDerivedEnsembleCaseCollection*>( m_ensemble1() );
auto derivedEnsemble2 = dynamic_cast<RimDerivedEnsembleCaseCollection*>( m_ensemble2() );
bool isDerived1 = derivedEnsemble1 != nullptr;
bool isDerived2 = derivedEnsemble2 != nullptr;
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() );
if ( m_fixedTimeStepIndex >= 0 && m_fixedTimeStepIndex < timeSteps.size() )
{
time_t selectedTime = timeSteps[m_fixedTimeStepIndex];
QDateTime dt = RiaQDateTimeTools::fromTime_t( selectedTime );
QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates( {dt} );
QString name = ( isDerived1 ? "(" : "" ) + ( m_ensemble1 ? m_ensemble1->name() : "" ) + ( isDerived1 ? ")" : "" ) +
" " + op + " " + ( isDerived2 ? "(" : "" ) + ( m_ensemble2 ? m_ensemble2->name() : "" ) +
( isDerived2 ? ")" : "" );
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 );
// If other derived ensembles are referring to this ensemble, update theirs name as well

View File

@ -40,6 +40,14 @@ class RimDerivedEnsembleCaseCollection : public RimSummaryCaseCollection
{
CAF_PDM_HEADER_INIT;
public:
enum class FixedTimeStepMode
{
FIXED_TIME_STEP_NONE,
FIXED_TIME_STEP_CASE_1,
FIXED_TIME_STEP_CASE_2
};
public:
RimDerivedEnsembleCaseCollection();
~RimDerivedEnsembleCaseCollection() override;
@ -89,4 +97,7 @@ private:
caf::PdmField<bool> m_swapEnsemblesButton;
caf::PdmField<QString> m_caseCount;
caf::PdmField<bool> m_matchOnParameters;
caf::PdmField<caf::AppEnum<FixedTimeStepMode>> m_useFixedTimeStep;
caf::PdmField<int> m_fixedTimeStepIndex;
};

View File

@ -27,6 +27,12 @@
#include "RimProject.h"
#include "RimSummaryPlot.h"
#include "cafPdmUiTreeSelectionEditor.h"
#include <QDateTime>
#include <algorithm>
namespace caf
{
template <>
@ -36,6 +42,15 @@ void caf::AppEnum<DerivedSummaryOperator>::setUp()
addItem( DerivedSummaryOperator::DERIVED_OPERATOR_ADD, "Add", "+" );
setDefault( DerivedSummaryOperator::DERIVED_OPERATOR_SUB );
}
template <>
void caf::AppEnum<RimDerivedSummaryCase::FixedTimeStepMode>::setUp()
{
addItem( RimDerivedSummaryCase::FixedTimeStepMode::FIXED_TIME_STEP_NONE, "FIXED_TIME_STEP_NONE", "None" );
addItem( RimDerivedSummaryCase::FixedTimeStepMode::FIXED_TIME_STEP_CASE_1, "FIXED_TIME_STEP_CASE_1", "Summary Case 1" );
addItem( RimDerivedSummaryCase::FixedTimeStepMode::FIXED_TIME_STEP_CASE_2, "FIXED_TIME_STEP_CASE_2", "Summary Case 2" );
setDefault( RimDerivedSummaryCase::FixedTimeStepMode::FIXED_TIME_STEP_NONE );
}
} // namespace caf
CAF_PDM_SOURCE_INIT( RimDerivedSummaryCase, "RimDerivedEnsembleCase" );
@ -48,10 +63,17 @@ RimDerivedSummaryCase::RimDerivedSummaryCase()
, m_summaryCase2( nullptr )
{
CAF_PDM_InitObject( "Summary Case", ":/SummaryCase16x16.png", "", "" );
CAF_PDM_InitFieldNoDefault( &m_summaryCase1, "SummaryCase1", "SummaryCase1", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_summaryCase2, "SummaryCase2", "SummaryCase2", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_summaryCase1, "SummaryCase1", "Summary Case 1", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_operator, "Operator", "Operator", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_summaryCase2, "SummaryCase2", "Summary Case 2", "", "", "" );
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 );
m_inUse = false;
}
@ -141,8 +163,20 @@ void RimDerivedSummaryCase::calculate( const RifEclipseSummaryAddress& address )
RifSummaryReaderInterface* reader1 = m_summaryCase1 ? m_summaryCase1->summaryReader() : nullptr;
RifSummaryReaderInterface* reader2 = m_summaryCase2 ? m_summaryCase2->summaryReader() : nullptr;
auto itAndIsInsertedPair =
m_dataCache.insert( std::make_pair( address, calculateDerivedValues( reader1, reader2, m_operator(), address ) ) );
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;
}
auto itAndIsInsertedPair = m_dataCache.insert(
std::make_pair( address,
calculateDerivedValues( reader1, fixedTimeStepCase1, reader2, fixedTimeStepCase2, m_operator(), address ) ) );
// Check if we got any data. If not, erase the map entry to comply with previous behavior
@ -157,7 +191,9 @@ void RimDerivedSummaryCase::calculate( const RifEclipseSummaryAddress& address )
//--------------------------------------------------------------------------------------------------
std::pair<std::vector<time_t>, std::vector<double>>
RimDerivedSummaryCase::calculateDerivedValues( RifSummaryReaderInterface* reader1,
int fixedTimeStepCase1,
RifSummaryReaderInterface* reader2,
int fixedTimeStepCase2,
DerivedSummaryOperator m_operator,
const RifEclipseSummaryAddress& address )
{
@ -212,15 +248,20 @@ std::pair<std::vector<time_t>, std::vector<double>>
std::vector<double> calculatedValues;
calculatedValues.reserve( sampleCount );
int clampedIndexCase1 = std::min( fixedTimeStepCase1, static_cast<int>( allValues1.size() ) );
int clampedIndexCase2 = std::min( fixedTimeStepCase2, static_cast<int>( allValues2.size() ) );
for ( size_t i = 0; i < sampleCount; i++ )
{
double valueCase1 = clampedIndexCase1 >= 0 ? allValues1[clampedIndexCase1] : allValues1[i];
double valueCase2 = clampedIndexCase2 >= 0 ? allValues2[clampedIndexCase2] : allValues2[i];
if ( m_operator == DerivedSummaryOperator::DERIVED_OPERATOR_SUB )
{
calculatedValues.push_back( allValues1[i] - allValues2[i] );
calculatedValues.push_back( valueCase1 - valueCase2 );
}
else if ( m_operator == DerivedSummaryOperator::DERIVED_OPERATOR_ADD )
{
calculatedValues.push_back( allValues1[i] + allValues2[i] );
calculatedValues.push_back( valueCase1 + valueCase2 );
}
}
@ -288,6 +329,25 @@ void RimDerivedSummaryCase::setOperator( DerivedSummaryOperator oper )
m_operator = oper;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDerivedSummaryCase::setFixedTimeSteps( int fixedTimeStepCase1, int fixedTimeStepCase2 )
{
m_useFixedTimeStep = FixedTimeStepMode::FIXED_TIME_STEP_NONE;
if ( fixedTimeStepCase1 >= 0 )
{
m_useFixedTimeStep = FixedTimeStepMode::FIXED_TIME_STEP_CASE_1;
m_fixedTimeStepIndex = fixedTimeStepCase1;
}
else if ( fixedTimeStepCase2 >= 0 )
{
m_useFixedTimeStep = FixedTimeStepMode::FIXED_TIME_STEP_CASE_2;
m_fixedTimeStepIndex = fixedTimeStepCase2;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -331,11 +391,16 @@ void RimDerivedSummaryCase::defineUiOrdering( QString uiConfigName, caf::PdmUiOr
// Base class
uiOrdering.add( &m_shortName );
// This class
uiOrdering.add( &m_summaryCase1 );
uiOrdering.add( &m_operator );
uiOrdering.add( &m_summaryCase2 );
uiOrdering.add( &m_useFixedTimeStep );
if ( m_useFixedTimeStep() != FixedTimeStepMode::FIXED_TIME_STEP_NONE )
{
uiOrdering.add( &m_fixedTimeStepIndex );
}
uiOrdering.skipRemainingFields();
}
@ -350,6 +415,27 @@ QList<caf::PdmOptionItemInfo>
RimProject* proj = RiaApplication::instance()->project();
auto summaryCases = proj->allSummaryCases();
if ( fieldNeedingOptions == &m_fixedTimeStepIndex )
{
RimSummaryCase* sourceCase = nullptr;
if ( m_useFixedTimeStep() == FixedTimeStepMode::FIXED_TIME_STEP_CASE_1 )
{
sourceCase = m_summaryCase1;
}
else if ( m_useFixedTimeStep() == FixedTimeStepMode::FIXED_TIME_STEP_CASE_2 )
{
sourceCase = m_summaryCase2;
}
if ( sourceCase && sourceCase->summaryReader() )
{
const std::vector<time_t>& timeSteps = sourceCase->summaryReader()->timeSteps( RifEclipseSummaryAddress() );
options = RiaQDateTimeTools::createOptionItems( timeSteps );
}
}
if ( fieldNeedingOptions == &m_summaryCase1 || fieldNeedingOptions == &m_summaryCase2 )
{
for ( auto c : summaryCases )
@ -375,6 +461,10 @@ void RimDerivedSummaryCase::fieldChangedByUi( const caf::PdmFieldHandle* changed
reloadData = true;
}
else if ( changedField == &m_useFixedTimeStep || changedField == &m_fixedTimeStepIndex )
{
reloadData = true;
}
else if ( changedField == &m_operator )
{
reloadData = true;
@ -411,3 +501,21 @@ void RimDerivedSummaryCase::fieldChangedByUi( const caf::PdmFieldHandle* changed
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDerivedSummaryCase::defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute )
{
if ( &m_fixedTimeStepIndex == field )
{
auto a = dynamic_cast<caf::PdmUiTreeSelectionEditorAttribute*>( attribute );
if ( a )
{
a->singleSelectionMode = true;
a->showTextFilter = true;
}
}
}

View File

@ -45,6 +45,14 @@ class RimDerivedSummaryCase : public RimSummaryCase
{
CAF_PDM_HEADER_INIT;
public:
enum class FixedTimeStepMode
{
FIXED_TIME_STEP_NONE,
FIXED_TIME_STEP_CASE_1,
FIXED_TIME_STEP_CASE_2
};
public:
RimDerivedSummaryCase();
~RimDerivedSummaryCase() override;
@ -53,6 +61,7 @@ public:
bool isInUse() const;
void setSummaryCases( RimSummaryCase* sumCase1, RimSummaryCase* sumCase2 );
void setOperator( DerivedSummaryOperator oper );
void setFixedTimeSteps( int fixedTimeStepCase1, int fixedTimeStepCase2 );
bool needsCalculation( const RifEclipseSummaryAddress& address ) const;
const std::vector<time_t>& timeSteps( const RifEclipseSummaryAddress& address ) const;
@ -62,7 +71,9 @@ public:
static std::pair<std::vector<time_t>, std::vector<double>>
calculateDerivedValues( RifSummaryReaderInterface* reader1,
int fixedTimeStepCase1,
RifSummaryReaderInterface* reader2,
int fixedTimeStepCase2,
DerivedSummaryOperator m_operator,
const RifEclipseSummaryAddress& address );
@ -81,14 +92,21 @@ private:
bool* useOptionsOnly ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute ) override;
void clearData( const RifEclipseSummaryAddress& address );
private:
caf::PdmPtrField<RimSummaryCase*> m_summaryCase1;
caf::PdmPtrField<RimSummaryCase*> m_summaryCase2;
caf::PdmPtrField<RimSummaryCase*> m_summaryCase1;
caf::PdmPtrField<RimSummaryCase*> m_summaryCase2;
caf::PdmField<caf::AppEnum<DerivedSummaryOperator>> m_operator;
caf::PdmField<caf::AppEnum<FixedTimeStepMode>> m_useFixedTimeStep;
caf::PdmField<int> m_fixedTimeStepIndex;
bool m_inUse;
std::unique_ptr<RifDerivedEnsembleReader> m_reader;

View File

@ -643,7 +643,8 @@ void RimSummaryCaseCollection::updateReferringCurveSets()
for ( auto curveSet : referringObjects )
{
if ( curveSet ) curveSet->updateAllCurves();
bool updateParentPlot = true;
if ( curveSet ) curveSet->loadDataAndUpdate( updateParentPlot );
}
}