diff --git a/NEWS b/NEWS index a989d597a..1df3a90eb 100644 --- a/NEWS +++ b/NEWS @@ -33,6 +33,20 @@ information carried in the missing and half-missing genotypes (e.g. ".", "./." or "./1") +* bcftools concat: + + - new `--ligate-force` and `--ligate-warn` options for finer control + of `-l, --ligate` behavior in imperfect overlaps. The new default is + to throw an error when sites present in one chunk but absent in the + other are encountered. To drop such sites and proceed, use the new + `--ligate-warn` option (previously this was the default). To keep such + sites, use the new `--ligate-force` option (#1567). + +* bcftools +contrast: + + - support for chunking within map/reduce framework allowing to collect + NASSOC counts even for empty case/control sample sets (#1566) + * bcftools csq: - bug fix, compound indels were not recognised in some cases (#1536) diff --git a/doc/bcftools.txt b/doc/bcftools.txt index c0bfc07dc..889f0b69c 100644 --- a/doc/bcftools.txt +++ b/doc/bcftools.txt @@ -787,7 +787,13 @@ are concatenated without being recompressed, which is very fast.. *-l, --ligate*:: Ligate phased VCFs by matching phase at overlapping haplotypes. Note that the option is intended for VCFs with perfect overlap, sites - in overlapping regions present in one but missing in other are dropped. + in overlapping regions present in one but missing in the other are dropped. + +*--ligate-force*:: + Keep all sites and ligate even non-overlapping chunks and chunks with imperfect overlap + +*--ligate-warn*:: + Drop sites in imperfect overlaps *--no-version*:: see *<>* diff --git a/test/concat.5.1.out b/test/concat.5.1.out new file mode 100644 index 000000000..8afafe46d --- /dev/null +++ b/test/concat.5.1.out @@ -0,0 +1,10 @@ +##fileformat=VCFv4.2 +##FILTER= +##contig= +##FORMAT= +##FORMAT= +##FORMAT= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE +chr1 1 . A C . . . GT:PS 0|1:1 +chr1 3 . G T . . . GT:PS 0|1:1 +chr1 4 . T A . . . GT:PS 1|0:1 diff --git a/test/concat.5.2.out b/test/concat.5.2.out new file mode 100644 index 000000000..4020e5368 --- /dev/null +++ b/test/concat.5.2.out @@ -0,0 +1,11 @@ +##fileformat=VCFv4.2 +##FILTER= +##contig= +##FORMAT= +##FORMAT= +##FORMAT= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE +chr1 1 . A C . . . GT:PS 0|1:1 +chr1 2 . C G . . . GT:PS 1|0:1 +chr1 3 . G T . . . GT:PQ:PS 0|1:99:1 +chr1 4 . T A . . . GT:PS 1|0:1 diff --git a/test/concat.5.a.vcf b/test/concat.5.a.vcf new file mode 100644 index 000000000..21bf29cab --- /dev/null +++ b/test/concat.5.a.vcf @@ -0,0 +1,5 @@ +##fileformat=VCFv4.2 +##contig= +##FORMAT= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE +chr1 1 . A C . . . GT 0|1 diff --git a/test/concat.5.b.vcf b/test/concat.5.b.vcf new file mode 100644 index 000000000..96fdf0a11 --- /dev/null +++ b/test/concat.5.b.vcf @@ -0,0 +1,6 @@ +##fileformat=VCFv4.2 +##contig= +##FORMAT= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE +chr1 2 . C G . . . GT 1|0 +chr1 3 . G T . . . GT 0|1 diff --git a/test/concat.5.c.vcf b/test/concat.5.c.vcf new file mode 100644 index 000000000..b3380bf65 --- /dev/null +++ b/test/concat.5.c.vcf @@ -0,0 +1,6 @@ +##fileformat=VCFv4.2 +##contig= +##FORMAT= +#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT SAMPLE +chr1 3 . G T . . . GT 1|0 +chr1 4 . T A . . . GT 0|1 diff --git a/test/test.pl b/test/test.pl index be3e87181..87e4fd292 100755 --- a/test/test.pl +++ b/test/test.pl @@ -601,11 +601,14 @@ test_vcf_concat($opts,in=>['concat.2.a','concat.2.b'],out=>'concat.2.bcf.out',do_bcf=>1,args=>'-a'); test_vcf_concat($opts,in=>['concat.2.a','concat.2.b'],out=>'concat.4.vcf.out',do_bcf=>0,args=>'-aD'); test_vcf_concat($opts,in=>['concat.2.a','concat.2.b'],out=>'concat.4.bcf.out',do_bcf=>1,args=>'-aD'); -test_vcf_concat($opts,in=>['concat.3.a','concat.3.b','concat.3.0','concat.3.c','concat.3.d','concat.3.e','concat.3.f'],out=>'concat.3.vcf.out',do_bcf=>0,args=>'-l'); -test_vcf_concat($opts,in=>['concat.3.a','concat.3.b','concat.3.0','concat.3.c','concat.3.d','concat.3.e','concat.3.f'],out=>'concat.3.bcf.out',do_bcf=>1,args=>'-l'); +test_vcf_concat($opts,in=>['concat.3.a','concat.3.b','concat.3.0','concat.3.c','concat.3.d','concat.3.e','concat.3.f'],out=>'concat.3.vcf.out',do_bcf=>0,args=>'-l --ligate-warn'); +test_vcf_concat($opts,in=>['concat.3.a','concat.3.b','concat.3.0','concat.3.c','concat.3.d','concat.3.e','concat.3.f'],out=>'concat.3.bcf.out',do_bcf=>1,args=>'-l --ligate-warn'); test_naive_concat($opts,name=>'naive_concat',max_hdr_lines=>10000,max_body_lines=>10000,nfiles=>10); test_vcf_concat($opts,in=>['concat.4.a','concat.4.b'],out=>'concat.5.out',do_bcf=>0,args=>'-l'); test_vcf_concat($opts,in=>['concat.4.a','concat.4.b'],out=>'concat.5.out',do_bcf=>1,args=>'-l'); +test_vcf_concat($opts,in=>['concat.5.a','concat.5.b','concat.5.c'],out=>'concat.5.1.out',do_bcf=>0,args=>'-l --ligate-warn'); +test_vcf_concat($opts,in=>['concat.5.a','concat.5.b','concat.5.c'],out=>'concat.5.1.out',do_bcf=>1,args=>'-l --ligate-warn'); +test_vcf_concat($opts,in=>['concat.5.a','concat.5.b','concat.5.c'],out=>'concat.5.2.out',do_bcf=>1,args=>'-l --ligate-force'); test_vcf_reheader($opts,in=>'reheader',out=>'reheader.1.out',header=>'reheader.hdr'); test_vcf_reheader($opts,in=>'reheader',out=>'reheader.2.out',samples=>'reheader.samples'); test_vcf_reheader($opts,in=>'reheader',out=>'reheader.2.out',samples=>'reheader.samples2'); diff --git a/vcfconcat.c b/vcfconcat.c index 2fbfd2a6b..1dac01d0f 100644 --- a/vcfconcat.c +++ b/vcfconcat.c @@ -51,13 +51,14 @@ typedef struct _args_t int *start_pos, start_tid, ifname; int *swap_phase, nswap, *nmatch, *nmism; bcf1_t **buf; + uint8_t *buf_mask; int nbuf, mbuf, prev_chr, min_PQ, prev_pos_check; int32_t *GTa, *GTb, mGTa, mGTb, *phase_qual, *phase_set; char **argv, *output_fname, *file_list, **fnames, *remove_dups, *regions_list; int argc, nfnames, allow_overlaps, phased_concat, regions_is_file; int compact_PS, phase_set_changed, naive_concat, naive_concat_trust_headers; - int verbose, explicit_output_type; + int verbose, explicit_output_type, ligate_force, ligate_warn; htsThreadPool *tpool; } args_t; @@ -213,6 +214,7 @@ static void destroy_data(args_t *args) free(args->swap_phase); for (i=0; imbuf; i++) bcf_destroy(args->buf[i]); free(args->buf); + free(args->buf_mask); free(args->GTa); free(args->GTb); free(args->nmatch); @@ -251,9 +253,10 @@ static void phased_flush(args_t *args) int i, j, nsmpl = bcf_hdr_nsamples(args->out_hdr); static int gt_absent_warned = 0; - for (i=0; inbuf; i+=2) { + if ( args->buf_mask[i/2]!=3 ) continue; + bcf1_t *arec = args->buf[i]; bcf1_t *brec = args->buf[i+1]; @@ -300,19 +303,23 @@ static void phased_flush(args_t *args) } for (i=0; inbuf/2; i+=2) { - bcf1_t *arec = args->buf[i]; - bcf_translate(args->out_hdr, args->files->readers[0].header, arec); - if ( args->nswap ) - phase_update(args, args->out_hdr, arec); + bcf1_t *rec; + bcf_hdr_t *hdr; + int mask = args->buf_mask[i/2]; + if ( mask & 1 ) { rec = args->buf[i]; hdr = args->files->readers[0].header; } + else { rec = args->buf[i+1]; hdr = args->files->readers[1].header; } + bcf_translate(args->out_hdr, hdr, rec); + if ( args->nswap && (mask&1) ) + phase_update(args, args->out_hdr, rec); if ( !args->compact_PS || args->phase_set_changed ) { - bcf_update_format_int32(args->out_hdr,arec,"PS",args->phase_set,nsmpl); + bcf_update_format_int32(args->out_hdr,rec,"PS",args->phase_set,nsmpl); args->phase_set_changed = 0; } - if ( bcf_write(args->out_fh, args->out_hdr, arec)!=0 ) error("[%s] Error: cannot write to %s\n", __func__,args->output_fname); + if ( bcf_write(args->out_fh, args->out_hdr, rec)!=0 ) error("[%s] Error: cannot write to %s\n", __func__,args->output_fname); - if ( arec->pos < args->prev_pos_check ) error("FIXME, disorder: %s:%"PRId64" vs %d [1]\n", bcf_seqname(args->files->readers[0].header,arec),(int64_t) arec->pos+1,args->prev_pos_check+1); - args->prev_pos_check = arec->pos; + if ( rec->pos < args->prev_pos_check ) error("FIXME, disorder: %s:%"PRId64" vs %d [1]\n", bcf_seqname(hdr,rec),(int64_t)rec->pos+1,args->prev_pos_check+1); + args->prev_pos_check = rec->pos; } args->nswap = 0; for (j=0; jnbuf; i+=2) { - bcf1_t *brec = args->buf[i+1]; - bcf_translate(args->out_hdr, args->files->readers[1].header, brec); - if ( !PQ_printed ) + bcf1_t *rec; + bcf_hdr_t *hdr; + int mask = args->buf_mask[i/2]; + if ( mask & 2 ) { rec = args->buf[i+1]; hdr = args->files->readers[1].header; } + else { rec = args->buf[i]; hdr = args->files->readers[0].header; } + bcf_translate(args->out_hdr, hdr, rec); + if ( !PQ_printed && mask==3 ) { - bcf_update_format_int32(args->out_hdr,brec,"PQ",args->phase_qual,nsmpl); + bcf_update_format_int32(args->out_hdr,rec,"PQ",args->phase_qual,nsmpl); PQ_printed = 1; for (j=0; jphase_qual[j] < args->min_PQ ) { - args->phase_set[j] = brec->pos+1; + args->phase_set[j] = rec->pos+1; args->phase_set_changed = 1; } else if ( args->compact_PS ) args->phase_set[j] = bcf_int32_missing; } if ( args->nswap ) - phase_update(args, args->out_hdr, brec); + phase_update(args, args->out_hdr, rec); if ( !args->compact_PS || args->phase_set_changed ) { - bcf_update_format_int32(args->out_hdr,brec,"PS",args->phase_set,nsmpl); + bcf_update_format_int32(args->out_hdr,rec,"PS",args->phase_set,nsmpl); args->phase_set_changed = 0; } - if ( bcf_write(args->out_fh, args->out_hdr, brec)!=0 ) error("[%s] Error: cannot write to %s\n", __func__,args->output_fname); + if ( bcf_write(args->out_fh, args->out_hdr, rec)!=0 ) error("[%s] Error: cannot write to %s\n", __func__,args->output_fname); - if ( brec->pos < args->prev_pos_check ) error("FIXME, disorder: %s:%"PRId64" vs %d [2]\n", bcf_seqname(args->files->readers[1].header,brec),(int64_t) brec->pos+1,args->prev_pos_check+1); - args->prev_pos_check = brec->pos; + if ( rec->pos < args->prev_pos_check ) error("FIXME, disorder: %s:%"PRId64" vs %d [2]\n", bcf_seqname(hdr,rec),(int64_t)rec->pos+1,args->prev_pos_check+1); + args->prev_pos_check = rec->pos; } args->nbuf = 0; } -static void phased_push(args_t *args, bcf1_t *arec, bcf1_t *brec) +static void phased_push(args_t *args, bcf1_t *arec, bcf1_t *brec, int is_overlap) { + bcf_hdr_t *ahdr = arec ? bcf_sr_get_header(args->files,0) : NULL; + bcf_hdr_t *bhdr = brec ? bcf_sr_get_header(args->files,1) : NULL; + if ( arec && arec->errcode ) - error("Parse error at %s:%"PRId64", cannot proceed: %s\n", bcf_seqname(args->files->readers[0].header,arec),(int64_t) arec->pos+1, args->files->readers[0].fname); + error("Parse error at %s:%"PRId64", cannot proceed: %s\n", bcf_seqname(ahdr,arec),(int64_t) arec->pos+1, args->files->readers[0].fname); if ( brec && brec->errcode ) - error("Parse error at %s:%"PRId64", cannot proceed: %s\n", bcf_seqname(args->files->readers[1].header,brec),(int64_t) brec->pos+1, args->files->readers[1].fname); + error("Parse error at %s:%"PRId64", cannot proceed: %s\n", bcf_seqname(bhdr,brec),(int64_t) brec->pos+1, args->files->readers[1].fname); int i, nsmpl = bcf_hdr_nsamples(args->out_hdr); - int chr_id = bcf_hdr_name2id(args->out_hdr, bcf_seqname(args->files->readers[0].header,arec)); + int chr_id = arec ? bcf_hdr_name2id(args->out_hdr,bcf_seqname(ahdr,arec)) : bcf_hdr_name2id(args->out_hdr,bcf_seqname(bhdr,brec)); if ( args->prev_chr<0 || args->prev_chr!=chr_id ) { if ( args->prev_chr>=0 ) phased_flush(args); for (i=0; iphase_set[i] = arec->pos+1; + args->phase_set[i] = arec ? arec->pos+1 : brec->pos+1; args->phase_set_changed = 1; - if ( args->seen_seq[chr_id] ) error("The chromosome block %s is not contiguous\n", bcf_seqname(args->files->readers[0].header,arec)); + if ( args->seen_seq[chr_id] ) error("The chromosome block %s is not contiguous\n", arec ? bcf_seqname(ahdr,arec) : bcf_seqname(bhdr,brec)); args->seen_seq[chr_id] = 1; args->prev_chr = chr_id; args->prev_pos_check = -1; } - if ( !brec ) + if ( !is_overlap ) { - bcf_translate(args->out_hdr, args->files->readers[0].header, arec); + assert(arec); + + bcf_translate(args->out_hdr, ahdr, arec); if ( args->nswap ) phase_update(args, args->out_hdr, arec); if ( !args->compact_PS || args->phase_set_changed ) @@ -403,7 +419,7 @@ static void phased_push(args_t *args, bcf1_t *arec, bcf1_t *brec) if ( bcf_write(args->out_fh, args->out_hdr, arec)!=0 ) error("[%s] Error: cannot write to %s\n", __func__,args->output_fname); if ( arec->pos < args->prev_pos_check ) - error("FIXME, disorder: %s:%"PRId64" in %s vs %d written [3]\n", bcf_seqname(args->files->readers[0].header,arec), (int64_t) arec->pos+1,args->files->readers[0].fname, args->prev_pos_check+1); + error("FIXME, disorder: %s:%"PRId64" in %s vs %d written [3]\n", bcf_seqname(ahdr,arec), (int64_t) arec->pos+1,args->files->readers[0].fname, args->prev_pos_check+1); args->prev_pos_check = arec->pos; return; } @@ -411,11 +427,21 @@ static void phased_push(args_t *args, bcf1_t *arec, bcf1_t *brec) int m = args->mbuf; args->nbuf += 2; hts_expand(bcf1_t*,args->nbuf,args->mbuf,args->buf); + if ( m < args->mbuf ) args->buf_mask = (uint8_t*)realloc(args->buf_mask,sizeof(*args->buf_mask)*args->mbuf); for (i=m; imbuf; i++) args->buf[i] = bcf_init1(); - SWAP(bcf1_t*, args->files->readers[0].buffer[0], args->buf[args->nbuf-2]); - SWAP(bcf1_t*, args->files->readers[1].buffer[0], args->buf[args->nbuf-1]); + if ( arec ) SWAP(bcf1_t*, args->files->readers[0].buffer[0], args->buf[args->nbuf-2]); + if ( brec ) SWAP(bcf1_t*, args->files->readers[1].buffer[0], args->buf[args->nbuf-1]); + args->buf_mask[args->nbuf/2-1] = (arec?1:0) | (brec?2:0); +} + +static int _get_active_index(bcf_srs_t *sr) +{ + int i; + for (i=0; inreaders; i++) + if ( bcf_sr_has_line(sr,i) ) return i; + return -1; } static void concat(args_t *args) @@ -451,37 +477,47 @@ static void concat(args_t *args) else if ( new_file ) bcf_sr_seek(args->files,NULL,0); // set to start - int nret; + int nret, ir; while ( (nret = bcf_sr_next_line(args->files)) ) { + int is_overlap = args->files->nreaders==1 ? 0 : 1; if ( !bcf_sr_has_line(args->files,0) ) // no input from the first reader { // We are assuming that there is a perfect overlap, sites which are not present in both files are dropped - if ( ! bcf_sr_region_done(args->files,0) ) + if ( bcf_sr_region_done(args->files,0) ) + { + phased_flush(args); + bcf_sr_remove_reader(args->files, 0); + is_overlap = 0; + } + else if ( args->ligate_warn ) { if ( !site_drop_warned ) { + ir = _get_active_index(args->files); fprintf(stderr, "Warning: Dropping the site %s:%"PRId64". The --ligate option is intended for VCFs with perfect\n" " overlap, sites in overlapping regions present in one but missing in other are dropped.\n" " This warning is printed only once.\n", - bcf_seqname(bcf_sr_get_header(args->files,1),bcf_sr_get_line(args->files,1)), (int64_t) bcf_sr_get_line(args->files,1)->pos+1 - ); + bcf_seqname(bcf_sr_get_header(args->files,ir),bcf_sr_get_line(args->files,ir)), (int64_t) bcf_sr_get_line(args->files,ir)->pos+1); site_drop_warned = 1; } continue; } - phased_flush(args); - bcf_sr_remove_reader(args->files, 0); + else if ( !args->ligate_force ) + { + ir = _get_active_index(args->files); + error("Error: The --ligate option is intended for VCFs with perfect overlap, the site %s:%"PRId64" breaks the assumption\n", + bcf_seqname(bcf_sr_get_header(args->files,ir),bcf_sr_get_line(args->files,ir)), (int64_t) bcf_sr_get_line(args->files,ir)->pos+1); + } } // Get a line to learn about current position - for (i=0; ifiles->nreaders; i++) - if ( bcf_sr_has_line(args->files,i) ) break; - bcf1_t *line = bcf_sr_get_line(args->files,i); + ir = _get_active_index(args->files); + bcf1_t *line = bcf_sr_get_line(args->files,ir); // This can happen after bcf_sr_seek: indel may start before the coordinate which we seek to. - if ( seek_chr>=0 && seek_pos>line->pos && seek_chr==bcf_hdr_name2id(args->out_hdr, bcf_seqname(args->files->readers[i].header,line)) ) continue; + if ( seek_chr>=0 && seek_pos>line->pos && seek_chr==bcf_hdr_name2id(args->out_hdr, bcf_seqname(args->files->readers[ir].header,line)) ) continue; seek_pos = seek_chr = -1; // Check if the position overlaps with the next, yet unopened, reader @@ -494,29 +530,37 @@ static void concat(args_t *args) } if ( must_seek ) { - bcf_sr_seek(args->files, bcf_seqname(args->files->readers[i].header,line), line->pos); + bcf_sr_seek(args->files, bcf_seqname(args->files->readers[ir].header,line), line->pos); seek_pos = line->pos; - seek_chr = bcf_hdr_name2id(args->out_hdr, bcf_seqname(args->files->readers[i].header,line)); + seek_chr = bcf_hdr_name2id(args->out_hdr, bcf_seqname(args->files->readers[ir].header,line)); continue; } // We are assuming that there is a perfect overlap, sites which are not present in both files are dropped - if ( args->files->nreaders>1 && !bcf_sr_has_line(args->files,1) && !bcf_sr_region_done(args->files,1) ) + if ( args->files->nreaders>1 && !bcf_sr_has_line(args->files,1) && !bcf_sr_region_done(args->files,1) && !args->ligate_force ) { - if ( !site_drop_warned ) + if ( args->ligate_warn && !site_drop_warned ) { + ir = _get_active_index(args->files); fprintf(stderr, "Warning: Dropping the site %s:%"PRId64". The --ligate option is intended for VCFs with perfect\n" " overlap, sites in overlapping regions present in one but missing in other are dropped.\n" " This warning is printed only once.\n", - bcf_seqname(bcf_sr_get_header(args->files,0),line), (int64_t) line->pos+1 - ); + bcf_seqname(bcf_sr_get_header(args->files,ir),line), (int64_t) line->pos+1); site_drop_warned = 1; } + else if ( !args->ligate_warn ) + { + ir = _get_active_index(args->files); + error("Error: The --ligate option is intended for VCFs with perfect overlap, the site %s:%"PRId64" breaks the assumption\n", + bcf_seqname(bcf_sr_get_header(args->files,ir),bcf_sr_get_line(args->files,ir)), (int64_t) bcf_sr_get_line(args->files,ir)->pos+1); + } continue; } - phased_push(args, bcf_sr_get_line(args->files,0), args->files->nreaders>1 ? bcf_sr_get_line(args->files,1) : NULL); + bcf1_t *line0 = bcf_sr_get_line(args->files,0); + bcf1_t *line1 = args->files->nreaders > 1 ? bcf_sr_get_line(args->files,1) : NULL; + phased_push(args, line0, line1, is_overlap); } if ( args->files->nreaders ) @@ -876,6 +920,8 @@ static void usage(args_t *args) fprintf(stderr, " -D, --remove-duplicates Alias for -d exact\n"); fprintf(stderr, " -f, --file-list Read the list of files from a file.\n"); fprintf(stderr, " -l, --ligate Ligate phased VCFs by matching phase at overlapping haplotypes\n"); + fprintf(stderr, " --ligate-force Ligate even non-overlapping chunks, keep all sites\n"); + fprintf(stderr, " --ligate-warn Drop sites in imperfect overlaps\n"); fprintf(stderr, " --no-version Do not append version and command line to the header\n"); fprintf(stderr, " -n, --naive Concatenate files without recompression, a header check compatibility is performed\n"); fprintf(stderr, " --naive-force Same as --naive, but header compatibility is not checked. Dangerous, use with caution.\n"); @@ -914,6 +960,8 @@ int main_vcfconcat(int argc, char *argv[]) {"rm-dups",required_argument,NULL,'d'}, {"allow-overlaps",no_argument,NULL,'a'}, {"ligate",no_argument,NULL,'l'}, + {"ligate-force",no_argument,NULL,10}, + {"ligate-warn",no_argument,NULL,11}, {"output",required_argument,NULL,'o'}, {"output-type",required_argument,NULL,'O'}, {"threads",required_argument,NULL,9}, @@ -950,6 +998,8 @@ int main_vcfconcat(int argc, char *argv[]) default: error("The output type \"%s\" not recognised\n", optarg); }; break; + case 10 : args->ligate_force = 1; break; + case 11 : args->ligate_warn = 1; break; case 9 : args->n_threads = strtol(optarg, 0, 0); break; case 8 : args->record_cmd_line = 0; break; case 7 : args->naive_concat = 1; args->naive_concat_trust_headers = 1; break; @@ -969,6 +1019,7 @@ int main_vcfconcat(int argc, char *argv[]) args->fnames[args->nfnames-1] = strdup(argv[optind]); optind++; } + if ( args->ligate_force && args->ligate_warn ) error("The options cannot be combined: --ligate-force and --ligate-warn\n"); if ( args->allow_overlaps && args->phased_concat ) error("The options -a and -l should not be combined. Please run with -l only.\n"); if ( args->compact_PS && !args->phased_concat ) error("The -c option is intended only with -l\n"); if ( args->file_list )