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