use of gov.sandia.n2a.language.type.Instance 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;
}
// when they are evaluated, which is generally different than the triggering event.
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 a 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.during)
spike = new EventSpikeSingleLatch();
else
spike = new EventSpikeSingle();
delay = step * 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.during)
spike = new EventSpikeSingleLatch();
else
spike = new EventSpikeSingle();
delay = step * 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.during)
spike = new EventSpikeMultiLatch();
else
spike = new EventSpikeMulti();
delay = step * 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));
clearExternalWriteBuffers(bed.localBufferedExternalWrite);
for (Integer i : bed.eventLatches) valuesFloat[i] = 0;
if (bed.type != null) {
int type = (int) ((Scalar) get(bed.type)).value;
if (type > 0) {
ArrayList<EquationSet> split = equations.splits.get(type - 1);
// 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;
// zeroes all variables
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();
// 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));
}
// sets $type, which will appear during init cycle
p.setFinal(otherBed.type, splitPosition);
p.init(simulator);
}
}
if (!used) {
die();
return false;
}
}
}
if (equations.lethalP) {
double p;
if (bed.p.hasAttribute("temporary")) {
// Probe $p in run phase (as opposed to connect phase).
InstanceTemporaries temp = new InstanceTemporaries(this, simulator);
for (Variable v : bed.PdependenciesTemp) {
Type result = v.eval(temp);
if (result == null)
temp.set(v, v.type);
else
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 && Math.pow(p, event.dt) < 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.Instance in project n2a by frothga.
the class Part method die.
public void die() {
InternalBackendData bed = (InternalBackendData) equations.backendData;
if (bed.fastExit) {
Simulator s = Simulator.instance.get();
s.stop = true;
s.fastExit = true;
// The bookkeeping below is no longer relevant.
return;
}
// set $live to false, if it is stored in this part
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);
}
use of gov.sandia.n2a.language.type.Instance in project n2a by frothga.
the class XyceBackend method generateNetlist.
public void generateNetlist(MNode job, Simulator simulator, BufferedWriter writer) throws Exception {
Population toplevel = (Population) simulator.wrapper.valuesObject[0];
XyceRenderer renderer = new XyceRenderer(simulator);
// Header
writer.append(toplevel.equations.name + "\n");
writer.append("\n");
writer.append("* seed: " + job.get("seed") + "\n");
writer.append(".tran 0 " + job.get("duration") + "\n");
MNode integrator = job.child("integrator");
if (integrator != null) {
String method = integrator.get();
if (!method.isEmpty()) {
writer.append(".options timeint method=" + method + "\n");
}
// TODO: add other integrator options
}
// Equations
for (Instance i : simulator) {
if (i == simulator.wrapper)
continue;
writer.append("\n");
writer.append("* " + i + "\n");
renderer.pi = i;
renderer.exceptions = null;
XyceBackendData bed = (XyceBackendData) i.equations.backendData;
if (bed.deviceSymbol != null) {
writer.append(bed.deviceSymbol.getDefinition(renderer));
}
InstanceTemporaries temp = new InstanceTemporaries(i, simulator, bed.internal);
for (final Variable v : i.equations.variables) {
// Compute variable v
// TODO: how to switch between multiple conditions that can be true during normal operation? IE: how to make Xyce code conditional?
// Perhaps gate each condition (through a transistor?) and sum them at a single node.
// e can be null
EquationEntry e = v.select(temp);
Symbol def = bed.equationSymbols.get(e);
if (def == null)
continue;
writer.append(def.getDefinition(renderer));
// Trace
class TraceFinder implements Visitor {
List<Operator> traces = new ArrayList<Operator>();
public boolean visit(Operator op) {
if (op instanceof Output) {
traces.add(((Output) op).operands[1]);
return false;
}
return true;
}
}
TraceFinder traceFinder = new TraceFinder();
e.expression.visit(traceFinder);
for (Operator trace : traceFinder.traces) {
// We don't know if contents is .func, expression or a node, so always wrap in braces.
writer.append(".print tran {");
if (trace instanceof AccessVariable) {
AccessVariable av = (AccessVariable) trace;
writer.append(renderer.change(av.reference));
} else // trace is an expression
{
if (// this trace wraps the entire equation
e.expression instanceof Output && ((Output) e.expression).operands[1] == trace) {
// simply print the LHS variable, similar to the AccessVariable case above
writer.append(renderer.change(v.reference));
} else {
// arbitrary expression
writer.append(renderer.change(trace));
}
}
// one .print line per variable
writer.append("}\n");
}
}
}
// Trailer
writer.append(".end\n");
}
use of gov.sandia.n2a.language.type.Instance in project n2a by frothga.
the class EquationSet method findConnectionMatrix.
/**
* Detects if $p depends on a NonzeroIterable operator.
* Depends on results of: determineTypes() and clearVariables() -- To provide fake values.
*/
public void findConnectionMatrix() {
for (EquationSet s : parts) {
s.findConnectionMatrix();
}
// Only do this on connections
if (connectionBindings == null)
return;
// Only check binary connections
if (connectionBindings.size() != 2)
return;
Variable p = find(new Variable("$p"));
if (p == null)
return;
// Determine which equation fires during connect phase
Instance instance = new Instance() {
public Type get(Variable v) {
if (v.name.equals("$connect"))
return new Scalar(1);
if (v.name.equals("$init"))
return new Scalar(0);
if (v.name.equals("$live"))
return new Scalar(0);
return v.type;
}
};
Operator predicate = null;
for (// Scan for first equation whose condition is nonzero
EquationEntry e : // Scan for first equation whose condition is nonzero
p.equations) {
if (e.condition == null) {
predicate = e.expression;
break;
}
Type doit = e.condition.eval(instance);
if (doit instanceof Scalar && ((Scalar) doit).value != 0) {
predicate = e.expression;
break;
}
}
if (predicate == null)
return;
// Detect if equation or dependency contains a NonzeroIterable.
class ContainsTransformer implements Transformer {
public NonzeroIterable found;
// Number of times a nonzero iterable was found
public int count;
public boolean substituted;
public Operator transform(Operator op) {
if (op instanceof NonzeroIterable) {
found = (NonzeroIterable) op;
count++;
return op;
}
if (op instanceof AccessVariable) {
// Check if this is a local reference to a single equation.
AccessVariable av = (AccessVariable) op;
Variable v = av.reference.variable;
// We only examine local dependencies.
if (v.container != p.container)
return op;
if (v.equations.size() != 1)
return op;
EquationEntry e = v.equations.first();
if (e.condition != null)
return op;
// Substitute the equation into the predicate.
substituted = true;
Operator result = e.expression.deepCopy();
result.parent = op.parent;
return result;
}
// continue descent
return null;
}
}
ContainsTransformer ct = new ContainsTransformer();
Operator p2 = predicate.deepCopy();
// to prevent infinite recursion
int depthLimit = variables.size();
do {
ct.count = 0;
ct.substituted = false;
p2 = p2.transform(ct);
} while (ct.substituted && depthLimit-- > 0);
if (ct.count != 1)
return;
if (!ct.found.hasCorrectForm())
return;
// then only non-zero elements will produce connections.
try {
Type result = p2.eval(instance);
// Any type other than Scalar is treated as "true", so p2 fails the test.
if (!(result instanceof Scalar))
return;
// Any nonzero value is treated as "true".
if (((Scalar) result).value != 0)
return;
} catch (EvaluationException e) {
return;
}
// Construct
// The NonzeroIterable we found above was a deep-copy, not the original.
// We need to locate and work with the original in order to maintain object
// identity in the finished model.
predicate.visit(new Visitor() {
public int depthLimit = variables.size();
public boolean visit(Operator op) {
if (op instanceof NonzeroIterable) {
ConnectionMatrix cm = new ConnectionMatrix((NonzeroIterable) op);
if (cm.rowMapping != null && cm.colMapping != null) {
connectionMatrix = cm;
// Somewhat of a hack. cm is a one-time process, so we shouldn't do polling.
p.metadata.clear("poll");
}
return false;
}
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable v = av.reference.variable;
if (v.container != p.container)
return false;
if (v.equations.size() != 1)
return false;
EquationEntry e = v.equations.first();
if (e.condition != null)
return false;
depthLimit--;
if (depthLimit >= 0)
e.expression.visit(this);
depthLimit++;
}
return true;
}
});
}
use of gov.sandia.n2a.language.type.Instance in project n2a by frothga.
the class EquationSet method resolveRHS.
public void resolveRHS(LinkedList<UnresolvedVariable> unresolved) {
for (EquationSet s : parts) {
s.resolveRHS(unresolved);
}
class Resolver implements Visitor {
public Variable from;
public LinkedList<UnresolvedVariable> unresolved;
public String fromName() {
String result = from.container.prefix();
if (!result.isEmpty())
result += ".";
return result + from.nameString();
}
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable query = new Variable(av.getName(), av.getOrder());
VariableReference r = new VariableReference();
query.reference = r;
av.reference = r;
// modifies "r" with actual resolution path
EquationSet dest = resolveEquationSet(query, false);
r.removeLoops();
// dependencies from "from" to each part in the resolution path
r.addDependencies(from);
if (dest == null) {
unresolved.add(new UnresolvedVariable(av.name, fromName()));
} else {
// "query" contains the modified variable name, needed for lookup within "dest"
r.variable = dest.find(query);
if (r.variable == null) {
if (query.hasAttribute("instance")) {
// Configure reference to destination container itself.
// Recycle the query variable as a pseudo target (one that doesn't actually exist in the container).
r.variable = query;
query.container = dest;
query.equations = new TreeSet<EquationEntry>();
query.type = new Instance();
// Only for use by Internal backend. It's easier to set this here than to scan for "instance" variables in InternalBackendData.analyze().
query.readIndex = -2;
} else if (// accountable endpoint
query.name.equals("$count")) {
int last = r.resolution.size() - 1;
Object o = null;
if (last >= 0)
o = r.resolution.get(last);
if (!(o instanceof ConnectionBinding)) {
unresolved.add(new UnresolvedVariable(av.name, fromName()));
} else {
ConnectionBinding cb = (ConnectionBinding) o;
if (dest.accountableConnections == null)
dest.accountableConnections = new TreeSet<AccountableConnection>();
AccountableConnection ac = new AccountableConnection(r.penultimateContainer(EquationSet.this), cb.alias);
if (!dest.accountableConnections.add(ac))
ac = dest.accountableConnections.floor(ac);
if (ac.count == null) {
// Create a fully-functional variable.
// However, it never gets formally added to dest, because dest should never evaluate it.
// Rather, it is maintained by the backend's connection system.
ac.count = new Variable(prefix() + ".$count");
ac.count.type = new Scalar(0);
ac.count.container = dest;
ac.count.equations = new TreeSet<EquationEntry>();
ac.count.reference = new VariableReference();
ac.count.reference.variable = ac.count;
}
r.variable = ac.count;
}
} else {
unresolved.add(new UnresolvedVariable(av.name, fromName()));
}
} else {
from.addDependencyOn(r.variable);
}
}
return false;
}
if (op instanceof Split) {
Split split = (Split) op;
split.parts = new ArrayList<EquationSet>(split.names.length);
EquationSet self = from.reference.variable.container;
// Could be null, if self is top-level model.
EquationSet family = self.container;
for (String partName : split.names) {
EquationSet part;
if (// This allows for $type in top-level model, where no higher container is available to search in.
partName.equals(self.name))
// This allows for $type in top-level model, where no higher container is available to search in.
part = self;
else
part = family.findPart(partName);
if (part != null) {
split.parts.add(part);
Variable query = new Variable("$type");
Variable type = part.find(query);
if (type == null) {
type = query;
part.add(type);
// double-buffer it
type.addAttribute("externalWrite");
type.unit = AbstractUnit.ONE;
type.equations = new TreeSet<EquationEntry>();
type.reference = new VariableReference();
type.reference.variable = type;
}
if (type != from)
type.addDependencyOn(from);
} else {
unresolved.add(new UnresolvedVariable(partName, fromName()));
}
}
return false;
}
return true;
}
}
Resolver resolver = new Resolver();
resolver.unresolved = unresolved;
for (Variable v : variables) {
resolver.from = v;
v.visit(resolver);
}
}
Aggregations