Mantid
Loading...
Searching...
No Matches
ConvertToMD.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
9#include <algorithm>
10
13#include "MantidAPI/Run.h"
16
25
30
32
37
38using namespace Mantid::API;
39using namespace Mantid::Kernel;
40using namespace Mantid::DataObjects;
42
43namespace Mantid::MDAlgorithms {
44
45//
46// Register the algorithm into the AlgorithmFactory
47DECLARE_ALGORITHM(ConvertToMD)
48
49void ConvertToMD::init() {
51 declareProperty(std::make_unique<WorkspaceProperty<IMDEventWorkspace>>("OutputWorkspace", "", Direction::Output),
52 "Name of the output *MDEventWorkspace*.");
53
54 declareProperty(std::make_unique<PropertyWithValue<bool>>("OverwriteExisting", true, Direction::Input),
55 "By default (\"1\"), existing Output Workspace will be replaced. Select "
56 "false (\"0\") if you want to add new events to the workspace, which "
57 "already exist. "
58 "\nChoosing \"0\" can be very inefficient for file-based workspaces");
59
60 declareProperty(std::make_unique<ArrayProperty<double>>("MinValues"),
61 "It has to be N comma separated values, where N is the "
62 "number of dimensions of the target workspace. Values "
63 "smaller then specified here will not be added to "
64 "workspace.\n Number N is defined by properties 4,6 and 7 "
65 "and "
66 "described on *MD Transformation factory* page. See also "
67 ":ref:`algm-ConvertToMDMinMaxLocal`");
68
69 // TODO: " If a minimal target workspace range is higher then the one
70 // specified here, the target workspace range will be used instead " );
71
72 declareProperty(std::make_unique<ArrayProperty<double>>("MaxValues"),
73 "A list of the same size and the same units as MinValues "
74 "list. Values higher or equal to the specified by "
75 "this list will be ignored");
76 // TODO: "If a maximal target workspace range is lower, then one of
77 // specified here, the target workspace range will be used instead" );
78
79 // Box controller properties. These are the defaults
80 this->initBoxControllerProps("5" /*SplitInto*/, 1000 /*SplitThreshold*/, 20 /*MaxRecursionDepth*/);
81 // additional box controller settings property.
82 auto mustBeMoreThan1 = std::make_shared<BoundedValidator<int>>();
83 mustBeMoreThan1->setLower(1);
84
85 declareProperty(std::make_unique<PropertyWithValue<int>>("MinRecursionDepth", 1, mustBeMoreThan1),
86 "Optional. If specified, then all the boxes will be split to this "
87 "minimum recursion depth. 0 = no splitting, "
88 "1 = one level of splitting, etc. \n Be careful using this since it can "
89 "quickly create a huge number of :math:`boxes = "
90 "SplitInto^{MinRercursionDepth \\times NumDimensions}`. \n But setting "
91 "this property equal to MaxRecursionDepth "
92 "is necessary if one wants to generate multiple file based "
93 "workspaces in order to merge them later.");
94 setPropertyGroup("MinRecursionDepth", getBoxSettingsGroupName());
95
96 declareProperty(std::make_unique<PropertyWithValue<bool>>("TopLevelSplitting", false, Direction::Input),
97 "This option causes a split of the top level, i.e. level0, of 50 for the "
98 "first four dimensions.");
99
100 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::OptionalSave, ".nxs"),
101 "The name of the Nexus file to write, as a full or relative path.\n"
102 "Only used if FileBackEnd is true.");
103 setPropertySettings("Filename", std::make_unique<EnabledWhenProperty>("FileBackEnd", IS_EQUAL_TO, "1"));
104
105 declareProperty("FileBackEnd", false,
106 "If true, Filename must also be specified. The algorithm "
107 "will create the specified file in addition to an output "
108 "workspace. The workspace will load data from the file on "
109 "demand in order to reduce memory use.");
110
111 std::vector<std::string> converterType{"Default", "Indexed"};
112
113 auto loadTypeValidator = std::make_shared<StringListValidator>(converterType);
114 declareProperty("ConverterType", "Default", loadTypeValidator,
115 "[Default, Indexed], indexed is the experimental type that "
116 "can speedup the conversion process"
117 "for the big files using the indexing.");
118}
119//----------------------------------------------------------------------------------------------
120
121const std::string ConvertToMD::name() const { return "ConvertToMD"; }
122
123int ConvertToMD::version() const { return 1; }
124
125std::map<std::string, std::string> ConvertToMD::validateInputs() {
126 std::map<std::string, std::string> result;
127
128 const std::string treeBuilderType = this->getProperty("ConverterType");
129 const bool topLevelSplittingChecked = this->getProperty("TopLevelSplitting");
130 std::vector<int> split_into = this->getProperty("SplitInto");
131 const std::string filename = this->getProperty("Filename");
132 const bool fileBackEnd = this->getProperty("FileBackEnd");
133 const bool useLogTimes = this->getProperty("UseLogTimes");
134
135 if (fileBackEnd && filename.empty()) {
136 result["Filename"] = "Filename must be given if FileBackEnd is required.";
137 }
138
139 if (treeBuilderType.find("Indexed") != std::string::npos) {
140 if (fileBackEnd)
141 result["ConverterType"] += "No file back end implemented "
142 "for indexed version of algorithm. ";
143 if (topLevelSplittingChecked)
144 result["ConverterType"] += "The usage of top level splitting is "
145 "not possible for indexed version of algorithm. ";
146
147 bool validSplitInfo = ConvToMDEventsWSIndexing::isSplitValid(split_into);
148 if (!validSplitInfo)
149 result["ConverterType"] += "The split parameter should be the same for"
150 " all dimensions and be equal the power of 2"
151 " (2 ,4, 8, 16,..) for indexed version of algorithm. ";
152 }
153
154 std::vector<double> minVals = this->getProperty("MinValues");
155 std::vector<double> maxVals = this->getProperty("MaxValues");
156
157 if (minVals.size() != maxVals.size()) {
158 std::stringstream msg;
159 msg << "Rank of MinValues != MaxValues (" << minVals.size() << "!=" << maxVals.size() << ")";
160 result["MinValues"] = msg.str();
161 result["MaxValues"] = msg.str();
162 } else {
163 std::stringstream msg;
164
165 size_t rank = minVals.size();
166 for (size_t i = 0; i < rank; ++i) {
167 if (minVals[i] >= maxVals[i]) {
168 if (msg.str().empty())
169 msg << "max not bigger than min ";
170 else
171 msg << ", ";
172 msg << "at index=" << (i + 1) << " (" << minVals[i] << ">=" << maxVals[i] << ")";
173 }
174 }
175
176 if (!msg.str().empty()) {
177 result["MinValues"] = msg.str();
178 result["MaxValues"] = msg.str();
179 }
180 }
181
182 if (useLogTimes) {
183 API::MatrixWorkspace_const_sptr inWS = this->getProperty("InputWorkspace");
184 const auto evWs = std::dynamic_pointer_cast<const DataObjects::EventWorkspace>(inWS);
185 if (!evWs) {
186 result["UseLogTimes"] = "UseLogTimes requires the input to be an EventWorkspace.";
187 } else {
188 const std::vector<std::string> otherDims = getProperty("OtherDimensions");
189 for (auto &nameDim : otherDims) {
190 if (!inWS->run().hasProperty(nameDim)) {
191 result["UseLogTimes"] = "Input workspace does not have " + nameDim + " property in its logs.";
192 } else {
193 if (Kernel::Property *pProperty = inWS->run().getProperty(nameDim);
194 !dynamic_cast<TimeSeriesProperty<double> *>(pProperty)) {
195 result["UseLogTimes"] = "Property " + nameDim + " is not a time series property, log times can't be used.";
196 }
197 }
198 }
199 }
200 }
201
202 return result;
203}
204
205//----------------------------------------------------------------------------------------------
206/* Execute the algorithm. */
208 // initiate class which would deal with any dimension workspaces requested by
209 // algorithm parameters
210 if (!m_OutWSWrapper)
211 m_OutWSWrapper = std::make_shared<MDEventWSWrapper>();
212
213 // -------- get Input workspace
214 m_InWS2D = getProperty("InputWorkspace");
215
216 const std::string out_filename = this->getProperty("Filename");
217 const bool fileBackEnd = this->getProperty("FileBackEnd");
218
219 // get the output workspace
220 API::IMDEventWorkspace_sptr spws = getProperty("OutputWorkspace");
221
222 // Collect and Analyze the requests to the job, specified by the input
223 // parameters:
224 // a) Q selector:
225 std::string QModReq = getProperty("QDimensions");
226 // b) the energy exchange mode
227 std::string dEModReq = getProperty("dEAnalysisMode");
228 // c) other dim property;
229 std::vector<std::string> otherDimNames = getProperty("OtherDimensions");
230 // d) The output dimensions in the Q3D mode, processed together with
231 // QConversionScales
232 std::string QFrame = getProperty("Q3DFrames");
233 // e) part of the procedure, specifying the target dimensions units. Currently
234 // only Q3D target units can be converted to different flavors of hkl
235 std::string convertTo_ = getProperty("QConversionScales");
236
237 // get the min and max values for the dimensions from the input properties
238 std::vector<double> dimMin = getProperty("MinValues");
239 std::vector<double> dimMax = getProperty("MaxValues");
240
241 // Sanity check some options
242 if (QModReq != MDTransfQ3D().transfID()) {
243 MDWSTransform transform;
244 const std::string autoSelect = transform.getTargetFrames()[CnvrtToMD::AutoSelect];
245 if (QFrame != autoSelect) {
246 g_log.warning("Q3DFrames value ignored with QDimensions != " + MDTransfQ3D().transfID());
247 QFrame = autoSelect;
248 }
249 const std::string noScaling = transform.getQScalings()[CnvrtToMD::NoScaling];
250 if (convertTo_ != noScaling) {
251 g_log.warning("QConversionScales value ignored with QDimensions != " + MDTransfQ3D().transfID());
252 convertTo_ = noScaling;
253 }
254 }
255
256 // Build the target ws description as function of the input & output ws and
257 // the parameters, supplied to the algorithm
258 MDWSDescription targWSDescr;
259 // get workspace parameters and build target workspace description, report if
260 // there is need to build new target MD workspace
261 bool createNewTargetWs =
262 buildTargetWSDescription(spws, QModReq, dEModReq, otherDimNames, dimMin, dimMax, QFrame, convertTo_, targWSDescr);
263
264 // create and initiate new workspace or set up existing workspace as a target.
265 if (createNewTargetWs) // create new
266 spws = this->createNewMDWorkspace(targWSDescr, fileBackEnd, out_filename);
267 else // setup existing MD workspace as workspace target.
268 m_OutWSWrapper->setMDWS(spws);
269
270 // pre-process detectors;
271 targWSDescr.m_PreprDetTable = this->preprocessDetectorsPositions(m_InWS2D, dEModReq, getProperty("UpdateMasks"),
272 std::string(getProperty("PreprocDetectorsWS")));
273
277 addExperimentInfo(spws, targWSDescr);
278 // get pointer to appropriate ConverttToMD plugin from the CovertToMD plugins
279 // factory, (will throw if logic is wrong and ChildAlgorithm is not found
280 // among existing)
283 ConvToMDSelector AlgoSelector(convType);
284 this->m_Convertor = AlgoSelector.convSelector(m_InWS2D, this->m_Convertor);
285
286 bool ignoreZeros = getProperty("IgnoreZeroSignals");
287 bool useLogTimes = getProperty("UseLogTimes");
288 // initiate conversion and estimate amount of job to do
289 size_t n_steps = this->m_Convertor->initialize(targWSDescr, m_OutWSWrapper, ignoreZeros, useLogTimes);
290
291 // copy the metadata, necessary for resolution corrections
292 copyMetaData(spws);
293
294 // progress reporter
295 m_Progress = std::make_unique<Progress>(this, 0.0, 1.0, n_steps);
296
297 g_log.information() << " conversion started\n";
298 // DO THE JOB:
299 this->m_Convertor->runConversion(m_Progress.get());
300
301 // Set the normalization of the event workspace
302 m_Convertor->setDisplayNormalization(spws, m_InWS2D);
303
304 if (fileBackEnd) {
305 auto savemd = this->createChildAlgorithm("SaveMD");
306 savemd->setProperty("InputWorkspace", spws);
307 savemd->setPropertyValue("Filename", out_filename);
308 savemd->setProperty("UpdateFileBackEnd", true);
309 savemd->setProperty("MakeFileBacked", false);
310 savemd->executeAsChildAlg();
311 }
312
313 if (const auto logname = m_Convertor->getTimeLogsName(); logname.size() > 0) {
314 std::string singlestring;
315 singlestring.reserve(2 * logname.size());
316 for (auto string : logname) {
317 singlestring.append(string).append(1, ',');
318 }
319 singlestring.pop_back();
320 spws->getExperimentInfo(0)->mutableRun().addProperty("useLogTimes", singlestring, true);
321 }
322
323 // JOB COMPLETED:
324 setProperty("OutputWorkspace", std::dynamic_pointer_cast<IMDEventWorkspace>(spws));
325 // free the algorithm from the responsibility for the target workspace to
326 // allow it to be deleted if necessary
327 m_OutWSWrapper->releaseWorkspace();
328 // free up the sp to the input workspace, which would be deleted if nobody
329 // needs it any more;
330 m_InWS2D.reset();
331}
340 // Copy ExperimentInfo (instrument, run, sample) to the output WS
341 API::ExperimentInfo_sptr ei(m_InWS2D->cloneExperimentInfo());
342
343 ei->mutableRun().addProperty("RUBW_MATRIX", targWSDescr.m_Wtransf.getVector(), true);
344 ei->mutableRun().addProperty("W_MATRIX", targWSDescr.getPropertyValueAsType<std::vector<double>>("W_MATRIX"), true);
345
346 // associated experiment-info index as the number of experiment into merged within this run. It is
347 // possible to interpret it differently
348 // and should never expect it to start with 0 (for first experiment info)
349 uint16_t expInfoIndex = mdEventWS->addExperimentInfo(ei);
350
351 // add run-index to the target workspace description for further usage as the
352 // identifier for the events, which come from this run.
353 targWSDescr.addProperty("EXP_INFO_INDEX", expInfoIndex, true);
354}
355
364
365 // found detector which is not a monitor to get proper bin boundaries.
366 size_t spectra_index(0);
367 bool detector_found(false);
368 const auto &spectrumInfo = m_InWS2D->spectrumInfo();
369 for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) {
370 if (spectrumInfo.hasDetectors(i) && !spectrumInfo.isMonitor(i)) {
371 spectra_index = i;
372 detector_found = true;
373 g_log.debug() << "Using spectra N " << i
374 << " as the source of the bin "
375 "boundaries for the resolution corrections \n";
376 break;
377 }
378 }
379 if (!detector_found) {
380 g_log.information() << "No spectra in the workspace have detectors associated "
381 "with them. Storing bin boundaries from first spectrum for"
382 "resolution calculation\n";
383 }
384
385 // retrieve representative bin boundaries
386 auto binBoundaries = m_InWS2D->x(spectra_index);
387
388 // check if the boundaries transformation is necessary
389 if (m_Convertor->getUnitConversionHelper().isUnitConverted()) {
390
391 if (!dynamic_cast<DataObjects::EventWorkspace *>(m_InWS2D.get())) {
392 g_log.information() << " ConvertToMD converts input workspace units, but "
393 "the bin boundaries are copied from the first "
394 "workspace spectra. The resolution estimates can "
395 "be incorrect if unit conversion depends on "
396 "spectra number.\n";
397
398 UnitsConversionHelper &unitConv = m_Convertor->getUnitConversionHelper();
399 unitConv.updateConversion(spectra_index);
400 std::transform(binBoundaries.cbegin(), binBoundaries.cend(), binBoundaries.begin(),
401 [&unitConv](const auto &binBoundary) { return unitConv.convertUnits(binBoundary); });
402 }
403 // sort bin boundaries in case if unit transformation have swapped them.
404 if (binBoundaries[0] > binBoundaries.back()) {
405 g_log.information() << "Bin boundaries are not arranged monotonously. "
406 "Sorting performed\n";
407 std::sort(binBoundaries.begin(), binBoundaries.end());
408 }
409 }
410
411 // The last experiment info should always be the one that refers
412 // to latest converting workspace. All others should have had this
413 // information set already
414 uint16_t nexpts = mdEventWS->getNumExperimentInfo();
415 if (nexpts > 0) {
416 ExperimentInfo_sptr expt = mdEventWS->getExperimentInfo(static_cast<uint16_t>(nexpts - 1));
417 expt->mutableRun().storeHistogramBinBoundaries(binBoundaries.rawData());
418 }
419}
420
440bool ConvertToMD::buildTargetWSDescription(const API::IMDEventWorkspace_sptr &spws, const std::string &QModReq,
441 const std::string &dEModReq, const std::vector<std::string> &otherDimNames,
442 std::vector<double> &dimMin, std::vector<double> &dimMax,
443 const std::string &QFrame, const std::string &convertTo_,
444 MDAlgorithms::MDWSDescription &targWSDescr) {
445 // ------- Is there need to create new output workspace?
446 bool createNewTargetWs = doWeNeedNewTargetWorkspace(spws);
447 std::vector<int> split_into;
448
449 if (createNewTargetWs) {
450 targWSDescr.m_buildingNewWorkspace = true;
451 // find min-max dimensions values -- either take them from input parameters
452 // or identify the defaults if input parameters are not defined
453 this->findMinMax(m_InWS2D, QModReq, dEModReq, QFrame, convertTo_, otherDimNames, dimMin, dimMax);
454 // set number of bins each dimension split into.
455 split_into = this->getProperty("SplitInto");
456 } else // get min/max from existing MD workspace ignoring input min/max values
457 {
458 targWSDescr.m_buildingNewWorkspace = false;
459 size_t NDims = spws->getNumDims();
460 dimMin.resize(NDims);
461 dimMax.resize(NDims);
462 split_into.resize(NDims);
463 for (size_t i = 0; i < NDims; i++) {
464 const Geometry::IMDDimension *pDim = spws->getDimension(i).get();
465 dimMin[i] = pDim->getMinimum();
466 dimMax[i] = pDim->getMaximum();
467 // number of dimension
468 split_into[i] = static_cast<int>(pDim->getNBins());
469 }
470 }
471
472 // verify that the number min/max values is equivalent to the number of
473 // dimensions defined by properties and min is less max
474 targWSDescr.setMinMax(dimMin, dimMax);
475 targWSDescr.buildFromMatrixWS(m_InWS2D, QModReq, dEModReq, otherDimNames);
476 targWSDescr.setNumBins(split_into);
477
478 bool LorentzCorrections = getProperty("LorentzCorrection");
479 targWSDescr.setLorentsCorr(LorentzCorrections);
480
481 double m_AbsMin = getProperty("AbsMinQ");
482 targWSDescr.setAbsMin(m_AbsMin);
483
484 // Set optional projections for Q3D mode
486 if (QModReq == MDTransfQ3D().transfID()) {
487 try {
488 // otherwise input uv are ignored -> later it can be modified to set ub
489 // matrix if no given, but this may over-complicate things.
490 MsliceProj.setUVvectors(getProperty("UProj"), getProperty("VProj"), getProperty("WProj"));
491 } catch (std::invalid_argument &) {
492 g_log.warning() << "The projections are coplanar. Will use defaults "
493 "[1,0,0],[0,1,0] and [0,0,1]\n";
494 }
495 } else {
496 auto warnIfSet = [this](const std::string &propName) {
497 Property *prop = this->getProperty(propName);
498 if (!prop->isDefault()) {
499 g_log.warning(propName + " value ignored with QDimensions != " + MDTransfQ3D().transfID());
500 }
501 };
502 for (const auto &name : {"UProj", "VProj", "WProj"}) {
503 warnIfSet(name);
504 }
505 }
506
507 if (createNewTargetWs) {
508
509 // check if we are working in powder mode
510 // set up target coordinate system and identify/set the (multi) dimension's
511 // names to use
512 targWSDescr.m_RotMatrix = MsliceProj.getTransfMatrix(targWSDescr, QFrame, convertTo_);
513 } else // user input is mainly ignored and everything is in old MD workspace
514 {
515 // dimensions are already build, so build MDWS description from existing
516 // workspace
518 oldWSDescr.buildFromMDWS(spws);
519
520 // some conversion parameters can not be defined by the target workspace.
521 // They have to be retrieved from the input workspace
522 // and derived from input parameters.
523 oldWSDescr.setUpMissingParameters(targWSDescr);
524 // set up target coordinate system and the dimension names/units
525 oldWSDescr.m_RotMatrix = MsliceProj.getTransfMatrix(oldWSDescr, QFrame, convertTo_);
526
527 // check inconsistencies, if the existing workspace can be used as target
528 // workspace.
529 oldWSDescr.checkWSCorresponsMDWorkspace(targWSDescr);
530 // reset new ws description name
531 targWSDescr = oldWSDescr;
532 }
533 return createNewTargetWs;
534}
535
545 const bool filebackend, const std::string &filename) {
546 // create new md workspace and set internal shared pointer of m_OutWSWrapper
547 // to this workspace
548 API::IMDEventWorkspace_sptr spws = m_OutWSWrapper->createEmptyMDWS(targWSDescr);
549 if (!spws) {
550 g_log.error() << "can not create target event workspace with :" << targWSDescr.nDimensions() << " dimensions\n";
551 throw(std::invalid_argument("can not create target workspace"));
552 }
553 // Build up the box controller
554 Mantid::API::BoxController_sptr bc = m_OutWSWrapper->pWorkspace()->getBoxController();
555 // Build up the box controller, using the properties in
556 // BoxControllerSettingsAlgorithm
557 this->setBoxController(bc, m_InWS2D->getInstrument());
558 if (filebackend) {
559 setupFileBackend(filename, m_OutWSWrapper->pWorkspace());
560 }
561
562 // Check if the user want sto force a top level split or not
563 bool topLevelSplittingChecked = this->getProperty("TopLevelSplitting");
564
565 if (topLevelSplittingChecked) {
566 // Perform initial split with the forced settings
568 }
569
570 // split boxes;
571 spws->splitBox();
572
573 // Do we split more due to MinRecursionDepth?
574 int minDepth = this->getProperty("MinRecursionDepth");
575 int maxDepth = this->getProperty("MaxRecursionDepth");
576 if (minDepth > maxDepth)
577 throw std::invalid_argument("MinRecursionDepth must be >= MaxRecursionDepth ");
578 spws->setMinRecursionDepth(size_t(minDepth));
579
580 return spws;
581}
582
589 const size_t topLevelSplitSetting = 50;
590 const size_t dimCutoff = 4;
591
592 // Set the Top level splitting
593 for (size_t dim = 0; dim < bc->getNDims(); dim++) {
594 if (dim < dimCutoff) {
595 bc->setSplitTopInto(dim, topLevelSplitSetting);
596 } else {
597 bc->setSplitTopInto(dim, bc->getSplitInto(dim));
598 }
599 }
600}
601
610
611 bool createNewWs(false);
612 if (!spws) {
613 createNewWs = true;
614 } else {
615 bool shouldOverwrite = getProperty("OverwriteExisting");
616 createNewWs = shouldOverwrite;
617 }
618 return createNewWs;
619}
620
638void ConvertToMD::findMinMax(const Mantid::API::MatrixWorkspace_sptr &inWS, const std::string &QMode,
639 const std::string &dEMode, const std::string &QFrame, const std::string &ConvertTo,
640 const std::vector<std::string> &otherDim, std::vector<double> &minVal,
641 std::vector<double> &maxVal) {
642
643 // get raw pointer to Q-transformation (do not delete this pointer, it hold by
644 // MDTransfFatctory!)
645 MDTransfInterface *pQtransf = MDTransfFactory::Instance().create(QMode).get();
646 // get number of dimensions this Q transformation generates from the
647 // workspace.
648 auto iEmode = Kernel::DeltaEMode::fromString(dEMode);
649 // get total number of dimensions the workspace would have.
650 unsigned int nMatrixDim = pQtransf->getNMatrixDimensions(iEmode, inWS);
651 // total number of dimensions
652 size_t nDim = nMatrixDim + otherDim.size();
653
654 // probably already have well defined min-max values, so no point of
655 // pre-calculating them
656 bool wellDefined(true);
657 if ((nDim == minVal.size()) && (minVal.size() == maxVal.size())) {
658 // are they indeed well defined?
659 for (size_t i = 0; i < minVal.size(); i++) {
660 if (minVal[i] >= maxVal[i]) // no it is ill defined
661 {
662 g_log.information() << " Min Value: " << minVal[i] << " for dimension N: " << i
663 << " equal or exceeds max value:" << maxVal[i] << '\n';
664 wellDefined = false;
665 break;
666 }
667 }
668 if (wellDefined)
669 return;
670 }
671
672 // we need to identify min-max values by themselves
673
674 Mantid::API::Algorithm_sptr childAlg = createChildAlgorithm("ConvertToMDMinMaxLocal");
675 if (!childAlg)
676 throw(std::runtime_error("Can not create child ChildAlgorithm to found min/max values"));
677
678 childAlg->setProperty("InputWorkspace", inWS);
679 childAlg->setProperty("QDimensions", QMode);
680 childAlg->setProperty("dEAnalysisMode", dEMode);
681 childAlg->setProperty("Q3DFrames", QFrame);
682 childAlg->setProperty("OtherDimensions", otherDim);
683 childAlg->setProperty("QConversionScales", ConvertTo);
684 childAlg->setProperty("PreprocDetectorsWS", std::string(getProperty("PreprocDetectorsWS")));
685 childAlg->execute();
686 if (!childAlg->isExecuted())
687 throw(std::runtime_error("Can not properly execute child algorithm to find "
688 "min/max workspace values"));
689
690 minVal = childAlg->getProperty("MinValues");
691 maxVal = childAlg->getProperty("MaxValues");
692
693 // if some min-max values for dimensions produce ws with 0 width in this
694 // direction, change it to have some width;
695 for (unsigned int i = 0; i < nDim; i++) {
696 if (minVal[i] >= maxVal[i]) {
697 g_log.debug() << "identified min-max values for dimension N: " << i
698 << " are equal. Modifying min-max value to produce "
699 "dimension with 0.2*dimValue width\n";
700 if (minVal[i] > 0) {
701 minVal[i] *= 0.9;
702 maxVal[i] *= 1.1;
703 } else if (minVal[i] == 0) {
704 minVal[i] = -0.1;
705 maxVal[i] = 0.1;
706 } else {
707 minVal[i] *= 1.1;
708 maxVal[i] *= 0.9;
709 }
710 } else {
711 MDHistoDimensionBuilder::resizeToFitMDBox(minVal[i], maxVal[i]);
712 }
713 }
714
715 if (!wellDefined)
716 return;
717
718 // if only min or only max limits are defined and are well defined workspace,
719 // the algorithm will use these limits
720 std::vector<double> minAlgValues = this->getProperty("MinValues");
721 std::vector<double> maxAlgValues = this->getProperty("MaxValues");
722 bool allMinDefined = (minAlgValues.size() == nDim);
723 bool allMaxDefined = (maxAlgValues.size() == nDim);
724 if (allMinDefined || allMaxDefined) {
725 for (size_t i = 0; i < nDim; i++) {
726 if (allMinDefined)
727 minVal[i] = minAlgValues[i];
728 if (allMaxDefined)
729 maxVal[i] = maxAlgValues[i];
730 }
731 }
732}
733
740void ConvertToMD::setupFileBackend(const std::string &filebackPath,
741 const Mantid::API::IMDEventWorkspace_sptr &outputWS) {
743 auto savemd = this->createChildAlgorithm("SaveMD", 0.01, 0.05, true);
744 savemd->setProperty("InputWorkspace", outputWS);
745 savemd->setPropertyValue("Filename", filebackPath);
746 savemd->setProperty("UpdateFileBackEnd", false);
747 savemd->setProperty("MakeFileBacked", false);
748 savemd->executeAsChildAlg();
749
750 // create file-backed box controller
751 auto boxControllerMem = outputWS->getBoxController();
752 auto boxControllerIO = std::make_shared<BoxControllerNeXusIO>(boxControllerMem.get());
753 boxControllerMem->setFileBacked(boxControllerIO, filebackPath);
754 outputWS->setFileBacked();
755 boxControllerMem->getFileIO()->setWriteBufferSize(1000000);
756}
757
758} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:542
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.
void setBoxController(const Mantid::API::BoxController_sptr &bc, const Mantid::Geometry::Instrument_const_sptr &instrument)
Set the settings in the given box controller.
@ OptionalSave
to specify a file to write to but an empty string is
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:90
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
A property class for workspaces.
The class responsible for saving events into nexus file using generic box controller interface Expect...
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
The class describes one dimension of multidimensional dataset representing an orthogonal dimension an...
virtual coord_t getMaximum() const =0
virtual coord_t getMinimum() const =0
virtual size_t getNBins() const =0
static void resizeToFitMDBox(CoordT &min, CoordT &max)
Push the min/max values out by a defined amount.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
std::vector< T > getVector() const
Definition Matrix.cpp:77
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:94
virtual bool isDefault() const =0
Overriden function that returns if property has the same value that it was initialised with,...
A specialised Property class for holding a series of time-value pairs.
static bool isSplitValid(const std::vector< T > &split_into)
small class to select proper solver as function of the workspace kind and (possibly,...
std::shared_ptr< ConvToMDBase > convSelector(const API::MatrixWorkspace_sptr &inputWS, std::shared_ptr< ConvToMDBase > &currentSolver) const
function which selects the convertor depending on workspace type and (possibly, in a future) some wor...
std::shared_ptr< MDAlgorithms::ConvToMDBase > m_Convertor
pointer to the class, which does the particular conversion
DataObjects::TableWorkspace_const_sptr preprocessDetectorsPositions(const Mantid::API::MatrixWorkspace_const_sptr &InWS2D, const std::string &dEModeRequested, bool updateMasks, const std::string &OutWSName)
The method responsible for analyzing input workspace parameters and preprocessing detectors positions...
void init() override
Initialize the algorithm's properties.
ConvertToMD : Transform a workspace into MD workspace with components defined by user.
Definition ConvertToMD.h:30
int version() const override
Algorithm's version for identification.
void findMinMax(const Mantid::API::MatrixWorkspace_sptr &inWS, const std::string &QMode, const std::string &dEMode, const std::string &QFrame, const std::string &ConvertTo, const std::vector< std::string > &otherDim, std::vector< double > &minVal, std::vector< double > &maxVal)
Method takes min-max values from algorithm parameters if they are present or calculates default min-m...
bool doWeNeedNewTargetWorkspace(const API::IMDEventWorkspace_sptr &spws)
Check if target workspace new or existing one and we need to create new workspace.
Mantid::API::MatrixWorkspace_sptr m_InWS2D
pointer to the input workspace;
Definition ConvertToMD.h:61
void setupFileBackend(const std::string &filebackPath, const API::IMDEventWorkspace_sptr &outputWS)
Setup the filebackend for the output workspace.
void addExperimentInfo(API::IMDEventWorkspace_sptr &mdEventWS, MDAlgorithms::MDWSDescription &targWSDescr) const
par of store metadata routine which generate metadata necessary for initializing ConvertToMD plugin
const std::string name() const override
Algorithm's name for identification.
std::shared_ptr< MDAlgorithms::MDEventWSWrapper > m_OutWSWrapper
Definition ConvertToMD.h:64
std::unique_ptr< API::Progress > m_Progress
progress reporter
Definition ConvertToMD.h:54
void copyMetaData(API::IMDEventWorkspace_sptr &mdEventWS) const
Store metadata and set some metadata, needed for plugin to run on the target workspace description.
void exec() override
Virtual method - must be overridden by concrete algorithm.
void setupTopLevelSplitting(const Mantid::API::BoxController_sptr &bc)
Sets up the top level splitting, i.e. of level 0, for the box controller.
API::IMDEventWorkspace_sptr createNewMDWorkspace(const MDAlgorithms::MDWSDescription &targWSDescr, const bool filebackend, const std::string &filename)
Create new MD workspace using existing parameters for algorithm.
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
bool buildTargetWSDescription(const API::IMDEventWorkspace_sptr &spws, const std::string &QModReq, const std::string &dEModReq, const std::vector< std::string > &otherDimNames, std::vector< double > &dimMin, std::vector< double > &dimMax, const std::string &QFrame, const std::string &convertTo_, MDAlgorithms::MDWSDescription &targWSDescr)
handle the input parameters and build target workspace description as function of input parameters
Interface to set of sub-classes used by ConvertToMD algorithm and responsible for conversion of input...
virtual unsigned int getNMatrixDimensions(Kernel::DeltaEMode::Type mode, API::MatrixWorkspace_const_sptr inWS) const =0
return the number of dimensions, calculated by the transformation from the workspace.
Class responsible for conversion of input workspace data into proper number of output dimensions for ...
Definition MDTransfQ3D.h:28
helper class describes the properties of target MD workspace, which should be obtained as the result ...
void setMinMax(const std::vector< double > &minVal, const std::vector< double > &maxVal)
function sets up min-max values to the dimensions, described by the class
void setUpMissingParameters(const MDWSDescription &SourceMatrWS)
copy some parameters from the input workspace, as target md WS do not have all information about the ...
void setNumBins(const std::vector< int > &nBins_toSplit)
sets number of bins each dimension is split
void buildFromMDWS(const API::IMDEventWorkspace_const_sptr &pWS)
method builds MD Event description from existing MD event workspace
void buildFromMatrixWS(const API::MatrixWorkspace_sptr &pWS, const std::string &QMode, const std::string &dEMode, const std::vector< std::string > &dimPropertyNames=std::vector< std::string >())
method builds MD Event ws description from a matrix workspace and the transformations,...
DataObjects::TableWorkspace_const_sptr m_PreprDetTable
void setLorentsCorr(bool On=false)
do we need to perform Lorentz corrections
void checkWSCorresponsMDWorkspace(const MDWSDescription &NewMDWorkspaceD)
compare two descriptions and select the complimentary result.
std::vector< std::string > getTargetFrames() const
returns the list of possible target frames to convert to
std::vector< double > getTransfMatrix(MDAlgorithms::MDWSDescription &TargWSDescription, const std::string &FrameRequested, const std::string &QScaleRequested) const
method to build the Q-coordinates transformation.
std::vector< std::string > getQScalings() const
return the list of possible scalings for momentums
void setUVvectors(const std::vector< double > &ut, const std::vector< double > &vt, const std::vector< double > &wt)
helper function which verifies if projection vectors are specified and if their values are correct wh...
void updateConversion(size_t i)
Method updates unit conversion given the index of detector parameters in the array of detectors.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition Algorithm.h:52
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
static Type fromString(const std::string &modeStr)
Returns the emode from the given string.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54