/* * Sum up all the unmasked detector pixels. * * @param rebinnedWS: workspace where all the wavelength bins have been grouped together * @param sum: sum of all the unmasked detector pixels (counts) * @param error: error on sum (counts) * @param nPixels: number of unmasked detector pixels that contributed to sum */ void CalculateEfficiency::sumUnmaskedDetectors(MatrixWorkspace_sptr rebinnedWS, double& sum, double& error, int& nPixels) { // Number of spectra const int numberOfSpectra = static_cast<int>(rebinnedWS->getNumberHistograms()); sum = 0.0; error = 0.0; nPixels = 0; for (int i = 0; i < numberOfSpectra; i++) { progress(0.2+0.2*i/numberOfSpectra, "Computing sensitivity"); // Get the detector object for this spectrum IDetector_const_sptr det = rebinnedWS->getDetector(i); // If this detector is masked, skip to the next one if ( det->isMasked() ) continue; // If this detector is a monitor, skip to the next one if ( det->isMonitor() ) continue; // Retrieve the spectrum into a vector const MantidVec& YValues = rebinnedWS->readY(i); const MantidVec& YErrors = rebinnedWS->readE(i); sum += YValues[0]; error += YErrors[0]*YErrors[0]; nPixels++; } error = std::sqrt(error); }
/** Returns the detectors of interest, specified via processing instructions. * Note that this returns the names of the parent detectors of the first and * last spectrum indices in the processing instructions. It is assumed that all * the interim detectors have the same parent. * * @param instructions :: processing instructions defining detectors of interest * @param inputWS :: the input workspace * @return :: the names of the detectors of interest */ std::vector<std::string> ReflectometryReductionOneAuto2::getDetectorNames( const std::string &instructions, MatrixWorkspace_sptr inputWS) { std::vector<std::string> wsIndices; boost::split(wsIndices, instructions, boost::is_any_of(":,-+")); // vector of comopnents std::vector<std::string> detectors; try { for (const auto &wsIndex : wsIndices) { size_t index = boost::lexical_cast<size_t>(wsIndex); auto detector = inputWS->getDetector(index); auto parent = detector->getParent(); if (parent) { auto parentType = parent->type(); auto detectorName = (parentType == "Instrument") ? detector->getName() : parent->getName(); detectors.push_back(detectorName); } } } catch (boost::bad_lexical_cast &) { throw std::runtime_error("Invalid processing instructions: " + instructions); } return detectors; }
/** Execute the algorithm. */ void WeightedMeanOfWorkspace::exec() { MatrixWorkspace_sptr inputWS = this->getProperty("InputWorkspace"); // Check if it is an event workspace EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (eventW != NULL) { throw std::runtime_error("WeightedMeanOfWorkspace cannot handle EventWorkspaces!"); } // Create the output workspace MatrixWorkspace_sptr singleValued = WorkspaceFactory::Instance().create("WorkspaceSingleValue", 1, 1, 1); // Calculate weighted mean std::size_t numHists = inputWS->getNumberHistograms(); double averageValue = 0.0; double weightSum = 0.0; for (std::size_t i = 0; i < numHists; ++i) { try { IDetector_const_sptr det = inputWS->getDetector(i); if( det->isMonitor() || det->isMasked() ) { continue; } } catch (...) { // Swallow these if no instrument is found ; } MantidVec y = inputWS->dataY(i); MantidVec e = inputWS->dataE(i); double weight = 0.0; for (std::size_t j = 0; j < y.size(); ++j) { if (!boost::math::isnan(y[j]) && !boost::math::isinf(y[j]) && !boost::math::isnan(e[j]) && !boost::math::isinf(e[j])) { weight = 1.0 / (e[j] * e[j]); averageValue += (y[j] * weight); weightSum += weight; } } } singleValued->dataX(0)[0] = 0.0; singleValued->dataY(0)[0] = averageValue / weightSum; singleValued->dataE(0)[0] = std::sqrt(weightSum); this->setProperty("OutputWorkspace", singleValued); }
/** * Get the detector component. Use the name provided as a property as the basis *for the lookup as a priority. * * Throws if the name is invalid. * @param workspace : Workspace from instrument with detectors * @param isPointDetector : True if this is a point detector. Used to guess a *name. * @return The component : The component object found. */ boost::shared_ptr<const Mantid::Geometry::IComponent> SpecularReflectionAlgorithm::getDetectorComponent( MatrixWorkspace_sptr workspace, const bool isPointDetector) const { boost::shared_ptr<const IComponent> searchResult; if (!isPropertyDefault("SpectrumNumbersOfDetectors")) { const std::vector<int> spectrumNumbers = this->getProperty("SpectrumNumbersOfDetectors"); const bool strictSpectrumChecking = this->getProperty("StrictSpectrumChecking"); checkSpectrumNumbers(spectrumNumbers, strictSpectrumChecking, g_log); auto specToWorkspaceIndex = workspace->getSpectrumToWorkspaceIndexMap(); DetectorGroup_sptr allDetectors = boost::make_shared<DetectorGroup>(); const auto &spectrumInfo = workspace->spectrumInfo(); for (auto index : spectrumNumbers) { const size_t spectrumNumber{static_cast<size_t>(index)}; auto it = specToWorkspaceIndex.find(index); if (it == specToWorkspaceIndex.end()) { std::stringstream message; message << "Spectrum number " << spectrumNumber << " does not exist in the InputWorkspace"; throw std::invalid_argument(message.str()); } const size_t workspaceIndex = it->second; auto detector = workspace->getDetector(workspaceIndex); if (spectrumInfo.isMasked(workspaceIndex)) g_log.warning() << "Adding a detector (ID:" << detector->getID() << ") that is flagged as masked.\n"; allDetectors->addDetector(detector); } searchResult = allDetectors; } else { Mantid::Geometry::Instrument_const_sptr inst = workspace->getInstrument(); std::string componentToCorrect = isPointDetector ? "point-detector" : "linedetector"; if (!isPropertyDefault("DetectorComponentName")) { componentToCorrect = this->getPropertyValue("DetectorComponentName"); } searchResult = inst->getComponentByName(componentToCorrect); if (searchResult == nullptr) { throw std::invalid_argument(componentToCorrect + " does not exist. Check input properties."); } } return searchResult; }
//calculate time from sample to detector double ModeratorTzero::CalculateT2(MatrixWorkspace_sptr inputWS, size_t i) { static const double convFact = 1.0e-6*sqrt(2*PhysicalConstants::meV/PhysicalConstants::NeutronMass); double t2(-1.0); // negative initialization signals error // Get detector position IDetector_const_sptr det; try { det = inputWS->getDetector(i); } catch (Exception::NotFoundError&) { return t2; } if( det->isMonitor() ) { t2 = 0.0; //t2=0.0 since there is no sample to detector path } else { IComponent_const_sptr sample = m_instrument->getSample(); // Get final energy E_f, final velocity v_f std::vector< double > wsProp=det->getNumberParameter("Efixed"); if ( !wsProp.empty() ) { double E2 = wsProp.at(0); //[E2]=meV double v2 = convFact * sqrt(E2); //[v2]=meter/microsec try { double L2 = det->getDistance(*sample); t2 = L2 / v2; } catch (Exception::NotFoundError &) { g_log.error("Unable to calculate detector-sample distance"); throw Exception::InstrumentDefinitionError("Unable to calculate detector-sample distance", inputWS->getTitle()); } } else { g_log.debug() <<"Efixed not found for detector "<< i << std::endl; } } return t2; } // end of CalculateT2(const MatrixWorkspace_sptr inputWS, size_t i)
/** Convert a workspace to Q * * @param inputWS : The input workspace (in wavelength) to convert to Q * @return : output workspace in Q */ MatrixWorkspace_sptr ReflectometryReductionOne2::convertToQ(MatrixWorkspace_sptr inputWS) { bool const moreThanOneDetector = inputWS->getDetector(0)->nDets() > 1; bool const shouldCorrectAngle = !(*getProperty("ThetaIn")).isDefault() && !summingInQ(); if (shouldCorrectAngle && moreThanOneDetector) { if (inputWS->getNumberHistograms() > 1) { throw std::invalid_argument( "Expected a single group in " "ProcessingInstructions to be able to " "perform angle correction, found " + std::to_string(inputWS->getNumberHistograms())); } MatrixWorkspace_sptr IvsQ = inputWS->clone(); auto &XOut0 = IvsQ->mutableX(0); const auto &XIn0 = inputWS->x(0); double const theta = getProperty("ThetaIn"); double const factor = 4.0 * M_PI * sin(theta * M_PI / 180.0); std::transform(XIn0.rbegin(), XIn0.rend(), XOut0.begin(), [factor](double x) { return factor / x; }); auto &Y0 = IvsQ->mutableY(0); auto &E0 = IvsQ->mutableE(0); std::reverse(Y0.begin(), Y0.end()); std::reverse(E0.begin(), E0.end()); IvsQ->getAxis(0)->unit() = UnitFactory::Instance().create("MomentumTransfer"); return IvsQ; } else { auto convertUnits = this->createChildAlgorithm("ConvertUnits"); convertUnits->initialize(); convertUnits->setProperty("InputWorkspace", inputWS); convertUnits->setProperty("Target", "MomentumTransfer"); convertUnits->setProperty("AlignBins", false); convertUnits->execute(); MatrixWorkspace_sptr IvsQ = convertUnits->getProperty("OutputWorkspace"); return IvsQ; } }
/** Execute the algorithm. */ void LoadNXSPE::exec() { std::string filename = getProperty("Filename"); // quicly check if it's really nxspe try { ::NeXus::File file(filename); std::string mainEntry = (*(file.getEntries().begin())).first; file.openGroup(mainEntry, "NXentry"); file.openData("definition"); if (identiferConfidence(file.getStrData()) < 1) { throw std::invalid_argument("Not NXSPE"); } file.close(); } catch (...) { throw std::invalid_argument("Not NeXus or not NXSPE"); } // Load the data ::NeXus::File file(filename); std::string mainEntry = (*(file.getEntries().begin())).first; file.openGroup(mainEntry, "NXentry"); file.openGroup("NXSPE_info", "NXcollection"); std::map<std::string, std::string> entries = file.getEntries(); std::vector<double> temporary; double fixed_energy, psi = 0.; if (!entries.count("fixed_energy")) { throw std::invalid_argument("fixed_energy field was not found"); } file.openData("fixed_energy"); file.getData(temporary); fixed_energy = temporary.at(0); file.closeData(); if (entries.count("psi")) { file.openData("psi"); file.getData(temporary); psi = temporary.at(0); file.closeData(); } int kikfscaling = 0; if (entries.count("ki_over_kf_scaling")) { file.openData("ki_over_kf_scaling"); std::vector<int> temporaryint; file.getData(temporaryint); kikfscaling = temporaryint.at(0); file.closeData(); } file.closeGroup(); // NXSPE_Info file.openGroup("data", "NXdata"); entries = file.getEntries(); if (!entries.count("data")) { throw std::invalid_argument("data field was not found"); } file.openData("data"); ::NeXus::Info info = file.getInfo(); std::size_t numSpectra = static_cast<std::size_t>(info.dims.at(0)); std::size_t numBins = static_cast<std::size_t>(info.dims.at(1)); std::vector<double> data; file.getData(data); file.closeData(); if (!entries.count("error")) { throw std::invalid_argument("error field was not found"); } file.openData("error"); std::vector<double> error; file.getData(error); file.closeData(); if (!entries.count("energy")) { throw std::invalid_argument("energy field was not found"); } file.openData("energy"); std::vector<double> energies; file.getData(energies); file.closeData(); if (!entries.count("azimuthal")) { throw std::invalid_argument("azimuthal field was not found"); } file.openData("azimuthal"); std::vector<double> azimuthal; file.getData(azimuthal); file.closeData(); if (!entries.count("azimuthal_width")) { throw std::invalid_argument("azimuthal_width field was not found"); } file.openData("azimuthal_width"); std::vector<double> azimuthal_width; file.getData(azimuthal_width); file.closeData(); if (!entries.count("polar")) { throw std::invalid_argument("polar field was not found"); } file.openData("polar"); std::vector<double> polar; file.getData(polar); file.closeData(); if (!entries.count("polar_width")) { throw std::invalid_argument("polar_width field was not found"); } file.openData("polar_width"); std::vector<double> polar_width; file.getData(polar_width); file.closeData(); // distance might not have been saved in all NXSPE files std::vector<double> distance; if (entries.count("distance")) { file.openData("distance"); file.getData(distance); file.closeData(); } file.closeGroup(); // data group file.closeGroup(); // Main entry file.close(); // check if dimensions of the vectors are correct if ((error.size() != data.size()) || (azimuthal.size() != numSpectra) || (azimuthal_width.size() != numSpectra) || (polar.size() != numSpectra) || (polar_width.size() != numSpectra) || ((energies.size() != numBins) && (energies.size() != numBins + 1))) { throw std::invalid_argument( "incompatible sizes of fields in the NXSPE file"); } MatrixWorkspace_sptr outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>( WorkspaceFactory::Instance().create("Workspace2D", numSpectra, energies.size(), numBins)); // Need to get hold of the parameter map outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("DeltaE"); outputWS->setYUnit("SpectraNumber"); // add logs outputWS->mutableRun().addLogData( new PropertyWithValue<double>("Ei", fixed_energy)); outputWS->mutableRun().addLogData(new PropertyWithValue<double>("psi", psi)); outputWS->mutableRun().addLogData(new PropertyWithValue<std::string>( "ki_over_kf_scaling", kikfscaling == 1 ? "true" : "false")); // Set Goniometer Geometry::Goniometer gm; gm.pushAxis("psi", 0, 1, 0, psi); outputWS->mutableRun().setGoniometer(gm, true); // generate instrument Geometry::Instrument_sptr instrument(new Geometry::Instrument("NXSPE")); outputWS->setInstrument(instrument); Geometry::ObjComponent *source = new Geometry::ObjComponent("source"); source->setPos(0.0, 0.0, -10.0); instrument->add(source); instrument->markAsSource(source); Geometry::ObjComponent *sample = new Geometry::ObjComponent("sample"); instrument->add(sample); instrument->markAsSamplePos(sample); Geometry::Object_const_sptr cuboid( createCuboid(0.1, 0.1, 0.1)); // FIXME: memory hog on rendering. Also, // make each detector separate size for (std::size_t i = 0; i < numSpectra; ++i) { double r = 1.0; if (!distance.empty()) { r = distance.at(i); } Kernel::V3D pos; pos.spherical(r, polar.at(i), azimuthal.at(i)); Geometry::Detector *det = new Geometry::Detector("pixel", static_cast<int>(i + 1), sample); det->setPos(pos); det->setShape(cuboid); instrument->add(det); instrument->markAsDetector(det); } Geometry::ParameterMap &pmap = outputWS->instrumentParameters(); std::vector<double>::iterator itdata = data.begin(), iterror = error.begin(), itdataend, iterrorend; API::Progress prog = API::Progress(this, 0.0, 0.9, numSpectra); for (std::size_t i = 0; i < numSpectra; ++i) { itdataend = itdata + numBins; iterrorend = iterror + numBins; outputWS->dataX(i) = energies; if ((!boost::math::isfinite(*itdata)) || (*itdata <= -1e10)) // masked bin { outputWS->dataY(i) = std::vector<double>(numBins, 0); outputWS->dataE(i) = std::vector<double>(numBins, 0); pmap.addBool(outputWS->getDetector(i)->getComponentID(), "masked", true); } else { outputWS->dataY(i) = std::vector<double>(itdata, itdataend); outputWS->dataE(i) = std::vector<double>(iterror, iterrorend); } itdata = (itdataend); iterror = (iterrorend); prog.report(); } setProperty("OutputWorkspace", outputWS); }
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inOutWS = getProperty("Workspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; const MatrixWorkspace_sptr sigmaModeratorVSwavelength = getProperty("SigmaModerator"); // create interpolation table from sigmaModeratorVSwavelength Kernel::Interpolation lookUpTable; const MantidVec xInterpolate = sigmaModeratorVSwavelength->readX(0); const MantidVec yInterpolate = sigmaModeratorVSwavelength->readY(0); // prefer the input to be a pointworkspace and create interpolation function if (sigmaModeratorVSwavelength->isHistogramData()) { g_log.notice() << "mid-points of SigmaModerator histogram bins will be " "used for interpolation."; for (size_t i = 0; i < xInterpolate.size() - 1; ++i) { const double midpoint = xInterpolate[i + 1] - xInterpolate[i]; lookUpTable.addPoint(midpoint, yInterpolate[i]); } } else { for (size_t i = 0; i < xInterpolate.size(); ++i) { lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]); } } const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; try { det = inOutWS->getDetector(i); } catch (Exception::NotFoundError &) { g_log.information() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; } // If no detector found or if it's masked or a monitor, skip onto the next // spectrum if (!det || det->isMonitor() || det->isMasked()) continue; // Get the flight path from the sample to the detector pixel const V3D scatteredFlightPathV3D = det->getPos() - samplePos; const double L2 = scatteredFlightPathV3D.norm(); const double Lsum = L1 + L2; // calculate part that is wavelenght independent const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) * (3.0 * R1 * R1 / (L1 * L1) + 3.0 * R2 * R2 * Lsum * Lsum / (L1 * L1 * L2 * L2) + (deltaR * deltaR) / (L2 * L2)); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = inOutWS->detectorTwoTheta(det); const double factor = 4.0 * M_PI * sin(theta / 2.0); const MantidVec &xIn = inOutWS->readX(i); MantidVec &yIn = inOutWS->dataY(i); const size_t xLength = xIn.size(); // for each wavelenght bin of each pixel calculate a q-resolution for (size_t j = 0; j < xLength - 1; j++) { // use the midpoint of each bin const double wl = (xIn[j + 1] + xIn[j]) / 2.0; // Calculate q. Alternatively q could be calculated using ConvertUnit const double q = factor / wl; // wavelenght spread from bin assumed to be const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j]; // wavelenght spread from moderatorm, converted from microseconds to // wavelengths const double sigmaModerator = lookUpTable.value(wl) * 3.9560 / (1000.0 * Lsum); // calculate wavelenght resolution from moderator and histogram time bin const double sigmaLambda = std::sqrt(sigmaSpreadFromBin * sigmaSpreadFromBin / 12.0 + sigmaModerator * sigmaModerator); // calculate sigmaQ for a given lambda and pixel const double sigmaOverLambdaTimesQ = q * sigmaLambda / wl; const double sigmaQ = std::sqrt( dTheta2 / (wl * wl) + sigmaOverLambdaTimesQ * sigmaOverLambdaTimesQ); // update inout workspace with this sigmaQ yIn[j] = sigmaQ; } progress.report("Computing Q resolution"); } }
/** * This function handles the logic for summing RebinnedOutput workspaces. * @param outputWorkspace the workspace to hold the summed input * @param progress the progress indicator * @param numSpectra * @param numMasked * @param numZeros */ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get a copy of the input workspace MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); // First, we need to clean the input workspace for nan's and inf's in order // to treat the data correctly later. This will create a new private // workspace that will be retrieved as mutable. IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_clean"; alg->setProperty("OutputWorkspace", outName); alg->setProperty("NaNValue", 0.0); alg->setProperty("NaNError", 0.0); alg->setProperty("InfinityValue", 0.0); alg->setProperty("InfinityError", 0.0); alg->executeAsChildAlg(); MatrixWorkspace_sptr localworkspace = alg->getProperty("OutputWorkspace"); // Transform to real workspace types RebinnedOutput_sptr inWS = boost::dynamic_pointer_cast<RebinnedOutput>(localworkspace); RebinnedOutput_sptr outWS = boost::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace); // Get references to the output workspaces's data vectors ISpectrum *outSpec = outputWorkspace->getSpectrum(0); MantidVec &YSum = outSpec->dataY(); MantidVec &YError = outSpec->dataE(); MantidVec &FracSum = outWS->dataF(0); MantidVec Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(YSum.size(), 0); nZeros.assign(YSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; // Loop over spectra std::set<int>::iterator it; // for (int i = m_minSpec; i <= m_maxSpec; ++i) for (it = m_indices.begin(); it != m_indices.end(); ++it) { int i = *it; // Don't go outside the range. if ((i >= m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } try { // Get the detector object for this spectrum Geometry::IDetector_const_sptr det = localworkspace->getDetector(i); // Skip monitors, if the property is set to do so if (!m_keepMonitors && det->isMonitor()) continue; // Skip masked detectors if (det->isMasked()) { numMasked++; continue; } } catch (...) { // if the detector not found just carry on } numSpectra++; // Retrieve the spectrum into a vector const MantidVec &YValues = localworkspace->readY(i); const MantidVec &YErrors = localworkspace->readE(i); const MantidVec &FracArea = inWS->readF(i); if (m_calculateWeightedSum) { for (int k = 0; k < this->m_yLength; ++k) { if (YErrors[k] != 0) { double errsq = YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; YError[k] += errsq; Weight[k] += 1. / errsq; YSum[k] += YValues[k] * FracArea[k] / errsq; FracSum[k] += FracArea[k]; } else { nZeros[k]++; FracSum[k] += FracArea[k]; } } } else { for (int k = 0; k < this->m_yLength; ++k) { YSum[k] += YValues[k] * FracArea[k]; YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; FracSum[k] += FracArea[k]; } } // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (nZeros[i] == 0) YSum[i] *= double(numSpectra) / Weight[i]; else numZeros += nZeros[i]; } } // Create the correct representation outWS->finalize(); }
void CalculateEfficiency::normalizeDetectors(MatrixWorkspace_sptr rebinnedWS, MatrixWorkspace_sptr outputWS, double sum, double error, int nPixels, double min_eff, double max_eff) { // Number of spectra const size_t numberOfSpectra = rebinnedWS->getNumberHistograms(); // Empty vector to store the pixels that outside the acceptable efficiency range std::vector<size_t> dets_to_mask; for (size_t i = 0; i < numberOfSpectra; i++) { const double currProgress = 0.4+0.2*((double)i/(double)numberOfSpectra); progress(currProgress, "Computing sensitivity"); // Get the detector object for this spectrum IDetector_const_sptr det = rebinnedWS->getDetector(i); // If this detector is masked, skip to the next one if ( det->isMasked() ) continue; // Retrieve the spectrum into a vector const MantidVec& YIn = rebinnedWS->readY(i); const MantidVec& EIn = rebinnedWS->readE(i); MantidVec& YOut = outputWS->dataY(i); MantidVec& EOut = outputWS->dataE(i); // If this detector is a monitor, skip to the next one if ( det->isMonitor() ) { YOut[0] = 1.0; EOut[0] = 0.0; continue; } // Normalize counts to get relative efficiency YOut[0] = nPixels/sum * YIn[0]; const double err_sum = YIn[0]/sum*error; EOut[0] = nPixels/std::abs(sum) * std::sqrt(EIn[0]*EIn[0] + err_sum*err_sum); // Mask this detector if the signal is outside the acceptable band if ( !isEmpty(min_eff) && YOut[0] < min_eff ) dets_to_mask.push_back(i); if ( !isEmpty(max_eff) && YOut[0] > max_eff ) dets_to_mask.push_back(i); } // If we identified pixels to be masked, mask them now if ( !dets_to_mask.empty() ) { // Mask detectors that were found to be outside the acceptable efficiency band try { IAlgorithm_sptr mask = createChildAlgorithm("MaskDetectors", 0.8, 0.9); // First we mask detectors in the output workspace mask->setProperty<MatrixWorkspace_sptr>("Workspace", outputWS); mask->setProperty< std::vector<size_t> >("WorkspaceIndexList", dets_to_mask); mask->execute(); mask = createChildAlgorithm("MaskDetectors", 0.9, 1.0); // Then we mask the same detectors in the input workspace mask->setProperty<MatrixWorkspace_sptr>("Workspace", rebinnedWS); mask->setProperty< std::vector<size_t> >("WorkspaceIndexList", dets_to_mask); mask->execute(); } catch (std::invalid_argument& err) { std::stringstream e; e << "Invalid argument to MaskDetectors Child Algorithm: " << err.what(); g_log.error(e.str()); } catch (std::runtime_error& err) { std::stringstream e; e << "Unable to successfully run MaskDetectors Child Algorithm: " << err.what(); g_log.error(e.str()); } } }
/** Executes the algorithm. Reading in the file and creating and populating * the output workspace * * @throw std::runtime_error If the instrument cannot be loaded by the LoadInstrument ChildAlgorithm * @throw InstrumentDefinitionError Thrown if issues with the content of XML instrument file not covered by LoadInstrument * @throw std::invalid_argument If the optional properties are set to invalid values */ void LoadEmptyInstrument::exec() { // Get other properties const double detector_value = getProperty("DetectorValue"); const double monitor_value = getProperty("MonitorValue"); // load the instrument into this workspace MatrixWorkspace_sptr ws = this->runLoadInstrument(); Instrument_const_sptr instrument = ws->getInstrument(); // Get number of detectors stored in instrument const size_t number_spectra = instrument->getNumberDetectors(); // Check that we have some spectra for the workspace if( number_spectra == 0){ g_log.error("Instrument has no detectors, unable to create workspace for it"); throw Kernel::Exception::InstrumentDefinitionError("No detectors found in instrument"); } bool MakeEventWorkspace = getProperty("MakeEventWorkspace"); MatrixWorkspace_sptr outWS; if (MakeEventWorkspace) { //Make a brand new EventWorkspace EventWorkspace_sptr localWorkspace = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create("EventWorkspace", number_spectra, 2, 1)); //Copy geometry over. API::WorkspaceFactory::Instance().initializeFromParent(ws, localWorkspace, true); // Cast to matrix WS outWS = boost::dynamic_pointer_cast<MatrixWorkspace>(localWorkspace); } else { // Now create the outputworkspace and copy over the instrument object DataObjects::Workspace2D_sptr localWorkspace = boost::dynamic_pointer_cast<DataObjects::Workspace2D>(WorkspaceFactory::Instance().create(ws,number_spectra,2,1)); outWS = boost::dynamic_pointer_cast<MatrixWorkspace>(localWorkspace); } outWS->rebuildSpectraMapping( true /* include monitors */); // ---- Set the values ---------- if (!MakeEventWorkspace) { MantidVecPtr x,v,v_monitor; x.access().resize(2); x.access()[0]=1.0; x.access()[1]=2.0; v.access().resize(1); v.access()[0]=detector_value; v_monitor.access().resize(1); v_monitor.access()[0]=monitor_value; for (size_t i=0; i < outWS->getNumberHistograms(); i++) { IDetector_const_sptr det = outWS->getDetector(i); if ( det->isMonitor() ) outWS->setData(i, v_monitor, v_monitor); else outWS->setData(i, v, v); } } // Save in output this->setProperty("OutputWorkspace", outWS); }
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inOutWS = getProperty("InputWorkspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; const double sigmaModeratorMicroSec = getProperty("SigmaModerator"); const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms()); Progress progress(this,0.0,1.0,numberOfSpectra); //PARALLEL_FOR1(inOutWS) for (int i = 0; i < numberOfSpectra; i++) { //PARALLEL_START_INTERUPT_REGION IDetector_const_sptr det; try { det = inOutWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.information() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; // Catch if no detector. Next line tests whether this happened - test placed // outside here because Mac Intel compiler doesn't like 'continue' in a catch // in an openmp block. } // If no detector found or if it's masked or a monitor, skip onto the next spectrum if ( !det || det->isMonitor() || det->isMasked() ) continue; // Get the flight path from the sample to the detector pixel const V3D scatteredFlightPathV3D = det->getPos() - samplePos; const double L2 = scatteredFlightPathV3D.norm(); const double Lsum = L1+L2; // calculate part that is wavelenght independent const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) * ( 3.0*R1*R1/(L1*L1) + 3.0*R2*R2*Lsum*Lsum/(L1*L1*L2*L2) + (deltaR*deltaR)/(L2*L2) ); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = inOutWS->detectorTwoTheta(det); const double factor = 4.0 * M_PI * sin( theta/2.0 ); const MantidVec& xIn = inOutWS->readX(i); MantidVec& yIn = inOutWS->dataY(i); const size_t xLength = xIn.size(); for ( size_t j = 0; j < xLength-1; j++) { // Calculate q. Alternatively q could be calculated using ConvertUnit const double wl = (xIn[j+1]+xIn[j])/2.0; const double q = factor/wl; // calculate wavelenght resolution from moderator and histogram time bin width and // convert to from unit of micro-seconds to Aangstrom const double sigmaLambda = sigmaModeratorMicroSec*3.9560/(1000.0*Lsum); // calculate sigmaQ for a given lambda and pixel const double sigmaOverLambdaTimesQ = q*sigmaLambda/wl; const double sigmaQ = std::sqrt(dTheta2/(wl*wl)+sigmaOverLambdaTimesQ*sigmaOverLambdaTimesQ); // update inout workspace with this sigmaQ yIn[j] = sigmaQ; } progress.report("Computing Q resolution"); //PARALLEL_END_INTERUPT_REGION } }
/** * Execute the algorithm. */ void SofQW3::exec() { MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); // Do the full check for common binning if( !WorkspaceHelpers::commonBoundaries(inputWS) ) { throw std::invalid_argument("The input workspace must have common binning across all spectra"); } RebinnedOutput_sptr outputWS = this->setUpOutputWorkspace(inputWS, getProperty("QAxisBinning"), m_Qout); g_log.debug() << "Workspace type: " << outputWS->id() << std::endl; setProperty("OutputWorkspace", outputWS); const size_t nEnergyBins = inputWS->blocksize(); const size_t nHistos = inputWS->getNumberHistograms(); // Progress reports & cancellation const size_t nreports(nHistos * nEnergyBins); m_progress = boost::shared_ptr<API::Progress>(new API::Progress(this, 0.0, 1.0, nreports)); // Compute input caches this->initCachedValues(inputWS); std::vector<double> par = inputWS->getInstrument()->getNumberParameter("detector-neighbour-offset"); if (par.empty()) { // Index theta cache this->initThetaCache(inputWS); } else { g_log.debug() << "Offset: " << par[0] << std::endl; this->m_detNeighbourOffset = static_cast<int>(par[0]); this->getValuesAndWidths(inputWS); } const MantidVec & X = inputWS->readX(0); PARALLEL_FOR2(inputWS, outputWS) for (int64_t i = 0; i < static_cast<int64_t>(nHistos); ++i) // signed for openmp { PARALLEL_START_INTERUPT_REGION DetConstPtr detector = inputWS->getDetector(i); if (detector->isMasked() || detector->isMonitor()) { continue; } double theta = this->m_theta[i]; double phi = 0.0; double thetaWidth = 0.0; double phiWidth = 0.0; // Non-PSD mode if (par.empty()) { thetaWidth = this->m_thetaWidth; } // PSD mode else { phi = this->m_phi[i]; thetaWidth = this->m_thetaWidths[i]; phiWidth = this->m_phiWidths[i]; } double thetaHalfWidth = 0.5 * thetaWidth; double phiHalfWidth = 0.5 * phiWidth; const double thetaLower = theta - thetaHalfWidth; const double thetaUpper = theta + thetaHalfWidth; const double phiLower = phi - phiHalfWidth; const double phiUpper = phi + phiHalfWidth; const double efixed = this->getEFixed(detector); for(size_t j = 0; j < nEnergyBins; ++j) { m_progress->report("Computing polygon intersections"); // For each input polygon test where it intersects with // the output grid and assign the appropriate weights of Y/E const double dE_j = X[j]; const double dE_jp1 = X[j+1]; const V2D ll(dE_j, this->calculateQ(efixed, dE_j, thetaLower, phiLower)); const V2D lr(dE_jp1, this->calculateQ(efixed, dE_jp1, thetaLower, phiLower)); const V2D ur(dE_jp1, this->calculateQ(efixed, dE_jp1, thetaUpper, phiUpper)); const V2D ul(dE_j, this->calculateQ(efixed, dE_j, thetaUpper, phiUpper)); Quadrilateral inputQ = Quadrilateral(ll, lr, ur, ul); this->rebinToFractionalOutput(inputQ, inputWS, i, j, outputWS, m_Qout); } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION outputWS->finalize(); this->normaliseOutput(outputWS, inputWS); }
/** Convert a SPICE 2D Det MatrixWorkspace to MDEvents and append to an * MDEventWorkspace * It is optional to use a virtual instrument or copy from input data workspace * @brief ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents * @param dataws :: data matrix workspace * @param usevirtual :: boolean flag to use virtual instrument * @param startdetid :: starting detid for detectors from this workspace mapping * to virtual instrument in MDEventWorkspace * @param runnumber :: run number for all MDEvents created from this matrix * workspace */ void ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents( MatrixWorkspace_sptr dataws, bool usevirtual, const detid_t &startdetid, const int runnumber) { // Create transformation matrix from which the transformation is Kernel::DblMatrix rotationMatrix; setupTransferMatrix(dataws, rotationMatrix); g_log.information() << "Before insert new event, output workspace has " << m_outputWS->getNEvents() << "Events.\n"; // Creates a new instance of the MDEventInserte to output workspace MDEventWorkspace<MDEvent<3>, 3>::sptr mdws_mdevt_3 = boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>(m_outputWS); MDEventInserter<MDEventWorkspace<MDEvent<3>, 3>::sptr> inserter(mdws_mdevt_3); // Calcualte k_i: it is assumed that all k_i are same for one Pt. // number, i.e., one 2D XML file Kernel::V3D sourcePos = dataws->getInstrument()->getSource()->getPos(); Kernel::V3D samplePos = dataws->getInstrument()->getSample()->getPos(); if (dataws->readX(0).size() != 2) throw std::runtime_error( "Input matrix workspace has wrong dimension in X-axis."); double momentum = 0.5 * (dataws->readX(0)[0] + dataws->readX(0)[1]); Kernel::V3D ki = (samplePos - sourcePos) * (momentum / sourcePos.norm()); g_log.debug() << "Source at " << sourcePos.toString() << ", Norm = " << sourcePos.norm() << ", momentum = " << momentum << "\n" << "k_i = " << ki.toString() << "\n"; // Go though each spectrum to conver to MDEvent size_t numspec = dataws->getNumberHistograms(); double maxsignal = 0; size_t nummdevents = 0; for (size_t iws = 0; iws < numspec; ++iws) { // Get detector positions and signal double signal = dataws->readY(iws)[0]; // Skip event with 0 signal if (signal < 0.001) continue; double error = dataws->readE(iws)[0]; Kernel::V3D detpos = dataws->getDetector(iws)->getPos(); std::vector<Mantid::coord_t> q_sample(3); // Calculate Q-sample and new detector ID in virtual instrument. Kernel::V3D qlab = convertToQSample(samplePos, ki, detpos, momentum, q_sample, rotationMatrix); detid_t native_detid = dataws->getDetector(iws)->getID(); detid_t detid = native_detid + startdetid; // Insert inserter.insertMDEvent( static_cast<float>(signal), static_cast<float>(error * error), static_cast<uint16_t>(runnumber), detid, q_sample.data()); updateQRange(q_sample); g_log.debug() << "Q-lab = " << qlab.toString() << "\n"; g_log.debug() << "Insert DetID " << detid << ", signal = " << signal << ", with q_sample = " << q_sample[0] << ", " << q_sample[1] << ", " << q_sample[2] << "\n"; // Update some statistical inforamtion if (signal > maxsignal) maxsignal = signal; ++nummdevents; } g_log.information() << "Imported Matrixworkspace: Max. Signal = " << maxsignal << ", Add " << nummdevents << " MDEvents " << "\n"; // Add experiment info including instrument, goniometer and run number ExperimentInfo_sptr expinfo = boost::make_shared<ExperimentInfo>(); if (usevirtual) expinfo->setInstrument(m_virtualInstrument); else { Geometry::Instrument_const_sptr tmp_inst = dataws->getInstrument(); expinfo->setInstrument(tmp_inst); } expinfo->mutableRun().setGoniometer(dataws->run().getGoniometer(), false); expinfo->mutableRun().addProperty("run_number", runnumber); // Add all the other propertys from original data workspace const std::vector<Kernel::Property *> vec_property = dataws->run().getProperties(); for (auto property : vec_property) { expinfo->mutableRun().addProperty(property->clone()); } m_outputWS->addExperimentInfo(expinfo); return; }
/** Convert the workspace units using TOF as an intermediate step in the * conversion * @param fromUnit :: The unit of the input workspace * @param inputWS :: The input workspace * @returns A shared pointer to the output workspace */ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF( Kernel::Unit_const_sptr fromUnit, API::MatrixWorkspace_const_sptr inputWS) { using namespace Geometry; // Let's see if we are using a TableWorkspace to override parameters TableWorkspace_sptr paramWS = getProperty("DetectorParameters"); // See if we have supplied a DetectorParameters Workspace // TODO: Check if paramWS is NULL and if so throw an exception // const std::string l1ColumnLabel("l1"); // Let's check all the columns exist and are readable try { auto spectraColumnTmp = paramWS->getColumn("spectra"); auto l1ColumnTmp = paramWS->getColumn("l1"); auto l2ColumnTmp = paramWS->getColumn("l2"); auto twoThetaColumnTmp = paramWS->getColumn("twotheta"); auto efixedColumnTmp = paramWS->getColumn("efixed"); auto emodeColumnTmp = paramWS->getColumn("emode"); } catch (...) { throw Exception::InstrumentDefinitionError( "DetectorParameter TableWorkspace is not defined correctly."); } // Now let's take a reference to the vectors. const auto &l1Column = paramWS->getColVector<double>("l1"); const auto &l2Column = paramWS->getColVector<double>("l2"); const auto &twoThetaColumn = paramWS->getColVector<double>("twotheta"); const auto &efixedColumn = paramWS->getColVector<double>("efixed"); const auto &emodeColumn = paramWS->getColVector<int>("emode"); const auto &spectraColumn = paramWS->getColVector<int>("spectra"); Progress prog(this, 0.2, 1.0, m_numberOfSpectra); int64_t numberOfSpectra_i = static_cast<int64_t>(m_numberOfSpectra); // cast to make openmp happy // Get the unit object for each workspace Kernel::Unit_const_sptr outputUnit = m_outputUnit; std::vector<double> emptyVec; int failedDetectorCount = 0; // Perform Sanity Validation before creating workspace size_t checkIndex = 0; int checkSpecNo = inputWS->getDetector(checkIndex)->getID(); auto checkSpecIter = std::find(spectraColumn.begin(), spectraColumn.end(), checkSpecNo); if (checkSpecIter != spectraColumn.end()) { size_t detectorRow = std::distance(spectraColumn.begin(), checkSpecIter); // copy the X values for the check auto checkXValues = inputWS->readX(checkIndex); // Convert the input unit to time-of-flight auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); double checkdelta = 0; checkFromUnit->toTOF(checkXValues, emptyVec, l1Column[detectorRow], l2Column[detectorRow], twoThetaColumn[detectorRow], emodeColumn[detectorRow], efixedColumn[detectorRow], checkdelta); // Convert from time-of-flight to the desired unit checkOutputUnit->fromTOF(checkXValues, emptyVec, l1Column[detectorRow], l2Column[detectorRow], twoThetaColumn[detectorRow], emodeColumn[detectorRow], efixedColumn[detectorRow], checkdelta); } // create the output workspace MatrixWorkspace_sptr outputWS = this->setupOutputWorkspace(inputWS); EventWorkspace_sptr eventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check // TODO: Check why this parallel stuff breaks // Loop over the histograms (detector spectra) // PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS)) for (int64_t i = 0; i < numberOfSpectra_i; ++i) { // Lets find what row this spectrum Number appears in our detector table. // PARALLEL_START_INTERUPT_REGION std::size_t wsid = i; try { double deg2rad = M_PI / 180.; auto det = outputWS->getDetector(i); int specNo = det->getID(); // int spectraNumber = static_cast<int>(spectraColumn->toDouble(i)); // wsid = outputWS->getIndexFromSpectrumNumber(spectraNumber); g_log.debug() << "###### Spectra #" << specNo << " ==> Workspace ID:" << wsid << '\n'; // Now we need to find the row that contains this spectrum std::vector<int>::const_iterator specIter; specIter = std::find(spectraColumn.begin(), spectraColumn.end(), specNo); if (specIter != spectraColumn.end()) { const size_t detectorRow = std::distance(spectraColumn.begin(), specIter); const double l1 = l1Column[detectorRow]; const double l2 = l2Column[detectorRow]; const double twoTheta = twoThetaColumn[detectorRow] * deg2rad; const double efixed = efixedColumn[detectorRow]; const int emode = emodeColumn[detectorRow]; if (g_log.is(Logger::Priority::PRIO_DEBUG)) { g_log.debug() << "specNo from detector table = " << spectraColumn[detectorRow] << '\n'; g_log.debug() << "###### Spectra #" << specNo << " ==> Det Table Row:" << detectorRow << '\n'; g_log.debug() << "\tL1=" << l1 << ",L2=" << l2 << ",TT=" << twoTheta << ",EF=" << efixed << ",EM=" << emode << '\n'; } // Make local copies of the units. This allows running the loop in // parallel auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); /// @todo Don't yet consider hold-off (delta) const double delta = 0.0; std::vector<double> values(outputWS->x(wsid).begin(), outputWS->x(wsid).end()); // Convert the input unit to time-of-flight localFromUnit->toTOF(values, emptyVec, l1, l2, twoTheta, emode, efixed, delta); // Convert from time-of-flight to the desired unit localOutputUnit->fromTOF(values, emptyVec, l1, l2, twoTheta, emode, efixed, delta); outputWS->mutableX(wsid) = std::move(values); // EventWorkspace part, modifying the EventLists. if (m_inputEvents) { eventWS->getSpectrum(wsid) .convertUnitsViaTof(localFromUnit.get(), localOutputUnit.get()); } } else { // Not found failedDetectorCount++; outputWS->maskWorkspaceIndex(wsid); } } catch (Exception::NotFoundError &) { // Get to here if exception thrown when calculating distance to detector failedDetectorCount++; // Since you usually (always?) get to here when there's no attached // detectors, this call is // the same as just zeroing out the data (calling clearData on the // spectrum) outputWS->maskWorkspaceIndex(i); } prog.report("Convert to " + m_outputUnit->unitID()); // PARALLEL_END_INTERUPT_REGION } // loop over spectra // PARALLEL_CHECK_INTERUPT_REGION if (failedDetectorCount != 0) { g_log.information() << "Something went wrong for " << failedDetectorCount << " spectra. Masking spectrum.\n"; } if (m_inputEvents) eventWS->clearMRU(); return outputWS; }
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inWS = getProperty("InputWorkspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); const bool doGravity = getProperty("AccountForGravity"); // Check the input checkInput(inWS); // Setup outputworkspace auto outWS = setupOutputWorkspace(inWS); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; // The moderator workspace needs to match the data workspace // in terms of wavelength binning const MatrixWorkspace_sptr sigmaModeratorVSwavelength = getModeratorWorkspace(inWS); // create interpolation table from sigmaModeratorVSwavelength Kernel::Interpolation lookUpTable; const MantidVec xInterpolate = sigmaModeratorVSwavelength->readX(0); const MantidVec yInterpolate = sigmaModeratorVSwavelength->readY(0); // prefer the input to be a pointworkspace and create interpolation function if (sigmaModeratorVSwavelength->isHistogramData()) { g_log.notice() << "mid-points of SigmaModerator histogram bins will be " "used for interpolation."; for (size_t i = 0; i < xInterpolate.size() - 1; ++i) { const double midpoint = (xInterpolate[i + 1] + xInterpolate[i]) / 2.0; lookUpTable.addPoint(midpoint, yInterpolate[i]); } } else { for (size_t i = 0; i < xInterpolate.size(); ++i) { lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]); } } // Calculate the L1 distance const V3D samplePos = inWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); // Get the collimation length double LCollim = getProperty("CollimationLength"); if (LCollim == 0.0) { auto collimationLengthEstimator = SANSCollimationLengthEstimator(); LCollim = collimationLengthEstimator.provideCollimationLength(inWS); g_log.information() << "No collimation length was specified. A default " "collimation length was estimated to be " << LCollim << std::endl; } else { g_log.information() << "The collimation length is " << LCollim << std::endl; } const int numberOfSpectra = static_cast<int>(inWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; try { det = inWS->getDetector(i); } catch (Exception::NotFoundError &) { g_log.information() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; } // If no detector found or if it's masked or a monitor, skip onto the next // spectrum if (!det || det->isMonitor() || det->isMasked()) continue; // Get the flight path from the sample to the detector pixel const V3D samplePos = inWS->getInstrument()->getSample()->getPos(); const V3D scatteredFlightPathV3D = det->getPos() - samplePos; const double L2 = scatteredFlightPathV3D.norm(); TOFSANSResolutionByPixelCalculator calculator; const double waveLengthIndependentFactor = calculator.getWavelengthIndependentFactor(R1, R2, deltaR, LCollim, L2); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = inWS->detectorTwoTheta(det); double sinTheta = sin(theta / 2.0); double factor = 4.0 * M_PI * sinTheta; const MantidVec &xIn = inWS->readX(i); const size_t xLength = xIn.size(); // Gravity correction boost::shared_ptr<GravitySANSHelper> grav; if (doGravity) { grav = boost::make_shared<GravitySANSHelper>(inWS, det, getProperty("ExtraLength")); } // Get handles on the outputWorkspace MantidVec &yOut = outWS->dataY(i); // for each wavelenght bin of each pixel calculate a q-resolution for (size_t j = 0; j < xLength - 1; j++) { // use the midpoint of each bin const double wl = (xIn[j + 1] + xIn[j]) / 2.0; // Calculate q. Alternatively q could be calculated using ConvertUnit // If we include a gravity correction we need to adjust sinTheta // for each wavelength (in Angstrom) if (doGravity) { double sinThetaGrav = grav->calcSinTheta(wl); factor = 4.0 * M_PI * sinThetaGrav; } const double q = factor / wl; // wavelenght spread from bin assumed to be const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j]; // Get the uncertainty in Q auto sigmaQ = calculator.getSigmaQValue(lookUpTable.value(wl), waveLengthIndependentFactor, q, wl, sigmaSpreadFromBin, L1, L2); // Insert the Q value and the Q resolution into the outputworkspace yOut[j] = sigmaQ; } progress.report("Computing Q resolution"); } // Set the y axis label outWS->setYUnitLabel("QResolution"); setProperty("OutputWorkspace", outWS); }