Unverified Commit 8afa1cad authored by Jose Borreguero's avatar Jose Borreguero Committed by GitHub
Browse files

Merge pull request #30849 from mantidproject/30737_topaz_satellite_peaks_v3

TOPAZ: Problem with peak intensity assignment for satellite peaks
parents c35a74fe 5686ea06
......@@ -52,6 +52,7 @@ set(SRC_FILES
src/ImportMDHistoWorkspace.cpp
src/ImportMDHistoWorkspaceBase.cpp
src/Integrate3DEvents.cpp
src/IntegrateQLabEvents.cpp
src/IntegrateEllipsoids.cpp
src/IntegrateEllipsoidsTwoStep.cpp
src/IntegrateFlux.cpp
......@@ -165,6 +166,7 @@ set(
inc/MantidMDAlgorithms/ImportMDHistoWorkspace.h
inc/MantidMDAlgorithms/ImportMDHistoWorkspaceBase.h
inc/MantidMDAlgorithms/Integrate3DEvents.h
inc/MantidMDAlgorithms/IntegrateQLabEvents.h
inc/MantidMDAlgorithms/IntegrateEllipsoids.h
inc/MantidMDAlgorithms/IntegrateEllipsoidsTwoStep.h
inc/MantidMDAlgorithms/IntegrateFlux.h
......@@ -275,6 +277,7 @@ set(TEST_FILES
ImportMDEventWorkspaceTest.h
ImportMDHistoWorkspaceTest.h
Integrate3DEventsTest.h
IntegrateQLabEventsTest.h
IntegrateEllipsoidsTest.h
IntegrateEllipsoidsTwoStepTest.h
IntegrateEllipsoidsWithSatellitesTest.h
......
......@@ -11,7 +11,7 @@
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidDataObjects/PeaksWorkspace.h"
#include "MantidDataObjects/Workspace2D.h"
#include "MantidMDAlgorithms/Integrate3DEvents.h"
#include "MantidMDAlgorithms/IntegrateQLabEvents.h"
#include "MantidMDAlgorithms/MDTransfInterface.h"
#include "MantidMDAlgorithms/MDWSDescription.h"
#include "MantidMDAlgorithms/UnitsConversionHelper.h"
......@@ -24,30 +24,43 @@ namespace MDAlgorithms {
class DLLExport IntegrateEllipsoids : public API::Algorithm {
public:
const std::string name() const override;
/// Summary of algorithms purpose
const std::string name() const override { return "IntegrateEllipsoids"; }
const std::string summary() const override {
return "Integrate Single Crystal Diffraction Bragg peaks using 3D "
"ellipsoids.";
}
int version() const override;
int version() const override { return 1; }
const std::vector<std::string> seeAlso() const override {
return {"IntegrateEllipsoidsTwoStep"};
}
const std::string category() const override;
const std::string category() const override { return "Crystal\\Integration"; }
private:
using PrincipleAxes = std::array<std::vector<double>, 3>;
/// Initialize the algorithm's properties
void init() override;
/// Execute the algorithm
void exec() override;
void qListFromEventWS(Integrate3DEvents &integrator, API::Progress &prog,
DataObjects::EventWorkspace_sptr &wksp,
Kernel::DblMatrix const &UBinv, bool hkl_integ);
void qListFromHistoWS(Integrate3DEvents &integrator, API::Progress &prog,
DataObjects::Workspace2D_sptr &wksp,
Kernel::DblMatrix const &UBinv, bool hkl_integ);
/**
* @brief create a list of SlimEvent objects from an events workspace
* @param integrator : integrator object on the list is accumulated
* @param prog : progress object
* @param wksp : input EventWorkspace
*/
void qListFromEventWS(IntegrateQLabEvents &integrator, API::Progress &prog,
DataObjects::EventWorkspace_sptr &wksp);
/**
* @brief create a list of SlimEvent objects from a histogram workspace
* @param integrator : integrator object on which the list is accumulated
* @param prog : progress object
* @param wksp : input Workspace2D
*/
void qListFromHistoWS(IntegrateQLabEvents &integrator, API::Progress &prog,
DataObjects::Workspace2D_sptr &wksp);
/// Calculate if this Q is on a detector
void calculateE1(const Geometry::DetectorInfo &detectorInfo);
......@@ -60,6 +73,10 @@ private:
MDWSDescription m_targWSDescr;
/**
* @brief Initialize the output information for the MD conversion framework.
* @param wksp : The workspace to get information from.
*/
void initTargetWSDescr(API::MatrixWorkspace_sptr &wksp);
};
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2012 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#pragma once
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidDataObjects/Peak.h"
#include "MantidDataObjects/PeakShapeEllipsoid.h"
#include "MantidKernel/Matrix.h"
#include "MantidKernel/V3D.h"
#include <memory>
#include <tuple>
#include <unordered_map>
#include <vector>
namespace Mantid {
namespace Geometry {
class PeakShape;
}
namespace MDAlgorithms {
using Mantid::DataObjects::PeakShapeEllipsoid_const_sptr;
using Mantid::Geometry::PeakShape_const_sptr;
using Mantid::Kernel::V3D;
/// Partition QLab space into a cubic lattice
struct CellCoords {
int64_t a;
int64_t b;
int64_t c;
CellCoords(const V3D &q, const double cellSize)
: a(static_cast<int64_t>(q[0] / cellSize)),
b(static_cast<int64_t>(q[1] / cellSize)),
c(static_cast<int64_t>(q[2] / cellSize)) {}
/// Check if all cell coords are zero
bool isOrigin() { return !(a || b || c); }
/// cast coordinates to scalar, to be used as key in an unordered map
int64_t getHash() { return 1000000000000 * a + 100000000 * b + 10000 * c; }
/// Hashes for the 26 first neighbor coordinates plus the coordinates
/// themselves
std::vector<int64_t> nearbyCellHashes() {
std::vector<int64_t> neighbors;
for (int64_t ia = a - 1; ia <= a + 1; ia++)
for (int64_t ib = b - 1; ib <= b + 1; ib++)
for (int64_t ic = c - 1; ic <= c + 1; ic++) {
int64_t key = 1000000000000 * ia + 100000000 * ib + 10000 * ic;
neighbors.emplace_back(key);
}
return neighbors;
}
};
// [(weight, error), Q-vector], trimmed-down info for an event
using SlimEvent = std::pair<std::pair<double, double>, V3D>;
using SlimEvents = std::vector<SlimEvent>;
// A cell in partitioned QLab space containing one peak
struct OccupiedCell {
size_t peakIndex; // index of the peak within this cell
V3D peakQ; // QLab vector of the peak within this cell
SlimEvents events; // events potentially closer than m_radius to the peak
};
/**
@class IntegrateQLabEvents
This is a low-level class to construct a map with lists of events near
each peak Q-vector in the lab frame. The Q-vector of each event is shifted
by the Q-vector of the associated peak.
A method is also provided to find the principal axes of such a list
of events and to find the net integrated counts using ellipsoids
with axis lengths determined from the standard deviations in the
directions of the principal axes.
@author Dennis Mikkelson
@date 2012-12-19
*/
class DLLExport IntegrateQLabEvents {
public:
/**
* @brief Store events within a certain radius of the specified peak centers,
* and sum these events to estimate pixel intensities.
* @param peak_q_list : List of Q-vectors for peak centers.
* @param radius : The maximum distance from a peak's Q-vector, for an
* event to be stored in the list associated with that peak.
* @param useOnePercentBackgroundCorrection : flag if one percent background
* correction should be used. */
IntegrateQLabEvents(const SlimEvents &peak_q_list, double radius,
const bool useOnePercentBackgroundCorrection = true);
/// Determine if an input Q-vector lies in the cell associated to the origin
static bool isOrigin(const V3D &q, const double &cellSize);
/**
* @brief distribute the events among the cells of the partitioned QLab
* space.
* @details Given QLab partitioned into a cubic lattice with unit cell of
* certain size, assign each event to one particular cell depending on its
* QLab vector.
* @param event_qs : List of SlimEvent objects to be distributed */
void addEvents(SlimEvents const &event_qs);
/**
* @brief Integrate the events around the specified peak QLab vector.
* @details The principal axes of the events near this Q-vector
* and the standard deviations in the directions of these principal
* axes determine ellipsoidal regions for integrating the peak and
* estimating the background. Alternatively, if peak and background
* radii are specified, then those will be used for half the major
* axis length of the ellipsoids, and the other axes of the ellipsoids
* will be set proportionally, based on the standard deviations.
* @param E1Vec : Vector of values for calculating edge of detectors
* @param peak_q : The QLab-vector for the peak center.
* @param specify_size : If true the integration will be done using the
* ellipsoids with major axes determined by the peak, back_inner
* and back_outer radii parameters. If false, the integration will be
* done using a peak region with major axis chosen so that it
* covers +- three standard deviations of the data in each direction. In
* this case, the background ellipsoidal shell is chosen to have the
* same VOLUME as the peak ellipsoid, and to use the peak ellipsoid
* for the inner radius.
* @param peak_radius : Size of half the major axis of the ellipsoidal
* peak region.
* @param back_inner_radius : Size of half the major axis of the INNER
* ellipsoidal boundary of the background region
* @param back_outer_radius : Size of half the major axis of the OUTER
* ellipsoidal boundary of the background region
* @param axes_radii : The radii used for integration in the directions
* of the three principal axes.
* @param inti : (output) collects the net integrated intensity
* @param sigi : (output) collects an estimate of the standard deviation
* of the net integrated intensity */
PeakShape_const_sptr ellipseIntegrateEvents(
const std::vector<V3D> &E1Vec, V3D const &peak_q, bool specify_size,
double peak_radius, double back_inner_radius, double back_outer_radius,
std::vector<double> &axes_radii, double &inti, double &sigi);
/**
* @brief Assign events to each of the cells occupied by events.
* @details Iterate over each QLab cell containing a peak and accumulate the
* list of events for the cell and for the first-neighbor cells into a
* single list of events. The QLab vectors for this events are shifted
* by the QLab vector of the peak. */
void populateCellsWithPeaks();
private:
/**
* @brief Number of events in an ellipsoid.
* @details The ellipsoid is centered at 0,0,0 with the three specified
* axes and the three specified sizes in the direction of those axes.
* NOTE: The three axes must be mutually orthogonal unit vectors.
* @param events : List of SlimEvents centered at 0,0,0
* @param directions : List of 3 orthonormal directions for the axes of
* the ellipsoid.
* @param sizes : List of three values a,b,c giving half the length
* of the three axes of the ellisoid.
* @return number of events and estimated error */
static std::pair<double, double>
numInEllipsoid(SlimEvents const &events, std::vector<V3D> const &directions,
std::vector<double> const &sizes);
/**
* @brief Number of events in an ellipsoid with background correction.
* @details The ellipsoid is centered at 0,0,0 with the three specified
* axes and the three specified sizes in the direction of those axes.
* NOTE: The three axes must be mutually orthogonal unit vectors.
* @param events : List of 3D events centered at 0,0,0
* @param directions : List of 3 orthonormal directions for the axes of
* the ellipsoid.
* @param sizes : List of three values a,b,c giving half the length
* of the three axes of the ellisoid.
* @param sizesIn : List of three values a,b,c giving half the length
* of the three inner axes of the ellisoid.
* @param useOnePercentBackgroundCorrection : flag if one percent background
* correction should be used.
* @return number of events and estimated error */
static std::pair<double, double> numInEllipsoidBkg(
SlimEvents const &events, std::vector<V3D> const &directions,
std::vector<double> const &sizes, std::vector<double> const &sizesIn,
const bool useOnePercentBackgroundCorrection);
/**
* @brief 3x3 covariance matrix of a list of SlimEvent objects
* @details the purpose of the covariance matrix is to find the principal axes
* of the SlimeEvents, associated with a particular peak. Their QLab vectors
* are already shifted by the QLab vector of the peak. Only events within
* the specified distance from the peak (here at Q=[0,0,0]) will be used.
* The covariance matrix can be easily constructed. X, Y, Z of each peak
* position are the variables we wish to determine the covariance. The mean
* position in each dimension has already been calculated on subtracted,
* since this corresponds to the QLab vector peak. The expected values
* of each correlation test X,X X,Y X,Z e.t.c form the elements of this
* 3x3 matrix, but since the probabilities are equal, we can remove them
* from the sums of the expected values, and simply divide by the number
* of events for each matrix element. Note that the diagonal elements
* form the variance X,X, Y,Y, Z,Z
* @param events : SlimEvents associated to one peak
* @param matrix : (output) 3x3 covariance matrix
* @param radius : Only events within this distance radius of the
* peak (here at Q=[0,0,0]) are used for calculating the covariance matrix.*/
static void makeCovarianceMatrix(SlimEvents const &events,
Kernel::DblMatrix &matrix, double radius);
/**
* @brief Eigen vectors of a 3x3 real symmetric matrix using the GSL.
* @param cov_matrix : 3x3 real symmetric matrix.
* @param eigen_vectors : (output) returned eigen vectors
* @param eigen_values : (output) three eigenvalues
*/
static void getEigenVectors(Kernel::DblMatrix const &cov_matrix,
std::vector<V3D> &eigen_vectors,
std::vector<double> &eigen_values);
/**
* @brief assign an event to one cell of the partitioned QLab space.
* @param event : SlimEvent to be assigned */
void addEvent(const SlimEvent event);
/**
* @brief Integrate a list of events associated to one peak.
* @details The QLab vector of the events are shifted by the QLab vector
* of the peak. Spatial distribution of the events in QLab space is
* described with principal axes of the ellipsoid, as well as the
* standard deviations in the the directions of the principal axes.
* @param E1Vec : Vector of values for calculating edge of detectors
* @param peak_q : The Q-vector for the peak center.
* @param ev_list : List of events centered around the peak (here with
* Q=[0,0,0]).
* @param directions : The three principal axes of the list of events
* @param sigmas : The standard deviations of the events in the
* directions of the three principal axes.
* @param specify_size : If true the integration will be done using the
* ellipsoids with major axes determined by the peak, back_inner and
* back_outer radii parameters. If false, the integration will be done
* using a peak region with major axis chosen so that it covers +- three
* standard deviations of the data in each direction. In this case, the
* background ellipsoidal shell is chosen to have the same VOLUME as the
* peak ellipsoid, and to use the peak ellipsoid for the inner radius.
* @param peak_radius : Size of half the major axis of the ellipsoid
* @param back_inner_radius : Size of half the major axis of the INNER
* ellipsoidal boundary of the background region
* @param back_outer_radius : Size of half the major axis of the OUTER
* ellipsoidal boundary of the background region
* @param axes_radii : The radii used for integration in the directions
* of the three principal axes.
* @param inti : (output) net integrated intensity
* @param sigi : (output) estimate of the standard deviation the intensity */
PeakShapeEllipsoid_const_sptr ellipseIntegrateEvents(
const std::vector<V3D> &E1Vec, V3D const &peak_q,
SlimEvents const &ev_list, std::vector<V3D> const &directions,
std::vector<double> const &sigmas, bool specify_size, double peak_radius,
double back_inner_radius, double back_outer_radius,
std::vector<double> &axes_radii, double &inti, double &sigi);
/**
* @brief Calculate if this Q is on a detector
* @details The distance from C to OE is given by dv=C-E*(C.scalar_prod(E))
* If dv.norm<integration_radius, one of the detector trajectories on the
* edge is too close to the peak. This method is applied to all masked
* pixels. If there are masked pixels trajectories inside an integration
* volume, the peak must be rejected.
* @param E1Vec : Vector of values for calculating edge of detectors
* @param QLabFrame: The Peak center.
* @param r: Peak radius.
*/
double detectorQ(const std::vector<V3D> &E1Vec, const V3D QLabFrame,
const std::vector<double> &r);
// Private data members
double m_radius; // size of sphere to use for events around a peak
/// if one percent culling of the background should be performed.
const bool m_useOnePercentBackgroundCorrection;
/// size of the square cell unit, holding at most one single peak
double m_cellSize;
/// list the occupied cells in an unordered map for fast searching
std::unordered_map<size_t, OccupiedCell> m_cellsWithPeaks;
/// list of cells occupied with events
std::unordered_map<size_t, SlimEvents> m_cellsWithEvents;
};
} // namespace MDAlgorithms
} // namespace Mantid
......@@ -24,12 +24,11 @@
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/CompositeValidator.h"
#include "MantidKernel/Statistics.h"
#include "MantidMDAlgorithms/Integrate3DEvents.h"
#include "MantidMDAlgorithms/IntegrateQLabEvents.h"
#include "MantidMDAlgorithms/MDTransfFactory.h"
#include "MantidMDAlgorithms/MDTransfQ3D.h"
#include "MantidMDAlgorithms/UnitsConversionHelper.h"
#include <boost/math/special_functions/round.hpp>
#include <cmath>
using namespace Mantid::API;
......@@ -41,6 +40,9 @@ using namespace Mantid::DataObjects;
namespace Mantid {
namespace MDAlgorithms {
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(IntegrateEllipsoids)
/// This only works for diffraction.
const std::string ELASTIC("Elastic");
......@@ -50,21 +52,9 @@ const std::string Q3D("Q3D");
/// Q-vector is always three dimensional.
const std::size_t DIMS(3);
/**
* @brief qListFromEventWS creates qlist from events
* @param integrator : itegrator object on which qlists are accumulated
* @param prog : progress object
* @param wksp : input EventWorkspace
* @param UBinv : inverse of UB matrix
* @param hkl_integ ; boolean for integrating in HKL space
*/
void IntegrateEllipsoids::qListFromEventWS(Integrate3DEvents &integrator,
void IntegrateEllipsoids::qListFromEventWS(IntegrateQLabEvents &integrator,
Progress &prog,
EventWorkspace_sptr &wksp,
DblMatrix const &UBinv,
bool hkl_integ) {
// loop through the eventlists
EventWorkspace_sptr &wksp) {
auto numSpectra = static_cast<int>(wksp->getNumberHistograms());
PARALLEL_FOR_IF(Kernel::threadSafe(*wksp))
for (int i = 0; i < numSpectra; ++i) {
......@@ -109,37 +99,22 @@ void IntegrateEllipsoids::qListFromEventWS(Integrate3DEvents &integrator,
buffer[dim] = locCoord[dim];
}
V3D qVec(buffer[0], buffer[1], buffer[2]);
if (hkl_integ)
qVec = UBinv * qVec;
qList.emplace_back(std::pair<double, double>(raw_event.m_weight,
raw_event.m_errorSquared),
qVec);
} // end of loop over events in list
PARALLEL_CRITICAL(addEvents) { integrator.addEvents(qList, hkl_integ); }
PARALLEL_CRITICAL(addEvents) { integrator.addEvents(qList); }
prog.report();
PARALLEL_END_INTERUPT_REGION
} // end of loop over spectra
PARALLEL_CHECK_INTERUPT_REGION
integrator.populateCellsWithPeaks();
}
/**
* @brief qListFromHistoWS creates qlist from input workspaces of type
* Workspace2D
* @param integrator : itegrator object on which qlists are accumulated
* @param prog : progress object
* @param wksp : input Workspace2D
* @param UBinv : inverse of UB matrix
* @param hkl_integ ; boolean for integrating in HKL space
*/
void IntegrateEllipsoids::qListFromHistoWS(Integrate3DEvents &integrator,
void IntegrateEllipsoids::qListFromHistoWS(IntegrateQLabEvents &integrator,
Progress &prog,
Workspace2D_sptr &wksp,
DblMatrix const &UBinv,
bool hkl_integ) {
// loop through the eventlists
Workspace2D_sptr &wksp) {
auto numSpectra = static_cast<int>(wksp->getNumberHistograms());
PARALLEL_FOR_IF(Kernel::threadSafe(*wksp))
for (int i = 0; i < numSpectra; ++i) {
......@@ -168,8 +143,7 @@ void IntegrateEllipsoids::qListFromHistoWS(Integrate3DEvents &integrator,
double signal(1.); // ignorable garbage
double errorSq(1.); // ignorable garbage
std::vector<std::pair<std::pair<double, double>, V3D>> qList;
SlimEvents qList;
for (size_t j = 0; j < yVals.size(); ++j) {
const double &yVal = yVals[j];
const double &esqVal = eVals[j] * eVals[j]; // error squared (variance)
......@@ -183,9 +157,6 @@ void IntegrateEllipsoids::qListFromHistoWS(Integrate3DEvents &integrator,
// qVec
}
V3D qVec(buffer[0], buffer[1], buffer[2]);
if (hkl_integ)
qVec = UBinv * qVec;
if (std::isnan(qVec[0]) || std::isnan(qVec[1]) || std::isnan(qVec[2]))
continue;
// Account for counts in histograms by increasing the qList with the
......@@ -193,38 +164,14 @@ void IntegrateEllipsoids::qListFromHistoWS(Integrate3DEvents &integrator,
qList.emplace_back(std::pair<double, double>(yVal, esqVal), qVec);
}
}
PARALLEL_CRITICAL(addHisto) { integrator.addEvents(qList, hkl_integ); }
PARALLEL_CRITICAL(addHisto) { integrator.addEvents(qList); }
prog.report();
PARALLEL_END_INTERUPT_REGION
} // end of loop over spectra
PARALLEL_CHECK_INTERUPT_REGION
integrator.populateCellsWithPeaks();
}
/** NOTE: This has been adapted from the SaveIsawQvector algorithm.
*/
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(IntegrateEllipsoids)
//---------------------------------------------------------------------
/// Algorithm's name for identification. @see Algorithm::name
const std::string IntegrateEllipsoids::name() const {
return "IntegrateEllipsoids";
}
/// Algorithm's version for identification. @see Algorithm::version
int IntegrateEllipsoids::version() const { return 1; }
/// Algorithm's category for identification. @see Algorithm::category
const std::string IntegrateEllipsoids::category() const {
return "Crystal\\Integration";
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void IntegrateEllipsoids::init() {
auto ws_valid = std::make_shared<CompositeValidator>();
ws_valid->add<WorkspaceUnitValidator>("TOF");
......@@ -279,9 +226,6 @@ void IntegrateEllipsoids::init() {
"Number of sigmas to add to mean of half-length of "
"major radius for second pass when SpecifySize is false.");
declareProperty("IntegrateInHKL", false,
"If true, integrate in HKL space not Q space.");
declareProperty(
"IntegrateIfOnEdge", true,
"Set to false to not integrate if peak radius is off edge of detector."
......@@ -301,29 +245,8 @@ void IntegrateEllipsoids::init() {
"If this options is enabled, then the the top 1% of the "
"background will be removed"
"before the background subtraction.");
declareProperty("SatelliteRegionRadius", .1, mustBePositive,
"Only events at most this distance from a peak will be "
"considered when integrating");
declareProperty("SatellitePeakSize", .08, mustBePositive,
"Half-length of major axis for satellite peak ellipsoid");
declareProperty("SatelliteBackgroundInnerSize", .08, mustBePositive,
"Half-length of major axis for inner ellipsoidal surface of "
"satellite background region");
declareProperty("SatelliteBackgroundOuterSize", .09, mustBePositive,
"Half-length of major axis for outer ellipsoidal surface of "
"satellite background region");
declareProperty("GetUBFromPeaksWorkspace", false,
"If true, UB is taken from peak workspace.");
}
//---------------------------------------------------------------------
/** Execute the algorithm.
*/
void IntegrateEllipsoids::exec() {
// get the input workspace
MatrixWorkspace_sptr wksp = getProperty("InputWorkspace");
......@@ -347,30 +270,18 @@ void IntegrateEllipsoids::exec() {
}
double radius_m = getProperty("RegionRadius");
double radius_s = getProperty("SatelliteRegionRadius");
int numSigmas = getProperty("NumSigmas");
double cutoffIsigI = getProperty("CutoffIsigI");
bool specify_size = getProperty("SpecifySize");
double peak_radius = getProperty("PeakSize");
double sate_peak_radius = getProperty("SatellitePeakSize");
double back_inner_radius = getProperty("BackgroundInnerSize");
double sate_back_inner_radius = getProperty("SatelliteBackgroundInnerSize");
double back_outer_radius = getProperty("BackgroundOuterSize");
double sate_back_outer_radius = getProperty("SatelliteBackgroundOuterSize");
bool hkl_integ = getProperty("IntegrateInHKL");
bool integrateEdge = getProperty("IntegrateIfOnEdge");
bool adaptiveQBackground = getProperty("AdaptiveQBackground");
double adaptiveQMultiplier = getProperty