54 "An input workspace (MatrixWorkspace, MDEventWorkspace, or "
55 "PeaksWorkspace) containing:\n"
56 " - The relevant Instrument (calibrated as needed).\n"
57 " - A sample with a UB matrix.\n"
58 " - The goniometer rotation matrix.");
61 "Minimum wavelength limit at which to start looking for single-crystal "
64 "Maximum wavelength limit at which to stop looking for single-crystal "
68 "Minimum d-spacing of peaks to consider. Default = 1.0");
70 "Maximum d-spacing of peaks to consider.");
73 "This will calculate the goniometer rotation (around y-axis "
74 "only) for a constant wavelength.");
76 auto nonNegativeDbl = std::make_shared<BoundedValidator<double>>();
77 nonNegativeDbl->setLower(0);
78 declareProperty(
"Wavelength", DBL_MAX, nonNegativeDbl,
"Wavelength to use when calculating goniometer angle");
82 "Whether the goniometer to be calculated is the most inner "
83 "(phi) or most outer (omega)");
85 std::make_unique<EnabledWhenProperty>(
"CalculateGoniometerForCW",
89 "Used when calculating goniometer angle if the q_lab x value "
90 "should be negative, hence the detector of the other side "
91 "(right) of the beam");
96 "Minimum goniometer rotation angle");
100 "Maximum goniometer rotation angle");
104 std::vector<std::string> propOptions;
107 [](
const auto &condition) { return condition->getName(); });
108 declareProperty(
"ReflectionCondition",
"Primitive", std::make_shared<StringListValidator>(propOptions),
109 "Which reflection condition applies to this crystal, "
110 "reducing the number of expected HKL peaks?");
113 "Calculate structure factors for the predicted peaks. This "
114 "option only works if the sample of the input workspace has "
115 "a crystal structure assigned.");
119 "Optional: An input PeaksWorkspace with the HKL of the peaks "
120 "that we should predict. \n"
121 "The WavelengthMin/Max and Min/MaxDSpacing parameters are "
122 "unused if this is specified.");
125 "When using HKLPeaksWorkspace, this will round the HKL "
126 "values in the HKLPeaksWorkspace to the nearest integers if "
128 "Keep unchecked to use the original values");
134 std::unique_ptr<IPropertySettings> set = std::make_unique<EnabledWhenProperty>(
"HKLPeaksWorkspace",
IS_DEFAULT);
143 std::vector<std::string> peakTypes = {
"Peak",
"LeanElasticPeak"};
144 declareProperty(
"OutputType",
"Peak", std::make_shared<StringListValidator>(peakTypes),
145 "Type of Peak in OutputWorkspace");
147 "CalculateWavelength",
true,
148 "When OutputType is LeanElasticPeak you can choose to calculate the wavelength of the peak using the instrument "
149 "and check it is in the valid range or alternatively just accept every peak while not setting the goniometer "
150 "(Q-lab will be incorrect).");
154 "An output PeaksWorkspace.");
157 "Use an extended detector space (if defined for the"
158 " instrument) to predict peaks which do not fall onto any"
159 "detector. This may produce a very high number of results.");
161 auto nonNegativeInt = std::make_shared<BoundedValidator<int>>();
162 nonNegativeInt->setLower(0);
163 declareProperty(
"EdgePixels", 0, nonNegativeInt,
"Remove peaks that are at pixels this close to edge. ");
175 ExperimentInfo_sptr inputExperimentInfo = std::dynamic_pointer_cast<ExperimentInfo>(rawInputWorkspace);
178 PeaksWorkspace_sptr peaksWS = std::dynamic_pointer_cast<PeaksWorkspace>(rawInputWorkspace);
181 std::vector<DblMatrix> gonioVec;
182 std::string goniometerConvension;
186 auto goniometerMatrix = matrixWS->run().getGoniometerMatrices();
187 std::move(goniometerMatrix.begin(), goniometerMatrix.end(), back_inserter(gonioVec));
188 }
catch (std::runtime_error &e) {
190 g_log.
error() <<
"Error getting the goniometer rotation matrix from the "
193 g_log.
warning() <<
"Using identity goniometer rotation matrix instead.\n";
196 goniometerConvension = matrixWS->run().getGoniometer().getConventionFromMotorAxes();
197 }
else if (peaksWS) {
200 std::vector<std::pair<std::string, bool>> criteria;
201 criteria.emplace_back(
"RunNumber",
true);
203 peaksWS->sort(criteria);
207 for (
int i = 0; i < static_cast<int>(peaksWS->getNumberPeaks()); ++i) {
208 IPeak const &p = peaksWS->getPeak(i);
210 if (!(currentGoniometerMatrix == lastGoniometerMatrix)) {
211 gonioVec.emplace_back(currentGoniometerMatrix);
212 lastGoniometerMatrix = currentGoniometerMatrix;
216 goniometerConvension = peaksWS->run().getGoniometer().getConventionFromMotorAxes();
218 if (mdWS->getNumExperimentInfo() <= 0)
219 throw std::invalid_argument(
"Specified a MDEventWorkspace as InputWorkspace but it does not have "
220 "any ExperimentInfo associated. Please choose a workspace with a "
221 "full instrument and sample.");
223 inputExperimentInfo = mdWS->getExperimentInfo(0);
226 for (uint16_t i = 0; i < mdWS->getNumExperimentInfo(); ++i) {
228 auto goniometerMatrix = mdWS->getExperimentInfo(i)->mutableRun().getGoniometerMatrices();
229 std::move(goniometerMatrix.begin(), goniometerMatrix.end(), back_inserter(gonioVec));
230 }
catch (std::runtime_error &e) {
232 gonioVec.emplace_back(
DblMatrix(3, 3,
true));
234 g_log.
error() <<
"Error getting the goniometer rotation matrix from the "
237 g_log.
warning() <<
"Using identity goniometer rotation matrix instead.\n";
241 goniometerConvension = inputExperimentInfo->run().getGoniometer().getConventionFromMotorAxes();
246 if (gonioVec.empty()) {
247 gonioVec.emplace_back(
DblMatrix(3, 3,
true));
250 if (usingInstrument) {
259 m_pw = std::make_shared<LeanElasticPeaksWorkspace>();
261 m_pw = std::make_shared<PeaksWorkspace>();
264 m_pw->copyExperimentInfoFrom(inputExperimentInfo.get());
266 const Sample &sample = inputExperimentInfo->sample();
273 ub = orientedLattice.
getUB();
275 std::vector<V3D> possibleHKLs;
278 if (!possibleHKLWorkspace) {
292 Progress prog(
this, 0.0, 1.0, possibleHKLs.size() * gonioVec.size());
298 if (!usingInstrument) {
299 for (
auto const &possibleHKL : possibleHKLs) {
302 }
else if (
getProperty(
"CalculateGoniometerForCW")) {
303 size_t allowedPeakCount = 0;
306 if (wavelength == DBL_MAX) {
307 if (
m_inst->hasParameter(
"wavelength")) {
308 wavelength =
m_inst->getNumberParameter(
"wavelength").at(0);
310 throw std::runtime_error(
"Could not get wavelength, neither Wavelength algorithm property "
311 "set nor instrument wavelength parameter");
316 bool innerGoniometer =
getProperty(
"InnerGoniometer");
318 if (goniometerConvension.empty()) {
320 goniometerConvension =
"YZY";
322 for (
const auto &possibleHKL : possibleHKLs) {
326 std::vector<double> angles = goniometer.
getEulerAngles(goniometerConvension);
327 double angle = innerGoniometer ? angles[2] : angles[0];
333 V3D q_lab = goniometer.
getR() * q_sample;
338 double lambda = (4.0 * M_PI * std::abs(q_lab.
Z())) / q_lab.
norm2();
340 if (!std::isfinite(angle) || angle < angleMin || angle > angleMax)
344 g_log.
information() <<
"Found goniometer rotation to be in " << goniometerConvension <<
" convention ["
345 << angles[0] <<
", " << angles[1] <<
". " << angles[2]
346 <<
"] degrees for Q sample = " << q_sample <<
"\n";
356 for (
auto const &goniometerMatrix : gonioVec) {
358 DblMatrix orientedUB = goniometerMatrix * ub;
364 size_t allowedPeakCount = 0;
366 bool useExtendedDetectorSpace =
getProperty(
"PredictPeaksOutsideDetectors");
367 if (useExtendedDetectorSpace && !
m_inst->getComponentByName(
"extended-detector-space")) {
368 g_log.
warning() <<
"Attempting to find peaks outside of detectors but "
369 "no extended detector space has been defined\n";
372 for (
auto const &possibleHKL : possibleHKLs) {
373 if (lambdaFilter.
isAllowed(possibleHKL)) {
386 std::vector<std::pair<std::string, bool>> criteria;
387 criteria.emplace_back(
"RunNumber",
true);
389 criteria.emplace_back(
"BankName",
true);
390 m_pw->sort(criteria);
392 for (
int i = 0; i < static_cast<int>(
m_pw->getNumberPeaks()); ++i) {
393 m_pw->getPeak(i).setPeakNumber(i);
395 setProperty<IPeaksWorkspace_sptr>(
"OutputWorkspace",
m_pw);
404 if (
auto pw = std::dynamic_pointer_cast<PeaksWorkspace>(
m_pw)) {
405 const bool usingExtendedDetectorSpace =
getProperty(
"PredictPeaksOutsideDetectors");
406 const auto &peaks = pw->getPeaks();
407 size_t offDetectorPeakCount = 0;
408 size_t onDetectorPeakCount = 0;
410 for (
const auto &peak : peaks) {
411 if (peak.getDetectorID() == -1) {
412 offDetectorPeakCount++;
414 onDetectorPeakCount++;
418 g_log.
notice() <<
"Out of " << allowedPeakCount <<
" allowed peaks within parameters, " << onDetectorPeakCount
419 <<
" were found to hit a detector";
420 if (usingExtendedDetectorSpace) {
421 g_log.
notice() <<
" and " << offDetectorPeakCount <<
" were found in "
422 <<
"extended detector space.";
432 if (!inWS || !inWS->getInstrument())
433 throw std::invalid_argument(
"Did not specify a valid InputWorkspace with a "
436 m_inst = inWS->getInstrument();
442 throw std::runtime_error(
"Failed to get run number");
450 const auto sample =
m_inst->getSample();
452 throw std::runtime_error(
"Instrument sample position has not been set");
453 const V3D samplePos = sample->getPos();
456 V3D beamDir =
m_inst->getSource()->getPos() - samplePos;
458 if ((
fabs(beamDir.
X()) > 1e-2) || (
fabs(beamDir.
Y()) > 1e-2))
459 throw std::invalid_argument(
"Instrument must have a beam direction that "
460 "is only in the +Z direction for this "
461 "algorithm to be valid..");
467 std::vector<V3D> &possibleHKLs)
const {
476 const auto found = std::find_if(
m_refConds.crbegin(),
m_refConds.crend(), [&refCondName](
const auto &condition) {
477 return condition->getName() == refCondName;
485 std::make_shared<HKLFilterCentering>(refCond) & std::make_shared<HKLFilterDRange>(orientedLattice, dMin, dMax);
489 g_log.
information() <<
"HKL range for d_min of " << dMin <<
" to d_max of " << dMax <<
" is from " << hklMin <<
" to "
490 << hklMin * -1.0 <<
", a total of " << gen.
size() <<
" possible HKL's\n";
492 if (gen.
size() > 10000000000)
493 throw std::invalid_argument(
"More than 10 billion HKLs to search. Is "
494 "your d_min value too small?");
496 possibleHKLs.clear();
497 possibleHKLs.reserve(gen.
size());
498 std::remove_copy_if(gen.
begin(), gen.
end(), std::back_inserter(possibleHKLs), (~filter)->fn());
503 std::vector<V3D> &possibleHKLs)
const {
504 possibleHKLs.clear();
505 possibleHKLs.reserve(peaksWorkspace->getNumberPeaks());
515 double peaks_q_convention_factor =
qConventionFactor(peaksWorkspace->getConvention());
517 for (
int i = 0; i < static_cast<int>(peaksWorkspace->getNumberPeaks()); ++i) {
518 IPeak const &p = peaksWorkspace->getPeak(i);
520 V3D hkl = p.
getHKL() * peaks_q_convention_factor;
525 possibleHKLs.emplace_back(hkl);
543 bool calculateStructureFactors =
getProperty(
"CalculateStructureFactors");
549 m_sfCalculator = StructureFactorCalculatorFactory::create<StructureFactorCalculatorSummation>(crystalStructure);
573 const auto detectorDir = std::get<0>(params);
574 const auto wl = std::get<1>(params);
576 const bool useExtendedDetectorSpace =
getProperty(
"PredictPeaksOutsideDetectors");
578 const auto hitDetector = std::get<0>(result);
579 const auto index = std::get<1>(result);
581 if (!hitDetector && !useExtendedDetectorSpace) {
585 const auto &detInfo =
m_pw->detectorInfo();
586 const auto &det = detInfo.detector(
index);
587 std::unique_ptr<Peak> peak;
591 peak = std::make_unique<Peak>(
m_inst, det.getID(), wl);
592 if (!peak->getDetector()) {
595 }
else if (useExtendedDetectorSpace) {
597 const auto returnedComponent =
m_inst->getComponentByName(
"extended-detector-space");
599 const auto component = std::dynamic_pointer_cast<const ObjComponent>(returnedComponent);
601 throw std::runtime_error(
"PredictPeaks: user requested use of a extended "
602 "detector space to predict peaks but there is no"
603 "definition in the IDF");
607 if (!component->interceptSurface(track))
611 const auto magnitude = track.
back().exitPoint.norm();
612 peak = std::make_unique<Peak>(
m_inst, q, std::optional<double>(magnitude));
619 peak->setGoniometerMatrix(goniometerMatrix);
630 m_pw->addPeak(*peak);
648 auto peak = std::make_unique<LeanElasticPeak>(q);
660 m_pw->addPeak(*peak);
669 double norm_q = q.
norm();
672 double one_over_wl = (norm_q * norm_q) / (2.0 * qBeam);
673 double wl = (2.0 * M_PI) / one_over_wl;
676 detectorDir[
m_refFrame->pointingAlongBeam()] = one_over_wl - qBeam;
678 return std::make_tuple(detectorDir, wl);
#define DECLARE_ALGORITHM(classname)
const std::vector< double > * lambda
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Helper class for reporting progress from algorithms.
This class stores information about the sample used in particular run.
const Geometry::OrientedLattice & getOrientedLattice() const
Get a reference to the sample's OrientedLattice.
bool hasCrystalStructure() const
Returns true if the sample actually holds a CrystalStructure.
const Geometry::CrystalStructure & getCrystalStructure() const
A property class for workspaces.
void calculateQAndAddToOutputLeanElastic(const Kernel::V3D &hkl, const Kernel::DblMatrix &UB)
Calculates Q from HKL and adds a peak to the output workspace.
double m_qConventionFactor
void setInstrumentFromInputWorkspace(const API::ExperimentInfo_sptr &inWS)
Tries to set the internally stored instrument from an ExperimentInfo-object.
int m_runNumber
Run number of input workspace.
void checkBeamDirection() const
Checks that the beam direction is +Z, throws exception otherwise.
int m_edge
Number of edge pixels with no peaks.
void setRunNumberFromInputWorkspace(const API::ExperimentInfo_sptr &inWS)
Sets the run number from the supplied ExperimentInfo or throws an exception.
void exec() override
Run the algorithm.
std::tuple< Kernel::V3D, double > getPeakParametersFromQ(const Kernel::V3D &q) const
Get the predicted detector direction from Q.
PredictPeaks()
Constructor.
void logNumberOfPeaksFound(size_t allowedPeakCount) const
Log the number of peaks found to fall on and off detectors.
std::shared_ptr< const Geometry::ReferenceFrame > m_refFrame
Reference frame for the instrument.
void fillPossibleHKLsUsingPeaksWorkspace(const API::IPeaksWorkspace_sptr &peaksWorkspace, std::vector< Kernel::V3D > &possibleHKLs) const
Fills possibleHKLs with all HKLs from the supplied PeaksWorkspace.
Geometry::Instrument_const_sptr m_inst
Instrument reference.
void calculateQAndAddToOutput(const Kernel::V3D &hkl, const Kernel::DblMatrix &orientedUB, const Kernel::DblMatrix &goniometerMatrix)
Calculates Q from HKL and adds a peak to the output workspace.
std::unique_ptr< API::DetectorSearcher > m_detectorCacheSearch
Detector search cache for fast look-up of detectors.
std::vector< Mantid::Geometry::ReflectionCondition_sptr > m_refConds
Reflection conditions possible.
void setReferenceFrameAndBeamDirection()
Cache the reference frame and beam direction from the instrument.
Mantid::API::IPeaksWorkspace_sptr m_pw
Output peaks workspace.
Geometry::StructureFactorCalculator_sptr m_sfCalculator
void fillPossibleHKLsUsingGenerator(const Geometry::OrientedLattice &orientedLattice, std::vector< Kernel::V3D > &possibleHKLs) const
Fills possibleHKLs with all HKLs that are allowed within d- and lambda-limits.
void init() override
Initialise the properties.
void setStructureFactorCalculatorFromSample(const API::Sample &sample)
Assigns a StructureFactorCalculator if available in sample.
Kernel::V3D m_refBeamDir
Direction of the beam for this instrument.
Three components are required to describe a crystal structure:
void setCell(const UnitCell &cell)
Assigns a new unit cell.
Class to represent a particular goniometer setting, which is described by the rotation matrix.
std::vector< double > getEulerAngles(const std::string &convention="YZX")
Return Euler angles acording to a convention.
const Kernel::DblMatrix & getR() const
Return global rotation matrix.
void calcFromQSampleAndWavelength(const Mantid::Kernel::V3D &Q, double wavelength, bool flip_x=false, bool inner=false)
Calculate goniometer for rotation around y-asix for constant wavelength from Q Sample.
bool isAllowed(const Kernel::V3D &hkl) const noexcept override
Returns true if lambda of the reflection is within the limits.
const const_iterator & end() const
Returns an iterator which "points at" one element past the end.
const const_iterator & begin() const
Returns an iterator to the beginning of the sequence.
size_t size() const
Returns the number of HKLs to be generated.
Structure describing a single-crystal peak.
virtual Mantid::Kernel::Matrix< double > getGoniometerMatrix() const =0
virtual Mantid::Kernel::V3D getHKL() const =0
Class to implement UB matrix.
const Kernel::DblMatrix & getUB() const
Get the UB matrix.
Defines a track as a start point and a direction.
LType::reference back()
Returns a reference to the last link.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void notice(const std::string &msg)
Logs at notice level.
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.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
void setNotifyStep(double notifyStepPct)
Override the frequency at which notifications are sent out.
The concrete, templated class for properties.
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
constexpr double X() const noexcept
Get x.
double normalize()
Make a normalized vector (return norm value)
constexpr double Y() const noexcept
Get y.
double norm() const noexcept
constexpr double norm2() const noexcept
Vector length squared.
constexpr double Z() const noexcept
Get z.
void round() noexcept
Round each component to the nearest integer.
std::shared_ptr< IPeaksWorkspace > IPeaksWorkspace_sptr
shared pointer to Mantid::API::IPeaksWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
std::shared_ptr< MultipleExperimentInfos > MultipleExperimentInfos_sptr
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
double qConventionFactor()
convenience overload to pull the convention from the config service
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
std::shared_ptr< ReflectionCondition > ReflectionCondition_sptr
Shared pointer to a ReflectionCondition.
MANTID_GEOMETRY_DLL bool edgePixel(const Geometry::Instrument_const_sptr &inst, const std::string &bankName, int col, int row, int Edge)
Function to find peaks near detector edge.
MANTID_GEOMETRY_DLL const ReflectionConditions & getAllReflectionConditions()
MANTID_KERNEL_DLL bool withinAbsoluteDifference(T const x, T const y, S const tolerance)
Test whether x, y are within absolute tolerance tol.
Mantid::Kernel::Matrix< double > DblMatrix
Peak indexing algorithm, which works by assigning multiple possible HKL values to each peak and then ...
@ Input
An input workspace.
@ Output
An output workspace.