/* * Microsatellite.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.evolution.datatype; import java.util.ArrayList; /** * @author Chieh-Hsi Wu * * Microsatellite data type */ public class Microsatellite extends DataType { public static final String DESCRIPTION = "microsatellite"; public static int UNKNOWN_STATE_LENGTH = -1; private int min; private int max; private int unitLength; private String name; public static final Microsatellite INSTANCE = new Microsatellite(); public Microsatellite() {} /** * Constructor * * @param min integer representing the minimum length of the microsatellite * @param max integer representing the maximum length of the microsatellite */ public Microsatellite(String name, int min, int max){ this(name, min, max, 1); } public Microsatellite(int min, int max){ this("microsat", min, max, 1); } /** * Constructor * * @param min integer representing the minimum length of the microsatellite * @param max integer representing the maximum length of the microsatellite * @param unitLength the length in nucleotide units for one repeat unit. */ public Microsatellite(String name, int min, int max, int unitLength){ this.min = min; this.max = max; this.name = name; this.unitLength = unitLength; stateCount = (max - min)/unitLength + 1; ambiguousStateCount = stateCount + 1; } /** * This class constructs a Microsatellite Parameter. * * @param pattern an array of ints representing the lengths (in nucleotide units) at a microsatellite locus * @param extRange the length (in repeat units) to which to extend the current range of microsatellite in the pattern * @param unitLength the length in nucleotide units for one repeat unit. */ public Microsatellite(int[] pattern, int extRange, int unitLength){ this.unitLength = unitLength; //find the current max and min in the pattern parameter min = pattern[0]; max = pattern[0]; for(int i = 1; i < pattern.length; i++){ if(min > pattern[i]&&(pattern[i] > 0)){ min=pattern[i]; } if(max < pattern[i]&&(pattern[i] > 0)){ max=pattern[i]; } } //new max and min according to the extRange provided max = max + extRange*this.unitLength; min = min - extRange*this.unitLength; //set stateCount if((max-min)%this.unitLength == 0){ stateCount = (max - min)/this.unitLength + 1; }else{ throw new IllegalArgumentException("Incorrect microsatellite unit length."); } //set ambiguous stateCount ambiguousStateCount = stateCount + 1; } /** * * @param srtRawLength a String representing the raw length of a microsatellite allele in nucleotide units * @return int the state of microsatellite allele corresponding to the length */ public int getState(String srtRawLength){ char chRawLength = srtRawLength.charAt(0); try{ if(chRawLength == UNKNOWN_CHARACTER){ return getState(UNKNOWN_STATE_LENGTH); }else{ return getState(Integer.parseInt(srtRawLength)); } } catch(java.lang.NumberFormatException exp) { throw new java.lang.NumberFormatException(srtRawLength+" can not be converted. State needs to be an integer or unknown (?)."); } } /** * * @param rawLength an int representing the raw length of a microsatellite allele in nucleotide units * @return int the state of microsatellite allele corresponding to the length */ public int getState(int rawLength){ if(rawLength != UNKNOWN_STATE_LENGTH){ if (rawLength < min) { throw new java.lang.IllegalArgumentException("Microsatellite length value is less, (" + rawLength + ") than the specified minimum (" + min + ")."); } return (int)Math.ceil(((double)rawLength - min)/unitLength); }else{ return stateCount; } } /** * * @param strStates an ArrayList of Strings representing the raw microsatellite lengths in a pattern at a locus * @return int[] an array of ints representing the raw microsatellite lengths in a pattern at a locus */ public static int[] convertToLengths(ArrayList<String> strStates){ return convertToLengths(strStates.toArray(new String[strStates.size()])); } /** * * @param strStates an array of Strings representing the raw microsatellite lengths in a pattern at a locus * @return int[] an array of ints representing the raw microsatellite lengths in a pattern at a locus */ public static int[] convertToLengths(String[] strStates){ int[] lengths = new int[strStates.length]; for(int i = 0; i < strStates.length; i++){ char ch = strStates[i].charAt(0); try{ if(ch == UNKNOWN_CHARACTER){ lengths[i] = UNKNOWN_STATE_LENGTH; }else{ lengths[i] = Integer.parseInt(strStates[i]); } }catch(java.lang.NumberFormatException exp){ throw new java.lang.NumberFormatException(strStates[i]+" can not be converted. State needs to be an integer or unknown (?)."); } } return lengths; } /** * * @param stateCode the code of the state of a microsatellite allele * @return the raw length of the microsallite allele given it's state code * */ public int getActualLength(int stateCode){ if(stateCode < stateCount){ return (stateCode+min); }else if(stateCode == stateCount){ return UNKNOWN_STATE_LENGTH; }else{ throw new java.lang.RuntimeException("The given state must be an integer greater or equal to -1"); } } /** * * @param state code representing a microsatellite allele * @return true if min <= state <= max, false otherwise. * */ public boolean isWithinRange(int state){ return (state >= min && state <= max); } /** * @return the upper bound of allele length */ public int getMax(){ return max; } /** * * @return the lower bound of allele length * */ public int getMin(){ return min; } public void setMax(int max){ this.max = max; } public void setMin(int min){ this.min = min; } /** * @return true if the provided stateCode = unknownStateCode */ public boolean isUnknownState(int stateCode){ return (stateCode == stateCount); } @Override public char[] getValidChars() { return null; } /** * @return number of unambiguous states for this data type. */ public int getStateCount(){ return stateCount; } /** * @return number of states (ambiguous states inclusive) for this data type. */ public int getAmbiguousStateCount(){ return ambiguousStateCount; } /** * @return the length (in bp) of one repeat unit */ public int getUnitLength(){ return unitLength; } public void setName(String name) { this.name = name; } public String getName() { return name; } /** * @return the description of the data type */ public String getDescription() { return DESCRIPTION; } public int getType(){ return MICRO_SAT; } }