32using namespace Kernel;
34using namespace DataObjects;
59void makeMappings(
const MatrixWorkspace &ws,
const std::vector<int> &ws_indices,
60 std::vector<int32_t> &out_detector_index, std::vector<int32_t> &out_detector_count,
61 std::vector<int32_t> &out_detector_list,
int &numberSpec,
size_t &numberDetectors) {
65 std::accumulate(ws_indices.cbegin(), ws_indices.cend(),
size_t(0), [&ws](
size_t sum,
const auto &
index) {
66 return sum + ws.getSpectrum(static_cast<size_t>(index)).getDetectorIDs().size();
69 numberSpec = int(ws_indices.size());
72 out_detector_index.resize(numberSpec + 1, 0);
73 out_detector_count.resize(numberSpec, 0);
74 out_detector_list.resize(numberDetectors, 0);
78 for (
int i = 0; i < numberSpec; i++) {
80 const int si = ws_indices[i];
86 const auto ndet1 =
static_cast<int>(detectorgroup.size());
89 out_detector_index[i + 1] = int32_t(out_detector_index[i] + ndet1);
90 out_detector_count[i] = int32_t(ndet1);
92 std::set<detid_t>::const_iterator it;
93 for (it = detectorgroup.begin(); it != detectorgroup.end(); ++it) {
94 out_detector_list[
id++] = int32_t(*it);
98 out_detector_index.resize(numberSpec);
108 "Name of the workspace to be saved");
110 const std::vector<std::string> fileExts{
".nxs",
".nx5",
".xml"};
112 "The name of the Nexus file to write, as a full or relative\n"
116 declareProperty(
"Title",
"", std::make_shared<NullValidator>(),
"A title to describe the saved workspace");
117 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
118 mustBePositive->setLower(0);
121 "Index number of first spectrum to write, only for single\n"
124 "Index of last spectrum to write, only for single period\n"
127 "List of spectrum numbers to write, only for single period\n"
131 "Determines whether .nxs file needs to be\n"
132 "over written or appended");
135 "For EventWorkspaces, preserve the events when saving (default).\n"
136 "If false, will save the 2D histogram version of the workspace with the "
137 "current binning parameters.");
142 "For EventWorkspaces, compress the Nexus data field (default False).\n"
143 "This will make smaller files but takes much longer.");
154 const std::vector<int> spec_list =
getProperty(
"WorkspaceIndexList");
157 const bool list = !spec_list.empty();
161 const auto numberOfHist =
static_cast<int>(matrixWorkspace->getNumberHistograms());
164 if (spec_max < spec_min || spec_max > numberOfHist - 1) {
165 g_log.
error(
"Invalid WorkspaceIndex min/max properties");
166 throw std::invalid_argument(
"Inconsistent properties defined");
168 indices.reserve(1 + spec_max - spec_min);
169 for (
int i = spec_min; i <= spec_max; i++)
170 indices.emplace_back(i);
172 for (
auto s : spec_list) {
175 if (s < spec_min || s > spec_max)
176 indices.emplace_back(s);
181 spec_min = numberOfHist - 1;
182 for (
auto s : spec_list) {
185 indices.emplace_back(s);
193 spec_max = numberOfHist - 1;
194 indices.reserve(1 + spec_max - spec_min);
195 for (
int i = spec_min; i <= spec_max; i++)
196 indices.emplace_back(i);
209 const bool PreserveEvents =
getProperty(
"PreserveEvents");
219 if (!matrixWorkspace && !tableWorkspace) {
224 if (
bool(std::dynamic_pointer_cast<const IMDEventWorkspace>(inputWorkspace)) ||
225 bool(std::dynamic_pointer_cast<const IMDHistoWorkspace>(inputWorkspace)))
229 std::stringstream msg;
230 msg <<
"Workspace \"" <<
name <<
"\" not saved because it is not of a type we can presently save.";
232 throw std::runtime_error(msg.str());
234 m_eventWorkspace = std::dynamic_pointer_cast<const EventWorkspace>(matrixWorkspace);
235 const std::string workspaceID = inputWorkspace->id();
236 if ((workspaceID.find(
"Workspace2D") == std::string::npos) &&
237 (workspaceID.find(
"RebinnedOutput") == std::string::npos) &&
238 (workspaceID.find(
"WorkspaceSingleValue") == std::string::npos) &&
239 (workspaceID.find(
"GroupingWorkspace") == std::string::npos) && !
m_eventWorkspace && !tableWorkspace &&
240 !offsetsWorkspace && !maskWorkspace)
242 "EventWorkspace, ITableWorkspace, OffsetsWorkspace, "
243 "GroupingWorkspace, or MaskWorkspace.");
256 title = inputWorkspace->getTitle();
259 const std::string wsName = inputWorkspace->getName();
264 nexusFile->resetProgress(&prog_init);
265 nexusFile->openNexusWrite(filename, entryNumber, append_to_file || keepFile);
268 if (nexusFile->writeNexusProcessedHeader(title, wsName) != 0)
274 if (matrixWorkspace) {
276 matrixWorkspace->saveExperimentInfoNexus(nexusFile->filehandle().get(),
saveLegacyInstrument());
280 const bool uniformSpectra = matrixWorkspace->isCommonBins();
281 const bool raggedSpectra = matrixWorkspace->isRaggedWorkspace();
284 std::vector<int> indices;
290 this->
execEvent(nexusFile.get(), uniformSpectra, raggedSpectra, indices);
292 std::string workspaceTypeGroupName;
293 if (offsetsWorkspace)
294 workspaceTypeGroupName =
"offsets_workspace";
295 else if (maskWorkspace)
296 workspaceTypeGroupName =
"mask_workspace";
297 else if (std::dynamic_pointer_cast<const GroupingWorkspace>(inputWorkspace))
298 workspaceTypeGroupName =
"grouping_workspace";
300 workspaceTypeGroupName =
"workspace";
302 nexusFile->writeNexusProcessedData2D(matrixWorkspace, uniformSpectra, raggedSpectra, indices,
303 workspaceTypeGroupName.c_str(),
true);
307 nexusFile->filehandle()->openGroup(
"instrument",
"NXinstrument");
308 nexusFile->filehandle()->makeGroup(
"detector",
"NXdetector",
true);
310 nexusFile->filehandle()->putAttr(
"version", 1);
313 nexusFile->filehandle()->closeGroup();
314 nexusFile->filehandle()->closeGroup();
319 if (peaksWorkspace) {
321 peaksWorkspace->saveExperimentInfoNexus(nexusFile->filehandle().get());
323 peaksWorkspace->saveNexus(nexusFile->filehandle().get());
324 }
else if (tableWorkspace) {
325 nexusFile->writeNexusTableWorkspace(tableWorkspace,
"table_workspace");
330 m_history->fillAlgorithmHistory(
this, Mantid::Types::Core::DateAndTime::getCurrentTime(), 0,
333 inputWorkspace->history().addHistory(
m_history);
341 inputWorkspace->history().saveNexus(nexusFile->filehandle().get());
342 nexusFile->closeGroup();
354 auto nexusFile = std::make_shared<Mantid::Nexus::NexusFileIO>();
357 doExec(inputWorkspace, nexusFile);
373 float *errorSquareds, int64_t *pulsetimes) {
378 const auto it = events.cbegin();
379 const auto it_end = events.cend();
383 std::transform(it, it_end, std::next(tofs, offset), [](
const T &event) {
return event.tof(); });
386 std::transform(it, it_end, std::next(weights, offset),
387 [](
const T &event) {
return static_cast<float>(
event.weight()); });
390 std::transform(it, it_end, std::next(errorSquareds, offset),
391 [](
const T &event) {
return static_cast<float>(
event.errorSquared()); });
394 std::transform(it, it_end, std::next(pulsetimes, offset),
395 [](
const T &event) {
return event.pulseTime().totalNanoseconds(); });
404 const bool raggedSpectra,
const std::vector<int> &spec) {
405 std::vector<int64_t> indices;
406 indices.reserve(spec.size() + 1);
409 for (
auto s : spec) {
410 indices.emplace_back(
index);
413 indices.emplace_back(
index);
424 double *tofs =
nullptr;
425 float *weights =
nullptr;
426 float *errorSquareds =
nullptr;
427 int64_t *pulsetimes =
nullptr;
431 bool writeTOF =
true;
432 bool writePulsetime =
false;
433 bool writeWeight =
false;
434 bool writeError =
false;
438 writePulsetime =
true;
441 writePulsetime =
true;
453 tofs =
new double[num];
455 weights =
new float[num];
457 errorSquareds =
new float[num];
459 pulsetimes =
new int64_t[num];
463 for (
int wi = 0; wi < static_cast<int>(spec.size()); wi++) {
469 size_t offset = indices[wi];
471 switch (el.getEventType()) {
476 appendEventListData(el.getWeightedEvents(), offset, tofs, weights, errorSquareds, pulsetimes);
479 appendEventListData(el.getWeightedEventsNoTime(), offset, tofs, weights, errorSquareds, pulsetimes);
482 m_progress->reportIncrement(el.getNumberEvents(),
"Copying EventList");
498 delete[] errorSquareds;
510 const std::string &propertyValue,
int perioidNum) {
511 if (propertyName ==
"Append") {
512 if (perioidNum != 1) {
525 auto nexusFile = std::make_shared<Mantid::Nexus::NexusFileIO>();
532 if (!workspaces.empty()) {
533 for (
size_t entry = 0; entry < workspaces.size(); entry++) {
536 throw std::runtime_error(
"NeXus files do not "
537 "support nested groups of groups");
539 this->
doExec(ws, nexusFile, entry > 0 , entry);
544 nexusFile->closeNexusFile();
556 const std::vector<int> &wsIndices,
559 std::vector<int32_t> detector_index;
560 std::vector<int32_t> detector_count;
561 std::vector<int32_t> detector_list;
563 size_t nDetectors = 0;
565 makeMappings(ws, wsIndices, detector_index, detector_count, detector_list, numberSpec, nDetectors);
571 file->writeCompData(
"detector_index", detector_index, dims, compression, dims);
572 file->writeCompData(
"detector_count", detector_count, dims, compression, dims);
573 dims.front() =
static_cast<int>(nDetectors);
574 file->writeCompData(
"detector_list", detector_list, dims, compression, dims);
577 std::vector<double> detPos(nDetectors * 3);
582 for (
size_t i = 0; i < nDetectors; i++) {
583 double R, Theta, Phi;
588 R = det->getDistance(*sample);
598 detPos[3 * i + 1] = Theta;
599 detPos[3 * i + 2] = Phi;
602 for (
size_t i = 0; i < 3 * nDetectors; i++)
605 dims.front() =
static_cast<int>(nDetectors);
606 dims.emplace_back(3);
607 file->writeCompData(
"detector_positions", detPos, dims, compression, dims);
609 g_log.
error(
"Unknown error caught when saving detector positions.");
620 const std::vector<int> &wsIndices,
622 const auto numberSpec = int(wsIndices.size());
623 std::vector<int32_t> spectra;
624 spectra.reserve(
static_cast<size_t>(numberSpec));
625 for (
const auto index : wsIndices) {
627 spectra.emplace_back(
static_cast<int32_t
>(spectrum.getSpectrumNo()));
631 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.