use of gov.sandia.n2a.backend.internal.InternalBackendData.Conversion 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;
}
Aggregations