/* $Id: phi_gapalign.c,v 1.15 2008/07/17 17:55:44 kazimird Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Ilya Dondoshansky * */ /** @file phi_gapalign.c * Functions to perform gapped alignment in PHI BLAST. * Pattern alignment does not contribute to the score. * The main function calls are described below in pseudo code. * *
 * Preliminary gapped alignment (does not align patterns). The following
 * function is called once per query/subject sequence pair.
 *
 * PHIGetGappedScore
 *    for each pattern occurrence in query and in subject {
 *       s_PHIGappedAlignment
 *          Left score = Blast_SemiGappedAlign(...)
 *          Right score = Blast_SemiGappedAlign(...) 
 *    }
 *
 * Alignment with traceback, including alignment of patterns, called for each
 * HSP saved in the preliminary stage.
 * 
 * PHIGappedAlignmentWithTraceback
 *    Left score = Blast_SemiGappedAlign(...)
 *    s_PHIBlastAlignPatterns(...)    
 *    Right score = Blast_SemiGappedAlign(...) 
 * 
*/ #ifndef SKIP_DOXYGEN_PROCESSING static char const rcsid[] = "$Id: phi_gapalign.c,v 1.15 2008/07/17 17:55:44 kazimird Exp $"; #endif /* SKIP_DOXYGEN_PROCESSING */ #include #include #include #include "blast_gapalign_priv.h" #include "pattern_priv.h" /** @todo FIXME Figure out what these mean and document. */ typedef enum { eDiagonalInsert = 1, eDiagonalDelete = 2, eInsertCode = 10, eDeleteCode = 20 } EDiagonalState; /** Returns the cost of an optimum conversion within highDiag and lowDiag * between two sequence segments and appends such a conversion to the current * script. * @param seq1 Points 1 byte before the start of the first sequence segment [in] * @param seq2 Points 1 byte before the start of the second sequence segment [in] * @param end1 Length of the first sequence segment [in] * @param end2 Length of the second sequence segment [in] * @param lowDiag Low diagonal for the alignment [in] * @param highDiag High diagonal for the alignment [in] * @param matrix Scoring matrix [in] * @param gapOpen Gap opening cost [in] * @param gapExtend Gap extension cost [in] * @param alignScript Stores traceback information. [out] */ static Int4 s_Align(Uint1 * seq1, Uint1 * seq2, Int4 end1, Int4 end2, Int4 lowDiag, Int4 highDiag, Int4 **matrix, Int4 gapOpen, Int4 gapExtend, GapPrelimEditBlock* alignScript) { Int4 nextState; /*stores code for next entry in state*/ Int4 score; /*score to return*/ Int4 band; /*number of diagonals between highDiag and lowDiag inclusive*/ Int4 diagIndex; /*loop index over diagonals*/ Int4 leftd, rightd; /* diagonal indices for CC, DD, CP and DP */ BlastGapDP* score_array; /*array for dynamic program information*/ Int4 curd; /* current index for CC, DD CP and DP */ Int4 i; /*loop index*/ Int4 index1; /*index on seq1*/ Int4 temp_sub_score = 0; /*placeholder for a substitution score */ Int4 temp_indel_score = 0; /*placeholder for an indel score */ Int4 tempHorScore; /*dual of temp_indel_score for the case where a horizontal edge (insertion) is the last step*/ BlastGapDP* score_row = NULL; /*points to a row of CD*/ Int4 stateDecoder; /*used to decode the edge information in a state*/ Int4 initialScore; /*score to initialize dynamic program entries*/ Int4 *matrixRow; /*row of score matrix*/ Int1 **state; /*stores dynamic program information*/ Int1 *stateRow; /*holds one row of state*/ Int1 *editInstructions; /*holds instruction for string-to-string edit*/ Int4 index2; /*index on seq2*/ Int4 charCounter; /*counts number of characters involved in optimal edit sequence*/ Int4 charIndex; /*index over character positions in optimal edit sequence*/ Int4 editStep, nextEditStep; /*steps in string conversion sequence*/ const Int4 kMinScore = INT4_MIN/2; Int4 gapCost = gapOpen + gapExtend; /* Boundary cases: end1 <= 0 , end2 <= 0, or highDiag-lowDiag <= 0 */ band = highDiag-lowDiag+1; /* Allocate array of scores. */ score_array = (BlastGapDP*) calloc(band+2, sizeof(BlastGapDP)); state = (Int1 **) malloc(sizeof(Int1 *)*(end1+1)); state[0] = (Int1 *) malloc((end1+1)*(band+2)); for (index1 = 1; index1 <= end1; index1++) state[index1] = state[index1-1]+band+2; /* Initialization */ leftd = 1-lowDiag; rightd = highDiag-lowDiag+1; score_array[leftd].best = 0; state[0][leftd] = -1; initialScore = -gapOpen; for (diagIndex = leftd+1; diagIndex <= rightd; diagIndex++) { score_array[diagIndex].best = initialScore = initialScore-gapExtend; score_array[diagIndex-1].best_gap = initialScore-gapCost; state[0][diagIndex] = eDiagonalInsert; } score_array[rightd+1].best = kMinScore; score_array[rightd].best_gap = kMinScore; score_array[leftd-1].best_gap = -gapCost; score_array[leftd-1].best = kMinScore; for (i = 1; i <= end1; i++) { if (i > end2-highDiag) rightd--; if (leftd > 1) leftd--; matrixRow = matrix[seq1[i]]; temp_indel_score = score_array[leftd].best_gap; nextState = 0; if ((index2 = leftd+lowDiag-1+i) > 0) temp_sub_score = score_array[leftd].best+matrixRow[seq2[index2]]; if (temp_indel_score > temp_sub_score || index2 <= 0) { temp_sub_score = temp_indel_score; nextState = eDiagonalDelete; } tempHorScore = temp_sub_score-gapCost; if (leftd >= 1) { if ((temp_indel_score-= gapExtend) >= tempHorScore) { score_array[leftd-1].best_gap = temp_indel_score; nextState += eDeleteCode; } else { score_array[leftd-1].best_gap = tempHorScore; } } stateRow = &state[i][leftd]; *stateRow++ = nextState; score_array[leftd].best = temp_sub_score; for (curd=leftd+1, score_row = &score_array[curd]; curd <= rightd; curd++) { temp_sub_score = score_row->best + matrixRow[seq2[curd+lowDiag-1+i]]; if ((temp_indel_score=score_row->best_gap) > temp_sub_score) { if (temp_indel_score > tempHorScore) { score_row->best = temp_indel_score; tempHorScore -= gapExtend; (score_row++-1)->best_gap = temp_indel_score-gapExtend; *stateRow++=eDeleteCode + eInsertCode + eDiagonalDelete; } else { score_row->best = tempHorScore; tempHorScore -= gapExtend; (score_row++-1)->best_gap = temp_indel_score-gapExtend; *stateRow++=eDeleteCode + eInsertCode + eDiagonalInsert; } } else if (tempHorScore > temp_sub_score) { score_row->best = tempHorScore; tempHorScore -= gapExtend; (score_row++-1)->best_gap = temp_indel_score-gapExtend; *stateRow++=eDeleteCode + eInsertCode + eDiagonalInsert;; } else { score_row->best = temp_sub_score; if ((temp_sub_score -= gapCost) > (tempHorScore-=gapExtend)) { tempHorScore = temp_sub_score; nextState = 0; } else { nextState = eInsertCode; } if (temp_sub_score > (temp_indel_score -= gapExtend)) { *stateRow++= nextState; (score_row++-1)->best_gap = temp_sub_score; } else { *stateRow++ = nextState+eDeleteCode; (score_row++-1)->best_gap = temp_indel_score; } } } } /* decide which path to be traced back */ score = (score_row-1)->best; editInstructions = (Int1*) malloc(end1+end2); for (index1 = end1, diagIndex = rightd, editStep=0, charCounter = 0; index1>=0; index1--, charCounter++) { nextEditStep = (stateDecoder=state[index1][diagIndex]) % eInsertCode; if (stateDecoder == -1) break; if (editStep == eDiagonalInsert && ((stateDecoder/eInsertCode)%2) == 1) nextEditStep = eDiagonalInsert; if (editStep == eDiagonalDelete && (stateDecoder/eDeleteCode)== 1) nextEditStep = eDiagonalDelete; if (nextEditStep == eDiagonalInsert) { diagIndex--; index1++; } else if (nextEditStep == eDiagonalDelete) { diagIndex++; } editInstructions[charCounter] = editStep = nextEditStep; } for (charIndex = charCounter-1; charIndex >= 0; charIndex--) { switch(editInstructions[charIndex]) { case 0: GapPrelimEditBlockAdd(alignScript, eGapAlignSub, 1); break; case eDiagonalInsert: GapPrelimEditBlockAdd(alignScript, eGapAlignDel, 1); break; case eDiagonalDelete: GapPrelimEditBlockAdd(alignScript, eGapAlignIns, 1); break; } } sfree(editInstructions); sfree(state[0]); sfree(state); sfree(score_array); return(score); } /** k-symbol indel cost. * @param gap_open Gap opening cost [in] * @param gap_extend Gap extension cost [in] * @param length Length of a gap [in] * @return Total cost of this gap = gap open + (gap extend)*length. */ static Int4 s_GapCost(Int4 gap_open, Int4 gap_extend, Int4 length) { return (length <= 0 ? 0 : (gap_open + gap_extend*length)); } /** Do a banded gapped alignment of two sequences. * @param seq1 First sequence [in] * @param seq2 Second sequence [in] * @param start1 Starting position in seq1 [in] * @param start2 Starting position in seq2 [in] * @param lowDiag Low diagonal in the banded alignment [in] * @param highDiag High diagonal in the banded alignment [in] * @param matrix Scoring matrix [in] * @param gapOpen Gap opening penalty [in] * @param gapExtend Gap extension penalty [in] * @param alignScript Stores traceback information [in] [out] * @return Alignment score. */ static Int4 s_BandedAlign(Uint1 *seq1, Uint1 *seq2,Int4 start1, Int4 start2, Int4 lowDiag, Int4 highDiag, Int4 **matrix, Int4 gapOpen, Int4 gapExtend, GapPrelimEditBlock* alignScript) { Int4 score; /*score to return*/ Int4 i; /*index over sequences*/ lowDiag = MIN(MAX(-start1, lowDiag),MIN(start2-start1,0)); highDiag = MAX(MIN(start2, highDiag),MAX(start2-start1,0)); if (start2 <= 0) { if (start1 > 0) GapPrelimEditBlockAdd(alignScript, eGapAlignIns, start1); return -s_GapCost(gapOpen, gapExtend, start1); } if (start1 <= 0) { GapPrelimEditBlockAdd(alignScript, eGapAlignDel, start2); return -s_GapCost(gapOpen, gapExtend, start2); } if ((highDiag-lowDiag+1) <= 1) { score = 0; for (i = 1; i <= start1; i++) { GapPrelimEditBlockAdd(alignScript, eGapAlignSub, 1); score += matrix[seq1[i]][seq2[i]]; } return score; } score = s_Align(seq1, seq2, start1, start2, lowDiag, highDiag, matrix, gapOpen, gapExtend, alignScript); return score; } /** Finds the position of the first pattern match in an input sequence, if * pattern consists of a single word. * The existence of the pattern in sequence must be already established. * @param seq Sequence to find pattern in [in] * @param len Length of seq [in] * @param start Start of pattern [out] * @param end End of pattern [out] * @param pattern_blk Pattern information [in] */ static Int2 s_PHIGetShortPattern(Uint1 *seq, Int4 len, Int4 *start, Int4 *end, SPHIPatternSearchBlk *pattern_blk) { Int4 mask; /*mask of input pattern positions after which a match can be declared*/ Int4 maskShiftPlus1; /*mask shifted left plus 1*/ Int4 prefixMatchedBitPattern = 0; /*indicates where pattern aligns with seq; e.g., if value is 9 = 0101 then last 3 chars of seq match first 3 positions in pattern and last 1 char of seq matches 1 position of pattern*/ Int4 i; /*index over seq */ Int4 rightOne; /*loop index looking for 1 in both mask and prefixMatchedBitPattern*/ Int4 rightMaskOnly; /*rightmost bit that is 1 in the mask only*/ SShortPatternItems* word_items = pattern_blk->one_word_items; mask = word_items->match_mask; maskShiftPlus1 = (mask << 1) +1; for (i = 0, prefixMatchedBitPattern= 0; i < len; i++) { prefixMatchedBitPattern = ((prefixMatchedBitPattern << 1) | maskShiftPlus1) & word_items->whichPositionPtr[seq[i]]; } _PHIGetRightOneBits(prefixMatchedBitPattern, mask, &rightOne, &rightMaskOnly); *start = rightMaskOnly + 1; *end = rightOne; return 0; } /** Finds the position of the first pattern match in an input sequence, if * pattern consists of a more than one word. The existence of the pattern in * sequence must be already established. * @param seq Sequence to find pattern in [in] * @param len Length of seq [in] * @param start Start of pattern [out] * @param end End of pattern [out] * @param pattern_blk Pattern information [in] */ static void s_PHIGetLongPattern(Uint1 *seq, Int4 len, Int4 *start, Int4 *end, SPHIPatternSearchBlk *pattern_blk) { Int4 *mask; /*mask of input pattern positions after which a match can be declared*/ Int4 *prefixMatchedBitPattern; /*indicates where pattern aligns with seq*/ Int4 wordIndex; /*index over words in pattern*/ Int4 i; /*index over seq*/ Int4 rightMaskOnly; /*rightmost bit that is 1 in the mask only*/ Int4 j = 0; /*index over bits in a word*/ Boolean found = FALSE; /*found match position yet*/ SLongPatternItems* multiword_items = pattern_blk->multi_word_items; Int4 num_words = multiword_items->numWords; mask = (Int4 *) calloc(num_words, sizeof(Int4)); prefixMatchedBitPattern = (Int4 *) calloc(num_words, sizeof(Int4)); for (wordIndex = 0; wordIndex < num_words; wordIndex++) { mask[wordIndex] = multiword_items->match_maskL[wordIndex]; prefixMatchedBitPattern[wordIndex] = 0; } _PHIPatternWordsLeftShift(mask, 1, num_words); for (i = 0; i < len; i++) { _PHIPatternWordsLeftShift(prefixMatchedBitPattern, 0, num_words); _PHIPatternWordsBitwiseOr(prefixMatchedBitPattern, mask, num_words); _PHIPatternWordsBitwiseAnd(prefixMatchedBitPattern, prefixMatchedBitPattern, multiword_items->bitPatternByLetter[seq[i]], num_words); } _PHIPatternWordsBitwiseAnd(prefixMatchedBitPattern, prefixMatchedBitPattern, multiword_items->match_maskL, num_words); rightMaskOnly = -1; for (wordIndex = 0; (wordIndex < num_words) && (!found); wordIndex++) { for (j = 0; j < PHI_BITS_PACKED_PER_WORD && (!found); j++) { if ((prefixMatchedBitPattern[wordIndex]>>j) % 2 == 1) found = TRUE; else if ((multiword_items->match_maskL[wordIndex] >> j)%2 == 1) rightMaskOnly = wordIndex*PHI_BITS_PACKED_PER_WORD+j; } } if (found) { wordIndex--; j --; } sfree(prefixMatchedBitPattern); sfree(mask); *start = rightMaskOnly+1; *end = wordIndex*PHI_BITS_PACKED_PER_WORD+j; } /** Maximal possible size of the hits array for one word of pattern. */ #define MAX_HITS_IN_WORD 64 /** Find pattern occurrences in seq when the pattern description is * extra long, report the results back in hitArray * @param seq Sequence to find pattern in [in] * @param len Length of seq [in] * @param hitArray Stores pairs of length/position for matches [out] * @param pattern_blk All necessary information about pattern [in] */ static Int2 s_PHIGetExtraLongPattern(Uint1 *seq, Int4 len, Int4 *hitArray, SPHIPatternSearchBlk *pattern_blk) { Int4 i, j; /*indices on one word hits*/ Int4 wordIndex, wordIndex2; /*indices on words in pattern representation*/ Int4 twiceHitsOneWord; /*Twice the number of hits against one word of the pattern*/ Int4 hitIndex; /*index over hits against one word*/ Int4 pos = 0; /*keeps track of how many intermediate hits*/ Int4 hitArray1[PHI_MAX_HIT]; Int4 oneWordHitArray[MAX_HITS_IN_WORD]; /*hits for one word of pattern representation*/ SShortPatternItems* one_word_items = pattern_blk->one_word_items; SLongPatternItems* multiword_items = pattern_blk->multi_word_items; SExtraLongPatternItems* extra_items = multiword_items->extra_long_items; Int4 num_words = multiword_items->numWords; i = 1; hitArray[0] = extra_items->numPlacesInWord[0]; for (wordIndex = 1; wordIndex < num_words; wordIndex++) { one_word_items->whichPositionPtr = multiword_items->SLL[wordIndex]; one_word_items->match_mask = multiword_items->match_maskL[wordIndex]; pos = 0; for (j = 0; j < i; j += wordIndex) { Int4 lastOffset = hitArray[j+wordIndex-1]; twiceHitsOneWord = _PHIBlastFindHitsShort(oneWordHitArray, seq + lastOffset, MIN(len-lastOffset, extra_items->spacing[wordIndex-1] + extra_items->numPlacesInWord[wordIndex]), pattern_blk); for (hitIndex = 0; hitIndex < twiceHitsOneWord; hitIndex+= 2, pos+= wordIndex+1) { for (wordIndex2 = 0; wordIndex2 < wordIndex; wordIndex2++) hitArray1[pos+wordIndex2] = hitArray[j+wordIndex2]; hitArray1[pos+wordIndex2] = hitArray1[pos+wordIndex2-1] + oneWordHitArray[hitIndex] + 1; } } i = pos; for (j = 0; j < pos; j++) hitArray[j] = hitArray1[j]; } for (j = 0; j < pos; j+= num_words) { if (hitArray[j+num_words-1] == len) { for (i = 0; i < num_words; i++) hitArray[i] = hitArray[i+j]; return 0; } } /* This point should never be reached. */ return -1; } /** Align pattern occurrences of the query and subject sequences. * @param querySeq Pointer to start of pattern in query [in] * @param dbSeq Pointer to start of pattern in subject [in] * @param lenQuerySeq Length of pattern occurrence in query [in] * @param lenDbSeq Length of pattern occurrence in subject [in] * @param alignScript Traceback script [out] * @param score_options Scoring options [in] * @param score_matrix Scoring matrix [in] * @param pattern_blk Structure with information about pattern [in] * @return Score for this alignment. */ static Int4 s_PHIBlastAlignPatterns(Uint1 *querySeq, Uint1 *dbSeq, Int4 lenQuerySeq, Int4 lenDbSeq, GapPrelimEditBlock *alignScript, const BlastScoringOptions* score_options, SBlastScoreMatrix* score_matrix, SPHIPatternSearchBlk *pattern_blk) { const int kBandLow = -5; const int kBandHigh = 5; Int4 startQueryMatch, endQueryMatch; /*positions delimiting where query matches pattern first */ Int4 startDbMatch, endDbMatch; /*positions delimiting where database sequence matches pattern first*/ Int4 local_score; /*score for return*/ Int4 queryMatchOffset, dbMatchOffset; /*offset from sequence start where pattern character matches, used as indices*/ Int4 patternPosQuery, patternPosDb; /*positions in pattern for matches to query and database sequences*/ Int4 placeIndex; /*index over places in pattern*/ Int4 *hitArray1=NULL, *hitArray2=NULL; Int4 gap_open; /*gap opening penalty*/ Int4 gap_extend; /*gap extension penalty*/ Int4** matrix = score_matrix->data; SLongPatternItems* multiword_items = pattern_blk->multi_word_items; gap_open = score_options->gap_open; gap_extend = score_options->gap_extend; startQueryMatch = 0; endQueryMatch = lenQuerySeq - 1; startDbMatch = 0; endDbMatch = lenDbSeq - 1; local_score = 0; if (pattern_blk->flagPatternLength == eOneWord) { s_PHIGetShortPattern(querySeq, lenQuerySeq, &startQueryMatch, &endQueryMatch, pattern_blk); s_PHIGetShortPattern(dbSeq, lenDbSeq, &startDbMatch, &endDbMatch, pattern_blk); } else if (pattern_blk->flagPatternLength == eMultiWord) { s_PHIGetLongPattern(querySeq, lenQuerySeq, &startQueryMatch, &endQueryMatch, pattern_blk); s_PHIGetLongPattern(dbSeq, lenDbSeq, &startDbMatch, &endDbMatch, pattern_blk); } else { Int4 QueryWord, DbWord; Int4 QueryVarSize, DbVarSize; SExtraLongPatternItems* extra_items = multiword_items->extra_long_items; hitArray1 = calloc(PHI_MAX_HIT, sizeof(Int4)); hitArray2 = calloc(PHI_MAX_HIT, sizeof(Int4)); /* Populate the hit arrays by matching the pattern to the query and subject sequence segments. */ s_PHIGetExtraLongPattern(querySeq, lenQuerySeq, hitArray1, pattern_blk); s_PHIGetExtraLongPattern(dbSeq, lenDbSeq, hitArray2, pattern_blk); queryMatchOffset = dbMatchOffset = 0; QueryWord = DbWord = 0; QueryVarSize = DbVarSize = 0; for (placeIndex = 0; placeIndex < extra_items->highestPlace; placeIndex++) { Int4 patternWord = multiword_items->inputPatternMasked[placeIndex]; if (patternWord < 0) { QueryVarSize += hitArray1[QueryWord] - hitArray1[QueryWord-1] - extra_items->numPlacesInWord[QueryWord]; DbVarSize += hitArray2[DbWord] - hitArray2[DbWord-1] - extra_items->numPlacesInWord[DbWord]; } else if (patternWord == kMaskAaAlphabetBits) { QueryVarSize++; DbVarSize++; } else { if (QueryVarSize || DbVarSize) { if (QueryVarSize == DbVarSize) { GapPrelimEditBlockAdd(alignScript, eGapAlignSub, QueryVarSize); } else { local_score += s_BandedAlign(querySeq-1, dbSeq-1, QueryVarSize, DbVarSize, kBandLow, kBandHigh, matrix, gap_open, gap_extend, alignScript); } queryMatchOffset += QueryVarSize; querySeq += QueryVarSize; dbMatchOffset += DbVarSize; dbSeq += DbVarSize; } GapPrelimEditBlockAdd(alignScript, eGapAlignSub, 1); queryMatchOffset++; querySeq++; dbMatchOffset++; dbSeq++; QueryVarSize = DbVarSize = 0; } if (queryMatchOffset + QueryVarSize >= hitArray1[QueryWord]) QueryWord++; if (dbMatchOffset + DbVarSize >= hitArray2[DbWord]) DbWord++; } sfree(hitArray1); sfree(hitArray2); return local_score; } for (patternPosQuery = startQueryMatch, patternPosDb = startDbMatch; patternPosQuery <= endQueryMatch || patternPosDb <= endDbMatch; ) { if (multiword_items->inputPatternMasked[patternPosQuery] != kMaskAaAlphabetBits && multiword_items->inputPatternMasked[patternPosDb] != kMaskAaAlphabetBits) { GapPrelimEditBlockAdd(alignScript, eGapAlignSub, 1); patternPosQuery++; patternPosDb++; querySeq++; dbSeq++; } else { for (queryMatchOffset =0; multiword_items->inputPatternMasked[patternPosQuery] == kMaskAaAlphabetBits && patternPosQuery <= endQueryMatch; patternPosQuery++, queryMatchOffset++) ; for (dbMatchOffset = 0; multiword_items->inputPatternMasked[patternPosDb] == kMaskAaAlphabetBits && patternPosDb <= endDbMatch; patternPosDb++, dbMatchOffset++) ; if (queryMatchOffset == dbMatchOffset) { do { GapPrelimEditBlockAdd(alignScript, eGapAlignSub, 1); querySeq++; dbSeq++; queryMatchOffset--; } while (queryMatchOffset > 0); } else { local_score += s_BandedAlign(querySeq-1, dbSeq-1, queryMatchOffset, dbMatchOffset, kBandLow, kBandHigh, matrix, gap_open, gap_extend, alignScript); querySeq+=queryMatchOffset; dbSeq+=dbMatchOffset; } } } return local_score; } /** Performs gapped extension for PHI BLAST, given two * sequence blocks, scoring and extension options, and an initial HSP * with information from the previously performed ungapped extension * @param query_blk The query sequence block [in] * @param subject_blk The subject sequence block [in] * @param gap_align The auxiliary structure for gapped alignment [in] * @param score_params Parameters related to scoring [in] * @param query_offset Start of pattern in query [in] * @param subject_offset Start of pattern in subject [in] * @param query_length Length of pattern in query [in] * @param subject_length Length of pattern in subject [in] */ static Int2 s_PHIGappedAlignment(BLAST_SequenceBlk* query_blk, BLAST_SequenceBlk* subject_blk, BlastGapAlignStruct* gap_align, const BlastScoringParameters* score_params, Int4 query_offset, Int4 subject_offset, Int4 query_length, Int4 subject_length) { Boolean found_start, found_end; Int4 q_length=0, s_length=0, score_right, score_left; Int4 private_q_start, private_s_start; Uint1* query,* subject; if (gap_align == NULL) return -1; q_length = query_offset; s_length = subject_offset; query = query_blk->sequence; subject = subject_blk->sequence; found_start = FALSE; found_end = FALSE; /* Looking for "left" score */ score_left = 0; if (q_length != 0 && s_length != 0) { found_start = TRUE; score_left = Blast_SemiGappedAlign(query, subject, q_length, s_length, &private_q_start, &private_s_start, TRUE, NULL, gap_align, score_params, query_offset, FALSE, TRUE, NULL); gap_align->query_start = q_length - private_q_start + 1; gap_align->subject_start = s_length - private_s_start + 1; } /* Pattern itself is not included in the gapped alignment */ q_length += query_length - 1; s_length += subject_length - 1; score_right = 0; if (q_length < query_blk->length && s_length < subject_blk->length) { found_end = TRUE; score_right = Blast_SemiGappedAlign(query+q_length, subject+s_length, query_blk->length-q_length-1, subject_blk->length-s_length-1, &(gap_align->query_stop), &(gap_align->subject_stop), TRUE, NULL, gap_align, score_params, q_length, FALSE, FALSE, NULL); gap_align->query_stop += q_length; gap_align->subject_stop += s_length; } if (found_start == FALSE) { /* Start never found */ gap_align->query_start = query_offset; gap_align->subject_start = subject_offset; } if (found_end == FALSE) { gap_align->query_stop = query_offset + query_length; gap_align->subject_stop = subject_offset + subject_length; } gap_align->score = score_right+score_left; return 0; } Int2 PHIGetGappedScore (EBlastProgramType program_number, BLAST_SequenceBlk* query, BlastQueryInfo* query_info, BLAST_SequenceBlk* subject, BlastGapAlignStruct* gap_align, const BlastScoringParameters* score_params, const BlastExtensionParameters* ext_params, const BlastHitSavingParameters* hit_params, BlastInitHitList* init_hitlist, BlastHSPList** hsp_list_ptr, BlastGappedStats* gapped_stats, Boolean * fence_hit) { BlastHSPList* hsp_list; BlastInitHSP* init_hsp; Int4 index; Int2 status = 0; BlastHitSavingOptions* hit_options; Int4 pattern_index; Int4 num_patterns; Int4 HspNumMax=0; /* PHI does not support partial fetching at the moment. */ ASSERT(! fence_hit); if (!query || !subject || !gap_align || !score_params || !hit_params || !init_hitlist || !hsp_list_ptr) return -1; if (init_hitlist->total == 0) return 0; hit_options = hit_params->options; HspNumMax = BlastHspNumMax(score_params->options->gapped_calculation, hit_options); if (*hsp_list_ptr == NULL) *hsp_list_ptr = hsp_list = Blast_HSPListNew(HspNumMax); else hsp_list = *hsp_list_ptr; num_patterns = query_info->pattern_info->num_patterns; for (pattern_index = 0; pattern_index < num_patterns; ++pattern_index) { SPHIPatternInfo* query_pattern = &query_info->pattern_info->occurrences[pattern_index]; Uint4 q_pat_offset = query_pattern->offset; Uint4 q_pat_length = query_pattern->length; for (index=0; indextotal; index++) { BlastHSP* new_hsp; Int4 s_pat_offset, s_pat_length; init_hsp = &init_hitlist->init_hsp_array[index]; s_pat_offset = init_hsp->offsets.phi_offsets.s_start; s_pat_length = init_hsp->offsets.phi_offsets.s_end - init_hsp->offsets.phi_offsets.s_start + 1; if (gapped_stats) ++gapped_stats->extensions; status = s_PHIGappedAlignment(query, subject, gap_align, score_params, q_pat_offset, s_pat_offset, q_pat_length, s_pat_length); if (status) { return status; } /* PHI BLAST does not support query concatenation, so context is always 0. */ if (gap_align->score >= hit_params->cutoff_score_min) { Blast_HSPInit(gap_align->query_start, gap_align->query_stop, gap_align->subject_start, gap_align->subject_stop, q_pat_offset, s_pat_offset, 0, query_info->contexts[0].frame, subject->frame, gap_align->score, &(gap_align->edit_script), &new_hsp); /* Save pattern index and subject length in the HSP structure. */ new_hsp->pat_info = (SPHIHspInfo*) malloc(sizeof(SPHIHspInfo)); new_hsp->pat_info->index = pattern_index; new_hsp->pat_info->length = s_pat_length; Blast_HSPListSaveHSP(hsp_list, new_hsp); } } } /* Sort the HSP array by score */ Blast_HSPListSortByScore(hsp_list); *hsp_list_ptr = hsp_list; return status; } Int2 PHIGappedAlignmentWithTraceback(Uint1* query, Uint1* subject, BlastGapAlignStruct* gap_align, const BlastScoringParameters* score_params, Int4 q_start, Int4 s_start, Int4 query_length, Int4 subject_length, Int4 q_pat_length, Int4 s_pat_length, SPHIPatternSearchBlk *pattern_blk) { Boolean found_end; Int4 score_right, score_left, private_q_length, private_s_length; Int2 status = 0; GapPrelimEditBlock *fwd_prelim_tback; GapPrelimEditBlock *rev_prelim_tback; GapPrelimEditBlock *pat_prelim_tback = GapPrelimEditBlockNew(); if (!gap_align || !score_params || !pattern_blk) return -1; fwd_prelim_tback = gap_align->fwd_prelim_tback; rev_prelim_tback = gap_align->rev_prelim_tback; GapPrelimEditBlockReset(fwd_prelim_tback); GapPrelimEditBlockReset(rev_prelim_tback); found_end = FALSE; score_left = 0; score_left = Blast_SemiGappedAlign(query, subject, q_start, s_start, &private_q_length, &private_s_length, FALSE, rev_prelim_tback, gap_align, score_params, q_start, FALSE, TRUE, NULL); gap_align->query_start = q_start - private_q_length; gap_align->subject_start = s_start - private_s_length; s_PHIBlastAlignPatterns(query+q_start, subject+s_start, q_pat_length, s_pat_length, pat_prelim_tback, score_params->options, gap_align->sbp->matrix, pattern_blk); /* Pattern traceback and left alignment traceback are both going in forward direction, so the former can be simply appended to the end of the latter. */ GapPrelimEditBlockAppend(rev_prelim_tback, pat_prelim_tback); GapPrelimEditBlockFree(pat_prelim_tback); score_right = 0; q_start += q_pat_length - 1; s_start += s_pat_length - 1; if ((q_start < query_length) && (s_start < subject_length)) { found_end = TRUE; score_right = Blast_SemiGappedAlign(query+q_start, subject+s_start, query_length-q_start-1, subject_length-s_start-1, &private_q_length, &private_s_length, FALSE, fwd_prelim_tback, gap_align, score_params, q_start, FALSE, FALSE, NULL); gap_align->query_stop = q_start + private_q_length + 1; gap_align->subject_stop = s_start + private_s_length + 1; } if (found_end == FALSE) { gap_align->query_stop = q_start; gap_align->subject_stop = s_start; } gap_align->edit_script = Blast_PrelimEditBlockToGapEditScript(rev_prelim_tback, fwd_prelim_tback); gap_align->score = score_right + score_left; return status; }