00001 #ifndef CCTBX_GEOMETRY_RESTRAINTS_PLANARITY_H
00002 #define CCTBX_GEOMETRY_RESTRAINTS_PLANARITY_H
00003
00004 #include <cctbx/sgtbx/rt_mx.h>
00005 #include <cctbx/geometry_restraints/utils.h>
00006 #include <scitbx/matrix/eigensystem.h>
00007 #include <scitbx/array_family/sort.h>
00008 #include <scitbx/sym_mat3.h>
00009 #include <scitbx/optional_copy.h>
00010
00011 namespace cctbx { namespace geometry_restraints {
00012
00014 struct planarity_proxy
00015 {
00017 typedef af::shared<std::size_t> i_seqs_type;
00018
00020 planarity_proxy() {}
00021
00023 planarity_proxy(
00024 i_seqs_type const& i_seqs_,
00025 af::shared<double> const& weights_)
00026 :
00027 i_seqs(i_seqs_),
00028 weights(weights_)
00029 {
00030 CCTBX_ASSERT(weights.size() == i_seqs.size());
00031 }
00032
00034 planarity_proxy(
00035 i_seqs_type const& i_seqs_,
00036 planarity_proxy const& other)
00037 :
00038 i_seqs(i_seqs_),
00039 weights(other.weights.begin(), other.weights.end())
00040 {
00041 CCTBX_ASSERT(weights.size() == i_seqs.size());
00042 }
00043
00045 planarity_proxy(
00046 i_seqs_type const& i_seqs_,
00047 af::shared<sgtbx::rt_mx> const& sym_ops_,
00048 af::shared<double> const& weights_)
00049 :
00050 i_seqs(i_seqs_),
00051 sym_ops(sym_ops_),
00052 weights(weights_)
00053 {
00054 CCTBX_ASSERT(weights.size() == i_seqs.size());
00055 if ( sym_ops.get() ) {
00056 CCTBX_ASSERT(sym_ops.get()->size() == i_seqs.size());
00057 }
00058 }
00059
00061 planarity_proxy(
00062 i_seqs_type const& i_seqs_,
00063 af::shared<sgtbx::rt_mx> const& sym_ops_,
00064 planarity_proxy const& other)
00065 :
00066 i_seqs(i_seqs_),
00067 sym_ops(sym_ops_),
00068 weights(other.weights.begin(), other.weights.end())
00069 {
00070 CCTBX_ASSERT(weights.size() == i_seqs.size());
00071 if ( sym_ops.get() ) {
00072 CCTBX_ASSERT(sym_ops.get()->size() == i_seqs.size());
00073 }
00074 }
00075
00077 planarity_proxy
00078 sort_i_seqs() const
00079 {
00080 af::const_ref<std::size_t> i_seqs_cr = i_seqs.const_ref();
00081 af::const_ref<double> weights_cr = weights.const_ref();
00082 CCTBX_ASSERT(i_seqs_cr.size() == weights_cr.size());
00083 planarity_proxy result;
00084 i_seqs_type i_seqs_result;
00085 i_seqs_result.reserve(i_seqs_cr.size());
00086 af::shared<double> weights_result;
00087 weights_result.reserve(i_seqs_cr.size());
00088 i_seqs_type perm = af::sort_permutation(i_seqs_cr);
00089 af::const_ref<std::size_t> perm_cr = perm.const_ref();
00090 for(std::size_t i=0;i<perm_cr.size();i++) {
00091 i_seqs_result.push_back(i_seqs_cr[perm_cr[i]]);
00092 weights_result.push_back(weights_cr[perm_cr[i]]);
00093 }
00094 if ( sym_ops.get() ) {
00095 af::const_ref<sgtbx::rt_mx> sym_ops_cr = sym_ops.get()->const_ref();
00096 af::shared<sgtbx::rt_mx> sym_ops_result;
00097 sym_ops_result.reserve(sym_ops_cr.size());
00098 for(std::size_t i=0;i<perm_cr.size();i++) {
00099 sym_ops_result.push_back(sym_ops_cr[perm_cr[i]]);
00100 }
00101 return planarity_proxy(i_seqs_result, sym_ops_result, weights_result);
00102 }
00103 else {
00104 return planarity_proxy(i_seqs_result, weights_result);
00105 }
00106 }
00107
00109 i_seqs_type i_seqs;
00111 af::shared<double> weights;
00113 scitbx::optional_copy<af::shared<sgtbx::rt_mx> > sym_ops;
00114 };
00115
00117
00129 class planarity
00130 {
00131 public:
00133 planarity() {}
00134
00136 planarity(
00137 af::shared<scitbx::vec3<double> > const& sites_,
00138 af::shared<double> const& weights_)
00139 :
00140 sites(sites_),
00141 weights(weights_)
00142 {
00143 init_deltas();
00144 }
00145
00149 planarity(
00150 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00151 planarity_proxy const& proxy)
00152 :
00153 weights(proxy.weights)
00154 {
00155 af::const_ref<std::size_t> i_seqs_ref = proxy.i_seqs.const_ref();
00156 sites.reserve(i_seqs_ref.size());
00157 for(std::size_t i=0;i<i_seqs_ref.size();i++) {
00158 std::size_t i_seq = i_seqs_ref[i];
00159 CCTBX_ASSERT(i_seq < sites_cart.size());
00160 sites.push_back(sites_cart[i_seq]);
00161 }
00162 init_deltas();
00163 }
00164
00169 planarity(
00170 uctbx::unit_cell const& unit_cell,
00171 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00172 planarity_proxy const& proxy)
00173 :
00174 weights(proxy.weights)
00175 {
00176 af::const_ref<std::size_t> i_seqs_ref = proxy.i_seqs.const_ref();
00177 sites.reserve(i_seqs_ref.size());
00178 for(std::size_t i=0;i<i_seqs_ref.size();i++) {
00179 std::size_t i_seq = i_seqs_ref[i];
00180 CCTBX_ASSERT(i_seq < sites_cart.size());
00181 sites.push_back(sites_cart[i_seq]);
00182 if ( proxy.sym_ops.get() ) {
00183 sgtbx::rt_mx rt_mx = proxy.sym_ops[i];
00184 if ( !rt_mx.is_unit_mx() ) {
00185 sites[i] = unit_cell.orthogonalize(
00186 rt_mx * unit_cell.fractionalize(sites[i]));
00187 }
00188 }
00189 }
00190 init_deltas();
00191 }
00193 af::shared<scitbx::vec3<double> > sites;
00195 af::shared<double> weights;
00196
00198 af::shared<double> const&
00199 deltas() const { return deltas_; }
00200
00202 double
00203 rms_deltas() const { return std::sqrt(af::mean_sq(deltas_.const_ref())); }
00204
00206 double
00207 residual() const
00208 {
00209 double result = 0;
00210 af::const_ref<double> weights_ref = weights.const_ref();
00211 af::const_ref<double> deltas_ref = deltas_.const_ref();
00212 for(std::size_t i_site=0;i_site<deltas_ref.size();i_site++) {
00213 result += weights_ref[i_site]
00214 * scitbx::fn::pow2(deltas_ref[i_site]);
00215 }
00216 return result;
00217 }
00218
00220 af::shared<scitbx::vec3<double> >
00221 gradients() const
00222 {
00223 af::shared<scitbx::vec3<double> > result;
00224 af::const_ref<double> weights_ref = weights.const_ref();
00225 af::const_ref<double> deltas_ref = deltas_.const_ref();
00226 result.reserve(deltas_ref.size());
00227 scitbx::vec3<double> n_min = normal();
00228 for(std::size_t i_site=0;i_site<deltas_ref.size();i_site++) {
00229 result.push_back(
00230 n_min * (2 * weights_ref[i_site] * deltas_ref[i_site]));
00231 }
00232 return result;
00233 }
00234
00236
00238 void
00239 add_gradients(
00240 af::ref<scitbx::vec3<double> > const& gradient_array,
00241 planarity_proxy::i_seqs_type const& i_seqs) const
00242 {
00243 af::const_ref<std::size_t> i_seqs_ref = i_seqs.const_ref();
00244 af::shared<scitbx::vec3<double> > grads = gradients();
00245 af::const_ref<scitbx::vec3<double> > grads_ref = grads.const_ref();
00246 for(std::size_t i=0;i<grads_ref.size();i++) {
00247 gradient_array[i_seqs_ref[i]] += grads_ref[i];
00248 }
00249 }
00250
00252
00257 void
00258 add_gradients(
00259 uctbx::unit_cell const& unit_cell,
00260 af::ref<scitbx::vec3<double> > const& gradient_array,
00261 planarity_proxy const& proxy) const
00262 {
00263 af::const_ref<std::size_t> i_seqs_ref = proxy.i_seqs.const_ref();
00264 scitbx::optional_copy<af::shared<sgtbx::rt_mx> > const& sym_ops = proxy.sym_ops;
00265 af::shared<scitbx::vec3<double> > grads = gradients();
00266 af::const_ref<scitbx::vec3<double> > grads_ref = grads.const_ref();
00267 for(std::size_t i=0;i<grads_ref.size();i++) {
00268 if (sym_ops.get() && !sym_ops[i].is_unit_mx() ) {
00269 scitbx::mat3<double> r_inv_cart_ = r_inv_cart(unit_cell, sym_ops[i]);
00270 gradient_array[i_seqs_ref[i]] += grads_ref[i] * r_inv_cart_;
00271 }
00272 else { gradient_array[i_seqs_ref[i]] += grads_ref[i]; }
00273 }
00274 }
00275
00279 scitbx::vec3<double>
00280 normal() const
00281 {
00282 return scitbx::vec3<double>(eigensystem_.vectors().begin()+2*3);
00283 }
00284
00287 double
00288 lambda_min() const { return eigensystem_.values()[2]; }
00289
00291
00294 scitbx::vec3<double> const&
00295 center_of_mass() const { return center_of_mass_; }
00296
00298
00300 scitbx::sym_mat3<double> const&
00301 residual_tensor() const { return residual_tensor_; }
00302
00304 scitbx::matrix::eigensystem::real_symmetric<double> const&
00305 eigensystem() const { return eigensystem_; }
00306
00307 protected:
00308 scitbx::vec3<double> center_of_mass_;
00309 scitbx::sym_mat3<double> residual_tensor_;
00310 scitbx::matrix::eigensystem::real_symmetric<double> eigensystem_;
00311 af::shared<double> deltas_;
00312
00313 void
00314 init_deltas()
00315 {
00316 CCTBX_ASSERT(weights.size() == sites.size());
00317 af::const_ref<scitbx::vec3<double> > sites_ref = sites.const_ref();
00318 af::const_ref<double> weights_ref = weights.const_ref();
00319 center_of_mass_.fill(0);
00320 double sum_weights = 0;
00321 for(std::size_t i_site=0;i_site<sites_ref.size();i_site++) {
00322 double w = weights_ref[i_site];
00323 center_of_mass_ += w * sites_ref[i_site];
00324 sum_weights += w;
00325 }
00326 CCTBX_ASSERT(sum_weights > 0);
00327 center_of_mass_ /= sum_weights;
00328 residual_tensor_.fill(0);
00329 for(std::size_t i_site=0;i_site<sites_ref.size();i_site++) {
00330 double w = weights_ref[i_site];
00331 scitbx::vec3<double> x = sites_ref[i_site] - center_of_mass_;
00332 residual_tensor_(0,0) += w*x[0]*x[0];
00333 residual_tensor_(1,1) += w*x[1]*x[1];
00334 residual_tensor_(2,2) += w*x[2]*x[2];
00335 residual_tensor_(0,1) += w*x[0]*x[1];
00336 residual_tensor_(0,2) += w*x[0]*x[2];
00337 residual_tensor_(1,2) += w*x[1]*x[2];
00338 }
00339 eigensystem_ = scitbx::matrix::eigensystem::real_symmetric<double>(
00340 residual_tensor_);
00341 scitbx::vec3<double> n_min = normal();
00342 deltas_.reserve(sites_ref.size());
00343 for(std::size_t i_site=0;i_site<sites_ref.size();i_site++) {
00344 deltas_.push_back(n_min * (sites_ref[i_site] - center_of_mass_));
00345 }
00346 }
00347 };
00348
00352 inline
00353 af::shared<double>
00354 planarity_deltas_rms(
00355 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00356 af::const_ref<planarity_proxy> const& proxies)
00357 {
00358 af::shared<double> result((af::reserve(proxies.size())));
00359 for(std::size_t i=0;i<proxies.size();i++) {
00360 result.push_back(planarity(sites_cart, proxies[i]).rms_deltas());
00361 }
00362 return result;
00363 }
00364
00368 inline
00369 af::shared<double>
00370 planarity_residuals(
00371 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00372 af::const_ref<planarity_proxy> const& proxies)
00373 {
00374 return detail::generic_residuals<planarity_proxy, planarity>::get(
00375 sites_cart, proxies);
00376 }
00377
00387 inline
00388 double
00389 planarity_residual_sum(
00390 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00391 af::const_ref<planarity_proxy> const& proxies,
00392 af::ref<scitbx::vec3<double> > const& gradient_array)
00393 {
00394 return detail::generic_residual_sum<planarity_proxy, planarity>::get(
00395 sites_cart, proxies, gradient_array);
00396 }
00397
00401 inline
00402 af::shared<double>
00403 planarity_deltas_rms(
00404 uctbx::unit_cell const& unit_cell,
00405 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00406 af::const_ref<planarity_proxy> const& proxies)
00407 {
00408 af::shared<double> result((af::reserve(proxies.size())));
00409 for(std::size_t i=0;i<proxies.size();i++) {
00410 result.push_back(planarity(unit_cell, sites_cart, proxies[i]).rms_deltas());
00411 }
00412 return result;
00413 }
00414
00418 inline
00419 af::shared<double>
00420 planarity_residuals(
00421 uctbx::unit_cell const& unit_cell,
00422 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00423 af::const_ref<planarity_proxy> const& proxies)
00424 {
00425 return detail::generic_residuals<planarity_proxy, planarity>::get(
00426 unit_cell, sites_cart, proxies);
00427 }
00428
00438 inline
00439 double
00440 planarity_residual_sum(
00441 uctbx::unit_cell const& unit_cell,
00442 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00443 af::const_ref<planarity_proxy> const& proxies,
00444 af::ref<scitbx::vec3<double> > const& gradient_array)
00445 {
00446 return detail::generic_residual_sum<planarity_proxy, planarity>::get(
00447 unit_cell, sites_cart, proxies, gradient_array);
00448 }
00449 }}
00450
00451 #endif // CCTBX_GEOMETRY_RESTRAINTS_PLANARITY_H