PredictSatellitePeaks.cpp 10.3 KB
Newer Older
1
2
3
/*
* PredictSatellitePeaks.cpp
*
4
5
*  Created on: July 15, 2018
*      Author: Vickie Lynch
6
7
8
9
10
11
12
13
14
15
*/
#include "MantidCrystal/PredictSatellitePeaks.h"
#include "MantidAPI/Sample.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidDataObjects/PeaksWorkspace.h"
#include "MantidGeometry/Crystal/OrientedLattice.h"
#include "MantidGeometry/Objects/InstrumentRayTracer.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/ArrayLengthValidator.h"
#include "MantidKernel/EnabledWhenProperty.h"
16
#include "MantidAPI/Run.h"
17
18
#include "MantidGeometry/Crystal/BasicHKLFilters.h"
#include "MantidGeometry/Crystal/HKLGenerator.h"
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <boost/math/special_functions/round.hpp>

namespace Mantid {
using namespace Mantid::DataObjects;
using namespace Mantid::API;
using namespace std;
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
namespace Crystal {

DECLARE_ALGORITHM(PredictSatellitePeaks)

/// Initialise the properties
void PredictSatellitePeaks::init() {
  declareProperty(
      make_unique<WorkspaceProperty<PeaksWorkspace>>("Peaks", "",
                                                     Direction::Input),
      "Workspace of Peaks with orientation matrix that indexed the peaks and "
      "instrument loaded");

  declareProperty(
      make_unique<WorkspaceProperty<PeaksWorkspace>>("SatellitePeaks", "",
                                                     Direction::Output),
      "Workspace of Peaks with peaks with fractional h,k, and/or l values");
  declareProperty(Kernel::make_unique<Kernel::ArrayProperty<double>>(
Lynch, Vickie's avatar
Lynch, Vickie committed
44
45
                      string("ModVector1"), "0.0,0.0,0.0"),
                  "Offsets for h, k, l directions ");
46
  declareProperty(Kernel::make_unique<Kernel::ArrayProperty<double>>(
Lynch, Vickie's avatar
Lynch, Vickie committed
47
48
                      string("ModVector2"), "0.0,0.0,0.0"),
                  "Offsets for h, k, l directions ");
49
  declareProperty(Kernel::make_unique<Kernel::ArrayProperty<double>>(
Lynch, Vickie's avatar
Lynch, Vickie committed
50
51
                      string("ModVector3"), "0.0,0.0,0.0"),
                  "Offsets for h, k, l directions ");
Lynch, Vickie's avatar
Lynch, Vickie committed
52
53
54
  declareProperty(
      make_unique<PropertyWithValue<int>>("MaxOrder", 0, Direction::Input),
      "Maximum order to apply ModVectors. Default = 0");
55
56

  declareProperty(
Lynch, Vickie's avatar
Lynch, Vickie committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
      "IncludeIntegerHKL", true,
      "If false order 0 peaks are not included in workspace (integer HKL)");

  declareProperty("IncludeAllPeaksInRange", false, "If false only offsets from "
                                                   "peaks from Peaks workspace "
                                                   "in input are used");

  declareProperty(make_unique<PropertyWithValue<double>>("WavelengthMin", 0.1,
                                                         Direction::Input),
                  "Minimum wavelength limit at which to start looking for "
                  "single-crystal peaks.");
  declareProperty(make_unique<PropertyWithValue<double>>("WavelengthMax", 100.0,
                                                         Direction::Input),
                  "Maximum wavelength limit at which to start looking for "
                  "single-crystal peaks.");
  declareProperty(make_unique<PropertyWithValue<double>>("MinDSpacing", 0.1,
                                                         Direction::Input),
                  "Minimum d-spacing of peaks to consider. Default = 1.0");
  declareProperty(make_unique<PropertyWithValue<double>>("MaxDSpacing", 100.0,
                                                         Direction::Input),
                  "Maximum d-spacing of peaks to consider");
78
79

  setPropertySettings(
Lynch, Vickie's avatar
Lynch, Vickie committed
80
81
82
      "WavelengthMin",
      Kernel::make_unique<Kernel::EnabledWhenProperty>(
          string("IncludeAllPeaksInRange"), Kernel::IS_EQUAL_TO, "1"));
83
84

  setPropertySettings(
Lynch, Vickie's avatar
Lynch, Vickie committed
85
86
87
      "WavelengthMax",
      Kernel::make_unique<Kernel::EnabledWhenProperty>(
          string("IncludeAllPeaksInRange"), Kernel::IS_EQUAL_TO, "1"));
88
  setPropertySettings(
Lynch, Vickie's avatar
Lynch, Vickie committed
89
90
91
      "MinDSpacing",
      Kernel::make_unique<Kernel::EnabledWhenProperty>(
          string("IncludeAllPeaksInRange"), Kernel::IS_EQUAL_TO, "1"));
92
93

  setPropertySettings(
Lynch, Vickie's avatar
Lynch, Vickie committed
94
95
96
      "MaxDSpacing",
      Kernel::make_unique<Kernel::EnabledWhenProperty>(
          string("IncludeAllPeaksInRange"), Kernel::IS_EQUAL_TO, "1"));
97
98
99
100
101
102
103
104
105
}

/// Run the algorithm
void PredictSatellitePeaks::exec() {
  PeaksWorkspace_sptr Peaks = getProperty("Peaks");
  if (!Peaks)
    throw std::invalid_argument(
        "Input workspace is not a PeaksWorkspace. Type=" + Peaks->id());

106
107
108
109
  V3D offsets1 = getOffsetVector("ModVector1");
  std::cout << offsets1<<"\n";
  V3D offsets2 = getOffsetVector("ModVector2");
  V3D offsets3 = getOffsetVector("ModVector3");
Lynch, Vickie's avatar
Lynch, Vickie committed
110
  int maxOrder = getProperty("MaxOrder");
111
112

  bool includePeaksInRange = getProperty("IncludeAllPeaksInRange");
113
  bool includeOrderZero = getProperty("IncludeIntegerHKL");
114
115
116
117
118
119

  if (Peaks->getNumberPeaks() <= 0) {
    g_log.error() << "There are No peaks in the input PeaksWorkspace\n";
    return;
  }

120
  API::Sample sample = Peaks->mutableSample();
121

122
  OrientedLattice lattice = sample.getOrientedLattice();
123

124
  const auto instrument = Peaks->getInstrument();
125
126
127

  auto OutPeaks = boost::dynamic_pointer_cast<IPeaksWorkspace>(
      WorkspaceFactory::Instance().createPeaks());
128
  OutPeaks->setInstrument(instrument);
129
  OutPeaks->mutableSample().setOrientedLattice(&lattice);
130
131
132
133

  V3D hkl;
  int peakNum = 0;
  const auto NPeaks = Peaks->getNumberPeaks();
134
135
  Kernel::Matrix<double> goniometer;
  goniometer.identityMatrix();
136

137
138
  const double lambdaMin = getProperty("WavelengthMin");
  const double lambdaMax = getProperty("WavelengthMax");
139
140
  IPeak &peak0 = Peaks->getPeak(0);

141
142
143
144
  std::vector<V3D> possibleHKLs;
  if (includePeaksInRange) {
    const double dMin = getProperty("MinDSpacing");
    const double dMax = getProperty("MaxDSpacing");
145
146
    Geometry::HKLGenerator gen(lattice, dMin);
    auto filter = boost::make_shared<HKLFilterDRange>(lattice, dMin, dMax);
Lynch, Vickie's avatar
Lynch, Vickie committed
147

148
149
    V3D hkl = *(gen.begin());
    g_log.information() << "HKL range for d_min of " << dMin << " to d_max of "
Lynch, Vickie's avatar
Lynch, Vickie committed
150
151
152
153
154
155
156
157
158
159
                        << dMax << " is from " << hkl << " to " << hkl * -1.0
                        << ", a total of " << gen.size() << " possible HKL's\n";
    if (gen.size() > 10000000000)
      throw std::invalid_argument("More than 10 billion HKLs to search. Is "
                                  "your d_min value too small?");

    possibleHKLs.clear();
    possibleHKLs.reserve(gen.size());
    std::remove_copy_if(gen.begin(), gen.end(),
                        std::back_inserter(possibleHKLs), (~filter)->fn());
160
161
162
163
164
165
  } else {
    hkl[0] = peak0.getH();
    hkl[1] = peak0.getK();
    hkl[2] = peak0.getL();
  }

Lynch, Vickie's avatar
Lynch, Vickie committed
166
  size_t N = NPeaks * (1 + 2 * maxOrder);
167
168
169
170
  if (includePeaksInRange) {
    N = possibleHKLs.size();
    N = max<size_t>(100, N);
  }
171
172
  auto &UB = lattice.getUB();
  goniometer = peak0.getGoniometerMatrix();
173
  Progress prog(this, 0.0, 1.0, N);
174
175
  vector<vector<int>> AlreadyDonePeaks;
  bool done = false;
176
  DblMatrix orientedUB = goniometer * UB;
177
  HKLFilterWavelength lambdaFilter(orientedUB, lambdaMin, lambdaMax);
Lynch, Vickie's avatar
Lynch, Vickie committed
178
  int seqNum = 0;
179
  size_t next = 0;
180
  while (!done) {
181
182
183
184
185
186
187
188
189
190
191
192
    predictOffsets(Peaks, OutPeaks, offsets1, maxOrder, peakNum,
                   lambdaFilter, includePeaksInRange,
                   includeOrderZero, seqNum, AlreadyDonePeaks);
    OutPeaks->mutableRun().addProperty<std::vector<double>>("Offset1", offsets1, true);
    predictOffsets(Peaks, OutPeaks, offsets2, maxOrder, peakNum,
                   lambdaFilter, includePeaksInRange,
                   includeOrderZero, seqNum, AlreadyDonePeaks);
    OutPeaks->mutableRun().addProperty<std::vector<double>>("Offset2", offsets2, true);
    predictOffsets(Peaks, OutPeaks, offsets3, maxOrder, peakNum,
                   lambdaFilter, includePeaksInRange,
                   includeOrderZero, seqNum, AlreadyDonePeaks);
    OutPeaks->mutableRun().addProperty<std::vector<double>>("Offset3", offsets3, true);
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
    if (includePeaksInRange) {
      next++;
      if (next == possibleHKLs.size())
        break;
      hkl = possibleHKLs[next];
    } else {
      peakNum++;
      if (peakNum >= NPeaks)
        done = true;
    }
    prog.report();
  }

  setProperty("SatellitePeaks", OutPeaks);
}

Lynch, Vickie's avatar
Lynch, Vickie committed
209
210
211
void PredictSatellitePeaks::predictOffsets(
    DataObjects::PeaksWorkspace_sptr Peaks,
    boost::shared_ptr<Mantid::API::IPeaksWorkspace> &OutPeaks,
212
    V3D offsets, int &maxOrder, int &peakNum,
Lynch, Vickie's avatar
Lynch, Vickie committed
213
    HKLFilterWavelength &lambdaFilter, bool &includePeaksInRange,
214
    bool &includeOrderZero, int &seqNum,
Lynch, Vickie's avatar
Lynch, Vickie committed
215
    vector<vector<int>> &AlreadyDonePeaks) {
216
217
218
219
220
221
222
223
  const Kernel::DblMatrix &UB = Peaks->sample().getOrientedLattice().getUB();
  IPeak &peak1 = Peaks->getPeak(peakNum);
  V3D hkl;
  hkl[0] = peak1.getH();
  hkl[1] = peak1.getK();
  hkl[2] = peak1.getL();
  Kernel::Matrix<double> goniometer = peak1.getGoniometerMatrix();
  auto RunNumber = peak1.getRunNumber();
224
  Geometry::InstrumentRayTracer tracer(Peaks->getInstrument());
Lynch, Vickie's avatar
Lynch, Vickie committed
225
226
227
  for (int order = -maxOrder; order <= maxOrder; order++) {
    if (order == 0 && !includeOrderZero)
      continue; // exclude order 0
228
    V3D satelliteHKL(hkl);
Lynch, Vickie's avatar
Lynch, Vickie committed
229

230
231
    satelliteHKL += offsets * order;
    if (!lambdaFilter.isAllowed(satelliteHKL) && includePeaksInRange)
Lynch, Vickie's avatar
Lynch, Vickie committed
232
      continue;
233

234
    Kernel::V3D Qs = goniometer * UB * satelliteHKL * 2.0 * M_PI;
Lynch, Vickie's avatar
Lynch, Vickie committed
235

236
    // Check if Q is non-physical
Lynch, Vickie's avatar
Lynch, Vickie committed
237
238
239
    if (Qs[2] <= 0)
      continue;

240
    auto peak(Peaks->createPeak(Qs, 1));
Lynch, Vickie's avatar
Lynch, Vickie committed
241

242
    peak->setGoniometerMatrix(goniometer);
Lynch, Vickie's avatar
Lynch, Vickie committed
243

244
245
246
247
    if (peak->findDetector(tracer)) {
      vector<int> SavPk{RunNumber, boost::math::iround(1000.0 * satelliteHKL[0]),
                        boost::math::iround(1000.0 * satelliteHKL[1]),
                        boost::math::iround(1000.0 * satelliteHKL[2])};
Lynch, Vickie's avatar
Lynch, Vickie committed
248

249
      auto it = find(AlreadyDonePeaks.begin(), AlreadyDonePeaks.end(), SavPk);
Lynch, Vickie's avatar
Lynch, Vickie committed
250

251
252
253
254
255
      if (it == AlreadyDonePeaks.end()) {
        AlreadyDonePeaks.push_back(SavPk);
        std::sort(AlreadyDonePeaks.begin(), AlreadyDonePeaks.end());
      } else {
        continue;
Lynch, Vickie's avatar
Lynch, Vickie committed
256
      }
257
258
259
260
261
262
263
264

      peak->setHKL(satelliteHKL);
      peak->setIntHKL(hkl);
      peak->setPeakNumber(seqNum);
      seqNum++;
      peak->setRunNumber(RunNumber);
      peak->setIntMNP(V3D(order, 0, 0));
      OutPeaks->addPeak(*peak);
Lynch, Vickie's avatar
Lynch, Vickie committed
265
    }
Lynch, Vickie's avatar
Lynch, Vickie committed
266
  }
267
268
}

269
270
271
272
273
274
275
276
277
278
279
V3D PredictSatellitePeaks::getOffsetVector(const std::string &label) {
  vector<double> offsets = getProperty(label);
  if (offsets.empty()) {
    offsets.push_back(0.0);
    offsets.push_back(0.0);
    offsets.push_back(0.0);
  }
  V3D offsets1 = V3D(offsets[0],offsets[1], offsets[2]);
  return offsets1;
}

280
281
} // namespace Crystal
} // namespace Mantid