CalculateGridmaps.cpp
上传用户:chinafayin
上传日期:2022-04-05
资源大小:153k
文件大小:19k
源码类别:

并行计算

开发平台:

Visual C++

  1. /*
  2.     FastGrid (formerly AutoGrid)
  3.     Copyright (C) 2009 The Scripps Research Institute. All rights reserved.
  4.     Copyright (C) 2009 Masaryk University. All rights reserved.
  5.     AutoGrid is a Trade Mark of The Scripps Research Institute.
  6.     This program is free software; you can redistribute it and/or
  7.     modify it under the terms of the GNU General Public License
  8.     as published by the Free Software Foundation; either version 2
  9.     of the License, or (at your option) any later version.
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17. */
  18. #include "CalculateGridmaps.h"
  19. #include "SpatialGrid.h"
  20. #include "NearestNeighborSearch3.h"
  21. #include "Utils.h"
  22. #define USE_SPATIAL_GRID
  23. #define USE_NNS
  24. struct HBondInfo
  25. {
  26.     struct Info
  27.     {
  28.         double min, max;
  29.         bool flag;
  30.     } info[MAX_MAPS];
  31.     inline HBondInfo(int numAtomMaps)
  32.     {
  33.         Info def;
  34.         def.min = 999999;
  35.         def.max = -999999;
  36.         def.flag = false;
  37.         for (int m = 0; m < numAtomMaps; m++)
  38.             info[m] = def;
  39.     }
  40.     inline Info &operator [](int i)
  41.     {
  42.         return info[i];
  43.     }
  44.     inline void insert(int mapIndex, double energy)
  45.     {
  46.         Info &i = info[mapIndex];
  47.         i.min = Mathd::Min(i.min, energy);
  48.         i.max = Mathd::Max(i.max, energy);
  49.         i.flag = true;
  50.     }
  51. };
  52. static inline int findClosestHBond(const InputData *input, const Vec3d &gridPos)
  53. {
  54.     int closestH = 0;
  55.     double rminSq = Mathd::Sqr(999999.0);
  56.     for (int ia = 0; ia < input->numReceptorAtoms; ia++)
  57.         if (input->hbond[ia] == DS || input->hbond[ia] == D1)
  58.         {
  59.             // DS or D1
  60.             Vec3d distance = Vec3d(input->receptorAtom[ia]) - gridPos;
  61.             double rSq = distance.MagnitudeSqr();
  62.             if (rSq < rminSq)
  63.             {
  64.                 rminSq = rSq;
  65.                 closestH = ia;
  66.             }
  67.         }           // Hydrogen test
  68.     return closestH;
  69. }
  70. static inline void getHBondAngularFunction(const InputData *input, const BondVectors *bondVectors, int ia, int closestH, const Vec3d &distance,
  71.                              double &racc, double &rdon, double &Hramp) // output
  72. {
  73.     racc = 1;
  74.     rdon = 1;
  75.     Hramp = 1;   // Hramp ramps in Hbond acceptor probes
  76.     //  cosTheta = distance dot bondVectors->rvector == cos(angle) subtended.
  77.     double cosTheta = -Vec3d::Dot(distance, bondVectors->rvector[ia]);
  78.     // Calculate racc/rdon/Hramp
  79.     if (input->hbond[ia] == D1)
  80.     {
  81.         // D1
  82.         //  ia-th receptor atom = Hydrogen (4 = H)
  83.         //  => receptor H-bond donor, OH or NH.
  84.         //  calculate racc for H-bond ACCEPTOR PROBES at this grid pt.
  85.         racc = 0;
  86.         //  H->current-grid-pt vector < 90 degrees from
  87.         //  N->H or O->H vector,
  88.         if (cosTheta > 0)
  89.         {
  90.             //  racc = [cos(theta)]^2.0 for N-H
  91.             //  racc = [cos(theta)]^4.0 for O-H
  92.             racc = cosTheta;
  93.             switch (bondVectors->rexp[ia]) // racc = pow(cosTheta, bondVectors->rexp[ia]);
  94.             {
  95.             case 4:
  96.                 racc = Mathd::Sqr(racc);
  97.             case 2:
  98.                 racc = Mathd::Sqr(racc);
  99.             }
  100.             // NEW2 calculate dot product of bond vector with bond vector of best input->hbond
  101.             if (ia != closestH)
  102.             {
  103.                 double theta = Vec3d::AngleUnnorm(bondVectors->rvector[closestH], bondVectors->rvector[ia]);
  104.                 Hramp = 0.5 - 0.5 * cos(theta * (120.0 / 90.0));
  105.             }   // ia test
  106.             // END NEW2 calculate dot product of bond vector with bond vector of best input->hbond
  107.         }
  108.         // endif (input->atomType[ia] == hydrogen)
  109.     }
  110.     else if (input->hbond[ia] == A1)
  111.     {
  112.         // NEW Directional N acceptor
  113.         //  ia-th macromolecule atom = Nitrogen (4 = H)
  114.         //  calculate rdon for H-bond Donor PROBES at this grid pt.
  115.         //  H->current-grid-pt vector < 90 degrees from X->N vector
  116.         rdon = 0;
  117.         if (cosTheta > 0)
  118.             rdon = Mathd::Sqr(cosTheta); // for H->N
  119.         // endif (input->atomType[ia] == nitrogen)
  120.         // end NEW Directional N acceptor
  121.     }
  122.     else if (input->hbond[ia] == A2)
  123.     {
  124.         rdon = 0;
  125.         if (bondVectors->disorder[ia])
  126.         {
  127.             // A2
  128.             // cylindrically disordered hydroxyl
  129.             racc = 0;
  130.             double theta = Mathd::Acos(cosTheta);
  131.             if (theta <= 1.24791 + (PI / 2))
  132.             {
  133.                 // 1.24791 rad = 180 deg minus C-O-H bond angle, ** 108.5 deg
  134.                 rdon = Mathd::Sqr(Mathd::Sqr(cos(theta - 1.24791)));    // pow(.., 4)
  135.                 racc = rdon;
  136.             }
  137.         }
  138.         else
  139.         {
  140.             // A2
  141.             //  ia-th receptor atom = Oxygen
  142.             //  => receptor H-bond acceptor, oxygen.
  143.             // rdon expressions from Goodford
  144.             if (cosTheta >= 0)
  145.             {
  146.                 // ti is the angle in the lone pair plane, away from the
  147.                 // vector between the lone pairs,
  148.                 // calculated as (grid vector CROSS lone pair plane normal)
  149.                 // DOT C=O vector - 90 deg
  150.                 Vec3d cross = Vec3d::Cross(distance, bondVectors->rvector2[ia]);
  151.                 double rd2 = cross.MagnitudeSqr();
  152.                 if (rd2 < APPROX_ZERO)
  153.                     rd2 = APPROX_ZERO;
  154.                 double inv_rd = Mathd::Rsqrt(rd2);
  155.                 double ti = fabs(Mathd::Acos(inv_rd * Vec3d::Dot(cross, bondVectors->rvector[ia])) - (PI / 2));
  156.                 // the 2.0*ti can be replaced by (ti + ti) in: rdon = (0.9 + 0.1*sin(2.0*ti))*cos(t0);
  157.                 rdon = 0.9 + 0.1 * sin(ti + ti);
  158.                 // 0.34202 = cos (100 deg)
  159.             }
  160.             else if (cosTheta >= -0.34202)
  161.                 rdon = 562.25 * Mathd::Cube(0.116978 - Mathd::Sqr(cosTheta));
  162.             // t0 is the angle out of the lone pair plane, calculated
  163.             // as 90 deg - acos (vector to grid point DOT lone pair
  164.             // plane normal)
  165.             double t0 = (PI / 2) - Vec3d::AngleUnnorm(distance, bondVectors->rvector2[ia]);
  166.             rdon *= cos(t0);
  167.             // endif input->atomType == oxygen, not disordered
  168.         }
  169.     }
  170. }
  171. static inline void sumPairwiseInteractions(const InputData *input, const GridMapList &gridmaps, const PairwiseInteractionEnergies &energyLookup,
  172.                              const DesolvExpFunc &desolvExpFunc, const BondVectors *bondVectors, HBondInfo &hbond,
  173.                              int outputIndex, int m, int ia, int indexR, int hydrogen, double racc, double rdon, double Hramp)
  174. {
  175.     double &e = gridmaps[m].energies[outputIndex];
  176.     double pwiEnergy = energyLookup(input->atomType[ia], indexR, m);
  177.     if (gridmaps[m].isHBonder)
  178.     {
  179.         // PROBE forms H-bonds...
  180.         // rsph ramps in angular dependence for distances with negative energy
  181.         double rsph = Mathd::Saturate(pwiEnergy / 100);
  182.         if ((gridmaps[m].hbond == AS || gridmaps[m].hbond == A2) && (input->hbond[ia] == DS || input->hbond[ia] == D1))
  183.             // PROBE can be an H-BOND ACCEPTOR,
  184.             e += (bondVectors->disorder[ia] ? energyLookup(hydrogen, Mathi::Max(0, indexR - 110), m) : pwiEnergy) *
  185.                  Hramp * (racc + (1 - racc) * rsph);
  186.         else if (gridmaps[m].hbond == A1 && (input->hbond[ia] == DS || input->hbond[ia] == D1))
  187.             // A1 vs DS, D1
  188.             hbond.insert(m, pwiEnergy * (racc + (1 - racc) * rsph));
  189.         else if ((gridmaps[m].hbond == DS || gridmaps[m].hbond == D1) && input->hbond[ia] >= AS)
  190.             // DS,D1 vs AS,A1,A2
  191.             // PROBE is H-BOND DONOR,
  192.             hbond.insert(m, pwiEnergy * (rdon + (1 - rdon) * rsph));
  193.         else
  194.             // hbonder PROBE-ia cannot form a H-bond...,
  195.             e += pwiEnergy;
  196.     }
  197.     else
  198.         // PROBE does not form H-bonds...,
  199.         e += pwiEnergy;
  200.     // add desolvation energy
  201.     // forcefield desolv coefficient/weight in desolvExpFunc
  202.     e += gridmaps[m].solparProbe * input->vol[ia] * desolvExpFunc(indexR) +
  203.         (input->solpar[ia] + input->solparQ * fabs(input->charge[ia])) * gridmaps[m].volProbe * desolvExpFunc(indexR);
  204. }
  205. template<int UseNNS, int UseCutoffGrid>
  206. static inline void calculateGridPoint(const InputData *input, GridMapList &gridmaps, int hydrogen,
  207.                        const PairwiseInteractionEnergies &energyLookup, const DesolvExpFunc &desolvExpFunc, const BondVectors *bondVectors,
  208.                        const SpatialGrid &cutoffGrid, const int *indicesHtoA, const NearestNeighborSearch3d &hsearch,
  209.                        const Vec3d &gridPos, int outputIndex)
  210. {
  211.     HBondInfo hbond(gridmaps.getNumAtomMaps());
  212.     int closestH;
  213.     if (UseNNS)
  214.         closestH = indicesHtoA[hsearch.searchNearest(gridPos)];
  215.     else
  216.         closestH = findClosestHBond(input, gridPos);
  217.     //  Do all Receptor (protein, DNA, etc.) atoms...
  218.     int num;
  219.     SpatialCell cell = 0;
  220.     if (UseCutoffGrid)
  221.     {
  222.         cell = cutoffGrid.getCellFromPos(gridPos);
  223.         num = cutoffGrid.getNumElements(cell);
  224.     }
  225.     else
  226.         num = input->numReceptorAtoms;
  227.     for (int index = 0; index < num; index++)
  228.     {
  229.         int ia = UseCutoffGrid ? cutoffGrid.getElement(cell, index) : index;
  230.         // If distance from grid point to atom ia is too large,
  231.         // or if atom is a disordered hydrogen,
  232.         //   add nothing to the grid-point's non-bond energy;
  233.         //   just continue to next atom...
  234.         //  Get distance from current grid point to this receptor atom
  235.         Vec3d distance = Vec3d(input->receptorAtom[ia]) - gridPos;
  236.         // rSq = |distance|^2
  237.         double rSq = distance.MagnitudeSqr();
  238.         if (rSq > Mathd::Sqr(NBCUTOFF))
  239.             continue;   // onto the next atom...
  240.         if (input->atomType[ia] == hydrogen && bondVectors->disorder[ia])
  241.             continue;   // onto the next atom...
  242.         // Normalize the distance vector
  243.         if (rSq < Mathd::Sqr(APPROX_ZERO*APPROX_ZERO))
  244.             rSq = Mathd::Sqr(APPROX_ZERO*APPROX_ZERO);
  245.         double invR = Mathd::Rsqrt(rSq);
  246.         distance *= invR;
  247.         int indexR = angstromToIndex<int>(1 / invR);
  248.         double racc, rdon, Hramp;
  249.         getHBondAngularFunction(input, bondVectors, ia, closestH, distance, racc, rdon, Hramp);
  250.         // For each probe atom-type,
  251.         // Sum pairwise interactions between each probe
  252.         // at this grid point (gridPos[0:2])
  253.         // and the current receptor atom, ia...
  254.         for (int m = 0; m < gridmaps.getNumAtomMaps(); m++)
  255.             if (!gridmaps[m].isCovalent)
  256.                 sumPairwiseInteractions(input, gridmaps, energyLookup, desolvExpFunc, bondVectors, hbond, outputIndex, m, ia, indexR, hydrogen, racc, rdon, Hramp);
  257.         gridmaps.getDesolvationMap().energies[outputIndex] += input->solparQ * input->vol[ia] * desolvExpFunc(indexR);
  258.     } // ia loop, over all receptor atoms...
  259.     // Adjust maps of hydrogen-bonding atoms by adding largest and
  260.     // smallest interaction of all 'pair-wise' interactions with receptor atoms
  261.     for (int m = 0; m < gridmaps.getNumAtomMaps(); m++)
  262.     {
  263.         double &e = gridmaps[m].energies[outputIndex];
  264.         if (hbond[m].flag)
  265.             e += hbond[m].min + hbond[m].max;
  266.         e = roundOutput(e);
  267.     }
  268.     double &e = gridmaps.getDesolvationMap().energies[outputIndex];
  269.     e = roundOutput(e);
  270. }
  271. template<int UseNNS, int UseCutoffGrid>
  272. static void LoopOverGrid(const InputData *input, GridMapList &gridmaps, int hydrogen,
  273.                        const PairwiseInteractionEnergies &energyLookup, const DesolvExpFunc &desolvExpFunc, const BondVectors *bondVectors,
  274.                        const SpatialGrid &cutoffGrid, const int *indicesHtoA, const NearestNeighborSearch3d &hsearch)
  275. {
  276. #if defined(AG_OPENMP)
  277.     #pragma omp parallel for schedule(dynamic, 1)
  278. #endif
  279.     FOR_EACH_GRID_POINT(gridPos, outputIndex)
  280.         calculateGridPoint<UseNNS, UseCutoffGrid>(input, gridmaps, hydrogen, energyLookup, desolvExpFunc, bondVectors,
  281.                                                   cutoffGrid, indicesHtoA, hsearch, gridPos, outputIndex);
  282.     END_FOR()
  283. }
  284. static void initCutoffGrid(const InputData *input, const ProgramParameters &programParams, SpatialGrid &cutoffGrid)
  285. {
  286.     Vec3d gridSize = Vec3d(input->numGridPoints) * input->gridSpacing;
  287.     double cellSize = NBCUTOFF/2;
  288. #if 0
  289. // Find distance^2 between two closest atoms
  290. #if defined(AG_OPENMP)
  291.     int subsets = omp_get_max_threads()*4;
  292. #else
  293.     int subsets = 1;
  294. #endif
  295.     int countPerSubset = Mathi::Max(1, int(Mathd::Ceil(double(input->numReceptorAtoms) / subsets)));
  296.     double *minDistances = new double[subsets];
  297.     for (int s = 0; s < subsets; s++)
  298.         minDistances[s] = 10000000;
  299.     NearestNeighborSearch3d search;
  300.     search.create(input->receptorAtom, input->numReceptorAtoms);
  301. #if defined(AG_OPENMP)
  302.     #pragma omp parallel for schedule(dynamic, 1)
  303. #endif
  304.     for (int s = 0; s < subsets; s++)
  305.     {
  306.         int start = s * countPerSubset;
  307.         int end = Mathi::Min((s+1) * countPerSubset - 1, input->numReceptorAtoms - 1);
  308.         for (int i = start; i < end; i++)
  309.         {
  310.             double dist = search.getDistanceSqrOfNearest2(input->receptorAtom[i]);
  311.             if (dist < minDistances[s])
  312.                 minDistances[s] = dist;
  313.         }
  314.     }
  315.     double minDistanceSq = 10000000;
  316.     for (int s = 0; s < subsets; s++)
  317.         if (minDistances[s] < minDistanceSq)
  318.             minDistanceSq = minDistances[s];
  319.     delete [] minDistances;
  320.     // Estimate a lower bound of atom volume
  321.     double minAtomRadius = sqrt(minDistanceSq)/2;
  322.     double minAtomVolume = (4.0/3.0) * 3.14159265358979323846 * Mathd::Cube(minAtomRadius);
  323.     double invMinAtomVolume = 1 / minAtomVolume;
  324.     // Calculate the cell size and the max atoms per cell according to memory usage
  325.     int maxAtomsPerCell = 0;
  326.     int i, iMax = 100;
  327.     for (i = 0; i < iMax; i++, cellSize *= 1.25)
  328.     {
  329.         Vec3d bucketVolume = cutoffGrid.getCorrectCellSize(gridSize, cellSize);
  330.         bucketVolume += NBCUTOFF*2;
  331.         maxAtomsPerCell = int(bucketVolume.Cube() * invMinAtomVolume + 1); // + 1 because of rounding
  332.         if (maxAtomsPerCell > input->numReceptorAtoms)
  333.             maxAtomsPerCell = input->numReceptorAtoms;
  334.         size_t mb = cutoffGrid.estimateMemorySize(gridSize, cellSize, maxAtomsPerCell) >> 20;
  335.         if (mb <= size_t(programParams.getCutoffGridMemoryLimit()))
  336.             break;
  337.         if (programParams.benchmarkEnabled())
  338.             0;//fprintf(stderr, "Cutoff Grid, test failed: Cell size: %f, Max atoms per cell: %i, Grid memory: %i MBn", cellSize, maxAtomsPerCell, mb);
  339.     }
  340.     if (i == iMax)
  341.         fprintf(stderr, "Determining the memory size of the cutoff grid FAILED.n");
  342.     if (programParams.benchmarkEnabled())
  343.     {
  344.         //fprintf(stderr, "Cutoff Grid: Min atom radius: %fn", minAtomRadius);
  345.         //fprintf(stderr, "Cutoff Grid: Max atoms per cell: %in", maxAtomsPerCell);
  346.         //fprintf(stderr, "Cutoff Grid: Cell size: %fn", cellSize);
  347. size_t mb = cutoffGrid.estimateMemorySize(gridSize, cellSize, maxAtomsPerCell);
  348.         fprintf(stderr, "Cutoff Grid: Allocating %1.2f MiBn", mb / double(1<<20));
  349.     }
  350. #endif
  351. cutoffGrid.create(gridSize, cellSize, 0);
  352.     cutoffGrid.insertSpheres(input->numReceptorAtoms, &input->receptorAtom[0], NBCUTOFF);
  353. if (programParams.benchmarkEnabled())
  354. fprintf(stderr, "Cutoff Grid: Allocated %1.2f MiBn", cutoffGrid.getSizeOfMemory() / double(1<<20));
  355. }
  356. static void initHSearch(const InputData *input, NearestNeighborSearch3d &hsearch, int *indicesHtoA)
  357. {
  358.     int numH = 0;
  359.     Vec3d *hcoord = new Vec3d[input->numReceptorAtoms];
  360.     for (int ia = 0; ia < input->numReceptorAtoms; ia++)
  361.         if (input->hbond[ia] == DS || input->hbond[ia] == D1)
  362.         {
  363.             hcoord[numH] = Vec3d(input->receptorAtom[ia]);
  364.             indicesHtoA[numH] = ia;
  365.             ++numH;
  366.         }
  367.     hsearch.create(hcoord, numH, true);
  368. }
  369. void calculateGridmaps(const InputData *input, const ProgramParameters &programParams, GridMapList &gridmaps, const ParameterLibrary &parameterLibrary,
  370.                        const PairwiseInteractionEnergies &energyLookup, const DesolvExpFunc &desolvExpFunc, const BondVectors *bondVectors)
  371. {
  372.     SpatialGrid cutoffGrid;
  373.     NearestNeighborSearch3d hsearch;
  374.     int *indicesHtoA = new int[input->numReceptorAtoms]; // table for translating a H index into a receptor atom index
  375.     if (programParams.useCutoffGrid())
  376.     {
  377.         // Create a grid for a cutoff of distant receptor atoms
  378.         Timer *t0 = 0;
  379.         if (programParams.benchmarkEnabled())
  380.             t0 = Timer::startNew("Cutoff grid            ");
  381.         initCutoffGrid(input, programParams, cutoffGrid);
  382.         if (programParams.benchmarkEnabled())
  383.             t0->stopAndLog(stderr);
  384.     }
  385.     if (programParams.useNNS())
  386.     {
  387.         // Create a tree for finding the closest H
  388.         Timer *t1 = 0;
  389.         if (programParams.benchmarkEnabled())
  390.             t1 = Timer::startNew("KD-tree of hydrogens   ");
  391.         initHSearch(input, hsearch, indicesHtoA);
  392.         if (programParams.benchmarkEnabled())
  393.             t1->stopAndLog(stderr);
  394.     }
  395.     int hydrogen = parameterLibrary.getAtomParameterRecIndex("HD");
  396.     Timer *t2 = 0;
  397.     if (programParams.benchmarkEnabled())
  398.         t2 = Timer::startNew("Atom & desolvation maps");
  399.     // Determine which template parameter to use based on program parameters
  400.     // This enabled/disables the nearest neighbor search and the cutoff grid
  401.     if (programParams.useNNS())
  402.         if (programParams.useCutoffGrid())
  403.             LoopOverGrid<1, 1>(input, gridmaps, hydrogen, energyLookup, desolvExpFunc, bondVectors, cutoffGrid, indicesHtoA, hsearch);
  404.         else
  405.             LoopOverGrid<1, 0>(input, gridmaps, hydrogen, energyLookup, desolvExpFunc, bondVectors, cutoffGrid, indicesHtoA, hsearch);
  406.     else
  407.         if (programParams.useCutoffGrid())
  408.             LoopOverGrid<0, 1>(input, gridmaps, hydrogen, energyLookup, desolvExpFunc, bondVectors, cutoffGrid, indicesHtoA, hsearch);
  409.         else
  410.             LoopOverGrid<0, 0>(input, gridmaps, hydrogen, energyLookup, desolvExpFunc, bondVectors, cutoffGrid, indicesHtoA, hsearch);
  411.     if (programParams.benchmarkEnabled())
  412.         t2->stopAndLog(stderr);
  413.     delete [] indicesHtoA;
  414. }