Mantid
Loading...
Searching...
No Matches
AlignAndFocusPowderSlim.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2024 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 +
7
10#include "MantidAPI/Axis.h"
13#include "MantidAPI/Run.h"
14#include "MantidAPI/Sample.h"
38#include "MantidKernel/Timer.h"
39#include "MantidKernel/Unit.h"
40#include "MantidKernel/V3D.h"
42#include "MantidNexus/H5Util.h"
43
44#include <H5Cpp.h>
45#include <cctype>
46#include <numbers>
47#include <ranges>
48#include <regex>
49#include <vector>
50
72
73namespace { // anonymous namespace
74
75const std::string LOG_CHARGE_NAME("proton_charge");
76
77const std::vector<std::string> binningModeNames{"Logarithmic", "Linear"};
78enum class BinningMode { LOGARITHMIC, LINEAR, enum_count };
80
81const std::vector<std::string> unitNames{"dSpacing", "TOF", "MomentumTransfer"};
82enum class BinUnit { DSPACE, TOF, Q, enum_count };
84
85const std::string ENTRY_TOP_LEVEL("entry");
86
87// TODO refactor this to use the actual grouping
88double getFocussedPostion(const detid_t detid, const std::vector<double> &difc_focus,
89 std::map<detid_t, size_t> &detIDToSpecNum) {
90 if (detIDToSpecNum.contains(detid)) {
91 return difc_focus[detIDToSpecNum[detid]];
92 } else {
93 return IGNORE_PIXEL;
94 }
95}
96
97std::vector<double> calculate_difc_focused(const double l1, const std::vector<double> &l2s,
98 const std::vector<double> &polars) {
99 constexpr double deg2rad = std::numbers::pi_v<double> / 180.;
100
101 std::vector<double> difc;
102
103 std::transform(l2s.cbegin(), l2s.cend(), polars.cbegin(), std::back_inserter(difc),
104 [l1, deg2rad](const auto &l2, const auto &polar) {
105 return 1. / Kernel::Units::tofToDSpacingFactor(l1, l2, deg2rad * polar, 0.);
106 });
107
108 return difc;
109}
110
111} // namespace
112
113// Register the algorithm into the AlgorithmFactory
114DECLARE_ALGORITHM(AlignAndFocusPowderSlim)
115
116//----------------------------------------------------------------------------------------------
117
118
119const std::string AlignAndFocusPowderSlim::name() const { return "AlignAndFocusPowderSlim"; }
120
122int AlignAndFocusPowderSlim::version() const { return 1; }
123
125const std::string AlignAndFocusPowderSlim::category() const { return "Workflow\\Diffraction"; }
126
128const std::string AlignAndFocusPowderSlim::summary() const {
129 return "Algorithm to focus powder diffraction data into a number of histograms according to a grouping "
130 "scheme defined in a CalFile.";
131}
132
133const std::vector<std::string> AlignAndFocusPowderSlim::seeAlso() const { return {"AlignAndFocusPowderFromFiles"}; }
134
135//----------------------------------------------------------------------------------------------
139 const std::vector<std::string> exts{".nxs.h5", ".nxs", "_event.nxs"};
140 // docs copied/modified from LoadEventNexus
141 declareProperty(std::make_unique<FileProperty>(PropertyNames::FILENAME, "", FileProperty::Load, exts),
142 "The name of the Event NeXus file to read, including its full or relative path. "
143 "The file name is typically of the form INST_####_event.nxs.");
146 "To only include events after the provided start time, in seconds (relative to the start of the run).");
147
150 "To only include events before the provided stop time, in seconds (relative to the start of the run).");
153 "Input workspace specifying \"splitters\", i.e. time intervals and targets for event filtering. "
154 "Currently only a single output workspace is supported.");
156 "Flag indicating whether in SplitterWorkspace the times are absolute or "
157 "relative. If true, they are relative to the run start time.");
160 "For development testing. Changes how the splitters are processed. If true then use ProcessBankSplitTask "
161 "otherwise loop over ProcessBankTask.");
163 "Find time-of-flight when neutron was at the sample position. This is only necessary for fast logs "
164 "(i.e. more frequent than proton on target pulse).");
167 "If true, events will be splitting using full time values (tof+pulsetime) rather than just pulsetime.");
168 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
169 mustBePositive->setLower(0);
171 "Filter bad pulses in the same way that :ref:`algm-FilterBadPulses` does.");
172 auto range = std::make_shared<BoundedValidator<double>>();
173 range->setBounds(0., 100.);
175 "The percentage of the average to use as the lower bound when filtering bad pulses.");
178 "A GroupingWorkspace giving the grouping info. If not provided then the grouping from the "
179 "calibration file will be used if provided, else a default grouping of one group per bank.");
180 const std::vector<std::string> cal_exts{".h5", ".hd5", ".hdf", ".cal"};
181 declareProperty(std::make_unique<FileProperty>(PropertyNames::CAL_FILE, "", FileProperty::OptionalLoad, cal_exts),
182 "The .cal file containing the position correction factors. Either this or OffsetsWorkspace needs to "
183 "be specified.");
186 "Optional: A Workspace containing the calibration information. This takes precedence over the "
187 "calibration from CalFileName.");
190 "Optional: A workspace giving which detectors are masked. This takes precedence over the mask "
191 "from CalFileName.");
192 const std::vector<std::string> grp_exts{".xml", ".h5", ".hd5", ".hdf", ".cal"};
193 declareProperty(std::make_unique<FileProperty>(PropertyNames::GROUP_FILE, "", FileProperty::OptionalLoad, grp_exts),
194 "An optional file containing grouping information. Overrides grouping from CalFileName. "
195 "Supported formats: XML (from SaveDetectorsGrouping) and HDF5/cal (from LoadDiffCal).");
196 auto mustBePosArr = std::make_shared<Kernel::ArrayBoundedValidator<double>>();
197 mustBePosArr->setLower(0.0);
198 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::X_MIN, std::vector<double>{0.1}, mustBePosArr),
199 "Minimum x-value for the output binning");
200 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::X_DELTA, std::vector<double>{0.0016}),
201 "Bin size for output data");
202 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::X_MAX, std::vector<double>{2.0}, mustBePosArr),
203 "Minimum x-value for the output binning");
205 "The units of the input X min, max and delta values. Output will always be TOF");
207 "Specify binning behavior ('Logarithmic')");
210 "If specified, only these logs will be loaded from the file. Setting this will automatically override the "
211 "default LogBlockList");
214 std::vector<std::string>{"Phase\\*", "Speed\\*", "BL\\*:Chop:\\*", "chopper\\*TDC"}),
215 "If specified, these logs will not be loaded from the file. Set as empty list ``[]`` to disable");
218 "An output workspace.");
219
220 // parameters for chunking options - consider removing these later
221 const std::string CHUNKING_PARAM_GROUP("Chunking-temporary");
222 auto positiveIntValidator = std::make_shared<Mantid::Kernel::BoundedValidator<int>>();
223 positiveIntValidator->setLower(1);
225 std::make_unique<PropertyWithValue<int>>(PropertyNames::READ_SIZE_FROM_DISK, 10000000, positiveIntValidator),
226 "Number of elements of time-of-flight or detector-id to read at a time. This is a maximum");
229 std::make_unique<PropertyWithValue<int>>(PropertyNames::EVENTS_PER_THREAD, 1000, positiveIntValidator),
230 "Number of events to read in a single thread. Higher means less threads are created.");
232
233 // load single bank
235 std::make_unique<PropertyWithValue<int>>(PropertyNames::BANK_NUMBER, EMPTY_INT(), positiveIntValidator),
236 "The bank for which to read data; if specified, others will be blank");
237
238 // parameters for focus position
239 // for L1, mandatory and must be positive
240 auto mandatoryDblValidator = std::make_shared<MandatoryValidator<double>>();
241 auto positiveDblValidator = std::make_shared<Mantid::Kernel::BoundedValidator<double>>();
242 positiveDblValidator->setLower(0);
243 auto l1Validator = std::make_shared<CompositeValidator>();
244 l1Validator->add(mandatoryDblValidator);
245 l1Validator->add(positiveDblValidator);
246 // for L2, 2theta, phi, mandatory arrays with positive valyes
247 auto mandatoryDblArrayValidator = std::make_shared<MandatoryValidator<std::vector<double>>>();
248 auto positionArrayValidator = std::make_shared<CompositeValidator>();
249 positionArrayValidator->add(mandatoryDblArrayValidator);
250 positionArrayValidator->add(mustBePosArr);
251 declareProperty(std::make_unique<PropertyWithValue<double>>(PropertyNames::L1, EMPTY_DBL(), l1Validator),
252 "The primary distance :math:`\\ell_1` from beam to sample");
254 std::make_unique<ArrayProperty<double>>(PropertyNames::L2, std::vector<double>{}, positionArrayValidator),
255 "The secondary distances :math:`\\ell_2` from sample to focus group");
257 std::make_unique<ArrayProperty<double>>(PropertyNames::POLARS, std::vector<double>{}, positionArrayValidator),
258 "The effective polar angle (:math:`2\\theta`) of each focus group");
260 std::make_unique<ArrayProperty<double>>(PropertyNames::AZIMUTHALS, std::vector<double>{}, mustBePosArr),
261 "The effective azimuthal angle :math:`\\phi` for each focus group");
262}
263
264std::map<std::string, std::string> AlignAndFocusPowderSlim::validateInputs() {
265 std::map<std::string, std::string> errors;
266
267 // make sure that data is read in larger chunks than the events processed in a single thread
268 const int disk_chunk = getProperty(PropertyNames::READ_SIZE_FROM_DISK);
269 const int grainsize_events = getProperty(PropertyNames::EVENTS_PER_THREAD);
270 if (disk_chunk < grainsize_events) {
271 const std::string msg(PropertyNames::READ_SIZE_FROM_DISK + " must be larger than " +
275 }
276
277 // only specify allow or block list for logs
278 std::vector<std::string> block_logs = getProperty(PropertyNames::BLOCK_LOGS);
279 if ((!isDefault(PropertyNames::ALLOW_LOGS)) && (!isDefault(PropertyNames::BLOCK_LOGS) && !block_logs.empty())) {
280 errors[PropertyNames::ALLOW_LOGS] = "Cannot specify both allow and block lists";
281 errors[PropertyNames::BLOCK_LOGS] = "Cannot specify both allow and block lists";
282 }
283
284 // the focus group position parameters must have same lengths
285 std::vector<double> l2s = getProperty(PropertyNames::L2);
286 const auto num_l2s = l2s.size();
287 std::vector<double> twoTheta = getProperty(PropertyNames::POLARS);
288 if (num_l2s != twoTheta.size()) {
289 errors[PropertyNames::L2] = strmakef("L2S has inconsistent length %zu", num_l2s);
290 errors[PropertyNames::POLARS] = strmakef("Polar has inconsistent length %zu", twoTheta.size());
291 }
292 // phi is optional, but if set must also have same size
293 std::vector<double> phi = getProperty(PropertyNames::AZIMUTHALS);
294 if (!phi.empty()) {
295 if (num_l2s != phi.size()) {
296 errors[PropertyNames::L2] = strmakef("L2S has inconsistent length %zu", num_l2s);
297 errors[PropertyNames::AZIMUTHALS] = strmakef("Azimuthal has inconsistent length %zu", phi.size());
298 ;
299 }
300 }
301
302 // validate binning information is consistent with each other and number of focus groups
303 const std::vector<double> xmins = getProperty(PropertyNames::X_MIN);
304 const std::vector<double> xmaxs = getProperty(PropertyNames::X_MAX);
305 const std::vector<double> deltas = getProperty(PropertyNames::X_DELTA);
306
307 const auto numMin = xmins.size();
308 const auto numMax = xmaxs.size();
309 const auto numDelta = deltas.size();
310
311 if (std::any_of(deltas.cbegin(), deltas.cend(), [](double d) { return !std::isfinite(d) || d == 0; }))
312 errors[PropertyNames::X_DELTA] = "All must be nonzero";
313 else if (!(numDelta == 1 || numDelta == num_l2s))
314 errors[PropertyNames::X_DELTA] = "Must have 1 or consistent number of values";
315
316 if (!(numMin == 1 || numMin == num_l2s))
317 errors[PropertyNames::X_MIN] = "Must have 1 or consistent number of values";
318 if (!(numMax == 1 || numMax == num_l2s))
319 errors[PropertyNames::X_MAX] = "Must have 1 or consistent number of values";
320 return errors;
321}
322
323//----------------------------------------------------------------------------------------------
327
328 const std::string filename = getPropertyValue(PropertyNames::FILENAME);
329 const Nexus::NexusDescriptor descriptor(filename);
330
331 std::vector<std::string> bankEntryNames;
332 std::vector<std::string> bankNames;
333 determineBanksToLoad(descriptor, bankEntryNames, bankNames);
334
335 const std::size_t num_banks_to_read = bankEntryNames.size();
336 g_log.debug() << "Total banks to read: " << num_banks_to_read << "\n";
337
338 H5::H5File h5file(filename, H5F_ACC_RDONLY, Nexus::H5Util::defaultFileAcc());
339
340 // These give the limits in each file as to which events we actually load (when filtering by time).
341 loadStart.resize(1, 0);
342 loadSize.resize(1, 0);
343
344 size_t num_hist;
345 std::map<size_t, std::set<detid_t>> grouping;
347
348 // Create the output workspace. Load the instrument, this is needed for LoadDiffCal but we cannot create the
349 // output workspace yet because we need grouping information from the cal file to know the correct number of
350 // spectra. We also need to load logs before instrument so we have the correct start time.
351 MatrixWorkspace_sptr wksp = std::make_shared<Workspace2D>();
352 try {
353 LoadEventNexus::loadEntryMetadata(filename, wksp, ENTRY_TOP_LEVEL);
354 } catch (std::exception &e) {
355 g_log.warning() << "Error while loading meta data: " << e.what() << '\n';
356 }
357
358 auto periodLog = std::make_unique<const TimeSeriesProperty<int>>("period_log"); // not used
359 const std::vector<std::string> &allow_logs = getProperty(PropertyNames::ALLOW_LOGS);
360 std::vector<std::string> block_logs = getProperty(PropertyNames::BLOCK_LOGS);
362 block_logs.clear();
363 g_log.information() << "User provided LogAllowList, default LogBlockList being ignored\n";
364 }
365 int nPeriods{1};
366 LoadEventNexus::runLoadNexusLogs<MatrixWorkspace_sptr>(filename, wksp, *this, false, nPeriods, periodLog, allow_logs,
367 block_logs);
368
369 LoadEventNexus::loadInstrument<MatrixWorkspace_sptr>(filename, wksp, ENTRY_TOP_LEVEL, this, &descriptor);
370
371 // load grouping from a separate file if provided (takes priority over grouping from CalFileName)
372 const std::string grp_filename = getPropertyValue(PropertyNames::GROUP_FILE);
373 if (!grp_filename.empty() && !groupingWS) {
374 groupingWS = this->loadGroupingFile(wksp, grp_filename);
375 }
376
379
380 const std::string cal_filename = getPropertyValue(PropertyNames::CAL_FILE);
381 if (!cal_filename.empty()) {
382 this->loadCalFile(wksp, cal_filename, groupingWS, calibrationWS, maskWS);
383 }
384
385 if (maskWS) {
386 m_masked = maskWS->getMaskedDetectors();
387 }
388
389 if (groupingWS) {
390 const auto groupIds = groupingWS->getGroupIDs(false);
391 num_hist = groupIds.size();
392 g_log.information() << "Using grouping workspace with " << num_hist << " groups\n";
393 for (size_t outputindex = 0; outputindex < groupIds.size(); ++outputindex) {
394 const auto detids = groupingWS->getDetectorIDsOfGroup(groupIds[outputindex]);
395 grouping[outputindex] = std::set<detid_t>(detids.begin(), detids.end());
396 }
397 } else {
398 // if no grouping defined then everything goes to one spectrum
399 num_hist = 1;
400 }
401
402 this->progress(.0, "Create output workspace");
403 // initialize the workspace with correct number of histograms and bins
404 initializeOutputWorkspace(wksp, num_hist);
405
406 // TODO parameters should be input information
407 const double l1 = getProperty(PropertyNames::L1);
408 const std::vector<double> l2s = getProperty(PropertyNames::L2);
409 const std::vector<double> polars = getProperty(PropertyNames::POLARS); // two-theta
410 // set angle from positive x-axis; will be zero unless specified
411 std::vector<double> setPhi(l2s.size(), 0.0);
414 }
415 const std::vector<double> azimuthals(setPhi);
416 const std::vector<specnum_t> specids;
417 const auto difc_focused = calculate_difc_focused(l1, l2s, polars);
418
419 const auto timeSplitter = this->timeSplitterFromSplitterWorkspace(wksp->run().startTime());
420 const auto filterROI = this->getFilterROI(wksp);
421 // determine the pulse indices from the time and splitter workspace
422 this->progress(.05, "Determining pulse indices");
423
424 this->progress(.07, "Reading events");
425
426 // get detector ids for each bank
427 std::map<size_t, std::set<detid_t>> bank_detids;
428 for (size_t bankIndex = 0; bankIndex < num_banks_to_read; ++bankIndex) {
429 try {
430 bank_detids[bankIndex] = wksp->getInstrument()->getDetectorIDsInBank(bankNames.at(bankIndex));
431 } catch (std::exception &e) {
432 g_log.warning() << "Error getting detector IDs for " << bankNames.at(bankIndex) << ": " << e.what() << "\n";
433 }
434 }
435
436 // create map of detid to output spectrum number to be used in focusing
437 if (!grouping.empty()) {
438 for (const auto &group : grouping) {
439 for (const auto &detid : group.second) {
440 detIDToSpecNum[detid] = group.first;
441 }
442 }
443 } else {
444 // no grouping provided so everything goes in the 1 output spectrum
445 grouping[0] = std::set<detid_t>{};
446 for (const auto &[i, detids] : bank_detids) {
447 grouping[0].insert(detids.begin(), detids.end());
448 for (const auto &detid : detids) {
449 detIDToSpecNum[detid] = 0;
450 }
451 }
452 }
453
454 // create values for focusing time-of-flight
455 this->progress(.1, "Creating calibration constants");
456 if (calibrationWS) {
457 this->initCalibrationConstantsFromCalWS(difc_focused, calibrationWS);
458 } else {
459 this->initCalibrationConstants(wksp, difc_focused);
460 }
461
462 // calculate correction for tof of the neutron at the sample position
464 this->initScaleAtSample(wksp);
465 }
466
467 // set the instrument. Needs to happen after we get detector ids for each bank
468 this->progress(.15, "Set instrument geometry");
469 wksp = this->editInstrumentGeometry(wksp, l1, polars, specids, l2s, azimuthals);
470
471 // convert to TOF if not already
472 this->progress(.17, "Convert bins to TOF");
473 wksp = this->convertToTOF(wksp);
474
475 // create the bank calibration factory to share with all of the ProcessBank*Task objects
476 BankCalibrationFactory calibFactory(m_calibration, m_scale_at_sample, grouping, m_masked, bank_detids);
477
478 // threaded processing of the banks
479 const int DISK_CHUNK = getProperty(PropertyNames::READ_SIZE_FROM_DISK);
480 const int GRAINSIZE_EVENTS = getProperty(PropertyNames::EVENTS_PER_THREAD);
481 g_log.debug() << (DISK_CHUNK / GRAINSIZE_EVENTS) << " threads per chunk\n";
482
483 // get pulse times from frequency log on workspace. We use this in several places.
484 const auto frequency_log = dynamic_cast<const TimeSeriesProperty<double> *>(wksp->run().getProperty("frequency"));
485 if (!frequency_log) {
486 throw std::runtime_error("Frequency log not found in workspace run");
487 }
488 m_pulse_times = std::make_shared<std::vector<Mantid::Types::Core::DateAndTime>>(frequency_log->timesAsVector());
489
490 if (timeSplitter.empty()) {
491 // create the nexus loader for handling combined calls to hdf5
492
494 const auto pulse_indices = this->determinePulseIndices(filterROI);
495 auto loader = std::make_shared<NexusLoader>(is_time_filtered, pulse_indices);
496
497 auto progress = std::make_shared<API::Progress>(this, .17, .9, num_banks_to_read);
498 ProcessBankTask task(bankEntryNames, h5file, loader, processingData, calibFactory, static_cast<size_t>(DISK_CHUNK),
499 static_cast<size_t>(GRAINSIZE_EVENTS), progress);
500 // generate threads only if appropriate
501 if (num_banks_to_read > 1) {
502 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_banks_to_read), task);
503 } else {
504 task(tbb::blocked_range<size_t>(0, 1));
505 }
506
507 // close the file so child algorithms can do their thing
508 h5file.close();
509
510 // copy data from processingData to wksp
511 storeSpectraProcessingData(processingData, wksp);
512
513 // update the run TimeROI and remove log data outside the time ROI
514 wksp->mutableRun().setTimeROI(filterROI);
515 wksp->mutableRun().removeDataOutsideTimeROI();
516
517 setProperty(PropertyNames::OUTPUT_WKSP, std::move(wksp));
518 } else {
519 std::string ws_basename = this->getPropertyValue(PropertyNames::OUTPUT_WKSP);
520 std::vector<std::string> wsNames;
521 std::vector<int> workspaceIndices;
522 std::vector<MatrixWorkspace_sptr> workspaces;
523 std::vector<SpectraProcessingData> processingDatas;
524 for (const int &splitter_target : timeSplitter.outputWorkspaceIndices()) {
525 std::string ws_name = ws_basename + "_" + timeSplitter.getWorkspaceIndexName(splitter_target);
526 wsNames.push_back(std::move(ws_name));
527 workspaceIndices.push_back(splitter_target);
528 workspaces.emplace_back(wksp->clone());
529 processingDatas.push_back(initializeSpectraProcessingData(workspaces.back()));
530 }
531
532 auto progress = std::make_shared<API::Progress>(this, .17, .9, num_banks_to_read * workspaceIndices.size());
534 g_log.information() << "Using ProcessBankSplitFullTimeTask for splitter processing\n";
535
536 // Get the combined time ROI for all targets so we only load necessary events.
537 // Need to offset the start time to account for tof's greater than pulsetime. 66.6ms is 4 pulses.
538 auto combined_time_roi = timeSplitter.combinedTimeROI(PULSETIME_OFFSET);
539 if (!filterROI.useAll()) {
540 combined_time_roi.update_intersection(filterROI);
541 }
542
543 // create the nexus loader for handling combined calls to hdf5
544 const auto pulse_indices = this->determinePulseIndices(combined_time_roi);
545 auto loader = std::make_shared<NexusLoader>(is_time_filtered, pulse_indices);
546
547 const auto &splitterMap = timeSplitter.getSplittersMap();
548
549 ProcessBankSplitFullTimeTask task(bankEntryNames, h5file, loader, workspaceIndices, processingDatas, calibFactory,
550 static_cast<size_t>(DISK_CHUNK), static_cast<size_t>(GRAINSIZE_EVENTS),
551 splitterMap, m_pulse_times, progress);
552
553 // generate threads only if appropriate
554 if (num_banks_to_read > 1) {
555 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_banks_to_read), task);
556 } else {
557 task(tbb::blocked_range<size_t>(0, 1));
558 }
559
561 g_log.information() << "Using ProcessBankSplitTask for splitter processing\n";
562 // determine the pulse indices from the time and splitter workspace
563 const auto target_to_pulse_indices = this->determinePulseIndicesTargets(filterROI, timeSplitter);
564 // create the nexus loader for handling combined calls to hdf5
565 std::vector<PulseROI> pulse_indices; // intentionally empty to get around loader needing const reference
566 auto loader = std::make_shared<NexusLoader>(is_time_filtered, pulse_indices, target_to_pulse_indices);
567
568 ProcessBankSplitTask task(bankEntryNames, h5file, loader, workspaceIndices, processingDatas, calibFactory,
569 static_cast<size_t>(DISK_CHUNK), static_cast<size_t>(GRAINSIZE_EVENTS), progress);
570 // generate threads only if appropriate
571 if (num_banks_to_read > 1) {
572 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_banks_to_read), task);
573 } else {
574 task(tbb::blocked_range<size_t>(0, 1));
575 }
576 } else {
577 g_log.information() << "Using ProcessBankTask for splitter processing\n";
578 // loop over the targets in the splitter workspace, each target gets its own output workspace
579 tbb::parallel_for(
580 tbb::blocked_range<size_t>(0, workspaceIndices.size()),
581 [&](const tbb::blocked_range<size_t> &target_indices) {
582 for (size_t target_index = target_indices.begin(); target_index != target_indices.end(); ++target_index) {
583 const int splitter_target = workspaceIndices[target_index];
584
585 auto splitter_roi = timeSplitter.getTimeROI(splitter_target);
586 // copy the roi so we can modify it just for this target
587 auto target_roi = filterROI;
588 if (target_roi.useAll())
589 target_roi = std::move(splitter_roi); // use the splitter ROI if no time filtering is specified
590 else if (!splitter_roi.useAll())
591 target_roi.update_intersection(splitter_roi); // otherwise intersect with the splitter ROI
592
593 // clone wksp for this target
594 MatrixWorkspace_sptr target_wksp = workspaces[target_index];
595
596 const auto pulse_indices = this->determinePulseIndices(target_roi);
597 auto loader = std::make_shared<NexusLoader>(is_time_filtered, pulse_indices);
598
599 ProcessBankTask task(bankEntryNames, h5file, loader, processingDatas[target_index], calibFactory,
600 static_cast<size_t>(DISK_CHUNK), static_cast<size_t>(GRAINSIZE_EVENTS), progress);
601 // generate threads only if appropriate
602 if (num_banks_to_read > 1) {
603 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_banks_to_read), task);
604 } else {
605 task(tbb::blocked_range<size_t>(0, 1));
606 }
607 }
608 });
609 }
610
611 // close the file so child algorithms can do their thing
612 h5file.close();
613
614 // add the workspaces to the ADS
615 for (size_t idx = 0; idx < workspaceIndices.size(); ++idx) {
616 // copy data from processingData to wksp
617 storeSpectraProcessingData(processingDatas[idx], workspaces[idx]);
618
619 // create the target time ROI combining the splitter and filter ROIs
620 auto target_roi = timeSplitter.getTimeROI(workspaceIndices[idx]);
621 if (target_roi.useAll())
622 target_roi = filterROI; // use the splitter ROI if no time filtering is specified
623 else if (!filterROI.useAll())
624 target_roi.update_intersection(filterROI); // otherwise intersect with the splitter ROI
625
626 // update the run TimeROI and remove log data outside the time ROI
627 workspaces[idx]->mutableRun().setTimeROI(target_roi);
628 workspaces[idx]->mutableRun().removeDataOutsideTimeROI();
629 AnalysisDataService::Instance().addOrReplace(wsNames[idx], workspaces[idx]);
630 }
631
632 // group the workspaces
633 auto groupws = createChildAlgorithm("GroupWorkspaces", 0.95, 1.00, true);
634 groupws->setAlwaysStoreInADS(true);
635 groupws->setProperty("InputWorkspaces", wsNames);
636 groupws->setProperty("OutputWorkspace", ws_basename);
637 groupws->execute();
638
639 if (!groupws->isExecuted()) {
640 throw std::runtime_error("Failed to group output workspaces");
641 }
642
643 API::Workspace_sptr outputWorkspace = AnalysisDataService::Instance().retrieveWS<API::Workspace>(ws_basename);
644
645 setProperty(PropertyNames::OUTPUT_WKSP, outputWorkspace);
646 }
647}
648
649void AlignAndFocusPowderSlim::determineBanksToLoad(const Nexus::NexusDescriptor &descriptor,
650 std::vector<std::string> &bankEntryNames,
651 std::vector<std::string> &bankNames) {
652 // Now we want to go through all the bankN_event entries
653
654 std::set<std::string> const classEntries = descriptor.allAddressesOfType("NXevent_data");
655 if (classEntries.empty()) {
656 throw std::runtime_error("No NXevent_data entries found in file");
657 }
658
659 const int bankNum = getProperty(PropertyNames::BANK_NUMBER);
660
661 const std::regex classRegex("(/entry/)([^/]*)");
662 std::smatch groups;
663 for (const std::string &classEntry : classEntries) {
664 if (std::regex_match(classEntry, groups, classRegex)) {
665 const std::string entry_name(groups[2].str());
666 if (classEntry.ends_with("bank_error_events")) {
667 // do nothing
668 } else if (classEntry.ends_with("bank_unmapped_events")) {
669 // do nothing
670 } else {
671 auto underscore_pos = entry_name.find_first_of('_');
672 const auto bankName = entry_name.substr(0, underscore_pos);
673 if (bankNum != EMPTY_INT()) {
674 if (bankName != ("bank" + std::to_string(bankNum))) {
675 continue; // skip this bank
676 }
677 }
678 bankEntryNames.push_back(entry_name);
679 bankNames.push_back(bankName);
680 }
681 }
682 }
683}
684
685void AlignAndFocusPowderSlim::initializeOutputWorkspace(const MatrixWorkspace_sptr &wksp, size_t num_hist) {
686 // set up the output workspace binning
687 const BINMODE binmode = getPropertyValue(PropertyNames::BINMODE);
688 const bool linearBins = bool(binmode == BinningMode::LINEAR);
689 const std::string binUnits = getPropertyValue(PropertyNames::BIN_UNITS);
690 std::vector<double> x_delta = getProperty(PropertyNames::X_DELTA);
691 std::vector<double> x_min = getProperty(PropertyNames::X_MIN);
692 std::vector<double> x_max = getProperty(PropertyNames::X_MAX);
693 const bool raggedBins = (x_delta.size() != 1 || x_min.size() != 1 || x_max.size() != 1);
694
695 constexpr bool resize_xnew{true};
696 constexpr bool full_bins_only{false};
697
698 // always use the first histogram x-values for initialization
699 double const binWidth = linearBins ? x_delta[0] : -1. * std::abs(x_delta[0]);
700 std::vector<double> xAxisTmp;
701 Kernel::VectorHelper::createAxisFromRebinParams({x_min[0], binWidth, x_max[0]}, xAxisTmp, resize_xnew,
702 full_bins_only);
703 HistogramData::BinEdges XValues(std::move(xAxisTmp));
704 wksp->initialize(num_hist, HistogramData::Histogram(XValues, HistogramData::Counts(XValues.size() - 1, 0.0)));
705
706 if (raggedBins) {
707 // if ragged bins, we need to resize the x-values for each histogram after the first one
708 if (x_delta.size() == 1)
709 x_delta.resize(num_hist, x_delta[0]);
710 if (x_min.size() == 1)
711 x_min.resize(num_hist, x_min[0]);
712 if (x_max.size() == 1)
713 x_max.resize(num_hist, x_max[0]);
714
715 for (size_t i = 1; i < num_hist; ++i) {
716 double const raggedBinWidth = linearBins ? x_delta[i] : -1. * std::abs(x_delta[i]);
717 std::vector<double> const params{x_min[i], raggedBinWidth, x_max[i]};
718 std::vector<double> xtmpragged;
719 Kernel::VectorHelper::createAxisFromRebinParams(params, xtmpragged, resize_xnew, full_bins_only);
720 HistogramData::BinEdges XValues_new(std::move(xtmpragged));
721 wksp->setHistogram(i, HistogramData::Histogram(XValues_new, HistogramData::Counts(XValues_new.size() - 1, 0.0)));
722 }
723 }
724
725 wksp->getAxis(0)->setUnit(binUnits);
726 wksp->setYUnit("Counts");
727}
728
730AlignAndFocusPowderSlim::initializeSpectraProcessingData(const API::MatrixWorkspace_sptr &outputWS) {
731 SpectraProcessingData processingData;
732 const size_t numSpectra = outputWS->getNumberHistograms();
733 for (size_t i = 0; i < numSpectra; ++i) {
734 const auto &spectrum = outputWS->getSpectrum(i);
735 processingData.binedges.emplace_back(&spectrum.x().rawData());
736 processingData.counts.emplace_back(spectrum.y().size());
737 }
738 return processingData;
739}
740
741void AlignAndFocusPowderSlim::storeSpectraProcessingData(const SpectraProcessingData &processingData,
742 const API::MatrixWorkspace_sptr &outputWS) {
743 const size_t numSpectra = outputWS->getNumberHistograms();
744 for (size_t i = 0; i < numSpectra; ++i) {
745 auto &spectrum = outputWS->getSpectrum(i);
746 auto &y_values = spectrum.mutableY();
747 std::transform(
748 processingData.counts[i].cbegin(), processingData.counts[i].cend(), y_values.begin(),
749 [](const std::atomic_uint32_t &val) { return static_cast<double>(val.load(std::memory_order_relaxed)); });
750 auto &e_values = spectrum.mutableE();
751 std::transform(processingData.counts[i].cbegin(), processingData.counts[i].cend(), e_values.begin(),
752 [](const std::atomic_uint32_t &val) {
753 return std::sqrt(static_cast<double>(val.load(std::memory_order_relaxed)));
754 });
755 }
756}
757
758void AlignAndFocusPowderSlim::initCalibrationConstants(API::MatrixWorkspace_sptr &wksp,
759 const std::vector<double> &difc_focus) {
760 const auto detInfo = wksp->detectorInfo();
761
762 for (auto iter = detInfo.cbegin(); iter != detInfo.cend(); ++iter) {
763 if (!iter->isMonitor()) {
764 const auto difc_focussed = getFocussedPostion(static_cast<detid_t>(iter->detid()), difc_focus, detIDToSpecNum);
765 if (difc_focussed == IGNORE_PIXEL)
766 m_calibration.emplace(static_cast<detid_t>(iter->detid()), IGNORE_PIXEL);
767 else
768 m_calibration.emplace(static_cast<detid_t>(iter->detid()),
769 difc_focussed / detInfo.difcUncalibrated(iter->index()));
770 }
771 }
772}
773
774void AlignAndFocusPowderSlim::initCalibrationConstantsFromCalWS(const std::vector<double> &difc_focus,
775 const ITableWorkspace_sptr calibrationWS) {
776 for (size_t row = 0; row < calibrationWS->rowCount(); ++row) {
777 const detid_t detid = calibrationWS->cell<int>(row, 0);
778 const double detc = calibrationWS->cell<double>(row, 1);
779 const auto difc_focussed = getFocussedPostion(detid, difc_focus, detIDToSpecNum);
780 if (difc_focussed == IGNORE_PIXEL)
781 m_calibration.emplace(detid, IGNORE_PIXEL);
782 else
783 m_calibration.emplace(detid, difc_focussed / detc);
784 }
785}
786
791void AlignAndFocusPowderSlim::loadCalFile(const API::Workspace_sptr &inputWS, const std::string &filename,
792 GroupingWorkspace_sptr &groupingWS, ITableWorkspace_sptr &calibrationWS,
793 MaskWorkspace_sptr &maskWS) {
794 const bool load_grouping = !groupingWS;
795 const bool load_calibration = !calibrationWS;
796 const bool load_mask = !maskWS;
797
798 // nothing left to load from the file
799 if (!load_grouping && !load_calibration && !load_mask)
800 return;
801
802 auto alg = createChildAlgorithm("LoadDiffCal");
803 alg->setPropertyValue("Filename", filename);
804 if (filename.ends_with(".cal")) {
805 alg->setProperty("InputWorkspace", inputWS);
806 } else {
807 // intentionally do not supply the input workspace because h5 version can work without
808 g_log.debug("Not supplying instrument information to LoadDifCal");
809 }
810 alg->setProperty<bool>("MakeCalWorkspace", load_calibration);
811 alg->setProperty<bool>("MakeGroupingWorkspace", load_grouping);
812 alg->setProperty<bool>("MakeMaskWorkspace", load_mask);
813 alg->setPropertyValue("WorkspaceName", "temp");
814 alg->executeAsChildAlg();
815
816 if (load_grouping) {
817 g_log.debug() << "Loading grouping workspace from calibration file\n";
818 groupingWS = alg->getProperty("OutputGroupingWorkspace");
819 }
820 if (load_calibration) {
821 calibrationWS = alg->getProperty("OutputCalWorkspace");
822 }
823 if (load_mask) {
824 maskWS = alg->getProperty("OutputMaskWorkspace");
825 }
826}
827
832GroupingWorkspace_sptr AlignAndFocusPowderSlim::loadGroupingFile(const API::MatrixWorkspace_sptr &wksp,
833 const std::string &filename) {
834 g_log.debug() << "Loading grouping from file: " << filename << '\n';
835
836 // case-insensitive extension check
837 std::string lowerFilename = filename;
838 std::transform(lowerFilename.begin(), lowerFilename.end(), lowerFilename.begin(),
839 [](unsigned char c) { return std::tolower(c); });
840
841 GroupingWorkspace_sptr groupingWS;
842 if (lowerFilename.ends_with(".xml")) {
843 // XML grouping files can carry their own instrument/date metadata. Do not
844 // supply InputWorkspace here because LoadDetectorsGroupingFile treats that
845 // as an override; without it, the child algorithm will use the instrument
846 // information embedded in the XML file.
847 auto alg = createChildAlgorithm("LoadDetectorsGroupingFile");
848 alg->setPropertyValue("InputFile", filename);
849 alg->executeAsChildAlg();
850 groupingWS = alg->getProperty("OutputWorkspace");
851 } else {
852 // HDF5 or .cal grouping file -- use LoadDiffCal as the Filename (cal file) parameter
853 auto alg = createChildAlgorithm("LoadDiffCal");
854 alg->setPropertyValue("Filename", filename);
855 if (lowerFilename.ends_with(".cal")) {
856 // .cal format requires an instrument to be provided
857 alg->setProperty("InputWorkspace", std::dynamic_pointer_cast<API::Workspace>(wksp));
858 }
859 alg->setProperty<bool>("MakeCalWorkspace", false);
860 alg->setProperty<bool>("MakeGroupingWorkspace", true);
861 alg->setProperty<bool>("MakeMaskWorkspace", false);
862 alg->setPropertyValue("WorkspaceName", "slim_grp");
863 alg->executeAsChildAlg();
864 groupingWS = alg->getProperty("OutputGroupingWorkspace");
865 }
866 return groupingWS;
867}
868
873void AlignAndFocusPowderSlim::initScaleAtSample(const API::MatrixWorkspace_sptr &wksp) {
874 // detector information for all of the L2
875 const auto detInfo = wksp->detectorInfo();
876 // cache a single L1 value
877 const double L1 = detInfo.l1();
878
879 if (this->getProperty(PropertyNames::CORRECTION_TO_SAMPLE)) {
880 // calculate scale factors for each detector
881 for (auto iter = detInfo.cbegin(); iter != detInfo.cend(); ++iter) {
882 if (!iter->isMonitor()) {
883 const double path_correction = L1 / (L1 + iter->l2()) * 1000.0;
884 m_scale_at_sample.emplace(static_cast<detid_t>(iter->detid()), path_correction);
885 }
886 }
887 } else {
888 // set all scale factors to 1.0
889 for (auto iter = detInfo.cbegin(); iter != detInfo.cend(); ++iter) {
890 if (!iter->isMonitor()) {
891 m_scale_at_sample.emplace(static_cast<detid_t>(iter->detid()), 1000.0);
892 }
893 }
894 }
895}
896
897API::MatrixWorkspace_sptr AlignAndFocusPowderSlim::editInstrumentGeometry(
898 API::MatrixWorkspace_sptr &wksp, const double l1, const std::vector<double> &polars,
899 const std::vector<specnum_t> &specids, const std::vector<double> &l2s, const std::vector<double> &azimuthals) {
900 API::IAlgorithm_sptr editAlg = createChildAlgorithm("EditInstrumentGeometry");
901 editAlg->setLoggingOffset(1);
902 editAlg->setProperty("Workspace", wksp);
903 if (l1 > 0.)
904 editAlg->setProperty("PrimaryFlightPath", l1);
905 if (!polars.empty())
906 editAlg->setProperty("Polar", polars);
907 if (!specids.empty())
908 editAlg->setProperty("SpectrumIDs", specids);
909 if (!l2s.empty())
910 editAlg->setProperty("L2", l2s);
911 if (!azimuthals.empty())
912 editAlg->setProperty("Azimuthal", azimuthals);
913 editAlg->executeAsChildAlg();
914
915 wksp = editAlg->getProperty("Workspace");
916
917 return wksp;
918}
919
920API::MatrixWorkspace_sptr AlignAndFocusPowderSlim::convertToTOF(API::MatrixWorkspace_sptr &wksp) {
921 if (wksp->getAxis(0)->unit()->unitID() == "TOF") {
922 // already in TOF, no need to convert
923 return wksp;
924 }
925
926 API::IAlgorithm_sptr convertUnits = createChildAlgorithm("ConvertUnits");
927 convertUnits->setProperty("InputWorkspace", wksp);
928 convertUnits->setPropertyValue("Target", "TOF");
929 convertUnits->executeAsChildAlg();
930 wksp = convertUnits->getProperty("OutputWorkspace");
931
932 return wksp;
933}
934
942Kernel::TimeROI AlignAndFocusPowderSlim::getFilterROI(const API::MatrixWorkspace_sptr &wksp) {
943 Kernel::TimeROI roi;
944 const auto startOfRun = wksp->run().startTime();
945
946 // filter by time
947 double filter_time_start_sec = getProperty(PropertyNames::FILTER_TIMESTART);
948 double filter_time_stop_sec = getProperty(PropertyNames::FILTER_TIMESTOP);
949 if (filter_time_start_sec != EMPTY_DBL() || filter_time_stop_sec != EMPTY_DBL()) {
950 this->progress(.15, "Creating time filtering");
951 g_log.information() << "Filtering pulses from " << filter_time_start_sec << " to " << filter_time_stop_sec << "s\n";
952
953 try {
954 roi.addROI(startOfRun + (filter_time_start_sec == EMPTY_DBL() ? 0.0 : filter_time_start_sec),
955 startOfRun + filter_time_stop_sec); // start and stop times in seconds
956 } catch (const std::runtime_error &e) {
957 throw std::invalid_argument("Invalid time range for filtering: " + std::string(e.what()));
958 }
959 }
960
961 // filter bad pulses
962 if (getProperty(PropertyNames::FILTER_BAD_PULSES)) {
963 this->progress(.16, "Filtering bad pulses");
964
965 // get limits from proton_charge
966 const auto [min_pcharge, max_pcharge, mean] =
967 wksp->run().getBadPulseRange(LOG_CHARGE_NAME, getProperty(PropertyNames::FILTER_BAD_PULSES_LOWER_CUTOFF));
968 g_log.information() << "Filtering bad pulses; pcharge outside of " << min_pcharge << " to " << max_pcharge << '\n';
969
970 const auto run_start = wksp->getFirstPulseTime();
971 const auto run_stop = wksp->getLastPulseTime();
972
973 const auto log = dynamic_cast<const TimeSeriesProperty<double> *>(wksp->run().getLogData(LOG_CHARGE_NAME));
974 if (log) {
975 // need to have centre=true for proton_charge
976 roi = log->makeFilterByValue(min_pcharge, max_pcharge, true, Mantid::Kernel::TimeInterval(run_start, run_stop),
977 0.0, true, &roi);
978 }
979 }
980 return roi;
981}
982
989std::vector<PulseROI> AlignAndFocusPowderSlim::determinePulseIndices(const TimeROI &filterROI) {
990
991 std::vector<PulseROI> pulse_indices;
992 if (filterROI.useAll()) {
993 pulse_indices.emplace_back(0, std::numeric_limits<size_t>::max());
994 } else {
995 is_time_filtered = true;
996 pulse_indices = filterROI.calculate_indices(*m_pulse_times);
997 if (pulse_indices.empty())
998 throw std::invalid_argument("No valid pulse time indices found for filtering");
999 }
1000
1001 return pulse_indices;
1002}
1003
1012std::vector<std::pair<int, PulseROI>>
1013AlignAndFocusPowderSlim::determinePulseIndicesTargets(const TimeROI &filterROI, const TimeSplitter &timeSplitter) {
1014 std::vector<PulseROI> pulse_indices;
1015 if (filterROI.useAll()) {
1016 pulse_indices.emplace_back(0, std::numeric_limits<size_t>::max());
1017 } else {
1018 pulse_indices = filterROI.calculate_indices(*m_pulse_times);
1019 if (pulse_indices.empty())
1020 throw std::invalid_argument("No valid pulse time indices found for filtering");
1021 }
1022
1023 const auto target_to_pulse_indices = timeSplitter.calculate_target_indices(*m_pulse_times);
1024
1025 // calculate intersection of target pulse indices and time filter pulse indices (removes pulses outside filterROI)
1026 std::vector<std::pair<int, PulseROI>> intersected_target_pulse_indices;
1027 auto pulse_it = pulse_indices.cbegin();
1028 for (const auto &target_pair : target_to_pulse_indices) {
1029 // move pulse_it to the first pulse that could overlap
1030 while (pulse_it != pulse_indices.cend() && pulse_it->second <= target_pair.second.first) {
1031 ++pulse_it;
1032 }
1033 // check for overlaps
1034 auto check_it = pulse_it;
1035 while (check_it != pulse_indices.cend() && check_it->first < target_pair.second.second) {
1036 // there is an overlap
1037 size_t start_index = std::max(check_it->first, target_pair.second.first);
1038 size_t stop_index = std::min(check_it->second, target_pair.second.second);
1039 if (start_index < stop_index) {
1040 intersected_target_pulse_indices.emplace_back(target_pair.first, PulseROI(start_index, stop_index));
1041 }
1042 ++check_it;
1043 }
1044 }
1045
1046 return intersected_target_pulse_indices;
1047}
1048
1050AlignAndFocusPowderSlim::timeSplitterFromSplitterWorkspace(const Types::Core::DateAndTime &filterStartTime) {
1051 API::Workspace_sptr tempws = this->getProperty(PropertyNames::SPLITTER_WS);
1052 DataObjects::SplittersWorkspace_sptr splittersWorkspace =
1053 std::dynamic_pointer_cast<DataObjects::SplittersWorkspace>(tempws);
1054 DataObjects::TableWorkspace_sptr splitterTableWorkspace =
1055 std::dynamic_pointer_cast<DataObjects::TableWorkspace>(tempws);
1056 API::MatrixWorkspace_sptr matrixSplitterWS = std::dynamic_pointer_cast<API::MatrixWorkspace>(tempws);
1057
1058 if (!splittersWorkspace && !splitterTableWorkspace && !matrixSplitterWS)
1059 return {};
1060
1061 const bool isSplittersRelativeTime = this->getProperty(PropertyNames::SPLITTER_RELATIVE);
1062
1063 TimeSplitter time_splitter;
1064 if (splittersWorkspace) {
1065 time_splitter = TimeSplitter{splittersWorkspace};
1066 } else if (splitterTableWorkspace) {
1067 time_splitter =
1068 TimeSplitter(splitterTableWorkspace, isSplittersRelativeTime ? filterStartTime : DateAndTime::GPS_EPOCH);
1069 } else {
1070 time_splitter = TimeSplitter(matrixSplitterWS, isSplittersRelativeTime ? filterStartTime : DateAndTime::GPS_EPOCH);
1071 }
1072
1073 return time_splitter;
1074}
1075
1076} // namespace Mantid::DataHandling::AlignAndFocusPowderSlim
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:542
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual 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)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:423
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
bool isDefault(const std::string &name) const
A specialized class for dealing with file properties.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
Base Workspace Abstract Class.
Definition Workspace.h:29
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
DataObjects::GroupingWorkspace_sptr loadGroupingFile(const API::MatrixWorkspace_sptr &wksp, const std::string &filename)
Load a grouping workspace from an explicit grouping file.
std::vector< std::pair< size_t, size_t > > determinePulseIndices(const Kernel::TimeROI &filterROI)
Determine the pulse indices for a given workspace and time ROI.
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
SpectraProcessingData initializeSpectraProcessingData(const API::MatrixWorkspace_sptr &outputWS)
std::vector< int64_t > loadStart
Index to load start at in the file.
std::shared_ptr< std::vector< Types::Core::DateAndTime > > m_pulse_times
void storeSpectraProcessingData(const SpectraProcessingData &processingData, const API::MatrixWorkspace_sptr &outputWS)
DataObjects::TimeSplitter timeSplitterFromSplitterWorkspace(const Types::Core::DateAndTime &)
void determineBanksToLoad(const Mantid::Nexus::NexusDescriptor &descriptor, std::vector< std::string > &bankEntryNames, std::vector< std::string > &bankNames)
std::map< detid_t, double > m_scale_at_sample
Multiplicative 0<value<1 to move neutron TOF at sample.
void initScaleAtSample(const API::MatrixWorkspace_sptr &wksp)
For fast logs, calculate the sample position correction.
const std::string category() const override
Algorithm's category for identification.
std::vector< std::pair< int, std::pair< size_t, size_t > > > determinePulseIndicesTargets(const Kernel::TimeROI &filterROI, const DataObjects::TimeSplitter &timeSplitter)
Determine the pulse indices for a given workspace, time ROI, and time splitter.
void loadCalFile(const API::Workspace_sptr &inputWS, const std::string &filename, DataObjects::GroupingWorkspace_sptr &groupingWS, API::ITableWorkspace_sptr &calibrationWS, DataObjects::MaskWorkspace_sptr &maskWS)
Load the calibration file, filling in only the workspaces (grouping, calibration, mask) that have not...
API::MatrixWorkspace_sptr editInstrumentGeometry(API::MatrixWorkspace_sptr &wksp, const double l1, const std::vector< double > &polars, const std::vector< specnum_t > &specids, const std::vector< double > &l2s, const std::vector< double > &azimuthals)
int version() const override
Algorithm's version for identification.
const std::vector< std::string > seeAlso() const override
Function to return all of the seeAlso (these are not validated) algorithms related to this algorithm....
void initializeOutputWorkspace(const API::MatrixWorkspace_sptr &wksp, size_t num_hist)
void initCalibrationConstantsFromCalWS(const std::vector< double > &difc_focus, const API::ITableWorkspace_sptr calibrationWS)
Kernel::TimeROI getFilterROI(const API::MatrixWorkspace_sptr &wksp)
Create a TimeROI based on the filtering properties set in the algorithm.
API::MatrixWorkspace_sptr convertToTOF(API::MatrixWorkspace_sptr &wksp)
void initCalibrationConstants(API::MatrixWorkspace_sptr &wksp, const std::vector< double > &difc_focus)
static void loadEntryMetadata(const std::string &nexusfilename, T WS, const std::string &entry_name)
Load the run number and other meta data from the given bank.
std::vector< std::pair< int, std::pair< size_t, size_t > > > calculate_target_indices(const std::vector< DateAndTime > &times) const
Given a list of times, calculate the corresponding indices in the TimeSplitter.
Concrete workspace implementation.
Definition Workspace2D.h:29
Kernel/ArrayBoundedValidator.h.
Support for a property that holds an array of values.
BoundedValidator is a validator that requires the values to be between upper or lower bounds,...
A concrete property based on user options of a finite list of strings.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
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
Validator to check that a property is not left empty.
The concrete, templated class for properties.
Represents a time interval.
Definition DateAndTime.h:25
TimeROI : Object that holds information about when the time measurement was active.
Definition TimeROI.h:18
std::vector< std::pair< size_t, size_t > > calculate_indices(const std::vector< Types::Core::DateAndTime > &times) const
Definition TimeROI.cpp:346
void addROI(const std::string &startTime, const std::string &stopTime)
Definition TimeROI.cpp:76
bool useAll() const
TimeROI selects all time to be used.
Definition TimeROI.cpp:693
A specialised Property class for holding a series of time-value pairs.
std::set< std::string > allAddressesOfType(const std::string &type) const
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Mantid::Kernel::SingletonHolder< AnalysisDataServiceImpl > AnalysisDataService
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
const std::string GROUPING_WS("GroupingWorkspace")
const std::string FILTER_TIMESTART("FilterByTimeStart")
const std::string FILTER_BAD_PULSES_LOWER_CUTOFF("BadPulsesLowerCutoff")
const std::string PROCESS_BANK_SPLIT_TASK("ProcessBankSplitTask")
const std::string CORRECTION_TO_SAMPLE("CorrectionToSample")
const std::string CAL_WKSP("CalibrationWorkspace")
const std::string FILTER_TIMESTOP("FilterByTimeStop")
const std::string SPLITTER_WS("SplitterWorkspace")
const std::string EVENTS_PER_THREAD("EventsPerThread")
const std::string FILTER_BAD_PULSES("FilterBadPulses")
const std::string READ_SIZE_FROM_DISK("ReadSizeFromDisk")
std::shared_ptr< SplittersWorkspace > SplittersWorkspace_sptr
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< GroupingWorkspace > GroupingWorkspace_sptr
shared pointer to the GroupingWorkspace class
std::shared_ptr< MaskWorkspace > MaskWorkspace_sptr
shared pointer to the MaskWorkspace class
constexpr double deg2rad
Defines units/enum for Crystal work.
Definition AngleUnits.h:20
MANTID_KERNEL_DLL std::string strmakef(char const *const fmt,...)
This is the constructor that std::string needed to have.
Definition Strings.cpp:1200
std::size_t MANTID_KERNEL_DLL createAxisFromRebinParams(const std::vector< double > &params, std::vector< double > &xnew, const bool resize_xnew=true, const bool full_bins_only=false, const double xMinHint=std::nan(""), const double xMaxHint=std::nan(""), const bool useReverseLogarithmic=false, const double power=-1)
Creates a new output X array given a 'standard' set of rebinning parameters.
MANTID_NEXUS_DLL H5::FileAccPropList defaultFileAcc()
Default file access is H5F_CLOSE_STRONG.
Definition H5Util.cpp:119
const std::string BINMODE("BinningMode")
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
int32_t detid_t
Typedef for a detector ID.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
std::vector< std::vector< std::atomic_uint32_t > > counts
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54