/* Copyright (C) 2011 Diego Darriba, David Posada This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package es.uvigo.darwin.jmodeltest.utilities; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Locale; import java.util.StringTokenizer; import javax.swing.text.Document; import javax.swing.text.SimpleAttributeSet; import pal.alignment.Alignment; import es.uvigo.darwin.jmodeltest.ModelTest; import es.uvigo.darwin.jmodeltest.gui.XManager; public final class Utilities { public static final int NA = Integer.MIN_VALUE; public static final int OS_LINUX = 1; public static final int OS_OSX = 2; public static final int OS_WINDOWS = 3; public Utilities() { } public static String firstNumericToken(String str) { StringTokenizer st = new StringTokenizer(str); String token = ""; boolean found = false; while (st.hasMoreTokens() && !found) { token = st.nextToken(); found |= isNumber(token); } if (found) return token; else return null; } public static String lastToken(String str) { StringTokenizer st = new StringTokenizer(str); String token = ""; while (st.hasMoreTokens()) { token = st.nextToken(); } return token; } public static boolean isWindows() { if (System.getProperty("os.name").startsWith("Window")) return true; return false; } public static int findCurrentOS() { String os = System.getProperty("os.name"); if (os.startsWith("Mac")) return OS_OSX; else if (os.startsWith("Windows")) return OS_WINDOWS; else return OS_LINUX; } public static String getBinaryVersion() { String arch = System.getProperty("os.arch"); String bit = System.getProperty("sun.arch.data.model"); String binaryName = null; switch (findCurrentOS()) { case OS_OSX: if (arch.startsWith("ppc")) { System.err .println("Sorry, PowerPC architecture is no longer supported"); System.exit(0); } else { binaryName = "PhyML_3.0_macOS_i386"; } break; case OS_LINUX: if (bit.startsWith("64")) binaryName = "PhyML_3.0_linux64"; else binaryName = "PhyML_3.0_linux32"; break; case OS_WINDOWS: binaryName = "PhyML_3.0_win32.exe"; break; default: binaryName = null; } return binaryName; } public static String calculateRuntimeMinutes(long startTime, long endTime) { long seconds = Math.round((endTime - startTime) / 1000.0); int hours = (int) (seconds / 3600.0); int rest1 = (int) (seconds % (3600.0)); int minutes = (int) (rest1 / 60.0); seconds = (int) (seconds - (hours * 3600 + minutes * 60)); String h = "" + hours; String m = "" + minutes; String s = "" + seconds; if (minutes < 10) m = "0" + m; if (seconds < 10) s = "0" + s; return h + "h:" + m + ":" + s + ""; } public static String getCurrentTime(String format) { Calendar cal = new GregorianCalendar(); SimpleDateFormat date_format = new SimpleDateFormat(format); return date_format.format(cal.getTime()); } public static String displayRuntime(long time) { long decimes = Math.round(time / 100.0); int hours = (int) (decimes / 36000.0); int rest1 = (int) (decimes % 36000.0); int minutes = (int) (rest1 / 600.0); int rest2 = (int) (rest1 % 600.0); int seconds = (int) (rest2 / 10.0); decimes = (int) (decimes - (hours * 36000 + minutes * 600 + seconds * 10)); String h = "" + hours; String m = "" + minutes; String s = "" + seconds; String d = "0" + decimes; if (hours < 10) h = "0" + h; if (minutes < 10) m = "0" + m; if (seconds < 10) s = "0" + s; return h + "h:" + m + ":" + s + ":" + d + ""; } public static String calculateRuntime(long startTime, long endTime) { return displayRuntime(endTime - startTime); } public static boolean isNumber(String s) { try { Double.parseDouble(s); return true; } catch (NumberFormatException ex) { return false; } } public static void toConsoleEnd() { if (ModelTest.buildGUI) XManager.getInstance() .getPane() .setCaretPosition( XManager.getInstance().getPane().getDocument() .getLength()); } /** * copyFile * * Copies src file to dst file. If the dst file does not exist, it is * created modified from The Java Developers Almanac 1.4: * http://www.exampledepot.com/egs/java.io/CopyFile.html */ public static void copyFile(String source, String destination) throws IOException { File src = new File(source); File dst = new File(destination); InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst); // Transfer bytes from in to out byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } in.close(); out.close(); } /** * CheckNA * * If value is NA it prints "-" */ public static String checkNA(double value) { if (value == NA) return " - "; else { String s = String.format(Locale.ENGLISH, "%8.4f", value); return s; } } /** * deleteFile * * Delete a given file */ public static void deleteFile(String fileName) { File f; try { f = new File(fileName); } catch (Exception e) { throw new IllegalArgumentException("DeleteFiles: deletion of " + fileName + " failed"); } // Make sure the file or directory exists and isn't write protected if (f.exists()) { if (!f.canWrite()) throw new IllegalArgumentException( "DeleteFiles: write protected: " + fileName); // if it is a directory, make sure it is empty if (f.isDirectory()) { String[] files = f.list(); if (files.length > 0) throw new IllegalArgumentException( "DeleteFiles: directory not empty: " + fileName); } // explicit close associated stream for windows // // attempt to delete it boolean success = f.delete(); if (!success) throw new IllegalArgumentException("DeleteFiles: deletion of " + fileName + " failed"); } } private static void printColor(String text, SimpleAttributeSet color) { if (ModelTest.buildGUI) { try { Document doc = XManager.getInstance().getPane().getDocument(); doc.insertString(doc.getLength(), text, color); } catch (javax.swing.text.BadLocationException e) { System.err.println("Bad Location Exception"); } } else { System.out.print(text); } } /** * printRed * * Prints to the main console text in red */ public static void printRed(String text) { printColor(text, XManager.redText); } /** * printBlue * * Prints to the main console text in blue */ public static void printBlue(String text) { printColor(text, XManager.blueText); } /****************** * RoundDoubleTo ************************** * * Rounds a double to a number of significant digits *********************************************************/ public static double roundDoubleTo(double decimal, int dplaces) { BigDecimal bd = new BigDecimal(decimal); bd = bd.setScale(dplaces, BigDecimal.ROUND_UP); return bd.doubleValue(); } public static String asPercent(double decimal) { if (decimal > 100.0d) { decimal = 100.0d; } return format(decimal, 6, 2, false) + "%"; } public static String format(double number, int totalLength, int decimalPlaces, boolean exp) { StringBuffer sb; String format; if (exp) { format = "%"+totalLength+"."+decimalPlaces+"e"; } else { format = "%"+totalLength+"."+decimalPlaces+"f"; } sb = new StringBuffer(String.format(Locale.ENGLISH, format, number)); // normalize string to size 6 for (int i = sb.length(); i < totalLength; i++) { sb.insert(0, " "); } return sb.toString(); } /****************** * putSlashBeforeSpaces ************************** * * Inserts slash before paces in a path (MacOS X) *********************************************************/ public static String putSlashBeforeSpaces(String originalPath) { if (originalPath == null) return ""; StringBuffer s = new StringBuffer(originalPath); for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == ' ') s.insert(i++, '\\'); } return s.toString(); } /****************** * substituteSpaces ************************** * * substitutes %20 in spaces in a path (MacOS X) *********************************************************/ public static String substituteSpaces(String originalPath) { if (originalPath == null) return ""; StringBuffer s = new StringBuffer(originalPath); for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == ' ') { s.setCharAt(i, '0'); s.insert(i++, '%'); s.insert(i++, '2'); } } return s.toString(); } /****************** * putQuotesAroundSpaces ************************** * * Inserts quotes at correct locations in nominated path string. (Windows) *********************************************************/ public static String putQuotesAroundSpaces(String originalPath) { StringTokenizer st = new StringTokenizer(originalPath, File.separator); String newPath = "\""; while (st.hasMoreTokens()) { String token = st.nextToken(); if (token.contains(" ")) { newPath += File.separator + "\"" + token + "\""; } else { newPath += File.separator + token; } } return newPath.substring(1, newPath.length()); } /****************** * specialConcatStringArrays ************************** * * concatenates two string arrays but removinf the first string from the * second *********************************************************/ public static String[] specialConcatStringArrays(String[] A, String[] B) { String[] C = new String[A.length + B.length - 1]; System.arraycopy(A, 0, C, 0, A.length); System.arraycopy(B, 1, C, A.length, B.length - 1); return C; } /** * Calculate invariable sites. * * @param alignment the alignment * * @return the invariable sites in the alignment */ public static int calculateInvariableSites (Alignment alignment) { //use this function to estimate a good starting value for the InvariableSites distribution. int numSites = alignment.getSiteCount(); int numSeqs = alignment.getSequenceCount(); int inv = 0; int tmp; boolean tmpInv = true; for(int i=0; i < numSites; i++) { tmp = indexOfChar(alignment.getData(0,i)); tmpInv = true; for(int j=0; j < numSeqs; j++) { if(indexOfChar(alignment.getData(j,i)) != tmp) { //if at least one difference in column i: j = numSeqs; //we exit this for. tmpInv = false; //i is not an invariable site. } } if(tmpInv) inv++; } return inv; } private static int indexOfChar (char c) { char[] charSet = {'A', 'C', 'G', 'T', 'a', 'c', 'g', 't'}; for (int charIndex = 0; charIndex < charSet.length; charIndex++) if (charSet[charIndex] == c) return charIndex % 4; return -1; } public static double calculateShannonSampleSize (Alignment alignment, boolean doJustShannonEntropy) { int numSites = alignment.getSiteCount(); int numTaxa = alignment.getSequenceCount(); //int pattern[][] = new int [numSites][numSeqs]; double freqs [][] = new double[numSites][4]; byte state [][] = new byte [numSites][4]; double siteS [] = new double[numSites]; int sequences[] = new int[numSites]; double shannonEntropy = 0.0; //We simply count bases at positions and store in state[][] for(int i=0; i < numSites; i++) { for(int j=0; j < numTaxa; j++) { //state[i][indexOfchar(alignment.getData(j,i))]++; int index = indexOfChar(alignment.getData(j,i)); if(index >= 0) { state[i][index]++; sequences[i]++; } //state[i][sP.pattern[j][i]]++; } } //For each alignment position, we calculate aminoacid frequencies. And also... //For each alignment position, we calculate Shannon Entropy based on previous frequencies. for(int i=0; i < numSites; i++) { for(int j=0; j < 4; j++) { //freqs[i][j] = (double)state[i][j]/(double)numSeqs; freqs[i][j] = (double)state[i][j]/(double)sequences[i]; if(freqs[i][j] > 0) siteS[i] += freqs[i][j]*Math.log(freqs[i][j])/Math.log(2); } } //We sum positions entropies over the whole alignment. for(int i=0; i < numSites; i++) { shannonEntropy += siteS[i]; } if(doJustShannonEntropy) { return -1.0*shannonEntropy; //sum of shannon Entropy positions. } else { //if Options.SHANNON_NxL double meanShannonEntropy; double maxShannonEntropy = 0; double normalizedShannonEntropy = 0; meanShannonEntropy = -1.0*shannonEntropy/(double)numSites; //mean S for sites //let's normalize ShannonEntropy from 0 to 1: for(int i=0; i<4; i++) { maxShannonEntropy += (1.0/(double)4)*Math.log(1.0/(double)4)/Math.log(2); } //by this moment we normalize by a "rule of three" normalizedShannonEntropy = -1.0*meanShannonEntropy/maxShannonEntropy; return (double)numSites*(double)numTaxa*normalizedShannonEntropy; //NxL x averaged Shannon entropy } } } // end of class