Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
BackrubMover.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 protocols/backrub/BackrubMover.cc
11 /// @brief implementation of BackrubMover class and functions
12 /// @author Colin A. Smith (colin.smith@ucsf.edu)
13 
14 
17 
18 // Protocols Headers
21 // AUTO-REMOVED #include <protocols/canonical_sampling/ThermodynamicObserver.hh> // needed for Windows build
23 #include <core/pose/selection.hh>
24 
25 // Core Headers
28 #include <core/id/DOF_ID_Range.hh>
32 #include <basic/options/option.hh>
33 #include <core/pose/Pose.hh>
37 #include <core/types.hh>
38 #include <basic/Tracer.hh>
39 
40 // Numeric Headers
41 #include <numeric/angle.functions.hh>
42 #include <numeric/conversions.hh>
43 #include <numeric/IntervalSet.hh>
44 #include <numeric/random/random.hh>
45 #include <numeric/xyzVector.hh>
46 
47 // Utility Headers
48 #include <utility/exit.hh>
49 #include <utility/string_util.hh>
50 #include <utility/tag/Tag.hh>
51 
52 // ObjexxFCL Headers
53 #include <ObjexxFCL/string.functions.hh>
54 
55 // C++ Headers
56 #include <iomanip>
57 #include <set>
58 
59 // option key includes
60 
61 #include <basic/options/keys/backrub.OptionKeys.gen.hh>
62 
65 #include <utility/vector0.hh>
66 #include <utility/vector1.hh>
67 #include <utility/keys/Key3Vector.hh>
68 
69 
70 
71 
72 using namespace core;
73 using namespace core::pose;
74 
75 static numeric::random::RandomGenerator RG(2225782);
76 static basic::Tracer TR("protocols.backrub.BackrubMover");
77 
78 namespace protocols {
79 namespace backrub {
80 
83  return BackrubMoverCreator::mover_name();
84 }
85 
88  return new BackrubMover;
89 }
90 
93  return "Backrub";
94 }
95 
97  pivot_atoms_(utility::vector1<std::string>(1, "CA")),
98  min_atoms_(3),
99  max_atoms_(34),
100  max_angle_disp_4_(numeric::conversions::radians(40.)),
101  max_angle_disp_7_(numeric::conversions::radians(20.)),
102  max_angle_disp_slope_(numeric::conversions::radians(-1./3.)),
103  next_segment_id_(0),
104  preserve_detailed_balance_(false),
105  require_mm_bend_(true)
106 {}
107 
109  BackrubMover const & mover
110 ) :
111  //utility::pointer::ReferenceCount(),
112  protocols::canonical_sampling::ThermodynamicMover(mover),
113  segments_(mover.segments_),
114  branchopt_(mover.branchopt_),
115  bond_angle_map_(mover.bond_angle_map_),
116  pivot_residues_(mover.pivot_residues_),
117  pivot_atoms_(mover.pivot_atoms_),
118  min_atoms_(mover.min_atoms_),
119  max_atoms_(mover.max_atoms_),
120  max_angle_disp_4_(mover.max_angle_disp_4_),
121  max_angle_disp_7_(mover.max_angle_disp_7_),
122  max_angle_disp_slope_(mover.max_angle_disp_slope_),
123  next_segment_id_(mover.next_segment_id_),
124  last_segment_id_(mover.last_segment_id_),
125  last_start_atom_name_(mover.last_start_atom_name_),
126  last_end_atom_name_(mover.last_end_atom_name_),
127  last_angle_(mover.last_angle_),
128  preserve_detailed_balance_(mover.preserve_detailed_balance_),
129  require_mm_bend_(mover.require_mm_bend_)
130 {}
131 
134 
135 void
137  BackrubMover & mover
138 )
139 {
140  using namespace basic::options;
141  using namespace basic::options::OptionKeys;
142 
143  utility::vector1<core::Size> pivot_residues;
144  for (core::Size i = 1; i <= option[ OptionKeys::backrub::pivot_residues ].size(); ++i) {
145  if (option[ OptionKeys::backrub::pivot_residues ][i] >= 1) pivot_residues.push_back(option[ OptionKeys::backrub::pivot_residues ][i]);
146  }
147 
148  mover.set_pivot_residues(pivot_residues);
149  mover.set_pivot_atoms(option[ OptionKeys::backrub::pivot_atoms ]);
150  mover.set_min_atoms(option[ OptionKeys::backrub::min_atoms ]);
151  mover.set_max_atoms(option[ OptionKeys::backrub::max_atoms ]);
152 }
153 
154 void
156 {
158 }
159 
160 void
162  utility::tag::TagPtr const tag,
163  protocols::moves::DataMap & /*data*/,
164  protocols::filters::Filters_map const & /*filters*/,
165  protocols::moves::Movers_map const & /*movers*/,
166  core::pose::Pose const & pose
167 )
168 {
169  if ( tag->hasOption("pivot_residues") ) {
170  pivot_residues_ = core::pose::get_resnum_list(tag, "pivot_residues", pose);
171  }
172 
173  if ( tag->hasOption("pivot_atoms") ) {
174  std::string const pivot_atoms_string( tag->getOption<std::string>("pivot_atoms") );
175  pivot_atoms_ = utility::string_split( pivot_atoms_string, ',' );
176  }
177 
178  min_atoms_ = tag->getOption<core::Size>( "min_atoms", min_atoms_ );
179  max_atoms_ = tag->getOption<core::Size>( "max_atoms", max_atoms_ );
180  max_angle_disp_4_ = tag->getOption<core::Real>( "max_angle_disp_4", max_angle_disp_4_ );
181  max_angle_disp_7_ = tag->getOption<core::Real>( "max_angle_disp_7", max_angle_disp_7_ );
182  max_angle_disp_slope_ = tag->getOption<core::Real>( "max_angle_disp_slope", max_angle_disp_slope_ );
183  set_preserve_detailed_balance( tag->getOption<bool>( "preserve_detailed_balance", preserve_detailed_balance() ) );
184  set_require_mm_bend( tag->getOption<bool>( "require_mm_bend", require_mm_bend() ) );
185 
186  set_input_pose(new core::pose::Pose(pose));
187 
188  clear_segments();
189  add_mainchain_segments();
190 
191  if ( ! branchopt_.initialized() ) branchopt_.read_database();
192 }
193 
194 void
196  core::pose::Pose & pose,
197  protocols::canonical_sampling::MetropolisHastingsMover const & metropolis_hastings_mover,
198  core::Size
199 )
200 {
201  if ( ! branchopt_.initialized() ) branchopt_.read_database();
202 
203  if (!(num_segments() && get_input_pose() && get_input_pose()->fold_tree() == pose.fold_tree())) {
204 
205  if (!(get_input_pose() && get_input_pose()->fold_tree() == pose.fold_tree())) {
206  set_input_pose(new core::pose::Pose(pose));
207  }
208 
209  // this code shouldn't get called when the parser is in use
210  init_with_options();
211  clear_segments();
212  add_mainchain_segments();
213  }
214 
215  protocols::moves::MonteCarloCOP monte_carlo(metropolis_hastings_mover.monte_carlo());
216 
217  if (monte_carlo->score_function().get_weight(core::scoring::mm_bend) == 0.0) {
218  TR << "*** WARNING: Using BackrubMover without mm_bend Score Term ***" << std::endl;
219  if (require_mm_bend_) {
220  TR << "Exit can be prevented by setting require_mm_bend to false" << std::endl;
221  utility_exit();
222  }
223  }
224 
225  // tell the branch angle optimizer about the score function MMBondAngleResidueTypeParamSet, if any
226  if (monte_carlo->score_function().energy_method_options().bond_angle_residue_type_param_set()) {
227  branchopt_.bond_angle_residue_type_param_set(monte_carlo->score_function().energy_method_options().bond_angle_residue_type_param_set());
228  }
229 
230  optimize_branch_angles(pose);
231 }
232 
233 /// @detailed
234 void
236  Pose & pose
237 )
238 {
239  // the BranchAngleOptimizer must be initialized by reading a database. Do so now if this has not occurred
240  if ( ! branchopt_.initialized() ) branchopt_.read_database();
241 
242  if (!(num_segments() && get_input_pose() && get_input_pose()->fold_tree() == pose.fold_tree())) {
243 
244  if (!(get_input_pose() && get_input_pose()->fold_tree() == pose.fold_tree())) {
245  set_input_pose(new core::pose::Pose(pose));
246  }
247 
248  clear_segments();
249  add_mainchain_segments();
250  }
251 
252  runtime_assert(segments_.size());
253 
254  // pick a random segment
255  Size segment_id;
256  if (next_segment_id_) {
257  segment_id = next_segment_id_;
258  next_segment_id_ = 0;
259  } else {
260  segment_id = RG.random_range(1, segments_.size());
261  }
262 
263  // record data about the move
264  last_segment_id_ = segment_id;
265  id::AtomID atomid1(segments_[segment_id].start_atomid());
266  id::AtomID atomid2(segments_[segment_id].end_atomid());
267  if (atomid2 < atomid1) {
268  id::AtomID temp(atomid1);
269  atomid1 = atomid2;
270  atomid2 = temp;
271  }
272  last_start_atom_name_ = pose.residue_type(atomid1.rsd()).atom_name(atomid1.atomno());
273  last_end_atom_name_ = pose.residue_type(atomid2.rsd()).atom_name(atomid2.atomno());
274 
275  // the function that calculates the constants would need to be called twice if we didn't save them
276  utility::vector0<Real> start_constants;
277  utility::vector0<Real> end_constants;
278 
279  // pick a random angle
280  last_angle_ = random_angle(pose, segment_id, start_constants, end_constants);
281 
282  TR.Debug << "Applying " << numeric::conversions::degrees(last_angle_) << " degree rotation to segment " << segment_id
283  << std::endl;
284 
285  // rotate the segment of the angle is not 0
286  if (last_angle_ != 0) {
287  rotate_segment(pose, segment_id, last_angle_, start_constants, end_constants);
288  }
289 
290  update_type();
291 }
292 
295  return "BackrubMover";
296 }
297 
298 // /// @detailed
299 // void
300 // BackrubMover::test_move(
301 // Pose &
302 // )
303 // {
304 //
305 // }
306 
307 /// @brief calculate the number of atom tree bonds between the two atoms
308 /// possibly move this into the Atom class
310  kinematics::tree::AtomCOP ancestor,
311  kinematics::tree::AtomCOP descendent
312 )
313 {
314  kinematics::tree::AtomCOP current(descendent);
315 
316  for (int tdist = 0; current; ++tdist) {
317  if (ancestor == current) return tdist;
318  current = current->parent();
319  }
320 
321  return -1;
322 }
323 
324 /// @detailed
325 /// The start atom MUST have all three stub atoms defined. However, the end atom
326 /// may be at the very end of the chain. There must be at least one atom between
327 /// start and end atoms.
328 ///
329 /// If the segment is for whatever reason invalid, 0 is returned. Otherwise, the
330 /// segment is added to the end of the segments vector and the ID to the new
331 /// segment is returned. If the segment already exists, then nothing is changed
332 /// and the existing segment ID is returned.
333 ///
334 /// There has been absolutely no testing of how the code handles jumps! Use this
335 /// with jumps at your own risk!
336 Size
338  id::AtomID start_atomid,
339  id::AtomID end_atomid,
340  Real max_angle_disp // = 0
341 )
342 {
343  PoseCOP input_pose(get_input_pose());
344 
345  runtime_assert(input_pose);
346 
347  // get references to Atom tree atoms
348  kinematics::tree::AtomCOP start_atom(&input_pose->atom_tree().atom(start_atomid));
349  kinematics::tree::AtomCOP end_atom(&input_pose->atom_tree().atom(end_atomid));
350 
351  // calculate initial tree distance
352  int tdist(tree_distance(start_atom, end_atom));
353 
354  // if no ancestry is detected, check to see if the atoms were reversed
355  if (tdist < 0) {
356  tdist = tree_distance(end_atom, start_atom);
357  if (tdist >= 2) {
358  //TR.Warning << "Warning: Backrub segment " << start_atomid << " to " << end_atomid
359  // << " ordered wrong, reversing" << std::endl;
360  kinematics::tree::AtomCOP const temp_atom(start_atom);
361  id::AtomID const temp_atomid(start_atomid);
362  start_atom = end_atom;
363  start_atomid = end_atomid;
364  end_atom = temp_atom;
365  end_atomid = temp_atomid;
366  }
367  }
368 
369  // if no ancestry is still detected, the segment is invalid
370  if (tdist < 0) {
371  TR.Warning << "Warning: Backrub segment " << start_atomid << " to " << end_atomid << " invalid, ignoring"
372  << std::endl;
373  return 0;
374  }
375 
376  // if the tree distance is too short, the segment is invalid
377  if (tdist < 2) {
378  TR.Warning << "Warning: Backrub segment " << start_atomid << " to " << end_atomid << " too short, ignoring"
379  << std::endl;
380  return 0;
381  }
382 
383  // check for duplicates
384  if ( Size segid = segment_id(start_atomid, end_atomid) ) {
385  TR.Warning << "Warning: Backrub segment " << start_atomid << " to " << end_atomid << " already exists, ignoring"
386  << std::endl;
387  return segid;
388  }
389 
390  //TR << "start_atom stub: " << start_atom->stub_atom1_id() << " " << start_atom->stub_atom2_id() << " "
391  // << start_atom->stub_atom3_id() << std::endl;
392 
393  if ( !(start_atom->stub_atom1() && start_atom->stub_atom2() && start_atom->stub_atom3()) ) {
394  TR.Warning << "Warning: Backrub segment " << start_atomid << " to " << end_atomid
395  << " has incomplete start stub, ignoring" << std::endl;
396  return 0;
397  }
398 
399  // Find the first two atoms on the path from start to end
400  id::AtomID start_atomid1(end_atom->parent()->id());
401  id::AtomID start_atomid2(end_atom->id());
402  for (kinematics::tree::AtomCOP current_atom = end_atom->parent()->parent(); current_atom != start_atom;
403  current_atom = current_atom->parent()) {
404  start_atomid2 = start_atomid1;
405  start_atomid1 = current_atom->id();
406  }
407 
408  // This catches a rare case that we can't currently handle
409  if ( start_atom->stub_atom2()->id() == start_atomid1 ) {
410  //TR.Warning << "Warning: Backrub segment " << start_atomid << " to " << end_atomid
411  // << " has incompatible stub, ignoring" << std::endl;
412  return 0;
413  }
414 
415  TR.Debug << "Adding Backrub segment " << start_atomid << " to " << end_atomid << " (size " << tdist+1 << ")" << std::endl;
416 
417  // use default maximum angular displacement parameters if it was not provided
418  if (max_angle_disp == 0) {
419  if (tdist+1 < 7) {
420  max_angle_disp = max_angle_disp_4_ + (tdist+1 - 4) * max_angle_disp_slope_;
421  } else {
422  max_angle_disp = max_angle_disp_7_ + (tdist+1 - 7) * max_angle_disp_slope_;
423  }
424  }
425 
426  segments_.push_back(protocols::backrub::BackrubSegment(start_atomid, start_atomid1, start_atomid2, end_atomid, tdist+1, max_angle_disp));
427 
428  Size segment_id = segments_.size();
429 
430  bond_angle_map_[segments_[segment_id].start_bond_angle_key(*input_pose)] = bond_angle_map_.size() + 1;
431  bond_angle_map_[segments_[segment_id].end_bond_angle_key(*input_pose)] = bond_angle_map_.size() + 1;
432 
433  return segment_id;
434 }
435 
438  Pose const & pose,
439  core::id::AtomID atomid,
441 )
442 {
443  // empty the input vector
444  atomids.clear();
445 
446  // make sure that atomid is a mainchain atom
447  chemical::AtomIndices const & mainchain_atoms(pose.residue_type(atomid.rsd()).mainchain_atoms());
448  Size mainchain_index(0);
449  for (Size i = 1; i <= mainchain_atoms.size(); ++i) {
450  if (mainchain_atoms[i] == atomid.atomno()) {
451  mainchain_index = i;
452  break;
453  }
454  }
455  // we weren't given a mainchain atom, return nothing
456  if (! mainchain_index) return 0;
457 
458  // rewind to the beginning of the chain
459  Size resnum(atomid.rsd());
460  while(true) {
461  conformation::Residue const & residue(pose.residue(resnum));
462  chemical::AtomIndices const & mainchain_atoms(residue.mainchain_atoms());
463 
464  if (!mainchain_atoms.size()) break;
465 
466  // loop over all residue connections in the current residue
467  for (Size i = 1; i <= residue.n_residue_connections(); ++i) {
468 
469  // check to see if the connection is to the first mainchain atom
470  if (residue.residue_connect_atom_index(i) == mainchain_atoms.front() && !residue.connection_incomplete(i)) {
471 
472  // check to see if the atom it is connected to is the last mainchain atom of the corresponding residue
473  chemical::ResConnID resconid(residue.actual_residue_connection(i));
474  Size connected_atomno(pose.residue(resconid.resid()).residue_connect_atom_index(resconid.connid()));
475  chemical::AtomIndices const & mainchain_atoms(pose.residue(resconid.resid()).mainchain_atoms());
476  if (mainchain_atoms.size() && mainchain_atoms.back() == connected_atomno) {
477  // success, set the new residue number
478  resnum = resconid.resid();
479  break;
480  }
481  }
482  }
483 
484  // get out of the loop if we didn't decrement resnum
485  if (resnum == residue.seqpos()) break;
486  }
487 
488  // now iterate over all connected residues and insert their mainchain atomids
489  while (resnum) {
490  conformation::Residue const & residue(pose.residue(resnum));
491  chemical::AtomIndices const & mainchain_atoms(residue.mainchain_atoms());
492 
493  // set the loop to exit by default
494  resnum = 0;
495 
496  for (Size i = 1; i <= mainchain_atoms.size(); i++) {
497  atomids.push_back(id::AtomID(mainchain_atoms[i], residue.seqpos()));
498  if (atomids.back() == atomid) {
499  mainchain_index = atomids.size();
500  }
501  }
502 
503  // loop over all residue connections in the current residue
504  for (Size i = 1; i <= residue.n_residue_connections(); ++i) {
505 
506  // check to see if the connection is to the last mainchain atom
507  if (residue.residue_connect_atom_index(i) == mainchain_atoms.back() && !residue.connection_incomplete(i)) {
508 
509  // check to see if the atom it is connected to is the first mainchain atom of the corresponding residue
510  chemical::ResConnID resconid(residue.actual_residue_connection(i));
511  Size connected_atomno(pose.residue(resconid.resid()).residue_connect_atom_index(resconid.connid()));
512  chemical::AtomIndices const & mainchain_atoms(pose.residue(resconid.resid()).mainchain_atoms());
513  if (mainchain_atoms.size() && mainchain_atoms.front() == connected_atomno) {
514  // success, set the new residue number
515  resnum = resconid.resid();
516  break;
517  }
518  }
519  }
520  }
521 
522  return mainchain_index;
523 }
524 
528  core::Size min_atoms,
529  core::Size max_atoms
530 )
531 {
532  PoseCOP input_pose(get_input_pose());
533 
534  runtime_assert(min_atoms >= 3 && max_atoms >= min_atoms);
535 
536  std::set<id::AtomID> atomid_set(atomids.begin(), atomids.end());
537  Size nsegments(0);
538 
539  while (atomid_set.size()) {
540 
541  // get a list of contiguous mainchain atoms connected to the first atomid in the set
542  utility::vector1<core::id::AtomID> mainchain_atomids;
543  if (!connected_mainchain_atomids(*input_pose, *atomid_set.begin(), mainchain_atomids)) {
544  // if it wasn't a mainchain atom, delete it from the set
545  atomid_set.erase(*atomid_set.begin());
546  }
547 
548  // iterate over all atoms in the chain
549  for (Size i = 1; i <= mainchain_atomids.size(); ++i) {
550 
551  // check to see if the atom is in our set
552  if (atomid_set.count(mainchain_atomids[i])) {
553  // delete it from the set
554  atomid_set.erase(mainchain_atomids[i]);
555 
556  // exclude proline N/CA atoms
557  if (input_pose->residue(mainchain_atomids[i].rsd()).aa() == chemical::aa_pro &&
558  (input_pose->residue(mainchain_atomids[i].rsd()).atom_name(mainchain_atomids[i].atomno()) == " N " ||
559  input_pose->residue(mainchain_atomids[i].rsd()).atom_name(mainchain_atomids[i].atomno()) == " CA ")) {
560  continue;
561  }
562 
563  // add any segments for atomids in the set
564  for (Size j = i+min_atoms-1; j <= i+max_atoms-1 && j <= mainchain_atomids.size(); ++j) {
565  if (atomid_set.count(mainchain_atomids[j])) {
566  // exclude proline N/CA atoms
567  if (input_pose->residue(mainchain_atomids[j].rsd()).aa() == chemical::aa_pro &&
568  (input_pose->residue(mainchain_atomids[j].rsd()).atom_name(mainchain_atomids[j].atomno()) == " N " ||
569  input_pose->residue(mainchain_atomids[j].rsd()).atom_name(mainchain_atomids[j].atomno()) == " CA ")) {
570  continue;
571  }
572  add_segment(mainchain_atomids[i], mainchain_atomids[j]);
573  }
574  }
575  }
576  }
577  }
578 
579  return nsegments;
580 }
581 
586  core::Size min_atoms,
587  core::Size max_atoms
588 )
589 {
590  PoseCOP input_pose(get_input_pose());
591 
592  runtime_assert(min_atoms >= 3 && max_atoms >= min_atoms);
593  Size nsegments(0);
594 
595  std::sort(resnums.begin(), resnums.end());
596  utility::vector1<core::Size>::iterator new_end(std::unique(resnums.begin(), resnums.end()));
597  resnums.erase(new_end, resnums.end());
598 
599  TR << "Segment lengths: " << min_atoms << "-" << max_atoms << " atoms" << std::endl;
600  TR << "Main chain pivot atoms:";
601  for (core::Size i = 1; i <= pivot_atoms_.size(); ++i) TR << ' ' << pivot_atoms_[i];
602  TR << std::endl;
603 
604  // loop over all contiguous segments
605  core::Size contiguous_begin = 1;
606  while (contiguous_begin <= resnums.size()) {
607 
608  // find the end of the current segment
609  core::Size contiguous_end = contiguous_begin;
610  while (contiguous_end+1 <= resnums.size() && resnums[contiguous_end]+1 == resnums[contiguous_end+1]) {
611  ++contiguous_end;
612  }
613 
614  TR << "Adding backrub segments for residues " << resnums[contiguous_begin] << "-" << resnums[contiguous_end]
615  << std::endl;
616 
617  // create a vector of input atomids
618  utility::vector1<core::id::AtomID> mainchain_atomids;
619  for (core::Size i = contiguous_begin; i <= contiguous_end; ++i) {
620  core::Size resnum(resnums[i]);
621  if (resnum >= 1 && resnum <= input_pose->total_residue()) {
622  for (core::Size j = 1; j <= atomnames.size(); j++) {
623  mainchain_atomids.push_back(core::id::AtomID(input_pose->residue(resnum).atom_index(atomnames[j]), resnum ));
624  }
625  }
626  }
627 
628  // enumerate segments for the current group of contiguous residues
629  nsegments += add_mainchain_segments(mainchain_atomids, min_atoms, max_atoms);
630 
631  // advance to after the current segment
632  contiguous_begin = contiguous_end+1;
633  }
634 
635  TR << "Total Segments Added: " << num_segments() << std::endl;
636 
637  return nsegments;
638 }
639 
642 {
643  utility::vector1<core::Size> resnums(pivot_residues_);
644  if (resnums.size() == 0) {
645  // use all residues if none defined
646  for (core::Size i = 1; i <= get_input_pose()->total_residue(); ++i) resnums.push_back(i);
647  }
648 
649  // add segments to the backrub mover
650  return add_mainchain_segments(resnums, pivot_atoms_, min_atoms_, max_atoms_);
651 }
652 
655 {
656  init_with_options();
657 
658  return add_mainchain_segments();
659 }
660 
661 void
663  Pose & pose
664 )
665 {
666  for (std::map<protocols::backrub::BackrubSegment::BondAngleKey, core::Size>::iterator iter(bond_angle_map_.begin());
667  iter != bond_angle_map_.end(); ++iter) {
668 
669  BackrubSegment::BondAngleKey const & bond_angle_key(iter->first);
670  if (bond_angle_key.key1().valid() && bond_angle_key.key2().valid() && bond_angle_key.key3().valid()) {
671  TR.Debug << "Optimizing angles for:" << bond_angle_key.key1() << bond_angle_key.key2() << bond_angle_key.key3()
672  << std::endl;
673  branchopt_.optimize_angles(pose, bond_angle_key.key1(), bond_angle_key.key2(), bond_angle_key.key3(), preserve_detailed_balance_);
674  }
675  }
676 }
677 
680 {
681  return pivot_residues_;
682 }
683 
684 void
686  utility::vector1<core::Size> const & pivot_residues
687 )
688 {
689  pivot_residues_ = pivot_residues;
690 }
691 
694 {
695  return pivot_atoms_;
696 }
697 
698 void
700  utility::vector1<std::string> const & pivot_atoms
701 )
702 {
703  pivot_atoms_ = pivot_atoms;
704 }
705 
708 {
709  return min_atoms_;
710 }
711 
712 void
714  core::Size min_atoms
715 )
716 {
717  min_atoms_ = min_atoms;
718 }
719 
722 {
723  return max_atoms_;
724 }
725 
726 void
728  core::Size max_atoms
729 )
730 {
731  max_atoms_ = max_atoms;
732 }
733 
736 {
737  return max_angle_disp_4_;
738 }
739 
740 void
742  core::Real max_angle_disp_4
743 )
744 {
745  max_angle_disp_4_ = max_angle_disp_4;
746 }
747 
750 {
751  return max_angle_disp_7_;
752 }
753 
754 void
756  core::Real max_angle_disp_7
757 )
758 {
759  max_angle_disp_7_ = max_angle_disp_7;
760 }
761 
764 {
765  return max_angle_disp_slope_;
766 }
767 
768 void
770  core::Real max_angle_disp_slope
771 )
772 {
773  max_angle_disp_slope_ = max_angle_disp_slope;
774 }
775 
776 bool
778 {
779  return preserve_detailed_balance_;
780 }
781 
782 void
784  bool preserve_detailed_balance
785 )
786 {
787  preserve_detailed_balance_ = preserve_detailed_balance;
788 }
789 
790 bool
792 {
793  return require_mm_bend_;
794 }
795 
796 void
798  bool require_mm_bend
799 )
800 {
801  require_mm_bend_ = require_mm_bend;
802 }
803 
806  core::pose::Pose & //pose
807 )
808 {
810 }
811 
814  core::pose::Pose & pose
815 )
816 {
817  Real static const pi(numeric::NumericTraits<Real>::pi());
818 
819  // code for declaring branching atom ranges hasn't been written yet
820  runtime_assert(preserve_detailed_balance_);
821 
822  std::set<core::id::DOF_ID_Range> range_set;
823 
824  for (core::Size i = 1; i <= segments_.size(); ++i) {
825 
826  BackrubSegment & segment(segments_[i]);
827 
828  // get references to Atom tree atoms
829  kinematics::tree::AtomCOP start_atom(&pose.atom_tree().atom(segment.start_atomid()));
830  kinematics::tree::AtomCOP start_atom1(&pose.atom_tree().atom(segment.start_atomid1()));
831  kinematics::tree::AtomCOP start_atom2(&pose.atom_tree().atom(segment.start_atomid2()));
832  kinematics::tree::AtomCOP end_atom(&pose.atom_tree().atom(segment.end_atomid()));
833  kinematics::tree::AtomCOP end_atom1(end_atom->get_nonjump_atom(0));
834  kinematics::tree::AtomCOP end_atom2(end_atom1 ? end_atom1->get_nonjump_atom(0) : kinematics::tree::AtomCOP( 0 ) );
835 
836  // Only proceed if stub_atom2 != start_atom1
837  if (start_atom->stub_atom2()->id() != segment.start_atomid1()) {
838 
839  // get overall bond angle parameters for the mainchain bond angle
840  Real start_Ktheta(0);
841  Real start_theta0(0);
842  Real start_energy0(0);
843  branchopt_.overall_params(pose, start_atom->stub_atom2()->id(), segment.start_atomid(), segment.start_atomid1(),
844  start_Ktheta, start_theta0, start_energy0);
845 
846  // limit bond angles to those having probabilites greater than 5% at a kT of 0.6
847  Real start_angle_dev(std::sqrt(-0.6*std::log(0.05)/start_Ktheta));
848 
849  range_set.insert(id::DOF_ID_Range(id::DOF_ID(segment.start_atomid1(), id::THETA),
850  pi - start_theta0 - start_angle_dev,
851  pi - start_theta0 + start_angle_dev));
852 
853  id::DOF_ID const start_dofid1(id::DOF_ID(start_atom1->id(), id::PHI));
854  range_set.insert(id::DOF_ID_Range(start_dofid1, -pi, pi));
855 
856  id::DOF_ID const start_dofid2(id::DOF_ID(start_atom2->parent()->get_nonjump_atom(0)->id(), id::PHI));
857  range_set.insert(id::DOF_ID_Range(start_dofid2, -pi, pi));
858  }
859 
860  // Only proceed if end_atom1 exists
861  if (end_atom1) {
862 
863  // get overall bond angle parameters for the mainchain bond angle
864  Real end_Ktheta(0);
865  Real end_theta0(0);
866  Real end_energy0(0);
867  branchopt_.overall_params(pose, end_atom->parent()->id(), segment.end_atomid(), end_atom1->id(),
868  end_Ktheta, end_theta0, end_energy0);
869 
870  // limit bond angles to those having probabilites greater than 5% at a kT of 0.6
871  Real end_angle_dev(std::sqrt(-0.6*std::log(0.05)/end_Ktheta));
872 
873  range_set.insert(id::DOF_ID_Range(id::DOF_ID(end_atom1->id(), id::THETA),
874  pi - end_theta0 - end_angle_dev,
875  pi - end_theta0 + end_angle_dev));
876 
877  // Set torsion angle 1 by incrementing the oldest sibling PHI DOF
878  id::DOF_ID const end_dofid1(id::DOF_ID(end_atom1->id(), id::PHI));
879  range_set.insert(id::DOF_ID_Range(end_dofid1, -pi, pi));
880 
881  // Only proceed if end_atom2 exists
882  if (end_atom2) {
883 
884  // Set torsion angle 2 by incrementing the oldest sibling PHI DOF
885  id::DOF_ID const end_dofid2(id::DOF_ID(end_atom2->id(), id::PHI));
886  range_set.insert(id::DOF_ID_Range(end_dofid2, -pi, pi));
887  }
888  }
889  }
890 
891  utility::vector1<core::id::DOF_ID_Range> range_vector(range_set.begin(), range_set.end());
892 
893  return range_vector;
894 }
895 
896 Real
898  Pose & pose,
899  Size segment_id,
900  utility::vector0<Real> & start_constants,
901  utility::vector0<Real> & end_constants
902 )
903 {
904  Real static const pi(numeric::NumericTraits<Real>::pi());
905 
906  BackrubSegment & segment(segments_[segment_id]);
907 
908  // get references to Atom tree atoms
909  kinematics::tree::AtomCOP start_atom(&pose.atom_tree().atom(segment.start_atomid()));
910  kinematics::tree::AtomCOP start_atom1(&pose.atom_tree().atom(segment.start_atomid1()));
911  kinematics::tree::AtomCOP start_atom2(&pose.atom_tree().atom(segment.start_atomid2()));
912  kinematics::tree::AtomCOP end_atom(&pose.atom_tree().atom(segment.end_atomid()));
913  kinematics::tree::AtomCOP end_atom1(end_atom->get_nonjump_atom(0));
914  kinematics::tree::AtomCOP end_atom2(end_atom1 ? end_atom1->get_nonjump_atom(0) : kinematics::tree::AtomCOP(0) );
915 
916  //TR << "Start Atom:" << segment.start_atomid() << std::endl;
917  //TR << "End Atom:" << segment.end_atomid() << std::endl;
918 
919  numeric::IntervalSet<Real> tau_intervals_bond_angle(-pi, pi);
920 
921  // Only proceed if stub_atom2 != start_atom1
922  if (start_atom->stub_atom2()->id() != segment.start_atomid1()) {
923 
924  // get overall bond angle parameters for the mainchain bond angle
925  Real start_Ktheta(0);
926  Real start_theta0(0);
927  Real start_energy0(0);
928  branchopt_.overall_params(pose, start_atom->stub_atom2()->id(), segment.start_atomid(), segment.start_atomid1(),
929  start_Ktheta, start_theta0, start_energy0);
930 
931  // limit bond angles to those having probabilites greater than 5% at a kT of 0.6
932  Real start_angle_dev(std::sqrt(-0.6*std::log(0.05)/start_Ktheta));
933 
934  // get bond angle constraint interval & constants for analytically calculating updated DOF values
935  backrub_rotation_constants(start_atom->stub_atom3(), start_atom->stub_atom2(), start_atom, start_atom1, start_atom2,
936  end_atom, start_constants, start_theta0 - start_angle_dev, start_theta0 + start_angle_dev,
937  &tau_intervals_bond_angle);
938  //TR << "Start Bond Angle Intervals: " << tau_intervals_bond_angle << std::endl;
939  }
940 
941  // Only proceed if end_atom1 exists
942  if (end_atom1) {
943 
944  // get overall bond angle parameters for the mainchain bond angle
945  Real end_Ktheta(0);
946  Real end_theta0(0);
947  Real end_energy0(0);
948  branchopt_.overall_params(pose, end_atom->parent()->id(), segment.end_atomid(), end_atom1->id(),
949  end_Ktheta, end_theta0, end_energy0);
950 
951  // limit bond angles to those having probabilites greater than 5% at a kT of 0.6
952  Real end_angle_dev(std::sqrt(-0.6*std::log(0.05)/end_Ktheta));
953 
954  // get bond angle constraint interval & constants for analytically calculating updated DOF values
955  numeric::IntervalSet<Real> tau_intervals_bond_angle_end;
956  backrub_rotation_constants(end_atom->parent()->parent(), end_atom->parent(), end_atom, end_atom1, end_atom2,
957  start_atom, end_constants, end_theta0 - end_angle_dev, end_theta0 + end_angle_dev,
958  &tau_intervals_bond_angle_end);
959  //TR << "End Bond Angle Intervals: " << tau_intervals_bond_angle_end << std::endl;
960 
961  // calculate overall bond angle constraining interval
962  tau_intervals_bond_angle = tau_intervals_bond_angle & tau_intervals_bond_angle_end;
963  //TR << "Bond Angle Intervals: " << tau_intervals_bond_angle << std::endl;
964  }
965 
966  // calculate rotation angle interval, the overall constraining interval, and the total length
967  Real const angle_disp(segments_[segment_id].max_angle_disp());
968  numeric::IntervalSet<Real> tau_intervals_rotation_angle(-angle_disp, angle_disp);
969  //TR << "Rotation Angle Intervals: " << tau_intervals_rotation_angle << std::endl;
970  numeric::IntervalSet<Real> tau_intervals(tau_intervals_bond_angle & tau_intervals_rotation_angle);
971  //TR << "Intervals: " << tau_intervals << std::endl;
972  Real const tau_intervals_length(tau_intervals.length());
973 
974  // return early if there are no angles to pick from
975  if (tau_intervals_length == 0) {
976  return 0;
977  }
978 
979  Real angle(0);
980  numeric::IntervalSet<Real> tau_intervals_rotation_angle_p;
981  Real const threshold(RG.uniform());
982  for (Size i = 0; i < 100000; i++) {
983 
984  angle = tau_intervals.random_point(RG);
985 
986  Real min_angle_p = angle - angle_disp;
987  Real max_angle_p = angle + angle_disp;
988  min_angle_p = numeric::nearest_angle_radians(min_angle_p, 0.);
989  max_angle_p = numeric::nearest_angle_radians(max_angle_p, 0.);
990  if (min_angle_p < max_angle_p) {
991  tau_intervals_rotation_angle_p.set(min_angle_p, max_angle_p);
992  } else {
993  tau_intervals_rotation_angle_p.set(-pi, max_angle_p, min_angle_p, pi);
994  }
995  //TR << "Rotation Angle Intervals': " << tau_intervals_rotation_angle_p << std::endl;
996  //TR << "Intervals': " << (tau_intervals_bond_angle & tau_intervals_rotation_angle_p) << std::endl;
997 
998  Real tau_intervals_length_p = (tau_intervals_bond_angle & tau_intervals_rotation_angle_p).length();
999 
1000  if (tau_intervals_length_p == 0 || tau_intervals_length/tau_intervals_length_p >= threshold) break;
1001  }
1002 
1003  return angle;
1004 }
1005 
1006 /// @detailed
1007 /// The code currently does not do any optimization of branching atom bond angles.
1008 void
1010  Pose & pose,
1011  Size segment_id,
1012  Real angle,
1013  utility::vector0<Real> & start_constants,
1014  utility::vector0<Real> & end_constants
1015 )
1016 {
1017  Real static const pi(numeric::NumericTraits<Real>::pi());
1018 
1019  BackrubSegment & segment(segments_[segment_id]);
1020 
1021  // get references to Atom tree atoms
1022  kinematics::tree::AtomCOP start_atom(&pose.atom_tree().atom(segment.start_atomid()));
1023  kinematics::tree::AtomCOP start_atom1(&pose.atom_tree().atom(segment.start_atomid1()));
1024  kinematics::tree::AtomCOP start_atom2(&pose.atom_tree().atom(segment.start_atomid2()));
1025  kinematics::tree::AtomCOP end_atom(&pose.atom_tree().atom(segment.end_atomid()));
1026  kinematics::tree::AtomCOP end_atom1(end_atom->get_nonjump_atom(0));
1027  kinematics::tree::AtomCOP end_atom2(end_atom1 ? end_atom1->get_nonjump_atom(0) : kinematics::tree::AtomCOP(0) );
1028 
1029  /*
1030  PointPosition end_atom_xyz(pose.xyz(end_atom->id()));
1031  PointPosition end_atom1_xyz;
1032  if (end_atom1) end_atom1_xyz = pose.xyz(end_atom1->id());
1033  PointPosition end_atom2_xyz;
1034  if (end_atom2) end_atom2_xyz = pose.xyz(end_atom2->id());
1035  */
1036 
1037  // Get constants for analytically calculating updated DOF values
1038  // Only recalculate the constants if they haven't already been calculated
1039  if (start_constants.size() == 0) {
1040  backrub_rotation_constants(start_atom->stub_atom3(), start_atom->stub_atom2(), start_atom, start_atom1, start_atom2,
1041  end_atom, start_constants);
1042  }
1043 
1044  // Get angles before and after the rotation
1045  Real start_0_bondangle(0), start_0_torsion1(0), start_0_torsion2(0);
1046  Real start_bondangle(0), start_torsion1(0), start_torsion2(0);
1047  backrub_rotation_angles(start_constants, 0, start_0_bondangle, start_0_torsion1, start_0_torsion2);
1048  backrub_rotation_angles(start_constants, angle, start_bondangle, start_torsion1, start_torsion2);
1049 
1050  //TR << "Start: Delta bondangle: " << start_bondangle-start_0_bondangle
1051  // << " Delta torsion1: " << start_torsion1 - start_0_torsion1
1052  // << " Delta torsion2: " << start_torsion2 - start_0_torsion2 << std::endl;
1053 
1054  // Set bond angles directly
1055  pose.set_dof(id::DOF_ID(segment.start_atomid1(), id::THETA), pi - start_bondangle);
1056 
1057  // Set torsion angles by incrementing the oldest sibling PHI DOF
1058  //id::DOF_ID const start_dofid1(id::DOF_ID(start_atom1->parent()->get_nonjump_atom(0)->id(), id::PHI));
1059  id::DOF_ID const start_dofid1(id::DOF_ID(start_atom1->id(), id::PHI));
1060  pose.set_dof(start_dofid1, pose.dof(start_dofid1) - start_0_torsion1 + start_torsion1);
1061  id::DOF_ID const start_dofid2(id::DOF_ID(start_atom2->parent()->get_nonjump_atom(0)->id(), id::PHI));
1062  //id::DOF_ID const start_dofid2(id::DOF_ID(start_atom2->id(), id::PHI));
1063  pose.set_dof(start_dofid2, pose.dof(start_dofid2) - start_0_torsion2 + start_torsion2);
1064 
1065  //TR << start_atom1->id() << "\t" << start_atom1->parent()->get_nonjump_atom(0)->id() << std::endl;
1066  //TR << start_atom2->id() << "\t" << start_atom2->parent()->get_nonjump_atom(0)->id() << std::endl;
1067 
1068  // Only proceed if stub_atom2 != start_atom1
1069  if (start_atom->stub_atom2()->id() != segment.start_atomid1()) {
1070 
1071  // optimize branching atom angles around the start pivot
1072  if (!preserve_detailed_balance_) {
1073  branchopt_.optimize_angles(pose, start_atom->stub_atom2()->id(), segment.start_atomid(), segment.start_atomid1());
1074  }
1075  }
1076 
1077  // Only proceed if end_atom1 exists
1078  if (end_atom1) {
1079 
1080  // Get constants for analytically calculating updated DOF values
1081  // Only recalculate the constants if they haven't already been calculated
1082  if (end_constants.size() == 0) {
1083  backrub_rotation_constants(end_atom->parent()->parent(), end_atom->parent(), end_atom, end_atom1, end_atom2,
1084  start_atom, end_constants);
1085  }
1086 
1087  Real end_bondangle(0), end_torsion1(0), end_torsion2(0);
1088  Real end_0_bondangle(0), end_0_torsion1(0), end_0_torsion2(0);
1089  backrub_rotation_angles(end_constants, 0, end_0_bondangle, end_0_torsion1, end_0_torsion2);
1090  backrub_rotation_angles(end_constants, angle, end_bondangle, end_torsion1, end_torsion2);
1091 
1092  //TR << "End: Delta bondangle: " << end_bondangle-end_0_bondangle
1093  // << " Delta torsion1: " << end_torsion1 - end_0_torsion1
1094  // << " Delta torsion2: " << end_torsion2 - end_0_torsion2 << std::endl;
1095 
1096  // Set bond angles directly
1097  pose.set_dof(id::DOF_ID(end_atom1->id(), id::THETA), pi - end_bondangle);
1098 
1099  // Set torsion angle 1 by incrementing the oldest sibling PHI DOF
1100  id::DOF_ID const end_dofid1(id::DOF_ID(end_atom1->id(), id::PHI));
1101  pose.set_dof(end_dofid1, pose.dof(end_dofid1) - end_0_torsion1 + end_torsion1);
1102 
1103  // Only proceed if end_atom2 exists
1104  if (end_atom2) {
1105 
1106  // Set torsion angle 2 by incrementing the oldest sibling PHI DOF
1107  id::DOF_ID const end_dofid2(id::DOF_ID(end_atom2->id(), id::PHI));
1108  pose.set_dof(end_dofid2, pose.dof(end_dofid2) - end_0_torsion2 + end_torsion2);
1109  }
1110 
1111  // optimize branching atom angles around the end pivot
1112  if (!preserve_detailed_balance_) {
1113  branchopt_.optimize_angles(pose, end_atom->parent()->id(), segment.end_atomid(), end_atom1->id());
1114  }
1115  }
1116 
1117  /*
1118  Real end_atom_distsq(pose.xyz(end_atom->id()).distance_squared(end_atom_xyz));
1119  Real end_atom1_distsq(end_atom1 ? pose.xyz(end_atom1->id()).distance_squared(end_atom1_xyz) : 0);
1120  Real end_atom2_distsq(end_atom2 ? pose.xyz(end_atom2->id()).distance_squared(end_atom2_xyz) : 0);
1121 
1122  if (end_atom_distsq > 1e-4 || end_atom1_distsq > 1e-4 || end_atom2_distsq > 1e-4) {
1123 
1124  TR << "ERROR: " << start_atom->atom_id() << "\t" << end_atom->atom_id() << std::endl;
1125  TR << end_atom_distsq << "\t" << end_atom1_distsq << "\t" << end_atom2_distsq << std::endl;
1126  //runtime_assert(false);
1127  }
1128  */
1129 }
1130 
1131 core::Size
1133 {
1134  return next_segment_id_;
1135 }
1136 
1137 void
1139  core::Size next_segment_id
1140 )
1141 {
1142  next_segment_id_ = next_segment_id;
1143 }
1144 
1145 core::Size
1147 {
1148  return last_segment_id_;
1149 }
1150 
1153 {
1154  return last_start_atom_name_;
1155 }
1156 
1159 {
1160  return last_end_atom_name_;
1161 }
1162 
1163 core::Real
1165 {
1166  return last_angle_;
1167 }
1168 
1169 /// @detailed
1170 /// All move types are prefixed with "br". Sections are divided by underscores.
1171 /// The next two sections indicates the names of the atoms at the start and end
1172 /// of the backrub segment. The last section gives the size of the segment.
1173 void
1175 {
1176  std::stringstream mt;
1177 
1178  std::string start_atom_name(last_start_atom_name_);
1179  std::string end_atom_name(last_end_atom_name_);
1180  ObjexxFCL::strip(start_atom_name);
1181  ObjexxFCL::strip(end_atom_name);
1182 
1183  mt << "br_" << start_atom_name << "_" << end_atom_name << "_"
1184  << std::setw(2) << std::setfill('0') << segments_[last_segment_id_].size();
1185 
1186  std::string new_type(mt.str());
1187  type(new_type);
1188 }
1189 
1190 /// @detailed
1191 /// PM1 & PM2 are the parent and grandparent atoms (respectively) of the pivot
1192 /// atom, P. PP1 and PP2 are the child and grandchiled atoms (respectively) of
1193 /// the pivot atom. PM2 and PP2 are optional and may be NULL. REF is the other
1194 /// (reference) pivot atom that defines the rotation axis.
1195 ///
1196 /// The first 9 constants returned represent A1-A3, B1-B3, & C1-C3 as described
1197 /// in Betancourt 2005. The last 6 constants allow calculation of the signs of
1198 /// phi and psi. They could be called B4-B6 & C4-C6. For a given tau angle, phi
1199 /// is negative if the following is true:
1200 ///
1201 /// B4 < B5 * cos(B6 + tau)
1202 ///
1203 /// Similarly, psi is negative if the following is true:
1204 ///
1205 /// C4 < C5 * cos(C6 + tau)
1206 void
1214  utility::vector0<Real> & constants,
1215  core::Real const alpha_min, // = 0
1216  core::Real const alpha_max, // = 0
1217  numeric::IntervalSet<core::Real> *tau_intervals // = NULL
1218 )
1219 {
1220  using numeric::conversions::radians;
1221  using numeric::sin_cos_range;
1222  using numeric::in_sin_cos_range;
1223 
1224  Real static const pi(numeric::NumericTraits<Real>::pi());
1225 
1226  constants.resize(15);
1227  for (int i = 0; i < 15; i++) {
1228  constants[i] = 0;
1229  }
1230 
1231  PointPosition const & N(PM1_atom->xyz());
1232  PointPosition const & CA(P_atom->xyz());
1233  PointPosition const & C(PP1_atom->xyz());
1234  PointPosition const & CAref(REF_atom->xyz());
1235 
1236  PointPosition const V( (CA - N).normalize() );
1237  PointPosition const U( (C - CA).normalize() );
1238  PointPosition const R( (CAref - CA).normalize() );
1239 
1240  Real const sigma_v = std::acos(sin_cos_range(-dot(V, R))); // N->CA
1241  Real const sigma_u = std::acos(sin_cos_range(-dot(U, R))); // CA->C
1242 
1243  Real const alpha = std::acos(sin_cos_range(-dot(V, U))); // N-CA-C
1244 
1245  Real const sin_sigma_v = std::sin(sigma_v);
1246  Real const cos_sigma_v = std::cos(sigma_v);
1247  Real const sin_sigma_u = std::sin(sigma_u);
1248  Real const cos_sigma_u = std::cos(sigma_u);
1249  Real const cos_alpha = std::cos(alpha);
1250 
1251  Real const tau_u = ((dot(U, cross(V, R)) < 0) ? -1 : 1) *
1252  std::acos(sin_cos_range((cos_alpha + cos_sigma_v * cos_sigma_u) /
1253  (sin_sigma_v * sin_sigma_u)));
1254 
1255  Real const a1 = constants[0] = sin_sigma_v * sin_sigma_u * std::cos(tau_u);
1256  Real const b1 = constants[1] = -sin_sigma_v * sin_sigma_u * std::sin(tau_u);
1257  Real const c1 = constants[2] = -cos_sigma_v * cos_sigma_u;
1258 
1259  if (PM2_atom) {
1260 
1261  PointPosition const & Cm1(PM2_atom->xyz());
1262 
1263  PointPosition const W( (N - Cm1).normalize() );
1264 
1265  Real const sigma_w = std::acos(sin_cos_range(-dot(W, R))); // C(-1)->N
1266 
1267  Real const gamma = std::acos(sin_cos_range(-dot(W, V))); // C(-1)-N-CA
1268 
1269  Real const sin_sigma_w = std::sin(sigma_w);
1270  Real const cos_sigma_w = std::cos(sigma_w);
1271  Real const sin_gamma = std::sin(gamma);
1272  Real const cos_gamma = std::cos(gamma);
1273 
1274  Real const tau_w = ((dot(U, cross(W, R)) < 0) ? -1 : 1) *
1275  std::acos(sin_cos_range((-dot(W, U) + cos_sigma_w * cos_sigma_u) /
1276  (sin_sigma_w * sin_sigma_u)));
1277 
1278  constants[3] = (sin_sigma_w * sin_sigma_u * std::cos(tau_w) + a1 * cos_gamma) / sin_gamma;
1279  constants[4] = (-sin_sigma_w * sin_sigma_u * std::sin(tau_w) + b1 * cos_gamma) / sin_gamma;
1280  constants[5] = (-cos_sigma_u * cos_sigma_w + c1 * cos_gamma) / sin_gamma;
1281 
1282  PointPosition const Wn( (cross(W, V)).normalize() ); // V-W plane normal
1283 
1284  Real const sigma_wn = std::acos(sin_cos_range(-dot(Wn, R)));
1285 
1286  Real const sin_sigma_wn = std::sin(sigma_wn);
1287  Real const cos_sigma_wn = std::cos(sigma_wn);
1288 
1289  Real const tau_wn = ((dot(U, cross(Wn, R)) < 0) ? -1 : 1) *
1290  std::acos(sin_cos_range((-dot(Wn, U) + cos_sigma_wn * cos_sigma_u) /
1291  (sin_sigma_wn * sin_sigma_u)));
1292 
1293  constants[9] = cos_sigma_wn * cos_sigma_u;
1294  constants[10] = sin_sigma_wn * sin_sigma_u;
1295  constants[11] = tau_wn;
1296  }
1297 
1298  if (PP2_atom) {
1299 
1300  PointPosition const & Np1(PP2_atom->xyz());
1301 
1302  PointPosition const W1( (Np1 - C).normalize() );
1303 
1304  Real const sigma_w1 = std::acos(sin_cos_range(-dot(W1, R))); // C->N(+1)
1305 
1306  Real const beta = std::acos(sin_cos_range(-dot(U, W1))); // CA-C-N(+1)
1307 
1308  Real const sin_sigma_w1 = std::sin(sigma_w1);
1309  Real const cos_sigma_w1 = std::cos(sigma_w1);
1310  Real const sin_beta = std::sin(beta);
1311  Real const cos_beta = std::cos(beta);
1312 
1313  Real const tau_w1 = ((dot(W1, cross(V, R)) < 0) ? -1 : 1) *
1314  std::acos(sin_cos_range((-dot(V, W1) + cos_sigma_v * cos_sigma_w1) /
1315  (sin_sigma_v * sin_sigma_w1)));
1316 
1317  constants[6] = (sin_sigma_v * sin_sigma_w1 * std::cos(tau_w1) + a1 * cos_beta) / sin_beta;
1318  constants[7] = (-sin_sigma_v * sin_sigma_w1 * std::sin(tau_w1) + b1 * cos_beta) / sin_beta;
1319  constants[8] = (-cos_sigma_v * cos_sigma_w1 + c1 * cos_beta) / sin_beta;
1320 
1321  PointPosition const W1n( (cross(U, W1)).normalize() ); // U-W1 plane normal
1322 
1323  Real const sigma_w1n = std::acos(sin_cos_range(-dot(W1n, R)));
1324 
1325  Real const sin_sigma_w1n = std::sin(sigma_w1n);
1326  Real const cos_sigma_w1n = std::cos(sigma_w1n);
1327 
1328  Real const tau_w1n = ((dot(W1n, cross(V, R)) < 0) ? -1 : 1) *
1329  std::acos(sin_cos_range((-dot(V, W1n) + cos_sigma_v * cos_sigma_w1n) /
1330  (sin_sigma_v * sin_sigma_w1n)));
1331 
1332  constants[12] = cos_sigma_w1n * cos_sigma_v;
1333  constants[13] = sin_sigma_w1n * sin_sigma_v;
1334  constants[14] = tau_w1n;
1335  }
1336 
1337  if (tau_intervals != NULL && alpha_min >= 0 && alpha_max > alpha_min) {
1338 
1339  if (alpha_min == 0 && alpha_max == pi) {
1340 
1341  // easiest base case: unconstrained
1342  tau_intervals->set(-pi, pi);
1343 
1344  } else {
1345 
1346  numeric::IntervalSet<Real> min_intervals;
1347  numeric::IntervalSet<Real> max_intervals;
1348 
1349  Real const min_value = (cos_sigma_v * cos_sigma_u + std::cos(alpha_min)) / (sin_sigma_v * sin_sigma_u);
1350 
1351  if (in_sin_cos_range(min_value, 0.00000001)) {
1352 
1353  Real const acos_min = std::acos(sin_cos_range(min_value));
1354  Real tau1 = -acos_min - tau_u;
1355  Real tau2 = acos_min - tau_u;
1356 
1357  tau1 = numeric::nearest_angle_radians(tau1, 0.);
1358  tau2 = numeric::nearest_angle_radians(tau2, 0.);
1359 
1360  if (tau1 > tau2) {
1361  Real const temp = tau1;
1362  tau1 = tau2;
1363  tau2 = temp;
1364  }
1365 
1366  Real const alpha_mid = std::acos(sin_cos_range(sin_sigma_v * sin_sigma_u *
1367  std::cos(tau_u + (tau1 + tau2)/2) - cos_sigma_v * cos_sigma_u));
1368 
1369  if (alpha_mid > alpha_min) {
1370  min_intervals.set(tau1, tau2);
1371  } else {
1372  min_intervals.set(-pi, tau1, tau2, pi);
1373  }
1374  } else if (alpha > alpha_min) {
1375  min_intervals.set(-pi, pi);
1376  } else {
1377  //std::cout << "Error: No tau angles meet minimum alpha bond angle" << std::endl;
1378  }
1379 
1380  /*
1381  if (min_intervals.endpoints().size() && !min_intervals.is_inside(0)) {
1382  std::cout << "Min not inside " << tau_u << " "
1383  << (in_sin_cos_range(min_value) ? std::acos(sin_cos_range(min_value)) : -1) << " "
1384  << min_value << std::endl;
1385  std::cout << min_intervals << std::endl;
1386  }
1387  */
1388 
1389  Real const max_value = (cos_sigma_v * cos_sigma_u + std::cos(alpha_max)) / (sin_sigma_v * sin_sigma_u);
1390 
1391  if (in_sin_cos_range(max_value, 0.00000001)) {
1392 
1393  Real const acos_max = std::acos(sin_cos_range(max_value));
1394  Real tau1 = -acos_max - tau_u;
1395  Real tau2 = acos_max - tau_u;
1396 
1397  tau1 = numeric::nearest_angle_radians(tau1, 0.);
1398  tau2 = numeric::nearest_angle_radians(tau2, 0.);
1399 
1400  if (tau1 > tau2) {
1401  Real const temp = tau1;
1402  tau1 = tau2;
1403  tau2 = temp;
1404  }
1405 
1406  Real const alpha_mid = std::acos(sin_cos_range(sin_sigma_v * sin_sigma_u *
1407  std::cos(tau_u + (tau1 + tau2)/2) - cos_sigma_v * cos_sigma_u));
1408 
1409  if (alpha_mid < alpha_max) {
1410  max_intervals.set(tau1, tau2);
1411  } else {
1412  max_intervals.set(-pi, tau1, tau2, pi);
1413  }
1414  } else if (alpha < alpha_max) {
1415  max_intervals.set(-pi, pi);
1416  } else {
1417  //std::cout << "Error: No tau angles meet maximum alpha bond angle" << std::endl;
1418  }
1419 
1420  /*
1421  if (max_intervals.endpoints().size() && !max_intervals.is_inside(0)) {
1422  std::cout << "Max not inside " << tau_u << " "
1423  << (in_sin_cos_range(max_value) ? std::acos(sin_cos_range(max_value)) : -1) << " "
1424  << max_value << std::endl;
1425  std::cout << max_intervals << std::endl;
1426  }
1427  */
1428 
1429  *tau_intervals = min_intervals & max_intervals;
1430  }
1431  }
1432 }
1433 
1434 /// @detailed
1435 /// tau is the angular displacement
1436 void
1438  utility::vector0<Real> const & constants,
1439  Real const tau,
1440  Real & bondange,
1441  Real & torsion1,
1442  Real & torsion2
1443 )
1444 {
1445  using numeric::sin_cos_range;
1446 
1447  Real const sin_tau = std::sin(tau);
1448  Real const cos_tau = std::cos(tau);
1449 
1450  bondange = std::acos(sin_cos_range(constants[0]*cos_tau + constants[1]*sin_tau + constants[2]));
1451 
1452  Real const sin_bondange = std::sin(bondange);
1453 
1454  torsion1 = acos(sin_cos_range((constants[3]*cos_tau + constants[4]*sin_tau + constants[5]) / sin_bondange));
1455  if (constants[9] < constants[10]*std::cos(constants[11] + tau)) torsion1 = -torsion1;
1456 
1457  torsion2 = acos(sin_cos_range((constants[6]*cos_tau + constants[7]*sin_tau + constants[8]) / sin_bondange));
1458  if (constants[12] < constants[13]*std::cos(constants[14] + tau)) torsion2 = -torsion2;
1459 }
1460 
1461 } // moves
1462 } // protocols