CEP 31 - Agent Registered Discrete Event Timing #447
CEP 31 - Agent Registered Discrete Event Timing #447meg-krieg wants to merge 8 commits intocyclus:sourcefrom
Conversation
There was a problem hiding this comment.
Thanks for kicking this off @meg-krieg!
I'm not sure I understand the motivation for not allowing Tick/Tock/Decision to be registered as events that come at discrete time queued by the context/timer?
| These actions map to the current *kernel* phases of cyclus's cardinal function. Thus, by extent, | ||
|
|
||
| - Tick | ||
| - Tock | ||
| - Decision | ||
|
|
||
| may not be considered events because they do *not* change the simulation state. They change | ||
| the agent's internal state (agent phase). As these actions are not events, they may never be independently registered by agents. | ||
| (There are scenarios in which build/requets/decomission may trigger them, however.) |
There was a problem hiding this comment.
This seems like a key point of discussion/contention. Can you say more about why you want this strict interpretation? If the context will be skipping time steps based on the registered events, how will agents know when it is time to tick or tock? How will they be triggered? What if a tick is necessary to determine whether or not to participate in a trade?
There was a problem hiding this comment.
There are scenarios in which i can see the Tock and Decision being registrable events based on the outcome of the DRE.
It is mainly the tick that cannot be registrable (in my opinion)! If all traders objects are available bidders every trade event and all bidders need accurate bid information and we don't know who will bid, then all bidders must all tick. In other words, all traders must tick either every scheduled event or every trade event.
I could be really off the mark though.
| =============================== | ||
|
|
||
| Material requests, Build, and Decomissioin event registration will be handled by individual agents. Cyclus already creates a preconditioned timeline | ||
| for discrete-build and decomission events. An additional ``EventRequest()`` member funcition for all cycamore archetypes will check a facility's inventory. |
There was a problem hiding this comment.
If such a function is necessary, it should perhaps be added to the agent class from which these all derive.
| for discrete-build and decomission events. An additional ``EventRequest()`` member funcition for all cycamore archetypes will check a facility's inventory. | ||
|
|
||
| 1. If inventory not at capacity, agent will register for the (+1) next immediate time step to attempt another request. | ||
| 2. If inventory at capacity, agent will register its next request event for a fixed ``+ cycle_length`` time from the current event. |
There was a problem hiding this comment.
This is too rooted in the current set of archetypes. We need to think beyond the concept of cycle length and reactors.
| 2. If inventory at capacity, agent will register its next request event for a fixed ``+ cycle_length`` time from the current event. | ||
|
|
||
| These material request events will be registered within Context in a dynamic dictionary that contains the event's timestamp and a list of ``Trader`` objects. To ensure that all | ||
| facility agents' ``EventRequest()`` functions are checked regularly, A look-ahead function will be added to cyclus's cardinal phase suite after the decomissioning phase. |
There was a problem hiding this comment.
Doesn't this degenerate to time steps again? I don't know what the purpose of a look-ahead function is and when/how it gets triggered?
There was a problem hiding this comment.
I pasted some general code below in case my words are really vague! Maybe this makes what I am thinking a little clearer? It is pretty bare-bones but just for a general idea -- in timer.cc
void Timer::RunSim() {
...
ctx_->Populate(0); // at time 0 everyone must register for a trade event to get started
while ( (time_ < si_.duration) && (prev_time_ != time_)) {
CLOG(LEV_INFO1) << "Current time: " << time_;
if (want_snapshot_) {
want_snapshot_ = false;
SimInit::Snapshot(ctx_);
}
// run through phases
DoBuild();
CLOG(LEV_INFO2) << "Beginning Tick for time: " << time_;
DoTick();
CLOG(LEV_INFO2) << "Beginning DRE for time: " << time_;
DoResEx(&matl_manager, &genrsrc_manager);
CLOG(LEV_INFO2) << "Beginning Tock for time: " << time_;
DoTock();
CLOG(LEV_INFO2) << "Beginning Decision for time: " << time_;
DoDecision();
DoDecom();
DoLookAhead();
#ifdef CYCLUS_WITH_PYTHON
EventLoop();
#endif
prev_time_ = time_;
time_ = NextEvent();
...
}Then, later in timer.cc, something similar to this will happen where timer checks for the next closest event registered in the timeline. (this is not meant to be accurate code).
void Timer::DoLookAhead() {
std::set<Trader*> all_traders = ctx_->traders();
for(Trader* m : all_traders){
m->EventRequest();
};
// another check will probably go here
}
int Timer::NextEvent(){
auto reg_traders = ctx_->EventRequesters(); //the list of traders who have registered for events in the timeline
int t_p = time_ +1; // time plus +1
std::vector<int> event_lists = {decom_queue_.upper_bound(t_p)->first,build_queue_.upper_bound(t_p)->first}, reg_traders.upper_bound(t_p)->first};
return *std::min_element(event_lists.begin(), event_lists.end());
}So, the simulation finishes some event and it looks for the next closest timestamp that has an event. That timestamp could have events registered under any 3, 2, or 1 of build/trade/decom actions scheduled. The simulation knows it has the event at the timestamp but does not know which type (this could change maybe), so it checks each phase for that event. If the phase is filled with participants, that phase is one of the events and is triggered.
This means that the phases will have some conditional check... for example
void Timer::DoBuild() {
if(build_queue_.count(time_)==0){
continue;}
else{
std::vector<std::pair<std::string, Agent*>> build_list = build_queue_[time_];
for (int i = 0; i < build_list.size(); ++i) {
Agent* m = ctx_->CreateAgent<Agent>(build_list[i].first);
Agent* parent = build_list[i].second;
...
}
...
}Overall, this treatment should skip the timeline from event to event instead of timestep to next timestep when fully fleshed out.
Summary of Changes
This PR adds a CEP 31 for discrete event timing proposal in Cyclus (and by extent cycamore). There are many areas where a more robust implementation can be proposed including
cycle_lengthfor each archetype to schedule new events under a capacity-met conditionTimer::RunSim()phase suite ordering within each event even if timesteps are skippedThe CEP goes through a broad restructuring ideas and more detailed implementation could be outlined in the future. Any suggestions to the implementations, clarifications to the CEP, or other comments from the cyclus community would be great!
Related CEPs and Issues
Creates new CEP 31.