]> git.donarmstrong.com Git - samtools.git/blobdiff - bcftools/call1.c
Fixed the VCF header to pass validation
[samtools.git] / bcftools / call1.c
index 5e4fc9fbc267928260c678ef3ce62f942fcebc7b..2308607ab6d9de176570282f32a4797a275b6f7c 100644 (file)
@@ -26,7 +26,7 @@ KSTREAM_INIT(gzFile, gzread, 16384)
 #define VC_CALL_GT 2048
 #define VC_ADJLD   4096
 #define VC_NO_INDEL 8192
-#define VC_FOLDED 16384
+#define VC_ANNO_MAX 16384
 
 typedef struct {
        int flag, prior_type, n1;
@@ -129,7 +129,7 @@ static int test16(bcf1_t *b, anno16_t *a)
        if ((p = strstr(b->info, "I16=")) == 0) return -1;
        p += 4;
        for (i = 0; i < 16; ++i) {
-               anno[i] = strtol(p, &p, 10);
+               errno = 0; anno[i] = strtol(p, &p, 10);
                if (anno[i] == 0 && (errno == EINVAL || errno == ERANGE)) return -2;
                ++p;
        }
@@ -151,7 +151,7 @@ static int update_bcf1(int n_smpl, bcf1_t *b, const bcf_p1aux_t *pa, const bcf_p
 {
        kstring_t s;
        int is_var = (pr->p_ref < pref);
-       double p_hwe, r = is_var? pr->p_ref : 1. - pr->p_ref;
+       double p_hwe, r = is_var? pr->p_ref : pr->p_var, fq;
        anno16_t a;
 
        p_hwe = pr->g[0] >= 0.? test_hwe(pr->g) : 1.0; // only do HWE g[] is calculated
@@ -164,20 +164,24 @@ static int update_bcf1(int n_smpl, bcf1_t *b, const bcf_p1aux_t *pa, const bcf_p
        kputs(b->info, &s);
        if (b->info[0]) kputc(';', &s);
 //     ksprintf(&s, "AF1=%.4lg;AFE=%.4lg;CI95=%.4lg,%.4lg", 1.-pr->f_em, 1.-pr->f_exp, pr->cil, pr->cih);
-       ksprintf(&s, "AF1=%.4lg;CI95=%.4lg,%.4lg", 1.-pr->f_em, pr->cil, pr->cih);
+       ksprintf(&s, "AF1=%.4g;CI95=%.4g,%.4g", 1.-pr->f_em, pr->cil, pr->cih);
        ksprintf(&s, ";DP4=%d,%d,%d,%d;MQ=%d", a.d[0], a.d[1], a.d[2], a.d[3], a.mq);
+       fq = pr->p_ref_folded < 0.5? -4.343 * log(pr->p_ref_folded) : 4.343 * log(pr->p_var_folded);
+       if (fq < -999) fq = -999;
+       if (fq > 999) fq = 999;
+       ksprintf(&s, ";FQ=%.3g", fq);
        if (a.is_tested) {
-               if (pr->pc[0] >= 0.) ksprintf(&s, ";PC4=%lg,%lg,%lg,%lg", pr->pc[0], pr->pc[1], pr->pc[2], pr->pc[3]);
-               ksprintf(&s, ";PV4=%.2lg,%.2lg,%.2lg,%.2lg", a.p[0], a.p[1], a.p[2], a.p[3]);
+               if (pr->pc[0] >= 0.) ksprintf(&s, ";PC4=%g,%g,%g,%g", pr->pc[0], pr->pc[1], pr->pc[2], pr->pc[3]);
+               ksprintf(&s, ";PV4=%.2g,%.2g,%.2g,%.2g", a.p[0], a.p[1], a.p[2], a.p[3]);
        }
        if (pr->g[0] >= 0. && p_hwe <= .2)
-               ksprintf(&s, ";GC=%.2lf,%.2lf,%.2lf;HWE=%.3lf", pr->g[2], pr->g[1], pr->g[0], p_hwe);
+               ksprintf(&s, ";GC=%.2f,%.2f,%.2f;HWE=%.3f", pr->g[2], pr->g[1], pr->g[0], p_hwe);
        kputc('\0', &s);
        kputs(b->fmt, &s); kputc('\0', &s);
        free(b->str);
        b->m_str = s.m; b->l_str = s.l; b->str = s.s;
-       b->qual = r < 1e-100? 99 : -4.343 * log(r);
-       if (b->qual > 99) b->qual = 99;
+       b->qual = r < 1e-100? 999 : -4.343 * log(r);
+       if (b->qual > 999) b->qual = 999;
        bcf_sync(b);
        if (!is_var) bcf_shrink_alt(b, 1);
        else if (!(flag&VC_KEEPALT))
@@ -197,12 +201,50 @@ static int update_bcf1(int n_smpl, bcf1_t *b, const bcf_p1aux_t *pa, const bcf_p
        return is_var;
 }
 
+static void write_header(bcf_hdr_t *h)
+{
+       kstring_t str;
+       str.l = h->l_txt? h->l_txt - 1 : 0;
+       str.m = str.l + 1; str.s = h->txt;
+       if (!strstr(str.s, "##INFO=<ID=DP,"))
+               kputs("##INFO=<ID=DP,Number=1,Type=Integer,Description=\"Raw read depth\">\n", &str);
+       if (!strstr(str.s, "##INFO=<ID=DP4,"))
+               kputs("##INFO=<ID=DP4,Number=4,Type=Integer,Description=\"# high-quality ref-forward bases, ref-reverse, alt-forward and alt-reverse bases\">\n", &str);
+       if (!strstr(str.s, "##INFO=<ID=MQ,"))
+               kputs("##INFO=<ID=MQ,Number=1,Type=Integer,Description=\"Root-mean-square mapping quality of covering reads\">\n", &str);
+       if (!strstr(str.s, "##INFO=<ID=FQ,"))
+               kputs("##INFO=<ID=FQ,Number=1,Type=Float,Description=\"Phred probability that sample chromosomes are not all the same\">\n", &str);
+       if (!strstr(str.s, "##INFO=<ID=AF1,"))
+               kputs("##INFO=<ID=AF1,Number=1,Type=Float,Description=\"Max-likelihood estimate of the site allele frequency of the first ALT allele\">\n", &str);
+       if (!strstr(str.s, "##INFO=<ID=CI95,"))
+               kputs("##INFO=<ID=CI95,Number=2,Type=Float,Description=\"Equal-tail Bayesian credible interval of the site allele frequency at the 95% level\">\n", &str);
+       if (!strstr(str.s, "##INFO=<ID=PV4,"))
+               kputs("##INFO=<ID=PV4,Number=4,Type=Float,Description=\"P-values for strand bias, baseQ bias, mapQ bias and tail distance bias\">\n", &str);
+    if (!strstr(str.s, "##INFO=<ID=INDEL,"))
+        kputs("##INFO=<ID=INDEL,Number=0,Type=Flag,Descriptin=\"Indicates that the variant is an INDEL.\">\n", &str);
+    if (!strstr(str.s, "##INFO=<ID=GT,"))
+        kputs("##FORMAT=<ID=GT,Number=1,Type=String,Description=\"Genotype\">\n", &str);
+    if (!strstr(str.s, "##FORMAT=<ID=GQ,"))
+        kputs("##FORMAT=<ID=GQ,Number=1,Type=Integer,Description=\"Genotype Quality\">\n", &str);
+    if (!strstr(str.s, "##FORMAT=<ID=GL,"))
+        kputs("##FORMAT=<ID=GL,Number=3,Type=Float,Description=\"Likelihoods for RR,RA,AA genotypes (R=ref,A=alt)\">\n", &str);
+       if (!strstr(str.s, "##FORMAT=<ID=DP,"))
+               kputs("##FORMAT=<ID=DP,Number=1,Type=Integer,Description=\"# high-quality bases\">\n", &str);
+       if (!strstr(str.s, "##FORMAT=<ID=SP,"))
+               kputs("##FORMAT=<ID=SP,Number=1,Type=Integer,Description=\"Phred-scaled strand bias P-value\">\n", &str);
+       if (!strstr(str.s, "##FORMAT=<ID=PL,"))
+               kputs("##FORMAT=<ID=PL,Number=-1,Type=Integer,Description=\"List of Phred-scaled genotype likelihoods, number of values is (#ALT+1)*(#ALT+2)/2\">\n", &str);
+       h->l_txt = str.l + 1; h->txt = str.s;
+}
+
 double bcf_ld_freq(const bcf1_t *b0, const bcf1_t *b1, double f[4]);
 
 int bcfview(int argc, char *argv[])
 {
        extern int bcf_2qcall(bcf_hdr_t *h, bcf1_t *b);
        extern void bcf_p1_indel_prior(bcf_p1aux_t *ma, double x);
+       extern int bcf_fix_gt(bcf1_t *b);
+       extern int bcf_anno_max(bcf1_t *b);
        bcf_t *bp, *bout = 0;
        bcf1_t *b, *blast;
        int c;
@@ -217,9 +259,8 @@ int bcfview(int argc, char *argv[])
        tid = begin = end = -1;
        memset(&vc, 0, sizeof(viewconf_t));
        vc.prior_type = vc.n1 = -1; vc.theta = 1e-3; vc.pref = 0.5; vc.indel_frac = -1.;
-       while ((c = getopt(argc, argv, "fN1:l:cHAGvbSuP:t:p:QgLi:I")) >= 0) {
+       while ((c = getopt(argc, argv, "N1:l:cHAGvbSuP:t:p:QgLi:IM")) >= 0) {
                switch (c) {
-               case 'f': vc.flag |= VC_FOLDED; break;
                case '1': vc.n1 = atoi(optarg); break;
                case 'l': vc.fn_list = strdup(optarg); break;
                case 'N': vc.flag |= VC_ACGT_ONLY; break;
@@ -233,6 +274,7 @@ int bcfview(int argc, char *argv[])
                case 'H': vc.flag |= VC_HWE; break;
                case 'g': vc.flag |= VC_CALL_GT | VC_CALL; break;
                case 'I': vc.flag |= VC_NO_INDEL; break;
+               case 'M': vc.flag |= VC_ANNO_MAX; break;
                case 't': vc.theta = atof(optarg); break;
                case 'p': vc.pref = atof(optarg); break;
                case 'i': vc.indel_frac = atof(optarg); break;
@@ -262,12 +304,11 @@ int bcfview(int argc, char *argv[])
                fprintf(stderr, "         -Q        output the QCALL likelihood format\n");
                fprintf(stderr, "         -L        calculate LD for adjacent sites\n");
                fprintf(stderr, "         -I        skip indels\n");
-               fprintf(stderr, "         -f        reference-free variant calling\n");
                fprintf(stderr, "         -1 INT    number of group-1 samples [0]\n");
                fprintf(stderr, "         -l FILE   list of sites to output [all sites]\n");
-               fprintf(stderr, "         -t FLOAT  scaled substitution mutation rate [%.4lg]\n", vc.theta);
-               fprintf(stderr, "         -i FLOAT  indel-to-substitution ratio [%.4lg]\n", vc.indel_frac);
-               fprintf(stderr, "         -p FLOAT  variant if P(ref|D)<FLOAT [%.3lg]\n", vc.pref);
+               fprintf(stderr, "         -t FLOAT  scaled substitution mutation rate [%.4g]\n", vc.theta);
+               fprintf(stderr, "         -i FLOAT  indel-to-substitution ratio [%.4g]\n", vc.indel_frac);
+               fprintf(stderr, "         -p FLOAT  variant if P(ref|D)<FLOAT [%.3g]\n", vc.pref);
                fprintf(stderr, "         -P STR    type of prior: full, cond2, flat [full]\n");
                fprintf(stderr, "\n");
                return 1;
@@ -283,7 +324,10 @@ int bcfview(int argc, char *argv[])
        bp = vcf_open(argv[optind], moder);
        h = vcf_hdr_read(bp);
        bout = vcf_open("-", modew);
-       if (!(vc.flag & VC_QCALL)) vcf_hdr_write(bout, h);
+       if (!(vc.flag & VC_QCALL)) {
+               if (vc.flag & VC_CALL) write_header(h);
+               vcf_hdr_write(bout, h);
+       }
        if (vc.flag & VC_CALL) {
                p1 = bcf_p1_init(h->n_smpl);
                if (vc.prior_file) {
@@ -297,7 +341,6 @@ int bcfview(int argc, char *argv[])
                        bcf_p1_init_subprior(p1, vc.prior_type, vc.theta);
                }
                if (vc.indel_frac > 0.) bcf_p1_indel_prior(p1, vc.indel_frac); // otherwise use the default indel_frac
-               if (vc.flag & VC_FOLDED) bcf_p1_set_folded(p1);
        }
        if (vc.fn_list) hash = bcf_load_pos(vc.fn_list, h);
        if (optind + 1 < argc && !(vc.flag&VC_VCFIN)) {
@@ -362,16 +405,18 @@ int bcfview(int argc, char *argv[])
                                kstring_t s;
                                s.m = s.l = 0; s.s = 0;
                                if (*b->info) kputc(';', &s);
-                               ksprintf(&s, "NEIR=%.3lf;NEIF=%.3lf,%.3lf", r2, f[0]+f[2], f[0]+f[1]);
+                               ksprintf(&s, "NEIR=%.3f;NEIF=%.3f,%.3f", r2, f[0]+f[2], f[0]+f[1]);
                                bcf_append_info(b, s.s, s.l);
                                free(s.s);
                        }
                        bcf_cpy(blast, b);
                }
+               if (vc.flag & VC_ANNO_MAX) bcf_anno_max(b);
                if (vc.flag & VC_NO_GENO) { // do not output GENO fields
                        b->n_gi = 0;
                        b->fmt[0] = '\0';
-               }
+                       b->l_str = b->fmt - b->str + 1;
+               } else bcf_fix_gt(b);
                vcf_write(bout, h, b);
        }
        if (vc.prior_file) free(vc.prior_file);