#define CALL_ETA 0.03f
#define CALL_MAX 256
#define CALL_DEFTHETA 0.83f
+#define DEF_MAPQ 20
#define CAP_DIST 25
bca->capQ = 60;
bca->openQ = 40; bca->extQ = 20; bca->tandemQ = 100;
bca->min_baseQ = min_baseQ;
- bca->last_mnp_pos = -100;
bca->e = errmod_init(1. - theta);
+ bca->min_frac = 0.002;
+ bca->min_support = 1;
return bca;
}
errmod_destroy(bca->e);
free(bca->bases); free(bca->inscns); free(bca);
}
-/* Compute genotype likelihood by combining likelihood of each
- * read. ref_base is the 4-bit representation of the reference base. It
- * is negative if we are looking at an indel or an MNP. Indel and MNP
- * are indistinguishable in this function. */
+/* ref_base is the 4-bit representation of the reference base. It is
+ * negative if we are looking at an indel. */
int bcf_call_glfgen(int _n, const bam_pileup1_t *pl, int ref_base, bcf_callaux_t *bca, bcf_callret1_t *r)
{
+ static int *var_pos = NULL, nvar_pos = 0;
int i, n, ref4, is_indel, ori_depth = 0;
memset(r, 0, sizeof(bcf_callret1_t));
if (ref_base >= 0) {
}
// fill the bases array
memset(r, 0, sizeof(bcf_callret1_t));
- for (i = n = 0; i < _n; ++i) {
+ for (i = n = r->n_supp = 0; i < _n; ++i) {
const bam_pileup1_t *p = pl + i;
int q, b, mapQ, baseQ, is_diff, min_dist, seqQ;
// set base
seqQ = is_indel? (p->aux>>8&0xff) : 99;
if (q < bca->min_baseQ) continue;
if (q > seqQ) q = seqQ;
- mapQ = p->b->core.qual < bca->capQ? p->b->core.qual : bca->capQ;
+ mapQ = p->b->core.qual < 255? p->b->core.qual : DEF_MAPQ; // special case for mapQ==255
+ mapQ = mapQ < bca->capQ? mapQ : bca->capQ;
if (q > mapQ) q = mapQ;
if (q > 63) q = 63;
if (q < 4) q = 4;
b = p->aux>>16&0x3f;
is_diff = (b != 0);
}
+ if (is_diff) ++r->n_supp;
bca->bases[n++] = q<<5 | (int)bam1_strand(p->b)<<4 | b;
// collect annotations
- r->qsum[b] += q;
+ if (b < 4) r->qsum[b] += q;
++r->anno[0<<2|is_diff<<1|bam1_strand(p->b)];
min_dist = p->b->core.l_qseq - 1 - p->qpos;
if (min_dist > p->qpos) min_dist = p->qpos;
r->depth = n; r->ori_depth = ori_depth;
// glfgen
errmod_cal(bca->e, n, 5, bca->bases, r->p);
+
+ // Calculate the Variant Distance Bias (make it optional?)
+ if ( nvar_pos < _n ) {
+ nvar_pos = _n;
+ var_pos = realloc(var_pos,sizeof(int)*nvar_pos);
+ }
+ int alt_dp=0, read_len=0;
+ for (i=0; i<_n; i++) {
+ const bam_pileup1_t *p = pl + i;
+ if ( bam1_seqi(bam1_seq(p->b),p->qpos) == ref_base )
+ continue;
+
+ var_pos[alt_dp] = p->qpos;
+ if ( (bam1_cigar(p->b)[0]&BAM_CIGAR_MASK)==4 )
+ var_pos[alt_dp] -= bam1_cigar(p->b)[0]>>BAM_CIGAR_SHIFT;
+
+ alt_dp++;
+ read_len += p->b->core.l_qseq;
+ }
+ float mvd=0;
+ int j;
+ n=0;
+ for (i=0; i<alt_dp; i++) {
+ for (j=0; j<i; j++) {
+ mvd += abs(var_pos[i] - var_pos[j]);
+ n++;
+ }
+ }
+ r->mvd[0] = n ? mvd/n : 0;
+ r->mvd[1] = alt_dp;
+ r->mvd[2] = alt_dp ? read_len/alt_dp : 0;
+
return r->depth;
}
-/* Combine individual calls. ref_base is a 4-bit A/C/G/T for a SNP, or
- * B2B_REF_MNP, or B2B_REF_INDEL. Indel and MNP are indistinguishable in
- * this function. */
+
+
+void calc_vdb(int n, const bcf_callret1_t *calls, bcf_call_t *call)
+{
+ // Variant distance bias. Samples merged by means of DP-weighted average.
+
+ float weight=0, tot_prob=0;
+
+ int i;
+ for (i=0; i<n; i++)
+ {
+ int mvd = calls[i].mvd[0];
+ int dp = calls[i].mvd[1];
+ int read_len = calls[i].mvd[2];
+
+ if ( dp<2 ) continue;
+
+ float prob = 0;
+ if ( dp==2 )
+ {
+ // Exact formula
+ prob = (mvd==0) ? 1.0/read_len : (read_len-mvd)*2.0/read_len/read_len;
+ }
+ else if ( dp==3 )
+ {
+ // Sin, quite accurate approximation
+ float mu = read_len/2.9;
+ prob = mvd>2*mu ? 0 : sin(mvd*3.14/2/mu) / (4*mu/3.14);
+ }
+ else
+ {
+ // Scaled gaussian curve, crude approximation, but behaves well. Using fixed depth for bigger depths.
+ if ( dp>5 )
+ dp = 5;
+ float sigma2 = (read_len/1.9/(dp+1)) * (read_len/1.9/(dp+1));
+ float norm = 1.125*sqrt(2*3.14*sigma2);
+ float mu = read_len/2.9;
+ if ( mvd < mu )
+ prob = exp(-(mvd-mu)*(mvd-mu)/2/sigma2)/norm;
+ else
+ prob = exp(-(mvd-mu)*(mvd-mu)/3.125/sigma2)/norm;
+ }
+
+ //fprintf(stderr,"dp=%d mvd=%d read_len=%d -> prob=%f\n", dp,mvd,read_len,prob);
+ tot_prob += prob*dp;
+ weight += dp;
+ }
+ tot_prob = weight ? tot_prob/weight : 1;
+ //fprintf(stderr,"prob=%f\n", tot_prob);
+ call->vdb = tot_prob;
+}
+
int bcf_call_combine(int n, const bcf_callret1_t *calls, int ref_base /*4-bit*/, bcf_call_t *call)
{
int ref4, i, j, qsum[4];
if (ref_base >= 0) {
call->ori_ref = ref4 = bam_nt16_nt4_table[ref_base];
if (ref4 > 4) ref4 = 4;
- } else call->ori_ref = ref_base, ref4 = 0; // ref_base < 0
+ } else call->ori_ref = -1, ref4 = 0;
// calculate qsum
memset(qsum, 0, 4 * sizeof(int));
for (i = 0; i < n; ++i)
if (((ref4 < 4 && j < 4) || (ref4 == 4 && j < 5)) && i >= 0)
call->unseen = j, call->a[j++] = qsum[i]&3;
call->n_alleles = j;
- } else { // for indels and MNPs
+ } else {
call->n_alleles = j;
if (call->n_alleles == 1) return -1; // no reliable supporting read. stop doing anything
}
x = call->n_alleles * (call->n_alleles + 1) / 2;
// get the possible genotypes
for (i = z = 0; i < call->n_alleles; ++i)
- for (j = i; j < call->n_alleles; ++j)
- g[z++] = call->a[i] * 5 + call->a[j];
+ for (j = 0; j <= i; ++j)
+ g[z++] = call->a[j] * 5 + call->a[i];
for (i = 0; i < n; ++i) {
uint8_t *PL = call->PL + x * i;
const bcf_callret1_t *r = calls + i;
call->ori_depth += calls[i].ori_depth;
for (j = 0; j < 16; ++j) call->anno[j] += calls[i].anno[j];
}
+
+ calc_vdb(n, calls, call);
+
return 0;
}
-/* Fill a bcf1_t record. The type of the record (SNP, MNP or INDEL) is
- * determined by bca->ori_ref. */
-int bcf_call2bcf(int tid, int pos, bcf_call_t *bc, bcf1_t *b, bcf_callret1_t *bcr, int is_SP,
+
+int bcf_call2bcf(int tid, int pos, bcf_call_t *bc, bcf1_t *b, bcf_callret1_t *bcr, int fmt_flag,
const bcf_callaux_t *bca, const char *ref)
{
extern double kt_fisher_exact(int n11, int n12, int n21, int n22, double *_left, double *_right, double *two);
b->tid = tid; b->pos = pos; b->qual = 0;
s.s = b->str; s.m = b->m_str; s.l = 0;
kputc('\0', &s);
- if (bc->ori_ref == B2B_REF_INDEL) { // an indel
+ if (bc->ori_ref < 0) { // an indel
// write REF
kputc(ref[pos], &s);
for (j = 0; j < bca->indelreg; ++j) kputc(ref[pos+1+j], &s);
}
}
kputc('\0', &s);
- } else if (bc->ori_ref == B2B_REF_MNP) {
- for (j = 0; j < bca->indelreg; ++j) kputc(ref[pos+1+j], &s);
- kputc('\0', &s);
- for (i = 1; i < 4; ++i) {
- if (bc->a[i] < 0) break;
- if (i > 1) kputc(',', &s);
- for (j = 0; j < bca->indelreg; ++j)
- kputc("ACGT"[bca->indel_types[i]>>2*i&3], &s);
- }
- kputc('\0', &s);
} else { // a SNP
kputc("ACGTN"[bc->ori_ref], &s); kputc('\0', &s);
for (i = 1; i < 5; ++i) {
}
kputc('\0', &s);
// INFO
- if (bc->ori_ref == B2B_REF_INDEL) kputs("INDEL;", &s);
- else if (bc->ori_ref == B2B_REF_MNP) kputs("MNP;", &s);
+ if (bc->ori_ref < 0) kputs("INDEL;", &s);
kputs("DP=", &s); kputw(bc->ori_depth, &s); kputs(";I16=", &s);
for (i = 0; i < 16; ++i) {
if (i) kputc(',', &s);
kputw(bc->anno[i], &s);
}
+ if (bc->vdb != 1)
+ ksprintf(&s, ";VDB=%.4f", bc->vdb);
kputc('\0', &s);
// FMT
kputs("PL", &s);
- if (bcr) {
- kputs(":DP", &s);
- if (is_SP) kputs(":SP", &s);
+ if (bcr && fmt_flag) {
+ if (fmt_flag & B2B_FMT_DP) kputs(":DP", &s);
+ if (fmt_flag & B2B_FMT_DV) kputs(":DV", &s);
+ if (fmt_flag & B2B_FMT_SP) kputs(":SP", &s);
}
kputc('\0', &s);
b->m_str = s.m; b->str = s.s; b->l_str = s.l;
bcf_sync(b);
memcpy(b->gi[0].data, bc->PL, b->gi[0].len * bc->n);
- if (bcr) {
- uint16_t *dp = (uint16_t*)b->gi[1].data;
- uint8_t *sp = is_SP? b->gi[2].data : 0;
+ if (bcr && fmt_flag) {
+ uint16_t *dp = (fmt_flag & B2B_FMT_DP)? b->gi[1].data : 0;
+ uint16_t *dv = (fmt_flag & B2B_FMT_DV)? b->gi[1 + ((fmt_flag & B2B_FMT_DP) != 0)].data : 0;
+ int32_t *sp = (fmt_flag & B2B_FMT_SP)? b->gi[1 + ((fmt_flag & B2B_FMT_DP) != 0) + ((fmt_flag & B2B_FMT_DV) != 0)].data : 0;
for (i = 0; i < bc->n; ++i) {
bcf_callret1_t *p = bcr + i;
- dp[i] = p->depth < 0xffff? p->depth : 0xffff;
- if (is_SP) {
+ if (dp) dp[i] = p->depth < 0xffff? p->depth : 0xffff;
+ if (dv) dv[i] = p->n_supp < 0xffff? p->n_supp : 0xffff;
+ if (sp) {
if (p->anno[0] + p->anno[1] < 2 || p->anno[2] + p->anno[3] < 2
|| p->anno[0] + p->anno[2] < 2 || p->anno[1] + p->anno[3] < 2)
{