Search in sources :

Example 1 with Event

use of gov.sandia.n2a.language.function.Event in project n2a by frothga.

the class InternalBackendData method analyzeEvents.

public static void analyzeEvents(final EquationSet s, final List<EventTarget> eventTargets, final List<Variable> eventReferences) {
    class EventVisitor extends Visitor {

        public boolean found;

        public boolean visit(Operator op) {
            if (op instanceof Event) {
                found = true;
                Event de = (Event) op;
                if (// this event has not yet been analyzed
                de.eventType == null) {
                    final EventTarget et = new EventTarget(de);
                    int targetIndex = eventTargets.indexOf(et);
                    if (// event target already exists
                    targetIndex >= 0) {
                        de.eventType = eventTargets.get(targetIndex);
                    } else // we must create a new event target, or more properly, fill in the event target we just used as a query object
                    {
                        // Create an entry and save the index
                        targetIndex = eventTargets.size();
                        eventTargets.add(et);
                        de.eventType = et;
                        et.container = s;
                        // Determine edge type
                        if (de.operands.length < 3) {
                            et.edge = EventTarget.RISE;
                        } else if (de.operands[2] instanceof Constant) {
                            Constant c = (Constant) de.operands[2];
                            if (c.value instanceof Text) {
                                Text t = (Text) c.value;
                                if (t.value.equalsIgnoreCase("nonzero"))
                                    et.edge = EventTarget.NONZERO;
                                else if (t.value.equalsIgnoreCase("change"))
                                    et.edge = EventTarget.CHANGE;
                                else if (t.value.equalsIgnoreCase("fall"))
                                    et.edge = EventTarget.FALL;
                                else
                                    et.edge = EventTarget.RISE;
                            } else {
                                Backend.err.get().println("ERROR: event() edge type must be a string.");
                                throw new Backend.AbortRun();
                            }
                        } else {
                            Backend.err.get().println("ERROR: event() edge type must be constant.");
                            throw new Backend.AbortRun();
                        }
                        // Allocate auxiliary variable
                        if (de.operands[0] instanceof AccessVariable) {
                            AccessVariable av = (AccessVariable) de.operands[0];
                            VariableReference reference = av.reference;
                            Variable v = reference.variable;
                            // then the user has broken the rule that we can't see temporaries in other parts.
                            if (v.hasAttribute("temporary") && v.container != s) {
                                Backend.err.get().println("WARNING: Cannot be temporary due to event monitor: " + v.container.name + "." + v.nameString() + " from " + s.name);
                                v.removeAttribute("temporary");
                            }
                            // so fall through to the !trackOne case below.
                            if (!v.hasAttribute("temporary")) {
                                // ensure it's buffered, so we can detect change
                                v.addAttribute("externalRead");
                                et.trackOne = true;
                                // just a holder for the reference
                                et.track = new Variable();
                                et.track.reference = reference;
                            }
                        }
                        if (// Expression, so create auxiliary variable. Aux not needed for NONZERO, because no change detection.
                        !et.trackOne && et.edge != EventTarget.NONZERO) {
                            et.track = new Variable("eventAux" + targetIndex, 0);
                            et.track.type = new Scalar(0);
                            et.track.reference = new VariableReference();
                            et.track.reference.variable = et.track;
                        }
                        // Locate any temporaries for evaluation. TODO: for more efficiency, we could have separate lists of temporaries for the condition and delay operands
                        // Tie into the dependency graph using a phantom variable (which can go away afterward without damaging the graph).
                        final Variable phantom = new Variable("event");
                        phantom.uses = new IdentityHashMap<Variable, Integer>();
                        for (int i = 0; i < et.event.operands.length; i++) et.event.operands[i].visit(new Visitor() {

                            public boolean visit(Operator op) {
                                if (op instanceof AccessVariable) {
                                    AccessVariable av = (AccessVariable) op;
                                    Variable v = av.reference.variable;
                                    if (!phantom.uses.containsKey(v))
                                        phantom.uses.put(v, 1);
                                    return false;
                                }
                                return true;
                            }
                        });
                        // Scan all variables in equation set to see if we need them
                        for (Variable t : s.variables) {
                            if (t.hasAttribute("temporary") && phantom.dependsOn(t) != null)
                                et.dependencies.add(t);
                        }
                        // Note the default is already set to -1 (no care)
                        class DelayVisitor extends Visitor {

                            TreeSet<EquationSet> containers = new TreeSet<EquationSet>();

                            public boolean visit(Operator op) {
                                if (op instanceof AccessVariable) {
                                    AccessVariable av = (AccessVariable) op;
                                    // could include the target part itself, if in fact we use local variables
                                    containers.add(av.reference.variable.container);
                                    return false;
                                }
                                return true;
                            }
                        }
                        DelayVisitor dv = new DelayVisitor();
                        if (de.operands.length >= 2) {
                            if (de.operands[1] instanceof Constant) {
                                Constant c = (Constant) de.operands[1];
                                et.delay = (float) ((Scalar) c.value).value;
                                if (et.delay < 0)
                                    et.delay = -1;
                            } else {
                                // indicates that we need to evaluate delay at run time
                                et.delay = -2;
                                de.operands[1].visit(dv);
                            }
                        }
                        // Set up monitors in source parts
                        class ConditionVisitor extends Visitor {

                            TreeSet<EquationSet> containers = new TreeSet<EquationSet>();

                            public boolean visit(Operator op) {
                                if (op instanceof AccessVariable) {
                                    AccessVariable av = (AccessVariable) op;
                                    Variable v = av.reference.variable;
                                    EquationSet sourceContainer = v.container;
                                    containers.add(sourceContainer);
                                    // Set up monitors for values that can vary during update.
                                    if (!v.hasAttribute("constant") && !v.hasAttribute("initOnly") && !et.monitors(sourceContainer)) {
                                        EventSource es = new EventSource(sourceContainer, et);
                                        // null means self-reference, a special case handled in Part
                                        if (sourceContainer != s)
                                            es.reference = av.reference;
                                        et.sources.add(es);
                                    }
                                    return false;
                                }
                                return true;
                            }
                        }
                        ConditionVisitor cv = new ConditionVisitor();
                        de.operands[0].visit(cv);
                        // Special case for event with no references that vary
                        if (et.sources.isEmpty()) {
                            // We can avoid creating a self monitor if we know for certain that the event will never fire
                            boolean neverFires = false;
                            if (de.operands[0] instanceof Constant) {
                                if (et.edge == EventTarget.NONZERO) {
                                    Type op0 = ((Constant) de.operands[0]).value;
                                    if (op0 instanceof Scalar) {
                                        neverFires = ((Scalar) op0).value == 0;
                                    } else {
                                        Backend.err.get().println("ERROR: Condition for event() must resolve to a number.");
                                        throw new Backend.AbortRun();
                                    }
                                } else {
                                    neverFires = true;
                                }
                            }
                            if (!neverFires) {
                                EventSource es = new EventSource(s, et);
                                // This is a self-reference, so es.reference should be null.
                                et.sources.add(es);
                            }
                        }
                        // Determine if monitor needs to test every target, or if one representative target is sufficient
                        for (EventSource source : et.sources) {
                            // associated with any given source instance, so every target must be evaluated separately.
                            if (cv.containers.size() > 1)
                                source.testEach = true;
                            if (dv.containers.size() > 1 || (dv.containers.size() == 1 && dv.containers.first() != source.container))
                                source.delayEach = true;
                        }
                    }
                }
            }
            return true;
        }
    }
    EventVisitor eventVisitor = new EventVisitor();
    for (Variable v : s.variables) {
        eventVisitor.found = false;
        v.visit(eventVisitor);
        if ((eventVisitor.found || v.dependsOnEvent()) && v.reference.variable != v)
            eventReferences.add(v);
    }
}
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) Constant(gov.sandia.n2a.language.Constant) Scalar(gov.sandia.n2a.language.type.Scalar) TreeSet(java.util.TreeSet) EquationSet(gov.sandia.n2a.eqset.EquationSet) AccessVariable(gov.sandia.n2a.language.AccessVariable) VariableReference(gov.sandia.n2a.eqset.VariableReference) Text(gov.sandia.n2a.language.type.Text) Backend(gov.sandia.n2a.plugins.extpoints.Backend) Type(gov.sandia.n2a.language.Type) Event(gov.sandia.n2a.language.function.Event)

Example 2 with Event

use of gov.sandia.n2a.language.function.Event in project n2a by frothga.

the class JobC method addImplicitDependenciesRecursive.

public void addImplicitDependenciesRecursive(EquationSet s) {
    for (EquationSet p : s.parts) {
        addImplicitDependenciesRecursive(p);
    }
    final Variable dt = s.find(new Variable("$t", 1));
    if (s.lethalP) {
        // Which should for sure exist, since lethalP implies it.
        Variable p = s.find(new Variable("$p"));
        p.addDependencyOn(dt);
    }
    class VisitorDt implements Visitor {

        public Variable from;

        public boolean visit(Operator op) {
            if (op instanceof Input) {
                Input i = (Input) op;
                String mode = i.getMode();
                if ((mode.contains("time") || mode.contains("smooth")) && !from.hasAttribute("global") && !T.equals("int")) {
                    // So that time epsilon can be determined from dt when initializing input.
                    from.addDependencyOn(dt);
                }
            }
            if (op instanceof Event) {
                Event e = (Event) op;
                if (// constant delay > 0
                e.operands.length > 1 && e.operands[1].getDouble() > 0) {
                    // We depend on $t' to know time exponent.
                    // This is necessary regardless of whether T=="int", because eventGenerate() handles this in a generic way.
                    EquationSet root = s.getRoot();
                    Variable rootDt = root.find(dt);
                    rootDt.addUser(root);
                }
            }
            return true;
        }
    }
    VisitorDt visitor = new VisitorDt();
    for (Variable v : s.variables) {
        visitor.from = v;
        v.visit(visitor);
        if (v.derivative != null)
            v.addDependencyOn(dt);
    }
}
Also used : Operator(gov.sandia.n2a.language.Operator) EquationSet(gov.sandia.n2a.eqset.EquationSet) Input(gov.sandia.n2a.language.function.Input) Variable(gov.sandia.n2a.eqset.Variable) AccessVariable(gov.sandia.n2a.language.AccessVariable) Visitor(gov.sandia.n2a.language.Visitor) Event(gov.sandia.n2a.language.function.Event)

Example 3 with Event

use of gov.sandia.n2a.language.function.Event in project n2a by frothga.

the class RendererPython method render.

public boolean render(Operator op) {
    if (op instanceof Add) {
        Add a = (Add) op;
        // Check if this is a string expression
        if (a.name != null) {
            result.append(a.name);
            return true;
        }
        return false;
    }
    if (op instanceof AccessElement) {
        AccessElement ae = (AccessElement) op;
        ae.operands[0].render(this);
        if (ae.operands.length >= 2) {
            result.append("[");
            ae.operands[1].render(this);
            if (ae.operands.length >= 3) {
                result.append(",");
                ae.operands[2].render(this);
            }
            result.append("]");
        }
        return true;
    }
    if (op instanceof AccessVariable) {
        AccessVariable av = (AccessVariable) op;
        result.append(job.resolve(av.reference, this, false));
        return true;
    }
    if (op instanceof AND) {
        AND and = (AND) op;
        and.render(this, " and ");
        return true;
    }
    if (op instanceof BuildMatrix) {
        BuildMatrix b = (BuildMatrix) op;
        result.append(b.name);
        return true;
    }
    if (op instanceof Constant) {
        Constant c = (Constant) op;
        Type o = c.value;
        if (o instanceof Scalar) {
            result.append(print(((Scalar) o).value));
            return true;
        }
        if (o instanceof Text) {
            result.append("\"" + o.toString() + "\"");
            return true;
        }
        if (o instanceof Matrix) {
            result.append(c.name);
            return true;
        }
        return false;
    }
    if (op instanceof Event) {
        Event e = (Event) op;
        // The cast to bool gets rid of the specific numeric value from flags.
        // If used in a numeric expression, it will convert to either 1 or 0.
        result.append("bool (flags & 0x1 << " + e.eventType.valueIndex + ")");
        return true;
    }
    if (op instanceof Exp) {
        Exp e = (Exp) op;
        Operator a = e.operands[0];
        result.append("exp(");
        a.render(this);
        result.append(")");
        return true;
    }
    if (op instanceof Gaussian) {
        Gaussian g = (Gaussian) op;
        result.append("gaussian(");
        if (g.operands.length > 0) {
            g.operands[0].render(this);
        }
        result.append(")");
        return true;
    }
    if (op instanceof Grid) {
        // TODO: needs library implementation
        Grid g = (Grid) op;
        boolean raw = g.operands.length >= 5 && g.operands[4].getString().contains("raw");
        result.append("grid");
        if (raw)
            result.append("Raw");
        result.append("(");
        int count = Math.min(4, g.operands.length);
        if (count > 0)
            g.operands[0].render(this);
        for (int i = 1; i < count; i++) {
            result.append(", ");
            g.operands[i].render(this);
        }
        result.append(")");
        return true;
    }
    if (op instanceof Input) {
        // TODO: needs library implementation
        Input i = (Input) op;
        String mode = "";
        if (i.operands.length == 2)
            mode = i.operands[1].getString();
        else if (i.operands.length >= 4)
            mode = i.operands[3].getString();
        if (mode.contains("columns")) {
            result.append(i.name + "->getColumns ()");
        } else {
            Operator op1 = i.operands[1];
            Operator op2 = i.operands[2];
            result.append(i.name + ".get");
            if (mode.contains("raw"))
                result.append("Raw");
            result.append("(");
            op1.render(this);
            result.append(", ");
            op2.render(this);
            result.append(")");
        }
        return true;
    }
    if (op instanceof Log) {
        Log l = (Log) op;
        Operator a = l.operands[0];
        result.append("log(");
        a.render(this);
        return true;
    }
    if (op instanceof Modulo) {
        Modulo m = (Modulo) op;
        Operator a = m.operand0;
        Operator b = m.operand1;
        a.render(this);
        result.append(" % ");
        b.render(this);
        return true;
    }
    if (op instanceof Norm) {
        Norm n = (Norm) op;
        Operator A = n.operands[0];
        result.append("numpy.linalg.norm(");
        A.render(this);
        result.append(", ");
        n.operands[1].render(this);
        result.append(")");
        return true;
    }
    if (op instanceof OR) {
        OR or = (OR) op;
        or.render(this, " or ");
        return true;
    }
    if (op instanceof Output) {
        Output o = (Output) op;
        result.append(o.name + "->trace (Simulator::instance.currentEvent->t, ");
        if (// column name is explicit
        o.hasColumnName) {
            o.operands[2].render(this);
        } else // column name is generated, so use prepared string value
        {
            result.append(o.columnName);
        }
        result.append(", ");
        o.operands[1].render(this);
        result.append(")");
        return true;
    }
    if (op instanceof Power) {
        Power p = (Power) op;
        Operator a = p.operand0;
        Operator b = p.operand1;
        result.append("pow(");
        a.render(this);
        result.append(", ");
        b.render(this);
        result.append(")");
        return true;
    }
    if (op instanceof ReadMatrix) {
        ReadMatrix r = (ReadMatrix) op;
        String mode = "";
        int lastParm = r.operands.length - 1;
        if (lastParm > 0) {
            if (r.operands[lastParm] instanceof Constant) {
                Constant c = (Constant) r.operands[lastParm];
                if (c.value instanceof Text) {
                    mode = ((Text) c.value).value;
                }
            }
        }
        if (mode.equals("rows")) {
            result.append(r.name + "->rows ()");
        } else if (mode.equals("columns")) {
            result.append(r.name + "->columns ()");
        } else {
            result.append(r.name + "->get");
            if (mode.equals("raw"))
                result.append("Raw");
            result.append("(");
            r.operands[1].render(this);
            result.append(", ");
            r.operands[2].render(this);
            result.append(")");
        }
        return true;
    }
    if (op instanceof SquareRoot) {
        SquareRoot s = (SquareRoot) op;
        Operator a = s.operands[0];
        result.append("sqrt(");
        a.render(this);
        return true;
    }
    if (op instanceof Tangent) {
        Tangent t = (Tangent) op;
        Operator a = t.operands[0];
        result.append("tan(");
        a.render(this);
        result.append(")");
        return true;
    }
    if (op instanceof Uniform) {
        Uniform u = (Uniform) op;
        result.append("uniform(");
        if (u.operands.length > 0) {
            u.operands[0].render(this);
        }
        result.append(")");
        return true;
    }
    return super.render(op);
}
Also used : Add(gov.sandia.n2a.language.operator.Add) Operator(gov.sandia.n2a.language.Operator) Constant(gov.sandia.n2a.language.Constant) Grid(gov.sandia.n2a.language.function.Grid) Uniform(gov.sandia.n2a.language.function.Uniform) Scalar(gov.sandia.n2a.language.type.Scalar) Input(gov.sandia.n2a.language.function.Input) ReadMatrix(gov.sandia.n2a.language.function.ReadMatrix) BuildMatrix(gov.sandia.n2a.language.BuildMatrix) Matrix(gov.sandia.n2a.language.type.Matrix) SquareRoot(gov.sandia.n2a.language.function.SquareRoot) BuildMatrix(gov.sandia.n2a.language.BuildMatrix) Output(gov.sandia.n2a.language.function.Output) OR(gov.sandia.n2a.language.operator.OR) AccessVariable(gov.sandia.n2a.language.AccessVariable) Log(gov.sandia.n2a.language.function.Log) Modulo(gov.sandia.n2a.language.operator.Modulo) Text(gov.sandia.n2a.language.type.Text) Tangent(gov.sandia.n2a.language.function.Tangent) ReadMatrix(gov.sandia.n2a.language.function.ReadMatrix) Type(gov.sandia.n2a.language.Type) AND(gov.sandia.n2a.language.operator.AND) Event(gov.sandia.n2a.language.function.Event) Norm(gov.sandia.n2a.language.function.Norm) Gaussian(gov.sandia.n2a.language.function.Gaussian) AccessElement(gov.sandia.n2a.language.AccessElement) Exp(gov.sandia.n2a.language.function.Exp) Power(gov.sandia.n2a.language.operator.Power)

Example 4 with Event

use of gov.sandia.n2a.language.function.Event in project n2a by frothga.

the class RendererCfp method render.

public boolean render(Operator op) {
    if (op == latch) {
        latch = null;
        return super.render(op);
    }
    // one or more exponent parameters to the end of the usual function call.
    if (operatorsWithExponent.contains(op.getClass()))
        return super.render(op);
    // These are ordered to trap specific cases before more general ones.
    if (op instanceof OperatorLogical) {
        // Return the boolean itself if being consumed by a condition or by another logical operator.
        if (op.parent == null || op.parent instanceof OperatorLogical)
            return super.render(op);
        result.append("(");
        escalate(op);
        result.append(" ? ");
        if (op instanceof NOT) {
            result.append("0 : " + print(1, op.exponentNext) + ")");
        } else {
            result.append(print(1, op.exponentNext) + " : 0)");
        }
        return true;
    }
    if (op instanceof Multiply || op instanceof MultiplyElementwise) {
        OperatorBinary b = (OperatorBinary) op;
        // Explanation of shift -- The exponent of the result will be the sum of the exponents
        // of the two operands. That new exponent will be associated with bit position 2*MSB.
        // We want the exponent at bit position MSB.
        // Exponent at MSB position after a direct integer multiply.
        int exponentRaw = b.operand0.exponentNext + b.operand1.exponentNext - Operator.MSB;
        int shift = exponentRaw - b.exponentNext;
        if (shift == 0) {
            escalate(b);
        } else {
            if (b.getType() instanceof Matrix) {
                if (shift > 0) {
                    result.append("shift (");
                    escalate(b);
                    result.append(", " + shift + ")");
                } else {
                    if (b instanceof Multiply || b.operand0.isScalar() || b.operand1.isScalar()) {
                        result.append("multiply (");
                    } else // MultiplyElementwise and both operands are matrices
                    {
                        result.append("multiplyElementwise (");
                    }
                    if (b.operand0.isScalar()) {
                        // Always put the scalar in second position, so we need only one form of multiply().
                        b.operand1.render(this);
                        result.append(", ");
                        b.operand0.render(this);
                    } else {
                        b.operand0.render(this);
                        result.append(", ");
                        b.operand1.render(this);
                    }
                    result.append(", " + -shift + ")");
                }
            } else {
                if (shift > 0) {
                    result.append("(");
                    escalate(b);
                    result.append(" << " + shift);
                    result.append(")");
                } else {
                    if (!parentAccepts64bit(b))
                        result.append("(int32_t) ");
                    result.append("(");
                    if (!provides64bit(b.operand0))
                        result.append("(int64_t) ");
                    escalate(b);
                    result.append(" >> " + -shift);
                    result.append(")");
                }
            }
        }
        return true;
    }
    if (op instanceof Divide) {
        Divide d = (Divide) op;
        // Explanation of shift -- In a division, the quotient is effectively down-shifted by
        // the number of bits in the denominator, and its exponent is the difference between
        // the exponents of the numerator and denominator.
        // Exponent in MSB from a direct integer division.
        int exponentRaw = d.operand0.exponentNext - d.operand1.exponentNext + Operator.MSB;
        int shift = exponentRaw - d.exponentNext;
        if (shift == 0) {
            escalate(d);
        } else {
            if (d.getType() instanceof Matrix) {
                if (shift > 0) {
                    result.append("divide (");
                    d.operand0.render(this);
                    result.append(", ");
                    d.operand1.render(this);
                    result.append(", " + shift + ")");
                } else {
                    result.append("shift (");
                    escalate(d);
                    result.append(", " + shift + ")");
                }
            } else {
                if (shift > 0) {
                    if (!parentAccepts64bit(d))
                        result.append("(int32_t) ");
                    result.append("((");
                    if (!provides64bit(d.operand0))
                        result.append("(int64_t) ");
                    // OperatorBinary.render() will add parentheses around operand0 if it has lower
                    // precedence than division. This includes the case where it has lower precedence
                    // than shift, so we are safe.
                    d.render(this, " << " + shift + ") / ");
                    result.append(")");
                } else {
                    result.append("(");
                    escalate(d);
                    result.append(" >> " + -shift + ")");
                }
            }
        }
        return true;
    }
    if (op instanceof Modulo) {
        Modulo m = (Modulo) op;
        int shift = m.exponent - m.exponentNext;
        if (m.operand0.exponentNext == m.operand1.exponentNext) {
            if (shift == 0)
                return super.render(m);
            result.append("(");
            escalate(m);
            result.append(printShift(shift) + ")");
        } else {
            if (shift != 0)
                result.append("(");
            result.append("modFloor (");
            m.operand0.render(this);
            result.append(", ");
            m.operand1.render(this);
            result.append(", " + m.operand0.exponentNext + ", " + m.operand1.exponentNext + ")");
            if (shift != 0)
                result.append(printShift(shift) + ")");
        }
        return true;
    }
    if (// Add, Subtract, Negate, Transpose
    op instanceof OperatorArithmetic) {
        int exponentOperand;
        if (op instanceof OperatorBinary)
            exponentOperand = ((OperatorBinary) op).operand0.exponentNext;
        else
            exponentOperand = ((OperatorUnary) op).operand.exponentNext;
        int shift = exponentOperand - op.exponentNext;
        if (shift == 0)
            return super.render(op);
        if (op.getType() instanceof Matrix) {
            result.append("shift (");
            escalate(op);
            result.append(", " + shift + ")");
        } else {
            result.append("(");
            // In C++, shift is just below addition in precedence.
            boolean needParens = op.precedence() > new Add().precedence();
            if (needParens)
                result.append("(");
            escalate(op);
            if (needParens)
                result.append(")");
            result.append(printShift(shift));
            result.append(")");
        }
        return true;
    }
    // These are listed in alphabetical order, with a catch-all at the end.
    if (// Actually just an operator, not a function
    op instanceof AccessVariable) {
        AccessVariable av = (AccessVariable) op;
        int shift = av.exponent - av.exponentNext;
        if (shift != 0) {
            if (av.getType() instanceof Matrix)
                result.append("shift ");
            result.append("(");
        }
        result.append(job.resolve(av.reference, this, false));
        if (useExponent && shift != 0) {
            if (av.getType() instanceof Matrix) {
                result.append(", " + shift);
            } else {
                result.append(printShift(shift));
            }
            result.append(")");
        }
        return true;
    }
    if (op instanceof Ceil) {
        Ceil f = (Ceil) op;
        Operator a = f.operands[0];
        // Ceil always sets operands[0].exponentNext to be same as f.exponentNext, so no shift is necessary.
        if (// LSB is above decimal, so ceil() operation is impossible.
        f.exponentNext >= Operator.MSB) {
            a.render(this);
        } else if (// All bits are below decimal
        f.exponentNext < 0) {
            result.append("0");
        } else {
            // Create a mask for bits below the decimal point.
            // When this mask is added to the number, it will add 1 to the first bit position
            // above the decimal if any bit is set under the mask. Afterward, used AND to remove
            // any residual bits below the decimal.
            // This works for both positive and negative numbers.
            int zeroes = Operator.MSB - f.exponentNext;
            int wholeMask = 0xFFFFFFFF << zeroes;
            int decimalMask = ~wholeMask;
            boolean needParens = a.precedence() >= new Add().precedence();
            result.append("(");
            if (needParens)
                result.append("(");
            a.render(this);
            if (needParens)
                result.append(")");
            result.append(" + " + decimalMask + " & " + wholeMask + ")");
        }
        return true;
    }
    if (op instanceof Cosine) {
        Cosine c = (Cosine) op;
        Operator a = c.operands[0];
        int shift = c.exponent - c.exponentNext;
        if (shift != 0)
            result.append("(");
        result.append("cos (");
        a.render(this);
        result.append(", " + a.exponentNext + ")");
        if (shift != 0)
            result.append(printShift(shift) + ")");
        return true;
    }
    if (op instanceof Event) {
        // See comment on OperatorLogical above. Since event() returns a boolean, we follow the same behavior here.
        if (op.parent == null || op.parent instanceof OperatorLogical)
            return super.render(op);
        Event e = (Event) op;
        int exponentRaw = Operator.MSB - e.eventType.valueIndex;
        int shift = exponentRaw - e.exponentNext;
        if (shift != 0)
            result.append("(");
        result.append("(flags & (" + bed.localFlagType + ") 0x1 << " + e.eventType.valueIndex + ")");
        if (shift != 0) {
            result.append(printShift(shift));
            result.append(")");
        }
        return true;
    }
    if (op instanceof Floor) {
        // See Ceil above for similar code.
        Floor f = (Floor) op;
        Operator a = f.operands[0];
        if (f.exponentNext >= Operator.MSB) {
            a.render(this);
        } else if (f.exponentNext < 0) {
            result.append("0");
        } else {
            // Mask off bits below the decimal point. This works for both positive and negative numbers.
            int zeroes = Operator.MSB - f.exponentNext;
            int wholeMask = 0xFFFFFFFF << zeroes;
            boolean needParens = a.precedence() >= new AND().precedence();
            result.append("(");
            if (needParens)
                result.append("(");
            a.render(this);
            if (needParens)
                result.append(")");
            result.append(" & " + wholeMask + ")");
        }
        return true;
    }
    if (op instanceof HyperbolicTangent) {
        HyperbolicTangent ht = (HyperbolicTangent) op;
        Operator a = ht.operands[0];
        int shift = ht.exponent - ht.exponentNext;
        if (shift != 0)
            result.append("(");
        result.append("tanh (");
        a.render(this);
        result.append(", " + a.exponentNext + ")");
        if (shift != 0)
            result.append(printShift(shift) + ")");
        return true;
    }
    if (op instanceof Round) {
        Round r = (Round) op;
        Operator a = r.operands[0];
        int shift = a.exponentNext - r.exponentNext;
        int decimalPlaces = Math.max(0, Operator.MSB - a.exponentNext);
        int mask = 0xFFFFFFFF << decimalPlaces;
        int half = 0;
        if (decimalPlaces > 0)
            half = 0x1 << decimalPlaces - 1;
        if (shift != 0)
            result.append("(");
        // Bitwise operators are low precedence, so we parenthesize them regardless.
        result.append("(");
        boolean needParens = a.precedence() > new Add().precedence();
        if (needParens)
            result.append("(");
        a.render(this);
        if (needParens)
            result.append(")");
        result.append(" + " + half + " & " + mask);
        // Close parens around bitwise operator
        result.append(")");
        if (shift != 0)
            result.append(printShift(shift) + ")");
        return true;
    }
    if (op instanceof Signum) {
        Signum s = (Signum) op;
        Operator a = s.operands[0];
        int one = 0x1 << Operator.MSB - s.exponentNext;
        boolean needParens = a.precedence() >= new LT().precedence();
        if (needParens)
            result.append("(");
        a.render(this);
        if (needParens)
            result.append(")");
        result.append(" < 0 ? " + -one + ":" + one + ")");
        return true;
    }
    if (op instanceof Sine) {
        Sine s = (Sine) op;
        Operator a = s.operands[0];
        int shift = s.exponent - s.exponentNext;
        if (shift != 0)
            result.append("(");
        result.append("sin (");
        a.render(this);
        result.append(", " + a.exponentNext + ")");
        if (shift != 0)
            result.append(printShift(shift) + ")");
        return true;
    }
    if (// AbsoluteValue, Grid, Max, Min
    op instanceof Function) {
        int shift = op.exponent - op.exponentNext;
        if (shift == 0)
            return super.render(op);
        if (op.getType() instanceof Matrix) {
            result.append("shift (");
            escalate(op);
            result.append(", " + shift + ")");
        } else {
            result.append("(");
            escalate(op);
            result.append(printShift(shift) + ")");
        }
        return true;
    }
    return super.render(op);
}
Also used : Add(gov.sandia.n2a.language.operator.Add) Operator(gov.sandia.n2a.language.Operator) LT(gov.sandia.n2a.language.operator.LT) Sine(gov.sandia.n2a.language.function.Sine) Divide(gov.sandia.n2a.language.operator.Divide) Function(gov.sandia.n2a.language.Function) ReadMatrix(gov.sandia.n2a.language.function.ReadMatrix) BuildMatrix(gov.sandia.n2a.language.BuildMatrix) Matrix(gov.sandia.n2a.language.type.Matrix) HyperbolicTangent(gov.sandia.n2a.language.function.HyperbolicTangent) Multiply(gov.sandia.n2a.language.operator.Multiply) Round(gov.sandia.n2a.language.function.Round) OperatorArithmetic(gov.sandia.n2a.language.OperatorArithmetic) Floor(gov.sandia.n2a.language.function.Floor) AccessVariable(gov.sandia.n2a.language.AccessVariable) Modulo(gov.sandia.n2a.language.operator.Modulo) OperatorLogical(gov.sandia.n2a.language.OperatorLogical) MultiplyElementwise(gov.sandia.n2a.language.operator.MultiplyElementwise) OperatorBinary(gov.sandia.n2a.language.OperatorBinary) Signum(gov.sandia.n2a.language.function.Signum) NOT(gov.sandia.n2a.language.operator.NOT) AND(gov.sandia.n2a.language.operator.AND) Event(gov.sandia.n2a.language.function.Event) Ceil(gov.sandia.n2a.language.function.Ceil) Cosine(gov.sandia.n2a.language.function.Cosine)

Example 5 with Event

use of gov.sandia.n2a.language.function.Event in project n2a by frothga.

the class InternalBackendData method analyzeEvents.

public static void analyzeEvents(EquationSet s, List<EventTarget> eventTargets, List<Variable> eventReferences, List<Delay> delays) {
    class EventVisitor implements Visitor {

        public boolean found;

        public boolean visit(Operator op) {
            if (op instanceof Delay) {
                delays.add((Delay) op);
            } else if (op instanceof Event) {
                found = true;
                Event de = (Event) op;
                if (// this event has not yet been analyzed
                de.eventType == null) {
                    final EventTarget et = new EventTarget(de);
                    int targetIndex = eventTargets.indexOf(et);
                    if (// event target already exists
                    targetIndex >= 0) {
                        de.eventType = eventTargets.get(targetIndex);
                    } else // we must create a new event target, or more properly, fill in the event target we just used as a query object
                    {
                        // Create an entry and save the index
                        targetIndex = eventTargets.size();
                        eventTargets.add(et);
                        de.eventType = et;
                        et.container = s;
                        // Determine edge type
                        if (de.operands.length < 3) {
                            et.edge = EventTarget.RISE;
                        } else if (de.operands[2] instanceof Constant) {
                            Constant c = (Constant) de.operands[2];
                            if (c.value instanceof Text) {
                                Text t = (Text) c.value;
                                if (t.value.equalsIgnoreCase("nonzero"))
                                    et.edge = EventTarget.NONZERO;
                                else if (t.value.equalsIgnoreCase("change"))
                                    et.edge = EventTarget.CHANGE;
                                else if (t.value.equalsIgnoreCase("fall"))
                                    et.edge = EventTarget.FALL;
                                else
                                    et.edge = EventTarget.RISE;
                            } else {
                                Backend.err.get().println("ERROR: event() edge type must be a string.");
                                throw new Backend.AbortRun();
                            }
                        } else {
                            Backend.err.get().println("ERROR: event() edge type must be constant.");
                            throw new Backend.AbortRun();
                        }
                        // Allocate auxiliary variable
                        if (de.operands[0] instanceof AccessVariable) {
                            AccessVariable av = (AccessVariable) de.operands[0];
                            VariableReference reference = av.reference;
                            Variable v = reference.variable;
                            // then the user has broken the rule that we can't see temporaries in other parts.
                            if (v.hasAttribute("temporary") && v.container != s) {
                                Backend.err.get().println("WARNING: Cannot be temporary due to event monitor: " + v.fullName() + " from " + s.name);
                                v.removeAttribute("temporary");
                            }
                            // so fall through to the !trackOne case below.
                            if (!v.hasAttribute("temporary")) {
                                // ensure it's buffered, so we can detect change
                                v.addAttribute("externalRead");
                                et.trackOne = true;
                                // just a holder for the reference
                                et.track = new Variable("");
                                et.track.reference = reference;
                            }
                        }
                        if (// Expression, so create auxiliary variable. Aux not needed for NONZERO, because no change detection.
                        !et.trackOne && et.edge != EventTarget.NONZERO) {
                            et.track = new Variable("$eventAux" + targetIndex);
                            et.track.container = s;
                            et.track.type = new Scalar(0);
                            et.track.reference = new VariableReference();
                            et.track.reference.variable = et.track;
                            // Make executable so it can be directly evaluated during the init cycle.
                            et.track.equations = new TreeSet<EquationEntry>();
                            EquationEntry ee = new EquationEntry(et.track, "");
                            et.track.equations.add(ee);
                            ee.expression = et.event.operands[0].deepCopy();
                            ee.expression.addDependencies(et.track);
                        }
                        // Locate any temporaries for evaluation.
                        // Tie into the dependency graph using a phantom variable (which can go away afterward without damaging the graph).
                        // TODO: for more efficiency, we could have separate lists of temporaries for the condition and delay operands
                        // TODO: for more efficiency, cut off search for temporaries along a given branch of the tree at the first non-temporary.
                        final Variable phantom = new Variable("event");
                        phantom.uses = new IdentityHashMap<Variable, Integer>();
                        phantom.container = s;
                        et.event.visit(new Visitor() {

                            public boolean visit(Operator op) {
                                if (op instanceof AccessVariable) {
                                    AccessVariable av = (AccessVariable) op;
                                    Variable v = av.reference.variable;
                                    if (v.hasAttribute("temporary") && !phantom.uses.containsKey(v))
                                        phantom.uses.put(v, 1);
                                    return false;
                                }
                                return true;
                            }
                        });
                        // Scan all variables in equation set to see if we need them
                        for (Variable t : s.ordered) {
                            if (t.hasAttribute("temporary") && phantom.dependsOn(t) != null)
                                et.dependencies.add(t);
                        }
                        // Note the default is already set to -1 (no care)
                        class DelayVisitor implements Visitor {

                            TreeSet<EquationSet> containers = new TreeSet<EquationSet>();

                            public boolean visit(Operator op) {
                                if (op instanceof AccessVariable) {
                                    AccessVariable av = (AccessVariable) op;
                                    // could include the target part itself, if in fact we use local variables
                                    containers.add(av.reference.variable.container);
                                    return false;
                                }
                                return true;
                            }
                        }
                        DelayVisitor dv = new DelayVisitor();
                        if (de.operands.length >= 2) {
                            if (de.operands[1] instanceof Constant) {
                                Constant c = (Constant) de.operands[1];
                                et.delay = (float) ((Scalar) c.value).value;
                                if (et.delay < 0)
                                    et.delay = -1;
                            } else {
                                // indicates that we need to evaluate delay at run time
                                et.delay = -2;
                                de.operands[1].visit(dv);
                            }
                        }
                        // Set up monitors in source parts
                        class ConditionVisitor implements Visitor {

                            TreeSet<EquationSet> containers = new TreeSet<EquationSet>();

                            public boolean visit(Operator op) {
                                if (op instanceof AccessVariable) {
                                    AccessVariable av = (AccessVariable) op;
                                    Variable v = av.reference.variable;
                                    EquationSet sourceContainer = v.container;
                                    containers.add(sourceContainer);
                                    // Set up monitors for values that can vary during update.
                                    if (!v.hasAttribute("constant") && !v.hasAttribute("initOnly") && !et.monitors(sourceContainer)) {
                                        EventSource es = new EventSource(sourceContainer, et);
                                        // null means self-reference, a special case handled in Part
                                        if (sourceContainer != s)
                                            es.reference = av.reference;
                                        et.sources.add(es);
                                    }
                                    return false;
                                }
                                return true;
                            }
                        }
                        ConditionVisitor cv = new ConditionVisitor();
                        de.operands[0].visit(cv);
                        // Special case for event with no references that vary
                        if (et.sources.isEmpty()) {
                            // We can avoid creating a self monitor if we know for certain that the event will never fire
                            boolean neverFires = false;
                            if (de.operands[0] instanceof Constant) {
                                if (et.edge == EventTarget.NONZERO) {
                                    Type op0 = ((Constant) de.operands[0]).value;
                                    if (op0 instanceof Scalar) {
                                        neverFires = ((Scalar) op0).value == 0;
                                    } else {
                                        Backend.err.get().println("ERROR: Condition for event() must resolve to a number.");
                                        throw new Backend.AbortRun();
                                    }
                                } else {
                                    neverFires = true;
                                }
                            }
                            if (!neverFires) {
                                EventSource es = new EventSource(s, et);
                                // This is a self-reference, so es.reference should be null.
                                et.sources.add(es);
                            }
                        }
                        // Determine if monitor needs to test every target, or if one representative target is sufficient
                        for (EventSource source : et.sources) {
                            // associated with any given source instance, so every target must be evaluated separately.
                            if (cv.containers.size() > 1)
                                source.testEach = true;
                            if (dv.containers.size() > 1 || (dv.containers.size() == 1 && dv.containers.first() != source.container))
                                source.delayEach = true;
                        }
                    }
                }
            }
            return true;
        }
    }
    EventVisitor eventVisitor = new EventVisitor();
    for (Variable v : s.variables) {
        eventVisitor.found = false;
        v.visit(eventVisitor);
        if ((eventVisitor.found || v.dependsOnEvent()) && v.reference.variable != v)
            eventReferences.add(v);
    }
}
Also used : Operator(gov.sandia.n2a.language.Operator) EquationSet(gov.sandia.n2a.eqset.EquationSet) AccessVariable(gov.sandia.n2a.language.AccessVariable) Variable(gov.sandia.n2a.eqset.Variable) AccessVariable(gov.sandia.n2a.language.AccessVariable) VariableReference(gov.sandia.n2a.eqset.VariableReference) Visitor(gov.sandia.n2a.language.Visitor) Constant(gov.sandia.n2a.language.Constant) IdentityHashMap(java.util.IdentityHashMap) Text(gov.sandia.n2a.language.type.Text) Delay(gov.sandia.n2a.language.function.Delay) Scalar(gov.sandia.n2a.language.type.Scalar) Type(gov.sandia.n2a.language.Type) Backend(gov.sandia.n2a.plugins.extpoints.Backend) TreeSet(java.util.TreeSet) Event(gov.sandia.n2a.language.function.Event) EquationEntry(gov.sandia.n2a.eqset.EquationEntry)

Aggregations

AccessVariable (gov.sandia.n2a.language.AccessVariable)7 Operator (gov.sandia.n2a.language.Operator)7 Event (gov.sandia.n2a.language.function.Event)7 Constant (gov.sandia.n2a.language.Constant)4 Type (gov.sandia.n2a.language.Type)4 Visitor (gov.sandia.n2a.language.Visitor)4 Scalar (gov.sandia.n2a.language.type.Scalar)4 Text (gov.sandia.n2a.language.type.Text)4 EquationSet (gov.sandia.n2a.eqset.EquationSet)3 Variable (gov.sandia.n2a.eqset.Variable)3 BuildMatrix (gov.sandia.n2a.language.BuildMatrix)3 Input (gov.sandia.n2a.language.function.Input)3 ReadMatrix (gov.sandia.n2a.language.function.ReadMatrix)3 Add (gov.sandia.n2a.language.operator.Add)3 Modulo (gov.sandia.n2a.language.operator.Modulo)3 Matrix (gov.sandia.n2a.language.type.Matrix)3 VariableReference (gov.sandia.n2a.eqset.VariableReference)2 AccessElement (gov.sandia.n2a.language.AccessElement)2 Delay (gov.sandia.n2a.language.function.Delay)2 Exp (gov.sandia.n2a.language.function.Exp)2