26using namespace Kernel;
28using namespace Geometry;
29using namespace DataObjects;
32 auto wsValidator = std::make_shared<CompositeValidator>();
37 "If not empty, a table workspace of that "
38 "name will contain the center of mass position.");
40 auto positiveInt = std::make_shared<BoundedValidator<int>>();
41 positiveInt->setLower(0);
42 declareProperty(
"NPixelX", 192, positiveInt,
"Number of detector pixels in the X direction.");
44 positiveInt->setLower(0);
45 declareProperty(
"NPixelY", 192, positiveInt,
"Number of detector pixels in the Y direction.");
48 "If true, a direct beam calculation will be performed. Otherwise, the "
50 "of the scattering data will be computed by excluding the beam area.");
52 auto positiveDouble = std::make_shared<BoundedValidator<double>>();
53 positiveDouble->setLower(0);
55 "Radius of the beam area, in pixels, used the exclude the "
56 "beam when calculating "
57 "the center of mass of the scattering pattern.");
72 int max_iteration = 200;
84 double xmax0 = n_pixel_x - 2.0;
86 double ymax0 = n_pixel_y - 2.0;
93 double center_x = n_pixel_x / 2.0;
94 double center_y = n_pixel_y / 2.0;
98 double distance_check = 0;
99 int n_local_minima = 0;
104 int n_monitors =
static_cast<int>(inputWS->getInstrument()->getMonitors().size());
105 const auto numSpec =
static_cast<int>(inputWS->getNumberHistograms());
109 while (distance > 0.25 || distance < 0) {
111 double total_count = 0;
112 double position_x = 0;
113 double position_y = 0;
115 const auto &spectrumInfo = inputWS->spectrumInfo();
116 for (
int i = 0; i < numSpec; i++) {
117 if (!spectrumInfo.hasDetectors(i)) {
118 g_log.
warning() <<
"Workspace index " << i <<
" has no detector assigned to it - discarding\n";
122 if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
126 const MantidVec &YIn = inputWS->readY(i);
127 auto y =
static_cast<double>((i - n_monitors) % n_pixel_x);
128 double x = floor(
static_cast<double>(i - n_monitors) / n_pixel_y);
130 if (
x >= xmin && x <= xmax && y >= ymin &&
y <= ymax) {
132 double dx =
x - center_x;
133 double dy =
y - center_y;
134 if (dx * dx + dy * dy < beam_radius * beam_radius)
137 position_x += YIn[specID] *
x;
138 position_y += YIn[specID] *
y;
139 total_count += YIn[specID];
144 position_x /= total_count;
145 position_y /= total_count;
149 sqrt((center_x - position_x) * (center_x - position_x) + (center_y - position_y) * (center_y - position_y));
154 double radius_x = std::min((position_x - xmin0), (xmax0 - position_x));
155 double radius_y = std::min((position_y - ymin0), (ymax0 - position_y));
157 if (!direct_beam && (radius_x <= beam_radius || radius_y <= beam_radius)) {
158 g_log.
error() <<
"Center of mass falls within the beam center area: "
163 center_x = position_x;
164 center_y = position_y;
166 xmin = center_x - radius_x;
167 xmax = center_x + radius_x;
168 ymin = center_y - radius_y;
169 ymax = center_y + radius_y;
172 if (distance == distance_check) {
179 if (n_local_minima > 5) {
180 g_log.
warning() <<
"Found the same or equivalent center of mass locations "
181 "more than 5 times in a row: stopping here\n";
186 if (++n_iteration > max_iteration) {
187 g_log.
warning() <<
"More than " << max_iteration <<
" iteration to find beam center: stopping here\n";
191 distance_check = distance;
201 if (!output.empty()) {
210 m_result->addColumn(
"str",
"Name");
211 m_result->addColumn(
"double",
"Value");
214 row <<
"X (m)" << center_x;
215 row = m_result->appendRow();
216 row <<
"Y (m)" << center_y;
223 std::vector<double> center_of_mass;
224 center_of_mass.emplace_back(center_x);
225 center_of_mass.emplace_back(center_y);
229 g_log.
information() <<
"Center of Mass found at x=" << center_x <<
" y=" << center_y <<
'\n';
#define DECLARE_ALGORITHM(classname)
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
Helper class for reporting progress from algorithms.
TableRow represents a row in a TableWorkspace.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
void init() override
Initialisation code.
void exec() override
Execution code.
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.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
@ Input
An input workspace.
@ Output
An output workspace.