25#include "MantidHistogramData/Histogram.h"
32using namespace Kernel;
34using namespace DataObjects;
36using HistogramData::HistogramDx;
37using HistogramData::HistogramE;
38using HistogramData::HistogramX;
39using HistogramData::HistogramY;
44Logger
g_log(
"NexusFileIO");
49 : m_filehandle(), m_nexuscompression(
NXcompression::
LZW), m_progress(nullptr), m_filename() {}
53 : m_filehandle(), m_nexuscompression(
NXcompression::
LZW), m_progress(prog), m_filename() {}
84 const bool append_to_file) {
89 std::string mantidEntryName;
100 if (fileName.find(
".xml") < fileName.size() || fileName.find(
".XML") < fileName.size()) {
103 mantidEntryName =
"mantid_workspace_1";
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: ";
117 auto file =
new Nexus::File(fileName, mode);
130 if (entryNumber.has_value()) {
132 count = entryNumber.value();
139 std::stringstream suffix;
140 suffix << (
count + 1);
141 mantidEntryName =
"mantid_workspace_" + suffix.str();
147 const std::string className =
"NXentry";
173 const std::string className =
"Mantid Processed Workspace";
174 std::vector<std::string> attributes, avalues;
175 attributes.reserve(2);
181 if (!wsName.empty()) {
182 if (!
writeNxValue(
"workspace_name", wsName, attributes, avalues))
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");
191 if (!
writeNxValue(
"definition", className, attributes, avalues))
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))
206const double _DEFAULT_FILL_VALUE(0.0);
211template <
class V,
class WS>
using _VAccessor =
const V &(WS::*)(
size_t)
const;
215template <
class V>
const double *_dataPointer(
const V &v) {
return v.rawData().data(); }
217template <>
const double *_dataPointer<MantidVec>(
const MantidVec &v) {
return v.data(); }
223template <
class V,
class WS>
224void _writeChunkedData(std::shared_ptr<Nexus::File> dest,
225 const std::string &
name,
226 std::shared_ptr<const WS> src,
227 const std::vector<int> &indices, _VAccessor<V, WS> vData,
bool raggedSpectra =
false,
229 bool closeData =
true) {
231 const size_t N_chunk = indices.size();
233 size_t _chunk_size = ((*src).*vData)(0).size();
235 for (
size_t n : indices)
236 _chunk_size =
std::max(_chunk_size, ((*src).*vData)(
n).size());
238 const size_t chunk_size = _chunk_size;
248 const bool pad_data(fillValue != _DEFAULT_FILL_VALUE);
249 const std::vector<double> vFill(pad_data ? chunk_size : 0, fillValue);
253 for (
size_t n : indices) {
254 const auto &v = ((*src).*vData)(
n);
256 dest->putSlab(_dataPointer<V>(v), start, data_dims);
257 if (pad_data && data_dims[1] != chunk_size) {
261 dest->putSlab(vFill.data(), _start, fill_dims);
278 const bool &uniformSpectra,
const bool &raggedSpectra,
279 const std::vector<int> &indices,
const std::string &group_name,
280 bool write2Ddata)
const {
290 const size_t nHist = localworkspace->getNumberHistograms();
297 std::string xLabel, sLabel;
299 xLabel =
"spectraNumber";
302 xLabel = xAxis->
unit()->unitID();
307 sLabel =
"spectraNumber";
310 sLabel = sAxis->
unit()->unitID();
315 std::vector<double> axis2;
316 const size_t nSpect = indices.size();
318 for (
size_t i = 0; i < nSpect; i++)
319 axis2.emplace_back((*sAxis)(indices[i]));
321 for (
size_t i = 0; i < sAxis->
length(); i++)
322 axis2.emplace_back((*sAxis)(i));
336 m_filehandle->putAttr(
"units", localworkspace->YUnit(),
false);
337 m_filehandle->putAttr(
"unit_label", localworkspace->YUnitLabel(),
false);
347 if (localworkspace->id() ==
"RebinnedOutput") {
350 _writeChunkedData<MantidVec, RebinnedOutput>(
m_filehandle,
"frac_area", rebin_workspace, indices,
356 std::string finalized = (rebin_workspace->isFinalized()) ?
"1" :
"0";
358 std::string sqrdErrs = (rebin_workspace->hasSqrdErrors()) ?
"1" :
"0";
367 if (localworkspace->hasDx(0)) {
368 _writeChunkedData<HistogramDx, MatrixWorkspace>(
m_filehandle,
"xerrors", localworkspace, indices,
374 if (uniformSpectra) {
376 m_filehandle->putData(localworkspace->x(0).rawData().data());
379 _writeChunkedData<HistogramX, MatrixWorkspace>(
381 raggedSpectra ? std::numeric_limits<double>::quiet_NaN() : _DEFAULT_FILL_VALUE,
386 std::string dist = (localworkspace->isDistribution()) ?
"1" :
"0";
390 auto label = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(xAxis->
unit());
392 m_filehandle->putAttr(
"caption", label->caption(),
false);
393 auto unitLbl = label->label();
405 auto unitLabel = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(sAxis->
unit());
407 m_filehandle->putAttr(
"caption", unitLabel->caption(),
false);
408 auto unitLbl = unitLabel->label();
414 std::string textAxis;
415 for (
size_t i = 0; i < sAxis->
length(); i++) {
416 textAxis += sAxis->
label(i) +
"\n";
422 auto unitLabel = std::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(sAxis->
unit());
424 m_filehandle->putAttr(
"caption", unitLabel->caption(),
false);
425 auto unitLbl = unitLabel->label();
447template <
typename ColumnT,
typename NexusT>
449 const std::string &columnName)
const {
450 const auto nRows = col.
size();
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);
461 std::string units =
"Not known";
463 m_filehandle->putAttr(
"interpret_as", interpret_as,
false);
471template <
typename VecType>
size_t getSizeOf(
const VecType &
vec) {
return vec.size(); }
474size_t getSizeOf(
const Kernel::V3D & ) {
return 3; }
484template <
typename VecType,
typename ElemType>
486 NXnumtype nexusType,
const std::string &interpret_as)
const {
488 size_t rowCount = column.
size();
492 for (
size_t i = 0; i < rowCount; ++i) {
493 size_t size = getSizeOf(column[i]);
503 boost::scoped_array<ElemType> data(
new ElemType[rowCount * maxSize]);
505 for (
size_t i = 0; i < rowCount; ++i) {
507 std::vector<ElemType> values = column[i];
510 values.resize(maxSize);
513 for (
size_t j = 0; j < maxSize; ++j)
514 data[i * maxSize + j] = values[j];
518 writeData(columnName.c_str(), nexusType, dims, data.get(),
false);
525 for (
size_t i = 0; i < rowCount; ++i) {
526 auto size =
static_cast<int>(getSizeOf(column[i]));
528 std::ostringstream rowSizeAttrName;
529 rowSizeAttrName <<
"row_size_" << i;
534 std::string units =
"Not known";
538 m_filehandle->putAttr(
"interpret_as", interpret_as,
false);
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);
552 if (!tableworkspace && !peakworkspace)
562 std::size_t nRows = itableworkspace->rowCount();
564 for (
size_t i = 0; i < itableworkspace->columnCount(); i++) {
569 if (col->isType<
double>()) {
571 }
else if (col->isType<
float>()) {
573 }
else if (col->isType<
int>()) {
575 }
else if (col->isType<uint32_t>()) {
577 }
else if (col->isType<int64_t>()) {
579 }
else if (col->isType<
size_t>()) {
581 }
else if (col->isType<
Boolean>()) {
583 }
else if (col->isType<std::string>()) {
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();
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] =
' ';
614 std::string units =
"N/A";
615 std::string interpret_as =
"A string";
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,
"");
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 {
661 if (!indices.empty()) {
669 m_filehandle->putAttr(
"unit_label", ws->YUnitLabel(),
false);
674 dims_array[0] =
static_cast<int>(indices.back());
691template <
typename NumT>
693 bool compress)
const {
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)
728 std::vector<int32_t> spectra;
729 std::vector<int64_t> bins;
730 std::vector<double> weights;
731 std::size_t spectra_count = 0;
733 for (std::size_t i = 0; i < ws->getNumberHistograms(); ++i) {
734 if (ws->hasMaskedBins(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);
743 offset +=
static_cast<int>(mList.size());
747 if (spectra_count == 0)
754 m_filehandle->putAttr(
"description",
"spectra index,offset in masked_bins and mask_weights");
759 dimensions[0] = bins.size();
765 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 Kernel::Unit_sptr & 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 RebinnedOutput > RebinnedOutput_const_sptr
shared pointer to a const RebinnedOutput
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
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...