コード例 #1
0
/**
 * Execute the MoveInstrumentComponent on all (named) subcomponents
 * @param toCorrect : Workspace to correct
 * @param detector : Detector or DetectorGroup
 * @param sample : Sample Component
 * @param upOffset : Up offset to apply
 * @param acrossOffset : Across offset to apply
 * @param detectorPosition: Actual detector or detector group position.
 */
void SpecularReflectionPositionCorrect::moveDetectors(
    API::MatrixWorkspace_sptr toCorrect, IComponent_const_sptr detector,
    IComponent_const_sptr sample, const double &upOffset,
    const double &acrossOffset, const V3D &detectorPosition) {
  auto instrument = toCorrect->getInstrument();
  const V3D samplePosition = sample->getPos();
  auto referenceFrame = instrument->getReferenceFrame();
  if (auto groupDetector = boost::dynamic_pointer_cast<const DetectorGroup>(
          detector)) // Do we have a group of detectors
  {
    const std::vector<IDetector_const_sptr> detectors =
        groupDetector->getDetectors();
    const bool commonParent = hasCommonParent(detectors);
    if (commonParent) {
      /*
       * Same parent component. So lets move that.
       */
      moveDetectors(toCorrect, detectors[0], sample, upOffset, acrossOffset,
                    detectorPosition); // Recursive call
    } else {
      /*
       * We have to move individual components.
       */
      for (size_t i = 0; i < detectors.size(); ++i) {
        moveDetectors(toCorrect, detectors[i], sample, upOffset, acrossOffset,
                      detectorPosition); // Recursive call
      }
    }
  } else {
    auto moveComponentAlg =
        this->createChildAlgorithm("MoveInstrumentComponent");
    moveComponentAlg->initialize();
    moveComponentAlg->setProperty("Workspace", toCorrect);
    IComponent_const_sptr root = getParentComponent(detector);
    const std::string componentName = root->getName();
    moveComponentAlg->setProperty("ComponentName", componentName);
    moveComponentAlg->setProperty("RelativePosition", false);
    // Movements
    moveComponentAlg->setProperty(
        referenceFrame->pointingAlongBeamAxis(),
        detectorPosition.scalar_prod(referenceFrame->vecPointingAlongBeam()));
    moveComponentAlg->setProperty(referenceFrame->pointingHorizontalAxis(),
                                  acrossOffset);
    const double detectorVerticalPosition =
        detectorPosition.scalar_prod(referenceFrame->vecPointingUp());
    const double rootVerticalPosition =
        root->getPos().scalar_prod(referenceFrame->vecPointingUp());

    const double dm = rootVerticalPosition - detectorVerticalPosition;
    moveComponentAlg->setProperty(
        referenceFrame->pointingUpAxis(),
        samplePosition.scalar_prod(referenceFrame->vecPointingUp()) + upOffset +
            dm);
    // Execute the movement.
    moveComponentAlg->execute();
  }
}
コード例 #2
0
ファイル: PeaksOnSurface.cpp プロジェクト: BigShows/mantid
 void PeaksOnSurface::checkTouchPoint(const V3D& touchPoint,const  V3D& normal,const  V3D& faceVertex) const
 {
    if( normal.scalar_prod(touchPoint - faceVertex) != 0)
    {
      throw std::runtime_error("Debugging. Calculation is wrong. touch point should always be on the plane!"); // Remove this line later. Check that geometry is setup properly.
    }
 }
コード例 #3
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;
}
コード例 #4
0
/**
 * Correct the position of the detectors based on the input theta value.
 * @param toCorrect : Workspace to correct detector posisitions on.
 * @param twoThetaInDeg : 2* Theta in degrees to use in correction calculations.
 * @param sample : Pointer to the sample
 * @param detector : Pointer to a given detector
 */
void SpecularReflectionPositionCorrect::correctPosition(
    API::MatrixWorkspace_sptr toCorrect, const double &twoThetaInDeg,
    IComponent_const_sptr sample, IComponent_const_sptr detector) {

  auto instrument = toCorrect->getInstrument();

  const V3D detectorPosition = detector->getPos();

  const V3D samplePosition = sample->getPos();

  const V3D sampleToDetector = detectorPosition - samplePosition;

  auto referenceFrame = instrument->getReferenceFrame();

  const double twoThetaInRad = twoThetaInDeg * (M_PI / 180.0);

  double acrossOffset = 0;

  double beamOffset = sampleToDetector.scalar_prod(
      referenceFrame
          ->vecPointingAlongBeam()); // We just recalculate beam offset.

  double upOffset =
      (beamOffset *
       std::tan(0.5 * twoThetaInRad)); // We only correct vertical position

  // Apply the movements.
  moveDetectors(toCorrect, detector, sample, upOffset, acrossOffset,
                detector->getPos());
}
コード例 #5
0
ファイル: Detector.cpp プロジェクト: dezed/mantid
/**
Get the two theata angle signed according the quadrant
@param observer :: The observer position
@param axis :: The axis
@param instrumentUp :: instrument up direction.
@return The angle
*/
double Detector::getSignedTwoTheta(const V3D &observer, const V3D &axis,
                                   const V3D &instrumentUp) const {
  const V3D sampleDetVec = this->getPos() - observer;
  double angle = sampleDetVec.angle(axis);

  V3D cross = axis.cross_prod(sampleDetVec);
  V3D normToSurface = axis.cross_prod(instrumentUp);
  if (normToSurface.scalar_prod(cross) < 0) {
    angle *= -1;
  }
  return angle;
}
コード例 #6
0
ファイル: ConventionalCell.cpp プロジェクト: trnielsen/mantid
  /**
   *  Change UB to a new matrix corresponding to a unit cell with the sides
   *  in increasing order of magnitude.  This is used to arrange the UB matrix
   *  for an orthorhombic cell into a standard order.
   *
   *  @param UB on input this should correspond to an orthorhombic cell. 
   *            On output, it will correspond to an orthorhombic cell with
   *            sides in increasing order.
   */
  void ConventionalCell::SetSidesIncreasing( Kernel::DblMatrix & UB )
  {
    V3D a_dir;
    V3D b_dir;
    V3D c_dir;
    IndexingUtils::GetABC( UB, a_dir, b_dir, c_dir );

    std::vector<V3D> edges;
    edges.push_back( a_dir );
    edges.push_back( b_dir );
    edges.push_back( c_dir );
    std::sort( edges.begin(), edges.end(), IndexingUtils::CompareMagnitude );

    V3D a = edges[0];
    V3D b = edges[1];
    V3D c = edges[2];

    V3D acrossb = a.cross_prod( b );           // keep a,b,c right handed
    if ( acrossb.scalar_prod(c) < 0 )
    {
      c = c * (-1);
    } 
    IndexingUtils::GetUB( UB, a, b, c );
  }
コード例 #7
0
/** Corrects a spectra for the detector efficiency calculated from detector information
Gets the detector information and uses this to calculate its efficiency
*  @param spectraIn :: index of the spectrum to get the efficiency for
*  @throw invalid_argument if the shape of a detector is isn't a cylinder aligned along one axis
*  @throw runtime_error if the SpectraDetectorMap has not been filled
*  @throw NotFoundError if the detector or its gas pressure or wall thickness were not found
*/
void DetectorEfficiencyCor::correctForEfficiency(int64_t spectraIn)
{
  IDetector_const_sptr det = m_inputWS->getDetector(spectraIn);
  if( det->isMonitor() || det->isMasked() )
  {
    return;
  }

  MantidVec & yout = m_outputWS->dataY(spectraIn);
  MantidVec & eout = m_outputWS->dataE(spectraIn);
  // Need the original values so this is not a reference
  const MantidVec yValues = m_inputWS->readY(spectraIn);
  const MantidVec eValues = m_inputWS->readE(spectraIn);

  // get a pointer to the detectors that created the spectrum
  const std::set<detid_t> dets = m_inputWS->getSpectrum(spectraIn)->getDetectorIDs();

  std::set<detid_t>::const_iterator it = dets.begin();
  std::set<detid_t>::const_iterator iend = dets.end();
  if ( it == iend )
  {
    throw Exception::NotFoundError("No detectors found", spectraIn);
  }
  
  // Storage for the reciprocal wave vectors that are calculated as the 
  //correction proceeds
  std::vector<double> oneOverWaveVectors(yValues.size());
  for( ; it != iend ; ++it )
  {
    IDetector_const_sptr det_member = m_inputWS->getInstrument()->getDetector(*it);
    
    Parameter_sptr par = m_paraMap->get(det_member.get(),"3He(atm)");
    if ( !par )
    {
      throw Exception::NotFoundError("3He(atm)", spectraIn);
    }
    const double atms = par->value<double>();
    par = m_paraMap->get(det_member.get(),"wallT(m)");
    if ( !par )
    {
      throw Exception::NotFoundError("wallT(m)", spectraIn);
    }
    const double wallThickness = par->value<double>();
    double detRadius(0.0);
    V3D detAxis;
    getDetectorGeometry(det_member, detRadius, detAxis);

   // now get the sin of the angle, it's the magnitude of the cross product of unit vector along the detector tube axis and a unit vector directed from the sample to the detector centre
    V3D vectorFromSample = det_member->getPos() - m_samplePos;
    vectorFromSample.normalize();
    Quat rot = det_member->getRotation();
    // rotate the original cylinder object axis to get the detector axis in the actual instrument
    rot.rotate(detAxis); 
    detAxis.normalize();
    // Scalar product is quicker than cross product
    double cosTheta = detAxis.scalar_prod(vectorFromSample);
    double sinTheta = std::sqrt(1.0 - cosTheta*cosTheta);
    // Detector constant
    const double det_const = g_helium_prefactor*(detRadius - wallThickness)*atms/sinTheta;

    MantidVec::const_iterator yinItr = yValues.begin();
    MantidVec::const_iterator einItr = eValues.begin();
    MantidVec::iterator youtItr = yout.begin();
    MantidVec::iterator eoutItr = eout.begin();
    MantidVec::const_iterator xItr = m_inputWS->readX(spectraIn).begin();
    std::vector<double>::iterator wavItr = oneOverWaveVectors.begin();

    for( ; youtItr != yout.end(); ++youtItr, ++eoutItr)
    {
      if( it == dets.begin() )
      {
        *youtItr = 0.0;
        *eoutItr = 0.0;
        *wavItr = calculateOneOverK(*xItr, *(xItr + 1 ));
      }
      const double oneOverWave = *wavItr;
      const double factor = 1.0/detectorEfficiency(det_const*oneOverWave);
      *youtItr += (*yinItr)*factor;
      *eoutItr += (*einItr)*factor;
      ++yinItr; ++einItr;
      ++xItr; ++wavItr;
    }
  }
}
コード例 #8
0
/** Set the outline of the assembly. Creates an Object and sets m_shape point to
 * it.
 *  All child components must be detectors and positioned along a straight line
 * and have the same shape.
 *  The shape can be either a box or a cylinder.
 *  @return The shape of the outline: "cylinder", "box", ...
 */
boost::shared_ptr<Object> ObjCompAssembly::createOutline() {
  if (group.empty()) {
    throw Kernel::Exception::InstrumentDefinitionError("Empty ObjCompAssembly");
  }

  if (nelements() < 2) {
    g_log.warning("Creating outline with fewer than 2 elements. The outline displayed may be inaccurate.");
  }

  // Get information about the shape and size of a detector
  std::string type;
  int otype;
  std::vector<Kernel::V3D> vectors;
  double radius, height;
  boost::shared_ptr<const Object> obj = group.front()->shape();
  if (!obj) {
    throw Kernel::Exception::InstrumentDefinitionError(
        "Found ObjComponent without shape");
  }
  obj->GetObjectGeom(otype, vectors, radius, height);
  if (otype == 1) {
    type = "box";
  } else if (otype == 3) {
    type = "cylinder";
  } else {
    throw std::runtime_error(
        "IDF \"outline\" option is only allowed for assemblies containing "
        "components of types \"box\" or \"cylinder\".");
  }

  // Calculate the dimensions of the outline object

  // find the 'moments of inertia' of the assembly
  double Ixx = 0, Iyy = 0, Izz = 0, Ixy = 0, Ixz = 0, Iyz = 0;
  V3D Cmass; // 'center of mass' of the assembly
  for (const_comp_it it = group.begin(); it != group.end(); it++) {
    V3D p = (**it).getRelativePos();
    Cmass += p;
  }
  Cmass /= nelements();
  for (const_comp_it it = group.begin(); it != group.end(); it++) {
    V3D p = (**it).getRelativePos();
    double x = p.X() - Cmass.X(), x2 = x * x;
    double y = p.Y() - Cmass.Y(), y2 = y * y;
    double z = p.Z() - Cmass.Z(), z2 = z * z;
    Ixx += y2 + z2;
    Iyy += x2 + z2;
    Izz += y2 + x2;
    Ixy -= x * y;
    Ixz -= x * z;
    Iyz -= y * z;
  }
  // principal axes of the outline shape
  // vz defines the line through all pixel centres
  V3D vx, vy, vz;

  if (Ixx == 0) // pixels along x axis
  {
    vx = V3D(0, 1, 0);
    vy = V3D(0, 0, 1);
    vz = V3D(1, 0, 0);
  } else if (Iyy == 0) // pixels along y axis
  {
    vx = V3D(0, 0, 1);
    vy = V3D(1, 0, 0);
    vz = V3D(0, 1, 0);
  } else if (Izz == 0) // pixels along z axis
  {
    vx = V3D(1, 0, 0);
    vy = V3D(0, 1, 0);
    vz = V3D(0, 0, 1);
  } else {
    // Either the detectors are not perfectrly aligned or
    // vz is parallel to neither of the 3 axis x,y,z
    // This code is unfinished
    DblMatrix II(3, 3), Vec(3, 3), D(3, 3);
    II[0][0] = Ixx;
    II[0][1] = Ixy;
    II[0][2] = Ixz;
    II[1][0] = Ixy;
    II[1][1] = Iyy;
    II[1][2] = Iyz;
    II[2][0] = Ixz;
    II[2][1] = Iyz;
    II[2][2] = Izz;
    std::cerr << "Inertia matrix: " << II << II.determinant() << '\n';
    II.Diagonalise(Vec, D);
    std::cerr << "Vectors: " << Vec << '\n';
    std::cerr << "Moments: " << D << '\n';
    vx = V3D(Vec[0][0], Vec[1][0], Vec[2][0]);
    vy = V3D(Vec[0][1], Vec[1][1], Vec[2][1]);
    vz = V3D(Vec[0][2], Vec[1][2], Vec[2][2]);
  }

  // find assembly sizes along the principal axes
  double hx, hy, hz; // sizes along x,y, and z axis

  // maximum displacements from the mass centre along axis vx,vy, and vz
  // in positive (p) and negative (n) directions.
  // positive displacements are positive numbers and negative ones are negative
  double hxn = 0, hyn = 0, hzn = 0;
  double hxp = 0, hyp = 0, hzp = 0;
  for (const_comp_it it = group.begin(); it != group.end(); it++) {
    // displacement vector of a detector
    V3D p = (**it).getRelativePos() - Cmass;
    // its projection on the vx axis
    double h = p.scalar_prod(vx);
    if (h > hxp)
      hxp = h;
    if (h < hxn)
      hxn = h;
    // its projection on the vy axis
    h = p.scalar_prod(vy);
    if (h > hyp)
      hyp = h;
    if (h < hyn)
      hyn = h;
    // its projection on the vz axis
    h = p.scalar_prod(vz);
    if (h > hzp)
      hzp = h;
    if (h < hzn)
      hzn = h;
  }

  // calc the assembly sizes
  hx = hxp - hxn;
  hy = hyp - hyn;
  hz = hzp - hzn;
  // hx and hy must be practically zero
  if (hx > 1e-3 || hy > 1e-3) // arbitrary numbers
  {
    throw Kernel::Exception::InstrumentDefinitionError(
        "Detectors of a ObjCompAssembly do not lie on a staraight line");
  }

  // determine the order of the detectors to make sure that the texture
  // coordinates are correct
  bool firstAtBottom; // first detector is at the bottom of the outline shape
  // the bottom end is the one with the negative displacement from the centre
  firstAtBottom =
      ((**group.begin()).getRelativePos() - Cmass).scalar_prod(vz) < 0;

  // form the input string for the ShapeFactory
  std::ostringstream obj_str;
  if (type == "box") {

    if (hz == 0)
      hz = 0.1;

    hx = hy = 0;
    height = 0;
    V3D p0 = vectors[0];
    for (size_t i = 1; i < vectors.size(); ++i) {
      V3D p = vectors[i] - p0;
      double h = fabs(p.scalar_prod(vx));
      if (h > hx)
        hx = h;
      h = fabs(p.scalar_prod(vy));
      if (h > hy)
        hy = h;
      height = fabs(p.scalar_prod(vz));
      if (h > height)
        height = h;
    }

    vx *= hx / 2;
    vy *= hy / 2;
    vz *= hzp + height / 2;

    if (!firstAtBottom) {
      vz = vz * (-1);
    }

    // define the outline shape as cuboid
    V3D p_lfb = Cmass - vx - vy - vz;
    V3D p_lft = Cmass - vx - vy + vz;
    V3D p_lbb = Cmass - vx + vy - vz;
    V3D p_rfb = Cmass + vx - vy - vz;
    obj_str << "<cuboid id=\"shape\">";
    obj_str << "<left-front-bottom-point ";
    obj_str << "x=\"" << p_lfb.X();
    obj_str << "\" y=\"" << p_lfb.Y();
    obj_str << "\" z=\"" << p_lfb.Z();
    obj_str << "\"  />";
    obj_str << "<left-front-top-point ";
    obj_str << "x=\"" << p_lft.X();
    obj_str << "\" y=\"" << p_lft.Y();
    obj_str << "\" z=\"" << p_lft.Z();
    obj_str << "\"  />";
    obj_str << "<left-back-bottom-point ";
    obj_str << "x=\"" << p_lbb.X();
    obj_str << "\" y=\"" << p_lbb.Y();
    obj_str << "\" z=\"" << p_lbb.Z();
    obj_str << "\"  />";
    obj_str << "<right-front-bottom-point ";
    obj_str << "x=\"" << p_rfb.X();
    obj_str << "\" y=\"" << p_rfb.Y();
    obj_str << "\" z=\"" << p_rfb.Z();
    obj_str << "\"  />";
    obj_str << "</cuboid>";

  } else if (type == "cylinder") {
    // the outline is one detector height short
    hz += height;
    // shift Cmass to the end of the cylinder where the first detector is
    if (firstAtBottom) {
      Cmass += vz * hzn;
    } else {
      hzp += height;
      Cmass += vz * hzp;
      // inverse the vz axis
      vz = vz * (-1);
    }
    obj_str << "<segmented-cylinder id=\"stick\">";
    obj_str << "<centre-of-bottom-base ";
    obj_str << "x=\"" << Cmass.X();
    obj_str << "\" y=\"" << Cmass.Y();
    obj_str << "\" z=\"" << Cmass.Z();
    obj_str << "\" />";
    obj_str << "<axis x=\"" << vz.X() << "\" y=\"" << vz.Y() << "\" z=\""
            << vz.Z() << "\" /> ";
    obj_str << "<radius val=\"" << radius << "\" />";
    obj_str << "<height val=\"" << hz << "\" />";
    obj_str << "</segmented-cylinder>";
  }

  if (!obj_str.str().empty()) {
    boost::shared_ptr<Object> s = ShapeFactory().createShape(obj_str.str());
    setOutline(s);
    return s;
  }
  return boost::shared_ptr<Object>();
}
コード例 #9
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;
}