Skip to content

Commit

Permalink
refs #9389. New algorithm created.
Browse files Browse the repository at this point in the history
Basic destructive unit tests added.
  • Loading branch information
OwenArnold committed Apr 29, 2014
1 parent d79230e commit 5082076
Show file tree
Hide file tree
Showing 5 changed files with 465 additions and 2 deletions.
3 changes: 3 additions & 0 deletions Code/Mantid/Framework/Algorithms/CMakeLists.txt
Expand Up @@ -204,6 +204,7 @@ set ( SRC_FILES
src/SolidAngle.cpp
src/SortEvents.cpp
src/SpatialGrouping.cpp
src/SpecularReflectionPositionCorrect.cpp
src/SphericalAbsorption.cpp
src/StripPeaks.cpp
src/StripVanadiumPeaks.cpp
Expand Down Expand Up @@ -433,6 +434,7 @@ set ( INC_FILES
inc/MantidAlgorithms/SolidAngle.h
inc/MantidAlgorithms/SortEvents.h
inc/MantidAlgorithms/SpatialGrouping.h
inc/MantidAlgorithms/SpecularReflectionPositionCorrect.h
inc/MantidAlgorithms/SphericalAbsorption.h
inc/MantidAlgorithms/StripPeaks.h
inc/MantidAlgorithms/StripVanadiumPeaks.h
Expand Down Expand Up @@ -653,6 +655,7 @@ set ( TEST_FILES
SolidAngleTest.h
SortEventsTest.h
SpatialGroupingTest.h
SpecularReflectionPositionCorrectTest.h
SphericalAbsorptionTest.h
StripPeaksTest.h
StripVanadiumPeaks2Test.h
Expand Down
@@ -0,0 +1,71 @@
#ifndef MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT_H_
#define MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT_H_

#include "MantidKernel/System.h"
#include "MantidAPI/Algorithm.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidGeometry/Instrument.h"
#include "MantidGeometry/IComponent.h"
#include "MantidGeometry/IDetector.h"

namespace Mantid
{
namespace Algorithms
{

/** SpecularReflectionPositionCorrect : Algorithm to perform vertical position corrections based on the specular reflection condition.
Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://github.com/mantidproject/mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class DLLExport SpecularReflectionPositionCorrect: public API::Algorithm
{
public:
SpecularReflectionPositionCorrect();
virtual ~SpecularReflectionPositionCorrect();

virtual const std::string name() const;
virtual int version() const;
virtual const std::string category() const;

private:
virtual void initDocs();
void init();
void exec();

/// Get the surface sample component
Mantid::Geometry::IComponent_const_sptr getSurfaceSampleComponent(
Mantid::Geometry::Instrument_const_sptr inst);

/// Get the detector component
Mantid::Geometry::IComponent_const_sptr getDetectorComponent(
Mantid::API::MatrixWorkspace_sptr workspace, const bool isPointDetector);

/// Correct detector positions.
void correctPosition(API::MatrixWorkspace_sptr toCorrect, const double& thetaInDeg,
Geometry::IComponent_const_sptr sample, Geometry::IComponent_const_sptr detector);

bool isPropertyDefault(const std::string& propertyName) const;
};

} // namespace Algorithms
} // namespace Mantid

#endif /* MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT_H_ */
Expand Up @@ -30,8 +30,6 @@ parameters will be needed.
#include "MantidAPI/WorkspaceValidators.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/MandatoryValidator.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/EnabledWhenProperty.h"
#include "MantidKernel/RebinParamsValidator.h"
Expand Down
@@ -0,0 +1,285 @@
/*WIKI*
Uses the specular reflection condition along with a supplied theta value to vertically shift the detectors into a corrected location.
For LineDetectors and MultiDetectors, the algorithm uses an average of grouped detector locations to determine the detector position.
*WIKI*/

#include "MantidAlgorithms/SpecularReflectionPositionCorrect.h"
#include "MantidAPI/WorkspaceValidators.h"
#include "MantidKernel/ArrayBoundedValidator.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/CompositeValidator.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/MandatoryValidator.h"
#include "MantidGeometry/Instrument/DetectorGroup.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include <boost/make_shared.hpp>

using namespace Mantid::API;
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;

namespace Mantid
{
namespace Algorithms
{
namespace
{
const std::string multiDetectorAnalysis = "MultiDetectorAnalysis";
const std::string lineDetectorAnalysis = "LineDetectorAnalysis";
const std::string pointDetectorAnalysis = "PointDetectorAnalysis";
}

// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(SpecularReflectionPositionCorrect)

//----------------------------------------------------------------------------------------------
/** Constructor
*/
SpecularReflectionPositionCorrect::SpecularReflectionPositionCorrect()
{
}

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

//----------------------------------------------------------------------------------------------
/// Algorithm's name for identification. @see Algorithm::name
const std::string SpecularReflectionPositionCorrect::name() const
{
return "SpecularReflectionPositionCorrect";
}
;

/// Algorithm's version for identification. @see Algorithm::version
int SpecularReflectionPositionCorrect::version() const
{
return 1;
}
;

/// Algorithm's category for identification. @see Algorithm::category
const std::string SpecularReflectionPositionCorrect::category() const
{
return "Reflectometry\\ISIS";
}

//----------------------------------------------------------------------------------------------
/// Sets documentation strings for this algorithm
void SpecularReflectionPositionCorrect::initDocs()
{
this->setWikiSummary(
"Correct detector positions vertically based on the specular reflection condition.");
this->setOptionalMessage(this->getWikiSummary());
}

//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void SpecularReflectionPositionCorrect::init()
{
auto thetaValidator = boost::make_shared<CompositeValidator>();
thetaValidator->add(boost::make_shared<MandatoryValidator<double> >());
thetaValidator->add(boost::make_shared<BoundedValidator<double> >(0, 90, true));
declareProperty(new WorkspaceProperty<MatrixWorkspace>("InputWorkspace", "", Direction::Input),
"An input workspace to correct.");
declareProperty(
new PropertyWithValue<double>("ThetaIn", Mantid::EMPTY_DBL(), thetaValidator,
Direction::Input), "Input theta angle in degrees.");

std::vector<std::string> propOptions;
propOptions.push_back(pointDetectorAnalysis);
propOptions.push_back(lineDetectorAnalysis);
propOptions.push_back(multiDetectorAnalysis);

std::stringstream message;
message << "The type of analysis to perform. " << multiDetectorAnalysis << ", "
<< lineDetectorAnalysis << " or " << multiDetectorAnalysis;

declareProperty("AnalysisMode", pointDetectorAnalysis,
boost::make_shared<StringListValidator>(propOptions), message.str());

declareProperty(new PropertyWithValue<std::string>("DetectorComponentName", "", Direction::Input),
"Name of the detector component i.e. point-detector. If these are not specified, the algorithm will attempt lookup using a standard naming convention.");

auto boundedArrayValidator = boost::make_shared<ArrayBoundedValidator<int> >();
boundedArrayValidator->setLower(0);
declareProperty(new ArrayProperty<int>("SpectrumNumbersOfGroupedDetectors", boundedArrayValidator, Direction::Input),
"A list of spectrum numbers making up an effective point detector.");

declareProperty(new PropertyWithValue<std::string>("SampleComponentName", "", Direction::Input),
"Name of the sample component i.e. some-surface-holder. If these are not specified, the algorithm will attempt lookup using a standard naming convention.");

declareProperty(new WorkspaceProperty<MatrixWorkspace>("OutputWorkspace", "", Direction::Output),
"An output workspace.");
}

//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void SpecularReflectionPositionCorrect::exec()
{

MatrixWorkspace_sptr inWS = this->getProperty("InputWorkspace");
auto cloneWS = this->createChildAlgorithm("CloneWorkspace");
cloneWS->initialize();
cloneWS->setProperty("InputWorkspace", inWS);
cloneWS->execute();
Workspace_sptr tmp = cloneWS->getProperty("OutputWorkspace");
MatrixWorkspace_sptr outWS = boost::dynamic_pointer_cast<MatrixWorkspace>(tmp);

const double thetaIn = this->getProperty("ThetaIn");

auto instrument = outWS->getInstrument();
IComponent_const_sptr detector = this->getDetectorComponent(outWS, true); // HARDCODED
IComponent_const_sptr sample = this->getSurfaceSampleComponent(instrument);

correctPosition(outWS, thetaIn, sample, detector);

setProperty("OutputWorkspace", outWS);
}

/**
* Get the sample component. Use the name provided as a property as the basis for the lookup as a priority.
*
* Throws if the name is invalid.
* @param inst : Instrument to search through
* @return : The component : The component object found.
*/
Mantid::Geometry::IComponent_const_sptr SpecularReflectionPositionCorrect::getSurfaceSampleComponent(
Mantid::Geometry::Instrument_const_sptr inst)
{
std::string sampleComponent = "some-surface-holder";
if (!isPropertyDefault("SampleComponentName"))
{
sampleComponent = this->getPropertyValue("SampleComponentName");
}
auto searchResult = inst->getComponentByName(sampleComponent);
if (searchResult == NULL)
{
throw std::invalid_argument(sampleComponent + " does not exist. Check input properties.");
}
return searchResult;
}

/**
* Get the detector component. Use the name provided as a property as the basis for the lookup as a priority.
*
* Throws if the name is invalid.
* @param workspace : Workspace from instrument with detectors
* @param isPointDetector : True if this is a point detector. Used to guess a name.
* @return The component : The component object found.
*/
boost::shared_ptr<const Mantid::Geometry::IComponent> SpecularReflectionPositionCorrect::getDetectorComponent(
MatrixWorkspace_sptr workspace, const bool isPointDetector)
{
boost::shared_ptr<const IComponent> searchResult;
if (!isPropertyDefault("SpectrumNumbersOfGroupedDetectors"))
{
const std::vector<int> spectrumNumbers = getProperty("SpectrumNumbersOfGroupedDetectors");
auto specToWorkspaceIndex = workspace->getSpectrumToWorkspaceIndexMap();
DetectorGroup_sptr allDetectors;
bool warnIfMasked = true;
for (size_t i = 0; i < spectrumNumbers.size(); ++i)
{
const size_t& spectrumNumber = spectrumNumbers[i];
auto it = specToWorkspaceIndex.find(spectrumNumbers[i]);
if (it == specToWorkspaceIndex.end())
{
std::stringstream message;
message << "Spectrum number " << spectrumNumber << " does not exist in the InputWorkspace";
throw std::invalid_argument(message.str());
}
const size_t workspaceIndex = it->second;
auto detector = workspace->getDetector(workspaceIndex);
allDetectors->addDetector(detector, warnIfMasked);
}
searchResult = allDetectors;
}
else
{
Mantid::Geometry::Instrument_const_sptr inst = workspace->getInstrument();
std::string componentToCorrect = isPointDetector ? "point-detector" : "line-detector";

if (!isPropertyDefault("DetectorComponentName"))
{
componentToCorrect = this->getPropertyValue("DetectorComponentName");

}
searchResult = inst->getComponentByName(componentToCorrect);
if (searchResult == NULL)
{
throw std::invalid_argument(componentToCorrect + " does not exist. Check input properties.");
}
}

return searchResult;
}

/**
* Correct the position of the detectors based on the input theta value.
* @param toCorrect : Workspace to correct detector posisitions on.
* @param thetaInDeg : Theta in degrees to use in correction calculations.
* @param sample : Pointer to the sample
* @param detector : Pointer to a given detector
*/
void SpecularReflectionPositionCorrect::correctPosition(API::MatrixWorkspace_sptr toCorrect,
const double& thetaInDeg, IComponent_const_sptr sample, IComponent_const_sptr detector)
{

auto instrument = toCorrect->getInstrument();

const V3D detectorPosition = detector->getPos();

const V3D samplePosition = sample->getPos();

const V3D sampleToDetector = detectorPosition - samplePosition;

auto referenceFrame = instrument->getReferenceFrame();

const double sampleToDetectorAlongBeam = sampleToDetector.scalar_prod(
referenceFrame->vecPointingAlongBeam());

const double thetaInRad = thetaInDeg * (M_PI / 180.0);

double acrossOffset = 0;

double beamOffset = detectorPosition.scalar_prod(referenceFrame->vecPointingAlongBeam());

double upOffset = sampleToDetectorAlongBeam * std::sin(2.0 * thetaInRad);

auto moveComponentAlg = this->createChildAlgorithm("MoveInstrumentComponent");
moveComponentAlg->initialize();
moveComponentAlg->setProperty("Workspace", toCorrect);
moveComponentAlg->setProperty("ComponentName", detector->getName());
moveComponentAlg->setProperty("RelativePosition", false);
// Movements
moveComponentAlg->setProperty(referenceFrame->pointingAlongBeamAxis(), beamOffset);
moveComponentAlg->setProperty(referenceFrame->pointingHorizontalAxis(), acrossOffset);
moveComponentAlg->setProperty(referenceFrame->pointingUpAxis(), upOffset);
// Execute the movement.
moveComponentAlg->execute();

}

/**
* Determine if the property value is the same as the default value.
* This can be used to determine if the property has not been set.
* @param propertyName : Name of property to query
* @return: True only if the property has it's default value.
*/
bool SpecularReflectionPositionCorrect::isPropertyDefault(const std::string& propertyName) const
{
Property* property = this->getProperty(propertyName);
return property->isDefault();
}

} // namespace Algorithms
} // namespace Mantid

0 comments on commit 5082076

Please sign in to comment.