IMP logo
IMP Reference Guide  2.18.0
The Integrative Modeling Platform
grid_embeddings.h
Go to the documentation of this file.
1 /**
2  * \file IMP/algebra/grid_embeddings.h
3  * \brief A class to represent a voxel grid.
4  *
5  * Copyright 2007-2022 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPALGEBRA_GRID_EMBEDDINGS_H
10 #define IMPALGEBRA_GRID_EMBEDDINGS_H
11 
12 #include <IMP/algebra/algebra_config.h>
13 
14 #include <IMP/types.h>
15 #include "grid_indexes.h"
16 #include "Vector3D.h"
17 #include "BoundingBoxD.h"
18 #include <boost/iterator/transform_iterator.hpp>
19 #include <boost/serialization/access.hpp>
20 #include <boost/serialization/split_member.hpp>
21 #include <IMP/Vector.h>
22 #include <IMP/check_macros.h>
23 #include <IMP/exception.h>
24 
25 #include <limits>
26 
27 IMPALGEBRA_BEGIN_NAMESPACE
28 
29 //! Embed a grid as an evenly spaced axis aligned grid.
30 template <int D>
32  VectorD<D> origin_;
33  VectorD<D> unit_cell_;
34  // inverse
35  VectorD<D> inverse_unit_cell_;
36 
37 #ifndef SWIG
38  friend class boost::serialization::access;
39 
40  template<class Archive> void save(Archive &ar, const unsigned int) const {
41  ar << origin_ << unit_cell_;
42  }
43 
44  template<class Archive> void load(Archive &ar, const unsigned int) {
45  ar >> origin_;
46  ar >> unit_cell_;
47  set_unit_cell(unit_cell_); // sets inverse
48  }
49 
50  BOOST_SERIALIZATION_SPLIT_MEMBER()
51 #endif
52 
53  template <class O>
54  VectorD<D> get_elementwise_product(VectorD<D> v0, const O &v1) const {
55  for (unsigned int i = 0; i < get_dimension(); ++i) {
56  v0[i] *= v1[i];
57  }
58  return v0;
59  }
60  template <class O>
61  VectorD<D> get_uniform_offset(const O &v0, double o) const {
62  Floats ret(get_dimension());
63  for (unsigned int i = 0; i < get_dimension(); ++i) {
64  ret[i] = v0[i] + o;
65  }
66  return VectorD<D>(ret.begin(), ret.end());
67  }
68  void initialize_from_box(Ints ns, const BoundingBoxD<D> &bb) {
69  Floats nuc(bb.get_dimension());
70  for (unsigned int i = 0; i < bb.get_dimension(); ++i) {
71  double side = bb.get_corner(1)[i] - bb.get_corner(0)[i];
72  IMP_USAGE_CHECK(side > 0, "Can't have flat grid");
73  nuc[i] = side / ns[i];
74  }
75  set_unit_cell(VectorD<D>(nuc.begin(), nuc.end()));
76  set_origin(bb.get_corner(0));
77  }
78 
79  public:
80  DefaultEmbeddingD(const VectorD<D> &origin, const VectorD<D> &cell) {
81  set_origin(origin);
82  set_unit_cell(cell);
83  }
85  void set_origin(const VectorD<D> &o) { origin_ = o; }
86  const VectorD<D> get_origin() const { return origin_; }
87  unsigned int get_dimension() const { return get_origin().get_dimension(); }
88  void set_unit_cell(const VectorD<D> &o) {
89  unit_cell_ = o;
90  Floats iuc(o.get_dimension());
91  for (unsigned int i = 0; i < get_dimension(); ++i) {
92  iuc[i] = 1.0 / unit_cell_[i];
93  }
94  inverse_unit_cell_ = VectorD<D>(iuc.begin(), iuc.end());
95  }
96 #ifndef IMP_DOXYGEN
97  //! Return the vector (1/u[0], 1/u[1], 1/u[2])
98  const VectorD<D> &get_inverse_unit_cell() const { return inverse_unit_cell_; }
99 #endif
100  //! Return the unit cell, relative to the origin.
101  /** That is, the unit cell is
102  \code
103  BoundingBoxD<D>(get_zeros_vector_d<D>(),get_unit_cell());
104  \endcode
105  */
106  const VectorD<D> &get_unit_cell() const { return unit_cell_; }
107  //! Return the index that would contain the voxel if the grid extended there
108  /** For example vectors below the "lower left" corner of the grid have
109  indexes with all negative components. This operation will always
110  succeed.
111  */
114  origin_.get_dimension());
115  for (unsigned int i = 0; i < get_dimension(); ++i) {
116  double d = o[i] - origin_[i];
117  double fi = d * inverse_unit_cell_[i];
118  ret.access_data().get_data()[i] = static_cast<int>(std::floor(fi));
119  }
120  return ret;
121  }
122  GridIndexD<D> get_index(const VectorD<D> &o) const {
124  origin_.get_dimension());
125  for (unsigned int i = 0; i < get_dimension(); ++i) {
126  double d = o[i] - origin_[i];
127  double fi = d * inverse_unit_cell_[i];
128  ret.access_data().get_data()[i] = static_cast<int>(std::floor(fi));
129  }
130  return ret;
131  }
132  /** \name Center
133  Return the coordinates of the center of the voxel.
134  @{
135  */
136  VectorD<D> get_center(const ExtendedGridIndexD<D> &ei) const {
137  return origin_ +
138  get_elementwise_product(get_unit_cell(), get_uniform_offset(ei, .5));
139  }
140  VectorD<D> get_center(const GridIndexD<D> &ei) const {
141  return origin_ +
142  get_elementwise_product(get_unit_cell(), get_uniform_offset(ei, .5));
143  }
144  /** @} */
145 
146  /** \name Bounding box
147  Return the bounding box of the voxel.
148  @{
149  */
150  BoundingBoxD<D> get_bounding_box(const ExtendedGridIndexD<D> &ei) const {
151  return BoundingBoxD<D>(
152  origin_ + get_elementwise_product(unit_cell_, ei),
153  origin_ +
154  get_elementwise_product(unit_cell_, get_uniform_offset(ei, 1)));
155  }
156  BoundingBoxD<D> get_bounding_box(const GridIndexD<D> &ei) const {
157  return BoundingBoxD<D>(
158  origin_ + get_elementwise_product(unit_cell_, ei),
159  origin_ +
160  get_elementwise_product(unit_cell_, get_uniform_offset(ei, 1)));
161  }
162  /** @} */
163  IMP_SHOWABLE_INLINE(DefaultEmbeddingD, out << "origin: " << origin_
164  << " unit cell: " << unit_cell_);
165 };
166 
167 #if !defined(IMP_DOXYGEN)
168 typedef DefaultEmbeddingD<1> DefaultEmbedding1D;
169 typedef Vector<DefaultEmbedding1D> DefaultEmbedding1Ds;
170 
171 typedef DefaultEmbeddingD<2> DefaultEmbedding2D;
172 typedef Vector<DefaultEmbedding2D> DefaultEmbedding2Ds;
173 
174 typedef DefaultEmbeddingD<3> DefaultEmbedding3D;
175 typedef Vector<DefaultEmbedding3D> DefaultEmbedding3Ds;
176 
177 typedef DefaultEmbeddingD<4> DefaultEmbedding4D;
178 typedef Vector<DefaultEmbedding4D> DefaultEmbedding4Ds;
179 
180 typedef DefaultEmbeddingD<5> DefaultEmbedding5D;
181 typedef Vector<DefaultEmbedding5D> DefaultEmbedding5Ds;
182 
183 typedef DefaultEmbeddingD<6> DefaultEmbedding6D;
184 typedef Vector<DefaultEmbedding6D> DefaultEmbedding6Ds;
185 
186 typedef DefaultEmbeddingD<-1> DefaultEmbeddingKD;
187 typedef Vector<DefaultEmbeddingKD> DefaultEmbeddingKDs;
188 #endif
189 
190 /** Embedding of a grid as log-evenly spaced axis aligned grid.*/
191 template <int D>
193  VectorD<D> origin_;
194  VectorD<D> unit_cell_;
195  VectorD<D> base_;
196 
197  friend class boost::serialization::access;
198 
199  template<class Archive> void serialize(Archive &ar, const unsigned int) {
200  ar & origin_ & unit_cell_ & base_;
201  }
202 
203  template <class O>
204  VectorD<D> get_coordinates(const O &index) const {
205  VectorD<D> ret = origin_;
206  for (unsigned int i = 0; i < unit_cell_.get_dimension(); ++i) {
207  IMP_USAGE_CHECK(index[i] >= 0, "Out of range index in log graph.'");
208  if (base_[i] != 1) {
209  IMP_USAGE_CHECK(index[i] >= 0,
210  "Log grid axis must have positive index.");
211  ret[i] += unit_cell_[i] * (1.0 - std::pow(base_[i], index[i])) /
212  (1.0 - base_[i]);
213  } else {
214  ret[i] += unit_cell_[i] * index[i];
215  }
216  }
217  return ret;
218  }
219  template <class O>
220  VectorD<D> get_uniform_offset(const O &v0, double o) const {
221  Floats ret(get_dimension());
222  for (unsigned int i = 0; i < get_dimension(); ++i) {
223  ret[i] = v0[i] + o;
224  }
225  return VectorD<D>(ret.begin(), ret.end());
226  }
227  void initialize_from_box(Ints ns, const BoundingBoxD<D> &bb) {
228  Floats nuc(bb.get_dimension());
229  for (unsigned int i = 0; i < bb.get_dimension(); ++i) {
230  double side = bb.get_corner(1)[i] - bb.get_corner(0)[i];
231  IMP_USAGE_CHECK(side > 0, "Can't have flat grid");
232  nuc[i] = side / ns[i];
233  }
234  set_unit_cell(VectorD<D>(nuc.begin(), nuc.end()));
235  set_origin(bb.get_corner(0));
236  }
237 
238  public:
239  LogEmbeddingD(const VectorD<D> &origin, const VectorD<D> &cell,
240  const VectorD<D> &base) {
241  set_origin(origin);
242  set_unit_cell(cell, base);
243  }
244  /** Embedding of a grid as a log-evenly distributed axis-aligned grid
245  over the bounding box bb.
246 
247  @param bb the bounding box in which the grid is embedded
248  @param bases bases[i] is a positive log base used for the grid
249  spacing in dimension i. Set base[i] to 1 in order
250  to create a standard evenly spaced grid along
251  dimension i.
252  @param counts counts[i] is the number of discrete points in dimension i
253  @param bound_centers if true, then the bounding box tightly bounds
254  the centers of the voxels, not their extents.
255  */
256  LogEmbeddingD(const BoundingBoxD<D> &bb, const VectorD<D> &bases,
257  const Ints &counts, bool bound_centers = false) {
258  set_origin(bb.get_corner(0));
259  VectorD<D> cell = bb.get_corner(0);
260  for (unsigned int i = 0; i < bases.get_dimension(); ++i) {
261  IMP_ALWAYS_CHECK(bases[i] > 0,
262  "LogEmbedding base #" << i << " cannot be negative",
264  // cell[i](1-base[i]^counts[i])/(1-base[i])=width[i]
265  if (bases[i] != 1) {
266  cell[i] = (bb.get_corner(1)[i] - bb.get_corner(0)[i]) * (bases[i] - 1) /
267  (std::pow(bases[i], counts[i]) - 1.0);
268  } else {
269  cell[i] = (bb.get_corner(1)[i] - bb.get_corner(0)[i]) / counts[i];
270  }
272  .9 * cell[i] < bb.get_corner(1)[i] - bb.get_corner(0)[i],
273  "Too large a cell side");
274  IMP_INTERNAL_CHECK(cell[i] > 0, "Non-positive cell side");
275  }
276  set_unit_cell(cell, bases);
277  if (bound_centers) {
278  VectorD<D> lower_corner = get_center(GridIndexD<D>(
279  typename GridIndexD<D>::Filled(), bases.get_dimension(), 0));
280  VectorD<D> upper_corner = get_coordinates(
281  get_uniform_offset(GridIndexD<D>(counts.begin(), counts.end()), -.5));
282  VectorD<D> extents = upper_corner - lower_corner;
283  VectorD<D> uc = cell;
284  VectorD<D> orig = uc;
285  for (unsigned int i = 0; i < uc.get_dimension(); ++i) {
286  uc[i] =
287  (bb.get_corner(1)[i] - bb.get_corner(0)[i]) / extents[i] * uc[i];
288  if (base_[i] == 1) {
289  orig[i] = bb.get_corner(0)[i] - .5 * uc[i];
290  } else {
291  /*orig[i]+ uc[i]*(1.0-std::pow(base_[i], index[i]))
292  /(1.0-base_[i])==bb[i]*/
293  orig[i] = bb.get_corner(0)[i] -
294  uc[i] * (1.0 - std::pow(bases[i], .5)) / (1.0 - bases[i]);
295  }
296  }
297  set_origin(orig);
298  set_unit_cell(uc, bases);
299  }
300  }
301  LogEmbeddingD(const VectorD<D> &, const VectorD<D> &) {
302  IMP_FAILURE("not supported");
303  }
304  LogEmbeddingD() {}
305  void set_origin(const VectorD<D> &o) { origin_ = o; }
306  const VectorD<D> get_origin() const { return origin_; }
307  unsigned int get_dimension() const { return get_origin().get_dimension(); }
308  void set_unit_cell(const VectorD<D> &o, const VectorD<D> &base) {
309  unit_cell_ = o;
310  base_ = base;
311  }
312  void set_unit_cell(const VectorD<D> &o) { unit_cell_ = o; }
313  //! Return the unit cell, relative to the origin.
314  /** That is, the unit cell is
315  \code
316  BoundingBoxD<D>(get_zeros_vector_d<D>(),get_unit_cell());
317  \endcode
318  */
319  const VectorD<D> &get_unit_cell() const { return unit_cell_; }
320  //! Return the index that would contain the voxel if the grid extended there
321  /** For example vectors below the "lower left" corner of the grid have
322  indexes with all negative components. This operation will always
323  succeed.
324  */
327  origin_.get_dimension());
328  for (unsigned int i = 0; i < get_dimension(); ++i) {
329  double d = o[i] - origin_[i];
330  // cache everything
331  double fi = d / unit_cell_[i];
332  double li = std::log(fi) / std::log(base_[i]);
333  ret.access_data().get_data()[i] = static_cast<int>(std::floor(li));
334  }
335  return ret;
336  }
337  GridIndexD<D> get_index(const VectorD<D> &o) const {
338  ExtendedGridIndexD<D> ei = get_extended_index(o);
339  return GridIndexD<D>(ei.begin(), ei.end());
340  }
341  /** \name Center
342  Return the coordinates of the center of the voxel.
343  @{
344  */
345  VectorD<D> get_center(const ExtendedGridIndexD<D> &ei) const {
346  return get_coordinates(get_uniform_offset(ei, .5));
347  }
348  VectorD<D> get_center(const GridIndexD<D> &ei) const {
349  return get_coordinates(get_uniform_offset(ei, .5));
350  }
351  /** @} */
352 
353  /** \name Bounding box
354  Return the bounding box of the voxel.
355  @{
356  */
357  BoundingBoxD<D> get_bounding_box(const ExtendedGridIndexD<D> &ei) const {
358  return BoundingBoxD<D>(get_coordinates(ei),
359  get_coordinates(get_uniform_offset(ei, 1)));
360  }
361  BoundingBoxD<D> get_bounding_box(const GridIndexD<D> &ei) const {
362  return get_bounding_box(ExtendedGridIndexD<D>(ei.begin(), ei.end()));
363  }
364  /** @} */
365  IMP_SHOWABLE_INLINE(LogEmbeddingD, out << "origin: " << origin_
366  << " base: " << base_);
367 };
368 
369 #if !defined(IMP_DOXYGEN)
370 typedef LogEmbeddingD<1> LogEmbedding1D;
371 typedef Vector<LogEmbedding1D> LogEmbedding1Ds;
372 
373 typedef LogEmbeddingD<2> LogEmbedding2D;
374 typedef Vector<LogEmbedding2D> LogEmbedding2Ds;
375 
376 typedef LogEmbeddingD<3> LogEmbedding3D;
377 typedef Vector<LogEmbedding3D> LogEmbedding3Ds;
378 
379 typedef LogEmbeddingD<4> LogEmbedding4D;
380 typedef Vector<LogEmbedding4D> LogEmbedding4Ds;
381 
382 typedef LogEmbeddingD<5> LogEmbedding5D;
383 typedef Vector<LogEmbedding5D> LogEmbedding5Ds;
384 
385 typedef LogEmbeddingD<6> LogEmbedding6D;
386 typedef Vector<LogEmbedding6D> LogEmbedding6Ds;
387 
388 typedef LogEmbeddingD<-1> LogEmbeddingKD;
389 typedef Vector<LogEmbeddingKD> LogEmbeddingKDs;
390 #endif
391 
392 IMPALGEBRA_END_NAMESPACE
393 
394 #endif /* IMPALGEBRA_GRID_EMBEDDINGS_H */
Basic types used by IMP.
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
VectorD< D > get_elementwise_product(const algebra::VectorD< D > &a, const algebra::VectorD< D > &b)
Return the vector that is the elementwise product of the two.
Definition: VectorD.h:457
const VectorD< D > & get_corner(unsigned int i) const
For 0 return lower corner and for 1, the upper corner.
Definition: BoundingBoxD.h:140
#define IMP_FAILURE(message)
A runtime failure for IMP.
Definition: check_macros.h:72
A class to represent a voxel grid.
Represent a real cell in a grid (one within the bounding box)
Definition: grid_indexes.h:170
An index in an infinite grid on space.
Definition: grid_indexes.h:31
ExtendedGridIndexD< D > get_extended_index(const VectorD< D > &o) const
Return the index that would contain the voxel if the grid extended there.
Exception definitions and assertions.
#define IMP_INTERNAL_CHECK(expr, message)
An assertion to check for internal errors in IMP. An IMP::ErrorException will be thrown.
Definition: check_macros.h:139
A Cartesian vector in D-dimensions.
Definition: VectorD.h:52
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
ExtendedGridIndexD< D > get_extended_index(const VectorD< D > &o) const
Return the index that would contain the voxel if the grid extended there.
const VectorD< D > & get_unit_cell() const
Return the unit cell, relative to the origin.
A bounding box in D dimensions.
A class for storing lists of IMP items.
An axis-aligned bounding box.
Definition: BoundingBoxD.h:28
Helper macros for throwing and handling exceptions.
Embed a grid as an evenly spaced axis aligned grid.
Simple 3D vector class.
const VectorD< D > & get_unit_cell() const
Return the unit cell, relative to the origin.
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168
const double * get_data() const
Return a pointer to the data stored.
Definition: VectorBaseD.h:232
#define IMP_ALWAYS_CHECK(condition, message, exception_name)
Throw an exception if a check fails.
Definition: check_macros.h:61
An exception for an invalid value being passed to IMP.
Definition: exception.h:136
LogEmbeddingD(const BoundingBoxD< D > &bb, const VectorD< D > &bases, const Ints &counts, bool bound_centers=false)