DevsSimulator.java
package nl.tudelft.simulation.dsol.simulators;
import java.io.Serializable;
import org.djutils.exceptions.Throw;
import nl.tudelft.simulation.dsol.SimRuntimeException;
import nl.tudelft.simulation.dsol.eventlists.EventListInterface;
import nl.tudelft.simulation.dsol.eventlists.RedBlackTree;
import nl.tudelft.simulation.dsol.experiment.Replication;
import nl.tudelft.simulation.dsol.formalisms.eventscheduling.Executable;
import nl.tudelft.simulation.dsol.formalisms.eventscheduling.LambdaSimEvent;
import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEvent;
import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEventInterface;
import nl.tudelft.simulation.dsol.model.DsolModel;
import nl.tudelft.simulation.dsol.simtime.SimTime;
/**
* The DEVS defines the interface of the DEVS simulator. DEVS stands for the Discrete Event System Specification. More
* information on Discrete Event Simulation can be found in "Theory of Modeling and Simulation" by Bernard Zeigler et.al.
* <p>
* Copyright (c) 2002-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://simulation.tudelft.nl/" target="_blank"> https://simulation.tudelft.nl</a>. The DSOL
* project is distributed under a three-clause BSD-style license, which can be found at
* <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">
* https://https://simulation.tudelft.nl/dsol/docs/latest/license.html</a>.
* </p>
* @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs </a>
* @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @param <T> the simulation time type based on the absolute and relative time.
* @since 1.5
*/
public class DevsSimulator<T extends Number & Comparable<T>> extends Simulator<T> implements DevsSimulatorInterface<T>
{
/** */
private static final long serialVersionUID = 20140804L;
/** eventList represents the future event list. */
@SuppressWarnings("checkstyle:visibilitymodifier")
protected EventListInterface<T> eventList = new RedBlackTree<T>();
/**
* Constructs a new DevsSimulator.
* @param id the id of the simulator, used in logging and firing of events.
*/
public DevsSimulator(final Serializable id)
{
super(id);
}
/** {@inheritDoc} */
@Override
public boolean cancelEvent(final SimEventInterface<T> event)
{
return this.eventList.remove(event);
}
/** {@inheritDoc} */
@Override
public EventListInterface<T> getEventList()
{
return this.eventList;
}
/** {@inheritDoc} */
@Override
@SuppressWarnings({"hiding", "checkstyle:hiddenfield"})
public void initialize(final DsolModel<T, ? extends SimulatorInterface<T>> model, final Replication<T> replication)
throws SimRuntimeException
{
// this check HAS to be done BEFORE clearing the event list
Throw.when(isStartingOrRunning(), SimRuntimeException.class, "Cannot initialize a running simulator");
synchronized (super.semaphore)
{
this.eventList.clear();
super.initialize(model, replication);
this.scheduleEvent(new SimEvent<T>(this.getReplication().getWarmupTime(),
(short) (SimEventInterface.MAX_PRIORITY + 1), this, "warmup", null));
this.scheduleEvent(new SimEvent<T>(this.getReplication().getEndTime(),
(short) (SimEventInterface.MIN_PRIORITY - 1), this, "endReplication", null));
}
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEvent(final SimEventInterface<T> event) throws SimRuntimeException
{
synchronized (super.semaphore)
{
if (event.getAbsoluteExecutionTime().compareTo(super.simulatorTime) < 0)
{
throw new SimRuntimeException("cannot schedule event " + event.toString() + " in past " + this.simulatorTime
+ ">" + event.getAbsoluteExecutionTime());
}
this.eventList.add(event);
return event;
}
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventRel(final T relativeDelay, final short priority, final Object target,
final String method, final Object[] args) throws SimRuntimeException
{
synchronized (super.semaphore)
{
T absEventTime = SimTime.plus(this.simulatorTime, relativeDelay);
return scheduleEvent(new SimEvent<T>(absEventTime, priority, target, method, args));
}
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventRel(final T relativeDelay, final Object target, final String method,
final Object[] args) throws SimRuntimeException
{
return scheduleEventRel(relativeDelay, SimEventInterface.NORMAL_PRIORITY, target, method, args);
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventAbs(final T absoluteTime, final short priority, final Object target,
final String method, final Object[] args) throws SimRuntimeException
{
synchronized (super.semaphore)
{
return scheduleEvent(new SimEvent<T>(absoluteTime, priority, target, method, args));
}
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventAbs(final T absoluteTime, final Object target, final String method,
final Object[] args) throws SimRuntimeException
{
return scheduleEventAbs(absoluteTime, SimEventInterface.NORMAL_PRIORITY, target, method, args);
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventNow(final short priority, final Object target, final String method,
final Object[] args) throws SimRuntimeException
{
synchronized (super.semaphore)
{
T absEventTime = SimTime.copy(this.simulatorTime);
return scheduleEvent(new SimEvent<T>(absEventTime, priority, target, method, args));
}
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventNow(final Object target, final String method, final Object[] args)
throws SimRuntimeException
{
return scheduleEventNow(SimEventInterface.NORMAL_PRIORITY, target, method, args);
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventRel(final T relativeDelay, final short priority, final Executable executable)
throws SimRuntimeException
{
synchronized (super.semaphore)
{
T absEventTime = SimTime.plus(this.simulatorTime, relativeDelay);
return scheduleEvent(new LambdaSimEvent<T>(absEventTime, priority, executable));
}
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventRel(final T relativeDelay, final Executable executable) throws SimRuntimeException
{
return scheduleEventRel(relativeDelay, SimEventInterface.NORMAL_PRIORITY, executable);
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventAbs(final T absoluteTime, final short priority, final Executable executable)
throws SimRuntimeException
{
synchronized (super.semaphore)
{
return scheduleEvent(new LambdaSimEvent<T>(absoluteTime, priority, executable));
}
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventAbs(final T absoluteTime, final Executable executable) throws SimRuntimeException
{
return scheduleEventAbs(absoluteTime, SimEventInterface.NORMAL_PRIORITY, executable);
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventNow(final short priority, final Executable executable) throws SimRuntimeException
{
synchronized (super.semaphore)
{
T absEventTime = SimTime.copy(this.simulatorTime);
return scheduleEvent(new LambdaSimEvent<T>(absEventTime, priority, executable));
}
}
/** {@inheritDoc} */
@Override
public SimEventInterface<T> scheduleEventNow(final Executable executable) throws SimRuntimeException
{
return scheduleEventNow(SimEventInterface.NORMAL_PRIORITY, executable);
}
/** {@inheritDoc} */
@Override
public synchronized void setEventList(final EventListInterface<T> eventList)
{
this.eventList = eventList;
this.fireEvent(EVENTLIST_CHANGED_EVENT);
}
/** {@inheritDoc} */
@Override
protected void stepImpl()
{
synchronized (super.semaphore)
{
if (!this.eventList.isEmpty())
{
SimEventInterface<T> event = this.eventList.removeFirst();
fireUnverifiedTimedEvent(SimulatorInterface.TIME_CHANGED_EVENT, null, event.getAbsoluteExecutionTime());
super.simulatorTime = event.getAbsoluteExecutionTime();
event.execute();
}
}
}
/** {@inheritDoc} */
@Override
public void run()
{
// set the run flag semaphore to signal to startImpl() that the run method has started
this.runflag = true;
while (!isStoppingOrStopped())
{
synchronized (super.semaphore)
{
int cmp = this.eventList.isEmpty() ? 2
: this.eventList.first().getAbsoluteExecutionTime().compareTo(this.runUntilTime);
if ((cmp == 0 && !this.runUntilIncluding) || cmp > 0)
{
this.simulatorTime = SimTime.copy(this.runUntilTime);
this.runState = RunState.STOPPING;
break;
}
SimEventInterface<T> event = this.eventList.removeFirst();
if (event.getAbsoluteExecutionTime().compareTo(super.simulatorTime) != 0)
{
fireUnverifiedTimedEvent(SimulatorInterface.TIME_CHANGED_EVENT, null, event.getAbsoluteExecutionTime());
}
super.simulatorTime = event.getAbsoluteExecutionTime();
try
{
event.execute();
}
catch (Exception exception)
{
handleSimulationException(exception);
}
}
}
}
/** {@inheritDoc} */
@Override
public void endReplication()
{
super.endReplication();
this.eventList.clear();
}
/** {@inheritDoc} */
@Override
@Deprecated
public boolean isPauseOnError()
{
return getErrorStrategy().equals(ErrorStrategy.WARN_AND_PAUSE);
}
/** {@inheritDoc} */
@Override
@Deprecated
public void setPauseOnError(final boolean pauseOnError)
{
setErrorStrategy(pauseOnError ? ErrorStrategy.WARN_AND_PAUSE : ErrorStrategy.LOG_AND_CONTINUE);
}
}