Mantid
Loading...
Searching...
No Matches
SaveHKL.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 +
9#include "MantidAPI/Run.h"
10#include "MantidAPI/Sample.h"
20#include "MantidKernel/Unit.h"
22#include "MantidKernel/Utils.h"
23#include <cmath>
24#include <filesystem>
25#include <fstream>
26
27using namespace Mantid::Geometry;
28using namespace Mantid::DataObjects;
29using namespace Mantid::Kernel;
30using namespace Mantid::Kernel::Strings;
31using namespace Mantid::API;
32using namespace Mantid::PhysicalConstants;
33
34namespace Mantid::Crystal {
35
36// Register the algorithm into the AlgorithmFactory
37DECLARE_ALGORITHM(SaveHKL)
38
39
41void SaveHKL::init() {
42 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("InputWorkspace", "", Direction::Input),
43 "An input PeaksWorkspace.");
44
45 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
46 mustBePositive->setLower(0.0);
47 declareProperty("ScalePeaks", 1.0, mustBePositive, "Multiply FSQ and sig(FSQ) by scaleFactor");
48 declareProperty("MinDSpacing", 0.0, "Minimum d-spacing (Angstroms)");
49 declareProperty("MinWavelength", 0.0, "Minimum wavelength (Angstroms)");
50 declareProperty("MaxWavelength", 100.0, "Maximum wavelength (Angstroms)");
51
52 declareProperty("AppendFile", false,
53 "Append to file if true. Use same corrections as file.\n"
54 "If false, new file (default).");
55 declareProperty("ApplyAnvredCorrections", false,
56 "Apply anvred corrections to peaks if true.\n"
57 "If false, no corrections during save (default).");
58 declareProperty("LinearScatteringCoef", EMPTY_DBL(), mustBePositive,
59 "Linear scattering coefficient in 1/cm if not set with "
60 "SetSampleMaterial");
61 declareProperty("LinearAbsorptionCoef", EMPTY_DBL(), mustBePositive,
62 "Linear absorption coefficient at 1.8 Angstroms in 1/cm if "
63 "not set with SetSampleMaterial");
64 declareProperty("Radius", EMPTY_DBL(), mustBePositive, "Radius of the sample in centimeters");
65 declareProperty("PowerLambda", 4.0, "Power of lambda ");
66 declareProperty(std::make_unique<FileProperty>("SpectraFile", "", API::FileProperty::OptionalLoad, ".dat"),
67 " Spectrum data read from a spectrum file.");
68
69 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Save, ".hkl"),
70 "Path to an hkl file to save.");
71
72 std::vector<std::string> histoTypes{"Bank", "RunNumber", ""};
73 declareProperty("SortBy", histoTypes[2], std::make_shared<StringListValidator>(histoTypes),
74 "Sort the histograms by bank, run number or both (default).");
75 declareProperty("MinIsigI", EMPTY_DBL(), mustBePositive, "The minimum I/sig(I) ratio");
76 declareProperty("WidthBorder", EMPTY_INT(), "Width of border of detectors");
77 declareProperty("MinIntensity", EMPTY_DBL(), mustBePositive, "The minimum Intensity");
78 declareProperty(
79 std::make_unique<WorkspaceProperty<PeaksWorkspace>>("OutputWorkspace", "SaveHKLOutput", Direction::Output),
80 "Output PeaksWorkspace");
81 declareProperty("HKLDecimalPlaces", EMPTY_INT(),
82 "Number of decimal places for fractional HKL. Default is integer HKL.");
83 declareProperty("DirectionCosines", false,
84 "Extra columns (22 total) in file if true for direction cosines.\n"
85 "If false, original 14 columns (default).");
86 const std::vector<std::string> exts{".mat", ".ub", ".txt"};
87 declareProperty(std::make_unique<FileProperty>("UBFilename", "", FileProperty::OptionalLoad, exts),
88 "Path to an ISAW-style UB matrix text file only needed for "
89 "DirectionCosines if workspace does not have lattice.");
90}
91
95
96 std::string filename = getPropertyValue("Filename");
97 m_ws = getProperty("InputWorkspace");
98
99 PeaksWorkspace_sptr peaksW = getProperty("OutputWorkspace");
100 if (peaksW != m_ws)
101 peaksW = m_ws->clone();
102 auto inst = peaksW->getInstrument();
103 std::vector<Peak> &peaks = peaksW->getPeaks();
104 double scaleFactor = getProperty("ScalePeaks");
105 double dMin = getProperty("MinDSpacing");
106 double wlMin = getProperty("MinWavelength");
107 double wlMax = getProperty("MaxWavelength");
108 std::string type = getProperty("SortBy");
109 double minIsigI = getProperty("MinIsigI");
110 double minIntensity = getProperty("MinIntensity");
111 int widthBorder = getProperty("WidthBorder");
112 int decimalHKL = getProperty("HKLDecimalPlaces");
113 bool cosines = getProperty("DirectionCosines");
115 if (cosines) {
116 if (peaksW->sample().hasOrientedLattice()) {
117 ol = peaksW->sample().getOrientedLattice();
118 } else {
119 // Find OrientedLattice
120 std::string fileUB = getProperty("UBFilename");
121 // Open the file
122 std::ifstream in(fileUB.c_str());
123 if (!in)
124 throw std::runtime_error("A file containing the UB matrix must be input into UBFilename.");
125
126 auto UB_alg = createChildAlgorithm("LoadIsawUB", -1, -1, false);
127 UB_alg->setProperty("PeaksWorkspace", peaksW);
128 UB_alg->setProperty("Filename", fileUB);
129 UB_alg->executeAsChildAlg();
130 }
131 }
132
133 // Sequence and run number
134 int bankSequence = 0;
135 int runSequence = 0;
136 // HKL is flipped by -1 due to different q convention in ISAW vs mantid.
137 // Default for kf-ki has -q
138 double qSign = -1.0;
139 std::string convention = ConfigService::Instance().getString("Q.convention");
140 if (convention == "Crystallography") {
141 qSign = 1.0;
142 }
143
144 std::fstream out;
145 out.open(filename.c_str(), std::ios::out);
146
147 // We cannot assume the peaks have bank type detector modules, so we have a
148 // string to check this
149 std::string bankPart = "?";
150 // We must sort the peaks first by run, then bank #, and save the list of
151 // workspace indices of it
152 using bankMap_t = std::map<int, std::vector<size_t>>;
153 using runMap_t = std::map<int, bankMap_t>;
154 std::set<int> uniqueBanks;
155 std::set<int> uniqueRuns;
156 runMap_t runMap;
157 for (size_t i = 0; i < peaks.size(); ++i) {
158 Peak const &p = peaks[i];
159 int run = p.getRunNumber();
160 int bank = 0;
161 std::string bankName = p.getBankName();
162 if (bankName.size() <= 4) {
163 g_log.information() << "Could not interpret bank number of peak " << i << "(" << bankName << ")\n";
164 continue;
165 }
166 // Save the "bank" part once to check whether it really is a bank
167 if (bankPart == "?")
168 bankPart = bankName.substr(0, 4);
169 // Take out the "bank" part of the bank name and convert to an int
170 if (bankPart == "bank")
171 bankName = bankName.substr(4, bankName.size() - 4);
172 else if (bankPart == "WISH")
173 bankName = bankName.substr(9, bankName.size() - 9);
174 Strings::convert(bankName, bank);
175
176 // Save in the map
177 if (type.compare(0, 2, "Ru") == 0)
178 runMap[run][bank].emplace_back(i);
179 else
180 runMap[bank][run].emplace_back(i);
181 // Track unique bank numbers
182 uniqueBanks.insert(bank);
183 uniqueRuns.insert(run);
184 }
185
186 bool correctPeaks = getProperty("ApplyAnvredCorrections");
187 std::vector<std::vector<double>> spectra;
188 std::vector<std::vector<double>> time;
189 int iSpec = 0;
190
191 m_smu = getProperty("LinearScatteringCoef"); // in 1/cm
192 m_amu = getProperty("LinearAbsorptionCoef"); // in 1/cm
193 m_power_th = getProperty("PowerLambda"); // in cm
194
195 API::Run &run = peaksW->mutableRun();
196
197 double radius = getProperty("Radius"); // in cm
198 if (radius != EMPTY_DBL()) {
199 run.addProperty<double>("Radius", radius, true);
200 } else {
201 if (run.hasProperty("Radius"))
202 radius = run.getPropertyValueAsType<double>("Radius");
203 }
204
205 const Material &sampleMaterial = peaksW->sample().getMaterial();
206 const IObject *sampleShape{nullptr};
207 // special case of sphere else assume the sample shape and material have been
208 // set already
209 if (radius != EMPTY_DBL()) {
210 // create sphere shape
211 auto sphere = ShapeFactory::createSphere(V3D(), radius * 0.01);
212 if (m_smu != EMPTY_DBL() && m_amu != EMPTY_DBL()) {
213 // Save input in Sample with wrong atomic number and name
214 NeutronAtom neutron(0, 0, 0.0, 0.0, m_smu, 0.0, m_smu, m_amu);
215 sphere->setMaterial(Material("SetInSaveHKL", neutron, 1.0));
216 } else {
217 sphere->setMaterial(sampleMaterial);
218 const double rho = sampleMaterial.numberDensity();
219 m_smu = sampleMaterial.totalScatterXSection() * rho;
221 }
222 peaksW->mutableSample().setShape(sphere);
223 } else if (peaksW->sample().getShape().hasValidShape()) {
224 sampleShape = &(peaksW->sample().getShape());
225 // if AddAbsorptionWeightedPathLengths has already been run on the workspace
226 // then keep those tbar values
227 if (std::all_of(peaks.cbegin(), peaks.cend(), [](auto &p) { return p.getAbsorptionWeightedPathLength() == 0; })) {
228 auto alg = createChildAlgorithm("AddAbsorptionWeightedPathLengths");
229 alg->setProperty("InputWorkspace", peaksW);
230 alg->setProperty("UseSinglePath", true);
231 alg->executeAsChildAlg();
232 }
233 }
234
235 if (correctPeaks) {
236 std::ifstream infile;
237 std::string spectraFile = getPropertyValue("SpectraFile");
238 infile.open(spectraFile.c_str());
239 if (infile.is_open()) {
240 std::string ignoreLine;
241 size_t a = 1;
242 for (int wi = 0; wi < 8; wi++)
243 getline(infile, ignoreLine);
244 while (!infile.eof()) {
245 time.resize(a + 1);
246 spectra.resize(a + 1);
247 std::string line;
248 getline(infile, line);
249 std::stringstream ss(line);
250 if (line.find("Bank") == std::string::npos) {
251 double time0, spectra0;
252 ss >> time0 >> spectra0;
253 time[a].emplace_back(time0);
254 spectra[a].emplace_back(spectra0);
255
256 } else {
257 std::string temp;
258 size_t a0 = 1;
259 ss >> temp >> a0 >> temp >> a;
260 }
261 }
262 infile.close();
263 }
264 }
265 // =================== Save all Peaks ======================================
266 std::set<size_t> banned;
267 // Go through each peak at this run / bank
268 int maxOrder = 0;
269 if (peaksW->sample().hasOrientedLattice()) {
270 maxOrder = peaksW->sample().getOrientedLattice().getMaxOrder();
271 }
272 // Go in order of run numbers
273 runMap_t::iterator runMap_it;
274 for (runMap_it = runMap.begin(); runMap_it != runMap.end(); ++runMap_it) {
275 // Start of a new run
276 // int run = runMap_it->first;
277 bankMap_t &bankMap = runMap_it->second;
278
279 bankMap_t::iterator bankMap_it;
280 for (bankMap_it = bankMap.begin(); bankMap_it != bankMap.end(); ++bankMap_it) {
281 // Start of a new bank.
282 // int bank = bankMap_it->first;
283 std::vector<size_t> &ids = bankMap_it->second;
284
285 // Go through each peak at this run / bank
286 for (auto wi : ids) {
287
288 Peak &p = peaks[wi];
289 if (p.getIntensity() == 0.0 || !(std::isfinite(p.getIntensity())) || !(std::isfinite(p.getSigmaIntensity()))) {
290 banned.insert(wi);
291 continue;
292 }
293 if (minIsigI != EMPTY_DBL() && p.getIntensity() < std::abs(minIsigI * p.getSigmaIntensity())) {
294 banned.insert(wi);
295 continue;
296 }
297 if (minIntensity != EMPTY_DBL() && p.getIntensity() < minIntensity) {
298 banned.insert(wi);
299 continue;
300 }
301 const int runNumber = p.getRunNumber();
302 int seqNum = p.getPeakNumber();
303 int bank = 0;
304 std::string bankName = p.getBankName();
305 int nCols, nRows;
306 sizeBanks(bankName, nCols, nRows);
307 // peaks with detectorID=-1 are from LoadHKL
308 if (widthBorder != EMPTY_INT() && p.getDetectorID() != -1 &&
309 (p.getCol() < widthBorder || p.getRow() < widthBorder || p.getCol() > (nCols - widthBorder) ||
310 p.getRow() > (nRows - widthBorder))) {
311 banned.insert(wi);
312 continue;
313 }
314 // Take out the "bank" part of the bank name and convert to an int
315 bankName.erase(remove_if(bankName.begin(), bankName.end(), std::not_fn(::isdigit)), bankName.end());
316 Strings::convert(bankName, bank);
317
318 // Two-theta = polar angle = scattering angle = between +Z vector and
319 // the
320 // scattered beam
321 double scattering = p.getScattering();
322 double lambda = p.getWavelength();
323 double dsp = p.getDSpacing();
324 if (dsp < dMin || lambda < wlMin || lambda > wlMax) {
325 banned.insert(wi);
326 continue;
327 }
328
329 double transmission{0}, tbar{0};
330 if (radius != EMPTY_DBL()) {
331 // keep original method if radius is provided
332 transmission = absorbSphere(radius, scattering, lambda, tbar);
333 } else if (sampleShape) {
335 transmission = exp(-tbar * 0.01 * sampleShape->material().attenuationCoefficient(lambda));
336 }
337
338 // Anvred write from Art Schultz/
339 if (p.getH() == 0 && p.getK() == 0 && p.getL() == 0) {
340 banned.insert(wi);
341 continue;
342 }
343 if (decimalHKL == EMPTY_INT()) {
344 V3D HKL = (maxOrder == 0) ? p.getHKL() : p.getIntHKL();
345 out << std::setw(4) << Utils::round(qSign * HKL[0]) << std::setw(4) << Utils::round(qSign * HKL[1])
346 << std::setw(4) << Utils::round(qSign * HKL[2]);
347 if (maxOrder > 0) {
348 V3D MNP = p.getIntMNP();
349 out << std::setw(4) << Utils::round(qSign * MNP[0]) << std::setw(4) << Utils::round(qSign * MNP[1])
350 << std::setw(4) << Utils::round(qSign * MNP[2]);
351 }
352 } else {
353 out << std::setw(5 + decimalHKL) << std::fixed << std::setprecision(decimalHKL) << qSign * p.getH()
354 << std::setw(5 + decimalHKL) << std::fixed << std::setprecision(decimalHKL) << qSign * p.getK()
355 << std::setw(5 + decimalHKL) << std::fixed << std::setprecision(decimalHKL) << qSign * p.getL();
356 }
357 double correc = scaleFactor;
358 double instBkg = 0;
359 double relSigSpect = 0.0;
360 bankSequence = static_cast<int>(std::distance(uniqueBanks.begin(), uniqueBanks.find(bank)));
361 runSequence = static_cast<int>(std::distance(uniqueRuns.begin(), uniqueRuns.find(runNumber)));
362 if (correctPeaks) {
363 // correct for the slant path throught the scintillator glass
364 double mu = (9.614 * lambda) + 0.266; // mu for GS20 glass
365 double depth = 0.2;
366 double eff_center = 1.0 - std::exp(-mu * depth); // efficiency at center of detector
367
368 // Distance to center of detector
369 const IComponent *det0 = inst->getComponentByName(p.getBankName()).get();
370 if (inst->getName() == "CORELLI") // for Corelli with sixteenpack under bank
371 {
372 const auto &componentInfo = m_ws->componentInfo();
373 const size_t bankIndex = componentInfo.indexOfAny(p.getBankName());
374 const auto children = componentInfo.children(bankIndex);
375 if (!children.empty()) {
376 det0 = componentInfo.componentID(children[0]);
377 }
378 }
379 IComponent_const_sptr sample = inst->getSample();
380 double cosA = det0->getDistance(*sample) / p.getL2();
381 double pathlength = depth / cosA;
382 double eff_R = 1.0 - exp(-mu * pathlength); // efficiency at point R
383 double sp_ratio = eff_center / eff_R; // slant path efficiency ratio
384 double sinsqt = std::pow(lambda / (2.0 * dsp), 2);
385 double wl4 = std::pow(lambda, m_power_th);
386 double cmonx = 1.0;
387 if (p.getMonitorCount() > 0) {
388 cmonx = 100e6 / p.getMonitorCount();
389 }
390 double spect = spectrumCalc(p.getTOF(), iSpec, time, spectra, bank);
391 // Find spectra at wavelength of 1 for normalization
392 std::vector<double> xdata(1, 1.0); // wl = 1
393 std::vector<double> ydata;
394 double theta2 = p.getScattering();
395 double l1 = p.getL1();
396 double l2 = p.getL2();
397 Mantid::Kernel::Unit_sptr unit = UnitFactory::Instance().create("Wavelength");
398 unit->toTOF(xdata, ydata, l1, 0, {{UnitParams::l2, l2}, {UnitParams::twoTheta, theta2}});
399 double one = xdata[0];
400 double spect1 = spectrumCalc(one, iSpec, time, spectra, bank);
401 relSigSpect = std::sqrt((1.0 / spect) + (1.0 / spect1));
402 if (spect1 != 0.0) {
403 spect /= spect1;
404 } else {
405 throw std::runtime_error("Wavelength for normalizing to spectrum is out of range.");
406 }
407 correc = scaleFactor * sinsqt * cmonx * sp_ratio / (wl4 * spect * transmission);
408
409 if (inst->hasParameter("detScale" + bankName)) {
410 correc *= static_cast<double>(inst->getNumberParameter("detScale" + bankName)[0]);
411 }
412
413 // instrument background constant for sigma
414 instBkg = 0. * 12.28 / cmonx * scaleFactor;
415 }
416
417 // SHELX can read data without the space between the l and intensity
418 if (p.getDetectorID() != -1) {
419 double ckIntensity = correc * p.getIntensity();
420 double cksigI = std::sqrt(std::pow(correc * p.getSigmaIntensity(), 2) +
421 std::pow(relSigSpect * correc * p.getIntensity(), 2) + instBkg);
422 p.setIntensity(ckIntensity);
423 p.setSigmaIntensity(cksigI);
424 if (ckIntensity > 99999.985)
425 g_log.warning() << "Scaled intensity, " << ckIntensity
426 << " is too large for format. Decrease ScalePeaks.\n";
427 out << std::setw(8) << std::fixed << std::setprecision(2) << ckIntensity;
428
429 out << std::setw(8) << std::fixed << std::setprecision(2) << cksigI;
430 } else {
431 // This is data from LoadHKL which is already corrected
432 out << std::setw(8) << std::fixed << std::setprecision(2) << p.getIntensity();
433
434 out << std::setw(8) << std::fixed << std::setprecision(2) << p.getSigmaIntensity();
435 }
436 if (type.compare(0, 2, "Ba") == 0)
437 out << std::setw(4) << bankSequence + 1;
438 else
439 out << std::setw(4) << runSequence + 1;
440
441 out << std::setw(8) << std::fixed << std::setprecision(5) << lambda;
442 out << std::setw(8) << std::fixed << std::setprecision(5) << tbar;
443
444 if (cosines) {
445 // This is the reverse incident beam
446 V3D reverse_incident_dir = p.getSourceDirectionSampleFrame();
447 V3D reverse_incident_cos = ol.cosFromDir(reverse_incident_dir);
448
449 // This is the scattered beam direction
450 V3D scattered_dir = p.getDetectorDirectionSampleFrame();
451 V3D scattered_cos = ol.cosFromDir(scattered_dir);
452
453 for (int k = 0; k < 3; ++k) {
454 out << std::setw(9) << std::fixed << std::setprecision(5) << reverse_incident_cos[k];
455 out << std::setw(9) << std::fixed << std::setprecision(5) << scattered_cos[k];
456 }
457 }
458
459 out << std::setw(6) << runNumber;
460
461 if (cosines) {
462 out << std::setw(7) << seqNum;
463 } else {
464 out << std::setw(7) << wi + 1;
465 }
466
467 out << std::setw(7) << std::fixed << std::setprecision(4) << transmission;
468
469 out << std::setw(4) << std::right << bank;
470
471 out << std::setw(9) << std::fixed << std::setprecision(5) << scattering; // two-theta scattering
472
473 out << std::setw(8) << std::fixed << std::setprecision(4) << dsp;
474
475 if (cosines) {
476 out << std::setw(7) << std::fixed << std::setprecision(2) << static_cast<double>(p.getCol());
477 out << std::setw(7) << std::fixed << std::setprecision(2) << static_cast<double>(p.getRow());
478 }
479
480 out << '\n';
481 }
482 }
483 }
484 if (decimalHKL == EMPTY_INT()) {
485 out << std::setw(4) << 0 << std::setw(4) << 0 << std::setw(4) << 0;
486 if (maxOrder > 0) {
487 out << std::setw(4) << 0 << std::setw(4) << 0 << std::setw(4) << 0;
488 }
489 } else {
490 //
491 out << std::setw(5 + decimalHKL) << std::fixed << std::setprecision(decimalHKL) << 0.0 << std::setw(5 + decimalHKL)
492 << std::fixed << std::setprecision(decimalHKL) << 0.0 << std::setw(5 + decimalHKL) << std::fixed
493 << std::setprecision(decimalHKL) << 0.0;
494 }
495 if (cosines) {
496 out << " 0.00 0.00 0 0.00000 0.00000"
497 " 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000"
498 " 0 0 0.0000 0 0.00000 0.0000 0.00 0.00";
499 } else {
500 out << " 0.00 0.00 0 0.00000 0.00000"
501 " 0 0 0.0000 0 0.00000 0.0000";
502 }
503 out << '\n';
504 out.flush();
505 out.close();
506 // delete banned peaks
507 std::vector<int> badPeaks;
508 for (auto it = banned.crbegin(); it != banned.crend(); ++it) {
509 badPeaks.emplace_back(static_cast<int>(*it));
510 }
511 peaksW->removePeaks(std::move(badPeaks));
512
513 bool append = getProperty("AppendFile");
514 if (append && std::filesystem::exists(filename)) {
515 auto load_alg = createChildAlgorithm("LoadHKL");
516 load_alg->setPropertyValue("Filename", filename);
517 load_alg->setProperty("OutputWorkspace", "peaks");
518 load_alg->executeAsChildAlg();
519 // Get back the result
520 DataObjects::PeaksWorkspace_sptr ws2 = load_alg->getProperty("OutputWorkspace");
521 ws2->setInstrument(inst);
522
523 auto plus_alg = createChildAlgorithm("CombinePeaksWorkspaces");
524 plus_alg->setProperty("LHSWorkspace", peaksW);
525 plus_alg->setProperty("RHSWorkspace", ws2);
526 plus_alg->executeAsChildAlg();
527 // Get back the result
528 peaksW = plus_alg->getProperty("OutputWorkspace");
529 }
530
531 setProperty("OutputWorkspace", peaksW);
532} // namespace Crystal
533
550double SaveHKL::absorbSphere(double radius, double twoth, double wl, double &tbar) {
551
552 const double mu = m_smu + (m_amu / 1.8f) * wl; // linear absorption coef
553 const double mur = mu * radius;
554
555 if (mur < 0. || mur > 2.5) {
556 std::ostringstream s;
557 s << mur;
558 throw std::runtime_error("muR is not in range of Dwiggins' table :" + s.str());
559 }
560
561 const double theta = twoth * radtodeg * 0.5;
562 if (theta < 0. || theta > 90.) {
563 std::ostringstream s;
564 s << theta;
565 throw std::runtime_error("theta is not valid it must be in range [0, 90]");
566 }
567
568 const double transmission = 1.f / AnvredCorrection::calc_Astar(theta, mur);
569
570 // calculate tbar as defined by coppens.
571 // transmission = exp(-mu*tbar)
572 if (std::fabs(mu) < 1e-300)
573 tbar = 0.0;
574 else
575 tbar = -std::log(transmission) / mu;
576
577 return transmission;
578}
579
580double SaveHKL::spectrumCalc(double TOF, int iSpec, const std::vector<std::vector<double>> &time,
581 const std::vector<std::vector<double>> &spectra, size_t id) {
582 double spect = 0;
583 if (iSpec == 1) {
584 //"Calculate the spectrum using spectral coefficients for the GSAS Type 2
585 // incident spectrum."
586 double T = TOF / 1000.; // time-of-flight in milliseconds
587
588 double c1 = spectra[id][0];
589 double c2 = spectra[id][1];
590 double c3 = spectra[id][2];
591 double c4 = spectra[id][3];
592 double c5 = spectra[id][4];
593 double c6 = spectra[id][5];
594 double c7 = spectra[id][6];
595 double c8 = spectra[id][7];
596 double c9 = spectra[id][8];
597 double c10 = spectra[id][9];
598 double c11 = spectra[id][10];
599
600 spect = c1 + c2 * exp(-c3 / std::pow(T, 2)) / std::pow(T, 5) + c4 * exp(-c5 * std::pow(T, 2)) +
601 c6 * exp(-c7 * std::pow(T, 3)) + c8 * exp(-c9 * std::pow(T, 4)) + c10 * exp(-c11 * std::pow(T, 5));
602 } else {
603 size_t i = 1;
604 for (i = 1; i < spectra[id].size(); ++i)
605 if (TOF < time[id][i])
606 break;
607 spect = spectra[id][i - 1] +
608 (TOF - time[id][i - 1]) / (time[id][i] - time[id][i - 1]) * (spectra[id][i] - spectra[id][i - 1]);
609 }
610
611 return spect;
612}
613void SaveHKL::sizeBanks(const std::string &bankName, int &nCols, int &nRows) {
614 if (bankName == "None")
615 return;
616 std::shared_ptr<const IComponent> parent = m_ws->getInstrument()->getComponentByName(bankName);
617 if (!parent)
618 return;
619 if (parent->type() == "RectangularDetector") {
620 std::shared_ptr<const RectangularDetector> RDet = std::dynamic_pointer_cast<const RectangularDetector>(parent);
621
622 nCols = RDet->xpixels();
623 nRows = RDet->ypixels();
624 } else {
625 const auto &componentInfo = m_ws->componentInfo();
626 size_t parentIndex = componentInfo.indexOfAny(bankName);
627
628 if (m_ws->getInstrument()->getName() == "CORELLI") // for Corelli with sixteenpack under bank
629 {
630 auto children = componentInfo.children(parentIndex);
631 if (!children.empty()) {
632 parentIndex = children[0];
633 }
634 }
635 auto children = componentInfo.children(parentIndex);
636 auto grandchildren = componentInfo.children(children[0]);
637 nRows = static_cast<int>(grandchildren.size());
638 nCols = static_cast<int>(children.size());
639 }
640}
641
642} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
const std::vector< double > * lambda
const int maxOrder
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.
Kernel::Logger & g_log
Definition Algorithm.h:422
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Save
to specify a file to write to, the file may or may not exist
bool hasProperty(const std::string &name) const
Does the property exist on the object.
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Definition LogManager.h:90
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:35
A property class for workspaces.
static double calc_Astar(const double theta, const double mur)
Save a PeaksWorkspace to a Gsas-style ASCII .hkl file.
Definition SaveHKL.h:22
void exec() override
Run the algorithm.
Definition SaveHKL.cpp:94
void sizeBanks(const std::string &bankName, int &nCols, int &nRows)
Definition SaveHKL.cpp:613
DataObjects::PeaksWorkspace_sptr m_ws
Definition SaveHKL.h:46
double spectrumCalc(double TOF, int iSpec, const std::vector< std::vector< double > > &time, const std::vector< std::vector< double > > &spectra, size_t id)
Definition SaveHKL.cpp:580
double absorbSphere(double radius, double twoth, double wl, double &tbar)
Definition SaveHKL.cpp:550
Mantid::Kernel::V3D getIntMNP() const override
Return the int MNP vector.
Definition BasePeak.cpp:115
void setSigmaIntensity(double m_sigmaIntensity) override
Set the error on the integrated peak intensity.
Definition BasePeak.cpp:205
double getL() const override
Get the L index of the peak.
Definition BasePeak.cpp:99
double getIntensity() const override
Return the integrated peak intensity.
Definition BasePeak.cpp:184
double getAbsorptionWeightedPathLength() const override
Gets the absorption weighted path length.
Definition BasePeak.cpp:347
double getSigmaIntensity() const override
Return the error on the integrated peak intensity.
Definition BasePeak.cpp:187
double getK() const override
Get the K index of the peak.
Definition BasePeak.cpp:96
int getPeakNumber() const override
Returns the unique peak number Returns -1 if it could not find it.
Definition BasePeak.cpp:233
int getRunNumber() const override
Return the run number this peak was measured at.
Definition BasePeak.cpp:77
double getH() const override
Get the H index of the peak.
Definition BasePeak.cpp:93
void setIntensity(double m_intensity) override
Set the integrated peak intensity.
Definition BasePeak.cpp:197
Mantid::Kernel::V3D getHKL() const override
Return the HKL vector.
Definition BasePeak.cpp:102
double getMonitorCount() const override
Return the monitor count stored in this peak.
Definition BasePeak.cpp:85
Mantid::Kernel::V3D getIntHKL() const override
Return the int HKL vector.
Definition BasePeak.cpp:112
Structure describing a single-crystal peak.
Definition Peak.h:34
int getCol() const override
For RectangularDetectors only, returns the column (x) of the pixel of the detector or -1 if not found...
Definition Peak.cpp:335
Mantid::Kernel::V3D getSourceDirectionSampleFrame() const override
Calculate the reverse incident beam direction in the sample frame
Definition Peak.cpp:418
double getDSpacing() const override
Calculate the d-spacing of the peak, in 1/Angstroms
Definition Peak.cpp:426
int getRow() const override
For RectangularDetectors only, returns the row (y) of the pixel of the detector or -1 if not found.
Definition Peak.cpp:326
double getL1() const override
Return the L1 flight path length (source to sample), in meters.
Definition Peak.cpp:724
int getDetectorID() const override
Get the ID of the detector at the center of the peak
Definition Peak.cpp:265
Mantid::Kernel::V3D getDetectorDirectionSampleFrame() const override
Calculate the scattered beam direction in the sample frame
Definition Peak.cpp:410
double getWavelength() const override
Calculate the neutron wavelength (in angstroms) at the peak (Note for inelastic scattering - it is th...
Definition Peak.cpp:358
double getTOF() const override
Calculate the time of flight (in microseconds) of the neutrons for this peak, using the geometry of t...
Definition Peak.cpp:373
double getL2() const override
Return the L2 flight path length (sample to detector), in meters.
Definition Peak.cpp:728
const std::string & getBankName() const
Find the name of the bank that is the parent of the detector.
Definition Peak.cpp:347
double getScattering() const override
Calculate the scattering angle of the peak
Definition Peak.cpp:391
HKL : HKL MDFrame.
Definition HKL.h:20
base class for Geometric IComponent
Definition IComponent.h:53
virtual double getDistance(const IComponent &) const =0
Get the distance to another IComponent.
IObject : Interface for geometry objects.
Definition IObject.h:42
Class to implement UB matrix.
Kernel::V3D cosFromDir(const Kernel::V3D &dir) const
Calculate the direction cosine corresponding to a given direction.
static std::shared_ptr< CSGObject > createSphere(const Kernel::V3D &centre, double radius)
Create a Sphere.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
Definition Material.h:50
double numberDensity() const
Get the number density.
Definition Material.cpp:189
double absorbXSection(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the absorption cross section at a given wavelength in barns.
Definition Material.cpp:260
double totalScatterXSection() const
Return the total scattering cross section for a given wavelength in barns.
Definition Material.cpp:252
Class for 3D vectors.
Definition V3D.h:34
const double radtodeg
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
std::shared_ptr< const IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition IComponent.h:167
Holds support functions for strings.
int convert(const std::string &A, T &out)
Convert a string into a number.
Definition Strings.cpp:696
long round(double x)
Custom rounding method for a double->long because none is portable in C++ (!)
Definition Utils.h:37
std::shared_ptr< Unit > Unit_sptr
Shared pointer to the Unit base class.
Definition Unit.h:194
A namespace containing physical constants that are required by algorithms and unit routines.
Definition Atom.h:14
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54
Structure to store neutronic scattering information for the various elements.
Definition NeutronAtom.h:22
static const double ReferenceLambda
The reference wavelength value for absorption cross sections.
Definition NeutronAtom.h:25