BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
IDetector.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Device/Detector/IDetector.cpp
6 //! @brief Implements common detector interface.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Base/Axis/FixedBinAxis.h"
17 #include "Base/Axis/Frame.h"
18 #include "Base/Axis/IAxis.h"
19 #include "Base/Const/Units.h"
20 #include "Base/Util/Assert.h"
21 #include "Device/Beam/Beam.h"
27 
28 namespace {
29 
30 inline size_t xcoord(size_t index, size_t sizeX, size_t sizeY)
31 {
32  return index / sizeY % sizeX;
33 }
34 
35 inline size_t ycoord(size_t index, size_t sizeY)
36 {
37  return index % sizeY;
38 }
39 
40 } // namespace
41 
43 
45  : INode()
46  , m_explicitROI(other.m_explicitROI)
47  , m_axes(other.m_axes)
48  , m_polAnalyzer(other.m_polAnalyzer)
49  , m_detector_mask(other.m_detector_mask)
50 {
51  if (other.m_detector_resolution)
53 }
54 
55 IDetector::~IDetector() = default;
56 
57 void IDetector::addDetAxis(const IAxis& axis)
58 {
60  if (rank() == 2)
61  m_detector_mask.reset(new DetectorMask(*m_axes[0], *m_axes[1]));
62 }
63 
64 size_t IDetector::rank() const
65 {
66  return m_axes.size();
67 }
68 
70 {
71  m_axes.clear();
72 }
73 
74 const IAxis& IDetector::axis(size_t index) const
75 {
76  ASSERT(index < rank());
77  return *m_axes[index];
78 }
79 
80 size_t IDetector::axisBinIndex(size_t index, size_t selected_axis) const
81 {
82  const size_t dim = rank();
83  size_t remainder(index);
84  size_t i_axis = dim;
85  for (size_t i = 0; i < dim; ++i) {
86  --i_axis;
87  if (selected_axis == i_axis)
88  return remainder % m_axes[i_axis]->size();
89  remainder /= m_axes[i_axis]->size();
90  }
91  ASSERT(0);
92 }
93 
95 {
96  if (m_explicitROI.size() != m_axes.size())
97  return 0;
98 
99  size_t s = 1;
100  for (const auto& roiOfAxis : m_explicitROI)
101  s *= roiOfAxis.roiSize;
102 
103  return s;
104 }
105 
106 std::pair<double, double> IDetector::boundsOfExplicitRegionOfInterest(size_t iAxis) const
107 {
108  ASSERT(iAxis < rank());
109  if (iAxis < m_explicitROI.size())
110  return {m_explicitROI[iAxis].lower, m_explicitROI[iAxis].upper};
111  return {0., 0.};
112 }
113 
114 size_t IDetector::totalSize() const
115 {
116  const size_t dim = rank();
117  if (dim == 0)
118  return 0;
119  size_t result = 1;
120  for (size_t i_axis = 0; i_axis < dim; ++i_axis)
121  result *= m_axes[i_axis]->size();
122  return result;
123 }
124 
126 {
127  const auto explicitSize = sizeOfExplicitRegionOfInterest();
128  return (explicitSize != 0) ? explicitSize : totalSize();
129 }
130 
132 {
133  return !m_axes.empty() && (m_explicitROI.size() == m_axes.size());
134 }
135 
137 {
138  OwningVector<IAxis> result;
139  for (size_t iAxis = 0; iAxis < m_axes.size(); ++iAxis) {
140  auto* axis = m_axes[iAxis]->clone();
142  result.emplace_back(axis);
143  }
144  return result;
145 }
146 
147 void IDetector::setAnalyzer(const R3 direction, double efficiency, double total_transmission)
148 {
149  m_polAnalyzer = PolFilter(direction, efficiency, total_transmission);
150 }
151 
152 void IDetector::setDetectorResolution(const IDetectorResolution& p_detector_resolution)
153 {
154  m_detector_resolution.reset(p_detector_resolution.clone());
155 }
156 
157 // TODO: pass dimension-independent argument to this function
159 {
160  ConvolutionDetectorResolution convFunc(resFunc);
161  setDetectorResolution(convFunc);
162 }
163 
165 {
166  m_explicitROI.clear();
167 }
168 
169 void IDetector::applyDetectorResolution(Datafield* p_intensity_map) const
170 {
171  ASSERT(p_intensity_map);
172 
173  if (m_detector_resolution) {
174  m_detector_resolution->applyDetectorResolution(p_intensity_map);
175  if (detectorMask() && detectorMask()->hasMasks()) {
176  // sets amplitude in masked areas to zero
177  std::unique_ptr<Datafield> buff(new Datafield(p_intensity_map->frame().cloned_axes()));
179  (*buff)[it.roiIndex()] = (*p_intensity_map)[it.roiIndex()];
180  });
181  p_intensity_map->setVector(buff->flatVector());
182  }
183  }
184 }
185 
187 {
188  return m_detector_resolution.get();
189 }
190 
192  const std::vector<std::unique_ptr<DiffuseElement>>& elements) const
193 {
194  std::unique_ptr<Datafield> detectorMap(createDetectorMap());
195  ASSERT(detectorMap);
196  size_t elementIndex = 0;
197  for (auto it = beginNonMaskedPoints(); it != endNonMaskedPoints(); ++it)
198  (*detectorMap)[it.roiIndex()] = elements[elementIndex++]->intensity();
200  applyDetectorResolution(detectorMap.get());
201 
202  return detectorMap.release();
203 }
204 
205 std::unique_ptr<Datafield> IDetector::createDetectorMap() const
206 {
207  const size_t dim = rank();
208  ASSERT(dim != 0);
209 
210  std::vector<IAxis*> axes;
211  for (size_t iAxis = 0; iAxis < dim; ++iAxis) {
212  IAxis* tmp = axis(iAxis).clone();
213  tmp->clip(regionOfInterestBounds(iAxis));
214  axes.emplace_back(tmp);
215  }
216 
217  return std::make_unique<Datafield>(axes);
218 }
219 
221 {
222  size_t result(0);
223  iterateOverNonMaskedPoints([&result](const_iterator) { ++result; });
224  return result;
225 }
226 
227 std::pair<double, double> IDetector::regionOfInterestBounds(size_t iAxis) const
228 {
229  ASSERT(iAxis < m_axes.size());
230 
231  const auto explicitBounds = boundsOfExplicitRegionOfInterest(iAxis);
232  if (explicitBounds.first != 0 || explicitBounds.second != 0)
233  return explicitBounds;
234 
235  return m_axes[iAxis]->bounds();
236 }
237 
238 std::vector<const INode*> IDetector::nodeChildren() const
239 {
240  return std::vector<const INode*>() << &m_polAnalyzer << m_detector_resolution;
241 }
242 
243 void IDetector::iterateOverRegionOfInterest(std::function<void(const_iterator)> func) const
244 {
245  if (this->rank() == 0)
246  return;
247 
248  for (auto it = beginRegionOfInterestPoints(); it != endRegionOfInterestPoints(); ++it)
249  func(it);
250 }
251 
252 void IDetector::iterateOverNonMaskedPoints(std::function<void(const_iterator)> func) const
253 {
254  if (this->rank() == 0)
255  return;
256 
257  for (auto it = beginNonMaskedPoints(); it != endNonMaskedPoints(); ++it)
258  func(it);
259 }
260 
262 {
264 }
265 
267 {
269 }
270 
272 {
274 }
275 
277 {
279 }
280 
281 size_t IDetector::regionOfInterestIndexToDetectorIndex(const size_t regionOfInterestIndex) const
282 {
283  if (m_explicitROI.size() != 2)
284  return regionOfInterestIndex;
285 
286  const auto& x = m_explicitROI[0];
287  const auto& y = m_explicitROI[1];
288 
289  const size_t globalIndex0 = y.lowerIndex + x.lowerIndex * y.detectorSize;
290  return globalIndex0 + ycoord(regionOfInterestIndex, y.roiSize)
291  + xcoord(regionOfInterestIndex, x.roiSize, y.roiSize) * y.detectorSize;
292 }
293 
294 size_t IDetector::detectorIndexToRegionOfInterestIndex(const size_t detectorIndex) const
295 {
296  if (m_explicitROI.size() != 2)
297  return detectorIndex;
298 
299  const auto& x = m_explicitROI[0];
300  const auto& y = m_explicitROI[1];
301 
302  const size_t ny = ycoord(detectorIndex, y.detectorSize);
303  if (ny < y.lowerIndex || ny > y.upperIndex)
304  throw std::runtime_error("IDetector::detectorIndexToRegionOfInterestIndex() -> Error.");
305 
306  const size_t nx = xcoord(detectorIndex, x.detectorSize, y.detectorSize);
307  if (nx < x.lowerIndex || nx > x.upperIndex)
308  throw std::runtime_error("IDetector::detectorIndexToRegionOfInterestIndex() -> Error.");
309 
310  return ny - y.lowerIndex + (nx - x.lowerIndex) * y.roiSize;
311 }
312 
313 /* -- IDetector::RoiOfAxis ----------------------------------------------------------- */
314 
315 IDetector::RoiOfAxis::RoiOfAxis(const IAxis& axis, double _lower, double _upper)
316 {
317  lower = _lower;
318  upper = _upper;
319 
322 
323  detectorSize = axis.size();
324  roiSize = upperIndex - lowerIndex + 1;
325 }
326 
327 /* -- from IDetector2D -- */
328 
329 void IDetector::setDetectorParameters(size_t n_x, double x_min, double x_max, size_t n_y,
330  double y_min, double y_max)
331 {
332  clear();
333  addDetAxis(FixedBinAxis(axisName(0), n_x, x_min, x_max));
334  addDetAxis(FixedBinAxis(axisName(1), n_y, y_min, y_max));
335 }
336 
337 void IDetector::setRegionOfInterest(double xlow, double ylow, double xup, double yup)
338 {
339  ASSERT(rank() == 2);
340 
341  m_explicitROI.clear();
342  m_explicitROI.emplace_back(axis(0), xlow, xup);
343  m_explicitROI.emplace_back(axis(1), ylow, yup);
344 }
345 
346 std::vector<size_t> IDetector::active_indices() const
347 {
348  std::vector<size_t> result;
349 
350  iterateOverNonMaskedPoints([&](const_iterator it) { result.push_back(it.detectorIndex()); });
351 
352  return result;
353 }
354 
355 std::unique_ptr<DetectorContext> IDetector::createContext() const
356 {
357  return std::make_unique<DetectorContext>(this);
358 }
359 
360 void IDetector::addMask(const IShape2D& shape, bool mask_value)
361 {
362  m_detector_mask->addMask(shape, mask_value);
363 }
364 
366 {
367  if (rank() != 2)
368  return;
369  addMask(InfinitePlane(), true);
370 }
371 
373 {
374  return m_detector_mask.get();
375 }
376 
377 size_t IDetector::getGlobalIndex(size_t x, size_t y) const
378 {
379  if (rank() != 2)
380  return totalSize();
381  return x * axis(1).size() + y;
382 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:45
Defines class Beam.
Defines class ConvolutionDetectorResolution.
Define DetectorContext class.
Defines class DetectorMask.
Defines class DiffuseElement.
Defines class FixedBinAxis.
Defines and implements templated class Frame.
Defines interface IAxis.
Defines common detector interface.
Defines class InfinitePlane.
Defines some unit conversion factors and other constants in namespace Units.
Convolutes the intensity in 1 or 2 dimensions with a resolution function.
Stores radiation power per bin.
Definition: Datafield.h:30
void setVector(const std::vector< double > &data_vector)
Sets new values to raw data vector.
Definition: Datafield.cpp:69
const Frame & frame() const
Definition: Datafield.cpp:86
Collection of detector masks.
Definition: DetectorMask.h:42
Axis with fixed bin size.
Definition: FixedBinAxis.h:23
std::vector< IAxis * > cloned_axes() const
Returns cloned axes.
Definition: Frame.cpp:32
Abstract base class for one-dimensional axes.
Definition: IAxis.h:27
virtual size_t findClosestIndex(double value) const =0
find bin index which is best match for given value
virtual IAxis * clone() const =0
virtual size_t size() const =0
Returns the number of bins.
virtual void clip(double lower, double upper)
Clips this axis to the given values.
Definition: IAxis.cpp:35
Interface for detector resolution algorithms.
IDetectorResolution * clone() const override=0
Abstract detector interface.
Definition: IDetector.h:57
virtual std::pair< double, double > boundsOfExplicitRegionOfInterest(size_t iAxis) const
Lower and upper bound of one axis of an explicitly set ROI. Return 0/0 if no ROI has been explicitly ...
Definition: IDetector.cpp:106
size_t sizeOfRegionOfInterest() const
The size of the "Region of Interest". Same as totalSize() if no region of interest has been explicitl...
Definition: IDetector.cpp:125
void iterateOverRegionOfInterest(std::function< void(const_iterator)> func) const
Iterate over all points within "region of interest", no matter whether they are masked or not....
Definition: IDetector.cpp:243
OwningVector< IAxis > m_axes
Definition: IDetector.h:248
PolFilter m_polAnalyzer
Definition: IDetector.h:249
void addDetAxis(const IAxis &axis)
Definition: IDetector.cpp:57
virtual size_t sizeOfExplicitRegionOfInterest() const
Return 0 if no ROI has been explicitly set. Size means number of data points.
Definition: IDetector.cpp:94
virtual std::string axisName(size_t index) const =0
Returns the name for the axis with given index.
size_t numberOfElements() const
Returns number of simulation elements.
Definition: IDetector.cpp:220
SimulationAreaIterator beginRegionOfInterestPoints() const
Create begin-iterator to iterate over all points which lay within the "Region of Interest"....
Definition: IDetector.cpp:271
void setRegionOfInterest(double xlow, double ylow, double xup, double yup)
Sets rectangular region of interest with lower left and upper right corners defined.
Definition: IDetector.cpp:337
std::pair< double, double > regionOfInterestBounds(size_t iAxis) const
The lower and upper bound of the region of interest. If no region of interest is explicitly defined,...
Definition: IDetector.cpp:227
void maskAll()
Put the mask for all detector channels (i.e. exclude whole detector from the analysis)
Definition: IDetector.cpp:365
void iterateOverNonMaskedPoints(std::function< void(const_iterator)> func) const
Iterate over all non-masked points within "region of interest". If no region of interest is explicitl...
Definition: IDetector.cpp:252
void clear()
Definition: IDetector.cpp:69
std::vector< const INode * > nodeChildren() const override
Returns all children.
Definition: IDetector.cpp:238
SimulationAreaIterator beginNonMaskedPoints() const
Create begin-iterator to iterate over all points which are not masked and lay within the "Region of I...
Definition: IDetector.cpp:261
size_t axisBinIndex(size_t index, size_t selected_axis) const
Calculate axis index for given global index.
Definition: IDetector.cpp:80
size_t regionOfInterestIndexToDetectorIndex(size_t regionOfInterestIndex) const
Convert an index of the region of interest to an index of the detector. If no region of interest is s...
Definition: IDetector.cpp:281
size_t totalSize() const
Returns total number of pixels. Any region of interest is not taken into account.
Definition: IDetector.cpp:114
void setDetectorParameters(size_t n_x, double x_min, double x_max, size_t n_y, double y_min, double y_max)
Sets equidistant axes.
Definition: IDetector.cpp:329
std::unique_ptr< Datafield > createDetectorMap() const
Returns empty detector map in given axes units. This map is a data array limited to the size of the "...
Definition: IDetector.cpp:205
std::unique_ptr< IDetectorResolution > m_detector_resolution
Definition: IDetector.h:250
size_t detectorIndexToRegionOfInterestIndex(size_t detectorIndex) const
Definition: IDetector.cpp:294
const IAxis & axis(size_t index) const
One axis of the complete detector. Any region of interest is not taken into account.
Definition: IDetector.cpp:74
void addMask(const IShape2D &shape, bool mask_value=true)
Adds mask of given shape to the stack of detector masks. The mask value 'true' means that the channel...
Definition: IDetector.cpp:360
bool hasExplicitRegionOfInterest() const
True if a region of interest is explicitly set.
Definition: IDetector.cpp:131
void setResolutionFunction(const IResolutionFunction2D &resFunc)
Definition: IDetector.cpp:158
std::vector< size_t > active_indices() const
Returns vector of unmasked detector indices.
Definition: IDetector.cpp:346
OwningVector< IAxis > axesClippedToRegionOfInterest() const
Returns the axes clipped to the region of interest. If no region of interest is explicitly defined,...
Definition: IDetector.cpp:136
void setAnalyzer(R3 direction, double efficiency, double total_transmission)
Sets the polarization analyzer characteristics of the detector.
Definition: IDetector.cpp:147
SimulationAreaIterator endNonMaskedPoints() const
Create end-iterator to iterate over all points which are not masked and lay within the "Region of Int...
Definition: IDetector.cpp:266
std::unique_ptr< DetectorContext > createContext() const
Definition: IDetector.cpp:355
size_t getGlobalIndex(size_t x, size_t y) const
Calculate global index from two axis indices.
Definition: IDetector.cpp:377
void setDetectorResolution(const IDetectorResolution &p_detector_resolution)
Sets the detector resolution.
Definition: IDetector.cpp:152
std::vector< RoiOfAxis > m_explicitROI
an explicitly defined region of interest. Empty if no ROI has been defined. Vector index corresponds ...
Definition: IDetector.h:242
~IDetector() override
const IDetectorResolution * detectorResolution() const
Returns a pointer to detector resolution object.
Definition: IDetector.cpp:186
SimulationAreaIterator endRegionOfInterestPoints() const
Create end-iterator to iterate over all points which lay within the "Region of Interest"....
Definition: IDetector.cpp:276
void resetRegionOfInterest()
Resets region of interest making whole detector plane available for the simulation.
Definition: IDetector.cpp:164
size_t rank() const
Returns number of defined axes.
Definition: IDetector.cpp:64
const DetectorMask * detectorMask() const
Definition: IDetector.cpp:372
Datafield * createDetectorIntensity(const std::vector< std::unique_ptr< DiffuseElement >> &elements) const
Returns new intensity map with resolution applied, and cropped to ROI if applicable.
Definition: IDetector.cpp:191
void applyDetectorResolution(Datafield *p_intensity_map) const
Applies the detector resolution to the given intensity maps.
Definition: IDetector.cpp:169
std::shared_ptr< DetectorMask > m_detector_mask
Definition: IDetector.h:251
Base class for tree-like structures containing parameterized objects.
Definition: INode.h:40
Interface providing two-dimensional resolution function.
Basic class for all shapes in 2D.
Definition: IShape2D.h:26
The infinite plane is used for masking the entire detector.
Definition: InfinitePlane.h:28
void emplace_back(T *e)
Definition: OwningVector.h:62
void clear()
Definition: OwningVector.h:63
size_t size() const
Definition: OwningVector.h:70
bool empty() const
Definition: OwningVector.h:71
Detector properties (efficiency, transmission).
Definition: PolFilter.h:27
An iterator for SimulationArea.
SimulationAreaIterator createEnd() const
Convenience function to create an end-iterator matching to this iterator.
@ notMasked
iterate over all points in "region of interest" and not masked
@ regionOfInterest
iterate over all points in "region of interest", no matter whether masked
static SimulationAreaIterator createBegin(const IDetector *detector, Mode mode)
Create begin-iterator to iterate over all points according to the given mode.
size_t roiSize
number of bins on axis of ROI
Definition: IDetector.h:236
size_t upperIndex
index corresponding to 'upper'
Definition: IDetector.h:235
RoiOfAxis(const IAxis &axis, double lower, double upper)
Definition: IDetector.cpp:315
size_t detectorSize
number of bins on axis of detector
Definition: IDetector.h:237
size_t lowerIndex
index corresponding to 'lower'
Definition: IDetector.h:234