Mantid
Loading...
Searching...
No Matches
SCDCalibratePanels.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 +
13#include "MantidAPI/IFunction.h"
15#include "MantidAPI/Run.h"
16#include "MantidAPI/Sample.h"
29#include <boost/container/flat_set.hpp>
30#include <boost/math/special_functions/round.hpp>
31#include <fstream>
32#include <sstream>
33
34using namespace Mantid::DataObjects;
35using namespace Mantid::API;
36using namespace std;
37using namespace Mantid::Geometry;
38using namespace Mantid::Kernel;
39
40namespace Mantid::Crystal {
41
42DECLARE_ALGORITHM(SCDCalibratePanels)
43
44// Default constructor
46 useAlgorithm("SCDCalibratePanels", 2);
47 deprecatedDate("2025-05-27");
48}
49
50const std::string SCDCalibratePanels::name() const { return "SCDCalibratePanels"; }
51
52int SCDCalibratePanels::version() const { return 1; }
53
54const std::string SCDCalibratePanels::category() const { return "Crystal\\Corrections"; }
55
57 PeaksWorkspace_sptr peaksWs = getProperty("PeakWorkspace");
58 // We must sort the peaks
59 std::vector<std::pair<std::string, bool>> criteria{{"BankName", true}};
60 peaksWs->sort(criteria);
61 // Remove peaks on edge
62 int edge = this->getProperty("EdgePixels");
63 Geometry::Instrument_const_sptr inst = peaksWs->getInstrument();
64 if (edge > 0) {
65 std::vector<Peak> &peaks = peaksWs->getPeaks();
66 auto it = std::remove_if(peaks.begin(), peaks.end(), [edge, inst](const Peak &pk) {
67 return edgePixel(inst, pk.getBankName(), pk.getCol(), pk.getRow(), edge);
68 });
69 peaks.erase(it, peaks.end());
70 }
71 findU(peaksWs);
72
73 auto nPeaks = static_cast<int>(peaksWs->getNumberPeaks());
74 bool changeL1 = getProperty("ChangeL1");
75 bool changeT0 = getProperty("ChangeT0");
76 bool bankPanels = getProperty("CalibrateBanks");
77 bool snapPanels = getProperty("CalibrateSNAPPanels");
78
79 if (changeT0)
80 findT0(nPeaks, peaksWs);
81 if (changeL1)
82 findL1(nPeaks, peaksWs);
83
84 boost::container::flat_set<string> MyBankNames;
85 boost::container::flat_set<string> MyPanels;
86 if (snapPanels) {
87 MyPanels.insert("East");
88 MyPanels.insert("West");
89 int maxRecurseDepth = 4;
90
91 PRAGMA_OMP(parallel for schedule(dynamic, 1) )
92 for (int num = 1; num < 64; ++num) {
94 std::ostringstream mess;
95 mess << "bank" << num;
96 IComponent_const_sptr comp = inst->getComponentByName(mess.str(), maxRecurseDepth);
97 PARALLEL_CRITICAL(MyBankNames)
98 if (comp)
99 MyBankNames.insert(mess.str());
101 }
103 } else {
104 for (int i = 0; i < nPeaks; ++i) {
105 std::string bankName = peaksWs->getPeak(i).getBankName();
106 if (bankName != "None")
107 MyBankNames.insert(bankName);
108 }
109 }
110
111 std::vector<std::string> fit_workspaces(MyBankNames.size() + MyPanels.size(), "fit_");
112 std::vector<std::string> parameter_workspaces(MyBankNames.size() + MyPanels.size(), "params_");
113 int bankAndPanelCount = 0;
114 for (const auto &MyPanel : MyPanels) {
115 fit_workspaces[bankAndPanelCount] += MyPanel;
116 parameter_workspaces[bankAndPanelCount] += MyPanel;
117 bankAndPanelCount++;
118 }
119 if (snapPanels) {
120 findL2(MyPanels, peaksWs);
121 ITableWorkspace_sptr results = AnalysisDataService::Instance().retrieveWS<ITableWorkspace>("params_West");
122 double delta = results->cell<double>(4, 1);
123 g_log.notice() << "For west rotation change det_arc1 " << delta << " degrees\n";
124 results = AnalysisDataService::Instance().retrieveWS<ITableWorkspace>("params_East");
125 delta = results->cell<double>(4, 1);
126 g_log.notice() << "For east rotation change det_arc2 " << delta << " degrees\n";
127 }
128
129 for (const auto &MyBankName : MyBankNames) {
130 fit_workspaces[bankAndPanelCount] += MyBankName;
131 parameter_workspaces[bankAndPanelCount] += MyBankName;
132 bankAndPanelCount++;
133 }
134 if (bankPanels) {
135 findL2(MyBankNames, peaksWs);
136 }
137
138 // remove skipped banks
139 for (int j = bankAndPanelCount - 1; j >= 0; j--) {
140 if (!AnalysisDataService::Instance().doesExist(fit_workspaces[j]))
141 fit_workspaces.erase(fit_workspaces.begin() + j);
142 if (!AnalysisDataService::Instance().doesExist(parameter_workspaces[j]))
143 parameter_workspaces.erase(parameter_workspaces.begin() + j);
144 }
145
146 // Try again to optimize L1
147 if (changeL1) {
148 findL1(nPeaks, peaksWs);
149 parameter_workspaces.emplace_back("params_L1");
150 fit_workspaces.emplace_back("fit_L1");
151 }
152 // Add T0 files to groups
153 if (changeT0) {
154 parameter_workspaces.emplace_back("params_T0");
155 fit_workspaces.emplace_back("fit_T0");
156 }
157 std::sort(parameter_workspaces.begin(), parameter_workspaces.end());
158 std::sort(fit_workspaces.begin(), fit_workspaces.end());
159
160 // collect output of fit for each spectrum into workspace groups
161 auto groupAlg = AlgorithmManager::Instance().createUnmanaged("GroupWorkspaces");
162 groupAlg->initialize();
163 groupAlg->setProperty("InputWorkspaces", parameter_workspaces);
164 groupAlg->setProperty("OutputWorkspace", "Fit_Parameters");
165 groupAlg->execute();
166
167 groupAlg = AlgorithmManager::Instance().createUnmanaged("GroupWorkspaces");
168 groupAlg->initialize();
169 groupAlg->setProperty("InputWorkspaces", fit_workspaces);
170 groupAlg->setProperty("OutputWorkspace", "Fit_Residuals");
171 groupAlg->execute();
172
173 // Use new instrument for PeaksWorkspace
174 Geometry::Instrument_sptr inst2 = std::const_pointer_cast<Geometry::Instrument>(peaksWs->getInstrument());
175 Geometry::OrientedLattice lattice0 = peaksWs->mutableSample().getOrientedLattice();
177 for (int i = 0; i < nPeaks; i++) {
179 DataObjects::Peak &peak = peaksWs->getPeak(i);
180 try {
181 peak.setInstrument(inst2);
182 } catch (const std::exception &exc) {
183 g_log.notice() << "Problem in applying calibration to peak " << i << " : " << exc.what() << "\n";
184 }
186 }
188
189 // Find U again for optimized geometry and index peaks
190 findU(peaksWs);
191 // Save as DetCal and XML if requested
192 string DetCalFileName = getProperty("DetCalFilename");
193 API::Run &run = peaksWs->mutableRun();
194 double T0 = 0.0;
195 if (run.hasProperty("T0")) {
196 T0 = run.getPropertyValueAsType<double>("T0");
197 }
198 saveIsawDetCal(inst2, MyBankNames, T0, DetCalFileName);
199 string XmlFileName = getProperty("XmlFilename");
200 saveXmlFile(XmlFileName, MyBankNames, *inst2);
201 // create table of theoretical vs calculated
202 //----------------- Calculate & Create Calculated vs Theoretical
203 // workspaces------------------,);
204 MatrixWorkspace_sptr ColWksp =
205 Mantid::API::WorkspaceFactory::Instance().create("Workspace2D", MyBankNames.size(), nPeaks, nPeaks);
206 ColWksp->setInstrument(inst2);
207 MatrixWorkspace_sptr RowWksp =
208 Mantid::API::WorkspaceFactory::Instance().create("Workspace2D", MyBankNames.size(), nPeaks, nPeaks);
209 RowWksp->setInstrument(inst2);
210 MatrixWorkspace_sptr TofWksp =
211 Mantid::API::WorkspaceFactory::Instance().create("Workspace2D", MyBankNames.size(), nPeaks, nPeaks);
212 TofWksp->setInstrument(inst2);
213 OrientedLattice lattice = peaksWs->mutableSample().getOrientedLattice();
214 const DblMatrix &UB = lattice.getUB();
215 // sort again since edge peaks can trace to other banks
216 peaksWs->sort(criteria);
217 PARALLEL_FOR_IF(Kernel::threadSafe(*ColWksp, *RowWksp, *TofWksp))
218 for (int i = 0; i < static_cast<int>(MyBankNames.size()); ++i) {
220 const std::string &bankName = *std::next(MyBankNames.begin(), i);
221 size_t k = bankName.find_last_not_of("0123456789");
222 int bank = 0;
223 if (k < bankName.length())
224 bank = boost::lexical_cast<int>(bankName.substr(k + 1));
225 ColWksp->getSpectrum(i).setSpectrumNo(specnum_t(bank));
226 RowWksp->getSpectrum(i).setSpectrumNo(specnum_t(bank));
227 TofWksp->getSpectrum(i).setSpectrumNo(specnum_t(bank));
228 auto &ColX = ColWksp->mutableX(i);
229 auto &ColY = ColWksp->mutableY(i);
230 auto &RowX = RowWksp->mutableX(i);
231 auto &RowY = RowWksp->mutableY(i);
232 auto &TofX = TofWksp->mutableX(i);
233 auto &TofY = TofWksp->mutableY(i);
234 int icount = 0;
235 for (int j = 0; j < nPeaks; j++) {
236 Peak peak = peaksWs->getPeak(j);
237 if (peak.getBankName() == bankName) {
238 try {
239 V3D q_lab = (peak.getGoniometerMatrix() * UB) * peak.getHKL() * M_2_PI;
240 Peak theoretical(peak.getInstrument(), q_lab);
241 ColX[icount] = peak.getCol();
242 ColY[icount] = theoretical.getCol();
243 RowX[icount] = peak.getRow();
244 RowY[icount] = theoretical.getRow();
245 TofX[icount] = peak.getTOF();
246 TofY[icount] = theoretical.getTOF();
247 } catch (...) {
248 // g_log.debug() << "Problem only in printing peaks\n";
249 }
250 icount++;
251 }
252 }
254 }
256
257 string colFilename = getProperty("ColFilename");
258 string rowFilename = getProperty("RowFilename");
259 string tofFilename = getProperty("TofFilename");
260 saveNexus(colFilename, ColWksp);
261 saveNexus(rowFilename, RowWksp);
262 saveNexus(tofFilename, TofWksp);
263}
264
265void SCDCalibratePanels::saveNexus(const std::string &outputFile, const MatrixWorkspace_sptr &outputWS) {
266 auto save = createChildAlgorithm("SaveNexus");
267 save->setProperty("InputWorkspace", outputWS);
268 save->setProperty("FileName", outputFile);
269 save->execute();
270}
271
273 MatrixWorkspace_sptr L1WS = std::dynamic_pointer_cast<MatrixWorkspace>(
274 API::WorkspaceFactory::Instance().create("Workspace2D", 1, 3 * nPeaks, 3 * nPeaks));
275
276 IAlgorithm_sptr fitL1_alg;
277 try {
278 fitL1_alg = createChildAlgorithm("Fit", -1, -1, false);
279 } catch (Exception::NotFoundError &) {
280 g_log.error("Can't locate Fit algorithm");
281 throw;
282 }
283 std::ostringstream fun_str;
284 fun_str << "name=SCDPanelErrors,Workspace=" << peaksWs->getName() << ",Bank=moderator";
285 std::ostringstream tie_str;
286 tie_str << "XShift=0.0,YShift=0.0,XRotate=0.0,YRotate=0.0,ZRotate=0.0,"
287 "ScaleWidth=1.0,ScaleHeight=1.0,T0Shift ="
288 << mT0;
289 fitL1_alg->setPropertyValue("Function", fun_str.str());
290 fitL1_alg->setProperty("Ties", tie_str.str());
291 fitL1_alg->setProperty("InputWorkspace", L1WS);
292 fitL1_alg->setProperty("CreateOutput", true);
293 fitL1_alg->setProperty("Output", "fit");
294 fitL1_alg->executeAsChildAlg();
295 std::string fitL1Status = fitL1_alg->getProperty("OutputStatus");
296 double chisqL1 = fitL1_alg->getProperty("OutputChi2overDoF");
297 MatrixWorkspace_sptr fitL1 = fitL1_alg->getProperty("OutputWorkspace");
298 AnalysisDataService::Instance().addOrReplace("fit_L1", fitL1);
299 ITableWorkspace_sptr paramsL1 = fitL1_alg->getProperty("OutputParameters");
300 AnalysisDataService::Instance().addOrReplace("params_L1", paramsL1);
301 double deltaL1 = paramsL1->getRef<double>("Value", 2);
302 SCDPanelErrors com;
303 com.moveDetector(0.0, 0.0, deltaL1, 0.0, 0.0, 0.0, 1.0, 1.0, "moderator", peaksWs);
304 g_log.notice() << "L1 = " << -peaksWs->getInstrument()->getSource()->getPos().Z() << " " << fitL1Status
305 << " Chi2overDoF " << chisqL1 << "\n";
306}
307
309 MatrixWorkspace_sptr T0WS = std::dynamic_pointer_cast<MatrixWorkspace>(
310 API::WorkspaceFactory::Instance().create("Workspace2D", 1, 3 * nPeaks, 3 * nPeaks));
311
312 IAlgorithm_sptr fitT0_alg;
313 try {
314 fitT0_alg = createChildAlgorithm("Fit", -1, -1, false);
315 } catch (Exception::NotFoundError &) {
316 g_log.error("Can't locate Fit algorithm");
317 throw;
318 }
319 std::ostringstream fun_str;
320 fun_str << "name=SCDPanelErrors,Workspace=" << peaksWs->getName() << ",Bank=none";
321 std::ostringstream tie_str;
322 tie_str << "XShift=0.0,YShift=0.0,ZShift=0.0,XRotate=0.0,YRotate=0.0,ZRotate=0.0,"
323 "ScaleWidth=1.0,ScaleHeight=1.0";
324 fitT0_alg->setPropertyValue("Function", fun_str.str());
325 fitT0_alg->setProperty("Ties", tie_str.str());
326 fitT0_alg->setProperty("InputWorkspace", T0WS);
327 fitT0_alg->setProperty("CreateOutput", true);
328 fitT0_alg->setProperty("Output", "fit");
329 // Does not converge with derviative minimizers
330 fitT0_alg->setProperty("Minimizer", "Simplex");
331 fitT0_alg->setProperty("MaxIterations", 1000);
332 fitT0_alg->executeAsChildAlg();
333 std::string fitT0Status = fitT0_alg->getProperty("OutputStatus");
334 double chisqT0 = fitT0_alg->getProperty("OutputChi2overDoF");
335 MatrixWorkspace_sptr fitT0 = fitT0_alg->getProperty("OutputWorkspace");
336 AnalysisDataService::Instance().addOrReplace("fit_T0", fitT0);
337 ITableWorkspace_sptr paramsT0 = fitT0_alg->getProperty("OutputParameters");
338 AnalysisDataService::Instance().addOrReplace("params_T0", paramsT0);
339 mT0 = paramsT0->getRef<double>("Value", 8);
340 API::Run &run = peaksWs->mutableRun();
341 // set T0 in the run parameters adding to value in peaks file
342 double oldT0 = 0.0;
343 if (run.hasProperty("T0")) {
344 oldT0 = run.getPropertyValueAsType<double>("T0");
345 }
346 run.addProperty<double>("T0", mT0 + oldT0, true);
347 g_log.notice() << "T0 = " << mT0 << " " << fitT0Status << " Chi2overDoF " << chisqT0 << "\n";
348 for (int i = 0; i < peaksWs->getNumberPeaks(); i++) {
349 DataObjects::Peak &peak = peaksWs->getPeak(i);
350
352
353 wl.initialize(peak.getL1(), 0, {{UnitParams::l2, peak.getL2()}, {UnitParams::twoTheta, peak.getScattering()}});
354 peak.setWavelength(wl.singleFromTOF(peak.getTOF() + mT0));
355 }
356}
357
359 IAlgorithm_sptr ub_alg;
360 try {
361 ub_alg = createChildAlgorithm("CalculateUMatrix", -1, -1, false);
362 } catch (Exception::NotFoundError &) {
363 g_log.error("Can't locate CalculateUMatrix algorithm");
364 throw;
365 }
366 double a = getProperty("a");
367 double b = getProperty("b");
368 double c = getProperty("c");
369 double alpha = getProperty("alpha");
370 double beta = getProperty("beta");
371 double gamma = getProperty("gamma");
372 if ((a == EMPTY_DBL() || b == EMPTY_DBL() || c == EMPTY_DBL() || alpha == EMPTY_DBL() || beta == EMPTY_DBL() ||
373 gamma == EMPTY_DBL()) &&
374 peaksWs->sample().hasOrientedLattice()) {
375 OrientedLattice latt = peaksWs->mutableSample().getOrientedLattice();
376 a = latt.a();
377 b = latt.b();
378 c = latt.c();
379 alpha = latt.alpha();
380 beta = latt.beta();
381 gamma = latt.gamma();
382 }
383 ub_alg->setProperty("PeaksWorkspace", peaksWs);
384 ub_alg->setProperty("a", a);
385 ub_alg->setProperty("b", b);
386 ub_alg->setProperty("c", c);
387 ub_alg->setProperty("alpha", alpha);
388 ub_alg->setProperty("beta", beta);
389 ub_alg->setProperty("gamma", gamma);
390 ub_alg->executeAsChildAlg();
391
392 // Reindex peaks with new UB
393 auto alg = createChildAlgorithm("IndexPeaks");
394 alg->setPropertyValue("PeaksWorkspace", peaksWs->getName());
395 alg->setProperty("Tolerance", 0.15);
396 alg->executeAsChildAlg();
397 int numIndexed = alg->getProperty("NumIndexed");
398 g_log.notice() << "Number Indexed = " << numIndexed << "\n";
399 g_log.notice() << peaksWs->sample().getOrientedLattice().getUB() << "\n";
400}
401
412void SCDCalibratePanels::saveIsawDetCal(std::shared_ptr<Instrument> &instrument,
413 boost::container::flat_set<string> &AllBankName, double T0,
414 const string &filename) {
415 // having a filename triggers doing the work
416 if (filename.empty())
417 return;
418
419 g_log.notice() << "Saving DetCal file in " << filename << "\n";
420
421 // create a workspace to pass to SaveIsawDetCal
422 const size_t number_spectra = instrument->getNumberDetectors();
423 DataObjects::Workspace2D_sptr wksp = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
424 WorkspaceFactory::Instance().create("Workspace2D", number_spectra, 2, 1));
425 wksp->setInstrument(instrument);
426 wksp->rebuildSpectraMapping(true /* include monitors */);
427
428 // convert the bank names into a vector
429 std::vector<string> banknames(AllBankName.begin(), AllBankName.end());
430
431 // call SaveIsawDetCal
432 auto alg = createChildAlgorithm("SaveIsawDetCal");
433 alg->setProperty("InputWorkspace", wksp);
434 alg->setProperty("Filename", filename);
435 alg->setProperty("TimeOffset", T0);
436 alg->setProperty("BankNames", banknames);
437 alg->executeAsChildAlg();
438}
439
441 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("PeakWorkspace", "", Kernel::Direction::InOut),
442 "Workspace of Indexed Peaks");
443
444 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
445 mustBePositive->setLower(0.0);
446
447 declareProperty("a", EMPTY_DBL(), mustBePositive,
448 "Lattice Parameter a (Leave empty to use lattice constants "
449 "in peaks workspace)");
450 declareProperty("b", EMPTY_DBL(), mustBePositive,
451 "Lattice Parameter b (Leave empty to use lattice constants "
452 "in peaks workspace)");
453 declareProperty("c", EMPTY_DBL(), mustBePositive,
454 "Lattice Parameter c (Leave empty to use lattice constants "
455 "in peaks workspace)");
456 declareProperty("alpha", EMPTY_DBL(), mustBePositive,
457 "Lattice Parameter alpha in degrees (Leave empty to use "
458 "lattice constants in peaks workspace)");
459 declareProperty("beta", EMPTY_DBL(), mustBePositive,
460 "Lattice Parameter beta in degrees (Leave empty to use "
461 "lattice constants in peaks workspace)");
462 declareProperty("gamma", EMPTY_DBL(), mustBePositive,
463 "Lattice Parameter gamma in degrees (Leave empty to use "
464 "lattice constants in peaks workspace)");
465 declareProperty("ChangeL1", true, "Change the L1(source to sample) distance");
466 declareProperty("ChangeT0", false, "Change the T0 (initial TOF)");
467 declareProperty("ChangePanelSize", true,
468 "Change the height and width of the "
469 "detectors. Implemented only for "
470 "RectangularDetectors.");
471
472 declareProperty("EdgePixels", 0, "Remove peaks that are at pixels this close to edge. ");
473 declareProperty("CalibrateBanks", true, "Calibrate the panels of the banks.");
474 declareProperty("CalibrateSNAPPanels", false,
475 "Calibrate the 3 X 3 panels of the "
476 "sides of SNAP.");
477
478 // ---------- outputs
479 const std::vector<std::string> detcalExts{".DetCal", ".Det_Cal"};
481 std::make_unique<FileProperty>("DetCalFilename", "SCDCalibrate.DetCal", FileProperty::Save, detcalExts),
482 "Path to an ISAW-style .detcal file to save.");
483
484 declareProperty(std::make_unique<FileProperty>("XmlFilename", "", FileProperty::OptionalSave, ".xml"),
485 "Path to an Mantid .xml description(for LoadParameterFile) file to "
486 "save.");
487
488 declareProperty(std::make_unique<FileProperty>("ColFilename", "ColCalcvsTheor.nxs", FileProperty::Save, ".nxs"),
489 "Path to a NeXus file comparing calculated and theoretical "
490 "column of each peak.");
491
492 declareProperty(std::make_unique<FileProperty>("RowFilename", "RowCalcvsTheor.nxs", FileProperty::Save, ".nxs"),
493 "Path to a NeXus file comparing calculated and theoretical "
494 "row of each peak.");
495
496 declareProperty(std::make_unique<FileProperty>("TofFilename", "TofCalcvsTheor.nxs", FileProperty::Save, ".nxs"),
497 "Path to a NeXus file comparing calculated and theoretical "
498 "TOF of each peak.");
499
500 const string OUTPUTS("Outputs");
501 setPropertyGroup("DetCalFilename", OUTPUTS);
502 setPropertyGroup("XmlFilename", OUTPUTS);
503 setPropertyGroup("ColFilename", OUTPUTS);
504 setPropertyGroup("RowFilename", OUTPUTS);
505 setPropertyGroup("TofFilename", OUTPUTS);
506}
507
508void writeXmlParameter(ofstream &ostream, const string &name, const double value) {
509 ostream << " <parameter name =\"" << name << "\"><value val=\"" << value << "\" /> </parameter>\n";
510}
511
512void SCDCalibratePanels::saveXmlFile(const string &FileName, const boost::container::flat_set<string> &AllBankNames,
513 const Instrument &instrument) const {
514 if (FileName.empty())
515 return;
516
517 g_log.notice() << "Saving parameter file as " << FileName << "\n";
518
519 // create the file and add the header
520 ofstream oss3(FileName.c_str());
521 oss3 << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
522 oss3 << " <parameter-file instrument=\"" << instrument.getName() << "\" valid-from=\""
523 << instrument.getValidFromDate().toISO8601String() << "\">\n";
525
526 // write out the detector banks
527 for (auto bankName : AllBankNames) {
528 if (instrument.getName().compare("CORELLI") == 0.0)
529 bankName.append("/sixteenpack");
530 oss3 << "<component-link name=\"" << bankName << "\">\n";
531 std::shared_ptr<const IComponent> bank = instrument.getComponentByName(bankName);
532
533 Quat relRot = bank->getRelativeRot();
534
535 std::vector<double> relRotAngles = relRot.getEulerAngles("XYZ");
536
537 writeXmlParameter(oss3, "rotx", relRotAngles[0]);
538 writeXmlParameter(oss3, "roty", relRotAngles[1]);
539 writeXmlParameter(oss3, "rotz", relRotAngles[2]);
540
541 V3D pos1 = bank->getRelativePos();
542 writeXmlParameter(oss3, "x", pos1.X());
543 writeXmlParameter(oss3, "y", pos1.Y());
544 writeXmlParameter(oss3, "z", pos1.Z());
545
546 vector<double> oldScalex = pmap->getDouble(bank->getName(), string("scalex"));
547 vector<double> oldScaley = pmap->getDouble(bank->getName(), string("scaley"));
548
549 double scalex, scaley;
550 if (!oldScalex.empty())
551 scalex = oldScalex[0];
552 else
553 scalex = 1.;
554
555 if (!oldScaley.empty())
556 scaley = oldScaley[0];
557 else
558 scaley = 1.;
559
560 oss3 << R"( <parameter name ="scalex"><value val=")" << scalex << "\" /> </parameter>\n";
561 oss3 << R"( <parameter name ="scaley"><value val=")" << scaley << "\" /> </parameter>\n";
562 oss3 << "</component-link>\n";
563 } // for each bank in the group
564
565 // write out the source
566 IComponent_const_sptr source = instrument.getSource();
567
568 oss3 << "<component-link name=\"" << source->getName() << "\">\n";
569 V3D sourceRelPos = source->getRelativePos();
570
571 writeXmlParameter(oss3, "x", sourceRelPos.X());
572 writeXmlParameter(oss3, "y", sourceRelPos.Y());
573 writeXmlParameter(oss3, "z", sourceRelPos.Z());
574 oss3 << "</component-link>\n";
575 oss3 << "</parameter-file>\n";
576
577 // flush and close the file
578 oss3.flush();
579 oss3.close();
580}
581void SCDCalibratePanels::findL2(boost::container::flat_set<string> MyBankNames,
582 const DataObjects::PeaksWorkspace_sptr &peaksWs) {
583 bool changeSize = getProperty("ChangePanelSize");
584 Geometry::Instrument_const_sptr inst = peaksWs->getInstrument();
585
587 for (int bankIndex = 0; bankIndex < static_cast<int>(MyBankNames.size()); ++bankIndex) {
589 const std::string &iBank = *std::next(MyBankNames.begin(), bankIndex);
590 const std::string bankName = "__PWS_" + iBank;
591 PeaksWorkspace_sptr local = peaksWs->clone();
592 AnalysisDataService::Instance().addOrReplace(bankName, local);
593 std::vector<Peak> &localPeaks = local->getPeaks();
594 auto lit = std::remove_if(localPeaks.begin(), localPeaks.end(), [&iBank](const Peak &pk) {
595 std::string name = pk.getBankName();
596 IComponent_const_sptr det = pk.getInstrument()->getComponentByName(name);
597 if (det && iBank.substr(0, 4) != "bank") {
598 IComponent_const_sptr parent = det->getParent();
599 if (parent) {
600 IComponent_const_sptr grandparent = parent->getParent();
601 if (grandparent) {
602 name = grandparent->getName();
603 }
604 }
605 }
606
607 return name != iBank;
608 });
609 localPeaks.erase(lit, localPeaks.end());
610
611 int nBankPeaks = local->getNumberPeaks();
612 if (nBankPeaks < 6) {
613 g_log.notice() << "Too few peaks for " << iBank << "\n";
614 continue;
615 }
616
617 MatrixWorkspace_sptr q3DWS = std::dynamic_pointer_cast<MatrixWorkspace>(
618 API::WorkspaceFactory::Instance().create("Workspace2D", 1, 3 * nBankPeaks, 3 * nBankPeaks));
619
620 auto &outSpec = q3DWS->getSpectrum(0);
621 auto &yVec = outSpec.mutableY();
622 auto &eVec = outSpec.mutableE();
623 auto &xVec = outSpec.mutableX();
624 yVec = 0.0;
625
626 for (int i = 0; i < nBankPeaks; i++) {
627 const DataObjects::Peak &peak = local->getPeak(i);
628 // 1/sigma is considered the weight for the fit
629 double weight = 1.; // default is even weighting
630 if (peak.getSigmaIntensity() > 0.) // prefer weight by sigmaI
631 weight = 1.0 / peak.getSigmaIntensity();
632 else if (peak.getIntensity() > 0.) // next favorite weight by I
633 weight = 1.0 / peak.getIntensity();
634 else if (peak.getBinCount() > 0.) // then by counts in peak centre
635 weight = 1.0 / peak.getBinCount();
636 for (int j = 0; j < 3; j++) {
637 int k = i * 3 + j;
638 xVec[k] = k;
639 eVec[k] = weight;
640 }
641 }
642
643 IAlgorithm_sptr fit_alg;
644 try {
645 fit_alg = createChildAlgorithm("Fit", -1, -1, false);
646 } catch (Exception::NotFoundError &) {
647 g_log.error("Can't locate Fit algorithm");
648 throw;
649 }
650 std::ostringstream fun_str;
651 fun_str << "name=SCDPanelErrors,Workspace=" + bankName << ",Bank=" << iBank;
652 fit_alg->setPropertyValue("Function", fun_str.str());
653 std::ostringstream tie_str;
654 tie_str << "ScaleWidth=1.0,ScaleHeight=1.0,T0Shift =" << mT0;
655 fit_alg->setProperty("Ties", tie_str.str());
656 fit_alg->setProperty("InputWorkspace", q3DWS);
657 fit_alg->setProperty("CreateOutput", true);
658 fit_alg->setProperty("Output", "fit");
659 fit_alg->executeAsChildAlg();
660 std::string fitStatus = fit_alg->getProperty("OutputStatus");
661 double fitChisq = fit_alg->getProperty("OutputChi2overDoF");
662 g_log.notice() << iBank << " " << fitStatus << " Chi2overDoF " << fitChisq << "\n";
663 MatrixWorkspace_sptr fitWS = fit_alg->getProperty("OutputWorkspace");
664 AnalysisDataService::Instance().addOrReplace("fit_" + iBank, fitWS);
665 ITableWorkspace_sptr paramsWS = fit_alg->getProperty("OutputParameters");
666 AnalysisDataService::Instance().addOrReplace("params_" + iBank, paramsWS);
667 double xShift = paramsWS->getRef<double>("Value", 0);
668 double yShift = paramsWS->getRef<double>("Value", 1);
669 double zShift = paramsWS->getRef<double>("Value", 2);
670 double xRotate = paramsWS->getRef<double>("Value", 3);
671 double yRotate = paramsWS->getRef<double>("Value", 4);
672 double zRotate = paramsWS->getRef<double>("Value", 5);
673 double scaleWidth = 1.0;
674 double scaleHeight = 1.0;
675 // Scaling only implemented for Rectangular Detectors
676 Geometry::IComponent_const_sptr comp = peaksWs->getInstrument()->getComponentByName(iBank);
677 std::shared_ptr<const Geometry::RectangularDetector> rectDet =
678 std::dynamic_pointer_cast<const Geometry::RectangularDetector>(comp);
679 if (rectDet && changeSize) {
680 IAlgorithm_sptr fit2_alg;
681 try {
682 fit2_alg = createChildAlgorithm("Fit", -1, -1, false);
683 } catch (Exception::NotFoundError &) {
684 g_log.error("Can't locate Fit algorithm");
685 throw;
686 }
687 fit2_alg->setPropertyValue("Function", fun_str.str());
688 std::ostringstream tie_str2;
689 tie_str2 << "XShift=" << xShift << ",YShift=" << yShift << ",ZShift=" << zShift << ",XRotate=" << xRotate
690 << ",YRotate=" << yRotate << ",ZRotate=" << zRotate << ",T0Shift =" << mT0;
691 fit2_alg->setProperty("Ties", tie_str2.str());
692 fit2_alg->setProperty("InputWorkspace", q3DWS);
693 fit2_alg->setProperty("CreateOutput", true);
694 fit2_alg->setProperty("Output", "fit");
695 fit2_alg->executeAsChildAlg();
696 std::string fit2Status = fit2_alg->getProperty("OutputStatus");
697 double fit2Chisq = fit2_alg->getProperty("OutputChi2overDoF");
698 g_log.notice() << iBank << " " << fit2Status << " Chi2overDoF " << fit2Chisq << "\n";
699 fitWS = fit2_alg->getProperty("OutputWorkspace");
700 AnalysisDataService::Instance().addOrReplace("fit_" + iBank, fitWS);
701 paramsWS = fit2_alg->getProperty("OutputParameters");
702 AnalysisDataService::Instance().addOrReplace("params_" + iBank, paramsWS);
703 scaleWidth = paramsWS->getRef<double>("Value", 6);
704 scaleHeight = paramsWS->getRef<double>("Value", 7);
705 }
706 AnalysisDataService::Instance().remove(bankName);
707 SCDPanelErrors det;
708 det.moveDetector(xShift, yShift, zShift, xRotate, yRotate, zRotate, scaleWidth, scaleHeight, iBank, peaksWs);
710 }
712}
713} // namespace Mantid::Crystal
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double value
The value of the point.
Definition FitMW.cpp:51
int numIndexed
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_CRITICAL(name)
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PRAGMA_OMP(expression)
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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
@ OptionalSave
to specify a file to write to but an empty string is
@ Save
to specify a file to write to, the file may or may not exist
ITableWorkspace is an implementation of Workspace in which the data are organised in columns of same ...
T & cell(size_t row, size_t col)
Get the reference to the element in row row and column col.
bool hasProperty(const std::string &name) const
Does the property exist on the object.
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.
SCDCalibratePanels calibrates instrument parameters for Rectangular Detectors.
void saveXmlFile(const std::string &FileName, const boost::container::flat_set< std::string > &AllBankNames, const Geometry::Instrument &instrument) const
Saves the new instrument to an xml file that can be used with the LoadParameterFile Algorithm.
void init() override
Virtual method - must be overridden by concrete algorithm.
const std::string name() const override
function to return a name of the algorithm, must be overridden in all algorithms
void findT0(int nPeaks, const DataObjects::PeaksWorkspace_sptr &peaksWs)
Function to optimize T0.
void findL2(boost::container::flat_set< std::string > MyBankNames, const DataObjects::PeaksWorkspace_sptr &peaksWs)
Function to optimize L2.
int version() const override
Algorithm's version for identification overriding a virtual method.
void saveIsawDetCal(std::shared_ptr< Geometry::Instrument > &instrument, boost::container::flat_set< std::string > &AllBankName, double T0, const std::string &filename)
Really this is the operator SaveIsawDetCal but only the results of the given banks are saved.
void findU(const DataObjects::PeaksWorkspace_sptr &peaksWs)
Function to calculate U.
void exec() override
Virtual method - must be overridden by concrete algorithm.
void saveNexus(const std::string &outputFile, const API::MatrixWorkspace_sptr &outputWS)
save workspaces
void findL1(int nPeaks, const DataObjects::PeaksWorkspace_sptr &peaksWs)
Function to optimize L1.
const std::string category() const override
Algorithm's category for identification overriding a virtual method.
void moveDetector(double x, double y, double z, double rotx, double roty, double rotz, double scalex, double scaley, std::string detname, const API::Workspace_sptr &inputW) const
Move detectors with parameters.
double getIntensity() const override
Return the integrated peak intensity.
Definition BasePeak.cpp:184
double getSigmaIntensity() const override
Return the error on the integrated peak intensity.
Definition BasePeak.cpp:187
Mantid::Kernel::V3D getHKL() const override
Return the HKL vector.
Definition BasePeak.cpp:102
double getBinCount() const override
Return the # of counts in the bin at its peak.
Definition BasePeak.cpp:181
Mantid::Kernel::Matrix< double > getGoniometerMatrix() const override
Get the goniometer rotation matrix at which this peak was measured.
Definition BasePeak.cpp:209
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
Geometry::Instrument_const_sptr getInstrument() const
Return a shared ptr to the instrument for this peak.
Definition Peak.cpp:320
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
void setWavelength(double wavelength) override
Set the incident wavelength of the neutron.
Definition Peak.cpp:188
double getL1() const override
Return the L1 flight path length (source to sample), in meters.
Definition Peak.cpp:724
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
void setInstrument(const Geometry::Instrument_const_sptr &inst)
Set the instrument (and save the source/sample pos).
Definition Peak.cpp:294
double getScattering() const override
Calculate the scattering angle of the peak
Definition Peak.cpp:391
std::shared_ptr< const IComponent > getComponentByName(const std::string &cname, int nlevels=0) const override
Returns a pointer to the first component of assembly encountered with the given name.
std::string getName() const override
Get the IComponent name.
Base Instrument Class.
Definition Instrument.h:47
IComponent_const_sptr getSource() const
Gets a pointer to the source.
std::shared_ptr< ParameterMap > getParameterMap() const
Pointer to the NOT const ParameterMap holding the parameters of the modified instrument components.
Types::Core::DateAndTime getValidFromDate() const
Definition Instrument.h:169
Class to implement UB matrix.
const Kernel::DblMatrix & getUB() const
Get the UB matrix.
double alpha() const
Get lattice parameter.
Definition UnitCell.cpp:133
double a(int nd) const
Get lattice parameter a1-a3 as function of index (0-2)
Definition UnitCell.cpp:94
double c() const
Get lattice parameter.
Definition UnitCell.cpp:128
double beta() const
Get lattice parameter.
Definition UnitCell.cpp:138
double b() const
Get lattice parameter.
Definition UnitCell.cpp:123
double gamma() const
Get lattice parameter.
Definition UnitCell.cpp:143
Exception for when an item is not found in a collection.
Definition Exception.h:145
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
Class for quaternions.
Definition Quat.h:39
std::vector< double > getEulerAngles(const std::string &convention) const
Calculate the Euler angles that are equivalent to this Quaternion.
Definition Quat.cpp:729
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
void initialize(const double &_l1, const int &_emode, const UnitParametersMap &params)
Initialize the unit to perform conversion using singleToTof() and singleFromTof()
Definition Unit.cpp:133
Wavelength in Angstrom.
Definition Unit.h:267
double singleFromTOF(const double tof) const override
Convert a single tof value to this unit.
Definition Unit.cpp:394
Class for 3D vectors.
Definition V3D.h:34
constexpr double X() const noexcept
Get x.
Definition V3D.h:238
constexpr double Y() const noexcept
Get y.
Definition V3D.h:239
constexpr double Z() const noexcept
Get z.
Definition V3D.h:240
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void writeXmlParameter(ofstream &ostream, const string &name, const double value)
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
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 IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition IComponent.h:167
std::shared_ptr< ParameterMap > ParameterMap_sptr
ParameterMap shared pointer typedef.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
std::shared_ptr< Instrument > Instrument_sptr
Shared pointer to an instrument object.
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
Generate a tableworkspace to store the calibration results.
adjust instrument component position and orientation
: detector size scale at y-direction
STL namespace.
@ InOut
Both an input & output workspace.
Definition Property.h:55