hisat-3n/spliced_aligner.h

2055 lines
113 KiB
C
Raw Permalink Normal View History

2025-01-18 13:09:52 +00:00
/*
* Copyright 2015, Daehwan Kim <infphilo@gmail.com>
*
* This file is part of HISAT 2.
*
* HISAT 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HISAT 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HISAT 2. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SPLICED_ALIGNER_H_
#define SPLICED_ALIGNER_H_
#include "hi_aligner.h"
/**
* With a hierarchical indexing, SplicedAligner provides several alignment strategies
* , which enable effective alignment of RNA-seq reads
*/
template <typename index_t, typename local_index_t>
class SplicedAligner : public HI_Aligner<index_t, local_index_t> {
public:
/**
* Initialize with index.
*/
SplicedAligner(
const GFM<index_t>& gfm,
bool anchorStop,
uint64_t threads_rids_mindist = 0) :
HI_Aligner<index_t, local_index_t>(gfm,
anchorStop,
threads_rids_mindist)
{
}
~SplicedAligner() {
}
/**
* Given a partial alignment of a read, try to further extend
* the alignment bidirectionally using a combination of
* local search, extension, and global search
*/
virtual
void hybridSearch(
const Scoring& sc,
const PairedEndPolicy& pepol, // paired-end policy
const TranscriptomePolicy& tpol,
const GraphPolicy& gpol,
const GFM<index_t>& gfm,
const ALTDB<index_t>& altdb,
const RepeatDB<index_t>& repeatdb,
const BitPairReference& ref,
SwAligner& swa,
SpliceSiteDB& ssdb,
index_t rdi,
bool fw,
WalkMetrics& wlm,
PerReadMetrics& prm,
SwMetrics& swm,
HIMetrics& him,
RandomSource& rnd,
AlnSinkWrap<index_t>& sink);
/**
* Given a partial alignment of a read, try to further extend
* the alignment bidirectionally using a combination of
* local search, extension, and global search
*/
virtual
int64_t hybridSearch_recur(
const Scoring& sc,
const PairedEndPolicy& pepol, // paired-end policy
const TranscriptomePolicy& tpol,
const GraphPolicy& gpol,
const GFM<index_t>& gfm,
const ALTDB<index_t>& altdb,
const RepeatDB<index_t>& repeatdb,
const BitPairReference& ref,
SwAligner& swa,
SpliceSiteDB& ssdb,
index_t rdi,
const GenomeHit<index_t>& hit,
index_t hitoff,
index_t hitlen,
WalkMetrics& wlm,
PerReadMetrics& prm,
SwMetrics& swm,
HIMetrics& him,
RandomSource& rnd,
AlnSinkWrap<index_t>& sink,
bool alignMate = false,
index_t dep = 0);
};
/**
* Given a partial alignment of a read, try to further extend
* the alignment bidirectionally using a combination of
* local search, extension, and global search
*/
template <typename index_t, typename local_index_t>
void SplicedAligner<index_t, local_index_t>::hybridSearch(
const Scoring& sc,
const PairedEndPolicy& pepol, // paired-end policy
const TranscriptomePolicy& tpol,
const GraphPolicy& gpol,
const GFM<index_t>& gfm,
const ALTDB<index_t>& altdb,
const RepeatDB<index_t>& repeatdb,
const BitPairReference& ref,
SwAligner& swa,
SpliceSiteDB& ssdb,
index_t rdi,
bool fw,
WalkMetrics& wlm,
PerReadMetrics& prm,
SwMetrics& swm,
HIMetrics& him,
RandomSource& rnd,
AlnSinkWrap<index_t>& sink)
{
assert_lt(rdi, 2);
assert(this->_rds[rdi] != NULL);
him.localatts++;
const ReportingParams& rp = sink.reportingParams();
// before further alignment using local search, extend the partial alignments directly
// by comparing with the corresponding genomic sequences
// this extension is performed without any mismatches allowed
for(index_t hi = 0; hi < this->_genomeHits.size(); hi++) {
GenomeHit<index_t>& genomeHit = this->_genomeHits[hi];
index_t leftext = (index_t)INDEX_MAX, rightext = (index_t)INDEX_MAX;
genomeHit.extend(
*(this->_rds[rdi]),
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
INDEX_MAX,
tpol,
gpol,
leftext,
rightext);
}
// for the candidate alignments, examine the longest (best) one first
this->_genomeHits_done.resize(this->_genomeHits.size());
this->_genomeHits_done.fill(false);
for(size_t hi = 0; hi < this->_genomeHits.size(); hi++) {
index_t hj = 0;
for(; hj < this->_genomeHits.size(); hj++) {
if(!this->_genomeHits_done[hj]) break;
}
if(hj >= this->_genomeHits.size()) break;
for(index_t hk = hj + 1; hk < this->_genomeHits.size(); hk++) {
if(this->_genomeHits_done[hk]) continue;
GenomeHit<index_t>& genomeHit_j = this->_genomeHits[hj];
GenomeHit<index_t>& genomeHit_k = this->_genomeHits[hk];
if(genomeHit_k.hitcount() > genomeHit_j.hitcount() ||
(genomeHit_k.hitcount() == genomeHit_j.hitcount() && genomeHit_k.len() > genomeHit_j.len())) {
hj = hk;
}
}
// given a candidate partial alignment, extend it bidirectionally
him.anchoratts++;
GenomeHit<index_t>& genomeHit = this->_genomeHits[hj];
int64_t maxsc = std::numeric_limits<int64_t>::min();
maxsc = hybridSearch_recur(sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
genomeHit,
genomeHit.rdoff(),
genomeHit.len(),
wlm,
prm,
swm,
him,
rnd,
sink);
if(rp.bowtie2_dp == 2 || (rp.bowtie2_dp == 1 && maxsc < this->_minsc[rdi])) {
const Read& rd = *this->_rds[rdi];
// Initialize the aligner with a new read
swa.initRead(rd.patFw, // fw version of query
rd.patRc, // rc version of query
rd.qual, // fw version of qualities
rd.qualRev, // rc version of qualities
0, // off of first char in 'rd' to consider
rd.length(), // off of last char (excl) in 'rd' to consider
sc); // scoring scheme
bool found = genomeHit.len() >= rd.length();
if(!found) {
DynProgFramer dpframe(false); // trimToRef
size_t tlen = ref.approxLen(genomeHit.ref());
size_t readGaps = 10, refGaps = 10, nceil = 0, maxhalf = 10;
index_t refoff = genomeHit.refoff() > genomeHit.rdoff() ? genomeHit.refoff() - genomeHit.rdoff() : 0;
DPRect rect;
dpframe.frameSeedExtensionRect(refoff, // ref offset implied by seed hit assuming no gaps
rd.length(), // length of read sequence used in DP table
tlen, // length of reference
readGaps, // max # of read gaps permitted in opp mate alignment
refGaps, // max # of ref gaps permitted in opp mate alignment
(size_t)nceil, // # Ns permitted
maxhalf, // max width in either direction
rect); // DP rectangle
assert(rect.repOk());
size_t cminlen = 2000, cpow2 = 4, nwindow = 10, nsInLeftShift = 0;
swa.initRef(fw, // whether to align forward or revcomp read
genomeHit.ref(), // reference aligned against
rect, // DP rectangle
ref, // Reference strings
tlen, // length of reference sequence
sc, // scoring scheme
this->_minsc[rdi], // minimum score permitted
true, // use 8-bit SSE if possible?
cminlen, // minimum length for using checkpointing scheme
cpow2, // interval b/t checkpointed diags; 1 << this
false, // triangular mini-fills?
true, // this is a seed extension - not finding a mate
nwindow,
nsInLeftShift);
// Now fill the dynamic programming matrix and return true iff
// there is at least one valid alignment
TAlScore bestCell = std::numeric_limits<TAlScore>::min();
found = swa.align(rnd, bestCell);
if(found) {
SwResult res;
res.reset();
res.alres.init_raw_edits(&(this->_rawEdits));
found = swa.nextAlignment(res, this->_minsc[rdi], rnd);
if(found) {
if(!fw) res.alres.invertEdits();
const Coord& coord = res.alres.refcoord();
assert_geq(genomeHit._joinedOff + coord.off(), genomeHit.refoff());
index_t joinedOff = genomeHit._joinedOff + coord.off() - genomeHit.refoff();
genomeHit.init(fw,
0, // rdoff
rd.length(),
0, // trim5
0, // trim3
coord.ref(),
coord.off(),
joinedOff,
this->_sharedVars,
genomeHit.repeat(), // repeat?
&res.alres.ned(),
NULL,
res.alres.score().score());
genomeHit.replace_edits_with_alts(rd,
altdb.alts(),
ssdb,
sc,
this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
(index_t)tpol.minAnchorLen(),
(index_t)tpol.minAnchorLen_noncan(),
ref);
}
}
}
if(found) {
hybridSearch_recur(sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
genomeHit,
genomeHit.rdoff(),
genomeHit.len(),
wlm,
prm,
swm,
him,
rnd,
sink);
}
}
this->_genomeHits_done[hj] = true;
}
}
/**
* Given a partial alignment of a read, try to further extend
* the alignment bidirectionally using a combination of
* local search, extension, and global search
*/
template <typename index_t, typename local_index_t>
int64_t SplicedAligner<index_t, local_index_t>::hybridSearch_recur(
const Scoring& sc,
const PairedEndPolicy& pepol, // paired-end policy
const TranscriptomePolicy& tpol,
const GraphPolicy& gpol,
const GFM<index_t>& gfm,
const ALTDB<index_t>& altdb,
const RepeatDB<index_t>& repeatdb,
const BitPairReference& ref,
SwAligner& swa,
SpliceSiteDB& ssdb,
index_t rdi,
const GenomeHit<index_t>& hit,
index_t hitoff,
index_t hitlen,
WalkMetrics& wlm,
PerReadMetrics& prm,
SwMetrics& swm,
HIMetrics& him,
RandomSource& rnd,
AlnSinkWrap<index_t>& sink,
bool alignMate,
index_t dep)
{
const ReportingParams& rp = sink.reportingParams();
int64_t maxsc = numeric_limits<int64_t>::min();
him.localsearchrecur++;
assert_lt(rdi, 2);
assert(this->_rds[rdi] != NULL);
const Read& rd = *(this->_rds[rdi]);
index_t rdlen = (index_t)rd.length();
TAlScore cushion = 0;
if(tpol.no_spliced_alignment()) {
cushion = alignMate ? rdlen * 0.03 * sc.mm(255) : 0;
}
if(hit.score() + cushion < this->_minsc[rdi]) return maxsc;
if(dep >= 128) return maxsc;
// if it's already examined, just return
if(hitoff == hit.rdoff() - hit.trim5() && hitlen == hit.len() + hit.trim5() + hit.trim3()) {
if(this->isSearched(hit, rdi)) return maxsc;
this->addSearched(hit, rdi);
}
// for effective use of memory allocation and deallocation
if(this->_coords.size() <= dep) {
this->_coords.expand();
assert_leq(this->_local_genomeHits.size(), dep);
this->_local_genomeHits.expand();
assert_leq(this->_spliceSites.size(), dep);
this->_spliceSites.expand();
}
EList<Coord>& coords = this->_coords[dep];
EList<SpliceSite>& spliceSites = this->_spliceSites[dep];
// daehwan - for debugging purposes
#if 0
cout << rd.name << "\t"
<< (hit.fw() ? "+" : "-") << "\t"
<< hitoff << "\t"
<< hitoff + hitlen << "\t"
<< "( " << hit.rdoff() << "\t"
<< hit.rdoff() + hit.len() << " )" << "\t"
<< hit.refoff() << "\t"
<< hit.getRightOff() << "\t"
<< hit.score() << "\t"
<< "dep: " << dep << "\t";
Edit::print(cout, hit.edits());
cout << endl;
#endif
assert_leq(hitoff + hitlen, rdlen);
// if this is a full alignment, report it
if(hitoff == 0 && hitlen == rdlen) {
if(!this->redundant(sink, rdi, hit)) {
bool another_spliced = false;
if(!ssdb.empty()) {
int64_t best_score = hit.score();
this->_local_genomeHits[dep].clear();
this->_anchors_added.clear();
this->_local_genomeHits[dep].expand();
this->_local_genomeHits[dep].back() = hit;
this->_anchors_added.push_back(0);
index_t fragoff = 0, fraglen = 0, left = 0, right = 0;
hit.getLeft(fragoff, fraglen, left);
const index_t minMatchLen = (index_t)this->_minK;
index_t min_left_anchor = rdlen, min_right_anchor = rdlen;
// make use of a list of known or novel splice sites to further align the read
if(fraglen >= minMatchLen &&
left >= minMatchLen &&
hit.trim5() == 0 &&
!hit.repeat() &&
!tpol.no_spliced_alignment()) {
spliceSites.clear();
ssdb.getLeftSpliceSites(hit.ref(), left + minMatchLen, minMatchLen, spliceSites);
for(size_t si = 0; si < spliceSites.size(); si++) {
const SpliceSite& ss = spliceSites[si];
if(!ss._fromfile && ss._readid + this->_thread_rids_mindist > rd.rdid) continue;
if(left + fraglen - 1 < ss.right()) continue;
index_t frag2off = ss.left() - (ss.right() - left);
if(frag2off + 1 < hitoff) continue;
GenomeHit<index_t> tempHit;
if(fragoff + ss.right() < left + 1) continue;
index_t readoff = fragoff + ss.right() - left - 1;
index_t joinedOff = 0;
bool success = gfm.textOffToJoined(hit.ref(), ss.left(), joinedOff);
if(!success) {
continue;
}
#ifndef NDEBUG
index_t debug_tid = 0, debug_toff = 0, debug_tlen = 0;
bool debug_straddled = false;
gfm.joinedToTextOff(1, // qlen
joinedOff,
debug_tid,
debug_toff,
debug_tlen,
false,
debug_straddled);
assert_eq(hit.ref(), debug_tid);
assert_eq(ss.left(), debug_toff);
#endif
tempHit.init(hit.fw(),
readoff + 1, // rdoff
0, // len
0, // trim5
0, // trim3
hit.ref(),
ss.left() + 1,
joinedOff + 1,
this->_sharedVars,
gfm.repeat());
index_t leftext = readoff + 1, rightext = 0;
tempHit.extend(rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext);
if(tempHit.len() <= 0)
continue;
if(!tempHit.compatibleWith(
hit,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
tpol.no_spliced_alignment()))
continue;
int64_t minsc = max<int64_t>(this->_minsc[rdi], best_score);
bool combined = tempHit.combineWith(
hit,
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
sc,
minsc,
rnd,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
1,
1,
gpol.maxAltsTried(),
&ss,
tpol.no_spliced_alignment());
if(rdi == 0) minsc = max(minsc, sink.bestUnp1());
else minsc = max(minsc, sink.bestUnp2());
index_t leftAnchorLen = 0, nedits = 0;
tempHit.getLeftAnchor(leftAnchorLen, nedits);
if(combined &&
tempHit.score() >= minsc &&
nedits <= leftAnchorLen / 4) { // prevent (short) anchors from having many mismatches
if(this->isSearched(tempHit, rdi)) continue;
if(!this->redundant(sink, rdi, tempHit)) {
another_spliced = true;
if(tempHit.score() > best_score)
best_score = tempHit.score();
this->_local_genomeHits[dep].expand();
this->_local_genomeHits[dep].back() = tempHit;
this->_anchors_added.push_back(1);
index_t temp_fragoff = 0, temp_fraglen = 0, temp_left = 0;
tempHit.getLeft(temp_fragoff, temp_fraglen, temp_left);
if(temp_fraglen < min_left_anchor)
min_left_anchor = temp_fraglen;
}
}
}
}
size_t num_local_genomeHits = this->_local_genomeHits[dep].size();
for(size_t i = 0; i < num_local_genomeHits; i++) {
this->_local_genomeHits[dep][i].getRight(fragoff, fraglen, right);
if(this->_local_genomeHits[dep][i].score() < best_score) continue;
// make use of a list of known or novel splice sites to further align the read
if(fraglen >= minMatchLen &&
this->_local_genomeHits[dep][i].trim3() == 0 &&
!hit.repeat() &&
!tpol.no_spliced_alignment()) {
spliceSites.clear();
assert_gt(fraglen, 0);
ssdb.getRightSpliceSites(this->_local_genomeHits[dep][i].ref(), right + fraglen - minMatchLen, minMatchLen, spliceSites);
for(size_t si = 0; si < spliceSites.size(); si++) {
const GenomeHit<index_t>& canHit = this->_local_genomeHits[dep][i];
const SpliceSite& ss = spliceSites[si];
if(!ss._fromfile && ss._readid + this->_thread_rids_mindist > rd.rdid) continue;
if(right > ss.left()) continue;
GenomeHit<index_t> tempHit;
index_t readoff = fragoff + ss.left() - right + 1;
if(readoff >= rdlen)
continue;
index_t joinedOff = 0;
bool success = gfm.textOffToJoined(canHit.ref(), ss.right(), joinedOff);
if(!success) {
continue;
}
#ifndef NDEBUG
index_t debug_tid = 0, debug_toff = 0, debug_tlen = 0;
bool debug_straddled = false;
gfm.joinedToTextOff(1, // qlen
joinedOff,
debug_tid,
debug_toff,
debug_tlen,
false,
debug_straddled);
assert_eq(canHit.ref(), debug_tid);
assert_eq(ss.right(), debug_toff);
#endif
tempHit.init(canHit.fw(),
readoff,
0, // len
0, // trim5
0, // trim3
canHit.ref(),
ss.right(),
joinedOff,
this->_sharedVars,
gfm.repeat());
index_t leftext = 0, rightext = rdlen - readoff;
tempHit.extend(rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext);
if(tempHit.len() <= 0)
continue;
if(!canHit.compatibleWith(tempHit, (index_t)tpol.minIntronLen(), (index_t)tpol.maxIntronLen(), tpol.no_spliced_alignment())) continue;
GenomeHit<index_t> combinedHit = canHit;
int64_t minsc = max<int64_t>(this->_minsc[rdi], best_score);
bool combined = combinedHit.combineWith(
tempHit,
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
sc,
minsc,
rnd,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
1,
1,
gpol.maxAltsTried(),
&ss,
tpol.no_spliced_alignment());
if(rdi == 0) minsc = max(minsc, sink.bestUnp1());
else minsc = max(minsc, sink.bestUnp2());
index_t rightAnchorLen = 0, nedits = 0;
combinedHit.getRightAnchor(rightAnchorLen, nedits);
if(combined &&
combinedHit.score() >= minsc &&
nedits <= rightAnchorLen / 4) { // prevent (short) anchors from having many mismatches
if(this->isSearched(combinedHit, rdi)) continue;
if(!this->redundant(sink, rdi, combinedHit)) {
another_spliced = true;
if(combinedHit.score() > best_score)
best_score = tempHit.score();
this->_local_genomeHits[dep].expand();
this->_local_genomeHits[dep].back() = combinedHit;
this->_anchors_added.push_back(this->_anchors_added[i] + 1);
index_t temp_fragoff = 0, temp_fraglen = 0, temp_right = 0;
combinedHit.getLeft(temp_fragoff, temp_fraglen, temp_right);
if(temp_fraglen < min_right_anchor)
min_right_anchor = temp_fraglen;
}
}
}
}
}
assert_eq(this->_local_genomeHits[dep].size(), this->_anchors_added.size());
for(size_t i = 0; i < this->_local_genomeHits[dep].size(); i++) {
const GenomeHit<index_t>& canHit = this->_local_genomeHits[dep][i];
if(!rp.secondary && canHit.score() < best_score) continue;
// if(min(min_left_anchor, min_right_anchor) <= this->_minK_local) {
// daehwan - for debugging purposes
// if(this->_anchors_added[i] < this->_anchors_added.back()) continue;
//}
if(i > 0 && !this->isSearched(canHit, rdi)) {
this->addSearched(canHit, rdi);
}
if(!this->redundant(sink, rdi, canHit)) {
this->reportHit(sc, pepol, tpol, gpol, gfm, altdb, repeatdb, ref, ssdb, sink, rdi, canHit, alignMate);
maxsc = max<int64_t>(maxsc, canHit.score());
}
}
}
else {
this->reportHit(sc, pepol, tpol, gpol, gfm, altdb, repeatdb, ref, ssdb, sink, rdi, hit, alignMate);
maxsc = max<int64_t>(maxsc, hit.score());
}
return maxsc;
}
} else if(hitoff > 0 && (hitoff + hitlen == rdlen || hitoff + hitoff < rdlen - hitlen)) {
// Decide which side to extend first (left or right)
if(!ssdb.empty()) {
// extend the partial alignment in the left direction
index_t fragoff = 0, fraglen = 0, left = 0;
hit.getLeft(fragoff, fraglen, left);
const index_t minMatchLen = (index_t)this->_minK_local;
// make use of a list of known or novel splice sites to further align the read
if(fraglen >= minMatchLen &&
left >= minMatchLen &&
!hit.repeat() &&
!tpol.no_spliced_alignment()) {
spliceSites.clear();
ssdb.getLeftSpliceSites(hit.ref(), left + minMatchLen, minMatchLen + min<index_t>(minMatchLen, fragoff), spliceSites);
for(size_t si = 0; si < spliceSites.size(); si++) {
const SpliceSite& ss = spliceSites[si];
if(!ss._fromfile && ss._readid + this->_thread_rids_mindist > rd.rdid) continue;
if(left + fraglen - 1 < ss.right()) continue;
if(fragoff + ss.right() < left + 1) continue;
index_t readoff = fragoff + ss.right() - left - 1;
index_t joinedOff = 0;
bool success = gfm.textOffToJoined(hit.ref(), ss.left(), joinedOff);
if(!success) {
continue;
}
#ifndef NDEBUG
index_t debug_tid = 0, debug_toff = 0, debug_tlen = 0;
bool debug_straddled = false;
gfm.joinedToTextOff(1, // qlen
joinedOff,
debug_tid,
debug_toff,
debug_tlen,
false,
debug_straddled);
assert_eq(hit.ref(), debug_tid);
assert_eq(ss.left(), debug_toff);
#endif
GenomeHit<index_t> tempHit;
tempHit.init(hit.fw(),
readoff + 1, // rdoff
0, // len
0, // trim5
0, // trim3
hit.ref(),
ss.left() + 1,
joinedOff + 1,
this->_sharedVars,
gfm.repeat());
index_t leftext = readoff + 1, rightext = 0;
tempHit.extend(rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext);
if(tempHit.len() <= 0)
continue;
if(!tempHit.compatibleWith(hit, (index_t)tpol.minIntronLen(), (index_t)tpol.maxIntronLen(), tpol.no_spliced_alignment())) continue;
int64_t minsc = this->_minsc[rdi];
bool combined = tempHit.combineWith(
hit,
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
sc,
minsc,
rnd,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
1,
1,
gpol.maxAltsTried(),
&ss,
tpol.no_spliced_alignment());
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(combined &&
tempHit.score() >= minsc &&
// soft-clipping might be better
tempHit.score() + sc.sc(0) * hit.rdoff() >= hit.score()) {
assert_eq(tempHit.trim5(), 0);
assert_leq(tempHit.rdoff() + tempHit.len() + tempHit.trim3(), rdlen);
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
tempHit,
tempHit.rdoff(),
tempHit.len() + tempHit.trim3(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
}
}
}
}
bool use_localindex = true;
if(hitoff == hit.rdoff() && hitoff <= this->_minK) {
index_t leftext = (index_t)INDEX_MAX, rightext = (index_t)0;
GenomeHit<index_t> tempHit = hit;
tempHit.extend(
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext,
1);
if(tempHit.rdoff() == 0) {
use_localindex = false;
}
}
// Choose a local index based on the genomic location of the partial alignment
const HGFM<index_t, local_index_t>* hGFM = (const HGFM<index_t, local_index_t>*)(&gfm);
const LocalGFM<local_index_t, index_t>* lGFM = hGFM->getLocalGFM(hit.ref(), hit.refoff());
assert_leq(lGFM->_localOffset, hit.refoff());
bool success = false, first = true;
index_t count = 0;
// Use at most two local indexes
const index_t max_count = 2;
int64_t prev_score = hit.score();
this->_local_genomeHits[dep].clear();
while(!success && count++ < max_count && use_localindex) {
if(him.localindexatts >= this->max_localindexatts) break;
if(first) {
first = false;
} else {
lGFM = hGFM->prevLocalGFM(lGFM);
if(lGFM == NULL || lGFM->empty()) break;
}
// local index search
index_t extlen = 0;
local_index_t top = (local_index_t)INDEX_MAX, bot = (local_index_t)INDEX_MAX;
local_index_t node_top = (local_index_t)INDEX_MAX, node_bot = (local_index_t)INDEX_MAX;
index_t extoff = hitoff - 1;
if(extoff > 0) extoff -= 1;
if(extoff < tpol.minAnchorLen()) {
extoff = tpol.minAnchorLen();
}
index_t nelt = (index_t)INDEX_MAX;
index_t max_nelt = std::max<index_t>(5, extlen);
bool no_extension = false;
bool uniqueStop= false;
index_t minUniqueLen = (index_t)this->_minK_local;
for(; extoff < rdlen; extoff++) {
extlen = 0;
uniqueStop = true;
him.localindexatts++;
this->_local_node_iedge_count.clear();
nelt = this->localGFMSearch(
*lGFM, // BWT index
rd, // read to align
sc, // scoring scheme
sink.reportingParams(),
hit.fw(),
extoff,
extlen,
top,
bot,
node_top,
node_bot,
this->_local_node_iedge_count,
rnd,
uniqueStop,
minUniqueLen);
if(extoff + 1 - extlen >= hitoff) {
no_extension = true;
break;
}
if(nelt <= max_nelt) break;
}
assert_leq(node_top, node_bot);
assert_eq(nelt, (index_t)(node_bot - node_top));
assert_leq(extlen, extoff + 1);
if(nelt > 0 &&
nelt <= max_nelt &&
extlen >= tpol.minAnchorLen() &&
!no_extension) {
assert_leq(nelt, max_nelt);
coords.clear();
bool straddled = false;
// get genomic locations for this local search
this->getGenomeCoords_local(
*lGFM,
altdb,
ref,
rnd,
top,
bot,
node_top,
node_bot,
this->_local_node_iedge_count,
hit.fw(),
extoff + 1 - extlen,
extlen,
coords,
wlm,
prm,
him,
true, // reject straddled?
straddled);
assert_leq(coords.size(), nelt);
coords.sort();
for(int ri = (int)coords.size() - 1; ri >= 0; ri--) {
const Coord& coord = coords[ri];
GenomeHit<index_t> tempHit;
tempHit.init(coord.orient(),
extoff + 1 - extlen,
extlen,
0, // trim5
0, // trim3
(index_t)coord.ref(),
(index_t)coord.off(),
(index_t)coord.joinedOff(),
this->_sharedVars,
gfm.repeat());
if(!tempHit.adjustWithALT(*this->_rds[rdi], gfm, altdb, ref, gpol)) continue;
// check if the partial alignment is compatible with the new alignment using the local index
if(!tempHit.compatibleWith(hit, (index_t)tpol.minIntronLen(), (index_t)tpol.maxIntronLen(), tpol.no_spliced_alignment())) {
if(count == 1) continue;
else break;
}
if(uniqueStop) {
assert_eq(coords.size(), 1);
index_t leftext = (index_t)INDEX_MAX, rightext = (index_t)0;
tempHit.extend(
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext);
}
// combine the partial alignment and the new alignment
int64_t minsc = this->_minsc[rdi];
bool combined = tempHit.combineWith(
hit,
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
sc,
minsc,
rnd,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
tpol.minAnchorLen(),
tpol.minAnchorLen_noncan(),
gpol.maxAltsTried(),
NULL, // splice sites
tpol.no_spliced_alignment());
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(combined && tempHit.score() >= minsc) {
assert_eq(tempHit.trim5(), 0);
assert_leq(tempHit.rdoff() + tempHit.len() + tempHit.trim3(), rdlen);
if(tempHit.score() >= prev_score - sc.mmpMax) {
// extend the new partial alignment recursively
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
tempHit,
tempHit.rdoff(),
tempHit.len() + tempHit.trim3(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
} else {
this->_local_genomeHits[dep].push_back(tempHit);
}
}
}
}
if(maxsc >= prev_score - sc.mmpMax) success = true;
if(!success &&
(him.localindexatts >= this->max_localindexatts || count == max_count || hGFM->prevLocalGFM(lGFM) == NULL)) {
for(index_t ti = 0; ti < this->_local_genomeHits[dep].size(); ti++) {
GenomeHit<index_t>& tempHit = this->_local_genomeHits[dep][ti];
int64_t minsc = this->_minsc[rdi];
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(tempHit.score() >= minsc) {
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
tempHit,
tempHit.rdoff(),
tempHit.len() + tempHit.trim3(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
}
}
}
} // while(!success && count++ < 2)
if(!success) {
if(hitoff > this->_minK &&
him.localindexatts < this->max_localindexatts) {
index_t extlen = 0;
index_t top = (index_t)INDEX_MAX, bot = (index_t)INDEX_MAX;
index_t node_top = (index_t)INDEX_MAX, node_bot = (index_t)INDEX_MAX;
this->_node_iedge_count.clear();
index_t extoff = hitoff - 1;
bool uniqueStop = true;
// perform global search for long introns
index_t nelt = this->globalGFMSearch(
gfm, // GFM index
rd, // read to align
sc, // scoring scheme
sink.reportingParams(),
hit.fw(),
extoff,
extlen,
top,
bot,
node_top,
node_bot,
this->_node_iedge_count,
rnd,
uniqueStop);
if(nelt > 0 && nelt <= 5 && extlen >= this->_minK) {
coords.clear();
bool straddled = false;
this->getGenomeCoords(
gfm,
altdb,
ref,
rnd,
top,
bot,
node_top,
node_bot,
this->_node_iedge_count,
hit.fw(),
bot - top,
extoff + 1 - extlen,
extlen,
coords,
wlm,
prm,
him,
true, // reject straddled?
straddled);
assert_leq(coords.size(), nelt);
if(coords.size() > 1) coords.sort();
for(int ri = (int)coords.size() - 1; ri >= 0; ri--) {
const Coord& coord = coords[ri];
GenomeHit<index_t> tempHit;
tempHit.init(coord.orient(),
extoff + 1 - extlen,
extlen,
0, // trim5
0, // trim3
(index_t)coord.ref(),
(index_t)coord.off(),
(index_t)coord.joinedOff(),
this->_sharedVars,
gfm.repeat());
if(!tempHit.adjustWithALT(*this->_rds[rdi], gfm, altdb, ref, gpol)) continue;
if(!tempHit.compatibleWith(hit, (index_t)tpol.minIntronLen(), (index_t)tpol.maxIntronLen(), tpol.no_spliced_alignment())) continue;
if(uniqueStop) {
assert_eq(coords.size(), 1);
index_t leftext = (index_t)INDEX_MAX, rightext = (index_t)0;
tempHit.extend(
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext);
}
int64_t minsc = this->_minsc[rdi];
bool combined = tempHit.combineWith(
hit,
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
sc,
minsc,
rnd,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
tpol.minAnchorLen(),
tpol.minAnchorLen_noncan(),
gpol.maxAltsTried(),
NULL, // splice sites
tpol.no_spliced_alignment());
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(combined && tempHit.score() >= minsc) {
assert_eq(tempHit.trim5(), 0);
assert_leq(tempHit.rdoff() + tempHit.len() + tempHit.trim3(), rdlen);
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
tempHit,
tempHit.rdoff(),
tempHit.len() + tempHit.trim3(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
}
}
}
}
GenomeHit<index_t> tempHit = hit;
index_t trimMax = (index_t)((tempHit.score() - max<int64_t>(maxsc, this->_minsc[rdi])) / sc.sc(0));
if(tempHit.rdoff() < trimMax) {
index_t trim5 = tempHit.rdoff();
GenomeHit<index_t> trimedHit = tempHit;
trimedHit.trim5(trim5,
rd,
ssdb,
sc,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
tpol.minAnchorLen(),
tpol.minAnchorLen_noncan(),
ref);
assert_leq(trimedHit.len() + trimedHit.trim5() + trimedHit.trim3(), rdlen);
int64_t tmp_score = trimedHit.score();
if(tmp_score > maxsc && tmp_score >= this->_minsc[rdi]) {
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
trimedHit,
0,
trimedHit.len() + trimedHit.trim5() + trimedHit.trim3(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
// return maxsc;
}
}
// extend the partial alignment directly comparing with the corresponding genomic sequence
// with mismatches or a gap allowed
int64_t minsc = this->_minsc[rdi];
assert_geq(tempHit.score(), minsc);
index_t mm = (index_t)((tempHit.score() - minsc) / sc.mmpMax);
index_t leftext = (index_t)INDEX_MAX, rightext = (index_t)0;
index_t num_mismatch_allowed = 1;
if(hitoff <= this->_minK_local) {
num_mismatch_allowed = min<index_t>(tempHit.rdoff(), mm);
}
him.localextatts++;
tempHit.extend(
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext,
num_mismatch_allowed);
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(tempHit.score() >= minsc && leftext >= min<index_t>((index_t)this->_minK_local, hit.rdoff())) {
assert_eq(tempHit.trim5(), 0);
assert_leq(tempHit.rdoff() + tempHit.len() + tempHit.trim3(), rdlen);
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
tempHit,
tempHit.rdoff(),
tempHit.len() + tempHit.trim3(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
} else if(hitoff > this->_minK_local) {
// skip some bases of a read
index_t jumplen = hitoff > this->_minK ? (index_t)this->_minK : (index_t)this->_minK_local;
assert_leq(hitoff, hit.rdoff());
int64_t expected_score = hit.score() - (hit.rdoff() - hitoff) / jumplen * sc.mmpMax - sc.mmpMax;
if(expected_score >= minsc) {
assert_lt(hitlen + jumplen, rdlen);
assert_eq(hit.trim5(), 0);
assert_leq(hitoff + hitlen, rdlen);
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
hit,
hitoff - jumplen,
hitlen + jumplen,
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
}
}
}
} else {
// extend the partial alignment in the right direction
assert_lt(hitoff + hitlen, rdlen);
if(!ssdb.empty()) {
index_t fragoff = 0, fraglen = 0, right = 0;
hit.getRight(fragoff, fraglen, right);
const index_t minMatchLen = (index_t)this->_minK_local;
// make use of a list of known or novel splice sites to further align the read
if(fraglen >= minMatchLen &&
!hit.repeat() &&
!tpol.no_spliced_alignment()) {
spliceSites.clear();
assert_gt(fraglen, 0);
assert_leq(fragoff + fraglen, rdlen);
index_t right_unmapped_len = rdlen - fragoff - fraglen;
ssdb.getRightSpliceSites(hit.ref(), right + fraglen - minMatchLen, minMatchLen + min<index_t>(minMatchLen, right_unmapped_len), spliceSites);
for(size_t si = 0; si < spliceSites.size(); si++) {
const SpliceSite& ss = spliceSites[si];
if(!ss._fromfile && ss._readid + this->_thread_rids_mindist > rd.rdid) continue;
if(right > ss.left()) continue;
GenomeHit<index_t> tempHit;
assert_leq(right, ss.left());
index_t readoff = fragoff + ss.left() - right + 1;
if(readoff >= rdlen)
continue;
index_t joinedOff = 0;
bool success = gfm.textOffToJoined(hit.ref(), ss.right(), joinedOff);
if(!success) {
continue;
}
#ifndef NDEBUG
index_t debug_tid = 0, debug_toff = 0, debug_tlen = 0;
bool debug_straddled = false;
gfm.joinedToTextOff(1, // qlen
joinedOff,
debug_tid,
debug_toff,
debug_tlen,
false,
debug_straddled);
assert_eq(hit.ref(), debug_tid);
assert_eq(ss.right(), debug_toff);
#endif
tempHit.init(hit.fw(),
readoff,
0, // len
0, // trim5
0, // trim3
hit.ref(),
ss.right(),
joinedOff,
this->_sharedVars,
gfm.repeat());
index_t leftext = 0, rightext = rdlen - readoff;
tempHit.extend(rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext);
if(tempHit.len() <= 0)
continue;
if(!hit.compatibleWith(tempHit, (index_t)tpol.minIntronLen(), (index_t)tpol.maxIntronLen(), tpol.no_spliced_alignment())) continue;
GenomeHit<index_t> combinedHit = hit;
int64_t minsc = this->_minsc[rdi];
bool combined = combinedHit.combineWith(
tempHit,
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
sc,
minsc,
rnd,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
1,
1,
gpol.maxAltsTried(),
&ss,
tpol.no_spliced_alignment());
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(combined && combinedHit.score() >= minsc &&
// soft-clipping might be better
combinedHit.score() + sc.sc(0) * (rdlen - hit.rdoff() - hit.len() - hit.trim5()) >= hit.score()) {
assert_leq(combinedHit.trim5(), combinedHit.rdoff());
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
combinedHit,
combinedHit.rdoff() - combinedHit.trim5(),
combinedHit.len() + combinedHit.trim5(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
}
}
}
}
bool use_localindex = true;
if(hit.len() == hitlen && hitoff + hitlen + this->_minK > rdlen) {
index_t leftext = (index_t)0, rightext = (index_t)INDEX_MAX;
GenomeHit<index_t> tempHit = hit;
tempHit.extend(
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext,
1);
if(tempHit.rdoff() + tempHit.len()== rdlen) {
use_localindex = false;
}
}
// Choose a local index based on the genomic location of the partial alignment
const HGFM<index_t, local_index_t>* hGFM = (const HGFM<index_t, local_index_t>*)(&gfm);
const LocalGFM<local_index_t, index_t>* lGFM = hGFM->getLocalGFM(hit.ref(), hit.refoff());
bool success = false, first = true;
index_t count = 0;
// Use at most two local indexes
const index_t max_count = 2;
int64_t prev_score = hit.score();
this->_local_genomeHits[dep].clear();
while(!success && count++ < max_count && use_localindex) {
if(him.localindexatts >= this->max_localindexatts) break;
if(first) {
first = false;
} else {
lGFM = hGFM->nextLocalGFM(lGFM);
if(lGFM == NULL || lGFM->empty()) break;
}
// local index search
index_t extlen = 0;
local_index_t top = (local_index_t)INDEX_MAX, bot = (local_index_t)INDEX_MAX;
local_index_t node_top = (local_index_t)INDEX_MAX, node_bot = (local_index_t)INDEX_MAX;
index_t extoff = hitoff + hitlen + (index_t)this->_minK_local;
if(extoff + 1 < rdlen) extoff += 1;
if(extoff >= rdlen) {
extoff = rdlen - 1;
}
index_t nelt = (index_t)INDEX_MAX;
index_t max_nelt = std::max<index_t>(5, extlen);
bool no_extension = false;
bool uniqueStop;
index_t minUniqueLen = (index_t)this->_minK_local;
index_t maxHitLen = max<index_t>(extoff - hitoff - hitlen, (index_t)this->_minK_local);
for(; maxHitLen < extoff + 1 && extoff < rdlen;) {
extlen = 0;
uniqueStop = false;
him.localindexatts++;
this->_local_node_iedge_count.clear();
nelt = this->localGFMSearch(
*lGFM, // GFM index
rd, // read to align
sc, // scoring scheme
sink.reportingParams(),
hit.fw(),
extoff,
extlen,
top,
bot,
node_top,
node_bot,
this->_local_node_iedge_count,
rnd,
uniqueStop,
minUniqueLen,
maxHitLen);
if(extoff < hitoff + hitlen) {
no_extension = true;
break;
}
if(nelt <= max_nelt) break;
if(extoff + 1 < rdlen) extoff++;
else {
if(extlen < maxHitLen) break;
else maxHitLen++;
}
}
assert_leq(node_top, node_bot);
assert_eq(nelt, (index_t)(node_bot - node_top));
assert_leq(extlen, extoff + 1);
assert_leq(extoff, rdlen);
if(nelt > 0 &&
nelt <= max_nelt &&
extlen >= tpol.minAnchorLen() &&
!no_extension) {
assert_leq(nelt, max_nelt);
coords.clear();
bool straddled = false;
// get genomic locations for this local search
this->getGenomeCoords_local(
*lGFM,
altdb,
ref,
rnd,
top,
bot,
node_top,
node_bot,
this->_local_node_iedge_count,
hit.fw(),
extoff + 1 - extlen,
extlen,
coords,
wlm,
prm,
him,
true, // reject straddled?
straddled);
assert_leq(coords.size(), nelt);
if(coords.size() > 1) coords.sort();
for(index_t ri = 0; ri < coords.size(); ri++) {
const Coord& coord = coords[ri];
GenomeHit<index_t> tempHit;
tempHit.init(coord.orient(),
extoff + 1 - extlen,
extlen,
0, // trim5
0, // trim3
(index_t)coord.ref(),
(index_t)coord.off(),
(index_t)coord.joinedOff(),
this->_sharedVars,
gfm.repeat());
if(!tempHit.adjustWithALT(*this->_rds[rdi], gfm, altdb, ref, gpol)) continue;
// check if the partial alignment is compatible with the new alignment using the local index
if(!hit.compatibleWith(tempHit, (index_t)tpol.minIntronLen(), (index_t)tpol.maxIntronLen(), tpol.no_spliced_alignment())) {
if(count == 1) continue;
else break;
}
index_t leftext = (index_t)0, rightext = (index_t)INDEX_MAX;
tempHit.extend(
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext);
GenomeHit<index_t> combinedHit = hit;
int64_t minsc = this->_minsc[rdi];
// combine the partial alignment and the new alignment
bool combined = combinedHit.combineWith(
tempHit,
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
sc,
minsc,
rnd,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
tpol.minAnchorLen(),
tpol.minAnchorLen_noncan(),
gpol.maxAltsTried(),
NULL, // splice sites
tpol.no_spliced_alignment());
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(combined && combinedHit.score() >= minsc) {
assert_leq(combinedHit.trim5(), combinedHit.rdoff());
if(combinedHit.score() >= prev_score - sc.mmpMax) {
// extend the new partial alignment recursively
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
combinedHit,
combinedHit.rdoff() - combinedHit.trim5(),
combinedHit.len() + combinedHit.trim5(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
} else {
this->_local_genomeHits[dep].push_back(combinedHit);
}
}
}
}
// int64_t minsc = (rdi == 0 ? sink.bestUnp1() : sink.bestUnp2());
if(maxsc >= prev_score - sc.mmpMax) success = true;
if(!success &&
(him.localindexatts >= this->max_localindexatts || count == max_count || hGFM->nextLocalGFM(lGFM) == NULL) ) {
for(index_t ti = 0; ti < this->_local_genomeHits[dep].size(); ti++) {
GenomeHit<index_t>& tempHit = this->_local_genomeHits[dep][ti];
int64_t minsc = this->_minsc[rdi];
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(tempHit.score() >= minsc) {
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
tempHit,
tempHit.rdoff() - tempHit.trim5(),
tempHit.len() + tempHit.trim5(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
}
}
}
} // while(!success && count++ < 2)
if(!success) {
// perform global search for long introns
if(hitoff + hitlen + this->_minK + 1 < rdlen &&
him.localindexatts < this->max_localindexatts) {
index_t extlen = 0;
index_t top = (index_t)INDEX_MAX, bot = (index_t)INDEX_MAX;
index_t node_top = (index_t)INDEX_MAX, node_bot = (index_t)INDEX_MAX;
this->_node_iedge_count.clear();
index_t extoff = hitoff + hitlen + (index_t)this->_minK + 1;
bool uniqueStop = true;
index_t nelt = this->globalGFMSearch(
gfm, // GFM index
rd, // read to align
sc, // scoring scheme
sink.reportingParams(),
hit.fw(),
extoff,
extlen,
top,
bot,
node_top,
node_bot,
this->_node_iedge_count,
rnd,
uniqueStop);
if(nelt > 0 && nelt <= 5 && extlen >= this->_minK) {
coords.clear();
bool straddled = false;
this->getGenomeCoords(
gfm,
altdb,
ref,
rnd,
top,
bot,
node_top,
node_bot,
this->_node_iedge_count,
hit.fw(),
bot - top,
extoff + 1 - extlen,
extlen,
coords,
wlm,
prm,
him,
true, // reject straddled
straddled);
assert_leq(coords.size(), nelt);
coords.sort();
for(index_t ri = 0; ri < coords.size(); ri++) {
const Coord& coord = coords[ri];
GenomeHit<index_t> tempHit;
tempHit.init(coord.orient(),
extoff + 1 - extlen,
extlen,
0, // trim5
0, // trim3
(index_t)coord.ref(),
(index_t)coord.off(),
(index_t)coord.joinedOff(),
this->_sharedVars,
gfm.repeat());
if(!tempHit.adjustWithALT(*this->_rds[rdi], gfm, altdb, ref, gpol)) continue;
if(!hit.compatibleWith(tempHit, (index_t)tpol.minIntronLen(), (index_t)tpol.maxIntronLen(), tpol.no_spliced_alignment())) continue;
index_t leftext = (index_t)0, rightext = (index_t)INDEX_MAX;
tempHit.extend(
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext);
GenomeHit<index_t> combinedHit = hit;
int64_t minsc = this->_minsc[rdi];
bool combined = combinedHit.combineWith(
tempHit,
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
sc,
minsc,
rnd,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
tpol.minAnchorLen(),
tpol.minAnchorLen_noncan(),
gpol.maxAltsTried(),
NULL, // splice sites
tpol.no_spliced_alignment());
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(combined && combinedHit.score() >= minsc) {
assert_leq(combinedHit.trim5(), combinedHit.rdoff());
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
combinedHit,
combinedHit.rdoff() - combinedHit.trim5(),
combinedHit.len() + combinedHit.trim5(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
}
}
}
}
GenomeHit<index_t> tempHit = hit;
assert(tempHit.trim5() == 0 || hitoff == 0);
index_t trimLen = rdlen - hitoff - tempHit.len() - tempHit.trim5();
index_t trimMax = (index_t)((tempHit.score() - max<int64_t>(maxsc, this->_minsc[rdi])) / sc.sc(0));
if(trimLen < trimMax) {
index_t trim3 = rdlen - hitoff - tempHit.len() - tempHit.trim5();
GenomeHit<index_t> trimedHit = tempHit;
trimedHit.trim3(trim3,
rd,
ssdb,
sc,
(index_t)this->_minK_local,
(index_t)tpol.minIntronLen(),
(index_t)tpol.maxIntronLen(),
tpol.minAnchorLen(),
tpol.minAnchorLen_noncan(),
ref);
assert_leq(trimedHit.trim5(), trimedHit.rdoff());
assert_leq(trimedHit.len() + trimedHit.trim5() + trimedHit.trim3(), rdlen);
int64_t tmp_score = trimedHit.score();
if(tmp_score > maxsc && tmp_score >= this->_minsc[rdi]) {
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
trimedHit,
trimedHit.rdoff() - trimedHit.trim5(),
trimedHit.len() + trimedHit.trim5() + trimedHit.trim3(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
// return maxsc;
}
}
// extend the partial alignment directly comparing with the corresponding genomic sequence
// with mismatches or a gap allowed
int64_t minsc = this->_minsc[rdi];
assert_geq(tempHit.score(), minsc);
index_t leftext = (index_t)0, rightext = (index_t)INDEX_MAX;
index_t mm = (index_t)((tempHit.score() - minsc) / sc.mmpMax);
index_t num_mismatch_allowed = 1;
if(rdlen - hitoff - hitlen <= this->_minK_local) {
num_mismatch_allowed = min<index_t>(rdlen - tempHit.rdoff() - tempHit.len(), mm);
}
him.localextatts++;
tempHit.extend(
rd,
gfm,
ref,
altdb,
repeatdb,
ssdb,
swa,
swm,
prm,
sc,
this->_minsc[rdi],
rnd,
(index_t)this->_minK_local,
tpol,
gpol,
leftext,
rightext,
num_mismatch_allowed);
if(!rp.secondary) {
if(rdi == 0) minsc = max(minsc, sink.bestUnp1() - cushion);
else minsc = max(minsc, sink.bestUnp2() - cushion);
}
if(tempHit.score() >= minsc && rightext >= min<index_t>((index_t)this->_minK_local, rdlen - hit.len() - hit.rdoff())) {
assert_eq(tempHit.trim3(), 0);
assert_leq(tempHit.trim5(), tempHit.rdoff());
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
tempHit,
tempHit.rdoff() - tempHit.trim5(),
tempHit.len() + tempHit.trim5(),
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
} else if(hitoff + hitlen + this->_minK_local < rdlen) {
// skip some bases of a read
index_t jumplen = hitoff + hitlen + this->_minK < rdlen ? (index_t)this->_minK : (index_t)this->_minK_local;
assert_lt(hitoff + hitlen + jumplen, rdlen);
assert_leq(hit.len(), hitlen);
int64_t expected_score = hit.score() - (hitlen - hit.len()) / jumplen * sc.mmpMax - sc.mmpMax;
if(expected_score >= minsc) {
assert_eq(hit.trim3(), 0);
int64_t tmp_maxsc = hybridSearch_recur(
sc,
pepol,
tpol,
gpol,
gfm,
altdb,
repeatdb,
ref,
swa,
ssdb,
rdi,
hit,
hitoff,
hitlen + jumplen,
wlm,
prm,
swm,
him,
rnd,
sink,
alignMate,
dep + 1);
maxsc = max<int64_t>(maxsc, tmp_maxsc);
}
}
}
}
return maxsc;
}
#endif /*SPLICED_ALIGNER_H_*/