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