use of gov.sandia.n2a.db.MNode in project n2a by frothga.
the class ImportJob method spikingSynapse.
/**
* Create a spike generator, which may be associated with its intended synapse.
*/
public void spikingSynapse(Node node) {
String id = getAttribute(node, "id");
String synapse = getAttribute(node, "synapse");
// "spikeTarget" appears to be redundant with "synapse". Probably exists due to some oddity in LEMS.
MNode part = models.childOrCreate(modelName, id);
String inherit = node.getNodeName();
NameMap nameMap = partMap.importMap(inherit);
inherit = nameMap.internal;
if (!inherit.isEmpty()) {
part.set("$inherit", inherit);
addDependency(part, inherit);
}
// "spikeArray" does not have an associated synapse.
if (!synapse.isEmpty())
part.set("$metadata", "backend.lems.synapse", synapse);
addAttributes(node, part, nameMap, "id", "synapse", "spikeTarget");
Map<Double, String> sorted = new TreeMap<Double, String>();
for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals("spike")) {
String time = biophysicalUnits(getAttribute(child, "time"));
sorted.put(Scalar.convert(time), time);
}
}
if (// generate spikeArray-like code
sorted.size() > 0) {
String times = "";
for (String s : sorted.values()) times += ";" + s;
// This shuts down spiking after last specified time.
times += ";∞";
times = "[" + times.substring(1) + "]";
part.set("times", times);
}
}
use of gov.sandia.n2a.db.MNode in project n2a by frothga.
the class ImportJob method typeFor.
/**
* Converts an element name to an internal part name, if one is available.
*/
public String typeFor(String nodeName, List<MNode> parents) {
String query = "backend.lems.children." + nodeName;
for (MNode parent : parents) {
// TODO: for lookup of direct child, may need to map node name in context of parent.
// This is only necessary if the subpart has a different internal name.
// Assumes single inheritance
String type = parent.get(nodeName, "$inherit").replace("\"", "");
if (!type.isEmpty())
return type;
MNode c = parent.child("$metadata", query);
if (c != null)
return c.getOrDefault(nodeName);
}
return "";
}
use of gov.sandia.n2a.db.MNode in project n2a by frothga.
the class ImportJob method resolve.
public void resolve(MNode dependent) {
dependents.remove(dependent);
boolean isChildrenType = dependent.key().startsWith("backend.lems.children");
boolean isConnect = dependent.get().contains("$connect");
String dependentInherit = dependent.get("$inherit");
// For connections, the part name might be a direct value.
if (dependentInherit.isEmpty())
dependentInherit = dependent.get();
if (dependentInherit.startsWith("$connect")) {
dependentInherit = dependentInherit.replace("$connect(", "");
dependentInherit = dependentInherit.replace(")", "");
}
String[] sourceNames = dependentInherit.split(",");
for (int sourceIndex = 0; sourceIndex < sourceNames.length; sourceIndex++) {
String sourceName = sourceNames[sourceIndex].replace("\"", "");
MNode source = models.child(modelName, sourceName);
if (source == null)
continue;
// Ensure that the source part has no unresolved dependencies of its own before using it.
resolveChildren(source);
boolean proxy;
if (source.child("$proxy") == null) {
proxy = true;
String inherit = source.key();
for (MNode c : source) {
String key = c.key();
if (key.equals("$count"))
continue;
if (key.equals("$connected"))
continue;
if (key.equals("$lems"))
continue;
if (key.equals("$lemsUses"))
continue;
// Inheriting our own name is characteristic of being a proxy.
if (key.equals("$inherit") && c.get().replace("\"", "").equals(inherit))
continue;
// key is something other than our temporary special keys, so not shallow
proxy = false;
break;
}
if (proxy) {
// proxies only have single inheritance
source.set("$inherit", "\"" + inherit + "\"");
MNode parent = AppData.models.child(inherit);
if (parent == null) {
source.set("$proxy", "1");
} else {
source.set("$proxy", "found");
String id = parent.get("$metadata", "id");
if (!id.isEmpty())
source.set("$inherit", "0", id);
}
} else {
source.set("$proxy", "0");
}
} else {
proxy = !source.get("$proxy").equals("0");
}
// Triage
// -1 == source has exactly one user. Merge and delete immediately.
// -2 == source is lightweight, but has multiple users. Merge and wait to delete.
// -3 == source is heavyweight. Keep reference and move out to independent model.
// -4 == source is the endpoint of a connection. Leave in place.
// Note that a "lightweight" part could also be a proxy, in which case it is an external reference.
// A proxy is configured (above) to inherit the external model, so when the part is merged,
// the dependent will end up referring directly to the external model.
int count = source.getInt("$count");
boolean connected = source.child("$connected") != null;
boolean lemsUses = source.child("$lemsUses") != null;
if (// triage is necessary
count > 0) {
if (lemsUses && !proxy) {
// Anything a LEMS component depends on must be even more abstract, and thus should be an independent model.
count = -3;
} else if (connected) {
if (// One dependent, with only one connection target, so OK to embed.
dependent.getOrDefaultInt("$n", "1") == 1 && count == 1)
// One dependent, with only one connection target, so OK to embed.
count = -1;
else
// Otherwise, the source should be separate from the connection part.
count = -4;
} else if (count == 1) {
count = -1;
} else // count > 1 and not connected, so could be moved out to independent model
{
// Criterion: If a part has subparts, then it is heavy-weight and should be moved out.
// A part that merely sets some parameters on an inherited model is lightweight, and should simply be merged everywhere it is used.
boolean heavy = false;
for (MNode s : source) {
if (MPart.isPart(s)) {
heavy = true;
break;
}
}
if (heavy)
count = -3;
else
count = -2;
}
source.set("$count", count);
if (count == -3) {
MNode id = source.childOrCreate("$metadata", "id");
if (id.get().isEmpty())
id.set(AddDoc.generateID());
}
}
if (count == -1 || count == -2) {
if (// Those two node types don't receive part injection, and don't change the name they use to reference the part.
!isChildrenType && !isConnect) {
dependent.set("");
sourceNames[sourceIndex] = source.get("$inherit");
String inherit = "";
for (int i = 0; i < sourceNames.length; i++) inherit += "," + sourceNames[i];
inherit = inherit.substring(1);
if (// This can happen if source is a Cell, which currently lacks a base class since it is merely a container for segments.
inherit.isEmpty()) {
dependent.clear("$inherit");
} else {
dependent.set("$inherit", inherit);
// Assume single-inheritance in sources
dependent.set("$inherit", sourceIndex, source.get("$inherit", "0"));
}
for (MNode n : source) {
String key = n.key();
if (key.equals("$count"))
continue;
if (key.equals("$connected"))
continue;
if (key.equals("$lems"))
continue;
if (key.equals("$lemsUses"))
continue;
if (key.equals("$proxy"))
continue;
// already handled above
if (key.equals("$inherit"))
continue;
MNode c = dependent.child(key);
if (c == null)
dependent.set(key, n);
else
c.mergeUnder(n);
}
if (!proxy)
dependent.set("$metadata", "backend.lems.id", sourceName);
}
if (count == -1)
models.clear(modelName, sourceName);
} else if (count == -3) {
String inherit = modelName + " " + sourceName;
String id = source.get("$metadata", "id");
if (isChildrenType) {
// TODO: Can't store ID under metadata node, but could tack it on the end as a comma-separated value.
dependent.set(inherit);
} else if (isConnect) {
dependent.set("$connect(\"" + inherit + "\")");
// dependent.set ("0", id); // TODO: Store ID with $connect() ?
} else {
sourceNames[sourceIndex] = "\"" + inherit + "\"";
inherit = "";
for (int i = 0; i < sourceNames.length; i++) inherit += "," + sourceNames[i];
dependent.set("$inherit", inherit.substring(1));
dependent.set("$inherit", sourceIndex, id);
}
}
}
}
use of gov.sandia.n2a.db.MNode in project n2a by frothga.
the class ImportJob method simulation.
public void simulation(Node node) {
String id = getAttribute(node, "id");
String length = getAttribute(node, "length");
String step = getAttribute(node, "step");
String target = getAttribute(node, "target");
// redirect, since "Simulation" itself is not a proper object.
if (primaryModel.equals(id))
primaryModel = target;
MNode part = models.childOrCreate(modelName, target);
part.set("$t'", step);
part.set("$p", "$t<" + length);
for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE)
output(child, part);
}
}
use of gov.sandia.n2a.db.MNode in project n2a by frothga.
the class ImportJob method collectParents.
/**
* Locates all the accessible parents of the given node and lists them in ascending
* order by distance from child. That is, most direct ancestor comes first in the list.
* In addition to terminating at the root parent, also terminates when a parent can't
* be found, so the list may be incomplete.
*/
public List<MNode> collectParents(MNode child) {
List<MNode> result = new ArrayList<MNode>();
String childInherit = child.get("$inherit");
String[] inherits = childInherit.split(",");
for (String inherit : inherits) {
inherit = inherit.replace("\"", "");
if (inherit.isEmpty())
continue;
MNode parent = models.child(modelName, inherit);
// Prevent infinite loop on proxies.
if (parent == child)
parent = null;
if (parent == null)
parent = AppData.models.child(inherit);
if (parent == null)
continue;
result.add(parent);
result.addAll(collectParents(parent));
}
return result;
}
Aggregations