25#include "MantidHistogramData/Histogram.h"
31using namespace Kernel;
33using namespace DataObjects;
35using HistogramData::HistogramDx;
36using HistogramData::HistogramE;
37using HistogramData::HistogramX;
38using HistogramData::HistogramY;
43Logger
g_log(
"NexusFileIO");
48 : m_filehandle(), m_nexuscompression(
NXcompression::
LZW), m_progress(nullptr), m_filename() {}
52 : m_filehandle(), m_nexuscompression(
NXcompression::
LZW), m_progress(prog), m_filename() {}
83 const bool append_to_file) {
88 std::string mantidEntryName;
99 if (fileName.find(
".xml") < fileName.size() || fileName.find(
".XML") < fileName.size()) {
102 mantidEntryName =
"mantid_workspace_1";
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: ";
116 auto file =
new Nexus::File(fileName, mode);
129 if (entryNumber.has_value()) {
131 count = entryNumber.value();
138 std::stringstream suffix;
139 suffix << (
count + 1);
140 mantidEntryName =
"mantid_workspace_" + suffix.str();
146 const std::string className =
"NXentry";
172 const std::string className =
"Mantid Processed Workspace";
173 std::vector<std::string> attributes, avalues;
174 attributes.reserve(2);
180 if (!wsName.empty()) {
181 if (!
writeNxValue(
"workspace_name", wsName, attributes, avalues))
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");
190 if (!
writeNxValue(
"definition", className, attributes, avalues))
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))
205const double _DEFAULT_FILL_VALUE(0.0);
210template <
class V,
class WS>
using _VAccessor =
const V &(WS::*)(
size_t)
const;
214template <
class V>
const double *_dataPointer(
const V &v) {
return v.rawData().data(); }
216template <>
const double *_dataPointer<MantidVec>(
const MantidVec &v) {
return v.data(); }
222template <
class V,
class WS>
223void _writeChunkedData(std::shared_ptr<Nexus::File> dest,
224 const std::string &
name,
225 std::shared_ptr<const WS> src,
226 const std::vector<int> &indices, _VAccessor<V, WS> vData,
bool raggedSpectra =
false,
228 bool closeData =
true) {
230 const size_t N_chunk = indices.size();
232 size_t _chunk_size = ((*src).*vData)(0).size();
234 for (
size_t n : indices)
235 _chunk_size =
std::max(_chunk_size, ((*src).*vData)(
n).size());
237 const size_t chunk_size = _chunk_size;
247 const bool pad_data(fillValue != _DEFAULT_FILL_VALUE);
248 const std::vector<double> vFill(pad_data ? chunk_size : 0, fillValue);
252 for (
size_t n : indices) {
253 const auto &v = ((*src).*vData)(
n);
255 dest->putSlab(_dataPointer<V>(v), start, data_dims);
256 if (pad_data && data_dims[1] != chunk_size) {
260 dest->putSlab(vFill.data(), _start, fill_dims);
277 const bool &uniformSpectra,
const bool &raggedSpectra,
278 const std::vector<int> &indices,
const std::string &group_name,
279 bool write2Ddata)
const {
289 const size_t nHist = localworkspace->getNumberHistograms();
296 std::string xLabel, sLabel;
298 xLabel =
"spectraNumber";
301 xLabel = xAxis->
unit()->unitID();
306 sLabel =
"spectraNumber";
309 sLabel = sAxis->
unit()->unitID();
314 std::vector<double> axis2;
315 const size_t nSpect = indices.size();
317 for (
size_t i = 0; i < nSpect; i++)
318 axis2.emplace_back((*sAxis)(indices[i]));
320 for (
size_t i = 0; i < sAxis->
length(); i++)
321 axis2.emplace_back((*sAxis)(i));
335 m_filehandle->putAttr(
"units", localworkspace->YUnit(),
false);
336 m_filehandle->putAttr(
"unit_label", localworkspace->YUnitLabel(),
false);
346 if (localworkspace->id() ==
"RebinnedOutput") {
349 _writeChunkedData<MantidVec, RebinnedOutput>(
m_filehandle,
"frac_area", rebin_workspace, indices,
355 std::string finalized = (rebin_workspace->isFinalized()) ?
"1" :
"0";
357 std::string sqrdErrs = (rebin_workspace->hasSqrdErrors()) ?
"1" :
"0";
366 if (localworkspace->hasDx(0)) {
367 _writeChunkedData<HistogramDx, MatrixWorkspace>(
m_filehandle,
"xerrors", localworkspace, indices,
373 if (uniformSpectra) {
375 m_filehandle->putData(localworkspace->x(0).rawData().data());
378 _writeChunkedData<HistogramX, MatrixWorkspace>(
380 raggedSpectra ? std::numeric_limits<double>::quiet_NaN() : _DEFAULT_FILL_VALUE,
385 std::string dist = (localworkspace->isDistribution()) ?
"1" :
"0";
389 auto label = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(xAxis->
unit());
391 m_filehandle->putAttr(
"caption", label->caption(),
false);
392 auto unitLbl = label->label();
404 auto unitLabel = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(sAxis->
unit());
406 m_filehandle->putAttr(
"caption", unitLabel->caption(),
false);
407 auto unitLbl = unitLabel->label();
413 std::string textAxis;
414 for (
size_t i = 0; i < sAxis->
length(); i++) {
415 textAxis += sAxis->
label(i) +
"\n";
421 auto unitLabel = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(sAxis->
unit());
423 m_filehandle->putAttr(
"caption", unitLabel->caption(),
false);
424 auto unitLbl = unitLabel->label();
446template <
typename ColumnT,
typename NexusT>
448 const std::string &columnName)
const {
449 const auto nRows = col.
size();
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);
460 std::string units =
"Not known";
462 m_filehandle->putAttr(
"interpret_as", interpret_as,
false);
470template <
typename VecType>
size_t getSizeOf(
const VecType &
vec) {
return vec.size(); }
473size_t getSizeOf(
const Kernel::V3D & ) {
return 3; }
483template <
typename VecType,
typename ElemType>
485 NXnumtype nexusType,
const std::string &interpret_as)
const {
487 size_t rowCount = column.
size();
491 for (
size_t i = 0; i < rowCount; ++i) {
492 size_t size = getSizeOf(column[i]);
502 boost::scoped_array<ElemType> data(
new ElemType[rowCount * maxSize]);
504 for (
size_t i = 0; i < rowCount; ++i) {
506 std::vector<ElemType> values = column[i];
509 values.resize(maxSize);
512 for (
size_t j = 0; j < maxSize; ++j)
513 data[i * maxSize + j] = values[j];
517 writeData(columnName.c_str(), nexusType, dims, data.get(),
false);
524 for (
size_t i = 0; i < rowCount; ++i) {
525 auto size =
static_cast<int>(getSizeOf(column[i]));
527 std::ostringstream rowSizeAttrName;
528 rowSizeAttrName <<
"row_size_" << i;
533 std::string units =
"Not known";
537 m_filehandle->putAttr(
"interpret_as", interpret_as,
false);
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);
551 if (!tableworkspace && !peakworkspace)
561 std::size_t nRows = itableworkspace->rowCount();
563 for (
size_t i = 0; i < itableworkspace->columnCount(); i++) {
568 if (col->isType<
double>()) {
570 }
else if (col->isType<
float>()) {
572 }
else if (col->isType<
int>()) {
574 }
else if (col->isType<uint32_t>()) {
576 }
else if (col->isType<int64_t>()) {
578 }
else if (col->isType<
size_t>()) {
580 }
else if (col->isType<
Boolean>()) {
582 }
else if (col->isType<std::string>()) {
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();
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] =
' ';
613 std::string units =
"N/A";
614 std::string interpret_as =
"A string";
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,
"");
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 {
660 if (!indices.empty()) {
668 m_filehandle->putAttr(
"unit_label", ws->YUnitLabel(),
false);
673 dims_array[0] =
static_cast<int>(indices.back());
690template <
typename NumT>
692 bool compress)
const {
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)
727 std::vector<int32_t> spectra;
728 std::vector<int64_t> bins;
729 std::vector<double> weights;
730 std::size_t spectra_count = 0;
732 for (std::size_t i = 0; i < ws->getNumberHistograms(); ++i) {
733 if (ws->hasMaskedBins(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);
742 offset +=
static_cast<int>(mList.size());
746 if (spectra_count == 0)
753 m_filehandle->putAttr(
"description",
"spectra index,offset in masked_bins and mask_weights");
758 dimensions[0] = bins.size();
764 dimensions[0] = bins.size();
NXaccess
Nexus file access codes.
NXcompression
The available compression types:
std::vector< T > const * vec
Class to represent the axis of a workspace.
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.
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.
virtual bool isSpectra() const
Returns true is the axis is a Spectra axis.
Column is the base class for columns of TableWorkspace.
T & cell(size_t index)
Templated method for returning a value. No type checks are done.
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.
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.
void reportIncrement(int inc, const std::string &msg="")
Sends the progress notification and increment the loop counter by more than one.
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.
~NexusFileIO()
Destructor.
NexusFileIO()
Default constructor.
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 closeGroup()
Close the group.
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
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
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...