/**
   * Write the marginalLikelihoodEstimator, pathSamplingAnalysis and steppingStoneSamplingAnalysis
   * blocks.
   *
   * @param writer XMLWriter
   */
  public void writeMLE(XMLWriter writer, MarginalLikelihoodEstimationOptions options) {

    if (options.performMLE) {

      writer.writeComment("Define marginal likelihood estimator (PS/SS) settings");

      List<Attribute> attributes = new ArrayList<Attribute>();
      // attributes.add(new Attribute.Default<String>(XMLParser.ID, "mcmc"));
      attributes.add(
          new Attribute.Default<Integer>(
              MarginalLikelihoodEstimator.CHAIN_LENGTH, options.mleChainLength));
      attributes.add(
          new Attribute.Default<Integer>(
              MarginalLikelihoodEstimator.PATH_STEPS, options.pathSteps));
      attributes.add(
          new Attribute.Default<String>(
              MarginalLikelihoodEstimator.PATH_SCHEME, options.pathScheme));
      if (!options.pathScheme.equals(MarginalLikelihoodEstimator.LINEAR)) {
        attributes.add(
            new Attribute.Default<Double>(
                MarginalLikelihoodEstimator.ALPHA, options.schemeParameter));
      }

      writer.writeOpenTag(MarginalLikelihoodEstimator.MARGINAL_LIKELIHOOD_ESTIMATOR, attributes);

      writer.writeOpenTag("samplers");
      writer.writeIDref("mcmc", "mcmc");
      writer.writeCloseTag("samplers");

      attributes = new ArrayList<Attribute>();
      attributes.add(new Attribute.Default<String>(XMLParser.ID, "pathLikelihood"));
      writer.writeOpenTag(PathLikelihood.PATH_LIKELIHOOD, attributes);
      writer.writeOpenTag(PathLikelihood.SOURCE);
      writer.writeIDref(CompoundLikelihoodParser.POSTERIOR, CompoundLikelihoodParser.POSTERIOR);
      writer.writeCloseTag(PathLikelihood.SOURCE);
      writer.writeOpenTag(PathLikelihood.DESTINATION);
      writer.writeIDref(CompoundLikelihoodParser.PRIOR, CompoundLikelihoodParser.PRIOR);
      writer.writeCloseTag(PathLikelihood.DESTINATION);
      writer.writeCloseTag(PathLikelihood.PATH_LIKELIHOOD);

      attributes = new ArrayList<Attribute>();
      attributes.add(new Attribute.Default<String>(XMLParser.ID, "MLELog"));
      attributes.add(new Attribute.Default<Integer>("logEvery", options.mleLogEvery));
      attributes.add(new Attribute.Default<String>("fileName", options.mleFileName));
      writer.writeOpenTag("log", attributes);
      writer.writeIDref("pathLikelihood", "pathLikelihood");
      writer.writeCloseTag("log");

      writer.writeCloseTag(MarginalLikelihoodEstimator.MARGINAL_LIKELIHOOD_ESTIMATOR);

      writer.writeComment("Path sampling estimator from collected samples");
      attributes = new ArrayList<Attribute>();
      attributes.add(new Attribute.Default<String>("fileName", options.mleFileName));
      writer.writeOpenTag(PathSamplingAnalysis.PATH_SAMPLING_ANALYSIS, attributes);
      writer.writeTag(
          "likelihoodColumn", new Attribute.Default<String>("name", "pathLikelihood.delta"), true);
      writer.writeTag(
          "thetaColumn", new Attribute.Default<String>("name", "pathLikelihood.theta"), true);
      writer.writeCloseTag(PathSamplingAnalysis.PATH_SAMPLING_ANALYSIS);

      writer.writeComment("Stepping-stone sampling estimator from collected samples");
      attributes = new ArrayList<Attribute>();
      attributes.add(new Attribute.Default<String>("fileName", options.mleFileName));
      writer.writeOpenTag(
          SteppingStoneSamplingAnalysis.STEPPING_STONE_SAMPLING_ANALYSIS, attributes);
      writer.writeTag(
          "likelihoodColumn", new Attribute.Default<String>("name", "pathLikelihood.delta"), true);
      writer.writeTag(
          "thetaColumn", new Attribute.Default<String>("name", "pathLikelihood.theta"), true);
      writer.writeCloseTag(SteppingStoneSamplingAnalysis.STEPPING_STONE_SAMPLING_ANALYSIS);

    } else if (options.performMLEGSS) {

      // First define necessary components for the tree working prior
      if (options.choiceTreeWorkingPrior.equals("Product of exponential distributions")) {
        // more general product of exponentials needs to be constructed

        if (DEBUG) {
          System.err.println("productOfExponentials selected: " + options.choiceTreeWorkingPrior);
        }

        List<Attribute> attributes = new ArrayList<Attribute>();
        attributes.add(new Attribute.Default<String>(XMLParser.ID, "exponentials"));
        attributes.add(new Attribute.Default<String>("fileName", beautiOptions.logFileName));
        attributes.add(
            new Attribute.Default<String>("burnin", "" + beautiOptions.chainLength * 0.10));
        attributes.add(
            new Attribute.Default<String>("parameterColumn", "coalescentEventsStatistic"));
        attributes.add(
            new Attribute.Default<String>(
                "dimension", "" + (beautiOptions.taxonList.getTaxonCount() - 1)));

        writer.writeOpenTag(
            TreeWorkingPriorParsers.PRODUCT_OF_EXPONENTIALS_POSTERIOR_MEANS_LOESS, attributes);
        writer.writeTag(
            TreeModel.TREE_MODEL,
            new Attribute.Default<String>(XMLParser.ID, TreeModel.TREE_MODEL),
            true);
        writer.writeCloseTag(TreeWorkingPriorParsers.PRODUCT_OF_EXPONENTIALS_POSTERIOR_MEANS_LOESS);

      } else {
        // matching coalescent model has to be constructed
        // getting the coalescent model
        if (DEBUG) {
          System.err.println(
              "matching coalescent model selected: " + options.choiceTreeWorkingPrior);
          System.err.println(beautiOptions.getPartitionTreePriors().get(0).getNodeHeightPrior());
        }
        /*for (PartitionTreePrior prior : options.getPartitionTreePriors()) {
            treePriorGenerator.writeTreePriorModel(prior, writer);
            writer.writeText("");
        }*/
        // TODO: extend for more than 1 coalescent model?
        TreePriorType nodeHeightPrior =
            beautiOptions.getPartitionTreePriors().get(0).getNodeHeightPrior();

        switch (nodeHeightPrior) {
          case CONSTANT:
            writer.writeComment("A working prior for the constant population size model.");
            writer.writeOpenTag(
                ConstantPopulationModelParser.CONSTANT_POPULATION_MODEL,
                new Attribute[] {
                  new Attribute.Default<String>(XMLParser.ID, modelPrefix + "constantReference"),
                  new Attribute.Default<String>(
                      "units", Units.Utils.getDefaultUnitName(beautiOptions.units))
                });

            writer.writeOpenTag(ConstantPopulationModelParser.POPULATION_SIZE);
            writeParameter(
                "constantReference.popSize",
                "constant.popSize",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(ConstantPopulationModelParser.POPULATION_SIZE);
            writer.writeCloseTag(ConstantPopulationModelParser.CONSTANT_POPULATION_MODEL);

            writer.writeComment("A working prior for the coalescent.");
            writer.writeOpenTag(
                CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD,
                new Attribute[] {
                  new Attribute.Default<String>(XMLParser.ID, modelPrefix + "coalescentReference")
                });
            writer.writeOpenTag(CoalescentLikelihoodParser.MODEL);
            writer.writeIDref(
                ConstantPopulationModelParser.CONSTANT_POPULATION_MODEL,
                beautiOptions.getPartitionTreePriors().get(0).getPrefix() + "constantReference");
            writer.writeCloseTag(CoalescentLikelihoodParser.MODEL);
            writer.writeOpenTag(CoalescentLikelihoodParser.POPULATION_TREE);
            writer.writeIDref(TreeModel.TREE_MODEL, modelPrefix + TreeModel.TREE_MODEL);
            writer.writeCloseTag(CoalescentLikelihoodParser.POPULATION_TREE);
            writer.writeCloseTag(CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD);

            break;

          case EXPONENTIAL:
            writer.writeComment("A working prior for the exponential growth model.");
            writer.writeOpenTag(
                ExponentialGrowthModelParser.EXPONENTIAL_GROWTH_MODEL,
                new Attribute[] {
                  new Attribute.Default<String>(XMLParser.ID, modelPrefix + "exponentialReference"),
                  new Attribute.Default<String>(
                      "units", Units.Utils.getDefaultUnitName(beautiOptions.units))
                });

            writer.writeOpenTag(ExponentialGrowthModelParser.POPULATION_SIZE);
            writeParameter(
                "exponentialReference.popSize",
                "exponential.popSize",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(ExponentialGrowthModelParser.POPULATION_SIZE);
            writer.writeOpenTag(ExponentialGrowthModelParser.GROWTH_RATE);
            writeParameter(
                "exponentialReference.growthRate",
                "exponential.growthRate",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(ExponentialGrowthModelParser.GROWTH_RATE);
            writer.writeCloseTag(ExponentialGrowthModelParser.EXPONENTIAL_GROWTH_MODEL);

            writer.writeComment("A working prior for the coalescent.");
            writer.writeOpenTag(
                CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD,
                new Attribute[] {
                  new Attribute.Default<String>(XMLParser.ID, modelPrefix + "coalescentReference")
                });
            writer.writeOpenTag(CoalescentLikelihoodParser.MODEL);
            writer.writeIDref(
                ExponentialGrowthModelParser.EXPONENTIAL_GROWTH_MODEL,
                beautiOptions.getPartitionTreePriors().get(0).getPrefix() + "constantReference");
            writer.writeCloseTag(CoalescentLikelihoodParser.MODEL);
            writer.writeOpenTag(CoalescentLikelihoodParser.POPULATION_TREE);
            writer.writeIDref(TreeModel.TREE_MODEL, modelPrefix + TreeModel.TREE_MODEL);
            writer.writeCloseTag(CoalescentLikelihoodParser.POPULATION_TREE);
            writer.writeCloseTag(CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD);

            break;

          case LOGISTIC:
            writer.writeComment("A working prior for the logistic growth model.");
            writer.writeOpenTag(
                LogisticGrowthModelParser.LOGISTIC_GROWTH_MODEL,
                new Attribute[] {
                  new Attribute.Default<String>(XMLParser.ID, modelPrefix + "logisticReference"),
                  new Attribute.Default<String>(
                      "units", Units.Utils.getDefaultUnitName(beautiOptions.units))
                });

            writer.writeOpenTag(LogisticGrowthModelParser.POPULATION_SIZE);
            writeParameter(
                "logisticReference.popSize",
                "logistic.popSize",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(LogisticGrowthModelParser.POPULATION_SIZE);
            writer.writeOpenTag(LogisticGrowthModelParser.GROWTH_RATE);
            writeParameter(
                "logisticReference.growthRate",
                "logistic.growthRate",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(LogisticGrowthModelParser.GROWTH_RATE);
            writer.writeOpenTag(LogisticGrowthModelParser.TIME_50);
            writeParameter(
                "logisticReference.t50",
                "logistic.t50",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(LogisticGrowthModelParser.TIME_50);
            writer.writeCloseTag(LogisticGrowthModelParser.LOGISTIC_GROWTH_MODEL);

            writer.writeComment("A working prior for the coalescent.");
            writer.writeOpenTag(
                CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD,
                new Attribute[] {
                  new Attribute.Default<String>(XMLParser.ID, modelPrefix + "coalescentReference")
                });
            writer.writeOpenTag(CoalescentLikelihoodParser.MODEL);
            writer.writeIDref(
                LogisticGrowthModelParser.LOGISTIC_GROWTH_MODEL,
                beautiOptions.getPartitionTreePriors().get(0).getPrefix() + "constantReference");
            writer.writeCloseTag(CoalescentLikelihoodParser.MODEL);
            writer.writeOpenTag(CoalescentLikelihoodParser.POPULATION_TREE);
            writer.writeIDref(TreeModel.TREE_MODEL, modelPrefix + TreeModel.TREE_MODEL);
            writer.writeCloseTag(CoalescentLikelihoodParser.POPULATION_TREE);
            writer.writeCloseTag(CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD);

            break;

          case EXPANSION:
            writer.writeComment("A working prior for the expansion growth model.");
            writer.writeOpenTag(
                ExpansionModelParser.EXPANSION_MODEL,
                new Attribute[] {
                  new Attribute.Default<String>(XMLParser.ID, modelPrefix + "expansionReference"),
                  new Attribute.Default<String>(
                      "units", Units.Utils.getDefaultUnitName(beautiOptions.units))
                });

            writer.writeOpenTag(ExpansionModelParser.POPULATION_SIZE);
            writeParameter(
                "expansionReference.popSize",
                "expansion.popSize",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(ExpansionModelParser.POPULATION_SIZE);
            writer.writeOpenTag(ExpansionModelParser.GROWTH_RATE);
            writeParameter(
                "expansionReference.growthRate",
                "expansion.growthRate",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(ExpansionModelParser.GROWTH_RATE);
            writer.writeOpenTag(ExpansionModelParser.ANCESTRAL_POPULATION_PROPORTION);
            writeParameter(
                "expansionReference.ancestralProportion",
                "expansion.ancestralProportion",
                beautiOptions.logFileName,
                (int) (options.mleChainLength * 0.10),
                writer);
            writer.writeCloseTag(ExpansionModelParser.ANCESTRAL_POPULATION_PROPORTION);
            writer.writeCloseTag(ExpansionModelParser.EXPANSION_MODEL);

            writer.writeComment("A working prior for the coalescent.");
            writer.writeOpenTag(
                CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD,
                new Attribute[] {
                  new Attribute.Default<String>(XMLParser.ID, modelPrefix + "coalescentReference")
                });
            writer.writeOpenTag(CoalescentLikelihoodParser.MODEL);
            writer.writeIDref(
                ExpansionModelParser.EXPANSION_MODEL,
                beautiOptions.getPartitionTreePriors().get(0).getPrefix() + "constantReference");
            writer.writeCloseTag(CoalescentLikelihoodParser.MODEL);
            writer.writeOpenTag(CoalescentLikelihoodParser.POPULATION_TREE);
            writer.writeIDref(TreeModel.TREE_MODEL, modelPrefix + TreeModel.TREE_MODEL);
            writer.writeCloseTag(CoalescentLikelihoodParser.POPULATION_TREE);
            writer.writeCloseTag(CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD);

            break;

          default:

            // Do not switch to product of exponentials as the coalescentEventsStatistic has not
            // been logged
            // TODO: show menu that explains mismatch between prior and working prior?
            // TODO: but show it when the MCM option is wrongfully being selected, don't do anything
            // here

        }
      }

      writer.writeComment("Define marginal likelihood estimator (GSS) settings");

      List<Attribute> attributes = new ArrayList<Attribute>();
      attributes.add(
          new Attribute.Default<Integer>(
              MarginalLikelihoodEstimator.CHAIN_LENGTH, options.mleChainLength));
      attributes.add(
          new Attribute.Default<Integer>(
              MarginalLikelihoodEstimator.PATH_STEPS, options.pathSteps));
      attributes.add(
          new Attribute.Default<String>(
              MarginalLikelihoodEstimator.PATH_SCHEME, options.pathScheme));
      if (!options.pathScheme.equals(MarginalLikelihoodEstimator.LINEAR)) {
        attributes.add(
            new Attribute.Default<Double>(
                MarginalLikelihoodEstimator.ALPHA, options.schemeParameter));
      }

      writer.writeOpenTag(MarginalLikelihoodEstimator.MARGINAL_LIKELIHOOD_ESTIMATOR, attributes);

      writer.writeOpenTag("samplers");
      writer.writeIDref("mcmc", "mcmc");
      writer.writeCloseTag("samplers");

      attributes = new ArrayList<Attribute>();
      attributes.add(new Attribute.Default<String>(XMLParser.ID, "pathLikelihood"));
      writer.writeOpenTag(PathLikelihood.PATH_LIKELIHOOD, attributes);
      writer.writeOpenTag(PathLikelihood.SOURCE);
      writer.writeIDref(CompoundLikelihoodParser.POSTERIOR, CompoundLikelihoodParser.POSTERIOR);
      writer.writeCloseTag(PathLikelihood.SOURCE);
      writer.writeOpenTag(PathLikelihood.DESTINATION);
      writer.writeOpenTag(CompoundLikelihoodParser.WORKING_PRIOR);

      ArrayList<Parameter> parameters = beautiOptions.selectParameters();

      for (Parameter param : parameters) {
        if (DEBUG) {
          System.err.println(param.toString() + "   " + param.priorType.toString());
        }
        // should leave out those parameters set by the coalescent
        if (param.priorType != PriorType.NONE_TREE_PRIOR) {
          // TODO: frequencies is multidimensional, is that automatically dealt with?
          writer.writeOpenTag(
              WorkingPriorParsers.NORMAL_REFERENCE_PRIOR,
              new Attribute[] {
                new Attribute.Default<String>("fileName", beautiOptions.logFileName),
                new Attribute.Default<String>("parameterColumn", param.getName()),
                new Attribute.Default<String>("burnin", "" + beautiOptions.chainLength * 0.10)
              });
          writeParameterIdref(writer, param);
          writer.writeCloseTag(WorkingPriorParsers.NORMAL_REFERENCE_PRIOR);
        }
      }

      if (options.choiceTreeWorkingPrior.equals("Product of exponential distributions")) {
        writer.writeIDref("productOfExponentialsPosteriorMeansLoess", "exponentials");
      } else {
        writer.writeIDref(CoalescentLikelihoodParser.COALESCENT_LIKELIHOOD, "coalescentReference");
      }

      writer.writeCloseTag(CompoundLikelihoodParser.WORKING_PRIOR);
      writer.writeCloseTag(PathLikelihood.DESTINATION);
      writer.writeCloseTag(PathLikelihood.PATH_LIKELIHOOD);

      attributes = new ArrayList<Attribute>();
      attributes.add(new Attribute.Default<String>(XMLParser.ID, "MLELog"));
      attributes.add(new Attribute.Default<Integer>("logEvery", options.mleLogEvery));
      attributes.add(new Attribute.Default<String>("fileName", options.mleFileName));
      writer.writeOpenTag("log", attributes);
      writer.writeIDref("pathLikelihood", "pathLikelihood");
      writer.writeCloseTag("log");

      writer.writeCloseTag(MarginalLikelihoodEstimator.MARGINAL_LIKELIHOOD_ESTIMATOR);

      writer.writeComment("Generalized stepping-stone sampling estimator from collected samples");
      attributes = new ArrayList<Attribute>();
      attributes.add(new Attribute.Default<String>("fileName", options.mleFileName));
      writer.writeOpenTag(
          GeneralizedSteppingStoneSamplingAnalysis.GENERALIZED_STEPPING_STONE_SAMPLING_ANALYSIS,
          attributes);
      writer.writeTag(
          "sourceColumn", new Attribute.Default<String>("name", "pathLikelihood.source"), true);
      writer.writeTag(
          "destinationColumn",
          new Attribute.Default<String>("name", "pathLikelihood.destination"),
          true);
      writer.writeTag(
          "thetaColumn", new Attribute.Default<String>("name", "pathLikelihood.theta"), true);
      writer.writeCloseTag(
          GeneralizedSteppingStoneSamplingAnalysis.GENERALIZED_STEPPING_STONE_SAMPLING_ANALYSIS);
    }
  }