001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.bio.program.fastq;
022
023import java.util.HashMap;
024import java.util.Map;
025
026/**
027 * FASTQ sequence format variant.
028 *
029 * @since 1.7.1
030 */
031public enum FastqVariant
032{
033    /** Sanger FASTQ sequence format variant. */
034    FASTQ_SANGER("Original or Sanger format")
035    {
036        @Override
037        public int minimumQualityScore()
038        {
039            return 0;
040        }
041
042        @Override
043        public int maximumQualityScore()
044        {
045            return 93;
046        }
047
048        @Override
049        public int qualityScore(final char c)
050        {
051            return ((int) c) - 33;
052        }
053
054        @Override
055        public char quality(final int qualityScore)
056        {
057            if (qualityScore < minimumQualityScore())
058            {
059                throw new IllegalArgumentException("qualityScore must be greater than or equal to minimumQualityScore()");
060            }
061            if (qualityScore > maximumQualityScore())
062            {
063                throw new IllegalArgumentException("qualityScore must be less than or equal to maximumQualityScore()");
064            }
065            return (char) (qualityScore + 33);
066        }
067
068        @Override
069        public double errorProbability(final int qualityScore)
070        {
071            return Math.pow(10.0d, ((double) qualityScore) / -10.0d);
072        }
073    },
074
075    /** Solexa FASTQ sequence format variant. */
076    FASTQ_SOLEXA("Solexa and early Illumina format")
077    {
078        @Override
079        public int minimumQualityScore()
080        {
081            return -5;
082        }
083
084        @Override
085        public int maximumQualityScore()
086        {
087            return 62;
088        }
089
090        @Override
091        public int qualityScore(final char c)
092        {
093            return ((int) c) - 64;
094        }
095
096        @Override
097        public char quality(final int qualityScore)
098        {
099            if (qualityScore < minimumQualityScore())
100            {
101                throw new IllegalArgumentException("qualityScore must be greater than or equal to minimumQualityScore()");
102            }
103            if (qualityScore > maximumQualityScore())
104            {
105                throw new IllegalArgumentException("qualityScore must be less than or equal to maximumQualityScore()");
106            }
107            return (char) (qualityScore + 64);
108        }
109
110        @Override
111        public double errorProbability(final int qualityScore)
112        {
113            double q = Math.pow(10.0d, ((double) qualityScore) / -10.0d);
114            return q / (1 + q);
115        }
116    },
117
118    /** Illumina FASTQ sequence format variant. */
119    FASTQ_ILLUMINA("Illumina 1.3+ format")
120    {
121        @Override
122        public int minimumQualityScore()
123        {
124            return 0;
125        }
126
127        @Override
128        public int maximumQualityScore()
129        {
130            return 62;
131        }
132
133        @Override
134        public int qualityScore(final char c)
135        {
136            return ((int) c) - 64;
137        }
138
139        @Override
140        public char quality(final int qualityScore)
141        {
142            if (qualityScore < minimumQualityScore())
143            {
144                throw new IllegalArgumentException("qualityScore must be greater than or equal to minimumQualityScore()");
145            }
146            if (qualityScore > maximumQualityScore())
147            {
148                throw new IllegalArgumentException("qualityScore must be less than or equal to maximumQualityScore()");
149            }
150            return (char) (qualityScore + 64);
151        }
152
153        @Override
154        public double errorProbability(final int qualityScore)
155        {
156            return Math.pow(10.0d, ((double) qualityScore) / -10.0d);
157        }
158    };
159
160
161    /** Map of FASTQ sequence format variants keyed by name and lowercase-with-dashes name. */
162    private static final Map<String, FastqVariant> FASTQ_VARIANTS = new HashMap<String, FastqVariant>(6);
163
164    static
165    {
166        for (FastqVariant fastqVariant : values())
167        {
168            FASTQ_VARIANTS.put(fastqVariant.name(), fastqVariant);
169            FASTQ_VARIANTS.put(fastqVariant.lowercaseName(), fastqVariant);
170        }
171    }
172
173    /** Description of this FASTQ sequence format variant. */
174    private final String description;
175
176
177    /**
178     * Create a new FASTQ sequence format variant with the specified description.
179     *
180     * @param description description of this FASTQ sequence format variant, must not be null
181     */
182    private FastqVariant(final String description)
183    {
184        if (description == null)
185        {
186            throw new IllegalArgumentException("description must not be null");
187        }
188        this.description = description;
189    }
190
191
192    /**
193     * Return the description of this FASTQ sequence format variant.
194     * The description will not be null.
195     *
196     * @return the description of this FASTQ sequence format variant
197     */
198    public String getDescription()
199    {
200        return description;
201    }
202
203    /**
204     * Return true if this FASTQ sequence format variant is {@link #FASTQ_SANGER}.
205     *
206     * @return true if this FASTQ sequence format variant is {@link #FASTQ_SANGER}
207     */
208    public boolean isSanger()
209    {
210        return (this == FASTQ_SANGER);
211    }
212
213    /**
214     * Return true if this FASTQ sequence format variant is {@link #FASTQ_SOLEXA}.
215     *
216     * @return true if this FASTQ sequence format variant is {@link #FASTQ_SOLEXA}
217     */
218    public boolean isSolexa()
219    {
220        return (this == FASTQ_SOLEXA);
221    }
222
223    /**
224     * Return true if this FASTQ sequence format variant is {@link #FASTQ_ILLUMINA}.
225     *
226     * @return true if this FASTQ sequence format variant is {@link #FASTQ_ILLUMINA}
227     */
228    public boolean isIllumina()
229    {
230        return (this == FASTQ_ILLUMINA);
231    }
232
233    /**
234     * Return the minimum quality score for this FASTQ sequence format variant.
235     *
236     * @since 1.8.2
237     * @return the minimum quality score for this FASTQ sequence format variant.
238     */
239    public abstract int minimumQualityScore();
240
241    /**
242     * Return the maximum quality score for this FASTQ sequence format variant.
243     *
244     * @since 1.8.2
245     * @return the maximum quality score for this FASTQ sequence format variant.
246     */
247    public abstract int maximumQualityScore();
248
249    /**
250     * Convert the specified quality in ASCII format to a quality score.
251     *
252     * @since 1.8.2
253     * @param c quality in ASCII format
254     * @return the specified quality in ASCII format converted to a quality score
255     */
256    public abstract int qualityScore(char c);
257
258    /**
259     * Convert the specified quality score to a quality in ASCII format.
260     *
261     * @since 1.8.3
262     * @param qualityScore quality score, must be <code>&gt;= minimumQualityScore()</code>
263     *    and <code>&lt;= maximumQualityScore()</code>
264     * @return the quality in ASCII format converted from the specified quality score
265     */
266    public abstract char quality(int qualityScore);
267
268    /**
269     * Convert the specified quality in ASCII format to an error probability.
270     *
271     * @since 1.8.2
272     * @param c quality in ASCII format
273     * @return the specified quality in ASCII format converted to an error probability
274     */
275    public double errorProbability(char c)
276    {
277        return errorProbability(qualityScore(c));
278    }
279
280    /**
281     * Calculate the error probability given the specified quality score.
282     *
283     * @since 1.8.2
284     * @param qualityScore quality score
285     * @return the error probability given the specified quality score
286     */
287    public abstract double errorProbability(int qualityScore);
288
289    /**
290     * Return the name of this FASTQ sequence format variant in <code>lowercase-with-dashes</code> style.
291     *
292     * @return the name of this FASTQ sequence format variant in <code>lowercase-with-dashes</code> style
293     */
294    public String lowercaseName()
295    {
296        return name().toLowerCase().replace('_', '-');
297    }
298
299
300    /**
301     * Return the FASTQ sequence format variant with the specified name, if any.  The name may
302     * be specified in either <code>UPPERCASE_WITH_UNDERSCORES</code>
303     * or <code>lowercase-with-dashes</code> style.
304     *
305     * @param name name
306     * @return the FASTQ sequence format variant with the specified name, or <code>null</code>
307     *    if no such FASTQ sequence format variant exists
308     */
309    public static FastqVariant parseFastqVariant(final String name)
310    {
311        return FASTQ_VARIANTS.get(name);
312    }
313}