/** method calculates fake detectors positions in the situation when real detector information has been lost */ void PreprocessDetectorsToMD::buildFakeDetectorsPositions(const API::MatrixWorkspace_const_sptr &inputWS,DataObjects::TableWorkspace_sptr &targWS) { UNUSED_ARG(inputWS); // set sample-detector position equal to 1; targWS->logs()->addProperty<double>("L1",1.,true); // targWS->logs()->addProperty<std::string>("InstrumentName","FakeInstrument",true); targWS->logs()->addProperty<bool>("FakeDetectors",true,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"); // auto &detMask = targWS->getColVector<bool>("detMask"); //// progress message appearance size_t nHist = targWS->rowCount(); targWS->logs()->addProperty<uint32_t>("ActualDetectorsNum",uint32_t(nHist),true); double polar(0); // Loop over the spectra for (size_t i = 0; i < nHist; i++) { sp2detMap[i]= i; detId[i] = (detid_t)i; detIDMap[i] = i; L2[i] = 1; TwoTheta[i] = polar; Azimuthal[i] = 0; //this->SinThetaSq[i]= 0; double ez = 1.; double ex = 0.; double ey = 0.; detDir[i].setX(ex); detDir[i].setY(ey); detDir[i].setZ(ez); } // }
/** 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( const 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) { // a direct mode instrument can be unchanged but incident energy can be // different. // It is cheap operation so we should always replace incident energy on // the target workspace bool hasEi = InWS2D->run().hasProperty("Ei"); bool hasEfix = InWS2D->run().hasProperty("eFixed"); if (hasEi || hasEfix) { double Ei; if (hasEi) Ei = InWS2D->run().getPropertyValueAsType<double>("Ei"); if (hasEfix) Ei = InWS2D->run().getPropertyValueAsType<double>("eFixed"); TargTableWS->logs()->addProperty<double>("Ei", Ei, true); } else { Emode = Kernel::DeltaEMode::fromString(dEModeRequested); if (Emode == Kernel::DeltaEMode::Direct) throw(std::invalid_argument( "Input neutron's energy has to be present at the workspace as " "Ei or eFixed number log in Direct inelastic mode")); // if(Emode==Kernel::DeltaEMode::Indirect && !hasEfix) // throw(std::invalid_argument("Input neutron's energy has to be // present at the workspace as eFixed number log in Indirect // inelastic mode")); } 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; }