Mantid
Loading...
Searching...
No Matches
CylinderAbsorption.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 +
9#include "MantidAPI/Sample.h"
16
17namespace Mantid::Algorithms {
18
19// Register the algorithm into the AlgorithmFactory
20DECLARE_ALGORITHM(CylinderAbsorption)
21
22using namespace Kernel;
23using namespace Geometry;
24using namespace API;
25
27 : AbsorptionCorrection(), m_cylHeight(0.0), m_cylRadius(0.0), m_numSlices(0), m_numAnnuli(0),
28 m_useSampleShape(false) {}
29
30std::map<std::string, std::string> CylinderAbsorption::validateInputs() {
31 std::map<std::string, std::string> issues;
32 std::vector<double> prop = getProperty("CylinderAxis");
33 if (prop.size() != 3) {
34 issues["CylinderAxis"] = "CylinderAxis must be a list with 3 elements.";
35 }
36 return issues;
37}
38
40 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
41 mustBePositive->setLower(0.0);
42 declareProperty("CylinderSampleHeight", EMPTY_DBL(), mustBePositive,
43 "The height of the cylindrical sample in centimetres");
44 declareProperty("CylinderSampleRadius", EMPTY_DBL(), mustBePositive,
45 "The radius of the cylindrical sample in centimetres");
46 declareProperty(std::make_unique<ArrayProperty<double>>("CylinderAxis", "0.0, 1.0, 0.0"),
47 "A 3D vector specifying the cylindrical sample's orientation");
48
49 auto positiveInt = std::make_shared<BoundedValidator<int>>();
50 positiveInt->setLower(1);
51 declareProperty("NumberOfSlices", 1, positiveInt,
52 "The number of slices into which the cylinder is divided for the\n"
53 "calculation");
54 declareProperty("NumberOfAnnuli", 1, positiveInt,
55 "The number of annuli into which each slice is divided for the\n"
56 "calculation");
57}
58
59// returns an empty string if anything is wrong
60void CylinderAbsorption::getShapeFromSample(const Geometry::IObject &sampleShape, bool updateHeight,
61 bool updateRadius) {
62 if (!(updateHeight || updateRadius))
63 return; // nothing to update
64 if (!sampleShape.hasValidShape())
65 return; // no valid shape
67 return; // not a cylinder
68
69 // get to the underlying ShapeInfo object
70 const auto csgshape = dynamic_cast<const CSGObject *>(&sampleShape);
71 if (!csgshape)
72 return;
73 const auto &shapeObj = csgshape->shapeInfo();
74
75 if (updateRadius)
76 m_cylRadius = shapeObj.radius();
77 if (updateHeight)
78 m_cylHeight = shapeObj.height();
79}
80
83 m_numSlices = getProperty("NumberOfSlices");
84 m_numAnnuli = getProperty("NumberOfAnnuli");
85 std::vector<double> axisXYZ = getProperty("CylinderAxis");
86 m_cylAxis = V3D(axisXYZ[0], axisXYZ[1], axisXYZ[2]);
87
88 bool userSuppliedHeight = false;
89 bool userSuppliedRadius = false;
90
91 m_cylHeight = getProperty("CylinderSampleHeight"); // in cm
92 if (!isEmpty(m_cylHeight)) {
93 m_cylHeight *= 0.01; // now in m
94 userSuppliedHeight = true;
95 }
96 m_cylRadius = getProperty("CylinderSampleRadius"); // in cm
97 if (!isEmpty(m_cylRadius)) {
98 m_cylRadius *= 0.01; // now in m
99 userSuppliedRadius = true;
100 }
101
102 // this declares that at least part of the built-in sample geometry should be
103 // ignored and use the supplied parameters instead
104 m_useSampleShape = !(userSuppliedHeight || userSuppliedRadius);
105
106 // if the user supplied both, then just ignore the built-in shape
107 if (userSuppliedHeight && userSuppliedRadius) {
108 g_log.information("Chosing user supplied sample geometry in CylinderAbsorption");
109 return;
110 }
111
112 // get the missing parameters from the sample shape
113 const auto &sampleShape = m_inputWS->sample().getShape();
114 getShapeFromSample(sampleShape, !userSuppliedHeight, !userSuppliedRadius);
115
116 bool heightOk = m_cylRadius >= 0. && (!isEmpty(m_cylHeight));
117 bool radiusOk = (m_cylRadius >= 0.) && (!isEmpty(m_cylRadius));
118 if (heightOk && radiusOk) {
119 g_log.information() << "Creating cylinder with radius=" << m_cylRadius << "m, height=" << m_cylHeight << "m\n";
120 } else if (!heightOk) {
121 if (radiusOk) {
122 throw std::invalid_argument("Failed to specify height of cylinder");
123 } else { // radiusOk == false
124 throw std::invalid_argument("Failed to specify height and radius of cylinder");
125 }
126 } else { // radiusOk == false
127 throw std::invalid_argument("Failed to specify radius of cylinder");
128 }
129}
130
133 return std::string();
134
135 // Get the sample position, which is typically the origin but we should be
136 // generic
137 const V3D samplePos = m_inputWS->getInstrument()->getSample()->getPos();
138 // Shift so that cylinder is centered at sample position
139 const V3D cylBase = m_cylAxis * (-0.5 * m_cylHeight) + samplePos;
140
141 // The default behavior is to have the sample along the y-axis. If something
142 // else is desired, it will have to be done through SetSample.
143 std::ostringstream xmlShapeStream;
144 xmlShapeStream << "<cylinder id=\"detector-shape\"> "
145 << "<centre-of-bottom-base x=\"" << cylBase.X() << "\" y=\"" << cylBase.Y() << "\" z=\"" << cylBase.Z()
146 << "\" /> "
147 << "<axis x=\"" << m_cylAxis.X() << "\" y=\"" << m_cylAxis.Y() << "\" z=\"" << m_cylAxis.Z()
148 << "\" /> "
149 << "<radius val=\"" << m_cylRadius << "\" /> "
150 << "<height val=\"" << m_cylHeight << "\" /> "
151 << "</cylinder>";
152
153 return xmlShapeStream.str();
154}
155
159 if (!m_sampleObject) // should never happen
160 throw std::runtime_error("Do not have a sample object defined");
161
163 throw std::runtime_error("Sample shape is not a cylinder");
164 const auto *shape = dynamic_cast<const Geometry::CSGObject *>(m_sampleObject);
165 if (!shape)
166 throw std::runtime_error("Failed to convert shape from IObject to CSGObject");
168 m_sampleVolume = raster.totalvolume;
169 if (raster.l1.size() == 0)
170 throw std::runtime_error("Failed to rasterize shape");
171 // move over the information
172 m_numVolumeElements = raster.l1.size();
173 m_L1s = std::move(raster.l1);
174 m_elementPositions = std::move(raster.position);
175 m_elementVolumes = std::move(raster.volume);
176}
177
178} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Kernel::Logger & g_log
Definition: Algorithm.h:451
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
A base class for absorption correction algorithms.
std::vector< double > m_elementVolumes
Cached element volumes.
Kernel::V3D m_beamDirection
The direction of the beam.
double m_sampleVolume
The total volume of the sample.
API::MatrixWorkspace_sptr m_inputWS
A pointer to the input workspace.
const Geometry::IObject * m_sampleObject
Local cache of sample object.
size_t m_numVolumeElements
The number of volume elements.
std::vector< Kernel::V3D > m_elementPositions
Cached element positions.
std::vector< double > m_L1s
Cached L1 distances.
Kernel::V3D m_cylAxis
The axis orientation of the cylinder.
void defineProperties() override
A virtual function in which additional properties of an algorithm should be declared.
void initialiseCachedDistances() override
Calculate the distances for L1 and element size for each element in the sample.
double m_cylRadius
The radius of the cylindrical sample in m.
void retrieveProperties() override
Fetch the properties and set the appropriate member variables.
std::string sampleXML() override
Returns the XML string describing the sample, which can be used by the ShapeFactory.
std::map< std::string, std::string > validateInputs() override
Method checking errors on ALL the inputs, before execution.
double m_cylHeight
The height of the cylindrical sample in m.
void getShapeFromSample(const Geometry::IObject &sampleShape, bool updateHeight, bool updateRadius)
Constructive Solid Geometry object.
Definition: CSGObject.h:51
const detail::ShapeInfo & shapeInfo() const override
Definition: CSGObject.cpp:2232
IObject : Interface for geometry objects.
Definition: IObject.h:41
virtual detail::ShapeInfo::GeometryShape shape() const =0
virtual bool hasValidShape() const =0
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
Class for 3D vectors.
Definition: V3D.h:34
constexpr double X() const noexcept
Get x.
Definition: V3D.h:232
constexpr double Y() const noexcept
Get y.
Definition: V3D.h:233
constexpr double Z() const noexcept
Get z.
Definition: V3D.h:234
MANTID_GEOMETRY_DLL Raster calculateCylinder(const Kernel::V3D &beamDirection, const IObject &shape, const size_t numSlices, const size_t numAnnuli)
Definition: Rasterize.cpp:206
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43