de.tuberlin.uebb.jdae.llmsl.ExecutableDAE.java Source code

Java tutorial

Introduction

Here is the source code for de.tuberlin.uebb.jdae.llmsl.ExecutableDAE.java

Source

/*
 * Copyright (C) 2012 uebb.tu-berlin.de.
 *
 * This file is part of modim
 *
 * modim is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * modim is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with modim. If not, see <http://www.gnu.org/licenses/>.
 */

package de.tuberlin.uebb.jdae.llmsl;

import gnu.trove.iterator.TIntObjectIterator;
import gnu.trove.map.TIntObjectMap;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.math3.exception.DimensionMismatchException;
import org.apache.commons.math3.exception.MaxCountExceededException;
import org.apache.commons.math3.ode.FirstOrderDifferentialEquations;
import org.apache.commons.math3.ode.events.EventHandler;

import com.google.common.collect.Range;
import com.google.common.collect.Sets;

import de.tuberlin.uebb.jdae.hlmsl.Unknown;
import de.tuberlin.uebb.jdae.llmsl.events.ContinuousEvent;
import de.tuberlin.uebb.jdae.llmsl.events.EventEffect;
import de.tuberlin.uebb.jdae.llmsl.events.EventEvaluator;
import de.tuberlin.uebb.jdae.simulation.ResultStorage;
import de.tuberlin.uebb.jdae.simulation.SimulationOptions;
import de.tuberlin.uebb.jdae.transformation.Causalisation;
import de.tuberlin.uebb.jdae.transformation.DerivedEquation;
import de.tuberlin.uebb.jdae.transformation.InitializationCausalisation;
import de.tuberlin.uebb.jdae.transformation.Reduction;

public final class ExecutableDAE implements FirstOrderDifferentialEquations {

    public final SimulationOptions options;
    public final double[][] data;
    public final EventEvaluator eventHandler;
    public final DataLayout layout;
    public final IBlock[] blocks;
    public final List<GlobalVariable> states;
    private final Logger logger;
    public final IBlock[] initials;
    private int evaluations;
    public long time;

    public final ExecutionContext execCtxt;

    public int getEvaluations() {
        return evaluations;
    }

    public ExecutableDAE(final DataLayout layout, Causalisation causalisation,
            InitializationCausalisation iCausalisation, final ContinuousEvent[] continuousEvents,
            SimulationOptions options) {
        this.options = options;
        this.logger = Logger.getLogger(this.getClass().toString());

        this.layout = layout;
        this.states = causalisation.states;
        data = layout.alloc();

        this.blocks = new IBlock[causalisation.computations.size()];
        int i = 0;
        for (TIntObjectMap<Range<Integer>> block : causalisation.computations) {

            final Set<DerivedEquation> deriveds = Sets.newHashSet();
            final TIntObjectIterator<Range<Integer>> blockIter = block.iterator();
            while (blockIter.hasNext()) {
                blockIter.advance();
                final int eq = blockIter.key();
                final Range<Integer> eqRange = blockIter.value();

                deriveds.add(new DerivedEquation(causalisation.equations[eq], eqRange.lowerEndpoint(),
                        eqRange.upperEndpoint()));
            }

            final IBlock block_i;
            /* always prepare a numerical fallback, just in case */
            final IBlock numericalSolution = new Block(data, layout, causalisation.iteratees.get(i), deriveds,
                    options);

            if (causalisation.iteratees.get(i).size() == 1) {
                /* causalisation */
                final GlobalVariable var = causalisation.iteratees.get(i).iterator().next();
                final GlobalEquation eq = deriveds.iterator().next().eqn;

                if (eq.canSpecializeFor(var)) {
                    block_i = eq.specializeFor(var, numericalSolution, this);
                } else {
                    block_i = numericalSolution;
                }
            } else {
                block_i = numericalSolution;
            }

            blocks[i++] = block_i;

        }
        i = 0;

        this.initials = new IBlock[iCausalisation.computations.size()];
        for (Set<DerivedEquation> block : iCausalisation.computations)
            initials[i] = new Block(data, layout, iCausalisation.iteratees.get(i++), block, options);

        this.execCtxt = new ExecutionContext(0, new GlobalVariable[0], data);

        // must be last, calls methods here
        this.eventHandler = new EventEvaluator(this, continuousEvents);
    }

    public ExecutableDAE(final DataLayout layout, final IBlock[] blocks, final IBlock[] initials,
            final List<GlobalVariable> states, SimulationOptions options) {

        this.options = options;
        this.eventHandler = new EventEvaluator(this, new ContinuousEvent[0]);
        this.logger = Logger.getLogger(this.getClass().toString());
        this.layout = layout;
        this.states = states;
        data = layout.alloc();

        this.blocks = blocks.clone();
        this.initials = initials.clone();
        this.execCtxt = new ExecutionContext(0, new GlobalVariable[0], data);
    }

    public void initialize() {
        for (IBlock iB : initials)
            iB.exec();
    }

    public void integrate(final ResultStorage results) {
        evaluations = 0;
        data[0][0] = options.startTime;

        if (options.integrator != null) {
            integrateApacheCommonsIntegrator(options);
        } else {
            switch (options.inlineIntegrator) {
            case INLINE_FORWARD_EULER:
                integrateInlineForwardEuler(results, options);
                break;
            }
        }
    }

    private void integrateInlineForwardEuler(final ResultStorage results, SimulationOptions options) {
        final long s = System.currentTimeMillis();
        double stepSize = options.minStepSize;

        while (data[0][0] < options.stopTime) {
            data[0][0] += stepSize;

            if (options.stopTime - data[0][0] < stepSize)
                stepSize = options.stopTime - data[0][0];

            evaluations++;

            for (int i = 0; i < blocks.length; i++) {
                blocks[i].exec();
            }

            for (GlobalVariable state : states) {
                data[state.index][state.der] += data[state.index][state.der + 1] * stepSize;
            }

            final Collection<EventEffect> effects = eventHandler.calculateEffects();

            if (!effects.isEmpty()) {
                ExecutableDAE nextDae = this;

                for (EventEffect effect : effects) {
                    nextDae = effect.apply(nextDae);
                }

                if (nextDae != this) {
                    throw new RuntimeException("Cannot handle structural changes yet.");
                }
            }

            /* accept step */
            eventHandler.acceptLastStep();
            results.addResult(data);
        }

        time += (System.currentTimeMillis() - s);
    }

    public void integrateApacheCommonsIntegrator(final SimulationOptions options) {
        logger.log(Level.INFO, "Starting integration.");

        for (EventHandler handler : eventHandler.getEventHandlers())
            options.integrator.addEventHandler(handler, options.maxStepSize, options.tolerance, 1000);

        final double[] stateVector = new double[states.size()];

        writeStates(stateVector);

        while (data[0][0] < options.stopTime) {
            data[0][0] = options.integrator.integrate(this, data[0][0], stateVector, options.stopTime, stateVector);

            if (eventHandler.getResult() != null && eventHandler.getResult().t == data[0][0]) {
                final ExecutableDAE next = eventHandler.getResult().effect.apply(this);
                eventHandler.acceptLastStep();
                if (next != this) {
                    throw new RuntimeException("Cannot handle structural changes yet.");
                }
            }

            writeStates(stateVector);
        }
    }

    private void writeStates(final double[] stateVector) {
        int i = 0;
        for (GlobalVariable state : states)
            stateVector[i++] = load(state);
    }

    @Override
    public int getDimension() {
        return states.size();
    }

    public double load(GlobalVariable v) {
        return data[v.index][v.der];
    }

    public void set(GlobalVariable v, double d) {
        data[v.index][v.der] = d;
    }

    @Override
    public void computeDerivatives(double t, double[] y, double[] yDot)
            throws MaxCountExceededException, DimensionMismatchException {
        setState(t, y);

        computeDerivatives(0, blocks.length);

        for (int i = 0; i < states.size(); i++) {
            yDot[i] = load(states.get(i).der());
        }
    }

    public void computeDerivatives(final int from, final int to) {
        final long s = System.currentTimeMillis();

        evaluations++;

        for (int i = from; i < to; i++) {
            blocks[i].exec();
        }

        time += (System.currentTimeMillis() - s);
    }

    public void setState(double t, double[] y) {
        data[0][0] = t;

        for (int i = 0; i < states.size(); i++) {
            set(states.get(i), y[i]);
        }
    }

    public double load(Reduction reduction, Unknown x) {
        return load(reduction.ctxt.get(x));
    }

    public double time() {
        return data[0][0];
    }

    public int lastBlock(final Collection<GlobalVariable> vars) {
        final Set<GlobalVariable> left = Sets.newTreeSet(vars);
        left.removeAll(states);

        int i = 0;
        while (!left.isEmpty() && i < blocks.length) {
            for (GlobalVariable gv : blocks[i].variables())
                left.remove(gv);
            i++;
        }

        if (!left.isEmpty())
            throw new RuntimeException("The following variables are not computed: " + left.toString());
        return i;
    }

    public ExecutableDAE(SimulationOptions options, double[][] data, EventEvaluator eventHandler, DataLayout layout,
            IBlock[] blocks, List<GlobalVariable> states, Logger logger, IBlock[] initials, int evaluations,
            long time, ExecutionContext execCtxt) {
        super();
        this.options = options;
        this.data = data;
        this.eventHandler = eventHandler;
        this.layout = layout;
        this.blocks = blocks;
        this.states = states;
        this.logger = logger;
        this.initials = initials;
        this.evaluations = evaluations;
        this.time = time;
        this.execCtxt = execCtxt;
    }

    public ExecutableDAE withOptions(SimulationOptions options2) {
        return new ExecutableDAE(options2, data, eventHandler, layout, blocks, states, logger, initials,
                evaluations, time, execCtxt);
    }

}