BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
RectangularDetector.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Device/Detector/RectangularDetector.cpp
6 //! @brief Implements class RectangularDetector.
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 
17 #include "Base/Const/Units.h"
19 #include "Device/Beam/Beam.h"
23 
24 RectangularDetector::RectangularDetector(size_t nxbins, double width, size_t nybins, double height)
25  : m_u0(0.0), m_v0(0.0), m_direction(kvector_t(0.0, -1.0, 0.0)), m_distance(0.0),
26  m_dbeam_u0(0.0), m_dbeam_v0(0.0), m_detector_arrangement(GENERIC)
27 {
28  setDetectorParameters(nxbins, 0.0, width, nybins, 0.0, height);
29  setName("RectangularDetector");
30 }
31 
33  : IDetector2D(other), m_normal_to_detector(other.m_normal_to_detector), m_u0(other.m_u0),
34  m_v0(other.m_v0), m_direction(other.m_direction), m_distance(other.m_distance),
35  m_dbeam_u0(other.m_dbeam_u0), m_dbeam_v0(other.m_dbeam_v0),
36  m_detector_arrangement(other.m_detector_arrangement), m_u_unit(other.m_u_unit),
37  m_v_unit(other.m_v_unit)
38 {
39  setName("RectangularDetector");
40 }
41 
42 RectangularDetector::~RectangularDetector() = default;
43 
44 RectangularDetector* RectangularDetector::clone() const
45 {
46  return new RectangularDetector(*this);
47 }
48 
50 {
51  double alpha_i = beam.getAlpha();
52  kvector_t central_k = beam.getCentralK();
53  initNormalVector(central_k);
54  initUandV(alpha_i);
55 }
56 
57 void RectangularDetector::setPosition(const kvector_t normal_to_detector, double u0, double v0,
58  const kvector_t direction)
59 {
60  m_detector_arrangement = GENERIC;
61  m_normal_to_detector = normal_to_detector;
62  m_distance = m_normal_to_detector.mag();
63  m_u0 = u0;
64  m_v0 = v0;
65  m_direction = direction;
66 }
67 
68 void RectangularDetector::setPerpendicularToSampleX(double distance, double u0, double v0)
69 {
70  m_detector_arrangement = PERPENDICULAR_TO_SAMPLE;
71  setDistanceAndOffset(distance, u0, v0);
72 }
73 
74 void RectangularDetector::setPerpendicularToDirectBeam(double distance, double u0, double v0)
75 {
76  m_detector_arrangement = PERPENDICULAR_TO_DIRECT_BEAM;
77  setDistanceAndOffset(distance, u0, v0);
78 }
79 
80 void RectangularDetector::setPerpendicularToReflectedBeam(double distance, double u0, double v0)
81 {
82  m_detector_arrangement = PERPENDICULAR_TO_REFLECTED_BEAM;
83  setDistanceAndOffset(distance, u0, v0);
84 }
85 
86 void RectangularDetector::setDirectBeamPosition(double u0, double v0)
87 {
88  m_detector_arrangement = PERPENDICULAR_TO_REFLECTED_BEAM_DPOS;
89  m_dbeam_u0 = u0;
90  m_dbeam_v0 = v0;
91 }
92 
93 double RectangularDetector::getWidth() const
94 {
95  const IAxis& axis = getAxis(0);
96  return axis.getMax() - axis.getMin();
97 }
98 
99 double RectangularDetector::getHeight() const
100 {
101  const IAxis& axis = getAxis(1);
102  return axis.getMax() - axis.getMin();
103 }
104 
105 size_t RectangularDetector::getNbinsX() const
106 {
107  return getAxis(0).size();
108 }
109 
110 size_t RectangularDetector::getNbinsY() const
111 {
112  return getAxis(1).size();
113 }
114 
115 kvector_t RectangularDetector::getNormalVector() const
116 {
117  return m_normal_to_detector;
118 }
119 
120 double RectangularDetector::getU0() const
121 {
122  return m_u0;
123 }
124 
125 double RectangularDetector::getV0() const
126 {
127  return m_v0;
128 }
129 
130 kvector_t RectangularDetector::getDirectionVector() const
131 {
132  return m_direction;
133 }
134 
135 double RectangularDetector::getDistance() const
136 {
137  return m_distance;
138 }
139 
140 double RectangularDetector::getDirectBeamU0() const
141 {
142  return m_dbeam_u0;
143 }
144 
145 double RectangularDetector::getDirectBeamV0() const
146 {
147  return m_dbeam_v0;
148 }
149 
150 RectangularDetector::EDetectorArrangement RectangularDetector::getDetectorArrangment() const
151 {
152  return m_detector_arrangement;
153 }
154 
156 {
157  return Axes::Units::MM;
158 }
159 
160 RectangularPixel* RectangularDetector::regionOfInterestPixel() const
161 {
162  const IAxis& u_axis = getAxis(0);
163  const IAxis& v_axis = getAxis(1);
164  double u_min, v_min, width, height;
165  auto p_roi = regionOfInterest();
166  if (p_roi) {
167  u_min = p_roi->getXlow();
168  v_min = p_roi->getYlow();
169  width = p_roi->getXup() - p_roi->getXlow();
170  height = p_roi->getYup() - p_roi->getYlow();
171  } else {
172  u_min = u_axis.getMin();
173  v_min = v_axis.getMin();
174  width = getWidth();
175  height = getHeight();
176  }
177  const kvector_t corner_position(m_normal_to_detector + (u_min - m_u0) * m_u_unit
178  + (v_min - m_v0) * m_v_unit);
179  const kvector_t uaxis_vector = width * m_u_unit;
180  const kvector_t vaxis_vector = height * m_v_unit;
181  return new RectangularPixel(corner_position, uaxis_vector, vaxis_vector);
182 }
183 
185 {
186  const IAxis& u_axis = getAxis(0);
187  const IAxis& v_axis = getAxis(1);
188  const size_t u_index = axisBinIndex(index, 0);
189  const size_t v_index = axisBinIndex(index, 1);
190 
191  const Bin1D u_bin = u_axis.getBin(u_index);
192  const Bin1D v_bin = v_axis.getBin(v_index);
193  const kvector_t corner_position(m_normal_to_detector + (u_bin.m_lower - m_u0) * m_u_unit
194  + (v_bin.m_lower - m_v0) * m_v_unit);
195  const kvector_t width = u_bin.getBinSize() * m_u_unit;
196  const kvector_t height = v_bin.getBinSize() * m_v_unit;
197  return new RectangularPixel(corner_position, width, height);
198 }
199 
200 std::string RectangularDetector::axisName(size_t index) const
201 {
202  switch (index) {
203  case 0:
204  return "u";
205  case 1:
206  return "v";
207  default:
209  "RectangularDetector::getAxisName(size_t index) -> Error! index > 1");
210  }
211 }
212 
214 {
215  if (dimension() != 2)
216  return totalSize();
217  const double alpha = beam.getAlpha();
218  const double phi = beam.getPhi();
219  const kvector_t k_spec = vecOfLambdaAlphaPhi(beam.getWavelength(), alpha, phi);
220  const kvector_t normal_unit = m_normal_to_detector.unit();
221  const double kd = k_spec.dot(normal_unit);
222  if (kd <= 0.0)
223  return totalSize();
224  ASSERT(m_distance != 0);
225  const kvector_t rpix = k_spec * (m_distance / kd);
226  const double u = rpix.dot(m_u_unit) + m_u0;
227  const double v = rpix.dot(m_v_unit) + m_v0;
228  const IAxis& u_axis = getAxis(0); // the x axis, GISAS only
229  const IAxis& v_axis = getAxis(1); // the y axis, in reflectometer plane
230  if (!u_axis.contains(u) || !v_axis.contains(v))
231  return totalSize();
232  return getGlobalIndex(u_axis.findClosestIndex(u), v_axis.findClosestIndex(v));
233 }
234 
235 void RectangularDetector::setDistanceAndOffset(double distance, double u0, double v0)
236 {
237  if (distance <= 0.0) {
238  std::ostringstream message;
239  message << "RectangularDetector::setPerpendicularToSample() -> Error. "
240  << "Distance to sample can't be negative or zero";
241  throw Exceptions::LogicErrorException(message.str());
242  }
243  m_distance = distance;
244  m_u0 = u0;
245  m_v0 = v0;
246 }
247 
248 void RectangularDetector::initNormalVector(const kvector_t central_k)
249 {
250  kvector_t central_k_unit = central_k.unit();
251 
252  if (m_detector_arrangement == GENERIC) {
253  // do nothing
254  }
255 
256  else if (m_detector_arrangement == PERPENDICULAR_TO_SAMPLE) {
257  m_normal_to_detector = kvector_t(m_distance, 0.0, 0.0);
258  }
259 
260  else if (m_detector_arrangement == PERPENDICULAR_TO_DIRECT_BEAM) {
261  m_normal_to_detector = m_distance * central_k_unit;
262  }
263 
264  else if (m_detector_arrangement == PERPENDICULAR_TO_REFLECTED_BEAM
265  || m_detector_arrangement == PERPENDICULAR_TO_REFLECTED_BEAM_DPOS) {
266  m_normal_to_detector = m_distance * central_k_unit;
267  m_normal_to_detector.setZ(-m_normal_to_detector.z());
268  }
269 
270  else {
272  "RectangularDetector::init() -> Unknown detector arrangement");
273  }
274 }
275 
276 void RectangularDetector::initUandV(double alpha_i)
277 {
278  double d2 = m_normal_to_detector.dot(m_normal_to_detector);
279  kvector_t u_direction =
280  d2 * m_direction - m_direction.dot(m_normal_to_detector) * m_normal_to_detector;
281  m_u_unit = u_direction.unit();
282  m_v_unit = m_u_unit.cross(m_normal_to_detector).unit();
283 
284  if (m_detector_arrangement == PERPENDICULAR_TO_REFLECTED_BEAM_DPOS) {
285  kvector_t z(0.0, 0.0, 1.0);
286  kvector_t normal_unit = m_normal_to_detector.unit();
287  kvector_t zp = z - z.dot(normal_unit) * normal_unit;
288  double uz = zp.dot(m_u_unit) / zp.mag();
289  double vz = zp.dot(m_v_unit) / zp.mag();
290  m_u0 = m_dbeam_u0 + m_distance * std::tan(2 * alpha_i) * uz;
291  m_v0 = m_dbeam_v0 + m_distance * std::tan(2 * alpha_i) * vz;
292  }
293 }
BasicVector3D< double > vecOfLambdaAlphaPhi(double _lambda, double _alpha, double _phi)
Creates a vector<double> as a wavevector with given wavelength and angles.
Defines class Beam.
Defines class IDetectorResolution.
Defines M_PI and some more mathematical constants.
Defines class RectangularDetector.
Defines class RectangularPixel.
Defines class RegionOfInterest.
Defines class SimulationElement.
Defines some unit conversion factors and other constants in namespace Units.
auto dot(const BasicVector3D< U > &v) const
Returns dot product of vectors (antilinear in the first [=self] argument).
BasicVector3D< T > unit() const
Returns unit vector in direction of this. Throws for null vector.
double mag() const
Returns magnitude of the vector.
T z() const
Returns z-component in cartesian coordinate system.
Definition: BasicVector3D.h:68
void setZ(const T &a)
Sets z-component in cartesian coordinate system.
Definition: BasicVector3D.h:75
auto cross(const BasicVector3D< U > &v) const
Returns cross product of vectors (linear in both arguments).
Beam defined by wavelength, direction and intensity.
Definition: Beam.h:27
kvector_t getCentralK() const
Returns the wavevector.
Definition: Beam.cpp:71
Interface for one-dimensional axes.
Definition: IAxis.h:25
virtual bool contains(double value) const
Returns true if axis contains given point.
Definition: IAxis.cpp:40
virtual size_t findClosestIndex(double value) const =0
find bin index which is best match for given value
virtual Bin1D getBin(size_t index) const =0
retrieve a 1d bin for the given index
virtual double getMin() const =0
Returns value of first point of axis.
virtual size_t size() const =0
retrieve the number of bins
virtual double getMax() const =0
Returns value of last point of axis.
Abstract 2D detector interface.
Definition: IDetector2D.h:31
const RegionOfInterest * regionOfInterest() const override
Returns region of interest if exists.
Definition: IDetector2D.cpp:43
void setDetectorParameters(size_t n_x, double x_min, double x_max, size_t n_y, double y_min, double y_max)
Sets detector parameters using angle ranges.
Definition: IDetector2D.cpp:35
size_t getGlobalIndex(size_t x, size_t y) const
Calculate global index from two axis indices.
Definition: IDetector2D.cpp:98
size_t dimension() const
Returns actual dimensionality of the detector (number of defined axes)
Definition: IDetector.cpp:44
size_t axisBinIndex(size_t index, size_t selected_axis) const
Calculate axis index for given global index.
Definition: IDetector.cpp:61
size_t totalSize() const
Returns total number of pixels.
Definition: IDetector.cpp:87
Interface for a function that maps [0,1]x[0,1] to the kvectors in a pixel.
Definition: IPixel.h:24
A flat rectangular detector with axes and resolution function.
void init(const Beam &beam) override
Inits detector with the beam settings.
Axes::Units defaultAxesUnits() const override
return default axes units
size_t indexOfSpecular(const Beam &beam) const override
Returns index of pixel that contains the specular wavevector.
IPixel * createPixel(size_t index) const override
Creates an IPixel for the given OutputData object and index.
std::string axisName(size_t index) const override
Returns the name for the axis with given index.
RectangularDetector(size_t nxbins, double width, size_t nybins, double height)
Rectangular detector constructor.
A pixel in a RectangularDetector.
Definition: Bin.h:20
double m_lower
lower bound of the bin
Definition: Bin.h:23