Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cartesian_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 // (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 core/optimization/cartesian_minimize.cc
11 /// @brief Atom tree minimization functions
12 /// @author Frank DiMaio
13 
14 
15 // Unit headers
17 
19 // AUTO-REMOVED #include <core/conformation/symmetry/util.hh>
23 
24 // Package headers
28 
29 // Project headers
30 // AUTO-REMOVED #include <core/kinematics/AtomTree.hh>
31 #include <core/pose/Pose.hh>
35 #include <core/scoring/Energies.hh>
39 
40 #include <ObjexxFCL/format.hh>
41 
42 // // Numeric headers
43 #include <numeric/constants.hh>
44 #include <numeric/conversions.hh>
45 
46 #include <basic/Tracer.hh>
47 
49 #include <utility/vector1.hh>
50 
51 using basic::T;
52 using basic::Error;
53 using basic::Warning;
54 
55 using namespace ObjexxFCL::fmt;
56 
57 namespace core {
58 namespace optimization {
59 
60 static basic::Tracer TR("core.optimization");
61 
62 /////////////////////////////////////////////////////////////////////////////
63 /// @detailed
64 ///
65 
66 void
68  pose::Pose & pose,
69  CartesianMinimizerMap & min_map,
70  scoring::ScoreFunction const & scorefxn,
71  Multivec const & vars,
72  Multivec & dE_dvars
73 ) {
74  dE_dvars.resize( min_map.ndofs() );
75 
76  // clear stored F1's and F2's
77  min_map.zero_stored_derivs();
78 
79  // puts the degrees of freedom from vars into pose
80  min_map.copy_dofs_to_pose( pose, vars );
81 
82  // do some pre-computation prior to looping over the torsions
83  // this will stash necessary information in the pose's energies object
84  scorefxn.setup_for_derivatives( pose );
85 
86  //fpd scale derivatives for symmetry
87  core::Real scale = 1;
88  if (pose::symmetry::is_symmetric( pose ) ) {
89  using namespace conformation::symmetry;
90  SymmetricConformation & symm_conf ( dynamic_cast<SymmetricConformation &> ( pose.conformation()) );
91  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
92  scale = symm_info->score_multiply_factor();
93  }
94 
95  // get derivative of all atom pair potentials
96  // this includes fa_pair and hbonds
97  //
98  // this call fills the F1's and F2's with contributions from their
99  // immediately downstream atoms
100  cartesian_collect_atompairE_deriv( pose, min_map, scorefxn, dE_dvars, scale );
101 
102  // now loop over the torsions in the map
103  Size ntorsions=min_map.ntorsions();
104  cartesian_collect_torsional_deriv( pose, min_map, scorefxn, dE_dvars, scale );
105 
106  scorefxn.finalize_after_derivatives( pose );
107 }
108 
109 ///////////////////////////////////////////////////////////////////////////////
110 void
112  pose::Pose & pose,
113  CartesianMinimizerMap & min_map,
114  scoring::ScoreFunction const & scorefxn,
115  Multivec & dE_dvars,
116  core::Real scale
117 ) {
118  using namespace scoring;
119  using namespace scoring::symmetry;
120  using namespace conformation::symmetry;
121 
122  assert( pose.energies().minimization_graph() );
124 
125  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
126  MinimizationNode const & minnode = * mingraph->get_minimization_node( ii );
127  /// 1. eval intra-residue derivatives
128  eval_atom_derivatives_for_minnode( minnode, pose.residue( ii ), pose, scorefxn.weights(), min_map.atom_derivatives( ii ) );
129  }
130 
131  /// 2. eval inter-residue derivatives
133  edgeit = mingraph->const_edge_list_begin(), edgeit_end = mingraph->const_edge_list_end();
134  edgeit != edgeit_end; ++edgeit ) {
135  MinimizationEdge const & minedge = static_cast< MinimizationEdge const & > ( (**edgeit) );
136  Size const rsd1ind = minedge.get_first_node_ind();
137  Size const rsd2ind = minedge.get_second_node_ind();
138  conformation::Residue const & rsd1( pose.residue( rsd1ind ));
139  conformation::Residue const & rsd2( pose.residue( rsd2ind ));
140  ResSingleMinimizationData const & r1_min_data( mingraph->get_minimization_node( rsd1ind )->res_min_data() );
141  ResSingleMinimizationData const & r2_min_data( mingraph->get_minimization_node( rsd2ind )->res_min_data() );
142 
143  eval_atom_derivatives_for_minedge( minedge, rsd1, rsd2,
144  r1_min_data, r2_min_data, pose, scorefxn.weights(),
145  min_map.atom_derivatives( rsd1ind ), min_map.atom_derivatives( rsd2ind ));
146  }
147 
148  // if we're symmetric loop over other edges
149  if (pose::symmetry::is_symmetric( pose ) ) {
150  SymmetricEnergies const & symm_energies( dynamic_cast< SymmetricEnergies const & > (pose.energies()) );
151  MinimizationGraphCOP dmingraph = symm_energies.derivative_graph();
152 
153  /// 2b. eval inter-residue derivatives from derivative minimization graph
155  edgeit = dmingraph->const_edge_list_begin(), edgeit_end = dmingraph->const_edge_list_end();
156  edgeit != edgeit_end; ++edgeit ) {
157  MinimizationEdge const & minedge = static_cast< MinimizationEdge const & > ( (**edgeit) );
158  Size const rsd1ind = minedge.get_first_node_ind();
159  Size const rsd2ind = minedge.get_second_node_ind();
160  conformation::Residue const & rsd1( pose.residue( rsd1ind ));
161  conformation::Residue const & rsd2( pose.residue( rsd2ind ));
162  ResSingleMinimizationData const & r1_min_data( dmingraph->get_minimization_node( rsd1ind )->res_min_data() );
163  ResSingleMinimizationData const & r2_min_data( dmingraph->get_minimization_node( rsd2ind )->res_min_data() );
164 
165  eval_atom_derivatives_for_minedge( minedge, rsd1, rsd2,
166  r1_min_data, r2_min_data, pose, scorefxn.weights(),
167  min_map.atom_derivatives( rsd1ind ), min_map.atom_derivatives( rsd2ind ));
168  }
169  }
170 
171  Size natoms=min_map.natoms();
172  for ( Size i=1; i<=natoms; ++i) {
173  id::AtomID const & atom_id( min_map.get_atom(i) );
174  core::Vector F1(0,0,0),F2(0,0,0);
175  scorefxn.eval_npd_atom_derivative( atom_id, pose, min_map.domain_map(), F1, F2 );
176  //F1 += min_map.atom_derivatives( atom_id.rsd() )[ atom_id.atomno() ].f1();
177  F2 += min_map.atom_derivatives( atom_id.rsd() )[ atom_id.atomno() ].f2();
178  dE_dvars[3*i-2] = F2[0]*scale;
179  dE_dvars[3*i-1] = F2[1]*scale;
180  dE_dvars[3*i ] = F2[2]*scale;
181  }
182 }
183 
184 ///////////////////////////////////////////////////////////////////////////////
186  pose::Pose & pose,
187  CartesianMinimizerMap & min_map,
188  core::scoring::ScoreFunction const & scorefxn,
189  Multivec & dE_dvars,
190  core::Real scale
191 )
192 {
193  using namespace core;
194  using namespace core::optimization;
195  using namespace id;
196 
197  // loop over the torsions
198  Size ntorsions=min_map.ntorsions();
199  for ( Size i=1; i<=ntorsions; ++i) {
200  id::DOF_ID const & dof_id( min_map.get_dof_id(i) );
201  id::TorsionID const & TorsionID( min_map.get_TorsionID(i) );
202 
203  Real deriv = 0.0;
204 
205  // eg rama,Paa,dunbrack,and torsional constraints
206  deriv = scorefxn.eval_dof_derivative( dof_id, TorsionID, pose );
207 
208  if( deriv == 0 ) continue;
209 
210  // work out which atoms are involved !
211  AtomID id1, id2, id3, id4;
212  pose.conformation().get_torsion_angle_atom_ids( TorsionID, id1,id2,id3,id4 );
213 
214  VectorQuad coords( pose.xyz(id1) , pose.xyz(id2) , pose.xyz(id3) , pose.xyz(id4) );
215  VectorQuad grads;
216 
217  tors_deriv_to_cartesian( deriv, coords, grads );
218 
219  core::Size atmidx1 = min_map.get_atom_index(id1);
220  core::Size atmidx2 = min_map.get_atom_index(id2);
221  core::Size atmidx3 = min_map.get_atom_index(id3);
222  core::Size atmidx4 = min_map.get_atom_index(id4);
223 
224  if (atmidx1>0) {
225  dE_dvars[3*atmidx1-2] += scale*(grads.get<0>().x());
226  dE_dvars[3*atmidx1-1] += scale*(grads.get<0>().y());
227  dE_dvars[3*atmidx1 ] += scale*(grads.get<0>().z());
228  }
229  if (atmidx2>0) {
230  dE_dvars[3*atmidx2-2] += scale*(grads.get<1>().x());
231  dE_dvars[3*atmidx2-1] += scale*(grads.get<1>().y());
232  dE_dvars[3*atmidx2 ] += scale*(grads.get<1>().z());
233  }
234  if (atmidx3>0) {
235  dE_dvars[3*atmidx3-2] += scale*(grads.get<2>().x());
236  dE_dvars[3*atmidx3-1] += scale*(grads.get<2>().y());
237  dE_dvars[3*atmidx3 ] += scale*(grads.get<2>().z());
238  }
239  if (atmidx4>0) {
240  dE_dvars[3*atmidx4-2] += scale*(grads.get<3>().x());
241  dE_dvars[3*atmidx4-1] += scale*(grads.get<3>().y());
242  dE_dvars[3*atmidx4 ] += scale*(grads.get<3>().z());
243  }
244 
245  } // loop over torsions
246 }
247 
248 
249 ///////////////////////////////////////////////////////////////////////////////
250 
251 void
253  CartesianMinimizerMap const & min_map,
254  CartesianMultifunc const & func,
255  Multivec const & start_vars,
256  Multivec const & dE_dvars,
257  NumericalDerivCheckResultOP deriv_check_result,
258  bool const verbose // = true
259 )
260 {
261  /////////////////////////////////////////////////////////////////////////////
262  // NUMERICAL DERIVATIVE CHECK
263  /////////////////////////////////////////////////////////////////////////////
264 
265  Size const ndofs( min_map.ndofs() );
266 
267  bool const write_to_stdout( ! deriv_check_result || deriv_check_result->send_to_stdout() );
268 
269  Real const increment = 0.0005; //fpd
270  Size const n_increment = 1;
271  utility::vector1< Multivec > dE_dvars_numeric( n_increment );
272  for ( Size i=1; i<= n_increment; ++i ) {
273  dE_dvars_numeric[i].resize( ndofs, 0.0 );
274  }
275 
276  // setup for saving diagnostics
277  NumDerivCheckDataOP min_debug;
278  if ( deriv_check_result ) min_debug = new NumDerivCheckData( ndofs, n_increment );
279 
280  Multivec vars( start_vars );
281 
282  //Real const f00 = func( vars );
283 
284  Size natoms=min_map.natoms();
285  for ( Size i=1; i<=natoms; ++i) {
286  id::AtomID const & atm_id( min_map.get_atom(i) );
287  for ( int jj=0; jj<3; ++jj) {
288  Size ii = (i-1)*3+jj+1;
289 
290  Real deriv_dev = 10000.0;
291  for ( Size j = 1,factor=1; j <= n_increment; ++j ) {
292  factor*=2;
293 
294  vars[ii] = start_vars[ii] + factor * increment;
295  Real const f11 = func( vars );
296 
297  vars[ii] = start_vars[ii] - factor * increment;
298  Real const f22 = func( vars );
299 
300  Real const deriv = ( f11 - f22 ) / ( factor * 2 * increment );
301 
302  dE_dvars_numeric[j][ii] = deriv;
303 
304  deriv_dev = std::min( deriv_dev, std::abs( deriv - dE_dvars[ii] ) );
305 
306  vars[ii] = start_vars[ii];
307 
308  Real const ratio( std::abs( dE_dvars[ii] ) < 0.001 ? 0.0 :
309  deriv / dE_dvars[ii] );
310 
311  if ( std::abs(dE_dvars[ii]) > 0.001 || std::abs(deriv) > 0.001 ) {
312  if ( verbose && write_to_stdout ) {
313  // if you change this output, please also change the comments
314  // at the beginning of this section
315  static bool ratio_header_output( false );
316  if ( !ratio_header_output ) {
317  ratio_header_output = true;
318  TR << "ratio" <<
319  A( 4, "inc" ) <<
320  A( 4, "rsd" ) <<
321  A( 4, "atm" ) <<
322  A( 4, "axs" ) <<
323  A( 5, "natm" ) <<
324  A( 10, "numeric" ) <<
325  A( 10, "analytic" ) <<
326  A( 10, "ratio" ) <<
327  A( 10, "vars[ii]" ) << std::endl;
328  }
329 
330 
331  TR << "ratio" <<
332  I( 4, j ) <<
333  I( 4, atm_id.rsd() ) <<
334  I( 4, atm_id.atomno() ) <<
335  A( 4, (jj==0)?"x":((jj==1)?"y":"z") ) <<
336  I( 5, natoms ) <<
337  F( 10, 4, deriv ) << // column 11
338  F( 10, 4, dE_dvars[ii] ) << // column 12
339  F( 10, 4, ratio ) <<
340  F( 10, 4, start_vars[ii] ) << std::endl;
341  }
342 
343  }
344  }
345  if ( true ) {
346  Real const ratio( std::abs( dE_dvars[ii] ) < 0.001 ? 0.0 :
347  deriv_dev / std::abs( dE_dvars[ii] ) );
348 
349  if ( min_debug ) min_debug->rel_deriv_dev( ii, ratio );
350  if ( min_debug ) min_debug->abs_deriv_dev( ii, deriv_dev );
351 
352  //if ( verbose && write_to_stdout ) {
353  // if you change this output, please also change the comments
354  // at the beginning of this section
355  // TR << "deriv_dev:" << SS(ii) << SS(ndofs) << SS(f00) << SS( atm_id.atomno() ) <<
356  // SS( atm_id.rsd() ) << SS( dE_dvars[ii] ) << SS( deriv_dev ) << SS(ratio) << std::endl;
357  //}
358  }
359  }
360  }
361 
362  // calculate magnitudes, dot products of gradient vectors
363  utility::vector1< Real > norm_numeric(n_increment,0.0), dot(n_increment,0.0);
364  Real norm(0.0);
365  for ( Size i=1; i<= ndofs; ++i ) {
366  norm += dE_dvars[i] * dE_dvars[i];
367  for ( Size j=1; j<= n_increment; ++j ) {
368  dot[j] += dE_dvars[i] * dE_dvars_numeric[j][i];
369  norm_numeric[j] += dE_dvars_numeric[j][i] * dE_dvars_numeric[j][i];
370  }
371  }
372  norm = std::sqrt( norm );
373 
374  Real lbest_cos_theta( -10.0 );
375  Real lbest_abs_log_norm_ratio( 200.0 );
376  Real lbest_norm_analytic( 999.9 );
377  Real lbest_norm_numeric( 999.9 );
378 
379  for ( Size j=1; j<= n_increment; ++j ) {
380  norm_numeric[j] = std::sqrt( norm_numeric[j] );
381 
382  // handle strange cases
383  Real log_norm_ratio;
384  if ( norm < 0.001 && norm_numeric[j] < 0.001 ) {
385  log_norm_ratio = 1.0;
386  } else if ( norm < 0.001 ) {
387  log_norm_ratio = 100.0;
388  } else if ( norm_numeric[j] < 0.001 ) {
389  log_norm_ratio = -100.0;
390  } else {
391  log_norm_ratio = std::log( norm_numeric[j] / norm );
392  }
393 
394  Real const cos_theta( dot[j] / ( norm * norm_numeric[j]) );
395 
396  if ( write_to_stdout ) {
397  TR <<
398  " norm: " << j << ' ' << F(12,4,norm) <<
399  " norm_numeric: " << F(12,4,norm_numeric[j]) <<
400  " cos_theta: " << F(7,4,cos_theta) <<
401  " log_norm_ratio: " << F(9,4,log_norm_ratio) << std::endl;
402  }
403 
404  lbest_cos_theta = std::max( lbest_cos_theta, cos_theta );
405  if ( std::abs( log_norm_ratio ) < lbest_abs_log_norm_ratio ) {
406  lbest_abs_log_norm_ratio = std::abs( log_norm_ratio );
407  lbest_norm_analytic = norm;
408  lbest_norm_numeric = norm_numeric[j];
409  }
410  }
411 
412  if ( min_debug ) min_debug->best_cos_theta( lbest_cos_theta );
413  if ( min_debug ) min_debug->best_abs_log_norm_ratio( lbest_abs_log_norm_ratio );
414  if ( min_debug ) min_debug->best_norm_analytic( lbest_norm_analytic );
415  if ( min_debug ) min_debug->best_norm_numeric( lbest_norm_numeric );
416 
417  if ( deriv_check_result ) deriv_check_result->add_deriv_data( min_debug );
418 }
419 
420 
421 // fpd convert torsional derivs to cartesian
422 void
423 tors_deriv_to_cartesian( Real dE_dtor, VectorQuad const & coords, VectorQuad & dE_dxs)
424 {
425  // convert to cartesian derivatives on those atoms using the usual MD code - lift from PD
426  //core::Real epot_dihedral_this=0;
427  core::Real sin_phi, cos_phi;
428  core::Vector vti_vta, vta_vtb, vtb_vtj;
429  core::Vector nrml1, nrml2, nrml3;
430  core::Real inv_nrml1_mag, inv_nrml2_mag, inv_nrml3_mag;
431 
432  core::Vector dcosdnrml1(0,0,0), dcosdnrml2(0,0,0), dsindnrml3(0,0,0), dsindnrml2(0,0,0);
433  core::Vector f(0,0,0), fi(0,0,0), fab(0,0,0), fj(0,0,0);
434 
435  vti_vta = coords.get<0>() - coords.get<1>();
436  vta_vtb = coords.get<1>() - coords.get<2>();
437  vtb_vtj = coords.get<2>() - coords.get<3>();
438 
439  nrml1.x() = (vti_vta.y() * vta_vtb.z() - vti_vta.z() * vta_vtb.y());
440  nrml1.y() = (vti_vta.z() * vta_vtb.x() - vti_vta.x() * vta_vtb.z());
441  nrml1.z() = (vti_vta.x() * vta_vtb.y() - vti_vta.y() * vta_vtb.x());
442 
443  nrml2.x() = (vta_vtb.y() * vtb_vtj.z() - vta_vtb.z() * vtb_vtj.y());
444  nrml2.y() = (vta_vtb.z() * vtb_vtj.x() - vta_vtb.x() * vtb_vtj.z());
445  nrml2.z() = (vta_vtb.x() * vtb_vtj.y() - vta_vtb.y() * vtb_vtj.x());
446 
447  nrml3.x() = (vta_vtb.y() * nrml1.z() - vta_vtb.z() * nrml1.y());
448  nrml3.y() = (vta_vtb.z() * nrml1.x() - vta_vtb.x() * nrml1.z());
449  nrml3.z() = (vta_vtb.x() * nrml1.y() - vta_vtb.y() * nrml1.x());
450 
451  inv_nrml1_mag = 1.0 / nrml1.length();
452  inv_nrml2_mag = 1.0 / nrml2.length();
453  inv_nrml3_mag = 1.0 / nrml3.length();
454 
455  cos_phi = (nrml1.x() * nrml2.x() + nrml1.y() * nrml2.y() + nrml1.z() * nrml2.z()) * inv_nrml1_mag * inv_nrml2_mag;
456  sin_phi = (nrml3.x() * nrml2.x() + nrml3.y() * nrml2.y() + nrml3.z() * nrml2.z()) * inv_nrml3_mag * inv_nrml2_mag;
457 
458  nrml2.x() *= inv_nrml2_mag;
459  nrml2.y() *= inv_nrml2_mag;
460  nrml2.z() *= inv_nrml2_mag;
461 
462  //phi = -atan2(sin_phi, cos_phi);
463 
464  if(fabs(sin_phi) > 0.1) {
465  nrml1.x() *= inv_nrml1_mag;
466  nrml1.y() *= inv_nrml1_mag;
467  nrml1.z() *= inv_nrml1_mag;
468 
469  dcosdnrml1.x() = inv_nrml1_mag * (nrml1.x() * cos_phi - nrml2.x());
470  dcosdnrml1.y() = inv_nrml1_mag * (nrml1.y() * cos_phi - nrml2.y());
471  dcosdnrml1.z() = inv_nrml1_mag * (nrml1.z() * cos_phi - nrml2.z());
472 
473  dcosdnrml2.x() = inv_nrml2_mag * (nrml2.x() * cos_phi - nrml1.x());
474  dcosdnrml2.y() = inv_nrml2_mag * (nrml2.y() * cos_phi - nrml1.y());
475  dcosdnrml2.z() = inv_nrml2_mag * (nrml2.z() * cos_phi - nrml1.z());
476 
477  } else {
478  nrml3.x() *= inv_nrml3_mag;
479  nrml3.y() *= inv_nrml3_mag;
480  nrml3.z() *= inv_nrml3_mag;
481 
482  dsindnrml3.x() = inv_nrml3_mag * (nrml3.x() * sin_phi - nrml2.x());
483  dsindnrml3.y() = inv_nrml3_mag * (nrml3.y() * sin_phi - nrml2.y());
484  dsindnrml3.z() = inv_nrml3_mag * (nrml3.z() * sin_phi - nrml2.z());
485 
486  dsindnrml2.x() = inv_nrml2_mag * (nrml2.x() * sin_phi - nrml3.x());
487  dsindnrml2.y() = inv_nrml2_mag * (nrml2.y() * sin_phi - nrml3.y());
488  dsindnrml2.z() = inv_nrml2_mag * (nrml2.z() * sin_phi - nrml3.z());
489  }
490  dE_dtor *= -1;
491 
492  // forces
493  if(fabs(sin_phi) > 0.1) {
494  dE_dtor /= sin_phi;
495  fi.x() += dE_dtor * (vta_vtb.y() * dcosdnrml1.z() - vta_vtb.z() * dcosdnrml1.y());
496  fi.y() += dE_dtor * (vta_vtb.z() * dcosdnrml1.x() - vta_vtb.x() * dcosdnrml1.z());
497  fi.z() += dE_dtor * (vta_vtb.x() * dcosdnrml1.y() - vta_vtb.y() * dcosdnrml1.x());
498 
499  fj.x() += dE_dtor * (vta_vtb.z() * dcosdnrml2.y() - vta_vtb.y() * dcosdnrml2.z());
500  fj.y() += dE_dtor * (vta_vtb.x() * dcosdnrml2.z() - vta_vtb.z() * dcosdnrml2.x());
501  fj.z() += dE_dtor * (vta_vtb.y() * dcosdnrml2.x() - vta_vtb.x() * dcosdnrml2.y());
502 
503  fab.x() += dE_dtor * (vti_vta.z() * dcosdnrml1.y() - vti_vta.y() * dcosdnrml1.z() + vtb_vtj.y() * dcosdnrml2.z() - vtb_vtj.z() * dcosdnrml2.y());
504  fab.y() += dE_dtor * (vti_vta.x() * dcosdnrml1.z() - vti_vta.z() * dcosdnrml1.x() + vtb_vtj.z() * dcosdnrml2.x() - vtb_vtj.x() * dcosdnrml2.z());
505  fab.z() += dE_dtor * (vti_vta.y() * dcosdnrml1.x() - vti_vta.x() * dcosdnrml1.y() + vtb_vtj.x() * dcosdnrml2.y() - vtb_vtj.y() * dcosdnrml2.x());
506 
507  } else {
508  dE_dtor /= -cos_phi;
509 
510  fi.x() += dE_dtor *
511  ((vta_vtb.y()*vta_vtb.y() + vta_vtb.z()*vta_vtb.z())*dsindnrml3.x()
512  - vta_vtb.x()*vta_vtb.y()*dsindnrml3.y() - vta_vtb.x()* vta_vtb.z()*dsindnrml3.z());
513  fi.y() += dE_dtor *
514  ((vta_vtb.z()*vta_vtb.z() + vta_vtb.x()*vta_vtb.x())*dsindnrml3.y()
515  - vta_vtb.y()*vta_vtb.z()*dsindnrml3.z() - vta_vtb.y()* vta_vtb.x()*dsindnrml3.x());
516  fi.z() += dE_dtor *
517  ((vta_vtb.x()*vta_vtb.x() + vta_vtb.y()*vta_vtb.y())*dsindnrml3.z()
518  - vta_vtb.z()*vta_vtb.x()*dsindnrml3.x() - vta_vtb.z()*vta_vtb.y()*dsindnrml3.y());
519 
520  fj.x() += dE_dtor * (dsindnrml2.y() * vta_vtb.z() - dsindnrml2.z() * vta_vtb.y());
521  fj.y() += dE_dtor * (dsindnrml2.z() * vta_vtb.x() - dsindnrml2.x() * vta_vtb.z());
522  fj.z() += dE_dtor * (dsindnrml2.x() * vta_vtb.y() - dsindnrml2.y() * vta_vtb.x());
523 
524  fab.x() += dE_dtor * (-(vta_vtb.y() * vti_vta.y() + vta_vtb.z() * vti_vta.z()) * dsindnrml3.x()
525  + (2.0 * vta_vtb.x() * vti_vta.y() - vti_vta.x() * vta_vtb.y()) * dsindnrml3.y()
526  + (2.0 * vta_vtb.x() * vti_vta.z() - vti_vta.x() * vta_vtb.z()) * dsindnrml3.z() + dsindnrml2.z() * vtb_vtj.y() - dsindnrml2.y() * vtb_vtj.z());
527  fab.y() += dE_dtor * (-(vta_vtb.z() * vti_vta.z() + vta_vtb.x() * vti_vta.x()) * dsindnrml3.y()
528  + (2.0 * vta_vtb.y() * vti_vta.z() - vti_vta.y() * vta_vtb.z()) * dsindnrml3.z()
529  + (2.0 * vta_vtb.y() * vti_vta.x() - vti_vta.y() * vta_vtb.x()) * dsindnrml3.x() + dsindnrml2.x() * vtb_vtj.z() - dsindnrml2.z() * vtb_vtj.x());
530  fab.z() += dE_dtor * (-(vta_vtb.x() * vti_vta.x() + vta_vtb.y() * vti_vta.y()) * dsindnrml3.z()
531  + (2.0 * vta_vtb.z() * vti_vta.x() - vti_vta.z() * vta_vtb.x()) * dsindnrml3.x()
532  + (2.0 * vta_vtb.z() * vti_vta.y() - vti_vta.z() * vta_vtb.y()) * dsindnrml3.y() + dsindnrml2.y() * vtb_vtj.x() - dsindnrml2.x() * vtb_vtj.y());
533  }
534 
535  boost::get<0>(dE_dxs) = fi;
536  boost::get<1>(dE_dxs) = fab-fi;
537  boost::get<2>(dE_dxs) = fj-fab;
538  boost::get<3>(dE_dxs) = -fj;
539 }
540 
541 
542 
543 
544 } // namespace optimization
545 } // namespace core