00001 #ifndef CCTBX_CRYSTAL_PAIR_TABLES_H
00002 #define CCTBX_CRYSTAL_PAIR_TABLES_H
00003
00004 #include <cctbx/crystal/neighbors_fast.h>
00005 #include <cctbx/eltbx/covalent_radii.h>
00006 #include <boost/scoped_array.hpp>
00007 #include <map>
00008 #include <set>
00009
00010 namespace cctbx { namespace crystal {
00011
00013 typedef sgtbx::rt_mx pair_sym_op;
00015 typedef std::vector<sgtbx::rt_mx> pair_sym_ops;
00017 typedef std::map<unsigned, pair_sym_ops> pair_sym_dict;
00019 typedef af::shared<pair_sym_dict> pair_sym_table;
00020
00024 inline
00025 af::shared<double>
00026 get_distances(
00027 af::const_ref<pair_sym_dict> const& pair_sym_table,
00028 scitbx::mat3<double> const& orthogonalization_matrix,
00029 af::const_ref<scitbx::vec3<double> > const& sites_frac)
00030 {
00031 CCTBX_ASSERT(sites_frac.size() == pair_sym_table.size());
00032 af::shared<double> distances;
00033 for(unsigned i_seq=0;i_seq<pair_sym_table.size();i_seq++) {
00034 crystal::pair_sym_dict const& pair_sym_dict = pair_sym_table[i_seq];
00035 scitbx::vec3<double> const& site_i = sites_frac[i_seq];
00036 for(crystal::pair_sym_dict::const_iterator
00037 pair_sym_dict_i=pair_sym_dict.begin();
00038 pair_sym_dict_i!=pair_sym_dict.end();
00039 pair_sym_dict_i++) {
00040 unsigned j_seq = pair_sym_dict_i->first;
00041 scitbx::vec3<double> const& site_j = sites_frac[j_seq];
00042 af::const_ref<sgtbx::rt_mx> rt_mx_list = af::make_const_ref(
00043 pair_sym_dict_i->second);
00044 for(unsigned i_op=0;i_op<rt_mx_list.size();i_op++) {
00045 distances.push_back((
00046 orthogonalization_matrix
00047 * (site_i - rt_mx_list[i_op] * site_j)).length());
00048 }
00049 }
00050 }
00051 return distances;
00052 }
00053
00054 class adp_iso_local_sphere_restraints_energies
00055 {
00056 public:
00057 adp_iso_local_sphere_restraints_energies() {}
00058
00059 adp_iso_local_sphere_restraints_energies(
00060 af::const_ref<pair_sym_dict> const& pair_sym_table,
00061 scitbx::mat3<double> const& orthogonalization_matrix,
00062 af::const_ref<scitbx::vec3<double> > const& sites_frac,
00063 af::const_ref<double> const& u_isos,
00064 af::const_ref<bool> const& selection,
00065 af::const_ref<bool> const& use_u_iso,
00066 af::const_ref<bool> const& grad_u_iso,
00067 double sphere_radius,
00068 double distance_power,
00069 double average_power,
00070 double min_u_sum,
00071 bool compute_gradients,
00072 bool collect)
00073 {
00074 CCTBX_ASSERT(sites_frac.size() == pair_sym_table.size());
00075 CCTBX_ASSERT(u_isos.size() == pair_sym_table.size());
00076 CCTBX_ASSERT(use_u_iso.size() == pair_sym_table.size());
00077 CCTBX_ASSERT(grad_u_iso.size() == pair_sym_table.size());
00078 CCTBX_ASSERT(selection.size() == pair_sym_table.size());
00079 number_of_restraints = 0;
00080 residual_sum = 0;
00081 if (compute_gradients) {
00082 gradients.resize(u_isos.size());
00083 }
00084 for(unsigned i_seq=0;i_seq<pair_sym_table.size();i_seq++) {
00085 if(use_u_iso[i_seq] && selection[i_seq]) {
00086 crystal::pair_sym_dict const& pair_sym_dict = pair_sym_table[i_seq];
00087 scitbx::vec3<double> const& site_i = sites_frac[i_seq];
00088 for(crystal::pair_sym_dict::const_iterator
00089 pair_sym_dict_i=pair_sym_dict.begin();
00090 pair_sym_dict_i!=pair_sym_dict.end();
00091 pair_sym_dict_i++) {
00092 unsigned j_seq = pair_sym_dict_i->first;
00093 scitbx::vec3<double> const& site_j = sites_frac[j_seq];
00094 af::const_ref<sgtbx::rt_mx> rt_mx_list = af::make_const_ref(
00095 pair_sym_dict_i->second);
00096 for(unsigned i_op=0;i_op<rt_mx_list.size();i_op++) {
00097 double dist = (orthogonalization_matrix
00098 * (site_i - rt_mx_list[i_op] * site_j)).length();
00099 if (dist <= sphere_radius && dist > 0.0) {
00100 if(dist < 0.1) {
00101 dist = 0.1;
00102 }
00103 double one_over_weight = std::pow(dist, distance_power);
00104 CCTBX_ASSERT(one_over_weight != 0);
00105 double weight = 1./one_over_weight;
00106 double u1 = u_isos[i_seq];
00107 double u2 = u_isos[j_seq];
00108 if(u1 >= 0.0 && u2 >= 0) {
00109 double sum = u1 + u2;
00110 if (sum >= min_u_sum) {
00111 double ave_pow = std::pow(sum/2, average_power);
00112 CCTBX_ASSERT(ave_pow != 0);
00113 double u_diff = u1 - u2;
00114 double u_diff_sq = u_diff * u_diff;
00115 number_of_restraints++;
00116 residual_sum += (weight * u_diff_sq / ave_pow);
00117 if (compute_gradients && grad_u_iso[i_seq] &&
00118 grad_u_iso[j_seq]) {
00119 double mem1 = 2.* u_diff / ave_pow;
00120 CCTBX_ASSERT(sum * ave_pow != 0);
00121 double mem2 = average_power * u_diff_sq / (sum*ave_pow);
00122 gradients[i_seq] += weight * (mem1 - mem2);
00123 gradients[j_seq] += weight * (-mem1 - mem2);
00124 }
00125 if (collect) {
00126 u_i.push_back(u1);
00127 u_j.push_back(u2);
00128 r_ij.push_back(dist);
00129 }
00130 }
00131 }
00132 }
00133 }
00134 }
00135 }
00136 }
00137 }
00138
00139 unsigned number_of_restraints;
00140 double residual_sum;
00141 af::shared<double> gradients;
00142 af::shared<double> u_i;
00143 af::shared<double> u_j;
00144 af::shared<double> r_ij;
00145 };
00146
00154 inline
00155 af::shared<double>
00156 get_distances(
00157 af::const_ref<pair_sym_dict> const& pair_sym_table,
00158 af::const_ref<scitbx::vec3<double> > const& sites_cart)
00159 {
00160 CCTBX_ASSERT(sites_cart.size() == pair_sym_table.size());
00161 af::shared<double> distances;
00162 for(unsigned i_seq=0;i_seq<pair_sym_table.size();i_seq++) {
00163 crystal::pair_sym_dict const& pair_sym_dict = pair_sym_table[i_seq];
00164 scitbx::vec3<double> const& site_i = sites_cart[i_seq];
00165 for(crystal::pair_sym_dict::const_iterator
00166 pair_sym_dict_i=pair_sym_dict.begin();
00167 pair_sym_dict_i!=pair_sym_dict.end();
00168 pair_sym_dict_i++) {
00169 unsigned j_seq = pair_sym_dict_i->first;
00170 scitbx::vec3<double> const& site_j = sites_cart[j_seq];
00171 af::const_ref<sgtbx::rt_mx> rt_mx_list = af::make_const_ref(
00172 pair_sym_dict_i->second);
00173 CCTBX_ASSERT(rt_mx_list.size() == 1);
00174 CCTBX_ASSERT(rt_mx_list[0].is_unit_mx());
00175 distances.push_back((site_i - site_j).length());
00176 }
00177 }
00178 return distances;
00179 }
00180
00182 typedef std::set<unsigned> pair_asu_j_sym_group;
00184 typedef std::vector<pair_asu_j_sym_group> pair_asu_j_sym_groups;
00186 typedef std::map<unsigned, pair_asu_j_sym_groups> pair_asu_dict;
00188 typedef af::shared<pair_asu_dict> pair_asu_table_table;
00189
00193 template <typename FloatType=double, typename IntShiftType=int>
00194 class pair_asu_table
00195 {
00196 public:
00198 pair_asu_table() {}
00199
00201 pair_asu_table(
00202 boost::shared_ptr<
00203 direct_space_asu::asu_mappings<
00204 FloatType, IntShiftType> > asu_mappings)
00205 :
00206 asu_mappings_owner_(asu_mappings),
00207 asu_mappings_(asu_mappings.get()),
00208 table_(asu_mappings->mappings_const_ref().size())
00209 {}
00210
00212 void
00213 reserve(std::size_t n_sites_final) { table_.reserve(n_sites_final); }
00214
00216 void
00217 grow(std::size_t number_of_additional_entries)
00218 {
00219 table_.resize(table_.size()+number_of_additional_entries);
00220 }
00221
00223 boost::shared_ptr<
00224 direct_space_asu::asu_mappings<FloatType, IntShiftType> >
00225 asu_mappings() const { return asu_mappings_owner_; }
00226
00228 pair_asu_table_table const&
00229 table() const { return table_; }
00230
00232 bool
00233 contains(direct_space_asu::asu_mapping_index_pair const& pair) const
00234 {
00235 return contains(pair.i_seq, pair.j_seq, pair.j_sym);
00236 }
00237
00239 bool
00240 contains(unsigned i_seq, unsigned j_seq, unsigned j_sym) const
00241 {
00242 pair_asu_dict const& asu_dict = table_[i_seq];
00243 pair_asu_dict::const_iterator asu_dict_i = asu_dict.find(j_seq);
00244 if (asu_dict_i != asu_dict.end()) {
00245 for (pair_asu_j_sym_groups::const_iterator
00246 j_sym_groups_i = asu_dict_i->second.begin();
00247 j_sym_groups_i != asu_dict_i->second.end();
00248 j_sym_groups_i++) {
00249 if (j_sym_groups_i->find(j_sym) != j_sym_groups_i->end()) {
00250 return true;
00251 }
00252 }
00253 }
00254 return false;
00255 }
00256
00258 bool
00259 operator==(pair_asu_table const& other) const
00260 {
00261 af::const_ref<pair_asu_dict> tab_a = table_.const_ref();
00262 af::const_ref<pair_asu_dict> tab_b = other.table_.const_ref();
00263 if (tab_a.size() != tab_b.size()) return false;
00264 for(unsigned i_seq=0;i_seq<tab_a.size();i_seq++) {
00265 pair_asu_dict const& dict_a = tab_a[i_seq];
00266 pair_asu_dict const& dict_b = tab_b[i_seq];
00267 if (dict_a.size() != dict_b.size()) return false;
00268 for(pair_asu_dict::const_iterator
00269 dict_a_i=dict_a.begin();
00270 dict_a_i!=dict_a.end();
00271 dict_a_i++) {
00272 pair_asu_dict::const_iterator
00273 dict_b_i = dict_b.find(dict_a_i->first);
00274 if (dict_b_i == dict_b.end()) return false;
00275 pair_asu_j_sym_groups const& jgs_a = dict_a_i->second;
00276 pair_asu_j_sym_groups const& jgs_b = dict_b_i->second;
00277 if (jgs_a.size() != jgs_b.size()) return false;
00278 std::vector<bool> is_matched(jgs_b.size(), false);
00279 for(unsigned ig_a=0;ig_a<jgs_a.size();ig_a++) {
00280 unsigned ig_b=0;
00281 for(;ig_b<jgs_b.size();ig_b++) {
00282 if (is_matched[ig_b]) continue;
00283 if (jgs_a[ig_a] == jgs_b[ig_b]) {
00284 is_matched[ig_b] = true;
00285 break;
00286 }
00287 }
00288 if (ig_b == jgs_b.size()) return false;
00289 }
00290 }
00291 }
00292 return true;
00293 }
00294
00296 bool
00297 operator!=(pair_asu_table const& other) const
00298 {
00299 return !((*this) == other);
00300 }
00301
00303 af::shared<std::size_t>
00304 pair_counts() const
00305 {
00306 af::const_ref<pair_asu_dict> tab = table_.const_ref();
00307 af::shared<std::size_t> result((af::reserve(tab.size())));
00308 for(unsigned i_seq=0;i_seq<tab.size();i_seq++) {
00309 std::size_t count = 0;
00310 pair_asu_dict const& dict = tab[i_seq];
00311 for(pair_asu_dict::const_iterator
00312 dict_i=dict.begin();
00313 dict_i!=dict.end();
00314 dict_i++) {
00315 pair_asu_j_sym_groups const& jgs = dict_i->second;
00316 for(unsigned ig=0;ig<jgs.size();ig++) {
00317 count += jgs[ig].size();
00318 }
00319 }
00320 result.push_back(count);
00321 }
00322 return result;
00323 }
00324
00326
00329 af::shared<std::size_t>
00330 cluster_pivot_selection(
00331 bool general_positions_only=false,
00332 std::size_t max_clusters=0,
00333 unsigned estimated_reduction_factor=4) const
00334 {
00335 af::const_ref<pair_asu_dict> tab = table_.const_ref();
00336 af::shared<std::size_t> result;
00337 if (max_clusters > 0) {
00338 result.reserve(max_clusters);
00339 }
00340 else if (estimated_reduction_factor > 1) {
00341 result.reserve( (tab.size()+estimated_reduction_factor-1)
00342 / estimated_reduction_factor);
00343 }
00344 else {
00345 result.reserve(tab.size());
00346 }
00347 boost::scoped_array<bool> keep_flags(new bool[tab.size()]);
00348 for(unsigned i_seq=0;i_seq<tab.size();i_seq++) {
00349 if (general_positions_only
00350 && asu_mappings_->site_symmetry_table()
00351 .is_special_position(i_seq)) {
00352 keep_flags[i_seq] = false;
00353 continue;
00354 }
00355 bool keep = true;
00356 pair_asu_dict const& dict = tab[i_seq];
00357 for(pair_asu_dict::const_iterator
00358 dict_i=dict.begin();
00359 dict_i!=dict.end();
00360 dict_i++) {
00361 unsigned j_seq = dict_i->first;
00362 if (j_seq == i_seq || (j_seq < i_seq && keep_flags[j_seq])) {
00363 keep = false;
00364 break;
00365 }
00366 }
00367 keep_flags[i_seq] = keep;
00368 if (keep) {
00369 result.push_back(i_seq);
00370 if (result.size() == max_clusters) break;
00371 }
00372 }
00373 return result;
00374 }
00375
00381 pair_asu_table&
00382 add_all_pairs(
00383 FloatType const& distance_cutoff,
00384 FloatType const& min_cubicle_edge=5,
00385 FloatType const& epsilon=1.e-6)
00386 {
00387 neighbors::fast_pair_generator<FloatType, IntShiftType> pair_generator(
00388 asu_mappings_owner_,
00389 distance_cutoff*(1+epsilon),
00390 true,
00391 min_cubicle_edge);
00392 while (!pair_generator.at_end()) {
00393 add_pair(pair_generator.next());
00394 }
00395 return *this;
00396 }
00397
00403 pair_asu_table&
00404 add_covalent_pairs(
00405 af::const_ref<std::string> const& scattering_types,
00406 af::const_ref<std::string> const& exclude_scattering_types
00407 = af::const_ref<std::string>(0,0),
00408 FloatType const& distance_cutoff=3.5,
00409 FloatType const& min_cubicle_edge=5,
00410 FloatType const& tolerance=0.5,
00411 FloatType const& epsilon=1.e-6)
00412 {
00413 neighbors::fast_pair_generator<FloatType, IntShiftType> pair_generator(
00414 asu_mappings_owner_,
00415 distance_cutoff*(1+epsilon),
00416 true,
00417 min_cubicle_edge);
00418 while (!pair_generator.at_end()) {
00419 direct_space_asu::asu_mapping_index_pair_and_diff<FloatType>
00420 const& pair = pair_generator.next();
00421 if (std::find(exclude_scattering_types.begin(),
00422 exclude_scattering_types.end(),
00423 scattering_types[pair.i_seq]) != exclude_scattering_types.end() ||
00424 std::find(
00425 exclude_scattering_types.begin(),
00426 exclude_scattering_types.end(),
00427 scattering_types[pair.j_seq]) != exclude_scattering_types.end()) continue;
00428 FloatType const& radius_i = eltbx::covalent_radii::table(
00429 scattering_types[pair.i_seq]).radius();
00430 FloatType const& radius_j = eltbx::covalent_radii::table(
00431 scattering_types[pair.j_seq]).radius();
00432 FloatType const max_bond_length = radius_i + radius_j + tolerance;
00433 if (std::sqrt(pair.dist_sq) <= max_bond_length)
00434 add_pair(pair);
00435 }
00436 return *this;
00437 }
00438
00440
00442 pair_asu_table&
00443 add_pair_sym_table(pair_sym_table const& sym_table)
00444 {
00445 af::const_ref<pair_sym_dict> sym_table_ref = sym_table.const_ref();
00446 for(unsigned i_seq=0;i_seq<sym_table_ref.size();i_seq++) {
00447 for(pair_sym_dict::const_iterator
00448 sym_dict_i = sym_table_ref[i_seq].begin();
00449 sym_dict_i != sym_table_ref[i_seq].end();
00450 sym_dict_i++) {
00451 unsigned j_seq = sym_dict_i->first;
00452 std::vector<sgtbx::rt_mx> const& rt_mx_list = sym_dict_i->second;
00453 for(unsigned i=0;i<rt_mx_list.size();i++) {
00454 add_pair(i_seq, j_seq, rt_mx_list[i]);
00455 }
00456 }
00457 }
00458 return *this;
00459 }
00460
00462 pair_asu_table&
00463 add_pair(direct_space_asu::asu_mapping_index_pair const& pair)
00464 {
00465 sgtbx::rt_mx rt_mx_i = asu_mappings_->get_rt_mx_i(pair);
00466 sgtbx::rt_mx rt_mx_j = asu_mappings_->get_rt_mx_j(pair);
00467 add_pair(
00468 pair.i_seq,
00469 pair.j_seq,
00470 rt_mx_i.inverse().multiply(rt_mx_j));
00471 return *this;
00472 }
00473
00475
00481 pair_asu_table&
00482 add_pair(unsigned i_seq, unsigned j_seq, sgtbx::rt_mx const& rt_mx_ji)
00483 {
00484 bool is_new = process_pair(i_seq, j_seq, rt_mx_ji);
00485 if (is_new && i_seq != j_seq) {
00486 is_new = process_pair(j_seq, i_seq, rt_mx_ji.inverse_cancel());
00487 CCTBX_ASSERT(is_new);
00488 }
00489 return *this;
00490 }
00491
00495 pair_asu_table&
00496 add_pair(af::tiny<unsigned, 2> const& i_seqs)
00497 {
00498 sgtbx::rt_mx rt_mx_ji(1, 1);
00499 bool is_new = process_pair(i_seqs[0], i_seqs[1], rt_mx_ji);
00500 if (is_new && i_seqs[0] != i_seqs[1]) {
00501 is_new = process_pair(i_seqs[1], i_seqs[0], rt_mx_ji);
00502 CCTBX_ASSERT(is_new);
00503 }
00504 return *this;
00505 }
00506
00508
00515 pair_sym_table
00516 extract_pair_sym_table(bool skip_j_seq_less_than_i_seq=true) const
00517 {
00518 pair_sym_table sym_table(asu_mappings_->mappings_const_ref().size());
00519 af::const_ref<pair_asu_dict> table_ref = table_.const_ref();
00520 for(unsigned i_seq=0;i_seq<table_.size();i_seq++) {
00521 sgtbx::rt_mx
00522 rt_mx_i_inv = asu_mappings_->get_rt_mx(i_seq, 0).inverse();
00523 pair_asu_dict const& asu_dict = table_ref[i_seq];
00524 pair_sym_dict& sym_dict = sym_table[i_seq];
00525 for(pair_asu_dict::const_iterator
00526 asu_dict_i = asu_dict.begin();
00527 asu_dict_i != asu_dict.end();
00528 asu_dict_i++) {
00529 unsigned j_seq = asu_dict_i->first;
00530 if (skip_j_seq_less_than_i_seq && j_seq < i_seq) continue;
00531 std::vector<sgtbx::rt_mx>& rt_mx_list = sym_dict[j_seq];
00532 for(pair_asu_j_sym_groups::const_iterator
00533 j_sym_groups_i = asu_dict_i->second.begin();
00534 j_sym_groups_i != asu_dict_i->second.end();
00535 j_sym_groups_i++) {
00536 unsigned j_sym = *(j_sym_groups_i->begin());
00537 sgtbx::rt_mx rt_mx_j = asu_mappings_->get_rt_mx(j_seq, j_sym);
00538 rt_mx_list.push_back(rt_mx_i_inv.multiply(rt_mx_j));
00539 }
00540 }
00541 }
00542 return sym_table;
00543 }
00544
00553 bool
00554 process_pair(
00555 unsigned i_seq,
00556 unsigned j_seq,
00557 sgtbx::rt_mx const& rt_mx_ji)
00558 {
00559 sgtbx::rt_mx rt_mx_i = asu_mappings_->get_rt_mx(i_seq, 0);
00560 sgtbx::rt_mx rt_mx_j = rt_mx_i.multiply(rt_mx_ji);
00561 int j_sym = asu_mappings_->find_i_sym(j_seq, rt_mx_j);
00562 return process_pair(i_seq, j_seq, rt_mx_ji, rt_mx_i, j_sym);
00563 }
00564
00573 bool
00574 process_pair(
00575 unsigned i_seq,
00576 unsigned j_seq,
00577 sgtbx::rt_mx const& rt_mx_ji,
00578 sgtbx::rt_mx const& rt_mx_i,
00579 int j_sym)
00580 {
00581 CCTBX_ASSERT(j_sym >= 0);
00582 if (contains(i_seq, j_seq, j_sym)) {
00583 return false;
00584 }
00585 table_[i_seq][j_seq].push_back(pair_asu_j_sym_group());
00586 pair_asu_j_sym_group& j_syms = table_[i_seq][j_seq].back();
00587 sgtbx::site_symmetry_table const&
00588 site_symmetry_table = asu_mappings_->site_symmetry_table();
00589 if ( i_seq != j_seq
00590 && !site_symmetry_table.is_special_position(i_seq)) {
00591 j_syms.insert(j_sym);
00592 }
00593 else {
00594 af::const_ref<sgtbx::rt_mx> const&
00595 site_symmetry_matrices = site_symmetry_table
00596 .get(i_seq).matrices().const_ref();
00597 for(unsigned i_mi=0;i_mi<site_symmetry_matrices.size();i_mi++) {
00598 sgtbx::rt_mx const& mi = site_symmetry_matrices[i_mi];
00599 if (i_seq == j_seq) {
00600 sgtbx::rt_mx rt_mx_j_eq
00601 = rt_mx_i.multiply(rt_mx_ji.multiply(mi).inverse_cancel());
00602 int j_sym_eq = asu_mappings_->find_i_sym(j_seq, rt_mx_j_eq);
00603 CCTBX_ASSERT(j_sym_eq >= 0);
00604 j_syms.insert(j_sym_eq);
00605 }
00606 sgtbx::rt_mx rt_mx_j_eq = rt_mx_i.multiply(mi.multiply(rt_mx_ji));
00607 int j_sym_eq = asu_mappings_->find_i_sym(j_seq, rt_mx_j_eq);
00608 CCTBX_ASSERT(j_sym_eq >= 0);
00609 j_syms.insert(j_sym_eq);
00610 }
00611 }
00612 return true;
00613 }
00614
00616 pair_asu_table
00617 angle_pair_asu_table() const
00618 {
00619 pair_asu_table result(asu_mappings_owner_);
00620 af::const_ref<pair_asu_dict> table_ref = table_.const_ref();
00621 typedef af::tiny<unsigned, 2> tu2;
00622 std::vector<tu2> pair_list;
00623 pair_list.reserve(16);
00624 for(unsigned i_seq=0;i_seq<table_.size();i_seq++) {
00625 pair_list.clear();
00626 pair_asu_dict const& asu_dict = table_ref[i_seq];
00627 for(pair_asu_dict::const_iterator
00628 asu_dict_i = asu_dict.begin();
00629 asu_dict_i != asu_dict.end();
00630 asu_dict_i++) {
00631 unsigned j_seq = asu_dict_i->first;
00632 for(pair_asu_j_sym_groups::const_iterator
00633 j_sym_groups_i = asu_dict_i->second.begin();
00634 j_sym_groups_i != asu_dict_i->second.end();
00635 j_sym_groups_i++) {
00636 for(pair_asu_j_sym_group::const_iterator
00637 j_sym_i = j_sym_groups_i->begin();
00638 j_sym_i != j_sym_groups_i->end();
00639 j_sym_i++) {
00640 pair_list.push_back(tu2(j_seq, *j_sym_i));
00641 }
00642 }
00643 }
00644 unsigned pair_list_size = static_cast<unsigned>(pair_list.size());
00645 for(unsigned i_jj1=0;i_jj1+1<pair_list_size;i_jj1++) {
00646 tu2 const& jj1 = pair_list[i_jj1];
00647 sgtbx::rt_mx rt_mx_jj1_inv = asu_mappings_->get_rt_mx(
00648 jj1[0], jj1[1]).inverse();
00649 for(unsigned i_jj2=i_jj1+1;i_jj2<pair_list_size;i_jj2++) {
00650 tu2 const& jj2 = pair_list[i_jj2];
00651 result.add_pair(
00652 jj1[0],
00653 jj2[0],
00654 rt_mx_jj1_inv.multiply(asu_mappings_->get_rt_mx(
00655 jj2[0], jj2[1])));
00656 }
00657 }
00658 }
00659 return result;
00660 }
00661
00662 protected:
00663 boost::shared_ptr<
00664 direct_space_asu::asu_mappings<FloatType, IntShiftType> >
00665 asu_mappings_owner_;
00666 const direct_space_asu::asu_mappings<FloatType, IntShiftType>*
00667 asu_mappings_;
00668 pair_asu_table_table table_;
00669 };
00670
00671 }}
00672
00673 #endif // CCTBX_CRYSTAL_PAIR_TABLES_H