I'm trying to build a model in Anylogic that would optimize the start and end time of my resource pool to meet demand. Is there a way to have the start time and end time for the schedule to be parameters to input in the optimization model. I currently have my shifts as 8-5 and meeting demand in 30 days, but the optimization model might say that 6-6 (us working overtime) would meet demand in 15 days. The start and end time would have min and max values.
This is unfortunately not straightforward.
When you create Schedule objects visually, you have to 'hardcode' start and end times. Thus, for them to be variable (driven from model parameters) you have to programmatically create a Schedule, and ensure the Resource Pool capacity is driven by it.
If you see AnyLogic Help > Functions, Table Functions and Schedules > Schedules > Schedule API in the help, that explains the programmatic interface (API) to create schedules and includes an example model. However
That example dynamically sets up a Source block arrival schedule from the dynamically-created schedule. You can't do that for a Resource Pool. (Dynamically changing the capacity definition is not allowed.) So you need to set up some AnyLogic events to change the Resource Pool capacity from the schedule. (You can change a resource pool's capacity dynamically whenever you like.) In fact, this is what the Resource Pool block is doing internally when you setup a capacity schedule visually for it...
That example is for a Rate schedule, doesn't document any of the code, and there are some errors/lack of proper explanation in the help. (In particular, setPeriod
takes the period in the time units you specified in setTimeUnit
, not in milliseconds.)
Let's say your shifts are Mon-Fri and you want to vary the start/end hour (and, for good measure, the shift size). So we add (type int
) model parameters for those, and a Resource Pool called workers
.
We are using an integer Schedule to define the resource pool capacity, so we define a variable (type Schedule<Integer>
) to hold that (initially null
). We also define a Dynamic Event ShiftChange
: we are going to launch a 'chain' of these, where each one fires at the next schedule change time and changes the Resource Pool capacity accordingly (with an animated clock from the Pictures palette to help us see what's happening more clearly; you could also use the time shown in the Developer Panel).
The dynamic event needs to have a single argument shiftSize
(type int
): it needs to know the shift size that it needs to change the resource pool's capacity to.
So Main
looks like this:
In the on-startup action of Main
we set up the dynamic schedule and the first instance of the dynamic event:
dynamicSchedule = new Schedule<Integer>();
dynamicSchedule.setOwner(this);
dynamicSchedule.setCalendarType(true);
dynamicSchedule.setFirstDayOfWeek(MONDAY);
dynamicSchedule.setTimeUnits(TIME_UNIT_WEEK);
dynamicSchedule.setPeriod(1); // Repeats every 1 time unit (week)
dynamicSchedule.setGlueIntervals(true);
dynamicSchedule.setDefaultValue(0); // Default schedule value (0)
// Add intervals for Mon-Fri (day 1-5) from the given start to the end hour with the given shift size
for (int i = 1; i <=5; i++) {
dynamicSchedule.addInterval(1, // startWeek
i, // startDayOfWeek,
startHour, //startHour
0, // startMinute
0, // startSecond
1, // endWeek
i, // endDayOfWeek
endHour, //endHour
0, // endMinute
0, // endSecond
shiftSize); //value
}
dynamicSchedule.initialize(); // Needed to 'take' the changes
// Can't do the below: can't change a ResourcePool's capacity definition dynamically
//workers.set_capacityDefinitionType(CapacityDefinitionType.CAPACITY_SCHEDULE);
//workers.set_capacitySchedule(dynamicSchedule);
// Instead we create a chain of dynamic events to change the Resource Pool capacity as per the schedule
create_ShiftChange(dynamicSchedule.getTimeoutToNextValue(), dynamicSchedule.getNextValue());
(See this help topic for Dynamic Event details: AnyLogic Help > Defining Behavior. Events and Statecharts > Events > Dynamic Event. I also include commented-out code which doesn't work for attempting to dynamically set up the capacity schedule in the Resource Pool.)
The Dynamic Event action code looks like this (together with a nice console message to help us check it's working properly):
traceln(format(date()) + ": changing shift size to " + shiftSize);
workers.set_capacity(shiftSize); // Dynamically change the resource pool's capacity
// Set up the next dynamic event in the chain
create_ShiftChange(dynamicSchedule.getTimeoutToNextValue(), dynamicSchedule.getNextValue());
In my case, I used defaults of start hour 1, end hour 3 and shift-size 5. If I start the model on a Monday date I get the following output (and you can see the resource pool capacity changing....):
Nov 25, 2019, 1:00:00 AM: changing shift size to 5
Nov 25, 2019, 3:00:00 AM: changing shift size to 0
Nov 26, 2019, 1:00:00 AM: changing shift size to 5
Nov 26, 2019, 3:00:00 AM: changing shift size to 0
Nov 27, 2019, 1:00:00 AM: changing shift size to 5
Nov 27, 2019, 3:00:00 AM: changing shift size to 0
Nov 28, 2019, 1:00:00 AM: changing shift size to 5
Nov 28, 2019, 3:00:00 AM: changing shift size to 0
Nov 29, 2019, 1:00:00 AM: changing shift size to 5
Nov 29, 2019, 3:00:00 AM: changing shift size to 0
Dec 2, 2019, 1:00:00 AM: changing shift size to 5
Dec 2, 2019, 3:00:00 AM: changing shift size to 0
[...]
Now your optimisation can vary the start/end time and shift-size as it desires (via the integer model parameters), setting max/min values as you desire.