Mantid
Loading...
Searching...
No Matches
LoadIsawSpectrum.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8#include "MantidAPI/Axis.h"
18#include "MantidKernel/Unit.h"
20#include "MantidKernel/Utils.h"
21
22#include <fstream>
23
24using namespace Mantid::Geometry;
25using namespace Mantid::DataObjects;
26using namespace Mantid::Kernel;
27using namespace Mantid::API;
28using namespace Mantid::PhysicalConstants;
29
30namespace Mantid::Crystal {
31
32// Register the algorithm into the AlgorithmFactory
33DECLARE_ALGORITHM(LoadIsawSpectrum)
34
35
37void LoadIsawSpectrum::init() {
38 declareProperty(std::make_unique<FileProperty>("SpectraFile", "", API::FileProperty::Load, ".dat"),
39 "Incident spectrum and detector efficiency correction file.");
40 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
41 "An output Workspace containing spectra for each detector bank.");
42 // 3 properties for getting the right instrument
43 getInstrument3WaysInit(this);
44}
45
50
51 // If sample not at origin, shift cached positions.
52 const V3D samplePos = inst->getSample()->getPos();
53 const V3D pos = inst->getSource()->getPos() - samplePos;
54 double l1 = pos.norm();
55
56 std::string STRING;
57 std::ifstream infile;
58 std::string spectraFile = getPropertyValue("SpectraFile");
59 infile.open(spectraFile.c_str());
60
61 size_t a = -1;
62 std::vector<std::vector<double>> spectra;
63 std::vector<std::vector<double>> time;
64 int iSpec = 0;
65 for (int wi = 0; wi < 8; wi++)
66 getline(infile, STRING); // Saves the line in STRING.
67 while (!infile.eof()) // To get you all the lines.
68 {
69 time.resize(a + 1);
70 spectra.resize(a + 1);
71 getline(infile, STRING); // Saves the line in STRING.
72 if (infile.eof())
73 break;
74 std::stringstream ss(STRING);
75 if (STRING.find("Bank") == std::string::npos) {
76 double time0, spectra0;
77 ss >> time0 >> spectra0;
78 time[a].emplace_back(time0);
79 spectra[a].emplace_back(spectra0);
80
81 } else {
82 a++;
83 }
84 }
85 infile.close();
86
87 if (spectra.size() < 1)
88 throw std::runtime_error("The number of spectra in the loaded file is zero.");
89
90 MatrixWorkspace_sptr outWS = std::dynamic_pointer_cast<MatrixWorkspace>(
91 API::WorkspaceFactory::Instance().create("Workspace2D", spectra.size(), spectra[0].size(), spectra[0].size()));
92 outWS->setInstrument(inst);
93 outWS->getAxis(0)->setUnit("TOF");
94 outWS->setYUnit("Counts");
95 outWS->setDistribution(true);
96 outWS->rebuildSpectraMapping(false);
97
98 const auto &componentInfo = outWS->componentInfo();
99 const auto &detectorInfo = outWS->detectorInfo();
100
101 // Build a list of Rectangular/Grid Detectors (as component indices)
102 // Do this after creating the workspace, to avoid double-walking the instrument tree
103 std::vector<size_t> detList;
104 for (const size_t i : componentInfo.children(componentInfo.root())) {
105 if (componentInfo.isGridDetector(i)) {
106 detList.emplace_back(i);
107 } else {
108 // Also, look in the first sub-level for RectangularDetectors (e.g. PG3).
109 // We are not doing a full recursive search since that will be very long
110 // for lots of pixels.
111 for (const size_t j : componentInfo.children(i)) {
112 if (componentInfo.isGridDetector(j)) {
113 detList.emplace_back(j);
114 } else {
115 // Also, look in the second sub-level for RectangularDetectors (e.g.
116 // PG3).
117 // We are not doing a full recursive search since that will be very
118 // long for lots of pixels.
119 const auto &grandchildren = componentInfo.children(j);
120 std::copy_if(grandchildren.begin(), grandchildren.end(), std::back_inserter(detList),
121 [&componentInfo](size_t k) { return componentInfo.isGridDetector(k); });
122 }
123 }
124 }
125 }
126
127 // Go through each point at this run / bank
128 for (size_t i = 0; i < spectra.size(); i++) {
129 auto &outSpec = outWS->getSpectrum(i);
130 outSpec.clearDetectorIDs();
131 const size_t bankIndex = detList[i];
132 const auto grid = componentInfo.pixelGridComponent(bankIndex);
133 for (int j = 0; j < grid.nX; j++) {
134 for (int k = 0; k < grid.nY; k++) {
135 outSpec.addDetectorID(detectorInfo.detid(componentInfo.detectorIndexAtXYZ(bankIndex, j, k, 0)));
136 }
137 }
138 auto &outX = outSpec.mutableX();
139 auto &outY = outSpec.mutableY();
140 auto &outE = outSpec.mutableE();
141 // This is the scattered beam direction
142 V3D dir = componentInfo.position(bankIndex) - samplePos;
143
144 // Find spectra at wavelength of 1 for normalization
145 std::vector<double> xdata(1, 1.0); // wl = 1
146 std::vector<double> ydata;
147 double l2 = dir.norm();
148 // Two-theta = polar angle = scattering angle = between +Z vector and the
149 // scattered beam
150 double theta2 = dir.angle(V3D(0.0, 0.0, 1.0));
151
152 Mantid::Kernel::Unit_sptr unit = UnitFactory::Instance().create("Wavelength");
153 unit->toTOF(xdata, ydata, l1, 0,
154 {
155 {UnitParams::l2, l2},
156 {UnitParams::twoTheta, theta2},
157 });
158 double one = xdata[0];
159 double spect1 = spectrumCalc(one, iSpec, time, spectra, i);
160
161 for (size_t j = 0; j < spectra[i].size(); j++) {
162 double spect = spectra[i][j];
163
164 double relSigSpect = std::sqrt((1.0 / spect) + (1.0 / spect1));
165 if (spect1 != 0.0) {
166 spect /= spect1;
167 outX[j] = time[i][j];
168 outY[j] = spect;
169 outE[j] = relSigSpect;
170 } else {
171 throw std::runtime_error("Wavelength for normalizing to spectrum is out of range.");
172 }
173 }
174 }
175
176 Algorithm_sptr convertAlg = createChildAlgorithm("ConvertToHistogram", 0.0, 0.2);
177 convertAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", outWS);
178 // Now execute the convert Algorithm but allow any exception to bubble up
179 convertAlg->execute();
180 outWS = convertAlg->getProperty("OutputWorkspace");
181
182 setProperty("OutputWorkspace", outWS);
183}
184
185double LoadIsawSpectrum::spectrumCalc(double TOF, int iSpec, const std::vector<std::vector<double>> &time,
186 const std::vector<std::vector<double>> &spectra, size_t id) {
187 double spect = 0;
188 if (iSpec == 1) {
189 //"Calculate the spectrum using spectral coefficients for the GSAS Type 2
190 // incident spectrum."
191 double T = TOF / 1000.; // time-of-flight in milliseconds
192
193 double c1 = spectra[id][0];
194 double c2 = spectra[id][1];
195 double c3 = spectra[id][2];
196 double c4 = spectra[id][3];
197 double c5 = spectra[id][4];
198 double c6 = spectra[id][5];
199 double c7 = spectra[id][6];
200 double c8 = spectra[id][7];
201 double c9 = spectra[id][8];
202 double c10 = spectra[id][9];
203 double c11 = spectra[id][10];
204
205 spect = c1 + c2 * exp(-c3 / std::pow(T, 2)) / std::pow(T, 5) + c4 * exp(-c5 * std::pow(T, 2)) +
206 c6 * exp(-c7 * std::pow(T, 3)) + c8 * exp(-c9 * std::pow(T, 4)) + c10 * exp(-c11 * std::pow(T, 5));
207 } else {
208 size_t i = 1;
209 for (i = 1; i < spectra[0].size() - 1; ++i)
210 if (TOF < time[id][i])
211 break;
212 spect = spectra[id][i - 1] +
213 (TOF - time[id][i - 1]) / (time[id][i] - time[id][i - 1]) * (spectra[id][i] - spectra[id][i - 1]);
214 }
215
216 return spect;
217}
218//----------------------------------------------------------------------------------------------
223 std::string grpName("Specify the Instrument");
224
225 alg->declareProperty(
226 std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input, PropertyMode::Optional),
227 "Optional: An input workspace with the instrument we want to use.");
228
229 alg->declareProperty(std::make_unique<PropertyWithValue<std::string>>("InstrumentName", "", Direction::Input),
230 "Optional: Name of the instrument to base the "
231 "GroupingWorkspace on which to base the "
232 "GroupingWorkspace.");
233
234 alg->declareProperty(std::make_unique<FileProperty>("InstrumentFilename", "", FileProperty::OptionalLoad, ".xml"),
235 "Optional: Path to the instrument definition file on "
236 "which to base the GroupingWorkspace.");
237
238 alg->setPropertyGroup("InputWorkspace", grpName);
239 alg->setPropertyGroup("InstrumentName", grpName);
240 alg->setPropertyGroup("InstrumentFilename", grpName);
241}
242
243//----------------------------------------------------------------------------------------------
249 MatrixWorkspace_sptr inWS = alg->getProperty("InputWorkspace");
250 std::string InstrumentName = alg->getPropertyValue("InstrumentName");
251 std::string InstrumentFilename = alg->getPropertyValue("InstrumentFilename");
252
253 // Some validation
254 int numParams = 0;
255 if (inWS)
256 numParams++;
257 if (!InstrumentName.empty())
258 numParams++;
259 if (!InstrumentFilename.empty())
260 numParams++;
261
262 if (numParams > 1)
263 throw std::invalid_argument("You must specify exactly ONE way to get an "
264 "instrument (workspace, instrument name, or "
265 "IDF file). You specified more than one.");
266 if (numParams == 0)
267 throw std::invalid_argument("You must specify exactly ONE way to get an "
268 "instrument (workspace, instrument name, or "
269 "IDF file). You specified none.");
270
271 // ---------- Get the instrument one of 3 ways ---------------------------
273 if (inWS) {
274 inst = inWS->getInstrument();
275 } else {
276 Algorithm_sptr childAlg = alg->createChildAlgorithm("LoadInstrument", 0.0, 0.2);
277 MatrixWorkspace_sptr tempWS(new Workspace2D());
278 childAlg->setProperty<MatrixWorkspace_sptr>("Workspace", tempWS);
279 childAlg->setPropertyValue("Filename", InstrumentFilename);
280 childAlg->setPropertyValue("InstrumentName", InstrumentName);
281 childAlg->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(false));
282 childAlg->executeAsChildAlg();
283 inst = tempWS->getInstrument();
284 }
285
286 return inst;
287}
288
289} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:542
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:76
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
Load incident spectrum and detector efficiency correction file.
Geometry::Instrument_const_sptr getInstrument3Ways(Algorithm *alg)
Get a pointer to an instrument in one of 3 ways: InputWorkspace, InstrumentName, InstrumentFilename.
double spectrumCalc(double TOF, int iSpec, const std::vector< std::vector< double > > &time, const std::vector< std::vector< double > > &spectra, size_t id)
void exec() override
Run the algorithm.
void getInstrument3WaysInit(Algorithm *alg)
For use by getInstrument3Ways, initializes the properties.
Concrete workspace implementation.
Definition Workspace2D.h:29
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
OptionalBool : Tri-state bool.
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Class for 3D vectors.
Definition V3D.h:34
double angle(const V3D &) const
Angle between this and another vector.
Definition V3D.cpp:162
double norm() const noexcept
Definition V3D.h:269
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition Algorithm.h:52
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
std::shared_ptr< Unit > Unit_sptr
Shared pointer to the Unit base class.
Definition Unit.h:239
A namespace containing physical constants that are required by algorithms and unit routines.
Definition Atom.h:14
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54