31using namespace Kernel;
33using namespace DataObjects;
58void 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();
68 numberSpec = int(ws_indices.size());
71 out_detector_index.resize(numberSpec + 1, 0);
72 out_detector_count.resize(numberSpec, 0);
73 out_detector_list.resize(numberDetectors, 0);
77 for (
int i = 0; i < numberSpec; i++) {
79 const int si = ws_indices[i];
85 const auto ndet1 =
static_cast<int>(detectorgroup.size());
88 out_detector_index[i + 1] = int32_t(out_detector_index[i] + ndet1);
89 out_detector_count[i] = int32_t(ndet1);
91 std::set<detid_t>::const_iterator it;
92 for (it = detectorgroup.begin(); it != detectorgroup.end(); ++it) {
93 out_detector_list[
id++] = int32_t(*it);
97 out_detector_index.resize(numberSpec);
107 "Name of the workspace to be saved");
109 const std::vector<std::string> fileExts{
".nxs",
".nx5",
".xml"};
111 "The name of the Nexus file to write, as a full or relative\n"
115 declareProperty(
"Title",
"", std::make_shared<NullValidator>(),
"A title to describe the saved workspace");
116 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
117 mustBePositive->setLower(0);
120 "Index number of first spectrum to write, only for single\n"
123 "Index of last spectrum to write, only for single period\n"
126 "List of spectrum numbers to write, only for single period\n"
130 "Determines whether .nxs file needs to be\n"
131 "over written or appended");
134 "For EventWorkspaces, preserve the events when saving (default).\n"
135 "If false, will save the 2D histogram version of the workspace with the "
136 "current binning parameters.");
141 "For EventWorkspaces, compress the Nexus data field (default False).\n"
142 "This will make smaller files but takes much longer.");
153 const std::vector<int> spec_list =
getProperty(
"WorkspaceIndexList");
156 const bool list = !spec_list.empty();
160 const auto numberOfHist =
static_cast<int>(matrixWorkspace->getNumberHistograms());
163 if (spec_max < spec_min || spec_max > numberOfHist - 1) {
164 g_log.
error(
"Invalid WorkspaceIndex min/max properties");
165 throw std::invalid_argument(
"Inconsistent properties defined");
167 indices.reserve(1 + spec_max - spec_min);
168 for (
int i = spec_min; i <= spec_max; i++)
169 indices.emplace_back(i);
171 for (
auto s : spec_list) {
174 if (s < spec_min || s > spec_max)
175 indices.emplace_back(s);
180 spec_min = numberOfHist - 1;
181 for (
auto s : spec_list) {
184 indices.emplace_back(s);
192 spec_max = numberOfHist - 1;
193 indices.reserve(1 + spec_max - spec_min);
194 for (
int i = spec_min; i <= spec_max; i++)
195 indices.emplace_back(i);
208 const bool PreserveEvents =
getProperty(
"PreserveEvents");
218 if (!matrixWorkspace && !tableWorkspace) {
223 if (
bool(std::dynamic_pointer_cast<const IMDEventWorkspace>(inputWorkspace)) ||
224 bool(std::dynamic_pointer_cast<const IMDHistoWorkspace>(inputWorkspace)))
228 std::stringstream msg;
229 msg <<
"Workspace \"" <<
name <<
"\" not saved because it is not of a type we can presently save.";
231 throw std::runtime_error(msg.str());
233 m_eventWorkspace = std::dynamic_pointer_cast<const EventWorkspace>(matrixWorkspace);
234 const std::string workspaceID = inputWorkspace->id();
235 if ((workspaceID.find(
"Workspace2D") == std::string::npos) &&
236 (workspaceID.find(
"RebinnedOutput") == std::string::npos) &&
237 (workspaceID.find(
"WorkspaceSingleValue") == std::string::npos) &&
238 (workspaceID.find(
"GroupingWorkspace") == std::string::npos) && !
m_eventWorkspace && !tableWorkspace &&
239 !offsetsWorkspace && !maskWorkspace)
241 "EventWorkspace, ITableWorkspace, OffsetsWorkspace, "
242 "GroupingWorkspace, or MaskWorkspace.");
255 title = inputWorkspace->getTitle();
258 const std::string wsName = inputWorkspace->getName();
263 nexusFile->resetProgress(&prog_init);
264 nexusFile->openNexusWrite(filename, entryNumber, append_to_file || keepFile);
267 if (nexusFile->writeNexusProcessedHeader(title, wsName) != 0)
273 if (matrixWorkspace) {
275 matrixWorkspace->saveExperimentInfoNexus(nexusFile->filehandle().get(),
saveLegacyInstrument());
279 const bool uniformSpectra = matrixWorkspace->isCommonBins();
280 const bool raggedSpectra = matrixWorkspace->isRaggedWorkspace();
283 std::vector<int> indices;
289 this->
execEvent(nexusFile.get(), uniformSpectra, raggedSpectra, indices);
291 std::string workspaceTypeGroupName;
292 if (offsetsWorkspace)
293 workspaceTypeGroupName =
"offsets_workspace";
294 else if (maskWorkspace)
295 workspaceTypeGroupName =
"mask_workspace";
296 else if (std::dynamic_pointer_cast<const GroupingWorkspace>(inputWorkspace))
297 workspaceTypeGroupName =
"grouping_workspace";
299 workspaceTypeGroupName =
"workspace";
301 nexusFile->writeNexusProcessedData2D(matrixWorkspace, uniformSpectra, raggedSpectra, indices,
302 workspaceTypeGroupName.c_str(),
true);
306 nexusFile->filehandle()->openGroup(
"instrument",
"NXinstrument");
307 nexusFile->filehandle()->makeGroup(
"detector",
"NXdetector",
true);
309 nexusFile->filehandle()->putAttr(
"version", 1);
312 nexusFile->filehandle()->closeGroup();
313 nexusFile->filehandle()->closeGroup();
318 if (peaksWorkspace) {
320 peaksWorkspace->saveExperimentInfoNexus(nexusFile->filehandle().get());
322 peaksWorkspace->saveNexus(nexusFile->filehandle().get());
323 }
else if (tableWorkspace) {
324 nexusFile->writeNexusTableWorkspace(tableWorkspace,
"table_workspace");
329 m_history->fillAlgorithmHistory(
this, Mantid::Types::Core::DateAndTime::getCurrentTime(), 0,
332 inputWorkspace->history().addHistory(
m_history);
340 inputWorkspace->history().saveNexus(nexusFile->filehandle().get());
341 nexusFile->closeGroup();
353 auto nexusFile = std::make_shared<Mantid::Nexus::NexusFileIO>();
356 doExec(inputWorkspace, nexusFile);
372 float *errorSquareds, int64_t *pulsetimes) {
377 const auto it = events.cbegin();
378 const auto it_end = events.cend();
382 std::transform(it, it_end, std::next(tofs, offset), [](
const T &event) {
return event.tof(); });
385 std::transform(it, it_end, std::next(weights, offset),
386 [](
const T &event) {
return static_cast<float>(
event.weight()); });
389 std::transform(it, it_end, std::next(errorSquareds, offset),
390 [](
const T &event) {
return static_cast<float>(
event.errorSquared()); });
393 std::transform(it, it_end, std::next(pulsetimes, offset),
394 [](
const T &event) {
return event.pulseTime().totalNanoseconds(); });
403 const bool raggedSpectra,
const std::vector<int> &spec) {
404 std::vector<int64_t> indices;
405 indices.reserve(spec.size() + 1);
408 for (
auto s : spec) {
409 indices.emplace_back(
index);
412 indices.emplace_back(
index);
423 double *tofs =
nullptr;
424 float *weights =
nullptr;
425 float *errorSquareds =
nullptr;
426 int64_t *pulsetimes =
nullptr;
430 bool writeTOF =
true;
431 bool writePulsetime =
false;
432 bool writeWeight =
false;
433 bool writeError =
false;
437 writePulsetime =
true;
440 writePulsetime =
true;
452 tofs =
new double[num];
454 weights =
new float[num];
456 errorSquareds =
new float[num];
458 pulsetimes =
new int64_t[num];
462 for (
int wi = 0; wi < static_cast<int>(spec.size()); wi++) {
468 size_t offset = indices[wi];
470 switch (el.getEventType()) {
475 appendEventListData(el.getWeightedEvents(), offset, tofs, weights, errorSquareds, pulsetimes);
478 appendEventListData(el.getWeightedEventsNoTime(), offset, tofs, weights, errorSquareds, pulsetimes);
481 m_progress->reportIncrement(el.getNumberEvents(),
"Copying EventList");
497 delete[] errorSquareds;
509 const std::string &propertyValue,
int perioidNum) {
510 if (propertyName ==
"Append") {
511 if (perioidNum != 1) {
524 auto nexusFile = std::make_shared<Mantid::Nexus::NexusFileIO>();
531 if (!workspaces.empty()) {
532 for (
size_t entry = 0; entry < workspaces.size(); entry++) {
535 throw std::runtime_error(
"NeXus files do not "
536 "support nested groups of groups");
538 this->
doExec(ws, nexusFile, entry > 0 , entry);
543 nexusFile->closeNexusFile();
555 const std::vector<int> &wsIndices,
558 std::vector<int32_t> detector_index;
559 std::vector<int32_t> detector_count;
560 std::vector<int32_t> detector_list;
562 size_t nDetectors = 0;
564 makeMappings(ws, wsIndices, detector_index, detector_count, detector_list, numberSpec, nDetectors);
570 file->writeCompData(
"detector_index", detector_index, dims, compression, dims);
571 file->writeCompData(
"detector_count", detector_count, dims, compression, dims);
572 dims.front() =
static_cast<int>(nDetectors);
573 file->writeCompData(
"detector_list", detector_list, dims, compression, dims);
576 std::vector<double> detPos(nDetectors * 3);
581 for (
size_t i = 0; i < nDetectors; i++) {
582 double R, Theta, Phi;
587 R = det->getDistance(*sample);
597 detPos[3 * i + 1] = Theta;
598 detPos[3 * i + 2] = Phi;
601 for (
size_t i = 0; i < 3 * nDetectors; i++)
604 dims.front() =
static_cast<int>(nDetectors);
605 dims.emplace_back(3);
606 file->writeCompData(
"detector_positions", detPos, dims, compression, dims);
608 g_log.
error(
"Unknown error caught when saving detector positions.");
619 const std::vector<int> &wsIndices,
621 const auto numberSpec = int(wsIndices.size());
622 std::vector<int32_t> spectra;
623 spectra.reserve(
static_cast<size_t>(numberSpec));
624 for (
const auto index : wsIndices) {
626 spectra.emplace_back(
static_cast<int32_t
>(spectrum.getSpectrumNo()));
630 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 const > settings)
Add a PropertySettings instance to the chain of settings for a given property.
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.