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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: blast_seqalign.cpp,v $
  4.  * PRODUCTION Revision 1000.6  2004/06/01 18:05:52  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.42
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: blast_seqalign.cpp,v 1000.6 2004/06/01 18:05:52 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 official 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:  Christiam Camacho
  35. *
  36. * ===========================================================================
  37. */
  38. /// @file blast_seqalign.cpp
  39. /// Utility function to convert internal BLAST result structures into
  40. /// CSeq_align_set objects.
  41. #include <ncbi_pch.hpp>
  42. #include "blast_seqalign.hpp"
  43. #include <objects/seqloc/Seq_loc.hpp>
  44. #include <objects/seqloc/Seq_interval.hpp>
  45. #include <objects/seqalign/Seq_align.hpp>
  46. #include <objects/seqalign/Seq_align_set.hpp>
  47. #include <objects/seqalign/Dense_seg.hpp>
  48. #include <objects/seqalign/Dense_diag.hpp>
  49. #include <objects/seqalign/Std_seg.hpp>
  50. #include <objects/seqalign/Score.hpp>
  51. #include <objects/general/Object_id.hpp>
  52. #include <objmgr/util/sequence.hpp>
  53. #include <serial/iterator.hpp>
  54. /** @addtogroup AlgoBlast
  55.  *
  56.  * @{
  57.  */
  58. BEGIN_NCBI_SCOPE
  59. USING_SCOPE(objects);
  60. BEGIN_SCOPE(blast)
  61. #ifndef SMALLEST_EVALUE
  62. #define SMALLEST_EVALUE 1.0e-180
  63. #endif
  64. #ifndef GAP_VALUE
  65. #define GAP_VALUE -1
  66. #endif
  67. // Converts a frame into the appropriate strand
  68. static ENa_strand
  69. x_Frame2Strand(short frame)
  70. {
  71.     if (frame > 0)
  72.         return eNa_strand_plus;
  73.     else if (frame < 0)
  74.         return eNa_strand_minus;
  75.     else
  76.         return eNa_strand_unknown;
  77. }
  78. static int 
  79. x_GetCurrPos(int& pos, int pos2advance)
  80. {
  81.     int retval;
  82.     if (pos < 0)
  83.         retval = -(pos + pos2advance - 1);
  84.     else
  85.         retval = pos;
  86.     pos += pos2advance;
  87.     return retval;
  88. }
  89. static TSeqPos
  90. x_GetAlignmentStart(int& curr_pos, const GapEditScript* esp, 
  91.         ENa_strand strand, bool translate, int length, int original_length, 
  92.         short frame)
  93. {
  94.     TSeqPos retval;
  95.     if (strand == eNa_strand_minus) {
  96.         if (translate)
  97.             retval = original_length - 
  98.                 CODON_LENGTH*(x_GetCurrPos(curr_pos, esp->num) + esp->num)
  99.                 + frame + 1;
  100.         else
  101.             retval = length - x_GetCurrPos(curr_pos, esp->num) - esp->num;
  102.     } else {
  103.         if (translate)
  104.             retval = frame - 1 + CODON_LENGTH*x_GetCurrPos(curr_pos, esp->num);
  105.         else
  106.             retval = x_GetCurrPos(curr_pos, esp->num);
  107.     }
  108.     return retval;
  109. }
  110. /// C++ version of GXECollectDataForSeqalign
  111. /// Note that even though the edit_block is passed in, data for seqalign is
  112. /// collected from the esp argument for nsegs segments
  113. static void
  114. x_CollectSeqAlignData(const GapEditBlock* edit_block, 
  115.         const GapEditScript* esp_head, unsigned int nsegs,
  116.         vector<TSignedSeqPos>& starts, vector<TSeqPos>& lengths, 
  117.         vector<ENa_strand>& strands)
  118. {
  119.     ASSERT(edit_block != NULL);
  120.     GapEditScript* esp = const_cast<GapEditScript*>(esp_head);
  121.     ENa_strand m_strand, s_strand;      // strands of alignment
  122.     TSignedSeqPos m_start, s_start;     // running starts of alignment
  123.     int start1 = edit_block->start1;    // start of alignment on master sequence
  124.     int start2 = edit_block->start2;    // start of alignment on slave sequence
  125.     m_strand = x_Frame2Strand(edit_block->frame1);
  126.     s_strand = x_Frame2Strand(edit_block->frame2);
  127.     for (unsigned int i = 0; esp && i < nsegs; esp = esp->next, i++) {
  128.         switch (esp->op_type) {
  129.         case eGapAlignDecline:
  130.         case eGapAlignSub:
  131.             m_start = x_GetAlignmentStart(start1, esp, m_strand,
  132.                     edit_block->translate1 != 0, edit_block->length1,
  133.                     edit_block->original_length1, edit_block->frame1);
  134.             s_start = x_GetAlignmentStart(start2, esp, s_strand,
  135.                     edit_block->translate2 != 0, edit_block->length2,
  136.                     edit_block->original_length2, edit_block->frame2);
  137.             if (edit_block->reverse) {
  138.                 strands.push_back(s_strand);
  139.                 strands.push_back(m_strand);
  140.                 starts.push_back(s_start);
  141.                 starts.push_back(m_start);
  142.             } else {
  143.                 strands.push_back(m_strand);
  144.                 strands.push_back(s_strand);
  145.                 starts.push_back(m_start);
  146.                 starts.push_back(s_start);
  147.             }
  148.             break;
  149.         // Insertion on the master sequence (gap on slave)
  150.         case eGapAlignIns:
  151.             m_start = x_GetAlignmentStart(start1, esp, m_strand,
  152.                     edit_block->translate1 != 0, edit_block->length1,
  153.                     edit_block->original_length1, edit_block->frame1);
  154.             s_start = GAP_VALUE;
  155.             if (edit_block->reverse) {
  156.                 strands.push_back(i == 0 ? eNa_strand_unknown : s_strand);
  157.                 strands.push_back(m_strand);
  158.                 starts.push_back(s_start);
  159.                 starts.push_back(m_start);
  160.             } else {
  161.                 strands.push_back(m_strand);
  162.                 strands.push_back(i == 0 ? eNa_strand_unknown : s_strand);
  163.                 starts.push_back(m_start);
  164.                 starts.push_back(s_start);
  165.             }
  166.             break;
  167.         // Deletion on master sequence (gap; insertion on slave)
  168.         case eGapAlignDel:
  169.             m_start = GAP_VALUE;
  170.             s_start = x_GetAlignmentStart(start2, esp, s_strand,
  171.                     edit_block->translate2 != 0, edit_block->length2,
  172.                     edit_block->original_length2, edit_block->frame2);
  173.             if (edit_block->reverse) {
  174.                 strands.push_back(s_strand);
  175.                 strands.push_back(i == 0 ? eNa_strand_unknown : m_strand);
  176.                 starts.push_back(s_start);
  177.                 starts.push_back(m_start);
  178.             } else {
  179.                 strands.push_back(i == 0 ? eNa_strand_unknown : m_strand);
  180.                 strands.push_back(s_strand);
  181.                 starts.push_back(m_start);
  182.                 starts.push_back(s_start);
  183.             }
  184.             break;
  185.         default:
  186.             break;
  187.         }
  188.         lengths.push_back(esp->num);
  189.     }
  190.     // Make sure the vectors have the right size
  191.     if (lengths.size() != nsegs)
  192.         lengths.resize(nsegs);
  193.     if (starts.size() != nsegs*2)
  194.         starts.resize(nsegs*2);
  195.     if (strands.size() != nsegs*2)
  196.         strands.resize(nsegs*2);
  197. }
  198. static CRef<CDense_seg>
  199. x_CreateDenseg(const CSeq_id* master, const CSeq_id* slave,
  200.         vector<TSignedSeqPos>& starts, vector<TSeqPos>& lengths, 
  201.         vector<ENa_strand>& strands)
  202. {
  203.     ASSERT(master);
  204.     ASSERT(slave);
  205.     CRef<CDense_seg> dense_seg(new CDense_seg());
  206.     // Pairwise alignment is 2 dimensional
  207.     dense_seg->SetDim(2);
  208.     // Set the sequence ids
  209.     CDense_seg::TIds& ids = dense_seg->SetIds();
  210.     CRef<CSeq_id> tmp(new CSeq_id(master->AsFastaString()));
  211.     ids.push_back(tmp);
  212.     tmp.Reset(new CSeq_id(slave->AsFastaString()));
  213.     ids.push_back(tmp);
  214.     ids.resize(dense_seg->GetDim());
  215.     dense_seg->SetLens() = lengths;
  216.     dense_seg->SetStrands() = strands;
  217.     dense_seg->SetStarts() = starts;
  218.     dense_seg->SetNumseg(lengths.size());
  219.     return dense_seg;
  220. }
  221. static CSeq_align::C_Segs::TStd
  222. x_CreateStdSegs(const CSeq_id* master, const CSeq_id* slave, 
  223.         vector<TSignedSeqPos>& starts, vector<TSeqPos>& lengths, 
  224.         vector<ENa_strand>& strands, bool reverse, bool translate_master, bool
  225.         translate_slave)
  226. {
  227.     ASSERT(master);
  228.     ASSERT(slave);
  229.     CSeq_align::C_Segs::TStd retval;
  230.     int nsegs = lengths.size();         // number of segments in alignment
  231.     TSignedSeqPos m_start, m_stop;      // start and stop for master sequence
  232.     TSignedSeqPos s_start, s_stop;      // start and stop for slave sequence
  233.     CRef<CSeq_id> master_id(new CSeq_id(master->AsFastaString()));
  234.     CRef<CSeq_id> slave_id(new CSeq_id(slave->AsFastaString()));
  235.     
  236.     for (int i = 0; i < nsegs; i++) {
  237.         CRef<CStd_seg> std_seg(new CStd_seg());
  238.         CRef<CSeq_loc> master_loc(new CSeq_loc());
  239.         CRef<CSeq_loc> slave_loc(new CSeq_loc());
  240.         // Pairwise alignment is 2 dimensional
  241.         std_seg->SetDim(2);
  242.         // Set master seqloc
  243.         if ( (m_start = starts[2*i]) != GAP_VALUE) {
  244.             master_loc->SetInt().SetId(*master_id);
  245.             master_loc->SetInt().SetFrom(m_start);
  246.             if (translate_master || (reverse && translate_slave))
  247.                 m_stop = m_start + CODON_LENGTH*lengths[i] - 1;
  248.             else
  249.                 m_stop = m_start + lengths[i] - 1;
  250.             master_loc->SetInt().SetTo(m_stop);
  251.             master_loc->SetInt().SetStrand(strands[2*i]);
  252.         } else {
  253.             master_loc->SetEmpty(*master_id);
  254.         }
  255.         // Set slave seqloc
  256.         if ( (s_start = starts[2*i+1]) != GAP_VALUE) {
  257.             slave_loc->SetInt().SetId(*slave_id);
  258.             slave_loc->SetInt().SetFrom(s_start);
  259.             if (translate_slave || (reverse && translate_master))
  260.                 s_stop = s_start + CODON_LENGTH*lengths[i] - 1;
  261.             else
  262.                 s_stop = s_start + lengths[i] - 1;
  263.             slave_loc->SetInt().SetTo(s_stop);
  264.             slave_loc->SetInt().SetStrand(strands[2*i+1]);
  265.         } else {
  266.             slave_loc->SetEmpty(*slave_id);
  267.         }
  268.         if (reverse) {
  269.             std_seg->SetIds().push_back(slave_id);
  270.             std_seg->SetIds().push_back(master_id);
  271.             std_seg->SetLoc().push_back(slave_loc);
  272.             std_seg->SetLoc().push_back(master_loc);
  273.         } else {
  274.             std_seg->SetIds().push_back(master_id);
  275.             std_seg->SetIds().push_back(slave_id);
  276.             std_seg->SetLoc().push_back(master_loc);
  277.             std_seg->SetLoc().push_back(slave_loc);
  278.         }
  279.         retval.push_back(std_seg);
  280.     }
  281.     return retval;
  282. }
  283. /// Clone of GXECorrectUASequence (tools/gapxdrop.c)
  284. /// Assumes eGapAlignDecline regions are to the right of eGapAlign{Ins,Del}.
  285. /// This function swaps them (eGapAlignDecline ends to the right of the gap)
  286. static void 
  287. x_CorrectUASequence(GapEditBlock* edit_block)
  288. {
  289.     GapEditScript* curr = NULL,* curr_last = NULL;
  290.     GapEditScript* indel_prev = NULL; // pointer to node before the last
  291.             // insertion or deletion followed immediately by GAPALIGN_DECLINE
  292.     bool last_indel = false;    // last operation was an insertion or deletion
  293.     for (curr = edit_block->esp; curr; curr = curr->next) {
  294.         // if GAPALIGN_DECLINE immediately follows an insertion or deletion
  295.         if (curr->op_type == eGapAlignDecline && last_indel) {
  296.             /* This is invalid condition and regions should be
  297.                exchanged */
  298.             if (indel_prev != NULL)
  299.                 indel_prev->next = curr;
  300.             else
  301.                 edit_block->esp = curr; /* First element in a list */
  302.             // CC: If flaking gaps are allowed, curr_last could be NULL and the
  303.             // following statement would core dump...
  304.             curr_last->next = curr->next;
  305.             curr->next = curr_last;
  306.         }
  307.         last_indel = false;
  308.         if (curr->op_type == eGapAlignIns || curr->op_type == eGapAlignDel) {
  309.             last_indel = true;
  310.             indel_prev = curr_last;
  311.         }
  312.         curr_last = curr;
  313.     }
  314.     return;
  315. }
  316. /// C++ version of GXEMakeSeqAlign (tools/gapxdrop.c)
  317. /// Creates a Seq-align for a single HSP
  318. static CRef<CSeq_align>
  319. x_CreateSeqAlign(const CSeq_id* master, const CSeq_id* slave,
  320.     vector<TSignedSeqPos> starts, vector<TSeqPos> lengths,
  321.     vector<ENa_strand> strands, bool translate_master, bool translate_slave,
  322.     bool reverse)
  323. {
  324.     CRef<CSeq_align> sar(new CSeq_align());
  325.     sar->SetType(CSeq_align::eType_partial);
  326.     sar->SetDim(2);         // BLAST only creates pairwise alignments
  327.     if (translate_master || translate_slave) {
  328.         sar->SetSegs().SetStd() =
  329.             x_CreateStdSegs(master, slave, starts, lengths, strands,
  330.                     reverse, translate_master, translate_slave);
  331.     } else {
  332.         CRef<CDense_seg> dense_seg = 
  333.             x_CreateDenseg(master, slave, starts, lengths, strands);
  334.         sar->SetSegs().SetDenseg(*dense_seg);
  335.     }
  336.     return sar;
  337. }
  338. static CRef<CSeq_align>
  339. x_GapEditBlock2SeqAlign(GapEditBlock* edit_block, 
  340.         const CSeq_id* id1, const CSeq_id* id2)
  341. {
  342.     ASSERT(edit_block != NULL);
  343.     vector<TSignedSeqPos> starts;
  344.     vector<TSeqPos> lengths;
  345.     vector<ENa_strand> strands;
  346.     bool is_disc_align = false;
  347.     int nsegs = 0;      // number of segments in edit_block->esp
  348.     for (GapEditScript* t = edit_block->esp; t; t = t->next, nsegs++) {
  349.         if (t->op_type == eGapAlignDecline)
  350.             is_disc_align = true;
  351.     }
  352.     if (is_disc_align) {
  353.         /* By request of Steven Altschul - we need to have 
  354.            the unaligned part being to the left if it is adjacent to the
  355.            gap (insertion or deletion) - so this function will do
  356.            shuffeling */
  357.         x_CorrectUASequence(edit_block);
  358.         CRef<CSeq_align> seqalign(new CSeq_align());
  359.         seqalign->SetType(CSeq_align::eType_partial);
  360.         seqalign->SetDim(2);         // BLAST only creates pairwise alignments
  361.         bool skip_region;
  362.         GapEditScript* curr = NULL,* curr_head = edit_block->esp;
  363.         while (curr_head) {
  364.             skip_region = false;
  365.             for (nsegs = 0, curr = curr_head; curr; curr = curr->next, nsegs++){
  366.                 if (curr->op_type == eGapAlignDecline) {
  367.                     if (nsegs != 0) { // end of aligned region
  368.                         break;
  369.                     } else {
  370.                         while (curr && curr->op_type == eGapAlignDecline) {
  371.                             nsegs++;
  372.                             curr = curr->next;
  373.                         }
  374.                         skip_region = true;
  375.                         break;
  376.                     }
  377.                 }
  378.             }
  379.             // build seqalign for required regions only
  380.             if (!skip_region) {
  381.                 x_CollectSeqAlignData(edit_block, curr_head, nsegs, starts,
  382.                         lengths, strands);
  383.                 CRef<CSeq_align> sa_tmp = x_CreateSeqAlign(id1, id2, starts,
  384.                         lengths, strands, edit_block->translate1 !=0,
  385.                         edit_block->translate2 != 0, edit_block->reverse != 0);
  386.                 // Add this seqalign to the list
  387.                 if (sa_tmp)
  388.                     seqalign->SetSegs().SetDisc().Set().push_back(sa_tmp);
  389.             }
  390.             curr_head = curr;
  391.         }
  392.         return seqalign;
  393.     } else {
  394.         x_CollectSeqAlignData(edit_block, edit_block->esp, nsegs, 
  395.                 starts, lengths, strands);
  396.         return x_CreateSeqAlign(id1, id2, starts, lengths, strands,
  397.                 edit_block->translate1 != 0, edit_block->translate2 != 0,
  398.                 edit_block->reverse != 0);
  399.     }
  400. }
  401. /** Get the current position. */
  402. static Int4 get_current_pos(Int4* pos, Int4 length)
  403. {
  404.     Int4 val;
  405.     if(*pos < 0)
  406.         val = -(*pos + length -1);
  407.     else
  408.         val = *pos;
  409.     *pos += length;
  410.     return val;
  411. }
  412. /** This function is used for Out-Of-Frame traceback conversion
  413.  * Convert an OOF EditScript chain to a SeqAlign of type StdSeg.
  414.  * Used for a non-simple interval (i.e., one without subs. or 
  415.  * deletions).  
  416.  * The first SeqIdPtr in the chain of subject_id and query_id is 
  417.  * duplicated for the SeqAlign.
  418. */
  419. static CRef<CSeq_align>
  420. x_OOFEditBlock2SeqAlign(EProgram program, 
  421.     GapEditBlock* edit_block, 
  422.     const CSeq_id* query_id, const CSeq_id* subject_id)
  423. {
  424.     ASSERT(edit_block != NULL);
  425.     CRef<CSeq_align> seqalign(new CSeq_align());
  426.     Boolean reverse = FALSE;
  427.     GapEditScript* curr,* esp;
  428.     Int2 frame1, frame2;
  429.     Int4 start1, start2;
  430.     Int4 original_length1, original_length2;
  431.     CRef<CSeq_interval> seq_int1_last;
  432.     CRef<CSeq_interval> seq_int2_last;
  433.     CConstRef<CSeq_id> id1;
  434.     CConstRef<CSeq_id> id2;
  435.     CRef<CSeq_loc> slp1, slp2;
  436.     ENa_strand strand1, strand2;
  437.     bool first_shift;
  438.     Int4 from1, from2, to1, to2;
  439.     CRef<CSeq_id> tmp;
  440.     if (program == eBlastx) {
  441.        reverse = TRUE;
  442.        start1 = edit_block->start2;
  443.        start2 = edit_block->start1;
  444.        frame1 = edit_block->frame2;
  445.        frame2 = edit_block->frame1;
  446.        original_length1 = edit_block->original_length2;
  447.        original_length2 = edit_block->original_length1;
  448.        id1.Reset(subject_id);
  449.        id2.Reset(query_id);
  450.     } else { 
  451.        start1 = edit_block->start1;
  452.        start2 = edit_block->start2;
  453.        frame1 = edit_block->frame1;
  454.        frame2 = edit_block->frame2;
  455.        original_length1 = edit_block->original_length1;
  456.        original_length2 = edit_block->original_length2;
  457.        id1.Reset(query_id);
  458.        id2.Reset(subject_id);
  459.     }
  460.  
  461.     strand1 = x_Frame2Strand(frame1);
  462.     strand2 = x_Frame2Strand(frame2);
  463.     
  464.     esp = edit_block->esp;
  465.     
  466.     seqalign->SetDim(2); /**only two dimention alignment**/
  467.     
  468.     seqalign->SetType(CSeq_align::eType_partial); /**partial for gapped translating search. */
  469.     esp = edit_block->esp;
  470.     first_shift = false;
  471.     for (curr=esp; curr; curr=curr->next) {
  472.         slp1.Reset(new CSeq_loc());
  473.         slp2.Reset(new CSeq_loc());
  474.         
  475.         switch (curr->op_type) {
  476.         case eGapAlignDel: /* deletion of three nucleotides. */
  477.             
  478.             first_shift = false;
  479.             slp1->SetInt().SetFrom(get_current_pos(&start1, curr->num));
  480.             slp1->SetInt().SetTo(MIN(start1,original_length1) - 1);
  481.             tmp.Reset(new CSeq_id(id1->AsFastaString()));
  482.             slp1->SetInt().SetId(*tmp);
  483.             slp1->SetInt().SetStrand(strand1);
  484.             
  485.             /* Empty nucleotide piece */
  486.             tmp.Reset(new CSeq_id(id2->AsFastaString()));
  487.             slp2->SetEmpty(*tmp);
  488.             seq_int1_last.Reset(&slp1->SetInt());
  489.             /* Keep previous seq_int2_last, in case there is a frame shift
  490.                immediately after this gap */
  491.             
  492.             break;
  493.         case eGapAlignIns: /* insertion of three nucleotides. */
  494.             /* If gap is followed after frameshift - we have to
  495.                add this element for the alignment to be correct */
  496.             
  497.             if(first_shift) { /* Second frameshift in a row */
  498.                 /* Protein coordinates */
  499.                 slp1->SetInt().SetFrom(get_current_pos(&start1, 1));
  500.                 to1 = MIN(start1,original_length1) - 1;
  501.                 slp1->SetInt().SetTo(to1);
  502.                 tmp.Reset(new CSeq_id(id1->AsFastaString()));
  503.                 slp1->SetInt().SetId(*tmp);
  504.                 slp1->SetInt().SetStrand(strand1);
  505.                 
  506.                 /* Nucleotide scale shifted by op_type */
  507.                 from2 = get_current_pos(&start2, 3);
  508.                 to2 = MIN(start2,original_length2) - 1;
  509.                 slp2->SetInt().SetFrom(from2);
  510.                 slp2->SetInt().SetTo(to2);
  511.                 if (start2 > original_length2)
  512.                     slp1->SetInt().SetTo(to1 - 1);
  513.                 
  514.                 /* Transfer to DNA minus strand coordinates */
  515.                 if(strand2 == eNa_strand_minus) {
  516.                     slp2->SetInt().SetTo(original_length2 - from2 - 1);
  517.                     slp2->SetInt().SetFrom(original_length2 - to2 - 1);
  518.                 }
  519.                 
  520.                 tmp.Reset(new CSeq_id(id2->AsFastaString()));
  521.                 slp2->SetInt().SetId(*tmp);
  522.                 slp2->SetInt().SetStrand(strand2);
  523.                 CRef<CStd_seg> seg(new CStd_seg());
  524.                 seg->SetDim(2);
  525.                 CStd_seg::TIds& ids = seg->SetIds();
  526.                 if (reverse) {
  527.                     seg->SetLoc().push_back(slp2);
  528.                     seg->SetLoc().push_back(slp1);
  529.                     tmp.Reset(new CSeq_id(id2->AsFastaString()));
  530.                     ids.push_back(tmp);
  531.                     tmp.Reset(new CSeq_id(id1->AsFastaString()));
  532.                     ids.push_back(tmp);
  533.                 } else {
  534.                     seg->SetLoc().push_back(slp1);
  535.                     seg->SetLoc().push_back(slp2);
  536.                     tmp.Reset(new CSeq_id(id1->AsFastaString()));
  537.                     ids.push_back(tmp);
  538.                     tmp.Reset(new CSeq_id(id2->AsFastaString()));
  539.                     ids.push_back(tmp);
  540.                 }
  541.                 ids.resize(seg->GetDim());
  542.                 
  543.                 seqalign->SetSegs().SetStd().push_back(seg);
  544.             }
  545.             first_shift = false;
  546.             /* Protein piece is empty */
  547.             tmp.Reset(new CSeq_id(id1->AsFastaString()));
  548.             slp1->SetEmpty(*tmp);
  549.             
  550.             /* Nucleotide scale shifted by 3, protein gapped */
  551.             from2 = get_current_pos(&start2, curr->num*3);
  552.             to2 = MIN(start2,original_length2) - 1;
  553.             slp2->SetInt().SetFrom(from2);
  554.             slp2->SetInt().SetTo(to2);
  555.             /* Transfer to DNA minus strand coordinates */
  556.             if(strand2 == eNa_strand_minus) {
  557.                 slp2->SetInt().SetTo(original_length2 - from2 - 1);
  558.                 slp2->SetInt().SetFrom(original_length2 - to2 - 1);
  559.             }
  560.             tmp.Reset(new CSeq_id(id2->AsFastaString()));
  561.             slp2->SetInt().SetId(*tmp);
  562.             slp2->SetInt().SetStrand(strand2);
  563.             
  564.             seq_int1_last.Reset(NULL);
  565.             seq_int2_last.Reset(&slp2->SetInt()); /* Will be used to adjust "to" value */
  566.             
  567.             break;
  568.         case eGapAlignSub: /* Substitution. */
  569.             first_shift = false;
  570.             /* Protein coordinates */
  571.             from1 = get_current_pos(&start1, curr->num);
  572.             to1 = MIN(start1, original_length1) - 1;
  573.             /* Adjusting last segment and new start point in
  574.                nucleotide coordinates */
  575.             from2 = get_current_pos(&start2, curr->num*((Uint1)curr->op_type));
  576.             to2 = start2 - 1;
  577.             /* Chop off three bases and one residue at a time.
  578.                Why does this happen, seems like a bug?
  579.             */
  580.             while (to2 >= original_length2) {
  581.                 to2 -= 3;
  582.                 to1--;
  583.             }
  584.             /* Transfer to DNA minus strand coordinates */
  585.             if(strand2 == eNa_strand_minus) {
  586.                 int tmp_int;
  587.                 tmp_int = to2;
  588.                 to2 = original_length2 - from2 - 1;
  589.                 from2 = original_length2 - tmp_int - 1;
  590.             }
  591.             slp1->SetInt().SetFrom(from1);
  592.             slp1->SetInt().SetTo(to1);
  593.             tmp.Reset(new CSeq_id(id1->AsFastaString()));
  594.             slp1->SetInt().SetId(*tmp);
  595.             slp1->SetInt().SetStrand(strand1);
  596.             slp2->SetInt().SetFrom(from2);
  597.             slp2->SetInt().SetTo(to2);
  598.             tmp.Reset(new CSeq_id(id2->AsFastaString()));
  599.             slp2->SetInt().SetId(*tmp);
  600.             slp2->SetInt().SetStrand(strand2);
  601.            
  602.             seq_int1_last.Reset(&slp1->SetInt()); /* Will be used to adjust "to" value */
  603.             seq_int2_last.Reset(&slp2->SetInt()); /* Will be used to adjust "to" value */
  604.             
  605.             break;
  606.         case eGapAlignDel2: /* gap of two nucleotides. */
  607.         case eGapAlignDel1: /* Gap of one nucleotide. */
  608.         case eGapAlignIns1: /* Insertion of one nucleotide. */
  609.         case eGapAlignIns2: /* Insertion of two nucleotides. */
  610.             if(first_shift) { /* Second frameshift in a row */
  611.                 /* Protein coordinates */
  612.                 from1 = get_current_pos(&start1, 1);
  613.                 to1 = MIN(start1,original_length1) - 1;
  614.                 /* Nucleotide scale shifted by op_type */
  615.                 from2 = get_current_pos(&start2, (Uint1)curr->op_type);
  616.                 to2 = start2 - 1;
  617.                 if (to2 >= original_length2) {
  618.                     to2 = original_length2 -1;
  619.                     to1--;
  620.                 }
  621.                 /* Transfer to DNA minus strand coordinates */
  622.                 if(strand2 == eNa_strand_minus) {
  623.                     int tmp_int;
  624.                     tmp_int = to2;
  625.                     to2 = original_length2 - from2 - 1;
  626.                     from2 = original_length2 - tmp_int - 1;
  627.                 }
  628.                 slp1->SetInt().SetFrom(from1);
  629.                 slp1->SetInt().SetTo(to1);
  630.                 tmp.Reset(new CSeq_id(id1->AsFastaString()));
  631.                 slp1->SetInt().SetId(*tmp);
  632.                 slp1->SetInt().SetStrand(strand1);
  633.                 slp2->SetInt().SetFrom(from2);
  634.                 slp2->SetInt().SetTo(to2);
  635.                 tmp.Reset(new CSeq_id(id2->AsFastaString()));
  636.                 slp2->SetInt().SetId(*tmp);
  637.                 slp2->SetInt().SetStrand(strand2);
  638.                 seq_int1_last.Reset(&slp1->SetInt()); 
  639.                 seq_int2_last.Reset(&slp2->SetInt()); 
  640.                 break;
  641.             }
  642.             
  643.             first_shift = true;
  644.             /* If this substitution is following simple frameshift
  645.                we do not need to start new segment, but may continue
  646.                old one */
  647.             if(seq_int2_last) {
  648.                 get_current_pos(&start2, curr->num*((Uint1)curr->op_type-3));
  649.                 if(strand2 != eNa_strand_minus) {
  650.                     seq_int2_last->SetTo(start2 - 1);
  651.                 } else {
  652.                     /* Transfer to DNA minus strand coordinates */
  653.                     seq_int2_last->SetFrom(original_length2 - start2);
  654.                 }
  655.                 /* Adjustment for multiple shifts - theoretically possible,
  656.                    but very improbable */
  657.                 if(seq_int2_last->GetFrom() > seq_int2_last->GetTo()) {
  658.                     
  659.                     if(strand2 != eNa_strand_minus) {
  660.                         seq_int2_last->SetTo(seq_int2_last->GetTo() + 3);
  661.                     } else {
  662.                         seq_int2_last->SetFrom(seq_int2_last->GetFrom() - 3);
  663.                     }
  664.                     
  665.                     if (seq_int1_last.GetPointer() &&
  666. seq_int1_last->GetTo() != 0)
  667.                         seq_int1_last->SetTo(seq_int1_last->GetTo() + 1);
  668.                 }
  669.             } else if ((Uint1)curr->op_type > 3) {
  670.                 /* Protein piece is empty */
  671.                 tmp.Reset(new CSeq_id(id1->AsFastaString()));
  672.                 slp1->SetEmpty(*tmp);
  673.                 /* Simulating insertion of nucleotides */
  674.                 from2 = get_current_pos(&start2, 
  675.                                         curr->num*((Uint1)curr->op_type-3));
  676.                 to2 = MIN(start2,original_length2) - 1;
  677.                 /* Transfer to DNA minus strand coordinates */
  678.                 if(strand2 == eNa_strand_minus) {
  679.                     int tmp_int;
  680.                     tmp_int = to2;
  681.                     to2 = original_length2 - from2 - 1;
  682.                     from2 = original_length2 - tmp_int - 1;
  683.                 }
  684.                 slp2->SetInt().SetFrom(from2);
  685.                 slp2->SetInt().SetTo(to2);
  686.                 
  687.                 tmp.Reset(new CSeq_id(id2->AsFastaString()));
  688.                 slp2->SetInt().SetId(*tmp);
  689.                 seq_int1_last.Reset(NULL);
  690.                 seq_int2_last.Reset(&slp2->SetInt()); /* Will be used to adjust "to" value */
  691.                 break;
  692.             } else {
  693.                 continue;       /* Main loop */
  694.             }
  695.             continue;       /* Main loop */
  696.             /* break; */
  697.         default:
  698.             continue;       /* Main loop */
  699.             /* break; */
  700.         } 
  701.         CRef<CStd_seg> seg(new CStd_seg());
  702.         seg->SetDim(2);
  703.         
  704.         CStd_seg::TIds& ids = seg->SetIds();
  705.         if (reverse) {
  706.             seg->SetLoc().push_back(slp2);
  707.             seg->SetLoc().push_back(slp1);
  708.             tmp.Reset(new CSeq_id(id2->AsFastaString()));
  709.             ids.push_back(tmp);
  710.             tmp.Reset(new CSeq_id(id1->AsFastaString()));
  711.             ids.push_back(tmp);
  712.         } else {
  713.             seg->SetLoc().push_back(slp1);
  714.             seg->SetLoc().push_back(slp2);
  715.             tmp.Reset(new CSeq_id(id1->AsFastaString()));
  716.             ids.push_back(tmp);
  717.             tmp.Reset(new CSeq_id(id2->AsFastaString()));
  718.             ids.push_back(tmp);
  719.         }
  720.         ids.resize(seg->GetDim());
  721.         
  722.         seqalign->SetSegs().SetStd().push_back(seg);
  723.     }
  724.     
  725.     return seqalign;
  726. }
  727. /// Creates and initializes CScore with i (if it's non-zero) or d
  728. static CRef<CScore> 
  729. x_MakeScore(const string& ident_string, double d = 0.0, int i = 0)
  730. {
  731.     CRef<CScore> retval(new CScore());
  732.     CRef<CObject_id> id(new CObject_id());
  733.     id->SetStr(ident_string);
  734.     retval->SetId(*id);
  735.     CRef<CScore::C_Value> val(new CScore::C_Value());
  736.     if (i)
  737.         val->SetInt(i);
  738.     else
  739.         val->SetReal(d);
  740.     retval->SetValue(*val);
  741.     return retval;
  742. }
  743. /// C++ version of GetScoreSetFromBlastHsp (tools/blastutl.c)
  744. static void
  745. x_BuildScoreList(const BlastHSP* hsp, const BlastScoreBlk* sbp, const
  746.         BlastScoringOptions* score_options, CSeq_align::TScore& scores,
  747.         EProgram program)
  748. {
  749.     string score_type;
  750.     Blast_KarlinBlk* kbp = NULL;
  751.     if (!hsp)
  752.         return;
  753.     score_type = "score";
  754.     if (hsp->score)
  755.         scores.push_back(x_MakeScore(score_type, 0.0, hsp->score));
  756.     score_type = "sum_n";
  757.     if (hsp->num > 1)
  758.         scores.push_back(x_MakeScore(score_type, 0.0, hsp->num));
  759.     // Set the E-Value
  760.     double evalue = (hsp->evalue < SMALLEST_EVALUE) ? 0.0 : hsp->evalue;
  761.     score_type = (hsp->num == 1) ? "e_value" : "sum_e";
  762.     if (evalue >= 0.0)
  763.         scores.push_back(x_MakeScore(score_type, evalue));
  764.     // Calculate the bit score from the raw score
  765.     score_type = "bit_score";
  766.     if (program == eBlastn || !score_options->gapped_calculation)
  767.         kbp = sbp->kbp[hsp->context];
  768.     else
  769.         kbp = sbp->kbp_gap[hsp->context];
  770.     double bit_score = ((hsp->score*kbp->Lambda) - kbp->logK)/NCBIMATH_LN2;
  771.     if (bit_score >= 0.0)
  772.         scores.push_back(x_MakeScore(score_type, bit_score));
  773.     // Set the identity score
  774.     score_type = "num_ident";
  775.     if (hsp->num_ident > 0)
  776.         scores.push_back(x_MakeScore(score_type, 0.0, hsp->num_ident));
  777.     if (hsp->splice_junction > 0) {
  778.         // Splice junction(s) was (were) found between linked HSPs
  779.         score_type = "splice_junction";
  780.         scores.push_back(x_MakeScore(score_type, 0.0, hsp->splice_junction));
  781.     }
  782.     return;
  783. }
  784. static void
  785. x_AddScoresToSeqAlign(CRef<CSeq_align>& seqalign, const BlastHSP* hsp, 
  786.         const BlastScoreBlk* sbp, EProgram program,
  787.         const BlastScoringOptions* score_options)
  788. {
  789.     // Add the scores for this HSP
  790.     CSeq_align::TScore& score_list = seqalign->SetScore();
  791.     x_BuildScoreList(hsp, sbp, score_options, score_list, program);
  792. }
  793. CRef<CDense_diag>
  794. x_UngappedHSPToDenseDiag(BlastHSP* hsp, const CSeq_id *query_id, 
  795.     const CSeq_id *subject_id, const BlastScoreBlk* sbp,
  796.     const BlastScoringOptions* score_options, EProgram program, 
  797.     Int4 query_length, Int4 subject_length)
  798. {
  799.     CRef<CDense_diag> retval(new CDense_diag());
  800.     
  801.     // Pairwise alignment is 2 dimensional
  802.     retval->SetDim(2);
  803.     // Set the sequence ids
  804.     CDense_diag::TIds& ids = retval->SetIds();
  805.     CRef<CSeq_id> tmp(new CSeq_id(query_id->AsFastaString()));
  806.     ids.push_back(tmp);
  807.     tmp.Reset(new CSeq_id(subject_id->AsFastaString()));
  808.     ids.push_back(tmp);
  809.     ids.resize(retval->GetDim());
  810.     retval->SetLen(hsp->query.length);
  811.     CDense_diag::TStrands& strands = retval->SetStrands();
  812.     strands.push_back(x_Frame2Strand(hsp->query.frame));
  813.     strands.push_back(x_Frame2Strand(hsp->subject.frame));
  814.     CDense_diag::TStarts& starts = retval->SetStarts();
  815.     if (hsp->query.frame >= 0) {
  816.        starts.push_back(hsp->query.offset);
  817.     } else {
  818.        starts.push_back(query_length - hsp->query.offset - hsp->query.length);
  819.     }
  820.     if (hsp->subject.frame >= 0) {
  821.        starts.push_back(hsp->subject.offset);
  822.     } else {
  823.        starts.push_back(subject_length - hsp->subject.offset - 
  824.                         hsp->subject.length);
  825.     }
  826.     CSeq_align::TScore& score_list = retval->SetScores();
  827.     x_BuildScoreList(hsp, sbp, score_options, score_list, program);
  828.     return retval;
  829. }
  830. CRef<CStd_seg>
  831. x_UngappedHSPToStdSeg(BlastHSP* hsp, const CSeq_id *query_id, 
  832.     const CSeq_id *subject_id, const BlastScoreBlk* sbp,
  833.     const BlastScoringOptions* score_options, EProgram program, 
  834.     Int4 query_length, Int4 subject_length)
  835. {
  836.     CRef<CStd_seg> retval(new CStd_seg());
  837.     // Pairwise alignment is 2 dimensional
  838.     retval->SetDim(2);
  839.     CRef<CSeq_loc> query_loc(new CSeq_loc());
  840.     CRef<CSeq_loc> subject_loc(new CSeq_loc());
  841.     // Set the sequence ids
  842.     CStd_seg::TIds& ids = retval->SetIds();
  843.     CRef<CSeq_id> tmp(new CSeq_id(query_id->AsFastaString()));
  844.     query_loc->SetInt().SetId(*tmp);
  845.     ids.push_back(tmp);
  846.     tmp.Reset(new CSeq_id(subject_id->AsFastaString()));
  847.     subject_loc->SetInt().SetId(*tmp);
  848.     ids.push_back(tmp);
  849.     ids.resize(retval->GetDim());
  850.     query_loc->SetInt().SetStrand(x_Frame2Strand(hsp->query.frame));
  851.     subject_loc->SetInt().SetStrand(x_Frame2Strand(hsp->subject.frame));
  852.     if (hsp->query.frame == 0) {
  853.        query_loc->SetInt().SetFrom(hsp->query.offset);
  854.        query_loc->SetInt().SetTo(hsp->query.offset + hsp->query.length - 1);
  855.     } else if (hsp->query.frame > 0) {
  856.        query_loc->SetInt().SetFrom(CODON_LENGTH*(hsp->query.offset) + 
  857.                                    hsp->query.frame - 1);
  858.        query_loc->SetInt().SetTo(CODON_LENGTH*(hsp->query.offset+
  859.                                                hsp->query.length)
  860.                                  + hsp->query.frame - 2);
  861.     } else {
  862.        query_loc->SetInt().SetFrom(query_length -
  863.            CODON_LENGTH*(hsp->query.offset+hsp->query.length) +
  864.            hsp->query.frame + 1);
  865.        query_loc->SetInt().SetTo(query_length - CODON_LENGTH*hsp->query.offset
  866.                                  + hsp->query.frame);
  867.     }
  868.     if (hsp->subject.frame == 0) {
  869.        subject_loc->SetInt().SetFrom(hsp->subject.offset);
  870.        subject_loc->SetInt().SetTo(hsp->subject.offset + 
  871.                                    hsp->subject.length - 1);
  872.     } else if (hsp->subject.frame > 0) {
  873.        subject_loc->SetInt().SetFrom(CODON_LENGTH*(hsp->subject.offset) + 
  874.                                    hsp->subject.frame - 1);
  875.        subject_loc->SetInt().SetTo(CODON_LENGTH*(hsp->subject.offset+
  876.                                                hsp->subject.length) +
  877.                                    hsp->subject.frame - 2);
  878.     } else {
  879.        subject_loc->SetInt().SetFrom(subject_length -
  880.            CODON_LENGTH*(hsp->subject.offset+hsp->subject.length) +
  881.            hsp->subject.frame + 1);
  882.        subject_loc->SetInt().SetTo(subject_length - 
  883.            CODON_LENGTH*hsp->subject.offset + hsp->subject.frame);
  884.     }
  885.     retval->SetLoc().push_back(query_loc);
  886.     retval->SetLoc().push_back(subject_loc);
  887.     CSeq_align::TScore& score_list = retval->SetScores();
  888.     x_BuildScoreList(hsp, sbp, score_options, score_list, program);
  889.     return retval;
  890. }
  891. static CRef<CSeq_align>
  892. BLASTUngappedHspListToSeqAlign(EProgram program, 
  893.     BlastHSPList* hsp_list, const CSeq_id *query_id, 
  894.     const CSeq_id *subject_id, Int4 query_length, Int4 subject_length,
  895.     const BlastScoringOptions* score_options, const BlastScoreBlk* sbp)
  896. {
  897.     CRef<CSeq_align> retval(new CSeq_align()); 
  898.     BlastHSP** hsp_array;
  899.     int index;
  900.     retval->SetType(CSeq_align::eType_diags);
  901.     hsp_array = hsp_list->hsp_array;
  902.     /* All HSPs are put in one seqalign, containing a list of 
  903.      * DenseDiag for same molecule search, or StdSeg for translated searches.
  904.     */
  905.     if (program == eBlastn || 
  906.         program == eBlastp ||
  907.         program == eRPSBlast) {
  908.         for (index=0; index<hsp_list->hspcnt; index++) { 
  909.             BlastHSP* hsp = hsp_array[index];
  910.             retval->SetSegs().SetDendiag().push_back(
  911.                 x_UngappedHSPToDenseDiag(hsp, query_id, subject_id, sbp, 
  912.                     score_options, program, query_length, subject_length));
  913.         }
  914.     } else { // Translated search
  915.         for (index=0; index<hsp_list->hspcnt; index++) { 
  916.             BlastHSP* hsp = hsp_array[index];
  917.             retval->SetSegs().SetStd().push_back(
  918.                 x_UngappedHSPToStdSeg(hsp, query_id, subject_id, sbp, 
  919.                     score_options, program, query_length, subject_length));
  920.         }
  921.     }
  922.     return retval;
  923. }
  924. // This is called for each query and each subject in the BLAST search
  925. // We always return CSeq_aligns of type disc to allow multiple HSPs
  926. // corresponding to the same query-subject pair to be grouped in one CSeq_align
  927. static CRef<CSeq_align>
  928. BLASTHspListToSeqAlign(EProgram program, 
  929.     BlastHSPList* hsp_list, const CSeq_id *query_id, 
  930.     const CSeq_id *subject_id,
  931.     const BlastScoringOptions* score_options, const BlastScoreBlk* sbp)
  932. {
  933.     CRef<CSeq_align> retval(new CSeq_align()); 
  934.     retval->SetType(CSeq_align::eType_disc);
  935.     retval->SetDim(2);         // BLAST only creates pairwise alignments
  936.     // Process the list of HSPs corresponding to one subject sequence and
  937.     // create one seq-align for each list of HSPs (use disc seqalign when
  938.     // multiple HSPs are found).
  939.     BlastHSP** hsp_array = hsp_list->hsp_array;
  940.     for (int index = 0; index < hsp_list->hspcnt; index++) { 
  941.         BlastHSP* hsp = hsp_array[index];
  942.         CRef<CSeq_align> seqalign;
  943.         if (score_options->is_ooframe) {
  944.             seqalign = 
  945.                 x_OOFEditBlock2SeqAlign(program, hsp->gap_info, 
  946.                     query_id, subject_id);
  947.         } else {
  948.             seqalign = 
  949.                 x_GapEditBlock2SeqAlign(hsp->gap_info, 
  950.                     query_id, subject_id);
  951.         }
  952.         
  953.         x_AddScoresToSeqAlign(seqalign, hsp, sbp, program, 
  954.                               score_options);
  955.         retval->SetSegs().SetDisc().Set().push_back(seqalign);
  956.     }
  957.     
  958.     return retval;
  959. }
  960. static void
  961. x_GetSequenceLengthAndId(const SSeqLoc* ss,          // [in]
  962.                          const BlastSeqSrc* seq_src, // [in]
  963.                          int oid,                    // [in] 
  964.                          CSeq_id** seqid,            // [out]
  965.                          TSeqPos* length)            // [out]
  966. {
  967.     ASSERT(ss || seq_src);
  968.     ASSERT(seqid);
  969.     ASSERT(length);
  970.     if ( !seq_src ) {
  971.         *seqid = const_cast<CSeq_id*>(&sequence::GetId(*ss->seqloc,
  972.                                                        ss->scope));
  973.         *length = sequence::GetLength(*ss->seqloc, ss->scope);
  974.     } else {
  975.         ListNode* seqid_wrap;
  976.         seqid_wrap = BLASTSeqSrcGetSeqId(seq_src, (void*) &oid);
  977.         ASSERT(seqid_wrap);
  978.         if (seqid_wrap->choice == BLAST_SEQSRC_CPP_SEQID) {
  979.             *seqid = (CSeq_id*)seqid_wrap->ptr;
  980.             ListNodeFree(seqid_wrap);
  981.         } else if (seqid_wrap->choice == BLAST_SEQSRC_CPP_SEQID_REF) {
  982.             *seqid = ((CRef<CSeq_id>*)seqid_wrap->ptr)->GetPointer();
  983.         } else {
  984.             /** FIXME!!! This is wrong, because the id created here will 
  985.                 not be registered! However if sequence source returns a 
  986.                 C object, we cannot handle it here. */
  987.             char* id = BLASTSeqSrcGetSeqIdStr(seq_src, (void*) &oid);
  988.             string id_str(id);
  989.             *seqid = new CSeq_id(id_str);
  990.             sfree(id);
  991.         }
  992.         *length = BLASTSeqSrcGetSeqLen(seq_src, (void*) &oid);
  993.     }
  994.     return;
  995. }
  996. /// Constructs an empty seq-align-set containing an empty discontinuous
  997. /// seq-align.
  998. static CSeq_align_set*
  999. x_CreateEmptySeq_align_set(CSeq_align_set* sas)
  1000. {
  1001.     CSeq_align_set* retval = NULL;
  1002.     if (!sas) {
  1003.         retval = new CSeq_align_set;
  1004.     } else {
  1005.         retval = sas;
  1006.     }
  1007.     CRef<CSeq_align> empty_seqalign(new CSeq_align);
  1008.     empty_seqalign->SetType(CSeq_align::eType_disc);
  1009.     empty_seqalign->SetSegs().SetDisc(*new CSeq_align_set);
  1010.     retval->Set().push_back(empty_seqalign);
  1011.     return retval;
  1012. }
  1013. /// Always remap the query, the subject is remapped if it's given (assumes
  1014. /// alignment created by BLAST 2 Sequences API).
  1015. /// Since the query strands were already taken into account when CSeq_align 
  1016. /// was created, only start position shifts in the CSeq_loc's are relevant in 
  1017. /// this function. However full remapping is necessary for the subject sequence
  1018. /// if it is on a negative strand.
  1019. static void
  1020. x_RemapAlignmentCoordinates(CRef<CSeq_align> sar, 
  1021.                             const SSeqLoc* query,
  1022.                             const SSeqLoc* subject = NULL)
  1023. {
  1024.     _ASSERT(sar);
  1025.     ASSERT(query);
  1026.     const int query_dimension = 0;
  1027.     const int subject_dimension = 1;
  1028.     // If subject is on a minus strand, we'll need to flip subject strands 
  1029.     // and remap subject coordinates on all segments.
  1030.     // Otherwise we only need to shift query and/or subject coordinates, 
  1031.     // if the respective location starts not from 0.
  1032.     bool remap_subject = 
  1033.         (subject && subject->seqloc->IsInt() &&
  1034.          subject->seqloc->GetInt().GetStrand() == eNa_strand_minus);
  1035.     TSeqPos q_shift = 0, s_shift = 0;
  1036.     if (query->seqloc->IsInt()) {
  1037.         q_shift = query->seqloc->GetInt().GetFrom();
  1038.     }
  1039.     if (subject && subject->seqloc->IsInt()) {
  1040.         s_shift = subject->seqloc->GetInt().GetFrom();
  1041.     }
  1042.     if (remap_subject || q_shift > 0 || s_shift > 0) {
  1043.         for (CTypeIterator<CDense_seg> itr(Begin(*sar)); itr; ++itr) {
  1044.             const vector<ENa_strand> strands = itr->GetStrands();
  1045.             // Create temporary CSeq_locs with strands either matching 
  1046.             // (for query and for subject if it is not on a minus strand),
  1047.             // or opposite to those in the segment, to force RemapToLoc to 
  1048.             // behave in the correct way.
  1049.             if (q_shift > 0) {
  1050.                 CSeq_loc q_seqloc;
  1051.                 ENa_strand q_strand = strands[0];
  1052.                 q_seqloc.SetInt().SetFrom(q_shift);
  1053.                 q_seqloc.SetInt().SetTo(query->seqloc->GetInt().GetTo());
  1054.                 q_seqloc.SetInt().SetStrand(q_strand);
  1055.                 q_seqloc.SetInt().SetId().Assign(sequence::GetId(*query->seqloc, query->scope));
  1056.                 itr->RemapToLoc(query_dimension, q_seqloc);
  1057.             }
  1058.             if (remap_subject || s_shift > 0) {
  1059.                 CSeq_loc s_seqloc;
  1060.                 ENa_strand s_strand;
  1061.                 if (remap_subject) {
  1062.                     s_strand = ((strands[1] == eNa_strand_plus) ? 
  1063.                                 eNa_strand_minus : eNa_strand_plus);
  1064.                 } else {
  1065.                     s_strand = strands[1];
  1066.                 }
  1067.                 s_seqloc.SetInt().SetFrom(s_shift);
  1068.                 s_seqloc.SetInt().SetTo(subject->seqloc->GetInt().GetTo());
  1069.                 s_seqloc.SetInt().SetStrand(s_strand);
  1070.                 s_seqloc.SetInt().SetId().Assign(sequence::GetId(*subject->seqloc, subject->scope));
  1071.                 itr->RemapToLoc(subject_dimension, s_seqloc);
  1072.             }
  1073.         }
  1074.     }
  1075. }
  1076. CSeq_align_set*
  1077. BLAST_HitList2CSeqAlign(const BlastHitList* hit_list, 
  1078.     EProgram prog, SSeqLoc &query,
  1079.     const BlastSeqSrc* seq_src,
  1080.     const BlastScoringOptions* score_options, 
  1081.     const BlastScoreBlk* sbp)
  1082. {
  1083.     CSeq_align_set* seq_aligns = new CSeq_align_set();
  1084.     bool is_gapped = score_options->gapped_calculation ? true : false;
  1085.     ASSERT(seq_src);
  1086.     if (!hit_list) {
  1087.         return x_CreateEmptySeq_align_set(seq_aligns);
  1088.     }
  1089.     TSeqPos query_length = 0;
  1090.     CSeq_id* qid = NULL;
  1091.     CConstRef<CSeq_id> query_id;
  1092.     x_GetSequenceLengthAndId(&query, NULL, 0, &qid, &query_length);
  1093.     query_id.Reset(qid);
  1094.     TSeqPos subj_length = 0;
  1095.     CSeq_id* sid = NULL;
  1096.     CConstRef<CSeq_id> subject_id;
  1097.     for (int index = 0; index < hit_list->hsplist_count; index++) {
  1098.         BlastHSPList* hsp_list = hit_list->hsplist_array[index];
  1099.         if (!hsp_list)
  1100.             continue;
  1101.         x_GetSequenceLengthAndId(NULL, seq_src, hsp_list->oid, 
  1102.                                  &sid, &subj_length);
  1103.         subject_id.Reset(sid);
  1104.         
  1105.         // Create a CSeq_align for each matching sequence
  1106.         CRef<CSeq_align> hit_align;
  1107.         if (is_gapped) {
  1108.             hit_align = 
  1109.                 BLASTHspListToSeqAlign(prog, hsp_list, query_id, 
  1110.                                        subject_id, score_options, sbp);
  1111.         } else {
  1112.             hit_align = 
  1113.                 BLASTUngappedHspListToSeqAlign(prog, hsp_list, query_id, 
  1114.                     subject_id, query_length, subj_length, score_options, sbp);
  1115.         }
  1116.         ListNode* subject_loc_wrap = 
  1117.             BLASTSeqSrcGetSeqLoc(seq_src, (void*)&hsp_list->oid);
  1118.         SSeqLoc* subject_loc = NULL;
  1119.         if (subject_loc_wrap && 
  1120.             subject_loc_wrap->choice == BLAST_SEQSRC_CPP_SEQLOC)
  1121.             subject_loc = (SSeqLoc*) subject_loc_wrap->ptr;
  1122.         x_RemapAlignmentCoordinates(hit_align, &query, subject_loc);
  1123.         seq_aligns->Set().push_back(hit_align);
  1124.     }
  1125.     return seq_aligns;
  1126. }
  1127. TSeqAlignVector
  1128. BLAST_Results2CSeqAlign(const BlastHSPResults* results, 
  1129.         EProgram prog,
  1130.         TSeqLocVector &query,
  1131.         const BlastSeqSrc* seq_src,
  1132.         const BlastScoringOptions* score_options, 
  1133.         const BlastScoreBlk* sbp)
  1134. {
  1135.     ASSERT(results->num_queries == (int)query.size());
  1136.     ASSERT(seq_src);
  1137.     TSeqAlignVector retval;
  1138.     CConstRef<CSeq_id> query_id;
  1139.     // Process each query's hit list
  1140.     for (int index = 0; index < results->num_queries; index++) {
  1141.        BlastHitList* hit_list = results->hitlist_array[index];
  1142.        CRef<CSeq_align_set> seq_aligns(BLAST_HitList2CSeqAlign(hit_list, prog,
  1143.                                            query[index], seq_src,
  1144.                                            score_options, sbp));
  1145.        retval.push_back(seq_aligns);
  1146.        _TRACE("Query " << index << ": " << seq_aligns->Get().size() 
  1147.               << " seqaligns");
  1148.     }
  1149.     
  1150.     return retval;
  1151. }
  1152. TSeqAlignVector
  1153. BLAST_OneSubjectResults2CSeqAlign(const BlastHSPResults* results, 
  1154.         EProgram prog,
  1155.         TSeqLocVector &query,
  1156.         const BlastSeqSrc* seq_src,
  1157.         Int4 subject_index,
  1158.         const BlastScoringOptions* score_options, 
  1159.         const BlastScoreBlk* sbp)
  1160. {
  1161.     ASSERT(results->num_queries == (int)query.size());
  1162.     ASSERT(seq_src);
  1163.     TSeqAlignVector retval;
  1164.     CConstRef<CSeq_id> subject_id;
  1165.     CConstRef<CSeq_id> query_id;
  1166.     CSeq_id* sid = NULL;
  1167.     CSeq_id* qid = NULL;
  1168.     bool is_gapped = score_options->gapped_calculation ? true : false;
  1169.     TSeqPos subj_length = 0;
  1170.     TSeqPos query_length = 0;
  1171.     // Subject is the same for all queries, so retrieve its id right away
  1172.     x_GetSequenceLengthAndId(NULL, seq_src, subject_index, 
  1173.                              &sid, &subj_length);
  1174.     subject_id.Reset(sid);
  1175.         
  1176.     // Process each query's hit list
  1177.     for (int index = 0; index < results->num_queries; index++) {
  1178.         x_GetSequenceLengthAndId(&query[index], NULL, 0, &qid, &query_length);
  1179.         query_id.Reset(qid);
  1180.         CRef<CSeq_align_set> seq_aligns;
  1181.         BlastHitList* hit_list = results->hitlist_array[index];
  1182.         BlastHSPList* hsp_list = NULL;
  1183.         // Find the HSP list corresponding to this subject, if it exists
  1184.         if (hit_list) {
  1185.             int result_index;
  1186.             for (result_index = 0; result_index < hit_list->hsplist_count;
  1187.                  ++result_index) {
  1188.                 hsp_list = hit_list->hsplist_array[result_index];
  1189.                 if (hsp_list->oid == subject_index)
  1190.                     break;
  1191.             }
  1192.         }
  1193.         if (hsp_list) {
  1194.             CRef<CSeq_align> hit_align;
  1195.             if (is_gapped) {
  1196.                 hit_align = 
  1197.                     BLASTHspListToSeqAlign(prog, hsp_list, query_id, 
  1198.                                            subject_id, score_options, sbp);
  1199.             } else {
  1200.                 hit_align = 
  1201.                     BLASTUngappedHspListToSeqAlign(prog, hsp_list, query_id, 
  1202.                         subject_id, query_length, subj_length, 
  1203.                         score_options, sbp);
  1204.             }
  1205.             ListNode* subject_loc_wrap = 
  1206.                 BLASTSeqSrcGetSeqLoc(seq_src, (void*)&hsp_list->oid);
  1207.             SSeqLoc* subject_loc = NULL;
  1208.             if (subject_loc_wrap && 
  1209.                 subject_loc_wrap->choice == BLAST_SEQSRC_CPP_SEQLOC)
  1210.                 subject_loc = (SSeqLoc*) subject_loc_wrap->ptr;
  1211.             x_RemapAlignmentCoordinates(hit_align, &query[index], 
  1212.                                         subject_loc);
  1213.             ListNodeFree(subject_loc_wrap);
  1214.             seq_aligns.Reset(new CSeq_align_set());
  1215.             seq_aligns->Set().push_back(hit_align);
  1216.         } else {
  1217.             seq_aligns.Reset(x_CreateEmptySeq_align_set(NULL));
  1218.         }
  1219.         retval.push_back(seq_aligns);
  1220.     }
  1221.     
  1222.     return retval;
  1223. }
  1224. END_SCOPE(blast)
  1225. END_NCBI_SCOPE
  1226. /* @} */
  1227. /*
  1228. * ===========================================================================
  1229. *
  1230. * $Log: blast_seqalign.cpp,v $
  1231. * Revision 1000.6  2004/06/01 18:05:52  gouriano
  1232. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.42
  1233. *
  1234. * Revision 1.42  2004/05/21 21:41:02  gorelenk
  1235. * Added PCH ncbi_pch.hpp
  1236. *
  1237. * Revision 1.41  2004/05/19 15:26:04  dondosha
  1238. * Edit script operations changed from macros to an enum
  1239. *
  1240. * Revision 1.40  2004/05/05 14:42:25  dondosha
  1241. * Correction in x_RemapAlignmentCoordinates for whole vs. interval Seq-locs
  1242. *
  1243. * Revision 1.39  2004/04/28 19:40:45  dondosha
  1244. * Fixed x_RemapAlignmentCoordinates function to work correctly with all strand combinations
  1245. *
  1246. * Revision 1.38  2004/04/19 12:59:12  madden
  1247. * Changed BLAST_KarlinBlk to Blast_KarlinBlk to avoid conflict with blastkar.h structure
  1248. *
  1249. * Revision 1.37  2004/04/16 14:28:19  papadopo
  1250. * add use of eRPSBlast program
  1251. *
  1252. * Revision 1.36  2004/04/06 20:47:14  dondosha
  1253. * Check if BLASTSeqSrcGetSeqId returns a pointer to CRef instead of a simple pointer to CSeq_id
  1254. *
  1255. * Revision 1.35  2004/03/24 19:14:14  dondosha
  1256. * BlastHSP structure does not have ordering_method field any more, but it does contain a splice_junction field
  1257. *
  1258. * Revision 1.34  2004/03/23 18:22:06  dondosha
  1259. * Minor memory leak fix
  1260. *
  1261. * Revision 1.33  2004/03/23 14:10:50  camacho
  1262. * Minor doxygen fix
  1263. *
  1264. * Revision 1.32  2004/03/19 19:22:55  camacho
  1265. * Move to doxygen group AlgoBlast, add missing CVS logs at EOF
  1266. *
  1267. * Revision 1.31  2004/03/16 22:03:38  camacho
  1268. * Remove dead code
  1269. *
  1270. * Revision 1.30  2004/03/15 19:58:55  dondosha
  1271. * Added BLAST_OneSubjectResults2CSeqalign function to retrieve single subject results from BlastHSPResults
  1272. *
  1273. * Revision 1.29  2003/12/19 20:16:10  dondosha
  1274. * Get length in x_GetSequenceLengthAndId regardless of whether search is gapped; do not call RemapToLoc for whole Seq-locs
  1275. *
  1276. * Revision 1.28  2003/12/03 16:43:47  dondosha
  1277. * Renamed BlastMask to BlastMaskLoc, BlastResults to BlastHSPResults
  1278. *
  1279. * Revision 1.27  2003/12/01 20:02:39  coulouri
  1280. * fix msvc warning
  1281. *
  1282. * Revision 1.26  2003/11/24 20:59:12  ucko
  1283. * Change one ASSERT to _ASSERT (probably more appropriate in general)
  1284. * due to MSVC brokenness.
  1285. *
  1286. * Revision 1.25  2003/11/24 17:14:58  camacho
  1287. * Remap alignment coordinates to original Seq-locs
  1288. *
  1289. * Revision 1.24  2003/11/04 18:37:36  dicuccio
  1290. * Fix for brain-dead MSVC (operator && is ambiguous)
  1291. *
  1292. * Revision 1.23  2003/11/04 17:13:31  dondosha
  1293. * Implemented conversion of results to seqalign for out-of-frame search
  1294. *
  1295. * Revision 1.22  2003/10/31 22:08:39  dondosha
  1296. * Implemented conversion of BLAST results to seqalign for ungapped search
  1297. *
  1298. * Revision 1.21  2003/10/31 00:05:15  camacho
  1299. * Changes to return discontinuous seq-aligns for each query-subject pair
  1300. *
  1301. * Revision 1.20  2003/10/30 21:40:57  dondosha
  1302. * Removed unneeded extra argument from BLAST_Results2CSeqAlign
  1303. *
  1304. * Revision 1.19  2003/10/28 20:53:59  camacho
  1305. * Temporarily use exception for unimplemented function
  1306. *
  1307. * Revision 1.18  2003/10/15 16:59:42  coulouri
  1308. * type correctness fixes
  1309. *
  1310. * Revision 1.17  2003/09/09 15:18:02  camacho
  1311. * Fix includes
  1312. *
  1313. * Revision 1.16  2003/08/19 20:27:51  dondosha
  1314. * Rewrote the results-to-seqalign conversion slightly
  1315. *
  1316. * Revision 1.15  2003/08/19 13:46:13  dicuccio
  1317. * Added 'USING_SCOPE(objects)' to .cpp files for ease of reading implementation.
  1318. *
  1319. * Revision 1.14  2003/08/18 22:17:36  camacho
  1320. * Renaming of SSeqLoc members
  1321. *
  1322. * Revision 1.13  2003/08/18 20:58:57  camacho
  1323. * Added blast namespace, removed *__.hpp includes
  1324. *
  1325. * Revision 1.12  2003/08/18 17:07:41  camacho
  1326. * Introduce new SSeqLoc structure (replaces pair<CSeq_loc, CScope>).
  1327. * Change in function to read seqlocs from files.
  1328. *
  1329. * Revision 1.11  2003/08/15 15:56:32  dondosha
  1330. * Corrections in implementation of results-to-seqalign function
  1331. *
  1332. * Revision 1.10  2003/08/12 19:19:34  dondosha
  1333. * Use TSeqLocVector type
  1334. *
  1335. * Revision 1.9  2003/08/11 14:00:41  dicuccio
  1336. * Indenting changes.  Fixed use of C++ namespaces (USING_SCOPE(objects) inside of
  1337. * BEGIN_NCBI_SCOPE block)
  1338. *
  1339. * Revision 1.8  2003/08/08 19:43:07  dicuccio
  1340. * Compilation fixes: #include file rearrangement; fixed use of 'list' and
  1341. * 'vector' as variable names; fixed missing ostrea<< for __int64
  1342. *
  1343. * Revision 1.7  2003/08/01 17:40:56  dondosha
  1344. * Use renamed functions and structures from local blastkar.h
  1345. *
  1346. * Revision 1.6  2003/07/31 19:45:33  camacho
  1347. * Eliminate Ptr notation
  1348. *
  1349. * Revision 1.5  2003/07/25 22:12:46  camacho
  1350. * Use BLAST Sequence Source to retrieve sequence identifier
  1351. *
  1352. * Revision 1.4  2003/07/25 13:55:58  camacho
  1353. * Removed unnecessary #includes
  1354. *
  1355. * Revision 1.3  2003/07/23 21:28:23  camacho
  1356. * Use new local gapinfo structures
  1357. *
  1358. * Revision 1.2  2003/07/14 21:40:22  camacho
  1359. * Pacify compiler warnings
  1360. *
  1361. * Revision 1.1  2003/07/10 18:34:19  camacho
  1362. * Initial revision
  1363. *
  1364. *
  1365. * ===========================================================================
  1366. */