Mantid
Loading...
Searching...
No Matches
AlignAndFocusPowder.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
9#include "MantidAPI/Axis.h"
30
32using namespace Mantid::Kernel;
33using namespace Mantid::API;
34using namespace Mantid::DataObjects;
35
37using namespace Kernel;
42
43namespace { // anonymous namespace
44namespace PropertyNames {
45const std::string INPUT_WKSP("InputWorkspace");
46const std::string OUTPUT_WKSP("OutputWorkspace");
47const std::string UNFOCUS_WKSP("UnfocussedWorkspace");
48const std::string CAL_FILE("CalFileName");
49const std::string GROUP_FILE("GroupFilename");
50const std::string GROUP_WKSP("GroupingWorkspace");
51const std::string CAL_WKSP("CalibrationWorkspace");
52const std::string OFFSET_WKSP("OffsetsWorkspace");
53const std::string MASK_WKSP("MaskWorkspace");
54const std::string MASK_TABLE("MaskBinTable");
55const std::string BINNING("Params");
56const std::string RESAMPLEX("ResampleX");
57const std::string BIN_IN_D("Dspacing");
58const std::string D_MINS("DMin");
59const std::string D_MAXS("DMax");
60const std::string RAGGED_DELTA("DeltaRagged");
61const std::string TOF_MIN("TMin");
62const std::string TOF_MAX("TMax");
63const std::string WL_MIN("CropWavelengthMin");
64const std::string WL_MAX("CropWavelengthMax");
65const std::string PRESERVE_EVENTS("PreserveEvents");
66const std::string REMOVE_PROMPT_PULSE("RemovePromptPulseWidth");
67const std::string RESONANCE_UNITS("ResonanceFilterUnits");
68const std::string RESONANCE_LOWER_LIMITS("ResonanceFilterLowerLimits");
69const std::string RESONANCE_UPPER_LIMITS("ResonanceFilterUpperLimits");
70const std::string COMPRESS_TOF_TOL("CompressTolerance");
71const std::string COMPRESS_WALL_TOL("CompressWallClockTolerance");
72const std::string COMPRESS_WALL_START("CompressStartTime");
73const std::string COMPRESS_MODE("CompressBinningMode");
74const std::string L1("PrimaryFlightPath");
75const std::string SPEC_IDS("SpectrumIDs");
76const std::string L2("L2");
77const std::string POLAR("Polar");
78const std::string AZIMUTHAL("Azimuthal");
79const std::string PM_NAME("ReductionProperties");
80const std::string LORENTZ("LorentzCorrection");
81const std::string UNWRAP_REF("UnwrapRef");
82const std::string LOWRES_REF("LowResRef");
83const std::string LOWRES_SPEC_OFF("LowResSpectrumOffset");
84} // namespace PropertyNames
85
86void getTofRange(const MatrixWorkspace_const_sptr &wksp, double &tmin, double &tmax) {
87 if (const auto eventWksp = std::dynamic_pointer_cast<const EventWorkspace>(wksp)) {
88 eventWksp->getEventXMinMax(tmin, tmax);
89 } else {
90 wksp->getXMinMax(tmin, tmax);
91 }
92}
93
94const std::vector<std::string> binningModeNames{"Default", "Linear", "Logarithmic"};
95enum class BinningMode { DEFAULT, LINEAR, LOGARITHMIC, enum_count };
97
98} // anonymous namespace
99
100// Register the class into the algorithm factory
101DECLARE_ALGORITHM(AlignAndFocusPowder)
102
103//----------------------------------------------------------------------------------------------
108 "The input workspace");
109 declareProperty(
111 "The result of diffraction focussing of InputWorkspace");
112 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>(PropertyNames::UNFOCUS_WKSP, "",
114 "Treated data in d-spacing before focussing (optional). This will likely "
115 "need rebinning.");
116 // declareProperty(
117 // new WorkspaceProperty<MatrixWorkspace>("LowResTOFWorkspace", "",
118 // Direction::Output, PropertyMode::Optional),
119 // "The name of the workspace containing the filtered low resolution TOF
120 // data.");
121 declareProperty(std::make_unique<FileProperty>(PropertyNames::CAL_FILE, "", FileProperty::OptionalLoad,
122 std::vector<std::string>{".h5", ".hd5", ".hdf", ".cal"}),
123 "The name of the calibration file with offset, masking, and "
124 "grouping data");
125 declareProperty(std::make_unique<FileProperty>(PropertyNames::GROUP_FILE, "", FileProperty::OptionalLoad,
126 std::vector<std::string>{".xml", ".cal"}),
127 "Overrides grouping from CalFileName");
128 declareProperty(std::make_unique<WorkspaceProperty<GroupingWorkspace>>(PropertyNames::GROUP_WKSP, "",
130 "Optional: A GroupingWorkspace giving the grouping info.");
131
132 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>(PropertyNames::CAL_WKSP, "", Direction::InOut,
134 "Optional: A Workspace containing the calibration information. Either "
135 "this or CalibrationFile needs to be specified.");
136 declareProperty(std::make_unique<WorkspaceProperty<OffsetsWorkspace>>(PropertyNames::OFFSET_WKSP, "",
138 "Optional: An OffsetsWorkspace giving the detector calibration values.");
139 declareProperty(std::make_unique<WorkspaceProperty<MaskWorkspace>>(PropertyNames::MASK_WKSP, "", Direction::InOut,
141 "Optional: A workspace giving which detectors are masked.");
142 declareProperty(
143 std::make_unique<WorkspaceProperty<TableWorkspace>>("MaskBinTable", "", Direction::Input, PropertyMode::Optional),
144 "Optional: A workspace giving pixels and bins to mask.");
145 declareProperty( // intentionally not using the RebinParamsValidator
146 std::make_unique<ArrayProperty<double>>(PropertyNames::BINNING),
147 "A comma separated list of first bin boundary, width, last bin boundary. "
148 "Optionally\n"
149 "this can be followed by a comma and more widths and last boundary "
150 "pairs.\n"
151 "Negative width values indicate logarithmic binning.");
152 declareProperty(PropertyNames::RESAMPLEX, 0,
153 "Number of bins in x-axis. Non-zero value "
154 "overrides \"Params\" property. Negative "
155 "value means logarithmic binning.");
156 setPropertySettings(PropertyNames::BINNING,
157 std::make_unique<EnabledWhenProperty>(PropertyNames::RESAMPLEX, IS_DEFAULT));
158 declareProperty(PropertyNames::BIN_IN_D, true, "Bin in Dspace. (True is Dspace; False is TOF)");
159 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::D_MINS),
160 "Minimum for Dspace axis. (Default 0.) ");
161 mapPropertyName(PropertyNames::D_MINS, "d_min");
162 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::D_MAXS),
163 "Maximum for Dspace axis. (Default 0.) ");
164 mapPropertyName(PropertyNames::D_MAXS, "d_max");
165 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::RAGGED_DELTA), "Step parameter for rebin");
166 mapPropertyName(PropertyNames::RAGGED_DELTA, "delta");
167 declareProperty(PropertyNames::TOF_MIN, EMPTY_DBL(), "Minimum for TOF axis. Defaults to 0. ");
168 mapPropertyName(PropertyNames::TOF_MIN, "tof_min");
169 declareProperty(PropertyNames::TOF_MAX, EMPTY_DBL(), "Maximum for TOF or dspace axis. Defaults to 0. ");
170 mapPropertyName(PropertyNames::TOF_MAX, "tof_max");
171 declareProperty(PropertyNames::PRESERVE_EVENTS, true,
172 "If the InputWorkspace is an "
173 "EventWorkspace, this will preserve "
174 "the full event list (warning: this "
175 "will use much more memory!).");
176 declareProperty(PropertyNames::REMOVE_PROMPT_PULSE, 0.,
177 "Width of events (in "
178 "microseconds) near the prompt "
179 "pulse to remove. 0 disables");
180 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
181 mustBePositive->setLower(0.0);
182
183 std::vector<std::string> allowedResonanceUnits({"Energy", "Wavelength"});
184 declareProperty(PropertyNames::RESONANCE_UNITS, allowedResonanceUnits.back(),
185 std::make_shared<StringListValidator>(allowedResonanceUnits),
186 "Units for resonances to be filtered in. "
187 "The data will be converted to these units temporarily to filter.");
188 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::RESONANCE_LOWER_LIMITS),
189 "Minimum values to filter absorption resonance. This must have same number of values as "
190 "ResonanceFilterUpperLimits. Default behavior is to not filter.");
191 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::RESONANCE_UPPER_LIMITS),
192 "Maximum values to filter absorption resonance. This must have same number of values as "
193 "ResonanceFilterLowerLimits. Default behavior is to not filter.");
194
195 declareProperty(std::make_unique<PropertyWithValue<double>>(PropertyNames::COMPRESS_TOF_TOL, 1e-5, Direction::Input),
196 "Compress events (in microseconds) within this tolerance. (Default 1e-5). If negative then do "
197 "logorithmic compression.");
198 declareProperty(std::make_unique<PropertyWithValue<double>>(PropertyNames::COMPRESS_WALL_TOL, EMPTY_DBL(),
199 mustBePositive, Direction::Input),
200 "The tolerance (in seconds) on the wall-clock time for comparison. Unset "
201 "means compressing all wall-clock times together disabling pulsetime "
202 "resolution.");
203 auto dateValidator = std::make_shared<DateTimeValidator>();
204 dateValidator->allowEmpty(true);
205 declareProperty(PropertyNames::COMPRESS_WALL_START, "", dateValidator,
206 "An ISO formatted date/time string specifying the timestamp for "
207 "starting filtering. Ignored if WallClockTolerance is not specified. "
208 "Default is start of run",
210 declareProperty(PropertyNames::COMPRESS_MODE, binningModeNames[size_t(BinningMode::DEFAULT)],
211 std::make_shared<Mantid::Kernel::StringListValidator>(binningModeNames),
212 "Optional. Binning behavior can be specified in the usual way through sign of tolerance "
213 "('Default'); or can be set to one of the allowed binning modes. ");
214 declareProperty(PropertyNames::LORENTZ, false,
215 "Multiply each spectrum by "
216 "sin(theta) where theta is "
217 "half of the Bragg angle");
218 declareProperty(PropertyNames::UNWRAP_REF, 0., "This property is deprecated (since v6.13).");
219 declareProperty(PropertyNames::LOWRES_REF, 0., "Reference DIFC for resolution removal. Zero skips the correction");
220 declareProperty("CropWavelengthMin", 0., "Crop the data at this minimum wavelength. Overrides LowResRef.");
221 mapPropertyName(PropertyNames::WL_MIN, "wavelength_min");
222 declareProperty("CropWavelengthMax", EMPTY_DBL(),
223 "Crop the data at this maximum wavelength. Forces use of "
224 "CropWavelengthMin.");
225 mapPropertyName(PropertyNames::WL_MAX, "wavelength_max");
226 declareProperty(PropertyNames::L1, -1.0, "If positive, focus positions are changed. (Default -1) ");
227 declareProperty(std::make_unique<ArrayProperty<int32_t>>(PropertyNames::SPEC_IDS),
228 "Optional: Spectrum Nos (note that it is not detector ID or "
229 "workspace indices).");
230 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::L2),
231 "Optional: Secondary flight (L2) paths for each detector");
232 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::POLAR),
233 "Optional: Polar angles (two thetas) for detectors");
234 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::AZIMUTHAL),
235 "Azimuthal angles (out-of-plain) for detectors");
236
237 declareProperty(PropertyNames::LOWRES_SPEC_OFF, -1,
238 "Offset on spectrum No of low resolution spectra from high "
239 "resolution one. "
240 "If negative, then all the low resolution TOF will not be "
241 "processed. Otherwise, low resolution TOF "
242 "will be stored in an additional set of spectra. "
243 "If offset is equal to 0, then the low resolution will have "
244 "same spectrum Nos as the normal ones. "
245 "Otherwise, the low resolution spectra will have spectrum "
246 "IDs offset from normal ones. ");
247 declareProperty(PropertyNames::PM_NAME, "__powdereduction", Direction::Input);
248}
249
250std::map<std::string, std::string> AlignAndFocusPowder::validateInputs() {
251 std::map<std::string, std::string> result;
252
253 if (!isDefault(PropertyNames::UNFOCUS_WKSP)) {
254 if (getPropertyValue(PropertyNames::OUTPUT_WKSP) == getPropertyValue(PropertyNames::UNFOCUS_WKSP)) {
255 result[PropertyNames::OUTPUT_WKSP] = "Cannot be the same as UnfocussedWorkspace";
256 result[PropertyNames::UNFOCUS_WKSP] = "Cannot be the same as OutputWorkspace";
257 }
258 }
259
260 if ((!isDefault(PropertyNames::RAGGED_DELTA)) && (!isDefault(PropertyNames::RESAMPLEX))) {
261 result[PropertyNames::RAGGED_DELTA] = "Cannot specify with " + PropertyNames::RESAMPLEX;
262 result[PropertyNames::RESAMPLEX] = "Cannot specify with " + PropertyNames::RAGGED_DELTA;
263 }
264
266 auto inputEW = std::dynamic_pointer_cast<EventWorkspace>(m_inputW);
267 if (inputEW && inputEW->getNumberEvents() <= 0)
268 result[PropertyNames::INPUT_WKSP] = "Empty workspace encounter, possibly due to beam down."
269 "Please plot the pCharge-time to identify suitable range for "
270 "re-time-slicing";
271
272 m_resonanceLower = getProperty(PropertyNames::RESONANCE_LOWER_LIMITS);
273 m_resonanceUpper = getProperty(PropertyNames::RESONANCE_UPPER_LIMITS);
274 // verify that they are the same length
275 if (m_resonanceLower.size() == m_resonanceUpper.size()) {
276 // verify that the lowers are less than the uppers
277 const size_t NUM_WINDOWS = m_resonanceLower.size();
278 bool ok = true;
279 for (size_t i = 0; i < NUM_WINDOWS; ++i) {
281 ok = false;
282 }
283 if (!ok) {
284 const std::string msg = "Lower limits must be less than upper limits";
285 result[PropertyNames::RESONANCE_LOWER_LIMITS] = msg;
286 result[PropertyNames::RESONANCE_UPPER_LIMITS] = msg;
287 }
288 } else {
289 result[PropertyNames::RESONANCE_LOWER_LIMITS] =
290 "Must have same number of values as " + PropertyNames::RESONANCE_UPPER_LIMITS;
291 result[PropertyNames::RESONANCE_UPPER_LIMITS] =
292 "Must have same number of values as " + PropertyNames::RESONANCE_LOWER_LIMITS;
293 }
294
295 // Deprecated properties
296 if (!isDefault(PropertyNames::UNWRAP_REF)) {
297 g_log.error("AlignAndFocusPowder property UnwrapRef is deprecated since 2025-03-24.");
298 }
299
300 return result;
301}
302
303template <typename NumT> struct RegLowVectorPair {
304 std::vector<NumT> reg;
305 std::vector<NumT> low;
306};
307
308template <typename NumT>
309RegLowVectorPair<NumT> splitVectors(const std::vector<NumT> &orig, const size_t numVal, const std::string &label) {
311
312 // check that there is work to do
313 if (!orig.empty()) {
314 // do the spliting
315 if (orig.size() == numVal) {
316 out.reg.assign(orig.begin(), orig.end());
317 out.low.assign(orig.begin(), orig.end());
318 } else if (orig.size() == 2 * numVal) {
319 out.reg.assign(orig.begin(), orig.begin() + numVal);
320 out.low.assign(orig.begin() + numVal, orig.begin());
321 } else {
322 std::stringstream msg;
323 msg << "Input number of " << label << " ids is not equal to "
324 << "the number of histograms or empty (" << orig.size() << " != 0 or " << numVal << " or " << (2 * numVal)
325 << ")";
326 throw std::runtime_error(msg.str());
327 }
328 }
329 return out;
330}
331
332//----------------------------------------------------------------------------------------------
343double AlignAndFocusPowder::getVecPropertyFromPmOrSelf(const std::string &name, std::vector<double> &avec) {
344 avec = getProperty(name);
345 if (!avec.empty()) {
346 return avec[0];
347 }
348 // No overrides provided.
349 return 0.0;
350}
351
352//----------------------------------------------------------------------------------------------
360 // retrieve the properties
362 m_instName = m_inputW->getInstrument()->getName();
363 try {
364 m_instName = Kernel::ConfigService::Instance().getInstrument(m_instName).shortName();
365 } catch (Exception::NotFoundError &) {
366 ; // not noteworthy
367 }
368 std::string calFilename = getPropertyValue(PropertyNames::CAL_FILE);
369 std::string groupFilename = getPropertyValue(PropertyNames::GROUP_FILE);
370 m_calibrationWS = getProperty(PropertyNames::CAL_WKSP);
371 m_maskWS = getProperty(PropertyNames::MASK_WKSP);
372 m_groupWS = getProperty(PropertyNames::GROUP_WKSP);
373 DataObjects::TableWorkspace_sptr maskBinTableWS = getProperty(PropertyNames::MASK_TABLE);
374 m_l1 = getProperty(PropertyNames::L1);
375 specids = getProperty(PropertyNames::SPEC_IDS);
376 l2s = getProperty(PropertyNames::L2);
377 tths = getProperty(PropertyNames::POLAR);
378 phis = getProperty(PropertyNames::AZIMUTHAL);
379 m_params = getProperty(PropertyNames::BINNING);
380 binInDspace = getProperty(PropertyNames::BIN_IN_D);
381 auto dmin = getVecPropertyFromPmOrSelf(PropertyNames::D_MINS, m_dmins);
382 auto dmax = getVecPropertyFromPmOrSelf(PropertyNames::D_MAXS, m_dmaxs);
383 this->getVecPropertyFromPmOrSelf(PropertyNames::RAGGED_DELTA, m_delta_ragged);
384 DIFCref = getProperty(PropertyNames::LOWRES_REF);
385 const bool applyLorentz = getProperty(PropertyNames::LORENTZ);
386 minwl = getProperty(PropertyNames::WL_MIN);
387 maxwl = getProperty(PropertyNames::WL_MAX);
388 if (maxwl == 0.)
389 maxwl = EMPTY_DBL(); // python can only specify 0 for unused
390 tmin = getProperty(PropertyNames::TOF_MIN);
391 tmax = getProperty(PropertyNames::TOF_MAX);
392 m_preserveEvents = getProperty(PropertyNames::PRESERVE_EVENTS);
393 m_resampleX = getProperty(PropertyNames::RESAMPLEX);
394 double compressEventsTolerance = getProperty(PropertyNames::COMPRESS_TOF_TOL);
395 const double wallClockTolerance = getProperty(PropertyNames::COMPRESS_WALL_TOL);
396 const BINMODE mode = getPropertyValue(PropertyNames::COMPRESS_MODE);
397 if (mode == BinningMode::LINEAR)
398 compressEventsTolerance = std::fabs(compressEventsTolerance);
399 else if (mode == BinningMode::LOGARITHMIC)
400 compressEventsTolerance = -1. * std::fabs(compressEventsTolerance);
401
402 // determine some bits about d-space and binning
403 if (m_resampleX != 0) {
404 // ignore the normal rebin parameters
405 m_params.clear();
406 } else if (m_params.size() == 1 && m_delta_ragged.empty()) {
407 // if there is 1 binning parameter and not in ragged rebinning mode
408 // ignore what people asked for
409 binInDspace = bool(dmax > 0.);
410 }
411 if (binInDspace) {
412 if (m_params.size() == 1 && (!isEmpty(dmin)) && (!isEmpty(dmax))) {
413 if (dmin > 0. && dmax > dmin) {
414 double step = m_params[0];
415 m_params.clear();
416 m_params.emplace_back(dmin);
417 m_params.emplace_back(step);
418 m_params.emplace_back(dmax);
419 g_log.information() << "d-Spacing binning updated: " << m_params[0] << " " << m_params[1] << " "
420 << m_params[2] << "\n";
421 } else {
422 g_log.warning() << "something is wrong with dmin (" << dmin << ") and dmax (" << dmax
423 << "). They are being ignored.\n";
424 }
425 }
426 } else {
427 if (m_params.size() == 1 && (!isEmpty(tmin)) && (!isEmpty(tmax))) {
428 if (tmin > 0. && tmax > tmin) {
429 double step = m_params[0];
430 m_params[0] = tmin;
431 m_params.emplace_back(step);
432 m_params.emplace_back(tmax);
433 g_log.information() << "TOF binning updated: " << m_params[0] << " " << m_params[1] << " " << m_params[2]
434 << "\n";
435 } else {
436 g_log.warning() << "something is wrong with tmin (" << tmin << ") and tmax (" << tmax
437 << "). They are being ignored.\n";
438 }
439 }
440 }
441 xmin = 0.;
442 xmax = 0.;
443 if (tmin > 0.) {
444 xmin = tmin;
445 }
446 if (tmax > 0.) {
447 xmax = tmax;
448 }
449 if (!binInDspace && m_params.size() == 3) {
450 xmin = m_params[0];
451 xmax = m_params[2];
452 }
453
454 // Low resolution
455 int lowresoffset = getProperty(PropertyNames::LOWRES_SPEC_OFF);
456 if (lowresoffset < 0) {
457 m_processLowResTOF = false;
458 } else {
459 m_processLowResTOF = true;
460 m_lowResSpecOffset = static_cast<size_t>(lowresoffset);
461 }
462
463 loadCalFile(calFilename, groupFilename);
464
465 // Now setup the output workspace
467 if (auto inputEW = std::dynamic_pointer_cast<EventWorkspace>(m_inputW)) {
468 // event workspace
469 if (m_outputW != m_inputW) {
470 // out-of-place: clone the input EventWorkspace
471 EventWorkspace_sptr outputEW = inputEW->clone();
472 m_outputW = std::dynamic_pointer_cast<MatrixWorkspace>(outputEW);
473 } // in-place doesn't require anything
474 } else {
475 // workspace2D
476 if (m_outputW != m_inputW) {
477 m_outputW = m_inputW->clone();
478 }
479 }
480
481 if (m_processLowResTOF) {
482 if (auto inputEW = std::dynamic_pointer_cast<EventWorkspace>(m_inputW)) {
483 // Make a brand new EventWorkspace
484 m_lowResEW = std::dynamic_pointer_cast<EventWorkspace>(
485 WorkspaceFactory::Instance().create("EventWorkspace", inputEW->getNumberHistograms(), 2, 1));
486
487 // Cast to the matrixOutputWS and save it
488 m_lowResW = std::dynamic_pointer_cast<MatrixWorkspace>(m_lowResEW);
489 // m_lowResW->setName(lowreswsname);
490 } else {
491 throw std::runtime_error("Input workspace is not EventWorkspace. It is not supported now.");
492 }
493 }
494
495 // set up a progress bar with the "correct" number of steps
496 m_progress = std::make_unique<Progress>(this, 0., 1., 21);
497
498 if (m_maskWS) {
499 g_log.information() << "running MaskDetectors started at " << Types::Core::DateAndTime::getCurrentTime() << "\n";
500
501 API::IAlgorithm_sptr maskDetAlg = createChildAlgorithm("MaskDetectors");
502 // cast to Workspace for MaksDetectors alg
503 Workspace_sptr outputw = std::dynamic_pointer_cast<Workspace>(m_outputW);
504 maskDetAlg->setProperty("Workspace", outputw);
505 MatrixWorkspace_sptr mksws = std::dynamic_pointer_cast<MatrixWorkspace>(m_maskWS);
506 maskDetAlg->setProperty("MaskedWorkspace", mksws);
507 maskDetAlg->executeAsChildAlg();
508 outputw = maskDetAlg->getProperty("Workspace");
509 // casting
510 m_outputW = std::dynamic_pointer_cast<MatrixWorkspace>(outputw);
511 }
512 m_progress->report();
513
514 // hold onto over tof range for CropWorkspace(tof) and RemovePromptPulse
515 double tofmin = EMPTY_DBL();
516 double tofmax = EMPTY_DBL();
517
518 // crop the workspace in time-of-flight
519 if (((!isEmpty(xmin)) && (xmin >= 0.)) || ((!isEmpty(xmax)) && (xmax > 0.))) {
520 getTofRange(m_outputW, tofmin, tofmax);
521
522 API::IAlgorithm_sptr cropAlg = createChildAlgorithm("CropWorkspace");
523 cropAlg->setProperty("InputWorkspace", m_outputW);
524 cropAlg->setProperty("OutputWorkspace", m_outputW);
525 bool setxmin = false;
526 if ((xmin >= 0.) && (xmin > tofmin)) {
527 cropAlg->setProperty("Xmin", xmin);
528 tofmin = xmin; // increase value
529 setxmin = true;
530 }
531 bool setxmax = false;
532 if ((xmax > 0.) && (xmax < tofmax)) {
533 cropAlg->setProperty("Xmax", xmax);
534 tofmax = xmax;
535 setxmax = true;
536 }
537 // only run if either xmin or xmax was set
538 if (setxmin || setxmax) {
539 g_log.information() << "running CropWorkspace(TOFmin=" << xmin << ", TOFmax=" << xmax << ") started at "
540 << Types::Core::DateAndTime::getCurrentTime() << "\n";
541 cropAlg->executeAsChildAlg();
542 m_outputW = cropAlg->getProperty("OutputWorkspace");
543 }
544 }
545 m_progress->report();
546
547 // filter the input events if appropriate
548 const double removePromptPulseWidth = getProperty(PropertyNames::REMOVE_PROMPT_PULSE);
549 if (removePromptPulseWidth > 0.) {
550 bool removePromptPulse(false);
551 if (auto outputEW = std::dynamic_pointer_cast<EventWorkspace>(m_outputW)) {
552 removePromptPulse = (outputEW->getNumberEvents() > 0);
553 }
554 if (removePromptPulse) {
555 g_log.information() << "running RemovePromptPulse(Width=" << removePromptPulseWidth << ") started at "
556 << Types::Core::DateAndTime::getCurrentTime() << "\n";
557 API::IAlgorithm_sptr filterPAlg = createChildAlgorithm("RemovePromptPulse");
558 filterPAlg->setProperty("InputWorkspace", m_outputW);
559 filterPAlg->setProperty("OutputWorkspace", m_outputW);
560 filterPAlg->setProperty("Width", removePromptPulseWidth);
561
562 // if some of the range was known in CropWorkspace-TOF, use it again here
563 // they default to EMPTY_DBL which the alg interprets as unset
564 filterPAlg->setProperty("TMin", tofmin);
565 filterPAlg->setProperty("TMax", tofmax);
566
567 filterPAlg->executeAsChildAlg();
568 m_outputW = filterPAlg->getProperty("OutputWorkspace");
569 } else {
570 g_log.information("skipping RemovePromptPulse on empty EventWorkspace");
571 }
572 }
573 m_progress->report();
574
575 if (maskBinTableWS) {
576 g_log.information() << "running MaskBinsFromTable started at " << Types::Core::DateAndTime::getCurrentTime()
577 << "\n";
578 API::IAlgorithm_sptr alg = createChildAlgorithm("MaskBinsFromTable");
579 alg->setProperty("InputWorkspace", m_outputW);
580 alg->setProperty("OutputWorkspace", m_outputW);
581 alg->setProperty("MaskingInformation", maskBinTableWS);
582 alg->executeAsChildAlg();
583 m_outputW = alg->getProperty("OutputWorkspace");
584 }
585 m_progress->report();
586
587 // do a calculation to determine if compressing the un-focussed data will reduce data size
588 if (shouldCompressUnfocused(compressEventsTolerance, tofmin, tofmax, !isEmpty(wallClockTolerance))) {
589 compressEventsOutputWS(compressEventsTolerance, wallClockTolerance);
590 }
591
592 if (!binInDspace)
594 m_progress->report();
595
596 if (m_calibrationWS) {
597 // ApplyDiffCal and update m_outputW
598 g_log.information() << "apply calibration workspace to input workspace at "
599 << Types::Core::DateAndTime::getCurrentTime() << "\n";
600 Workspace_sptr outputw = std::dynamic_pointer_cast<Workspace>(m_outputW);
601 API::IAlgorithm_sptr applyDiffCalAlg = createChildAlgorithm("ApplyDiffCal");
602 applyDiffCalAlg->setProperty("InstrumentWorkspace", outputw);
603 applyDiffCalAlg->setProperty("CalibrationWorkspace", m_calibrationWS);
604 applyDiffCalAlg->executeAsChildAlg();
605 // grab and cast
606 outputw = applyDiffCalAlg->getProperty("InstrumentWorkspace");
607 m_outputW = std::dynamic_pointer_cast<MatrixWorkspace>(outputw);
608 }
609
610 m_progress->report();
611
612 m_outputW = convertUnits(m_outputW, "dSpacing");
613 m_progress->report();
614
615 if (m_calibrationWS) {
616 // NOTE:
617 // The conventional workflow for AlignAndFocusPowder allows users to modify the instrument so that the averaged
618 // pixel position can be used when converting back to TOF.
619 // With the recent changes in Unit.h, Mantid is using the averaged DIFC attached to workspace to convert from
620 // d-spacing to TOF by default, which unfortunately breaks the intended workflow here.
621 // To bypass this issue, we are going to remove the attached paramter map so taht Unit.h cannot perform the default
622 // conversion, which will effectively forcing Mantid to revert back to the original intended method.
623 Workspace_sptr outputw = std::dynamic_pointer_cast<Workspace>(m_outputW);
624 API::IAlgorithm_sptr applyDiffCalAlg = createChildAlgorithm("ApplyDiffCal");
625 applyDiffCalAlg->setProperty("InstrumentWorkspace", outputw);
626 applyDiffCalAlg->setProperty("ClearCalibration", true);
627 applyDiffCalAlg->executeAsChildAlg();
628 // grab and cast
629 outputw = applyDiffCalAlg->getProperty("InstrumentWorkspace");
630 m_outputW = std::dynamic_pointer_cast<MatrixWorkspace>(outputw);
631 }
632
633 // filter out absorption resonances
634 if (!m_resonanceLower.empty()) {
636 }
637 m_progress->report(); // the step wil be really fast if the option isn't selected
638
639 // ----------------- WACKY LORENTZ THING HERE
640 // TODO should call LorentzCorrection as a sub-algorithm
641 if (applyLorentz) {
642 g_log.information() << "Applying Lorentz correction started at " << Types::Core::DateAndTime::getCurrentTime()
643 << "\n";
644
645 API::IAlgorithm_sptr alg = createChildAlgorithm("LorentzCorrection");
646 alg->setProperty("InputWorkspace", m_outputW);
647 alg->setProperty("OutputWorkspace", m_outputW);
648 alg->setPropertyValue("Type", "PowderTOF");
649 alg->executeAsChildAlg();
650 m_outputW = alg->getProperty("OutputWorkspace");
651 }
652
653 m_progress->report();
654
655 // Beyond this point, low resolution TOF workspace is considered.
656 if (minwl > 0. || (!isEmpty(maxwl))) { // just crop the workspace
657 // turn off the low res stuff
658 m_processLowResTOF = false;
659
660 if (const auto ews = std::dynamic_pointer_cast<EventWorkspace>(m_outputW))
661 g_log.information() << "Number of events = " << ews->getNumberEvents() << ".\n";
662
663 m_outputW = convertUnits(m_outputW, "Wavelength");
664
665 g_log.information() << "running CropWorkspace(WavelengthMin=" << minwl;
666 if (!isEmpty(maxwl))
667 g_log.information() << ", WavelengthMax=" << maxwl;
668 g_log.information() << ") started at " << Types::Core::DateAndTime::getCurrentTime() << "\n";
669
670 API::IAlgorithm_sptr removeAlg = createChildAlgorithm("CropWorkspace");
671 removeAlg->setProperty("InputWorkspace", m_outputW);
672 removeAlg->setProperty("OutputWorkspace", m_outputW);
673 removeAlg->setProperty("XMin", minwl);
674 removeAlg->setProperty("XMax", maxwl);
675 removeAlg->executeAsChildAlg();
676 m_outputW = removeAlg->getProperty("OutputWorkspace");
677 if (const auto ews = std::dynamic_pointer_cast<EventWorkspace>(m_outputW))
678 g_log.information() << "Number of events = " << ews->getNumberEvents() << ".\n";
679 } else if (DIFCref > 0.) {
681 // this correction has some assumptions on the events being compressed
682 compressEventsOutputWS(compressEventsTolerance, wallClockTolerance);
683
684 // this is a legacy way for describing the minimum wavelength to remove from the data
685 // it is uncommon that it is used
686 g_log.information() << "running RemoveLowResTof(RefDIFC=" << DIFCref << ",K=3.22) started at "
687 << Types::Core::DateAndTime::getCurrentTime() << "\n";
688 if (const auto ews = std::dynamic_pointer_cast<EventWorkspace>(m_outputW))
689 g_log.information() << "Number of events = " << ews->getNumberEvents() << ".\n";
690
691 API::IAlgorithm_sptr removeAlg = createChildAlgorithm("RemoveLowResTOF");
692 removeAlg->setProperty("InputWorkspace", m_outputW);
693 removeAlg->setProperty("OutputWorkspace", m_outputW);
694 removeAlg->setProperty("ReferenceDIFC", DIFCref);
695 removeAlg->setProperty("K", 3.22);
696 if (tmin > 0.)
697 removeAlg->setProperty("Tmin", tmin);
699 removeAlg->setProperty("LowResTOFWorkspace", m_lowResW);
700
701 removeAlg->executeAsChildAlg();
702 m_outputW = removeAlg->getProperty("OutputWorkspace");
704 m_lowResW = removeAlg->getProperty("LowResTOFWorkspace");
705 }
706 m_progress->report();
707
708 if (const auto ews = std::dynamic_pointer_cast<EventWorkspace>(m_outputW)) {
709 const size_t numhighevents = ews->getNumberEvents();
710 if (m_processLowResTOF) {
711 EventWorkspace_sptr lowes = std::dynamic_pointer_cast<EventWorkspace>(m_lowResW);
712 const size_t numlowevents = lowes->getNumberEvents();
713 g_log.information() << "Number of high TOF events = " << numhighevents << "; "
714 << "Number of low TOF events = " << numlowevents << ".\n";
715 }
716 }
717 m_progress->report();
718
719 // Convert units
720 if (minwl > 0. || DIFCref > 0. || (!isEmpty(maxwl))) {
721 m_outputW = convertUnits(m_outputW, "dSpacing");
723 m_lowResW = convertUnits(m_lowResW, "dSpacing");
724 }
725 m_progress->report();
726
727 if (binInDspace) {
731 }
732 m_progress->report();
733
734 // copy the output workspace just before `DiffractionFocusing`
735 // this probably should be binned by callers before inspecting
736 if (!isDefault("UnfocussedWorkspace")) {
737 auto wkspCopy = m_outputW->clone();
738 setProperty("UnfocussedWorkspace", std::move(wkspCopy));
739 }
740
741 if (binInDspace && m_resampleX == 0 && !m_delta_ragged.empty() && !m_dmins.empty() && !m_dmaxs.empty()) {
742 // Special case where we can do ragged rebin within diffraction focus
746 m_progress->report();
747 } else {
748 // Diffraction focus
752 m_progress->report();
753
754 // this next call should probably be in for rebin as well
755 // but it changes the system tests
756 if (binInDspace) {
757 if (m_resampleX != 0.) {
761 } else if (!m_delta_ragged.empty()) {
765 }
766 }
767 }
768 m_progress->report();
769
770 // edit the instrument geometry
771 if (m_groupWS && (m_l1 > 0 || !tths.empty() || !l2s.empty() || !phis.empty())) {
772 size_t numreg = m_outputW->getNumberHistograms();
773
774 try {
775 // set up the vectors for doing everything
776 auto specidsSplit = splitVectors(specids, numreg, "specids");
777 auto tthsSplit = splitVectors(tths, numreg, "two-theta");
778 auto l2sSplit = splitVectors(l2s, numreg, "L2");
779 auto phisSplit = splitVectors(phis, numreg, "phi");
780
781 // Edit instrument
782 m_outputW = editInstrument(m_outputW, tthsSplit.reg, specidsSplit.reg, l2sSplit.reg, phisSplit.reg);
783
784 if (m_processLowResTOF) {
785 m_lowResW = editInstrument(m_lowResW, tthsSplit.low, specidsSplit.low, l2sSplit.low, phisSplit.low);
786 }
787 } catch (std::runtime_error &e) {
788 g_log.warning("Not editing instrument geometry:");
789 g_log.warning(e.what());
790 }
791 }
792 m_progress->report();
793
794 // Conjoin 2 workspaces if there is low resolution
795 if (m_processLowResTOF) {
797 }
798 m_progress->report();
799
800 // Convert units to TOF
802 m_progress->report();
803
804 // compress again if appropriate
805 compressEventsOutputWS(compressEventsTolerance, wallClockTolerance);
806 m_progress->report();
807
808 if (!binInDspace && !m_delta_ragged.empty()) {
810 }
811
812 // return the output workspace
813 setProperty("OutputWorkspace", m_outputW);
814}
815
816//----------------------------------------------------------------------------------------------
820 const std::vector<double> &polars,
821 const std::vector<specnum_t> &specids,
822 const std::vector<double> &l2s,
823 const std::vector<double> &phis) {
824 g_log.information() << "running EditInstrumentGeometry started at " << Types::Core::DateAndTime::getCurrentTime()
825 << "\n";
826
827 API::IAlgorithm_sptr editAlg = createChildAlgorithm("EditInstrumentGeometry");
828 editAlg->setProperty("Workspace", ws);
829 if (m_l1 > 0.)
830 editAlg->setProperty("PrimaryFlightPath", m_l1);
831 if (!polars.empty())
832 editAlg->setProperty("Polar", polars);
833 if (!specids.empty())
834 editAlg->setProperty("SpectrumIDs", specids);
835 if (!l2s.empty())
836 editAlg->setProperty("L2", l2s);
837 if (!phis.empty())
838 editAlg->setProperty("Azimuthal", phis);
839 editAlg->executeAsChildAlg();
840
841 ws = editAlg->getProperty("Workspace");
842
843 return ws;
844}
845
846//----------------------------------------------------------------------------------------------
850 if (!m_groupWS) {
851 g_log.information() << "not focussing data\n";
852 return ws;
853 }
854
855 // cannot convert to histogram if running with ragged bins
856 // otherwise the data is a histogram *before* the correct binning is set
857 const bool preserveEvents = m_delta_ragged.empty() ? m_preserveEvents : true;
858
859 g_log.information() << "running DiffractionFocussing(PreserveEvents=" << preserveEvents << ") started at "
860 << Types::Core::DateAndTime::getCurrentTime() << "\n";
861
862 API::IAlgorithm_sptr focusAlg = createChildAlgorithm("DiffractionFocussing");
863 focusAlg->setProperty("InputWorkspace", ws);
864 focusAlg->setProperty("OutputWorkspace", ws);
865 focusAlg->setProperty("GroupingWorkspace", m_groupWS);
866 focusAlg->setProperty("PreserveEvents", preserveEvents);
867 focusAlg->executeAsChildAlg();
868 ws = focusAlg->getProperty("OutputWorkspace");
869
870 return ws;
871}
872
873//----------------------------------------------------------------------------------------------
877 if (!m_groupWS) {
878 g_log.information() << "not focussing data\n";
879 return ws;
880 }
881
882 API::IAlgorithm_sptr focusAlg = createChildAlgorithm("DiffractionFocussing");
883 focusAlg->setProperty("InputWorkspace", ws);
884 focusAlg->setProperty("OutputWorkspace", ws);
885 focusAlg->setProperty("GroupingWorkspace", m_groupWS);
886 focusAlg->setProperty("PreserveEvents", m_preserveEvents);
887 focusAlg->setProperty("DMin", m_dmins);
888 focusAlg->setProperty("DMax", m_dmaxs);
889 focusAlg->setProperty("Delta", m_delta_ragged);
890
891 g_log.information() << "running DiffractionFocussing(PreserveEvents=" << m_preserveEvents;
892 g_log.information() << " XMin=" << focusAlg->getPropertyValue("DMin");
893 g_log.information() << " XMax=" << focusAlg->getPropertyValue("DMax");
894 g_log.information() << " Delta=" << focusAlg->getPropertyValue("Delta");
895 g_log.information() << ") started at " << Types::Core::DateAndTime::getCurrentTime() << "\n";
896
897 focusAlg->executeAsChildAlg();
898 ws = focusAlg->getProperty("OutputWorkspace");
899
900 return ws;
901}
902//----------------------------------------------------------------------------------------------
906 const std::string &target) {
907 g_log.information() << "running ConvertUnits(Target=" << target << ") started at "
908 << Types::Core::DateAndTime::getCurrentTime() << "\n";
909
910 API::IAlgorithm_sptr convert2Alg = createChildAlgorithm("ConvertUnits");
911 convert2Alg->setProperty("InputWorkspace", matrixws);
912 convert2Alg->setProperty("OutputWorkspace", matrixws);
913 convert2Alg->setProperty("Target", target);
914 convert2Alg->executeAsChildAlg();
915
916 matrixws = convert2Alg->getProperty("OutputWorkspace");
917
918 return matrixws;
919}
920
922 // determine the previous units
923 const std::string PREVIOUS_UNITS(matrixws->getAxis(0)->unit()->unitID());
924 // number of resonance windows to be removed
925 const size_t NUM_WINDOWS = m_resonanceLower.size();
926
927 // convert to the units requested
928 matrixws = convertUnits(matrixws, getPropertyValue(PropertyNames::RESONANCE_UNITS));
929
930 // filter out the requested area
931 API::IAlgorithm_sptr maskBinsAlg = createChildAlgorithm("MaskBins");
932 for (size_t i = 0; i < NUM_WINDOWS; ++i) {
933 g_log.information() << "running MaskBins(XMin=" << m_resonanceLower[i] << ", XMax=" << m_resonanceUpper[i]
934 << ") started at " << Types::Core::DateAndTime::getCurrentTime() << "\n";
935 maskBinsAlg->setProperty("InputWorkspace", matrixws);
936 maskBinsAlg->setProperty("OutputWorkspace", matrixws); // operate in-place
937 maskBinsAlg->setProperty("XMin", m_resonanceLower[i]);
938 maskBinsAlg->setProperty("XMax", m_resonanceUpper[i]);
939 maskBinsAlg->executeAsChildAlg();
940
941 matrixws = maskBinsAlg->getProperty("OutputWorkspace"); // update workspace pointer
942 }
943
944 // convert back to the original units
945 matrixws = convertUnits(matrixws, PREVIOUS_UNITS);
946
947 return matrixws;
948}
949
950//----------------------------------------------------------------------------------------------
954 if (!m_delta_ragged.empty()) {
955 return matrixws;
956 } else if (m_resampleX != 0) {
957 // ResampleX
958 g_log.information() << "running ResampleX(NumberBins=" << abs(m_resampleX) << ", LogBinning=" << (m_resampleX < 0)
959 << ", dMin(" << m_dmins.size() << "), dmax(" << m_dmaxs.size() << ")) started at "
960 << Types::Core::DateAndTime::getCurrentTime() << "\n";
962 alg->setProperty("InputWorkspace", matrixws);
963 alg->setProperty("OutputWorkspace", matrixws);
964 if ((!m_dmins.empty()) && (!m_dmaxs.empty())) {
965 size_t numHist = m_outputW->getNumberHistograms();
966 if ((numHist == m_dmins.size()) && (numHist == m_dmaxs.size())) {
967 alg->setProperty("XMin", m_dmins);
968 alg->setProperty("XMax", m_dmaxs);
969 } else {
970 g_log.information() << "Number of dmin and dmax values don't match the "
971 << "number of workspace indices. Ignoring the parameters.\n";
972 }
973 }
974 alg->setProperty("NumberBins", abs(m_resampleX));
975 alg->setProperty("LogBinning", (m_resampleX < 0));
976 alg->executeAsChildAlg();
977 matrixws = alg->getProperty("OutputWorkspace");
978 return matrixws;
979 } else {
980 g_log.information() << "running Rebin( ";
981 for (double param : m_params)
982 g_log.information() << param << " ";
983 g_log.information() << ") started at " << Types::Core::DateAndTime::getCurrentTime() << "\n";
984 for (double param : m_params)
985 if (isEmpty(param))
986 g_log.warning("encountered empty binning parameter");
987
988 API::IAlgorithm_sptr rebin3Alg = createChildAlgorithm("Rebin");
989 rebin3Alg->setProperty("InputWorkspace", matrixws);
990 rebin3Alg->setProperty("OutputWorkspace", matrixws);
991 rebin3Alg->setProperty("Params", m_params);
992 rebin3Alg->executeAsChildAlg();
993 matrixws = rebin3Alg->getProperty("OutputWorkspace");
994 return matrixws;
995 }
996}
997
998//----------------------------------------------------------------------------------------------
1002 // local variables to control whether or not to log individual values
1003 bool print_xmin = false;
1004 bool print_xmax = false;
1005
1006 // configure RebinRagged
1007 API::IAlgorithm_sptr alg = createChildAlgorithm("RebinRagged");
1008 if (inDspace) {
1009 if (!m_dmins.empty()) {
1010 print_xmin = true;
1011 alg->setProperty("XMin", m_dmins);
1012 }
1013 if (!m_dmaxs.empty()) {
1014 print_xmax = true;
1015 alg->setProperty("XMax", m_dmaxs);
1016 }
1017 } else { // assume time-of-flight
1018 if (tmin > 0.) {
1019 print_xmin = true;
1020 // wacky syntax to set a single value to an ArrayProperty
1021 alg->setProperty("XMin", std::vector<double>(1, tmin));
1022 }
1023 if (tmax > 0. && tmax > tmin) {
1024 print_xmax = true;
1025 // wacky syntax to set a single value to an ArrayProperty
1026 alg->setProperty("XMax", std::vector<double>(1, tmax));
1027 }
1028 }
1029 alg->setProperty("Delta", m_delta_ragged);
1030 alg->setProperty("InputWorkspace", matrixws);
1031 alg->setProperty("OutputWorkspace", matrixws);
1032 alg->setProperty("PreserveEvents", m_preserveEvents);
1033
1034 // log the parameters used
1035 g_log.information() << "running RebinRagged(";
1036 if (print_xmin)
1037 g_log.information() << " XMin=" << alg->getPropertyValue("XMin");
1038 if (print_xmax)
1039 g_log.information() << " XMax=" << alg->getPropertyValue("XMax");
1040 g_log.information() << " Delta=" << alg->getPropertyValue("Delta");
1041 g_log.information() << " ) started at " << Types::Core::DateAndTime::getCurrentTime() << "\n";
1042
1043 // run the algorithm and get the result back
1044 alg->executeAsChildAlg();
1045 matrixws = alg->getProperty("OutputWorkspace");
1046 return matrixws;
1047}
1048
1049//----------------------------------------------------------------------------------------------
1053 const API::MatrixWorkspace_sptr &ws2, size_t offset) {
1054 // Get information from ws1: maximum spectrum number, and store original
1055 // spectrum Nos
1056 size_t nspec1 = ws1->getNumberHistograms();
1057 specnum_t maxspecNo1 = 0;
1058 std::vector<specnum_t> origspecNos;
1059 for (size_t i = 0; i < nspec1; ++i) {
1060 specnum_t tmpspecNo = ws1->getSpectrum(i).getSpectrumNo();
1061 origspecNos.emplace_back(tmpspecNo);
1062 if (tmpspecNo > maxspecNo1)
1063 maxspecNo1 = tmpspecNo;
1064 }
1065
1066 g_log.information() << "[DBx536] Max spectrum number of ws1 = " << maxspecNo1 << ", Offset = " << offset << ".\n";
1067
1068 size_t nspec2 = ws2->getNumberHistograms();
1069
1070 // Conjoin 2 workspaces
1071 Algorithm_sptr alg = this->createChildAlgorithm("AppendSpectra");
1072 alg->initialize();
1073 ;
1074
1075 alg->setProperty("InputWorkspace1", ws1);
1076 alg->setProperty("InputWorkspace2", ws2);
1077 alg->setProperty("OutputWorkspace", ws1);
1078 alg->setProperty("ValidateInputs", false);
1079
1080 alg->executeAsChildAlg();
1081
1082 API::MatrixWorkspace_sptr outws = alg->getProperty("OutputWorkspace");
1083
1084 // FIXED : Restore the original spectrum Nos to spectra from ws1
1085 for (size_t i = 0; i < nspec1; ++i) {
1086 specnum_t tmpspecNo = outws->getSpectrum(i).getSpectrumNo();
1087 outws->getSpectrum(i).setSpectrumNo(origspecNos[i]);
1088
1089 g_log.information() << "[DBx540] Conjoined spectrum " << i << ": restore spectrum number to "
1090 << outws->getSpectrum(i).getSpectrumNo() << " from spectrum number = " << tmpspecNo << ".\n";
1091 }
1092
1093 // Rename spectrum number
1094 if (offset >= 1) {
1095 for (size_t i = 0; i < nspec2; ++i) {
1096 specnum_t newspecid = maxspecNo1 + static_cast<specnum_t>((i) + offset);
1097 outws->getSpectrum(nspec1 + i).setSpectrumNo(newspecid);
1098 // ISpectrum* spec = outws->getSpectrum(nspec1+i);
1099 // if (spec)
1100 // spec->setSpectrumNo(3);
1101 }
1102 }
1103
1104 return outws;
1105}
1106
1108 if (!offsetsWS)
1109 return;
1110
1111 IAlgorithm_sptr alg = createChildAlgorithm("ConvertDiffCal");
1112 alg->setProperty("OffsetsWorkspace", offsetsWS);
1113 alg->setPropertyValue("OutputWorkspace", m_instName + "_cal");
1114 alg->executeAsChildAlg();
1115
1116 m_calibrationWS = alg->getProperty("OutputWorkspace");
1117 AnalysisDataService::Instance().addOrReplace(m_instName + "_cal", m_calibrationWS);
1118}
1119
1120//----------------------------------------------------------------------------------------------
1124void AlignAndFocusPowder::loadCalFile(const std::string &calFilename, const std::string &groupFilename) {
1125
1126 // check if the workspaces exist with their canonical names so they are not
1127 // reloaded for chunks
1128 if ((!m_groupWS) && (!calFilename.empty()) && (!groupFilename.empty())) {
1129 if (AnalysisDataService::Instance().doesExist(m_instName + "_group"))
1130 m_groupWS = AnalysisDataService::Instance().retrieveWS<GroupingWorkspace>(m_instName + "_group");
1131 }
1132 if ((!m_calibrationWS) && (!calFilename.empty())) {
1133 OffsetsWorkspace_sptr offsetsWS = getProperty(PropertyNames::OFFSET_WKSP);
1134 if (offsetsWS) {
1135 convertOffsetsToCal(offsetsWS);
1136 } else {
1137 if (AnalysisDataService::Instance().doesExist(m_instName + "_cal"))
1138 m_calibrationWS = AnalysisDataService::Instance().retrieveWS<ITableWorkspace>(m_instName + "_cal");
1139 if (!m_calibrationWS) {
1140 if (AnalysisDataService::Instance().doesExist(m_instName + "_offsets")) {
1141 offsetsWS = AnalysisDataService::Instance().retrieveWS<OffsetsWorkspace>(m_instName + "_offsets");
1142 convertOffsetsToCal(offsetsWS);
1143 }
1144 }
1145 }
1146 }
1147 if ((!m_maskWS) && (!calFilename.empty())) {
1148 if (AnalysisDataService::Instance().doesExist(m_instName + "_mask"))
1149 m_maskWS = AnalysisDataService::Instance().retrieveWS<MaskWorkspace>(m_instName + "_mask");
1150 }
1151
1152 // see if everything exists to exit early
1154 return;
1155
1156 // see if the calfile or grouping file is specified
1157 if (calFilename.empty() && groupFilename.empty())
1158 return;
1159
1160 // bunch of booleans to keep track of things
1161 const bool loadMask = !m_maskWS;
1162 const bool loadGrouping = !m_groupWS;
1163 const bool loadCalibration = !m_calibrationWS;
1164
1165 if (calFilename.empty()) { // only load the grouping file
1166 g_log.information() << "Loading Grouping file \"" << groupFilename << "\"\n";
1167
1168 IAlgorithm_sptr alg = createChildAlgorithm("LoadDetectorsGroupingFile");
1169 alg->setProperty("InputFile", groupFilename);
1170 alg->setProperty("InputWorkspace", m_inputW);
1171 alg->executeAsChildAlg();
1172
1173 m_groupWS = alg->getProperty("OutputWorkspace");
1174 const std::string groupname = m_instName + "_group";
1175 AnalysisDataService::Instance().addOrReplace(groupname, m_groupWS);
1176 this->setPropertyValue(PropertyNames::GROUP_WKSP, groupname);
1177 } else { // let LoadDiffCal sort out everything
1178 g_log.information() << "Loading Calibration file \"" << calFilename << "\"";
1179 if (!groupFilename.empty())
1180 g_log.information() << "with grouping from \"" << groupFilename << "\"";
1181 g_log.information("");
1182
1183 IAlgorithm_sptr alg = createChildAlgorithm("LoadDiffCal");
1184 alg->setProperty("InputWorkspace", m_inputW);
1185 alg->setPropertyValue("Filename", calFilename);
1186 alg->setPropertyValue("GroupFilename", groupFilename);
1187 alg->setProperty<bool>("MakeCalWorkspace", loadCalibration);
1188 alg->setProperty<bool>("MakeGroupingWorkspace", loadGrouping);
1189 alg->setProperty<bool>("MakeMaskWorkspace", loadMask);
1190 alg->setProperty<double>("TofMin", getProperty("TMin"));
1191 alg->setProperty<double>("TofMax", getProperty("TMax"));
1192 alg->setPropertyValue("WorkspaceName", m_instName);
1193 alg->executeAsChildAlg();
1194
1195 // replace workspaces as appropriate
1196 if (loadGrouping) {
1197 m_groupWS = alg->getProperty("OutputGroupingWorkspace");
1198
1199 const std::string groupname = m_instName + "_group";
1200 AnalysisDataService::Instance().addOrReplace(groupname, m_groupWS);
1201 this->setPropertyValue(PropertyNames::GROUP_WKSP, groupname);
1202 }
1203 if (loadCalibration) {
1204 m_calibrationWS = alg->getProperty("OutputCalWorkspace");
1205
1206 const std::string calname = m_instName + "_cal";
1207 AnalysisDataService::Instance().addOrReplace(calname, m_calibrationWS);
1208 this->setPropertyValue(PropertyNames::CAL_WKSP, calname);
1209 }
1210 if (loadMask) {
1211 m_maskWS = alg->getProperty("OutputMaskWorkspace");
1212
1213 const std::string maskname = m_instName + "_mask";
1214 AnalysisDataService::Instance().addOrReplace(maskname, m_maskWS);
1215 this->setPropertyValue(PropertyNames::MASK_WKSP, maskname);
1216 }
1217 }
1218}
1219
1220void AlignAndFocusPowder::compressEventsOutputWS(const double compressEventsTolerance,
1221 const double wallClockTolerance) {
1222 if (compressEventsTolerance == 0.)
1223 return; // no compression is required
1224
1225 if (auto outputEW = std::dynamic_pointer_cast<EventWorkspace>(m_outputW)) {
1226 g_log.information() << "running CompressEvents(Tolerance=" << compressEventsTolerance;
1227 if (!isEmpty(wallClockTolerance))
1228 g_log.information() << " and WallClockTolerance=" << wallClockTolerance;
1229 g_log.information() << ") started at " << Types::Core::DateAndTime::getCurrentTime() << "\n";
1230 API::IAlgorithm_sptr compressAlg = createChildAlgorithm("CompressEvents");
1231 compressAlg->setProperty("InputWorkspace", outputEW);
1232 compressAlg->setProperty("OutputWorkspace", outputEW);
1233 compressAlg->setProperty("Tolerance", compressEventsTolerance);
1234 if (!isEmpty(wallClockTolerance)) {
1235 compressAlg->setProperty("WallClockTolerance", wallClockTolerance);
1236 compressAlg->setPropertyValue("StartTime", getPropertyValue(PropertyNames::COMPRESS_WALL_START));
1237 }
1238 compressAlg->executeAsChildAlg();
1239 outputEW = compressAlg->getProperty("OutputWorkspace");
1240 m_outputW = std::dynamic_pointer_cast<MatrixWorkspace>(outputEW);
1241 }
1242}
1243
1249bool AlignAndFocusPowder::shouldCompressUnfocused(const double compressTolerance, const double tofmin,
1250 const double tofmax, const bool hasWallClockTolerance) {
1251 // compressing to WEIGHTED (w/ time) is harder to predict
1252 if (hasWallClockTolerance)
1253 return false;
1254 // compressing isn't an option
1255 if (compressTolerance == 0.)
1256 return false;
1257
1258 if (const auto eventWS = std::dynamic_pointer_cast<const EventWorkspace>(m_outputW)) {
1259 // estimate the time-of-flight range for the data
1260 // if the parameters aren't supplied, get them from the workspace
1261 double tofmin_wksp = tofmin;
1262 double tofmax_wksp = tofmax;
1263 if (isEmpty(tofmin) || isEmpty(tofmax))
1264 getTofRange(m_outputW, tofmin_wksp, tofmax_wksp);
1265 const double tofRange = std::fabs(tofmax_wksp - tofmin_wksp);
1266
1267 // constants estimating size difference of various events
1268 constexpr double TOF_EVENT_BYTE_SIZE{static_cast<double>(sizeof(Types::Event::TofEvent))};
1269 constexpr double WEIGHTED_EVENT_BYTE_SIZE{static_cast<double>(sizeof(WeightedEvent))};
1270 constexpr double WEIGHTED_NOTIME_EVENT_BYTE_SIZE{static_cast<double>(sizeof(WeightedEventNoTime))};
1271
1272 // assume one frame although this is generically wrong
1273 // there are 3 fields in weighted events no time
1274 double sizeWeightedEventsEstimate;
1275 if (compressTolerance > 0) // linear
1276 sizeWeightedEventsEstimate = WEIGHTED_NOTIME_EVENT_BYTE_SIZE * tofRange / compressTolerance;
1277 else { // log
1278 if (tofmin_wksp < 0)
1279 return false; // log compression cannot have negative TOF values
1280
1281 if (tofmin_wksp == 0)
1282 tofmin_wksp = compressTolerance;
1283
1284 sizeWeightedEventsEstimate =
1285 WEIGHTED_NOTIME_EVENT_BYTE_SIZE * log(tofmax_wksp / tofmin_wksp) / log1p(abs(compressTolerance));
1286 }
1287
1288 double numEvents = static_cast<double>(eventWS->getNumberEvents());
1289 const auto eventType = eventWS->getEventType();
1290 if (eventType == API::EventType::TOF) {
1291 // there are two fields in tof
1292 numEvents *= TOF_EVENT_BYTE_SIZE;
1293 } else if (eventType == API::EventType::WEIGHTED) {
1294 // there are four fields in weighted w/ time
1295 numEvents *= WEIGHTED_EVENT_BYTE_SIZE;
1296 } else if (eventType == API::EventType::WEIGHTED_NOTIME) {
1297 // it looks like things are already compressed
1298 return false;
1299 } else {
1300 return false; // not coded for something else
1301 }
1302
1303 // there is an error as this doesn't account for the number of spectra, but this is meant to be
1304 // a rough calculation
1305 g_log.information() << "Calculation for compressing events early with size of events currently " << numEvents
1306 << " and comparing to " << sizeWeightedEventsEstimate << "\n";
1307 return sizeWeightedEventsEstimate < numEvents;
1308 } else {
1309 // fall-through is to not compress
1310 return false;
1311 }
1312}
1313
1314} // namespace Mantid::WorkflowAlgorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
A specialized class for dealing with file properties.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1) override
Create a Child Algorithm.
Kernel::IPropertyManager::TypedValue getProperty(const std::string &name) const override
Get the property held by this object.
std::string getPropertyValue(const std::string &name) const override
Get the property held by this object.
ITableWorkspace is an implementation of Workspace in which the data are organised in columns of same ...
Base MatrixWorkspace Abstract Class.
A property class for workspaces.
A GroupingWorkspace is a subclass of Workspace2D where each spectrum has a single number entry,...
An OffsetsWorkspace is a specialized Workspace2D where the Y value at each pixel is the offset to be ...
Info about a single neutron detection event, including a weight and error value, but excluding the pu...
Definition Events.h:91
Info about a single neutron detection event, including a weight and error value:
Definition Events.h:39
Support for a property that holds an array of values.
Exception for when an item is not found in a collection.
Definition Exception.h:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
This is a parent algorithm that uses several different child algorithms to perform it's task.
void exec() override
Executes the algorithm.
void loadCalFile(const std::string &calFilename, const std::string &groupFilename)
Loads the .cal file if necessary.
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
API::MatrixWorkspace_sptr diffractionFocusRaggedRebinInDspace(API::MatrixWorkspace_sptr ws)
Call diffraction focus to a matrix workspace with ragged rebin parameters.
DataObjects::GroupingWorkspace_sptr m_groupWS
bool shouldCompressUnfocused(const double compressTolerance, const double tofmin, const double tofmax, const bool hasWallClockTolerance)
Return true if a rough estimate suggests that the size of the events will be smaller after compressin...
API::MatrixWorkspace_sptr m_lowResW
Low resolution TOF matrix workspace.
void convertOffsetsToCal(DataObjects::OffsetsWorkspace_sptr &offsetsWS)
API::MatrixWorkspace_sptr editInstrument(API::MatrixWorkspace_sptr ws, const std::vector< double > &polars, const std::vector< specnum_t > &specids, const std::vector< double > &l2s, const std::vector< double > &phis)
Call edit instrument geometry.
size_t m_lowResSpecOffset
Offset to low resolution TOF spectra.
API::MatrixWorkspace_sptr diffractionFocus(API::MatrixWorkspace_sptr ws)
Call diffraction focus to a matrix workspace.
std::unique_ptr< API::Progress > m_progress
Progress reporting.
DataObjects::EventWorkspace_sptr m_lowResEW
Low resolution TOF event workspace.
API::MatrixWorkspace_sptr filterResonances(API::MatrixWorkspace_sptr matrixws)
Filter out absorption resonances.
API::MatrixWorkspace_sptr rebinRagged(API::MatrixWorkspace_sptr matrixws, const bool inDspace)
RebinRagged this should only be done on the final focussed workspace.
double getVecPropertyFromPmOrSelf(const std::string &name, std::vector< double > &avec)
Function to get a vector property either from a PropertyManager or the algorithm properties.
API::MatrixWorkspace_sptr convertUnits(API::MatrixWorkspace_sptr matrixws, const std::string &target)
Convert units.
bool m_processLowResTOF
Flag to process low resolution workspace.
API::MatrixWorkspace_sptr rebin(API::MatrixWorkspace_sptr matrixws)
Rebin.
void compressEventsOutputWS(const double compressEventsTolerance, const double wallClockTolerance)
API::MatrixWorkspace_sptr conjoinWorkspaces(const API::MatrixWorkspace_sptr &ws1, const API::MatrixWorkspace_sptr &ws2, size_t offset)
Add workspace2 to workspace1 by adding spectrum.
std::map< std::string, std::string > validateInputs() override
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition Algorithm.h:52
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::size_t numEvents(Nexus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const Nexus::NexusDescriptor &descriptor)
Get the number of events in the currently opened group.
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< OffsetsWorkspace > OffsetsWorkspace_sptr
shared pointer to the OffsetsWorkspace class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
const std::string BINMODE("BinningMode")
const std::string OUTPUT_WKSP("OutputWorkspace")
const std::string INPUT_WKSP("InputWorkspace")
RegLowVectorPair< NumT > splitVectors(const std::vector< NumT > &orig, const size_t numVal, const std::string &label)
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ InOut
Both an input & output workspace.
Definition Property.h:55
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54