21#include <boost/algorithm/string.hpp>
22#include <boost/regex.hpp>
32using MinMax = std::pair<double, double>;
36 throw std::runtime_error(
"Invalid workspace passed to getDimensionExtents.");
37 auto dim = ws->getDimension(
index);
38 return std::make_pair(dim->getMinimum(), dim->getMaximum());
41std::string numToStringWithPrecision(
const double num) {
44 s.setf(std::ios::fixed, std::ios::floatfield);
49DblMatrix scaleProjection(
const DblMatrix &inMatrix,
const std::vector<std::string> &inUnits,
53 if (std::equal(inUnits.begin(), inUnits.end(), outUnits.begin()))
56 if (inUnits.size() != outUnits.size())
57 throw std::runtime_error(
"scaleProjection given different quantity of input and output units");
59 assert(inWS->getNumExperimentInfo() > 0);
60 const OrientedLattice &orientedLattice = inWS->getExperimentInfo(0)->sample().getOrientedLattice();
62 const size_t numDims = inUnits.size();
63 for (
size_t i = 0; i < numDims; ++i) {
64 const double dStar = 2 * M_PI * orientedLattice.
dstar(inMatrix[i][0], inMatrix[i][1], inMatrix[i][2]);
65 if (inUnits[i] == outUnits[i])
69 outUnits[i] =
"in " + numToStringWithPrecision(dStar) +
" A^-1";
70 for (
size_t j = 0; j < numDims; ++j)
74 for (
size_t j = 0; j < numDims; ++j)
82std::vector<MinMax> calculateExtents(
const DblMatrix &inMatrix,
const std::vector<MinMax> &limits) {
88 std::vector<double> hRange(2), kRange(2), lRange(2);
90 hRange[0] = limits[0].first;
91 hRange[1] = limits[0].second;
92 kRange[0] = limits[1].first;
93 kRange[1] = limits[1].second;
94 lRange[0] = limits[2].first;
95 lRange[1] = limits[2].second;
99 const double maxDbl = std::numeric_limits<double>::max();
100 std::vector<MinMax> extents(3, std::make_pair(maxDbl, maxDbl));
102 for (
double &hIt : hRange) {
103 for (
double &kIt : kRange) {
104 for (
double &lIt : lRange) {
105 V3D origPos(hIt, kIt, lIt);
106 for (
size_t i = 0; i < 3; ++i) {
107 const V3D other(invMat[i][0], invMat[i][1], invMat[i][2]);
108 double val = origPos.scalar_prod(other);
110 if (extents[i].first == maxDbl || extents[i].first > val)
111 extents[i].first = val;
113 if (extents[i].second == maxDbl || extents[i].second < val)
114 extents[i].second = val;
123std::pair<std::vector<MinMax>, std::vector<int>> calculateSteps(
const std::vector<MinMax> &inExtents,
124 const std::vector<std::vector<double>> &binning) {
125 std::vector<MinMax> outExtents(inExtents);
126 std::vector<int> outBins;
128 for (
size_t i = 0; i < inExtents.size(); ++i) {
129 const size_t nArgs = binning[i].size();
133 throw std::runtime_error(
"Binning parameter cannot be empty");
135 }
else if (nArgs == 1) {
136 const double dimRange = inExtents[i].second - inExtents[i].first;
137 const double stepSize = binning[i][0] < dimRange ? binning[i][0] : dimRange;
138 outBin =
static_cast<int>(dimRange / stepSize);
139 outExtents[i].second = inExtents[i].first + outBin * stepSize;
141 }
else if (nArgs == 2) {
142 outExtents[i].first = binning[i][0];
143 outExtents[i].second = binning[i][1];
146 }
else if (nArgs == 3) {
147 const double dimMin = binning[i][0];
148 const double dimMax = binning[i][2];
149 const double dimRange = dimMax - dimMin;
150 const double stepSize = binning[i][1] < dimRange ? binning[i][1] : dimRange;
151 outBin =
static_cast<int>(dimRange / stepSize);
152 outExtents[i].second = dimMin + outBin * stepSize;
153 outExtents[i].first = dimMin;
156 throw std::runtime_error(
"Cannot handle " +
std::to_string(nArgs) +
" bins.");
159 throw std::runtime_error(
"output bin calculated to be less than 0");
160 outBins.emplace_back(outBin);
162 return std::make_pair(outExtents, outBins);
165std::vector<std::string> labelProjection(
const DblMatrix &projection) {
166 const std::string replacements[] = {
"zeta",
"eta",
"xi"};
167 std::vector<std::string> ret(3);
168 std::vector<std::string> labels(3);
170 for (
size_t i = 0; i < 3; ++i) {
171 for (
size_t j = 0; j < 3; ++j) {
172 const double in = projection[i][j];
173 if (std::abs(in) == 1)
175 labels[j] =
"'" + replacements[i] +
"'";
177 labels[j] =
"'-" + replacements[i] +
"'";
181 labels[j] =
"'" + numToStringWithPrecision(in) + replacements[i] +
"'";
184 ret[i] =
"[" + boost::algorithm::join(labels,
", ") +
"]";
200 std::vector<std::string> unitMarkers(3);
201 for (
size_t i = 0; i < inws->getNumDims() && i < 3; ++i) {
202 auto units = inws->getDimension(i)->getUnits();
203 const boost::regex re(
"(Angstrom\\^-1)|(A\\^-1)", boost::regex::icase);
205 std::string unitMarker;
206 if (boost::regex_match(units.ascii(), re)) {
211 unitMarkers[i] = unitMarker;
212 logger.
debug() <<
"In dimension with index " << i <<
" and units " << units.ascii() <<
" taken to be of type "
213 << unitMarker <<
'\n';
231 "MDWorkspace to slice");
244 "Output cut workspace");
245 declareProperty(
"NoPix",
false,
246 "If False creates a full MDEventWorkspaces "
247 "as output. True to create an "
248 "MDHistoWorkspace as output. This is DND "
249 "only in Horace terminology.");
251 auto mustBePositiveInteger = std::make_shared<BoundedValidator<int>>();
252 mustBePositiveInteger->setLower(0);
254 declareProperty(
"MaxRecursionDepth", 1, mustBePositiveInteger,
255 "Sets the maximum recursion depth to use. Can be used to "
256 "constrain the workspaces internal structure");
261 "How will the Q units of the input workspace be interpreted? "
262 "This property will disappear in future versions of Mantid\n"
263 "%s : Figure it out based on the label units\n"
264 "%s : Force them to be rlu\n"
265 "%s : Force them to be inverse angstroms",
268 std::string help(buffer);
269 boost::algorithm::trim(help);
270 declareProperty(
"InterpretQDimensionUnits",
AutoMethod, std::make_shared<StringListValidator>(propOptions), help);
274 g_log.
warning(
"CutMD is in the beta stage of development. Its properties and "
275 "behaviour may change without warning.");
279 const size_t numDims = inWS->getNumDims();
287 if (
auto histInWS = std::dynamic_pointer_cast<IMDHistoWorkspace>(inWS)) {
291 integrateAlg->setProperty(
"InputWorkspace", histInWS);
292 integrateAlg->setProperty(
"P1Bin", pbins[0]);
293 integrateAlg->setProperty(
"P2Bin", pbins[1]);
294 integrateAlg->setProperty(
"P3Bin", pbins[2]);
295 integrateAlg->setProperty(
"P4Bin", pbins[3]);
296 integrateAlg->setProperty(
"P5Bin", pbins[4]);
297 integrateAlg->execute();
302 auto eventInWS = std::dynamic_pointer_cast<IMDEventWorkspace>(inWS);
311 for (
size_t i = 0; i < 5; ++i) {
312 if (i < numDims && pbins[i].empty())
313 throw std::runtime_error(
"P" +
std::to_string(i + 1) +
"Bin must be set when processing a workspace with " +
315 if (i >= numDims && !pbins[i].empty())
316 throw std::runtime_error(
"P" +
std::to_string(i + 1) +
"Bin must NOT be set when processing a workspace with " +
321 std::vector<MinMax> extentLimits{getDimensionExtents(eventInWS, 0), getDimensionExtents(eventInWS, 1),
322 getDimensionExtents(eventInWS, 2)};
326 projectionMatrix.
setRow(0, projection.
U());
327 projectionMatrix.
setRow(1, projection.
V());
328 projectionMatrix.
setRow(2, projection.
W());
330 std::vector<std::string> targetUnits(3);
331 for (
size_t i = 0; i < 3; ++i)
334 const std::string determineUnitsMethod = this->
getProperty(
"InterpretQDimensionUnits");
335 std::vector<std::string> originUnits;
338 }
else if (determineUnitsMethod ==
RLUMethod) {
339 originUnits = std::vector<std::string>(3,
RLUSymbol);
344 DblMatrix scaledProjectionMatrix = scaleProjection(projectionMatrix, originUnits, targetUnits, eventInWS);
347 std::vector<MinMax> scaledExtents = calculateExtents(scaledProjectionMatrix, extentLimits);
348 auto stepPair = calculateSteps(scaledExtents, pbins);
349 std::vector<MinMax> steppedExtents = stepPair.first;
350 std::vector<int> steppedBins = stepPair.second;
353 for (
size_t i = 3; i < numDims; ++i) {
354 const size_t nArgs = pbins[i].size();
355 const MinMax extentLimit = getDimensionExtents(eventInWS, i);
356 const double extentRange = extentLimit.second - extentLimit.first;
359 steppedExtents.emplace_back(extentLimit);
360 steppedBins.emplace_back(
static_cast<int>(extentRange / pbins[i][0]));
361 }
else if (nArgs == 2) {
362 steppedExtents.emplace_back(pbins[i][0], pbins[i][1]);
363 steppedBins.emplace_back(1);
364 }
else if (nArgs == 3) {
365 const double dimRange = pbins[i][2] - pbins[i][0];
366 const double stepSize = pbins[i][1] < dimRange ? pbins[i][1] : dimRange;
367 steppedExtents.emplace_back(pbins[i][0], pbins[i][2]);
368 steppedBins.emplace_back(
static_cast<int>(dimRange / stepSize));
372 const size_t preSize = targetUnits.size();
373 targetUnits.resize(preSize * 2);
374 auto halfEnd = targetUnits.begin() + preSize;
375 std::copy(targetUnits.begin(), halfEnd, halfEnd);
379 std::vector<std::string> labels = labelProjection(projectionMatrix);
382 const std::string cutAlgName = noPix ?
"BinMD" :
"SliceMD";
384 cutAlg->initialize();
385 cutAlg->setProperty(
"InputWorkspace", inWS);
386 cutAlg->setProperty(
"OutputWorkspace",
"sliced");
387 cutAlg->setProperty(
"NormalizeBasisVectors",
false);
388 cutAlg->setProperty(
"AxisAligned",
false);
390 int recursion_depth =
getProperty(
"MaxRecursionDepth");
391 cutAlg->setProperty(
"TakeMaxRecursionDepthFromInput",
false);
392 cutAlg->setProperty(
"MaxRecursionDepth", recursion_depth);
395 for (
size_t i = 0; i < numDims; ++i) {
403 unit = targetUnits[i];
405 std::vector<std::string> vec(numDims,
"0");
406 for (
size_t j = 0; j < 3; ++j)
407 vec[j] = boost::lexical_cast<std::string>(scaledProjectionMatrix[i][j]);
408 vecStr = boost::algorithm::join(vec,
", ");
411 auto dim = inWS->getDimension(i);
412 label = dim->getName();
413 unit = dim->getUnits();
414 std::vector<std::string> vec(numDims,
"0");
416 vecStr = boost::algorithm::join(vec,
", ");
419 const std::string
value = std::string(label).append(
", ").append(unit).append(
", ").append(vecStr);
424 std::vector<double> outExtents(steppedExtents.size() * 2);
425 for (
size_t i = 0; i < steppedExtents.size(); ++i) {
426 outExtents[2 * i] = steppedExtents[i].first;
427 outExtents[2 * i + 1] = steppedExtents[i].second;
430 cutAlg->setProperty(
"OutputExtents", outExtents);
431 cutAlg->setProperty(
"OutputBins", steppedBins);
434 sliceWS = cutAlg->getProperty(
"OutputWorkspace");
439 throw std::runtime_error(
"Could not extract experiment info from child's OutputWorkspace");
442 if (sliceInfo->getNumExperimentInfo() > 0) {
444 info->mutableRun().addProperty(
"W_MATRIX", projectionMatrix.
getVector(),
true);
448 auto geometry = std::dynamic_pointer_cast<Mantid::API::MDGeometry>(sliceWS);
453 geometry->clearTransforms();
454 geometry->clearOriginalWorkspaces();
456 setProperty(
"OutputWorkspace", sliceWS);
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1) override
Create a Child Algorithm.
Kernel::IPropertyManager::TypedValue getProperty(const std::string &name) const override
Get the property held by this object.
ProjectionUnit getUnit(size_t nd)
Retrives the unit of the given dimension.
A property class for workspaces.
Class to implement UB matrix.
double dstar(double h, double k, double l) const
Return d*=1/d ( ) for a given h,k,l coordinate.
Support for a property that holds an array of values.
The Logger class is in charge of the publishing messages from the framework through various channels.
void debug(const std::string &msg)
Logs at debug level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
void setRow(const size_t nRow, const std::vector< T > &newRow)
std::vector< T > getVector() const
static const std::string InvAngstromSymbol
static const std::string InvAngstromMethod
static const std::string RLUSymbol
static const std::string AutoMethod
static const std::string RLUMethod
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const IMDWorkspace > IMDWorkspace_const_sptr
Shared pointer to the IMDWorkspace base class (const version)
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
std::shared_ptr< IMDHistoWorkspace > IMDHistoWorkspace_sptr
shared pointer to Mantid::API::IMDHistoWorkspace
std::shared_ptr< IMDWorkspace > IMDWorkspace_sptr
Shared pointer to the IMDWorkspace base class.
std::shared_ptr< MultipleExperimentInfos > MultipleExperimentInfos_sptr
std::vector< std::string > DLLExport findOriginalQUnits(const Mantid::API::IMDWorkspace_const_sptr &inws, Mantid::Kernel::Logger &logger)
Determine the original q units.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.