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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: splign_hit.cpp,v $
  4.  * PRODUCTION Revision 1000.0  2004/06/01 18:12:48  gouriano
  5.  * PRODUCTION PRODUCTION: IMPORTED [GCC34_MSVC7] Dev-tree R1.8
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: splign_hit.cpp,v 1000.0 2004/06/01 18:12:48 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. *   Temporary code - will be part of the hit filtering library
  38. *
  39. */
  40. #include <ncbi_pch.hpp>
  41. #include <algo/align/splign/splign_hit.hpp>
  42. #include <algo/align/align_exception.hpp>
  43. #include <corelib/ncbistre.hpp>
  44. #include <objects/seqloc/Seq_id.hpp>
  45. #include <objects/seqalign/Seq_align.hpp>
  46. #include <objects/seqalign/Dense_seg.hpp>
  47. #include <algorithm>
  48. #include <numeric>
  49. #include <math.h>
  50. BEGIN_NCBI_SCOPE
  51. USING_SCOPE(objects);
  52. CHit::CHit()
  53. {
  54.     x_InitDefaults();
  55. }
  56. void CHit::x_InitDefaults()
  57. {
  58.     m_Idnty = m_Score = m_Value = m_MM = m_Gaps = 0;
  59.     m_GroupID = -1;
  60.     m_MaxDistClustID = -1;
  61.     m_an[0] = m_an[1] = m_an[2] = m_an[3] = 0;
  62.     m_ai[0] = m_ai[1] = m_ai[2] = m_ai[3] = 0;
  63. }
  64. // constructs new hit by merging two existing
  65. CHit::CHit(const CHit& a, const CHit& b)
  66. {
  67.     x_InitDefaults();
  68.     bool bsa = a.IsStraight();
  69.     bool bsb = b.IsStraight();
  70.     bool bBothStraight = (bsa && bsb);
  71.     bool bBothInverse = (!bsa && !bsb);
  72.     if(!bBothStraight && !bBothInverse) {
  73.         NCBI_THROW( CAlgoAlignException,
  74.                     eInternal,
  75.                     "Cannot merge hits with diferent strands");
  76.     }
  77.   
  78.     m_an[0] = min(a.m_an[0],min(a.m_an[1],min(b.m_an[0],b.m_an[1])));
  79.     m_an[1] = max(a.m_an[0],max(a.m_an[1],max(b.m_an[0],b.m_an[1])));
  80.     m_an[2] = min(a.m_an[2],min(a.m_an[3],min(b.m_an[2],b.m_an[3])));
  81.     m_an[3] = max(a.m_an[2],max(a.m_an[3],max(b.m_an[2],b.m_an[3])));
  82.     
  83.     // make size the same
  84.     int n1 = m_an[1]-m_an[0];
  85.     int n2 = m_an[3]-m_an[2];
  86.     if(n1 != n2)
  87.     {
  88.         int n = min(n1,n2);
  89.         m_an[1] = m_an[0] + n;
  90.         m_an[3] = m_an[2] + n;
  91.     }
  92.     if(bBothInverse)
  93.     {
  94.         int k = m_an[2];
  95.         m_an[2] = m_an[3];
  96.         m_an[3] = k;
  97.     }
  98.     
  99.     // adjust parameters
  100.     m_Query = a.m_Query;
  101.     m_Subj = a.m_Subj;
  102.     m_GroupID = a.m_GroupID;
  103.     m_Score = a.m_Score + b.m_Score;
  104.     m_anLength[0] = abs(m_an[1]-m_an[0]) + 1;
  105.     m_anLength[1] = abs(m_an[3]-m_an[2]) + 1;
  106.     m_Length = max(m_anLength[0], m_anLength[1]);
  107.     m_Value = (double(a.m_Length)*a.m_Value + double(b.m_Length)*b.m_Value) /
  108.               (a.m_Length + b.m_Length);
  109.     m_Idnty = (a.m_Length*a.m_Idnty + b.m_Length*b.m_Idnty) / 
  110.              (a.m_Length + b.m_Length);
  111.     
  112.     m_Gaps = a.m_Gaps + b.m_Gaps;
  113.     m_MM = a.m_MM + b.m_MM;
  114.     
  115.     SetEnvelop();
  116. }
  117. CHit::CHit(const string& strTemplate)
  118. {
  119.     x_InitDefaults();
  120.     
  121.     int nCount = 0;
  122.     string::const_iterator ii = strTemplate.begin(),
  123.         ii_end = strTemplate.end(), jj = ii;
  124.     while( jj < ii_end ) {
  125.         ii = find(jj, ii_end, 't');
  126.         string s (jj, ii);
  127.         if(s == "-") {
  128.             s = "-1";
  129.         }
  130.         CNcbiIstrstream ss (s.c_str());
  131.         switch(nCount++)   {
  132.         
  133.         case 0:    m_Query = s;  break;
  134.         case 1:    m_Subj = s;   break;
  135.         case 2:    ss >> m_Idnty;  break;
  136.         case 3:    ss >> m_Length; break;
  137.         case 4:    ss >> m_MM;     break;
  138.         case 5:    ss >> m_Gaps;   break;
  139.         case 6:    ss >> m_an[0];   break;
  140.         case 7:    ss >> m_an[1];   break;
  141.         case 8:    ss >> m_an[2];   break;
  142.         case 9:    ss >> m_an[3];   break;
  143.         case 10:   ss >> m_Value;  break;
  144.         case 11:   ss >> m_Score;  break;
  145.         default: {
  146.             NCBI_THROW( CAlgoAlignException,
  147.                         eFormat,
  148.                         "Too many fields while parsing hit line.");
  149.             }
  150.         }
  151.         jj = ii + 1;
  152.     }
  153.     if (nCount < 12) {
  154.       NCBI_THROW( CAlgoAlignException,
  155.                   eFormat,
  156.                   "One or more fields missing.");
  157.     }
  158.     
  159.     // u-turn the hit if necessary
  160.     if(m_an[0] > m_an[1] && m_an[2] > m_an[3]) {
  161.         int n = m_an[0]; m_an[0] = m_an[1]; m_an[1] = n;
  162.         n = m_an[2]; m_an[2] = m_an[3]; m_an[3] = n;
  163.     }
  164.     
  165.     SetEnvelop();
  166.     m_anLength[0] = m_ai[1] - m_ai[0] + 1;
  167.     m_anLength[1] = m_ai[3] - m_ai[2] + 1;
  168. }
  169. CHit::CHit(const CSeq_align& sa)
  170. {
  171.     x_InitDefaults();
  172.     if (sa.CheckNumRows() != 2) {
  173.         NCBI_THROW(CAlgoAlignException, eBadParameter,
  174.                    "CHit::CHit passed seq-align of dimension != 2");
  175.     }
  176.     m_Query = sa.GetSeq_id(0).GetSeqIdString(true);
  177.     m_Subj  = sa.GetSeq_id(1).GetSeqIdString(true);
  178.     m_an[0] = sa.GetSeqStart(0) + 1;
  179.     m_an[1] = sa.GetSeqStop(0) + 1;
  180.     m_an[2] = sa.GetSeqStart(1) + 1;
  181.     m_an[3] = sa.GetSeqStop(1) + 1;
  182.     if (!sa.GetSegs().IsDenseg()) {
  183.         NCBI_THROW(CAlgoAlignException, eBadParameter,
  184.                    "CHit::CHit passed a seq-align that isn't a dense-seg.");
  185.     }
  186.     const CDense_seg &ds = sa.GetSegs().GetDenseg();
  187.     const CDense_seg::TStrands& strands = ds.GetStrands();
  188.     const CDense_seg::TLens& lens = ds.GetLens();
  189.     bool strand_query;
  190.     if(strands[0] == eNa_strand_plus) {
  191.         strand_query = true;
  192.     }
  193.     else if(strands[0] == eNa_strand_minus) {
  194.         strand_query = false;
  195.     }
  196.     else {
  197.         NCBI_THROW(CAlgoAlignException, eBadParameter,
  198.                    "Unexpected query strand reported to CHit::CHit(CSeq_align).");
  199.     }
  200.     bool strand_subj;
  201.     if( strands[1] == eNa_strand_plus) {
  202.         strand_subj = true;
  203.     }
  204.     else if(strands[1] == eNa_strand_minus) {
  205.         strand_subj = false;
  206.     }
  207.     else {
  208.         NCBI_THROW(CAlgoAlignException, eBadParameter,
  209.                    "Unexpected subject strand reported to CHit::CHit(CSeq_align).");
  210.     }
  211.     if (strand_query != strand_subj) {
  212.         swap(m_an[2], m_an[3]);
  213.     }
  214.     sa.GetNamedScore("num_ident", m_Idnty);
  215.     sa.GetNamedScore("bit_score", m_Score);
  216.     sa.GetNamedScore("sum_e", m_Value);
  217.     SetEnvelop();    
  218.     m_anLength[0] = m_ai[1] - m_ai[0] + 1;
  219.     m_anLength[1] = m_ai[3] - m_ai[2] + 1;
  220.     m_Length = accumulate(lens.begin(), lens.end(), 0);
  221.     m_Idnty = 100 * m_Idnty / m_Length; //convert # identities to % identity
  222. }
  223. bool CHit::IsConsistent() const
  224. {
  225.     return m_ai[0] <= m_ai[1] && m_ai[2] <= m_ai[3];
  226. }
  227. void CHit::SetEnvelop()
  228. {
  229.     m_ai[0] = min(m_an[0],m_an[1]);    m_ai[1] = max(m_an[0],m_an[1]);
  230.     m_ai[2] = min(m_an[2],m_an[3]);    m_ai[3] = max(m_an[2],m_an[3]);
  231. }
  232. void CHit::Move(unsigned char i, int pos_new, bool prot2nucl)
  233. {
  234.     bool strand_plus = IsStraight();
  235.     // for minus strand, flip the hit if necessary
  236.     if(!strand_plus && m_an[0] > m_an[1]) {
  237.         int n = m_an[0]; m_an[0] = m_an[1]; m_an[1] = n;
  238.         n = m_an[2]; m_an[2] = m_an[3]; m_an[3] = n;
  239.     }
  240.     
  241.     // i --> m_ai, n --> m_an
  242.     unsigned char n = 0;
  243.     switch(i) {
  244.         case 0: n = 0; break; 
  245.         case 1: n = 1; break; 
  246.         case 2: n = strand_plus? 2: 3; break; 
  247.         case 3: n = strand_plus? 3: 2; break; 
  248.     }
  249.     
  250.     int shift = pos_new - m_an[n], shiftQ, shiftS;
  251.     if(shift == 0) return;
  252.     // figure out shifts on query and subject
  253.     if(prot2nucl) {
  254.         if(n < 2) {
  255.             shiftQ = shift;
  256.             shiftS = 3*shiftQ;
  257.         }
  258.         else {
  259.             if(shift % 3) {
  260.                 shiftQ = (shift > 0)? (shift/3 + 1): (shift/3 - 1);
  261.                 shiftS = 3*shiftQ;
  262.             }
  263.             else {
  264.                 shiftQ = shift / 3;
  265.                 shiftS = shift;
  266.             }
  267.         }
  268.     }
  269.     else {
  270.         shiftQ = shiftS = shift;
  271.     }
  272.     // make sure hit ratio doesn't change (todo: prot2nucl)
  273.     if(!prot2nucl) {
  274.         bool plus = shift >= 0;
  275.         unsigned shift_abs = plus? shift: -shift;
  276.         if(n < 2) {
  277.             double D = double(shift_abs) / (m_ai[1] - m_ai[0] + 1);
  278.             shiftQ = shift;
  279.             shiftS = int(ceil(D*(m_ai[3] - m_ai[2] + 1)));
  280.             if(!plus) shiftS = -shiftS;
  281.         }
  282.         else {
  283.             double D = double(shift_abs) / (m_ai[3] - m_ai[2] + 1);
  284.             shiftS = shift;
  285.             shiftQ = int(ceil(D*(m_ai[1] - m_ai[0] + 1)));
  286.             if(!plus) shiftQ = -shiftQ;
  287.         }
  288.     }
  289.     if(strand_plus) {
  290.         m_an[n % 2] += shiftQ; m_an[n % 2 + 2] += shiftS;
  291.         m_ai[i % 2] += shiftQ; m_ai[i % 2 + 2] += shiftS;
  292.     }
  293.     else {
  294.         switch(i) {
  295.             case 0: m_an[0] = m_ai[0] += shiftQ;
  296.                     m_an[2] = m_ai[3] -= shiftS;
  297.                     break;
  298.             case 1: m_an[1] = m_ai[1] += shiftQ;
  299.                     m_an[3] = m_ai[2] -= shiftS;
  300.                     break;
  301.             case 2: m_an[3] = m_ai[2] += shiftS;
  302.                     m_an[1] = m_ai[1] -= shiftQ;
  303.                     break;
  304.             case 3: m_an[2] = m_ai[3] += shiftS;
  305.                     m_an[0] = m_ai[0] -= shiftQ;
  306.                     break;
  307.         }
  308.     }
  309. }
  310. bool CHit::Inside(const CHit& b) const
  311. {
  312.     bool b0 = b.m_ai[0] <= m_ai[0] && m_ai[1] <= b.m_ai[1];
  313.     if(!b0) return false;
  314.     bool b1 = b.m_ai[2] <= m_ai[2] && m_ai[3] <= b.m_ai[3];
  315.     return b1;
  316. }
  317. // This function must be called once after a series of Move() calls.
  318. // Changes are made based on previous values of the parameters.
  319. void CHit::UpdateAttributes()
  320. {
  321.     int nLength0 = m_Length;
  322.     m_anLength[0] = m_ai[1] - m_ai[0] + 1;
  323.     m_anLength[1] = m_ai[3] - m_ai[2] + 1;
  324.     m_Length = max(m_anLength[0], m_anLength[1]);
  325.     double dk = nLength0? double(m_Length) / nLength0: 1.0;
  326.     m_Score *= dk;
  327.     m_Gaps = int(m_Gaps*dk);
  328.     m_MM = int(m_MM*dk);
  329.     // do not change m_Value, m_Idnty
  330. }
  331. ostream& operator << (ostream& os, const CHit& hit) {
  332.     const int nLen = min(hit.m_anLength[0], hit.m_anLength[1]);
  333.     return os
  334.        << hit.m_Query << 't' << hit.m_Subj << 't'
  335.        << hit.m_Idnty   << 't' << nLen          << 't'
  336.        << hit.m_MM      << 't' << hit.m_Gaps   << 't'
  337.        << hit.m_an[0]    << 't' << hit.m_an[1]   << 't'
  338.        << hit.m_an[2]    << 't' << hit.m_an[3]   << 't'
  339.        << hit.m_Value   << 't' << hit.m_Score;
  340. }
  341. bool hit_same_order::operator() (const CHit& hm, const CHit& h0) const
  342. {
  343.     bool bStraightM = hm.IsStraight();
  344.     bool bStraight0 = h0.IsStraight();
  345.     bool b0 = bStraightM && bStraight0;
  346.     bool b1 = !bStraightM && !bStraight0;
  347.     if(b0 || b1)
  348.     {
  349.         int vm [4]; copy(hm.m_an, hm.m_an + 4, vm);
  350.         int v0 [4]; copy(h0.m_an, h0.m_an + 4, v0);
  351.         if(b1)
  352.         {
  353.                 // we need to change direction for one axis
  354.             double dmin1 = 1e38, dmax1 = -dmin1;
  355.             int i = 0;
  356.             for(i=2; i<4; i++)
  357.             {
  358.                 if(dmin1 > vm[i]) dmin1 = vm[i];
  359.                    if(dmin1 > v0[i]) dmin1 = v0[i];
  360.                 if(dmax1 < vm[i]) dmax1 = vm[i];
  361.                    if(dmax1 < v0[i]) dmax1 = v0[i];
  362.             }
  363.             for(i=2; i<4; i++)
  364.             {
  365.                 vm[i] = int(-vm[i] + dmin1 + dmax1);
  366.                 v0[i] = int(-v0[i] + dmin1 + dmax1);
  367.             }
  368.                 // now u-turn hits if necessary
  369.             if(vm[0] > vm[1] && vm[2] > vm[3])
  370.             {
  371.                 int n = vm[0]; vm[0] = vm[1]; vm[1] = n;
  372.                 n = vm[2]; vm[2] = vm[3]; vm[3] = n;
  373.             }
  374.             if(v0[0] > v0[1] && v0[2] > v0[3])
  375.             {
  376.                 int n = v0[0]; v0[0] = v0[1]; v0[1] = n;
  377.                 n = v0[2]; v0[2] = v0[3]; v0[3] = n;
  378.             }
  379.         }
  380.         double dx = .1*0.5*(abs(vm[1] - vm[0]) + abs(v0[1] - v0[0]));
  381.         if(vm[0] > v0[1] - dx) // left bottom
  382.             return vm[2] > v0[3] - dx? true: false;
  383.         else
  384.         if(vm[2] > v0[3] - dx) // left top
  385.             return vm[0] > v0[1] - dx? true: false;
  386.         else
  387.         if(vm[1] < v0[0] + dx) // right bottom
  388.             return vm[3] < v0[2] + dx? true: false;
  389.         else
  390.         if(vm[3] < v0[2] + dx) // right top
  391.             return vm[1] < v0[0] + dx? true: false;
  392.         else return false;
  393.     }
  394.     else
  395.         return false;   // different strands and same order are incompatible
  396. }
  397. bool hit_not_same_order::operator()(const CHit& hm, const CHit& h0) const
  398. {
  399.     return !hit_same_order::operator() (hm,h0);
  400. }
  401. // Calculates distance btw. two hits on query or subject
  402. int CHit::GetHitDistance(const CHit& h1, const CHit& h2, int nWhere)
  403. {
  404.     int i0 = -1, i1 = -1;
  405.     switch(nWhere)
  406.     {
  407.         case 0: // query
  408.             i0 = 0; i1 = 1;
  409.             break;
  410.         case 1: // subject
  411.             i0 = 2; i1 = 3;
  412.             break;
  413.         default:
  414.             return -2; // wrong parameter
  415.     }
  416.     if(h1.m_ai[i1] < h2.m_ai[i0])  // no intersection
  417.         return h2.m_ai[i0] - h1.m_ai[i1];
  418.     else
  419.     if(h2.m_ai[i1] < h1.m_ai[i0])  // no intersection
  420.         return h1.m_ai[i0] - h2.m_ai[i1];
  421.     else // overlapping
  422.         return 0;
  423. }
  424. END_NCBI_SCOPE
  425. /*
  426. * ===========================================================================
  427. *
  428. * $Log: splign_hit.cpp,v $
  429. * Revision 1000.0  2004/06/01 18:12:48  gouriano
  430. * PRODUCTION: IMPORTED [GCC34_MSVC7] Dev-tree R1.8
  431. *
  432. * Revision 1.8  2004/05/24 16:13:57  gorelenk
  433. * Added PCH ncbi_pch.hpp
  434. *
  435. * Revision 1.7  2004/05/10 16:33:52  kapustin
  436. * Report unexpected strands in CHit(CSeq_align&). Calculate length and identity based on alignment data.
  437. *
  438. * Revision 1.6  2004/05/06 17:43:27  johnson
  439. * CHit(CSeq_align&) now indicates minus strand via swapping subject
  440. * coordinates (*not* query coordinates)
  441. *
  442. * Revision 1.5  2004/05/04 15:23:45  ucko
  443. * Split splign code out of xalgoalign into new xalgosplign.
  444. *
  445. * Revision 1.4  2004/05/03 15:23:08  johnson
  446. * Added CHit constructor that takes a CSeq_align
  447. *
  448. * Revision 1.3  2004/04/23 14:37:44  kapustin
  449. * *** empty log message ***
  450. *
  451. * ===========================================================================
  452. */