mirror of
https://github.com/OPM/ResInsight.git
synced 2026-08-27 05:37:21 -05:00
Implement timeline-based event system for managing temporal changes in well completions, perforations, valves, and production controls. Features: - Event timeline container with date-based querying - Six event types: PERF, VALVE, TUBING, WSTATE, WTYPE, WCONTROL - Schedule keyword generation (DATES, COMPDAT, WELSEGS, WCONPROD, WCONINJE) - Multi-well schedule generation support - Python GRPC API for event management - YAML configuration file support - Comprehensive test suite Implementation: - New directory: ApplicationLibCode/ProjectDataModel/WellEvents/ - Event classes inherit from RimWellEvent base class - RimWellEventTimeline integrated into RimWellPath - RicScheduleDataGenerator for multi-well schedule export - Python API: event_timeline(), add_perf_event(), add_valve_event(), etc. - Tests verify all event types and YAML config parsing #13425 Add date tracking to valves and diameter/roughness intervals Add creation date fields to RimWellPathValve and RimDiameterRoughnessInterval to support filtering objects by date during completion data export. - Add m_useCustomStartDate and m_startDate fields - Add enableCustomStartDate(), setCustomStartDate(), isActiveOnDate() methods - Set creation dates when applying valve and tubing events in RimWellEventTimeline #13425 Add date-based filtering for schedule data export Add optional export date parameter to MSW data collection functions to filter valves and perforations based on their creation dates during schedule export. - Add exportDate parameter to collectWsegvalvData, collectWsegAicdData, collectWsegSicdData, and collectCompsegData functions - Filter valves by checking isActiveOnDate() on the associated RimWellPathValve - Add RimPerforationInterval reference to RicMswPerforation for date filtering - Pass export date from RicScheduleDataGenerator through the extraction chain This ensures segment numbers reflect the full model while only including objects active on the export date in output keywords. Add test to prove compsegs changes over time. #13425 Fix mypy type checking errors in well_events.py - Add type annotations to all function parameters - Fix generic type hints (dict -> Dict[str, Any]) - Import Any type for proper type safety - Add type: ignore for method reassignment - All 31 tests pass #13425 Add schedule-level keyword events for non-well-specific keywords Add a new event type called "Keyword Event" for schedule-level Eclipse keywords (RPTRST, GRUPTREE, RPTSCHED, etc.) that are NOT tied to a specific well path. This complements the existing RimWellEventKeyword which operates at the well level. - Add RimKeywordEvent class inheriting from RimWellEvent with null wellPath - Add SCHEDULE_KEYWORD enum value to EventType - Add addKeywordEvent() method to RimWellEventTimeline - Add AddKeywordEvent Python API method to RimcWellEventTimeline - Update RicScheduleDataGenerator to output global keywords after well sections - Add Python wrapper add_keyword_event() with type inference - Add tests and examples for RPTRST, GRUPTREE keywords
594 lines
20 KiB
C++
594 lines
20 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2025- 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 "RimWellEventTimeline.h"
|
|
|
|
#include "RimKeywordEvent.h"
|
|
#include "RimWellEvent.h"
|
|
#include "RimWellEventControl.h"
|
|
#include "RimWellEventKeyword.h"
|
|
#include "RimWellEventPerf.h"
|
|
#include "RimWellEventState.h"
|
|
#include "RimWellEventTubing.h"
|
|
#include "RimWellEventType.h"
|
|
#include "RimWellEventValve.h"
|
|
|
|
#include "RimDiameterRoughnessInterval.h"
|
|
#include "RimDiameterRoughnessIntervalCollection.h"
|
|
#include "RimMswCompletionParameters.h"
|
|
#include "RimPerforationCollection.h"
|
|
#include "RimPerforationInterval.h"
|
|
#include "RimProject.h"
|
|
#include "RimTools.h"
|
|
#include "RimValveTemplate.h"
|
|
#include "RimWellPath.h"
|
|
#include "RimWellPathCollection.h"
|
|
#include "RimWellPathValve.h"
|
|
|
|
#include "Riu3DMainWindowTools.h"
|
|
|
|
#include "cafPdmFieldScriptingCapability.h"
|
|
#include "cafPdmObjectScriptingCapability.h"
|
|
#include "cafPdmUiTreeOrdering.h"
|
|
|
|
#include <algorithm>
|
|
#include <set>
|
|
|
|
CAF_PDM_SOURCE_INIT( RimWellEventTimeline, "WellEventTimeline" );
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventTimeline::RimWellEventTimeline()
|
|
{
|
|
CAF_PDM_InitScriptableObject( "Well Event Timeline", "", "", "WellEventTimeline" );
|
|
|
|
CAF_PDM_InitScriptableFieldNoDefault( &m_events, "Events", "Events" );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventTimeline::~RimWellEventTimeline()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimWellEvent*> RimWellEventTimeline::events() const
|
|
{
|
|
return m_events.childrenByType();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<QDateTime> RimWellEventTimeline::getAllEventDates() const
|
|
{
|
|
std::set<QDateTime> uniqueDates;
|
|
|
|
for ( const auto& event : m_events )
|
|
{
|
|
if ( event && event->eventDate().isValid() )
|
|
{
|
|
uniqueDates.insert( event->eventDate() );
|
|
}
|
|
}
|
|
|
|
return std::vector<QDateTime>( uniqueDates.begin(), uniqueDates.end() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimWellEvent*> RimWellEventTimeline::getEventsAtDate( const QDateTime& date ) const
|
|
{
|
|
std::vector<RimWellEvent*> result;
|
|
|
|
for ( auto& event : m_events )
|
|
{
|
|
if ( event && event->eventDate() == date )
|
|
{
|
|
result.push_back( event );
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimWellEvent*> RimWellEventTimeline::getEventsByType( RimWellEvent::EventType type ) const
|
|
{
|
|
std::vector<RimWellEvent*> result;
|
|
|
|
for ( auto& event : m_events )
|
|
{
|
|
if ( event && event->eventType() == type )
|
|
{
|
|
result.push_back( event );
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimWellEvent*> RimWellEventTimeline::getEventsUpToDate( const QDateTime& date ) const
|
|
{
|
|
std::vector<RimWellEvent*> result;
|
|
|
|
for ( auto& event : m_events )
|
|
{
|
|
if ( event && event->eventDate().isValid() && event->eventDate() <= date )
|
|
{
|
|
result.push_back( event );
|
|
}
|
|
}
|
|
|
|
// Sort by date
|
|
std::sort( result.begin(), result.end(), []( const RimWellEvent* a, const RimWellEvent* b ) { return a->eventDate() < b->eventDate(); } );
|
|
|
|
return result;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimWellPath*> RimWellEventTimeline::getWellPathsWithEvents() const
|
|
{
|
|
std::set<RimWellPath*> uniqueWellPaths;
|
|
|
|
for ( auto& event : m_events )
|
|
{
|
|
if ( event && event->wellPath() )
|
|
{
|
|
uniqueWellPaths.insert( event->wellPath() );
|
|
}
|
|
}
|
|
|
|
return std::vector<RimWellPath*>( uniqueWellPaths.begin(), uniqueWellPaths.end() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimWellPath*> RimWellEventTimeline::getWellPathsWithEventsUpToDate( const QDateTime& date ) const
|
|
{
|
|
std::set<RimWellPath*> uniqueWellPaths;
|
|
|
|
for ( auto& event : m_events )
|
|
{
|
|
if ( event && event->wellPath() && event->eventDate().isValid() && event->eventDate() <= date )
|
|
{
|
|
uniqueWellPaths.insert( event->wellPath() );
|
|
}
|
|
}
|
|
|
|
return std::vector<RimWellPath*>( uniqueWellPaths.begin(), uniqueWellPaths.end() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RimWellEventTimeline::lastAppliedTimestamp() const
|
|
{
|
|
return m_lastAppliedTimestamp;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventPerf* RimWellEventTimeline::addPerforationEvent( RimWellPath* wellPath, const QDateTime& date )
|
|
{
|
|
auto* event = new RimWellEventPerf();
|
|
event->setWellPath( wellPath );
|
|
event->setEventDate( date );
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
return event;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventValve* RimWellEventTimeline::addValveEvent( RimWellPath* wellPath, const QDateTime& date )
|
|
{
|
|
auto* event = new RimWellEventValve();
|
|
event->setWellPath( wellPath );
|
|
event->setEventDate( date );
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
return event;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventTubing* RimWellEventTimeline::addTubingEvent( RimWellPath* wellPath, const QDateTime& date )
|
|
{
|
|
auto* event = new RimWellEventTubing();
|
|
event->setWellPath( wellPath );
|
|
event->setEventDate( date );
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
return event;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventState* RimWellEventTimeline::addStateEvent( RimWellPath* wellPath, const QDateTime& date )
|
|
{
|
|
auto* event = new RimWellEventState();
|
|
event->setWellPath( wellPath );
|
|
event->setEventDate( date );
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
return event;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventType* RimWellEventTimeline::addTypeEvent( RimWellPath* wellPath, const QDateTime& date )
|
|
{
|
|
auto* event = new RimWellEventType();
|
|
event->setWellPath( wellPath );
|
|
event->setEventDate( date );
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
return event;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventControl* RimWellEventTimeline::addControlEvent( RimWellPath* wellPath, const QDateTime& date )
|
|
{
|
|
auto* event = new RimWellEventControl();
|
|
event->setWellPath( wellPath );
|
|
event->setEventDate( date );
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
return event;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimWellEventKeyword* RimWellEventTimeline::addWellKeywordEvent( RimWellPath* wellPath, const QDateTime& date, const QString& keywordName )
|
|
{
|
|
auto* event = new RimWellEventKeyword();
|
|
event->setWellPath( wellPath );
|
|
event->setEventDate( date );
|
|
event->setKeywordName( keywordName );
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
return event;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimKeywordEvent* RimWellEventTimeline::addKeywordEvent( const QDateTime& date, const QString& keywordName )
|
|
{
|
|
auto* event = new RimKeywordEvent();
|
|
// Note: wellPath is NOT set for schedule-level keyword events
|
|
event->setEventDate( date );
|
|
event->setKeywordName( keywordName );
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
return event;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimWellEventTimeline::addEvent( RimWellEvent* event )
|
|
{
|
|
if ( event )
|
|
{
|
|
m_events.push_back( event );
|
|
updateConnectedEditors();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimWellEventTimeline::removeEvent( RimWellEvent* event )
|
|
{
|
|
m_events.removeChild( event );
|
|
delete event;
|
|
updateConnectedEditors();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimWellEventTimeline::clearAllEvents()
|
|
{
|
|
m_events.deleteChildren();
|
|
updateConnectedEditors();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t RimWellEventTimeline::eventCount() const
|
|
{
|
|
return m_events.size();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimWellEventTimeline::applyEventsUpToDate( const QDateTime& date )
|
|
{
|
|
// Store the timestamp for later use in schedule generation
|
|
m_lastAppliedTimestamp = date;
|
|
|
|
// Get events up to the specified date (already sorted by date)
|
|
std::vector<RimWellEvent*> eventsToApply = getEventsUpToDate( date );
|
|
|
|
if ( eventsToApply.empty() )
|
|
{
|
|
return true; // Nothing to apply is not an error
|
|
}
|
|
|
|
// Get the well path collection from the parent hierarchy
|
|
auto* wellPathCollection = firstAncestorOrThisOfType<RimWellPathCollection>();
|
|
if ( !wellPathCollection )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool anyEventApplied = false;
|
|
|
|
// Apply each event based on its type
|
|
for ( RimWellEvent* event : eventsToApply )
|
|
{
|
|
bool success = applyEvent( wellPathCollection, event );
|
|
if ( success )
|
|
{
|
|
anyEventApplied = true;
|
|
}
|
|
}
|
|
|
|
// Update views if any events were applied
|
|
if ( anyEventApplied )
|
|
{
|
|
RimProject::current()->scheduleCreateDisplayModelAndRedrawAllViews();
|
|
}
|
|
|
|
return anyEventApplied;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimWellEventTimeline::applyEvent( RimWellPathCollection* wellPathCollection, RimWellEvent* event )
|
|
{
|
|
// Find the well path by name
|
|
if ( RimWellPath* wellPath = wellPathCollection->wellPathByName( event->wellName() ) )
|
|
{
|
|
switch ( event->eventType() )
|
|
{
|
|
case RimWellEvent::EventType::PERF:
|
|
{
|
|
if ( auto* perfEvent = dynamic_cast<RimWellEventPerf*>( event ) )
|
|
{
|
|
return applyPerfEvent( *perfEvent, *wellPath );
|
|
}
|
|
break;
|
|
}
|
|
case RimWellEvent::EventType::TUBING:
|
|
{
|
|
if ( auto* tubingEvent = dynamic_cast<RimWellEventTubing*>( event ) )
|
|
{
|
|
return applyTubingEvent( *tubingEvent, *wellPath );
|
|
}
|
|
break;
|
|
}
|
|
case RimWellEvent::EventType::VALVE:
|
|
{
|
|
if ( auto* valveEvent = dynamic_cast<RimWellEventValve*>( event ) )
|
|
{
|
|
return applyValveEvent( *valveEvent, *wellPath );
|
|
}
|
|
break;
|
|
}
|
|
case RimWellEvent::EventType::WSTATE:
|
|
case RimWellEvent::EventType::WCONTROL:
|
|
case RimWellEvent::EventType::WTYPE:
|
|
// Skip WSTATE and WCONTROL events per requirements
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimWellEventTimeline::applyTubingEvent( const RimWellEventTubing& event, RimWellPath& wellPath )
|
|
{
|
|
auto* mswParams = wellPath.mswCompletionParameters();
|
|
if ( !mswParams )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto* intervalCollection = mswParams->diameterRoughnessIntervals();
|
|
if ( !intervalCollection )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Set the diameter roughness mode to intervals
|
|
mswParams->setDiameterRoughnessMode( RimMswCompletionParameters::DiameterRoughnessMode::INTERVALS );
|
|
|
|
// Create a new interval
|
|
auto* interval = intervalCollection->createInterval( event.startMD(), event.endMD(), event.innerDiameter(), event.roughness() );
|
|
|
|
if ( interval )
|
|
{
|
|
// Set the custom start date based on the event date
|
|
interval->enableCustomStartDate( true );
|
|
interval->setCustomStartDate( event.eventDate().date() );
|
|
|
|
mswParams->updateConnectedEditors();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimWellEventTimeline::applyPerfEvent( const RimWellEventPerf& event, RimWellPath& wellPath )
|
|
{
|
|
auto* perfCollection = wellPath.perforationIntervalCollection();
|
|
if ( !perfCollection )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Create a new perforation interval
|
|
auto* perfInterval = new RimPerforationInterval;
|
|
perfInterval->setStartAndEndMD( event.startMD(), event.endMD() );
|
|
perfInterval->setDiameter( event.diameter() );
|
|
perfInterval->setSkinFactor( event.skinFactor() );
|
|
perfInterval->setUnitSystemSpecificDefaults();
|
|
|
|
// Set the custom start date based on the event date
|
|
perfInterval->enableCustomStartDate( true );
|
|
perfInterval->setCustomStartDate( event.eventDate().date() );
|
|
|
|
perfCollection->appendPerforation( perfInterval );
|
|
perfCollection->updateConnectedEditors();
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimWellEventTimeline::applyValveEvent( const RimWellEventValve& event, RimWellPath& wellPath )
|
|
{
|
|
auto* perfCollection = wellPath.perforationIntervalCollection();
|
|
if ( !perfCollection )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto findByMeasuredDepth = []( const std::vector<RimPerforationInterval*>& perfs, double valveMD ) -> RimPerforationInterval*
|
|
{
|
|
for ( auto* perf : perfs )
|
|
{
|
|
if ( valveMD >= perf->startMD() && valveMD <= perf->endMD() ) return perf;
|
|
}
|
|
|
|
return nullptr;
|
|
};
|
|
|
|
// Find a perforation interval that contains this valve's measured depth
|
|
std::vector<RimPerforationInterval*> perfs = perfCollection->perforationsNoConst();
|
|
double valveMD = event.measuredDepth();
|
|
RimPerforationInterval* targetPerf = findByMeasuredDepth( perfs, valveMD );
|
|
|
|
if ( !targetPerf )
|
|
{
|
|
// No matching perforation found - valve cannot be placed
|
|
return false;
|
|
}
|
|
|
|
// Create a new valve
|
|
auto* valve = new RimWellPathValve;
|
|
|
|
targetPerf->addValve( valve );
|
|
|
|
valve->setMeasuredDepthAndCount( valveMD, 0, 1 );
|
|
|
|
// Set the custom start date based on the event date
|
|
valve->enableCustomStartDate( true );
|
|
valve->setCustomStartDate( event.eventDate().date() );
|
|
|
|
auto convertToValveType = []( RimWellEventValve::ValveType valveType )
|
|
{
|
|
switch ( valveType )
|
|
{
|
|
case RimWellEventValve::ValveType::ICD:
|
|
return RiaDefines::WellPathComponentType::ICD;
|
|
case RimWellEventValve::ValveType::AICD:
|
|
return RiaDefines::WellPathComponentType::AICD;
|
|
case RimWellEventValve::ValveType::ICV:
|
|
default:
|
|
return RiaDefines::WellPathComponentType::ICV;
|
|
}
|
|
};
|
|
|
|
// Map the event valve type to the RiaDefines type and find a matching template
|
|
RiaDefines::WellPathComponentType valveComponentType = convertToValveType( event.valveType() );
|
|
|
|
// Try to find a matching valve template
|
|
if ( RimProject* project = RimProject::current() )
|
|
{
|
|
for ( auto* tmpl : project->allValveTemplates() )
|
|
{
|
|
if ( tmpl->type() == valveComponentType )
|
|
{
|
|
valve->setValveTemplate( tmpl );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
targetPerf->updateConnectedEditors();
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimWellEventTimeline::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
|
|
{
|
|
setUiName( QString( "Event Timeline (%1 events)" ).arg( m_events.size() ) );
|
|
|
|
// Sort events by date for display
|
|
std::vector<RimWellEvent*> sortedEvents = events();
|
|
std::sort( sortedEvents.begin(),
|
|
sortedEvents.end(),
|
|
[]( const RimWellEvent* a, const RimWellEvent* b ) { return a->eventDate() < b->eventDate(); } );
|
|
|
|
for ( auto* event : sortedEvents )
|
|
{
|
|
uiTreeOrdering.add( event );
|
|
}
|
|
|
|
uiTreeOrdering.skipRemainingChildren();
|
|
}
|