use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class ExportJob method fakeConnectionTarget.
/**
* Replace any entries of the form A=connect() with A=N2A_fakePart.
*/
public static boolean fakeConnectionTarget(EquationSet s) {
boolean result = false;
for (Variable v : s.variables) {
if (// may be due to unreadable part names in connect()
v.equations.size() == 0) {
String value = s.source.get(v.nameString());
if (!Operator.containsConnect(value))
continue;
try {
v.add(new EquationEntry("N2A_fakePart"));
result = true;
} catch (Exception e) {
}
} else if (// could be a properly-parsed connect() line
v.equations.size() == 1) {
EquationEntry e = v.equations.first();
// connect() appears like AccessElement during initial parse
if (!(e.expression instanceof AccessElement))
continue;
AccessElement ae = (AccessElement) e.expression;
AccessVariable av = (AccessVariable) ae.operands[0];
if (!av.name.equals("connect"))
continue;
av.name = "N2A_fakePart";
e.expression = av;
result = true;
}
}
for (EquationSet p : s.parts) if (fakeConnectionTarget(p))
result = true;
return result;
}
use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class ExportJob method analyze.
/**
* Find references to $index in connection endpoints, and set up info for ConnectionContext.
*/
public void analyze(EquationSet s) {
for (EquationSet p : s.parts) analyze(p);
class ExportTransformer implements Transformer {
Variable v;
public Operator transform(Operator op) {
if (op instanceof AccessVariable) {
VariableReference r = ((AccessVariable) op).reference;
// It is possible that some variables were not resolved.
if (r == null)
return null;
Variable rv = r.variable;
if (rv.container != v.container && !r.resolution.isEmpty()) {
Object o = r.resolution.get(r.resolution.size() - 1);
if (o instanceof ConnectionBinding) {
// This is somewhat of a hack, but ConnectionContext assumes the mappings A->0 and B->1.
switch(((ConnectionBinding) o).alias) {
case "A":
r.index = 0;
break;
case "B":
r.index = 1;
break;
}
}
}
return null;
}
if (op instanceof Output) {
return new OutputLEMS((Output) op);
}
return null;
}
}
;
ExportTransformer xform = new ExportTransformer();
for (final Variable v : s.variables) {
xform.v = v;
v.transform(xform);
// does not call that function.
if (v.hasUsers() || v.hasAttribute("externalWrite"))
continue;
if (v.name.startsWith("$") || v.name.contains(".$"))
continue;
for (EquationEntry e : v.equations) {
if (e.expression.isOutput()) {
v.addAttribute("dummy");
break;
}
}
}
}
use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class XyceBackendData method analyze.
public void analyze(EquationSet s) {
if (Device.isXyceDevice(s)) {
deviceSymbol = new Device(s);
}
class ContainsOperator implements Visitor {
@SuppressWarnings("rawtypes")
public Class targetClass;
boolean found;
public boolean visit(Operator op) {
if (found)
return false;
if (op.getClass().equals(targetClass)) {
found = true;
return false;
}
return true;
}
public boolean check(EquationEntry e) {
found = false;
e.expression.visit(this);
return found;
}
}
ContainsOperator containsPulse = new ContainsOperator();
containsPulse.targetClass = Pulse.class;
ContainsOperator containsSinewave = new ContainsOperator();
containsSinewave.targetClass = Sinewave.class;
ContainsVariable containsT = new ContainsVariable(new Variable("$t"));
for (Variable v : s.variables) {
// in a static (no structural dynamics) simulation, no $variable needs to be computed at runtime
if (v.name.startsWith("$"))
continue;
// Constants are already subbed in. "initOnly" values are defined during init cycle, and can now be subbed during code generation.
if (v.hasAttribute("constant") || v.hasAttribute("initOnly"))
continue;
for (EquationEntry eq : v.equations) {
// don't need to write out equations defining dynamics already defined by a device
if (Device.isXyceDevice(s) && Device.ignoreEquation(eq))
continue;
Symbol handler = null;
if (eq.variable.order > 1) {
Backend.err.get().println("Support for higher order differential equations not implemented yet (" + eq + ")");
throw new Backend.AbortRun();
} else if (eq.variable.order == 1) {
handler = new SymbolStateVar1(eq);
} else // The following are all order 0
if (containsPulse.check(eq)) {
handler = new SymbolPulse(eq);
} else if (containsSinewave.check(eq)) {
handler = new SymbolSinewave(eq);
} else // TODO: this doesn't seem like an adequate test. Why would having a $t be the only reason to generate a zero-order symbol?
if (containsT.check(eq.expression)) {
handler = new SymbolStateVar0(eq);
} else if (isExplicitInit(eq)) {
handler = new SymbolConstantIC(eq);
} else {
// The RHS expression depends on state variables, so we create a netlist .func for it.
handler = new SymbolFunc(eq);
}
equationSymbols.put(eq, handler);
// May set the handler for v several times, but only the last one is kept. Multiple handlers should agree on symbol for reference. Better yet is to handle multiple equations together.
variableSymbols.put(v.name, handler);
}
}
}
use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class SymbolStateVar1 method getDefinition.
@Override
public String getDefinition(XyceRenderer renderer) {
String translatedEq = renderer.change(eq.expression);
Variable v = eq.variable;
VariableReference r = v.reference;
if (// symbol is defined here; no += allowed within same part
r.index < 0) {
return Xyceisms.defineDiffEq(v.name, renderer.pi.hashCode(), translatedEq);
}
// This symbol refers to a symbol in another part. We don't re-define the
// variable, rather we create another diff eq that updates the existing one.
Instance target = (Instance) renderer.pi.valuesObject[r.index];
String thisVarname = r.variable.name + "_" + target.hashCode();
String eqName = v.name + "_" + renderer.pi.hashCode();
return Xyceisms.updateDiffEq(eqName, thisVarname, translatedEq);
}
use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class BackendDataC method analyze.
public void analyze(final EquationSet s) {
boolean headless = AppData.properties.getBoolean("headless");
if (!headless)
System.out.println(s.name);
for (// we want the sub-lists to be ordered correctly
Variable v : // we want the sub-lists to be ordered correctly
s.ordered) {
if (!headless) {
String className = "null";
if (v.type != null)
className = v.type.getClass().getSimpleName();
System.out.println(" " + v.nameString() + " " + v.attributeString() + " " + className);
}
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("$n") && v.order == 0) {
if (s.connectionBindings != null) {
// It is an error to explicitly define $n on a connection,
// which is the only way we can get to this point.
Backend.err.get().println("$n is not applicable to connections");
throw new Backend.AbortRun();
}
n = v;
nInitOnly = n.hasAttribute("initOnly");
// In this special case we will directly use the current population count.
if (nInitOnly)
n.addAttribute("preexistent");
} else if (v.name.equals("$index")) {
index = v;
// Don't let $index enter into any variable lists. Instead, always give it special treatment. In effect, it is a list of one.
continue;
} else if (v.name.equals("$live")) {
live = v;
// $live can never function as a regular variable because it is stored as a bit flag
continue;
} else if (v.name.equals("$t")) {
if (v.order == 0)
t = v;
else if (v.order == 1)
dt = v;
}
if (v.hasAny(new String[] { "constant", "accessor" }) && !v.hasAll(new String[] { "constant", "reference" }))
continue;
boolean initOnly = v.hasAttribute("initOnly");
boolean emptyCombiner = v.isEmptyCombiner();
boolean updates = !initOnly && v.equations.size() > 0 && !emptyCombiner && (v.derivative == null || v.hasAttribute("updates"));
boolean temporary = v.hasAttribute("temporary");
boolean unusedTemporary = temporary && !v.hasUsers();
boolean derivativeOrDependency = v.hasAttribute("derivativeOrDependency");
if (v.hasAttribute("global")) {
if (updates && !unusedTemporary)
globalUpdate.add(v);
if (derivativeOrDependency)
globalDerivativeUpdate.add(v);
if (!unusedTemporary && !emptyCombiner)
globalInit.add(v);
if (!v.hasAttribute("reference")) {
if (!temporary && !v.hasAttribute("dummy")) {
if (!v.hasAttribute("preexistent")) {
globalMembers.add(v);
// check if v.usedBy contains any variable that is not v's integral
if (derivativeOrDependency && v.derivative == null && v.usedBy != null) {
for (Object o : v.usedBy) {
if (o instanceof Variable && ((Variable) o).derivative != v) {
globalDerivativePreserve.add(v);
break;
}
}
}
}
boolean external = false;
if (!initOnly) {
if (v.name.equals("$t")) {
if (v.order > 1)
globalDerivative.add(v);
} else // any other variable
{
if (v.order > 0)
globalDerivative.add(v);
}
// The integration step has roughly the same effect as an external write.
if (v.hasAttribute("externalWrite") || v.assignment != Variable.REPLACE) {
external = true;
globalBufferedExternalWrite.add(v);
if (derivativeOrDependency)
globalBufferedExternalWriteDerivative.add(v);
}
if (external || (v.hasAttribute("externalRead") && updates)) {
external = true;
globalBufferedExternal.add(v);
if (derivativeOrDependency)
globalBufferedExternalDerivative.add(v);
}
}
if (external || v.hasAttribute("cycle")) {
globalBuffered.add(v);
if (!external && !initOnly) {
globalBufferedInternalUpdate.add(v);
if (derivativeOrDependency)
globalBufferedInternalDerivative.add(v);
}
}
}
}
} else // local
{
if (updates && !unusedTemporary)
localUpdate.add(v);
if (derivativeOrDependency)
localDerivativeUpdate.add(v);
if (!unusedTemporary && !emptyCombiner && v != type)
localInit.add(v);
if (v.hasAttribute("reference")) {
if (v.reference.variable.container.canDie())
localReference.add(v.reference);
} else {
if (!temporary && !v.hasAttribute("dummy")) {
if (!v.hasAttribute("preexistent")) {
localMembers.add(v);
if (derivativeOrDependency && v.derivative == null && v.usedBy != null) {
for (Object o : v.usedBy) {
if (o instanceof Variable && ((Variable) o).derivative != v) {
localDerivativePreserve.add(v);
break;
}
}
}
}
boolean external = false;
if (!initOnly) {
if (v.name.equals("$t")) {
if (v.order > 1)
localDerivative.add(v);
} else {
if (v.order > 0)
localDerivative.add(v);
}
if (v.hasAttribute("externalWrite") || v.assignment != Variable.REPLACE) {
external = true;
localBufferedExternalWrite.add(v);
if (derivativeOrDependency)
localBufferedExternalWriteDerivative.add(v);
}
if (external || (v.hasAttribute("externalRead") && updates)) {
external = true;
localBufferedExternal.add(v);
if (derivativeOrDependency)
localBufferedExternalDerivative.add(v);
}
}
if (external || v.hasAttribute("cycle")) {
localBuffered.add(v);
if (!external && !initOnly) {
localBufferedInternalUpdate.add(v);
if (derivativeOrDependency)
localBufferedInternalDerivative.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("constant", "initOnly")) {
if (v.hasAttribute("global"))
globalIntegrated.add(v);
else
localIntegrated.add(v);
}
}
// Purge any lists that consist solely of temporaries, as they accomplish nothing.
for (List<Variable> list : Arrays.asList(globalUpdate, globalDerivativeUpdate, globalInit, globalIntegrated, localUpdate, localDerivativeUpdate, localInit, localIntegrated)) {
boolean allTemporary = true;
for (Variable v : list) if (!v.hasAttribute("temporary"))
allTemporary = false;
if (allTemporary)
list.clear();
}
if (dt != null && dt.hasAttribute("constant")) {
setDt = true;
// However, if the nearest container that defines $t' matches our value, then don't set $t'.
if (s.container != null) {
Variable pdt = s.container.findDt();
if (pdt != null && pdt.hasAttribute("constant")) {
double value = dt.equations.first().expression.getDouble();
double pvalue = pdt.equations.first().expression.getDouble();
setDt = value != pvalue;
}
}
}
if (s.connectionBindings != null) {
for (ConnectionBinding c : s.connectionBindings) {
Variable v = s.find(new Variable(c.alias + ".$max", -1));
if (v == null)
v = s.find(new Variable(c.alias + ".$min", -1));
if (v != null)
accountableEndpoints.add(c.alias);
if (s.find(new Variable(c.alias + ".$project")) != null)
hasProject = true;
}
}
if (eventTargets.size() > 0) {
for (EventTarget et : eventTargets) {
if (et.delay < -1) {
needLocalEventDelay = true;
break;
}
}
}
boolean canDie = s.canDie();
refcount = s.referenced && canDie;
singleton = s.isSingleton(true);
// Works correctly even if n is null.
canResize = globalMembers.contains(n);
trackInstances = s.connected || s.needInstanceTracking || canResize;
canGrowOrDie = s.lethalP || s.lethalType || s.canGrow();
trackN = n != null && !singleton;
boolean Euler = s.getRoot().metadata.getOrDefault("Euler", "backend", "all", "integrator").equals("Euler");
if (!canResize && canGrowOrDie && n != null && n.hasUsers()) {
// This is a flaw in the analysis process that needs to be fixed.
// See note in InternalBackendData for details.
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.");
}
int flagCount = eventTargets.size();
if (live != null && !live.hasAny(new String[] { "constant", "accessor" }))
liveFlag = flagCount++;
if (trackInstances && s.connected)
newborn = flagCount++;
if (flagCount == 0)
localFlagType = "";
else if (flagCount <= 8)
localFlagType = "uint8_t";
else if (flagCount <= 16)
localFlagType = "uint16_t";
else if (flagCount <= 32)
localFlagType = "uint32_t";
else if (flagCount <= 64)
localFlagType = "uint64_t";
else {
Backend.err.get().println("ERROR: Too many local flags to fit in basic integer type");
throw new Backend.AbortRun();
}
flagCount = 0;
if (trackInstances && s.connected)
clearNew = flagCount++;
if (flagCount == 0)
globalFlagType = "";
else if (flagCount <= 8)
globalFlagType = "uint8_t";
else if (flagCount <= 16)
globalFlagType = "uint16_t";
else if (flagCount <= 32)
globalFlagType = "uint32_t";
else if (flagCount <= 64)
globalFlagType = "uint64_t";
else {
Backend.err.get().println("ERROR: Too many global flags to fit in basic integer type");
throw new Backend.AbortRun();
}
needGlobalDerivative = !Euler && globalDerivative.size() > 0;
needGlobalIntegrate = globalIntegrated.size() > 0;
needGlobalPreserve = !Euler && (needGlobalIntegrate || globalDerivativePreserve.size() > 0 || globalBufferedExternalWriteDerivative.size() > 0);
needGlobalDtor = needGlobalPreserve || needGlobalDerivative;
needGlobalCtor = needGlobalDtor || (index != null || n != null) && !singleton;
needGlobalInit = globalMembers.size() > 0 || !globalFlagType.isEmpty() || globalInit.size() > 0 || singleton || n != null || s.connectionBindings != null;
needGlobalUpdate = globalUpdate.size() > 0;
needGlobalFinalizeN = s.container == null && (canResize || canGrowOrDie);
needGlobalFinalize = globalBufferedExternal.size() > 0 || needGlobalFinalizeN || (canResize && (canGrowOrDie || !n.hasAttribute("initOnly")));
needGlobalUpdateDerivative = !Euler && globalDerivativeUpdate.size() > 0;
needGlobalFinalizeDerivative = !Euler && globalBufferedExternalDerivative.size() > 0;
// Created simplified localInit to check if init is needed.
// This is only temporary, because the proper simplification should only be done after I/O operators have names generated.
List<Variable> simplifiedLocalInit = new ArrayList<Variable>(localInit);
s.simplify("$init", simplifiedLocalInit);
needLocalDerivative = !Euler && localDerivative.size() > 0;
needLocalIntegrate = localIntegrated.size() > 0;
needLocalPreserve = !Euler && (needLocalIntegrate || localDerivativePreserve.size() > 0 || localBufferedExternalWriteDerivative.size() > 0);
needLocalDtor = needLocalPreserve || needLocalDerivative;
needLocalCtor = needLocalDtor || s.accountableConnections != null || refcount || index != null || localMembers.size() > 0 || s.parts.size() > 0;
needLocalDie = canDie && (liveFlag >= 0 || trackN || accountableEndpoints.size() > 0 || eventTargets.size() > 0);
needLocalInit = localBufferedExternal.size() > 0 || eventTargets.size() > 0 || !localFlagType.isEmpty() || lastT || simplifiedLocalInit.size() > 0 || trackN || accountableEndpoints.size() > 0 || eventTargets.size() > 0 || s.parts.size() > 0;
needLocalUpdate = localUpdate.size() > 0;
needLocalFinalize = localBufferedExternal.size() > 0 || type != null || canDie;
needLocalUpdateDerivative = !Euler && localDerivativeUpdate.size() > 0;
needLocalFinalizeDerivative = !Euler && localBufferedExternalDerivative.size() > 0;
// Ensure that functions are emitted to update child populations.
for (EquationSet p : s.parts) {
BackendDataC pbed = (BackendDataC) p.backendData;
if (pbed.needGlobalInit)
needLocalInit = true;
if (pbed.needGlobalIntegrate)
needLocalIntegrate = true;
if (pbed.needGlobalUpdate)
needLocalUpdate = true;
if (pbed.needGlobalFinalize)
needLocalFinalize = true;
if (pbed.needGlobalUpdateDerivative)
needLocalUpdateDerivative = true;
if (pbed.needGlobalFinalizeDerivative)
needLocalFinalizeDerivative = true;
if (pbed.needGlobalPreserve)
needLocalPreserve = true;
if (pbed.needGlobalDerivative)
needLocalDerivative = true;
}
}
Aggregations