use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class InternalBackendData method dumpVariableList.
public void dumpVariableList(String name, List<Variable> list) {
System.out.print(" " + name + ":");
for (Variable v : list) System.out.print(" " + v.nameString());
System.out.println();
}
use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class InternalBackendData method analyzeEvents.
public static void analyzeEvents(EquationSet s, List<EventTarget> eventTargets, List<Variable> eventReferences, List<Delay> delays) {
class EventVisitor implements Visitor {
public boolean found;
public boolean visit(Operator op) {
if (op instanceof Delay) {
delays.add((Delay) op);
} else 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.fullName() + " 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);
et.track.container = s;
et.track.type = new Scalar(0);
et.track.reference = new VariableReference();
et.track.reference.variable = et.track;
// Make executable so it can be directly evaluated during the init cycle.
et.track.equations = new TreeSet<EquationEntry>();
EquationEntry ee = new EquationEntry(et.track, "");
et.track.equations.add(ee);
ee.expression = et.event.operands[0].deepCopy();
ee.expression.addDependencies(et.track);
}
// Locate any temporaries for evaluation.
// Tie into the dependency graph using a phantom variable (which can go away afterward without damaging the graph).
// TODO: for more efficiency, we could have separate lists of temporaries for the condition and delay operands
// TODO: for more efficiency, cut off search for temporaries along a given branch of the tree at the first non-temporary.
final Variable phantom = new Variable("event");
phantom.uses = new IdentityHashMap<Variable, Integer>();
phantom.container = s;
et.event.visit(new Visitor() {
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable v = av.reference.variable;
if (v.hasAttribute("temporary") && !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.ordered) {
if (t.hasAttribute("temporary") && phantom.dependsOn(t) != null)
et.dependencies.add(t);
}
// Note the default is already set to -1 (no care)
class DelayVisitor implements 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 implements 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.Variable in project n2a by frothga.
the class InternalBackendData method analyzeConversions.
public void analyzeConversions(EquationSet s) {
// Type conversions
// forbid $index and all phase variables. TODO: create attributes just for this?
List<String> forbiddenVariables = Arrays.asList("$type", "$index", "$live", "$init", "$connect");
for (EquationSet target : s.getConversionTargets()) {
if (s.connectionBindings == null) {
if (target.connectionBindings != null)
throw new EvaluationException("Can't change $type from compartment to connection.");
} else {
if (target.connectionBindings == null)
throw new EvaluationException("Can't change $type from connection to compartment.");
}
Conversion conversion = new Conversion();
conversions.put(target, conversion);
// Match variables
InternalBackendData targetBed = (InternalBackendData) target.backendData;
for (Variable v : targetBed.localMembers) {
if (forbiddenVariables.contains(v.name))
continue;
// find() does not consider container
Variable v2 = s.find(v);
if (v2 != null) {
conversion.to.add(v);
conversion.from.add(v2);
}
}
// Match connection bindings
if (// Since we checked above, we know that target is also a connection.
s.connectionBindings != null) {
conversion.bindings = new int[s.connectionBindings.size()];
int i = 0;
for (ConnectionBinding c : s.connectionBindings) {
conversion.bindings[i] = -1;
int j = 0;
for (ConnectionBinding d : target.connectionBindings) {
if (c.alias.equals(d.alias)) {
conversion.bindings[i] = j;
break;
}
j++;
}
// Note: ALL bindings must match. There is no other mechanism for initializing the endpoints.
if (conversion.bindings[i] < 0)
throw new EvaluationException("Unfulfilled connection binding during $type change.");
i++;
}
}
// TODO: Match populations?
// Currently, any contained populations do not carry over to new instance. Instead, it must create them from scratch.
}
}
use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class Part method getXYZ.
public double[] getXYZ(Simulator simulator, boolean connect) {
InternalBackendData bed = (InternalBackendData) equations.backendData;
// default is ~[0,0,0]
if (bed.xyz == null)
return new double[3];
// Either "constant" or stored
if (!bed.xyz.hasAttribute("temporary"))
return ((MatrixDense) get(bed.xyz)).getData();
InstanceTemporaries temp;
List<Variable> list;
if (// evaluate in connect phase
connect) {
temp = new InstanceConnect(this, simulator);
list = bed.XYZdependencies;
} else // evaluate in live phase
{
temp = new InstanceTemporaries(this, simulator);
list = bed.XYZdependenciesTemp;
}
for (Variable v : list) {
Type result = v.eval(temp);
if (result == null)
temp.set(v, v.type);
else
temp.set(v, result);
}
Type result = bed.xyz.eval(temp);
if (result == null)
return new double[3];
return ((MatrixDense) result).getData();
}
use of gov.sandia.n2a.eqset.Variable in project n2a by frothga.
the class Part method init.
/**
* Note: specifically for Parts, call resolve() separately before calling init().
* This is to accommodate the connection process, which must probe values in a part
* (which may include references) before calling init().
*/
public void init(Simulator simulator) {
InstanceTemporaries temp = new InstanceInit(this, simulator);
InternalBackendData bed = temp.bed;
// update $n and assign $index
((Population) container.valuesObject[bed.populationIndex]).insert(this);
// Note: these do not require resolve(). Instead, they access their target directly through the endpoints array.
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]]++;
}
}
}
// Initialize variables
// Note that some valuesObject entries could be left null. This is OK, because Instance.get() will return
// a zero-equivalent value if it finds null.
// So our intial values can be applied correctly.
clearExternalWriteInit(bed.localBufferedExternalWrite);
for (Variable v : bed.localInit) {
Type result = v.eval(temp);
if (result == null || v.reference.variable.writeIndex < 0)
continue;
// with its finish() step. It would be as if the part had an extra cycle inserted.
if (v.reference.variable == v)
temp.applyResultInit(v, result);
else
((Instance) valuesObject[v.reference.index]).applyResultInit(v.reference.variable, result);
}
if (bed.liveStorage == InternalBackendData.LIVE_STORED)
set(bed.live, new Scalar(1));
if (bed.lastT != null)
temp.setFinal(bed.lastT, new Scalar(simulator.currentEvent.t));
if (bed.type != null)
temp.setFinal(bed.type, new Scalar(0));
if (bed.setDt)
simulator.move(this, ((Scalar) bed.dt.type).value);
// Prepare variables that have a combiner, in case they get written before the first finish().
// skips REPLACE it because it is unnecessary when called from update(). Handle REPLACE separately ...
clearExternalWriteBuffers(bed.localBufferedExternalWrite);
// This must come after the variables are initialized. Otherwise, there is no point.
for (Variable v : bed.localBufferedExternalWrite) if (v.assignment == Variable.REPLACE)
temp.set(v, temp.get(v));
// Request event monitors
for (EventTarget et : bed.eventTargets) {
for (EventSource es : et.sources) {
Part source;
if (es.reference == null)
source = this;
else
source = (Part) valuesObject[es.reference.index];
@SuppressWarnings("unchecked") ArrayList<Instance> monitors = (ArrayList<Instance>) source.valuesObject[es.monitorIndex];
monitors.add(this);
}
}
if (equations.parts.size() > 0) {
// If there are parts at all, then orderedParts must be filled in correctly. Otherwise it may be null.
for (EquationSet s : equations.orderedParts) ((Population) valuesObject[s.priority]).init(simulator);
}
}
Aggregations