00001 #ifndef CCTBX_UCTBX_H
00002 #define CCTBX_UCTBX_H
00003
00004 #include <cmath>
00005 #include <boost/numeric/conversion/cast.hpp>
00006 #include <boost/optional.hpp>
00007 #include <scitbx/constants.h>
00008 #include <scitbx/sym_mat3.h>
00009 #include <scitbx/array_family/tiny_types.h>
00010 #include <scitbx/array_family/small.h>
00011 #include <scitbx/array_family/shared.h>
00012 #include <scitbx/math/utils.h>
00013 #include <cctbx/coordinates.h>
00014 #include <cctbx/miller.h>
00015
00016 namespace cctbx {
00017
00018
00019 namespace sgtbx
00020 {
00021 class rot_mx;
00022 class change_of_basis_op;
00023 }
00024
00026 typedef scitbx::vec3<double> uc_vec3;
00028 typedef scitbx::mat3<double> uc_mat3;
00030 typedef scitbx::sym_mat3<double> uc_sym_mat3;
00031
00033 namespace uctbx {
00034
00036 inline double d_star_sq_as_stol_sq(double d_star_sq)
00037 {
00038 return d_star_sq * .25;
00039 }
00040
00042 inline double d_star_sq_as_two_stol(double d_star_sq)
00043 {
00044 return std::sqrt(d_star_sq);
00045 }
00046
00048 inline double d_star_sq_as_stol(double d_star_sq)
00049 {
00050 return std::sqrt(d_star_sq) * .5;
00051 }
00052
00054 inline double d_star_sq_as_d(double d_star_sq)
00055 {
00056 if (d_star_sq == 0.) return -1.;
00057 return 1. / std::sqrt(d_star_sq);
00058 }
00059
00061 inline double d_star_sq_as_two_theta(double d_star_sq, double wavelength,
00062 bool deg=false)
00063 {
00064 double sin_theta = d_star_sq_as_stol(d_star_sq) * wavelength;
00065 CCTBX_ASSERT(sin_theta <= 1.0);
00066 double result = 2. * std::asin(sin_theta);
00067 if (deg) return scitbx::rad_as_deg(result);
00068 return result;
00069 }
00070
00071 template <typename FloatType>
00072 FloatType
00073 mean_square_difference(
00074 scitbx::mat3<FloatType> const& a,
00075 scitbx::mat3<FloatType> const& b)
00076 {
00077 FloatType result = 0;
00078 for(std::size_t i=0;i<9;i++) {
00079 result += scitbx::fn::pow2(a[i] - b[i]);
00080 }
00081 return result;
00082 }
00083
00085
00097 class unit_cell
00098 {
00099 public:
00101
00106 unit_cell() : volume_(0) {}
00107
00109
00113 explicit
00114 unit_cell(af::small<double, 6> const& parameters);
00115
00117
00119 explicit
00120 unit_cell(af::double6 const& parameters);
00121
00123
00131 explicit
00132 unit_cell(uc_sym_mat3 const& metrical_matrix);
00133
00135
00137 explicit
00138 unit_cell(uc_mat3 const& orthogonalization_matrix);
00139
00141 af::double6 const&
00142 parameters() const { return params_; }
00143
00145 af::double6 const&
00146 reciprocal_parameters() const { return r_params_; }
00147
00149 uc_sym_mat3 const&
00150 metrical_matrix() const { return metr_mx_; }
00151
00153 uc_sym_mat3 const&
00154 reciprocal_metrical_matrix() const { return r_metr_mx_; }
00155
00157 double
00158 volume() const { return volume_; }
00159
00161 unit_cell
00162 reciprocal() const;
00163
00165 double
00166 longest_vector_sq() const;
00167
00169
00172 double
00173 shortest_vector_sq() const;
00174
00176 bool
00177 is_degenerate(double min_min_length_over_max_length=1.e-10,
00178 double min_volume_over_min_length=1.e-5);
00179
00181 bool
00182 is_similar_to(unit_cell const& other,
00183 double relative_length_tolerance=0.01,
00184 double absolute_angle_tolerance=1.) const;
00185
00187 af::shared<scitbx::mat3<int> >
00188 similarity_transformations(
00189 unit_cell const& other,
00190 double relative_length_tolerance=0.02,
00191 double absolute_angle_tolerance=2.,
00192 int unimodular_generator_range=1) const;
00193
00195
00196 uc_mat3 const& fractionalization_matrix() const { return frac_; }
00197
00199
00200 uc_mat3 const& orthogonalization_matrix() const { return orth_; }
00201
00203
00204 template <class IntType>
00205 uc_mat3
00206 grid_index_as_site_cart_matrix(
00207 scitbx::vec3<IntType> const& gridding) const
00208 {
00209 uc_mat3 result = orth_;
00210 for(unsigned i=0;i<3;i++) {
00211 CCTBX_ASSERT(gridding[i] > 0);
00212 double f = 1. / boost::numeric_cast<double>(gridding[i]);
00213 for(unsigned j=0;j<9;j+=3) result[i+j] *= f;
00214 }
00215 return result;
00216 }
00217
00219 template <class FloatType>
00220 scitbx::vec3<FloatType>
00221 fractionalize(scitbx::vec3<FloatType> const& site_cart) const
00222 {
00223
00224 return fractional<FloatType>(
00225 frac_[0] * site_cart[0]
00226 + frac_[1] * site_cart[1]
00227 + frac_[2] * site_cart[2],
00228 frac_[4] * site_cart[1]
00229 + frac_[5] * site_cart[2],
00230 frac_[8] * site_cart[2]);
00231 }
00232
00234 template <class FloatType>
00235 scitbx::vec3<FloatType>
00236 orthogonalize(scitbx::vec3<FloatType> const& site_frac) const
00237 {
00238
00239 return cartesian<FloatType>(
00240 orth_[0] * site_frac[0]
00241 + orth_[1] * site_frac[1]
00242 + orth_[2] * site_frac[2],
00243 orth_[4] * site_frac[1]
00244 + orth_[5] * site_frac[2],
00245 orth_[8] * site_frac[2]);
00246 }
00247
00249 template <typename FloatType>
00250 af::shared<scitbx::vec3<FloatType> >
00251 fractionalize(
00252 af::const_ref<scitbx::vec3<FloatType> > const& sites_cart) const
00253 {
00254 af::shared<scitbx::vec3<FloatType> > result(
00255 sites_cart.size(),
00256 af::init_functor_null<scitbx::vec3<FloatType> >());
00257 const scitbx::vec3<FloatType>* si = sites_cart.begin();
00258 scitbx::vec3<FloatType>* ri = result.begin();
00259 for(std::size_t i=0;i<sites_cart.size();i++,ri++,si++) {
00260
00261 (*ri)[0] = frac_[0] * (*si)[0]
00262 + frac_[1] * (*si)[1]
00263 + frac_[2] * (*si)[2];
00264 (*ri)[1] = frac_[4] * (*si)[1]
00265 + frac_[5] * (*si)[2];
00266 (*ri)[2] = frac_[8] * (*si)[2];
00267 }
00268 return result;
00269 }
00270
00272 template <typename FloatType>
00273 af::shared<scitbx::vec3<FloatType> >
00274 orthogonalize(
00275 af::const_ref<scitbx::vec3<FloatType> > const& sites_frac) const
00276 {
00277 af::shared<scitbx::vec3<FloatType> > result(
00278 sites_frac.size(),
00279 af::init_functor_null<scitbx::vec3<FloatType> >());
00280 const scitbx::vec3<FloatType>* si = sites_frac.begin();
00281 scitbx::vec3<FloatType>* ri = result.begin();
00282 for(std::size_t i=0;i<sites_frac.size();i++,ri++,si++) {
00283
00284 (*ri)[0] = orth_[0] * (*si)[0]
00285 + orth_[1] * (*si)[1]
00286 + orth_[2] * (*si)[2];
00287 (*ri)[1] = orth_[4] * (*si)[1]
00288 + orth_[5] * (*si)[2];
00289 (*ri)[2] = orth_[8] * (*si)[2];
00290 }
00291 return result;
00292 }
00293
00295
00297 template <class FloatType>
00298 scitbx::vec3<FloatType>
00299 v_times_fractionalization_matrix_transpose(
00300 scitbx::vec3<FloatType> const& v) const
00301 {
00302
00303 return fractional<FloatType>(
00304 frac_[0] * v[0],
00305 frac_[1] * v[0]
00306 + frac_[4] * v[1],
00307 frac_[2] * v[0]
00308 + frac_[5] * v[1]
00309 + frac_[8] * v[2]);
00310 }
00311
00312
00318 template <class FloatType>
00319 scitbx::vec3<FloatType>
00320 orthogonalize_gradient (scitbx::vec3<FloatType> const& v) const
00321 {
00322 return v_times_fractionalization_matrix_transpose(v);
00323 }
00324
00325
00329 template <class FloatType>
00330 scitbx::vec3<FloatType>
00331 fractionalize_gradient (const scitbx::vec3<FloatType>& g) const
00332 {
00333 const uc_mat3& O = orth_;
00334 return fractional<FloatType>(O[0]*g[0],
00335 O[1]*g[0] + O[4]*g[1],
00336 O[2]*g[0] + O[5]*g[1] + O[8]*g[2]);
00337 }
00338
00340
00342 template <class FloatType>
00343 FloatType
00344 length_sq(fractional<FloatType> const& site_frac) const
00345 {
00346 return orthogonalize(site_frac).length_sq();
00347 }
00348
00350 template <class FloatType>
00351 FloatType
00352 length(fractional<FloatType> const& site_frac) const
00353 {
00354 return std::sqrt(length_sq(site_frac));
00355 }
00356
00358
00360 template <class FloatType>
00361 FloatType
00362 distance_sq(fractional<FloatType> const& site_frac_1,
00363 fractional<FloatType> const& site_frac_2) const
00364 {
00365 return length_sq(fractional<FloatType>(site_frac_1 - site_frac_2));
00366 }
00367
00369 template <class FloatType>
00370 FloatType
00371 distance(fractional<FloatType> const& site_frac_1,
00372 fractional<FloatType> const& site_frac_2) const
00373 {
00374 return length(fractional<FloatType>(site_frac_1 - site_frac_2));
00375 }
00376
00378 template <class FloatType>
00379 boost::optional<FloatType>
00380 angle(fractional<FloatType> const& site_frac_1,
00381 fractional<FloatType> const& site_frac_2,
00382 fractional<FloatType> const& site_frac_3) const
00383 {
00384 cartesian<FloatType> vec_12 = orthogonalize(site_frac_1 - site_frac_2);
00385 cartesian<FloatType> vec_32 = orthogonalize(site_frac_3 - site_frac_2);
00386 FloatType length_12 = vec_12.length();
00387 FloatType length_32 = vec_32.length();
00388 if (length_12 == 0 || length_32 == 0) {
00389 return boost::optional<FloatType>();
00390 }
00391 const FloatType cos_angle = std::max(-1.,std::min(1.,
00392 (vec_12 * vec_32)/(length_12 * length_32)));
00393 return boost::optional<FloatType>(
00394 std::acos(cos_angle) / scitbx::constants::pi_180);
00395 }
00396
00398
00401 template <class FloatType>
00402 boost::optional<FloatType>
00403 dihedral(fractional<FloatType> const& site_frac_1,
00404 fractional<FloatType> const& site_frac_2,
00405 fractional<FloatType> const& site_frac_3,
00406 fractional<FloatType> const& site_frac_4) const
00407 {
00408 cartesian<FloatType> u = orthogonalize(site_frac_1 - site_frac_2);
00409 cartesian<FloatType> v = orthogonalize(site_frac_3 - site_frac_2);
00410 cartesian<FloatType> w = orthogonalize(site_frac_3 - site_frac_4);
00411 cartesian<FloatType> u_cross_v = u.cross(v);
00412 cartesian<FloatType> v_cross_w = v.cross(w);
00413 FloatType norm_u_cross_v = u_cross_v.length_sq();
00414 if (norm_u_cross_v == 0) return boost::optional<FloatType>();
00415 FloatType norm_v_cross_w = v_cross_w.length_sq();
00416 if (norm_v_cross_w == 0) return boost::optional<FloatType>();
00417 FloatType cos_angle = std::max(-1.,std::min(1.,
00418 u_cross_v * v_cross_w / std::sqrt(norm_u_cross_v * norm_v_cross_w)));
00419 FloatType angle = std::acos(cos_angle) / scitbx::constants::pi_180;
00420 if (u_cross_v * w < 0) {
00421 angle *= -1;
00422 }
00423 return boost::optional<FloatType>(angle);
00424 }
00425
00430 template <class FloatType>
00431 FloatType
00432 mod_short_length_sq(fractional<FloatType> const& site_frac) const
00433 {
00434 return length_sq(site_frac.mod_short());
00435 }
00436
00439 template <class FloatType>
00440 FloatType
00441 mod_short_length(fractional<FloatType> const& site_frac) const
00442 {
00443 return std::sqrt(mod_short_length_sq(site_frac));
00444 }
00445
00450 template <class FloatType>
00451 FloatType
00452 mod_short_distance_sq(fractional<FloatType> const& site_frac_1,
00453 fractional<FloatType> const& site_frac_2) const
00454 {
00455 return mod_short_length_sq(
00456 fractional<FloatType>(site_frac_1 - site_frac_2));
00457 }
00458
00461 template <class FloatType>
00462 FloatType
00463 mod_short_distance(fractional<FloatType> const& site_frac_1,
00464 fractional<FloatType> const& site_frac_2) const
00465 {
00466 return std::sqrt(mod_short_distance_sq(site_frac_1, site_frac_2));
00467 }
00468
00474 template <class FloatType>
00475 FloatType
00476 min_mod_short_distance_sq(
00477 af::const_ref<scitbx::vec3<FloatType> > const& sites_frac_1,
00478 fractional<FloatType> const& site_frac_2) const
00479 {
00480 FloatType
00481 result = mod_short_distance_sq(
00482 fractional<FloatType>(sites_frac_1[0]), site_frac_2);
00483 for(std::size_t i=1;i<sites_frac_1.size();i++) {
00484 scitbx::math::update_min(
00485 result, mod_short_distance_sq(
00486 fractional<FloatType>(sites_frac_1[i]), site_frac_2));
00487 }
00488 return result;
00489 }
00490
00494 template <class FloatType>
00495 FloatType
00496 min_mod_short_distance(
00497 af::const_ref<scitbx::vec3<FloatType> > const& sites_frac_1,
00498 fractional<FloatType> const& site_frac_2) const
00499 {
00500 return std::sqrt(min_mod_short_distance_sq(sites_frac_1, site_frac_2));
00501 }
00502
00504
00508 unit_cell
00509 change_basis(uc_mat3 const& c_inv_r, double r_den=1.) const;
00510
00512
00518 unit_cell
00519 change_basis(sgtbx::rot_mx const& c_inv_r) const;
00520
00522 unit_cell
00523 change_basis(sgtbx::change_of_basis_op const& cb_op) const;
00524
00531 miller::index<>
00532 max_miller_indices(double d_min, double tolerance=1.e-4) const;
00533
00535 template <typename NumType>
00536 double
00537 d_star_sq(miller::index<NumType> const& miller_index) const
00538 {
00539 return
00540 (miller_index[0] * miller_index[0]) * r_metr_mx_[0]
00541 + (miller_index[1] * miller_index[1]) * r_metr_mx_[1]
00542 + (miller_index[2] * miller_index[2]) * r_metr_mx_[2]
00543 + (2 * miller_index[0] * miller_index[1]) * r_metr_mx_[3]
00544 + (2 * miller_index[0] * miller_index[2]) * r_metr_mx_[4]
00545 + (2 * miller_index[1] * miller_index[2]) * r_metr_mx_[5];
00546 }
00547
00549 template <typename NumType>
00550 af::shared<double>
00551 d_star_sq(
00552 af::const_ref<miller::index<NumType> > const& miller_indices) const
00553 {
00554 af::shared<double> result(
00555 miller_indices.size(), af::init_functor_null<double>());
00556 for(std::size_t i=0;i<miller_indices.size();i++) {
00557 result[i] = d_star_sq(miller_indices[i]);
00558 }
00559 return result;
00560 }
00561
00563 template <typename NumType>
00564 double
00565 max_d_star_sq(
00566 af::const_ref<miller::index<NumType> > const& miller_indices) const
00567 {
00568 double result = 0;
00569 for(std::size_t i=0;i<miller_indices.size();i++) {
00570 scitbx::math::update_max(result, d_star_sq(miller_indices[i]));
00571 }
00572 return result;
00573 }
00574
00576 template <typename NumType>
00577 af::double2
00578 min_max_d_star_sq(
00579 af::const_ref<miller::index<NumType> > const& miller_indices) const
00580 {
00581 af::double2 result(0, 0);
00582 if (miller_indices.size()) {
00583 result.fill(d_star_sq(miller_indices[0]));
00584 for(std::size_t i=1;i<miller_indices.size();i++) {
00585 double q = d_star_sq(miller_indices[i]);
00586 scitbx::math::update_min(result[0], q);
00587 scitbx::math::update_max(result[1], q);
00588 }
00589 }
00590 return result;
00591 }
00592
00594 template <typename NumType>
00595 double
00596 stol_sq(miller::index<NumType> const& miller_index) const
00597 {
00598 return d_star_sq_as_stol_sq(d_star_sq(miller_index));
00599 }
00600
00602 template <typename NumType>
00603 af::shared<double>
00604 stol_sq(
00605 af::const_ref<miller::index<NumType> > const& miller_indices) const
00606 {
00607 af::shared<double> result(
00608 miller_indices.size(), af::init_functor_null<double>());
00609 for(std::size_t i=0;i<miller_indices.size();i++) {
00610 result[i] = stol_sq(miller_indices[i]);
00611 }
00612 return result;
00613 }
00614
00616 template <typename NumType>
00617 double
00618 two_stol(miller::index<NumType> const& miller_index) const
00619 {
00620 return d_star_sq_as_two_stol(d_star_sq(miller_index));
00621 }
00622
00624 template <typename NumType>
00625 af::shared<double>
00626 two_stol(
00627 af::const_ref<miller::index<NumType> > const& miller_indices) const
00628 {
00629 af::shared<double> result(
00630 miller_indices.size(), af::init_functor_null<double>());
00631 for(std::size_t i=0;i<miller_indices.size();i++) {
00632 result[i] = two_stol(miller_indices[i]);
00633 }
00634 return result;
00635 }
00636
00638 template <typename NumType>
00639 double
00640 stol(miller::index<NumType> const& miller_index) const
00641 {
00642 return d_star_sq_as_stol(d_star_sq(miller_index));
00643 }
00644
00646 template <typename NumType>
00647 af::shared<double>
00648 stol(af::const_ref<miller::index<NumType> > const& miller_indices) const
00649 {
00650 af::shared<double> result(
00651 miller_indices.size(), af::init_functor_null<double>());
00652 for(std::size_t i=0;i<miller_indices.size();i++) {
00653 result[i] = stol(miller_indices[i]);
00654 }
00655 return result;
00656 }
00657
00659 template <typename NumType>
00660 double
00661 d(miller::index<NumType> const& miller_index) const
00662 {
00663 return d_star_sq_as_d(d_star_sq(miller_index));
00664 }
00665
00667 template <typename NumType>
00668 af::shared<double>
00669 d(af::const_ref<miller::index<NumType> > const& miller_indices) const
00670 {
00671 af::shared<double> result(
00672 miller_indices.size(), af::init_functor_null<double>());
00673 for(std::size_t i=0;i<miller_indices.size();i++) {
00674 result[i] = d(miller_indices[i]);
00675 }
00676 return result;
00677 }
00678
00680 template <typename NumType>
00681 double
00682 two_theta(
00683 miller::index<NumType> const& miller_index,
00684 double wavelength,
00685 bool deg=false) const
00686 {
00687 return d_star_sq_as_two_theta(
00688 d_star_sq(miller_index), wavelength, deg);
00689 }
00690
00692 template <typename NumType>
00693 af::shared<double>
00694 two_theta(
00695 af::const_ref<miller::index<NumType> > const& miller_indices,
00696 double wavelength,
00697 bool deg=false) const
00698 {
00699 af::shared<double> result(
00700 miller_indices.size(), af::init_functor_null<double>());
00701 for(std::size_t i=0;i<miller_indices.size();i++) {
00702 result[i] = two_theta(miller_indices[i], wavelength, deg);
00703 }
00704 return result;
00705 }
00706
00708
00713 double
00714 bases_mean_square_difference(unit_cell const& other) const
00715 {
00716 return mean_square_difference(orth_, other.orth_) / 3;
00717 }
00718
00736 int
00737 compare_orthorhombic(
00738 const unit_cell& other) const;
00739
00761 int
00762 compare_monoclinic(
00763 const unit_cell& other,
00764 unsigned unique_axis,
00765 double angular_tolerance) const;
00766
00767 sgtbx::change_of_basis_op const&
00768 change_of_basis_op_for_best_monoclinic_beta() const;
00769
00770 protected:
00771 void init_volume();
00772 void init_reciprocal();
00773 void init_metrical_matrices();
00774 void init_orth_and_frac_matrices();
00775 void initialize();
00776
00777 af::double6 params_;
00778 af::double3 sin_ang_;
00779 af::double3 cos_ang_;
00780 double volume_;
00781 uc_sym_mat3 metr_mx_;
00782 af::double6 r_params_;
00783 af::double3 r_sin_ang_;
00784 af::double3 r_cos_ang_;
00785 uc_sym_mat3 r_metr_mx_;
00786 uc_mat3 frac_;
00787 uc_mat3 orth_;
00788 mutable double longest_vector_sq_;
00789 mutable double shortest_vector_sq_;
00790
00791
00792 unit_cell(
00793 af::double6 const& params,
00794 af::double3 const& sin_ang,
00795 af::double3 const& cos_ang,
00796 double volume,
00797 uc_sym_mat3 const& metr_mx,
00798 af::double6 const& r_params,
00799 af::double3 const& r_sin_ang,
00800 af::double3 const& r_cos_ang,
00801 uc_sym_mat3 const& r_metr_mx);
00802 };
00803
00807 template <typename FloatType>
00808 class incremental_d_star_sq
00809 {
00810 public:
00812 incremental_d_star_sq() {}
00813
00815
00817 incremental_d_star_sq(unit_cell const& ucell)
00818 {
00819 initialize(ucell.reciprocal_metrical_matrix());
00820 }
00821
00823 void update0(int h0)
00824 {
00825 h0_ = h0;
00826 im0_ = (h0_ * h0_) * r_g00_;
00827 }
00828
00830 void update1(int h1)
00831 {
00832 h1_ = h1;
00833 im1_ = im0_ + (h1_ * h1_) * r_g11_
00834 + (2 * h0_ * h1_) * r_g01_;
00835 }
00836
00838 FloatType get(int h2)
00839 {
00840 return im1_ + (h2 * h2) * r_g22_
00841 + (2 * h0_ * h2) * r_g02_
00842 + (2 * h1_ * h2) * r_g12_;
00843 }
00844
00845 protected:
00846 FloatType r_g00_, r_g11_, r_g22_, r_g01_, r_g02_, r_g12_;
00847 int h0_, h1_;
00848 FloatType im0_, im1_;
00849
00850 void initialize(uc_sym_mat3 const& r_g)
00851 {
00852 r_g00_ = r_g[0];
00853 r_g11_ = r_g[1];
00854 r_g22_ = r_g[2];
00855 r_g01_ = r_g[3];
00856 r_g02_ = r_g[4];
00857 r_g12_ = r_g[5];
00858 }
00859 };
00860
00861 }}
00862
00863 #endif // CCTBX_UCTBX_H