Mantid
Loading...
Searching...
No Matches
FindCenterOfMassPosition2.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 +
10#include "MantidAPI/TableRow.h"
23namespace Mantid::Algorithms {
24
25// Register the algorithm into the AlgorithmFactory
26DECLARE_ALGORITHM(FindCenterOfMassPosition2)
27
28using namespace Kernel;
29using namespace API;
30using namespace Geometry;
31using namespace DataObjects;
32
34 const auto wsValidator = std::make_shared<CompositeValidator>();
35 const auto positiveDouble = std::make_shared<BoundedValidator<double>>();
36
37 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input, wsValidator));
38 declareProperty("Output", "",
39 "TableWorkspace will contain the center of mass position. "
40 "When empty, a CenterOfMass output parameter with two elements (x,y) is created.");
41
42 declareProperty("CenterX", 0.0, "Initial estimate for the beam center in X in meters");
43 declareProperty("CenterY", 0.0, "Initial estimate for the beam center in Y in meters");
44 declareProperty("Tolerance", 0.00125,
45 "Tolerance on the center of mass position between each iteration in meters. "
46 "Suggested value is the size of a quarter of a pixel.");
47
48 declareProperty("DirectBeam", true,
49 "When true, the calculation will include the pixels within BeamRadius from the beam center. "
50 "Since the process is iterative, the pixels masked by DirectBeam=False will move.");
51
52 positiveDouble->setLower(0);
53 declareProperty("BeamRadius", 0.0155, positiveDouble,
54 "Radius of the direct beam area, in meters, used the exclude the beam when calculating "
55 "the center of mass of the scattering pattern. "
56 "This is ignored when DirectBeam=True");
57 declareProperty("IntegrationRadius", EMPTY_DBL(), positiveDouble,
58 "Integration radius, in meters, used to include when calculating "
59 "the center of mass of the scattering pattern.");
60}
61
71 double &centerY, Progress &progress) {
72 const double tolerance = getProperty("Tolerance");
73 const bool includeDirectBeam = getProperty("DirectBeam");
74 const double beamRadius = getProperty("BeamRadius");
75 // when the integration radius isn't set, put the integration radius to 100m which is effectively infinity
76 const double integrationRadius = isDefault("IntegrationRadius") ? 100. : getProperty("IntegrationRadius");
77
78 // Define box around center of mass so that only pixels in an area
79 // _centered_ on the latest center position are considered. At each
80 // iteration we will recompute the bounding box, and we will make
81 // it as large as possible. The largest box is defined in:
82 WorkspaceBoundingBox boundingBox(inputWS, integrationRadius, beamRadius, !includeDirectBeam, centerX, centerY);
83
84 // Initialize book-keeping
85 // distance between previous and current beam center
86 double distanceFromPrevious = std::numeric_limits<double>::max();
87 // previous distance between previous and current beam center
88 double distanceFromPreviousPrevious = std::numeric_limits<double>::max();
89
90 int totalLocalMinima = 0;
91 int totalIterations = 0;
92 constexpr int LOCAL_MINIMA_MAX{5};
93
94 // Find center of mass and iterate until we converge
95 // to within the tolerance specified in meters
96 while (distanceFromPrevious > tolerance) {
97 // Normalize output to find center of mass position
98 // Compute the distance to the previous iteration
99 distanceFromPrevious = boundingBox.distanceFromPrevious();
100
101 // skip out early if the center found is within the ignore region
102 if (boundingBox.centerOfMassWithinBeamCenter()) {
103 g_log.error("Center of mass falls within the beam center area: stopping here");
104 break;
105 }
106
107 // Recenter around new mass position
108 boundingBox.prepareCenterCalculation();
109
110 // Check to see if we have the same result
111 // as the previous iteration
112 if (Kernel::equals(distanceFromPrevious, distanceFromPreviousPrevious)) {
113 totalLocalMinima++;
114 } else {
115 totalLocalMinima = 0;
116 }
117
118 // Quit if we found the exact same distance five times in a row.
119 if (totalLocalMinima > LOCAL_MINIMA_MAX) {
120 g_log.warning() << "Found the same or equivalent center of mass locations more than " << LOCAL_MINIMA_MAX
121 << " times in a row: stopping here\n";
122 break;
123 }
124
125 // Quit if we haven't converged after the maximum number of iterations.
126 if (++totalIterations > m_maxIteration) {
127 g_log.warning() << "More than " << m_maxIteration << " iteration to find beam center: stopping here\n";
128 break;
129 }
130
131 distanceFromPreviousPrevious = distanceFromPrevious;
132
133 // Count histogram for normalization
134 boundingBox.findNewCenterPosition();
135
136 progress.report("Find Beam Center");
137 }
138
139 // get the final result
140 centerX = boundingBox.getCenterX();
141 centerY = boundingBox.getCenterY();
142}
143
150void FindCenterOfMassPosition2::storeOutputWorkspace(double centerX, double centerY) {
151 std::string output = getProperty("Output");
152
153 // If an output workspace name was given, create a TableWorkspace with the
154 // results,
155 // otherwise use an ArrayProperty
156 if (!output.empty()) {
157 // Store the result in a table workspace
159 std::make_unique<WorkspaceProperty<API::ITableWorkspace>>("OutputWorkspace", "", Direction::Output));
160
161 // Set the name of the new workspace
162 setPropertyValue("OutputWorkspace", output);
163
164 Mantid::API::ITableWorkspace_sptr m_result = std::make_shared<TableWorkspace>();
165 m_result->addColumn("str", "Name");
166 m_result->addColumn("double", "Value");
167
168 Mantid::API::TableRow row = m_result->appendRow();
169 row << "X (m)" << centerX;
170 row = m_result->appendRow();
171 row << "Y (m)" << centerY;
172
173 setProperty("OutputWorkspace", m_result);
174 } else {
175 // Store the results using an ArrayProperty
176 if (!existsProperty("CenterOfMass"))
177 declareProperty(std::make_unique<ArrayProperty<double>>("CenterOfMass", std::make_shared<NullValidator>(),
179 std::vector<double> center_of_mass;
180 center_of_mass.emplace_back(centerX);
181 center_of_mass.emplace_back(centerY);
182 setProperty("CenterOfMass", center_of_mass);
183 }
184
185 g_log.information() << "Center of Mass found at x=" << centerX << " y=" << centerY << '\n';
186}
187
189 const MatrixWorkspace_sptr inputWSWvl = getProperty("InputWorkspace");
190 double centerX = getProperty("CenterX");
191 double centerY = getProperty("CenterY");
192
193 MatrixWorkspace_sptr inputWS;
194
195 // Sum up all the wavelength bins
196 IAlgorithm_sptr childAlg = createChildAlgorithm("Integration", 0., 0.5); // first half is integrating
197 childAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputWSWvl);
198 childAlg->executeAsChildAlg();
199 inputWS = childAlg->getProperty("OutputWorkspace");
200
201 // Set up the progress reporting object
202 Progress progress(this, 0.5, 1.0, m_maxIteration);
203
204 findCenterOfMass(inputWS, centerX, centerY, progress);
205 storeOutputWorkspace(centerX, centerY);
206}
207
208} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double tolerance
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
bool existsProperty(const std::string &name) const override
Checks whether the named property is already in the list of managed property.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual 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)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
bool isDefault(const std::string &name) const
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
void findCenterOfMass(const API::MatrixWorkspace_sptr &inputWS, double &centerX, double &centerY, API::Progress &progress)
Helper functions.
void storeOutputWorkspace(double centerX, double centerY)
Package the algorithm outputs one of two ways depending on whether or not it was given an input Event...
bool centerOfMassWithinBeamCenter()
This only has effect if the integral is ignoring the beam center as a whole.
void prepareCenterCalculation()
Copy the current center to the previous and update the x/y range for overall integration.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
MANTID_KERNEL_DLL bool equals(T const x, T const y)
Test for equality of doubles using compiler-defined precision.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54