diff --git a/Code/Mantid/Framework/API/src/BoxController.cpp b/Code/Mantid/Framework/API/src/BoxController.cpp index 12991f61edd6c3c06b58de580d1a8cf297bd7670..001cb4219da91c7752fe0407cdb880caff762ddd 100644 --- a/Code/Mantid/Framework/API/src/BoxController.cpp +++ b/Code/Mantid/Framework/API/src/BoxController.cpp @@ -48,6 +48,36 @@ namespace API } + + bool BoxController::operator==(const BoxController & other) const + { + if(nd != other.nd || m_maxId!=other.m_maxId || m_SplitThreshold != other.m_SplitThreshold || + m_maxDepth != other.m_maxDepth || m_numSplit != other.m_numSplit || + m_splitInto.size() != other.m_splitInto.size()|| m_numMDBoxes.size()!=other.m_numMDBoxes.size()|| + m_numMDGridBoxes.size()!=other.m_numMDGridBoxes.size() || m_maxNumMDBoxes.size()!= other.m_maxNumMDBoxes.size())return false; + + for(size_t i=0;i<m_splitInto.size();i++) + { + if(m_splitInto[i]!=other.m_splitInto[i])return false; + } + + for(size_t i=0;i<m_numMDBoxes.size();i++) + { + if(m_numMDBoxes[i]!=other.m_numMDBoxes[i])return false; + if(m_numMDGridBoxes[i]!=other.m_numMDGridBoxes[i])return false; + if(m_maxNumMDBoxes[i]!=other.m_maxNumMDBoxes[i])return false; + } + //There are number of variables which are + // 1) derived: + // Number of events sitting in the boxes which should be split but are already split up to the max depth: volatile size_t m_numEventsAtMax; + // 2) Dynamical and related to current processor and dynamical jobs allocation: + // For adding events tasks: size_t m_addingEvents_eventsPerTask; m_addingEvents_numTasksPerBlock; + // These variables are not compared here but may need to be compared in a future for some purposes. + + + return true; + } + /// Destructor BoxController::~BoxController() { diff --git a/Code/Mantid/Framework/MDEvents/CMakeLists.txt b/Code/Mantid/Framework/MDEvents/CMakeLists.txt index 66e6f45beb1fe8c96002d9ec07782b82272d1f71..1dc673da580b43440d6964f40ad1591b26d04336 100644 --- a/Code/Mantid/Framework/MDEvents/CMakeLists.txt +++ b/Code/Mantid/Framework/MDEvents/CMakeLists.txt @@ -140,6 +140,7 @@ set ( TEST_FILES MDBinTest.h MDBoxBaseTest.h MDBoxIteratorTest.h + MDBoxFlatTreeTest.h MDBoxTest.h MDBoxSaveableTest.h MDDimensionStatsTest.h diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDBoxFlatTree.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDBoxFlatTree.h index d7eed0cdc54f036b5ecf3f0f4645fe2998d76d5a..fa20bbfcb0ad582e8d6d37fd0b5383e3d5f46cb1 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDBoxFlatTree.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDBoxFlatTree.h @@ -61,7 +61,7 @@ namespace MDEvents //--------------------------------------------------------------------------------------------------------------------- /// convert MDWS box structure into flat structure used for saving/loading on hdd void initFlatStructure(API::IMDEventWorkspace_sptr pws,const std::string &fileName); - /** Method resotores the interconnected box structure in memory, namely the nodes and their connectivity*/ + uint64_t restoreBoxTree(std::vector<API::IMDNode *>&Boxes ,API::BoxController_sptr bc, bool FileBackEnd,bool NoFileInfo=false); /*** this function tries to set file positions of the boxes to @@ -70,8 +70,10 @@ namespace MDEvents /**Save flat box structure into a file, defined by the file name*/ void saveBoxStructure(const std::string &fileName); - /**load box structure from the file, defined by file name */ void loadBoxStructure(const std::string &fileName,size_t nDim,const std::string &EventType,bool onlyEventInfo=false); + + /// Return number of dimensions this class is initiated for (or not initiated if -1) + int getNDims()const{return m_nDim;} protected: // for testing private: /**Load flat box structure from a nexus file*/ diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventFactory.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventFactory.h index 6e4cd0ee561f726066ac807715dc80894a406f4a..b8e8bb3472ae3dcfbf1073e33f62b0678a2109cb 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventFactory.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventFactory.h @@ -31,7 +31,7 @@ namespace Mantid class DLLExport MDEventFactory { - /** definition which states how many dimensions to generate. + /** definition which states how many dimensions to generate. This defines the number of dimensions in MD wokspace supported by Mantid *IF THIS NUMBER CHANGES, ONE HAS TO RUN generate_mdevent_declarations.py located with MDEventFactory.cpp file TO REINSTANTIATE AUTOGENERATED CODE */ enum {MAX_MD_DIMENSIONS_NUM = 9}; @@ -56,7 +56,8 @@ namespace Mantid 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); - + /** Returns max number of MD dimensions allowed by current Mantid version*/ + static size_t getMaxNumDim(){return size_t(MAX_MD_DIMENSIONS_NUM);} private: typedef API::IMDNode *(*fpCreateBox)(API::BoxController * ,const std::vector<Mantid::Geometry::MDDimensionExtents<coord_t> > & , const uint32_t,const size_t ,const size_t); diff --git a/Code/Mantid/Framework/MDEvents/src/MDBoxFlatTree.cpp b/Code/Mantid/Framework/MDEvents/src/MDBoxFlatTree.cpp index b6e76f1c1e3c6b94c3e25bea71003cf181d3c246..b3aa327fbd55d992c5ad324e8d7d77b66800e284 100644 --- a/Code/Mantid/Framework/MDEvents/src/MDBoxFlatTree.cpp +++ b/Code/Mantid/Framework/MDEvents/src/MDBoxFlatTree.cpp @@ -58,6 +58,7 @@ namespace Mantid m_BoxChildren.assign(maxBoxes*2, 0); API::IMDNode *Box; + size_t ic(0); bool filePositionDefined(true); for(size_t i=0;i<maxBoxes;i++) { @@ -76,20 +77,20 @@ namespace Mantid // throw std::runtime_error("Non-sequential child ID encountered!"); // lastId = Box->getChild(i)->getId(); //} - - m_BoxType[id] = 2; - m_BoxChildren[id*2] = int(Box->getChild(0)->getID()); - m_BoxChildren[id*2+1] = int(Box->getChild(numChildren-1)->getID()); + //TODO! id != ic + m_BoxType[ic] = 2; + m_BoxChildren[ic*2] = int(Box->getChild(0)->getID()); + m_BoxChildren[ic*2+1] = int(Box->getChild(numChildren-1)->getID()); // no events but index defined -- TODO -- The proper file has to have consequent indexes for all boxes too. - m_BoxEventIndex[id*2] = 0; - m_BoxEventIndex[id*2+1] = 0; + m_BoxEventIndex[ic*2] = 0; + m_BoxEventIndex[ic*2+1] = 0; } else { - m_BoxType[id] = 1; - m_BoxChildren[id*2]=0; - m_BoxChildren[id*2+1]=0; + m_BoxType[ic] = 1; + m_BoxChildren[ic*2]=0; + m_BoxChildren[ic*2+1]=0; //MDBox<MDE,nd> * mdBox = dynamic_cast<MDBox<MDE,nd> *>(Box); //if(!mdBox) throw std::runtime_error("found unfamiliar type of box"); @@ -98,18 +99,18 @@ namespace Mantid uint64_t nPoints = Box->getNPoints(); Kernel::ISaveable *pSaver = Box->getISaveable(); if(pSaver) - m_BoxEventIndex[id*2] = pSaver->getFilePosition(); + m_BoxEventIndex[ic*2] = pSaver->getFilePosition(); else filePositionDefined = false; - m_BoxEventIndex[id*2+1] = nPoints; + m_BoxEventIndex[ic*2+1] = nPoints; } // Various bits of data about the box - m_Depth[id] = int(Box->getDepth()); - m_BoxSignalErrorsquared[id*2] = double(Box->getSignal()); - m_BoxSignalErrorsquared[id*2+1] = double(Box->getErrorSquared()); - m_InverseVolume[id] = Box->getInverseVolume(); + m_Depth[ic] = int(Box->getDepth()); + m_BoxSignalErrorsquared[ic*2] = double(Box->getSignal()); + m_BoxSignalErrorsquared[ic*2+1] = double(Box->getErrorSquared()); + m_InverseVolume[ic] = Box->getInverseVolume(); for (int d=0; d<m_nDim; d++) { size_t newIndex = id*size_t(m_nDim*2) + d*2; @@ -117,6 +118,7 @@ namespace Mantid m_Extents[newIndex+1] = Box->getExtents(d).getMax(); } + ic++; } // file postion have to be calculated afresh if(!filePositionDefined) @@ -251,6 +253,12 @@ namespace Mantid } + /**load box structure from the file, defined by file name + @param fileName :: The name of the file with the box information + @param nDim :: number of dimensions the boxes have (as load usually occurs into existing MD workspace, this parameter + use to check the correspondence between workspace and the box structire in the file + @param EventType :: "MDEvent" or "MDLeanEvent" -- describe the type of events the workspace contans, similarly to nDim, used to check the data integrity + @param onlyEventInfo :: load only box controller information and do not restore boxes thenleves and the events locations */ void MDBoxFlatTree::loadBoxStructure(const std::string &fileName,size_t nDim,const std::string &EventType,bool onlyEventInfo) { @@ -425,7 +433,15 @@ namespace Mantid } + /** Method recovers the interconnected box structure from the plain tree into box tree, recovering both boxes and their connectivity + * does the opposite to the initFlatStructure operation (the class contants remains unchanged) + @param Boxes :: the return vector of pointers to interconnected boxes. All previous pointers found in the vector will be overwritten (beware of memory loss) + @param bc :: shard pointer to the box controller, which each box uses + @param FileBackEnd :: if one should make the data file backed, namely restore/calculate the data, nesessary to obtain events file positions + @parman BoxStructureOnly :: restore box tree only ignoring information about the box events + @returns totalNumEvents :: total number of events the box structure should contain and allocated memory for. + */ uint64_t MDBoxFlatTree::restoreBoxTree(std::vector<API::IMDNode *>&Boxes,API::BoxController_sptr bc, bool FileBackEnd,bool BoxStructureOnly) { @@ -434,7 +450,8 @@ namespace Mantid uint64_t totalNumEvents(0); m_nDim = int(bc->getNDims()); - if(m_nDim<=0||m_nDim>11 )throw std::runtime_error("Workspace dimesnions are not defined properly"); + int maxNdim = int(MDEventFactory::getMaxNumDim()); + if(m_nDim<=0||m_nDim>maxNdim)throw std::runtime_error("Workspace dimesnions are not defined properly in the box controller"); int iEventType(0); if(m_eventType=="MDLeanEvent") @@ -523,7 +540,6 @@ namespace Mantid } bc->setMaxId(numBoxes); return totalNumEvents; - return 0; } /** The function to create a NeXus MD workspace group with specified events type and number of dimensions or opens the existing group, which corresponds to the input parameters. diff --git a/Code/Mantid/Framework/MDEvents/test/MDBoxFlatTreeTest.h b/Code/Mantid/Framework/MDEvents/test/MDBoxFlatTreeTest.h index 26749ab742878be8f1d34a9baee1d2cf9cb882a6..86f1bad7de41ecb9295d65d56c5e6dddab822a26 100644 --- a/Code/Mantid/Framework/MDEvents/test/MDBoxFlatTreeTest.h +++ b/Code/Mantid/Framework/MDEvents/test/MDBoxFlatTreeTest.h @@ -5,44 +5,86 @@ #include "MantidMDEvents/MDBoxFlatTree.h" #include "MantidTestHelpers/MDEventsTestHelper.h" #include "MantidMDEvents/MDLeanEvent.h" +#include "MantidAPI/BoxController.h" #include <cxxtest/TestSuite.h> +#include <Poco/File.h> using namespace Mantid; using namespace Mantid::MDEvents; -class MDEventFlatTreeTest :public CxxTest::TestSuite +class MDBoxFlatTreeTest :public CxxTest::TestSuite { -private: - - Mantid::API::IMDEventWorkspace_sptr spEw3; - public: // This pair of boilerplate methods prevent the suite being created statically // This means the constructor isn't called when running other tests - static MDEventFlatTreeTest *createSuite() { return new MDEventFlatTreeTest(); } - static void destroySuite( MDEventFlatTreeTest *suite ) { delete suite; } + static MDBoxFlatTreeTest *createSuite() { return new MDBoxFlatTreeTest (); } + static void destroySuite( MDBoxFlatTreeTest *suite ) { delete suite; } - void testInit() + MDBoxFlatTreeTest() { - MDBoxFlatTree BoxTree("aFile"); + // load dependent DLL, which are used in MDEventsTestHelper (e.g. MDAlgorithms to create MD workspace) + // Mantid::API::FrameworkManager::Instance(); + // make non-file backet mdEv workspace with 10000 events + spEw3 = MDEventsTestHelper::makeFileBackedMDEW("TestLeanEvWS", false,10000); + } + + void testFlatTreeOperations() + { + MDBoxFlatTree BoxTree; TS_ASSERT_EQUALS(0,BoxTree.getNBoxes()); - TS_ASSERT_THROWS_NOTHING((BoxTree.initFlatStructure<MDLeanEvent<3>, 3>(spEw3,"aFile"))); + TS_ASSERT_THROWS_NOTHING((BoxTree.initFlatStructure(spEw3,"aFile"))); TSM_ASSERT_EQUALS("Workspace creatrion helper should generate ws split into 1001 boxes",1001,BoxTree.getNBoxes()); - } + TS_ASSERT_THROWS_NOTHING(BoxTree.saveBoxStructure("someFile.nxs")); - MDEventFlatTreeTest() - { - // load dependent DLL, which are used in MDEventsTestHelper (e.g. MDAlgorithms to create MD workspace) -// Mantid::API::FrameworkManager::Instance(); - // make non-file backet mdEv workspace with 10000 events - spEw3 = MDEventsTestHelper::makeFileBackedMDEW("TestLeanEvWS", false,10000); + Poco::File testFile("someFile.nxs"); + TSM_ASSERT("BoxTree was not able to create test file",testFile.exists()); + + + MDBoxFlatTree BoxStoredTree; + TSM_ASSERT_THROWS("Should throw as the box data were written for lean event and now we try to retrieve full events", + BoxStoredTree.loadBoxStructure("someFile.nxs",3,"MDEvent"),std::runtime_error); + + TS_ASSERT_THROWS_NOTHING(BoxStoredTree.loadBoxStructure("someFile.nxs",3,"MDLeanEvent")); + + size_t nDim = size_t(BoxStoredTree.getNDims()); + API::BoxController_sptr new_bc = boost::shared_ptr<API::BoxController>(new API::BoxController(nDim)); + new_bc->fromXMLString(BoxStoredTree.getBCXMLdescr()); + + TSM_ASSERT("Should restore the box controller equal to the one before saving ",*(spEw3->getBoxController())==*(new_bc)); + + std::vector<API::IMDNode *>Boxes; + TS_ASSERT_THROWS_NOTHING(BoxStoredTree.restoreBoxTree(Boxes ,new_bc, false,false)); + + std::vector<API::IMDNode *>OldBoxes; + TS_ASSERT_THROWS_NOTHING(spEw3->getBoxes(OldBoxes, 1000, false)); + // just in case, should be already sorted + API::IMDNode::sortObjByID(OldBoxes); + + for(size_t i=0;i<OldBoxes.size();i++) + { + TS_ASSERT(OldBoxes[i]->getID()==Boxes[i]->getID()); + size_t numChildren = Boxes[i]->getNumChildren(); + TS_ASSERT(OldBoxes[i]->getNumChildren()==numChildren); + if(numChildren>0) + { + TS_ASSERT(OldBoxes[i]->getChild(0)->getID()==Boxes[i]->getChild(0)->getID()); + } + } + + + if(testFile.exists()) + testFile.remove(); } +private: + + Mantid::API::IMDEventWorkspace_sptr spEw3; + };