コード例 #1
0
ファイル: PeaksOnSurface.cpp プロジェクト: spaceyatom/mantid
bool lineIntersectsSphere(const V3D &line, const V3D &lineStart,
                          const V3D &peakCenter, const double peakRadius) {
  V3D peakToStart = peakCenter - lineStart;
  V3D unitLine = line;
  unitLine.normalize();
  double proj = peakToStart.scalar_prod(unitLine); // All we are doing here is
                                                   // projecting the peak to
                                                   // segment start vector onto
                                                   // the segment itself.

  V3D closestPointOnSegment;
  if (proj <= 0) // The projection is outside the segment. So use the start
                 // point of the segment.
  {
    closestPointOnSegment = lineStart; // Start of line
  } else if (proj >= line.norm()) // The projection is greater than the segment
                                  // length. So use the end point of the
                                  // segment.
  {
    closestPointOnSegment = lineStart + line; // End of line.
  } else // The projection falls somewhere between the start and end of the line
         // segment.
  {
    V3D projectionVector = unitLine * proj;
    closestPointOnSegment = projectionVector + lineStart;
  }

  return (peakCenter - closestPointOnSegment).norm() <= peakRadius;
}
コード例 #2
0
/**
  Determines if this,B,C are collinear
  @param Bv :: Vector to test
  @param Cv :: Vector to test
  @return false is no colinear and true if they are (within Ptolerance)
*/
bool
V3D::coLinear(const V3D& Bv,const V3D& Cv) const
{
  const V3D& Av=*this;
  const V3D Tmp((Bv-Av).cross_prod(Cv-Av));
  return (Tmp.norm()>Tolerance) ? false : true;
}
コード例 #3
0
ファイル: FilterStates.hpp プロジェクト: raghavkhanna/rovio
 /** \brief Initializes the FilterState \ref Base::state_ with the Acceleration-Vector.
  *
  *  @param fMeasInit - Acceleration-Vector which should be used for initializing the attitude of the IMU.
  */
 void initWithAccelerometer(const V3D& fMeasInit){
   V3D unitZ(0,0,1);
   if(fMeasInit.norm()>1e-6){
     state_.qWM().setFromVectors(unitZ,fMeasInit);
   } else {
     state_.qWM().setIdentity();
   }
 }
コード例 #4
0
ファイル: V3D.cpp プロジェクト: Mantid-Test-Account/mantid
/** Calculates the angle between this and another vector.
 *
 *  @param v :: The other vector
 *  @return The angle between the vectors in radians (0 < theta < pi)
 */
double V3D::angle(const V3D &v) const {
  double ratio = this->scalar_prod(v) / (this->norm() * v.norm());

  if (ratio >= 1.0)       // NOTE: Due to rounding errors, if v is
    return 0.0;           //       is nearly the same as "this" or
  else if (ratio <= -1.0) //       as "-this", ratio can be slightly
    return M_PI;          //       more than 1 in absolute value.
                          //       That causes acos() to return NaN.
  return acos(ratio);
}
コード例 #5
0
ファイル: FeatureOutput.hpp プロジェクト: BastianJaeger/rovio
  void jacTransform(MXD& J, const mtInput& input) const{
    J.setZero();
    const int& camID = input.CfP(ID_).camID_;
    if(camID != outputCamID_){
      input.updateMultiCameraExtrinsics(mpMultiCamera_);
      const QPD qDC = input.qCM(outputCamID_)*input.qCM(camID).inverted(); // TODO: avoid double computation
      const V3D CrCD = input.qCM(camID).rotate(V3D(input.MrMC(outputCamID_)-input.MrMC(camID)));
      const V3D CrCP = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getVec();
      const V3D DrDP = qDC.rotate(V3D(CrCP-CrCD));
      const double d_out = DrDP.norm();
      const LWF::NormalVectorElement nor_out(DrDP); // TODO: test if Jacobian works, this new setting of vector is dangerous

      const Eigen::Matrix<double,1,3> J_d_DrDP = nor_out.getVec().transpose();
      const Eigen::Matrix<double,2,3> J_nor_DrDP = nor_out.getM().transpose()/d_out;
      const Eigen::Matrix<double,3,3> J_DrDP_qDC = gSM(DrDP);
      const Eigen::Matrix<double,3,3> J_DrDP_CrCP = MPD(qDC).matrix();
      const Eigen::Matrix<double,3,3> J_DrDP_CrCD = -MPD(qDC).matrix();

      const Eigen::Matrix<double,3,3> J_qDC_qDB = Eigen::Matrix3d::Identity();
      const Eigen::Matrix<double,3,3> J_qDC_qCB = -MPD(qDC).matrix();
      const Eigen::Matrix<double,3,3> J_CrCD_qCB = gSM(CrCD);
      const Eigen::Matrix<double,3,3> J_CrCD_BrBC = -MPD(input.qCM(camID)).matrix();
      const Eigen::Matrix<double,3,3> J_CrCD_BrBD = MPD(input.qCM(camID)).matrix();

      const Eigen::Matrix<double,3,1> J_CrCP_d = input.CfP(ID_).get_nor().getVec()*input.dep(ID_).getDistanceDerivative();
      const Eigen::Matrix<double,3,2> J_CrCP_nor = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getM();

      J.template block<2,2>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)) = J_nor_DrDP*J_DrDP_CrCP*J_CrCP_nor;
      J.template block<2,1>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)+2) = J_nor_DrDP*J_DrDP_CrCP*J_CrCP_d;
      if(!ignoreDistanceOutput_){
        J.template block<1,2>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)) = J_d_DrDP*J_DrDP_CrCP*J_CrCP_nor;
        J.template block<1,1>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)+2) = J_d_DrDP*J_DrDP_CrCP*J_CrCP_d;
      }

      if(input.aux().doVECalibration_ && camID != outputCamID_){
        J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vea>(camID)) = J_nor_DrDP*(J_DrDP_qDC*J_qDC_qCB+J_DrDP_CrCD*J_CrCD_qCB);
        J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vea>(outputCamID_)) = J_nor_DrDP*J_DrDP_qDC*J_qDC_qDB;
        J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vep>(camID)) = J_nor_DrDP*J_DrDP_CrCD*J_CrCD_BrBC;
        J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vep>(outputCamID_)) = J_nor_DrDP*J_DrDP_CrCD*J_CrCD_BrBD;
        if(!ignoreDistanceOutput_){
          J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vea>(camID)) = J_d_DrDP*(J_DrDP_qDC*J_qDC_qCB+J_DrDP_CrCD*J_CrCD_qCB);
          J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vea>(outputCamID_)) = J_d_DrDP*J_DrDP_qDC*J_qDC_qDB;
          J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vep>(camID)) = J_d_DrDP*J_DrDP_CrCD*J_CrCD_BrBC;
          J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vep>(outputCamID_)) = J_d_DrDP*J_DrDP_CrCD*J_CrCD_BrBD;
        }
      }
    } else {
      J.template block<2,2>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)) = Eigen::Matrix2d::Identity();
      J.template block<1,1>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)+2) = Eigen::Matrix<double,1,1>::Identity();
    }
  }
コード例 #6
0
/**
 * Provide the collimation length which is associated with the instrument
 * @param workspace: the input workspace
 * @returns the collimation length
 */
double SANSCollimationLengthEstimator::provideCollimationLength(
    Mantid::API::MatrixWorkspace_sptr workspace) {
  // If the instrument does not have a correction specified then set the length
  // to 4
  const double defaultLColim = 4.0;
  auto collimationLengthID = "collimation-length-correction";

  if (!workspace->getInstrument()->hasParameter(collimationLengthID)) {
    g_log.error("Error in SANSCollimtionLengthEstimator: The instrument "
                "parameter file does not contain a collimation length "
                "correction,"
                "a default of 4 is provided. Please update the instrument "
                "parameter file.");
    return defaultLColim;
  }

  // Get the L1 length
  const V3D samplePos = workspace->getInstrument()->getSample()->getPos();
  const V3D sourcePos = workspace->getInstrument()->getSource()->getPos();
  const V3D SSD = samplePos - sourcePos;
  const double L1 = SSD.norm();

  auto collimationLengthCorrection =
      workspace->getInstrument()->getNumberParameter(collimationLengthID);

  if (workspace->getInstrument()->hasParameter(
          "special-default-collimation-length-method")) {
    auto specialCollimationMethod =
        workspace->getInstrument()->getStringParameter(
            "special-default-collimation-length-method");
    if (specialCollimationMethod[0] == "guide") {
      try {
        return getCollimationLengthWithGuides(workspace, L1,
                                              collimationLengthCorrection[0]);
      } catch (std::invalid_argument &ex) {
        g_log.notice() << ex.what();
        g_log.notice()
            << "SANSCollimationLengthEstimator: Not using any guides";
        return L1 - collimationLengthCorrection[0];
      }
    } else {
      throw std::invalid_argument("Error in SANSCollimationLengthEstimator: "
                                  "Unknown special collimation method.");
    }
  }
  return L1 - collimationLengthCorrection[0];
}
コード例 #7
0
ファイル: FeatureOutput.hpp プロジェクト: BastianJaeger/rovio
 void evalTransform(mtOutput& output, const mtInput& input) const{
   input.updateMultiCameraExtrinsics(mpMultiCamera_);
   mpMultiCamera_->transformFeature(outputCamID_,input.CfP(ID_),input.dep(ID_),output.c(),output.d());
   if(input.CfP(ID_).trackWarping_ && input.CfP(ID_).com_warp_nor()){
     const int& camID = input.CfP(ID_).camID_;
     const QPD qDC = input.qCM(outputCamID_)*input.qCM(camID).inverted(); // TODO: avoid double computation
     const V3D CrCD = input.qCM(camID).rotate(V3D(input.MrMC(outputCamID_)-input.MrMC(camID)));
     const V3D CrCP = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getVec();
     const V3D DrDP = qDC.rotate(V3D(CrCP-CrCD));
     const double d_out = DrDP.norm();
     const LWF::NormalVectorElement nor_out(DrDP);
     const Eigen::Matrix<double,2,3> J_nor_DrDP = nor_out.getM().transpose()/d_out;
     const Eigen::Matrix<double,3,3> J_DrDP_CrCP = MPD(qDC).matrix();
     const Eigen::Matrix<double,3,2> J_CrCP_nor = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getM();
     output.c().set_warp_nor(J_nor_DrDP*J_DrDP_CrCP*J_CrCP_nor*input.CfP(ID_).get_warp_nor());
   }
 }
コード例 #8
0
ファイル: Integrate3DEvents.cpp プロジェクト: BigShows/mantid
/**
 * Add an event to the appropriate vector of events for the closest h,k,l,
 * if it is within the required radius of the corresponding peak in the
 * PeakQMap.
 *
 * NOTE: The event passed in may be modified by this method.  In particular,
 * if it corresponds to one of the specified peak_qs, the corresponding peak q
 * will be subtracted from the event and the event will be added to that 
 * peak's vector in the event_lists map.  
 *
 * @param event_Q      The Q-vector for the event that may be added to the
 *                     event_lists map, if it is close enough to some peak
 */
void Integrate3DEvents::addEvent( V3D event_Q )
{
  int64_t hkl_key = getHklKey( event_Q );

  if ( hkl_key == 0 )      // don't keep events associated with 0,0,0
    return;

  V3D peak_q = peak_qs[hkl_key];
  if ( ! peak_q.nullVector() )
  {
    event_Q = event_Q - peak_q;
    if ( event_Q.norm() < radius )
    {
      event_lists[ hkl_key ].push_back( event_Q );
    }
  }
}
コード例 #9
0
/**
 * Builds a map based on the given number of neighbours
 * @param noNeighbours :: The number of nearest neighbours to use to build
 * the graph
 */
void NearestNeighbours::build(const int noNeighbours) {
  std::map<specid_t, IDetector_const_sptr> spectraDets =
      getSpectraDetectors(m_instrument, m_spectraMap);
  if (spectraDets.empty()) {
    throw std::runtime_error(
        "NearestNeighbours::build - Cannot find any spectra");
  }
  const int nspectra =
      static_cast<int>(spectraDets.size()); // ANN only deals with integers
  if (noNeighbours >= nspectra) {
    throw std::invalid_argument(
        "NearestNeighbours::build - Invalid number of neighbours");
  }

  // Clear current
  m_graph.clear();
  m_specToVertex.clear();
  m_noNeighbours = noNeighbours;

  BoundingBox bbox;
  // Base the scaling on the first detector, should be adequate but we can look
  // at this
  IDetector_const_sptr firstDet = (*spectraDets.begin()).second;
  firstDet->getBoundingBox(bbox);
  m_scale.reset(new V3D(bbox.width()));
  ANNpointArray dataPoints = annAllocPts(nspectra, 3);
  MapIV pointNoToVertex;

  std::map<specid_t, IDetector_const_sptr>::const_iterator detIt;
  int pointNo = 0;
  for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) {
    IDetector_const_sptr detector = detIt->second;
    const specid_t spectrum = detIt->first;
    V3D pos = detector->getPos() / (*m_scale);
    dataPoints[pointNo][0] = pos.X();
    dataPoints[pointNo][1] = pos.Y();
    dataPoints[pointNo][2] = pos.Z();
    Vertex vertex = boost::add_vertex(spectrum, m_graph);
    pointNoToVertex[pointNo] = vertex;
    m_specToVertex[spectrum] = vertex;
    ++pointNo;
  }

  ANNkd_tree *annTree = new ANNkd_tree(dataPoints, nspectra, 3);
  pointNo = 0;
  // Run the nearest neighbour search on each detector, reusing the arrays
  ANNidxArray nnIndexList = new ANNidx[m_noNeighbours];
  ANNdistArray nnDistList = new ANNdist[m_noNeighbours];

  for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) {
    ANNpoint scaledPos = dataPoints[pointNo];
    annTree->annkSearch(scaledPos,      // Point to search nearest neighbours of
                        m_noNeighbours, // Number of neighbours to find (8)
                        nnIndexList,    // Index list of results
                        nnDistList,     // List of distances to each of these
                        0.0 // Error bound (?) is this the radius to search in?
                        );
    // The distances that are returned are in our scaled coordinate
    // system. We store the real space ones.
    V3D realPos = V3D(scaledPos[0], scaledPos[1], scaledPos[2]) * (*m_scale);
    for (int i = 0; i < m_noNeighbours; i++) {
      ANNidx index = nnIndexList[i];
      V3D neighbour = V3D(dataPoints[index][0], dataPoints[index][1],
                          dataPoints[index][2]) *
                      (*m_scale);
      V3D distance = neighbour - realPos;
      double separation = distance.norm();
      boost::add_edge(m_specToVertex[detIt->first], // from
                      pointNoToVertex[index],       // to
                      distance, m_graph);
      if (separation > m_cutoff) {
        m_cutoff = separation;
      }
    }
    pointNo++;
  }
  delete[] nnIndexList;
  delete[] nnDistList;
  delete annTree;
  annDeallocPts(dataPoints);
  annClose();
  pointNoToVertex.clear();

  m_vertexID = get(boost::vertex_name, m_graph);
  m_edgeLength = get(boost::edge_name, m_graph);
}
コード例 #10
0
/** Calculates the angle between this and another vector.
 *
 *  @param v :: The other vector
 *  @return The angle between the vectors in radians (0 < theta < pi)
 */
double V3D::angle(const V3D& v) const
{
  return acos( this->scalar_prod(v) / (this->norm() * v.norm()) );
}
コード例 #11
0
void ConvertToDiffractionMDWorkspace::convertEventList(int workspaceIndex,
                                                       EventList &el) {
  size_t numEvents = el.getNumberEvents();
  DataObjects::MDBoxBase<DataObjects::MDLeanEvent<3>, 3> *box = ws->getBox();

  // Get the position of the detector there.
  const std::set<detid_t> &detectors = el.getDetectorIDs();
  if (!detectors.empty()) {
    // Get the detector (might be a detectorGroup for multiple detectors)
    // or might return an exception if the detector is not in the instrument
    // definition
    IDetector_const_sptr det;
    try {
      det = m_inWS->getDetector(workspaceIndex);
    } catch (Exception::NotFoundError &) {
      this->failedDetectorLookupCount++;
      return;
    }

    // Vector between the sample and the detector
    V3D detPos = det->getPos() - samplePos;

    // Neutron's total travelled distance
    double distance = detPos.norm() + l1;

    // Detector direction normalized to 1
    V3D detDir = detPos / detPos.norm();

    // The direction of momentum transfer in the inelastic convention ki-kf
    //  = input beam direction (normalized to 1) - output beam direction
    //  (normalized to 1)
    V3D Q_dir_lab_frame = beamDir - detDir;
    double qSign = -1.0;
    std::string convention =
        ConfigService::Instance().getString("Q.convention");
    if (convention == "Crystallography")
      qSign = 1.0;
    Q_dir_lab_frame *= qSign;

    // Multiply by the rotation matrix to convert to Q in the sample frame (take
    // out goniometer rotation)
    // (or to HKL, if that's what the matrix is)
    V3D Q_dir = mat * Q_dir_lab_frame;

    // For speed we extract the components.
    coord_t Q_dir_x = coord_t(Q_dir.X());
    coord_t Q_dir_y = coord_t(Q_dir.Y());
    coord_t Q_dir_z = coord_t(Q_dir.Z());

    // For lorentz correction, calculate  sin(theta))^2
    double sin_theta_squared = 0;
    if (LorentzCorrection) {
      // Scattering angle = 2 theta = angle between neutron beam direction and
      // the detector (scattering) direction
      // The formula for Lorentz Correction is sin(theta), i.e. sin(half the
      // scattering angle)
      double theta = detDir.angle(beamDir) / 2.0;
      sin_theta_squared = sin(theta);
      sin_theta_squared = sin_theta_squared * sin_theta_squared; // square it
    }

    /** Constant that you divide by tof (in usec) to get wavenumber in ang^-1 :
     * Wavenumber (in ang^-1) =  (PhysicalConstants::NeutronMass * distance) /
     * ((tof (in usec) * 1e-6) * PhysicalConstants::h_bar) * 1e-10; */
    const double wavenumber_in_angstrom_times_tof_in_microsec =
        (PhysicalConstants::NeutronMass * distance * 1e-10) /
        (1e-6 * PhysicalConstants::h_bar);

    // PARALLEL_CRITICAL( convert_tester_output ) { std::cout << "Spectrum " <<
    // el.getSpectrumNo() << " beamDir = " << beamDir << " detDir = " << detDir
    // << " Q_dir = " << Q_dir << " conversion factor " <<
    // wavenumber_in_angstrom_times_tof_in_microsec << std::endl;  }

    // g_log.information() << wi << " : " << el.getNumberEvents() << " events.
    // Pos is " << detPos << std::endl;
    // g_log.information() << Q_dir.norm() << " Qdir norm" << std::endl;

    // This little dance makes the getting vector of events more general (since
    // you can't overload by return type).
    typename std::vector<T> *events_ptr;
    getEventsFrom(el, events_ptr);
    typename std::vector<T> &events = *events_ptr;

    // Iterators to start/end
    auto it = events.begin();
    auto it_end = events.end();

    for (; it != it_end; it++) {
      // Get the wavenumber in ang^-1 using the previously calculated constant.
      coord_t wavenumber =
          coord_t(wavenumber_in_angstrom_times_tof_in_microsec / it->tof());

      // Q vector = K_final - K_initial = wavenumber * (output_direction -
      // input_direction)
      coord_t center[3] = {Q_dir_x * wavenumber, Q_dir_y * wavenumber,
                           Q_dir_z * wavenumber};

      // Check that the event is within bounds
      if (center[0] < m_extentsMin[0] || center[0] >= m_extentsMax[0])
        continue;
      if (center[1] < m_extentsMin[1] || center[1] >= m_extentsMax[1])
        continue;
      if (center[2] < m_extentsMin[2] || center[2] >= m_extentsMax[2])
        continue;

      if (LorentzCorrection) {
        // double lambda = 1.0/wavenumber;
        // (sin(theta))^2 / wavelength^4
        float correct = float(sin_theta_squared * wavenumber * wavenumber *
                              wavenumber * wavenumber);
        // Push the MDLeanEvent but correct the weight.
        box->addEvent(MDE(float(it->weight() * correct),
                          float(it->errorSquared() * correct * correct),
                          center));
      } else {
        // Push the MDLeanEvent with the same weight
        box->addEvent(
            MDE(float(it->weight()), float(it->errorSquared()), center));
      }
    }

    // Clear out the EventList to save memory
    if (ClearInputWorkspace) {
      // Track how much memory you cleared
      size_t memoryCleared = el.getMemorySize();
      // Clear it now
      el.clear();
      // For Linux with tcmalloc, make sure memory goes back, if you've cleared
      // 200 Megs
      MemoryManager::Instance().releaseFreeMemoryIfAccumulated(
          memoryCleared, static_cast<size_t>(2e8));
    }
  }
  prog->reportIncrement(numEvents, "Adding Events");
}
コード例 #12
0
void TOFSANSResolutionByPixel::exec() {
  MatrixWorkspace_sptr inOutWS = getProperty("Workspace");
  double deltaR = getProperty("DeltaR");
  double R1 = getProperty("SourceApertureRadius");
  double R2 = getProperty("SampleApertureRadius");
  // Convert to meters
  deltaR /= 1000.0;
  R1 /= 1000.0;
  R2 /= 1000.0;

  const MatrixWorkspace_sptr sigmaModeratorVSwavelength =
      getProperty("SigmaModerator");

  // create interpolation table from sigmaModeratorVSwavelength
  Kernel::Interpolation lookUpTable;

  const MantidVec xInterpolate = sigmaModeratorVSwavelength->readX(0);
  const MantidVec yInterpolate = sigmaModeratorVSwavelength->readY(0);

  // prefer the input to be a pointworkspace and create interpolation function
  if (sigmaModeratorVSwavelength->isHistogramData()) {
    g_log.notice() << "mid-points of SigmaModerator histogram bins will be "
                      "used for interpolation.";

    for (size_t i = 0; i < xInterpolate.size() - 1; ++i) {
      const double midpoint = xInterpolate[i + 1] - xInterpolate[i];
      lookUpTable.addPoint(midpoint, yInterpolate[i]);
    }
  } else {
    for (size_t i = 0; i < xInterpolate.size(); ++i) {
      lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]);
    }
  }

  const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos();
  const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos();
  const V3D SSD = samplePos - sourcePos;
  const double L1 = SSD.norm();

  const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms());
  Progress progress(this, 0.0, 1.0, numberOfSpectra);

  for (int i = 0; i < numberOfSpectra; i++) {
    IDetector_const_sptr det;
    try {
      det = inOutWS->getDetector(i);
    } catch (Exception::NotFoundError &) {
      g_log.information() << "Spectrum index " << i
                          << " has no detector assigned to it - discarding"
                          << std::endl;
    }
    // If no detector found or if it's masked or a monitor, skip onto the next
    // spectrum
    if (!det || det->isMonitor() || det->isMasked())
      continue;

    // Get the flight path from the sample to the detector pixel
    const V3D scatteredFlightPathV3D = det->getPos() - samplePos;

    const double L2 = scatteredFlightPathV3D.norm();
    const double Lsum = L1 + L2;

    // calculate part that is wavelenght independent
    const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) *
                           (3.0 * R1 * R1 / (L1 * L1) +
                            3.0 * R2 * R2 * Lsum * Lsum / (L1 * L1 * L2 * L2) +
                            (deltaR * deltaR) / (L2 * L2));

    // Multiplicative factor to go from lambda to Q
    // Don't get fooled by the function name...
    const double theta = inOutWS->detectorTwoTheta(det);
    const double factor = 4.0 * M_PI * sin(theta / 2.0);

    const MantidVec &xIn = inOutWS->readX(i);
    MantidVec &yIn = inOutWS->dataY(i);
    const size_t xLength = xIn.size();

    // for each wavelenght bin of each pixel calculate a q-resolution
    for (size_t j = 0; j < xLength - 1; j++) {
      // use the midpoint of each bin
      const double wl = (xIn[j + 1] + xIn[j]) / 2.0;
      // Calculate q. Alternatively q could be calculated using ConvertUnit
      const double q = factor / wl;

      // wavelenght spread from bin assumed to be
      const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j];

      // wavelenght spread from moderatorm, converted from microseconds to
      // wavelengths
      const double sigmaModerator =
          lookUpTable.value(wl) * 3.9560 / (1000.0 * Lsum);

      // calculate wavelenght resolution from moderator and histogram time bin
      const double sigmaLambda =
          std::sqrt(sigmaSpreadFromBin * sigmaSpreadFromBin / 12.0 +
                    sigmaModerator * sigmaModerator);

      // calculate sigmaQ for a given lambda and pixel
      const double sigmaOverLambdaTimesQ = q * sigmaLambda / wl;
      const double sigmaQ = std::sqrt(
          dTheta2 / (wl * wl) + sigmaOverLambdaTimesQ * sigmaOverLambdaTimesQ);

      // update inout workspace with this sigmaQ
      yIn[j] = sigmaQ;
    }

    progress.report("Computing Q resolution");
  }
}
コード例 #13
0
/** Execute the algorithm.
 */
void IntegrateEllipsoids::exec() {
  // get the input workspace
  MatrixWorkspace_sptr wksp = getProperty("InputWorkspace");

  EventWorkspace_sptr eventWS =
      boost::dynamic_pointer_cast<EventWorkspace>(wksp);
  Workspace2D_sptr histoWS = boost::dynamic_pointer_cast<Workspace2D>(wksp);
  if (!eventWS && !histoWS) {
    throw std::runtime_error("IntegrateEllipsoids needs either a "
                             "EventWorkspace or Workspace2D as input.");
  }

  // error out if there are not events
  if (eventWS && eventWS->getNumberEvents() <= 0) {
    throw std::runtime_error(
        "IntegrateEllipsoids does not work for empty event lists");
  }

  PeaksWorkspace_sptr in_peak_ws = getProperty("PeaksWorkspace");
  if (!in_peak_ws) {
    throw std::runtime_error("Could not read the peaks workspace");
  }

  double radius_m = getProperty("RegionRadius");
  double radius_s = getProperty("SatelliteRegionRadius");
  int numSigmas = getProperty("NumSigmas");
  double cutoffIsigI = getProperty("CutoffIsigI");
  bool specify_size = getProperty("SpecifySize");
  double peak_radius = getProperty("PeakSize");
  double sate_peak_radius = getProperty("SatellitePeakSize");
  double back_inner_radius = getProperty("BackgroundInnerSize");
  double sate_back_inner_radius = getProperty("SatelliteBackgroundInnerSize");
  double back_outer_radius = getProperty("BackgroundOuterSize");
  double sate_back_outer_radius = getProperty("SatelliteBackgroundOuterSize");
  bool hkl_integ = getProperty("IntegrateInHKL");
  bool integrateEdge = getProperty("IntegrateIfOnEdge");
  bool adaptiveQBackground = getProperty("AdaptiveQBackground");
  double adaptiveQMultiplier = getProperty("AdaptiveQMultiplier");
  double adaptiveQBackgroundMultiplier = 0.0;
  bool useOnePercentBackgroundCorrection =
      getProperty("UseOnePercentBackgroundCorrection");
  if (adaptiveQBackground)
    adaptiveQBackgroundMultiplier = adaptiveQMultiplier;
  if (!integrateEdge) {
    // This only fails in the unit tests which say that MaskBTP is not
    // registered
    try {
      runMaskDetectors(in_peak_ws, "Tube", "edges");
      runMaskDetectors(in_peak_ws, "Pixel", "edges");
    } catch (...) {
      g_log.error("Can't execute MaskBTP algorithm for this instrument to set "
                  "edge for IntegrateIfOnEdge option");
    }
    calculateE1(in_peak_ws->detectorInfo()); // fill E1Vec for use in detectorQ
  }

  Mantid::DataObjects::PeaksWorkspace_sptr peak_ws =
      getProperty("OutputWorkspace");
  if (peak_ws != in_peak_ws)
    peak_ws = in_peak_ws->clone();

  // get UBinv and the list of
  // peak Q's for the integrator
  std::vector<Peak> &peaks = peak_ws->getPeaks();
  size_t n_peaks = peak_ws->getNumberPeaks();
  size_t indexed_count = 0;
  std::vector<V3D> peak_q_list;
  std::vector<std::pair<double, V3D>> qList;
  std::vector<V3D> hkl_vectors;
  std::vector<V3D> mnp_vectors;
  int ModDim = 0;
  for (size_t i = 0; i < n_peaks; i++) // Note: we skip un-indexed peaks
  {
    V3D hkl(peaks[i].getIntHKL());
    V3D mnp(peaks[i].getIntMNP());

    if (mnp[0] != 0 && ModDim == 0)
      ModDim = 1;
    if (mnp[1] != 0 && ModDim == 1)
      ModDim = 2;
    if (mnp[2] != 0 && ModDim == 2)
      ModDim = 3;

    // use tolerance == 1 to just check for (0,0,0,0,0,0)
    if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0)) {
      peak_q_list.emplace_back(peaks[i].getQLabFrame());
      qList.emplace_back(1., V3D(peaks[i].getQLabFrame()));
      hkl_vectors.push_back(hkl);
      mnp_vectors.push_back(mnp);
      indexed_count++;
    }
  }

  if (indexed_count < 3)
    throw std::runtime_error(
        "At least three linearly independent indexed peaks are needed.");

  // Get UB using indexed peaks and
  // lab-Q vectors
  Matrix<double> UB(3, 3, false);
  Matrix<double> modUB(3, 3, false);
  Matrix<double> modHKL(3, 3, false);
  Geometry::IndexingUtils::Optimize_6dUB(UB, modUB, hkl_vectors, mnp_vectors,
                                         ModDim, peak_q_list);

  int maxOrder = 0;
  bool CT = false;
  if (peak_ws->sample().hasOrientedLattice()) {
    OrientedLattice lattice = peak_ws->mutableSample().getOrientedLattice();
    lattice.setUB(UB);
    lattice.setModUB(modUB);
    modHKL = lattice.getModHKL();
    maxOrder = lattice.getMaxOrder();
    CT = lattice.getCrossTerm();
  }

  Matrix<double> UBinv(UB);
  UBinv.Invert();
  UBinv *= (1.0 / (2.0 * M_PI));

  std::vector<double> PeakRadiusVector(n_peaks, peak_radius);
  std::vector<double> BackgroundInnerRadiusVector(n_peaks, back_inner_radius);
  std::vector<double> BackgroundOuterRadiusVector(n_peaks, back_outer_radius);
  if (specify_size) {
    if (back_outer_radius > radius_m)
      throw std::runtime_error(
          "BackgroundOuterSize must be less than or equal to the RegionRadius");

    if (back_inner_radius >= back_outer_radius)
      throw std::runtime_error(
          "BackgroundInnerSize must be less BackgroundOuterSize");

    if (peak_radius > back_inner_radius)
      throw std::runtime_error(
          "PeakSize must be less than or equal to the BackgroundInnerSize");
  }

  // make the integrator
  Integrate3DEvents integrator(qList, hkl_vectors, mnp_vectors, UBinv, modHKL,
                               radius_m, radius_s, maxOrder, CT,
                               useOnePercentBackgroundCorrection);

  // get the events and add
  // them to the inegrator
  // set up a descripter of where we are going
  this->initTargetWSDescr(wksp);

  // set up the progress bar
  const size_t numSpectra = wksp->getNumberHistograms();
  Progress prog(this, 0.5, 1.0, numSpectra);

  if (eventWS) {
    // process as EventWorkspace
    qListFromEventWS(integrator, prog, eventWS, UBinv, hkl_integ);
  } else {
    // process as Workspace2D
    qListFromHistoWS(integrator, prog, histoWS, UBinv, hkl_integ);
  }

  double inti;
  double sigi;
  std::vector<double> principalaxis1, principalaxis2, principalaxis3;
  std::vector<double> sateprincipalaxis1, sateprincipalaxis2,
      sateprincipalaxis3;
  for (size_t i = 0; i < n_peaks; i++) {
    const V3D hkl(peaks[i].getIntHKL());
    const V3D mnp(peaks[i].getIntMNP());

    if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0) ||
        Geometry::IndexingUtils::ValidIndex(mnp, 1.0)) {
      const V3D peak_q = peaks[i].getQLabFrame();
      // modulus of Q
      const double lenQpeak = adaptiveQMultiplier != 0.0 ? peak_q.norm() : 0.0;

      double adaptiveRadius = adaptiveQMultiplier * lenQpeak + peak_radius;
      if (mnp != V3D(0, 0, 0))
        adaptiveRadius = adaptiveQMultiplier * lenQpeak + sate_peak_radius;

      if (adaptiveRadius <= 0.0) {
        g_log.error() << "Error: Radius for integration sphere of peak " << i
                      << " is negative =  " << adaptiveRadius << '\n';
        peaks[i].setIntensity(0.0);
        peaks[i].setSigmaIntensity(0.0);
        PeakRadiusVector[i] = 0.0;
        BackgroundInnerRadiusVector[i] = 0.0;
        BackgroundOuterRadiusVector[i] = 0.0;
        continue;
      }

      double adaptiveBack_inner_radius;
      double adaptiveBack_outer_radius;
      if (mnp == V3D(0, 0, 0)) {
        adaptiveBack_inner_radius =
            adaptiveQBackgroundMultiplier * lenQpeak + back_inner_radius;
        adaptiveBack_outer_radius =
            adaptiveQBackgroundMultiplier * lenQpeak + back_outer_radius;
      } else {
        adaptiveBack_inner_radius =
            adaptiveQBackgroundMultiplier * lenQpeak + sate_back_inner_radius;
        adaptiveBack_outer_radius =
            adaptiveQBackgroundMultiplier * lenQpeak + sate_back_outer_radius;
      }
      PeakRadiusVector[i] = adaptiveRadius;
      BackgroundInnerRadiusVector[i] = adaptiveBack_inner_radius;
      BackgroundOuterRadiusVector[i] = adaptiveBack_outer_radius;

      std::vector<double> axes_radii;
      Mantid::Geometry::PeakShape_const_sptr shape =
          integrator.ellipseIntegrateModEvents(
              E1Vec, peak_q, hkl, mnp, specify_size, adaptiveRadius,
              adaptiveBack_inner_radius, adaptiveBack_outer_radius, axes_radii,
              inti, sigi);
      peaks[i].setIntensity(inti);
      peaks[i].setSigmaIntensity(sigi);
      peaks[i].setPeakShape(shape);
      if (axes_radii.size() == 3) {
        if (inti / sigi > cutoffIsigI || cutoffIsigI == EMPTY_DBL()) {
          if (mnp == V3D(0, 0, 0)) {
            principalaxis1.push_back(axes_radii[0]);
            principalaxis2.push_back(axes_radii[1]);
            principalaxis3.push_back(axes_radii[2]);
          } else {
            sateprincipalaxis1.push_back(axes_radii[0]);
            sateprincipalaxis2.push_back(axes_radii[1]);
            sateprincipalaxis3.push_back(axes_radii[2]);
          }
        }
      }
    } else {
      peaks[i].setIntensity(0.0);
      peaks[i].setSigmaIntensity(0.0);
    }
  }
  if (principalaxis1.size() > 1) {
    Statistics stats1 = getStatistics(principalaxis1);
    g_log.notice() << "principalaxis1: "
                   << " mean " << stats1.mean << " standard_deviation "
                   << stats1.standard_deviation << " minimum " << stats1.minimum
                   << " maximum " << stats1.maximum << " median "
                   << stats1.median << "\n";
    Statistics stats2 = getStatistics(principalaxis2);
    g_log.notice() << "principalaxis2: "
                   << " mean " << stats2.mean << " standard_deviation "
                   << stats2.standard_deviation << " minimum " << stats2.minimum
                   << " maximum " << stats2.maximum << " median "
                   << stats2.median << "\n";
    Statistics stats3 = getStatistics(principalaxis3);
    g_log.notice() << "principalaxis3: "
                   << " mean " << stats3.mean << " standard_deviation "
                   << stats3.standard_deviation << " minimum " << stats3.minimum
                   << " maximum " << stats3.maximum << " median "
                   << stats3.median << "\n";

    if (sateprincipalaxis1.size() > 1) {
      Statistics satestats1 = getStatistics(sateprincipalaxis1);
      g_log.notice() << "sateprincipalaxis1: "
                     << " mean " << satestats1.mean << " standard_deviation "
                     << satestats1.standard_deviation << " minimum "
                     << satestats1.minimum << " maximum " << satestats1.maximum
                     << " median " << satestats1.median << "\n";
      Statistics satestats2 = getStatistics(sateprincipalaxis2);
      g_log.notice() << "sateprincipalaxis2: "
                     << " mean " << satestats2.mean << " standard_deviation "
                     << satestats2.standard_deviation << " minimum "
                     << satestats2.minimum << " maximum " << satestats2.maximum
                     << " median " << satestats2.median << "\n";
      Statistics satestats3 = getStatistics(sateprincipalaxis3);
      g_log.notice() << "sateprincipalaxis3: "
                     << " mean " << satestats3.mean << " standard_deviation "
                     << satestats3.standard_deviation << " minimum "
                     << satestats3.minimum << " maximum " << satestats3.maximum
                     << " median " << satestats3.median << "\n";
    }

    constexpr size_t histogramNumber = 3;
    Workspace_sptr wsProfile = WorkspaceFactory::Instance().create(
        "Workspace2D", histogramNumber, principalaxis1.size(),
        principalaxis1.size());
    Workspace2D_sptr wsProfile2D =
        boost::dynamic_pointer_cast<Workspace2D>(wsProfile);
    AnalysisDataService::Instance().addOrReplace("EllipsoidAxes", wsProfile2D);

    // set output workspace
    Points points(principalaxis1.size(), LinearGenerator(0, 1));
    wsProfile2D->setHistogram(0, points, Counts(std::move(principalaxis1)));
    wsProfile2D->setHistogram(1, points, Counts(std::move(principalaxis2)));
    wsProfile2D->setHistogram(2, points, Counts(std::move(principalaxis3)));

    if (cutoffIsigI != EMPTY_DBL()) {
      principalaxis1.clear();
      principalaxis2.clear();
      principalaxis3.clear();
      sateprincipalaxis1.clear();
      sateprincipalaxis2.clear();
      sateprincipalaxis3.clear();
      specify_size = true;
      peak_radius = std::max(std::max(stats1.mean, stats2.mean), stats3.mean) +
                    numSigmas * std::max(std::max(stats1.standard_deviation,
                                                  stats2.standard_deviation),
                                         stats3.standard_deviation);
      back_inner_radius = peak_radius;
      back_outer_radius = peak_radius * 1.25992105; // A factor of 2 ^ (1/3)
      // will make the background
      // shell volume equal to the peak region volume.
      for (size_t i = 0; i < n_peaks; i++) {
        V3D hkl(peaks[i].getIntHKL());
        V3D mnp(peaks[i].getIntMNP());
        if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0) ||
            Geometry::IndexingUtils::ValidIndex(mnp, 1.0)) {
          const V3D peak_q = peaks[i].getQLabFrame();
          std::vector<double> axes_radii;
          integrator.ellipseIntegrateModEvents(
              E1Vec, peak_q, hkl, mnp, specify_size, peak_radius,
              back_inner_radius, back_outer_radius, axes_radii, inti, sigi);
          peaks[i].setIntensity(inti);
          peaks[i].setSigmaIntensity(sigi);
          if (axes_radii.size() == 3) {
            if (mnp == V3D(0, 0, 0)) {
              principalaxis1.push_back(axes_radii[0]);
              principalaxis2.push_back(axes_radii[1]);
              principalaxis3.push_back(axes_radii[2]);
            } else {
              sateprincipalaxis1.push_back(axes_radii[0]);
              sateprincipalaxis2.push_back(axes_radii[1]);
              sateprincipalaxis3.push_back(axes_radii[2]);
            }
          }
        } else {
          peaks[i].setIntensity(0.0);
          peaks[i].setSigmaIntensity(0.0);
        }
      }
      if (principalaxis1.size() > 1) {
        Workspace_sptr wsProfile2 = WorkspaceFactory::Instance().create(
            "Workspace2D", histogramNumber, principalaxis1.size(),
            principalaxis1.size());
        Workspace2D_sptr wsProfile2D2 =
            boost::dynamic_pointer_cast<Workspace2D>(wsProfile2);
        AnalysisDataService::Instance().addOrReplace("EllipsoidAxes_2ndPass",
                                                     wsProfile2D2);

        Points profilePoints(principalaxis1.size(), LinearGenerator(0, 1));
        wsProfile2D->setHistogram(0, profilePoints,
                                  Counts(std::move(principalaxis1)));
        wsProfile2D->setHistogram(1, profilePoints,
                                  Counts(std::move(principalaxis2)));
        wsProfile2D->setHistogram(2, profilePoints,
                                  Counts(std::move(principalaxis3)));
      }
    }
  }

  // This flag is used by the PeaksWorkspace to evaluate whether it has been
  // integrated.
  peak_ws->mutableRun().addProperty("PeaksIntegrated", 1, true);
  // These flags are specific to the algorithm.
  peak_ws->mutableRun().addProperty("PeakRadius", PeakRadiusVector, true);
  peak_ws->mutableRun().addProperty("BackgroundInnerRadius",
                                    BackgroundInnerRadiusVector, true);
  peak_ws->mutableRun().addProperty("BackgroundOuterRadius",
                                    BackgroundOuterRadiusVector, true);

  setProperty("OutputWorkspace", peak_ws);
}
コード例 #14
0
void SANSDirectBeamScaling::exec()
{
  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
  const double beamRadius = getProperty("BeamRadius");
  const double attTrans = getProperty("AttenuatorTransmission");
  const double attTransErr = getProperty("AttenuatorTransmissionError");

  // Extract the required spectra into separate workspaces
  std::vector<detid_t> udet;
  std::vector<size_t> index;
  udet.push_back(getProperty("BeamMonitor"));
  // Convert UDETs to workspace indices
  inputWS->getIndicesFromDetectorIDs(udet,index);
  if (index.size() < 1)
  {
    g_log.debug() << "inputWS->getIndicesFromDetectorIDs() returned empty\n";
    throw std::invalid_argument("Could not find the incident beam monitor spectra\n");
  }

  const int64_t numHists = inputWS->getNumberHistograms();
  Progress progress(this,0.0,1.0,numHists);

  // Number of X bins
  const int64_t xLength = inputWS->readY(0).size();

  // Monitor counts
  double monitor = 0.0;
  const MantidVec& MonIn = inputWS->readY(index[0]);
  for (int64_t j = 0; j < xLength; j++)
    monitor += MonIn[j];

  const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos();
  double counts = 0.0;
  double error = 0.0;
  int nPixels = 0;

  // Sample-detector distance for the contributing pixels
  double sdd = 0.0;

  for (int64_t i = 0; i < int64_t(numHists); ++i)
  {
    IDetector_const_sptr det;
    try {
      det = inputWS->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl;
      continue;
    }

    // Skip if we have a monitor or if the detector is masked.
    if ( det->isMonitor() || det->isMasked() ) continue;

    const MantidVec& YIn = inputWS->readY(i);
    const MantidVec& EIn = inputWS->readE(i);

    // Sum up all the counts
    V3D pos = det->getPos() - V3D(sourcePos.X(), sourcePos.Y(), 0.0);
    const double pixelDistance = pos.Z();
    pos.setZ(0.0);
    if (pos.norm() <= beamRadius) {
      // Correct data for all X bins
      for (int64_t j = 0; j < xLength; j++)
      {
        counts += YIn[j];
        error += EIn[j]*EIn[j];
      }
      nPixels += 1;
      sdd += pixelDistance;
    }
    progress.report("Absolute Scaling");
  }
  // Get the average SDD for the counted pixels, and transform to mm.
  sdd = sdd/nPixels*1000.0;
  error = std::sqrt(error);

  // Transform from m to mm
  double sourceAperture = getProperty("SourceApertureRadius");
  sourceAperture *= 1000.0;
  // Transform from m to mm
  double sampleAperture = getProperty("SampleApertureRadius");
  sampleAperture *= 1000.0;
  //TODO: replace this by some meaningful value
  const double KCG2FluxPerMon_SUGAR = 1.0;

  // Solid angle correction scale in 1/(cm^2)/steradian
  double solidAngleCorrScale = sdd/(M_PI*sourceAperture*sampleAperture);
  solidAngleCorrScale = solidAngleCorrScale*solidAngleCorrScale*100.0;

  // Scaling factor in n/(monitor count)/(cm^2)/steradian
  double scale = counts/monitor*solidAngleCorrScale/KCG2FluxPerMon_SUGAR;
  double scaleErr = std::abs(error/monitor)*solidAngleCorrScale/KCG2FluxPerMon_SUGAR;

  scaleErr = std::abs(scale/attTrans)*sqrt( (scaleErr/scale)*(scaleErr/scale) +(attTransErr/attTrans)*(attTransErr/attTrans) );
  scale /= attTrans;

  std::vector<double> output;
  output.push_back(scale);
  output.push_back(scaleErr);
  setProperty("ScaleFactor", output);
}
コード例 #15
0
ファイル: V3D.cpp プロジェクト: Mantid-Test-Account/mantid
/**
  Determines if this,B,C are collinear
  @param Bv :: Vector to test
  @param Cv :: Vector to test
  @return false is no colinear and true if they are (within Ptolerance)
*/
bool V3D::coLinear(const V3D &Bv, const V3D &Cv) const {
  const V3D &Av = *this;
  const V3D Tmp((Bv - Av).cross_prod(Cv - Av));
  return Tmp.norm() <= Tolerance;
}
コード例 #16
0
void ConvertToDiffractionMDWorkspace::convertEventList(
    int workspaceIndex, const API::SpectrumInfo &specInfo, EventList &el) {
  size_t numEvents = el.getNumberEvents();
  DataObjects::MDBoxBase<DataObjects::MDLeanEvent<3>, 3> *box = ws->getBox();

  // Get the position of the detector there.
  const auto &detectors = el.getDetectorIDs();
  if (!detectors.empty()) {
    // Check if a detector is located at this workspace index, returns
    // immediately if one is not found.
    if (!specInfo.hasDetectors(workspaceIndex)) {
      this->failedDetectorLookupCount++;
      return;
    }

    // Neutron's total travelled distance
    double distance = l1 + specInfo.l2(workspaceIndex);

    // Vector between the sample and the detector
    const V3D detPos = specInfo.position(workspaceIndex);

    // Detector direction normalized to 1
    const V3D detDir = detPos / detPos.norm();

    // The direction of momentum transfer in the inelastic convention ki-kf
    //  = input beam direction (normalized to 1) - output beam direction
    //  (normalized to 1)
    V3D Q_dir_lab_frame = beamDir - detDir;
    double qSign = -1.0;
    std::string convention =
        ConfigService::Instance().getString("Q.convention");
    if (convention == "Crystallography")
      qSign = 1.0;
    Q_dir_lab_frame *= qSign;

    // Multiply by the rotation matrix to convert to Q in the sample frame (take
    // out goniometer rotation)
    // (or to HKL, if that's what the matrix is)
    const V3D Q_dir = mat * Q_dir_lab_frame;

    // For speed we extract the components.
    coord_t Q_dir_x = coord_t(Q_dir.X());
    coord_t Q_dir_y = coord_t(Q_dir.Y());
    coord_t Q_dir_z = coord_t(Q_dir.Z());

    // For lorentz correction, calculate  sin(theta))^2
    double sin_theta_squared = 0;
    if (LorentzCorrection) {
      // Scattering angle = 2 theta = angle between neutron beam direction and
      // the detector (scattering) direction
      // The formula for Lorentz Correction is sin(theta), i.e. sin(half the
      // scattering angle)
      double theta = specInfo.twoTheta(workspaceIndex) / 2.0;
      sin_theta_squared = sin(theta);
      sin_theta_squared = sin_theta_squared * sin_theta_squared; // square it
    }

    /** Constant that you divide by tof (in usec) to get wavenumber in ang^-1 :
     * Wavenumber (in ang^-1) =  (PhysicalConstants::NeutronMass * distance) /
     * ((tof (in usec) * 1e-6) * PhysicalConstants::h_bar) * 1e-10; */
    const double wavenumber_in_angstrom_times_tof_in_microsec =
        (PhysicalConstants::NeutronMass * distance * 1e-10) /
        (1e-6 * PhysicalConstants::h_bar);

    // This little dance makes the getting vector of events more general (since
    // you can't overload by return type).
    typename std::vector<T> *events_ptr;
    getEventsFrom(el, events_ptr);
    typename std::vector<T> &events = *events_ptr;

    // Iterators to start/end
    auto it = events.begin();
    auto it_end = events.end();

    for (; it != it_end; it++) {
      // Get the wavenumber in ang^-1 using the previously calculated constant.
      coord_t wavenumber =
          coord_t(wavenumber_in_angstrom_times_tof_in_microsec / it->tof());

      // Q vector = K_final - K_initial = wavenumber * (output_direction -
      // input_direction)
      coord_t center[3] = {Q_dir_x * wavenumber, Q_dir_y * wavenumber,
                           Q_dir_z * wavenumber};

      // Check that the event is within bounds
      if (center[0] < m_extentsMin[0] || center[0] >= m_extentsMax[0])
        continue;
      if (center[1] < m_extentsMin[1] || center[1] >= m_extentsMax[1])
        continue;
      if (center[2] < m_extentsMin[2] || center[2] >= m_extentsMax[2])
        continue;

      if (LorentzCorrection) {
        // double lambda = 1.0/wavenumber;
        // (sin(theta))^2 / wavelength^4
        float correct = float(sin_theta_squared * wavenumber * wavenumber *
                              wavenumber * wavenumber);
        // Push the MDLeanEvent but correct the weight.
        box->addEvent(MDE(float(it->weight() * correct),
                          float(it->errorSquared() * correct * correct),
                          center));
      } else {
        // Push the MDLeanEvent with the same weight
        box->addEvent(
            MDE(float(it->weight()), float(it->errorSquared()), center));
      }
    }

    // Clear out the EventList to save memory
    if (ClearInputWorkspace)
      el.clear();
  }
  prog->reportIncrement(numEvents, "Adding Events");
}
コード例 #17
0
void TOFSANSResolutionByPixel::exec() {
  MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
  double deltaR = getProperty("DeltaR");
  double R1 = getProperty("SourceApertureRadius");
  double R2 = getProperty("SampleApertureRadius");
  const bool doGravity = getProperty("AccountForGravity");

  // Check the input
  checkInput(inWS);

  // Setup outputworkspace
  auto outWS = setupOutputWorkspace(inWS);

  // Convert to meters
  deltaR /= 1000.0;
  R1 /= 1000.0;
  R2 /= 1000.0;

  // The moderator workspace needs to match the data workspace
  // in terms of wavelength binning
  const MatrixWorkspace_sptr sigmaModeratorVSwavelength =
      getModeratorWorkspace(inWS);

  // create interpolation table from sigmaModeratorVSwavelength
  Kernel::Interpolation lookUpTable;

  const auto &xInterpolate = sigmaModeratorVSwavelength->points(0);
  const auto &yInterpolate = sigmaModeratorVSwavelength->y(0);

  // prefer the input to be a pointworkspace and create interpolation function
  if (sigmaModeratorVSwavelength->isHistogramData()) {
    g_log.notice() << "mid-points of SigmaModerator histogram bins will be "
                      "used for interpolation.";
  }

  for (size_t i = 0; i < xInterpolate.size(); ++i) {
    lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]);
  }

  // Calculate the L1 distance
  const V3D samplePos = inWS->getInstrument()->getSample()->getPos();
  const V3D sourcePos = inWS->getInstrument()->getSource()->getPos();
  const V3D SSD = samplePos - sourcePos;
  const double L1 = SSD.norm();

  // Get the collimation length
  double LCollim = getProperty("CollimationLength");

  if (LCollim == 0.0) {
    auto collimationLengthEstimator = SANSCollimationLengthEstimator();
    LCollim = collimationLengthEstimator.provideCollimationLength(inWS);
    g_log.information() << "No collimation length was specified. A default "
                           "collimation length was estimated to be " << LCollim
                        << '\n';
  } else {
    g_log.information() << "The collimation length is  " << LCollim << '\n';
  }

  const int numberOfSpectra = static_cast<int>(inWS->getNumberHistograms());
  Progress progress(this, 0.0, 1.0, numberOfSpectra);

  const auto &spectrumInfo = inWS->spectrumInfo();
  for (int i = 0; i < numberOfSpectra; i++) {
    IDetector_const_sptr det;
    if (!spectrumInfo.hasDetectors(i)) {
      g_log.information() << "Workspace index " << i
                          << " has no detector assigned to it - discarding\n";
      continue;
    }
    // If no detector found or if it's masked or a monitor, skip onto the next
    // spectrum
    if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
      continue;

    const double L2 = spectrumInfo.l2(i);
    TOFSANSResolutionByPixelCalculator calculator;
    const double waveLengthIndependentFactor =
        calculator.getWavelengthIndependentFactor(R1, R2, deltaR, LCollim, L2);

    // Multiplicative factor to go from lambda to Q
    // Don't get fooled by the function name...
    const double theta = spectrumInfo.twoTheta(i);
    double sinTheta = sin(0.5 * theta);
    double factor = 4.0 * M_PI * sinTheta;

    const auto &xIn = inWS->x(i);
    const size_t xLength = xIn.size();

    // Gravity correction
    std::unique_ptr<GravitySANSHelper> grav;
    if (doGravity) {
      grav = Kernel::make_unique<GravitySANSHelper>(spectrumInfo, i,
                                                    getProperty("ExtraLength"));
    }

    // Get handles on the outputWorkspace
    auto &yOut = outWS->mutableY(i);
    // for each wavelenght bin of each pixel calculate a q-resolution
    for (size_t j = 0; j < xLength - 1; j++) {
      // use the midpoint of each bin
      const double wl = (xIn[j + 1] + xIn[j]) / 2.0;
      // Calculate q. Alternatively q could be calculated using ConvertUnit
      // If we include a gravity correction we need to adjust sinTheta
      // for each wavelength (in Angstrom)
      if (doGravity) {
        double sinThetaGrav = grav->calcSinTheta(wl);
        factor = 4.0 * M_PI * sinThetaGrav;
      }
      const double q = factor / wl;

      // wavelenght spread from bin assumed to be
      const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j];

      // Get the uncertainty in Q
      auto sigmaQ = calculator.getSigmaQValue(lookUpTable.value(wl),
                                              waveLengthIndependentFactor, q,
                                              wl, sigmaSpreadFromBin, L1, L2);

      // Insert the Q value and the Q resolution into the outputworkspace
      yOut[j] = sigmaQ;
    }
    progress.report("Computing Q resolution");
  }

  // Set the y axis label
  outWS->setYUnitLabel("QResolution");

  setProperty("OutputWorkspace", outWS);
}
コード例 #18
0
void TOFSANSResolution::exec()
{
  Workspace2D_sptr iqWS = getProperty("InputWorkspace");
  MatrixWorkspace_sptr reducedWS = getProperty("ReducedWorkspace");
  EventWorkspace_sptr reducedEventWS = boost::dynamic_pointer_cast<EventWorkspace>(reducedWS);
  const double min_wl = getProperty("MinWavelength");
  const double max_wl = getProperty("MaxWavelength");
  double pixel_size_x = getProperty("PixelSizeX");
  double pixel_size_y = getProperty("PixelSizeY");
  double R1 = getProperty("SourceApertureRadius");
  double R2 = getProperty("SampleApertureRadius");
  // Convert to meters
  pixel_size_x /= 1000.0;
  pixel_size_y /= 1000.0;
  R1 /= 1000.0;
  R2 /= 1000.0;
  wl_resolution = getProperty("DeltaT");

  // Although we want the 'ReducedWorkspace' to be an event workspace for this algorithm to do
  // anything, we don't want the algorithm to 'fail' if it isn't
  if (!reducedEventWS)
  {
    g_log.warning() << "An Event Workspace is needed to compute dQ. Calculation skipped." << std::endl;
    return;
  }

  // Calculate the output binning
  const std::vector<double> binParams = getProperty("OutputBinning");

  // Count histogram for normalization
  const int xLength = static_cast<int>(iqWS->readX(0).size());
  std::vector<double> XNorm(xLength-1, 0.0);

  // Create workspaces with each component of the resolution for debugging purposes
  MatrixWorkspace_sptr thetaWS = WorkspaceFactory::Instance().create(iqWS);
  declareProperty(new WorkspaceProperty<>("ThetaError","",Direction::Output));
  setPropertyValue("ThetaError","__"+iqWS->getName()+"_theta_error");
  setProperty("ThetaError",thetaWS);
  thetaWS->setX(0,iqWS->readX(0));
  MantidVec& ThetaY = thetaWS->dataY(0);

  MatrixWorkspace_sptr tofWS = WorkspaceFactory::Instance().create(iqWS);
  declareProperty(new WorkspaceProperty<>("TOFError","",Direction::Output));
  setPropertyValue("TOFError","__"+iqWS->getName()+"_tof_error");
  setProperty("TOFError",tofWS);
  tofWS->setX(0,iqWS->readX(0));
  MantidVec& TOFY = tofWS->dataY(0);

  // Initialize Dq
  MantidVec& DxOut = iqWS->dataDx(0);
  for ( int i = 0; i<xLength-1; i++ ) DxOut[i] = 0.0;

  const V3D samplePos = reducedWS->getInstrument()->getSample()->getPos();
  const V3D sourcePos = reducedWS->getInstrument()->getSource()->getPos();
  const V3D SSD = samplePos - sourcePos;
  const double L1 = SSD.norm();

  const int numberOfSpectra = static_cast<int>(reducedWS->getNumberHistograms());
  Progress progress(this,0.0,1.0,numberOfSpectra);

  PARALLEL_FOR2(reducedEventWS, iqWS)
  for (int i = 0; i < numberOfSpectra; i++)
  {
    PARALLEL_START_INTERUPT_REGION
    IDetector_const_sptr det;
    try {
      det = reducedEventWS->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl;
      // Catch if no detector. Next line tests whether this happened - test placed
      // outside here because Mac Intel compiler doesn't like 'continue' in a catch
      // in an openmp block.
    }
    // If no detector found or if it's masked or a monitor, skip onto the next spectrum
    if ( !det || det->isMonitor() || det->isMasked() ) continue;

    // Get the flight path from the sample to the detector pixel
    const V3D scattered_flight_path = det->getPos() - samplePos;

    // Multiplicative factor to go from lambda to Q
    // Don't get fooled by the function name...
    const double theta = reducedEventWS->detectorTwoTheta(det);
    const double factor = 4.0 * M_PI * sin( theta/2.0 );

    EventList& el = reducedEventWS->getEventList(i);
    el.switchTo(WEIGHTED);

    std::vector<WeightedEvent>::iterator itev;
    std::vector<WeightedEvent>::iterator itev_end = el.getWeightedEvents().end();

    for (itev = el.getWeightedEvents().begin(); itev != itev_end; ++itev)
    {
      if ( itev->m_weight != itev->m_weight ) continue;
      if (std::abs(itev->m_weight) == std::numeric_limits<double>::infinity()) continue;
      if ( !isEmpty(min_wl) && itev->m_tof < min_wl ) continue;
      if ( !isEmpty(max_wl) && itev->m_tof > max_wl ) continue;

      const double q = factor/itev->m_tof;
      int iq = 0;

      // Bin assignment depends on whether we have log or linear bins
      if(binParams[1]>0.0)
      {
        iq = (int)floor( (q-binParams[0])/ binParams[1] );
      } else {
        iq = (int)floor(log(q/binParams[0])/log(1.0-binParams[1]));
      }

      const double L2 = scattered_flight_path.norm();
      const double src_to_pixel = L1+L2;
      const double dTheta2 = ( 3.0*R1*R1/(L1*L1) + 3.0*R2*R2*src_to_pixel*src_to_pixel/(L1*L1*L2*L2)
            + 2.0*(pixel_size_x*pixel_size_x+pixel_size_y*pixel_size_y)/(L2*L2) )/12.0;

      const double dwl_over_wl = 3.9560*getTOFResolution(itev->m_tof)/(1000.0*(L1+L2)*itev->m_tof);
      const double dq_over_q = std::sqrt(dTheta2/(theta*theta)+dwl_over_wl*dwl_over_wl);

      PARALLEL_CRITICAL(iq)    /* Write to shared memory - must protect */
      if (iq>=0 && iq < xLength-1 && !dq_over_q!=dq_over_q && dq_over_q>0)
      {
        DxOut[iq] += q*dq_over_q*itev->m_weight;
        XNorm[iq] += itev->m_weight;
        TOFY[iq] += q*std::fabs(dwl_over_wl)*itev->m_weight;
        ThetaY[iq] += q*std::sqrt(dTheta2)/theta*itev->m_weight;
      }
    }

    progress.report("Computing Q resolution");
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION
  // Normalize according to the chosen weighting scheme
  for ( int i = 0; i<xLength-1; i++ )
  {
    if (XNorm[i]>0)
    {
      DxOut[i] /= XNorm[i];
      TOFY[i] /= XNorm[i];
      ThetaY[i] /= XNorm[i];
    }
  }
}
コード例 #19
0
void PeakHKLErrors::functionDeriv1D(Jacobian *out, const double *xValues,
                                    const size_t nData) {
  PeaksWorkspace_sptr Peaks =
      AnalysisDataService::Instance().retrieveWS<PeaksWorkspace>(
          PeakWorkspaceName);
  boost::shared_ptr<Geometry::Instrument> instNew = getNewInstrument(Peaks);

  const DblMatrix &UB = Peaks->sample().getOrientedLattice().getUB();
  DblMatrix UBinv(UB);
  UBinv.Invert();
  UBinv /= 2 * M_PI;

  double GonRotx = getParameter("GonRotx");
  double GonRoty = getParameter("GonRoty");
  double GonRotz = getParameter("GonRotz");
  Matrix<double> InvGonRotxMat = RotationMatrixAboutRegAxis(GonRotx, 'x');
  Matrix<double> InvGonRotyMat = RotationMatrixAboutRegAxis(GonRoty, 'y');
  Matrix<double> InvGonRotzMat = RotationMatrixAboutRegAxis(GonRotz, 'z');
  Matrix<double> GonRot = InvGonRotxMat * InvGonRotyMat * InvGonRotzMat;

  InvGonRotxMat.Invert();
  InvGonRotyMat.Invert();
  InvGonRotzMat.Invert();

  std::map<int, Kernel::Matrix<double>> RunNums2GonMatrix;
  getRun2MatMap(Peaks, OptRuns, RunNums2GonMatrix);

  g_log.debug()
      << "----------------------------Derivative------------------------\n";

  V3D samplePosition = instNew->getSample()->getPos();
  IPeak &ppeak = Peaks->getPeak(0);
  double L0 = ppeak.getL1();
  double velocity = (L0 + ppeak.getL2()) / ppeak.getTOF();

  double K =
      2 * M_PI / ppeak.getWavelength() / velocity; // 2pi/lambda = K* velocity
  V3D beamDir = instNew->getBeamDirection();

  size_t paramNums[] = {parameterIndex(std::string("SampleXOffset")),
                        parameterIndex(std::string("SampleYOffset")),
                        parameterIndex(std::string("SampleZOffset"))};

  for (size_t i = 0; i < nData; i += 3) {
    int peakNum = boost::math::iround(xValues[i]);
    IPeak &peak_old = Peaks->getPeak(peakNum);
    Peak peak = createNewPeak(peak_old, instNew, 0, peak_old.getL1());

    int runNum = peak_old.getRunNumber();
    std::string runNumStr = std::to_string(runNum);

    for (int kk = 0; kk < static_cast<int>(nParams()); kk++) {
      out->set(i, kk, 0.0);
      out->set(i + 1, kk, 0.0);
      out->set(i + 2, kk, 0.0);
    }

    double chi, phi, omega;
    size_t chiParamNum, phiParamNum, omegaParamNum;

    size_t N = OptRuns.find("/" + runNumStr);
    if (N < OptRuns.size()) {
      chi = getParameter("chi" + (runNumStr));
      phi = getParameter("phi" + (runNumStr));
      omega = getParameter("omega" + (runNumStr));

      peak.setGoniometerMatrix(GonRot * RunNums2GonMatrix[runNum]);

      chiParamNum = parameterIndex("chi" + (runNumStr));
      phiParamNum = parameterIndex("phi" + (runNumStr));
      omegaParamNum = parameterIndex("omega" + (runNumStr));
    } else {

      Geometry::Goniometer Gon(peak.getGoniometerMatrix());
      std::vector<double> phichiOmega = Gon.getEulerAngles("YZY");
      chi = phichiOmega[1];
      phi = phichiOmega[2];
      omega = phichiOmega[0];
      // peak.setGoniometerMatrix( GonRot*Gon.getR());
      chiParamNum = phiParamNum = omegaParamNum = nParams() + 10;
      peak.setGoniometerMatrix(GonRot * peak.getGoniometerMatrix());
    }
    V3D sampOffsets(getParameter("SampleXOffset"),
                    getParameter("SampleYOffset"),
                    getParameter("SampleZOffset"));
    peak.setSamplePos(peak.getSamplePos() + sampOffsets);
    // NOTE:Use getQLabFrame except for below.
    // For parameters the getGoniometerMatrix should remove GonRot, for derivs
    // wrt GonRot*, wrt chi*,phi*,etc.

    // Deriv wrt chi phi and omega
    if (phiParamNum < nParams()) {
      Matrix<double> chiMatrix = RotationMatrixAboutRegAxis(chi, 'z');
      Matrix<double> phiMatrix = RotationMatrixAboutRegAxis(phi, 'y');
      Matrix<double> omegaMatrix = RotationMatrixAboutRegAxis(omega, 'y');

      Matrix<double> dchiMatrix = DerivRotationMatrixAboutRegAxis(chi, 'z');
      Matrix<double> dphiMatrix = DerivRotationMatrixAboutRegAxis(phi, 'y');
      Matrix<double> domegaMatrix = DerivRotationMatrixAboutRegAxis(omega, 'y');

      Matrix<double> InvG = omegaMatrix * chiMatrix * phiMatrix;
      InvG.Invert();
      // Calculate Derivatives wrt chi(phi,omega) in degrees
      Matrix<double> R = omegaMatrix * chiMatrix * dphiMatrix;
      Matrix<double> InvR = InvG * R * InvG * -1;
      V3D lab = peak.getQLabFrame();
      V3D Dhkl0 = UBinv * InvR * lab;

      R = omegaMatrix * dchiMatrix * phiMatrix;
      InvR = InvG * R * InvG * -1;
      V3D Dhkl1 = UBinv * InvR * peak.getQLabFrame();

      R = domegaMatrix * chiMatrix * phiMatrix;
      InvR = InvG * R * InvG * -1;
      V3D Dhkl2 =
          UBinv * InvR * peak.getQLabFrame(); // R.transpose should be R inverse

      out->set(i, chiParamNum, Dhkl1[0]);
      out->set(i + 1, chiParamNum, Dhkl1[1]);
      out->set(i + 2, chiParamNum, Dhkl1[2]);
      out->set(i, phiParamNum, Dhkl0[0]);
      out->set(i + 1, phiParamNum, Dhkl0[1]);
      out->set(i + 2, phiParamNum, Dhkl0[2]);
      out->set(i, omegaParamNum, Dhkl2[0]);
      out->set(i + 1, omegaParamNum, Dhkl2[1]);
      out->set(i + 2, omegaParamNum, Dhkl2[2]);

    } // if optimize for chi phi and omega on this peak

    //------------------------Goniometer Rotation Derivatives
    //-----------------------
    Matrix<double> InvGonRot(GonRot);
    InvGonRot.Invert();
    Matrix<double> InvGon = InvGonRot * peak.getGoniometerMatrix();
    InvGon.Invert();
    V3D DGonx = (UBinv * InvGon * InvGonRotzMat * InvGonRotyMat *
                 DerivRotationMatrixAboutRegAxis(
                     -GonRotx, 'x') * // - gives inverse of GonRot
                 peak.getQLabFrame()) *
                -1;

    V3D DGony = (UBinv * InvGon * InvGonRotzMat *
                 DerivRotationMatrixAboutRegAxis(-GonRoty, 'y') *
                 InvGonRotxMat * peak.getQLabFrame()) *
                -1;
    V3D DGonz =
        (UBinv * InvGon * DerivRotationMatrixAboutRegAxis(-GonRotz, 'z') *
         InvGonRotyMat * InvGonRotxMat * peak.getQLabFrame()) *
        -1;

    size_t paramnum = parameterIndex("GonRotx");
    out->set(i, paramnum, DGonx[0]);
    out->set(i + 1, paramnum, DGonx[1]);
    out->set(i + 2, paramnum, DGonx[2]);
    out->set(i, parameterIndex("GonRoty"), DGony[0]);
    out->set(i + 1, parameterIndex("GonRoty"), DGony[1]);
    out->set(i + 2, parameterIndex("GonRoty"), DGony[2]);
    out->set(i, parameterIndex("GonRotz"), DGonz[0]);
    out->set(i + 1, parameterIndex("GonRotz"), DGonz[1]);
    out->set(i + 2, parameterIndex("GonRotz"), DGonz[2]);
    //-------------------- Sample Orientation derivatives
    //----------------------------------
    // Qlab = -KV + k|V|*beamdir
    // D = pos-sampPos
    //|V|= vmag=(L0 + D )/tof
    // t1= tof - L0/|V|   {time from sample to pixel}
    // V = D/t1
    V3D D = peak.getDetPos() - samplePosition;
    double vmag = (L0 + D.norm()) / peak.getTOF();
    double t1 = peak.getTOF() - L0 / vmag;

    // Derivs wrt sample x, y, z
    // Ddsx =( - 1, 0, 0),  d|D|^2/dsx -> 2|D|d|D|/dsx =d(tranp(D)* D)/dsx =2
    // Ddsx* tranp(D)
    //|D| also called Dmag
    V3D Dmagdsxsysz(D);
    Dmagdsxsysz *= (-1 / D.norm());

    V3D vmagdsxsysz = Dmagdsxsysz / peak.getTOF();

    V3D t1dsxsysz = vmagdsxsysz * (L0 / vmag / vmag);
    Matrix<double> Gon = peak.getGoniometerMatrix();
    Gon.Invert();

    // x=0 is deriv wrt SampleXoffset, x=1 is deriv wrt SampleYoffset, etc.
    for (int x = 0; x < 3; x++) {
      V3D pp;
      pp[x] = 1;
      V3D dQlab1 = pp / -t1 - D * (t1dsxsysz[x] / t1 / t1);
      V3D dQlab2 = beamDir * vmagdsxsysz[x];
      V3D dQlab = dQlab2 - dQlab1;
      dQlab *= K;

      V3D dQSamp = Gon * dQlab;
      V3D dhkl = UBinv * dQSamp;

      out->set(i, paramNums[x], dhkl[0]);
      out->set(i + 1, paramNums[x], dhkl[1]);
      out->set(i + 2, paramNums[x], dhkl[2]);
    }
  }
}
コード例 #20
0
void TOFSANSResolutionByPixel::exec()
{
  MatrixWorkspace_sptr inOutWS = getProperty("InputWorkspace");
  double deltaR = getProperty("DeltaR");
  double R1 = getProperty("SourceApertureRadius");
  double R2 = getProperty("SampleApertureRadius");
  // Convert to meters
  deltaR /= 1000.0;
  R1 /= 1000.0;
  R2 /= 1000.0;
  const double sigmaModeratorMicroSec = getProperty("SigmaModerator");

  const V3D samplePos = inOutWS->getInstrument()->getSample()->getPos();
  const V3D sourcePos = inOutWS->getInstrument()->getSource()->getPos();
  const V3D SSD = samplePos - sourcePos;
  const double L1 = SSD.norm();

  const int numberOfSpectra = static_cast<int>(inOutWS->getNumberHistograms());
  Progress progress(this,0.0,1.0,numberOfSpectra);

  //PARALLEL_FOR1(inOutWS)
  for (int i = 0; i < numberOfSpectra; i++)
  {
    //PARALLEL_START_INTERUPT_REGION
    IDetector_const_sptr det;
    try {
      det = inOutWS->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.information() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl;
      // Catch if no detector. Next line tests whether this happened - test placed
      // outside here because Mac Intel compiler doesn't like 'continue' in a catch
      // in an openmp block.
    }
    // If no detector found or if it's masked or a monitor, skip onto the next spectrum
    if ( !det || det->isMonitor() || det->isMasked() ) continue;

    // Get the flight path from the sample to the detector pixel
    const V3D scatteredFlightPathV3D = det->getPos() - samplePos; 

    const double L2 = scatteredFlightPathV3D.norm();
    const double Lsum = L1+L2;

    // calculate part that is wavelenght independent
    const double dTheta2 = (4.0 * M_PI * M_PI / 12.0) * 
      ( 3.0*R1*R1/(L1*L1) + 3.0*R2*R2*Lsum*Lsum/(L1*L1*L2*L2) + (deltaR*deltaR)/(L2*L2) );

    // Multiplicative factor to go from lambda to Q
    // Don't get fooled by the function name...
    const double theta = inOutWS->detectorTwoTheta(det);
    const double factor = 4.0 * M_PI * sin( theta/2.0 );

    const MantidVec& xIn = inOutWS->readX(i);
    MantidVec& yIn = inOutWS->dataY(i);
    const size_t xLength = xIn.size();

    for ( size_t j = 0; j < xLength-1; j++)
    {
      // Calculate q. Alternatively q could be calculated using ConvertUnit
      const double wl = (xIn[j+1]+xIn[j])/2.0;
      const double q = factor/wl;

      // calculate wavelenght resolution from moderator and histogram time bin width and
      // convert to from unit of micro-seconds to Aangstrom
      const double sigmaLambda = sigmaModeratorMicroSec*3.9560/(1000.0*Lsum);

      // calculate sigmaQ for a given lambda and pixel
      const double sigmaOverLambdaTimesQ = q*sigmaLambda/wl;
      const double sigmaQ = std::sqrt(dTheta2/(wl*wl)+sigmaOverLambdaTimesQ*sigmaOverLambdaTimesQ);

      // update inout workspace with this sigmaQ
      yIn[j] = sigmaQ;
    }

    progress.report("Computing Q resolution");
    //PARALLEL_END_INTERUPT_REGION
  }

}
コード例 #21
0
void AnvredCorrection::execEvent()
{

  const int64_t numHists = static_cast<int64_t>(m_inputWS->getNumberHistograms());
  std::string unitStr = m_inputWS->getAxis(0)->unit()->unitID();
  //Create a new outputworkspace with not much in it
  DataObjects::EventWorkspace_sptr correctionFactors;
  correctionFactors = boost::dynamic_pointer_cast<EventWorkspace>(
      API::WorkspaceFactory::Instance().create("EventWorkspace",numHists,2,1) );
  correctionFactors->sortAll(TOF_SORT, NULL);
  //Copy required stuff from it
  API::WorkspaceFactory::Instance().initializeFromParent(m_inputWS, correctionFactors, true);
  bool inPlace = (this->getPropertyValue("InputWorkspace") == this->getPropertyValue("OutputWorkspace"));
  if (inPlace)
    g_log.debug("Correcting EventWorkspace in-place.");

  // If sample not at origin, shift cached positions.
  const V3D samplePos = m_inputWS->getInstrument()->getSample()->getPos();
  const V3D pos = m_inputWS->getInstrument()->getSource()->getPos()-samplePos;
  double L1 = pos.norm();

  Progress prog(this,0.0,1.0,numHists);
  // Loop over the spectra
  PARALLEL_FOR2(eventW,correctionFactors)
  for (int64_t i = 0; i < int64_t(numHists); ++i)
  {
    PARALLEL_START_INTERUPT_REGION

    // Copy over bin boundaries
    const MantidVec& X = eventW->readX(i);
    correctionFactors->dataX(i) = X;

    // Get detector position
    IDetector_const_sptr det;
    try
    {
      det = eventW->getDetector(i);
    } catch (Exception::NotFoundError&)
    {
      // Catch if no detector. Next line tests whether this happened - test placed
      // outside here because Mac Intel compiler doesn't like 'continue' in a catch
      // in an openmp block.
    }
    // If no detector found, skip onto the next spectrum
    if ( !det ) continue;

    // This is the scattered beam direction
    Instrument_const_sptr inst = eventW->getInstrument();
    V3D dir = det->getPos() - samplePos;
    double L2 = dir.norm();
    // Two-theta = polar angle = scattering angle = between +Z vector and the scattered beam
    double scattering = dir.angle( V3D(0.0, 0.0, 1.0) );

    EventList el = eventW->getEventList(i);
    el.switchTo(WEIGHTED_NOTIME);
    std::vector<WeightedEventNoTime> events = el.getWeightedEventsNoTime();

    std::vector<WeightedEventNoTime>::iterator itev;
    std::vector<WeightedEventNoTime>::iterator itev_end = events.end();

    Mantid::Kernel::Units::Wavelength wl;
    std::vector<double> timeflight;

    // multiplying an event list by a scalar value
    for (itev = events.begin(); itev != itev_end; itev++)
    {
      timeflight.push_back(itev->tof());
      if (unitStr.compare("TOF") == 0)
        wl.fromTOF(timeflight, timeflight, L1, L2, scattering, 0, 0, 0);
      double value = this->getEventWeight(timeflight[0], scattering);
      timeflight.clear();
      itev->m_errorSquared = static_cast<float>(itev->m_errorSquared * value*value);
      itev->m_weight *= static_cast<float>(value);
    }
    correctionFactors->getOrAddEventList(i) +=events;
    
    std::set<detid_t>& dets = eventW->getEventList(i).getDetectorIDs();
    std::set<detid_t>::iterator j;
    for (j = dets.begin(); j != dets.end(); ++j)
      correctionFactors->getOrAddEventList(i).addDetectorID(*j);
    // When focussing in place, you can clear out old memory from the input one!
    if (inPlace)
    {
      eventW->getEventList(i).clear();
      Mantid::API::MemoryManager::Instance().releaseFreeMemory();
    }


    prog.report();

    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION

  correctionFactors->doneAddingEventLists();
  setProperty("OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(correctionFactors));

  // Now do some cleaning-up since destructor may not be called immediately
  this->cleanup();
}
コード例 #22
0
ファイル: EQSANSTofStructure.cpp プロジェクト: mducle/mantid
void EQSANSTofStructure::execEvent(
    Mantid::DataObjects::EventWorkspace_sptr inputWS, double threshold,
    double frame_offset, double tof_frame_width, double tmp_frame_width,
    bool frame_skipping) {
  const size_t numHists = inputWS->getNumberHistograms();
  Progress progress(this, 0.0, 1.0, numHists);

  // Get the nominal sample-to-detector distance (in mm)
  Mantid::Kernel::Property *prop =
      inputWS->run().getProperty("sample_detector_distance");
  auto dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop);
  if (!dp) {
    throw std::runtime_error("sample_detector_distance log not found.");
  }
  const double SDD = *dp / 1000.0;

  // Loop through the spectra and apply correction
  PARALLEL_FOR1(inputWS)
  for (int64_t ispec = 0; ispec < int64_t(numHists); ++ispec) {

    IDetector_const_sptr det;
    try {
      det = inputWS->getDetector(ispec);
    } catch (Exception::NotFoundError &) {
      g_log.warning() << "Workspace index " << ispec
                      << " has no detector assigned to it - discarding\n";
      // 'continue' statement moved outside catch block because Mac Intel
      // compiler has a problem with it being here in an openmp block.
    }
    if (!det)
      continue;

    // Get the flight path from the sample to the detector pixel
    const V3D samplePos = inputWS->getInstrument()->getSample()->getPos();
    const V3D scattered_flight_path = det->getPos() - samplePos;

    // Sample-to-source distance
    const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos();
    const V3D SSD = samplePos - sourcePos;
    double tof_factor =
        (SSD.norm() + scattered_flight_path.norm()) / (SSD.norm() + SDD);

    PARALLEL_START_INTERUPT_REGION

    // Get the pointer to the output event list
    std::vector<TofEvent> &events = inputWS->getSpectrum(ispec).getEvents();
    std::vector<TofEvent>::iterator it;
    std::vector<TofEvent> clean_events;

    for (it = events.begin(); it < events.end(); ++it) {
      double newtof = it->tof();
      newtof += frame_offset;
      // Correct for the scattered neutron flight path
      if (flight_path_correction)
        newtof /= tof_factor;

      while (newtof < threshold)
        newtof += tmp_frame_width;

      // Remove events that don't fall within the accepted time window
      double rel_tof = newtof - frame_tof0;
      double x = (static_cast<int>(floor(rel_tof * 10)) %
                  static_cast<int>(floor(tof_frame_width * 10))) *
                 0.1;
      if (x < low_tof_cut || x > tof_frame_width - high_tof_cut) {
        continue;
      }
      // At this point the events in the second frame are still off by a frame
      if (frame_skipping && rel_tof > tof_frame_width)
        newtof += tof_frame_width;
      clean_events.emplace_back(newtof, it->pulseTime());
    }
    events.clear();
    events.reserve(clean_events.size());
    for (it = clean_events.begin(); it < clean_events.end(); ++it) {
      events.push_back(*it);
    }

    progress.report("TOF structure");
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION
}
コード例 #23
0
ファイル: ConventionalCell.cpp プロジェクト: trnielsen/mantid
  /**
   *  Change UB to a new matrix corresponding to a unit cell with the first 
   *  two sides approximately equal in magnitude.  This is used to arrange 
   *  the UB matrix for a tetragonal cell into a standard order.
   *
   *  @param UB on input this should correspond to a tetragonal cell.  
   *            On output, it will correspond to a tetragonal cell with the 
   *            first two sides, a and b, set to the two sides that are most
   *            nearly equal in length. 
   */
  void ConventionalCell::StandardizeTetragonal( Kernel::DblMatrix & UB )
  {
    V3D a;
    V3D b;
    V3D c;
    IndexingUtils::GetABC( UB, a, b, c );

    double a_b_diff = fabs( a.norm() - b.norm() ) /
                      std::min( a.norm(), b.norm() );

    double a_c_diff = fabs( a.norm() - c.norm() ) /
                      std::min( a.norm(), c.norm() );

    double b_c_diff = fabs( b.norm() - c.norm() ) /
                      std::min( b.norm(), c.norm() );

                          // if needed, change UB to have the two most nearly
                          // equal sides first.
    if ( a_c_diff <= a_b_diff && a_c_diff <= b_c_diff )
    {
      IndexingUtils::GetUB( UB, c, a, b );
    }
    else if ( b_c_diff <= a_b_diff && b_c_diff <= a_c_diff )
    {
      IndexingUtils::GetUB( UB, b, c, a );
    }
  
  }
コード例 #24
0
ファイル: NiggliCell.cpp プロジェクト: spaceyatom/mantid
bool NiggliCell::MakeNiggliUB(const DblMatrix &UB, DblMatrix &newUB) {
  V3D a;
  V3D b;
  V3D c;

  if (!OrientedLattice::GetABC(UB, a, b, c)) {
    return false;
  }

  V3D v1;
  V3D v2;
  V3D v3;
  // first make a list of linear combinations
  // of vectors a,b,c with coefficients up to 5
  std::vector<V3D> directions;
  int N_coeff = 5;
  for (int i = -N_coeff; i <= N_coeff; i++) {
    for (int j = -N_coeff; j <= N_coeff; j++) {
      for (int k = -N_coeff; k <= N_coeff; k++) {
        if (i != 0 || j != 0 || k != 0) {
          v1 = a * i;
          v2 = b * j;
          v3 = c * k;
          V3D sum(v1);
          sum += v2;
          sum += v3;
          directions.push_back(sum);
        }
      }
    }
  }
  // next sort the list of linear combinations
  // in order of increasing length
  std::sort(directions.begin(), directions.end(), V3D::CompareMagnitude);

  // next form a list of possible UB matrices
  // using sides from the list of linear
  // combinations, using shorter directions first.
  // Keep trying more until 25 UBs are found.
  // Only keep UBs corresponding to cells with
  // at least a minimum cell volume
  std::vector<DblMatrix> UB_list;

  size_t num_needed = 25;
  size_t max_to_try = 5;
  while (UB_list.size() < num_needed && max_to_try < directions.size()) {
    max_to_try *= 2;
    size_t num_to_try = std::min(max_to_try, directions.size());

    V3D acrossb;
    double vol = 0;
    double min_vol = .1f; // what should this be? 0.1 works OK, but...?
    for (size_t i = 0; i < num_to_try - 2; i++) {
      a = directions[i];
      for (size_t j = i + 1; j < num_to_try - 1; j++) {
        b = directions[j];
        acrossb = a.cross_prod(b);
        for (size_t k = j + 1; k < num_to_try; k++) {
          c = directions[k];
          vol = acrossb.scalar_prod(c);
          if (vol > min_vol && HasNiggliAngles(a, b, c, 0.01)) {
            Matrix<double> new_tran(3, 3, false);
            OrientedLattice::GetUB(new_tran, a, b, c);
            UB_list.push_back(new_tran);
          }
        }
      }
    }
  }
  // if no valid UBs could be formed, return
  // false and the original UB
  if (UB_list.empty()) {
    newUB = UB;
    return false;
  }
  // now sort the UB's in order of increasing
  // total side length |a|+|b|+|c|
  std::sort(UB_list.begin(), UB_list.end(), CompareABCsum);

  // keep only those UB's with total side length
  // within .1% of the first one.  This can't
  // be much larger or "bad" UBs are made for
  // some tests with 5% noise
  double length_tol = 0.001;
  double total_length;

  std::vector<DblMatrix> short_list;
  short_list.push_back(UB_list[0]);
  OrientedLattice::GetABC(short_list[0], a, b, c);
  total_length = a.norm() + b.norm() + c.norm();

  bool got_short_list = false;
  size_t i = 1;
  while (i < UB_list.size() && !got_short_list) {
    OrientedLattice::GetABC(UB_list[i], v1, v2, v3);
    double next_length = v1.norm() + v2.norm() + v3.norm();
    if (fabs(next_length - total_length) / total_length < length_tol)
      short_list.push_back(UB_list[i]);
    else
      got_short_list = true;
    i++;
  }
  // now sort on the basis of difference of cell
  // angles from 90 degrees and return the one
  // with angles most different from 90
  std::sort(short_list.begin(), short_list.end(), CompareDiffFrom90);

  newUB = short_list[0];

  return true;
}