75 "Name of the workspace to have detector resolution calculated");
78 "Workspace containing the divergence");
81 "Name of the output workspace containing delta(d)/d of each "
84 auto positiveOrZero = std::make_shared<BoundedValidator<double>>();
85 positiveOrZero->setLower(0.);
86 positiveOrZero->setLowerExclusive(
false);
89 "DeltaT as the resolution of TOF with unit microsecond");
92 "DeltaT/T as the full term in the equation");
95 "Uncertainty in the path length due to the source in unit of meters");
97 "Uncertainty in angle due to the source in unit of radians");
99 auto positiveWavelength = std::make_shared<BoundedValidator<double>>();
100 positiveWavelength->setLower(0.);
101 positiveWavelength->setLowerExclusive(
true);
103 "Wavelength setting in Angstroms. This overrides what is in "
108 "Workspaces created showing the various resolution terms");
112 std::map<std::string, std::string> errors;
115 const double deltaT =
getProperty(PropertyNames::DELTA_T);
116 const bool hasDeltaT = (deltaT > 0.);
117 const bool hasDeltaTOverT = (!
isDefault(PropertyNames::DELTA_T_OVER_T));
119 if (hasDeltaT && hasDeltaTOverT) {
120 msg =
"Cannot specify both " + PropertyNames::DELTA_T +
" and " + PropertyNames::DELTA_T_OVER_T;
121 }
else if ((!hasDeltaT) && (!hasDeltaTOverT)) {
122 msg =
"Must specify either " + PropertyNames::DELTA_T +
" or " + PropertyNames::DELTA_T_OVER_T;
125 errors[PropertyNames::DELTA_T] = msg;
126 errors[PropertyNames::DELTA_T_OVER_T] = msg;
136 std::string partials_prefix =
getPropertyValue(PropertyNames::PARTIALS_WKSP_GRP);
137 m_resTof = DataObjects::create<DataObjects::Workspace2D>(*
m_inputWS, HistogramData::Points(1));
139 m_resAngle = DataObjects::create<DataObjects::Workspace2D>(*
m_inputWS, HistogramData::Points(1));
140 m_outputWS = DataObjects::create<DataObjects::Workspace2D>(*
m_inputWS, HistogramData::Points(1));
147 auto partialsGroup = std::make_shared<WorkspaceGroup>();
148 API::AnalysisDataService::Instance().addOrReplace(partials_prefix +
"_tof",
m_resTof);
149 API::AnalysisDataService::Instance().addOrReplace(partials_prefix +
"_length",
m_resPathLength);
150 API::AnalysisDataService::Instance().addOrReplace(partials_prefix +
"_angle",
m_resAngle);
151 partialsGroup->addWorkspace(
m_resTof);
154 setProperty(PropertyNames::PARTIALS_WKSP_GRP, partialsGroup);
215 const auto &spectrumInfo =
m_inputWS->spectrumInfo();
216 const auto l1 = spectrumInfo.l1();
217 const auto &componentInfo =
m_inputWS->componentInfo();
218 const auto &detectorInfo =
m_inputWS->detectorInfo();
220 const auto samplepos = spectrumInfo.samplePosition();
222 const size_t numspec =
m_inputWS->getNumberHistograms();
224 double mintwotheta = 2. * M_PI;
225 double maxtwotheta = 0.;
226 for (std::size_t i = 0; i < detectorInfo.size(); ++i) {
227 if (!(detectorInfo.isMasked(i) || detectorInfo.isMonitor(i))) {
229 const auto twotheta = detectorInfo.twoTheta(i);
230 mintwotheta = std::min(twotheta, mintwotheta);
231 maxtwotheta = std::max(twotheta, maxtwotheta);
235 double minTerm3Sq = 1.;
236 double maxTerm3Sq = 0.;
242 for (
size_t specNum = 0; specNum < numspec; ++specNum) {
244 const auto &spectrumDefinition = spectrumInfo.spectrumDefinition(specNum);
246 const double numDet = double(spectrumDefinition.size());
253 term1Sq = std::accumulate(spectrumDefinition.cbegin(), spectrumDefinition.cend(), 0.,
254 [&detectorInfo, ¢reVel, &l1, &deltaT](
const auto sum,
const auto &
index) {
255 if (detectorInfo.isMasked(index.first) || detectorInfo.isMonitor(index.first)) {
259 const double l2 = detectorInfo.l2(index.first);
260 const double centraltof = (l1 + l2) / centreVel;
261 const double term = deltaT / centraltof;
262 return sum + (term * term);
265 term1Sq = term1Sq / numDet;
272 term2Sq = std::accumulate(spectrumDefinition.cbegin(), spectrumDefinition.cend(), 0.,
273 [&componentInfo, &detectorInfo, &sourceTerm, &l1](
const auto sum,
const auto &
index) {
274 if (detectorInfo.isMasked(index.first) || detectorInfo.isMonitor(index.first)) {
277 const auto l2 = detectorInfo.l2(index.first);
278 const auto l_total = (l1 + l2);
280 const auto &bbox = componentInfo.shape(index.first).getBoundingBox();
281 const auto scale = componentInfo.scaleFactor(index.first);
282 const double dx = (bbox.xMax() - bbox.xMin()) / scale.X();
283 const double dy = (bbox.yMax() - bbox.yMin()) / scale.Y();
284 const double dz = (bbox.zMax() - bbox.zMin()) / scale.Z();
286 const double detdimSq = (dx * dx + dy * dy + dz * dz) * 0.25;
287 const double term = (detdimSq + sourceTerm) / (l_total * l_total);
291 term2Sq = term2Sq / numDet;
296 if (m_divergenceWS) {
297 double deltathetaSq = m_divergenceWS->y(specNum)[0];
298 deltathetaSq = deltathetaSq * deltathetaSq;
300 const double theta = spectrumInfo.isMonitor(specNum) ? 0.0 : 0.5 * spectrumInfo.twoTheta(specNum);
301 const double tan_theta = tan(theta);
302 term3Sq = (deltathetaSq + m_sourceDeltaThetaRadiansSq) / (tan_theta * tan_theta);
304 const double sourceTerm = m_sourceDeltaThetaRadiansSq;
305 const double solidAngle = std::accumulate(
306 spectrumDefinition.cbegin(), spectrumDefinition.cend(), 0.,
307 [&componentInfo, &samplepos, &detectorInfo, &sourceTerm](
const auto sum,
const auto &
index) {
308 if (detectorInfo.isMasked(index.first) || detectorInfo.isMonitor(index.first)) {
311 const double theta = 0.5 * detectorInfo.twoTheta(index.first);
312 const double cot_theta = 1. / tan(theta);
313 return sum + ((componentInfo.solidAngle(index.first, samplepos) + sourceTerm) * cot_theta * cot_theta);
316 term3Sq = solidAngle / numDet;
320 if (spectrumInfo.isMonitor(specNum)) {
321 m_resTof->mutableY(specNum) = 0.;
322 m_resPathLength->mutableY(specNum) = 0.;
323 m_resAngle->mutableY(specNum) = 0.;
324 m_outputWS->mutableY(specNum) = 0.;
326 const double resolution = sqrt(term1Sq + term2Sq + term3Sq);
327 m_resTof->mutableY(specNum) = sqrt(term1Sq);
328 m_resPathLength->mutableY(specNum) = sqrt(term2Sq);
329 m_resAngle->mutableY(specNum) = sqrt(term3Sq);
330 m_outputWS->mutableY(specNum) = resolution;
333 m_resTof->mutableX(specNum) =
static_cast<double>(specNum);
334 m_resPathLength->mutableX(specNum) =
static_cast<double>(specNum);
335 m_resAngle->mutableX(specNum) =
static_cast<double>(specNum);
336 m_outputWS->mutableX(specNum) =
static_cast<double>(specNum);
339 minTerm3Sq = std::min(term3Sq, minTerm3Sq);
340 maxTerm3Sq = std::max(term3Sq, maxTerm3Sq);
345 const double twotheta = spectrumInfo.isMonitor(specNum) ? 0.0 : spectrumInfo.twoTheta(specNum);
347 const std::string detType = spectrumInfo.hasUniqueDetector(specNum) ?
"DetectorComponent" :
"LogicalComponent";
349 g_log.
debug() << detType <<
" " << specNum <<
"\t\t" << twotheta <<
"\t\tdT/T = " << sqrt(term1Sq)
350 <<
"\t\tdL/L = " << sqrt(term2Sq) <<
"\t\tdTheta*cotTheta = " << sqrt(term3Sq) <<
"\n";
356 g_log.
notice() <<
"t3 range: " << sqrt(minTerm3Sq) <<
", " << sqrt(maxTerm3Sq) <<
"\n";