/** * Constructor helper * @param workspace :: MDWorkspace * @param function :: implicit function or NULL for none. Gains ownership of the pointer. * @param beginPos :: Start position * @param endPos :: End position */ void MDHistoWorkspaceIterator::init(const MDHistoWorkspace * workspace, Mantid::Geometry::MDImplicitFunction * function, size_t beginPos, size_t endPos) { m_ws = workspace; if (m_ws == NULL) throw std::invalid_argument("MDHistoWorkspaceIterator::ctor(): NULL workspace given."); m_begin = beginPos; m_pos = m_begin; m_function = function; m_max = endPos; if (m_max > m_ws->getNPoints()) m_max = m_ws->getNPoints(); if (m_max < m_pos) throw std::invalid_argument("MDHistoWorkspaceIterator::ctor(): End point given is before the start point."); m_nd = m_ws->getNumDims(); m_center = new coord_t[m_nd]; m_origin = new coord_t[m_nd]; m_binWidth = new coord_t[m_nd]; m_index = new size_t[m_nd]; m_indexMax = new size_t[m_nd]; m_indexMaker = new size_t[m_nd]; Utils::NestedForLoop::SetUp(m_nd, m_index, 0); // Initalize all these values for (size_t d=0; d<m_nd; d++) { IMDDimension_const_sptr dim = m_ws->getDimension(d); m_center[d] = 0; m_origin[d] = dim->getMinimum(); m_binWidth[d] = dim->getBinWidth(); m_indexMax[d] = dim->getNBins(); } Utils::NestedForLoop::SetUpIndexMaker(m_nd, m_indexMaker, m_indexMax); // Initialize the current index from the start position. Utils::NestedForLoop::GetIndicesFromLinearIndex(m_nd, m_pos, m_indexMaker, m_indexMax, m_index); // Make sure that the first iteration is at a point inside the implicit function if (m_function) { // Calculate the center of the 0-th bin for (size_t d=0; d<m_nd; d++) m_center[d] = m_origin[d] + 0.5f * m_binWidth[d]; // Skip on if the first point is NOT contained if (!m_function->isPointContained(m_center)) next(); } }
/* Extract the geometry and function information @param eventWs : event workspace to get the information from. */ void MDEWLoadingPresenter::extractMetadata( Mantid::API::IMDEventWorkspace_sptr eventWs) { using namespace Mantid::Geometry; MDGeometryBuilderXML<NoDimensionPolicy> refresh; xmlBuilder = refresh; // Reassign. std::vector<MDDimensionExtents<coord_t>> ext = eventWs->getMinimumExtents(5); std::vector<IMDDimension_sptr> dimensions; size_t nDimensions = eventWs->getNumDims(); for (size_t d = 0; d < nDimensions; d++) { IMDDimension_const_sptr inDim = eventWs->getDimension(d); coord_t min = ext[d].getMin(); coord_t max = ext[d].getMax(); if (min > max) { min = 0.0; max = 1.0; } // std::cout << "dim " << d << min << " to " << max << std::endl; axisLabels.push_back(makeAxisTitle(inDim)); MDHistoDimension_sptr dim(new MDHistoDimension( inDim->getName(), inDim->getName(), inDim->getMDFrame(), min, max, inDim->getNBins())); dimensions.push_back(dim); } // Configuring the geometry xml builder allows the object panel associated // with this reader to later // determine how to display all geometry related properties. if (nDimensions > 0) { xmlBuilder.addXDimension(dimensions[0]); } if (nDimensions > 1) { xmlBuilder.addYDimension(dimensions[1]); } if (nDimensions > 2) { xmlBuilder.addZDimension(dimensions[2]); } if (nDimensions > 3) { tDimension = dimensions[3]; xmlBuilder.addTDimension(tDimension); } m_isSetup = true; }
/** Get ordered list of boundaries in position-along-the-line coordinates * * @param start :: start of the line * @param end :: end of the line * @param nd :: number of dimensions * @param dir :: vector of the direction * @param length :: unit-vector of the direction * @returns :: ordered list of boundaries */ std::set<coord_t> MDHistoWorkspace::getBinBoundariesOnLine(const VMD &start, const VMD &end, size_t nd, const VMD &dir, coord_t length) const { std::set<coord_t> boundaries; // Start with the start/end points, if they are within range. if (pointInWorkspace(this, start)) boundaries.insert(0.0f); if (pointInWorkspace(this, end)) boundaries.insert(length); // Next, we go through each dimension and see where the bin boundaries // intersect the line. for (size_t d = 0; d < nd; d++) { IMDDimension_const_sptr dim = getDimension(d); coord_t lineStartX = start[d]; if (dir[d] != 0.0) { for (size_t i = 0; i <= dim->getNBins(); i++) { // Position in this coordinate coord_t thisX = dim->getX(i); // Position along the line. Is this between the start and end of it? coord_t linePos = (thisX - lineStartX) / dir[d]; if (linePos >= 0 && linePos <= length) { // Full position VMD pos = start + (dir * linePos); // This is a boundary if the line point is inside the workspace if (pointInWorkspace(this, pos)) boundaries.insert(linePos); } } } } return boundaries; }
/** 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; }