package dr.app.beauti.components.continuous;
import dr.app.beauti.generator.BaseComponentGenerator;
import dr.app.beauti.options.*;
import dr.app.beauti.util.XMLWriter;
import dr.evolution.datatype.ContinuousDataType;
import dr.evolution.util.Taxon;
import dr.evomodelxml.tree.TreeLoggerParser;
import dr.util.Attribute;
import dr.xml.AttributeParser;
/**
* @author Andrew Rambaut
* @version $Id$
*/
public class ContinuousComponentGenerator extends BaseComponentGenerator {
protected ContinuousComponentGenerator(BeautiOptions options) {
super(options);
}
public boolean usesInsertionPoint(InsertionPoint point) {
if (options.getDataPartitions(ContinuousDataType.INSTANCE).size() == 0) {
// Empty, so do nothing
return false;
}
switch (point) {
// case IN_TAXON:
case AFTER_SITE_MODEL:
case AFTER_TREE_LIKELIHOOD:
case IN_OPERATORS:
case IN_MCMC_PRIOR:
case IN_MCMC_LIKELIHOOD:
case IN_FILE_LOG_PARAMETERS:
case IN_FILE_LOG_LIKELIHOODS:
case IN_TREES_LOG:
return true;
default:
return false;
}
}// END: usesInsertionPoint
protected void generate(InsertionPoint point, Object item, XMLWriter writer) {
ContinuousComponentOptions component = (ContinuousComponentOptions) options
.getComponentOptions(ContinuousComponentOptions.class);
switch (point) {
// Don't need this because all traits are written for all taxa:
// case IN_TAXON:
// Taxon taxon = (Taxon)item;
// writeTaxonTraits(taxon, writer);
// break;
case AFTER_SITE_MODEL:
writeMultivariateDiffusionModels(writer, component);
break;
case AFTER_TREE_LIKELIHOOD:
writeMultivariateTreeLikelihoods(writer, component);
break;
case IN_OPERATORS:
writeRRWOperators(writer, component);
writePrecisionGibbsOperators(writer, component);
break;
case IN_MCMC_PRIOR:
writeMultivariatePriors(writer, component);
break;
case IN_MCMC_LIKELIHOOD:
writeMultivariateTreeLikelihoodIdRefs(writer, component);
break;
case IN_FILE_LOG_PARAMETERS:
writePrecisionMatrixIdRefs(writer, component);
break;
case IN_FILE_LOG_LIKELIHOODS:
writeMultivariateTreeLikelihoodIdRefs(writer, component);
break;
case IN_TREES_LOG:
writeTreeLogEntries((PartitionTreeModel)item, writer);
break;
default:
throw new IllegalArgumentException(
"This insertion point is not implemented for "
+ this.getClass().getName());
}
}// END: generate
protected String getCommentLabel() {
return "Multivariate diffusion model";
}
private void writeTaxonTraits(Taxon taxon, XMLWriter writer) {
for (AbstractPartitionData partition : options.getDataPartitions(ContinuousDataType.INSTANCE)) {
writer.writeOpenTag(AttributeParser.ATTRIBUTE, new Attribute[]{
new Attribute.Default<String>(Attribute.NAME, partition.getName())});
StringBuilder sb = new StringBuilder();
boolean first = true;
for (TraitData trait : partition.getTraits()) {
if (!first) {
sb.append(" ");
}
if (taxon.containsAttribute(trait.getName())) {
sb.append(taxon.getAttribute(trait.getName()).toString());
} else {
sb.append("?");
}
first = false;
}
writer.writeText(sb.toString());
writer.writeCloseTag(AttributeParser.ATTRIBUTE);
}
}
private void writeMultivariateDiffusionModels(XMLWriter writer,
ContinuousComponentOptions component) {
boolean first = false;
for (PartitionSubstitutionModel model : component.getOptions().getPartitionSubstitutionModels(ContinuousDataType.INSTANCE)) {
String precisionMatrixId = model.getName() + ".precision";
if (!first) { writer.writeBlankLine(); } else { first = false; }
writeMultivariateDiffusionModel(writer, model, precisionMatrixId);
writer.writeBlankLine();
writeMultivariateWishartPrior(writer, model, precisionMatrixId);
}
}
private void writeMultivariateDiffusionModel(XMLWriter writer,
PartitionSubstitutionModel model,
String precisionMatrixId) {
writer.writeOpenTag("multivariateDiffusionModel",
new Attribute[] {
new Attribute.Default<String>("id", model.getName() + ".diffusionModel")
});
writer.writeOpenTag("precisionMatrix");
writer.writeOpenTag("matrixParameter",
new Attribute[] {
new Attribute.Default<String>("id", precisionMatrixId)
});
for (int i = 0; i < model.getContinuousTraitCount(); i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < model.getContinuousTraitCount(); j++) {
if (j > 0) {
sb.append(" ");
}
if (i == j) {
sb.append(0.05);
} else {
sb.append(0.002);
}
}
writer.writeTag("parameter",
new Attribute[]{
new Attribute.Default<String>("id", "col" + (i + 1)),
new Attribute.Default<String>("value", sb.toString())
}, true);
}
writer.writeCloseTag("matrixParameter");
writer.writeCloseTag("precisionMatrix");
writer.writeCloseTag("multivariateDiffusionModel");
}
private void writeMultivariateWishartPrior(XMLWriter writer,
PartitionSubstitutionModel model,
String precisionMatrixId) {
int n = model.getContinuousTraitCount();
writer.writeOpenTag("multivariateWishartPrior",
new Attribute[] {
new Attribute.Default<String>("id", model.getName() + ".precisionPrior"),
new Attribute.Default<String>("df", "" + n),
});
writer.writeOpenTag("scaleMatrix");
writer.writeOpenTag("matrixParameter");
for (int i = 0; i < n; i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < n; j++) {
if (j > 0) {
sb.append(" ");
}
if (i == j) {
sb.append(1.0);
} else {
sb.append(0.0);
}
}
writer.writeTag("parameter",
new Attribute[]{
new Attribute.Default<String>("value", sb.toString())
}, true);
}
writer.writeCloseTag("matrixParameter");
writer.writeCloseTag("scaleMatrix");
writer.writeOpenTag("data");
writer.writeIDref("parameter", precisionMatrixId);
writer.writeCloseTag("data");
writer.writeCloseTag("multivariateWishartPrior");
}
private void writeMultivariateTreeLikelihoods(XMLWriter writer,
ContinuousComponentOptions component) {
boolean first = true;
for (AbstractPartitionData partitionData : component.getOptions().getDataPartitions(ContinuousDataType.INSTANCE)) {
PartitionSubstitutionModel model = partitionData.getPartitionSubstitutionModel();
String diffusionModelId = model.getName() + ".diffusionModel";
String treeModelId = partitionData.getPartitionTreeModel().getPrefix() + "treeModel";
if (!first) { writer.writeBlankLine(); } else { first = false; }
if (model.getContinuousSubstModelType() != ContinuousSubstModelType.HOMOGENOUS) {
writeRelaxedBranchRateModel(writer, partitionData, treeModelId);
}
writer.writeBlankLine();
writeMultivariateTreeLikelihood(writer, partitionData, diffusionModelId, treeModelId);
if (partitionData.getTraits().size() == 2) {
// if we are analysing bivariate traits we can add these special statistics...
String precisionMatrixId = model.getName() + ".precision";
write2DStatistics(writer, partitionData, precisionMatrixId, treeModelId);
}
}
}
private void writeRelaxedBranchRateModel(XMLWriter writer,
AbstractPartitionData partitionData,
String treeModelId) {
String prefix = partitionData.getName() + ".";
writer.writeOpenTag("discretizedBranchRates",
new Attribute[] {
new Attribute.Default<String>("id",
prefix + "diffusionRates"),
});
writer.writeIDref("treeModel", treeModelId);
writer.writeOpenTag("distribution");
writer.writeOpenTag("onePGammaDistributionModel");
// don't think this needs an id
// new Attribute[] {
// new Attribute.Default<String>("id", prefix + "gamma"),
// });
writer.writeOpenTag("shape");
switch (partitionData.getPartitionSubstitutionModel().getContinuousSubstModelType()) {
case HOMOGENOUS:
throw new IllegalArgumentException("Shouldn't be here");
case CAUCHY_RRW:
writer.writeComment("half DF (i.e., df = 1)");
writer.writeTag("parameter",
new Attribute[]{
// don't think this needs an id
// new Attribute.Default<String>("id", "halfDF"),
new Attribute.Default<String>("value", "0.5")
}, true);
break;
case GAMMA_RRW:
writer.writeComment("half DF");
writer.writeTag("parameter",
new Attribute[]{
new Attribute.Default<String>("id", prefix + "halfDF"),
new Attribute.Default<String>("value", "0.5")
}, true);
break;
default:
throw new IllegalArgumentException("Unknown continuous substitution type");
}
writer.writeCloseTag("shape");
writer.writeCloseTag("onePGammaDistributionModel");
writer.writeCloseTag("distribution");
writer.writeOpenTag("rateCategories");
writer.writeTag("parameter", new Attribute.Default<String>("id", prefix + "rrwCategories"), true);
writer.writeCloseTag("rateCategories");
writer.writeCloseTag("discretizedBranchRates");
}
private void writeMultivariateTreeLikelihood(XMLWriter writer,
AbstractPartitionData partitionData,
String diffusionModelId,
String treeModelId) {
writer.writeOpenTag("multivariateTraitLikelihood",
new Attribute[] {
new Attribute.Default<String>("id", partitionData.getName() + ".traitLikelihood"),
new Attribute.Default<String>("traitName", partitionData.getName()),
new Attribute.Default<String>("useTreeLength", "true"),
new Attribute.Default<String>("scaleByTime", "true"),
new Attribute.Default<String>("reportAsMultivariate", "true"),
new Attribute.Default<String>("reciprocalRates", "true"),
new Attribute.Default<String>("integrateInternalTraits", "true")
});
writer.writeIDref("multivariateDiffusionModel", diffusionModelId);
writer.writeIDref("treeModel", treeModelId);
writer.writeOpenTag("traitParameter");
writer.writeTag("parameter", new Attribute.Default<String>("id", "leaf." + partitionData.getName()), true);
writer.writeCloseTag("traitParameter");
writer.writeOpenTag("conjugateRootPrior");
writer.writeOpenTag("meanParameter");
StringBuilder sb = new StringBuilder();
for (int j = 0; j < partitionData.getTraits().size(); j++) {
if (j > 0) {
sb.append(" ");
}
sb.append(0.0);
}
writer.writeTag("parameter", new Attribute.Default<String>("value", sb.toString()), true);
writer.writeCloseTag("meanParameter");
writer.writeOpenTag("priorSampleSize");
writer.writeTag("parameter", new Attribute.Default<String>("value", "0.001"), true);
writer.writeCloseTag("priorSampleSize");
writer.writeCloseTag("conjugateRootPrior");
if (partitionData.getPartitionSubstitutionModel().getContinuousSubstModelType() != ContinuousSubstModelType.HOMOGENOUS) {
writer.writeIDref("discretizedBranchRates", partitionData.getName() + "." + "diffusionRates");
}
writer.writeCloseTag("multivariateTraitLikelihood");
}
private void write2DStatistics(XMLWriter writer, AbstractPartitionData partitionData, String precisionMatrixId, String treeModelId) {
String prefix = partitionData.getName() + ".";
writer.writeOpenTag("correlation",
new Attribute[] {
new Attribute.Default<String>("id", prefix + "correlation")
});
writer.writeIDref("matrixParameter", precisionMatrixId);
writer.writeCloseTag("correlation");
writer.writeOpenTag("treeLengthStatistic",
new Attribute[] {
new Attribute.Default<String>("id", prefix + "treeLength")
});
writer.writeIDref("treeModel", treeModelId);
writer.writeCloseTag("treeLengthStatistic");
writer.writeOpenTag("productStatistic",
new Attribute[] {
new Attribute.Default<String>("id", prefix + "treeLengthPrecision1")
});
writer.writeIDref("treeLengthStatistic", prefix + "treeLength");
writer.writeOpenTag("subStatistic",
new Attribute[] {
new Attribute.Default<String>("id", prefix + "precision1"),
new Attribute.Default<String>("dimension", "0")
});
writer.writeIDref("parameter", prefix + "col1");
writer.writeCloseTag("subStatistic");
writer.writeCloseTag("productStatistic");
writer.writeOpenTag("productStatistic",
new Attribute[] {
new Attribute.Default<String>("id", prefix + "treeLengthPrecision2")
});
writer.writeIDref("treeLengthStatistic", prefix + "treeLength");
writer.writeOpenTag("subStatistic",
new Attribute[] {
new Attribute.Default<String>("id", prefix + "precision2"),
new Attribute.Default<String>("dimension", "1")
});
writer.writeIDref("parameter", prefix + "col2");
writer.writeCloseTag("subStatistic");
writer.writeCloseTag("productStatistic");
}
private void write2DStatisticsIDrefs(XMLWriter writer, AbstractPartitionData partitionData) {
String prefix = partitionData.getName() + ".";
writer.writeIDref("correlation", prefix + "correlation");
writer.writeIDref("treeLengthStatistic", prefix + "treeLength");
writer.writeIDref("productStatistic", prefix + "treeLengthPrecision1");
writer.writeIDref("productStatistic", prefix + "treeLengthPrecision2");
}
/*
<correlation id="locationCorrelation" dimension1="1" dimension2="2">
<matrixParameter idref="precisionMatrix"/>
</correlation>
<treeLengthStatistic id="treeLength">
<treeModel idref="treeModel"/>
</treeLengthStatistic>
<productStatistic id="treeLengthPrecision1">
<treeLengthStatistic idref="treeLength"/>
<subStatistic id="precision1" dimension="0"> <!-- I do not know why Joseph programmed these to start counting from 0 -->
<parameter idref="col1"/>
</subStatistic>
</productStatistic>
<productStatistic id="treeLengthPrecision2">
<treeLengthStatistic idref="treeLength"/>
<subStatistic id="precision2" dimension="1">
<parameter idref="col2"/>
</subStatistic>
</productStatistic>
<treeDispersionStatistic id="dispersionRate" greatCircleDistance="true">
<treeModel idref="treeModel"/>
<multivariateTraitLikelihood idref="traitLikelihood"/>
</treeDispersionStatistic>
*/
private void writeRRWOperators(XMLWriter writer,
ContinuousComponentOptions component) {
for (AbstractPartitionData partitionData : component.getOptions().getDataPartitions(ContinuousDataType.INSTANCE)) {
ContinuousSubstModelType type = partitionData.getPartitionSubstitutionModel().getContinuousSubstModelType();
if (type != ContinuousSubstModelType.HOMOGENOUS) {
// this is now in the parameter table...
// if (type == ContinuousSubstModelType.GAMMA_RRW) {
// writer.writeOpenTag("scaleOperator",
// new Attribute[] {
// new Attribute.Default<String>("scaleFactor", "0.75"),
// new Attribute.Default<String>("weight", "1")
// });
// writer.writeIDref("parameter", partitionData.getName() + ".halfDF");
// writer.writeCloseTag("scaleOperator");
// }
writer.writeOpenTag("swapOperator",
new Attribute[] {
new Attribute.Default<String>("size", "1"),
new Attribute.Default<String>("weight", "30"),
new Attribute.Default<String>("autoOptimize", "false")
});
writer.writeIDref("parameter", partitionData.getName() + ".rrwCategories");
writer.writeCloseTag("swapOperator");
// See Issue 500:
// http://code.google.com/p/beast-mcmc/issues/detail?id=500&can=1&start=400
// writer.writeOpenTag("randomWalkIntegerOperator",
// new Attribute[] {
// new Attribute.Default<String>("windowSize", "2"),
// new Attribute.Default<String>("weight", "10")
// });
// writer.writeIDref("parameter", partitionData.getName() + ".rrwCategories");
// writer.writeCloseTag("randomWalkIntegerOperator");
writer.writeOpenTag("uniformIntegerOperator",
new Attribute[] {
new Attribute.Default<String>("weight", "10")
});
writer.writeIDref("parameter", partitionData.getName() + ".rrwCategories");
writer.writeCloseTag("uniformIntegerOperator");
}
}
}
private void writePrecisionGibbsOperators(XMLWriter writer,
ContinuousComponentOptions component) {
for (AbstractPartitionData partitionData : component.getOptions().getDataPartitions(ContinuousDataType.INSTANCE)) {
writePrecisionGibbsOperator(writer, component, partitionData);
}
}
private void writePrecisionGibbsOperator(final XMLWriter writer,
final ContinuousComponentOptions component,
AbstractPartitionData partitionData
) {
writer.writeOpenTag("precisionGibbsOperator",
new Attribute[] {
new Attribute.Default<String>("weight", "" + partitionData.getTraits().size())
});
writer.writeIDref("multivariateTraitLikelihood", partitionData.getName() + ".traitLikelihood");
writer.writeIDref("multivariateWishartPrior", partitionData.getPartitionSubstitutionModel().getName() + ".precisionPrior");
writer.writeCloseTag("precisionGibbsOperator");
}
private void writePrecisionMatrixIdRefs(final XMLWriter writer, final ContinuousComponentOptions component) {
for (PartitionSubstitutionModel model : component.getOptions().getPartitionSubstitutionModels(ContinuousDataType.INSTANCE)) {
writer.writeIDref("matrixParameter", model.getName() + ".precision");
if (model.getContinuousTraitCount() == 2) {
// if we are analysing bivariate traits we can add these special statistics...
write2DStatisticsIDrefs(writer, null);
}
}
}
private void writeMultivariatePriors(XMLWriter writer,
ContinuousComponentOptions component) {
for (AbstractPartitionData partitionData : component.getOptions().getDataPartitions(ContinuousDataType.INSTANCE)) {
writer.writeIDref("multivariateWishartPrior", partitionData.getName() + ".precisionPrior");
}
}
private void writeMultivariateTreeLikelihoodIdRefs(XMLWriter writer,
ContinuousComponentOptions component) {
for (AbstractPartitionData partitionData : component.getOptions().getDataPartitions(ContinuousDataType.INSTANCE)) {
writer.writeIDref("multivariateTraitLikelihood", partitionData.getName() + ".traitLikelihood");
}
}
private void writeTreeLogEntries(PartitionTreeModel treeModel, XMLWriter writer) {
for (AbstractPartitionData partitionData : options.getDataPartitions(ContinuousDataType.INSTANCE)) {
if (partitionData.getPartitionTreeModel() == treeModel) {
PartitionSubstitutionModel model = partitionData.getPartitionSubstitutionModel();
writer.writeIDref("multivariateDiffusionModel", model.getName() + ".diffusionModel");
writer.writeIDref("multivariateTraitLikelihood", partitionData.getName() + ".traitLikelihood");
if (model.getContinuousSubstModelType() != ContinuousSubstModelType.HOMOGENOUS) {
writer.writeOpenTag(TreeLoggerParser.TREE_TRAIT,
new Attribute[] {
new Attribute.Default<String>(TreeLoggerParser.NAME, "rate"),
new Attribute.Default<String>(TreeLoggerParser.TAG, partitionData.getName() + ".rate"),
});
writer.writeIDref("discretizedBranchRates", partitionData.getName() + "." + "diffusionRates");
writer.writeCloseTag(TreeLoggerParser.TREE_TRAIT);
}
}
}
}
}