[med-svn] [beast2-mcmc] 01/04: Imported Upstream version 2.4.3+dfsg
Andreas Tille
tille at debian.org
Tue Aug 30 06:53:56 UTC 2016
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository beast2-mcmc.
commit 37327ec1be32f3b05104ffc50df98951d0c49469
Author: Andreas Tille <tille at debian.org>
Date: Tue Aug 30 08:30:51 2016 +0200
Imported Upstream version 2.4.3+dfsg
---
build.xml | 4 +-
release/common/README.txt | 4 +-
release/common/VERSION HISTORY.txt | 27 +-
src/beast/app/BEASTVersion.java | 2 +-
src/beast/app/BEASTVersion2.java | 2 +-
src/beast/app/BeastMCMC.java | 8 +-
src/beast/app/DocMaker.java | 3 +-
src/beast/app/beastapp/BeastLauncher.java | 2 +-
src/beast/app/beastapp/BeastMain.java | 2 +
src/beast/app/beauti/AlignmentImporter.java | 54 +++
src/beast/app/beauti/AlignmentListInputEditor.java | 8 +-
src/beast/app/beauti/Beauti.java | 12 +-
src/beast/app/beauti/BeautiAlignmentProvider.java | 468 ++++++++++++---------
src/beast/app/beauti/BeautiDoc.java | 1 +
src/beast/app/beauti/GuessPatternDialog.java | 5 +-
src/beast/app/beauti/JPackageDialog.java | 166 +++++++-
src/beast/app/beauti/JPackageRepositoryDialog.java | 2 +
src/beast/app/beauti/MRCAPriorInputEditor.java | 101 +++++
src/beast/app/beauti/OperatorListInputEditor.java | 3 +-
.../beauti/ParametricDistributionInputEditor.java | 19 +-
src/beast/app/beauti/PriorInputEditor.java | 4 +-
src/beast/app/beauti/PriorListInputEditor.java | 173 +++++---
src/beast/app/beauti/PriorProvider.java | 24 ++
src/beast/app/beauti/TaxonSetDialog.java | 6 +-
src/beast/app/beauti/TaxonSetInputEditor.java | 9 +-
src/beast/app/beauti/TipDatesInputEditor.java | 159 -------
src/beast/app/draw/BEASTObjectInputEditor.java | 3 +-
src/beast/app/draw/DoubleListInputEditor.java | 7 +-
src/beast/app/draw/EnumInputEditor.java | 4 +
src/beast/app/draw/InputEditor.java | 2 +-
src/beast/app/draw/IntegerListInputEditor.java | 3 +-
src/beast/app/tools/LogCombiner.java | 8 +-
src/beast/app/treeannotator/TreeAnnotator.java | 2 +
src/beast/app/util/Utils.java | 2 +-
src/beast/core/BEASTInterface.java | 38 +-
src/beast/core/Citation.java | 18 +-
src/beast/core/Logger.java | 2 +-
src/beast/core/parameter/Parameter.java | 2 +-
src/beast/core/util/Sum.java | 32 +-
src/beast/evolution/alignment/TaxonSet.java | 4 +-
src/beast/evolution/datatype/IntegerData.java | 7 +
.../likelihood/ThreadedTreeLikelihood.java | 8 +-
.../evolution/speciation/CalibratedYuleModel.java | 1 +
src/beast/evolution/tree/RandomTree.java | 16 +-
src/beast/evolution/tree/TraitSet.java | 3 +-
src/beast/evolution/tree/Tree.java | 1 +
src/beast/evolution/tree/TreeHeightLogger.java | 7 +-
src/beast/evolution/tree/TreeStatLogger.java | 80 ++++
.../tree/coalescent/ExponentialGrowth.java | 5 +-
.../evolution/tree/coalescent/TreeIntervals.java | 21 +-
src/beast/math/distributions/Gamma.java | 42 +-
src/beast/math/distributions/MRCAPrior.java | 2 +-
src/beast/util/AddOnManager.java | 89 +++-
src/beast/util/Package.java | 16 +-
src/beast/util/TreeParser.java | 15 +-
src/beast/util/XMLParser.java | 37 +-
src/beast/util/XMLParserUtils.java | 19 +-
src/beast/util/XMLProducer.java | 26 +-
.../beast/app/beauti/BeautiRateTutorialTest.java | 5 +-
src/test/beast/core/BEASTInterfaceTest.java | 16 +
src/test/beast/core/util/SumTest.java | 63 +++
.../beast/evolution/datatype/IntegerDataTest.java | 32 ++
src/test/beast/evolution/tree/TraitSetTest.java | 78 ++++
src/test/beast/math/distributions/GammaTest.java | 101 +++++
.../beast/math/distributions/InvGammaTest.java | 128 ++++++
.../LogNormalDistributionModelTest.java | 140 +++++-
.../beast/math/distributions/MRCAPriorTest.java | 19 +
.../math/distributions/NormalDistributionTest.java | 132 ++++++
68 files changed, 1954 insertions(+), 550 deletions(-)
diff --git a/build.xml b/build.xml
index 3c6a376..420fe49 100644
--- a/build.xml
+++ b/build.xml
@@ -242,8 +242,8 @@
<!-- Release -->
- <property name="version" value="2.4.2" />
- <property name="version_number" value="2.4.0" />
+ <property name="version" value="2.4.3" />
+ <property name="version_number" value="2.4.3" />
<property name="release_dir" value="release" />
<property name="copyright" value="Beast 2 development team 2011-2016" />
diff --git a/release/common/README.txt b/release/common/README.txt
index dae7c51..9e7954b 100644
--- a/release/common/README.txt
+++ b/release/common/README.txt
@@ -1,7 +1,7 @@
- BEAST v2.4.2 2016
+ BEAST v2.4.3 2016
Beast 2 development team 2011-2016
-Last updated: June 2016
+Last updated: August 2016
Contents:
1) INTRODUCTION
diff --git a/release/common/VERSION HISTORY.txt b/release/common/VERSION HISTORY.txt
index 19b6d1e..c795a5c 100644
--- a/release/common/VERSION HISTORY.txt
+++ b/release/common/VERSION HISTORY.txt
@@ -1,10 +1,33 @@
- BEAST v2.4.2 2016
+ BEAST v2.4.3 2016
Beast 2 development team 2011-2016
Version History
-Last updated: June 2016
+Last updated: August 2016
All issues can be viewed at https://github.com/CompEvol/beast2/issues
================================================================================
+Version 2.4.3 August 2016
+
+ BEAUti
+ Support for tip data sampling by setting 'tipsonly' in MRCA Priors
+ Allow packages to specify priors, e.g. multi-monophyletic constraints in BEASTLabs
+ Allow packages to specify file importers, which allows microsattelite support through the BEASTvntr package
+ Gamma distribution allows multiple parameterisations
+ Packages used now encoded in XML, for better error reporting of missing packages
+ Better looking on high-res screens
+
+ Package Manager
+ Links to documentation available
+ Better layout
+
+ BEAST
+ allow multiple citations per class
+ allow trait sets with unspecified dates
+ allow multiple arguments to Sum
+ improved error reporting
+
+ TreeAnnotator fix for phylogeography in low-mem mode.
+ LogCombiner suppress duplicate '=' in tree output
+
Version 2.4.2 June 2016
Applications are scalable, making them visible on high resolution screens
diff --git a/src/beast/app/BEASTVersion.java b/src/beast/app/BEASTVersion.java
index a8b8e03..44a8abd 100644
--- a/src/beast/app/BEASTVersion.java
+++ b/src/beast/app/BEASTVersion.java
@@ -19,7 +19,7 @@ public class BEASTVersion extends Version {
/**
* Version string: assumed to be in format x.x.x
*/
- private static final String VERSION = "2.4.2";
+ private static final String VERSION = "2.4.3";
private static final String DATE_STRING = "2002-2016";
diff --git a/src/beast/app/BEASTVersion2.java b/src/beast/app/BEASTVersion2.java
index 6e029ae..d91d2b6 100644
--- a/src/beast/app/BEASTVersion2.java
+++ b/src/beast/app/BEASTVersion2.java
@@ -9,7 +9,7 @@ public class BEASTVersion2 extends BEASTVersion {
/**
* Version string: assumed to be in format x.x.x
*/
- private static final String VERSION = "2.4.2";
+ private static final String VERSION = "2.4.3";
private static final String DATE_STRING = "2002-2016";
diff --git a/src/beast/app/BeastMCMC.java b/src/beast/app/BeastMCMC.java
index 974b38a..4497bfd 100644
--- a/src/beast/app/BeastMCMC.java
+++ b/src/beast/app/BeastMCMC.java
@@ -418,12 +418,13 @@ public class BeastMCMC {
Box box = Box.createHorizontalBox();
box.add(new JLabel("Beast XML File: "));
m_fileEntry = new JTextField();
- Dimension size = new Dimension(300, 20);
+ int fontsize = m_fileEntry.getFont().getSize();
+ Dimension size = new Dimension(300 * fontsize / 13, 20 * fontsize / 13);
m_fileEntry.setMinimumSize(size);
m_fileEntry.setPreferredSize(size);
m_fileEntry.setSize(size);
m_fileEntry.setToolTipText("Enter file name of Beast 2 XML file");
- m_fileEntry.setMaximumSize(new Dimension(1024, 20));
+ m_fileEntry.setMaximumSize(new Dimension(1024 * fontsize / 13, 20 * fontsize / 13));
box.add(m_fileEntry);
//box.add(Box.createHorizontalGlue());
@@ -459,7 +460,8 @@ public class BeastMCMC {
m_seedEntry.setPreferredSize(size);
m_seedEntry.setSize(size);
m_seedEntry.setToolTipText("Enter seed number used for initialising the random number generator");
- m_seedEntry.setMaximumSize(new Dimension(1024, 20));
+ int fontsize = m_seedEntry.getFont().getSize();
+ m_seedEntry.setMaximumSize(new Dimension(1024 * fontsize / 13, 20 * fontsize / 13));
box.add(m_seedEntry);
box.add(Box.createHorizontalGlue());
return box;
diff --git a/src/beast/app/DocMaker.java b/src/beast/app/DocMaker.java
index 8bded67..ed25980 100644
--- a/src/beast/app/DocMaker.java
+++ b/src/beast/app/DocMaker.java
@@ -423,8 +423,7 @@ public class DocMaker {
buf.append("<p>" + m_descriptions.get(beastObjectName) + "</p>\n");
// show citation (if any)
- Citation citation = beastObject.getCitation();
- if (citation != null) {
+ for (Citation citation : beastObject.getCitationList()) {
buf.append("<h2>Reference:</h2><p>" + citation.value() + "</p>\n");
if (citation.DOI().length() > 0) {
buf.append("<p><a href=\"http://dx.doi.org/" + citation.DOI() + "\">doi:" + citation.DOI() + "</a></p>\n");
diff --git a/src/beast/app/beastapp/BeastLauncher.java b/src/beast/app/beastapp/BeastLauncher.java
index 198c1f8..ef96819 100644
--- a/src/beast/app/beastapp/BeastLauncher.java
+++ b/src/beast/app/beastapp/BeastLauncher.java
@@ -29,7 +29,7 @@ import beast.app.util.Utils6;
* remainder of BEAST can be compiled against Java 1.8
* **/
public class BeastLauncher {
- private static String getVersion() {return "2.4.2";}
+ private static String getVersion() {return "2.4.3";}
private static String getMajorVersion() {return "2.4";}
private static String pathDelimiter;
diff --git a/src/beast/app/beastapp/BeastMain.java b/src/beast/app/beastapp/BeastMain.java
index 20f4c58..7375ebd 100644
--- a/src/beast/app/beastapp/BeastMain.java
+++ b/src/beast/app/beastapp/BeastMain.java
@@ -640,6 +640,8 @@ public class BeastMain {
}
Log.info.println();
Log.info.println("BEAST has terminated with an error. Please select QUIT from the menu.");
+ } else {
+ rte.printStackTrace();
}
// logger.severe will throw a RTE but we want to keep the console visible
} catch (XMLParserException e) {
diff --git a/src/beast/app/beauti/AlignmentImporter.java b/src/beast/app/beauti/AlignmentImporter.java
new file mode 100644
index 0000000..70080e8
--- /dev/null
+++ b/src/beast/app/beauti/AlignmentImporter.java
@@ -0,0 +1,54 @@
+package beast.app.beauti;
+
+import java.io.File;
+import java.util.List;
+
+import beast.core.BEASTInterface;
+
+
+/** Interface for importing alignments from file that are recognisable
+ * from for example its file extension (see canHandleFile()). BeautiAlignmentProvider
+ * will find implementations in packages through introspection, and these are used
+ * when a implementation is not available in the BEAST core.
+ **/
+public interface AlignmentImporter {
+
+ /** return list of file extensions
+ * that are supported by this importer
+ * @return
+ */
+ public String [] getFileExtensions();
+
+ /** process single file
+ * @param file
+ * @return list of Alignments found in file, and calibrations
+ */
+ public List<BEASTInterface> loadFile(File file);
+
+ /** check whether the file can be processed by this particular importer.
+ * Often, the first line of a file contains information about the nature
+ * of the file (e.g. #NEXUS in nexus files, <beast version="2.0"... in BEAST 2
+ * files) that can tell a bit more than just the file extension.
+ *
+ * By default, it only checks whether the file extension matches any of the
+ * ones listed in getFileExtension().
+ *
+ * return true if file can be processed by this importer.
+ */
+ default public boolean canHandleFile(File file) {
+ String name = file.getName();
+ if (name.lastIndexOf('.') == -1) {
+ // this file has no file extension
+ return false;
+ }
+
+ String extension = name.substring(name.lastIndexOf('.') + 1);
+ for (String s : getFileExtensions()) {
+ if (s.equals(extension)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/beast/app/beauti/AlignmentListInputEditor.java b/src/beast/app/beauti/AlignmentListInputEditor.java
index c6d7f65..8d73a4f 100644
--- a/src/beast/app/beauti/AlignmentListInputEditor.java
+++ b/src/beast/app/beauti/AlignmentListInputEditor.java
@@ -27,6 +27,7 @@ import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.CellEditorListener;
@@ -152,7 +153,12 @@ public class AlignmentListInputEditor extends ListInputEditor {
new FileDrop(null, scrollPane, focusBorder, new FileDrop.Listener() {
@Override
public void filesDropped(java.io.File[] files) {
- addFiles(files);
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ addFiles(files);
+ }
+ });
} // end filesDropped
}); // end FileDrop.Listener
diff --git a/src/beast/app/beauti/Beauti.java b/src/beast/app/beauti/Beauti.java
index bb3383a..16d58e8 100644
--- a/src/beast/app/beauti/Beauti.java
+++ b/src/beast/app/beauti/Beauti.java
@@ -208,12 +208,16 @@ public class Beauti extends JTabbedPane implements BeautiDocListener {
@Override
public void actionPerformed(ActionEvent ae) {
- if (!doc.getFileName().equals("")) {
- if (doc.validateModel() != DOC_STATUS.DIRTY) {
+ DOC_STATUS docStatus = doc.validateModel();
+ if (docStatus != DOC_STATUS.DIRTY) {
+ if (docStatus == DOC_STATUS.NO_DOCUMENT)
JOptionPane.showMessageDialog(null,
"There is no data to save to file");
- return;
- }
+
+ return;
+ }
+
+ if (!doc.getFileName().equals("")) {
saveFile(doc.getFileName());
// m_doc.isSaved();
} else {
diff --git a/src/beast/app/beauti/BeautiAlignmentProvider.java b/src/beast/app/beauti/BeautiAlignmentProvider.java
index fb526e1..44681f8 100644
--- a/src/beast/app/beauti/BeautiAlignmentProvider.java
+++ b/src/beast/app/beauti/BeautiAlignmentProvider.java
@@ -36,6 +36,7 @@ import beast.evolution.alignment.FilteredAlignment;
import beast.evolution.alignment.Sequence;
import beast.evolution.datatype.DataType;
import beast.math.distributions.MRCAPrior;
+import beast.util.AddOnManager;
import beast.util.NexusParser;
import beast.util.XMLParser;
@@ -43,7 +44,36 @@ import beast.util.XMLParser;
@Description("Class for creating new alignments to be edited by AlignmentListInputEditor")
public class BeautiAlignmentProvider extends BEASTObject {
-
+ /** map extension to importer class names **/
+ static List<AlignmentImporter> importers = null;
+ /**
+ * directory to pick up importers from *
+ */
+ final static String[] IMPLEMENTATION_DIR = {"beast.app"};
+
+ private void initImporters() {
+ importers = new ArrayList<>();
+ // add standard importers
+ importers.add(new NexusImporter());
+ importers.add(new XMLImporter());
+ importers.add(new FastaImporter());
+
+ // build up list of data types
+ List<String> importerClasses = AddOnManager.find(AlignmentImporter.class, IMPLEMENTATION_DIR);
+ for (String _class: importerClasses) {
+ try {
+ if (!_class.startsWith(this.getClass().getName())) {
+ AlignmentImporter importer = (AlignmentImporter) Class.forName(_class).newInstance();
+ importers.add(importer);
+ }
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ }
+
final public Input<BeautiSubTemplate> template = new Input<>("template", "template to be used after creating a new alignment. ", Validate.REQUIRED);
@Override
@@ -62,10 +92,17 @@ public class BeautiAlignmentProvider extends BEASTObject {
* return new alignment, return null if not successful
* **/
protected List<BEASTInterface> getAlignments(BeautiDoc doc) {
+ if (importers == null) {
+ initImporters();
+ }
+ Set<String> extensions = new HashSet<>();
+ for (AlignmentImporter importer : importers) {
+ for (String extension : importer.getFileExtensions()) {
+ extensions.add(extension);
+ }
+ }
File [] files = beast.app.util.Utils.getLoadFiles("Load Alignment File",
- new File(Beauti.g_sDir), "Alignment files", "xml",
- "fa","fas","fst","fasta","fna","ffn","faa","frn",
- "nex","nxs","nexus");
+ new File(Beauti.g_sDir), "Alignment files", extensions.toArray(new String[]{}));
if (files != null && files.length > 0) {
return getAlignments(doc, files);
}
@@ -79,100 +116,52 @@ public class BeautiAlignmentProvider extends BEASTObject {
* @return
*/
public List<BEASTInterface> getAlignments(BeautiDoc doc, File[] files) {
+ if (importers == null) {
+ initImporters();
+ }
List<BEASTInterface> selectedBEASTObjects = new ArrayList<>();
List<MRCAPrior> calibrations = new ArrayList<>();
for (File file : files) {
- String fileName = file.getName();
- String fileExtension = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
- Alignment alignment;
-
- switch (fileExtension) {
- case ".nex":
- case ".nxs":
- case ".nexus":
- NexusParser parser = new NexusParser();
- try {
- parser.parseFile(file);
- if (parser.filteredAlignments.size() > 0) {
- /**
- * sanity check: make sure the filters do not
- * overlap
- **/
- int[] used = new int[parser.m_alignment.getSiteCount()];
- Set<Integer> overlap = new HashSet<>();
- int partitionNr = 1;
- for (Alignment data : parser.filteredAlignments) {
- int[] indices = ((FilteredAlignment) data).indices();
- for (int i : indices) {
- if (used[i] > 0) {
- overlap.add(used[i] * 10000 + partitionNr);
- } else {
- used[i] = partitionNr;
- }
- }
- partitionNr++;
- }
- if (overlap.size() > 0) {
- String overlaps = "<html>Warning: The following partitions overlap:<br/>";
- for (int i : overlap) {
- overlaps += parser.filteredAlignments.get(i / 10000 - 1).getID()
- + " overlaps with "
- + parser.filteredAlignments.get(i % 10000 - 1).getID() + "<br/>";
- }
- overlaps += "The first thing you might want to do is delete some of these partitions.</html>";
- JOptionPane.showMessageDialog(null, overlaps);
- }
- /** add alignments **/
- for (Alignment data : parser.filteredAlignments) {
- sortByTaxonName(data.sequenceInput.get());
- selectedBEASTObjects.add(data);
- }
- if (parser.calibrations != null) {
- if (calibrations == null) {
- calibrations = new ArrayList<>();
- }
- calibrations.addAll(parser.calibrations);
- }
- } else {
- selectedBEASTObjects.add(parser.m_alignment);
- if (parser.calibrations != null) {
- if (calibrations == null) {
- calibrations = new ArrayList<>();
- }
- calibrations.addAll(parser.calibrations);
- }
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- JOptionPane.showMessageDialog(null, "Loading of " + fileName + " failed: " + ex.getMessage());
- return null;
+ // create list of importers that can handle the file
+ List<AlignmentImporter> availableImporters = new ArrayList<>();
+ for (AlignmentImporter importer : importers) {
+ if (importer.canHandleFile(file)) {
+ availableImporters.add(importer);
+ }
+ }
+
+ if (availableImporters.size() > 0) {
+ AlignmentImporter importer = availableImporters.get(0);
+ if (availableImporters.size() > 1) {
+ // let user choose an importer
+ List<String> descriptions = new ArrayList<>();
+ for (AlignmentImporter i : availableImporters) {
+ descriptions.add(((BEASTInterface)i).getDescription());
}
- break;
-
- case ".xml":
- alignment = (Alignment)getXMLData(file);
- selectedBEASTObjects.add(alignment);
- break;
-
- case ".fa":
- case ".fas":
- case ".fasta":
- case ".fst":
- case ".fna":
- case ".ffn":
- case ".faa":
- case ".frn":
- alignment = getFASTAData(file);
- sortByTaxonName(alignment.sequenceInput.get());
- selectedBEASTObjects.add(alignment);
- break;
-
- default:
- JOptionPane.showMessageDialog(null,
- "Unsupported sequence file extension.",
- "Error", JOptionPane.ERROR_MESSAGE);
- break;
+ String option = (String)JOptionPane.showInputDialog(null, "Which importer is appropriate", "Option",
+ JOptionPane.WARNING_MESSAGE, null, descriptions.toArray(), descriptions.get(0));
+ if (option == null) {
+ return selectedBEASTObjects;
+ }
+ int i = descriptions.indexOf(option);
+ importer = availableImporters.get(i);
+ }
+
+ // get a fresh instance
+ try {
+ importer = importer.getClass().newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ List<BEASTInterface> list = importer.loadFile(file);
+ selectedBEASTObjects.addAll(list);
+ } else {
+ JOptionPane.showMessageDialog(null,
+ "Unsupported sequence file.",
+ "Error", JOptionPane.ERROR_MESSAGE);
}
+
}
addAlignments(doc, selectedBEASTObjects);
if (calibrations != null) {
@@ -185,16 +174,18 @@ public class BeautiAlignmentProvider extends BEASTObject {
protected void addAlignments(BeautiDoc doc, List<BEASTInterface> selectedBEASTObjects) {
for (BEASTInterface beastObject : selectedBEASTObjects) {
- // ensure ID of alignment is unique
- int k = 0;
- String id = beastObject.getID();
- while (doc.pluginmap.containsKey(id)) {
- k++;
- id = beastObject.getID() + k;
+ if (beastObject instanceof Alignment) {
+ // ensure ID of alignment is unique
+ int k = 0;
+ String id = beastObject.getID();
+ while (doc.pluginmap.containsKey(id)) {
+ k++;
+ id = beastObject.getID() + k;
+ }
+ beastObject.setID(id);
+ sortByTaxonName(((Alignment) beastObject).sequenceInput.get());
+ doc.addAlignmentWithSubnet((Alignment) beastObject, getStartTemplate());
}
- beastObject.setID(id);
- sortByTaxonName(((Alignment) beastObject).sequenceInput.get());
- doc.addAlignmentWithSubnet((Alignment) beastObject, getStartTemplate());
}
}
@@ -262,94 +253,6 @@ public class BeautiAlignmentProvider extends BEASTObject {
}
}
- private Alignment getFASTAData(File file) {
- try {
- // grab alignment data
- Map<String, StringBuilder> seqMap = new HashMap<>();
- List<String> taxa = new ArrayList<>();
- String currentTaxon = null;
- BufferedReader fin = new BufferedReader(new FileReader(file));
- String missing = "?";
- String gap = "-";
- int totalCount = 4;
- String datatype = "nucleotide";
- // According to http://en.wikipedia.org/wiki/FASTA_format lists file formats and their data content
- // .fna = nucleic acid
- // .ffn = nucleotide coding regions
- // .frn = non-coding RNA
- // .ffa = amino acid
- boolean mayBeAminoacid = !(file.getName().toLowerCase().endsWith(".fna") || file.getName().toLowerCase().endsWith(".ffn") || file.getName().toLowerCase().endsWith(".frn"));
-
- while (fin.ready()) {
- String line = fin.readLine();
- if (line.startsWith(";")) {
- // it is a comment, ignore
- } else if (line.startsWith(">")) {
- // it is a taxon
- currentTaxon = line.substring(1).trim();
- // only up to first space
- currentTaxon = currentTaxon.replaceAll("\\s.*$", "");
- } else {
- // it is a data line
- if (currentTaxon == null) {
- fin.close();
- throw new RuntimeException("Expected taxon defined on first line");
- }
- if (seqMap.containsKey(currentTaxon)) {
- StringBuilder sb = seqMap.get(currentTaxon);
- sb.append(line);
- } else {
- StringBuilder sb = new StringBuilder();
- seqMap.put(currentTaxon, sb);
- sb.append(line);
- taxa.add(currentTaxon);
- }
- }
- }
- fin.close();
-
- int charCount = -1;
- Alignment alignment = new Alignment();
- for (final String taxon : taxa) {
- final StringBuilder bsData = seqMap.get(taxon);
- String data = bsData.toString();
- data = data.replaceAll("\\s", "");
- seqMap.put(taxon, new StringBuilder(data));
-
- if (charCount < 0) {charCount = data.length();}
- if (data.length() != charCount) {
- throw new IllegalArgumentException("Expected sequence of length " + charCount + " instead of " + data.length() + " for taxon " + taxon);
- }
- // map to standard missing and gap chars
- data = data.replace(missing.charAt(0), DataType.MISSING_CHAR);
- data = data.replace(gap.charAt(0), DataType.GAP_CHAR);
-
- if (mayBeAminoacid && datatype.equals("nucleotide") && !data.matches("[ACGTUXNacgtuxn?_-]+")) {
- datatype = "aminoacid";
- totalCount = 20;
- for (Sequence seq : alignment.sequenceInput.get()) {
- seq.totalCountInput.setValue(totalCount, seq);
- }
- }
-
- final Sequence sequence = new Sequence();
- data = data.replaceAll("[Xx]", "?");
- sequence.init(totalCount, taxon, data);
- sequence.setID(NexusParser.generateSequenceID(taxon));
- alignment.sequenceInput.setValue(sequence, alignment);
- }
- String ID = file.getName();
- ID = ID.substring(0, ID.lastIndexOf('.')).replaceAll("\\..*", "");
- alignment.setID(ID);
- alignment.dataTypeInput.setValue(datatype, alignment);
- alignment.initAndValidate();
- return alignment;
- } catch (Exception e) {
- e.printStackTrace();
- JOptionPane.showMessageDialog(null, "Loading of " + file.getName() + " failed: " + e.getMessage());
- }
- return null;
- }
private static BEASTInterface parseBeast1XML(String ID, String xml) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
@@ -417,4 +320,189 @@ public class BeautiAlignmentProvider extends BEASTObject {
return null;
}
+ @Description("NEXUS file importer")
+ class NexusImporter implements AlignmentImporter {
+
+ @Override
+ public String[] getFileExtensions() {
+ return new String[]{"nex","nxs","nexus"};
+ }
+
+ @Override
+ public List<BEASTInterface> loadFile(File file) {
+ List<BEASTInterface> selectedBEASTObjects = new ArrayList<>();
+ NexusParser parser = new NexusParser();
+ try {
+ parser.parseFile(file);
+ if (parser.filteredAlignments.size() > 0) {
+ /**
+ * sanity check: make sure the filters do not
+ * overlap
+ **/
+ int[] used = new int[parser.m_alignment.getSiteCount()];
+ Set<Integer> overlap = new HashSet<>();
+ int partitionNr = 1;
+ for (Alignment data : parser.filteredAlignments) {
+ int[] indices = ((FilteredAlignment) data).indices();
+ for (int i : indices) {
+ if (used[i] > 0) {
+ overlap.add(used[i] * 10000 + partitionNr);
+ } else {
+ used[i] = partitionNr;
+ }
+ }
+ partitionNr++;
+ }
+ if (overlap.size() > 0) {
+ String overlaps = "<html>Warning: The following partitions overlap:<br/>";
+ for (int i : overlap) {
+ overlaps += parser.filteredAlignments.get(i / 10000 - 1).getID()
+ + " overlaps with "
+ + parser.filteredAlignments.get(i % 10000 - 1).getID() + "<br/>";
+ }
+ overlaps += "The first thing you might want to do is delete some of these partitions.</html>";
+ JOptionPane.showMessageDialog(null, overlaps);
+ }
+ /** add alignments **/
+ for (Alignment data : parser.filteredAlignments) {
+ sortByTaxonName(data.sequenceInput.get());
+ selectedBEASTObjects.add(data);
+ }
+ if (parser.calibrations != null) {
+ selectedBEASTObjects.addAll(parser.calibrations);
+ }
+ } else {
+ selectedBEASTObjects.add(parser.m_alignment);
+ if (parser.calibrations != null) {
+ selectedBEASTObjects.addAll(parser.calibrations);
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ JOptionPane.showMessageDialog(null, "Loading of " + file.getPath() + " failed: " + ex.getMessage());
+ return null;
+ }
+ return selectedBEASTObjects;
+ }
+ }
+
+ @Description("BEAST XML file importer")
+ class XMLImporter implements AlignmentImporter {
+
+ @Override
+ public String[] getFileExtensions() {
+ return new String[]{"xml"};
+ }
+
+ @Override
+ public List<BEASTInterface> loadFile(File file) {
+ List<BEASTInterface> selectedBEASTObjects = new ArrayList<>();
+ Alignment alignment = (Alignment)getXMLData(file);
+ selectedBEASTObjects.add(alignment);
+ return selectedBEASTObjects;
+ }
+
+ }
+
+ @Description("Fasta file importer")
+ class FastaImporter implements AlignmentImporter {
+
+ @Override
+ public String[] getFileExtensions() {
+ return new String[]{"fa","fas","fst","fasta","fna","ffn","faa","frn"};
+ }
+
+ @Override
+ public List<BEASTInterface> loadFile(File file) {
+ List<BEASTInterface> selectedBEASTObjects = new ArrayList<>();
+ try {
+ // grab alignment data
+ Map<String, StringBuilder> seqMap = new HashMap<>();
+ List<String> taxa = new ArrayList<>();
+ String currentTaxon = null;
+ BufferedReader fin = new BufferedReader(new FileReader(file));
+ String missing = "?";
+ String gap = "-";
+ int totalCount = 4;
+ String datatype = "nucleotide";
+ // According to http://en.wikipedia.org/wiki/FASTA_format lists file formats and their data content
+ // .fna = nucleic acid
+ // .ffn = nucleotide coding regions
+ // .frn = non-coding RNA
+ // .ffa = amino acid
+ boolean mayBeAminoacid = !(file.getName().toLowerCase().endsWith(".fna") || file.getName().toLowerCase().endsWith(".ffn") || file.getName().toLowerCase().endsWith(".frn"));
+
+ while (fin.ready()) {
+ String line = fin.readLine();
+ if (line.startsWith(";")) {
+ // it is a comment, ignore
+ } else if (line.startsWith(">")) {
+ // it is a taxon
+ currentTaxon = line.substring(1).trim();
+ // only up to first space
+ currentTaxon = currentTaxon.replaceAll("\\s.*$", "");
+ } else {
+ // it is a data line
+ if (currentTaxon == null) {
+ fin.close();
+ throw new RuntimeException("Expected taxon defined on first line");
+ }
+ if (seqMap.containsKey(currentTaxon)) {
+ StringBuilder sb = seqMap.get(currentTaxon);
+ sb.append(line);
+ } else {
+ StringBuilder sb = new StringBuilder();
+ seqMap.put(currentTaxon, sb);
+ sb.append(line);
+ taxa.add(currentTaxon);
+ }
+ }
+ }
+ fin.close();
+
+ int charCount = -1;
+ Alignment alignment = new Alignment();
+ for (final String taxon : taxa) {
+ final StringBuilder bsData = seqMap.get(taxon);
+ String data = bsData.toString();
+ data = data.replaceAll("\\s", "");
+ seqMap.put(taxon, new StringBuilder(data));
+
+ if (charCount < 0) {charCount = data.length();}
+ if (data.length() != charCount) {
+ throw new IllegalArgumentException("Expected sequence of length " + charCount + " instead of " + data.length() + " for taxon " + taxon);
+ }
+ // map to standard missing and gap chars
+ data = data.replace(missing.charAt(0), DataType.MISSING_CHAR);
+ data = data.replace(gap.charAt(0), DataType.GAP_CHAR);
+
+ if (mayBeAminoacid && datatype.equals("nucleotide") && !data.matches("[ACGTUXNacgtuxn?_-]+")) {
+ datatype = "aminoacid";
+ totalCount = 20;
+ for (Sequence seq : alignment.sequenceInput.get()) {
+ seq.totalCountInput.setValue(totalCount, seq);
+ }
+ }
+
+ final Sequence sequence = new Sequence();
+ data = data.replaceAll("[Xx]", "?");
+ sequence.init(totalCount, taxon, data);
+ sequence.setID(NexusParser.generateSequenceID(taxon));
+ alignment.sequenceInput.setValue(sequence, alignment);
+ }
+ String ID = file.getName();
+ ID = ID.substring(0, ID.lastIndexOf('.')).replaceAll("\\..*", "");
+ alignment.setID(ID);
+ alignment.dataTypeInput.setValue(datatype, alignment);
+ alignment.initAndValidate();
+ selectedBEASTObjects.add(alignment);
+ } catch (Exception e) {
+ e.printStackTrace();
+ JOptionPane.showMessageDialog(null, "Loading of " + file.getName() + " failed: " + e.getMessage());
+ }
+ return selectedBEASTObjects;
+ }
+
+ }
+
}
diff --git a/src/beast/app/beauti/BeautiDoc.java b/src/beast/app/beauti/BeautiDoc.java
index 2d92a4f..c1a6d86 100644
--- a/src/beast/app/beauti/BeautiDoc.java
+++ b/src/beast/app/beauti/BeautiDoc.java
@@ -2504,6 +2504,7 @@ public class BeautiDoc extends BEASTObject implements RequiredInputProvider {
t.taxonsetInput.get().get(0).getID() + "=" + date
, dateTrait);
}
+ mrcaPrior.onlyUseTipsInput.setValue(true, mrcaPrior);
}
}
diff --git a/src/beast/app/beauti/GuessPatternDialog.java b/src/beast/app/beauti/GuessPatternDialog.java
index 88b61ac..4653762 100644
--- a/src/beast/app/beauti/GuessPatternDialog.java
+++ b/src/beast/app/beauti/GuessPatternDialog.java
@@ -134,7 +134,8 @@ public class GuessPatternDialog extends JDialog {
textRegExp.setText(pattern);
textRegExp.setColumns(10);
textRegExp.setToolTipText("Enter regular expression to match taxa");
- textRegExp.setMaximumSize(new Dimension(1024, 25));
+ int fontsize = textRegExp.getFont().getSize();
+ textRegExp.setMaximumSize(new Dimension(1024 * fontsize/13, 25 * fontsize/13));
GridBagConstraints gbc2 = new GridBagConstraints();
gbc2.insets = new Insets(0, 0, 5, 5);
gbc2.anchor = GridBagConstraints.WEST;
@@ -559,7 +560,7 @@ public class GuessPatternDialog extends JDialog {
}
if (trait.trim().length() == 0) {
- JOptionPane.showMessageDialog(m_parent, "Could not find traint information in the file. " +
+ JOptionPane.showMessageDialog(m_parent, "Could not find trait information in the file. " +
"Perhaps this is not a tab-delimited but space file?");
}
} catch (Exception e) {
diff --git a/src/beast/app/beauti/JPackageDialog.java b/src/beast/app/beauti/JPackageDialog.java
index afcd5f7..c591e15 100644
--- a/src/beast/app/beauti/JPackageDialog.java
+++ b/src/beast/app/beauti/JPackageDialog.java
@@ -1,5 +1,7 @@
package beast.app.beauti;
+import beast.app.util.Arguments;
+import beast.app.util.Utils;
import beast.core.Description;
import beast.util.AddOnManager;
import beast.util.Package;
@@ -9,11 +11,16 @@ import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
@@ -66,6 +73,7 @@ public class JPackageDialog extends JPanel {
@Override
public void run() {
resetPackages();
+ dataTable.updateWidths();
isRunning = false;
}
};
@@ -113,39 +121,73 @@ public class JPackageDialog extends JPanel {
private void createTable() {
DataTableModel dataTableModel = new DataTableModel();
dataTable = new PackageTable(dataTableModel);
-
- double [] widths = new double[dataTable.getColumnCount()];
- //double total = 0;
- for (int i = 0; i < dataTable.getColumnCount(); i++) {
- widths[i] = dataTable.getColumnModel().getColumn(i).getWidth();
- //total += widths[i];
- }
- widths[2] /= 4.0;
- dataTable.getColumnModel().getColumn(2).setPreferredWidth((int) widths[2]);
- dataTable.getColumnModel().getColumn(2).setMinWidth((int) widths[2]);
- widths[3] /= 2.0;
- dataTable.getColumnModel().getColumn(3).setPreferredWidth((int) widths[3]);
- widths[4] *= 2.0;
- dataTable.getColumnModel().getColumn(4).setPreferredWidth((int) widths[4]);
-
-
+ dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
+
// TODO:
// The following would work ...
//dataTable.setAutoCreateRowSorter(true);
// ...if all processing was done based on the data in the table,
// instead of the row number alone.
+
dataTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
dataTable.addMouseListener(new MouseAdapter() {
@Override
- public void mouseClicked(MouseEvent e) {
- if (e.getClickCount() == 2) {
- Package selPackage = getSelectedPackage(dataTable.getSelectedRow());
- showDetail(selPackage);
+ public void mouseClicked(MouseEvent e) {
+ if (dataTable.getSelectedColumn() == dataTableModel.linkColumn) {
+ URL url = getSelectedPackage(dataTable.getSelectedRow()).getProjectURL();
+ if (url != null) {
+ try {
+ Desktop.getDesktop().browse(url.toURI());
+ } catch (IOException | URISyntaxException e1) {
+ e1.printStackTrace();
+ }
+ }
+
+ } else {
+ if (e.getClickCount() == 2) {
+ Package selPackage = getSelectedPackage(dataTable.getSelectedRow());
+ showDetail(selPackage);
+ }
}
}
});
+
+ dataTable.addMouseMotionListener(new MouseMotionAdapter() {
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ super.mouseMoved(e);
+
+ int row = dataTable.rowAtPoint(e.getPoint());
+ int col = dataTable.columnAtPoint(e.getPoint());
+
+ int currentCursorType = dataTable.getCursor().getType();
+
+ if (col != dataTableModel.linkColumn) {
+ if (currentCursorType == Cursor.HAND_CURSOR)
+ dataTable.setCursor(Cursor.getDefaultCursor());
+
+ return;
+ }
+
+ Package thisPkg = getSelectedPackage(row);
+
+ if (thisPkg.getProjectURL() == null) {
+ if (currentCursorType == Cursor.HAND_CURSOR)
+ dataTable.setCursor(Cursor.getDefaultCursor());
+
+ return;
+ }
+
+ dataTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+
+ }
+ });
+
+ int size = dataTable.getFont().getSize();
+ dataTable.setRowHeight(20 * size/13);
}
+
private void resetPackages() {
packageMap.clear();
try {
@@ -351,7 +393,10 @@ public class JPackageDialog extends JPanel {
class DataTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
- String[] columnNames = {"Name", "Status/Version", "Latest", "Dependencies", "Detail"};
+ String[] columnNames = {"Name", "Installed", "Latest", "Dependencies", "Link", "Detail"};
+
+ public final int linkColumn = 4;
+ ImageIcon linkIcon = Utils.getIcon(BeautiPanel.ICONPATH + "link.png");
@Override
public int getColumnCount() {
@@ -370,12 +415,14 @@ public class JPackageDialog extends JPanel {
case 0:
return aPackage.getName();
case 1:
- return aPackage.getStatusString();
+ return aPackage.getInstalledVersion();
case 2:
- return aPackage.isAvailable() ? aPackage.getLatestVersion() : "not available";
+ return aPackage.getLatestVersion();
case 3:
return aPackage.getDependenciesString();
case 4:
+ return aPackage.getProjectURL() != null ? linkIcon : null ;
+ case 5:
return aPackage.getDescription();
default:
throw new IllegalArgumentException("unknown column, " + col);
@@ -455,6 +502,14 @@ public class JPackageDialog extends JPanel {
}
@Override
+ public Class<?> getColumnClass(int column) {
+ if (column != ((DataTableModel)getModel()).linkColumn)
+ return String.class;
+ else
+ return ImageIcon.class;
+ }
+
+ @Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
@@ -488,5 +543,70 @@ public class JPackageDialog extends JPanel {
return c;
}
+
+ /**
+ * Calculate the width based on the widest cell renderer for the
+ * given column.
+ *
+ * @param cIdx column index
+ * @return maximum width.
+ */
+ private int getColumnDataWidth(int cIdx)
+ {
+ int preferredWidth = 0;
+ int maxWidth = getColumnModel().getColumn(cIdx).getMaxWidth();
+
+ for (int row = 0; row < getRowCount(); row++)
+ {
+ preferredWidth = Math.max(preferredWidth, getCellDataWidth(row, cIdx));
+
+ // We've exceeded the maximum width, no need to check other rows
+
+ if (preferredWidth >= maxWidth)
+ break;
+ }
+
+ preferredWidth = Math.max(preferredWidth, getHeaderWidth(cIdx));
+
+ return preferredWidth;
+ }
+
+ /*
+ * Get the preferred width for the specified cell
+ */
+ private int getCellDataWidth(int row, int column)
+ {
+ // Inovke the renderer for the cell to calculate the preferred width
+
+ TableCellRenderer cellRenderer = getCellRenderer(row, column);
+ Component c = prepareRenderer(cellRenderer, row, column);
+
+ return c.getPreferredSize().width + 2*getIntercellSpacing().width;
+ }
+
+ /*
+ * Get the preferred width for the specified header
+ */
+ private int getHeaderWidth(int cIdx)
+ {
+ // Inovke the renderer for the cell to calculate the preferred width
+
+ TableColumn column = getColumnModel().getColumn(cIdx);
+ TableCellRenderer cellRenderer = getDefaultRenderer(String.class);
+ Component c = cellRenderer.getTableCellRendererComponent(this, column.getHeaderValue(), false, false, -1, cIdx);
+
+ return c.getPreferredSize().width + 2*getIntercellSpacing().width;
+ }
+
+
+ void updateWidths() {
+ for (int cIdx = 0; cIdx < getColumnCount(); cIdx++) {
+ int width = getColumnDataWidth(cIdx);
+
+ TableColumn column = getColumnModel().getColumn(cIdx);
+ getTableHeader().setResizingColumn(column);
+ column.setWidth(width);
+ }
+ }
}
}
diff --git a/src/beast/app/beauti/JPackageRepositoryDialog.java b/src/beast/app/beauti/JPackageRepositoryDialog.java
index 5373d57..1a5ee05 100644
--- a/src/beast/app/beauti/JPackageRepositoryDialog.java
+++ b/src/beast/app/beauti/JPackageRepositoryDialog.java
@@ -63,6 +63,8 @@ public class JPackageRepositoryDialog extends JDialog {
// Assemble table
final RepoTableModel repoTableModel = new RepoTableModel(urls);
final JTable repoTable = new JTable(repoTableModel);
+ int size = repoTable.getFont().getSize();
+ repoTable.setRowHeight(20 * size/13);
repoTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane scrollPane = new JScrollPane(repoTable);
getContentPane().add(scrollPane, BorderLayout.CENTER);
diff --git a/src/beast/app/beauti/MRCAPriorInputEditor.java b/src/beast/app/beauti/MRCAPriorInputEditor.java
index 35b12a0..18f0632 100644
--- a/src/beast/app/beauti/MRCAPriorInputEditor.java
+++ b/src/beast/app/beauti/MRCAPriorInputEditor.java
@@ -1,7 +1,10 @@
package beast.app.beauti;
+import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -10,15 +13,19 @@ import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
+import javax.swing.JOptionPane;
import beast.app.draw.BEASTObjectPanel;
+import beast.app.draw.BooleanInputEditor;
import beast.app.draw.InputEditor;
import beast.app.draw.SmallButton;
import beast.core.BEASTInterface;
import beast.core.Input;
+import beast.core.Operator;
import beast.core.util.Log;
import beast.evolution.alignment.Taxon;
import beast.evolution.alignment.TaxonSet;
+import beast.evolution.operators.TipDatesRandomWalker;
import beast.evolution.tree.Tree;
import beast.math.distributions.MRCAPrior;
import beast.math.distributions.OneOnX;
@@ -58,9 +65,18 @@ public class MRCAPriorInputEditor extends InputEditor.Base {
MRCAPrior prior2 = (MRCAPrior) list.get(itemNr);
try {
TaxonSet taxonset = prior2.taxonsetInput.get();
+ List<Taxon> originalTaxa = new ArrayList<>();
+ originalTaxa.addAll(taxonset.taxonsetInput.get());
Set<Taxon> candidates = getTaxonCandidates(prior2);
TaxonSetDialog dlg = new TaxonSetDialog(taxonset, candidates, doc);
if (dlg.showDialog()) {
+ if (dlg.taxonSet.taxonsetInput.get().size() == 0) {
+ JOptionPane.showMessageDialog(doc.beauti, "At least one taxon should be included in the taxon set",
+ "Error specifying taxon set", JOptionPane.ERROR_MESSAGE);
+ taxonset.taxonsetInput.get().addAll(originalTaxa);
+ return;
+ }
+
prior2.taxonsetInput.setValue(dlg.taxonSet, prior2);
int i = 1;
String id = dlg.taxonSet.getID();
@@ -202,5 +218,90 @@ public class MRCAPriorInputEditor extends InputEditor.Base {
}
}
}
+
+
+ InputEditor tipsonlyEditor;
+
+ public InputEditor createTipsonlyEditor() throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ BooleanInputEditor e = new BooleanInputEditor (doc) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void init(Input<?> input, BEASTInterface beastObject, int itemNr, ExpandOption isExpandOption,
+ boolean addButtons) {
+ super.init(input, beastObject, itemNr, isExpandOption, addButtons);
+ // hack to get to JCheckBox
+ Component [] components = getComponents();
+ ((JCheckBox) components[0]).addActionListener(e -> {
+ JCheckBox src = (JCheckBox) e.getSource();
+ if (src.isSelected()) {
+ enableTipSampling();
+ } else {
+ disableTipSampling();
+ }
+ });
+ }
+
+ };
+
+ MRCAPrior prior = (MRCAPrior) m_beastObject;
+ Input<?> input = prior.onlyUseTipsInput;
+ e.init(input, prior, -1, ExpandOption.FALSE, false);
+ return e;
+ }
+
+ // add TipDatesRandomWalker (if not present) and add to list of operators
+ private void enableTipSampling() {
+ // First, create/find the operator
+ TipDatesRandomWalker operator = null;
+ MRCAPrior prior = (MRCAPrior) m_beastObject;
+ TaxonSet taxonset = prior.taxonsetInput.get();
+ taxonset.initAndValidate();
+
+ // see if an old operator still hangs around -- happens when toggling the TipsOnly checkbox a few times
+ for (BEASTInterface o : taxonset.getOutputs()) {
+ if (o instanceof TipDatesRandomWalker) {
+ operator = (TipDatesRandomWalker) o;
+ }
+ }
+
+ if (operator == null) {
+ operator = new TipDatesRandomWalker();
+ operator.initByName("tree", prior.treeInput.get(), "taxonset", taxonset, "windowSize", 1.0, "weight", 1.0);
+ }
+ operator.setID("tipDatesSampler." + taxonset.getID());
+
+ doc.mcmc.get().setInputValue("operator", operator);
+ }
+
+ // remove TipDatesRandomWalker from list of operators
+ private void disableTipSampling() {
+ // First, find the operator
+ TipDatesRandomWalker operator = null;
+ MRCAPrior prior = (MRCAPrior) m_beastObject;
+ TaxonSet taxonset = prior.taxonsetInput.get();
+
+ // We cannot rely on the operator ID created in enableTipSampling()
+ // since the taxoneset name may have changed.
+ // However, if there is an TipDatesRandomWalker with taxonset as input, we want to remove it.
+ for (BEASTInterface o : taxonset.getOutputs()) {
+ if (o instanceof TipDatesRandomWalker) {
+ operator = (TipDatesRandomWalker) o;
+ }
+ }
+
+ if (operator == null) {
+ // should never happen
+ return;
+ }
+
+ // remove from list of operators
+ Object o = doc.mcmc.get().getInput("operator");
+ if (o instanceof Input<?>) {
+ Input<List<Operator>> operatorInput = (Input<List<Operator>>) o;
+ List<Operator> operators = operatorInput.get();
+ operators.remove(operator);
+ }
+ }
}
diff --git a/src/beast/app/beauti/OperatorListInputEditor.java b/src/beast/app/beauti/OperatorListInputEditor.java
index a490b6a..241fcf7 100644
--- a/src/beast/app/beauti/OperatorListInputEditor.java
+++ b/src/beast/app/beauti/OperatorListInputEditor.java
@@ -81,7 +81,8 @@ public class OperatorListInputEditor extends ListInputEditor {
Dimension size = new Dimension(50, 25);
weightEntry.setMinimumSize(size);
weightEntry.setPreferredSize(size);
- weightEntry.setMaximumSize(new Dimension(50, 50));
+ int fontsize = weightEntry.getFont().getSize();
+ weightEntry.setMaximumSize(new Dimension(50 * fontsize/13, 50 * fontsize/13));
itemBox.add(weightEntry);
return this;
diff --git a/src/beast/app/beauti/ParametricDistributionInputEditor.java b/src/beast/app/beauti/ParametricDistributionInputEditor.java
index 9976d49..611a85a 100644
--- a/src/beast/app/beauti/ParametricDistributionInputEditor.java
+++ b/src/beast/app/beauti/ParametricDistributionInputEditor.java
@@ -119,7 +119,6 @@ public class ParametricDistributionInputEditor extends BEASTObjectInputEditor {
// ignore
}
- Font font = g.getFont();
double minValue = 0.1;
double maxValue = 1;
try {
@@ -188,6 +187,7 @@ public class ParametricDistributionInputEditor extends BEASTObjectInputEditor {
final int NR_OF_TICKS_Y = m_nTicks;
// draw ticks on edge
+ Font font = g.getFont();
Font smallFont = new Font(font.getName(), font.getStyle(), font.getSize() * 2/3);
g.setFont(smallFont);
@@ -248,7 +248,8 @@ public class ParametricDistributionInputEditor extends BEASTObjectInputEditor {
g.drawString(ylabels[i], leftMargin - TICK_LENGTH - 1 - sfm.stringWidth(ylabels[i]), y + 3);
}
- g.setFont(new Font(font.getName(), font.getStyle(), font.getSize() * 10 / 12));
+ int fontHeight = font.getSize() * 10 / 12;
+ g.setFont(new Font(font.getName(), font.getStyle(), fontHeight));
try {
FontMetrics fontMetrics = g.getFontMetrics();
String[] strs = new String[]{"2.5% Quantile", "5% Quantile", "Median", "95% Quantile", "97.5% Quantile"};
@@ -256,23 +257,23 @@ public class ParametricDistributionInputEditor extends BEASTObjectInputEditor {
mayBeUnstable = false;
for (k = 0; k < 5; k++) {
- int y = TOP_MARGIN + graphHeight + bottomMargin + g.getFontMetrics().getMaxAscent() + k * 10;
+ int y = TOP_MARGIN + graphHeight + bottomMargin + g.getFontMetrics().getMaxAscent() + k * fontHeight;
try {
g.drawString(format(m_distr.inverseCumulativeProbability(quantiles[k])), graphWidth / 2 + leftMargin, y);
} catch (MathException e) {
g.drawString("not available", graphWidth / 2 + leftMargin, y);
}
- g.drawString(strs[k], graphWidth / 2 - fontMetrics.stringWidth(strs[k]) + leftMargin - 10, y);
+ g.drawString(strs[k], graphWidth / 2 - fontMetrics.stringWidth(strs[k]) + leftMargin - fontHeight, y);
}
if (mayBeUnstable) {
- int x = graphWidth * 3/ 4 + leftMargin; int y =TOP_MARGIN + graphHeight + bottomMargin + 10;
- g.drawString("* numbers", x, y + 20);
- g.drawString("may not be", x, y + 30);
- g.drawString("accurate", x, y + 40);
+ int x = graphWidth * 3/ 4 + leftMargin; int y =TOP_MARGIN + graphHeight + bottomMargin + fontHeight;
+ g.drawString("* numbers", x, y + 2*fontHeight);
+ g.drawString("may not be", x, y + 3*fontHeight);
+ g.drawString("accurate", x, y + 4*fontHeight);
}
try {
- g.drawString("mean " + format(m_distr.getMean()), graphWidth * 3/ 4 + leftMargin, TOP_MARGIN + graphHeight + bottomMargin + 10);
+ g.drawString("mean " + format(m_distr.getMean()), graphWidth * 3/ 4 + leftMargin, TOP_MARGIN + graphHeight + bottomMargin + fontHeight);
} catch (RuntimeException e) {
// catch in case it is not implemented.
}
diff --git a/src/beast/app/beauti/PriorInputEditor.java b/src/beast/app/beauti/PriorInputEditor.java
index 9d9060a..bee8056 100644
--- a/src/beast/app/beauti/PriorInputEditor.java
+++ b/src/beast/app/beauti/PriorInputEditor.java
@@ -10,6 +10,7 @@ import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
+import javax.swing.text.StyledEditorKit.FontSizeAction;
import beast.app.draw.BEASTObjectDialog;
import beast.app.draw.InputEditor;
@@ -125,7 +126,8 @@ public class PriorInputEditor extends InputEditor.Base {
itemBox.add(Box.createHorizontalStrut(10));
itemBox.add(rangeButton);
}
- comboBox.setMaximumSize(new Dimension(1024, 24));
+ int fontsize = comboBox.getFont().getSize();
+ comboBox.setMaximumSize(new Dimension(1024 * fontsize / 13, 24 * fontsize / 13));
String tipText = getDoc().tipTextMap.get(beastObject.getID());
//System.out.println(beastObject.getID());
diff --git a/src/beast/app/beauti/PriorListInputEditor.java b/src/beast/app/beauti/PriorListInputEditor.java
index 48aa72c..c8e5a53 100644
--- a/src/beast/app/beauti/PriorListInputEditor.java
+++ b/src/beast/app/beauti/PriorListInputEditor.java
@@ -36,6 +36,7 @@ import beast.evolution.tree.TreeInterface;
import beast.math.distributions.MRCAPrior;
import beast.math.distributions.OneOnX;
import beast.math.distributions.Prior;
+import beast.util.AddOnManager;
@@ -216,63 +217,131 @@ public class PriorListInputEditor extends ListInputEditor {
sync();
refreshPanel();
} // addItem
+
+ List<PriorProvider> priorProviders;
+
+ private void initProviders() {
+ priorProviders = new ArrayList<>();
+ priorProviders.add(new MRCAPriorProvider());
+
+ // build up list of data types
+ List<String> importerClasses = AddOnManager.find(PriorProvider.class, new String[]{"beast.app"});
+ for (String _class: importerClasses) {
+ try {
+ if (!_class.startsWith(this.getClass().getName())) {
+ PriorProvider priorProvider = (PriorProvider) Class.forName(_class).newInstance();
+ priorProviders.add(priorProvider);
+ }
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
@Override
protected List<BEASTInterface> pluginSelector(Input<?> input, BEASTInterface parent, List<String> tabooList) {
- MRCAPrior prior = new MRCAPrior();
- try {
-
- List<Tree> trees = new ArrayList<>();
- getDoc().scrubAll(true, false);
- State state = (State) doc.pluginmap.get("state");
- for (StateNode node : state.stateNodeInput.get()) {
- if (node instanceof Tree) { // && ((Tree) node).m_initial.get() != null) {
- trees.add((Tree) node);
- }
- }
- int treeIndex = 0;
- if (trees.size() > 1) {
- String[] treeIDs = new String[trees.size()];
- for (int j = 0; j < treeIDs.length; j++) {
- treeIDs[j] = trees.get(j).getID();
- }
- treeIndex = JOptionPane.showOptionDialog(null, "Select a tree", "MRCA selector",
- JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
- treeIDs, trees.get(0));
- }
- if (treeIndex < 0) {
- return null;
- }
- prior.treeInput.setValue(trees.get(treeIndex), prior);
- TaxonSet taxonSet = new TaxonSet();
-
- TaxonSetDialog dlg = new TaxonSetDialog(taxonSet, getTaxonCandidates(prior), doc);
- if (!dlg.showDialog() || dlg.taxonSet.getID() == null || dlg.taxonSet.getID().trim().equals("")) {
- return null;
- }
- taxonSet = dlg.taxonSet;
- int i = 1;
- String id = taxonSet.getID();
- while (doc.pluginmap.containsKey(taxonSet.getID()) && doc.pluginmap.get(taxonSet.getID()) != taxonSet) {
- taxonSet.setID(id + i);
- i++;
- }
- BEASTObjectPanel.addPluginToMap(taxonSet, doc);
- prior.taxonsetInput.setValue(taxonSet, prior);
- prior.setID(taxonSet.getID() + ".prior");
- // this sets up the type
- prior.distInput.setValue(new OneOnX(), prior);
- // this removes the parametric distribution
- prior.distInput.setValue(null, prior);
+ if (priorProviders == null) {
+ initProviders();
+ }
+ PriorProvider priorProvider = priorProviders.get(0);
+ if (priorProviders.size() > 1) {
+ // let user choose a PriorProvider
+ List<String> descriptions = new ArrayList<>();
+ for (PriorProvider i : priorProviders) {
+ descriptions.add(i.getDescription());
+ }
+ String option = (String)JOptionPane.showInputDialog(null, "Which prior do you want to add", "Option",
+ JOptionPane.WARNING_MESSAGE, null, descriptions.toArray(), descriptions.get(0));
+ if (option == null) {
+ return null;
+ }
+ int i = descriptions.indexOf(option);
+ priorProvider = priorProviders.get(i);
- Logger logger = (Logger) doc.pluginmap.get("tracelog");
- logger.loggersInput.setValue(prior, logger);
- } catch (Exception e) {
- // TODO: handle exception
- }
+ }
+
List<BEASTInterface> selectedPlugins = new ArrayList<>();
- selectedPlugins.add(prior);
- g_collapsedIDs.add(prior.getID());
+ List<Distribution> distrs = priorProvider.createDistribution(doc);
+ if (distrs == null) {
+ return null;
+ }
+ for (Distribution distr : distrs) {
+ selectedPlugins.add(distr);
+ }
return selectedPlugins;
}
+
+ class MRCAPriorProvider implements PriorProvider {
+ @Override
+ public List<Distribution> createDistribution(BeautiDoc doc) {
+ MRCAPrior prior = new MRCAPrior();
+ try {
+
+ List<Tree> trees = new ArrayList<>();
+ getDoc().scrubAll(true, false);
+ State state = (State) doc.pluginmap.get("state");
+ for (StateNode node : state.stateNodeInput.get()) {
+ if (node instanceof Tree) { // && ((Tree) node).m_initial.get() != null) {
+ trees.add((Tree) node);
+ }
+ }
+ int treeIndex = 0;
+ if (trees.size() > 1) {
+ String[] treeIDs = new String[trees.size()];
+ for (int j = 0; j < treeIDs.length; j++) {
+ treeIDs[j] = trees.get(j).getID();
+ }
+ treeIndex = JOptionPane.showOptionDialog(null, "Select a tree", "MRCA selector",
+ JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
+ treeIDs, trees.get(0));
+ }
+ if (treeIndex < 0) {
+ return null;
+ }
+ prior.treeInput.setValue(trees.get(treeIndex), prior);
+ TaxonSet taxonSet = new TaxonSet();
+
+ TaxonSetDialog dlg = new TaxonSetDialog(taxonSet, getTaxonCandidates(prior), doc);
+ if (!dlg.showDialog() || dlg.taxonSet.getID() == null || dlg.taxonSet.getID().trim().equals("")) {
+ return null;
+ }
+ taxonSet = dlg.taxonSet;
+ if (taxonSet.taxonsetInput.get().size() == 0) {
+ JOptionPane.showMessageDialog(doc.beauti, "At least one taxon should be included in the taxon set",
+ "Error specifying taxon set", JOptionPane.ERROR_MESSAGE);
+ return null;
+ }
+ int i = 1;
+ String id = taxonSet.getID();
+ while (doc.pluginmap.containsKey(taxonSet.getID()) && doc.pluginmap.get(taxonSet.getID()) != taxonSet) {
+ taxonSet.setID(id + i);
+ i++;
+ }
+ BEASTObjectPanel.addPluginToMap(taxonSet, doc);
+ prior.taxonsetInput.setValue(taxonSet, prior);
+ prior.setID(taxonSet.getID() + ".prior");
+ // this sets up the type
+ prior.distInput.setValue(new OneOnX(), prior);
+ // this removes the parametric distribution
+ prior.distInput.setValue(null, prior);
+
+ Logger logger = (Logger) doc.pluginmap.get("tracelog");
+ logger.loggersInput.setValue(prior, logger);
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+ List<Distribution> selectedPlugins = new ArrayList<>();
+ selectedPlugins.add(prior);
+ g_collapsedIDs.add(prior.getID());
+ return selectedPlugins;
+ }
+
+ @Override
+ public String getDescription() {
+ return "MRCA prior";
+ }
+
+ }
}
diff --git a/src/beast/app/beauti/PriorProvider.java b/src/beast/app/beauti/PriorProvider.java
new file mode 100644
index 0000000..39fbd26
--- /dev/null
+++ b/src/beast/app/beauti/PriorProvider.java
@@ -0,0 +1,24 @@
+package beast.app.beauti;
+
+import java.util.List;
+
+import beast.core.Distribution;
+
+/** packages can implement a PriorProvider. The PrioListInputEditor will
+ * pick up these PriorProviders by introspection. When a user selects the +
+ * button, the user can check whichever PriorProvider to add a new Distribution
+ * to the list of priors.
+ */
+public interface PriorProvider {
+
+ /** create a distribution, but do not add to the prior -- this is handled
+ * by the PrioListInputEditor. If null is returned, the operator is canceled.
+ * @param doc useful to get information about the model being edited
+ * @return Distribution to be added to prior, or null if nothing should
+ * be done.
+ */
+ public List<Distribution> createDistribution(BeautiDoc doc);
+
+ /** return description to be used in drop-down box for selecting among PriorProviders **/
+ public String getDescription();
+}
diff --git a/src/beast/app/beauti/TaxonSetDialog.java b/src/beast/app/beauti/TaxonSetDialog.java
index 2b72d14..7f993b4 100644
--- a/src/beast/app/beauti/TaxonSetDialog.java
+++ b/src/beast/app/beauti/TaxonSetDialog.java
@@ -137,7 +137,8 @@ public class TaxonSetDialog extends JDialog {
//filterEntry.setPreferredSize(size);
//filterEntry.setSize(size);
filterEntry.setToolTipText("Enter regular expression to match taxa");
- filterEntry.setMaximumSize(new Dimension(1024, 50));
+ int fontsize = filterEntry.getFont().getSize();
+ filterEntry.setMaximumSize(new Dimension(1024 * fontsize / 13, 50 * fontsize / 13));
box.add(filterEntry);
box.add(Box.createHorizontalGlue());
@@ -198,7 +199,8 @@ public class TaxonSetDialog extends JDialog {
}
});
- box.setMaximumSize(new Dimension(400, 100));
+ int fontsize = idEntry.getFont().getSize();
+ box.setMaximumSize(new Dimension(400 * fontsize / 13, 100 * fontsize / 13));
return box;
}
diff --git a/src/beast/app/beauti/TaxonSetInputEditor.java b/src/beast/app/beauti/TaxonSetInputEditor.java
index 9b06762..31d4901 100644
--- a/src/beast/app/beauti/TaxonSetInputEditor.java
+++ b/src/beast/app/beauti/TaxonSetInputEditor.java
@@ -209,8 +209,10 @@ public class TaxonSetInputEditor extends InputEditor.Base {
});
m_table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
m_table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
- m_table.getColumnModel().getColumn(0).setPreferredWidth(250);
- m_table.getColumnModel().getColumn(1).setPreferredWidth(250);
+ int size = m_table.getFont().getSize();
+ m_table.setRowHeight(20 * size/13);
+ m_table.getColumnModel().getColumn(0).setPreferredWidth(250 * size/13);
+ m_table.getColumnModel().getColumn(1).setPreferredWidth(250 * size/13);
JTableHeader header = m_table.getTableHeader();
header.addMouseListener(new ColumnHeaderListener());
@@ -474,7 +476,8 @@ public class TaxonSetInputEditor extends InputEditor.Base {
// filterEntry.setPreferredSize(size);
// filterEntry.setSize(size);
filterEntry.setToolTipText("Enter regular expression to match taxa");
- filterEntry.setMaximumSize(new Dimension(1024, 20));
+ int size = filterEntry.getFont().getSize();
+ filterEntry.setMaximumSize(new Dimension(1024, 20 * size/13));
filterBox.add(filterEntry);
filterBox.add(Box.createHorizontalGlue());
filterEntry.getDocument().addDocumentListener(new DocumentListener() {
diff --git a/src/beast/app/beauti/TipDatesInputEditor.java b/src/beast/app/beauti/TipDatesInputEditor.java
index 55d638e..e3f653e 100644
--- a/src/beast/app/beauti/TipDatesInputEditor.java
+++ b/src/beast/app/beauti/TipDatesInputEditor.java
@@ -1,9 +1,7 @@
package beast.app.beauti;
import java.awt.*;
-import java.awt.event.ActionEvent;
import java.text.DateFormat;
-import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.EventObject;
@@ -27,8 +25,6 @@ import beast.core.BEASTInterface;
import beast.core.Input;
import beast.core.util.Log;
import beast.evolution.alignment.Taxon;
-import beast.evolution.alignment.TaxonSet;
-import beast.evolution.operators.TipDatesRandomWalker;
import beast.evolution.tree.TraitSet;
import beast.evolution.tree.Tree;
@@ -108,165 +104,10 @@ public class TipDatesInputEditor extends BEASTObjectInputEditor {
if (traitSet != null) {
box.add(createButtonBox());
box.add(createListBox());
- box.add(createSamplingBox());
}
add(box);
}
} // init
- final static int NO_TIP_SAMPLING = 0;
- final static int SAMPLE_TIPS_SAME_PRIOR = 1;
- final static int SAMPLE_TIPS_MULTIPLE_PRIOR = 2;
- final static String ALL_TAXA = "all";
- int m_iMode = NO_TIP_SAMPLING;
-
- private Component createSamplingBox() {
- Box samplingBox = Box.createHorizontalBox();
- JComboBox<String> comboBox = new JComboBox<>(new String[]{"no tips sampling", "sample tips from taxon set:"});// ,"sample tips with individual priors"});
-
- comboBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, comboBox.getPreferredSize().height));
-
- // determine mode
- m_iMode = NO_TIP_SAMPLING;
- // count nr of TipDateScalers with weight > 0
- String treeID = tree.getID();
- String operatorID = "allTipDatesRandomWalker.t:" + treeID.substring(treeID.lastIndexOf(":") + 1);
- TipDatesRandomWalker operator = (TipDatesRandomWalker) doc.pluginmap.get(operatorID);
- if (operator != null && operator.m_pWeight.get() > 0) {
- m_iMode = SAMPLE_TIPS_SAME_PRIOR;
- }
-
- m_iMode = Math.min(m_iMode, 2);
- comboBox.setSelectedIndex(m_iMode);
- comboBox.addActionListener(this::selectMode);
- samplingBox.add(comboBox);
-
- taxonsets = new ArrayList<>();
- Taxon allTaxa = getDoc().getTaxon(ALL_TAXA);
- allTaxa.setID(ALL_TAXA);
- taxonsets.add(allTaxa);
- List<String> taxonSetIDs = new ArrayList<>();
- taxonSetIDs.add(ALL_TAXA);
- for (Taxon taxon : doc.taxaset.values()) {
- if (taxon instanceof TaxonSet) {
- taxonsets.add(taxon);
- taxonSetIDs.add(taxon.getID());
- }
- }
- JComboBox<String> comboBox2 = new JComboBox<>(taxonSetIDs.toArray(new String[]{}));
-
- comboBox2.setMaximumSize(new Dimension(Integer.MAX_VALUE, comboBox2.getPreferredSize().height));
-
- if (operator == null) {
- comboBox.setEnabled(false);
- comboBox2.setEnabled(false);
- } else {
- // find TipDatesSampler and set TaxonSet input
- Taxon set = operator.m_taxonsetInput.get();
- if (set != null) {
- int i = taxonSetIDs.indexOf(set.getID());
- comboBox2.setSelectedIndex(i);
- }
-
- comboBox2.addActionListener(this::selectTaxonSet);
- }
- samplingBox.add(comboBox2);
-
- return samplingBox;
- }
-
- private void selectTaxonSet(ActionEvent e) {
- @SuppressWarnings("unchecked")
- JComboBox<String> comboBox = (JComboBox<String>) e.getSource();
- String taxonSetID = (String) comboBox.getSelectedItem();
- Taxon taxonset = null;;
- for (Taxon taxon : taxonsets) {
- if (taxon.getID().equals(taxonSetID)) {
- taxonset = taxon;
- break;
- }
- }
-
- if (taxonset.getID().equals(ALL_TAXA)) {
- taxonset = null;
- }
- try {
- // find TipDatesSampler and set TaxonSet input
-
- String treeID = tree.getID();
- String operatorID = "allTipDatesRandomWalker.t:" + treeID.substring(treeID.lastIndexOf(":") + 1);
- TipDatesRandomWalker operator = (TipDatesRandomWalker) doc.pluginmap.get(operatorID);
- Log.warning.println("treeID = " + treeID);
- Log.warning.println("operatorID = " + operatorID);
- Log.warning.println("operator = " + operator);
- operator.m_taxonsetInput.setValue(taxonset, operator);
-
-// for (BEASTObject beastObject : traitSet.outputs) {
-// if (beastObject instanceof Tree) {
-// for (BEASTObject beastObject2 : beastObject.outputs) {
-// if (beastObject2 instanceof TipDatesScaler) {
-// TipDatesScaler operator = (TipDatesScaler) beastObject2;
-// operator.m_taxonsetInput.setValue(taxonset, operator);
-// }
-// }
-// }
-// }
-//
-// // TODO: find MRACPriors and set TaxonSet inputs
-// for (BEASTObject beastObject : traitSet.outputs) {
-// if (beastObject instanceof Tree) {
-// for (BEASTObject beastObject2 : beastObject.outputs) {
-// if (beastObject2 instanceof MRCAPrior) {
-// MRCAPrior prior = (MRCAPrior) beastObject2;
-// if (prior.m_bOnlyUseTipsInput.get()) {
-// prior.m_taxonset.setValue(taxonset, prior);
-// }
-// }
-// }
-// }
-// }
- } catch (Exception ex) {
- // TODO: handle exception
- ex.printStackTrace();
- }
- }
-
- private void selectMode(ActionEvent e) {
- JComboBox<?> comboBox = (JComboBox<?>) e.getSource();
- m_iMode = comboBox.getSelectedIndex();
- try {
- // clear
- for (Object beastObject : traitSet.getOutputs()) {
- if (beastObject instanceof Tree) {
- for (Object beastObject2 : BEASTInterface.getOutputs(beastObject)) {
- if (beastObject2 instanceof TipDatesRandomWalker) {
- TipDatesRandomWalker operator = (TipDatesRandomWalker) beastObject2;
- switch (m_iMode) {
- case NO_TIP_SAMPLING:
- operator.m_pWeight.setValue(0.0, operator);
- break;
- case SAMPLE_TIPS_SAME_PRIOR:
- if (operator.getID().contains("allTipDatesRandomWalker")) {
- operator.m_pWeight.setValue(1.0, operator);
- } else {
- operator.m_pWeight.setValue(0.0, operator);
- }
- break;
- case SAMPLE_TIPS_MULTIPLE_PRIOR:
- if (operator.getID().contains("allTipDatesRandomWalker")) {
- operator.m_pWeight.setValue(0.0, operator);
- } else {
- operator.m_pWeight.setValue(0.1, operator);
- }
- break;
- }
- }
- }
- }
- }
- } catch (Exception ex) {
- // TODO: handle exception
- }
- }
private Component createListBox() {
taxa = traitSet.taxaInput.get().asStringList();
diff --git a/src/beast/app/draw/BEASTObjectInputEditor.java b/src/beast/app/draw/BEASTObjectInputEditor.java
index 4f7942f..31fbdbe 100644
--- a/src/beast/app/draw/BEASTObjectInputEditor.java
+++ b/src/beast/app/draw/BEASTObjectInputEditor.java
@@ -327,7 +327,8 @@ public class BEASTObjectInputEditor extends InputEditor.Base {
});
m_selectBEASTObjectBox.setToolTipText(input.getHTMLTipText());
- m_selectBEASTObjectBox.setMaximumSize(new Dimension(1024, 200));
+ int fontsize = m_selectBEASTObjectBox.getFont().getSize();
+ m_selectBEASTObjectBox.setMaximumSize(new Dimension(1024, 200 * fontsize / 13));
box.add(m_selectBEASTObjectBox);
}
}
diff --git a/src/beast/app/draw/DoubleListInputEditor.java b/src/beast/app/draw/DoubleListInputEditor.java
index 9fe6495..785d921 100644
--- a/src/beast/app/draw/DoubleListInputEditor.java
+++ b/src/beast/app/draw/DoubleListInputEditor.java
@@ -169,12 +169,14 @@ public class DoubleListInputEditor extends ListInputEditor {
void setUpEntry() {
m_entry = new JTextField();
m_entry.setName(m_input.getName());
+ int size = m_entry.getFont().getSize();
+ PREFERRED_SIZE = new Dimension(200, 25 * size / 13);
m_entry.setMinimumSize(PREFERRED_SIZE);
m_entry.setPreferredSize(PREFERRED_SIZE);
m_entry.setSize(PREFERRED_SIZE);
initEntry();
m_entry.setToolTipText(m_input.getHTMLTipText());
- m_entry.setMaximumSize(MAX_SIZE);
+ m_entry.setMaximumSize(new Dimension(1024, 25 * size / 13));
m_entry.getDocument().addDocumentListener(new DocumentListener() {
@Override
@@ -260,7 +262,8 @@ public class DoubleListInputEditor extends ListInputEditor {
m_inputLabel.setToolTipText(tipText);
m_inputLabel.setHorizontalTextPosition(SwingConstants.RIGHT);
//Dimension size = new Dimension(g_nLabelWidth, 20);
- Dimension size = new Dimension(200, 20);
+ int fontsize = m_inputLabel.getFont().getSize();
+ Dimension size = new Dimension(200, 20 * fontsize / 13);
m_inputLabel.setMaximumSize(size);
m_inputLabel.setMinimumSize(size);
m_inputLabel.setPreferredSize(size);
diff --git a/src/beast/app/draw/EnumInputEditor.java b/src/beast/app/draw/EnumInputEditor.java
index 73869d3..965ddf3 100644
--- a/src/beast/app/draw/EnumInputEditor.java
+++ b/src/beast/app/draw/EnumInputEditor.java
@@ -1,5 +1,6 @@
package beast.app.draw;
+import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
@@ -48,6 +49,9 @@ public class EnumInputEditor extends InputEditor.Base {
}
if (availableValues.size() > 1) {
m_selectPluginBox = new JComboBox<>(availableValues.toArray(new String[0]));
+ Dimension maxDim = m_selectPluginBox.getPreferredSize();
+ m_selectPluginBox.setMaximumSize(maxDim);
+
String selectString = input.get().toString();
m_selectPluginBox.setSelectedItem(selectString);
diff --git a/src/beast/app/draw/InputEditor.java b/src/beast/app/draw/InputEditor.java
index 7c6126a..01d0763 100644
--- a/src/beast/app/draw/InputEditor.java
+++ b/src/beast/app/draw/InputEditor.java
@@ -315,7 +315,7 @@ public abstract class Base extends JPanel implements InputEditor {
m_inputLabel.setHorizontalTextPosition(SwingConstants.RIGHT);
//Dimension size = new Dimension(g_nLabelWidth, 20);
int fontsize = m_inputLabel.getFont().getSize();
- Dimension size = new Dimension(200, 20 * fontsize / 13);
+ Dimension size = new Dimension(200 * fontsize / 13, 20 * fontsize / 13);
m_inputLabel.setMaximumSize(size);
m_inputLabel.setMinimumSize(size);
m_inputLabel.setPreferredSize(size);
diff --git a/src/beast/app/draw/IntegerListInputEditor.java b/src/beast/app/draw/IntegerListInputEditor.java
index 7eef756..599eb6c 100644
--- a/src/beast/app/draw/IntegerListInputEditor.java
+++ b/src/beast/app/draw/IntegerListInputEditor.java
@@ -278,7 +278,8 @@ public class IntegerListInputEditor extends ListInputEditor {
m_inputLabel.setToolTipText(tipText);
m_inputLabel.setHorizontalTextPosition(SwingConstants.RIGHT);
//Dimension size = new Dimension(g_nLabelWidth, 20);
- Dimension size = new Dimension(200, 20);
+ int fontsize = m_inputLabel.getFont().getSize();
+ Dimension size = new Dimension(200 * fontsize / 13, 20 * fontsize / 13);
m_inputLabel.setMaximumSize(size);
m_inputLabel.setMinimumSize(size);
m_inputLabel.setPreferredSize(size);
diff --git a/src/beast/app/tools/LogCombiner.java b/src/beast/app/tools/LogCombiner.java
index decf417..7e10945 100644
--- a/src/beast/app/tools/LogCombiner.java
+++ b/src/beast/app/tools/LogCombiner.java
@@ -325,8 +325,8 @@ public class LogCombiner extends LogAnalyser {
} else {
state += m_nSampleInterval;
}
- str = str.replaceAll("^tree STATE_[^\\s=]*", "");
- m_out.print("tree STATE_" + state + " =" + str);
+ str = str.replaceAll("^tree STATE_[^\\s]*", "");
+ m_out.print("tree STATE_" + state + str);
m_out.println();
}
}
@@ -539,8 +539,10 @@ public class LogCombiner extends LogAnalyser {
String titleString = "<html><center><p>LogCombiner<br>" +
"Version " + version.getVersionString() + ", " + version.getDateString() + "</p></center></html>";
- //ConsoleApplication consoleApp =
new ConsoleApplication(nameString, aboutString, icon, true);
+ Log.info = System.out;
+ Log.warning = System.out;
+ Log.err = System.err;
combiner.printTitle(aboutString);
diff --git a/src/beast/app/treeannotator/TreeAnnotator.java b/src/beast/app/treeannotator/TreeAnnotator.java
index b16aca7..5601b64 100644
--- a/src/beast/app/treeannotator/TreeAnnotator.java
+++ b/src/beast/app/treeannotator/TreeAnnotator.java
@@ -1291,6 +1291,8 @@ public class TreeAnnotator {
"</center></html>";
new ConsoleApplication(nameString, aboutString, icon, true);
+ Log.info = System.out;
+ Log.err = System.err;
// The ConsoleApplication will have overridden System.out so set progressStream
// to capture the output to the window:
diff --git a/src/beast/app/util/Utils.java b/src/beast/app/util/Utils.java
index c54b13f..65a85ab 100644
--- a/src/beast/app/util/Utils.java
+++ b/src/beast/app/util/Utils.java
@@ -278,7 +278,7 @@ public class Utils {
chooser.setMultiSelectionEnabled(allowMultipleSelection);
//chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
- if (description != null) {
+ if (description != null && extensions.length > 1 && extensions[0].length() > 0) {
FileNameExtensionFilter filter = new FileNameExtensionFilter(description, extensions);
chooser.setFileFilter(filter);
}
diff --git a/src/beast/core/BEASTInterface.java b/src/beast/core/BEASTInterface.java
index fe45033..0ff64e5 100644
--- a/src/beast/core/BEASTInterface.java
+++ b/src/beast/core/BEASTInterface.java
@@ -131,19 +131,44 @@ public interface BEASTInterface {
}
/**
- * @return citation from @Citation annotation *
+ * Deprecated: use getCitationList() instead to allow multiple citations, not just the first one
*/
+ @Deprecated
default public Citation getCitation() {
final Annotation[] classAnnotations = this.getClass().getAnnotations();
for (final Annotation annotation : classAnnotations) {
if (annotation instanceof Citation) {
return (Citation) annotation;
}
+ if (annotation instanceof Citation.Citations) {
+ return ((Citation.Citations) annotation).value()[0];
+ // TODO: this ignores other citations
+ }
}
return null;
}
/**
+ * @return array of @Citation annotations for this class
+ * or empty list if there are no citations
+ **/
+ default public List<Citation> getCitationList() {
+ final Annotation[] classAnnotations = this.getClass().getAnnotations();
+ List<Citation> citations = new ArrayList<>();
+ for (final Annotation annotation : classAnnotations) {
+ if (annotation instanceof Citation) {
+ citations.add((Citation) annotation);
+ }
+ if (annotation instanceof Citation.Citations) {
+ for (Citation citation : ((Citation.Citations) annotation).value()) {
+ citations.add(citation);
+ }
+ }
+ }
+ return citations;
+ }
+
+ /**
* @return references for this plug in and all its inputs *
*/
default public String getCitations() {
@@ -158,16 +183,15 @@ public interface BEASTInterface {
IDs.add(getID());
}
final StringBuilder buf = new StringBuilder();
- if (getCitation() != null) {
- // only add citation if it is not already processed
- if (!citations.contains(getCitation().value())) {
+ // only add citation if it is not already processed
+ for (Citation citation : getCitationList()) {
+ if (!citations.contains(citation.value())) {
// and there is actually a citation to add
buf.append("\n");
- buf.append(getCitation().value());
+ buf.append(citation.value());
buf.append("\n");
- citations.add(getCitation().value());
+ citations.add(citation.value());
}
- //return buf.toString();
}
try {
for (final BEASTInterface beastObject : listActiveBEASTObjects()) {
diff --git a/src/beast/core/Citation.java b/src/beast/core/Citation.java
index 45c9739..b2457bf 100644
--- a/src/beast/core/Citation.java
+++ b/src/beast/core/Citation.java
@@ -27,6 +27,7 @@ package beast.core;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -42,9 +43,10 @@ import java.lang.annotation.Target;
* like DocMaker then can pick it up through introspection.
* <p/>
*/
- at Target({ElementType.TYPE})
+//@Target({ElementType.TYPE}) //<- does not work together with @Repeatable
@Retention(RetentionPolicy.RUNTIME)
@Inherited
+ at Repeatable(Citation.Citations.class)
public @interface Citation {
/**
@@ -57,4 +59,16 @@ public @interface Citation {
int year() default 0;
String firstAuthorSurname() default "";
-}
\ No newline at end of file
+
+ /**
+ * The Citations annotation is required to retrieve classes annotated with
+ * multiple citations.
+ **/
+ @Inherited
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Citations {
+ Citation[] value();
+ }
+}
+
+
diff --git a/src/beast/core/Logger.java b/src/beast/core/Logger.java
index a00fbf8..1ba1f9b 100644
--- a/src/beast/core/Logger.java
+++ b/src/beast/core/Logger.java
@@ -266,7 +266,7 @@ public class Logger extends BEASTObject {
for (int i = 0; i < header.length(); i++) {
char c = header.charAt(i);
if (c == '.') {
- if (header.charAt(i+2) == ':') {
+ if (i < header.length() - 2 && header.charAt(i+2) == ':') {
final char c2 = header.charAt(++i);
i++;
String prefix = "";
diff --git a/src/beast/core/parameter/Parameter.java b/src/beast/core/parameter/Parameter.java
index 8f69ee1..00269f7 100644
--- a/src/beast/core/parameter/Parameter.java
+++ b/src/beast/core/parameter/Parameter.java
@@ -332,7 +332,7 @@ public interface Parameter<T> extends Function {
public void assignFromFragile(final StateNode other) {
@SuppressWarnings("unchecked")
final Parameter.Base<T> source = (Parameter.Base<T>) other;
- System.arraycopy(source.values, 0, values, 0, values.length);
+ System.arraycopy(source.values, 0, values, 0, Math.min(values.length, source.getDimension()));
Arrays.fill(m_bIsDirty, false);
}
diff --git a/src/beast/core/util/Sum.java b/src/beast/core/util/Sum.java
index 5213225..0b37a99 100644
--- a/src/beast/core/util/Sum.java
+++ b/src/beast/core/util/Sum.java
@@ -1,6 +1,8 @@
package beast.core.util;
import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
import beast.core.BEASTObject;
import beast.core.CalculationNode;
@@ -16,7 +18,7 @@ import beast.core.parameter.IntegerParameter;
@Description("calculates sum of a valuable")
public class Sum extends CalculationNode implements Function, Loggable {
- final public Input<Function> functionInput = new Input<>("arg", "argument to be summed", Validate.REQUIRED);
+ final public Input<List<Function>> functionInput = new Input<>("arg", "argument to be summed", new ArrayList<>(), Validate.REQUIRED);
enum Mode {integer_mode, double_mode}
@@ -28,11 +30,12 @@ public class Sum extends CalculationNode implements Function, Loggable {
@Override
public void initAndValidate() {
- Function valuable = functionInput.get();
- if (valuable instanceof IntegerParameter || valuable instanceof BooleanParameter) {
- mode = Mode.integer_mode;
- } else {
- mode = Mode.double_mode;
+ List<Function> valuable = functionInput.get();
+ mode = Mode.integer_mode;
+ for (Function v : valuable) {
+ if (!(v instanceof IntegerParameter || v instanceof BooleanParameter)) {
+ mode = Mode.double_mode;
+ }
}
}
@@ -54,9 +57,10 @@ public class Sum extends CalculationNode implements Function, Loggable {
*/
void compute() {
sum = 0;
- final Function v = functionInput.get();
- for (int i = 0; i < v.getDimension(); i++) {
- sum += v.getArrayValue(i);
+ for (Function v : functionInput.get()) {
+ for (int i = 0; i < v.getDimension(); i++) {
+ sum += v.getArrayValue(i);
+ }
}
needsRecompute = false;
}
@@ -95,16 +99,16 @@ public class Sum extends CalculationNode implements Function, Loggable {
*/
@Override
public void init(PrintStream out) {
- out.print("sum(" + ((BEASTObject) functionInput.get()).getID() + ")\t");
+ out.print("sum(" + ((BEASTObject) functionInput.get().get(0)).getID() + ")\t");
}
@Override
public void log(int sampleNr, PrintStream out) {
- Function valuable = functionInput.get();
- final int dimension = valuable.getDimension();
double sum = 0;
- for (int i = 0; i < dimension; i++) {
- sum += valuable.getArrayValue(i);
+ for (Function v : functionInput.get()) {
+ for (int i = 0; i < v.getDimension(); i++) {
+ sum += v.getArrayValue(i);
+ }
}
if (mode == Mode.integer_mode) {
out.print((int) sum + "\t");
diff --git a/src/beast/evolution/alignment/TaxonSet.java b/src/beast/evolution/alignment/TaxonSet.java
index 79034b2..4183cf5 100644
--- a/src/beast/evolution/alignment/TaxonSet.java
+++ b/src/beast/evolution/alignment/TaxonSet.java
@@ -50,12 +50,12 @@ public class TaxonSet extends Taxon {
taxonList = taxonsetInput.get();
if (alignmentInput.get() != null) {
if (taxonList.size() > 0) {
- throw new IllegalArgumentException("Only one of taxon and alignment should be specified, not both.");
+ throw new IllegalArgumentException("Only one of taxon and alignment should be specified, not both (id=" + getID() + ").");
}
taxaNames = alignmentInput.get().taxaNames;
} else {
if (taxonList.size() == 0) {
- throw new IllegalArgumentException("Either taxon or alignment should be specified.");
+ throw new IllegalArgumentException(getID() + ": Either taxon or alignment should be specified (id=" + getID() + ").");
}
taxaNames = new ArrayList<>();
for (final Taxon taxon : taxonList) {
diff --git a/src/beast/evolution/datatype/IntegerData.java b/src/beast/evolution/datatype/IntegerData.java
index 136d82d..77d7115 100644
--- a/src/beast/evolution/datatype/IntegerData.java
+++ b/src/beast/evolution/datatype/IntegerData.java
@@ -31,4 +31,11 @@ public class IntegerData extends Base {
return (char)('0'+state);
}
+ @Override
+ public String getCode(int state) {
+ if (state < 0) {
+ return "?";
+ }
+ return state + "";
+ }
}
diff --git a/src/beast/evolution/likelihood/ThreadedTreeLikelihood.java b/src/beast/evolution/likelihood/ThreadedTreeLikelihood.java
index f485262..f23af2a 100644
--- a/src/beast/evolution/likelihood/ThreadedTreeLikelihood.java
+++ b/src/beast/evolution/likelihood/ThreadedTreeLikelihood.java
@@ -58,12 +58,12 @@ import beast.evolution.substitutionmodel.SubstitutionModel;
"a variant of the 'peeling algorithm'. For details, see" +
"Felsenstein, Joseph (1981). Evolutionary trees from DNA sequences: a maximum likelihood approach. J Mol Evol 17 (6): 368-376.")
public class ThreadedTreeLikelihood extends GenericTreeLikelihood {
- final public Input<Boolean> useAmbiguitiesInput = new Input<>("useAmbiguities", "flag to indicate leafs that sites containing ambigue states should be handled instead of ignored (the default)", false);
+ final public Input<Boolean> useAmbiguitiesInput = new Input<>("useAmbiguities", "flag to indicate leafs that sites containing ambiguous states should be handled instead of ignored (the default)", false);
final public Input<Integer> maxNrOfThreadsInput = new Input<>("threads","maximum number of threads to use, if less than 1 the number of threads in BeastMCMC is used (default -1)", -1);
final public Input<String> proportionsInput = new Input<>("proportions", "specifies proportions of patterns used per thread as space "
- + "delimted string. This is useful when using a mixture of BEAGLE devices that run at different speeds, e.g GPU and CPU. "
+ + "delimited string. This is useful when using a mixture of BEAGLE devices that run at different speeds, e.g GPU and CPU. "
+ "The string is duplicated if there are more threads than proportions specified. For example, "
+ "'1 2' as well as '33 66' with 2 threads specifies that the first thread gets a third of the patterns and the second "
+ "two thirds. With 3 threads, it is interpreted as '1 2 1' = 25%, 50%, 25% and with 7 threads it is "
@@ -123,7 +123,7 @@ public class ThreadedTreeLikelihood extends GenericTreeLikelihood {
treelikelihood = new TreeLikelihood[threadCount];
if (dataInput.get().isAscertained) {
- Log.warning.println("Note, because the alignment is ascertained -- can only use single trhead per alignment");
+ Log.warning.println("Note, can only use single thread per alignment because the alignment is ascertained");
threadCount = 1;
}
@@ -170,7 +170,7 @@ public class ThreadedTreeLikelihood extends GenericTreeLikelihood {
"siteModel", duplicate((BEASTInterface) siteModelInput.get(), i),
"branchRateModel", duplicate(branchRateModelInput.get(), i),
"useAmbiguities", useAmbiguitiesInput.get(),
- "scaling" , scalingInput.get() + ""
+ "scaling" , scalingInput.get() + ""
);
likelihoodCallers.add(new TreeLikelihoodCaller(treelikelihood[i], i));
diff --git a/src/beast/evolution/speciation/CalibratedYuleModel.java b/src/beast/evolution/speciation/CalibratedYuleModel.java
index 7a7ae35..511c8b6 100644
--- a/src/beast/evolution/speciation/CalibratedYuleModel.java
+++ b/src/beast/evolution/speciation/CalibratedYuleModel.java
@@ -132,6 +132,7 @@ public class CalibratedYuleModel extends SpeciesTreeDistribution {
final CalibrationPoint cal = new CalibrationPoint();
cal.distInput.setValue(_MRCAPrior.distInput.get(), cal);
cal.taxonsetInput.setValue(_MRCAPrior.taxonsetInput.get(), cal);
+ cal.forParentInput.setValue(_MRCAPrior.useOriginateInput.get(), cal);
cal.initAndValidate();
cals.add(cal);
taxaSets.add(cal.taxa());
diff --git a/src/beast/evolution/tree/RandomTree.java b/src/beast/evolution/tree/RandomTree.java
index 61df99e..fdd9df1 100644
--- a/src/beast/evolution/tree/RandomTree.java
+++ b/src/beast/evolution/tree/RandomTree.java
@@ -203,7 +203,7 @@ public class RandomTree extends Tree implements StateNodeInitialiser {
for (final MRCAPrior prior : calibrations) {
final TaxonSet taxonSet = prior.taxonsetInput.get();
if (taxonSet != null && !prior.onlyUseTipsInput.get()) {
- final Set<String> usedTaxa = new HashSet<>();
+ final Set<String> usedTaxa = new LinkedHashSet<>();
if (taxonSet.asStringList() == null) {
taxonSet.initAndValidate();
}
@@ -257,7 +257,7 @@ public class RandomTree extends Tree implements StateNodeInitialiser {
for (int i = 0; i < lastMonophyletic; i++) {
for (int j = i + 1; j < lastMonophyletic; j++) {
- Set<String> intersection = new HashSet<>(taxonSets.get(i));
+ Set<String> intersection = new LinkedHashSet<>(taxonSets.get(i));
intersection.retainAll(taxonSets.get(j));
if (intersection.size() > 0) {
@@ -351,7 +351,7 @@ public class RandomTree extends Tree implements StateNodeInitialiser {
if (taxonSet == null) {
throw new IllegalArgumentException("Something is wrong with constraint " + p.getID() + " -- a taxonset must be specified if a monophyletic constraint is enforced.");
}
- final Set<String> usedTaxa = new HashSet<>();
+ final Set<String> usedTaxa = new LinkedHashSet<>();
usedTaxa.addAll(taxonSet.asStringList());
/* int c = */ traverse(root, usedTaxa, taxonSet.getTaxonCount(), new int[1]);
// boolean b = c == nrOfTaxa + 127;
@@ -418,7 +418,7 @@ public class RandomTree extends Tree implements StateNodeInitialiser {
for (int attempts = 0; attempts < 1000; ++attempts) {
try {
nextNodeNr = nrOfTaxa;
- final Set<Node> candidates = new HashSet<>();
+ final Set<Node> candidates = new LinkedHashSet<>();
int i = 0;
for (String taxon : taxa) {
final Node node = newNode();
@@ -450,8 +450,9 @@ public class RandomTree extends Tree implements StateNodeInitialiser {
+ "be nested clades.\n";
msg += "2. clade heights are constrained by an upper and lower bound, but the population size \n"
+ "is too large, so it is very unlikely a generated treed does not violate these constraints. To \n"
- + "fix this you can try to reduce the popultion size of the population model.\n";
+ + "fix this you can try to reduce the population size of the population model.\n";
msg += "Expect BEAST to crash if this is not fixed.\n";
+ Log.err.println(msg);
}
}
throw new RuntimeException(msg);
@@ -477,7 +478,7 @@ public class RandomTree extends Tree implements StateNodeInitialiser {
final Set<String> taxaDone = new TreeSet<>();
for (final int monoNode : children[isMonophyleticNode]) {
// create list of leaf nodes for this monophyletic MRCA
- final Set<Node> candidates2 = new HashSet<>();
+ final Set<Node> candidates2 = new LinkedHashSet<>();
final Set<String> isTaxonSet = taxonSets.get(monoNode);
for (String taxon : isTaxonSet) {
candidates2.add(allCandidates.get(taxon));
@@ -743,7 +744,8 @@ public class RandomTree extends Tree implements StateNodeInitialiser {
if (getMinimumInactiveHeight() < height) {
throw new RuntimeException(
- "This should never happen! Somehow the current active node is older than the next inactive node!");
+ "This should never happen! Somehow the current active node is older than the next inactive node!\n"
+ + "One possible solution you can try is to increase the population size of the population model.");
}
return height;
}
diff --git a/src/beast/evolution/tree/TraitSet.java b/src/beast/evolution/tree/TraitSet.java
index e95cc84..afa94bd 100644
--- a/src/beast/evolution/tree/TraitSet.java
+++ b/src/beast/evolution/tree/TraitSet.java
@@ -98,7 +98,8 @@ public class TraitSet extends BEASTObject {
// sanity check: did we cover all taxa?
for (int i = 0; i < labels.size(); i++) {
if (taxonValues[i] == null) {
- Log.warning.println("WARNING: no trait specified for " + labels.get(i));
+ Log.warning.println("WARNING: no trait specified for " + labels.get(i) +": Assumed to be 0");
+ map.put(labels.get(i), i);
}
}
diff --git a/src/beast/evolution/tree/Tree.java b/src/beast/evolution/tree/Tree.java
index ee00c05..7bd4715 100644
--- a/src/beast/evolution/tree/Tree.java
+++ b/src/beast/evolution/tree/Tree.java
@@ -189,6 +189,7 @@ public class Tree extends StateNode implements TreeInterface {
m_storedNodes = new Node[nodeCount];
final Node copy = root.copy();
listNodes(copy, m_storedNodes);
+ postCache = null;
}
diff --git a/src/beast/evolution/tree/TreeHeightLogger.java b/src/beast/evolution/tree/TreeHeightLogger.java
index 2c93418..a1364ec 100644
--- a/src/beast/evolution/tree/TreeHeightLogger.java
+++ b/src/beast/evolution/tree/TreeHeightLogger.java
@@ -12,10 +12,11 @@ import beast.core.Input.Validate;
import beast.core.Loggable;
- at Description("Logger to report height of a tree")
+ at Description("Logger to report height of a tree -- deprecated: use TreeStatLogger instead")
+ at Deprecated
public class TreeHeightLogger extends CalculationNode implements Loggable, Function {
final public Input<Tree> treeInput = new Input<>("tree", "tree to report height for.", Validate.REQUIRED);
-
+
@Override
public void initAndValidate() {
// nothing to do
@@ -37,7 +38,7 @@ public class TreeHeightLogger extends CalculationNode implements Loggable, Funct
out.print(tree.getRoot().getHeight() + "\t");
}
- @Override
+ @Override
public void close(PrintStream out) {
// nothing to do
}
diff --git a/src/beast/evolution/tree/TreeStatLogger.java b/src/beast/evolution/tree/TreeStatLogger.java
new file mode 100644
index 0000000..7c6cb88
--- /dev/null
+++ b/src/beast/evolution/tree/TreeStatLogger.java
@@ -0,0 +1,80 @@
+package beast.evolution.tree;
+
+
+
+import java.io.PrintStream;
+
+import beast.core.CalculationNode;
+import beast.core.Description;
+import beast.core.Function;
+import beast.core.Input;
+import beast.core.Input.Validate;
+import beast.core.util.Log;
+import beast.core.Loggable;
+
+
+ at Description("Logger to report statistics of a tree")
+public class TreeStatLogger extends CalculationNode implements Loggable, Function {
+ final public Input<Tree> treeInput = new Input<>("tree", "tree to report height for.", Validate.REQUIRED);
+ final public Input<Boolean> logHeigthInput = new Input<>("logHeigth", "If true, tree height will be logged.", true);
+ final public Input<Boolean> logLengthInput = new Input<>("logLength", "If true, tree length will be logged.", true);
+
+ @Override
+ public void initAndValidate() {
+ if (!logHeigthInput.get() && !logLengthInput.get()) {
+ Log.warning.println("TreeStatLogger " + getID() + "logs nothing. Set logHeigth=true or logLength=true to log at least something");
+ }
+ }
+
+ @Override
+ public void init(PrintStream out) {
+ final Tree tree = treeInput.get();
+ if (logHeigthInput.get()) {
+ out.print(tree.getID() + ".height\t");
+ }
+ if (logLengthInput.get()) {
+ out.print(tree.getID() + ".treeLength\t");
+ }
+ }
+
+ @Override
+ public void log(int sample, PrintStream out) {
+ final Tree tree = treeInput.get();
+ if (logHeigthInput.get()) {
+ out.print(tree.getRoot().getHeight() + "\t");
+ }
+ if (logLengthInput.get()) {
+ out.print(getLength(tree) + "\t");
+ }
+ }
+
+ private double getLength(Tree tree) {
+ double length = 0;
+ for (Node node : tree.getNodesAsArray()) {
+ if (!node.isRoot()) {
+ length += node.getLength();
+ }
+ }
+ return length;
+ }
+
+ @Override
+ public void close(PrintStream out) {
+ // nothing to do
+ }
+
+ @Override
+ public int getDimension() {
+ return 1;
+ }
+
+ @Override
+ public double getArrayValue() {
+ return treeInput.get().getRoot().getHeight();
+ }
+
+ @Override
+ public double getArrayValue(int dim) {
+ return treeInput.get().getRoot().getHeight();
+ }
+}
diff --git a/src/beast/evolution/tree/coalescent/ExponentialGrowth.java b/src/beast/evolution/tree/coalescent/ExponentialGrowth.java
index 879e782..d10d88b 100644
--- a/src/beast/evolution/tree/coalescent/ExponentialGrowth.java
+++ b/src/beast/evolution/tree/coalescent/ExponentialGrowth.java
@@ -43,7 +43,10 @@ public class ExponentialGrowth extends PopulationFunction.Abstract {
final public Input<RealParameter> popSizeParameterInput = new Input<>("popSize",
"present-day population size (defaults to 1.0). ");
final public Input<RealParameter> growthRateParameterInput = new Input<>("growthRate",
- "growth rate is the exponent of the exponential growth");
+ "Growth rate is the exponent of the exponential growth. " +
+ "A value of zero represents a constant population size, negative values represent " +
+ "decline towards the present, positive numbers represents exponential growth towards " +
+ "the present.");
//
// Public stuff
diff --git a/src/beast/evolution/tree/coalescent/TreeIntervals.java b/src/beast/evolution/tree/coalescent/TreeIntervals.java
index c79c9c8..9aa7ae4 100644
--- a/src/beast/evolution/tree/coalescent/TreeIntervals.java
+++ b/src/beast/evolution/tree/coalescent/TreeIntervals.java
@@ -324,12 +324,12 @@ public class TreeIntervals extends CalculationNode implements IntervalList {
final int nodeCount = tree.getNodeCount();
- double[] times = new double[nodeCount];
+ times = new double[nodeCount];
int[] childCounts = new int[nodeCount];
collectTimes(tree, times, childCounts);
- int[] indices = new int[nodeCount];
+ indices = new int[nodeCount];
HeapSort.sort(times, indices);
@@ -430,6 +430,19 @@ public class TreeIntervals extends CalculationNode implements IntervalList {
intervalsKnown = true;
}
+ /**
+ * Returns the time of the start of an interval
+ *
+ * @param i which interval
+ * @return start time
+ */
+ public double getIntervalTime(int i) {
+ if (!intervalsKnown) {
+ calculateIntervals();
+ }
+ return times[indices[i]];
+ }
+
protected void addLineage(int interval, Node node) {
if (lineagesAdded[interval] == null) lineagesAdded[interval] = new ArrayList<>();
lineagesAdded[interval].add(node);
@@ -475,6 +488,10 @@ public class TreeIntervals extends CalculationNode implements IntervalList {
protected double[] intervals;
protected double[] storedIntervals;
+ /** interval times **/
+ double[] times;
+ int[] indices;
+
/**
* The number of uncoalesced lineages within a particular interval.
*/
diff --git a/src/beast/math/distributions/Gamma.java b/src/beast/math/distributions/Gamma.java
index 8e06ffc..43ea49f 100644
--- a/src/beast/math/distributions/Gamma.java
+++ b/src/beast/math/distributions/Gamma.java
@@ -13,12 +13,25 @@ import beast.core.parameter.RealParameter;
"separate independent component.")
public class Gamma extends ParametricDistribution {
final public Input<RealParameter> alphaInput = new Input<>("alpha", "shape parameter, defaults to 2");
- final public Input<RealParameter> betaInput = new Input<>("beta", "scale parameter, defaults to 2");
+ final public Input<RealParameter> betaInput = new Input<>("beta", "second parameter depends on mode, defaults to 2."
+ + "For mode=ShapeScale beta is interpreted as scale. "
+ + "For mode=ShapeRate beta is interpreted as rate. "
+ + "For mode=ShapeMean beta is interpreted as mean."
+ + "For mode=OneParameter beta is ignored.");
+ public enum mode {ShapeScale, ShapeRate, ShapeMean, OneParameter};
+ final public Input<mode> modeInput = new Input<>("mode", "determines parameterisation. "
+ + "For ShapeScale beta is interpreted as scale. "
+ + "For ShapeRate beta is interpreted as rate. "
+ + "For ShapeMean beta is interpreted as mean."
+ + "For OneParameter beta is ignored.", mode.ShapeScale, mode.values());
static org.apache.commons.math.distribution.GammaDistribution m_dist = new GammaDistributionImpl(1, 1);
+ mode parameterisation = mode.ShapeScale;
+
@Override
public void initAndValidate() {
+ parameterisation = modeInput.get();
refresh();
}
@@ -28,16 +41,32 @@ public class Gamma extends ParametricDistribution {
@SuppressWarnings("deprecation")
void refresh() {
double alpha;
- double beta;
+ double beta = 2.0;
if (alphaInput.get() == null) {
alpha = 2;
} else {
alpha = alphaInput.get().getValue();
}
- if (betaInput.get() == null) {
- beta = 2;
- } else {
- beta = betaInput.get().getValue();
+
+ switch (parameterisation) {
+ case ShapeScale:
+ if (betaInput.get() != null) {
+ beta = betaInput.get().getValue();
+ }
+ break;
+ case ShapeRate:
+ if (betaInput.get() != null) {
+ beta = 1.0/betaInput.get().getValue();
+ }
+ break;
+ case ShapeMean:
+ if (betaInput.get() != null) {
+ beta = betaInput.get().getValue() / alpha;
+ }
+ break;
+ case OneParameter:
+ beta = 1.0 / alpha;
+ break;
}
m_dist.setAlpha(alpha);
m_dist.setBeta(beta);
@@ -51,6 +80,7 @@ public class Gamma extends ParametricDistribution {
@Override
public double getMean() {
+ refresh();
return offsetInput.get() + m_dist.getAlpha() * m_dist.getBeta();
}
} // class Gamma
diff --git a/src/beast/math/distributions/MRCAPrior.java b/src/beast/math/distributions/MRCAPrior.java
index 238c584..b564981 100644
--- a/src/beast/math/distributions/MRCAPrior.java
+++ b/src/beast/math/distributions/MRCAPrior.java
@@ -366,7 +366,7 @@ public class MRCAPrior extends Distribution {
if (dist != null) {
out.print("logP(mrca(" + taxonsetInput.get().getID() + "))\t");
}
- out.print("mrcatime(" + taxonsetInput.get().getID() + ")\t");
+ out.print("mrcatime(" + taxonsetInput.get().getID() + (useOriginate ? ".originate" : "") +")\t");
}
}
diff --git a/src/beast/util/AddOnManager.java b/src/beast/util/AddOnManager.java
index 37e5ac8..05f55a9 100644
--- a/src/beast/util/AddOnManager.java
+++ b/src/beast/util/AddOnManager.java
@@ -62,6 +62,7 @@ import beast.app.BEASTVersion2;
import beast.app.beastapp.BeastMain;
import beast.app.util.Arguments;
import beast.app.util.Utils;
+import beast.core.BEASTInterface;
import beast.core.Description;
import beast.core.util.Log;
import beast.evolution.alignment.Alignment;
@@ -218,7 +219,15 @@ public class AddOnManager {
packageMap.put(packageName, pkg);
}
+ if (addon.hasAttribute("projectURL"))
+ pkg.setProjectURL(new URL(addon.getAttribute("projectURL")));
+
PackageVersion installedVersion = new PackageVersion(packageVersionString);
+
+ if (addon.hasAttribute("projectURL") &&
+ !(pkg.getLatestVersion() != null && installedVersion.compareTo(pkg.getLatestVersion())<0))
+ pkg.setProjectURL(new URL(addon.getAttribute("projectURL")));
+
Set<PackageDependency> installedVersionDependencies =
new TreeSet<>((o1, o2) -> o1.dependencyName.compareTo(o2.dependencyName));
@@ -307,8 +316,12 @@ public class AddOnManager {
pkg.setDescription(element.getAttribute("description"));
PackageVersion packageVersion = new PackageVersion(element.getAttribute("version"));
- Set<PackageDependency> packageDependencies = new HashSet<>();
+ if (element.hasAttribute("projectURL") &&
+ !(pkg.getLatestVersion() != null && packageVersion.compareTo(pkg.getLatestVersion())<0))
+ pkg.setProjectURL(new URL(element.getAttribute("projectURL")));
+
+ Set<PackageDependency> packageDependencies = new HashSet<>();
NodeList depNodes = element.getElementsByTagName("depends");
for (int j = 0; j < depNodes.getLength(); j++) {
Element dependson = (Element) depNodes.item(j);
@@ -818,13 +831,14 @@ public class AddOnManager {
return dirs;
} // getBeastDirectories
- /**
+
+
+ /**
* load external jars in beast directories *
*/
public static void loadExternalJars() throws IOException {
processDeleteList();
- TreeMap<String, Package> packages = new TreeMap<>();
addInstalledPackages(packages);
processInstallList(packages);
@@ -833,13 +847,15 @@ public class AddOnManager {
for (String jarDirName : getBeastDirectories()) {
File versionFile = new File(jarDirName + "/version.xml");
+ String packageNameAndVersion = null;
if (versionFile.exists()) {
try {
// print name and version of package
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document doc = factory.newDocumentBuilder().parse(versionFile);
Element addon = doc.getDocumentElement();
- Log.warning.println("Loading package " + addon.getAttribute("name") + " v" + addon.getAttribute("version"));
+ packageNameAndVersion = addon.getAttribute("name") + " v" + addon.getAttribute("version");
+ Log.warning.println("Loading package " + packageNameAndVersion);
} catch (Exception e) {
// too bad, won't print out any info
}
@@ -873,6 +889,9 @@ public class AddOnManager {
} catch (Exception e) {
// TODO: handle exception
}
+ if (loadedClass == null && packageNameAndVersion != null) {
+ classToPackageMap.put(className, packageNameAndVersion);
+ }
}
}
jarFile.close();
@@ -1376,7 +1395,7 @@ public class AddOnManager {
// Define headers here - need to know lengths
String nameHeader = "Name";
- String statusHeader = "Installation Status";
+ String statusHeader = "Installed Version";
String latestHeader = "Latest Version";
String depsHeader = "Dependencies";
String descriptionHeader = "Description";
@@ -1395,7 +1414,7 @@ public class AddOnManager {
packageList.add(pkg);
maxNameWidth = Math.max(pkg.getName().length(), maxNameWidth);
- maxStatusWidth = Math.max(pkg.getStatusString().length(), maxStatusWidth);
+ maxStatusWidth = Math.max(pkg.isInstalled() ? pkg.getInstalledVersion().toString().length() : 2, maxStatusWidth);
maxLatestWidth = Math.max(maxLatestWidth, pkg.isAvailable()
? pkg.getLatestVersion().toString().length()
: Math.max(2, maxStatusWidth));
@@ -1429,7 +1448,7 @@ public class AddOnManager {
for (Package pkg : packageList) {
if (pkg.getName().equals(BEAST_PACKAGE_NAME)) {
ps.printf(nameFormat, pkg.getName()); ps.print(sep);
- ps.printf(statusFormat, pkg.getStatusString()); ps.print(sep);
+ ps.printf(statusFormat, pkg.isInstalled() ? pkg.getInstalledVersion() : "NA"); ps.print(sep);
ps.printf(latestFormat, pkg.isAvailable() ? pkg.getLatestVersion() : "NA"); ps.print(sep);
ps.printf(depsFormat, pkg.getDependenciesString()); ps.print(sep);
ps.printf("%s\n", pkg.getDescription());
@@ -1443,7 +1462,7 @@ public class AddOnManager {
for (Package pkg : packageList) {
if (!pkg.getName().equals(BEAST_PACKAGE_NAME)) {
ps.printf(nameFormat, pkg.getName()); ps.print(sep);
- ps.printf(statusFormat, pkg.getStatusString()); ps.print(sep);
+ ps.printf(statusFormat, pkg.isInstalled() ? pkg.getInstalledVersion() : "NA"); ps.print(sep);
ps.printf(latestFormat, pkg.isAvailable() ? pkg.getLatestVersion() : "NA"); ps.print(sep);
ps.printf(depsFormat, pkg.getDependenciesString()); ps.print(sep);
ps.printf("%s\n", pkg.getDescription());
@@ -1578,4 +1597,58 @@ public class AddOnManager {
e.printStackTrace();
}
}
+
+ /** keep track of which class comes from a particular package.
+ * It maps a full class name onto a package name + " v" + package version
+ * e.g. "bModelTest v0.3.2"
+ */
+ private static Map<String, String> classToPackageMap = new HashMap<>();
+
+ /** maps package name to a Package object, which contains info on whether
+ * and which version is installed. This is initialised when loadExternalJars()
+ * is called, which happens at the start of BEAST, BEAUti and many utilities.
+ */
+ private static TreeMap<String, Package> packages = new TreeMap<>();
+
+ /** return set of Strings in the format of classToPackageMap (like "bModelTest v0.3.2")
+ * for all packages used by o and its predecessors in the model graph.
+ */
+ public static Set<String> getPackagesAndVersions(BEASTInterface o) {
+ Set<String> packagesAndVersions = new LinkedHashSet<>();
+ getPackagesAndVersions(o, packagesAndVersions);
+ return packagesAndVersions;
+ }
+
+ /** traverse model graph starting at o, and collect packageAndVersion strings
+ * along the way.
+ */
+ private static void getPackagesAndVersions(BEASTInterface o, Set<String> packagesAndVersions) {
+ String packageAndVersion = classToPackageMap.get(o.getClass().getName());
+ if (packageAndVersion != null) {
+ packagesAndVersions.add(packageAndVersion);
+ }
+ for (BEASTInterface o2 : o.listActiveBEASTObjects()) {
+ getPackagesAndVersions(o2, packagesAndVersions);
+ }
+ }
+
+ /** test whether a package with given name and version is available.
+ * @param pkgname
+ * @param pkgversion ignored for now
+ * @return
+ */
+ // RRB: may need to return PackageStatus instead of boolean, but not sure yet how to handle
+ // the case where a newer package is installed, and the old one is not available yet.
+ //public static enum PackageStatus {NOT_INSTALLED, INSTALLED, INSTALLED_VERSION_NOT_AVAILABLE};
+ public static boolean isInstalled(String pkgname, String pkgversion) {
+ if (!packages.containsKey(pkgname)) {
+ return false;
+ }
+ return true;
+// Package pkg = packages.get(pkgname);
+// PackageVersion version = new PackageVersion(pkgversion);
+// if (pkg.isAvailable(version)) {
+// return false;
+// }
+ }
}
diff --git a/src/beast/util/Package.java b/src/beast/util/Package.java
index 3c95e0c..ff737ce 100644
--- a/src/beast/util/Package.java
+++ b/src/beast/util/Package.java
@@ -22,6 +22,8 @@ public class Package {
protected TreeMap<PackageVersion, URL> availableVersionURLs;
protected TreeMap<PackageVersion, Set<PackageDependency>> availableVersionDeps;
+ protected URL projectURL;
+
public Package(String name) {
this.packageName = name;
this.description = "";
@@ -42,6 +44,14 @@ public class Package {
this.description = description;
}
+ public URL getProjectURL() {
+ return projectURL;
+ }
+
+ public void setProjectURL(URL url) {
+ this.projectURL = url;
+ }
+
/**
* @return true iff package is available online.
*/
@@ -87,10 +97,6 @@ public class Package {
return installedVersionDeps;
}
- public String getStatusString() {
- return isInstalled() ? installedVersion.getVersionString() : NOT_INSTALLED;
- }
-
/**
* @return latest available version of package.
*/
@@ -193,7 +199,7 @@ public class Package {
public String toHTML() {
String html = "<html>";
html += "<h1>" + packageName + "</h1>";
- html += "<p>Installed version: " + getStatusString() + "</p>";
+ html += "<p>Installed version: " + (isInstalled() ? getInstalledVersion() : "NA") + "</p>";
html += "<p>Latest version: " + (isAvailable() ? getLatestVersion() : "NA") + "</p>";
html += "<p>" + description +"</p>";
html += "</html>";
diff --git a/src/beast/util/TreeParser.java b/src/beast/util/TreeParser.java
index daa7cea..b46423e 100644
--- a/src/beast/util/TreeParser.java
+++ b/src/beast/util/TreeParser.java
@@ -467,8 +467,19 @@ public class TreeParser extends Tree implements StateNodeInitialiser {
stringValue = stringValue.substring(1, stringValue.length()-1);
}
node.setMetaData(key, stringValue);
- } else {
- // BEAST doesn't do anything with vectors yet.
+ } else if (attribctx.attribValue().vector() != null) {
+ try {
+ String value = attribctx.attribValue().vector().getText();
+ String str = value.substring(1, value.length() - 1);
+ String [] strs = str.split(",");
+ Double [] values = new Double[strs.length];
+ for (int j = 0; j < strs.length; j++) {
+ values[j] = Double.parseDouble(strs[j]);
+ }
+ node.setMetaData(key, values);
+ } catch (Exception e) {
+ // ignore parsing errors
+ }
}
}
}
diff --git a/src/beast/util/XMLParser.java b/src/beast/util/XMLParser.java
index 46acc9d..7b59b31 100644
--- a/src/beast/util/XMLParser.java
+++ b/src/beast/util/XMLParser.java
@@ -196,6 +196,7 @@ public class XMLParser {
HashMap<String, BEASTInterface> IDMap;
HashMap<String, Integer[]> likelihoodMap;
HashMap<String, Node> IDNodeMap;
+ String unavailablePacakges = "";
static HashMap<String, String> element2ClassMap;
@@ -332,7 +333,7 @@ public class XMLParser {
// if (typeName == null || !typeName.equals("template")) {
// return beastObjects;
// }
-
+ // sanity check that required packages are installed
initIDNodeMap(topNode);
parseNameSpaceAndMap(topNode);
@@ -485,6 +486,31 @@ public class XMLParser {
throw new XMLParserException(topNode, "Wrong version: only versions > 2.0 are supported", 101);
}
+ String required = getAttribute(topNode, "required");
+ if (required != null && required.trim().length() > 0) {
+ String [] packageAndVersions = required.split(":");
+ for (String s : packageAndVersions) {
+ s = s.trim();
+ int i = s.lastIndexOf(" ");
+ if (i > 0) {
+ String pkgname = s.substring(0, i);
+ String pkgversion = s.substring(i+1);
+ if (!AddOnManager.isInstalled(pkgname, pkgversion)) {
+ unavailablePacakges += s +", ";
+ }
+ }
+ }
+ if (unavailablePacakges.length() > 1) {
+ unavailablePacakges = unavailablePacakges.substring(0, unavailablePacakges.length() - 2);
+ if (unavailablePacakges.contains(",")) {
+ Log.warning("The following packages are required, but not available: " + unavailablePacakges);
+ } else {
+ Log.warning("The following package is required, but is not available: " + unavailablePacakges);
+ }
+ Log.warning("See http://beast2.org/managing-packages/ for details on how to install packages.");
+ }
+ }
+
initIDNodeMap(topNode);
parseNameSpaceAndMap(topNode);
@@ -713,6 +739,15 @@ public class XMLParser {
}
}
if (clazzName == null) {
+ if (unavailablePacakges.length() > 2) {
+ String msg = "Class " + specClass + " could not be found.\n" +
+ (unavailablePacakges.contains(",") ?
+ "This XML requires the following packages that are not installed: " :
+ "This XML requires the following package that is not installed: ") + unavailablePacakges + "\n" +
+ "See http://beast2.org/managing-packages/ for details on how to install packages.\n" +
+ "Or perhaps there is a typo in spec and you meant " + XMLParserUtils.guessClass(specClass) + "?";
+ throw new XMLParserException(node, msg, 1018);
+ }
throw new XMLParserException(node, "Class could not be found. Did you mean " + XMLParserUtils.guessClass(specClass) + "?", 1017);
// throw new ClassNotFoundException(specClass);
}
diff --git a/src/beast/util/XMLParserUtils.java b/src/beast/util/XMLParserUtils.java
index 6bd272a..de334d4 100644
--- a/src/beast/util/XMLParserUtils.java
+++ b/src/beast/util/XMLParserUtils.java
@@ -28,6 +28,7 @@ import beast.core.BEASTInterface;
import beast.core.Input;
import beast.core.InputForAnnotatedConstructor;
import beast.core.Param;
+import beast.core.util.Log;
/**
*
@@ -73,12 +74,18 @@ public class XMLParserUtils {
List<String> vals = new ArrayList<>();
for (final String valueString : valuesString) {
if (valueString.indexOf(":") > 0) {
- String[] range = valueString.split(":");
- int min = Integer.parseInt(range[0]);
- int max = Integer.parseInt(range[1]);
- for (int i = min; i <= max; i++) {
- vals.add(String.valueOf(i));
- }
+ try {
+ String[] range = valueString.split(":");
+ int min = Integer.parseInt(range[0]);
+ int max = Integer.parseInt(range[1]);
+ for (int i = min; i <= max; i++) {
+ vals.add(String.valueOf(i));
+ }
+ } catch (NumberFormatException e) {
+ Log.warning.println("plate range value '" + valueString + "'contains a ':' but does not seem to be a range, (like 1:5).");
+ Log.warning.println("interpreting it as if it were not a range");
+ vals.add(valueString);
+ }
} else {
vals.add(valueString);
}
diff --git a/src/beast/util/XMLProducer.java b/src/beast/util/XMLProducer.java
index 6af6b7d..0d455f8 100644
--- a/src/beast/util/XMLProducer.java
+++ b/src/beast/util/XMLProducer.java
@@ -56,6 +56,7 @@ import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import beast.app.BEASTVersion2;
import beast.core.BEASTInterface;
import beast.core.Input;
@@ -98,7 +99,14 @@ public class XMLProducer extends XMLParser {
public String toXML(BEASTInterface beastObject, Collection<BEASTInterface> others) {
try {
StringBuffer buf = new StringBuffer();
- buf.append("<" + XMLParser.BEAST_ELEMENT + " version='2.0' namespace='" + DEFAULT_NAMESPACE + "'>\n");
+ Set<String> requiredPacakges = AddOnManager.getPackagesAndVersions(beastObject);
+ String required = requiredPacakges.toString();
+ required = required.substring(1, required.length() - 1);
+ required = required.replaceAll(", ", ":");
+ buf.append("<" + XMLParser.BEAST_ELEMENT +
+ " version='" + new BEASTVersion2().getMajorVersion() + "'" +
+ " required='" + required + "'" +
+ " namespace='" + DEFAULT_NAMESPACE + "'>\n");
for (String element : element2ClassMap.keySet()) {
if (!reservedElements.contains(element)) {
buf.append("<map name='" + element + "'>" + element2ClassMap.get(element) +"</map>\n");
@@ -826,8 +834,24 @@ public class XMLProducer extends XMLParser {
// open element
buf.append("<").append(elementName);
+
+ if (beastObject.getID() == null) {
+ String id = beastObject.getClass().getName();
+ if (id.contains(".")) {
+ id = id.substring(id.lastIndexOf('.') + 1);
+ }
+ if (IDs.contains(id)) {
+ int k = 1;
+ while (IDs.contains(id + k)) {
+ k++;
+ }
+ id = id + k;
+ }
+ beastObject.setID(id);
+ }
boolean skipInputs = false;
+ // isDone.contains(beastObject) fails when BEASTObjects override equals(), so use a stream with == instead
if (isDone.stream().anyMatch(x -> x == beastObject)) {
// XML is already produced, we can idref it
buf.append(" idref='" + normalise(beastObject.getID()) + "'");
diff --git a/src/test/beast/app/beauti/BeautiRateTutorialTest.java b/src/test/beast/app/beauti/BeautiRateTutorialTest.java
index e2d8d5d..5774e6a 100644
--- a/src/test/beast/app/beauti/BeautiRateTutorialTest.java
+++ b/src/test/beast/app/beauti/BeautiRateTutorialTest.java
@@ -236,8 +236,9 @@ public class BeautiRateTutorialTest extends BeautiBase {
warning("7. Run MCMC and look at results in Tracer, TreeAnnotator->FigTree");
makeSureXMLParses();
- MEPRunner runner = new MEPRunner(org.fest.util.Files.temporaryFolder());
- runner.analyse(0);
+ // TODO: this should run as a separate process since the BEAUti run can interfere with the BEAST run on Hudson
+ //MEPRunner runner = new MEPRunner(org.fest.util.Files.temporaryFolder());
+ //runner.analyse(0);
long t1 = System.currentTimeMillis();
System.err.println("total time: " + (t1 - t0)/1000 + " seconds");
diff --git a/src/test/beast/core/BEASTInterfaceTest.java b/src/test/beast/core/BEASTInterfaceTest.java
index 1b5e5c5..5f667e3 100644
--- a/src/test/beast/core/BEASTInterfaceTest.java
+++ b/src/test/beast/core/BEASTInterfaceTest.java
@@ -58,6 +58,12 @@ public class BEASTInterfaceTest extends TestCase {
}
}
+ @Description("class that extends BEASTi with multiple citations")
+ @Citation("this is another dummy citation")
+ @Citation("and yet another dummy citation")
+ public class BEASTi2 extends BEASTi {
+
+ }
@Test
public void testBEASTi() throws Exception {
@@ -67,6 +73,14 @@ public class BEASTInterfaceTest extends TestCase {
Citation citation = beasti.getCitation();
assertEquals("this is a dummy citation", citation.value());
+ citation = beasti.getCitationList().get(0);
+ assertEquals("this is a dummy citation", citation.value());
+
+ BEASTi beasti02 = new BEASTi2();
+ List<Citation> citations = beasti02.getCitationList();
+ assertEquals(3, citations.size());
+
+
System.err.println("test initByName");
beasti.initByName("value", "hello world");
Input<?> input = beasti.getInput("value");
@@ -127,6 +141,8 @@ public class BEASTInterfaceTest extends TestCase {
beasti2.setInputValue("value", "Goodbye!");
String msg = (String) beasti2.getInputValue("value");
assertEquals("Goodbye!", msg);
+
+
}
diff --git a/src/test/beast/core/util/SumTest.java b/src/test/beast/core/util/SumTest.java
new file mode 100644
index 0000000..f566136
--- /dev/null
+++ b/src/test/beast/core/util/SumTest.java
@@ -0,0 +1,63 @@
+package test.beast.core.util;
+
+import org.junit.Test;
+
+import beast.core.parameter.BooleanParameter;
+import beast.core.parameter.IntegerParameter;
+import beast.core.parameter.RealParameter;
+import beast.core.util.Sum;
+import junit.framework.TestCase;
+
+public class SumTest extends TestCase {
+
+
+ @Test
+ public void testSum() {
+ RealParameter p1 = new RealParameter("1.0 2.0");
+ Sum sum = new Sum();
+
+ // single argument sum
+ sum.initByName("arg", p1);
+ double v = sum.getArrayValue();
+ assertEquals(3.0, v, 1e-10);
+
+ // multiple argument sum
+ sum = new Sum();
+ RealParameter p2 = new RealParameter("2.0 2.5");
+ sum.initByName("arg", p1, "arg", p2);
+ v = sum.getArrayValue();
+ assertEquals(7.5, v, 1e-10);
+
+ // multiple same argument sum
+ sum = new Sum();
+ sum.initByName("arg", p1, "arg", p1);
+ v = sum.getArrayValue();
+ assertEquals(6.0, v, 1e-10);
+
+ // sum of integers
+ IntegerParameter p3 = new IntegerParameter("1 2 5");
+ sum = new Sum();
+ sum.initByName("arg", p3);
+ v = sum.getArrayValue();
+ assertEquals(8.0, v, 1e-10);
+
+ // sum of boolean
+ BooleanParameter p4 = new BooleanParameter("true false false true true");
+ sum = new Sum();
+ sum.initByName("arg", p4);
+ v = sum.getArrayValue();
+ assertEquals(3.0, v, 1e-10);
+
+ // sum of booleans and integer
+ sum = new Sum();
+ sum.initByName("arg", p4, "arg", p3);
+ v = sum.getArrayValue();
+ assertEquals(11.0, v, 1e-10);
+
+ // sum of booleans and real
+ sum = new Sum();
+ sum.initByName("arg", p1, "arg", p4);
+ v = sum.getArrayValue();
+ assertEquals(6.0, v, 1e-10);
+ }
+}
diff --git a/src/test/beast/evolution/datatype/IntegerDataTest.java b/src/test/beast/evolution/datatype/IntegerDataTest.java
new file mode 100644
index 0000000..c595704
--- /dev/null
+++ b/src/test/beast/evolution/datatype/IntegerDataTest.java
@@ -0,0 +1,32 @@
+package test.beast.evolution.datatype;
+
+import org.junit.Test;
+
+import beast.evolution.datatype.IntegerData;
+import beast.util.Randomizer;
+import junit.framework.TestCase;;
+
+public class IntegerDataTest extends TestCase {
+
+
+ @Test
+ public void testIntegerData() {
+ IntegerData datatype = new IntegerData();
+ assertEquals("?", datatype.getCode(-1));
+ assertEquals("0", datatype.getCode(0));
+ assertEquals("1", datatype.getCode(1));
+ assertEquals("10", datatype.getCode(10));
+ assertEquals("123", datatype.getCode(123));
+ Randomizer.setSeed(127);
+ for (int i = 0; i < 100; i++) {
+ int state = Randomizer.nextInt(100000000);
+ int x = state;
+ String str = "";
+ while (state > 0) {
+ str = (char)('0' + state%10) + str;
+ state /= 10;
+ }
+ assertEquals(str, datatype.getCode(x));
+ }
+ }
+}
diff --git a/src/test/beast/evolution/tree/TraitSetTest.java b/src/test/beast/evolution/tree/TraitSetTest.java
new file mode 100644
index 0000000..055fba0
--- /dev/null
+++ b/src/test/beast/evolution/tree/TraitSetTest.java
@@ -0,0 +1,78 @@
+/**
+ *
+ */
+package test.beast.evolution.tree;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import beast.evolution.alignment.Alignment;
+import beast.evolution.alignment.Sequence;
+import beast.evolution.alignment.TaxonSet;
+import beast.evolution.tree.TraitSet;
+
+/**
+ * @author Gereon Kaiping <g.a.kaiping at hum.leidenuniv.nl>
+ *
+ */
+public class TraitSetTest {
+
+ public TaxonSet taxonSet(int Nleaves) {
+ List<Sequence> seqList = new ArrayList<Sequence>();
+
+ for (int i=0; i<Nleaves; i++) {
+ String taxonID = "t" + i;
+ seqList.add(new Sequence(taxonID, "?"));
+ }
+
+ Alignment alignment = new Alignment(seqList, "nucleotide");
+ TaxonSet taxonSet = new TaxonSet(alignment);
+ return taxonSet;}
+
+
+ @Test
+ public void testDateBackward() {
+ int Nleaves = 2;
+ TraitSet timeTrait = new TraitSet();
+
+ timeTrait.initByName(
+ "traitname", "date-backward",
+ "taxa", taxonSet(Nleaves),
+ "value", "t0=0, t1=10");
+ // The trait actually represents the age of the taxa relative to
+ // each other with arbitrary zero, so we test it like this.
+ assertEquals(-10.0, timeTrait.getValue("t0")-timeTrait.getValue("t1"), 1e-7);
+ }
+
+ @Test
+ public void testDateForward() {
+ int Nleaves = 2;
+ TraitSet timeTrait = new TraitSet();
+
+ timeTrait.initByName(
+ "traitname", "date-forward",
+ "taxa", taxonSet(Nleaves),
+ "value", "t0=0, t1=10");
+ // The trait actually represents the age of the taxa relative to
+ // each other with arbitrary zero, so we test it like this.
+ assertEquals(10.0, timeTrait.getValue("t0")-timeTrait.getValue("t1"), 1e-7);
+ }
+
+ @Test
+ public void testDateForwardUnspecified() {
+ int Nleaves = 2;
+ TraitSet timeTrait = new TraitSet();
+
+ timeTrait.initByName(
+ "traitname", "date-forward",
+ "taxa", taxonSet(Nleaves),
+ "value", "t1=10");
+ // The trait actually represents the age of the taxa relative to
+ // each other with arbitrary zero, so we test it like this.
+ assertEquals(10.0, timeTrait.getValue("t0")-timeTrait.getValue("t1"), 1e-7);
+ }
+}
diff --git a/src/test/beast/math/distributions/GammaTest.java b/src/test/beast/math/distributions/GammaTest.java
index 6dd7531..2164519 100644
--- a/src/test/beast/math/distributions/GammaTest.java
+++ b/src/test/beast/math/distributions/GammaTest.java
@@ -1,8 +1,16 @@
package test.beast.math.distributions;
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.analysis.integration.RombergIntegrator;
+import org.apache.commons.math.analysis.integration.UnivariateRealIntegrator;
import org.junit.Test;
+import beast.math.GammaFunction;
import beast.math.distributions.Gamma;
+import beast.util.Randomizer;
import junit.framework.TestCase;
public class GammaTest extends TestCase {
@@ -25,4 +33,97 @@ public class GammaTest extends TestCase {
}
+ /** The code below is adapted from GammaDistributionTest from BEAST 1
+ * This test stochastically draws gamma
+ * variates and compares the coded pdf
+ * with the actual pdf.
+ * The tolerance is required to be at most 1e-10.
+ */
+
+ static double mypdf(double value, double shape, double scale) {
+ return Math.exp((shape-1) * Math.log(value) - value/scale - GammaFunction.lnGamma(shape) - shape * Math.log(scale) );
+ }
+
+ public void testPdf() throws MathException {
+
+ final int numberOfTests = 300;
+ double totErr = 0;
+ double ptotErr = 0; int np = 0;
+ double qtotErr = 0;
+
+ Randomizer.setSeed(551);
+
+ for(int i = 0; i < numberOfTests; i++){
+ final double mean = .01 + (3-0.01) * Randomizer.nextDouble();
+ final double var = .01 + (3-0.01) * Randomizer.nextDouble();
+
+ double scale0 = var / mean;
+ double shape = mean / scale0;
+
+ final Gamma gamma = new Gamma();
+ Gamma.mode mode = Gamma.mode.values()[Randomizer.nextInt(4)];
+
+ double other = 0;
+ switch (mode) {
+ case ShapeScale: other = scale0; break;
+ case ShapeRate: other = 1/scale0; break;
+ case ShapeMean: other = scale0 * shape; break;
+ case OneParameter: other = 1/shape; scale0 = 1/shape; break;
+ }
+ final double scale = scale0;
+
+ gamma.initByName("alpha", shape +"", "beta", other +"", "mode", mode);
+
+ final double value = Randomizer.nextGamma(shape, 1/scale);
+
+ final double mypdf = mypdf(value, shape, scale);
+ final double pdf = gamma.density(value);
+ if ( Double.isInfinite(mypdf) && Double.isInfinite(pdf)) {
+ continue;
+ }
+
+ assertFalse(Double.isNaN(mypdf));
+ assertFalse(Double.isNaN(pdf));
+
+ totErr += mypdf != 0 ? Math.abs((pdf - mypdf)/mypdf) : pdf;
+
+ assertFalse("nan", Double.isNaN(totErr));
+ //assertEquals("" + shape + "," + scale + "," + value, mypdf,gamma.pdf(value),1e-10);
+
+ final double cdf = gamma.cumulativeProbability(value);
+ UnivariateRealFunction f = new UnivariateRealFunction() {
+ public double value(double v) throws FunctionEvaluationException {
+ return mypdf(v, shape, scale);
+ }
+ };
+ final UnivariateRealIntegrator integrator = new RombergIntegrator();
+ integrator.setAbsoluteAccuracy(1e-14);
+ integrator.setMaximalIterationCount(16); // fail if it takes too much time
+
+ double x;
+ try {
+ x = integrator.integrate(f, 0, value);
+ ptotErr += cdf != 0.0 ? Math.abs(x-cdf)/cdf : x;
+ np += 1;
+ //assertTrue("" + shape + "," + scale + "," + value + " " + Math.abs(x-cdf)/x + "> 1e-6", Math.abs(1-cdf/x) < 1e-6);
+
+ final double q = gamma.inverseCumulativeProbability(cdf);
+ qtotErr += q != 0 ? Math.abs(q-value)/q : value;
+ //System.out.println(shape + "," + scale + " " + value);
+ } catch( ConvergenceException e ) {
+ // can't integrate , skip test
+ //System.out.print(" theta(" + shape + "," + scale + ") skipped");
+ }
+
+ // assertEquals("" + shape + "," + scale + "," + value + " " + Math.abs(q-value)/value, q, value, 1e-6);
+ // System.out.print("\n" + np + ": " + mode + " " + totErr/np + " " + qtotErr/np + " " + ptotErr/np);
+ }
+ //System.out.println( !Double.isNaN(totErr) );
+ // System.out.println(totErr);
+ // bad test, but I can't find a good threshold that works for all individual cases
+ assertTrue("failed " + totErr/numberOfTests, totErr/numberOfTests < 1e-7);
+ assertTrue("failed " + qtotErr/numberOfTests , qtotErr/numberOfTests < 1e-10);
+ assertTrue("failed " + ptotErr/np, np > 0 ? (ptotErr/np < 2e-7) : true);
+ }
+
}
diff --git a/src/test/beast/math/distributions/InvGammaTest.java b/src/test/beast/math/distributions/InvGammaTest.java
new file mode 100644
index 0000000..545cdfc
--- /dev/null
+++ b/src/test/beast/math/distributions/InvGammaTest.java
@@ -0,0 +1,128 @@
+package test.beast.math.distributions;
+
+import org.apache.commons.math.MathException;
+
+import beast.math.distributions.InverseGamma;
+import junit.framework.TestCase;
+
+/**
+ * Simple test for inverse gamma distribution.
+ *
+ * @author Joseph Heled
+ * Date: 24/04/2009
+ */
+public class InvGammaTest extends TestCase {
+ interface TestData {
+ double getShape();
+
+ double getScale();
+
+ double[] getPDF();
+
+ double[] getCDF();
+ }
+
+ // test data generated from this python code:
+// import scipy.stats
+//
+//print """TestData[] tests = {"""
+//for shape,scale in ((3,2), (3,1)) :
+// d = scipy.stats.invgamma(shape, scale=scale)
+// print """
+// new TestData() {
+// public double getShape() {
+// return %d;
+// }
+//
+// public double getScale() {
+// return %d;
+// }""" % (shape, scale)
+// x = (0.5, 1, 2)
+// print """
+// public double[] getPDF() {
+// return new double[]{%s};
+// }""" % " , ".join(["%g,%.14lf" % (z,d.pdf(z)) for z in x])
+//
+// print """
+// public double[] getCDF() {
+// return new double[]{%s};
+// }
+// } ,""" % " , ".join(["%g,%.14lf" % (z,d.cdf(z)) for z in x])
+//
+
+ TestData[] tests = {
+
+ new TestData() {
+ public double getShape() {
+ return 3;
+ }
+
+ public double getScale() {
+ return 2;
+ }
+
+ public double[] getPDF() {
+ return new double[]{0.5, 1.17220088887899, 1, 0.54134113294645, 2, 0.09196986029286};
+ }
+
+ public double[] getCDF() {
+ return new double[]{0.5, 0.23810330555354, 1, 0.67667641618306, 2, 0.91969860292861};
+ }
+ },
+
+ new TestData() {
+ public double getShape() {
+ return 3;
+ }
+
+ public double getScale() {
+ return 1;
+ }
+
+ public double[] getPDF() {
+ return new double[]{0.5, 1.08268226589290, 1, 0.18393972058572, 2, 0.01895408311602};
+ }
+
+ public double[] getCDF() {
+ return new double[]{0.5, 0.67667641618306, 1, 0.91969860292861, 2, 0.98561232203303};
+ }
+ },
+ };
+
+
+ public void testInvGamma() throws MathException {
+ for( TestData td : tests ) {
+ InverseGamma d = new InverseGamma();
+ d.initByName("alpha", td.getShape() + "" , "beta", td.getScale() + "");
+
+ {
+ double[] p = td.getPDF();
+ for(int k = 0; k < p.length; k += 2) {
+ assertEquals(d.density(p[k]), p[k + 1], 1e-10);
+
+ assertEquals(d.logDensity(p[k]), Math.log(p[k + 1]), 1e-10);
+ }
+ }
+
+ double[] cdf = td.getCDF();
+ for(int k = 0; k < cdf.length; k += 2) {
+ // InverseGamma.cumulativeProbability is not implemented yet
+ // assertEquals(d.cumulativeProbability(cdf[k]), cdf[k + 1], 1e-10);
+ }
+
+// int count[] = new int[cdf.length];
+// final int N = 100000;
+// for(int k = 0; k < N; ++k) {
+// double x = d.nextInverseGamma();
+// for(int l = 0; l < cdf.length; l += 2) {
+// if( x < cdf[l] ) {
+// count[l / 2] += 1;
+// }
+// }
+// }
+// for(int l = 0; l < cdf.length; l += 2) {
+// assertEquals(count[l / 2] / (double) N, cdf[l + 1], 5e-3);
+// }
+ }
+ }
+}
diff --git a/src/test/beast/math/distributions/LogNormalDistributionModelTest.java b/src/test/beast/math/distributions/LogNormalDistributionModelTest.java
index 39cde57..6ad4926 100644
--- a/src/test/beast/math/distributions/LogNormalDistributionModelTest.java
+++ b/src/test/beast/math/distributions/LogNormalDistributionModelTest.java
@@ -1,10 +1,12 @@
package test.beast.math.distributions;
+import org.apache.commons.math.MathException;
import org.junit.Test;
import beast.core.parameter.RealParameter;
import beast.math.distributions.LogNormalDistributionModel;
+import beast.util.Randomizer;
import beast.util.XMLParser;
import junit.framework.TestCase;
@@ -17,12 +19,12 @@ public class LogNormalDistributionModelTest extends TestCase {
logNormal.init("1.0", "2.0");
for (int i = 0; i < 10000; i++) {
- double M = Math.random() * 10.0 - 5.0;
- double S = Math.random() * 10;
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+ double S = Randomizer.nextDouble() * 10;
double x = -1;
while( x < 0 ) {
- x = Math.log(Math.random() * 10);
+ x = Math.log(Randomizer.nextDouble() * 10);
}
logNormal.MParameterInput.setValue(M + "", logNormal);
@@ -79,5 +81,137 @@ public class LogNormalDistributionModelTest extends TestCase {
double f0 = logNormal.calcLogP(p);
assertEquals(-7.880210654973873, f0, 1e-10);
}
+
+
+
+ // remainder is adapted from Alexei's LogNormalDistributionTest from BEAST 1
+ LogNormalDistributionModel logNormal;
+
+ public void setUp() {
+
+ logNormal = new LogNormalDistributionModel();
+ logNormal.initByName("M", "1.0", "S", "2.0");
+ Randomizer.setSeed(123);
+ }
+
+ public void testPdf() {
+
+ System.out.println("Testing 10000 random pdf calls");
+
+ for (int i = 0; i < 10000; i++) {
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+ double S = Randomizer.nextDouble() * 10;
+
+ double x = Math.log(Randomizer.nextDouble() * 10);
+
+ logNormal.MParameterInput.setValue(M + "", logNormal);
+ logNormal.SParameterInput.setValue(S + "", logNormal);
+ logNormal.initAndValidate();
+
+ double pdf = 1.0 / (x * S * Math.sqrt(2 * Math.PI)) * Math.exp(-Math.pow(Math.log(x) - M, 2) / (2 * S * S));
+ if (x <= 0) pdf = 0; // see logNormal.pdf(x)
+
+ //System.out.println("Testing logNormal[M=" + M + " S=" + S + "].pdf(" + x + ")");
+
+ assertEquals(pdf, logNormal.density(x), 1e-10);
+ }
+ }
+
+ public void testMean() {
+
+ for (int i = 0; i < 1000; i++) {
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+ double S = Randomizer.nextDouble() * 10;
+
+ logNormal.MParameterInput.setValue(M + "", logNormal);
+ logNormal.SParameterInput.setValue(S + "", logNormal);
+ logNormal.initAndValidate();
+
+ double mean = Math.exp(M + S * S / 2);
+
+ //System.out.println("Testing logNormal[M=" + M + " S=" + S + "].mean()");
+
+ assertEquals(mean, logNormal.getMean(), 1e-10);
+ }
+ }
+
+// public void testVariance() {
+//
+// for (int i = 0; i < 1000; i++) {
+// double M = Randomizer.nextDouble() * 10.0 - 5.0;
+// double S = Randomizer.nextDouble() * 10;
+//
+// logNormal.MParameterInput.setValue(M, logNormal);
+// logNormal.SParameterInput.setValue(S, logNormal);
+// logNormal.initAndValidate();
+//
+// double variance = (Math.exp(S * S) - 1) * Math.exp(2 * M + S * S);
+//
+// //System.out.println("Testing logNormal[M=" + M + " S=" + S + "].variance()");
+//
+// assertEquals(variance, logNormal.getVariance(), 1e-10);
+// }
+// }
+
+
+ public void testMedian() throws MathException {
+
+ System.out.println("Testing 10000 random quantile(0.5) calls");
+
+ for (int i = 0; i < 10000; i++) {
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+ double S = Randomizer.nextDouble() * 10;
+
+ logNormal.MParameterInput.setValue(M + "", logNormal);
+ logNormal.SParameterInput.setValue(S + "", logNormal);
+ logNormal.initAndValidate();
+
+ double median = Math.exp(M);
+
+ //System.out.println("Testing logNormal[M=" + M + " S=" + S + "].median()");
+
+ assertEquals(median, logNormal.inverseCumulativeProbability(0.5), median / 1e6);
+ }
+ }
+
+ public void testCDFAndQuantile() throws MathException {
+
+ System.out.println("Testing 10000 random quantile/cdf pairs");
+
+ for (int i = 0; i < 10000; i++) {
+
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+ double S = Randomizer.nextDouble() * 10;
+
+ logNormal.MParameterInput.setValue(M + "", logNormal);
+ logNormal.SParameterInput.setValue(S + "", logNormal);
+ logNormal.initAndValidate();
+
+ double p = Randomizer.nextDouble();
+ double quantile = logNormal.inverseCumulativeProbability(p);
+
+ double cdf = logNormal.cumulativeProbability(quantile);
+
+ assertEquals(p, cdf, 1e-7);
+ }
+ }
+
+// public void testCDFAndQuantile2() {
+//
+// final LogNormalDistributionModel f = new LogNormalDistributionModel();
+// logNormal.initByName("M", "1.0", "S", "1.0");
+// for (double i = 0.01; i < 0.95; i += 0.01) {
+// final double y = i;
+//
+// BisectionZeroFinder zeroFinder = new BisectionZeroFinder(new OneVariableFunction() {
+// public double value(double x) {
+// return f.cdf(x) - y;
+// }
+// }, 0.01, 100);
+// zeroFinder.evaluate();
+//
+// assertEquals(f.quantile(i), zeroFinder.getResult(), 1e-6);
+// }
+// }
}
diff --git a/src/test/beast/math/distributions/MRCAPriorTest.java b/src/test/beast/math/distributions/MRCAPriorTest.java
index f15bbf7..39c4e4a 100644
--- a/src/test/beast/math/distributions/MRCAPriorTest.java
+++ b/src/test/beast/math/distributions/MRCAPriorTest.java
@@ -1,5 +1,9 @@
package test.beast.math.distributions;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+
import org.junit.Test;
import beast.evolution.alignment.Alignment;
@@ -64,6 +68,21 @@ public class MRCAPriorTest extends TestCase {
prior.initByName("tree", tree, "taxonset", set, "monophyletic", true);
logP = prior.calculateLogP();
assertEquals(logP, Double.NEGATIVE_INFINITY, 0);
+
+
+ set.setID("test");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ prior.init(ps);
+ String log = new String(baos.toByteArray(), StandardCharsets.UTF_8);
+ assertEquals(log, "mrcatime(test)\t");
+
+ baos = new ByteArrayOutputStream();
+ ps = new PrintStream(baos);
+ prior.initByName("tree", tree, "taxonset", set, "monophyletic", true, "useOriginate", true);
+ prior.init(ps);
+ log = new String(baos.toByteArray(), StandardCharsets.UTF_8);
+ assertEquals(log, "mrcatime(test.originate)\t");
}
@Test
diff --git a/src/test/beast/math/distributions/NormalDistributionTest.java b/src/test/beast/math/distributions/NormalDistributionTest.java
new file mode 100644
index 0000000..f88b46c
--- /dev/null
+++ b/src/test/beast/math/distributions/NormalDistributionTest.java
@@ -0,0 +1,132 @@
+package test.beast.math.distributions;
+
+import org.apache.commons.math.MathException;
+
+import beast.math.distributions.Normal;
+import beast.util.Randomizer;
+import junit.framework.TestCase;
+
+/**
+ * adapted from BEAST 1
+ * @author Wai Lok Sibon Li
+ *
+ */
+public class NormalDistributionTest extends TestCase {
+ Normal norm;
+
+ public void setUp() {
+
+ norm = new Normal();
+ norm.initAndValidate();
+ Randomizer.setSeed(123);
+ }
+
+
+ public void testPdf() {
+
+ System.out.println("Testing 10000 random pdf calls");
+
+ for (int i = 0; i < 10000; i++) {
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+ double S = Randomizer.nextDouble() * 10;
+
+ double x = Randomizer.nextDouble() * 10;
+
+ norm.meanInput.setValue(M + "", norm);
+ norm.sigmaInput.setValue(S + "", norm);
+ norm.initAndValidate();
+
+ double a = 1.0 / (Math.sqrt(2.0 * Math.PI) * S);
+ double b = -(x - M) * (x - M) / (2.0 * S * S);
+ double pdf = a * Math.exp(b);
+
+ assertEquals(pdf, norm.density(x), 1e-10);
+ }
+
+ /* Test with an example using R */
+ norm.meanInput.setValue(2.835202292812448 + "", norm);
+ norm.sigmaInput.setValue(3.539139491639669 + "", norm);
+ assertEquals(0.1123318, norm.density(2.540111), 1e-6);
+ }
+
+ public void testMean() {
+
+ for (int i = 0; i < 1000; i++) {
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+
+ norm.meanInput.setValue(M + "", norm);
+ norm.initAndValidate();
+
+ assertEquals(M, norm.getMean(), 1e-10);
+ }
+ }
+
+// public void testVariance() {
+//
+// for (int i = 0; i < 1000; i++) {
+// double S = Randomizer.nextDouble() * 10;
+// norm.sigmaInput.setValue(S + "", norm);
+// norm.initAndValidate();
+//
+// double variance = S * S;
+//
+// assertEquals(variance, norm.variance(), 1e-10);
+// }
+// }
+
+
+ public void testMedian() throws MathException {
+
+ System.out.println("Testing 10000 random quantile(0.5) calls");
+
+ for (int i = 0; i < 10000; i++) {
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+ double S = Randomizer.nextDouble() * 10;
+
+ norm.meanInput.setValue(M + "", norm);
+ norm.sigmaInput.setValue(S + "", norm);
+ norm.initAndValidate();
+
+ double median = M;
+
+ assertEquals(median, norm.inverseCumulativeProbability(0.5), 1e-6);
+ }
+ }
+
+ public void testCDFAndQuantile() throws MathException {
+
+ System.out.println("Testing 10000 random quantile/cdf pairs");
+
+ for (int i = 0; i < 10000; i++) {
+
+ double M = Randomizer.nextDouble() * 10.0 - 5.0;
+ double S = Randomizer.nextDouble() * 10;
+
+ norm.meanInput.setValue(M + "", norm);
+ norm.sigmaInput.setValue(S + "", norm);
+ norm.initAndValidate();
+
+ double p = Randomizer.nextDouble();
+ double quantile = norm.inverseCumulativeProbability(p);
+ double cdf = norm.cumulativeProbability(quantile);
+
+ assertEquals(p, cdf, 1e-7);
+ }
+
+ }
+
+// public void testCDFAndQuantile2() {
+// for(int i=0; i<10000; i++) {
+// double x =Randomizer.nextDouble();
+// double m = Randomizer.nextDouble() * 10;
+// double s = Randomizer.nextDouble() * 10;
+//
+// double a = NormalDistribution.cdf(x, m, s, false);
+// double b =NormalDistribution.cdf(x, m, s);
+//
+// assertEquals(a, b, 1.0e-8);
+// }
+// }
+
+
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/beast2-mcmc.git
More information about the debian-med-commit
mailing list