diff --git a/build.xml b/build.xml
index c2c69dd..2efc3d8 100644
--- a/build.xml
+++ b/build.xml
@@ -13,12 +13,13 @@
+
-
+
@@ -34,6 +35,7 @@
+
diff --git a/src/beast/app/tools/BModelAnalyser.java b/src/beast/app/tools/BModelAnalyser.java
new file mode 100644
index 0000000..2978a76
--- /dev/null
+++ b/src/beast/app/tools/BModelAnalyser.java
@@ -0,0 +1,139 @@
+package beast.app.tools;
+
+import java.io.File;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import beast.app.beauti.BeautiConfig;
+import beast.app.beauti.BeautiDoc;
+import beast.app.draw.BEASTObjectDialog;
+import beast.app.draw.BEASTObjectPanel;
+import beast.app.util.Application;
+import beast.app.util.ConsoleApp;
+import beast.app.util.LogFile;
+import beast.core.Description;
+import beast.core.Input;
+import beast.core.Input.Validate;
+import beast.core.Runnable;
+import beast.util.LogAnalyser;
+
+@Description("Analyses bModelTest log and list useful stats such as 95% HPDs of model indicators")
+public class BModelAnalyser extends Runnable {
+ public Input traceFileInput = new Input<>("file","trace log file containing output of a bModelTest analysis", Validate.REQUIRED);
+ public Input prefixInput = new Input<>("prefix", "prefix of the entry in the log file containing the substitution model trace (default 'substmodel')" , "substmodel");
+ public Input burninInput = new Input<>("burnin", "percentage of the log file to disregard as burn-in (default 10)" , 10);
+
+
+ @Override
+ public void initAndValidate() {
+ int burnin = burninInput.get();
+ if (burnin >= 100) {
+ throw new IllegalArgumentException("burnin is a percentage and should not be larger than 100");
+ }
+
+ }
+
+ @Override
+ public void run() throws Exception {
+ File file = traceFileInput.get();
+ String prefix = prefixInput.get();
+ int burnin = burninInput.get();
+ if (burnin < 0) {
+ burnin = 0;
+ }
+
+ LogAnalyser analyser = new LogAnalyser(file.getAbsolutePath(), burnin);
+ for (String label : analyser.getLabels()) {
+ if (label.startsWith(prefix)) {
+ Double [] trace = analyser.getTrace(label);
+ processTrace(label, trace);
+ }
+ }
+ }
+
+ private void processTrace(String label, Double[] trace) {
+ System.out.println(label);
+ int [] model = new int[trace.length];
+ for (int i = 0; i < trace.length; i++) {
+ model[i] = (int) (double) (trace[i] + 0.5);
+ }
+
+ Map countMap = new HashMap<>();
+ for (int i : model) {
+ if (!countMap.containsKey(i)) {
+ countMap.put(i, 0);
+ }
+ countMap.put(i, countMap.get(i) + 1);
+ }
+
+ List models = new ArrayList<>();
+ for (Integer i : countMap.keySet().toArray(new Integer[]{})) {
+ models.add(i);
+ }
+
+ Collections.sort(models, (i1,i2)-> {
+ return countMap.get(i1).compareTo(countMap.get(i2));
+ });
+
+ int treshold = 95 * trace.length / 100;
+ int sum = 0;
+ NumberFormat formatter = new DecimalFormat("##0.00");
+ for (int i = models.size() - 1; i > 0 && sum < treshold; i--) {
+ int current = models.get(i);
+ int contribution = countMap.get(current);
+ sum += contribution;
+ double con = 100*(contribution + 0.0)/trace.length;
+ if (con < 10) {
+ System.out.print(" ");
+ }
+ System.out.print(formatter.format(con) + "% " );
+ System.out.print(formatter.format(100*(sum + 0.0)/trace.length) + "% " );
+ System.out.println(current);
+ }
+ System.out.println();
+ }
+
+ static ConsoleApp app;
+ public static void main(String[] args) throws Exception {
+ BModelAnalyser analyser = new BModelAnalyser();
+ analyser.setID("Analyses bModelTest trace logs");
+ analyser.traceFileInput.setValue(new LogFile("someTrace.log"), analyser);
+
+ if (args.length == 0) {
+ // create BeautiDoc and beauti configuration
+ BeautiDoc doc = new BeautiDoc();
+ doc.beautiConfig = new BeautiConfig();
+ doc.beautiConfig.initAndValidate();
+
+ // create panel with entries for the application
+ BEASTObjectPanel panel = new BEASTObjectPanel(analyser, analyser.getClass(), doc);
+
+ // wrap panel in a dialog
+ BEASTObjectDialog dialog = new BEASTObjectDialog(panel, null);
+
+ // show the dialog
+ if (dialog.showDialog()) {
+ dialog.accept(analyser, doc);
+ // create a console to show standard error and standard output
+ app = new ConsoleApp("BModelAnalyser",
+ "BModelAnalyser: " + analyser.traceFileInput.get().getPath(),
+ null
+ );
+ analyser.initAndValidate();
+ analyser.run();
+ }
+ return;
+ }
+
+ Application main = new Application(analyser);
+ main.parseArgs(args, false);
+ analyser.initAndValidate();
+ analyser.run();
+ }
+
+}
diff --git a/version.xml b/version.xml
index cf3445c..77309f8 100644
--- a/version.xml
+++ b/version.xml
@@ -1,3 +1,9 @@
-
+
+
+
+