예제 #1
0
파일: MDPlane.cpp 프로젝트: DanNixon/mantid
/** Constructor with normal and point
 *
 * @param normal :: normal to the plane. Points that are in the direction of the
 *normal of the plane are considered to be bounded by it.
 * @param point :: any point that is on the plane
 */
MDPlane::MDPlane(const Mantid::Kernel::VMD &normal,
                 const Mantid::Kernel::VMD &point) {
  m_nd = normal.getNumDims();
  if ((m_nd < 1) || (m_nd > 100))
    throw std::invalid_argument(
        "MDPlane::ctor(): Invalid number of dimensions in the normal vector !");
  if (point.getNumDims() != normal.getNumDims())
    throw std::invalid_argument("MDPlane::ctor(): Inconsistent number of "
                                "dimensions in the normal/point vectors!");
  construct(normal, point);
}
예제 #2
0
/** Apply the transformation to an input vector (as a VMD type).
 * This wraps the apply(in,out) method (and will be slower!)
 *
 * @param inputVector :: an inD-length vector
 * @return the output vector as VMD
 */
Mantid::Kernel::VMD
CoordTransform::applyVMD(const Mantid::Kernel::VMD &inputVector) const {
  if (inputVector.getNumDims() != inD)
    throw std::runtime_error("CoordTransform::apply(): inputVector has the "
                             "wrong number of coordinates!");
  coord_t *outArray = new coord_t[outD];
  this->apply(inputVector.getBareArray(), outArray);
  VMD out(outD, outArray);
  delete[] outArray;
  return out;
}
/** Constructor
 *
 * @param workspace :: IMDWorkspace to plot
 * @param logScale :: true to plot Y in log scale
 * @param start :: start point in N-dimensions of the line
 * @param end :: end point in N-dimensions of the line
 * @param normalize :: method for normalizing the line
 * @param isDistribution :: is this a distribution (divide by bin width?)
 * @return
 */
MantidQwtIMDWorkspaceData::MantidQwtIMDWorkspaceData(Mantid::API::IMDWorkspace_const_sptr workspace, const bool logScale,
    Mantid::Kernel::VMD start, Mantid::Kernel::VMD end,
    Mantid::API::MDNormalization normalize,
    bool isDistribution)
 : m_workspace(workspace),
   m_logScale(logScale), m_minPositive(0),
   m_preview(false),
   m_start(start),
   m_end(end),
   m_normalization(normalize),
   m_isDistribution(isDistribution),
   m_transform(NULL),
   m_plotAxis(PlotDistance), m_currentPlotAxis(PlotDistance)
{
  if (start.getNumDims() == 1 && end.getNumDims() == 1)
  {
    if (start[0] == 0.0 && end[0] == 0.0)
    {
      // Default start and end. Find the limits
      Mantid::Geometry::VecIMDDimension_const_sptr nonIntegDims = m_workspace->getNonIntegratedDimensions();
      std::string alongDim = "";
      if (!nonIntegDims.empty())
        alongDim = nonIntegDims[0]->getName();
      else
        alongDim = m_workspace->getDimension(0)->getName();

      size_t nd = m_workspace->getNumDims();
      m_start = VMD(nd);
      m_end = VMD(nd);
      for (size_t d=0; d<nd; d++)
      {
        IMDDimension_const_sptr dim = m_workspace->getDimension(d);
        if (dim->getDimensionId() == alongDim)
        {
          // All the way through in the single dimension
          m_start[d] = dim->getMinimum();
          m_end[d] = dim->getMaximum();
        }
        else
        {
          // Mid point along each dimension
          m_start[d] = (dim->getMaximum() + dim->getMinimum()) / 2.0f;
          m_end[d] = m_start[d];
        }
      }
    }
  }
  // Unit direction of the line
  m_dir = m_end - m_start;
  m_dir.normalize();
  // And cache the X/Y values
  this->cacheLinePlot();
}
예제 #4
0
/** Set the width of the line in each dimensions
 * @param width :: vector for the width in each dimension. X dimension stands in for the XY plane width */
void LineViewer::setThickness(Mantid::Kernel::VMD width)
{
  if (m_ws && width.getNumDims() != m_ws->getNumDims())
    throw std::runtime_error("LineViewer::setThickness(): Invalid number of dimensions in the width vector.");
  m_thickness = width;
  updateStartEnd();
}
예제 #5
0
/** Set the end point of the line to integrate
 * @param end :: vector for the end point */
void LineViewer::setEnd(Mantid::Kernel::VMD end)
{
  if (m_ws && end.getNumDims() != m_ws->getNumDims())
    throw std::runtime_error("LineViewer::setEnd(): Invalid number of dimensions in the end vector.");
  m_end = end;
  updateStartEnd();
}
예제 #6
0
/** Set the start point of the line to integrate
 * @param start :: vector for the start point */
void LineViewer::setStart(Mantid::Kernel::VMD start)
{
  if (m_ws && start.getNumDims() != m_ws->getNumDims())
    throw std::runtime_error("LineViewer::setStart(): Invalid number of dimensions in the start vector.");
  m_start = start;
  updateStartEnd();
}
예제 #7
0
/** Constructor helper method
 * @param min :: nd-sized vector of the minimum edge of the box in each
 * dimension
 * @param max :: nd-sized vector of the maximum edge of the box
 * */
void MDBoxImplicitFunction::construct(const Mantid::Kernel::VMD &min,
                                      const Mantid::Kernel::VMD &max) {
  size_t nd = min.size();
  if (max.size() != nd)
    throw std::invalid_argument(
        "MDBoxImplicitFunction::ctor(): Min and max vector sizes must match!");
  if (nd == 0 || nd > 100)
    throw std::invalid_argument(
        "MDBoxImplicitFunction::ctor(): Invalid number of dimensions!");

  double volume = 1;
  for (size_t d = 0; d < nd; d++) {
    volume *= (max[d] - min[d]);

    // Make two parallel planes per dimension

    // Normal on the min side, so it faces towards +X
    std::vector<coord_t> normal_min(nd, 0);
    normal_min[d] = +1.0;
    // Origin just needs to have its X set to the value. Other coords are
    // irrelevant
    std::vector<coord_t> origin_min(nd, 0);
    origin_min[d] = static_cast<coord_t>(min[d]);
    // Build the plane
    MDPlane p_min(normal_min, origin_min);
    this->addPlane(p_min);

    // Normal on the max side, so it faces towards -X
    std::vector<coord_t> normal_max(nd, 0);
    normal_max[d] = -1.0;
    // Origin just needs to have its X set to the value. Other coords are
    // irrelevant
    std::vector<coord_t> origin_max(nd, 0);
    origin_max[d] = static_cast<coord_t>(max[d]);
    // Build the plane
    MDPlane p_max(normal_max, origin_max);
    this->addPlane(p_max);
  }
  m_volume = volume;
}
예제 #8
0
  /** Build a coordinate transformation based on an origin and orthogonal basis vectors.
   * This can reduce the number of dimensions. For example:
   *
   * - The input position is X=(x,y,z)
   * - The origin is X0=(x0,y0,z0)
   * - The basis vectors are U and V (reducing from 3 to 2D)
   * - The output position u = (X-X0).U = X.U - X0.U = x*Ux + y*Uy + z*Uz + (X0.U)
   * - The output position v = (X-X0).V = X.V - X0.V = x*Vx + y*Vy + z*Vz + (X0.V)
   *
   * And this allows us to create the affine matrix:
   *
   * | Ux  Uy  Uz  X0.U | | x |   | u |
   * | Vx  Vy  Vz  X0.V | | y | = | v |
   * | 0   0   0    1   | | z |   | 1 |
   *                      | 1 |
   *
   * @param origin :: origin (in the inDimension), which corresponds to (0,0,...) in outD
   * @param axes :: a list of basis vectors. There must be outD vectors (one for each output dimension)
   *        and each vector must be of length inD (all coordinates in the input dimension).
   *        The vectors must be properly orthogonal: not coplanar or collinear. This is not checked!
   * @param scaling :: a vector of size outD of the scaling to perform in each of the
   *        OUTPUT dimensions.
   * @throw if inconsistent vector sizes are received, or zero-length
   */
  void CoordTransformAffine::buildOrthogonal(const Mantid::Kernel::VMD & origin, const std::vector< Mantid::Kernel::VMD> & axes,
      const Mantid::Kernel::VMD & scaling)
  {
    if (origin.size() != inD)
      throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): the origin must be in the dimensions of the input workspace (length inD).");
    if (axes.size() != outD)
      throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): you must give as many basis vectors as there are dimensions in the output workspace.");
    if (scaling.size() != outD)
      throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): the size of the scaling vector must be the same as the number of dimensions in the output workspace.");

    // Start with identity
    affineMatrix.identityMatrix();

    for (size_t i=0; i<axes.size(); i++)
    {
      if (axes[i].length() == 0.0)
        throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): one of the basis vector was of zero length.");
      if (axes[i].size() != inD)
        throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): one of the basis vectors had the wrong number of dimensions (must be inD).");
      // Normalize each axis to unity
      VMD basis = axes[i];
      basis.normalize();
      // The row of the affine matrix = the unit vector
      for (size_t j=0; j<basis.size(); j++)
        affineMatrix[i][j] = basis[j] * scaling[i];

      // Now account for the translation
      coord_t transl = 0;
      for (size_t j=0; j<basis.size(); j++)
        transl += origin[j] * basis[j]; // dot product of origin * basis aka ( X0 . U )
      // The last column of the matrix = the translation movement
      affineMatrix[i][inD] = -transl * scaling[i];
    }

    // Copy into the raw matrix (for speed)
    copyRawMatrix();
  }
예제 #9
0
/** Returns the signal (normalized by volume) at a given coordinates
 * or 0 if masked
 *
 * @param coords :: coordinate as a VMD vector
 * @param normalization :: how to normalize the signal returned
 * @return normalized signal
 */
signal_t IMDWorkspace::getSignalWithMaskAtVMD(
    const Mantid::Kernel::VMD &coords,
    const Mantid::API::MDNormalization &normalization) const {
  return this->getSignalWithMaskAtCoord(coords.getBareArray(), normalization);
}
/**
  * Make 1D MatrixWorkspace
  */
void ConvertMDHistoToMatrixWorkspace::make1DWorkspace() {
  IMDHistoWorkspace_sptr inputWorkspace = getProperty("InputWorkspace");

  // This code is copied from MantidQwtIMDWorkspaceData
  Mantid::Geometry::VecIMDDimension_const_sptr nonIntegDims =
      inputWorkspace->getNonIntegratedDimensions();

  std::string alongDim = "";
  if (!nonIntegDims.empty())
    alongDim = nonIntegDims[0]->getDimensionId();
  else
    alongDim = inputWorkspace->getDimension(0)->getDimensionId();

  size_t nd = inputWorkspace->getNumDims();
  Mantid::Kernel::VMD start = VMD(nd);
  Mantid::Kernel::VMD end = VMD(nd);

  size_t id = 0;
  for (size_t d = 0; d < nd; d++) {
    Mantid::Geometry::IMDDimension_const_sptr dim =
        inputWorkspace->getDimension(d);
    if (dim->getDimensionId() == alongDim) {
      // All the way through in the single dimension
      start[d] = dim->getMinimum();
      end[d] = dim->getMaximum();
      id = d; // We take the first non integrated dimension to be the diemnsion
              // of interest.
    } else {
      // Mid point along each dimension
      start[d] = (dim->getMaximum() + dim->getMinimum()) / 2.0f;
      end[d] = start[d];
    }
  }

  // Unit direction of the line
  Mantid::Kernel::VMD dir = end - start;
  dir.normalize();

  std::string normProp = getPropertyValue("Normalization");

  Mantid::API::MDNormalization normalization;
  if (normProp == "NoNormalization") {
    normalization = NoNormalization;
  } else if (normProp == "VolumeNormalization") {
    normalization = VolumeNormalization;
  } else if (normProp == "NumEventsNormalization") {
    normalization = NumEventsNormalization;
  } else {
    normalization = NoNormalization;
  }

  auto line = inputWorkspace->getLineData(start, end, normalization);

  MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(
      "Workspace2D", 1, line.x.size(), line.y.size());
  outputWorkspace->dataY(0).assign(line.y.begin(), line.y.end());
  outputWorkspace->dataE(0).assign(line.e.begin(), line.e.end());

  const size_t numberTransformsToOriginal =
      inputWorkspace->getNumberTransformsToOriginal();

  CoordTransform_const_sptr transform =
      boost::make_shared<NullCoordTransform>(inputWorkspace->getNumDims());
  if (numberTransformsToOriginal > 0) {
    const size_t indexToLastTransform = numberTransformsToOriginal - 1;
    transform = CoordTransform_const_sptr(
        inputWorkspace->getTransformToOriginal(indexToLastTransform),
        NullDeleter());
  }

  assert(line.x.size() == outputWorkspace->dataX(0).size());

  std::string xAxisLabel = inputWorkspace->getDimension(id)->getName();
  const bool autoFind = this->getProperty("FindXAxis");
  if (autoFind) {
    // We look to the original workspace if possbible to find the dimension of
    // interest to plot against.
    id = findXAxis(start, end, transform.get(), inputWorkspace.get(), g_log, id,
                   xAxisLabel);
  }

  for (size_t i = 0; i < line.x.size(); ++i) {
    // Coordinates in the workspace being plotted
    VMD wsCoord = start + dir * line.x[i];

    VMD inTargetCoord = transform->applyVMD(wsCoord);
    outputWorkspace->dataX(0)[i] = inTargetCoord[id];
  }

  boost::shared_ptr<Kernel::Units::Label> labelX =
      boost::dynamic_pointer_cast<Kernel::Units::Label>(
          Kernel::UnitFactory::Instance().create("Label"));
  labelX->setLabel(xAxisLabel);
  outputWorkspace->getAxis(0)->unit() = labelX;

  outputWorkspace->setYUnitLabel("Signal");

  setProperty("OutputWorkspace", outputWorkspace);
}
예제 #11
0
/** Obtain coordinates for a line plot through a MDWorkspace.
 * Cross the workspace from start to end points, recording the signal along the
 *lin at either bin boundaries, or halfway between bin boundaries (which is bin
 *centres if the line is dimension aligned). If recording halfway values then
 *omit points in masked bins.
 *
 * @param start :: coordinates of the start point of the line
 * @param end :: coordinates of the end point of the line
 * @param normalize :: how to normalize the signal
 * @returns :: LinePlot with x as the boundaries of the bins, relative
 * to start of the line, y set to the normalized signal for each bin with
 * Length = length(x) - 1 and e as the error vector for each bin.
 * @param bin_centres :: if true then record points halfway between bin
 *boundaries, otherwise record on bin boundaries
 */
IMDWorkspace::LinePlot MDHistoWorkspace::getLinePoints(
    const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end,
    Mantid::API::MDNormalization normalize, const bool bin_centres) const {
  LinePlot line;

  size_t nd = this->getNumDims();
  if (start.getNumDims() != nd)
    throw std::runtime_error("Start point must have the same number of "
                             "dimensions as the workspace.");
  if (end.getNumDims() != nd)
    throw std::runtime_error(
        "End point must have the same number of dimensions as the workspace.");

  // Unit-vector of the direction
  VMD dir = end - start;
  const auto length = dir.normalize();

// Vector with +1 where direction is positive, -1 where negative
#define sgn(x) ((x < 0) ? -1.0f : ((x > 0.) ? 1.0f : 0.0f))
  VMD dirSign(nd);
  for (size_t d = 0; d < nd; d++) {
    dirSign[d] = sgn(dir[d]);
  }
  const size_t BADINDEX = size_t(-1);

  // Dimensions of the workspace
  boost::scoped_array<size_t> index(new size_t[nd]);
  boost::scoped_array<size_t> numBins(new size_t[nd]);
  for (size_t d = 0; d < nd; d++) {
    IMDDimension_const_sptr dim = this->getDimension(d);
    index[d] = BADINDEX;
    numBins[d] = dim->getNBins();
  }

  const std::set<coord_t> boundaries =
      getBinBoundariesOnLine(start, end, nd, dir, length);

  if (boundaries.empty()) {
    this->makeSinglePointWithNaN(line.x, line.y, line.e);

    // Require x.size() = y.size()+1 if recording bin boundaries
    if (!bin_centres)
      line.x.push_back(length);

    return line;
  } else {
    // Get the first point
    std::set<coord_t>::iterator it;
    it = boundaries.cbegin();

    coord_t lastLinePos = *it;
    VMD lastPos = start + (dir * lastLinePos);
    if (!bin_centres) {
      line.x.push_back(lastLinePos);
    }

    ++it;
    coord_t linePos = 0;
    for (; it != boundaries.cend(); ++it) {
      // This is our current position along the line
      linePos = *it;

      // This is the full position at this boundary
      VMD pos = start + (dir * linePos);

      // Position in the middle of the bin
      VMD middle = (pos + lastPos) * 0.5;

      // Find the signal in this bin
      const auto linearIndex =
          this->getLinearIndexAtCoord(middle.getBareArray());

      if (bin_centres && !this->getIsMaskedAt(linearIndex)) {
        coord_t bin_centrePos =
            static_cast<coord_t>((linePos + lastLinePos) * 0.5);
        line.x.push_back(bin_centrePos);
      } else if (!bin_centres)
        line.x.push_back(linePos);

      if (linearIndex < m_length) {

        auto normalizer = getNormalizationFactor(normalize, linearIndex);
        // And add the normalized signal/error to the list too
        auto signal = this->getSignalAt(linearIndex) * normalizer;
        if (boost::math::isinf(signal)) {
          // The plotting library (qwt) doesn't like infs.
          signal = std::numeric_limits<signal_t>::quiet_NaN();
        }
        if (!bin_centres || !this->getIsMaskedAt(linearIndex)) {
          line.y.push_back(signal);
          line.e.push_back(this->getErrorAt(linearIndex) * normalizer);
        }
        // Save the position for next bin
        lastPos = pos;
      } else {
        // Invalid index. This shouldn't happen
        line.y.push_back(std::numeric_limits<signal_t>::quiet_NaN());
        line.e.push_back(std::numeric_limits<signal_t>::quiet_NaN());
      }

      lastLinePos = linePos;

    } // for each unique boundary

    // If all bins were masked
    if (line.x.size() == 0) {
      this->makeSinglePointWithNaN(line.x, line.y, line.e);
    }
  }
  return line;
}