Search in sources :

Example 56 with EquationSet

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

the class InternalBackendData method analyzeEvents.

/**
 *        Find event() calls and collate them (in case the same signature appears several different places
 *        in the equation set).
 *        This must be done before the variables are sorted into sets according to attributes, because we
 *        may need to add the "externalRead" attribute to some of them.
 */
public void analyzeEvents(EquationSet s) {
    analyzeEvents(s, eventTargets, eventReferences, delays);
    // Allocate storage for Event
    int valueIndex = -1;
    int mask = 0;
    int eventIndex = 0;
    for (EventTarget et : eventTargets) {
        if (valueIndex == -1) {
            valueIndex = countLocalFloat++;
            namesLocalFloat.add("eventLatch" + valueIndex);
            eventLatches.add(valueIndex);
            mask = 1;
        }
        et.valueIndex = valueIndex;
        et.mask = mask;
        mask <<= 1;
        // Due to limitations of float-int conversion, only 23 bits are available. Allocate another float.
        if (mask > 0x400000)
            valueIndex = -1;
        if (// We have an auxiliary variable.
        !et.trackOne && et.edge != EventTarget.NONZERO) {
            et.track.readIndex = et.track.writeIndex = allocateLocalFloat(et.track.name);
            // Preemptively add this, because the main analyze() routine won't see it.
            // We put the aux in init so that it can pick up the initial value without a call
            // to EventTarget.test(). Note that dependencies have been set when the aux was
            // created, so it will execute in the correct order with all the other init variables.
            localInit.add(et.track);
        }
        // the same part. Since #2 is already a rare case, we won't worry about trapping this.
        if (et.edge == EventTarget.NONZERO && (et.sources.size() > 1 || et.sources.get(0).container == et.container && (et.delay == 0 || et.delay == -2))) {
            et.timeIndex = allocateLocalFloat("eventTime" + eventIndex);
        }
        // TODO: What if two different event targets in this part reference the same source part? What if the condition is different? The same?
        for (EventSource es : et.sources) {
            EquationSet sourceContainer = es.container;
            InternalBackendData sourceBed = (InternalBackendData) sourceContainer.backendData;
            // TODO: Consolidate monitors that share the same trigger condition.
            es.monitorIndex = sourceBed.allocateLocalObject("eventMonitor_" + s.prefix());
            sourceBed.eventSources.add(es);
        }
        eventIndex++;
    }
    // Allocate storage for Delay
    int i = 0;
    for (Delay d : delays) {
        d.index = allocateLocalObject("delay" + i++);
    }
}
Also used : EquationSet(gov.sandia.n2a.eqset.EquationSet) Delay(gov.sandia.n2a.language.function.Delay)

Example 57 with EquationSet

use of gov.sandia.n2a.eqset.EquationSet 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)

Example 58 with EquationSet

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

the class InternalBackendData method analyzeConversions.

public void analyzeConversions(EquationSet s) {
    // Type conversions
    // forbid $index and all phase variables. TODO: create attributes just for this?
    List<String> forbiddenVariables = Arrays.asList("$type", "$index", "$live", "$init", "$connect");
    for (EquationSet target : s.getConversionTargets()) {
        if (s.connectionBindings == null) {
            if (target.connectionBindings != null)
                throw new EvaluationException("Can't change $type from compartment to connection.");
        } else {
            if (target.connectionBindings == null)
                throw new EvaluationException("Can't change $type from connection to compartment.");
        }
        Conversion conversion = new Conversion();
        conversions.put(target, conversion);
        // Match variables
        InternalBackendData targetBed = (InternalBackendData) target.backendData;
        for (Variable v : targetBed.localMembers) {
            if (forbiddenVariables.contains(v.name))
                continue;
            // find() does not consider container
            Variable v2 = s.find(v);
            if (v2 != null) {
                conversion.to.add(v);
                conversion.from.add(v2);
            }
        }
        // Match connection bindings
        if (// Since we checked above, we know that target is also a connection.
        s.connectionBindings != null) {
            conversion.bindings = new int[s.connectionBindings.size()];
            int i = 0;
            for (ConnectionBinding c : s.connectionBindings) {
                conversion.bindings[i] = -1;
                int j = 0;
                for (ConnectionBinding d : target.connectionBindings) {
                    if (c.alias.equals(d.alias)) {
                        conversion.bindings[i] = j;
                        break;
                    }
                    j++;
                }
                // Note: ALL bindings must match. There is no other mechanism for initializing the endpoints.
                if (conversion.bindings[i] < 0)
                    throw new EvaluationException("Unfulfilled connection binding during $type change.");
                i++;
            }
        }
    // TODO: Match populations?
    // Currently, any contained populations do not carry over to new instance. Instead, it must create them from scratch.
    }
}
Also used : EquationSet(gov.sandia.n2a.eqset.EquationSet) AccessVariable(gov.sandia.n2a.language.AccessVariable) Variable(gov.sandia.n2a.eqset.Variable) ConnectionBinding(gov.sandia.n2a.eqset.EquationSet.ConnectionBinding) EvaluationException(gov.sandia.n2a.language.EvaluationException)

Example 59 with EquationSet

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

the class InternalBackend method analyzeLastT.

public static void analyzeLastT(EquationSet s) {
    InternalBackendData bed = (InternalBackendData) s.backendData;
    bed.analyzeLastT(s);
    for (EquationSet p : s.parts) analyzeLastT(p);
}
Also used : EquationSet(gov.sandia.n2a.eqset.EquationSet)

Example 60 with EquationSet

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

the class InternalBackend method analyzeEvents.

public static void analyzeEvents(EquationSet s) throws Backend.AbortRun {
    InternalBackendData bed = (InternalBackendData) s.backendData;
    bed.analyzeEvents(s);
    for (EquationSet p : s.parts) analyzeEvents(p);
}
Also used : EquationSet(gov.sandia.n2a.eqset.EquationSet)

Aggregations

EquationSet (gov.sandia.n2a.eqset.EquationSet)63 Variable (gov.sandia.n2a.eqset.Variable)25 AccessVariable (gov.sandia.n2a.language.AccessVariable)24 ConnectionBinding (gov.sandia.n2a.eqset.EquationSet.ConnectionBinding)16 ArrayList (java.util.ArrayList)16 EquationEntry (gov.sandia.n2a.eqset.EquationEntry)12 Operator (gov.sandia.n2a.language.Operator)12 MNode (gov.sandia.n2a.db.MNode)11 MPart (gov.sandia.n2a.eqset.MPart)10 Constant (gov.sandia.n2a.language.Constant)10 Scalar (gov.sandia.n2a.language.type.Scalar)10 IncommensurableException (javax.measure.IncommensurableException)9 UnconvertibleException (javax.measure.UnconvertibleException)9 AbortRun (gov.sandia.n2a.plugins.extpoints.Backend.AbortRun)8 VariableReference (gov.sandia.n2a.eqset.VariableReference)7 Type (gov.sandia.n2a.language.Type)7 ExtensionPoint (gov.sandia.n2a.plugins.ExtensionPoint)7 EventTarget (gov.sandia.n2a.backend.internal.InternalBackendData.EventTarget)6 Visitor (gov.sandia.n2a.language.Visitor)6 EventSource (gov.sandia.n2a.backend.internal.InternalBackendData.EventSource)5