00001 #ifndef CCTBX_MAPTBX_STRUCTURE_FACTORS_H
00002 #define CCTBX_MAPTBX_STRUCTURE_FACTORS_H
00003
00004 #include <cctbx/sgtbx/reciprocal_space_asu.h>
00005 #include <cctbx/miller/sym_equiv.h>
00006 #include <cctbx/maptbx/utils.h>
00007 #include <scitbx/array_family/accessors/c_grid_padded.h>
00008 #include <scitbx/array_family/versa.h>
00009 #include <set>
00010
00011 namespace cctbx { namespace maptbx { namespace structure_factors {
00012
00014
00016 template <typename FloatType=double>
00017 class to_map
00018 {
00019 public:
00021 to_map() {}
00022
00024 template <typename OtherFloatType>
00025 to_map(
00026 sgtbx::space_group const& space_group,
00027 bool anomalous_flag,
00028 af::const_ref<miller::index<> > const& miller_indices,
00029 af::const_ref<std::complex<OtherFloatType> > const& structure_factors,
00030 af::int3 const& n_real,
00031 af::c_grid_padded<3> const& map_grid,
00032 bool conjugate_flag,
00033 bool treat_restricted=true)
00034 :
00035 complex_map_(map_grid)
00036 {
00037 init(space_group, anomalous_flag, miller_indices, structure_factors,
00038 n_real, conjugate_flag, treat_restricted);
00039 }
00040
00042 template <typename OtherFloatType>
00043 to_map(
00044 sgtbx::space_group const& space_group,
00045 bool anomalous_flag,
00046 af::const_ref<miller::index<> > const& miller_indices,
00047 af::const_ref<std::complex<OtherFloatType> > const& structure_factors,
00048 af::int3 const& n_real,
00049 af::flex_grid<> const& map_grid,
00050 bool conjugate_flag,
00051 bool treat_restricted=true)
00052 :
00053 complex_map_(af::c_grid_padded<3>(map_grid))
00054 {
00055 init(space_group, anomalous_flag, miller_indices, structure_factors,
00056 n_real, conjugate_flag, treat_restricted);
00057 }
00058
00059 af::versa<std::complex<FloatType>, af::c_grid_padded<3> >
00060 complex_map() const { return complex_map_; }
00061
00062 protected:
00063 af::versa<std::complex<FloatType>, af::c_grid_padded<3> > complex_map_;
00064
00065 template <typename OtherFloatType>
00066 void
00067 init(
00068 sgtbx::space_group const& space_group,
00069 bool anomalous_flag,
00070 af::const_ref<miller::index<> > const& miller_indices,
00071 af::const_ref<std::complex<OtherFloatType> > const& structure_factors,
00072 af::int3 const& n_real,
00073 bool conjugate_flag,
00074 bool treat_restricted)
00075 {
00076 CCTBX_ASSERT(complex_map_.accessor().all()
00077 .all_ge(complex_map_.accessor().focus()));
00078 af::int3 map_grid_focus(complex_map_.accessor().focus());
00079 std::size_t count_n_real_not_equal_map_grid_focus = 0;
00080 std::size_t i_focus_short = 3;
00081 int focus_short = 0;
00082 for(std::size_t i=0;i<3;i++) {
00083 CCTBX_ASSERT( map_grid_focus[i] == n_real[i]
00084 || map_grid_focus[i] == n_real[i]/2+1);
00085 if (map_grid_focus[i] != n_real[i]) {
00086 i_focus_short = i;
00087 focus_short = map_grid_focus[i];
00088 count_n_real_not_equal_map_grid_focus++;
00089 }
00090 }
00091 CCTBX_ASSERT(count_n_real_not_equal_map_grid_focus <= 1);
00092 CCTBX_ASSERT( anomalous_flag == false
00093 || count_n_real_not_equal_map_grid_focus == 0);
00094 int t_den = space_group.t_den();
00095 std::vector<std::complex<FloatType> > trig_table;
00096 trig_table.reserve(t_den);
00097 for(int ht=0;ht<t_den;ht++) {
00098 FloatType ht_angle = -scitbx::constants::two_pi * ht / t_den;
00099 trig_table.push_back(std::complex<FloatType>(
00100 std::cos(ht_angle),
00101 std::sin(ht_angle)));
00102 }
00103 std::set<miller::index<>, miller::fast_less_than<> > processed_mem;
00104 std::set<miller::index<>, miller::fast_less_than<> >* processed;
00105 if (treat_restricted && space_group.order_p() > 1) {
00106 processed = &processed_mem;
00107 }
00108 else {
00109 processed = 0;
00110 }
00111 int h_inv_t = -1;
00112 for(std::size_t i=0;i<miller_indices.size();i++) {
00113 miller::index<> const& h = miller_indices[i];
00114 if (h[0] == 0 && h[1] == 0 && h[2] == 0) {
00115
00116 complex_map_[0] += structure_factors[i];
00117 continue;
00118 }
00119 if (anomalous_flag && space_group.is_centric()) {
00120 h_inv_t = (h * space_group.inv_t()) % t_den;
00121 if (h_inv_t < 0) h_inv_t += t_den;
00122 }
00123 if (processed) processed->clear();
00124 for(std::size_t i_smx=0;i_smx<space_group.n_smx();i_smx++) {
00125 sgtbx::rt_mx const& s = space_group.smx(i_smx);
00126 int ht = (h * s.t()) % t_den;
00127 if (ht < 0) ht += t_den;
00128 std::complex<FloatType>
00129 term = structure_factors[i] * trig_table[ht];
00130 miller::index<> hr = h * s.r();
00131 if (conjugate_flag) hr = -hr;
00132 if (processed == 0 || processed->insert(hr).second) {
00133 af::int3 ih = h_as_ih_mod_array(hr, n_real);
00134 if (i_focus_short == 3 || ih[i_focus_short] < focus_short) {
00135 complex_map_(ih) += term;
00136 }
00137 }
00138 if (!anomalous_flag) {
00139 hr = -hr;
00140 if (processed == 0 || processed->insert(hr).second) {
00141 af::int3 ih = h_as_ih_mod_array(hr, n_real);
00142 if (i_focus_short == 3 || ih[i_focus_short] < focus_short) {
00143 complex_map_(ih) += std::conj(term);
00144 }
00145 }
00146 }
00147 else if (h_inv_t >= 0) {
00148 int mht = (t_den - ht + h_inv_t) % t_den;
00149 if (mht != ht) {
00150 term = structure_factors[i] * trig_table[mht];
00151 }
00152 hr = -hr;
00153 if (processed == 0 || processed->insert(hr).second) {
00154 af::int3 ih = h_as_ih_mod_array(hr, n_real);
00155 if (i_focus_short == 3 || ih[i_focus_short] < focus_short) {
00156 complex_map_(ih) += term;
00157 }
00158 }
00159 }
00160 }
00161 }
00162 if (!treat_restricted) {
00163 complex_map_[0] *= static_cast<FloatType>(space_group.order_p());
00164 }
00165 }
00166 };
00167
00169 template <typename FloatType=double>
00170 class from_map
00171 {
00172 public:
00173 from_map() {}
00174
00176 template <typename OtherFloatType>
00177 from_map(
00178 uctbx::unit_cell const& unit_cell,
00179 sgtbx::space_group_type const& sg_type,
00180 bool anomalous_flag,
00181 double d_min,
00182 af::const_ref<std::complex<OtherFloatType>,
00183 af::c_grid_padded<3> > const& complex_map,
00184 bool conjugate_flag,
00185 bool discard_indices_affected_by_aliasing=false)
00186 :
00187 n_indices_affected_by_aliasing_(0)
00188 {
00189 CCTBX_ASSERT(d_min > 0);
00190 double d_star_sq_max = 1. / (d_min * d_min);
00191 typedef typename af::c_grid_padded<3>::index_type index_type;
00192 index_type n_complex = complex_map.accessor().focus();
00193 sgtbx::reciprocal_space::asu asu(sg_type);
00194 sgtbx::space_group const& space_group = sg_type.group();
00195 miller::index<> h;
00196 miller::index<> mh;
00197 uctbx::incremental_d_star_sq<double> incr_d_star_sq(unit_cell);
00198 index_type ih;
00199 ih[2] = 1;
00200 for(ih[0]=0;ih[0]<n_complex[0];ih[0]++) {
00201 h[0] = ih_as_h(ih[0], n_complex[0]);
00202 mh[0] = -h[0];
00203 incr_d_star_sq.update0(h[0]);
00204 for(ih[1]=0;ih[1]<n_complex[1];ih[1]++,ih[2]=0) {
00205 h[1] = ih_as_h(ih[1], n_complex[1]);
00206 mh[1] = -h[1];
00207 incr_d_star_sq.update1(h[1]);
00208 for(;ih[2]<n_complex[2];ih[2]++) {
00209 if (anomalous_flag) {
00210 h[2] = ih_as_h(ih[2], n_complex[2]);
00211 }
00212 else {
00213 h[2] = ih[2];
00214 }
00215 if (incr_d_star_sq.get(h[2]) > d_star_sq_max) continue;
00216 if (discard_indices_affected_by_aliasing) {
00217 bool discard = false;
00218 if (ih[0]*2 == n_complex[0]) discard = true;
00219 else if (ih[1]*2 == n_complex[1]) discard = true;
00220 else if (anomalous_flag) {
00221 if (ih[2]*2 == n_complex[2]) discard = true;
00222 }
00223 if (discard) {
00224 n_indices_affected_by_aliasing_++;
00225 continue;
00226 }
00227 }
00228 else {
00229 CCTBX_ASSERT(ih[0]*2 != n_complex[0]);
00230 CCTBX_ASSERT(ih[1]*2 != n_complex[1]);
00231 if (anomalous_flag) {
00232 CCTBX_ASSERT(ih[2]*2 != n_complex[2]);
00233 }
00234 }
00235 mh[2] = -h[2];
00236 int asu_which = asu.which(h, mh);
00237 if (asu_which == 0) continue;
00238 sgtbx::phase_info phase_info(space_group, h, false);
00239 if (phase_info.is_sys_absent()) continue;
00240 bool f_conj = false;
00241 if (!anomalous_flag) {
00242 if (asu_which > 0) {
00243 miller_indices_.push_back(h);
00244 f_conj = conjugate_flag;
00245 }
00246 else {
00247 if (h[2] == 0) continue;
00248 miller_indices_.push_back(mh);
00249 f_conj = !conjugate_flag;
00250 }
00251 }
00252 else {
00253 if ( ((asu_which < 0) != conjugate_flag)
00254 && phase_info.is_centric()) {
00255 continue;
00256 }
00257 if (conjugate_flag) miller_indices_.push_back(mh);
00258 else miller_indices_.push_back(h);
00259 }
00260 if (f_conj) data_.push_back(std::conj(complex_map(ih)));
00261 else data_.push_back(complex_map(ih));
00262 }}}
00263 }
00264
00266 template <typename OtherFloatType>
00267 from_map(
00268 bool anomalous_flag,
00269 af::const_ref<miller::index<> > const& miller_indices,
00270 af::const_ref<std::complex<OtherFloatType>,
00271 af::c_grid_padded<3> > const& complex_map,
00272 bool conjugate_flag,
00273 bool allow_miller_indices_outside_map=false)
00274 :
00275 n_indices_affected_by_aliasing_(0)
00276 {
00277 af::int3 map_grid_focus = complex_map.accessor().focus();
00278 data_.reserve(miller_indices.size());
00279 for(std::size_t i=0;i<miller_indices.size();i++) {
00280 array_access aa(
00281 anomalous_flag, map_grid_focus, conjugate_flag, miller_indices[i]);
00282 if (aa.ih.all_ge(0)) {
00283 if (!aa.f_conj) data_.push_back(complex_map(aa.ih));
00284 else data_.push_back(std::conj(complex_map(aa.ih)));
00285 }
00286 else if (allow_miller_indices_outside_map) {
00287 outside_map_.push_back(data_.size());
00288 data_.push_back(0);
00289 }
00290 else {
00291 throw_error_not_in_map();
00292 }
00293 }
00294 }
00295
00297 template <typename OtherFloatType>
00298 from_map(
00299 sgtbx::space_group const& space_group,
00300 bool anomalous_flag,
00301 af::const_ref<miller::index<> > const& miller_indices,
00302 af::const_ref<std::complex<OtherFloatType>,
00303 af::c_grid_padded<3> > const& complex_map,
00304 bool conjugate_flag)
00305 :
00306 n_indices_affected_by_aliasing_(0)
00307 {
00308 typedef FloatType f_t;
00309 typedef std::complex<FloatType> c_t;
00310 int t_den = space_group.t_den();
00311 std::vector<std::complex<FloatType> > trig_table;
00312 trig_table.reserve(t_den);
00313 for(int ht=0;ht<t_den;ht++) {
00314 FloatType ht_angle = scitbx::constants::two_pi * ht / t_den;
00315 trig_table.push_back(std::complex<FloatType>(
00316 std::cos(ht_angle),
00317 std::sin(ht_angle)));
00318 }
00319 af::int3 map_grid_focus = complex_map.accessor().focus();
00320 data_.reserve(miller_indices.size());
00321 bool sum_bijvoet_pairs = (anomalous_flag && space_group.is_centric());
00322 const c_t* shift_inv_t = 0;
00323 for(std::size_t i=0;i<miller_indices.size();i++) {
00324 miller::index<> const& h = miller_indices[i];
00325 if (space_group.is_centric()) {
00326 int ih = (h * space_group.inv_t()) % t_den;
00327 if (ih < 0) ih += t_den;
00328 shift_inv_t = &trig_table[ih];
00329 }
00330 c_t f(0,0);
00331 for(std::size_t i_smx=0;i_smx<space_group.n_smx();i_smx++) {
00332 sgtbx::rt_mx const& s = space_group.smx(i_smx);
00333 miller::index<> hr = h * s.r();
00334 array_access aa(
00335 anomalous_flag, map_grid_focus, conjugate_flag, hr);
00336 if (!aa.ih.all_ge(0)) throw_error_not_in_map();
00337 int ih = (h * s.t()) % t_den;
00338 if (ih < 0) ih += t_den;
00339 c_t const& shift = trig_table[ih];
00340 if (!aa.f_conj) f += complex_map(aa.ih) * shift;
00341 else f += std::conj(complex_map(aa.ih)) * shift;
00342 if (sum_bijvoet_pairs) {
00343 aa = array_access(
00344 anomalous_flag, map_grid_focus, conjugate_flag, -hr);
00345 if (!aa.ih.all_ge(0)) throw_error_not_in_map();
00346 CCTBX_ASSERT(!aa.f_conj);
00347 f += complex_map(aa.ih) * std::conj(shift) * (*shift_inv_t);
00348 }
00349 }
00350 if (!anomalous_flag && shift_inv_t) {
00351 f += std::conj(f) * (*shift_inv_t);
00352 }
00353 f *= space_group.n_ltr();
00354 data_.push_back(f);
00355 }
00356 }
00357
00358 af::shared<miller::index<> >
00359 miller_indices() const { return miller_indices_; }
00360
00361 af::shared<std::complex<FloatType> >
00362 data() const { return data_; }
00363
00364 std::size_t
00365 n_indices_affected_by_aliasing() const
00366 {
00367 return n_indices_affected_by_aliasing_;
00368 }
00369
00370 af::shared<std::size_t>
00371 outside_map() const { return outside_map_; }
00372
00373 protected:
00374 af::shared<miller::index<> > miller_indices_;
00375 af::shared<std::complex<FloatType> > data_;
00376 std::size_t n_indices_affected_by_aliasing_;
00377 af::shared<std::size_t> outside_map_;
00378
00379 static
00380 void
00381 throw_error_not_in_map()
00382 {
00383 throw error("Miller index not in structure factor map.");
00384 }
00385
00386 struct array_access
00387 {
00388 array_access(
00389 bool anomalous_flag,
00390 af::int3 const& map_grid_focus,
00391 bool conjugate_flag,
00392 miller::index<> h)
00393 {
00394 f_conj = conjugate_flag;
00395 if (!anomalous_flag) {
00396 if (h[2] < 0) {
00397 h = -h;
00398 f_conj = !f_conj;
00399 }
00400 }
00401 else {
00402 if (f_conj) {
00403 h = -h;
00404 f_conj = false;
00405 }
00406 }
00407 ih = h_as_ih_exact_array(anomalous_flag, h, map_grid_focus);
00408 }
00409
00410 bool f_conj;
00411 af::int3 ih;
00412 };
00413 };
00414
00415 }}}
00416
00417 #endif // CCTBX_MAPTBX_STRUCTURE_FACTORS_H