441 if (fileName.empty() && !inputEventWS) {
442 g_log.
error() <<
"EQSANSLoad input error: Either a valid file path or an "
443 "input workspace must be provided\n";
444 throw std::runtime_error(
"EQSANSLoad input error: Either a valid file path "
445 "or an input workspace must be provided");
446 }
else if (!fileName.empty() && inputEventWS) {
447 g_log.
error() <<
"EQSANSLoad input error: Either a valid file path or an "
448 "input workspace must be provided, but not both\n";
449 throw std::runtime_error(
"EQSANSLoad input error: Either a valid file path "
450 "or an input workspace must be provided, but not "
455 const bool skipTOFCorrection =
getProperty(
"SkipTOFCorrection");
462 const bool noBeamCenter =
getProperty(
"NoBeamCenter");
465 const std::string reductionManagerName =
getProperty(
"ReductionProperties");
466 std::shared_ptr<PropertyManager> reductionManager;
467 if (PropertyManagerDataService::Instance().doesExist(reductionManagerName)) {
468 reductionManager = PropertyManagerDataService::Instance().retrieve(reductionManagerName);
470 reductionManager = std::make_shared<PropertyManager>();
471 PropertyManagerDataService::Instance().addOrReplace(reductionManagerName, reductionManager);
474 if (!reductionManager->existsProperty(
"LoadAlgorithm")) {
475 auto loadProp = std::make_unique<AlgorithmProperty>(
"LoadAlgorithm");
479 reductionManager->declareProperty(std::move(loadProp));
482 if (!reductionManager->existsProperty(
"InstrumentName"))
490 const bool loadMonitors =
getProperty(
"LoadMonitors");
491 const bool loadNexusInstrumentXML =
getProperty(
"LoadNexusInstrumentXML");
493 loadAlg->setProperty(
"LoadMonitors", loadMonitors);
494 loadAlg->setProperty(
"Filename", fileName);
495 loadAlg->setProperty(
"LoadNexusInstrumentXML", loadNexusInstrumentXML);
496 if (skipTOFCorrection) {
503 Workspace_sptr dataWS_asWks = loadAlg->getProperty(
"OutputWorkspace");
504 dataWS = std::dynamic_pointer_cast<MatrixWorkspace>(dataWS_asWks);
508 if (loadMonitors && loadAlg->existsProperty(
"MonitorWorkspace")) {
509 Workspace_sptr monWSOutput = loadAlg->getProperty(
"MonitorWorkspace");
511 if ((monWSOutput) && (!monWS))
515 "data, support for this is not "
516 "implemented in EQSANSLoad yet");
518 "Monitors from the Event NeXus file");
524 if (inputEventWS != outputEventWS) {
526 copyAlg->setProperty(
"InputWorkspace", inputEventWS);
527 copyAlg->executeAsChildAlg();
528 Workspace_sptr dataWS_asWks = copyAlg->getProperty(
"OutputWorkspace");
529 dataWS = std::dynamic_pointer_cast<MatrixWorkspace>(dataWS_asWks);
531 dataWS = std::dynamic_pointer_cast<MatrixWorkspace>(inputEventWS);
539 const double sampleflange_det_dist =
getProperty(
"SampleDetectorDistance");
540 if (!
isEmpty(sampleflange_det_dist)) {
541 sfdd = sampleflange_det_dist;
543 if (!
dataWS->run().hasProperty(
"detectorZ")) {
544 g_log.
error() <<
"Could not determine Z position: the "
545 "SampleDetectorDistance property was not set "
546 "and the run logs do not contain the detectorZ property\n";
547 throw std::invalid_argument(
"Could not determine Z position: stopping execution");
550 const std::string dzName =
"detectorZ";
554 throw std::runtime_error(
"Could not cast (interpret) the property " + dzName +
555 " as a time series property value.");
556 sfdd = dp->getStatistics().mean;
559 const double sampleflange_det_offset =
getProperty(
"DetectorOffset");
560 if (!
isEmpty(sampleflange_det_offset))
561 sfdd += sampleflange_det_offset;
565 const double sample_det_offset =
getProperty(
"SampleDetectorDistanceOffset");
566 if (!
isEmpty(sample_det_offset))
567 sfdd += sample_det_offset;
568 if (!
isEmpty(sample_det_offset) && !
isEmpty(sampleflange_det_offset))
569 g_log.
error() <<
"Both DetectorOffset and SampleDetectorDistanceOffset "
570 "are set. Only one should be used.\n";
575 const double sampleflange_sample_offset =
getProperty(
"SampleOffset");
576 if (!
isEmpty(sampleflange_sample_offset)) {
577 s2d -= sampleflange_sample_offset;
582 mvAlg->setProperty(
"ComponentName",
"sample-position");
583 mvAlg->setProperty(
"Z", sampleflange_sample_offset / 1000.0);
584 mvAlg->setProperty(
"RelativePosition",
false);
585 mvAlg->executeAsChildAlg();
586 g_log.
information() <<
"Moving sample to " << sampleflange_sample_offset / 1000.0 <<
" meters\n";
588 " Sample position: " + Poco::NumberFormatter::format(sampleflange_sample_offset / 1000.0, 3) +
" m\n";
591 dataWS->mutableRun().addProperty(
"sampleflange_detector_distance", sfdd,
"mm",
true);
592 dataWS->mutableRun().addProperty(
"sample_detector_distance", s2d,
"mm",
true);
597 mvAlg->setProperty(
"ComponentName",
"detector1");
598 mvAlg->setProperty(
"Z", sfdd / 1000.0);
599 mvAlg->setProperty(
"RelativePosition",
false);
600 mvAlg->executeAsChildAlg();
601 g_log.
information() <<
"Moving detector to " << sfdd / 1000.0 <<
" meters\n";
602 m_output_message +=
" Detector position: " + Poco::NumberFormatter::format(sfdd / 1000.0, 3) +
" m\n";
606 std::string config_file;
607 if (
dataWS->run().hasProperty(
"run_number")) {
608 const std::string run_str =
dataWS->run().getPropertyValueAsType<std::string>(
"run_number");
609 Poco::NumberParser::tryParse(run_str, run_number);
619 if (use_config && !config_file.empty()) {
627 }
else if (use_config) {
631 " Could not find configuration file for run " + Poco::NumberFormatter::format(run_number) +
"\n";
637 g_log.
error() <<
"Moderator position seems close to the sample, please check\n";
642 mvAlg->setProperty(
"ComponentName",
"moderator");
644 mvAlg->setProperty(
"RelativePosition",
false);
645 mvAlg->executeAsChildAlg();
654 if (reductionManager->existsProperty(
"LatestBeamCenterX") &&
655 reductionManager->existsProperty(
"LatestBeamCenterY")) {
656 m_center_x = reductionManager->getProperty(
"LatestBeamCenterX");
657 m_center_y = reductionManager->getProperty(
"LatestBeamCenterY");
665 if (!reductionManager->existsProperty(
"LatestBeamCenterX"))
668 reductionManager->setProperty(
"LatestBeamCenterX",
m_center_x);
669 if (!reductionManager->existsProperty(
"LatestBeamCenterY"))
672 reductionManager->setProperty(
"LatestBeamCenterY",
m_center_y);
676 const bool correct_for_flight_path =
getProperty(
"CorrectForFlightPath");
679 double wl_combined_max = 0.0;
680 if (skipTOFCorrection) {
681 m_output_message +=
" Skipping EQSANS TOF correction: assuming a single frame\n";
682 dataWS->mutableRun().addProperty(
"is_frame_skipping", 0,
true);
683 if (correct_for_flight_path) {
684 g_log.
error() <<
"CorrectForFlightPath and SkipTOFCorrection can't be "
685 "set to true at the same time\n";
690 if (!correct_for_flight_path)
698 tofAlg->setProperty(
"FlightPathCorrection", correct_for_flight_path);
699 tofAlg->executeAsChildAlg();
700 wl_min = tofAlg->getProperty(
"WavelengthMin");
701 wl_max = tofAlg->getProperty(
"WavelengthMax");
702 if (wl_min >= wl_max) {
707 const bool frame_skipping = tofAlg->getProperty(
"FrameSkipping");
708 dataWS->mutableRun().addProperty(
"wavelength_min", wl_min,
"Angstrom",
true);
709 dataWS->mutableRun().addProperty(
"wavelength_max", wl_max,
"Angstrom",
true);
710 dataWS->mutableRun().addProperty(
"is_frame_skipping",
int(frame_skipping),
true);
711 wl_combined_max = wl_max;
713 " Wavelength range: " + Poco::NumberFormatter::format(wl_min) +
" - " + Poco::NumberFormatter::format(wl_max);
714 if (frame_skipping) {
715 const double wl_min2 = tofAlg->getProperty(
"WavelengthMinFrame2");
716 const double wl_max2 = tofAlg->getProperty(
"WavelengthMaxFrame2");
717 wl_combined_max = wl_max2;
718 dataWS->mutableRun().addProperty(
"wavelength_min_frame2", wl_min2,
"Angstrom",
true);
719 dataWS->mutableRun().addProperty(
"wavelength_max_frame2", wl_max2,
"Angstrom",
true);
720 m_output_message +=
" and " + Poco::NumberFormatter::format(wl_min2) +
" - " +
721 Poco::NumberFormatter::format(wl_max2) +
" Angstrom\n";
729 const double ssd =
fabs(
dataWS->getInstrument()->getSource()->getPos().Z()) * 1000.0;
730 const double conversion_factor = 3.9560346 / (sfdd + ssd);
732 " TOF to wavelength conversion factor: " + Poco::NumberFormatter::format(conversion_factor) +
"\n";
734 if (skipTOFCorrection) {
736 if (dataWS_evt->getNumberEvents() == 0)
737 throw std::invalid_argument(
"No event to process: check your TOF cuts");
738 wl_min = dataWS_evt->getTofMin() * conversion_factor;
739 wl_max = dataWS_evt->getTofMax() * conversion_factor;
740 wl_combined_max = wl_max;
741 g_log.
information() <<
"Wavelength range: " << wl_min <<
" to " << wl_max <<
'\n';
742 dataWS->mutableRun().addProperty(
"wavelength_min", wl_min,
"Angstrom",
true);
743 dataWS->mutableRun().addProperty(
"wavelength_max", wl_max,
"Angstrom",
true);
749 scAlg->setProperty(
"Factor", conversion_factor);
750 scAlg->executeAsChildAlg();
751 dataWS->getAxis(0)->setUnit(
"Wavelength");
754 const bool preserveEvents =
getProperty(
"PreserveEvents");
755 const double wl_step =
getProperty(
"WavelengthStep");
757 const double wl_min_rounded = round(wl_min * 100.0) / 100.0;
758 const double wl_max_rounded = round(wl_combined_max * 100.0) / 100.0;
759 std::string params = Poco::NumberFormatter::format(wl_min_rounded, 2) +
"," + Poco::NumberFormatter::format(wl_step) +
760 "," + Poco::NumberFormatter::format(wl_max_rounded, 2);
766 rebinAlg->setPropertyValue(
"Params", params);
767 rebinAlg->setProperty(
"PreserveEvents", preserveEvents);
768 rebinAlg->executeAsChildAlg();
771 dataWS = rebinAlg->getProperty(
"OutputWorkspace");
774 setProperty<MatrixWorkspace_sptr>(
"OutputWorkspace", std::dynamic_pointer_cast<MatrixWorkspace>(
dataWS));