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