Skip to content
Snippets Groups Projects
EditTOFPowderDiffractomerGeometry.cpp 7.94 KiB
Newer Older
/*WIKI*



This algorithm edits the diffractomer detectors' parameters




*WIKI*/

#include "MantidAlgorithms/EditTOFPowderDiffractomerGeometry.h"
#include "MantidAPI/IAlgorithm.h"
#include "MantidGeometry/IDetector.h"
#include "MantidAPI/ISpectrum.h"
#include "MantidKernel/System.h"
#include "MantidKernel/ArrayProperty.h"
using namespace Mantid::Kernel;
using namespace Mantid::API;

namespace Mantid
{
namespace Algorithms
{

  DECLARE_ALGORITHM(EditTOFPowderDiffractomerGeometry);
  //---------------------------------------------- ------------------------------------------------
  /** Constructor
   */
  EditTOFPowderDiffractomerGeometry::EditTOFPowderDiffractomerGeometry()
  {
    // TODO Auto-generated constructor stub
  }
    
  //----------------------------------------------------------------------------------------------
  /** Destructor
   */
  EditTOFPowderDiffractomerGeometry::~EditTOFPowderDiffractomerGeometry()
  {
    // TODO Auto-generated destructor stub
  }
  
  //----------------------------------------------------------------------------------------------
  /// Sets documentation strings for this algorithm
  void EditTOFPowderDiffractomerGeometry::initDocs()
  {
    this->setWikiSummary("Add and/or edit T.O.F. powder diffractomer instrument geometry information");
    this->setOptionalMessage("The edit or added information will be attached to a Workspace.  Currently it is in an overwrite mode only.");
  }

  //----------------------------------------------------------------------------------------------
  /** Initialize the algorithm's properties.
   */
  void EditTOFPowderDiffractomerGeometry::init()
  {
    declareProperty(new WorkspaceProperty<>("Workspace", "", Direction::InOut),
        "Workspace to edit the detector information");
    declareProperty("InstrumentName", "GenericPowder", "Name of the instrument. ");
    declareProperty("PrimaryFlightPath", -1.0);
    declareProperty(new ArrayProperty<int32_t>("SpectrumIDs", new MandatoryValidator<std::vector<int32_t> >),
        "Spectrum IDs (note that it is not detector ID or workspace indices).");
    declareProperty(new ArrayProperty<double>("L2", new MandatoryValidator<std::vector<double> >),
        "Seconary flight (L2) paths for each detector");
    declareProperty(new ArrayProperty<double>("Polar", new MandatoryValidator<std::vector<double> >),
        "Polar angles (two thetas) for detectors");
    declareProperty(new ArrayProperty<double>("Azimuthal", new MandatoryValidator<std::vector<double> >),
        "Azimuthal angles (out-of-plain) for detectors");
    declareProperty("NewInstrument", false, "Add detectors information from scratch");
  }

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

    // 1. Get Input
    MatrixWorkspace_sptr workspace = getProperty("Workspace");
    double l1 = this->getProperty("PrimaryFlightPath");
    const std::vector<int32_t> specids = this->getProperty("SpectrumIDs");
    const std::vector<double> l2s = this->getProperty("L2");
    const std::vector<double> tths = this->getProperty("Polar");
    const std::vector<double> phis = this->getProperty("Azimuthal");
    const bool newinstrument = getProperty("NewInstrument");
    bool userL1 = true;
      userL1 = false;
    } else {
      g_log.information() << "L1 = " << l1 << "  # Detector = " << std::endl;
    if (specids.size() != l2s.size() || l2s.size() != tths.size() || phis.size() != l2s.size()){
      throw std::invalid_argument("Input Spectrum, L2 (Secondary Flight Paths), Polar angles (Two Thetas) and Azimuthal have different items number");
    }

    for (size_t ib = 0; ib < l2s.size(); ib ++){
      g_log.information() << "Detector " << specids[ib] << "  L2 = " << l2s[ib] << "  2Theta = " << tths[ib] << std::endl;
      if (specids[ib] < 0){
        throw std::invalid_argument("Detector ID cannot be less than 0");
      }
      if (l2s[ib] <= 0.0){
        throw std::invalid_argument("L2 cannot be less or equal to 0");
      }
    }

    // 3. Generate a new instrument
    std::string name = "";
    if (newinstrument){
      std::string tempname = getProperty("InstrumentName");
      name += tempname;
    } else {
      name += workspace->getInstrument()->getName();
    //  Create a new instrument from scratch
    Geometry::Instrument_sptr instrument(new Geometry::Instrument(name));
      g_log.error("Trying to use a Parametrized Instrument as an Instrument.");
      throw std::runtime_error("Trying to use a Parametrized Instrument as an Instrument.");
    }

    // 4. Get information from original: L1
    double mL1;
    if (newinstrument){
      // use input L1
      mL1 = l1;
      if (l1 <= 0){
        g_log.error() << "Input L1 = " << l1 << "  < 0 Is Not Allowed!" << std::endl;
        throw std::invalid_argument("Input L1 is not allowed.");
      }
    } else {
      if (l1 > 0){
        mL1 = l1;
      } else {
        Kernel::V3D sourcepos = workspace->getInstrument()->getSource()->getPos();
        mL1 = sourcepos.Z()*-1;
        g_log.notice() << "source position = " << sourcepos.X() << ", " << sourcepos.Y() << ", " << sourcepos.Z() << std::endl;
      }
    // 5. Source and sample information
    Geometry::ObjComponent *samplepos = new Geometry::ObjComponent("Sample", instrument.get());
    instrument->add(samplepos);
    instrument->markAsSamplePos(samplepos);
    samplepos->setPos(0.0, 0.0, 0.0);

    Geometry::ObjComponent *source = new Geometry::ObjComponent("Source", instrument.get());
    instrument->add(source);
    instrument->markAsSource(source);
    source->setPos(0.0, 0.0, -1.0 * mL1);
    // 6. Keep original instrument and set the new instrument
    Geometry::Instrument_const_sptr oldinstrument = workspace->getInstrument();
    workspace->setInstrument(instrument);

    // 6. Add detector information
    spec2index_map * spec2indexmap = workspace->getSpectrumToWorkspaceIndexMap();
    for (size_t i = 0; i < specids.size(); i ++){
      // Create a new detector. Instrument will take ownership of pointer so no need to delete.
      Geometry::Detector *detector = new Geometry::Detector("det", specids[i]+100, samplepos);
      spec2index_map::iterator it = spec2indexmap->find(specids[i]);
      if (it == spec2indexmap->end()){
        g_log.error() << "Spectrum ID " << specids[i] << " is not found" << std::endl;
        continue;
      }
      size_t workspaceindex = it->second;
      g_log.notice() << "workspace index = " << workspaceindex << " is for Spectrum " << specids[i] << std::endl;

      Kernel::V3D pos;
      double l2 = l2s[i];
      double tth = tths[i];
      double phi = phis[i];
      pos.spherical(l2, tth, phi);
      double tl2, t2t, tph;
      detector->getPos().getSpherical(tl2, t2t, tph);
      g_log.notice() << "Detector Position (Input) = " << l2 << ", " << tth << ", " << phi << std::endl;
      g_log.notice() << "New Detector " << specids[i] << ":  L2, 2theta, phi = " << tl2 << ", " << t2t << ", " << tph << std::endl;

      // add copy to instrument and mark it
      API::ISpectrum *spectrum = workspace->getSpectrum(workspaceindex);
      if (!spectrum){
        g_log.error() << g_log.error() << "Spectrum ID " << specids[i] << " does not exist!  Skip setting detector parameters to this spectrum" << std::endl;
        continue;
      } else {
        g_log.notice() << "Raw: Spectrum " << specids[i] << ": # Detectors =  " << spectrum->getDetectorIDs().size() << std::endl;
      }

      spectrum->clearDetectorIDs();
      spectrum->addDetectorID(specids[i]+100);
      instrument->add(detector);
      instrument->markAsDetector(detector);

      // Check
      g_log.notice() << "New: Spectrum: " << specids[i] << ": # Detectros = " << spectrum->getDetectorIDs().size() << std::endl;


    } // for i

    delete spec2indexmap;

} // namespace Mantid
} // namespace Algorithms