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"); } }
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 auto &xInterpolate = sigmaModeratorVSwavelength->points(0); const auto &yInterpolate = sigmaModeratorVSwavelength->y(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(); ++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 << '\n'; } else { g_log.information() << "The collimation length is " << LCollim << '\n'; } const int numberOfSpectra = static_cast<int>(inWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); const auto &spectrumInfo = inWS->spectrumInfo(); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; if (!spectrumInfo.hasDetectors(i)) { g_log.information() << "Workspace index " << i << " has no detector assigned to it - discarding\n"; continue; } // If no detector found or if it's masked or a monitor, skip onto the next // spectrum if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i)) continue; const double L2 = spectrumInfo.l2(i); 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 = spectrumInfo.twoTheta(i); double sinTheta = sin(0.5 * theta); double factor = 4.0 * M_PI * sinTheta; const auto &xIn = inWS->x(i); const size_t xLength = xIn.size(); // Gravity correction std::unique_ptr<GravitySANSHelper> grav; if (doGravity) { grav = Kernel::make_unique<GravitySANSHelper>(spectrumInfo, i, getProperty("ExtraLength")); } // Get handles on the outputWorkspace auto &yOut = outWS->mutableY(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); }