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"
16
17#include <boost/algorithm/string.hpp>
18#include <boost/algorithm/string/split.hpp>
19
20namespace {
28template <typename T> T convert(const std::string &str) {
29 std::istringstream iss(str);
30 T obj;
31 iss >> std::ws >> obj >> std::ws;
32 if (!iss.eof()) {
33 throw std::invalid_argument("Wrong type destination. Cannot convert " + str);
34 }
35 return obj;
36}
37} // namespace
38
39namespace Mantid::MDAlgorithms {
40
41using namespace API;
42using namespace DataObjects;
43using namespace Geometry;
44using namespace Kernel;
45
46// Register the algorithm into the AlgorithmFactory
47DECLARE_ALGORITHM(ImportMDEventWorkspace)
48
49
55const std::string ImportMDEventWorkspace::DimensionBlockFlag() { return "DIMENSIONS"; }
56
63const std::string ImportMDEventWorkspace::MDEventBlockFlag() { return "MDEVENTS"; }
64
71const std::string ImportMDEventWorkspace::CommentLineStartFlag() { return "#"; }
72
73//----------------------------------------------------------------------------------------------
75const std::string ImportMDEventWorkspace::name() const { return "ImportMDEventWorkspace"; }
76
78int ImportMDEventWorkspace::version() const { return 1; }
79
81const std::string ImportMDEventWorkspace::category() const { return "MDAlgorithms\\DataHandling"; }
82
83//----------------------------------------------------------------------------------------------
84
85//----------------------------------------------------------------------------------------------
89 std::vector<std::string> fileExtensions{".txt"};
90 declareProperty(std::make_unique<API::FileProperty>("Filename", "", API::FileProperty::Load, fileExtensions),
91 "File of type txt");
92 declareProperty(std::make_unique<WorkspaceProperty<IMDEventWorkspace>>("OutputWorkspace", "", Direction::Output),
93 "An output workspace.");
94}
95
101template <typename MDE, size_t nd>
105 auto mdEventEntriesIterator = m_posMDEventStart;
106 std::vector<Mantid::coord_t> centers(nd);
107 for (size_t i = 0; i < m_nDataObjects; ++i) {
108 auto signal = convert<float>(*(++mdEventEntriesIterator));
109 auto error = convert<float>(*(++mdEventEntriesIterator));
110 uint16_t run_no = 0;
111 int32_t detector_no = 0;
113 run_no = convert<uint16_t>(*(++mdEventEntriesIterator));
114 detector_no = convert<int32_t>(*(++mdEventEntriesIterator));
115 }
116 for (size_t j = 0; j < m_nDimensions; ++j) {
117 centers[j] = convert<Mantid::coord_t>(*(++mdEventEntriesIterator));
118 }
119 // Actually add the mdevent.
120 inserter.insertMDEvent(signal, error * error, run_no, 0, detector_no, centers.data());
121 }
122}
123
130bool ImportMDEventWorkspace::fileDoesContain(const std::string &flag) {
131 return m_file_data.end() != std::find(m_file_data.begin(), m_file_data.end(), flag);
132}
133
136 // Does it have the mandatory blocks?
138 std::string message = DimensionBlockFlag() + " missing from file";
139 throw std::invalid_argument(message);
140 }
142 std::string message = MDEventBlockFlag() + " missing from file";
143 throw std::invalid_argument(message);
144 }
145 // Are the mandatory block in the correct order.
146 auto posDimStart = std::find(m_file_data.begin(), m_file_data.end(), DimensionBlockFlag());
147 auto posMDEventStart = std::find(m_file_data.begin(), m_file_data.end(), MDEventBlockFlag());
148 auto posDiffDims = static_cast<int>(std::distance(posDimStart, posMDEventStart));
149 if (posDiffDims < 1) {
150 std::string message = DimensionBlockFlag() + " must be specified in file before " + MDEventBlockFlag();
151 throw std::invalid_argument(message);
152 }
153 // Do we have the expected number of dimension entries.
154 if ((posDiffDims - 1) % 4 != 0) {
155 throw std::invalid_argument("Dimensions in the file should be specified id, name, units, nbins");
156 }
157 const size_t nDimensions = (posDiffDims - 1) / 4;
158 // Are the dimension entries all of the correct type.
159 auto dimEntriesIterator = posDimStart;
160 for (size_t i = 0; i < nDimensions; ++i) {
161 convert<std::string>(*(++dimEntriesIterator));
162 convert<std::string>(*(++dimEntriesIterator));
163 convert<std::string>(*(++dimEntriesIterator));
164 convert<int>(*(++dimEntriesIterator));
165 }
166 // Do we have the expected number of mdevent entries
167 int posDiffMDEvent = static_cast<int>(std::distance(posMDEventStart, m_file_data.end()));
168 const size_t columnsForFullEvents = nDimensions + 4; // signal, error, run_no, detector_no
169 const size_t columnsForLeanEvents = nDimensions + 2; // signal, error
170 if ((posDiffMDEvent - 1) % columnsForFullEvents != 0) {
171 if ((posDiffMDEvent - 1) % columnsForLeanEvents != 0) {
172 std::stringstream stream;
173 stream << "With the dimenionality found to be " << nDimensions << ". Should either have " << columnsForLeanEvents
174 << " or " << columnsForFullEvents << " in each row";
175 throw std::invalid_argument(stream.str());
176 }
177 }
178}
179
180//----------------------------------------------------------------------------------------------
184 std::string filename = getProperty("Filename");
185
186 std::ifstream file;
187 try {
188 file.open(filename.c_str(), std::ios::in);
189 } catch (std::ifstream::failure &e) {
190 g_log.error() << "Cannot open file: " << filename;
191 throw(e);
192 }
193
194 // Extract data from the file, excluding comment lines.
195 std::string line;
196 std::string lastLine;
197 size_t nActualColumns = 0;
198 while (std::getline(file, line)) {
199 boost::algorithm::trim(line);
200 if (std::string::npos == line.find_first_of(CommentLineStartFlag())) {
201 std::stringstream buffer(line);
202 std::copy(std::istream_iterator<std::string>(buffer), std::istream_iterator<std::string>(),
203 std::back_inserter(m_file_data));
204
205 if (lastLine == MDEventBlockFlag()) {
206 std::vector<std::string> strVec;
207 boost::algorithm::split(strVec, line, boost::is_any_of("\t "), boost::token_compress_on);
208 nActualColumns = strVec.size();
209 }
210 }
211 lastLine = line;
212 }
213
214 file.close();
215
216 // Check the file format.
218
219 // Extract some well used posisions
220 m_posDimStart = std::find(m_file_data.begin(), m_file_data.end(), DimensionBlockFlag());
221 m_posMDEventStart = std::find(m_file_data.begin(), m_file_data.end(), MDEventBlockFlag());
222
223 // Calculate the dimensionality
224 auto posDiffDims = static_cast<int>(std::distance(m_posDimStart, m_posMDEventStart));
225 m_nDimensions = (posDiffDims - 1) / 4;
226
227 // Calculate the actual number of columns in the MDEvent data.
228 int posDiffMDEvent = static_cast<int>(std::distance(m_posMDEventStart, m_file_data.end()));
229 const size_t columnsForFullEvents = m_nDimensions + 4; // signal, error, run_no, detector_no
230 m_IsFullDataObjects = (nActualColumns == columnsForFullEvents);
231
232 if (0 == nActualColumns) {
233 m_nDataObjects = 0;
234 g_log.warning() << "The number of actual columns found in the file "
235 "(exlcuding comments) is zero\n";
236 } else {
237 m_nDataObjects = posDiffMDEvent / nActualColumns;
238 }
239
240 // Get the min and max extents in each dimension.
241 std::vector<double> extentMins(m_nDimensions);
242 std::vector<double> extentMaxs(m_nDimensions);
243 auto mdEventEntriesIterator = m_posMDEventStart;
244 for (size_t i = 0; i < m_nDataObjects; ++i) {
245 mdEventEntriesIterator += 2;
247 mdEventEntriesIterator += 2;
248 }
249 for (size_t j = 0; j < m_nDimensions; ++j) {
250 auto coord = convert<double>(*(++mdEventEntriesIterator));
251 extentMins[j] = coord < extentMins[j] ? coord : extentMins[j];
252 extentMaxs[j] = coord > extentMaxs[j] ? coord : extentMaxs[j];
253 }
254 }
255
256 // Create a target output workspace.
259
260 // Extract Dimensions and add to the output workspace.
261 auto dimEntriesIterator = m_posDimStart;
262 auto unitFactory = makeMDUnitFactoryChain();
263 for (size_t i = 0; i < m_nDimensions; ++i) {
264 std::string id = convert<std::string>(*(++dimEntriesIterator));
265 std::string name = convert<std::string>(*(++dimEntriesIterator));
266 std::string units = convert<std::string>(*(++dimEntriesIterator));
267 auto nbins = convert<int>(*(++dimEntriesIterator));
268
269 auto mdUnit = unitFactory->create(units);
271 outWs->addDimension(MDHistoDimension_sptr(new MDHistoDimension(id, name, frame, static_cast<coord_t>(extentMins[i]),
272 static_cast<coord_t>(extentMaxs[i]), nbins)));
273 }
274
276
277 // set output
278 this->setProperty("OutputWorkspace", outWs);
279}
280
281} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double error
Definition: IndexPeaks.cpp:133
#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.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Kernel::Logger & g_log
Definition: Algorithm.h:451
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
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.
Definition: GeneralFrame.h:21
static const std::string GeneralFrameName
Definition: GeneralFrame.h:25
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:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
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 exec() override
Execute the algorithm.
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:665
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