32 #include <basic/options/option.hh>
38 #include <basic/Tracer.hh>
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>
48 #include <utility/exit.hh>
49 #include <utility/string_util.hh>
50 #include <utility/tag/Tag.hh>
53 #include <ObjexxFCL/string.functions.hh>
61 #include <basic/options/keys/backrub.OptionKeys.gen.hh>
65 #include <utility/vector0.hh>
66 #include <utility/vector1.hh>
67 #include <utility/keys/Key3Vector.hh>
73 using namespace core::pose;
75 static numeric::random::RandomGenerator
RG(2225782);
76 static basic::Tracer
TR(
"protocols.backrub.BackrubMover");
83 return BackrubMoverCreator::mover_name();
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.)),
104 preserve_detailed_balance_(false),
105 require_mm_bend_(true)
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_)
140 using namespace basic::options;
141 using namespace basic::options::OptionKeys;
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]);
150 mover.
set_min_atoms(option[ OptionKeys::backrub::min_atoms ]);
151 mover.
set_max_atoms(option[ OptionKeys::backrub::max_atoms ]);
169 if ( tag->hasOption(
"pivot_residues") ) {
173 if ( tag->hasOption(
"pivot_atoms") ) {
175 pivot_atoms_ = utility::string_split( pivot_atoms_string,
',' );
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() ) );
189 add_mainchain_segments();
191 if ( ! branchopt_.initialized() ) branchopt_.read_database();
201 if ( ! branchopt_.initialized() ) branchopt_.read_database();
203 if (!(num_segments() && get_input_pose() && get_input_pose()->fold_tree() == pose.
fold_tree())) {
205 if (!(get_input_pose() && get_input_pose()->fold_tree() == pose.
fold_tree())) {
212 add_mainchain_segments();
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;
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());
230 optimize_branch_angles(pose);
240 if ( ! branchopt_.initialized() ) branchopt_.read_database();
242 if (!(num_segments() && get_input_pose() && get_input_pose()->fold_tree() == pose.
fold_tree())) {
244 if (!(get_input_pose() && get_input_pose()->fold_tree() == pose.
fold_tree())) {
249 add_mainchain_segments();
252 runtime_assert(segments_.size());
256 if (next_segment_id_) {
257 segment_id = next_segment_id_;
258 next_segment_id_ = 0;
260 segment_id =
RG.random_range(1, segments_.size());
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) {
280 last_angle_ = random_angle(pose, segment_id, start_constants, end_constants);
282 TR.Debug <<
"Applying " << numeric::conversions::degrees(last_angle_) <<
" degree rotation to segment " << segment_id
286 if (last_angle_ != 0) {
287 rotate_segment(pose, segment_id, last_angle_, start_constants, end_constants);
295 return "BackrubMover";
316 for (
int tdist = 0; current; ++tdist) {
317 if (ancestor == current)
return tdist;
318 current = current->parent();
343 PoseCOP input_pose(get_input_pose());
345 runtime_assert(input_pose);
362 start_atom = end_atom;
363 start_atomid = end_atomid;
364 end_atom = temp_atom;
365 end_atomid = temp_atomid;
371 TR.Warning <<
"Warning: Backrub segment " << start_atomid <<
" to " << end_atomid <<
" invalid, ignoring"
378 TR.Warning <<
"Warning: Backrub segment " << start_atomid <<
" to " << end_atomid <<
" too short, ignoring"
384 if (
Size segid = segment_id(start_atomid, end_atomid) ) {
385 TR.Warning <<
"Warning: Backrub segment " << start_atomid <<
" to " << end_atomid <<
" already exists, ignoring"
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;
400 id::AtomID start_atomid1(end_atom->parent()->id());
403 current_atom = current_atom->parent()) {
404 start_atomid2 = start_atomid1;
405 start_atomid1 = current_atom->id();
409 if ( start_atom->stub_atom2()->id() == start_atomid1 ) {
415 TR.Debug <<
"Adding Backrub segment " << start_atomid <<
" to " << end_atomid <<
" (size " << tdist+1 <<
")" << std::endl;
418 if (max_angle_disp == 0) {
420 max_angle_disp = max_angle_disp_4_ + (tdist+1 - 4) * max_angle_disp_slope_;
422 max_angle_disp = max_angle_disp_7_ + (tdist+1 - 7) * max_angle_disp_slope_;
428 Size segment_id = segments_.size();
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;
448 Size mainchain_index(0);
449 for (
Size i = 1; i <= mainchain_atoms.size(); ++i) {
450 if (mainchain_atoms[i] == atomid.
atomno()) {
456 if (! mainchain_index)
return 0;
464 if (!mainchain_atoms.size())
break;
467 for (
Size i = 1; i <= residue.n_residue_connections(); ++i) {
470 if (residue.residue_connect_atom_index(i) == mainchain_atoms.front() && !residue.connection_incomplete(i)) {
474 Size connected_atomno(pose.
residue(resconid.resid()).residue_connect_atom_index(resconid.connid()));
476 if (mainchain_atoms.size() && mainchain_atoms.back() == connected_atomno) {
478 resnum = resconid.resid();
485 if (resnum == residue.seqpos())
break;
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();
504 for (
Size i = 1; i <= residue.n_residue_connections(); ++i) {
507 if (residue.residue_connect_atom_index(i) == mainchain_atoms.back() && !residue.connection_incomplete(i)) {
511 Size connected_atomno(pose.
residue(resconid.resid()).residue_connect_atom_index(resconid.connid()));
513 if (mainchain_atoms.size() && mainchain_atoms.front() == connected_atomno) {
515 resnum = resconid.resid();
522 return mainchain_index;
532 PoseCOP input_pose(get_input_pose());
534 runtime_assert(min_atoms >= 3 && max_atoms >= min_atoms);
536 std::set<id::AtomID> atomid_set(atomids.begin(), atomids.end());
539 while (atomid_set.size()) {
545 atomid_set.erase(*atomid_set.begin());
549 for (
Size i = 1; i <= mainchain_atomids.size(); ++i) {
552 if (atomid_set.count(mainchain_atomids[i])) {
554 atomid_set.erase(mainchain_atomids[i]);
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 ")) {
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])) {
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 ")) {
572 add_segment(mainchain_atomids[i], mainchain_atomids[j]);
590 PoseCOP input_pose(get_input_pose());
592 runtime_assert(min_atoms >= 3 && max_atoms >= min_atoms);
595 std::sort(resnums.begin(), resnums.end());
597 resnums.erase(new_end, resnums.end());
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];
606 while (contiguous_begin <= resnums.size()) {
610 while (contiguous_end+1 <= resnums.size() && resnums[contiguous_end]+1 == resnums[contiguous_end+1]) {
614 TR <<
"Adding backrub segments for residues " << resnums[contiguous_begin] <<
"-" << resnums[contiguous_end]
619 for (
core::Size i = contiguous_begin; i <= contiguous_end; ++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 ));
629 nsegments += add_mainchain_segments(mainchain_atomids, min_atoms, max_atoms);
632 contiguous_begin = contiguous_end+1;
635 TR <<
"Total Segments Added: " << num_segments() << std::endl;
644 if (resnums.size() == 0) {
646 for (
core::Size i = 1; i <= get_input_pose()->total_residue(); ++i) resnums.push_back(i);
650 return add_mainchain_segments(resnums, pivot_atoms_, min_atoms_, max_atoms_);
658 return add_mainchain_segments();
666 for (std::map<protocols::backrub::BackrubSegment::BondAngleKey, core::Size>::iterator iter(bond_angle_map_.begin());
667 iter != bond_angle_map_.end(); ++iter) {
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()
673 branchopt_.optimize_angles(pose, bond_angle_key.key1(), bond_angle_key.key2(), bond_angle_key.key3(), preserve_detailed_balance_);
681 return pivot_residues_;
689 pivot_residues_ = pivot_residues;
703 pivot_atoms_ = pivot_atoms;
717 min_atoms_ = min_atoms;
731 max_atoms_ = max_atoms;
737 return max_angle_disp_4_;
745 max_angle_disp_4_ = max_angle_disp_4;
751 return max_angle_disp_7_;
759 max_angle_disp_7_ = max_angle_disp_7;
765 return max_angle_disp_slope_;
773 max_angle_disp_slope_ = max_angle_disp_slope;
779 return preserve_detailed_balance_;
784 bool preserve_detailed_balance
787 preserve_detailed_balance_ = preserve_detailed_balance;
793 return require_mm_bend_;
801 require_mm_bend_ = require_mm_bend;
817 Real static const pi(numeric::NumericTraits<Real>::pi());
820 runtime_assert(preserve_detailed_balance_);
822 std::set<core::id::DOF_ID_Range> range_set;
824 for (
core::Size i = 1; i <= segments_.size(); ++i) {
837 if (start_atom->stub_atom2()->id() != segment.
start_atomid1()) {
840 Real start_Ktheta(0);
841 Real start_theta0(0);
842 Real start_energy0(0);
844 start_Ktheta, start_theta0, start_energy0);
847 Real start_angle_dev(std::sqrt(-0.6*std::log(0.05)/start_Ktheta));
850 pi - start_theta0 - start_angle_dev,
851 pi - start_theta0 + start_angle_dev));
867 branchopt_.overall_params(pose, end_atom->parent()->id(), segment.
end_atomid(), end_atom1->id(),
868 end_Ktheta, end_theta0, end_energy0);
871 Real end_angle_dev(std::sqrt(-0.6*std::log(0.05)/end_Ktheta));
874 pi - end_theta0 - end_angle_dev,
875 pi - end_theta0 + end_angle_dev));
904 Real static const pi(numeric::NumericTraits<Real>::pi());
919 numeric::IntervalSet<Real> tau_intervals_bond_angle(-pi, pi);
922 if (start_atom->stub_atom2()->id() != segment.
start_atomid1()) {
925 Real start_Ktheta(0);
926 Real start_theta0(0);
927 Real start_energy0(0);
929 start_Ktheta, start_theta0, start_energy0);
932 Real start_angle_dev(std::sqrt(-0.6*std::log(0.05)/start_Ktheta));
936 end_atom, start_constants, start_theta0 - start_angle_dev, start_theta0 + start_angle_dev,
937 &tau_intervals_bond_angle);
948 branchopt_.overall_params(pose, end_atom->parent()->id(), segment.
end_atomid(), end_atom1->id(),
949 end_Ktheta, end_theta0, end_energy0);
952 Real end_angle_dev(std::sqrt(-0.6*std::log(0.05)/end_Ktheta));
955 numeric::IntervalSet<Real> tau_intervals_bond_angle_end;
957 start_atom, end_constants, end_theta0 - end_angle_dev, end_theta0 + end_angle_dev,
958 &tau_intervals_bond_angle_end);
962 tau_intervals_bond_angle = tau_intervals_bond_angle & tau_intervals_bond_angle_end;
967 Real const angle_disp(segments_[segment_id].max_angle_disp());
968 numeric::IntervalSet<Real> tau_intervals_rotation_angle(-angle_disp, angle_disp);
970 numeric::IntervalSet<Real> tau_intervals(tau_intervals_bond_angle & tau_intervals_rotation_angle);
972 Real const tau_intervals_length(tau_intervals.length());
975 if (tau_intervals_length == 0) {
980 numeric::IntervalSet<Real> tau_intervals_rotation_angle_p;
981 Real const threshold(
RG.uniform());
982 for (
Size i = 0; i < 100000; i++) {
984 angle = tau_intervals.random_point(
RG);
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);
993 tau_intervals_rotation_angle_p.set(-pi, max_angle_p, min_angle_p, pi);
998 Real tau_intervals_length_p = (tau_intervals_bond_angle & tau_intervals_rotation_angle_p).length();
1000 if (tau_intervals_length_p == 0 || tau_intervals_length/tau_intervals_length_p >= threshold)
break;
1017 Real static const pi(numeric::NumericTraits<Real>::pi());
1039 if (start_constants.size() == 0) {
1041 end_atom, start_constants);
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);
1060 pose.
set_dof(start_dofid1, pose.
dof(start_dofid1) - start_0_torsion1 + start_torsion1);
1063 pose.
set_dof(start_dofid2, pose.
dof(start_dofid2) - start_0_torsion2 + start_torsion2);
1069 if (start_atom->stub_atom2()->id() != segment.
start_atomid1()) {
1072 if (!preserve_detailed_balance_) {
1082 if (end_constants.size() == 0) {
1084 start_atom, end_constants);
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);
1101 pose.
set_dof(end_dofid1, pose.
dof(end_dofid1) - end_0_torsion1 + end_torsion1);
1108 pose.
set_dof(end_dofid2, pose.
dof(end_dofid2) - end_0_torsion2 + end_torsion2);
1112 if (!preserve_detailed_balance_) {
1113 branchopt_.optimize_angles(pose, end_atom->parent()->id(), segment.
end_atomid(), end_atom1->id());
1134 return next_segment_id_;
1142 next_segment_id_ = next_segment_id;
1148 return last_segment_id_;
1154 return last_start_atom_name_;
1160 return last_end_atom_name_;
1176 std::stringstream
mt;
1178 std::string start_atom_name(last_start_atom_name_);
1180 ObjexxFCL::strip(start_atom_name);
1181 ObjexxFCL::strip(end_atom_name);
1183 mt <<
"br_" << start_atom_name <<
"_" << end_atom_name <<
"_"
1184 << std::setw(2) << std::setfill(
'0') << segments_[last_segment_id_].size();
1217 numeric::IntervalSet<core::Real> *tau_intervals
1220 using numeric::conversions::radians;
1221 using numeric::sin_cos_range;
1222 using numeric::in_sin_cos_range;
1224 Real static const pi(numeric::NumericTraits<Real>::pi());
1226 constants.resize(15);
1227 for (
int i = 0; i < 15; i++) {
1240 Real const sigma_v = std::acos(sin_cos_range(-dot(V, R)));
1241 Real const sigma_u = std::acos(sin_cos_range(-dot(U, R)));
1243 Real const alpha = std::acos(sin_cos_range(-dot(V, U)));
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);
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)));
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;
1265 Real const sigma_w = std::acos(sin_cos_range(-dot(W, R)));
1267 Real const gamma = std::acos(sin_cos_range(-dot(W, V)));
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);
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)));
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;
1284 Real const sigma_wn = std::acos(sin_cos_range(-dot(Wn, R)));
1286 Real const sin_sigma_wn = std::sin(sigma_wn);
1287 Real const cos_sigma_wn = std::cos(sigma_wn);
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)));
1293 constants[9] = cos_sigma_wn * cos_sigma_u;
1294 constants[10] = sin_sigma_wn * sin_sigma_u;
1295 constants[11] = tau_wn;
1304 Real const sigma_w1 = std::acos(sin_cos_range(-dot(W1, R)));
1306 Real const beta = std::acos(sin_cos_range(-dot(U, W1)));
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);
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)));
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;
1323 Real const sigma_w1n = std::acos(sin_cos_range(-dot(W1n, R)));
1325 Real const sin_sigma_w1n = std::sin(sigma_w1n);
1326 Real const cos_sigma_w1n = std::cos(sigma_w1n);
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)));
1332 constants[12] = cos_sigma_w1n * cos_sigma_v;
1333 constants[13] = sin_sigma_w1n * sin_sigma_v;
1334 constants[14] = tau_w1n;
1337 if (tau_intervals != NULL && alpha_min >= 0 && alpha_max > alpha_min) {
1339 if (alpha_min == 0 && alpha_max == pi) {
1342 tau_intervals->set(-pi, pi);
1346 numeric::IntervalSet<Real> min_intervals;
1347 numeric::IntervalSet<Real> max_intervals;
1349 Real const min_value = (cos_sigma_v * cos_sigma_u + std::cos(alpha_min)) / (sin_sigma_v * sin_sigma_u);
1351 if (in_sin_cos_range(min_value, 0.00000001)) {
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;
1357 tau1 = numeric::nearest_angle_radians(tau1, 0.);
1358 tau2 = numeric::nearest_angle_radians(tau2, 0.);
1361 Real const temp = tau1;
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));
1369 if (alpha_mid > alpha_min) {
1370 min_intervals.set(tau1, tau2);
1372 min_intervals.set(-pi, tau1, tau2, pi);
1374 }
else if (alpha > alpha_min) {
1375 min_intervals.set(-pi, pi);
1389 Real const max_value = (cos_sigma_v * cos_sigma_u + std::cos(alpha_max)) / (sin_sigma_v * sin_sigma_u);
1391 if (in_sin_cos_range(max_value, 0.00000001)) {
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;
1397 tau1 = numeric::nearest_angle_radians(tau1, 0.);
1398 tau2 = numeric::nearest_angle_radians(tau2, 0.);
1401 Real const temp = tau1;
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));
1409 if (alpha_mid < alpha_max) {
1410 max_intervals.set(tau1, tau2);
1412 max_intervals.set(-pi, tau1, tau2, pi);
1414 }
else if (alpha < alpha_max) {
1415 max_intervals.set(-pi, pi);
1429 *tau_intervals = min_intervals & max_intervals;
1445 using numeric::sin_cos_range;
1447 Real const sin_tau = std::sin(tau);
1448 Real const cos_tau = std::cos(tau);
1450 bondange = std::acos(sin_cos_range(constants[0]*cos_tau + constants[1]*sin_tau + constants[2]));
1452 Real const sin_bondange = std::sin(bondange);
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;
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;