/** * @brief IntegratePeaksCWSD::createPeakworkspace * @param peakCenter * @param mdws :: source MDEventWorkspace where the run numbers come from * @return */ DataObjects::PeaksWorkspace_sptr IntegratePeaksCWSD::createPeakworkspace(Kernel::V3D peakCenter, API::IMDEventWorkspace_sptr mdws) { g_log.notice("Create peak workspace for output ... ..."); // new peak workspace DataObjects::PeaksWorkspace_sptr peakws = boost::make_shared<DataObjects::PeaksWorkspace>(); // get number of runs size_t numruns = mdws->getNumExperimentInfo(); for (size_t i_run = 0; i_run < numruns; ++i_run) { // get experiment info for run number, instrument and peak count API::ExperimentInfo_const_sptr expinfo = mdws->getExperimentInfo(static_cast<uint16_t>(i_run)); int runnumber = expinfo->getRunNumber(); // FIXME - This is a hack for HB3A's run number issue std::map<int, double>::iterator miter = m_runPeakCountsMap.find(runnumber % 1000); double peakcount(0); if (miter != m_runPeakCountsMap.end()) { peakcount = miter->second; g_log.notice() << "[DB] Get peak count of run " << runnumber << " as " << peakcount << "\n"; } else { g_log.notice() << "[DB] Unable to find run " << runnumber << " in peak count map." << "\n"; } // Create and add a new peak to peak workspace DataObjects::Peak newpeak; try { Geometry::Instrument_const_sptr instrument = expinfo->getInstrument(); newpeak.setInstrument(instrument); newpeak.setGoniometerMatrix(expinfo->run().getGoniometerMatrix()); } catch (std::exception) { throw std::runtime_error( "Unable to set instrument and goniometer matrix."); } newpeak.setQSampleFrame(peakCenter); newpeak.setRunNumber(runnumber); newpeak.setIntensity(peakcount * m_scaleFactor); peakws->addPeak(newpeak); } g_log.notice("Peak workspace is generated.... "); return peakws; }
/** * Add the fake data to the given workspace * @param workspace A pointer to MD event workspace to fill using the object * parameters */ void FakeMD::fill(API::IMDEventWorkspace_sptr workspace) { setupDetectorCache(*workspace); CALL_MDEVENT_FUNCTION(this->addFakePeak, workspace) CALL_MDEVENT_FUNCTION(this->addFakeUniformData, workspace) // Mark that events were added, so the file back end (if any) needs updating workspace->setFileNeedsUpdating(true); }
/** * Create new MD workspace and set up its box controller using algorithm's box * controllers properties * @param targWSDescr :: Description of workspace to create * @param filebackend :: true if the workspace will have a file back end * @param filename :: file to use for file back end of workspace * @return :: Shared pointer for the created workspace */ API::IMDEventWorkspace_sptr ConvertToMD::createNewMDWorkspace(const MDWSDescription &targWSDescr, const bool filebackend, const std::string &filename) { // create new md workspace and set internal shared pointer of m_OutWSWrapper // to this workspace API::IMDEventWorkspace_sptr spws = m_OutWSWrapper->createEmptyMDWS(targWSDescr); if (!spws) { g_log.error() << "can not create target event workspace with :" << targWSDescr.nDimensions() << " dimensions\n"; throw(std::invalid_argument("can not create target workspace")); } // Build up the box controller Mantid::API::BoxController_sptr bc = m_OutWSWrapper->pWorkspace()->getBoxController(); // Build up the box controller, using the properties in // BoxControllerSettingsAlgorithm this->setBoxController(bc, m_InWS2D->getInstrument()); if (filebackend) { setupFileBackend(filename, m_OutWSWrapper->pWorkspace()); } // Check if the user want sto force a top level split or not bool topLevelSplittingChecked = this->getProperty("TopLevelSplitting"); if (topLevelSplittingChecked) { // Perform initial split with the forced settings setupTopLevelSplitting(bc); } // split boxes; spws->splitBox(); // Do we split more due to MinRecursionDepth? int minDepth = this->getProperty("MinRecursionDepth"); int maxDepth = this->getProperty("MaxRecursionDepth"); if (minDepth > maxDepth) throw std::invalid_argument( "MinRecursionDepth must be >= MaxRecursionDepth "); spws->setMinRecursionDepth(size_t(minDepth)); return spws; }
/** * Create new MD workspace and set up its box controller using algorithm's box controllers properties * @param targWSDescr * @return */ API::IMDEventWorkspace_sptr ConvertToMD::createNewMDWorkspace(const MDEvents::MDWSDescription &targWSDescr) { // create new md workspace and set internal shared pointer of m_OutWSWrapper to this workspace API::IMDEventWorkspace_sptr spws = m_OutWSWrapper->createEmptyMDWS(targWSDescr); if(!spws) { g_log.error()<<"can not create target event workspace with :"<<targWSDescr.nDimensions()<<" dimensions\n"; throw(std::invalid_argument("can not create target workspace")); } // Build up the box controller Mantid::API::BoxController_sptr bc = m_OutWSWrapper->pWorkspace()->getBoxController(); // Build up the box controller, using the properties in BoxControllerSettingsAlgorithm this->setBoxController(bc, m_InWS2D->getInstrument()); // split boxes; spws->splitBox(); // Do we split more due to MinRecursionDepth? int minDepth = this->getProperty("MinRecursionDepth"); int maxDepth = this->getProperty("MaxRecursionDepth"); if (minDepth>maxDepth) throw std::invalid_argument("MinRecursionDepth must be >= MaxRecursionDepth "); spws->setMinRecursionDepth(size_t(minDepth)); return spws; }
/** handle the input parameters and build target workspace description as function of input parameters * @param spws shared pointer to target MD workspace (just created or already existing) * @param QModReq -- mode to convert momentum * @param dEModReq -- mode to convert energy * @param otherDimNames -- the vector of additional dimensions names (if any) * @param dimMin -- the vector of minimal values for all dimensions of the workspace; on input it is copied from the algorithm parameters, on output it is defined from MD workspace of matrix workspace depending on how well input parameters are defined * @param dimMax -- the vector of maximal values for all dimensions of the workspace; is set up similarly to dimMin * @param QFrame -- in Q3D case this describes target coordinate system and is ignored in any other caste * @param convertTo_ -- The parameter describing Q-scaling transformations * @param targWSDescr -- the resulting class used to interpret all parameters together and used to describe selected transformation. */ bool ConvertToMD::buildTargetWSDescription(API::IMDEventWorkspace_sptr spws,const std::string &QModReq,const std::string &dEModReq,const std::vector<std::string> &otherDimNames, std::vector<double> &dimMin, std::vector<double> &dimMax, const std::string &QFrame,const std::string &convertTo_,MDEvents::MDWSDescription &targWSDescr) { // ------- Is there need to create new output workspace? bool createNewTargetWs =doWeNeedNewTargetWorkspace(spws); if (createNewTargetWs ) { targWSDescr.m_buildingNewWorkspace = true; // find min-max dimensions values -- either take them from input parameters or identify the defaults if input parameters are not defined this->findMinMax(m_InWS2D,QModReq,dEModReq,QFrame,convertTo_,otherDimNames,dimMin,dimMax); } else // get min/max from existing MD workspace ignoring input min/max values { targWSDescr.m_buildingNewWorkspace = false; size_t NDims = spws->getNumDims(); dimMin.resize(NDims); dimMax.resize(NDims); for(size_t i=0;i<NDims;i++) { const Geometry::IMDDimension *pDim = spws->getDimension(i).get(); dimMin[i] = pDim->getMinimum(); dimMax[i] = pDim->getMaximum(); } } // verify that the number min/max values is equivalent to the number of dimensions defined by properties and min is less max targWSDescr.setMinMax(dimMin,dimMax); targWSDescr.buildFromMatrixWS(m_InWS2D,QModReq,dEModReq,otherDimNames); bool LorentzCorrections = getProperty("LorentzCorrection"); targWSDescr.setLorentsCorr(LorentzCorrections); // instantiate class, responsible for defining Mslice-type projection MDEvents::MDWSTransform MsliceProj; //identify if u,v are present among input parameters and use defaults if not std::vector<double> ut = getProperty("UProj"); std::vector<double> vt = getProperty("VProj"); std::vector<double> wt = getProperty("WProj"); try { // otherwise input uv are ignored -> later it can be modified to set ub matrix if no given, but this may over-complicate things. MsliceProj.setUVvectors(ut,vt,wt); } catch(std::invalid_argument &) { g_log.error() << "The projections are coplanar. Will use defaults [1,0,0],[0,1,0] and [0,0,1]" << std::endl; } if(createNewTargetWs) { // check if we are working in powder mode // set up target coordinate system and identify/set the (multi) dimension's names to use targWSDescr.m_RotMatrix = MsliceProj.getTransfMatrix(targWSDescr,QFrame,convertTo_); } else // user input is mainly ignored and everything is in old MD workspace { // dimensions are already build, so build MDWS description from existing workspace MDEvents::MDWSDescription oldWSDescr; oldWSDescr.buildFromMDWS(spws); // some conversion parameters can not be defined by the target workspace. They have to be retrieved from the input workspace // and derived from input parameters. oldWSDescr.setUpMissingParameters(targWSDescr); // set up target coordinate system and the dimension names/units oldWSDescr.m_RotMatrix = MsliceProj.getTransfMatrix(oldWSDescr,QFrame,convertTo_); // check inconsistencies, if the existing workspace can be used as target workspace. oldWSDescr.checkWSCorresponsMDWorkspace(targWSDescr); // reset new ws description name targWSDescr =oldWSDescr; } return createNewTargetWs; }
/** * Copy over the metadata from the input matrix workspace to output MDEventWorkspace * @param mdEventWS :: The output MDEventWorkspace where metadata are copied to. The source of the metadata is the input matrix workspace * */ void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr &mdEventWS) const { // found detector which is not a monitor to get proper bin boundaries. size_t spectra_index(0); bool dector_found(false); for(size_t i=0;i<m_InWS2D->getNumberHistograms(); ++i) { try { auto det=m_InWS2D->getDetector(i); if (!det->isMonitor()) { spectra_index=i; dector_found = true; g_log.debug()<<"Using spectra N "<<i<< " as the source of the bin boundaries for the resolution corrections \n"; break; } } catch(...) {} } if (!dector_found) g_log.warning()<<"No detectors in the workspace are associated with spectra. Using spectrum 0 trying to retrieve the bin boundaries \n"; // retrieve representative bin boundaries MantidVec binBoundaries = m_InWS2D->readX(spectra_index); // check if the boundaries transformation is necessary if (m_Convertor->getUnitConversionHelper().isUnitConverted()) { if( !dynamic_cast<DataObjects::EventWorkspace *>(m_InWS2D.get())) { g_log.information()<<" ConvertToMD converts input workspace units, but the bin boundaries are copied from the first workspace spectra. The resolution estimates can be incorrect if unit conversion depends on spectra number.\n"; UnitsConversionHelper &unitConv = m_Convertor->getUnitConversionHelper(); unitConv.updateConversion(spectra_index); for(size_t i=0;i<binBoundaries.size();i++) { binBoundaries[i] =unitConv.convertUnits(binBoundaries[i]); } } // sort bin boundaries in case if unit transformation have swapped them. if (binBoundaries[0]>binBoundaries[binBoundaries.size()-1]) { g_log.information()<<"Bin boundaries are not arranged monotonously. Sorting performed\n"; std::sort(binBoundaries.begin(),binBoundaries.end()); } } // Replacement for SpectraDetectorMap::createIDGroupsMap using the ISpectrum objects instead auto mapping = boost::make_shared<det2group_map>(); for ( size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i ) { const auto& dets = m_InWS2D->getSpectrum(i)->getDetectorIDs(); if(!dets.empty()) { std::vector<detid_t> id_vector; std::copy(dets.begin(), dets.end(), std::back_inserter(id_vector)); mapping->insert(std::make_pair(id_vector.front(), id_vector)); } } uint16_t nexpts = mdEventWS->getNumExperimentInfo(); for(uint16_t i = 0; i < nexpts; ++i) { ExperimentInfo_sptr expt = mdEventWS->getExperimentInfo(i); expt->mutableRun().storeHistogramBinBoundaries(binBoundaries); expt->cacheDetectorGroupings(*mapping); } }
/** handle the input parameters and build target workspace description as function of input parameters * @param spws shared pointer to target MD workspace (just created or already existing) * @param QModReq -- mode to convert momentum * @param dEModReq -- mode to convert energy * @param otherDimNames -- the vector of additional dimensions names (if any) * @param dimMin -- the vector of minimal values for all dimensions of the workspace; on input it is copied from the algorithm parameters, on output it is defined from MD workspace of matrix workspace depending on how well input parameters are defined * @param dimMax -- the vector of maximal values for all dimensions of the workspace; is set up similarly to dimMin * @param QFrame -- in Q3D case this describes target coordinate system and is ignored in any other case * @param convertTo_ -- The parameter describing Q-scaling transformations * @param targWSDescr -- the resulting class used to interpret all parameters together and used to describe selected transformation. */ bool ConvertToMD::buildTargetWSDescription( API::IMDEventWorkspace_sptr spws, const std::string &QModReq, const std::string &dEModReq, const std::vector<std::string> &otherDimNames, std::vector<double> &dimMin, std::vector<double> &dimMax, const std::string &QFrame, const std::string &convertTo_, MDAlgorithms::MDWSDescription &targWSDescr) { // ------- Is there need to create new output workspace? bool createNewTargetWs = doWeNeedNewTargetWorkspace(spws); std::vector<int> split_into; if (createNewTargetWs) { targWSDescr.m_buildingNewWorkspace = true; // find min-max dimensions values -- either take them from input parameters // or identify the defaults if input parameters are not defined this->findMinMax(m_InWS2D, QModReq, dEModReq, QFrame, convertTo_, otherDimNames, dimMin, dimMax); // set number of bins each dimension split into. split_into = this->getProperty("SplitInto"); } else // get min/max from existing MD workspace ignoring input min/max values { targWSDescr.m_buildingNewWorkspace = false; size_t NDims = spws->getNumDims(); dimMin.resize(NDims); dimMax.resize(NDims); split_into.resize(NDims); for (size_t i = 0; i < NDims; i++) { const Geometry::IMDDimension *pDim = spws->getDimension(i).get(); dimMin[i] = pDim->getMinimum(); dimMax[i] = pDim->getMaximum(); // number of dimension split_into[i] = static_cast<int>(pDim->getNBins()); } } // verify that the number min/max values is equivalent to the number of // dimensions defined by properties and min is less max targWSDescr.setMinMax(dimMin, dimMax); targWSDescr.buildFromMatrixWS(m_InWS2D, QModReq, dEModReq, otherDimNames); targWSDescr.setNumBins(split_into); bool LorentzCorrections = getProperty("LorentzCorrection"); targWSDescr.setLorentsCorr(LorentzCorrections); double m_AbsMin = getProperty("AbsMinQ"); targWSDescr.setAbsMin(m_AbsMin); // Set optional projections for Q3D mode MDAlgorithms::MDWSTransform MsliceProj; if (QModReq == MDTransfQ3D().transfID()) { try { // otherwise input uv are ignored -> later it can be modified to set ub // matrix if no given, but this may over-complicate things. MsliceProj.setUVvectors(getProperty("UProj"), getProperty("VProj"), getProperty("WProj")); } catch (std::invalid_argument &) { g_log.warning() << "The projections are coplanar. Will use defaults " "[1,0,0],[0,1,0] and [0,0,1]\n"; } } else { auto warnIfSet = [this](const std::string &propName) { Property *prop = this->getProperty(propName); if (!prop->isDefault()) { g_log.warning(propName + " value ignored with QDimensions != " + MDTransfQ3D().transfID()); } }; for (const auto &name : {"UProj", "VProj", "WProj"}) { warnIfSet(name); } } if (createNewTargetWs) { // check if we are working in powder mode // set up target coordinate system and identify/set the (multi) dimension's // names to use targWSDescr.m_RotMatrix = MsliceProj.getTransfMatrix(targWSDescr, QFrame, convertTo_); } else // user input is mainly ignored and everything is in old MD workspace { // dimensions are already build, so build MDWS description from existing // workspace MDAlgorithms::MDWSDescription oldWSDescr; oldWSDescr.buildFromMDWS(spws); // some conversion parameters can not be defined by the target workspace. // They have to be retrieved from the input workspace // and derived from input parameters. oldWSDescr.setUpMissingParameters(targWSDescr); // set up target coordinate system and the dimension names/units oldWSDescr.m_RotMatrix = MsliceProj.getTransfMatrix(oldWSDescr, QFrame, convertTo_); // check inconsistencies, if the existing workspace can be used as target // workspace. oldWSDescr.checkWSCorresponsMDWorkspace(targWSDescr); // reset new ws description name targWSDescr = oldWSDescr; } return createNewTargetWs; }
/** * Copy over the metadata from the input matrix workspace to output *MDEventWorkspace * @param mdEventWS :: The output MDEventWorkspace where metadata are copied to. *The source of the metadata is the input matrix workspace * */ void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr &mdEventWS) const { // found detector which is not a monitor to get proper bin boundaries. size_t spectra_index(0); bool detector_found(false); const auto &spectrumInfo = m_InWS2D->spectrumInfo(); for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) { if (spectrumInfo.hasDetectors(i) && !spectrumInfo.isMonitor(i)) { spectra_index = i; detector_found = true; g_log.debug() << "Using spectra N " << i << " as the source of the bin " "boundaries for the resolution corrections \n"; break; } } if (!detector_found) { g_log.information() << "No spectra in the workspace have detectors associated " "with them. Storing bin boundaries from first spectrum for" "resolution calculation\n"; } // retrieve representative bin boundaries auto binBoundaries = m_InWS2D->x(spectra_index); // check if the boundaries transformation is necessary if (m_Convertor->getUnitConversionHelper().isUnitConverted()) { if (!dynamic_cast<DataObjects::EventWorkspace *>(m_InWS2D.get())) { g_log.information() << " ConvertToMD converts input workspace units, but " "the bin boundaries are copied from the first " "workspace spectra. The resolution estimates can " "be incorrect if unit conversion depends on " "spectra number.\n"; UnitsConversionHelper &unitConv = m_Convertor->getUnitConversionHelper(); unitConv.updateConversion(spectra_index); for (auto &binBoundary : binBoundaries) { binBoundary = unitConv.convertUnits(binBoundary); } } // sort bin boundaries in case if unit transformation have swapped them. if (binBoundaries[0] > binBoundaries.back()) { g_log.information() << "Bin boundaries are not arranged monotonously. " "Sorting performed\n"; std::sort(binBoundaries.begin(), binBoundaries.end()); } } // Replacement for SpectraDetectorMap::createIDGroupsMap using the ISpectrum // objects instead auto mapping = boost::make_shared<det2group_map>(); for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) { const auto &dets = m_InWS2D->getSpectrum(i).getDetectorIDs(); if (!dets.empty()) mapping->emplace(*dets.begin(), dets); } // The last experiment info should always be the one that refers // to latest converting workspace. All others should have had this // information set already uint16_t nexpts = mdEventWS->getNumExperimentInfo(); if (nexpts > 0) { ExperimentInfo_sptr expt = mdEventWS->getExperimentInfo(static_cast<uint16_t>(nexpts - 1)); expt->mutableRun().storeHistogramBinBoundaries(binBoundaries.rawData()); expt->cacheDetectorGroupings(*mapping); } }