use of gov.sandia.n2a.eqset.EquationEntry in project n2a by frothga.
the class AccessVariable method simplify.
public Operator simplify(Variable from) {
// unresolved!
if (reference == null || reference.variable == null)
return this;
Variable v = reference.variable;
// specifically prevent $init and $live from being replaced by a Constant
if (v.name.equals("$init") || v.name.equals("$live"))
return this;
// A variable may locally evaluate to a constant, yet be subject to change from outside equations.
if (v.hasAttribute("externalWrite"))
return this;
if (v.equations.size() != 1)
return this;
EquationEntry e = v.equations.first();
if (e.expression == null)
return this;
if (e.condition != null) {
if (!(e.condition instanceof Constant))
return this;
// Check for nonzero constant
Type value = ((Constant) e.condition).value;
// This second condition should be eliminated by Variable.simplify(), but until it is, don't do anything here.
if (!(value instanceof Scalar) || ((Scalar) value).value == 0)
return this;
}
if (e.expression instanceof Constant) {
from.removeDependencyOn(v);
from.changed = true;
return e.expression;
}
// Attempt to simplify expression, and maybe get a Constant
Variable p = from;
while (p != null) {
// can't simplify, because we've already visited this variable
if (p == v)
return this;
p = p.visited;
}
v.visited = from;
e.expression = e.expression.simplify(v);
if (e.expression instanceof Constant) {
from.removeDependencyOn(v);
from.changed = true;
return e.expression;
}
if (// Our variable is simply an alias for another variable, so grab the other variable instead.
e.expression instanceof AccessVariable) {
AccessVariable av = (AccessVariable) e.expression;
Variable v2 = av.reference.variable;
if (v2 == v)
return this;
// Can't reference a temporary outside the current equation set.
if (v2.hasAttribute("temporary") && v2.container != from.container)
return this;
// Note: Folding an aliased variable will very likely remove one or more steps of delay in the movement of values through an equation set.
// This might go against the user's intention. The folding can be blocked by adding a condition
reference = av.reference;
name = av.reference.variable.nameString();
from.removeDependencyOn(v);
from.addDependencyOn(v2);
from.changed = true;
}
return this;
}
use of gov.sandia.n2a.eqset.EquationEntry in project n2a by frothga.
the class JobC method resolve.
/**
* @param v A variable to convert into C++ code that can access it at runtime.
* @param context For the AST rendering system.
* @param lvalue Indicates that this will receive a value assignment. The other case is an rvalue, which will simply be read.
* @param base Injects a pointer at the beginning of the resolution path.
* @param logical The intended use is in a boolean expression, such as an if-test.
*/
public String resolve(VariableReference r, CRenderer context, boolean lvalue, String base, boolean logical) {
if (r == null || r.variable == null)
return "unresolved";
if (r.variable.hasAttribute("constant")) {
EquationEntry e = r.variable.equations.first();
StringBuilder temp = context.result;
StringBuilder result = new StringBuilder();
context.result = result;
e.expression.render(context);
context.result = temp;
return result.toString();
}
String containers = resolveContainer(r, context, base);
if (r.variable.name.equals("(connection)")) {
if (containers.endsWith("->"))
containers = containers.substring(0, containers.length() - 2);
if (containers.endsWith("."))
containers = containers.substring(0, containers.length() - 1);
return containers;
}
String name = "";
// NOT context.bed !
BackendDataC bed = (BackendDataC) r.variable.container.backendData;
if (r.variable.hasAttribute("preexistent")) {
if (!lvalue) {
if (r.variable.name.equals("$t")) {
if (r.variable.order == 0)
name = "simulator.currentEvent->t";
else if (r.variable.order == 1) {
if (context.hasEvent)
name = "event->dt";
else
name = "getEvent ()->dt";
}
// TODO: what about higher orders of $t?
} else {
// strip the $ and expect it to be a member of simulator
return "simulator." + r.variable.name.substring(1);
}
}
// for lvalue, fall through to the main case below
}
if (r.variable.name.equals("$live")) {
if (r.variable.hasAttribute("accessor")) {
if (lvalue)
return "unresolved";
name = "getLive ()";
} else // not "constant" or "accessor", so must be direct access
{
if (logical)
return "(" + containers + "flags & (" + bed.flagType + ") 0x1 << " + bed.liveFlag + ")";
else
return "((" + containers + "flags & (" + bed.flagType + ") 0x1 << " + bed.liveFlag + ") ? 1 : 0)";
}
} else if (r.variable.hasAttribute("accessor")) {
// At present, only $live can have "accessor" attribute.
return "unresolved";
}
if (r.variable.name.endsWith(".$count")) {
if (lvalue)
return "unresolved";
String alias = r.variable.name.substring(0, r.variable.name.lastIndexOf("."));
name = mangle(alias) + "->" + prefix(r.variable.container) + "_" + mangle(alias) + "_count";
}
if (name.length() == 0) {
if (lvalue && (bed.globalBuffered.contains(r.variable) || bed.localBuffered.contains(r.variable))) {
name = mangle("next_", r.variable);
} else {
name = mangle(r.variable);
}
}
return containers + name;
}
use of gov.sandia.n2a.eqset.EquationEntry in project n2a by frothga.
the class XyceBackend method generateNetlist.
public void generateNetlist(MNode job, Simulator simulator, FileWriter 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("$metadata", "seed") + "\n");
writer.append(".tran 0 " + job.get("$metadata", "duration") + "\n");
// 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, false, 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 extends Visitor {
List<Operator> traces = new ArrayList<Operator>();
public boolean visit(Operator op) {
if (op instanceof Output) {
traces.add(((Output) op).operands[0]);
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[0] == 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.eqset.EquationEntry 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 extends 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", 0));
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.EquationEntry in project n2a by frothga.
the class AccessElement method simplify.
public Operator simplify(Variable from) {
for (int i = 0; i < operands.length; i++) operands[i] = operands[i].simplify(from);
if (operands.length == 1) {
from.changed = true;
return operands[0];
}
// All operand positions beyond 0 are subscripts, presumably into a matrix at operands[0].
// Attempt to replace the element access with a constant.
int row = -1;
int col = 0;
if (operands[1] instanceof Constant) {
Constant c = (Constant) operands[1];
if (c.value instanceof Scalar)
row = (int) ((Scalar) c.value).value;
}
if (operands.length > 2) {
col = -1;
if (operands[2] instanceof Constant) {
Constant c = (Constant) operands[2];
if (c.value instanceof Scalar)
col = (int) ((Scalar) c.value).value;
}
}
if (row < 0 || col < 0)
return this;
if (operands[0] instanceof Constant) {
Constant c = (Constant) operands[0];
if (c.value instanceof Matrix) {
from.changed = true;
return new Constant(new Scalar(((Matrix) c.value).get(row, col)));
}
} else {
// Try to unpack the target variable and see if the specific element we want is constant
AccessVariable av = (AccessVariable) operands[0];
if (av.reference != null && av.reference.variable != null) {
Variable v = av.reference.variable;
if (v.equations != null && v.equations.size() == 1) {
EquationEntry e = v.equations.first();
if (// Ideally, we would also ensure e.condition is satisfied. However, only weird code would have a condition at all.
e.expression instanceof BuildMatrix) {
BuildMatrix b = (BuildMatrix) e.expression;
Operator element = b.getElement(row, col);
if (element != null && element instanceof Constant) {
from.changed = true;
e.expression.releaseDependencies(from);
if (e.condition != null)
e.condition.releaseDependencies(from);
return element;
}
}
}
}
}
return this;
}
Aggregations