use of gov.sandia.n2a.eqset.EquationSet.ConnectionBinding 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.EquationSet.ConnectionBinding 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;
}
}
use of gov.sandia.n2a.eqset.EquationSet.ConnectionBinding in project n2a by frothga.
the class JobC method resolveContainer.
/**
* Compute a series of pointers to get from current part to r.
* Result does not include the variable name itself.
*/
public String resolveContainer(VariableReference r, RendererC context, String base) {
String containers = base;
EquationSet current = context.part;
boolean global = context.global;
int last = r.resolution.size() - 1;
for (int i = 0; i <= last; i++) {
Object o = r.resolution.get(i);
if (// We are following the containment hierarchy.
o instanceof EquationSet) {
EquationSet s = (EquationSet) o;
if (// descend into one of our contained populations
s.container == current) {
if (// descend to the population object
i == last && r.variable.hasAttribute("global")) {
// No need to cast the population instance, because it is explicitly typed
containers += mangle(s.name) + ".";
global = true;
} else // descend to a singleton instance of the population.
{
BackendDataC bed = (BackendDataC) s.backendData;
if (!bed.singleton) {
Backend.err.get().println("ERROR: Down-reference to population with more than one instance is ambiguous.");
throw new AbortRun();
}
containers += mangle(s.name) + ".instance.";
global = false;
}
} else // ascend to our container
{
containers = containerOf(current, i == 0 && context.global, containers);
global = false;
}
current = s;
} else if (// We are following a part reference (which means we are a connection)
o instanceof ConnectionBinding) {
ConnectionBinding c = (ConnectionBinding) o;
containers += mangle(c.alias) + "->";
current = c.endpoint;
global = false;
}
}
if (r.variable.hasAttribute("global") && !global) {
// Must ascend to our container and then descend to our population object.
containers = containerOf(current, false, containers);
containers += mangle(current.name) + ".";
}
return containers;
}
use of gov.sandia.n2a.eqset.EquationSet.ConnectionBinding in project n2a by frothga.
the class JobC method findPathToContainer.
public void findPathToContainer(EquationSet s) {
for (EquationSet p : s.parts) {
findPathToContainer(p);
}
if (s.connectionBindings != null) {
for (ConnectionBinding c : s.connectionBindings) {
if (c.endpoint.container == s.container) {
BackendDataC bed = (BackendDataC) s.backendData;
bed.pathToContainer = c.alias;
break;
}
}
}
}
use of gov.sandia.n2a.eqset.EquationSet.ConnectionBinding in project n2a by frothga.
the class JobC method assembleInstances.
/**
* Generate code to enumerate all instances of a connection endpoint. Handles deep hierarchical
* embedding.
*
* <p>A connection resolution can take 3 kinds of step:
* <ul>
* <li>Up to container
* <li>Down to a population
* <li>Through another connection
* </ul>
*
* @param current EquationSet associated with the context of the current step of resolution.
* @param pointer Name of a pointer to the context for the current step of resolution. Can
* be a chain of pointers. Can be empty if the code is to be emitted in the current context.
* @param depth Position in the resolution array of our next step.
* @param prefix Spaces to insert in front of each line to maintain nice indenting.
*/
public void assembleInstances(EquationSet current, String pointer, List<Object> resolution, int depth, String prefix, StringBuilder result) {
int last = resolution.size() - 1;
for (int i = depth; i <= last; i++) {
Object r = resolution.get(i);
if (r instanceof EquationSet) {
EquationSet s = (EquationSet) r;
if (// ascend to parent
r == current.container) {
pointer = containerOf(current, i == 0, pointer);
} else // descend to child
{
pointer += mangle(s.name) + ".";
if (// Enumerate the instances of child population.
i < last) {
if (depth == 0) {
result.append(prefix + "result->instances = new vector<Part<" + T + "> *>;\n");
result.append(prefix + "result->deleteInstances = true;\n");
}
String it = "it" + i;
result.append(prefix + "for (auto " + it + " : " + pointer + "instances)\n");
result.append(prefix + "{\n");
assembleInstances(s, it + "->", resolution, i + 1, prefix + " ", result);
result.append(prefix + "}\n");
return;
}
}
current = s;
} else if (r instanceof ConnectionBinding) {
ConnectionBinding c = (ConnectionBinding) r;
pointer += mangle(c.alias) + "->";
current = c.endpoint;
}
// else something is broken. This case should never occur.
}
// "pointer" now references the target population.
// Collect its instances.
BackendDataC bed = (BackendDataC) current.backendData;
if (bed.singleton) {
result.append(prefix + "bool newborn = " + pointer + "instance.flags & (" + bed.localFlagType + ") 0x1 << " + bed.newborn + ";\n");
if (depth == 0) {
result.append(prefix + "result->instances = new vector<Part<" + T + "> *>;\n");
result.append(prefix + "result->deleteInstances = true;\n");
}
result.append(prefix + "if (result->firstborn == INT_MAX && newborn) result->firstborn = result->instances->size ();\n");
result.append(prefix + "result->instances->push_back (& " + pointer + "instance);\n");
} else {
if (// No enumerations occurred during the resolution, so no list was created.
depth == 0) {
// Simply reference the existing list of instances.
result.append(prefix + "result->firstborn = " + pointer + "firstborn;\n");
result.append(prefix + "result->instances = (vector<Part<" + T + "> *> *) & " + pointer + "instances;\n");
} else // Enumerations occurred, so we are already accumulating a list.
{
// Append instances to accumulating list.
result.append(prefix + "if (result->firstborn == INT_MAX && " + pointer + "firstborn < " + pointer + "instances.size ()) result->firstborn = result->instances->size () + " + pointer + "firstborn;\n");
result.append(prefix + "result->instances->insert (result->instances->end (), " + pointer + "instances.begin (), " + pointer + "instances.end ());\n");
}
}
// Schedule the population to have its newborn flags cleared.
// We assume that any newborn flags along the path to this population are either unimportant
// or will get cleared elsewhere.
result.append(prefix + "if (! (" + pointer + "flags & (" + bed.globalFlagType + ") 0x1 << " + bed.clearNew + "))\n");
result.append(prefix + "{\n");
result.append(prefix + " " + pointer + "flags |= (" + bed.globalFlagType + ") 0x1 << " + bed.clearNew + ";\n");
pointer = stripDereference(pointer);
if (pointer.isEmpty())
pointer = "this";
else
pointer = "& " + pointer;
result.append(prefix + " Simulator<" + T + ">::instance.clearNew (" + pointer + ");\n");
result.append(prefix + "}\n");
}
Aggregations