Beispiel #1
0
int Line::intersect(std::list<Kernel::V3D> &PntOut, const Cylinder &Cyl) const
/**
For the line that intersects the cylinder generate
add the point to the VecOut, return number of points
added. It does not check the points for validity.

@param PntOut :: Vector of points found by the line/cylinder intersection
@param Cyl :: Cylinder to intersect line with
@return Number of points found by intersection
*/
{
    const Kernel::V3D Cent = Cyl.getCentre();
    const Kernel::V3D Ax = Origin - Cent;
    const Kernel::V3D N = Cyl.getNormal();
    const double R = Cyl.getRadius();
    const double vDn = N.scalar_prod(Direct);
    const double vDA = N.scalar_prod(Ax);
    // First solve the equation of intersection
    double C[3];
    C[0] = 1.0 - (vDn * vDn);
    C[1] = 2.0 * (Ax.scalar_prod(Direct) - vDA * vDn);
    C[2] = Ax.scalar_prod(Ax) - (R * R + vDA * vDA);
    std::pair<std::complex<double>, std::complex<double>> SQ;
    const int ix = solveQuadratic(C, SQ);
    // This takes the centre displacement into account:
    return lambdaPair(ix, SQ, PntOut);
}
Beispiel #2
0
/**
 Calculate if the point R is on
 the cone (Note: have to be careful here
 since angle calcuation calcuates an angle.
 We need a distance for tolerance!)
 @param R :: Point to check
 @return 1 if on surface and 0 if not not on surface
 */
int Cone::onSurface(const Kernel::V3D &R) const {

    const Kernel::V3D cR = R - Centre;
    double rptAngle = cR.scalar_prod(Normal);
    rptAngle *= rptAngle / cR.scalar_prod(cR);
    const double eqn(sqrt(rptAngle));

    return (fabs(eqn - cangle) > Tolerance) ? 0 : 1;
}
Beispiel #3
0
/**
 Calculate if the point R is within
 the cone (return -1) or outside,
 (return 1)
 \todo NEEDS ON SURFACE CALCULATING::
 waiting for a point to cone distance function

 @param R :: Point to determine if in/out of cone
 @return Side of R
 */
int Cone::side(const Kernel::V3D &R) const {

    const Kernel::V3D cR = R - Centre;
    double rptAngle = cR.scalar_prod(Normal);
    rptAngle *= rptAngle / cR.scalar_prod(cR);
    const double eqn(sqrt(rptAngle));
    if (fabs(eqn - cangle) < Tolerance)
        return 0;
    return (eqn > cangle) ? 1 : -1;
}
Beispiel #4
0
    double Cone::distance(const Kernel::V3D& Pt) const
    /**
     Calculates the distance from the point to the Cone
     does not calculate the point on the cone that is closest
     @param Pt :: Point to calcuate from

     - normalise to a cone vertex at the origin
     - calculate the angle between the axis and the Point
     - Calculate the distance to P
     @return distance to Pt
     */
    {
      const Kernel::V3D Px = Pt - Centre;
      // test is the centre to point distance is zero
      if (Px.norm() < Tolerance)
        return Px.norm();
      double Pangle = Px.scalar_prod(Normal) / Px.norm();
      if (Pangle < 0.0)
        Pangle = acos(-Pangle);
      else
        Pangle = acos(Pangle);

      Pangle -= M_PI * alpha / 180.0;
      return Px.norm() * sin(Pangle);
    }
Beispiel #5
0
double Plane::distance(const Kernel::V3D &A) const
/**
  Determine the distance of point A from the plane
  returns a value relative to the normal
  @param A :: point to get distance from
  @return singed distance from point
*/
{
  return A.scalar_prod(NormV) - Dist;
}
Beispiel #6
0
int Line::intersect(std::list<Kernel::V3D> &PntOut, const Sphere &Sph) const
/**
For the line that intersects the cylinder generate
add the point to the VecOut, return number of points
added. It does not check the points for validity.

@param PntOut :: Vector of points found by the line/sphere intersection
@param Sph :: Sphere to intersect line with
@return Number of points found by intersection
*/
{
    // Nasty stripping of useful stuff from sphere
    const Kernel::V3D Ax = Origin - Sph.getCentre();
    const double R = Sph.getRadius();
    // First solve the equation of intersection
    double C[3];
    C[0] = 1;
    C[1] = 2.0 * Ax.scalar_prod(Direct);
    C[2] = Ax.scalar_prod(Ax) - R * R;
    std::pair<std::complex<double>, std::complex<double>> SQ;
    const int ix = solveQuadratic(C, SQ);
    return lambdaPair(ix, SQ, PntOut);
}
Beispiel #7
0
int Plane::setPlane(const Kernel::V3D &P, const Kernel::V3D &N)
/**
  Given a point and a normal direction set the plane
  @param P :: Point for plane to pass thought
  @param N :: Normal for the plane
  @retval 0 :: success
*/
{
  try {
    NormV = normalize(N);
  } catch (std::runtime_error &) {
    throw std::invalid_argument("Attempt to create Plane with zero normal");
  }
  Dist = P.scalar_prod(NormV);
  setBaseEqn();
  return 0;
}
Beispiel #8
0
/**
 * Returns whether the given reflection is allowed or not in this space group
 *
 * Space groups that contain translational symmetry cause certain reflections
 * to be absent due to the contributions of symmetry equivalent atoms to the
 * structure factor cancelling out. This method implements the procedure
 * described in ITA [1] to check whether a reflection is allowed or not
 * according to the symmetry operations in the space group. Please note that
 * certain arrangements of atoms can lead to additional conditions that can not
 * be determined using a space group's symmetry operations alone. For these
 * situations, Geometry::CrystalStructure can help.
 *
 * [1] International Tables for Crystallography (2006). Vol. A, ch. 12.3, p. 832
 *
 * @param hkl :: HKL to be checked.
 * @return :: true if the reflection is allowed, false otherwise.
 */
bool SpaceGroup::isAllowedReflection(const Kernel::V3D &hkl) const {
  for (const auto &operation : m_allOperations) {
    if (operation.hasTranslation()) {
      /* Floating point precision problem:
       *    (H . v) % 1.0 is not always exactly 0, so instead:
       *    | [(H . v) + delta] % 1.0 | > 1e-14 is checked
       * The transformation is only performed if necessary.
       */
      if ((fabs(fmod(fabs(hkl.scalar_prod(operation.reducedVector())) + 1e-15,
                     1.0)) > 1e-14) &&
          (operation.transformHKL(hkl) == hkl)) {
        return false;
      }
    }
  }

  return true;
}
Beispiel #9
0
double Cylinder::distance(const Kernel::V3D &A) const
/**
 Calculates the distance of point A from
 the surface of the  cylinder.
 @param A :: Point to calculate distance from
 @return :: +ve distance to the surface.

 \todo INCOMPLETE AS Does not deal with the case of
 non axis centre line  (has been updated?? )
 */
{
  // First find the normal going to the point
  const Kernel::V3D Amov = A - Centre;
  double lambda = Amov.scalar_prod(Normal);
  const Kernel::V3D Ccut = Normal * lambda;
  // The distance is from the centre line to the
  return fabs(Ccut.distance(Amov) - Radius);
}
Beispiel #10
0
/**
 * This function calculates the exponential contribution to the He3 tube
 * efficiency.
 * @param spectraIndex :: the current index to calculate
 * @param idet :: the current detector pointer
 * @throw out_of_range if twice tube thickness is greater than tube diameter
 * @return the exponential contribution for the given detector
 */
double He3TubeEfficiency::calculateExponential(
    std::size_t spectraIndex,
    boost::shared_ptr<const Geometry::IDetector> idet) {
  // Get the parameters for the current associated tube
  double pressure =
      this->getParameter("TubePressure", spectraIndex, "tube_pressure", idet);
  double tubethickness =
      this->getParameter("TubeThickness", spectraIndex, "tube_thickness", idet);
  double temperature = this->getParameter("TubeTemperature", spectraIndex,
                                          "tube_temperature", idet);

  double detRadius(0.0);
  Kernel::V3D detAxis;
  this->getDetectorGeometry(idet, detRadius, detAxis);
  double detDiameter = 2.0 * detRadius;
  double twiceTubeThickness = 2.0 * tubethickness;

  // 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 center
  Kernel::V3D vectorFromSample = idet->getPos() - this->samplePos;
  vectorFromSample.normalize();
  Kernel::Quat rot = idet->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);

  const double straight_path = detDiameter - twiceTubeThickness;
  if (std::fabs(straight_path - 0.0) < TOL) {
    throw std::out_of_range("Twice tube thickness cannot be greater than "
                            "or equal to the tube diameter");
  }

  const double pathlength = straight_path / sinTheta;
  return EXP_SCALAR_CONST * (pressure / temperature) * pathlength;
}
Beispiel #11
0
/**
 * Calculate volume.
 * @return The volume.
 */
double MeshObject::volume() const {
  // Select centre of bounding box as centre point.
  // For each triangle calculate the signed volume of
  // the tetrahedron formed by the triangle and the
  // centre point. Then add to total.

  BoundingBox bb = getBoundingBox();
  double cX = 0.5 * (bb.xMax() + bb.xMin());
  double cY = 0.5 * (bb.yMax() + bb.yMin());
  double cZ = 0.5 * (bb.zMax() + bb.zMin());
  Kernel::V3D centre(cX, cY, cZ);

  double volumeTimesSix(0.0);

  Kernel::V3D vertex1, vertex2, vertex3;
  for (size_t i = 0; getTriangle(i, vertex1, vertex2, vertex3); ++i) {
    Kernel::V3D a = vertex1 - centre;
    Kernel::V3D b = vertex2 - centre;
    Kernel::V3D c = vertex3 - centre;
    volumeTimesSix += a.scalar_prod(b.cross_prod(c));
  }

  return volumeTimesSix / 6.0;
}
Beispiel #12
0
/**
 * Make a map of the conversion factors between tof and D-spacing
 * for all pixel IDs in a workspace.
 * map vulcan should contain the module/module and stack/stack offset
 *
 * @param vulcan :: map between detector ID and vulcan correction factor.
 * @param offsetsWS :: OffsetsWorkspace to be filled.
 */
void LoadDspacemap::CalculateOffsetsFromVulcanFactors(
    std::map<detid_t, double> &vulcan,
    Mantid::DataObjects::OffsetsWorkspace_sptr offsetsWS) {
  // Get a pointer to the instrument contained in the workspace
  // At this point, instrument VULCAN has been created?
  Instrument_const_sptr instrument = offsetsWS->getInstrument();

  g_log.notice() << "Name of instrument = " << instrument->getName()
                 << std::endl;
  g_log.notice() << "Input map (dict):  size = " << vulcan.size() << std::endl;

  // To get all the detector ID's
  detid2det_map allDetectors;
  instrument->getDetectors(allDetectors);

  detid2det_map::const_iterator it;
  int numfinds = 0;
  g_log.notice() << "Input number of detectors = " << allDetectors.size()
                 << std::endl;

  // Get detector information
  double l1, beamline_norm;
  Kernel::V3D beamline, samplePos;
  instrument->getInstrumentParameters(l1, beamline, beamline_norm, samplePos);

  /*** A survey of parent detector
  std::map<detid_t, bool> parents;
  for (it = allDetectors.begin(); it != allDetectors.end(); it++){
    int32_t detid = it->first;

    // def boost::shared_ptr<const Mantid::Geometry::IDetector>
  IDetector_const_sptr;

    std::string parentname =
  it->second->getParent()->getComponentID()->getName();
    g_log.notice() << "Name = " << parentname << std::endl;
    // parents.insert(parentid, true);
  }
  ***/

  /*** Here some special configuration for VULCAN is hard-coded here!
   *   Including (1) Super-Parent Information
   ***/
  Kernel::V3D referencePos;
  detid_t anydetinrefmodule = 21 * 1250 + 5;

  std::map<detid_t, Geometry::IDetector_const_sptr>::iterator det_iter =
      allDetectors.find(anydetinrefmodule);

  if (det_iter == allDetectors.end()) {
    throw std::invalid_argument("Any Detector ID is Instrument's detector");
  }
  referencePos = det_iter->second->getParent()->getPos();
  double refl2 = referencePos.norm();
  double halfcosTwoThetaRef =
      referencePos.scalar_prod(beamline) / (refl2 * beamline_norm);
  double sinThetaRef = sqrt(0.5 - halfcosTwoThetaRef);
  double difcRef = sinThetaRef * (l1 + refl2) / CONSTANT;

  // Loop over all detectors in instrument to find the offset
  for (it = allDetectors.begin(); it != allDetectors.end(); ++it) {
    int detectorID = it->first;
    Geometry::IDetector_const_sptr det = it->second;
    double offset = 0.0;

    // Find the vulcan factor;
    double vulcan_factor = 0.0;
    std::map<detid_t, double>::const_iterator vulcan_iter =
        vulcan.find(detectorID);
    if (vulcan_iter != vulcan.end()) {
      vulcan_factor = vulcan_iter->second;
      numfinds++;
    }

    // g_log.notice() << "Selected Detector with ID = " << detectorID << "  ID2
    // = " << id2 << std::endl; proved to be same

    double intermoduleoffset = 0;
    double interstackoffset = 0;

    detid_t intermoduleid = detid_t(detectorID / 1250) * 1250 + 1250 - 2;
    vulcan_iter = vulcan.find(intermoduleid);
    if (vulcan_iter == vulcan.end()) {
      g_log.error() << "Cannot find inter-module offset ID = " << intermoduleid
                    << std::endl;
    } else {
      intermoduleoffset = vulcan_iter->second;
    }

    detid_t interstackid = detid_t(detectorID / 1250) * 1250 + 1250 - 1;
    vulcan_iter = vulcan.find(interstackid);
    if (vulcan_iter == vulcan.end()) {
      g_log.error() << "Cannot find inter-module offset ID = " << intermoduleid
                    << std::endl;
    } else {
      interstackoffset = vulcan_iter->second;
    }

    /***  This is the previous way to correct upon DIFC[module center pixel]
    // The actual factor is 10^(-value_in_the_file)
    vulcan_factor = pow(10.0,-vulcan_factor);
    // At this point, tof_corrected = vulcan_factor * tof_input
    // So this is the offset
    offset = vulcan_factor - 1.0;
    ***/

    /*** New approach to correct based on DIFC of each pixel
     *   Equation:  offset = DIFC^(pixel)/DIFC^(parent)*(1+vulcan_offset)-1
     *   offset should be close to 0
     ***/
    // 1. calculate DIFC
    Kernel::V3D detPos;
    detPos = det->getPos();

    // Now detPos will be set with respect to samplePos
    detPos -= samplePos;
    double l2 = detPos.norm();
    double halfcosTwoTheta =
        detPos.scalar_prod(beamline) / (l2 * beamline_norm);
    double sinTheta = sqrt(0.5 - halfcosTwoTheta);
    double difc_pixel = sinTheta * (l1 + l2) / CONSTANT;

    // Kernel::V3D parentPos = det->getParent()->getPos();
    // parentPos -= samplePos;
    // double l2parent = parentPos.norm();
    // double halfcosTwoThetaParent = parentPos.scalar_prod(beamline)/(l2 *
    // beamline_norm);
    // double sinThetaParent = sqrt(0.5 - halfcosTwoThetaParent);
    // double difc_parent = sinThetaParent*(l1+l2parent)/CONSTANT;

    /*** Offset Replicate Previous Result
    offset = difc_pixel/difc_parent*(pow(10.0, -vulcan_factor))-1.0;
    ***/

    offset =
        difc_pixel / difcRef * (pow(10.0, -(vulcan_factor + intermoduleoffset +
                                            interstackoffset))) -
        1.0;

    // Save in the map
    try {
      offsetsWS->setValue(detectorID, offset);

      if (intermoduleid != 27498 && intermoduleid != 28748 &&
          intermoduleid != 29998 && intermoduleid != 33748 &&
          intermoduleid != 34998 && intermoduleid != 36248) {
        g_log.error() << "Detector ID = " << detectorID
                      << "  Inter-Module ID = " << intermoduleid << std::endl;
        throw std::invalid_argument("Indexing error!");
      }

    } catch (std::invalid_argument &) {
      g_log.notice() << "Misses Detector ID = " << detectorID << std::endl;
    }
  } // for

  g_log.notice() << "Number of matched detectors =" << numfinds << std::endl;
}
Beispiel #13
0
int Plane::setSurface(const std::string &Pstr)
/**
   processes a standard MCNPX plane string:
   There are three types :
   - (A) px Distance
   - (B) p A B C D (equation Ax+By+Cz=D)
   - (C) p V3D V3D V3D
   @param Pstr :: String to make into a plane of type p{xyz} or p
   @return 0 on success, -ve of failure
*/
{
  // Two types of plane string p[x-z]  and p
  std::string Line = Pstr;
  std::string item;

  if (!Mantid::Kernel::Strings::section(Line, item) || tolower(item[0]) != 'p')
    return -1;
  // Only 3 need to be declared
  double surf[9] = {0.0, 0, 0, 0, 0};

  if (item.size() == 1) // PROCESS BASIC PLANE:
  {
    int cnt;
    for (cnt = 0; cnt < 9 && Mantid::Kernel::Strings::section(Line, surf[cnt]);
         cnt++)
      ;

    if (cnt != 4 && cnt != 9)
      return -3;
    if (cnt == 9) // V3D type
    {
      Kernel::V3D A = Kernel::V3D(surf[0], surf[1], surf[2]);
      Kernel::V3D B = Kernel::V3D(surf[3], surf[4], surf[5]);
      Kernel::V3D C = Kernel::V3D(surf[6], surf[7], surf[8]);
      B -= A;
      C -= A;
      NormV = B * C;
      NormV.normalize();
      Dist = A.scalar_prod(NormV);
    } else // Norm Equation:
    {
      NormV = Kernel::V3D(surf[0], surf[1], surf[2]);
      const double ll = NormV.normalize();
      if (ll < Tolerance) // avoid
        return -4;
      Dist = surf[3] / ll;
    }
  } else if (item.size() == 2) //  PROCESS px type PLANE
  {
    const int ptype = static_cast<int>(tolower(item[1]) - 'x');
    if (ptype < 0 || ptype > 2) // Not x,y,z
      return -5;
    surf[ptype] = 1.0;
    if (!Mantid::Kernel::Strings::convert(Line, Dist))
      return -6; // Too short or no number
    NormV = Kernel::V3D(surf[0], surf[1], surf[2]);
  } else
    return -3; // WRONG NAME

  setBaseEqn();
  return 0;
}