// In the following, we first try to resolve the signal types of
// the ports of the rest actors including nonCTSubsystems
// by propagating known signal types.
// First make sure that there is no causality loop of arithmetic
// actors. This makes the graph reachability algorithms terminate.
DirectedAcyclicGraph arithmeticGraph = _toGraph(arithmeticActors);
if (!arithmeticGraph.isAcyclic()) {
Object[] cycleNodes = arithmeticGraph.cycleNodes();
LinkedList nodesAsList = new LinkedList();
StringBuffer inCycle = new StringBuffer("Cycle includes: ");
for (int i = 0; i < cycleNodes.length; i++) {
inCycle.append(((NamedObj) cycleNodes[i]).getFullName());
if (i < cycleNodes.length - 1) {
inCycle.append(", ");
}
nodesAsList.add(cycleNodes[i]);
}
throw new NotSchedulableException(nodesAsList, null,
"Algebraic loop. " + inCycle.toString());
}
// We do not allow loops of dynamic actors, either.
DirectedAcyclicGraph dynamicGraph = _toGraph(dynamicActors);
// FIXME: Why is this disallowed? If we change this, change the class
// comment (at the end) also.
if (!dynamicGraph.isAcyclic()) {
throw new NotSchedulableException(
"Loops of dynamic actors (e.g. integrators) "
+ "are not allowed in the CT domain. You may insert a "
+ "Scale actor with factor 1.");
}
// Now we propagate the signal types by topological sort.
// Notice that signal types of the output ports of the dynamic actors,
// source actors, waveform generators, event generators, and sequence
// actors have already been propagated by one step.
// So, we start with arithmetic actors.
Object[] sortedArithmeticActors = arithmeticGraph.topologicalSort();
for (int i = 0; i < sortedArithmeticActors.length; i++) {
Actor actor = (Actor) sortedArithmeticActors[i];
// Note that the signal type of the input ports should be set
// already. If all input ports are CONTINUOUS, and the
// output ports are UNKNOWN, then all output ports should be
// CONTINUOUS. If all input ports are DISCRETE, and the
// output ports are UNKNOWN, then all output ports should be
// DISCRETE. If some input ports are continuous and some
// input ports are discrete, then the output port type must
// be set manually, which means they can not been resolved.
Iterator inputPorts = actor.inputPortList().iterator();
CTReceiver.SignalType knownInputType = UNKNOWN;
boolean needManuallySetType = true;
while (inputPorts.hasNext()) {
IOPort inputPort = (IOPort) inputPorts.next();
if (inputPort.getWidth() != 0) {
CTReceiver.SignalType inputType = _signalTypeMap
.getType(inputPort);
if (inputType == UNKNOWN) {
throw new NotSchedulableException("Cannot resolve "
+ "signal type for port "
+ inputPort.getFullName()
+ ". If you are certain about the signal type"
+ ", you can set them manually.\n"
+ " To do this, you can add a parameter "
+ "called \'signalType\' with value "
+ "\'\"CONTINUOUS\"\' or \'\"DISCRETE\"\'"
+ " to a port.");
} else if (knownInputType == UNKNOWN) {
knownInputType = inputType;
needManuallySetType = false;
} else if (knownInputType != inputType) {
needManuallySetType = true;
break;
}
}
}
Iterator outputPorts = actor.outputPortList().iterator();
while (outputPorts.hasNext()) {
IOPort outputPort = (IOPort) outputPorts.next();
if (outputPort.getWidth() != 0) {
CTReceiver.SignalType outputType = _signalTypeMap
.getType(outputPort);
if (outputType == UNKNOWN) {
if (needManuallySetType) {
throw new NotSchedulableException(
"Cannot resolve "
+ "signal type for port "
+ outputPort.getFullName()
+ ".\n To set the signal type manually, "
+ "add a parameter with name \'signalType\'"
+ " and a string value \'\"CONTINUOUS\"\' "
+ "or \'\"DISCRETE\"\'.");
} else {
_signalTypeMap.setType(outputPort, knownInputType);
}
}
_signalTypeMap.propagateType(outputPort);
}
}
}
// Set the "signalType" parameters in the model
// to display the signal types.
_setPortSignalTypes(_signalTypeMap);
// Output the signal type resolution result to the debugger.
if (_debugging) {
_debug("Resolved signal types: {\n" + _signalTypeMap.toString()
+ "}");
}
// Now the signal types of all ports are resolved and stored in the
// SignalTypes table. We classify continuous and discrete actors.
// NOTE: An actor is continuous if it has continuous ports;
// an actor is discrete if it has discrete ports. Under this
// rule, the set of continuous actors and discrete actors may have
// a non-empty intersection set.
discreteActors = _signalTypeMap.getDiscreteActors();
continuousActors = _signalTypeMap.getContinuousActors();
// NOTE: There is a situation that the signal types of all the input
// and output ports of a CT composite actor are derived as "DISCRETE".
// In such case, we still need to include this actor into the set of
// continuous actors, because there may be some continuous actors
// hidden inside that CT composite actor.
// To avoid introducing duplication:
continuousActors.removeAll(ctSubsystems);
continuousActors.addAll(ctSubsystems);
// NOTE: There is a situation that the signal types of all the input
// and output ports of a CT composite actor are derived as "CONTINUOUS".
// In such case, we still need to include this actor into the set of
// discrete actors, because there may be some discrete actors
// hidden inside that CT composite actor.
// To avoid introducing duplication:
discreteActors.removeAll(ctSubsystems);
discreteActors.addAll(ctSubsystems);
// FIXME: the following statement does not make sense.
// At this point, since the ports of all actors have their signal types
// resolved, a nonCTSubsystem will be clarified based on
// the signal types of its input and output ports.
Iterator subsystems = nonCTSubsystems.iterator();
while (subsystems.hasNext()) {
CompositeActor subsystem = (CompositeActor) subsystems.next();
if (discreteActors.contains(subsystem)
&& continuousActors.contains(subsystem)) {
// NOTE:
// For a non-CT composite actor, it can not be a
// waveform generator or an event generator.
// Because the transformation of different type of signals
// can only be made in CT models.
waveformGenerators.add(subsystem);
// remove the current subsystem from both the continuous
// and discrete actor clusters.
discreteActors.remove(subsystem);
continuousActors.remove(subsystem);
}
}
// Now, all actors are classified.
// Notice that by now, we have all the discrete actors, but
// they are not in the topological order. Sort them and
// create the discrete schedule.
DirectedAcyclicGraph discreteGraph = _toGraph(discreteActors);
Object[] discreteSorted = discreteGraph.topologicalSort();
for (int i = 0; i < discreteSorted.length; i++) {
Actor actor = (Actor) discreteSorted[i];
// We want to distinguish the waveform and event generators,
// which have at least one input or output declared as CONTINUOUS
// signal type, from purely discrete (continuous) actors, whose
// ports are all DISCRETE (CONTINUOUS).
if (continuousActors.contains(actor)) {
if (actor instanceof CTCompositeActor) {
// We add CT composite actors into the list of discrete
// actors because a CTComposite actor can be anything.
discreteActorSchedule.add(new Firing(actor));
} else {
// the following code removes event generators
// and waveform generators from the list of purely
// continuous actors.
// NOTE: we only remove actors that are declared to be
// event generators or waveform generators. Some actors,
// such as TriggeredContinuousClock actor, are still treated
// as purely continuous actors even though they have
// discrete inputs, because they produce continuous signals.
// TESTIT: Clock3, Clock5, and Clock6 in ct/lib/test/auto.
if ((actor instanceof CTEventGenerator)
|| (actor instanceof CTWaveformGenerator)) {
continuousActors.remove(actor);
}
}
continue;
}
// We add purely discrete actors (discrete -> discrete) into list.
discreteActorSchedule.add(new Firing(actor));
}
// Create the schedule for waveform generators.
Iterator generators = waveformGenerators.iterator();
while (generators.hasNext()) {
Actor generator = (Actor) generators.next();
waveformGeneratorSchedule.add(new Firing(generator));
}
// Schedule event generators so that they are executed topologically.
// Treat them as sink actors from the point of view of a
// continuous phase of execution.
if (!eventGenerators.isEmpty()) {
DirectedAcyclicGraph eventGraph = _toGraph(eventGenerators);
Object[] eventSorted = eventGraph.topologicalSort();
for (int i = 0; i < eventSorted.length; i++) {
Actor actor = (Actor) eventSorted[i];
// If this actor is both an event generator and