Mantid
Loading...
Searching...
No Matches
DetermineChunking.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#include "LoadRaw/isisraw.h"
11#include "MantidAPI/TableRow.h"
17#include "MantidNexus/NexusFile.h"
18
19#include <exception>
20#include <filesystem>
21#include <set>
22#include <vector>
23
24using namespace Mantid::Kernel;
25using namespace Mantid::API;
26using std::map;
27using std::size_t;
28using std::string;
29using std::vector;
30
31namespace Mantid::DataHandling {
33const std::vector<std::string> EVENT_NEXUS_EXT = {"_event.nxs", ".nxs", ".nxs.h5"};
35const std::vector<std::string> HISTO_NEXUS_EXT = {"_histo.nxs"};
37const std::vector<std::string> RAW_EXT = {".raw"};
38
39// Register the algorithm into the AlgorithmFactory
41
42namespace {
43constexpr double BYTES_TO_GiB = 1. / 1024. / 1024. / 1024.;
44}
45
46//----------------------------------------------------------------------------------------------
48const std::string DetermineChunking::name() const { return "DetermineChunking"; }
49
51int DetermineChunking::version() const { return 1; }
52
54const std::string DetermineChunking::category() const { return "Workflow\\DataHandling"; }
55
56//----------------------------------------------------------------------------------------------
59 // runfile to read in
60 std::set<std::string> exts_set;
61 exts_set.insert(EVENT_NEXUS_EXT.cbegin(), EVENT_NEXUS_EXT.cend());
62 exts_set.insert(HISTO_NEXUS_EXT.cbegin(), HISTO_NEXUS_EXT.cend());
63 exts_set.insert(RAW_EXT.cbegin(), RAW_EXT.end());
64 std::vector<std::string> exts(exts_set.begin(), exts_set.end());
65 this->declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, exts),
66 "The name of the event nexus, raw, or histo nexus file to "
67 "read, including its full or relative path. The Event NeXus file name is "
68 "typically of the form INST_####_event.nxs (N.B. case sensitive if "
69 "running on Linux).");
70
71 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
72 mustBePositive->setLower(0.0);
73 declareProperty("MaxChunkSize", EMPTY_DBL(), mustBePositive,
74 "Get chunking strategy for chunks with this number of "
75 "Gbytes. File will not be loaded if this option is set.");
76
77 declareProperty(std::make_unique<WorkspaceProperty<API::ITableWorkspace>>("OutputWorkspace", "", Direction::Output),
78 "An output workspace.");
79}
80
81//----------------------------------------------------------------------------------------------
84 // get the chunking parameter and fix it up
85 double maxChunk = this->getProperty("MaxChunkSize");
86 if (maxChunk == 0) {
87 g_log.debug() << "Converting maxChunk=0 to maxChunk=EMPTY_DBL\n";
88 maxChunk = EMPTY_DBL();
89 }
90
91 // get the filename and determine the file type
92 int m_numberOfSpectra = 0;
93 string filename = this->getPropertyValue("Filename");
94 FileType fileType = getFileType(filename);
95
96 // setup the chunking table with the correct column headings
97 Mantid::API::ITableWorkspace_sptr strategy = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
98 if (fileType == EVENT_NEXUS_FILE) {
99 strategy->addColumn("int", "ChunkNumber");
100 strategy->addColumn("int", "TotalChunks");
101 } else if (fileType == RAW_FILE || fileType == HISTO_NEXUS_FILE) {
102 strategy->addColumn("int", "SpectrumMin");
103 strategy->addColumn("int", "SpectrumMax");
104 }
105 this->setProperty("OutputWorkspace", strategy);
106
107 if (maxChunk == 0 || isEmpty(maxChunk)) {
108 return;
109 }
110
111 std::filesystem::path fileinfo(filename);
112 const double fileSizeGiB = static_cast<double>(std::filesystem::file_size(fileinfo)) * BYTES_TO_GiB;
113
114 // don't bother opening the file if its size is "small"
115 if (6. * fileSizeGiB < maxChunk)
116 return;
117
118 // --------------------- DETERMINE NUMBER OF CHUNKS
119 double wkspSizeGiB = 0;
120 // Event Nexus
121 if (fileType == EVENT_NEXUS_FILE) {
122
123 // top level file information
124 Nexus::File file(filename);
125 std::string m_top_entry_name = setTopEntryName(filename);
126
127 // Start with the base entry
128 file.openGroup(m_top_entry_name, "NXentry");
129
130 // Now we want to go through all the bankN_event entries
131 map<string, string> entries = file.getEntries();
132 map<string, string>::const_iterator it = entries.begin();
133 std::string classType = "NXevent_data";
134 size_t total_events = 0;
135 for (; it != entries.end(); ++it) {
136 const std::string entry_class(it->second);
137 if (entry_class == classType) {
138 if (!isEmpty(maxChunk)) {
139 try {
140 const std::string entry_name(it->first);
141 // Get total number of events for each bank
142 file.openGroup(entry_name, entry_class);
143 file.openData("total_counts");
144 if (file.getInfo().type == NXnumtype::UINT64) {
145 std::vector<uint64_t> bank_events;
146 file.getData(bank_events);
147 total_events += bank_events[0];
148 } else {
149 std::vector<int> bank_events;
150 file.getDataCoerce(bank_events);
151 total_events += bank_events[0];
152 }
153 file.closeData();
154 file.closeGroup();
155 } catch (Nexus::Exception const &) {
156 g_log.error() << "Unable to find total counts to determine "
157 "chunking strategy.\n";
158 }
159 }
160 }
161 }
162
163 // Close up the file
164 file.closeGroup();
165 file.close();
166 // Factor of 2 for compression
167 wkspSizeGiB = static_cast<double>(total_events) * 48.0 * BYTES_TO_GiB;
168 } else if (fileType == RAW_FILE) {
169 // Check the size of the file loaded
170 wkspSizeGiB = fileSizeGiB * 24.0;
171 g_log.notice() << "Wksp size is " << wkspSizeGiB << " GB\n";
172
173 LoadRawHelper helper;
174 FILE *file = helper.openRawFile(filename);
175 ISISRAW iraw;
176 iraw.ioRAW(file, true);
177
178 // Read in the number of spectra in the RAW file
179 m_numberOfSpectra = iraw.t_nsp1;
180 g_log.notice() << "Spectra size is " << m_numberOfSpectra << " spectra\n";
181 fclose(file);
182 }
183 // Histo Nexus
184 else if (fileType == HISTO_NEXUS_FILE) {
185 // Check the size of the file loaded
186 wkspSizeGiB = fileSizeGiB * 144.0;
187 g_log.notice() << "Wksp size is " << wkspSizeGiB << " GB\n";
189 lp.m_signalNo = 1;
190 // Find the entry name we want.
191 std::string entry_name = LoadTOFRawNexus::getEntryName(filename);
192 std::vector<std::string> bankNames;
193 lp.countPixels(filename, entry_name, bankNames);
194 m_numberOfSpectra = static_cast<int>(lp.m_numPixels);
195 g_log.notice() << "Spectra size is " << m_numberOfSpectra << " spectra\n";
196 } else {
197 throw(std::invalid_argument("unsupported file type"));
198 }
199
200 int numChunks = 0;
201 if (maxChunk != 0.0) // protect from divide by zero
202 {
203 numChunks = static_cast<int>(wkspSizeGiB / maxChunk);
204 }
205
206 numChunks++; // So maxChunkSize is not exceeded
207 if (numChunks <= 1 || isEmpty(maxChunk)) {
208 g_log.information() << "Everything can be done in a single chunk returning empty table\n";
209 return;
210 }
211
212 // --------------------- FILL IN THE CHUNKING TABLE
213 for (int i = 1; i <= numChunks; i++) {
214 Mantid::API::TableRow row = strategy->appendRow();
215 if (fileType == EVENT_NEXUS_FILE) {
216 row << i << numChunks;
217 } else if (fileType == RAW_FILE || fileType == HISTO_NEXUS_FILE) {
218 int spectraPerChunk = m_numberOfSpectra / numChunks;
219 int first = (i - 1) * spectraPerChunk + 1;
220 int last = first + spectraPerChunk - 1;
221 if (i == numChunks)
222 last = m_numberOfSpectra;
223 row << first << last;
224 }
225 }
226}
227
229std::string DetermineChunking::setTopEntryName(const std::string &filename) {
230 std::string top_entry_name;
231 using string_map_t = std::map<std::string, std::string>;
232 try {
233 string_map_t::const_iterator it;
234 Nexus::File file = Nexus::File(filename);
235 string_map_t entries = file.getEntries();
236
237 // Choose the first entry as the default
238 top_entry_name = entries.begin()->first;
239
240 for (it = entries.begin(); it != entries.end(); ++it) {
241 if (((it->first == "entry") || (it->first == "raw_data_1")) && (it->second == "NXentry")) {
242 top_entry_name = it->first;
243 break;
244 }
245 }
246 } catch (const std::exception &) {
247 g_log.error() << "Unable to determine name of top level NXentry - assuming "
248 "\"entry\".\n";
249 top_entry_name = "entry";
250 }
251 return top_entry_name;
252}
253
262 // check for histogram nexus
263 if (filenameHasExtension(filename, HISTO_NEXUS_EXT)) {
264 g_log.information() << "Determined \'" << filename << "\' is a histogram nexus file\n";
265 return HISTO_NEXUS_FILE;
266 }
267
268 // check for event nexus - must be last because a valid extension is ".nxs"
269 if (filenameHasExtension(filename, EVENT_NEXUS_EXT)) {
270 g_log.information() << "Determined \'" << filename << "\' is an event nexus file\n";
271 return EVENT_NEXUS_FILE;
272 }
273
274 // check for isis raw files
275 if (filenameHasExtension(filename, RAW_EXT)) {
276 g_log.information() << "Determined \'" << filename << "\' is an ISIS raw file\n";
277 return RAW_FILE;
278 }
279
280 throw std::invalid_argument("Unsupported file type");
281}
282
283bool DetermineChunking::filenameHasExtension(const std::string &filename,
284 const std::vector<std::string> &fileExtensions) {
285 return std::any_of(fileExtensions.cbegin(), fileExtensions.cend(),
286 [&filename](const auto &extension) { return filename.find(extension) != std::string::npos; });
287}
288
289} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
isis raw file.
Definition isisraw.h:267
int t_nsp1
number of spectra in time regime 1
Definition isisraw.h:324
virtual int ioRAW(FILE *file, bool from_file, bool read_data=true)
stuff
Definition isisraw.cpp:401
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:426
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
@ Load
allowed here which will be passed to the algorithm
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
void init() override
Virtual method - must be overridden by concrete algorithm.
int version() const override
function to return a version of the algorithm, must be overridden in all algorithms
void exec() override
Virtual method - must be overridden by concrete algorithm.
const std::string name() const override
function to return a name of the algorithm, must be overridden in all algorithms
FileType getFileType(const std::string &filename)
Determine the file type using the filename.
const std::string category() const override
function to return a category of the algorithm.
std::string setTopEntryName(const std::string &filename)
set the name of the top level NXentry m_top_entry_name
bool filenameHasExtension(const std::string &filename, const std::vector< std::string > &fileExtensions)
Helper class for LoadRaw algorithms.
FILE * openRawFile(const std::string &fileName)
Opens Raw File.
Loads a NeXus file that conforms to the TOFRaw instrument definition format and stores it in a 2D wor...
int m_signalNo
Signal # to load. Default 1.
static std::string getEntryName(const std::string &filename)
void countPixels(const std::string &nexusfilename, const std::string &entry_name, std::vector< std::string > &bankNames)
Goes thoguh a histogram NXS file and counts the number of pixels.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Class that provides for a standard Nexus exception.
static unsigned short constexpr UINT64
ISIS VMS raw file definitions.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
const std::vector< std::string > RAW_EXT
Valid extensions for ISIS raw files.
FileType
DetermineChunking : Workflow algorithm to determine chunking.
@ RAW_FILE
ISIS raw files.
@ HISTO_NEXUS_FILE
Histogram NeXus files.
@ EVENT_NEXUS_FILE
Event NeXus files.
const std::vector< std::string > HISTO_NEXUS_EXT
Valid extensions for histogram nexus files.
const std::vector< std::string > EVENT_NEXUS_EXT
Valid extensions for event nexus files.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Output
An output workspace.
Definition Property.h:55