Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OccludedHbondSolEnergy_onebody.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 /// @file core/scoring/geometric_solvation/OccludedHbondSolEnergy_onebody.cc
10 /// @brief Solvation model based on penalizing potential for Hbonding to solvent
11 /// @author John Karanicolas
12 
13 
14 
15 
16 // NOTES FOR IMPROVED PERFORMANCE / POTENTIAL IMPROVEMENTS....
17 
18 // The GeometricSolvation implementation was context-dependent,
19 // because backbone groups participating in secondary structure
20 // were considered exempt. Here, though, we'll compute their solvation
21 // energy as for any other group (partly since it's not obvious how
22 // else they *should* be treated). This in turn allows this energy
23 // term to be context-independent. The real question is....
24 // what should be the solvation energy for CO in secondary structure??
25 
26 // Probably the best alternative would be to *NOT* compute solvation energies
27 // here for backbone groups in secondary structure, and instead assign
28 // them a fixed solvation penalty. Not clear what this penalty should be though...
29 
30 // It might make sense to precompute and cache scores and derivatives
31 // in eg. a "geometric solvation potential" object,
32 // so that they don't need to be computed over and over again
33 
34 
35 // Unit Headers
40 #include <core/scoring/Energies.hh>
42 // AUTO-REMOVED #include <core/scoring/EnergyGraph.hh>
47 #include <core/pose/Pose.hh>
48 #include <basic/Tracer.hh>
49 // AUTO-REMOVED #include <basic/prof.hh>
50 
51 // Package headers
52 
53 // Project headers
54 #include <numeric/trig.functions.hh>
55 // AUTO-REMOVED #include <numeric/deriv/distance_deriv.hh>
56 // AUTO-REMOVED #include <numeric/deriv/angle_deriv.hh>
57 
58 // Utility headers
59 // AUTO-REMOVED #include <ObjexxFCL/format.hh>
60 
61 #include <utility/vector1.hh>
62 
63 //Auto using namespaces
64 namespace ObjexxFCL { namespace fmt { } } using namespace ObjexxFCL::fmt; // AUTO USING NS
65 //Auto using namespaces end
66 
67 
68 static basic::Tracer tr( "core.scoring.geometric_solvation.OccludedHbondSolEnergy_onebody" );
69 
70 namespace core {
71 namespace scoring {
72 namespace geometric_solvation {
73 
74 using namespace ObjexxFCL::fmt;
75 
76 /// @details This must return a fresh instance of the OccludedHbondSolEnergy_onebody class,
77 /// never an instance already in use
79 OccludedHbondSolEnergy_onebodyCreator::create_energy_method(
80  methods::EnergyMethodOptions const & options
81 ) const {
83 }
84 
86 OccludedHbondSolEnergy_onebodyCreator::score_types_for_method() const {
87  ScoreTypes sts;
88  sts.push_back( occ_sol_fitted_onebody );
89  return sts;
90 }
91 
92 
93 // jumpouts will apply if this is the best possible energy.
94 // this value corresponds to the discontinuity we'll deem acceptable.
95 // deriv_check starts to give bad results with a value of 0.05 (dist=6.6), but is mostly acceptable with 0.01 (dist=7.5)
96 core::Real const MIN_OCC_ENERGY = { 0.01 };
97 
98 
99 OccludedHbondSolEnergy_onebody::OccludedHbondSolEnergy_onebody(
100  methods::EnergyMethodOptions const & options,
101  bool const verbose )
102 :
104  occ_hbond_sol_database_( ScoringManager::get_instance()->get_DatabaseOccSolEne( options.etable_type(), MIN_OCC_ENERGY ) ),
105  verbose_( verbose )
106 {
107  if ( verbose_ ) tr <<"OccludedHbondSolEnergy_onebody constructor" << std::endl;
108 }
109 
111  parent( src ),
112  occ_hbond_sol_database_( src.occ_hbond_sol_database_ ),
113  verbose_( src.verbose_ )
114 {
115  if ( verbose_ ) tr <<"OccludedHbondSolEnergy_onebody constructor" << std::endl;
116 }
117 
120 {
121  return new OccludedHbondSolEnergy_onebody( *this );
122 }
123 
124 void
126 {
128 }
129 
130 void
132  pose::Pose & pose,
133  utility::vector1< bool > const &,
135 ) const
136 {
138 }
139 
140 void
142 {
143  tr << "Error - no derivatives yet for OccludedHbondSolEnergy_onebody (occ_sol_fitted_onebody)" << std::endl;
144  assert(false);
145  exit(1);
146 }
147 
148 void
150 {
151  tr << "Error - no derivatives yet for OccludedHbondSolEnergy_onebody (occ_sol_fitted_onebody)" << std::endl;
152  assert(false);
153  exit(1);
154 }
155 
156 Distance
158 {
159  tr << "atomic_interaction_cutoff is: " << occ_hbond_sol_database_.atomic_interaction_cutoff() << std::endl;
160  // jk max interaction distance is computed using the hydrogen for donors - is this okay? or should we add one to get a heavyatom distance?
161  // probably is doesn't matter, since at worst we'll just end up using an acceptor-based distance, which is fine...
163 }
164 
165 
167  conformation::Residue const & polar_rsd,
168  pose::Pose const & pose,
169  EnergyMap & emap
170 ) const {
171 
172  core::Size polar_resnum = (core::Size) polar_rsd.seqpos();
173  core::Real residue_geosol(0.), energy(0.);
174 
175  // loop over all atoms of neighboring residues, INCLUDING SELF
177  utility::vector1 <core::Size> neighborlist;
178  neighborlist.push_back( polar_resnum);
180  neighbor_iter = graph.get_node( polar_resnum )->const_edge_list_begin(),
181  neighbor_iter_end = graph.get_node( polar_resnum )->const_edge_list_end();
182  neighbor_iter != neighbor_iter_end; ++neighbor_iter ) {
183  neighborlist.push_back( (*neighbor_iter)->get_other_ind( polar_resnum ) );
184  }
185 
186  // cycle through donors in polar_rsd
187  for ( chemical::AtomIndices::const_iterator hnum = polar_rsd.Hpos_polar().begin(), hnume = polar_rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
188  Size const don_h_atom( *hnum );
189  Size const base_atom( polar_rsd.atom_base( don_h_atom ) );
190  core::Real polar_group_energy = 0.;
191  for ( Size occ_inx = 1; occ_inx <= neighborlist.size(); ++occ_inx ) {
192  core::Size const occ_resnum( neighborlist[occ_inx] );
193  conformation::Residue const occ_rsd = pose.residue(occ_resnum);
194  for ( Size occ_atom = 1; occ_atom <= occ_rsd.natoms(); occ_atom++ ) {
195  get_atom_atom_occ_solvation( don_h_atom, base_atom, polar_rsd, occ_atom, occ_rsd, energy );
196  polar_group_energy += energy;
197  }
198  }
199  residue_geosol += polar_group_energy;
200  std::string const base_atom_name = polar_rsd.atom_name( base_atom );
201  // std::cout << "jk FITTED_ONEBODY Donor " << base_atom_name << " " << pose.residue(polar_resnum).aa() << " " << polar_resnum << " " << polar_group_energy << std::endl;
202  }
203 
204  // cycle through acceptors in polar_rsd
205  for ( chemical::AtomIndices::const_iterator anum = polar_rsd.accpt_pos().begin(), anume = polar_rsd.accpt_pos().end(); anum != anume; ++anum ) {
206  Size const acc_atom( *anum );
207  Size const base_atom ( polar_rsd.atom_base( acc_atom ) );
208  core::Real polar_group_energy = 0.;
209  for ( Size occ_inx = 1; occ_inx <= neighborlist.size(); ++occ_inx ) {
210  core::Size const occ_resnum( neighborlist[occ_inx] );
211  conformation::Residue const occ_rsd = pose.residue(occ_resnum);
212  for ( Size occ_atom = 1; occ_atom <= occ_rsd.natoms(); occ_atom++ ) {
213  get_atom_atom_occ_solvation( acc_atom, base_atom, polar_rsd, occ_atom, occ_rsd, energy );
214  polar_group_energy += energy;
215  }
216  }
217  residue_geosol += polar_group_energy;
218  std::string const base_atom_name = polar_rsd.atom_name( base_atom );
219  // std::cout << "jk FITTED_ONEBODY Acceptor " << base_atom_name << " " << pose.residue(polar_resnum).aa() << " " << polar_resnum << " " << polar_group_energy << std::endl;
220  }
221 
222  emap[ occ_sol_fitted_onebody ] += residue_geosol;
223 
224 }
225 
226 
227 
228 Real
230  conformation::Residue const & polar_rsd,
231  conformation::Residue const & occ_rsd ) const
232 {
233 
234  // Rhiju importantly notes: for GeometricSolvation he originally had the code in
235  // the following functions written out inside these loop -- and packing was faster.
236  // Perhaps something to do with inlining or compiler optimization.
237  // I've left it this way for now, because it helps prevent copying too
238  // much of the code shared between residue pair scoring and for the derivatives.
239  // However, if speed becomes important, here's a place to start.
240 
241  // jk note: moved the loop over occluding atoms into the next fxn, this could be the speed diff...
242 
243  Real geo_solE(0.), energy(0.);
244 
245  // cycle through donors in polar_rsd
246  for ( chemical::AtomIndices::const_iterator hnum = polar_rsd.Hpos_polar().begin(), hnume = polar_rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
247  Size const don_h_atom( *hnum );
248  Size const don_base_atom( polar_rsd.atom_base( don_h_atom ) );
249  for ( Size occ_atom = 1; occ_atom <= occ_rsd.natoms(); occ_atom++ ) {
250  get_atom_atom_occ_solvation( don_h_atom, don_base_atom, polar_rsd, occ_atom, occ_rsd, energy );
251  geo_solE += energy;
252  }
253  }
254 
255  // cycle through acceptors in polar_rsd
256  for ( chemical::AtomIndices::const_iterator anum = polar_rsd.accpt_pos().begin(), anume = polar_rsd.accpt_pos().end(); anum != anume; ++anum ) {
257  Size const acc_atom( *anum );
258  Size const base_atom ( polar_rsd.atom_base( acc_atom ) );
259  for ( Size occ_atom = 1; occ_atom <= occ_rsd.natoms(); occ_atom++ ) {
260  get_atom_atom_occ_solvation( acc_atom, base_atom, polar_rsd, occ_atom, occ_rsd, energy );
261  geo_solE += energy;
262  }
263  }
264 
265  return geo_solE;
266 }
267 
268 
269 void
271  Size const polar_atom,
272  Size const base_atom,
273  conformation::Residue const & polar_rsd,
274  Size const occ_atom,
275  conformation::Residue const & occ_rsd,
276  Real & energy
277 ) const
278 {
279 
280  // In case of early return, initialize. Note that energy does NOT accumulate, but f1/f2 do.
281  // Also note that f1 and f2 are returned unweighted.
282  energy = 0.;
283 
284  // note: after testing, hydrogens need not occlude
285  if ( occ_rsd.atom_is_hydrogen(occ_atom) ) return;
286  // if ( occ_atom > occ_rsd.nheavyatoms() ) return;
287 
288  // note: the lines above don't exclude Proline NV...
289  // catch proline NV here (and other virtual atoms, etc.)
290  if ( occ_rsd.atom_type(occ_atom).lj_radius() < 0.1 ) return;
291 
292  // can be occluded by atoms directly bonded to this group, but not by self
293  if ( polar_rsd.seqpos() == occ_rsd.seqpos() ) {
294  if ( polar_atom == occ_atom ) return;
295  if ( base_atom == occ_atom ) return;
296  }
297 
298  bool polar_atom_donates = false;
299  if ( polar_rsd.atom_is_hydrogen(polar_atom) ) polar_atom_donates = true;
300 
301  if ( polar_atom_donates ) {
302  // polar donor cannot be occluded by an acceptor (analogous to exact_occ_skip_Hbonders in exact model, but not quite the same)
303  for ( chemical::AtomIndices::const_iterator anum = occ_rsd.accpt_pos().begin(), anume = occ_rsd.accpt_pos().end(); anum != anume; ++anum ) {
304  if ( occ_atom == *anum ) {
305  return;
306  }
307  }
308  } else {
309  // polar acceptor cannot be occluded by an donor base (analogous to exact_occ_skip_Hbonders in exact model, but not quite the same)
310  for ( chemical::AtomIndices::const_iterator hnum = occ_rsd.Hpos_polar().begin(), hnume = occ_rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
311  Size const don_h_atom( *hnum );
312  if ( occ_atom == occ_rsd.atom_base( don_h_atom ) ) {
313  return;
314  }
315  }
316  }
317 
318  assert( ( polar_atom_donates && atom_is_donor_h( polar_rsd, polar_atom ) ) ||
319  ( ( ! polar_atom_donates ) && atom_is_acceptor( polar_rsd, polar_atom ) ) );
320 
321  // If acceptor, do lookup on polar atom. If donor (ie. polar atom is a hydrogen), use the base atom instead
322  Size polar_atom_type_lookup_index = polar_rsd.atom_type_index( polar_atom );
323  if ( polar_atom_donates ) polar_atom_type_lookup_index = polar_rsd.atom_type_index( base_atom );
324 
325  Vector const & polar_atom_xyz( polar_rsd.atom( polar_atom ).xyz() );
326  Vector const & base_atom_xyz( polar_rsd.atom( base_atom ).xyz() );
327 
328  Size const occ_atom_type_index = occ_rsd.atom_type_index( occ_atom );
329  Vector const & occ_atom_xyz( occ_rsd.atom( occ_atom ).xyz() );
330 
331  // jumpout with no calculations if easy tests are violated, ie. no contribution to solvation energy
332  Real const dist_sq = ( occ_atom_xyz - polar_atom_xyz).length_squared();
333  if ( dist_sq > occ_hbond_sol_database_( polar_atom_donates, polar_atom_type_lookup_index, occ_atom_type_index, OccFitParam_max_sq_dist ) ) return;
334  Real const curr_cos_angle = get_cos_angle( base_atom_xyz, polar_atom_xyz, occ_atom_xyz );
335  if ( curr_cos_angle < occ_hbond_sol_database_( polar_atom_donates, polar_atom_type_lookup_index, occ_atom_type_index, OccFitParam_min_cos_angle ) ) return;
336 
337  // geometric filters are met, compute energy (no derivatives!)
338  // get the appropriate parameters
339  Real const amp = occ_hbond_sol_database_( polar_atom_donates, polar_atom_type_lookup_index, occ_atom_type_index, OccFitParam_amp );
340  Real const dist_mu = occ_hbond_sol_database_( polar_atom_donates, polar_atom_type_lookup_index, occ_atom_type_index, OccFitParam_dist_mu );
341  Real const twice_dist_sigma_sq = occ_hbond_sol_database_( polar_atom_donates, polar_atom_type_lookup_index, occ_atom_type_index, OccFitParam_twice_dist_sigma_sq );
342  Real const cos_angle_mu = occ_hbond_sol_database_( polar_atom_donates, polar_atom_type_lookup_index, occ_atom_type_index, OccFitParam_cos_angle_mu );
343  Real const twice_cos_angle_sigma_sq = occ_hbond_sol_database_( polar_atom_donates, polar_atom_type_lookup_index, occ_atom_type_index, OccFitParam_twice_cos_angle_sigma_sq );
344 
345  // Note: differences are in different order. Doesn't matter for scores, does for derivatives
346  // Briefly, we're in the regime where dist energy contribution gets small as we get big values,
347  // while cos_angle contribution gets small as we get smaller values
348  Real const dist_diff = sqrt(dist_sq) - dist_mu;
349  Real const cos_angle_diff = cos_angle_mu - curr_cos_angle;
350  energy = amp *
351  exp( - ( ( dist_diff * dist_diff / twice_dist_sigma_sq ) + ( cos_angle_diff * cos_angle_diff / twice_cos_angle_sigma_sq ) ) );
352 
353  return;
354 
355 }
356 
357 
358 Real
360  Vector const & polar_atom_xyz,
361  Vector const & occluding_atom_xyz ) const
362 {
363  return dot( (polar_atom_xyz - base_atom_xyz).normalize(), (occluding_atom_xyz - polar_atom_xyz).normalize() );
364 }
365 
366 
367 
368 // Helper function that should live inside conformation::Residue (Rhiju's comment)
370  for ( chemical::AtomIndices::const_iterator hnum = rsd.Hpos_polar().begin(), hnume = rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
371  Size const don_h_atom( *hnum );
372  if ( don_h_atom == atom ) return true;
373  }
374  return false;
375 }
376 
377 // Helper function that should live inside conformation::Residue (Rhiju's comment)
379  for ( chemical::AtomIndices::const_iterator anum = rsd.accpt_pos().begin(), anume = rsd.accpt_pos().end(); anum != anume; ++anum ) {
380  Size const acc_atom( *anum );
381  if ( acc_atom == atom ) return true;
382  }
383  return false;
384 }
385 
386 // Helper function that should live inside conformation::Residue (Rhiju's comment)
388  for ( chemical::AtomIndices::const_iterator hnum = rsd.Hpos_polar().begin(), hnume = rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
389  Size const don_h_atom( *hnum );
390  Size const base_atom ( rsd.atom_base( don_h_atom ) );
391  if ( base_atom == atom ) return true;
392  }
393  for ( chemical::AtomIndices::const_iterator anum = rsd.accpt_pos().begin(), anume = rsd.accpt_pos().end(); anum != anume; ++anum ) {
394  Size const acc_atom( *anum );
395  Size const base_atom ( rsd.atom_base( acc_atom ) );
396  if ( base_atom == atom ) return true;
397  }
398  return false;
399 }
402 {
403  return 1; // Initial versioning
404 }
405 
406 
407 
408 } // geometric_solvation
409 } // scoring
410 } // core
411