00001 #ifndef CCTBX_GEOMETRY_RESTRAINTS_DIHEDRAL_H
00002 #define CCTBX_GEOMETRY_RESTRAINTS_DIHEDRAL_H
00003
00004 #include <cctbx/sgtbx/rt_mx.h>
00005 #include <cctbx/geometry_restraints/utils.h>
00006 #include <scitbx/constants.h>
00007 #include <scitbx/optional_copy.h>
00008
00009 namespace cctbx { namespace geometry_restraints {
00010
00012 struct dihedral_proxy
00013 {
00015 typedef af::tiny<unsigned, 4> i_seqs_type;
00016
00018 dihedral_proxy() {}
00019
00021 dihedral_proxy(
00022 i_seqs_type const& i_seqs_,
00023 double angle_ideal_,
00024 double weight_,
00025 int periodicity_=0)
00026 :
00027 angle_ideal(angle_ideal_),
00028 weight(weight_),
00029 periodicity(periodicity_),
00030 i_seqs(i_seqs_)
00031 {}
00032
00034 dihedral_proxy(
00035 i_seqs_type const& i_seqs_,
00036 dihedral_proxy const& params)
00037 :
00038 angle_ideal(params.angle_ideal),
00039 weight(params.weight),
00040 periodicity(params.periodicity),
00041 i_seqs(i_seqs_)
00042 {}
00043
00045 dihedral_proxy(
00046 i_seqs_type const& i_seqs_,
00047 af::shared<sgtbx::rt_mx> const& sym_ops_,
00048 double angle_ideal_,
00049 double weight_,
00050 int periodicity_=0)
00051 :
00052 angle_ideal(angle_ideal_),
00053 weight(weight_),
00054 periodicity(periodicity_),
00055 sym_ops(sym_ops_),
00056 i_seqs(i_seqs_)
00057 {
00058 if ( sym_ops.get() ) {
00059 CCTBX_ASSERT(sym_ops.get()->size() == i_seqs.size());
00060 }
00061 }
00062
00064 dihedral_proxy(
00065 i_seqs_type const& i_seqs_,
00066 af::shared<sgtbx::rt_mx> const& sym_ops_,
00067 dihedral_proxy const& params)
00068 :
00069 angle_ideal(params.angle_ideal),
00070 weight(params.weight),
00071 periodicity(params.periodicity),
00072 sym_ops(sym_ops_),
00073 i_seqs(i_seqs_)
00074 {
00075 if ( sym_ops.get() ) {
00076 CCTBX_ASSERT(sym_ops.get()->size() == i_seqs.size());
00077 }
00078 }
00079
00081 dihedral_proxy
00082 sort_i_seqs() const
00083 {
00084 dihedral_proxy result(*this);
00085 if (result.i_seqs[0] > result.i_seqs[3]) {
00086 std::swap(result.i_seqs[0], result.i_seqs[3]);
00087 if ( sym_ops.get() ) {
00088 std::swap(result.sym_ops[0], result.sym_ops[3]);
00089 }
00090 result.angle_ideal *= -1;
00091 }
00092 if (result.i_seqs[1] > result.i_seqs[2]) {
00093 std::swap(result.i_seqs[1], result.i_seqs[2]);
00094 if ( sym_ops.get() ) {
00095 std::swap(result.sym_ops[1], result.sym_ops[2]);
00096 }
00097 result.angle_ideal *= -1;
00098 }
00099 return result;
00100 }
00101
00103 double angle_ideal;
00105 double weight;
00107 int periodicity;
00109 i_seqs_type i_seqs;
00111 scitbx::optional_copy<af::shared<sgtbx::rt_mx> > sym_ops;
00112 };
00113
00115
00128 class dihedral
00129 {
00130 public:
00132 dihedral() {}
00133
00135 dihedral(
00136 af::tiny<scitbx::vec3<double>, 4> const& sites_,
00137 double angle_ideal_,
00138 double weight_,
00139 int periodicity_=0)
00140 :
00141 sites(sites_),
00142 angle_ideal(angle_ideal_),
00143 weight(weight_),
00144 periodicity(periodicity_)
00145 {
00146 init_angle_model();
00147 }
00148
00152 dihedral(
00153 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00154 dihedral_proxy const& proxy)
00155 :
00156 angle_ideal(proxy.angle_ideal),
00157 weight(proxy.weight),
00158 periodicity(proxy.periodicity)
00159 {
00160 for(int i=0;i<4;i++) {
00161 std::size_t i_seq = proxy.i_seqs[i];
00162 CCTBX_ASSERT(i_seq < sites_cart.size());
00163 sites[i] = sites_cart[i_seq];
00164 }
00165 init_angle_model();
00166 }
00167
00172 dihedral(
00173 uctbx::unit_cell const& unit_cell,
00174 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00175 dihedral_proxy const& proxy)
00176 :
00177 angle_ideal(proxy.angle_ideal),
00178 weight(proxy.weight),
00179 periodicity(proxy.periodicity)
00180 {
00181 for(int i=0;i<4;i++) {
00182 std::size_t i_seq = proxy.i_seqs[i];
00183 CCTBX_ASSERT(i_seq < sites_cart.size());
00184 sites[i] = sites_cart[i_seq];
00185 if ( proxy.sym_ops.get() ) {
00186 sgtbx::rt_mx rt_mx = proxy.sym_ops[i];
00187 if ( !rt_mx.is_unit_mx() ) {
00188 sites[i] = unit_cell.orthogonalize(
00189 rt_mx * unit_cell.fractionalize(sites[i]));
00190 }
00191 }
00192 }
00193 init_angle_model();
00194 }
00195
00197
00218 double
00219 residual() const
00220 {
00221 using scitbx::constants::pi_180;
00222 double term;
00223 if (periodicity > 0) {
00224 term = 9600. / (periodicity * periodicity)
00225 * (1 - std::cos(periodicity * delta * pi_180));
00226 }
00227 else {
00228 term = delta * delta;
00229 }
00230 return weight * term;
00231 }
00232
00234
00244 af::tiny<scitbx::vec3<double>, 4>
00245 gradients(double epsilon=1.e-100) const
00246 {
00247 af::tiny<scitbx::vec3<double>, 4> result;
00248 double d_21_norm = d_21.length_sq();
00249 if ( !have_angle_model
00250 || d_21_norm < epsilon
00251 || n_0121_norm < epsilon
00252 || n_2123_norm < epsilon) {
00253 result.fill(scitbx::vec3<double>(0,0,0));
00254 }
00255 else {
00256 using scitbx::constants::pi_180;
00257 double grad_factor;
00258 if (periodicity > 0) {
00259 grad_factor = 9600. / periodicity * pi_180
00260 * std::sin(periodicity * delta * pi_180);
00261 }
00262 else {
00263 grad_factor = 2 * delta;
00264 }
00265 grad_factor *= weight * d_21.length() / pi_180;
00266 result[0] = -grad_factor/n_0121_norm * n_0121;
00267 result[3] = grad_factor/n_2123_norm * n_2123;
00268 double d_01_dot_d_21 = d_01 * d_21;
00269 double d_21_dot_d_23 = d_21 * d_23;
00270 result[1] = (d_01_dot_d_21/d_21_norm-1) * result[0]
00271 - d_21_dot_d_23/d_21_norm * result[3];
00272 result[2] = (d_21_dot_d_23/d_21_norm-1) * result[3]
00273 - d_01_dot_d_21/d_21_norm * result[0];
00274 }
00275 return result;
00276 }
00277
00279
00281 void
00282 add_gradients(
00283 af::ref<scitbx::vec3<double> > const& gradient_array,
00284 dihedral_proxy::i_seqs_type const& i_seqs) const
00285 {
00286 af::tiny<scitbx::vec3<double>, 4> grads = gradients();
00287 for(int i=0;i<4;i++) {
00288 gradient_array[i_seqs[i]] += grads[i];
00289 }
00290 }
00291
00293
00298 void
00299 add_gradients(
00300 uctbx::unit_cell const& unit_cell,
00301 af::ref<scitbx::vec3<double> > const& gradient_array,
00302 dihedral_proxy const& proxy) const
00303 {
00304 dihedral_proxy::i_seqs_type const& i_seqs = proxy.i_seqs;
00305 scitbx::optional_copy<af::shared<sgtbx::rt_mx> > const&
00306 sym_ops = proxy.sym_ops;
00307 af::tiny<scitbx::vec3<double>, 4> grads = gradients();
00308 for(int i=0;i<4;i++) {
00309 if ( sym_ops.get() && !sym_ops[i].is_unit_mx() ) {
00310 scitbx::mat3<double>
00311 r_inv_cart_ = r_inv_cart(unit_cell, sym_ops[i]);
00312 gradient_array[i_seqs[i]] += grads[i] * r_inv_cart_;
00313 }
00314 else { gradient_array[i_seqs[i]] += grads[i]; }
00315 }
00316 }
00317
00319 af::tiny<scitbx::vec3<double>, 4> sites;
00321 double angle_ideal;
00323 double weight;
00325 int periodicity;
00327 bool have_angle_model;
00328 protected:
00329 scitbx::vec3<double> d_01;
00330 scitbx::vec3<double> d_21;
00331 scitbx::vec3<double> d_23;
00332 scitbx::vec3<double> n_0121;
00333 double n_0121_norm;
00334 scitbx::vec3<double> n_2123;
00335 double n_2123_norm;
00336 public:
00338 double angle_model;
00344 double delta;
00345
00346 protected:
00347 void
00348 init_angle_model()
00349 {
00350 using scitbx::constants::pi_180;
00351 have_angle_model = false;
00352 angle_model = angle_ideal;
00353 delta = 0;
00354 d_01 = sites[0] - sites[1];
00355 d_21 = sites[2] - sites[1];
00356 d_23 = sites[2] - sites[3];
00357 n_0121 = d_01.cross(d_21);
00358 n_0121_norm = n_0121.length_sq();
00359 if (n_0121_norm == 0) return;
00360 n_2123 = d_21.cross(d_23);
00361 n_2123_norm = n_2123.length_sq();
00362 if (n_2123_norm == 0) return;
00363 double cos_angle_model = std::max(-1.,std::min(1.,
00364 n_0121 * n_2123 / std::sqrt(n_0121_norm * n_2123_norm)));
00365 angle_model = std::acos(cos_angle_model) / pi_180;
00366 if (d_21 * (n_0121.cross(n_2123)) < 0) {
00367 angle_model *= -1;
00368 }
00369 have_angle_model = true;
00370 delta = angle_delta_deg(angle_model, angle_ideal, periodicity);
00371 }
00372 };
00373
00375 inline
00376 std::size_t
00377 dihedral_count_harmonic(
00378 af::const_ref<dihedral_proxy> const& proxies)
00379 {
00380 std::size_t result = 0;
00381 for(std::size_t i=0;i<proxies.size();i++) {
00382 if (proxies[i].periodicity <= 0) result++;
00383 }
00384 return result;
00385 }
00386
00390 inline
00391 af::shared<double>
00392 dihedral_deltas(
00393 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00394 af::const_ref<dihedral_proxy> const& proxies)
00395 {
00396 return detail::generic_deltas<dihedral_proxy, dihedral>::get(
00397 sites_cart, proxies);
00398 }
00399
00403 inline
00404 af::shared<double>
00405 dihedral_residuals(
00406 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00407 af::const_ref<dihedral_proxy> const& proxies)
00408 {
00409 return detail::generic_residuals<dihedral_proxy, dihedral>::get(
00410 sites_cart, proxies);
00411 }
00412
00422 inline
00423 double
00424 dihedral_residual_sum(
00425 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00426 af::const_ref<dihedral_proxy> const& proxies,
00427 af::ref<scitbx::vec3<double> > const& gradient_array)
00428 {
00429 return detail::generic_residual_sum<dihedral_proxy, dihedral>::get(
00430 sites_cart, proxies, gradient_array);
00431 }
00432
00436 inline
00437 af::shared<double>
00438 dihedral_deltas(
00439 uctbx::unit_cell const& unit_cell,
00440 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00441 af::const_ref<dihedral_proxy> const& proxies)
00442 {
00443 return detail::generic_deltas<dihedral_proxy, dihedral>::get(
00444 unit_cell, sites_cart, proxies);
00445 }
00446
00450 inline
00451 af::shared<double>
00452 dihedral_residuals(
00453 uctbx::unit_cell const& unit_cell,
00454 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00455 af::const_ref<dihedral_proxy> const& proxies)
00456 {
00457 return detail::generic_residuals<dihedral_proxy, dihedral>::get(
00458 unit_cell, sites_cart, proxies);
00459 }
00460
00471 inline
00472 double
00473 dihedral_residual_sum(
00474 uctbx::unit_cell const& unit_cell,
00475 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00476 af::const_ref<dihedral_proxy> const& proxies,
00477 af::ref<scitbx::vec3<double> > const& gradient_array)
00478 {
00479 return detail::generic_residual_sum<dihedral_proxy, dihedral>::get(
00480 unit_cell, sites_cart, proxies, gradient_array);
00481 }
00482
00483 }}
00484
00485 #endif // CCTBX_GEOMETRY_RESTRAINTS_DIHEDRAL_H