Commit 637c0509 authored by Danny Hindson's avatar Danny Hindson
Browse files

New absorption weighted path length calculation

Monte Carlo simulation to calculate a quantity called absorption
weighted path length that is used in extinction correction calculations
downstream from Mantid eg in Jana. Requested by WISH. Specific changes:

- new AddAbsorptionWeightedPathLengths algorithm that uses the existing MCAbsorptionStrategy class to do most of leg work
- adjust the MCAbsorptionStrategy class to make the code more reusable for calculation involving a single wavelength such as the absorption weighted path length for a peak. In particular change the Calculate function signature to replace the HistoramData and Spectrum parameters with simple vectors and move the interpolation functionality back into the MonteCarloAbsorption algorithm
- extend the Peak class to add in an extra column called tbar for the absorption weighted path length + get\set functions. Also expose the get\set in the Python interface
- update SaveReflections python algorithm to write the actual tbar value for each peak in a peaksworkspace out to Jana file instead of zero
- add the absorption weighted path length to the nexus file and adjust save\load code
parent 6c4d5605
set(SRC_FILES
src/AbsorptionCorrection.cpp
src/AddAbsorptionWeightedPathLengths.cpp
src/AddLogDerivative.cpp
src/AddNote.cpp
src/AddPeak.cpp
......@@ -345,6 +346,7 @@ set(SRC_FILES
set(INC_FILES
inc/MantidAlgorithms/AbsorptionCorrection.h
inc/MantidAlgorithms/AddAbsorptionWeightedPathLengths.h
inc/MantidAlgorithms/AddLogDerivative.h
inc/MantidAlgorithms/AddNote.h
inc/MantidAlgorithms/AddPeak.h
......@@ -707,6 +709,7 @@ if(UNITY_BUILD)
endif(UNITY_BUILD)
set(TEST_FILES
AddAbsorptionWeightedPathLengthsTest.h
AddLogDerivativeTest.h
AddNoteTest.h
AddPeakTest.h
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2011 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 "MantidAPI/Algorithm.h"
#include "MantidAlgorithms/DllConfig.h"
#include "MantidAlgorithms/SampleCorrections/IBeamProfile.h"
namespace Mantid {
namespace API {
class Sample;
}
namespace Geometry {
class Instrument;
}
namespace Algorithms {
/** Takes an existing sample log, and calculates its first or second
* derivative, and adds it as a new log.
@author Danny Hindson
@date 2020-05-07
*/
class MANTID_ALGORITHMS_DLL AddAbsorptionWeightedPathLengths
: public API::Algorithm {
public:
/// Algorithm's name for identification
const std::string name() const override {
return "AddAbsorptionWeightedPathLengths";
};
/// Summary of algorithms purpose
const std::string summary() const override {
return "Add absorption weighted path lengths to each peak in a peaks "
"workspace.";
}
/// Algorithm's version for identification
int version() const override { return 1; };
const std::vector<std::string> seeAlso() const override {
return {"MonteCarloAbsorption, SetSample, SaveReflections"};
}
/// Algorithm's category for identification
const std::string category() const override { return "Crystal\\Peaks"; }
private:
/// Initialise the properties
void init() override;
/// Run the algorithm
void exec() override;
std::map<std::string, std::string> validateInputs() override;
std::unique_ptr<IBeamProfile>
createBeamProfile(const Geometry::Instrument &instrument,
const API::Sample &sample) const;
};
} // namespace Algorithms
} // namespace Mantid
\ No newline at end of file
......@@ -8,7 +8,6 @@
#include "MantidAPI/ISpectrum.h"
#include "MantidAlgorithms/DllConfig.h"
#include "MantidAlgorithms/InterpolationOption.h"
#include "MantidAlgorithms/SampleCorrections/MCInteractionVolume.h"
#include "MantidHistogramData/Histogram.h"
#include "MantidKernel/DeltaEMode.h"
......@@ -40,16 +39,14 @@ public:
MCAbsorptionStrategy(const IBeamProfile &beamProfile,
const API::Sample &sample,
Kernel::DeltaEMode::Type EMode, const size_t nevents,
const int nlambda, const size_t maxScatterPtAttempts,
const bool useSparseInstrument,
const InterpolationOption &interpolateOpt,
const size_t maxScatterPtAttempts,
const bool regenerateTracksForEachLambda,
Kernel::Logger &logger);
void calculate(Kernel::PseudoRandomNumberGenerator &rng,
const Kernel::V3D &finalPos,
const Mantid::HistogramData::Points &lambdas,
double lambdaFixed,
Mantid::API::ISpectrum &attenuationFactorsSpectrum);
const std::vector<double> &lambdas, double lambdaFixed,
std::vector<double> &attenuationFactors,
std::vector<double> &attFactorErrors);
private:
const IBeamProfile &m_beamProfile;
......@@ -58,9 +55,6 @@ private:
const size_t m_maxScatterAttempts;
const double m_error;
const Kernel::DeltaEMode::Type m_EMode;
const int m_nlambda;
const bool m_useSparseInstrument;
const InterpolationOption &m_interpolateOpt;
const bool m_regenerateTracksForEachLambda;
};
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2018 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 +
#include "MantidAlgorithms/AddAbsorptionWeightedPathLengths.h"
#include "MantidAPI/ExperimentInfo.h"
#include "MantidAPI/Sample.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h"
#include "MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h"
#include "MantidDataObjects/PeaksWorkspace.h"
#include "MantidGeometry/Instrument.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidGeometry/Instrument/SampleEnvironment.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/Material.h"
#include "MantidKernel/MersenneTwister.h"
using namespace Mantid::API;
using namespace Mantid::DataObjects;
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
namespace Mantid {
namespace Algorithms {
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(AddAbsorptionWeightedPathLengths)
//----------------------------------------------------------------------------------------------
namespace {
constexpr int DEFAULT_NEVENTS = 1000;
constexpr int DEFAULT_SEED = 123456789;
} // namespace
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void AddAbsorptionWeightedPathLengths::init() {
declareProperty(
std::make_unique<WorkspaceProperty<PeaksWorkspace_sptr::element_type>>(
"InputWorkspace", "", Direction::InOut),
"An input/output peaks workspace that the path distances will be added "
"to.");
auto positiveInt = std::make_shared<Kernel::BoundedValidator<int>>();
positiveInt->setLower(1);
declareProperty("EventsPerPoint", DEFAULT_NEVENTS, positiveInt,
"The number of \"neutron\" events to generate per peak");
declareProperty("SeedValue", DEFAULT_SEED, positiveInt,
"Seed the random number generator with this value");
declareProperty("MaxScatterPtAttempts", 5000, positiveInt,
"Maximum number of tries made to generate a scattering point "
"within the sample. Objects with "
"holes in them, e.g. a thin annulus can cause problems "
"if this number is too low.\n"
"If a scattering point cannot be generated by increasing "
"this value then there is most likely a problem with "
"the sample geometry.");
}
std::map<std::string, std::string>
AddAbsorptionWeightedPathLengths::validateInputs() {
PeaksWorkspace_sptr inputWS = getProperty("InputWorkspace");
std::map<std::string, std::string> issues;
Geometry::IComponent_const_sptr sample =
inputWS->getInstrument()->getSample();
if (!sample) {
issues["InputWorkspace"] = "Input workspace does not have a Sample";
} else {
if (inputWS->sample().hasEnvironment()) {
issues["InputWorkspace"] = "Sample must not have a sample environment";
}
if (inputWS->sample().getMaterial().numberDensity() == 0) {
issues["InputWorkspace"] =
"Sample must have a material set up with a non-zero number density";
}
}
return issues;
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void AddAbsorptionWeightedPathLengths::exec() {
const PeaksWorkspace_sptr inputWS = getProperty("InputWorkspace");
const int nevents = getProperty("EventsPerPoint");
const int maxScatterPtAttempts = getProperty("MaxScatterPtAttempts");
auto instrument = inputWS->getInstrument();
auto beamProfile = createBeamProfile(*instrument, inputWS->sample());
// Configure strategy
/*MCAbsorptionWeightedPathStrategy strategy(
*beamProfile, inputWS->sample(), nevents, maxScatterPtAttempts, g_log);*/
const int nlambda = 1;
MCAbsorptionStrategy strategy(*beamProfile, inputWS->sample(),
DeltaEMode::Elastic, nevents,
maxScatterPtAttempts, true, g_log);
const int seed = getProperty("SeedValue");
MersenneTwister rng(seed);
for (int i = 0; i < inputWS->getNumberPeaks(); ++i) {
IPeak &peak = inputWS->getPeak(i);
auto peakWavelength = peak.getWavelength();
std::vector<double> lambdas{peakWavelength}, absFactors(nlambda),
absFactorErrors(nlambda);
strategy.calculate(rng, peak.getDetectorPosition(), lambdas, peakWavelength,
absFactors, absFactorErrors);
double mu = inputWS->sample().getMaterial().attenuationCoefficient(
peakWavelength); // m-1
double absWeightedPathLength = -log(absFactors[0]) / mu; // metres
peak.setAbsorptionWeightedPathLength(absWeightedPathLength * 100); // cm
}
}
/**
* Create the beam profile. Currently only supports Rectangular. The dimensions
* are either specified by those provided by `SetBeam` algorithm or default
* to the width and height of the samples bounding box
* @param instrument A reference to the instrument object
* @param sample A reference to the sample object
* @return A new IBeamProfile object
*/
std::unique_ptr<IBeamProfile>
AddAbsorptionWeightedPathLengths::createBeamProfile(
const Instrument &instrument, const Sample &sample) const {
const auto frame = instrument.getReferenceFrame();
const auto source = instrument.getSource();
auto beamWidthParam = source->getNumberParameter("beam-width");
auto beamHeightParam = source->getNumberParameter("beam-height");
double beamWidth(-1.0), beamHeight(-1.0);
if (beamWidthParam.size() == 1 && beamHeightParam.size() == 1) {
beamWidth = beamWidthParam[0];
beamHeight = beamHeightParam[0];
} else {
const auto bbox = sample.getShape().getBoundingBox().width();
beamWidth = bbox[frame->pointingHorizontal()];
beamHeight = bbox[frame->pointingUp()];
}
return std::make_unique<RectangularBeamProfile>(*frame, source->getPos(),
beamWidth, beamHeight);
}
} // namespace Algorithms
} // namespace Mantid
\ No newline at end of file
......@@ -20,7 +20,6 @@
#include "MantidDataObjects/WorkspaceCreation.h"
#include "MantidGeometry/Instrument.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidGeometry/Instrument/SampleEnvironment.h"
#include "MantidHistogramData/Histogram.h"
#include "MantidHistogramData/Interpolate.h"
#include "MantidKernel/BoundedValidator.h"
......@@ -261,9 +260,8 @@ MatrixWorkspace_uptr MonteCarloAbsorption::doSimulation(
const std::string reportMsg = "Computing corrections";
// Configure strategy
MCAbsorptionStrategy strategy(
*beamProfile, inputWS.sample(), efixed.emode(), nevents, nlambda,
maxScatterPtAttempts, useSparseInstrument, interpolateOpt, false, g_log);
MCAbsorptionStrategy strategy(*beamProfile, inputWS.sample(), efixed.emode(),
nevents, maxScatterPtAttempts, false, g_log);
const auto &spectrumInfo = simulationWS.spectrumInfo();
......@@ -284,10 +282,53 @@ MatrixWorkspace_uptr MonteCarloAbsorption::doSimulation(
toWavelength(efixed.value(spectrumInfo.detector(i).getID()));
MersenneTwister rng(seed);
const auto lambdas = simulationWS.points(i);
const auto lambdas = simulationWS.points(i).rawData();
const auto nbins = lambdas.size();
const size_t lambdaStepSize = nbins / nlambda;
std::vector<double> packedLambdas;
std::vector<double> packedAttFactors;
std::vector<double> packedAttFactorErrors;
for (size_t j = 0; j < nbins; j += lambdaStepSize) {
packedLambdas.push_back(lambdas[j]);
packedAttFactors.push_back(0);
packedAttFactorErrors.push_back(0);
// Ensure we have the last point for the interpolation
if (lambdaStepSize > 1 && j + lambdaStepSize >= nbins && j + 1 != nbins) {
j = nbins - lambdaStepSize - 1;
}
}
strategy.calculate(rng, detPos, packedLambdas, lambdaFixed,
packedAttFactors, packedAttFactorErrors);
for (size_t j = 0; j < packedLambdas.size(); j++) {
simulationWS.getSpectrum(i)
.dataY()[simulationWS.yIndexOfX(packedLambdas[j])] =
packedAttFactors[j];
simulationWS.getSpectrum(i)
.dataE()[simulationWS.yIndexOfX(packedLambdas[j])] =
packedAttFactorErrors[j];
}
// Interpolate through points not simulated. Simulation WS only has
// reduced X values if using sparse instrument so no interpolation required
if (!useSparseInstrument && lambdaStepSize > 1) {
auto histnew = simulationWS.histogram(i);
if (lambdaStepSize < nbins) {
interpolateOpt.applyInplace(histnew, lambdaStepSize);
} else {
std::fill(histnew.mutableY().begin() + 1, histnew.mutableY().end(),
histnew.y()[0]);
}
outputWS->setHistogram(i, histnew);
}
strategy.calculate(rng, detPos, lambdas, lambdaFixed,
simulationWS.getSpectrum(i));
prog.report(reportMsg);
if (!useSparseInstrument) {
......
......@@ -24,12 +24,7 @@ namespace Algorithms {
* @param sample A reference to the object defining details of the sample
* @param EMode The energy mode of the instrument
* @param nevents The number of Monte Carlo events used in the simulation
* @param nlambda The number of steps to use across the wavelength range
* @param maxScatterPtAttempts The maximum number of tries to generate a random
* @param useSparseInstrument Whether a sparse instrument representation is
* being used
* @param interpolateOpt Method to be used to interpolate between wavelength
* points
* @param regenerateTracksForEachLambda Whether to resimulate tracks for each
* wavelength point or not
* @param logger Logger from parent algorithm to write logging info
......@@ -37,17 +32,14 @@ namespace Algorithms {
*/
MCAbsorptionStrategy::MCAbsorptionStrategy(
const IBeamProfile &beamProfile, const API::Sample &sample,
DeltaEMode::Type EMode, const size_t nevents, const int nlambda,
const size_t maxScatterPtAttempts, const bool useSparseInstrument,
const InterpolationOption &interpolateOpt,
const bool regenerateTracksForEachLambda, Kernel::Logger &logger)
DeltaEMode::Type EMode, const size_t nevents,
const size_t maxScatterPtAttempts, const bool regenerateTracksForEachLambda,
Kernel::Logger &logger)
: m_beamProfile(beamProfile),
m_scatterVol(MCInteractionVolume(
sample, beamProfile.defineActiveRegion(sample), logger)),
m_nevents(nevents), m_maxScatterAttempts(maxScatterPtAttempts),
m_error(1.0 / std::sqrt(m_nevents)), m_EMode(EMode), m_nlambda(nlambda),
m_useSparseInstrument(useSparseInstrument),
m_interpolateOpt(interpolateOpt),
m_error(1.0 / std::sqrt(m_nevents)), m_EMode(EMode),
m_regenerateTracksForEachLambda(regenerateTracksForEachLambda) {}
/**
......@@ -59,22 +51,24 @@ MCAbsorptionStrategy::MCAbsorptionStrategy(
* @param lambdas Set of wavelength values from the input workspace
* @param lambdaFixed Efixed value for a detector ID converted to wavelength, in
* \f$\\A^-1\f$
* @param attenuationFactorsSpectrum A spectrum containing the correction
* factors and associated errors
* @param attenuationFactors A vector containing the calculated correction
* factors
* @param attFactorErrors A vector containing the calculated correction factor
* errors
*/
void MCAbsorptionStrategy::calculate(
Kernel::PseudoRandomNumberGenerator &rng, const Kernel::V3D &finalPos,
const Mantid::HistogramData::Points &lambdas, double lambdaFixed,
Mantid::API::ISpectrum &attenuationFactorsSpectrum) {
void MCAbsorptionStrategy::calculate(Kernel::PseudoRandomNumberGenerator &rng,
const Kernel::V3D &finalPos,
const std::vector<double> &lambdas,
double lambdaFixed,
std::vector<double> &attenuationFactors,
std::vector<double> &attFactorErrors) {
const auto scatterBounds = m_scatterVol.getBoundingBox();
const auto nbins = static_cast<int>(lambdas.size());
const int lambdaStepSize = nbins / m_nlambda;
auto &attenuationFactors = attenuationFactorsSpectrum.mutableY();
for (size_t i = 0; i < m_nevents; ++i) {
Geometry::Track beforeScatter;
Geometry::Track afterScatter;
for (int j = 0; j < nbins; j += lambdaStepSize) {
for (int j = 0; j < nbins; j++) {
size_t attempts(0);
do {
bool success = false;
......@@ -101,12 +95,6 @@ void MCAbsorptionStrategy::calculate(
beforeScatter, afterScatter, lambdaIn, lambdaOut);
attenuationFactors[j] += wgt;
// Ensure we have the last point for the interpolation
if (lambdaStepSize > 1 && j + lambdaStepSize >= nbins &&
j + 1 != nbins) {
j = nbins - lambdaStepSize - 1;
}
break;
}
if (attempts == m_maxScatterAttempts) {
......@@ -123,27 +111,12 @@ void MCAbsorptionStrategy::calculate(
m_scatterVol.generateScatterPointStats();
attenuationFactors = attenuationFactors / static_cast<double>(m_nevents);
// Interpolate through points not simulated. Simulation WS only has
// reduced X values if using sparse instrument so no interpolation required
auto attenuationFactorsHist = attenuationFactorsSpectrum.histogram();
if (!m_useSparseInstrument && lambdaStepSize > 1) {
if (lambdaStepSize < nbins) {
m_interpolateOpt.applyInplace(attenuationFactorsHist, lambdaStepSize);
} else {
std::fill(attenuationFactorsHist.mutableY().begin() + 1,
attenuationFactorsHist.mutableY().end(),
attenuationFactorsHist.y()[0]);
}
}
std::transform(attenuationFactors.begin(), attenuationFactors.end(),
attenuationFactors.begin(),
std::bind(std::divides<double>(), std::placeholders::_1,
static_cast<double>(m_nevents)));
std::fill(attenuationFactorsHist.mutableE().begin(),
attenuationFactorsHist.mutableE().end(), m_error);
// ISpectrum::histogram() returns a value rather than reference so need to
// reapply
attenuationFactorsSpectrum.setHistogram(attenuationFactorsHist);
std::fill(attFactorErrors.begin(), attFactorErrors.end(), m_error);
}
} // namespace Algorithms
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2018 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 "MantidAPI/Run.h"
#include "MantidAPI/Sample.h"
#include "MantidAlgorithms/AddAbsorptionWeightedPathLengths.h"
#include "MantidDataObjects/PeaksWorkspace.h"
#include "MantidGeometry/Crystal/IPeak.h"
#include "MantidGeometry/Instrument/Container.h"
#include "MantidGeometry/Instrument/SampleEnvironment.h"
#include "MantidGeometry/Objects/IObject.h"
#include "MantidKernel/Material.h"
#include "MantidKernel/PhysicalConstants.h"
#include "MantidTestHelpers/ComponentCreationHelper.h"
#include "MantidTestHelpers/WorkspaceCreationHelper.h"
#include <cxxtest/TestSuite.h>
using namespace Mantid::DataObjects;
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
class AddAbsorptionWeightedPathLengthsTest : public CxxTest::TestSuite {
public:
// This pair of boilerplate methods prevent the suite being created statically
// This means the constructor isn't called when running other tests
static AddAbsorptionWeightedPathLengthsTest *createSuite() {
return new AddAbsorptionWeightedPathLengthsTest();
}
static void destroySuite(AddAbsorptionWeightedPathLengthsTest *suite) {
delete suite;
}
void test_spherical_sample_single_onbeam_detector() {
using namespace Mantid::Kernel;
auto peaksWS = std::make_shared<PeaksWorkspace>();
setTestInstrument(peaksWS);
setMaterialToVanadium(peaksWS);
auto parametrizedInstrument = peaksWS->getInstrument();
const int NPEAKS = 10;
for (int i = 0; i < NPEAKS; ++i) {
Peak peak(parametrizedInstrument, 1, i + 0.5);
peaksWS->addPeak(peak);
}
// make beam v narrow so simulated paths all pass through sphere centre
auto &paramMap = peaksWS->instrumentParameters();
auto parametrizedSource = parametrizedInstrument->getSource();
paramMap.add("double", parametrizedSource.get(), "beam-width", 0.000001);
paramMap.add("double", parametrizedSource.get(), "beam-height", 0.000001);
Mantid::Algorithms::AddAbsorptionWeightedPathLengths alg;
TS_ASSERT_THROWS_NOTHING(alg.initialize());
TS_ASSERT(alg.isInitialized());
TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", peaksWS));
TS_ASSERT_THROWS_NOTHING(alg.setProperty("EventsPerPoint", 1000));
TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("SeedValue", "654321"));
TS_ASSERT_THROWS_NOTHING(alg.execute(););
for (int i = 0; i < NPEAKS; i++) {
Mantid::Geometry::IPeak &peak = peaksWS->getPeak(i);
const double delta(1e-04);
// all path lengths regardless of peak wavelength should be 2 * radius
// ie 2mm
TS_ASSERT_DELTA(0.2000, peak.getAbsorptionWeightedPathLength(), delta);
}
}
void test_spherical_sample() {
using namespace Mantid::Kernel;
const int NPEAKS = 10;
// this sets up a sample with a spherical shape of radius = 1mm
auto peaksWS = WorkspaceCreationHelper::createPeaksWorkspace(NPEAKS);
setMaterialToVanadium(peaksWS);
Mantid::Algorithms::AddAbsorptionWeightedPathLengths alg;
TS_ASSERT_THROWS_NOTHING(alg.initialize());
TS_ASSERT(alg.isInitialized());
TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", peaksWS));
TS_ASSERT_THROWS_NOTHING(alg.setProperty("EventsPerPoint", 1000));
TS_ASSERT_THROWS_NOTHING(alg.execute(););
Mantid::Geometry::IPeak &peak = peaksWS->getPeak(0);
const double delta(1e-04);
// weighted path length will be less than 2mm because off centre scatter
// points that are near the detector will have significantly shorter paths
// than those on the opposite side of the sphere
TS_ASSERT_DELTA(0.1502, peak.getAbsorptionWeightedPathLength(), delta);
}
void test_no_sample() {
auto peaksWS = std::make_shared<PeaksWorkspace>();
Mantid::Algorithms::AddAbsorptionWeightedPathLengths alg;
TS_ASSERT_THROWS_NOTHING(alg.initialize());
TS_ASSERT(alg.isInitialized());
TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", peaksWS));
TS_ASSERT_THROWS_NOTHING(alg.setProperty("EventsPerPoint", 1000));
TS_ASSERT_THROWS(alg.execute(), const std::runtime_error &);
}
void test_sample_without_material() {
auto peaksWS = std::make_shared<PeaksWorkspace>();
setTestInstrument(peaksWS);
Mantid::Algorithms::AddAbsorptionWeightedPathLengths alg;
TS_ASSERT_THROWS_NOTHING(alg.initialize());