Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ElecDensCenEnergy.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>
24 #include <core/scoring/Energies.hh>
27 #include <core/kinematics/Edge.hh>
29 #include <numeric/xyz.functions.hh>
30 #include <numeric/statistics.functions.hh>
33 // AUTO-REMOVED #include <core/conformation/symmetry/util.hh>
34 
35 
36 // Project headers
37 #include <core/pose/Pose.hh>
39 
40 #include <basic/options/keys/edensity.OptionKeys.gen.hh>
41 
42 
43 //
44 #include <basic/Tracer.hh>
45 
47 #include <utility/vector1.hh>
48 
49 using basic::T;
50 using basic::Error;
51 using basic::Warning;
52 
53 #ifdef WIN32
54  #define _USE_MATH_DEFINES
55  #include <math.h>
56 #endif
57 // C++
58 
59 namespace core {
60 namespace scoring {
61 namespace electron_density {
62 
63 
64 /// @details This must return a fresh instance of the ElecDensCenEnergy class,
65 /// never an instance already in use
69 ) const {
70  return new ElecDensCenEnergy;
71 }
72 
75  ScoreTypes sts;
76  sts.push_back( elec_dens_whole_structure_ca );
77  return sts;
78 }
79 
80 
81 using namespace core::scoring::methods;
82 
83 static basic::Tracer TR("core.scoring.electron_density.ElecDensEnergy");
84 
85 inline core::Real SQ( core::Real N ) { return N*N; }
86 
89 
90 /// c-tor
92  // load map
94  TR.Debug << "Map loaded? " << (map_loaded ? "yes" : "no") << std::endl;
95 }
96 
97 
98 /// clone
101  return new ElecDensCenEnergy( *this );
102 }
103 
104 
105 /////////////////////////////////////////////////////////////////////////////
106 // scoring
107 /////////////////////////////////////////////////////////////////////////////
108 
109 bool
111  pose::Pose const & pose,
112  Size res1,
113  Size res2
114 ) const {
115  return ( pose.residue( res1 ).aa() == core::chemical::aa_vrt || pose.residue( res2 ).aa() == core::chemical::aa_vrt );
116 }
117 
118 
119 void
121 {
122  if (!pose.is_fullatom()) return;
123 
126  symminfo = dynamic_cast<const core::conformation::symmetry::SymmetricConformation & >( pose.conformation()).Symmetry_Info();
127  }
129 }
130 
131 
132 void
134  pose::Pose & pose,
135  ScoreFunction const &
136 ) const {
137  // Do we have a map?
138  if (!map_loaded) {
139  utility_exit_with_message("Density scoring function called but no map loaded.");
140  }
141 
142  // make sure the root of the FoldTree is a virtual atom and is followed by a jump
143  kinematics::Edge const &root_edge ( *pose.fold_tree().begin() );
144  int virt_res_idx = root_edge.start();
145  conformation::Residue const &root_res( pose.residue( virt_res_idx ) );
146 
147  pose_is_proper = true;
148  if (root_res.type().name() != "VRT" || root_edge.label() < 0) {
149  utility_exit_with_message("Fold tree is not set properly for density scoring!");
150  //pose_is_proper = false;
151  }
152 
153  // create LR energy container
154  LongRangeEnergyType const & lr_type( long_range_type() );
155  Energies & energies( pose.energies() );
156  bool create_new_lre_container( false );
157 
158  if ( energies.long_range_container( lr_type ) == 0 ) {
159  create_new_lre_container = true;
160  } else {
161  LREnergyContainerOP lrc = energies.nonconst_long_range_container( lr_type );
162  OneToAllEnergyContainerOP dec( static_cast< OneToAllEnergyContainer * > ( lrc.get() ) );
163  // make sure size or root did not change
164  if ( dec->size() != pose.total_residue() || dec->fixed() != virt_res_idx ) {
165  create_new_lre_container = true;
166  }
167  }
168 
169  if ( create_new_lre_container ) {
170  TR << "Creating new LRE container (" << pose.total_residue() << ")" << std::endl;
172  energies.set_long_range_container( lr_type, new_dec );
173  }
174 
175  // allocate space for per-AA stats
176  int nres = pose.total_residue();
178 
179  // grab symminfo (if defined) from the pose
180  // make a copy
183  //symminfo = &(dynamic_cast<const core::conformation::symmetry::SymmetricConformation &>(pose.conformation()).Symmetry_Info());
184  symminfo = dynamic_cast<const core::conformation::symmetry::SymmetricConformation & >( pose.conformation() ).Symmetry_Info();
185  }
186 
187  // do the actual matching here; split scores among individual residues
188  //utility::vector1< conformation::ResidueCAP > reses = pose.conformation().const_residues();
190 
191  TR.Debug << "ElecDensCenEnergy::setup_for_scoring() returns CC = " << structure_score << std::endl;
192 
193  // # of scoring residues
194  nreses = 0;
195  for (int i=1; i<=(int)pose.total_residue(); ++i)
196  if ( pose.residue(i).is_protein() && pose.residue(i).atom_name(2) == " CA " )
197  nreses++;
198 }
199 
200 
201 void
203  conformation::Residue const &,
204  pose::Pose const &,
205  ScoreFunction const &,
206  EnergyMap &
207 ) const {
208  return;
209 }
210 
211 
212 void
214  pose::Pose const & ,
215  ScoreFunction const &,
216  EnergyMap &
217 ) const {
218  return;
219 }
220 
221 
222 void
224  conformation::Residue const & rsd1,
225  conformation::Residue const & rsd2,
226  pose::Pose const & , //pose,
227  ScoreFunction const &,
228  EnergyMap & emap
229 ) const
230 {
231  using namespace numeric::statistics;
232 
233  if (rsd1.aa() != core::chemical::aa_vrt && rsd2.aa() != core::chemical::aa_vrt) return;
234  if (rsd1.aa() == core::chemical::aa_vrt && rsd2.aa() == core::chemical::aa_vrt) return;
235 
236  //Size resid = rsd.seqpos();
238  Real z_CC = cc / 0.1;
239  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
240  Real edensScore = log ( p_null );
241 
242  emap[ elec_dens_whole_structure_ca ] += edensScore;
243  return;
244 }
245 
246 
247 void
249  id::AtomID const & id,
250  pose::Pose const & pose,
251  kinematics::DomainMap const &, // domain_map,
252  ScoreFunction const & /*sfxn*/,
253  EnergyMap const & weights,
254  Vector & F1,
255  Vector & F2
256 ) const {
257  using namespace numeric::statistics;
258 
259  if (!pose_is_proper) return;
260  if (!pose.is_fullatom()) return;
261 
262  // derivative
263  int resid = id.rsd();
264  int atmid = id.atomno();
265 
266  // fn only defined for CA's
267  if ( pose.residue(resid).aa() != core::chemical::aa_vrt &&
268  ( !pose.residue(resid).is_protein() || pose.residue(resid).atom_name(atmid) != " CA ") ) return;
269 
273 
274  // if we're symmetric, but _not_ scoring the symmetric complex,
275  // we need to scale derivatives by the score
277  //////////////////////
278  // SYMMETRIC CASE
279  //////////////////////
281  (dynamic_cast<const core::conformation::symmetry::SymmetricConformation &>(pose.conformation()).Symmetry_Info());
282  core::Size nsubunits = symminfo->subunits();
283  core::Size nres_per = symminfo->num_independent_residues();
284  bool remapSymm = basic::options::option[ basic::options::OptionKeys::edensity::score_symm_complex ]();
285 
286  if ( pose.residue(resid).aa() == core::chemical::aa_vrt && remapSymm) {
287 
288  // derivative is only defined for the 'ORIG' atom in the virtual
289  if (atmid != 2) return;
290 
291  // if not a branch node, we're done
293  int nchildren = edges_i.size();
294  if (nchildren < 2) return;
295 
296  // odd case ... if this vrt is controlled by a cloned jump then we dont have to compute derivs
297  // for now we'll just check the parent, but perhaps we should trace root->here?
298  if ( !pose.fold_tree().is_root( resid ) ) {
299  core::kinematics::Edge edge_incoming = pose.fold_tree().get_residue_edge(resid);
300  if (! symminfo->jump_is_independent( edge_incoming.label() ) )
301  return;
302  }
303 
304  // if any child jumps are cloned such that the clone jump start is ALSO a branching vrt
305  // then we need to aggregate these as well
306  // TO DO: if a jump is _fixed_ we should move downstream to the next movable jump
307  // This isn't a problem with symm files generated by the perl script, however,
308  // it may be a problem in hand-coded ones
310  for (int j=1; j<=nchildren; ++j) {
311  int basejump = edges_i[j].label();
312  if (! symminfo->jump_is_independent( basejump ) )
313  basejump = symminfo->jump_follows( basejump );
314  utility::vector1< core::Size > jumpclones = symminfo->jump_clones( basejump );
315  for (int k=0; k<=(int)jumpclones.size(); ++k) {
316  core::Size upstream = pose.fold_tree().jump_edge( k==0 ? basejump : jumpclones[k] ).start();
317  edges_j = pose.fold_tree().get_outgoing_edges(upstream);
318  if (edges_j.size() > 1 && std::find( vrtclones.begin(), vrtclones.end(), upstream ) == vrtclones.end() ) {
319  vrtclones.push_back( upstream );
320  }
321  }
322  }
323 
324  // loop over all clones of this VRT
325  for (int i=1; i<=(int)vrtclones.size(); ++i) {
326  edges_i = pose.fold_tree().get_outgoing_edges(vrtclones[i]);
327 
328  // STEP 1: subtract children's contribution
329  for (int j=1; j<=nchildren; ++j) {
330  int downstream = edges_i[j].stop();
331  utility::vector1<int> mapping_j;
333  core::scoring::electron_density::getDensityMap().get_symmMap( downstream , mapping_j, R_j );
334 
335  for (int k=1; k<=(int)nsubunits; ++k) {
336  if (mapping_j[k] == 0) continue; // subunit k is not under child j
337 
338  // loop over all atms in reses in subunit k
339  for (int l=1, l_end=nres_per; l<=l_end; ++l) {
340  // there is a mapping from k->mapping_j[k]
341  int source_res = (k-1)*nres_per+l;
342  int target_res = (mapping_j[k]-1)*nres_per+l;
343 
344  if ( !pose.residue(source_res).is_protein() || pose.residue(source_res).atom_name(2)!=" CA " ) continue;
345 
346  numeric::xyzVector<core::Real> X_lm_src = pose.residue(source_res).atom(2).xyz();
347  numeric::xyzVector<core::Real> X_lm_tgt = pose.residue(target_res).atom(2).xyz();
348 
349  core::scoring::electron_density::getDensityMap().dCCdx_cen( source_res, X_lm_src, pose, dCCdx );
350  Real CC = structure_score;
351  Real z_CC = CC / 0.1;
352  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
353  numeric::xyzVector< core::Real > dEdx = 0.5 * ( 1.0 / p_null ) *
354  (-2.0/sqrt(M_PI)) *
355  exp(-SQ( z_CC/sqrt(2.0) )) *
356  1/sqrt(0.02) *
357  nreses * R_j * dCCdx / ((core::Real)nsubunits);
358 
359  numeric::xyzVector<core::Real> atom_x = X_lm_tgt;
360  numeric::xyzVector<core::Real> const f2( dEdx );
361  numeric::xyzVector<core::Real> atom_y = -f2 + atom_x;
362  Vector const f1( atom_x.cross( atom_y ) );
363 
364  F1 -= weights[ elec_dens_whole_structure_ca ] * f1;
365  F2 -= weights[ elec_dens_whole_structure_ca ] * f2;
366  }
367  }
368  }
369 
370  // STEP 2: add my contribution
371  utility::vector1<int> mapping_i;
373  core::scoring::electron_density::getDensityMap().get_symmMap( vrtclones[i] , mapping_i, R_i );
374  for (int k=1; k<=(int)nsubunits; ++k) {
375  if (mapping_i[k] == 0) continue; // subunit k is not under child j
376 
377  // loop over all atms in reses in subunit k
378  for (int l=1, l_end=nres_per; l<=l_end; ++l) {
379  // there is a mapping from k->mapping_i[k]
380  int source_res = (k-1)*nres_per+l;
381  int target_res = (mapping_i[k]-1)*nres_per+l;
382 
383  if ( !pose.residue(source_res).is_protein() || pose.residue(source_res).atom_name(2)!=" CA " ) continue;
384 
385  numeric::xyzVector<core::Real> X_lm_src = pose.residue(source_res).atom(2).xyz();
386  numeric::xyzVector<core::Real> X_lm_tgt = pose.residue(target_res).atom(2).xyz();
387 
388  core::scoring::electron_density::getDensityMap().dCCdx_cen( source_res, X_lm_src, pose, dCCdx );
389  Real CC = structure_score;
390  Real z_CC = CC / 0.1;
391  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
392  numeric::xyzVector< core::Real > dEdx = 0.5 * ( 1.0 / p_null ) *
393  (-2.0/sqrt(M_PI)) *
394  exp(-SQ( z_CC/sqrt(2.0) )) *
395  1/sqrt(0.02) *
396  nreses * R_i * dCCdx / ((core::Real)nsubunits);
397 
398  numeric::xyzVector<core::Real> atom_x = X_lm_tgt;
399  numeric::xyzVector<core::Real> const f2( dEdx );
400  numeric::xyzVector<core::Real> atom_y = -f2 + atom_x;
401  Vector const f1( atom_x.cross( atom_y ) );
402 
403  F1 += weights[ elec_dens_whole_structure_ca ] * f1;
404  F2 += weights[ elec_dens_whole_structure_ca ] * f2;
405  }
406  }
407  }
408  } else { // NON-VRT
409  if (! symminfo->bb_is_independent( resid ) ) return;
410 
411  utility::vector1< Size > myClones = symminfo->bb_clones(resid);
412  for (int i=0; i<=(int)myClones.size(); ++i) {
413  numeric::xyzVector<core::Real> X_i = (i==0) ? X : pose.xyz( id::AtomID( 2, myClones[i] ) );
414  core::scoring::electron_density::getDensityMap().dCCdx_cen( (i==0) ? resid : myClones[i], X_i, pose, dCCdx );
415 
416  // get R
417  if (remapSymm)
418  core::scoring::electron_density::getDensityMap().get_R( symminfo->subunit_index( (i==0) ? resid : myClones[i] ), R );
419 
420  Real CC = structure_score;
421  Real z_CC = CC / 0.1;
422  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
423 
424  // divide by the number of subunits since rosetta will scale up later (??)
425  numeric::xyzVector< core::Real > dEdx = 0.5 * ( 1.0 / p_null ) *
426  (-2.0/sqrt(M_PI)) *
427  exp(-SQ( z_CC/sqrt(2.0) )) *
428  1/sqrt(0.02) *
429  nreses * R * dCCdx / ((core::Real)nsubunits);
430 
431  numeric::xyzVector<core::Real> atom_x = X; //X_i;
432  numeric::xyzVector<core::Real> const f2( dEdx );
433  numeric::xyzVector<core::Real> atom_y = -f2 + atom_x;
434  Vector const f1( atom_x.cross( atom_y ) );
435 
436  F1 += weights[ elec_dens_whole_structure_ca ] * f1;
437  F2 += weights[ elec_dens_whole_structure_ca ] * f2;
438  }
439  }
440  } else {
441  //////////////////////
442  // ASYMMETRIC CASE
443  //////////////////////
444 
445  // the derivative of edens _score_ as a function of dCC/dx
446  Real CC = structure_score;
447  Real z_CC = CC / 0.1;
448  Real p_null = 0.5 * errfc( z_CC/sqrt(2.0) );
449 
451 
452  // divide by the number of subunits since rosetta will scale up later (??)
453  numeric::xyzVector< core::Real > dEdx = ( 1.0 / p_null ) *
454  0.5 *
455  (-2.0/sqrt(M_PI)) *
456  exp(-SQ( z_CC/sqrt(2.0) )) *
457  1/sqrt(0.02) *
458  nreses *
459  dCCdx;
460 
462  numeric::xyzVector<core::Real> const f2( dEdx );
463  numeric::xyzVector<core::Real> atom_y = -f2 + atom_x; // a "fake" atom in the direcion of the gradient
464  Vector const f1( atom_x.cross( atom_y ) );
465 
466  F1 += weights[ elec_dens_whole_structure_ca ] * f1;
467  F2 += weights[ elec_dens_whole_structure_ca ] * f2;
468  }
469 }
472 {
473  return 1; // Initial versioning
474 }
475 
476 }
477 }
478 }