Search in sources :

Example 26 with AccessVariable

use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.

the class EquationSet method fillAutoPins.

/**
 *        If this part exposes an auto pin, then duplicate the dependent sub-parts for each bound input.
 *        Finally, this function recurses into all child parts, whether or not they are the result of duplication.
 *        The duplication takes place only at the EquationSet level. The corresponding source field is
 *        simply a reference to the original source. This is slightly inconsistent with the contents
 *        of the resulting EquationSet objects. For example, the key of the source will not match the name
 *        of the EquationSet. If this breaks any middle-end code, then we can create a fake
 *        source, or even update the true source. In the last case, it would be necessary for the true
 *        source to be volatile, so the database record is not changed.
 *        Depends on: collectPins()
 */
public void fillAutoPins() {
    for (MNode autopin : pinIn) {
        String pinName = autopin.key();
        if (!pinName.endsWith("#"))
            continue;
        // Found an auto pin; now process it ...
        int length = pinName.length() - 1;
        String pinBase = pinName.substring(0, length);
        // Scan for instances
        // These only exist in the part's original metadata, since they are not backed by actual sub-parts.
        // automatically sorted, which is useful for iteration below
        TreeSet<Integer> instances = new TreeSet<Integer>();
        for (MNode pin2 : metadata.childOrEmpty("gui", "pin", "in")) {
            String pinBaseI = pin2.key();
            if (!pinBaseI.startsWith(pinBase))
                continue;
            // remove prefix
            String suffix = pinBaseI.substring(length);
            // The suffix must be a proper integer.
            try {
                int index = Integer.parseInt(suffix);
                if (index > 0)
                    instances.add(index);
            } catch (NumberFormatException e) {
            }
        }
        int lastIndex = 0;
        if (!instances.isEmpty())
            lastIndex = instances.last();
        // Collect destination parts for connections
        Map<String, EquationSet> Bparts = new HashMap<String, EquationSet>();
        for (MNode subscriber : autopin) {
            String baseName = subscriber.key();
            EquationSet template = findPart(baseName);
            if (template.connectionBindings == null)
                continue;
            MNode templatePin = template.metadata.child("gui", "pin");
            // assigned by collectPins()
            String Aname = templatePin.get("alias");
            // This is a compact form of the same code in resolveConnectionBindings()
            for (Variable v : template.variables) {
                if (v.name.equals(Aname))
                    continue;
                AccessVariable av = template.isConnectionBinding(v);
                if (av == null)
                    continue;
                ConnectionBinding cb = new ConnectionBinding();
                if (!template.resolveConnectionBinding(av.name, cb))
                    continue;
                if (cb.endpoint == null)
                    continue;
                Bparts.put(baseName, cb.endpoint);
                // for an alias, v.name is sufficient
                templatePin.set(v.name, "aliasB");
                break;
            }
        }
        // Process each instance
        // previous index; zero is never a suffix, so this is sufficient to indicate none (start of list)
        int previous = 0;
        for (int index : instances) {
            String pinBaseI = pinBase + index;
            // Duplicate each subscriber
            for (MNode subscriber : autopin) {
                String baseName = subscriber.key();
                EquationSet template = findPart(baseName);
                EquationSet duplicate = new EquationSet(this, baseName + index);
                parts.add(duplicate);
                duplicate.copyPinTemplate(template);
                duplicate.override("autoIndex=" + index);
                duplicate.override("autoCount=" + lastIndex);
                MNode templatePin = template.metadata.child("gui", "pin");
                if (// connectionBindings got preliminary setting from collectPins()
                template.connectionBindings != null) {
                    MNode append = templatePin.child("append");
                    String autoBase = templatePin.getOrDefault("0", "append");
                    EquationSet Bpart = Bparts.get(baseName);
                    if (Bpart == null) {
                        // In that case, fake the autoBase in the duplicated part itself.
                        if (append != null)
                            duplicate.override("autoBase=" + autoBase);
                    } else {
                        // assigned by collectPins()
                        String Aname = templatePin.get("alias");
                        // assigned above
                        String Bname = templatePin.get("aliasB");
                        if (append != null) {
                            duplicate.override("autoBase=:" + Bname + ".autoBase" + index);
                            duplicate.override("$all." + Bname + ".autoN" + index + "=" + Aname + ".$n");
                        }
                        // Set variables in B part
                        if (append != null) {
                            if (previous == 0)
                                Bpart.override("$all.autoBase" + index + "=" + autoBase);
                            else
                                Bpart.override("$all.autoBase" + index + "=autoBase" + previous + "+autoN" + previous);
                            previous = index;
                            if (index == lastIndex) {
                                String n = Bpart.source.get("$n");
                                if (n.isEmpty() || n.startsWith("autoBase"))
                                    Bpart.override("$n=autoBase" + index + "+autoN" + index);
                            }
                        }
                    }
                }
                // connections
                if (// must match the auto-pin name
                templatePin.get().equals(pinName)) {
                    duplicate.metadata.set(pinBaseI, "gui", "pin");
                }
                // parts that forward inputs
                for (MNode b : templatePin.childOrEmpty("in")) {
                    if (// must bind to IO block and match the auto-pin name
                    b.get("bind").isEmpty() && b.get("bind", "pin").equals(pinName)) {
                        duplicate.metadata.set(pinBaseI, "gui", "pin", "in", b.key(), "bind", "pin");
                    }
                }
            }
        }
    }
    // model, but is useful for an export routine that understands auto pins.
    for (EquationSet s : parts) s.fillAutoPins();
}
Also used : AccessVariable(gov.sandia.n2a.language.AccessVariable) AccessVariable(gov.sandia.n2a.language.AccessVariable) HashMap(java.util.HashMap) MNode(gov.sandia.n2a.db.MNode) TreeSet(java.util.TreeSet)

Example 27 with AccessVariable

use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.

the class EquationSet method findConstantsEval.

protected boolean findConstantsEval() {
    boolean changed = false;
    for (Variable v : variables) {
        if (v.simplify())
            changed = true;
        // "externalWrite" -- Regardless of the local math, a variable that gets written is not constant.
        if (v.hasAny("constant", "initOnly", "externalWrite"))
            continue;
        if (// A variable with a derivative is usually not constant, with the following exceptions ...
        v.derivative != null) {
            // 1) Check for unconditional constant.
            if (v.equations.size() == 1) {
                EquationEntry e = v.equations.first();
                if (// Must be unconditional. No exception for $init. (Non-integrated variables do get an exception for $init; see below.)
                e.expression instanceof Constant && e.condition == null) {
                    changed = true;
                    v.addAttribute("constant");
                    v.removeDependencyOn(v.derivative);
                    v.derivative = null;
                    continue;
                }
            }
            // 2a) Check for pure circular dependency.
            Variable top = v;
            while (// This single dependency must be the derivative.
            top.uses != null && top.uses.size() == 1) {
                if (top.derivative != null) {
                    top = top.derivative;
                    continue;
                }
                // Its single dependency is not a derivative, but could be anything else.
                if (// This is a pure circular dependency.
                top.uses.containsKey(v)) {
                    // Evaluate top. Initial value of v must be zero, because otherwise it would depend on other variables or be trapped above as an unconditional constant.
                    // We can only make this assumption here.
                    Instance instance = new Instance() {

                        public Scalar zero = new Scalar(0);

                        // all AccessVariable objects will reach here first.
                        public Type get(VariableReference r) throws EvaluationException {
                            return zero;
                        }
                    };
                    Type result = top.eval(instance);
                    if (result instanceof Scalar && ((Scalar) result).value == 0) {
                        changed = true;
                        top.addAttribute("constant");
                        // Should just be v, but there may be multiple references.
                        top.removeDependencies();
                        top.equations.clear();
                        EquationEntry e = new EquationEntry(top, "");
                        e.expression = new Constant(0);
                        top.add(e);
                    }
                }
                // And fall through to case 2. If top is immediately v.derivative, then it will be detached in this iteration.
                break;
            }
            // 2) Check if derivative is constant zero.
            if (!v.derivative.hasAttribute("constant"))
                continue;
            EquationEntry e = v.derivative.equations.first();
            if (!((Constant) e.expression).value.isZero())
                continue;
            changed = true;
            v.removeDependencyOn(v.derivative);
            v.derivative = null;
            if (v.equations.isEmpty()) {
                // $t, $t', $index an $type are also added without equations.
                if (v.name.equals("$t") && v.order < 2)
                    continue;
                v.addAttribute("constant");
                e = new EquationEntry(v, "");
                e.expression = new Constant(0);
                v.add(e);
                // Already determined that v is constant, so done with it.
                continue;
            }
        // v is now effectively an ordinary variable (no derivative) with equation(s), so fall through ...
        }
        if (v.equations.size() != 1) {
            if (// Special cases for $variables
            v.equations.isEmpty()) {
                if (v.name.equals("$index")) {
                    // Check if $n has become constant 1, that is, if we have detected a singleton in later processing.
                    // In this case, $index should become constant 0.
                    Variable n = find(new Variable("$n"));
                    if (n != null && n.hasAttribute("constant")) {
                        if (n.equations.first().expression.getDouble() == 1) {
                            changed = true;
                            v.removeAttribute("initOnly");
                            v.addAttribute("constant");
                            v.unit = AbstractUnit.ONE;
                            v.equations = new TreeSet<EquationEntry>();
                            EquationEntry e = new EquationEntry(v, "");
                            e.expression = new Constant(0);
                            e.expression.unit = AbstractUnit.ONE;
                            v.add(e);
                        }
                    }
                } else if (// $t'
                v.name.equals("$t") && v.order == 1 && container != null) {
                    // Copy constant $t' from container.
                    Variable parentDt = container.find(v);
                    if (parentDt.hasAttribute("constant")) {
                        changed = true;
                        v.addAttribute("constant");
                        EquationEntry e = new EquationEntry(v, "");
                        v.add(e);
                        EquationEntry parentE = parentDt.equations.first();
                        e.expression = new Constant(parentE.expression.getDouble());
                        e.expression.unit = AbstractUnit.ONE;
                    }
                }
            }
            continue;
        }
        // At this point, the variable satisfies most of the requirements to be constant.
        // It has no external writers or derivatives, so only its single equation can change it.
        // The remaining question is whether the equation is an unconditional constant.
        EquationEntry e = v.equations.first();
        // Notice that a constant equation conditioned on $init is effectively unconditional.
        if (e.condition != null && !e.ifString.equals("$init"))
            continue;
        if (e.expression instanceof Constant) {
            changed = true;
            v.addAttribute("constant");
            // in case it was $init
            e.condition = null;
            e.ifString = "";
        }
    }
    for (EquationSet s : parts) {
        if (s.findConstantsEval())
            changed = true;
    }
    return changed;
}
Also used : Type(gov.sandia.n2a.language.Type) AccessVariable(gov.sandia.n2a.language.AccessVariable) Instance(gov.sandia.n2a.language.type.Instance) Constant(gov.sandia.n2a.language.Constant) Scalar(gov.sandia.n2a.language.type.Scalar)

Example 28 with AccessVariable

use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.

the class EquationSet method resolveConnectionBindings.

/**
 *        Scan for equations that look and smell like connection bindings.
 *        A binding equation has these characteristics:
 *        <ul>
 *        <li>Only one equation on the variable.
 *        <li>Unconditional (conditional bindings are not permitted)
 *        <li>No operators, only a name on RHS that appears like a variable name.
 *        <li>Both LHS and RHS are order 0 (not derivatives)
 *        <li>No variable in the current equation set matches the name.
 *        </ul>
 *        $up is permitted. The explicit name of a higher container may also be used.
 *        connect() should not appear. It should have been overwritten during construction.
 *        If connect() does appear, bindings are incomplete, which is an error.
 */
public void resolveConnectionBindings(LinkedList<String> unresolved) throws Exception {
    // need to use an iterator here, so we can remove variables from the set
    Iterator<Variable> it = variables.iterator();
    while (it.hasNext()) {
        Variable v = it.next();
        // Detect instance variables
        AccessVariable av = isConnectionBinding(v);
        if (av == null)
            continue;
        // Resolve connection endpoint to a specific equation set
        ConnectionBinding result = new ConnectionBinding();
        if (!resolveConnectionBinding(av.name, result)) {
            // Only report simple names here, to minimize confusion.
            if (!av.name.contains("."))
                unresolved.add(v.fullName() + " --> " + av.name);
            continue;
        }
        // Could be a variable or prefix referring to an already-found connection.
        if (result.endpoint == null)
            continue;
        // Store connection binding
        if (connectionBindings == null)
            connectionBindings = new ArrayList<ConnectionBinding>();
        result.alias = v.name;
        result.variable = v;
        result.index = connectionBindings.size();
        connectionBindings.add(result);
        result.endpoint.connected = true;
        // Prevent variable from interacting with other analysis routines.
        v.container = null;
        // Should no longer be in the equation list, as there is nothing further to compute.
        it.remove();
    }
    // The population reached in the first descent needs to be tracked.
    if (connectionBindings != null) {
        for (ConnectionBinding c : connectionBindings) {
            int last = c.resolution.size() - 1;
            for (int i = 1; i < last; i++) {
                Object o0 = c.resolution.get(i - 1);
                if (!(o0 instanceof EquationSet))
                    continue;
                Object o1 = c.resolution.get(i);
                if (!(o1 instanceof EquationSet))
                    continue;
                Object o2 = c.resolution.get(i + 1);
                if (!(o2 instanceof EquationSet))
                    continue;
                EquationSet s0 = (EquationSet) o0;
                EquationSet s1 = (EquationSet) o1;
                EquationSet s2 = (EquationSet) o2;
                if (// double descent
                s1.container == s0 && s2.container == s1) {
                    s1.needInstanceTracking = true;
                }
            }
        }
    }
    // Descend to child parts after resolving parent. This order is necessary to support nested connections.
    for (EquationSet s : parts) {
        s.resolveConnectionBindings(unresolved);
    }
}
Also used : AccessVariable(gov.sandia.n2a.language.AccessVariable) AccessVariable(gov.sandia.n2a.language.AccessVariable) ArrayList(java.util.ArrayList)

Example 29 with AccessVariable

use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.

the class EquationSet method dump.

public String dump(boolean showNamespace, String pad) {
    Renderer renderer = new Renderer() {

        public boolean render(Operator op) {
            if (!(op instanceof AccessVariable))
                return false;
            AccessVariable av = (AccessVariable) op;
            if (av.reference == null || av.reference.variable == null) {
                if (showNamespace)
                    result.append("<unresolved!>");
                result.append(av.name);
            } else {
                if (showNamespace)
                    result.append("<" + av.reference.variable.container.prefix() + ">");
                result.append(av.reference.variable.nameString());
            }
            return true;
        }
    };
    renderer.result.append(pad + name + "\n");
    pad = pad + " ";
    if (connectionBindings != null) {
        for (ConnectionBinding c : connectionBindings) {
            renderer.result.append(pad + c.alias + " = ");
            EquationSet s = c.endpoint;
            if (showNamespace) {
                renderer.result.append("<");
                if (s.container != null) {
                    renderer.result.append(s.container.prefix());
                }
                renderer.result.append(">");
            }
            renderer.result.append(s.name + "\n");
        }
    }
    for (Variable v : variables) {
        // If no equations, then this is an implicit variable, so no need to list here.
        if (v.equations.size() == 0)
            continue;
        // Phase indicators are always present, and thus uninformative.
        if (v.name.equals("$connect") || v.name.equals("$init") || v.name.equals("$live"))
            continue;
        renderer.result.append(pad + v.nameString());
        renderer.result.append(" =" + v.combinerString());
        if (v.equations.size() == 1) {
            renderer.result.append(" ");
            v.equations.first().render(renderer);
            renderer.result.append("\n");
        } else {
            renderer.result.append("\n");
            for (EquationEntry e : v.equations) {
                renderer.result.append(pad + " ");
                e.render(renderer);
                renderer.result.append("\n");
            }
        }
    }
    for (EquationSet e : parts) {
        renderer.result.append(e.dump(showNamespace, pad));
    }
    return renderer.result.toString();
}
Also used : Operator(gov.sandia.n2a.language.Operator) AccessVariable(gov.sandia.n2a.language.AccessVariable) AccessVariable(gov.sandia.n2a.language.AccessVariable) Renderer(gov.sandia.n2a.language.Renderer)

Example 30 with AccessVariable

use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.

the class Variable method convertToGlobal.

/**
 *        If resolution path starts with a connection, then convert it to a walk through containers instead.
 */
public void convertToGlobal() {
    reference.convertToGlobal(this);
    visit(new Visitor() {

        public boolean visit(Operator op) {
            if (op instanceof AccessVariable) {
                AccessVariable av = (AccessVariable) op;
                av.reference.convertToGlobal(Variable.this);
                return false;
            }
            return true;
        }
    });
}
Also used : Operator(gov.sandia.n2a.language.Operator) Visitor(gov.sandia.n2a.language.Visitor) AccessVariable(gov.sandia.n2a.language.AccessVariable)

Aggregations

AccessVariable (gov.sandia.n2a.language.AccessVariable)42 Operator (gov.sandia.n2a.language.Operator)31 Visitor (gov.sandia.n2a.language.Visitor)16 Variable (gov.sandia.n2a.eqset.Variable)15 Constant (gov.sandia.n2a.language.Constant)15 Scalar (gov.sandia.n2a.language.type.Scalar)13 ArrayList (java.util.ArrayList)12 EquationEntry (gov.sandia.n2a.eqset.EquationEntry)11 TreeSet (java.util.TreeSet)11 EquationSet (gov.sandia.n2a.eqset.EquationSet)10 Type (gov.sandia.n2a.language.Type)9 Instance (gov.sandia.n2a.language.type.Instance)7 ConnectionBinding (gov.sandia.n2a.eqset.EquationSet.ConnectionBinding)6 VariableReference (gov.sandia.n2a.eqset.VariableReference)6 Output (gov.sandia.n2a.language.function.Output)6 Transformer (gov.sandia.n2a.language.Transformer)5 Event (gov.sandia.n2a.language.function.Event)5 Text (gov.sandia.n2a.language.type.Text)5 MNode (gov.sandia.n2a.db.MNode)4 AccessElement (gov.sandia.n2a.language.AccessElement)4