package picard.vcf; /** * A class to store the various classifications for: * 1. a truth genotype versus a reference * 2. a call genotype versus a truth, relative to a reference * * An example use of this class is to have one instance per following use case: * - SNPs * - indels * - filtered variant (truth or call) * - filtered genotype (truth or call) * - low GQ (call) * - low DP (call) * - No call (truth or call) * - No variant (truth or call) * * * @author nhomer */ public class GenotypeConcordanceStates { /** * These states represent the relationship between a truth genotype and the reference sequence. */ public enum TruthState { MISSING, HOM_REF, // ref/ref HET_REF_VAR1, // ref/var1 (var1!=ref) HET_VAR1_VAR2, // var1/var2 (var1!=var2, var1!=ref, var2!=ref) HOM_VAR1, // var1/var1 (var1!=ref) NO_CALL, LOW_GQ, LOW_DP, VC_FILTERED, GT_FILTERED, IS_MIXED; public static TruthState getHom(final int alleleIdx) { if (alleleIdx == 0) return HOM_REF; if (alleleIdx == 1) return HOM_VAR1; assert false; return null; } public static TruthState getVar(final int allele0idx, final int allele1idx) { if (allele0idx == 0 && allele1idx == 1) return HET_REF_VAR1; if (allele0idx == 1 && allele1idx == 0) return HET_REF_VAR1; if (allele0idx == 1 && allele1idx == 2) return HET_VAR1_VAR2; if (allele0idx == 2 && allele1idx == 1) return HET_VAR1_VAR2; assert false; return null; } } /** * These states represent the relationship between the call genotype and the truth genotype relative to * a reference sequence. */ enum CallState { MISSING, HOM_REF, // ref/ref, valid for all TruthStates HET_REF_VAR1, // ref/var1, valid for all TruthStates HET_REF_VAR2, // ref/var2, valid only for TruthStates: HET_REF_VAR1, HET_VAR1_VAR2, HOM_VAR1 HET_REF_VAR3, // ref/var3, valid only for TruthStates: HET_VAR1_VAR2 HET_VAR1_VAR2, // var1/var2, valid for all TruthStates HET_VAR1_VAR3, // var1/var3, valid only for TruthStates: HET_VAR1_VAR2. also encapsulates HET_VAR2_VAR3 (see special case below) HET_VAR3_VAR4, // var3/var4, valid only for TruthStates: HET_REF_VAR1, HET_VAR1_VAR2, HOM_VAR1 HOM_VAR1, // var1/var1, valid for all TruthStates HOM_VAR2, // var2/var2, valid only for TruthStates: HET_REF_VAR1, HET_VAR1_VAR2, HOM_VAR1 HOM_VAR3, // var3/var3, valid only for TruthStates: HET_VAR1_VAR2 NO_CALL, LOW_GQ, LOW_DP, VC_FILTERED, GT_FILTERED, IS_MIXED; public static CallState getHom(final int alleleIdx) { if (alleleIdx == 0) return HOM_REF; if (alleleIdx == 1) return HOM_VAR1; if (alleleIdx == 2) return HOM_VAR2; if (alleleIdx == 3) return HOM_VAR3; assert false; return null; } public static CallState getHet(int allele0idx, int allele1idx) { if(allele0idx > allele1idx){ final int temp = allele0idx; allele0idx=allele1idx; allele1idx=temp; } if(allele0idx == 0) { //REF CASE if (allele1idx == 1) return HET_REF_VAR1; if (allele1idx == 2) return HET_REF_VAR2; if (allele1idx == 3) return HET_REF_VAR3; assert false; return null; } //HET CASES if(allele0idx == 1) { if (allele1idx == 2) return HET_VAR1_VAR2; if (allele1idx == 3) return HET_VAR1_VAR3; assert false; return null; } if(allele0idx == 2 && allele1idx == 3) return HET_VAR3_VAR4; //special case not a mistake. if(allele0idx == 3 && allele1idx == 4) return HET_VAR3_VAR4; assert false; return null; } } /** * A specific state for a 2x2 contingency table. * NA denotes an invalid state that should not be reachable by the code. * EMPTY denotes that no conclusion could be drawn from the data. */ enum ContingencyState { TP, FP, TN, FN, NA, EMPTY } /** * A minute class to store the truth and call state respectively. */ static class TruthAndCallStates implements Comparable<TruthAndCallStates>{ public final TruthState truthState; public final CallState callState; public TruthAndCallStates(final TruthState truthState, final CallState callState) { this.truthState = truthState; this.callState = callState; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; return compareTo((TruthAndCallStates) o) == 0; } @Override public int hashCode() { int result = truthState.hashCode(); result = 31 * result + callState.hashCode(); return result; } @Override public int compareTo(final TruthAndCallStates that) { int result = this.truthState.compareTo(that.truthState); if (result == 0) result = this.callState.compareTo(that.callState); return result; } } }