Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ContextIndependentGeometricSolEnergy.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 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file core/scoring/methods/ContextIndependentGeometricSolEnergy.fwd.hh
11 /// @author Parin Sripakdeevong (sripakpa@stanford.edu), Rhiju Das (rhiju@stanford.edu)
12 /// @brief Similar to the standard version of GeometricSolEnergy.cc BUT without the CONTEXT_DEPENDENT stuff. ALOT OF CODE DUPLICATION!
13 /// @brief Significantly speed up when used in src/protocol/swa/rna/StepwiseRNA_Sampler.cc!
14 
15 // Unit Headers
18 
19 // Package headers
20 #include <core/scoring/Energies.hh>
33 
34 #include <core/id/AtomID.hh>
35 
36 // Project headers
38 
39 // Utility headers
40 #include <ObjexxFCL/format.hh>
41 
42 #include <core/pose/Pose.hh>
43 
44 #include <basic/Tracer.hh>
45 #include <basic/options/option.hh>
46 #include <basic/options/keys/score.OptionKeys.gen.hh>
47 
48 //Auto Headers
51 #include <ObjexxFCL/FArray3D.hh>
52 
53 
54 static basic::Tracer tr("core.scoring.geometric_solvation.ContextIndependentGeometricSolEnergy" );
55 
56 
57 //////////////////////////////////////////////////
58 //////////////////////////////////////////////////
59 // Added on July. 22, 2011, Parin Sripakdeevong (sripakpa@stanford.edu).
60 //
61 // This copies huge amounts of code from GeometricSolEnergy.cc.
62 // Should instead make a GeometricSolPotential.cc, which holds *all* the core functions,
63 // and then GeometricSolEnergy and ContextIndependentGeometricSolEnergy can both call those core functions.
64 ///////////////////////////////////////////////////
65 
66 namespace core {
67 namespace scoring {
68 namespace geometric_solvation {
69 
70 using namespace ObjexxFCL::fmt;
71 
72 /// @details This must return a fresh instance of the GeometricSolEnergy class,
73 /// never an instance already in use
76  methods::EnergyMethodOptions const & options
77 ) const {
78  return new ContextIndependentGeometricSolEnergy( options );
79 }
80 
83  ScoreTypes sts;
84  sts.push_back( CI_geom_sol );
85  sts.push_back( CI_geom_sol_intra_RNA );
86  return sts;
87 }
88 
89 
90 using namespace core::scoring::hbonds;
91 
92 ///@brief copy c-tor
95  options_( new methods::EnergyMethodOptions( opts ) ),
96  hb_database_( HBondDatabase::get_database( opts.hbond_options().params_database_tag() )),
97  dist_cut2_( 27.0 ), // 5.2*5.2
98  geometric_sol_scale_( 0.4 * 1.17 / 0.65 ),
99  correct_geom_sol_acceptor_base_( basic::options::option[ basic::options::OptionKeys::score::geom_sol_correct_acceptor_base ]() ),
100  verbose_( false )
101 {
102  options_->exclude_DNA_DNA( false /*GEOMETRIC SOLVATION NOT COMPATIBLE WITH EXCLUDE_DNA_DNA FLAG YET*/ ); //REMOVE?
103 
104  // override command line. Copy from GeometricSolEnergy on Jan 09, 2012. This is necessary to reproduce Parin's branch result
105  options_->hbond_options().use_incorrect_deriv( true );
106  options_->hbond_options().use_sp2_chi_penalty( false );
107  // override command line. Copy from GeometricSolEnergy on Jan 09, 2012. This is necessary to reproduce Parin's branch result
108 
109 }
110 
111 /// copy ctor
114  options_( new methods::EnergyMethodOptions( * src.options_ ) ),
115  hb_database_( src.hb_database_ ),
116  dist_cut2_( src.dist_cut2_ ), // 5.2*5.2
117  geometric_sol_scale_( src.geometric_sol_scale_ ),
118  correct_geom_sol_acceptor_base_( src.correct_geom_sol_acceptor_base_ ),
119  verbose_( src.verbose_ )
120 {}
121 
122 /// clone
125 {
126  return new ContextIndependentGeometricSolEnergy( *this );
127 }
128 
129 ///
130 void
132 {
133 
135  //RNA implementation doesn't not actually require the hbond_set?
136 
137 
139 
140  hbonds::HBondSetOP hbond_set( new hbonds::HBondSet( options_->hbond_options() ) );
141  hbond_set->setup_for_residue_pair_energies( pose );
142  pose.energies().data().set( HBOND_SET, hbond_set );
143 
144 
145 }
146 
147 /////////////////////////////////////////////////////////////////////////////
148 void
150 {
151 
152 
154  //RNA implementation doesn't not actually require the hbond_set?
155 
156 
158 
159  hbonds::HBondSetOP hbond_set( new hbonds::HBondSet( options_->hbond_options() ) );
160  hbonds::fill_hbond_set( pose, true /*calc derivs*/, *hbond_set );
161  hbond_set->resize_bb_donor_acceptor_arrays( pose.total_residue() );
162  pose.energies().data().set( HBOND_SET, hbond_set );
163 
164 }
165 
166 
167 /////////////////////////////////////////////////////////////////////////////
168 // scoring
169 /////////////////////////////////////////////////////////////////////////////
170 
171 /// Everything in here.
172 void
174  conformation::Residue const & rsd1,
175  conformation::Residue const & rsd2,
176  pose::Pose const & pose,
177  ScoreFunction const &,
178  EnergyMap & emap
179 ) const
180 {
181 
182  //std::cout << "ContextIndependentGeometricSolEnergy::residue_pair_energy rsd1.seqpos()= " << rsd1.seqpos() << " , rsd2.seqpos()= " << rsd2.seqpos() << std::endl;
183 
184  // if( rsd1.is_RNA()==false ) utility_exit_with_message("rsd1.is_RNA()==false"); //This code has been tested only for RNA!
185  // if( rsd2.is_RNA()==false ) utility_exit_with_message("rsd2.is_RNA()==false"); //This code has been tested only for RNA!
186 
187  if ( rsd1.seqpos() == rsd2.seqpos() ) utility_exit_with_message("rsd1.seqpos() == rsd2.seqpos()");
188 
189  Real geo_solE = res_res_geometric_sol_one_way( rsd1, rsd2, pose ) + res_res_geometric_sol_one_way( rsd2, rsd1, pose );
190 
191  // store the energies
192  emap[ CI_geom_sol ] += geo_solE;
193 
194 }
195 
196 
197 /////////////////////////////////////////////////////////////////////
198 // [Note to self (rhiju) : It might also make sense to precompute and cache this data
199 // in, say, a geometric solvation potential object, so that derivatives
200 // don't need to be computed over and over again, and code won't be
201 // copied. ]
202 //
203 Real
205  conformation::Residue const & polar_rsd,
206  conformation::Residue const & occ_rsd,
207  pose::Pose const & pose ) const
208 {
209 
210  Real geo_solE =
211  donorRes_occludingRes_geometric_sol_one_way( polar_rsd, occ_rsd, pose ) +
212  acceptorRes_occludingRes_geometric_sol_one_way( polar_rsd, occ_rsd, pose );
213 
214  return geo_solE;
215 }
216 
217 //////////////////////////////////////////////////////////////////////////////////////
218 Real
220  conformation::Residue const & don_rsd,
221  conformation::Residue const & occ_rsd,
222  pose::Pose const & pose ) const
223 {
224 
225  Real res_solE( 0.0 ), energy( 0.0 );
226 
227  // Here we go -- cycle through polar hydrogens in don_aa, everything heavy in occluding atom.
228  for ( chemical::AtomIndices::const_iterator hnum = don_rsd.Hpos_polar().begin(), hnume = don_rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
229  Size const don_h_atm( *hnum );
230  for ( Size occ_atm = 1; occ_atm <= occ_rsd.nheavyatoms(); occ_atm++ ) {
231 
232  //Important NOTE If speed becomes important, here's a place to start.
233  get_atom_atom_geometric_solvation_for_donor( don_h_atm, don_rsd, occ_atm, occ_rsd, pose, energy );
234  res_solE += energy;
235  }
236  }
237 
238  return res_solE;
239 }
240 
241 ///////////////////////////////////////////////////////////////////////////////////////
242 Real
244  conformation::Residue const & acc_rsd,
245  conformation::Residue const & occ_rsd,
246  pose::Pose const & pose ) const
247 {
248 
249  Real res_solE( 0.0 ), energy( 0.0 );
250 
251  for ( chemical::AtomIndices::const_iterator anum = acc_rsd.accpt_pos().begin(), anume = acc_rsd.accpt_pos().end(); anum != anume; ++anum ) {
252  Size const acc_atm( *anum );
253  for ( Size occ_atm = 1; occ_atm <= occ_rsd.nheavyatoms(); occ_atm++ ) {
254 
255  //Important NOTE: If speed becomes important, here's a place to start.
256  get_atom_atom_geometric_solvation_for_acceptor( acc_atm, acc_rsd, occ_atm, occ_rsd, pose, energy);
257  res_solE += energy;
258  }
259  }
260 
261  return res_solE;
262 }
263 
264 
265 //////////////////////////////////////////////////////////////////////////////
266 // Helper function for creating a mock H or O for the mock water.
267 // Assume it is in the same plane as that defined by the other
268 // atoms involved in the hydrogen bond.
269 // There are probably (better) examples of this function elsewhere in the code.
270 //
271 inline
272 void
274  Vector const & base_v,
275  Vector const & atom_v,
276  Vector const & water_v,
277  Vector & water_base_v,
278  Real const & xH /*cos(theta)*/,
279  Distance const & bond_length ) const
280 {
281  Vector x,y,z, direction;
282 
283  //Define coordinate system.
284  z = cross( (water_v - atom_v), (atom_v - base_v) );
285  z.normalize();
286  y = water_v - atom_v;
287  y.normalize();
288  x = cross( y, z );
289 
290  // Plop the atom down
291  direction = xH * y + Real( std::sqrt( 1 - (xH * xH) ) ) * x;
292  water_base_v = water_v + bond_length * direction;
293 
294 }
295 
296 
297 /////////////////////////////////////////////////////////////////////////////////////////
298 inline
299 Real
301  bool const & is_donor,
302  hbonds::HBEvalTuple const & hbond_eval_type,
303  Vector const & polar_atm_xyz,
304  Vector const & base_atm_xyz,
305  Vector const & occluding_atm_xyz,
306  bool const update_deriv /* = false*/,
307  HBondDerivs & deriv /* = DUMMY_DERIV2D*/ ) const
308 {
309 
310  static bool const always_do_full_calculation( true );
311 
312  // jumpout criteria copied from hb_energy_deriv in hbonds.cc
313 
314  // Compute geometry
315  Real AHdis( 0.0 ), xD( 0.0 ), xH( 0.0 ), energy( 0.0 );
316 
317  //Craziness... create an artifical atom to complete "water molecule".
318  Vector water_base_atm;
319  static Distance const water_O_H_distance( 0.958 );
320  Real const environment_weight= 1.0; //NO CONTEXT DEPENDENCE!
321 
322  //Might be cleaner to separate this into two functions, one for donor, one for acceptor?
323  if ( is_donor ) {
324 
325  // water is the acceptor, give it perfect geometry
326  xH = 1./3.; // perfect geometry is cos( 180 - 109.5 degrees), which is 1/3
327 
328  // compute the distance to the accepting water
329  Real const AHdis2 = (polar_atm_xyz - occluding_atm_xyz).length_squared();
330  if ( AHdis2 > MAX_R2 ) return 0.0;
331  if ( AHdis2 < MIN_R2 ) return 0.0;
332  AHdis = std::sqrt(AHdis2);
333 
334  // find the cosine of the base-proton-water angle (xD)
335  xD = get_water_cos( base_atm_xyz, polar_atm_xyz, occluding_atm_xyz );
336  if ( xD < MIN_xD ) return 0.0;
337  if ( xD > MAX_xD ) return 0.0;
338 
339  //rhiju, testing alternative calculation that will give derivative.
340  Vector occluding_base_atm_xyz( 0.0 );
341  if ( update_deriv || always_do_full_calculation ) {
342  set_water_base_atm( base_atm_xyz, polar_atm_xyz, occluding_atm_xyz, occluding_base_atm_xyz,
343  xH, water_O_H_distance );
344  hb_energy_deriv( *hb_database_, options_->hbond_options(),
345  hbond_eval_type, base_atm_xyz, polar_atm_xyz,
346  occluding_atm_xyz,
347  occluding_base_atm_xyz,
348  occluding_base_atm_xyz,
349  energy, hbderiv_ABE_GO_NO_xH, deriv);
350 
351  if (verbose_) tr << "DONOR ENERGY: " << energy << std::endl;
352  }
353 
354  } else {
355 
356  // water is the donor, give it perfect geometry
357  xD = 0.9999;
358 
359  // compute the distance to the accepting water proton
360  // subtract the water's OH distance to get the AHdis,
361  // since the distance computed was from the acceptor to the water oxygen
362  // note: water proton lies on the line between the acceptor and the water oxygen
363  AHdis = ( polar_atm_xyz - occluding_atm_xyz ).length();
364  AHdis -= water_O_H_distance; // water O-H distance
365  Real const AHdis2 = AHdis * AHdis;
366  if ( AHdis2 > MAX_R2 ) return 0.;
367  if ( AHdis2 < MIN_R2 ) return 0.;
368 
369  // find cosine of the base-acceptor-water_proton angle (xH)
370  // note: this is the same as the base-acceptor-water_oxygen angle
371  xH = get_water_cos( base_atm_xyz, polar_atm_xyz, occluding_atm_xyz );
372  if ( xH < MIN_xH ) return 0.;
373  if ( xH > MAX_xH ) return 0.;
374 
375  //rhiju, testing alternative calculation that will give derivative.
376  if ( update_deriv || always_do_full_calculation ) {
377  Vector occluding_base_atm_xyz( 0.0 );
378  set_water_base_atm( base_atm_xyz, polar_atm_xyz, occluding_atm_xyz, occluding_base_atm_xyz,
379  -xD, water_O_H_distance );
380  hb_energy_deriv( *hb_database_, options_->hbond_options(), hbond_eval_type,
381  occluding_atm_xyz, occluding_base_atm_xyz,
382  polar_atm_xyz, base_atm_xyz, base_atm_xyz,
383  energy, hbderiv_ABE_GO_NO_xD, deriv);
384 
385 
386  if (verbose_) tr << "ACCPT ENERGY: " << energy << std::endl;
387 
388 
389  }
390 
391 
392  }
393 
394  // Note that following should be a little faster and could be used if derivative is not necessary
395  // However, use of hb_energy_deriv gives nearly exact match of analytical and numerical.
396  // while every once in a while this does not...
397  if ( !always_do_full_calculation ) {
398  Real dummy_chi( 0.0 );
399  assert( ! options_->hbond_options().use_sp2_chi_penalty() ); // APL avoid the new sp2 chi term.
400  hbond_compute_energy(*hb_database_, options_->hbond_options(), hbond_eval_type, AHdis, xD, xH, dummy_chi, energy);
401  }
402 
403  if (verbose_ ) tr << " jk ENERGY: " << energy << std::endl;
404 
405  core::Real sol_penalty = -1.0 * energy;
406 
407  // jk THIS NEEDS TO BE FIT MORE RIGOROUSLY LATER...
408  // Apply a scaling factor (effectively a weight), tying the weight of the
409  // solvation term to the Hbond term (rather than to the LK weight)
410  // Note: chose the bb-sc Hbond weight, because they're all about the same
411  // core::Real const sol_weight = geometric_sol_weight * pack_wts.Whbond_bb_sc() / pack_wts.Wsol();
412  Real reweight = geometric_sol_scale_ * environment_weight;
413 
414  sol_penalty *= reweight;
415 
416  if ( update_deriv ){
417  if ( is_donor ) {
418  deriv.h_deriv.f1() *= -1.0 * reweight;
419  deriv.h_deriv.f2() *= -1.0 * reweight;
420  deriv.don_deriv.f1() *= -1.0 * reweight;
421  deriv.don_deriv.f2() *= -1.0 * reweight;
422  } else {
423  // had to flip reference frame to get HB energy and derivative.
424  deriv.h_deriv.f1() *= +1.0 * reweight;
425  deriv.h_deriv.f2() *= +1.0 * reweight;
426  deriv.don_deriv.f1() *= +1.0 * reweight;
427  deriv.don_deriv.f2() *= +1.0 * reweight;
428  }
429 
430  }
431 
432  // this is a penalty, don't return a negative number
433  if (sol_penalty < 0.) {
434  if ( update_deriv ) deriv = ZERO_DERIV2D;
435  return 0.;
436  }
437 
438  // if (sol_penalty > 0. ) {
439  // tr << F(7,3,polar_atm_xyz(1)) << " " << F(7,3,base_atm_xyz(1)) << " " << F(7,3,occluding_atm_xyz(1) ) << std::endl;
440  // tr << "[AHdis " << F(7,3,AHdis) << "; xD " << F(7,3,xD) << "; xH " << F(7,3,xH) << ", e " << F(7,3,energy) << "]" ;
441  // }
442 
443  return sol_penalty; // return a positive number (this is a penalty)
444 
445 }
446 
447 
448 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
449 inline
450 void
452  Size const & don_h_atm,
453  conformation::Residue const & don_rsd,
454  Size const & occ_atm,
455  conformation::Residue const & occ_rsd,
456  pose::Pose const &,
457  Real & energy,
458  bool const update_deriv /*= false*/,
459  HBondDerivs & deriv /* = DUMMY_DERIVS */) const
460 {
461 
462  //Why do we need to send in the pose and the residue stuff?
463  // Well, the pose has info on backbone H-bonds.
464  // and, during design, the residue type doesn't actually
465  // have to match what's in the pose! Tricky!
466 
467  // In case of early return, initialize. Note that energy *does not* accumulate
468  energy = 0.0;
469  deriv = ZERO_DERIV2D;
470 
471  assert( atom_is_donor_h( don_rsd, don_h_atm ) );
472 
473  Size const don_base_atm( don_rsd.atom_base( don_h_atm ) );
474 
475  Vector const & don_h_atm_xyz( don_rsd.atom( don_h_atm ).xyz() );
476  Vector const & don_base_atm_xyz( don_rsd.atom( don_base_atm ).xyz() );
477 
478  // the base atom isn't allowed to occlude solvent
479  // Note: In current implementation, intraresidue pairs aren't checked...
480  if ( ( don_rsd.seqpos() == occ_rsd.seqpos() ) && ( occ_atm == don_base_atm ) ) return;
481 
482  ////////////////07/23/2011: Parin Sripakdeevong (sripakpa@stanford.edu)/////////////////////
483  if(occ_rsd.is_virtual(occ_atm)) return;
484  if(don_rsd.is_virtual(don_h_atm)) return;
485  ////////////////////////////////////////////////////////////////////////////////////////////
486 
487 
488  // if the distance is > 5.2 A, from the base atom, it doesn't occlude solvent
489  Vector const & occ_atm_xyz( occ_rsd.atom( occ_atm ).xyz() );
490  Real const base_dis2 = ( occ_atm_xyz - don_base_atm_xyz).length_squared();
491  if ( base_dis2 > dist_cut2_ ) return;
492 
493  // if distance to base atom is greater than distance to donor, it doesn't occlude solvent
494  Real const hdis2 = ( occ_atm_xyz - don_h_atm_xyz ).length_squared();
495  if ( hdis2 > base_dis2 ) return;
496 
497  HBEvalTuple hbe( hbdon_HXL, hbacc_HXL, seq_sep_other ); // apl note: this donor/accpetor/seqse combo maps to hbe_dHXLaHXL;
498 
499  if(don_rsd.is_protein() && occ_rsd.is_protein()){ //Parin Sripakdeevong. Special Protien stuff. Not sure if this works!
500  // if a backbone donor participates in a backbone-backbone Hbond,
501  // nothing is allowed to occlude solvent except a backbone acceptor
502  bool const don_h_atm_is_protein_backbone ( don_rsd.is_protein() && don_rsd.atom_is_backbone( don_h_atm ) );
503 
504  bool const occ_atm_is_protein_backbone_acceptor ( occ_rsd.is_protein() && occ_rsd.atom_is_backbone( occ_atm ) && atom_is_acceptor(occ_rsd, occ_atm ) );
505 
506  bool const potential_backbone_backbone_hbond = ( don_h_atm_is_protein_backbone && occ_atm_is_protein_backbone_acceptor );
507 
508  hbe = potential_backbone_backbone_hbond ? ( hbond_evaluation_type( don_base_atm, don_rsd, occ_atm, occ_rsd) ) : HBEvalTuple( hbdon_HXL, hbacc_HXL, seq_sep_other ); // note HBEvalTuple( hbdon_HXL, hbacc_HXL, seq_sep_other ) creates hbeval type of hbe_dHXLaHXL
509  }
510 
511 
512  // jk Compute the Hbond energy as if this was a water
513  // jk Add the water Hbond energy to a running total sum, as well as to the residue sum
514  energy = occluded_water_hbond_penalty( true /*is_donor*/, hbe, don_h_atm_xyz, don_base_atm_xyz, occ_atm_xyz, update_deriv, deriv);
515 
516  if ( verbose_ && ( energy > 0.0 ) ) {
517  tr <<"jk DON res "<< don_rsd.name1() << I(3,don_rsd.seqpos())<<
518  " atom "<< don_rsd.atom_name( don_h_atm )<<" is occluded by occ_res " <<
519  occ_rsd.name1()<< I(3, occ_rsd.seqpos()) <<
520  " atom "<< occ_rsd.atom_name( occ_atm ) <<
521  " (HBEvalType " << I(2,hbe.eval_type()) << ") " <<
522  " with energy "<< F(8,3,energy)<< std::endl;
523  }
524 }
525 
526 
527 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
528 inline
529 Vector
531 
532  Vector base_atm_xyz;
533 
535  // following handles the special case in which acceptor has two base residues -- occurs for
536  // N inside rings.
537  // This matches machinery in hbonds_geom.cc. That doesn't mean that the base atom is set
538  // totally correctly -- water (TIP3.params) and O4* in nucleic acids still have weird base atoms,
539  // but at least the hbonds and geom_sol match up.
540  Vector dummy;
541  chemical::Hybridization acc_hybrid( acc_rsd.atom_type( acc_atm ).hybridization());
543  options_->hbond_options(),
544  acc_hybrid,
545  acc_rsd.atom( acc_atm ).xyz(),
546  acc_rsd.xyz( acc_rsd.atom_base( acc_atm ) ),
547  acc_rsd.xyz( acc_rsd.abase2( acc_atm ) ),
548  base_atm_xyz, dummy );
549  } else {
550  base_atm_xyz = acc_rsd.atom( acc_rsd.atom_base( acc_atm ) ).xyz();
551  }
552  return base_atm_xyz;
553 }
554 
555 
556 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
557 inline
558 void
560  Size const & acc_atm,
561  conformation::Residue const & acc_rsd,
562  Size const & occ_atm,
563  conformation::Residue const & occ_rsd,
564  pose::Pose const &,
565  Real & energy,
566  bool const update_deriv /*= false*/,
567  HBondDerivs & deriv /* = DUMMY_DERIV2D */) const
568 {
569 
570  //Why do we need to send in the pose and the residue stuff?
571  // Well, the pose has info on backbone H-bonds.
572  // and, during design, the residue type doesn't actually
573  // have to match what's in the pose! Tricky!
574 
575  // In case of early return, initialize. Note that energy *does not* accumulate
576  energy = 0.0;
577  deriv = ZERO_DERIV2D;
578 
579  assert( atom_is_acceptor( acc_rsd, acc_atm ) );
580 
581  Size const base_atm ( acc_rsd.atom_base( acc_atm ) );
582 
583  Vector const & acc_atm_xyz( acc_rsd.atom( acc_atm ).xyz() );
584  //Vector const & base_atm_xyz( acc_rsd.atom( base_atm ).xyz() );
585 
586  Vector base_atm_xyz = get_acceptor_base_atm_xyz( acc_rsd, acc_atm );
587 
588  ////////////////////////////Parin S June 26, 2011////////////////////////////////////
589  if(occ_rsd.is_virtual(occ_atm)) return;
590  if(acc_rsd.is_virtual(acc_atm)) return;
591  /////////////////////////////////////////////////////////////////////////////////////
592 
593  // the base atom isn't allowed to occlude solvent
594  // Note: In current implementation, intraresidue pairs aren't checked...
595  if ( ( acc_rsd.seqpos() == occ_rsd.seqpos() ) && ( occ_atm == base_atm ) ) return;
596 
597  // an atom directly bound to the acceptor isn't allowed to occlude solvent
598  // Note: In current implementation, intraresidue pairs aren't checked...
599  if ( ( acc_rsd.seqpos() == occ_rsd.seqpos() ) && acc_rsd.path_distance( acc_atm, occ_atm ) < 2 ) return;
600 
601  // if the distance is > 5.2 A, from the acceptor, it doesn't occlude solvent
602  Vector const & occ_atm_xyz( occ_rsd.atom( occ_atm ).xyz() );
603  Real const acc_dis2 = ( occ_atm_xyz - acc_atm_xyz ).length_squared();
604  if ( acc_dis2 > dist_cut2_ ) return;
605 
606  // if distance to base atom is greater than distance to donor, it doesn't occlude solvent
607  Real const base_dis2 = ( occ_atm_xyz - base_atm_xyz ).length_squared();
608  if ( acc_dis2 > base_dis2 ) return;
609 
610  HBEvalTuple hbe( hbdon_H2O, get_hb_acc_chem_type( acc_atm, acc_rsd), seq_sep_other );
611 
612 
613  if(occ_rsd.is_protein() && acc_rsd.is_protein()){ //Parin Sripakdeevong. Special Protien stuff. Not sure if this works!
614  // if a backbone acceptor participates in a backbone-backbone Hbond,
615  // nothing is allowed to occlude solvent except a backbone donor
616  bool const occ_atm_is_protein_backbone_donor ( occ_rsd.is_protein() && occ_rsd.atom_is_backbone( occ_atm ) && atom_is_donor(occ_rsd, occ_atm ) );
617 
618  bool const acc_atm_is_protein_backbone ( acc_rsd.is_protein() && acc_rsd.atom_is_backbone( acc_atm ) );
619 
620  bool const potential_backbone_backbone_hbond = ( acc_atm_is_protein_backbone && occ_atm_is_protein_backbone_donor );
621 
622  if(potential_backbone_backbone_hbond) hbe = ( hbond_evaluation_type( occ_atm, occ_rsd, acc_atm, acc_rsd ) );
623 
624  }
625 
626  // jk Compute the Hbond energy as if this was a water
627  // jk Add the water Hbond energy to a running total sum, as well as to the residue sum
628  energy = occluded_water_hbond_penalty( false /*is_donor*/, hbe, acc_atm_xyz, base_atm_xyz, occ_atm_xyz, update_deriv, deriv);
629 
630  if ( verbose_ && ( energy > 0.0 ) ) {
631  tr<<"jk ACC res "<< acc_rsd.name1() << I(3, acc_rsd.seqpos())<<
632  " atom "<< acc_rsd.atom_name( acc_atm )<<" is occluded by occ_res "<<
633  occ_rsd.name1()<< I(3, occ_rsd.seqpos()) <<
634  " atom "<< occ_rsd.atom_name( occ_atm ) <<
635  " (HBEvalType " << I(2,hbe.eval_type()) << ") " <<
636  " with energy "<< F(8,3,energy)<<std::endl;
637  }
638 
639 }
640 
641 
642 ///////////////////////////////////////////////////////////////////////////////
643 /// Compute the cosine required for calling water Hbond energies
644 inline
645 Real
647  Vector const & polar_atm_xyz,
648  Vector const & occluding_atm_xyz ) const
649 {
650  return dot( (polar_atm_xyz - base_atm_xyz).normalize(), (occluding_atm_xyz - polar_atm_xyz).normalize() );
651 }
652 
653 
654 //////////////////////////////////////////////////////////////////////////////////////
655 // Stupid helper function
656 // These should probably live inside conformation::Residue.
657 //
658 bool
660 {
661  for ( chemical::AtomIndices::const_iterator
662  hnum = rsd.Hpos_polar().begin(),
663  hnume = rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
664  Size const don_h_atm( *hnum );
665  Size const don_base_atm( rsd.atom_base( don_h_atm ) );
666  if ( don_base_atm == atm ) return true;
667  }
668  return false;
669 }
670 //////////////////////////////////////////////////////////////////////////////////////
671 // Stupid helper function
672 // These should probably live inside conformation::Residue.
673 //
674 bool
676 {
677  for ( chemical::AtomIndices::const_iterator
678  hnum = rsd.Hpos_polar().begin(),
679  hnume = rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
680  Size const don_h_atm( *hnum );
681  if ( don_h_atm == atm ) return true;
682  }
683  return false;
684 }
685 //////////////////////////////////////////////////////////////////////////////
686 // Stupid helper function
687 // These should probably live inside conformation::Residue.
688 bool
690 {
691  for ( chemical::AtomIndices::const_iterator
692  anum = rsd.accpt_pos().begin(),
693  anume = rsd.accpt_pos().end(); anum != anume; ++anum ) {
694  Size const acc_atm( *anum );
695  if ( acc_atm == atm ) return true;
696  }
697  return false;
698 }
699 
700 //////////////////////////////////////////////////////////////////////////////
701 // Stupid helper function
702 // These should probably live inside conformation::Residue.
703 bool
705 {
706  //July 22, 2011..WARNING virtualized hydrogen atoms are mistaken as heavy under this citeria!!!
707  //Could check if its hydrogen, but this is the same delineation used in the
708  // residue-residue pair energy loop.
709  return (atm <= rsd.nheavyatoms() );
710 }
711 
712 //////////////////////////////////////////////////////////////////////////////
713 // Note that this computes every interaction *twice* -- three times if you
714 // note that the score calculation above does most of the computation already.
715 // Oh well -- we currently assume derivative calculation doesn't happen to often!
716 //
717 
718 void
720  id::AtomID const & atom_id,
721  pose::Pose const & pose,
722  EnergyMap const & weights,
723  Vector & F1,
724  Vector & F2
725 ) const
726 {
727 
728  Size const i( atom_id.rsd() );
729 
730  conformation::Residue const & current_rsd( pose.residue( i ) );
731  conformation::Residue const & other_rsd( pose.residue( i ) );
732 
733  //Ok right now intrares energy is define only for the RNA case. Parin Sripakdeevong, June 26, 2011.
734  // if(current_rsd.is_RNA()==false) return;
735  // if(other_rsd.is_RNA()==false) return; //no effect!
736 
737  static bool const update_deriv( true );
738 
739  Real energy( 0.0 );
740  hbonds::HBondDerivs deriv;
741 
742  Size const current_atm( atom_id.atomno() );
743 
744  if(verbose_) std::cout << "Start eval_atom_derivative, intra_res case, res= " << i << " atomno= " << current_atm << "[" << current_rsd.atom_name(current_atm) << "]" << std::endl;
745 
746  // If this atom is a donor, go over heavy atoms in other residue.
747  if ( atom_is_donor_h( current_rsd, current_atm ) ) {
748  for (Size m = 1; m <= other_rsd.nheavyatoms(); m++ ){
749 
750  if(core::scoring::rna::Is_base_phosphate_atom_pair(current_rsd, other_rsd, current_atm, m)==false) continue;
751 
752  get_atom_atom_geometric_solvation_for_donor( current_atm, current_rsd, m, other_rsd, pose, energy, update_deriv, deriv );
753 
754  F1 += weights[ CI_geom_sol_intra_RNA ] * ( deriv.h_deriv.f1() + deriv.don_deriv.f1() );
755  F2 += weights[ CI_geom_sol_intra_RNA ] * ( deriv.h_deriv.f2() + deriv.don_deriv.f2() );
756  }
757  }
758 
759  // If this atom is an acceptor, go over heavy atoms in other residue.
760  if ( atom_is_acceptor( current_rsd, atom_id.atomno() ) ) {
761  for (Size m = 1; m <= other_rsd.nheavyatoms(); m++ ){
762 
763  if(core::scoring::rna::Is_base_phosphate_atom_pair(current_rsd, other_rsd, current_atm, m)==false) continue;
764 
765  get_atom_atom_geometric_solvation_for_acceptor( current_atm, current_rsd, m, other_rsd, pose, energy, update_deriv, deriv );
766 
767  F1 += weights[ CI_geom_sol_intra_RNA ] * ( deriv.h_deriv.f1() + deriv.don_deriv.f1() );
768  F2 += weights[ CI_geom_sol_intra_RNA ] * ( deriv.h_deriv.f2() + deriv.don_deriv.f2() );
769  }
770  }
771 
772  //Treat atom as occluder if its heavy.
773  if ( atom_is_heavy( current_rsd, atom_id.atomno() ) ) {
774  // Go over donors in other atom.
775  for ( chemical::AtomIndices::const_iterator hnum = other_rsd.Hpos_polar().begin(), hnume = other_rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
776  Size const don_h_atm( *hnum );
777 
778  if(core::scoring::rna::Is_base_phosphate_atom_pair(current_rsd, other_rsd, current_atm, don_h_atm)==false) continue;
779 
780  get_atom_atom_geometric_solvation_for_donor( don_h_atm, other_rsd, atom_id.atomno(), current_rsd, pose, energy, update_deriv, deriv );
781 
782  F1 -= weights[ CI_geom_sol_intra_RNA ] * ( deriv.h_deriv.f1() + deriv.don_deriv.f1() );
783  F2 -= weights[ CI_geom_sol_intra_RNA ] * ( deriv.h_deriv.f2() + deriv.don_deriv.f2() );
784  }
785 
786  // Go over acceptors in other atom.
787  for ( chemical::AtomIndices::const_iterator anum = other_rsd.accpt_pos().begin(), anume = other_rsd.accpt_pos().end(); anum != anume; ++anum ) {
788  Size const acc_atm ( *anum );
789 
790  if(core::scoring::rna::Is_base_phosphate_atom_pair(current_rsd, other_rsd, current_atm, acc_atm)==false) continue;
791 
792  get_atom_atom_geometric_solvation_for_acceptor( acc_atm, other_rsd, atom_id.atomno(), current_rsd, pose, energy, update_deriv, deriv );
793 
794  F1 -= weights[ CI_geom_sol_intra_RNA ] * ( deriv.h_deriv.f1() + deriv.don_deriv.f1() );
795  F2 -= weights[ CI_geom_sol_intra_RNA ] * ( deriv.h_deriv.f2() + deriv.don_deriv.f2() );
796  }
797  }
798 
799  if(verbose_){
800  std::cout << "eval_atom_derivative, intra_res :";
801  std::cout << " F1= " << F1[0] << " " << F1[1] << " " << F1[2];
802  std::cout << " F2= " << F2[0] << " " << F2[1] << " " << F2[2] << std::endl;
803  std::cout << "Finish eval_atom_derivative, intra_res case, res= " << i << " atomno= " << current_atm << "[" << current_rsd.atom_name(current_atm) << "]" << std::endl;
804  }
805 }
806 
807 
808 void
810  id::AtomID const & atom_id,
811  pose::Pose const & pose,
812  kinematics::DomainMap const &,
813  ScoreFunction const &,
814  EnergyMap const & weights,
815  Vector & F1,
816  Vector & F2
817 ) const
818 {
819 
820  Real energy( 0.0 );
821  hbonds::HBondDerivs deriv;
822 
823  eval_atom_derivative_intra_RNA(atom_id, pose, weights, F1, F2);
824 
825  conformation::Residue const & current_rsd( pose.residue( atom_id.rsd() ) );
826 
827  Size const i( atom_id.rsd() );
828  Size const current_atm( atom_id.atomno() );
829 
830  // Size const nres = pose.total_residue();
831  static bool const update_deriv( true );
832 
833  EnergyGraph const & energy_graph( pose.energies().energy_graph() );
834 
836  iter = energy_graph.get_node( i )->const_edge_list_begin();
837  iter != energy_graph.get_node( i )->const_edge_list_end();
838  ++iter ){
839 
840  Size j( (*iter)->get_other_ind( i ) );
841 
842  conformation::Residue const & other_rsd( pose.residue( j ) );
843 
844  if ( i == j ) continue; //Already dealt with above! Plus I think a edge doesn't point to itself!
845 
846  // If this atom is a donor, go over heavy atoms in other residue.
847  if ( atom_is_donor_h( current_rsd, current_atm ) ) {
848  for (Size m = 1; m <= other_rsd.nheavyatoms(); m++ ){
849  get_atom_atom_geometric_solvation_for_donor( current_atm, current_rsd,
850  m, other_rsd,
851  pose, energy, update_deriv, deriv );
852  F1 += weights[ CI_geom_sol ] * ( deriv.h_deriv.f1() + deriv.don_deriv.f1() );
853  F2 += weights[ CI_geom_sol ] * ( deriv.h_deriv.f2() + deriv.don_deriv.f2() );
854  }
855  }
856 
857  // If this atom is an acceptor, go over heavy atoms in other residue.
858  if ( atom_is_acceptor( current_rsd, atom_id.atomno() ) ) {
859  for (Size m = 1; m <= other_rsd.nheavyatoms(); m++ ){
860  get_atom_atom_geometric_solvation_for_acceptor( current_atm, current_rsd,
861  m, other_rsd,
862  pose, energy, update_deriv, deriv );
863  F1 += weights[ CI_geom_sol ] * ( deriv.h_deriv.f1() + deriv.don_deriv.f1() );
864  F2 += weights[ CI_geom_sol ] * ( deriv.h_deriv.f2() + deriv.don_deriv.f2() );
865  }
866  }
867 
868  //Treat atom as occluder if its heavy.
869  if ( atom_is_heavy( current_rsd, atom_id.atomno() ) ) {
870  // Go over donors in other atom.
871  for ( chemical::AtomIndices::const_iterator
872  hnum = other_rsd.Hpos_polar().begin(),
873  hnume = other_rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
874  Size const don_h_atm( *hnum );
875  get_atom_atom_geometric_solvation_for_donor( don_h_atm, other_rsd,
876  atom_id.atomno(), current_rsd,
877  pose, energy, update_deriv, deriv );
878  F1 -= weights[ CI_geom_sol ] * ( deriv.h_deriv.f1() + deriv.don_deriv.f1() );
879  F2 -= weights[ CI_geom_sol ] * ( deriv.h_deriv.f2() + deriv.don_deriv.f2() );
880  }
881 
882  // Go over acceptors in other atom.
883  for ( chemical::AtomIndices::const_iterator
884  anum = other_rsd.accpt_pos().begin(),
885  anume = other_rsd.accpt_pos().end(); anum != anume; ++anum ) {
886  Size const acc_atm ( *anum );
888  atom_id.atomno(), current_rsd,
889  pose, energy, update_deriv, deriv );
890  F1 -= weights[ CI_geom_sol ] * ( deriv.h_deriv.f1() + deriv.don_deriv.f1() );
891  F2 -= weights[ CI_geom_sol ] * ( deriv.h_deriv.f2() + deriv.don_deriv.f2() );
892  }
893  }
894 
895  }
896 }
897 
898 ////////////////////////////////////////////////////////////////////
899 // Only return energy for occluded polar atoms.
900 Real
902  id::AtomID const & atom_id,
903  pose::Pose const & pose
904 ) const
905 {
906 
907 
908  Real total_energy( 0.0 );
909 
910  conformation::Residue const & current_rsd( pose.residue( atom_id.rsd() ) );
911 
912  Size const i( atom_id.rsd() );
913  Size const current_atm( atom_id.atomno() );
914 
915  EnergyGraph const & energy_graph( pose.energies().energy_graph() );
916 
918  iter = energy_graph.get_node( i )->const_edge_list_begin();
919  iter != energy_graph.get_node( i )->const_edge_list_end();
920  ++iter ){
921 
922  Size j( (*iter)->get_other_ind( i ) );
923 
924  //As above disallow contribution within a residue. Is this OK? Sure there shouldn't be an "intra" term?
925  // anyway list of neighbors does not include i==j.
926  if ( i == j ) continue;
927 
928  conformation::Residue const & other_rsd( pose.residue( j ) );
929 
930  // If this atom is a donor, go over heavy atoms in other residue.
931  if ( atom_is_donor_h( current_rsd, current_atm ) ) {
932  for (Size m = 1; m <= other_rsd.nheavyatoms(); m++ ){
933  Real energy( 0.0 );
934  get_atom_atom_geometric_solvation_for_donor( current_atm, current_rsd,
935  m, other_rsd,
936  pose, energy );
937  total_energy += energy;
938  }
939  }
940 
941  // If this atom is an acceptor, go over heavy atoms in other residue.
942  if ( atom_is_acceptor( current_rsd, atom_id.atomno() ) ) {
943  for (Size m = 1; m <= other_rsd.nheavyatoms(); m++ ){
944  Real energy( 0.0 );
945  get_atom_atom_geometric_solvation_for_acceptor( current_atm, current_rsd,
946  m, other_rsd,
947  pose, energy );
948  total_energy += energy;
949  }
950  }
951 
952  }
953 
954  return total_energy;
955 }
956 
957 
958 // COPIED OVER FROM HBondEnergy.cc ==> comment is not rhiju's!
959 ///@brief HACK! MAX_R defines the maximum donorH to acceptor distance.
960 // The atomic_interaction_cutoff method is meant to return the maximum distance
961 // between two *heavy atoms* for them to have a zero interaction energy.
962 // I am currently assuming a 1.35 A maximum distance between a hydrogen and the
963 // heavy atom it is bound to, stealing this number from the CYS.params file since
964 // the HG in CYS is much further from it's SG than aliphatic hydrogens are from their carbons.
965 // This is a bad idea. Someone come up with a way to fix this!
966 //
967 // At 4.35 A interaction cutoff, the hbond energy function is incredibly short ranged!
968 Distance
970 {
971  return MAX_R + 1.35; // MAGIC NUMBER
972 }
973 
974 ///////////////////////////////////////////////////////////////////////////////////////
975 bool
977 {
978  //bool method_1= (weights[CI_geom_sol_intra_RNA]>0.0) ? true : false;
979 
980  bool condition_1= (weights[CI_geom_sol_intra_RNA]>0.0001) ? true : false; //Change to this on Feb 06, 2012. Ensure that the function returns false if weights[CI_geom_sol_intra_RNA]==0.0
981 
982  return condition_1;
983 }
984 
985 
986 ///////////////////////////////////////////////////////////////////////////////////////
987 void
989  conformation::Residue const & rsd,
990  pose::Pose const & pose,
991  ScoreFunction const & ,
992  EnergyMap & emap
993 ) const{
994 
995  // if(rsd.is_RNA()==false) return;
996 
997  Real geo_solE_intra_RNA =
1000 
1001  // store the energies
1002  emap[ CI_geom_sol_intra_RNA ] += geo_solE_intra_RNA;
1003 
1004 }
1005 
1006 
1007 ///////////////////////////////////////////////////////////////////////////////////////
1008 Real
1010  conformation::Residue const & rsd,
1011  pose::Pose const & pose ) const
1012 {
1013 
1014 
1015  Real res_solE( 0.0 ), energy( 0.0 );
1016 
1017  conformation::Residue const & don_rsd=rsd;
1018  conformation::Residue const & occ_rsd=rsd;
1019 
1020  // Here we go -- cycle through polar hydrogens in don_aa, everything heavy in occluding atom.
1021  for ( chemical::AtomIndices::const_iterator hnum = don_rsd.Hpos_polar().begin(), hnume = don_rsd.Hpos_polar().end(); hnum != hnume; ++hnum ) {
1022  Size const don_h_atm( *hnum );
1023  for ( Size occ_atm = 1; occ_atm <= occ_rsd.nheavyatoms(); occ_atm++ ) {
1024 
1025  if(core::scoring::rna::Is_base_phosphate_atom_pair(rsd, rsd, occ_atm, don_h_atm)==false) continue;
1026 
1027  get_atom_atom_geometric_solvation_for_donor( don_h_atm, don_rsd, occ_atm, occ_rsd, pose, energy );
1028  res_solE += energy;
1029  }
1030  }
1031 
1032  return res_solE;
1033 }
1034 
1035 ///////////////////////////////////////////////////////////////////////////////////////
1036 Real
1038  conformation::Residue const & rsd,
1039  pose::Pose const & pose ) const
1040 {
1041 
1042  conformation::Residue const & acc_rsd=rsd;
1043  conformation::Residue const & occ_rsd=rsd;
1044 
1045 
1046  Real res_solE( 0.0 ), energy( 0.0 );
1047 
1048  for ( chemical::AtomIndices::const_iterator anum = acc_rsd.accpt_pos().begin(), anume = acc_rsd.accpt_pos().end(); anum != anume; ++anum ) {
1049  Size const acc_atm( *anum );
1050  for ( Size occ_atm = 1; occ_atm <= occ_rsd.nheavyatoms(); occ_atm++ ) {
1051 
1052  if(core::scoring::rna::Is_base_phosphate_atom_pair(rsd, rsd, occ_atm, acc_atm)==false) continue;
1053 
1054  get_atom_atom_geometric_solvation_for_acceptor( acc_atm, acc_rsd, occ_atm, occ_rsd, pose, energy);
1055  res_solE += energy;
1056 
1057  }
1058  }
1059 
1060  return res_solE;
1061 }
1062 
1063 
1064 ///@brief ContextIndependentGeometricSolEnergy is NOT context sensitive
1065 void
1067  utility::vector1< bool > & /*context_graphs_required*/
1068 ) const
1069 {}
1070 
1071 core::Size
1073 {
1074  return 1; // Initial versioning
1075 }
1076 
1077 
1078 } // hbonds
1079 } // scoring
1080 } // core
1081