use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class EquationSet method fillAutoPins.
/**
* If this part exposes an auto pin, then duplicate the dependent sub-parts for each bound input.
* Finally, this function recurses into all child parts, whether or not they are the result of duplication.
* The duplication takes place only at the EquationSet level. The corresponding source field is
* simply a reference to the original source. This is slightly inconsistent with the contents
* of the resulting EquationSet objects. For example, the key of the source will not match the name
* of the EquationSet. If this breaks any middle-end code, then we can create a fake
* source, or even update the true source. In the last case, it would be necessary for the true
* source to be volatile, so the database record is not changed.
* Depends on: collectPins()
*/
public void fillAutoPins() {
for (MNode autopin : pinIn) {
String pinName = autopin.key();
if (!pinName.endsWith("#"))
continue;
// Found an auto pin; now process it ...
int length = pinName.length() - 1;
String pinBase = pinName.substring(0, length);
// Scan for instances
// These only exist in the part's original metadata, since they are not backed by actual sub-parts.
// automatically sorted, which is useful for iteration below
TreeSet<Integer> instances = new TreeSet<Integer>();
for (MNode pin2 : metadata.childOrEmpty("gui", "pin", "in")) {
String pinBaseI = pin2.key();
if (!pinBaseI.startsWith(pinBase))
continue;
// remove prefix
String suffix = pinBaseI.substring(length);
// The suffix must be a proper integer.
try {
int index = Integer.parseInt(suffix);
if (index > 0)
instances.add(index);
} catch (NumberFormatException e) {
}
}
int lastIndex = 0;
if (!instances.isEmpty())
lastIndex = instances.last();
// Collect destination parts for connections
Map<String, EquationSet> Bparts = new HashMap<String, EquationSet>();
for (MNode subscriber : autopin) {
String baseName = subscriber.key();
EquationSet template = findPart(baseName);
if (template.connectionBindings == null)
continue;
MNode templatePin = template.metadata.child("gui", "pin");
// assigned by collectPins()
String Aname = templatePin.get("alias");
// This is a compact form of the same code in resolveConnectionBindings()
for (Variable v : template.variables) {
if (v.name.equals(Aname))
continue;
AccessVariable av = template.isConnectionBinding(v);
if (av == null)
continue;
ConnectionBinding cb = new ConnectionBinding();
if (!template.resolveConnectionBinding(av.name, cb))
continue;
if (cb.endpoint == null)
continue;
Bparts.put(baseName, cb.endpoint);
// for an alias, v.name is sufficient
templatePin.set(v.name, "aliasB");
break;
}
}
// Process each instance
// previous index; zero is never a suffix, so this is sufficient to indicate none (start of list)
int previous = 0;
for (int index : instances) {
String pinBaseI = pinBase + index;
// Duplicate each subscriber
for (MNode subscriber : autopin) {
String baseName = subscriber.key();
EquationSet template = findPart(baseName);
EquationSet duplicate = new EquationSet(this, baseName + index);
parts.add(duplicate);
duplicate.copyPinTemplate(template);
duplicate.override("autoIndex=" + index);
duplicate.override("autoCount=" + lastIndex);
MNode templatePin = template.metadata.child("gui", "pin");
if (// connectionBindings got preliminary setting from collectPins()
template.connectionBindings != null) {
MNode append = templatePin.child("append");
String autoBase = templatePin.getOrDefault("0", "append");
EquationSet Bpart = Bparts.get(baseName);
if (Bpart == null) {
// In that case, fake the autoBase in the duplicated part itself.
if (append != null)
duplicate.override("autoBase=" + autoBase);
} else {
// assigned by collectPins()
String Aname = templatePin.get("alias");
// assigned above
String Bname = templatePin.get("aliasB");
if (append != null) {
duplicate.override("autoBase=:" + Bname + ".autoBase" + index);
duplicate.override("$all." + Bname + ".autoN" + index + "=" + Aname + ".$n");
}
// Set variables in B part
if (append != null) {
if (previous == 0)
Bpart.override("$all.autoBase" + index + "=" + autoBase);
else
Bpart.override("$all.autoBase" + index + "=autoBase" + previous + "+autoN" + previous);
previous = index;
if (index == lastIndex) {
String n = Bpart.source.get("$n");
if (n.isEmpty() || n.startsWith("autoBase"))
Bpart.override("$n=autoBase" + index + "+autoN" + index);
}
}
}
}
// connections
if (// must match the auto-pin name
templatePin.get().equals(pinName)) {
duplicate.metadata.set(pinBaseI, "gui", "pin");
}
// parts that forward inputs
for (MNode b : templatePin.childOrEmpty("in")) {
if (// must bind to IO block and match the auto-pin name
b.get("bind").isEmpty() && b.get("bind", "pin").equals(pinName)) {
duplicate.metadata.set(pinBaseI, "gui", "pin", "in", b.key(), "bind", "pin");
}
}
}
}
}
// model, but is useful for an export routine that understands auto pins.
for (EquationSet s : parts) s.fillAutoPins();
}
use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class EquationSet method findConstantsEval.
protected boolean findConstantsEval() {
boolean changed = false;
for (Variable v : variables) {
if (v.simplify())
changed = true;
// "externalWrite" -- Regardless of the local math, a variable that gets written is not constant.
if (v.hasAny("constant", "initOnly", "externalWrite"))
continue;
if (// A variable with a derivative is usually not constant, with the following exceptions ...
v.derivative != null) {
// 1) Check for unconditional constant.
if (v.equations.size() == 1) {
EquationEntry e = v.equations.first();
if (// Must be unconditional. No exception for $init. (Non-integrated variables do get an exception for $init; see below.)
e.expression instanceof Constant && e.condition == null) {
changed = true;
v.addAttribute("constant");
v.removeDependencyOn(v.derivative);
v.derivative = null;
continue;
}
}
// 2a) Check for pure circular dependency.
Variable top = v;
while (// This single dependency must be the derivative.
top.uses != null && top.uses.size() == 1) {
if (top.derivative != null) {
top = top.derivative;
continue;
}
// Its single dependency is not a derivative, but could be anything else.
if (// This is a pure circular dependency.
top.uses.containsKey(v)) {
// Evaluate top. Initial value of v must be zero, because otherwise it would depend on other variables or be trapped above as an unconditional constant.
// We can only make this assumption here.
Instance instance = new Instance() {
public Scalar zero = new Scalar(0);
// all AccessVariable objects will reach here first.
public Type get(VariableReference r) throws EvaluationException {
return zero;
}
};
Type result = top.eval(instance);
if (result instanceof Scalar && ((Scalar) result).value == 0) {
changed = true;
top.addAttribute("constant");
// Should just be v, but there may be multiple references.
top.removeDependencies();
top.equations.clear();
EquationEntry e = new EquationEntry(top, "");
e.expression = new Constant(0);
top.add(e);
}
}
// And fall through to case 2. If top is immediately v.derivative, then it will be detached in this iteration.
break;
}
// 2) Check if derivative is constant zero.
if (!v.derivative.hasAttribute("constant"))
continue;
EquationEntry e = v.derivative.equations.first();
if (!((Constant) e.expression).value.isZero())
continue;
changed = true;
v.removeDependencyOn(v.derivative);
v.derivative = null;
if (v.equations.isEmpty()) {
// $t, $t', $index an $type are also added without equations.
if (v.name.equals("$t") && v.order < 2)
continue;
v.addAttribute("constant");
e = new EquationEntry(v, "");
e.expression = new Constant(0);
v.add(e);
// Already determined that v is constant, so done with it.
continue;
}
// v is now effectively an ordinary variable (no derivative) with equation(s), so fall through ...
}
if (v.equations.size() != 1) {
if (// Special cases for $variables
v.equations.isEmpty()) {
if (v.name.equals("$index")) {
// Check if $n has become constant 1, that is, if we have detected a singleton in later processing.
// In this case, $index should become constant 0.
Variable n = find(new Variable("$n"));
if (n != null && n.hasAttribute("constant")) {
if (n.equations.first().expression.getDouble() == 1) {
changed = true;
v.removeAttribute("initOnly");
v.addAttribute("constant");
v.unit = AbstractUnit.ONE;
v.equations = new TreeSet<EquationEntry>();
EquationEntry e = new EquationEntry(v, "");
e.expression = new Constant(0);
e.expression.unit = AbstractUnit.ONE;
v.add(e);
}
}
} else if (// $t'
v.name.equals("$t") && v.order == 1 && container != null) {
// Copy constant $t' from container.
Variable parentDt = container.find(v);
if (parentDt.hasAttribute("constant")) {
changed = true;
v.addAttribute("constant");
EquationEntry e = new EquationEntry(v, "");
v.add(e);
EquationEntry parentE = parentDt.equations.first();
e.expression = new Constant(parentE.expression.getDouble());
e.expression.unit = AbstractUnit.ONE;
}
}
}
continue;
}
// At this point, the variable satisfies most of the requirements to be constant.
// It has no external writers or derivatives, so only its single equation can change it.
// The remaining question is whether the equation is an unconditional constant.
EquationEntry e = v.equations.first();
// Notice that a constant equation conditioned on $init is effectively unconditional.
if (e.condition != null && !e.ifString.equals("$init"))
continue;
if (e.expression instanceof Constant) {
changed = true;
v.addAttribute("constant");
// in case it was $init
e.condition = null;
e.ifString = "";
}
}
for (EquationSet s : parts) {
if (s.findConstantsEval())
changed = true;
}
return changed;
}
use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class EquationSet method resolveConnectionBindings.
/**
* Scan for equations that look and smell like connection bindings.
* A binding equation has these characteristics:
* <ul>
* <li>Only one equation on the variable.
* <li>Unconditional (conditional bindings are not permitted)
* <li>No operators, only a name on RHS that appears like a variable name.
* <li>Both LHS and RHS are order 0 (not derivatives)
* <li>No variable in the current equation set matches the name.
* </ul>
* $up is permitted. The explicit name of a higher container may also be used.
* connect() should not appear. It should have been overwritten during construction.
* If connect() does appear, bindings are incomplete, which is an error.
*/
public void resolveConnectionBindings(LinkedList<String> unresolved) throws Exception {
// need to use an iterator here, so we can remove variables from the set
Iterator<Variable> it = variables.iterator();
while (it.hasNext()) {
Variable v = it.next();
// Detect instance variables
AccessVariable av = isConnectionBinding(v);
if (av == null)
continue;
// Resolve connection endpoint to a specific equation set
ConnectionBinding result = new ConnectionBinding();
if (!resolveConnectionBinding(av.name, result)) {
// Only report simple names here, to minimize confusion.
if (!av.name.contains("."))
unresolved.add(v.fullName() + " --> " + av.name);
continue;
}
// Could be a variable or prefix referring to an already-found connection.
if (result.endpoint == null)
continue;
// Store connection binding
if (connectionBindings == null)
connectionBindings = new ArrayList<ConnectionBinding>();
result.alias = v.name;
result.variable = v;
result.index = connectionBindings.size();
connectionBindings.add(result);
result.endpoint.connected = true;
// Prevent variable from interacting with other analysis routines.
v.container = null;
// Should no longer be in the equation list, as there is nothing further to compute.
it.remove();
}
// The population reached in the first descent needs to be tracked.
if (connectionBindings != null) {
for (ConnectionBinding c : connectionBindings) {
int last = c.resolution.size() - 1;
for (int i = 1; i < last; i++) {
Object o0 = c.resolution.get(i - 1);
if (!(o0 instanceof EquationSet))
continue;
Object o1 = c.resolution.get(i);
if (!(o1 instanceof EquationSet))
continue;
Object o2 = c.resolution.get(i + 1);
if (!(o2 instanceof EquationSet))
continue;
EquationSet s0 = (EquationSet) o0;
EquationSet s1 = (EquationSet) o1;
EquationSet s2 = (EquationSet) o2;
if (// double descent
s1.container == s0 && s2.container == s1) {
s1.needInstanceTracking = true;
}
}
}
}
// Descend to child parts after resolving parent. This order is necessary to support nested connections.
for (EquationSet s : parts) {
s.resolveConnectionBindings(unresolved);
}
}
use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class EquationSet method dump.
public String dump(boolean showNamespace, String pad) {
Renderer renderer = new Renderer() {
public boolean render(Operator op) {
if (!(op instanceof AccessVariable))
return false;
AccessVariable av = (AccessVariable) op;
if (av.reference == null || av.reference.variable == null) {
if (showNamespace)
result.append("<unresolved!>");
result.append(av.name);
} else {
if (showNamespace)
result.append("<" + av.reference.variable.container.prefix() + ">");
result.append(av.reference.variable.nameString());
}
return true;
}
};
renderer.result.append(pad + name + "\n");
pad = pad + " ";
if (connectionBindings != null) {
for (ConnectionBinding c : connectionBindings) {
renderer.result.append(pad + c.alias + " = ");
EquationSet s = c.endpoint;
if (showNamespace) {
renderer.result.append("<");
if (s.container != null) {
renderer.result.append(s.container.prefix());
}
renderer.result.append(">");
}
renderer.result.append(s.name + "\n");
}
}
for (Variable v : variables) {
// If no equations, then this is an implicit variable, so no need to list here.
if (v.equations.size() == 0)
continue;
// Phase indicators are always present, and thus uninformative.
if (v.name.equals("$connect") || v.name.equals("$init") || v.name.equals("$live"))
continue;
renderer.result.append(pad + v.nameString());
renderer.result.append(" =" + v.combinerString());
if (v.equations.size() == 1) {
renderer.result.append(" ");
v.equations.first().render(renderer);
renderer.result.append("\n");
} else {
renderer.result.append("\n");
for (EquationEntry e : v.equations) {
renderer.result.append(pad + " ");
e.render(renderer);
renderer.result.append("\n");
}
}
}
for (EquationSet e : parts) {
renderer.result.append(e.dump(showNamespace, pad));
}
return renderer.result.toString();
}
use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class Variable method convertToGlobal.
/**
* If resolution path starts with a connection, then convert it to a walk through containers instead.
*/
public void convertToGlobal() {
reference.convertToGlobal(this);
visit(new Visitor() {
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
av.reference.convertToGlobal(Variable.this);
return false;
}
return true;
}
});
}
Aggregations