Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
hbonds_geom.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
11 /// @brief
12 /// @author
13 
14 // Unit headers
16 
17 // Package headers
26 
27 // Project headers
29 #include <basic/Tracer.hh>
30 
31 // Numeric headers
32 #include <numeric/constants.hh>
33 #include <numeric/conversions.hh>
34 #include <numeric/deriv/distance_deriv.hh>
35 #include <numeric/deriv/angle_deriv.hh>
36 #include <numeric/deriv/dihedral_deriv.hh>
37 
38 // ObjexxFCL Headers
39 #include <ObjexxFCL/format.hh>
40 
41 // C++ Headers
42 #include <cmath>
43 #include <iostream>
44 
45 
46 // option key includes
47 #include <basic/options/option.hh>
48 #include <basic/options/keys/OptionKeys.hh>
49 #include <basic/options/keys/in.OptionKeys.gen.hh>
50 // AUTO-REMOVED #include <basic/options/keys/score.OptionKeys.gen.hh>
51 #include <basic/options/keys/corrections.OptionKeys.gen.hh>
52 
53 // Numeric Headers
54 #include <numeric/numeric.functions.hh>
55 #include <numeric/xyz.functions.hh>
56 
57 //Exception for NaN in hbonds.
58 #include <utility/excn/Exceptions.hh>
59 
60 //Utility Headers
61 #include <utility/basic_sys_util.hh>
62 #include <utility/PyAssert.hh>
63 
68 #include <utility/vector1.hh>
69 #include <ObjexxFCL/FArray3D.hh>
70 
71 namespace ObjexxFCL { namespace fmt { } } using namespace ObjexxFCL::fmt;
72 
73 namespace core {
74 namespace scoring {
75 namespace hbonds {
76 
77 static basic::Tracer tr("core.scoring.hbonds");
78 
79 Real DUMMY_DERIV(0.0);
80 bool DUMMY_BOOL(false);
84 
85 
86 ///////////////////////////////////////////////////////////////////////////////
89  int const datm,
90  conformation::Residue const & don_rsd
91 )
92 {
93  using namespace chemical;
94  std::string const & aname(don_rsd.atom_name(datm)); // NEVER create a string when a string const & will do
95  if (don_rsd.atom_is_backbone(datm)){
96  if (don_rsd.is_protein()) {
97  if(don_rsd.is_lower_terminus()){
98 
99  /// WARNING this is set to hbdon_PBA for backwards compatibility only!!!!
100  /// but it should be hbdon_AMO because it is actually an amino group
101  return hbdon_PBA;
102  } else {
103  // should backbone prolines be a separate type?
104  return hbdon_PBA;
105  }
106  } else {
107  //tr << "WARNING: Unknown Hydrogen Bond donor type for: " + don_rsd.name1() + I(3, don_rsd.seqpos()) + " " + don_rsd.atom_name( datm) + ". Using hbdon_GENERIC_BB.";
108  return hbdon_GENERIC_BB;
109  }
110  } else {
111  switch(don_rsd.aa()){
112  case aa_asn: case aa_gln: return hbdon_CXA; break;
113  case aa_his:
114  if (aname == " ND1"){
115  return hbdon_IMD;
116  } else {
117  assert( aname == " NE2");
118  return hbdon_IME;
119  } break;
120  case aa_trp:
121  return hbdon_IND; break;
122  case aa_lys:
123  return hbdon_AMO; break;
124  case aa_arg:
125  if (aname == " NE "){
126  return hbdon_GDE;
127  } else {
128  assert(aname == " NH1" || aname == " NH2");
129  return hbdon_GDH;
130  } break;
131  case aa_tyr:
132  return hbdon_AHX; break;
133  case aa_ser:
134  case aa_thr:
135  return hbdon_HXL; break;
136  case aa_ala: case aa_cys: case aa_asp: case aa_glu: case aa_phe:
137  case aa_gly: case aa_ile: case aa_leu: case aa_met: case aa_pro: case aa_val:
138  return hbdon_NONE; break;
139  case na_ade:
140  if (aname == " N6 ") {
141  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
142  /// it should actually be sidechain hbdon_CXA.
143  return hbdon_CXA;
144  } else if (aname == "WN6" || aname == "WN7" || aname == "WN3") { // DNA_MAJOR_GROOVE_WATER ADDUCTS
145  return hbdon_H2O;
146  } break;
147  case na_cyt:
148  if (aname == " N4 ") {
149  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
150  /// it should actually be sidechain hbdon_CXA.
151  return hbdon_CXA;
152  //} else if ( aname == " N1 ") { // while it is an Ntrp it is not protonated to it doesn't donate
153  // return hbdon_IND;
154  } else if ( aname == "WN4" || aname == "WO2" ) {
155  return hbdon_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCTS
156  } break;
157  case na_gua:
158  if (aname == " N1 ") {
159  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
160  /// it should actually be sidechain hbdon_IND.
161  return hbdon_IND;
162  } else if (aname == " N2 ") {
163  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
164  /// it should actually be sidechain hbdon_CXA.
165  return hbdon_CXA;
166  } else if ( aname == "WO6" || aname == "WN7" || aname == "WN3" ){
167  return hbdon_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCT
168  } break;
169  case na_thy:
170  if (aname == " N3 ") {
171  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
172  /// it should actually be sidechain hbdon_IND.
173  return hbdon_IND;
174  } else if ( aname == "WO4" || aname == "WO2" ) {
175  return hbdon_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCTS
176  } break;
177  case na_rad:
178  if (aname == " N6 ") {
179  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
180  /// it should actually be sidechain hbdon_CXA.
181  return hbdon_GENERIC_SC;
182  } else if ( aname == "WN6" || aname == "WN7" ){
183  return hbdon_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCTS
184  } else if ( aname == " O2*" ){
185  ///. WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
186  /// it should actually be sidechain hbdon_HXL
187  return hbdon_GENERIC_SC;
188  } else if ( aname == " N1 " && don_rsd.has_variant_type("PROTONATED_H1_ADENOSINE") ) { //Parin Sripakdeevong May 03, 2011.
189  return hbdon_GENERIC_SC;
190  } break;
191  case na_rgu:
192  if (aname == " N1 ") {
193  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
194  /// it should actually be sidechain hbdon_IND.
195  return hbdon_GENERIC_SC;
196  } else if (aname == " N2 ") {
197  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
198  /// it should actually be sidechain hbdon_CXA.
199  return hbdon_GENERIC_SC;
200  } else if ( aname == " O2*" ){
201  ///. WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
202  /// it should actually be sidechain hbdon_HXL
203  return hbdon_GENERIC_SC;
204  } else if ( aname == "WO6" || aname == "WN7"){
205  return hbdon_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCT
206  } break;
207  case na_rcy:
208  if (aname == " N4 ") {
209  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
210  /// it should actually be sidechain hbdon_CXA.
211  return hbdon_GENERIC_SC;
212  } else if ( aname == " O2*" ){
213  ///. WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
214  /// it should actually be sidechain hbdon_HXL
215  return hbdon_GENERIC_SC;
216  } else if ( aname == "WN4" ){
217  return hbdon_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCT
218  } break;
219  case na_ura:
220  if (aname == " N3 ") {
221  /// WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
222  /// it should actually be sidechain hbdon_IND.
223  return hbdon_GENERIC_SC;
224  } else if ( aname == " O2*" ){
225  ///. WARNING this is set to hbdon_GENERIC_SC for backwards compatibility only!!!
226  /// it should actually be sidechain hbdon_HXL
227  return hbdon_GENERIC_SC;
228  } else if ( aname == "WO4" ){
229  return hbdon_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCT
230  } break;
231  case aa_vrt:
232  case aa_unk:
233  //tr << "WARNING: Unknown Hydrogen Bond donor type for: " + don_rsd.name1() + I(3, don_rsd.seqpos()) + " " + don_rsd.atom_name( datm) + ". Using hbdon_GENERIC_SC.";
234  return hbdon_GENERIC_SC; break;
235  }
236  }
237  utility_exit_with_message( "ERROR: Unknown Hydrogen Bond donor type for: " + don_rsd.name1() + I(3, don_rsd.seqpos()) + " " + don_rsd.atom_name( datm) + ". Using hbdon_GENERIC_SC.");
238  return hbdon_NONE;
239 }
240 
241 ///////////////////////////////////////////////////////////////////////////////
244  int const aatm,
245  conformation::Residue const & acc_rsd
246 )
247 {
248  using namespace chemical;
249  std::string const & aname(acc_rsd.atom_name(aatm)); // NEVER create a string when a string const & will do
250 
251  if( acc_rsd.atom_is_backbone(aatm)){
252  if( acc_rsd.is_protein() ) {
253  if(acc_rsd.is_upper_terminus()){
254 
255  /// WARNING this is set to hbacc_PBA for backwards compatibility!!!!
256  /// but it should be hbacc_CXL because it is actually a carboxyl group
257  return hbacc_PBA;
258  } else {
259  return hbacc_PBA;
260  }
261  } else if (acc_rsd.is_DNA()){
262  if (aname == " O1P" || aname == " O2P" ){
263  return hbacc_PCA_DNA;
264  } else if (aname == " O5*" || aname == " O3*"){
265  return hbacc_PES_DNA;
266  } else if (aname == " O4*"){
267  return hbacc_RRI_DNA;
268  }
269  }else if ( acc_rsd.is_RNA() ){
270  if (aname == " O1P" || aname == " O2P" || aname == " O3P"){
271  return hbacc_PCA_RNA;
272  } else if (aname == " O5*" || aname == " O3*"){
273  return hbacc_PES_RNA;
274  } else if (aname == " O4*"){
275  return hbacc_RRI_RNA;
276  }
277  } else {
278  // generic types; for backwards compatibility; prefer functional group based chem type
279  switch (acc_rsd.atom_type(aatm).hybridization()){
280  case SP2_HYBRID:
281  // tr << "WARNING: Unknown hydrogen bond acceptor type for: " + acc_rsd.name1() + I(3, acc_rsd.seqpos()) + " " + acc_rsd.atom_name(aatm) + ". Using hbdon_GENERIC_SP2BB.";
282  return hbacc_GENERIC_SP2BB; break;
283  case SP3_HYBRID:
284  //tr << "WARNING: Unknown hydrogen bond acceptor type for: " + acc_rsd.name1() + I(3, acc_rsd.seqpos()) + " " + acc_rsd.atom_name(aatm) + ". Using hbdon_GENERIC_SP3BB.";
285  return hbacc_GENERIC_SP3BB; break;
286  case RING_HYBRID:
287  //tr << "WARNING: Unknown hydrogen bond acceptor type for: " + acc_rsd.name1() + I(3, acc_rsd.seqpos()) + " " + acc_rsd.atom_name(aatm) + ". Using hbdon_GENERIC_RINGBB.";
288  return hbacc_GENERIC_RINGBB; break;
289  case UNKNOWN_HYBRID:
290  //tr << "WARNING: Unknown hydrogen bond acceptor type for: " + acc_rsd.name1() + I(3, acc_rsd.seqpos()) + " " + acc_rsd.atom_name(aatm) + ". Using hbdon_GENERIC_RINGBB.";
291  return hbacc_NONE; break;
292  }
293  }
294  } else {
295  switch(acc_rsd.aa()){
296  case aa_asn: case aa_gln: return hbacc_CXA; break;
297  case aa_asp: case aa_glu: return hbacc_CXL; break;
298  case aa_his:
299  if (aname == " ND1"){
300  return hbacc_IMD;
301  } else {
302  return hbacc_IME;
303  } break;
304  case aa_ala: case aa_cys: case aa_phe: case aa_gly: case aa_ile: case aa_leu:
305  case aa_met: case aa_pro: case aa_val: case aa_tyr: return hbacc_AHX; break;
306  case aa_ser: case aa_thr: return hbacc_HXL; break;
307  case aa_lys: case aa_arg: case aa_trp:
308  return hbacc_NONE;
309  case na_ade:
310  if (aname == " N1 " || aname == " N3 " || aname == " N7 "){
311  /// WARNING this is set to hbacc_GENERIC_RINGSC for backwards compatibility only!!!
312  /// it should actually be sidechain hbacc_IME.
313  return hbacc_IME;
314  } else if (aname == "WN6" || aname == "WN7" || aname == "WN3") {
315  return hbacc_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCTS
316  } break;
317  case na_gua:
318  if (aname == " N3 " || aname == " N7 "){
319  /// WARNING this is set to hbacc_GENERIC_RINGSC for backwards compatibility only!!!
320  /// it should actually be sidechain hbacc_IME.
321  return hbacc_IME;
322  } else if ( aname == " O6 "){
323  return hbacc_CXL;
324  } else if ( aname == "WO6" || aname == "WN7" || aname == "WN3" ) {
325  return hbacc_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCTS
326  } break;
327  case na_cyt:
328  if (aname == " O2 "){
329  /// WARNING this is set to hbacc_GENERIC_SP2SC for backwards compatibility only!!!
330  /// it should actually be sidechain hbacc_CXA.
331  return hbacc_CXA;
332  } else if (aname == " N3 "){
333  /// WARNING this is set to hbacc_GENERIC_RINGSC for backwards compatibility only!!!
334  /// it should actually be sidechain hbacc_IME.
335  return hbacc_IME;
336  } else if ( aname == "WN4" || aname == "WO2" ) {
337  return hbacc_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCTS
338  } break;
339  case na_thy:
340  if (aname == " O2 " || aname == " O4 "){
341  /// WARNING this is set to hbacc_GENERIC_SP2SC for backwards compatibility only!!!
342  /// it should actually be sidechain hbacc_CXA.
343  return hbacc_CXA;
344  } else if ( aname == "WO4" || aname == "WO2" ) {
345  return hbacc_H2O; // DNA_MAJOR_GROOVE_WATER ADDUCTS
346  } break;
347  case na_rad:
348  if (aname == " N1 " || aname == " N3 " || aname == " N7 "){
349  if(aname == " N1 "){
350  if(acc_rsd.has_variant_type("PROTONATED_H1_ADENOSINE")) utility_exit_with_message("acc_rsd.aa()==na_rad, aname == \" N1 \" and acc_rsd.has_variant_type(\"PROTONATED_H1_ADENOSINE\")!");
351  }
352  /// WARNING this is set to hbacc_GENERIC_RINGSC for backwards compatibility only!!!
353  /// it should actually be sidechain hbacc_IME.
354  return hbacc_GENERIC_RINGSC;
355  } else if (aname == " O2*") {
356  /// WARNING this is set to hbacc_GENERIC_SP3BB for backwards compatibility only!!!
357  /// it should actually be backbone hbacc_HXL.
358  return hbacc_GENERIC_SP3SC;
359  } break;
360  case na_rgu:
361  if (aname == " N3 " || aname == " N7 "){
362  /// WARNING this is set to hbacc_GENERIC_RINGSC for backwards compatibility only!!!
363  /// it should actually be sidechain hbacc_IME.
364  return hbacc_GENERIC_RINGSC;
365  } else if (aname == " O6 "){
366  /// WARNING this is set to hbacc_GENERIC_RINGSC for backwards compatibility only!!!
367  /// it should actually be sidechain hbacc_CXA.
368  return hbacc_GENERIC_SP2SC;
369  } else if (aname == " O2*") {
370  /// WARNING this is set to hbacc_GENERIC_SP3BB for backwards compatibility only!!!
371  /// it should actually be backbone hbacc_HXL.
372  return hbacc_GENERIC_SP3SC;
373  } break;
374  case na_rcy:
375  if (aname == " O2 "){
376  /// WARNING this is set to hbacc_GENERIC_SP2SC for backwards compatibility only!!!
377  /// it should actually be sidechain hbacc_CXA.
378  return hbacc_GENERIC_SP2SC;
379  } else if (aname == " N3 "){
380  /// WARNING this is set to hbacc_GENERIC_RINGSC for backwards compatibility only!!!
381  /// it should actually be sidechain hbacc_IME.
382  return hbacc_GENERIC_RINGSC;
383  } else if (aname == " O2*") {
384  /// WARNING this is set to hbacc_GENERIC_SP3BB for backwards compatibility only!!!
385  /// it should actually be backbone hbacc_HXL.
386  return hbacc_GENERIC_SP3SC;
387  } break;
388  case na_ura:
389  if (aname == " O2 " || aname == " O4 "){
390  /// WARNING this is set to hbacc_GENERIC_SP2SC for backwards compatibility only!!!
391  /// it should actually be sidechain hbacc_CXA.
392  return hbacc_GENERIC_SP2SC;
393  } else if (aname == " O2*") {
394  /// WARNING this is set to hbacc_GENERIC_SP3BB for backwards compatibility only!!!
395  /// it should actually be backbone hbacc_HXL.
396  return hbacc_GENERIC_SP3SC;
397  } break;
398  case aa_vrt:
399  case aa_unk:
400  // generic types; for backwards compatibility; prefer functional group based chem type
401  switch(acc_rsd.atom_type(aatm).hybridization()){
402  case SP2_HYBRID:
403  return hbacc_GENERIC_SP2SC; break;
404  case SP3_HYBRID:
405  return hbacc_GENERIC_SP3SC; break;
406  case RING_HYBRID:
407  return hbacc_GENERIC_RINGSC; break;
408  case UNKNOWN_HYBRID:
409  return hbacc_NONE; break;
410  }
411  }
412  }
413  utility_exit_with_message( "unknown Hydrogen Bond acceptor type for: " + acc_rsd.name1() + I(3,acc_rsd.seqpos()) + " " + acc_rsd.atom_name( aatm) );
414  return hbacc_NONE;
415 }
416 
417 // jk comment out inline so this can be used elsewhere (exact SHO model)
418 //inline
419 HBSeqSep
421  HBDonChemType const & don_chem_type,
422  HBAccChemType const & acc_chem_type,
423  int const & sep
424 ){
425  // The logic here is, if it is protein backbone to protein backbone
426  // then identify secondary struture sterics by sequence separation.
427  // Rhiju notices that down weighting hbonds between adjacent
428  // residues where at least one is a backbone improved scientific
429  // benchmarks in RNA. Until more study is done, this is either
430  // something RNA specific or an artifact kinimatic sampling, eg it
431  // is easier to sample close hydrogen bonds than far hydrogen bonds.
432  // If it is the latter then all adjacent BSC hbonds should be split out.
433  // Nucleic acid backbone is unfortunately treated as backbone
434  // only for the purposes of scoring and only when it is DNA with
435  // something that is not protein or DNA or it is RNA. Yeah it's
436  // confusing. So DNA backbone is for now treated similar to protein
437  // sidechain for the purposes of sequence separation.
438 
439  // hbonds involving water are always seq_sep_other.
440 
441  // I'm not sure if this should code should be done like it is here
442  // or if it should be folded into another ~500 cases of the
443  // HBEval_lookup table.
444 
445  switch(don_chem_type){
446  case hbdon_NONE:
447  case hbdon_H2O:
448  return seq_sep_other;
449  case hbdon_PBA:
450  switch(acc_chem_type){
451  case hbacc_NONE:
452  case hbacc_H2O:
453  return seq_sep_other;
454  case hbacc_PBA:
455  switch(sep){
456  case -4: return seq_sep_M4; break;
457  case -3: return seq_sep_M3; break;
458  case -2: return seq_sep_M2; break;
459  case -1:
460  case 1: return seq_sep_PM1; break;
461  case 2: return seq_sep_P2; break;
462  case 3: return seq_sep_P3; break;
463  case 4: return seq_sep_P4; break;
464  default: return seq_sep_other; break;
465  }
466  default:
467  if (sep == 1 || sep == -1) { return seq_sep_PM1;}
468  else { return seq_sep_other; }
469  break;
470  } break;
471  case hbdon_CXA:
472  case hbdon_IMD:
473  case hbdon_IME:
474  case hbdon_IND:
475  case hbdon_AMO:
476  case hbdon_GDE:
477  case hbdon_GDH:
478  case hbdon_AHX:
479  case hbdon_HXL:
480  switch(acc_chem_type){
481  case hbacc_NONE:
482  case hbacc_CXA:
483  case hbacc_CXL:
484  case hbacc_IMD:
485  case hbacc_IME:
486  case hbacc_AHX:
487  case hbacc_HXL:
488  case hbacc_PCA_DNA:
489  case hbacc_PES_DNA:
490  case hbacc_RRI_DNA:
491  case hbacc_H2O:
492  return seq_sep_other; break;
493  default:
494  if (sep == 1 || sep == -1) { return seq_sep_PM1;}
495  else { return seq_sep_other; } break;
496  }break;
497  default:
498  if (sep == 1 || sep == -1) { return seq_sep_PM1;}
499  else { return seq_sep_other; } break;
500  }
501  return seq_sep_other; // Make compilers happy.
502 }
503 
504  /// Warning if you use this interface you are responsible for
505  /// testing if the residues are on different chains!
508  hbtrie::HBAtom const & datm,
509  int const & don_rsd,
510  hbtrie::HBAtom const & aatm,
511  int const & acc_rsd
512 ){
513 
514  HBDonChemType don_chem_type(datm.hb_don_chem_type());
515  HBAccChemType acc_chem_type(aatm.hb_acc_chem_type());
516  HBSeqSep seq_sep(get_seq_sep(don_chem_type, acc_chem_type, acc_rsd - don_rsd)); //This should really test if things are on different chains
517  //HBEvalType hbe(HBEval_lookup(don_chem_type, acc_chem_type, seq_sep));
518  return HBEvalTuple( don_chem_type, acc_chem_type, seq_sep );
519 }
520 
523  int const datm,
524  conformation::Residue const & don_rsd,
525  int const aatm,
526  conformation::Residue const & acc_rsd
527 ){
528  HBDonChemType don_chem_type(get_hb_don_chem_type(datm, don_rsd));
529  HBAccChemType acc_chem_type(get_hb_acc_chem_type(aatm, acc_rsd));
530  HBSeqSep seq_sep(get_seq_sep(don_chem_type, acc_chem_type, don_rsd.polymeric_oriented_sequence_distance(acc_rsd)));
531  //HBEvalType hbe(HBEval_lookup(don_chem_type, acc_chem_type, seq_sep));
532  return HBEvalTuple( don_chem_type, acc_chem_type, seq_sep );
533 }
534 
535 
536 void
538  HBondDatabase const & database,
539  HBondOptions const & hbondoptions,
540  HBEvalTuple hbt, // the tuple representing the evaluation information for this hbond
541  Real const AHdis, // acceptor proton distance
542  Real const xD, // -cos(180-theta), where theta is defined by Tanja K.
543  Real const xH, // cos(180-phi), where phi is defined by Tanja K.
544  Real const chi, // AB2-AB-A-H dihdral angle for sp2 hybridized acceptors
545  Real & energy,
546  bool & apply_chi_torsion_penalty, // did this hbond get the chi torsion penalty?
547  HBGeoDimType & AHD_geometric_dimension, // measure in angle in cosine space?
548  Real & dE_dr,
549  Real & dE_dxD,
550  Real & dE_dxH,
551  Real & dE_dBAH, // the change in the energy wrt the BAH angle
552  Real & dE_dchi // the change in the energy wrt the chi dihedral
553 )
554 {
555  HBEvalType hbe = hbt.eval_type();
556  energy = MAX_HB_ENERGY + 1.0f;
557  apply_chi_torsion_penalty = false;
558  dE_dr = dE_dxD = dE_dxH = dE_dBAH = dE_dchi = 0.0;
559 
560  // These should throw an exection if fail_on_bad_hbond is true
561  if ( std::abs(xD) > 1.0 || std::abs(xH) > 1.0 ) {
562  if ( true )
563  tr << "WARNING:: invalid angle value in hbond_compute_energy:"
564  << " xH = " << ObjexxFCL::fmt::SS( xH ) << " xD = " << ObjexxFCL::fmt::SS( xD ) << std::endl;
565  return;
566  }
567  //std::cout << " hb: " << AHdis << " " << xH << " " << xD << std::endl;
568  if ( AHdis > MAX_R || AHdis < MIN_R || xH < MIN_xH || xD < MIN_xD ||
569  xH > MAX_xH || xD > MAX_xD ) {
570  return;
571  }
572 
573  // The function takes in single precision and computes in double
574  // precision To help numeric stability
575  double const dAHdis = static_cast<double>(AHdis);
576  double const dxD = static_cast<double>(xD);
577  double const dxH = static_cast<double>(xH);
578  double Pr(0.0), PSxD(0.0), PSxH(0.0), PLxD(0.0), PLxH(0.0); // values of polynomials
579  double dPr(0.0), dPSxD(0.0), dPSxH(0.0), dPLxD(0.0), dPLxH(0.0); // derivatives of polynomials
580  double FSr(0.0), FLr(0.0), FxD(0.0), FxH(0.0); // values of fading intervals
581  double dFSr(0.0), dFLr(0.0), dFxD(0.0), dFxH(0.0); // derivatives of fading intervals
582 
583  database.AHdist_short_fade_lookup( hbe )->value_deriv(AHdis, FSr, dFSr);
584  database.AHdist_long_fade_lookup( hbe )->value_deriv(AHdis, FLr, dFLr);
585  database.cosBAH_fade_lookup( hbe )->value_deriv(xH, FxH, dFxH);
586  database.cosAHD_fade_lookup( hbe )->value_deriv(xD, FxD, dFxD);
587 
588  if ( FSr == Real(0.0) && FLr == Real(0.0) ) {
589  // is dAHdis out of range for both its fade function and its polynnomials? Then set energy > MAX_HB_ENERGY.
590  if ( dAHdis < database.AHdist_poly_lookup( hbe )->xmin() ||
591  dAHdis > database.AHdist_poly_lookup( hbe )->xmax() ) {
592  energy = MAX_HB_ENERGY + Real(1.0);
593  return;
594  }
595  }
596 
597  if ( FxH == Real(0.0) ) {
598  // is xH out of range for both its fade function and its polynnomials? Then set energy > MAX_HB_ENERGY.
599  if ( ( dxH < database.cosBAH_short_poly_lookup( hbe )->xmin() && dxH < database.cosBAH_long_poly_lookup( hbe )->xmin() ) ||
600  ( dxH > database.cosBAH_short_poly_lookup( hbe )->xmax() && dxH > database.cosBAH_long_poly_lookup( hbe )->xmax() ) ) {
601  energy = MAX_HB_ENERGY + Real(1.0);
602  return;
603  }
604  }
605 
606  // add these checks, of course, to the hbeval reading
607  assert( database.cosAHD_short_poly_lookup(hbe)->geometric_dimension() == database.cosAHD_long_poly_lookup(hbe)->geometric_dimension() );
608  bool const use_cosAHD = database.cosAHD_short_poly_lookup(hbe)->geometric_dimension() == hbgd_cosAHD;
609  AHD_geometric_dimension = use_cosAHD ? hbgd_cosAHD : hbgd_AHD;
610  assert( use_cosAHD || database.cosAHD_short_poly_lookup(hbe)->geometric_dimension() == hbgd_AHD );
611 
612  Real AHD(-1234);
613  if ( ! use_cosAHD ) {
614  AHD = numeric::constants::d::pi-acos(dxD); // spare this calculation if were evaluating the polynomial in cosine space
615  }
616 
617  if ( FxD == Real(0.0) ) {
618  // is xD out of range for both its fade function and its polynnomials? Then set energy > MAX_HB_ENERGY.
619  if ( use_cosAHD ) {
620  if ( ( dxD < database.cosAHD_short_poly_lookup( hbe )->xmin() && dxD < database.cosAHD_long_poly_lookup( hbe )->xmin() ) ||
621  ( dxD > database.cosAHD_short_poly_lookup( hbe )->xmax() && dxD > database.cosAHD_long_poly_lookup( hbe )->xmax() ) ) {
622  energy = MAX_HB_ENERGY + Real(1.0);
623  return;
624  }
625  } else {
626  if ( ( AHD < database.cosAHD_short_poly_lookup( hbe )->xmin() && AHD < database.cosAHD_long_poly_lookup( hbe )->xmin() ) ||
627  ( AHD > database.cosAHD_short_poly_lookup( hbe )->xmax() && AHD > database.cosAHD_long_poly_lookup( hbe )->xmax() ) ) {
628  energy = MAX_HB_ENERGY + Real(1.0);
629  return;
630  }
631  }
632  }
633 
634  (*database.AHdist_poly_lookup( hbe ))(dAHdis, Pr, dPr);
635  (*database.cosBAH_short_poly_lookup( hbe ))(dxH, PSxH, dPSxH);
636  (*database.cosBAH_long_poly_lookup( hbe ))(dxH, PLxH, dPLxH);
637  if ( use_cosAHD ) {
638  (*database.cosAHD_short_poly_lookup( hbe ))(dxD, PSxD, dPSxD);
639  (*database.cosAHD_long_poly_lookup( hbe ))(dxD, PLxD, dPLxD);
640  } else {
641  (*database.cosAHD_short_poly_lookup( hbe ))(AHD, PSxD, dPSxD);
642  (*database.cosAHD_long_poly_lookup( hbe ))(AHD, PLxD, dPLxD);
643  }
644 
645 
646  energy = Pr*FxD*FxH + FSr*(PSxD*FxH + FxD*PSxH) + FLr*(PLxD*FxH + FxD*PLxH);
647  //std::cout << " hb: " << AHdis << " " << xH << " " << xD << " energy: " << energy << std::endl;
648 
649  //if ( dxH < 0 && energy < 0 ) {
650  // std::cout << " hbond out of range with non-zero energy: energy= " << energy << " dAHdis= " << dAHdis << " dxD= " << dxD << " dxH= " << dxH << std::endl;
651  // std::cout << " Fade function values: FSr= " << FSr << " FLr= " << FLr << " FxH= " << FxH << " FxD= " << FxD << std::endl;
652  // std::cout << "Pr*FxD*FxH " << Pr*FxD*FxH << " FSr*(PSxD*FxH ) "<< FSr*PSxD*FxH << " FSr*FxD*PSxH " << FSr*FxD*PSxH << " FLr*PLxD*FxH " << FLr*PLxD*FxH << " FLr*FxD*PLxH " << FLr*FxD*PLxH << std::endl;
653  // std::cout << "eval type: " << hbe << std::endl;
654  //}
655 
656  //Real const peak_height = basic::options::option[ basic::options::OptionKeys::corrections::score::hb_sp2_peak_heigh_above_trough ];
657  //Real const chi_amp = basic::options::option[ basic::options::OptionKeys::corrections::score::hb_sp2_amp ];
658  Real const bah180_rise = hbondoptions.sp2_BAH180_rise();
659 
660  //Real chi_penalty( 1.0 );
661  //Real chi_penalty_via_chi( 1.0 ); // for derivatives
662  Real angleBAH(0.0);
663  //Real half_cos_piminus3BAH_plus_1(1.0);
664  bool apply_chi_torsion_penalty_sp2 = false;
665  bool apply_chi_torsion_penalty_sp3 = false;
666  if ( hbondoptions.use_sp2_chi_penalty() &&
668  apply_chi_torsion_penalty = true;
669  apply_chi_torsion_penalty_sp2 = true;
670  // NEW FORMULA #6: (aka "vesion 7")
671  // weaken hbonds in the center relative to hbonds on the edges
672  // place the maximum chi bonus @ BAH = 120, but make sure that @ BAH = 180, there is no contribution from the chi angle
673  // chi term: cos(2chi)+1/2 -- ranges from 1 to 0; maxima at 0 and 180, minima at 90 and 270.
674  // BAH term: 1-(cos(pi-3BAH)+1)/2 -- ranges from 1 to 0: maxima at BAH = 120, minima at BAH = 180
675  // chi_amp: the maximum strength of a hydrogen bond to an SP2 acceptor (relative to hbonds to other acceptors)
676  // peak_height: the relative strength of the best hbond to an SP2 acceptor to the worst hbond; @2, this means that
677  // out-of-plane hydrogen bonds are half the strenght of in-plane hydrogen bonds.
678  // (a/p)*( (p-1)(cos(2chi)+1)/2 + 1 ) * ( 1 - (cos(pi-3BAH)+1)/2 ) + a/p*(cos(pi-3BAH)+1)/2
679  // (a/p)*(( (p-1)(cos(2chi)+1)/2 + 1 ) * ( 1 - (cos(pi-3BAH)+1)/2) + (cos(pi-3BAH)+1)/2))
680  // (a/p)*(( (p-1)(cos(2chi)+1)/2 )( 1 - (cos3BAH+1)/2) + 1) -- may be easier to just add a and p back in.
681 
682  /// Version #8: do not use the sp2 term for short-ranged backbone-backbone hydrogen bonds.
683  /// Added exclusion in the if-check above for hbe <= hbe_dPBAaPBAsepP4helix (which covers
684  /// all the short-ranged backbone-backbone hydrogen bonds)
685 
686  /// Version #7: (11/12/19) restoring v7 after determining that sp2 potential should be used for
687  /// all bb/bb contacts.
688 
689  //chi_penalty = std::cos( 2 * chi ) + 1;
690  //chi_penalty *= (peak_height - 1)/ 2;
691  //chi_penalty += 1;
692  //chi_penalty_via_chi = chi_penalty;
693  //
694  //angleBAH = numeric::constants::d::pi - acos( xH );
695  //Real cospiminus3BAH = cos( numeric::constants::d::pi - 3 * angleBAH );
696  //half_cos_piminus3BAH_plus_1 = ( cospiminus3BAH + 1 ) * 0.5;
697  //
698  //chi_penalty *= 1 - half_cos_piminus3BAH_plus_1;
699  //chi_penalty += half_cos_piminus3BAH_plus_1;
700  //
701  //chi_penalty *= chi_amp / peak_height;
702 
703  /// New Formula #9 additive chi/BAH score
704  /// with the "rise" taken as a constant, d, marking the distance between the minimum value of -0.5 at chi=180 (or 0)
705  /// BAH at 120 (which has a value then of -0.5 + d)
706  /// the energy is given by this function:
707  /// h*f + (1-h)*g
708  /// where the "h" interpolation function is given by (cos(2*chi)+1)/2
709  /// and f and g reflect either peaky or flat energy landscapes
710  /// f = d/2*cos(3*(pi-BAH)) + (d/2-0.5) for 180 > BAH > 120
711  /// = 3/4*cos(3*(pi-BAH)) + (3/4 - 0.5) for 120 > BAH > 60
712  /// = 1 for 60 > BAH
713  ///
714  /// g = -0.5 + d for 180 > BAH > 120
715  /// = (1.5-d)/2*cos(3*(pi-BAH)) + ((1.5-d)/2 - 0.5 + d )for 120 > BAH > 60
716  /// = 1 for 60 > BAH
717 
718  Real g(0), f(0);
719  Real h = (std::cos(2*chi)+1) * 0.5;
720  Real const acos_xH = acos( xH );
721  angleBAH = numeric::constants::d::pi - acos_xH;
722  if ( angleBAH >= numeric::constants::d::pi * 2/3 ) {
723  f = bah180_rise/2*std::cos( 3 * acos_xH ) + (bah180_rise / 2 - 0.5 );
724  g = -0.5 + bah180_rise;
725  } else if ( angleBAH >= numeric::constants::d::pi * 1/3 ) {
726  f = std::cos(3*acos_xH)*0.75 + 0.25;
727  g = (1.5-bah180_rise)*0.5*std::cos(3*acos_xH) + (0.25 + bah180_rise/2 );
728  } else {
729  f = 1;
730  g = 1;
731  }
732  //std::cout << "angleBAH " << 180/numeric::constants::d::pi*angleBAH << " chi " << 180/numeric::constants::d::pi*chi << " " << f << " " << g << std::endl;
733  energy += h*f + (1-h)*g;
734 
735  } else if ( hbondoptions.measure_sp3acc_BAH_from_hvy()
736  && ( hbt.acc_type() == hbacc_AHX || hbt.acc_type() == hbacc_HXL )) {
737  apply_chi_torsion_penalty = true;
738  apply_chi_torsion_penalty_sp3 = true;
739 
740  // just add in a penalty directly to the energy sum; the chi-penalty
741  // is only multiplied in for the sp2 term.
742  Real const max_penalty = 0.25;
743  Real cos2ChiShifted = max_penalty * ( 1 + std::cos(chi)) / 2;
744  //std::cout << "penalizing hbond by " << cos2ChiShifted << " for having hydroxyl hydrogen too close: chi " << chi*180/3.1415926535 << std::endl;
745  energy += cos2ChiShifted;
746  }
747 
748  Real const don_strength(database.don_strength(hbt.don_type()));
749  Real const acc_strength(database.acc_strength(hbt.acc_type()));
750  Real const bond_strength(sqrt(don_strength*acc_strength));
751 
752  energy *= bond_strength;
753 
754  // NOTE: if any deriv parameter omitted, we don't compute derivatives.
755  if (&dE_dxH == &DUMMY_DERIV) {
756  //energy *= chi_penalty; // multiply the chi penalty into the energy now.
757  return;
758  }
759 
760  dE_dr = dPr*FxD*FxH + dFSr*(PSxD*FxH + FxD*PSxH) + dFLr*(PLxD*FxH + FxD*PLxH);
761  dE_dr *= bond_strength;
762 
763  if(use_cosAHD){
764  dE_dxD = dFxD*(Pr*FxH + FLr*PLxH + FSr*PSxH) + FxH*(FSr*dPSxD + FLr*dPLxD);
765  } else {
766  /// the fade function is still evaluated in cosine space, so its derivatives have to
767  /// be converted to units of dE/dAHD by multiplying dE/dcosAHD by sin(AHD)
768  /// the polynomial's derivatives, on the other hand, is already in units of dE/dAHD
769  dE_dxD = dFxD*(Pr*FxH + FLr*PLxH + FSr*PSxH)*sin(AHD) + FxH*(FSr*dPSxD + FLr*dPLxD);
770  }
771  dE_dxH = dFxH*(Pr*FxD + FLr*PLxD + FSr*PSxD) + FxD*(FSr*dPSxH + FLr*dPLxH);
772 
773  if ( apply_chi_torsion_penalty_sp2 ) {
774  //dE_dr *= chi_penalty;
775  //dE_dxD *= chi_penalty;
776  //dE_dxH *= chi_penalty;
777 
778  // Formula #6
779  // p = chi_penalty_via_chi (not divided by k), k = peak_height
780  // a/k * ( p * ( 1 - (cos(pi-3BAH)+1)/2 ) + (cos(pi-3BAH)+1)/2)*E(d,a1,a2)
781  // NOTE: E(d,a1,a2) -- aka "energy" -- has not yet been muplied by the chi_penalty.
782  // dE / dBAH = a /k * ( - p * 3 * sin(pi-3BAH) / 2 + 3 * sin(pi-3BAH) / 2) * E(d,a1,a2)
783  // dE / dBAH = a / k * 3/2 * ( -p * sin(pi-3BAH) + sin(pi-3BAH) ) * E(d,a1,a2)
784  // dE / dBAH = a/k * ( 1 - p ) * sin(pi-3BAH) * E(d,a1,a2)
785  //dchipen_dBAH = energy * chi_amp / peak_height * 1.5 * ( 1 - chi_penalty_via_chi ) * sin( numeric::constants::d::pi - 3*angleBAH );
786  //dchipen_dchi = -energy * chi_amp * sin( 2*chi ) * ( peak_height - 1 ) / peak_height * ( 1 - half_cos_piminus3BAH_plus_1 );
787 
788  /// wait until the above calculations have completed, then scale the energy by the chi penalty
789  // energy *= chi_penalty;
790 
791 
792  /// New Formula #9 additive chi/BAH score
793  /// with the "rise" taken as a constant, d, marking the distance between the minimum value of -0.5 at chi=180 (or 0)
794  /// BAH at 120 (which has a value then of -0.5 + d)
795  /// the energy is given by this function:
796  /// h*f + (1-h)*g
797  /// where the "h" interpolation function is given by (cos(2*chi)+1)/2
798  /// and f and g reflect either peaky or flat energy landscapes
799  /// f = d/2*cos(3*(pi-BAH)) + (d/2-0.5) for 180 > BAH > 120
800  /// = 3/4*cos(3*(pi-BAH)) + (3/4 - 0.5) for 120 > BAH > 60
801  /// = 1 for 60 > BAH
802  ///
803  /// g = -0.5 + d for 180 > BAH > 120
804  /// = (1.5-d)/2*cos(3*(pi-BAH)) + ((1.5-d)/2 - 0.5 + d )for 120 > BAH > 60
805  /// = 1 for 60 > BAH
806  /// therefore
807  /// dE/dchi = dh/dchi*f - dh/dchi*g
808  /// dE/dBAH = h*df/dBAH + (1-h)*dg/dBAH
809  /// and
810  /// df/dBAH = 3*d/2*sin(3*(pi-BAH)) for 180 > BAH > 120
811  /// = 9/4 *sin(3*(pi-BAH)) for 120 > BAH > 60
812  /// = 0 for 60 > BAH
813  /// dg/dBAH = 0 for 180 > BAH > 120
814  /// = 3*(1.5-d)/2*sin(3*(pi-BAH)) for 120 > BAH > 60
815  /// = 0 for 60 > BAH
816 
817  Real g(0), f(0), dfdBAH(0), dgdBAH(0);
818  Real h = (std::cos(2*chi)+1) * 0.5;
819  Real dhdchi = -std::sin(2*chi);
820  Real const acos_xH = numeric::constants::d::pi - angleBAH; // since the arccos has already been computed
821  if ( angleBAH >= numeric::constants::d::pi * 2/3 ) {
822  f = bah180_rise/2*std::cos( 3 * acos_xH ) + (bah180_rise / 2 - 0.5 );
823  g = -0.5 + bah180_rise;
824  dfdBAH = 3*bah180_rise/2*sin(3*acos_xH);
825  } else if ( angleBAH >= numeric::constants::d::pi * 1/3 ) {
826  f = 0.75*cos(3*acos_xH) + 0.25;
827  g = (1.5-bah180_rise)*0.5*cos(3*acos_xH) + (0.25 + bah180_rise/2 );
828  dfdBAH = 9.0/4.0*sin(3*acos_xH);
829  dgdBAH = 3*(1.5-bah180_rise)/2*sin(3*acos_xH);
830  } else {
831  f = 1;
832  g = 1;
833  }
834  dE_dchi = f*dhdchi - g*dhdchi;
835  dE_dBAH = h*dfdBAH + (1-h)*dgdBAH;
836  //std::cout << "angleBAH " << 180/numeric::constants::d::pi*angleBAH << " chi " << 180/numeric::constants::d::pi*chi << f << " " << g << " deriv: " << dfdBAH << " " << dgdBAH << std::endl;
837 
838  } else if ( apply_chi_torsion_penalty_sp3 ) {
839  Real const max_penalty = 0.25;
840  //std::cout << "applying dchipen_dchi" << std::endl;
841  Real minussin2ChiShifted = -1 * max_penalty * std::sin(chi)/2;
842  dE_dchi = minussin2ChiShifted;
843  }
844 
845 }
846 
847 ////////////////////////////////////////////////////////////////////////////////
848 /// @begin hb_energy_deriv
849 ///
850 /// @brief
851 ///car Evaluate the energy and derivative components for a hydrogen bond
852 ///
853 /// @detailed
854 ///car Energy is assumed to be a sum of independent functions of distance,
855 ///car angle at the donor atom, and angle at the acceptor atom. This form
856 ///car of the hydrogen bond potential was selected by Tanja Kortemme
857 ///car The math for computing the derivative of the angular components of
858 ///car the potential was derived by Bill Wedemeyer.
859 ///
860 ///ora used also to calculate derivatives for RB movements if docking_flag T
861 ///ora important NOTE: if in docking mode minimization is done NOT in tr space, this
862 ///ora should be specified and the docking_specific part should be skipped
863 ///
864 /// @param hbe_type - [in] - hydrogen bond evaluation type from hbonds_ns.h
865 /// @param donor_res - [in] -
866 /// @param acceptor_res - [in] -
867 /// @param Dxyz - [in/out] - donor
868 /// @param Hxyz - [in/out] - proton
869 /// @param Axyz - [in/out] - acceptor
870 /// @param Bxyz - [in/out] - acceptor base
871 /// @param B2xyz - [in/out] - 2nd acceptor base for ring acceptors
872 /// @param energy - [out] -
873 /// @param deriv - [out (optional)] - xyz,f1/f2
874 /// @param deriv_type [in (optional)] - deriv is NORMAL(default), DOCK_ACC_DON, DOCK_DON_ACC
875 ///
876 /// @global_read
877 /// When docking derivatives are computed (DOCK_ACC_DON or DOCK_DON_ACC), center_of_rotation MUST BE DEFINED!
878 ///
879 /// @global_write
880 ///
881 /// @remarks
882 ///
883 /// @references
884 ///
885 /// @authors
886 ///
887 /// @last_modified
888 ////////////////////////////////////////////////////////////////////////////////
889 // Overload to allow non-standard derivative calculations for geometric solvation
890 void
892  HBondDatabase const & database,
893  HBondOptions const & hbondoptions,
894  hbonds::HBEvalTuple const hbt, // hb evalation tuple
895  Vector const & Hxyz, // proton coords
896  Vector const & Dxyz, // Donor coords -- needed for derivative calculations
897  Vector const & HDunit, // unit vector toward donor
898  Vector const & Axyz, // acceptor coords
899  Vector const & Bxyz, // (acceptor) (pseudo) Base coords -- needed for derivative calculations
900  Vector const & BAunit, // unit vector towards base
901  Vector const & B2xyz, /// acceptor base 2 coords -- will be needed for derivative evaluation when the torsional term comes online
902  Real & energy, // returned energy
903  bool const evaluate_deriv,
904  HBondDerivs & deriv
905 ) {
906  HBDerivType const deriv_type = ( evaluate_deriv ? hbderiv_ABE_GO : hbderiv_NONE );
907  hb_energy_deriv_u2( database, hbondoptions, hbt, deriv_type, Hxyz, Dxyz, HDunit, Axyz, Bxyz, BAunit, B2xyz, energy, deriv );
908 }
909 ///////////////////////////////////////////////////////////////////////////////////////
910 /// @details Innermost score/derivative evaluation logic in this function; "u" stands for "unit vector"
911 /// and 2 stands for "the second u function" since the arguments to hbond_energy_deriv_u and the arguments
912 /// to hbond_energy_deriv_u2 are interchangable (i.e. if we tried to overload the hbond_energy_deriv, we end
913 /// up with infinite recursion as hbond_energy_deriv calls itself over and over again).
914 /// In here, we have the logic for evaluating the hbond polynomials and, if deriv_type == hbderiv_ABE_GO,
915 /// then it also computes the f1/f2 vectors for the 4 (eventually 5!) atoms involved in the hydrogen bond.
916 void
918  HBondDatabase const & database,
919  HBondOptions const & hbondoptions,
920  hbonds::HBEvalTuple const hbt, // hb evalation tuple
921  HBDerivType const deriv_type,
922  Vector const & Hxyz, // proton coords
923  Vector const & Dxyz, // Donor coords
924  Vector const & HDunit, // unit vector toward donor
925  Vector const & Axyz, // acceptor coords
926  Vector const & Bxyz, // (acceptor) (pseudo) Base coords
927  Vector const & BAunit, // unit vector from base to acceptor
928  Vector const & B2xyz, /// acceptor base 2 coords -- will be needed for derivative evaluation when the torsional term comes online
929  Real & energy, // returned energy
930  HBondDerivs & deriv
931 )
932 {
933  using namespace hbonds;
934 
935  // angle definitions: JSS the angle names are really bad. A-H-D = xD and B-A-H = xH
936  // cos(180-theta) = cos(thetaD) = xD angle to donor
937  // cos(180-psi) = cos(thetaH) = xH angle to proton
938  // raw angle in radians for ring nitrogen improper dihedral
939 
940  // energy - total energy from this hbond
941  // dE_dr - deriv w/respect to distance
942  // dE_dxD - deriv w/respect to cos(thetaD)
943  // dE_dxH - deriv w/respect to cos(thetaH)
944 
945  energy = MAX_HB_ENERGY + 1.0f;
946  //deriv.first = Vector( 0.0 );
947  //deriv.second = Vector( 0.0 );
948 
949  //Objexx: Local arrays declared static for speed
950  //car A->H unit vector, distance
951  Vector AH;
952  AH = Hxyz - Axyz;
953  //Real const AHdis2 = AH(1) * AH(1) + AH(2) * AH(2) + AH(3) * AH(3);
954  Real const AHdis2( AH.length_squared() );
955 
956  if ( AHdis2 > MAX_R2 ) return;
957  if ( AHdis2 < MIN_R2 ) return;
958  Real const AHdis = std::sqrt(AHdis2);
959  Real const inv_AHdis = 1.0f / AHdis;
960  Vector AHunit;
961  AHunit = AH * inv_AHdis;
962 
963 
964  //BW cosines of angle at donor, proton
965  Real const xD = /* cos(180-theta) = cos(thetaD) */
966  dot( AHunit, HDunit );
967 
968  if ( xD < MIN_xD ) return;
969  if ( xD > MAX_xD ) return;
970 
971  Real const xH = /* cos(180-psi) = cos(thetaH) */
972  dot( BAunit, AHunit );
973 
974  if ( xH < MIN_xH ) return;
975  if ( xH > MAX_xH ) return;
976 
977  Real chi( 0 );
978  if ( hbondoptions.use_sp2_chi_penalty() &&
980  B2xyz != Vector(-1.0, -1.0, -1.0) ) {
981  chi = numeric::dihedral_radians( Hxyz, Axyz, Bxyz, B2xyz );
982  } else if ( hbondoptions.measure_sp3acc_BAH_from_hvy() &&
983  ( hbt.acc_type() == hbacc_AHX || hbt.acc_type() == hbacc_HXL ) ) {
984  /// Bxyz really is the heavy atom base and B2xyz really is the hydroxyl hydrogen
985  /// this is guaranteed by the hbond_measure_sp3acc_BAH_from_hvy flag.
986  chi = numeric::dihedral_radians( Hxyz, Axyz, Bxyz, B2xyz );
987  }
988  //std::cout << " hb_energy_deriv_u2" <<
989  // " h =(" << Hxyz.x() << " " << Hxyz.y() << " " << Hxyz.z() << ")\n" <<
990  // " d =(" << Dxyz.x() << " " << Dxyz.y() << " " << Dxyz.z() << ")\n" <<
991  // " a =(" << Axyz.x() << " " << Axyz.y() << " " << Axyz.z() << ")\n" <<
992  // " ab =(" << Bxyz.x() << " " << Bxyz.y() << " " << Bxyz.z() << ")\n" <<
993  // " ab2=(" << B2xyz.x() << " " << B2xyz.y() << " " << B2xyz.z() << ")" <<
994  // std::endl;
995 
996  if ( deriv_type == hbderiv_NONE ) {
997  // NOTE: early return with energy if no derivatives
998  hbond_compute_energy( database, hbondoptions, hbt, AHdis, xD, xH, chi, energy );
999  return;
1000  }
1001 
1002  //JSS the rest happens only if we want deriviative information
1003  Real dE_dxH, dE_dxD, dE_dr, dE_dBAH, dE_dchi;
1004  bool apply_chi_torsion_penalty( false );
1005  HBGeoDimType AHD_geometric_dimension;
1006 
1008  database,
1009  hbondoptions,
1010  hbt,
1011  AHdis,
1012  xD,
1013  xH,
1014  chi,
1015  energy,
1016  apply_chi_torsion_penalty,
1017  AHD_geometric_dimension,
1018  dE_dr,
1019  dE_dxD,
1020  dE_dxH,
1021  dE_dBAH,
1022  dE_dchi);
1023 
1024  if (energy >= MAX_HB_ENERGY) return;
1025 
1026  deriv.h_deriv.f1() = deriv.h_deriv.f2() = Vector(0.0);
1027  deriv.acc_deriv.f1() = deriv.acc_deriv.f2() = Vector(0.0);
1028  deriv.abase_deriv.f1() = deriv.abase_deriv.f2() = Vector(0.0);
1029  deriv.abase2_deriv.f1() = deriv.abase2_deriv.f2() = Vector(0.0);
1030 
1031  if( ! hbondoptions.use_incorrect_deriv() ){
1032  /// APL: replacing the older derivative evaluation logic with calls to the
1033  /// numeric::deriv functions.
1034  /// There are five atoms, and therefore five derivative-vector pairs.
1035  /// D -- H -- A -- AB -- AB2
1036  /// D gets an angle_p1_deriv for the D-H-A angle
1037  /// H gets a) an angle_p2_deriv for the D-H-A angle,
1038  /// b) an angle_p1_deriv for the H-A-AB angle, and
1039  /// c) a distance_deriv for the H-A distance
1040  /// d) a chi-penalty deriv for the H-A-AB-AB2 dihedral
1041  /// A gets a) an angle_p1_deriv for the D-H-A angle,
1042  /// b) an angle_p2_deriv for the H-A-AB angle, and
1043  /// c) a distance_deriv for the H-A distance
1044  /// d) a chi-penalty deriv for the H-A-AB-AB2 dihedral
1045  /// AB gets a) an angle_p1_deriv for the H-A-AB angle
1046  /// b) a chi-penalty deriv for the H-A-AB-AB2 dihedral
1047  /// AB2 gets a chi-penalty deriv for the H-A-AB-AB2 dihedral
1048  using namespace numeric::deriv;
1049 
1050  Vector f1,f2;
1051 
1052  /// 1. H/A distance
1053  Real temp_AHdis;
1054  distance_f1_f2_deriv(Hxyz, Axyz, temp_AHdis, f1, f2);
1055  deriv.h_deriv.f1() = dE_dr * f1;
1056  deriv.h_deriv.f2() = dE_dr * f2;
1057  deriv.acc_deriv.f1() = -1 * dE_dr * f1;
1058  deriv.acc_deriv.f2() = -1 * dE_dr * f2;
1059 
1060  /// 2. theta derivatives (theta is the D-H-A angle)
1061  if(AHD_geometric_dimension == hbgd_cosAHD){
1062  Real theta;
1063  angle_p1_deriv( Axyz, Hxyz, Dxyz, theta, f1, f2);
1064  Real const dE_dxD_sin_theta = dE_dxD*sin( theta );
1065  deriv.acc_deriv.f1() += dE_dxD_sin_theta * f1;
1066  deriv.acc_deriv.f2() += dE_dxD_sin_theta * f2;
1067 
1068  angle_p1_deriv( Dxyz, Hxyz, Axyz, theta, f1, f2);
1069  deriv.don_deriv.f1() = dE_dxD_sin_theta * f1;
1070  deriv.don_deriv.f2() = dE_dxD_sin_theta * f2;
1071 
1072  angle_p2_deriv( Dxyz, Hxyz, Axyz, theta, f1, f2);
1073  deriv.h_deriv.f1() += dE_dxD_sin_theta * f1;
1074  deriv.h_deriv.f2() += dE_dxD_sin_theta * f2;
1075  } else if (AHD_geometric_dimension == hbgd_AHD){
1076  Real theta;
1077  angle_p1_deriv( Axyz, Hxyz, Dxyz, theta, f1, f2);
1078  deriv.acc_deriv.f1() += dE_dxD * f1;
1079  deriv.acc_deriv.f2() += dE_dxD * f2;
1080 
1081  angle_p1_deriv( Dxyz, Hxyz, Axyz, theta, f1, f2);
1082  deriv.don_deriv.f1() = dE_dxD * f1;
1083  deriv.don_deriv.f2() = dE_dxD * f2;
1084 
1085  angle_p2_deriv( Dxyz, Hxyz, Axyz, theta, f1, f2);
1086  deriv.h_deriv.f1() += dE_dxD * f1;
1087  deriv.h_deriv.f2() += dE_dxD * f2;
1088  }
1089 
1090 
1091  /// 3. phi derivatives (phi is the H-A-AB angle
1092  { // scope
1093  Real phi;
1094  Vector f1h(0.0),f2h(0.0);
1095  angle_p1_deriv( Hxyz, Axyz, Bxyz, phi, f1h, f2h);
1096  Real const dE_dxH_sin_phi = dE_dxH *sin( phi );
1097  deriv.h_deriv.f1() += dE_dxH_sin_phi * f1h;
1098  deriv.h_deriv.f2() += dE_dxH_sin_phi * f2h;
1099 
1100  Vector f1b(0.0),f2b(0.0);
1101  angle_p1_deriv( Bxyz, Axyz, Hxyz, phi, f1b, f2b);
1102  deriv.abase_deriv.f1() = dE_dxH_sin_phi * f1b;
1103  deriv.abase_deriv.f2() = dE_dxH_sin_phi * f2b;
1104 
1105  Vector f1a(0.0),f2a(0.0);
1106  angle_p2_deriv( Bxyz, Axyz, Hxyz, phi, f1a, f2a);
1107  deriv.acc_deriv.f1() += dE_dxH_sin_phi * f1a;
1108  deriv.acc_deriv.f2() += dE_dxH_sin_phi * f2a;
1109  if ( apply_chi_torsion_penalty ) {
1110  deriv.acc_deriv.f1() += dE_dBAH * f1a;
1111  deriv.acc_deriv.f2() += dE_dBAH * f2a;
1112  deriv.abase_deriv.f1() += dE_dBAH * f1b;
1113  deriv.abase_deriv.f2() += dE_dBAH * f2b;
1114  deriv.h_deriv.f1() += dE_dBAH * f1h;
1115  deriv.h_deriv.f2() += dE_dBAH * f2h;
1116  }
1117  }
1118 
1119  /// 4. The chi derivative, for the chi torsion defined by H -- A -- AB -- AB2,
1120  /// H gets a p1 deriv
1121  /// A gets a p2 deriv
1122  /// AB gets a p2 deriv
1123  /// and AB2 gets a p1 deriv.
1124  if ( apply_chi_torsion_penalty ) {
1125  Vector chi_h_f1(0), chi_h_f2(0);
1126  Vector chi_a_f1(0), chi_a_f2(0);
1127  Vector chi_ab_f1(0), chi_ab_f2(0);
1128  Vector chi_ab2_f1(0), chi_ab2_f2(0);
1129 
1130  dihedral_p1_cosine_deriv( Hxyz, Axyz, Bxyz, B2xyz, chi, chi_h_f1, chi_h_f2 );
1131  dihedral_p2_cosine_deriv( Hxyz, Axyz, Bxyz, B2xyz, chi, chi_a_f1, chi_a_f2 );
1132  dihedral_p2_cosine_deriv( B2xyz, Bxyz, Axyz, Hxyz, chi, chi_ab_f1, chi_ab_f2 );
1133  dihedral_p1_cosine_deriv( B2xyz, Bxyz, Axyz, Hxyz, chi, chi_ab2_f1, chi_ab2_f2 );
1134 
1135  deriv.h_deriv.f1() += dE_dchi * chi_h_f1;
1136  deriv.h_deriv.f2() += dE_dchi * chi_h_f2;
1137 
1138  deriv.acc_deriv.f1() += dE_dchi * chi_a_f1;
1139  deriv.acc_deriv.f2() += dE_dchi * chi_a_f2;
1140 
1141  deriv.abase_deriv.f1() += dE_dchi * chi_ab_f1;
1142  deriv.abase_deriv.f2() += dE_dchi * chi_ab_f2;
1143 
1144  deriv.abase2_deriv.f1() += dE_dchi * chi_ab2_f1;
1145  deriv.abase2_deriv.f2() += dE_dchi * chi_ab2_f2;
1146 
1147  }
1148 
1149  } else {
1150  ///APL -- older derivative evaluation logic depricated 2010-8-23
1151 
1152  Vector f1( 0.0 );
1153  Vector f2( 0.0 );
1154 
1155  //car distance-dependent gradient component.
1156  //car see also comments in minimize.cc
1157  //car dr/dphi = Eab x (V-Vb) . (V' - V)/|V-V'|
1158  //db (first cross product is the displacement of V upon a rotation dphi
1159  //db around the unit vector Eab, Vb is the coordinates of the second atom
1160  //db in the bond)
1161 
1162  //car dEr/dphi = dEr/dr * (Eab x (V-Vb) . (V' - V)] / |V-V'|
1163  //car dEr/dphi = dEr/dr * (Eab x (V-Vb) . (V' - V)] / r
1164  //car rearrange...
1165  //car dEr/dphi = dEr/dr * [Eab X Vb . (V' - V) + Eab . (V' x V)] / r
1166 
1167  //car Eab and Eab X Vb are calulated in dfunc_vdw and dependent on the torison
1168  //car angle with respect to which the derivative is being taken
1169  //car f1 and f2 are independent of the torsion angle and here we're precomputing
1170  //car increments to f1 and f2 for each hbond
1171  //car f1 = dEr/dr * (V'xV) / r
1172  //car f2 = dEr/dr * (V'-V) / r
1173  //car here, V' = H
1174  //car V = A
1175  //car dE/dr * 1/r = prefactor
1176 
1177  //car Eab and Eab X Vb are calulated in dfunc_vdw, here
1178 
1179  //car V'x V
1180  Vector HxA;
1181  HxA = cross( Hxyz, Axyz );
1182 
1183  // in/decrements to the f1 and f2 of the angle moving donor/acceptor
1184  Real prefactor = inv_AHdis * dE_dr;
1185  f1 = prefactor * HxA;
1186  f2 = prefactor * AH;
1187 
1188  //car gradient component for xD (theta)
1189  //car (see comments below for xH gradient)
1190  if (deriv_type != hbderiv_ABE_GO_NO_xD ){
1191  Vector BD;
1192  prefactor = inv_AHdis * dE_dxD;
1193  BD = prefactor * ( HDunit - xD * AHunit );
1194 
1195  Vector BDxA;
1196  BDxA = cross( BD, Axyz );
1197 
1198  //BW in/decrements to the f1 and f2 of the angle moving donor/acceptor
1199  f1 += BDxA;
1200  f2 += BD;
1201  }
1202 
1203  //BW gradient component for xH (psi)
1204  //car (from code and paper by Bill Wedemeyer)
1205  //car xH = (BAunit . AH)/AHdis
1206  //car dxH/dphi = 1/AHdis * (BAunit . dAH/dphi - xH *dAHdis/dphi)
1207  //car (note dBAunit/dphi = 0)
1208  //car
1209  //car dAHdis/dphi = AHunit . dAH/dphi
1210  //car
1211  //car substituting and rearranging....
1212  //car dxH/dphi = 1/AHdis * dAH/dphi . (BAunit - xH*AHunit)
1213  //car = 1/AHdis * dAH/dphi . BH
1214  //car
1215  //car note: BH = (BAunit - xH*AHunit) = component of BAunit that is
1216  //car perpendicular to AHunit
1217  //car
1218  //car dAH/dphi = Eab x (V-Vb) . (V' - V)/|V-V'| from above
1219  //car dAH/dphi = Eab x (H-Vb) . AHunit
1220  //car
1221  //car dExH/dphi = dExH/dxH * dxH/dphi
1222  //car = dExH/dxH * 1/AHdis * dAH/dphi . BH
1223  //car = dExH/dxH * 1/AHdis * (Eab x (H-Vb) .(H-A)/AHdis) . BH
1224  //car
1225  //car rearrange as with dEr/dr above to get f1 and f2 component
1226 
1227  //car f1 = dE/dxH *(1/AHdis) * BH x H
1228  //car f2 = dE/dxH *(1/AHdis) * BH
1229 
1230  if ( deriv_type != hbderiv_ABE_GO_NO_xH ){
1231 
1232  Vector BH;
1233  prefactor = inv_AHdis * dE_dxH;
1234  BH = prefactor * ( BAunit - xH * AHunit );
1235 
1236  Vector BHxH;
1237  BHxH = cross( BH, Hxyz );
1238 
1239  //BW in/decrements to the f1 and f2 of the angle moving donor/acceptor
1240  f1 += BHxH;
1241  f2 += BH;
1242  }
1243 
1244  deriv.h_deriv.f1() = f1;
1245  deriv.h_deriv.f2() = f2;
1246  deriv.acc_deriv.f1() = -1*f1;
1247  deriv.acc_deriv.f2() = -1*f2;
1248  }
1249 
1250 }
1251 
1252 
1253 ////////////////////////////////////////////////////////////////////////////////
1254 /// @begin hb_energy_deriv
1255 ///
1256 /// @remarks See comments on helper function above.
1257 ///
1258 ////////////////////////////////////////////////////////////////////////////////
1259 // Overload to allow non-standard derivative calculations for geometric solvation
1260 void
1262  HBondDatabase const & database,
1263  HBondOptions const & hbondoptions,
1264  HBEvalTuple const hbt, // hbond evaluation tuple -- determines what scoring function to use
1265  Vector const & Dxyz, // donor coords
1266  Vector const & Hxyz, // proton
1267  Vector const & Axyz, // acceptor
1268  Vector const & Bxyz, // acceptor base
1269  Vector const & B2xyz, // 2nd acceptor base for ring & SP3 acceptors
1270  Real & energy,
1271  bool const evaluate_deriv, // hb derivative type
1272  HBondDerivs & deriv
1273 ){
1274  HBDerivType const deriv_type = ( evaluate_deriv ? hbderiv_ABE_GO : hbderiv_NONE );
1275  hb_energy_deriv(database, hbondoptions, hbt, Dxyz, Hxyz, Axyz, Bxyz, B2xyz, energy, deriv_type, deriv );
1276 }
1277 
1278 void
1280  HBondDatabase const & database,
1281  HBondOptions const & hbondoptions,
1282  HBEvalTuple const hbt, // hbond evaluation type -- determines what scoring function to use
1283  Vector const & Dxyz, // donor coords
1284  Vector const & Hxyz, // proton
1285  Vector const & Axyz, // acceptor
1286  Vector const & Bxyz, // acceptor base
1287  Vector const & B2xyz, // 2nd acceptor base for ring & SP3 acceptors
1288  Real & energy,
1289  HBDerivType const deriv_type, // hb derivative type
1290  HBondDerivs & deriv
1291 )
1292 {
1293  using namespace hbonds;
1294 
1295 // angle definitions: JSS the angle names are really bad. A-H-D = xD and B-A-H = xH
1296 // cos(180-theta) = cos(thetaD) = xD angle to donor
1297 // cos(180-psi) = cos(thetaH) = xH angle to proton
1298 // raw angle in radians for ring nitrogen improper dihedral
1299 
1300 // energy - total energy from this hbond
1301 // dE_dr - deriv w/respect to distance
1302 // dE_dxD - deriv w/respect to cos(thetaD)
1303 // dE_dxH - deriv w/respect to cos(thetaH)
1304 
1305 //Objexx: Local arrays declared static for speed
1306 //JSS all early exits are in helper above, so this version of the function is deprecated.
1307 //These unit vectors are invariant for hbonded pairs and can be precalculated.
1308 //car H->D unit vector, dis2
1309  Vector HDunit;
1310  HDunit = Dxyz - Hxyz;
1311  Real const HDdis2( HDunit.length_squared() );
1312 
1313  // NaN check
1314  if ( ! numeric::is_a_finitenumber( HDdis2, 1.0, 0.0 ) ) {
1315  std::string const warning( "NAN occurred in H-bonding calculations!" );
1316  PyAssert(false, warning); // allows for better error handling from within Python
1317  tr.Error << warning << std::endl;
1318 
1319 #ifndef BOINC
1320  bool fail_on_bad_hbond = basic::options::option[ basic::options::OptionKeys::in::file::fail_on_bad_hbond ]();
1321  if ( fail_on_bad_hbond ) {
1322  throw( utility::excn::EXCN_Msg_Exception( warning ) );
1323  utility_exit();
1324  }
1325 #endif
1326  }
1327 
1328  if ( HDdis2 < 0.64 || HDdis2 > 1.5625 ) { // .8 to 1.25A
1329  if ( true ) {
1330  // this warning was runlevel dependent
1331  if ( tr.visible() )
1332  tr.Debug << "Warning: hb_energy_deriv has H(" << Hxyz(1) << ","
1333  << Hxyz(2)<< "," << Hxyz(3) << ") D(" << Dxyz(1) << "," << Dxyz(2)
1334  << "," << Dxyz(3) << ") distance out of range " << std::sqrt( HDdis2 ) << std::endl;
1335  }
1336  energy = 0.0;
1337  //deriv.first = Vector( 0.0 );
1338  //deriv.second = Vector( 0.0 );
1339  deriv = ZERO_DERIV2D; /// overwrite everything as 0
1340  return;
1341  }
1342 
1343  Real const inv_HDdis = 1.0f / std::sqrt( HDdis2 );
1344  HDunit *= inv_HDdis;
1345 
1346  //car B->A unit vector
1347  Vector BAunit;
1348  // the pseudo-base xyz coordinate
1349  Vector PBxyz;
1350  chemical::Hybridization acc_hybrid( get_hbe_acc_hybrid( hbt.eval_type() ) );
1351  make_hbBasetoAcc_unitvector(hbondoptions, acc_hybrid, Axyz, Bxyz, B2xyz, PBxyz, BAunit);
1352  hb_energy_deriv_u2(database, hbondoptions, hbt, deriv_type, Hxyz, Dxyz, HDunit, Axyz, PBxyz, BAunit, B2xyz, energy, deriv );
1353 }
1354 
1355 
1356 Vector
1358  HBondOptions const & hbondoptions,
1359  conformation::Residue const & residue,
1360  int atom_id
1361 )
1362 {
1363  assert( residue.atom_type_set()[ residue.atom(atom_id).type() ].is_acceptor() );
1364  chemical::Hybridization acc_hybrid(residue.atom_type(atom_id).hybridization());
1365  Vector ovect, dummy;
1367  hbondoptions,
1368  acc_hybrid,
1369  residue.atom( atom_id ).xyz(),
1370  residue.atom( residue.atom_base( atom_id ) ).xyz(),
1371  residue.atom( residue.abase2( atom_id ) ).xyz(),
1372  dummy, ovect );
1373  return ovect;
1374 }
1375 
1376 
1377 ///////////////////////////////////////////////////////////////////////////////
1378 //
1379 // construct for a hydrogen bond Acceptor, the coordinate of the pseudo-atom
1380 // that controls the H-A-AB angle and the the unit vector from the acceptor
1381 // to this pseudo atom. Different hybridization types use different pseudo-atom
1382 // geometries
1383 //
1384 void
1386  HBondOptions const & hbondoptions,
1387  chemical::Hybridization const & acc_hybrid,
1388  Vector const & Axyz,
1389  Vector const & Bxyz,
1390  Vector const & B2xyz,
1391  Vector & PBxyz,
1392  Vector & BAunit
1393 )
1394 {
1395  using namespace chemical;
1396  switch(acc_hybrid){
1397  case SP2_HYBRID: PBxyz = Bxyz; break;
1398  case SP3_HYBRID:
1399  /// If the heavy-atom base of an sp3 hybridized acceptor is to be used
1400  /// to compute the BAH angle (i.e. CB on Ser/Thr), then give it Bxyz;
1401  /// else, git it B2xyz (i.e. HG on Ser/Thr).
1402  if ( hbondoptions.measure_sp3acc_BAH_from_hvy() ) {
1403  PBxyz = Bxyz;
1404  } else {
1405  PBxyz = B2xyz;
1406  }
1407  break;
1408  case RING_HYBRID: PBxyz = Real(0.5) * ( Bxyz + B2xyz ); break;
1409  default:
1410  BAunit = 0.0;
1411  tr << "Unrecognized Hybridization: " << acc_hybrid << std::endl;
1412  utility_exit();
1413  }
1414  BAunit = Axyz - PBxyz;
1415  BAunit.normalize();
1416 }
1417 
1418 /// @details Divide up the f1/f2 contributions calculated for the PBxyz coordinate
1419 /// among the atom(s) that define the location of the PBxyz coordinate. In the
1420 /// base of ring-hybridized acceptors, half of the derivative goes to the abase,
1421 /// and half of hte derivative goes to the abase2. This code mirrors the logic
1422 /// in the make_hbBasetoAcc_unitvector code above.
1423 void
1425  HBondOptions const & hbondoptions,
1426  conformation::Residue const & acc_rsd,
1427  Size acc_atom,
1428  HBEvalTuple const hbt,
1429  DerivVectorPair const & abase_deriv,
1430  Real weighted_energy,
1431  utility::vector1< DerivVectorPair > & acc_atom_derivs
1432 )
1433 {
1434  using namespace chemical;
1435  Hybridization acc_hybrid( get_hbe_acc_hybrid( hbt.eval_type() ) );
1436  switch( acc_hybrid ){
1437  case SP2_HYBRID: {
1438  acc_atom_derivs[ acc_rsd.atom_base( acc_atom ) ].f1() += weighted_energy * abase_deriv.f1();
1439  acc_atom_derivs[ acc_rsd.atom_base( acc_atom ) ].f2() += weighted_energy * abase_deriv.f2(); break;
1440  }
1441  case SP3_HYBRID: {
1442  if ( ! hbondoptions.measure_sp3acc_BAH_from_hvy() ) {
1443  acc_atom_derivs[ acc_rsd.abase2( acc_atom ) ].f1() += weighted_energy * abase_deriv.f1();
1444  acc_atom_derivs[ acc_rsd.abase2( acc_atom ) ].f2() += weighted_energy * abase_deriv.f2();
1445  } else {
1446  acc_atom_derivs[ acc_rsd.atom_base( acc_atom ) ].f1() += weighted_energy * abase_deriv.f1();
1447  acc_atom_derivs[ acc_rsd.atom_base( acc_atom ) ].f2() += weighted_energy * abase_deriv.f2();
1448  }
1449  break;
1450  }
1451  case RING_HYBRID: {
1452  acc_atom_derivs[ acc_rsd.atom_base( acc_atom ) ].f1() += 0.5 * weighted_energy * abase_deriv.f1();
1453  acc_atom_derivs[ acc_rsd.atom_base( acc_atom ) ].f2() += 0.5 * weighted_energy * abase_deriv.f2();
1454  acc_atom_derivs[ acc_rsd.abase2( acc_atom ) ].f1() += 0.5 * weighted_energy * abase_deriv.f1();
1455  acc_atom_derivs[ acc_rsd.abase2( acc_atom ) ].f2() += 0.5 * weighted_energy * abase_deriv.f2(); break;
1456  }
1457  default:
1458  tr << "Unrecognized Hybridization: " << acc_hybrid << std::endl;
1459  utility_exit();
1460  }
1461 
1462 }
1463 
1464 
1465 /// @brief create a unit vector pointing from the hydrogen toward the donor
1466 /// The atom_id is the atom id of the hydrogen atom
1467 Vector
1469  conformation::Residue const & residue,
1470  int atom_id
1471 )
1472 {
1473  assert( residue.atom_type_set()[ residue.atom( residue.atom_base(atom_id)).type() ].is_donor() );
1474 
1475  Vector HDunit;
1476  HDunit = residue.atom( residue.atom_base( atom_id ) ).xyz() - residue.atom( atom_id ).xyz();
1477  Real const HDdis2( HDunit.length_squared() );
1478  Real const inv_HDdis = 1.0f / std::sqrt( HDdis2 );
1479  HDunit *= inv_HDdis;
1480  return HDunit;
1481 }
1482 
1483 } // hbonds
1484 } // scoring
1485 } // core