Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sym_atom_tree_minimize.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/optimization/atom_tree_minimize.hh
10 /// @brief Atom tree minimization functions
11 /// @author Ingemar Andre
12 
13 // Unit headers
15 
16 // Package headers
21 
22 // Symmetry headers
25 
27 
28 // Project headers
29 #include <core/pose/Pose.hh>
35 // AUTO-REMOVED #include <core/scoring/NeighborList.hh>
36 // AUTO-REMOVED #include <core/scoring/hbonds/hbonds.hh>
37 // AUTO-REMOVED #include <core/scoring/hbonds/HBondSet.hh>
38 
39 // // ObjexxFCL headers
40 #include <ObjexxFCL/FArray2D.hh>
41 #include <ObjexxFCL/format.hh>
42 
43 // // Numeric headers
44 #include <numeric/constants.hh>
45 #include <numeric/conversions.hh>
46 
47 // AUTO-REMOVED #include <basic/prof.hh>
48 #include <basic/Tracer.hh>
49 
52 #include <utility/vector1.hh>
53 
54 //Auto Headers
57 
58 
59 
60 using basic::T;
61 using basic::Error;
62 using basic::Warning;
63 
64 using namespace ObjexxFCL::fmt;
65 
66 namespace core {
67 namespace optimization {
68 namespace symmetry {
69 
70 static basic::Tracer TR("core.optimization.symmetry");
71 
73 
74 
75 /////////////////////////////////////////////////////////////////////////////
76 /// @detailed
77 ///car note that this calculates the deriv for all torsion angles even
78 ///car those that are fixed. Because of the way that the derivative is
79 ///car calculated, I don't believe this is a significant slow down (ie
80 ///car have to run over all the atom pairs twice, regardless of the number
81 ///car of torsion angles)
82 ///
83 ///car multiple neighborlists:
84 ///car cendist centroid distances in current structure, cutoff for vdw
85 ///car dis2_tether centroid distances in tether structure, cutoff for tether
86 ///
87 ///db computes the derivative of E with respect to each
88 ///db of the torsion angles. Using the chain rule, we have
89 ///db
90 ///db dE/d phi = dE/dr * dr/dphi
91 ///db
92 ///db dr/dphi = Eab x (V-Vb) . (V' - V)/|V-V'|
93 ///db
94 ///db (the first cross product is the displacement of V upon a rotation dphi
95 ///db around the unit vector Eab, Vb is the coordinates of the second atom in
96 ///db the bond)
97 ///db
98 ///car dE/dR = 2r (for vdw at least)
99 ///db since | V-V'| = r,
100 ///db
101 ///db dE/ dphi = 2 Eab x (V-Vb) . (V' - V)
102 ///db
103 ///db note that Eab and Vb are different for each torsion angle, but V'
104 ///db and V are the same. rearranging:
105 ///db
106 ///db = - 2 Eab X Vb . (V' - V) - 2 Eab . (V' x V).
107 ///db
108 ///db now we need the averages over all Vi of the difference and the
109 ///db crossproduct of V and V'.
110 ///
111 ///car below, Eab x Vb is 'vec'
112 ///car Eab is 'unit'
113 ///car (V'-V) is 'f2'
114 ///car 'F2tot' = f2*dE_dR (cumulative)
115 ///car (V' X V) is 'f1' ('F1_xxxE' is cumulative for potential xxx)
116 ///car eval_dE_dR actually returns dE_dR/r
117 ///
118 ///car if two atoms are fixed relatively in cartesian space, then dr/dphi = 0
119 ///car and there is no contribution to the derivative
120 ///
121 
122 void
124  pose::Pose & pose,
125  SymMinimizerMap & symm_min_map,
126  /*MinimizerMap & semisymm_min_map,
127  MinimizerMap & asymm_min_map,*/
128  scoring::ScoreFunction const & scorefxn,
129  Multivec const & vars,
130  Multivec & dE_dvars
131 )
132 {
133  using namespace conformation::symmetry;
134  // Initialize symmetry
135  assert (pose::symmetry::is_symmetric( pose ) );
136  SymmetricConformation & symm_conf (
137  dynamic_cast<SymmetricConformation &> ( pose.conformation()) );
138  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
139 
140  //Real const deg2rad( numeric::conversions::radians(1.0) );
141 
142  dE_dvars.resize( symm_min_map.nangles() );
143 
144  // clear all the F1's and F2's
145  symm_min_map.zero_torsion_vectors();
146 
147 
148  // puts the degrees of freedom from vars into pose
149  symm_min_map.copy_dofs_to_pose( pose, vars );
150 
151 
152  /////////////////////////////////////////////////////////////////////////////
153  // do some pre-computation prior to looping over the torsions
154 
155  // this will stash necessary information in the pose's energies object
156  //
157  scorefxn.setup_for_derivatives( pose );
158 
159  /////////////////////////////////////////////////////////////////////////////
160  // get derivative of all atom pair potentials
161  // this includes fa_pair and hbonds
162  //
163  // this call fills the F1's and F2's with contributions from their
164  // immediately downstream atoms
165  atom_tree_get_atompairE_deriv( pose, symm_min_map, scorefxn );
166 
167 
168  /////////////////////////////////////////////////////////////////////////////
169  // this should only be done once, after all torsion F1,F2's have
170  // been filled in
171  //
172  // this sums all the F1,F2 contributions down the tree from leaves to root
173  symm_min_map.link_torsion_vectors();
174 
175 
176  /////////////////////////////////////////////////////////////////////////////
177  // now loop over the torsions in the map
178  int imap( 1 ); // for indexing into de_dvars( imap )
179  for ( SymMinimizerMap::const_iterator it=symm_min_map.begin(), ite=symm_min_map.end();
180  it != ite; ++it, ++imap ) {
181 
182  DOF_Node const & dof_node( **it );
183  kinematics::tree::Atom const & atom( pose.atom_tree().atom( dof_node.atom_id() ) );
184  /////////////////////////////////////////////////////////////////
185  // derivatives of this particular degree of freedom
186  //
187  // eg rama,Paa,dunbrack,and torsional constraints
188  Real sfxn_dof_deriv = scorefxn.eval_dof_derivative( dof_node.dof_id(), dof_node.torsion_id(), pose );
189  Real scale = symm_min_map.torsion_scale_factor( dof_node ) / symm_info->score_multiply_factor();
190 
191  dE_dvars[ imap ] = torsional_derivative_from_cartesian_derivatives( atom, dof_node, sfxn_dof_deriv, scale );
192 
193  } // loop over map
194 
195 
196  scorefxn.finalize_after_derivatives( pose );
197 }
198 
199 
200 ///////////////////////////////////////////////////////////////////////////////
201 
202 void
204  pose::Pose & pose,
205  SymMinimizerMap & symm_min_map,
206  //MinimizerMap & semisymm_min_map,
207  //MinimizerMap & asymm_min_map,
208  scoring::ScoreFunction const & scorefxn
209 )
210 {
211  using namespace conformation::symmetry;
212  using namespace scoring;
213  using namespace scoring::symmetry;
214 
215  SymmetricConformation const & symm_conf (
216  dynamic_cast<SymmetricConformation const &> ( pose.conformation()) );
217  assert( conformation::symmetry::is_symmetric( symm_conf ) );
218  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
219 
220 
221  SymmetricEnergies const & symm_energies( dynamic_cast< SymmetricEnergies const & > (pose.energies()) );
222 
223  assert( symm_energies.minimization_graph() );
224  assert( symm_energies.derivative_graph() );
225 
226  MinimizationGraphCOP mingraph = symm_energies.minimization_graph();
227  MinimizationGraphCOP dmingraph = symm_energies.derivative_graph();
228 
229  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
230  MinimizationNode const & minnode = * mingraph->get_minimization_node( ii );
231  /// 1. eval intra-residue derivatives
232  eval_atom_derivatives_for_minnode( minnode, pose.residue( ii ), pose, scorefxn.weights(), symm_min_map.atom_derivatives( ii ) );
233  }
234 
235  /// 2a. eval inter-residue derivatives from the regular minimization graph
237  edgeit = mingraph->const_edge_list_begin(), edgeit_end = mingraph->const_edge_list_end();
238  edgeit != edgeit_end; ++edgeit ) {
239  MinimizationEdge const & minedge = static_cast< MinimizationEdge const & > ( (**edgeit) );
240  Size const rsd1ind = minedge.get_first_node_ind();
241  Size const rsd2ind = minedge.get_second_node_ind();
242  conformation::Residue const & rsd1( pose.residue( rsd1ind ));
243  conformation::Residue const & rsd2( pose.residue( rsd2ind ));
244  ResSingleMinimizationData const & r1_min_data( mingraph->get_minimization_node( rsd1ind )->res_min_data() );
245  ResSingleMinimizationData const & r2_min_data( mingraph->get_minimization_node( rsd2ind )->res_min_data() );
246 
247  eval_atom_derivatives_for_minedge( minedge, rsd1, rsd2,
248  r1_min_data, r2_min_data, pose, scorefxn.weights(),
249  symm_min_map.atom_derivatives( rsd1ind ), symm_min_map.atom_derivatives( rsd2ind ));
250  }
251 
252  /// 2b. eval inter-residue derivatives from derivative minimization graph
254  edgeit = dmingraph->const_edge_list_begin(), edgeit_end = dmingraph->const_edge_list_end();
255  edgeit != edgeit_end; ++edgeit ) {
256  MinimizationEdge const & minedge = static_cast< MinimizationEdge const & > ( (**edgeit) );
257  Size const rsd1ind = minedge.get_first_node_ind();
258  Size const rsd2ind = minedge.get_second_node_ind();
259  conformation::Residue const & rsd1( pose.residue( rsd1ind ));
260  conformation::Residue const & rsd2( pose.residue( rsd2ind ));
261  ResSingleMinimizationData const & r1_min_data( dmingraph->get_minimization_node( rsd1ind )->res_min_data() );
262  ResSingleMinimizationData const & r2_min_data( dmingraph->get_minimization_node( rsd2ind )->res_min_data() );
263 
264  eval_atom_derivatives_for_minedge( minedge, rsd1, rsd2,
265  r1_min_data, r2_min_data, pose, scorefxn.weights(),
266  symm_min_map.atom_derivatives( rsd1ind ), symm_min_map.atom_derivatives( rsd2ind ));
267  }
268 
269 
270  //std::cerr << pose.fold_tree();
271 
272  // Loop over all dofs in the symmetric movemap
273  // use atom lists from the semisymmetric movemap
274  //
275  for ( MinimizerMap::const_iterator iter = symm_min_map.begin(), iter_e = symm_min_map.end();
276  iter != iter_e; ++iter ) {
277  DOF_Node & dof_node( **iter );
278 
279  core::Real dof_wt_i = symm_info->get_dof_derivative_weight( dof_node.dof_id(), symm_conf );
280  // if( dof_wt_i == 0 ) continue;
281  //std::cout << " dof_node: " << dof_node.rsd() << " " << dof_node.atomno() << " " << dof_node.type() << " " << dof_wt_i << std::endl;
282 
283  Vector f1(0,0,0), f2(0,0,0);
284  // loop through atoms first moved by this torsion
285  for ( DOF_Node::AtomIDs::const_iterator it1=dof_node.atoms().begin(),
286  it1e = dof_node.atoms().end(); it1 != it1e; ++it1 ) {
287  id::AtomID const & atom_id( *it1 );
288 
289  /// Most of the derivative evaluation has already taken place by the time we get here.
290  dof_node.F1() += symm_min_map.atom_derivatives( atom_id.rsd() )[ atom_id.atomno() ].f1();
291  dof_node.F2() += symm_min_map.atom_derivatives( atom_id.rsd() )[ atom_id.atomno() ].f2();
292 
293  scorefxn.eval_npd_atom_derivative( atom_id, pose, symm_min_map.domain_map(), dof_node.F1(), dof_node.F2() );
294 
295  } // atom1
296 
297  //std::cout << " ... summing " << dof_node.atom_id() << " with weight " << dof_wt_i << std::endl;
298  //std::cout << " " << f1.x() << " " << f1.y() << " " << f1.z() << " " << f2.x() << " " << f2.y() << " " << f2.z() << std::endl;
299 
300  dof_node.F1() += dof_wt_i * f1;
301  dof_node.F2() += dof_wt_i * f2;
302  }
303  for ( MinimizerMap::const_iterator iter = symm_min_map.dependent_begin(), iter_e = symm_min_map.dependent_end();
304  iter != iter_e; ++iter ) {
305  DOF_Node & dof_node( **iter );
306 
307  core::Real dof_wt_i = symm_info->get_dof_derivative_weight( dof_node.dof_id(), symm_conf );
308  // if( dof_wt_i == 0 ) continue;
309  //std::cout << " dof_node: " << dof_node.rsd() << " " << dof_node.atomno() << " " << dof_node.type() << " " << dof_wt_i << std::endl;
310 
311  Vector f1(0,0,0), f2(0,0,0);
312  // loop through atoms first moved by this torsion
313  for ( DOF_Node::AtomIDs::const_iterator it1=dof_node.atoms().begin(),
314  it1e = dof_node.atoms().end(); it1 != it1e; ++it1 ) {
315  id::AtomID const & atom_id( *it1 );
316 
317  /// Most of the derivative evaluation has already taken place by the time we get here.
318  f1 += symm_min_map.atom_derivatives( atom_id.rsd() )[ atom_id.atomno() ].f1();
319  f2 += symm_min_map.atom_derivatives( atom_id.rsd() )[ atom_id.atomno() ].f2();
320 
321  scorefxn.eval_npd_atom_derivative( atom_id, pose, symm_min_map.domain_map(), f1, f2 );
322 
323  } // atom1
324 
325  Size this_jump = pose.fold_tree().get_jump_that_builds_residue( dof_node.dof_id().rsd() );
326  Size master_jump = symm_info->jump_follows( this_jump );
327  DOF_ID symm_dof_id(
328  id::AtomID( dof_node.atomno(), pose.fold_tree().downstream_jump_residue( master_jump ) ), dof_node.type() );
329  // get the equiv node in the symm min map
330  DOF_NodeOP symm_dof_node = symm_min_map.dof_node_from_id( symm_dof_id );
331 
332  //std::cout << " ... summing " << dof_node.atom_id() << " at dof node " << symm_dof_node->atom_id() << " with weight " << dof_wt_i << std::endl;
333  //std::cout << " ... summing " << dof_node.atom_id() << " at dof node " << symm_dof_node->atom_id() << " with weight " << dof_wt_i << std::endl;
334  //std::cout << " " << f1.x() << " " << f1.y() << " " << f1.z() << " " << f2.x() << " " << f2.y() << " " << f2.z() << std::endl;
335 
336  // add f1 f2 using dof deriv wt
337  symm_dof_node->F1() += dof_wt_i * f1;
338  symm_dof_node->F2() += dof_wt_i * f2;
339 
340  } // tor
341 }
342 
343 ///////////////////////////////////////////////////////////////////////////////
344 // temporary!
345 class MinDebug {
346 public:
347  MinDebug( Size const nangles ):
348  abs_deriv_dev( nangles ),
349  rel_deriv_dev( nangles )
350  {}
351 
354 
359 };
360 
361 ///////////////////////////////////////////////////////////////////////////////
362 
363 void
365  SymMinimizerMap const & min_map,
366  Multifunc const & func,
367  Multivec const & start_vars,
368  Multivec const & dE_dvars,
369  bool const verbose // = true
370 )
371 {
372  /////////////////////////////////////////////////////////////////////////////
373  // NUMERICAL DERIVATIVE CHECK
374  /////////////////////////////////////////////////////////////////////////////
375  // how to analyze this:
376  //
377  // in gnuplot, look at numerical vs analytical derivs:
378  // plot '< grep "^ratio" a3.log ' u 10:11,x
379  //
380  // also sort by deriv_dev lines:
381  //
382  // by magnitude of deviation
383  // grep deriv_dev a3.log | sort -g +8
384  //
385  // or by ratio of deviation to actual
386  //
387  // grep deriv_dev a3.log | sort -g +9
388 
389  Size const nangles( min_map.nangles() );
390 
391 
392  Real const increment = 0.0005; // PB -- 3/02
393  Size const n_increment = 5;
394  utility::vector1< Multivec > dE_dvars_numeric( n_increment );
395  for ( Size i=1; i<= n_increment; ++i ) {
396  dE_dvars_numeric[i].resize( nangles, 0.0 );
397  }
398  //FArray2D_Real dE_dvars_numeric( nangles, n_increment );
399 
400  // setup for saving diagnostics
401  MinDebug min_debug( nangles );
402 
403 // min_debug.nangles = nangles;
404 // if ( nangles > int( min_debug.abs_deriv_dev.size1() ) ) {
405 // min_debug.abs_deriv_dev.dimension( nangles );
406 // min_debug.rel_deriv_dev.dimension( nangles );
407 // }
408 
409  Multivec vars( start_vars );
410 
411  Real const f00 = func( vars );
412  Size ii( 1 ); // for indexing into dE_dvars[ ii ]
413 
414  for ( MinimizerMap::const_iterator iter= min_map.begin(),
415  iter_end= min_map.end(); iter != iter_end; ++iter, ++ii ) {
416  DOF_Node const & dof_node( **iter );
417 
418  Real deriv_dev = 10000.0;
419  for ( Size j = 1,factor=1; j <= n_increment; ++j ) {
420  factor*=2;
421 
422  vars[ii] = start_vars[ii] + factor * increment;
423  Real const f11 = func( vars );
424 
425  vars[ii] = start_vars[ii] - factor * increment;
426  Real const f22 = func( vars );
427 
428  Real const deriv = ( f11 - f22 ) / ( factor * 2 * increment );
429 
430  dE_dvars_numeric[j][ii] = deriv;
431 
432  deriv_dev = std::min( deriv_dev, std::abs( deriv - dE_dvars[ii] ) );
433 
434  vars[ii] = start_vars[ii];
435 
436  Real const ratio( std::abs( dE_dvars[ii] ) < 0.001 ? 0.0 :
437  deriv / dE_dvars[ii] );
438 
439  if ( verbose &&
440  ( std::abs(dE_dvars[ii]) > 0.001 || std::abs(deriv) > 0.001 ) ) {
441  // if you change this output, please also change the comments
442  // at the beginning of this section
443  static bool ratio_header_output( false );
444  if ( !ratio_header_output ) {
445  ratio_header_output = true;
446  TR << "ratio" <<
447  A( 4, "inc" ) <<
448  A( 4, "rsd" ) <<
449  A( 4, "typ" ) <<
450  A( 4, "atm" ) <<
451  A( 5, "prsd" ) <<
452  A( 5, "ptyp" ) <<
453  A( 5, "patm" ) <<
454  A( 5, "natm" ) <<
455  A( 10, "numeric" ) <<
456  A( 10, "analytic" ) <<
457  A( 10, "ratio" ) <<
458  A( 10, "f11" ) <<
459  A( 10, "f00" ) <<
460  A( 10, "f22" ) <<
461  A( 10, "vars[ii]" ) << std::endl;
462  }
463 
464  id::DOF_ID parent_id( id::BOGUS_DOF_ID );
465  if ( dof_node.parent() ) {
466  parent_id = dof_node.parent()->dof_id();
467  }
468 
469  TR << "ratio" <<
470  I( 4, j ) <<
471  I( 4, dof_node.rsd() ) <<
472  I( 4, dof_node.type() ) <<
473  I( 4, dof_node.atomno() ) <<
474  I( 5, parent_id.rsd() ) <<
475  I( 5, parent_id.type() ) <<
476  I( 5, parent_id.atomno() ) <<
477  I( 5, dof_node.atoms().size()) <<
478  F( 10, 4, deriv ) <<
479  F( 10, 4, dE_dvars[ii] ) <<
480  F( 10, 4, ratio ) <<
481  F( 10, 4, f11 ) <<
482  F( 10, 4, f00 ) <<
483  F( 10, 4, f22 ) <<
484  F( 10, 4, start_vars[ii] ) << std::endl;
485  }
486  }
487  if ( true ) {
488 
489  Real const ratio( std::abs( dE_dvars[ii] ) < 0.001 ? 0.0 :
490  deriv_dev / std::abs( dE_dvars[ii] ) );
491 
492  min_debug.rel_deriv_dev[ ii ] = ratio;
493  min_debug.abs_deriv_dev[ ii ] = deriv_dev;
494 
495  if ( verbose ) {
496  // if you change this output, please also change the comments
497  // at the beginning of this section
498  TR << "deriv_dev:" << SS(ii) << SS(nangles) << SS(f00) <<
499  SS( dof_node.type() ) << SS( dof_node.atomno() ) <<
500  SS( dof_node.rsd() ) <<
501  SS( dE_dvars[ii] ) << SS( deriv_dev ) << SS(ratio) << std::endl;
502  }
503  }
504  }
505 
506  // calculate magnitudes, dot products of gradient vectors
507  utility::vector1< Real > norm_numeric(n_increment,0.0), dot(n_increment,0.0);
508  Real norm(0.0);
509  for ( Size i=1; i<= nangles; ++i ) {
510  norm += dE_dvars[i] * dE_dvars[i];
511  for ( Size j=1; j<= n_increment; ++j ) {
512  dot[j] += dE_dvars[i] * dE_dvars_numeric[j][i];
513  norm_numeric[j] += dE_dvars_numeric[j][i] * dE_dvars_numeric[j][i];
514  }
515  }
516  norm = std::sqrt( norm );
517 
518  min_debug.best_cos_theta = -10.0;
519  min_debug.best_abs_log_norm_ratio = 200.0;
520  min_debug.best_norm_analytic = 999.9;
521  min_debug.best_norm_numeric = 999.9;
522 
523  for ( Size j=1; j<= n_increment; ++j ) {
524  norm_numeric[j] = std::sqrt( norm_numeric[j] );
525 
526  // handle strange cases
527  Real log_norm_ratio;
528  if ( norm < 0.001 && norm_numeric[j] < 0.001 ) {
529  log_norm_ratio = 1.0;
530  } else if ( norm < 0.001 ) {
531  log_norm_ratio = 100.0;
532  } else if ( norm_numeric[j] < 0.001 ) {
533  log_norm_ratio = -100.0;
534  } else {
535  log_norm_ratio = std::log( norm_numeric[j] / norm );
536  }
537 
538  Real const cos_theta( dot[j] / ( norm * norm_numeric[j]) );
539 
540  TR <<
541  " norm: " << j << ' ' << F(12,4,norm) <<
542  " norm_numeric: " << F(12,4,norm_numeric[j]) <<
543  " cos_theta: " << F(7,4,cos_theta) <<
544  " log_norm_ratio: " << F(9,4,log_norm_ratio) << std::endl;
545 
546  min_debug.best_cos_theta = std::max( min_debug.best_cos_theta,
547  cos_theta );
548  if ( std::abs( log_norm_ratio ) < min_debug.best_abs_log_norm_ratio ) {
549  min_debug.best_abs_log_norm_ratio = std::abs( log_norm_ratio );
550  min_debug.best_norm_analytic = norm;
551  min_debug.best_norm_numeric = norm_numeric[j];
552  }
553  }
554 }
555 
556 } // namespace symmetry
557 } // namespace optimization
558 } // namespace core
559 // { // dont want to modify the pose if we can avoid it
560 // Size const nangles( min_map.nangles() );
561 // Multivec tmp_vars( nangles );
562 // min_map.copy_dofs_from_pose( pose, tmp_vars );
563 // Real dev(0.0);
564 // for ( Size i=1; i<= nangles; ++i ) {
565 // dev += std::abs( tmp_vars[i] - vars[i] );
566 // }
567 // std::cout << "[ DEBUG ] vars dev in atom_tree_dfunc: " << dev << std::endl;
568 // if ( dev > 1e-2 ) {
569 // min_map.copy_dofs_to_pose( pose, vars );
570 // scorefxn( pose );
571 // }
572 // }