Mantid
Loading...
Searching...
No Matches
MonteCarloAbsorption.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 +
9#include "MantidAPI/Run.h"
10#include "MantidAPI/Sample.h"
31
32using namespace Mantid::API;
33using namespace Mantid::Geometry;
34using namespace Mantid::Kernel;
37
39namespace {
40
41constexpr int DEFAULT_NEVENTS = 1000;
42constexpr int DEFAULT_SEED = 123456789;
43constexpr int DEFAULT_LATITUDINAL_DETS = 5;
44constexpr int DEFAULT_LONGITUDINAL_DETS = 10;
45
47inline double toWavelength(double energy) {
48 static const double factor =
50 return factor / sqrt(energy);
51}
52
53struct EFixedProvider {
54 explicit EFixedProvider(const ExperimentInfo &expt) : m_expt(expt), m_emode(expt.getEMode()), m_value(0.0) {
55 if (m_emode == DeltaEMode::Direct) {
56 m_value = m_expt.getEFixed();
57 }
58 }
59 inline DeltaEMode::Type emode() const { return m_emode; }
60 inline double value(const Mantid::detid_t detID) const {
61 if (m_emode != DeltaEMode::Indirect)
62 return m_value;
63 else
64 return m_expt.getEFixed(detID);
65 }
66
67private:
68 const ExperimentInfo &m_expt;
69 const DeltaEMode::Type m_emode;
70 double m_value;
71};
72} // namespace
74
75namespace Mantid::Algorithms {
76
77DECLARE_ALGORITHM(MonteCarloAbsorption)
78
79//------------------------------------------------------------------------------
80// Private methods
81//------------------------------------------------------------------------------
82
83
87 // The input workspace must have an instrument and units of wavelength
88 auto wsValidator = std::make_shared<CompositeValidator>();
89 wsValidator->add<WorkspaceUnitValidator>("Wavelength");
90 wsValidator->add<InstrumentValidator>();
91
92 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input, wsValidator),
93 "The name of the input workspace. The input workspace must "
94 "have X units of wavelength.");
95 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
96 "The name to use for the output workspace.");
97
98 auto positiveInt = std::make_shared<Kernel::BoundedValidator<int>>();
99 positiveInt->setLower(1);
100 declareProperty("NumberOfWavelengthPoints", EMPTY_INT(), positiveInt,
101 "The number of wavelength points for which a simulation is "
102 "attempted if ResimulateTracksForDifferentWavelengths=true");
103 declareProperty("EventsPerPoint", DEFAULT_NEVENTS, positiveInt,
104 "The number of \"neutron\" events to generate per simulated point");
105 declareProperty("SeedValue", DEFAULT_SEED, positiveInt, "Seed the random number generator with this value");
106
107 auto interpolateOpt = createInterpolateOption();
108 declareProperty(interpolateOpt->property(), interpolateOpt->propertyDoc());
109 declareProperty("SparseInstrument", false,
110 "Enable simulation on special "
111 "instrument with a sparse grid of "
112 "detectors interpolating the "
113 "results to the real instrument.");
114 auto threeOrMore = std::make_shared<Kernel::BoundedValidator<int>>();
115 threeOrMore->setLower(3);
116 declareProperty("NumberOfDetectorRows", DEFAULT_LATITUDINAL_DETS, threeOrMore,
117 "Number of detector rows in the detector grid of the sparse instrument.");
118 setPropertySettings("NumberOfDetectorRows",
119 std::make_unique<EnabledWhenProperty>("SparseInstrument", ePropertyCriterion::IS_NOT_DEFAULT));
120 auto twoOrMore = std::make_shared<Kernel::BoundedValidator<int>>();
121 twoOrMore->setLower(2);
122 declareProperty("NumberOfDetectorColumns", DEFAULT_LONGITUDINAL_DETS, twoOrMore,
123 "Number of detector columns in the detector grid "
124 "of the sparse instrument.");
125 setPropertySettings("NumberOfDetectorColumns",
126 std::make_unique<EnabledWhenProperty>("SparseInstrument", ePropertyCriterion::IS_NOT_DEFAULT));
127
128 // Control the number of attempts made to generate a random point in the
129 // object
130 declareProperty("MaxScatterPtAttempts", 5000, positiveInt,
131 "Maximum number of tries made to generate a scattering point "
132 "within the sample (+ optional container etc). Objects with "
133 "holes in them, e.g. a thin annulus can cause problems "
134 "if this number is too low.\n"
135 "If a scattering point cannot be generated by increasing "
136 "this value then there is most likely a problem with "
137 "the sample geometry.");
138 declareProperty("ResimulateTracksForDifferentWavelengths", false, "Resimulate tracks for each wavelength point.");
139 setPropertySettings("NumberOfWavelengthPoints",
140 std::make_unique<EnabledWhenProperty>("ResimulateTracksForDifferentWavelengths",
141 ePropertyCriterion::IS_NOT_DEFAULT));
142 auto scatteringOptionValidator = std::make_shared<StringListValidator>();
143 scatteringOptionValidator->addAllowedValue("SampleAndEnvironment");
144 scatteringOptionValidator->addAllowedValue("SampleOnly");
145 scatteringOptionValidator->addAllowedValue("EnvironmentOnly");
146 declareProperty("SimulateScatteringPointIn", "SampleAndEnvironment",
147 "Simulate the scattering point in the vicinity of the sample or its "
148 "environment or both (default).",
149 scatteringOptionValidator);
150}
151
156 const MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
157 const int nevents = getProperty("EventsPerPoint");
158 const bool resimulateTracks = getProperty("ResimulateTracksForDifferentWavelengths");
159 const int seed = getProperty("SeedValue");
160 InterpolationOption interpolateOpt;
161 interpolateOpt.set(getPropertyValue("Interpolation"), true, resimulateTracks);
162 const bool useSparseInstrument = getProperty("SparseInstrument");
163 const int maxScatterPtAttempts = getProperty("MaxScatterPtAttempts");
165 const auto pointsInProperty = getPropertyValue("SimulateScatteringPointIn");
166 if (pointsInProperty == "SampleOnly") {
168 } else if (pointsInProperty == "EnvironmentOnly") {
170 }
171 auto outputWS = doSimulation(*inputWS, static_cast<size_t>(nevents), resimulateTracks, seed, interpolateOpt,
172 useSparseInstrument, static_cast<size_t>(maxScatterPtAttempts), simulatePointsIn);
173 setProperty("OutputWorkspace", std::move(outputWS));
174}
175
180std::map<std::string, std::string> MonteCarloAbsorption::validateInputs() {
181 std::map<std::string, std::string> issues;
182 const bool resimulateTracksForDiffWavelengths = getProperty("ResimulateTracksForDifferentWavelengths");
183 // Only interpolate between wavelength points if resimulating tracks
184 if (resimulateTracksForDiffWavelengths) {
185 const int nlambda = getProperty("NumberOfWavelengthPoints");
186 InterpolationOption interpOpt;
187 const std::string interpValue = getPropertyValue("Interpolation");
188 interpOpt.set(interpValue, true, resimulateTracksForDiffWavelengths);
189 const auto nlambdaIssue = interpOpt.validateInputSize(nlambda);
190 if (!nlambdaIssue.empty()) {
191 issues["NumberOfWavelengthPoints"] = nlambdaIssue;
192 }
193 }
194 return issues;
195}
196
211std::shared_ptr<IMCAbsorptionStrategy>
212MonteCarloAbsorption::createStrategy(std::shared_ptr<IMCInteractionVolume> interactionVol,
213 const IBeamProfile &beamProfile, Kernel::DeltaEMode::Type EMode,
214 const size_t nevents, const size_t maxScatterPtAttempts,
215 const bool regenerateTracksForEachLambda) {
216 return std::make_shared<MCAbsorptionStrategy>(interactionVol, beamProfile, EMode, nevents, maxScatterPtAttempts,
217 regenerateTracksForEachLambda);
218}
219
229std::shared_ptr<SparseWorkspace> MonteCarloAbsorption::createSparseWorkspace(const API::MatrixWorkspace &modelWS,
230 const size_t wavelengthPoints,
231 const size_t rows, const size_t columns) {
232 auto sparseWS = std::make_shared<SparseWorkspace>(modelWS, wavelengthPoints, rows, columns);
233 return sparseWS;
234}
235
241std::unique_ptr<InterpolationOption> MonteCarloAbsorption::createInterpolateOption() {
242 auto interpolationOpt = std::make_unique<InterpolationOption>();
243 return interpolationOpt;
244}
245
261 const bool resimulateTracksForDiffWavelengths, const int seed,
262 const InterpolationOption &interpolateOpt,
263 const bool useSparseInstrument,
264 const size_t maxScatterPtAttempts,
266 auto outputWS = createOutputWorkspace(inputWS);
267 const auto inputNbins = static_cast<int>(inputWS.blocksize());
268
269 int nlambda;
270 if (resimulateTracksForDiffWavelengths) {
271 nlambda = getProperty("NumberOfWavelengthPoints");
272 if (isEmpty(nlambda) || nlambda > inputNbins) {
273 if (!isEmpty(nlambda)) {
274 g_log.warning() << "The requested number of wavelength points is larger "
275 "than the spectra size. "
276 "Defaulting to spectra size.\n";
277 }
278 nlambda = inputNbins;
279 }
280 } else {
281 nlambda = inputNbins;
282 }
283 SparseWorkspace_sptr sparseWS;
284 if (useSparseInstrument) {
285 const int latitudinalDets = getProperty("NumberOfDetectorRows");
286 const int longitudinalDets = getProperty("NumberOfDetectorColumns");
287 sparseWS = createSparseWorkspace(inputWS, nlambda, latitudinalDets, longitudinalDets);
288 }
289 MatrixWorkspace &simulationWS = useSparseInstrument ? *sparseWS : *outputWS;
290 const MatrixWorkspace &instrumentWS = useSparseInstrument ? simulationWS : inputWS;
291 // Cache information about the workspace that will be used repeatedly
292 auto instrument = instrumentWS.getInstrument();
293 const auto nhists = static_cast<int64_t>(instrumentWS.getNumberHistograms());
294
295 EFixedProvider efixed(instrumentWS);
296 auto beamProfile = BeamProfileFactory::createBeamProfile(*instrument, inputWS.sample());
297
298 // Configure progress
299 Progress prog(this, 0.0, 1.0, nhists);
300 prog.setNotifyStep(0.01);
301 const std::string reportMsg = "Computing corrections";
302
303 // Configure interaction volume
304
305 bool hasGaugeVol = false;
306 Geometry::IObject_sptr gaugeVolume = nullptr;
307
308 try {
309 inputWS.run().getProperty("GaugeVolume");
310 hasGaugeVol = true;
311 } catch (const std::exception &) {
312 }
313
314 if (hasGaugeVol) {
315 std::string xmlString = inputWS.run().getProperty("GaugeVolume")->value();
316 gaugeVolume = ShapeFactory().createShape(std::move(xmlString));
318 g_log.warning("Gauge Volume found. Scattering Points limited to Sample Only.");
319 }
320 pointsIn = MCInteractionVolume::ScatteringPointVicinity::SAMPLEONLY; // if gauge volume present, only generate
321 // points from the sample
322 }
323
324 std::shared_ptr<IMCInteractionVolume> interactionVolume =
325 MCInteractionVolume::create(inputWS.sample(), maxScatterPtAttempts, pointsIn, gaugeVolume);
326
327 Geometry::IObject_sptr gv = interactionVolume->getGaugeVolume();
328
329 std::shared_ptr<IMCAbsorptionStrategy> strategy =
330 createStrategy(std::move(interactionVolume), *beamProfile, efixed.emode(), nevents, maxScatterPtAttempts,
331 resimulateTracksForDiffWavelengths);
332
333 const auto &spectrumInfo = simulationWS.spectrumInfo();
334
336 for (int64_t i = 0; i < nhists; ++i) {
338
339 auto &outE = simulationWS.mutableE(i);
340 // The input was cloned so clear the errors out
341 outE = 0.0;
342
343 if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMasked(i)) {
344 continue;
345 }
346 // Per spectrum values
347 const auto &detPos = spectrumInfo.position(i);
348 const double lambdaFixed = toWavelength(efixed.value(spectrumInfo.detector(i).getID()));
349 MersenneTwister rng(seed + int(i));
350
351 const auto lambdas = simulationWS.points(i).rawData();
352
353 const auto nbins = lambdas.size();
354 const size_t lambdaStepSize = nbins / nlambda;
355
356 std::vector<double> packedLambdas;
357 std::vector<double> packedAttFactors;
358 std::vector<double> packedAttFactorErrors;
359
360 for (size_t j = 0; j < nbins; j += lambdaStepSize) {
361 packedLambdas.push_back(lambdas[j]);
362 packedAttFactors.push_back(0);
363 packedAttFactorErrors.push_back(0);
364 // Ensure we have the last point for the interpolation
365 if (lambdaStepSize > 1 && j + lambdaStepSize >= nbins && j + 1 != nbins) {
366 j = nbins - lambdaStepSize - 1;
367 }
368 }
369 MCInteractionStatistics detStatistics(spectrumInfo.detector(i).getID(), inputWS.sample());
370
371 strategy->calculate(rng, detPos, packedLambdas, lambdaFixed, packedAttFactors, packedAttFactorErrors,
372 detStatistics);
373
374 if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) {
375 g_log.debug(detStatistics.generateScatterPointStats());
376 }
377
378 for (size_t j = 0; j < packedLambdas.size(); j++) {
379 auto idx = simulationWS.yIndexOfX(packedLambdas[j], i);
380 simulationWS.getSpectrum(i).dataY()[idx] = packedAttFactors[j];
381 simulationWS.getSpectrum(i).dataE()[idx] = packedAttFactorErrors[j];
382 }
383
384 // Interpolate through points not simulated. Simulation WS only has
385 // reduced X values if using sparse instrument so no interpolation required
386
387 if (!useSparseInstrument && lambdaStepSize > 1) {
388 auto histnew = simulationWS.histogram(i);
389
390 if (lambdaStepSize < nbins) {
391 interpolateOpt.applyInplace(histnew, lambdaStepSize);
392 } else {
393 std::fill(histnew.mutableY().begin() + 1, histnew.mutableY().end(), histnew.y()[0]);
394 }
395 outputWS->setHistogram(i, histnew);
396 }
397
398 prog.report(reportMsg);
399
401 }
403
404 if (useSparseInstrument) {
405 interpolateFromSparse(*outputWS, *sparseWS, interpolateOpt);
406 }
407
408 return outputWS;
409}
410
412 MatrixWorkspace_uptr outputWS = DataObjects::create<Workspace2D>(inputWS);
413 // The algorithm computes the signal values at bin centres so they should
414 // be treated as a distribution
415 outputWS->setDistribution(true);
416 outputWS->setYUnit("");
417 outputWS->setYUnitLabel("Attenuation factor");
418 return outputWS;
419}
420
423 const auto &spectrumInfo = targetWS.spectrumInfo();
424 const auto refFrame = targetWS.getInstrument()->getReferenceFrame();
425 PARALLEL_FOR_IF(Kernel::threadSafe(targetWS, sparseWS))
426 for (int64_t i = 0; i < static_cast<decltype(i)>(spectrumInfo.size()); ++i) {
428 if (spectrumInfo.hasDetectors(i)) {
429 double lat, lon;
430 std::tie(lat, lon) = spectrumInfo.geographicalAngles(i);
431 const auto spatiallyInterpHisto = sparseWS.bilinearInterpolateFromDetectorGrid(lat, lon);
432 if (spatiallyInterpHisto.size() > 1) {
433 auto targetHisto = targetWS.histogram(i);
434 interpOpt.applyInPlace(spatiallyInterpHisto, targetHisto);
435 targetWS.setHistogram(i, targetHisto);
436 } else {
437 targetWS.mutableY(i) = spatiallyInterpHisto.y().front();
438 }
439 }
441 }
443}
444} // namespace Mantid::Algorithms
const std::string & m_value
Definition Algorithm.cpp:71
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double value
The value of the point.
Definition FitMW.cpp:51
double energy
Definition GetAllEi.cpp:157
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
This class is shared by a few Workspace types and holds information related to a particular experimen...
const SpectrumInfo & spectrumInfo() const
Return a reference to the SpectrumInfo object.
const Run & run() const
Run details object access.
Geometry::Instrument_const_sptr getInstrument() const
Returns the parameterized instrument.
const Sample & sample() const
Sample accessors.
virtual MantidVec & dataY()=0
virtual MantidVec & dataE()=0
A validator which checks that a workspace has a valid instrument.
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
Base MatrixWorkspace Abstract Class.
virtual ISpectrum & getSpectrum(const size_t index)=0
Return the underlying ISpectrum ptr at the given workspace index.
HistogramData::Points points(const size_t index) const
virtual std::size_t blocksize() const =0
Returns the size of each block of data returned by the dataY accessors.
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
void setHistogram(const size_t index, T &&...data) &
std::size_t yIndexOfX(const double xValue, const std::size_t &index=0, const double tolerance=0.0) const
Returns the y index which corresponds to the X Value provided.
HistogramData::Histogram histogram(const size_t index) const
Returns the Histogram at the given workspace index.
HistogramData::HistogramE & mutableE(const size_t index) &
HistogramData::HistogramY & mutableY(const size_t index) &
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
static std::unique_ptr< IBeamProfile > createBeamProfile(const Geometry::Instrument &instrument, const API::Sample &sample)
Base class for all classes defining a beam profile.
Class to provide a consistent interface to an interpolation option on algorithms.
std::string validateInputSize(const size_t size) const
Validate the size of input histogram.
void applyInPlace(const HistogramData::Histogram &in, HistogramData::Histogram &out) const
Apply the interpolation method to the output histogram.
void set(const Value &kind, const bool calculateErrors, const bool independentErrors)
Set the interpolation option.
void applyInplace(HistogramData::Histogram &inOut, size_t stepSize) const
Apply the interpolation method to the given histogram.
Stores statistics relating to the tracks generated in MCInteractionVolume for a specific detector.
std::string generateScatterPointStats()
Log a debug string summarising which parts of the environment the simulated scatter points occurred i...
static std::shared_ptr< IMCInteractionVolume > create(const API::Sample &sample, const size_t maxScatterAttempts=5000, const ScatteringPointVicinity pointsIn=ScatteringPointVicinity::SAMPLEANDENVIRONMENT, Geometry::IObject_sptr gaugeVolume=nullptr)
Factory Method for constructing the volume encompassing the sample + any environment kit.
Calculates attenuation due to absorption and scattering in a sample + its environment using a Monte C...
virtual std::shared_ptr< IMCAbsorptionStrategy > createStrategy(std::shared_ptr< IMCInteractionVolume > interactionVol, const IBeamProfile &beamProfile, Kernel::DeltaEMode::Type EMode, const size_t nevents, const size_t maxScatterPtAttempts, const bool regenerateTracksForEachLambda)
Factory method to return an instance of the required absorption strategy class.
void interpolateFromSparse(API::MatrixWorkspace &targetWS, const SparseWorkspace &sparseWS, const Mantid::Algorithms::InterpolationOption &interpOpt)
virtual std::shared_ptr< SparseWorkspace > createSparseWorkspace(const API::MatrixWorkspace &modelWS, const size_t wavelengthPoints, const size_t rows, const size_t columns)
Factory method to return an instance of the required SparseInstrument class.
API::MatrixWorkspace_uptr doSimulation(const API::MatrixWorkspace &inputWS, const size_t nevents, const bool simulateTracksForEachWavelength, const int seed, const InterpolationOption &interpolateOpt, const bool useSparseInstrument, const size_t maxScatterPtAttempts, MCInteractionVolume::ScatteringPointVicinity pointsIn)
Run the simulation over the whole input workspace.
API::MatrixWorkspace_uptr createOutputWorkspace(const API::MatrixWorkspace &inputWS) const
std::map< std::string, std::string > validateInputs() override
Validate the input properties.
virtual std::unique_ptr< InterpolationOption > createInterpolateOption()
Factory method to return an instance of the required InterpolationOption class.
Defines functions and utilities to create and deal with sparse instruments.
virtual HistogramData::Histogram bilinearInterpolateFromDetectorGrid(const double lat, const double lon) const
Spatially interpolate a single histogram from nearby detectors using bilinear interpolation method.
Concrete workspace implementation.
Definition Workspace2D.h:29
Class originally intended to be used with the DataHandling 'LoadInstrument' algorithm.
std::shared_ptr< CSGObject > createShape(Poco::XML::Element *pElem)
Creates a geometric object from a DOM-element-node pointing to an element whose child nodes contain t...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
bool is(int level) const
Returns true if at least the given log level is set.
Definition Logger.cpp:177
This implements the Mersenne Twister 19937 pseudo-random number generator algorithm as a specialzatio...
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.
virtual std::string value() const =0
Returns the value of the property as a string.
EXPORT_OPT_MANTIDQT_COMMON std::string getEMode(const Mantid::API::MatrixWorkspace_sptr &ws)
Gets the energy mode from a workspace based on the X unit.
std::unique_ptr< MatrixWorkspace > MatrixWorkspace_uptr
unique pointer to Mantid::API::MatrixWorkspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< SparseWorkspace > SparseWorkspace_sptr
std::shared_ptr< IObject > IObject_sptr
Typdef for a shared pointer.
Definition IObject.h:93
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
A namespace containing physical constants that are required by algorithms and unit routines.
Definition Atom.h:14
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
static constexpr double meV
1 meV in Joules.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
int32_t detid_t
Typedef for a detector ID.
Type
Define the available energy transfer modes It is important to assign enums proper numbers,...
Definition DeltaEMode.h:29
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54