use of gov.sandia.n2a.eqset.EquationSet 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 in project n2a by frothga.
the class BackendDataC method setLocalNeedPath.
public void setLocalNeedPath(EquationSet s) {
EquationSet c = s.container;
// Don't set flag, because we know that path() will return "".
if (c == null && s.isSingleton(false))
return;
needLocalPath = true;
setParentNeedPath(s);
}
use of gov.sandia.n2a.eqset.EquationSet 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 in project n2a by frothga.
the class JobC method analyzeEvents.
public void analyzeEvents(EquationSet s) throws Backend.AbortRun {
BackendDataC bed = (BackendDataC) s.backendData;
bed.analyzeEvents(s);
for (EquationSet p : s.parts) analyzeEvents(p);
}
use of gov.sandia.n2a.eqset.EquationSet in project n2a by frothga.
the class JobC method run.
public void run() {
localJobDir = Host.getJobDir(Host.getLocalResourceDir(), job);
Path errPath = localJobDir.resolve("err");
try {
Backend.err.set(new PrintStream(new FileOutputStream(errPath.toFile(), true), false, "UTF-8"));
} catch (Exception e) {
}
try {
Files.createFile(localJobDir.resolve("started"));
MNode model = NodeJob.getModel(job);
T = model.getOrDefault("float", "$metadata", "backend", "c", "type");
if (T.startsWith("int") && T.length() > 3) {
T = "int";
Backend.err.get().println("WARNING: Only supported integer type is 'int', which is assumed to be signed 32-bit.");
}
if (!T.equals("int") && !T.equals("double") && !T.equals("float")) {
T = "float";
Backend.err.get().println("WARNING: Unsupported numeric type. Defaulting to single-precision float.");
}
kokkos = model.getFlag("$metadata", "backend", "c", "kokkos");
gprof = model.getFlag("$metadata", "backend", "c", "gprof");
cli = model.getFlag("$metadata", "backend", "c", "cli");
String e = model.get("$metadata", "backend", "all", "event");
switch(e) {
case "before":
during = false;
after = false;
break;
case "after":
during = false;
after = true;
default:
// during
during = true;
after = false;
}
env = Host.get(job);
Path resourceDir = env.getResourceDir();
// Unlike localJobDir (which is created by MDir), this may not exist until we explicitly create it.
jobDir = Host.getJobDir(resourceDir, job);
// No good way to decide absolute path for the default value. Maybe need to call "which" command for this.
gcc = resourceDir.getFileSystem().getPath(env.config.getOrDefault("g++", "backend", "c", "cxx"));
runtimeDir = resourceDir.resolve("backend").resolve("c");
rebuildRuntime();
// digestModel() might write to a remote file (params), so we need to ensure the dir exists first.
Files.createDirectories(jobDir);
digestedModel = new EquationSet(model);
digestModel();
String duration = digestedModel.metadata.get("duration");
if (!duration.isEmpty())
job.set(duration, "duration");
seed = -1;
if (// only record seed if actually used
digestedModel.usesRandom()) {
seed = model.getOrDefault(System.currentTimeMillis() & 0xFFFFFFFFL, "$metadata", "seed");
job.set(seed, "seed");
}
System.out.println(digestedModel.dump(false));
Path source = jobDir.resolve("model.cc");
generateCode(source);
String command = env.quote(build(source));
// The C program could append to the same error file, so we need to close the file before submitting.
PrintStream ps = Backend.err.get();
if (ps != System.err) {
ps.close();
Backend.err.remove();
job.set(Host.size(errPath), "errSize");
}
env.submitJob(job, false, command);
} catch (Exception e) {
if (!(e instanceof AbortRun))
e.printStackTrace(Backend.err.get());
try {
Files.copy(new ByteArrayInputStream("failure".getBytes("UTF-8")), localJobDir.resolve("finished"));
} catch (Exception f) {
}
}
// If an exception occurred, the error file will still be open.
PrintStream ps = Backend.err.get();
if (ps != System.err)
ps.close();
}
Aggregations