/** Calculates the actual rates corresponding to the category indices. */
  protected void setupRates() {

    // System.out.println("BRRRTTZZZ " + distributionIndexParameter.getValue(0));
    for (int i = 0; i < tree.getNodeCount(); i++) {
      // rates[i] = distributionModel.quantile(rateCategoryQuantiles.getNodeValue(
      // rateCategoryQuantiles.getTreeModel(), rateCategoryQuantiles.getTreeModel().getNode(i) ));
      if (!tree.isRoot(tree.getNode(i))) {

        if (useQuantilesForRates) {
            /* Using quantiles to represent rates */
          rates[tree.getNode(i).getNumber()] =
              distributionModels[(int) Math.round(distributionIndexParameter.getValue(0))].quantile(
                  rateCategoryQuantiles.getNodeValue(tree, tree.getNode(i)));
        } else {
            /* Not using quantiles to represent rates. This is practically useless for anything else other than simulation */
          rates[tree.getNode(i).getNumber()] =
              rateCategoryQuantiles.getNodeValue(tree, tree.getNode(i));
        }
      }
    }
    /*System.out.print(distributionModels[(int) Math.round(distributionIndexParameter.getValue(0))].getClass().getName() + "\t" + (int) Math.round(distributionIndexParameter.getValue(0)) + "\t" + rates[1] + "\t" + rateCategoryQuantiles.getNodeValue(tree, tree.getNode(1)));// + "\t" + distributionModels[(int) Math.round(distributionIndexParameter.getValue(0))].);
    if(distributionModels[(int) Math.round(distributionIndexParameter.getValue(0))].getClass().getName().equals("dr.inference.distribution.LogNormalDistributionModel")) {
        LogNormalDistributionModel lndm = (LogNormalDistributionModel) distributionModels[(int) Math.round(distributionIndexParameter.getValue(0))];
        System.out.println("\t" + lndm.getS());
    }
    else if (distributionModels[(int) Math.round(distributionIndexParameter.getValue(0))].getClass().getName().equals("dr.inference.distribution.InverseGaussianDistributionModel")) {
        InverseGaussianDistributionModel lndm = (InverseGaussianDistributionModel) distributionModels[(int) Math.round(distributionIndexParameter.getValue(0))];
        System.out.println("\t" + lndm.getS());
    }*/
    if (normalize) computeFactor();
  }
  public SubstitutionModelDelegate(Tree tree, BranchModel branchModel, int bufferPoolSize) {

    if (MEASURE_RUN_TIME) {
      updateTime = 0;
      convolveTime = 0;
    }

    this.tree = tree;

    this.substitutionModelList = branchModel.getSubstitutionModels();

    this.branchModel = branchModel;

    eigenCount = substitutionModelList.size();
    nodeCount = tree.getNodeCount();

    // two eigen buffers for each decomposition for store and restore.
    eigenBufferHelper = new BufferIndexHelper(eigenCount, 0);

    // two matrices for each node less the root
    matrixBufferHelper = new BufferIndexHelper(nodeCount, 0);

    this.extraBufferCount =
        branchModel.requiresMatrixConvolution()
            ? (bufferPoolSize > 0 ? bufferPoolSize : BUFFER_POOL_SIZE_DEFAULT)
            : 0;

    if (branchModel.requiresMatrixConvolution() && this.extraBufferCount < eigenCount) {
      throw new RuntimeException(
          "SubstitutionModelDelegate requires at least "
              + eigenCount
              + " extra buffers to convolve matrices");
    }

    for (int i = 0; i < extraBufferCount; i++) {
      pushAvailableBuffer(i + matrixBufferHelper.getBufferCount());
    }

    // one extra created as a reserve
    // which is used to free up buffers when the avail stack is empty.
    reserveBufferIndex = matrixBufferHelper.getBufferCount() + extraBufferCount;

    if (DEBUG) {
      System.out.println("Creating reserve buffer with index: " + reserveBufferIndex);
    }
  } // END: Constructor
  double calculateNorm(Tree tree) {

    double time = 0.0;
    double rateTime = 0.0;
    for (int i = 0; i < tree.getNodeCount(); i++) {

      NodeRef node = tree.getNode(i);

      if (!tree.isRoot(node)) {

        double branchTime = tree.getBranchLength(node);

        rateTime += getRawBranchRate(tree, node) * branchTime;
        time += branchTime;
      }
    }
    return rateTime / time;
  }
 @Override
 public int getNoOfVertices() {
   return tree.getNodeCount();
 }