00001 #ifndef CCTBX_GEOMETRY_RESTRAINTS_NONBONDED_H
00002 #define CCTBX_GEOMETRY_RESTRAINTS_NONBONDED_H
00003
00004 #include <cctbx/geometry_restraints/asu_cache.h>
00005 #include <cctbx/geometry_restraints/sorted_asu_proxies.h>
00006 #include <set>
00007
00008 namespace cctbx { namespace geometry_restraints {
00009
00011 typedef std::map<std::string, double>
00012 nonbonded_distance_dict;
00014 typedef std::map<std::string, std::map<std::string, double> >
00015 nonbonded_distance_table;
00016
00018 typedef std::map<std::string, double>
00019 nonbonded_radius_table;
00020
00024 struct nonbonded_params
00025 {
00027 nonbonded_params(
00028 double factor_1_4_interactions_=2/3.,
00029 double const_shrink_1_4_interactions_=0,
00030 double default_distance_=0,
00031 double minimum_distance_=0)
00032 :
00033 factor_1_4_interactions(factor_1_4_interactions_),
00034 const_shrink_1_4_interactions(const_shrink_1_4_interactions_),
00035 default_distance(default_distance_),
00036 minimum_distance(minimum_distance_)
00037 {}
00038
00040 double
00041 find_max_vdw_distance(
00042 af::const_ref<std::string> const& nonbonded_types) const
00043 {
00044 double result = -1;
00045 std::set<std::string> unique_types(
00046 nonbonded_types.begin(), nonbonded_types.end());
00047 for(std::set<std::string>::const_iterator
00048 unique_types_i = unique_types.begin();
00049 unique_types_i != unique_types.end();
00050 unique_types_i++) {
00051 for(std::set<std::string>::const_iterator
00052 unique_types_j = unique_types_i;
00053 unique_types_j != unique_types.end();
00054 unique_types_j++) {
00055 double distance = get_nonbonded_distance(
00056 *unique_types_i,
00057 *unique_types_j);
00058 if (distance < 0) distance = default_distance;
00059 if (result < distance) result = distance;
00060 }
00061 }
00062 return std::max(minimum_distance, result);
00063 }
00064
00066
00068 double
00069 get_nonbonded_distance(
00070 std::string const& type_i,
00071 std::string const& type_j) const
00072 {
00073 nonbonded_distance_table::const_iterator
00074 distance_dict = distance_table.find(type_i);
00075 if (distance_dict != distance_table.end()) {
00076 nonbonded_distance_dict::const_iterator
00077 dict_entry = distance_dict->second.find(type_j);
00078 if (dict_entry != distance_dict->second.end()) {
00079 return dict_entry->second;
00080 }
00081 }
00082 distance_dict = distance_table.find(type_j);
00083 if (distance_dict != distance_table.end()) {
00084 nonbonded_distance_dict::const_iterator
00085 dict_entry = distance_dict->second.find(type_i);
00086 if (dict_entry != distance_dict->second.end()) {
00087 return dict_entry->second;
00088 }
00089 }
00090 geometry_restraints::nonbonded_radius_table::const_iterator
00091 radius_i = radius_table.find(type_i);
00092 if (radius_i != radius_table.end()) {
00093 geometry_restraints::nonbonded_radius_table::const_iterator
00094 radius_j = radius_table.find(type_j);
00095 if (radius_j != radius_table.end()) {
00096 return radius_i->second + radius_j->second;
00097 }
00098 }
00099 return -1;
00100 }
00101
00107 double
00108 adjust_nonbonded_distance(
00109 double distance,
00110 bool is_1_4_interaction) const
00111 {
00112 if (is_1_4_interaction) {
00113 distance *= factor_1_4_interactions;
00114 distance -= const_shrink_1_4_interactions;
00115 }
00116 return std::max(minimum_distance, distance);
00117 }
00118
00120 nonbonded_distance_table distance_table;
00122 nonbonded_radius_table radius_table;
00124 double factor_1_4_interactions;
00126 double const_shrink_1_4_interactions;
00128
00131 double default_distance;
00133 double minimum_distance;
00134 };
00135
00137 struct nonbonded_simple_proxy
00138 {
00140 nonbonded_simple_proxy() {}
00141
00143 nonbonded_simple_proxy(
00144 af::tiny<unsigned, 2> const& i_seqs_,
00145 double vdw_distance_)
00146 :
00147 i_seqs(i_seqs_),
00148 vdw_distance(vdw_distance_)
00149 {}
00150
00152 af::tiny<unsigned, 2> i_seqs;
00154 double vdw_distance;
00155 };
00156
00158 struct nonbonded_asu_proxy : asu_mapping_index_pair
00159 {
00161 nonbonded_asu_proxy() {}
00162
00164 nonbonded_asu_proxy(
00165 asu_mapping_index_pair const& pair_,
00166 double vdw_distance_)
00167 :
00168 asu_mapping_index_pair(pair_),
00169 vdw_distance(vdw_distance_)
00170 {}
00171
00173
00175 nonbonded_simple_proxy
00176 as_simple_proxy() const
00177 {
00178 return nonbonded_simple_proxy(
00179 af::tiny<unsigned, 2>(i_seq, j_seq),
00180 vdw_distance);
00181 }
00182
00184 double vdw_distance;
00185 };
00186
00188
00191 struct prolsq_repulsion_function
00192 {
00194 prolsq_repulsion_function(
00195 double c_rep_=16,
00196 double k_rep_=1,
00197 double irexp_=1,
00198 double rexp_=4)
00199 :
00200 c_rep(c_rep_),
00201 k_rep(k_rep_),
00202 irexp(irexp_),
00203 rexp(rexp_)
00204 {
00205 CCTBX_ASSERT(rexp > 0);
00206 }
00207
00209
00211 double
00212 term(double vdw_distance, double delta) const
00213 {
00214 if (irexp == 1) return k_rep*vdw_distance - delta;
00215 return std::pow(k_rep*vdw_distance, irexp) - std::pow(delta, irexp);
00216 }
00217
00219
00221 double
00222 residual(double term) const
00223 {
00224 if (term <= 0) return 0;
00225 if (rexp == 4) {
00226 double term_sq = term * term;
00227 return c_rep * term_sq * term_sq;
00228 }
00229 return c_rep * std::pow(term, rexp);
00230 }
00231
00233 double
00234 residual(double vdw_distance, double delta) const
00235 {
00236 return residual(term(vdw_distance, delta));
00237 }
00238
00240
00242 double
00243 d_residual_d_delta_over_delta(
00244 double delta, double , double term) const
00245 {
00246 if (term <= 0 || delta == 0) return 0;
00247 double d_term_d_r;
00248 if (irexp == 1) d_term_d_r = -1;
00249 else d_term_d_r = -irexp * std::pow(delta, irexp-1);
00250 if (rexp == 4) {
00251 return c_rep * rexp * term * term * term * d_term_d_r / delta;
00252 }
00253 return c_rep * rexp * std::pow(term, rexp-1) * d_term_d_r / delta;
00254 }
00255
00256 double c_rep;
00257 double k_rep;
00258 double irexp;
00259 double rexp;
00260 };
00261
00263 struct inverse_power_repulsion_function
00264 {
00266 inverse_power_repulsion_function(
00267 double nonbonded_distance_cutoff_,
00268 double k_rep_=1,
00269 double irexp_=1)
00270 :
00271 nonbonded_distance_cutoff(nonbonded_distance_cutoff_),
00272 k_rep(k_rep_),
00273 irexp(irexp_)
00274 {}
00275
00277
00279 double
00280 term(double vdw_distance, double delta) const
00281 {
00282 CCTBX_ASSERT(delta != 0);
00283 if (delta >= nonbonded_distance_cutoff) return 0;
00284 if (irexp == 1) return k_rep*vdw_distance / delta;
00285 if (irexp == 2) return k_rep*vdw_distance / delta / delta;
00286 return k_rep*vdw_distance / std::pow(delta, irexp);
00287 }
00288
00290
00292 double
00293 residual(double term) const { return term; }
00294
00296 double
00297 residual(double vdw_distance, double delta) const
00298 {
00299 return residual(term(vdw_distance, delta));
00300 }
00301
00303
00305 double
00306 d_residual_d_delta_over_delta(
00307 double delta, double , double term) const
00308 {
00309 if (term == 0) return 0;
00310 return -irexp * term / delta / delta;
00311 }
00312
00313 double nonbonded_distance_cutoff;
00314 double k_rep;
00315 double irexp;
00316 };
00317
00319 struct cos_repulsion_function
00320 {
00322 cos_repulsion_function(
00323 double max_residual_,
00324 double exponent_=1)
00325 :
00326 max_residual(max_residual_),
00327 exponent(exponent_)
00328 {}
00329
00331
00333 double
00334 term(double vdw_distance, double delta) const
00335 {
00336 if (delta >= vdw_distance) return 0;
00337 using scitbx::constants::pi;
00338 double w2 = (std::cos(pi * delta / vdw_distance) + 1) / 2;
00339 if (exponent == 1) return max_residual * w2;
00340 if (exponent == 2) return max_residual * w2 * w2;
00341 return max_residual * std::pow(w2, exponent);
00342 }
00343
00345
00347 double
00348 residual(double term) const { return term; }
00349
00351 double
00352 residual(double vdw_distance, double delta) const
00353 {
00354 return residual(term(vdw_distance, delta));
00355 }
00356
00358
00360 double
00361 d_residual_d_delta_over_delta(
00362 double delta, double vdw_distance, double ) const
00363 {
00364 if (delta == 0 || delta >= vdw_distance) return 0;
00365 using scitbx::constants::pi;
00366 double a = pi * delta / vdw_distance;
00367 double w = std::cos(a) + 1;
00368 if (exponent == 1) {
00369 return -(exponent*max_residual*pi*std::sin(a))
00370 / (2 * vdw_distance * delta);
00371 }
00372 if (exponent == 2) {
00373 return -(exponent*max_residual*pi*w*std::sin(a))
00374 / (4 * vdw_distance * delta);
00375 }
00376 return -(exponent*max_residual*pi*std::pow(w,exponent-1)*std::sin(a))
00377 / (std::pow(2.0,exponent) * vdw_distance * delta);
00378 }
00379
00380 double max_residual;
00381 double exponent;
00382 };
00383
00385
00387 struct gaussian_repulsion_function
00388 {
00390 gaussian_repulsion_function(
00391 double max_residual_,
00392 double norm_height_at_vdw_distance=0.1)
00393 :
00394 max_residual(max_residual_)
00395 {
00396 CCTBX_ASSERT(norm_height_at_vdw_distance < 1);
00397 CCTBX_ASSERT(norm_height_at_vdw_distance > 0);
00398 log_norm_height_at_vdw_distance = std::log(norm_height_at_vdw_distance);
00399 CCTBX_ASSERT(log_norm_height_at_vdw_distance < 0);
00400 }
00401
00402 double
00403 norm_height_at_vdw_distance() const
00404 {
00405 return std::exp(log_norm_height_at_vdw_distance);
00406 }
00407
00409
00411 double
00412 term(double vdw_distance, double delta) const
00413 {
00414 double minus_f_sq = (vdw_distance * vdw_distance)
00415 / log_norm_height_at_vdw_distance;
00416 CCTBX_ASSERT(minus_f_sq != 0);
00417 return max_residual * std::exp(delta*delta / minus_f_sq);
00418 }
00419
00421
00423 double
00424 residual(double term) const { return term; }
00425
00427 double
00428 residual(double vdw_distance, double delta) const
00429 {
00430 return residual(term(vdw_distance, delta));
00431 }
00432
00434
00436 double
00437 d_residual_d_delta_over_delta(
00438 double , double vdw_distance, double term) const
00439 {
00440 double minus_f_sq = (vdw_distance * vdw_distance)
00441 / log_norm_height_at_vdw_distance;
00442 CCTBX_ASSERT(minus_f_sq != 0);
00443 return 2 * term / minus_f_sq;
00444 }
00445
00446 double max_residual;
00447 double log_norm_height_at_vdw_distance;
00448 };
00449
00451 template <typename NonbondedFunction>
00452 class nonbonded
00453 {
00454 public:
00456 typedef scitbx::vec3<double> vec3;
00457
00459 nonbonded() {}
00460
00462 nonbonded(
00463 af::tiny<scitbx::vec3<double>, 2> const& sites_,
00464 double vdw_distance_,
00465 NonbondedFunction const& function_)
00466 :
00467 sites(sites_),
00468 vdw_distance(vdw_distance_),
00469 function(function_)
00470 {
00471 init_term();
00472 }
00473
00477 nonbonded(
00478 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00479 nonbonded_simple_proxy const& proxy,
00480 NonbondedFunction const& function_)
00481 :
00482 vdw_distance(proxy.vdw_distance),
00483 function(function_)
00484 {
00485 for(int i=0;i<2;i++) {
00486 std::size_t i_seq = proxy.i_seqs[i];
00487 CCTBX_ASSERT(i_seq < sites_cart.size());
00488 sites[i] = sites_cart[i_seq];
00489 }
00490 init_term();
00491 }
00492
00496 nonbonded(
00497 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00498 direct_space_asu::asu_mappings<> const& asu_mappings,
00499 nonbonded_asu_proxy const& proxy,
00500 NonbondedFunction const& function_)
00501 :
00502 vdw_distance(proxy.vdw_distance),
00503 function(function_)
00504 {
00505 sites[0] = asu_mappings.map_moved_site_to_asu(
00506 sites_cart[proxy.i_seq], proxy.i_seq, 0);
00507 sites[1] = asu_mappings.map_moved_site_to_asu(
00508 sites_cart[proxy.j_seq], proxy.j_seq, proxy.j_sym);
00509 init_term();
00510 }
00511
00513 nonbonded(
00514 asu_cache<> const& cache,
00515 nonbonded_asu_proxy const& proxy,
00516 NonbondedFunction const& function_)
00517 :
00518 vdw_distance(proxy.vdw_distance),
00519 function(function_)
00520 {
00521 sites[0] = cache.sites[proxy.i_seq][0];
00522 sites[1] = cache.sites[proxy.j_seq][proxy.j_sym];
00523 init_term();
00524 }
00525
00527 double
00528 residual() const { return function.residual(term_); }
00529
00531
00533 scitbx::vec3<double>
00534 gradient_0() const
00535 {
00536 return diff_vec
00537 * function.d_residual_d_delta_over_delta(
00538 delta, vdw_distance, term_);
00539 }
00540
00542 af::tiny<scitbx::vec3<double>, 2>
00543 gradients() const
00544 {
00545 af::tiny<scitbx::vec3<double>, 2> result;
00546 result[0] = gradient_0();
00547 result[1] = -result[0];
00548 return result;
00549 }
00550
00551
00552 void
00553 add_gradients(
00554 af::ref<scitbx::vec3<double> > const& gradient_array,
00555 af::tiny<unsigned, 2> const& i_seqs) const
00556 {
00557 vec3 g0 = gradient_0();
00558 gradient_array[i_seqs[0]] += g0;
00559 gradient_array[i_seqs[1]] += -g0;
00560 }
00561
00563
00565 void
00566 add_gradients(
00567 af::ref<scitbx::vec3<double> > const& gradient_array,
00568 direct_space_asu::asu_mappings<> const& asu_mappings,
00569 asu_mapping_index_pair const& pair) const
00570 {
00571 vec3 grad_asu = gradient_0();
00572 vec3 grad_i_seq = asu_mappings.r_inv_cart(pair.i_seq, 0) * grad_asu;
00573 gradient_array[pair.i_seq] += grad_i_seq;
00574 if (pair.j_sym == 0) {
00575 vec3 grad_j_seq = asu_mappings.r_inv_cart(pair.j_seq, 0) * grad_asu;
00576 gradient_array[pair.j_seq] -= grad_j_seq;
00577 }
00578 }
00579
00581
00583 void
00584 add_gradients(
00585 asu_cache<>& cache,
00586 asu_mapping_index_pair const& pair) const
00587 {
00588 vec3 grad_asu = gradient_0();
00589 cache.gradients[pair.i_seq] += grad_asu;
00590 if (pair.j_sym == 0) {
00591 cache.gradients[pair.j_seq] -= grad_asu;
00592 }
00593 }
00594
00596 af::tiny<scitbx::vec3<double>, 2> sites;
00598 double vdw_distance;
00600 NonbondedFunction function;
00602 scitbx::vec3<double> diff_vec;
00604 double delta;
00605 protected:
00606 double term_;
00607
00608 void
00609 init_term()
00610 {
00611 diff_vec = sites[0] - sites[1];
00612 delta = diff_vec.length();
00613 term_ = function.term(vdw_distance, delta);
00614 }
00615 };
00616
00618 inline
00619 af::shared<double>
00620 nonbonded_deltas(
00621 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00622 af::const_ref<nonbonded_simple_proxy> const& proxies)
00623 {
00624 af::shared<double> result((af::reserve(proxies.size())));
00625 prolsq_repulsion_function function;
00626 for(std::size_t i=0;i<proxies.size();i++) {
00627 nonbonded<prolsq_repulsion_function> restraint(
00628 sites_cart, proxies[i], function);
00629 result.push_back(restraint.delta);
00630 }
00631 return result;
00632 }
00633
00637 template <typename NonbondedFunction>
00638 af::shared<double>
00639 nonbonded_residuals(
00640 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00641 af::const_ref<nonbonded_simple_proxy> const& proxies,
00642 NonbondedFunction const& function)
00643 {
00644 af::shared<double> result((af::reserve(proxies.size())));
00645 for(std::size_t i=0;i<proxies.size();i++) {
00646 nonbonded<NonbondedFunction> restraint(sites_cart, proxies[i], function);
00647 result.push_back(restraint.residual());
00648 }
00649 return result;
00650 }
00651
00661 template <typename NonbondedFunction>
00662 double
00663 nonbonded_residual_sum(
00664 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00665 af::const_ref<nonbonded_simple_proxy> const& proxies,
00666 af::ref<scitbx::vec3<double> > const& gradient_array,
00667 NonbondedFunction const& function)
00668 {
00669 double result = 0;
00670 for(std::size_t i=0;i<proxies.size();i++) {
00671 nonbonded<NonbondedFunction> restraint(sites_cart, proxies[i], function);
00672 result += restraint.residual();
00673 if (gradient_array.size() != 0) {
00674 restraint.add_gradients(gradient_array, proxies[i].i_seqs);
00675 }
00676 }
00677 return result;
00678 }
00679
00681 typedef sorted_asu_proxies<nonbonded_simple_proxy, nonbonded_asu_proxy>
00682 nonbonded_sorted_asu_proxies_base;
00683
00685 inline
00686 af::shared<double>
00687 nonbonded_deltas(
00688 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00689 nonbonded_sorted_asu_proxies_base const& sorted_asu_proxies)
00690 {
00691 af::shared<double> result = nonbonded_deltas(
00692 sites_cart, sorted_asu_proxies.simple.const_ref());
00693 af::const_ref<nonbonded_asu_proxy>
00694 sym = sorted_asu_proxies.asu.const_ref();
00695 if (sym.size() > 0) {
00696 result.reserve(sorted_asu_proxies.simple.size() + sym.size());
00697 direct_space_asu::asu_mappings<> const&
00698 asu_mappings = *sorted_asu_proxies.asu_mappings();
00699 prolsq_repulsion_function function;
00700 for(std::size_t i=0;i<sym.size();i++) {
00701 nonbonded<prolsq_repulsion_function> restraint(
00702 sites_cart, asu_mappings, sym[i], function);
00703 result.push_back(restraint.delta);
00704 }
00705 }
00706 return result;
00707 }
00708
00710 template <typename NonbondedFunction>
00711 af::shared<double>
00712 nonbonded_residuals(
00713 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00714 nonbonded_sorted_asu_proxies_base const& sorted_asu_proxies,
00715 NonbondedFunction const& function)
00716 {
00717 af::shared<double> result = nonbonded_residuals(
00718 sites_cart, sorted_asu_proxies.simple.const_ref(), function);
00719 af::const_ref<nonbonded_asu_proxy>
00720 sym = sorted_asu_proxies.asu.const_ref();
00721 if (sym.size() > 0) {
00722 result.reserve(sorted_asu_proxies.simple.size() + sym.size());
00723 direct_space_asu::asu_mappings<> const&
00724 asu_mappings = *sorted_asu_proxies.asu_mappings();
00725 for(std::size_t i=0;i<sym.size();i++) {
00726 nonbonded<NonbondedFunction> restraint(
00727 sites_cart, asu_mappings, sym[i], function);
00728 result.push_back(restraint.residual());
00729 }
00730 }
00731 return result;
00732 }
00733
00734 namespace detail {
00735
00736 template <typename NonbondedFunction>
00737 double
00738 nonbonded_residual_sum(
00739 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00740 direct_space_asu::asu_mappings<> const& asu_mappings,
00741 af::const_ref<nonbonded_asu_proxy> const& proxies,
00742 std::vector<bool> const& sym_active_flags,
00743 af::ref<scitbx::vec3<double> > const& gradient_array,
00744 NonbondedFunction const& function,
00745 bool disable_cache=false)
00746 {
00747 double result = 0;
00748 if (!disable_cache) {
00749 asu_cache<> cache(
00750 sites_cart,
00751 asu_mappings,
00752 sym_active_flags,
00753 gradient_array.size() != 0);
00754 for(std::size_t i=0;i<proxies.size();i++) {
00755 nonbonded<NonbondedFunction> restraint(cache, proxies[i], function);
00756 if (proxies[i].j_sym == 0) result += restraint.residual();
00757 else result += restraint.residual()*.5;
00758 if (gradient_array.size() != 0) {
00759 restraint.add_gradients(cache, proxies[i]);
00760 }
00761 }
00762 if (gradient_array.size() != 0) {
00763 cache.add_gradients(gradient_array, asu_mappings);
00764 }
00765 }
00766 else {
00767 for(std::size_t i=0;i<proxies.size();i++) {
00768 nonbonded<NonbondedFunction> restraint(
00769 sites_cart, asu_mappings, proxies[i], function);
00770 if (proxies[i].j_sym == 0) result += restraint.residual();
00771 else result += restraint.residual()*.5;
00772 if (gradient_array.size() != 0) {
00773 restraint.add_gradients(gradient_array, asu_mappings, proxies[i]);
00774 }
00775 }
00776 }
00777 return result;
00778 }
00779
00780 }
00781
00796 template <typename NonbondedFunction>
00797 double
00798 nonbonded_residual_sum(
00799 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00800 nonbonded_sorted_asu_proxies_base const& sorted_asu_proxies,
00801 af::ref<scitbx::vec3<double> > const& gradient_array,
00802 NonbondedFunction const& function,
00803 bool disable_cache=false)
00804 {
00805 double result = nonbonded_residual_sum(
00806 sites_cart,
00807 sorted_asu_proxies.simple.const_ref(),
00808 gradient_array,
00809 function);
00810 if (sorted_asu_proxies.asu.size() > 0) {
00811 result += detail::nonbonded_residual_sum(
00812 sites_cart,
00813 *sorted_asu_proxies.asu_mappings(),
00814 sorted_asu_proxies.asu.const_ref(),
00815 sorted_asu_proxies.asu_active_flags,
00816 gradient_array,
00817 function,
00818 disable_cache);
00819 }
00820 return result;
00821 }
00822
00823 }}
00824
00825 #endif // CCTBX_GEOMETRY_RESTRAINTS_NONBONDED_H