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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: splign.cpp,v $
  4.  * PRODUCTION Revision 1000.0  2004/06/01 18:12:28  gouriano
  5.  * PRODUCTION PRODUCTION: IMPORTED [GCC34_MSVC7] Dev-tree R1.12
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: splign.cpp,v 1000.0 2004/06/01 18:12:28 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:  Yuri Kapustin
  35. *
  36. * File Description:
  37. *   CSplign class implementation
  38. *
  39. */
  40. #include <ncbi_pch.hpp>
  41. #include "splign_compartment_finder.hpp"
  42. #include "splign_util.hpp"
  43. #include <algo/align/splign/splign.hpp>
  44. #include <algo/align/nw_formatter.hpp>
  45. #include <algo/align/align_exception.hpp>
  46. #include <deque>
  47. #include <math.h>
  48. #include <algorithm>
  49. BEGIN_NCBI_SCOPE
  50. CSplign::CSplign( void )
  51. {
  52.     m_min_query_coverage = 0.25;
  53.     m_compartment_penalty = 0.65;
  54.     m_minidty = 0.75;
  55.     m_endgaps = true;
  56.     m_strand = true;
  57.     m_max_genomic_ext = 100000;
  58.     m_nopolya = false;
  59.     m_model_id = 0;
  60. }
  61. void CSplign::SetAligner( CRef<CSplicedAligner>& aligner ) {
  62.     m_aligner = aligner;
  63. }
  64. const CRef<CSplicedAligner>& CSplign::GetAligner( void ) const {
  65.     return m_aligner;
  66. }
  67. void CSplign::SetSeqAccessor( CRef<CSplignSeqAccessor>& sa ) {
  68.     m_sa = sa;
  69. }
  70. const CRef<CSplignSeqAccessor>& CSplign::GetSeqAccessor( void ) const {
  71.     return m_sa;
  72. }
  73. void CSplign::SetEndGapDetection( bool on ) {
  74.     m_endgaps = on;
  75. }
  76. bool CSplign::GetEndGapDetection( void ) const {
  77.     return m_endgaps;
  78. }
  79. void CSplign::SetPolyaDetection( bool on ) {
  80.     m_nopolya = !on;
  81. }
  82. bool CSplign::GetPolyaDetection( void ) const {
  83.     return !m_nopolya;
  84. }
  85. void CSplign::SetStrand( bool strand ) {
  86.     m_strand = strand;
  87. }
  88. bool CSplign::GetStrand( void ) const {
  89.     return m_strand;
  90. }
  91. void CSplign::SetMinExonIdentity( double idty )
  92. {
  93.     if(!(0 <= idty && idty <= 1)) {
  94.         NCBI_THROW( CAlgoAlignException,
  95.                     eBadParameter,
  96.                     "Identity threshold must be between 0 and 1" );
  97.     }
  98.     else {
  99.         m_minidty = idty;
  100.     }
  101. }
  102. double CSplign::GetMinExonIdentity( void ) const {
  103.     return m_minidty;
  104. }
  105. void CSplign::SetMaxGenomicExtension( size_t ext ) {
  106.     m_max_genomic_ext = ext;
  107. }
  108. size_t CSplign::GetMaxGenomicExtension( void ) const {
  109.     return m_max_genomic_ext;
  110. }
  111. void CSplign::SetMinQueryCoverage( double cov )
  112. {
  113.     if(cov < 0 || cov > 1) {
  114.         NCBI_THROW( CAlgoAlignException,
  115.                     eBadParameter,
  116.                     "Min query coverage out of range");
  117.     }
  118.     m_min_query_coverage = cov;
  119. }
  120. double CSplign::GetMinQueryCoverage( void ) const 
  121. {
  122.     return m_min_query_coverage;
  123. }
  124. void CSplign::SetCompartmentPenalty(double penalty)
  125. {
  126.     if(penalty < 0 || penalty > 1) {
  127.         NCBI_THROW( CAlgoAlignException,
  128.                     eBadParameter,
  129.                     "Min query coverage out of range");
  130.     }
  131.     m_compartment_penalty = penalty;
  132. }
  133. double CSplign::GetCompartmentPenalty( void ) const 
  134. {
  135.     return m_compartment_penalty;
  136. }
  137. void CSplign::x_SetPattern(THits* hits)
  138. {  
  139.     sort(hits->begin(), hits->end(), CHit::PPrecedeQ);
  140.     vector<size_t> pattern0;
  141.     for(size_t i = 0, n = hits->size(); i < n; ++i) {
  142.         const CHit& h = (*hits)[i];
  143.         if(1 + h.m_ai[1] - h.m_ai[0] >= 10) {
  144.             pattern0.push_back( h.m_ai[0] );
  145.             pattern0.push_back( h.m_ai[1] );
  146.             pattern0.push_back( h.m_ai[2] );
  147.             pattern0.push_back( h.m_ai[3] );
  148.         }
  149.     }
  150.     const char* Seq1 = &m_mrna.front();
  151.     const size_t SeqLen1 = m_polya_start < kMax_UInt?
  152.         m_polya_start: m_mrna.size();
  153.     const char* Seq2 = &m_genomic.front();
  154.     const size_t SeqLen2 = m_genomic.size();
  155.     
  156.     // verify some conditions on the input hit pattern
  157.     size_t dim = pattern0.size();
  158.     const char* err = 0;
  159.     if(dim % 4 == 0) {
  160.         for(size_t i = 0; i < dim; i += 4) {
  161.             
  162.             if(pattern0[i] > pattern0[i+1] || pattern0[i+2] > pattern0[i+3]) {
  163.                 err = "Pattern hits must be specified in plus strand";
  164.                 break;
  165.             }
  166.             
  167.             if(i > 4) {
  168.                 if(pattern0[i]<=pattern0[i-3] || pattern0[i+2]<=pattern0[i-2]){
  169.                     err = "Pattern hits coordinates must be sorted";
  170.                     break;
  171.                 }
  172.             }
  173.             
  174.             if(pattern0[i+1] >= SeqLen1 || pattern0[i+3] >= SeqLen2) {
  175.                 err = "One or several pattern hits are out of range";
  176.                 break;
  177.             }
  178.         }
  179.     }
  180.     else {
  181.         err = "Pattern must have a dimension multiple of four";
  182.     }
  183.     
  184.     if(err) {
  185.         NCBI_THROW( CAlgoAlignException, eBadParameter, err );
  186.     }
  187.     else {
  188.         m_alnmap.clear();
  189.         m_pattern.clear();
  190.         
  191.         // copy from pattern0 to pattern so that each hit is not too large
  192.         const size_t max_len = kMax_UInt;// turn this off: sometimes we really
  193.                                          // need just the longest perf match
  194.                                          // and there is no direct relationship
  195.                                          // btw hits and exons
  196.         vector<size_t> pattern;
  197.         for(size_t i = 0; i < dim; i += 4) {
  198.             size_t lenq = 1 + pattern0[i+1] - pattern0[i];
  199.             if(lenq <= max_len) {
  200.                 copy(pattern0.begin() + i,
  201.                      pattern0.begin() + i + 4,
  202.                      back_inserter(pattern));
  203.             }
  204.             else {
  205.                 const size_t d = (lenq-1) / max_len + 1;
  206.                 const size_t inc = lenq / d + 1;
  207.                 for(size_t a = pattern0[i], b = a , c = pattern0[i+2], d = c;
  208.                     a < pattern0[i+1]; (a = b + 1), (c = d + 1) ) {
  209.                     b = a + inc - 1;
  210.                     d = c + inc - 1;
  211.                     if(b > pattern0[i+1] || d > pattern0[i+3]) {
  212.                         b = pattern0[i+1];
  213.                         d = pattern0[i+3];
  214.                     }
  215.                     pattern.push_back(a);
  216.                     pattern.push_back(b);
  217.                     pattern.push_back(c);
  218.                     pattern.push_back(d);
  219.                 }
  220.             }
  221.         }
  222.         
  223.         dim = pattern.size();
  224.         
  225.         SAlnMapElem map_elem;
  226.         map_elem.m_box[0] = map_elem.m_box[2] = 0;
  227.         map_elem.m_pattern_start = map_elem.m_pattern_end = -1;
  228.         
  229.         // realign pattern hits and build the alignment map
  230.         for(size_t i = 0; i < dim; i += 4) {    
  231.             
  232.             CNWAligner nwa ( Seq1 + pattern[i],
  233.                              pattern[i+1] - pattern[i] + 1,
  234.                              Seq2 + pattern[i+2],
  235.                              pattern[i+3] - pattern[i+2] + 1 );
  236.             nwa.Run();
  237.             
  238.             size_t L1, R1, L2, R2;
  239.             const size_t max_seg_size = nwa.GetLongestSeg(&L1, &R1, &L2, &R2);
  240.             if(max_seg_size) {
  241.                 const size_t hitlen_q = pattern[i + 1] - pattern[i] + 1;
  242.                 const size_t hlq3 = hitlen_q/3;
  243.                 const size_t sh = hlq3;
  244.                 
  245.                 size_t delta = sh > L1? sh - L1: 0;
  246.                 size_t q0 = pattern[i] + L1 + delta;
  247.                 size_t s0 = pattern[i+2] + L2 + delta;
  248.                 
  249.                 const size_t h2s_right = hitlen_q - R1 - 1;
  250.                 delta = sh > h2s_right? sh - h2s_right: 0;
  251.                 size_t q1 = pattern[i] + R1 - delta;
  252.                 size_t s1 = pattern[i+2] + R2 - delta;
  253.                 
  254.                 if(q0 > q1 || s0 > s1) { // longest seg was probably too short
  255.                     q0 = pattern[i] + L1;
  256.                     s0 = pattern[i+2] + L2;
  257.                     q1 = pattern[i] + R1;
  258.                     s1 = pattern[i+2] + R2;
  259.                 }
  260.                 m_pattern.push_back(q0); m_pattern.push_back(q1);
  261.                 m_pattern.push_back(s0); m_pattern.push_back(s1);
  262.                 
  263.                 const size_t pattern_dim = m_pattern.size();
  264.                 if(map_elem.m_pattern_start == -1) {
  265.                     map_elem.m_pattern_start = pattern_dim - 4;;
  266.                 }
  267.                 map_elem.m_pattern_end = pattern_dim - 1;
  268.             }
  269.             
  270.             map_elem.m_box[1] = pattern[i+1];
  271.             map_elem.m_box[3] = pattern[i+3];
  272.         }
  273.         
  274.         map_elem.m_box[1] = SeqLen1 - 1;
  275.         map_elem.m_box[3] = SeqLen2 - 1;
  276.         m_alnmap.push_back(map_elem);
  277.     }
  278. }
  279. void CSplign::Run( THits* phits )
  280. {
  281.     if(!phits) {
  282.         NCBI_THROW( CAlgoAlignException,
  283.                     eInternal,
  284.                     "Unexpected NULL pointers" );
  285.     }
  286.     THits& hits = *phits;
  287.   
  288.     if(m_sa.IsNull()) {
  289.         NCBI_THROW( CAlgoAlignException,
  290.                     eNotInitialized,
  291.                     "Sequence accessor object not specified" );
  292.     }
  293.   
  294.     if(m_aligner.IsNull()) {
  295.       NCBI_THROW( CAlgoAlignException,
  296.   eNotInitialized,
  297.   "Spliced aligner object not specified" );
  298.     }
  299.     if(hits.size() == 0) {
  300.       NCBI_THROW( CAlgoAlignException,
  301.   eNoData,
  302.   "Empty hit vector passed to CSplign" );
  303.     }
  304.     const string query ( hits[0].m_Query );
  305.     const string subj  ( hits[0].m_Subj );
  306.     m_result.clear();
  307.     // pre-load the spliced sequence and calculate min coverage
  308.     m_mrna.clear();
  309.     m_sa->Load(query, &m_mrna, 0, kMax_UInt);
  310.     const size_t mrna_size = m_mrna.size();
  311.     const size_t min_coverage = size_t(m_min_query_coverage * mrna_size);
  312.     const size_t comp_penalty_bps = size_t(m_compartment_penalty * mrna_size);
  313.     
  314.     // iterate through compartments
  315.     CCompartmentAccessor comps (hits.begin(), hits.end(),
  316.                                 comp_penalty_bps, min_coverage);
  317.     THits comp_hits;
  318.     size_t smin = 0, smax = kMax_UInt;
  319.     bool same_strand = false;
  320.     for(size_t i = 0, dim = comps.GetCount(); i < dim; ++i) {
  321.       comps.Get(i, comp_hits);
  322.       
  323.       // limit the space beyond the compartment
  324.       // to avoid shared exons
  325.       if(i+1 == dim) {
  326.         smax = kMax_UInt;
  327.         same_strand = false;
  328.       }
  329.       else {
  330.         
  331.         bool strand_this = comps.GetStrand(i);
  332.         bool strand_next = comps.GetStrand(i+1);
  333.         same_strand = strand_this == strand_next;
  334.         if(same_strand) {
  335.           const size_t* box0  = comps.GetBox(i);
  336.           const size_t* box1  = box0 + 4;
  337.           const size_t  dist  = box1[2] - box0[3];
  338.           
  339.           size_t qdim0, qdim1;
  340.           if(strand_this) {
  341.             qdim0 = mrna_size - box0[1] - 1;
  342.             qdim1 = box1[0];
  343.           }
  344.           else {
  345.             qdim0 = box0[0];
  346.             qdim1 = mrna_size - box1[1] - 1;
  347.           }
  348.           
  349.           const size_t  qdim = qdim0 + qdim1;
  350.           
  351.           if(qdim == 0) {
  352.             smax = box1[2] - 1; 
  353.           }
  354.           else {
  355.             const double a0 = double(qdim0) / qdim;
  356.             smax = size_t(floor (box0[3] + a0*dist));
  357.             if(smax == box1[2]) {
  358.               --smax;
  359.             }
  360.           }
  361.         }
  362.         else { // !same_strand
  363.           smax = kMax_UInt;
  364.         }
  365.       }
  366.      
  367.       try {
  368.         SAlignedCompartment ac = x_RunOnCompartment(&comp_hits, smin, smax);
  369.         ac.m_id = ++m_model_id;
  370.         ac.m_segments = m_segments;
  371.         ac.m_error = false;
  372.         ac.m_msg = "Ok";
  373.         m_result.push_back(ac);
  374.       }
  375.       catch(CException& e) {
  376.         m_result.push_back(SAlignedCompartment(0, true, e.GetMsg().c_str()));
  377.       }
  378.       smin = same_strand? (smax + 1): 0;
  379.     }
  380. }
  381. // naive polya detection
  382. size_t CSplign::x_TestPolyA(void)
  383. {
  384.   const size_t dim = m_mrna.size();
  385.   int i = dim - 1;
  386.   for(; i >= 0; --i) {
  387.     if(m_mrna[i] != 'A') break;
  388.   }
  389.   const size_t len = dim - i - 1;;
  390.   return len > 3 ? i + 1 : kMax_UInt;
  391. }
  392. CSplign::SAlignedCompartment CSplign::x_RunOnCompartment( THits* hits,
  393.                                                           size_t range_left,
  394.                                                           size_t range_right )
  395. {
  396.   SAlignedCompartment rv;
  397.   m_segments.clear();
  398.   if(range_left > range_right) {
  399.     NCBI_THROW( CAlgoAlignException, eInternal, "Invalid range data");
  400.   }
  401.   XFilter(hits);
  402.   if(hits->size() == 0) {
  403.     NCBI_THROW( CAlgoAlignException, eNoData,
  404. "No hits left after filtering");
  405.   }
  406.   const string query ( hits->front().m_Query );
  407.   const string subj  ( hits->front().m_Subj );
  408.   const size_t mrna_size = m_mrna.size();  
  409.   if( !m_strand ) {
  410.     // make reverse complimentary
  411.     reverse (m_mrna.begin(), m_mrna.end());
  412.     transform(m_mrna.begin(), m_mrna.end(), m_mrna.begin(),
  413.       SCompliment());
  414.     // adjust the hits
  415.     for(size_t i = 0, n = hits->size(); i < n; ++i) {
  416.       CHit& h = (*hits)[i];
  417.       bool plus = h.IsStraight();
  418.       size_t a0 = mrna_size - h.m_ai[0] + 1;
  419.       size_t a1 = mrna_size - h.m_ai[1] + 1;
  420.       h.m_an[0] = h.m_ai[0] = a1;
  421.       h.m_an[1] = h.m_ai[1] = a0;
  422.       // change strand
  423.       if(plus) {
  424. h.m_an[2] = h.m_ai[3];
  425. h.m_an[3] = h.m_ai[2];
  426.       }
  427.       else {
  428. h.m_an[2] = h.m_ai[2];
  429. h.m_an[3] = h.m_ai[3];
  430.       }
  431.     }
  432.   }
  433.   m_polya_start = m_nopolya? kMax_UInt: x_TestPolyA();
  434.   if(m_polya_start < kMax_UInt) {
  435.     CleaveOffByTail(hits, m_polya_start + 1); // cleave off hits beyond cds
  436.     if(hits->size() == 0) {
  437.       NCBI_THROW( CAlgoAlignException,
  438.                   eNoData,
  439.                   "No hits found beyond Poly(A), if any");
  440.     }
  441.   }
  442.   // find regions of interest on mRna (query)
  443.   // and contig (subj)
  444.   size_t qmin, qmax, smin, smax;
  445.   GetHitsMinMax(*hits, &qmin, &qmax, &smin, &smax);
  446.   --qmin; --qmax; --smin; --smax;
  447.   qmin = 0;
  448.   qmax = m_polya_start < kMax_UInt? m_polya_start - 1: mrna_size - 1;
  449.   smin = max(0, int(smin - m_max_genomic_ext));
  450.   smax += m_max_genomic_ext;
  451.  
  452.   if(smin < range_left) {
  453.     smin = range_left;
  454.   }
  455.   if(smax > range_right) {
  456.     smax = range_right;
  457.   }
  458.   
  459.   bool ctg_strand = (*hits)[0].IsStraight();
  460.   m_genomic.clear();
  461.   m_sa->Load(subj, &m_genomic, smin, smax);
  462.   const size_t ctg_end = smin + m_genomic.size();
  463.   if(ctg_end - 1 < smax) { // perhabs adjust smax
  464.     smax = ctg_end - 1;
  465.   }
  466.   if(!ctg_strand) {
  467.     // make reverse complementary
  468.     // for the contig's area of interest
  469.     reverse (m_genomic.begin(), m_genomic.end());
  470.     transform(m_genomic.begin(), m_genomic.end(), m_genomic.begin(),
  471.       SCompliment());
  472.     // flip the hits
  473.     for(size_t i = 0, n = hits->size(); i < n; ++i) {
  474.       CHit& h = (*hits)[i];
  475.       size_t a2 = smax - (h.m_ai[3] - smin) + 2;
  476.       size_t a3 = smax - (h.m_ai[2] - smin) + 2;
  477.       h.m_an[2] = h.m_ai[2] = a2;
  478.       h.m_an[3] = h.m_ai[3] = a3;
  479.     }
  480.   }
  481.   rv.m_QueryStrand = m_strand;
  482.   rv.m_SubjStrand  = ctg_strand;
  483.   rv.m_qmin = qmin;
  484.   rv.m_smin = smin;
  485.   rv.m_smax = smax;
  486.   rv.m_mrnasize = mrna_size;
  487.   // shift hits so that they originate from qmin, smin;
  488.   // also make them zero-based
  489.   for(size_t i = 0, n = hits->size(); i < n; ++i) {
  490.     CHit& h = (*hits)[i];
  491.     h.m_an[0] = h.m_ai[0] -= qmin + 1;
  492.     h.m_an[1] = h.m_ai[1] -= qmin + 1;
  493.     h.m_an[2] = h.m_ai[2] -= smin + 1;
  494.     h.m_an[3] = h.m_ai[3] -= smin + 1;
  495.   }  
  496.   x_SetPattern( hits );
  497.   x_Run(&m_mrna.front(), &m_genomic.front());
  498.  
  499.   const size_t seg_dim = m_segments.size();
  500.   if(seg_dim == 0) {
  501.     NCBI_THROW( CAlgoAlignException, eNoData, "No alignment found.");
  502.   }
  503.   // try to extend the last segment into the PolyA area  
  504.   if(m_polya_start < kMax_UInt && seg_dim && m_segments[seg_dim-1].m_exon) {
  505.     CSplign::SSegment& s = const_cast<CSplign::SSegment&>(
  506.        m_segments[seg_dim-1]);
  507.     const char* p0 = &m_mrna.front() + s.m_box[1] + 1;
  508.     const char* q = &m_genomic.front() + s.m_box[3] + 1;
  509.     const char* p = p0;
  510.     const char* pe = &m_mrna.front() + mrna_size;
  511.     const char* qe = &m_genomic.front() + m_genomic.size();
  512.     for(; p < pe && q < qe; ++p, ++q) {
  513.       if(*p != 'A') break;
  514.       if(*p != *q) break;
  515.     }
  516.     const size_t sh = p - p0;
  517.     if(sh) {
  518.       // resize
  519.       s.m_box[1] += sh;
  520.       s.m_box[3] += sh;
  521.       s.m_details.append(sh, 'M');
  522.       s.RestoreIdentity();
  523.       // correct annotation
  524.       const size_t ann_dim = s.m_annot.size();
  525.       if(ann_dim > 2 && s.m_annot[ann_dim - 3] == '>') {
  526.           ++q;
  527.           s.m_annot[ann_dim - 2] = q < qe? *q: ' ';
  528.           ++q;
  529.           s.m_annot[ann_dim - 1] = q < qe? *q: ' ';
  530.       }
  531.       m_polya_start += sh;
  532.     }
  533.   }
  534.   int j = seg_dim - 1;
  535.   // look for PolyA in trailing segments:
  536.   // if a segment is mostly 'A's then we add it to PolyA
  537.   for(; j >= 0; --j) {
  538.     const CSplign::SSegment& s = m_segments[j];
  539.     const char* p0 = &m_mrna[qmin] + s.m_box[0];
  540.     const char* p1 = &m_mrna[qmin] + s.m_box[1] + 1;
  541.     size_t count = 0;
  542.     for(const char* pc = p0; pc != p1; ++pc) {
  543.       if(*pc == 'A') ++count;
  544.     }
  545.     const size_t len = p1 - p0;
  546.     double min_a_content = 0.799;
  547.     // also check splices
  548.     if(s.m_exon && j > 0 && m_segments[j-1].m_exon) {
  549.       if(!IsConsensus(m_segments[j-1].GetDonor(), s.GetAcceptor())) {
  550.         min_a_content = 0.599;
  551.       }
  552.     }
  553.     if(!s.m_exon) {
  554.         min_a_content = 0.599;
  555.     }
  556.     if(double(count)/len < min_a_content) {
  557.         break;
  558.     }
  559.   }
  560.   if(j >= 0 && j < int(seg_dim - 1)) {
  561.     m_polya_start = m_segments[j].m_box[1] + 1;
  562.   }
  563.   // test if we have at least one exon
  564.   bool some_exons = false;
  565.   for(int i = 0; i <= j; ++i ) {
  566.     if(m_segments[i].m_exon) {
  567.       some_exons = true;
  568.       break;
  569.     }
  570.   }
  571.   if(!some_exons) {
  572.     NCBI_THROW( CAlgoAlignException, eNoData,
  573.                 "No exons found above identity limit.");
  574.   }
  575.   m_segments.resize(j + 1);
  576.   return rv;
  577. }
  578. void CSplign::x_Run(const char* Seq1, const char* Seq2)
  579. {
  580.     deque<SSegment> segments;
  581.     for(size_t i = 0, map_dim = m_alnmap.size(); i < map_dim; ++i) {
  582.         const SAlnMapElem& zone = m_alnmap[i];
  583.         // setup sequences
  584.         m_aligner->SetSequences(Seq1 + zone.m_box[0],
  585.             zone.m_box[1] - zone.m_box[0] + 1,
  586.             Seq2 + zone.m_box[2],
  587.             zone.m_box[3] - zone.m_box[2] + 1,
  588.             false);
  589.         // prepare the pattern
  590.         vector<size_t> pattern;
  591.         if(zone.m_pattern_start >= 0) {
  592.             copy(m_pattern.begin() + zone.m_pattern_start,
  593.             m_pattern.begin() + zone.m_pattern_end + 1,
  594.             back_inserter(pattern));
  595.             for(size_t j = 0, pt_dim = pattern.size(); j < pt_dim; j += 4) {
  596. //#define DBG_DUMP_PATTERN
  597. #ifdef  DBG_DUMP_PATTERN
  598.       cerr << pattern[j] << 't' << pattern[j+1] << 't'
  599.    << pattern[j+2] << 't' << pattern[j+3] << endl;
  600. #endif
  601.                 pattern[j]   -= zone.m_box[0];
  602.                 pattern[j+1] -= zone.m_box[0];
  603.                 pattern[j+2] -= zone.m_box[2];
  604.                 pattern[j+3] -= zone.m_box[2];
  605.             }
  606.             if(pattern.size()) {
  607.                 m_aligner->SetPattern(pattern);
  608.             }
  609.             // setup esf
  610.             m_aligner->SetEndSpaceFree(true, true, true, true);
  611.             
  612.             // align
  613.             m_aligner->Run();
  614. // #define DBG_DUMP_TYPE2
  615. #ifdef  DBG_DUMP_TYPE2
  616.             {{
  617.             CNWFormatter fmt (*m_aligner);
  618.             string txt;
  619.             fmt.AsText(&txt, CNWFormatter::eFormatType2);
  620.             cerr << txt;
  621.             }}  
  622. #endif
  623.             // create list of segments
  624.             CNWFormatter formatter (*m_aligner);
  625.             string exons;
  626.             formatter.AsText(&exons, CNWFormatter::eFormatExonTableEx);      
  627.     
  628.             CNcbiIstrstream iss_exons (exons.c_str());
  629.             while(iss_exons) {
  630.                 string id1, id2, txt, repr;
  631.                 size_t q0, q1, s0, s1, size;
  632.                 double idty;
  633.                 iss_exons >> id1 >> id2 >> idty >> size
  634.   >> q0 >> q1 >> s0 >> s1 >> txt >> repr;
  635.                 if(!iss_exons) break;
  636.                 q0 += zone.m_box[0];
  637.                 q1 += zone.m_box[0];
  638.                 s0 += zone.m_box[2];
  639.                 s1 += zone.m_box[2];
  640.                 SSegment e;
  641.                 e.m_exon = true;
  642.                 e.m_idty = idty;
  643.                 e.m_len = size;
  644.                 e.m_box[0] = q0; e.m_box[1] = q1;
  645.                 e.m_box[2] = s0; e.m_box[3] = s1;
  646.                 e.m_annot = txt;
  647.                 e.m_details = repr;
  648.                 segments.push_back(e);
  649.             }
  650.             // append a gap
  651.             if(i + 1 < map_dim) {
  652.                 SSegment g;
  653.                 g.m_exon = false;
  654.                 g.m_box[0] = zone.m_box[1] + 1;
  655.                 g.m_box[1] = m_alnmap[i+1].m_box[0] - 1;
  656.                 g.m_box[2] = zone.m_box[3] + 1;
  657.                 g.m_box[3] = m_alnmap[i+1].m_box[2] - 1;
  658.                 g.m_idty = 0;
  659.                 g.m_len = g.m_box[1] - g.m_box[0] + 1;
  660.                 g.m_annot = "<GAP>";
  661.                 g.m_details.append(Seq1+g.m_box[0], g.m_box[1]-g.m_box[0]+1);
  662.                 segments.push_back(g);
  663.             }
  664.         }
  665.     } // zone iterations end
  666.     // segment-level postprocessing
  667.     size_t seg_dim = segments.size();
  668.     if(seg_dim == 0) {
  669.         return;
  670.     }
  671.     // First go from the ends and see if we
  672.     // can improve boundary exons
  673.     size_t k0 = 0;
  674.     while(k0 < seg_dim) {
  675.         SSegment& s = segments[k0];
  676.         if(s.m_exon) {
  677.             if(s.m_idty < m_minidty || m_endgaps) {
  678.                 s.ImproveFromLeft(Seq1, Seq2);
  679.             }
  680.             if(s.m_idty >= m_minidty) {
  681.                 break;
  682.             }
  683.         }
  684.         ++k0;
  685.     }
  686.     // fill the left-hand gap, if any
  687.     if(segments[0].m_exon && segments[0].m_box[0] > 0) {
  688.         segments.push_front(SSegment());
  689.         SSegment& g = segments.front();
  690.         g.m_exon = false;
  691.         g.m_box[0] = 0;
  692.         g.m_box[1] = segments[0].m_box[0] - 1;
  693.         g.m_box[2] = 0;
  694.         g.m_box[3] = segments[0].m_box[2] - 1;
  695.         g.m_idty = 0;
  696.         g.m_len = segments[0].m_box[0];
  697.         g.m_annot = "<GAP>";
  698.         g.m_details = string(Seq1 + g.m_box[0], g.m_box[1] + 1 - g.m_box[0]);
  699.         ++seg_dim;
  700.         ++k0;
  701.     }
  702.     int k1 = int(seg_dim - 1);
  703.     while(k1 >= int(k0)) {
  704.         SSegment& s = segments[k1];
  705.         if(s.m_exon) {
  706.             if(s.m_idty < m_minidty || m_endgaps) {
  707.             s.ImproveFromRight(Seq1, Seq2);
  708.             }
  709.             if(s.m_idty >= m_minidty) {
  710.             break;
  711.             }
  712.         }
  713.         --k1;
  714.     }
  715.     const size_t SeqLen2 = m_genomic.size();
  716.     const size_t SeqLen1 = m_polya_start == kMax_UInt? m_mrna.size():
  717.         m_polya_start;
  718.     // fill the right-hand gap, if any
  719.     if( segments[seg_dim - 1].m_exon && 
  720.         segments[seg_dim - 1].m_box[1] < SeqLen1 - 1) {
  721.         SSegment g;
  722.         g.m_exon = false;
  723.         g.m_box[0] = segments[seg_dim - 1].m_box[1] + 1;
  724.         g.m_box[1] = SeqLen1 - 1;
  725.         g.m_box[2] = segments[seg_dim - 1].m_box[3] + 1;
  726.         g.m_box[3] = SeqLen2 - 1;
  727.         g.m_idty = 0;
  728.         g.m_len = g.m_box[1] - g.m_box[0] + 1;
  729.         g.m_annot = "<GAP>";
  730.         g.m_details = string(Seq1 + g.m_box[0], g.m_box[1] + 1 - g.m_box[0]);
  731.         segments.push_back(g);
  732.         ++seg_dim;
  733.     }
  734.     // turn to gaps exons with low identity
  735.     for(size_t k = 0; k < seg_dim; ++k) {
  736.         SSegment& s = segments[k];
  737.         if(s.m_exon && s.m_idty < m_minidty) {
  738.             s.m_exon = false;
  739.             s.m_idty = 0;
  740.             s.m_len = s.m_box[1] - s.m_box[0] + 1;
  741.             s.m_annot = "<GAP>";
  742.             s.m_details.resize(0);
  743.             s.m_details.append(Seq1 + s.m_box[0],
  744.        s.m_box[1] + 1 - s.m_box[0]);
  745.         }
  746.     }
  747.     // turn to gaps extra-short exons preceeded/followed by gaps
  748.     bool gap_prev = false;
  749.     for(size_t k = 0; k < seg_dim; ++k) {
  750.         SSegment& s = segments[k];
  751. if(s.m_exon == false) {
  752.   gap_prev = true;
  753. }
  754. else {
  755.   size_t length = s.m_box[1] - s.m_box[0] + 1;
  756.   bool gap_next = false;
  757.   if(k + 1 < seg_dim) {
  758.     gap_next = !segments[k+1].m_exon;
  759.   }
  760.   if(length <= 5 && (gap_prev || gap_next)) {
  761.             s.m_exon = false;
  762.             s.m_idty = 0;
  763.             s.m_len = s.m_box[1] - s.m_box[0] + 1;
  764.             s.m_annot = "<GAP>";
  765.             s.m_details.resize(0);
  766.             s.m_details.append(Seq1 + s.m_box[0],
  767.        s.m_box[1] + 1 - s.m_box[0]);
  768.   }
  769.   gap_prev = false;
  770. }
  771.     }
  772.     // now merge all adjacent gaps
  773.     int gap_start_idx = -1;
  774.     if(segments.size() && segments[0].m_exon == false) {
  775.         gap_start_idx = 0;
  776.     }
  777.     size_t segs_dim = segments.size();
  778.     for(size_t k = 0; k < segs_dim; ++k) {
  779.         SSegment& s = segments[k];
  780.         if(!s.m_exon) {
  781.             if(gap_start_idx == -1) {
  782.                 gap_start_idx = int(k);
  783.                 if(k > 0) {
  784.                     s.m_box[0] = segments[k-1].m_box[1] + 1;
  785.                     s.m_box[2] = segments[k-1].m_box[3] + 1;
  786.                 }
  787.             }
  788.         }
  789.         else {
  790.            if(gap_start_idx >= 0) {
  791.                SSegment& g = segments[gap_start_idx];
  792.                g.m_box[1] = s.m_box[0] - 1;
  793.                g.m_box[3] = s.m_box[2] - 1;
  794.                g.m_len = g.m_box[1] - g.m_box[0] + 1;
  795.                g.m_details.resize(0);
  796.                g.m_details.append(Seq1 + g.m_box[0],
  797.   g.m_box[1] + 1 - g.m_box[0]);
  798.                m_segments.push_back(g);
  799.                gap_start_idx = -1;
  800.            }
  801.            m_segments.push_back(s);
  802.         } 
  803.     }
  804.     if(gap_start_idx >= 0) {
  805.         SSegment& g = segments[gap_start_idx];
  806.         g.m_box[1] = segments[segs_dim-1].m_box[1];
  807.         g.m_box[3] = segments[segs_dim-1].m_box[3];
  808.         g.m_len = g.m_box[1] - g.m_box[0] + 1;
  809.         g.m_details.resize(0);
  810.         g.m_details.append(Seq1 + g.m_box[0], g.m_box[1] + 1 - g.m_box[0]);
  811.         m_segments.push_back(g);
  812.     }
  813. }
  814. // try improving the segment by cutting it from the left
  815. void CSplign::SSegment::ImproveFromLeft(const char* seq1, const char* seq2)
  816. {
  817.   const size_t min_query_size = 4;
  818.   int i0 = int(m_box[1] - m_box[0] + 1), i0_max = i0;
  819.   if(i0 < int(min_query_size)) {
  820.     return;
  821.   }
  822.   // find the top score suffix
  823.   int i1 = int(m_box[3] - m_box[2] + 1), i1_max = i1;
  824.   
  825.   CNWAligner::TScore score_max = 0, s = 0;
  826.   
  827.   const CNWAligner::TScore wm =  1;
  828.   const CNWAligner::TScore wms = -1;
  829.   const CNWAligner::TScore wg =  0;
  830.   const CNWAligner::TScore ws =  -1;
  831.   
  832.   string::reverse_iterator irs0 = m_details.rbegin(),
  833.     irs1 = m_details.rend(), irs = irs0, irs_max = irs0;
  834.   for( ; irs != irs1; ++irs) {
  835.     
  836.     switch(*irs) {
  837.       
  838.     case 'M': {
  839.       s += wm;
  840.       --i0;
  841.       --i1;
  842.       }
  843.       break;
  844.       
  845.     case 'R': {
  846.       s += wms;
  847.       --i0;
  848.       --i1;
  849.       }
  850.       break;
  851.       
  852.     case 'I': {
  853.         s += ws;
  854. if(irs > irs0 && *(irs-1)!='I') s += wg;
  855. --i1;
  856.       }
  857.       break;
  858.     case 'D': {
  859.         s += ws;
  860. if(irs > irs0 && *(irs-1)!='D') s += wg;
  861. --i0;
  862.       }
  863.     }
  864.     if(s >= score_max) {
  865.       score_max = s;
  866.       i0_max = i0;
  867.       i1_max = i1;
  868.       irs_max = irs;
  869.     }
  870.   }
  871.   // work around a weird case of equally optimal
  872.   // but detrimental for our purposes alignment
  873.   // -check the actual sequence chars
  874.   size_t head = 0;
  875.   while(i0_max > 0 && i1_max > 0) {
  876.     if(seq1[m_box[0]+i0_max-1] == seq2[m_box[2]+i1_max-1]) {
  877.       --i0_max; --i1_max;
  878.       ++head;
  879.     }
  880.     else {
  881.       break;
  882.     }
  883.   }
  884.   // if the resulting segment is still long enough
  885.   if(m_box[1] - m_box[0] + 1 - i0_max >= min_query_size
  886.      && i0_max > 0) {
  887.     // resize
  888.     m_box[0] += i0_max;
  889.     m_box[2] += i1_max;
  890.     m_details.erase(0, m_details.size() - (irs_max - irs0 + 1));
  891.     m_details.insert(m_details.begin(), head, 'M');
  892.     RestoreIdentity();
  893.     
  894.     // update the first two annotation symbols
  895.     if(m_annot.size() > 2 && m_annot[2] == '<') {
  896.       int  j1 = m_box[2] - 2;
  897.       char c1 = j1 >= 0? seq2[j1]: ' ';
  898.       m_annot[0] = c1;
  899.       int  j2 = m_box[2] - 2;
  900.       char c2 = j2 >= 0? seq2[j2]: ' ';
  901.       m_annot[1] = c2;
  902.     }
  903.   }
  904. }
  905. // try improving the segment by cutting it from the right
  906. void CSplign::SSegment::ImproveFromRight(const char* seq1, const char* seq2)
  907. {
  908.   const size_t min_query_size = 4;
  909.   if(m_box[1] - m_box[0] + 1 < min_query_size) {
  910.     return;
  911.   }
  912.   // find the top score prefix
  913.   int i0 = -1, i0_max = i0;
  914.   int i1 = -1, i1_max = i1;
  915.   CNWAligner::TScore score_max = 0, s = 0;
  916.   const CNWAligner::TScore wm =  1;
  917.   const CNWAligner::TScore wms = -1;
  918.   const CNWAligner::TScore wg =  0;
  919.   const CNWAligner::TScore ws =  -1;
  920.   string::iterator irs0 = m_details.begin(),
  921.     irs1 = m_details.end(), irs = irs0, irs_max = irs0;
  922.   for( ; irs != irs1; ++irs) {
  923.     switch(*irs) {
  924.     case 'M': {
  925.         s += wm;
  926. ++i0;
  927. ++i1;
  928.       }
  929.       break;
  930.     case 'R': {
  931.         s += wms;
  932. ++i0;
  933. ++i1;
  934.       }
  935.       break;
  936.       
  937.     case 'I': {
  938.       s += ws;
  939. if(irs > irs0 && *(irs-1) != 'I') s += wg;
  940. ++i1;
  941.     }
  942.       break;
  943.     case 'D': {
  944.         s += ws;
  945. if(irs > irs0 && *(irs-1) != 'D') s += wg;
  946. ++i0;
  947.       }
  948.     }
  949.     if(s >= score_max) {
  950.       score_max = s;
  951.       i0_max = i0;
  952.       i1_max = i1;
  953.       irs_max = irs;
  954.     }
  955.   }
  956.   int dimq = int(m_box[1] - m_box[0] + 1);
  957.   int dims = int(m_box[3] - m_box[2] + 1);
  958.   // work around a weird case of equally optimal
  959.   // but detrimental for our purposes alignment
  960.   // -check the actual sequences
  961.   size_t tail = 0;
  962.   while(i0_max < dimq - 1  && i1_max < dims - 1) {
  963.     if(seq1[m_box[0]+i0_max+1] == seq2[m_box[2]+i1_max+1]) {
  964.       ++i0_max; ++i1_max;
  965.       ++tail;
  966.     }
  967.     else {
  968.       break;
  969.     }
  970.   }
  971.   dimq += tail;
  972.   dims += tail;
  973.   // if the resulting segment is still long enough
  974.   if(i0_max >= int(min_query_size) && i0_max < dimq - 1) {
  975.     m_box[1] = m_box[0] + i0_max;
  976.     m_box[3] = m_box[2] + i1_max;
  977.     m_details.resize(irs_max - irs0 + 1);
  978.     m_details.insert(m_details.end(), tail, 'M');
  979.     RestoreIdentity();
  980.     
  981.     // update the last two annotation chars
  982.     const size_t adim = m_annot.size();
  983.     if(adim > 2 && m_annot[adim - 3] == '>') {
  984.       m_annot[adim-2] = seq2[m_box[3] + 1];
  985.       m_annot[adim-1] = seq2[m_box[3] + 2];
  986.     }
  987.   }
  988. }
  989. void CSplign::SSegment::RestoreIdentity()
  990. {
  991.     // restore length and identity
  992.     m_len = m_details.size();
  993.     string::const_iterator ib = m_details.begin(), ie = m_details.end();
  994.     size_t count = 0; // not using std::count here due to known incompatibilty
  995.     for(string::const_iterator ii = ib; ii != ie; ++ii) {
  996.         if(*ii == 'M') ++count;
  997.     }
  998.     m_idty = double(count) / m_len;
  999. }
  1000. const char* CSplign::SSegment::GetDonor() const 
  1001. {
  1002.     const size_t adim = m_annot.size();
  1003.     return
  1004.       (adim > 2 && m_annot[adim - 3] == '>')? (m_annot.c_str() + adim - 2): 0;
  1005. }
  1006. const char* CSplign::SSegment::GetAcceptor() const 
  1007. {
  1008.     const size_t adim = m_annot.size();
  1009.     return (adim > 3 && m_annot[2] == '<')? m_annot.c_str(): 0;
  1010. }
  1011. END_NCBI_SCOPE
  1012. /*
  1013.  * ===========================================================================
  1014.  * $Log: splign.cpp,v $
  1015.  * Revision 1000.0  2004/06/01 18:12:28  gouriano
  1016.  * PRODUCTION: IMPORTED [GCC34_MSVC7] Dev-tree R1.12
  1017.  *
  1018.  * Revision 1.12  2004/05/24 16:13:57  gorelenk
  1019.  * Added PCH ncbi_pch.hpp
  1020.  *
  1021.  * Revision 1.11  2004/05/19 13:37:48  kapustin
  1022.  * Remove test dumping code
  1023.  *
  1024.  * Revision 1.10  2004/05/18 21:43:40  kapustin
  1025.  * Code cleanup
  1026.  *
  1027.  * Revision 1.9  2004/05/04 15:23:45  ucko
  1028.  * Split splign code out of xalgoalign into new xalgosplign.
  1029.  *
  1030.  * Revision 1.8  2004/05/03 15:22:18  johnson
  1031.  * added typedefs for public stl types
  1032.  *
  1033.  * Revision 1.7  2004/04/30 15:00:47  kapustin
  1034.  * Support ASN formatting
  1035.  *
  1036.  * Revision 1.6  2004/04/26 15:38:45  kapustin
  1037.  * Add model_id as a CSplign member
  1038.  *
  1039.  * Revision 1.5  2004/04/23 18:43:47  ucko
  1040.  * <cmath> -> <math.h>, since some older compilers (MIPSpro) lack the wrappers.
  1041.  *
  1042.  * Revision 1.4  2004/04/23 16:52:04  kapustin
  1043.  * Change the way we get donor address
  1044.  *
  1045.  * Revision 1.3  2004/04/23 14:37:44  kapustin
  1046.  * *** empty log message ***
  1047.  *
  1048.  * ===========================================================================
  1049.  */