DoubleBlockPiecewiseContinuousDynamicSystem.java

/*
 * Created on 2007/04/08
 * Copyright (C) 2007 Koga Laboratory. All rights reserved.
 *
 */
package org.mklab.tool.control.system.continuous;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.ode.DoublePiecewiseContinuousAlgebraicSystem;
import org.mklab.nfc.ode.DoublePiecewiseDifferentialSystem;
import org.mklab.nfc.ode.SolverStopException;
import org.mklab.tool.control.system.DoubleSystemOperator;


/**
 * 区分的微分可能な微分方程式で表現されるブロック連続時間動的システムを表わすクラスです。
 * 
 * @author koga
 * @version $Revision: 1.17 $, 2007/04/08
 */
public class DoubleBlockPiecewiseContinuousDynamicSystem extends DoubleBlockContinuousExplicitDynamicSystem implements DoublePiecewiseDifferentialSystem {

  /** 区分的微分可能システムのリスト */
  private List<DoublePiecewiseDifferentialSystem> piecewiseDifferentialSystems = new ArrayList<>();

  /** 区分的連続代数システムのリスト */
  private List<DoublePiecewiseContinuousAlgebraicSystem> piecewiseContinuousAlgebraicSystems = new ArrayList<>();

  /**
   * 新しく生成された<code>BlockPiecewiseContinuousDynamicSystem</code>オブジェクトを初期化します。
   * 
   * @param elements 隣接行列
   * @param inputNodes 入力ノードの番号のリスト(番号は1から始まります)
   * @param outputNodes 出力ノードの番号のリスト(番号は1から始まります)
   */
  public DoubleBlockPiecewiseContinuousDynamicSystem(DoubleSystemOperator[][] elements, List<Integer> inputNodes, List<Integer> outputNodes) {
    super(elements, inputNodes, outputNodes);
    setupPiecewiseDifferentialSystems();
    setupPiecewiseContinuousAlgebraicSystems();
  }

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("boxing")
  public double getDiscontinuousPoint(double t1, DoubleMatrix state1,  DoubleMatrix input1, double t2, DoubleMatrix state2,  DoubleMatrix input2)
      throws SolverStopException {
    final DoubleMatrix originalState = getState();

    outputEquation(t1, state1);

    final List<DoubleMatrix> differentialSystemInputs1 = getDifferentialSystemInputs();
    final List<DoubleMatrix> differentialSystemStates1 = getDifferentialSystemStates();
    final List<DoubleMatrix> continuousSystemInputs1 = getContinuousSystemInputs();

    outputEquation(t2, state2);

    final List<DoubleMatrix> differentialSystemInputs2 = getDifferentialSystemInputs();
    final List<DoubleMatrix> differentialSystemStates2 = getDifferentialSystemStates();
    final List<DoubleMatrix> continuousSystemInputs2 = getContinuousSystemInputs();

    final List<Double> differentialSystemDiscontinuousPoints = getDiscontinuousPoints(t1, differentialSystemStates1, differentialSystemInputs1, t2, differentialSystemStates2,
        differentialSystemInputs2);
    final List<Double> continuousSystemDiscontinuousPoints = getDiscontinuousPoints(t1, continuousSystemInputs1, t2, continuousSystemInputs2);

    final List<Double> discontinuousPoints = differentialSystemDiscontinuousPoints;
    discontinuousPoints.addAll(continuousSystemDiscontinuousPoints);

    outputEquation(t1, originalState);

    final Double[] sortedPoints = discontinuousPoints.toArray(new Double[discontinuousPoints.size()]);
    Arrays.sort(sortedPoints);
    return sortedPoints[0];
  }

  /**
   * 指定された区間内([(t1,inputs1),(t2,inputs2)]の不連続点の時刻を返します。
   * 
   * @param t1 不連続点の前の時刻
   * @param inputs1 不連続点の前の入力
   * @param t2 不連続点の後の時刻
   * @param inputs2 不連続点の後の入力
   * @return 指定された区間内([(t1,inputs1),(t2,inputs2)]の不連続点の時刻
   * @exception SolverStopException ソルバーが停止された場合
   */
  @SuppressWarnings("boxing")
  private List<Double> getDiscontinuousPoints(double t1, final List<DoubleMatrix> inputs1, double t2, final List<DoubleMatrix> inputs2) throws SolverStopException {
    final List<Double> points = new ArrayList<>();
    for (int i = 0; i < this.piecewiseContinuousAlgebraicSystems.size(); i++) {
      final DoublePiecewiseContinuousAlgebraicSystem system = this.piecewiseContinuousAlgebraicSystems.get(i);
      final DoubleMatrix u1 = inputs1.get(i);
      final DoubleMatrix u2 = inputs2.get(i);
      points.add(system.getDiscontinuousPoint(t1, u1, t2, u2));
    }
    return points;
  }

  /**
   * 指定された区間内([(t1,state1,inputs1),(t2,state2,inputs2)]の不連続点の時刻を返します。
   * 
   * @param t1 不連続点の前の時刻
   * @param states1 不連続点の前の状態
   * @param inputs1 不連続点の前の入力
   * @param t2 不連続点の後の時刻
   * @param states2 不連続点の後の状態
   * @param inputs2 不連続点の後の入力
   * @return 指定された区間内([(t1,x1,inputs1),(t2,x2,inputs2)]の不連続点の時刻
   * @exception SolverStopException ソルバーが停止された場合
   */
  @SuppressWarnings("boxing")
  private List<Double> getDiscontinuousPoints(double t1, List<DoubleMatrix> states1, final List<DoubleMatrix> inputs1, double t2, List<DoubleMatrix> states2, final List<DoubleMatrix> inputs2) throws SolverStopException {
    final List<Double> points = new ArrayList<>();
    for (int i = 0; i < this.piecewiseDifferentialSystems.size(); i++) {
      final DoublePiecewiseDifferentialSystem system = this.piecewiseDifferentialSystems.get(i);
      final DoubleMatrix x1 = states1.get(i);
      final DoubleMatrix x2 = states2.get(i);
      final DoubleMatrix u1 = inputs1.get(i);
      final DoubleMatrix u2 = inputs2.get(i);
      points.add(system.getDiscontinuousPoint(t1, x1, u1, t2, x2, u2));
    }
    return points;
  }

  /**
   * 区分的連続代数システムへの入力を返します。
   * 
   * @return 区分的連続代数システムへの入力
   */
  private List<DoubleMatrix> getContinuousSystemInputs() {
    final List<DoubleMatrix> inputs = new ArrayList<>();
    for (DoublePiecewiseContinuousAlgebraicSystem system : this.piecewiseContinuousAlgebraicSystems) {
      inputs.add(getInputNodeValueOf((DoubleSystemOperator)system).createClone());
    }
    return inputs;
  }

  /**
   * 区分的微分可能システムのへの入力を返します。
   * 
   * @return 区分的微分可能システムのへの入力
   */
  private List<DoubleMatrix> getDifferentialSystemInputs() {
    final List<DoubleMatrix> inputs = new ArrayList<>();
    for (DoublePiecewiseDifferentialSystem system : this.piecewiseDifferentialSystems) {
      inputs.add(getInputNodeValueOf((DoubleSystemOperator)system).createClone());
    }
    return inputs;
  }

  /**
   * 区分的微分可能システムの状態を返します。
   * 
   * @return 区分的微分可能システムの状態
   */
  private List<DoubleMatrix> getDifferentialSystemStates() {
    final List<DoubleMatrix> states = new ArrayList<>();
    for (DoublePiecewiseDifferentialSystem system : this.piecewiseDifferentialSystems) {
      states.add(((DoubleContinuousExplicitDynamicSystem)system).getState().createClone());
    }
    return states;
  }

  /**
   * {@inheritDoc}
   */
  public List<Integer> getPiece(double t, DoubleMatrix state,  DoubleMatrix input) throws SolverStopException {
    final DoubleMatrix originalState = getState();

    setState(state);
    calcNodeValue(t);

    final List<DoubleMatrix> states = getDifferentialSystemStates();

    final List<Integer> differentialSystemPieces = getPieces(t, states);
    final List<Integer> continuousSystemPieces = getPieces(t);

    setState(originalState);
    calcNodeValue(t);

    differentialSystemPieces.addAll(continuousSystemPieces);

    final List<Integer> pieces = differentialSystemPieces;
    pieces.addAll(continuousSystemPieces);

    return pieces;
  }

  /**
   * 区分的連続代数システムの区分の番号のリストを返します。
   * 
   * @param t 時刻
   * 
   * @return 区分的連続代数システムの区分の番号のリスト
   * @exception SolverStopException ソルバーが停止された場合
   */
  private List<Integer> getPieces(double t) throws SolverStopException {
    final List<Integer> pieces = new ArrayList<>();
    for (DoublePiecewiseContinuousAlgebraicSystem system : this.piecewiseContinuousAlgebraicSystems) {
      pieces.addAll(system.getPiece(t, getInputNodeValueOf((DoubleSystemOperator)system)));
    }
    return pieces;
  }

  /**
   * 区分的微分可能システムの区分の番号のリストを返します。
   * 
   * @param t 時刻
   * @param states 状態
   * @return 区分的微分可能システムの区分の番号のリスト
   * @exception SolverStopException ソルバーが停止された場合
   */
  private List<Integer> getPieces(double t, List<DoubleMatrix> states) throws SolverStopException {
    final List<Integer> pieces = new ArrayList<>();
    for (int i = 0; i < this.piecewiseDifferentialSystems.size(); i++) {
      final DoublePiecewiseDifferentialSystem system = this.piecewiseDifferentialSystems.get(i);
      final DoubleMatrix x = states.get(i);
      pieces.addAll(system.getPiece(t, x, getInputNodeValueOf((DoubleSystemOperator)system)));
    }
    return pieces;
  }

  /**
   * 区分的微分可能システムのリストを設定します。
   */
  private void setupPiecewiseDifferentialSystems() {
    this.piecewiseDifferentialSystems.clear();

    final int size = getNodeSize();

    for (int row = 0; row < size; row++) {
      for (int column = 0; column < size; column++) {
        final DoubleSystemOperator system = getSystemOperator(row, column);
        if (system instanceof DoublePiecewiseDifferentialSystem) {
          this.piecewiseDifferentialSystems.add((DoublePiecewiseDifferentialSystem)system);
        }
      }
    }
  }

  /**
   * 区分的連続代数システムのリストを設定します。
   */
  private void setupPiecewiseContinuousAlgebraicSystems() {
    this.piecewiseContinuousAlgebraicSystems.clear();

    final int size = getNodeSize();

    for (int row = 0; row < size; row++) {
      for (int column = 0; column < size; column++) {
        final DoubleSystemOperator system = getSystemOperator(row, column);
        if (system instanceof DoublePiecewiseContinuousAlgebraicSystem) {
          this.piecewiseContinuousAlgebraicSystems.add((DoublePiecewiseContinuousAlgebraicSystem)system);
        }
      }
    }
  }
}