21#include <boost/regex.hpp>
34 : m_transform(), m_transformFromOriginal(), m_transformToOriginal(), m_transformFromIntermediate(),
35 m_transformToIntermediate(), m_axisAligned(true), m_outD(0),
36 m_NormalizeBasisVectors(false) {}
45 declareProperty(
"AxisAligned",
true,
"Perform binning aligned with the axes of the input MDEventWorkspace?");
47 for (
size_t i = 0; i < dimChars.size(); i++) {
50 std::string propName =
"AlignedDim" + dim;
54 "Enter it as a comma-separated list of values with the format: "
55 "'name,minimum,maximum,number_of_bins'. Leave blank for NONE.");
62 std::string grpName =
"Non-Aligned Binning";
65 std::unique_ptr<IPropertySettings> settings =
66 std::make_unique<VisibleWhenProperty>(
"AxisAligned",
IS_EQUAL_TO,
"0");
69 for (
size_t i = 0; i < dimChars.size(); i++) {
72 std::string propName =
"BasisVector" + dim;
75 "th output dimension."
76 "Format: 'name, units, x,y,z,..'.\n"
77 " name : string for the name of the output dimension.\n"
78 " units : string for the units of the output dimension.\n"
79 " x,y,z,...: vector definining the basis in the input dimensions "
81 "Leave blank for NONE.");
86 "Coordinates in the INPUT workspace that corresponds to "
87 "(0,0,0) in the OUTPUT workspace.\n"
88 "Enter as a comma-separated string.\n"
89 "Default: 0 in all dimensions (no translation).");
92 "The minimum, maximum edges of space of each dimension of "
93 "the OUTPUT workspace, as a comma-separated list");
96 "The number of bins for each dimension of the OUTPUT workspace.");
99 "Normalize the given basis vectors to unity. \n"
100 "If true, then a distance of 1 in the INPUT dimensions = 1 "
101 "in the OUTPUT dimensions.\n"
102 "If false, then a distance of norm(basis_vector) in the "
103 "INPUT dimension = 1 in the OUTPUT dimensions.");
106 "Force the input basis vectors to form an orthogonal coordinate system. "
107 "Only works in 3 dimension!");
139 if (input.size() < 3)
140 throw std::invalid_argument(
"Dimension string is too short to be valid: " + str);
145 size_t n_first_comma;
148 if (input[0] ==
'[') {
150 size_t n = input.find_first_of(
']', 1);
151 if (
n == std::string::npos)
152 throw std::invalid_argument(
"No closing ] character in the dimension name of : " + str);
154 n_first_comma = input.find_first_of(
',',
n);
155 if (n_first_comma == std::string::npos)
156 throw std::invalid_argument(
"No comma after the closing ] character in the dimension string: " + str);
159 n_first_comma = input.find_first_of(
',');
161 if (n_first_comma == std::string::npos)
162 throw std::invalid_argument(
"No comma in the dimension string: " + str);
163 if (n_first_comma == input.size() - 1)
164 throw std::invalid_argument(
"Dimension string ends in a comma: " + str);
169 throw std::invalid_argument(
"name should not be blank.");
173 input = input.substr(n_first_comma + 1);
174 std::vector<std::string> strs;
175 boost::split(strs, input, boost::is_any_of(
","));
176 if (strs.size() != this->m_inWS->getNumDims() + 1)
177 throw std::invalid_argument(
"Wrong number of values (expected 2 + # of "
178 "input dimensions) in the dimensions string: " +
184 throw std::invalid_argument(
"Number of bins for output dimension " +
Strings::toString(dim) +
" should be >= 1.");
189 double lengthInOutput = max - min;
190 if (lengthInOutput <= 0)
191 throw std::invalid_argument(
"The maximum extents for dimension " +
Strings::toString(dim) +
" should be > 0.");
195 for (
size_t d = 0;
d < this->
m_inWS->getNumDims();
d++)
197 throw std::invalid_argument(
"Error converting argument '" + strs[
d + 1] +
"' in the dimensions string '" + str +
211 basis = origBasis1 - origBasis0;
215 double basisLength = basis.
norm();
216 if (basisLength <= 0)
217 throw std::invalid_argument(
"direction should not be 0-length.");
220 double transformScaling = 1.0;
225 transformScaling = 1.0;
229 transformScaling = (1.0 / basisLength);
232 double lengthInInput = lengthInOutput / transformScaling;
236 double binningScaling = double(numBins) / (lengthInInput);
245 auto out = std::make_shared<MDHistoDimension>(
name,
name, *frame,
static_cast<coord_t>(min),
246 static_cast<coord_t>(max), numBins);
265 for (
char dimChar : dimChars) {
266 std::string propName =
"BasisVector0";
267 propName[11] = dimChar;
272 std::vector<double> extents = this->
getProperty(
"OutputExtents");
273 if (extents.size() !=
m_outD * 2)
276 "(2 for each dimension in the OUTPUT workspace).");
287 throw std::invalid_argument(
"The OutputBins parameter must have 1 entry "
288 "for each dimension in the OUTPUT workspace.");
294 for (
char dimChar : dimChars) {
295 std::string propName =
"BasisVector0";
296 propName[11] = dimChar;
299 }
catch (std::exception &e) {
300 throw std::invalid_argument(
"Error parsing the " + propName +
" parameter: " + std::string(e.what()));
307 throw std::runtime_error(
"No output dimensions were found in the MDEventWorkspace. Cannot bin!");
310 std::vector<double> translVector;
313 }
catch (std::exception &e) {
314 throw std::invalid_argument(
"Error parsing the Translation parameter: " + std::string(e.what()));
318 if (translVector.empty())
319 translVector.resize(
m_inWS->getNumDims(), 0);
323 throw std::invalid_argument(
"The number of dimensions in the Translation parameter is "
324 "not consistent with the number of dimensions in the input workspace.");
328 throw std::runtime_error(
"More output dimensions were specified than input dimensions "
329 "exist in the MDEventWorkspace. Cannot bin!");
331 throw std::runtime_error(
"Inconsistent number of entries in scaling vector.");
343 size_t inD =
m_inWS->getNumDims();
346 bool ForceOrthogonal =
getProperty(
"ForceOrthogonal");
347 if (ForceOrthogonal &&
m_bases[0].getNumDims() == 3 &&
m_bases.size() >= 2) {
348 std::vector<VMD> firstTwo =
m_bases;
349 firstTwo.resize(2,
VMD(3));
375 auto ct = std::make_unique<DataObjects::CoordTransformAffine>(inD,
m_outD);
381 auto ctFrom = std::make_unique<DataObjects::CoordTransformAffine>(inD,
m_outD);
387 throw std::invalid_argument(
"The number of input dimensions in the CoordinateTransform "
388 "object is not consistent with the number of dimensions in the input "
391 throw std::invalid_argument(
"The number of output dimensions in the CoordinateTransform "
392 "object is not consistent with the number of dimensions specified in "
393 "the OutDimX, etc. properties.");
399 auto ctTo = std::make_unique<DataObjects::CoordTransformAffine>(inD,
m_outD);
417 throw std::runtime_error(
"Empty string passed to one of the AlignedDim0 parameters.");
421 if (input.size() < 4)
422 throw std::invalid_argument(
"Dimensions string is too short to be valid: " + str);
425 size_t n = std::string::npos;
426 for (
size_t i = 0; i < 3; i++) {
427 n = input.find_last_of(
',',
n);
428 if (
n == std::string::npos)
429 throw std::invalid_argument(
"Wrong number of values (4 are expected) "
430 "in the dimensions string: " +
433 throw std::invalid_argument(
"Dimension string starts with a comma: " + str);
437 std::string
name = input.substr(0,
n + 1);
441 input = input.substr(
n + 2);
442 std::vector<std::string> strs;
443 boost::split(strs, input, boost::is_any_of(
","));
444 if (strs.size() != 3)
445 throw std::invalid_argument(
"Wrong number of values (3 are expected) after the name "
446 "in the dimensions string: " +
456 throw std::invalid_argument(
"Name should not be blank.");
458 throw std::invalid_argument(
"Min should be > max.");
460 throw std::invalid_argument(
"Number of bins should be >= 1.");
463 size_t dim_index = 0;
465 dim_index =
m_inWS->getDimensionIndexByName(
name);
466 }
catch (std::runtime_error &) {
469 dim_index =
m_inWS->getDimensionIndexById(
name);
470 }
catch (std::runtime_error &) {
471 throw std::runtime_error(
"Dimension " +
name +
472 " was not found in the "
473 "MDEventWorkspace! Cannot continue.");
479 const auto &frame = inputDim->getMDFrame();
481 new MDHistoDimension(inputDim->getName(), inputDim->getDimensionId(), frame, min, max, numBins)));
495 bool previousWasEmpty =
false;
497 for (
char dimChar : dimChars) {
498 std::string propName =
"AlignedDim0";
499 propName[10] = dimChar;
503 if (!prop.empty() && previousWasEmpty)
504 throw std::invalid_argument(
"Please enter the AlignedDim parameters in the order 0,1,2, etc.,"
505 "without skipping any entries.");
506 previousWasEmpty = prop.empty();
510 size_t inD =
m_inWS->getNumDims();
513 throw std::runtime_error(
"No output dimensions specified.");
515 throw std::runtime_error(
"More output dimensions were specified than input dimensions "
516 "exist in the MDEventWorkspace.");
519 for (
size_t i = 0; i < numDims; i++) {
520 std::string propName =
"AlignedDim0";
521 propName[10] = dimChars[i];
548 std::vector<coord_t> unitScaling(
m_outD, 1.0);
549 std::vector<coord_t> zeroOrigin(
m_outD, 0.0);
559 auto tmp = std::make_unique<DataObjects::CoordTransformAffine>(inD,
m_outD);
565 g_log.
warning(
"SlicingAlgorithm: Your slice will cause the output "
566 "workspace to have fewer dimensions than the input. This will "
567 "affect your ability to create subsequent slices.");
585 throw std::runtime_error(
"SlicingAlgorithm::createTransform(): input "
586 "MDWorkspace must be set first!");
587 if (std::dynamic_pointer_cast<MatrixWorkspace>(
m_inWS))
588 throw std::runtime_error(this->
name() +
" cannot be run on a MatrixWorkspace!");
594 if (
m_inWS->numOriginalWorkspaces() > 0)
595 m_originalWS = std::dynamic_pointer_cast<IMDWorkspace>(
m_inWS->getOriginalWorkspace());
598 throw std::runtime_error(
"Cannot perform axis-aligned binning on a MDHistoWorkspace. "
599 "Please use non-axis aligned binning.");
602 throw std::runtime_error(
"SlicingAlgorithm::createTransform(): Cannot propagate "
603 "a transformation if the number of dimensions has changed.");
605 if (!
m_inWS->getTransformToOriginal())
606 throw std::runtime_error(
"SlicingAlgorithm::createTransform(): Cannot propagate "
607 "a transformation. There is no transformation saved from " +
613 if (inHisto->getNumExperimentInfo() > 0) {
614 const Run &run = inHisto->getExperimentInfo(0)->run();
618 if (prop->
value() ==
"1") {
619 throw std::runtime_error(
"This MDHistoWorkspace was modified by a binary operation "
620 "(e.g. Plus, Minus). "
621 "It is not currently possible to rebin a modified "
622 "MDHistoWorkspace because that requires returning to the "
624 "(unmodified) MDEventWorkspace, and so would give incorrect "
626 "Instead, you can use SliceMD and perform operations on the "
628 "MDEventWorkspaces, which preserve all events. "
629 "You can override this check by removing the "
630 "'mdhisto_was_modified' sample log.");
660 Matrix<coord_t> matToIntermediate = matOriginalToIntermediate * matToOriginal;
666 matToIntermediate.
Invert();
670 }
catch (std::runtime_error &) {
699 const size_t *
const chunkMax) {
700 size_t nd =
m_inWS->getNumDims();
703 auto func = std::make_unique<MDImplicitFunction>();
710 std::vector<VMD> bases;
717 if (chunkMin !=
nullptr)
719 if (chunkMax !=
nullptr)
726 bases.emplace_back(thisBase);
732 size_t boxDim = bases.
size();
735 VMD insidePoint = (o1 + o2) / 2.0;
741 func->addPlane(
MDPlane(
x * -1.0, o2));
742 }
else if (boxDim == nd || boxDim == nd - 1) {
755 std::vector<VMD> vectors;
757 for (
size_t ignoreIndex = 0; ignoreIndex < boxDim; ++ignoreIndex) {
760 for (
size_t baseIndex = 0; baseIndex < boxDim; ++baseIndex) {
761 if (baseIndex != ignoreIndex)
762 vectors.emplace_back(bases[baseIndex]);
767 if (boxDim == nd - 1)
771 func->addPlane(
MDPlane(vectors, o1, insidePoint));
772 func->addPlane(
MDPlane(vectors, o2, insidePoint));
779 " dimensions and " +
"therefore will assume orthogonality");
780 for (
auto &base : bases) {
783 func->addPlane(
MDPlane(base, o1));
784 func->addPlane(
MDPlane(base * -1.0, o2));
805 const size_t *
const chunkMax) {
806 size_t nd =
m_inWS->getNumDims();
808 std::vector<coord_t> function_min(nd, -1e30f);
809 std::vector<coord_t> function_max(nd, +1e30f);
810 for (
size_t bd = 0; bd <
m_outD; bd++) {
822 return std::make_unique<MDBoxImplicitFunction>(function_min, function_max);
851 std::vector<Mantid::Kernel::VMD> oldBasis;
852 for (
size_t i = 0; i < dimension; ++i) {
854 basisVector[i] = 1.0;
855 oldBasis.emplace_back(basisVector);
868 return std::fabs(oldVector.
scalar_prod(basisVector)) > 0.0;
878 const std::vector<Mantid::Kernel::VMD> &oldBasis)
const {
879 std::vector<size_t> indexWithProjection;
882 indexWithProjection.emplace_back(
index);
885 return indexWithProjection;
897 const std::string &units)
const {
898 if (indicesWithProjection.empty()) {
899 g_log.
warning() <<
"Slicing Algorithm: Chosen vector does not "
900 "project on any vector of the old basis.";
903 const auto &referenceMDFrame =
m_inWS->getDimension(indicesWithProjection[0])->getMDFrame();
905 for (
auto &
index : indicesWithProjection) {
906 const auto &toCheckMDFrame =
m_inWS->getDimension(
index)->getMDFrame();
907 if (!referenceMDFrame.isSameType(toCheckMDFrame)) {
908 g_log.
warning() <<
"Slicing Algorithm: New basis vector tries to "
909 "mix un-mixable MDFrame types.";
925 boost::regex pattern(
"in.*A.*\\^-1");
927 if (boost::regex_match(unit, pattern)) {
930 mdFrame->setMDUnit(md_unit);
931 }
else if (unit ==
"r") {
934 mdFrame->setMDUnit(md_unit);
935 }
else if (unit ==
"a") {
938 mdFrame->setMDUnit(md_unit);
std::map< DeltaEMode::Type, std::string > index
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.
const std::string name() const override=0
function to return a name of the algorithm, must be overridden in all algorithms
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
This class stores information regarding an experimental run as a series of log entries.
A generalized description of a N-dimensional hyperplane.
Support for a property that holds an array of values.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void notice(const std::string &msg)
Logs at notice level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
T Invert()
LU inversion routine.
The concrete, templated class for properties.
Base class for properties.
virtual std::string value() const =0
Returns the value of the property as a string.
static std::vector< VMDBase > makeVectorsOrthogonal(std::vector< VMDBase > &vectors)
Make an orthogonal system with 2 input 3D vectors.
TYPE normalize()
Normalize this vector to unity length.
TYPE scalar_prod(const VMDBase &v) const
Scalar product of two vectors.
size_t getNumDims() const
static VMDBase getNormalVector(const std::vector< VMDBase > &vectors)
Given N-1 vectors defining a N-1 dimensional hyperplane in N dimensions, returns a vector that is nor...
std::unique_ptr< API::CoordTransform > m_transformFromOriginal
Coordinate transformation to save in the output workspace (original->binned)
Mantid::API::IMDWorkspace_sptr m_intermediateWS
Intermediate original workspace.
std::vector< size_t > m_dimensionToBinFrom
Index of the dimension in the MDEW for the dimension in the output.
std::unique_ptr< Mantid::Geometry::MDImplicitFunction > getImplicitFunctionForChunk(const size_t *const chunkMin, const size_t *const chunkMax)
Create an implicit function for picking boxes, based on the indexes in the output MDHistoWorkspace.
bool isProjectingOnFrame(const Mantid::Kernel::VMD &oldVector, const Mantid::Kernel::VMD &basisVector) const
Check if the two vectors are orthogonal or not.
std::unique_ptr< API::CoordTransform > m_transform
Coordinate transformation to apply.
std::vector< size_t > getIndicesWithProjection(const Mantid::Kernel::VMD &basisVector, const std::vector< Mantid::Kernel::VMD > &oldBasis) const
Get indices which have a projection contribution.
Mantid::API::IMDWorkspace_sptr m_originalWS
Original (MDEventWorkspace) that inWS was based on.
static std::string getDimensionChars()
void createGeneralTransform()
Loads the dimensions and create the coordinate transform, using the inputs.
void createTransform()
Read the algorithm properties and creates the appropriate transforms for slicing the MDEventWorkspace...
void createAlignedTransform()
Using the parameters, create a coordinate transformation for aligned cuts.
void setTargetUnits(Mantid::Geometry::MDFrame_uptr &frame, const std::string &units) const
std::vector< Mantid::Kernel::VMD > getOldBasis(size_t dimension) const
Mantid::Kernel::VMD m_inputMinPoint
Coordinates in the INPUT workspace corresponding to the minimum edge in all dimensions.
std::vector< double > m_maxExtents
For non-aligned, the maximum coordinate extents in each OUTPUT dimension.
Mantid::API::IMDWorkspace_sptr m_inWS
Input workspace.
std::unique_ptr< API::CoordTransform > m_transformToOriginal
Coordinate transformation to save in the output workspace (binned->original)
std::unique_ptr< DataObjects::CoordTransformAffine > m_transformFromIntermediate
Coordinate transformation to save in the output WS, from the intermediate WS.
std::vector< double > m_binningScaling
Scaling factor to apply for each basis vector (to map to the bins).
size_t m_outD
Number of dimensions in the output (binned) workspace.
void makeBasisVectorFromString(const std::string &str)
Generate the MDHistoDimension and basis vector for a given string from BasisVector0 etc.
Mantid::Geometry::MDFrame_uptr createMDFrameForNonAxisAligned(const std::string &units, const Mantid::Kernel::VMD &basisVector) const
Create an MDFrame for the Non-Axis-Aligned case.
bool m_NormalizeBasisVectors
The NormalizeBasisVectors option.
void processGeneralTransformProperties()
Reads the various Properties for the general (non-aligned) case and fills in members on the Algorithm...
std::vector< Mantid::Kernel::VMD > m_bases
Basis vectors of the output dimensions, normalized to unity length.
std::unique_ptr< Mantid::Geometry::MDImplicitFunction > getGeneralImplicitFunction(const size_t *const chunkMin, const size_t *const chunkMax)
Create an implicit function for picking boxes, based on the indexes in the output MDHistoWorkspace.
Mantid::Geometry::MDFrame_uptr extractMDFrameForNonAxisAligned(std::vector< size_t > indicesWithProjection, const std::string &units) const
Extract the MDFrame.
bool m_axisAligned
Set to true if the cut is aligned with the axes.
void initSlicingProps()
Initialise the properties.
std::vector< int > m_numBins
For non-aligned, the number of bins in each OUTPUT dimension.
SlicingAlgorithm()
Constructor.
Mantid::Kernel::VMD m_translation
Translation from the OUTPUT to the INPUT workspace i.e.
std::vector< double > m_transformScaling
Scaling factor to apply for each basis vector to transfor to the output dimensions.
std::vector< double > m_minExtents
For non-aligned, the minimum coordinate extents in each OUTPUT dimension.
std::unique_ptr< DataObjects::CoordTransformAffine > m_transformToIntermediate
Coordinate transformation to save in the intermediate WS.
void makeAlignedDimensionFromString(const std::string &str)
Generate a MDHistoDimension_sptr from a comma-sep string (for AlignedDim0, etc.) Must be called in or...
std::vector< Mantid::Geometry::MDHistoDimension_sptr > m_binDimensions
Bin dimensions to actually use.
std::shared_ptr< MDHistoWorkspace > MDHistoWorkspace_sptr
A shared pointer to a MDHistoWorkspace.
std::unique_ptr< MDFrame > MDFrame_uptr
std::shared_ptr< MDHistoDimension > MDHistoDimension_sptr
Shared pointer to a MDHistoDimension.
std::shared_ptr< const IMDDimension > IMDDimension_const_sptr
Shared Pointer to const IMDDimension.
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
int convert(const std::string &A, T &out)
Convert a string into a number.
std::string toString(const T &value)
Convert a number to a string.
VMDBase< VMD_t > VMD
Define the VMD as using the double or float data type.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.