17#include "MantidNexus/NexusFile.h"
20#include <boost/scoped_ptr.hpp>
35 : m_nDims(0), m_MDEventType(), m_fileBasedTargetWS(false), m_Filenames(), m_EventLoader(), m_OutIWS(),
36 m_totalEvents(0), m_totalLoaded(0), m_fileMutex(), m_statsMutex() {}
49 std::vector<std::string> exts(1,
".nxs");
50 declareProperty(std::make_unique<MultipleFileProperty>(
"Filenames", exts),
51 "Select several MDEventWorkspace NXS files to merge "
52 "together. Files must have common box structure.");
55 "Choose a file to which to save the output workspace. \n"
56 "Optional: if specified, the workspace created will be file-backed. \n"
57 "If not, it will be created in memory.");
60 "Run the loading tasks in parallel.\n"
61 "This can be faster but might use more memory.");
64 "An output MDEventWorkspace.");
72 this->
progress(0.05,
"Loading File Info");
77 targetEventIndexes.assign(targetEventIndexes.size(), 0);
96 throw std::runtime_error(
"Inconsistent number of boxes found in file " +
m_Filenames[i] +
97 ". Cannot merge these files. Did you generate them all with "
98 "exactly the same box structure?");
102 size_t nBoxes = Boxes.size();
103 for (
size_t j = 0; j < nBoxes; j++) {
104 size_t ID = Boxes[j]->getID();
125 uint64_t eventsStart = 0;
126 for (
auto mdBox : Boxes) {
128 size_t ID = mdBox->getID();
131 if (boxType[ID] == 2)
134 uint64_t nEvents = targetEventIndexes[2 * ID + 1];
135 targetEventIndexes[ID * 2] = eventsStart;
137 mdBox->setFileBacked(eventsStart, nEvents,
false);
139 eventsStart += nEvents;
154 uint64_t nBoxEvents(0);
158 size_t ID = TargetBox->
getID();
160 nBoxEvents += numFileEvents[iw];
167 size_t ID = TargetBox->
getID();
169 if (numFileEvents[iw] == 0)
197 m_nDims =
static_cast<int>(bc->getNDims());
201 bc->setSplitThreshold(5000);
205 bc->setFileBacked(saver, outputFile);
207 g_log.
notice() <<
"Setting cache to 400 MB write.\n";
208 bc->getFileIO()->setWriteBufferSize(400000000 /
m_OutIWS->sizeofEvent());
224 m_progress = std::make_unique<Progress>(
this, 0.1, 0.9,
size_t(numBoxes));
238 DiskBuf = bc->getFileIO();
244 for (
size_t ib = 0; ib < numBoxes; ib++) {
245 auto box = boxes[ib];
252 if (box->getDataInMemorySize() > 0) {
253 box->getISaveable()->save();
254 box->clearDataFromMemory();
277 m_progress->reportIncrement(ib,
"Loading and merging box data");
281 bc->getFileIO()->flushData();
299 this->
progress(0.90,
"Refreshing Cache");
304 if (!outputFile.empty()) {
305 g_log.
notice() <<
"Starting SaveMD to update the file back-end.\n";
309 boost::scoped_ptr<Nexus::File> file(
311 this->
progress(0.94,
"Saving ws history and dimensions");
314 this->
progress(0.98,
"Saving experiment infos");
341 if (!multiFileProp) {
342 throw std::logic_error(
"Filenames property must have MultipleFileProperty type.");
346 throw std::invalid_argument(
"Must specify at least one filename.");
349 std::string outputFile =
getProperty(
"OutputFilename");
351 if (!outputFile.empty()) {
353 if (Poco::File(outputFile).
exists())
354 throw std::invalid_argument(
" File " + outputFile +
355 " already exists. Can not use existing file "
356 "as the target to MergeMD files.\n" +
357 " Use it as one of source files if you want to add MD data to it");
364 loader->setPropertyValue(
"Filename", firstFile);
365 loader->setProperty(
"MetadataOnly",
false);
366 loader->setProperty(
"BoxStructureOnly",
true);
367 loader->setProperty(
"FileBackEnd",
false);
368 loader->executeAsChildAlg();
371 auto firstWS = std::dynamic_pointer_cast<API::IMDEventWorkspace>(result);
373 throw std::runtime_error(
"Can not load MDEventWorkspace from initial file " + firstFile);
378 m_OutIWS->setFileNeedsUpdating(
false);
#define DECLARE_ALGORITHM(classname)
static std::unique_ptr< QThreadPool > tp
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Kernel::Property * getPointerToProperty(const std::string &name) const override
Get a property by name.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
This class is used by MDBox and MDGridBox in order to intelligently determine optimal behavior.
@ OptionalSave
to specify a file to write to but an empty string is
virtual void loadAndAddFrom(API::IBoxControllerIO *const, uint64_t, size_t, std::vector< coord_t > &)=0
Load the additional box data of specified size from the disk location provided using the class,...
virtual void clear()=0
Clear all contained data including precalculated averages.
virtual size_t getID() const =0
virtual void reserveMemoryForLoad(uint64_t)=0
A property to allow a user to specify multiple files to load.
A property class for workspaces.
The class responsible for saving events into nexus file using generic box controller interface Expect...
std::vector< API::IMDNode * > & getBoxes()
void initFlatStructure(const API::IMDEventWorkspace_sptr &pws, const std::string &fileName)
convert MDWS box structure into flat structure used for saving/loading on hdd
std::vector< uint64_t > & getEventIndex()
const std::vector< int > & getBoxType() const
static void saveWSGenericInfo(Mantid::Nexus::File *const file, const API::IMDWorkspace_const_sptr &ws)
Save workspace generic info like dimension structure, history, title dimensions etc.
void saveBoxStructure(const std::string &fileName)
Save flat box structure into a file, defined by the file name.
static Mantid::Nexus::File * createOrOpenMDWSgroup(const std::string &fileName, int &nDims, const std::string &WSEventType, bool readOnly, bool &alreadyExists)
The function to create a NeXus MD workspace group with specified events type and number of dimensions...
static void saveExperimentInfos(Mantid::Nexus::File *const file, const API::IMDEventWorkspace_const_sptr &ws)
Save each NEW ExperimentInfo to a spot in the file.
CPUTimer : Timer that uses the CPU time, rather than wall-clock time to measure execution time.
Buffer objects that need to be written out to disk so as to optimize writing operations.
void flushCache()
Flush out all the data in the memory; and writes out everything in the to-write cache.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void notice(const std::string &msg)
Logs at notice level.
void information(const std::string &msg)
Logs at information level.
A Thread Pool implementation that keeps a certain number of threads running (normally,...
A First-In-First-Out Thread Scheduler.
Algorithm to merge multiple MDEventWorkspaces from files that obey a common box format.
std::string m_MDEventType
string describes type of the event, stored in the workspaces.
void doExecByCloning(const Mantid::API::IMDEventWorkspace_sptr &ws, const std::string &outputFile)
Perform the merging, but clone the initial workspace and use the same splitting as its structure is e...
std::vector< std::string > m_Filenames
Files to load.
std::vector< API::IBoxControllerIO * > m_EventLoader
Vector of file handles to each input file //TODO unique?
uint64_t loadEventsFromSubBoxes(API::IMDNode *TargetBox)
Task that loads all of the events from corresponded boxes of all files that is being merged into a pa...
void finalizeOutput(const std::string &outputFile)
Now re-save the MDEventWorkspace to update the file back end.
std::unique_ptr< Mantid::API::Progress > m_progress
Progress reporter.
int m_nDims
number of workspace dimensions
~MergeMDFiles() override
Destructor.
bool m_fileBasedTargetWS
if the workspace is indeed file-based
DataObjects::MDBoxFlatTree m_BoxStruct
std::vector< DataObjects::MDBoxFlatTree > m_fileComponentsStructure
void exec() override
Run the algorithm.
Mantid::API::IMDEventWorkspace_sptr m_OutIWS
Output IMDEventWorkspace.
void clearEventLoaders()
Set to true if the output is cloned of the first one.
void init() override
Initialise the properties.
void loadBoxData()
Loads all of the box data required (no events) for later use.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< IMDWorkspace > IMDWorkspace_sptr
Shared pointer to the IMDWorkspace base class.
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
bool exists(Nexus::File &file, const std::string &name)
std::vector< T > flattenVector(const std::vector< std::vector< T > > &v)
A convenience function to "flatten" the given vector of vectors into a single vector.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
@ Output
An output workspace.