00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifndef CCTBX_DMTBX_TRIPLET_GENERATOR_H
00015 #define CCTBX_DMTBX_TRIPLET_GENERATOR_H
00016
00017 #include <cctbx/dmtbx/triplet_phase_relation.h>
00018 #include <cctbx/miller/sym_equiv.h>
00019 #include <scitbx/array_family/sort.h>
00020 #include <scitbx/array_family/selections.h>
00021 #include <boost/scoped_array.hpp>
00022
00023 namespace cctbx {
00024
00026 namespace dmtbx {
00027
00028 namespace detail {
00029
00030 struct expanded_index
00031 {
00032 expanded_index(
00033 std::size_t ih_,
00034 miller::sym_equiv_index sym_equiv_index_)
00035 :
00036 ih(ih_),
00037 h(sym_equiv_index_.h()),
00038 friedel_flag(sym_equiv_index_.friedel_flag()),
00039 ht(sym_equiv_index_.ht())
00040 {}
00041
00042 bool
00043 operator<(expanded_index const& other) const
00044 {
00045 for(std::size_t i=0;i<3;i++) {
00046 if (h[i] < other.h[i]) return true;
00047 if (h[i] > other.h[i]) return false;
00048 }
00049 return false;
00050 }
00051
00052 std::size_t ih;
00053 miller::index<> h;
00054 bool friedel_flag;
00055 int ht;
00056 };
00057
00058 }
00059
00061 template <typename FloatType = double>
00062 class triplet_generator
00063 {
00064 protected:
00065 typedef weighted_triplet_phase_relation wtpr_t;
00066 typedef af::shared<af::shared<wtpr_t> > array_of_wtprs_t;
00067 typedef af::const_ref<wtpr_t> cr_wtprs_t;
00068
00069 public:
00071 triplet_generator() {}
00072
00074
00091 triplet_generator(
00092 sgtbx::space_group const& space_group,
00093 af::const_ref<miller::index<> > const& miller_indices,
00094 af::const_ref<FloatType> const&
00095 amplitudes=af::const_ref<FloatType>(0,0),
00096 std::size_t max_relations_per_reflection=0,
00097 bool sigma_2_only=false,
00098 bool discard_weights=false)
00099 :
00100 t_den_(space_group.t_den()),
00101 max_relations_per_reflection_(max_relations_per_reflection),
00102 sigma_2_only_(sigma_2_only),
00103 discard_weights_(discard_weights),
00104 array_of_wtprs_((af::reserve(miller_indices.size())))
00105 {
00106 CCTBX_ASSERT( amplitudes.size() == 0
00107 || amplitudes.size() == miller_indices.size());
00108 CCTBX_ASSERT( max_relations_per_reflection == 0
00109 || amplitudes.size() > 0);
00110 std::vector<detail::expanded_index> expanded_indices;
00111 setup_expanded_indices(space_group, miller_indices, expanded_indices);
00112 for(std::size_t ih=0;ih<miller_indices.size();ih++) {
00113 af::shared<wtpr_t> tprs = find_triplets(
00114 ih,
00115 miller_indices[ih],
00116 expanded_indices);
00117 if ( max_relations_per_reflection == 0
00118 || max_relations_per_reflection >= tprs.size()) {
00119 array_of_wtprs_.push_back(tprs);
00120 }
00121 else {
00122 array_of_wtprs_.push_back(truncate(
00123 tprs.const_ref(),
00124 amplitudes,
00125 max_relations_per_reflection));
00126 }
00127 }
00128 }
00129
00131 int
00132 t_den() const { return t_den_; }
00133
00135 std::size_t
00136 max_relations_per_reflection() const
00137 {
00138 return max_relations_per_reflection_;
00139 }
00140
00142 bool
00143 sigma_2_only() const { return sigma_2_only_; }
00144
00146 bool
00147 discard_weights() const { return discard_weights_; }
00148
00150
00152 af::shared<std::size_t>
00153 n_relations() const
00154 {
00155 af::shared<std::size_t> result((af::reserve(array_of_wtprs_.size())));
00156 std::size_t n_miller_indices = array_of_wtprs_.size();
00157 for(std::size_t ih=0;ih<n_miller_indices;ih++) {
00158 cr_wtprs_t tprs = array_of_wtprs_[ih].const_ref();
00159 std::size_t n = 0;
00160 for(const wtpr_t* tpr=tprs.begin();tpr!=tprs.end();tpr++) {
00161 n += tpr->weight();
00162 }
00163 result.push_back(n);
00164 }
00165 return result;
00166 }
00167
00169
00171 af::shared<weighted_triplet_phase_relation>
00172 relations_for(std::size_t ih)
00173 {
00174 std::size_t n_miller_indices = array_of_wtprs_.size();
00175 CCTBX_ASSERT(ih < n_miller_indices);
00176 return array_of_wtprs_[ih];
00177 }
00178
00180
00182 af::shared<FloatType>
00183 sums_of_amplitude_products(
00184 af::const_ref<FloatType> const& amplitudes) const
00185 {
00186 std::size_t n_miller_indices = array_of_wtprs_.size();
00187 CCTBX_ASSERT(amplitudes.size() == n_miller_indices);
00188 af::shared<FloatType> result((af::reserve(n_miller_indices)));
00189 for(std::size_t ih=0;ih<n_miller_indices;ih++) {
00190 cr_wtprs_t tprs = array_of_wtprs_[ih].const_ref();
00191 FloatType sum = 0;
00192 for(const wtpr_t* tpr=tprs.begin();tpr!=tprs.end();tpr++) {
00193 sum += amplitudes[tpr->ik()]
00194 * amplitudes[tpr->ihmk()]
00195 * tpr->weight();
00196 }
00197 result.push_back(sum);
00198 }
00199 return result;
00200 }
00201
00203
00218 af::shared<FloatType>
00219 apply_tangent_formula(
00220 af::const_ref<FloatType> const& amplitudes,
00221 af::const_ref<FloatType> const& phases_rad,
00222 af::const_ref<bool> const& selection_fixed,
00223 bool use_fixed_only=false,
00224 bool reuse_results=false,
00225 FloatType const& sum_epsilon=1.e-10) const
00226 {
00227 CCTBX_ASSERT(amplitudes.size() == array_of_wtprs_.size());
00228 CCTBX_ASSERT(phases_rad.size() == amplitudes.size());
00229 CCTBX_ASSERT( selection_fixed.size() == 0
00230 || selection_fixed.size() == amplitudes.size());
00231 CCTBX_ASSERT(!use_fixed_only || selection_fixed.size() > 0);
00232 af::shared<FloatType> result(phases_rad.begin(), phases_rad.end());
00233 const FloatType* phase_source = (
00234 reuse_results ? result.begin() : phases_rad.begin());
00235 std::vector<bool> fixed_or_extrapolated;
00236 if (selection_fixed.size() == 0) {
00237 fixed_or_extrapolated.resize(amplitudes.size(), false);
00238 }
00239 else {
00240 fixed_or_extrapolated.assign(
00241 selection_fixed.begin(), selection_fixed.end());
00242 }
00243 for(std::size_t ih=0;ih<phases_rad.size();ih++) {
00244 if (selection_fixed.size() != 0 && selection_fixed[ih]) continue;
00245 CCTBX_ASSERT(!fixed_or_extrapolated[ih]);
00246 cr_wtprs_t tprs = array_of_wtprs_[ih].const_ref();
00247 FloatType sum_sin(0);
00248 FloatType sum_cos(0);
00249 for(const wtpr_t* tpr=tprs.begin();tpr!=tprs.end();tpr++) {
00250 CCTBX_ASSERT(tpr->ik() < amplitudes.size());
00251 CCTBX_ASSERT(tpr->ihmk() < amplitudes.size());
00252 if (use_fixed_only) {
00253 if (reuse_results) {
00254 if (!fixed_or_extrapolated[tpr->ik()]) continue;
00255 if (!fixed_or_extrapolated[tpr->ihmk()]) continue;
00256 }
00257 else {
00258 if (!selection_fixed[tpr->ik()]) continue;
00259 if (!selection_fixed[tpr->ihmk()]) continue;
00260 }
00261 }
00262 FloatType a_k_a_hmk = amplitudes[tpr->ik()]
00263 * amplitudes[tpr->ihmk()]
00264 * tpr->weight();
00265 FloatType phi_k_phi_hmk = tpr->phi_k_phi_hmk(phase_source, t_den_);
00266 sum_sin += a_k_a_hmk * std::sin(phi_k_phi_hmk);
00267 sum_cos += a_k_a_hmk * std::cos(phi_k_phi_hmk);
00268 }
00269 if ( scitbx::fn::absolute(sum_sin) >= sum_epsilon
00270 || scitbx::fn::absolute(sum_cos) >= sum_epsilon) {
00271 result[ih] = std::atan2(sum_sin, sum_cos);
00272 fixed_or_extrapolated[ih] = true;
00273 }
00274 }
00275 return result;
00276 }
00277
00278 protected:
00279 void
00280 setup_expanded_indices(
00281 sgtbx::space_group const& space_group,
00282 af::const_ref<miller::index<> > const& miller_indices,
00283 std::vector<detail::expanded_index>& expanded_indices)
00284 {
00285 for(std::size_t ih=0;ih<miller_indices.size();ih++) {
00286 miller::index<> h = miller_indices[ih];
00287 miller::sym_equiv_indices sym_eq_h(space_group, h);
00288 int mult = sym_eq_h.multiplicity(false);
00289 for(std::size_t ih_eq=0;ih_eq<mult;ih_eq++) {
00290 miller::sym_equiv_index h_seq = sym_eq_h(ih_eq);
00291 CCTBX_ASSERT(h_seq.t_den() == t_den_);
00292 expanded_indices.push_back(detail::expanded_index(ih, h_seq));
00293 }
00294 }
00295 std::sort(expanded_indices.begin(), expanded_indices.end());
00296 }
00297
00298 struct expanded_indices_scanner
00299 {
00300 expanded_indices_scanner(
00301 std::vector<detail::expanded_index> const& expanded_indices)
00302 :
00303 i_low(0),
00304 i_high(expanded_indices.size() - 1),
00305 e_low(&expanded_indices[i_low]),
00306 e_high(&expanded_indices[i_high])
00307 {}
00308
00309 bool
00310 incr_low()
00311 {
00312 if (i_low == i_high) return false;
00313 i_low++;
00314 e_low++;
00315 return true;
00316 }
00317
00318 bool
00319 decr_high()
00320 {
00321 if (i_low == i_high) return false;
00322 i_high--;
00323 e_high--;
00324 return true;
00325 }
00326
00327 bool
00328 advance()
00329 {
00330 if (!incr_low()) return false;
00331 if (!decr_high()) return false;
00332 return true;
00333 }
00334
00335 bool
00336 find_next(miller::index<> const& h)
00337 {
00338 for(std::size_t i=0;i<3;) {
00339 int s = e_low->h[i] + e_high->h[i];
00340 if (h[i] > s) {
00341 if (!incr_low()) return false;
00342 i = 0;
00343 }
00344 else if (h[i] < s) {
00345 if (!decr_high()) return false;
00346 i = 0;
00347 }
00348 else {
00349 i++;
00350 }
00351 }
00352 return true;
00353 }
00354
00355 bool
00356 current_is_sigma_2(std::size_t ih) const
00357 {
00358 return e_low->ih != ih
00359 && e_high->ih != ih
00360 && e_low->ih != e_high->ih;
00361 }
00362
00363 triplet_phase_relation
00364 get_tpr(int t_den) const
00365 {
00366 return triplet_phase_relation(
00367 e_low->ih,
00368 e_low->friedel_flag,
00369 e_low->ht,
00370 e_high->ih,
00371 e_high->friedel_flag,
00372 e_high->ht,
00373 t_den);
00374 }
00375
00376 std::size_t
00377 get_weight() const
00378 {
00379 if (i_low == i_high) return 1;
00380 return 2;
00381 }
00382
00383 std::size_t i_low;
00384 std::size_t i_high;
00385 const detail::expanded_index* e_low;
00386 const detail::expanded_index* e_high;
00387 };
00388
00389 af::shared<weighted_triplet_phase_relation>
00390 find_triplets(
00391 std::size_t ih,
00392 miller::index<> const& h,
00393 std::vector<detail::expanded_index> const& expanded_indices)
00394 {
00395 typedef std::map<triplet_phase_relation, std::size_t> tpr_map_t;
00396 tpr_map_t tpr_map;
00397 tpr_map_t::const_iterator m;
00398 if (expanded_indices.size() != 0) {
00399 expanded_indices_scanner scanner(expanded_indices);
00400 while (scanner.find_next(h)) {
00401 if (!sigma_2_only_ || scanner.current_is_sigma_2(ih)) {
00402 tpr_map[scanner.get_tpr(t_den_)] += scanner.get_weight();
00403 }
00404 if (!scanner.advance()) break;
00405 }
00406 }
00407 af::shared<wtpr_t> wtpr_array((af::reserve(tpr_map.size())));
00408 if (!discard_weights_) {
00409 for(m=tpr_map.begin();m!=tpr_map.end();m++) {
00410 wtpr_array.push_back(wtpr_t(m->first, m->second));
00411 }
00412 }
00413 else {
00414 const triplet_phase_relation* prev_tpr = 0;
00415 for(m=tpr_map.begin();m!=tpr_map.end();m++) {
00416 if (prev_tpr != 0 && m->first.is_similar_to(*prev_tpr)) continue;
00417 prev_tpr = &m->first;
00418 wtpr_array.push_back(wtpr_t(m->first, 1));
00419 }
00420 }
00421 return wtpr_array;
00422 }
00423
00424 af::shared<weighted_triplet_phase_relation>
00425 truncate(
00426 af::const_ref<weighted_triplet_phase_relation> const& tprs,
00427 af::const_ref<FloatType> const& amplitudes,
00428 std::size_t max_relations_per_reflection)
00429 {
00430 CCTBX_ASSERT(tprs.size() > max_relations_per_reflection);
00431 af::shared<weighted_triplet_phase_relation>
00432 result((af::reserve(max_relations_per_reflection)));
00433 boost::scoped_array<FloatType>
00434 values_to_sort(new FloatType[tprs.size()]);
00435 FloatType* v = values_to_sort.get();
00436 for(const wtpr_t* tpr=tprs.begin();tpr!=tprs.end();tpr++) {
00437 *v++ = amplitudes[tpr->ik()]
00438 * amplitudes[tpr->ihmk()]
00439 * tpr->weight();
00440 }
00441 af::shared<std::size_t> perm = af::sort_permutation(
00442 af::const_ref<FloatType>(values_to_sort.get(), tprs.size()),
00443 true);
00444 perm.resize(max_relations_per_reflection);
00445 return af::select(tprs, perm.const_ref());
00446 }
00447
00448 int t_den_;
00449 std::size_t max_relations_per_reflection_;
00450 bool sigma_2_only_;
00451 bool discard_weights_;
00452 array_of_wtprs_t array_of_wtprs_;
00453 };
00454
00455 }}
00456
00457 #endif // CCTBX_DMTBX_TRIPLET_GENERATOR_H