Search in sources :

Example 1 with EquationEntry

use of gov.sandia.n2a.eqset.EquationEntry in project n2a by frothga.

the class AccessVariable method simplify.

public Operator simplify(Variable from) {
    // unresolved!
    if (reference == null || reference.variable == null)
        return this;
    Variable v = reference.variable;
    // specifically prevent $init and $live from being replaced by a Constant
    if (v.name.equals("$init") || v.name.equals("$live"))
        return this;
    // A variable may locally evaluate to a constant, yet be subject to change from outside equations.
    if (v.hasAttribute("externalWrite"))
        return this;
    if (v.equations.size() != 1)
        return this;
    EquationEntry e = v.equations.first();
    if (e.expression == null)
        return this;
    if (e.condition != null) {
        if (!(e.condition instanceof Constant))
            return this;
        // Check for nonzero constant
        Type value = ((Constant) e.condition).value;
        // This second condition should be eliminated by Variable.simplify(), but until it is, don't do anything here.
        if (!(value instanceof Scalar) || ((Scalar) value).value == 0)
            return this;
    }
    if (e.expression instanceof Constant) {
        from.removeDependencyOn(v);
        from.changed = true;
        return e.expression;
    }
    // Attempt to simplify expression, and maybe get a Constant
    Variable p = from;
    while (p != null) {
        // can't simplify, because we've already visited this variable
        if (p == v)
            return this;
        p = p.visited;
    }
    v.visited = from;
    e.expression = e.expression.simplify(v);
    if (e.expression instanceof Constant) {
        from.removeDependencyOn(v);
        from.changed = true;
        return e.expression;
    }
    if (// Our variable is simply an alias for another variable, so grab the other variable instead.
    e.expression instanceof AccessVariable) {
        AccessVariable av = (AccessVariable) e.expression;
        Variable v2 = av.reference.variable;
        if (v2 == v)
            return this;
        // Can't reference a temporary outside the current equation set.
        if (v2.hasAttribute("temporary") && v2.container != from.container)
            return this;
        // Note: Folding an aliased variable will very likely remove one or more steps of delay in the movement of values through an equation set.
        // This might go against the user's intention. The folding can be blocked by adding a condition
        reference = av.reference;
        name = av.reference.variable.nameString();
        from.removeDependencyOn(v);
        from.addDependencyOn(v2);
        from.changed = true;
    }
    return this;
}
Also used : Variable(gov.sandia.n2a.eqset.Variable) EquationEntry(gov.sandia.n2a.eqset.EquationEntry) Scalar(gov.sandia.n2a.language.type.Scalar)

Example 2 with EquationEntry

use of gov.sandia.n2a.eqset.EquationEntry in project n2a by frothga.

the class JobC method resolve.

/**
 *        @param v A variable to convert into C++ code that can access it at runtime.
 *        @param context For the AST rendering system.
 *        @param lvalue Indicates that this will receive a value assignment. The other case is an rvalue, which will simply be read.
 *        @param base Injects a pointer at the beginning of the resolution path.
 *        @param logical The intended use is in a boolean expression, such as an if-test.
 */
public String resolve(VariableReference r, CRenderer context, boolean lvalue, String base, boolean logical) {
    if (r == null || r.variable == null)
        return "unresolved";
    if (r.variable.hasAttribute("constant")) {
        EquationEntry e = r.variable.equations.first();
        StringBuilder temp = context.result;
        StringBuilder result = new StringBuilder();
        context.result = result;
        e.expression.render(context);
        context.result = temp;
        return result.toString();
    }
    String containers = resolveContainer(r, context, base);
    if (r.variable.name.equals("(connection)")) {
        if (containers.endsWith("->"))
            containers = containers.substring(0, containers.length() - 2);
        if (containers.endsWith("."))
            containers = containers.substring(0, containers.length() - 1);
        return containers;
    }
    String name = "";
    // NOT context.bed !
    BackendDataC bed = (BackendDataC) r.variable.container.backendData;
    if (r.variable.hasAttribute("preexistent")) {
        if (!lvalue) {
            if (r.variable.name.equals("$t")) {
                if (r.variable.order == 0)
                    name = "simulator.currentEvent->t";
                else if (r.variable.order == 1) {
                    if (context.hasEvent)
                        name = "event->dt";
                    else
                        name = "getEvent ()->dt";
                }
            // TODO: what about higher orders of $t?
            } else {
                // strip the $ and expect it to be a member of simulator
                return "simulator." + r.variable.name.substring(1);
            }
        }
    // for lvalue, fall through to the main case below
    }
    if (r.variable.name.equals("$live")) {
        if (r.variable.hasAttribute("accessor")) {
            if (lvalue)
                return "unresolved";
            name = "getLive ()";
        } else // not "constant" or "accessor", so must be direct access
        {
            if (logical)
                return "(" + containers + "flags & (" + bed.flagType + ") 0x1 << " + bed.liveFlag + ")";
            else
                return "((" + containers + "flags & (" + bed.flagType + ") 0x1 << " + bed.liveFlag + ") ? 1 : 0)";
        }
    } else if (r.variable.hasAttribute("accessor")) {
        // At present, only $live can have "accessor" attribute.
        return "unresolved";
    }
    if (r.variable.name.endsWith(".$count")) {
        if (lvalue)
            return "unresolved";
        String alias = r.variable.name.substring(0, r.variable.name.lastIndexOf("."));
        name = mangle(alias) + "->" + prefix(r.variable.container) + "_" + mangle(alias) + "_count";
    }
    if (name.length() == 0) {
        if (lvalue && (bed.globalBuffered.contains(r.variable) || bed.localBuffered.contains(r.variable))) {
            name = mangle("next_", r.variable);
        } else {
            name = mangle(r.variable);
        }
    }
    return containers + name;
}
Also used : EquationEntry(gov.sandia.n2a.eqset.EquationEntry)

Example 3 with EquationEntry

use of gov.sandia.n2a.eqset.EquationEntry in project n2a by frothga.

the class XyceBackend method generateNetlist.

public void generateNetlist(MNode job, Simulator simulator, FileWriter writer) throws Exception {
    Population toplevel = (Population) simulator.wrapper.valuesObject[0];
    XyceRenderer renderer = new XyceRenderer(simulator);
    // Header
    writer.append(toplevel.equations.name + "\n");
    writer.append("\n");
    writer.append("* seed: " + job.get("$metadata", "seed") + "\n");
    writer.append(".tran 0 " + job.get("$metadata", "duration") + "\n");
    // Equations
    for (Instance i : simulator) {
        if (i == simulator.wrapper)
            continue;
        writer.append("\n");
        writer.append("* " + i + "\n");
        renderer.pi = i;
        renderer.exceptions = null;
        XyceBackendData bed = (XyceBackendData) i.equations.backendData;
        if (bed.deviceSymbol != null) {
            writer.append(bed.deviceSymbol.getDefinition(renderer));
        }
        InstanceTemporaries temp = new InstanceTemporaries(i, simulator, false, bed.internal);
        for (final Variable v : i.equations.variables) {
            // Compute variable v
            // TODO: how to switch between multiple conditions that can be true during normal operation? IE: how to make Xyce code conditional?
            // Perhaps gate each condition (through a transistor?) and sum them at a single node.
            // e can be null
            EquationEntry e = v.select(temp);
            Symbol def = bed.equationSymbols.get(e);
            if (def == null)
                continue;
            writer.append(def.getDefinition(renderer));
            // Trace
            class TraceFinder extends Visitor {

                List<Operator> traces = new ArrayList<Operator>();

                public boolean visit(Operator op) {
                    if (op instanceof Output) {
                        traces.add(((Output) op).operands[0]);
                        return false;
                    }
                    return true;
                }
            }
            TraceFinder traceFinder = new TraceFinder();
            e.expression.visit(traceFinder);
            for (Operator trace : traceFinder.traces) {
                // We don't know if contents is .func, expression or a node, so always wrap in braces.
                writer.append(".print tran {");
                if (trace instanceof AccessVariable) {
                    AccessVariable av = (AccessVariable) trace;
                    writer.append(renderer.change(av.reference));
                } else // trace is an expression
                {
                    if (// this trace wraps the entire equation
                    e.expression instanceof Output && ((Output) e.expression).operands[0] == trace) {
                        // simply print the LHS variable, similar to the AccessVariable case above
                        writer.append(renderer.change(v.reference));
                    } else {
                        // arbitrary expression
                        writer.append(renderer.change(trace));
                    }
                }
                // one .print line per variable
                writer.append("}\n");
            }
        }
    }
    // Trailer
    writer.append(".end\n");
}
Also used : Operator(gov.sandia.n2a.language.Operator) AccessVariable(gov.sandia.n2a.language.AccessVariable) Variable(gov.sandia.n2a.eqset.Variable) Visitor(gov.sandia.n2a.language.Visitor) AccessVariable(gov.sandia.n2a.language.AccessVariable) Instance(gov.sandia.n2a.language.type.Instance) Symbol(gov.sandia.n2a.backend.xyce.netlist.Symbol) InstanceTemporaries(gov.sandia.n2a.backend.internal.InstanceTemporaries) XyceRenderer(gov.sandia.n2a.backend.xyce.netlist.XyceRenderer) Output(gov.sandia.n2a.language.function.Output) Population(gov.sandia.n2a.backend.internal.Population) ArrayList(java.util.ArrayList) List(java.util.List) EquationEntry(gov.sandia.n2a.eqset.EquationEntry)

Example 4 with EquationEntry

use of gov.sandia.n2a.eqset.EquationEntry in project n2a by frothga.

the class XyceBackendData method analyze.

public void analyze(EquationSet s) {
    if (Device.isXyceDevice(s)) {
        deviceSymbol = new Device(s);
    }
    class ContainsOperator extends Visitor {

        @SuppressWarnings("rawtypes")
        public Class targetClass;

        boolean found;

        public boolean visit(Operator op) {
            if (found)
                return false;
            if (op.getClass().equals(targetClass)) {
                found = true;
                return false;
            }
            return true;
        }

        public boolean check(EquationEntry e) {
            found = false;
            e.expression.visit(this);
            return found;
        }
    }
    ContainsOperator containsPulse = new ContainsOperator();
    containsPulse.targetClass = Pulse.class;
    ContainsOperator containsSinewave = new ContainsOperator();
    containsSinewave.targetClass = Sinewave.class;
    ContainsVariable containsT = new ContainsVariable(new Variable("$t", 0));
    for (Variable v : s.variables) {
        // in a static (no structural dynamics) simulation, no $variable needs to be computed at runtime
        if (v.name.startsWith("$"))
            continue;
        // Constants are already subbed in. "initOnly" values are defined during init cycle, and can now be subbed during code generation.
        if (v.hasAttribute("constant") || v.hasAttribute("initOnly"))
            continue;
        for (EquationEntry eq : v.equations) {
            // don't need to write out equations defining dynamics already defined by a device
            if (Device.isXyceDevice(s) && Device.ignoreEquation(eq))
                continue;
            Symbol handler = null;
            if (eq.variable.order > 1) {
                Backend.err.get().println("Support for higher order differential equations not implemented yet (" + eq + ")");
                throw new Backend.AbortRun();
            } else if (eq.variable.order == 1) {
                handler = new SymbolStateVar1(eq);
            } else // The following are all order 0
            if (containsPulse.check(eq)) {
                handler = new SymbolPulse(eq);
            } else if (containsSinewave.check(eq)) {
                handler = new SymbolSinewave(eq);
            } else // TODO: this doesn't seem like an adequate test. Why would having a $t be the only reason to generate a zero-order symbol?
            if (containsT.check(eq.expression)) {
                handler = new SymbolStateVar0(eq);
            } else if (isExplicitInit(eq)) {
                handler = new SymbolConstantIC(eq);
            } else {
                // The RHS expression depends on state variables, so we create a netlist .func for it.
                handler = new SymbolFunc(eq);
            }
            equationSymbols.put(eq, handler);
            // May set the handler for v several times, but only the last one is kept. Multiple handlers should agree on symbol for reference. Better yet is to handle multiple equations together.
            variableSymbols.put(v.name, handler);
        }
    }
}
Also used : Operator(gov.sandia.n2a.language.Operator) AccessVariable(gov.sandia.n2a.language.AccessVariable) Variable(gov.sandia.n2a.eqset.Variable) Visitor(gov.sandia.n2a.language.Visitor) SymbolStateVar0(gov.sandia.n2a.backend.xyce.netlist.SymbolStateVar0) SymbolStateVar1(gov.sandia.n2a.backend.xyce.netlist.SymbolStateVar1) Device(gov.sandia.n2a.backend.xyce.netlist.Device) Symbol(gov.sandia.n2a.backend.xyce.netlist.Symbol) SymbolPulse(gov.sandia.n2a.backend.xyce.netlist.SymbolPulse) SymbolFunc(gov.sandia.n2a.backend.xyce.netlist.SymbolFunc) SymbolSinewave(gov.sandia.n2a.backend.xyce.netlist.SymbolSinewave) EquationEntry(gov.sandia.n2a.eqset.EquationEntry) SymbolConstantIC(gov.sandia.n2a.backend.xyce.netlist.SymbolConstantIC)

Example 5 with EquationEntry

use of gov.sandia.n2a.eqset.EquationEntry in project n2a by frothga.

the class AccessElement method simplify.

public Operator simplify(Variable from) {
    for (int i = 0; i < operands.length; i++) operands[i] = operands[i].simplify(from);
    if (operands.length == 1) {
        from.changed = true;
        return operands[0];
    }
    // All operand positions beyond 0 are subscripts, presumably into a matrix at operands[0].
    // Attempt to replace the element access with a constant.
    int row = -1;
    int col = 0;
    if (operands[1] instanceof Constant) {
        Constant c = (Constant) operands[1];
        if (c.value instanceof Scalar)
            row = (int) ((Scalar) c.value).value;
    }
    if (operands.length > 2) {
        col = -1;
        if (operands[2] instanceof Constant) {
            Constant c = (Constant) operands[2];
            if (c.value instanceof Scalar)
                col = (int) ((Scalar) c.value).value;
        }
    }
    if (row < 0 || col < 0)
        return this;
    if (operands[0] instanceof Constant) {
        Constant c = (Constant) operands[0];
        if (c.value instanceof Matrix) {
            from.changed = true;
            return new Constant(new Scalar(((Matrix) c.value).get(row, col)));
        }
    } else {
        // Try to unpack the target variable and see if the specific element we want is constant
        AccessVariable av = (AccessVariable) operands[0];
        if (av.reference != null && av.reference.variable != null) {
            Variable v = av.reference.variable;
            if (v.equations != null && v.equations.size() == 1) {
                EquationEntry e = v.equations.first();
                if (// Ideally, we would also ensure e.condition is satisfied. However, only weird code would have a condition at all.
                e.expression instanceof BuildMatrix) {
                    BuildMatrix b = (BuildMatrix) e.expression;
                    Operator element = b.getElement(row, col);
                    if (element != null && element instanceof Constant) {
                        from.changed = true;
                        e.expression.releaseDependencies(from);
                        if (e.condition != null)
                            e.condition.releaseDependencies(from);
                        return element;
                    }
                }
            }
        }
    }
    return this;
}
Also used : Matrix(gov.sandia.n2a.language.type.Matrix) Variable(gov.sandia.n2a.eqset.Variable) EquationEntry(gov.sandia.n2a.eqset.EquationEntry) Scalar(gov.sandia.n2a.language.type.Scalar)

Aggregations

EquationEntry (gov.sandia.n2a.eqset.EquationEntry)8 Variable (gov.sandia.n2a.eqset.Variable)6 AccessVariable (gov.sandia.n2a.language.AccessVariable)3 Scalar (gov.sandia.n2a.language.type.Scalar)3 EventTarget (gov.sandia.n2a.backend.internal.InternalBackendData.EventTarget)2 Symbol (gov.sandia.n2a.backend.xyce.netlist.Symbol)2 EquationSet (gov.sandia.n2a.eqset.EquationSet)2 ConnectionBinding (gov.sandia.n2a.eqset.EquationSet.ConnectionBinding)2 Operator (gov.sandia.n2a.language.Operator)2 Visitor (gov.sandia.n2a.language.Visitor)2 AbortRun (gov.sandia.n2a.plugins.extpoints.Backend.AbortRun)2 InstanceTemporaries (gov.sandia.n2a.backend.internal.InstanceTemporaries)1 EventSource (gov.sandia.n2a.backend.internal.InternalBackendData.EventSource)1 Population (gov.sandia.n2a.backend.internal.Population)1 Device (gov.sandia.n2a.backend.xyce.netlist.Device)1 SymbolConstantIC (gov.sandia.n2a.backend.xyce.netlist.SymbolConstantIC)1 SymbolFunc (gov.sandia.n2a.backend.xyce.netlist.SymbolFunc)1 SymbolPulse (gov.sandia.n2a.backend.xyce.netlist.SymbolPulse)1 SymbolSinewave (gov.sandia.n2a.backend.xyce.netlist.SymbolSinewave)1 SymbolStateVar0 (gov.sandia.n2a.backend.xyce.netlist.SymbolStateVar0)1