Mantid
Loading...
Searching...
No Matches
SCDCalibratePanels2.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 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 +
7
15#include "MantidAPI/Run.h"
16#include "MantidAPI/Sample.h"
17#include "MantidAPI/TableRow.h"
26#include "MantidKernel/Logger.h"
27#include <boost/container/flat_set.hpp>
28#include <boost/property_tree/ptree.hpp>
29#include <boost/property_tree/xml_parser.hpp>
30
31#include <boost/math/special_functions/round.hpp>
32#include <cmath>
33#include <filesystem>
34#include <fstream>
35#include <iostream>
36#include <sstream>
37#include <utility>
38
39namespace Mantid::Crystal {
40
41using namespace Mantid::API;
42using namespace Mantid::DataObjects;
43using namespace Mantid::Geometry;
44using namespace Mantid::Kernel;
45
47namespace {
48Logger logger("SCDCalibratePanels2");
49}
50
51DECLARE_ALGORITHM(SCDCalibratePanels2)
52
53
57void SCDCalibratePanels2::init() {
58 // Input peakworkspace
59 declareProperty(std::make_unique<WorkspaceProperty<IPeaksWorkspace>>("PeakWorkspace", "", Kernel::Direction::Input),
60 "Workspace of Indexed Peaks");
61
62 // Lattice constant group
63 auto mustBeNonNegative = std::make_shared<BoundedValidator<double>>();
64 mustBeNonNegative->setLower(0.0);
65 declareProperty("RecalculateUB", true, "Recalculate UB matrix using given lattice constants");
66 declareProperty("a", EMPTY_DBL(), mustBeNonNegative,
67 "Lattice Parameter a (Leave empty to use lattice constants "
68 "in peaks workspace)");
69 declareProperty("b", EMPTY_DBL(), mustBeNonNegative,
70 "Lattice Parameter b (Leave empty to use lattice constants "
71 "in peaks workspace)");
72 declareProperty("c", EMPTY_DBL(), mustBeNonNegative,
73 "Lattice Parameter c (Leave empty to use lattice constants "
74 "in peaks workspace)");
75 declareProperty("alpha", EMPTY_DBL(), mustBeNonNegative,
76 "Lattice Parameter alpha in degrees (Leave empty to use "
77 "lattice constants in peaks workspace)");
78 declareProperty("beta", EMPTY_DBL(), mustBeNonNegative,
79 "Lattice Parameter beta in degrees (Leave empty to use "
80 "lattice constants in peaks workspace)");
81 declareProperty("gamma", EMPTY_DBL(), mustBeNonNegative,
82 "Lattice Parameter gamma in degrees (Leave empty to use "
83 "lattice constants in peaks workspace)");
84 const std::string LATTICE("Lattice Constants");
85 setPropertyGroup("RecalculateUB", LATTICE);
86 setPropertyGroup("a", LATTICE);
87 setPropertyGroup("b", LATTICE);
88 setPropertyGroup("c", LATTICE);
89 setPropertyGroup("alpha", LATTICE);
90 setPropertyGroup("beta", LATTICE);
91 setPropertyGroup("gamma", LATTICE);
92 setPropertySettings("a", std::make_unique<EnabledWhenProperty>("RecalculateUB", IS_DEFAULT));
93 setPropertySettings("b", std::make_unique<EnabledWhenProperty>("RecalculateUB", IS_DEFAULT));
94 setPropertySettings("c", std::make_unique<EnabledWhenProperty>("RecalculateUB", IS_DEFAULT));
95 setPropertySettings("alpha", std::make_unique<EnabledWhenProperty>("RecalculateUB", IS_DEFAULT));
96 setPropertySettings("beta", std::make_unique<EnabledWhenProperty>("RecalculateUB", IS_DEFAULT));
97 setPropertySettings("gamma", std::make_unique<EnabledWhenProperty>("RecalculateUB", IS_DEFAULT));
98
99 declareProperty("Tolerance", 0.15, mustBeNonNegative, "Peak indexing tolerance");
100
101 // Calibration options group
102 // NOTE:
103 // The general workflow of calibration is
104 // - calibrate L1 using all peaks
105 // - calibrate each bank
106 // - calibrate/update L1 again since bank movement will affect L1
107 // - calibrate T0
108 // - calibrate samplePos
109 const std::string CALIBRATION("Calibration Options");
110 // --------------
111 // ----- L1 -----
112 // --------------
113 declareProperty("CalibrateL1", true, "Change the L1(source to sample) distance");
114 declareProperty("SearchRadiusL1", 0.1, mustBeNonNegative,
115 "Search radius of delta L1 in meters, which is used to constrain optimization search space"
116 "when calibrating L1");
117 // editability
118 setPropertySettings("SearchRadiusL1", std::make_unique<EnabledWhenProperty>("CalibrateL1", IS_EQUAL_TO, "1"));
119 // grouping
120 setPropertyGroup("CalibrateL1", CALIBRATION);
121 setPropertyGroup("SearchRadiusL1", CALIBRATION);
122 // ----------------
123 // ----- bank -----
124 // ----------------
125 declareProperty("CalibrateBanks", false, "Calibrate position and orientation of each bank.");
126 declareProperty(
127 "SearchRadiusTransBank", 5e-2, mustBeNonNegative,
128 "This is the search radius (in meter) when calibrating component translations, used to constrain optimization"
129 "search space when calibration translation of banks");
130 declareProperty("SearchradiusRotXBank", 1.0, mustBeNonNegative,
131 "This is the search radius (in deg) when calibrating component reorientation, used to constrain "
132 "optimization search space");
133 declareProperty("SearchradiusRotYBank", 1.0, mustBeNonNegative,
134 "This is the search radius (in deg) when calibrating component reorientation, used to constrain "
135 "optimization search space");
136 declareProperty("SearchradiusRotZBank", 1.0, mustBeNonNegative,
137 "This is the search radius (in deg) when calibrating component reorientation, used to constrain "
138 "optimization search space");
139 declareProperty("CalibrateSize", false, "Calibrate detector size for each bank.");
140 declareProperty("SearchRadiusSize", 0.0, mustBeNonNegative,
141 "This is the search radius (unit less) of scale factor around at value 1.0 "
142 "when calibrating component size if it is a rectangualr detector.");
143 declareProperty("FixAspectRatio", true,
144 "If true, the scaling factor for detector along X- and Y-axis "
145 "must be the same. Otherwise, the 2 scaling factors are free.");
146 declareProperty("BankName", "",
147 "If given, only the specified bank/component will be calibrated."
148 "Otherwise, all banks will be calibrated.");
149
150 // editability
151 setPropertySettings("BankName", std::make_unique<EnabledWhenProperty>("CalibrateBanks", IS_EQUAL_TO, "1"));
152 setPropertySettings("SearchRadiusTransBank",
153 std::make_unique<EnabledWhenProperty>("CalibrateBanks", IS_EQUAL_TO, "1"));
154 setPropertySettings("SearchradiusRotXBank",
155 std::make_unique<EnabledWhenProperty>("CalibrateBanks", IS_EQUAL_TO, "1"));
156 setPropertySettings("SearchradiusRotYBank",
157 std::make_unique<EnabledWhenProperty>("CalibrateBanks", IS_EQUAL_TO, "1"));
158 setPropertySettings("SearchradiusRotZBank",
159 std::make_unique<EnabledWhenProperty>("CalibrateBanks", IS_EQUAL_TO, "1"));
160 setPropertySettings("CalibrateSize", std::make_unique<EnabledWhenProperty>("CalibrateBanks", IS_EQUAL_TO, "1"));
161 setPropertySettings("SearchRadiusSize", std::make_unique<EnabledWhenProperty>("CalibrateSize", IS_EQUAL_TO, "1"));
162 setPropertySettings("FixAspectRatio", std::make_unique<EnabledWhenProperty>("CalibrateSize", IS_EQUAL_TO, "1"));
163 // grouping
164 setPropertyGroup("CalibrateBanks", CALIBRATION);
165 setPropertyGroup("BankName", CALIBRATION);
166 setPropertyGroup("SearchRadiusTransBank", CALIBRATION);
167 setPropertyGroup("SearchradiusRotXBank", CALIBRATION);
168 setPropertyGroup("SearchradiusRotYBank", CALIBRATION);
169 setPropertyGroup("SearchradiusRotZBank", CALIBRATION);
170 setPropertyGroup("CalibrateSize", CALIBRATION);
171 setPropertyGroup("SearchRadiusSize", CALIBRATION);
172 setPropertyGroup("FixAspectRatio", CALIBRATION);
173
174 // --------------
175 // ----- T0 -----
176 // --------------
177 declareProperty("CalibrateT0", false, "Calibrate the T0 (initial TOF)");
178 declareProperty("SearchRadiusT0", 10.0, mustBeNonNegative,
179 "Search radius of T0 (in ms), used to constrain optimization search space");
180 // editability
181 setPropertySettings("SearchRadiusT0", std::make_unique<EnabledWhenProperty>("CalibrateT0", IS_EQUAL_TO, "1"));
182 // grouping
183 setPropertyGroup("CalibrateT0", CALIBRATION);
184 setPropertyGroup("SearchRadiusT0", CALIBRATION);
185 // ---------------------
186 // ----- samplePos -----
187 // ---------------------
188 declareProperty("TuneSamplePosition", false, "Fine tunning sample position");
189 declareProperty("SearchRadiusSamplePos", 0.1, mustBeNonNegative,
190 "Search radius of sample position change (in meters), used to constrain optimization search space");
191 // editability
192 setPropertySettings("SearchRadiusSamplePos",
193 std::make_unique<EnabledWhenProperty>("TuneSamplePosition", IS_EQUAL_TO, "1"));
194 // grouping
195 setPropertyGroup("TuneSamplePosition", CALIBRATION);
196 setPropertyGroup("SearchRadiusSamplePos", CALIBRATION);
197
198 // Output options group
199 declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("OutputWorkspace", "", Direction::Output),
200 "The workspace containing the calibration table.");
201 declareProperty("T0", 0.0, "Returns the TOF offset from optimization", Kernel::Direction::Output);
202 const std::vector<std::string> detcalExts{".DetCal", ".Det_Cal"};
203 declareProperty(
204 std::make_unique<FileProperty>("DetCalFilename", "SCDCalibrate2.DetCal", FileProperty::OptionalSave, detcalExts),
205 "Path to an ISAW-style .detcal file to save.");
206 declareProperty(
207 std::make_unique<FileProperty>("XmlFilename", "SCDCalibrate2.xml", FileProperty::OptionalSave, ".xml"),
208 "Path to an Mantid .xml description(for LoadParameterFile) file to "
209 "save.");
210 declareProperty(
211 std::make_unique<FileProperty>("CSVFilename", "SCDCalibrate2.csv", FileProperty::OptionalSave, ".csv"),
212 "Path to an .csv file which contains the Calibration Table");
213 // group into Output group
214 const std::string OUTPUT("Output");
215 setPropertyGroup("OutputWorkspace", OUTPUT);
216 setPropertyGroup("DetCalFilename", OUTPUT);
217 setPropertyGroup("XmlFilename", OUTPUT);
218 setPropertyGroup("CSVFilename", OUTPUT);
219
220 // Add new section for advanced control of the calibration/optimization
221 // NOTE: profiling is expensive, think twice before start
222 declareProperty("VerboseOutput", false, "Toggle of child algorithm console output.");
223 declareProperty("ProfileL1", false, "Perform profiling of objective function with given input for L1");
224 declareProperty("ProfileBanks", false, "Perform profiling of objective function with given input for Banks");
225 declareProperty("ProfileT0", false, "Perform profiling of objective function with given input for T0");
226 declareProperty("ProfileL1T0", false, "Perform profiling of objective function along L1 and T0");
227 // grouping into one category
228 const std::string ADVCNTRL("Advanced Option");
229 setPropertyGroup("VerboseOutput", ADVCNTRL);
230 setPropertyGroup("ProfileL1", ADVCNTRL);
231 setPropertyGroup("ProfileBanks", ADVCNTRL);
232 setPropertyGroup("ProfileT0", ADVCNTRL);
233 setPropertyGroup("ProfileL1T0", ADVCNTRL);
234
235 // About fitting
236 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<int>>();
237 mustBePositive->setLower(0);
238 declareProperty("MaxFitIterations", 500, mustBePositive,
239 "Stop after this number of iterations if a good fit is not found");
240}
241
247std::map<std::string, std::string> SCDCalibratePanels2::validateInputs() {
248 std::map<std::string, std::string> issues;
249
250 // Lattice constants are required if no UB is attached to the input
251 // peak workspace
252 IPeaksWorkspace_sptr pws = getProperty("PeakWorkspace");
253 double a = getProperty("a");
254 double b = getProperty("b");
255 double c = getProperty("c");
256 double alpha = getProperty("alpha");
257 double beta = getProperty("beta");
258 double gamma = getProperty("gamma");
259 if ((a == EMPTY_DBL() || b == EMPTY_DBL() || c == EMPTY_DBL() || alpha == EMPTY_DBL() || beta == EMPTY_DBL() ||
260 gamma == EMPTY_DBL()) &&
261 (!pws->sample().hasOrientedLattice())) {
262 issues["RecalculateUB"] = "Lattice constants are needed for peak "
263 "workspace without a UB mattrix";
264 }
265
266 // sanity check
268 throw std::runtime_error("calibrationTableColumnTypes and calibrationTableColumnTypes have different size.");
269
270 return issues;
271}
272
278 // parse all inputs
279 IPeaksWorkspace_sptr m_pws = getProperty("PeakWorkspace");
280
281 // recalculate UB with given lattice constant
282 // if required
283 if (getProperty("RecalculateUB")) {
284 // parse lattice constants
286
287 // recalculate UB and index peaks
288 updateUBMatrix(m_pws);
289 }
290
291 // remove unindexed peaks
292 m_pws = removeUnindexedPeaks(m_pws);
293
294 bool calibrateT0 = getProperty("CalibrateT0");
295 bool calibrateL1 = getProperty("CalibrateL1");
296 bool calibrateBanks = getProperty("CalibrateBanks");
297 bool tuneSamplePos = getProperty("TuneSamplePosition");
298 mCalibBankName = getPropertyValue("BankName");
299 bool profL1 = getProperty("ProfileL1");
300 bool profBanks = getProperty("ProfileBanks");
301 bool profT0 = getProperty("ProfileT0");
302 bool profL1T0 = getProperty("ProfileL1T0");
303
304 const std::string DetCalFilename = getProperty("DetCalFilename");
305 const std::string XmlFilename = getProperty("XmlFilename");
306 const std::string CSVFilename = getProperty("CSVFilename");
307
308 // Properties for resizing rectangular detector size
309 bool docalibsize = getProperty("CalibrateSize");
310 double sizesearchradius = getProperty("SearchRadiusSize");
311 bool fixdetxyratio = getProperty("FixAspectRatio");
312
313 maxFitIterations = getProperty("MaxFitIterations");
314 LOGCHILDALG = getProperty("VerboseOutput");
315
316 // STEP_0: sort the peaks
317 std::vector<std::pair<std::string, bool>> criteria{{"BankName", true}};
318 m_pws->sort(criteria);
319 // need to keep a copy of the peak workspace at its input state
320 IPeaksWorkspace_sptr pws_original = m_pws->clone();
321
322 // STEP_2: preparation
323 // get names of banks that can be calibrated
324 getBankNames(m_pws);
325
326 // DEV ONLY
327 // !!!WARNNING!!!
328 // Profiling a parameter space can be time-consuming and may freeze up your
329 // computing resources for days, therefore please proceed with caution.
330 if (profL1) {
331 profileL1(m_pws, pws_original);
332 }
333 if (profBanks) {
334 profileBanks(m_pws, pws_original);
335 }
336 if (profT0) {
337 profileT0(m_pws, pws_original);
338 }
339 if (profL1T0) {
340 profileL1T0(m_pws, pws_original);
341 }
342
343 // STEP_3: optimize
344 // - L1 (with or without T0 cali attached)
345 // - Banks
346 // - sample position
347 if (calibrateL1) {
348 // NOTE:
349 // L1 and T0 can be calibrated together to provide stable calibration results.
350 g_log.notice() << "** Calibrating L1 (moderator) as requested\n";
351 optimizeL1(m_pws, pws_original);
352 }
353
354 if (calibrateBanks) {
355 g_log.notice() << "** Calibrating L2 and orientation (bank) as requested\n";
356 optimizeBanks(m_pws, pws_original, docalibsize, sizesearchradius, fixdetxyratio);
357 }
358
359 if (calibrateL1 && calibrateBanks) {
360 g_log.notice() << "** Calibrating L1 (moderator) after bank adjusted\n";
361 optimizeL1(m_pws, pws_original);
362 // NOTE:
363 // Turns out 1 pass is sufficient (tested with the following block)
364 //
365 // double delta = 1;
366 // int cnt = 0;
367 // while (delta > 0.01) {
368 // double L1_pre = m_pws->getInstrument()->getSource()->getPos().Z();
369 // optimizeBanks(m_pws, pws_original);
370 // optimizeL1(m_pws, pws_original);
371 // double L1_post = m_pws->getInstrument()->getSource()->getPos().Z();
372 // delta = std::abs((L1_pre - L1_post) / L1_pre);
373 // cnt += 1;
374 // g_log.notice() << "@pass_" << cnt << "\n" << L1_pre << "-->" << L1_post << "\n";
375 // }
376 }
377
378 if (calibrateT0 && !calibrateL1) {
379 // NOTE:
380 // L1 and T0 can be calibrated together to provide a stable results, which is the
381 // recommended way.
382 // However, one can still calibrate T0 only if desired.
383 g_log.notice() << "** Calibrating T0 only as requested\n";
384 optimizeT0(m_pws, pws_original);
385 }
386
387 if (tuneSamplePos && !calibrateL1) {
388 g_log.notice() << "** Tunning sample position only as requested\n";
389 optimizeSamplePos(m_pws, pws_original);
390 }
391
392 if (calibrateT0 && tuneSamplePos && !calibrateL1) {
393 g_log.warning() << "** You have chosen to calibrate T0 and sample position while ignoring"
394 << " L1, which means an iterative search outside this calibration is needed"
395 << " in order to find the minimum.\n";
396 }
397
398 // STEP_4: generate a table workspace to save the calibration results
399 g_log.notice() << "-- Generate calibration table\n";
400 Instrument_sptr instCalibrated = std::const_pointer_cast<Geometry::Instrument>(m_pws->getInstrument());
401 const Geometry::ParameterMap &pmap = m_pws->instrumentParameters();
402 ITableWorkspace_sptr tablews = generateCalibrationTable(instCalibrated, pmap);
403
404 // STEP_5: Write to disk if required
405 if (!XmlFilename.empty()) {
406 saveXmlFile(XmlFilename, m_BankNames, instCalibrated, pmap);
407 }
408
409 if (!DetCalFilename.empty()) {
410 saveIsawDetCal(DetCalFilename, m_BankNames, instCalibrated, m_T0);
411 }
412
413 if (!CSVFilename.empty()) {
414 saveCalibrationTable(CSVFilename, tablews);
415 }
416
417 // STEP_4: Set the output
418 setProperty("T0", m_T0); // output the calibrated T0 as a single value
419}
420
424
432 // cache starting L1 position
433 double original_L1 = std::abs(pws->getInstrument()->getSource()->getPos().Z());
434 // T0 can be calibrate along with L1 to provide a more stable results
435 bool caliT0 = getProperty("CalibrateT0");
436 bool tuneSamplepos = getProperty("TuneSamplePosition");
437
439
440 // fit algorithm for the optimization of L1
441 auto fitL1_alg = createChildAlgorithm("Fit", -1, -1, false);
442 auto objf = std::make_shared<SCDCalibratePanels2ObjFunc>();
443 // NOTE: always use the original pws to get the tofs
444 std::vector<double> tofs = captureTOF(pws_original);
445 objf->setPeakWorkspace(pws, "moderator", tofs);
446 fitL1_alg->setProperty("Function", std::dynamic_pointer_cast<IFunction>(objf));
447
448 //-- bounds&constraints def
449 std::ostringstream tie_str;
450 tie_str << "DeltaX=0.0,DeltaY=0.0,"
451 << "RotX=0.0,RotY=0.0,RotZ=0.0";
452 if (!tuneSamplepos) {
453 tie_str << ",DeltaSampleX=0.0,DeltaSampleY=0.0,DeltaSampleZ=0.0";
454 }
455 if (!caliT0) {
456 tie_str << ",DeltaT0=" << m_T0;
457 }
458 std::ostringstream constraint_str;
459 double r_L1 = getProperty("SearchRadiusL1"); // get search radius
460 r_L1 = std::abs(r_L1);
461 constraint_str << -r_L1 << "<DeltaZ<" << r_L1;
462 // throw in the constrain for T0 cali if needed
463 if (caliT0) {
464 double r_dT0 = getProperty("SearchRadiusT0");
465 r_dT0 = std::abs(r_dT0);
466 constraint_str << "," << -r_dT0 << "<DeltaT0<" << r_dT0;
467 }
468 if (tuneSamplepos) {
469 double r_dsp = getProperty("SearchRadiusSamplePos");
470 r_dsp = std::abs(r_dsp);
471 constraint_str << "," << -r_dsp << "<DeltaSampleX<" << r_dsp // dsx
472 << "," << -r_dsp << "<DeltaSampleY<" << r_dsp // dsy
473 << "," << -r_dsp << "<DeltaSampleZ<" << r_dsp; // dsz
474 }
475 //-- set and go
476 fitL1_alg->setProperty("Ties", tie_str.str());
477 fitL1_alg->setProperty("Constraints", constraint_str.str());
478 fitL1_alg->setProperty("InputWorkspace", l1ws);
479 fitL1_alg->setProperty("CreateOutput", true);
480 fitL1_alg->setProperty("Output", "fit");
481 fitL1_alg->executeAsChildAlg();
482
483 //-- parse output
484 std::ostringstream calilog;
485 double chi2OverDOF = fitL1_alg->getProperty("OutputChi2overDoF");
486 ITableWorkspace_sptr rst = fitL1_alg->getProperty("OutputParameters");
487 // get results for L1
488 double dL1_optimized = rst->getRef<double>("Value", 2);
489
490 // get results for T0 (optional)
491 double dT0_optimized = rst->getRef<double>("Value", 6);
492
493 // get results for sample pos
494 // NOTE:
495 // if samplePos is not part of calibration, we will get zeros here, which means zero
496 // negative impact on the whole pws
497 double dsx_optimized = rst->getRef<double>("Value", 7);
498 double dsy_optimized = rst->getRef<double>("Value", 8);
499 double dsz_optimized = rst->getRef<double>("Value", 9);
500
501 // apply the cali results (for output cali table and file)
502 adjustComponent(0.0, 0.0, dL1_optimized, 0.0, 0.0, 0.0, EMPTY_DBL(), EMPTY_DBL(),
503 pws->getInstrument()->getSource()->getName(), pws);
504 m_T0 = dT0_optimized;
505 adjustComponent(dsx_optimized, dsy_optimized, dsz_optimized, 0.0, 0.0, 0.0, EMPTY_DBL(), EMPTY_DBL(),
506 "sample-position", pws);
507 // logging
508 int npks = pws->getNumberPeaks();
509 calilog << "-- Fit L1 results using " << npks << " peaks:\n"
510 << " dL1: " << dL1_optimized << " \n"
511 << " L1 " << original_L1 << " -> " << -pws->getInstrument()->getSource()->getPos().Z() << " \n"
512 << " dT0 = " << m_T0 << " (ms)\n"
513 << " dSamplePos = (" << dsx_optimized << "," << dsy_optimized << "," << dsz_optimized << ")\n"
514 << " chi2/DOF = " << chi2OverDOF << "\n";
515 g_log.notice() << calilog.str();
516}
517
528 const bool &docalibsize, const double &sizesearchradius,
529 const bool &fixdetxyratio) {
530
532 for (int i = 0; i < static_cast<int>(m_BankNames.size()); ++i) {
534 // prepare local copies to work with
535 const std::string bankname = *std::next(m_BankNames.begin(), i);
536 const std::string pwsBankiName = "_pws_" + bankname;
537
538 // Find out whether to skip the calibration by user's specification
539 // This check is only requied when mCalibBankName is not empty string
540 if (mCalibBankName != "") {
541 bool isbank = (bankname == mCalibBankName);
542 std::stringstream ss;
543 ss << "i = " << i << " m bank name = " << bankname;
544 if (isbank)
545 ss << " ... True ...";
546 else
547 ss << " ... Stop ...";
548 g_log.notice(ss.str());
549 // continue/skip if bank name is not what is specified
550 if (!isbank)
551 continue;
552 }
553
554 //-- step 0: extract peaks that lies on the current bank
555 IPeaksWorkspace_sptr pwsBanki = selectPeaksByBankName(pws, bankname, pwsBankiName);
556 // get tofs from the original subset of pws
557 IPeaksWorkspace_sptr pwsBanki_original = selectPeaksByBankName(pws_original, bankname, pwsBankiName);
558 std::vector<double> tofs = captureTOF(pwsBanki_original);
559
560 // Do not attempt correct panels with less than 6 peaks as the system will
561 // be under-determined
562 int nBankPeaks = pwsBanki->getNumberPeaks();
563 if (nBankPeaks < MINIMUM_PEAKS_PER_BANK) {
564 // use ostringstream to prevent OPENMP breaks log info
565 std::ostringstream msg_npeakCheckFail;
566 msg_npeakCheckFail << "-- Bank " << bankname << " have only " << nBankPeaks << " (<" << MINIMUM_PEAKS_PER_BANK
567 << ") Peaks, skipping\n";
568 g_log.notice() << msg_npeakCheckFail.str();
569 continue;
570 }
571
572 //-- step 1: prepare a mocked workspace with QSample as its yValues
574
575 //-- step 2&3: invoke fit to find both traslation and rotation
576 auto fitBank_alg = createChildAlgorithm("Fit", -1, -1, false);
577 //---- setup obj fun def
578 auto objf = std::make_shared<SCDCalibratePanels2ObjFunc>();
579 objf->setPeakWorkspace(pwsBanki, bankname, tofs);
580 fitBank_alg->setProperty("Function", std::dynamic_pointer_cast<IFunction>(objf));
581
582 //---- bounds&constraints def
583 //
584 double searchRadiusRotX = getProperty("SearchradiusRotXBank");
585 searchRadiusRotX = std::abs(searchRadiusRotX);
586 double searchRadiusRotY = getProperty("SearchradiusRotYBank");
587 searchRadiusRotY = std::abs(searchRadiusRotY);
588 double searchRadiusRotZ = getProperty("SearchradiusRotZBank");
589 searchRadiusRotZ = std::abs(searchRadiusRotZ);
590 //
591 double searchRadiusTran = getProperty("SearchRadiusTransBank");
592 searchRadiusTran = std::abs(searchRadiusTran);
593 //
594 std::ostringstream tie_str;
595 tie_str << "DeltaSampleX=0.0,DeltaSampleY=0.0,DeltaSampleZ=0.0,"
596 << "DeltaT0=" << m_T0;
597 std::ostringstream constraint_str;
598 // rot x
599 if (searchRadiusRotX < Tolerance) {
600 tie_str << ",RotX=0.0";
601 } else {
602 constraint_str << -searchRadiusRotX << "<RotX<" << searchRadiusRotX << ",";
603 }
604 // rot y
605 if (searchRadiusRotY < Tolerance) {
606 tie_str << ",RotY=0.0";
607 } else {
608 constraint_str << -searchRadiusRotY << "<RotY<" << searchRadiusRotY << ",";
609 }
610 // rot z
611 if (searchRadiusRotZ < Tolerance) {
612 tie_str << ",RotZ=0.0";
613 } else {
614 constraint_str << -searchRadiusRotZ << "<RotZ<" << searchRadiusRotZ << ","; // constrain rotation around Z-axis
615 }
616 // translation
617 if (searchRadiusTran < Tolerance) {
618 tie_str << ",DeltaX=0.0,DeltaY=0.0,DeltaZ=0.0";
619 } else {
620 constraint_str << -searchRadiusTran << "<DeltaX<" << searchRadiusTran << "," // restrict tranlastion along X
621 << -searchRadiusTran << "<DeltaY<" << searchRadiusTran << "," // restrict tranlastion along Y
622 << -searchRadiusTran << "<DeltaZ<" << searchRadiusTran; // restrict tranlastion along Z
623 }
624 // calibration of detector size
625 // docalibsize, sizesearchradius, fixdetxyratio
626 Geometry::Instrument_sptr inst = std::const_pointer_cast<Geometry::Instrument>(pws->getInstrument());
627 Geometry::IComponent_const_sptr comp = inst->getComponentByName(bankname);
628 std::shared_ptr<const Geometry::RectangularDetector> rectDet =
629 std::dynamic_pointer_cast<const Geometry::RectangularDetector>(comp);
630
631 std::pair<double, double> scales = getRectangularDetectorScaleFactors(inst, bankname, pws->instrumentParameters());
632
633 std::ostringstream scaleconstraints;
634 std::ostringstream scaleties;
635 if (rectDet && docalibsize) {
636 // set up constraints
637 scaleconstraints << scales.first - sizesearchradius << " <=ScaleX<" << scales.first + sizesearchradius;
638 if (fixdetxyratio) {
639 scaleties << "ScaleX=ScaleY";
640 } else {
641 scaleconstraints << "," << scales.second - sizesearchradius << " <=ScaleY<" << scales.second + sizesearchradius;
642 }
643 } else {
644 // fix the scalex and scaley to its
645 scaleties << "ScaleX=" << scales.first << ", ScaleY=" << scales.second;
646 }
647
648 // construct the final constraint and tie
649 std::string fitconstraint{constraint_str.str()};
650 if (scaleconstraints.str() != "") {
651 if (fitconstraint == "")
652 fitconstraint += scaleconstraints.str();
653 else
654 fitconstraint += "," + scaleconstraints.str();
655 }
656 std::string fittie{tie_str.str()};
657 if (scaleties.str() != "") {
658 if (fittie == "")
659 fittie += scaleties.str();
660 else
661 fittie += "," + scaleties.str();
662 }
663
664 g_log.information("Fitting " + bankname + ": constraint = " + fitconstraint + "\n\t tie = " + fittie);
665
666 //---- set&go
667 if (fittie != "")
668 fitBank_alg->setProperty("Ties", fittie);
669 if (fitconstraint != "")
670 fitBank_alg->setProperty("Constraints", fitconstraint);
671 fitBank_alg->setProperty("InputWorkspace", wsBankCali);
672 fitBank_alg->setProperty("CreateOutput", true);
673 fitBank_alg->setProperty("Output", "fit");
674 fitBank_alg->setProperty("MaxIterations", maxFitIterations);
675
676 fitBank_alg->executeAsChildAlg();
677
678 //---- cache results
679 double chi2OverDOF = fitBank_alg->getProperty("OutputChi2overDoF");
680 ITableWorkspace_sptr rstFitBank = fitBank_alg->getProperty("OutputParameters");
681 double dx = rstFitBank->getRef<double>("Value", 0);
682 double dy = rstFitBank->getRef<double>("Value", 1);
683 double dz = rstFitBank->getRef<double>("Value", 2);
684 double drx = rstFitBank->getRef<double>("Value", 3);
685 double dry = rstFitBank->getRef<double>("Value", 4);
686 double drz = rstFitBank->getRef<double>("Value", 5);
687 double scalex = rstFitBank->getRef<double>("Value", 10);
688 double scaley = rstFitBank->getRef<double>("Value", 11);
689
690 //-- step 4: update the instrument with optimization results
691 std::string bn = bankname;
692 std::ostringstream calilog;
693 if (pws->getInstrument()->getName().compare("CORELLI") == 0) {
694 bn.append("/sixteenpack");
695 }
696 // update instrument for output
697 if (rectDet && docalibsize) {
698 // adjust detector size only if it is to be set to refine
699 adjustComponent(dx, dy, dz, drx, dry, drz, scalex, scaley, bn, pws);
700 } else {
701 // (1) no rectangular det or (2) not to refine detector size:
702 // do not set any physically possible scalex or scaley
703 adjustComponent(dx, dy, dz, drx, dry, drz, EMPTY_DBL(), EMPTY_DBL(), bn, pws);
704 }
705 // logging
706 V3D dtrans(dx, dy, dz);
707 V3D drots(drx, dry, drz);
708 calilog << "-- Fit " << bn << " results using " << nBankPeaks << " peaks:\n"
709 << " d(x,y,z) = " << dtrans << "\n"
710 << " r(x,y,z) = " << drots << "\n"
711 << " scale(x, y) = " << scalex << ", " << scaley << " chi2/DOF = " << chi2OverDOF << "\n";
712 g_log.notice() << calilog.str();
713
714 // -- cleanup
716 }
718}
719
731 // create child Fit alg to optimize T0
732 auto fitT0_alg = createChildAlgorithm("Fit", -1, -1, false);
733 //-- obj func def
734 // dl;dr;
735 // Fit algorithm requires a IFunction1D to fit
736 // details
737 // Fit algorithm requires a class derived from IFunction1D as its
738 // input, so we have to implement the objective function as a separate
739 // class just to get Fit serving as an optimizer.
740 // For this particular case, we are constructing an objective function
741 // based on IFunction1D that outputs a fake histogram consist of
742 // qSample calculated based on perturbed instrument positions and
743 // orientations.
745
746 auto objf = std::make_shared<SCDCalibratePanels2ObjFunc>();
747 // NOTE: always use the original pws to get the tofs
748 std::vector<double> tofs = captureTOF(pws_original);
749 objf->setPeakWorkspace(pws, "none", tofs);
750 fitT0_alg->setProperty("Function", std::dynamic_pointer_cast<IFunction>(objf));
751
752 //-- bounds&constraints def
753 std::ostringstream tie_str;
754 tie_str << "DeltaX=0.0,DeltaY=0.0,DeltaZ=0.0,"
755 << "RotX=0.0,RotY=0.0,RotZ=0.0,"
756 << "DeltaSampleX=0.0,DeltaSampleY=0.0,DeltaSampleZ=0.0";
757 std::ostringstream constraint_str;
758 double r_dT0 = getProperty("SearchRadiusT0");
759 r_dT0 = std::abs(r_dT0);
760 constraint_str << -r_dT0 << "<DeltaT0<" << r_dT0;
761
762 //-- set&go
763 fitT0_alg->setProperty("Ties", tie_str.str());
764 fitT0_alg->setProperty("Constraints", constraint_str.str());
765 fitT0_alg->setProperty("InputWorkspace", t0ws);
766 fitT0_alg->setProperty("CreateOutput", true);
767 fitT0_alg->setProperty("Output", "fit");
768 fitT0_alg->executeAsChildAlg();
769
770 //-- parse output
771 std::ostringstream calilog;
772 double chi2OverDOF = fitT0_alg->getProperty("OutputChi2overDoF");
773 ITableWorkspace_sptr rst = fitT0_alg->getProperty("OutputParameters");
774 double dT0_optimized = rst->getRef<double>("Value", 6);
775
776 // apply calibration results (for output file and caliTable)
777 m_T0 = dT0_optimized;
778 int npks = pws->getNumberPeaks();
779 // logging
780 calilog << "-- Fit T0 results using " << npks << " peaks:\n"
781 << " dT0 = " << m_T0 << " (ms)\n"
782 << " chi2/DOF = " << chi2OverDOF << "\n";
783 g_log.notice() << calilog.str();
784}
785
793 // create child Fit alg to optimize T0
794 auto fitSamplePos_alg = createChildAlgorithm("Fit", -1, -1, false);
795
796 // creat input 1DHist from qSample
798
799 auto objf = std::make_shared<SCDCalibratePanels2ObjFunc>();
800 // NOTE: always use the original pws to get the tofs
801 std::vector<double> tofs = captureTOF(pws_original);
802 objf->setPeakWorkspace(pws, "none", tofs);
803 fitSamplePos_alg->setProperty("Function", std::dynamic_pointer_cast<IFunction>(objf));
804
805 //-- bounds&constraints def
806 std::ostringstream tie_str;
807 tie_str << "DeltaX=0.0,DeltaY=0.0,DeltaZ=0.0,"
808 << "RotX=0.0,RotY=0.0,RotZ=0.0,"
809 << "DeltaT0=" << m_T0;
810 std::ostringstream constraint_str;
811 double r_dsp = getProperty("SearchRadiusSamplePos");
812 r_dsp = std::abs(r_dsp);
813 constraint_str << -r_dsp << "<DeltaSampleX<" << r_dsp << "," << -r_dsp << "<DeltaSampleY<" << r_dsp << "," << -r_dsp
814 << "<DeltaSampleZ<" << r_dsp;
815
816 //-- set&go
817 fitSamplePos_alg->setProperty("Ties", tie_str.str());
818 fitSamplePos_alg->setProperty("Constraints", constraint_str.str());
819 fitSamplePos_alg->setProperty("InputWorkspace", samplePosws);
820 fitSamplePos_alg->setProperty("CreateOutput", true);
821 fitSamplePos_alg->setProperty("Output", "fit");
822 fitSamplePos_alg->executeAsChildAlg();
823
824 //-- parse output
825 std::ostringstream calilog;
826 double chi2OverDOF = fitSamplePos_alg->getProperty("OutputChi2overDoF");
827 ITableWorkspace_sptr rst = fitSamplePos_alg->getProperty("OutputParameters");
828 double dsx_optimized = rst->getRef<double>("Value", 7);
829 double dsy_optimized = rst->getRef<double>("Value", 8);
830 double dsz_optimized = rst->getRef<double>("Value", 9);
831
832 // apply the calibration results to pws for ouptut file
833 adjustComponent(dsx_optimized, dsy_optimized, dsz_optimized, 0.0, 0.0, 0.0, EMPTY_DBL(), EMPTY_DBL(),
834 "sample-position", pws);
835 int npks = pws->getNumberPeaks();
836 // logging
837 calilog << "-- Tune SamplePos results using " << npks << " peaks:\n"
838 << " deltaSamplePos = (" << dsx_optimized << "," << dsy_optimized << "," << dsz_optimized << ")\n"
839 << " chi2/DOF = " << chi2OverDOF << "\n";
840 g_log.notice() << calilog.str();
841}
842
846
853 m_a = getProperty("a");
854 m_b = getProperty("b");
855 m_c = getProperty("c");
856 m_alpha = getProperty("alpha");
857 m_beta = getProperty("beta");
858 m_gamma = getProperty("gamma");
859 // if any one of the six lattice constants is missing, try to get
860 // one from the workspace
861 if ((m_a == EMPTY_DBL() || m_b == EMPTY_DBL() || m_c == EMPTY_DBL() || m_alpha == EMPTY_DBL() ||
862 m_beta == EMPTY_DBL() || m_gamma == EMPTY_DBL()) &&
863 (pws->sample().hasOrientedLattice())) {
864 OrientedLattice lattice = pws->mutableSample().getOrientedLattice();
865 m_a = lattice.a();
866 m_b = lattice.b();
867 m_c = lattice.c();
868 m_alpha = lattice.alpha();
869 m_beta = lattice.beta();
870 m_gamma = lattice.gamma();
871 }
872}
873
881 auto calcUB_alg = createChildAlgorithm("CalculateUMatrix", -1, -1, false);
882 calcUB_alg->setLogging(LOGCHILDALG);
883 calcUB_alg->setProperty("PeaksWorkspace", pws);
884 calcUB_alg->setProperty("a", m_a);
885 calcUB_alg->setProperty("b", m_b);
886 calcUB_alg->setProperty("c", m_c);
887 calcUB_alg->setProperty("alpha", m_alpha);
888 calcUB_alg->setProperty("beta", m_beta);
889 calcUB_alg->setProperty("gamma", m_gamma);
890 calcUB_alg->executeAsChildAlg();
891
892 double tol = getProperty("Tolerance");
893
894 // Since UB is updated, we need to redo the indexation
895 auto idxpks_alg = createChildAlgorithm("IndexPeaks", -1, -1, false);
896 idxpks_alg->setLogging(LOGCHILDALG);
897 idxpks_alg->setProperty("PeaksWorkspace", pws);
898 idxpks_alg->setProperty("RoundHKLs", true); // using default
899 idxpks_alg->setProperty("Tolerance", tol); // values
900 idxpks_alg->executeAsChildAlg();
901}
902
910 auto fltpk_alg = createChildAlgorithm("FilterPeaks");
911 fltpk_alg->setLogging(LOGCHILDALG);
912 fltpk_alg->setProperty("InputWorkspace", pws);
913 fltpk_alg->setProperty("FilterVariable", "h^2+k^2+l^2");
914 fltpk_alg->setProperty("Operator", ">");
915 fltpk_alg->setProperty("FilterValue", 0.0);
916 fltpk_alg->setProperty("OutputWorkspace", "pws_filtered");
917 fltpk_alg->executeAsChildAlg();
918
919 IPeaksWorkspace_sptr outWS = fltpk_alg->getProperty("OutputWorkspace");
920 return outWS;
921}
922
930 std::vector<double> tofs;
931
932 for (int i = 0; i < pws->getNumberPeaks(); ++i) {
933 tofs.emplace_back(pws->getPeak(i).getTOF());
934 }
935
936 return tofs;
937}
938
945 auto peaksWorkspace = std::dynamic_pointer_cast<DataObjects::PeaksWorkspace>(pws);
946 if (!peaksWorkspace)
947 throw std::invalid_argument("a PeaksWorkspace is required to retrieve bank names");
948 int npeaks = static_cast<int>(pws->getNumberPeaks());
949 for (int i = 0; i < npeaks; ++i) {
950 std::string bname = peaksWorkspace->getPeak(i).getBankName();
951 if (bname != "None")
952 m_BankNames.insert(bname);
953 }
954}
955
965 const std::string &bankname,
966 const std::string &outputwsn) {
967 auto fltpk_alg = createChildAlgorithm("FilterPeaks");
968 fltpk_alg->setLogging(LOGCHILDALG);
969 fltpk_alg->setProperty("InputWorkspace", pws);
970 fltpk_alg->setProperty("BankName", bankname);
971 fltpk_alg->setProperty("Criterion", "=");
972 fltpk_alg->setProperty("OutputWorkspace", outputwsn);
973 fltpk_alg->executeAsChildAlg();
974
975 IPeaksWorkspace_sptr outWS = fltpk_alg->getProperty("OutputWorkspace");
976 return outWS;
977}
978
987 int npeaks = pws->getNumberPeaks();
988
989 // prepare workspace to store qSample as Histogram1D
990 MatrixWorkspace_sptr mws = std::dynamic_pointer_cast<MatrixWorkspace>(
991 WorkspaceFactory::Instance().create("Workspace2D", // use workspace 2D to mock a histogram
992 1, // one vector
993 3 * npeaks, // X :: anything is fine
994 3 * npeaks)); // Y :: flattened Q vector
995 auto &spectrum = mws->getSpectrum(0);
996 auto &xvector = spectrum.mutableX();
997 auto &yvector = spectrum.mutableY();
998 auto &evector = spectrum.mutableE();
999
1000 // quick check to see what kind of weighting we can use
1001 double totalSigmaInt = 0.0;
1002 for (int i = 0; i < npeaks; ++i) {
1003 totalSigmaInt += pws->getPeak(i).getSigmaIntensity();
1004 }
1005 double totalInt = 0.0;
1006 for (int i = 0; i < npeaks; ++i) {
1007 totalInt += pws->getPeak(i).getIntensity();
1008 }
1009 double totalCnt = 0.0;
1010 for (int i = 0; i < npeaks; ++i) {
1011 totalCnt += pws->getPeak(i).getBinCount();
1012 }
1013
1014 // directly compute qsample from UBmatrix and HKL
1015 auto ubmatrix = pws->sample().getOrientedLattice().getUB();
1016 for (int i = 0; i < npeaks; ++i) {
1017
1018 V3D qv = ubmatrix * pws->getPeak(i).getIntHKL();
1019 qv *= 2 * PI;
1020 // qv = qv / qv.norm();
1021 double wgt = 1.0;
1022 if (totalSigmaInt > 0.0) {
1023 wgt = 1.0 / pws->getPeak(i).getSigmaIntensity();
1024 } else if (totalInt > 0.0) {
1025 wgt = 1.0 / pws->getPeak(i).getIntensity();
1026 } else if (totalCnt > 0.0) {
1027 wgt = 1.0 / pws->getPeak(i).getBinCount();
1028 }
1029 // make 1dhist
1030 for (int j = 0; j < 3; ++j) {
1031 xvector[i * 3 + j] = i * 3 + j;
1032 yvector[i * 3 + j] = qv[j];
1033 evector[i * 3 + j] = wgt;
1034 }
1035 }
1036
1037 return mws;
1038}
1039
1054void SCDCalibratePanels2::adjustComponent(double dx, double dy, double dz, double drx, double dry, double drz,
1055 double scalex, double scaley, const std::string &cmptName,
1056 IPeaksWorkspace_sptr &pws) {
1057 // translation
1058 auto mv_alg = createChildAlgorithm("MoveInstrumentComponent", -1, -1, false);
1059 mv_alg->setLogging(LOGCHILDALG);
1060 mv_alg->setProperty<Workspace_sptr>("Workspace", pws);
1061 mv_alg->setProperty("ComponentName", cmptName);
1062 mv_alg->setProperty("X", dx);
1063 mv_alg->setProperty("Y", dy);
1064 mv_alg->setProperty("Z", dz);
1065 mv_alg->setProperty("RelativePosition", true);
1066 mv_alg->executeAsChildAlg();
1067
1068 // rotation
1069 auto rot_alg = createChildAlgorithm("RotateInstrumentComponent", -1, -1, false);
1070 rot_alg->setLogging(LOGCHILDALG);
1071 // - x-axis
1072 rot_alg->setProperty<Workspace_sptr>("Workspace", pws);
1073 rot_alg->setProperty("ComponentName", cmptName);
1074 rot_alg->setProperty("X", 1.0);
1075 rot_alg->setProperty("Y", 0.0);
1076 rot_alg->setProperty("Z", 0.0);
1077 rot_alg->setProperty("Angle", drx);
1078 rot_alg->setProperty("RelativeRotation", true);
1079 rot_alg->executeAsChildAlg();
1080 // - y-axis
1081 rot_alg->setProperty<Workspace_sptr>("Workspace", pws);
1082 rot_alg->setProperty("ComponentName", cmptName);
1083 rot_alg->setProperty("X", 0.0);
1084 rot_alg->setProperty("Y", 1.0);
1085 rot_alg->setProperty("Z", 0.0);
1086 rot_alg->setProperty("Angle", dry);
1087 rot_alg->setProperty("RelativeRotation", true);
1088 rot_alg->executeAsChildAlg();
1089 // - z-axis
1090 rot_alg->setProperty<Workspace_sptr>("Workspace", pws);
1091 rot_alg->setProperty("ComponentName", cmptName);
1092 rot_alg->setProperty("X", 0.0);
1093 rot_alg->setProperty("Y", 0.0);
1094 rot_alg->setProperty("Z", 1.0);
1095 rot_alg->setProperty("Angle", drz);
1096 rot_alg->setProperty("RelativeRotation", true);
1097 rot_alg->executeAsChildAlg();
1098
1099 // scale detector size
1101 auto resizeAlg = createChildAlgorithm("ResizeRectangularDetector", -1, -1, false);
1102 resizeAlg->initialize();
1103 resizeAlg->setProperty("Workspace", pws);
1104 resizeAlg->setProperty("ComponentName", cmptName);
1105 resizeAlg->setProperty("ScaleX", scalex);
1106 resizeAlg->setProperty("ScaleY", scaley);
1107 resizeAlg->execute();
1108
1109 g_log.notice() << "Resize " << cmptName << " by (absolute) " << scalex << ", " << scaley << "\n";
1110 }
1111}
1112
1120ITableWorkspace_sptr SCDCalibratePanels2::generateCalibrationTable(std::shared_ptr<Geometry::Instrument> &instrument,
1122 g_log.notice() << "Generate a TableWorkspace to store calibration results.\n";
1123
1124 // Create table workspace
1125 ITableWorkspace_sptr itablews = WorkspaceFactory::Instance().createTable();
1126 for (size_t i = 0; i < calibrationTableColumnNames.size(); ++i)
1127 itablews->addColumn(calibrationTableColumnTypes[i], calibrationTableColumnNames[i]);
1128
1129 // The first row is always the source
1130 IComponent_const_sptr source = instrument->getSource();
1131 V3D sourceRelPos = source->getRelativePos();
1132 Mantid::API::TableRow sourceRow = itablews->appendRow();
1133 // NOTE: source should not have any rotation, so we pass a zero
1134 // rotation with a fixed axis
1135 sourceRow << instrument->getSource()->getName() << sourceRelPos.X() << sourceRelPos.Y() << sourceRelPos.Z() << 1.0
1136 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0;
1137
1138 // Loop through banks and set row values
1139 for (auto bankName : m_BankNames) {
1140 // CORELLLI instrument has one extra layer that pack tubes into
1141 // banks, which is what we need here
1142 if (instrument->getName().compare("CORELLI") == 0)
1143 bankName.append("/sixteenpack");
1144
1145 std::shared_ptr<const IComponent> bank = instrument->getComponentByName(bankName);
1146
1147 Quat relRot = bank->getRelativeRot();
1148 V3D pos1 = bank->getRelativePos();
1149
1150 // Calculate cosines using relRot
1151 double deg, xAxis, yAxis, zAxis;
1152 relRot.getAngleAxis(deg, xAxis, yAxis, zAxis);
1153
1154 // Detector scaling
1155 std::pair<double, double> scales = getRectangularDetectorScaleFactors(instrument, bankName, pmap);
1156
1157 // Append a new row
1158 Mantid::API::TableRow bankRow = itablews->appendRow();
1159 // Row and positions
1160 bankRow << bankName << pos1.X() << pos1.Y() << pos1.Z() << xAxis << yAxis << zAxis << deg << scales.first
1161 << scales.second;
1162 }
1163
1164 g_log.notice() << "finished generating tables\n";
1165 setProperty("OutputWorkspace", itablews);
1166
1167 return itablews;
1168}
1169
1186void SCDCalibratePanels2::saveXmlFile(const std::string &FileName,
1187 const boost::container::flat_set<std::string> &AllBankNames,
1188 std::shared_ptr<Instrument> &instrument, const Geometry::ParameterMap &pmap) {
1189 g_log.notice() << "Generating xml tree \n";
1190
1191 using boost::property_tree::ptree;
1192 ptree root;
1193 ptree parafile;
1194
1195 // configure root node
1196 parafile.put("<xmlattr>.instrument", instrument->getName());
1197 parafile.put("<xmlattr>.valid-from", instrument->getValidFromDate().toISO8601String());
1198
1199 // get L1 info for source
1200 ptree src;
1201 ptree src_dx, src_dy, src_dz;
1202 ptree src_dx_val, src_dy_val, src_dz_val;
1203 // -- get positional data from source
1204 IComponent_const_sptr source = instrument->getSource();
1205 V3D sourceRelPos = source->getRelativePos();
1206 // -- add data to node
1207 src_dx_val.put("<xmlattr>.val", sourceRelPos.X());
1208 src_dy_val.put("<xmlattr>.val", sourceRelPos.Y());
1209 src_dz_val.put("<xmlattr>.val", sourceRelPos.Z());
1210 src_dx.put("<xmlattr>.name", "x");
1211 src_dy.put("<xmlattr>.name", "y");
1212 src_dz.put("<xmlattr>.name", "z");
1213 src.put("<xmlattr>.name", source->getName());
1214
1215 src_dx.add_child("value", src_dx_val);
1216 src_dy.add_child("value", src_dy_val);
1217 src_dz.add_child("value", src_dz_val);
1218 src.add_child("parameter", src_dx);
1219 src.add_child("parameter", src_dy);
1220 src.add_child("parameter", src_dz);
1221
1222 parafile.add_child("component-link", src);
1223
1224 // add node for T0
1225 // -- property_root is a dumping group for property type values that are not tied to particular
1226 // component (i.e. virtual properties)
1227 ptree property_root;
1228 property_root.put("<xmlattr>.name", instrument->getName());
1229 ptree tof0;
1230 ptree tof0_val;
1231 tof0.put("<xmlattr>.name", "T0");
1232 tof0_val.put("<xmlattr>.val", m_T0);
1233 tof0.add_child("value", tof0_val);
1234 property_root.add_child("parameter", tof0);
1235 parafile.add_child("component-link", property_root);
1236
1237 // save sample position as a standalone component-link
1238 ptree samplePos;
1239 ptree samplePos_dx, samplePos_dy, samplePos_dz;
1240 ptree samplePos_dx_val, samplePos_dy_val, samplePos_dz_val;
1241 // -- get positional data from sample
1242 std::shared_ptr<const IComponent> sp = instrument->getComponentByName("sample-position");
1243 V3D sppos = sp->getRelativePos();
1244 samplePos_dx_val.put("<xmlattr>.val", sppos.X());
1245 samplePos_dy_val.put("<xmlattr>.val", sppos.Y());
1246 samplePos_dz_val.put("<xmlattr>.val", sppos.Z());
1247 samplePos_dx.put("<xmlattr>.name", "x");
1248 samplePos_dy.put("<xmlattr>.name", "y");
1249 samplePos_dz.put("<xmlattr>.name", "z");
1250 samplePos.put("<xmlattr>.name", "sample-position");
1251
1252 samplePos_dx.add_child("value", samplePos_dx_val);
1253 samplePos_dy.add_child("value", samplePos_dy_val);
1254 samplePos_dz.add_child("value", samplePos_dz_val);
1255 samplePos.add_child("parameter", samplePos_dx);
1256 samplePos.add_child("parameter", samplePos_dy);
1257 samplePos.add_child("parameter", samplePos_dz);
1258
1259 parafile.add_child("component-link", samplePos);
1260
1261 // configure and add each bank
1262 for (auto bankName : AllBankNames) {
1263 // Prepare data for node
1264 if (instrument->getName().compare("CORELLI") == 0)
1265 bankName.append("/sixteenpack");
1266
1267 std::shared_ptr<const IComponent> bank = instrument->getComponentByName(bankName);
1268
1269 Quat relRot = bank->getRelativeRot();
1270 std::vector<double> relRotAngles = relRot.getEulerAngles("XYZ");
1271 V3D pos1 = bank->getRelativePos();
1272 std::pair<double, double> scales = getRectangularDetectorScaleFactors(instrument, bankName, pmap);
1273
1274 // prepare node
1275 ptree bank_root;
1276 ptree bank_dx, bank_dy, bank_dz;
1277 ptree bank_dx_val, bank_dy_val, bank_dz_val;
1278 ptree bank_drotx, bank_droty, bank_drotz;
1279 ptree bank_drotx_val, bank_droty_val, bank_drotz_val;
1280 ptree bank_sx, bank_sy;
1281 ptree bank_sx_val, bank_sy_val;
1282
1283 // add data to node
1284 bank_dx_val.put("<xmlattr>.val", pos1.X());
1285 bank_dy_val.put("<xmlattr>.val", pos1.Y());
1286 bank_dz_val.put("<xmlattr>.val", pos1.Z());
1287 bank_dx.put("<xmlattr>.name", "x");
1288 bank_dy.put("<xmlattr>.name", "y");
1289 bank_dz.put("<xmlattr>.name", "z");
1290
1291 bank_drotx_val.put("<xmlattr>.val", relRotAngles[0]);
1292 bank_droty_val.put("<xmlattr>.val", relRotAngles[1]);
1293 bank_drotz_val.put("<xmlattr>.val", relRotAngles[2]);
1294 bank_drotx.put("<xmlattr>.name", "rotx");
1295 bank_droty.put("<xmlattr>.name", "roty");
1296 bank_drotz.put("<xmlattr>.name", "rotz");
1297
1298 bank_sx_val.put("<xmlattr>.val", scales.first);
1299 bank_sy_val.put("<xmlattr>.val", scales.second);
1300 bank_sx.put("<xmlattr>.name", "scalex");
1301 bank_sy.put("<xmlattr>.name", "scaley");
1302
1303 bank_root.put("<xmlattr>.name", bankName);
1304
1305 // configure structure
1306 bank_dx.add_child("value", bank_dx_val);
1307 bank_dy.add_child("value", bank_dy_val);
1308 bank_dz.add_child("value", bank_dz_val);
1309
1310 bank_drotx.add_child("value", bank_drotx_val);
1311 bank_droty.add_child("value", bank_droty_val);
1312 bank_drotz.add_child("value", bank_drotz_val);
1313
1314 bank_sx.add_child("value", bank_sx_val);
1315 bank_sy.add_child("value", bank_sy_val);
1316
1317 bank_root.add_child("parameter", bank_drotx);
1318
1319 bank_root.add_child("parameter", bank_droty);
1320 bank_root.add_child("parameter", bank_drotz);
1321 bank_root.add_child("parameter", bank_dx);
1322 bank_root.add_child("parameter", bank_dy);
1323 bank_root.add_child("parameter", bank_dz);
1324 bank_root.add_child("parameter", bank_sx);
1325 bank_root.add_child("parameter", bank_sy);
1326
1327 parafile.add_child("component-link", bank_root);
1328 }
1329
1330 // give everything to root
1331 root.add_child("parameter-file", parafile);
1332 // write the xml tree to disk
1333 g_log.notice() << "\tSaving parameter file as " << FileName << "\n";
1334 boost::property_tree::write_xml(FileName, root, std::locale(),
1335 boost::property_tree::xml_writer_settings<std::string>(' ', 2));
1336}
1337
1348void SCDCalibratePanels2::saveIsawDetCal(const std::string &filename,
1349 boost::container::flat_set<std::string> &AllBankName,
1350 std::shared_ptr<Instrument> &instrument, double T0) {
1351 g_log.notice() << "Saving DetCal file in " << filename << "\n";
1352
1353 bool tuneSamplePos = getProperty("TuneSamplePosition");
1354 if (tuneSamplePos) {
1355 g_log.warning() << "!!!WARNING!!!\n"
1356 << "DetCal format cannot retain sample position info, therefore the calibrated "
1357 << "sample position will be lost if DetCal format is the only output!\n";
1358 }
1359
1360 // create a workspace to pass to SaveIsawDetCal
1361 const size_t number_spectra = instrument->getNumberDetectors();
1362 Workspace2D_sptr wksp =
1363 std::dynamic_pointer_cast<Workspace2D>(WorkspaceFactory::Instance().create("Workspace2D", number_spectra, 2, 1));
1364 wksp->setInstrument(instrument);
1365 wksp->rebuildSpectraMapping(true /* include monitors */);
1366
1367 // convert the bank names into a vector
1368 std::vector<std::string> banknames(AllBankName.begin(), AllBankName.end());
1369
1370 // call SaveIsawDetCal
1371 auto alg = createChildAlgorithm("SaveIsawDetCal");
1372 alg->setProperty("InputWorkspace", wksp);
1373 alg->setProperty("Filename", filename);
1374 alg->setProperty("TimeOffset", T0);
1375 alg->setProperty("BankNames", banknames);
1376 alg->executeAsChildAlg();
1377}
1378
1385void SCDCalibratePanels2::saveCalibrationTable(const std::string &FileName,
1387 auto alg = createChildAlgorithm("SaveAscii");
1388 alg->setProperty("InputWorkspace", tws);
1389 alg->setProperty("Filename", FileName);
1390 alg->setPropertyValue("CommentIndicator", "#");
1391 alg->setPropertyValue("Separator", "CSV");
1392 alg->setProperty("ColumnHeader", true);
1393 alg->setProperty("AppendToFile", false);
1394 alg->executeAsChildAlg();
1395}
1396
1404 Mantid::API::IPeaksWorkspace_sptr pws_original) {
1405 g_log.notice() << "START of profiling objective func along L1\n";
1406
1407 // control option
1408 bool verbose = getProperty("VerboseOutput");
1409 if (verbose) {
1410 // header to console
1411 g_log.notice() << "deltaL1 -- residual\n";
1412 }
1413
1414 // prepare container for profile information
1415 std::ostringstream msgrst;
1416 msgrst.precision(12);
1417 msgrst << "dL1\tresidual\n";
1418
1419 // setting up as if we are doing optimization
1420 auto objf = std::make_shared<SCDCalibratePanels2ObjFunc>();
1421 // NOTE: always use the original pws to get the tofs
1422 std::vector<double> tofs = captureTOF(pws_original);
1423 objf->setPeakWorkspace(pws, "moderator", tofs);
1424
1425 // call the obj to perform evaluation
1426 const int n_peaks = pws->getNumberPeaks();
1427 std::unique_ptr<double[]> target(new double[n_peaks * 3]);
1428
1429 // generate the target
1430 auto ubmatrix = pws->sample().getOrientedLattice().getUB();
1431 for (int i = 0; i < n_peaks; ++i) {
1432 V3D qv = ubmatrix * pws->getPeak(i).getIntHKL();
1433 qv *= 2 * PI;
1434 for (int j = 0; j < 3; ++j) {
1435 target[i * 3 + j] = qv[j];
1436 }
1437 }
1438
1439 const double xValues[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // xValues is not used
1440
1441 // scan from -4cm to 4cm along dL1 where the minimum is supposed to be at 0 for null
1442 // case with instrument at the engineering position
1443 double deltaL1 = -4e-2;
1444 while (deltaL1 < 4e-2) {
1445 std::unique_ptr<double[]> out(new double[n_peaks * 3]);
1446 objf->setParameter("DeltaZ", deltaL1);
1447 objf->setParameter("DeltaT0", 0.0); // need to set dT0 to 0.0 if we are not cali it
1448 objf->function1D(out.get(), xValues, 1);
1449
1450 // calc residual
1451 double residual = 0.0;
1452 for (int i = 0; i < n_peaks * 3; ++i) {
1453 residual += (out[i] - target[i]) * (out[i] - target[i]);
1454 }
1455 residual = std::sqrt(residual) / (n_peaks - 1); // only 1 deg of freedom here
1456 // log rst
1457 msgrst << deltaL1 << "\t" << residual << "\n";
1458
1459 if (verbose) {
1460 g_log.notice() << deltaL1 << " -- " << residual << "\n";
1461 }
1462
1463 // increment
1464 deltaL1 += 1e-4; // 0.1mm step size
1465 }
1466
1467 // output to file
1468 auto filenamebase = std::filesystem::temp_directory_path() / "profileSCDCalibratePanels2_L1.csv";
1469 std::ofstream profL1File;
1470 profL1File.open(filenamebase.string());
1471 profL1File << msgrst.str();
1472 profL1File.close();
1473 g_log.notice() << "Profile data is saved at:\n"
1474 << filenamebase << "\n"
1475 << "END of profiling objective func along L1\n";
1476}
1477
1485 const Mantid::API::IPeaksWorkspace_sptr &pws_original) {
1486 g_log.notice() << "START of profiling all banks along six degree of freedom\n";
1487
1488 // control option
1489 bool verbose = getProperty("VerboseOutput");
1490 if (verbose) {
1491 // header to console
1492 g_log.notice() << "--bankname: residual\n";
1493 }
1494
1495 // Use OPENMP to speed up the profiling
1497 for (int bankIndex = 0; bankIndex < static_cast<int>(m_BankNames.size()); ++bankIndex) {
1499 // prepare local copies to work with
1500 const std::string bankname = *std::next(m_BankNames.begin(), bankIndex);
1501 const std::string pwsBankiName = "_pws_" + bankname;
1502
1503 //-- step 0: extract peaks that lies on the current bank
1504 IPeaksWorkspace_sptr pwsBanki = selectPeaksByBankName(pws, bankname, pwsBankiName);
1505 // get tofs from the original subset of pws
1506 IPeaksWorkspace_sptr pwsBanki_original = selectPeaksByBankName(pws_original, bankname, pwsBankiName);
1507 std::vector<double> tofs = captureTOF(pwsBanki_original);
1508
1509 // Do not attempt correct panels with less than 6 peaks as the system will
1510 // be under-determined
1511 int nBankPeaks = pwsBanki->getNumberPeaks();
1512 if (nBankPeaks < MINIMUM_PEAKS_PER_BANK) {
1513 // use ostringstream to prevent OPENMP breaks log info
1514 std::ostringstream msg_npeakCheckFail;
1515 msg_npeakCheckFail << "-- Cannot profile Bank " << bankname << " have only " << nBankPeaks << " (<"
1516 << MINIMUM_PEAKS_PER_BANK << ") Peaks, skipping\n";
1517 g_log.notice() << msg_npeakCheckFail.str();
1518 continue;
1519 }
1520
1521 //
1523 std::ostringstream msgrst;
1524 msgrst.precision(12);
1525 msgrst << "dx\tdy\tdz\ttheta\tphi\trogang\tresidual\n";
1526 //
1527 auto objf = std::make_shared<SCDCalibratePanels2ObjFunc>();
1528 objf->setPeakWorkspace(pwsBanki, bankname, tofs);
1529 //
1530 const int n_peaks = pwsBanki->getNumberPeaks();
1531 std::unique_ptr<double[]> target(new double[n_peaks * 3]);
1532 // generate the target
1533 auto ubmatrix = pwsBanki->sample().getOrientedLattice().getUB();
1534 for (int i = 0; i < n_peaks; ++i) {
1535 V3D qv = ubmatrix * pwsBanki->getPeak(i).getIntHKL();
1536 qv *= 2 * PI;
1537 for (int j = 0; j < 3; ++j) {
1538 target[i * 3 + j] = qv[j];
1539 }
1540 }
1541
1542 const double xValues[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // xValues is not used
1543
1544 // NOTE: very expensive scan of the parameter space
1545 for (double dx = -1e-2; dx < 1e-2; dx += 2e-2 / 20.0) {
1546 // deltaX: meter
1547 for (double dy = -1e-2; dy < 1e-2; dy += 2e-2 / 20.0) {
1548 // deltaY: meter
1549 for (double dz = -1e-2; dz < 1e-2; dz += 2e-2 / 20.0) {
1550 // deltaZ: meter
1551 for (double theta = 0.0; theta < PI; theta += PI / 20.0) {
1552 // theta: rad
1553 for (double phi = 0.0; phi < 2 * PI; phi += 2 * PI / 20.0) {
1554 // phi: rad
1555 for (double ang = -5.0; ang < 5.0; ang += 5.0 / 20.0) {
1556 // ang: degrees
1557 // configure the objfunc
1558 std::unique_ptr<double[]> out(new double[n_peaks * 3]);
1559 objf->setParameter("DeltaX", dx);
1560 objf->setParameter("DeltaY", dy);
1561 objf->setParameter("DeltaZ", dz);
1562 objf->setParameter("Theta", theta);
1563 objf->setParameter("Phi", phi);
1564 objf->setParameter("DeltaRotationAngle", ang);
1565 objf->setParameter("DeltaT0", 0.0); // need to set dT0 to 0.0 if we are not cali it
1566 objf->function1D(out.get(), xValues, 1);
1567 // calc residual
1568 double residual = 0.0;
1569 for (int i = 0; i < n_peaks * 3; ++i) {
1570 residual += (out[i] - target[i]) * (out[i] - target[i]);
1571 }
1572 residual = std::sqrt(residual) / (n_peaks - 6);
1573 // record
1574 msgrst << dx << "\t" << dy << "\t" << dz << "\t" << theta << "\t" << phi << "\t" << ang << "\t"
1575 << residual << "\n";
1576
1577 if (verbose) {
1578 g_log.notice() << "--" << bankname << ": " << residual << "\n";
1579 }
1580 }
1581 }
1582 }
1583 }
1584 }
1585 }
1586
1587 // output to file
1588 const std::string csvname = "profileSCDCalibratePanels2_" + bankname + ".csv";
1589 auto filenamebase = std::filesystem::temp_directory_path() / csvname;
1590 std::ofstream profBankFile;
1591 profBankFile.open(filenamebase.string());
1592 profBankFile << msgrst.str();
1593 profBankFile.close();
1594
1595 // notify at the terminal
1596 std::ostringstream msg;
1597 msg << "Profile of " << bankname << " is saved at:\n"
1598 << filenamebase << "\n"
1599 << "END of profiling objective func for " << bankname << "\n";
1600 g_log.notice() << msg.str();
1602 }
1604}
1605
1613 Mantid::API::IPeaksWorkspace_sptr pws_original) {
1614 g_log.notice() << "START of profiling objective func along T0\n";
1615
1616 // control option
1617 bool verbose = getProperty("VerboseOutput");
1618 if (verbose) {
1619 // print the header to console
1620 g_log.notice() << "deltaT0 -- residual\n";
1621 }
1622
1623 // prepare container for profile information
1624 std::ostringstream msgrst;
1625 msgrst.precision(12);
1626 msgrst << "dT0\tresidual\n";
1627
1628 // setting up as if we are doing optimization
1629 auto objf = std::make_shared<SCDCalibratePanels2ObjFunc>();
1630 // NOTE: always use the original pws to get the tofs
1631 std::vector<double> tofs = captureTOF(pws_original);
1632 objf->setPeakWorkspace(pws, "none", tofs);
1633
1634 // generate the target
1635 const int n_peaks = pws->getNumberPeaks();
1636 std::unique_ptr<double[]> target(new double[n_peaks * 3]);
1637 auto ubmatrix = pws->sample().getOrientedLattice().getUB();
1638 for (int i = 0; i < n_peaks; ++i) {
1639 V3D qv = ubmatrix * pws->getPeak(i).getIntHKL();
1640 qv *= 2 * PI;
1641 for (int j = 0; j < 3; ++j) {
1642 target[i * 3 + j] = qv[j];
1643 }
1644 }
1645
1646 const double xValues[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // xValues is not used
1647
1648 // scan from -10 ~ 10 ms along dT0
1649 double deltaT0 = -10;
1650 while (deltaT0 < 10) {
1651 std::unique_ptr<double[]> out(new double[n_peaks * 3]);
1652 objf->setParameter("DeltaT0", deltaT0);
1653 objf->function1D(out.get(), xValues, 1);
1654
1655 // calc residual
1656 double residual = 0.0;
1657 for (int i = 0; i < n_peaks * 3; ++i) {
1658 residual += (out[i] - target[i]) * (out[i] - target[i]);
1659 }
1660 residual = std::sqrt(residual) / (n_peaks - 1); // only 1 deg of freedom here
1661 // log rst
1662 msgrst << deltaT0 << "\t" << residual << "\n";
1663
1664 if (verbose) {
1665 g_log.notice() << deltaT0 << " -- " << residual << "\n";
1666 }
1667
1668 // increment
1669 deltaT0 += 0.01; // 20/2000.0
1670 }
1671
1672 // output to file
1673 auto filenamebase = std::filesystem::temp_directory_path() / "profileSCDCalibratePanels2_T0.csv";
1674 std::ofstream profL1File;
1675 profL1File.open(filenamebase.string());
1676 profL1File << msgrst.str();
1677 profL1File.close();
1678 g_log.notice() << "Profile data is saved at:\n"
1679 << filenamebase << "\n"
1680 << "END of profiling objective func along T0\n";
1681}
1682
1690 Mantid::API::IPeaksWorkspace_sptr pws_original) {
1691 g_log.notice() << "START of profiling objective func along L1 and T0\n";
1692
1693 // control option
1694 bool verbose = getProperty("VerboseOutput");
1695 if (verbose) {
1696 // print the header to console
1697 g_log.notice() << "deltaL1 -- deltaT0 -- residual\n";
1698 }
1699
1700 // prepare container for profile information
1701 std::ostringstream msgrst;
1702 msgrst.precision(12);
1703 msgrst << "dL1\tdT0\tresidual\n";
1704
1705 // setting up as if we are doing optimization
1706 auto objf = std::make_shared<SCDCalibratePanels2ObjFunc>();
1707 // NOTE: always use the original pws to get the tofs
1708 std::vector<double> tofs = captureTOF(pws_original);
1709 objf->setPeakWorkspace(pws, "moderator", tofs);
1710
1711 // generate the target
1712 const int n_peaks = pws->getNumberPeaks();
1713 std::unique_ptr<double[]> target(new double[n_peaks * 3]);
1714 auto ubmatrix = pws->sample().getOrientedLattice().getUB();
1715 for (int i = 0; i < n_peaks; ++i) {
1716 V3D qv = ubmatrix * pws->getPeak(i).getIntHKL();
1717 qv *= 2 * PI;
1718 for (int j = 0; j < 3; ++j) {
1719 target[i * 3 + j] = qv[j];
1720 }
1721 }
1722
1723 const double xValues[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // xValues is not used
1724
1725 // profile begin
1726 for (double deltaL1 = -4e-2; deltaL1 < 4e-2; deltaL1 += 1e-4) {
1727 for (double deltaT0 = -4.0; deltaT0 < 4.0; deltaT0 += 1e-2) {
1728 std::unique_ptr<double[]> out(new double[n_peaks * 3]);
1729 objf->setParameter("DeltaZ", deltaL1);
1730 objf->setParameter("DeltaT0", deltaT0);
1731 objf->function1D(out.get(), xValues, 1);
1732
1733 // calc residual
1734 double residual = 0.0;
1735 for (int i = 0; i < n_peaks * 3; ++i) {
1736 residual += (out[i] - target[i]) * (out[i] - target[i]);
1737 }
1738 residual = std::sqrt(residual) / (n_peaks - 2); // only 1 deg of freedom here
1739
1740 if (verbose) {
1741 g_log.notice() << deltaL1 << " -- " << deltaT0 << " -- " << residual << "\n";
1742 }
1743 // log rst
1744 msgrst << deltaL1 << "\t" << deltaT0 << "\t" << residual << "\n";
1745 }
1746 }
1747
1748 // output to file
1749 auto filenamebase = std::filesystem::temp_directory_path() / "profileSCDCalibratePanels2_L1T0.csv";
1750 std::ofstream profL1File;
1751 profL1File.open(filenamebase.string());
1752 profL1File << msgrst.str();
1753 profL1File.close();
1754
1755 // log
1756 g_log.notice() << "Profile data is saved at:\n"
1757 << filenamebase << "\n"
1758 << "END of profiling objective func along L1 and T0\n";
1759}
1760
1773std::pair<double, double>
1774SCDCalibratePanels2::getRectangularDetectorScaleFactors(std::shared_ptr<Geometry::Instrument> &instrument,
1775 const std::string &bankname,
1777
1778 std::pair<double, double> scales{1.0, 1.0};
1779
1780 // docalibsize, sizesearchradius, fixdetxyratio
1781 Geometry::IComponent_const_sptr comp = instrument->getComponentByName(bankname);
1782 std::shared_ptr<const Geometry::RectangularDetector> rectDet =
1783 std::dynamic_pointer_cast<const Geometry::RectangularDetector>(comp);
1784
1785 if (rectDet) {
1786 // retrieve the (scalex, scaley) stored in the workspace for this bank/component
1787 auto scalexparams = pmap.getDouble(rectDet->getName(), "scalex");
1788 auto scaleyparams = pmap.getDouble(rectDet->getName(), "scaley");
1789 if (!scalexparams.empty())
1790 scales.first = scalexparams[0];
1791 if (!scaleyparams.empty())
1792 scales.second = scaleyparams[0];
1793 }
1794
1795 return scales;
1796}
1797
1798} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#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_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 PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
@ OptionalSave
to specify a file to write to but an empty string is
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
SCDCalibratePanels2 : Using input peakworkspace with indexation results to calibrate each individual ...
Mantid::API::IPeaksWorkspace_sptr removeUnindexedPeaks(const Mantid::API::IPeaksWorkspace_sptr &pws)
Remove unindexed peaks from workspace.
void adjustComponent(double dx, double dy, double dz, double drx, double dry, double drz, double scalex, double scaley, const std::string &cmptName, Mantid::API::IPeaksWorkspace_sptr &pws)
Helper functions for adjusting components.
void saveIsawDetCal(const std::string &filename, boost::container::flat_set< std::string > &AllBankName, std::shared_ptr< Geometry::Instrument > &instrument, double T0)
Save to ISAW type det calibration output for backward compatiblity.
Mantid::API::ITableWorkspace_sptr generateCalibrationTable(std::shared_ptr< Geometry::Instrument > &instrument, const Geometry::ParameterMap &pmap)
Generate a Table workspace to store the calibration results.
void profileBanks(Mantid::API::IPeaksWorkspace_sptr const &pws, const Mantid::API::IPeaksWorkspace_sptr &pws_original)
Profiling obj func along six degree of freedom, which can be very slow.
void optimizeT0(Mantid::API::IPeaksWorkspace_sptr pws, Mantid::API::IPeaksWorkspace_sptr pws_original)
Private function for calibrating T0.
void optimizeL1(Mantid::API::IPeaksWorkspace_sptr pws, Mantid::API::IPeaksWorkspace_sptr pws_original)
Private function for calibrating L1.
double m_a
unique vars for a given instance of calibration
void optimizeSamplePos(Mantid::API::IPeaksWorkspace_sptr pws, Mantid::API::IPeaksWorkspace_sptr pws_original)
Private function for fine tunning sample position.
const std::vector< std::string > calibrationTableColumnTypes
void getBankNames(const Mantid::API::IPeaksWorkspace_sptr &pws)
Private function for getting names of banks to be calibrated.
boost::container::flat_set< std::string > m_BankNames
void updateUBMatrix(const Mantid::API::IPeaksWorkspace_sptr &pws)
Update the UB matrix.
void optimizeBanks(Mantid::API::IPeaksWorkspace_sptr pws, const Mantid::API::IPeaksWorkspace_sptr &pws_original, const bool &docalibsize, const double &sizesearchradius, const bool &fixdetxyratio)
Private function for calibrating banks.
void parseLatticeConstant(const Mantid::API::IPeaksWorkspace_sptr &pws)
Private function dedicated for parsing lattice constant.
const std::vector< std::string > calibrationTableColumnNames
void saveXmlFile(const std::string &FileName, const boost::container::flat_set< std::string > &AllBankNames, std::shared_ptr< Geometry::Instrument > &instrument, const Geometry::ParameterMap &pmap)
Save to xml file for Mantid to load by manual crafting.
void exec() override
Overwrites Algorithm method.
void profileT0(Mantid::API::IPeaksWorkspace_sptr &pws, Mantid::API::IPeaksWorkspace_sptr pws_original)
Profile obj func along T0 axis.
Mantid::API::IPeaksWorkspace_sptr selectPeaksByBankName(const Mantid::API::IPeaksWorkspace_sptr &pws, const std::string &bankname, const std::string &outputwsn)
Helper function for selecting peaks based on given bank name.
std::map< std::string, std::string > validateInputs() override
Private validator for inputs.
std::pair< double, double > getRectangularDetectorScaleFactors(std::shared_ptr< Geometry::Instrument > &instrument, const std::string &bankname, const Geometry::ParameterMap &pmap)
Retrieve "scalex" and "scaley" from a workspace's parameter map if the component is rectangular detec...
void saveCalibrationTable(const std::string &FileName, Mantid::API::ITableWorkspace_sptr const &tws)
Save the calibration table to a CSV file.
Mantid::API::MatrixWorkspace_sptr getIdealQSampleAsHistogram1D(const Mantid::API::IPeaksWorkspace_sptr &pws)
Helper function that calculates the ideal qSample based on integer HKL.
void profileL1(Mantid::API::IPeaksWorkspace_sptr &pws, Mantid::API::IPeaksWorkspace_sptr pws_original)
Profile related functions.
void profileL1T0(Mantid::API::IPeaksWorkspace_sptr &pws, Mantid::API::IPeaksWorkspace_sptr pws_original)
Profile obj func along L1 and T0 axis.
std::vector< double > captureTOF(const Mantid::API::IPeaksWorkspace_sptr &pws)
Cache TOF equivalent to those measured from experiment.
Class to implement 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
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
Class for quaternions.
Definition Quat.h:39
void getAngleAxis(double &_deg, double &_ax0, double &_ax1, double &ax2) const
Extracts the angle of roatation and axis.
Definition Quat.cpp:135
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...
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< IPeaksWorkspace > IPeaksWorkspace_sptr
shared pointer to Mantid::API::IPeaksWorkspace
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
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< 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.
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
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54