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 <numbers>
46#include <ranges>
47#include <regex>
48#include <vector>
49
71
72namespace { // anonymous namespace
73
74const std::string LOG_CHARGE_NAME("proton_charge");
75
76const std::vector<std::string> binningModeNames{"Logarithmic", "Linear"};
77enum class BinningMode { LOGARITHMIC, LINEAR, enum_count };
79
80const std::vector<std::string> unitNames{"dSpacing", "TOF", "MomentumTransfer"};
81enum class BinUnit { DSPACE, TOF, Q, enum_count };
83
84const std::string ENTRY_TOP_LEVEL("entry");
85
86// TODO refactor this to use the actual grouping
87double getFocussedPostion(const detid_t detid, const std::vector<double> &difc_focus,
88 std::map<detid_t, size_t> &detIDToSpecNum) {
89 if (detIDToSpecNum.contains(detid)) {
90 return difc_focus[detIDToSpecNum[detid]];
91 } else {
92 return IGNORE_PIXEL;
93 }
94}
95
96std::vector<double> calculate_difc_focused(const double l1, const std::vector<double> &l2s,
97 const std::vector<double> &polars) {
98 constexpr double deg2rad = std::numbers::pi_v<double> / 180.;
99
100 std::vector<double> difc;
101
102 std::transform(l2s.cbegin(), l2s.cend(), polars.cbegin(), std::back_inserter(difc),
103 [l1, deg2rad](const auto &l2, const auto &polar) {
104 return 1. / Kernel::Units::tofToDSpacingFactor(l1, l2, deg2rad * polar, 0.);
105 });
106
107 return difc;
108}
109
110} // namespace
111
112// Register the algorithm into the AlgorithmFactory
113DECLARE_ALGORITHM(AlignAndFocusPowderSlim)
114
115//----------------------------------------------------------------------------------------------
116
117
118const std::string AlignAndFocusPowderSlim::name() const { return "AlignAndFocusPowderSlim"; }
119
121int AlignAndFocusPowderSlim::version() const { return 1; }
122
124const std::string AlignAndFocusPowderSlim::category() const { return "Workflow\\Diffraction"; }
125
127const std::string AlignAndFocusPowderSlim::summary() const {
128 return "Algorithm to focus powder diffraction data into a number of histograms according to a grouping "
129 "scheme defined in a CalFile.";
130}
131
132const std::vector<std::string> AlignAndFocusPowderSlim::seeAlso() const { return {"AlignAndFocusPowderFromFiles"}; }
133
134//----------------------------------------------------------------------------------------------
138 const std::vector<std::string> exts{".nxs.h5", ".nxs", "_event.nxs"};
139 // docs copied/modified from LoadEventNexus
140 declareProperty(std::make_unique<FileProperty>(PropertyNames::FILENAME, "", FileProperty::Load, exts),
141 "The name of the Event NeXus file to read, including its full or relative path. "
142 "The file name is typically of the form INST_####_event.nxs.");
145 "To only include events after the provided start time, in seconds (relative to the start of the run).");
146
149 "To only include events before the provided stop time, in seconds (relative to the start of the run).");
152 "Input workspace specifying \"splitters\", i.e. time intervals and targets for event filtering. "
153 "Currently only a single output workspace is supported.");
155 "Flag indicating whether in SplitterWorkspace the times are absolute or "
156 "relative. If true, they are relative to the run start time.");
159 "For development testing. Changes how the splitters are processed. If true then use ProcessBankSplitTask "
160 "otherwise loop over ProcessBankTask.");
162 "Find time-of-flight when neutron was at the sample position. This is only necessary for fast logs "
163 "(i.e. more frequent than proton on target pulse).");
166 "If true, events will be splitting using full time values (tof+pulsetime) rather than just pulsetime.");
167 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
168 mustBePositive->setLower(0);
170 "Filter bad pulses in the same way that :ref:`algm-FilterBadPulses` does.");
171 auto range = std::make_shared<BoundedValidator<double>>();
172 range->setBounds(0., 100.);
174 "The percentage of the average to use as the lower bound when filtering bad pulses.");
177 "A GroupingWorkspace giving the grouping info. If not provided then the grouping from the "
178 "calibration file will be used if provided, else a default grouping of one group per bank.");
179 const std::vector<std::string> cal_exts{".h5", ".hd5", ".hdf", ".cal"};
180 declareProperty(std::make_unique<FileProperty>(PropertyNames::CAL_FILE, "", FileProperty::OptionalLoad, cal_exts),
181 "The .cal file containing the position correction factors. Either this or OffsetsWorkspace needs to "
182 "be specified.");
183 auto mustBePosArr = std::make_shared<Kernel::ArrayBoundedValidator<double>>();
184 mustBePosArr->setLower(0.0);
185 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::X_MIN, std::vector<double>{0.1}, mustBePosArr),
186 "Minimum x-value for the output binning");
187 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::X_DELTA, std::vector<double>{0.0016}),
188 "Bin size for output data");
189 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::X_MAX, std::vector<double>{2.0}, mustBePosArr),
190 "Minimum x-value for the output binning");
192 "The units of the input X min, max and delta values. Output will always be TOF");
194 "Specify binning behavior ('Logarithmic')");
197 "If specified, only these logs will be loaded from the file. Setting this will automatically override the "
198 "default LogBlockList");
201 std::vector<std::string>{"Phase\\*", "Speed\\*", "BL\\*:Chop:\\*", "chopper\\*TDC"}),
202 "If specified, these logs will not be loaded from the file. Set as empty list ``[]`` to disable");
205 "An output workspace.");
206
207 // parameters for chunking options - consider removing these later
208 const std::string CHUNKING_PARAM_GROUP("Chunking-temporary");
209 auto positiveIntValidator = std::make_shared<Mantid::Kernel::BoundedValidator<int>>();
210 positiveIntValidator->setLower(1);
212 std::make_unique<PropertyWithValue<int>>(PropertyNames::READ_SIZE_FROM_DISK, 10000000, positiveIntValidator),
213 "Number of elements of time-of-flight or detector-id to read at a time. This is a maximum");
216 std::make_unique<PropertyWithValue<int>>(PropertyNames::EVENTS_PER_THREAD, 1000, positiveIntValidator),
217 "Number of events to read in a single thread. Higher means less threads are created.");
219
220 // load single bank
222 std::make_unique<PropertyWithValue<int>>(PropertyNames::BANK_NUMBER, EMPTY_INT(), positiveIntValidator),
223 "The bank for which to read data; if specified, others will be blank");
224
225 // parameters for focus position
226 // for L1, mandatory and must be positive
227 auto mandatoryDblValidator = std::make_shared<MandatoryValidator<double>>();
228 auto positiveDblValidator = std::make_shared<Mantid::Kernel::BoundedValidator<double>>();
229 positiveDblValidator->setLower(0);
230 auto l1Validator = std::make_shared<CompositeValidator>();
231 l1Validator->add(mandatoryDblValidator);
232 l1Validator->add(positiveDblValidator);
233 // for L2, 2theta, phi, mandatory arrays with positive valyes
234 auto mandatoryDblArrayValidator = std::make_shared<MandatoryValidator<std::vector<double>>>();
235 auto positionArrayValidator = std::make_shared<CompositeValidator>();
236 positionArrayValidator->add(mandatoryDblArrayValidator);
237 positionArrayValidator->add(mustBePosArr);
238 declareProperty(std::make_unique<PropertyWithValue<double>>(PropertyNames::L1, EMPTY_DBL(), l1Validator),
239 "The primary distance :math:`\\ell_1` from beam to sample");
241 std::make_unique<ArrayProperty<double>>(PropertyNames::L2, std::vector<double>{}, positionArrayValidator),
242 "The secondary distances :math:`\\ell_2` from sample to focus group");
244 std::make_unique<ArrayProperty<double>>(PropertyNames::POLARS, std::vector<double>{}, positionArrayValidator),
245 "The effective polar angle (:math:`2\\theta`) of each focus group");
247 std::make_unique<ArrayProperty<double>>(PropertyNames::AZIMUTHALS, std::vector<double>{}, mustBePosArr),
248 "The effective azimuthal angle :math:`\\phi` for each focus group");
249}
250
251std::map<std::string, std::string> AlignAndFocusPowderSlim::validateInputs() {
252 std::map<std::string, std::string> errors;
253
254 // make sure that data is read in larger chunks than the events processed in a single thread
255 const int disk_chunk = getProperty(PropertyNames::READ_SIZE_FROM_DISK);
256 const int grainsize_events = getProperty(PropertyNames::EVENTS_PER_THREAD);
257 if (disk_chunk < grainsize_events) {
258 const std::string msg(PropertyNames::READ_SIZE_FROM_DISK + " must be larger than " +
262 }
263
264 // only specify allow or block list for logs
265 std::vector<std::string> block_logs = getProperty(PropertyNames::BLOCK_LOGS);
266 if ((!isDefault(PropertyNames::ALLOW_LOGS)) && (!isDefault(PropertyNames::BLOCK_LOGS) && !block_logs.empty())) {
267 errors[PropertyNames::ALLOW_LOGS] = "Cannot specify both allow and block lists";
268 errors[PropertyNames::BLOCK_LOGS] = "Cannot specify both allow and block lists";
269 }
270
271 // the focus group position parameters must have same lengths
272 std::vector<double> l2s = getProperty(PropertyNames::L2);
273 const auto num_l2s = l2s.size();
274 std::vector<double> twoTheta = getProperty(PropertyNames::POLARS);
275 if (num_l2s != twoTheta.size()) {
276 errors[PropertyNames::L2] = strmakef("L2S has inconsistent length %zu", num_l2s);
277 errors[PropertyNames::POLARS] = strmakef("Polar has inconsistent length %zu", twoTheta.size());
278 }
279 // phi is optional, but if set must also have same size
280 std::vector<double> phi = getProperty(PropertyNames::AZIMUTHALS);
281 if (!phi.empty()) {
282 if (num_l2s != phi.size()) {
283 errors[PropertyNames::L2] = strmakef("L2S has inconsistent length %zu", num_l2s);
284 errors[PropertyNames::AZIMUTHALS] = strmakef("Azimuthal has inconsistent length %zu", phi.size());
285 ;
286 }
287 }
288
289 // validate binning information is consistent with each other and number of focus groups
290 const std::vector<double> xmins = getProperty(PropertyNames::X_MIN);
291 const std::vector<double> xmaxs = getProperty(PropertyNames::X_MAX);
292 const std::vector<double> deltas = getProperty(PropertyNames::X_DELTA);
293
294 const auto numMin = xmins.size();
295 const auto numMax = xmaxs.size();
296 const auto numDelta = deltas.size();
297
298 if (std::any_of(deltas.cbegin(), deltas.cend(), [](double d) { return !std::isfinite(d) || d == 0; }))
299 errors[PropertyNames::X_DELTA] = "All must be nonzero";
300 else if (!(numDelta == 1 || numDelta == num_l2s))
301 errors[PropertyNames::X_DELTA] = "Must have 1 or consistent number of values";
302
303 if (!(numMin == 1 || numMin == num_l2s))
304 errors[PropertyNames::X_MIN] = "Must have 1 or consistent number of values";
305 if (!(numMax == 1 || numMax == num_l2s))
306 errors[PropertyNames::X_MAX] = "Must have 1 or consistent number of values";
307 return errors;
308}
309
310//----------------------------------------------------------------------------------------------
314
315 const std::string filename = getPropertyValue(PropertyNames::FILENAME);
316 const Nexus::NexusDescriptor descriptor(filename);
317
318 std::vector<std::string> bankEntryNames;
319 std::vector<std::string> bankNames;
320 determineBanksToLoad(descriptor, bankEntryNames, bankNames);
321
322 const std::size_t num_banks_to_read = bankEntryNames.size();
323 g_log.debug() << "Total banks to read: " << num_banks_to_read << "\n";
324
325 H5::H5File h5file(filename, H5F_ACC_RDONLY, Nexus::H5Util::defaultFileAcc());
326
327 // These give the limits in each file as to which events we actually load (when filtering by time).
328 loadStart.resize(1, 0);
329 loadSize.resize(1, 0);
330
331 size_t num_hist;
332 std::map<size_t, std::set<detid_t>> grouping;
334
335 // Create the output workspace. Load the instrument, this is needed for LoadDiffCal but we cannot create the
336 // output workspace yet because we need grouping information from the cal file to know the correct number of
337 // spectra. We also need to load logs before instrument so we have the correct start time.
338 MatrixWorkspace_sptr wksp = std::make_shared<Workspace2D>();
339 try {
340 LoadEventNexus::loadEntryMetadata(filename, wksp, ENTRY_TOP_LEVEL);
341 } catch (std::exception &e) {
342 g_log.warning() << "Error while loading meta data: " << e.what() << '\n';
343 }
344
345 auto periodLog = std::make_unique<const TimeSeriesProperty<int>>("period_log"); // not used
346 const std::vector<std::string> &allow_logs = getProperty(PropertyNames::ALLOW_LOGS);
347 std::vector<std::string> block_logs = getProperty(PropertyNames::BLOCK_LOGS);
349 block_logs.clear();
350 g_log.information() << "User provided LogAllowList, default LogBlockList being ignored\n";
351 }
352 int nPeriods{1};
353 LoadEventNexus::runLoadNexusLogs<MatrixWorkspace_sptr>(filename, wksp, *this, false, nPeriods, periodLog, allow_logs,
354 block_logs);
355
356 LoadEventNexus::loadInstrument<MatrixWorkspace_sptr>(filename, wksp, ENTRY_TOP_LEVEL, this, &descriptor);
357
358 // load calibration file if provided
359 const std::string cal_filename = getPropertyValue(PropertyNames::CAL_FILE);
360 ITableWorkspace_sptr calibrationWS;
361 if (!cal_filename.empty()) {
362 calibrationWS = this->loadCalFile(wksp, cal_filename, groupingWS);
363 }
364
365 if (groupingWS) {
366 const auto groupIds = groupingWS->getGroupIDs(false);
367 num_hist = groupIds.size();
368 g_log.information() << "Using grouping workspace with " << num_hist << " groups\n";
369 for (size_t outputindex = 0; outputindex < groupIds.size(); ++outputindex) {
370 const auto detids = groupingWS->getDetectorIDsOfGroup(groupIds[outputindex]);
371 grouping[outputindex] = std::set<detid_t>(detids.begin(), detids.end());
372 }
373 } else {
374 // if no grouping defined then everything goes to one spectrum
375 num_hist = 1;
376 }
377
378 this->progress(.0, "Create output workspace");
379 // initialize the workspace with correct number of histograms and bins
380 initializeOutputWorkspace(wksp, num_hist);
381
382 // TODO parameters should be input information
383 const double l1 = getProperty(PropertyNames::L1);
384 const std::vector<double> l2s = getProperty(PropertyNames::L2);
385 const std::vector<double> polars = getProperty(PropertyNames::POLARS); // two-theta
386 // set angle from positive x-axis; will be zero unless specified
387 std::vector<double> setPhi(l2s.size(), 0.0);
390 }
391 const std::vector<double> azimuthals(setPhi);
392 const std::vector<specnum_t> specids;
393 const auto difc_focused = calculate_difc_focused(l1, l2s, polars);
394
395 const auto timeSplitter = this->timeSplitterFromSplitterWorkspace(wksp->run().startTime());
396 const auto filterROI = this->getFilterROI(wksp);
397 // determine the pulse indices from the time and splitter workspace
398 this->progress(.05, "Determining pulse indices");
399
400 this->progress(.07, "Reading events");
401
402 // get detector ids for each bank
403 std::map<size_t, std::set<detid_t>> bank_detids;
404 for (size_t bankIndex = 0; bankIndex < num_banks_to_read; ++bankIndex) {
405 try {
406 bank_detids[bankIndex] = wksp->getInstrument()->getDetectorIDsInBank(bankNames.at(bankIndex));
407 } catch (std::exception &e) {
408 g_log.warning() << "Error getting detector IDs for " << bankNames.at(bankIndex) << ": " << e.what() << "\n";
409 }
410 }
411
412 // create map of detid to output spectrum number to be used in focusing
413 if (!grouping.empty()) {
414 for (const auto &group : grouping) {
415 for (const auto &detid : group.second) {
416 detIDToSpecNum[detid] = group.first;
417 }
418 }
419 } else {
420 // no grouping provided so everything goes in the 1 output spectrum
421 grouping[0] = std::set<detid_t>{};
422 for (const auto &[i, detids] : bank_detids) {
423 grouping[0].insert(detids.begin(), detids.end());
424 for (const auto &detid : detids) {
425 detIDToSpecNum[detid] = 0;
426 }
427 }
428 }
429
430 // create values for focusing time-of-flight
431 this->progress(.1, "Creating calibration constants");
432 if (calibrationWS) {
433 this->initCalibrationConstantsFromCalWS(difc_focused, calibrationWS);
434 } else {
435 this->initCalibrationConstants(wksp, difc_focused);
436 }
437
438 // calculate correction for tof of the neutron at the sample position
440 this->initScaleAtSample(wksp);
441 }
442
443 // set the instrument. Needs to happen after we get detector ids for each bank
444 this->progress(.15, "Set instrument geometry");
445 wksp = this->editInstrumentGeometry(wksp, l1, polars, specids, l2s, azimuthals);
446
447 // convert to TOF if not already
448 this->progress(.17, "Convert bins to TOF");
449 wksp = this->convertToTOF(wksp);
450
451 // create the bank calibration factory to share with all of the ProcessBank*Task objects
452 BankCalibrationFactory calibFactory(m_calibration, m_scale_at_sample, grouping, m_masked, bank_detids);
453
454 // threaded processing of the banks
455 const int DISK_CHUNK = getProperty(PropertyNames::READ_SIZE_FROM_DISK);
456 const int GRAINSIZE_EVENTS = getProperty(PropertyNames::EVENTS_PER_THREAD);
457 g_log.debug() << (DISK_CHUNK / GRAINSIZE_EVENTS) << " threads per chunk\n";
458
459 // get pulse times from frequency log on workspace. We use this in several places.
460 const auto frequency_log = dynamic_cast<const TimeSeriesProperty<double> *>(wksp->run().getProperty("frequency"));
461 if (!frequency_log) {
462 throw std::runtime_error("Frequency log not found in workspace run");
463 }
464 m_pulse_times = std::make_shared<std::vector<Mantid::Types::Core::DateAndTime>>(frequency_log->timesAsVector());
465
466 if (timeSplitter.empty()) {
467 // create the nexus loader for handling combined calls to hdf5
468
470 const auto pulse_indices = this->determinePulseIndices(filterROI);
471 auto loader = std::make_shared<NexusLoader>(is_time_filtered, pulse_indices);
472
473 auto progress = std::make_shared<API::Progress>(this, .17, .9, num_banks_to_read);
474 ProcessBankTask task(bankEntryNames, h5file, loader, processingData, calibFactory, static_cast<size_t>(DISK_CHUNK),
475 static_cast<size_t>(GRAINSIZE_EVENTS), progress);
476 // generate threads only if appropriate
477 if (num_banks_to_read > 1) {
478 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_banks_to_read), task);
479 } else {
480 task(tbb::blocked_range<size_t>(0, 1));
481 }
482
483 // close the file so child algorithms can do their thing
484 h5file.close();
485
486 // copy data from processingData to wksp
487 storeSpectraProcessingData(processingData, wksp);
488
489 // update the run TimeROI and remove log data outside the time ROI
490 wksp->mutableRun().setTimeROI(filterROI);
491 wksp->mutableRun().removeDataOutsideTimeROI();
492
493 setProperty(PropertyNames::OUTPUT_WKSP, std::move(wksp));
494 } else {
495 std::string ws_basename = this->getPropertyValue(PropertyNames::OUTPUT_WKSP);
496 std::vector<std::string> wsNames;
497 std::vector<int> workspaceIndices;
498 std::vector<MatrixWorkspace_sptr> workspaces;
499 std::vector<SpectraProcessingData> processingDatas;
500 for (const int &splitter_target : timeSplitter.outputWorkspaceIndices()) {
501 std::string ws_name = ws_basename + "_" + timeSplitter.getWorkspaceIndexName(splitter_target);
502 wsNames.push_back(std::move(ws_name));
503 workspaceIndices.push_back(splitter_target);
504 workspaces.emplace_back(wksp->clone());
505 processingDatas.push_back(initializeSpectraProcessingData(workspaces.back()));
506 }
507
508 auto progress = std::make_shared<API::Progress>(this, .17, .9, num_banks_to_read * workspaceIndices.size());
510 g_log.information() << "Using ProcessBankSplitFullTimeTask for splitter processing\n";
511
512 // Get the combined time ROI for all targets so we only load necessary events.
513 // Need to offset the start time to account for tof's greater than pulsetime. 66.6ms is 4 pulses.
514 auto combined_time_roi = timeSplitter.combinedTimeROI(PULSETIME_OFFSET);
515 if (!filterROI.useAll()) {
516 combined_time_roi.update_intersection(filterROI);
517 }
518
519 // create the nexus loader for handling combined calls to hdf5
520 const auto pulse_indices = this->determinePulseIndices(combined_time_roi);
521 auto loader = std::make_shared<NexusLoader>(is_time_filtered, pulse_indices);
522
523 const auto &splitterMap = timeSplitter.getSplittersMap();
524
525 ProcessBankSplitFullTimeTask task(bankEntryNames, h5file, loader, workspaceIndices, processingDatas, calibFactory,
526 static_cast<size_t>(DISK_CHUNK), static_cast<size_t>(GRAINSIZE_EVENTS),
527 splitterMap, m_pulse_times, progress);
528
529 // generate threads only if appropriate
530 if (num_banks_to_read > 1) {
531 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_banks_to_read), task);
532 } else {
533 task(tbb::blocked_range<size_t>(0, 1));
534 }
535
537 g_log.information() << "Using ProcessBankSplitTask for splitter processing\n";
538 // determine the pulse indices from the time and splitter workspace
539 const auto target_to_pulse_indices = this->determinePulseIndicesTargets(filterROI, timeSplitter);
540 // create the nexus loader for handling combined calls to hdf5
541 std::vector<PulseROI> pulse_indices; // intentionally empty to get around loader needing const reference
542 auto loader = std::make_shared<NexusLoader>(is_time_filtered, pulse_indices, target_to_pulse_indices);
543
544 ProcessBankSplitTask task(bankEntryNames, h5file, loader, workspaceIndices, processingDatas, calibFactory,
545 static_cast<size_t>(DISK_CHUNK), static_cast<size_t>(GRAINSIZE_EVENTS), progress);
546 // generate threads only if appropriate
547 if (num_banks_to_read > 1) {
548 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_banks_to_read), task);
549 } else {
550 task(tbb::blocked_range<size_t>(0, 1));
551 }
552 } else {
553 g_log.information() << "Using ProcessBankTask for splitter processing\n";
554 // loop over the targets in the splitter workspace, each target gets its own output workspace
555 tbb::parallel_for(
556 tbb::blocked_range<size_t>(0, workspaceIndices.size()),
557 [&](const tbb::blocked_range<size_t> &target_indices) {
558 for (size_t target_index = target_indices.begin(); target_index != target_indices.end(); ++target_index) {
559 const int splitter_target = workspaceIndices[target_index];
560
561 auto splitter_roi = timeSplitter.getTimeROI(splitter_target);
562 // copy the roi so we can modify it just for this target
563 auto target_roi = filterROI;
564 if (target_roi.useAll())
565 target_roi = std::move(splitter_roi); // use the splitter ROI if no time filtering is specified
566 else if (!splitter_roi.useAll())
567 target_roi.update_intersection(splitter_roi); // otherwise intersect with the splitter ROI
568
569 // clone wksp for this target
570 MatrixWorkspace_sptr target_wksp = workspaces[target_index];
571
572 const auto pulse_indices = this->determinePulseIndices(target_roi);
573 auto loader = std::make_shared<NexusLoader>(is_time_filtered, pulse_indices);
574
575 ProcessBankTask task(bankEntryNames, h5file, loader, processingDatas[target_index], calibFactory,
576 static_cast<size_t>(DISK_CHUNK), static_cast<size_t>(GRAINSIZE_EVENTS), progress);
577 // generate threads only if appropriate
578 if (num_banks_to_read > 1) {
579 tbb::parallel_for(tbb::blocked_range<size_t>(0, num_banks_to_read), task);
580 } else {
581 task(tbb::blocked_range<size_t>(0, 1));
582 }
583 }
584 });
585 }
586
587 // close the file so child algorithms can do their thing
588 h5file.close();
589
590 // add the workspaces to the ADS
591 for (size_t idx = 0; idx < workspaceIndices.size(); ++idx) {
592 // copy data from processingData to wksp
593 storeSpectraProcessingData(processingDatas[idx], workspaces[idx]);
594
595 // create the target time ROI combining the splitter and filter ROIs
596 auto target_roi = timeSplitter.getTimeROI(workspaceIndices[idx]);
597 if (target_roi.useAll())
598 target_roi = filterROI; // use the splitter ROI if no time filtering is specified
599 else if (!filterROI.useAll())
600 target_roi.update_intersection(filterROI); // otherwise intersect with the splitter ROI
601
602 // update the run TimeROI and remove log data outside the time ROI
603 workspaces[idx]->mutableRun().setTimeROI(target_roi);
604 workspaces[idx]->mutableRun().removeDataOutsideTimeROI();
605 AnalysisDataService::Instance().addOrReplace(wsNames[idx], workspaces[idx]);
606 }
607
608 // group the workspaces
609 auto groupws = createChildAlgorithm("GroupWorkspaces", 0.95, 1.00, true);
610 groupws->setAlwaysStoreInADS(true);
611 groupws->setProperty("InputWorkspaces", wsNames);
612 groupws->setProperty("OutputWorkspace", ws_basename);
613 groupws->execute();
614
615 if (!groupws->isExecuted()) {
616 throw std::runtime_error("Failed to group output workspaces");
617 }
618
619 API::Workspace_sptr outputWorkspace = AnalysisDataService::Instance().retrieveWS<API::Workspace>(ws_basename);
620
621 setProperty(PropertyNames::OUTPUT_WKSP, outputWorkspace);
622 }
623}
624
625void AlignAndFocusPowderSlim::determineBanksToLoad(const Nexus::NexusDescriptor &descriptor,
626 std::vector<std::string> &bankEntryNames,
627 std::vector<std::string> &bankNames) {
628 // Now we want to go through all the bankN_event entries
629
630 std::set<std::string> const classEntries = descriptor.allAddressesOfType("NXevent_data");
631 if (classEntries.empty()) {
632 throw std::runtime_error("No NXevent_data entries found in file");
633 }
634
635 const int bankNum = getProperty(PropertyNames::BANK_NUMBER);
636
637 const std::regex classRegex("(/entry/)([^/]*)");
638 std::smatch groups;
639 for (const std::string &classEntry : classEntries) {
640 if (std::regex_match(classEntry, groups, classRegex)) {
641 const std::string entry_name(groups[2].str());
642 if (classEntry.ends_with("bank_error_events")) {
643 // do nothing
644 } else if (classEntry.ends_with("bank_unmapped_events")) {
645 // do nothing
646 } else {
647 auto underscore_pos = entry_name.find_first_of('_');
648 const auto bankName = entry_name.substr(0, underscore_pos);
649 if (bankNum != EMPTY_INT()) {
650 if (bankName != ("bank" + std::to_string(bankNum))) {
651 continue; // skip this bank
652 }
653 }
654 bankEntryNames.push_back(entry_name);
655 bankNames.push_back(bankName);
656 }
657 }
658 }
659}
660
661void AlignAndFocusPowderSlim::initializeOutputWorkspace(const MatrixWorkspace_sptr &wksp, size_t num_hist) {
662 // set up the output workspace binning
663 const BINMODE binmode = getPropertyValue(PropertyNames::BINMODE);
664 const bool linearBins = bool(binmode == BinningMode::LINEAR);
665 const std::string binUnits = getPropertyValue(PropertyNames::BIN_UNITS);
666 std::vector<double> x_delta = getProperty(PropertyNames::X_DELTA);
667 std::vector<double> x_min = getProperty(PropertyNames::X_MIN);
668 std::vector<double> x_max = getProperty(PropertyNames::X_MAX);
669 const bool raggedBins = (x_delta.size() != 1 || x_min.size() != 1 || x_max.size() != 1);
670
671 constexpr bool resize_xnew{true};
672 constexpr bool full_bins_only{false};
673
674 // always use the first histogram x-values for initialization
675 HistogramData::BinEdges XValues(0);
676 if (linearBins) {
677 const std::vector<double> params{x_min[0], x_delta[0], x_max[0]};
679 Kernel::VectorHelper::createAxisFromRebinParams(params, XValues.mutableRawData(), resize_xnew, full_bins_only));
680 } else {
681 const std::vector<double> params{x_min[0], -1. * std::abs(x_delta[0]), x_max[0]};
683 Kernel::VectorHelper::createAxisFromRebinParams(params, XValues.mutableRawData(), resize_xnew, full_bins_only));
684 }
685 wksp->initialize(num_hist, HistogramData::Histogram(XValues, HistogramData::Counts(XValues.size() - 1, 0.0)));
686
687 if (raggedBins) {
688 // if ragged bins, we need to resize the x-values for each histogram after the first one
689 if (x_delta.size() == 1)
690 x_delta.resize(num_hist, x_delta[0]);
691 if (x_min.size() == 1)
692 x_min.resize(num_hist, x_min[0]);
693 if (x_max.size() == 1)
694 x_max.resize(num_hist, x_max[0]);
695
696 for (size_t i = 1; i < num_hist; ++i) {
697 HistogramData::BinEdges XValues_new(0);
698
699 if (linearBins) {
700 const std::vector<double> params{x_min[i], x_delta[i], x_max[i]};
701 Kernel::VectorHelper::createAxisFromRebinParams(params, XValues_new.mutableRawData(), resize_xnew,
702 full_bins_only);
703 } else {
704 const std::vector<double> params{x_min[i], -1. * std::abs(x_delta[i]), x_max[i]};
705 Kernel::VectorHelper::createAxisFromRebinParams(params, XValues_new.mutableRawData(), resize_xnew,
706 full_bins_only);
707 }
708 wksp->setHistogram(i, HistogramData::Histogram(XValues_new, HistogramData::Counts(XValues_new.size() - 1, 0.0)));
709 }
710 }
711
712 wksp->getAxis(0)->setUnit(binUnits);
713 wksp->setYUnit("Counts");
714}
715
717AlignAndFocusPowderSlim::initializeSpectraProcessingData(const API::MatrixWorkspace_sptr &outputWS) {
718 SpectraProcessingData processingData;
719 const size_t numSpectra = outputWS->getNumberHistograms();
720 for (size_t i = 0; i < numSpectra; ++i) {
721 const auto &spectrum = outputWS->getSpectrum(i);
722 processingData.binedges.emplace_back(&spectrum.readX());
723 processingData.counts.emplace_back(spectrum.dataY().size());
724 }
725 return processingData;
726}
727
728void AlignAndFocusPowderSlim::storeSpectraProcessingData(const SpectraProcessingData &processingData,
729 const API::MatrixWorkspace_sptr &outputWS) {
730 const size_t numSpectra = outputWS->getNumberHistograms();
731 for (size_t i = 0; i < numSpectra; ++i) {
732 auto &spectrum = outputWS->getSpectrum(i);
733 auto &y_values = spectrum.dataY();
734 std::transform(
735 processingData.counts[i].cbegin(), processingData.counts[i].cend(), y_values.begin(),
736 [](const std::atomic_uint32_t &val) { return static_cast<double>(val.load(std::memory_order_relaxed)); });
737 auto &e_values = spectrum.dataE();
738 std::transform(processingData.counts[i].cbegin(), processingData.counts[i].cend(), e_values.begin(),
739 [](const std::atomic_uint32_t &val) {
740 return std::sqrt(static_cast<double>(val.load(std::memory_order_relaxed)));
741 });
742 }
743}
744
745void AlignAndFocusPowderSlim::initCalibrationConstants(API::MatrixWorkspace_sptr &wksp,
746 const std::vector<double> &difc_focus) {
747 const auto detInfo = wksp->detectorInfo();
748
749 for (auto iter = detInfo.cbegin(); iter != detInfo.cend(); ++iter) {
750 if (!iter->isMonitor()) {
751 const auto difc_focussed = getFocussedPostion(static_cast<detid_t>(iter->detid()), difc_focus, detIDToSpecNum);
752 if (difc_focussed == IGNORE_PIXEL)
753 m_calibration.emplace(static_cast<detid_t>(iter->detid()), IGNORE_PIXEL);
754 else
755 m_calibration.emplace(static_cast<detid_t>(iter->detid()),
756 difc_focussed / detInfo.difcUncalibrated(iter->index()));
757 }
758 }
759}
760
761void AlignAndFocusPowderSlim::initCalibrationConstantsFromCalWS(const std::vector<double> &difc_focus,
762 const ITableWorkspace_sptr calibrationWS) {
763 for (size_t row = 0; row < calibrationWS->rowCount(); ++row) {
764 const detid_t detid = calibrationWS->cell<int>(row, 0);
765 const double detc = calibrationWS->cell<double>(row, 1);
766 const auto difc_focussed = getFocussedPostion(detid, difc_focus, detIDToSpecNum);
767 if (difc_focussed == IGNORE_PIXEL)
768 m_calibration.emplace(detid, IGNORE_PIXEL);
769 else
770 m_calibration.emplace(detid, difc_focussed / detc);
771 }
772}
773
774const ITableWorkspace_sptr AlignAndFocusPowderSlim::loadCalFile(const Mantid::API::Workspace_sptr &inputWS,
775 const std::string &filename,
776 GroupingWorkspace_sptr &groupingWS) {
777 const bool load_grouping = !groupingWS;
778
779 auto alg = createChildAlgorithm("LoadDiffCal");
780 alg->setProperty("InputWorkspace", inputWS);
781 alg->setPropertyValue("Filename", filename);
782 alg->setProperty<bool>("MakeCalWorkspace", true);
783 alg->setProperty<bool>("MakeGroupingWorkspace", load_grouping);
784 alg->setProperty<bool>("MakeMaskWorkspace", true);
785 alg->setPropertyValue("WorkspaceName", "temp");
786 alg->executeAsChildAlg();
787
788 if (load_grouping) {
789 g_log.debug() << "Loading grouping workspace from calibration file\n";
790 groupingWS = alg->getProperty("OutputGroupingWorkspace");
791 }
792
793 const ITableWorkspace_sptr calibrationWS = alg->getProperty("OutputCalWorkspace");
794
795 const MaskWorkspace_sptr maskWS = alg->getProperty("OutputMaskWorkspace");
796 m_masked = maskWS->getMaskedDetectors();
797 g_log.debug() << "Masked detectors: " << m_masked.size() << '\n';
798
799 return calibrationWS;
800}
801
806void AlignAndFocusPowderSlim::initScaleAtSample(const API::MatrixWorkspace_sptr &wksp) {
807 // detector information for all of the L2
808 const auto detInfo = wksp->detectorInfo();
809 // cache a single L1 value
810 const double L1 = detInfo.l1();
811
812 if (this->getProperty(PropertyNames::CORRECTION_TO_SAMPLE)) {
813 // calculate scale factors for each detector
814 for (auto iter = detInfo.cbegin(); iter != detInfo.cend(); ++iter) {
815 if (!iter->isMonitor()) {
816 const double path_correction = L1 / (L1 + iter->l2()) * 1000.0;
817 m_scale_at_sample.emplace(static_cast<detid_t>(iter->detid()), path_correction);
818 }
819 }
820 } else {
821 // set all scale factors to 1.0
822 for (auto iter = detInfo.cbegin(); iter != detInfo.cend(); ++iter) {
823 if (!iter->isMonitor()) {
824 m_scale_at_sample.emplace(static_cast<detid_t>(iter->detid()), 1000.0);
825 }
826 }
827 }
828}
829
830API::MatrixWorkspace_sptr AlignAndFocusPowderSlim::editInstrumentGeometry(
831 API::MatrixWorkspace_sptr &wksp, const double l1, const std::vector<double> &polars,
832 const std::vector<specnum_t> &specids, const std::vector<double> &l2s, const std::vector<double> &azimuthals) {
833 API::IAlgorithm_sptr editAlg = createChildAlgorithm("EditInstrumentGeometry");
834 editAlg->setLoggingOffset(1);
835 editAlg->setProperty("Workspace", wksp);
836 if (l1 > 0.)
837 editAlg->setProperty("PrimaryFlightPath", l1);
838 if (!polars.empty())
839 editAlg->setProperty("Polar", polars);
840 if (!specids.empty())
841 editAlg->setProperty("SpectrumIDs", specids);
842 if (!l2s.empty())
843 editAlg->setProperty("L2", l2s);
844 if (!azimuthals.empty())
845 editAlg->setProperty("Azimuthal", azimuthals);
846 editAlg->executeAsChildAlg();
847
848 wksp = editAlg->getProperty("Workspace");
849
850 return wksp;
851}
852
853API::MatrixWorkspace_sptr AlignAndFocusPowderSlim::convertToTOF(API::MatrixWorkspace_sptr &wksp) {
854 if (wksp->getAxis(0)->unit()->unitID() == "TOF") {
855 // already in TOF, no need to convert
856 return wksp;
857 }
858
859 API::IAlgorithm_sptr convertUnits = createChildAlgorithm("ConvertUnits");
860 convertUnits->setProperty("InputWorkspace", wksp);
861 convertUnits->setPropertyValue("Target", "TOF");
862 convertUnits->executeAsChildAlg();
863 wksp = convertUnits->getProperty("OutputWorkspace");
864
865 return wksp;
866}
867
875Kernel::TimeROI AlignAndFocusPowderSlim::getFilterROI(const API::MatrixWorkspace_sptr &wksp) {
876 Kernel::TimeROI roi;
877 const auto startOfRun = wksp->run().startTime();
878
879 // filter by time
880 double filter_time_start_sec = getProperty(PropertyNames::FILTER_TIMESTART);
881 double filter_time_stop_sec = getProperty(PropertyNames::FILTER_TIMESTOP);
882 if (filter_time_start_sec != EMPTY_DBL() || filter_time_stop_sec != EMPTY_DBL()) {
883 this->progress(.15, "Creating time filtering");
884 g_log.information() << "Filtering pulses from " << filter_time_start_sec << " to " << filter_time_stop_sec << "s\n";
885
886 try {
887 roi.addROI(startOfRun + (filter_time_start_sec == EMPTY_DBL() ? 0.0 : filter_time_start_sec),
888 startOfRun + filter_time_stop_sec); // start and stop times in seconds
889 } catch (const std::runtime_error &e) {
890 throw std::invalid_argument("Invalid time range for filtering: " + std::string(e.what()));
891 }
892 }
893
894 // filter bad pulses
895 if (getProperty(PropertyNames::FILTER_BAD_PULSES)) {
896 this->progress(.16, "Filtering bad pulses");
897
898 // get limits from proton_charge
899 const auto [min_pcharge, max_pcharge, mean] =
900 wksp->run().getBadPulseRange(LOG_CHARGE_NAME, getProperty(PropertyNames::FILTER_BAD_PULSES_LOWER_CUTOFF));
901 g_log.information() << "Filtering bad pulses; pcharge outside of " << min_pcharge << " to " << max_pcharge << '\n';
902
903 const auto run_start = wksp->getFirstPulseTime();
904 const auto run_stop = wksp->getLastPulseTime();
905
906 const auto log = dynamic_cast<const TimeSeriesProperty<double> *>(wksp->run().getLogData(LOG_CHARGE_NAME));
907 if (log) {
908 // need to have centre=true for proton_charge
909 roi = log->makeFilterByValue(min_pcharge, max_pcharge, true, Mantid::Kernel::TimeInterval(run_start, run_stop),
910 0.0, true, &roi);
911 }
912 }
913 return roi;
914}
915
922std::vector<PulseROI> AlignAndFocusPowderSlim::determinePulseIndices(const TimeROI &filterROI) {
923
924 std::vector<PulseROI> pulse_indices;
925 if (filterROI.useAll()) {
926 pulse_indices.emplace_back(0, std::numeric_limits<size_t>::max());
927 } else {
928 is_time_filtered = true;
929 pulse_indices = filterROI.calculate_indices(*m_pulse_times);
930 if (pulse_indices.empty())
931 throw std::invalid_argument("No valid pulse time indices found for filtering");
932 }
933
934 return pulse_indices;
935}
936
945std::vector<std::pair<int, PulseROI>>
946AlignAndFocusPowderSlim::determinePulseIndicesTargets(const TimeROI &filterROI, const TimeSplitter &timeSplitter) {
947 std::vector<PulseROI> pulse_indices;
948 if (filterROI.useAll()) {
949 pulse_indices.emplace_back(0, std::numeric_limits<size_t>::max());
950 } else {
951 pulse_indices = filterROI.calculate_indices(*m_pulse_times);
952 if (pulse_indices.empty())
953 throw std::invalid_argument("No valid pulse time indices found for filtering");
954 }
955
956 const auto target_to_pulse_indices = timeSplitter.calculate_target_indices(*m_pulse_times);
957
958 // calculate intersection of target pulse indices and time filter pulse indices (removes pulses outside filterROI)
959 std::vector<std::pair<int, PulseROI>> intersected_target_pulse_indices;
960 auto pulse_it = pulse_indices.cbegin();
961 for (const auto &target_pair : target_to_pulse_indices) {
962 // move pulse_it to the first pulse that could overlap
963 while (pulse_it != pulse_indices.cend() && pulse_it->second <= target_pair.second.first) {
964 ++pulse_it;
965 }
966 // check for overlaps
967 auto check_it = pulse_it;
968 while (check_it != pulse_indices.cend() && check_it->first < target_pair.second.second) {
969 // there is an overlap
970 size_t start_index = std::max(check_it->first, target_pair.second.first);
971 size_t stop_index = std::min(check_it->second, target_pair.second.second);
972 if (start_index < stop_index) {
973 intersected_target_pulse_indices.emplace_back(target_pair.first, PulseROI(start_index, stop_index));
974 }
975 ++check_it;
976 }
977 }
978
979 return intersected_target_pulse_indices;
980}
981
983AlignAndFocusPowderSlim::timeSplitterFromSplitterWorkspace(const Types::Core::DateAndTime &filterStartTime) {
984 API::Workspace_sptr tempws = this->getProperty(PropertyNames::SPLITTER_WS);
985 DataObjects::SplittersWorkspace_sptr splittersWorkspace =
986 std::dynamic_pointer_cast<DataObjects::SplittersWorkspace>(tempws);
987 DataObjects::TableWorkspace_sptr splitterTableWorkspace =
988 std::dynamic_pointer_cast<DataObjects::TableWorkspace>(tempws);
989 API::MatrixWorkspace_sptr matrixSplitterWS = std::dynamic_pointer_cast<API::MatrixWorkspace>(tempws);
990
991 if (!splittersWorkspace && !splitterTableWorkspace && !matrixSplitterWS)
992 return {};
993
994 const bool isSplittersRelativeTime = this->getProperty(PropertyNames::SPLITTER_RELATIVE);
995
996 TimeSplitter time_splitter;
997 if (splittersWorkspace) {
998 time_splitter = TimeSplitter{splittersWorkspace};
999 } else if (splitterTableWorkspace) {
1000 time_splitter =
1001 TimeSplitter(splitterTableWorkspace, isSplittersRelativeTime ? filterStartTime : DateAndTime::GPS_EPOCH);
1002 } else {
1003 time_splitter = TimeSplitter(matrixSplitterWS, isSplittersRelativeTime ? filterStartTime : DateAndTime::GPS_EPOCH);
1004 }
1005
1006 return time_splitter;
1007}
1008
1009} // namespace Mantid::DataHandling::AlignAndFocusPowderSlim
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
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:422
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.
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.
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)
const API::ITableWorkspace_sptr loadCalFile(const API::Workspace_sptr &inputWS, const std::string &filename, DataObjects::GroupingWorkspace_sptr &groupingWS)
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 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:1205
int 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