/**
   * @param tree
   * @param node
   * @return and array of the total amount of time spent in each of the discrete states along the
   *     branch above the given node.
   */
  private double[] getProcessValues(final Tree tree, final NodeRef node) {

    double[] processValues = null;
    double branchTime = tree.getBranchLength(node);

    if (mode == Mode.MARKOV_JUMP_PROCESS) {
      processValues = (double[]) trait.getTrait(tree, node);
    } else if (mode == Mode.PARSIMONY) {
      // an approximation to dwell times using parsimony, assuming
      // the state changes midpoint on the tree. Does a weighted
      // average of the equally parsimonious state reconstructions
      // at the top and bottom of each branch.

      if (treeChanged) {
        fitchParsimony.initialize(tree);
        // Debugging test to count work
        //                treeInitializeCounter += 1;
        //                if (treeInitializeCounter % 10 == 0) {
        //                    System.err.println("Cnt: "+treeInitializeCounter);
        //                }
        treeChanged = false;
      }
      int[] states = fitchParsimony.getStates(tree, node);
      int[] parentStates = fitchParsimony.getStates(tree, tree.getParent(node));

      processValues = new double[fitchParsimony.getPatterns().getStateCount()];

      for (int state : states) {
        processValues[state] += branchTime / 2;
      }
      for (int state : parentStates) {
        processValues[state] += branchTime / 2;
      }

      for (int i = 0; i < processValues.length; i++) {
        // normalize by the number of equally parsimonious states at each end of the branch
        // processValues should add up to the total branch length
        processValues[i] /= (states.length + parentStates.length) / 2;
      }
    } else if (mode == Mode.NODE_STATES) {
      processValues = new double[dataType.getStateCount()];
      //            if (indicatorParameter != null) {
      //                // this array should be size #states NOT #rates
      //                processValues = new double[indicatorParameter.getDimension()];
      //            } else {
      //                // this array should be size #states NOT #rates
      //                processValues = new double[rateParameter.getDimension()];
      //            }

      // if the states are being sampled - then there is only one possible state at each
      // end of the branch.
      int state = ((int[]) trait.getTrait(tree, node))[traitIndex];
      processValues[state] += branchTime / 2;
      int parentState = ((int[]) trait.getTrait(tree, tree.getParent(node)))[traitIndex];
      processValues[parentState] += branchTime / 2;
    }

    return processValues;
  }
  /**
   * A constructor for a node-sampled discrete trait
   *
   * @param treeModel
   * @param trait
   * @param traitIndex
   * @param rateParameter
   * @param relativeRatesParameter
   * @param indicatorParameter
   */
  public DiscreteTraitBranchRateModel(
      TreeTraitProvider traitProvider,
      DataType dataType,
      TreeModel treeModel,
      TreeTrait trait,
      int traitIndex,
      Parameter rateParameter,
      Parameter relativeRatesParameter,
      Parameter indicatorParameter) {

    this(treeModel, traitIndex, rateParameter, relativeRatesParameter, indicatorParameter);

    //        if (trait.getTreeModel() != treeModel)
    //            throw new IllegalArgumentException("Tree Models for ancestral state tree
    // likelihood and target model of these rates must match!");

    this.trait = trait;
    this.dataType = dataType;

    if (trait.getTraitName().equals("states")) {
      // Assume the trait is one or more discrete traits reconstructed at nodes
      mode = Mode.NODE_STATES;
    } else /*if (double[].class.isAssignableFrom(trait.getClass()))*/ {
      // Assume the trait itself is the dwell times for the individual states on the branch above
      // the node
      mode = Mode.MARKOV_JUMP_PROCESS;
    } /* else {
          throw new IllegalArgumentException("The trait class type is not suitable for use in this class.");
      } */

    if (traitProvider instanceof Model) {
      addModel((Model) traitProvider);
    }

    if (trait instanceof Model) {
      addModel((Model) trait); // MAS: Does this ever occur?
    }
  }