74 "Name of the workspace to have detector resolution calculated");
77 "Workspace containing the divergence");
80 "Name of the output workspace containing delta(d)/d of each "
83 auto positiveOrZero = std::make_shared<BoundedValidator<double>>();
84 positiveOrZero->setLower(0.);
85 positiveOrZero->setLowerExclusive(
false);
88 "DeltaT as the resolution of TOF with unit microsecond");
91 "DeltaT/T as the full term in the equation");
94 "Uncertainty in the path length due to the source in unit of meters");
96 "Uncertainty in angle due to the source in unit of radians");
98 auto positiveWavelength = std::make_shared<BoundedValidator<double>>();
99 positiveWavelength->setLower(0.);
100 positiveWavelength->setLowerExclusive(
true);
102 "Wavelength setting in Angstroms. This overrides what is in "
107 "Workspaces created showing the various resolution terms");
111 std::map<std::string, std::string> errors;
114 const double deltaT =
getProperty(PropertyNames::DELTA_T);
115 const bool hasDeltaT = (deltaT > 0.);
116 const bool hasDeltaTOverT = (!
isDefault(PropertyNames::DELTA_T_OVER_T));
118 if (hasDeltaT && hasDeltaTOverT) {
119 msg =
"Cannot specify both " + PropertyNames::DELTA_T +
" and " + PropertyNames::DELTA_T_OVER_T;
120 }
else if ((!hasDeltaT) && (!hasDeltaTOverT)) {
121 msg =
"Must specify either " + PropertyNames::DELTA_T +
" or " + PropertyNames::DELTA_T_OVER_T;
124 errors[PropertyNames::DELTA_T] = msg;
125 errors[PropertyNames::DELTA_T_OVER_T] = msg;
135 std::string partials_prefix =
getPropertyValue(PropertyNames::PARTIALS_WKSP_GRP);
136 m_resTof = DataObjects::create<DataObjects::Workspace2D>(*
m_inputWS, HistogramData::Points(1));
138 m_resAngle = DataObjects::create<DataObjects::Workspace2D>(*
m_inputWS, HistogramData::Points(1));
139 m_outputWS = DataObjects::create<DataObjects::Workspace2D>(*
m_inputWS, HistogramData::Points(1));
146 auto partialsGroup = std::make_shared<WorkspaceGroup>();
147 API::AnalysisDataService::Instance().addOrReplace(partials_prefix +
"_tof",
m_resTof);
148 API::AnalysisDataService::Instance().addOrReplace(partials_prefix +
"_length",
m_resPathLength);
149 API::AnalysisDataService::Instance().addOrReplace(partials_prefix +
"_angle",
m_resAngle);
150 partialsGroup->addWorkspace(
m_resTof);
153 setProperty(PropertyNames::PARTIALS_WKSP_GRP, partialsGroup);
214 const auto &spectrumInfo =
m_inputWS->spectrumInfo();
215 const auto l1 = spectrumInfo.l1();
216 const auto &componentInfo =
m_inputWS->componentInfo();
217 const auto &detectorInfo =
m_inputWS->detectorInfo();
219 const auto samplepos = spectrumInfo.samplePosition();
221 const size_t numspec =
m_inputWS->getNumberHistograms();
223 double mintwotheta = 2. * M_PI;
224 double maxtwotheta = 0.;
225 for (std::size_t i = 0; i < detectorInfo.size(); ++i) {
226 if (!(detectorInfo.isMasked(i) || detectorInfo.isMonitor(i))) {
228 const auto twotheta = detectorInfo.twoTheta(i);
229 mintwotheta = std::min(twotheta, mintwotheta);
230 maxtwotheta = std::max(twotheta, maxtwotheta);
234 double minTerm3Sq = 1.;
235 double maxTerm3Sq = 0.;
241 for (
size_t specNum = 0; specNum < numspec; ++specNum) {
243 const auto &spectrumDefinition = spectrumInfo.spectrumDefinition(specNum);
245 const double numDet = double(spectrumDefinition.size());
252 term1Sq = std::accumulate(spectrumDefinition.cbegin(), spectrumDefinition.cend(), 0.,
253 [&detectorInfo, ¢reVel, &l1, &deltaT](
const auto sum,
const auto &
index) {
254 if (detectorInfo.isMasked(index.first) || detectorInfo.isMonitor(index.first)) {
258 const double l2 = detectorInfo.l2(index.first);
259 const double centraltof = (l1 + l2) / centreVel;
260 const double term = deltaT / centraltof;
261 return sum + (term * term);
264 term1Sq = term1Sq / numDet;
271 term2Sq = std::accumulate(spectrumDefinition.cbegin(), spectrumDefinition.cend(), 0.,
272 [&detectorInfo, &sourceTerm, &l1](
const auto sum,
const auto &
index) {
273 if (detectorInfo.isMasked(index.first) || detectorInfo.isMonitor(index.first)) {
276 const auto &detector = detectorInfo.detector(index.first);
277 const auto realdet = dynamic_cast<const Detector *>(&detector);
279 const auto l2 = detectorInfo.l2(index.first);
280 const auto l_total = (l1 + l2);
282 const double dx = realdet->getWidth();
283 const double dy = realdet->getHeight();
284 const double dz = realdet->getDepth();
286 const double detdimSq = (dx * dx + dy * dy + dz * dz) * 0.25;
287 const double term = (detdimSq + sourceTerm) / (l_total * l_total);
294 term2Sq = term2Sq / numDet;
299 if (m_divergenceWS) {
300 double deltathetaSq = m_divergenceWS->y(specNum)[0];
301 deltathetaSq = deltathetaSq * deltathetaSq;
303 const double theta = spectrumInfo.isMonitor(specNum) ? 0.0 : 0.5 * spectrumInfo.twoTheta(specNum);
304 const double tan_theta = tan(theta);
305 term3Sq = (deltathetaSq + m_sourceDeltaThetaRadiansSq) / (tan_theta * tan_theta);
307 const double sourceTerm = m_sourceDeltaThetaRadiansSq;
308 const double solidAngle = std::accumulate(
309 spectrumDefinition.cbegin(), spectrumDefinition.cend(), 0.,
310 [&componentInfo, &samplepos, &detectorInfo, &sourceTerm](
const auto sum,
const auto &
index) {
311 if (detectorInfo.isMasked(index.first) || detectorInfo.isMonitor(index.first)) {
314 const double theta = 0.5 * detectorInfo.twoTheta(index.first);
315 const double cot_theta = 1. / tan(theta);
316 return sum + ((componentInfo.solidAngle(index.first, samplepos) + sourceTerm) * cot_theta * cot_theta);
319 term3Sq = solidAngle / numDet;
323 if (spectrumInfo.isMonitor(specNum)) {
324 m_resTof->mutableY(specNum) = 0.;
325 m_resPathLength->mutableY(specNum) = 0.;
326 m_resAngle->mutableY(specNum) = 0.;
327 m_outputWS->mutableY(specNum) = 0.;
329 const double resolution = sqrt(term1Sq + term2Sq + term3Sq);
330 m_resTof->mutableY(specNum) = sqrt(term1Sq);
331 m_resPathLength->mutableY(specNum) = sqrt(term2Sq);
332 m_resAngle->mutableY(specNum) = sqrt(term3Sq);
333 m_outputWS->mutableY(specNum) = resolution;
336 m_resTof->mutableX(specNum) =
static_cast<double>(specNum);
337 m_resPathLength->mutableX(specNum) =
static_cast<double>(specNum);
338 m_resAngle->mutableX(specNum) =
static_cast<double>(specNum);
339 m_outputWS->mutableX(specNum) =
static_cast<double>(specNum);
342 minTerm3Sq = std::min(term3Sq, minTerm3Sq);
343 maxTerm3Sq = std::max(term3Sq, maxTerm3Sq);
348 const double twotheta = spectrumInfo.isMonitor(specNum) ? 0.0 : spectrumInfo.twoTheta(specNum);
349 const auto &det = spectrumInfo.detector(specNum);
351 g_log.
debug() << det.type() <<
" " << specNum <<
"\t\t" << twotheta <<
"\t\tdT/T = " << sqrt(term1Sq)
352 <<
"\t\tdL/L = " << sqrt(term2Sq) <<
"\t\tdTheta*cotTheta = " << sqrt(term3Sq) <<
"\n";
358 g_log.
notice() <<
"t3 range: " << sqrt(minTerm3Sq) <<
", " << sqrt(maxTerm3Sq) <<
"\n";