001package com.hfg.bio; 002 003 004import java.util.ArrayList; 005import java.util.Collection; 006import java.util.HashSet; 007import java.util.List; 008import java.util.Set; 009import java.util.stream.Collectors; 010 011import com.hfg.chem.Molecule; 012import com.hfg.util.StringUtil; 013 014//------------------------------------------------------------------------------ 015/** 016 * Nucleotide. 017 * @author J. Alex Taylor, hairyfatguy.com 018 */ 019//------------------------------------------------------------------------------ 020// com.hfg XML/HTML Coding Library 021// 022// This library is free software; you can redistribute it and/or 023// modify it under the terms of the GNU Lesser General Public 024// License as published by the Free Software Foundation; either 025// version 2.1 of the License, or (at your option) any later version. 026// 027// This library is distributed in the hope that it will be useful, 028// but WITHOUT ANY WARRANTY; without even the implied warranty of 029// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 030// Lesser General Public License for more details. 031// 032// You should have received a copy of the GNU Lesser General Public 033// License along with this library; if not, write to the Free Software 034// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 035// 036// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 037// jataylor@hairyfatguy.com 038//------------------------------------------------------------------------------ 039 040public class Nucleotide extends Molecule 041{ 042 //########################################################################## 043 // PRIVATE FIELDS 044 //########################################################################## 045 046 private Character m1LetterCode; 047 private BaseType mBaseType; 048 private List<Nucleotide> mDegeneracy; 049 private Nucleotide mComplement; 050 051 // This declaration has to come before the public constants below. 052 private static Set<Nucleotide> sValues = new HashSet<>(); 053 054 //########################################################################## 055 // PUBLIC FIELDS 056 //########################################################################## 057 058 public enum BaseType { PURINE, PYRIMIDINE }; 059 060 public static final Nucleotide ADENINE = new Nucleotide("Adenine", 'A', BaseType.PURINE) 061 .lock() 062 .register(); 063 064 public static final Nucleotide GUANINE = new Nucleotide("Guanine", 'G', BaseType.PURINE) 065 .lock() 066 .register(); 067 068 public static final Nucleotide CYTOSINE = new Nucleotide("Cytosine",'C', BaseType.PYRIMIDINE) 069 .lock() 070 .register(); 071 072 // DNA only 073 public static final Nucleotide THYMINE = new Nucleotide("Thymine", 'T', BaseType.PYRIMIDINE) 074 .lock() 075 .register(); 076 077 // RNA only 078 public static final Nucleotide URACIL = new Nucleotide("Uracil", 'U', BaseType.PYRIMIDINE) 079 .lock() 080 .register(); 081 082 // TODO Add elemental composition. How to distinguish RNA & DNA? 083 084 // Degenerate (ambiguous) nucleotides 085 public static final Nucleotide W = new Nucleotide("W", 'W').addDegeneracy(ADENINE).addDegeneracy(THYMINE) 086 .lock() 087 .register(); 088 089 public static final Nucleotide S = new Nucleotide("S", 'S').addDegeneracy(CYTOSINE).addDegeneracy(GUANINE) 090 .lock() 091 .register(); 092 093 public static final Nucleotide M = new Nucleotide("M", 'M').addDegeneracy(ADENINE).addDegeneracy(CYTOSINE) 094 .lock() 095 .register(); 096 097 public static final Nucleotide K = new Nucleotide("K", 'K').addDegeneracy(GUANINE).addDegeneracy(THYMINE) 098 .lock() 099 .register(); 100 101 public static final Nucleotide R = new Nucleotide("R", 'R').addDegeneracy(ADENINE).addDegeneracy(GUANINE) 102 .lock() 103 .register(); 104 105 public static final Nucleotide Y = new Nucleotide("Y", 'Y').addDegeneracy(CYTOSINE).addDegeneracy(THYMINE) 106 .lock() 107 .register(); 108 109 public static final Nucleotide B = new Nucleotide("B", 'B').addDegeneracy(CYTOSINE).addDegeneracy(GUANINE).addDegeneracy(THYMINE) 110 .lock() 111 .register(); 112 113 public static final Nucleotide D = new Nucleotide("D", 'D').addDegeneracy(ADENINE).addDegeneracy(GUANINE).addDegeneracy(THYMINE) 114 .lock() 115 .register(); 116 117 public static final Nucleotide H = new Nucleotide("H", 'H').addDegeneracy(ADENINE).addDegeneracy(CYTOSINE).addDegeneracy(THYMINE) 118 .lock() 119 .register(); 120 121 public static final Nucleotide V = new Nucleotide("V", 'V').addDegeneracy(ADENINE).addDegeneracy(CYTOSINE).addDegeneracy(GUANINE) 122 .lock() 123 .register(); 124 125 public static final Nucleotide N = new Nucleotide("N", 'N').addDegeneracy(ADENINE).addDegeneracy(CYTOSINE).addDegeneracy(GUANINE).addDegeneracy(THYMINE) 126 .lock() 127 .register(); 128 129 130 static 131 { 132 // Set the complement values 133 ADENINE.setComplement(THYMINE); 134 THYMINE.setComplement(ADENINE); 135 CYTOSINE.setComplement(GUANINE); 136 GUANINE.setComplement(CYTOSINE); 137 138 R.setComplement(Y); 139 Y.setComplement(R); 140 S.setComplement(S); 141 W.setComplement(W); 142 K.setComplement(M); 143 M.setComplement(K); 144 B.setComplement(V); 145 V.setComplement(B); 146 D.setComplement(H); 147 H.setComplement(D); 148 N.setComplement(N); 149 } 150 151 152 //########################################################################## 153 // CONSTRUCTORS 154 //########################################################################## 155 156 //-------------------------------------------------------------------------- 157 public Nucleotide(String inName) 158 { 159 super(); 160 setName(inName); 161 } 162 163 //-------------------------------------------------------------------------- 164 public Nucleotide(String inName, char in1LetterCode) 165 { 166 this(inName); 167 m1LetterCode = in1LetterCode; 168 } 169 170 //-------------------------------------------------------------------------- 171 public Nucleotide(String inName, char in1LetterCode, BaseType inBaseType) 172 { 173 this(inName, in1LetterCode); 174 mBaseType = inBaseType; 175 } 176 177 178 //########################################################################## 179 // PUBLIC METHODS 180 //########################################################################## 181 182 183 //-------------------------------------------------------------------------- 184 @Override 185 public Nucleotide lock() 186 { 187 return (Nucleotide) super.lock(); 188 } 189 190 //-------------------------------------------------------------------------- 191 /** 192 Puts the Nucleotide into the Set of unique Nucleotides returned by Nucleotide.values(). 193 */ 194 public Nucleotide register() 195 { 196 if (! isLocked()) 197 { 198 throw new RuntimeException("Only locked Nucleotides can be added to the values list!"); 199 } 200 201 sValues.add(this); 202 203 return this; 204 } 205 206 //-------------------------------------------------------------------------- 207 /** 208 Returns the Nucleotide whose name or 1-letter code matches the specified String. 209 @param inString the name or 1-letter code for the Nucleotide to retrieve 210 @return the Nucleotide whose name or 1-letter code matches the specified String 211 */ 212 public static Nucleotide valueOf(String inString) 213 { 214 Nucleotide value = null; 215 216 if (StringUtil.isSet(inString)) 217 { 218 for (Nucleotide nuc : sValues) 219 { 220 if (nuc.name().equalsIgnoreCase(inString) 221 || inString.charAt(0) == nuc.getOneLetterCode()) 222 { 223 value = nuc; 224 break; 225 } 226 } 227 } 228 229 return value; 230 } 231 232 //-------------------------------------------------------------------------- 233 /** 234 Returns the Nucleotide whose 1-letter code matches the specified String. 235 @param inChar the 1-letter code for the Nucleotide to retrieve 236 @return the Nucleotide whose 1-letter code matches the specified String 237 */ 238 public static Nucleotide valueOf(char inChar) 239 { 240 return valueOf(inChar + ""); 241 } 242 243 //-------------------------------------------------------------------------- 244 public static Nucleotide[] values() 245 { 246 return sValues.toArray(new Nucleotide[sValues.size()]); 247 } 248 249 //-------------------------------------------------------------------------- 250 public static Nucleotide[] degenerateValues() 251 { 252 Set<Nucleotide> values = new HashSet<>(11); 253 for (Nucleotide nucleotide : sValues) 254 { 255 if (nucleotide.isAmbiguous()) 256 { 257 values.add(nucleotide); 258 } 259 } 260 261 return values.toArray(new Nucleotide[values.size()]); 262 } 263 264 //-------------------------------------------------------------------------- 265 /** 266 Returns an unlocked copy of the Nucleotide. 267 */ 268 @Override 269 public Nucleotide clone() 270 { 271 return (Nucleotide) super.clone(); 272 } 273 274 //-------------------------------------------------------------------------- 275 public BaseType getBaseType() 276 { 277 return mBaseType; 278 } 279 280 //-------------------------------------------------------------------------- 281 public Character getOneLetterCode() 282 { 283 return m1LetterCode; 284 } 285 286 287 //-------------------------------------------------------------------------- 288 private Nucleotide setComplement(Nucleotide inValue) 289 { 290 mComplement = inValue; 291 return this; 292 } 293 294 //-------------------------------------------------------------------------- 295 public Nucleotide getComplement() 296 { 297 return mComplement; 298 } 299 300 301 //-------------------------------------------------------------------------- 302 public Nucleotide addDegeneracy(Nucleotide inValue) 303 { 304 if (null == mDegeneracy) 305 { 306 mDegeneracy = new ArrayList<>(4); 307 } 308 309 mDegeneracy.add(inValue); 310 return this; 311 } 312 313 //-------------------------------------------------------------------------- 314 public Collection<Nucleotide> getDegeneracy() 315 { 316 return mDegeneracy; 317 } 318 319 //-------------------------------------------------------------------------- 320 public String getDegeneracyAsString() 321 { 322 return StringUtil.join(mDegeneracy.stream().map(Nucleotide::getOneLetterCode).collect(Collectors.toCollection(ArrayList::new)), ""); 323 } 324 325 //-------------------------------------------------------------------------- 326 public boolean isAmbiguous() 327 { 328 return mDegeneracy != null; 329 } 330}