Skip to content
Snippets Groups Projects
CarpenterSampleCorrection.cpp 6.71 KiB
Newer Older
#include "MantidAlgorithms/CarpenterSampleCorrection.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/InstrumentValidator.h"
#include "MantidAPI/Sample.h"
#include "MantidAPI/SpectrumInfo.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/WorkspaceUnitValidator.h"
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidGeometry/Instrument.h"
#include "MantidGeometry/IComponent.h"
#include "MantidKernel/CompositeValidator.h"
#include "MantidKernel/Material.h"
#include "MantidKernel/PhysicalConstants.h"

#include <stdexcept>

namespace Mantid {
namespace Algorithms {
DECLARE_ALGORITHM(CarpenterSampleCorrection) // Register the class
                                             // into the algorithm
                                             // factory

using namespace Kernel;
using namespace API;
using Mantid::DataObjects::EventList;
using Mantid::DataObjects::EventWorkspace;
using Mantid::DataObjects::EventWorkspace_sptr;
using Mantid::DataObjects::WeightedEventNoTime;
using Mantid::HistogramData::HistogramX;
using Mantid::HistogramData::HistogramY;
using Mantid::HistogramData::HistogramE;
using std::vector;
using namespace Mantid::PhysicalConstants;
using namespace Geometry;

// Constants required internally only, so make them static. These are
// Chebyshev expansion coefficients copied directly from Carpenter 1969 Table 1
// clang-format off
const std::string CarpenterSampleCorrection::name() const {
  return "CarpenterSampleCorrection";
}

int CarpenterSampleCorrection::version() const { return 1; }

const std::string CarpenterSampleCorrection::category() const {
  return "CorrectionFunctions\\AbsorptionCorrections";
}

/**
 * Initialize the properties to default values
 */
void CarpenterSampleCorrection::init() {
  // The input workspace must have an instrument and units of wavelength
  auto wsValidator = boost::make_shared<CompositeValidator>();
  wsValidator->add<WorkspaceUnitValidator>("Wavelength");
  wsValidator->add<InstrumentValidator>();

  declareProperty(make_unique<WorkspaceProperty<API::MatrixWorkspace> >(
                      "InputWorkspace", "", Direction::Input, wsValidator),
                  "The name of the input workspace.");
  declareProperty(make_unique<WorkspaceProperty<API::MatrixWorkspace> >(
                      "OutputWorkspace", "", Direction::Output),
                  "The name of the output workspace.");

  declareProperty("AttenuationXSection", 2.8, "Coefficient 1, absorption cross "
                                              "section / 1.81 if not set with "
                                              "SetSampleMaterial");
  declareProperty("ScatteringXSection", 5.1, "Coefficient 3, total scattering "
                                             "cross section if not set with "
                                             "SetSampleMaterial");
  declareProperty("SampleNumberDensity", 0.0721,
                  "Coefficient 2, density if not set with SetSampleMaterial");
  declareProperty("CylinderSampleRadius", 0.3175, "Sample radius, in cm");
}

/**
 * Execute the algorithm
 */
void CarpenterSampleCorrection::exec() {
  // common information
  MatrixWorkspace_sptr inputWksp = getProperty("InputWorkspace");
  double radius = getProperty("CylinderSampleRadius");
  double coeff1 = getProperty("AttenuationXSection");
  double coeff2 = getProperty("SampleNumberDensity");
  double coeff3 = getProperty("ScatteringXSection");

  // Calculate the absorption and multiple scattering corrections
  WorkspaceGroup_sptr calcOutput = calculateCorrection(
      inputWksp, radius, coeff1, coeff2, coeff3, true, true);
  Workspace_sptr absPtr = calcOutput->getItem(0);
  Workspace_sptr msPtr = calcOutput->getItem(1);
  auto absWksp = boost::dynamic_pointer_cast<MatrixWorkspace>(absPtr);
  auto msWksp = boost::dynamic_pointer_cast<MatrixWorkspace>(msPtr);

  // Clone input -> to apply corrections
  MatrixWorkspace_sptr outputWksp = getProperty("OutputWorkspace");

  EventWorkspace_sptr inputWkspEvent =
      boost::dynamic_pointer_cast<EventWorkspace>(inputWksp);

  outputWksp = inputWksp->clone();

  // Apply the absorption correction to the sample workspace
  outputWksp = divide(outputWksp, absWksp);

  // Apply the multiple scattering correction to the sample workspace
  auto factorWksp = multiply(inputWksp, msWksp);
  outputWksp = minus(outputWksp, factorWksp);

  // Output workspace
  if (inputWkspEvent) {
    auto outputWkspEvent =
        boost::dynamic_pointer_cast<EventWorkspace>(outputWksp);
    setProperty("OutputWorkspace", outputWkspEvent);
  }
  setProperty("OutputWorkspace", outputWksp);
}

WorkspaceGroup_sptr CarpenterSampleCorrection::calculateCorrection(
    MatrixWorkspace_sptr &inputWksp, double radius, double coeff1,
    double coeff2, double coeff3, bool doAbs, bool doMS) {
  auto calculate =
      this->createChildAlgorithm("CalculateCarpenterSampleCorrection");
  calculate->initialize();
  calculate->setProperty("InputWorkspace", inputWksp);
  calculate->setProperty("CylinderSampleRadius", radius);
  calculate->setProperty("AttenuationXSection", coeff1);
  calculate->setProperty("SampleNumberDensity", coeff2);
  calculate->setProperty("ScatteringXSection", coeff3);
  calculate->setProperty("Absorption", doAbs);
  calculate->setProperty("MultipleScattering", doMS);
  calculate->execute();
  WorkspaceGroup_sptr calcOutput =
      calculate->getProperty("OutputWorkspaceBaseName");
  return calcOutput;
}

MatrixWorkspace_sptr
CarpenterSampleCorrection::divide(const MatrixWorkspace_sptr lhsWS,
                                  const MatrixWorkspace_sptr rhsWS) {
  IAlgorithm_sptr divide = this->createChildAlgorithm("Divide");
  divide->initialize();
  divide->setProperty("LHSWorkspace", lhsWS);
  divide->setProperty("RHSWorkspace", rhsWS);
  divide->execute();
  MatrixWorkspace_sptr outWS = divide->getProperty("OutputWorkspace");
  return outWS;
}

MatrixWorkspace_sptr
CarpenterSampleCorrection::multiply(const MatrixWorkspace_sptr lhsWS,
                                    const MatrixWorkspace_sptr rhsWS) {
  auto multiply = this->createChildAlgorithm("Multiply");
  multiply->initialize();
  multiply->setProperty("LHSWorkspace", lhsWS);
  multiply->setProperty("RHSWorkspace", rhsWS);
  multiply->execute();
  MatrixWorkspace_sptr outWS = multiply->getProperty("OutputWorkspace");
  return outWS;
}

MatrixWorkspace_sptr
CarpenterSampleCorrection::minus(const MatrixWorkspace_sptr lhsWS,
                                 const MatrixWorkspace_sptr rhsWS) {
  auto minus = this->createChildAlgorithm("Minus");
  minus->initialize();
  minus->setProperty("LHSWorkspace", lhsWS);
  minus->setProperty("RHSWorkspace", rhsWS);
  minus->execute();
  MatrixWorkspace_sptr outWS = minus->getProperty("OutputWorkspace");
  return outWS;
}

} // namespace Algorithm
} // namespace Mantid