use of de.hpi.bpt.scylla.model.global.resource.TimetableItem in project scylla by bptlab.
the class DateTimeUtils method getTimeTableIndexWithinOrNext.
/**
* Determines the index of the timetable item in which the given datetime is located.
*
* @param dateTime
* the datetime in question
* @param timetable
* the timetable in question
* @return the index of the timetable item in which the given datetime is located
*/
public static int getTimeTableIndexWithinOrNext(ZonedDateTime dateTime, List<TimetableItem> timetable) {
int index = -1;
double minDurationToItemStart = Double.MAX_VALUE;
for (int i = 0; i < timetable.size(); i++) {
TimetableItem item = timetable.get(i);
if (isWithin(dateTime, item)) {
return i;
}
double durationUntilItemStart = getDurationInReferenceUnit(dateTime, item.getWeekdayFrom(), item.getBeginTime());
if (durationUntilItemStart < minDurationToItemStart) {
minDurationToItemStart = durationUntilItemStart;
index = i;
}
}
return index;
}
use of de.hpi.bpt.scylla.model.global.resource.TimetableItem in project scylla by bptlab.
the class DateTimeUtils method getTaskTerminationTime.
/**
* Calculates the relative end time of a task. Consideres timetables of resources instances. If any resource
* instance is idle, the duration is extended by the idle time.
*
* @param timeSpan
* the original duration of the task without any interruptions
* @param presentTime
* current simulation time
* @param tuple
* resource instances assigned to the task
* @param event
* source event (for logging purposes)
* @return the end time of the task
*/
public static TimeInstant getTaskTerminationTime(TimeSpan timeSpan, TimeInstant presentTime, ResourceObjectTuple tuple, ScyllaEvent event) {
SimulationModel model = (SimulationModel) event.getModel();
ProcessInstance processInstance = event.getProcessInstance();
ProcessModel processModel = processInstance.getProcessModel();
String source = event.getSource();
String taskName = event.getDisplayName();
int nodeId = event.getNodeId();
String processScopeNodeId = SimulationUtils.getProcessScopeNodeId(processModel, nodeId);
Set<String> resources = new HashSet<String>();
Set<ResourceObject> resourceObjects = tuple.getResourceObjects();
for (ResourceObject res : resourceObjects) {
String resourceName = res.getResourceType() + "_" + res.getId();
resources.add(resourceName);
}
// start
long duration = timeSpan.getTimeRounded(timeUnit);
if (duration == 0) {
return presentTime;
}
ZonedDateTime dateTime = DateTimeUtils.getDateTime(presentTime);
List<TimetableItem> timetable = tuple.getSharedTimetable();
if (timetable == null) {
return new TimeInstant(presentTime.getTimeRounded(timeUnit) + duration);
}
Integer index = null;
for (int i = 0; i < timetable.size(); i++) {
TimetableItem item = timetable.get(i);
if (isWithin(dateTime, item)) {
index = i;
break;
}
}
long timePassed = 0;
while (timePassed < duration) {
TimetableItem item = timetable.get(index);
DayOfWeek untilWeekday = item.getWeekdayTo();
LocalTime untilTime = item.getEndTime();
ZonedDateTime dateTimeUntilEnd = getNextOrSameZonedDateTime(dateTime, untilWeekday, untilTime);
long durationUntilEnd = chronoUnit.between(dateTime, dateTimeUntilEnd);
long amountToAdd;
if (timePassed + durationUntilEnd >= duration) {
// task completes in current timetable item
amountToAdd = duration - timePassed;
} else {
// until end of timetable item
amountToAdd = durationUntilEnd;
}
timePassed += amountToAdd;
dateTime = dateTime.plus(amountToAdd, chronoUnit);
if (timePassed + durationUntilEnd < duration) {
// task is not completed in current timetable item, so jump to the start of the next timetable item
if (model.isOutputLoggingOn()) {
// log idle during use
ResourceStatus status = ResourceStatus.IN_USE_IDLE;
long timeRelativeToStart = getTimeInstant(dateTime).getTimeRounded(timeUnit);
ResourceInfo info = new ResourceInfo(timeRelativeToStart, status, processInstance, nodeId);
for (ResourceObject obj : tuple.getResourceObjects()) {
String resourceType = obj.getResourceType();
String resourceId = obj.getId();
model.addResourceInfo(resourceType, resourceId, info);
}
ProcessNodeTransitionType transition = ProcessNodeTransitionType.PAUSE;
ProcessNodeInfo nodeInfo = new ProcessNodeInfo(nodeId, processScopeNodeId, source, timeRelativeToStart, taskName, resources, transition);
model.addNodeInfo(processModel, processInstance, nodeInfo);
}
index++;
if (index == timetable.size()) {
index = 0;
}
TimetableItem nextItem = timetable.get(index);
untilWeekday = nextItem.getWeekdayFrom();
untilTime = nextItem.getBeginTime();
dateTime = getNextZonedDateTime(dateTime, untilWeekday, untilTime);
if (model.isOutputLoggingOn()) {
// log back to work
ResourceStatus status = ResourceStatus.IN_USE;
long timeRelativeToStart = getTimeInstant(dateTime).getTimeRounded(timeUnit);
ResourceInfo info = new ResourceInfo(timeRelativeToStart, status, processInstance, nodeId);
for (ResourceObject obj : tuple.getResourceObjects()) {
String resourceType = obj.getResourceType();
String resourceId = obj.getId();
model.addResourceInfo(resourceType, resourceId, info);
}
ProcessNodeTransitionType transition = ProcessNodeTransitionType.RESUME;
ProcessNodeInfo nodeInfo = new ProcessNodeInfo(nodeId, processScopeNodeId, source, timeRelativeToStart, taskName, resources, transition);
model.addNodeInfo(processModel, processInstance, nodeInfo);
}
}
}
TimeInstant timeInstant = getTimeInstant(dateTime);
return timeInstant;
}
use of de.hpi.bpt.scylla.model.global.resource.TimetableItem in project scylla by bptlab.
the class SimulationUtils method scheduleNextResourceAvailableEvent.
/**
* Creates and schedules a DesmoJ event which represents a resource instance which returns from idle.
*
* @param model
* the simulation model
* @param resourceObject
* the resource instance returning from idle
* @param currentDateTime
* the current date time
* @param currentlyInTimetableItem
* true if the resource instance is currently active
*/
public static void scheduleNextResourceAvailableEvent(SimulationModel model, ResourceObject resourceObject, ZonedDateTime currentDateTime, boolean currentlyInTimetableItem) {
boolean showInTrace = model.traceIsOn();
TimeUnit timeUnit = DateTimeUtils.getReferenceTimeUnit();
long currentTime = DateTimeUtils.getTimeInstant(currentDateTime).getTimeRounded(timeUnit);
List<TimetableItem> timetable = resourceObject.getTimetable();
if (timetable == null) {
return;
}
int index = DateTimeUtils.getTimeTableIndexWithinOrNext(currentDateTime, timetable);
if (currentlyInTimetableItem) {
index++;
if (index == timetable.size()) {
index = 0;
}
}
TimetableItem nextTimetableItem = timetable.get(index);
DayOfWeek weekday = nextTimetableItem.getWeekdayFrom();
LocalTime time = nextTimetableItem.getBeginTime();
ZonedDateTime nextDateTime = DateTimeUtils.getNextZonedDateTime(currentDateTime, weekday, time);
long durationToNextResourceAvailableEvent = DateTimeUtils.getDuration(currentDateTime, nextDateTime);
if (model.getEndDateTime() != null) {
long endTimeRelativeToGlobalStart = DateTimeUtils.getDuration(model.getStartDateTime(), model.getEndDateTime());
if (currentTime + durationToNextResourceAvailableEvent >= endTimeRelativeToGlobalStart) {
return;
}
}
ResourceAvailabilityEvent event = new ResourceAvailabilityEvent(model, resourceObject, showInTrace);
event.schedule(new TimeSpan(durationToNextResourceAvailableEvent, timeUnit));
}
use of de.hpi.bpt.scylla.model.global.resource.TimetableItem in project scylla by bptlab.
the class GlobalConfigurationParser method parse.
@Override
public GlobalConfiguration parse(Element rootElement) throws ScyllaValidationException {
System.out.println(rootElement.getNamespace());
Iterator<EventOrderType> eventOrderTypesIterator = PluginLoader.dGetPlugins(EventOrderType.class);
// ServiceLoader.load(EventOrderType.class).iterator();
// Get all event order type plugins and store them in eventOrderTypes
Map<String, EventOrderType> eventOrderTypes = new HashMap<String, EventOrderType>();
while (eventOrderTypesIterator.hasNext()) {
EventOrderType eot = eventOrderTypesIterator.next();
eventOrderTypes.put(eot.getName(), eot);
}
Namespace bsimNamespace = rootElement.getNamespace();
List<Element> globalConfigurationElements = rootElement.getChildren(null, bsimNamespace);
String globalConfId = rootElement.getAttributeValue("id");
Long randomSeed = null;
ZoneId zoneId = ZoneId.of("UTC");
Map<String, Resource> resources = new HashMap<String, Resource>();
List<EventOrderType> resourceAssignmentOrder = new ArrayList<EventOrderType>();
// resourceId:[instanceName:timetableId]
Map<String, Map<String, String>> resourcesToTimetableIds = new HashMap<String, Map<String, String>>();
Map<String, List<TimetableItem>> timetables = new HashMap<String, List<TimetableItem>>();
for (Element el : globalConfigurationElements) {
String elementName = el.getName();
if (isKnownElement(elementName)) {
if (el.getText().isEmpty()) {
continue;
}
if (elementName.equals("resourceAssignmentOrder")) {
String resourceAssignmentOrderString = el.getText();
String[] orderTypeArray = resourceAssignmentOrderString.split(",");
for (String orderTypeName : orderTypeArray) {
if (orderTypeName.isEmpty()) {
continue;
}
EventOrderType eventOrderType = eventOrderTypes.get(orderTypeName);
if (eventOrderType == null) {
throw new ScyllaValidationException("Event order type " + orderTypeName + " for resource assignment is unknown.");
}
resourceAssignmentOrder.add(eventOrderType);
}
} else if (elementName.equals("randomSeed")) {
randomSeed = Long.parseLong(el.getText());
} else if (elementName.equals("zoneOffset")) {
zoneId = ZoneId.of("GMT" + el.getText());
} else if (elementName.equals("resourceData")) {
List<Element> rDataElements = el.getChildren();
for (Element elem : rDataElements) {
String resourceId = elem.getAttributeValue("id");
String rDataElementName = elem.getName();
if (rDataElementName.equals("dynamicResource")) {
String resourceName = elem.getAttributeValue("name");
Integer defaultQuantity = Integer.valueOf(elem.getAttributeValue("defaultQuantity"));
Double defaultCost = Double.valueOf(elem.getAttributeValue("defaultCost"));
TimeUnit defaultTimeUnit = TimeUnit.valueOf(elem.getAttributeValue("defaultTimeUnit"));
DynamicResource dynamicResource = new DynamicResource(resourceId, resourceName, defaultQuantity, defaultCost, defaultTimeUnit);
String defaultTimetableId = elem.getAttributeValue("defaultTimetableId");
if (resourcesToTimetableIds.containsKey(resourceId)) {
throw new ScyllaValidationException("Multiple resource definitions: " + resourceId);
}
resourcesToTimetableIds.put(resourceId, new HashMap<String, String>());
Map<String, DynamicResourceInstance> resourceInstances = dynamicResource.getResourceInstances();
List<Element> instanceElements = elem.getChildren("instance", bsimNamespace);
// fill up list of resource instances if not explicitly defined
if (instanceElements.size() > defaultQuantity) {
throw new ScyllaValidationException("Too many instances defined for resource " + resourceId);
}
int numberOfDefaultInstances = defaultQuantity - instanceElements.size();
for (int i = 0; i < numberOfDefaultInstances; i++) {
String name = "#" + i;
DynamicResourceInstance instance = new DynamicResourceInstance(defaultCost, defaultTimeUnit);
resourceInstances.put(name, instance);
if (defaultTimetableId != null) {
resourcesToTimetableIds.get(resourceId).put(name, defaultTimetableId);
}
}
// parse defined resource instances
for (Element element : instanceElements) {
String name = element.getAttributeValue("name");
if (name == null) {
throw new ScyllaValidationException("Resource instance of type " + resourceId + " does not have name.");
}
Double cost;
if (element.getAttributeValue("cost") == null) {
cost = defaultCost;
} else {
cost = Double.valueOf(element.getAttributeValue("cost"));
}
TimeUnit timeUnit;
if (element.getAttributeValue("timeUnit") == null) {
timeUnit = defaultTimeUnit;
} else {
timeUnit = TimeUnit.valueOf(element.getAttributeValue("timeUnit"));
}
DynamicResourceInstance instance = new DynamicResourceInstance(cost, timeUnit);
if (resourceInstances.containsKey(name)) {
throw new ScyllaValidationException("Duplicate resource instance: " + name);
}
resourceInstances.put(name, instance);
String timetableId = element.getAttributeValue("timetableId");
if (timetableId != null) {
resourcesToTimetableIds.get(resourceId).put(name, timetableId);
}
}
resources.put(resourceId, dynamicResource);
} else {
DebugLogger.log("Element " + elem.getName() + " of resource data is expected to be known, but not supported.");
}
}
} else if (elementName.equals("timetables")) {
List<Element> tElements = el.getChildren("timetable", bsimNamespace);
for (Element tElement : tElements) {
String timetableId = tElement.getAttributeValue("id");
List<TimetableItem> items = new ArrayList<TimetableItem>();
List<Element> tItemElements = tElement.getChildren("timetableItem", bsimNamespace);
for (Element tItemElement : tItemElements) {
DayOfWeek weekdayFrom = DayOfWeek.valueOf(tItemElement.getAttributeValue("from"));
DayOfWeek weekdayTo = DayOfWeek.valueOf(tItemElement.getAttributeValue("to"));
LocalTime beginTime = LocalTime.parse(tItemElement.getAttributeValue("beginTime"));
LocalTime endTime = LocalTime.parse(tItemElement.getAttributeValue("endTime"));
// TODO check for overlapping timetable items and handle them
if (DateTimeUtils.compareWeekdayTime(weekdayFrom, beginTime, weekdayTo, endTime) != 0) {
if (weekdayFrom.compareTo(weekdayTo) > 0) {
// e.g. FRIDAY to MONDAY
TimetableItem item = new TimetableItem(weekdayFrom, DayOfWeek.SUNDAY, beginTime, LocalTime.MAX);
items.add(item);
item = new TimetableItem(DayOfWeek.MONDAY, weekdayTo, LocalTime.MIN, endTime);
items.add(item);
} else {
TimetableItem item = new TimetableItem(weekdayFrom, weekdayTo, beginTime, endTime);
items.add(item);
}
}
}
timetables.put(timetableId, items);
}
}
} else {
DebugLogger.log("Element " + el.getName() + " of global configuration is not supported.");
}
}
// match timetables (if any available) and resource data (if any available)s
for (String resourceId : resourcesToTimetableIds.keySet()) {
Map<String, String> resourceInstanceIdToTimetableIds = resourcesToTimetableIds.get(resourceId);
for (String resourceInstanceName : resourceInstanceIdToTimetableIds.keySet()) {
String timetableId = resourceInstanceIdToTimetableIds.get(resourceInstanceName);
if (!timetables.containsKey(timetableId)) {
DebugLogger.log("Timetable " + timetableId + " not found.");
}
List<TimetableItem> timetable = timetables.get(timetableId);
Resource resource = resources.get(resourceId);
if (resource instanceof DynamicResource) {
DynamicResource dResource = (DynamicResource) resource;
dResource.getResourceInstances().get(resourceInstanceName).setTimetable(timetable);
}
}
}
if (resources.isEmpty()) {
throw new ScyllaValidationException("No resource data definitions in file.");
}
if (randomSeed == null) {
Random random = new Random();
randomSeed = random.nextLong();
}
DebugLogger.log("Random seed for whole simulation (if not overriden by simulation configuration): " + randomSeed);
GlobalConfiguration globalConfiguration = new GlobalConfiguration(globalConfId, zoneId, randomSeed, resources, resourceAssignmentOrder);
return globalConfiguration;
}
Aggregations