/** method does preliminary calculations of the detectors positions to convert results into k-dE space ; and places the results into static cash to be used in subsequent calls to this algorithm */ void PreprocessDetectorsToMD::processDetectorsPositions( const API::MatrixWorkspace_const_sptr &inputWS, DataObjects::TableWorkspace_sptr &targWS) { g_log.information() << "Preprocessing detector locations in a target reciprocal space\n"; // Geometry::Instrument_const_sptr instrument = inputWS->getInstrument(); // this->pBaseInstr = instrument->baseInstrument(); // Geometry::IComponent_const_sptr source = instrument->getSource(); Geometry::IComponent_const_sptr sample = instrument->getSample(); if ((!source) || (!sample)) { g_log.error() << " Instrument is not fully defined. Can not identify " "source or sample\n"; throw Kernel::Exception::InstrumentDefinitionError( "Instrument not sufficiently defined: failed to get source and/or " "sample"); } // L1 try { double L1 = source->getDistance(*sample); targWS->logs()->addProperty<double>("L1", L1, true); g_log.debug() << "Source-sample distance: " << L1 << '\n'; } catch (Kernel::Exception::NotFoundError &) { throw Kernel::Exception::InstrumentDefinitionError( "Unable to calculate source-sample distance for workspace", inputWS->getTitle()); } // Instrument name std::string InstrName = instrument->getName(); targWS->logs()->addProperty<std::string>( "InstrumentName", InstrName, true); // "The name which should unique identify current instrument"); targWS->logs()->addProperty<bool>("FakeDetectors", false, true); // get access to the workspace memory auto &sp2detMap = targWS->getColVector<size_t>("spec2detMap"); auto &detId = targWS->getColVector<int32_t>("DetectorID"); auto &detIDMap = targWS->getColVector<size_t>("detIDMap"); auto &L2 = targWS->getColVector<double>("L2"); auto &TwoTheta = targWS->getColVector<double>("TwoTheta"); auto &Azimuthal = targWS->getColVector<double>("Azimuthal"); auto &detDir = targWS->getColVector<Kernel::V3D>("DetDirections"); // Efixed; do we need one and does one exist? double Efi = targWS->getLogs()->getPropertyValueAsType<double>("Ei"); float *pEfixedArray(nullptr); const Geometry::ParameterMap &pmap = inputWS->constInstrumentParameters(); if (m_getEFixed) pEfixedArray = targWS->getColDataArray<float>("eFixed"); // check if one needs to generate masked detectors column. int *pMasksArray(nullptr); if (m_getIsMasked) pMasksArray = targWS->getColDataArray<int>("detMask"); //// progress message appearance size_t div = 100; size_t nHist = targWS->rowCount(); Mantid::API::Progress theProgress(this, 0, 1, nHist); //// Loop over the spectra uint32_t liveDetectorsCount(0); const auto &spectrumInfo = inputWS->spectrumInfo(); for (size_t i = 0; i < nHist; i++) { sp2detMap[i] = std::numeric_limits<uint64_t>::quiet_NaN(); detId[i] = std::numeric_limits<int32_t>::quiet_NaN(); detIDMap[i] = std::numeric_limits<uint64_t>::quiet_NaN(); L2[i] = std::numeric_limits<double>::quiet_NaN(); TwoTheta[i] = std::numeric_limits<double>::quiet_NaN(); Azimuthal[i] = std::numeric_limits<double>::quiet_NaN(); // detMask[i] = true; if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) continue; // if masked detectors state is not used, masked detectors just ignored; bool maskDetector = spectrumInfo.isMasked(i); if (m_getIsMasked) *(pMasksArray + liveDetectorsCount) = maskDetector ? 1 : 0; else if (maskDetector) continue; const auto &spDet = spectrumInfo.detector(i); // calculate the requested values; sp2detMap[i] = liveDetectorsCount; detId[liveDetectorsCount] = int32_t(spDet.getID()); detIDMap[liveDetectorsCount] = i; L2[liveDetectorsCount] = spectrumInfo.l2(i); double polar = spectrumInfo.twoTheta(i); double azim = spDet.getPhi(); TwoTheta[liveDetectorsCount] = polar; Azimuthal[liveDetectorsCount] = azim; double sPhi = sin(polar); double ez = cos(polar); double ex = sPhi * cos(azim); double ey = sPhi * sin(azim); detDir[liveDetectorsCount].setX(ex); detDir[liveDetectorsCount].setY(ey); detDir[liveDetectorsCount].setZ(ez); // double sinTheta=sin(0.5*polar); // this->SinThetaSq[liveDetectorsCount] = sinTheta*sinTheta; // specific code which should work and makes sense // for indirect instrument but may be deployed on any code with Ei property // defined; if (pEfixedArray) { try { Geometry::Parameter_sptr par = pmap.getRecursive(&spDet, "eFixed"); if (par) Efi = par->value<double>(); } catch (std::runtime_error &) { } // set efixed for each existing detector *(pEfixedArray + liveDetectorsCount) = static_cast<float>(Efi); } liveDetectorsCount++; if (i % div == 0) theProgress.report(i, "Preprocessing detectors"); } targWS->logs()->addProperty<uint32_t>("ActualDetectorsNum", liveDetectorsCount, true); theProgress.report(); g_log.information() << "Finished preprocessing detector locations. Found: " << liveDetectorsCount << " detectors out of: " << nHist << " histograms\n"; }
/**The method responsible for analyzing input workspace parameters and preprocessing detectors positions into reciprocal space * * @param InWS2D -- input Matrix workspace with defined instrument * @param dEModeRequested -- energy conversion mode (direct/indirect/elastic) * @param updateMasks -- if full detector positions calculations or just update masking requested * @param OutWSName -- the name for the preprocessed detectors workspace to have in the analysis data service * * @return shared pointer to the workspace with preprocessed detectors information. */ DataObjects::TableWorkspace_const_sptr ConvertToMDParent::preprocessDetectorsPositions( Mantid::API::MatrixWorkspace_const_sptr InWS2D,const std::string &dEModeRequested, bool updateMasks, const std::string & OutWSName) { DataObjects::TableWorkspace_sptr TargTableWS; Kernel::DeltaEMode::Type Emode; // Do we need to reuse output workspace bool storeInDataService(true); std::string tOutWSName(OutWSName); if(tOutWSName=="-"||tOutWSName.empty()) // TargTableWS is recalculated each time; { storeInDataService = false; tOutWSName = "ServiceTableWS"; // TODO: should be hidden? } else { storeInDataService = true; } // if output workspace exists in dataservice, we may try to use it if(storeInDataService && API::AnalysisDataService::Instance().doesExist(tOutWSName) ) { TargTableWS = API::AnalysisDataService::Instance().retrieveWS<DataObjects::TableWorkspace>(tOutWSName); // get number of all histograms (may be masked or invalid) size_t nHist = InWS2D->getNumberHistograms(); size_t nDetMap=TargTableWS->rowCount(); if(nHist==nDetMap) { // let's take at least some precaution to ensure that instrument have not changed std::string currentWSInstrumentName = InWS2D->getInstrument()->getName(); std::string oldInstrName = TargTableWS->getLogs()->getPropertyValueAsType<std::string>("InstrumentName"); if(oldInstrName==currentWSInstrumentName) { if(!updateMasks) return TargTableWS; //Target workspace with preprocessed detectors exists and seems is correct one. // We still need to update masked detectors information TargTableWS = this->runPreprocessDetectorsToMDChildUpdatingMasks(InWS2D,tOutWSName,dEModeRequested,Emode); return TargTableWS; } } else // there is a workspace in the data service with the same name but this ws is not suitable as target for this algorithm. { // Should delete this WS from the dataservice API::AnalysisDataService::Instance().remove(tOutWSName); } } // No result found in analysis data service or the result is unsatisfactory. Try to calculate target workspace. TargTableWS =this->runPreprocessDetectorsToMDChildUpdatingMasks(InWS2D,tOutWSName,dEModeRequested,Emode); if(storeInDataService) API::AnalysisDataService::Instance().addOrReplace(tOutWSName,TargTableWS); // else // TargTableWS->setName(OutWSName); // check if we got what we wanted: // in direct or indirect mode input ws has to have input energy if(Emode==Kernel::DeltaEMode::Direct||Emode==Kernel::DeltaEMode::Indirect) { double m_Ei = TargTableWS->getLogs()->getPropertyValueAsType<double>("Ei"); if(isNaN(m_Ei)) { // Direct mode needs Ei if(Emode==Kernel::DeltaEMode::Direct)throw(std::invalid_argument("Input neutron's energy has to be defined in inelastic mode ")); // Do we have at least something for Indirect? float *eFixed = TargTableWS->getColDataArray<float>("eFixed"); if(!eFixed) throw(std::invalid_argument("Input neutron's energy has to be defined in inelastic mode ")); uint32_t NDetectors = TargTableWS->getLogs()->getPropertyValueAsType<uint32_t>("ActualDetectorsNum"); for(uint32_t i=0;i<NDetectors;i++) if(isNaN(*(eFixed+i)))throw(std::invalid_argument("Undefined eFixed energy for detector N: "+boost::lexical_cast<std::string>(i))); } } return TargTableWS; }