BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
ParameterTreeUtils.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/Model/Model/ParameterTreeUtils.cpp
6 //! @brief Implements ParameterTreeUtils namespace
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 
31 #include "GUI/Model/Job/JobItem.h"
42 
43 namespace {
44 
45 QString labelWithUnit(const QString& label, variant<QString, Unit> unit)
46 {
47  const QString s = std::holds_alternative<QString>(unit) ? std::get<QString>(unit)
48  : unitAsString(std::get<Unit>(unit));
49 
50  if (!s.isEmpty())
51  return label + " [" + s + "]";
52 
53  return label;
54 }
55 
56 template <typename Catalog>
57 ParameterLabelItem* addLabel(ParameterLabelItem* parent, const QString& category,
58  const typename Catalog::CatalogedType* p)
59 {
60  const auto title = category + " (" + Catalog::uiInfo(Catalog::type(p)).menuEntry + ")";
61  return new ParameterLabelItem(title, parent);
62 }
63 
64 template <typename Catalog>
65 ParameterLabelItem* addLabel(ParameterLabelItem* parent, const typename Catalog::CatalogedType* p)
66 {
67  const auto title = Catalog::uiInfo(Catalog::type(p)).menuEntry;
68  return new ParameterLabelItem(title, parent);
69 }
70 
71 } // namespace
72 
73 // ************************************************************************************************
74 
75 ParameterTreeBuilder::ParameterTreeBuilder(JobItem* jobItem, bool recreateBackupValues)
76  : m_jobItem(jobItem)
77  , m_recreateBackupValues(recreateBackupValues)
78 {
79 }
80 
82 {
83  addMaterials();
84  addSample();
85  addInstrument();
86 }
87 
89 {
90  auto* materialTopLabel =
91  new ParameterLabelItem("Materials", parameterContainer()->parameterTreeRoot());
92  for (auto* item : m_jobItem->sampleItem()->materialItems().materialItems()) {
93  auto* label = new ParameterLabelItem(item->matItemName(), materialTopLabel);
94  if (item->hasRefractiveIndex()) {
95  addParameterItem(label, item->delta());
96  addParameterItem(label, item->beta());
97  } else {
98  addParameterItem(label, item->sldRe());
99  addParameterItem(label, item->sldIm());
100  }
101 
102  if (allowMagneticFields())
103  addParameterItem(label, item->magnetizationVector());
104  }
105 }
106 
108 {
109  auto* label = new ParameterLabelItem("Sample", parameterContainer()->parameterTreeRoot());
111  if (allowMagneticFields())
113 
114  int iLayer = 0;
115  for (auto* layer : m_jobItem->sampleItem()->layers()) {
116  auto* layerLabel = new ParameterLabelItem("Layer" + QString::number(iLayer++), label);
117  if (!layer->isTopLayer() && !layer->isBottomLayer())
118  addParameterItem(layerLabel, layer->thickness());
119  if (!layer->isTopLayer())
120  if (auto* roughnessItem = layer->roughness().currentItem()) {
121  auto* roughnessLabel = new ParameterLabelItem("Top roughness", layerLabel);
122  addParameterItem(roughnessLabel, roughnessItem->sigma());
123  addParameterItem(roughnessLabel, roughnessItem->hurst());
124  addParameterItem(roughnessLabel, roughnessItem->lateralCorrelationLength());
125  }
126 
127  int iLayout = 0;
128  for (auto* layout : layer->layouts()) {
129  auto* label = new ParameterLabelItem("Layout" + QString::number(iLayout++), layerLabel);
130  if (!layout->totalDensityIsDefinedByInterference())
131  addParameterItem(label, layout->ownDensity());
132  addParameterItem(label, layout->weight());
133 
134  addInterference(label, layout);
135 
136  for (auto* p : layout->particles())
137  addParticle(label, p, true);
138  }
139  }
140 }
141 
143  const QString& label)
144 {
145  auto* parameterItem = new ParameterItem(parent);
146  parameterItem->setTitle(labelWithUnit(label.isEmpty() ? d.label : label, d.unit));
147  parameterItem->linkToDescriptor(d);
149  m_jobItem->parameterContainerItem()->setBackupValue(parameterItem->link(), d.get());
150 }
151 
153 {
154  auto* label = new ParameterLabelItem(d.label, parent);
155  addParameterItem(label, d.x);
156  addParameterItem(label, d.y);
157  addParameterItem(label, d.z);
158 }
159 
160 
162  ParameterLabelItem* parent, const std::variant<VectorDescriptor, DoubleDescriptor>& v)
163 {
164  std::visit([=](auto const& e) { addParameterItem(parent, e); }, v);
165 }
166 
168 {
170 }
171 
173 {
174  // TODO: return true when specular instrument is ready for magnetization
175  return !m_jobItem->isSpecularJob();
176 }
177 
179  const ParticleLayoutItem* layout)
180 {
181  const auto* interference = layout->interference().currentItem();
182  if (!interference)
183  return;
184 
185  const auto itfType = InterferenceItemCatalog::type(interference);
186  const QString title = InterferenceItemCatalog::uiInfo(itfType).menuEntry;
187 
188  auto* label = new ParameterLabelItem("Interference (" + title + ")", layoutLabel);
189 
190  if (const auto* itf = dynamic_cast<const InterferenceRadialParaCrystalItem*>(interference)) {
191  addParameterItem(label, itf->positionVariance());
192  addParameterItem(label, itf->peakDistance());
193  addParameterItem(label, itf->dampingLength());
194  addParameterItem(label, itf->domainSize());
195  addParameterItem(label, itf->kappa());
196 
197  const auto* pdf = itf->probabilityDistribution().currentItem();
198  auto* pdfLabel = addLabel<Profile1DItemCatalog>(label, "PDF", pdf);
199  for (const auto& d : pdf->valueDescriptors())
200  addParameterItem(pdfLabel, d);
201  } else if (const auto* itf = dynamic_cast<const Interference2DParaCrystalItem*>(interference)) {
202  addParameterItem(label, itf->positionVariance());
203  addParameterItem(label, itf->dampingLength());
204  addParameterItem(label, itf->domainSize1());
205  addParameterItem(label, itf->domainSize2());
206  addLattice(label, itf);
207 
208  const auto* pdf1 = itf->probabilityDistribution1().currentItem();
209  const auto* pdf2 = itf->probabilityDistribution2().currentItem();
210  const bool samePdfTypes =
212  auto* pdf1Label =
213  addLabel<Profile2DItemCatalog>(label, samePdfTypes ? "PDF1" : "PDF", pdf1);
214  for (const auto& d : pdf1->valueDescriptors())
215  addParameterItem(pdf1Label, d);
216  auto* pdf2Label =
217  addLabel<Profile2DItemCatalog>(label, samePdfTypes ? "PDF2" : "PDF", pdf2);
218  for (const auto& d : pdf2->valueDescriptors())
219  addParameterItem(pdf2Label, d);
220  } else if (const auto* itf = dynamic_cast<const Interference1DLatticeItem*>(interference)) {
221  addParameterItem(label, itf->positionVariance());
222  addParameterItem(label, itf->length());
223  addParameterItem(label, itf->rotationAngle());
224 
225  const auto* df = itf->decayFunction().currentItem();
226  auto* dfLabel = addLabel<Profile1DItemCatalog>(label, "Decay function", df);
227  for (const auto& d : df->valueDescriptors())
228  addParameterItem(dfLabel, d);
229  } else if (const auto* itf = dynamic_cast<const Interference2DLatticeItem*>(interference)) {
230  addParameterItem(label, itf->positionVariance());
231  addLattice(label, itf);
232 
233  const auto* df = itf->decayFunction().currentItem();
234  auto* dfLabel = addLabel<Profile2DItemCatalog>(label, "Decay function", df);
235  for (const auto& d : df->valueDescriptors())
236  addParameterItem(dfLabel, d);
237  } else if (const auto* itf =
238  dynamic_cast<const InterferenceFinite2DLatticeItem*>(interference)) {
239  // domainSize1 and domainSize2 are of type UInt (not matching the double approach for tuning
240  // and fitting). In BornAgain 1.18 these values have not been added to the tuning tree, and
241  // also not to the fitting parameters. Maybe this should be necessary, but for now this
242  // stays the same and the two sizes are not added
243  addParameterItem(label, itf->positionVariance());
244  addLattice(label, itf);
245  } else if (const auto* itf = dynamic_cast<const InterferenceHardDiskItem*>(interference)) {
246  addParameterItem(label, itf->positionVariance());
247  addParameterItem(label, itf->radius());
248  addParameterItem(label, itf->density());
249  }
250 }
251 
253  ItemWithParticles* p, bool enableAbundance,
254  bool enablePosition)
255 {
256  auto* label = addLabel<ItemWithParticlesCatalog>(parentLabel, p);
257 
258  if (enableAbundance)
259  addParameterItem(label, p->abundance());
260  if (enablePosition)
261  addParameterItem(label, p->positionVector());
262  addRotation(label, p);
263 
264  if (const auto* particle = dynamic_cast<const ParticleItem*>(p)) {
265  const auto* formFactor = particle->formfactor_at_bottom();
266  auto* ffLabel = addLabel<FormFactorItemCatalog>(label, "Formfactor", formFactor);
267  for (const auto& d : formFactor->geometryValues())
268  addParameterItem(ffLabel, d);
269  } else if (const auto* particleComposition = dynamic_cast<const ParticleCompositionItem*>(p)) {
270  for (auto* p : particleComposition->particles())
271  addParticle(label, p, false);
272  } else if (const auto* coreShell = dynamic_cast<const ParticleCoreShellItem*>(p)) {
273  auto* l = addParticle(label, coreShell->core(), false);
274  l->setTitle(l->title() + " (Core)");
275  l = addParticle(label, coreShell->shell(), false, false);
276  l->setTitle(l->title() + " (Shell)");
277  } else if (const auto* meso = dynamic_cast<const MesoCrystalItem*>(p)) {
278  addParameterItem(label, meso->vectorA());
279  addParameterItem(label, meso->vectorB());
280  addParameterItem(label, meso->vectorC());
281 
282  const auto* outerShape = meso->outerShape().currentItem();
283  auto* ffLabel = addLabel<FormFactorItemCatalog>(label, "Outer shape", outerShape);
284  for (const auto& d : outerShape->geometryValues())
285  addParameterItem(ffLabel, d);
286 
287  auto* l = addParticle(label, meso->basisParticle(), false);
288  l->setTitle(l->title() + " (Basis particle)");
289  }
290 
291  return label;
292 }
293 
296 {
297  const auto* lattice = itf->latticeType().currentItem();
298  auto* label = addLabel<Lattice2DItemCatalog>(parentLabel, "Lattice", lattice);
299  for (const auto& d : lattice->geometryValues(!itf->xiIntegration()))
300  addParameterItem(label, d);
301 }
302 
304 {
305  const auto* r = p->rotation().currentItem();
306  if (!r)
307  return;
308 
309  auto* label = addLabel<RotationItemCatalog>(parentLabel, "Rotation", r);
310  for (const auto& d : r->rotationValues())
311  addParameterItem(label, d);
312 }
313 
315 {
316  const auto* instrument = m_jobItem->instrumentItem();
317  auto* label = new ParameterLabelItem(instrument->instrumentType() + " instrument",
318  parameterContainer()->parameterTreeRoot());
319 
320  auto* beamItem = instrument->beamItem();
321  if (auto* gisas = dynamic_cast<const GISASInstrumentItem*>(instrument)) {
322  auto* beamLabel = new ParameterLabelItem("Beam", label);
323  addParameterItem(beamLabel, beamItem->intensity());
324  addBeamDistribution(beamLabel, beamItem->wavelengthItem(), "Wavelength");
325  addBeamDistribution(beamLabel, beamItem->inclinationAngleItem(), "Inclination angle");
326  addBeamDistribution(beamLabel, beamItem->azimuthalAngleItem(), "Azimuthal angle");
327  addDetector(label, gisas->detectorItem());
328  addPolarization(label, instrument);
329  addBackground(label, instrument->backgroundItem());
330  } else if (instrument->is<SpecularInstrumentItem>()) {
331  auto* beamLabel = new ParameterLabelItem("Beam", label);
332  addParameterItem(beamLabel, beamItem->intensity());
333  addBeamDistribution(beamLabel, beamItem->wavelengthItem(), "Wavelength", false);
334  addBeamDistribution(beamLabel, beamItem->inclinationAngleItem(), "Inclination angle",
335  false);
336  addPolarization(label, instrument);
337  addBackground(label, instrument->backgroundItem());
338  } else if (auto* os = dynamic_cast<const OffspecInstrumentItem*>(instrument)) {
339  auto* beamLabel = new ParameterLabelItem("Beam", label);
340  addParameterItem(beamLabel, beamItem->intensity());
341  addBeamDistribution(beamLabel, beamItem->wavelengthItem(), "Wavelength");
342  addBeamDistribution(beamLabel, beamItem->azimuthalAngleItem(), "Azimuthal angle");
343  addDetector(label, os->detectorItem());
344  addPolarization(label, instrument);
345  } else if (instrument->is<DepthProbeInstrumentItem>()) {
346  auto* beamLabel = new ParameterLabelItem("Parameters", label);
347  addBeamDistribution(beamLabel, beamItem->wavelengthItem(), "Wavelength");
348  addBeamDistribution(beamLabel, beamItem->inclinationAngleItem(), "Inclination angle",
349  false);
350  addPolarization(label, instrument);
351  } else
352  ASSERT(false);
353 }
354 
356  BeamDistributionItem* distributionItem,
357  const QString& label, bool withMean)
358 {
359  auto* distribution = distributionItem->distribution();
360  if (auto* dn = dynamic_cast<DistributionNoneItem*>(distribution)) {
361  if (withMean)
362  addParameterItem(parentLabel, dn->mean(), label);
363  } else {
364  const auto type = DistributionItemCatalog::type(distribution);
366  auto* item = new ParameterLabelItem(QString("%1 (%2 distribution)").arg(label).arg(name),
367  parentLabel);
368  for (const auto& d : distribution->distributionValues(withMean))
369  addParameterItem(item, d);
370  }
371 }
372 
374 {
375  const auto addResolutionFunction = [=](ParameterLabelItem* detLabel) {
376  if (auto* r = dynamic_cast<ResolutionFunction2DGaussianItem*>(
377  detector->resolutionFunctionSelection().currentItem())) {
378  auto* label = new ParameterLabelItem("Resolution (Gaussian)", detLabel);
379  addParameterItem(label, r->sigmaX());
380  addParameterItem(label, r->sigmaY());
381  }
382  };
383 
384  if (auto* rectDetector = dynamic_cast<RectangularDetectorItem*>(detector)) {
385  auto* label = new ParameterLabelItem("Detector (rectangular)", parentLabel);
386  addParameterItem(label, rectDetector->width());
387  addParameterItem(label, rectDetector->height());
388  addResolutionFunction(label);
389  for (const auto& a : rectDetector->alignmentPropertiesForUI())
390  addParameterItem(label, a);
391  } else if (auto* spherDetector = dynamic_cast<SphericalDetectorItem*>(detector)) {
392  auto* label = new ParameterLabelItem("Detector (spherical)", parentLabel);
393  auto* phiLabel = new ParameterLabelItem("Phi axis", label);
394  const QString unit = unitAsString(Unit::degree);
395  addParameterItem(phiLabel, spherDetector->phiAxis().min());
396  addParameterItem(phiLabel, spherDetector->phiAxis().max());
397  auto* alphaLabel = new ParameterLabelItem("Alpha axis", label);
398  addParameterItem(alphaLabel, spherDetector->alphaAxis().min());
399  addParameterItem(alphaLabel, spherDetector->alphaAxis().max());
400  addResolutionFunction(label);
401  } else
402  ASSERT(false);
403 }
404 
406  BackgroundItem* backgroundItem)
407 {
408  if (auto* b = dynamic_cast<ConstantBackgroundItem*>(backgroundItem))
409  addParameterItem(instrumentLabel, b->backgroundValue(),
410  labelWithUnit("Constant background", b->backgroundValue().unit));
411 }
412 
414  const InstrumentItem* instrument)
415 {
416  if (!instrument->withPolarizerAnalyzer())
417  return;
418 
419  auto* label = new ParameterLabelItem("Polarization analysis", instrumentLabel);
420  addParameterItem(label, instrument->polarization());
421  addParameterItem(label, instrument->analyzerDirection());
422  addParameterItem(label, instrument->analyzerEfficiency());
423  addParameterItem(label, instrument->analyzerTotalTransmission());
424 }
Defines various axis items.
Defines BackgroundItem classes.
Defines class BeamAngleItems.
Defines class BeamWavelengthItem.
Defines class DistributionItemCatalog.
Defines class FormFactorItemCatalog.
Defines class InstrumentItem and all its children.
Defines class InterferenceItemCatalog.
Defines InterferenceItems's classes.
Defines class ItemWithParticlesCatalog.
Defines class JobItem.
Defines class Lattice2DItemCatalog.
Defines class LayerItem.
Defines class MaterialItem.
Defines class MesoCrystalItem.
Defines class MultiLayerItem.
Defines classes for ParameterTreeItems.
Defines namespace GUI::Model::ParameterTreeUtils.
Defines class ParticleCompositionItem.
Defines class ParticleCoreShellItem.
Defines class ParticleItem.
Defines class ParticleLayoutItem.
Defines ProfileItemCatalog classes.
Defines class RectangularDetectorItem.
Defines family of ResolutionFunctionItem.
Defines class RotationItemCatalog.
Defines class SphericalDetectorItem.
QString unitAsString(const Unit &unit)
Returns the string for the given unit.
Definition: Unit.cpp:58
Unit
Defines units, mainly to be able to convert between units.
Definition: Unit.h:26
@ degree
The BeamDistributionItem handles wavelength, inclination and azimuthal parameter distribution for Bea...
DistributionItem * distribution() const
SelectionDescriptor< ResolutionFunctionItem * > resolutionFunctionSelection() const
static Type type(const DistributionItem *item)
Returns the enum type of the given item.
static UiInfo uiInfo(Type t)
UiInfo on the given type.
Describes properties of a double value which are necessary to allow GUI representation,...
variant< QString, Unit > unit
Unit of the value (internal unit only!)
QString label
A label text (short, no trailing colon)
function< double()> get
function to get the current value
Abstract base class for instrument-specific item classes.
bool withPolarizerAnalyzer() const
SelectionDescriptor< Lattice2DItem * > latticeType() const
static Type type(const InterferenceItem *item)
Returns the enum type of the given item.
static UiInfo uiInfo(Type t)
UiInfo on the given type.
DoubleDescriptor abundance() const
SelectionDescriptor< RotationItem * > rotation()
Returns selection descriptor for rotation methods.
VectorDescriptor positionVector() const
MultiLayerItem * sampleItem()
Definition: JobItem.cpp:222
InstrumentItem * instrumentItem() const
Definition: JobItem.cpp:233
ParameterContainerItem * parameterContainerItem()
Definition: JobItem.cpp:271
bool isSpecularJob() const
Definition: JobItem.cpp:394
const QVector< MaterialItem * > & materialItems() const
MaterialItems & materialItems()
QVector< LayerItem * > layers() const
DoubleDescriptor crossCorrLength() const
VectorDescriptor externalFieldVector() const
The ParameterContainerItem is a top item to hold all ParameterItem, represents an entry point to para...
void setBackupValue(const QString &link, double d)
The ParameterItem class represent a tuning value in a parameter tuning tree.
ParameterTreeItems is a collection of items necessary to form a tuning tree for real time widget.
void addLattice(ParameterLabelItem *parentLabel, const Interference2DAbstractLatticeItem *itf)
ParameterLabelItem * addParticle(ParameterLabelItem *parentLabel, ItemWithParticles *p, bool enableAbundance, bool enablePosition=true)
Returns the top label which was created for the particle.
void addPolarization(ParameterLabelItem *instrumentLabel, const InstrumentItem *instrument)
void addMaterials()
add the job's materials
void addBackground(ParameterLabelItem *instrumentLabel, BackgroundItem *backgroundItem)
void addBeamDistribution(ParameterLabelItem *parentLabel, BeamDistributionItem *distributionItem, const QString &label, bool withMean=true)
void addDetector(ParameterLabelItem *parentLabel, DetectorItem *detector)
ParameterTreeBuilder(JobItem *jobItem, bool recreateBackupValues)
void addParameterItem(ParameterLabelItem *parent, const DoubleDescriptor &d, const QString &label=QString())
void addSample()
add the job's sample
void addRotation(ParameterLabelItem *parentLabel, ItemWithParticles *p)
ParameterContainerItem * parameterContainer()
void addInterference(ParameterLabelItem *layoutLabel, const ParticleLayoutItem *layout)
SelectionDescriptor< InterferenceItem * > interference() const
static Type type(const CatalogedType *item)
Returns the enum type of the given item.
Describes properties of a 3D vector, consisting of three double values.
DoubleDescriptor y
DoubleDescriptor x
QString label
A label text (short, no trailing colon)
DoubleDescriptor z
QString const & name(EShape k)
Definition: particles.cpp:20
QString labelWithUnit(const QString &label, std::variant< QString, Unit > unit)
Create a label with an optional unit in brackets.