Skip to content

Commit

Permalink
Alter Frequency to be able to represent both percentage frequency val…
Browse files Browse the repository at this point in the history
…ues and fractional frequencies i.e. AF = AC/AN with a hom count.

Alter FrequencyData to work with Frequency for representing AF, AC, AN and HOM counts
Alter FrequencyData 'get' prefixed methods to remove the 'get' e.g. getMaxFreqForPopulation() is now maxFreqForPopulation(), getScore() -> frequencyScore(), frequencyData.getKnownFrequencies() -> frequencyData.frequencies()
  • Loading branch information
julesjacobsen committed Feb 13, 2024
1 parent 6b8027f commit 12731b5
Show file tree
Hide file tree
Showing 18 changed files with 317 additions and 229 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ private List<VariantEvaluation> getCompatibleVariantsUnderFrequencyThreshold(Lis
// float maxFreq = frequencyData.maxFreqIgnoring(Set.of(LOCAL, ESP))
// float maxFreq = frequencyData.maxFreqFrom(Set.of(LOCAL, ESP))
FrequencyData frequencyData = variantEvaluation.getFrequencyData();
if (frequencyData.getMaxFreq() <= maxFreqForMode || variantEvaluation.isWhiteListed()) {
if (frequencyData.maxFreq() <= maxFreqForMode || variantEvaluation.isWhiteListed()) {
compatibleVariants.add(variantEvaluation);
} else {
logger.debug("FAIL variant freq {} >= {} (maxFreq for MOI) {}", frequencyData.getMaxFreq(), maxFreqForMode, variantEvaluation);
logger.debug("FAIL variant freq {} >= {} (maxFreq for MOI) {}", frequencyData.maxFreq(), maxFreqForMode, variantEvaluation);
}
}
return compatibleVariants;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public AcmgEvidence assignVariantAcmgEvidence(VariantEvaluation variantEvaluatio
// AlleleProto.AlleleKey alleleKey = AlleleProtoAdaptor.toAlleleKey(variantEvaluation);
AlleleProto.AlleleKey alleleKey = variantEvaluation.alleleKey();
boolean isBa1ExcludedVariant = variantEvaluation.getGenomeAssembly() == GenomeAssembly.HG19 ? HG19_BA1_EXCLUSION_VARIANTS.contains(alleleKey) : HG38_BA1_EXCLUSION_VARIANTS.contains(alleleKey);
if (!isBa1ExcludedVariant && frequencyData.getMaxFreqForPopulation(FrequencySource.NON_FOUNDER_POPS) >= 5.0) {
if (!isBa1ExcludedVariant && frequencyData.maxFreqForPopulation(FrequencySource.NON_FOUNDER_POPS) >= 5.0) {
acmgEvidenceBuilder.add(BA1);
// BA1 is supposed to be used as a filtering criterion where no other evidence need be considered.
return acmgEvidenceBuilder.build();
Expand Down Expand Up @@ -436,7 +436,7 @@ private void assignPM2(AcmgEvidence.Builder acmgEvidenceBuilder, FrequencyData f
// allow local frequency occurrences as these are unverifiable as to their size or content. Also do not use isRepresentedInDatabase()
// as this will exclude anything with an rsID which could be a ClinVar variant not seen in any population database.
boolean absentFromDatabase = frequencyData.isEmpty() || (frequencyData.size() == 1 && frequencyData.containsFrequencySource(FrequencySource.LOCAL));
boolean atVeryLowFrequencyIfRecessive = modeOfInheritance.isRecessive() && frequencyData.getMaxFreqForPopulation(FrequencySource.NON_FOUNDER_POPS) < 0.01f;
boolean atVeryLowFrequencyIfRecessive = modeOfInheritance.isRecessive() && frequencyData.maxFreqForPopulation(FrequencySource.NON_FOUNDER_POPS) < 0.01f;
if (absentFromDatabase || atVeryLowFrequencyIfRecessive) {
acmgEvidenceBuilder.add(PM2, Evidence.SUPPORTING);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private FrequencyData mapToFrequencyData(List<SvResult> topMatches) {
}
SvResult first = topMatches.get(0);
Frequency frequency = toFrequency(first);
if (first.an < 10 || frequency.getFrequency() == 0) {
if (first.an < 10 || frequency.frequency() == 0) {
// Don't report poorly defined frequencies
return FrequencyData.of(first.id());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,15 @@ private static void parseFrequencyData(FrequencyData.Builder frequencyDataBuilde
for (int i = 0; i < freqsCount; i++) {
AlleleProto.Frequency frequency = alleleProperties.getFrequencies(i);
var freqSource = toFreqSource(frequency.getFrequencySource());
var freq = Frequency.percentageFrequency(frequency.getAc(), frequency.getAn());
var hom = frequency.getHom();
frequencyDataBuilder.addFrequency(freqSource, freq, hom);
int an = frequency.getAn();
if (an == 0) {
float af = frequency.getFrequency();
frequencyDataBuilder.addFrequency(freqSource, af);
} else {
int ac = frequency.getAc();
int hom = frequency.getHom();
frequencyDataBuilder.addFrequency(freqSource, ac, an, hom);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ public float getVariantScore() {
* @return a score between 0 and 1
*/
public float getFrequencyScore() {
return whiteListed ? 1f : frequencyData.getScore();
return whiteListed ? 1f : frequencyData.frequencyScore();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,62 +36,93 @@ public class Frequency {

private final FrequencySource source;
private final float value;
private final int ac;
private final int an;
private final int homs;

public static Frequency of(FrequencySource source, float value) {
return new Frequency(source, value);
return new Frequency(source, value, 0, 0, 0);
}

private Frequency(FrequencySource source, float value) {
public static Frequency of(FrequencySource source, int ac, int an, int homs) {
if (an <= 0 || ac > an || homs > ac) {
throw new IllegalArgumentException(source + " AN must be > 0, AC must be < AN and HOM must be < AC. Got AC=" + ac + ", AN=" + an + ", hom=" + homs);
}
return new Frequency(source, percentageFrequency(ac, an), ac, an, homs);
}

// package private to work with FrequencyData *ONLY* where allele frequency has already been calculated and input
// values have already been validated
static Frequency of(FrequencySource source, float af, int ac, int an, int homs) {
return new Frequency(source, af, ac, an, homs);
}

private Frequency(FrequencySource source, float value, int ac, int an, int homs) {
this.source = source;
this.value = value;
this.ac = ac;
this.an = an;
this.homs = homs;
}

public FrequencySource source() {
return source;
}

public float getFrequency() {
public float frequency() {
return value;
}

public FrequencySource getSource() {
return source;
public int ac() {
return ac;
}

public int an() {
return an;
}

public int homs() {
return homs;
}

public boolean isOverThreshold(float threshold) {
return value > threshold;
}

/**
* Returns the frequency of ac/an as a percentage value.
* Returns the frequency of ac/an as a percentage frequency.
*
* @param ac Allele Count - the number of observed alleles.
* @param an Allele Number - size of the population in which the AC was observed.
* @return the frequency of ac/an as a percentage value in the range 0..100
* @return the frequency of ac/an as a percentage frequency in the range 0..100
*/
public static float percentageFrequency(int ac, int an) {
return 100f * (ac / (float) an);
}


@Override
public int hashCode() {
return Objects.hash(source, value);
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Frequency frequency = (Frequency) o;
return Float.compare(value, frequency.value) == 0 && ac == frequency.ac && an == frequency.an && homs == frequency.homs && source == frequency.source;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Frequency)) {
return false;
}
Frequency other = (Frequency) o;
if (source != other.source) {
return false;
}
return Float.compare(other.value, value) == 0;
public int hashCode() {
return Objects.hash(source, value, ac, an, homs);
}


@Override
public String toString() {
return "Frequency{" + source + "=" + value + '}';
return "Frequency{" + source +
'=' + value + (an > 0 ? formatAcAn() : "") +
'}';
}

private String formatAcAn() {
return "(" + ac + '|' + an + '|' + homs + ')';
}
}
Loading

0 comments on commit 12731b5

Please sign in to comment.