Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions ApplicationLibCode/Application/Tools/RiaQDateTimeTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,61 @@ QDateTime RiaQDateTimeTools::createDateTime( const QDate& date, Qt::TimeSpec tim
return date.startOfDay( timeSpec );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RiaQDateTimeTools::calendarYearsBetween( time_t startTime, time_t endTime )
{
return calendarUnitsBetween( startTime, endTime, false );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RiaQDateTimeTools::calendarMonthsBetween( time_t startTime, time_t endTime )
{
return calendarUnitsBetween( startTime, endTime, true );
}

//--------------------------------------------------------------------------------------------------
/// A calendar month or year has a varying number of seconds. Count the number of whole calendar units, and express the
/// remainder as a fraction of the calendar unit it falls inside.
//--------------------------------------------------------------------------------------------------
double RiaQDateTimeTools::calendarUnitsBetween( time_t startTime, time_t endTime, bool useMonths )
{
const QDateTime start = fromTime_t( startTime );
const QDateTime end = fromTime_t( endTime );
if ( start == end ) return 0.0;

auto addUnits = [&start, useMonths]( int unitCount ) { return useMonths ? start.addMonths( unitCount ) : start.addYears( unitCount ); };

const int sign = ( end > start ) ? 1 : -1;

auto isBeyondEnd = [&end, sign]( const QDateTime& dt ) { return sign > 0 ? dt > end : dt < end; };

// Start off with an estimate based on the average length of the calendar unit, then adjust to the exact count
const double averageSecondsInUnit = useMonths ? 2629746.0 : 31556952.0;

int unitCount = static_cast<int>( std::abs( static_cast<double>( endTime - startTime ) ) / averageSecondsInUnit );

while ( unitCount > 0 && isBeyondEnd( addUnits( unitCount * sign ) ) )
{
unitCount--;
}
while ( !isBeyondEnd( addUnits( ( unitCount + 1 ) * sign ) ) )
{
unitCount++;
}

const QDateTime lower = addUnits( unitCount * sign );
const QDateTime upper = addUnits( ( unitCount + 1 ) * sign );

const double secondsInUnit = std::abs( static_cast<double>( lower.secsTo( upper ) ) );
const double fraction = secondsInUnit > 0.0 ? std::abs( static_cast<double>( lower.secsTo( end ) ) ) / secondsInUnit : 0.0;

return sign * ( unitCount + fraction );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions ApplicationLibCode/Application/Tools/RiaQDateTimeTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#include <QString>

#include <ctime>

#include <set>
#include <string>
#include <vector>
Expand Down Expand Up @@ -58,6 +60,12 @@ class RiaQDateTimeTools

static QDateTime createDateTime( const QDate& date, Qt::TimeSpec timeSpec = Qt::LocalTime );

// Number of calendar years/months between two time steps. The remainder is expressed as a fraction of the calendar
// unit it falls inside, so a time step exactly N calendar years/months after the start reports exactly N. Time
// steps before the start time are reported as negative values.
static double calendarYearsBetween( time_t startTime, time_t endTime );
static double calendarMonthsBetween( time_t startTime, time_t endTime );
Comment on lines +66 to +67

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

time_t still? Either use QDateTime or std::chrono::time_point?


static QDateTime epoch();

static QDateTime createUtcDateTime();
Expand Down Expand Up @@ -99,6 +107,8 @@ class RiaQDateTimeTools
getTimeStepsWithinSelectedRange( const std::vector<QDateTime>& timeSteps, const QDateTime& fromTimeStep, const QDateTime& toTimeStep );

private:
static double calendarUnitsBetween( time_t startTime, time_t endTime, bool useMonths );

static const DateTimeSpan TIMESPAN_MINUTE;
static const DateTimeSpan TIMESPAN_HOUR;
static const DateTimeSpan TIMESPAN_DAY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,15 @@ void RimAsciiDataCurve::onLoadDataAndUpdate( bool updateParentPlot )
}
else
{
double timeScale = plot->timeAxisProperties()->fromTimeTToDisplayUnitScale();
auto* timeAxisProperties = plot->timeAxisProperties();

std::vector<double> times;
if ( !dateTimes.empty() )
{
time_t startDate = dateTimes[0];
for ( time_t& date : dateTimes )
{
times.push_back( timeScale * ( date - startDate ) );
times.push_back( timeAxisProperties->timeFromSimulationStart( startDate, date ) );
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -704,15 +704,15 @@ void RimSummaryCurve::onLoadDataAndUpdate( bool updateParentPlot )
}
else
{
double timeScale = plot->timeAxisProperties()->fromTimeTToDisplayUnitScale();
auto* timeAxisProperties = plot->timeAxisProperties();

std::vector<double> timeFromSimulationStart;
if ( !curveTimeStepsY.empty() )
{
time_t startDate = curveTimeStepsY[0];
for ( const auto& date : curveTimeStepsY )
{
timeFromSimulationStart.push_back( timeScale * ( date - startDate ) );
timeFromSimulationStart.push_back( timeAxisProperties->timeFromSimulationStart( startDate, date ) );
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,36 @@

#include <QMessageBox>

namespace
{
//--------------------------------------------------------------------------------------------------
/// Header text for the time column, either date and time or time from simulation start
//--------------------------------------------------------------------------------------------------
QString timeColumnHeaderText( const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
if ( timeFromSimulationStart ) return QString( "Time [%1]" ).arg( timeFromSimulationStart->displayUnitText );

return "Date and time";
}

//--------------------------------------------------------------------------------------------------
/// Text for a single time step, either date and time or time from simulation start
//--------------------------------------------------------------------------------------------------
QString timeStepText( time_t timeStep, const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
if ( timeFromSimulationStart )
{
double timeSinceSimulationStart = RimSummaryTimeAxisProperties::timeFromSimulationStart( timeFromSimulationStart->simulationStartTime,
timeStep,
timeFromSimulationStart->displayUnit );

return QString::number( timeSinceSimulationStart, 'g', RimSummaryPlot::precision() );
}

return QDateTime::fromSecsSinceEpoch( timeStep ).toUTC().toString( "yyyy-MM-dd hh:mm:ss " );
}
} // namespace

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -135,11 +165,12 @@ void RimSummaryCurvesData::addCurveDataNoSearch( const QString& c
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryCurvesData::createTextForExport( const std::vector<RimSummaryCurve*>& curves,
const std::vector<RimAsciiDataCurve*>& asciiCurves,
const std::vector<RimGridTimeHistoryCurve*>& gridCurves,
RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString )
QString RimSummaryCurvesData::createTextForExport( const std::vector<RimSummaryCurve*>& curves,
const std::vector<RimAsciiDataCurve*>& asciiCurves,
const std::vector<RimGridTimeHistoryCurve*>& gridCurves,
RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
if ( curves.empty() && asciiCurves.empty() && gridCurves.empty() ) return {};

Expand All @@ -152,22 +183,22 @@ QString RimSummaryCurvesData::createTextForExport( const std::vector<RimSummaryC
RimSummaryCurvesData::populateSummaryCurvesData( curves, SummaryCurveType::CURVE_TYPE_OBSERVED, &summaryCurvesObsData );
RimSummaryCurvesData::populateTimeHistoryCurvesData( gridCurves, &gridCurvesData );

RimSummaryCurvesData::appendToExportData( out, { summaryCurvesObsData }, showTimeAsLongString );
RimSummaryCurvesData::appendToExportData( out, { summaryCurvesObsData }, showTimeAsLongString, timeFromSimulationStart );

std::vector<RimSummaryCurvesData> exportData( 2 );

RimSummaryCurvesData::prepareCaseCurvesForExport( resamplingPeriod, summaryCurvesData, &exportData[0] );
RimSummaryCurvesData::prepareCaseCurvesForExport( resamplingPeriod, gridCurvesData, &exportData[1] );

RimSummaryCurvesData::appendToExportData( out, exportData, showTimeAsLongString );
RimSummaryCurvesData::appendToExportData( out, exportData, showTimeAsLongString, timeFromSimulationStart );

{
// Handle observed data pasted into plot from clipboard

RimSummaryCurvesData asciiCurvesData;
RimSummaryCurvesData::populateAsciiDataCurvesData( asciiCurves, &asciiCurvesData );

RimSummaryCurvesData::appendToExportData( out, { asciiCurvesData }, showTimeAsLongString );
RimSummaryCurvesData::appendToExportData( out, { asciiCurvesData }, showTimeAsLongString, timeFromSimulationStart );
}

return out;
Expand Down Expand Up @@ -328,20 +359,23 @@ void RimSummaryCurvesData::prepareCaseCurvesForExport( RiaDefines::DateTimePerio
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryCurvesData::appendToExportDataForCase( QString& out, const std::vector<time_t>& timeSteps, const std::vector<CurveData>& curveData )
void RimSummaryCurvesData::appendToExportDataForCase( QString& out,
const std::vector<time_t>& timeSteps,
const std::vector<CurveData>& curveData,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
for ( size_t j = 0; j < timeSteps.size(); j++ ) // time steps & data points
{
if ( j == 0 )
{
out += "Date and time";
out += timeColumnHeaderText( timeFromSimulationStart );
for ( const auto& k : curveData ) // curves
{
out += "\t" + ( k.name );
}
}
out += "\n";
out += QDateTime::fromSecsSinceEpoch( timeSteps[j] ).toUTC().toString( "yyyy-MM-dd hh:mm:ss " );
out += timeStepText( timeSteps[j], timeFromSimulationStart );

for ( const auto& k : curveData ) // curves
{
Expand All @@ -358,7 +392,10 @@ void RimSummaryCurvesData::appendToExportDataForCase( QString& out, const std::v
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryCurvesData::appendToExportData( QString& out, const std::vector<RimSummaryCurvesData>& curvesData, bool showTimeAsLongString )
void RimSummaryCurvesData::appendToExportData( QString& out,
const std::vector<RimSummaryCurvesData>& curvesData,
bool showTimeAsLongString,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
RimSummaryCurvesData data = RimSummaryCurvesData::concatCurvesData( curvesData );

Expand Down Expand Up @@ -392,7 +429,7 @@ void RimSummaryCurvesData::appendToExportData( QString& out, const std::vector<R
}

out += "\n\n";
out += "Date and time";
out += timeColumnHeaderText( timeFromSimulationStart );
for ( size_t i = 0; i < data.caseIds.size(); i++ )
{
for ( auto& j : data.allCurveData[i] )
Expand All @@ -411,7 +448,11 @@ void RimSummaryCurvesData::appendToExportData( QString& out, const std::vector<R
QDateTime timseStepUtc = QDateTime::fromSecsSinceEpoch( timeStep ).toUTC();
QString timeText;

if ( showTimeAsLongString )
if ( timeFromSimulationStart )
{
timeText = timeStepText( timeStep, timeFromSimulationStart );
}
else if ( showTimeAsLongString )
{
timeText = timseStepUtc.toString( "yyyy-MM-dd hh:mm:ss " );
}
Expand Down Expand Up @@ -502,7 +543,7 @@ void RimSummaryCurvesData::appendToExportData( QString& out, const std::vector<R
out += "\n";
}

appendToExportDataForCase( out, data.timeSteps[i], data.allCurveData[i] );
appendToExportDataForCase( out, data.timeSteps[i], data.allCurveData[i], timeFromSimulationStart );
}
}
}
Expand Down
33 changes: 26 additions & 7 deletions ApplicationLibCode/ProjectDataModel/Summary/RimSummaryCurvesData.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@
#include "RiaDateTimeDefines.h"
#include "RifEclipseSummaryAddress.h"

#include "RimSummaryTimeAxisProperties.h"

#include <QString>

#include <optional>

class RimSummaryCurve;
class RimGridTimeHistoryCurve;
class RimAsciiDataCurve;
Expand All @@ -34,6 +38,14 @@ struct CurveData
std::vector<double> values;
};

// Used to report the time column as time from simulation start instead of date and time
struct TimeFromSimulationStartInfo
{
time_t simulationStartTime = 0;
RimSummaryTimeAxisProperties::TimeUnitType displayUnit = RimSummaryTimeAxisProperties::YEARS;
QString displayUnitText;
};

enum class SummaryCurveType
{
CURVE_TYPE_SUMMARY = 0x1,
Expand All @@ -53,11 +65,12 @@ class RimSummaryCurvesData
const std::vector<time_t>& curvetimeSteps,
const std::vector<CurveData>& curveDataVector );

static QString createTextForExport( const std::vector<RimSummaryCurve*>& curves,
const std::vector<RimAsciiDataCurve*>& asciiCurves,
const std::vector<RimGridTimeHistoryCurve*>& gridCurves,
RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString );
static QString createTextForExport( const std::vector<RimSummaryCurve*>& curves,
const std::vector<RimAsciiDataCurve*>& asciiCurves,
const std::vector<RimGridTimeHistoryCurve*>& gridCurves,
RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart = {} );

static QString createTextForCrossPlotCurves( const std::vector<RimSummaryCurve*>& curves );

Expand All @@ -70,8 +83,14 @@ class RimSummaryCurvesData
const RimSummaryCurvesData& inputCurvesData,
RimSummaryCurvesData* resultCurvesData );

static void appendToExportDataForCase( QString& out, const std::vector<time_t>& timeSteps, const std::vector<CurveData>& curveData );
static void appendToExportData( QString& out, const std::vector<RimSummaryCurvesData>& curvesData, bool showTimeAsLongString );
static void appendToExportDataForCase( QString& out,
const std::vector<time_t>& timeSteps,
const std::vector<CurveData>& curveData,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart );
static void appendToExportData( QString& out,
const std::vector<RimSummaryCurvesData>& curvesData,
bool showTimeAsLongString,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart );
RimSummaryCurvesData static concatCurvesData( const std::vector<RimSummaryCurvesData>& curvesData );

private:
Expand Down
Loading
Loading