00001 #ifndef CCTBX_CRYSTAL_CLOSE_PACKING_H
00002 #define CCTBX_CRYSTAL_CLOSE_PACKING_H
00003
00004 #include <cctbx/crystal/direct_space_asu.h>
00005
00006 namespace cctbx { namespace crystal {
00007
00009 namespace close_packing {
00010
00011 namespace detail {
00012
00013 inline
00014 scitbx::vec3<int> const&
00015 twelve_neighbor_offsets(std::size_t i)
00016 {
00017 typedef scitbx::vec3<int> v;
00018 static const v offsets[] = {
00019 v(1,0,0),v(1,1,0),v(0,1,0),v(-1,0,0),v(-1,-1,0),v(0,-1,0),
00020 v(0,0,1),v(-1,-1,1),v(0,-1,1),
00021 v(0,0,-1),v(-1,-1,-1),v(0,-1,-1)
00022 };
00023 return offsets[i];
00024 }
00025
00026 }
00027
00029 template <typename FloatType=double>
00030 class hexagonal_sampling_generator
00031 {
00032 public:
00034 hexagonal_sampling_generator() {}
00035
00037
00061 hexagonal_sampling_generator(
00062 sgtbx::change_of_basis_op const& cb_op_original_to_sampling,
00063 direct_space_asu::float_asu<FloatType> const& float_asu,
00064 af::tiny<bool, 3> const& continuous_shift_flags,
00065 FloatType const& point_distance,
00066 FloatType const& buffer_thickness=-1,
00067 bool all_twelve_neighbors=false)
00068 :
00069 cb_op_original_to_sampling_(cb_op_original_to_sampling),
00070 float_asu_(float_asu),
00071 continuous_shift_flags_(continuous_shift_flags),
00072 point_distance_(point_distance),
00073 buffer_thickness_(buffer_thickness),
00074 all_twelve_neighbors_(all_twelve_neighbors),
00075 sampling_cell_(af::double6(
00076 point_distance, point_distance, point_distance*std::sqrt(8/3.),
00077 90, 90, 120)),
00078 box_lower_(0,0,0),
00079 box_upper_(0,0,0),
00080 loop_status_(0)
00081 {
00082 if (buffer_thickness_ < 0) {
00083 buffer_thickness_ = point_distance * (2/3. * (1/2. * std::sqrt(3.)));
00084 }
00085 float_asu_buffer_ = float_asu_.add_buffer(buffer_thickness_);
00086 sampling_box_determination();
00087 hex_to_frac_matrix_ = float_asu_.unit_cell().fractionalization_matrix()
00088 * sampling_cell_.orthogonalization_matrix();
00089 if (all_twelve_neighbors_) {
00090 precompute_twelve_neighbor_offsets_frac();
00091 }
00092 cb_op_r_inv_ = cb_op_original_to_sampling_.c_inv().r()
00093 .as_floating_point(scitbx::type_holder<FloatType>());
00094 cb_op_t_inv_ = cb_op_original_to_sampling_.c_inv().t()
00095 .as_floating_point(scitbx::type_holder<FloatType>());
00096 incr();
00097 }
00098
00100 sgtbx::change_of_basis_op const&
00101 cb_op_original_to_sampling() const {return cb_op_original_to_sampling_;}
00102
00104 direct_space_asu::float_asu<FloatType> const&
00105 float_asu() const { return float_asu_; }
00106
00108
00110 af::tiny<bool, 3> const&
00111 continuous_shift_flags() const { return continuous_shift_flags_; }
00112
00114 FloatType const&
00115 point_distance() const { return point_distance_; }
00116
00120 FloatType const&
00121 buffer_thickness() const { return buffer_thickness_; }
00122
00124 bool
00125 all_twelve_neighbors() const { return all_twelve_neighbors_; }
00126
00128
00130 scitbx::vec3<int> const&
00131 box_lower() const { return box_lower_; }
00132
00134
00136 scitbx::vec3<int> const&
00137 box_upper() const { return box_upper_; }
00138
00142 bool
00143 at_end() const { return loop_status_ < 0; }
00144
00146
00155 fractional<FloatType>
00156 next_site_frac()
00157 {
00158 CCTBX_ASSERT(!at_end());
00159 fractional<FloatType> result = get_site_frac_original();
00160 incr();
00161 return result;
00162 }
00163
00165
00170 af::shared<scitbx::vec3<FloatType> >
00171 all_sites_frac()
00172 {
00173 CCTBX_ASSERT(!at_end());
00174 af::shared<scitbx::vec3<FloatType> > result;
00175 while (!at_end()) {
00176 result.push_back(get_site_frac_original());
00177 incr();
00178 }
00179 return result;
00180 }
00181
00183 void
00184 restart()
00185 {
00186 loop_status_ = 0;
00187 incr();
00188 }
00189
00191
00193 std::size_t
00194 count_sites()
00195 {
00196 std::size_t result = 0;
00197 while (!at_end()) {
00198 incr();
00199 result++;
00200 }
00201 return result;
00202 }
00203
00204 protected:
00205 sgtbx::change_of_basis_op cb_op_original_to_sampling_;
00206 direct_space_asu::float_asu<FloatType> float_asu_;
00207 af::tiny<bool, 3> continuous_shift_flags_;
00208 FloatType point_distance_;
00209 FloatType buffer_thickness_;
00210 bool all_twelve_neighbors_;
00211 uctbx::unit_cell sampling_cell_;
00212 direct_space_asu::float_asu<FloatType> float_asu_buffer_;
00213 scitbx::vec3<FloatType> box_pivot_;
00214 scitbx::vec3<int> box_lower_;
00215 scitbx::vec3<int> box_upper_;
00216 scitbx::mat3<FloatType> hex_to_frac_matrix_;
00217 af::tiny<af::tiny<scitbx::vec3<FloatType>, 12>, 2>
00218 twelve_neighbor_offsets_frac_;
00219 scitbx::mat3<FloatType> cb_op_r_inv_;
00220 scitbx::vec3<FloatType> cb_op_t_inv_;
00221
00222 int loop_status_;
00223 scitbx::vec3<int> point_;
00224 fractional<FloatType> site_frac_sampling_;
00225 int point_2_mod_2_;
00226 std::size_t i12_;
00227
00228 void
00229 sampling_box_determination()
00230 {
00231 typedef scitbx::vec3<FloatType> v;
00232 typedef cartesian<FloatType> c;
00233 typedef scitbx::math::float_int_conversions<FloatType, int> fic;
00234 af::shared<v> asu_vertices_cart = float_asu_.volume_vertices(true);
00235 CCTBX_ASSERT(asu_vertices_cart.size() > 0);
00236 v box_max = sampling_cell_.fractionalize(c(asu_vertices_cart[0]));
00237 FloatType pivot_dist_sq = box_max.length_sq();
00238 box_pivot_ = box_max;
00239 for(std::size_t i=1;i<asu_vertices_cart.size();i++) {
00240 v vertex_hex = sampling_cell_.fractionalize(c(asu_vertices_cart[i]));
00241 box_max.each_update_max(vertex_hex);
00242 FloatType dist_sq = vertex_hex.length_sq();
00243 if (pivot_dist_sq > dist_sq) {
00244 pivot_dist_sq = dist_sq;
00245 box_pivot_ = vertex_hex;
00246 }
00247 }
00248 asu_vertices_cart = float_asu_buffer_.volume_vertices(true);
00249 CCTBX_ASSERT(asu_vertices_cart.size() > 0);
00250 v box_buffer_min = sampling_cell_.fractionalize(
00251 c(asu_vertices_cart[0]));
00252 v box_buffer_max = box_buffer_min;
00253 for(std::size_t i=1;i<asu_vertices_cart.size();i++) {
00254 v vertex_hex = sampling_cell_.fractionalize(c(asu_vertices_cart[i]));
00255 box_buffer_min.each_update_min(vertex_hex);
00256 box_buffer_max.each_update_max(vertex_hex);
00257 }
00258 for(std::size_t i=0;i<3;i++) {
00259 if (!continuous_shift_flags_[i]) {
00260 box_lower_[i] = std::min(-2,
00261 fic::ifloor(box_buffer_min[i]-box_pivot_[i]));
00262 int n = fic::iceil(scitbx::fn::absolute(box_max[i]-box_pivot_[i]));
00263 box_upper_[i] = n+std::max(2,
00264 fic::iceil(box_buffer_max[i]-box_max[i]));
00265 }
00266 }
00267 }
00268
00269 static
00270 scitbx::vec3<FloatType>
00271 indices_as_site(scitbx::vec3<int> const& point, int layer=0)
00272 {
00273 typedef scitbx::vec3<FloatType> v;
00274 if (layer % 2 == 0) {
00275 if (point[2] % 2 == 0) {
00276 return v(point[0],point[1],point[2]*.5);
00277 }
00278 return v(point[0]+1/3.,point[1]+2/3.,point[2]*.5);
00279 }
00280 else {
00281 if (point[2] % 2 == 0) {
00282 return v(-point[0],-point[1],point[2]*.5);
00283 }
00284 return v(-point[0]-1/3.,-point[1]-2/3.,point[2]*.5);
00285 }
00286 }
00287
00288 void
00289 precompute_twelve_neighbor_offsets_frac()
00290 {
00291 for(int layer=0;layer<=1;layer++) {
00292 for(std::size_t i12=0;i12<12;i12++) {
00293 twelve_neighbor_offsets_frac_[layer][i12] =
00294 hex_to_frac_matrix_ * indices_as_site(
00295 detail::twelve_neighbor_offsets(i12), layer);
00296 }
00297 }
00298 }
00299
00300 void
00301 incr()
00302 {
00303 if (loop_status_ == 1) goto continue_after_return_1;
00304 if (loop_status_ == 2) goto continue_after_return_2;
00305 for(point_[0]=box_lower_[0];point_[0]<=box_upper_[0];point_[0]++)
00306 for(point_[1]=box_lower_[1];point_[1]<=box_upper_[1];point_[1]++)
00307 for(point_[2]=box_lower_[2];point_[2]<=box_upper_[2];point_[2]++) {
00308 site_frac_sampling_ = hex_to_frac_matrix_
00309 * (box_pivot_ + indices_as_site(point_));
00310 if (float_asu_buffer_.is_inside(site_frac_sampling_)) {
00311 loop_status_ = 1;
00312 return;
00313 continue_after_return_1:;
00314 }
00315 else if (all_twelve_neighbors_) {
00316 point_2_mod_2_ = scitbx::math::mod_positive(point_[2], 2);
00317 for(i12_=0;i12_<12;i12_++) {
00318 if (float_asu_.is_inside(
00319 site_frac_sampling_
00320 + twelve_neighbor_offsets_frac_[point_2_mod_2_][i12_])) {
00321 loop_status_ = 2;
00322 return;
00323 continue_after_return_2:
00324 break;
00325 }
00326 }
00327 }
00328 }
00329 loop_status_ = -1;
00330 }
00331
00332 fractional<FloatType>
00333 get_site_frac_original() const
00334 {
00335 return cb_op_r_inv_ * site_frac_sampling_ + cb_op_t_inv_;
00336 }
00337 };
00338
00339 }}}
00340
00341 #endif // CCTBX_CRYSTAL_CLOSE_PACKING_H