Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
non_scorefxn_exact_model.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet;
3 //
4 // This file is part of the Rosetta software suite and is made available under license.
5 // The Rosetta software is developed by the contributing members of the Rosetta Commons consortium.
6 // (C) 199x-2009 Rosetta Commons participating institutions and developers.
7 // For more information, see http://www.rosettacommons.org/.
8 
9 /// @brief
10 /// @author jk
11 
12 // Project Headers
13 // AUTO-REMOVED #include <core/scoring/geometric_solvation/non_scorefxn_exact_model.hh>
15 // AUTO-REMOVED #include <core/init.hh>
16 #include <core/types.hh>
17 // AUTO-REMOVED #include <core/io/pdb/pose_io.hh>
18 // AUTO-REMOVED #include <core/id/AtomID.hh>
19 // AUTO-REMOVED #include <core/id/AtomID_Map.hh>
20 // AUTO-REMOVED #include <core/id/AtomID_Map.Pose.hh>
21 #include <core/pose/Pose.hh>
22 // AUTO-REMOVED
24 // AUTO-REMOVED #include <core/chemical/ResidueTypeSet.hh>
25 // AUTO-REMOVED #include <core/conformation/ResidueFactory.hh>
27 #include <core/scoring/Energies.hh>
28 // AUTO-REMOVED #include <core/scoring/rms_util.hh>
31 // AUTO-REMOVED #include <core/scoring/ScoreFunction.hh>
32 // AUTO-REMOVED #include <core/scoring/ScoreFunctionFactory.hh>
34 // AUTO-REMOVED #include <basic/options/util.hh>
35 #include <basic/Tracer.hh>
36 
40 // AUTO-REMOVED #include <core/scoring/hbonds/constants.hh>
41 
42 // AUTO-REMOVED #include <numeric/constants.hh>
43 #include <numeric/xyzVector.hh>
44 #include <numeric/xyzMatrix.hh>
45 
46 //#include <core/scoring/ScoreFunction.hh>
47 //#include <core/scoring/ScoreFunctionFactory.hh>
48 
49 // AUTO-REMOVED #include <basic/options/option_macros.hh>
50 
51 // Utility Headers
52 #include <utility/vector1.hh>
53 // AUTO-REMOVED #include <utility/io/ozstream.hh>
54 
55 // C++ Headers
56 #include <cmath>
57 #include <iostream>
58 #include <iomanip>
59 #include <map>
60 
63 #include <core/kinematics/Jump.hh>
64 #include <numeric/xyz.functions.hh>
65 
66 
67 
68 
69 //Vector dummy_res_energy_vector_;
70 
71 static basic::Tracer TR( "core.scoring.geometric_solvation.exact_model" );
72 
73 namespace core {
74 namespace scoring {
75 namespace geometric_solvation {
76 
77 using namespace core;
78 using namespace core::scoring;
79 using namespace core::scoring::hbonds;
80 
81 core::Real const geosol_kT = { 0.593 };
82 
83 // apply this weight to everything, so that scale will match LK
85 
86 
88  pose::Pose & input_pose,
89  core::Size const polar_resnum,
90  core::Size const polar_atomno,
92  GridInfo const & grid_info,
93  core::Real const & grid_constant,
94  std::vector < std::vector < std::vector <core::Real> > > const & water_weights,
95  std::vector < std::vector < std::vector <bool> > > & occluded_sites,
96  bool const hydrogens_can_occlude,
97  bool const pairwise_additive,
98  bool const pairwise_additive_output,
99  utility::vector1 <core::Real> & residue_energies ) {
100 
101  core::Real const water_radius = 1.4;
102 
103  if ( pairwise_additive_output && ! pairwise_additive ) {
104  TR << "Error - pairwise additive output doesn't make sense when calculations are not pairwise additive!!" << std::endl;
105  exit(1);
106  }
107 
108  // Reset grid of occluded sites, by setting everything to false (for "not occluded")
109  for (core::Size tx=0;tx<grid_info.xnum_points();tx++){
110  for (core::Size ty=0;ty<grid_info.ynum_points();ty++){
111  for (core::Size tz=0;tz<grid_info.znum_points();tz++){
112  occluded_sites[tx][ty][tz] = false;
113  }
114  }
115  }
116 
117  // Find the transformation which puts the donor/acceptor of interest onto the existing grid
118  // The plan is to apply this transformation to bring each occluding atom onto the existing grid (translation then matrix multiplication)
119  core::Size const base_atomno( input_pose.residue(polar_resnum).atom_base( polar_atomno ) );
120  core::Vector const & orig_polar_atom_xyz( input_pose.residue(polar_resnum).atom( polar_atomno ).xyz() );
121  core::Vector const & orig_base_atom_xyz( input_pose.residue(polar_resnum).atom( base_atomno ).xyz() );
122  core::Vector translation_vector = -1.0 * orig_polar_atom_xyz;
123  core::Vector translated_base_atom = orig_base_atom_xyz + translation_vector;
124 
125  // We want to translate positions of occluding atoms _from_ a cartesian basis set into one using the reference frame of the polar group
126  core::Vector cartesian_x(1,0,0);
127  core::Vector cartesian_y(0,1,0);
128  core::Vector cartesian_z(0,0,1);
129 
130  // There's not a unique solution for this, so we'll arbitrarily pick a second basis vector, requiring that the dot product with desired_z is zero
131  core::Vector desired_z = -1. * translated_base_atom.normalized();
132 
133  // Treat the case where polar_atom.z == base_atom.z ; this leads to desired_z.z == 0
134  core::Real arbitrary_x, arbitrary_y, arbitrary_z;
135  if ( std::abs( desired_z.z() ) > 0.01 ) {
136  arbitrary_x = 1;
137  arbitrary_y = 1;
138  arbitrary_z = -1. * ((arbitrary_x * desired_z.x()) + (arbitrary_y * desired_z.y())) / desired_z.z();
139  } else {
140  arbitrary_x = 1;
141  arbitrary_z = 1;
142  arbitrary_y = -1. * ((arbitrary_x * desired_z.x()) + (arbitrary_z * desired_z.z())) / desired_z.y();
143  }
144  core::Vector desired_x(arbitrary_x,arbitrary_y,arbitrary_z);
145  desired_x.normalize();
146  core::Vector desired_y = cross_product( desired_x, desired_z );
147 
148  // The transformation matrix to do this is i.i' i.j', etc. where i,j,k are the unit vectors of the starting system
149  // and i',j',k' are the unit vectors of the target system
150  // for reference see http://kwon3d.com/theory/transform/transform.html
151  numeric::xyzMatrix< Length > transformation_matrix;
152  transformation_matrix.xx( desired_x.dot(cartesian_x) );
153  transformation_matrix.xy( desired_x.dot(cartesian_y) );
154  transformation_matrix.xz( desired_x.dot(cartesian_z) );
155  transformation_matrix.yx( desired_y.dot(cartesian_x) );
156  transformation_matrix.yy( desired_y.dot(cartesian_y) );
157  transformation_matrix.yz( desired_y.dot(cartesian_z) );
158  transformation_matrix.zx( desired_z.dot(cartesian_x) );
159  transformation_matrix.zy( desired_z.dot(cartesian_y) );
160  transformation_matrix.zz( desired_z.dot(cartesian_z) );
161 
162  // Double-check transformation matrix
163  core::Vector new_base_atom_location = transformation_matrix * translated_base_atom;
164  assert( std::abs(new_base_atom_location.normalized().x()) < 0.001 );
165  assert( std::abs(new_base_atom_location.normalized().y()) < 0.001 );
166  assert( std::abs(new_base_atom_location.normalized().z() + 1.) < 0.001 );
167 
168  // Loop over all atoms of neighboring residues, INCLUDING SELF
169  core::scoring::TenANeighborGraph const & graph = input_pose.energies().tenA_neighbor_graph();
170  utility::vector1 <core::Size> neighborlist;
171  neighborlist.push_back( polar_resnum);
173  neighbor_iter = graph.get_node( polar_resnum )->const_edge_list_begin(),
174  neighbor_iter_end = graph.get_node( polar_resnum )->const_edge_list_end();
175  neighbor_iter != neighbor_iter_end; ++neighbor_iter ) {
176  neighborlist.push_back( (*neighbor_iter)->get_other_ind( polar_resnum ) );
177  }
178 
179  for ( Size occ_inx = 1; occ_inx <= neighborlist.size(); ++occ_inx ) {
180  core::Size const occ_resnum( neighborlist[occ_inx] );
181  conformation::Residue const occ_rsd = input_pose.residue(occ_resnum);
182  // TR << "jk computing occlusion of polar residue " << polar_resnum << " by residue " << occ_resnum << std::endl;
183 
184  for ( Size occ_atomno = 1; occ_atomno <= occ_rsd.natoms(); ++occ_atomno ) {
185 
186  bool const occ_atom_is_hydrogen = occ_rsd.atom_is_hydrogen( occ_atomno );
187  if ( occ_atom_is_hydrogen && ! hydrogens_can_occlude ) continue;
188 
189  // can be occluded by atoms directly bonded to this group, but not by self
190  if ( polar_resnum == occ_resnum ) {
191  if ( polar_atomno == occ_atomno ) continue;
192  if ( base_atomno == occ_atomno ) continue;
193  }
194 
195  // If pairwise-additive, reset grid of occluded sites for every atom
196  if ( pairwise_additive ) {
197  for (core::Size tx=0;tx<grid_info.xnum_points();tx++){
198  for (core::Size ty=0;ty<grid_info.ynum_points();ty++){
199  for (core::Size tz=0;tz<grid_info.znum_points();tz++){
200  occluded_sites[tx][ty][tz] = false;
201  }
202  }
203  }
204  }
205 
206  // Apply the transformation to put this atom onto the current grid
207  core::Vector const & orig_occ_atom_xyz( occ_rsd.atom( occ_atomno ).xyz() );
208  core::Vector const translated_occ_atom_xyz = orig_occ_atom_xyz + translation_vector;
209  core::Vector const transformed_occ_atom_xyz = transformation_matrix * ( orig_occ_atom_xyz + translation_vector );
210 
211  // Double-check transformations
212  assert( std::abs(orig_polar_atom_xyz.distance( orig_occ_atom_xyz ) - transformed_occ_atom_xyz.magnitude()) < 0.001 );
213  assert( std::abs(orig_base_atom_xyz.distance( orig_occ_atom_xyz ) - new_base_atom_location.distance( transformed_occ_atom_xyz )) < 0.001 );
214  // Find sites occluded by this atom, set these to true
215  core::Real const occ_radius = etable_ptr->lj_radius( occ_rsd.atom_type_index( occ_atomno ) );
216  core::Real const sq_dist_cut = ( occ_radius + water_radius ) * ( occ_radius + water_radius );
217 
218  // Loop over all water positions, mark those which are occluded
219  core::Vector water_position(grid_info.xorigin(),grid_info.yorigin(),grid_info.zorigin());
220  for (core::Size wx=0;wx<grid_info.xnum_points();wx++){
221  water_position.x() += grid_info.xstep();
222  core::Real sq_xdist = ( water_position.x() - transformed_occ_atom_xyz.x() ) * ( water_position.x() - transformed_occ_atom_xyz.x() );
223  if ( sq_xdist > sq_dist_cut ) continue;
224  water_position.y() = grid_info.yorigin();
225  for (core::Size wy=0;wy<grid_info.ynum_points();wy++){
226  water_position.y() += grid_info.ystep();
227  core::Real sq_ydist = ( water_position.y() - transformed_occ_atom_xyz.y() ) * ( water_position.y() - transformed_occ_atom_xyz.y() );
228  if ( sq_ydist > sq_dist_cut ) continue;
229  water_position.z() = grid_info.zorigin();
230  for (core::Size wz=0;wz<grid_info.znum_points();wz++){
231  water_position.z() += grid_info.zstep();
232  core::Real sq_zdist = ( water_position.z() - transformed_occ_atom_xyz.z() ) * ( water_position.z() - transformed_occ_atom_xyz.z() );
233  if ( sq_zdist > sq_dist_cut ) continue;
234  core::Real sq_curr_dist = sq_xdist + sq_ydist + sq_zdist;
235  if ( sq_curr_dist < sq_dist_cut ) {
236  // this atom occludes this water site
237  occluded_sites[wx][wy][wz] = true;
238  }
239  }
240  }
241  }
242 
243  if ( pairwise_additive ) {
244  // For pairwise additive version, compute and save energy for every occluding atom separately
245  core::Real sum_occluded_weights(0.);
246  for (core::Size tx=0;tx<grid_info.xnum_points();tx++){
247  for (core::Size ty=0;ty<grid_info.ynum_points();ty++){
248  for (core::Size tz=0;tz<grid_info.znum_points();tz++){
249  if ( occluded_sites[tx][ty][tz] ) {
250  core::Real const curr_water_weight = water_weights[tx][ty][tz];
251  sum_occluded_weights += curr_water_weight;
252  }
253  }
254  }
255  }
256  core::Real const geometric_solvation_energy = - geosol_kT * log( 1 - ( sum_occluded_weights / grid_constant ) );
257  if ( pairwise_additive_output ) {
258  // For pairwise additive output, split the energy between polar and occluding residue (eg. to match form used in scorefxn)
259  residue_energies[ polar_resnum ] += geometric_solvation_energy / 2.;
260  residue_energies[ occ_resnum ] += geometric_solvation_energy / 2.;
261  } else {
262  // For testing, write output in the non-pairwise additive format (eg. to compare to non-pairwise additive model)
263  residue_energies[ polar_resnum ] += geometric_solvation_energy;
264  }
265  }
266 
267  }
268  }
269 
270  if ( ! pairwise_additive ) {
271  // Compute and store the solvation energy for the grid occluded by all nearby atoms
272  // Compute the numerator (the sum of occluded weights)
273  core::Real sum_occluded_weights(0.);
274  for (core::Size tx=0;tx<grid_info.xnum_points();tx++){
275  for (core::Size ty=0;ty<grid_info.ynum_points();ty++){
276  for (core::Size tz=0;tz<grid_info.znum_points();tz++){
277  if ( occluded_sites[tx][ty][tz] ) {
278  core::Real const curr_water_weight = water_weights[tx][ty][tz];
279  sum_occluded_weights += curr_water_weight;
280  }
281  }
282  }
283  }
284  // If we have a non-pairwise additive model, we can't split the energy between the polar and occluding residues
285  core::Real const geometric_solvation_energy = - geosol_kT * log( 1 - ( sum_occluded_weights / grid_constant ) );
286  residue_energies[ polar_resnum ] += geometric_solvation_energy;
287  }
288 
289  return;
290 }
291 
292 
294  pose::Pose & input_pose,
295  bool const hydrogens_can_occlude,
296  bool const pairwise_additive,
297  bool const pairwise_additive_output,
298  utility::vector1<core::Real> & residue_energies ) {
299 
300  TR << "jk geometric solvation exact scoring" << std::endl;
301 
302  residue_energies.clear();
303  residue_energies.resize( input_pose.total_residue(), 0.);
304 
305  // Get a copy of the Etable (to lookup atomic radii)
307 
308  // Allocate memory for grid of occluded sites
309  std::vector < std::vector < std::vector <bool> > > occluded_sites;
310  occluded_sites.clear();
311  occluded_sites.resize(GridInfo::get_instance()->xnum_points());
312  for (core::Size tx=0;tx<GridInfo::get_instance()->xnum_points();tx++){
313  occluded_sites[tx].resize(GridInfo::get_instance()->ynum_points());
314  for (core::Size ty=0;ty<GridInfo::get_instance()->ynum_points();ty++){
315  occluded_sites[tx][ty].resize(GridInfo::get_instance()->znum_points());
316  }
317  }
318 
319  // get exact geometric solvation scores as a fxn of residue number
320  TR << "jk computing exact solvation scores" << std::endl;
321  for ( Size polar_resnum = 1; polar_resnum <= input_pose.total_residue(); polar_resnum++ ) {
322 
323  conformation::Residue const polar_rsd = input_pose.residue(polar_resnum);
324 
325  // loop over donors in polar_rsd
326  for ( chemical::AtomIndices::const_iterator
327  hnum = polar_rsd.Hpos_polar().begin(),
328  hnume = polar_rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
329  Size const polar_atom( *hnum );
330  Size const base_atom( polar_rsd.atom_base( polar_atom ) );
331  hbonds::HBEvalTuple const curr_hbond_eval_tuple(
332  get_hb_don_chem_type( polar_atom, polar_rsd ),
334 
335  // Figure out max LK energy
336  std::string const base_atom_name = polar_rsd.atom_name( base_atom );
337  core::Real max_possible_LK = etable_ptr->lk_dgfree( polar_rsd.atom_type_index( base_atom ) );
338  if ( ( base_atom_name == " N " ) && polar_rsd.is_lower_terminus() ) max_possible_LK /= 3; // charged N-terminus
339  if ( base_atom_name == " NZ " ) max_possible_LK /= 3; // Lys
340  if ( base_atom_name == " ND2" ) max_possible_LK /= 2; // Asn
341  if ( base_atom_name == " NE2" ) max_possible_LK /= 2; // Gln
342  if ( base_atom_name == " NH1" ) max_possible_LK /= 2; // Arg
343  if ( base_atom_name == " NH2" ) max_possible_LK /= 2; // Arg
344  // Note: inner nitrogen of Arg (NE) is extra strong, since it's the same atom type as the other two but doesn't get
345  // cut in half because there's only one proton...
346  // TR << "jk max LK for donor with base " << base_atom_name << " is " << max_possible_LK << std::endl;
347 
348  // Compute Ebulk (using the LK energy)
349  core::Real const Emax_weight = exp( max_possible_LK / geosol_kT );
350  core::Real const sum_water_weights = WaterWeightGridSet::get_instance()->get_sum_water_weight_grid( curr_hbond_eval_tuple.eval_type() );
351  core::Real const Ebulk_weight = ( sum_water_weights * Emax_weight ) / ( 1. - Emax_weight);
352  // This grid constant is the denominator in computing solvation energies,
353  // it depends on the grid dimensions, and sets the max possible solvation energy (in this case to match LK)
354  core::Real const grid_constant = sum_water_weights + Ebulk_weight;
355  // Setup then call compute_individual_sol_energies
356  add_to_individual_sol_energies(input_pose, polar_resnum, polar_atom, etable_ptr, *GridInfo::get_instance(), grid_constant,
357  WaterWeightGridSet::get_instance()->get_water_weight_grid( curr_hbond_eval_tuple.eval_type() ), occluded_sites, hydrogens_can_occlude,
358  pairwise_additive, pairwise_additive_output, residue_energies );
359  }
360 
361  // loop over acceptors in polar_rsd
362  for ( chemical::AtomIndices::const_iterator
363  anum = polar_rsd.accpt_pos().begin(),
364  anume = polar_rsd.accpt_pos().end(); anum != anume; ++anum ) {
365  Size const polar_atom( *anum );
366  Size const base_atom ( polar_rsd.atom_base( polar_atom ) );
367  hbonds::HBEvalType const curr_hbeval_type = hbonds::HBEval_lookup( hbdon_H2O, get_hb_acc_chem_type( polar_atom, polar_rsd ), seq_sep_other);
368 
369  // Figure out max LK energy
370  std::string const base_atom_name = polar_rsd.atom_name( base_atom );
371  core::Real max_possible_LK = etable_ptr->lk_dgfree( polar_rsd.atom_type_index( polar_atom ) );
372  // TR << "jk max LK for acceptor " << polar_rsd.atom_name(polar_atom) << " is " << max_possible_LK << std::endl;
373  // Compute Ebulk (using the LK energy)
374  core::Real const Emax_weight = exp( max_possible_LK / geosol_kT );
375  core::Real const sum_water_weights = WaterWeightGridSet::get_instance()->get_sum_water_weight_grid( curr_hbeval_type );
376  core::Real const Ebulk_weight = ( sum_water_weights * Emax_weight ) / ( 1. - Emax_weight);
377  // This grid constant is the denominator in computing solvation energies,
378  // it depends on the grid dimensions, and sets the max possible solvation energy (in this case to match LK)
379  core::Real const grid_constant = sum_water_weights + Ebulk_weight;
380  // Setup then call compute_individual_sol_energies
381  add_to_individual_sol_energies(input_pose, polar_resnum, polar_atom, etable_ptr, *GridInfo::get_instance(), grid_constant,
382  WaterWeightGridSet::get_instance()->get_water_weight_grid( curr_hbeval_type ), occluded_sites, hydrogens_can_occlude,
383  pairwise_additive, pairwise_additive_output, residue_energies );
384  }
385 
386  }
387 
388  TR << "jk finished computing exact geometric solvation scores" << std::endl;
389 
390  core::Real total_solvation_energy(0.);
391  for ( Size i = 1; i <= input_pose.total_residue(); i++ ) {
392  residue_energies[i] *= LK_MATCHING_WEIGHT_OLD_EXACT;
393  total_solvation_energy += residue_energies[i];
394  }
395 
396  return total_solvation_energy;
397 }
398 
399 
400 } // geometric_solvation
401 } // scoring
402 } // core
403