00001 #ifndef CCTBX_MAPTBX_GRID_INDICES_AROUND_SITES_H
00002 #define CCTBX_MAPTBX_GRID_INDICES_AROUND_SITES_H
00003
00004 #include <cctbx/uctbx.h>
00005 #include <scitbx/math/modulo.h>
00006 #include <boost/scoped_array.hpp>
00007
00008 namespace cctbx { namespace maptbx {
00009
00010 template <typename SetType>
00011 std::auto_ptr<SetType>
00012 grid_indices_around_sites(
00013 uctbx::unit_cell const& unit_cell,
00014 af::tiny<int, 3> const& fft_n_real,
00015 af::tiny<int, 3> const& fft_m_real,
00016 af::const_ref<scitbx::vec3<double> > const& sites_cart,
00017 af::const_ref<double> const& site_radii)
00018 {
00019 CCTBX_ASSERT(unit_cell.volume() > 0);
00020 CCTBX_ASSERT(fft_n_real.const_ref().all_gt(0));
00021 CCTBX_ASSERT(fft_m_real.const_ref().all_ge(fft_n_real.const_ref()));
00022 CCTBX_ASSERT(site_radii.size() == sites_cart.size());
00023 typedef typename SetType::value_type svt;
00024 {
00025 svt m[3];
00026 for(unsigned i=0;i<3;i++) {
00027 m[i] = boost::numeric_cast<svt>(fft_m_real[i]);
00028 }
00029 if (scitbx::math::unsigned_product_leads_to_overflow(m, 3U)) {
00030 throw std::runtime_error(
00031 "product of fft_m_real grid dimensions leads to SetType::value_type"
00032 " integer overflow (i.e. the grid is too large).");
00033 }
00034 }
00035 std::auto_ptr<SetType> result_ap(new SetType);
00036 SetType* result = result_ap.get();
00037 scitbx::vec3<double> fft_n_real_f;
00038 scitbx::vec3<double> one_over_grid_spacing;
00039 for(unsigned i=0;i<3;i++) {
00040 fft_n_real_f[i] = boost::numeric_cast<double>(fft_n_real[i]);
00041 double unit_cell_parameter = unit_cell.parameters()[i];
00042 CCTBX_ASSERT(unit_cell_parameter > 0);
00043 one_over_grid_spacing[i] = fft_n_real_f[i] / unit_cell_parameter;
00044 }
00045 svt n0 = boost::numeric_cast<svt>(fft_n_real[0]);
00046 svt n1 = boost::numeric_cast<svt>(fft_n_real[1]);
00047 svt n2 = boost::numeric_cast<svt>(fft_n_real[2]);
00048 svt m1 = boost::numeric_cast<svt>(fft_m_real[1]);
00049 svt m2 = boost::numeric_cast<svt>(fft_m_real[2]);
00050 for(std::size_t i_site=0;i_site<sites_cart.size();i_site++) {
00051 scitbx::vec3<double> uvw = unit_cell.fractionalize(sites_cart[i_site]);
00052 for(unsigned i=0;i<3;i++) uvw[i] *= fft_n_real_f[i];
00053 double site_radius = site_radii[i_site];
00054 af::tiny<svt, 3> box_min;
00055 af::tiny<svt, 3> box_max;
00056 for(unsigned i=0;i<3;i++) {
00057 double grid_radius = std::min(
00058 site_radius * one_over_grid_spacing[i],
00059 fft_n_real_f[i] * (0.5+1.e-5));
00060 typedef scitbx::math::float_int_conversions<double, int> fic;
00061 int box_min_i = fic::ifloor(uvw[i] - grid_radius);
00062 int box_max_i = fic::iceil( uvw[i] + grid_radius);
00063 int box_min_mod = scitbx::math::mod_positive(box_min_i, fft_n_real[i]);
00064 int shift = box_min_mod - box_min_i;
00065 uvw[i] += boost::numeric_cast<double>(shift);
00066 box_min[i] = boost::numeric_cast<svt>(box_min_i + shift);
00067 box_max[i] = boost::numeric_cast<svt>(box_max_i + shift);
00068 }
00069 double site_radius_sq = site_radius * site_radius;
00070 scitbx::mat3<double> orth = unit_cell.orthogonalization_matrix();
00071 CCTBX_ASSERT(orth[3] == 0);
00072 CCTBX_ASSERT(orth[6] == 0);
00073 CCTBX_ASSERT(orth[7] == 0);
00074 orth[0] /= fft_n_real_f[0];
00075 orth[1] /= fft_n_real_f[1];
00076 orth[4] /= fft_n_real_f[1];
00077 orth[2] /= fft_n_real_f[2];
00078 orth[5] /= fft_n_real_f[2];
00079 orth[8] /= fft_n_real_f[2];
00080 svt box_n1_2 = (box_max[1] + 1 - box_min[1]) * 2;
00081 svt box_n2_3 = (box_max[2] + 1 - box_min[2]) * 3;
00082 boost::scoped_array<double> buffer(new double[box_n1_2 + box_n2_3]);
00083 double* o14d1_beg = buffer.get();
00084 double* o258d2_beg = o14d1_beg + box_n1_2;
00085 const double* o258d2_end = o258d2_beg + box_n2_3;
00086 {
00087 double* o14d1 = o14d1_beg;
00088 for(svt b1=box_min[1];b1<=box_max[1];b1++) {
00089 double diff1 = boost::numeric_cast<double>(b1) - uvw[1];
00090 *o14d1++ = orth[1] * diff1;
00091 *o14d1++ = orth[4] * diff1;
00092 }
00093 }
00094 {
00095 double* o258d2 = o258d2_beg;
00096 for(svt b2=box_min[2];b2<=box_max[2];b2++) {
00097 double diff2 = boost::numeric_cast<double>(b2) - uvw[2];
00098 *o258d2++ = orth[2] * diff2;
00099 *o258d2++ = orth[5] * diff2;
00100 *o258d2++ = scitbx::fn::pow2(orth[8] * diff2);
00101 }
00102 }
00103 svt g0 = box_min[0];
00104 svt g1b = box_min[1];
00105 svt g2b = box_min[2];
00106 for(svt b0=box_min[0];b0<=box_max[0];b0++,g0++) {
00107 double diff0 = boost::numeric_cast<double>(b0) - uvw[0];
00108 double orth0_diff0 = orth[0] * diff0;
00109 if (g0 == n0) g0 = 0;
00110 svt gm0 = g0 * m1;
00111 svt g1 = g1b;
00112 for(const double* o14d1=o14d1_beg;o14d1!=o258d2_beg;g1++) {
00113 double orth0_diff0_orth1_diff_1 = orth0_diff0 + *o14d1++;
00114 double orth4_diff1 = *o14d1++;
00115 if (g1 == n1) g1 = 0;
00116 svt gm01 = (gm0 + g1) * m2;
00117 svt g2 = g2b;
00118 for(const double* o258d2=o258d2_beg;o258d2!=o258d2_end;g2++) {
00119 if (g2 == n2) g2 = 0;
00120 double dc_sq = orth0_diff0_orth1_diff_1 + *o258d2++;
00121 dc_sq *= dc_sq;
00122 double dc1 = orth4_diff1 + *o258d2++;
00123 dc_sq += dc1 * dc1;
00124 dc_sq += *o258d2++;
00125 if (dc_sq > site_radius_sq) continue;
00126 result->insert(gm01 + g2);
00127 }
00128 }
00129 }
00130 }
00131 return result_ap;
00132 }
00133
00134 }}
00135
00136 #endif // GUARD