diff --git a/public/java/src/org/broadinstitute/sting/utils/variantcontext/Genotype.java b/public/java/src/org/broadinstitute/sting/utils/variantcontext/Genotype.java index 5639ef30e..e2e44e2b9 100755 --- a/public/java/src/org/broadinstitute/sting/utils/variantcontext/Genotype.java +++ b/public/java/src/org/broadinstitute/sting/utils/variantcontext/Genotype.java @@ -108,14 +108,19 @@ public class Genotype { /** * @return the ploidy of this genotype */ - public int getPloidy() { return alleles.size(); } + public int getPloidy() { + if ( alleles == null ) + throw new ReviewedStingException("Requesting ploidy for an UNAVAILABLE genotype"); + return alleles.size(); + } public enum Type { NO_CALL, HOM_REF, HET, HOM_VAR, - UNAVAILABLE + UNAVAILABLE, + MIXED // no-call and call in the same genotype } public Type getType() { @@ -129,36 +134,68 @@ public class Genotype { if ( alleles == null ) return Type.UNAVAILABLE; - Allele firstAllele = alleles.get(0); + boolean sawNoCall = false, sawMultipleAlleles = false; + Allele observedAllele = null; - if ( firstAllele.isNoCall() ) { - return Type.NO_CALL; + for ( Allele allele : alleles ) { + if ( allele.isNoCall() ) + sawNoCall = true; + else if ( observedAllele == null ) + observedAllele = allele; + else if ( !allele.equals(observedAllele) ) + sawMultipleAlleles = true; } - for (Allele a : alleles) { - if ( ! firstAllele.equals(a) ) - return Type.HET; + if ( sawNoCall ) { + if ( observedAllele == null ) + return Type.NO_CALL; + return Type.MIXED; } - return firstAllele.isReference() ? Type.HOM_REF : Type.HOM_VAR; + + if ( observedAllele == null ) + throw new ReviewedStingException("BUG: there are no alleles present in this genotype but the alleles list is not null"); + + return sawMultipleAlleles ? Type.HET : observedAllele.isReference() ? Type.HOM_REF : Type.HOM_VAR; } /** - * @return true if all observed alleles are the same (regardless of whether they are ref or alt) + * @return true if all observed alleles are the same (regardless of whether they are ref or alt); if any alleles are no-calls, this method will return false. */ public boolean isHom() { return isHomRef() || isHomVar(); } + + /** + * @return true if all observed alleles are ref; if any alleles are no-calls, this method will return false. + */ public boolean isHomRef() { return getType() == Type.HOM_REF; } + + /** + * @return true if all observed alleles are alt; if any alleles are no-calls, this method will return false. + */ public boolean isHomVar() { return getType() == Type.HOM_VAR; } /** - * @return true if we're het (observed alleles differ) + * @return true if we're het (observed alleles differ); if the ploidy is less than 2 or if any alleles are no-calls, this method will return false. */ public boolean isHet() { return getType() == Type.HET; } /** - * @return true if this genotype is not actually a genotype but a "no call" (e.g. './.' in VCF) + * @return true if this genotype is not actually a genotype but a "no call" (e.g. './.' in VCF); if any alleles are not no-calls (even if some are), this method will return false. */ public boolean isNoCall() { return getType() == Type.NO_CALL; } + + /** + * @return true if this genotype is comprised of any alleles that are not no-calls (even if some are). + */ public boolean isCalled() { return getType() != Type.NO_CALL && getType() != Type.UNAVAILABLE; } + + /** + * @return true if this genotype is comprised of both calls and no-calls. + */ + public boolean isMixed() { return getType() == Type.MIXED; } + + /** + * @return true if the type of this genotype is set. + */ public boolean isAvailable() { return getType() != Type.UNAVAILABLE; } // diff --git a/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java b/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java index 14a680af4..f52a7087b 100755 --- a/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java +++ b/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java @@ -998,7 +998,7 @@ public class VariantContext implements Feature { // to enable tribble intergrati else if ( g.isHomVar() ) genotypeCounts[Genotype.Type.HOM_VAR.ordinal()]++; else - throw new IllegalStateException("Genotype of unknown type: " + g); + genotypeCounts[Genotype.Type.MIXED.ordinal()]++; } } } @@ -1042,6 +1042,15 @@ public class VariantContext implements Feature { // to enable tribble intergrati return genotypeCounts[Genotype.Type.HOM_VAR.ordinal()]; } + /** + * Genotype-specific functions -- how many mixed calls are there in the genotypes? + * + * @return number of mixed calls + */ + public int getMixedCount() { + return genotypeCounts[Genotype.Type.MIXED.ordinal()]; + } + // --------------------------------------------------------------------------------------------------------- // // validation: extra-strict validation routines for paranoid users diff --git a/public/java/test/org/broadinstitute/sting/utils/variantcontext/VariantContextUnitTest.java b/public/java/test/org/broadinstitute/sting/utils/variantcontext/VariantContextUnitTest.java index a5060e54e..a4d78b637 100755 --- a/public/java/test/org/broadinstitute/sting/utils/variantcontext/VariantContextUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/utils/variantcontext/VariantContextUnitTest.java @@ -267,6 +267,12 @@ public class VariantContextUnitTest extends BaseTest { Assert.assertEquals(vc.getChromosomeCount(), 2); // we know that there are 2 chromosomes, even though one isn't called Assert.assertEquals(vc.getChromosomeCount(Aref), 0); Assert.assertEquals(vc.getChromosomeCount(C), 1); + Assert.assertFalse(vc.getGenotype("foo").isHet()); + Assert.assertFalse(vc.getGenotype("foo").isHom()); + Assert.assertFalse(vc.getGenotype("foo").isNoCall()); + Assert.assertFalse(vc.getGenotype("foo").isHom()); + Assert.assertTrue(vc.getGenotype("foo").isMixed()); + Assert.assertEquals(vc.getGenotype("foo").getType(), Genotype.Type.MIXED); } @Test (expectedExceptions = IllegalArgumentException.class)