Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LK_hack.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/LK_hack.hh
11 /// @brief LK Solvation using hemisphere culling class declaration
12 /// @author David Baker
13 /// @author Andrew Leaver-Fay
14 
15 
16 // Unit headers
19 
22 #include <core/scoring/Energies.hh>
29 
30 // Project headers
31 #include <core/pose/Pose.hh>
34 
36 
37 #include <numeric/constants.hh>
38 #include <numeric/xyz.functions.hh>
39 
41 #include <utility/vector1.hh>
42 
43 
44 namespace core {
45 namespace scoring {
46 namespace methods {
47 
48 
49 /// @details This must return a fresh instance of the LK_hack class,
50 /// never an instance already in use
53  methods::EnergyMethodOptions const & options
54 ) const {
55  return new LK_hack( *( ScoringManager::get_instance()->etable( options.etable_type() )) );
56 }
57 
60  ScoreTypes sts;
61  sts.push_back( lk_hack );
62  return sts;
63 }
64 
65 
66 using namespace constraints;
67 
69 public:
71 
72  FuncOP
73  clone() const;
74 
75  virtual Real func( Real const x ) const;
76  virtual Real dfunc( Real const x ) const;
77 
78  static Real const ANGLE_CUTOFF_HIGH;
79  static Real const ANGLE_CUTOFF_LOW;
80 
83 
84 };
85 
86 using namespace numeric;
87 using namespace numeric::constants::d;
88 
89 /// Ramp the score from 1 to 0 over the range from 100 degrees to 90 degrees
90 Real const LK_SigmoidalFunc::ANGLE_CUTOFF_HIGH( 100.0 * degrees_to_radians );
91 Real const LK_SigmoidalFunc::ANGLE_CUTOFF_LOW( 90.0 * degrees_to_radians );
92 
95 
96 
98 
100 
101 /// @brief a Sigmoidal function that ramps from 1 to 0 over a certain range.
102 /// Thanks to Mike Tyka for having a sigmoidal function on the top of his head.
103 Real
104 LK_SigmoidalFunc::func( Real const x ) const
105 {
106  //std::cout << "LK_SigmoidalFunc: x=" << x << " degx = " << radians_to_degrees * x << " high " << ANGLE_CUTOFF_HIGH << " low " << ANGLE_CUTOFF_LOW << std::endl;
107  /// x in radians, angle between base atom, atom, and desolvator atom
108  if ( x >= ANGLE_CUTOFF_HIGH ) { return 1.0; }
109  else if ( x <= ANGLE_CUTOFF_LOW ) { return 0.0; }
110  else {
111  static Real const range = ANGLE_CUTOFF_HIGH - ANGLE_CUTOFF_LOW;
112  // x on a zero-to-one range = x'
113  Real const xprime = ( ANGLE_CUTOFF_HIGH - x ) / range;
114  //std::cout << "LK_SigmoidalFunc::func x= " << radians_to_degrees * x << " xprime= " << xprime << " " << ( 1 - xprime*xprime )*( 1 - xprime*xprime ) << std::endl;
115  return ( 1 - xprime*xprime )*( 1 - xprime*xprime );
116  }
117 }
118 
119 Real
121 {
122  /// x in radians, angle between base atom, atom, and desolvator atom
123  if ( x >= ANGLE_CUTOFF_HIGH ) { return 0.0; }
124  else if ( x <= ANGLE_CUTOFF_LOW ) { return 0.0; }
125  else {
126  // x on a zero-to-one range
127  static Real const range = ANGLE_CUTOFF_HIGH - ANGLE_CUTOFF_LOW;
128  Real const xprime = ( ANGLE_CUTOFF_HIGH - x ) / range;
129  //Real const eps = 0.00001;
130  //Real const numD = ( func( x + eps ) - func( x ) ) / eps ;
131  //Real const anD = ( 4.0 / (range) ) * ( 1 - xprime*xprime ) * ( xprime );
132  //std::cout << "LK_SigmoidalFunc::dfunc x= " << radians_to_degrees * x << " xprime= " << xprime << " d: " << anD << " range: " << range << " invrange " << 1 / range << std::endl;
133  //std::cout << "func( " << x << ") " << func( x ) << " func( " << x + eps << " )= " << func( x + eps ) << " numD : " << numD << " numD rat: "<< numD / anD << std::endl;
134  return ( 4.0 / (range) ) * ( 1 - xprime*xprime ) * ( xprime );
135  }
136 }
137 
138 LK_hack::LK_hack( etable::Etable const & etable_in ) :
139  parent( new LK_hackCreator ),
140  etable_(etable_in),
141  solv1_(etable_in.solv1()),
142  solv2_(etable_in.solv2()),
143  dsolv1_( etable_in.dsolv1() ),
144  safe_max_dis2_( etable_in.get_safe_max_dis2() ),
145  get_bins_per_A2_( etable_in.get_bins_per_A2())
146 {}
147 
148 Distance
150 {
151  return etable_.max_dis();
152 }
153 
154 /// clone
157 {
158  return new LK_hack( *this );
159 }
160 
161 LK_hack::LK_hack( LK_hack const & src ):
162  parent( src ),
163  etable_(src.etable_),
164  solv1_( src.solv1_ ),
165  solv2_( src.solv2_ ),
166  dsolv1_( src.dsolv1_ ),
167  safe_max_dis2_( src.safe_max_dis2_ ),
168  get_bins_per_A2_( src.get_bins_per_A2_ )
169 {
170 }
171 
172 
173 /////////////////////////////////////////////////////////////////////////////
174 // scoring
175 /////////////////////////////////////////////////////////////////////////////
176 
177 ///
178 void
180  conformation::Residue const & rsd1,
181  conformation::Residue const & rsd2,
182  pose::Pose const & pose,
183  ScoreFunction const &,
184  EnergyMap & emap
185 ) const
186 {
187  using namespace etable::count_pair;
188 
189  Real score(0.0);
190 
191  LK_SigmoidalFunc lksigmoidalfunc;
192 
193  CountPairFunctionOP cpfxn =
194  CountPairFactory::create_count_pair_function( rsd1, rsd2, CP_CROSSOVER_4 );
195 
196  /// allocation and deallocation of these vectors is somewhat slow.
197  utility::vector1< Vector > res1_base_vectors( rsd1.nheavyatoms(),Vector( 0.0 ));
198  utility::vector1< Vector > res2_base_vectors( rsd2.nheavyatoms(), Vector( 0.0));
199  utility::vector1< Size > res1_heavy_is_polar( rsd1.nheavyatoms(), false );
200  utility::vector1< Size > res2_heavy_is_polar( rsd2.nheavyatoms(), false );
201 
202  for ( Size i = 1, i_end = rsd1.nheavyatoms(); i <= i_end; ++i ) {
203  if (rsd1.atom_type(i).is_acceptor() || rsd1.atom_type(i).is_donor()){
204  res1_heavy_is_polar[ i ] = true;
205  Size non_H_neib = 0;
206  Vector base_pseudo_atom(0);
207  for (Size ii = 1; ii <=rsd1.bonded_neighbor(i).size(); ++ii){
208  Size neighbor_id = rsd1.bonded_neighbor(i)[ii];
209  if ( ! rsd1.atom_is_hydrogen(neighbor_id)){
210  base_pseudo_atom += rsd1.xyz(neighbor_id);
211  non_H_neib++;
212  }
213  }
214  if ( rsd1.type().n_residue_connections_for_atom(i) > 0 ) {
215  /// CONTEXT DEPENDENCY HERE -- e.g. if c_prev moves, rsd1 needs to be rescored. Fortunately,
216  /// if c_prev moves, the internal "psi" for rsd1 will be updated, and this residue will be rescored.
217  for ( Size ii = 1; ii <= rsd1.type().residue_connections_for_atom(i).size(); ++ii ) {
218  chemical::ResConnID const ii_conn = rsd1.connect_map( rsd1.type().residue_connections_for_atom(i)[ ii ] );
219  Size const neighbor_res_id( ii_conn.resid() );
220  Size const nieghbor_atom_id( pose.residue( ii_conn.resid() ).residue_connection( ii_conn.connid() ).atomno() );
221  if ( ! pose.residue( neighbor_res_id ).atom_is_hydrogen( nieghbor_atom_id ) ) {
222  base_pseudo_atom += pose.residue( neighbor_res_id ).xyz( nieghbor_atom_id );
223  non_H_neib++;
224  }
225  }
226  }
227  base_pseudo_atom /= non_H_neib;
228  res1_base_vectors[i] = rsd1.xyz(i) - base_pseudo_atom;
229  res1_base_vectors[i].normalize();
230  }
231  }
232  //same for residue 2//
233  for ( Size i = 1, i_end = rsd2.nheavyatoms(); i <= i_end; ++i ) {
234  if (rsd2.atom_type(i).is_acceptor() || rsd2.atom_type(i).is_donor()){
235  res2_heavy_is_polar[ i ] = true;
236  Size non_H_neib = 0;
237  Vector base_pseudo_atom(0);
238  for (Size ii = 1; ii <=rsd2.bonded_neighbor(i).size(); ++ii){
239  Size neighbor_id = rsd2.bonded_neighbor(i)[ii];
240  if ( ! rsd2.atom_is_hydrogen(neighbor_id) ){
241  base_pseudo_atom += rsd2.xyz(neighbor_id);
242  non_H_neib++;
243  }
244  }
245  if ( rsd2.type().n_residue_connections_for_atom(i) > 0 ) {
246  for ( Size ii = 1; ii <= rsd2.type().residue_connections_for_atom(i).size(); ++ii ) {
247  chemical::ResConnID const ii_conn = rsd2.connect_map( rsd2.type().residue_connections_for_atom(i)[ ii ] );
248  Size const neighbor_res_id( ii_conn.resid() );
249  Size const nieghbor_atom_id( pose.residue( ii_conn.resid() ).residue_connection( ii_conn.connid() ).atomno() );
250  if ( ! pose.residue( neighbor_res_id ).atom_is_hydrogen( nieghbor_atom_id ) ) {
251  base_pseudo_atom += pose.residue( neighbor_res_id ).xyz( nieghbor_atom_id );
252  non_H_neib++;
253  }
254  }
255  }
256 
257  base_pseudo_atom /= non_H_neib;
258  res2_base_vectors[i] = rsd2.xyz(i) - base_pseudo_atom;
259  res2_base_vectors[i].normalize();
260 
261  }
262  }
263 
264  Real cp_weight=0.;
265  for ( Size i = 1, i_end = rsd1.nheavyatoms(); i <= i_end; ++i){
266  for ( Size j = 1, j_end = rsd2.nheavyatoms(); j <= j_end; ++j ) {
267 
268  cp_weight = 1.0;
269  Size path_dist( 0 );
270  if ( cpfxn->count( i, j, cp_weight, path_dist ) ) {
271  /// if ( weight < 0.1 ) continue; // apl --- I don't think this ever happens
272  Real d2 = rsd1.atom(i).xyz().distance_squared( rsd2.atom(j).xyz() );
273 
274  if ( ( d2 >= safe_max_dis2_) || ( d2 == Real(0.0) ) ) continue;
275 
276  Real const d2_bin = d2 * get_bins_per_A2_;
277  int disbin = static_cast< int >( d2_bin ) + 1;
278  Real frac = d2_bin - ( disbin - 1 );
279  int const l1 = solv1_.index( disbin, rsd2.atom(j).type(), rsd1.atom(i).type() ); // atom i being desolvated by atom j
280  int const l2 = l1 + 1;
281 
282  Vector i_to_j_vec( rsd2.xyz( j ) - rsd1.xyz( i ) );
283  bool i_to_j_vec_normalized( false ); // don't normalize twice!
284 
285  Real i_to_j_angle_weight( 1.0 ), j_to_i_angle_weight( 1.0 );
286 
287  if ( res1_heavy_is_polar[i] ) {
288  if (res1_base_vectors[i].dot( i_to_j_vec ) >= 0 ) {
289  //std::cout << "Normalizing i_to_j" << std::endl;
290 
291  i_to_j_vec *= 1 / ( std::sqrt( d2 ) ); /// we already have d2, reuse it
292  i_to_j_vec_normalized = true;
293  Real dotprod = res1_base_vectors[i].dot( i_to_j_vec );
294  //std::cout << "r1 base dot prod: " << dotprod << " angle " << radians_to_degrees * (pi - std::acos( dotprod )) << " with " << rsd2.seqpos() << " " << j << std::endl;
296  // noop, i_to_j weight is already 1.
297  } else if ( dotprod <= LK_SigmoidalFunc::cos_flipped_ANGLE_CUTOFF_LOW ) {
298  i_to_j_angle_weight = 0;
299  } else {
300  Real angle = pi - std::acos( dotprod );
301  i_to_j_angle_weight = lksigmoidalfunc.func( angle );
302  //std::cout << "Angle: " << radians_to_degrees * angle << " func " << i_to_j_angle_weight << std::endl;
303  }
304  } else { // Dot product is 0 or negative; do not count this interaction
305  i_to_j_angle_weight = 0.0;
306  }
307  } // else, rsd1 is apolar, and its weight should be 1, which it already is
308 
309  //std::cout << "Desolvation of atom i: " << rsd1.atom_name( i ) << " on " << rsd1.name() << " with weight: " << i_to_j_angle_weight << std::endl;
310  if ( i_to_j_angle_weight != 0 ) {
311  score += i_to_j_angle_weight * cp_weight * ( (1.-frac)* solv1_[ l1 ] + frac * solv1_[ l2 ]);
312  }
313 
314  if ( res2_heavy_is_polar[j] ) {
315  Vector j_to_i_vec = -1 * i_to_j_vec;
316  if (res2_base_vectors[j].dot( j_to_i_vec ) > 0 ) {
317  if ( ! i_to_j_vec_normalized ) {
318  //std::cout << "Normalizing j_to_i" << std::endl;
319  j_to_i_vec *= 1 / ( std::sqrt( d2 ));
320  }
321  Real dotprod = res2_base_vectors[j].dot( j_to_i_vec );
322  //std::cout << "r2 base dot prod: " << dotprod << " angle " << radians_to_degrees * (pi - std::acos( dotprod )) << " with " << rsd1.seqpos() << " " << i << std::endl;
323 
325  // noop, i_to_j weight is already 1.
326  } else if ( dotprod <= LK_SigmoidalFunc::cos_flipped_ANGLE_CUTOFF_LOW ) {
327  j_to_i_angle_weight = 0;
328  } else {
329  Real angle = pi - std::acos( dotprod );
330  j_to_i_angle_weight = lksigmoidalfunc.func( angle );
331  //std::cout << "Angle: " << radians_to_degrees * angle << " func " << j_to_i_angle_weight << std::endl;
332 
333  }
334  } else { // Dot product is 0 or negative; do not count this interaction
335  j_to_i_angle_weight = 0.0;
336  }
337  } // else, rsd2 is apolar, and its weight should be 1, which it already is
338 
339  //std::cout << "Desolvation of atom j: " << rsd2.atom_name( j ) << " on " << rsd2.name() << " with weight: " << j_to_i_angle_weight << std::endl;
340  if ( j_to_i_angle_weight != 0 ) {
341  score += j_to_i_angle_weight * cp_weight * ( (1.-frac)* solv2_[ l1 ] + frac * solv2_[ l2 ]);
342  }
343  //std::cout << "Finished pair " << i << " " << j << std::endl;
344  }
345  }
346  }
347 
348  emap[ lk_hack ]+=score;
349 
350 }
351 
352 /////////////////////////////////////////////////////////////////////////////
353 // derivatives
354 /////////////////////////////////////////////////////////////////////////////
355 
356 void
358  pose::Pose & pose,
359  ScoreFunction const & sfxn
360 ) const
361 {
363 
364  lk_hack_weight_ = sfxn.weights()[ lk_hack ];
369 }
370 
371 void
373 {
374  Size const total_residue( pose.total_residue() );
375 
376  nneighbs_.resize( total_residue );
377  orientation_vectors_.resize( total_residue );
378  base_pseudo_atom_centers_.resize( total_residue );
379  atom_f1_f2s_.resize( total_residue );
380  base_pseudo_atom_f1_f2s_.resize( total_residue );
381 
382  for ( Size ii = 1; ii <= total_residue; ++ii ) {
383  Size const ii_nheavy( pose.residue( ii ).nheavyatoms() );
384  nneighbs_[ ii ].resize( ii_nheavy );
385  orientation_vectors_[ ii ].resize( ii_nheavy );
386  base_pseudo_atom_centers_[ ii ].resize( ii_nheavy );
387  atom_f1_f2s_[ ii ].resize( ii_nheavy );
388  base_pseudo_atom_f1_f2s_[ ii ].resize( ii_nheavy );
389  for ( Size jj = 1; jj <= ii_nheavy; ++jj ) {
390  nneighbs_[ ii ][ jj ] = 0;
391  orientation_vectors_[ ii ][ jj ] = Vector( 0.0 );
392  base_pseudo_atom_centers_[ ii ][ jj ] = Vector( 0.0 );
393  atom_f1_f2s_[ ii ][ jj ].first = Vector(0.0);
394  atom_f1_f2s_[ ii ][ jj ].second = Vector(0.0);
395  base_pseudo_atom_f1_f2s_[ ii ][ jj ].first = Vector(0.0);
396  base_pseudo_atom_f1_f2s_[ ii ][ jj ].second = Vector(0.0);
397  }
398  }
399 }
400 
401 void
403 {
404  using namespace conformation;
405 
406  Size const total_residue( pose.total_residue() );
407 
408  for ( Size ii = 1; ii <= total_residue; ++ii ) {
409  Size const ii_nheavy( pose.residue( ii ).nheavyatoms() );
410  Residue const & ii_res( pose.residue( ii ));
411  for ( Size jj = 1; jj <= ii_nheavy; ++jj ) {
412  if (ii_res.atom_type(jj).is_acceptor() || ii_res.atom_type(jj).is_donor()) {
413  for (Size kk = 1; kk <= ii_res.bonded_neighbor(jj).size(); ++kk){
414  Size neighbor_id = ii_res.bonded_neighbor(jj)[kk];
415  if ( ! ii_res.atom_is_hydrogen(neighbor_id)){
416  base_pseudo_atom_centers_[ii][jj] += ii_res.xyz(neighbor_id);
417  ++nneighbs_[ii][jj];
418  }
419  }
420  if ( ii_res.type().n_residue_connections_for_atom(jj) > 0 ) {
421  for ( Size kk = 1; kk <= ii_res.type().residue_connections_for_atom(jj).size(); ++kk ) {
422  chemical::ResConnID kk_conn = ii_res.connect_map( ii_res.type().residue_connections_for_atom(jj)[ kk ] );
423  Size const neighbor_res_id( kk_conn.resid() );
424  Size const nieghbor_atom_id( pose.residue( kk_conn.resid() ).residue_connection( kk_conn.connid() ).atomno() );
425  if ( ! pose.residue( neighbor_res_id ).atom_is_hydrogen( nieghbor_atom_id ) ) {
426  base_pseudo_atom_centers_[ii][jj] += pose.residue( neighbor_res_id ).xyz( nieghbor_atom_id );
427  ++nneighbs_[ii][jj];
428  }
429  }
430  }
431  if ( nneighbs_[ii][jj] != 0 ) {
432  base_pseudo_atom_centers_[ii][jj] /= nneighbs_[ii][jj];
433  orientation_vectors_[ii][jj] = ii_res.xyz( jj ) - base_pseudo_atom_centers_[ii][jj];
434  }
435  } //end if
436  }//end for jj
437  } // end for ii
438  for ( Size ii = 1; ii <= total_residue; ++ii ) {
439  for ( Size jj = 1, jje = orientation_vectors_[ii].size(); jj <= jje; ++jj ) {
440  if ( nneighbs_[ii][jj] != 0 ) {
441  orientation_vectors_[ ii ][ jj ].normalize_or_zero();
442  }
443  }
444  }
445 }
446 
447 
448 void
450 {
451  using namespace constraints;
452 
453  Size const total_residue( pose.total_residue() );
454 
455  // cached energies object
456  Energies const & energies( pose.energies() );
457 
458  // the neighbor/energy links
459  EnergyGraph const & energy_graph( energies.energy_graph() );
460 
461  for ( Size ii = 1; ii <= total_residue; ++ii ) {
463  iru = energy_graph.get_node(ii)->const_upper_edge_list_begin(),
464  irue = energy_graph.get_node(ii)->const_upper_edge_list_end();
465  iru != irue; ++iru ) {
466  Size jj = (*iru)->get_second_node_ind();
468  }
469  }
470 }
471 
472 void
474 (
475  pose::Pose const & pose,
476  Size lower_res_id,
477  Size upper_res_id
478 ) const
479 {
480  using namespace etable::count_pair;
481 
482  FuncOP lkfunc = new LK_SigmoidalFunc;
483  AngleConstraint lk_angle_cst( lkfunc ); //Using the stupid and dangerous version of the AngleConstraint ctor
484 
485  conformation::Residue const & lowerres( pose.residue( lower_res_id ) );
486  conformation::Residue const & upperres( pose.residue( upper_res_id ) );
487 
488  CountPairFunctionOP cpfxn =
489  CountPairFactory::create_count_pair_function( lowerres, upperres, CP_CROSSOVER_4 );
490 
491  for ( Size ii = 1, iie = lowerres.nheavyatoms(), jje = upperres.nheavyatoms();
492  ii <= iie; ++ii ) {
493  for ( Size jj = 1; jj <= jje; ++jj ) {
494  Real cp_weight = 1.0;
495  Size path_dist( 0 );
496  if ( ! cpfxn->count( ii, jj, cp_weight, path_dist ) ) continue;
497 
498  Vector ii_to_jj = upperres.xyz( jj ) - lowerres.xyz( ii );
499  DistanceSquared ii_jj_dis2 = ii_to_jj.norm_squared();
500 
501  if ( ii_jj_dis2 > safe_max_dis2_ || ii_jj_dis2 == 0.0 ) continue;
502  Distance const ii_jj_one_over_d( 1 / (std::sqrt( ii_jj_dis2 )));
503  ii_to_jj *= ii_jj_one_over_d; // normalize
504 
505  /// 1. Atom jj's desolvation of atom ii.
506  if ( nneighbs_[ lower_res_id ][ ii ] != 0 ) { // ii polar
507  Real const dot_prod = ii_to_jj.dot(orientation_vectors_[lower_res_id][ ii ]);
508  //std::cout << "Derivative for lowerres " << lowerres.atom_name( ii ) << " on " << lowerres.name() << " dotprod: " << dot_prod << " with " << upper_res_id << " " << jj << std::endl;
509  if ( dot_prod > 0 && dot_prod > LK_SigmoidalFunc::cos_flipped_ANGLE_CUTOFF_LOW ) {
510 
511  Vector f1_ii( 0.0 ), f2_ii( 0.0 ), f1_jj( 0.0 ), f2_jj( 0.0 );
512 
513  Real const dE_dR_over_r(
515  lowerres.atom(ii), upperres.atom(jj),
516  ii_jj_one_over_d, ii_jj_dis2,
517  f1_ii, f2_ii, f1_jj, f2_jj ) );
518 
520  /// sigmoidal function evaluates to 1 and its derivative is 0
521  atom_f1_f2s_[ lower_res_id ][ ii ].first += dE_dR_over_r * cp_weight * f1_ii;
522  atom_f1_f2s_[ lower_res_id ][ ii ].second += dE_dR_over_r * cp_weight * f2_ii;
523  atom_f1_f2s_[ upper_res_id ][ jj ].first += dE_dR_over_r * cp_weight * f1_jj;
524  atom_f1_f2s_[ upper_res_id ][ jj ].second += dE_dR_over_r * cp_weight * f2_jj;
525  } else { // ( dot_prod < cos_flipped_ANGLE_CUTOFF_HIGH && dot_prod > cos_flipped_ANGLE_CUTOFF_LOW ) {
526  /// ramping range of sigmoidal function "w"
527  /// Energy is w*lk; derivative is w'*lk + w*lk'
528  /// lk' already computed
529 
530  // lk
531  Real const d2_bin = ii_jj_dis2 * get_bins_per_A2_;
532  int disbin = static_cast< int >( d2_bin ) + 1;
533  Real frac = d2_bin - ( disbin - 1 );
534  int const l1 = solv1_.index( disbin, upperres.atom(jj).type(), lowerres.atom(ii).type() );
535  int const l2 = l1 + 1;
536  Real const lk = lk_hack_weight_ * cp_weight * ( (1.-frac)* solv1_[ l1 ] + frac * solv1_[ l2 ]);
537 
538  // w'
539  Vector w_f1_ii( 0.0 ), w_f2_ii( 0.0 ), w_f1_jj( 0.0 ), w_f2_jj( 0.0 ), w_f1_ii_pbase( 0.0 ), w_f2_ii_pbase( 0.0 );
540  lk_angle_cst.p1_deriv(
541  base_pseudo_atom_centers_[ lower_res_id ][ ii ], lowerres.xyz( ii ), upperres.xyz( jj ),
542  w_f1_ii_pbase, w_f2_ii_pbase );
543 
544  lk_angle_cst.p2_deriv(
545  base_pseudo_atom_centers_[ lower_res_id ][ ii ], lowerres.xyz( ii ), upperres.xyz( jj ),
546  w_f1_ii, w_f2_ii );
547 
548  lk_angle_cst.p1_deriv(
549  upperres.xyz( jj ), lowerres.xyz( ii ), base_pseudo_atom_centers_[ lower_res_id ][ ii ],
550  w_f1_jj, w_f2_jj );
551 
552  /// w
553  Real const w = lkfunc->func(
554  angle_radians(
555  base_pseudo_atom_centers_[ lower_res_id ][ ii ],
556  lowerres.xyz( ii ),
557  upperres.xyz( jj ) ) );
558 
559  //// Add everything up
560  atom_f1_f2s_[ lower_res_id ][ ii ].first += w * dE_dR_over_r * cp_weight * f1_ii;
561  atom_f1_f2s_[ lower_res_id ][ ii ].second += w * dE_dR_over_r * cp_weight * f2_ii;
562  atom_f1_f2s_[ upper_res_id ][ jj ].first += w * dE_dR_over_r * cp_weight * f1_jj;
563  atom_f1_f2s_[ upper_res_id ][ jj ].second += w * dE_dR_over_r * cp_weight * f2_jj;
564 
565  atom_f1_f2s_[ lower_res_id ][ ii ].first += lk * w_f1_ii;
566  atom_f1_f2s_[ lower_res_id ][ ii ].second += lk * w_f2_ii;
567  atom_f1_f2s_[ upper_res_id ][ jj ].first += lk * w_f1_jj;
568  atom_f1_f2s_[ upper_res_id ][ jj ].second += lk * w_f2_jj;
569  base_pseudo_atom_f1_f2s_[ lower_res_id ][ ii ].first += lk * w_f1_ii_pbase;
570  base_pseudo_atom_f1_f2s_[ lower_res_id ][ ii ].second += lk * w_f2_ii_pbase;
571 
572  }
573  }
574  } else {
575  // ii apolar or water.
576  Vector f1_ii, f2_ii, f1_jj, f2_jj;
577 
578  Real const dE_dR_over_r(
580  lowerres.atom(ii), upperres.atom(jj),
581  ii_jj_one_over_d, ii_jj_dis2,
582  f1_ii, f2_ii, f1_jj, f2_jj ) );
583 
584  if ( dE_dR_over_r != 0.0 ) {
585  atom_f1_f2s_[ lower_res_id ][ ii ].first += dE_dR_over_r * cp_weight * f1_ii;
586  atom_f1_f2s_[ lower_res_id ][ ii ].second += dE_dR_over_r * cp_weight * f2_ii;
587  atom_f1_f2s_[ upper_res_id ][ jj ].first += dE_dR_over_r * cp_weight * f1_jj;
588  atom_f1_f2s_[ upper_res_id ][ jj ].second += dE_dR_over_r * cp_weight * f2_jj;
589  }
590  }
591 
592  /// 2. Atom ii's desolvation of atom jj
593  if ( nneighbs_[ upper_res_id ][ jj ] != 0 ) { // jj polar
594  Vector jj_to_ii = -1*ii_to_jj;
595  Real dot_prod = jj_to_ii.dot( orientation_vectors_[upper_res_id][ jj ] );
596  //std::cout << "Derivative for upperres " << upperres.atom_name( jj ) << " on " << upperres.name() << " dotprod: " << dot_prod << " with " << lower_res_id << " " << ii << std::endl;
597 
598  if ( dot_prod > 0 && dot_prod > LK_SigmoidalFunc::cos_flipped_ANGLE_CUTOFF_LOW) {
599 
600  Vector f1_jj( 0.0 ), f2_jj( 0.0 ), f1_ii( 0.0 ), f2_ii( 0.0 );
601 
602  Real const dE_dR_over_r(
604  upperres.atom(jj), lowerres.atom(ii),
605  ii_jj_one_over_d, ii_jj_dis2,
606  f1_jj, f2_jj, f1_ii, f2_ii ) );
607 
609  /// sigmoidal function evaluates to 1 and its derivative is 0
610  atom_f1_f2s_[ upper_res_id ][ jj ].first += dE_dR_over_r * cp_weight * f1_jj;
611  atom_f1_f2s_[ upper_res_id ][ jj ].second += dE_dR_over_r * cp_weight * f2_jj;
612  atom_f1_f2s_[ lower_res_id ][ ii ].first += dE_dR_over_r * cp_weight * f1_ii;
613  atom_f1_f2s_[ lower_res_id ][ ii ].second += dE_dR_over_r * cp_weight * f2_ii;
614  } else { // ( dot_prod < cos_flipped_ANGLE_CUTOFF_HIGH && dot_prod > cos_flipped_ANGLE_CUTOFF_LOW ) {
615  /// ramping range of sigmoidal function "w"
616  /// Energy is w*lk; chain rule says the derivative is w'*lk + w*lk'
617  /// lk' already computed
618 
619  // lk
620  Real const d2_bin = ii_jj_dis2 * get_bins_per_A2_;
621  int disbin = static_cast< int >( d2_bin ) + 1;
622  Real frac = d2_bin - ( disbin - 1 );
623  int const l1 = solv1_.index( disbin, lowerres.atom(ii).type(), upperres.atom(jj).type() );
624  int const l2 = l1 + 1;
625  Real const lk = lk_hack_weight_ * cp_weight * ( (1.-frac)* solv1_[ l1 ] + frac * solv1_[ l2 ]);
626 
627  // w'
628  Vector w_f1_jj(0.0), w_f2_jj(0.0), w_f1_ii(0.0), w_f2_ii(0.0), w_f1_jj_pbase(0.0), w_f2_jj_pbase(0.0);
629  lk_angle_cst.p1_deriv(
630  base_pseudo_atom_centers_[ upper_res_id ][ jj ], upperres.xyz( jj ), lowerres.xyz( ii ),
631  w_f1_jj_pbase, w_f2_jj_pbase );
632 
633  lk_angle_cst.p2_deriv(
634  base_pseudo_atom_centers_[ upper_res_id ][ jj ], upperres.xyz( jj ), lowerres.xyz( ii ),
635  w_f1_jj, w_f2_jj );
636 
637  lk_angle_cst.p1_deriv(
638  lowerres.xyz( ii ), upperres.xyz( jj ), base_pseudo_atom_centers_[ upper_res_id ][ jj ],
639  w_f1_ii, w_f2_ii );
640 
641  /// w
642  Real const w = lkfunc->func(
643  angle_radians(
644  base_pseudo_atom_centers_[ upper_res_id ][ jj ],
645  upperres.xyz( jj ),
646  lowerres.xyz( ii ) ) );
647 
648  //// Add everything up
649  atom_f1_f2s_[ upper_res_id ][ jj ].first += w * dE_dR_over_r * cp_weight * f1_jj;
650  atom_f1_f2s_[ upper_res_id ][ jj ].second += w * dE_dR_over_r * cp_weight * f2_jj;
651  atom_f1_f2s_[ lower_res_id ][ ii ].first += w * dE_dR_over_r * cp_weight * f1_ii;
652  atom_f1_f2s_[ lower_res_id ][ ii ].second += w * dE_dR_over_r * cp_weight * f2_ii;
653 
654  atom_f1_f2s_[ upper_res_id ][ jj ].first += lk * w_f1_jj;
655  atom_f1_f2s_[ upper_res_id ][ jj ].second += lk * w_f2_jj;
656  atom_f1_f2s_[ lower_res_id ][ ii ].first += lk * w_f1_ii;
657  atom_f1_f2s_[ lower_res_id ][ ii ].second += lk * w_f2_ii;
658  base_pseudo_atom_f1_f2s_[ upper_res_id ][ jj ].first += lk * w_f1_jj_pbase;
659  base_pseudo_atom_f1_f2s_[ upper_res_id ][ jj ].second += lk * w_f2_jj_pbase;
660 
661  }
662  }
663  } else {
664  // jj apolar or water.
665  Vector f1_jj, f2_jj, f1_ii, f2_ii;
666 
667  Real const dE_dR_over_r(
669  upperres.atom(jj), lowerres.atom(ii),
670  ii_jj_one_over_d, ii_jj_dis2,
671  f1_jj, f2_jj, f1_ii, f2_ii ) );
672 
673  if ( dE_dR_over_r != 0.0 ) {
674  atom_f1_f2s_[ upper_res_id ][ jj ].first += dE_dR_over_r * cp_weight * f1_jj;
675  atom_f1_f2s_[ upper_res_id ][ jj ].second += dE_dR_over_r * cp_weight * f2_jj;
676  atom_f1_f2s_[ lower_res_id ][ ii ].first += dE_dR_over_r * cp_weight * f1_ii;
677  atom_f1_f2s_[ lower_res_id ][ ii ].second += dE_dR_over_r * cp_weight * f2_ii;
678  }
679  }
680  }
681  }
682 }
683 
684 /// @details Evaluate the weighted derivative of atom2's desolvatation of atom1
685 Real
687  conformation::Atom const & atom1,
688  conformation::Atom const & atom2,
689  Distance const one_over_d, // known
690  DistanceSquared const d2, // known
691  Vector & f1_1,
692  Vector & f2_1,
693  Vector & f1_2,
694  Vector & f2_2
695 ) const
696 {
697  f1_1 = atom1.xyz().cross( atom2.xyz() );
698  f2_1 = atom1.xyz() - atom2.xyz();
699  f1_2 = -1.0 * f1_1;
700  f2_2 = -1.0 * f2_1;
701 
702  if ( ( d2 < safe_max_dis2_) && ( d2 != Real(0.0) ) ) {
703 
704  Real const d2_bin = d2 * get_bins_per_A2_;
705  int disbin = static_cast< int >( d2_bin ) + 1;
706  Real frac = d2_bin - ( disbin - 1 );
707 
708  Real deriv = 0.0;
709 
710  // l1 and l2 are FArray LINEAR INDICES for fast lookup:
711  // [ l1 ] == (disbin ,attype2,attype1)
712  // [ l2 ] == (disbin+1,attype2,attype1)
713 
714  int const l1 = dsolv1_.index( disbin, atom2.type(), atom1.type() ),
715  l2 = l1 + 1;
716 
717  Real e1 = dsolv1_[ l1 ];
718  deriv = lk_hack_weight_ * ( e1 + frac * ( dsolv1_[ l2 ] - e1 ) );
719 
720  //std::cout << "dsolv1_ deriv: " << deriv << " numeric: " << ((solv1_[ l2 ] - solv1_[ l1 ] )*get_bins_per_A2_)*2*sqrt(d2) << std::endl;
721 
722  return deriv * one_over_d;
723  } else {
724  return 0.0;
725  }
726 
727 }
728 
729 /// @details iterates across polar atoms, and increments the f1/f2 derivative vectors
730 /// a proportion of the derivative vectors each atom's pseudo-base atom had accumulated
731 /// into the derivatives of the atom's bonded neighbors
732 void
734 {
735  Size const total_residue = base_pseudo_atom_f1_f2s_.size();
736  for ( Size ii = 1; ii <= total_residue; ++ii ) {
737  Size const ii_nheavy = base_pseudo_atom_f1_f2s_[ ii ].size();
738  conformation::Residue const & ii_res( pose.residue( ii ) );
739  for ( Size jj = 1; jj <= ii_nheavy; ++jj ) {
740  if ( nneighbs_[ ii ][ jj ] == 0 ) continue;
741  Size jj_nneighbs( nneighbs_[ ii ][ jj ] );
742  Real divvy_proportion = 1.0 / jj_nneighbs;
743 
744  Vector const f1_to_divvy = divvy_proportion * base_pseudo_atom_f1_f2s_[ ii ][ jj ].first;
745  Vector const f2_to_divvy = divvy_proportion * base_pseudo_atom_f1_f2s_[ ii ][ jj ].second;
746 
747  Size count_neighbors_found = 0;
748  for (Size kk = 1; kk <= ii_res.bonded_neighbor(jj).size(); ++kk){
749  Size neighbor_id = ii_res.bonded_neighbor(jj)[kk];
750  if ( ! ii_res.atom_is_hydrogen(neighbor_id) ){
751  ++count_neighbors_found;
752  atom_f1_f2s_[ ii ][ neighbor_id ].first += f1_to_divvy;
753  atom_f1_f2s_[ ii ][ neighbor_id ].second += f2_to_divvy;
754  }
755  }
756  if ( ii_res.type().n_residue_connections_for_atom( jj ) > 0 ) {
757  for ( Size kk = 1; kk <= ii_res.type().residue_connections_for_atom(jj).size(); ++kk ) {
758 
759  chemical::ResConnID const kk_conn = ii_res.connect_map( ii_res.type().residue_connections_for_atom( jj )[ kk ] );
760  Size const neighbor_res_id( kk_conn.resid() );
761  Size const nieghbor_atom_id( pose.residue( kk_conn.resid() ).residue_connection( kk_conn.connid() ).atomno() );
762  if ( ! pose.residue( neighbor_res_id ).atom_is_hydrogen( nieghbor_atom_id ) ) {
763  atom_f1_f2s_[ neighbor_res_id ][ nieghbor_atom_id ].first += f1_to_divvy;
764  atom_f1_f2s_[ neighbor_res_id ][ nieghbor_atom_id ].second += f2_to_divvy;
765  count_neighbors_found++;
766  }
767  }
768  }
769  assert( count_neighbors_found == jj_nneighbs );
770  }
771  }
772 
773 }
774 
775 
776 void
778  id::AtomID const & id,
779  pose::Pose const & pose,
780  kinematics::DomainMap const &, // domain_map,
781  ScoreFunction const &,// sfxn,
782  EnergyMap const & ,//weights,
783  Vector & F1,
784  Vector & F2
785 ) const
786 {
787  if ( pose.residue( id.rsd() ).atom_is_hydrogen( id.atomno() ) ) return;
788 
789  F1 += atom_f1_f2s_[ id.rsd() ][ id.atomno() ].first;
790  F2 += atom_f1_f2s_[ id.rsd() ][ id.atomno() ].second;
791 }
792 
793 
794 
795 void
797  utility::vector1< bool > & /* context_graphs_required */ ) const
798 {}
801 {
802  return 1; // Initial versioning
803 }
804 
805 }
806 }
807 }
808 
809 
810