/******************************************************************************* * Copyright 2013 EMBL-EBI * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package net.sf.cram.mask; import java.util.Arrays; public class RefMaskUtils { public static final byte[] bases = new byte[] { 'A', 'C', 'G', 'T' }; public static final byte[] base2index = new byte[256]; static { Arrays.fill(base2index, (byte) -1); base2index['A'] = 0; base2index['a'] = 0; base2index['C'] = 1; base2index['c'] = 1; base2index['G'] = 2; base2index['g'] = 2; base2index['T'] = 3; base2index['t'] = 3; } public static int minHits = 2; public static final int getBaseCount(byte mask, byte base) { return 3 & (mask >>> (2 * base2index[base])); } public static final byte addReadBase(byte mask, byte readBase, byte refBase) { byte baseMask = 0; switch (readBase) { case 'A': case 'a': // 00000011 baseMask = 3; break; case 'C': case 'c': // 00001100 baseMask = 12; break; case 'G': case 'g': // 00110000 baseMask = 48; break; case 'T': case 't': // 11000000 baseMask = ~63; break; default: // throw new IllegalArgumentException("Unkown base: " + readBase); return mask; } // byte count = (byte) ((baseMask & mask) >>> (2 * base2index[readBase]) // & 3); int count = getBaseCount(mask, readBase); if (count < 3) { count++; mask &= ~baseMask; mask |= count << (2 * base2index[readBase]); } return mask; } public static final boolean shouldStore(byte mask, byte refBase) { for (byte base : bases) { if (base == refBase) continue; if (getBaseCount(mask, base) >= minHits) return true; } return false; } public static final int getBaseCount(short mask, byte base) { return 15 & (mask >>> (4 * base2index[base])); } public static final short addReadBase(short mask, byte readBase, byte refBase) { short baseMask = 0; switch (readBase) { case 'A': case 'a': // 00000000 00001111 baseMask = 15; break; case 'C': case 'c': // 00000000 11110000 baseMask = 240; break; case 'G': case 'g': // 00001111 00000000 baseMask = 3840; break; case 'T': case 't': // 11110000 00000000 baseMask = ~4095; break; default: // throw new IllegalArgumentException("Unkown base: " + readBase); return mask; } int count = getBaseCount(mask, readBase); if (count < 15) { count++; mask &= ~baseMask; mask |= count << (4 * base2index[readBase]); } return mask; } private static final int minCoverageEstimate(short mask) { int coverage = 15 & mask; coverage += 15 & (mask >>> 4); coverage += 15 & (mask >>> 8); coverage += 15 & (mask >>> 12); return coverage; } public static final boolean shouldStore(short mask, byte refBase) { if (minCoverageEstimate(mask) > 10) return false; int[] counts = new int[3]; int i = 0; for (byte base : bases) { if (base == refBase) continue; counts[i] = getBaseCount(mask, base); if (counts[i] >= minHits) return true; i++; } // Arrays.sort(counts); // int depth = minCoverageEstimate(mask); // if (depth > 10 && ((float) counts[1] + counts[2]) / counts[0] > 0.3) // return true; return false; } public static class RefMask { private short[] mask; private int minHits; public RefMask(int len, int minHits) { super(); this.mask = new short[len]; Arrays.fill(mask, (short) 0); this.minHits = minHits; } public void addReadBase(int pos, byte readBase, byte refBase) { mask[pos] = RefMaskUtils.addReadBase(mask[pos], readBase, refBase); } public boolean shouldStore(int pos, byte refBase) { short maskAtPos = mask[pos]; if (maskAtPos == 0) return false; if (minCoverageEstimate(maskAtPos) > 10) return false; int[] counts = new int[3]; int i = 0; for (byte base : bases) { if (base == refBase) continue; counts[i] = getBaseCount(maskAtPos, base); if (counts[i] >= minHits) return true; i++; } return false; } public int getMinHits() { return minHits; } public void setMinHits(int minHits) { this.minHits = minHits; } } }