use of gov.sandia.n2a.eqset.EquationSet in project n2a by frothga.
the class XyceBackend method getOutputVariables.
@Override
public ParameterDomain getOutputVariables(MNode model) {
try {
MNode n = (MNode) model;
if (n == null)
return null;
EquationSet s = new EquationSet(n);
if (s.name.length() < 1)
s.name = "Model";
s.resolveLHS();
return s.getOutputParameters();
} catch (Exception error) {
return null;
}
}
use of gov.sandia.n2a.eqset.EquationSet in project n2a by frothga.
the class JobC method generateStatic.
public void generateStatic(final EquationSet s, final StringBuilder result) {
for (EquationSet p : s.parts) generateStatic(p, result);
// Generate static definitions
final BackendDataC bed = (BackendDataC) s.backendData;
class CheckStatic extends Visitor {
public boolean global;
public boolean visit(Operator op) {
if (op instanceof Constant) {
Type m = ((Constant) op).value;
if (m instanceof Matrix) {
Matrix A = (Matrix) m;
int rows = A.rows();
int cols = A.columns();
String matrixName = "Matrix" + matrixNames.size();
matrixNames.put(op, matrixName);
if (rows == 3 && cols == 1)
result.append("Vector3 " + matrixName + " = Matrix<float>");
else
result.append("Matrix<float> " + matrixName);
result.append(" (\"" + A + "\");\n");
}
// Don't try to descend tree from here
return false;
}
if (op instanceof Function) {
Function f = (Function) op;
if (// We need to auto-generate the column name.
f instanceof Output && f.operands.length < 3) {
String stringName = "columnName" + stringNames.size();
stringNames.put(op, stringName);
if (global) {
bed.setGlobalNeedPath(s);
bed.globalColumns.add(stringName);
} else {
bed.setLocalNeedPath(s);
bed.localColumns.add(stringName);
}
}
// Detect functions that need static handles
if (f.operands.length > 0) {
Operator operand0 = f.operands[0];
if (operand0 instanceof Constant) {
Constant c = (Constant) operand0;
Type o = c.value;
if (o instanceof Text) {
String fileName = ((Text) o).value;
if (op instanceof ReadMatrix) {
if (!matrixNames.containsKey(fileName)) {
String matrixName = "Matrix" + matrixNames.size();
matrixNames.put(fileName, matrixName);
result.append("MatrixInput * " + matrixName + " = matrixHelper (\"" + fileName + "\");\n");
}
} else if (f instanceof Input) {
if (!inputNames.containsKey(fileName)) {
String inputName = "Input" + inputNames.size();
inputNames.put(fileName, inputName);
result.append("InputHolder * " + inputName + " = inputHelper (\"" + fileName + "\");\n");
}
} else if (f instanceof Output) {
if (!outputNames.containsKey(fileName)) {
String outputName = "Output" + outputNames.size();
outputNames.put(fileName, outputName);
result.append("OutputHolder * " + outputName + " = outputHelper (\"" + fileName + "\");\n");
}
}
}
} else // Dynamic file name (no static handle)
{
if (f instanceof ReadMatrix) {
matrixNames.put(op, "Matrix" + matrixNames.size());
stringNames.put(operand0, "fileName" + stringNames.size());
} else if (f instanceof Input) {
inputNames.put(op, "Input" + inputNames.size());
stringNames.put(operand0, "fileName" + stringNames.size());
} else if (f instanceof Output) {
outputNames.put(op, "Output" + outputNames.size());
stringNames.put(operand0, "fileName" + stringNames.size());
}
}
}
// Functions could be nested, so continue descent.
return true;
}
return true;
}
}
CheckStatic checkStatic = new CheckStatic();
for (Variable v : s.ordered) {
checkStatic.global = v.hasAttribute("global");
v.visit(checkStatic);
}
}
use of gov.sandia.n2a.eqset.EquationSet in project n2a by frothga.
the class InternalBackendData method analyzeEvents.
public static void analyzeEvents(final EquationSet s, final List<EventTarget> eventTargets, final List<Variable> eventReferences) {
class EventVisitor extends Visitor {
public boolean found;
public boolean visit(Operator op) {
if (op instanceof Event) {
found = true;
Event de = (Event) op;
if (// this event has not yet been analyzed
de.eventType == null) {
final EventTarget et = new EventTarget(de);
int targetIndex = eventTargets.indexOf(et);
if (// event target already exists
targetIndex >= 0) {
de.eventType = eventTargets.get(targetIndex);
} else // we must create a new event target, or more properly, fill in the event target we just used as a query object
{
// Create an entry and save the index
targetIndex = eventTargets.size();
eventTargets.add(et);
de.eventType = et;
et.container = s;
// Determine edge type
if (de.operands.length < 3) {
et.edge = EventTarget.RISE;
} else if (de.operands[2] instanceof Constant) {
Constant c = (Constant) de.operands[2];
if (c.value instanceof Text) {
Text t = (Text) c.value;
if (t.value.equalsIgnoreCase("nonzero"))
et.edge = EventTarget.NONZERO;
else if (t.value.equalsIgnoreCase("change"))
et.edge = EventTarget.CHANGE;
else if (t.value.equalsIgnoreCase("fall"))
et.edge = EventTarget.FALL;
else
et.edge = EventTarget.RISE;
} else {
Backend.err.get().println("ERROR: event() edge type must be a string.");
throw new Backend.AbortRun();
}
} else {
Backend.err.get().println("ERROR: event() edge type must be constant.");
throw new Backend.AbortRun();
}
// Allocate auxiliary variable
if (de.operands[0] instanceof AccessVariable) {
AccessVariable av = (AccessVariable) de.operands[0];
VariableReference reference = av.reference;
Variable v = reference.variable;
// then the user has broken the rule that we can't see temporaries in other parts.
if (v.hasAttribute("temporary") && v.container != s) {
Backend.err.get().println("WARNING: Cannot be temporary due to event monitor: " + v.container.name + "." + v.nameString() + " from " + s.name);
v.removeAttribute("temporary");
}
// so fall through to the !trackOne case below.
if (!v.hasAttribute("temporary")) {
// ensure it's buffered, so we can detect change
v.addAttribute("externalRead");
et.trackOne = true;
// just a holder for the reference
et.track = new Variable();
et.track.reference = reference;
}
}
if (// Expression, so create auxiliary variable. Aux not needed for NONZERO, because no change detection.
!et.trackOne && et.edge != EventTarget.NONZERO) {
et.track = new Variable("eventAux" + targetIndex, 0);
et.track.type = new Scalar(0);
et.track.reference = new VariableReference();
et.track.reference.variable = et.track;
}
// Locate any temporaries for evaluation. TODO: for more efficiency, we could have separate lists of temporaries for the condition and delay operands
// Tie into the dependency graph using a phantom variable (which can go away afterward without damaging the graph).
final Variable phantom = new Variable("event");
phantom.uses = new IdentityHashMap<Variable, Integer>();
for (int i = 0; i < et.event.operands.length; i++) et.event.operands[i].visit(new Visitor() {
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable v = av.reference.variable;
if (!phantom.uses.containsKey(v))
phantom.uses.put(v, 1);
return false;
}
return true;
}
});
// Scan all variables in equation set to see if we need them
for (Variable t : s.variables) {
if (t.hasAttribute("temporary") && phantom.dependsOn(t) != null)
et.dependencies.add(t);
}
// Note the default is already set to -1 (no care)
class DelayVisitor extends Visitor {
TreeSet<EquationSet> containers = new TreeSet<EquationSet>();
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
// could include the target part itself, if in fact we use local variables
containers.add(av.reference.variable.container);
return false;
}
return true;
}
}
DelayVisitor dv = new DelayVisitor();
if (de.operands.length >= 2) {
if (de.operands[1] instanceof Constant) {
Constant c = (Constant) de.operands[1];
et.delay = (float) ((Scalar) c.value).value;
if (et.delay < 0)
et.delay = -1;
} else {
// indicates that we need to evaluate delay at run time
et.delay = -2;
de.operands[1].visit(dv);
}
}
// Set up monitors in source parts
class ConditionVisitor extends Visitor {
TreeSet<EquationSet> containers = new TreeSet<EquationSet>();
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable v = av.reference.variable;
EquationSet sourceContainer = v.container;
containers.add(sourceContainer);
// Set up monitors for values that can vary during update.
if (!v.hasAttribute("constant") && !v.hasAttribute("initOnly") && !et.monitors(sourceContainer)) {
EventSource es = new EventSource(sourceContainer, et);
// null means self-reference, a special case handled in Part
if (sourceContainer != s)
es.reference = av.reference;
et.sources.add(es);
}
return false;
}
return true;
}
}
ConditionVisitor cv = new ConditionVisitor();
de.operands[0].visit(cv);
// Special case for event with no references that vary
if (et.sources.isEmpty()) {
// We can avoid creating a self monitor if we know for certain that the event will never fire
boolean neverFires = false;
if (de.operands[0] instanceof Constant) {
if (et.edge == EventTarget.NONZERO) {
Type op0 = ((Constant) de.operands[0]).value;
if (op0 instanceof Scalar) {
neverFires = ((Scalar) op0).value == 0;
} else {
Backend.err.get().println("ERROR: Condition for event() must resolve to a number.");
throw new Backend.AbortRun();
}
} else {
neverFires = true;
}
}
if (!neverFires) {
EventSource es = new EventSource(s, et);
// This is a self-reference, so es.reference should be null.
et.sources.add(es);
}
}
// Determine if monitor needs to test every target, or if one representative target is sufficient
for (EventSource source : et.sources) {
// associated with any given source instance, so every target must be evaluated separately.
if (cv.containers.size() > 1)
source.testEach = true;
if (dv.containers.size() > 1 || (dv.containers.size() == 1 && dv.containers.first() != source.container))
source.delayEach = true;
}
}
}
}
return true;
}
}
EventVisitor eventVisitor = new EventVisitor();
for (Variable v : s.variables) {
eventVisitor.found = false;
v.visit(eventVisitor);
if ((eventVisitor.found || v.dependsOnEvent()) && v.reference.variable != v)
eventReferences.add(v);
}
}
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 ChangePart method apply.
public void apply(String nameBefore, String nameAfter) {
NodePart parent = (NodePart) NodeBase.locateNode(path);
if (parent == null)
throw new CannotRedoException();
NodeBase temp = parent.child(nameBefore);
if (!(temp instanceof NodePart))
throw new CannotRedoException();
NodePart nodeBefore = (NodePart) temp;
// Update the database
// Move the subtree
MPart mparent = parent.source;
mparent.clear(nameBefore);
mparent.set(savedTree, nameAfter);
MPart oldPart = (MPart) mparent.child(nameBefore);
MPart newPart = (MPart) mparent.child(nameAfter);
// Change connection bindings to this part.
// See ChangeVariable.apply() for a similar procedure. More detailed comments appear there.
// We make use of static functions in that class to do the heavy work of emitting code with name changes.
// TODO: This approach will probably fail on parts that contain references to themselves.
PanelEquations pe = PanelModel.instance.panelEquations;
List<List<String>> references = new ArrayList<List<String>>();
try {
MPart doc = pe.root.source;
EquationSet compiled = new EquationSet(doc);
List<String> keypath = new ArrayList<String>(path.subList(1, path.size()));
EquationSet eold;
EquationSet enew;
if (oldPart == null) {
EquationSet p = (EquationSet) compiled.getObject(keypath);
eold = new EquationSet(p, nameBefore);
p.parts.add(eold);
keypath.add(nameAfter);
} else {
keypath.add(nameBefore);
eold = (EquationSet) compiled.getObject(keypath);
keypath.set(keypath.size() - 1, nameAfter);
}
enew = (EquationSet) compiled.getObject(keypath);
try {
compiled.resolveConnectionBindings();
} catch (Exception e) {
}
try {
compiled.resolveLHS();
compiled.resolveRHS();
} catch (Exception e) {
}
ChangeVariable.prepareConnections(compiled);
// Collect variables that might have changed.
List<Variable> users = collectVariables(compiled, eold);
if (eold.dependentConnections != null) {
// The variable associated with such a connection binding could explicitly mention the part name.
for (ConnectionBinding cb : eold.dependentConnections) users.add(cb.variable);
}
eold.name = enew.name;
for (Variable v : users) {
List<String> ref = v.getKeyPath();
MNode n = doc.child(ref.toArray());
String oldKey = n.key();
String newKey = ChangeVariable.changeReferences(eold, n, v);
if (// Handle a change in variable name.
!newKey.equals(oldKey)) {
NodeBase nb = pe.root.locateNodeFromHere(ref);
n.parent().move(oldKey, newKey);
ref.set(ref.size() - 1, newKey);
nb.source = (MPart) doc.child(ref.toArray());
}
// Queue GUI updates for nodes other than the primary ones.
if (v.container != enew && v.container != eold)
references.add(ref);
}
} catch (Exception e) {
}
// Change pin links to this part.
// Scan peer parts (which is the only place a pin link can be declared) and check for "bind" keys that reference nameBefore.
// for updating GUI later
Map<NodePart, List<String>> rebind = new HashMap<NodePart, List<String>>();
Enumeration<?> siblings = parent.children();
while (siblings.hasMoreElements()) {
Object o = siblings.nextElement();
if (!(o instanceof NodePart))
continue;
NodePart sibling = (NodePart) o;
MNode pins;
if (// because the old source is no longer attached to document
sibling == nodeBefore)
// because the old source is no longer attached to document
pins = parent.source.child(nameAfter, "$metadata", "gui", "pin", "in");
else
pins = sibling.source.child("$metadata", "gui", "pin", "in");
if (pins == null)
continue;
List<String> bound = null;
for (MNode pin : pins) {
if (pin.get("bind").equals(nameBefore)) {
pin.set(nameAfter, "bind");
// Also set the new name in collated pin data.
sibling.pinIn.set(nameAfter, pin.key(), "bind");
if (bound == null)
bound = new ArrayList<String>();
bound.add(pin.key());
}
}
if (bound != null)
rebind.put(sibling, bound);
}
// Check parent for pin exports.
MNode pins = parent.source.child("$metadata", "gui", "pin", "out");
if (pins != null) {
List<String> bound = null;
for (MNode pin : pins) {
if (pin.get("bind").equals(nameBefore)) {
pin.set(nameAfter, "bind");
if (bound == null)
bound = new ArrayList<String>();
bound.add(pin.key());
}
}
if (bound != null)
rebind.put(parent, bound);
}
// Update GUI
boolean graphParent = parent == pe.part;
PanelEquationTree pet = graphParent ? null : parent.getTree();
FilteredTreeModel model = null;
if (pet != null)
model = (FilteredTreeModel) pet.tree.getModel();
// Only used if graphParent is true.
PanelEquationGraph peg = pe.panelEquationGraph;
// It's either a NodePart or it's null. Any other case should be blocked by GUI constraints.
NodePart nodeAfter = (NodePart) parent.child(nameAfter);
boolean addGraphNode = false;
if (// Only one node will remain when we are done.
oldPart == null) {
pe.renameFocus(nodeBefore.getKeyPath(), nameAfter);
if (// This is a simple rename, with no restructuring. Keep nodeBefore.
nodeAfter == null) {
nodeAfter = nodeBefore;
nodeAfter.source = newPart;
if (graphParent)
peg.updatePart(nodeAfter);
} else // Use existing nodeAfter, so get rid of nodeBefore.
{
if (model == null)
FilteredTreeModel.removeNodeFromParentStatic(nodeBefore);
else
model.removeNodeFromParent(nodeBefore);
if (graphParent)
peg.removePart(nodeBefore, true);
}
} else // Need two nodes
{
if (// Need a node to hold the new part.
nodeAfter == null) {
int index = parent.getIndex(nodeBefore);
nodeAfter = new NodePart(newPart);
nodeAfter.hide = graphParent;
if (model == null)
FilteredTreeModel.insertNodeIntoUnfilteredStatic(nodeAfter, parent, index);
else
model.insertNodeIntoUnfiltered(nodeAfter, parent, index);
addGraphNode = true;
}
nodeBefore.build();
nodeBefore.findConnections();
nodeBefore.rebuildPins();
nodeBefore.filter();
if (nodeBefore.visible()) {
if (// Need to update entire model under fake root.
graphParent) {
PanelEquationTree subpet = nodeBefore.getTree();
if (subpet != null) {
FilteredTreeModel submodel = (FilteredTreeModel) subpet.tree.getModel();
submodel.nodeStructureChanged(nodeBefore);
subpet.animate();
}
} else if (model != null) {
model.nodeStructureChanged(nodeBefore);
}
} else {
parent.hide(nodeBefore, model);
}
}
nodeAfter.build();
if (graphParent)
parent.findConnections();
else
nodeAfter.findConnections();
nodeAfter.rebuildPins();
nodeAfter.filter();
pe.resetBreadcrumbs();
TreeNode[] nodePath = nodeAfter.getPath();
Set<PanelEquationTree> needAnimate = new HashSet<PanelEquationTree>();
if (pet == null) {
PanelEquationTree.updateOrder(null, nodePath);
PanelEquationTree.updateVisibility(null, nodePath, -2, false);
} else {
pet.updateOrder(nodePath);
// Will include nodeStructureChanged(), if necessary.
pet.updateVisibility(nodePath);
needAnimate.add(pet);
}
for (List<String> ref : references) {
NodeVariable n = (NodeVariable) pe.root.locateNodeFromHere(ref);
if (n == null)
continue;
// Rebuild n, because equations and/or their conditions may have changed.
n.build();
n.findConnections();
n.filter();
if (// n's visibility won't change
n.visible()) {
PanelEquationTree subpet = n.getTree();
if (subpet == null)
continue;
JTree subtree = subpet.tree;
FilteredTreeModel submodel = (FilteredTreeModel) subtree.getModel();
NodeBase subparent = (NodeBase) n.getParent();
// Node will collapse if it was open. Don't worry about this.
submodel.nodeStructureChanged(n);
subparent.invalidateColumns(submodel);
needAnimate.add(subpet);
}
}
for (NodePart peer : rebind.keySet()) {
PanelEquationTree subpet = peer.getTree();
// also works for parent
NodeBase metadata = peer.child("$metadata");
for (String pinKey : rebind.get(peer)) {
// Retrieve GUI metadata node so it can be updated to match DB.
NodeBase nodeBind;
if (peer == parent)
nodeBind = (NodeAnnotation) AddAnnotation.findExact(metadata, false, "gui", "pin", "out", pinKey, "bind");
else
nodeBind = (NodeAnnotation) AddAnnotation.findExact(metadata, false, "gui", "pin", "in", pinKey, "bind");
nodeBind.setUserObject();
// Update display tree.
if (subpet != null) {
// For simplicity, look up subtree, submodel and subparent each time,
// even though they could be done just once per peer part.
JTree subtree = subpet.tree;
FilteredTreeModel submodel = (FilteredTreeModel) subtree.getModel();
NodeBase subparent = (NodeBase) nodeBind.getParent();
submodel.nodeChanged(nodeBind);
subparent.invalidateColumns(submodel);
needAnimate.add(subpet);
}
}
}
for (PanelEquationTree ap : needAnimate) ap.animate();
if (graphParent) {
if (addGraphNode) {
// builds tree
peg.addPart(nodeAfter);
} else {
PanelEquationTree subpet = nodeAfter.getTree();
if (subpet != null) {
FilteredTreeModel submodel = (FilteredTreeModel) subpet.tree.getModel();
submodel.nodeStructureChanged(nodeAfter);
FocusCacheEntry fce = pe.createFocus(nodeAfter);
if (fce.sp != null)
fce.sp.restore(subpet.tree, false);
subpet.animate();
}
}
nodeAfter.hide = false;
nodeAfter.graph.takeFocusOnTitle();
peg.updatePins();
peg.reconnect();
peg.repaint();
}
}
Aggregations