Program Listing for File event.h
↰ Return to documentation for file (include/amici/event.h)
#ifndef AMICI_EVENT_H
#define AMICI_EVENT_H
#include "amici/defines.h"
#include "amici/model_state.h"
#include <algorithm>
#include <iterator>
#include <list>
#include <optional>
#include <stdexcept>
#include <string>
namespace amici {
class Event {
public:
Event(
std::string id, bool use_values_from_trigger_time, bool initial_value,
realtype priority
)
: id_(id)
, use_values_from_trigger_time_(use_values_from_trigger_time)
, initial_value_(initial_value)
, priority_(priority) {}
std::string const& get_id() const { return id_; }
bool get_initial_value() const { return initial_value_; }
realtype get_priority() const { return priority_; }
bool uses_values_from_trigger_time() const {
return use_values_from_trigger_time_;
}
private:
std::string id_;
bool use_values_from_trigger_time_;
bool initial_value_ = true;
realtype priority_ = NAN;
};
struct PendingEvent {
Event const& event;
int idx;
std::optional<SimulationState> state_old;
};
class EventQueue {
public:
EventQueue() = default;
bool empty() const { return pending_events_.empty(); }
void push(PendingEvent event) { pending_events_.push_back(event); }
PendingEvent pop() {
if (empty()) {
throw std::runtime_error("No pending events");
}
// Sort events by priority from high to low.
pending_events_.sort([](PendingEvent const& a, PendingEvent const& b) {
// The priority is to NaN in AMICI if not defined.
// In this case, the execution order is undefined,
// so this does not need any special treatment.
return a.event.get_priority() > b.event.get_priority();
});
// If there is any undefined (NaN) priority, the order of all
// simulataneously executed events is undefined. We just proceed
// with the first one in the list.
if (std::any_of(
pending_events_.begin(), pending_events_.end(),
[](PendingEvent const& e) {
return std::isnan(e.event.get_priority());
}
)) {
auto event = pending_events_.front();
pending_events_.pop_front();
return event;
}
// If there are multiple events with the same not-NaN priority,
// then *their* ordering is random (not undefined).
int num_equal_priority = 0;
for (auto it = pending_events_.begin(); it != pending_events_.end();
++it) {
if (it->event.get_priority()
== pending_events_.front().event.get_priority()) {
num_equal_priority++;
} else {
break;
}
}
auto it = pending_events_.begin();
if (num_equal_priority > 1) {
// choose randomly among the events with the same priority
std::advance(it, rand() % num_equal_priority);
}
auto event = *it;
pending_events_.erase(it);
return event;
}
private:
std::list<PendingEvent> pending_events_;
};
} // namespace amici
#endif // AMICI_EVENT_H