blast_traceback.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:41k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: blast_traceback.c,v $
  4.  * PRODUCTION Revision 1000.5  2004/06/01 18:07:53  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.110
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: blast_traceback.c,v 1000.5 2004/06/01 18:07:53 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's offical duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author: Ilya Dondoshansky
  35.  *
  36.  */
  37. /** @file blast_traceback.c
  38.  * Functions responsible for the traceback stage of the BLAST algorithm
  39.  */
  40. static char const rcsid[] = 
  41.     "$Id: blast_traceback.c,v 1000.5 2004/06/01 18:07:53 gouriano Exp $";
  42. #include <algo/blast/core/blast_traceback.h>
  43. #include <algo/blast/core/blast_util.h>
  44. #include <algo/blast/core/link_hsps.h>
  45. #include <algo/blast/core/blast_setup.h>
  46. #include <algo/blast/core/blast_kappa.h>
  47. #include "blast_psi_priv.h"
  48. /* Comparison function for sorting HSPs by score. 
  49.  * Ties are broken based on subject sequence offsets.
  50.  */
  51. static int
  52. score_compare_hsps(const void* v1, const void* v2)
  53. {
  54.    BlastHSP* h1,* h2;
  55.    BlastHSP** hp1,** hp2;
  56.    
  57.    hp1 = (BlastHSP**) v1;
  58.    hp2 = (BlastHSP**) v2;
  59.    h1 = *hp1;
  60.    h2 = *hp2;
  61.    
  62.    if (h1 == NULL || h2 == NULL)
  63.       return 0;
  64.    
  65.    if (h1->score < h2->score) 
  66.       return 1;
  67.    if (h1->score > h2->score)
  68.       return -1;
  69.    
  70.    if( h1->subject.offset < h2->subject.offset )
  71.       return 1;
  72.    if( h1->subject.offset > h2->subject.offset )
  73.       return -1;
  74.    
  75.    if( h1->subject.end < h2->subject.end )
  76.       return 1;
  77.    if( h1->subject.end > h2->subject.end )
  78.       return -1;
  79.    
  80.    return 0;
  81. }
  82. /** TRUE if c is between a and b; f between d and f.  Determines if the
  83.  * coordinates are already in an HSP that has been evaluated. 
  84. */
  85. #define CONTAINED_IN_HSP(a,b,c,d,e,f) (((a <= c && b >= c) && (d <= f && e >= f)) ? TRUE : FALSE)
  86. static void BLASTCheckHSPInclusion(BlastHSP* *hsp_array, Int4 hspcnt, 
  87.                                    Boolean is_ooframe)
  88. {
  89.    Int4 index, index1;
  90.    BlastHSP* hsp,* hsp1;
  91.    
  92.    for (index = 0; index < hspcnt; index++) {
  93.       hsp = hsp_array[index];
  94.       
  95.       if (hsp == NULL)
  96.          continue;
  97.       
  98.       for (index1 = 0; index1 < index; index1++) {
  99.          hsp1 = hsp_array[index1];
  100.          
  101.          if (hsp1 == NULL)
  102.             continue;
  103.          
  104.          if(is_ooframe) {
  105.             if (SIGN(hsp1->query.frame) != SIGN(hsp->query.frame))
  106.                continue;
  107.          } else {
  108.             if (hsp->context != hsp1->context)
  109.                continue;
  110.          }
  111.          
  112.          /* Check of the start point of this HSP */
  113.          if (CONTAINED_IN_HSP(hsp1->query.offset, hsp1->query.end, 
  114.                 hsp->query.offset, hsp1->subject.offset, hsp1->subject.end, 
  115.                 hsp->subject.offset) == TRUE) {
  116.             /* Check of the end point of this HSP */
  117.             if (CONTAINED_IN_HSP(hsp1->query.offset, hsp1->query.end, 
  118.                    hsp->query.end, hsp1->subject.offset, hsp1->subject.end, 
  119.                    hsp->subject.end) == TRUE) {
  120.                /* Now checking correct strand */
  121.                if (SIGN(hsp1->query.frame) == SIGN(hsp->query.frame) &&
  122.                    SIGN(hsp1->subject.frame) == SIGN(hsp->subject.frame)){
  123.                   
  124.                   /* If we come here through all these if-s - this
  125.                      mean, that current HSP should be removed. */
  126.                   
  127.                   if(hsp_array[index] != NULL) {
  128.                      hsp_array[index] = Blast_HSPFree(hsp_array[index]);
  129.                      break;
  130.                   }
  131.                }
  132.             }
  133.          }
  134.       }
  135.    }
  136.    return;
  137. }
  138. /* Window size used to scan HSP for highest score region, where gapped
  139.  * extension starts. 
  140.  */
  141. #define HSP_MAX_WINDOW 11
  142. /** Function to check that the highest scoring region in an HSP still gives a 
  143.  * positive score. This value was originally calcualted by 
  144.  * GetStartForGappedAlignment but it may have changed due to the introduction 
  145.  * of ambiguity characters. Such a change can lead to 'strange' results from 
  146.  * ALIGN. 
  147.  * @param hsp An HSP structure [in]
  148.  * @param query Query sequence buffer [in]
  149.  * @param subject Subject sequence buffer [in]
  150.  * @param sbp Scoring block containing matrix [in]
  151.  * @return TRUE if region aroung starting offsets gives a positive score
  152. */
  153. static Boolean
  154. BLAST_CheckStartForGappedAlignment (BlastHSP* hsp, Uint1* query, 
  155.                                     Uint1* subject, const BlastScoreBlk* sbp)
  156. {
  157.    Int4 index1, score, start, end, width;
  158.    Uint1* query_var,* subject_var;
  159.    Boolean positionBased = (sbp->posMatrix != NULL);
  160.    
  161.    width = MIN((hsp->query.gapped_start-hsp->query.offset), HSP_MAX_WINDOW/2);
  162.    start = hsp->query.gapped_start - width;
  163.    end = MIN(hsp->query.end, hsp->query.gapped_start + width);
  164.    /* Assures that the start of subject is above zero. */
  165.    if ((hsp->subject.gapped_start + start - hsp->query.gapped_start) < 0)
  166.       start -= hsp->subject.gapped_start + (start - hsp->query.gapped_start);
  167.    query_var = query + start;
  168.    subject_var = subject + hsp->subject.gapped_start + 
  169.       (start - hsp->query.gapped_start);
  170.    score=0;
  171.    for (index1=start; index1<end; index1++)
  172.       {
  173.          if (!positionBased)
  174.     score += sbp->matrix[*query_var][*subject_var];
  175.          else
  176.     score += sbp->posMatrix[index1][*subject_var];
  177.          query_var++; subject_var++;
  178.       }
  179.    if (score <= 0)
  180.       return FALSE;
  181.    
  182.    return TRUE;
  183. }
  184. static Int4 GetPatternLengthFromBlastHSP(BlastHSP* hsp)
  185. {
  186.    return hsp->pattern_length;
  187. }
  188. static void SavePatternLengthInGapAlignStruct(Int4 length,
  189.                BlastGapAlignStruct* gap_align)
  190. {
  191.    /* Kludge: save length in an output structure member, to avoid introducing 
  192.       a new structure member. Probably should be changed??? */
  193.    gap_align->query_stop = length;
  194. }
  195. #define MAX_FULL_TRANSLATION 2100
  196. /** Translate the subject sequence into 6 frames, and create a mixed-frame 
  197.  * sequnce if out-of-frame gapping will be used.
  198.  * @param subject_blk Subject sequence structure [in]
  199.  * @param gen_code_string Genetic code to use for translation [in]
  200.  * @param translation_buffer_ptr Pointer to buffer to hold the 
  201.  *                               translated sequence(s) [out]
  202.  * @param frame_offsets_ptr Pointer to an array to hold offsets into the
  203.  *                          translation buffer for each frame. Mixed-frame 
  204.  *                          sequence is to be returned, if NULL. [in] [out]
  205.  * @param partial_translation_ptr Should partial translations be performed later
  206.  *                                for each HSP instead of a full 
  207.  *                                translation? [out]
  208. */
  209. static Int2
  210. SetUpSubjectTranslation(BLAST_SequenceBlk* subject_blk, 
  211.                         const Uint1* gen_code_string,
  212.                         Uint1** translation_buffer_ptr, 
  213.                         Int4** frame_offsets_ptr,
  214.                         Boolean* partial_translation_ptr)
  215. {
  216.    Boolean partial_translation;
  217.    Boolean is_ooframe = (frame_offsets_ptr == NULL);
  218.    if (!gen_code_string)
  219.       return -1;
  220.    if (is_ooframe && subject_blk->oof_sequence) {
  221.       /* If mixed-frame sequence is already available (two-sequences case),
  222.          then no need to translate again */
  223.       *partial_translation_ptr = FALSE;
  224.       return 0;
  225.    } 
  226.    *partial_translation_ptr = partial_translation = 
  227.       (subject_blk->length > MAX_FULL_TRANSLATION);
  228.       
  229.    if (!partial_translation) {
  230.       if (is_ooframe) {
  231.          BLAST_GetAllTranslations(subject_blk->sequence_start, 
  232.             NCBI4NA_ENCODING, subject_blk->length, gen_code_string, 
  233.             NULL, NULL, &subject_blk->oof_sequence);
  234.       } else {
  235.          BLAST_GetAllTranslations(subject_blk->sequence_start, 
  236.             NCBI4NA_ENCODING, subject_blk->length, gen_code_string, 
  237.             translation_buffer_ptr, frame_offsets_ptr, NULL);
  238.       }
  239.    }
  240.    return 0;
  241. }
  242. /** Performs the translation and coordinates adjustment, if only part of the 
  243.  * subject sequence is translated for gapped alignment. 
  244.  * @param subject_blk Subject sequence structure [in]
  245.  * @param hsp The HSP information [in]
  246.  * @param is_ooframe Return a mixed-frame sequence if TRUE [in]
  247.  * @param gen_code_string Database genetic code [in]
  248.  * @param translation_buffer_ptr Pointer to buffer holding the translation [out]
  249.  * @param subject_ptr Pointer to sequence to be passed to the gapped 
  250.  *                    alignment [out]
  251.  * @param subject_length_ptr Length of the translated sequence [in]
  252.  * @param start_shift_ptr How far is the partial sequence shifted w.r.t. the 
  253.  *                        full sequence. [out]
  254. */
  255. static void 
  256. GetPartialSubjectTranslation(BLAST_SequenceBlk* subject_blk, BlastHSP* hsp,
  257.                              Boolean is_ooframe, const Uint1* gen_code_string, 
  258.                              Uint1** translation_buffer_ptr,
  259.                              Uint1** subject_ptr, Int4* subject_length_ptr,
  260.                              Int4* start_shift_ptr)
  261. {
  262.    Int4 translation_length;
  263.    Uint1* translation_buffer = *translation_buffer_ptr;
  264.    Uint1* subject;
  265.    Int4 start_shift;
  266.    Int4 nucl_shift;
  267.    sfree(translation_buffer);
  268.    if (!is_ooframe) {
  269.       start_shift = 
  270.          MAX(0, 3*hsp->subject.offset - MAX_FULL_TRANSLATION);
  271.       translation_length =
  272.          MIN(3*hsp->subject.end + MAX_FULL_TRANSLATION, 
  273.              subject_blk->length) - start_shift;
  274.       if (hsp->subject.frame > 0) {
  275.          nucl_shift = start_shift;
  276.       } else {
  277.          nucl_shift = subject_blk->length - start_shift 
  278.             - translation_length;
  279.       }
  280.       GetPartialTranslation(subject_blk->sequence_start+nucl_shift, 
  281.                             translation_length, hsp->subject.frame,
  282.                             gen_code_string, &translation_buffer, 
  283.                             subject_length_ptr, NULL);
  284.       /* Below, the start_shift will be used for the protein
  285.          coordinates, so need to divide it by 3 */
  286.       start_shift /= CODON_LENGTH;
  287.    } else {
  288.       Int4 oof_start, oof_end;
  289.       if (hsp->subject.frame > 0) {
  290.          oof_start = 0;
  291.          oof_end = subject_blk->length;
  292.       } else {
  293.          oof_start = subject_blk->length + 1;
  294.          oof_end = 2*subject_blk->length + 1;
  295.       }
  296.       
  297.       start_shift = 
  298.          MAX(oof_start, hsp->subject.offset - MAX_FULL_TRANSLATION);
  299.       translation_length =
  300.          MIN(hsp->subject.end + MAX_FULL_TRANSLATION, 
  301.              oof_end) - start_shift;
  302.       if (hsp->subject.frame > 0) {
  303.          nucl_shift = start_shift - oof_start;
  304.       } else {
  305.          nucl_shift = oof_end - start_shift - translation_length;
  306.       }
  307.       GetPartialTranslation(subject_blk->sequence_start+nucl_shift, 
  308.                             translation_length, hsp->subject.frame, 
  309.                             gen_code_string, NULL, 
  310.                             subject_length_ptr, &translation_buffer);
  311.    }
  312.    hsp->subject.offset -= start_shift;
  313.    hsp->subject.gapped_start -= start_shift;
  314.    *translation_buffer_ptr = translation_buffer;
  315.    *start_shift_ptr = start_shift;
  316.    if (!is_ooframe) {
  317.       subject = translation_buffer + 1;
  318.    } else {
  319.       subject = translation_buffer + CODON_LENGTH;
  320.    }
  321.    *subject_ptr = subject;
  322. }
  323. /** Check whether an HSP is already contain within another higher scoring HSP.
  324.  * "Containment" is defined by the macro CONTAINED_IN_HSP.  
  325.  * the implicit assumption here is that HSP's are sorted by score
  326.  * The main goal of this routine is to eliminate double gapped extensions of HSP's.
  327.  *
  328.  * @param hsp_array Full Array of all HSP's found so far. [in]
  329.  * @param hsp HSP to be compared to other HSP's [in]
  330.  * @param max_index compare above HSP to all HSP's in hsp_array up to max_index [in]
  331.  * @param is_ooframe true if out-of-frame gapped alignment (blastx and tblastn only). [in]
  332.  */
  333. static Boolean
  334. HSPContainedInHSPCheck(BlastHSP** hsp_array, BlastHSP* hsp, Int4 max_index, Boolean is_ooframe)
  335. {
  336.       BlastHSP* hsp1;
  337.       Boolean delete_hsp=FALSE;
  338.       Boolean hsp_start_is_contained=FALSE;
  339.       Boolean hsp_end_is_contained=FALSE;
  340.       Int4 index;
  341.       for (index=0; index<max_index; index++) {
  342.          hsp_start_is_contained = FALSE;
  343.          hsp_end_is_contained = FALSE;
  344.          
  345.          hsp1 = hsp_array[index];
  346.          if (hsp1 == NULL)
  347.             continue;
  348.          
  349.          if(is_ooframe) {
  350.             if (SIGN(hsp1->query.frame) != SIGN(hsp->query.frame))
  351.                continue;
  352.          } else {
  353.             if (hsp->context != hsp1->context)
  354.                continue;
  355.          }
  356.          
  357.          if (CONTAINED_IN_HSP(hsp1->query.offset, hsp1->query.end, hsp->query.offset, hsp1->subject.offset, hsp1->subject.end, hsp->subject.offset) == TRUE) {
  358.             if (SIGN(hsp1->query.frame) == SIGN(hsp->query.frame) &&
  359.                 SIGN(hsp1->subject.frame) == SIGN(hsp->subject.frame))
  360.                hsp_start_is_contained = TRUE;
  361.          }
  362.          if (CONTAINED_IN_HSP(hsp1->query.offset, hsp1->query.end, hsp->query.end, hsp1->subject.offset, hsp1->subject.end, hsp->subject.end) == TRUE) {
  363.             if (SIGN(hsp1->query.frame) == SIGN(hsp->query.frame) &&
  364.                 SIGN(hsp1->subject.frame) == SIGN(hsp->subject.frame))
  365.                hsp_end_is_contained = TRUE;
  366.          }
  367.          if (hsp_start_is_contained && hsp_end_is_contained && hsp->score <= hsp1->score) {
  368.             delete_hsp = TRUE;
  369.             break;
  370.          }
  371.       }
  372.       return delete_hsp;
  373. }
  374. /** Sets some values that will be in the "score" block of the SeqAlign.
  375.  * The values set here are expect value and number of identical matches.
  376.  *
  377.  * @param query_info information about query. [in]
  378.  * @param query query sequence as a raw string [in]
  379.  * @param hsp HPS to operate on [in][out]
  380.  * @param subject database sequence as a raw string [in]
  381.  * @param program_number which program [in]
  382.  * @param sbp the scoring information [in]
  383.  * @param scoring_params Parameters for how to score matches. [in]
  384.  * @param hit_options determines which scores to save. [in]
  385.  */
  386. static Boolean
  387. HSPSetScores(BlastQueryInfo* query_info, Uint1* query, 
  388.    Uint1* subject, BlastHSP* hsp, 
  389.    Uint1 program_number, BlastScoreBlk* sbp,
  390.    const BlastScoringParameters* score_params,
  391.    const BlastHitSavingOptions* hit_options)
  392. {
  393.             Boolean keep = TRUE;
  394.             Int4 align_length = 0;
  395.             double scale_factor = score_params->scale_factor;
  396.             BlastScoringOptions *score_options = score_params->options;
  397.             /* Calculate alignment length and number of 
  398.                identical letters. Do not get the number of 
  399.                identities if the query is not available */
  400.             if (query != NULL) {
  401.                if (score_options->is_ooframe) {
  402.                   Blast_HSPGetOOFNumIdentities(query, subject, hsp, program_number,
  403.                                           &hsp->num_ident, &align_length);
  404.                }
  405.                else {
  406.                      Blast_HSPGetNumIdentities(query, subject, hsp, 
  407.                         score_options->gapped_calculation, &hsp->num_ident, 
  408.                         &align_length);
  409.                }
  410.             }
  411.             if ((hsp->num_ident * 100 < 
  412.                 align_length * hit_options->percent_identity) ||
  413.                 align_length < hit_options->min_hit_length) {
  414.                keep = FALSE;
  415.             }
  416.             
  417.             if (keep == TRUE)
  418.             {
  419.                if (program_number == blast_type_blastp ||
  420.                    program_number == blast_type_rpsblast ||
  421.                    program_number == blast_type_blastn) {
  422.                   Blast_KarlinBlk** kbp;
  423.                   if (score_options->gapped_calculation)
  424.                      kbp = sbp->kbp_gap;
  425.                   else
  426.                      kbp = sbp->kbp;
  427.                   if (hit_options->phi_align) {
  428.                      Blast_HSPPHIGetEvalue(hsp, sbp);
  429.                   } else {
  430.                      hsp->evalue = BLAST_KarlinStoE_simple(hsp->score, kbp[hsp->context],
  431.                           query_info->eff_searchsp_array[hsp->context]);
  432.                   }
  433.                   if (hsp->evalue > hit_options->expect_value) 
  434.                     /* put in for comp. based stats. */
  435.                      keep = FALSE;
  436.                }
  437.                /* remove any scaling of the calculated score */
  438.                hsp->score = (Int4) ((hsp->score+(0.5*scale_factor))/
  439.                                         scale_factor);
  440.                /* only one alignment considered for blast[np]. */
  441.                /* This may be changed by LinkHsps for blastx or tblastn. */
  442.                hsp->num = 1;
  443.                if ((program_number == blast_type_tblastn ||
  444.                     program_number == blast_type_rpstblastn) && 
  445.                      hit_options->longest_intron > 0) {
  446.                    hsp->evalue = 
  447.                      BLAST_KarlinStoE_simple(hsp->score, 
  448.                      sbp->kbp_gap[hsp->context],
  449.                      query_info->eff_searchsp_array[hsp->context]);
  450.                }
  451.            }
  452.            return keep;
  453. }
  454. /** Adjusts offset if out-of-frame and negative frame, or if partial sequence used for extension.
  455.  * @param hsp The hit to work on [in][out]
  456.  * @param subject_blk information about database sequence [in]
  457.  * @param is_ooframe true if out-of-frame (blastx or tblastn) used. [in]
  458.  * @param start_shift amount of database sequence not used for extension. [in]
  459. */
  460. static void
  461. HSPAdjustSubjectOffset(BlastHSP* hsp, BLAST_SequenceBlk* subject_blk, Boolean is_ooframe, Int4 start_shift)
  462. {
  463.             if (is_ooframe) {
  464.                /* Adjust subject offsets for negative frames */
  465.                if (hsp->subject.frame < 0) {
  466.                   Int4 strand_start = subject_blk->length + 1;
  467.                   hsp->subject.offset -= strand_start;
  468.                   hsp->subject.end -= strand_start;
  469.                   hsp->subject.gapped_start -= strand_start;
  470.                   hsp->gap_info->start2 -= strand_start;
  471.                }
  472.             } 
  473.             /* Adjust subject offsets if shifted (partial) sequence was used 
  474.                for extension */
  475.             if (start_shift > 0) {
  476.                hsp->subject.offset += start_shift;
  477.                hsp->subject.end += start_shift;
  478.                hsp->subject.gapped_start += start_shift;
  479.                if (hsp->gap_info)
  480.                   hsp->gap_info->start2 += start_shift;
  481.             }
  482.             return;
  483. }
  484. /** Check whether an HSP is already contained within another higher scoring HSP.
  485.  * This is done AFTER the gapped alignment has been performed
  486.  *
  487.  * @param hsp_array Full Array of all HSP's found so far. [in][out]
  488.  * @param hsp HSP to be compared to other HSP's [in]
  489.  * @param max_index compare above HSP to all HSP's in hsp_array up to max_index [in]
  490.  */
  491. static Boolean
  492. HSPCheckForDegenerateAlignments(BlastHSP** hsp_array, BlastHSP* hsp, Int4 max_index)
  493. {
  494.             BlastHSP* hsp2;
  495.             Boolean keep=TRUE;
  496.             Int4 index;
  497.             for (index=0; index<max_index; index++) {
  498.                hsp2 = hsp_array[index];
  499.                if (hsp2 == NULL)
  500.                   continue;
  501.                
  502.                /* Check if both HSP's start or end on the same diagonal 
  503.                   (and are on same strands). */
  504.                if (((hsp->query.offset == hsp2->query.offset &&
  505.                      hsp->subject.offset == hsp2->subject.offset) ||
  506.                     (hsp->query.end == hsp2->query.end &&
  507.                      hsp->subject.end == hsp2->subject.end))  &&
  508.                    hsp->context == hsp2->context &&
  509.                    hsp->subject.frame == hsp2->subject.frame) {
  510.                   if (hsp2->score > hsp->score) {
  511.                      keep = FALSE;
  512.                      break;
  513.                   } else {
  514.                      hsp_array[index] = Blast_HSPFree(hsp2);
  515.                   }
  516.                }
  517.             }
  518.             return keep;
  519. }
  520. /*
  521.     Comments in blast_traceback.h
  522.  */
  523. Int2
  524. Blast_TracebackFromHSPList(Uint1 program_number, BlastHSPList* hsp_list, 
  525.    BLAST_SequenceBlk* query_blk, BLAST_SequenceBlk* subject_blk, 
  526.    BlastQueryInfo* query_info,
  527.    BlastGapAlignStruct* gap_align, BlastScoreBlk* sbp, 
  528.    const BlastScoringParameters* score_params,
  529.    const BlastExtensionOptions* ext_options,
  530.    const BlastHitSavingParameters* hit_params,
  531.    const Uint1* gen_code_string)
  532. {
  533.    Int4 index;
  534.    BlastHSP* hsp;
  535.    Uint1* query,* subject;
  536.    Int4 query_length, query_length_orig;
  537.    Int4 subject_length=0;
  538.    BlastHSP** hsp_array;
  539.    Int4 q_start, s_start;
  540.    BlastHitSavingOptions* hit_options = hit_params->options;
  541.    BlastScoringOptions* score_options = score_params->options;
  542.    Int4 context_offset;
  543.    Uint1* translation_buffer = NULL;
  544.    Int4* frame_offsets = NULL;
  545.    Boolean partial_translation = FALSE;
  546.    const Boolean k_is_ooframe = score_options->is_ooframe;
  547.    const Boolean kGreedyTraceback = (ext_options->ePrelimGapExt == eGreedyExt);
  548.    const Boolean kTranslateSubject = 
  549.       (program_number == blast_type_tblastn ||
  550.        program_number == blast_type_rpstblastn); 
  551.    if (hsp_list->hspcnt == 0) {
  552.       return 0;
  553.    }
  554.    hsp_array = hsp_list->hsp_array;
  555.    if (kTranslateSubject) {
  556.       if (!gen_code_string)
  557.          return -1;
  558.       if (k_is_ooframe) {
  559.          SetUpSubjectTranslation(subject_blk, gen_code_string,
  560.                                  NULL, NULL, &partial_translation);
  561.          subject = subject_blk->oof_sequence + CODON_LENGTH;
  562.          /* Mixed-frame sequence spans all 6 frames, i.e. both strands
  563.             of the nucleotide sequence. However its start will also be 
  564.             shifted by 3.*/
  565.          subject_length = 2*subject_blk->length - 1;
  566.       } else {
  567.          SetUpSubjectTranslation(subject_blk, gen_code_string,
  568.             &translation_buffer, &frame_offsets, &partial_translation);
  569.          /* subject and subject_length will be set later, for each HSP. */
  570.       }
  571.    } else {
  572.       /* Subject is not translated */
  573.       subject = subject_blk->sequence;
  574.       subject_length = subject_blk->length;
  575.    }
  576.    for (index=0; index < hsp_list->hspcnt; index++) {
  577.       hsp = hsp_array[index];
  578.       if (program_number == blast_type_blastx || 
  579.           program_number == blast_type_tblastx) {
  580.          Int4 context = hsp->context - hsp->context % 3;
  581.          context_offset = query_info->context_offsets[context];
  582.          query_length_orig = 
  583.             query_info->context_offsets[context+3] - context_offset - 1;
  584.          if (k_is_ooframe) {
  585.             query = query_blk->oof_sequence + CODON_LENGTH + context_offset;
  586.             query_length = query_length_orig;
  587.          } else {
  588.             query = query_blk->sequence + 
  589.                query_info->context_offsets[hsp->context];
  590.             query_length = BLAST_GetQueryLength(query_info, hsp->context);
  591.          }
  592.       } else {
  593.          query = query_blk->sequence + 
  594.             query_info->context_offsets[hsp->context];
  595.          query_length = query_length_orig = 
  596.             BLAST_GetQueryLength(query_info, hsp->context);
  597.       }
  598.       /* preliminary RPS blast alignments have not had
  599.          the composition-based correction applied yet, so
  600.          we cannot reliably check whether an HSP is contained
  601.          within another */
  602.       if (program_number == blast_type_rpsblast ||
  603.           !HSPContainedInHSPCheck(hsp_array, hsp, index, k_is_ooframe)) {
  604.          Int4 start_shift = 0;
  605.          Int4 adjusted_s_length;
  606.          Uint1* adjusted_subject;
  607.          if (kTranslateSubject) {
  608.             if (!k_is_ooframe && !partial_translation) {
  609.                Int4 context = FrameToContext(hsp->subject.frame);
  610.                subject = translation_buffer + frame_offsets[context] + 1;
  611.                subject_length = 
  612.                   frame_offsets[context+1] - frame_offsets[context] - 1;
  613.             } else if (partial_translation) {
  614.                GetPartialSubjectTranslation(subject_blk, hsp, k_is_ooframe,
  615.                   gen_code_string, &translation_buffer, &subject,
  616.                   &subject_length, &start_shift);
  617.             }
  618.          }
  619.          if (!hit_options->phi_align && !k_is_ooframe && 
  620.              (((hsp->query.gapped_start == 0 && 
  621.                 hsp->subject.gapped_start == 0) ||
  622.                !BLAST_CheckStartForGappedAlignment(hsp, query, 
  623.                    subject, sbp)))) {
  624.             Int4 max_offset = 
  625.                BlastGetStartForGappedAlignment(query, subject, sbp,
  626.                   hsp->query.offset, hsp->query.length,
  627.                   hsp->subject.offset, hsp->subject.length);
  628.             q_start = max_offset;
  629.             s_start = 
  630.                (hsp->subject.offset - hsp->query.offset) + max_offset;
  631.             hsp->query.gapped_start = q_start;
  632.             hsp->subject.gapped_start = s_start;
  633.          } else {
  634.             if(k_is_ooframe) {
  635.                /* Code below should be investigated for possible
  636.                   optimization for OOF */
  637.                s_start = hsp->subject.gapped_start;
  638.                q_start = hsp->query.gapped_start;
  639.                gap_align->subject_start = 0;
  640.                gap_align->query_start = 0;
  641.             } else {
  642.                q_start = hsp->query.gapped_start;
  643.                s_start = hsp->subject.gapped_start;
  644.             }
  645.          }
  646.          
  647.          adjusted_s_length = subject_length;
  648.          adjusted_subject = subject;
  649.         /* Perform the gapped extension with traceback */
  650.          if (hit_options->phi_align) {
  651.             Int4 pat_length = GetPatternLengthFromBlastHSP(hsp);
  652.             SavePatternLengthInGapAlignStruct(pat_length, gap_align);
  653.             PHIGappedAlignmentWithTraceback(program_number, query, subject,
  654.                gap_align, score_params, q_start, s_start, query_length, 
  655.                subject_length);
  656.          } else {
  657.             if (!kTranslateSubject) {
  658.                AdjustSubjectRange(&s_start, &adjusted_s_length, q_start, 
  659.                                   query_length, &start_shift);
  660.                adjusted_subject = subject + start_shift;
  661.             }
  662.             if (kGreedyTraceback) {
  663.                BLAST_GreedyGappedAlignment(query, adjusted_subject, 
  664.                   query_length, adjusted_s_length, gap_align, 
  665.                   score_params, q_start, s_start, FALSE, TRUE);
  666.             } else {
  667.                BLAST_GappedAlignmentWithTraceback(program_number, query, 
  668.                   adjusted_subject, gap_align, score_params, q_start, s_start, 
  669.                   query_length, adjusted_s_length);
  670.             }
  671.          }
  672.          if (gap_align->score >= hit_params->cutoff_score) {
  673.             Boolean keep=FALSE;
  674.             Blast_HSPReset(gap_align->query_start, gap_align->query_stop,
  675.                            gap_align->subject_start, gap_align->subject_stop, 
  676.                            gap_align->score, &(gap_align->edit_block), hsp);
  677.             /* FIXME not pretty, should be wrapped as function, done earlier or part of Blast_HSPReset. */
  678.             if (hsp && hsp->gap_info) {
  679.                    hsp->gap_info->frame1 = hsp->query.frame;
  680.                    hsp->gap_info->frame2 = hsp->subject.frame;
  681.                    hsp->gap_info->original_length1 = query_length_orig;
  682.                    hsp->gap_info->original_length2 = subject_blk->length;
  683.                    if (program_number == blast_type_blastx)
  684.                       hsp->gap_info->translate1 = TRUE;
  685.                    if (program_number == blast_type_tblastn ||
  686.                        program_number == blast_type_rpstblastn)
  687.                       hsp->gap_info->translate2 = TRUE;
  688.             }
  689.             if (kGreedyTraceback) {
  690.                /* Low level greedy algorithm ignores ambiguities, so the score
  691.                   needs to be reevaluated. */
  692.                Blast_HSPReevaluateWithAmbiguities(hsp, query, adjusted_subject,
  693.                   hit_options, score_params, query_info, sbp);
  694.             }
  695.             
  696.             keep = HSPSetScores(query_info, query, adjusted_subject, hsp, 
  697.                                 program_number, sbp, score_params, hit_options);
  698.             HSPAdjustSubjectOffset(hsp, subject_blk, k_is_ooframe, 
  699.                                    start_shift);
  700.             if (keep)
  701.                 keep = HSPCheckForDegenerateAlignments(hsp_array, hsp, index);
  702.             if (!keep) {
  703.                hsp_array[index] = Blast_HSPFree(hsp);
  704.             }
  705.          } else {
  706.             /* Score is below threshold */
  707.             gap_align->edit_block = GapEditBlockDelete(gap_align->edit_block);
  708.             hsp_array[index] = Blast_HSPFree(hsp);
  709.          }
  710.       } else { 
  711.          /* Contained within another HSP, delete. */
  712.          hsp_array[index] = Blast_HSPFree(hsp);
  713.       }
  714.    } /* End loop on HSPs */
  715.     if (translation_buffer) {
  716.         sfree(translation_buffer);
  717.     }
  718.     if (frame_offsets) {
  719.         sfree(frame_offsets);
  720.     }
  721.     /* Now try to detect simular alignments */
  722.     BLASTCheckHSPInclusion(hsp_array, hsp_list->hspcnt, k_is_ooframe);
  723.     Blast_HSPListPurgeNullHSPs(hsp_list);
  724.     
  725.     /* Relink and rereap the HSP list, if needed. */
  726.     if (program_number == blast_type_blastx ||
  727.         program_number == blast_type_tblastn ||
  728.         program_number == blast_type_rpstblastn) {
  729.         
  730.         if (hit_params->do_sum_stats == TRUE) {
  731.            BLAST_LinkHsps(program_number, hsp_list, query_info, subject_blk,
  732.                          sbp, hit_params, score_options->gapped_calculation);
  733.         } else if (hit_options->phi_align) {
  734.            Blast_HSPListPHIGetEvalues(hsp_list, sbp);
  735.         } else {
  736.            Blast_HSPListGetEvalues(program_number, query_info, hsp_list, 
  737.                                       score_options->gapped_calculation, sbp);
  738.         }
  739.         
  740.         Blast_HSPListReapByEvalue(hsp_list, hit_options);
  741.     }
  742.     
  743.     qsort(hsp_array, hsp_list->hspcnt, sizeof(BlastHSP*), score_compare_hsps);
  744.     
  745.     /* Remove extra HSPs if there is a user proveded limit on the number 
  746.        of HSPs per database sequence */
  747.     if (hit_options->hsp_num_max > 0 && 
  748.         hit_options->hsp_num_max < hsp_list->hspcnt) {
  749.        for (index=hit_options->hsp_num_max; index<hsp_list->hspcnt; ++index) {
  750.           hsp_array[index] = Blast_HSPFree(hsp_array[index]);
  751.        }
  752.        hsp_list->hspcnt = hit_options->hsp_num_max;
  753.     }
  754.     return 0;
  755. }
  756. static Uint1 Blast_TracebackGetEncoding(Uint1 program_number) 
  757. {
  758.    Uint1 encoding;
  759.    switch (program_number) {
  760.    case blast_type_blastn:
  761.       encoding = BLASTNA_ENCODING;
  762.       break;
  763.    case blast_type_blastp:
  764.    case blast_type_rpsblast:
  765.       encoding = BLASTP_ENCODING;
  766.       break;
  767.    case blast_type_blastx:
  768.       encoding = BLASTP_ENCODING;
  769.       break;
  770.    case blast_type_tblastn:
  771.    case blast_type_rpstblastn:
  772.       encoding = NCBI4NA_ENCODING;
  773.       break;
  774.    case blast_type_tblastx:
  775.       encoding = NCBI4NA_ENCODING;
  776.       break;
  777.    default:
  778.       encoding = ERROR_ENCODING;
  779.       break;
  780.    }
  781.    return encoding;
  782. }
  783. /** Delete extra subject sequences hits, if after-traceback hit list size is
  784.  * smaller than preliminary hit list size.
  785.  * @param results All results after traceback, assumed already sorted by best
  786.  *                e-value [in] [out]
  787.  * @param hitlist_size Final hit list size [in]
  788.  */
  789. static void 
  790. BlastPruneExtraHits(BlastHSPResults* results, Int4 hitlist_size)
  791. {
  792.    Int4 query_index, subject_index;
  793.    BlastHitList* hit_list;
  794.    for (query_index = 0; query_index < results->num_queries; ++query_index) {
  795.       if (!(hit_list = results->hitlist_array[query_index]))
  796.          continue;
  797.       for (subject_index = hitlist_size;
  798.            subject_index < hit_list->hsplist_count; ++subject_index) {
  799.          hit_list->hsplist_array[subject_index] = 
  800.             Blast_HSPListFree(hit_list->hsplist_array[subject_index]);
  801.       }
  802.       hit_list->hsplist_count = MIN(hit_list->hsplist_count, hitlist_size);
  803.    }
  804. }
  805. Int2 BLAST_ComputeTraceback(Uint1 program_number, BlastHSPResults* results, 
  806.         BLAST_SequenceBlk* query, BlastQueryInfo* query_info, 
  807.         const BlastSeqSrc* seq_src, BlastGapAlignStruct* gap_align,
  808.         BlastScoringParameters* score_params,
  809.         const BlastExtensionParameters* ext_params,
  810.         BlastHitSavingParameters* hit_params,
  811.         BlastEffectiveLengthsParameters* eff_len_params,
  812.         const BlastDatabaseOptions* db_options,
  813.         const PSIBlastOptions* psi_options)
  814. {
  815.    Int2 status = 0;
  816.    Int4 query_index, subject_index;
  817.    BlastHitList* hit_list;
  818.    BlastHSPList* hsp_list;
  819.    BlastScoreBlk* sbp;
  820.    Uint1 encoding;
  821.    GetSeqArg seq_arg;
  822.    
  823.    if (!results || !query_info || !seq_src) {
  824.       return 0;
  825.    }
  826.    
  827.    /* Set the raw X-dropoff value for the final gapped extension with 
  828.       traceback */
  829.    gap_align->gap_x_dropoff = ext_params->gap_x_dropoff_final;
  830.    sbp = gap_align->sbp;
  831.    
  832.    encoding = Blast_TracebackGetEncoding(program_number);
  833.    memset((void*) &seq_arg, 0, sizeof(seq_arg));
  834.    for (query_index = 0; query_index < results->num_queries; ++query_index) {
  835.       hit_list = results->hitlist_array[query_index];
  836.       if (!hit_list)
  837.          continue;
  838.      if (program_number == blast_type_blastp && 
  839.          (ext_params->options->compositionBasedStats == TRUE || 
  840.             ext_params->options->eTbackExt == eSmithWatermanTbck))
  841.      {
  842.          Kappa_RedoAlignmentCore(query, query_info, sbp, hit_list, seq_src, 
  843.            score_params, ext_params, hit_params, psi_options); 
  844.      }
  845.      else
  846.      {
  847.       for (subject_index = 0; subject_index < hit_list->hsplist_count;
  848.            ++subject_index) {
  849.          hsp_list = hit_list->hsplist_array[subject_index];
  850.          if (!hsp_list)
  851.             continue;
  852.          if (!hsp_list->traceback_done) {
  853.             seq_arg.oid = hsp_list->oid;
  854.             seq_arg.encoding = encoding;
  855.             BlastSequenceBlkClean(seq_arg.seq);
  856.             if (BLASTSeqSrcGetSequence(seq_src, (void*) &seq_arg) < 0)
  857.                 continue;
  858.             if (BLASTSeqSrcGetTotLen(seq_src) == 0) {
  859.                /* This is not a database search, so effective search spaces
  860.                   need to be recalculated based on this subject sequence 
  861.                   length */
  862.                if ((status = BLAST_OneSubjectUpdateParameters(program_number, 
  863.                                 seq_arg.seq->length, score_params->options, 
  864.                                 query_info, sbp, ext_params, hit_params, 
  865.                                 NULL, eff_len_params)) != 0)
  866.                   return status;
  867.             }
  868.             Blast_TracebackFromHSPList(program_number, hsp_list, query, 
  869.                seq_arg.seq, query_info, gap_align, sbp, score_params, 
  870.                ext_params->options, hit_params, db_options->gen_code_string);
  871.             BLASTSeqSrcRetSequence(seq_src, (void*)&seq_arg);
  872.          }
  873.       }
  874.      }
  875.    }
  876.    /* Re-sort the hit lists according to their best e-values, because
  877.       they could have changed. Only do this for a database search. */
  878.    if (BLASTSeqSrcGetTotLen(seq_src) > 0)
  879.       Blast_HSPResultsSortByEvalue(results);
  880.    /* Eliminate extra hits from results, if preliminary hit list size is larger
  881.       than the final hit list size */
  882.    if (hit_params->options->hitlist_size < 
  883.        hit_params->options->prelim_hitlist_size)
  884.       BlastPruneExtraHits(results, hit_params->options->hitlist_size);
  885.    BlastSequenceBlkFree(seq_arg.seq);
  886.    return status;
  887. }
  888. #define SWAP(a, b) {tmp = (a); (a) = (b); (b) = tmp; }
  889. static void 
  890. RPSUpdateTraceback(BlastHSP *hsp)
  891. {
  892.    Int4 tmp;
  893.    GapEditBlock *gap_info = hsp->gap_info;
  894.    GapEditScript *esp;
  895.    if (gap_info == NULL)
  896.       return;
  897.    SWAP(gap_info->start1, gap_info->start2);
  898.    SWAP(gap_info->length1, gap_info->length2);
  899.    SWAP(gap_info->original_length1, gap_info->original_length2);
  900.    SWAP(gap_info->frame1, gap_info->frame2);
  901.    SWAP(gap_info->translate1, gap_info->translate2);
  902.    esp = gap_info->esp;
  903.    while (esp != NULL) {
  904.       if (esp->op_type == eGapAlignIns)
  905.           esp->op_type = eGapAlignDel;
  906.       else if (esp->op_type == eGapAlignDel)
  907.           esp->op_type = eGapAlignIns;
  908.       esp = esp->next;
  909.    }
  910. }
  911. static void 
  912. RPSUpdateHSPList(BlastHSPList *hsplist)
  913. {
  914.    Int4 i;
  915.    BlastHSP **hsp;
  916.    BlastSeg tmp;
  917.    hsp = hsplist->hsp_array;
  918.    for (i = 0; i < hsplist->hspcnt; i++) {
  919.       /* switch query and subject offsets (which are
  920.          already in local coordinates) */
  921.       tmp = hsp[i]->query;
  922.       hsp[i]->query = hsp[i]->subject;
  923.       hsp[i]->subject = tmp;
  924.       /* Change the traceback information to reflect the
  925.          query and subject sequences getting switched */
  926.       RPSUpdateTraceback(hsp[i]);
  927.    }
  928. }
  929. #define RPS_K_MULT 1.2
  930. Int2 BLAST_RPSTraceback(Uint1 program_number, 
  931.         BlastHSPResults* results, 
  932.         BLAST_SequenceBlk* concat_db, BlastQueryInfo* concat_db_info, 
  933.         BLAST_SequenceBlk* query, BlastQueryInfo* query_info, 
  934.         BlastGapAlignStruct* gap_align,
  935.         const BlastScoringParameters* score_params,
  936.         const BlastExtensionParameters* ext_params,
  937.         BlastHitSavingParameters* hit_params,
  938.         const BlastDatabaseOptions* db_options,
  939.         const double* karlin_k)
  940. {
  941.    Int2 status = 0;
  942.    Int4 i;
  943.    BlastHitList* hit_list;
  944.    BlastHSPList* hsp_list;
  945.    BlastScoreBlk* sbp;
  946.    Int4 **orig_pssm;
  947.    
  948.    if (!results || !concat_db_info || !concat_db) {
  949.       return 0;
  950.    }
  951.    
  952.    /* Set the raw X-dropoff value for the final gapped extension with 
  953.       traceback */
  954.    gap_align->gap_x_dropoff = ext_params->gap_x_dropoff_final;
  955.    sbp = gap_align->sbp;
  956.    orig_pssm = gap_align->sbp->posMatrix;
  957.    hit_list = results->hitlist_array[0];
  958.    if (!hit_list)
  959.       return 0;
  960.    /* for translated searches, the traceback code calculates
  961.       E values *after* the scaling factor has been removed from
  962.       the alignment scores. Thus, lambda must not be pre-scaled
  963.       for a translated search */
  964.    if (program_number != blast_type_rpstblastn)
  965.       sbp->kbp_gap[0]->Lambda /= score_params->scale_factor;
  966.    for (i = 0; i < hit_list->hsplist_count; i++) {
  967.       hsp_list = hit_list->hsplist_array[i];
  968.       if (!hsp_list)
  969.          continue;
  970.       if (!hsp_list->traceback_done) {
  971.          Int4 offsets[2];
  972.          BLAST_SequenceBlk one_db_seq;
  973.          BlastQueryInfo one_db_seq_info;
  974.          Int4 *db_seq_start;
  975.          /* pick out one of the sequences from the concatenated
  976.             DB (given by the OID of this HSPList). The sequence
  977.             size does not include the trailing NULL */
  978.          db_seq_start = &concat_db_info->context_offsets[hsp_list->oid];
  979.          memset(&one_db_seq, 0, sizeof(one_db_seq));
  980.          one_db_seq.sequence = NULL;
  981.          one_db_seq.length = db_seq_start[1] - db_seq_start[0] - 1;
  982.          /* Set up the QueryInfo structure for this sequence. The
  983.             trailing NULL must be added back */
  984.          offsets[0] = 0;
  985.          offsets[1] = one_db_seq.length + 1;
  986.          memset(&one_db_seq_info, 0, sizeof(one_db_seq_info));
  987.          one_db_seq_info.first_context = 0;
  988.          one_db_seq_info.last_context = 0;
  989.          one_db_seq_info.num_queries = 1;
  990.          one_db_seq_info.context_offsets = &offsets[0];
  991.          one_db_seq_info.eff_searchsp_array = query_info->eff_searchsp_array;
  992.          /* Update the statistics for this database sequence
  993.             (if not a translated search) */
  994.          if (program_number == blast_type_rpstblastn) {
  995.             sbp->posMatrix = orig_pssm + db_seq_start[0];
  996.          }
  997.          else {
  998.             /* replace the PSSM and the Karlin values
  999.                for this DB sequence. */
  1000.             sbp->posMatrix = RPSCalculatePSSM(score_params->scale_factor,
  1001.                         query->length, query->sequence, one_db_seq.length,
  1002.                         orig_pssm + db_seq_start[0]);
  1003.             if (sbp->posMatrix == NULL)
  1004.                return -1;
  1005.             sbp->kbp_gap[0]->K = RPS_K_MULT * karlin_k[hsp_list->oid];
  1006.             sbp->kbp_gap[0]->logK = log(RPS_K_MULT * karlin_k[hsp_list->oid]);
  1007.          }
  1008.          /* compute the traceback information and calculate E values
  1009.             for all HSPs in the list */
  1010.          Blast_TracebackFromHSPList(program_number, hsp_list, &one_db_seq, 
  1011.             query, &one_db_seq_info, gap_align, sbp, score_params, 
  1012.             ext_params->options, hit_params, db_options->gen_code_string);
  1013.          if (program_number != blast_type_rpstblastn)
  1014.             _PSIDeallocateMatrix((void**)sbp->posMatrix, one_db_seq.length+1);
  1015.       }
  1016.       /* Revert query and subject to their traditional meanings. 
  1017.          This involves switching the offsets around and reversing
  1018.          any traceback information */
  1019.       RPSUpdateHSPList(hsp_list);
  1020.    }
  1021.    /* restore input data */
  1022.    if (program_number != blast_type_rpstblastn)
  1023.       sbp->kbp_gap[0]->Lambda *= score_params->scale_factor;
  1024.    gap_align->sbp->posMatrix = orig_pssm;
  1025.    return status;
  1026. }