Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ConvertToDiffractionMDWorkspace2.cpp 10.22 KiB
#include "MantidMDAlgorithms/ConvertToDiffractionMDWorkspace2.h"

#include "MantidAPI/IMDEventWorkspace.h"
#include "MantidAPI/Progress.h"
#include "MantidAPI/WorkspaceValidators.h"

#include "MantidDataObjects/EventWorkspace.h"
#include "MantidDataObjects/MDEventWorkspace.h"
#include "MantidDataObjects/Workspace2D.h"

#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/EnabledWhenProperty.h"
#include "MantidKernel/ListValidator.h"

#include "MantidMDAlgorithms/MDTransfFactory.h"
#include "MantidMDAlgorithms/MDWSTransform.h"

using namespace Mantid::API;
using namespace Mantid::Kernel;
using namespace Mantid::DataObjects;
using namespace Mantid::Geometry;

namespace Mantid {
namespace MDAlgorithms {

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

/**Small class to diable propery on interface */
class DisabledProperty : public EnabledWhenProperty {
public:
  DisabledProperty() : EnabledWhenProperty("NonExistingProperty", IS_DEFAULT) {}
  virtual bool fulfillsCriterion(const IPropertyManager * /*algo*/) const {
    return false;
  }
};

//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
 */
void ConvertToDiffractionMDWorkspace2::init() {

  declareProperty(new WorkspaceProperty<MatrixWorkspace>("InputWorkspace", "",
                                                         Direction::Input),
                  "An input workspace.");

  declareProperty(new WorkspaceProperty<IMDEventWorkspace>(
                      "OutputWorkspace", "", Direction::Output),
                  "Name of the output MDEventWorkspace. If the workspace "
                  "already exists, then the events will be added to it.");
  declareProperty(
      new PropertyWithValue<bool>("Append", false, Direction::Input),
      "Append events to the output workspace. The workspace is replaced if "
      "unchecked.");

  // Disabled for this version
  declareProperty(new PropertyWithValue<bool>("ClearInputWorkspace", false,
                                              Direction::Input),
                  "Clearing the events from the input workspace during "
                  "conversion (to save memory) is not supported by algorithm "
                  "v2");
  // disable property on interface
  this->setPropertySettings("ClearInputWorkspace", new DisabledProperty());

  declareProperty(
      new PropertyWithValue<bool>("OneEventPerBin", true, Direction::Input),
      "Use the histogram representation (event for event workspaces).\n"
      "One MDEvent will be created for each histogram bin (even empty ones).\n"
      "Warning! This can use signficantly more memory!");
  frameOptions.push_back("Q (sample frame)");
  frameOptions.push_back("Q (lab frame)");
  frameOptions.push_back("HKL");
  declareProperty(
      "OutputDimensions", "Q (lab frame)",
      boost::make_shared<StringListValidator>(frameOptions),
      "What will be the dimensions of the output workspace?\n"
      "  Q (lab frame): Wave-vector change of the lattice in the lab frame.\n"
      "  Q (sample frame): Wave-vector change of the lattice in the frame of "
      "the sample (taking out goniometer rotation).\n"
      "  HKL: Use the sample's UB matrix to convert to crystal's HKL indices.");

  declareProperty(
      new PropertyWithValue<bool>("LorentzCorrection", false, Direction::Input),
      "Correct the weights of events with by multiplying by the Lorentz "
      "formula: sin(theta)^2 / lambda^4");

  // Box controller properties. These are the defaults
  this->initBoxControllerProps("2" /*SplitInto*/, 1500 /*SplitThreshold*/,
                               20 /*MaxRecursionDepth*/);

  declareProperty(
      new PropertyWithValue<int>("MinRecursionDepth", 1),
      "Optional. If specified, then all the boxes will be split to this "
      "minimum recursion depth. 1 = one level of splitting, etc.\n"
      "Be careful using this since it can quickly create a huge number of "
      "boxes = (SplitInto ^ (MinRercursionDepth * NumDimensions)).\n"
      "But setting this property equal to MaxRecursionDepth property is "
      "necessary if one wants to generate multiple file based workspaces in "
      "order to merge them later\n");
  setPropertyGroup("MinRecursionDepth", getBoxSettingsGroupName());

  std::vector<double> extents(2, 0);
  extents[0] = -50;
  extents[1] = +50;
  declareProperty(new ArrayProperty<double>("Extents", extents),
                  "A comma separated list of min, max for each dimension,\n"
                  "specifying the extents of each dimension. Optional, default "
                  "+-50 in each dimension.");
  setPropertyGroup("Extents", getBoxSettingsGroupName());
}

/** method to convert the value of the target frame specified for the
  *ConvertToDiffractionMDWorksapce into the properties names of the ConvertToMD
  * @param  TargFrame -- the string, describing target transformation frame in
  *the form accepted by convertToDiffractionWorksapce
  * @param  TargFrameName -- the string describing target transformation frame
  *in the form acepted by convertToMD
  * @param  ScalingName    -- default coordinate scaling name accepted by
  *convertToMD;
  *
  *@return TargFrameName and ScalingName
*/
void ConvertToDiffractionMDWorkspace2::convertFramePropertyNames(
    const std::string &TargFrame, std::string &TargFrameName,
    std::string &ScalingName) {
  // ----------------- Handle the type of output
  // -------------------------------------

  MDAlgorithms::MDWSTransform QSclAndFrames;

  if (TargFrame == frameOptions[0]) // "Q (sample frame)"
  {
    TargFrameName =
        QSclAndFrames.getTargetFrame(MDAlgorithms::CnvrtToMD::SampleFrame);
    ScalingName = QSclAndFrames.getQScaling(
        MDAlgorithms::CnvrtToMD::NoScaling); //< momentums in A^-1
  } else if (TargFrame == frameOptions[1])   //     "Q (lab frame)"
  {
    TargFrameName =
        QSclAndFrames.getTargetFrame(MDAlgorithms::CnvrtToMD::LabFrame);
    ScalingName = QSclAndFrames.getQScaling(
        MDAlgorithms::CnvrtToMD::NoScaling); //< momentums in A^-1
  } else if (TargFrame == frameOptions[2])   // "HKL"
  {
    TargFrameName =
        QSclAndFrames.getTargetFrame(MDAlgorithms::CnvrtToMD::HKLFrame);
    ScalingName = QSclAndFrames.getQScaling(
        MDAlgorithms::CnvrtToMD::HKLScale); //< momentums in A^-1
  } else {
    throw std::invalid_argument(
        "ConvertToDiffractionMDWorkspace2::Unknown target frame: " + TargFrame);
  }
}
/** Splits extents accepted by convertToDiffreactionMD workspace in the form
 *min1,max1 or min1,max1,min2,max2,min3,max3
 *   into tso vectors min(3),max(3) accepted by convertToMD
 *  @param  Extents  -- the vector of extents consititing of 2 or 6 elements
 *  @param minVal   -- 3-vector of minimal values for 3 processed dimensions
 *  @param maxVal   -- 3-vector of maximal values for 3 processed dimensions
 *
 * @return minVal and maxVal -- two vectors with minimal and maximal values of
 *the momentums in the target workspace.
*/
void ConvertToDiffractionMDWorkspace2::convertExtents(
    const std::vector<double> &Extents, std::vector<double> &minVal,
    std::vector<double> &maxVal) const {
  minVal.resize(3);
  maxVal.resize(3);
  if (Extents.size() == 2) {
    for (size_t d = 0; d < 3; d++) {
      minVal[d] = Extents[0];
      maxVal[d] = Extents[1];
    }
  } else if (Extents.size() == 6) {
    for (size_t d = 0; d < 3; d++) {
      minVal[d] = Extents[2 * d + 0];
      maxVal[d] = Extents[2 * d + 1];
    }
  } else
    throw std::invalid_argument(
        "You must specify either 2 or 6 extents (min,max).");
}

//----------------------------------------------------------------------------------------------
/** Execute the algorithm.   */
void ConvertToDiffractionMDWorkspace2::exec() {

  Mantid::API::Algorithm_sptr Convert =
      createChildAlgorithm("ConvertToMD", 0., 1.);
  Convert->initialize();

  Convert->setRethrows(true);
  Convert->initialize();

  Convert->setProperty<MatrixWorkspace_sptr>(
      "InputWorkspace", this->getProperty("InputWorkspace"));
  Convert->setProperty("OutputWorkspace",
                       this->getPropertyValue("OutputWorkspace"));
  Convert->setProperty("OverwriteExisting", !this->getProperty("Append"));

  if (!MDTransfFactory::Instance().exists("Q3D")) {
    throw std::runtime_error(" ConvertToMD Q3D plugin used to transform into "
                             "DiffractionWorkspaced has not been registered "
                             "with the MDTransformation factory");
  }
  Convert->setPropertyValue("QDimensions", "Q3D");

  std::vector<std::string> dE_modes = Kernel::DeltaEMode::availableTypes();
  Convert->setPropertyValue("dEAnalysisMode",
                            dE_modes[Kernel::DeltaEMode::Elastic]);

  std::string TargetFrame, Scaling;
  this->convertFramePropertyNames(this->getPropertyValue("OutputDimensions"),
                                  TargetFrame, Scaling);
  Convert->setProperty("Q3DFrames", TargetFrame);
  Convert->setProperty("QConversionScales", Scaling);

  Convert->setProperty("OtherDimensions", "");
  Convert->setProperty("PreprocDetectorsWS", "-");

  bool lorCorr = this->getProperty("LorentzCorrection");
  Convert->setProperty("LorentzCorrection", lorCorr);

  bool ignoreZeros = !this->getProperty("OneEventPerBin");
  Convert->setProperty("IgnoreZeroSignals", ignoreZeros);
  // set extents
  std::vector<double> extents = this->getProperty("Extents");
  std::vector<double> minVal, maxVal;
  convertExtents(extents, minVal, maxVal);
  Convert->setProperty("MinValues", minVal);
  Convert->setProperty("MaxValues", maxVal);

  // Box controller properties. Has defaults
  Convert->setProperty("SplitInto", this->getPropertyValue("SplitInto"));
  Convert->setProperty("SplitThreshold",
                       this->getPropertyValue("SplitThreshold"));
  Convert->setProperty("MaxRecursionDepth",
                       this->getPropertyValue("MaxRecursionDepth"));
  std::string depth = this->getPropertyValue("MinRecursionDepth");
  if (depth == "0")
    depth = "1"; // ConvertToMD does not understand 0 depth
  Convert->setProperty("MinRecursionDepth", depth);

  Convert->executeAsChildAlg();

  IMDEventWorkspace_sptr iOut = Convert->getProperty("OutputWorkspace");
  this->setProperty("OutputWorkspace", iOut);
}

} // namespace Mantid
} // namespace DataObjects