Mantid
Loading...
Searching...
No Matches
ImportMDEventWorkspace.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
9#include <fstream>
10
15#include "MantidKernel/MDUnit.h"
17
18#include <boost/algorithm/string.hpp>
19#include <boost/algorithm/string/split.hpp>
20
21namespace {
29template <typename T> T convert(const std::string &str) {
30 std::istringstream iss(str);
31 T obj;
32 iss >> std::ws >> obj >> std::ws;
33 if (!iss.eof()) {
34 throw std::invalid_argument("Wrong type destination. Cannot convert " + str);
35 }
36 return obj;
37}
38} // namespace
39
40namespace Mantid::MDAlgorithms {
41
42using namespace API;
43using namespace DataObjects;
44using namespace Geometry;
45using namespace Kernel;
46
47// Register the algorithm into the AlgorithmFactory
48DECLARE_ALGORITHM(ImportMDEventWorkspace)
49
50
56const std::string ImportMDEventWorkspace::DimensionBlockFlag() { return "DIMENSIONS"; }
57
64const std::string ImportMDEventWorkspace::MDEventBlockFlag() { return "MDEVENTS"; }
65
72const std::string ImportMDEventWorkspace::CommentLineStartFlag() { return "#"; }
73
74//----------------------------------------------------------------------------------------------
76const std::string ImportMDEventWorkspace::name() const { return "ImportMDEventWorkspace"; }
77
79int ImportMDEventWorkspace::version() const { return 1; }
80
82const std::string ImportMDEventWorkspace::category() const { return "MDAlgorithms\\DataHandling"; }
83
84//----------------------------------------------------------------------------------------------
85
86//----------------------------------------------------------------------------------------------
90 std::vector<std::string> fileExtensions{".txt"};
91 declareProperty(std::make_unique<API::FileProperty>("Filename", "", API::FileProperty::Load, fileExtensions),
92 "File of type txt");
93 declareProperty(std::make_unique<WorkspaceProperty<IMDEventWorkspace>>("OutputWorkspace", "", Direction::Output),
94 "An output workspace.");
95}
96
102template <typename MDE, size_t nd>
106 auto mdEventEntriesIterator = m_posMDEventStart;
107 std::vector<Mantid::coord_t> centers(nd);
108 for (size_t i = 0; i < m_nDataObjects; ++i) {
109 auto signal = convert<float>(*(++mdEventEntriesIterator));
110 auto error = convert<float>(*(++mdEventEntriesIterator));
111 uint16_t run_no = 0;
112 int32_t detector_no = 0;
114 run_no = convert<uint16_t>(*(++mdEventEntriesIterator));
115 detector_no = convert<int32_t>(*(++mdEventEntriesIterator));
116 }
117 for (size_t j = 0; j < m_nDimensions; ++j) {
118 centers[j] = convert<Mantid::coord_t>(*(++mdEventEntriesIterator));
119 }
120 // Actually add the mdevent.
121 inserter.insertMDEvent(signal, error * error, run_no, 0, detector_no, centers.data());
122 }
123}
124
131bool ImportMDEventWorkspace::fileDoesContain(const std::string &flag) {
132 return m_file_data.end() != std::find(m_file_data.begin(), m_file_data.end(), flag);
133}
134
137 // Does it have the mandatory blocks?
139 std::string message = DimensionBlockFlag() + " missing from file";
140 throw std::invalid_argument(message);
141 }
143 std::string message = MDEventBlockFlag() + " missing from file";
144 throw std::invalid_argument(message);
145 }
146 // Are the mandatory block in the correct order.
147 auto posDimStart = std::find(m_file_data.begin(), m_file_data.end(), DimensionBlockFlag());
148 auto posMDEventStart = std::find(m_file_data.begin(), m_file_data.end(), MDEventBlockFlag());
149 auto posDiffDims = static_cast<int>(std::distance(posDimStart, posMDEventStart));
150 if (posDiffDims < 1) {
151 std::string message = DimensionBlockFlag() + " must be specified in file before " + MDEventBlockFlag();
152 throw std::invalid_argument(message);
153 }
154 // Do we have the expected number of dimension entries.
155 if ((posDiffDims - 1) % 4 != 0) {
156 throw std::invalid_argument("Dimensions in the file should be specified id, name, units, nbins");
157 }
158 const size_t nDimensions = (posDiffDims - 1) / 4;
159 // Are the dimension entries all of the correct type.
160 auto dimEntriesIterator = posDimStart;
161 for (size_t i = 0; i < nDimensions; ++i) {
162 convert<std::string>(*(++dimEntriesIterator));
163 convert<std::string>(*(++dimEntriesIterator));
164 convert<std::string>(*(++dimEntriesIterator));
165 convert<int>(*(++dimEntriesIterator));
166 }
167 // Do we have the expected number of mdevent entries
168 int posDiffMDEvent = static_cast<int>(std::distance(posMDEventStart, m_file_data.end()));
169 const size_t columnsForFullEvents = nDimensions + 4; // signal, error, run_no, detector_no
170 const size_t columnsForLeanEvents = nDimensions + 2; // signal, error
171 if ((posDiffMDEvent - 1) % columnsForFullEvents != 0) {
172 if ((posDiffMDEvent - 1) % columnsForLeanEvents != 0) {
173 std::stringstream stream;
174 stream << "With the dimenionality found to be " << nDimensions << ". Should either have " << columnsForLeanEvents
175 << " or " << columnsForFullEvents << " in each row";
176 throw std::invalid_argument(stream.str());
177 }
178 }
179}
180
181//----------------------------------------------------------------------------------------------
185 std::string filename = getProperty("Filename");
186
187 std::ifstream file;
188 try {
189 file.open(filename.c_str(), std::ios::in);
190 } catch (std::ifstream::failure &e) {
191 g_log.error() << "Cannot open file: " << filename;
192 throw(e);
193 }
194
195 // Extract data from the file, excluding comment lines.
196 std::string line;
197 std::string lastLine;
198 size_t nActualColumns = 0;
199 while (std::getline(file, line)) {
200 boost::algorithm::trim(line);
201 if (std::string::npos == line.find_first_of(CommentLineStartFlag())) {
202 std::stringstream buffer(line);
203 std::copy(std::istream_iterator<std::string>(buffer), std::istream_iterator<std::string>(),
204 std::back_inserter(m_file_data));
205
206 if (lastLine == MDEventBlockFlag()) {
207 std::vector<std::string> strVec;
208 boost::algorithm::split(strVec, line, boost::is_any_of("\t "), boost::token_compress_on);
209 nActualColumns = strVec.size();
210 }
211 }
212 lastLine = line;
213 }
214
215 file.close();
216
217 // Check the file format.
219
220 // Extract some well used posisions
221 m_posDimStart = std::find(m_file_data.begin(), m_file_data.end(), DimensionBlockFlag());
222 m_posMDEventStart = std::find(m_file_data.begin(), m_file_data.end(), MDEventBlockFlag());
223
224 // Calculate the dimensionality
225 auto posDiffDims = static_cast<int>(std::distance(m_posDimStart, m_posMDEventStart));
226 m_nDimensions = (posDiffDims - 1) / 4;
227
228 // Calculate the actual number of columns in the MDEvent data.
229 int posDiffMDEvent = static_cast<int>(std::distance(m_posMDEventStart, m_file_data.end()));
230 const size_t columnsForFullEvents = m_nDimensions + 4; // signal, error, run_no, detector_no
231 m_IsFullDataObjects = (nActualColumns == columnsForFullEvents);
232
233 if (0 == nActualColumns) {
234 m_nDataObjects = 0;
235 g_log.warning() << "The number of actual columns found in the file "
236 "(exlcuding comments) is zero\n";
237 } else {
238 m_nDataObjects = posDiffMDEvent / nActualColumns;
239 }
240
241 // Get the min and max extents in each dimension.
242 std::vector<double> extentMins(m_nDimensions);
243 std::vector<double> extentMaxs(m_nDimensions);
244 auto mdEventEntriesIterator = m_posMDEventStart;
245 for (size_t i = 0; i < m_nDataObjects; ++i) {
246 mdEventEntriesIterator += 2;
248 mdEventEntriesIterator += 2;
249 }
250 for (size_t j = 0; j < m_nDimensions; ++j) {
251 auto coord = convert<double>(*(++mdEventEntriesIterator));
252 extentMins[j] = coord < extentMins[j] ? coord : extentMins[j];
253 extentMaxs[j] = coord > extentMaxs[j] ? coord : extentMaxs[j];
254 }
255 }
256
257 // Create a target output workspace.
260
261 // Extract Dimensions and add to the output workspace.
262 auto dimEntriesIterator = m_posDimStart;
263 auto unitFactory = makeMDUnitFactoryChain();
264 for (size_t i = 0; i < m_nDimensions; ++i) {
265 std::string id = convert<std::string>(*(++dimEntriesIterator));
266 std::string name = convert<std::string>(*(++dimEntriesIterator));
267 std::string units = convert<std::string>(*(++dimEntriesIterator));
268 auto nbins = convert<int>(*(++dimEntriesIterator));
269
270 auto mdUnit = unitFactory->create(units);
272 outWs->addDimension(MDHistoDimension_sptr(new MDHistoDimension(id, name, frame, static_cast<coord_t>(extentMins[i]),
273 static_cast<coord_t>(extentMaxs[i]), nbins)));
274 }
275
277
278 // set output
279 this->setProperty("OutputWorkspace", outWs);
280}
281
282} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double error
#define CALL_MDEVENT_FUNCTION(funcname, workspace)
Macro that makes it possible to call a templated method for a MDEventWorkspace using a IMDEventWorksp...
double obj
the value of the quadratic function
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
static API::IMDEventWorkspace_sptr CreateMDWorkspace(size_t nd, const std::string &eventType="MDLeanEvent", const Mantid::API::MDNormalization &preferredNormalization=Mantid::API::MDNormalization::VolumeNormalization, const Mantid::API::MDNormalization &preferredNormalizationHisto=Mantid::API::MDNormalization::VolumeNormalization)
Create a MDEventWorkspace of the given type.
MDEventInserter : Helper class that provides a generic interface for adding events to an MDWorkspace ...
void insertMDEvent(float signal, float errorSQ, uint16_t expInfoIndex, uint16_t goniometerIndex, int32_t detectno, Mantid::coord_t *coords)
Creates an mdevent and adds it to the MDEW.
std::shared_ptr< MDEventWorkspace< MDE, nd > > sptr
Typedef for a shared pointer of this kind of event workspace.
GeneralFrame : Any MDFrame that isn't related to momemtum transfer.
static const std::string GeneralFrameName
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
ImportMDEventWorkspace : Loads a file containing dimensionality and data for an MDEventWorkspace.
const std::string category() const override
Algorithm's category for identification.
const std::string name() const override
Algorithm's name for identification.
void addEventsData(typename DataObjects::MDEventWorkspace< MDE, nd >::sptr ws)
call back to add event data
DataCollectionType::iterator m_posDimStart
Iterator for the dimensionality start position.
static const std::string MDEventBlockFlag()
Flag used to indicate the mdevent block in the file.
void init() override
Initialize the algorithm's properties.
int version() const override
Algorithm's version for identification.
DataCollectionType::iterator m_posMDEventStart
Iterator for the mdevent data start position.
void quickFileCheck()
Quick check of the structure, so we can abort if passed junk.
static const std::string DimensionBlockFlag()
Flag used to indicate the dimension block in the file.
bool m_IsFullDataObjects
Flag indicating whether full md events for lean events will be generated.
bool fileDoesContain(const std::string &flag)
Check that the a flag exists in the file.
static const std::string CommentLineStartFlag()
Flag used to indicate a comment line.
DataCollectionType m_file_data
All read-in data.
size_t m_nDimensions
Actual number of dimensions specified.
size_t m_nDataObjects
Actual number of md events provided.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< MDHistoDimension > MDHistoDimension_sptr
Shared pointer to a MDHistoDimension.
int convert(const std::string &A, T &out)
Convert a string into a number.
Definition Strings.cpp:696
MDUnitFactory_uptr MANTID_KERNEL_DLL makeMDUnitFactoryChain()
Convience method. Pre-constructed builder chain.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
Definition MDTypes.h:27
STL namespace.
@ Output
An output workspace.
Definition Property.h:54