Skip to content

Commit

Permalink
Merge pull request #220 from mantidproject/feature/11056_create_peak_hkl
Browse files Browse the repository at this point in the history
Corrupted state DataObject::Peak
  • Loading branch information
martyngigg committed Feb 19, 2015
2 parents 3272eac + f42f48d commit a851158
Show file tree
Hide file tree
Showing 33 changed files with 719 additions and 75 deletions.
5 changes: 3 additions & 2 deletions Code/Mantid/Framework/API/inc/MantidAPI/IPeak.h
Expand Up @@ -7,6 +7,7 @@
#include "MantidKernel/Matrix.h"
#include "MantidKernel/V3D.h"
#include "MantidKernel/PhysicalConstants.h"
#include <boost/optional.hpp>

namespace Mantid {
namespace API {
Expand Down Expand Up @@ -50,9 +51,9 @@ class MANTID_API_DLL IPeak {
virtual bool findDetector() = 0;

virtual void setQSampleFrame(Mantid::Kernel::V3D QSampleFrame,
double detectorDistance = 1.0) = 0;
boost::optional<double> detectorDistance) = 0;
virtual void setQLabFrame(Mantid::Kernel::V3D QLabFrame,
double detectorDistance = 1.0) = 0;
boost::optional<double> detectorDistance) = 0;

virtual void setWavelength(double wavelength) = 0;
virtual double getWavelength() const = 0;
Expand Down
15 changes: 12 additions & 3 deletions Code/Mantid/Framework/API/inc/MantidAPI/IPeaksWorkspace.h
Expand Up @@ -7,6 +7,7 @@
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/ExperimentInfo.h"
#include "MantidKernel/SpecialCoordinateSystem.h"
#include <boost/optional.hpp>

namespace Mantid {

Expand Down Expand Up @@ -98,12 +99,20 @@ class MANTID_API_DLL IPeaksWorkspace : public ITableWorkspace,

//---------------------------------------------------------------------------------------------
/** Create an instance of a Peak
* @param QLabFrame :: Q of the center of the peak, in reciprocal space
* @param detectorDistance :: distance between the sample and the detector.
* @param QLabFrame :: Q of the center of the peak in the lab frame, in reciprocal space
* @param detectorDistance :: Optional distance between the sample and the detector. Calculated if not provided.
* @return a pointer to a new Peak object.
*/
virtual IPeak *createPeak(Mantid::Kernel::V3D QLabFrame,
double detectorDistance = 1.0) const = 0;
boost::optional<double> detectorDistance) const = 0;


/**
* Create an instance of a peak using a V3D
* @param HKL V3D
* @return a pointer to a new Peak object.
*/
virtual IPeak *createPeakHKL(Mantid::Kernel::V3D HKL) const = 0;

//---------------------------------------------------------------------------------------------
/** Determine if the workspace has been integrated using a peaks integration
Expand Down
4 changes: 2 additions & 2 deletions Code/Mantid/Framework/API/test/MockObjects.h
Expand Up @@ -103,9 +103,9 @@ namespace
MOCK_METHOD0(findDetector,
bool());
MOCK_METHOD2(setQSampleFrame,
void(Mantid::Kernel::V3D QSampleFrame, double detectorDistance));
void(Mantid::Kernel::V3D QSampleFrame, boost::optional<double> detectorDistance));
MOCK_METHOD2(setQLabFrame,
void(Mantid::Kernel::V3D QLabFrame, double detectorDistance));
void(Mantid::Kernel::V3D QLabFrame, boost::optional<double> detectorDistance));
MOCK_METHOD1(setWavelength,
void(double wavelength));
MOCK_CONST_METHOD0(getWavelength,
Expand Down
Expand Up @@ -396,7 +396,7 @@ Instrument_sptr CreateSampleWorkspace::createTestInstrumentRectangular(
int num_banks, int pixels, double pixelSpacing) {
boost::shared_ptr<Instrument> testInst(new Instrument("basic_rect"));
testInst->setReferenceFrame(
boost::shared_ptr<ReferenceFrame>(new ReferenceFrame(Y, X, Left, "")));
boost::shared_ptr<ReferenceFrame>(new ReferenceFrame(Y, Z, Left, "")));

const double cylRadius(pixelSpacing / 2);
const double cylHeight(0.0002);
Expand Down
3 changes: 3 additions & 0 deletions Code/Mantid/Framework/Crystal/CMakeLists.txt
@@ -1,5 +1,6 @@

set ( SRC_FILES
src/AddPeakHKL.cpp
src/AnvredCorrection.cpp
src/CalculatePeaksHKL.cpp
src/CalculateUMatrix.cpp
Expand Down Expand Up @@ -69,6 +70,7 @@ set ( SRC_FILES

set ( SRC_UNITY_IGNORE_FILES )
set ( INC_FILES
inc/MantidCrystal/AddPeakHKL.h
inc/MantidCrystal/AnvredCorrection.h
inc/MantidCrystal/BackgroundStrategy.h
inc/MantidCrystal/CalculatePeaksHKL.h
Expand Down Expand Up @@ -140,6 +142,7 @@ set ( INC_FILES
)

set ( TEST_FILES
AddPeakHKLTest.h
AnvredCorrectionTest.h
CalculatePeaksHKLTest.h
CalculateUMatrixTest.h
Expand Down
56 changes: 56 additions & 0 deletions Code/Mantid/Framework/Crystal/inc/MantidCrystal/AddPeakHKL.h
@@ -0,0 +1,56 @@
#ifndef MANTID_CRYSTAL_ADDPEAKHKL_H_
#define MANTID_CRYSTAL_ADDPEAKHKL_H_

#include "MantidKernel/System.h"
#include "MantidAPI/Algorithm.h"

namespace Mantid
{
namespace Crystal
{

/** AddPeakHKL : Algorithm to add a peaks to a PeaksWorkspace in the HKL frame
Copyright &copy; 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source
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 AddPeakHKL : public API::Algorithm
{
public:
AddPeakHKL();
virtual ~AddPeakHKL();

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

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


};


} // namespace Crystal
} // namespace Mantid

#endif /* MANTID_CRYSTAL_ADDPEAKHKL_H_ */
74 changes: 74 additions & 0 deletions Code/Mantid/Framework/Crystal/src/AddPeakHKL.cpp
@@ -0,0 +1,74 @@
#include "MantidCrystal/AddPeakHKL.h"
#include "MantidAPI/IPeaksWorkspace.h"
#include "MantidAPI/IPeak.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/ArrayLengthValidator.h"
#include "MantidKernel/V3D.h"

namespace Mantid
{
namespace Crystal
{

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

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



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

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


//----------------------------------------------------------------------------------------------

/// Algorithms name for identification. @see Algorithm::name
const std::string AddPeakHKL::name() const { return "AddPeakHKL"; }

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

/// Algorithm's category for identification. @see Algorithm::category
const std::string AddPeakHKL::category() const { return "Crystal";}

/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
const std::string AddPeakHKL::summary() const { return "Add a peak in the hkl frame";};

//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void AddPeakHKL::init()
{
declareProperty(new WorkspaceProperty<Mantid::API::IPeaksWorkspace>("Workspace","",Direction::InOut), "An input workspace.");
declareProperty(new ArrayProperty<double>("HKL", boost::make_shared<ArrayLengthValidator<double> > (3)), "HKL point to add");
}

//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void AddPeakHKL::exec()
{
IPeaksWorkspace_sptr peakWS = this->getProperty("Workspace");
const std::vector<double> hklValue = this->getProperty("HKL");
IPeak * peak = peakWS->createPeakHKL(V3D(hklValue[0], hklValue[1], hklValue[2]));
peakWS->addPeak(*peak);
delete peak;
}



} // namespace Crystal
} // namespace Mantid
2 changes: 1 addition & 1 deletion Code/Mantid/Framework/Crystal/src/PredictPeaks.cpp
Expand Up @@ -145,7 +145,7 @@ void PredictPeaks::doHKL(const double h, const double k, const double l,
PARALLEL_CRITICAL(PredictPeaks_numInRange) { numInRange++; }

// Create the peak using the Q in the lab framewith all its info:
Peak p(inst, q);
Peak p(inst, q, boost::optional<double>());
if (p.findDetector()) {
// Only add peaks that hit the detector
p.setGoniometerMatrix(gonio);
Expand Down
112 changes: 112 additions & 0 deletions Code/Mantid/Framework/Crystal/test/AddPeakHKLTest.h
@@ -0,0 +1,112 @@
#ifndef MANTID_CRYSTAL_ADDPEAKHKLTEST_H_
#define MANTID_CRYSTAL_ADDPEAKHKLTEST_H_

#include <cxxtest/TestSuite.h>
#include "MantidCrystal/AddPeakHKL.h"
#include "MantidKernel/V3D.h"
#include "MantidAPI/AnalysisDataService.h"
#include "MantidDataObjects/PeaksWorkspace.h"
#include "MantidGeometry/Crystal/OrientedLattice.h"
#include "MantidTestHelpers/ComponentCreationHelper.h"

using Mantid::Crystal::AddPeakHKL;
using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::DataObjects;

class AddPeakHKLTest : 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 AddPeakHKLTest *createSuite() { return new AddPeakHKLTest(); }
static void destroySuite( AddPeakHKLTest *suite ) { delete suite; }


void test_Init()
{
AddPeakHKL alg;
TS_ASSERT_THROWS_NOTHING( alg.initialize() )
TS_ASSERT( alg.isInitialized() )
}

void test_hkl_validation()
{
AddPeakHKL alg;
alg.initialize();
std::vector<double> hkl_bad(4); // Too big!
TS_ASSERT_THROWS( alg.setProperty("HKL", hkl_bad), std::invalid_argument& );

std::vector<double> hkl_good(3, 0); // Right size.
TS_ASSERT_THROWS_NOTHING( alg.setProperty("HKL", hkl_good) );
}


void test_exec()
{
// Create simple fictional instrument
const V3D source(0,0,0);
const V3D sample(15, 0, 0);
const V3D detectorPos(20, 5, 0);
const V3D beam1 = sample - source;
const V3D beam2 = detectorPos - sample;
auto minimalInstrument = ComponentCreationHelper::createMinimalInstrument( source, sample, detectorPos );

// Derive distances and angles
const double l1 = beam1.norm();
const double l2 = beam2.norm();
const V3D qLabDir = (beam1/l1) - (beam2/l2);

const double microSecsInSec = 1e6;

// Derive QLab for diffraction
const double wavenumber_in_angstrom_times_tof_in_microsec =
(Mantid::PhysicalConstants::NeutronMass * (l1 + l2) * 1e-10 * microSecsInSec) /
Mantid::PhysicalConstants::h_bar;
V3D qLab = qLabDir * wavenumber_in_angstrom_times_tof_in_microsec;

Mantid::Geometry::OrientedLattice orientedLattice(1, 1, 1, 90, 90, 90); // U is identity, real and reciprocal lattice vectors are identical.
Mantid::Geometry::Goniometer goniometer; // identity
V3D hkl = qLab / (2 * M_PI); // Given our settings above, this is the simplified relationship between qLab and hkl.

// Now create a peaks workspace around the simple fictional instrument
PeaksWorkspace_sptr ws = boost::make_shared<PeaksWorkspace>();
ws->setInstrument(minimalInstrument);
ws->mutableSample().setOrientedLattice(&orientedLattice);
ws->mutableRun().setGoniometer(goniometer, false);

AddPeakHKL alg;
alg.setChild(true);
alg.initialize();
std::vector<double> hklVec;
hklVec.push_back(hkl.X());
hklVec.push_back(hkl.Y());
hklVec.push_back(hkl.Z());
alg.setProperty("HKL", hklVec);
alg.setProperty("Workspace", ws);
alg.execute();
IPeaksWorkspace_sptr ws_out = alg.getProperty("Workspace");

// Get the peak just added.
const IPeak& peak =ws_out->getPeak(0);

/*
Now we check we have made a self - consistent peak
*/
TSM_ASSERT_EQUALS("New peak should have HKL we demanded.", hkl, peak.getHKL());
TSM_ASSERT_EQUALS("New peak should have QLab we expected.", qLab, peak.getQLabFrame());
TSM_ASSERT_EQUALS("QSample and QLab should be identical given the identity goniometer settings.", peak.getQLabFrame(), peak.getQSampleFrame());
auto detector = peak.getDetector();
TSM_ASSERT("No detector", detector);
TSM_ASSERT_EQUALS("This detector id does not match what we expect from the instrument definition", 1, detector->getID());
TSM_ASSERT_EQUALS("Thie detector position is wrong", detectorPos, detector->getPos());
TSM_ASSERT_EQUALS("Goniometer has not been set properly", goniometer.getR(), peak.getGoniometerMatrix());

}



};


#endif /* MANTID_CRYSTAL_ADDPEAKHKLTEST_H_ */
2 changes: 1 addition & 1 deletion Code/Mantid/Framework/Crystal/test/IndexSXPeaksTest.h
Expand Up @@ -120,7 +120,7 @@ class IndexSXPeaksTest : public CxxTest::TestSuite
{
IPeak& peak = m_masterPeaks->getPeak(i);
Mantid::Kernel::V3D v(1, 0, 0);
peak.setQSampleFrame(v); // Overwrite all Q samples to be co-linear.
peak.setQSampleFrame(v, boost::optional<double>()); // Overwrite all Q samples to be co-linear.
}

TS_ASSERT_THROWS(doTest(6, "1, 2, 3, 4, 5, 6", 14.131, 19.247, 8.606, 90.0, 105.071, 90.0), std::runtime_error);
Expand Down
4 changes: 2 additions & 2 deletions Code/Mantid/Framework/Crystal/test/PeaksOnSurfaceTest.h
Expand Up @@ -33,7 +33,7 @@ class PeaksOnSurfaceTest : public CxxTest::TestSuite
Mantid::Kernel::V3D position;
if(coordFrame == "Q (lab frame)")
{
peak.setQLabFrame(peakPosition);
peak.setQLabFrame(peakPosition,1/*set the detector distance explicitly*/);
}
else
{
Expand Down Expand Up @@ -374,4 +374,4 @@ class PeaksOnSurfaceTestPerformance : public CxxTest::TestSuite
}
};

#endif /* MANTID_CRYSTAL_PEAKSONSURFACETEST_H_ */
#endif /* MANTID_CRYSTAL_PEAKSONSURFACETEST_H_ */

0 comments on commit a851158

Please sign in to comment.