Skip to content
Snippets Groups Projects
EQSANSDarkCurrentSubtraction.cpp 7.8 KiB
Newer Older
Doucet, Mathieu's avatar
Doucet, Mathieu committed
#include "MantidWorkflowAlgorithms/EQSANSDarkCurrentSubtraction.h"
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/WorkspaceUnitValidator.h"
Doucet, Mathieu's avatar
Doucet, Mathieu committed
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidAPI/FileProperty.h"
Doucet, Mathieu's avatar
Doucet, Mathieu committed
#include "Poco/Path.h"
#include "Poco/String.h"
#include "MantidAPI/AlgorithmProperty.h"
#include "MantidKernel/PropertyManagerDataService.h"
#include "MantidKernel/PropertyManager.h"
namespace Mantid {
namespace WorkflowAlgorithms {
Doucet, Mathieu's avatar
Doucet, Mathieu committed

// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(EQSANSDarkCurrentSubtraction)

using namespace Kernel;
using namespace API;
using namespace Geometry;
using namespace DataObjects;

void EQSANSDarkCurrentSubtraction::init() {
  auto wsValidator = boost::make_shared<WorkspaceUnitValidator>("Wavelength");
  declareProperty(make_unique<WorkspaceProperty<>>(
      "InputWorkspace", "", Direction::Input, wsValidator));
  declareProperty(
      make_unique<API::FileProperty>("Filename", "", API::FileProperty::Load,
                                     "_event.nxs"),
Doucet, Mathieu's avatar
Doucet, Mathieu committed
      "The name of the input event Nexus file to load as dark current.");

  declareProperty(make_unique<WorkspaceProperty<>>("OutputWorkspace", "",
                                                   Direction::Output));
  declareProperty("PersistentCorrection", true,
                  "If true, the algorithm will be persistent and re-used when "
                  "other data sets are processed");
  declareProperty("ReductionProperties", "__sans_reduction_properties",
                  Direction::Input);
  declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>(
      "OutputDarkCurrentWorkspace", "", Direction::Output,
      PropertyMode::Optional));
  declareProperty("OutputMessage", "", Direction::Output);
void EQSANSDarkCurrentSubtraction::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) {
    auto algProp = make_unique<AlgorithmProperty>("DarkCurrentAlgorithm");
    algProp->setValue(toString());
    reductionManager->declareProperty(std::move(algProp));
  Progress progress(this, 0.0, 1.0, 10);
Doucet, Mathieu's avatar
Doucet, Mathieu committed

  MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");

  const std::string fileName = getPropertyValue("Filename");
  MatrixWorkspace_sptr darkWS;
Doucet, Mathieu's avatar
Doucet, Mathieu committed

  progress.report("Subtracting dark current");

  // Look for an entry for the dark current in the reduction table
Doucet, Mathieu's avatar
Doucet, Mathieu committed
  Poco::Path path(fileName);
  const std::string entryName = "DarkCurrent" + path.getBaseName();
  std::string darkWSName = "__dark_current_" + 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
    IAlgorithm_sptr loadAlg;
    if (!reductionManager->existsProperty("LoadAlgorithm")) {
      loadAlg = createChildAlgorithm("EQSANSLoad", 0.1, 0.3);
Doucet, Mathieu's avatar
Doucet, Mathieu committed
      loadAlg->setProperty("Filename", fileName);
      if (loadAlg->existsProperty("LoadMonitors"))
        loadAlg->setProperty("LoadMonitors", false);
      loadAlg->executeAsChildAlg();
      darkWS = loadAlg->getProperty("OutputWorkspace");
      // 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();
      loadAlg = Algorithm::fromString(loadString);
      loadAlg->setChild(true);
      loadAlg->setProperty("Filename", fileName);
      if (loadAlg->existsProperty("LoadMonitors"))
        loadAlg->setProperty("LoadMonitors", false);
      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";
    }

    std::string darkWSOutputName =
        getPropertyValue("OutputDarkCurrentWorkspace");
    if (!darkWSOutputName.empty())
      setProperty("OutputDarkCurrentWorkspace", darkWS);
    AnalysisDataService::Instance().addOrReplace(darkWSName, darkWS);
    reductionManager->declareProperty(Kernel::make_unique<WorkspaceProperty<>>(
        entryName, "", Direction::Output));
    reductionManager->setPropertyValue(entryName, darkWSName);
    reductionManager->setProperty(entryName, darkWS);
Doucet, Mathieu's avatar
Doucet, Mathieu committed
  }
  progress.report(3, "Loaded dark current");
Doucet, Mathieu's avatar
Doucet, Mathieu committed

  // Normalize the dark current and data to counting time
  double scaling_factor = 1.0;
  if (inputWS->run().hasProperty("proton_charge")) {
    auto dp = inputWS->run().getTimeSeriesProperty<double>("proton_charge");
    double duration = dp->getStatistics().duration;

    dp = darkWS->run().getTimeSeriesProperty<double>("proton_charge");
    double dark_duration = dp->getStatistics().duration;
    scaling_factor = duration / dark_duration;
  } else if (inputWS->run().hasProperty("timer")) {
    double duration = inputWS->run().getPropertyValueAsType<double>("timer");
    double dark_duration =
        darkWS->run().getPropertyValueAsType<double>("timer");
    ;
    scaling_factor = duration / dark_duration;
  } else {
    output_message +=
        "\n   Could not find proton charge or duration in sample logs";
    g_log.error()
Hahn, Steven's avatar
Hahn, Steven committed
        << "ERROR: Could not find proton charge or duration in sample logs\n";
  progress.report("Scaling dark current");
Doucet, Mathieu's avatar
Doucet, Mathieu committed

  // Scale the stored dark current by the counting time
  IAlgorithm_sptr rebinAlg = createChildAlgorithm("RebinToWorkspace", 0.4, 0.5);
Doucet, Mathieu's avatar
Doucet, Mathieu committed
  rebinAlg->setProperty("WorkspaceToRebin", darkWS);
Doucet, Mathieu's avatar
Doucet, Mathieu committed
  rebinAlg->setProperty("WorkspaceToMatch", inputWS);
  rebinAlg->setProperty("OutputWorkspace", darkWS);
  rebinAlg->executeAsChildAlg();
Doucet, Mathieu's avatar
Doucet, Mathieu committed
  MatrixWorkspace_sptr scaledDarkWS = rebinAlg->getProperty("OutputWorkspace");
Doucet, Mathieu's avatar
Doucet, Mathieu committed

  // Perform subtraction
  IAlgorithm_sptr scaleAlg = createChildAlgorithm("Scale", 0.5, 0.6);
  scaleAlg->setProperty("InputWorkspace", scaledDarkWS);
  scaleAlg->setProperty("Factor", scaling_factor);
  scaleAlg->setProperty("OutputWorkspace", scaledDarkWS);
  scaleAlg->setProperty("Operation", "Multiply");
  scaleAlg->executeAsChildAlg();
  scaledDarkWS = rebinAlg->getProperty("OutputWorkspace");
  IAlgorithm_sptr minusAlg = createChildAlgorithm("Minus", 0.6, 0.7);
  minusAlg->setProperty("LHSWorkspace", inputWS);
  minusAlg->setProperty("RHSWorkspace", scaledDarkWS);
  const std::string outputWSname = getPropertyValue("OutputWorkspace");
  minusAlg->setPropertyValue("OutputWorkspace", outputWSname);
  minusAlg->executeAsChildAlg();
  MatrixWorkspace_sptr outputWS = minusAlg->getProperty("OutputWorkspace");
Doucet, Mathieu's avatar
Doucet, Mathieu committed

  setProperty("OutputWorkspace", outputWS);
  setProperty("OutputMessage", "Dark current subtracted: " + output_message);
  progress.report("Subtracted dark current");
Doucet, Mathieu's avatar
Doucet, Mathieu committed
}

} // namespace WorkflowAlgorithms
} // namespace Mantid