20#include <boost/regex.hpp>
33 : m_transform(), m_transformFromOriginal(), m_transformToOriginal(), m_transformFromIntermediate(),
34 m_transformToIntermediate(), m_axisAligned(true), m_outD(0),
35 m_NormalizeBasisVectors(false) {}
44 declareProperty(
"AxisAligned",
true,
"Perform binning aligned with the axes of the input MDEventWorkspace?");
46 for (
size_t i = 0; i < dimChars.size(); i++) {
49 std::string propName =
"AlignedDim" + dim;
53 "Enter it as a comma-separated list of values with the format: "
54 "'name,minimum,maximum,number_of_bins'. Leave blank for NONE.");
61 std::string grpName =
"Non-Aligned Binning";
64 std::unique_ptr<IPropertySettings> settings =
65 std::make_unique<VisibleWhenProperty>(
"AxisAligned",
IS_EQUAL_TO,
"0");
68 for (
size_t i = 0; i < dimChars.size(); i++) {
71 std::string propName =
"BasisVector" + dim;
74 "th output dimension."
75 "Format: 'name, units, x,y,z,..'.\n"
76 " name : string for the name of the output dimension.\n"
77 " units : string for the units of the output dimension.\n"
78 " x,y,z,...: vector definining the basis in the input dimensions "
80 "Leave blank for NONE.");
85 "Coordinates in the INPUT workspace that corresponds to "
86 "(0,0,0) in the OUTPUT workspace.\n"
87 "Enter as a comma-separated string.\n"
88 "Default: 0 in all dimensions (no translation).");
91 "The minimum, maximum edges of space of each dimension of "
92 "the OUTPUT workspace, as a comma-separated list");
95 "The number of bins for each dimension of the OUTPUT workspace.");
98 "Normalize the given basis vectors to unity. \n"
99 "If true, then a distance of 1 in the INPUT dimensions = 1 "
100 "in the OUTPUT dimensions.\n"
101 "If false, then a distance of norm(basis_vector) in the "
102 "INPUT dimension = 1 in the OUTPUT dimensions.");
105 "Force the input basis vectors to form an orthogonal coordinate system. "
106 "Only works in 3 dimension!");
138 if (input.size() < 3)
139 throw std::invalid_argument(
"Dimension string is too short to be valid: " + str);
144 size_t n_first_comma;
147 if (input[0] ==
'[') {
149 size_t n = input.find_first_of(
']', 1);
150 if (
n == std::string::npos)
151 throw std::invalid_argument(
"No closing ] character in the dimension name of : " + str);
153 n_first_comma = input.find_first_of(
',',
n);
154 if (n_first_comma == std::string::npos)
155 throw std::invalid_argument(
"No comma after the closing ] character in the dimension string: " + str);
158 n_first_comma = input.find_first_of(
',');
160 if (n_first_comma == std::string::npos)
161 throw std::invalid_argument(
"No comma in the dimension string: " + str);
162 if (n_first_comma == input.size() - 1)
163 throw std::invalid_argument(
"Dimension string ends in a comma: " + str);
168 throw std::invalid_argument(
"name should not be blank.");
172 input = input.substr(n_first_comma + 1);
173 std::vector<std::string> strs;
174 boost::split(strs, input, boost::is_any_of(
","));
175 if (strs.size() != this->m_inWS->getNumDims() + 1)
176 throw std::invalid_argument(
"Wrong number of values (expected 2 + # of "
177 "input dimensions) in the dimensions string: " +
183 throw std::invalid_argument(
"Number of bins for output dimension " +
Strings::toString(dim) +
" should be >= 1.");
188 double lengthInOutput = max - min;
189 if (lengthInOutput <= 0)
190 throw std::invalid_argument(
"The maximum extents for dimension " +
Strings::toString(dim) +
" should be > 0.");
194 for (
size_t d = 0;
d < this->
m_inWS->getNumDims();
d++)
196 throw std::invalid_argument(
"Error converting argument '" + strs[
d + 1] +
"' in the dimensions string '" + str +
210 basis = origBasis1 - origBasis0;
214 double basisLength = basis.
norm();
215 if (basisLength <= 0)
216 throw std::invalid_argument(
"direction should not be 0-length.");
219 double transformScaling = 1.0;
224 transformScaling = 1.0;
228 transformScaling = (1.0 / basisLength);
231 double lengthInInput = lengthInOutput / transformScaling;
235 double binningScaling = double(numBins) / (lengthInInput);
244 auto out = std::make_shared<MDHistoDimension>(
name,
name, *frame,
static_cast<coord_t>(min),
245 static_cast<coord_t>(max), numBins);
264 for (
char dimChar : dimChars) {
265 std::string propName =
"BasisVector0";
266 propName[11] = dimChar;
271 std::vector<double> extents = this->
getProperty(
"OutputExtents");
272 if (extents.size() !=
m_outD * 2)
275 "(2 for each dimension in the OUTPUT workspace).");
286 throw std::invalid_argument(
"The OutputBins parameter must have 1 entry "
287 "for each dimension in the OUTPUT workspace.");
293 for (
char dimChar : dimChars) {
294 std::string propName =
"BasisVector0";
295 propName[11] = dimChar;
298 }
catch (std::exception &e) {
299 throw std::invalid_argument(
"Error parsing the " + propName +
" parameter: " + std::string(e.what()));
306 throw std::runtime_error(
"No output dimensions were found in the MDEventWorkspace. Cannot bin!");
309 std::vector<double> translVector;
312 }
catch (std::exception &e) {
313 throw std::invalid_argument(
"Error parsing the Translation parameter: " + std::string(e.what()));
317 if (translVector.empty())
318 translVector.resize(
m_inWS->getNumDims(), 0);
322 throw std::invalid_argument(
"The number of dimensions in the Translation parameter is "
323 "not consistent with the number of dimensions in the input workspace.");
327 throw std::runtime_error(
"More output dimensions were specified than input dimensions "
328 "exist in the MDEventWorkspace. Cannot bin!");
330 throw std::runtime_error(
"Inconsistent number of entries in scaling vector.");
342 size_t inD =
m_inWS->getNumDims();
345 bool ForceOrthogonal =
getProperty(
"ForceOrthogonal");
346 if (ForceOrthogonal &&
m_bases[0].getNumDims() == 3 &&
m_bases.size() >= 2) {
347 std::vector<VMD> firstTwo =
m_bases;
348 firstTwo.resize(2,
VMD(3));
374 auto ct = std::make_unique<DataObjects::CoordTransformAffine>(inD,
m_outD);
380 auto ctFrom = std::make_unique<DataObjects::CoordTransformAffine>(inD,
m_outD);
386 throw std::invalid_argument(
"The number of input dimensions in the CoordinateTransform "
387 "object is not consistent with the number of dimensions in the input "
390 throw std::invalid_argument(
"The number of output dimensions in the CoordinateTransform "
391 "object is not consistent with the number of dimensions specified in "
392 "the OutDimX, etc. properties.");
398 auto ctTo = std::make_unique<DataObjects::CoordTransformAffine>(inD,
m_outD);
416 throw std::runtime_error(
"Empty string passed to one of the AlignedDim0 parameters.");
420 if (input.size() < 4)
421 throw std::invalid_argument(
"Dimensions string is too short to be valid: " + str);
424 size_t n = std::string::npos;
425 for (
size_t i = 0; i < 3; i++) {
426 n = input.find_last_of(
',',
n);
427 if (
n == std::string::npos)
428 throw std::invalid_argument(
"Wrong number of values (4 are expected) "
429 "in the dimensions string: " +
432 throw std::invalid_argument(
"Dimension string starts with a comma: " + str);
436 std::string
name = input.substr(0,
n + 1);
440 input = input.substr(
n + 2);
441 std::vector<std::string> strs;
442 boost::split(strs, input, boost::is_any_of(
","));
443 if (strs.size() != 3)
444 throw std::invalid_argument(
"Wrong number of values (3 are expected) after the name "
445 "in the dimensions string: " +
455 throw std::invalid_argument(
"Name should not be blank.");
457 throw std::invalid_argument(
"Min should be > max.");
459 throw std::invalid_argument(
"Number of bins should be >= 1.");
462 size_t dim_index = 0;
464 dim_index =
m_inWS->getDimensionIndexByName(
name);
465 }
catch (std::runtime_error &) {
468 dim_index =
m_inWS->getDimensionIndexById(
name);
469 }
catch (std::runtime_error &) {
470 throw std::runtime_error(
"Dimension " +
name +
471 " was not found in the "
472 "MDEventWorkspace! Cannot continue.");
478 const auto &frame = inputDim->getMDFrame();
480 new MDHistoDimension(inputDim->getName(), inputDim->getDimensionId(), frame, min, max, numBins)));
494 bool previousWasEmpty =
false;
496 for (
char dimChar : dimChars) {
497 std::string propName =
"AlignedDim0";
498 propName[10] = dimChar;
502 if (!prop.empty() && previousWasEmpty)
503 throw std::invalid_argument(
"Please enter the AlignedDim parameters in the order 0,1,2, etc.,"
504 "without skipping any entries.");
505 previousWasEmpty = prop.empty();
509 size_t inD =
m_inWS->getNumDims();
512 throw std::runtime_error(
"No output dimensions specified.");
514 throw std::runtime_error(
"More output dimensions were specified than input dimensions "
515 "exist in the MDEventWorkspace.");
518 for (
size_t i = 0; i < numDims; i++) {
519 std::string propName =
"AlignedDim0";
520 propName[10] = dimChars[i];
547 std::vector<coord_t> unitScaling(
m_outD, 1.0);
548 std::vector<coord_t> zeroOrigin(
m_outD, 0.0);
558 auto tmp = std::make_unique<DataObjects::CoordTransformAffine>(inD,
m_outD);
564 g_log.
warning(
"SlicingAlgorithm: Your slice will cause the output "
565 "workspace to have fewer dimensions than the input. This will "
566 "affect your ability to create subsequent slices.");
584 throw std::runtime_error(
"SlicingAlgorithm::createTransform(): input "
585 "MDWorkspace must be set first!");
586 if (std::dynamic_pointer_cast<MatrixWorkspace>(
m_inWS))
587 throw std::runtime_error(this->
name() +
" cannot be run on a MatrixWorkspace!");
593 if (
m_inWS->numOriginalWorkspaces() > 0)
594 m_originalWS = std::dynamic_pointer_cast<IMDWorkspace>(
m_inWS->getOriginalWorkspace());
597 throw std::runtime_error(
"Cannot perform axis-aligned binning on a MDHistoWorkspace. "
598 "Please use non-axis aligned binning.");
601 throw std::runtime_error(
"SlicingAlgorithm::createTransform(): Cannot propagate "
602 "a transformation if the number of dimensions has changed.");
604 if (!
m_inWS->getTransformToOriginal())
605 throw std::runtime_error(
"SlicingAlgorithm::createTransform(): Cannot propagate "
606 "a transformation. There is no transformation saved from " +
612 if (inHisto->getNumExperimentInfo() > 0) {
613 const Run &run = inHisto->getExperimentInfo(0)->run();
617 if (prop->
value() ==
"1") {
618 throw std::runtime_error(
"This MDHistoWorkspace was modified by a binary operation "
619 "(e.g. Plus, Minus). "
620 "It is not currently possible to rebin a modified "
621 "MDHistoWorkspace because that requires returning to the "
623 "(unmodified) MDEventWorkspace, and so would give incorrect "
625 "Instead, you can use SliceMD and perform operations on the "
627 "MDEventWorkspaces, which preserve all events. "
628 "You can override this check by removing the "
629 "'mdhisto_was_modified' sample log.");
659 Matrix<coord_t> matToIntermediate = matOriginalToIntermediate * matToOriginal;
665 matToIntermediate.
Invert();
669 }
catch (std::runtime_error &) {
698 const size_t *
const chunkMax) {
699 size_t nd =
m_inWS->getNumDims();
702 auto func = std::make_unique<MDImplicitFunction>();
709 std::vector<VMD> bases;
716 if (chunkMin !=
nullptr)
718 if (chunkMax !=
nullptr)
725 bases.emplace_back(thisBase);
731 size_t boxDim = bases.
size();
734 VMD insidePoint = (o1 + o2) / 2.0;
740 func->addPlane(
MDPlane(
x * -1.0, o2));
741 }
else if (boxDim == nd || boxDim == nd - 1) {
754 std::vector<VMD> vectors;
756 for (
size_t ignoreIndex = 0; ignoreIndex < boxDim; ++ignoreIndex) {
759 for (
size_t baseIndex = 0; baseIndex < boxDim; ++baseIndex) {
760 if (baseIndex != ignoreIndex)
761 vectors.emplace_back(bases[baseIndex]);
766 if (boxDim == nd - 1)
770 func->addPlane(
MDPlane(vectors, o1, insidePoint));
771 func->addPlane(
MDPlane(vectors, o2, insidePoint));
778 " dimensions and " +
"therefore will assume orthogonality");
779 for (
auto &base : bases) {
782 func->addPlane(
MDPlane(base, o1));
783 func->addPlane(
MDPlane(base * -1.0, o2));
804 const size_t *
const chunkMax) {
805 size_t nd =
m_inWS->getNumDims();
807 std::vector<coord_t> function_min(nd, -1e30f);
808 std::vector<coord_t> function_max(nd, +1e30f);
809 for (
size_t bd = 0; bd <
m_outD; bd++) {
821 return std::make_unique<MDBoxImplicitFunction>(function_min, function_max);
850 std::vector<Mantid::Kernel::VMD> oldBasis;
851 for (
size_t i = 0; i < dimension; ++i) {
853 basisVector[i] = 1.0;
854 oldBasis.emplace_back(basisVector);
867 return std::fabs(oldVector.
scalar_prod(basisVector)) > 0.0;
877 const std::vector<Mantid::Kernel::VMD> &oldBasis)
const {
878 std::vector<size_t> indexWithProjection;
881 indexWithProjection.emplace_back(
index);
884 return indexWithProjection;
896 const std::string &units)
const {
897 if (indicesWithProjection.empty()) {
898 g_log.
warning() <<
"Slicing Algorithm: Chosen vector does not "
899 "project on any vector of the old basis.";
902 const auto &referenceMDFrame =
m_inWS->getDimension(indicesWithProjection[0])->getMDFrame();
904 for (
auto &
index : indicesWithProjection) {
905 const auto &toCheckMDFrame =
m_inWS->getDimension(
index)->getMDFrame();
906 if (!referenceMDFrame.isSameType(toCheckMDFrame)) {
907 g_log.
warning() <<
"Slicing Algorithm: New basis vector tries to "
908 "mix un-mixable MDFrame types.";
924 boost::regex pattern(
"in.*A.*\\^-1");
926 if (boost::regex_match(unit, pattern)) {
929 mdFrame->setMDUnit(md_unit);
930 }
else if (unit ==
"r") {
933 mdFrame->setMDUnit(md_unit);
934 }
else if (unit ==
"a") {
937 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.