BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
InstrumentItems.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/Model/Device/InstrumentItems.cpp
6 //! @brief Implement class InstrumentItem and all its children
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/Const/Units.h"
17 #include "Base/Pixel/RectangularPixel.h"
18 #include "Device/Beam/Beam.h"
19 #include "Device/Coord/CoordSystem1D.h"
20 #include "Device/Coord/CoordSystem2D.h"
21 #include "Device/Detector/RectangularDetector.h"
22 #include "Device/Detector/SphericalDetector.h"
34 #include "GUI/Support/XML/Backup.h"
36 #include "GUI/Util/CoordName.h"
37 #include "GUI/Util/Error.h"
38 #include "GUI/Util/String.h"
39 #include "Sim/Simulation/DepthProbeSimulation.h"
40 #include "Sim/Simulation/OffspecSimulation.h"
41 #include "Sim/Simulation/ScatteringSimulation.h"
42 
43 namespace {
44 
45 void setBeamDistribution(ParameterDistribution::WhichParameter which,
46  const BeamDistributionItem& item, ISimulation& simulation)
47 {
48  auto P_par_distr = item.getParameterDistributionForName(which);
49  if (P_par_distr)
50  simulation.addParameterDistribution(*P_par_distr);
51 }
52 
53 } // namespace
54 
55 // ************************************************************************************************
56 // class InstrumentItem
57 // ************************************************************************************************
58 
60  : m_withPolarizerAnalyzer(false)
61 {
62  m_id = QUuid::createUuid().toString();
63  m_analyzerEfficiency.init("Analyzer efficiency", "Efficiency of the polarization analysis", 0.0,
64  Unit::unitless, 4, RealLimits::limitless(), "efficiency");
65  m_analyzerTotalTransmission.init("Analyzer transmission",
66  "Total transmission of the polarization analysis", 1.0,
67  Unit::unitless, 4, RealLimits::nonnegative(), "transmission");
68  m_polarization.init("Polarization (Bloch vector)",
69  "Polarization of the beam, given as the Bloch vector", Unit::unitless,
70  "polarization");
71  m_analyzerDirection.init("Analyzer direction", "Direction of the polarization analysis",
72  Unit::unitless, "analyzerDirection");
73  m_backgroundItem.init<BackgroundItemCatalog>("Background", "", "background");
74 }
75 
77 {
78  const auto type = InstrumentItemCatalog::type(this);
79  auto* copy = InstrumentItemCatalog::create(type);
80  GUI::Util::copyContents(this, copy);
81  return copy;
82 }
83 
84 QString InstrumentItem::id() const
85 {
86  return m_id;
87 }
88 
89 void InstrumentItem::setId(const QString& id)
90 {
91  m_id = id;
92 }
93 
94 void InstrumentItem::setInstrumentName(const QString& instrumentName)
95 {
97 }
98 
100 {
101  return m_name;
102 }
103 
105 {
106  return m_description;
107 }
108 
109 void InstrumentItem::setDescription(const QString& description)
110 {
112 }
113 
115 {
116  return m_beamItem.get();
117 }
118 
120 {
121  return m_backgroundItem.get();
122 }
123 
125 {
126  return m_backgroundItem;
127 }
128 
130 {
131  return shape() == item->shape();
132 }
133 
135 {
137 }
138 
140 {
142 }
143 
144 template <typename T>
146 {
147  return dynamic_cast<T*>(m_beamItem.get());
148 }
149 
151 {
152  s.assertVersion(0);
153  Serialize::rwValue(s, "id", m_id);
154  Serialize::rwValue(s, "name", m_name);
155  Serialize::rwValue(s, "description", m_description);
157  Serialize::rwProperty(s, m_polarization);
158  Serialize::rwProperty(s, m_analyzerDirection);
159  Serialize::rwProperty(s, m_analyzerEfficiency);
160  Serialize::rwProperty(s, m_analyzerTotalTransmission);
161  Serialize::rwSelected<BackgroundItemCatalog>(s, m_backgroundItem);
162  Serialize::rwClass(s, "beam", *m_beamItem);
163 }
164 
165 // ************************************************************************************************
166 // class SpecularInstrumentItem
167 // ************************************************************************************************
168 
170 {
171  m_beamItem.reset(new SpecularBeamItem(this));
172 }
173 
175 {
176  return beam<SpecularBeamItem>();
177 }
178 
179 std::vector<int> SpecularInstrumentItem::shape() const
180 {
181  auto* const axis_item = beamItem()->inclinationAxis();
182  return {axis_item->binCount()};
183 }
184 
186 {
187  if (shape().size() != item->shape().size())
188  throw Error("Error in SpecularInstrumentItem::updateToRealData: The type "
189  "of instrument is incompatible with passed data shape.");
190 
191  const auto& data = item->nativeDatafield()->axis(0);
192  beamItem()->updateToData(data, item->nativeDataUnits());
193 }
194 
196 {
197  const QString native_units = item->nativeDataUnits();
198  if (native_units == "nbins") {
200  && shape() == item->shape();
201  }
202 
203  if (!beamItem()->inclinationAngleItem()->pointwiseAlphaAxisSelected())
204  return false;
205 
206  const auto* axisItem =
207  dynamic_cast<const PointwiseAxisItem*>(beamItem()->inclinationAngleItem()->alphaAxis());
208  ASSERT(axisItem);
209 
210  if (axisItem->getUnitsLabel() != native_units)
211  return false;
212 
213  const auto* instrumentAxis = axisItem->axis();
214  if (!instrumentAxis)
215  return false;
216 
217  if (!item->hasNativeData())
218  return false;
219 
220  const auto& native_axis = item->nativeDatafield()->axis(0);
221  return *instrumentAxis == native_axis;
222 }
223 
225 {
226  std::unique_ptr<Beam> beam = beamItem()->createBeam();
227  auto* axis_item = beamItem()->inclinationAxis();
228  if (auto* pointwise_axis = dynamic_cast<PointwiseAxisItem*>(axis_item)) {
229  if (!pointwise_axis->axis()) // workaround for loading project
230  return nullptr;
231  Coords native_units = GUI::Util::CoordName::coordFromName(pointwise_axis->getUnitsLabel());
232  return new AngularReflectometryCoordinates(beam->wavelength(), *pointwise_axis->axis(),
233  native_units);
234  }
235 
236  return new AngularReflectometryCoordinates(beam->wavelength(), *axis_item->createAxis(1.0),
237  Coords::DEGREES);
238 }
239 
241 {
242  return "Specular";
243 }
244 
246 {
247  return "Specular";
248 }
249 
250 // ************************************************************************************************
251 // class DepthProbeInstrumentItem
252 // ************************************************************************************************
253 
255 {
256  m_beamItem.reset(new SpecularBeamItem(this));
257 
258  auto* axisItem = beamItem()->inclinationAxis();
259  axisItem->setLowerBound(0.0);
260  axisItem->setUpperBound(1.0);
261  axisItem->setBinCount(500);
262 
263  m_zAxis.initNbins("Nbins", "Number of points in scan across sample bulk");
264  m_zAxis.initMin("Min", "Starting value below sample horizon", -100.0, Unit::nanometer,
265  RealLimits::limitless());
266  m_zAxis.initMax("Max", "Ending value above sample horizon", 100.0, Unit::nanometer,
267  RealLimits::limitless());
268 }
269 
271 {
272  s.assertVersion(0);
273  Serialize::rwBaseClass<InstrumentItem>(s, "InstrumentItem", this);
274  m_zAxis.rwAxisProperty(s, "zAxis");
275 }
276 
278 {
279  return beam<SpecularBeamItem>();
280 }
281 
282 std::vector<int> DepthProbeInstrumentItem::shape() const
283 {
284  return std::vector<int>(); // no certain shape to avoid linking to real data
285 }
286 
288 {
289  throw std::runtime_error("DepthProbeInstrumentItem::updateToRealData()");
290 }
291 
293 {
294  return "DepthProbe";
295 }
296 
298 {
299  return "Depth probe";
300 }
301 
302 DepthProbeSimulation* DepthProbeInstrumentItem::createSimulation(const MultiLayer& sample) const
303 {
304  auto* simulation = new DepthProbeSimulation(sample);
305 
306  auto* const axis_item = beamItem()->inclinationAxis();
307  auto axis = axis_item->createAxis(Units::deg);
308 
309  simulation->setBeamParameters(beamItem()->wavelength(), static_cast<int>(axis->size()),
310  axis->min(), axis->max());
311 
312  simulation->setZSpan(m_zAxis.nbins(), m_zAxis.min(), m_zAxis.max());
313 
314  setBeamDistribution(ParameterDistribution::BeamWavelength, *beamItem()->wavelengthItem(),
315  *simulation);
316 
317  setBeamDistribution(ParameterDistribution::BeamInclinationAngle,
318  *beamItem()->inclinationAngleItem(), *simulation);
319 
320  return simulation;
321 }
322 
324 {
325  // TODO set pol filters ?
326  return nullptr; // TODO NOW RESTORE createSimulation()->createCoordSystem();
327 }
328 
329 // ************************************************************************************************
330 // class Instrument2DItem
331 // ************************************************************************************************
332 
334 {
335  m_beamItem.reset(new GISASBeamItem());
336  m_detectorItem.init<DetectorItemCatalog>("Detector", "", "detector");
337 }
338 
340 {
341  s.assertVersion(0);
342  Serialize::rwBaseClass<InstrumentItem>(s, "InstrumentItem", this);
343  Serialize::rwSelected<DetectorItemCatalog>(s, m_detectorItem);
344 }
345 
347 {
348  return m_detectorItem.get();
349 }
350 
352 {
353  return m_detectorItem;
354 }
355 
357 {
358  detectorItem()->importMasks(maskContainer);
359 }
360 
361 std::unique_ptr<Instrument> Instrument2DItem::createInstrument() const
362 {
363  auto beam = beamItem()->createBeam();
364  auto detector = detectorItem()->createDetector();
365  detector->setDetectorNormal(beam->direction().zReflected());
366 
367  return std::make_unique<Instrument>(*beam, *detector);
368 }
369 
370 ScatteringSimulation* Instrument2DItem::createScatteringSimulation(const MultiLayer& sample) const
371 {
372  auto beam = beamItem()->createBeam();
373  beam->setPolarization(m_polarization);
374  auto detector = detectorItem()->createDetector();
375  detector->setAnalyzer(m_analyzerDirection, m_analyzerEfficiency, m_analyzerTotalTransmission);
376  detector->setDetectorNormal(beam->direction().zReflected());
377 
378  auto* result = new ScatteringSimulation(*beam, sample, *detector);
379  return result;
380 }
381 
382 OffspecSimulation* Instrument2DItem::createOffspecSimulation(const MultiLayer& sample) const
383 {
384  auto beam = beamItem()->createBeam();
385  beam->setPolarization(m_polarization);
386  auto detector = detectorItem()->createDetector();
387  detector->setAnalyzer(m_analyzerDirection, m_analyzerEfficiency, m_analyzerTotalTransmission);
388  detector->setDetectorNormal(beam->direction().zReflected());
389 
390  auto* result = new OffspecSimulation(*beam, sample, *detector);
391  return result;
392 }
393 
394 // ************************************************************************************************
395 // class GISASInstrumentItem
396 // ************************************************************************************************
397 
398 std::vector<int> GISASInstrumentItem::shape() const
399 {
400  auto* detector_item = detectorItem();
401  return {detector_item->xSize(), detector_item->ySize()};
402 }
403 
405 {
406  if (!item)
407  return;
408 
409  const auto data_shape = item->shape();
410  if (shape().size() != data_shape.size())
411  throw Error("Error in GISASInstrumentItem::updateToRealData: The type of "
412  "instrument is incompatible with passed data shape.");
413  detectorItem()->setXSize(data_shape[0]);
414  detectorItem()->setYSize(data_shape[1]);
415 }
416 
418 {
419  return "GISAS";
420 }
421 
423 {
424  return "GISAS";
425 }
426 
428 {
429  const auto instrument = createInstrument();
430  return instrument->detector().scatteringCoords(instrument->beam());
431 }
432 
433 // ************************************************************************************************
434 // class OffspecInstrumentItem
435 // ************************************************************************************************
436 
438 {
439  m_alphaAxis.initNbins("Nbins", "Number of points in scan");
440  m_alphaAxis.initMin("Min", "Starting value", 0.0, Unit::degree, RealLimits::limited(-90, 90));
441  m_alphaAxis.initMax("Max", "Ending value", 10.0, Unit::degree, RealLimits::limited(-90, 90));
442 
443  auto* beam_item = dynamic_cast<GISASBeamItem*>(beamItem());
444  beam_item->setInclinationAngleGetter([=]() { return m_alphaAxis.min(); });
445 }
446 
448 {
449  s.assertVersion(0);
450  Serialize::rwBaseClass<Instrument2DItem>(s, "Instrument2DItem", this);
451  m_alphaAxis.rwAxisProperty(s, "alphaAxis");
452 }
453 
454 std::vector<int> OffspecInstrumentItem::shape() const
455 {
456  return {(int)m_alphaAxis.nbins(), detectorItem()->ySize()};
457 }
458 
460 {
461  if (!dataItem)
462  return;
463 
464  const auto data_shape = dataItem->shape();
465  if (shape().size() != data_shape.size())
466  throw Error("Error in OffspecInstrumentItem::updateToRealData: The type of "
467  "instrument is incompatible with passed data shape.");
468 
469  m_alphaAxis.setNbins(data_shape[0]);
470  detectorItem()->setYSize(data_shape[1]);
471 }
472 
474 {
475  return "Offspec";
476 }
477 
479 {
480  return "Off specular";
481 }
482 
484 {
485  IAxis* alphaAxis =
486  new FixedBinAxis("alpha", m_alphaAxis.nbins(), m_alphaAxis.min() * Units::deg,
487  m_alphaAxis.max() * Units::deg);
488  const auto instrument = createInstrument();
489  return instrument->detector().offspecCoords(alphaAxis, instrument->beam().direction());
490 }
Defines class BackgroundItemCatalog.
Defines BackgroundItem classes.
Defines GUI::Util namespace.
Defines class BeamWavelengthItem.
Defines namespace GUI::Util::CoordName.
Defines class DetectorItemCatalog.
Defines classes DetectorItems.
Defines error class.
Defines class InstrumentItemCatalog.
Defines class InstrumentItem and all its children.
Defines class Instrument.
Defines pointwise axis item.
Defines class RealDataItem.
Defines class RectangularDetectorItem.
Defines class Streamer.
Defines class SphericalDetectorItem.
Defines functions from namespace GUI::Util::String.
@ unitless
@ nanometer
@ degree
int binCount() const
Definition: AxesItems.cpp:26
void setLowerBound(double value)
Definition: AxesItems.cpp:48
virtual std::unique_ptr< IAxis > createAxis(double scale) const
Definition: AxesItems.cpp:110
The BeamDistributionItem handles wavelength, inclination and azimuthal parameter distribution for Bea...
std::unique_ptr< ParameterDistribution > getParameterDistributionForName(ParameterDistribution::WhichParameter which) const
std::unique_ptr< Beam > createBeam() const
Definition: BeamItems.cpp:97
QString instrumentType() const override
The type as how to show it on the UI. Do not use for type checking or similar!
DepthProbeSimulation * createSimulation(const MultiLayer &sample) const
SpecularBeamItem * beamItem() const override
QString defaultName() const override
The default user visible name when creating an instrument.
ICoordSystem * createCoordSystem() const override
void serialize(Streamer &s) override
void updateToRealData(const RealDataItem *item) override
std::vector< int > shape() const override
void importMasks(const MaskContainerItem *maskContainer)
virtual void setYSize(size_t ny)=0
sets the size of y-axis of the detector
virtual int ySize() const =0
Returns the size of y-axis of the detector.
std::unique_ptr< IDetector > createDetector() const
virtual void setXSize(size_t nx)=0
sets the size of x-axis of the detector
void setInclinationAngleGetter(std::function< double()> getter)
Explicitly set a getter function for the inclination angle.
Definition: BeamItems.cpp:222
QString instrumentType() const override
The type as how to show it on the UI. Do not use for type checking or similar!
ICoordSystem * createCoordSystem() const override
std::vector< int > shape() const override
QString defaultName() const override
The default user visible name when creating an instrument.
void updateToRealData(const RealDataItem *item) override
void serialize(Streamer &s) override
SelectionDescriptor< DetectorItem * > detectorSelection() const
DetectorItem * detectorItem() const
ScatteringSimulation * createScatteringSimulation(const MultiLayer &sample) const
OffspecSimulation * createOffspecSimulation(const MultiLayer &sample) const
SelectionProperty< DetectorItem * > m_detectorItem
std::unique_ptr< Instrument > createInstrument() const
void importMasks(const MaskContainerItem *maskContainer) override
static Type type(const InstrumentItem *item)
Returns the enum type of the given item.
static InstrumentItem * create(Type type)
Creates the item of the given type.
Abstract base class for instrument-specific item classes.
InstrumentItem * createCopy() const
Creates an exact copy; also ID is the same!
QString instrumentName() const
bool withPolarizerAnalyzer() const
QString id() const
void setId(const QString &id)
virtual std::vector< int > shape() const =0
void setDescription(const QString &description)
virtual BeamItem * beamItem() const
std::unique_ptr< BeamItem > m_beamItem
void setWithPolarizerAnalyzer(bool with)
SelectionDescriptor< BackgroundItem * > backgroundSelection() const
void setInstrumentName(const QString &instrumentName)
virtual void serialize(Streamer &s)
SelectionProperty< BackgroundItem * > m_backgroundItem
virtual bool alignedWith(const RealDataItem *item) const
BackgroundItem * backgroundItem() const
bool m_withPolarizerAnalyzer
QString description() const
Container holding various masks as children.
Definition: MaskItems.h:202
void updateToRealData(const RealDataItem *item) override
QString instrumentType() const override
The type as how to show it on the UI. Do not use for type checking or similar!
QString defaultName() const override
The default user visible name when creating an instrument.
std::vector< int > shape() const override
void serialize(Streamer &s) override
ICoordSystem * createCoordSystem() const override
Item for non-uniform axis with specified coordinates.
Provides access to experimental data, for display and fitting. Owns an AbstractDataLoader.
Definition: RealDataItem.h:33
QString nativeDataUnits() const
std::vector< int > shape() const
Returns the shape of underlying data item.
bool hasNativeData() const
const Datafield * nativeDatafield() const
Describes a selection (various possibilities and the current one).
T get() const
Direct access to the stored pointer.
void init(const QString &label, const QString &tooltip, const QString &persistentTag, ArgsForCreation... argsForCreation)
Initialize by means of a catalog class and optional creation arguments.
bool uniformAlphaAxisSelected() const
True if uniform axis is selected.
BasicAxisItem * alphaAxis() const
The currently selected axis.
BasicAxisItem * inclinationAxis() const
Definition: BeamItems.cpp:156
void updateToData(const IAxis &axis, QString units)
Definition: BeamItems.cpp:181
SpecularBeamInclinationItem * inclinationAngleItem() const override
Definition: BeamItems.cpp:151
ICoordSystem * createCoordSystem() const override
SpecularBeamItem * beamItem() const override
std::vector< int > shape() const override
QString defaultName() const override
The default user visible name when creating an instrument.
QString instrumentType() const override
The type as how to show it on the UI. Do not use for type checking or similar!
void updateToRealData(const RealDataItem *item) override
bool alignedWith(const RealDataItem *item) const override
Supports serialization to or deserialization from QXmlStream.
Definition: Streamer.h:36
void assertVersion(unsigned expectedVersion) const
As reader, throws DeserializationException unless the expected version is read. As writer,...
Definition: Streamer.cpp:26
Coords coordFromName(const QString &name)
Returns domain axes units type from their GUI name.
Definition: CoordName.cpp:46
void copyContents(const T *source, T *dest)
Definition: Backup.h:46
void rwProperty(Streamer &s, DoubleProperty &d)
void rwValue(Streamer &s, const QString &tag, bool &val)
Definition: Serialize.cpp:19
void rwClass(Streamer &s, const QString &tag, T &t)
Serializes an item from a class that provides the function void serialize(Streamer&).
Definition: Serialize.h:77