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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: cn3d_threader.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 18:28:21  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.43
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: cn3d_threader.cpp,v 1000.3 2004/06/01 18:28:21 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. * Authors:  Paul Thiessen
  35. *
  36. * File Description:
  37. *       class to isolate and run the threader
  38. *
  39. * ===========================================================================
  40. */
  41. #ifdef _MSC_VER
  42. #pragma warning(disable:4018)   // disable signed/unsigned mismatch warning in MSVC
  43. #endif
  44. #include <ncbi_pch.hpp>
  45. #include <corelib/ncbistd.hpp> // must come first to avoid NCBI type clashes
  46. #include <corelib/ncbistl.hpp>
  47. #include <memory>
  48. #include "block_multiple_alignment.hpp"
  49. #include "cn3d_threader.hpp"
  50. #include "sequence_set.hpp"
  51. #include "molecule.hpp"
  52. #include "structure_set.hpp"
  53. #include "residue.hpp"
  54. #include "coord_set.hpp"
  55. #include "atom_set.hpp"
  56. #include "cn3d_tools.hpp"
  57. #include "molecule_identifier.hpp"
  58. // C-toolkit stuff
  59. #include <objseq.h>
  60. #include <objalign.h>
  61. #include <thrdatd.h>
  62. #include <thrddecl.h>
  63. #include <cddutil.h>
  64. #include <ncbistr.h>
  65. USING_NCBI_SCOPE;
  66. BEGIN_SCOPE(Cn3D)
  67. // define to include debugging output (threader structures to files)
  68. //#define DEBUG_THREADER
  69. // always do debugging in Debug build mode
  70. #if (!defined(DEBUG_THREADER) && defined(_DEBUG))
  71. #define DEBUG_THREADER
  72. #endif
  73. // default threading options
  74. ThreaderOptions::ThreaderOptions(void) :
  75.     weightPSSM(0.5),
  76.     loopLengthMultiplier(1.5),
  77.     nRandomStarts(1),
  78.     nResultAlignments(1),
  79.     terminalResidueCutoff(-1),
  80.     mergeAfterEachSequence(true),
  81.     freezeIsolatedBlocks(true)
  82. {
  83. }
  84. ThreaderOptions globalThreaderOptions;
  85. // gives threader residue number for a character (-1 if non-standard aa)
  86. static int LookupThreaderResidueNumberFromCharacterAbbrev(char r)
  87. {
  88.     typedef map < char, int > Char2Int;
  89.     static Char2Int charMap;
  90.     if (charMap.size() == 0) {
  91.         for (int i=0; i<Threader::ThreaderResidues.size(); ++i)
  92.             charMap[Threader::ThreaderResidues[i]] = i;
  93.     }
  94.     Char2Int::const_iterator c = charMap.find(toupper(r));
  95.     return ((c != charMap.end()) ? c->second : -1);
  96. }
  97. const int Threader::SCALING_FACTOR = 1000000;
  98. const string Threader::ThreaderResidues = "ARNDCQEGHILKMFPSTWYV";
  99. Threader::Threader(void)
  100. {
  101. }
  102. Threader::~Threader(void)
  103. {
  104.     ContactMap::iterator c, ce = contacts.end();
  105.     for (c=contacts.begin(); c!=ce; ++c) FreeFldMtf(c->second);
  106. }
  107. Seq_Mtf * Threader::CreateSeqMtf(const BlockMultipleAlignment *multiple,
  108.     double weightPSSM, BLAST_KarlinBlkPtr karlinBlock)
  109. {
  110.     // special case for "PSSM" of single-row "alignment" - just use BLOSUM62 score
  111.     if (multiple->NRows() == 1) {
  112.         Seq_Mtf *seqMtf = NewSeqMtf(multiple->GetMaster()->Length(), ThreaderResidues.size());
  113.         for (int res=0; res<multiple->GetMaster()->Length(); ++res)
  114.             for (int aa=0; aa<ThreaderResidues.size(); ++aa)
  115.                 seqMtf->ww[res][aa] = ThrdRound(
  116.                     weightPSSM * SCALING_FACTOR *
  117.                         GetBLOSUM62Score(multiple->GetMaster()->sequenceString[res],
  118.                                          ThreaderResidues[aa]));
  119.         TRACEMSG("Created Seq_Mtf (PSSM) from BLOSUM62 scores");
  120.         return seqMtf;
  121.     }
  122.     // convert all sequences to Bioseqs
  123.     multiple->GetMaster()->parentSet->CreateAllBioseqs(multiple);
  124.     // create SeqAlign from this BlockMultipleAlignment
  125.     SeqAlignPtr seqAlign = multiple->CreateCSeqAlign();
  126. #ifdef DEBUG_THREADER
  127.     // dump for debugging
  128.     SeqAlignPtr saChain = seqAlign;
  129.     AsnIoPtr aip = AsnIoOpen("Seq-align.debug.txt", "w");
  130.     while (saChain) {
  131.         SeqAlignAsnWrite(saChain, aip, NULL);
  132.         saChain = saChain->next;
  133.     }
  134.     aip = AsnIoClose(aip);
  135. #endif
  136.     // "spread" unaligned residues between aligned blocks, for PSSM construction
  137.     CddDegapSeqAlign(seqAlign);
  138.     Seq_Mtf *seqMtf = NULL;
  139.     for (int i=11; i>=1; --i) {
  140.         // first try auto-determined pseudocount (-1); if fails, find higest <= 10 that works
  141.         int pseudocount = (i == 11) ? -1 : i;
  142.         seqMtf = CddDenDiagCposComp2KBP(
  143.             multiple->GetMaster()->parentSet->GetOrCreateBioseq(multiple->GetMaster()),
  144.             pseudocount,
  145.             seqAlign,
  146.             NULL,
  147.             NULL,
  148.             weightPSSM,
  149.             SCALING_FACTOR,
  150.             NULL,
  151.             karlinBlock
  152.         );
  153.         if (seqMtf)
  154.             break;
  155.         else
  156.             WARNINGMSG("Cannot use " << ((pseudocount == -1) ? "(empirical) " : "")
  157.                 << "pseudocount of " << pseudocount);
  158.     }
  159.     if (seqMtf)
  160.         TRACEMSG("created Seq_Mtf (PSSM)");
  161.     else
  162.         ERRORMSG("Cannot find any pseudocount that yields an acceptable PSSM!");
  163.     SeqAlignSetFree(seqAlign);
  164. return seqMtf;
  165. }
  166. Cor_Def * Threader::CreateCorDef(const BlockMultipleAlignment *multiple, double loopLengthMultiplier)
  167. {
  168.     static const int MIN_LOOP_MAX = 2;
  169.     static const int EXTENSION_MAX = 10;
  170.     BlockMultipleAlignment::UngappedAlignedBlockList alignedBlocks;
  171.     multiple->GetUngappedAlignedBlocks(&alignedBlocks);
  172.     Cor_Def *corDef = NewCorDef(alignedBlocks.size());
  173.     // zero loop constraints for tails
  174.     corDef->lll.llmn[0] = corDef->lll.llmn[alignedBlocks.size()] =
  175.     corDef->lll.llmx[0] = corDef->lll.llmx[alignedBlocks.size()] =
  176.     corDef->lll.lrfs[0] = corDef->lll.lrfs[alignedBlocks.size()] = 0;
  177.     // loop constraints for unaligned regions between aligned blocks
  178.     BlockMultipleAlignment::UngappedAlignedBlockList::const_iterator
  179.         b = alignedBlocks.begin(), be = alignedBlocks.end();
  180.     int n, max;
  181.     for (n=1, ++b; b!=be; ++n, ++b) {
  182.         const UnalignedBlock *uaBlock = multiple->GetUnalignedBlockBefore(*b);
  183.         if (uaBlock) {
  184.             max = (int) (loopLengthMultiplier * uaBlock->width);
  185.             if (max < MIN_LOOP_MAX) max = MIN_LOOP_MAX;
  186.         } else
  187.             max = MIN_LOOP_MAX;
  188.         corDef->lll.llmn[n] = 0;
  189.         corDef->lll.llmx[n] = max;
  190.         corDef->lll.lrfs[n] = max;
  191.     }
  192.     // minimum block sizes (in coordinates of master)
  193.     const Block::Range *range;
  194.     int mid;
  195.     for (n=0, b=alignedBlocks.begin(); b!=be; ++b, ++n) {
  196.         range = (*b)->GetRangeOfRow(0);
  197.         mid = (range->from + range->to) / 2;
  198.         corDef->sll.rfpt[n] = mid;
  199.         corDef->sll.nomn[n] = mid - range->from;
  200.         corDef->sll.comn[n] = range->to - mid;
  201.     }
  202.     // left extension - trim to available residues
  203.     corDef->sll.nomx[0] = corDef->sll.nomn[0] + EXTENSION_MAX;
  204.     if (corDef->sll.rfpt[0] - corDef->sll.nomx[0] < 0)
  205.         corDef->sll.nomx[0] = corDef->sll.rfpt[0];
  206.     // right extension - trim to available residues
  207.     corDef->sll.comx[alignedBlocks.size() - 1] = corDef->sll.comn[alignedBlocks.size() - 1] + EXTENSION_MAX;
  208.     if (corDef->sll.rfpt[alignedBlocks.size() - 1] + corDef->sll.comx[alignedBlocks.size() - 1] >=
  209.             multiple->GetMaster()->Length())
  210.         corDef->sll.comx[alignedBlocks.size() - 1] =
  211.             multiple->GetMaster()->Length() - corDef->sll.rfpt[alignedBlocks.size() - 1] - 1;
  212.     // extensions into unaligned areas between blocks
  213.     const Block::Range *prevRange = NULL;
  214.     int nUnaligned, extN;
  215.     for (n=0, b=alignedBlocks.begin(); b!=be; ++b, ++n) {
  216.         range = (*b)->GetRangeOfRow(0);
  217.         if (n > 0) {
  218.             nUnaligned = range->from - prevRange->to - 1;
  219.             extN = nUnaligned / 2;  // N extension of right block gets smaller portion if nUnaligned is odd
  220.             corDef->sll.nomx[n] = corDef->sll.nomn[n] + extN;
  221.             corDef->sll.comx[n - 1] = corDef->sll.comn[n - 1] + nUnaligned - extN;
  222.         }
  223.         prevRange = range;
  224.     }
  225.     // no fixed segments
  226.     corDef->fll.n = 0;
  227.     return corDef;
  228. }
  229. Qry_Seq * Threader::CreateQrySeq(const BlockMultipleAlignment *multiple,
  230.         const BlockMultipleAlignment *pairwise, int terminalCutoff)
  231. {
  232.     const Sequence *slaveSeq = pairwise->GetSequenceOfRow(1);
  233.     BlockMultipleAlignment::UngappedAlignedBlockList multipleABlocks, pairwiseABlocks;
  234.     multiple->GetUngappedAlignedBlocks(&multipleABlocks);
  235.     pairwise->GetUngappedAlignedBlocks(&pairwiseABlocks);
  236.     // query has # constraints = # blocks in multiple alignment
  237.     Qry_Seq *qrySeq = NewQrySeq(slaveSeq->Length(), multipleABlocks.size());
  238.     // fill in residue numbers
  239.     int i;
  240.     for (i=0; i<slaveSeq->Length(); ++i)
  241.         qrySeq->sq[i] = LookupThreaderResidueNumberFromCharacterAbbrev(slaveSeq->sequenceString[i]);
  242.     // if a block in the multiple is contained in the pairwise (looking at master coords),
  243.     // then add a constraint to keep it there
  244.     BlockMultipleAlignment::UngappedAlignedBlockList::const_iterator
  245.         m, me = multipleABlocks.end(), p, pe = pairwiseABlocks.end();
  246.     const Block::Range *multipleRange, *pairwiseRange;
  247.     for (i=0, m=multipleABlocks.begin(); m!=me; ++i, ++m) {
  248.         multipleRange = (*m)->GetRangeOfRow(0);
  249.         for (p=pairwiseABlocks.begin(); p!=pe; ++p) {
  250.             pairwiseRange = (*p)->GetRangeOfRow(0);
  251.             if (pairwiseRange->from <= multipleRange->from && pairwiseRange->to >= multipleRange->to) {
  252.                 int masterCenter = (multipleRange->from + multipleRange->to) / 2;
  253.                 // offset of master residue at center of multiple block
  254.                 int offset = masterCenter - pairwiseRange->from;
  255.                 pairwiseRange = (*p)->GetRangeOfRow(1);
  256.                 // slave residue in pairwise aligned to master residue at center of multiple block
  257.                 qrySeq->sac.mn[i] = qrySeq->sac.mx[i] = pairwiseRange->from + offset;
  258.                 break;
  259.             }
  260.         }
  261.     }
  262.     // if a terminal block is unconstrained (mn,mx == -1), set limits for how far the new
  263.     // (religned) block is allowed to be from the edge of the next block or from the
  264.     // aligned region set upon demotion
  265.     if (terminalCutoff >= 0) {
  266.         if (qrySeq->sac.mn[0] == -1) {
  267.             if (pairwise->alignSlaveFrom >= 0) {
  268.                 qrySeq->sac.mn[0] = pairwise->alignSlaveFrom - terminalCutoff;
  269.             } else if (pairwiseABlocks.size() > 0) {
  270.                 const Block::Range *nextQryBlock = pairwiseABlocks.front()->GetRangeOfRow(1);
  271.                 qrySeq->sac.mn[0] = nextQryBlock->from - 1 - terminalCutoff;
  272.             }
  273.             if (qrySeq->sac.mn[0] < 0) qrySeq->sac.mn[0] = 0;
  274.             INFOMSG("new N-terminal block constrained to query loc >= " << qrySeq->sac.mn[0] + 1);
  275.         }
  276.         if (qrySeq->sac.mx[multipleABlocks.size() - 1] == -1) {
  277.             if (pairwise->alignSlaveTo >= 0) {
  278.                 qrySeq->sac.mx[multipleABlocks.size() - 1] = pairwise->alignSlaveTo + terminalCutoff;
  279.             } else if (pairwiseABlocks.size() > 0) {
  280.                 const Block::Range *prevQryBlock = pairwiseABlocks.back()->GetRangeOfRow(1);
  281.                 qrySeq->sac.mx[multipleABlocks.size() - 1] = prevQryBlock->to + 1 + terminalCutoff;
  282.             }
  283.             if (qrySeq->sac.mx[multipleABlocks.size() - 1] >= qrySeq->n ||
  284.                 qrySeq->sac.mx[multipleABlocks.size() - 1] < 0)
  285.                 qrySeq->sac.mx[multipleABlocks.size() - 1] = qrySeq->n - 1;
  286.             INFOMSG("new C-terminal block constrained to query loc <= "
  287.                 << qrySeq->sac.mx[multipleABlocks.size() - 1] + 1);
  288.         }
  289.     }
  290.     return qrySeq;
  291. }
  292. /*----------------------------------------------------------------------------
  293.  *  stuff to read in the contact potential. (code swiped from DDV)
  294.  *---------------------------------------------------------------------------*/
  295. static Int4 CountWords(char* Str) {
  296.     Int4     i, Count=0;
  297.     Boolean  InsideStr;
  298.     InsideStr = FALSE;
  299.     for (i=0; i<StrLen(Str); ++i) {
  300.         if (!InsideStr && (Str[i] != ' ')) {
  301.             ++Count;
  302.             InsideStr = TRUE;
  303.         }
  304.         if (Str[i] == ' ') {
  305.             InsideStr = FALSE;
  306.         }
  307.     }
  308.     return(Count);
  309. }
  310. static void ReadToRowOfEnergies(ifstream& InFile, int NumResTypes) {
  311.     char  Str[1024];
  312.     while (!InFile.eof()) {
  313.         InFile.getline(Str, sizeof(Str));
  314.             if (CountWords(Str) == NumResTypes) {
  315.             break;
  316.         }
  317.     }
  318. }
  319. static const int NUM_RES_TYPES = 21;
  320. Rcx_Ptl * Threader::CreateRcxPtl(double weightContacts)
  321. {
  322.     Rcx_Ptl*  pmf;
  323.     char      *FileName = "ContactPotential";
  324.     char      ResName[32];
  325.     char      Path[512];
  326.     Int4      i, j, k;
  327.     double    temp;
  328.     static const int kNumDistances = 6;
  329.     static const int kPeptideIndex = 20;
  330.     /* open the contact potential for reading */
  331.     StrCpy(Path, GetDataDir().c_str());
  332.     StrCat(Path, FileName);
  333.     auto_ptr<CNcbiIfstream> InFile(new CNcbiIfstream(Path));
  334.     if (!(*InFile)) {
  335.         ERRORMSG("Threader::CreateRcxPtl() - can't open " << Path << " for reading");
  336.         return NULL;
  337.     }
  338.     pmf = NewRcxPtl(NUM_RES_TYPES, kNumDistances, kPeptideIndex);
  339.     /* read in the contact potential */
  340.     for (i=0; i<kNumDistances; ++i) {
  341.         ReadToRowOfEnergies(*InFile, NUM_RES_TYPES);
  342.         if (InFile->eof()) goto error;
  343.         for (j=0; j<NUM_RES_TYPES; ++j) {
  344.             InFile->getline(ResName, sizeof(ResName), ' ');  /* skip residue name */
  345.             if (InFile->eof()) goto error;
  346.             for (k=0; k<NUM_RES_TYPES; ++k) {
  347.                 *InFile >> temp;
  348.                 if (InFile->eof()) goto error;
  349.                 pmf->rre[i][j][k] = ThrdRound(temp*SCALING_FACTOR*weightContacts);
  350.             }
  351.         }
  352.     }
  353.     /* read in the hydrophobic energies */
  354.     ReadToRowOfEnergies(*InFile, kNumDistances);
  355.     for (i=0; i<NUM_RES_TYPES; ++i) {
  356.         InFile->getline(ResName, sizeof(ResName), ' ');  /* skip residue name */
  357.         if (InFile->eof()) goto error;
  358.         for (j=0; j<kNumDistances; ++j) {
  359.             *InFile >> temp;
  360.             if (InFile->eof()) goto error;
  361.             pmf->re[j][i] = ThrdRound(temp*SCALING_FACTOR*weightContacts);
  362.         }
  363.     }
  364.     /* calculate sum of pair energies plus hydrophobic energies */
  365.     for(i=0; i<kNumDistances; ++i) {
  366.         for(j=0; j<NUM_RES_TYPES; ++j) {
  367.             for(k=0; k<NUM_RES_TYPES; ++k) {
  368.                 pmf->rrt[i][j][k] = pmf->rre[i][j][k] + pmf->re[i][j] + pmf->re[i][k];
  369.             }
  370.         }
  371.     }
  372.     return(pmf);
  373. error:
  374.     ERRORMSG("Threader::CreateRcxPtl() - error parsing " << FileName);
  375.     FreeRcxPtl(pmf);
  376.     return NULL;
  377. }
  378. /*----------------------------------------------------------------------------
  379.  *  set up the annealing parameters. (more code swiped from DDV)
  380.  *  hard-coded for now.  later we can move these parameters to a file.
  381.  *---------------------------------------------------------------------------*/
  382. Gib_Scd * Threader::CreateGibScd(bool fast, int nRandomStarts)
  383. {
  384.     Gib_Scd*  gsp;
  385.     int       NumTrajectoryPoints;
  386.     static const int kNumTempSteps = 3;
  387.     gsp = NewGibScd(kNumTempSteps);
  388.     gsp->nrs = nRandomStarts;     /* Number of random starts */
  389.     gsp->nts = kNumTempSteps;     /* Number of temperature steps */
  390.     gsp->crs = 50;                /* Number of starts before convergence test */
  391.     gsp->cfm = 20;                /* Top thread frequency convergence criterion */
  392.     gsp->csm = 5;                 /* Top thread start convergence criterion */
  393.     gsp->cet = 5 * SCALING_FACTOR;/* Temperature for convergence test ensemble */
  394.     gsp->cef = 50;                /* Percent of ensemble defining top threads */
  395.     gsp->isl = 1;                 /* Code for choice of starting locations */
  396.     gsp->iso = 0;                 /* Code for choice of segment sample order */
  397.     gsp->ito = 0;                 /* Code for choice of terminus sample order */
  398.     gsp->rsd = -1;                /* Seed for random number generator -- neg for Rand01() */
  399.     gsp->als = 0;                 /* Code for choice of alignment record style */
  400.     gsp->trg = 0;                 /* Code for choice of trajectory record */
  401.     if (fast) {
  402.     //    gsp->nti[0] = 5;            /* Number of iterations per tempeature step */
  403.     //    gsp->nti[1] = 10;
  404.     //    gsp->nti[2] = 25;
  405.         gsp->nti[0] = 10;           /* Number of iterations per tempeature step */
  406.         gsp->nti[1] = 20;
  407.         gsp->nti[2] = 40;
  408.     } else {
  409.         gsp->nti[0] = 10;           /* Number of iterations per tempeature step */
  410.         gsp->nti[1] = 20;
  411.         gsp->nti[2] = 40;
  412.     }
  413.     gsp->nac[0] = 4;              /* Number of alignment cycles per iteration */
  414.     gsp->nac[1] = 4;
  415.     gsp->nac[2] = 4;
  416.     gsp->nlc[0] = 2;              /* Number of location cycles per iteration */
  417.     gsp->nlc[1] = 2;
  418.     gsp->nlc[2] = 2;
  419.     if (fast) {
  420.     //    gsp->tma[0] = 5 * SCALING_FACTOR;  /* Temperature steps for alignment sampling */
  421.     //    gsp->tma[1] = 5 * SCALING_FACTOR;
  422.     //    gsp->tma[2] = 5 * SCALING_FACTOR;
  423.         gsp->tma[0] = 20 * SCALING_FACTOR;  /* Temperature steps for alignment sampling */
  424.         gsp->tma[1] = 10 * SCALING_FACTOR;
  425.         gsp->tma[2] =  5 * SCALING_FACTOR;
  426.     } else {
  427.         gsp->tma[0] = 20 * SCALING_FACTOR;  /* Temperature steps for alignment sampling */
  428.         gsp->tma[1] = 10 * SCALING_FACTOR;
  429.         gsp->tma[2] =  5 * SCALING_FACTOR;
  430.     }
  431.     gsp->tml[0] = 5 * SCALING_FACTOR;     /* Temperature steps for location sampling */
  432.     gsp->tml[1] = 5 * SCALING_FACTOR;
  433.     gsp->tml[2] = 5 * SCALING_FACTOR;
  434.     gsp->lms[0] = 0;              /* Iterations before local minimum test */
  435.     gsp->lms[1] = 10;
  436.     gsp->lms[2] = 20;
  437.     gsp->lmw[0] = 0;              /* Iterations in local min test interval */
  438.     gsp->lmw[1] = 10;
  439.     gsp->lmw[2] = 10;
  440.     gsp->lmf[0] = 0;              /* Percent of top score indicating local min */
  441.     gsp->lmf[1] = 80;
  442.     gsp->lmf[2] = 95;
  443.     if (gsp->als == 0) {
  444.         NumTrajectoryPoints = 1;
  445.     } else {
  446.         NumTrajectoryPoints = 0;
  447.         for (int i=0; i<kNumTempSteps; ++i) {
  448.             NumTrajectoryPoints += gsp->nti[i] * (gsp->nac[i] + gsp->nlc[i]);
  449.         }
  450.         NumTrajectoryPoints *= gsp->nrs;
  451.         NumTrajectoryPoints += gsp->nrs;
  452.     }
  453.     gsp->ntp = NumTrajectoryPoints;
  454.     return(gsp);
  455. }
  456. #define NO_VIRTUAL_COORDINATE(coord) 
  457.     do { coord->type = Threader::MISSING_COORDINATE; return; } while (0)
  458. static void GetVirtualResidue(const AtomSet *atomSet, const Molecule *mol,
  459.     const Residue *res, Threader::VirtualCoordinate *coord)
  460. {
  461.     // find coordinates of key atoms
  462.     const AtomCoord *C = NULL, *CA = NULL, *CB = NULL, *N = NULL;
  463.     Residue::AtomInfoMap::const_iterator a, ae = res->GetAtomInfos().end();
  464.     for (a=res->GetAtomInfos().begin(); a!=ae; ++a) {
  465.         AtomPntr ap(mol->id, res->id, a->first);
  466.         if (a->second->atomicNumber == 6) {
  467.             if (a->second->code == " C  ")
  468.                 C = atomSet->GetAtom(ap, true, true);
  469.             else if (a->second->code == " CA ")
  470.                 CA = atomSet->GetAtom(ap, true, true);
  471.             else if (a->second->code == " CB ")
  472.                 CB = atomSet->GetAtom(ap, true, true);
  473.         } else if (a->second->atomicNumber == 7 && a->second->code == " N  ")
  474.             N = atomSet->GetAtom(ap, true, true);
  475.         if (C && CA && CB && N) break;
  476.     }
  477.     if (!C || !CA || !N) NO_VIRTUAL_COORDINATE(coord);
  478.     // find direction of real or idealized C-beta
  479.     Vector toCB;
  480.     // if C-beta present, vector is in its direction
  481.     if (CB) {
  482.         toCB = CB->site - CA->site;
  483.     }
  484.     // ... else need to calculate a C-beta direction (not C-beta position!)
  485.     else {
  486.         Vector CaN, CaC, cross, bisect;
  487.         CaN = N->site - CA->site;
  488.         CaC = C->site - CA->site;
  489.         // for a true bisector, these vectors should be normalized! but they aren't in other
  490.         // versions of the threader (Cn3D/C and S), so the average is used instead...
  491. //        CaN.normalize();
  492. //        CaC.normalize();
  493.         bisect = CaN + CaC;
  494.         bisect.normalize();
  495.         cross = vector_cross(CaN, CaC);
  496.         cross.normalize();
  497.         toCB = 0.816497 * cross - 0.57735 * bisect;
  498.     }
  499.     // virtual C-beta location is 2.4 A away from C-alpha in the C-beta direction
  500.     toCB.normalize();
  501.     coord->coord = CA->site + 2.4 * toCB;
  502.     coord->type = Threader::VIRTUAL_RESIDUE;
  503.     // is this disulfide-bound?
  504.     Molecule::DisulfideMap::const_iterator ds = mol->disulfideMap.find(res->id);
  505.     coord->disulfideWith =
  506.         (ds == mol->disulfideMap.end()) ? -1 :
  507.         (ds->second - 1) * 2;   // calculate virtualCoordinate index from other residueID
  508. }
  509. static void GetVirtualPeptide(const AtomSet *atomSet, const Molecule *mol,
  510.     const Residue *res1, const Residue *res2, Threader::VirtualCoordinate *coord)
  511. {
  512.     if (res1->alphaID == Residue::NO_ALPHA_ID || res2->alphaID == Residue::NO_ALPHA_ID)
  513.         NO_VIRTUAL_COORDINATE(coord);
  514.     AtomPntr ap1(mol->id, res1->id, res1->alphaID), ap2(mol->id, res2->id, res2->alphaID);
  515.     const AtomCoord
  516.         *atom1 = atomSet->GetAtom(ap1, true, true),   // 'true' means just use first alt coord
  517.         *atom2 = atomSet->GetAtom(ap2, true, true);
  518.     if (!atom1 || !atom2) NO_VIRTUAL_COORDINATE(coord);
  519.     coord->coord = (atom1->site + atom2->site) / 2;
  520.     coord->type = Threader::VIRTUAL_PEPTIDE;
  521.     coord->disulfideWith = -1;
  522. }
  523. static void GetVirtualCoordinates(const Molecule *mol, const AtomSet *atomSet,
  524.     Threader::VirtualCoordinateList *virtualCoordinates)
  525. {
  526.     virtualCoordinates->resize(2 * mol->residues.size() - 1);
  527.     Molecule::ResidueMap::const_iterator r, re = mol->residues.end();
  528.     const Residue *prevResidue = NULL;
  529.     int i = 0;
  530.     for (r=mol->residues.begin(); r!=re; ++r) {
  531.         if (prevResidue)
  532.             GetVirtualPeptide(atomSet, mol,
  533.                 prevResidue, r->second, &((*virtualCoordinates)[i++]));
  534.         prevResidue = r->second;
  535.         GetVirtualResidue(atomSet, mol,
  536.             r->second, &((*virtualCoordinates)[i++]));
  537.     }
  538. }
  539. static const int MAX_DISTANCE_BIN = 5;
  540. static int BinDistance(const Vector& p1, const Vector& p2)
  541. {
  542.     double dist = (p2 - p1).length();
  543.     int bin;
  544.     if (dist > 10.0)
  545.         bin = MAX_DISTANCE_BIN + 1;
  546.     else if (dist > 9.0)
  547.         bin = 5;
  548.     else if (dist > 8.0)
  549.         bin = 4;
  550.     else if (dist > 7.0)
  551.         bin = 3;
  552.     else if (dist > 6.0)
  553.         bin = 2;
  554.     else if (dist > 5.0)
  555.         bin = 1;
  556.     else
  557.         bin = 0;
  558.     return bin;
  559. }
  560. static void GetContacts(const Threader::VirtualCoordinateList& coords,
  561.     Threader::ContactList *resResContacts, Threader::ContactList *resPepContacts)
  562. {
  563.     int i, j, bin;
  564.     // loop i through whole chain, just to report all missing coords
  565.     for (i=0; i<coords.size(); ++i) {
  566.         if (coords[i].type == Threader::MISSING_COORDINATE) {
  567.             WARNINGMSG("Threader::CreateFldMtf() - unable to determine virtual coordinate for "
  568.                 << ((i%2 == 0) ? "sidechain " : "peptide ") << (i/2));
  569.             continue;
  570.         }
  571.         for (j=i+10; j<coords.size(); ++j) {    // must be at least 10 virtual bonds away
  572.             if (coords[j].type == Threader::MISSING_COORDINATE ||
  573.                 // not interested in peptide-peptide contacts
  574.                 (coords[i].type == Threader::VIRTUAL_PEPTIDE &&
  575.                  coords[j].type == Threader::VIRTUAL_PEPTIDE) ||
  576.                 // don't include disulfide-bonded cysteine pairs
  577.                 (coords[i].disulfideWith == j || coords[j].disulfideWith == i)
  578.                 ) continue;
  579.             bin = BinDistance(coords[i].coord, coords[j].coord);
  580.             if (bin <= MAX_DISTANCE_BIN) {
  581.                 // add residue-residue contact - res1 is lower-numbered residue
  582.                 if (coords[i].type == Threader::VIRTUAL_RESIDUE &&
  583.                     coords[j].type == Threader::VIRTUAL_RESIDUE) {
  584.                     resResContacts->resize(resResContacts->size() + 1);
  585.                     resResContacts->back().vc1 = i;
  586.                     resResContacts->back().vc2 = j;
  587.                     resResContacts->back().distanceBin = bin;
  588.                 }
  589.                 // add residue-peptide contact
  590.                 else {
  591.                     resPepContacts->resize(resPepContacts->size() + 1);
  592.                     resPepContacts->back().distanceBin = bin;
  593.                     // peptide must go in vc2
  594.                     if (coords[i].type == Threader::VIRTUAL_RESIDUE) {
  595.                         resPepContacts->back().vc1 = i;
  596.                         resPepContacts->back().vc2 = j;
  597.                     } else {
  598.                         resPepContacts->back().vc2 = i;
  599.                         resPepContacts->back().vc1 = j;
  600.                     }
  601.                 }
  602.             }
  603.         }
  604.     }
  605. }
  606. static void TranslateContacts(const Threader::ContactList& resResContacts,
  607.     const Threader::ContactList& resPepContacts, Fld_Mtf *fldMtf)
  608. {
  609.     int i;
  610.     Threader::ContactList::const_iterator c;
  611.     for (i=0, c=resResContacts.begin(); i<resResContacts.size(); ++i, ++c) {
  612.         fldMtf->rrc.r1[i] = c->vc1 / 2;  // threader coord points to (res,pep) pair
  613.         fldMtf->rrc.r2[i] = c->vc2 / 2;
  614.         fldMtf->rrc.d[i] = c->distanceBin;
  615.     }
  616.     for (i=0, c=resPepContacts.begin(); i<resPepContacts.size(); ++i, ++c) {
  617.         fldMtf->rpc.r1[i] = c->vc1 / 2;
  618.         fldMtf->rpc.p2[i] = c->vc2 / 2;
  619.         fldMtf->rpc.d[i] = c->distanceBin;
  620.     }
  621. }
  622. // for sorting contacts
  623. inline bool operator < (const Threader::Contact& c1, const Threader::Contact& c2)
  624. {
  625.     return (c1.vc1 < c2.vc1 || (c1.vc1 == c2.vc1 && c1.vc2 < c2.vc2));
  626. }
  627. static void GetMinimumLoopLengths(const Molecule *mol, const AtomSet *atomSet, Fld_Mtf *fldMtf)
  628. {
  629.     int i, j;
  630.     const AtomCoord *a1, *a2;
  631.     Molecule::ResidueMap::const_iterator r1, r2, re = mol->residues.end();
  632.     for (r1=mol->residues.begin(), i=0; r1!=re; ++r1, ++i) {
  633.         if (r1->second->alphaID == Residue::NO_ALPHA_ID)
  634.             a1 = NULL;
  635.         else {
  636.             AtomPntr ap1(mol->id, r1->second->id, r1->second->alphaID);
  637.             a1 = atomSet->GetAtom(ap1, true, true);   // 'true' means just use first alt coord
  638.         }
  639.         for (r2=r1, j=i; r2!=re; ++r2, ++j) {
  640.             if (i == j) {
  641.                 fldMtf->mll[i][j] = 0;
  642.             } else {
  643.                 if (r2->second->alphaID == Residue::NO_ALPHA_ID)
  644.                     a2 = NULL;
  645.                 else {
  646.                     AtomPntr ap2(mol->id, r2->second->id, r2->second->alphaID);
  647.                     a2 = atomSet->GetAtom(ap2, true, true);
  648.                 }
  649.                 fldMtf->mll[i][j] = fldMtf->mll[j][i] =
  650.                     (!a1 || !a2) ? 0 : (int) (((a2->site - a1->site).length() - 2.7) / 3.4);
  651.             }
  652.         }
  653.     }
  654. }
  655. Fld_Mtf * Threader::CreateFldMtf(const Sequence *masterSequence)
  656. {
  657.     if (!masterSequence) return NULL;
  658.     const Molecule *mol = masterSequence->molecule;
  659.     // return cached copy if we've already constructed a Fld_Mtf for this master
  660.     ContactMap::iterator c = mol ? contacts.find(mol) : contacts.find(masterSequence);
  661.     if (c != contacts.end()) return c->second;
  662.     // work-around to allow PSSM-only threading when master has no structure (or only C-alphas)
  663.     Fld_Mtf *fldMtf;
  664.     if (!mol || mol->parentSet->isAlphaOnly) {
  665.         fldMtf = NewFldMtf(masterSequence->Length(), 0, 0);
  666.         contacts[masterSequence] = fldMtf;
  667.         return fldMtf;
  668.     }
  669.     // for convenience so subroutines don't have to keep looking this up... Use first
  670.     // CoordSet if multiple model (e.g., NMR)
  671.     const StructureObject *object;
  672.     if (!mol->GetParentOfType(&object)) return NULL;
  673.     const AtomSet *atomSet = object->coordSets.front()->atomSet;
  674.     // get virtual coordinates for this chain
  675.     VirtualCoordinateList virtualCoordinates;
  676.     GetVirtualCoordinates(mol, atomSet, &virtualCoordinates);
  677.     // check for contacts of virtual coords separated by >= 10 virtual bonds
  678.     ContactList resResContacts, resPepContacts;
  679.     GetContacts(virtualCoordinates, &resResContacts, &resPepContacts);
  680.     // create Fld_Mtf, and store contacts in it
  681.     fldMtf = NewFldMtf(mol->residues.size(), resResContacts.size(), resPepContacts.size());
  682.     resPepContacts.sort();  // not really necessary, but makes same order as Cn3D for comparison/testing
  683.     TranslateContacts(resResContacts, resPepContacts, fldMtf);
  684.     // fill out min. loop lengths
  685.     GetMinimumLoopLengths(mol, atomSet, fldMtf);
  686.     TRACEMSG("created Fld_Mtf for " << mol->identifier->pdbID << " chain '" << (char) mol->identifier->pdbChain << "'");
  687.     contacts[mol] = fldMtf;
  688.     return fldMtf;
  689. }
  690. static BlockMultipleAlignment * CreateAlignmentFromThdTbl(const Thd_Tbl *thdTbl, int nResult,
  691.     const Cor_Def *corDef, BlockMultipleAlignment::SequenceList *sequences, AlignmentManager *alnMgr)
  692. {
  693.     if (corDef->sll.n != thdTbl->nsc || nResult >= thdTbl->n) {
  694.         ERRORMSG("CreateAlignmentFromThdTbl() - inconsistent Thd_Tbl");
  695.         return NULL;
  696.     }
  697.     BlockMultipleAlignment *newAlignment = new BlockMultipleAlignment(sequences, alnMgr);
  698.     // add blocks from threader result
  699.     for (int block=0; block<corDef->sll.n; ++block) {
  700.         UngappedAlignedBlock *aBlock = new UngappedAlignedBlock(newAlignment);
  701.         aBlock->SetRangeOfRow(0,
  702.             corDef->sll.rfpt[block] - thdTbl->no[block][nResult],
  703.             corDef->sll.rfpt[block] + thdTbl->co[block][nResult]);
  704.         aBlock->SetRangeOfRow(1,
  705.             thdTbl->al[block][nResult] - thdTbl->no[block][nResult],
  706.             thdTbl->al[block][nResult] + thdTbl->co[block][nResult]);
  707.         aBlock->width = thdTbl->no[block][nResult] + 1 + thdTbl->co[block][nResult];
  708.         if (!newAlignment->AddAlignedBlockAtEnd(aBlock)) {
  709.             ERRORMSG("CreateAlignmentFromThdTbl() - error adding block");
  710.             delete newAlignment;
  711.             return NULL;
  712.         }
  713.     }
  714.     // finish alignment
  715.     if (!newAlignment->AddUnalignedBlocks() || !newAlignment->UpdateBlockMapAndColors()) {
  716.         ERRORMSG("CreateAlignmentFromThdTbl() - error finishing alignment");
  717.         delete newAlignment;
  718.         return NULL;
  719.     }
  720.     return newAlignment;
  721. }
  722. static bool FreezeIsolatedBlocks(Cor_Def *corDef, const Cor_Def *masterCorDef, const Qry_Seq *qrySeq)
  723. {
  724.     if (!corDef || !masterCorDef || !qrySeq ||
  725.         corDef->sll.n != masterCorDef->sll.n || corDef->sll.n != qrySeq->sac.n) {
  726.         ERRORMSG("FreezeIsolatedBlocks() - bad parameters");
  727.         return false;
  728.     }
  729.     TRACEMSG("freezing blocks...");
  730.     for (int i=0; i<corDef->sll.n; ++i) {
  731.         // default: blocks allowed to grow
  732.         corDef->sll.nomx[i] = masterCorDef->sll.nomx[i];
  733.         corDef->sll.comx[i] = masterCorDef->sll.comx[i];
  734.         // new blocks always allowed to grow
  735.         if (qrySeq->sac.mn[i] < 0 || qrySeq->sac.mx[i] < 0) continue;
  736.         // if an existing block is adjacent to any new (to-be-realigned) block, then allow block's
  737.         // boundaries to grow on that side; otherwise, freeze (isolated) existing block boundaries
  738.         bool adjacentLeft = (i > 0 && (qrySeq->sac.mn[i - 1] < 0 || qrySeq->sac.mx[i - 1] < 0));
  739.         bool adjacentRight = (i < corDef->sll.n - 1 &&
  740.             (qrySeq->sac.mn[i + 1] < 0 || qrySeq->sac.mx[i + 1] < 0));
  741.         if (!adjacentLeft) {
  742.             corDef->sll.nomx[i] = corDef->sll.nomn[i];
  743. //            TESTMSG("block " << i << " fixed N-terminus");
  744.         }
  745.         if (!adjacentRight) {
  746.             corDef->sll.comx[i] = corDef->sll.comn[i];
  747. //            TESTMSG("block " << i << " fixed C-terminus");
  748.         }
  749.     }
  750.     return true;
  751. }
  752. bool Threader::Realign(const ThreaderOptions& options, BlockMultipleAlignment *masterMultiple,
  753.     const AlignmentList *originalAlignments,
  754.     int *nRowsAddedToMultiple, AlignmentList *newAlignments)
  755. {
  756.     *nRowsAddedToMultiple = 0;
  757.     if (!masterMultiple || !originalAlignments || !newAlignments || originalAlignments->size() == 0)
  758.         return false;
  759.     // either calculate no z-scores (0), or calculate z-score for best result (1)
  760.     static const int zscs = 0;
  761.     Seq_Mtf *seqMtf = NULL;
  762.     Cor_Def *corDef = NULL, *masterCorDef = NULL;
  763.     Rcx_Ptl *rcxPtl = NULL;
  764.     Gib_Scd *gibScd = NULL;
  765.     Fld_Mtf *fldMtf = NULL;
  766.     float *trajectory = NULL;
  767.     bool retval = false;
  768.     AlignmentList::const_iterator p, pe = originalAlignments->end();
  769. #ifdef DEBUG_THREADER
  770.     FILE *pFile;
  771. #endif
  772.     // create contact lists
  773.     if (options.weightPSSM < 1.0 && (!masterMultiple->GetMaster()->molecule ||
  774.             masterMultiple->GetMaster()->molecule->parentSet->isAlphaOnly)) {
  775.         ERRORMSG("Can't use contact potential on non-structured master, or alpha-only (virtual bond) models!");
  776.         goto cleanup;
  777.     }
  778.     if (!(fldMtf = CreateFldMtf(masterMultiple->GetMaster()))) goto cleanup;
  779.     // create potential and Gibbs schedule
  780.     if (!(rcxPtl = CreateRcxPtl(1.0 - options.weightPSSM))) goto cleanup;
  781.     if (!(gibScd = CreateGibScd(true, options.nRandomStarts))) goto cleanup;
  782.     trajectory = new float[gibScd->ntp];
  783.     // create initial PSSM
  784.     if (!(seqMtf = CreateSeqMtf(masterMultiple, options.weightPSSM, NULL))) goto cleanup;
  785. #ifdef DEBUG_THREADER
  786.     pFile = fopen("Seq_Mtf.debug.txt", "w");
  787.     PrintSeqMtf(seqMtf, pFile);
  788.     fclose(pFile);
  789. #endif
  790.     // create core definition
  791.     if (!(corDef = CreateCorDef(masterMultiple, options.loopLengthMultiplier))) goto cleanup;
  792.     if (options.freezeIsolatedBlocks)   // make a copy to used as an original "master"
  793.         if (!(masterCorDef = CreateCorDef(masterMultiple, options.loopLengthMultiplier))) goto cleanup;
  794. #ifdef DEBUG_THREADER
  795.     pFile = fopen("Fld_Mtf.debug.txt", "w");
  796.     PrintFldMtf(fldMtf, pFile);
  797.     fclose(pFile);
  798. #endif
  799.     for (p=originalAlignments->begin(); p!=pe; ) {
  800.         if ((*p)->NRows() != 2 || (*p)->GetMaster() != masterMultiple->GetMaster()) {
  801.             ERRORMSG("Threader::Realign() - bad pairwise alignment");
  802.             continue;
  803.         }
  804.         Qry_Seq *qrySeq = NULL;
  805.         Thd_Tbl *thdTbl = NULL;
  806.         int success;
  807.         // create query sequence
  808.         if (!(qrySeq = CreateQrySeq(masterMultiple, *p, options.terminalResidueCutoff))) goto cleanup2;
  809. #ifdef DEBUG_THREADER
  810.         pFile = fopen("Qry_Seq.debug.txt", "w");
  811.         PrintQrySeq(qrySeq, pFile);
  812.         fclose(pFile);
  813. #endif
  814.         // freeze block sizes if opted (changes corDef but not masterCorDef or qrySeq)
  815.         if (options.freezeIsolatedBlocks)
  816.             FreezeIsolatedBlocks(corDef, masterCorDef, qrySeq);
  817. #ifdef DEBUG_THREADER
  818.         pFile = fopen("Cor_Def.debug.txt", "w");
  819.         PrintCorDef(corDef, pFile);
  820.         fclose(pFile);
  821. #endif
  822.         // create results storage structure
  823.         thdTbl = NewThdTbl(options.nResultAlignments, corDef->sll.n);
  824.         // actually run the threader (finally!)
  825.         INFOMSG("threading " << (*p)->GetSequenceOfRow(1)->identifier->ToString());
  826.         success = atd(fldMtf, corDef, qrySeq, rcxPtl, gibScd, thdTbl, seqMtf,
  827.             trajectory, zscs, SCALING_FACTOR, (float) options.weightPSSM);
  828.         BlockMultipleAlignment *newAlignment;
  829.         if (success) {
  830.             TRACEMSG("threading succeeded");
  831. #ifdef DEBUG_THREADER
  832.             pFile = fopen("Thd_Tbl.debug.txt", "w");
  833.             PrintThdTbl(thdTbl, pFile);
  834.             fclose(pFile);
  835. #endif
  836.             // create new alignment(s) from threading result; merge or add to list as appropriate
  837.             for (int i=0; i<thdTbl->n; ++i) {
  838.                 // skip if this entry is not a real result
  839.                 if (thdTbl->tf[i] <= 0) continue;
  840.                 BlockMultipleAlignment::SequenceList *sequences = new BlockMultipleAlignment::SequenceList(2);
  841.                 sequences->front() = (*p)->GetMaster();
  842.                 sequences->back() = (*p)->GetSequenceOfRow(1);
  843.                 newAlignment = CreateAlignmentFromThdTbl(thdTbl, i, corDef,
  844.                     sequences, masterMultiple->alignmentManager);
  845.                 if (!newAlignment) continue;
  846.                 // set scores to show in alignment
  847.                 newAlignment->SetRowDouble(0, thdTbl->tg[i]);
  848.                 newAlignment->SetRowDouble(1, thdTbl->tg[i]);
  849.                 CNcbiOstrstream oss;
  850.                 oss << "Threading successful; alignment score before merge: " << thdTbl->tg[i] << '';
  851.                 newAlignment->SetRowStatusLine(0, oss.str());
  852.                 newAlignment->SetRowStatusLine(1, oss.str());
  853.                 delete oss.str();
  854.                 if (options.mergeAfterEachSequence) {
  855.                     if (masterMultiple->MergeAlignment(newAlignment)) {
  856.                         delete newAlignment; // if merge is successful, we can delete this alignment;
  857.                         ++(*nRowsAddedToMultiple);
  858.                     } else {                 // otherwise keep it
  859.                         newAlignments->push_back(newAlignment);
  860.                     }
  861.                 }
  862.                 // no merge - add new alignment to list, let calling function deal with it
  863.                 else {
  864.                     newAlignments->push_back(newAlignment);
  865.                 }
  866.             }
  867.         }
  868.         // threading failed - add old alignment to list so it doesn't get lost
  869.         else {
  870.             TRACEMSG("threading failed!");
  871.             newAlignment = (*p)->Clone();
  872.             newAlignment->SetRowDouble(0, -1.0);
  873.             newAlignment->SetRowDouble(1, -1.0);
  874.             newAlignment->SetRowStatusLine(0, "Threading failed!");
  875.             newAlignment->SetRowStatusLine(1, "Threading failed!");
  876.             newAlignments->push_back(newAlignment);
  877.         }
  878. cleanup2:
  879.         if (qrySeq) FreeQrySeq(qrySeq);
  880.         if (thdTbl) FreeThdTbl(thdTbl);
  881.         ++p;
  882.         if (success && p != pe && options.mergeAfterEachSequence) {
  883.             // re-create PSSM after each merge
  884.             FreeSeqMtf(seqMtf);
  885.             if (!(seqMtf = CreateSeqMtf(masterMultiple, options.weightPSSM, NULL))) goto cleanup;
  886.         }
  887.     }
  888.     retval = true;
  889. cleanup:
  890.     if (seqMtf) FreeSeqMtf(seqMtf);
  891.     if (corDef) FreeCorDef(corDef);
  892.     if (masterCorDef) FreeCorDef(masterCorDef);
  893.     if (rcxPtl) FreeRcxPtl(rcxPtl);
  894.     if (gibScd) FreeGibScd(gibScd);
  895.     if (trajectory) delete[] trajectory;
  896.     return retval;
  897. }
  898. static double CalculatePSSMScore(const BlockMultipleAlignment::UngappedAlignedBlockList& aBlocks,
  899.     int row, const vector < int >& residueNumbers, const Seq_Mtf *seqMtf)
  900. {
  901.     double score = 0.0;
  902.     BlockMultipleAlignment::UngappedAlignedBlockList::const_iterator b, be = aBlocks.end();
  903.     const Block::Range *masterRange, *slaveRange;
  904.     int i;
  905.     for (b=aBlocks.begin(); b!=be; ++b) {
  906.         masterRange = (*b)->GetRangeOfRow(0);
  907.         slaveRange = (*b)->GetRangeOfRow(row);
  908.         for (i=0; i<(*b)->width; ++i)
  909.             if (residueNumbers[slaveRange->from + i] >= 0)
  910.                 score += seqMtf->ww[masterRange->from + i][residueNumbers[slaveRange->from + i]];
  911.     }
  912. //    TESTMSG("PSSM score for row " << row << ": " << score);
  913.     return score;
  914. }
  915. static double CalculateContactScore(const BlockMultipleAlignment *multiple,
  916.     int row, const vector < int >& residueNumbers, const Fld_Mtf *fldMtf, const Rcx_Ptl *rcxPtl)
  917. {
  918.     double score = 0.0;
  919.     int i, seqIndex1, seqIndex2, resNum1, resNum2, dist;
  920.     // for each res-res contact, convert seqIndexes of master into corresponding seqIndexes
  921.     // of slave if they're aligned; add contact energies if so
  922.     for (i=0; i<fldMtf->rrc.n; ++i) {
  923.         seqIndex1 = multiple->GetAlignedSlaveIndex(fldMtf->rrc.r1[i], row);
  924.         if (seqIndex1 < 0) continue;
  925.         seqIndex2 = multiple->GetAlignedSlaveIndex(fldMtf->rrc.r2[i], row);
  926.         if (seqIndex2 < 0) continue;
  927.         resNum1 = residueNumbers[seqIndex1];
  928.         resNum2 = residueNumbers[seqIndex2];
  929.         if (resNum1 < 0 || resNum2 < 0) continue;
  930.         dist = fldMtf->rrc.d[i];
  931.         score += rcxPtl->rre[dist][resNum1][resNum2] + rcxPtl->re[dist][resNum1] + rcxPtl->re[dist][resNum2];
  932.     }
  933.     // ditto for res-pep contacts - except only one slave residue to look up; 2nd is always peptide group
  934.     for (i=0; i<fldMtf->rpc.n; ++i) {
  935.         seqIndex1 = multiple->GetAlignedSlaveIndex(fldMtf->rpc.r1[i], row);
  936.         if (seqIndex1 < 0) continue;
  937.         // peptides are only counted if both contributing master residues are aligned
  938.         if (fldMtf->rpc.p2[i] >= multiple->GetMaster()->Length() - 1 ||
  939.             !multiple->IsAligned(0, fldMtf->rpc.p2[i]) ||
  940.             !multiple->IsAligned(0, fldMtf->rpc.p2[i] + 1)) continue;
  941.         resNum1 = residueNumbers[seqIndex1];
  942.         if (resNum1 < 0) continue;
  943.         resNum2 = NUM_RES_TYPES - 1; // peptide group
  944.         dist = fldMtf->rpc.d[i];
  945.         score += rcxPtl->rre[dist][resNum1][resNum2] + rcxPtl->re[dist][resNum1] + rcxPtl->re[dist][resNum2];
  946.     }
  947. //    TESTMSG("Contact score for row " << row << ": " << score);
  948.     return score;
  949. }
  950. bool Threader::CalculateScores(const BlockMultipleAlignment *multiple, double weightPSSM)
  951. {
  952.     Seq_Mtf *seqMtf = NULL;
  953.     Rcx_Ptl *rcxPtl = NULL;
  954.     Fld_Mtf *fldMtf = NULL;
  955.     BlockMultipleAlignment::UngappedAlignedBlockList aBlocks;
  956.     vector < int > residueNumbers;
  957.     bool retval = false;
  958.     int row;
  959.     // create contact lists
  960.     if (weightPSSM < 1.0 && (!multiple->GetMaster()->molecule ||
  961.             multiple->GetMaster()->molecule->parentSet->isAlphaOnly)) {
  962.         ERRORMSG("Can't use contact potential on non-structured master, or alpha-only (virtual bond) models!");
  963.         goto cleanup;
  964.     }
  965.     if (weightPSSM < 1.0 && !(fldMtf = CreateFldMtf(multiple->GetMaster()))) goto cleanup;
  966.     // create PSSM
  967.     if (weightPSSM > 0.0 && !(seqMtf = CreateSeqMtf(multiple, weightPSSM, NULL))) goto cleanup;
  968.     // create potential
  969.     if (weightPSSM < 1.0 && !(rcxPtl = CreateRcxPtl(1.0 - weightPSSM))) goto cleanup;
  970.     // get aligned blocks
  971.     multiple->GetUngappedAlignedBlocks(&aBlocks);
  972.     for (row=0; row<multiple->NRows(); ++row) {
  973.         // get sequence's residue numbers
  974.         const Sequence *seq = multiple->GetSequenceOfRow(row);
  975.         residueNumbers.resize(seq->Length());
  976.         for (int i=0; i<seq->Length(); ++i)
  977.             residueNumbers[i] = LookupThreaderResidueNumberFromCharacterAbbrev(seq->sequenceString[i]);
  978.         // sum score types (weightPSSM already built into seqMtf & rcxPtl)
  979.         double
  980.             scorePSSM = (weightPSSM > 0.0) ?
  981.                 CalculatePSSMScore(aBlocks, row, residueNumbers, seqMtf) : 0.0,
  982.             scoreContacts = (weightPSSM < 1.0) ?
  983.                 CalculateContactScore(multiple, row, residueNumbers, fldMtf, rcxPtl) : 0.0,
  984.             score = (scorePSSM + scoreContacts) / SCALING_FACTOR;
  985.         // set score in alignment rows (for sorting and status line display)
  986.         multiple->SetRowDouble(row, score);
  987.         CNcbiOstrstream oss;
  988.         oss << "PSSM+Contact score (PSSM x" << weightPSSM << "): " << score << '';
  989.         multiple->SetRowStatusLine(row, oss.str());
  990.         delete oss.str();
  991.     }
  992.     retval = true;
  993. cleanup:
  994.     if (seqMtf) FreeSeqMtf(seqMtf);
  995.     if (rcxPtl) FreeRcxPtl(rcxPtl);
  996.     return retval;
  997. }
  998. int Threader::GetGeometryViolations(const BlockMultipleAlignment *multiple,
  999.     GeometryViolationsForRow *violations)
  1000. {
  1001.     Fld_Mtf *fldMtf = NULL;
  1002.     // create contact lists
  1003.     if (!multiple->GetMaster()->molecule || multiple->GetMaster()->molecule->parentSet->isAlphaOnly) {
  1004.         ERRORMSG("Can't use contact potential on non-structured master, or alpha-only (virtual bond) models!");
  1005.         return false;
  1006.     }
  1007.     if (!(fldMtf = CreateFldMtf(multiple->GetMaster()))) return false;
  1008.     violations->clear();
  1009.     violations->resize(multiple->NRows());
  1010.     // look for too-short regions between aligned blocks
  1011.     BlockMultipleAlignment::UngappedAlignedBlockList aBlocks;
  1012.     multiple->GetUngappedAlignedBlocks(&aBlocks);
  1013.     BlockMultipleAlignment::UngappedAlignedBlockList::const_iterator b, be = aBlocks.end(), n;
  1014.     int nViolations = 0;
  1015.     const Block::Range *thisRange, *nextRange, *thisMaster, *nextMaster;
  1016.     for (b=aBlocks.begin(); b!=be; ++b) {
  1017.         n = b;
  1018.         ++n;
  1019.         if (n == be) break;
  1020.         thisMaster = (*b)->GetRangeOfRow(0);
  1021.         nextMaster = (*n)->GetRangeOfRow(0);
  1022.         for (int row=1; row<multiple->NRows(); ++row) {
  1023.             thisRange = (*b)->GetRangeOfRow(row);
  1024.             nextRange = (*n)->GetRangeOfRow(row);
  1025.             // violation found
  1026.             if (nextRange->from - thisRange->to - 1 < fldMtf->mll[nextMaster->from][thisMaster->to]) {
  1027.                 (*violations)[row].push_back(make_pair(thisRange->to, nextRange->from));
  1028.                 ++nViolations;
  1029.             }
  1030.         }
  1031.     }
  1032. //    TESTMSG("Found " << nViolations << " geometry violations");
  1033.     return nViolations;
  1034. }
  1035. int Threader::EstimateNRandomStarts(const BlockMultipleAlignment *coreAlignment,
  1036.     const BlockMultipleAlignment *toBeThreaded)
  1037. {
  1038.     int nBlocksToAlign = 0;
  1039.     BlockMultipleAlignment::UngappedAlignedBlockList multipleABlocks, pairwiseABlocks;
  1040.     coreAlignment->GetUngappedAlignedBlocks(&multipleABlocks);
  1041.     toBeThreaded->GetUngappedAlignedBlocks(&pairwiseABlocks);
  1042.     // if a block in the multiple is *not* contained in the pairwise (looking at master coords),
  1043.     // then it'll probably be realigned upon threading
  1044.     BlockMultipleAlignment::UngappedAlignedBlockList::const_iterator
  1045.         m, me = multipleABlocks.end(), p, pe = pairwiseABlocks.end();
  1046.     const Block::Range *multipleRange, *pairwiseRange;
  1047.     for (m=multipleABlocks.begin(); m!=me; ++m) {
  1048.         multipleRange = (*m)->GetRangeOfRow(0);
  1049.         bool realignBlock = true;
  1050.         for (p=pairwiseABlocks.begin(); p!=pe; ++p) {
  1051.             pairwiseRange = (*p)->GetRangeOfRow(0);
  1052.             if (pairwiseRange->from <= multipleRange->from && pairwiseRange->to >= multipleRange->to) {
  1053.                 realignBlock = false;
  1054.                 break;
  1055.             }
  1056.         }
  1057.         if (realignBlock) ++nBlocksToAlign;
  1058.     }
  1059.     if (nBlocksToAlign <= 1)
  1060.         return 1;
  1061.     else
  1062.         // round to nearest integer
  1063.         return (int) (exp(1.5 + 0.25432 * nBlocksToAlign) + 0.5);
  1064. }
  1065. END_SCOPE(Cn3D)
  1066. /*
  1067. * ---------------------------------------------------------------------------
  1068. * $Log: cn3d_threader.cpp,v $
  1069. * Revision 1000.3  2004/06/01 18:28:21  gouriano
  1070. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.43
  1071. *
  1072. * Revision 1.43  2004/05/21 21:41:39  gorelenk
  1073. * Added PCH ncbi_pch.hpp
  1074. *
  1075. * Revision 1.42  2004/03/15 17:59:20  thiessen
  1076. * prefer prefix vs. postfix ++/-- operators
  1077. *
  1078. * Revision 1.41  2004/03/15 17:33:12  thiessen
  1079. * prefer prefix vs. postfix ++/-- operators
  1080. *
  1081. * Revision 1.40  2004/02/19 17:04:51  thiessen
  1082. * remove cn3d/ from include paths; add pragma to disable annoying msvc warning
  1083. *
  1084. * Revision 1.39  2003/11/04 18:09:17  thiessen
  1085. * rearrange headers for OSX build
  1086. *
  1087. * Revision 1.38  2003/07/14 18:37:07  thiessen
  1088. * change GetUngappedAlignedBlocks() param types; other syntax changes
  1089. *
  1090. * Revision 1.37  2003/06/18 11:38:42  thiessen
  1091. * add another trace message
  1092. *
  1093. * Revision 1.36  2003/04/14 18:13:58  thiessen
  1094. * retry pseudocounts until matrix is constructed okay
  1095. *
  1096. * Revision 1.35  2003/02/03 19:20:03  thiessen
  1097. * format changes: move CVS Log to bottom of file, remove std:: from .cpp files, and use new diagnostic macros
  1098. *
  1099. * Revision 1.34  2003/01/23 20:03:05  thiessen
  1100. * add BLAST Neighbor algorithm
  1101. *
  1102. * Revision 1.33  2002/10/08 12:35:42  thiessen
  1103. * use delete[] for arrays
  1104. *
  1105. * Revision 1.32  2002/08/15 22:13:14  thiessen
  1106. * update for wx2.3.2+ only; add structure pick dialog; fix MultitextDialog bug
  1107. *
  1108. * Revision 1.31  2002/07/26 15:28:47  thiessen
  1109. * add Alejandro's block alignment algorithm
  1110. *
  1111. * Revision 1.30  2002/07/12 13:24:10  thiessen
  1112. * fixes for PSSM creation to agree with cddumper/RPSBLAST
  1113. *
  1114. * Revision 1.29  2002/05/26 21:58:46  thiessen
  1115. * add CddDegapSeqAlign to PSSM generator
  1116. *
  1117. * Revision 1.28  2002/03/28 14:06:02  thiessen
  1118. * preliminary BLAST/PSSM ; new CD startup style
  1119. *
  1120. * Revision 1.27  2002/03/19 18:47:57  thiessen
  1121. * small bug fixes; remember PSSM weight
  1122. *
  1123. * Revision 1.26  2002/02/21 22:01:49  thiessen
  1124. * remember alignment range on demotion
  1125. *
  1126. * Revision 1.25  2002/02/21 12:26:29  thiessen
  1127. * fix row delete bug ; remember threader options
  1128. *
  1129. * Revision 1.24  2001/10/08 00:00:09  thiessen
  1130. * estimate threader N random starts; edit CDD name
  1131. *
  1132. * Revision 1.23  2001/09/27 15:37:58  thiessen
  1133. * decouple sequence import and BLAST
  1134. *
  1135. * Revision 1.22  2001/06/21 02:02:33  thiessen
  1136. * major update to molecule identification and highlighting ; add toggle highlight (via alt)
  1137. *
  1138. * Revision 1.21  2001/06/02 17:22:45  thiessen
  1139. * fixes for GCC
  1140. *
  1141. * Revision 1.20  2001/06/01 21:48:26  thiessen
  1142. * add terminal cutoff to threading
  1143. *
  1144. * Revision 1.19  2001/05/31 18:47:07  thiessen
  1145. * add preliminary style dialog; remove LIST_TYPE; add thread single and delete all; misc tweaks
  1146. *
  1147. * Revision 1.18  2001/05/24 21:38:41  thiessen
  1148. * fix threader options initial values
  1149. *
  1150. * Revision 1.17  2001/05/15 23:48:36  thiessen
  1151. * minor adjustments to compile under Solaris/wxGTK
  1152. *
  1153. * Revision 1.16  2001/05/15 14:57:55  thiessen
  1154. * add cn3d_tools; bring up log window when threading starts
  1155. *
  1156. * Revision 1.15  2001/05/11 13:45:06  thiessen
  1157. * set up data directory
  1158. *
  1159. * Revision 1.14  2001/05/11 02:10:42  thiessen
  1160. * add better merge fail indicators; tweaks to windowing/taskbar
  1161. *
  1162. * Revision 1.13  2001/04/13 18:50:54  thiessen
  1163. * fix for when threader returns fewer than requested results
  1164. *
  1165. * Revision 1.12  2001/04/12 18:54:39  thiessen
  1166. * fix memory leak for PSSM-only threading
  1167. *
  1168. * Revision 1.11  2001/04/12 18:10:00  thiessen
  1169. * add block freezing
  1170. *
  1171. * Revision 1.10  2001/04/05 22:55:35  thiessen
  1172. * change bg color handling ; show geometry violations
  1173. *
  1174. * Revision 1.9  2001/04/04 00:27:14  thiessen
  1175. * major update - add merging, threader GUI controls
  1176. *
  1177. * Revision 1.8  2001/03/30 14:43:41  thiessen
  1178. * show threader scores in status line; misc UI tweaks
  1179. *
  1180. * Revision 1.7  2001/03/30 03:07:34  thiessen
  1181. * add threader score calculation & sorting
  1182. *
  1183. * Revision 1.6  2001/03/29 15:35:55  thiessen
  1184. * remove GetAtom warnings
  1185. *
  1186. * Revision 1.5  2001/03/28 23:02:16  thiessen
  1187. * first working full threading
  1188. *
  1189. * Revision 1.4  2001/03/23 23:31:56  thiessen
  1190. * keep atom info around even if coords not all present; mainly for disulfide parsing in virtual models
  1191. *
  1192. * Revision 1.3  2001/03/22 00:33:16  thiessen
  1193. * initial threading working (PSSM only); free color storage in undo stack
  1194. *
  1195. * Revision 1.2  2001/02/13 01:03:56  thiessen
  1196. * backward-compatible domain ID's in output; add ability to delete rows
  1197. *
  1198. * Revision 1.1  2001/02/08 23:01:49  thiessen
  1199. * hook up C-toolkit stuff for threading; working PSSM calculation
  1200. *
  1201. */