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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: blast_psi_cxx.cpp,v $
  4.  * PRODUCTION Revision 1000.0  2004/06/01 18:13:18  gouriano
  5.  * PRODUCTION PRODUCTION: IMPORTED [GCC34_MSVC7] Dev-tree R1.3
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. static char const rcsid[] =
  10.     "$Id: blast_psi_cxx.cpp,v 1000.0 2004/06/01 18:13:18 gouriano Exp $";
  11. /* ===========================================================================
  12.  *
  13.  *                            PUBLIC DOMAIN NOTICE
  14.  *               National Center for Biotechnology Information
  15.  *
  16.  *  This software/database is a "United States Government Work" under the
  17.  *  terms of the United States Copyright Act.  It was written as part of
  18.  *  the author's official duties as a United States Government employee and
  19.  *  thus cannot be copyrighted.  This software/database is freely available
  20.  *  to the public for use. The National Library of Medicine and the U.S.
  21.  *  Government have not placed any restriction on its use or reproduction.
  22.  *
  23.  *  Although all reasonable efforts have been taken to ensure the accuracy
  24.  *  and reliability of the software and data, the NLM and the U.S.
  25.  *  Government do not and cannot warrant the performance or results that
  26.  *  may be obtained by using this software or data. The NLM and the U.S.
  27.  *  Government disclaim all warranties, express or implied, including
  28.  *  warranties of performance, merchantability or fitness for any particular
  29.  *  purpose.
  30.  *
  31.  *  Please cite the author in any work or product based on this material.
  32.  *
  33.  * ===========================================================================
  34.  *
  35.  * Author:  Christiam Camacho
  36.  *
  37.  */
  38. /** @file blast_psi_cxx.cpp
  39.  * Implementation of the C++ API for the PSI-BLAST PSSM generation engine.
  40.  */
  41. #include <ncbi_pch.hpp>
  42. #include <algo/blast/api/blast_psi.hpp>
  43. #include <algo/blast/api/blast_exception.hpp>
  44. #include <corelib/ncbi_limits.hpp>
  45. // Object includes
  46. #include <objects/seqalign/Seq_align.hpp>
  47. #include <objects/seqalign/Seq_align_set.hpp>
  48. #include <objects/seqalign/Dense_seg.hpp>
  49. #include <objects/seqalign/Score.hpp>
  50. #include <objects/general/Object_id.hpp>
  51. #include <objects/seqloc/Seq_loc.hpp>
  52. #include <objects/seqloc/Seq_interval.hpp>
  53. // Object manager includes
  54. #include <objmgr/scope.hpp>
  55. #include <objmgr/seq_vector.hpp>
  56. #include <objects/seq/Seq_data.hpp>
  57. // Core includes
  58. #include <algo/blast/core/blast_options.h>
  59. #include <algo/blast/core/blast_encoding.h>
  60. #include <serial/serial.hpp>
  61. #include <serial/objostr.hpp>
  62. #include <sstream>
  63. #include "../core/blast_psi_priv.h"
  64. BEGIN_NCBI_SCOPE
  65. USING_SCOPE(objects);
  66. BEGIN_SCOPE(blast)
  67. //////////////////////////////////////////////////////////////////////////////
  68. // Static function prototypes
  69. static double 
  70. s_GetEvalue(const CScore& score);
  71. static Uint1* 
  72. s_ExtractSequenceFromSeqVector(CSeqVector& sv);
  73. static double
  74. s_GetLowestEvalue(const CDense_seg::TScores& scores);
  75. // Debugging functions
  76. static void 
  77. s_DBG_printSequence(const Uint1* seq, TSeqPos len, ostream& out, 
  78.                     bool show_markers = true, TSeqPos chars_per_line = 80);
  79. // End static function prototypes
  80. //////////////////////////////////////////////////////////////////////////////
  81. CScoreMatrixBuilder::CScoreMatrixBuilder(const Uint1* query,
  82.                                          TSeqPos query_sz,
  83.                                          CRef<CSeq_align_set> sset,
  84.                                          CRef<CScope> scope,
  85.                                          const PSIBlastOptions& opts)
  86. {
  87.     if (!query) {
  88.         NCBI_THROW(CBlastException, eBadParameter, "NULL query");
  89.     }
  90.     if (!sset || sset->Get().front()->GetDim() != 2) {
  91.         NCBI_THROW(CBlastException, eNotSupported, 
  92.                    "Only 2-dimensional alignments are supported");
  93.     }
  94.     m_Scope.Reset(scope);
  95.     m_SeqAlignSet.Reset(sset);
  96.     m_Opts = const_cast<PSIBlastOptions&>(opts);
  97.     m_PssmDimensions.query_sz = query_sz;
  98.     m_PssmDimensions.num_seqs = sset->Get().size();
  99.     m_AlignmentData.reset(PSIAlignmentDataNew(query, &m_PssmDimensions));
  100. }
  101. void
  102. CScoreMatrixBuilder::Run()
  103. {
  104.     // this method should just extract information from Seq-align set and
  105.     // populate alignment data structure and delegate everything else to core
  106.     // PSSM library
  107.     SelectSequencesForProcessing();
  108.     ExtractAlignmentData();
  109.     // @todo Will need a function to populate the score block for psiblast
  110.     // add a new program type psiblast
  111.     //PsiMatrix* retval = PSICreatePSSM(m_AlignmentData.get(),
  112.                                       //&m_Opts, sbp, NULL);
  113.     // @todo populate Score-mat ASN.1 structure with retval and sbp contents
  114.     
  115. }
  116. // Selects those sequences which have an evalue lower than the inclusion
  117. // threshold in PsiInfo structure
  118. void
  119. CScoreMatrixBuilder::x_SelectByEvalue()
  120. {
  121.     TSeqPos seq_index = 0;
  122.     m_AlignmentData->use_sequences[seq_index++] = true; // always use query
  123.     // For each discontinuous Seq-align corresponding to each query-subj pair
  124.     ITERATE(CSeq_align_set::Tdata, i, m_SeqAlignSet->Get()) {
  125.         ASSERT((*i)->GetSegs().IsDisc());
  126.         // For each HSP of this query-subj pair
  127.         ITERATE(CSeq_align::C_Segs::TDisc::Tdata, hsp_itr,
  128.                 (*i)->GetSegs().GetDisc().Get()) {
  129.             
  130.             // Look for HSP with score less than inclusion_ethresh
  131.             double e = s_GetLowestEvalue((*hsp_itr)->GetScore());
  132.             if (e < m_Opts.inclusion_ethresh) {
  133.                 m_AlignmentData->use_sequences[seq_index] = true;
  134.                 break;
  135.             }
  136.         }
  137.         seq_index++;
  138.     }
  139.     ASSERT(seq_index == GetNumAlignedSequences()+1);
  140. }
  141. void
  142. CScoreMatrixBuilder::x_SelectBySeqId(const vector< CRef<CSeq_id> >& /*ids*/)
  143. {
  144.     NCBI_THROW(CBlastException, eNotSupported, "select by id not implemented");
  145. }
  146. // Finds sequences in alignment that warrant further processing. The criteria
  147. // to determine this includes:
  148. // 1) Include those that have evalues that are lower than the inclusion evalue 
  149. //    threshold
  150. // 2) Could use some functor object if more criteria are needed
  151. void
  152. CScoreMatrixBuilder::SelectSequencesForProcessing()
  153. {
  154.     // Reset the use_sequences array sequence vector
  155.     std::fill_n(m_AlignmentData->use_sequences, GetNumAlignedSequences() + 1,
  156.                 false);
  157.     x_SelectByEvalue();
  158. }
  159. void
  160. CScoreMatrixBuilder::ExtractAlignmentData()
  161. {
  162.     // Query sequence already processed
  163.     TSeqPos seq_index = 1;  
  164.     ITERATE(list< CRef<CSeq_align> >, itr, m_SeqAlignSet->Get()) {
  165.         if ( !m_AlignmentData->use_sequences[seq_index] ) {
  166.             seq_index++;
  167.             continue;
  168.         }
  169.         const list< CRef<CSeq_align> >& hsp_list = 
  170.             (*itr)->GetSegs().GetDisc().Get();
  171.         list< CRef<CSeq_align> >::const_iterator hsp;
  172.         // HSPs with the same query-subject pair
  173.         for (hsp = hsp_list.begin(); hsp != hsp_list.end(); ++hsp) {
  174.             // Note: Std-seg can be converted to Denseg, will need conversion
  175.             // from Dendiag to Denseg too
  176.             if ( !(*hsp)->GetSegs().IsDenseg() ) {
  177.                 NCBI_THROW(CBlastException, eNotSupported, 
  178.                            "Segment type not supported");
  179.             }
  180.             double evalue = s_GetLowestEvalue((*hsp)->GetScore());
  181.             // this could be refactored to support other segment types, will
  182.             // need to pass portion of subj. sequence and evalue
  183.             x_ProcessDenseg((*hsp)->GetSegs().GetDenseg(), seq_index, evalue);
  184.         }
  185.         seq_index++;
  186.     }
  187.     ASSERT(seq_index == GetNumAlignedSequences()+1);
  188. }
  189. /// Iterates over Dense-seg for a given HSP and extracts alignment information 
  190. /// to PsiAlignmentData structure. 
  191. void
  192. CScoreMatrixBuilder::x_ProcessDenseg(const CDense_seg& denseg, 
  193.                                      TSeqPos seq_index, double e_value)
  194. {
  195.     ASSERT(denseg.GetDim() == 2);
  196.     const Uint1 GAP = AMINOACID_TO_NCBISTDAA[(Uint1)'-'];
  197.     const vector<TSignedSeqPos>& starts = denseg.GetStarts();
  198.     const vector<TSeqPos>& lengths = denseg.GetLens();
  199.     TSeqPos query_index = 0;        // index into starts vector
  200.     TSeqPos subj_index = 1;         // index into starts vector
  201.     TSeqPos subj_seq_idx = 0;       // index into subject sequence buffer
  202.     // Get the portion of the subject sequence corresponding to this Dense-seg
  203.     TSeqPair seq = x_GetSubjectSequence(denseg, *m_Scope);
  204.     // Iterate over all segments
  205.     for (int segmt_idx = 0; segmt_idx < denseg.GetNumseg(); segmt_idx++) {
  206.         TSeqPos query_offset = starts[query_index];
  207.         TSeqPos subject_offset = starts[subj_index];
  208.         // advance the query and subject indices for next iteration
  209.         query_index += denseg.GetDim();
  210.         subj_index += denseg.GetDim();
  211.         if (query_offset == GAP_IN_ALIGNMENT) {
  212.             // gap in query, just skip residues on subject sequence
  213.             subj_seq_idx += lengths[segmt_idx];
  214.             continue;
  215.         } else if (subject_offset == GAP_IN_ALIGNMENT) {
  216.             // gap in subject, initialize appropriately
  217.             for (TSeqPos i = 0; i < lengths[segmt_idx]; i++) {
  218.                 PsiDesc& pos_desc =
  219.                     m_AlignmentData->desc_matrix[seq_index][query_offset++];
  220.                 pos_desc.letter = GAP;
  221.                 pos_desc.used = true;
  222.                 pos_desc.e_value = kDefaultEvalueForPosition;
  223.             }
  224.         } else {
  225.             // Aligned segments without any gaps
  226.             for (TSeqPos i = 0; i < lengths[segmt_idx]; i++) {
  227.                 PsiDesc& pos_desc =
  228.                     m_AlignmentData->desc_matrix[seq_index][query_offset++];
  229.                 pos_desc.letter = seq.first.get()[subj_seq_idx++];
  230.                 pos_desc.used = true;
  231.                 pos_desc.e_value = e_value;
  232.             }
  233.         }
  234.     }
  235. }
  236. // Should be called once per HSP
  237. // @todo merge with blast_objmgr_tools next week
  238. CScoreMatrixBuilder::TSeqPair 
  239. CScoreMatrixBuilder::x_GetSubjectSequence(const CDense_seg& ds, 
  240.                                           CScope& scope) 
  241. {
  242.     ASSERT(ds.GetDim() == 2);
  243.     Uint1* retval = NULL;
  244.     TSeqPos subjlen = 0;                    // length of the return value
  245.     TSeqPos subj_start = kInvalidSeqPos;    // start of subject alignment
  246.     bool subj_start_found = false;
  247.     TSeqPos subj_index = 1;                 // index into starts vector
  248.     const vector<TSignedSeqPos>& starts = ds.GetStarts();
  249.     const vector<TSeqPos>& lengths = ds.GetLens();
  250.     for (int i = 0; i < ds.GetNumseg(); i++) {
  251.         if (starts[subj_index] != (TSignedSeqPos)GAP_IN_ALIGNMENT) {
  252.             if ( !subj_start_found ) {
  253.                 subj_start = starts[subj_index];
  254.                 subj_start_found = true;
  255.             }
  256.             subjlen += lengths[i];
  257.         }
  258.         subj_index += ds.GetDim();
  259.     }
  260.     ASSERT(subj_start_found);
  261.     CSeq_loc seqloc;
  262.     seqloc.SetInt().SetFrom(subj_start);
  263.     seqloc.SetInt().SetTo(subj_start+subjlen-1);
  264.     seqloc.SetInt().SetStrand(eNa_strand_unknown);
  265.     seqloc.SetInt().SetId(const_cast<CSeq_id&>(*ds.GetIds().back()));
  266.     CBioseq_Handle bh = scope.GetBioseqHandle(seqloc);
  267.     CSeqVector sv = bh.GetSequenceView(seqloc,
  268.                                        CBioseq_Handle::eViewConstructed,
  269.                                        CBioseq_Handle::eCoding_Ncbi);
  270.     sv.SetCoding(CSeq_data::e_Ncbistdaa);
  271.     retval = s_ExtractSequenceFromSeqVector(sv);
  272.     return make_pair(AutoPtr<Uint1, ArrayDeleter<Uint1> >(retval), subjlen);
  273. }
  274. //////////////////////////////////////////////////////////////////////////////
  275. // Static function definitions
  276. // Returns the evalue from this score object
  277. static double
  278. s_GetEvalue(const CScore& score)
  279. {
  280.     string score_type = score.GetId().GetStr();
  281.     if (score.GetValue().IsReal() && 
  282.        (score_type == "e_value" || score_type == "sum_e")) {
  283.         return score.GetValue().GetReal();
  284.     }
  285.     return numeric_limits<double>::max();
  286. }
  287. static Uint1* 
  288. s_ExtractSequenceFromSeqVector(CSeqVector& sv) 
  289. {
  290.     Uint1* retval = NULL;
  291.     try {
  292.         retval = new Uint1[sv.size()];
  293.     } catch (const std::bad_alloc&) {
  294.         ostringstream os;
  295.         os << sv.size();
  296.         string msg = string("Could not allocate ") + os.str() + " bytes";
  297.         NCBI_THROW(CBlastException, eOutOfMemory, msg);
  298.     }
  299.     for (TSeqPos i = 0; i < sv.size(); i++) {
  300.         retval[i] = sv[i];
  301.     }
  302.     return retval;
  303. }
  304. static double 
  305. s_GetLowestEvalue(const CDense_seg::TScores& scores)
  306. {
  307.     double retval = numeric_limits<double>::max();
  308.     double tmp;
  309.     ITERATE(CDense_seg::TScores, i, scores) {
  310.         if ( (tmp = s_GetEvalue(**i)) < retval) {
  311.             retval = tmp;
  312.         }
  313.     }
  314.     return retval;
  315. }
  316. //////////////////////////////////////////////////////////////////////////////
  317. // Debugging code
  318. // Pretty print sequence
  319. static void 
  320. s_DBG_printSequence(const Uint1* seq, TSeqPos len, ostream& out,
  321.                     bool show_markers, TSeqPos chars_per_line)
  322. {
  323.     TSeqPos nlines = len/chars_per_line;
  324.     for (TSeqPos line = 0; line < nlines + 1; line++) {
  325.         // print chars_per_line residues/bases
  326.         for (TSeqPos i = (chars_per_line*line); 
  327.              i < chars_per_line*(line+1) && (i < len); i++) {
  328.             out << AMINOACID_TO_NCBISTDAA[seq[i]];
  329.         }
  330.         out << endl;
  331.         if ( !show_markers )
  332.             continue;
  333.         // print the residue/base markers
  334.         for (TSeqPos i = (chars_per_line*line); 
  335.              i < chars_per_line*(line+1) && (i < len); i++) {
  336.             if (i == 0 || ((i%10) == 0)) {
  337.                 out << i;
  338.                 ostringstream os;
  339.                 os << i;
  340.                 TSeqPos marker_length = os.str().size();
  341.                 i += (marker_length-1);
  342.             } else {
  343.                 out << " ";
  344.             }
  345.         }
  346.         out << endl;
  347.     }
  348. }
  349. std::string
  350. PsiAlignmentData2String(const PsiAlignmentData* alignment)
  351. {
  352.     if ( !alignment ) {
  353.         return "";
  354.     }
  355.     stringstream ss;
  356.     for (TSeqPos i = 0; i < alignment->dimensions->num_seqs+1; i++) {
  357.         ss << "Seq " << setw(3) << i;
  358.         if ( !alignment->use_sequences[i] ) {
  359.             ss << " NOT USED";
  360.         }
  361.         ss << endl;
  362.         for (TSeqPos j = 0; j < alignment->dimensions->query_sz; j++) {
  363.             if ( !alignment->use_sequences[i] ) {
  364.                 continue;
  365.             }
  366.             ss << setw(3) << j << " {" 
  367.                << AMINOACID_TO_NCBISTDAA[alignment->desc_matrix[i][j].letter]
  368.                << ",";
  369.             if (alignment->desc_matrix[i][j].used)
  370.                 ss << "used";
  371.             else
  372.                 ss << "unused";
  373.             ss << "," << alignment->desc_matrix[i][j].e_value
  374.                << "," << alignment->desc_matrix[i][j].extents.left
  375.                << "," << alignment->desc_matrix[i][j].extents.right
  376.                << "}" << endl;
  377.         }
  378.         ss << "*****************************************************" << endl;
  379.     }
  380.     ss << endl;
  381.     // Print the number of matching sequences per column
  382.     ss << "Matching sequences (alignment->match_seqs)" << endl;
  383.     for (TSeqPos i = 0; i < alignment->dimensions->query_sz; i++) { 
  384.         ss << alignment->match_seqs[i] << " "; 
  385.     }
  386.     ss << endl;
  387.     ss << "*****************************************************" << endl;
  388.     // Print the number of distinct residues per position
  389.     ss << "Residue counts in the matrix " << endl;
  390.     for (TSeqPos i = 0; i < alignment->dimensions->query_sz; i++) {
  391.         for (TSeqPos j = 0; j < PSI_ALPHABET_SIZE; j++) {
  392.             ss << alignment->res_counts[i][j] << " ";
  393.         }
  394.     }
  395.     return ss.str();
  396. }
  397. ostream&
  398. operator<<(ostream& out, const CScoreMatrixBuilder& smb)
  399. {
  400.     TSeqPos query_sz = smb.m_AlignmentData->dimensions->query_sz;
  401.     // Print query sequence in IUPAC
  402.     out << "QUERY:n";
  403.     s_DBG_printSequence(smb.m_AlignmentData->query, query_sz, out);
  404.     // Print description of alignment and associated data
  405.     out << PsiAlignmentData2String(smb.m_AlignmentData.get());
  406.     out << endl;
  407.     return out;
  408. }
  409. // End debugging code
  410. //////////////////////////////////////////////////////////////////////////////
  411. END_SCOPE(blast)
  412. END_NCBI_SCOPE
  413. /*
  414. * ===========================================================================
  415. *
  416. * $Log: blast_psi_cxx.cpp,v $
  417. * Revision 1000.0  2004/06/01 18:13:18  gouriano
  418. * PRODUCTION: IMPORTED [GCC34_MSVC7] Dev-tree R1.3
  419. *
  420. * Revision 1.3  2004/05/28 17:42:02  camacho
  421. * Fix compiler warning
  422. *
  423. * Revision 1.2  2004/05/28 17:15:43  camacho
  424. * Fix NCBI {BEGIN,END}_SCOPE macro usage, remove warning
  425. *
  426. * Revision 1.1  2004/05/28 16:41:39  camacho
  427. * Initial revision
  428. *
  429. *
  430. * ===========================================================================
  431. */