// Now resolve signal types to find the continuous and
// discrete clusters of actors.
if (a instanceof SequenceActor) {
// Set all ports of a sequence actor with signal type "DISCRETE"
if (predecessorList(a).isEmpty()) {
throw new NotSchedulableException(((Nameable) a).getName()
+ " is a SequenceActor, which cannot be a"
+ " source actor in the CT domain.");
}
Iterator ports = ((Entity) a).portList().iterator();
while (ports.hasNext()) {
IOPort port = (IOPort) ports.next();
_signalTypeMap.setType(port, DISCRETE);
if (port.isOutput()) {
_signalTypeMap.propagateType(port);
}
}
} else if ((a instanceof CompositeActor)
&& !(a instanceof CTCompositeActor)) {
// This actor is an opaque composite actor but not a
// CT Composite actor.
// NOTE: For its output ports, we can tell the signal type
// from their receiver types. However, the signal types of
// its input ports have to be derived from the output ports
// of some other actors that reside at the same hierarchical
// level. So we only handle output ports here.
Iterator ports = ((Entity) a).portList().iterator();
while (ports.hasNext()) {
IOPort port = (IOPort) ports.next();
if (port.isOutput()) {
Receiver[][] insideReceivers = port
.getInsideReceivers();
// NOTE: The assumption is that all the receivers
// belonging to the same IO port have the same
// signal type, so if there is at least one
// receiver, then use its type. If there are no
// receivers, assume the type is continuous.
if (insideReceivers.length > 0
&& insideReceivers[0] != null
&& insideReceivers[0].length > 0) {
Receiver insideReceiver = insideReceivers[0][0];
if (insideReceiver instanceof StateReceiver) {
_signalTypeMap.setType(port, CONTINUOUS);
} else {
_signalTypeMap.setType(port, DISCRETE);
}
} else {
_signalTypeMap.setType(port, CONTINUOUS);
}
_signalTypeMap.propagateType(port);
}
}
} else {
// The signal types of the rest ports are obtained
// from the "signalType" parameter.
Iterator ports = ((Entity) a).portList().iterator();
while (ports.hasNext()) {
IOPort port = (IOPort) ports.next();
Parameter signalType = (Parameter) port
.getAttribute("signalType");
if (signalType != null) {
String type = ((StringToken) signalType.getToken())
.stringValue();
type = type.trim().toUpperCase();
if (type.equals("CONTINUOUS")) {
_signalTypeMap.setType(port, CONTINUOUS);
if (port.isOutput()) {
_signalTypeMap.propagateType(port);
}
} else if (type.equals("DISCRETE")) {
_signalTypeMap.setType(port, DISCRETE);
if (port.isOutput()) {
_signalTypeMap.propagateType(port);
}
} else {
throw new InvalidStateException(port,
" signalType not understandable.");
}
} else if (a instanceof CTCompositeActor) {
// Assume all the ports of a CTCompositeActor
// to be continuous unless otherwise specified.
// NOTE: this is a conservative approximation.
if (_signalTypeMap.getType(port) == UNKNOWN) {
_signalTypeMap.setType(port, CONTINUOUS);
}
if (port.isOutput()) {
_signalTypeMap.propagateType(port);
}
}
}
// NOTE: If it is a domain polymorphic source, unless its
// outputs are declared as DISCRETE, assume their signal
// types to CONTINUOUS. For example, the Const actor.
// FIXME: Should the Sequence actor implement the SequenceActor
// interface?
if (predecessorList(a).isEmpty()) {
ports = ((Entity) a).portList().iterator();
while (ports.hasNext()) {
IOPort port = (IOPort) ports.next();
if (_signalTypeMap.getType(port) == UNKNOWN) {
_signalTypeMap.setType(port, CONTINUOUS);
if (port.isOutput()) {
_signalTypeMap.propagateType(port);
}
}
}
}
}
}
// Done with classification and port signal type assignment
// of the sources, waveform generators, event generators,
// sequence actors, and dynamic actors.
// 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\'"