15using Geometry::CSGObject;
19 l1.reserve(numVolumeElements);
20 volume.reserve(numVolumeElements);
26constexpr static V3D X_AXIS{1, 0, 0};
27constexpr static V3D Y_AXIS{0, 1, 0};
28constexpr static V3D Z_AXIS{0, 0, 1};
32V3D createPerpendicular(
const V3D &symmetryAxis) {
33 const std::array<double, 3> scalars = {{
fabs(symmetryAxis.scalar_prod(X_AXIS)),
34 fabs(symmetryAxis.scalar_prod(Y_AXIS)),
35 fabs(symmetryAxis.scalar_prod(Z_AXIS))}};
39 else if (scalars[1] == 0.)
41 else if (scalars[2] == 0.)
45 if (scalars[0] < scalars[1] && scalars[0] < scalars[2])
47 else if (scalars[1] < scalars[0] && scalars[1] < scalars[2])
53const V3D CalculatePosInCylinder(
const double phi,
const double R,
const double z,
const std::array<V3D, 3> coords) {
54 const auto &x_prime = coords[0];
55 const auto &y_prime = coords[1];
56 const auto &z_prime = coords[2];
58 double rSinPhi = -R * sin(phi);
59 const double rCosPhi = -R * cos(phi);
62 const double xcomp = rCosPhi * x_prime[0] + rSinPhi * y_prime[0] +
z * z_prime[0];
63 const double ycomp = rCosPhi * x_prime[1] + rSinPhi * y_prime[1] +
z * z_prime[1];
64 const double zcomp = rCosPhi * x_prime[2] + rSinPhi * y_prime[2] +
z * z_prime[2];
65 return V3D(xcomp, ycomp, zcomp);
78Raster calculateGeneric(
const V3D &beamDirection,
const IObject &integShape,
const IObject &sampleShape,
79 const double cubeSizeInMetre) {
80 if (cubeSizeInMetre <= 0.)
81 throw std::runtime_error(
"Tried to section shape into zero size elements");
83 const auto integBbox = integShape.getBoundingBox();
84 assert(integBbox.xMax() > integBbox.xMin());
85 assert(integBbox.yMax() > integBbox.yMin());
86 assert(integBbox.zMax() > integBbox.zMin());
88 const double xLength = integBbox.xMax() - integBbox.xMin();
89 const double yLength = integBbox.yMax() - integBbox.yMin();
90 const double zLength = integBbox.zMax() - integBbox.zMin();
92 const auto numXSlices =
static_cast<size_t>(xLength / cubeSizeInMetre);
93 const auto numYSlices =
static_cast<size_t>(yLength / cubeSizeInMetre);
94 const auto numZSlices =
static_cast<size_t>(zLength / cubeSizeInMetre);
95 const double XSliceThickness = xLength /
static_cast<double>(numXSlices);
96 const double YSliceThickness = yLength /
static_cast<double>(numYSlices);
97 const double ZSliceThickness = zLength /
static_cast<double>(numZSlices);
98 const double elementVolume = XSliceThickness * YSliceThickness * ZSliceThickness;
100 const size_t numVolumeElements = numXSlices * numYSlices * numZSlices;
103 const auto sampleBbox = sampleShape.getBoundingBox();
104 assert(sampleBbox.xMax() > sampleBbox.xMin());
105 assert(sampleBbox.yMax() > sampleBbox.yMin());
106 assert(sampleBbox.zMax() > sampleBbox.zMin());
110 result.reserve(numVolumeElements);
114 throw std::logic_error(
"Too many volume elements requested - try increasing the value "
115 "of the ElementSize property.");
120 for (
size_t i = 0; i < numZSlices; ++i) {
121 const double z = (
static_cast<double>(i) + 0.5) * ZSliceThickness + integBbox.zMin();
123 for (
size_t j = 0; j < numYSlices; ++j) {
124 const double y = (
static_cast<double>(j) + 0.5) * YSliceThickness + integBbox.yMin();
126 for (
size_t k = 0; k < numXSlices; ++k) {
127 const double x = (
static_cast<double>(k) + 0.5) * XSliceThickness + integBbox.xMin();
129 const Kernel::V3D currentPosition = V3D(
x,
y,
z);
131 if (sampleShape.isValid(currentPosition)) {
133 Track incoming(currentPosition, -beamDirection);
139 if (sampleShape.interceptSurface(incoming) > 0) {
140 result.l1.emplace_back(incoming.totalDistInsideObject());
141 result.position.emplace_back(currentPosition);
142 result.volume.emplace_back(elementVolume);
150 result.totalvolume =
static_cast<double>(result.l1.size()) * elementVolume;
163 const double cubeSizeInMetre) {
164 const auto primitive = integShape.
shape();
165 if (hasCustomizedRaster(primitive)) {
168 const auto &shapeInfo = integShape.
shapeInfo();
171 const size_t numSlice = std::max<size_t>(1,
static_cast<size_t>(params.height / cubeSizeInMetre));
172 const size_t numAnnuli = std::max<size_t>(1,
static_cast<size_t>(params.radius / cubeSizeInMetre));
173 return calculateCylinder(beamDirection, integShape, sampleShape, numSlice, numAnnuli);
175 const auto params = shapeInfo.hollowCylinderGeometry();
176 const size_t numSlice = std::max<size_t>(1,
static_cast<size_t>(params.height / cubeSizeInMetre));
177 const size_t numAnnuli =
178 std::max<size_t>(1,
static_cast<size_t>((params.radius - params.innerRadius) / cubeSizeInMetre));
181 throw std::runtime_error(
"Rasterize::calculate should never get to this point");
184 return calculateGeneric(beamDirection, integShape, sampleShape, cubeSizeInMetre);
189 const size_t numSlices,
const size_t numAnnuli) {
191 throw std::invalid_argument(
"Given shape is not a cylinder.");
194 throw std::runtime_error(
"Tried to section cylinder into zero slices");
196 throw std::runtime_error(
"Tried to section cylinder into zero annuli");
199 const auto &shapeInfo = integShape.
shapeInfo();
203 const V3D center = (params.axis * .5 * params.height) + params.centreOfBottomBase;
205 const double sliceThickness{params.height /
static_cast<double>(numSlices)};
206 const double deltaR{params.radius /
static_cast<double>(numAnnuli)};
213 const size_t numVolumeElements = numSlices * numAnnuli * (numAnnuli + 1) * 3;
216 result.
reserve(numVolumeElements);
217 result.totalvolume = params.height * M_PI * params.radius * params.radius;
222 const V3D x_prime = createPerpendicular(z_prime);
224 const auto coords = std::array<V3D, 3>{{x_prime, y_prime, z_prime}};
228 for (
size_t i = 0; i < numSlices; ++i) {
229 const double z = (
static_cast<double>(i) + 0.5) * sliceThickness - 0.5 * params.height;
234 for (
size_t j = 0; j < numAnnuli; ++j) {
236 const double R = (
static_cast<double>(j) * params.radius /
static_cast<double>(numAnnuli)) + (0.5 * deltaR);
239 const double outerR = R + (deltaR / 2.0);
240 const double innerR = outerR - deltaR;
241 const double elementVolume =
242 M_PI * (outerR * outerR - innerR * innerR) * sliceThickness /
static_cast<double>(Ni);
245 for (
size_t k = 0; k < Ni; ++k) {
246 const double phi = 2. * M_PI *
static_cast<double>(k) /
static_cast<double>(Ni);
247 const auto position = center + CalculatePosInCylinder(phi, R,
z, coords);
254 result.position.emplace_back(
position);
255 result.volume.emplace_back(elementVolume);
266 const size_t numSlices,
const size_t numAnnuli) {
268 throw std::invalid_argument(
"Given shape is not a hollow cylinder.");
271 throw std::runtime_error(
"Tried to section cylinder into zero slices");
273 throw std::runtime_error(
"Tried to section cylinder into zero annuli");
276 const auto &shapeInfo = integShape.
shapeInfo();
280 const V3D center = (params.axis * .5 * params.height) + params.centreOfBottomBase;
282 const double sliceThickness{params.height /
static_cast<double>(numSlices)};
283 const double deltaR{(params.radius - params.innerRadius) /
static_cast<double>(numAnnuli)};
290 const size_t numVolumeElements = numSlices * numAnnuli * (numAnnuli + 1) * 3;
293 result.
reserve(numVolumeElements);
294 result.totalvolume = params.height * M_PI * (params.radius * params.radius - params.innerRadius * params.innerRadius);
298 V3D z_prime = params.axis;
300 const V3D x_prime = createPerpendicular(z_prime);
302 const auto coords = std::array<V3D, 3>{{x_prime, y_prime, z_prime}};
306 for (
size_t i = 0; i < numSlices; ++i) {
307 const double z = (
static_cast<double>(i) + 0.5) * sliceThickness - 0.5 * params.height;
317 const auto nSteps = params.innerRadius / deltaR;
318 size_t Ni =
static_cast<size_t>(nSteps) * 6;
320 for (
size_t j = 0; j < numAnnuli; ++j) {
324 (
static_cast<double>(j) * (params.radius - params.innerRadius) /
static_cast<double>(numAnnuli)) +
328 const double outerR = R + (deltaR / 2.0);
329 const double innerR = outerR - deltaR;
330 const double elementVolume =
331 M_PI * (outerR * outerR - innerR * innerR) * sliceThickness /
static_cast<double>(Ni);
334 for (
size_t k = 0; k < Ni; ++k) {
335 const double phi = 2. * M_PI *
static_cast<double>(k) /
static_cast<double>(Ni);
337 const auto position = center + CalculatePosInCylinder(phi, R,
z, coords);
345 result.position.emplace_back(
position);
346 result.volume.emplace_back(elementVolume);
IObject : Interface for geometry objects.
virtual int interceptSurface(Geometry::Track &) const =0
virtual const detail::ShapeInfo & shapeInfo() const =0
virtual detail::ShapeInfo::GeometryShape shape() const =0
virtual bool isValid(const Kernel::V3D &) const =0
Defines a track as a start point and a direction.
double totalDistInsideObject() const
Returns the sum of all the links distInsideObject in the track.
@ HOLLOWCYLINDER
HOLLOW CYLINDER.
CylinderGeometry cylinderGeometry() const
HollowCylinderGeometry hollowCylinderGeometry() const
double normalize()
Make a normalized vector (return norm value)
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
MANTID_GEOMETRY_DLL Raster calculateHollowCylinder(const Kernel::V3D &beamDirection, const IObject &integShape, const IObject &sampleShape, const size_t numSlices, const size_t numAnnuli)
MANTID_GEOMETRY_DLL Raster calculate(const Kernel::V3D &beamDirection, const IObject &integShape, const IObject &sampleShape, const double cubeSizeInMetre)
MANTID_GEOMETRY_DLL Raster calculateCylinder(const Kernel::V3D &beamDirection, const IObject &integShape, const IObject &sampleShape, const size_t numSlices, const size_t numAnnuli)
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Holds the information used for doing numerical integrations of object in the beam.
std::vector< double > volume
Cached element volumes.
std::vector< double > l1
Cached L1 distances.
void reserve(size_t numVolumeElements)
std::vector< Kernel::V3D > position
Cached element positions.