<commit_before>/*  junctions_annotator.cc -- class methods for `junctions annotate`

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.  */

#include <getopt.h>
#include <stdexcept>
#include <string>
#include "common.h"
#include "junctions_annotator.h"
#include "faidx.h"

using namespace std;

//Return stream to write output to
void JunctionsAnnotator::close_ofstream() {
    if(ofs_.is_open())
        ofs_.close();
}

//Return stream to write output to
//If output file is not empty, attempt to open
//If output file is empty, set to cout
void JunctionsAnnotator::set_ofstream_object(ofstream &out) {
    if(output_file_ == "NA") {
        copy_stream(cout, out);
        return;
    }
    ofs_.open(output_file_.c_str());
    if(!ofs_.is_open())
        throw runtime_error("Unable to open " +
                            output_file_);
    copy_stream(ofs_, out);
}

//Open junctions file
void JunctionsAnnotator::open_junctions() {
    junctions_.Open();
}

//Open junctions file
void JunctionsAnnotator::close_junctions() {
    junctions_.Close();
}

//Adjust the start and end of the junction
void JunctionsAnnotator::adjust_junction_ends(BED & line) {
    //Adjust the start and end with block sizes
    //The junction start is thick_start + block_size1
    //The junction end is thick_end - block_size2 + 1
    if(!line.fields.size() || line.fields[10].empty()) {
        stringstream position;
        position << line.chrom << ":" << line.start;
        throw runtime_error("Block sizes not found. Invalid line. " +
                            position.str());
    }
    string blocksize_field = line.fields[10];
    vector<int> block_sizes;
    Tokenize(blocksize_field, block_sizes, ',');
    line.start += block_sizes[0];
    line.end -= block_sizes[1] - 1;
}

//Get a single line from the junctions file
bool JunctionsAnnotator::get_single_junction(BED & line) {
    junctions_._status = BED_INVALID;
    if(junctions_.GetNextBed(line) && junctions_._status == BED_VALID) {
        adjust_junction_ends(line);
        return true;
    } else {
        return false;
    }
}

//Get the splice_site bases
bool JunctionsAnnotator::get_splice_site(AnnotatedJunction & line) {
    string position1 = line.chrom + ":" +
                      num_to_str(line.start + 1) + "-" + num_to_str(line.start + 2);
    string position2 = line.chrom + ":" +
                      num_to_str(line.end - 2) + "-" + num_to_str(line.end - 1);
    string seq1, seq2;
    try {
        seq1 = get_reference_sequence(position1);
        seq2 = get_reference_sequence(position2);
    } catch (const runtime_error& e) {
        throw e;
    }
    if(line.strand == "-") {
        seq1 = rev_comp(seq1);
        seq2 = rev_comp(seq2);
        line.splice_site = seq2 + "-" + seq1;
    } else {
        line.splice_site = seq1 + "-" + seq2;
    }
    return true;
}

//Extract gtf info
bool JunctionsAnnotator::read_gtf() {
    gtf_.create_transcript_map();
    gtf_.construct_junctions();
    gtf_.sort_exons_within_transcripts();
    gtf_.annotate_transcript_with_bins();
    //gtf_.print_transcripts();
    return true;
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if either the acceptor or the donor is known
bool JunctionsAnnotator::overlap_ps(const vector<BED>& exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].start > junction.end &&
            exons[exons.size() - 1].end < junction.start)
        return false;
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].start > junction.end) {
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //known junction
        if(exons[i].end == junction.start &&
                exons[i + 1].start == junction.end) {
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            if(!junction_start) {
                if(exons[i].end >= junction.start) {
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].end == junction.start) {
                    junction.known_donor = true;
                }
                //TODO - check for last exon
                if(exons[i].start == junction.end) {
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return (junction.anchor != "N");
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if either the acceptor or the donor is known
bool JunctionsAnnotator::overlap_ns(const vector<BED> & exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].end < junction.start ||
            exons[exons.size() - 1].start > junction.end) {
        return known_junction;
    }
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].end < junction.start) {
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //Check if this is a known junction
        if(exons[i].start == junction.end &&
                exons[i + 1].end == junction.start) {
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            if(!junction_start) {
                if(exons[i].start <= junction.end) {
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].start == junction.end) {
                    junction.known_donor = true;
                }
                if(exons[i].end == junction.start) {
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return (junction.anchor != "N");
}

//Annotate the anchor i.e is this a known/novel donor-acceptor pair
void JunctionsAnnotator::annotate_anchor(AnnotatedJunction & junction) {
    junction.anchor = string("N");
    if(junction.known_junction) {
        junction.anchor = "DA";
    } else {
        if(junction.known_donor)
            if(junction.known_acceptor)
                junction.anchor = string("NDA");
            else
                junction.anchor = string("D");
        else if(junction.known_acceptor)
            junction.anchor = string("A");
    }
}

//Check for overlap between a transcript and junctions
//Check if the junction we saw is a known junction
//Calculate exons_skipped, donors_skipped, acceptors_skipped
void JunctionsAnnotator::check_for_overlap(string transcript_id, AnnotatedJunction & junction) {
    const vector<BED> & exons =
        gtf_.get_exons_from_transcript(transcript_id);
    if(!exons.size()) {
        cerr << "Unexpected error. No exons for transcript "
             << transcript_id;
        exit(1);
    }
    string transcript_strand = exons[0].strand;
    //Make sure the strands of the junction and transcript match
    if(junction.strand != transcript_strand)
        return;
    //Remember exons are sorted from exon1 to last exon
    if(junction.strand == "+") {
        if(overlap_ps(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else if(junction.strand == "-") {
        if(overlap_ns(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else {
        cerr << "\nUnknown strand " << junction.strand;
        exit(1);
    }
    cerr << "\n\tDonors skipped " << junction.donors_skipped.size();
    cerr << "\n\tExons skipped " << junction.exons_skipped.size();
    cerr << "\n\tAcceptors skipped " << junction.acceptors_skipped.size();
    cerr << "\n\tSplice site " << junction.anchor;
}

//Annotate with gtf
//Takes a single junction BED and annotates with GTF
void JunctionsAnnotator::annotate_junction_with_gtf(AnnotatedJunction & j1) {
    BIN junction_bin = getBin(j1.start, j1.end);
    //From BedTools
    BIN start_bin, end_bin;
    start_bin = (j1.start >> _binFirstShift);
    end_bin = ((j1.end-1) >> _binFirstShift);
    //We loop through each UCSC BIN level for feature A's chrom.
    //For each BIN, we loop through each B feature and add it to
    // hits if it meets all of the user's requests.
    for (BINLEVEL i = 0; i < _binLevels; ++i) {
        BIN offset = _binOffsetsExtended[i];
        for (BIN b = (start_bin + offset); b <= (end_bin + offset); ++b) {
            vector<string> transcripts = gtf_.transcripts_from_bin(j1.chrom, b);
            if(transcripts.size())
                for(std::size_t i = 0; i < transcripts.size(); i++)
                    check_for_overlap(transcripts[i], j1);
        }
        start_bin >>= _binNextShift;
        end_bin >>= _binNextShift;
    }
}

//Get the reference sequence at a particular coordinate
string JunctionsAnnotator::get_reference_sequence(string position) {
    int len;
    faidx_t *fai = fai_load(ref_.c_str());
    char *s = fai_fetch(fai, position.c_str(), &len);
    if(s == NULL)
        throw runtime_error("Unable to extract FASTA sequence "
                             "for position " + position);
    std::string seq(s);
    free(s);
    fai_destroy(fai);
    return seq;
}

//Get the name of the GTF file
string JunctionsAnnotator::gtf_file() {
    return gtf_.gtffile();
}

//Parse the options passed to this tool
int JunctionsAnnotator::parse_options(int argc, char *argv[]) {
    optind = 1; //Reset before parsing again.
    int c;
    while((c = getopt(argc, argv, "Eo:")) != -1) {
        switch(c) {
            case 'E':
                skip_single_exon_genes_ = false;
                break;
            case 'o':
                output_file_ = string(optarg);
                break;
            default:
                usage();
                throw runtime_error("\nError parsing inputs!");
        }
    }
    if(argc - optind >= 3) {
        junctions_.bedFile = string(argv[optind++]);
        ref_ = string(argv[optind++]);
        gtf_.set_gtffile(string(argv[optind++]));
    }
    if(optind < argc ||
       ref_ == "NA" ||
       junctions_.bedFile.empty() ||
       gtf_.gtffile().empty()) {
        usage();
        throw runtime_error("\nError parsing inputs!");
    }
    cerr << "\nReference: " << ref_;
    cerr << "\nGTF: " << gtf_.gtffile();
    cerr << "\nJunctions: " << junctions_.bedFile;
    if(skip_single_exon_genes_)
        cerr << "\nSkip single exon genes.";
    if(!output_file_.empty())
        cerr << "\nOutput file: " << output_file_;
    return 0;
}

//Usage statement for this tool
int JunctionsAnnotator::usage() {
    cout << "\nUsage:\t\t" << "regtools junctions annotate [options] junctions.bed ref.fa annotations.gtf";
    cout << "\nOptions:\t" << "-E include single exon genes";
    cout << "\n\t\t" << "-o Output file";
    cout << "\n";
    return 0;
}
<commit_msg>Switch to exceptions.<commit_after>/*  junctions_annotator.cc -- class methods for `junctions annotate`

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.  */

#include <getopt.h>
#include <stdexcept>
#include <string>
#include "common.h"
#include "junctions_annotator.h"
#include "faidx.h"

using namespace std;

//Return stream to write output to
void JunctionsAnnotator::close_ofstream() {
    if(ofs_.is_open())
        ofs_.close();
}

//Return stream to write output to
//If output file is not empty, attempt to open
//If output file is empty, set to cout
void JunctionsAnnotator::set_ofstream_object(ofstream &out) {
    if(output_file_ == "NA") {
        copy_stream(cout, out);
        return;
    }
    ofs_.open(output_file_.c_str());
    if(!ofs_.is_open())
        throw runtime_error("Unable to open " +
                            output_file_);
    copy_stream(ofs_, out);
}

//Open junctions file
void JunctionsAnnotator::open_junctions() {
    junctions_.Open();
}

//Open junctions file
void JunctionsAnnotator::close_junctions() {
    junctions_.Close();
}

//Adjust the start and end of the junction
void JunctionsAnnotator::adjust_junction_ends(BED & line) {
    //Adjust the start and end with block sizes
    //The junction start is thick_start + block_size1
    //The junction end is thick_end - block_size2 + 1
    if(!line.fields.size() || line.fields[10].empty()) {
        stringstream position;
        position << line.chrom << ":" << line.start;
        throw runtime_error("Block sizes not found. Invalid line. " +
                            position.str());
    }
    string blocksize_field = line.fields[10];
    vector<int> block_sizes;
    Tokenize(blocksize_field, block_sizes, ',');
    line.start += block_sizes[0];
    line.end -= block_sizes[1] - 1;
}

//Get a single line from the junctions file
bool JunctionsAnnotator::get_single_junction(BED & line) {
    junctions_._status = BED_INVALID;
    if(junctions_.GetNextBed(line) && junctions_._status == BED_VALID) {
        adjust_junction_ends(line);
        return true;
    } else {
        return false;
    }
}

//Get the splice_site bases
bool JunctionsAnnotator::get_splice_site(AnnotatedJunction & line) {
    string position1 = line.chrom + ":" +
                      num_to_str(line.start + 1) + "-" + num_to_str(line.start + 2);
    string position2 = line.chrom + ":" +
                      num_to_str(line.end - 2) + "-" + num_to_str(line.end - 1);
    string seq1, seq2;
    try {
        seq1 = get_reference_sequence(position1);
        seq2 = get_reference_sequence(position2);
    } catch (const runtime_error& e) {
        throw e;
    }
    if(line.strand == "-") {
        seq1 = rev_comp(seq1);
        seq2 = rev_comp(seq2);
        line.splice_site = seq2 + "-" + seq1;
    } else {
        line.splice_site = seq1 + "-" + seq2;
    }
    return true;
}

//Extract gtf info
bool JunctionsAnnotator::read_gtf() {
    gtf_.create_transcript_map();
    gtf_.construct_junctions();
    gtf_.sort_exons_within_transcripts();
    gtf_.annotate_transcript_with_bins();
    //gtf_.print_transcripts();
    return true;
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if either the acceptor or the donor is known
bool JunctionsAnnotator::overlap_ps(const vector<BED>& exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].start > junction.end &&
            exons[exons.size() - 1].end < junction.start)
        return false;
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].start > junction.end) {
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //known junction
        if(exons[i].end == junction.start &&
                exons[i + 1].start == junction.end) {
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            if(!junction_start) {
                if(exons[i].end >= junction.start) {
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].end == junction.start) {
                    junction.known_donor = true;
                }
                //TODO - check for last exon
                if(exons[i].start == junction.end) {
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return (junction.anchor != "N");
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if either the acceptor or the donor is known
bool JunctionsAnnotator::overlap_ns(const vector<BED> & exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].end < junction.start ||
            exons[exons.size() - 1].start > junction.end) {
        return known_junction;
    }
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].end < junction.start) {
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //Check if this is a known junction
        if(exons[i].start == junction.end &&
                exons[i + 1].end == junction.start) {
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            if(!junction_start) {
                if(exons[i].start <= junction.end) {
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].start == junction.end) {
                    junction.known_donor = true;
                }
                if(exons[i].end == junction.start) {
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return (junction.anchor != "N");
}

//Annotate the anchor i.e is this a known/novel donor-acceptor pair
void JunctionsAnnotator::annotate_anchor(AnnotatedJunction & junction) {
    junction.anchor = string("N");
    if(junction.known_junction) {
        junction.anchor = "DA";
    } else {
        if(junction.known_donor)
            if(junction.known_acceptor)
                junction.anchor = string("NDA");
            else
                junction.anchor = string("D");
        else if(junction.known_acceptor)
            junction.anchor = string("A");
    }
}

//Check for overlap between a transcript and junctions
//Check if the junction we saw is a known junction
//Calculate exons_skipped, donors_skipped, acceptors_skipped
void JunctionsAnnotator::check_for_overlap(string transcript_id, AnnotatedJunction & junction) {
    const vector<BED> & exons =
        gtf_.get_exons_from_transcript(transcript_id);
    if(!exons.size()) {
        throw runtime_error("Unexpected error. No exons for transcript "
                            + transcript_id);
    }
    string transcript_strand = exons[0].strand;
    //Make sure the strands of the junction and transcript match
    if(junction.strand != transcript_strand)
        return;
    //Remember exons are sorted from exon1 to last exon
    if(junction.strand == "+") {
        if(overlap_ps(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else if(junction.strand == "-") {
        if(overlap_ns(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else {
        throw runtime_error("\nUnknown strand " + junction.strand);
    }
    cerr << "\n\tDonors skipped " << junction.donors_skipped.size();
    cerr << "\n\tExons skipped " << junction.exons_skipped.size();
    cerr << "\n\tAcceptors skipped " << junction.acceptors_skipped.size();
    cerr << "\n\tSplice site " << junction.anchor;
}

//Annotate with gtf
//Takes a single junction BED and annotates with GTF
void JunctionsAnnotator::annotate_junction_with_gtf(AnnotatedJunction & j1) {
    BIN junction_bin = getBin(j1.start, j1.end);
    //From BedTools
    BIN start_bin, end_bin;
    start_bin = (j1.start >> _binFirstShift);
    end_bin = ((j1.end-1) >> _binFirstShift);
    //We loop through each UCSC BIN level for feature A's chrom.
    //For each BIN, we loop through each B feature and add it to
    // hits if it meets all of the user's requests.
    for (BINLEVEL i = 0; i < _binLevels; ++i) {
        BIN offset = _binOffsetsExtended[i];
        for (BIN b = (start_bin + offset); b <= (end_bin + offset); ++b) {
            vector<string> transcripts = gtf_.transcripts_from_bin(j1.chrom, b);
            if(transcripts.size())
                for(std::size_t i = 0; i < transcripts.size(); i++)
                    check_for_overlap(transcripts[i], j1);
        }
        start_bin >>= _binNextShift;
        end_bin >>= _binNextShift;
    }
}

//Get the reference sequence at a particular coordinate
string JunctionsAnnotator::get_reference_sequence(string position) {
    int len;
    faidx_t *fai = fai_load(ref_.c_str());
    char *s = fai_fetch(fai, position.c_str(), &len);
    if(s == NULL)
        throw runtime_error("Unable to extract FASTA sequence "
                             "for position " + position);
    std::string seq(s);
    free(s);
    fai_destroy(fai);
    return seq;
}

//Get the name of the GTF file
string JunctionsAnnotator::gtf_file() {
    return gtf_.gtffile();
}

//Parse the options passed to this tool
int JunctionsAnnotator::parse_options(int argc, char *argv[]) {
    optind = 1; //Reset before parsing again.
    int c;
    while((c = getopt(argc, argv, "Eo:")) != -1) {
        switch(c) {
            case 'E':
                skip_single_exon_genes_ = false;
                break;
            case 'o':
                output_file_ = string(optarg);
                break;
            default:
                usage();
                throw runtime_error("\nError parsing inputs!");
        }
    }
    if(argc - optind >= 3) {
        junctions_.bedFile = string(argv[optind++]);
        ref_ = string(argv[optind++]);
        gtf_.set_gtffile(string(argv[optind++]));
    }
    if(optind < argc ||
       ref_ == "NA" ||
       junctions_.bedFile.empty() ||
       gtf_.gtffile().empty()) {
        usage();
        throw runtime_error("\nError parsing inputs!");
    }
    cerr << "\nReference: " << ref_;
    cerr << "\nGTF: " << gtf_.gtffile();
    cerr << "\nJunctions: " << junctions_.bedFile;
    if(skip_single_exon_genes_)
        cerr << "\nSkip single exon genes.";
    if(!output_file_.empty())
        cerr << "\nOutput file: " << output_file_;
    return 0;
}

//Usage statement for this tool
int JunctionsAnnotator::usage() {
    cout << "\nUsage:\t\t" << "regtools junctions annotate [options] junctions.bed ref.fa annotations.gtf";
    cout << "\nOptions:\t" << "-E include single exon genes";
    cout << "\n\t\t" << "-o Output file";
    cout << "\n";
    return 0;
}
<|endoftext|>


<commit_before>/*  junctions_annotator.cc -- class methods for `junctions annotate`

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.  */

#include <getopt.h>
#include <stdexcept>
#include <string>
#include "common.h"
#include "junctions_annotator.h"
#include "faidx.h"

using namespace std;

//Open junctions file
void JunctionsAnnotator::open_junctions() {
    junctions_.Open();
}

//Open junctions file
void JunctionsAnnotator::close_junctions() {
    junctions_.Close();
}

//Adjust the start and end of the junction
void JunctionsAnnotator::adjust_junction_ends(BED & line) {
    //Adjust the start and end with block sizes
    //The junction start is thick_start + block_size1
    //The junction end is thick_end - block_size2 + 1
    if(!line.fields.size() || line.fields[10].empty()) {
        stringstream position;
        position << line.chrom << ":" << line.start;
        throw runtime_error("Block sizes not found. Invalid line. " +
                            position.str());
    }
    string blocksize_field = line.fields[10];
    vector<int> block_sizes;
    Tokenize(blocksize_field, block_sizes, ',');
    line.start += block_sizes[0];
    line.end -= block_sizes[1] - 1;
}

//Get a single line from the junctions file
bool JunctionsAnnotator::get_single_junction(BED & line) {
    junctions_.GetNextBed(line);
    adjust_junction_ends(line);
    return true;
}

//Get the splice_site bases
bool JunctionsAnnotator::get_splice_site(AnnotatedJunction & line) {
    string position1 = line.chrom + ":" +
                      num_to_str(line.start + 1) + "-" + num_to_str(line.start + 2);
    string position2 = line.chrom + ":" +
                      num_to_str(line.end - 2) + "-" + num_to_str(line.end - 1);
    string seq1, seq2;
    try {
        seq1 = get_reference_sequence(position1);
        seq2 = get_reference_sequence(position2);
    } catch (const runtime_error& e) {
        throw e;
    }
    if(line.strand == "-") {
        seq1 = rev_comp(seq1);
        seq2 = rev_comp(seq2);
        line.splice_site = seq2 + "-" + seq1;
    } else {
        line.splice_site = seq1 + "-" + seq2;
    }
    return true;
}

//Extract gtf info
bool JunctionsAnnotator::read_gtf() {
    gtf_.create_transcript_map();
    gtf_.construct_junctions();
    gtf_.sort_exons_within_transcripts();
    gtf_.annotate_transcript_with_bins();
    //gtf_.print_transcripts();
    return true;
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if this is a known junction in the transcript
bool JunctionsAnnotator::overlap_ps(const vector<BED>& exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].start > junction.end &&
            exons[exons.size() - 1].end < junction.start)
        return false;
    for(std::size_t i = 0; i < exons.size(); i++) {
        cerr << endl << "exon number " << i << "\t" << exons[i].start
             << "\t" << exons[i].end;
        if(exons[i].start > junction.end) {
            cerr << endl << "-1";
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //known junction
        if(exons[i].end == junction.start &&
                exons[i + 1].start == junction.end) {
            cerr << endl << "DA";
            junction.anchor = "DA";
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            cerr << endl << "0";
            if(!junction_start) {
                if(exons[i].end >= junction.start) {
                    junction_start = true;
                    cerr << endl << "1";
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    cerr << endl << "2";
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    cerr << endl << "3";
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    cerr << endl << "4";
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].end == junction.start) {
                    cerr << endl << "5";
                    junction.known_donor = true;
                }
                //TODO - check for last exon
                if(exons[i].start == junction.end) {
                    cerr << endl << "6";
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return known_junction;
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if this is a known junction in the transcript
bool JunctionsAnnotator::overlap_ns(const vector<BED> & exons,
                                          AnnotatedJunction & junction) {
    cerr << endl << "in negative overlap";
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].end < junction.start ||
            exons[exons.size() - 1].start > junction.end) {
        cerr << endl << "transcript outside junction";
        return known_junction;
    }
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].end < junction.start) {
            cerr << endl << "-1";
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //Check if this is a known junction
        if(exons[i].start == junction.end &&
                exons[i + 1].end == junction.start) {
            cerr << endl << "DA";
            junction.anchor = "DA";
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            cerr << endl << "0\t" << i;
            if(!junction_start) {
                if(exons[i].start <= junction.end) {
                    cerr << endl << "1";
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    cerr << endl << "2";
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    cerr << endl << "3";
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    cerr << endl << "4";
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].start == junction.end) {
                    cerr << endl << "5";
                    junction.known_donor = true;
                }
                if(exons[i].end == junction.start) {
                    cerr << endl << "6";
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return known_junction;
}

//Annotate the anchor
void JunctionsAnnotator::annotate_anchor(AnnotatedJunction & junction) {
    //check if known junction
    if(!junction.known_junction) {
        if(junction.known_donor)
            if(junction.known_acceptor)
                junction.anchor = string("NDA");
            else
                junction.anchor = string("D");
        else if(junction.known_acceptor)
            junction.anchor = string("A");
        else
            junction.anchor = string("N");
    }
}

//Check for overlap between a transcript and junctions
//Check if the junction we saw is a known junction
//Calculate exons_skipped, donors_skipped, acceptors_skipped
void JunctionsAnnotator::check_for_overlap(string transcript_id, AnnotatedJunction & junction) {
    cerr << "\nTranscript id: " << transcript_id;
    const vector<BED> & exons =
        gtf_.get_exons_from_transcript(transcript_id);
    if(!exons.size()) {
        cerr << "Unexpected error. No exons for transcript "
             << transcript_id;
        exit(1);
    }
    string transcript_strand = exons[0].strand;
    //Make sure the strands of the junction and transcript match
    if(junction.strand != transcript_strand)
        return;
    //Remember exons are sorted from exon1 to last exon
    if(junction.strand == "+") {
        if(overlap_ps(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else if(junction.strand == "-") {
        if(overlap_ns(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else {
        cerr << "\nUnknown strand " << junction.strand;
        exit(1);
    }
    cerr << "\n\tDonors skipped " << junction.donors_skipped.size();
    cerr << "\n\tExons skipped " << junction.exons_skipped.size();
    cerr << "\n\tAcceptors skipped " << junction.acceptors_skipped.size();
    cerr << "\n\tSplice site " << junction.anchor;
}

//Annotate with gtf
//Takes a single junction BED and annotates with GTF
void JunctionsAnnotator::annotate_junction_with_gtf(AnnotatedJunction & j1) {
    BIN junction_bin = getBin(j1.start, j1.end);
    //From BedTools
    BIN start_bin, end_bin;
    start_bin = (j1.start >> _binFirstShift);
    end_bin = ((j1.end-1) >> _binFirstShift);
    cerr << endl << "junction_bin " << junction_bin;
    //We loop through each UCSC BIN level for feature A's chrom.
    //For each BIN, we loop through each B feature and add it to
    // hits if it meets all of the user's requests.
    for (BINLEVEL i = 0; i < _binLevels; ++i) {
        BIN offset = _binOffsetsExtended[i];
        for (BIN b = (start_bin + offset); b <= (end_bin + offset); ++b) {
            vector<string> transcripts = gtf_.transcripts_from_bin(j1.chrom, b);
            if(transcripts.size())
                for(std::size_t i = 0; i < transcripts.size(); i++)
                    check_for_overlap(transcripts[i], j1);
        }
        start_bin >>= _binNextShift;
        end_bin >>= _binNextShift;
    }
}

//Get the reference sequence at a particular coordinate
string JunctionsAnnotator::get_reference_sequence(string position) {
    int len;
    faidx_t *fai = fai_load(ref_.c_str());
    char *s = fai_fetch(fai, position.c_str(), &len);
    if(s == NULL)
        throw runtime_error("Unable to extract FASTA sequence "
                             "for position " + position);
    std::string seq(s);
    free(s);
    fai_destroy(fai);
    return seq;
}

//Get the name of the GTF file
string JunctionsAnnotator::gtf_file() {
    return gtf_.gtffile();
}

//Parse the options passed to this tool
int JunctionsAnnotator::parse_options(int argc, char *argv[]) {
    static struct option long_options[] = {
        {"ref", required_argument, 0, 'r'},
        {"junctions", required_argument, 0, 'j'},
        {"gtf", required_argument, 0, 'g'},
    };
    int option_index = 0;
    int c = getopt_long(argc, argv, "r:g:j:",
                    long_options, &option_index);
    while(c != -1) {
        switch(c) {
            case 'r':
                ref_ = string(optarg);
                break;
            case 'g':
                gtf_.set_gtffile(string(optarg));
                break;
            case 'j':
                junctions_.bedFile = string(optarg);
                break;
            default:
                usage();
                exit(-1);
        }
        c = getopt_long(argc, argv, "r:g:j:",
                    long_options, &option_index);
    }
    //This could be made an option if need be
    skip_single_exon_genes_ = true;
    if(optind < argc || ref_.empty() || junctions_.bedFile.empty() || gtf_.gtffile().empty()) {
        usage();
        exit(-1);
    }
    cerr << "\nReference: " << ref_;
    cerr << "\nGTF: " << gtf_.gtffile();
    cerr << "\nJunctions: " << junctions_.bedFile;
    return 0;
}

//Usage statement for this tool
int JunctionsAnnotator::usage() {
    cout << "\nUsage:\t\t" << "regtools junctions annotate [options] -r ref.fa -j junctions.bed -g annotations.gtf";
    cout << "\nOptions:\t" << "-r ref.fa\t\tThe reference FASTA file.";
    cout << "\n\t\t" << "-j junctions.bed\tThe junctions to be annotated.";
    cout << "\n\t\t" << "-g annotations.gtf\tThe transcripts that we want to annotate the junctions with.";
    cout << "\n";
    return 0;
}

<commit_msg>Make sure bed entry is valid<commit_after>/*  junctions_annotator.cc -- class methods for `junctions annotate`

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.  */

#include <getopt.h>
#include <stdexcept>
#include <string>
#include "common.h"
#include "junctions_annotator.h"
#include "faidx.h"

using namespace std;

//Open junctions file
void JunctionsAnnotator::open_junctions() {
    junctions_.Open();
}

//Open junctions file
void JunctionsAnnotator::close_junctions() {
    junctions_.Close();
}

//Adjust the start and end of the junction
void JunctionsAnnotator::adjust_junction_ends(BED & line) {
    //Adjust the start and end with block sizes
    //The junction start is thick_start + block_size1
    //The junction end is thick_end - block_size2 + 1
    if(!line.fields.size() || line.fields[10].empty()) {
        stringstream position;
        position << line.chrom << ":" << line.start;
        throw runtime_error("Block sizes not found. Invalid line. " +
                            position.str());
    }
    string blocksize_field = line.fields[10];
    vector<int> block_sizes;
    Tokenize(blocksize_field, block_sizes, ',');
    line.start += block_sizes[0];
    line.end -= block_sizes[1] - 1;
}

//Get a single line from the junctions file
bool JunctionsAnnotator::get_single_junction(BED & line) {
    if(junctions_.GetNextBed(line) && junctions_._status == BED_VALID) {
        adjust_junction_ends(line);
        return true;
    } else {
        return false;
    }
}

//Get the splice_site bases
bool JunctionsAnnotator::get_splice_site(AnnotatedJunction & line) {
    string position1 = line.chrom + ":" +
                      num_to_str(line.start + 1) + "-" + num_to_str(line.start + 2);
    string position2 = line.chrom + ":" +
                      num_to_str(line.end - 2) + "-" + num_to_str(line.end - 1);
    string seq1, seq2;
    try {
        seq1 = get_reference_sequence(position1);
        seq2 = get_reference_sequence(position2);
    } catch (const runtime_error& e) {
        throw e;
    }
    if(line.strand == "-") {
        seq1 = rev_comp(seq1);
        seq2 = rev_comp(seq2);
        line.splice_site = seq2 + "-" + seq1;
    } else {
        line.splice_site = seq1 + "-" + seq2;
    }
    return true;
}

//Extract gtf info
bool JunctionsAnnotator::read_gtf() {
    gtf_.create_transcript_map();
    gtf_.construct_junctions();
    gtf_.sort_exons_within_transcripts();
    gtf_.annotate_transcript_with_bins();
    //gtf_.print_transcripts();
    return true;
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if this is a known junction in the transcript
bool JunctionsAnnotator::overlap_ps(const vector<BED>& exons,
                                          AnnotatedJunction & junction) {
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].start > junction.end &&
            exons[exons.size() - 1].end < junction.start)
        return false;
    for(std::size_t i = 0; i < exons.size(); i++) {
        cerr << endl << "exon number " << i << "\t" << exons[i].start
             << "\t" << exons[i].end;
        if(exons[i].start > junction.end) {
            cerr << endl << "-1";
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //known junction
        if(exons[i].end == junction.start &&
                exons[i + 1].start == junction.end) {
            cerr << endl << "DA";
            junction.anchor = "DA";
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            cerr << endl << "0";
            if(!junction_start) {
                if(exons[i].end >= junction.start) {
                    junction_start = true;
                    cerr << endl << "1";
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    cerr << endl << "2";
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    cerr << endl << "3";
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    cerr << endl << "4";
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].end == junction.start) {
                    cerr << endl << "5";
                    junction.known_donor = true;
                }
                //TODO - check for last exon
                if(exons[i].start == junction.end) {
                    cerr << endl << "6";
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return known_junction;
}

//Find overlap between transcript and junction on the negative strand,
//function returns true if this is a known junction in the transcript
bool JunctionsAnnotator::overlap_ns(const vector<BED> & exons,
                                          AnnotatedJunction & junction) {
    cerr << endl << "in negative overlap";
    //skip single exon genes
    if(skip_single_exon_genes_ && exons.size() == 1) return false;
    bool junction_start = false;
    bool known_junction = false;
    //check if transcript overlaps with junction
    if(exons[0].end < junction.start ||
            exons[exons.size() - 1].start > junction.end) {
        cerr << endl << "transcript outside junction";
        return known_junction;
    }
    for(std::size_t i = 0; i < exons.size(); i++) {
        if(exons[i].end < junction.start) {
            cerr << endl << "-1";
            //No need to look any further
            //the rest of the exons are outside the junction
            break;
        }
        //Check if this is a known junction
        if(exons[i].start == junction.end &&
                exons[i + 1].end == junction.start) {
            cerr << endl << "DA";
            junction.anchor = "DA";
            junction.known_acceptor = true;
            junction.known_donor = true;
            junction.known_junction = true;
            known_junction = true;
        }
        else {
            cerr << endl << "0\t" << i;
            if(!junction_start) {
                if(exons[i].start <= junction.end) {
                    cerr << endl << "1";
                    junction_start = true;
                }
            }
            if(junction_start) {
                if(exons[i].start > junction.start &&
                        exons[i].end < junction.end) {
                    cerr << endl << "2";
                    junction.exons_skipped.insert(exons[i].name);
                }
                if(exons[i].start > junction.start) {
                    cerr << endl << "3";
                    junction.donors_skipped.insert(exons[i].start);
                }
                if(exons[i].end < junction.end) {
                    cerr << endl << "4";
                    junction.acceptors_skipped.insert(exons[i].end);
                }
                if(exons[i].start == junction.end) {
                    cerr << endl << "5";
                    junction.known_donor = true;
                }
                if(exons[i].end == junction.start) {
                    cerr << endl << "6";
                    junction.known_acceptor = true;
                }
            }
        }
    }
    annotate_anchor(junction);
    return known_junction;
}

//Annotate the anchor
void JunctionsAnnotator::annotate_anchor(AnnotatedJunction & junction) {
    //check if known junction
    if(!junction.known_junction) {
        if(junction.known_donor)
            if(junction.known_acceptor)
                junction.anchor = string("NDA");
            else
                junction.anchor = string("D");
        else if(junction.known_acceptor)
            junction.anchor = string("A");
        else
            junction.anchor = string("N");
    }
}

//Check for overlap between a transcript and junctions
//Check if the junction we saw is a known junction
//Calculate exons_skipped, donors_skipped, acceptors_skipped
void JunctionsAnnotator::check_for_overlap(string transcript_id, AnnotatedJunction & junction) {
    cerr << "\nTranscript id: " << transcript_id;
    const vector<BED> & exons =
        gtf_.get_exons_from_transcript(transcript_id);
    if(!exons.size()) {
        cerr << "Unexpected error. No exons for transcript "
             << transcript_id;
        exit(1);
    }
    string transcript_strand = exons[0].strand;
    //Make sure the strands of the junction and transcript match
    if(junction.strand != transcript_strand)
        return;
    //Remember exons are sorted from exon1 to last exon
    if(junction.strand == "+") {
        if(overlap_ps(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else if(junction.strand == "-") {
        if(overlap_ns(exons, junction)) {
            junction.transcripts_overlap.insert(transcript_id);
            junction.genes_overlap.insert(
                    gtf_.get_gene_from_transcript(transcript_id));
        }
    } else {
        cerr << "\nUnknown strand " << junction.strand;
        exit(1);
    }
    cerr << "\n\tDonors skipped " << junction.donors_skipped.size();
    cerr << "\n\tExons skipped " << junction.exons_skipped.size();
    cerr << "\n\tAcceptors skipped " << junction.acceptors_skipped.size();
    cerr << "\n\tSplice site " << junction.anchor;
}

//Annotate with gtf
//Takes a single junction BED and annotates with GTF
void JunctionsAnnotator::annotate_junction_with_gtf(AnnotatedJunction & j1) {
    BIN junction_bin = getBin(j1.start, j1.end);
    //From BedTools
    BIN start_bin, end_bin;
    start_bin = (j1.start >> _binFirstShift);
    end_bin = ((j1.end-1) >> _binFirstShift);
    cerr << endl << "junction_bin " << junction_bin;
    //We loop through each UCSC BIN level for feature A's chrom.
    //For each BIN, we loop through each B feature and add it to
    // hits if it meets all of the user's requests.
    for (BINLEVEL i = 0; i < _binLevels; ++i) {
        BIN offset = _binOffsetsExtended[i];
        for (BIN b = (start_bin + offset); b <= (end_bin + offset); ++b) {
            vector<string> transcripts = gtf_.transcripts_from_bin(j1.chrom, b);
            if(transcripts.size())
                for(std::size_t i = 0; i < transcripts.size(); i++)
                    check_for_overlap(transcripts[i], j1);
        }
        start_bin >>= _binNextShift;
        end_bin >>= _binNextShift;
    }
}

//Get the reference sequence at a particular coordinate
string JunctionsAnnotator::get_reference_sequence(string position) {
    int len;
    faidx_t *fai = fai_load(ref_.c_str());
    char *s = fai_fetch(fai, position.c_str(), &len);
    if(s == NULL)
        throw runtime_error("Unable to extract FASTA sequence "
                             "for position " + position);
    std::string seq(s);
    free(s);
    fai_destroy(fai);
    return seq;
}

//Get the name of the GTF file
string JunctionsAnnotator::gtf_file() {
    return gtf_.gtffile();
}

//Parse the options passed to this tool
int JunctionsAnnotator::parse_options(int argc, char *argv[]) {
    static struct option long_options[] = {
        {"ref", required_argument, 0, 'r'},
        {"junctions", required_argument, 0, 'j'},
        {"gtf", required_argument, 0, 'g'},
    };
    int option_index = 0;
    int c = getopt_long(argc, argv, "r:g:j:",
                    long_options, &option_index);
    while(c != -1) {
        switch(c) {
            case 'r':
                ref_ = string(optarg);
                break;
            case 'g':
                gtf_.set_gtffile(string(optarg));
                break;
            case 'j':
                junctions_.bedFile = string(optarg);
                break;
            default:
                usage();
                exit(-1);
        }
        c = getopt_long(argc, argv, "r:g:j:",
                    long_options, &option_index);
    }
    //This could be made an option if need be
    skip_single_exon_genes_ = true;
    if(optind < argc || ref_.empty() || junctions_.bedFile.empty() || gtf_.gtffile().empty()) {
        usage();
        exit(-1);
    }
    cerr << "\nReference: " << ref_;
    cerr << "\nGTF: " << gtf_.gtffile();
    cerr << "\nJunctions: " << junctions_.bedFile;
    return 0;
}

//Usage statement for this tool
int JunctionsAnnotator::usage() {
    cout << "\nUsage:\t\t" << "regtools junctions annotate [options] -r ref.fa -j junctions.bed -g annotations.gtf";
    cout << "\nOptions:\t" << "-r ref.fa\t\tThe reference FASTA file.";
    cout << "\n\t\t" << "-j junctions.bed\tThe junctions to be annotated.";
    cout << "\n\t\t" << "-g annotations.gtf\tThe transcripts that we want to annotate the junctions with.";
    cout << "\n";
    return 0;
}

<|endoftext|>


<commit_before>/*  junctions_extractor.h -- Declarations for `junctions extract` command

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.  */

#include <algorithm>
#include <getopt.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include "common.h"
#include "junctions_extractor.h"
#include "sam.h"
#include "hts.h"
#include "faidx.h"
#include "kstring.h"

using namespace std;

//Parse the options passed to this tool
int JunctionsExtractor::parse_options(int argc, char *argv[]) {
    optind = 1; //Reset before parsing again.
    int c;
    stringstream help_ss;
    while((c = getopt(argc, argv, "ha:i:I:o:r:")) != -1) {
        switch(c) {
            case 'a':
                min_anchor_length_ = atoi(optarg);
                break;
            case 'i':
                min_intron_length_ = atoi(optarg);
                break;
            case 'I':
                max_intron_length_ = atoi(optarg);
                break;
            case 'o':
                output_file_ = string(optarg);
                break;
            case 'r':
                region_ = string(optarg);
                break;
            case 'h':
                usage(help_ss);
                throw common::cmdline_help_exception(help_ss.str());
            case '?':
            default:
                throw runtime_error("Error parsing inputs!");
        }
    }
    if(argc - optind >= 1) {
        bam_ = string(argv[optind++]);
    }
    if(optind < argc || bam_ == "NA") {
        throw runtime_error("\nError parsing inputs!");
    }
    cerr << endl << "Minimum junction anchor length: " << min_anchor_length_;
    cerr << endl << "Minimum intron length: " << min_intron_length_;
    cerr << endl << "Maximum intron length: " << max_intron_length_;
    cerr << endl << "Alignment: " << bam_;
    cerr << endl << "Output file: " << output_file_;
    cerr << endl;
    return 0;
}

//Usage statement for this tool
int JunctionsExtractor::usage(ostream& out) {
    out << "\nUsage:\t\t" << "regtools junctions extract [options] indexed_alignments.bam";
    out << "\nOptions:";
    out << "\t" << "-a INT\tMinimum anchor length. Junctions which satisfy a minimum "
                     "anchor length on both sides are reported. [8]";
    out << "\n\t\t" << "-i INT\tMinimum intron length. [70]";
    out << "\n\t\t" << "-I INT\tMaximum intron length. [500000]";
    out << "\n\t\t" << "-o FILE\tThe file to write output to. [STDOUT]";
    out << "\n\t\t" << "-r STR\tThe region to identify junctions "
                     "in \"chr:start-end\" format. Entire BAM by default.";
    out << "\n";
    return 0;
}

//Get the BAM filename
string JunctionsExtractor::get_bam() {
    return bam_;
}

//Name the junction based on the number of junctions
// in the map.
string JunctionsExtractor::get_new_junction_name() {
    int index = junctions_.size() + 1;
    stringstream name_ss;
    name_ss << "JUNC" << setfill('0') << setw(8) << index;
    return name_ss.str();
}

//Do some basic qc on the junction
bool JunctionsExtractor::junction_qc(Junction &j1) {
    if(j1.end - j1.start < min_intron_length_ ||
       j1.end - j1.start > max_intron_length_) {
        return false;
    }
    if(j1.start - j1.thick_start >= min_anchor_length_)
        j1.has_left_min_anchor = true;
    if(j1.thick_end - j1.end >= min_anchor_length_)
        j1.has_right_min_anchor = true;
    return true;
}

//Add a junction to the junctions map
//The read_count field is the number of reads supporting the junction.
int JunctionsExtractor::add_junction(Junction j1) {
    //Check junction_qc
    if(!junction_qc(j1)) {
        return 0;
    }

    //Construct key chr:start-end:strand
    stringstream s1;
    string start, end;
    s1 << j1.start; start = s1.str();
    s1 << j1.end; end = s1.str();
    string key = j1.chrom + string(":") + start + "-" + end + ":" + j1.strand;

    //Check if new junction
    if(!junctions_.count(key)) {
        j1.name = get_new_junction_name();
        j1.read_count = 1;
    } else { //existing junction
        Junction j0 = junctions_[key];
        //increment read count
        j1.read_count = j0.read_count + 1;
        //Keep the same name
        j1.name = j0.name;
        //Check if thick starts are any better
        if(j0.thick_start < j1.thick_start)
            j1.thick_start = j0.thick_start;
        if(j0.thick_end > j1.thick_end)
            j1.thick_end = j0.thick_end;
        //preserve min anchor information
        j1.has_left_min_anchor = j1.has_left_min_anchor || j0.has_left_min_anchor;
        j1.has_right_min_anchor = j1.has_right_min_anchor || j0.has_right_min_anchor;
    }
    //Add junction and check anchor while printing.
    junctions_[key] = j1;
    return 0;
}

//Print one junction
void JunctionsExtractor::print_one_junction(const Junction j1, ostream& out) {
    out << j1.chrom <<
        "\t" << j1.thick_start << "\t" << j1.thick_end <<
        "\t" << j1.name << "\t" << j1.read_count << "\t" << j1.strand <<
        "\t" << j1.thick_start << "\t" << j1.thick_end <<
        "\t" << j1.color << "\t" << j1.nblocks <<
        "\t" << j1.start - j1.thick_start << "," << j1.thick_end - j1.end <<
        "\t" << "0," << j1.end - j1.thick_start << endl;
}

//Print all the junctions - this function needs work
vector<Junction> JunctionsExtractor::get_all_junctions() {
    //Sort junctions by position
    if(!junctions_sorted_) {
        create_junctions_vector();
        sort_junctions();
    }
    return junctions_vector_;
}

//Print all the junctions - this function needs work
void JunctionsExtractor::print_all_junctions(ostream& out) {
    ofstream fout;
    if(output_file_ != string("NA")) {
        fout.open(output_file_.c_str());
    }
    //Sort junctions by position
    if(!junctions_sorted_) {
        create_junctions_vector();
        sort_junctions();
    }
    for(vector<Junction> :: iterator it = junctions_vector_.begin();
        it != junctions_vector_.end(); it++) {
        Junction j1 = *it;
        if(j1.has_left_min_anchor && j1.has_right_min_anchor) {
            if(fout.is_open())
                print_one_junction(j1, fout);
            else
                print_one_junction(j1, out);
        }
    }
    if(fout.is_open())
        fout.close();
}

//Get the strand from the XS aux tag
void JunctionsExtractor::set_junction_strand(bam1_t *aln, Junction& j1) {
    uint8_t *p = bam_aux_get(aln, "XS");
    if(p != NULL) {
        char strand = bam_aux2A(p);
        strand ? j1.strand = string(1, strand) : j1.strand = string(1, '?');
    } else {
        j1.strand = string(1, '?');
        return;
    }
}

//Parse junctions from the read and store in junction map
int JunctionsExtractor::parse_alignment_into_junctions(bam_hdr_t *header, bam1_t *aln) {
    int n_cigar = aln->core.n_cigar;
    if (n_cigar <= 1) // max one cigar operation exists(likely all matches)
        return 0;

    int chr_id = aln->core.tid;
    int read_pos = aln->core.pos;
    string chr(header->target_name[chr_id]);
    uint32_t *cigar = bam_get_cigar(aln);

    /*
    //Skip duplicates
    int flag = aln->core.flag;
    if(flag & 1024) {
        cerr << "Skipping read_pos " << read_pos << " flag " << flag << endl;
        return 0;
    }
    */

    Junction j1;
    j1.chrom = chr;
    j1.start = read_pos; //maintain start pos of junction
    j1.thick_start = read_pos;
    set_junction_strand(aln, j1);
    bool started_junction = false;
    for (int i = 0; i < n_cigar; ++i) {
        char op =
               bam_cigar_opchr(cigar[i]);
        int len =
               bam_cigar_oplen(cigar[i]);
        switch(op) {
            case 'N':
                if(!started_junction) {
                    j1.end = j1.start + len;
                    j1.thick_end = j1.end;
                    //Start the first one and remains started
                    started_junction = true;
                } else {
                    //Add the previous junction
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    j1.thick_start = j1.end;
                    j1.start = j1.thick_end;
                    j1.end = j1.start + len;
                    j1.thick_end = j1.end;
                    //For clarity - the next junction is now open
                    started_junction = true;
                }
                break;
            case '=':
            case 'M':
                if(!started_junction)
                    j1.start += len;
                else
                    j1.thick_end += len;
                break;
            //No mismatches allowed in anchor
            case 'D':
            case 'X':
                if(!started_junction) {
                    j1.start += len;
                    j1.thick_start = j1.start;
                } else {
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    //Don't include these in the next anchor
                    j1.start = j1.thick_end + len;
                    j1.thick_start = j1.start;
                }
                started_junction = false;
                break;
            case 'I':
            case 'S':
                if(!started_junction)
                    j1.thick_start = j1.start;
                else {
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    //Don't include these in the next anchor
                    j1.start = j1.thick_end;
                    j1.thick_start = j1.start;
                }
                started_junction = false;
                break;
            case 'H':
                break;
            default:
                cerr << "Unknown cigar " << op;
                break;
        }
    }
    if(started_junction) {
        try {
            add_junction(j1);
        } catch (const std::logic_error& e) {
            cout << e.what() << '\n';
        }
    }
    return 0;
}

//The workhorse - identifies junctions from BAM
int JunctionsExtractor::identify_junctions_from_BAM() {
    if(!bam_.empty()) {
        //open BAM for reading
        samFile *in = sam_open(bam_.c_str(), "r");
        if(in == NULL) {
            throw runtime_error("Unable to open BAM/SAM file.");
        }
        //Load the index
        hts_idx_t *idx = sam_index_load(in, bam_.c_str());
        if(idx == NULL) {
            throw runtime_error("Unable to open BAM/SAM index."
                                " Make sure alignments are indexed");
        }
        //Get the header
        bam_hdr_t *header = sam_hdr_read(in);
        //Initialize iterator
        hts_itr_t *iter = NULL;
        //Move the iterator to the region we are interested in
        iter  = sam_itr_querys(idx, header, region_.c_str());
        if(header == NULL || iter == NULL) {
            sam_close(in);
            throw runtime_error("Unable to iterate to region within BAM.");
        }
        //Initiate the alignment record
        bam1_t *aln = bam_init1();
        while(sam_itr_next(in, iter, aln) >= 0) {
            parse_alignment_into_junctions(header, aln);
        }
        hts_itr_destroy(iter);
        hts_idx_destroy(idx);
        bam_destroy1(aln);
        bam_hdr_destroy(header);
        sam_close(in);
    }
    return 0;
}

//Create the junctions vector from the map
void JunctionsExtractor::create_junctions_vector() {
    for(map<string, Junction> :: iterator it = junctions_.begin();
        it != junctions_.end(); it++) {
        Junction j1 = it->second;
        junctions_vector_.push_back(j1);
    }
}

//Sort all the junctions by their position
void JunctionsExtractor::sort_junctions() {
    sort(junctions_vector_.begin(), junctions_vector_.end(), compare_junctions);
    junctions_sorted_ = true;
}
<commit_msg>Store score column.<commit_after>/*  junctions_extractor.h -- Declarations for `junctions extract` command

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.  */

#include <algorithm>
#include <getopt.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include "common.h"
#include "junctions_extractor.h"
#include "sam.h"
#include "hts.h"
#include "faidx.h"
#include "kstring.h"

using namespace std;

//Parse the options passed to this tool
int JunctionsExtractor::parse_options(int argc, char *argv[]) {
    optind = 1; //Reset before parsing again.
    int c;
    stringstream help_ss;
    while((c = getopt(argc, argv, "ha:i:I:o:r:")) != -1) {
        switch(c) {
            case 'a':
                min_anchor_length_ = atoi(optarg);
                break;
            case 'i':
                min_intron_length_ = atoi(optarg);
                break;
            case 'I':
                max_intron_length_ = atoi(optarg);
                break;
            case 'o':
                output_file_ = string(optarg);
                break;
            case 'r':
                region_ = string(optarg);
                break;
            case 'h':
                usage(help_ss);
                throw common::cmdline_help_exception(help_ss.str());
            case '?':
            default:
                throw runtime_error("Error parsing inputs!");
        }
    }
    if(argc - optind >= 1) {
        bam_ = string(argv[optind++]);
    }
    if(optind < argc || bam_ == "NA") {
        throw runtime_error("\nError parsing inputs!");
    }
    cerr << endl << "Minimum junction anchor length: " << min_anchor_length_;
    cerr << endl << "Minimum intron length: " << min_intron_length_;
    cerr << endl << "Maximum intron length: " << max_intron_length_;
    cerr << endl << "Alignment: " << bam_;
    cerr << endl << "Output file: " << output_file_;
    cerr << endl;
    return 0;
}

//Usage statement for this tool
int JunctionsExtractor::usage(ostream& out) {
    out << "\nUsage:\t\t" << "regtools junctions extract [options] indexed_alignments.bam";
    out << "\nOptions:";
    out << "\t" << "-a INT\tMinimum anchor length. Junctions which satisfy a minimum "
                     "anchor length on both sides are reported. [8]";
    out << "\n\t\t" << "-i INT\tMinimum intron length. [70]";
    out << "\n\t\t" << "-I INT\tMaximum intron length. [500000]";
    out << "\n\t\t" << "-o FILE\tThe file to write output to. [STDOUT]";
    out << "\n\t\t" << "-r STR\tThe region to identify junctions "
                     "in \"chr:start-end\" format. Entire BAM by default.";
    out << "\n";
    return 0;
}

//Get the BAM filename
string JunctionsExtractor::get_bam() {
    return bam_;
}

//Name the junction based on the number of junctions
// in the map.
string JunctionsExtractor::get_new_junction_name() {
    int index = junctions_.size() + 1;
    stringstream name_ss;
    name_ss << "JUNC" << setfill('0') << setw(8) << index;
    return name_ss.str();
}

//Do some basic qc on the junction
bool JunctionsExtractor::junction_qc(Junction &j1) {
    if(j1.end - j1.start < min_intron_length_ ||
       j1.end - j1.start > max_intron_length_) {
        return false;
    }
    if(j1.start - j1.thick_start >= min_anchor_length_)
        j1.has_left_min_anchor = true;
    if(j1.thick_end - j1.end >= min_anchor_length_)
        j1.has_right_min_anchor = true;
    return true;
}

//Add a junction to the junctions map
//The read_count field is the number of reads supporting the junction.
int JunctionsExtractor::add_junction(Junction j1) {
    //Check junction_qc
    if(!junction_qc(j1)) {
        return 0;
    }

    //Construct key chr:start-end:strand
    stringstream s1;
    string start, end;
    s1 << j1.start; start = s1.str();
    s1 << j1.end; end = s1.str();
    string key = j1.chrom + string(":") + start + "-" + end + ":" + j1.strand;

    //Check if new junction
    if(!junctions_.count(key)) {
        j1.name = get_new_junction_name();
        j1.read_count = 1;
        j1.score = common::num_to_str(j1.read_count);
    } else { //existing junction
        Junction j0 = junctions_[key];
        //increment read count
        j1.read_count = j0.read_count + 1;
        j1.score = common::num_to_str(j1.read_count);
        //Keep the same name
        j1.name = j0.name;
        //Check if thick starts are any better
        if(j0.thick_start < j1.thick_start)
            j1.thick_start = j0.thick_start;
        if(j0.thick_end > j1.thick_end)
            j1.thick_end = j0.thick_end;
        //preserve min anchor information
        j1.has_left_min_anchor = j1.has_left_min_anchor || j0.has_left_min_anchor;
        j1.has_right_min_anchor = j1.has_right_min_anchor || j0.has_right_min_anchor;
    }
    //Add junction and check anchor while printing.
    junctions_[key] = j1;
    return 0;
}

//Print one junction
void JunctionsExtractor::print_one_junction(const Junction j1, ostream& out) {
    out << j1.chrom <<
        "\t" << j1.thick_start << "\t" << j1.thick_end <<
        "\t" << j1.name << "\t" << j1.read_count << "\t" << j1.strand <<
        "\t" << j1.thick_start << "\t" << j1.thick_end <<
        "\t" << j1.color << "\t" << j1.nblocks <<
        "\t" << j1.start - j1.thick_start << "," << j1.thick_end - j1.end <<
        "\t" << "0," << j1.end - j1.thick_start << endl;
}

//Print all the junctions - this function needs work
vector<Junction> JunctionsExtractor::get_all_junctions() {
    //Sort junctions by position
    if(!junctions_sorted_) {
        create_junctions_vector();
        sort_junctions();
    }
    return junctions_vector_;
}

//Print all the junctions - this function needs work
void JunctionsExtractor::print_all_junctions(ostream& out) {
    ofstream fout;
    if(output_file_ != string("NA")) {
        fout.open(output_file_.c_str());
    }
    //Sort junctions by position
    if(!junctions_sorted_) {
        create_junctions_vector();
        sort_junctions();
    }
    for(vector<Junction> :: iterator it = junctions_vector_.begin();
        it != junctions_vector_.end(); it++) {
        Junction j1 = *it;
        if(j1.has_left_min_anchor && j1.has_right_min_anchor) {
            if(fout.is_open())
                print_one_junction(j1, fout);
            else
                print_one_junction(j1, out);
        }
    }
    if(fout.is_open())
        fout.close();
}

//Get the strand from the XS aux tag
void JunctionsExtractor::set_junction_strand(bam1_t *aln, Junction& j1) {
    uint8_t *p = bam_aux_get(aln, "XS");
    if(p != NULL) {
        char strand = bam_aux2A(p);
        strand ? j1.strand = string(1, strand) : j1.strand = string(1, '?');
    } else {
        j1.strand = string(1, '?');
        return;
    }
}

//Parse junctions from the read and store in junction map
int JunctionsExtractor::parse_alignment_into_junctions(bam_hdr_t *header, bam1_t *aln) {
    int n_cigar = aln->core.n_cigar;
    if (n_cigar <= 1) // max one cigar operation exists(likely all matches)
        return 0;

    int chr_id = aln->core.tid;
    int read_pos = aln->core.pos;
    string chr(header->target_name[chr_id]);
    uint32_t *cigar = bam_get_cigar(aln);

    /*
    //Skip duplicates
    int flag = aln->core.flag;
    if(flag & 1024) {
        cerr << "Skipping read_pos " << read_pos << " flag " << flag << endl;
        return 0;
    }
    */

    Junction j1;
    j1.chrom = chr;
    j1.start = read_pos; //maintain start pos of junction
    j1.thick_start = read_pos;
    set_junction_strand(aln, j1);
    bool started_junction = false;
    for (int i = 0; i < n_cigar; ++i) {
        char op =
               bam_cigar_opchr(cigar[i]);
        int len =
               bam_cigar_oplen(cigar[i]);
        switch(op) {
            case 'N':
                if(!started_junction) {
                    j1.end = j1.start + len;
                    j1.thick_end = j1.end;
                    //Start the first one and remains started
                    started_junction = true;
                } else {
                    //Add the previous junction
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    j1.thick_start = j1.end;
                    j1.start = j1.thick_end;
                    j1.end = j1.start + len;
                    j1.thick_end = j1.end;
                    //For clarity - the next junction is now open
                    started_junction = true;
                }
                break;
            case '=':
            case 'M':
                if(!started_junction)
                    j1.start += len;
                else
                    j1.thick_end += len;
                break;
            //No mismatches allowed in anchor
            case 'D':
            case 'X':
                if(!started_junction) {
                    j1.start += len;
                    j1.thick_start = j1.start;
                } else {
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    //Don't include these in the next anchor
                    j1.start = j1.thick_end + len;
                    j1.thick_start = j1.start;
                }
                started_junction = false;
                break;
            case 'I':
            case 'S':
                if(!started_junction)
                    j1.thick_start = j1.start;
                else {
                    try {
                        add_junction(j1);
                    } catch (const std::logic_error& e) {
                        cout << e.what() << '\n';
                    }
                    //Don't include these in the next anchor
                    j1.start = j1.thick_end;
                    j1.thick_start = j1.start;
                }
                started_junction = false;
                break;
            case 'H':
                break;
            default:
                cerr << "Unknown cigar " << op;
                break;
        }
    }
    if(started_junction) {
        try {
            add_junction(j1);
        } catch (const std::logic_error& e) {
            cout << e.what() << '\n';
        }
    }
    return 0;
}

//The workhorse - identifies junctions from BAM
int JunctionsExtractor::identify_junctions_from_BAM() {
    if(!bam_.empty()) {
        //open BAM for reading
        samFile *in = sam_open(bam_.c_str(), "r");
        if(in == NULL) {
            throw runtime_error("Unable to open BAM/SAM file.");
        }
        //Load the index
        hts_idx_t *idx = sam_index_load(in, bam_.c_str());
        if(idx == NULL) {
            throw runtime_error("Unable to open BAM/SAM index."
                                " Make sure alignments are indexed");
        }
        //Get the header
        bam_hdr_t *header = sam_hdr_read(in);
        //Initialize iterator
        hts_itr_t *iter = NULL;
        //Move the iterator to the region we are interested in
        iter  = sam_itr_querys(idx, header, region_.c_str());
        if(header == NULL || iter == NULL) {
            sam_close(in);
            throw runtime_error("Unable to iterate to region within BAM.");
        }
        //Initiate the alignment record
        bam1_t *aln = bam_init1();
        while(sam_itr_next(in, iter, aln) >= 0) {
            parse_alignment_into_junctions(header, aln);
        }
        hts_itr_destroy(iter);
        hts_idx_destroy(idx);
        bam_destroy1(aln);
        bam_hdr_destroy(header);
        sam_close(in);
    }
    return 0;
}

//Create the junctions vector from the map
void JunctionsExtractor::create_junctions_vector() {
    for(map<string, Junction> :: iterator it = junctions_.begin();
        it != junctions_.end(); it++) {
        Junction j1 = it->second;
        junctions_vector_.push_back(j1);
    }
}

//Sort all the junctions by their position
void JunctionsExtractor::sort_junctions() {
    sort(junctions_vector_.begin(), junctions_vector_.end(), compare_junctions);
    junctions_sorted_ = true;
}
<|endoftext|>


<commit_before>
#ifdef _WIN32

#include <iostream>
#include <windows.h>
#include <windowsx.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include "../../batterytech.h"
using namespace std;

// WinMain
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC);
void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC);
BOOL leftButtonDown = FALSE;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine, int iCmdShow)
{
	WNDCLASS wc;
	HWND hWnd;
	HDC hDC;
	HGLRC hRC;
	MSG msg;
	BOOL quit = FALSE;

	// register window class
	wc.style = CS_OWNDC;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "BatteryTech";
	RegisterClass( &wc );

	// create main window
	hWnd = CreateWindow(
		"BatteryTech", "BatteryTech",
		WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
		0, 0, 800, 480,
		NULL, NULL, hInstance, NULL );

	// enable OpenGL for the window
	EnableOpenGL( hWnd, &hDC, &hRC );

	btInit(800, 480);

	DWORD time = timeGetTime();
	DWORD oldTime = time;

	// program main loop
	while ( !quit ) {
		// check for messages
		if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )  ) {
			// handle or dispatch messages
			if ( msg.message == WM_QUIT ) {

				quit = TRUE;
			} else {
				TranslateMessage( &msg );
				DispatchMessage( &msg );
			}
		}
		if (!quit) {
			oldTime = time;
			time = timeGetTime();
			btUpdate((time - oldTime) / 1000.0f);
			btDraw();
			SwapBuffers( hDC );
		}
	}

	// shutdown OpenGL
	DisableOpenGL( hWnd, hDC, hRC );

	// destroy the window explicitly
	DestroyWindow( hWnd );

	return msg.wParam;

}

// Window Procedure

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	switch (message)
	{

	case WM_LBUTTONDOWN:
		leftButtonDown = TRUE;
		int x = GET_X_LPARAM(lParam);
		int y = GET_Y_LPARAM(lParam);
		btSetPointerState(0, true, x, y);
		return 0;
	case WM_LBUTTONUP:
		leftButtonDown = FALSE;
		btSetPointerState(0, false, 0, 0);
		return 0;
	case WM_MOUSEMOVE:
		if (leftButtonDown) {
			int x = GET_X_LPARAM(lParam);
			int y = GET_Y_LPARAM(lParam);
			btSetPointerState(0, true, x, y);
		}
		return 0;
	case WM_CREATE:
		return 0;

	case WM_CLOSE:
		PostQuitMessage( 0 );
		return 0;

	case WM_DESTROY:
		return 0;

	case WM_KEYDOWN:
		switch ( wParam )
		{

		case VK_ESCAPE:
			PostQuitMessage(0);
			return 0;

		}
		return 0;

	default:
		return DefWindowProc( hWnd, message, wParam, lParam );

	}

}

// Enable OpenGL

void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC)
{
	PIXELFORMATDESCRIPTOR pfd;
	int format;

	// get the device context (DC)
	*hDC = GetDC( hWnd );

	// set the pixel format for the DC
	ZeroMemory( &pfd, sizeof( pfd ) );
	pfd.nSize = sizeof( pfd );
	pfd.nVersion = 1;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.cColorBits = 24;
	pfd.cDepthBits = 16;
	pfd.iLayerType = PFD_MAIN_PLANE;
	format = ChoosePixelFormat( *hDC, &pfd );
	SetPixelFormat( *hDC, format, &pfd );

	// create and enable the render context (RC)
	*hRC = wglCreateContext( *hDC );
	wglMakeCurrent( *hDC, *hRC );

}

// Disable OpenGL

void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC)
{
	wglMakeCurrent( NULL, NULL );
	wglDeleteContext( hRC );
	ReleaseDC( hWnd, hDC );
}

#endif /* _WIN32 */
<commit_msg>Batterytech - Game runs in own thread in win32 now<commit_after>
#ifdef _WIN32

#include <iostream>
#include <windows.h>
#include <windowsx.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include "../../batterytech.h"
using namespace std;

// WinMain
DWORD WINAPI StartThread(LPVOID iValue);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC);
void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC);
BOOL leftButtonDown = FALSE;
BOOL quit = FALSE;
HWND hWnd;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine, int iCmdShow)
{
	WNDCLASS wc;
	MSG msg;

	// register window class
	wc.style = CS_OWNDC;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "BatteryTech";
	RegisterClass( &wc );

	// create main window
	hWnd = CreateWindow(
		"BatteryTech", "BatteryTech",
		WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
		0, 0, 800, 480,
		NULL, NULL, hInstance, NULL );

	HANDLE hThread1;
	DWORD dwGenericThread;
	hThread1 = CreateThread(NULL,0,StartThread,NULL,0,&dwGenericThread);
	if (!hThread1) {
		cout << "Error creating thread" << endl;
	}
	// program main loop
	while ( !quit ) {
		// check for messages
		if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )  ) {
			// handle or dispatch messages
			if ( msg.message == WM_QUIT ) {
				quit = TRUE;
			} else {
				TranslateMessage( &msg );
				DispatchMessage( &msg );
			}
		}
	}
	WaitForSingleObject(hThread1,INFINITE);
	// destroy the window explicitly
	DestroyWindow( hWnd );
	return msg.wParam;
}

DWORD WINAPI StartThread(LPVOID iValue) {
	cout << "Starting Game Thread" << endl;
	HGLRC hRC;
	HDC hDC;
	// enable OpenGL for the window
	cout << "Enabling OpenGL" << endl;
	EnableOpenGL( hWnd, &hDC, &hRC );
	btInit(800, 480);
	DWORD time = timeGetTime();
	DWORD oldTime = time;
	while (!quit) {
		//cout << "Ticking" << endl;
		oldTime = time;
		time = timeGetTime();
		btUpdate((time - oldTime) / 1000.0f);
		btDraw();
		SwapBuffers( hDC );
	}
	// shutdown OpenGL
	DisableOpenGL( hWnd, hDC, hRC );
	return 0;
}

// Window Procedure

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	switch (message)
	{

	case WM_LBUTTONDOWN:
		leftButtonDown = TRUE;
		int x = GET_X_LPARAM(lParam);
		int y = GET_Y_LPARAM(lParam);
		btSetPointerState(0, true, x, y);
		return 0;
	case WM_LBUTTONUP:
		leftButtonDown = FALSE;
		btSetPointerState(0, false, 0, 0);
		return 0;
	case WM_MOUSEMOVE:
		if (leftButtonDown) {
			int x = GET_X_LPARAM(lParam);
			int y = GET_Y_LPARAM(lParam);
			btSetPointerState(0, true, x, y);
		}
		return 0;
	case WM_CREATE:
		return 0;

	case WM_CLOSE:
		PostQuitMessage( 0 );
		return 0;

	case WM_DESTROY:
		return 0;

	case WM_KEYDOWN:
		switch ( wParam )
		{

		case VK_ESCAPE:
			PostQuitMessage(0);
			return 0;

		}
		return 0;

	default:
		return DefWindowProc( hWnd, message, wParam, lParam );

	}

}

// Enable OpenGL

void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC)
{
	PIXELFORMATDESCRIPTOR pfd;
	int format;

	// get the device context (DC)
	*hDC = GetDC( hWnd );

	// set the pixel format for the DC
	ZeroMemory( &pfd, sizeof( pfd ) );
	pfd.nSize = sizeof( pfd );
	pfd.nVersion = 1;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.cColorBits = 24;
	pfd.cDepthBits = 16;
	pfd.iLayerType = PFD_MAIN_PLANE;
	format = ChoosePixelFormat( *hDC, &pfd );
	SetPixelFormat( *hDC, format, &pfd );

	// create and enable the render context (RC)
	*hRC = wglCreateContext( *hDC );
	wglMakeCurrent( *hDC, *hRC );

}

// Disable OpenGL

void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC)
{
	wglMakeCurrent( NULL, NULL );
	wglDeleteContext( hRC );
	ReleaseDC( hWnd, hDC );
}

#endif /* _WIN32 */
<|endoftext|>