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

生物技术

开发平台:

C/C++

  1.                 if (best_score - score > x_dropoff) {
  2.                     if (first_b_index == b_index) 
  3.                         first_b_index = b_index + 1;
  4.                     else
  5.                         score_array[b_index].best = MININT;
  6.                 }
  7.                 else {
  8.                     last_b_index = b_index + 1;
  9.                     score_array[b_index].best = score;
  10.                     score_array[b_index].best_gap = score_gap_col - gap_extend;
  11.                     score_row2 -= gap_extend;
  12.                 }
  13.             }
  14.             else {
  15.                 if (best_score - score > x_dropoff) {
  16.                     if (first_b_index == b_index) 
  17.                         first_b_index = b_index + 1;
  18.                     else
  19.                         score_array[b_index].best = MININT;
  20.                 }
  21.                 else {
  22.                     last_b_index = b_index + 1;
  23.                     score_array[b_index].best = score;
  24.                     if (score > best_score) {
  25.                         best_score = score;
  26.                         *a_offset = a_index;
  27.                         *b_offset = b_index;
  28.                     }
  29.                     score -= gap_open_extend;
  30.                     score_row2 -= gap_extend;
  31.                     score_row2 = MAX(score, score_row2);
  32.                     score_array[b_index].best_gap = MAX(score, 
  33.                                                   score_gap_col - gap_extend);
  34.                 }
  35.             }
  36.             if (++b_index >= b_size) {
  37.                 score = score_row2;
  38.                 score_row2 = score_row1;
  39.                 score_row1 = score_row3;
  40.                 score_row3 = score;
  41.                 break;
  42.             }
  43.             /* FRAME 2 */
  44.             score = MAX(score_other_frame1, score_other_frame2) - shift_penalty;
  45.             score = MAX(score, score_col3) + 
  46.                                 matrix_row[ B[ b_index * increment ] ];
  47.             score_other_frame1 = score_other_frame2;
  48.             score_other_frame2 = MAX(score_col3, score_array[b_index].best);
  49.             score_col3 = score_array[b_index].best;
  50.             score_gap_col = score_array[b_index].best_gap;
  51.             if (score < MAX(score_gap_col, score_row3)) {
  52.                 score = MAX(score_gap_col, score_row3);
  53.                 if (best_score - score > x_dropoff) {
  54.                     if (first_b_index == b_index) 
  55.                         first_b_index = b_index + 1;
  56.                     else
  57.                         score_array[b_index].best = MININT;
  58.                 }
  59.                 else {
  60.                     last_b_index = b_index + 1;
  61.                     score_array[b_index].best = score;
  62.                     score_array[b_index].best_gap = score_gap_col - gap_extend;
  63.                     score_row3 -= gap_extend;
  64.                 }
  65.             }
  66.             else {
  67.                 if (best_score - score > x_dropoff) {
  68.                     if (first_b_index == b_index) 
  69.                         first_b_index = b_index + 1;
  70.                     else
  71.                         score_array[b_index].best = MININT;
  72.                 }
  73.                 else {
  74.                     last_b_index = b_index + 1;
  75.                     score_array[b_index].best = score;
  76.                     if (score > best_score) {
  77.                         best_score = score;
  78.                         *a_offset = a_index;
  79.                         *b_offset = b_index;
  80.                     }
  81.                     score -= gap_open_extend;
  82.                     score_row3 -= gap_extend;
  83.                     score_row3 = MAX(score, score_row3);
  84.                     score_array[b_index].best_gap = MAX(score, 
  85.                                                   score_gap_col - gap_extend);
  86.                 }
  87.             }
  88.             b_index++;
  89.         }
  90.   
  91.         /* Finish aligning if the best scores for all positions
  92.            of B will fail the X-dropoff test, i.e. the inner loop 
  93.            bounds have converged to each other */
  94.         if (first_b_index == b_size)
  95.             break;
  96.         if (last_b_index < b_size) {
  97.             /* This row failed the X-dropoff test earlier than
  98.                the last row did; just shorten the loop bounds
  99.                before doing the next row */
  100.             b_size = last_b_index;
  101.         }
  102.         else {
  103.             /* The inner loop finished without failing the X-dropoff
  104.                test; initialize extra bookkeeping structures until
  105.                the X dropoff test fails or we run out of letters in B. 
  106.                The next inner loop will have larger bounds. 
  107.              
  108.                Keep initializing extra structures until the X dropoff
  109.                test fails in all frames for this row */
  110.             score = MAX(score_row1, MAX(score_row2, score_row3));
  111.             last_b_index = b_size + (score - (best_score - x_dropoff)) /
  112.                                                     gap_extend;
  113.             last_b_index = MIN(last_b_index, N+2);
  114.             while (b_size < last_b_index) {
  115.                 score_array[b_size].best = score_row1;
  116.                 score_array[b_size].best_gap = score_row1 - gap_open_extend;
  117.                 score_row1 -= gap_extend;
  118.                 if (++b_size > last_b_index)
  119.                     break;
  120.                 score_array[b_size].best = score_row2;
  121.                 score_array[b_size].best_gap = score_row2 - gap_open_extend;
  122.                 score_row2 -= gap_extend;
  123.                 if (++b_size > last_b_index)
  124.                     break;
  125.                 score_array[b_size].best = score_row3;
  126.                 score_array[b_size].best_gap = score_row3 - gap_open_extend;
  127.                 score_row3 -= gap_extend;
  128.                 if (++b_size > last_b_index)
  129.                     break;
  130.             }
  131.         }
  132.         /* chop off the best score in each frame */
  133.         last_b_index = MIN(b_size + 4, N + 3);
  134.         while (b_size < last_b_index) {
  135.             score_array[b_size].best = MININT;
  136.             score_array[b_size].best_gap = MININT;
  137.             b_size++;
  138.         }
  139.     }
  140.     if (!reversed) {
  141.         /* The sequence was shifted, so length should be adjusted as well */
  142.         *b_offset -= 2;
  143.     }
  144.     sfree(score_array);
  145.     return best_score;
  146. }
  147. /** Callback function for a sorting of initial HSPs by diagonal */
  148. static int
  149. diag_compare_match(const void* v1, const void* v2)
  150. {
  151.    BlastInitHSP* h1,* h2;
  152.    h1 = *((BlastInitHSP**) v1);
  153.    h2 = *((BlastInitHSP**) v2);
  154.    
  155.    if (!h1 || !h2)
  156.       return 0;
  157.    return (h1->q_off - h1->s_off) - (h2->q_off - h2->s_off);
  158. }
  159. /** Find the HSP offsets relative to the individual query sequence instead of
  160.  * the concatenated sequence.
  161.  * @param query Query sequence block [in]
  162.  * @param query_info Query information structure, including context offsets 
  163.  *                   array [in]
  164.  * @param init_hsp Initial HSP [in] [out]
  165.  * @param query_out Optional: query sequence block with modified sequence 
  166.  *                  pointer and sequence length [out]
  167.  * @param init_hsp_out Optional: Pointer to initial HSP structure to hold
  168.  *                     adjusted offsets; the input init_hsp will be modified if
  169.  *                     this parameter is NULL [out]
  170.  * @param context_out Which context this HSP belongs to? [out]
  171.  */
  172. static void 
  173. GetRelativeCoordinates(const BLAST_SequenceBlk* query, 
  174.                        BlastQueryInfo* query_info, 
  175.                        BlastInitHSP* init_hsp, BLAST_SequenceBlk* query_out,
  176.                        BlastInitHSP* init_hsp_out, Int4* context_out)
  177. {
  178.    Int4 context;
  179.    Int4 query_start, query_length;
  180.    context = BSearchInt4(init_hsp->q_off, query_info->context_offsets, 
  181.                          query_info->last_context+2);
  182.    if (query && query->oof_sequence) {
  183.       /* Out-of-frame blastx case: all frames of the same parity are mixed
  184.          together in a special sequence. */
  185.       Int4 mixed_frame_context = context - context%CODON_LENGTH;
  186.       query_start = query_info->context_offsets[mixed_frame_context];
  187.       query_length = 
  188.          query_info->context_offsets[mixed_frame_context+CODON_LENGTH] - 
  189.          query_start - 1;
  190.    } else {
  191.       query_start = query_info->context_offsets[context];
  192.       query_length = BLAST_GetQueryLength(query_info, context);
  193.    }
  194.    if (query && query_out) {
  195.       if (query->oof_sequence) {
  196.          query_out->sequence = NULL;
  197.          query_out->oof_sequence = query->oof_sequence + query_start;
  198.       } else {
  199.          query_out->sequence = query->sequence + query_start;
  200.          query_out->oof_sequence = NULL;
  201.       }
  202.       query_out->length = query_length;
  203.    }
  204.    if (init_hsp_out) {
  205.       init_hsp_out->q_off = init_hsp->q_off - query_start;
  206.       init_hsp_out->s_off = init_hsp->s_off;
  207.       if (init_hsp->ungapped_data) {
  208.          if (!init_hsp_out->ungapped_data) {
  209.             init_hsp_out->ungapped_data = (BlastUngappedData*) 
  210.                BlastMemDup(init_hsp->ungapped_data, sizeof(BlastUngappedData));
  211.          } else {
  212.             memcpy(init_hsp_out->ungapped_data, init_hsp->ungapped_data,
  213.                    sizeof(BlastUngappedData));
  214.          }
  215.          init_hsp_out->ungapped_data->q_start = 
  216.             init_hsp->ungapped_data->q_start - query_start;
  217.       }
  218.    } else {
  219.       init_hsp->q_off -= query_start;
  220.       if (init_hsp->ungapped_data)
  221.          init_hsp->ungapped_data->q_start -= query_start;
  222.    }
  223.    *context_out = context;
  224. }
  225. Int2 BLAST_MbGetGappedScore(Uint1 program_number, 
  226.              BLAST_SequenceBlk* query, BlastQueryInfo* query_info, 
  227.     BLAST_SequenceBlk* subject,
  228.     BlastGapAlignStruct* gap_align,
  229.     const BlastScoringParameters* score_params, 
  230.     const BlastExtensionParameters* ext_params,
  231.     const BlastHitSavingParameters* hit_params,
  232.     BlastInitHitList* init_hitlist,
  233.     BlastHSPList** hsp_list_ptr, BlastGappedStats* gapped_stats)
  234. {
  235.    const BlastExtensionOptions* ext_options = ext_params->options;
  236.    Int4 index, i;
  237.    Boolean delete_hsp;
  238.    BlastInitHSP* init_hsp;
  239.    BlastInitHSP** init_hsp_array;
  240.    BlastHSPList* hsp_list;
  241.    BlastHSP* hsp;
  242.    const BlastHitSavingOptions* hit_options = hit_params->options;
  243.    BLAST_SequenceBlk query_tmp;
  244.    Int4 context;
  245.    if (*hsp_list_ptr == NULL)
  246.       *hsp_list_ptr = hsp_list = Blast_HSPListNew(hit_options->hsp_num_max);
  247.    else 
  248.       hsp_list = *hsp_list_ptr;
  249.    init_hsp_array = (BlastInitHSP**) 
  250.      malloc(init_hitlist->total*sizeof(BlastInitHSP*));
  251.    for (index=0; index<init_hitlist->total; ++index)
  252.      init_hsp_array[index] = &init_hitlist->init_hsp_array[index];
  253.    qsort(init_hsp_array, init_hitlist->total, 
  254.             sizeof(BlastInitHSP*), diag_compare_match);
  255.    for (index=0; index<init_hitlist->total; index++) {
  256.       init_hsp = init_hsp_array[index];
  257.       /* Change query coordinates to relative in the initial HSP right here */
  258.       GetRelativeCoordinates(query, query_info, init_hsp, &query_tmp, NULL, 
  259.                              &context);
  260.       delete_hsp = FALSE;
  261.       for (i = hsp_list->hspcnt - 1; i >= 0; i--) {
  262.          hsp = hsp_list->hsp_array[i];
  263.          if (context != hsp->context)
  264.             continue;
  265.          if (!MB_HSP_CLOSE(init_hsp->q_off, hsp->query.offset, 
  266.                            init_hsp->s_off, hsp->subject.offset, MB_DIAG_NEAR))
  267.              break;
  268.          /* Do not extend an HSP already contained in another HSP, unless
  269.             its ungapped score is higher than that HSP's gapped score,
  270.             which indicates wrong starting offset for previously extended HSP.
  271.          */
  272.          if (MB_HSP_CONTAINED(init_hsp->q_off, hsp->query.offset, 
  273.                 hsp->query.end, init_hsp->s_off, 
  274.                 hsp->subject.offset, hsp->subject.end, MB_DIAG_CLOSE) &&
  275.              (!init_hsp->ungapped_data || 
  276.               init_hsp->ungapped_data->score < hsp->score)) 
  277.          {
  278.                delete_hsp = TRUE;
  279.                break;
  280.          }
  281.       }
  282.       if (!delete_hsp) {
  283.          Boolean good_hit = TRUE;
  284.          if (gapped_stats)
  285.             ++gapped_stats->extensions;
  286.          BLAST_GreedyGappedAlignment(query_tmp.sequence, 
  287.             subject->sequence, query_tmp.length, subject->length, gap_align, 
  288.             score_params, init_hsp->q_off, init_hsp->s_off, 
  289.             (Boolean) TRUE, (Boolean) (ext_options->ePrelimGapExt == eGreedyWithTracebackExt));
  290.          /* For neighboring we have a stricter criterion to keep an HSP */
  291.          if (hit_options->is_neighboring) {
  292.             Int4 hsp_length;
  293.                
  294.             hsp_length = 
  295.                MIN(gap_align->query_stop-gap_align->query_start, 
  296.                    gap_align->subject_stop-gap_align->subject_start) + 1;
  297.             if (hsp_length < MIN_NEIGHBOR_HSP_LENGTH || 
  298.                 gap_align->percent_identity < MIN_NEIGHBOR_PERC_IDENTITY)
  299.                good_hit = FALSE;
  300.          }
  301.                
  302.          if (good_hit && gap_align->score >= hit_options->cutoff_score) {
  303.             /* gap_align contains alignment endpoints; init_hsp contains 
  304.                the offsets to start the alignment from, if traceback is to 
  305.                be performed later */
  306.             BlastHSP* new_hsp;
  307.             Blast_HSPInit(gap_align->query_start, gap_align->query_stop,
  308.                            gap_align->subject_start, gap_align->subject_stop, 
  309.                            init_hsp->q_off, init_hsp->s_off, 
  310.                            context, 1, gap_align->score,
  311.                            &(gap_align->edit_block), &new_hsp);
  312.             Blast_HSPListSaveHSP(hsp_list, new_hsp);
  313.          }
  314.       }
  315.    }
  316.    if (ext_options->ePrelimGapExt != eGreedyExt)
  317.       /* Set the flag that traceback is already done for this HSP list */
  318.       hsp_list->traceback_done = TRUE;
  319.    sfree(init_hsp_array);
  320.    return 0;
  321. }
  322. /** Auxiliary function to transform one style of edit script into 
  323.  *  another. 
  324.  */
  325. static GapEditScript*
  326. MBToGapEditScript (MBGapEditScript* ed_script)
  327. {
  328.     /* Moved from greedy_align.h because it's only needed in this function */
  329. #define EDIT_VAL(op) (op >> 2)
  330. #define EDIT_OPC(op) (op & 0x3) /* EDIT_OP_MASK == 0x3 */
  331.    GapEditScript* esp_start = NULL,* esp,* esp_prev = NULL;
  332.    Uint4 i;
  333.    if (ed_script==NULL || ed_script->num == 0)
  334.       return NULL;
  335.    for (i=0; i<ed_script->num; i++) {
  336.       esp = (GapEditScript*) calloc(1, sizeof(GapEditScript));
  337.       esp->num = EDIT_VAL(ed_script->op[i]);
  338.       switch (EDIT_OPC(ed_script->op[i])) {
  339.       case 1: 
  340.          esp->op_type = eGapAlignDel; break;
  341.       case 2:
  342.          esp->op_type = eGapAlignIns; break;
  343.       case 3:
  344.          esp->op_type = eGapAlignSub; break;
  345.       default:
  346.          fprintf(stderr, "op_type = 3n"); break;
  347.       }
  348.       if (i==0)
  349.          esp_start = esp_prev = esp;
  350.       else {
  351.          esp_prev->next = esp;
  352.          esp_prev = esp;
  353.       }
  354.    }
  355.    return esp_start;
  356. }
  357. /** Fills the BlastGapAlignStruct structure with the results of a gapped 
  358.  * extension.
  359.  * @param gap_align the initialized gapped alignment structure [in] [out]
  360.  * @param q_start The starting offset in query [in]
  361.  * @param s_start The starting offset in subject [in]
  362.  * @param q_end The ending offset in query [in]
  363.  * @param s_end The ending offset in subject [in]
  364.  * @param query_length Length of the query sequence [in]
  365.  * @param subject_length Length of the subject sequence [in]
  366.  * @param score The alignment score [in]
  367.  * @param esp The edit script containing the traceback information [in]
  368.  */
  369. static Int2
  370. BLAST_GapAlignStructFill(BlastGapAlignStruct* gap_align, Int4 q_start, 
  371.    Int4 s_start, Int4 q_end, Int4 s_end, Uint4 query_length, 
  372.    Uint4 subject_length, Int4 score, GapEditScript* esp)
  373. {
  374.    gap_align->query_start = q_start;
  375.    gap_align->query_stop = q_end;
  376.    gap_align->subject_start = s_start;
  377.    gap_align->subject_stop = s_end;
  378.    gap_align->score = score;
  379.    if (esp) {
  380.       gap_align->edit_block = GapEditBlockNew(q_start, s_start);
  381.       gap_align->edit_block->start1 = q_start;
  382.       gap_align->edit_block->start2 = s_start;
  383.       gap_align->edit_block->length1 = query_length;
  384.       gap_align->edit_block->length2 = subject_length;
  385.       gap_align->edit_block->original_length1 = query_length;
  386.       gap_align->edit_block->original_length2 = subject_length;
  387.       gap_align->edit_block->frame1 = gap_align->edit_block->frame2 = 1;
  388.       gap_align->edit_block->reverse = 0;
  389.       gap_align->edit_block->esp = esp;
  390.    }
  391.    return 0;
  392. }
  393. Int2 
  394. BLAST_GreedyGappedAlignment(Uint1* query, Uint1* subject, 
  395.    Int4 query_length, Int4 subject_length, BlastGapAlignStruct* gap_align,
  396.    const BlastScoringParameters* score_params, 
  397.    Int4 q_off, Int4 s_off, Boolean compressed_subject, Boolean do_traceback)
  398. {
  399.    Uint1* q;
  400.    Uint1* s;
  401.    Int4 score;
  402.    Int4 X;
  403.    Int4 q_avail, s_avail;
  404.    /* Variables for the call to MegaBlastGreedyAlign */
  405.    Int4 q_ext_l, q_ext_r, s_ext_l, s_ext_r;
  406.    MBGapEditScript *ed_script_fwd=NULL, *ed_script_rev=NULL;
  407.    Uint1 rem;
  408.    GapEditScript* esp = NULL;
  409.    
  410.    q_avail = query_length - q_off;
  411.    s_avail = subject_length - s_off;
  412.    
  413.    q = query + q_off;
  414.    if (!compressed_subject) {
  415.       s = subject + s_off;
  416.       rem = 4; /* Special value to indicate that sequence is already
  417.                   uncompressed */
  418.    } else {
  419.       s = subject + s_off/4;
  420.       rem = s_off % 4;
  421.    }
  422.    /* Find where positive scoring starts & ends within the word hit */
  423.    score = 0;
  424.    
  425.    X = gap_align->gap_x_dropoff;
  426.    
  427.    if (do_traceback) {
  428.       ed_script_fwd = MBGapEditScriptNew();
  429.       ed_script_rev = MBGapEditScriptNew();
  430.    }
  431.    
  432.    /* extend to the right */
  433.    score = BLAST_AffineGreedyAlign(s, s_avail, q, q_avail, FALSE, X,
  434.               score_params->reward, -score_params->penalty, 
  435.               score_params->gap_open, score_params->gap_extend,
  436.               &s_ext_r, &q_ext_r, gap_align->greedy_align_mem, 
  437.               ed_script_fwd, rem);
  438.    if (compressed_subject)
  439.       rem = 0;
  440.    /* extend to the left */
  441.    score += BLAST_AffineGreedyAlign(subject, s_off, 
  442.                query, q_off, TRUE, X, 
  443.                score_params->reward, -score_params->penalty, 
  444.                score_params->gap_open, score_params->gap_extend, 
  445.                &s_ext_l, &q_ext_l, gap_align->greedy_align_mem, 
  446.                ed_script_rev, rem);
  447.    /* In basic case the greedy algorithm returns number of 
  448.       differences, hence we need to convert it to score */
  449.    if (score_params->gap_open==0 && score_params->gap_extend==0) {
  450.       /* Take advantage of an opportunity to easily calculate percent 
  451.          identity, to avoid parsing the traceback later */
  452.       gap_align->percent_identity = 
  453.          100*(1 - ((double)score) / MIN(q_ext_l+q_ext_r, s_ext_l+s_ext_r));
  454.       score = 
  455.          (q_ext_r + s_ext_r + q_ext_l + s_ext_l)*score_params->reward/2 - 
  456.          score*(score_params->reward - score_params->penalty);
  457.    } else if (score_params->reward % 2 == 1) {
  458.       score /= 2;
  459.    }
  460.    if (do_traceback) {
  461.       MBGapEditScriptAppend(ed_script_rev, ed_script_fwd);
  462.       esp = MBToGapEditScript(ed_script_rev);
  463.    }
  464.    
  465.    MBGapEditScriptFree(ed_script_fwd);
  466.    MBGapEditScriptFree(ed_script_rev);
  467.    
  468.    BLAST_GapAlignStructFill(gap_align, q_off-q_ext_l, 
  469.       s_off-s_ext_l, q_off+q_ext_r, 
  470.       s_off+s_ext_r, query_length, subject_length, score, esp);
  471.    return 0;
  472. }
  473. /** Performs dynamic programming style gapped extension, given an initial 
  474.  * HSP (offset pair), two sequence blocks and scoring and extension options.
  475.  * Note: traceback is not done in this function.
  476.  * @param query_blk The query sequence [in]
  477.  * @param subject_blk The subject sequence [in]
  478.  * @param gap_align The auxiliary structure for gapped alignment [in]
  479.  * @param score_params Parameters related to scoring [in]
  480.  * @param init_hsp The initial HSP that needs to be extended [in]
  481. */
  482. static Int2 BLAST_DynProgNtGappedAlignment(BLAST_SequenceBlk* query_blk, 
  483.    BLAST_SequenceBlk* subject_blk, BlastGapAlignStruct* gap_align, 
  484.    const BlastScoringParameters* score_params, BlastInitHSP* init_hsp)
  485. {
  486.    Boolean found_start, found_end;
  487.    Int4 q_length=0, s_length=0, score_right, score_left, 
  488.       private_q_start, private_s_start;
  489.    Uint1 offset_adjustment;
  490.    Uint1* query,* subject;
  491.    
  492.    found_start = FALSE;
  493.    found_end = FALSE;
  494.    query = query_blk->sequence;
  495.    subject = subject_blk->sequence;
  496.    score_left = 0;
  497.    /* If subject offset is not at the start of a full byte, 
  498.       BLAST_AlignPackedNucl won't work, so shift the alignment start
  499.       to the left */
  500.    offset_adjustment = 
  501.       COMPRESSION_RATIO - (init_hsp->s_off % COMPRESSION_RATIO);
  502.    q_length = init_hsp->q_off + offset_adjustment;
  503.    s_length = init_hsp->s_off + offset_adjustment;
  504.    if (q_length != 0 && s_length != 0) {
  505.       found_start = TRUE;
  506.       score_left = BLAST_AlignPackedNucl(query, subject, q_length, s_length, 
  507.                       &private_q_start, &private_s_start, gap_align, 
  508.                       score_params, TRUE);
  509.       if (score_left < 0) 
  510.          return -1;
  511.       gap_align->query_start = q_length - private_q_start;
  512.       gap_align->subject_start = s_length - private_s_start;
  513.    }
  514.    score_right = 0;
  515.    if (q_length < query_blk->length && 
  516.        s_length < subject_blk->length)
  517.    {
  518.       found_end = TRUE;
  519.       score_right = BLAST_AlignPackedNucl(query+q_length-1, 
  520.          subject+(s_length+3)/COMPRESSION_RATIO - 1, 
  521.          query_blk->length-q_length, 
  522.          subject_blk->length-s_length, &(gap_align->query_stop),
  523.          &(gap_align->subject_stop), gap_align, score_params, FALSE);
  524.       if (score_right < 0) 
  525.          return -1;
  526.       gap_align->query_stop += q_length;
  527.       gap_align->subject_stop += s_length;
  528.    }
  529.    if (found_start == FALSE) {
  530.       /* Start never found */
  531.       gap_align->query_start = init_hsp->q_off;
  532.       gap_align->subject_start = init_hsp->s_off;
  533.    }
  534.    if (found_end == FALSE) {
  535.       gap_align->query_stop = init_hsp->q_off - 1;
  536.       gap_align->subject_stop = init_hsp->s_off - 1;
  537.    }
  538.    gap_align->score = score_right+score_left;
  539.    return 0;
  540. }
  541. /* Aligns two nucleotide sequences, one (A) should be packed in the
  542.  * same way as the BLAST databases, the other (B) should contain one
  543.  * basepair/byte. Traceback is not done in this function.
  544.  * @param B The query sequence [in]
  545.  * @param A The subject sequence [in]
  546.  * @param N Maximal extension length in query [in]
  547.  * @param M Maximal extension length in subject [in]
  548.  * @param b_offset Resulting starting offset in query [out]
  549.  * @param a_offset Resulting starting offset in subject [out]
  550.  * @param gap_align The auxiliary structure for gapped alignment [in]
  551.  * @param score_params Parameters related to scoring [in]
  552.  * @param reverse_sequence Reverse the sequence.
  553.  * @return The best alignment score found.
  554. */
  555. static Int4 BLAST_AlignPackedNucl(Uint1* B, Uint1* A, Int4 N, Int4 M, 
  556. Int4* b_offset, Int4* a_offset, 
  557.         BlastGapAlignStruct* gap_align,
  558.         const BlastScoringParameters* score_params, 
  559.         Boolean reverse_sequence)
  560.     BlastGapDP* score_array;            /* sequence pointers and indices */
  561.     Int4 i; 
  562.     Int4 a_index, a_base_pair;
  563.     Int4 b_index, b_size, first_b_index, last_b_index, b_increment;
  564.     Uint1* b_ptr;
  565.   
  566.     Int4 gap_open;              /* alignment penalty variables */
  567.     Int4 gap_extend;
  568.     Int4 gap_open_extend;
  569.     Int4 decline_penalty;
  570.     Int4 x_dropoff;
  571.   
  572.     Int4* *matrix;              /* pointers to the score matrix */
  573.     Int4* matrix_row;
  574.   
  575.     Int4 score;                 /* score tracking variables */
  576.     Int4 score_gap_row;
  577.     Int4 score_gap_col;
  578.     Int4 score_decline;
  579.     Int4 next_score;
  580.     Int4 next_score_decline;
  581.     Int4 best_score;
  582.   
  583.     /* do initialization and sanity-checking */
  584.     matrix = gap_align->sbp->matrix;
  585.     *a_offset = 0;
  586.     *b_offset = 0;
  587.     gap_open = score_params->gap_open;
  588.     gap_extend = score_params->gap_extend;
  589.     gap_open_extend = gap_open + gap_extend;
  590.     decline_penalty = score_params->decline_align;
  591.     x_dropoff = gap_align->gap_x_dropoff;
  592.   
  593.     if (x_dropoff < gap_open_extend)
  594.         x_dropoff = gap_open_extend;
  595.   
  596.     if(N <= 0 || M <= 0) 
  597.         return 0;
  598.   
  599.     /* Allocate and fill in the auxiliary 
  600.        bookeeping structures (one struct
  601.        per letter of B) */
  602.     score_array = (BlastGapDP*)malloc((N + 2) * sizeof(BlastGapDP));
  603.     score = -gap_open_extend;
  604.     score_array[0].best = 0;
  605.     score_array[0].best_gap = -gap_open_extend;
  606.     score_array[0].best_decline = -gap_open_extend - decline_penalty;
  607.   
  608.     for (i = 1; i <= N; i++) {
  609.         if (score < -x_dropoff) 
  610.             break;
  611.         score_array[i].best = score;
  612.         score_array[i].best_gap = score - gap_open_extend; 
  613.         score_array[i].best_decline = score - gap_open_extend - decline_penalty;
  614.         score -= gap_extend;
  615.     }
  616.   
  617.     /* The inner loop below examines letters of B from 
  618.        index 'first_b_index' to 'b_size' */
  619.     b_size = i;
  620.     best_score = 0;
  621.     first_b_index = 0;
  622.     if (reverse_sequence)
  623.         b_increment = -1;
  624.     else
  625.         b_increment = 1;
  626.   
  627.     for (a_index = 1; a_index <= M; a_index++) {
  628.         /* pick out the row of the score matrix 
  629.            appropriate for A[a_index] */
  630.         if(reverse_sequence) {
  631.             a_base_pair = NCBI2NA_UNPACK_BASE(A[(M-a_index)/4], 
  632.                                                ((a_index-1)%4));
  633.             matrix_row = matrix[a_base_pair];
  634.         } 
  635.         else {
  636.             a_base_pair = NCBI2NA_UNPACK_BASE(A[1+((a_index-1)/4)], 
  637.                                                (3-((a_index-1)%4)));
  638.             matrix_row = matrix[a_base_pair];
  639.         }
  640.         if(reverse_sequence)
  641.             b_ptr = &B[N - first_b_index];
  642.         else
  643.             b_ptr = &B[first_b_index];
  644.         /* initialize running-score variables */
  645.         score = MININT;
  646.         score_gap_row = MININT;
  647.         score_decline = MININT;
  648.         last_b_index = first_b_index;
  649.         for (b_index = first_b_index; b_index < b_size; b_index++) {
  650.             b_ptr += b_increment;
  651.             score_gap_col = score_array[b_index].best_gap;
  652.             next_score = score_array[b_index].best + matrix_row[ *b_ptr ];
  653.             next_score_decline = score_array[b_index].best_decline;
  654.             /* decline the alignment if that improves the score */
  655.             score = MAX(score, score_decline);
  656.             
  657.             /* decline the best row score if that improves it;
  658.                if not, make it the new high score if it's
  659.                an improvement */
  660.             if (score_gap_col < score_decline)
  661.                 score_gap_col = score_decline;
  662.             else if (score < score_gap_col)
  663.                 score = score_gap_col;
  664.             /* decline the best column score if that improves it;
  665.                if not, make it the new high score if it's
  666.                an improvement */
  667.             if (score_gap_row < score_decline)
  668.                 score_gap_row = score_decline;
  669.             else if (score < score_gap_row)
  670.                 score = score_gap_row;
  671.             if (best_score - score > x_dropoff) {
  672.                 /* the current best score failed the X-dropoff
  673.                    criterion. Note that this does not stop the
  674.                    inner loop, only forces future iterations to
  675.                    skip this column of B. 
  676.                    Also, if the very first letter of B that was
  677.                    tested failed the X dropoff criterion, make
  678.                    sure future inner loops start one letter to 
  679.                    the right */
  680.                 if (b_index == first_b_index)
  681.                     first_b_index++;
  682.                 else
  683.                     score_array[b_index].best = MININT;
  684.             }
  685.             else {
  686.                 last_b_index = b_index;
  687.                 if (score > best_score) {
  688.                     best_score = score;
  689.                     *a_offset = a_index;
  690.                     *b_offset = b_index;
  691.                 }
  692.                 /* If starting a gap at this position will improve
  693.                    the best row, column, or declined alignment score, 
  694.                    update them to reflect that. */
  695.                 score_gap_row -= gap_extend;
  696.                 score_gap_col -= gap_extend;
  697.                 score_array[b_index].best_gap = MAX(score - gap_open_extend,
  698.                                                     score_gap_col);
  699.                 score_gap_row = MAX(score - gap_open_extend, score_gap_row);
  700.                 score_array[b_index].best_decline = 
  701.                         MAX(score_decline, score - gap_open) - decline_penalty;
  702.                 score_array[b_index].best = score;
  703.             }
  704.             score = next_score;
  705.             score_decline = next_score_decline;
  706.         }
  707.   
  708.         /* Finish aligning if the best scores for all positions
  709.            of B will fail the X-dropoff test, i.e. the inner loop 
  710.            bounds have converged to each other */
  711.         if (first_b_index == b_size)
  712.             break;
  713.         if (last_b_index < b_size - 1) {
  714.             /* This row failed the X-dropoff test earlier than
  715.                the last row did; just shorten the loop bounds
  716.                before doing the next row */
  717.             b_size = last_b_index + 1;
  718.         }
  719.         else {
  720.             /* The inner loop finished without failing the X-dropoff
  721.                test; initialize extra bookkeeping structures until
  722.                the X dropoff test fails or we run out of letters in B. 
  723.                The next inner loop will have larger bounds */
  724.             while (score_gap_row >= (best_score - x_dropoff) && b_size <= N) {
  725.                 score_array[b_size].best = score_gap_row;
  726.                 score_array[b_size].best_gap = score_gap_row - gap_open_extend;
  727.                 score_array[b_size].best_decline = score_gap_row - gap_open -
  728.                                                         decline_penalty;
  729.                 score_gap_row -= gap_extend;
  730.                 b_size++;
  731.             }
  732.         }
  733.         if (b_size <= N) {
  734.             score_array[b_size].best = MININT;
  735.             score_array[b_size].best_gap = MININT;
  736.             score_array[b_size].best_decline = MININT;
  737.             b_size++;
  738.         }
  739.     }
  740.     
  741.     sfree(score_array);
  742.     return best_score;
  743. }
  744. /** Callback for sorting initial HSPs by score. */
  745. static int
  746. score_compare_match(const void* v1, const void* v2)
  747. {
  748. BlastInitHSP* h1,* h2;
  749. h1 = *(BlastInitHSP**) v1;
  750. h2 = *(BlastInitHSP**) v2;
  751. if (h1 == NULL || h2 == NULL || 
  752.             !h1->ungapped_data || !h2->ungapped_data)
  753. return 0;
  754. if (h1->ungapped_data->score < h2->ungapped_data->score) 
  755. return 1;
  756. if (h1->ungapped_data->score > h2->ungapped_data->score)
  757. return -1;
  758.    /* Tie breaks: starting offset in subject; then length
  759.     * (equivalent to ending offset in subject).
  760.     */
  761.    if (h1->ungapped_data->s_start < h2->ungapped_data->s_start)
  762.       return 1;
  763.    if (h1->ungapped_data->s_start > h2->ungapped_data->s_start )
  764.       return -1;
  765.    if (h1->ungapped_data->length < h2->ungapped_data->length)
  766.       return 1;
  767.    if (h1->ungapped_data->length > h2->ungapped_data->length)
  768.       return -1;
  769. return 0;
  770. }
  771. #define HSP_MAX_WINDOW 11
  772. Int4 
  773. BlastGetStartForGappedAlignment (Uint1* query, Uint1* subject,
  774.    const BlastScoreBlk* sbp, Uint4 q_start, Uint4 q_length, 
  775.    Uint4 s_start, Uint4 s_length)
  776. {
  777.     Int4 index1, max_offset, score, max_score, hsp_end;
  778.     Uint1* query_var,* subject_var;
  779.     Boolean positionBased = (sbp->posMatrix != NULL);
  780.     
  781.     if (q_length <= HSP_MAX_WINDOW) {
  782.         max_offset = q_start + q_length/2;
  783.         return max_offset;
  784.     }
  785.     hsp_end = q_start + HSP_MAX_WINDOW;
  786.     query_var = query + q_start;
  787.     subject_var = subject + s_start;
  788.     score=0;
  789.     for (index1=q_start; index1<hsp_end; index1++) {
  790.         if (!(positionBased))
  791.             score += sbp->matrix[*query_var][*subject_var];
  792.         else
  793.             score += sbp->posMatrix[index1][*subject_var];
  794.         query_var++; subject_var++;
  795.     }
  796.     max_score = score;
  797.     max_offset = hsp_end - 1;
  798.     hsp_end = q_start + MIN(q_length, s_length);
  799.     for (index1=q_start + HSP_MAX_WINDOW; index1<hsp_end; index1++) {
  800.         if (!(positionBased)) {
  801.             score -= sbp->matrix[*(query_var-HSP_MAX_WINDOW)][*(subject_var-HSP_MAX_WINDOW)];
  802.             score += sbp->matrix[*query_var][*subject_var];
  803.         } else {
  804.             score -= sbp->posMatrix[index1-HSP_MAX_WINDOW][*(subject_var-HSP_MAX_WINDOW)];
  805.             score += sbp->posMatrix[index1][*subject_var];
  806.         }
  807.         if (score > max_score) {
  808.             max_score = score;
  809.             max_offset = index1;
  810.         }
  811.         query_var++; subject_var++;
  812.     }
  813.     if (max_score > 0)
  814.        max_offset -= HSP_MAX_WINDOW/2;
  815.     else 
  816.        max_offset = q_start;
  817.     return max_offset;
  818. }
  819. static Boolean 
  820. Blast_GappedScorePrelimTest(Uint1 program_number, 
  821.         BLAST_SequenceBlk* query, BlastQueryInfo* query_info, 
  822.         BLAST_SequenceBlk* subject, 
  823.         BlastGapAlignStruct* gap_align,
  824.         const BlastScoringParameters* score_params,
  825.         const BlastExtensionParameters* ext_params,
  826.         const BlastHitSavingParameters* hit_params,
  827.         BlastInitHSP** init_hsp_array, Int4 init_hsp_count,
  828.         BlastGappedStats* gapped_stats)
  829. {
  830.    BlastInitHSP* init_hsp = NULL;
  831.    BlastInitHSP init_hsp_tmp;
  832.    Int4 index;
  833.    BLAST_SequenceBlk query_tmp;
  834.    Int4 context;
  835.    Int4 **orig_pssm;
  836.    Boolean further_process = FALSE;
  837.    Int4 gap_trigger;
  838.    Int4 cutoff_score;
  839.    Boolean is_prot;
  840.    Int4 max_offset;
  841.    Int2 status = 0;
  842.    gap_trigger = ext_params->gap_trigger;
  843.    cutoff_score = hit_params->cutoff_score;
  844.    is_prot = (program_number != blast_type_blastn);
  845.    orig_pssm = gap_align->sbp->posMatrix;
  846.    qsort(init_hsp_array, init_hsp_count,
  847.          sizeof(BlastInitHSP*), score_compare_match);
  848.    /* If no initial HSP passes the e-value threshold so far, check if any 
  849.       would do after gapped alignment, and exit if none are found. 
  850.       Only attempt to extend initial HSPs whose scores are already above 
  851.       gap trigger */
  852.    if (init_hsp_array[0]->ungapped_data && 
  853.        init_hsp_array[0]->ungapped_data->score < cutoff_score) {
  854.       init_hsp_tmp.ungapped_data = NULL;
  855.       for (index=0; index<init_hsp_count; index++) {
  856.          init_hsp = init_hsp_array[index];
  857.          if (init_hsp->ungapped_data && 
  858.              init_hsp->ungapped_data->score < gap_trigger)
  859.             break;
  860.          if (gapped_stats) {
  861.             ++gapped_stats->extra_extensions;
  862.             ++gapped_stats->extensions;
  863.          }
  864.          /* Don't modify initial HSP's coordinates here, because it will be 
  865.             done again if further processing is required */
  866.          GetRelativeCoordinates(query, query_info, init_hsp, &query_tmp, 
  867.                                 &init_hsp_tmp, &context);
  868.          if (orig_pssm)
  869.             gap_align->sbp->posMatrix = orig_pssm + 
  870.                                 query_info->context_offsets[context];
  871.          if(is_prot && !score_params->options->is_ooframe) {
  872.             max_offset = 
  873.                BlastGetStartForGappedAlignment(query_tmp.sequence, 
  874.                   subject->sequence, gap_align->sbp,
  875.                   init_hsp_tmp.ungapped_data->q_start,
  876.                   init_hsp_tmp.ungapped_data->length,
  877.                   init_hsp_tmp.ungapped_data->s_start,
  878.                   init_hsp_tmp.ungapped_data->length);
  879.             init_hsp_tmp.s_off += max_offset - init_hsp_tmp.q_off;
  880.             init_hsp_tmp.q_off = max_offset;
  881.          }
  882.          if (is_prot) {
  883.             status =  
  884.                BLAST_ProtGappedAlignment(program_number, &query_tmp, 
  885.                   subject, gap_align, score_params, &init_hsp_tmp);
  886.          } else {
  887.             status = 
  888.                BLAST_DynProgNtGappedAlignment(&query_tmp, subject, 
  889.                   gap_align, score_params, &init_hsp_tmp);
  890.          }
  891.          if (status) {
  892.             further_process = FALSE;
  893.             break;
  894.          }
  895.          if (gap_align->score >= cutoff_score) {
  896.             further_process = TRUE;
  897.             break;
  898.          }
  899.       }
  900.       sfree(init_hsp_tmp.ungapped_data);
  901.    } else {
  902.       index = 0;
  903.       further_process = TRUE;
  904.       if (gapped_stats)
  905.          ++gapped_stats->seqs_ungapped_passed;
  906.    }
  907.    if (!further_process) {
  908.       /* Free the ungapped data */
  909.       for (index = 0; index < init_hsp_count; ++index) {
  910.             sfree(init_hsp_array[index]->ungapped_data);
  911.       }
  912.       sfree(init_hsp_array);
  913.       gap_align->sbp->posMatrix = orig_pssm;
  914.    } else if (index > 0) { /* Sort again, if necessary */
  915.       qsort(init_hsp_array, init_hsp_count,
  916.                sizeof(BlastInitHSP*), score_compare_match);
  917.    }
  918.    return further_process;
  919. }
  920. Int2 BLAST_GetGappedScore (Uint1 program_number, 
  921.         BLAST_SequenceBlk* query, BlastQueryInfo* query_info, 
  922.         BLAST_SequenceBlk* subject, 
  923.         BlastGapAlignStruct* gap_align,
  924.         const BlastScoringParameters* score_params,
  925.         const BlastExtensionParameters* ext_params,
  926.         const BlastHitSavingParameters* hit_params,
  927.         BlastInitHitList* init_hitlist,
  928.         BlastHSPList** hsp_list_ptr, BlastGappedStats* gapped_stats)
  929. {
  930.    SSeqRange* helper = NULL;
  931.    Boolean hsp_start_is_contained, hsp_end_is_contained;
  932.    Int4 index, index1, next_offset;
  933.    BlastInitHSP* init_hsp = NULL;
  934.    BlastHSP* hsp1 = NULL;
  935.    Int4 q_start, s_start, q_end, s_end;
  936.    Boolean is_prot;
  937.    Int4 max_offset;
  938.    Int2 status = 0;
  939.    Int2 frame = 0; /* CHANGE!!!!!!!!!!!!!!!!! */
  940.    BlastInitHSP** init_hsp_array = NULL;
  941.    BlastHSPList* hsp_list = NULL;
  942.    const BlastHitSavingOptions* hit_options = hit_params->options;
  943.    BLAST_SequenceBlk query_tmp;
  944.    Int4 context;
  945.    Int4 **orig_pssm;
  946.    if (!query || !subject || !gap_align || !score_params || !ext_params ||
  947.        !hit_params || !init_hitlist || !hsp_list_ptr)
  948.       return 1;
  949.    if (init_hitlist->total == 0)
  950.       return 0;
  951.    is_prot = (program_number != blast_type_blastn);
  952.    orig_pssm = gap_align->sbp->posMatrix;
  953.    if (*hsp_list_ptr == NULL)
  954.       *hsp_list_ptr = hsp_list = Blast_HSPListNew(hit_options->hsp_num_max);
  955.    else 
  956.       hsp_list = *hsp_list_ptr;
  957.    init_hsp_array = (BlastInitHSP**) 
  958.       malloc(init_hitlist->total*sizeof(BlastInitHSP*));
  959.    for (index = 0; index < init_hitlist->total; ++index)
  960.       init_hsp_array[index] = &init_hitlist->init_hsp_array[index];
  961.    if (!Blast_GappedScorePrelimTest(program_number, query, query_info, 
  962.            subject, gap_align, score_params, ext_params, hit_params, 
  963.            init_hsp_array, init_hitlist->total, gapped_stats))
  964.       return 0;
  965.    /* helper contains most frequently used information to speed up access. */
  966.    helper = (SSeqRange*) malloc((init_hitlist->total)*sizeof(SSeqRange));
  967.    for (index=0; index<init_hitlist->total; index++)
  968.    {
  969.       hsp_start_is_contained = FALSE;
  970.       hsp_end_is_contained = FALSE;
  971.       init_hsp = init_hsp_array[index];
  972.       /* Now adjust the initial HSP's coordinates. */
  973.       GetRelativeCoordinates(query, query_info, init_hsp, &query_tmp, 
  974.                              NULL, &context);
  975.       if (orig_pssm)
  976.          gap_align->sbp->posMatrix = orig_pssm + 
  977.                                 query_info->context_offsets[context];
  978.       /* This prefetches this value for the test below. */
  979.       next_offset = init_hsp->q_off;
  980.       if (!init_hsp->ungapped_data) {
  981.          q_start = q_end = next_offset;
  982.          s_start = s_end = init_hsp->s_off;
  983.       } else {
  984.          q_start = init_hsp->ungapped_data->q_start;
  985.          q_end = q_start + init_hsp->ungapped_data->length;
  986.          s_start = init_hsp->ungapped_data->s_start;
  987.          s_end = s_start + init_hsp->ungapped_data->length;
  988.       }
  989.       hsp1 = NULL;
  990.       for (index1=0; index1<hsp_list->hspcnt; index1++)
  991.       {
  992.          hsp_start_is_contained = FALSE;
  993.          hsp_end_is_contained = FALSE;
  994.          
  995.          hsp1 = hsp_list->hsp_array[index1];
  996.          if (hsp1->context != context)
  997.             continue;
  998.          /* Check with the helper array whether further
  999.             tests are warranted.  Having only two ints
  1000.             in the helper array speeds up access. */
  1001.          if (helper[index1].left <= next_offset &&
  1002.              helper[index1].right >= next_offset)
  1003.          {
  1004.             if (CONTAINED_IN_HSP(hsp1->query.offset, hsp1->query.end, q_start,
  1005.                 hsp1->subject.offset, hsp1->subject.end, s_start) &&
  1006.                 (!init_hsp->ungapped_data || (SIGN(hsp1->query.frame) == 
  1007.                     SIGN(init_hsp->ungapped_data->frame))))
  1008.             {
  1009.                   hsp_start_is_contained = TRUE;
  1010.             }
  1011.             if (hsp_start_is_contained && (CONTAINED_IN_HSP(hsp1->query.offset,
  1012.                 hsp1->query.end, q_end, hsp1->subject.offset, 
  1013.                 hsp1->subject.end, s_end)))
  1014.             {
  1015.                hsp_end_is_contained = TRUE;
  1016.             }
  1017.             if (hsp_start_is_contained && hsp_end_is_contained && 
  1018.                 (!init_hsp->ungapped_data || 
  1019.                  init_hsp->ungapped_data->score <= hsp1->score))
  1020.                break;
  1021.          }
  1022.       }
  1023.       
  1024.       if (!hsp_start_is_contained || !hsp_end_is_contained || 
  1025.           (hsp1 && init_hsp->ungapped_data && 
  1026.            init_hsp->ungapped_data->score > hsp1->score)) {
  1027.          BlastHSP* new_hsp;
  1028.          if (gapped_stats) {
  1029.             ++gapped_stats->extensions;
  1030.          }
  1031.  
  1032.          if(is_prot && !score_params->options->is_ooframe) {
  1033.             max_offset = 
  1034.                BlastGetStartForGappedAlignment(query_tmp.sequence, 
  1035.                   subject->sequence, gap_align->sbp,
  1036.                   init_hsp->ungapped_data->q_start,
  1037.                   init_hsp->ungapped_data->length,
  1038.                   init_hsp->ungapped_data->s_start,
  1039.                   init_hsp->ungapped_data->length);
  1040.             init_hsp->s_off += max_offset - init_hsp->q_off;
  1041.             init_hsp->q_off = max_offset;
  1042.          }
  1043.          if (is_prot) {
  1044.             status =  BLAST_ProtGappedAlignment(program_number, &query_tmp, 
  1045.                          subject, gap_align, score_params, init_hsp);
  1046.          } else {
  1047.             status = BLAST_DynProgNtGappedAlignment(&query_tmp, subject, 
  1048.                          gap_align, score_params, init_hsp);
  1049.          }
  1050.          if (status) {
  1051.             sfree(init_hsp_array);
  1052.             gap_align->sbp->posMatrix = orig_pssm;
  1053.             return status;
  1054.          }
  1055.          Blast_HSPInit(gap_align->query_start, gap_align->query_stop,
  1056.                        gap_align->subject_start, gap_align->subject_stop, 
  1057.                        init_hsp->q_off, init_hsp->s_off, 
  1058.                        context, subject->frame, gap_align->score,
  1059.                        &(gap_align->edit_block), &new_hsp);
  1060.          Blast_HSPListSaveHSP(hsp_list, new_hsp);
  1061.          /* Fill in the helper structure. */
  1062.          helper[hsp_list->hspcnt - 1].left = gap_align->query_start;
  1063.          helper[hsp_list->hspcnt - 1].right = gap_align->query_stop;
  1064.       }
  1065.       /* Free ungapped data here - it's no longer needed */
  1066.       sfree(init_hsp->ungapped_data);
  1067.    }   
  1068.    sfree(init_hsp_array);
  1069.    sfree(helper);
  1070.    gap_align->sbp->posMatrix = orig_pssm;
  1071.       
  1072.    /* Remove any HSPs that share a starting or ending diagonal
  1073.       with a higher-scoring HSP. Do not perform this step with RPS
  1074.       blast, because the alignments can change during the traceback
  1075.       and thus may not share any diagonals later */
  1076.    if (is_prot && program_number != blast_type_rpsblast) {
  1077.       hsp_list->hspcnt = 
  1078.          CheckGappedAlignmentsForOverlap(hsp_list->hsp_array, 
  1079.             hsp_list->hspcnt, frame);
  1080.    }
  1081.    *hsp_list_ptr = hsp_list;
  1082.    return status;
  1083. }
  1084. /** Out-of-frame gapped alignment.
  1085.  * @param query Query sequence [in]
  1086.  * @param subject Subject sequence [in]
  1087.  * @param q_off Offset in query [in]
  1088.  * @param s_off Offset in subject [in]
  1089.  * @param S Start of the traceback buffer [in]
  1090.  * @param private_q_start Extent of alignment in query [out]
  1091.  * @param private_s_start Extent of alignment in subject [out]
  1092.  * @param score_only Return score only, without traceback [in]
  1093.  * @param sapp End of the traceback buffer [out]
  1094.  * @param gap_align Gapped alignment information and preallocated 
  1095.  *                  memory [in] [out]
  1096.  * @param score_params Scoring parameters [in]
  1097.  * @param psi_offset Starting position in PSI-BLAST matrix [in]
  1098.  * @param reversed Direction of the extension [in]
  1099.  * @param switch_seq Sequences need to be switched for blastx, 
  1100.  *                   but not for tblastn [in]
  1101.  */
  1102. static Int4 
  1103. OOF_SEMI_G_ALIGN_EX(Uint1* query, Uint1* subject, Int4 q_off, 
  1104.    Int4 s_off, Int4* S, Int4* private_q_start, Int4* private_s_start, 
  1105.    Boolean score_only, Int4** sapp, BlastGapAlignStruct* gap_align, 
  1106.    const BlastScoringParameters* score_params, Int4 psi_offset, 
  1107.    Boolean reversed, Boolean switch_seq)
  1108. {
  1109.    if (switch_seq) {
  1110.       return OOF_SEMI_G_ALIGN(subject, query, s_off, q_off, S, 
  1111.                 private_s_start, private_q_start, score_only, sapp, 
  1112.                 gap_align, score_params, psi_offset, reversed);
  1113.    } else {
  1114.       return OOF_SEMI_G_ALIGN(query, subject, q_off, s_off, S,
  1115.                 private_q_start, private_s_start, score_only, sapp, 
  1116.                 gap_align, score_params, psi_offset, reversed);
  1117.    }
  1118. }
  1119. #define MAX_SUBJECT_OFFSET 90000
  1120. #define MAX_TOTAL_GAPS 3000
  1121. void 
  1122. AdjustSubjectRange(Int4* subject_offset_ptr, Int4* subject_length_ptr, 
  1123.    Int4 query_offset, Int4 query_length, Int4* start_shift)
  1124. {
  1125.    Int4 s_offset;
  1126.    Int4 subject_length = *subject_length_ptr;
  1127.    Int4 max_extension_left, max_extension_right;
  1128.    
  1129.    /* If subject sequence is not too long, leave everything as is */
  1130.    if (subject_length < MAX_SUBJECT_OFFSET) {
  1131.       *start_shift = 0;
  1132.       return;
  1133.    }
  1134.    s_offset = *subject_offset_ptr;
  1135.    /* Maximal extension length is the remaining length in the query, plus 
  1136.       an estimate of a maximal total number of gaps. */
  1137.    max_extension_left = query_offset + MAX_TOTAL_GAPS;
  1138.    max_extension_right = query_length - query_offset + MAX_TOTAL_GAPS;
  1139.    if (s_offset <= max_extension_left) {
  1140.       *start_shift = 0;
  1141.    } else {
  1142.       *start_shift = s_offset - max_extension_left;
  1143.       *subject_offset_ptr = max_extension_left;
  1144.    }
  1145.    if (subject_length - s_offset > max_extension_right) {
  1146.       *subject_length_ptr = s_offset + max_extension_right - *start_shift;
  1147.    }
  1148. }
  1149. /** Performs gapped extension for protein sequences, given two
  1150.  * sequence blocks, scoring and extension options, and an initial HSP 
  1151.  * with information from the previously performed ungapped extension
  1152.  * @param program BLAST program [in]
  1153.  * @param query_blk The query sequence block [in]
  1154.  * @param subject_blk The subject sequence block [in]
  1155.  * @param gap_align The auxiliary structure for gapped alignment [in]
  1156.  * @param score_params Parameters related to scoring [in]
  1157.  * @param init_hsp The initial HSP information [in]
  1158.  */
  1159. static Int2 BLAST_ProtGappedAlignment(Uint1 program, 
  1160.    BLAST_SequenceBlk* query_blk, BLAST_SequenceBlk* subject_blk, 
  1161.    BlastGapAlignStruct* gap_align,
  1162.    const BlastScoringParameters* score_params, BlastInitHSP* init_hsp)
  1163. {
  1164.    Boolean found_start, found_end;
  1165.    Int4 q_length=0, s_length=0, score_right, score_left;
  1166.    Int4 private_q_start, private_s_start;
  1167.    Uint1* query=NULL,* subject=NULL;
  1168.    Boolean switch_seq = FALSE;
  1169.    Int4 query_length = query_blk->length;
  1170.    Int4 subject_length = subject_blk->length;
  1171.    Int4 subject_shift = 0;
  1172.    BlastScoringOptions *score_options = score_params->options;
  1173.     
  1174.    if (gap_align == NULL)
  1175.       return FALSE;
  1176.    
  1177.    if (score_options->is_ooframe) {
  1178.       q_length = init_hsp->q_off;
  1179.       s_length = init_hsp->s_off;
  1180.       if (program == blast_type_blastx) {
  1181.          subject = subject_blk->sequence + s_length;
  1182.          query = query_blk->oof_sequence + CODON_LENGTH + q_length;
  1183.          query_length -= CODON_LENGTH - 1;
  1184.          switch_seq = TRUE;
  1185.       } else if (program == blast_type_tblastn ||
  1186.                  program == blast_type_rpstblastn) {
  1187.          subject = subject_blk->oof_sequence + CODON_LENGTH + s_length;
  1188.          query = query_blk->sequence + q_length;
  1189.          subject_length -= CODON_LENGTH - 1;
  1190.       }
  1191.    } else {
  1192.       q_length = init_hsp->q_off + 1;
  1193.       s_length = init_hsp->s_off + 1;
  1194.       query = query_blk->sequence;
  1195.       subject = subject_blk->sequence;
  1196.    }
  1197.    AdjustSubjectRange(&s_length, &subject_length, q_length, query_length, 
  1198.                       &subject_shift);
  1199.    found_start = FALSE;
  1200.    found_end = FALSE;
  1201.     
  1202.    /* Looking for "left" score */
  1203.    score_left = 0;
  1204.    if (q_length != 0 && s_length != 0) {
  1205.       found_start = TRUE;
  1206.       if(score_options->is_ooframe) {
  1207.          score_left = OOF_SEMI_G_ALIGN_EX(query, subject, q_length, s_length,
  1208.                NULL, &private_q_start, &private_s_start, TRUE, NULL, 
  1209.                gap_align, score_params, q_length, TRUE, switch_seq);
  1210.       } else {
  1211.          score_left = SEMI_G_ALIGN_EX(query, subject+subject_shift, q_length, 
  1212.             s_length, NULL,
  1213.             &private_q_start, &private_s_start, TRUE, NULL, gap_align, 
  1214.             score_params, init_hsp->q_off, FALSE, TRUE);
  1215.       }
  1216.         
  1217.       gap_align->query_start = q_length - private_q_start;
  1218.       gap_align->subject_start = s_length - private_s_start + subject_shift;
  1219.       
  1220.    }
  1221.    score_right = 0;
  1222.    if (q_length < query_length && s_length < subject_length) {
  1223.       found_end = TRUE;
  1224.       if(score_options->is_ooframe) {
  1225.          score_right = OOF_SEMI_G_ALIGN_EX(query-1, subject-1, 
  1226.             query_length-q_length+1, subject_length-s_length+1,
  1227.             NULL, &(gap_align->query_stop), &(gap_align->subject_stop), 
  1228.             TRUE, NULL, gap_align, 
  1229.             score_params, q_length, FALSE, switch_seq);
  1230.          gap_align->query_stop += q_length;
  1231.          gap_align->subject_stop += s_length + subject_shift;
  1232.       } else {
  1233.          score_right = SEMI_G_ALIGN_EX(query+init_hsp->q_off,
  1234.             subject+init_hsp->s_off, query_length-q_length, 
  1235.             subject_length-s_length, NULL, &(gap_align->query_stop), 
  1236.             &(gap_align->subject_stop), TRUE, NULL, gap_align, 
  1237.             score_params, init_hsp->q_off, FALSE, FALSE);
  1238.          /* Make end offsets point to the byte after the end of the 
  1239.             alignment */
  1240.          gap_align->query_stop += init_hsp->q_off + 1;
  1241.          gap_align->subject_stop += init_hsp->s_off + 1;
  1242.       }
  1243.    }
  1244.    
  1245.    if (found_start == FALSE) { /* Start never found */
  1246.       gap_align->query_start = init_hsp->q_off;
  1247.       gap_align->subject_start = init_hsp->s_off;
  1248.    }
  1249.    
  1250.    if (found_end == FALSE) {
  1251.       gap_align->query_stop = init_hsp->q_off - 1;
  1252.       gap_align->subject_stop = init_hsp->s_off - 1;
  1253.       
  1254.       if(score_options->is_ooframe) {  /* Do we really need this ??? */
  1255.          gap_align->query_stop++;
  1256.          gap_align->subject_stop++;
  1257.       }
  1258.    }
  1259.    
  1260.    gap_align->score = score_right+score_left;
  1261.    return 0;
  1262. }
  1263. /** Copy of the TracebackToGapXEditBlock function from gapxdrop.c, only 
  1264.  * without 2 unused arguments 
  1265.  * @param S The traceback obtained from ALIGN [in]
  1266.  * @param M Length of alignment in query [in]
  1267.  * @param N Length of alignment in subject [in]
  1268.  * @param start1 Starting query offset [in]
  1269.  * @param start2 Starting subject offset [in]
  1270.  * @param edit_block The constructed edit block [out]
  1271.  */
  1272. Int2 
  1273. BLAST_TracebackToGapEditBlock(Int4* S, Int4 M, Int4 N, Int4 start1, 
  1274.                                Int4 start2, GapEditBlock** edit_block)
  1275. {
  1276.   Int4 i, j, op, number_of_subs, number_of_decline;
  1277.   GapEditScript* e_script;
  1278.   if (S == NULL)
  1279.      return -1;
  1280.   i = j = op = number_of_subs = number_of_decline = 0;
  1281.   *edit_block = GapEditBlockNew(start1, start2);
  1282.   (*edit_block)->esp = e_script = GapEditScriptNew(NULL);
  1283.   while(i < M || j < N) 
  1284.   {
  1285. op = *S;
  1286. if (op != MININT && number_of_decline > 0) 
  1287. {
  1288.                e_script->op_type = eGapAlignDecline;
  1289.                e_script->num = number_of_decline;
  1290.                e_script = GapEditScriptNew(e_script);
  1291. number_of_decline = 0;
  1292. }
  1293.         if (op != 0 && number_of_subs > 0) 
  1294. {
  1295.                         e_script->op_type = eGapAlignSub;
  1296.                         e_script->num = number_of_subs;
  1297.                         e_script = GapEditScriptNew(e_script);
  1298.                         number_of_subs = 0;
  1299.         }      
  1300. if (op == 0) {
  1301. i++; j++; number_of_subs++;
  1302. } else if (op == MININT) {
  1303. i++; j++;
  1304. number_of_decline++; 
  1305. }
  1306. else
  1307. {
  1308. if(op > 0) 
  1309. {
  1310. e_script->op_type = eGapAlignDel;
  1311. e_script->num = op;
  1312. j += op;
  1313. if (i < M || j < N)
  1314.                                 e_script = GapEditScriptNew(e_script);
  1315. }
  1316. else
  1317. {
  1318. e_script->op_type = eGapAlignIns;
  1319. e_script->num = ABS(op);
  1320. i += ABS(op);
  1321. if (i < M || j < N)
  1322.                                 e_script = GapEditScriptNew(e_script);
  1323. }
  1324.      }
  1325. S++;
  1326.   }
  1327.   if (number_of_subs > 0)
  1328.   {
  1329. e_script->op_type = eGapAlignSub;
  1330. e_script->num = number_of_subs;
  1331.   } else if (number_of_decline > 0) {
  1332.         e_script->op_type = eGapAlignDecline;
  1333.         e_script->num = number_of_decline;
  1334.   }
  1335.   return 0;
  1336. }
  1337. /** Converts a OOF traceback from the gapped alignment to a GapEditBlock.
  1338.  * This function is for out-of-frame gapping:
  1339.  * index1 is for the protein, index2 is for the nucleotides.
  1340.  * 0: deletion of a dna codon, i.e dash aligned with a protein letter.
  1341.  * 1: one nucleotide vs a protein, deletion of 2 nuc.
  1342.  * 2: 2 nucleotides aligned with a protein, i.e deletion of one nuc.
  1343.  * 3: substitution, 3 nucleotides vs an amino acid.
  1344.  * 4: 4 nuc vs an amino acid.
  1345.  * 5: 5 nuc vs an amino acid.
  1346.  * 6: a codon aligned with a dash. opposite of 0.
  1347.  */
  1348. static Int2
  1349. BLAST_OOFTracebackToGapEditBlock(Int4* S, Int4 q_length, 
  1350.    Int4 s_length, Int4 q_start, Int4 s_start, Uint1 program, 
  1351.    GapEditBlock** edit_block_ptr)
  1352. {
  1353.     register Int4 current_val, last_val, number, index1, index2;
  1354.     Int4 M, N;
  1355.     GapEditScript* e_script;
  1356.     GapEditBlock* edit_block;
  1357.     
  1358.     if (S == NULL)
  1359.         return -1;
  1360.     
  1361.     number = 0;
  1362.     index1 = 0;
  1363.     index2 = 0;
  1364.     
  1365.     *edit_block_ptr = edit_block = GapEditBlockNew(q_start, s_start);
  1366.     edit_block->is_ooframe = TRUE;
  1367.     if (program == blast_type_blastx) {
  1368.         M = s_length;
  1369.         N = q_length;
  1370.     } else {
  1371.         M = q_length;
  1372.         N = s_length;
  1373.     }
  1374.     edit_block->esp = e_script = GapEditScriptNew(NULL);
  1375.     
  1376.     last_val = *S;
  1377.     
  1378.     /* index1, M - index and length of protein, 
  1379.        index2, N - length of the nucleotide */
  1380.     
  1381.     for(index1 = 0, index2 = 0; index1 < M && index2 < N; S++, number++) {
  1382.         
  1383.         current_val = *S;
  1384.         /* New script element will be created for any new frameshift
  1385.            region  0,3,6 will be collected in a single segment */
  1386.         if (current_val != last_val || (current_val%3 != 0 && 
  1387.                                         edit_block->esp != e_script)) {
  1388.             e_script->num = number;
  1389.             e_script = GapEditScriptNew(e_script);
  1390.             
  1391.             /* if(last_val%3 != 0 && current_val%3 == 0) */
  1392.             if(last_val%3 != 0 && current_val == eGapAlignSub) 
  1393.                 /* 1, 2, 4, 5 vs. 0, 3, 6*/                
  1394.                 number = 1;
  1395.             else
  1396.                 number = 0;
  1397.         }
  1398.         
  1399.         last_val = current_val;
  1400.         
  1401.         /* for out_of_frame == TRUE - we have op_type == S parameter */
  1402.         e_script->op_type = current_val;
  1403.         
  1404.         if(current_val != eGapAlignIns) {
  1405.             index1++;
  1406.             index2 += current_val;
  1407.         } else {
  1408.             index2 += 3;
  1409.         }
  1410.     }
  1411.     /* Get the last one. */    
  1412.     e_script->num = number;
  1413.     return 0;
  1414. }
  1415. Int2 BLAST_GappedAlignmentWithTraceback(Uint1 program, Uint1* query, 
  1416.         Uint1* subject, BlastGapAlignStruct* gap_align, 
  1417.         const BlastScoringParameters* score_params,
  1418.         Int4 q_start, Int4 s_start, Int4 query_length, Int4 subject_length)
  1419. {
  1420.     Boolean found_start, found_end;
  1421.     Int4 score_right, score_left, private_q_length, private_s_length, tmp;
  1422.     Int4 q_length, s_length;
  1423.     Int4 prev;
  1424.     Int4* tback,* tback1,* p = NULL,* q;
  1425.     Boolean is_ooframe = score_params->options->is_ooframe;
  1426.     Int2 status = 0;
  1427.     Boolean switch_seq = FALSE;
  1428.     
  1429.     if (gap_align == NULL)
  1430.         return -1;
  1431.     
  1432.     found_start = FALSE;
  1433.     found_end = FALSE;
  1434.     
  1435.     q_length = query_length;
  1436.     s_length = subject_length;
  1437.     if (is_ooframe) {
  1438.        /* The mixed frame sequence is shifted to the 3rd position, so its 
  1439.           maximal available length for extension is less by 2 than its 
  1440.           total length. */
  1441.        switch_seq = (program == blast_type_blastx);
  1442.        if (switch_seq) {
  1443.           q_length -= CODON_LENGTH - 1;
  1444.        } else {
  1445.           s_length -= CODON_LENGTH - 1;
  1446.        }
  1447.     }
  1448.     tback = tback1 = (Int4*)
  1449.        malloc((s_length + q_length)*sizeof(Int4));
  1450.     score_left = 0; prev = 3;
  1451.     found_start = TRUE;
  1452.         
  1453.     if(is_ooframe) {
  1454.        /* NB: Left extension does not include starting point corresponding
  1455.           to the offset pair; the right extension does. */
  1456.        score_left =
  1457.           OOF_SEMI_G_ALIGN_EX(query+q_start, subject+s_start, q_start, 
  1458.              s_start, tback, &private_q_length, &private_s_length, FALSE,
  1459.              &tback1, gap_align, score_params, q_start, TRUE, switch_seq);
  1460.        gap_align->query_start = q_start - private_q_length;
  1461.        gap_align->subject_start = s_start - private_s_length;
  1462.     } else {        
  1463.        /* NB: The left extension includes the starting point 
  1464.           [q_start,s_start]; the right extension does not. */
  1465.        score_left = 
  1466.           SEMI_G_ALIGN_EX(query, subject, q_start+1, s_start+1, tback, 
  1467.              &private_q_length, &private_s_length, FALSE, &tback1, 
  1468.              gap_align, score_params, q_start, FALSE, TRUE);
  1469.        gap_align->query_start = q_start - private_q_length + 1;
  1470.        gap_align->subject_start = s_start - private_s_length + 1;
  1471.     }
  1472.     
  1473.     for(p = tback, q = tback1-1; p < q; p++, q--)  {
  1474.        tmp = *p;
  1475.        *p = *q;
  1476.        *q = tmp;
  1477.     }
  1478.         
  1479.     if(is_ooframe){
  1480.        for (prev = 3, p = tback; p < tback1; p++) {
  1481.           if (*p == 0 || *p ==  6) continue;
  1482.           tmp = *p; *p = prev; prev = tmp;
  1483.        }
  1484.     }
  1485.     
  1486.     score_right = 0;
  1487.     if ((q_start < q_length) && (s_start < s_length)) {
  1488.        found_end = TRUE;
  1489.        if(is_ooframe) {
  1490.           score_right = 
  1491.              OOF_SEMI_G_ALIGN_EX(query+q_start-1, subject+s_start-1, 
  1492.                 q_length-q_start, s_length-s_start, 
  1493.                 tback1, &private_q_length, &private_s_length, FALSE,
  1494.                 &tback1, gap_align, score_params, q_start, FALSE, switch_seq);
  1495.             if (prev != 3 && p) {
  1496.                 while (*p == 0 || *p == 6) p++;
  1497.                 *p = prev+*p-3;
  1498.             }
  1499.         } else {
  1500.             score_right = 
  1501.                SEMI_G_ALIGN_EX(query+q_start, subject+s_start, 
  1502.                   q_length-q_start-1, s_length-s_start-1, 
  1503.                   tback1, &private_q_length, &private_s_length, FALSE, 
  1504.                   &tback1, gap_align, score_params, q_start, FALSE, FALSE);
  1505.         }
  1506.         gap_align->query_stop = q_start + private_q_length + 1;
  1507.         gap_align->subject_stop = s_start + private_s_length + 1;
  1508.     }
  1509.     
  1510.     if (found_start == FALSE) { /* Start never found */
  1511.         gap_align->query_start = q_start;
  1512.         gap_align->subject_start = s_start;
  1513.     }
  1514.     
  1515.     if (found_end == FALSE) {
  1516.         gap_align->query_stop = q_start - 1;
  1517.         gap_align->subject_stop = s_start - 1;
  1518.     }
  1519.     if(is_ooframe) {
  1520.         status = BLAST_OOFTracebackToGapEditBlock(tback, 
  1521.            gap_align->query_stop-gap_align->query_start, 
  1522.            gap_align->subject_stop-gap_align->subject_start, 
  1523.            gap_align->query_start, gap_align->subject_start, 
  1524.            program, &gap_align->edit_block);
  1525.     } else {
  1526.         status = BLAST_TracebackToGapEditBlock(tback, 
  1527.            gap_align->query_stop-gap_align->query_start, 
  1528.            gap_align->subject_stop-gap_align->subject_start, 
  1529.            gap_align->query_start, gap_align->subject_start,
  1530.            &gap_align->edit_block);
  1531.     }
  1532.     gap_align->edit_block->length1 = query_length;
  1533.     gap_align->edit_block->length2 = subject_length;
  1534. #if 0 /** How can these be assigned???? This data is now not in gap_align. */
  1535.     gap_align->edit_block->translate1 = gap_align->translate1;
  1536.     gap_align->edit_block->translate2 = gap_align->translate2;
  1537.     gap_align->edit_block->discontinuous = gap_align->discontinuous;
  1538. #endif
  1539.     sfree(tback);
  1540.     gap_align->score = score_right+score_left;
  1541.     
  1542.     return status;
  1543. }
  1544. static Int4 
  1545. GetPatternLengthFromGapAlignStruct(BlastGapAlignStruct* gap_align)
  1546. {
  1547.    /* Kludge: pattern lengths are saved in the output structure member 
  1548.       query_stop. Probably should be changed??? */
  1549.    return gap_align->query_stop;
  1550. }
  1551. Int2 PHIGappedAlignmentWithTraceback(Uint1 program, 
  1552.         Uint1* query, Uint1* subject, 
  1553.         BlastGapAlignStruct* gap_align, 
  1554.         const BlastScoringParameters* score_params,
  1555.         Int4 q_start, Int4 s_start, Int4 query_length, Int4 subject_length)
  1556. {
  1557.     Boolean found_end;
  1558.     Int4 score_right, score_left, private_q_length, private_s_length, tmp;
  1559.     Int4* tback,* tback1,* p = NULL,* q;
  1560.     Int2 status = 0;
  1561.     Int4 pat_length;
  1562.     
  1563.     if (gap_align == NULL)
  1564.         return -1;
  1565.     
  1566.     found_end = FALSE;
  1567.     
  1568.     tback = tback1 = (Int4*)
  1569.        malloc((subject_length + query_length)*sizeof(Int4));
  1570.     score_left = 0;
  1571.         
  1572.     score_left = 
  1573.        SEMI_G_ALIGN_EX(query, subject, q_start, s_start, tback, 
  1574.            &private_q_length, &private_s_length, FALSE, &tback1, 
  1575.           gap_align, score_params, q_start, FALSE, TRUE);
  1576.     gap_align->query_start = q_start - private_q_length;
  1577.     gap_align->subject_start = s_start - private_s_length;
  1578.     
  1579.     for(p = tback, q = tback1-1; p < q; p++, q--)  {
  1580.        tmp = *p;
  1581.        *p = *q;
  1582.        *q = tmp;
  1583.     }
  1584.         
  1585.     pat_length = GetPatternLengthFromGapAlignStruct(gap_align);
  1586.     memset(tback1, 0, pat_length*sizeof(Int4));
  1587.     tback1 += pat_length;
  1588.     score_right = 0;
  1589.     q_start += pat_length - 1;
  1590.     s_start += pat_length - 1;
  1591.     if ((q_start < query_length) && (s_start < subject_length)) {
  1592.        found_end = TRUE;
  1593.        score_right = 
  1594.           SEMI_G_ALIGN_EX(query+q_start, subject+s_start, 
  1595.              query_length-q_start-1, subject_length-s_start-1, 
  1596.              tback1, &private_q_length, &private_s_length, FALSE, 
  1597.              &tback1, gap_align, score_params, q_start, FALSE, FALSE);
  1598.        gap_align->query_stop = q_start + private_q_length + 1;
  1599.        gap_align->subject_stop = s_start + private_s_length + 1; 
  1600.     }
  1601.     
  1602.     if (found_end == FALSE) {
  1603.         gap_align->query_stop = q_start;
  1604.         gap_align->subject_stop = s_start;
  1605.     }
  1606.     status = BLAST_TracebackToGapEditBlock(tback, 
  1607.                 gap_align->query_stop-gap_align->query_start, 
  1608.                 gap_align->subject_stop-gap_align->subject_start, 
  1609.                 gap_align->query_start, gap_align->subject_start,
  1610.                 &gap_align->edit_block);
  1611.     gap_align->edit_block->length1 = query_length;
  1612.     gap_align->edit_block->length2 = subject_length;
  1613.     sfree(tback);
  1614.     gap_align->score = score_right+score_left;
  1615.     
  1616.     return status;
  1617. }
  1618. Int2 BLAST_GetUngappedHSPList(BlastInitHitList* init_hitlist,
  1619.         BlastQueryInfo* query_info, BLAST_SequenceBlk* subject, 
  1620.         const BlastHitSavingOptions* hit_options, 
  1621.         BlastHSPList** hsp_list_ptr)
  1622. {
  1623.    BlastHSPList* hsp_list = NULL;
  1624.    Int4 index;
  1625.    BlastInitHSP* init_hsp;
  1626.    Int4 context;
  1627.    /* The BlastHSPList structure can be allocated and passed from outside */
  1628.    if (*hsp_list_ptr != NULL)
  1629.       hsp_list = *hsp_list_ptr;
  1630.    if (!init_hitlist) {
  1631.       if (!hsp_list)
  1632.          *hsp_list_ptr = NULL;
  1633.       else
  1634.          hsp_list->hspcnt = 0;
  1635.       return 0;
  1636.    }
  1637.    for (index = 0; index < init_hitlist->total; ++index) {
  1638.       BlastHSP* new_hsp;
  1639.       BlastUngappedData* ungapped_data=NULL;
  1640.       init_hsp = &init_hitlist->init_hsp_array[index];
  1641.       if (!init_hsp->ungapped_data) 
  1642.          continue;
  1643.       /* Adjust the initial HSP's coordinates in case of concatenated 
  1644.          multiple queries/strands/frames */
  1645.       GetRelativeCoordinates(NULL, query_info, init_hsp, NULL, 
  1646.                              NULL, &context);
  1647.       if (!hsp_list) {
  1648.          hsp_list = Blast_HSPListNew(hit_options->hsp_num_max);
  1649.          *hsp_list_ptr = hsp_list;
  1650.       }
  1651.       ungapped_data = init_hsp->ungapped_data;
  1652.       Blast_HSPInit(ungapped_data->q_start, ungapped_data->length+ungapped_data->q_start,
  1653.                     ungapped_data->s_start, ungapped_data->length+ungapped_data->s_start,
  1654.                     init_hsp->q_off, init_hsp->s_off, 
  1655.                     context, subject->frame, ungapped_data->score,
  1656.                     NULL, &new_hsp);
  1657.       Blast_HSPListSaveHSP(hsp_list, new_hsp);
  1658.    }
  1659.    return 0;
  1660. }
  1661. /** Performs gapped extension for PHI BLAST, given two
  1662.  * sequence blocks, scoring and extension options, and an initial HSP 
  1663.  * with information from the previously performed ungapped extension
  1664.  * @param program BLAST program [in]
  1665.  * @param query_blk The query sequence block [in]
  1666.  * @param subject_blk The subject sequence block [in]
  1667.  * @param gap_align The auxiliary structure for gapped alignment [in]
  1668.  * @param score_params Parameters related to scoring [in]
  1669.  * @param init_hsp The initial HSP information [in]
  1670.  */
  1671. static Int2 PHIGappedAlignment(Uint1 program, 
  1672.    BLAST_SequenceBlk* query_blk, BLAST_SequenceBlk* subject_blk, 
  1673.    BlastGapAlignStruct* gap_align,
  1674.    const BlastScoringParameters* score_params, BlastInitHSP* init_hsp)
  1675. {
  1676.    Boolean found_start, found_end;
  1677.    Int4 q_length=0, s_length=0, score_right, score_left;
  1678.    Int4 private_q_start, private_s_start;
  1679.    Uint1* query,* subject;
  1680.     
  1681.    if (gap_align == NULL)
  1682.       return FALSE;
  1683.    
  1684.    q_length = init_hsp->q_off;
  1685.    s_length = init_hsp->s_off;
  1686.    query = query_blk->sequence;
  1687.    subject = subject_blk->sequence;
  1688.    found_start = FALSE;
  1689.    found_end = FALSE;
  1690.     
  1691.    /* Looking for "left" score */
  1692.    score_left = 0;
  1693.    if (q_length != 0 && s_length != 0) {
  1694.       found_start = TRUE;
  1695.       score_left = 
  1696.          SEMI_G_ALIGN_EX(query, subject, q_length, s_length, NULL,
  1697.             &private_q_start, &private_s_start, TRUE, NULL, gap_align, 
  1698.             score_params, init_hsp->q_off, FALSE, TRUE);
  1699.         
  1700.       gap_align->query_start = q_length - private_q_start + 1;
  1701.       gap_align->subject_start = s_length - private_s_start + 1;
  1702.       
  1703.    } else {
  1704.       q_length = init_hsp->q_off;
  1705.       s_length = init_hsp->s_off;
  1706.    }
  1707.    /* Pattern itself is not included in the gapped alignment */
  1708.    q_length += init_hsp->ungapped_data->length - 1;
  1709.    s_length += init_hsp->ungapped_data->length - 1;
  1710.    score_right = 0;
  1711.    if (init_hsp->q_off < query_blk->length && 
  1712.        init_hsp->s_off < subject_blk->length) {
  1713.       found_end = TRUE;
  1714.       score_right = SEMI_G_ALIGN_EX(query+q_length,
  1715.          subject+s_length, query_blk->length-q_length, 
  1716.          subject_blk->length-s_length, NULL, &(gap_align->query_stop), 
  1717.          &(gap_align->subject_stop), TRUE, NULL, gap_align, 
  1718.          score_params, q_length, FALSE, FALSE);
  1719.       gap_align->query_stop += q_length;
  1720.       gap_align->subject_stop += s_length;
  1721.    }
  1722.    
  1723.    if (found_start == FALSE) { /* Start never found */
  1724.       gap_align->query_start = init_hsp->q_off;
  1725.       gap_align->subject_start = init_hsp->s_off;
  1726.    }
  1727.    
  1728.    if (found_end == FALSE) {
  1729.       gap_align->query_stop = init_hsp->q_off - 1;
  1730.       gap_align->subject_stop = init_hsp->s_off - 1;
  1731.    }
  1732.    
  1733.    gap_align->score = score_right+score_left;
  1734.    return 0;
  1735. }
  1736. Int2 PHIGetGappedScore (Uint1 program_number, 
  1737.         BLAST_SequenceBlk* query, BlastQueryInfo* query_info, 
  1738.         BLAST_SequenceBlk* subject, 
  1739.         BlastGapAlignStruct* gap_align,
  1740.         const BlastScoringParameters* score_params,
  1741.         const BlastExtensionParameters* ext_params,
  1742.         const BlastHitSavingParameters* hit_params,
  1743.         BlastInitHitList* init_hitlist,
  1744.         BlastHSPList** hsp_list_ptr, BlastGappedStats* gapped_stats)
  1745. {
  1746.    BlastHSPList* hsp_list;
  1747.    BlastInitHSP** init_hsp_array;
  1748.    BlastInitHSP* init_hsp;
  1749.    Int4 index;
  1750.    Int2 status = 0;
  1751.    BlastHitSavingOptions* hit_options;
  1752.    BLAST_SequenceBlk query_tmp;
  1753.    Int4 context;
  1754.    if (!query || !subject || !gap_align || !score_params || !ext_params ||
  1755.        !hit_params || !init_hitlist || !hsp_list_ptr)
  1756.       return 1;
  1757.    if (init_hitlist->total == 0)
  1758.       return 0;
  1759.    hit_options = hit_params->options;
  1760.    if (*hsp_list_ptr == NULL)
  1761.       *hsp_list_ptr = hsp_list = Blast_HSPListNew(hit_options->hsp_num_max);
  1762.    else 
  1763.       hsp_list = *hsp_list_ptr;
  1764.    init_hsp_array = (BlastInitHSP**) 
  1765.       malloc(init_hitlist->total*sizeof(BlastInitHSP*));
  1766.    for (index = 0; index < init_hitlist->total; ++index)
  1767.       init_hsp_array[index] = &init_hitlist->init_hsp_array[index];
  1768.    for (index=0; index<init_hitlist->total; index++)
  1769.    {
  1770.       BlastHSP* new_hsp;
  1771.       init_hsp = init_hsp_array[index];
  1772.       if (gapped_stats)
  1773.          ++gapped_stats->extensions;
  1774.       /* Adjust the initial HSP's coordinates to ones relative to an 
  1775.          individual query sequence */
  1776.       GetRelativeCoordinates(query, query_info, init_hsp, &query_tmp, 
  1777.                              NULL, &context);
  1778.       status =  PHIGappedAlignment(program_number, &query_tmp, 
  1779.                    subject, gap_align, score_params, init_hsp);
  1780.       if (status) {
  1781.          sfree(init_hsp_array);
  1782.          return status;
  1783.       }
  1784.       Blast_HSPInit(gap_align->query_start, gap_align->query_stop,
  1785.                     gap_align->subject_start, gap_align->subject_stop, 
  1786.                     init_hsp->q_off, init_hsp->s_off, 
  1787.                     context, subject->frame, gap_align->score,
  1788.                     &(gap_align->edit_block), &new_hsp);
  1789.       new_hsp->pattern_length = init_hsp->ungapped_data->length;
  1790.       Blast_HSPListSaveHSP(hsp_list, new_hsp);
  1791.       /* Free ungapped data here - it's no longer needed */
  1792.       sfree(init_hsp->ungapped_data);
  1793.    }   
  1794.    sfree(init_hsp_array);
  1795.    *hsp_list_ptr = hsp_list;
  1796.    return status;
  1797. }