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 @@ - + + + +