20#include <boost/algorithm/string.hpp>
21#include <boost/regex.hpp>
31using MinMax = std::pair<double, double>;
35 throw std::runtime_error(
"Invalid workspace passed to getDimensionExtents.");
36 auto dim = ws->getDimension(
index);
37 return std::make_pair(dim->getMinimum(), dim->getMaximum());
40std::string numToStringWithPrecision(
const double num) {
43 s.setf(std::ios::fixed, std::ios::floatfield);
48DblMatrix scaleProjection(
const DblMatrix &inMatrix,
const std::vector<std::string> &inUnits,
52 if (std::equal(inUnits.begin(), inUnits.end(), outUnits.begin()))
55 if (inUnits.size() != outUnits.size())
56 throw std::runtime_error(
"scaleProjection given different quantity of input and output units");
58 assert(inWS->getNumExperimentInfo() > 0);
59 const OrientedLattice &orientedLattice = inWS->getExperimentInfo(0)->sample().getOrientedLattice();
61 const size_t numDims = inUnits.size();
62 for (
size_t i = 0; i < numDims; ++i) {
63 const double dStar = 2 * M_PI * orientedLattice.
dstar(inMatrix[i][0], inMatrix[i][1], inMatrix[i][2]);
64 if (inUnits[i] == outUnits[i])
68 outUnits[i] =
"in " + numToStringWithPrecision(dStar) +
" A^-1";
69 for (
size_t j = 0; j < numDims; ++j)
73 for (
size_t j = 0; j < numDims; ++j)
81std::vector<MinMax> calculateExtents(
const DblMatrix &inMatrix,
const std::vector<MinMax> &limits) {
87 std::vector<double> hRange(2), kRange(2), lRange(2);
89 hRange[0] = limits[0].first;
90 hRange[1] = limits[0].second;
91 kRange[0] = limits[1].first;
92 kRange[1] = limits[1].second;
93 lRange[0] = limits[2].first;
94 lRange[1] = limits[2].second;
98 const double maxDbl = std::numeric_limits<double>::max();
99 std::vector<MinMax> extents(3, std::make_pair(maxDbl, maxDbl));
101 for (
double &hIt : hRange) {
102 for (
double &kIt : kRange) {
103 for (
double &lIt : lRange) {
104 V3D origPos(hIt, kIt, lIt);
105 for (
size_t i = 0; i < 3; ++i) {
106 const V3D other(invMat[i][0], invMat[i][1], invMat[i][2]);
107 double val = origPos.scalar_prod(other);
109 if (extents[i].first == maxDbl || extents[i].first > val)
110 extents[i].first = val;
112 if (extents[i].second == maxDbl || extents[i].second < val)
113 extents[i].second = val;
122std::pair<std::vector<MinMax>, std::vector<int>> calculateSteps(
const std::vector<MinMax> &inExtents,
123 const std::vector<std::vector<double>> &binning) {
124 std::vector<MinMax> outExtents(inExtents);
125 std::vector<int> outBins;
127 for (
size_t i = 0; i < inExtents.size(); ++i) {
128 const size_t nArgs = binning[i].size();
132 throw std::runtime_error(
"Binning parameter cannot be empty");
134 }
else if (nArgs == 1) {
135 const double dimRange = inExtents[i].second - inExtents[i].first;
136 const double stepSize = binning[i][0] < dimRange ? binning[i][0] : dimRange;
137 outBin =
static_cast<int>(dimRange / stepSize);
138 outExtents[i].second = inExtents[i].first + outBin * stepSize;
140 }
else if (nArgs == 2) {
141 outExtents[i].first = binning[i][0];
142 outExtents[i].second = binning[i][1];
145 }
else if (nArgs == 3) {
146 const double dimMin = binning[i][0];
147 const double dimMax = binning[i][2];
148 const double dimRange = dimMax - dimMin;
149 const double stepSize = binning[i][1] < dimRange ? binning[i][1] : dimRange;
150 outBin =
static_cast<int>(dimRange / stepSize);
151 outExtents[i].second = dimMin + outBin * stepSize;
152 outExtents[i].first = dimMin;
155 throw std::runtime_error(
"Cannot handle " +
std::to_string(nArgs) +
" bins.");
158 throw std::runtime_error(
"output bin calculated to be less than 0");
159 outBins.emplace_back(outBin);
161 return std::make_pair(outExtents, outBins);
164std::vector<std::string> labelProjection(
const DblMatrix &projection) {
165 const std::string replacements[] = {
"zeta",
"eta",
"xi"};
166 std::vector<std::string> ret(3);
167 std::vector<std::string> labels(3);
169 for (
size_t i = 0; i < 3; ++i) {
170 for (
size_t j = 0; j < 3; ++j) {
171 const double in = projection[i][j];
172 if (std::abs(in) == 1)
174 labels[j] =
"'" + replacements[i] +
"'";
176 labels[j] =
"'-" + replacements[i] +
"'";
180 labels[j] =
"'" + numToStringWithPrecision(in) + replacements[i] +
"'";
183 ret[i] =
"[" + boost::algorithm::join(labels,
", ") +
"]";
199 std::vector<std::string> unitMarkers(3);
200 for (
size_t i = 0; i < inws->getNumDims() && i < 3; ++i) {
201 auto units = inws->getDimension(i)->getUnits();
202 const boost::regex re(
"(Angstrom\\^-1)|(A\\^-1)", boost::regex::icase);
204 std::string unitMarker;
205 if (boost::regex_match(units.ascii(), re)) {
210 unitMarkers[i] = unitMarker;
211 logger.
debug() <<
"In dimension with index " << i <<
" and units " << units.ascii() <<
" taken to be of type "
212 << unitMarker <<
'\n';
230 "MDWorkspace to slice");
243 "Output cut workspace");
244 declareProperty(
"NoPix",
false,
245 "If False creates a full MDEventWorkspaces "
246 "as output. True to create an "
247 "MDHistoWorkspace as output. This is DND "
248 "only in Horace terminology.");
250 auto mustBePositiveInteger = std::make_shared<BoundedValidator<int>>();
251 mustBePositiveInteger->setLower(0);
253 declareProperty(
"MaxRecursionDepth", 1, mustBePositiveInteger,
254 "Sets the maximum recursion depth to use. Can be used to "
255 "constrain the workspaces internal structure");
260 "How will the Q units of the input workspace be interpreted? "
261 "This property will disappear in future versions of Mantid\n"
262 "%s : Figure it out based on the label units\n"
263 "%s : Force them to be rlu\n"
264 "%s : Force them to be inverse angstroms",
267 std::string help(buffer);
268 boost::algorithm::trim(help);
269 declareProperty(
"InterpretQDimensionUnits",
AutoMethod, std::make_shared<StringListValidator>(propOptions), help);
273 g_log.
warning(
"CutMD is in the beta stage of development. Its properties and "
274 "behaviour may change without warning.");
278 const size_t numDims = inWS->getNumDims();
286 if (
auto histInWS = std::dynamic_pointer_cast<IMDHistoWorkspace>(inWS)) {
290 integrateAlg->setProperty(
"InputWorkspace", histInWS);
291 integrateAlg->setProperty(
"P1Bin", pbins[0]);
292 integrateAlg->setProperty(
"P2Bin", pbins[1]);
293 integrateAlg->setProperty(
"P3Bin", pbins[2]);
294 integrateAlg->setProperty(
"P4Bin", pbins[3]);
295 integrateAlg->setProperty(
"P5Bin", pbins[4]);
296 integrateAlg->execute();
301 auto eventInWS = std::dynamic_pointer_cast<IMDEventWorkspace>(inWS);
310 for (
size_t i = 0; i < 5; ++i) {
311 if (i < numDims && pbins[i].empty())
312 throw std::runtime_error(
"P" +
std::to_string(i + 1) +
"Bin must be set when processing a workspace with " +
314 if (i >= numDims && !pbins[i].empty())
315 throw std::runtime_error(
"P" +
std::to_string(i + 1) +
"Bin must NOT be set when processing a workspace with " +
320 std::vector<MinMax> extentLimits{getDimensionExtents(eventInWS, 0), getDimensionExtents(eventInWS, 1),
321 getDimensionExtents(eventInWS, 2)};
325 projectionMatrix.
setRow(0, projection.
U());
326 projectionMatrix.
setRow(1, projection.
V());
327 projectionMatrix.
setRow(2, projection.
W());
329 std::vector<std::string> targetUnits(3);
330 for (
size_t i = 0; i < 3; ++i)
333 const std::string determineUnitsMethod = this->
getProperty(
"InterpretQDimensionUnits");
334 std::vector<std::string> originUnits;
337 }
else if (determineUnitsMethod ==
RLUMethod) {
338 originUnits = std::vector<std::string>(3,
RLUSymbol);
343 DblMatrix scaledProjectionMatrix = scaleProjection(projectionMatrix, originUnits, targetUnits, eventInWS);
346 std::vector<MinMax> scaledExtents = calculateExtents(scaledProjectionMatrix, extentLimits);
347 auto stepPair = calculateSteps(scaledExtents, pbins);
348 std::vector<MinMax> steppedExtents = stepPair.first;
349 std::vector<int> steppedBins = stepPair.second;
352 for (
size_t i = 3; i < numDims; ++i) {
353 const size_t nArgs = pbins[i].size();
354 const MinMax extentLimit = getDimensionExtents(eventInWS, i);
355 const double extentRange = extentLimit.second - extentLimit.first;
358 steppedExtents.emplace_back(extentLimit);
359 steppedBins.emplace_back(
static_cast<int>(extentRange / pbins[i][0]));
360 }
else if (nArgs == 2) {
361 steppedExtents.emplace_back(pbins[i][0], pbins[i][1]);
362 steppedBins.emplace_back(1);
363 }
else if (nArgs == 3) {
364 const double dimRange = pbins[i][2] - pbins[i][0];
365 const double stepSize = pbins[i][1] < dimRange ? pbins[i][1] : dimRange;
366 steppedExtents.emplace_back(pbins[i][0], pbins[i][2]);
367 steppedBins.emplace_back(
static_cast<int>(dimRange / stepSize));
371 const size_t preSize = targetUnits.size();
372 targetUnits.resize(preSize * 2);
373 auto halfEnd = targetUnits.begin() + preSize;
374 std::copy(targetUnits.begin(), halfEnd, halfEnd);
378 std::vector<std::string> labels = labelProjection(projectionMatrix);
381 const std::string cutAlgName = noPix ?
"BinMD" :
"SliceMD";
383 cutAlg->initialize();
384 cutAlg->setProperty(
"InputWorkspace", inWS);
385 cutAlg->setProperty(
"OutputWorkspace",
"sliced");
386 cutAlg->setProperty(
"NormalizeBasisVectors",
false);
387 cutAlg->setProperty(
"AxisAligned",
false);
389 int recursion_depth =
getProperty(
"MaxRecursionDepth");
390 cutAlg->setProperty(
"TakeMaxRecursionDepthFromInput",
false);
391 cutAlg->setProperty(
"MaxRecursionDepth", recursion_depth);
394 for (
size_t i = 0; i < numDims; ++i) {
402 unit = targetUnits[i];
404 std::vector<std::string>
vec(numDims,
"0");
405 for (
size_t j = 0; j < 3; ++j)
406 vec[j] = boost::lexical_cast<std::string>(scaledProjectionMatrix[i][j]);
407 vecStr = boost::algorithm::join(
vec,
", ");
410 auto dim = inWS->getDimension(i);
411 label = dim->getName();
412 unit = dim->getUnits();
413 std::vector<std::string>
vec(numDims,
"0");
415 vecStr = boost::algorithm::join(
vec,
", ");
418 const std::string
value = std::string(label).append(
", ").append(unit).append(
", ").append(vecStr);
423 std::vector<double> outExtents(steppedExtents.size() * 2);
424 for (
size_t i = 0; i < steppedExtents.size(); ++i) {
425 outExtents[2 * i] = steppedExtents[i].first;
426 outExtents[2 * i + 1] = steppedExtents[i].second;
429 cutAlg->setProperty(
"OutputExtents", outExtents);
430 cutAlg->setProperty(
"OutputBins", steppedBins);
433 sliceWS = cutAlg->getProperty(
"OutputWorkspace");
438 throw std::runtime_error(
"Could not extract experiment info from child's OutputWorkspace");
441 if (sliceInfo->getNumExperimentInfo() > 0) {
443 info->mutableRun().addProperty(
"W_MATRIX", projectionMatrix.
getVector(),
true);
447 auto geometry = std::dynamic_pointer_cast<Mantid::API::MDGeometry>(sliceWS);
452 geometry->clearTransforms();
453 geometry->clearOriginalWorkspaces();
455 setProperty(
"OutputWorkspace", sliceWS);
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
std::vector< T > const * vec
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.