mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-24 22:27:55 -05:00
#14688 Sim Events: Add API to query event dates and wells
Add event date and well queries with date, owner and event type/keyword filters to SimulatorEventsDocument and WellEventTimeline, including latest_event_date() and wells_with_msw_events() for building the export_msw_for_wells list.
This commit is contained in:
1 parent
360c3c69db
commit
8dc1d56bd3
11 files changed
+903
-3
No files matched your search
@@ -219,6 +219,50 @@ QDateTime RimWellEventTimeline::lastAppliedTimestamp() const
|
||||
return m_lastAppliedTimestamp;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RimWellEvent*> RimWellEventTimeline::queryEvents( const EventQuery& query ) const
|
||||
{
|
||||
auto keywordName = []( const RimWellEvent* event ) -> QString
|
||||
{
|
||||
if ( auto keywordEvent = dynamic_cast<const RimWellEventKeyword*>( event ) ) return keywordEvent->keywordName().toUpper();
|
||||
if ( auto scheduleKeywordEvent = dynamic_cast<const RimKeywordEvent*>( event ) )
|
||||
return scheduleKeywordEvent->keywordName().toUpper();
|
||||
return {};
|
||||
};
|
||||
|
||||
auto matchesType = [&]( const RimWellEvent* event )
|
||||
{
|
||||
if ( query.eventTypes.empty() && query.keywords.empty() ) return true;
|
||||
if ( query.eventTypes.contains( event->eventType() ) ) return true;
|
||||
if ( query.keywords.empty() ) return false;
|
||||
|
||||
const QString keyword = keywordName( event );
|
||||
return !keyword.isEmpty() && query.keywords.contains( keyword );
|
||||
};
|
||||
|
||||
std::vector<RimWellEvent*> result;
|
||||
for ( auto& event : m_events )
|
||||
{
|
||||
if ( !event || !event->eventDate().isValid() ) continue;
|
||||
|
||||
const QDateTime date = event->eventDate();
|
||||
if ( query.startDate.isValid() && date < query.startDate ) continue;
|
||||
if ( query.endDate.isValid() && date > query.endDate ) continue;
|
||||
if ( !query.wellPaths.empty() && !query.wellPaths.contains( event->wellPath() ) ) continue;
|
||||
if ( !matchesType( event ) ) continue;
|
||||
|
||||
result.push_back( event );
|
||||
}
|
||||
|
||||
std::stable_sort( result.begin(),
|
||||
result.end(),
|
||||
[]( const RimWellEvent* a, const RimWellEvent* b ) { return a->eventDate() < b->eventDate(); } );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include "cafPdmPtrArrayField.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
class RimWellEventPerf;
|
||||
@@ -59,6 +62,16 @@ public:
|
||||
TYPE
|
||||
};
|
||||
|
||||
// Filter for queryEvents(). Invalid dates leave the range open, empty sets disable the filter.
|
||||
struct EventQuery
|
||||
{
|
||||
QDateTime startDate;
|
||||
QDateTime endDate;
|
||||
std::set<const RimWellPath*> wellPaths;
|
||||
std::set<RimWellEvent::EventType> eventTypes;
|
||||
std::set<QString> keywords; // Upper case keyword names
|
||||
};
|
||||
|
||||
RimWellEventTimeline();
|
||||
~RimWellEventTimeline() override;
|
||||
|
||||
@@ -73,6 +86,9 @@ public:
|
||||
std::vector<RimWellPath*> getWellPathsWithEvents() const;
|
||||
std::vector<RimWellPath*> getWellPathsWithEventsUpToDate( const QDateTime& date ) const;
|
||||
|
||||
// Events matching all filters in the query, sorted by date. Ignores the applied timestamp.
|
||||
std::vector<RimWellEvent*> queryEvents( const EventQuery& query ) const;
|
||||
|
||||
// Add event methods (return the created event for further configuration)
|
||||
RimWellEventPerf* addPerforationEvent( RimWellPath* wellPath, const QDateTime& date );
|
||||
RimWellEventValve* addValveEvent( RimWellPath* wellPath, const QDateTime& date );
|
||||
|
||||
@@ -48,6 +48,52 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Builds a timeline query from the scripting arguments. Empty dates leave the range open. Each event
|
||||
/// type is either an event type name (SEGMENT, PERF, ...) or a keyword name (WCONHIST, ...).
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::expected<RimWellEventTimeline::EventQuery, QString> createEventQuery( const QString& startDate,
|
||||
const QString& endDate,
|
||||
const std::vector<RimWellPath*>& wellPaths,
|
||||
const std::vector<QString>& eventTypes )
|
||||
{
|
||||
RimWellEventTimeline::EventQuery query;
|
||||
|
||||
auto parseDate = []( const QString& text, QDateTime& date ) -> std::expected<void, QString>
|
||||
{
|
||||
if ( text.trimmed().isEmpty() ) return {};
|
||||
|
||||
date = QDateTime::fromString( text.trimmed(), Qt::ISODate );
|
||||
if ( !date.isValid() ) return std::unexpected( QString( "Invalid date format: %1. Expected YYYY-MM-DD" ).arg( text ) );
|
||||
return {};
|
||||
};
|
||||
|
||||
if ( auto result = parseDate( startDate, query.startDate ); !result ) return std::unexpected( result.error() );
|
||||
if ( auto result = parseDate( endDate, query.endDate ); !result ) return std::unexpected( result.error() );
|
||||
|
||||
for ( auto wellPath : wellPaths )
|
||||
{
|
||||
if ( wellPath ) query.wellPaths.insert( wellPath );
|
||||
}
|
||||
|
||||
for ( const auto& eventType : eventTypes )
|
||||
{
|
||||
const QString name = eventType.trimmed().toUpper();
|
||||
if ( name.isEmpty() ) continue;
|
||||
|
||||
if ( caf::AppEnum<RimWellEvent::EventType>::isValid( name ) )
|
||||
{
|
||||
query.eventTypes.insert( caf::AppEnum<RimWellEvent::EventType>::fromText( name ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
query.keywords.insert( name );
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
std::expected<void, QString> validateKeywordItems( const QString& keywordName, const std::vector<QString>& itemNames )
|
||||
{
|
||||
auto keywordInfo = RiaOpmKeywordTools::keywordInfo( keywordName );
|
||||
@@ -898,3 +944,134 @@ QString RimcWellEventTimeline_generateSchedule::classKeywordReturnedType() const
|
||||
{
|
||||
return RimcDataContainerString::classKeywordStatic();
|
||||
}
|
||||
|
||||
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimWellEventTimeline, RimcWellEventTimeline_eventDates, "QueryEventDates" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimcWellEventTimeline_eventDates::RimcWellEventTimeline_eventDates( caf::PdmObjectHandle* self )
|
||||
: caf::PdmObjectMethod( self, PdmObjectMethod::NullPointerType::NULL_IS_INVALID, PdmObjectMethod::ResultType::PERSISTENT_FALSE )
|
||||
{
|
||||
CAF_PDM_InitObject( "Event Dates", "", "", "Sorted, unique dates of the events matching the filters, as ISO date-time strings" );
|
||||
|
||||
CAF_PDM_InitScriptableField( &m_startDate, "StartDate", QString(), "", "", "", "Earliest date to include (inclusive). Empty: no limit" );
|
||||
CAF_PDM_InitScriptableField( &m_endDate,
|
||||
"EndDate",
|
||||
QString(),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Latest date to include (inclusive). A date-only value means midnight, excluding events later that day. "
|
||||
"Empty: no limit" );
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_wellPaths,
|
||||
"WellPaths",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Only include events for these wells. Empty: events for all wells and schedule events" );
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_eventTypes,
|
||||
"EventTypes",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Event types (SEGMENT, PERF, VALVE, ...) or keyword names (WCONHIST, ...). Empty: all events" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::expected<caf::PdmObjectHandle*, QString> RimcWellEventTimeline_eventDates::execute()
|
||||
{
|
||||
auto timeline = self<RimWellEventTimeline>();
|
||||
|
||||
auto query = createEventQuery( m_startDate(), m_endDate(), m_wellPaths.ptrReferencedObjectsByType(), m_eventTypes() );
|
||||
if ( !query ) return std::unexpected( query.error() );
|
||||
|
||||
std::set<QDateTime> dates;
|
||||
for ( auto event : timeline->queryEvents( *query ) )
|
||||
{
|
||||
dates.insert( event->eventDate() );
|
||||
}
|
||||
|
||||
// Explicit format without a time zone suffix, as the event dates are stored in local time
|
||||
std::vector<QString> dateTexts;
|
||||
for ( const auto& date : dates )
|
||||
{
|
||||
dateTexts.push_back( date.toString( "yyyy-MM-ddTHH:mm:ss" ) );
|
||||
}
|
||||
|
||||
auto* dataObject = new RimcDataContainerString();
|
||||
dataObject->m_stringValues = dateTexts;
|
||||
|
||||
return dataObject;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimcWellEventTimeline_eventDates::classKeywordReturnedType() const
|
||||
{
|
||||
return RimcDataContainerString::classKeywordStatic();
|
||||
}
|
||||
|
||||
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimWellEventTimeline, RimcWellEventTimeline_wellsWithEvents, "QueryWellsWithEvents" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimcWellEventTimeline_wellsWithEvents::RimcWellEventTimeline_wellsWithEvents( caf::PdmObjectHandle* self )
|
||||
: caf::PdmObjectMethod( self, PdmObjectMethod::NullPointerType::NULL_IS_INVALID, PdmObjectMethod::ResultType::PERSISTENT_FALSE )
|
||||
{
|
||||
CAF_PDM_InitObject( "Wells With Events",
|
||||
"",
|
||||
"",
|
||||
"Sorted names of the well paths with events matching the filters. "
|
||||
"Well path names must be unique within the well path collection" );
|
||||
|
||||
CAF_PDM_InitScriptableField( &m_startDate, "StartDate", QString(), "", "", "", "Earliest date to include (inclusive). Empty: no limit" );
|
||||
CAF_PDM_InitScriptableField( &m_endDate,
|
||||
"EndDate",
|
||||
QString(),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Latest date to include (inclusive). A date-only value means midnight, excluding events later that day. "
|
||||
"Empty: no limit" );
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_eventTypes,
|
||||
"EventTypes",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Event types (SEGMENT, PERF, VALVE, ...) or keyword names (WCONHIST, ...). Empty: all events" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::expected<caf::PdmObjectHandle*, QString> RimcWellEventTimeline_wellsWithEvents::execute()
|
||||
{
|
||||
auto timeline = self<RimWellEventTimeline>();
|
||||
|
||||
auto query = createEventQuery( m_startDate(), m_endDate(), {}, m_eventTypes() );
|
||||
if ( !query ) return std::unexpected( query.error() );
|
||||
|
||||
std::set<QString> wellNames;
|
||||
for ( auto event : timeline->queryEvents( *query ) )
|
||||
{
|
||||
if ( event->wellPath() ) wellNames.insert( event->wellPath()->name() );
|
||||
}
|
||||
|
||||
auto* dataObject = new RimcDataContainerString();
|
||||
dataObject->m_stringValues = std::vector<QString>( wellNames.begin(), wellNames.end() );
|
||||
|
||||
return dataObject;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimcWellEventTimeline_wellsWithEvents::classKeywordReturnedType() const
|
||||
{
|
||||
return RimcDataContainerString::classKeywordStatic();
|
||||
}
|
||||
@@ -300,3 +300,42 @@ private:
|
||||
caf::PdmField<bool> m_firstDateAsComment;
|
||||
caf::PdmField<bool> m_alignColumns;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimcWellEventTimeline_eventDates : public caf::PdmObjectMethod
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimcWellEventTimeline_eventDates( caf::PdmObjectHandle* self );
|
||||
|
||||
std::expected<caf::PdmObjectHandle*, QString> execute() override;
|
||||
QString classKeywordReturnedType() const override;
|
||||
|
||||
private:
|
||||
caf::PdmField<QString> m_startDate;
|
||||
caf::PdmField<QString> m_endDate;
|
||||
caf::PdmPtrArrayField<RimWellPath*> m_wellPaths;
|
||||
caf::PdmField<std::vector<QString>> m_eventTypes;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimcWellEventTimeline_wellsWithEvents : public caf::PdmObjectMethod
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimcWellEventTimeline_wellsWithEvents( caf::PdmObjectHandle* self );
|
||||
|
||||
std::expected<caf::PdmObjectHandle*, QString> execute() override;
|
||||
QString classKeywordReturnedType() const override;
|
||||
|
||||
private:
|
||||
caf::PdmField<QString> m_startDate;
|
||||
caf::PdmField<QString> m_endDate;
|
||||
caf::PdmField<std::vector<QString>> m_eventTypes;
|
||||
};
|
||||
Reference in new issue
Block a user