Skip to content

Commit

Permalink
refs #7445. Create QxQz Matrix WS Transform.
Browse files Browse the repository at this point in the history
Add unit tests to cover the new case. Ensure that the experiment info is copied across, and add new property that allows the user to select what output type they want. The output type defaults to the existing MDWorkspace return as this will ensure backwards compatibility.
  • Loading branch information
OwenArnold committed Jul 16, 2013
1 parent 459859d commit 1a91541
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,13 @@ namespace MDEvents
boost::shared_ptr<MDEventWorkspace2Lean> createMDWorkspace(Mantid::Geometry::IMDDimension_sptr, Mantid::Geometry::IMDDimension_sptr, Mantid::API::BoxController_sptr boxController) const;

public:
//Execute the strategy to produce the a transformed, output MDWorkspace

//Execute the strategy to produce a transformed, output MDWorkspace
virtual Mantid::API::IMDEventWorkspace_sptr executeMD(Mantid::API::MatrixWorkspace_const_sptr inputWs, Mantid::API::BoxController_sptr boxController) const = 0;

//Execute the strategy to produce a transformed, output group of Matrix (2D) Workspaces
virtual Mantid::API::MatrixWorkspace_sptr execute(Mantid::API::MatrixWorkspace_const_sptr inputWs) const = 0;

virtual ~ReflectometryTransform();
ReflectometryTransform();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ namespace MDEvents
ReflectometryTransformKiKf(double kiMin, double kiMax, double kfMin, double kfMax, double incidentTheta);
virtual ~ReflectometryTransformKiKf();

/// Execute transformation
virtual Mantid::API::MatrixWorkspace_sptr execute(Mantid::API::MatrixWorkspace_const_sptr inputWs) const;

/// Execute transformation
virtual Mantid::API::IMDEventWorkspace_sptr executeMD(Mantid::API::MatrixWorkspace_const_sptr inputWs, Mantid::API::BoxController_sptr boxController) const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ namespace MDEvents
ReflectometryTransformP(double pSumMin, double pSumMax, double pDiffMin, double pDiffMax, double incidentTheta);
virtual ~ReflectometryTransformP();
virtual Mantid::API::IMDEventWorkspace_sptr executeMD(Mantid::API::MatrixWorkspace_const_sptr inputWs, Mantid::API::BoxController_sptr boxController) const;

/// Execute transformation
virtual Mantid::API::MatrixWorkspace_sptr execute(Mantid::API::MatrixWorkspace_const_sptr inputWs) const;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ namespace Mantid
/// Destructor
virtual ~ReflectometryTransformQxQz();
/// Execute transformation
virtual Mantid::API::MatrixWorkspace_sptr execute(Mantid::API::MatrixWorkspace_const_sptr inputWs) const;
/// Execute MD transformation
virtual Mantid::API::IMDEventWorkspace_sptr executeMD(Mantid::API::MatrixWorkspace_const_sptr inputWs, Mantid::API::BoxController_sptr boxController) const;

private:
Expand Down
33 changes: 24 additions & 9 deletions Code/Mantid/Framework/MDEvents/src/ConvertToReflectometryQ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,9 @@ namespace MDEvents

setPropertySettings("IncidentTheta", new Kernel::EnabledWhenProperty("OverrideIncidentTheta", IS_EQUAL_TO, "1") );

declareProperty(new WorkspaceProperty<IMDEventWorkspace>("OutputWorkspace","",Direction::Output), "Output 2D Workspace.");
declareProperty(new Kernel::PropertyWithValue<bool>("OutputAsMDWorkspace", true), "Generate the output as a MDWorkspace, otherwise a Workspace2D is returned.");

declareProperty(new WorkspaceProperty<IMDWorkspace>("OutputWorkspace","",Direction::Output), "Output 2D Workspace.");

this->initBoxControllerProps("2,2", 50, 10);
}
Expand All @@ -252,10 +254,11 @@ namespace MDEvents
void ConvertToReflectometryQ::exec()
{
Mantid::API::MatrixWorkspace_sptr inputWs = getProperty("InputWorkspace");
bool bUseOwnIncidentTheta = getProperty("OverrideIncidentTheta");
std::vector<double> extents = getProperty("Extents");
const bool bUseOwnIncidentTheta = getProperty("OverrideIncidentTheta");
const std::vector<double> extents = getProperty("Extents");
double incidentTheta = getProperty("IncidentTheta");
std::string outputDimensions = getPropertyValue("OutputDimensions");
const std::string outputDimensions = getPropertyValue("OutputDimensions");
const bool outputAsMDWorkspace = getProperty("OutputAsMDWorkspace");

//Validation of input parameters
checkInputWorkspace(inputWs);
Expand Down Expand Up @@ -294,6 +297,7 @@ namespace MDEvents

//Select the transform strategy.
ReflectometryTransform_sptr transform;

if(outputDimensions == qSpaceTransform())
{
transform = boost::make_shared<ReflectometryTransformQxQz>(dim0min, dim0max, dim1min, dim1max, incidentTheta);
Expand All @@ -307,12 +311,23 @@ namespace MDEvents
transform = boost::make_shared<ReflectometryTransformKiKf>(dim0min, dim0max, dim1min, dim1max, incidentTheta);
}

auto outputWS = transform->executeMD(inputWs, bc);
IMDWorkspace_sptr outputWS;

if(outputAsMDWorkspace)
{
auto outputMDWS = transform->executeMD(inputWs, bc);

// Copy ExperimentInfo (instrument, run, sample) to the output WS
ExperimentInfo_sptr ei(inputWs->cloneExperimentInfo());
uint16_t runIndex = outputWS->addExperimentInfo(ei);
UNUSED_ARG(runIndex);
// Copy ExperimentInfo (instrument, run, sample) to the output WS
ExperimentInfo_sptr ei(inputWs->cloneExperimentInfo());
outputMDWS->addExperimentInfo(ei);
outputWS = outputMDWS;
}
else
{
auto outputWS2D = transform->execute(inputWs);
outputWS2D->copyExperimentInfoFrom(inputWs.get());
outputWS = outputWS2D;
}

//Execute the transform and bind to the output.
setProperty("OutputWorkspace", outputWS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Mantid
namespace MDEvents
{

ReflectometryTransform::ReflectometryTransform() : m_nbinsx(10), m_nbinsz(10)
ReflectometryTransform::ReflectometryTransform() : m_nbinsx(50), m_nbinsz(50)
{
}

Expand Down
11 changes: 11 additions & 0 deletions Code/Mantid/Framework/MDEvents/src/ReflectometryTransformKiKf.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "MantidMDEvents/ReflectometryTransformKiKf.h"
#include "MantidMDEvents/MDEventWorkspace.h"
#include "MantidGeometry/MDGeometry/MDHistoDimension.h"
#include "MantidDataObjects/Workspace2D.h"
#include <stdexcept>

using namespace Mantid::Kernel;
Expand Down Expand Up @@ -82,6 +83,16 @@ namespace MDEvents
return ws;
}

/**
*
* @param inputWs : Input Matrix workspace
* @return workspace group containing output matrix workspaces of ki and kf
*/
Mantid::API::MatrixWorkspace_sptr ReflectometryTransformKiKf::execute(Mantid::API::MatrixWorkspace_const_sptr inputWs) const
{
return boost::make_shared<Mantid::DataObjects::Workspace2D>();
}


} // namespace Mantid
} // namespace MDEvents
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "MantidKernel/System.h"
#include "MantidMDEvents/MDEventWorkspace.h"
#include "MantidGeometry/MDGeometry/MDHistoDimension.h"
#include "MantidDataObjects/Workspace2D.h"
#include <stdexcept>

using namespace Mantid::Kernel;
Expand Down Expand Up @@ -77,6 +78,11 @@ namespace Mantid
return ws;
}

Mantid::API::MatrixWorkspace_sptr ReflectometryTransformP::execute(Mantid::API::MatrixWorkspace_const_sptr inputWs) const
{
return boost::make_shared<Mantid::DataObjects::Workspace2D>();
}



} // namespace Mantid
Expand Down
140 changes: 113 additions & 27 deletions Code/Mantid/Framework/MDEvents/src/ReflectometryTransformQxQz.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "MantidMDEvents/ReflectometryTransformQxQz.h"
#include "MantidMDEvents/MDEventWorkspace.h"
#include "MantidGeometry/MDGeometry/MDHistoDimension.h"
#include "MantidDataObjects/Workspace2D.h"
#include "MantidAPI/NumericAxis.h"
#include "MantidKernel/UnitFactory.h"
#include <stdexcept>

using namespace Mantid::Kernel;
Expand All @@ -14,75 +17,158 @@ namespace Mantid

//----------------------------------------------------------------------------------------------
/** Destructor
*/
*/
ReflectometryTransformQxQz::~ReflectometryTransformQxQz()
{
}

/*
Constructor
@param qxMin: min qx value (extent)
@param qxMax: max qx value (extent)
@param qzMin: min qz value (extent)
@param qzMax; max qz value (extent)
@param incidentTheta: Predetermined incident theta value
*/
ReflectometryTransformQxQz::ReflectometryTransformQxQz(double qxMin, double qxMax, double qzMin, double qzMax, double incidentTheta):
m_qxMin(qxMin), m_qxMax(qxMax), m_qzMin(qzMin), m_qzMax(qzMax), m_QxCalculation(incidentTheta), m_QzCalculation(incidentTheta)
Constructor
@param qxMin: min qx value (extent)
@param qxMax: max qx value (extent)
@param qzMin: min qz value (extent)
@param qzMax; max qz value (extent)
@param incidentTheta: Predetermined incident theta value
*/
ReflectometryTransformQxQz::ReflectometryTransformQxQz(double qxMin, double qxMax, double qzMin,
double qzMax, double incidentTheta) :
m_qxMin(qxMin), m_qxMax(qxMax), m_qzMin(qzMin), m_qzMax(qzMax), m_QxCalculation(incidentTheta), m_QzCalculation(
incidentTheta)
{
if(qxMin >= qxMax)
if (qxMin >= qxMax)
{
throw std::invalid_argument("min qx bounds must be < max qx bounds");
}
if(qzMin >= qzMax)
if (qzMin >= qzMax)
{
throw std::invalid_argument("min qz bounds must be < max qz bounds");
}
if(incidentTheta < 0 || incidentTheta > 90)
if (incidentTheta < 0 || incidentTheta > 90)
{
throw std::out_of_range("incident theta angle must be > 0 and < 90");
}
}

/*
Execute the transformtion. Generates an output IMDEventWorkspace.
@return the constructed IMDEventWorkspace following the transformation.
@param ws: Input MatrixWorkspace const shared pointer
@param boxController: Box controller to apply to output workspace
*/
IMDEventWorkspace_sptr ReflectometryTransformQxQz::executeMD(MatrixWorkspace_const_sptr inputWs, BoxController_sptr boxController) const
Execute the transformation. Generates an output IMDEventWorkspace.
@return the constructed IMDEventWorkspace following the transformation.
@param ws: Input MatrixWorkspace, with a vertical axis of signed-theta, and an x-axis of wavelength
@param boxController: Box controller to apply to output workspace
*/
IMDEventWorkspace_sptr ReflectometryTransformQxQz::executeMD(MatrixWorkspace_const_sptr inputWs,
BoxController_sptr boxController) const
{

MDHistoDimension_sptr qxDim = MDHistoDimension_sptr(new MDHistoDimension("Qx","qx","(Ang^-1)", static_cast<Mantid::coord_t>(m_qxMin), static_cast<Mantid::coord_t>(m_qxMax), m_nbinsx));
MDHistoDimension_sptr qzDim = MDHistoDimension_sptr(new MDHistoDimension("Qz","qz","(Ang^-1)", static_cast<Mantid::coord_t>(m_qzMin), static_cast<Mantid::coord_t>(m_qzMax), m_nbinsz));
MDHistoDimension_sptr qxDim = MDHistoDimension_sptr(
new MDHistoDimension("Qx", "qx", "(Ang^-1)", static_cast<Mantid::coord_t>(m_qxMin),
static_cast<Mantid::coord_t>(m_qxMax), m_nbinsx));
MDHistoDimension_sptr qzDim = MDHistoDimension_sptr(
new MDHistoDimension("Qz", "qz", "(Ang^-1)", static_cast<Mantid::coord_t>(m_qzMin),
static_cast<Mantid::coord_t>(m_qzMax), m_nbinsz));

auto ws = createMDWorkspace(qxDim, qzDim, boxController);

auto spectraAxis = inputWs->getAxis(1);
for(size_t index = 0; index < inputWs->getNumberHistograms(); ++index)
for (size_t index = 0; index < inputWs->getNumberHistograms(); ++index)
{
auto counts = inputWs->readY(index);
auto wavelengths = inputWs->readX(index);
auto errors = inputWs->readE(index);
const size_t nInputBins = wavelengths.size() -1;
const size_t nInputBins = wavelengths.size() - 1;
const double theta_final = spectraAxis->getValue(index);
m_QxCalculation.setThetaFinal(theta_final);
m_QzCalculation.setThetaFinal(theta_final);
//Loop over all bins in spectra
for(size_t binIndex = 0; binIndex < nInputBins; ++binIndex)
for (size_t binIndex = 0; binIndex < nInputBins; ++binIndex)
{
const double& wavelength = 0.5*(wavelengths[binIndex] + wavelengths[binIndex+1]);
const double& wavelength = 0.5 * (wavelengths[binIndex] + wavelengths[binIndex + 1]);
double _qx = m_QxCalculation.execute(wavelength);
double _qz = m_QzCalculation.execute(wavelength);
double centers[2] = {_qx, _qz};
double centers[2] =
{ _qx, _qz };

ws->addEvent(MDLeanEvent<2>(float(counts[binIndex]), float(errors[binIndex]*errors[binIndex]), centers));
ws->addEvent(
MDLeanEvent<2>(float(counts[binIndex]), float(errors[binIndex] * errors[binIndex]),
centers));
}
}
ws->splitAllIfNeeded(NULL);
ws->refreshCache();
return ws;
}

/**
* Execute the transformation. Generates an output Matrix workspace.
* @param inputWs : Input workspace with a vertical axis of signed-theta and an x-axis of wavelength
* @return : A 2D workspace with qz on the vertical axis and qx on the horizontal axis.
*/
MatrixWorkspace_sptr ReflectometryTransformQxQz::execute(MatrixWorkspace_const_sptr inputWs) const
{
auto ws = boost::make_shared<Mantid::DataObjects::Workspace2D>();

ws->initialize(m_nbinsz, m_nbinsx, m_nbinsx); // Create the output workspace as a distribution

// Mapping so that qx and qz values calculated can be added to the matrix workspace at the correct index.
const double gradQx = (m_nbinsx / (m_qxMax - m_qxMin)); // The x - axis
const double gradQz = (m_nbinsz / (m_qzMax - m_qzMin)); // Actually the y-axis
const double cx = -gradQx * m_qxMin;
const double cz = -gradQz * m_qzMin;

// Create an X - Axis.
Axis* const xAxis = new NumericAxis(m_nbinsx);
ws->replaceAxis(0, xAxis);
xAxis->unit() = UnitFactory::Instance().create("MomentumTransfer");
xAxis->title() = "Qx";
MantidVec xAxisVec(m_nbinsx);
for (int i = 0; i < m_nbinsx; ++i)
{
double qxIncrement = (1 / gradQx) * i;
xAxis->setValue(i, qxIncrement);
xAxisVec[i] = qxIncrement;
}

// Create a Y (vertical) Axis
Axis* const verticalAxis = new NumericAxis(m_nbinsx);
ws->replaceAxis(1, verticalAxis);
verticalAxis->unit() = UnitFactory::Instance().create("MomentumTransfer");
verticalAxis->title() = "Qz";
for (int i = 0; i < m_nbinsz; ++i)
{
ws->setX(i, xAxisVec);
double qzIncrement = (1 / gradQz) * i;
verticalAxis->setValue(i, qzIncrement);
}

// Loop over all entries in the input workspace and calculate qx and qz for each.
auto spectraAxis = inputWs->getAxis(1);
for (size_t index = 0; index < inputWs->getNumberHistograms(); ++index)
{
auto counts = inputWs->readY(index);
auto wavelengths = inputWs->readX(index);
auto errors = inputWs->readE(index);
const size_t nInputBins = wavelengths.size() - 1;
const double theta_final = spectraAxis->getValue(index);
m_QxCalculation.setThetaFinal(theta_final);
m_QzCalculation.setThetaFinal(theta_final);
//Loop over all bins in spectra
for (size_t binIndex = 0; binIndex < nInputBins; ++binIndex)
{
const double& wavelength = 0.5 * (wavelengths[binIndex] + wavelengths[binIndex + 1]);
const double _qx = m_QxCalculation.execute(wavelength);
const double _qz = m_QzCalculation.execute(wavelength);

if (_qx >= m_qxMin && _qx <= m_qxMax && _qz >= m_qzMin && _qz <= m_qzMax) // Check that the calculated qx and qz are in range
{
const int outIndexX = (gradQx * _qx) + cx;
const int outIndexZ = (gradQz * _qz) + cz;

ws->dataY(outIndexZ)[outIndexX] += counts[binIndex];
ws->dataE(outIndexZ)[outIndexX] += errors[binIndex];
}
}
}
return ws;
}

} // namespace Mantid
} // namespace MDEvents

0 comments on commit 1a91541

Please sign in to comment.