use of gov.sandia.n2a.eqset.EquationSet 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.eqset.EquationSet in project n2a by frothga.
the class ExportJob method getEquations.
public EquationSet getEquations(MPart p) {
List<String> path = new ArrayList<String>();
MPart parent = p;
while (parent != null) {
path.add(parent.key());
parent = parent.getParent();
}
EquationSet result = equations;
for (int i = path.size() - 2; i >= 0; i--) {
String name = path.get(i);
result = result.findPart(name);
if (result == null)
return null;
if (!result.name.equals(name))
return null;
}
return result;
}
use of gov.sandia.n2a.eqset.EquationSet in project n2a by frothga.
the class ExportJob method process.
public void process(MNode source, File destination) {
try {
MPart mpart = new MPart((MPersistent) source);
modelName = source.key();
equations = new EquationSet(mpart);
// Make eqset minimally executable ...
try {
equations.resolveConnectionBindings();
}// Still try to finish rest of compilation. Maybe only one or two minor parts were affected.
catch (Exception e) {
}
try {
equations.addGlobalConstants();
// $index, $init, $live, $n, $t, $t', $type
equations.addSpecials();
equations.fillIntegratedVariables();
equations.findIntegrated();
equations.resolveLHS();
equations.resolveRHS();
// This could hurt the analysis. It simplifies expressions and substitutes constants, breaking some dependency chains.
equations.findConstants();
equations.determineTypes();
equations.clearVariables();
}// It may still be possible to complete the export.
catch (Exception e) {
}
analyze(equations);
DocumentBuilderFactory factoryBuilder = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factoryBuilder.newDocumentBuilder();
doc = builder.newDocument();
// Convert top-level N2A part into top-level NeuroML elements
process(mpart);
DOMSource dom = new DOMSource(doc);
StreamResult stream = new StreamResult(new OutputStreamWriter(new FileOutputStream(destination), "UTF-8"));
TransformerFactory factoryXform = TransformerFactory.newInstance();
factoryXform.setAttribute("indent-number", 4);
Transformer xform = factoryXform.newTransformer();
xform.setOutputProperty(OutputKeys.INDENT, "yes");
xform.transform(dom, stream);
} catch (Exception e) {
e.printStackTrace();
}
}
use of gov.sandia.n2a.eqset.EquationSet in project n2a by frothga.
the class Output method determineVariableName.
// This method should be called by analysis, with v set to the variable that holds this equation.
public void determineVariableName(Variable v) {
// Ensure that the first operand is a file name.
// If no file name is specified, stdout is used. We get the same effect by specifying the empty string, so insert it here.
// This makes parameter processing much simpler elsewhere.
int length = operands.length;
if (length > 0 && !isStringExpression(v, operands[0])) {
variableName = variableName0;
Operator[] newOperands = new Operator[length + 1];
for (int i = 0; i < length; i++) newOperands[i + 1] = operands[i];
newOperands[0] = new Constant(new Text());
operands = newOperands;
} else {
variableName = variableName1;
}
if (// Column name not specified
length < 3) {
if (variableName == null)
variableName = v.nameString();
EquationSet container = v.container;
if (// regular part
container.connectionBindings == null) {
dependOnIndex(v, container);
} else // connection
{
// depend on all endpoints
for (ConnectionBinding c : container.connectionBindings) {
dependOnIndex(v, c.endpoint);
}
}
}
}
use of gov.sandia.n2a.eqset.EquationSet in project n2a by frothga.
the class BackendDataC method setGlobalNeedPath.
/**
* @param s The equation set directly associated with this backend data.
*/
public void setGlobalNeedPath(EquationSet s) {
EquationSet c = s.container;
// Don't set flag, because we know that path() will return "".
if (c == null)
return;
needGlobalPath = true;
setParentNeedPath(s);
}
Aggregations