コード例 #1
0
Workspace_sptr
GenericDataProcessorAlgorithm<Base>::load(const std::string &inputData,
                                          const bool loadQuiet) {
  Workspace_sptr inputWS;

  // First, check whether we have the name of an existing workspace
  if (AnalysisDataService::Instance().doesExist(inputData)) {
    inputWS = AnalysisDataService::Instance().retrieve(inputData);
  } else {
    std::string foundFile = FileFinder::Instance().getFullPath(inputData);
    if (foundFile.empty()) {
      // Get facility extensions
      FacilityInfo facilityInfo = ConfigService::Instance().getFacility();
      const std::vector<std::string> facilityExts = facilityInfo.extensions();
      foundFile = FileFinder::Instance().findRun(inputData, facilityExts);
    }

    if (!foundFile.empty()) {
      Poco::Path p(foundFile);
      const std::string outputWSName = p.getBaseName();

      IAlgorithm_sptr loadAlg = createChildAlgorithm(m_loadAlg);
      loadAlg->setProperty(m_loadAlgFileProp, foundFile);
      if (!loadQuiet) {
        loadAlg->setAlwaysStoreInADS(true);
      }

// Set up MPI if available
#ifdef MPI_BUILD
      // First, check whether the loader allows use to chunk the data
      if (loadAlg->existsProperty("ChunkNumber") &&
          loadAlg->existsProperty("TotalChunks")) {
        m_useMPI = true;
        // The communicator containing all processes
        boost::mpi::communicator world;
        g_log.notice() << "Chunk/Total: " << world.rank() + 1 << "/"
                       << world.size() << '\n';
        loadAlg->setPropertyValue("OutputWorkspace", outputWSName);
        loadAlg->setProperty("ChunkNumber", world.rank() + 1);
        loadAlg->setProperty("TotalChunks", world.size());
      }
#endif
      loadAlg->execute();

      if (loadQuiet) {
        inputWS = loadAlg->getProperty("OutputWorkspace");
      } else {
        inputWS = AnalysisDataService::Instance().retrieve(outputWSName);
      }
    } else
      throw std::runtime_error(
          "DataProcessorAlgorithm::load could process any data");
  }
  return inputWS;
}
コード例 #2
0
void HFIRDarkCurrentSubtraction::exec()
{
  std::string output_message = "";
  // Reduction property manager
  const std::string reductionManagerName = getProperty("ReductionProperties");
  boost::shared_ptr<PropertyManager> reductionManager;
  if (PropertyManagerDataService::Instance().doesExist(reductionManagerName))
  {
    reductionManager = PropertyManagerDataService::Instance().retrieve(reductionManagerName);
  }
  else
  {
    reductionManager = boost::make_shared<PropertyManager>();
    PropertyManagerDataService::Instance().addOrReplace(reductionManagerName, reductionManager);
  }

  // If the load algorithm isn't in the reduction properties, add it
  const bool persistent = getProperty("PersistentCorrection");
  if (!reductionManager->existsProperty("DarkCurrentAlgorithm") && persistent)
  {
    AlgorithmProperty *algProp = new AlgorithmProperty("DarkCurrentAlgorithm");
    algProp->setValue(toString());
    reductionManager->declareProperty(algProp);
  }

  Progress progress(this,0.0,1.0,10);

  MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
  const std::string fileName = getPropertyValue("Filename");
  MatrixWorkspace_sptr darkWS;
  std::string darkWSName = getPropertyValue("OutputDarkCurrentWorkspace");

  progress.report("Subtracting dark current");

  // Look for an entry for the dark current in the reduction table
  Poco::Path path(fileName);
  const std::string entryName = "DarkCurrent"+path.getBaseName();

  if (reductionManager->existsProperty(entryName))
  {
    darkWS = reductionManager->getProperty(entryName);
    darkWSName = reductionManager->getPropertyValue(entryName);
    output_message += darkWSName + '\n';
  } else {
    // Load the dark current if we don't have it already
    if (darkWSName.size()==0)
    {
      darkWSName = "__dark_current_"+path.getBaseName();
      setPropertyValue("OutputDarkCurrentWorkspace", darkWSName);
    }

    IAlgorithm_sptr loadAlg;
    if (!reductionManager->existsProperty("LoadAlgorithm"))
    {
      loadAlg = createChildAlgorithm("HFIRLoad", 0.1, 0.3);
      loadAlg->setProperty("Filename", fileName);
      loadAlg->setProperty("ReductionProperties", reductionManagerName);
      loadAlg->executeAsChildAlg();
    } else {
      IAlgorithm_sptr loadAlg0 = reductionManager->getProperty("LoadAlgorithm");
      const std::string loadString = loadAlg0->toString();
      loadAlg = Algorithm::fromString(loadString);
      loadAlg->setChild(true);
      loadAlg->setProperty("Filename", fileName);
      loadAlg->setProperty("ReductionProperties", reductionManagerName);
      loadAlg->setPropertyValue("OutputWorkspace", darkWSName);
      loadAlg->execute();
    }
    darkWS = loadAlg->getProperty("OutputWorkspace");
    output_message += "\n   Loaded " + fileName + "\n";
    if (loadAlg->existsProperty("OutputMessage"))
    {
      std::string msg = loadAlg->getPropertyValue("OutputMessage");
      output_message += "   |" + Poco::replace(msg, "\n", "\n   |") + "\n";
    }

    setProperty("OutputDarkCurrentWorkspace", darkWS);
    reductionManager->declareProperty(new WorkspaceProperty<>(entryName,"",Direction::Output));
    reductionManager->setPropertyValue(entryName, darkWSName);
    reductionManager->setProperty(entryName, darkWS);
  }
  progress.report(3, "Loaded dark current");

  // Perform subtraction
  double darkTimer = getCountingTime(darkWS);
  double dataTimer = getCountingTime(inputWS);
  IAlgorithm_sptr scaleAlg = createChildAlgorithm("Scale", 0.3, 0.5);
  scaleAlg->setProperty("InputWorkspace", darkWS);
  scaleAlg->setProperty("Factor", dataTimer/darkTimer);
  scaleAlg->setProperty("Operation", "Multiply");
  scaleAlg->executeAsChildAlg();
  MatrixWorkspace_sptr scaledDarkWS = scaleAlg->getProperty("OutputWorkspace");

  // Zero out timer and monitor so that we don't subtract them out
  for(size_t i=0; i<scaledDarkWS->dataY(0).size(); i++)
  {
    scaledDarkWS->dataY(DEFAULT_TIMER_ID)[i]=0.0;
    scaledDarkWS->dataE(DEFAULT_TIMER_ID)[i]=0.0;
    scaledDarkWS->dataY(DEFAULT_MONITOR_ID)[i]=0.0;
    scaledDarkWS->dataE(DEFAULT_MONITOR_ID)[i]=0.0;
  }
  IAlgorithm_sptr minusAlg = createChildAlgorithm("Minus", 0.5, 0.7);
  minusAlg->setProperty("LHSWorkspace", inputWS);
  minusAlg->setProperty("RHSWorkspace", scaledDarkWS);
  MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
  minusAlg->setProperty("OutputWorkspace", outputWS);
  minusAlg->executeAsChildAlg();
  MatrixWorkspace_sptr correctedWS = minusAlg->getProperty("OutputWorkspace");
  setProperty("OutputWorkspace", correctedWS);
  setProperty("OutputMessage", "Dark current subtracted: "+output_message);

  progress.report("Subtracted dark current");
}
コード例 #3
0
ファイル: EQSANSLoad.cpp プロジェクト: liyulun/mantid
void EQSANSLoad::exec() {
  // Verify the validity of the inputs
  // TODO: this should be done by the new data management algorithm used for
  // live data reduction (when it's implemented...)
  const std::string fileName = getPropertyValue("Filename");
  EventWorkspace_sptr inputEventWS = getProperty("InputWorkspace");
  if (fileName.size() == 0 && !inputEventWS) {
    g_log.error() << "EQSANSLoad input error: Either a valid file path or an "
                     "input workspace must be provided\n";
    throw std::runtime_error("EQSANSLoad input error: Either a valid file path "
                             "or an input workspace must be provided");
  } else if (fileName.size() > 0 && inputEventWS) {
    g_log.error() << "EQSANSLoad input error: Either a valid file path or an "
                     "input workspace must be provided, but not both\n";
    throw std::runtime_error("EQSANSLoad input error: Either a valid file path "
                             "or an input workspace must be provided, but not "
                             "both");
  }

  // Read in default TOF cuts
  const bool skipTOFCorrection = getProperty("SkipTOFCorrection");
  m_low_TOF_cut = getProperty("LowTOFCut");
  m_high_TOF_cut = getProperty("HighTOFCut");

  // Read in default beam center
  m_center_x = getProperty("BeamCenterX");
  m_center_y = getProperty("BeamCenterY");
  const bool noBeamCenter = getProperty("NoBeamCenter");

  // Reduction property manager
  const std::string reductionManagerName = getProperty("ReductionProperties");
  boost::shared_ptr<PropertyManager> reductionManager;
  if (PropertyManagerDataService::Instance().doesExist(reductionManagerName)) {
    reductionManager =
        PropertyManagerDataService::Instance().retrieve(reductionManagerName);
  } else {
    reductionManager = boost::make_shared<PropertyManager>();
    PropertyManagerDataService::Instance().addOrReplace(reductionManagerName,
                                                        reductionManager);
  }

  if (!reductionManager->existsProperty("LoadAlgorithm")) {
    auto loadProp = make_unique<AlgorithmProperty>("LoadAlgorithm");
    setPropertyValue("InputWorkspace", "");
    setProperty("NoBeamCenter", false);
    loadProp->setValue(toString());
    reductionManager->declareProperty(std::move(loadProp));
  }

  if (!reductionManager->existsProperty("InstrumentName")) {
    reductionManager->declareProperty(
        make_unique<PropertyWithValue<std::string>>("InstrumentName",
                                                    "EQSANS"));
  }

  // Output log
  m_output_message = "";

  // Check whether we need to load the data
  if (!inputEventWS) {
    const bool loadMonitors = getProperty("LoadMonitors");
    IAlgorithm_sptr loadAlg = createChildAlgorithm("LoadEventNexus", 0, 0.2);
    loadAlg->setProperty("LoadMonitors", loadMonitors);
    loadAlg->setProperty("MonitorsAsEvents", false);
    loadAlg->setProperty("Filename", fileName);
    if (skipTOFCorrection) {
      if (m_low_TOF_cut > 0.0)
        loadAlg->setProperty("FilterByTofMin", m_low_TOF_cut);
      if (m_high_TOF_cut > 0.0)
        loadAlg->setProperty("FilterByTofMax", m_high_TOF_cut);
    }
    loadAlg->execute();
    Workspace_sptr dataWS_asWks = loadAlg->getProperty("OutputWorkspace");
    dataWS = boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS_asWks);

    // Get monitor workspace as necessary
    std::string mon_wsname = getPropertyValue("OutputWorkspace") + "_monitors";
    if (loadMonitors && loadAlg->existsProperty("MonitorWorkspace")) {
      Workspace_sptr monWSOutput = loadAlg->getProperty("MonitorWorkspace");
      MatrixWorkspace_sptr monWS =
          boost::dynamic_pointer_cast<MatrixWorkspace>(monWSOutput);
      if ((monWSOutput) && (!monWS)) {
        // this was a group workspace - EQSansLoad does not support multi period
        // data yet
        throw Exception::NotImplementedError("The file contains multi period "
                                             "data, support for this is not "
                                             "implemented in EQSANSLoad yet");
      }
      declareProperty(Kernel::make_unique<WorkspaceProperty<>>(
                          "MonitorWorkspace", mon_wsname, Direction::Output),
                      "Monitors from the Event NeXus file");
      setProperty("MonitorWorkspace", monWS);
    }
  } else {
    MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
    EventWorkspace_sptr outputEventWS =
        boost::dynamic_pointer_cast<EventWorkspace>(outputWS);
    if (inputEventWS != outputEventWS) {
      IAlgorithm_sptr copyAlg = createChildAlgorithm("CloneWorkspace", 0, 0.2);
      copyAlg->setProperty("InputWorkspace", inputEventWS);
      copyAlg->executeAsChildAlg();
      Workspace_sptr dataWS_asWks = copyAlg->getProperty("OutputWorkspace");
      dataWS = boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS_asWks);
    } else {
      dataWS = boost::dynamic_pointer_cast<MatrixWorkspace>(inputEventWS);
    }
  }

  // Get the sample-detector distance
  double sdd = 0.0;
  const double sample_det_dist = getProperty("SampleDetectorDistance");
  if (!isEmpty(sample_det_dist)) {
    sdd = sample_det_dist;
  } else {
    if (!dataWS->run().hasProperty("detectorZ")) {
      g_log.error()
          << "Could not determine Z position: the "
             "SampleDetectorDistance property was not set "
             "and the run logs do not contain the detectorZ property\n";
      throw std::invalid_argument(
          "Could not determine Z position: stopping execution");
    }

    const std::string dzName = "detectorZ";
    Mantid::Kernel::Property *prop = dataWS->run().getProperty(dzName);
    Mantid::Kernel::TimeSeriesProperty<double> *dp =
        dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double> *>(prop);
    if (!dp) {
      throw std::runtime_error("Could not cast (interpret) the property " +
                               dzName + " as a time series property value.");
    }
    sdd = dp->getStatistics().mean;

    // Modify SDD according to offset if given
    const double sample_det_offset =
        getProperty("SampleDetectorDistanceOffset");
    if (!isEmpty(sample_det_offset)) {
      sdd += sample_det_offset;
    }
  }
  dataWS->mutableRun().addProperty("sample_detector_distance", sdd, "mm", true);

  // Move the detector to its correct position
  IAlgorithm_sptr mvAlg =
      createChildAlgorithm("MoveInstrumentComponent", 0.2, 0.4);
  mvAlg->setProperty<MatrixWorkspace_sptr>("Workspace", dataWS);
  mvAlg->setProperty("ComponentName", "detector1");
  mvAlg->setProperty("Z", sdd / 1000.0);
  mvAlg->setProperty("RelativePosition", false);
  mvAlg->executeAsChildAlg();
  g_log.information() << "Moving detector to " << sdd / 1000.0 << " meters\n";
  m_output_message += "   Detector position: " +
                      Poco::NumberFormatter::format(sdd / 1000.0, 3) + " m\n";

  // Get the run number so we can find the proper config file
  int run_number = 0;
  std::string config_file = "";
  if (dataWS->run().hasProperty("run_number")) {
    const std::string run_str =
        dataWS->run().getPropertyValueAsType<std::string>("run_number");
    Poco::NumberParser::tryParse(run_str, run_number);
    // Find a proper config file
    config_file = findConfigFile(run_number);
  } else {
    g_log.error() << "Could not find run number for workspace "
                  << getPropertyValue("OutputWorkspace") << '\n';
    m_output_message += "   Could not find run number for data file\n";
  }

  // Process the config file
  bool use_config = getProperty("UseConfig");
  if (use_config && config_file.size() > 0) {
    // Special case to force reading the beam center from the config file
    // We're adding this to be compatible with the original EQSANS load
    // written in python
    if (m_center_x == 0.0 && m_center_y == 0.0) {
      setProperty("UseConfigBeam", true);
    }

    readConfigFile(config_file);
  } else if (use_config) {
    use_config = false;
    g_log.error() << "Cound not find config file for workspace "
                  << getPropertyValue("OutputWorkspace") << '\n';
    m_output_message += "   Could not find configuration file for run " +
                        Poco::NumberFormatter::format(run_number) + "\n";
  }

  // If we use the config file, move the moderator position
  if (use_config) {
    if (m_moderator_position > -13.0)
      g_log.error()
          << "Moderator position seems close to the sample, please check\n";
    g_log.information() << "Moving moderator to " << m_moderator_position
                        << '\n';
    m_output_message += "   Moderator position: " +
                        Poco::NumberFormatter::format(m_moderator_position) +
                        " m\n";
    mvAlg = createChildAlgorithm("MoveInstrumentComponent", 0.4, 0.45);
    mvAlg->setProperty<MatrixWorkspace_sptr>("Workspace", dataWS);
    mvAlg->setProperty("ComponentName", "moderator");
    mvAlg->setProperty("Z", m_moderator_position);
    mvAlg->setProperty("RelativePosition", false);
    mvAlg->executeAsChildAlg();
  }

  // Get source aperture radius
  getSourceSlitSize();

  // Move the beam center to its proper position
  if (!noBeamCenter) {
    if (isEmpty(m_center_x) || isEmpty(m_center_y)) {
      if (reductionManager->existsProperty("LatestBeamCenterX") &&
          reductionManager->existsProperty("LatestBeamCenterY")) {
        m_center_x = reductionManager->getProperty("LatestBeamCenterX");
        m_center_y = reductionManager->getProperty("LatestBeamCenterY");
      }
    }
    moveToBeamCenter();

    // Add beam center to reduction properties, as the last beam center position
    // that was used.
    // This will give us our default position next time.
    if (!reductionManager->existsProperty("LatestBeamCenterX"))
      reductionManager->declareProperty(make_unique<PropertyWithValue<double>>(
          "LatestBeamCenterX", m_center_x));
    else
      reductionManager->setProperty("LatestBeamCenterX", m_center_x);
    if (!reductionManager->existsProperty("LatestBeamCenterY"))
      reductionManager->declareProperty(make_unique<PropertyWithValue<double>>(
          "LatestBeamCenterY", m_center_y));
    else
      reductionManager->setProperty("LatestBeamCenterY", m_center_y);
  }

  // Modify TOF
  const bool correct_for_flight_path = getProperty("CorrectForFlightPath");
  double wl_min = 0.0;
  double wl_max = 0.0;
  double wl_combined_max = 0.0;
  if (skipTOFCorrection) {
    m_output_message +=
        "    Skipping EQSANS TOF correction: assuming a single frame\n";
    dataWS->mutableRun().addProperty("is_frame_skipping", 0, true);
    if (correct_for_flight_path) {
      g_log.error() << "CorrectForFlightPath and SkipTOFCorrection can't be "
                       "set to true at the same time\n";
      m_output_message += "    Skipped flight path correction: see error log\n";
    }
  } else {
    m_output_message += "   Flight path correction ";
    if (!correct_for_flight_path)
      m_output_message += "NOT ";
    m_output_message += "applied\n";
    DataObjects::EventWorkspace_sptr dataWS_evt =
        boost::dynamic_pointer_cast<EventWorkspace>(dataWS);
    IAlgorithm_sptr tofAlg =
        createChildAlgorithm("EQSANSTofStructure", 0.5, 0.7);
    tofAlg->setProperty<EventWorkspace_sptr>("InputWorkspace", dataWS_evt);
    tofAlg->setProperty("LowTOFCut", m_low_TOF_cut);
    tofAlg->setProperty("HighTOFCut", m_high_TOF_cut);
    tofAlg->setProperty("FlightPathCorrection", correct_for_flight_path);
    tofAlg->executeAsChildAlg();
    wl_min = tofAlg->getProperty("WavelengthMin");
    wl_max = tofAlg->getProperty("WavelengthMax");
    if (wl_min != wl_min || wl_max != wl_max) {
      g_log.error() << "Bad wavelength range\n";
      g_log.error() << m_output_message << '\n';
    }

    const bool frame_skipping = tofAlg->getProperty("FrameSkipping");
    dataWS->mutableRun().addProperty("wavelength_min", wl_min, "Angstrom",
                                     true);
    dataWS->mutableRun().addProperty("wavelength_max", wl_max, "Angstrom",
                                     true);
    dataWS->mutableRun().addProperty("is_frame_skipping", int(frame_skipping),
                                     true);
    wl_combined_max = wl_max;
    m_output_message += "   Wavelength range: " +
                        Poco::NumberFormatter::format(wl_min) + " - " +
                        Poco::NumberFormatter::format(wl_max);
    if (frame_skipping) {
      const double wl_min2 = tofAlg->getProperty("WavelengthMinFrame2");
      const double wl_max2 = tofAlg->getProperty("WavelengthMaxFrame2");
      wl_combined_max = wl_max2;
      dataWS->mutableRun().addProperty("wavelength_min_frame2", wl_min2,
                                       "Angstrom", true);
      dataWS->mutableRun().addProperty("wavelength_max_frame2", wl_max2,
                                       "Angstrom", true);
      m_output_message += " and " + Poco::NumberFormatter::format(wl_min2) +
                          " - " + Poco::NumberFormatter::format(wl_max2) +
                          " Angstrom\n";
    } else
      m_output_message += " Angstrom\n";
  }

  // Convert to wavelength
  const double ssd =
      fabs(dataWS->getInstrument()->getSource()->getPos().Z()) * 1000.0;
  const double conversion_factor = 3.9560346 / (sdd + ssd);
  m_output_message += "   TOF to wavelength conversion factor: " +
                      Poco::NumberFormatter::format(conversion_factor) + "\n";

  if (skipTOFCorrection) {
    DataObjects::EventWorkspace_sptr dataWS_evt =
        boost::dynamic_pointer_cast<EventWorkspace>(dataWS);
    if (dataWS_evt->getNumberEvents() == 0)
      throw std::invalid_argument("No event to process: check your TOF cuts");
    wl_min = dataWS_evt->getTofMin() * conversion_factor;
    wl_max = dataWS_evt->getTofMax() * conversion_factor;
    wl_combined_max = wl_max;
    g_log.information() << "Wavelength range: " << wl_min << " to " << wl_max
                        << '\n';
    dataWS->mutableRun().addProperty("wavelength_min", wl_min, "Angstrom",
                                     true);
    dataWS->mutableRun().addProperty("wavelength_max", wl_max, "Angstrom",
                                     true);
  }

  IAlgorithm_sptr scAlg = createChildAlgorithm("ScaleX", 0.7, 0.71);
  scAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", dataWS);
  scAlg->setProperty<MatrixWorkspace_sptr>("OutputWorkspace", dataWS);
  scAlg->setProperty("Factor", conversion_factor);
  scAlg->executeAsChildAlg();
  dataWS->getAxis(0)->setUnit("Wavelength");

  // Rebin so all the wavelength bins are aligned
  const bool preserveEvents = getProperty("PreserveEvents");
  const double wl_step = getProperty("WavelengthStep");

  const double wl_min_rounded = round(wl_min * 100.0) / 100.0;
  const double wl_max_rounded = round(wl_combined_max * 100.0) / 100.0;
  std::string params = Poco::NumberFormatter::format(wl_min_rounded, 2) + "," +
                       Poco::NumberFormatter::format(wl_step) + "," +
                       Poco::NumberFormatter::format(wl_max_rounded, 2);
  g_log.information() << "Rebin parameters: " << params << '\n';
  IAlgorithm_sptr rebinAlg = createChildAlgorithm("Rebin", 0.71, 0.72);
  rebinAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", dataWS);
  if (preserveEvents)
    rebinAlg->setProperty<MatrixWorkspace_sptr>("OutputWorkspace", dataWS);
  rebinAlg->setPropertyValue("Params", params);
  rebinAlg->setProperty("PreserveEvents", preserveEvents);
  rebinAlg->executeAsChildAlg();

  if (!preserveEvents)
    dataWS = rebinAlg->getProperty("OutputWorkspace");

  dataWS->mutableRun().addProperty("event_ws",
                                   getPropertyValue("OutputWorkspace"), true);
  setProperty<MatrixWorkspace_sptr>(
      "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS));
  // m_output_message = "Loaded " + fileName + '\n' + m_output_message;
  setPropertyValue("OutputMessage", m_output_message);
}
コード例 #4
0
void SANSSensitivityCorrection::exec() {
  // Output log
  m_output_message = "";

  Progress progress(this, 0.0, 1.0, 10);

  // Reduction property manager
  const std::string reductionManagerName = getProperty("ReductionProperties");
  boost::shared_ptr<PropertyManager> reductionManager;
  if (PropertyManagerDataService::Instance().doesExist(reductionManagerName)) {
    reductionManager =
        PropertyManagerDataService::Instance().retrieve(reductionManagerName);
  } else {
    reductionManager = boost::make_shared<PropertyManager>();
    PropertyManagerDataService::Instance().addOrReplace(reductionManagerName,
                                                        reductionManager);
  }

  if (!reductionManager->existsProperty("SensitivityAlgorithm")) {
    auto algProp = make_unique<AlgorithmProperty>("SensitivityAlgorithm");
    algProp->setValue(toString());
    reductionManager->declareProperty(std::move(algProp));
  }

  progress.report("Loading sensitivity file");
  const std::string fileName = getPropertyValue("Filename");

  // Look for an entry for the dark current in the reduction table
  Poco::Path path(fileName);
  const std::string entryName = "Sensitivity" + path.getBaseName();
  MatrixWorkspace_sptr floodWS;
  std::string floodWSName = "__sensitivity_" + path.getBaseName();

  if (reductionManager->existsProperty(entryName)) {
    std::string wsName = reductionManager->getPropertyValue(entryName);
    floodWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsName));
    m_output_message += "   |Using " + wsName + "\n";
    g_log.debug()
        << "SANSSensitivityCorrection :: Using sensitivity workspace: "
        << wsName << "\n";
  } else {
    // Load the flood field if we don't have it already
    // First, try to determine whether we need to load data or a sensitivity
    // workspace...
    if (!floodWS && fileCheck(fileName)) {
      g_log.debug() << "SANSSensitivityCorrection :: Loading sensitivity file: "
                    << fileName << "\n";
      IAlgorithm_sptr loadAlg = createChildAlgorithm("Load", 0.1, 0.3);
      loadAlg->setProperty("Filename", fileName);
      loadAlg->executeAsChildAlg();
      Workspace_sptr floodWS_ws = loadAlg->getProperty("OutputWorkspace");
      floodWS = boost::dynamic_pointer_cast<MatrixWorkspace>(floodWS_ws);

      // Check that it's really a sensitivity file
      if (!floodWS->run().hasProperty("is_sensitivity")) {
        // Reset pointer
        floodWS.reset();
        g_log.error() << "A processed Mantid workspace was loaded but it "
                         "wasn't a sensitivity file!\n";
      }
    }

    // ... if we don't, just load the data and process it
    if (!floodWS) {
      // Read in default beam center
      double center_x = getProperty("BeamCenterX");
      double center_y = getProperty("BeamCenterY");
      if (isEmpty(center_x) || isEmpty(center_y)) {
        if (reductionManager->existsProperty("LatestBeamCenterX") &&
            reductionManager->existsProperty("LatestBeamCenterY")) {
          center_x = reductionManager->getProperty("LatestBeamCenterX");
          center_y = reductionManager->getProperty("LatestBeamCenterY");
          m_output_message +=
              "   |Setting beam center to [" +
              Poco::NumberFormatter::format(center_x, 1) + ", " +
              Poco::NumberFormatter::format(center_y, 1) + "]\n";
        } else
          m_output_message += "   |No beam center provided: skipping!\n";
      }

      const std::string rawFloodWSName = "__flood_data_" + path.getBaseName();
      MatrixWorkspace_sptr rawFloodWS;
      if (!reductionManager->existsProperty("LoadAlgorithm")) {
        IAlgorithm_sptr loadAlg = createChildAlgorithm("Load", 0.1, 0.3);
        loadAlg->setProperty("Filename", fileName);
        if (!isEmpty(center_x) && loadAlg->existsProperty("BeamCenterX"))
          loadAlg->setProperty("BeamCenterX", center_x);
        if (!isEmpty(center_y) && loadAlg->existsProperty("BeamCenterY"))
          loadAlg->setProperty("BeamCenterY", center_y);
        loadAlg->setPropertyValue("OutputWorkspace", rawFloodWSName);
        loadAlg->executeAsChildAlg();
        Workspace_sptr tmpWS = loadAlg->getProperty("OutputWorkspace");
        rawFloodWS = boost::dynamic_pointer_cast<MatrixWorkspace>(tmpWS);
        m_output_message += "   | Loaded " + fileName + " (Load algorithm)\n";
      } else {
        // Get load algorithm as a string so that we can create a completely
        // new proxy and ensure that we don't overwrite existing properties
        IAlgorithm_sptr loadAlg0 =
            reductionManager->getProperty("LoadAlgorithm");
        const std::string loadString = loadAlg0->toString();
        IAlgorithm_sptr loadAlg = Algorithm::fromString(loadString);
        loadAlg->setChild(true);
        loadAlg->setProperty("Filename", fileName);
        loadAlg->setPropertyValue("OutputWorkspace", rawFloodWSName);
        if (!isEmpty(center_x) && loadAlg->existsProperty("BeamCenterX"))
          loadAlg->setProperty("BeamCenterX", center_x);
        if (!isEmpty(center_y) && loadAlg->existsProperty("BeamCenterY"))
          loadAlg->setProperty("BeamCenterY", center_y);
        loadAlg->execute();
        rawFloodWS = loadAlg->getProperty("OutputWorkspace");
        m_output_message += "   |Loaded " + fileName + "\n";
        if (loadAlg->existsProperty("OutputMessage")) {
          std::string msg = loadAlg->getPropertyValue("OutputMessage");
          m_output_message +=
              "   |" + Poco::replace(msg, "\n", "\n   |") + "\n";
        }
      }

      // Check whether we just loaded a flood field data set, or the actual
      // sensitivity
      if (!rawFloodWS->run().hasProperty("is_sensitivity")) {
        const std::string darkCurrentFile = getPropertyValue("DarkCurrentFile");

        // Look for a dark current subtraction algorithm
        std::string dark_result;
        if (reductionManager->existsProperty("DarkCurrentAlgorithm")) {
          IAlgorithm_sptr darkAlg =
              reductionManager->getProperty("DarkCurrentAlgorithm");
          darkAlg->setChild(true);
          darkAlg->setProperty("InputWorkspace", rawFloodWS);
          darkAlg->setProperty("OutputWorkspace", rawFloodWS);

          // Execute as-is if we use the sample dark current, otherwise check
          // whether a dark current file was provided.
          // Otherwise do nothing
          if (getProperty("UseSampleDC")) {
            darkAlg->execute();
            if (darkAlg->existsProperty("OutputMessage"))
              dark_result = darkAlg->getPropertyValue("OutputMessage");
          } else if (!darkCurrentFile.empty()) {
            darkAlg->setProperty("Filename", darkCurrentFile);
            darkAlg->setProperty("PersistentCorrection", false);
            darkAlg->execute();
            if (darkAlg->existsProperty("OutputMessage"))
              dark_result = darkAlg->getPropertyValue("OutputMessage");
            else
              dark_result = "   Dark current subtracted\n";
          }
        } else if (!darkCurrentFile.empty()) {
          // We need to subtract the dark current for the flood field but no
          // dark
          // current subtraction was set for the sample! Use the default dark
          // current algorithm if we can find it.
          if (reductionManager->existsProperty("DefaultDarkCurrentAlgorithm")) {
            IAlgorithm_sptr darkAlg =
                reductionManager->getProperty("DefaultDarkCurrentAlgorithm");
            darkAlg->setChild(true);
            darkAlg->setProperty("InputWorkspace", rawFloodWS);
            darkAlg->setProperty("OutputWorkspace", rawFloodWS);
            darkAlg->setProperty("Filename", darkCurrentFile);
            darkAlg->setProperty("PersistentCorrection", false);
            darkAlg->execute();
            if (darkAlg->existsProperty("OutputMessage"))
              dark_result = darkAlg->getPropertyValue("OutputMessage");
          } else {
            // We are running out of options
            g_log.error() << "No dark current algorithm provided to load ["
                          << getPropertyValue("DarkCurrentFile")
                          << "]: skipped!\n";
            dark_result = "   No dark current algorithm provided: skipped\n";
          }
        }
        m_output_message +=
            "   |" + Poco::replace(dark_result, "\n", "\n   |") + "\n";

        // Look for solid angle correction algorithm
        if (reductionManager->existsProperty("SANSSolidAngleCorrection")) {
          IAlgorithm_sptr solidAlg =
              reductionManager->getProperty("SANSSolidAngleCorrection");
          solidAlg->setChild(true);
          solidAlg->setProperty("InputWorkspace", rawFloodWS);
          solidAlg->setProperty("OutputWorkspace", rawFloodWS);
          solidAlg->execute();
          std::string msg = "Solid angle correction applied\n";
          if (solidAlg->existsProperty("OutputMessage"))
            msg = solidAlg->getPropertyValue("OutputMessage");
          m_output_message +=
              "   |" + Poco::replace(msg, "\n", "\n   |") + "\n";
        }

        // Apply transmission correction as needed
        double floodTransmissionValue = getProperty("FloodTransmissionValue");
        double floodTransmissionError = getProperty("FloodTransmissionError");

        if (!isEmpty(floodTransmissionValue)) {
          g_log.debug() << "SANSSensitivityCorrection :: Applying transmission "
                           "to flood field\n";
          IAlgorithm_sptr transAlg =
              createChildAlgorithm("ApplyTransmissionCorrection");
          transAlg->setProperty("InputWorkspace", rawFloodWS);
          transAlg->setProperty("OutputWorkspace", rawFloodWS);
          transAlg->setProperty("TransmissionValue", floodTransmissionValue);
          transAlg->setProperty("TransmissionError", floodTransmissionError);
          transAlg->setProperty("ThetaDependent", true);
          transAlg->execute();
          rawFloodWS = transAlg->getProperty("OutputWorkspace");
          m_output_message += "   |Applied transmission to flood field\n";
        }

        // Calculate detector sensitivity
        IAlgorithm_sptr effAlg = createChildAlgorithm("CalculateEfficiency");
        effAlg->setProperty("InputWorkspace", rawFloodWS);

        const double minEff = getProperty("MinEfficiency");
        const double maxEff = getProperty("MaxEfficiency");
        const std::string maskFullComponent =
            getPropertyValue("MaskedFullComponent");
        const std::string maskEdges = getPropertyValue("MaskedEdges");
        const std::string maskComponent = getPropertyValue("MaskedComponent");

        effAlg->setProperty("MinEfficiency", minEff);
        effAlg->setProperty("MaxEfficiency", maxEff);
        effAlg->setProperty("MaskedFullComponent", maskFullComponent);
        effAlg->setProperty("MaskedEdges", maskEdges);
        effAlg->setProperty("MaskedComponent", maskComponent);
        effAlg->execute();
        floodWS = effAlg->getProperty("OutputWorkspace");
      } else {
        floodWS = rawFloodWS;
      }
      // Patch as needed
      if (reductionManager->existsProperty("SensitivityPatchAlgorithm")) {
        IAlgorithm_sptr patchAlg =
            reductionManager->getProperty("SensitivityPatchAlgorithm");
        patchAlg->setChild(true);
        patchAlg->setProperty("Workspace", floodWS);
        patchAlg->execute();
        m_output_message += "   |Sensitivity patch applied\n";
      }

      floodWS->mutableRun().addProperty("is_sensitivity", 1, "", true);
    }
    std::string floodWSOutputName =
        getPropertyValue("OutputSensitivityWorkspace");
    if (floodWSOutputName.empty()) {
      setPropertyValue("OutputSensitivityWorkspace", floodWSName);
      AnalysisDataService::Instance().addOrReplace(floodWSName, floodWS);
      reductionManager->declareProperty(
          Kernel::make_unique<WorkspaceProperty<>>(entryName, floodWSName,
                                                   Direction::InOut));
      reductionManager->setPropertyValue(entryName, floodWSName);
      reductionManager->setProperty(entryName, floodWS);
    }
    setProperty("OutputSensitivityWorkspace", floodWS);
  }

  progress.report(3, "Loaded flood field");

  // Check whether we need to apply the correction to a workspace
  MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
  if (inputWS) {
    // Divide sample data by detector efficiency
    IAlgorithm_sptr divideAlg = createChildAlgorithm("Divide", 0.6, 0.7);
    divideAlg->setProperty("LHSWorkspace", inputWS);
    divideAlg->setProperty("RHSWorkspace", floodWS);
    divideAlg->executeAsChildAlg();
    MatrixWorkspace_sptr outputWS = divideAlg->getProperty("OutputWorkspace");

    // Copy over the efficiency's masked pixels to the reduced workspace
    IAlgorithm_sptr maskAlg = createChildAlgorithm("MaskDetectors", 0.75, 0.85);
    maskAlg->setProperty("Workspace", outputWS);
    maskAlg->setProperty("MaskedWorkspace", floodWS);
    maskAlg->executeAsChildAlg();

    setProperty("OutputWorkspace", outputWS);
  }
  setProperty("OutputMessage",
              "Sensitivity correction computed\n" + m_output_message);

  progress.report("Performed sensitivity correction");
}