Mantid
Loading...
Searching...
No Matches
SaveNexusProcessedHelper.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 +
7// NexusFileIO
8// @author Ronald Fowler
9#include <sstream>
10#include <vector>
11
12#ifdef _WIN32
13#include <io.h>
14// Define the MAX_NAME macro for Windows
15// Maximum base file name size on modern windows systems is 260 characters
16#define NAME_MAX 260
17#endif /* _WIN32 */
18
25#include "MantidHistogramData/Histogram.h"
26#include "MantidKernel/Unit.h"
27
28#include <filesystem>
29#include <memory>
30
31namespace Mantid::Nexus {
32using namespace Kernel;
33using namespace API;
34using namespace DataObjects;
35
36using HistogramData::HistogramDx;
37using HistogramData::HistogramE;
38using HistogramData::HistogramX;
39using HistogramData::HistogramY;
40using Mantid::MantidVec; // for `<rebinned output>->readF(size_t index)`
41
42namespace {
44Logger g_log("NexusFileIO");
45} // namespace
46
49 : m_filehandle(), m_nexuscompression(NXcompression::LZW), m_progress(nullptr), m_filename() {}
50
53 : m_filehandle(), m_nexuscompression(NXcompression::LZW), m_progress(prog), m_filename() {}
54
56
57//
58// Write out the data in a worksvn space in Nexus "Processed" format.
59// This *Proposed* standard comprises the fields:
60// <NXentry name="{Name of entry}">
61// <title>
62// {Extended title for entry}
63// </title>
64// <definition
65// URL="http://www.nexusformat.org/instruments/xml/NXprocessed.xml"
66// version="1.0">
67// NXprocessed
68// </definition>
69// <NXsample name="{Name of sample}">?
70// {Any relevant sample information necessary to define the data.}
71// </NXsample>
72// <NXdata name="{Name of processed data}">
73// <values signal="1" type="NX_FLOAT[:,:]" axes="axis1:axis2">{Processed
74// values}</values>
75// <axis1 type="NX_FLOAT[:]">{Values of the first dimension's axis}</axis1>
76// <axis2 type="NX_FLOAT[:]">{Values of the second dimension's axis}</axis2>
77// </NXdata>
78// <NXprocess name="{Name of process}">?
79// {Any relevant information about the steps used to process the data.}
80// </NXprocess>
81// </NXentry>
82
83void NexusFileIO::openNexusWrite(const std::string &fileName, NexusFileIO::optional_size_t entryNumber,
84 const bool append_to_file) {
85 // open named file and entry - file may exist
86 // @throw Exception::FileError if cannot open Nexus file for writing
87 //
89 std::string mantidEntryName;
90 m_filename = fileName;
91 //
92 // If file to write exists, then open as is else see if the extension is xml,
93 // if so open as xml
94 // format otherwise as compressed hdf5
95 //
96 if ((std::filesystem::exists(m_filename) && append_to_file) || m_filehandle)
97 mode = NXaccess::RDWR;
98
99 else {
100 if (fileName.find(".xml") < fileName.size() || fileName.find(".XML") < fileName.size()) {
101 throw Kernel::Exception::FileError("Cannot save XML files", fileName);
102 }
103 mantidEntryName = "mantid_workspace_1";
104 }
105
106 /*Only create the file handle if needed.*/
107 if (!m_filehandle) {
108 // The nexus or HDF5 libraries crash when the filename is greater than 255
109 // on OSX and Ubuntu.
110 std::filesystem::path path(fileName);
111 std::string baseName = path.stem().string();
112 if (baseName.size() > NAME_MAX) {
113 std::string message = "Filename is too long. Unable to open file: ";
114 throw Kernel::Exception::FileError(message, fileName);
115 }
116
117 auto file = new Nexus::File(fileName, mode);
118
119 m_filehandle = std::shared_ptr<Nexus::File>(file);
120 }
121
122 //
123 // for existing files, search for any current mantid_workspace_<n> entries and
124 // set the
125 // new name to be n+1 so that we do not over-write by default. This may need
126 // changing.
127 //
128 if (mode == NXaccess::RDWR) {
129 size_t count = 0;
130 if (entryNumber.has_value()) {
131 // Use the entry number provided.
132 count = entryNumber.value();
133 } else {
134 // Have to figure it our ourselves. Requires opening the exisitng file to
135 // get the information via a search.
137 }
138
139 std::stringstream suffix;
140 suffix << (count + 1);
141 mantidEntryName = "mantid_workspace_" + suffix.str();
142 }
143 //
144 // make and open the new mantid_workspace_<n> group
145 // file remains open until explicit close
146 //
147 const std::string className = "NXentry";
148
149 m_filehandle->makeGroup(mantidEntryName, className);
150 m_filehandle->openGroup(mantidEntryName, className);
151}
152
153void NexusFileIO::closeGroup() { m_filehandle->closeGroup(); }
154
155//-----------------------------------------------------------------------------------------------
157 if (m_filehandle) {
158 m_filehandle.reset();
159 }
160}
161
162//-----------------------------------------------------------------------------------------------
171int NexusFileIO::writeNexusProcessedHeader(const std::string &title, const std::string &wsName) const {
172
173 const std::string className = "Mantid Processed Workspace";
174 std::vector<std::string> attributes, avalues;
175 attributes.reserve(2);
176 avalues.reserve(2);
177 if (!writeNxValue("title", title, attributes, avalues))
178 return (3);
179
180 // name for workspace if this is a multi workspace nexus file
181 if (!wsName.empty()) {
182 if (!writeNxValue("workspace_name", wsName, attributes, avalues))
183 return (3);
184 }
185
186 attributes.emplace_back("URL");
187 avalues.emplace_back("http://www.nexusformat.org/instruments/xml/NXprocessed.xml");
188 attributes.emplace_back("Version");
189 avalues.emplace_back("1.0");
190 // this may not be the "correct" long term path, but it is valid at present
191 if (!writeNxValue("definition", className, attributes, avalues))
192 return (3);
193 avalues.clear();
194 avalues.emplace_back("http://www.isis.rl.ac.uk/xml/IXmantid.xml");
195 avalues.emplace_back("1.0");
196 if (!writeNxValue("definition_local", className, attributes, avalues))
197 return (3);
198 return (0);
199}
200
201//-------------------------------------------------------------------------------------
202// Internal constants and template functions, used by `NexusFileIO::writeNexusProcessedData2D`:
203
204namespace {
205
206const double _DEFAULT_FILL_VALUE(0.0);
207
208// Typedef for vector-accessor member functions with signatures like:
209// `const HistogramData::HistogramY & Mantid::API::MatrixWorkspace::y ( const size_t index )
210// const`
211template <class V, class WS> using _VAccessor = const V &(WS::*)(size_t) const;
212
213// Return the data pointer for a vector:
214// this allows us to work with both `MantidVec` and `FixedLengthVector`.
215template <class V> const double *_dataPointer(const V &v) { return v.rawData().data(); }
216
217template <> const double *_dataPointer<MantidVec>(const MantidVec &v) { return v.data(); }
218
219// Internal-use method:
220// * Create the dataset and write chunks of double-precision data;
221// * Optionally fill the chunks with a specified fill value;
222// * Optionally close the dataset.
223template <class V, class WS>
224void _writeChunkedData(std::shared_ptr<Nexus::File> dest, // Must have open group, but NO open dataset
225 const std::string &name,
226 std::shared_ptr<const WS> src, // Do not pass std::shared_ptr<..> by reference!
227 const std::vector<int> &indices, _VAccessor<V, WS> vData, bool raggedSpectra = false,
228 NXcompression compressionType = NXcompression::NONE, double fillValue = _DEFAULT_FILL_VALUE,
229 bool closeData = true) {
230
231 const size_t N_chunk = indices.size(); // number of spectra
232
233 size_t _chunk_size = ((*src).*vData)(0).size();
234 if (raggedSpectra) {
235 for (size_t n : indices)
236 _chunk_size = std::max(_chunk_size, ((*src).*vData)(n).size());
237 }
238 const size_t chunk_size = _chunk_size;
239
240 const Nexus::DimVector dims = {N_chunk, chunk_size};
241 const Nexus::DimVector chunk_dims = {1, chunk_size};
242
243 // Create and open the dataset.
244 // (If compressionType == NXcompression::NONE, this just creates a non-compressed dataset.)
245 dest->makeCompData(name, NXnumtype::FLOAT64, dims, compressionType, chunk_dims, true);
246
247 // Prepare a padding vector. (Unfortunately, NeXus-api does not access `setFillValue`.)
248 const bool pad_data(fillValue != _DEFAULT_FILL_VALUE);
249 const std::vector<double> vFill(pad_data ? chunk_size : 0, fillValue);
250
251 // Write the data.
252 Nexus::DimVector start{0, 0};
253 for (size_t n : indices) {
254 const auto &v = ((*src).*vData)(n);
255 const Nexus::DimVector data_dims = {1, v.size()};
256 dest->putSlab(_dataPointer<V>(v), start, data_dims);
257 if (pad_data && data_dims[1] != chunk_size) {
258 // Fill the remainder of the slab.
259 const Nexus::DimVector fill_dims = {1, chunk_size - data_dims[1]};
260 const Nexus::DimVector _start = {start[0], data_dims[1]};
261 dest->putSlab(vFill.data(), _start, fill_dims);
262 }
263
264 ++start[0];
265 }
266
267 if (closeData)
268 dest->closeData();
269}
270
271} // namespace
272
273//-------------------------------------------------------------------------------------
278 const bool &uniformSpectra, const bool &raggedSpectra,
279 const std::vector<int> &indices, const std::string &group_name,
280 bool write2Ddata) const {
281
282 // write data entry
283 try {
284 m_filehandle->makeGroup(group_name, "NXdata", true);
285 } catch (Nexus::Exception const &) {
286 return 2;
287 }
288
289 // write workspace data
290 const size_t nHist = localworkspace->getNumberHistograms();
291 if (nHist < 1)
292 return (2);
293
294 // Set the axis labels and values
295 Mantid::API::Axis *xAxis = localworkspace->getAxis(0);
296 Mantid::API::Axis *sAxis = localworkspace->getAxis(1);
297 std::string xLabel, sLabel;
298 if (xAxis->isSpectra())
299 xLabel = "spectraNumber";
300 else {
301 if (xAxis->unit())
302 xLabel = xAxis->unit()->unitID();
303 else
304 xLabel = "unknown";
305 }
306 if (sAxis->isSpectra())
307 sLabel = "spectraNumber";
308 else {
309 if (sAxis->unit())
310 sLabel = sAxis->unit()->unitID();
311 else
312 sLabel = "unknown";
313 }
314 // Get the values on the vertical axis
315 std::vector<double> axis2;
316 const size_t nSpect = indices.size();
317 if (nSpect < nHist)
318 for (size_t i = 0; i < nSpect; i++)
319 axis2.emplace_back((*sAxis)(indices[i]));
320 else
321 for (size_t i = 0; i < sAxis->length(); i++)
322 axis2.emplace_back((*sAxis)(i));
323
324 // -------------- Actually write the 2D data ----------------------------
325 if (write2Ddata) {
326 _writeChunkedData<HistogramY, MatrixWorkspace>(m_filehandle, "values", localworkspace, indices, &MatrixWorkspace::y,
327 raggedSpectra, m_nexuscompression, _DEFAULT_FILL_VALUE,
328 false // don't close the dataset
329 );
330
331 if (m_progress != nullptr)
332 m_progress->reportIncrement(1, "Writing data");
333 m_filehandle->putAttr("signal", 1);
334 // More properties
335 m_filehandle->putAttr("axes", "axis2,axis1");
336 m_filehandle->putAttr("units", localworkspace->YUnit(), false);
337 m_filehandle->putAttr("unit_label", localworkspace->YUnitLabel(), false);
338 m_filehandle->closeData();
339
340 // errors
341 _writeChunkedData<HistogramE, MatrixWorkspace>(m_filehandle, "errors", localworkspace, indices, &MatrixWorkspace::e,
342 raggedSpectra, m_nexuscompression);
343 if (m_progress != nullptr)
344 m_progress->reportIncrement(1, "Writing data");
345
346 // Fractional area for RebinnedOutput
347 if (localworkspace->id() == "RebinnedOutput") {
348 RebinnedOutput_const_sptr rebin_workspace = std::dynamic_pointer_cast<const RebinnedOutput>(localworkspace);
349
350 _writeChunkedData<MantidVec, RebinnedOutput>(m_filehandle, "frac_area", rebin_workspace, indices,
352 _DEFAULT_FILL_VALUE,
353 false // don't close the dataset
354 );
355
356 std::string finalized = (rebin_workspace->isFinalized()) ? "1" : "0";
357 m_filehandle->putAttr("finalized", finalized);
358 std::string sqrdErrs = (rebin_workspace->hasSqrdErrors()) ? "1" : "0";
359 m_filehandle->putAttr("sqrd_errors", sqrdErrs);
360
361 if (m_progress != nullptr)
362 m_progress->reportIncrement(1, "Writing data");
363 m_filehandle->closeData();
364 }
365
366 // x errors
367 if (localworkspace->hasDx(0)) {
368 _writeChunkedData<HistogramDx, MatrixWorkspace>(m_filehandle, "xerrors", localworkspace, indices,
369 &MatrixWorkspace::dx, raggedSpectra, m_nexuscompression);
370 }
371 }
372
373 // write X data, as single array or all values if "ragged"
374 if (uniformSpectra) {
375 m_filehandle->makeData("axis1", NXnumtype::FLOAT64, localworkspace->x(0).size(), true);
376 m_filehandle->putData(localworkspace->x(0).rawData().data());
377
378 } else {
379 _writeChunkedData<HistogramX, MatrixWorkspace>(
380 m_filehandle, "axis1", localworkspace, indices, &MatrixWorkspace::x, raggedSpectra, NXcompression::NONE,
381 raggedSpectra ? std::numeric_limits<double>::quiet_NaN() : _DEFAULT_FILL_VALUE,
382 false // don't close the dataset
383 );
384 }
385
386 std::string dist = (localworkspace->isDistribution()) ? "1" : "0";
387 m_filehandle->putAttr("distribution", dist);
388 m_filehandle->putAttr("units", xLabel);
389
390 auto label = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(xAxis->unit());
391 if (label) {
392 m_filehandle->putAttr("caption", label->caption(), false);
393 auto unitLbl = label->label();
394 m_filehandle->putAttr("label", unitLbl.ascii(), false);
395 }
396
397 m_filehandle->closeData();
398
399 if (!sAxis->isText()) {
400 // write axis2, maybe just spectra number
401 m_filehandle->makeData("axis2", NXnumtype::FLOAT64, axis2.size(), true);
402 m_filehandle->putData(axis2.data());
403 m_filehandle->putAttr("units", sLabel, false);
404
405 auto unitLabel = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(sAxis->unit());
406 if (unitLabel) {
407 m_filehandle->putAttr("caption", unitLabel->caption(), false);
408 auto unitLbl = unitLabel->label();
409 m_filehandle->putAttr("label", unitLbl.ascii(), false);
410 }
411
412 m_filehandle->closeData();
413 } else {
414 std::string textAxis;
415 for (size_t i = 0; i < sAxis->length(); i++) {
416 textAxis += sAxis->label(i) + "\n";
417 }
418 m_filehandle->makeData("axis2", NXnumtype::CHAR, textAxis.size(), true);
419 m_filehandle->putData(textAxis.c_str());
420 m_filehandle->putAttr("units", "TextAxis");
421
422 auto unitLabel = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(sAxis->unit());
423 if (unitLabel) {
424 m_filehandle->putAttr("caption", unitLabel->caption(), false);
425 auto unitLbl = unitLabel->label();
426 m_filehandle->putAttr("label", unitLbl.ascii(), false);
427 }
428
429 m_filehandle->closeData();
430 }
431
432 writeNexusBinMasking(localworkspace);
433
434 m_filehandle->closeGroup();
435 return 0;
436}
437
438//-------------------------------------------------------------------------------------
447template <typename ColumnT, typename NexusT>
448void NexusFileIO::writeTableColumn(NXnumtype type, const std::string &interpret_as, const API::Column &col,
449 const std::string &columnName) const {
450 const auto nRows = col.size();
451 const Nexus::DimVector dims_array{nRows};
452
453 auto toNexus = new NexusT[nRows];
454 for (std::size_t ii = 0; ii < nRows; ii++)
455 toNexus[ii] = static_cast<NexusT>(col.cell<ColumnT>(ii));
456 writeData(columnName.c_str(), type, dims_array, toNexus, false);
457 delete[] toNexus;
458
459 // attributes
460 m_filehandle->openData(columnName);
461 std::string units = "Not known";
462 m_filehandle->putAttr("units", units, false);
463 m_filehandle->putAttr("interpret_as", interpret_as, false);
464 m_filehandle->closeData();
465}
466
467// Helper templated definitions
468namespace {
469
470// Get a size of a vector to be used in writeNexusVectorColumn(...)
471template <typename VecType> size_t getSizeOf(const VecType &vec) { return vec.size(); }
472
473// Special case of V3D
474size_t getSizeOf(const Kernel::V3D & /*unused*/) { return 3; }
475} // namespace
476
484template <typename VecType, typename ElemType>
485void NexusFileIO::writeNexusVectorColumn(const Column_const_sptr &col, const std::string &columnName,
486 NXnumtype nexusType, const std::string &interpret_as) const {
487 ConstColumnVector<VecType> column(col);
488 size_t rowCount = column.size();
489
490 // Search for the longest array amongst the cells
491 size_t maxSize(0);
492 for (size_t i = 0; i < rowCount; ++i) {
493 size_t size = getSizeOf(column[i]);
494
495 if (size > maxSize)
496 maxSize = size;
497 }
498
499 // Set-up dimensions
500 const Nexus::DimVector dims{rowCount, maxSize};
501
502 // Create data array
503 boost::scoped_array<ElemType> data(new ElemType[rowCount * maxSize]);
504
505 for (size_t i = 0; i < rowCount; ++i) {
506 // copy data in a cell to a vector with the same element type
507 std::vector<ElemType> values = column[i];
508
509 // So that all the arrays are of the size maxSize
510 values.resize(maxSize);
511
512 // Copy values to the data array
513 for (size_t j = 0; j < maxSize; ++j)
514 data[i * maxSize + j] = values[j];
515 }
516
517 // Write data
518 writeData(columnName.c_str(), nexusType, dims, data.get(), false);
519
520 m_filehandle->openData(columnName);
521
522 // Add sizes of rows as attributes. We can't use padding zeroes to determine
523 // that because the
524 // vector stored might end with zeroes as well.
525 for (size_t i = 0; i < rowCount; ++i) {
526 auto size = static_cast<int>(getSizeOf(column[i]));
527
528 std::ostringstream rowSizeAttrName;
529 rowSizeAttrName << "row_size_" << i;
530
531 m_filehandle->putAttr(rowSizeAttrName.str(), size);
532 }
533
534 std::string units = "Not known";
535
536 // Write general attributes
537 m_filehandle->putAttr("units", units, false);
538 m_filehandle->putAttr("interpret_as", interpret_as, false);
539
540 m_filehandle->closeData();
541}
542//-------------------------------------------------------------------------------------
546 const char *group_name) const {
547 std::shared_ptr<const TableWorkspace> tableworkspace =
548 std::dynamic_pointer_cast<const TableWorkspace>(itableworkspace);
549 std::shared_ptr<const PeaksWorkspace> peakworkspace =
550 std::dynamic_pointer_cast<const PeaksWorkspace>(itableworkspace);
551
552 if (!tableworkspace && !peakworkspace)
553 return 3;
554
555 // write data entry
556 try {
557 m_filehandle->makeGroup(group_name, "NXdata", true);
558 } catch (Nexus::Exception const &) {
559 return 2;
560 }
561
562 std::size_t nRows = itableworkspace->rowCount();
563
564 for (size_t i = 0; i < itableworkspace->columnCount(); i++) {
565 Column_const_sptr col = itableworkspace->getColumn(i);
566
567 std::string str = "column_" + std::to_string(i + 1);
568
569 if (col->isType<double>()) {
570 writeTableColumn<double, double>(NXnumtype::FLOAT64, "", *col, str);
571 } else if (col->isType<float>()) {
572 writeTableColumn<float, float>(NXnumtype::FLOAT32, "", *col, str);
573 } else if (col->isType<int>()) {
574 writeTableColumn<int, int32_t>(NXnumtype::INT32, "", *col, str);
575 } else if (col->isType<uint32_t>()) {
576 writeTableColumn<uint32_t, uint32_t>(NXnumtype::UINT32, "", *col, str);
577 } else if (col->isType<int64_t>()) {
578 writeTableColumn<int64_t, int64_t>(NXnumtype::INT64, "", *col, str);
579 } else if (col->isType<size_t>()) {
580 writeTableColumn<size_t, uint64_t>(NXnumtype::UINT64, "", *col, str);
581 } else if (col->isType<Boolean>()) {
582 writeTableColumn<bool, bool>(NXnumtype::UINT8, "", *col, str);
583 } else if (col->isType<std::string>()) {
584 // determine max string size
585 std::size_t maxStr = 0;
586 for (std::size_t ii = 0; ii < nRows; ii++) {
587 if (col->cell<std::string>(ii).size() > maxStr)
588 maxStr = col->cell<std::string>(ii).size();
589 }
590 // If the column is empty fill the data with spaces.
591 // Strings containing spaces only will be read back in as empty strings.
592 if (maxStr == 0) {
593 maxStr = 1;
594 }
595 const Nexus::DimVector dims_array{nRows, maxStr};
596 const Nexus::DimVector asize{1, dims_array[1]};
597
598 m_filehandle->makeCompData(str, NXnumtype::CHAR, dims_array, NXcompression::LZW, asize);
599
600 m_filehandle->openData(str);
601 auto toNexus = new char[maxStr * nRows];
602 for (std::size_t ii = 0; ii < nRows; ii++) {
603 std::string rowStr = col->cell<std::string>(ii);
604 for (size_t ic = 0; ic < rowStr.size(); ic++)
605 toNexus[ii * maxStr + ic] = rowStr[ic];
606 for (size_t ic = rowStr.size(); ic < static_cast<size_t>(maxStr); ic++)
607 toNexus[ii * maxStr + ic] = ' ';
608 }
609
610 m_filehandle->putData(toNexus);
611 delete[] toNexus;
612
613 // attributes
614 std::string units = "N/A";
615 std::string interpret_as = "A string";
616 m_filehandle->putAttr("units", units);
617 m_filehandle->putAttr("interpret_as", interpret_as);
618
619 m_filehandle->closeData();
620 } else if (col->isType<std::vector<int>>()) {
621 writeNexusVectorColumn<std::vector<int>, int>(col, str, NXnumtype::INT32, "");
622 } else if (col->isType<std::vector<double>>()) {
623 writeNexusVectorColumn<std::vector<double>, double>(col, str, NXnumtype::FLOAT64, "");
624 } else if (col->isType<Kernel::V3D>()) {
625 writeNexusVectorColumn<Kernel::V3D, double>(col, str, NXnumtype::FLOAT64, "V3D");
626 }
627
628 // write out title
629 m_filehandle->openData(str);
630 m_filehandle->putAttr("name", col->name());
631 m_filehandle->closeData();
632 }
633
634 try {
635 m_filehandle->closeGroup();
636 } catch (Nexus::Exception const &) {
637 return 3;
638 }
639 return 0;
640}
641
642//-------------------------------------------------------------------------------------
654 std::vector<int64_t> const &indices, double const *tofs,
655 float const *weights, float const *errorSquareds,
656 int64_t const *pulsetimes, bool compress) const {
657 m_filehandle->openGroup("event_workspace", "NXdata");
658
659 // The array of indices for each event list #
660 Nexus::DimVector dims_array = {indices.size()};
661 if (!indices.empty()) {
662 if (compress)
663 m_filehandle->makeCompData("indices", NXnumtype::INT64, dims_array, m_nexuscompression, dims_array);
664 else
665 m_filehandle->makeData("indices", NXnumtype::INT64, dims_array);
666 m_filehandle->openData("indices");
667 m_filehandle->putData(indices.data());
668 m_filehandle->putAttr("units", ws->YUnit(), false);
669 m_filehandle->putAttr("unit_label", ws->YUnitLabel(), false);
670 m_filehandle->closeData();
671 }
672
673 // Write out each field
674 dims_array[0] = static_cast<int>(indices.back()); // TODO big truncation error! This is the # of events
675 if (tofs)
676 writeData("tof", NXnumtype::FLOAT64, dims_array, tofs, compress);
677 if (pulsetimes)
678 writeData("pulsetime", NXnumtype::INT64, dims_array, pulsetimes, compress);
679 if (weights)
680 writeData("weight", NXnumtype::FLOAT32, dims_array, weights, compress);
681 if (errorSquareds)
682 writeData("error_squared", NXnumtype::FLOAT32, std::move(dims_array), errorSquareds, compress);
683
684 // Close up the overall group
685 m_filehandle->closeGroup();
686 return 0;
687}
688
689//-------------------------------------------------------------------------------------
691template <typename NumT>
692void NexusFileIO::writeData(const char *name, NXnumtype datatype, Nexus::DimVector dims_array, NumT const *data,
693 bool compress) const {
694 if (compress) {
695 // We'll use the same slab/buffer size as the size of the array
696 m_filehandle->makeCompData(name, datatype, dims_array, m_nexuscompression, dims_array);
697 } else {
698 // Write uncompressed.
699 m_filehandle->makeData(name, datatype, dims_array);
700 }
701
702 m_filehandle->openData(name);
703 m_filehandle->putData(data);
704 m_filehandle->closeData();
705}
706
708 // search exiting file for entries of form mantid_workspace_<n> and return
709 // count
710 int count = 0;
711 std::map<std::string, std::string> entries = m_filehandle->getEntries();
712 for (auto &entrie : entries) {
713 if (entrie.second == "NXentry") {
714 if (entrie.first.find("mantid_workspace_") == 0)
715 count++;
716 }
717 }
718
719 return count;
720}
721
728 std::vector<int32_t> spectra;
729 std::vector<int64_t> bins;
730 std::vector<double> weights;
731 std::size_t spectra_count = 0;
732 int offset = 0;
733 for (std::size_t i = 0; i < ws->getNumberHistograms(); ++i) {
734 if (ws->hasMaskedBins(i)) {
735 const API::MatrixWorkspace::MaskList &mList = ws->maskedBins(i);
736 spectra.emplace_back(static_cast<int32_t>(spectra_count));
737 spectra.emplace_back(offset);
738 for (const auto &mask : mList) {
739 bins.emplace_back(mask.first);
740 weights.emplace_back(mask.second);
741 }
742 ++spectra_count;
743 offset += static_cast<int>(mList.size());
744 }
745 }
746
747 if (spectra_count == 0)
748 return false;
749
750 // save spectra offsets as a 2d array of ints
751 Nexus::DimVector dimensions{spectra_count, 2};
752
753 m_filehandle->makeData("masked_spectra", NXnumtype::INT32, dimensions, true);
754 m_filehandle->putAttr("description", "spectra index,offset in masked_bins and mask_weights");
755 m_filehandle->putData(spectra.data());
756 m_filehandle->closeData();
757
758 // save masked bin indices
759 dimensions[0] = bins.size();
760 m_filehandle->makeData("masked_bins", NXnumtype::UINT64, dimensions, true);
761 m_filehandle->putData(bins.data());
762 m_filehandle->closeData();
763
764 // save masked bin weights
765 dimensions[0] = bins.size();
766 m_filehandle->makeData("mask_weights", NXnumtype::FLOAT64, dimensions, true);
767 m_filehandle->putData(weights.data());
768 m_filehandle->closeData();
769
770 return true;
771}
772
777 // Close the nexus file if not already closed.
778 // this->closeNexusFile();
779}
780
781} // namespace Mantid::Nexus
std::string name
Definition Run.cpp:60
int count
counter
Definition Matrix.cpp:37
NXaccess
Nexus file access codes.
NXcompression
The available compression types:
std::vector< T > const * vec
Class to represent the axis of a workspace.
Definition Axis.h:28
virtual std::string label(const std::size_t &index) const =0
Returns a text label of for a value Note that the index here is not the index of a value,...
virtual bool isText() const
Returns true if the axis is Text.
Definition Axis.h:52
virtual std::size_t length() const =0
Get the length of the axis.
const Kernel::Unit_sptr & unit() const
The unit for this axis.
Definition Axis.cpp:28
virtual bool isSpectra() const
Returns true is the axis is a Spectra axis.
Definition Axis.h:48
Column is the base class for columns of TableWorkspace.
Definition Column.h:35
T & cell(size_t index)
Templated method for returning a value. No type checks are done.
Definition Column.h:124
virtual size_t size() const =0
Number of individual elements in the column.
ConstColumnVector gives const access to the column elements without alowing its resizing.
size_t size()
Size of the vector.
const HistogramData::HistogramE & e(const size_t index) const
const HistogramData::HistogramDx & dx(const size_t index) const
std::map< size_t, double > MaskList
Masked bins for each spectrum are stored as a set of pairs containing <bin index, weight>
const HistogramData::HistogramX & x(const size_t index) const
const HistogramData::HistogramY & y(const size_t index) const
Helper class for reporting progress from algorithms.
Definition Progress.h:25
const MantidVec & readF(std::size_t const index) const
Returns a read-only (i.e. const) reference to the specified F array.
Records the filename and the description of failure.
Definition Exception.h:98
void reportIncrement(int inc, const std::string &msg="")
Sends the progress notification and increment the loop counter by more than one.
Class for 3D vectors.
Definition V3D.h:35
Class that provides for a standard Nexus exception.
int writeNexusProcessedDataEventCombined(const DataObjects::EventWorkspace_const_sptr &ws, std::vector< int64_t > const &indices, double const *tofs, float const *weights, float const *errorSquareds, int64_t const *pulsetimes, bool compress) const
Write out a combined chunk of event data.
int writeNexusTableWorkspace(const API::ITableWorkspace_const_sptr &itableworkspace, const char *group_name) const
write table workspace
bool writeNexusBinMasking(const API::MatrixWorkspace_const_sptr &ws) const
write bin masking information
int writeNexusProcessedHeader(const std::string &title, const std::string &wsName="") const
write the header ifon for the Mantid workspace format
int writeNexusProcessedData2D(const API::MatrixWorkspace_const_sptr &localworkspace, const bool &uniformSpectra, const bool &raggedSpectra, const std::vector< int > &indices, const std::string &group_name, bool write2Ddata) const
write the workspace data
std::shared_ptr< Nexus::File > m_filehandle
C++ API file handle.
void writeNexusVectorColumn(const API::Column_const_sptr &col, const std::string &columnName, NXnumtype nexusType, const std::string &interpret_as) const
Writes given vector column to the currently open Nexus file.
void writeData(const char *name, NXnumtype datatype, Nexus::DimVector dims_array, NumT const *data, bool compress=false) const
Write out an array to the open file.
void openNexusWrite(const std::string &fileName, optional_size_t entryNumber=optional_size_t(), const bool append_to_file=true)
open the nexus file for writing
void writeTableColumn(NXnumtype type, const std::string &interpret_as, const API::Column &col, const std::string &columnName) const
Save a numeric columns of a TableWorkspace to currently open nexus file.
bool writeNxValue(const std::string &name, const std::string &value, const std::vector< std::string > &attributes, const std::vector< std::string > &avalues) const
Write a simple value plus possible attributes.
void closeNexusFile()
close the nexus file
API::Progress * m_progress
Allow an externally supplied progress object to be used.
NXcompression m_nexuscompression
Nexus compression method.
int findMantidWSEntries() const
search for exisiting MantidWorkpace_n entries in opened file
std::string m_filename
nexus file name
std::optional< size_t > optional_size_t
void resetProgress(Mantid::API::Progress *prog)
Reset the pointer to the progress object.
The primitive types published by this API.
static unsigned short constexpr UINT64
static unsigned short constexpr INT64
static unsigned short constexpr UINT32
static unsigned short constexpr CHAR
static unsigned short constexpr UINT8
static unsigned short constexpr INT32
static unsigned short constexpr FLOAT32
static unsigned short constexpr FLOAT64
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const ITableWorkspace > ITableWorkspace_const_sptr
shared pointer to Mantid::API::ITableWorkspace (const version)
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< const Column > Column_const_sptr
Definition Column.h:230
std::shared_ptr< const RebinnedOutput > RebinnedOutput_const_sptr
shared pointer to a const RebinnedOutput
Definition SumSpectra.h:24
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
Header for a base Nexus::Exception.
std::vector< dimsize_t > DimVector
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition cow_ptr.h:172
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
As TableColumn stores its data in a std::vector bool type cannot be used in the same way as the other...
Definition Column.h:210