diff --git a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToDetectorFaceMD.h b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToDetectorFaceMD.h index 91e045e5b714a1e289ba9c904178b4097ff6fc5b..25fd4eba41ee57726d1dc9ad2adbe3999260ee38 100644 --- a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToDetectorFaceMD.h +++ b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertToDetectorFaceMD.h @@ -3,13 +3,12 @@ #include "MantidKernel/System.h" #include "MantidAPI/Algorithm.h" -#include "MantidMDEvents/BoxControllerSettingsAlgorithm.h" #include "MantidDataObjects/EventWorkspace.h" +#include "MantidGeometry/Instrument/RectangularDetector.h" +#include "MantidMDEvents/BoxControllerSettingsAlgorithm.h" #include "MantidMDEvents/MDEventWorkspace.h" #include "MantidMDEvents/MDLeanEvent.h" -using Mantid::MDEvents::MDLeanEvent; - namespace Mantid { namespace MDAlgorithms @@ -56,9 +55,12 @@ namespace MDAlgorithms void init(); void exec(); + std::map<int, Geometry::RectangularDetector_const_sptr> getBanks(); + template <class T, class MDE, size_t nd> void convertEventList(boost::shared_ptr<Mantid::MDEvents::MDEventWorkspace<MDE, nd>> outWS, - size_t workspaceIndex, coord_t x, coord_t y, coord_t bankNum); + size_t workspaceIndex, coord_t x, coord_t y, coord_t bankNum, + uint16_t runIndex, int32_t detectorID); /// The input event workspace Mantid::DataObjects::EventWorkspace_sptr in_ws; diff --git a/Code/Mantid/Framework/MDAlgorithms/src/ConvertToDetectorFaceMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/ConvertToDetectorFaceMD.cpp index 9c47ee636df956de456a738a1c2d32e68e5efdd4..5c4733314c7941ee8676b02f507933c938ada789 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/ConvertToDetectorFaceMD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/ConvertToDetectorFaceMD.cpp @@ -92,10 +92,13 @@ namespace MDAlgorithms * @param x :: x-coordinate for all output events * @param y :: y-coordinate for all output events * @param bankNum :: coordinate for the 4th dimension (optional) + * @param detectorID :: detectorID for this event list + * @param runIndex :: index of the run, starting at 0 */ template <class T, class MDE, size_t nd> void ConvertToDetectorFaceMD::convertEventList(boost::shared_ptr<Mantid::MDEvents::MDEventWorkspace<MDE, nd>> outWS, - size_t workspaceIndex, coord_t x, coord_t y, coord_t bankNum) + size_t workspaceIndex, coord_t x, coord_t y, coord_t bankNum, + uint16_t runIndex, int32_t detectorID) { EventList & el = in_ws->getEventList(workspaceIndex); @@ -118,14 +121,13 @@ namespace MDAlgorithms if (nd == 3) { coord_t center[3] = {x, y, tof}; - out_events.push_back( MDE(float(it->weight()), float(it->errorSquared()), center) ); + out_events.push_back( MDE(float(it->weight()), float(it->errorSquared()), runIndex, detectorID, center) ); } else if (nd == 4) { coord_t center[4] = {x, y, tof, bankNum}; - out_events.push_back( MDE(float(it->weight()), float(it->errorSquared()), center) ); + out_events.push_back( MDE(float(it->weight()), float(it->errorSquared()), runIndex, detectorID, center) ); } - //TODO: 4D } // Add them to the MDEW @@ -133,6 +135,72 @@ namespace MDAlgorithms } + + //---------------------------------------------------------------------------------------------- + /** Get the list of banks, given the settings + * + * @return map with key = bank number; value = pointer to the rectangular detector + */ + std::map<int, RectangularDetector_const_sptr> ConvertToDetectorFaceMD::getBanks() + { + Instrument_const_sptr inst = in_ws->getInstrument(); + + std::vector<int> bankNums = this->getProperty("BankNumbers"); + std::sort(bankNums.begin(), bankNums.end()); + + std::map<int, RectangularDetector_const_sptr> banks; + + if (bankNums.empty()) + { + // --- Find all rectangular detectors ---- + // Get all children + std::vector<IComponent_const_sptr> comps; + inst->getChildren(comps, true); + + for (size_t i=0; i<comps.size(); i++) + { + // Retrieve it + RectangularDetector_const_sptr det = boost::dynamic_pointer_cast<const RectangularDetector>(comps[i]); + if (det) + { + std::string name = det->getName(); + if (name.size() < 5) continue; + std::string bank = name.substr(4,name.size()-4); + int bankNum; + if (Mantid::Kernel::Strings::convert(bank, bankNum)) + banks[bankNum] = det; + g_log.debug() << "Found bank " << bank << "." << std::endl; + } + } + } + else + { + // -- Find detectors using the numbers given --- + for (auto bankNum = bankNums.begin(); bankNum != bankNums.end(); bankNum++) + { + std::string bankName = "bank" + Mantid::Kernel::Strings::toString(*bankNum); + IComponent_const_sptr comp = inst->getComponentByName(bankName); + RectangularDetector_const_sptr det = boost::dynamic_pointer_cast<const RectangularDetector>(comp); + if (det) + banks[*bankNum] = det; + } + } + + for (auto bank = banks.begin(); bank != banks.end(); bank++) + { + RectangularDetector_const_sptr det = bank->second; + // Track the largest detector + if (det->xpixels() > m_numXPixels) m_numXPixels = det->xpixels(); + if (det->ypixels() > m_numYPixels) m_numYPixels = det->ypixels(); + } + + if (banks.size() == 0) + throw std::runtime_error("No RectangularDetectors with a name like 'bankXX' found in the instrument."); + + return banks; + } + + //---------------------------------------------------------------------------------------------- /** Execute the algorithm. */ @@ -148,35 +216,21 @@ namespace MDAlgorithms // Fill the map, throw if there are grouped pixels. in_ws->getDetectorIDToWorkspaceIndexVector(m_detID_to_WI, m_detID_to_WI_offset, true); - std::vector<int> bankNums = this->getProperty("BankNumbers"); - std::sort(bankNums.begin(), bankNums.end()); - Instrument_const_sptr inst = in_ws->getInstrument(); - - std::map<int, RectangularDetector_const_sptr> banks; - for (auto bankNum = bankNums.begin(); bankNum != bankNums.end(); bankNum++) - { - std::string bankName = "bank" + Mantid::Kernel::Strings::toString(*bankNum); - IComponent_const_sptr comp = inst->getComponentByName(bankName); - RectangularDetector_const_sptr det = boost::dynamic_pointer_cast<const RectangularDetector>(comp); - if (det) - { - // Track the largest detector - if (det->xpixels() > m_numXPixels) m_numXPixels = det->xpixels(); - if (det->ypixels() > m_numYPixels) m_numYPixels = det->ypixels(); - banks[*bankNum] = det; - } - } + // Get the map of the banks we'll display + std::map<int, RectangularDetector_const_sptr> banks = this->getBanks(); // Find the size in the TOF dimension double tof_min, tof_max; + Axis * ax0 = in_ws->getAxis(0); in_ws->getXMinMax(tof_min, tof_max); + if (ax0->getValue(0) < tof_min) tof_min = ax0->getValue(0); + if (ax0->getValue(ax0->length()-1) > tof_max) tof_max = ax0->getValue(ax0->length()-1); // ------------------ Build all the dimensions ---------------------------- MDHistoDimension_sptr dimX(new MDHistoDimension("x", "x", "pixel", static_cast<coord_t>(0), static_cast<coord_t>(m_numXPixels), m_numXPixels)); MDHistoDimension_sptr dimY(new MDHistoDimension("y", "y", "pixel", static_cast<coord_t>(0), static_cast<coord_t>(m_numYPixels), m_numYPixels)); - Axis * ax0 = in_ws->getAxis(0); std::string TOFname = ax0->title(); if (TOFname.empty()) TOFname = ax0->unit()->unitID(); MDHistoDimension_sptr dimTOF(new MDHistoDimension(TOFname, TOFname, ax0->unit()->label(), @@ -187,29 +241,35 @@ namespace MDAlgorithms dims.push_back(dimY); dims.push_back(dimTOF); - if (bankNums.size() > 1) + if (banks.size() > 1) { - int min = bankNums.front(); - int max = bankNums.back()+1; - MDHistoDimension_sptr dimBanks(new MDHistoDimension("bank", "bank", "Bank Number", + int min = banks.begin()->first; + int max = banks.rbegin()->first+1; + MDHistoDimension_sptr dimBanks(new MDHistoDimension("bank", "bank", "number", static_cast<coord_t>( min ), static_cast<coord_t>( max ), max-min)); dims.push_back(dimBanks); } - // Create the workspace with the right number of dimensions + // --------- Create the workspace with the right number of dimensions ---------- size_t nd = dims.size(); - IMDEventWorkspace_sptr outWS = MDEventFactory::CreateMDWorkspace(nd, "MDLeanEvent"); + IMDEventWorkspace_sptr outWS = MDEventFactory::CreateMDWorkspace(nd, "MDEvent"); outWS->initGeometry(dims); outWS->initialize(); this->setBoxController(outWS->getBoxController()); outWS->splitBox(); - MDEventWorkspace3Lean::sptr outWS3 = boost::dynamic_pointer_cast<MDEventWorkspace3Lean>(outWS); - MDEventWorkspace4Lean::sptr outWS4 = boost::dynamic_pointer_cast<MDEventWorkspace4Lean>(outWS); + MDEventWorkspace3::sptr outWS3 = boost::dynamic_pointer_cast<MDEventWorkspace3>(outWS); + MDEventWorkspace4::sptr outWS4 = boost::dynamic_pointer_cast<MDEventWorkspace4>(outWS); + + // Copy ExperimentInfo (instrument, run, sample) to the output WS + ExperimentInfo_sptr ei(in_ws->cloneExperimentInfo()); + uint16_t runIndex = outWS->addExperimentInfo(ei); - for (auto bankNum = bankNums.begin(); bankNum != bankNums.end(); bankNum++) + // ---------------- Convert each bank -------------------------------------- + for (auto it = banks.begin(); it != banks.end(); it++) { - RectangularDetector_const_sptr det = banks[*bankNum]; + int bankNum = it->first; + RectangularDetector_const_sptr det = it->second; for (int x=0; x<det->xpixels(); x++) for (int y=0; y<det->ypixels(); y++) { @@ -221,7 +281,7 @@ namespace MDAlgorithms coord_t xPos = static_cast<coord_t>(x); coord_t yPos = static_cast<coord_t>(y); - coord_t bankPos = static_cast<coord_t>(*bankNum); + coord_t bankPos = static_cast<coord_t>(bankNum); EventList & el = in_ws->getEventList(wi); @@ -231,31 +291,29 @@ namespace MDAlgorithms { case TOF: if (nd==3) - this->convertEventList<TofEvent, MDLeanEvent<3>, 3>(outWS3, wi, xPos, yPos, bankPos); + this->convertEventList<TofEvent, MDEvent<3>, 3>(outWS3, wi, xPos, yPos, bankPos, runIndex, detID); else if (nd==4) - this->convertEventList<TofEvent, MDLeanEvent<4>, 4>(outWS4, wi, xPos, yPos, bankPos); + this->convertEventList<TofEvent, MDEvent<4>, 4>(outWS4, wi, xPos, yPos, bankPos, runIndex, detID); break; case WEIGHTED: if (nd==3) - this->convertEventList<WeightedEvent, MDLeanEvent<3>, 3>(outWS3, wi, xPos, yPos, bankPos); + this->convertEventList<WeightedEvent, MDEvent<3>, 3>(outWS3, wi, xPos, yPos, bankPos, runIndex, detID); else if (nd==4) - this->convertEventList<WeightedEvent, MDLeanEvent<4>, 4>(outWS4, wi, xPos, yPos, bankPos); + this->convertEventList<WeightedEvent, MDEvent<4>, 4>(outWS4, wi, xPos, yPos, bankPos, runIndex, detID); break; case WEIGHTED_NOTIME: if (nd==3) - this->convertEventList<WeightedEventNoTime, MDLeanEvent<3>, 3>(outWS3, wi, xPos, yPos, bankPos); + this->convertEventList<WeightedEventNoTime, MDEvent<3>, 3>(outWS3, wi, xPos, yPos, bankPos, runIndex, detID); else if (nd==4) - this->convertEventList<WeightedEventNoTime, MDLeanEvent<4>, 4>(outWS4, wi, xPos, yPos, bankPos); + this->convertEventList<WeightedEventNoTime, MDEvent<4>, 4>(outWS4, wi, xPos, yPos, bankPos, runIndex, detID); break; default: throw std::runtime_error("EventList had an unexpected data type!"); } - } - } - // Create the thread pool that will run all of these. + // ---------------------- Perform all box splitting --------------- ThreadScheduler * ts = new ThreadSchedulerLargestCost(); ThreadPool tp(ts); outWS->splitAllIfNeeded(ts); diff --git a/Code/Mantid/Framework/MDAlgorithms/test/ConvertToDetectorFaceMDTest.h b/Code/Mantid/Framework/MDAlgorithms/test/ConvertToDetectorFaceMDTest.h index 2add70ecf46de31b4ed19c78c94ad94c95529073..1446747ef8ae2d7fab7b51fea35eb2a91474a979 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/ConvertToDetectorFaceMDTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/ConvertToDetectorFaceMDTest.h @@ -1,23 +1,26 @@ #ifndef MANTID_MDALGORITHMS_CONVERTTODETECTORFACEMDTEST_H_ #define MANTID_MDALGORITHMS_CONVERTTODETECTORFACEMDTEST_H_ -#include <cxxtest/TestSuite.h> -#include "MantidKernel/Timer.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidDataObjects/Events.h" +#include "MantidDataObjects/EventWorkspace.h" +#include "MantidGeometry/MDGeometry/IMDDimension.h" #include "MantidKernel/System.h" -#include <iostream> -#include <iomanip> - +#include "MantidKernel/Timer.h" #include "MantidMDAlgorithms/ConvertToDetectorFaceMD.h" -#include "MantidAPI/MatrixWorkspace.h" #include "MantidMDEvents/MDEventFactory.h" -#include "MantidDataObjects/EventWorkspace.h" #include "MantidTestHelpers/MDEventsTestHelper.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include <cxxtest/TestSuite.h> +#include <iomanip> +#include <iostream> using namespace Mantid; using namespace Mantid::MDAlgorithms; using namespace Mantid::API; using namespace Mantid::DataObjects; using namespace Mantid::MDEvents; +using Mantid::Geometry::IMDDimension_const_sptr; class ConvertToDetectorFaceMDTest : public CxxTest::TestSuite { @@ -35,48 +38,136 @@ public: TS_ASSERT( alg.isInitialized() ) } - - void do_test_MINITOPAZ(EventType type) + //---------------------------------------------------------------------------- + EventWorkspace_sptr makeTestWS(EventType type) { - - int numEventsPer = 100; - EventWorkspace_sptr in_ws = Mantid::MDEvents::MDEventsTestHelper::createDiffractionEventWorkspace(numEventsPer); - if (type == WEIGHTED) - in_ws *= 2.0; - if (type == WEIGHTED_NOTIME) + EventWorkspace_sptr in_ws = WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument(5, 10, false); + if ((type == WEIGHTED) || (type == WEIGHTED_NOTIME)) { for (size_t i =0; i<in_ws->getNumberHistograms(); i++) { EventList & el = in_ws->getEventList(i); - el.compressEvents(0.0, &el); + if (type == WEIGHTED) + el.multiply(2.0); + else + el.compressEvents(0.0, &el); } } + return in_ws; + } + + //---------------------------------------------------------------------------- + template <class WSTYPE> + boost::shared_ptr<WSTYPE> doTest(EventType type, const std::string & BankNumbers) + { + EventWorkspace_sptr in_ws = makeTestWS(type); ConvertToDetectorFaceMD alg; TS_ASSERT_THROWS_NOTHING( alg.initialize() ) TS_ASSERT( alg.isInitialized() ) alg.setProperty("InputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(in_ws) ); - alg.setPropertyValue("BankNumbers", "1"); - alg.setPropertyValue("OutputWorkspace", "test_md3"); + alg.setPropertyValue("BankNumbers", BankNumbers); + alg.setPropertyValue("OutputWorkspace", "output_md"); TS_ASSERT_THROWS_NOTHING( alg.execute(); ) TS_ASSERT( alg.isExecuted() ) - MDEventWorkspace3Lean::sptr ws; + boost::shared_ptr<WSTYPE> ws; TS_ASSERT_THROWS_NOTHING( - ws = AnalysisDataService::Instance().retrieveWS<MDEventWorkspace3Lean>("test_md3") ); + ws = AnalysisDataService::Instance().retrieveWS<WSTYPE>("output_md") ); TS_ASSERT(ws); - if (!ws) return; - size_t npoints = ws->getNPoints(); - TS_ASSERT_LESS_THAN( 100000, npoints); // Some points are left + if (!ws) return ws; - AnalysisDataService::Instance().remove("test_md3"); + for (size_t d=0; d<2; d++) + { + IMDDimension_const_sptr dim = ws->getDimension(d); + TS_ASSERT_EQUALS( dim->getName(), (d == 0 ? "x" : "y") ); + TS_ASSERT_EQUALS( dim->getNBins(), 10); + TS_ASSERT_DELTA( dim->getMinimum(), 0, 1e-5); + TS_ASSERT_DELTA( dim->getMaximum(),10, 1e-5); + TS_ASSERT_EQUALS( dim->getUnits(), "pixel"); + } + IMDDimension_const_sptr dim = ws->getDimension(2); + TS_ASSERT_EQUALS( dim->getName(), "dSpacing" ); + TS_ASSERT_EQUALS( dim->getNBins(), 101); + TS_ASSERT_DELTA( dim->getMinimum(), 0, 1e-5); + TS_ASSERT_DELTA( dim->getMaximum(), 100, 1e-5); + TS_ASSERT_EQUALS( dim->getUnits(), "Angstrom"); + + return ws; } - void test_MINITOPAZ() + + //---------------------------------------------------------------------------- + /** Run algorithm and check that it fails */ + void doTestFails(const std::string & BankNumbers) { - do_test_MINITOPAZ(TOF); + EventWorkspace_sptr in_ws = makeTestWS(TOF); + ConvertToDetectorFaceMD alg; + TS_ASSERT_THROWS_NOTHING( alg.initialize() ) + TS_ASSERT( alg.isInitialized() ) + alg.setProperty("InputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(in_ws) ); + alg.setPropertyValue("BankNumbers", BankNumbers); + alg.setPropertyValue("OutputWorkspace", "output_md"); + TS_ASSERT_THROWS_NOTHING( alg.execute(); ) + TS_ASSERT( !alg.isExecuted() ) + } + + + + //---------------------------------------------------------------------------- + void test_oneBank() + { + MDEventWorkspace3::sptr ws = doTest<MDEventWorkspace3>(TOF, "1"); + TS_ASSERT_EQUALS( ws->getNPoints(), 20000); + } + + void test_WeightedEvent() + { + MDEventWorkspace3::sptr ws3 = doTest<MDEventWorkspace3>(WEIGHTED, "1"); + TS_ASSERT_EQUALS( ws3->getNPoints(), 20000); + MDEventWorkspace4::sptr ws4 = doTest<MDEventWorkspace4>(WEIGHTED, "1,2"); + TS_ASSERT_EQUALS( ws4->getNPoints(), 20000*2); + } + void test_WeightedEventNoTime() + { + MDEventWorkspace3::sptr ws3 = doTest<MDEventWorkspace3>(WEIGHTED_NOTIME, "1"); + TS_ASSERT_EQUALS( ws3->getNPoints(), 10000); + MDEventWorkspace4::sptr ws4 = doTest<MDEventWorkspace4>(WEIGHTED_NOTIME, "1,2"); + TS_ASSERT_EQUALS( ws4->getNPoints(), 10000*2); + } + + void test_nonexistentBank_fails() + { + doTestFails("7"); + doTestFails("0"); } + //---------------------------------------------------------------------------- + void test_severalBanks() + { + MDEventWorkspace4::sptr ws = doTest<MDEventWorkspace4>(TOF, "1, 3"); + TS_ASSERT_EQUALS( ws->getNPoints(), 2*20000); + IMDDimension_const_sptr dim = ws->getDimension(3); + TS_ASSERT_EQUALS( dim->getName(), "bank" ); + TS_ASSERT_EQUALS( dim->getNBins(), 3); + TS_ASSERT_DELTA( dim->getMinimum(), 1, 1e-5); + TS_ASSERT_DELTA( dim->getMaximum(), 4, 1e-5); + TS_ASSERT_EQUALS( dim->getUnits(), "number"); + } + + /** If you do not specify a list of banks, all are used */ + void test_allBanks() + { + MDEventWorkspace4::sptr ws = doTest<MDEventWorkspace4>(TOF, ""); + TS_ASSERT_EQUALS( ws->getNPoints(), 5*20000); + IMDDimension_const_sptr dim = ws->getDimension(3); + TS_ASSERT_EQUALS( dim->getName(), "bank" ); + TS_ASSERT_EQUALS( dim->getNBins(), 5); + TS_ASSERT_DELTA( dim->getMinimum(), 1, 1e-5); + TS_ASSERT_DELTA( dim->getMaximum(), 6, 1e-5); + TS_ASSERT_EQUALS( dim->getUnits(), "number"); + } + }; diff --git a/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp index a2223ad18c343ea1fb6a874ed582190cf4853ca8..d94cc7767a223a9b64654ab357c3c68733f40516 100644 --- a/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp +++ b/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp @@ -337,7 +337,9 @@ namespace WorkspaceCreationHelper //================================================================================================================ - /** Create an Eventworkspace with an instrument that contains RectangularDetector's + /** Create an Eventworkspace with an instrument that contains RectangularDetector's. + * X axis = 100 histogrammed bins from 0.0 in steps of 1.0. + * 200 events per pixel. * * @param numBanks :: number of rectangular banks * @param numPixels :: each bank will be numPixels*numPixels @@ -347,9 +349,18 @@ namespace WorkspaceCreationHelper Mantid::DataObjects::EventWorkspace_sptr createEventWorkspaceWithFullInstrument(int numBanks, int numPixels, bool clearEvents) { Instrument_sptr inst = ComponentCreationHelper::createTestInstrumentRectangular(numBanks, numPixels); - EventWorkspace_sptr ws = CreateEventWorkspace2(numBanks*numPixels*numPixels, 10); + EventWorkspace_sptr ws = CreateEventWorkspace2(numBanks*numPixels*numPixels, 100); ws->setInstrument(inst); - ws->getAxis(0)->setUnit("dSpacing"); + + // Set the X axes + MantidVec x = ws->readX(0); + NumericAxis * ax0 = new NumericAxis(x.size()); + ax0->setUnit("dSpacing"); + for (size_t i=0; i<x.size(); i++) + ax0->setValue(i, x[i]); + ws->replaceAxis(0, ax0); + + // re-assign detector IDs to the rectangular detector int detID = numPixels*numPixels; for (int wi=0; wi< static_cast<int>(ws->getNumberHistograms()); wi++) { @@ -360,7 +371,6 @@ namespace WorkspaceCreationHelper detID++; } ws->doneAddingEventLists(); - // std::vector<int> dets = ws->getInstrument()->getDetectorIDs(); std::cout << dets.size() << " dets found " << dets[0] <<","<<dets[1]<<"\n"; return ws; }