BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SaveProjectionsAssistant.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/coregui/Views/IntensityDataWidgets/SaveProjectionsAssistant.cpp
6 //! @brief Implements class SaveProjectionsAssistant
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 "Core/Export/PyFmt.h"
24 #include <QFileDialog>
25 #include <QTextStream>
26 
27 namespace {
28 const int bin_centers_colwidth = 12;
29 const int bin_values_colwidth = 20;
30 
31 QString to_scientific_str(double value)
32 {
33  auto str = pyfmt::printScientificDouble(value);
34  return QString("%1").arg(QString::fromStdString(str), -bin_values_colwidth);
35 }
36 
37 QString to_double_str(double value)
38 {
39  auto str = pyfmt::printDouble(value);
40  return QString("%1").arg(QString::fromStdString(str), -bin_centers_colwidth);
41 }
42 } // unnamed namespace
43 
46 
47 //! Calls file open dialog and writes projection data as ASCII
48 
49 void SaveProjectionsAssistant::saveProjections(QWidget* parent, IntensityDataItem* intensityItem)
50 {
51  ASSERT(intensityItem);
52 
53  QString defaultName = ProjectUtils::userExportDir() + "/untitled.txt";
54  QString fileName = QFileDialog::getSaveFileName(parent, "Save projections data", defaultName);
55 
56  if (fileName.isEmpty())
57  return;
58 
59  QFile file(fileName);
60  if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
61  throw GUIHelpers::Error("TestProjectUtils::createTestFile() -> Error. "
62  "Can't create file");
63 
64  m_hist2d = std::make_unique<Histogram2D>(*intensityItem->getOutputData());
65 
66  QTextStream out(&file);
67 
68  out << "# Projections along x-axis (horizontal projections) \n";
69  out << projectionsToString("HorizontalLineMask", intensityItem);
70  out << "\n";
71 
72  out << "# Projections along y-axis (vertical projections) \n";
73  out << projectionsToString("VerticalLineMask", intensityItem);
74  out << "\n";
75 
76  file.close();
77 }
78 
79 //! Generates multi-line string with projections data of given type (horizontal, vertical).
80 
81 QString SaveProjectionsAssistant::projectionsToString(const QString& projectionsType,
82  IntensityDataItem* intensityItem)
83 {
84  QString result;
85  QTextStream out(&result);
86 
87  auto projData = projectionsData(projectionsType, intensityItem);
88 
89  if (projData.projections.isEmpty())
90  return result;
91 
92  out << projectionFileHeader(projData);
93 
94  auto bin_centers = projData.bin_centers;
95 
96  for (int i_point = 0; i_point < bin_centers.size(); ++i_point) {
97  out << to_double_str(bin_centers[i_point]) << " ";
98  for (auto& data : projData.projections) {
99  out << to_scientific_str(data.bin_values[i_point]);
100  }
101  out << "\n";
102  }
103  return result;
104 }
105 
106 //! Returns projections data for all projections of given type (horizontal, vertical).
107 
109 SaveProjectionsAssistant::projectionsData(const QString& projectionsType,
110  IntensityDataItem* intensityItem)
111 {
112  ProjectionsData result;
113  projectionsType == "VerticalLineMask" ? result.is_horizontal = false
114  : result.is_horizontal = true;
115 
116  for (auto item : projectionItems(projectionsType, intensityItem)) {
117  std::unique_ptr<Histogram1D> hist;
119 
120  if (item->modelType() == "HorizontalLineMask") {
121  data.axis_value = item->getItemValue(HorizontalLineItem::P_POSY).toDouble();
122  hist.reset(m_hist2d->projectionX(data.axis_value));
123  } else {
124  data.axis_value = item->getItemValue(VerticalLineItem::P_POSX).toDouble();
125  hist.reset(m_hist2d->projectionY(data.axis_value));
126  }
127 
128 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
129  auto values = hist->binValues();
130  auto centers = hist->binCenters();
131  data.bin_values = QVector<double>(values.begin(), values.end());
132  if (result.bin_centers.isEmpty())
133  result.bin_centers = QVector<double>(centers.begin(), centers.end());
134 #else
135  data.bin_values = QVector<double>::fromStdVector(hist->binValues());
136  if (result.bin_centers.isEmpty())
137  result.bin_centers = QVector<double>::fromStdVector(hist->binCenters());
138 #endif
139 
140  result.projections.push_back(data);
141  }
142  return result;
143 }
144 
145 //! Returns vector of ProjectionItems sorted according to axis value.
146 
147 QVector<SessionItem*> SaveProjectionsAssistant::projectionItems(const QString& projectionsType,
148  IntensityDataItem* intensityItem)
149 {
150  auto result = intensityItem->projectionContainerItem()->getChildrenOfType(projectionsType);
151  std::sort(result.begin(), result.end(), [=](SessionItem* item1, SessionItem* item2) {
152  QString propertyName = HorizontalLineItem::P_POSY;
153  if (projectionsType != "HorizontalLineMask")
154  propertyName = VerticalLineItem::P_POSX;
155 
156  return item1->getItemValue(propertyName).toDouble()
157  < item2->getItemValue(propertyName).toDouble();
158  });
159  return result;
160 }
161 
162 //! Returns projections header. For projections along x it will be
163 //! "# x y=6.0194 y=33.5922 y=61.9417"
164 
166 {
167  QString xcol, ycol;
168 
169  projectionsData.is_horizontal ? xcol = "# x" : xcol = "# y";
170  projectionsData.is_horizontal ? ycol = " y=" : ycol = " x=";
171 
172  QString result;
173  result.append(QString("%1").arg(xcol, -bin_centers_colwidth));
174 
175  for (auto& data : projectionsData.projections)
176  result.append(QString("%1%2").arg(ycol).arg(data.axis_value,
177  -(bin_values_colwidth - ycol.size()), 'f', 4));
178  result.append("\n");
179 
180  return result;
181 }
#define ASSERT(condition)
Definition: Assert.h:31
Defines class GUIHelpers functions.
Defines class Histogram1D.
Defines class Histogram2D.
Defines class IntensityDataItem.
Defines MaskItems classes.
Defines ProjectUtils namespace.
Defines items related to projections over color map.
Defines functions in namespace pyfmt.
Defines class SaveProjectionsAssistant.
OutputData< double > * getOutputData()
Definition: DataItem.h:36
static const QString P_POSY
Definition: MaskItems.h:81
ProjectionContainerItem * projectionContainerItem()
QString projectionFileHeader(ProjectionsData &projectionsData)
Returns projections header.
ProjectionsData projectionsData(const QString &projectionsType, IntensityDataItem *intensityItem)
Returns projections data for all projections of given type (horizontal, vertical).
std::unique_ptr< Histogram2D > m_hist2d
QString projectionsToString(const QString &projectionsType, IntensityDataItem *intensityItem)
Generates multi-line string with projections data of given type (horizontal, vertical).
QVector< SessionItem * > projectionItems(const QString &projectionsType, IntensityDataItem *intensityItem)
Returns vector of ProjectionItems sorted according to axis value.
void saveProjections(QWidget *parent, IntensityDataItem *intensityItem)
Calls file open dialog and writes projection data as ASCII.
QVector< SessionItem * > getChildrenOfType(const QString &model_type) const
Returns a vector of all children of the given type.
static const QString P_POSX
Definition: MaskItems.h:73
QVector< double > fromStdVector(const std::vector< double > &data)
Definition: GUIHelpers.cpp:225
QString userExportDir()
Returns directory which user is normally using to export files.
std::string printDouble(double input)
Definition: PyFmt.cpp:41
std::string printScientificDouble(double input)
Definition: PyFmt.cpp:91
double axis_value
value on axis where projection has been made