31using namespace Kernel;
33using namespace DataObjects;
58bool makeMappings(
const MatrixWorkspace &ws,
const std::vector<int> &ws_indices,
59 std::vector<int32_t> &out_detector_index, std::vector<int32_t> &out_detector_count,
60 std::vector<int32_t> &out_detector_list,
int &numberSpec,
size_t &numberDetectors) {
64 std::accumulate(ws_indices.cbegin(), ws_indices.cend(),
size_t(0), [&ws](
size_t sum,
const auto &
index) {
65 return sum + ws.getSpectrum(static_cast<size_t>(index)).getDetectorIDs().size();
67 if (numberDetectors < 1) {
72 numberSpec = int(ws_indices.size());
75 out_detector_index.resize(numberSpec + 1, 0);
76 out_detector_count.resize(numberSpec, 0);
77 out_detector_list.resize(numberDetectors, 0);
81 for (
int i = 0; i < numberSpec; i++) {
83 const int si = ws_indices[i];
89 const auto ndet1 =
static_cast<int>(detectorgroup.size());
92 out_detector_index[i + 1] = int32_t(out_detector_index[i] + ndet1);
93 out_detector_count[i] = int32_t(ndet1);
95 std::set<detid_t>::const_iterator it;
96 for (it = detectorgroup.begin(); it != detectorgroup.end(); ++it) {
97 out_detector_list[
id++] = int32_t(*it);
101 out_detector_index.resize(numberSpec);
112 "Name of the workspace to be saved");
114 const std::vector<std::string> fileExts{
".nxs",
".nx5",
".xml"};
116 "The name of the Nexus file to write, as a full or relative\n"
120 declareProperty(
"Title",
"", std::make_shared<NullValidator>(),
"A title to describe the saved workspace");
121 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
122 mustBePositive->setLower(0);
125 "Index number of first spectrum to write, only for single\n"
128 "Index of last spectrum to write, only for single period\n"
131 "List of spectrum numbers to read, only for single period\n"
135 "Determines whether .nxs file needs to be\n"
136 "over written or appended");
139 "For EventWorkspaces, preserve the events when saving (default).\n"
140 "If false, will save the 2D histogram version of the workspace with the "
141 "current binning parameters.");
146 "For EventWorkspaces, compress the Nexus data field (default False).\n"
147 "This will make smaller files but takes much longer.");
158 const std::vector<int> spec_list =
getProperty(
"WorkspaceIndexList");
161 const bool list = !spec_list.empty();
165 const auto numberOfHist =
static_cast<int>(matrixWorkspace->getNumberHistograms());
168 if (spec_max < spec_min || spec_max > numberOfHist - 1) {
169 g_log.
error(
"Invalid WorkspaceIndex min/max properties");
170 throw std::invalid_argument(
"Inconsistent properties defined");
172 indices.reserve(1 + spec_max - spec_min);
173 for (
int i = spec_min; i <= spec_max; i++)
174 indices.emplace_back(i);
176 for (
auto s : spec_list) {
179 if (s < spec_min || s > spec_max)
180 indices.emplace_back(s);
185 spec_min = numberOfHist - 1;
186 for (
auto s : spec_list) {
189 indices.emplace_back(s);
197 spec_max = numberOfHist - 1;
198 indices.reserve(1 + spec_max - spec_min);
199 for (
int i = spec_min; i <= spec_max; i++)
200 indices.emplace_back(i);
213 const bool PreserveEvents =
getProperty(
"PreserveEvents");
223 if (!matrixWorkspace && !tableWorkspace) {
228 if (
bool(std::dynamic_pointer_cast<const IMDEventWorkspace>(inputWorkspace)) ||
229 bool(std::dynamic_pointer_cast<const IMDHistoWorkspace>(inputWorkspace)))
233 std::stringstream msg;
234 msg <<
"Workspace \"" <<
name <<
"\" not saved because it is not of a type we can presently save.";
236 throw std::runtime_error(msg.str());
238 m_eventWorkspace = std::dynamic_pointer_cast<const EventWorkspace>(matrixWorkspace);
239 const std::string workspaceID = inputWorkspace->id();
240 if ((workspaceID.find(
"Workspace2D") == std::string::npos) &&
241 (workspaceID.find(
"RebinnedOutput") == std::string::npos) &&
242 (workspaceID.find(
"WorkspaceSingleValue") == std::string::npos) &&
243 (workspaceID.find(
"GroupingWorkspace") == std::string::npos) && !
m_eventWorkspace && !tableWorkspace &&
244 !offsetsWorkspace && !maskWorkspace)
246 "EventWorkspace, ITableWorkspace, OffsetsWorkspace, "
247 "GroupingWorkspace, or MaskWorkspace.");
260 title = inputWorkspace->getTitle();
263 const std::string wsName = inputWorkspace->getName();
268 nexusFile->resetProgress(&prog_init);
269 nexusFile->openNexusWrite(filename, entryNumber, append_to_file || keepFile);
272 if (nexusFile->writeNexusProcessedHeader(title, wsName) != 0)
278 if (matrixWorkspace) {
280 matrixWorkspace->saveExperimentInfoNexus(nexusFile->filehandle().get(),
saveLegacyInstrument());
284 const bool uniformSpectra = matrixWorkspace->isCommonBins();
285 const bool raggedSpectra = matrixWorkspace->isRaggedWorkspace();
288 std::vector<int> indices;
294 this->
execEvent(nexusFile.get(), uniformSpectra, raggedSpectra, indices);
296 std::string workspaceTypeGroupName;
297 if (offsetsWorkspace)
298 workspaceTypeGroupName =
"offsets_workspace";
299 else if (maskWorkspace)
300 workspaceTypeGroupName =
"mask_workspace";
301 else if (std::dynamic_pointer_cast<const GroupingWorkspace>(inputWorkspace))
302 workspaceTypeGroupName =
"grouping_workspace";
304 workspaceTypeGroupName =
"workspace";
306 nexusFile->writeNexusProcessedData2D(matrixWorkspace, uniformSpectra, raggedSpectra, indices,
307 workspaceTypeGroupName.c_str(),
true);
311 nexusFile->filehandle()->openGroup(
"instrument",
"NXinstrument");
312 nexusFile->filehandle()->makeGroup(
"detector",
"NXdetector",
true);
314 nexusFile->filehandle()->putAttr(
"version", 1);
317 nexusFile->filehandle()->closeGroup();
318 nexusFile->filehandle()->closeGroup();
323 if (peaksWorkspace) {
325 peaksWorkspace->saveExperimentInfoNexus(nexusFile->filehandle().get());
327 peaksWorkspace->saveNexus(nexusFile->filehandle().get());
328 }
else if (tableWorkspace) {
329 nexusFile->writeNexusTableWorkspace(tableWorkspace,
"table_workspace");
334 m_history->fillAlgorithmHistory(
this, Mantid::Types::Core::DateAndTime::getCurrentTime(), 0,
337 inputWorkspace->history().addHistory(
m_history);
345 inputWorkspace->history().saveNexus(nexusFile->filehandle().get());
346 nexusFile->closeGroup();
358 auto nexusFile = std::make_shared<Mantid::Nexus::NexusFileIO>();
361 doExec(inputWorkspace, nexusFile);
377 float *errorSquareds, int64_t *pulsetimes) {
382 const auto it = events.cbegin();
383 const auto it_end = events.cend();
387 std::transform(it, it_end, std::next(tofs, offset), [](
const T &event) {
return event.tof(); });
390 std::transform(it, it_end, std::next(weights, offset),
391 [](
const T &event) {
return static_cast<float>(
event.weight()); });
394 std::transform(it, it_end, std::next(errorSquareds, offset),
395 [](
const T &event) {
return static_cast<float>(
event.errorSquared()); });
398 std::transform(it, it_end, std::next(pulsetimes, offset),
399 [](
const T &event) {
return event.pulseTime().totalNanoseconds(); });
408 const bool raggedSpectra,
const std::vector<int> &spec) {
415 std::vector<int64_t> indices;
419 for (
int wi = 0; wi < static_cast<int>(
m_eventWorkspace->getNumberHistograms()); wi++) {
420 indices.emplace_back(
index);
424 indices.emplace_back(
index);
428 double *tofs =
nullptr;
429 float *weights =
nullptr;
430 float *errorSquareds =
nullptr;
431 int64_t *pulsetimes =
nullptr;
435 bool writeTOF =
true;
436 bool writePulsetime =
false;
437 bool writeWeight =
false;
438 bool writeError =
false;
442 writePulsetime =
true;
445 writePulsetime =
true;
457 tofs =
new double[num];
459 weights =
new float[num];
461 errorSquareds =
new float[num];
463 pulsetimes =
new int64_t[num];
467 for (
int wi = 0; wi < static_cast<int>(
m_eventWorkspace->getNumberHistograms()); wi++) {
473 size_t offset = indices[wi];
475 switch (el.getEventType()) {
480 appendEventListData(el.getWeightedEvents(), offset, tofs, weights, errorSquareds, pulsetimes);
483 appendEventListData(el.getWeightedEventsNoTime(), offset, tofs, weights, errorSquareds, pulsetimes);
486 m_progress->reportIncrement(el.getNumberEvents(),
"Copying EventList");
502 delete[] errorSquareds;
514 const std::string &propertyValue,
int perioidNum) {
515 if (propertyName ==
"Append") {
516 if (perioidNum != 1) {
529 auto nexusFile = std::make_shared<Mantid::Nexus::NexusFileIO>();
536 if (!workspaces.empty()) {
537 for (
size_t entry = 0; entry < workspaces.size(); entry++) {
540 throw std::runtime_error(
"NeXus files do not "
541 "support nested groups of groups");
543 this->
doExec(ws, nexusFile, entry > 0 , entry);
548 nexusFile->closeNexusFile();
560 const std::vector<int> &wsIndices,
563 std::vector<int32_t> detector_index;
564 std::vector<int32_t> detector_count;
565 std::vector<int32_t> detector_list;
567 size_t nDetectors = 0;
569 const bool mappingsToWrite =
570 makeMappings(ws, wsIndices, detector_index, detector_count, detector_list, numberSpec, nDetectors);
571 if (!mappingsToWrite)
576 file->writeCompData(
"detector_index", detector_index, dims, compression, dims);
577 file->writeCompData(
"detector_count", detector_count, dims, compression, dims);
578 dims.front() =
static_cast<int>(nDetectors);
579 file->writeCompData(
"detector_list", detector_list, dims, compression, dims);
582 std::vector<double> detPos(nDetectors * 3);
587 for (
size_t i = 0; i < nDetectors; i++) {
588 double R, Theta, Phi;
593 R = det->getDistance(*sample);
603 detPos[3 * i + 1] = Theta;
604 detPos[3 * i + 2] = Phi;
607 for (
size_t i = 0; i < 3 * nDetectors; i++)
610 dims.front() =
static_cast<int>(nDetectors);
611 dims.emplace_back(3);
612 file->writeCompData(
"detector_positions", detPos, dims, compression, dims);
614 g_log.
error(
"Unknown error caught when saving detector positions.");
625 const std::vector<int> &wsIndices,
627 const auto numberSpec = int(wsIndices.size());
628 std::vector<int32_t> spectra;
629 spectra.reserve(
static_cast<size_t>(numberSpec));
630 for (
const auto index : wsIndices) {
632 spectra.emplace_back(
static_cast<int32_t
>(spectrum.getSpectrumNo()));
636 file->writeCompData(
"spectra", spectra, dims, compression, dims);
#define DECLARE_ALGORITHM(classname)
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_FOR_NO_WSP_CHECK()
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
NXcompression
The available compression types:
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
std::shared_ptr< AlgorithmHistory > m_parentHistory
Pointer to the parent history object (if set)
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
std::shared_ptr< AlgorithmHistory > m_history
Pointer to the history for the algorithm being executed.
bool isChild() const override
To query whether algorithm is a child.
virtual void setOtherProperties(IAlgorithm *alg, const std::string &propertyName, const std::string &propertyValue, int periodNum)
Virtual method to set the non workspace properties for this algorithm.
bool trackingHistory()
get whether we are tracking the history for this algorithm,
std::vector< WorkspaceVector > m_unrolledInputWorkspaces
One vector of workspaces for each input workspace property.
bool isRecordingHistoryForChild()
static size_t g_execCount
Counter to keep track of algorithm execution order.
Show a property as enabled when the workspace pointed to by another is of a given type.
Geometry::Instrument_const_sptr getInstrument() const
Returns the parameterized instrument.
@ Save
to specify a file to write to, the file may or may not exist
IAlgorithm is the interface implemented by the Algorithm base class.
const std::set< detid_t > & getDetectorIDs() const
Get a const reference to the detector IDs set.
Base MatrixWorkspace Abstract Class.
virtual ISpectrum & getSpectrum(const size_t index)=0
Return the underlying ISpectrum ptr at the given workspace index.
double detectorTwoTheta(const Geometry::IDetector &det) const
Returns the 2Theta scattering angle for a detector.
Helper class for reporting progress from algorithms.
A property class for workspaces.
DataHandling/SaveNexusProcessed.h.
static void appendEventListData(const std::vector< T > &events, size_t offset, double *tofs, float *weights, float *errorSquareds, int64_t *pulsetimes)
Append out each field of a vector of events to separate array.
DataObjects::EventWorkspace_const_sptr m_eventWorkspace
Pointer to the local workspace, cast to EventWorkspace.
void getWSIndexList(std::vector< int > &indices, const Mantid::API::MatrixWorkspace_const_sptr &matrixWorkspace)
Get the list of workspace indices to use.
void doExec(const Mantid::API::Workspace_sptr &inputWorkspace, std::shared_ptr< Mantid::Nexus::NexusFileIO > &nexusFile, const bool keepFile=false, std::optional< size_t > entryNumber=std::optional< size_t >())
virtual bool saveLegacyInstrument()
void saveSpectraDetectorMapNexus(const API::MatrixWorkspace &ws, Nexus::File *file, const std::vector< int > &wsIndices, const NXcompression compression=NXcompression::LZW) const
Save the spectra detector map to an open NeXus file.
void init() override
Overwrites Algorithm method.
double m_timeProgInit
Proportion of progress time expected to write initial part.
bool processGroups() override
Override process groups.
void execEvent(const Mantid::Nexus::NexusFileIO *nexusFile, const bool uniformSpectra, const bool raggedSpectra, const std::vector< int > &spec)
Execute the saving of event data.
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
void exec() override
Overwrites Algorithm method.
void setOtherProperties(IAlgorithm *alg, const std::string &propertyName, const std::string &propertyValue, int perioidNum) override
sets non workspace properties for the algorithm
std::unique_ptr< API::Progress > m_progress
Progress bar.
void saveSpectrumNumbersNexus(const API::MatrixWorkspace &ws, Nexus::File *file, const std::vector< int > &wsIndices, const NXcompression compression=NXcompression::LZW) const
Save the spectra numbers to an open NeXus file.
Support for a property that holds an array of values.
Records the filename and the description of failure.
Marks code as not implemented yet.
virtual void setPropertyValue(const std::string &name, const std::string &value)=0
Sets property value from a string.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void debug(const std::string &msg)
Logs at debug level.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
void reportIncrement(int inc, const std::string &msg="")
Sends the progress notification and increment the loop counter by more than one.
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
Utility methods for saving Mantid Workspaces in NeXus format.
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 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::optional< size_t > optional_size_t
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
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 IPeaksWorkspace > IPeaksWorkspace_const_sptr
shared pointer to Mantid::API::IPeaksWorkspace (const version)
EventType
What kind of event list is being stored.
Nexus::NexusFileIO::optional_size_t optional_size_t
std::shared_ptr< const OffsetsWorkspace > OffsetsWorkspace_const_sptr
shared pointer to a const OffsetsWorkspace
std::shared_ptr< const MaskWorkspace > MaskWorkspace_const_sptr
shared pointer to a const MaskWorkspace
constexpr double rad2deg
Radians to degrees conversion factor.
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
std::vector< dimsize_t > DimVector
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
@ Input
An input workspace.