so my model works fine, but since I introduced conditional events (= an event that triggers once a specified condition is met), I find that the computational performance is decreased.
This is especially annoying when I run experiments with many iterations...
Is there an alternative way to trigger an event at a specified condition?
Thank you :)
The answer to this will be triggering events directly by the mechanism that are influencing the conditions you are monitoring. So instead of having the "permanent" condition check, make sure that each time the condition changes you are triggering a check. If that is not possible, because there are too many influencing factors, or it is continuosly changing, consider a cyclic check in discrete timesteps at an interval that suits you. Even this will be much more performant (depending on your choosen time check interval) then the current continous monitoring.
Example on how to do an event trigger monitoring instead of continous monitoring:
In your main, add global counter variable of type int (here: nrAgentsState1) and create a function to update that variable (here: updateStateCounter). Also in the function: a check that triggers a function whenever your threeshold is reached.
In your transition leading into the state you want to monitor (here: state1), call the function in main that updates the global counter. For the transition leading out of the monitored state, add the same action, but with a -1 as parameter.
Related
I am creating a model where I require agents from a population to be removed at a certain rate after a certain moment in time. This rate should be similar and have the same variability as a "Rate" in a source block. My current method runs, but I would like to know whether this method is accurate and if there exists a more elegant solution.
To begin the removal, I set up a Timeout Event that creates a Dynamic Event.
create_dynamicEvent(exponential(rate));
My dynamic event then removes the agent by sending it through an enter block to a sink block, and sets up another instance of itself.
enter_sink.take(population.get(0));
create_dynamicEvent(exponential(rate));
Thank you for your help
I would also use Dynamic Events. You may want to create the DE in the Source block, though, i.e. each created agent already "schedules" its destruction. May be more appropriate, but it depends on the real system.
Apart from that: all good
Utilizing a source generating agents on an Interarrival time basis, I would like to stop the source block from generating agents after a certain amount of time passing so that the model can continue to process the agents.
One option to encapsulate all the logic inside the source block, without external events or variables, would be to select Multiple agents per arrival as true and then have a conditional statement for the number of agents, for example time() > 10 ? 0 : 1, so that after 10 model time units there will no agents arriving
Sure. If it is a inter-arrival source block, make it use a variable as the interrarrival time, of type double:
Then, create an event that triggers once only, after your specific time. Make it change the variable to 0 as below. Make SURE to trigger it not at time 0 (as in the screen but when you need it!):
NOTE: Do not set myRate = 0;. Instead, set it to infinity` to actually have no more arrivals.
I'm working with code that uses a tumbling window of one day, and would like to send early results to a different DataStream on an hourly basis.
I understand that triggers are a way to go here, but don't really see how it would work.
The current code is as follows:
myStream
.keyBy(..)
.window(TumblingEventTimeWindows.of(Time.days(1)))
.aggregate(new MyAggregateFunction(), new MyProcessWindowFunction())
In my understanding, I should register a trigger, and then on its onEventTime method get a hold of a TriggerContext and I can send data to the labeled output from there. But how do I get the current state of MyAggregateFunction from there? Or would I need to my own computation here inside of onEventTime()?
Also, the documentation states that "By specifying a trigger using trigger() you are overwriting the default trigger of a WindowAssigner.". Would my one day window then still fire correctly, or do I need to trigger it somehow differently?
Another way of doing this is creating two different operators - one that windows by 1 hour, and another that windows by 1 day. Would triggers be a preferred approach to that?
Rather than using a custom Trigger, it would be simpler to have two layers of windowing, where the hourly results are further aggregated into daily results. Something like this:
hourlyResults = myStream
.keyBy(...)
.window(TumblingEventTimeWindows.of(Time.hours(1)))
.aggregate(new MyAggregateFunction(), new MyProcessWindowFunction())
dailyResults = hourlyResults
.keyBy(...)
.window(TumblingEventTimeWindows.of(Time.days(1)))
.aggregate(new MyAggregateFunction(), new MyProcessWindowFunction())
hourlyResults.addSink(...)
dailyResults.addSink(...)
Note that the result of a window is not a KeyedStream, so you will need to use keyBy again, unless you can arrange to leverage reinterpretAsKeyedStream (docs).
Normally when I get to more complex behavior like this, I use a KeyedProcessFunction. You can aggregate (and save in state) hourly and daily results, set timers as needed, and use a side output for the hourly results versus the regular output for the daily results.
There are quite a few questions here. I will try to ask all of them. First of all, if You specify Your own trigger using trigger() this means You are going to effectively override the default trigger and thus the window may not work the way it would by default. So, if You for example if You create the 1 day event time tumbling window, but override a trigger so that it fires for every 20th element, it will never fire based on event time.
Now, after Your custom trigger fires, the output from MyAggregateFunction will be passed to MyProcessWindowFunction, so It will work the same as for the default trigger, you don't need to access the MyAggregateFunction from inside the trigger.
Finally, while it may be technically possible to implement trigger to trigger partial results every hour, my personal opinion is that You should probably go with the two separate windows. While this solution may create a slightly larger overhead and may result in a larger state, it should be much clearer, easier to implement, and finally much more error resistant.
While sending events to the runtime if some condition applies I want to ignore all past events and start fresh (with the same runtime, pattern, listeners, etc.), and that could happen many times so i need a relatively fast way of doing that. Is there a function that deletes from the runtime all the events that were already sent (I couldn't find such function in the documentation)? (I know I could create a new runtime but that is very time consuming)
Yes the contexts; You define the start condition and end condition. When the end condition is reached the runtime throws away all state, doc link.
What would be the best way to incorporate changing tide times into an AnyLogic model? I would like to use the times to effectively block and unblock a port. I have looked at the schedule option and the format (Start: Day1, Time) doesn't seem the best way to do it.
You can model the tide by a reoccuring timed trigger.
AnyLogic offers the Dynamic Event for this, an event that can reschedule itself.
Depending on how you have the time data for the tides (list of DateTimes, fixed periods, database), you can retrieve that value for each new rescheduling of the dynamic event.
I attached a screenshot of a simple sample model. Here I assume you have got a list with the interval in minutes between each port-affecting tide moment (Low Tide/Port Blocked - High Tide/Port Open - Low Tide/Port Blocked - and so on....) . The dynamic event then sets a boolean variable portBlocked, but depending on your needs you could also trigger a Statechart Transition, block flowchart modules, or trigger a function.
The Action code of the Dynamic Event:
portBlocked=!portBlocked;
create_MyDynamicEvent(tideIntervalsInMinutes.get(tideCounter),MINUTE);
tideCounter++;
Explanation of the code:
Trigger your needed actions (here simple boolean variable)
Reschedule the event for the next tide change
Update the tide counter (used to retrieve the corresponding tide interval time from the list)
In the startup code of the model you will have to trigger the Dynamic Event once initially, for this just use the same code as point 2 above.