25Kernel::Logger
g_log(
"MDBoxFlatTree");
27void EmplaceExperimentBlockNum(
const std::string &name, std::list<uint16_t> &experimentBlockNum) {
28 if (boost::starts_with(name,
"experiment")) {
30 auto num = boost::lexical_cast<uint16_t>(name.substr(10, name.size() - 10));
31 if (num < std::numeric_limits<uint16_t>::max() - 1) {
34 experimentBlockNum.emplace_back(num);
36 }
catch (boost::bad_lexical_cast &) {
42void CheckExperimentBlockNum(
const std::list<uint16_t> &experimentBlockNum) {
44 auto itr = experimentBlockNum.begin();
46 for (; itr != experimentBlockNum.end(); itr++) {
48 for (
size_t i = ic + 1; i < *itr; i++) {
50 g_log.
warning() <<
"NXS file is missing a ExperimentInfo block " << groupName
51 <<
". Workspace will be missing ExperimentInfo.\n";
74 m_nDim = int(pws->getNumDims());
76 pws->getBoxes(
m_Boxes, 1000,
false);
80 size_t maxBoxes =
m_Boxes.size();
98 bool filePositionDefined(
true);
99 for (
size_t i = 0; i < maxBoxes; i++) {
103 size_t id = Box->getID();
104 size_t numChildren = Box->getNumChildren();
120 m_BoxChildren[ic * 2 + 1] = int(Box->getChild(numChildren - 1)->getID());
135 uint64_t nPoints = Box->getNPoints();
140 filePositionDefined =
false;
146 m_Depth[ic] = int(Box->getDepth());
151 size_t newIndex =
id * size_t(
m_nDim * 2) +
d * 2;
152 m_Extents[newIndex] = Box->getExtents(
d).getMin();
153 m_Extents[newIndex + 1] = Box->getExtents(
d).getMax();
158 if (!filePositionDefined) {
159 uint64_t boxPosition(0);
160 for (
size_t i = 0; i < maxBoxes; i++) {
182 uint64_t eventsStart = 0;
184 size_t ID = mdBox->getID();
190 size_t nEvents = mdBox->getTotalDataSize();
194 mdBox->setFileBacked(eventsStart, nEvents,
false);
196 eventsStart += nEvents;
218 std::map<std::string, std::string> groupEntries;
219 hFile->getEntries(groupEntries);
222 if (groupEntries.find(
"box_structure") == groupEntries.end())
227 hFile->makeGroup(
"box_structure",
"NXdata",
true);
228 hFile->putAttr(
"version",
"1.0");
233 hFile->openGroup(
"box_structure",
"NXdata");
238 std::vector<int64_t> exents_dims(2, 0);
239 exents_dims[0] = (int64_t(maxBoxes));
240 exents_dims[1] = (
m_nDim * 2);
241 std::vector<int64_t> exents_chunk(2, 0);
242 exents_chunk[0] = int64_t(16384);
243 exents_chunk[1] = (
m_nDim * 2);
245 std::vector<int64_t> box_2_dims(2, 0);
246 box_2_dims[0] = int64_t(maxBoxes);
248 std::vector<int64_t> box_2_chunk(2, 0);
249 box_2_chunk[0] = int64_t(16384);
250 box_2_chunk[1] = (2);
254 hFile->writeExtendibleData(
"box_type",
m_BoxType);
255 hFile->writeExtendibleData(
"depth",
m_Depth);
257 hFile->writeExtendibleData(
"extents",
m_Extents, exents_dims, exents_chunk);
258 hFile->writeExtendibleData(
"box_children",
m_BoxChildren, box_2_dims, box_2_chunk);
260 hFile->writeExtendibleData(
"box_event_index",
m_BoxEventIndex, box_2_dims, box_2_chunk);
263 hFile->writeUpdatedData(
"box_type",
m_BoxType);
264 hFile->writeUpdatedData(
"depth",
m_Depth);
266 hFile->writeUpdatedData(
"extents",
m_Extents, exents_dims);
267 hFile->writeUpdatedData(
"box_children",
m_BoxChildren, box_2_dims);
269 hFile->writeUpdatedData(
"box_event_index",
m_BoxEventIndex, box_2_dims);
290 bool onlyEventInfo,
bool restoreExperimentInfo) {
306 if (restoreExperimentInfo) {
322 hFile->openGroup(
"box_structure",
"NXdata");
338 throw std::runtime_error(
"Zero boxes found. There must have been an error "
339 "reading or writing the file.");
341 hFile->readData(
"depth",
m_Depth);
351 if (
m_Depth.size() != numBoxes)
352 throw std::runtime_error(
"Incompatible size for data: depth.");
354 throw std::runtime_error(
"Incompatible size for data: inverse_volume.");
360 throw std::runtime_error(
"Incompatible size for data: box_children.");
362 throw std::runtime_error(
"Incompatible size for data: box_event_index.");
364 throw std::runtime_error(
"Incompatible size for data: box_signal_errorsquared.");
377 std::map<std::string, std::string> entries;
378 file->getEntries(entries);
379 for (uint16_t i = 0; i < ws->getNumExperimentInfo(); i++) {
382 if (entries.find(groupName) == entries.end()) {
384 file->makeGroup(groupName,
"NXgroup",
true);
385 file->putAttr(
"version", 1);
386 ei->saveExperimentInfoNexus(file);
397 ei->getInstrument()->getMinMaxDetectorIDs(min, max);
398 }
catch (std::runtime_error &) {
401 if (max > 16777216) {
402 g_log.
warning() <<
"This instrument (" << ei->getInstrument()->getName()
403 <<
") has detector IDs that are higher than can be "
404 "saved in the .NXS file as single-precision floats."
406 g_log.
warning() <<
"Detector IDs above 16777216 will not be precise. "
407 "Please contact the developers.\n";
414 std::shared_ptr<Mantid::API::MultipleExperimentInfos> mei,
416 const std::string ¤tGroup,
bool lazy) {
420 auto itNXgroup = allEntries.find(
"NXgroup");
421 const std::set<std::string> &nxGroupEntries =
422 (itNXgroup != allEntries.end()) ? itNXgroup->second : std::set<std::string>{};
424 std::list<uint16_t> experimentBlockNum;
425 for (
const std::string &entry : nxGroupEntries) {
426 if (std::count(entry.begin(), entry.end(),
'/') != 2) {
429 if (!boost::starts_with(entry,
"/" + currentGroup +
"/experiment")) {
433 const std::string name = entry.substr(entry.find(
"experiment"));
434 EmplaceExperimentBlockNum(name, experimentBlockNum);
437 experimentBlockNum.sort();
438 CheckExperimentBlockNum(experimentBlockNum);
441 auto itr = experimentBlockNum.begin();
442 for (; itr != experimentBlockNum.end(); itr++) {
445 auto ei = std::make_shared<API::FileBackedExperimentInfo>(filename, file->getPath() +
"/" + groupName);
447 mei->addExperimentInfo(ei);
449 auto ei = std::make_shared<API::ExperimentInfo>();
450 file->openGroup(groupName,
"NXgroup");
451 std::string parameterStr;
454 ei->loadExperimentInfoNexus(filename, file, parameterStr, fileInfo, file->getPath());
456 if (parameterStr.empty()) {
457 ei->populateInstrumentParameters();
459 ei->readParameterMap(parameterStr);
462 mei->addExperimentInfo(ei);
463 }
catch (std::exception &e) {
464 g_log.
information(
"Error loading section '" + groupName +
"' of nxs file.");
485 const std::shared_ptr<Mantid::API::MultipleExperimentInfos> &mei,
bool lazy) {
487 std::map<std::string, std::string> entries;
488 file->getEntries(entries);
490 std::list<uint16_t> experimentBlockNum;
491 for (
auto &entry : entries) {
492 const std::string &name = entry.first;
493 EmplaceExperimentBlockNum(name, experimentBlockNum);
496 experimentBlockNum.sort();
497 CheckExperimentBlockNum(experimentBlockNum);
499 auto itr = experimentBlockNum.begin();
500 for (; itr != experimentBlockNum.end(); itr++) {
503 auto ei = std::make_shared<API::FileBackedExperimentInfo>(filename, file->getPath() +
"/" + groupName);
505 mei->addExperimentInfo(ei);
507 auto ei = std::make_shared<API::ExperimentInfo>();
508 file->openGroup(groupName,
"NXgroup");
509 std::string parameterStr;
512 ei->loadExperimentInfoNexus(filename, file, parameterStr);
514 if (parameterStr.empty()) {
515 ei->populateInstrumentParameters();
517 ei->readParameterMap(parameterStr);
520 mei->addExperimentInfo(ei);
521 }
catch (std::exception &e) {
522 g_log.
information(
"Error loading section '" + groupName +
"' of nxs file.");
533 targetWS->copyExperimentInfos(*
m_mEI);
556 bool FileBackEnd,
bool BoxStructureOnly) {
559 Boxes.assign(numBoxes,
nullptr);
561 uint64_t totalNumEvents(0);
562 m_nDim =
static_cast<int>(bc->getNDims());
564 if (m_nDim <= 0 || m_nDim > maxNdim)
565 throw std::runtime_error(
"Workspace dimesnions are not defined properly in the box controller");
573 throw std::invalid_argument(
" Unknown event type provided for MDBoxFlatTree::restoreBoxTree");
575 for (
size_t i = 0; i < numBoxes; i++) {
584 std::vector<Mantid::Geometry::MDDimensionExtents<coord_t>> extentsVector(
m_nDim);
585 for (
size_t d = 0;
d < size_t(
m_nDim);
d++)
586 extentsVector[
d].setExtents(
static_cast<double>(
m_Extents[i *
m_nDim * 2 +
d * 2]),
597 if (BoxStructureOnly) {
615 }
else if (box_type == 2) {
626 if (vol <= FLT_EPSILON)
644 for (
size_t i = 0; i < numBoxes; i++) {
648 Boxes[i]->setChildren(Boxes, indexStart, indexEnd);
651 bc->setMaxId(numBoxes);
652 return totalNumEvents;
671 const std::string &WSEventType,
bool readOnly,
672 bool &alreadyExists) {
673 alreadyExists =
false;
674 Poco::File oldFile(fileName);
675 bool fileExists = oldFile.exists();
676 if (!fileExists && readOnly)
679 NXaccess access(NXACC_RDWR);
693 std::map<std::string, std::string> groupEntries;
695 hFile->getEntries(groupEntries);
696 if (groupEntries.find(
"MDEventWorkspace") != groupEntries.end())
700 hFile->openGroup(
"MDEventWorkspace",
"NXentry");
701 alreadyExists =
true;
703 std::string eventType;
704 if (hFile->hasAttr(
"event_type")) {
705 hFile->getAttr(
"event_type", eventType);
707 if (eventType != WSEventType)
709 "\n different from workspace type: " + WSEventType,
716 " does not have necessary attribute describing the event type used",
718 hFile->putAttr(
"event_type", WSEventType);
721 bool dimDatasetExist(
false);
722 hFile->getEntries(groupEntries);
723 if (groupEntries.find(
"dimensions") != groupEntries.end())
724 dimDatasetExist =
true;
726 if (dimDatasetExist) {
728 hFile->readData<int32_t>(
"dimensions", nFileDims);
731 if (nFileDims !=
static_cast<int32_t
>(nDims))
733 "number of dimensions then requested ",
737 nDims =
static_cast<int>(nFileDims);
740 auto nFileDim =
static_cast<int32_t
>(nDims);
742 throw std::invalid_argument(
"MDBoxFlatTree::createOrOpenMDWSgrou: "
743 "Invalid number of workspace dimensions "
744 "provided to save into file ");
747 hFile->writeData(
"dimensions", nFileDim);
756 "does not exist in the read-only file",
760 alreadyExists =
false;
761 hFile->makeGroup(
"MDEventWorkspace",
"NXentry",
true);
762 hFile->putAttr(
"event_type", WSEventType);
764 auto nDim = int32_t(nDims);
766 hFile->writeData(
"dimensions", nDim);
773 return hFile.release();
780 file->writeData(
"coordinate_system",
static_cast<uint32_t
>(ws->getSpecialCoordinateSystem()));
784 std::string m_QConvention = ws->getConvention();
785 file->putAttr(
"QConvention", m_QConvention);
788 file->writeData(
"visual_normalization",
static_cast<uint32_t
>(ws->displayNormalization()));
792 file->writeData(
"visual_normalization_histo",
static_cast<uint32_t
>(ws->displayNormalizationHisto()));
795 ws->getHistory().saveNexus(file);
802 file->putAttr(
"definition", ws->id());
803 file->putAttr(
"title", ws->getTitle());
805 size_t nDim = ws->getNumDims();
806 for (
size_t d = 0;
d < nDim;
d++) {
807 std::ostringstream mess;
808 mess <<
"dimension" <<
d;
809 file->putAttr(mess.str(), ws->getDimension(
d)->toXMLString());
822 }
catch (std::runtime_error &) {
827 }
catch (std::runtime_error &) {
838 const std::string &entry_name) {
843 saveMatrix<coord_t>(file, entry_name, matrix, ::NeXus::FLOAT32, transform->
id());
856 const std::string &tag) {
857 std::vector<T> v =
m.getVector();
859 auto nPoints =
static_cast<int>(v.size());
861 file->makeData(name, type, nPoints,
true);
863 file->putData(&v[0]);
865 file->putAttr(
"type", tag);
866 file->putAttr(
"rows",
static_cast<int>(
m.numRows()));
867 file->putAttr(
"columns",
static_cast<int>(
m.numCols()));
std::unique_ptr<::NeXus::File > file_holder_type
virtual void setSignal(const signal_t)=0
virtual coord_t getInverseVolume() const =0
virtual void calcVolume()=0
virtual void setErrorSquared(const signal_t)=0
virtual void setID(const size_t &newID)=0
sets the special id, which specify the position of this node in the chain linearly ordered nodes
virtual void setFileBacked(const uint64_t, const size_t, const bool)=0
initiate the structure responsible for swapping the box on HDD if out of memory.
static void sortObjByID(std::vector< IMDNode * > &boxes)
Static method for sorting a list of MDBoxBase pointers by their file position, ascending.
virtual void setInverseVolume(const coord_t)=0
Small class that allows a MDEventWorkspace or a MDHistoWorkspace to hold several ExperimentInfo class...
uint64_t restoreBoxTree(std::vector< API::IMDNode * > &Boxes, API::BoxController_sptr &bc, bool FileBackEnd, bool BoxStructureOnly=false)
Method recovers the interconnected box structure from the plain tree into box tree,...
std::vector< int > m_BoxChildren
Start/end children IDs.
std::vector< uint64_t > m_BoxEventIndex
Start/end indices into the list of events; 2*i – filePosition, 2*i+1 number of events in the block.
std::vector< double > m_InverseVolume
Inverse of the volume of the cell.
std::string m_eventType
name of the event type
void exportExperiment(Mantid::API::IMDEventWorkspace_sptr &targetWS)
Export existing experiment info defined in the box structure to target workspace (or other experiment...
void loadBoxStructure(const std::string &fileName, int &nDim, const std::string &EventType, bool onlyEventInfo=false, bool restoreExperimentInfo=false)
load box structure from the file, defined by file name
std::vector< double > m_BoxSignalErrorsquared
Box cached signal/error squared.
void initFlatStructure(const API::IMDEventWorkspace_sptr &pws, const std::string &fileName)
convert MDWS box structure into flat structure used for saving/loading on hdd
static void saveWSGenericInfo(::NeXus::File *const file, const API::IMDWorkspace_const_sptr &ws)
Save workspace generic info like dimension structure, history, title dimensions etc.
std::vector< API::IMDNode * > m_Boxes
linear vector of boxes;
static void saveAffineTransformMatricies(::NeXus::File *const file, const API::IMDWorkspace_const_sptr &ws)
Save the affine matrices to both directional conversions to the data.
std::vector< double > m_Extents
Min/Max extents in each dimension.
std::string m_bcXMLDescr
XML representation of the box controller.
std::vector< int > m_Depth
Recursion depth.
MDBoxFlatTree()
The constructor of the flat box tree
std::shared_ptr< API::MultipleExperimentInfos > m_mEI
shared pointer to multiple experiment info stored within the workspace
static void saveExperimentInfos(::NeXus::File *const file, const API::IMDEventWorkspace_const_sptr &ws)
Save each NEW ExperimentInfo to a spot in the file.
static void loadExperimentInfos(::NeXus::File *const file, const std::string &filename, std::shared_ptr< API::MultipleExperimentInfos > mei, const Mantid::Kernel::NexusHDF5Descriptor &fileInfo, const std::string ¤tGroup, bool lazy=false)
void saveBoxStructure(const std::string &fileName)
Save flat box structure into a file, defined by the file name.
::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...
void setBoxesFilePositions(bool setFileBacked)
static void saveAffineTransformMatrix(::NeXus::File *const file, API::CoordTransform const *transform, const std::string &entry_name)
Extract and save the requested affine matrix.
std::vector< int > m_BoxType
Box type (0=None, 1=MDBox, 2=MDGridBox.
BoxType
enum defines fifferent box types generated by createBox factory We will use typecast from integer to ...
static size_t getMaxNumDim()
Returns max number of MD dimensions allowed by current Mantid version.
static API::IMDNode * createBox(size_t nDimensions, BoxType Type, API::BoxController_sptr &splitter, const std::vector< Mantid::Geometry::MDDimensionExtents< coord_t > > &extentsVector=std::vector< Mantid::Geometry::MDDimensionExtents< coord_t > >(), const uint32_t depth=0, const size_t nBoxEvents=UNDEF_SIZET, const size_t boxID=UNDEF_SIZET)
Create a MDBox or MDGridBoxof the given type.
Records the filename and the description of failure.
An interface for objects that can be cached or saved to disk.
virtual uint64_t getFilePosition() const
void debug(const std::string &msg)
Logs at debug level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
std::string str() const
Convert the matrix into a simple linear string expression.
const std::map< std::string, std::set< std::string > > & getAllEntries() const noexcept
Returns a const reference of the internal map holding all entries in the NeXus HDF5 file.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< const IMDEventWorkspace > IMDEventWorkspace_const_sptr
Shared pointer to Mantid::API::IMDEventWorkspace (const version)
std::shared_ptr< const ExperimentInfo > ExperimentInfo_const_sptr
Shared pointer to const ExperimentInfo.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const IMDWorkspace > IMDWorkspace_const_sptr
Shared pointer to the IMDWorkspace base class (const version)
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
EventType
What kind of event list is being stored.
std::size_t numEvents(::NeXus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const NexusHDF5Descriptor &descriptor)
Get the number of events in the currently opened group.
void saveMatrix(::NeXus::File *const file, const std::string &name, Kernel::Matrix< T > &m, ::NeXus::NXnumtype type, const std::string &tag)
Save routine for a generic matrix.
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
std::string toString(const T &value)
Convert a number to a string.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
int32_t detid_t
Typedef for a detector ID.