Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SemiExplicitWaterUnsatisfiedPolarsCalculator.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 /// @begin SemiExplicitWaterUnsatisfiedPolarsCalculator
11 ///
12 /// @brief
13 /// How many unsatisfied polars are there?
14 ///
15 /// @detailed
16 /// Buried unsatisfied polar hbonds are destabilizing for proteins. It is good to have less.
17 /// In a study of 2299 high resolution crystal structures of 1.5A or better, there was an average
18 /// 71 unsatisfied buried polar hbonds. The normalized average (normalized against aa #) was 0.30 (unpublished).
19 /// To get this piece of code to work, you must first load in your pdb. Then, you need the following lines:
20 ///
21 /// core::pose::metrics::PoseMetricCalculatorOP num_hbonds_calculator = new protocols::toolbox::pose_metric_calculators::NumberHBondsCalculator();
22 /// core::pose::metrics::CalculatorFactory::Instance().register_calculator( "num_hbonds", num_hbonds_calculator );
23 ///
24 /// core::pose::metrics::PoseMetricCalculatorOP unsat_calculator = new protocols::toolbox::pose_metric_calculators::SemiExplicitWaterUnsatisfiedPolarsCalculator("num_hbonds");
25 /// core::pose::metrics::CalculatorFactory::Instance().register_calculator( "unsat", unsat_calculator );
26 ///
27 /// This segment of code sets everything up to be used in the calculator. To use this on your protein, you simply need to
28 /// write the following: pose.print_metric("unsat", "all_unsat_polars");
29 ///
30 /// @author
31 /// Chris King
32 /// Steven Combs - comments
33 ///
34 /// @last_modified 9/2/2011
35 /////////////////////////////////////////////////////////////////////////
36 /// @file core/pose/metrics/SemiExplicitWaterUnsatisfiedPolarsCalculator.cc
37 /// @brief number of hbonds calculator class
38 /// @author Chris King, templated off of BuriedUnsatisfiedPolarsCalculator by Florian Richter
39 
40 // Unit headers
42 
46 #include <core/pose/Pose.hh>
48 
49 // AUTO-REMOVED #include <numeric/random/random.hh>
50 
52 #include <core/scoring/Energies.hh>
54 // AUTO-REMOVED #include <core/scoring/hbonds/HBondSet.hh>
58 // AUTO-REMOVED #include <core/kinematics/MoveMap.hh>
60 #include <core/kinematics/Jump.hh>
63 
64 //protocol headers
65 // AUTO-REMOVED #include <protocols/simple_moves/MinMover.hh>
66 // AUTO-REMOVED #include <protocols/moves/MonteCarlo.hh>
67 // AUTO-REMOVED #include <protocols/rigid/RB_geometry.hh>
68 
69 
70 // Utility headers
71 #include <basic/Tracer.hh>
72 #include <utility/exit.hh>
73 #include <utility/stream_util.hh>
74 #include <utility/string_util.hh>
75 #include <basic/MetricValue.hh>
76 
77 
78 #include <cassert>
79 
81 #include <utility/vector1.hh>
82 #include <numeric/constants.hh>
83 
84 
85 
86 using namespace core;
87 using namespace core::pose;
88 using namespace core::pose::metrics;
89 using utility::vector1;
90 using std::string;
91 using utility::to_string;
92 using numeric::constants::f::pi;
93 using numeric::constants::f::pi_2;
94 
95 static basic::Tracer TR("protocols.toolbox.PoseMetricCalculators.SemiExplicitWaterUnsatisfiedPolarsCalculator");
96 
97 namespace protocols{
98 namespace toolbox {
99 namespace pose_metric_calculators {
100 
101 SemiExplicitWaterUnsatisfiedPolarsCalculator::SemiExplicitWaterUnsatisfiedPolarsCalculator(
102  std::string hbond_calc,
103  scoring::ScoreFunctionOP scorefxn,
104  core::Real semiexpl_water_cutoff
105 ) : hb_database_( core::scoring::hbonds::HBondDatabase::get_database( "standard_params" ) ),
106  all_unsat_polars_( 0 ),
107  special_region_unsat_polars_(0),
108  semiexpl_water_cutoff_( semiexpl_water_cutoff ),
109  name_of_hbond_calc_( hbond_calc ),
110  scorefxn_( scorefxn )
111 {
112  atom_unsat_.clear();
113  residue_unsat_polars_.clear();
115  residue_semiexpl_score_.clear();
116  special_region_.clear();
118 
119 }
120 
122  std::string hbond_calc,
123  scoring::ScoreFunctionOP scorefxn,
124  std::set< core::Size > const & special_region,
125  core::Real semiexpl_water_cutoff
126 ) : hb_database_( core::scoring::hbonds::HBondDatabase::get_database( "standard_params" ) ),
127  all_unsat_polars_(0),
128  special_region_unsat_polars_(0),
129  semiexpl_water_cutoff_( semiexpl_water_cutoff ),
130  name_of_hbond_calc_( hbond_calc ),
131  scorefxn_( scorefxn ),
132  special_region_( special_region )
133 {
134  atom_unsat_.clear();
135  residue_unsat_polars_.clear();
137  residue_semiexpl_score_.clear();
139 }
140 
141 
142 void
144 {
145  if( !CalculatorFactory::Instance().check_calculator_exists( name_of_hbond_calc_ ) ){
146  if( name_of_hbond_calc_ != "default" ) TR << "Attention: couldn't find the specified hbond calculator ( " << name_of_hbond_calc_ << " ), instantiating default one." << std::endl;
147  name_of_hbond_calc_ = "unsat_calc_default_hbond_calc";
148  if( !CalculatorFactory::Instance().check_calculator_exists( name_of_hbond_calc_ ) ){
149  CalculatorFactory::Instance().register_calculator( name_of_hbond_calc_, new NumberHBondsCalculator() );
150  }
151  }
152 }
153 
154 
155 void
157  std::string const & key,
158  basic::MetricValueBase * valptr
159 ) const
160 {
161 
162  if ( key == "all_unsat_polars" ) {
163  basic::check_cast( valptr, &all_unsat_polars_, "all_unsat_polars expects to return a Size" );
164  (static_cast<basic::MetricValue<Size> *>(valptr))->set( all_unsat_polars_ );
165 
166  } else if ( key == "special_region_unsat_polars" ) {
167  basic::check_cast( valptr, &special_region_unsat_polars_, "special_region_unsat_polars expects to return a Size" );
168  (static_cast<basic::MetricValue<Size> *>(valptr))->set( special_region_unsat_polars_ );
169 
170  } else if ( key == "atom_unsat" ) {
171  basic::check_cast( valptr, &atom_unsat_, "atom_unsat expects to return a id::AtomID_Map< bool >" );
172  (static_cast<basic::MetricValue<id::AtomID_Map< bool > > *>(valptr))->set( atom_unsat_ );
173 
174  } else if ( key == "atom_semiexpl_score" ) {
175  basic::check_cast( valptr, &atom_semiexpl_score_, "atom_semiexpl_score expects to return a id::AtomID_Map< Real >" );
176  (static_cast<basic::MetricValue<id::AtomID_Map< Real > > *>(valptr))->set( atom_semiexpl_score_ );
177 
178  } else if ( key == "residue_unsat_polars" ) {
179  basic::check_cast( valptr, &residue_unsat_polars_, "residue_unsat_polars expects to return a utility::vector1< Size >" );
180  (static_cast<basic::MetricValue<utility::vector1< Size > > *>(valptr))->set( residue_unsat_polars_ );
181 
182  } else if ( key == "residue_semiexpl_score" ) {
183  basic::check_cast( valptr, &residue_semiexpl_score_, "residue_semiexpl_score expects to return a utility::vector1< Real >" );
184  (static_cast<basic::MetricValue<utility::vector1< Real > > *>(valptr))->set( residue_semiexpl_score_ );
185 
186  } else {
187  basic::Error() << "SemiExplicitWaterUnsatisfiedPolarsCalculator cannot compute the requested metric " << key << std::endl;
188  utility_exit();
189  }
190 
191 } //lookup
192 
193 
194 
197 {
198 
199  if ( key == "all_unsat_polars" ) {
200  return utility::to_string( all_unsat_polars_ );
201  } else if ( key == "special_region_unsat_polars" ) {
202  return utility::to_string( special_region_unsat_polars_ );
203  } else if ( key == "atom_Hbonds" ) {
204  basic::Error() << "id::AtomID_Map< bool > has no output operator, for metric " << key << std::endl;
205  utility_exit();
206  } else if ( key == "residue_unsat_polars" ) {
207  return utility::to_string( residue_unsat_polars_ );
208  }
209 
210  basic::Error() << "SemiExplicitWaterUnsatisfiedPolarsCalculator cannot compute metric " << key << std::endl;
211  utility_exit();
212  return "";
213 
214 } //print
215 
216 //check for clashes based on atom distances
217 //only check atoms in AtomID vector
218 //should be way faster than calculating entire score
219 bool
221  Pose const & pose,
222  vector1< id::AtomID > const check_atids,
223  Real const clash_dist_cut
224 )
225 {
226  Real const clash_dist2_cut( clash_dist_cut * clash_dist_cut );
227  for( Size iatid = 1; iatid <= check_atids.size(); ++iatid ){
228  Vector const at1_xyz( pose.xyz( check_atids[ iatid ] ) );
229  for( Size res2 = 1; res2 <= pose.total_residue(); ++res2 ){
230  for( Size at2 = 1; at2 <= pose.residue( res2 ).natoms(); ++at2 ){
231  //skip virtual atoms!
232  if( pose.residue( res2 ).atom_type( at2 ).lj_wdepth() == 0.0 ) continue;
233  id::AtomID atid2( at2, res2 );
234  //skip if atid2 is in check_atids
235  bool skip_at2( false );
236  for( Size jatid = 1; jatid <= check_atids.size(); ++jatid ){
237  if( atid2 == check_atids[ jatid ] ){ skip_at2 = true; break; }
238  }
239  if( skip_at2 ) continue;
240  Real const dist2( at1_xyz.distance_squared( pose.xyz( atid2 ) ) );
241  if( dist2 < clash_dist2_cut ){
242  //TR_unsat << "CLASH!: " << check_atids[ iatid ] << " - " << atid2 <<
243  // " = " << dist2 << std::endl;
244  return true;
245  }
246  }
247  }
248  }
249  return false;
250 }
251 
252 
253 
254 Real
256  pose::Pose pose,
257  scoring::ScoreFunctionOP scorefxn,
258  Size seqpos,
259  Size atomno,
260  conformation::Residue new_rsd,
261  Size new_atomno
262 )
263 {
264  using namespace id;
265  using namespace conformation;
266  using namespace scoring;
267  using namespace scoring::hbonds;
268  using namespace kinematics;
269 
270  Residue rsd( pose.residue( seqpos ) );
271  Pose ref_pose( pose );
272  //store hbond e before adding water
273  /*Real rsd_hbond_e_before(
274  pose.energies().residue_total_energies( seqpos )[ hbond_bb_sc ] +
275  pose.energies().residue_total_energies( seqpos )[ hbond_sc ]
276  );*/
277 
278  //append by jump from seqpos atomno to new_rsd atom 1, maybe make random downstream atom?
279  pose.append_residue_by_jump( new_rsd, seqpos, rsd.atom_name( atomno ), new_rsd.atom_name( new_atomno ), true );
280 
281  Size new_seqpos( pose.total_residue() );
282  Size jump_number( pose.fold_tree().num_jump() );
283  Jump jump( pose.jump( jump_number ) );
284  //store water atom ids for clash check
285  vector1< id::AtomID > clash_check_atids;
286  for( Size iat = 1; iat <= new_rsd.natoms(); ++iat ){
287  clash_check_atids.push_back( id::AtomID( iat, new_seqpos ) );
288  }
289 
290  //which is acceptor, donor?
291  Size aatm( 0 ), acc_pos( 0 ), hatm( 0 ), don_pos( 0 );
292  bool wat_is_acc( false );
293  //water is acceptor
294  if( rsd.atom_type( atomno ).is_polar_hydrogen() &&
295  new_rsd.atom_type( new_atomno ).is_acceptor() ){
296  don_pos = seqpos;
297  hatm = atomno;
298  acc_pos = new_seqpos;
299  aatm = new_atomno;
300  wat_is_acc = true;
301  }
302  //or water is donor
303  else if( new_rsd.atom_type( new_atomno ).is_polar_hydrogen() &&
304  rsd.atom_type( atomno ).is_acceptor() ){
305  don_pos = new_seqpos;
306  hatm = new_atomno;
307  acc_pos = seqpos;
308  aatm = atomno;
309  }
310  else{ utility_exit_with_message( "ERROR: res " + to_string( seqpos ) + " atom " + to_string( atomno ) +
311  " res " + to_string( new_seqpos ) + " atom " + to_string( new_atomno ) + " is not HB don/acc pair!!\n" );
312  }
313 
314  //now get their base atoms to get datm and batm
315  Size datm( pose.residue( don_pos ).atom_base( hatm ) );
316  Size batm( pose.residue( acc_pos ).atom_base( aatm ) );
317  Size b2atm( pose.residue( acc_pos ).abase2( aatm ) );
318  Size dbatm( pose.residue( don_pos ).atom_base( datm ) ); //hpol base2
319 
320  //add vrt res so final torsion exists
321  chemical::ResidueTypeSet const & rsd_set( rsd.residue_type_set() );
322  conformation::ResidueOP vrt_rsd( conformation::ResidueFactory::create_residue( rsd_set.name_map( "VRT" ) ) );
323  pose.append_residue_by_jump( *vrt_rsd, pose.total_residue() );
324  FoldTree f_jump( pose.fold_tree() );
325  //just min the new jump
326  //MoveMapOP mm = new MoveMap;
327  //mm->set_jump( jump_number, true );
328  //protocols::simple_moves::MinMoverOP min_mover = new protocols::simple_moves::MinMover( mm, scorefxn, "dfpmin", 0.01, true );
329 
330  //new naive fold tree
331  FoldTree f_rot( pose.total_residue() );
332  //switch to chem bond so can use bond angle defs directly
333  f_rot.new_chemical_bond( seqpos, new_seqpos, rsd.atom_name( atomno ), new_rsd.atom_name( new_atomno ), pose.total_residue() - 2 );
334  pose.fold_tree( f_rot );
335 
336  Size water_hb_states_tot( 0 );
337  Size water_hb_states_good( 0 );
338  hbonds::HBEvalTuple hbe_type( datm, pose.residue( don_pos ), aatm, pose.residue( acc_pos ) );
339  //granularity of enumeration
340  //Size steps( 7 );
341  //must import from hbonds/constants.hh
342  // in case you're wondering, we're sampling in angle space instead of cos(angle)
343  // space so we sample more equally in polar coord space (not more densely when cos(pi-angle)->1)
344  Real AHdist_min(MIN_R), AHdist_max(MAX_R); Size AHdist_steps( 5 );
345 // Real cosBAH_min( MIN_xH ), cosBAH_max( MAX_xH ); Size cosBAH_steps( 5 );
346 // Real cosAHD_min( MIN_xD ), cosAHD_max( MAX_xD ); Size cosAHD_steps( 5 );
347  Real BAHang_min( pi - std::acos( MIN_xH ) ), BAHang_max( pi - std::acos( MAX_xH ) ); Size BAHang_steps( 5 );
348  Real AHDang_min( pi - std::acos( MIN_xD ) ), AHDang_max( pi - std::acos( MAX_xD ) ); Size AHDang_steps( 5 );
349 // Real B2BAHchi_min( 0 ), B2BAHchi_max( pi_2 ); Size B2BAHchi_steps( 1 );
350  Real B2BAHchi_min( 0 ), B2BAHchi_max( pi_2 ); Size B2BAHchi_steps( 10 );
351  Real BAHDchi_min( 0 ), BAHDchi_max( pi_2 ); Size BAHDchi_steps( 3 );
352  //gimbal lock… <sigh>
353  for( Real AHdist = AHdist_min; AHdist <= AHdist_max;
354  AHdist += (AHdist_max - AHdist_min)/static_cast<Real>(AHdist_steps-1)){
355 // for( Real cosBAH = cosBAH_min - 0.0001; cosBAH <= cosBAH_max;
356 // cosBAH += (cosBAH_max - cosBAH_min)/static_cast<Real>(cosBAH_steps-1)){
357 // for( Real cosAHD = cosAHD_min - .0001; cosAHD <= cosAHD_max;
358 // cosAHD += (cosAHD_max - cosAHD_min)/static_cast<Real>(cosAHD_steps-1)){
359  for( Real BAHang = BAHang_min - 0.0001; BAHang <= BAHang_max;
360  BAHang += (BAHang_max - BAHang_min)/static_cast<Real>(BAHang_steps-1)){
361  for( Real AHDang = AHDang_min - .0001; AHDang <= AHDang_max;
362  AHDang += (AHDang_max - AHDang_min)/static_cast<Real>(AHDang_steps-1)){
363  //this loop should be longer than the water internal orientation loops
364  for( Real B2BAHchi = B2BAHchi_min; B2BAHchi <= B2BAHchi_max;
365  B2BAHchi += (B2BAHchi_max - B2BAHchi_min)/static_cast<Real>(B2BAHchi_steps-1)){
366  for( Real BAHDchi = BAHDchi_min; BAHDchi <= BAHDchi_max;
367  BAHDchi += (BAHDchi_max - BAHDchi_min)/static_cast<Real>(BAHDchi_steps-1)){
368 
369 // Real BAHang( pi - std::acos( cosBAH ) );
370 // Real AHDang( pi - std::acos( cosAHD ) );
371  Real cosBAH( std::cos( pi - BAHang ) );
372  Real cosAHD( std::cos( pi - AHDang ) );
373  //call hbonds::hbond_compute_energy( ... ) with these angles
374  // and skip if is zero hb energy
375  // this allows computing exactly what frac of actual HB phase space
376  // can be filled w/ a favorable water molecule
377  Real hb_energy( 0.0 );
379  scorefxn->energy_method_options().hbond_options(),
380  hbe_type, AHdist, cosAHD, cosBAH, B2BAHchi, hb_energy );
381  //TR << hb_energy << std::endl;
382  if( hb_energy >= 0.0 ) continue; //was not actually an hbond
383 
384  ++water_hb_states_tot;
385 
386  //reset chem bond ftree
387  pose.fold_tree( f_rot );
388 
389  //Real water_ang( 0.0 );
390  //store water internal bond angle
391  //WARNING: hard-coded for TP3 water (H1-O-H2)
392 // if( wat_is_acc ){
393 // water_ang = pose.conformation().bond_angle( AtomID( 2, acc_pos ),
394 // AtomID( 1, acc_pos ),
395 // AtomID( 3, acc_pos ) );
396 // }
397  pose.conformation().set_bond_angle( AtomID( batm, acc_pos ),
398  AtomID( aatm, acc_pos ),
399  AtomID( hatm, don_pos ),
400  BAHang );
401 // if( wat_is_acc ){
402 // //need to fix water internal bond angle
403 // pose.conformation().set_bond_angle( AtomID( 2, acc_pos ),
404 // AtomID( 1, acc_pos ),
405 // AtomID( 3, don_pos ),
406 // water_ang );
407 // }
408 
409  pose.conformation().set_bond_angle( AtomID( aatm, acc_pos ),
410  AtomID( hatm, don_pos ),
411  AtomID( datm, don_pos ),
412  AHDang );
413 
414  pose.conformation().set_torsion_angle( AtomID( batm, acc_pos ),
415  AtomID( aatm, acc_pos ),
416  AtomID( hatm, don_pos ),
417  AtomID( datm, don_pos ),
418  BAHDchi );
419  if( wat_is_acc ){
420  //need to redefine hbond chi torsion if water acceptor (hbond chi undefined)
421  pose.conformation().set_torsion_angle( AtomID( dbatm, don_pos ),
422  AtomID( datm, don_pos ),
423  AtomID( hatm, don_pos ),
424  AtomID( aatm, acc_pos ),
425  B2BAHchi );
426  }
427  else{
428  pose.conformation().set_torsion_angle( AtomID( b2atm, acc_pos ),
429  AtomID( batm, acc_pos ),
430  AtomID( aatm, acc_pos ),
431  AtomID( hatm, don_pos ),
432  B2BAHchi );
433  }
434 
435  pose.conformation().set_bond_length( AtomID( aatm, acc_pos ),
436  AtomID( hatm, don_pos ),
437  AHdist );
438 
439  //do fast clash check, OH hbonds are only 0.8A!
440  if( fast_clash_check( pose, clash_check_atids, 0.8 ) ) continue;
441 
442  pose.fold_tree( f_jump );
443  //minimize the new jump, too slow!
444  //min_mover->apply( pose );
445  scorefxn->score( pose );
446 
447  //get score
448  Real wat_score( pose.energies().residue_total_energies( new_seqpos ).dot( scorefxn->weights() ) );
449 
450  if( wat_score <= 0.0 ){
451  ++water_hb_states_good;
452  //TR_unsat << "AHdist: " << AHdist << " ";
453  //TR_unsat << "\tBAHang: " << BAHang << " ";
454  //TR_unsat << "\tBAHDchi: " << BAHDchi << " ";
455  //TR_unsat << "\twat_score: " << wat_score << std::endl;
456  //TR_unsat << pose.energies().total_energies().weighted_to_string( scorefxn->weights() )
457  // + " total_score: " + to_string( pose.energies().total_energies()[ total_score ] );
458  //pose.dump_pdb( "watest." + to_string( seqpos ) + "." + to_string( atomno ) + "." + to_string( Size( numeric::conversions::degrees( AHDang ) ) ) + "." + to_string( Size( numeric::conversions::degrees( BAHang ) ) ) + "." + to_string( Size( numeric::conversions::degrees( BAHDchi ) ) ) + "." + to_string( Size( numeric::conversions::degrees( B2BAHchi ) ) ) + ".pdb" );
459  }
460  }
461  }
462  }
463  }
464  }
465  return ( static_cast< Real >( water_hb_states_good ) /
466  static_cast< Real >( water_hb_states_tot ) );
467 }
468 
469 /// @brief this should just be caled "compute"
470 /// @brief for non-hbonded polar atoms, attempt docking single water residues, then count number still unsatisfied
471 void
473 {
474 
475  all_unsat_polars_ = 0;
477  //Real min_dist( core::scoring::hbonds::MIN_R );
478  //Real shell_cutoff( core::scoring::hbonds::MAX_R );
479  chemical::ResidueTypeSet const & rsd_set( in_pose.residue( 1 ).residue_type_set() );
480  conformation::ResidueOP wat_rsd( conformation::ResidueFactory::create_residue( rsd_set.name_map( "TP3" ) ) );
481  Size wat_O_at( 1 ); //warning! hardcoded for TP3 water!
482  Size wat_H1_at( 2 ); //warning! hardcoded for TP3 water!
483  //turn off solvation score
485  scorefxn->set_weight( scoring::fa_sol, 0.0 );
486 
487 
488  if( in_pose.total_residue() != residue_unsat_polars_.size() ){
489  residue_unsat_polars_.resize( in_pose.total_residue() );
490  atom_unsat_.resize( in_pose.total_residue() );
491  }
492 
493  basic::MetricValue< id::AtomID_Map< Size > > atom_hbonds_dry;
494  in_pose.metric( name_of_hbond_calc_, "atom_Hbonds", atom_hbonds_dry );
495 
496  for( Size i = 1; i <= in_pose.total_residue(); ++i ){
497 
498  residue_unsat_polars_[i] = 0;
499  conformation::Residue const & rsd = in_pose.residue( i );
500 
501  for( Size at = 1; at <= rsd.natoms(); ++at){
502  //reset pose after each atom
503  pose::Pose pose( in_pose );
504 
505  core::id::AtomID atid( at, i );
506  bool this_atom_unsat(false);
507 
508  //counting acceptors and donors
509  if( !( rsd.atom_type( at ).is_acceptor() || rsd.atom_type( at ).is_donor() ) ){
510  atom_unsat_.set( atid, this_atom_unsat );
511  continue;
512  }
513 
514  //how about instead we iter over heavy atoms, then simply check all H's is is donor
515  //can just avg al child H's water hbond fraction
516  //just add this vale into the bonded+hbonds value to gauge
517  //this is not the best way, but is the way that is comparable w/ BuriedUnsatCalc...
518  Size satisfac_cut = satisfaction_cutoff( rsd.type().atom_type( at ).name() );
519  Size bonded_heavyatoms = rsd.n_bonded_neighbor_all_res( at ) - rsd.type().number_bonded_hydrogens( at );
520  Size n_hbonds_needed( satisfac_cut - bonded_heavyatoms );
521 
522  //check for unsat hbonds first
523  Size n_atom_hbonds( atom_hbonds_dry.value()[ atid ] );
524  if( n_atom_hbonds >= n_hbonds_needed ){
525  atom_unsat_.set( atid, this_atom_unsat );
526  continue;
527  }
528 
529  //could atom make enough water hbonds?
530  Real semiexpl_water_score( 0.0 );
531  if( rsd.atom_type( at ).is_acceptor() ){
532  //hmmmm, acc score should count for > max 1
533  //n_hbonds_needed is a good proxy
534  semiexpl_water_score += semiexpl_water_hbgeom_score(
535  pose, scorefxn, i, at, *wat_rsd, wat_H1_at );
536  TR << rsd.name3() << " " << to_string( i ) << " " << rsd.atom_name( at ) <<
537  " semiexpl_wat_score: " << semiexpl_water_score << std::endl;
538  if( semiexpl_water_score >= semiexpl_water_cutoff_ ){
539  n_atom_hbonds += n_hbonds_needed;
540  }
541  }
542  if( rsd.atom_type( at ).is_donor() ){
543  //H atom score should only count for 1 hbond
544  //but to mimic bur unsat hbonds logic, make it so that
545  //we just avg hbgeom score and see if above cutoff
546  Size n_bonded_H = rsd.type().attached_H_end( at ) - rsd.type().attached_H_begin( at );
547  for( Size h_at = rsd.type().attached_H_begin( at );
548  h_at<= rsd.type().attached_H_end( at ); h_at++){
549  //get avg wat score of all attached H's
550  semiexpl_water_score += ( semiexpl_water_hbgeom_score(
551  pose, scorefxn, i, h_at, *wat_rsd, wat_O_at ) / n_bonded_H );
552  }
553  TR << rsd.name3() << " " << to_string( i ) << " " << rsd.atom_name( at ) <<
554  " semiexpl_wat_score: " << semiexpl_water_score << std::endl;
555  if( semiexpl_water_score >= semiexpl_water_cutoff_ ){
556  n_atom_hbonds += n_hbonds_needed;
557  }
558  }
559 
560  //debug
561  //TR << "HBONDS_WET: res\t" << i << "\t" << rsd.atom_name( at ) << "\t" << atom_hbonds_wet.value()[ atid ] << std::endl;
562  //store semiexpl score
563  atom_semiexpl_score_.set( atid, semiexpl_water_score );
564  residue_semiexpl_score_[ i ] += semiexpl_water_score;
565 
566  //now check if still unsat
567  if( n_atom_hbonds < n_hbonds_needed ){
568 
571  this_atom_unsat = true;
572 
574 
575  //debug
576  //TR << "UNSAT_POLARS: res\t" << i << "\t" << rsd.atom_name( at ) << "\t";
577  //if( this_atom_unsat ) TR << 1 << std::endl;
578  //else TR << 0 << std::endl;
579  }
580  atom_unsat_.set( atid, this_atom_unsat );
581 
582  } //atom
583  } //residue
584 } //recompute
585 
586 //sum of n bonded heavyatoms and n hbonds must reach this val
589 {
590 
591  //according to jk, buried hydroxyls are often seen making only one hydrogen bond. also, ether oxygens often are bad h-bond acceptors
592  if( atom_type == "OH" ) return 2;
593 
594  //backbone oxygens also only have one h-bbond in most secondary structure elements
595  else if (atom_type == "OCbb") return 2;
596 
597  else if( atom_type == "S") return 2;
598 
599  //everything else we expect to have 3 bonded/h-bonded neighbours to count as satisfied
600  else return 3;
601 
602 
603 }
604 
605 } //namespace pose_metric_calculators
606 } //namespace toolbox
607 } //namespace protocols