use of gov.sandia.n2a.language.type.Scalar in project n2a by frothga.
the class InternalBackendData method analyze.
public void analyze(final EquationSet s) {
System.out.println(s.name);
if (s.connectionBindings != null) {
// Note that populations have already been allocated in the constructor.
endpoints = countLocalObject;
countLocalObject += s.connectionBindings.size();
}
for (// we want the sub-lists to be ordered correctly
Variable v : // we want the sub-lists to be ordered correctly
s.ordered) {
String className = "null";
if (v.type != null)
className = v.type.getClass().getSimpleName();
System.out.println(" " + v.nameString() + " " + v.attributeString() + " " + className);
if (v.name.equals("$index"))
index = v;
else if (v.name.equals("$init"))
init = v;
else if (v.name.equals("$live"))
live = v;
else if (v.name.equals("$n") && v.order == 0)
n = v;
else if (v.name.equals("$p") && v.order == 0)
p = v;
else if (v.name.equals("$type"))
type = v;
else if (v.name.equals("$xyz") && v.order == 0)
xyz = v;
else if (v.name.equals("$t")) {
if (v.order == 0)
t = v;
else if (v.order == 1)
dt = v;
}
if (v.hasAttribute("global")) {
v.global = true;
v.visit(new Visitor() {
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
if (av.reference.resolution.size() > 0)
addReferenceGlobal(av.reference, s);
return false;
}
if (op instanceof Output) {
Output o = (Output) op;
if (o.operands.length < 3) {
o.index = countGlobalObject++;
namesGlobalObject.add("columnName" + o.index);
}
// Continue descent, because parameters of output() may contain variable references
return true;
}
return true;
}
});
if (// eliminate non-computed values, unless they refer to a variable outside the immediate equation set
!v.hasAny(new String[] { "constant", "accessor", "readOnly" }) || v.hasAll(new String[] { "constant", "reference" })) {
boolean initOnly = v.hasAttribute("initOnly");
boolean updates = !initOnly && v.equations.size() > 0 && (v.derivative == null || v.hasAttribute("updates"));
if (updates)
globalUpdate.add(v);
if (v.hasAttribute("reference")) {
addReferenceGlobal(v.reference, s);
} else {
boolean temporary = v.hasAttribute("temporary");
if (!temporary || v.hasUsers())
globalInit.add(v);
if (!temporary && !v.hasAttribute("dummy")) {
if (!v.hasAttribute("preexistent"))
globalMembers.add(v);
boolean external = false;
if (v.hasAttribute("externalWrite") || v.assignment != Variable.REPLACE) {
external = true;
globalBufferedExternalWrite.add(v);
}
if (external || (v.hasAttribute("externalRead") && updates)) {
external = true;
globalBufferedExternal.add(v);
}
if (external || v.hasAttribute("cycle")) {
globalBuffered.add(v);
if (!external) {
globalBufferedInternal.add(v);
if (!initOnly)
globalBufferedInternalUpdate.add(v);
}
}
}
}
}
} else // local
{
v.visit(new Visitor() {
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
if (av.reference.resolution.size() > 0)
addReferenceLocal(av.reference, s);
return false;
}
if (op instanceof Output) {
Output o = (Output) op;
if (o.operands.length < 3) {
o.index = countLocalObject++;
namesLocalObject.add("columnName" + o.index);
}
// Continue descent, because parameters of output() may contain variable references
return true;
}
return true;
}
});
if (!v.hasAny(new String[] { "constant", "accessor", "readOnly" }) || v.hasAll(new String[] { "constant", "reference" })) {
boolean initOnly = v.hasAttribute("initOnly");
boolean updates = !initOnly && v.equations.size() > 0 && (v.derivative == null || v.hasAttribute("updates"));
if (updates)
localUpdate.add(v);
if (v.hasAttribute("reference")) {
addReferenceLocal(v.reference, s);
} else {
boolean temporary = v.hasAttribute("temporary");
if (!temporary || v.hasUsers()) {
if (v.name.startsWith("$") || (temporary && v.neededBySpecial())) {
if (!v.name.equals("$index") && !v.name.equals("$live"))
localInitSpecial.add(v);
} else {
localInitRegular.add(v);
}
}
if (!temporary && !v.hasAttribute("dummy")) {
if (!v.hasAttribute("preexistent"))
localMembers.add(v);
boolean external = false;
if (v.hasAttribute("externalWrite") || v.assignment != Variable.REPLACE) {
external = true;
localBufferedExternalWrite.add(v);
}
if (external || (v.hasAttribute("externalRead") && updates)) {
external = true;
localBufferedExternal.add(v);
}
if (external || v.hasAttribute("cycle")) {
if (v.name.startsWith("$"))
localBufferedSpecial.add(v);
else
localBufferedRegular.add(v);
if (// v got here only by being a "cycle", not "externalRead" or "externalWrite"
!external) {
localBufferedInternal.add(v);
if (!initOnly)
localBufferedInternalUpdate.add(v);
}
}
}
}
}
}
}
for (// we need these to be in order by differential level, not by dependency
Variable v : // we need these to be in order by differential level, not by dependency
s.variables) {
if (v.derivative != null && !v.hasAny(new String[] { "constant", "initOnly" })) {
if (v.hasAttribute("global"))
globalIntegrated.add(v);
else
localIntegrated.add(v);
}
}
populationCanGrowOrDie = s.lethalP || s.lethalType || s.canGrow();
if (n != null) {
populationCanResize = globalMembers.contains(n);
// See EquationSet.forceTemporaryStorageForSpecials() for a related issue.
if (!populationCanResize && populationCanGrowOrDie && n.hasUsers()) {
Backend.err.get().println("WARNING: $n can change (due to structural dynamics) but it was detected as a constant. Equations that depend on $n may give incorrect results.");
}
}
if (index != null) {
indexNext = countGlobalFloat++;
namesGlobalFloat.add("indexNext");
indexAvailable = countGlobalObject++;
namesGlobalObject.add("indexAvailable");
}
if (// track instances
s.connected || s.needInstanceTracking || populationCanResize) {
// The reason populationCanResize forces use of the instances array is to enable pruning of parts when $n decreases.
instances = countGlobalObject++;
namesGlobalObject.add("instances");
if (// in addition, track newly created instances
s.connected) {
firstborn = countGlobalFloat++;
namesGlobalFloat.add("firstborn");
newborn = countLocalFloat++;
namesLocalFloat.add("newborn");
}
}
if (p != null) {
Pdependencies = new ArrayList<Variable>();
for (Variable t : s.ordered) {
if (t.hasAttribute("temporary") && p.dependsOn(t) != null) {
Pdependencies.add(t);
}
}
}
populationIndex = 0;
if (// check for null specifically to guard against the Wrapper equation set (which is not fully constructed)
s.container != null && s.container.parts != null) {
for (EquationSet p : s.container.parts) {
if (p == s)
break;
populationIndex++;
}
}
if (// connection-specific stuff
s.connectionBindings != null) {
int size = s.connectionBindings.size();
// endpoints is allocated at the top of this function, because it is needed for reference handling in the variable analysis loop
projectDependencies = new Object[size];
projectReferences = new Object[size];
count = new int[size];
k = new Variable[size];
max = new Variable[size];
min = new Variable[size];
project = new Variable[size];
radius = new Variable[size];
for (int i = 0; i < s.connectionBindings.size(); i++) {
ConnectionBinding c = s.connectionBindings.get(i);
count[i] = -1;
k[i] = s.find(new Variable(c.alias + ".$k"));
max[i] = s.find(new Variable(c.alias + ".$max"));
min[i] = s.find(new Variable(c.alias + ".$min"));
project[i] = s.find(new Variable(c.alias + ".$project"));
radius[i] = s.find(new Variable(c.alias + ".$radius"));
if (c.endpoint.accountableConnections != null) {
AccountableConnection query = new AccountableConnection(s, c.alias);
AccountableConnection ac = c.endpoint.accountableConnections.floor(query);
if (// Only true if this endpoint is accountable.
ac.equals(query)) {
// Allocate space for counter in target part
InternalBackendData endpointBed = (InternalBackendData) c.endpoint.backendData;
count[i] = endpointBed.countLocalFloat++;
endpointBed.namesLocalFloat.add(s.prefix() + ".$count");
if (// $count is referenced explicitly, so need to finish setting it up
ac.count != null) {
ac.count.readIndex = ac.count.writeIndex = count[i];
}
}
}
// Note that countLocalObject has already been incremented above
namesLocalObject.add(c.alias);
if (project[i] != null) {
ArrayList<Variable> dependencies = new ArrayList<Variable>();
// Always assign, even if empty.
projectDependencies[i] = dependencies;
for (Variable t : s.ordered) {
if (t.hasAttribute("temporary") && project[i].dependsOn(t) != null) {
dependencies.add(t);
}
}
final TreeSet<VariableReference> references = new TreeSet<VariableReference>(referenceComparator);
class ProjectVisitor extends Visitor {
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
if (av.reference.resolution.size() > 0)
references.add(av.reference);
return false;
}
return true;
}
}
ProjectVisitor visitor = new ProjectVisitor();
project[i].visit(visitor);
for (Variable v : dependencies) v.visit(visitor);
if (references.size() > 0)
projectReferences[i] = references;
}
c.resolution = translateResolution(c.resolution, s);
}
}
// Locals
for (Variable v : localMembers) {
// in the type array rather than the float array.
if (v.type instanceof Scalar && v.reference.variable == v) {
v.readIndex = v.writeIndex = countLocalFloat++;
namesLocalFloat.add(v.nameString());
} else {
v.readIndex = v.writeIndex = countLocalObject++;
namesLocalObject.add(v.nameString());
}
}
for (Variable v : localBufferedExternal) {
if (v.type instanceof Scalar && v.reference.variable == v) {
v.writeIndex = countLocalFloat++;
namesLocalFloat.add("next_" + v.nameString());
} else {
v.writeIndex = countLocalObject++;
namesLocalObject.add("next_" + v.nameString());
}
}
for (Variable v : localBufferedInternal) {
v.writeTemp = true;
if (v.type instanceof Scalar && v.reference.variable == v) {
v.writeIndex = countLocalTempFloat++;
namesLocalTempFloat.add("next_" + v.nameString());
} else {
v.writeIndex = countLocalTempObject++;
namesLocalTempObject.add("next_" + v.nameString());
}
}
// Globals
for (Variable v : globalMembers) {
if (v.type instanceof Scalar && v.reference.variable == v) {
v.readIndex = v.writeIndex = countGlobalFloat++;
namesGlobalFloat.add(v.nameString());
} else {
v.readIndex = v.writeIndex = countGlobalObject++;
namesGlobalObject.add(v.nameString());
}
}
for (Variable v : globalBufferedExternal) {
if (v.type instanceof Scalar && v.reference.variable == v) {
v.writeIndex = countGlobalFloat++;
namesGlobalFloat.add("next_" + v.nameString());
} else {
v.writeIndex = countGlobalObject++;
namesGlobalObject.add("next_" + v.nameString());
}
}
for (Variable v : globalBufferedInternal) {
v.writeTemp = true;
if (v.type instanceof Scalar && v.reference.variable == v) {
v.writeIndex = countGlobalTempFloat++;
namesGlobalTempFloat.add("next_" + v.nameString());
} else {
v.writeIndex = countGlobalTempObject++;
namesGlobalTempObject.add("next_" + v.nameString());
}
}
// fully temporary values
for (Variable v : s.variables) {
if (!v.hasAttribute("temporary"))
continue;
v.readTemp = v.writeTemp = true;
if (v.hasAttribute("global")) {
if (v.type instanceof Scalar && v.reference.variable == v) {
v.readIndex = v.writeIndex = countGlobalTempFloat++;
namesGlobalTempFloat.add(v.nameString());
} else {
v.readIndex = v.writeIndex = countGlobalTempObject++;
namesGlobalTempObject.add(v.nameString());
}
} else {
if (v.type instanceof Scalar && v.reference.variable == v) {
v.readIndex = v.writeIndex = countLocalTempFloat++;
namesLocalTempFloat.add(v.nameString());
} else {
v.readIndex = v.writeIndex = countLocalTempObject++;
namesLocalTempObject.add(v.nameString());
}
}
}
if (live.hasAttribute("constant"))
liveStorage = LIVE_CONSTANT;
else if (live.hasAttribute("accessor"))
liveStorage = LIVE_ACCESSOR;
else
// $live is "initOnly"
liveStorage = LIVE_STORED;
for (VariableReference r : localReference) r.resolution = translateResolution(r.resolution, s);
for (VariableReference r : globalReference) r.resolution = translateResolution(r.resolution, s);
// Type conversions
String[] forbiddenAttributes = new String[] { "global", "constant", "accessor", "reference", "temporary", "dummy", "preexistent" };
for (EquationSet target : s.getConversionTargets()) {
if (s.connectionBindings == null) {
if (target.connectionBindings != null)
throw new EvaluationException("Can't change $type from compartment to connection.");
} else {
if (target.connectionBindings == null)
throw new EvaluationException("Can't change $type from connection to compartment.");
}
Conversion conversion = new Conversion();
conversions.put(target, conversion);
// Match variables
for (Variable v : target.variables) {
if (v.name.equals("$type"))
continue;
if (v.hasAny(forbiddenAttributes))
continue;
Variable v2 = s.find(v);
if (v2 != null && v2.equals(v)) {
conversion.to.add(v);
conversion.from.add(v2);
}
}
// Match connection bindings
if (// Since we checked above, we know that target is also a connection.
s.connectionBindings != null) {
conversion.bindings = new int[s.connectionBindings.size()];
int i = 0;
for (ConnectionBinding c : s.connectionBindings) {
conversion.bindings[i] = -1;
int j = 0;
for (ConnectionBinding d : target.connectionBindings) {
if (c.alias.equals(d.alias)) {
conversion.bindings[i] = j;
break;
}
j++;
}
// Note: ALL bindings must match. There is no other mechanism for initializing the endpoints.
if (conversion.bindings[i] < 0)
throw new EvaluationException("Unfulfilled connection binding during $type change.");
i++;
}
}
// TODO: Match populations?
// Currently, any contained populations do not carry over to new instance. Instead, it must create them from scratch.
}
}
use of gov.sandia.n2a.language.type.Scalar in project n2a by frothga.
the class InternalBackendData method analyzeLastT.
/**
* Determine if time of last integration must be stored.
* Note: global (population) variables are integrated at same time as container using its dt value.
* Thus, we only handle local variables here.
*/
public void analyzeLastT(EquationSet s) {
boolean hasIntegrated = localIntegrated.size() > 0;
for (EquationSet p : s.parts) {
if (hasIntegrated)
break;
hasIntegrated = ((InternalBackendData) p.backendData).globalIntegrated.size() > 0;
}
boolean dtCanChange = dt != null && dt.equations.size() > 0 && !dt.hasAttribute("initOnly");
if (hasIntegrated && (eventTargets.size() > 0 || dtCanChange)) {
lastT = new Variable("$lastT");
lastT.readIndex = lastT.writeIndex = countLocalFloat++;
namesLocalFloat.add(lastT.nameString());
lastT.type = new Scalar(0);
}
}
use of gov.sandia.n2a.language.type.Scalar in project n2a by frothga.
the class InternalBackendData method analyzeEvents.
public static void analyzeEvents(final EquationSet s, final List<EventTarget> eventTargets, final List<Variable> eventReferences) {
class EventVisitor extends Visitor {
public boolean found;
public boolean visit(Operator op) {
if (op instanceof Event) {
found = true;
Event de = (Event) op;
if (// this event has not yet been analyzed
de.eventType == null) {
final EventTarget et = new EventTarget(de);
int targetIndex = eventTargets.indexOf(et);
if (// event target already exists
targetIndex >= 0) {
de.eventType = eventTargets.get(targetIndex);
} else // we must create a new event target, or more properly, fill in the event target we just used as a query object
{
// Create an entry and save the index
targetIndex = eventTargets.size();
eventTargets.add(et);
de.eventType = et;
et.container = s;
// Determine edge type
if (de.operands.length < 3) {
et.edge = EventTarget.RISE;
} else if (de.operands[2] instanceof Constant) {
Constant c = (Constant) de.operands[2];
if (c.value instanceof Text) {
Text t = (Text) c.value;
if (t.value.equalsIgnoreCase("nonzero"))
et.edge = EventTarget.NONZERO;
else if (t.value.equalsIgnoreCase("change"))
et.edge = EventTarget.CHANGE;
else if (t.value.equalsIgnoreCase("fall"))
et.edge = EventTarget.FALL;
else
et.edge = EventTarget.RISE;
} else {
Backend.err.get().println("ERROR: event() edge type must be a string.");
throw new Backend.AbortRun();
}
} else {
Backend.err.get().println("ERROR: event() edge type must be constant.");
throw new Backend.AbortRun();
}
// Allocate auxiliary variable
if (de.operands[0] instanceof AccessVariable) {
AccessVariable av = (AccessVariable) de.operands[0];
VariableReference reference = av.reference;
Variable v = reference.variable;
// then the user has broken the rule that we can't see temporaries in other parts.
if (v.hasAttribute("temporary") && v.container != s) {
Backend.err.get().println("WARNING: Cannot be temporary due to event monitor: " + v.container.name + "." + v.nameString() + " from " + s.name);
v.removeAttribute("temporary");
}
// so fall through to the !trackOne case below.
if (!v.hasAttribute("temporary")) {
// ensure it's buffered, so we can detect change
v.addAttribute("externalRead");
et.trackOne = true;
// just a holder for the reference
et.track = new Variable();
et.track.reference = reference;
}
}
if (// Expression, so create auxiliary variable. Aux not needed for NONZERO, because no change detection.
!et.trackOne && et.edge != EventTarget.NONZERO) {
et.track = new Variable("eventAux" + targetIndex, 0);
et.track.type = new Scalar(0);
et.track.reference = new VariableReference();
et.track.reference.variable = et.track;
}
// Locate any temporaries for evaluation. TODO: for more efficiency, we could have separate lists of temporaries for the condition and delay operands
// Tie into the dependency graph using a phantom variable (which can go away afterward without damaging the graph).
final Variable phantom = new Variable("event");
phantom.uses = new IdentityHashMap<Variable, Integer>();
for (int i = 0; i < et.event.operands.length; i++) et.event.operands[i].visit(new Visitor() {
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable v = av.reference.variable;
if (!phantom.uses.containsKey(v))
phantom.uses.put(v, 1);
return false;
}
return true;
}
});
// Scan all variables in equation set to see if we need them
for (Variable t : s.variables) {
if (t.hasAttribute("temporary") && phantom.dependsOn(t) != null)
et.dependencies.add(t);
}
// Note the default is already set to -1 (no care)
class DelayVisitor extends Visitor {
TreeSet<EquationSet> containers = new TreeSet<EquationSet>();
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
// could include the target part itself, if in fact we use local variables
containers.add(av.reference.variable.container);
return false;
}
return true;
}
}
DelayVisitor dv = new DelayVisitor();
if (de.operands.length >= 2) {
if (de.operands[1] instanceof Constant) {
Constant c = (Constant) de.operands[1];
et.delay = (float) ((Scalar) c.value).value;
if (et.delay < 0)
et.delay = -1;
} else {
// indicates that we need to evaluate delay at run time
et.delay = -2;
de.operands[1].visit(dv);
}
}
// Set up monitors in source parts
class ConditionVisitor extends Visitor {
TreeSet<EquationSet> containers = new TreeSet<EquationSet>();
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable v = av.reference.variable;
EquationSet sourceContainer = v.container;
containers.add(sourceContainer);
// Set up monitors for values that can vary during update.
if (!v.hasAttribute("constant") && !v.hasAttribute("initOnly") && !et.monitors(sourceContainer)) {
EventSource es = new EventSource(sourceContainer, et);
// null means self-reference, a special case handled in Part
if (sourceContainer != s)
es.reference = av.reference;
et.sources.add(es);
}
return false;
}
return true;
}
}
ConditionVisitor cv = new ConditionVisitor();
de.operands[0].visit(cv);
// Special case for event with no references that vary
if (et.sources.isEmpty()) {
// We can avoid creating a self monitor if we know for certain that the event will never fire
boolean neverFires = false;
if (de.operands[0] instanceof Constant) {
if (et.edge == EventTarget.NONZERO) {
Type op0 = ((Constant) de.operands[0]).value;
if (op0 instanceof Scalar) {
neverFires = ((Scalar) op0).value == 0;
} else {
Backend.err.get().println("ERROR: Condition for event() must resolve to a number.");
throw new Backend.AbortRun();
}
} else {
neverFires = true;
}
}
if (!neverFires) {
EventSource es = new EventSource(s, et);
// This is a self-reference, so es.reference should be null.
et.sources.add(es);
}
}
// Determine if monitor needs to test every target, or if one representative target is sufficient
for (EventSource source : et.sources) {
// associated with any given source instance, so every target must be evaluated separately.
if (cv.containers.size() > 1)
source.testEach = true;
if (dv.containers.size() > 1 || (dv.containers.size() == 1 && dv.containers.first() != source.container))
source.delayEach = true;
}
}
}
}
return true;
}
}
EventVisitor eventVisitor = new EventVisitor();
for (Variable v : s.variables) {
eventVisitor.found = false;
v.visit(eventVisitor);
if ((eventVisitor.found || v.dependsOnEvent()) && v.reference.variable != v)
eventReferences.add(v);
}
}
use of gov.sandia.n2a.language.type.Scalar in project n2a by frothga.
the class Part method finish.
public boolean finish(Simulator simulator) {
InternalBackendData bed = (InternalBackendData) equations.backendData;
int populations = equations.parts.size();
for (int i = 0; i < populations; i++) ((Population) valuesObject[i]).finish(simulator);
if (bed.liveStorage == InternalBackendData.LIVE_STORED) {
// early-out if we are already dead, to avoid another call to die()
if (((Scalar) get(bed.live)).value == 0)
return false;
}
// Events
for (EventSource es : bed.eventSources) {
@SuppressWarnings("unchecked") List<Instance> monitors = (ArrayList<Instance>) valuesObject[es.monitorIndex];
if (monitors.size() == 0)
continue;
EventTarget eventType = es.target;
if (es.testEach) {
for (Instance i : monitors) {
if (i == null)
continue;
double delay = eventType.test(i, simulator);
// the trigger condition was not satisfied
if (delay < -1)
continue;
EventSpikeSingle spike;
if (// event was triggered, but timing is no-care
delay < 0) {
spike = new EventSpikeSingleLatch();
// queue immediately after current cycle, so latches get set for next full cycle
spike.t = simulator.currentEvent.t;
} else if (// process as close to current cycle as possible
delay == 0) {
// fully execute the event (not latch it)
spike = new EventSpikeSingle();
// queue immediately
spike.t = simulator.currentEvent.t;
} else {
// Is delay an quantum number of $t' steps?
double ratio = delay / event.dt;
int step = (int) Math.round(ratio);
if (Math.abs(ratio - step) < 1e-3) {
if (simulator.eventMode == Simulator.DURING)
spike = new EventSpikeSingleLatch();
else
spike = new EventSpikeSingle();
if (simulator.eventMode == Simulator.AFTER)
delay = (step + 1e-6) * event.dt;
else
delay = (step - 1e-6) * event.dt;
} else {
spike = new EventSpikeSingle();
}
spike.t = simulator.currentEvent.t + delay;
}
spike.eventType = eventType;
spike.target = i;
simulator.queueEvent.add(spike);
}
} else // All monitors share same condition, so only test one.
{
double delay = -2;
for (Instance i : monitors) {
if (i == null)
continue;
delay = eventType.test(i, simulator);
break;
}
// the trigger condition was not satisfied
if (delay < -1)
continue;
if (// Each target instance may require a different delay.
es.delayEach) {
for (Instance i : monitors) {
if (i == null)
continue;
// This results in one redundant eval, of first entry in monitors. Not clear if it's worth the work to avoid this.
delay = eventType.delay(i, simulator);
EventSpikeSingle spike;
if (delay < 0) {
spike = new EventSpikeSingleLatch();
spike.t = simulator.currentEvent.t;
} else if (delay == 0) {
spike = new EventSpikeSingle();
spike.t = simulator.currentEvent.t;
} else {
double ratio = delay / event.dt;
int step = (int) Math.round(ratio);
if (Math.abs(ratio - step) < 1e-3) {
if (simulator.eventMode == Simulator.DURING)
spike = new EventSpikeSingleLatch();
else
spike = new EventSpikeSingle();
if (simulator.eventMode == Simulator.AFTER)
delay = (step + 1e-6) * event.dt;
else
delay = (step - 1e-6) * event.dt;
} else {
spike = new EventSpikeSingle();
}
spike.t = simulator.currentEvent.t + delay;
}
spike.eventType = eventType;
spike.target = i;
simulator.queueEvent.add(spike);
}
} else // All delays are the same.
{
EventSpikeMulti spike;
if (delay < 0) {
spike = new EventSpikeMultiLatch();
spike.t = simulator.currentEvent.t;
} else if (delay == 0) {
spike = new EventSpikeMulti();
spike.t = simulator.currentEvent.t;
} else {
double ratio = delay / event.dt;
int step = (int) Math.round(ratio);
if (Math.abs(ratio - step) < 1e-3) {
if (simulator.eventMode == Simulator.DURING)
spike = new EventSpikeMultiLatch();
else
spike = new EventSpikeMulti();
if (simulator.eventMode == Simulator.AFTER)
delay = (step + 1e-6) * event.dt;
else
delay = (step - 1e-6) * event.dt;
} else {
spike = new EventSpikeMulti();
}
spike.t = simulator.currentEvent.t + delay;
}
spike.eventType = eventType;
// We don't copy the array, just keep a reference to it. What could go wrong with this?
// If a part dies and tries to remove itself from the list while it is being used to deliver spikes,
// then we could get a null pointer exception. Solution is to synchronize access to the list.
// If a connection is born while the spike is in flight, one could argue that it shouldn't
// receive it, but one could also argue that it should. In nature these two things (spikes
// and synapse creation) occur at vastly different timescales. Wouldn't a nascent synapse
// receive spikes even as it is forming?
spike.targets = monitors;
simulator.queueEvent.add(spike);
}
}
}
// Other stuff
if (bed.lastT != null)
setFinal(bed.lastT, new Scalar(simulator.currentEvent.t));
for (Variable v : bed.localBufferedExternal) setFinal(v, getFinal(v));
for (Integer i : bed.eventLatches) valuesFloat[i] = 0;
for (Variable v : bed.localBufferedExternalWrite) {
switch(v.assignment) {
case Variable.ADD:
// initial value is zero-equivalent (additive identity)
set(v, v.type);
break;
case Variable.MULTIPLY:
case Variable.DIVIDE:
// multiplicative identity
if (v.type instanceof Matrix)
set(v, ((Matrix) v.type).identity());
else
set(v, new Scalar(1));
break;
case Variable.MIN:
if (v.type instanceof Matrix)
set(v, ((Matrix) v.type).clear(Double.POSITIVE_INFINITY));
else
set(v, new Scalar(Double.POSITIVE_INFINITY));
break;
case Variable.MAX:
if (v.type instanceof Matrix)
set(v, ((Matrix) v.type).clear(Double.NEGATIVE_INFINITY));
else
set(v, new Scalar(Double.NEGATIVE_INFINITY));
break;
}
}
if (bed.type != null) {
int type = (int) ((Scalar) get(bed.type)).value;
if (type > 0) {
ArrayList<EquationSet> split = equations.splits.get(type - 1);
if (// Make sure $type != me. Otherwise it's a null operation
split.size() > 1 || split.get(0) != equations) {
// indicates that this instance is one of the resulting parts
boolean used = false;
int countParts = split.size();
for (int i = 0; i < countParts; i++) {
EquationSet other = split.get(i);
Scalar splitPosition = new Scalar(i + 1);
if (other == equations && !used) {
used = true;
setFinal(bed.type, splitPosition);
} else {
InternalBackendData otherBed = (InternalBackendData) other.backendData;
Part p = new Part(other, (Part) container);
// If this is a connection, keep the same bindings
Conversion conversion = bed.conversions.get(other);
if (conversion.bindings != null) {
for (int j = 0; j < conversion.bindings.length; j++) {
p.valuesObject[otherBed.endpoints + conversion.bindings[j]] = valuesObject[bed.endpoints + j];
}
}
event.enqueue(p);
p.resolve();
// accountable connections are updated here
p.init(simulator);
// Copy over variables
int count = conversion.from.size();
for (int v = 0; v < count; v++) {
Variable from = conversion.from.get(v);
Variable to = conversion.to.get(v);
p.setFinal(to, get(from));
}
// Set $type to be our position in the split
p.setFinal(otherBed.type, splitPosition);
}
}
if (!used) {
die();
return false;
}
}
}
}
if (equations.lethalP) {
double p;
if (bed.p.hasAttribute("temporary")) {
InstanceTemporaries temp = new InstanceTemporaries(this, simulator, false);
for (Variable v : bed.Pdependencies) {
Type result = v.eval(temp);
if (result != null && v.writeIndex >= 0)
temp.set(v, result);
}
Type result = bed.p.eval(temp);
if (result == null)
p = 1;
else
p = ((Scalar) result).value;
} else {
p = ((Scalar) get(bed.p)).value;
}
if (p == 0 || p < 1 && p < simulator.random.nextDouble()) {
die();
return false;
}
}
if (equations.lethalConnection) {
int count = equations.connectionBindings.size();
for (int i = 0; i < count; i++) {
if (!getPart(i).getLive()) {
die();
return false;
}
}
}
if (equations.lethalContainer) {
if (!((Part) container).getLive()) {
die();
return false;
}
}
return true;
}
use of gov.sandia.n2a.language.type.Scalar in project n2a by frothga.
the class Part method die.
public void die() {
// set $live to false, if it is stored in this part
InternalBackendData bed = (InternalBackendData) equations.backendData;
if (bed.liveStorage == InternalBackendData.LIVE_STORED) {
set(bed.live, new Scalar(0));
}
// update accountable endpoints
if (bed.count != null) {
int length = bed.count.length;
for (int i = 0; i < length; i++) {
if (bed.count[i] >= 0) {
Part p = (Part) valuesObject[bed.endpoints + i];
p.valuesFloat[bed.count[i]]--;
}
}
}
// Release event monitors
for (EventTarget et : bed.eventTargets) {
for (EventSource es : et.sources) {
// Don't bother with self-connection, since we are going away.
if (es.reference == null)
continue;
Part source = (Part) valuesObject[es.reference.index];
@SuppressWarnings("unchecked") ArrayList<Instance> monitors = (ArrayList<Instance>) source.valuesObject[es.monitorIndex];
int index = monitors.indexOf(this);
// Actually removing the element can cause a concurrent modification exception. Instead, the monitors array will get flushed next time an event processes it.
monitors.set(index, null);
}
}
((Population) container.valuesObject[bed.populationIndex]).remove(this);
}
Aggregations