CentroidPeaksMD.cpp 6.79 KB
Newer Older
1
2
3
4
5
6
7
/*WIKI* 


This algorithm starts with a PeaksWorkspace containing the expected positions of peaks in reciprocal space. It calculates the centroid of the peak by calculating the average of the coordinates of all events within a given radius of the peak, weighted by the weight (signal) of the event.


*WIKI*/
8
9
#include "MantidKernel/System.h"
#include "MantidKernel/ListValidator.h"
10
11
12
13
#include "MantidAPI/IMDEventWorkspace.h"
#include "MantidDataObjects/PeaksWorkspace.h"
#include "MantidMDEvents/CoordTransformDistance.h"
#include "MantidMDEvents/MDEventFactory.h"
14
15
16
#include "MantidMDAlgorithms/IntegratePeaksMD.h"
#include "MantidMDAlgorithms/CentroidPeaksMD.h"

17
18

using Mantid::DataObjects::PeaksWorkspace;
19
20
21

namespace Mantid
{
22
namespace MDAlgorithms
23
24
25
{

  // Register the algorithm into the AlgorithmFactory
26
  DECLARE_ALGORITHM(CentroidPeaksMD)
27
28
  
  using namespace Mantid::API;
29
30
31
32
  using namespace Mantid::DataObjects;
  using namespace Mantid::Geometry;
  using namespace Mantid::Kernel;
  using namespace Mantid::MDEvents;
33
34
35
36
37


  //----------------------------------------------------------------------------------------------
  /** Constructor
   */
38
  CentroidPeaksMD::CentroidPeaksMD()
39
40
41
42
43
44
  {
  }
    
  //----------------------------------------------------------------------------------------------
  /** Destructor
   */
45
  CentroidPeaksMD::~CentroidPeaksMD()
46
47
48
49
50
51
  {
  }
  

  //----------------------------------------------------------------------------------------------
  /// Sets documentation strings for this algorithm
52
  void CentroidPeaksMD::initDocs()
53
54
55
56
57
58
59
60
  {
    this->setWikiSummary("Find the centroid of single-crystal peaks in a MDEventWorkspace, in order to refine their positions.");
    this->setOptionalMessage("Find the centroid of single-crystal peaks in a MDEventWorkspace, in order to refine their positions.");
  }

  //----------------------------------------------------------------------------------------------
  /** Initialize the algorithm's properties.
   */
61
  void CentroidPeaksMD::init()
62
  {
63
64
65
    declareProperty(new WorkspaceProperty<IMDEventWorkspace>("InputWorkspace","",Direction::Input), "An input MDEventWorkspace.");

    std::vector<std::string> propOptions;
66
67
    propOptions.push_back("Q (lab frame)");
    propOptions.push_back("Q (sample frame)");
68
    propOptions.push_back("HKL");
69
    declareProperty("CoordinatesToUse", "HKL",boost::make_shared<StringListValidator>(propOptions),
70
71
72
73
74
75
      "Which coordinates of the peak center do you wish to use to find the center? This should match the InputWorkspace's dimensions."
       );

    declareProperty(new PropertyWithValue<double>("PeakRadius",1.0,Direction::Input),
        "Fixed radius around each peak position in which to calculate the centroid.");

76
77
78
79
80
81
    declareProperty(new WorkspaceProperty<PeaksWorkspace>("PeaksWorkspace","",Direction::Input),
        "A PeaksWorkspace containing the peaks to centroid.");

    declareProperty(new WorkspaceProperty<PeaksWorkspace>("OutputWorkspace","",Direction::Output),
        "The output PeaksWorkspace will be a copy of the input PeaksWorkspace "
        "with the peaks' positions modified by the new found centroids.");
82
83
84
  }

  //----------------------------------------------------------------------------------------------
85
86
  /** Integrate the peaks of the workspace using parameters saved in the algorithm class
   * @param ws ::  MDEventWorkspace to integrate
87
   */
88
  template<typename MDE, size_t nd>
89
  void CentroidPeaksMD::integrate(typename MDEventWorkspace<MDE, nd>::sptr ws)
90
  {
91
92
93
    if (nd != 3)
      throw std::invalid_argument("For now, we expect the input MDEventWorkspace to have 3 dimensions only.");

94
95
96
97
98
99
100
    /// Peak workspace to centroid
    Mantid::DataObjects::PeaksWorkspace_sptr inPeakWS = getProperty("PeaksWorkspace");

    /// Output peaks workspace, create if needed
    Mantid::DataObjects::PeaksWorkspace_sptr peakWS = getProperty("OutputWorkspace");
    if (peakWS != inPeakWS)
      peakWS = inPeakWS->clone();
101
102
103
104
105
106
107
108
109

    /// Value of the CoordinatesToUse property.
    std::string CoordinatesToUse = getPropertyValue("CoordinatesToUse");

    // TODO: Confirm that the coordinates requested match those in the MDEventWorkspace

    /// Radius to use around peaks
    double PeakRadius = getProperty("PeakRadius");

110
    // cppcheck-suppress syntaxError
111
112
113
114
    PRAGMA_OMP(parallel for schedule(dynamic, 10) )
    for (int i=0; i < int(peakWS->getNumberPeaks()); ++i)
    {
      // Get a direct ref to that peak.
115
      IPeak & p = peakWS->getPeak(i);
116
      double detectorDistance = p.getL2();
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

      // Get the peak center as a position in the dimensions of the workspace
      V3D pos;
      if (CoordinatesToUse == "Q (lab frame)")
        pos = p.getQLabFrame();
      else if (CoordinatesToUse == "Q (sample frame)")
        pos = p.getQSampleFrame();
      else if (CoordinatesToUse == "HKL")
        pos = p.getHKL();

      // Build the sphere transformation
      bool dimensionsUsed[nd];
      coord_t center[nd];
      for (size_t d=0; d<nd; ++d)
      {
        dimensionsUsed[d] = true; // Use all dimensions
133
        center[d] = static_cast<coord_t>(pos[d]);
134
135
136
137
      }
      CoordTransformDistance sphere(nd, center, dimensionsUsed);

      // Initialize the centroid to 0.0
138
      signal_t signal = 0;
139
140
141
142
143
      coord_t centroid[nd];
      for (size_t d=0; d<nd; d++)
        centroid[d] = 0.0;

      // Perform centroid
144
      ws->getBox()->centroidSphere(sphere, static_cast<coord_t>(PeakRadius*PeakRadius), centroid, signal);
145
146
147
148
149

      // Normalize by signal
      if (signal != 0.0)
      {
        for (size_t d=0; d<nd; d++)
150
          centroid[d] /= static_cast<coord_t>(signal);
151

152
153
154
155
        V3D vecCentroid(centroid[0], centroid[1], centroid[2]);

        // Save it back in the peak object, in the dimension specified.
        if (CoordinatesToUse == "Q (lab frame)")
156
        {
157
          p.setQLabFrame( vecCentroid, detectorDistance);
158
159
          p.findDetector();
        }
160
        else if (CoordinatesToUse == "Q (sample frame)")
161
        {
162
          p.setQSampleFrame( vecCentroid, detectorDistance);
163
164
          p.findDetector();
        }
165
        else if (CoordinatesToUse == "HKL")
166
        {
167
          p.setHKL( vecCentroid );
168
        }
169

170
171

        g_log.information() << "Peak " << i << " at " << pos << ": signal "
172
173
            << signal << ", centroid " << vecCentroid
            << " in " << CoordinatesToUse
174
175
176
177
178
179
180
181
182
            << std::endl;
      }
      else
      {
        g_log.information() << "Peak " << i << " at " << pos << " had no signal, and could not be centroided."
            << std::endl;
      }
    }

183
184
185
    // Save the output
    setProperty("OutputWorkspace", peakWS);

186
187
  }

188
189
190
  //----------------------------------------------------------------------------------------------
  /** Execute the algorithm.
   */
191
  void CentroidPeaksMD::exec()
192
193
  {
    inWS = getProperty("InputWorkspace");
194

195
    CALL_MDEVENT_FUNCTION3(this->integrate, inWS);
196
  }
197
198
199
200

} // namespace Mantid
} // namespace MDEvents