BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
RealDataItem.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/coregui/Models/RealDataItem.cpp
6 //! @brief Implements class RealDataItem
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 "Device/Data/DataUtils.h"
33 #include <QtCore/QXmlStreamReader>
34 #include <QtCore/QXmlStreamWriter>
35 
36 const QString RealDataItem::P_INSTRUMENT_ID = "Instrument Id";
37 const QString RealDataItem::P_INSTRUMENT_NAME = "Instrument";
38 const QString RealDataItem::T_INTENSITY_DATA = "Intensity data";
39 const QString RealDataItem::T_NATIVE_DATA = "Native user data axis";
40 const QString RealDataItem::P_NATIVE_DATA_UNITS = "Native user data units";
41 
43 {
44  setItemName("undefined");
45 
46  // Registering this tag even without actual data item to avoid troubles in copying RealDataItem
48  QStringList() << "IntensityData"
49  << "SpecularData");
51 
52  addProperty(P_INSTRUMENT_ID, QString());
53  addProperty(P_INSTRUMENT_NAME, QString()); // #migration This is never used - remove after
54  // checking whether this breaks loading old files
55 
57  QStringList() << "IntensityData"
58  << "SpecularData");
59  addProperty(P_NATIVE_DATA_UNITS, "nbins")->setVisible(false);
60 
61  mapper()->setOnPropertyChange([this](const QString& name) {
62  if (name == P_NAME)
64  });
65 
67  if (dynamic_cast<DataItem*>(item))
69  });
70 
71  mapper()->setOnChildPropertyChange([this](SessionItem* item, const QString& name) {
72  auto data_item = dynamic_cast<DataItem*>(item);
73  if (!data_item || !linkedInstrument() || name != DataItem::P_AXES_UNITS)
74  return;
75 
76  mapper()->setActive(false);
77  data_item->updateAxesUnits(linkedInstrument());
78  mapper()->setActive(true);
79  });
80 }
81 
82 QString RealDataItem::name() const
83 {
84  return itemName();
85 }
86 
87 void RealDataItem::setName(const QString& name)
88 {
90 }
91 
93 {
94  return dynamic_cast<IntensityDataItem*>(dataItem());
95 }
96 
98 {
99  return dynamic_cast<const IntensityDataItem*>(dataItem());
100 }
101 
103 {
104  return dynamic_cast<SpecularDataItem*>(dataItem());
105 }
106 
108 {
109  return dynamic_cast<const SpecularDataItem*>(dataItem());
110 }
111 
113 {
114  return const_cast<DataItem*>(static_cast<const RealDataItem*>(this)->dataItem());
115 }
116 
118 {
119  return dynamic_cast<const DataItem*>(getItem(T_INTENSITY_DATA));
120 }
121 
123 {
124  return const_cast<DataItem*>(static_cast<const RealDataItem*>(this)->nativeData());
125 }
126 
128 {
129  return dynamic_cast<const DataItem*>(getItem(T_NATIVE_DATA));
130 }
131 
133 {
134  const size_t rank = isSpecularData() ? 1 : 2;
136 }
137 
139 {
140  return getItemValue(P_NATIVE_DATA_UNITS).toString();
141 }
142 
143 void RealDataItem::setNativeDataUnits(const QString& units)
144 {
146 }
147 
149 {
150  ASSERT(isSpecularData()); // not implemented for intensityDataItem
151 
152  if (nativeData() != nullptr)
153  nativeData()->setOutputData(nullptr);
154 }
155 
157 {
158  return (nativeData() != nullptr) && (nativeData()->getOutputData() != nullptr);
159 }
160 
162 {
163  return hasNativeData() ? nativeData()->getOutputData() : nullptr;
164 }
165 
166 //! takes ownership of data
167 
169 {
170  nativeData()->setOutputData(data); // takes ownership of odata
171 }
172 
173 //! Creates data item if not existing so far. Checks for rank compatibility if already existing. No
174 //! further initialization like clearing the data etc.
175 
176 void RealDataItem::initDataItem(size_t rank, const QString& tag)
177 {
178  ASSERT(rank <= 2 && rank > 0);
179 
180  auto data_item = getItem(tag);
181  if (data_item != nullptr) {
182  const bool rankMismatch = (rank == 1 && !data_item->is<SpecularDataItem>())
183  || (rank == 2 && !data_item->is<IntensityDataItem>());
184 
185  if (rankMismatch)
186  throw GUIHelpers::Error("Error in RealDataItem::initDataItem: trying to set data "
187  "incompatible with underlying data item");
188  } else {
189  if (rank == 1)
190  model()->insertItem<SpecularDataItem>(this, 0, tag);
191  else
192  model()->insertItem<IntensityDataItem>(this, 0, tag);
193 
194  ASSERT(getItem(tag)
195  && "Assertion failed in RealDataItem::initDataItem: inserting data item failed.");
196  }
197 }
198 
199 //! Sets OutputData to underlying item. Creates it if not existing.
200 
202 {
203  ASSERT(data && "Assertion failed in RealDataItem::setOutputData: passed data is nullptr");
204 
206 
207  dataItem()->setOutputData(data);
208 }
209 
210 //! Sets imported data to underlying item. Creates it if not existing.
211 //! This is used for 1-D import (2-D only using setOutputData). BUT: This last
212 //! statement seems wrong - in the unit tests it is used for 2D import
213 
215 {
216  if (!data)
217  return;
218 
219  const size_t data_rank = data.dataRank();
220  initDataItem(data_rank, T_INTENSITY_DATA);
221  initDataItem(data_rank, T_NATIVE_DATA);
222 
223  QString units_name = data.unitsLabel();
224  auto output_data = data.intensityData();
225 
226  dataItem()->reset(std::move(data));
227  setNativeDataUnits(units_name);
228  item<DataItem>(T_NATIVE_DATA)->setOutputData(output_data.release());
229 }
230 
232 {
233  const size_t rank = 1;
235 }
236 
238 {
239  const size_t rank = 2;
241 }
242 
244 {
245  return nativeDataUnits() != "nbins";
246 }
247 
249 {
250  return getItemValue(P_INSTRUMENT_ID).toString();
251 }
252 
253 void RealDataItem::setInstrumentId(const QString& id)
254 {
256 }
257 
259 {
260  setItemValue(P_INSTRUMENT_ID, QString());
261 }
262 
264 {
265  if (instrumentId().isEmpty()) // not linked or still in initialization state
266  return nullptr;
267 
268  // If this item is contained in a job item, then the instrument has to be taken from the job
269  // item. Otherwise it has to be taken from the instrumentModel
270  JobItem* parentJob = dynamic_cast<JobItem*>(SessionItem::parent());
271  if (parentJob != nullptr) {
272  if (instrumentId() != parentJob->instrumentItem()->id())
273  return nullptr; // still not completely initialized
274 
275  return parentJob->instrumentItem();
276  }
277 
279  : nullptr;
280 }
281 
282 std::vector<int> RealDataItem::shape() const
283 {
284  auto data_item = dataItem();
285  if (!data_item) {
286  ASSERT(data_item);
287  return {};
288  }
289  return data_item->shape();
290 }
291 
293 {
294  return intensityDataItem() != nullptr;
295 }
296 
298 {
299  return specularDataItem() != nullptr;
300 }
301 
303 {
304  return (dataLoader() != nullptr) ? dataLoader()->numErrors() > 0 : false;
305 }
306 
308 {
309  if (auto intensity_data = intensityDataItem())
310  return intensity_data->maskContainerItem();
311  return nullptr;
312 }
313 
315 {
317 }
318 
320 {
321  return m_nativeFileName;
322 }
323 
325 {
326  QByteArray a;
327  QDataStream s(&a, QIODevice::WriteOnly);
328  s.setVersion(QDataStream::Qt_5_12);
329 
330  s << (quint8)1; // version
331  s << m_nativeFileName;
332 
333  if (m_dataLoader) {
334  s << m_dataLoader->persistentClassName();
335  s << *m_dataLoader;
336  } else
337  s << QString(); // empty loader class name => no loader present
338 
339  return a;
340 }
341 
342 void RealDataItem::deserializeBinaryData(const QByteArray& data)
343 {
344  m_nativeFileName.clear();
345  m_importSettings.clear();
346  m_dataLoader.release();
347 
348  QDataStream s(data);
349  s.setVersion(QDataStream::Qt_5_12);
350 
351  quint8 version;
352  s >> version;
353 
354  if (version == 1) {
355  s >> m_nativeFileName;
356  QString persistentLoaderClassName;
357  s >> persistentLoaderClassName;
358  if (!persistentLoaderClassName.isEmpty()) {
360  DataLoaders1D::instance().createFromPersistentName(persistentLoaderClassName));
361  // #baUserDefLoaders ++ implement userdefined loaders (may require new version!)
362  if (!m_dataLoader)
364  s >> *m_dataLoader;
365  m_dataLoader->setRealDataItem(this);
366  }
367  } else
369 
370  if (s.status() != QDataStream::Ok)
372 }
373 
375 {
376  m_dataLoader.reset(loader);
377  if (m_dataLoader)
380 }
381 
383 {
384  return m_dataLoader.get();
385 }
386 
388 {
389  if (!isIntensityData()) // rotation only for 2D items possible
390  return false;
391 
392  const bool hasLinkToInstrument = !instrumentId().isEmpty();
393  if (hasLinkToInstrument)
394  return true;
395 
396  if (intensityDataItem()->hasMasks())
397  return true;
398 
399  if (intensityDataItem()->hasProjections())
400  return true;
401 
402  return false;
403 }
404 
406 {
407  if (!isIntensityData()) // rotation only for 2D items possible
408  return;
409 
410  // -- first break instrument link, clear masks and projections
412 
413  if (auto maskContainer = intensityDataItem()->maskContainerItem())
414  maskContainer->model()->removeRows(0, maskContainer->numberOfChildren(),
415  maskContainer->index());
416 
417  if (auto projectionsContainer = intensityDataItem()->projectionContainerItem())
418  projectionsContainer->model()->removeRows(0, projectionsContainer->numberOfChildren(),
419  projectionsContainer->index());
420 
421  // -- now rotate data
422  const auto input = intensityDataItem()->getOutputData();
425 }
426 
427 //! Updates the name of file to store intensity data.
428 
430 {
431  if (DataItem* item = dataItem())
432  item->setFileName(ItemFileNameUtils::realDataFileName(*this));
433  if (DataItem* item = nativeData())
434  item->setFileName(ItemFileNameUtils::nativeDataFileName(*this));
435 }
436 
438 {
439  return dynamic_cast<RealDataModel*>(model());
440 }
441 
443 {
444  return realDataModel() != nullptr ? realDataModel()->instrumentModel() : nullptr;
445 }
446 
448 {
449  DataItem* data_item = dataItem();
450  if (!data_item)
451  return;
452 
453  if (instrument) {
454  JobItemUtils::setIntensityItemAxesUnits(data_item, instrument);
455  return;
456  }
457 
458  // unlinking => going back to native data
459  if (isSpecularData()) {
460  if (hasNativeData()) {
461  std::unique_ptr<OutputData<double>> native_data(nativeData()->getOutputData()->clone());
462  const QString units_label = nativeDataUnits();
463  data_item->reset(ImportDataInfo(std::move(native_data), units_label));
464  } else {
465  specularDataItem()->setOutputData(nullptr);
466  }
467  } else {
468  auto native_data_item = nativeData();
469  auto data_source = native_data_item ? native_data_item : data_item;
470 
471  std::unique_ptr<OutputData<double>> native_data(data_source->getOutputData()->clone());
472  const QString units_label = nativeDataUnits();
473  data_item->reset(ImportDataInfo(std::move(native_data), units_label));
474  }
475 }
476 
477 void RealDataItem::updateToInstrument(const QString& id)
478 {
479  updateToInstrument(instrumentModel()->findInstrumentById(id));
480 }
Defines class AbstractDataLoader1D.
#define ASSERT(condition)
Definition: Assert.h:31
Defines class DataLoaders1D.
Defines namespace DataUtils.
Defines class DeserializationException.
Defines class GUIHelpers functions.
Defines ImportDataInfo helper struct.
Defines InstrumentItems classes.
Defines class InstrumentModel.
Defines class IntensityDataItem.
Defines auxiliary functions in ItemFileNameUtils namespace.
Defines class JobItemUtils.
Defines class JobItem.
Defines MaskItems classes.
Defines items related to projections over color map.
Defines class RealDataItem.
Defines class RealDataModel.
Defines class SessionModel.
Defines class SpecularDataItem.
Base class for all data loaders (classes which can import real data)
void contentsProcessed()
Emitted whenever contents have been processed.
virtual int numErrors() const
Number of errors found while processing the content.
Provides common functionality for IntensityDataItem and SpecularDataItem.
Definition: DataItem.h:29
OutputData< double > * getOutputData()
Definition: DataItem.h:36
virtual void setOutputData(OutputData< double > *data)=0
The given pointer becomes owned by this class!!
Definition: DataItem.cpp:24
static const QString P_AXES_UNITS
Definition: DataItem.h:34
virtual void reset(ImportDataInfo data)=0
Resets data to the state defined by user (imported) data.
static DataLoaders1D & instance()
The one and only instance.
static DeserializationException streamError()
static DeserializationException tooNew()
Carries information about loaded data.
size_t dataRank() const
Returns number of dimensions.
QString unitsLabel() const
std::unique_ptr< OutputData< double > > intensityData() const &
QString id() const
InstrumentItem * findInstrumentById(const QString &instrumentId) const
void setAxesRangeToData() override
set zoom range of x,y axes to axes of input data
void setOutputData(OutputData< double > *data) override
The given pointer becomes owned by this class!!
InstrumentItem * instrumentItem()
Definition: JobItem.cpp:224
Container holding various masks as children.
Definition: MaskItems.h:24
void setOnChildPropertyChange(std::function< void(SessionItem *, QString)> f, const void *caller=0)
Calls back on child property change, report childItem and property name.
Definition: ModelMapper.cpp:49
void setActive(bool state)
Definition: ModelMapper.h:48
void setOnPropertyChange(std::function< void(QString)> f, const void *caller=0)
Definition: ModelMapper.cpp:35
void setOnChildrenChange(std::function< void(SessionItem *)> f, const void *caller=0)
Calls back when number of children has changed, reports newChild.
Definition: ModelMapper.cpp:68
size_t rank() const
Returns number of dimensions.
Definition: OutputData.h:56
The RealDataItem class represents intensity data imported from file and intended for fitting.
Definition: RealDataItem.h:35
RealDataModel * realDataModel() const
static const QString T_NATIVE_DATA
Definition: RealDataItem.h:47
void initDataItem(size_t data_rank, const QString &tag)
Creates data item if not existing so far.
void removeNativeData()
void initAsSpecularItem()
MaskContainerItem * maskContainerItem()
Returns mask container item.
bool hasImportErrors() const
QString name() const
The name which is presented to the user.
bool holdsDimensionalData() const
void setImportData(ImportDataInfo data)
Sets imported data to underlying item.
virtual QByteArray serializeBinaryData() const override
QString nativeDataUnits() const
void setInstrumentId(const QString &id)
void clearInstrumentId()
virtual void deserializeBinaryData(const QByteArray &data) override
QByteArray m_importSettings
Definition: RealDataItem.h:127
static const QString P_INSTRUMENT_ID
Definition: RealDataItem.h:42
void initNativeData()
const OutputData< double > * nativeOutputData() const
bool isIntensityData() const
std::vector< int > shape() const
Returns the shape of underlying data item.
InstrumentModel * instrumentModel() const
std::unique_ptr< AbstractDataLoader > m_dataLoader
Definition: RealDataItem.h:130
bool isSpecularData() const
AbstractDataLoader * dataLoader() const
void updateToInstrument(const InstrumentItem *instrument)
QString instrumentId() const
QString nativeFileName() const
void setDataLoader(AbstractDataLoader *loader)
Takes ownership of loader.
bool hasNativeData() const
static const QString P_INSTRUMENT_NAME
Definition: RealDataItem.h:46
static const QString T_INTENSITY_DATA
Definition: RealDataItem.h:45
InstrumentItem * linkedInstrument() const
void setNativeOutputData(OutputData< double > *data)
takes ownership of data
void setName(const QString &name)
void setNativeFileName(const QString &filename)
The name from where the native data was originally imported.
QString m_nativeFileName
Definition: RealDataItem.h:128
IntensityDataItem * intensityDataItem()
void setNativeDataUnits(const QString &units)
DataItem * nativeData()
SpecularDataItem * specularDataItem()
void initAsIntensityItem()
bool rotationAffectsSetup() const
Returns true, if rotation will affect linked instrument or mask presence.
DataItem * dataItem()
void importContentsProcessed()
void updateNonXMLDataFileNames()
Updates the name of file to store intensity data.
void setOutputData(OutputData< double > *data)
Sets OutputData to underlying item. Creates it if not existing.
static const QString P_NATIVE_DATA_UNITS
Definition: RealDataItem.h:48
The RealDataModel class is a model to store all imported RealDataItem's.
Definition: RealDataModel.h:26
InstrumentModel * instrumentModel() const
QString itemName() const
Get item name, return display name if no name is set.
void setItemName(const QString &name)
Set item name, add property if necessary.
SessionItem * addProperty(const QString &name, const QVariant &variant)
Add new property item and register new tag.
bool registerTag(const QString &name, int min=0, int max=-1, QStringList modelTypes={})
Add new tag to this item with given name, min, max and types.
void setVisible(bool enabled)
Flags accessors.
bool setValue(QVariant value)
Set value, ensure that variant types match.
static const QString P_NAME
Definition: SessionItem.h:37
QVariant getItemValue(const QString &tag) const
Directly access value of item under given tag.
ModelMapper * mapper()
Returns the current model mapper of this item. Creates new one if necessary.
SessionItem * parent() const
Returns parent of this item.
Definition: SessionItem.cpp:73
void setDefaultTag(const QString &tag)
Set default tag.
SessionModel * model() const
Returns model of this item.
Definition: SessionItem.cpp:66
T * item(const QString &tag) const
Definition: SessionItem.h:151
void setItemValue(const QString &tag, const QVariant &variant)
Directly set value of item under given tag.
SessionItem * getItem(const QString &tag="", int row=0) const
Returns item in given row of given tag.
T * insertItem(SessionItem *parent=nullptr, int row=-1, QString tag="")
Definition: SessionModel.h:125
void setOutputData(OutputData< double > *data) override
The given pointer becomes owned by this class!!
std::unique_ptr< OutputData< double > > createRearrangedDataSet(const OutputData< double > &data, int n)
Returns new object with input data rotated by n*90 deg counterclockwise (n > 0) or clockwise (n < 0) ...
Definition: DataUtils.cpp:82
std::string filename(const std::string &path)
Returns path without directory part ("Foo/Bar/Doz.int.gz" -> "Doz.int.gz")
QString nativeDataFileName(const RealDataItem &realDataItem)
QString realDataFileName(const RealDataItem &realDataItem)
Constructs the name of the intensity file belonging to real data item.
void setIntensityItemAxesUnits(DataItem *intensityItem, const InstrumentItem *instrumentItem)
Sets axes units suitable for given instrument.
QString const & name(EShape k)
Definition: particles.cpp:21