Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ElecDensEnergy.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // This file is part of the Rosetta software suite and is made available under license.
5 // The Rosetta software is developed by the contributing members of the Rosetta Commons consortium.
6 // (C) 199x-2009 Rosetta Commons participating institutions and developers.
7 // For more information, see http://www.rosettacommons.org/.
8 
9 /// @file core/scoring/methods/ElecDensEnergy.cc
10 /// @brief Scoring a structure's fit to electron density
11 /// @author Frank DiMaio
12 
13 
14 // Unit headers
17 #include <basic/options/option.hh>
18 
19 // Package headers
20 #include <core/chemical/AA.hh>
23 #include <core/scoring/Energies.hh>
24 // AUTO-REMOVED #include <core/scoring/EnergyGraph.hh>
27 #include <numeric/xyz.functions.hh>
28 #include <numeric/statistics.functions.hh>
29 #include <core/kinematics/Edge.hh>
34 // AUTO-REMOVED #include <core/conformation/symmetry/util.hh>
35 
36 
37 // Project headers
38 #include <core/pose/Pose.hh>
40 
41 #include <basic/options/keys/edensity.OptionKeys.gen.hh>
42 
43 // Utility headers
44 
45 //
46 #include <basic/Tracer.hh>
47 
50 #include <utility/vector1.hh>
51 
52 #ifdef WIN32
53  #define _USE_MATH_DEFINES
54  #include <math.h>
55 #endif
56 
57 using basic::T;
58 using basic::Error;
59 using basic::Warning;
60 
61 // C++
62 
63 namespace core {
64 namespace scoring {
65 namespace electron_density {
66 
67 
68 /// @details This must return a fresh instance of the ElecDensEnergy class,
69 /// never an instance already in use
73 ) const {
74  return new ElecDensEnergy;
75 }
76 
79  ScoreTypes sts;
80  sts.push_back( elec_dens_window );
81  return sts;
82 }
83 
84 
85  using namespace core::scoring::methods;
86 
87 static basic::Tracer TR("core.scoring.electron_density.ElecDensEnergy");
88 
89 inline core::Real SQ( core::Real N ) { return N*N; }
90 
91 
94 
95 /// c-tor
97  // load map
99  TR.Debug << (map_loaded? "Map loaded." : "Error loading map!") << std::endl;
100 }
101 
102 
103 /// clone
105  return new ElecDensEnergy( *this );
106 }
107 
108 /////////////////////////////////////////////////////////////////////////////
109 
111  pose::Pose const & pose,
112  Size res1,
113  Size res2
114 ) const {
115  // is this fn. called?
116  return ( pose.residue( res1 ).aa() == core::chemical::aa_vrt || pose.residue( res2 ).aa() == core::chemical::aa_vrt );
117 }
118 
119 
120 void
123 
124  // grab symminfo (if defined) from the pose
127  symminfo = dynamic_cast<const core::conformation::symmetry::SymmetricConformation & >(
128  pose.conformation()).Symmetry_Info();
129  }
130 
131  // rescore everything, cache derivatives
132  core::Real ccsum=0.0;
133  core::Size nressum=0;
134  for (int r = 1; r<= (int)pose.total_residue(); ++r) {
135  conformation::Residue const &rsd ( pose.residue(r) );
136  if (rsd.aa() == core::chemical::aa_vrt) continue;
137 
138  ccsum += core::scoring::electron_density::getDensityMap().matchRes(r, rsd, pose, symminfo, true );
139  nressum++;
140 
141  // if we're symmetric, add contributions from all copies
142  if (symminfo) {
143  utility::vector1< core::Size > bbclones = symminfo->bb_clones( r );
144  for (int i=1; i<=(int)bbclones.size(); ++i)
146  bbclones[i], pose.residue(bbclones[i]), pose, symminfo, true );
147  nressum++;
148  }
149  }
150  TR.Debug << "Average CC = " << ccsum/nressum << " ( " << nressum << " res)" << std::endl;
152 }
153 
154 
155 void
157  pose::Pose & pose,
158  ScoreFunction const &
159 ) const {
160  using namespace methods;
161 
162  // Do we have a map?
163  if (!map_loaded) {
164  utility_exit_with_message("Density scoring function called but no map loaded.");
165  }
166 
167  // make sure the root of the FoldTree is a virtual atom and is followed by a jump
168  // if not, emit warning
169  kinematics::Edge const &root_edge ( *pose.fold_tree().begin() );
170  int virt_res_idx = root_edge.start();
171  conformation::Residue const &root_res( pose.residue( virt_res_idx ) );
172 
173  pose_is_proper = true;
174  if (root_res.aa() != core::chemical::aa_vrt || root_edge.label() < 0) {
175  //utility_exit_with_message("Fold tree is not set properly for density scoring!");
176  TR.Error << "Fold tree is not set properly for density scoring!" << std::endl;
177  pose_is_proper = false;
178  }
179 
180  // create LR energy container if needed
181  LongRangeEnergyType const & lr_type( long_range_type() );
182  Energies & energies( pose.energies() );
183  bool create_new_lre_container( false );
184  if ( energies.long_range_container( lr_type ) == 0 ) {
185  create_new_lre_container = true;
186  } else {
187  LREnergyContainerOP lrc = energies.nonconst_long_range_container( lr_type );
188  OneToAllEnergyContainerOP dec( static_cast< OneToAllEnergyContainer * > ( lrc.get() ) );
189  // make sure size or root did not change
190  if ( dec->size() != pose.total_residue() || dec->fixed() != virt_res_idx ) {
191  create_new_lre_container = true;
192  }
193  }
194 
195  if ( create_new_lre_container ) {
196  TR << "Creating new one-to-all energy container (" << pose.total_residue() << ")" << std::endl;
197  LREnergyContainerOP new_dec = new OneToAllEnergyContainer( virt_res_idx, pose.total_residue(), elec_dens_window );
198  energies.set_long_range_container( lr_type, new_dec );
199  }
200 
201  // allocate space for per-AA stats
202  int nres = pose.total_residue();
204 }
205 
206 
207 void
209  conformation::Residue const &,
210  pose::Pose const &,
211  ScoreFunction const &,
212  EnergyMap &
213 ) const {
214  return;
215 }
216 
217 
218 void
220  pose::Pose const & ,
221  ScoreFunction const &,
222  EnergyMap &
223 ) const {
224  return;
225 }
226 
227 
228 void
230  conformation::Residue const & rsd1,
231  conformation::Residue const & rsd2,
232  pose::Pose const & pose,
233  ScoreFunction const &,
234  EnergyMap & emap
235 ) const {
236  using namespace numeric::statistics;
237 
238  if (!pose_is_proper) {
239  return;
240  }
241  if (rsd1.aa() != core::chemical::aa_vrt && rsd2.aa() != core::chemical::aa_vrt) return;
242  if (rsd1.aa() == core::chemical::aa_vrt && rsd2.aa() == core::chemical::aa_vrt) return;
243 
244  conformation::Residue const &rsd (rsd1.aa() == core::chemical::aa_vrt? rsd2 : rsd1 );
245  Size r = rsd.seqpos();
246 
247  // grab symminfo (if defined) from the pose
249  core::Size nsubunits = 1;
251  symminfo = dynamic_cast<const core::conformation::symmetry::SymmetricConformation & >( pose.conformation()).Symmetry_Info();
252  nsubunits = symminfo->subunits();
253 
254  if (! symminfo->bb_is_independent( r ) ) return;
255  }
256 
257  core::Real cc = core::scoring::electron_density::getDensityMap().matchRes(r, rsd, pose, symminfo, false );
258  Real z_CC = cc / 0.1;
259  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
260  Real edensScore = log ( p_null ) / ((core::Real)nsubunits);
261 
262  // if we're symmetric, add contributions from all copies
263  if (symminfo) {
264  utility::vector1< core::Size > bbclones = symminfo->bb_clones( r );
265  for (int i=1; i<=(int)bbclones.size(); ++i) {
267  bbclones[i], pose.residue(bbclones[i]), pose, symminfo, false );
268  z_CC = cc / 0.1;
269  p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
270  edensScore += log ( p_null ) / ((core::Real)nsubunits);
271  }
272  }
273 
274  emap[ elec_dens_window ] += edensScore;
275  return;
276 }
277 
278 
279 void
281  id::AtomID const & id,
282  pose::Pose const & pose,
283  kinematics::DomainMap const &, // domain_map,
284  ScoreFunction const & ,
285  EnergyMap const & weights,
286  Vector & F1,
287  Vector & F2
288 ) const
289 {
290  using namespace numeric::statistics;
291 
292  int resid = id.rsd();
293  int atmid = id.atomno();
294 
295  if (!pose_is_proper) return;
296  if (!pose.is_fullatom()) return;
297 
298  // if (hydrogen) return
299  if ( pose.residue(resid).aa() != core::chemical::aa_vrt && !pose.residue(resid).atom_type(atmid).is_heavyatom() ) return;
300 
304 
306 
307  // if we're symmetric, but _not_ scoring the symmetric complex,
308  // we need to scale derivatives by the score
310  //////////////////////
311  // SYMMETRIC CASE
312  //////////////////////
314  (dynamic_cast<const core::conformation::symmetry::SymmetricConformation &>(pose.conformation()).Symmetry_Info());
315  core::Size nsubunits = symminfo->subunits();
316  core::Size nres_per = symminfo->num_independent_residues();
317  bool remapSymm = basic::options::option[ basic::options::OptionKeys::edensity::score_symm_complex ]();
318 
319  if ( pose.residue(resid).aa() == core::chemical::aa_vrt) {
320  if (!remapSymm) return;
321 
322  // derivative is only defined for the 'ORIG' atom in the virtual
323  if (atmid != 2) return;
324 
325  // if not a branch node, we're done
327  int nchildren = edges_i.size();
328  if (nchildren < 2) return;
329 
330  // odd case ... if this vrt is controlled by a cloned jump then we dont have to compute derivs
331  // for now we'll just check the parent, but perhaps we should trace root->here?
332  if ( !pose.fold_tree().is_root( resid ) ) {
333  core::kinematics::Edge edge_incoming = pose.fold_tree().get_residue_edge(resid);
334  if (! symminfo->jump_is_independent( edge_incoming.label() ) )
335  return;
336  }
337 
338  // if any child jumps are cloned such that the clone jump start is ALSO a branching vrt
339  // then we need to aggregate these as well
340  // TO DO: if a jump is _fixed_ we should move downstream to the next movable jump
341  // This isn't a problem with symm files generated by the perl script, however,
342  // it may be a problem in hand-coded ones
344  for (int j=1; j<=nchildren; ++j) {
345  int basejump = edges_i[j].label();
346  if (! symminfo->jump_is_independent( basejump ) )
347  basejump = symminfo->jump_follows( basejump );
348  utility::vector1< core::Size > jumpclones = symminfo->jump_clones( basejump );
349  for (int k=0; k<=(int)jumpclones.size(); ++k) {
350  core::Size upstream = pose.fold_tree().jump_edge( k==0 ? basejump : jumpclones[k] ).start();
351  edges_j = pose.fold_tree().get_outgoing_edges(upstream);
352  if (edges_j.size() > 1 && std::find( vrtclones.begin(), vrtclones.end(), upstream ) == vrtclones.end() ) {
353  vrtclones.push_back( upstream );
354  }
355  }
356  }
357 
358  // loop over all clones of this VRT
359  for (int i=1; i<=(int)vrtclones.size(); ++i) {
360  edges_i = pose.fold_tree().get_outgoing_edges(vrtclones[i]);
361 
362  // STEP 1: subtract children's contribution
363  for (int j=1; j<=nchildren; ++j) {
364  int downstream = edges_i[j].stop();
365  utility::vector1<int> mapping_j;
367  core::scoring::electron_density::getDensityMap().get_symmMap( downstream , mapping_j, R_j );
368 
369  for (int k=1; k<=(int)nsubunits; ++k) {
370  if (mapping_j[k] == 0) continue; // subunit k is not under child j
371 
372  // loop over all atms in reses in subunit k
373  for (int l=1, l_end=nres_per; l<=l_end; ++l) {
374  // there is a mapping from k->mapping_j[k]
375  int source_res = (k-1)*nres_per+l;
376  int target_res = (mapping_j[k]-1)*nres_per+l;
377 
378  for (int m=1, m_end=pose.residue(target_res).nheavyatoms(); m<=m_end; ++m) {
379  numeric::xyzVector<core::Real> X_lm_src = pose.residue(source_res).atom(m).xyz();
380  numeric::xyzVector<core::Real> X_lm_tgt = pose.residue(target_res).atom(m).xyz();
381 
382  core::scoring::electron_density::getDensityMap().dCCdx_res( m, source_res, X_lm_src, pose.residue(source_res), pose, dCCdx );
384  Real z_CC = CC / 0.1;
385  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
386  numeric::xyzVector< core::Real > dEdx = 0.5 * ( 1.0 / p_null ) *
387  (-2.0/sqrt(M_PI)) *
388  exp(-SQ( z_CC/sqrt(2.0) )) *
389  1/sqrt(0.02) *
390  R_j * dCCdx / ((core::Real)nsubunits);
391 
392  numeric::xyzVector<core::Real> atom_x = X_lm_tgt;
393  numeric::xyzVector<core::Real> const f2( dEdx );
394  numeric::xyzVector<core::Real> atom_y = -f2 + atom_x;
395  Vector const f1( atom_x.cross( atom_y ) );
396 
397  F1 -= weights[ elec_dens_window ] * f1;
398  F2 -= weights[ elec_dens_window ] * f2;
399  }
400  }
401  }
402  }
403 
404  // STEP 2: add my contribution
405  utility::vector1<int> mapping_i;
407  core::scoring::electron_density::getDensityMap().get_symmMap( vrtclones[i] , mapping_i, R_i );
408  for (int k=1; k<=(int)nsubunits; ++k) {
409  if (mapping_i[k] == 0) continue; // subunit k is not under child j
410 
411  // loop over all atms in reses in subunit k
412  for (int l=1, l_end=nres_per; l<=l_end; ++l) {
413  // there is a mapping from k->mapping_i[k]
414  int source_res = (k-1)*nres_per+l;
415  int target_res = (mapping_i[k]-1)*nres_per+l;
416 
417  for (int m=1, m_end=pose.residue(target_res).nheavyatoms(); m<=m_end; ++m) {
418  numeric::xyzVector<core::Real> X_lm_src = pose.residue(source_res).atom(m).xyz();
419  numeric::xyzVector<core::Real> X_lm_tgt = pose.residue(target_res).atom(m).xyz();
420 
421  //core::scoring::electron_density::getDensityMap().dCCdx_res( m, source_res, X_lm_src, dummyAtmList, dummyAtmList, dCCdx );
422  core::scoring::electron_density::getDensityMap().dCCdx_res( m, source_res, X_lm_src, pose.residue(source_res), pose, dCCdx );
424  Real z_CC = CC / 0.1;
425  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
426  numeric::xyzVector< core::Real > dEdx = 0.5 * ( 1.0 / p_null ) *
427  (-2.0/sqrt(M_PI)) *
428  exp(-SQ( z_CC/sqrt(2.0) )) *
429  1/sqrt(0.02) *
430  R_i * dCCdx / ((core::Real)nsubunits);
431 
432  numeric::xyzVector<core::Real> atom_x = X_lm_tgt;
433  numeric::xyzVector<core::Real> const f2( dEdx );
434  numeric::xyzVector<core::Real> atom_y = -f2 + atom_x;
435  Vector const f1( atom_x.cross( atom_y ) );
436 
437  F1 += weights[ elec_dens_window ] * f1;
438  F2 += weights[ elec_dens_window ] * f2;
439  }
440  }
441  }
442  }
443  } else { // NON-VRT
444  if (! symminfo->bb_is_independent( resid ) ) return;
445 
446  utility::vector1< Size > myClones = symminfo->bb_clones(resid);
447  for (int i=0; i<=(int)myClones.size(); ++i) {
448  numeric::xyzVector<core::Real> X_i = (i==0) ? X : pose.xyz( id::AtomID( atmid, myClones[i] ) );
449  //core::scoring::electron_density::getDensityMap().dCCdx_res(
450  // atmid, (i==0) ? resid : myClones[i], X_i, dummyAtmList, dummyAtmList, dCCdx );
452  atmid, (i==0)?resid:myClones[i], X_i, pose.residue((i==0)?resid:myClones[i]), pose, dCCdx );
453 
454  // get R
455  if (remapSymm)
456  core::scoring::electron_density::getDensityMap().get_R( symminfo->subunit_index( (i==0) ? resid : myClones[i] ), R );
457 
458  Real CC = core::scoring::electron_density::getDensityMap().getCachedScore( (i==0) ? resid : myClones[i] );
459  Real z_CC = CC / 0.1;
460  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
461 
462  // divide by the number of subunits since rosetta will scale up later (??)
463  numeric::xyzVector< core::Real > dEdx = 0.5 * ( 1.0 / p_null ) *
464  (-2.0/sqrt(M_PI)) *
465  exp(-SQ( z_CC/sqrt(2.0) )) *
466  1/sqrt(0.02) *
467  R * dCCdx / ((core::Real)nsubunits);
468 
469  numeric::xyzVector<core::Real> atom_x = X; //X_i;
470  numeric::xyzVector<core::Real> const f2( dEdx );
471  numeric::xyzVector<core::Real> atom_y = -f2 + atom_x;
472  Vector const f1( atom_x.cross( atom_y ) );
473 
474  //if ( atmid==2)
475  // std::cerr << "at res " << resid
476  // << " f1=" << f1 << " f2=" << f2 << std::endl;
477  F1 += weights[ elec_dens_window ] * f1;
478  F2 += weights[ elec_dens_window ] * f2;
479  }
480  }
481  } else {
482  //////////////////////
483  // ASYMMETRIC CASE
484  //////////////////////
485  if ( pose.residue(resid).aa() == core::chemical::aa_vrt) return;
486 
487 
488  // the derivative of edens _score_ as a function of dCC/dx
490  Real z_CC = CC / 0.1;
491  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
492 
493  core::scoring::electron_density::getDensityMap().dCCdx_res( atmid, resid, X, pose.residue(resid), pose, dCCdx );
494  numeric::xyzVector< core::Real > dEdx = ( 1.0 / p_null ) *
495  0.5 *
496  (-2.0/sqrt(M_PI)) *
497  exp(-SQ( z_CC/sqrt(2.0) )) *
498  1/sqrt(0.02) *
499  dCCdx;
500 
502  numeric::xyzVector<core::Real> const f2( dEdx );
503  numeric::xyzVector<core::Real> atom_y = -f2 + atom_x; // a "fake" atom in the direcion of the gradient
504  Vector const f1( atom_x.cross( atom_y ) );
505 
506  F1 += weights[ elec_dens_window ] * f1;
507  F2 += weights[ elec_dens_window ] * f2;
508  }
509 }
510 
513 {
514  return 1; // Initial versioning
515 }
516 
517 
518 }
519 }
520 }