/*
* BeautiOptions.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.app.beauti.options;
import java.util.*;
import dr.app.beauti.components.ComponentFactory;
import dr.app.beauti.components.ancestralstates.AncestralStatesComponentOptions;
import dr.app.beauti.components.continuous.ContinuousComponentOptions;
import dr.app.beauti.components.discrete.DiscreteTraitsComponentOptions;
import dr.app.beauti.mcmcpanel.MCMCPanel;
import dr.app.beauti.types.OperatorSetType;
import dr.app.beauti.types.TreePriorType;
import dr.evolution.alignment.Alignment;
import dr.evolution.alignment.Patterns;
import dr.evolution.datatype.DataType;
import dr.evolution.datatype.Microsatellite;
import dr.evolution.tree.Tree;
import dr.evolution.util.Date;
import dr.evolution.util.Taxa;
import dr.evolution.util.Taxon;
import dr.evolution.util.TaxonList;
import dr.evolution.util.Units;
import dr.evoxml.util.DateUnitsType;
import dr.inference.operators.OperatorSchedule;
/**
* @author Andrew Rambaut
* @author Alexei Drummond
* @author Walter Xie
*/
public class BeautiOptions extends ModelOptions {
public static final boolean NEW_RELATIVE_RATE_PARAMETERIZATION = false;
public static final boolean NEW_GTR_PARAMETERIZATION = false;
public static final boolean FREQUENCIES_DIRICLET_PRIOR = false;
private static final long serialVersionUID = -3676802825545741012L;
public BeautiOptions() {
this(new ComponentFactory[]{});
}
public BeautiOptions(ComponentFactory[] components) {
// Install all the component's options from the given list of factories:
registerComponents(components);
}
/**
* This will register the list of components if not already there...
* @param components
*/
public void registerComponents(ComponentFactory[] components) {
// Install all the component's options from the given list of factories:
for (ComponentFactory component : components) {
if (!hasComponent(component)) {
addComponent(component.createOptions(this));
}
}
}
/**
*
* resets the options to the initial conditions
*/
public void reset() {
// Data options
taxonList = null;
taxonSets.clear();
taxonSetsMono.clear();
taxonSetsIncludeStem.clear();
taxonSetsTreeModel.clear();
// meanDistance = 1.0;
datesUnits = DateUnitsType.YEARS;
datesDirection = DateUnitsType.FORWARDS;
maximumTipHeight = 0.0;
translation = 0;
// selecetedTraits.clear();
// traitTypes.clear();
dataPartitions.clear();
traits.clear();
// partitionModels.clear();
// partitionTreeModels.clear();
// partitionTreePriors.clear();
partitionClockTreeLinks.clear();
// activedSameTreePrior = null;
// shareSameTreePrior = true;
userTrees.clear();
// rateOptionClockModel = FixRateType.FIX_FIRST_PARTITION;
// meanSubstitutionRate = 1.0;
unlinkPartitionRates = true;
units = Units.Type.SUBSTITUTIONS;
// Operator schedule options
optimizationTransform = OperatorSchedule.OptimizationTransform.DEFAULT;
// MCMC options
chainLength = 10000000;
logEvery = 1000;
echoEvery = 1000;
burnIn = 100000;
fileName = null;
autoOptimize = true;
performTraceAnalysis = false;
generateCSV = true; // until/if a button
samplePriorOnly = false;
fileNameStem = MCMCPanel.DEFAULT_FILE_NAME_STEM;
logFileName = null;
allowOverwriteLog = false;
// mapTreeLog = false;
// mapTreeFileName = null;
treeFileName.clear();
substTreeLog = false;
substTreeFileName.clear();
operatorAnalysis = false;
operatorAnalysisFileName = null;
globalModelOptions = new GlobalModelOptions(this);
clockModelOptions = new ClockModelOptions(this);
treeModelOptions = new TreeModelOptions(this);
// priorOptions = new PriorOptions(this);
// traitsOptions = new TraitsOptions(this);
useStarBEAST = false;
speciesSets.clear();
speciesSetsMono.clear();
starBEASTOptions = new STARBEASTOptions(this);
microsatelliteOptions = new MicrosatelliteOptions(this);
parameters.clear();
operators.clear();
statistics.clear();
shareMicroSat = true;
clearDataPartitionCaches();
}
public void selectTaxonSetsStatistics(List<Parameter> params) {
if (useStarBEAST) {
if (speciesSets != null) {
for (Taxa taxa : speciesSets) {
Parameter statistic = statistics.get(taxa);
if (statistic == null) {
statistic = new Parameter.Builder(taxa.getId(), "tmrca statistic for species set " + taxa.getId())
.taxaId(taxa.getId()).isStatistic(true).isNodeHeight(true)
.initial(Double.NaN).isNonNegative(true).build();
statistics.put(taxa, statistic);
} else {
statistic.isCalibratedYule = getPartitionTreePriors().get(0).getNodeHeightPrior()
== TreePriorType.SPECIES_YULE_CALIBRATION && speciesSetsMono.get(taxa);
}
params.add(statistic);
}
} else {
System.err.println("SpeciesSets are null");
}
} else {
if (taxonSets != null) {
for (Taxa taxa : taxonSets) {
Parameter statistic = statistics.get(taxa);
PartitionTreeModel treeModel = taxonSetsTreeModel.get(taxa);
if (statistic == null) {
// default scaleType = PriorScaleType.NONE; priorType = PriorType.NONE_TREE_PRIOR
statistic = new Parameter.Builder(taxa.getId(), "tmrca statistic for taxon set " + taxa.getId())
.taxaId(taxa.getId()).isStatistic(true).isNodeHeight(true)
.partitionOptions(treeModel).initial(Double.NaN).isNonNegative(true).build();
statistic.setPrefix(treeModel.getPrefix());
statistics.put(taxa, statistic);
} else {
statistic.setOptions(treeModel); // keep consistent to taxonSetsTreeModel
statistic.setPrefix(treeModel.getPrefix()); // keep prefix consistent after link/unlink tree
PartitionTreePrior treePrior = treeModel.getPartitionTreePrior();
statistic.isCalibratedYule = treePrior.getNodeHeightPrior() == TreePriorType.YULE_CALIBRATION
&& taxonSetsMono.get(taxa);
}
params.add(statistic);
}
} else {
System.err.println("TaxonSets are null");
}
}
}
public boolean renameTMRCAStatistic(Taxa taxonSet) {
Parameter statistic = statistics.get(taxonSet);
if (statistic != null) {
if (useStarBEAST) {
statistic.taxaId = taxonSet.getId();
} else {
PartitionTreeModel treeModel = taxonSetsTreeModel.get(taxonSet);
statistic.taxaId = treeModel.getPrefix() + taxonSet.getId();
}
return true;
} else {
return false;
}
}
@Override
public void initModelParametersAndOpererators() {
}
public List<Parameter> selectParameters() {
return selectParameters(new ArrayList<Parameter>());
}
/**
* return an list of parameters that are required
*
* @return the parameter list
*/
@Override
public List<Parameter> selectParameters(List<Parameter> parameters) {
globalModelOptions.selectParameters(parameters);
selectTaxonSetsStatistics(parameters); // have to be before clockModelOptions.selectParameters(parameters);
for (PartitionSubstitutionModel model : getPartitionSubstitutionModels()) {
// parameters.addAll(model.getParameters(multiplePartitions));
model.selectParameters(parameters);
}
for (PartitionClockModel model : getPartitionClockModels()) {
Set<PartitionSubstitutionModel> substitutionModels = new LinkedHashSet<PartitionSubstitutionModel>();
for (AbstractPartitionData partition : getDataPartitions()) {
if (partition.getPartitionClockModel() == model) {
substitutionModels.add(partition.getPartitionSubstitutionModel());
}
}
// collect all the relative rate paremeters (partition rates and codon position rates)
ArrayList<Parameter> relativeRateParameters = new ArrayList<Parameter>();
for (PartitionSubstitutionModel substitutionModel : substitutionModels) {
relativeRateParameters.addAll(substitutionModel.getRelativeRateParameters());
}
if (relativeRateParameters.size() > 1) {
Parameter allMus = model.getParameter(NEW_RELATIVE_RATE_PARAMETERIZATION ? "allNus" : "allMus" );
allMus.clearSubParameters();
int totalWeight = 0;
for (Parameter mu : relativeRateParameters) {
allMus.addSubParameter(mu);
totalWeight += mu.getDimensionWeight();
}
parameters.add(allMus);
// add the total weight of all mus/nus to the allMus parameter
allMus.setDimensionWeight(totalWeight);
}
model.selectParameters(parameters);
}
clockModelOptions.selectParameters(parameters);
for (PartitionClockModelSubstModelLink clockSubst : getTraitClockSubstLinks()) {
clockSubst.selectParameters(parameters);
}
for (PartitionTreeModel tree : getPartitionTreeModels()) {
tree.selectParameters(parameters);
}
treeModelOptions.selectParameters(parameters);
for (PartitionTreePrior prior : getPartitionTreePriors()) {
prior.selectParameters(parameters);
}
for (PartitionClockModelTreeModelLink clockTree : getPartitionClockTreeLinks()) {
clockTree.selectParameters(parameters);
clockTree.selectStatistics(parameters);
}
if (useStarBEAST) { // species
starBEASTOptions.selectParameters(parameters);
}
if (contains(Microsatellite.INSTANCE)) {
microsatelliteOptions.selectParameters(parameters);
}
// for (TraitData trait : getTraitsList()) { // all traits including locations
// if (!trait.getName().equalsIgnoreCase(TraitData.Traits.TRAIT_SPECIES.toString()))
// trait.gets.selectParameters(parameters);
// }
selectComponentParameters(this, parameters);
selectComponentStatistics(this, parameters);
// priorOptions.selectParameters(parameters);
return parameters;
}
/**
* return an list of operators that are required
*
* @return the operator list
*/
public List<Operator> selectOperators() {
return selectOperators(new ArrayList<Operator>());
}
@Override
public List<Operator> selectOperators(List<Operator> ops) {
globalModelOptions.selectOperators(ops);
for (PartitionSubstitutionModel model : getPartitionSubstitutionModels()) {
model.selectOperators(ops);
}
for (PartitionClockModel model : getPartitionClockModels()) {
model.selectOperators(ops);
}
clockModelOptions.selectOperators(ops);
for (PartitionClockModelSubstModelLink clockSubst : getTraitClockSubstLinks()) {
clockSubst.selectOperators(ops);
}
for (PartitionTreeModel tree : getPartitionTreeModels()) {
tree.selectOperators(ops);
}
treeModelOptions.selectOperators(ops);
for (PartitionTreePrior prior : getPartitionTreePriors()) {
prior.selectOperators(ops);
}
for (PartitionClockModelTreeModelLink clockTree : getPartitionClockTreeLinks()) {
clockTree.selectOperators(ops);
}
if (useStarBEAST) { // species
starBEASTOptions.selectOperators(ops);
}
if (contains(Microsatellite.INSTANCE)) {
microsatelliteOptions.selectOperators(ops);
}
// for (TraitData trait : getTraitsList()) { // all traits including locations
// if (!trait.getName().equalsIgnoreCase(TraitData.Traits.TRAIT_SPECIES.toString()))
// trait.getTraitData().selectOperators(ops);
// }
selectComponentOperators(this, ops);
// no remove operators for parameters that are part of a joint prior...
List<Operator> toRemove = new ArrayList<Operator>();
for (Operator operator : ops) {
if ((operator.getParameter1() != null && operator.getParameter1().isLinked) ||
(operator.getParameter2() != null && operator.getParameter2().isLinked)) {
toRemove.add(operator);
}
}
ops.removeAll(toRemove);
return ops;
}
@Override
public String getPrefix() {
return "";
}
public Operator getOperator(Parameter parameter) {
for (Operator operator : selectOperators()) {
if (operator.getParameter1() == parameter || operator.getParameter2() == parameter) {
return operator;
}
}
return null;
}
public boolean hasData() {
return dataPartitions.size() > 0;
}
public boolean contains(DataType dataType) {
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getDataType().getType() == dataType.getType()) {
return true;
}
}
return false;
}
public void shareMicroSat() {
Microsatellite microsatellite = null;
for (PartitionSubstitutionModel model : getPartitionSubstitutionModels(Microsatellite.INSTANCE)) {
if (microsatellite == null) {
microsatellite = model.getMicrosatellite();
} else {
model.setMicrosatellite(microsatellite);
}
}
}
public void unshareMicroSat() {
Microsatellite microsatellite = null;
for (PartitionSubstitutionModel model : getPartitionSubstitutionModels(Microsatellite.INSTANCE)) {
if (microsatellite == null) {
microsatellite = model.getMicrosatellite();
} else {
microsatellite = new Microsatellite(model.getName() + ".microsat",
microsatellite.getMin(), microsatellite.getMax(), 1);
model.setMicrosatellite(microsatellite);
}
}
}
public boolean hasPartitionData(String name) {
for (AbstractPartitionData pd : dataPartitions) {
if (name.equalsIgnoreCase(pd.getName())) {
return true;
}
}
return false;
}
public PartitionData getPartitionData(Alignment alignment) {
for (PartitionData partition : getPartitionData()) {
if (partition.getAlignment() == alignment)
return partition;
}
return null;
}
/**
* exclude microsatellite and traits
*/
public List<PartitionData> getPartitionData() {
List<PartitionData> pdList = new ArrayList<PartitionData>();
for (AbstractPartitionData partition : dataPartitions) {
if (partition instanceof PartitionData && partition.getTraits() == null) {
pdList.add((PartitionData) partition);
}
}
return pdList;
}
/**
* exclude PartitionData and traits
*/
public List<PartitionPattern> getPartitionPattern() {
List<PartitionPattern> pdList = new ArrayList<PartitionPattern>();
for (AbstractPartitionData partition : dataPartitions) {
if (partition instanceof PartitionPattern) {
pdList.add((PartitionPattern) partition);
}
}
return pdList;
}
public List<AbstractPartitionData> getDataPartitions() {
return dataPartitions;
}
public List<AbstractPartitionData> getTraitPartitions(TraitData trait) {
List<AbstractPartitionData> pdList = new ArrayList<AbstractPartitionData>();
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getTraits() != null && pd.getTraits().contains(trait)) {
pdList.add(pd);
}
}
return pdList;
}
public List<AbstractPartitionData> getDataPartitions(DataType dataType) {
List<AbstractPartitionData> pdList = new ArrayList<AbstractPartitionData>();
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getDataType().getType() == dataType.getType()) {
pdList.add(pd);
}
}
return pdList;
}
public List<AbstractPartitionData> getDataPartitions(PartitionOptions model) {
if (model instanceof PartitionSubstitutionModel) {
return getDataPartitions((PartitionSubstitutionModel) model);
} else if (model instanceof PartitionClockModel) {
return getDataPartitions((PartitionClockModel) model);
} else if (model instanceof PartitionTreeModel) {
return getDataPartitions((PartitionTreeModel) model);
} else if (model instanceof PartitionTreePrior) {
return getDataPartitions((PartitionTreePrior) model);
} else if (model instanceof PartitionClockModelTreeModelLink) {
return getDataPartitions((PartitionClockModelTreeModelLink) model);
} else if (model instanceof PartitionClockModelSubstModelLink) {
return getDataPartitions((PartitionClockModelSubstModelLink) model);
} else {
return null;
}
}
private final Map<PartitionSubstitutionModel, List<AbstractPartitionData>> psmCache = new HashMap<PartitionSubstitutionModel, List<AbstractPartitionData>>();
public List<AbstractPartitionData> getDataPartitions(PartitionSubstitutionModel model) {
List<AbstractPartitionData> pdList = psmCache.get(model);
if (pdList == null) {
pdList = new ArrayList<AbstractPartitionData>();
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getPartitionSubstitutionModel() == model) {
pdList.add(pd);
}
}
psmCache.put(model, pdList);
}
return pdList;
}
private final Map<PartitionClockModel, List<AbstractPartitionData>> pcmCache = new HashMap<PartitionClockModel, List<AbstractPartitionData>>();
private final Map<PartitionTreeModel, List<AbstractPartitionData>> ptmCache = new HashMap<PartitionTreeModel, List<AbstractPartitionData>>();
public List<AbstractPartitionData> getDataPartitions(PartitionTreeModel model) {
List<AbstractPartitionData> pdList = ptmCache.get(model);
if (pdList == null) {
pdList = new ArrayList<AbstractPartitionData>();
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getPartitionTreeModel() == model) {
pdList.add(pd);
}
}
ptmCache.put(model, pdList);
}
return pdList;
}
private final Map<PartitionTreePrior, List<AbstractPartitionData>> ptpCache = new HashMap<PartitionTreePrior, List<AbstractPartitionData>>();
public List<AbstractPartitionData> getDataPartitions(PartitionTreePrior prior) {
List<AbstractPartitionData> pdList = ptpCache.get(prior);
if (pdList == null) {
pdList = new ArrayList<AbstractPartitionData>();
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getPartitionTreeModel().getPartitionTreePrior() == prior) {
pdList.add(pd);
}
}
ptpCache.put(prior, pdList);
}
return pdList;
}
private final Map<PartitionClockModelTreeModelLink, List<AbstractPartitionData>> pcmtmlCache = new HashMap<PartitionClockModelTreeModelLink, List<AbstractPartitionData>>();
public List<AbstractPartitionData> getDataPartitions(PartitionClockModelTreeModelLink link) {
List<AbstractPartitionData> pdList = pcmtmlCache.get(link);
if (pdList == null) {
pdList = new ArrayList<AbstractPartitionData>();
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getPartitionClockModel() == link.getPartitionClockModel() && pd.getPartitionTreeModel() == link.getPartitionTreeTree()) {
pdList.add(pd);
}
}
pcmtmlCache.put(link, pdList);
}
return pdList;
}
private final Map<PartitionClockModelSubstModelLink, List<AbstractPartitionData>> pcmsmlCache = new HashMap<PartitionClockModelSubstModelLink, List<AbstractPartitionData>>();
public List<AbstractPartitionData> getDataPartitions(PartitionClockModelSubstModelLink link) {
List<AbstractPartitionData> pdList = pcmsmlCache.get(link);
if (pdList == null) {
pdList = new ArrayList<AbstractPartitionData>();
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getPartitionClockModel() == link.getClockModel() && pd.getPartitionSubstitutionModel() == link.getSubstModel()) {
pdList.add(pd);
}
}
pcmsmlCache.put(link, pdList);
}
return pdList;
}
public List<AbstractPartitionData> getDataPartitions(PartitionClockModel clockModel) {
List<AbstractPartitionData> pdList = pcmCache.get(clockModel);
if (pdList == null) {
pdList = new ArrayList<AbstractPartitionData>();
for (AbstractPartitionData pd : dataPartitions) {
if (pd.getPartitionClockModel() != null && pd.getPartitionClockModel() == clockModel) {
pdList.add(pd);
}
}
pcmCache.put(clockModel, pdList);
}
return pdList;
}
public void clearDataPartitionCaches() {
psmCache.clear();
pcmCache.clear();
ptmCache.clear();
ptpCache.clear();
pcmtmlCache.clear();
pcmsmlCache.clear();
psmlCache.clear();
ptmlCache.clear();
pcmlCache.clear();
}
public boolean isEBSPSharingSamePrior() {
return getPartitionTreePriors().size() >= 1 &&
(isShareSameTreePrior() && getPartitionTreePriors().get(0).getNodeHeightPrior() == TreePriorType.EXTENDED_SKYLINE);
}
// ++++++++++++++ Partition Substitution Model ++++++++++++++
// public void addPartitionSubstitutionModel(PartitionSubstitutionModel model) {
// if (!partitionModels.contains(model)) {
// partitionModels.add(model);
// }
// }
// public List<PartitionSubstitutionModel> getPartitionSubstitutionModels() {
// return partitionModels;
// }
public List<PartitionSubstitutionModel> getPartitionSubstitutionModels(DataType dataType) {
List<PartitionSubstitutionModel> models = new ArrayList<PartitionSubstitutionModel>();
for (PartitionSubstitutionModel model : getPartitionSubstitutionModels(dataPartitions)) {
if (model.getDataType().getType() == dataType.getType()) {
models.add(model);
}
}
return models;
}
private final Map<List<? extends AbstractPartitionData>, List<PartitionSubstitutionModel>> psmlCache = new HashMap<List<? extends AbstractPartitionData>, List<PartitionSubstitutionModel>>();
public List<PartitionSubstitutionModel> getPartitionSubstitutionModels(List<? extends AbstractPartitionData> givenDataPartitions) {
List<PartitionSubstitutionModel> psmList = psmlCache.get(givenDataPartitions);
if (psmList == null) {
Set<PartitionSubstitutionModel> activeModels = new LinkedHashSet<PartitionSubstitutionModel>();
for (AbstractPartitionData partition : givenDataPartitions) {
PartitionSubstitutionModel model = partition.getPartitionSubstitutionModel();
if (model != null) {
activeModels.add(model);
}
}
psmList = new ArrayList<PartitionSubstitutionModel>(activeModels);
psmlCache.put(givenDataPartitions, psmList);
}
return psmList;
}
public List<PartitionSubstitutionModel> getPartitionSubstitutionModels() {
return getPartitionSubstitutionModels(dataPartitions);
}
// public List<PartitionSubstitutionModel> getPartitionTraitsSubstitutionModels() {
// return getPartitionSubstitutionModels(getTraitsList());
// }
//
// public List<PartitionSubstitutionModel> getPartitionNonTraitsSubstitutionModels() {
// return getPartitionSubstitutionModels(getNonTraitsDataList());
// }
// ++++++++++++++ Partition Clock Model ++++++++++++++
private final Map<List<? extends AbstractPartitionData>, List<PartitionClockModel>> pcmlCache = new HashMap<List<? extends AbstractPartitionData>, List<PartitionClockModel>>();
public List<PartitionClockModel> getPartitionClockModels(List<? extends AbstractPartitionData> givenDataPartitions) {
List<PartitionClockModel> pcmList = pcmlCache.get(givenDataPartitions);
if (pcmList == null) {
Set<PartitionClockModel> activeModels = new LinkedHashSet<PartitionClockModel>();
for (AbstractPartitionData partition : givenDataPartitions) {
PartitionClockModel model = partition.getPartitionClockModel();
if (model != null && !(partition.getDataType().getType() == DataType.CONTINUOUS)) {
activeModels.add(model);
}
}
pcmList = new ArrayList<PartitionClockModel>(activeModels);
pcmlCache.put(givenDataPartitions, pcmList);
}
return pcmList;
}
public List<PartitionClockModel> getPartitionClockModels(DataType dataType) {
List<PartitionClockModel> models = new ArrayList<PartitionClockModel>();
for (PartitionClockModel model : getPartitionClockModels()) {
if (model.getDataType().getType() == dataType.getType()) {
models.add(model);
}
}
return models;
}
public List<PartitionClockModel> getPartitionClockModels() {
return getPartitionClockModels(dataPartitions);
}
// ++++++++++++++ Partition Tree Model ++++++++++++++
// public void addPartitionTreeModel(PartitionTreeModel tree) {
//
// if (!partitionTreeModels.contains(tree)) {
// partitionTreeModels.add(tree);
// }
// }
// public List<PartitionTreeModel> getPartitionTreeModels() {
// return partitionTreeModels;
// }
private final Map<List<? extends AbstractPartitionData>, List<PartitionTreeModel>> ptmlCache = new HashMap<List<? extends AbstractPartitionData>, List<PartitionTreeModel>>();
public List<PartitionTreeModel> getPartitionTreeModels(List<? extends AbstractPartitionData> givenDataPartitions) {
List<PartitionTreeModel> ptmList = ptmlCache.get(givenDataPartitions);
if (ptmList == null) {
Set<PartitionTreeModel> activeTrees = new LinkedHashSet<PartitionTreeModel>();
for (AbstractPartitionData partition : givenDataPartitions) {
if (partition.getPartitionTreeModel() != null) {
activeTrees.add(partition.getPartitionTreeModel());
}
}
ptmList = new ArrayList<PartitionTreeModel>(activeTrees);
ptmlCache.put(givenDataPartitions, ptmList);
}
return ptmList;
}
public List<PartitionTreeModel> getPartitionTreeModels() {
return getPartitionTreeModels(dataPartitions);
}
// public List<PartitionTreeModel> getNonTraitPartitionTreeModels() {
// return getPartitionTreeModels(getNonTraitsDataList());
// }
// ++++++++++++++ Partition Tree Prior ++++++++++++++
public List<PartitionTreePrior> getPartitionTreePriors() {
List<PartitionTreePrior> activeTrees = new ArrayList<PartitionTreePrior>();
// # tree prior = 1 or # tree model
for (PartitionTreeModel model : getPartitionTreeModels()) {
PartitionTreePrior prior = model.getPartitionTreePrior();
if (prior != null && (!activeTrees.contains(prior))) {
activeTrees.add(prior);
}
}
return activeTrees;
}
public List<PartitionTreeModel> getPartitionTreeModels(PartitionTreePrior treePrior) {
List<PartitionTreeModel> activeTrees = new ArrayList<PartitionTreeModel>();
for (PartitionTreeModel model : getPartitionTreeModels()) {
PartitionTreePrior prior = model.getPartitionTreePrior();
if (prior != null && model.getPartitionTreePrior() == treePrior && (!activeTrees.contains(model))) {
activeTrees.add(model);
}
}
return activeTrees;
}
/**
* unlink all and copy the tree prior in selectedTreeModel to others
* currently, tree prior name cannot be changed, but tree model name can, so that we have to use instance
*
* @param selectedTreeModel the selected tree model whose tree prior copied to others
*/
public void unLinkTreePriors(PartitionTreeModel selectedTreeModel) {
for (PartitionTreeModel model : getPartitionTreeModels()) {
// because # tree prior = 1 or # tree model, prior here will be a same instance through all tree models
PartitionTreePrior prior = model.getPartitionTreePrior();
if (model == selectedTreeModel) {
prior.setName(model.getName()); // keep name same as its tree model
} else {
PartitionTreePrior ptp = new PartitionTreePrior(this, model.getName(), prior);
model.setPartitionTreePrior(ptp);
}
}
clearDataPartitionCaches();
}
// link all to given treePrior
public void linkTreePriors(PartitionTreePrior treePrior) {
if (treePrior == null) treePrior = new PartitionTreePrior(this, getPartitionTreeModels().get(0));
for (PartitionTreeModel model : getPartitionTreeModels()) {
model.setPartitionTreePrior(treePrior);
}
clearDataPartitionCaches();
}
public boolean isShareSameTreePrior() {
return getPartitionTreePriors().size() <= 1;
}
// ++++++++++++++ Partition Clock Model ++++++++++++++
public List<PartitionClockModelTreeModelLink> getPartitionClockTreeLinks() {
return partitionClockTreeLinks;
}
public List<PartitionClockModelSubstModelLink> getTraitClockSubstLinks() {
return partitionClockSubstLinks;
}
public PartitionClockModelTreeModelLink getPartitionClockTreeLink(PartitionClockModel model, PartitionTreeModel tree) {
for (PartitionClockModelTreeModelLink clockTree : getPartitionClockTreeLinks()) {
if (clockTree.getPartitionClockModel().equals(model) && clockTree.getPartitionTreeTree().equals(tree)) {
return clockTree;
}
}
return null;
}
public void updatePartitionAllLinks() {
clearDataPartitionCaches();
partitionClockTreeLinks.clear();
partitionClockSubstLinks.clear();
for (PartitionClockModel model : getPartitionClockModels()) {
for (PartitionTreeModel tree : getPartitionTreeModels(getDataPartitions(model))) {
PartitionClockModelTreeModelLink clockTree = new PartitionClockModelTreeModelLink(this, model, tree);
if (!partitionClockTreeLinks.contains(clockTree)) {
partitionClockTreeLinks.add(clockTree);
}
}
}
}
// public void updateAll() {
// updatePartitionAllLinks();
// for (ClockModelGroup clockModelGroup : clockModelOptions.getClockModelGroups()) {
// if (clockModelGroup.contain(Microsatellite.INSTANCE, this)) {
// if (getPartitionClockModels(clockModelGroup).size() == 1) {
// clockModelOptions.fixRateOfFirstClockPartition(clockModelGroup);
// getPartitionClockModels(clockModelGroup).get(0).setEstimatedRate(true);
// } else {
// clockModelOptions.fixMeanRate(clockModelGroup);
// }
// } else if (!(clockModelGroup.getRateTypeOption() == FixRateType.TIP_CALIBRATED
// || clockModelGroup.getRateTypeOption() == FixRateType.NODE_CALIBRATED
// || clockModelGroup.getRateTypeOption() == FixRateType.RATE_CALIBRATED)) {
// //TODO correct?
// clockModelOptions.fixRateOfFirstClockPartition(clockModelGroup);
// }
// }
// }
// update links (e.g List<PartitionData> allPartitionData), after use (e.g partition.setPartitionSubstitutionModel(model))
// public void updateLinksBetweenPDPCMPSMPTMPTPP() {
// for (PartitionSubstitutionModel model : getPartitionSubstitutionModels()) {
// model.clearAllPartitionData();
// }
//
// for (PartitionClockModel model : getPartitionClockModels()) {
// model.clearAllPartitionData();
// }
//
// for (PartitionTreeModel tree : getPartitionTreeModels()) {
// tree.clearAllPartitionData();
// }
//
// //TODO update PartitionTreePrior ?
//
// for (PartitionData partition : dataPartitions) {
// PartitionSubstitutionModel psm = partition.getPartitionSubstitutionModel();
// if (!psm.getDataPartitions().contains(partition)) {
// psm.addPartitionData(partition);
// }
//
// PartitionClockModel pcm = partition.getPartitionClockModel();
// if (!pcm.getDataPartitions().contains(partition)) {
// pcm.addPartitionData(partition);
// }
//
// PartitionTreeModel ptm = partition.getPartitionTreeModel();
// if (!ptm.getDataPartitions().contains(partition)) {
// ptm.addPartitionData(partition);
// }
// }
//
// }
public double getAveWeightedMeanDistance(List<AbstractPartitionData> partitions) {
double meanDistance = 0;
double totalSite = 0;
for (AbstractPartitionData partition : partitions) {
meanDistance = meanDistance + partition.getMeanDistance() * partition.getSiteCount();
totalSite = totalSite + partition.getSiteCount();
}
if (totalSite == 0) {
return 0;
} else {
return meanDistance / totalSite;
}
}
// public boolean hasDifferentTaxa(List<AbstractPartitionData> partitionDataList) {
// if (partitionDataList.size() < 2)
// return false;
//
// TaxonList ref = null;
// boolean hasDiff = false;
// for (AbstractPartitionData partition : partitionDataList) {
// final TaxonList a = partition.getTaxonList();
// if (ref == null) {
// ref = a;
// } else {
// if (a.getTaxonCount() != ref.getTaxonCount()) {
// hasDiff = true;
// } else {
// for (int k = 0; k < a.getTaxonCount(); ++k) {
// if (ref.getTaxonIndex(a.getTaxonId(k)) == -1) {
// hasDiff = true;
// }
// }
// }
// }
// }
// return hasDiff;
// }
/**
* check if all taxa are same across partitions.
*/
public boolean hasIdenticalTaxa(List<AbstractPartitionData> partitionDataList) {
TaxonList taxa = null;
for (AbstractPartitionData partition : partitionDataList) {
if (taxa == null) {
taxa = partition.getTaxonList();
} else {
final TaxonList taxa1 = partition.getTaxonList();
if (taxa1 != null) {
// Trait partitions are assumed to have the same taxon list as the
// tree they are using and so will return null.
if (taxa1.getTaxonCount() != taxa.getTaxonCount()) {
return false;
}
for (int k = 0; k < taxa1.getTaxonCount(); ++k) {
if (taxa.getTaxonIndex(taxa1.getTaxonId(k)) == -1) {
// for (Taxon taxon : taxa1) {
// if (taxa.getTaxonIndex(taxon) == -1) { // this is wrong code
return false;
}
}
}
}
}
return true;
}
public boolean hasIdenticalTaxa() {
return hasIdenticalTaxa(dataPartitions);
}
public void updateTaxonList() {
taxonList.removeAllTaxa();
for (AbstractPartitionData partition : dataPartitions) {
if (!partition.isCreatedFromTrait()) {
for (Taxon taxon : partition.getTaxonList()) {
if (!taxonList.contains(taxon)) {
taxonList.addTaxon(taxon);
}
}
}
}
}
/**
* given a list of BEAUti AbstractPartitionData, take the union of taxon list from them
* but if partition instanceof PartitionPattern and taxon is masked in Patterns class, then not count.
* @param partitionDataList can be BEAUti PartitionData or PartitionPattern or both
* @return num of taxon
*/
public int getTaxonCount(List<AbstractPartitionData> partitionDataList) {
if (partitionDataList == null || partitionDataList.size() == 0) return 0;
List<String> taxonNameList = new ArrayList<String>();
for (AbstractPartitionData partition : partitionDataList) {
if (partition.getTaxonList() != null) { // not a trait partition
for (Taxon t : partition.getTaxonList()) {
if (!taxonNameList.contains(t.getId())) {
if (partition instanceof PartitionPattern) {
Patterns patterns = ((PartitionPattern) partition).getPatterns();
if (!patterns.isMasked(patterns.getTaxonIndex(t)))
taxonNameList.add(t.getId());
} else {
taxonNameList.add(t.getId());
}
}
}
}
}
return taxonNameList.size();
}
// +++++++++++++ Traits +++++++++++++
// public List<PartitionData> getNonTraitsDataList() {
// List<PartitionData> nonTraitsData = new ArrayList<PartitionData>();
// for (PartitionData partition : dataPartitions) {
// if (partition.getTraitType() == null) {
// nonTraitsData.add(partition);
// }
// }
// return nonTraitsData;
// }
//
// public List<TraitData> getTraitsList() {
// List<TraitData> traits = new ArrayList<TraitData>();
// for (PartitionData partition : dataPartitions) {
// if (partition.getTraitType() != null) {
// traits.add((TraitData) partition);
// }
// }
// return traits;
// }
//
// public List<TraitData> getDiscreteIntegerTraits() {
// List<TraitData> traits = new ArrayList<TraitData>();
// for (PartitionData partition : dataPartitions) {
// if (partition.getTraitType() != null && partition.getTraitType() != TraitData.TraitType.CONTINUOUS) {
// traits.add((TraitData) partition);
// }
// }
// return traits;
// }
//
// public boolean hasDiscreteIntegerTraitsExcludeSpecies() { // exclude species at moment
// return getDiscreteIntegerTraits().size() > 1
// || (getDiscreteIntegerTraits().size() > 0 && (!traitExists(TraitData.TRAIT_SPECIES)));
// }
public int getIndexOfTrait(String traitName) {
int i = 0;
for (TraitData trait : traits) {
if (trait.getName().equalsIgnoreCase(traitName)) {
return i;
}
i++;
}
return -1;
}
public boolean traitExists(String traitName) {
return getIndexOfTrait(traitName) != -1;
}
public int addTrait(TraitData newTrait) {
int selRow = getIndexOfTrait(newTrait.getName());
if (selRow == -1) {
traits.add(newTrait);
selRow = traits.size() - 1; // start 0
}
return selRow; // only for trait panel
}
public int createPartitionForTraits(String name, TraitData trait) {
List<TraitData> traits = new ArrayList<TraitData>();
traits.add(trait);
return createPartitionForTraits(name, traits);
}
public int createPartitionForTraits(String name, List<TraitData> traits) {
int selRow = -1;
PartitionData partition = new PartitionData(this, name, traits.get(0).getFileName(), traits);
dataPartitions.add(partition);
selRow = dataPartitions.size() - 1;
if (partition.getPartitionSubstitutionModel() == null) {
PartitionSubstitutionModel substModel = new PartitionSubstitutionModel(this, partition);
partition.setPartitionSubstitutionModel(substModel);
}
if (partition.getPartitionClockModel() == null && partition.getDataType().getType() != DataType.CONTINUOUS) {
// PartitionClockModel based on PartitionData
PartitionClockModel pcm = new PartitionClockModel(this, partition);
partition.setPartitionClockModel(pcm);
}
if (partition.getPartitionTreeModel() == null) {
partition.setPartitionTreeModel(getPartitionTreeModels().get(0));// always use 1st tree
// getPartitionTreeModels().get(0).addPartitionData(newTrait);
}
updateTraitParameters(partition);
return selRow; // only for trait panel
}
private void updateTraitParameters(AbstractPartitionData partition) {
if (partition.isCreatedFromTrait()) {
ContinuousComponentOptions comp = (ContinuousComponentOptions) getComponentOptions(ContinuousComponentOptions.class);
comp.createParameters(this);
DiscreteTraitsComponentOptions comp2 = (DiscreteTraitsComponentOptions) getComponentOptions(DiscreteTraitsComponentOptions.class);
comp2.createParameters(this);
AncestralStatesComponentOptions comp3 = (AncestralStatesComponentOptions) getComponentOptions(AncestralStatesComponentOptions.class);
comp3.setReconstructAtNodes(partition, true);
comp3.setReconstructAtMRCA(partition, false);
}
}
public void renamePartition(AbstractPartitionData partition, String newName) {
partition.setName(newName);
updateTraitParameters(partition);
}
public void removeTrait(String traitName) {
if (traitExists(traitName)) {
clearTraitValues(traitName); // Clear trait values
traits.remove(getTrait(traitName));
}
}
public void clearTraitValues(String traitName) {
for (int i = 0; i < taxonList.getTaxonCount(); i++) {
taxonList.getTaxon(i).setAttribute(traitName, "");
}
}
public TraitData getTrait(String traitName) {
for (TraitData trait : traits) {
if (trait.getName().equalsIgnoreCase(traitName))
return trait;
}
return null;
}
// public boolean hasAlignmentPartition() {
// for (AbstractPartitionData partition : dataPartitions) {
// if (partition instanceof PartitionData) {
// if (((PartitionData) partition).getAlignment() != null) {
// return true;
// }
// }
// }
// return false;
// }
public boolean hasDiscreteTrait() {
for (TraitData traitData : traits) {
if (traitData.getTraitType() == TraitData.TraitType.DISCRETE) {
return true;
}
}
return false;
}
public boolean hasDiscreteTraitPartition() {
for (AbstractPartitionData partition : dataPartitions) {
if (partition.getTraits() != null && partition.getTraits().get(0).getTraitType() == TraitData.TraitType.DISCRETE) {
return true;
}
}
return false;
}
public boolean hasContinuousTrait() {
for (TraitData traitData : traits) {
if (traitData.getTraitType() == TraitData.TraitType.CONTINUOUS) {
return true;
}
}
return false;
}
public boolean hasContinuousTraitPartition() {
for (AbstractPartitionData partition : dataPartitions) {
if (partition.getTraits() != null && partition.getTraits().get(0).getTraitType() == TraitData.TraitType.CONTINUOUS) {
return true;
}
}
return false;
}
public Set<String> getStatesForDiscreteModel(PartitionSubstitutionModel model) {
Set<String> states = new TreeSet<String>();
for (AbstractPartitionData partition : getDataPartitions(model)) {
Set<String> newStates = partition.getTraits().get(0).getStatesOfTrait(taxonList);
if (states.size() > 0) {
Set<String> shared = new HashSet<String>(states);
shared.retainAll(newStates);
if (shared.size() == 0) {
throw new IllegalArgumentException("For discrete trait partitions to have a linked model they must share states");
}
}
states.addAll(newStates);
}
if (states.size() < 1) throw new IllegalArgumentException("The number of states must be greater than 1");
return states;
}
public static TraitData.TraitType guessTraitType(TaxonList taxa, String name) {
TraitData.TraitType type = TraitData.TraitType.DISCRETE;
return type;
}
// ++++++++++++++++++++ message bar +++++++++++++++++
public String statusMessage() {
// String message = "<html><p>";
String message = "";
if (hasData()) {
message += "Data: " + taxonList.getTaxonCount() + " taxa, ";
message += dataPartitions.size() + (dataPartitions.size() > 1 ? " partitions" : " partition");
if (starBEASTOptions.getSpeciesList() != null && useStarBEAST) {
int num = starBEASTOptions.getSpeciesList().size();
message += ", " + num + " species"; // species is both singular and plural
}
if (userTrees.size() > 0) {
message += ", " + userTrees.size() + " user" +
(userTrees.size() > 1 ? " trees" : " tree");
}
if (useStarBEAST) {
message += "; Species Tree Ancestral Reconstruction (*BEAST)";
}
// if (hasPhylogeographic()) {
// message += "; Phylogeographic Analysis";
// }
// message += "; " + clockModelOptions.statusMessageClockModel();
} else if (userTrees.size() > 0) { // TODO
message += "Trees only : " + userTrees.size() +
(userTrees.size() > 1 ? " trees, " : " tree, ") +
taxonList.getTaxonCount() + " taxa";
} else if (taxonList != null && taxonList.getTaxonCount() > 0) { // TODO
message += "Taxa only: " + taxonList.getTaxonCount() + " taxa";
} else {
message += "No data loaded - select 'Import Data...' from the 'File' menu.";
}
// message += "</p></html>";
return message;
}
public List<Object> getKeysFromValue(Map<?, ?> hm, Object value) {
List<Object> list = new ArrayList<Object>();
for (Object o : hm.keySet()) {
if (hm.get(o).equals(value)) {
list.add(o);
}
}
return list;
}
public Taxa getTaxa(String taxaName) {
for (Taxa taxa : taxonSets) {
if (taxa.getId().equalsIgnoreCase(taxaName)) return taxa;
}
return null;
}
public int getTaxaIndex(String taxaName) {
for (int i = 0; i < taxonSets.size(); i++) {
if (taxonSets.get(i).getId().equalsIgnoreCase(taxaName)) return i;
}
return -1;
}
public int getSpeciesIndex(String speciesName) {
for (int i = 0; i < speciesSets.size(); i++) {
if (speciesSets.get(i).getId().equalsIgnoreCase(speciesName)) return i;
}
return -1;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Data options
public Taxa taxonList = null; // union set of all taxa in all partitions. todo change to List<Taxa> regarding data type?
public List<Taxa> taxonSets = new ArrayList<Taxa>();
public Map<Taxa, Boolean> taxonSetsMono = new HashMap<Taxa, Boolean>();
public Map<Taxa, Double> taxonSetsHeights = new HashMap<Taxa, Double>();
public Map<Taxa, Boolean> taxonSetsIncludeStem = new HashMap<Taxa, Boolean>();
public Map<Taxa, PartitionTreeModel> taxonSetsTreeModel = new HashMap<Taxa, PartitionTreeModel>();
public DateUnitsType datesUnits = DateUnitsType.YEARS;
public DateUnitsType datesDirection = DateUnitsType.FORWARDS;
public double maximumTipHeight = 0.0;
public int translation = 0;
public Date originDate = null;
public DateGuesser dateGuesser = new DateGuesser();
// public TraitGuesser traitGuesser = new TraitGuesser();
//
// public List<String> selecetedTraits = new ArrayList<String>();
// public Map<String, TraitGuesser.TraitType> traitTypes = new HashMap<String, TraitGuesser.TraitType>();
// Data
public List<AbstractPartitionData> dataPartitions = new ArrayList<AbstractPartitionData>();
public List<TraitData> traits = new ArrayList<TraitData>();
// ClockModel <=> TreeModel
private List<PartitionClockModelTreeModelLink> partitionClockTreeLinks = new ArrayList<PartitionClockModelTreeModelLink>();
// ClockModel <=> SubstModel
private List<PartitionClockModelSubstModelLink> partitionClockSubstLinks = new ArrayList<PartitionClockModelSubstModelLink>();
// list of starting tree from user import
public List<Tree> userTrees = new ArrayList<Tree>();
public boolean unlinkPartitionRates = true;
public Units.Type units = Units.Type.YEARS;
// Operator schedule options
public OperatorSchedule.OptimizationTransform optimizationTransform = OperatorSchedule.OptimizationTransform.DEFAULT;
// MCMC options
public int chainLength = 10000000;
public int logEvery = 1000;
public int echoEvery = 1000;
public int burnIn = 100000;
public String fileName = null;
public boolean autoOptimize = true;
public boolean performTraceAnalysis = false;
public boolean generateCSV = true; // until/if a button
public boolean samplePriorOnly = false;
public String fileNameStem = MCMCPanel.DEFAULT_FILE_NAME_STEM;
public String logFileName = null;
public boolean generateDemographicLogFile = false;
public String demographicModelName = null;
public String demographicLogFileName = null;
public boolean allowOverwriteLog = false;
// public boolean mapTreeLog = false;
// public String mapTreeFileName = null;
public List<String> treeFileName = new ArrayList<String>();
public boolean substTreeLog = false;
public List<String> substTreeFileName = new ArrayList<String>();
public boolean operatorAnalysis = true;
public String operatorAnalysisFileName = null;
public GlobalModelOptions globalModelOptions = new GlobalModelOptions(this);
public ClockModelOptions clockModelOptions = new ClockModelOptions(this);
public TreeModelOptions treeModelOptions = new TreeModelOptions(this);
public OperatorSetType operatorSetType = OperatorSetType.DEFAULT;
public boolean useStarBEAST = false;
public List<Taxa> speciesSets = new ArrayList<Taxa>();
public Map<Taxa, Boolean> speciesSetsMono = new HashMap<Taxa, Boolean>();
public STARBEASTOptions starBEASTOptions = new STARBEASTOptions(this);
public MicrosatelliteOptions microsatelliteOptions = new MicrosatelliteOptions(this);
public boolean shareMicroSat = true;
public boolean logCoalescentEventsStatistic = false;
}