/** * Create the output workspace in the right shape. * @param inWS : Input workspace for dimensionality * @param pbins : User provided binning * @param logger : Logging object * @return */ MDHistoWorkspace_sptr createShapedOutput(IMDHistoWorkspace const *const inWS, std::vector<std::vector<double>> pbins, Logger &logger) { const size_t nDims = inWS->getNumDims(); std::vector<Mantid::Geometry::IMDDimension_sptr> dimensions(nDims); for (size_t i = 0; i < nDims; ++i) { IMDDimension_const_sptr inDim = inWS->getDimension(i); auto outDim = boost::make_shared<MDHistoDimension>(inDim.get()); // Apply dimensions as inputs. if (i < pbins.size() && integrationBinning(pbins[i])) { auto binning = pbins[i]; outDim->setRange( 1 /*single bin*/, static_cast<Mantid::coord_t>(binning.front()) /*min*/, static_cast<Mantid::coord_t>( binning.back()) /*max*/); // Set custom min, max and nbins. } else if (i < pbins.size() && similarBinning(pbins[i])) { auto binning = pbins[i]; Mantid::coord_t pMin = static_cast<Mantid::coord_t>(binning.front()); Mantid::coord_t pMax = static_cast<Mantid::coord_t>(binning.back()); size_t numberOfBins; setMinMaxBins(pMin, pMax, numberOfBins, inDim, logger); outDim->setRange(numberOfBins, static_cast<Mantid::coord_t>(pMin) /*min*/, static_cast<Mantid::coord_t>( pMax) /*max*/); // Set custom min, max and nbins. } dimensions[i] = outDim; } return boost::make_shared<MDHistoWorkspace>(dimensions); }
//----------------------------------------------------------------------------- /// @return the label for the X axis QString MantidQwtIMDWorkspaceData::getXAxisLabel() const { QString xLabel; if ( m_originalWorkspace.expired() ) return xLabel; // Empty string if (m_currentPlotAxis >= 0) { // One of the dimensions of the original IMDDimension_const_sptr dim = m_originalWorkspace.lock()->getDimension(m_currentPlotAxis); xLabel = QString::fromStdString(dim->getName()) + " (" + QString::fromStdWString(dim->getUnits().utf8()) + ")"; } else { // Distance // Distance, or not set. xLabel = "Distance from start"; // if (dimX->getUnits() == dimY->getUnits()) // xLabel += " (" + dimX->getUnits() + ")"; // else // xLabel += " (undefined units)"; // break; } return xLabel; }
/** @return true if the point is within the workspace (including the max edges) * */ bool pointInWorkspace(const MDHistoWorkspace *ws, const VMD &point) { for (size_t d = 0; d < ws->getNumDims(); d++) { IMDDimension_const_sptr dim = ws->getDimension(d); if ((point[d] < dim->getMinimum()) || (point[d] > dim->getMaximum())) return false; } return true; }
/** * 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->getUnits(), 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; }
/** Set the original workspace, to show the axes plot choice */ void LinePlotOptions::setOriginalWorkspace(Mantid::API::IMDWorkspace_sptr ws) { if (!ws) return; for (size_t d = 0; d < (ws->getNumDims()); d++) { IMDDimension_const_sptr dim = ws->getDimension(d); std::string text = dim->getName(); std::string tooltip = "Use the " + dim->getName() + " dimension as the X plot axis."; const bool bIntegrated = dim->getIsIntegrated(); // Index into the radio buttons array int index = int(d) + 2; if (m_radPlots.size() > index) { m_radPlots[index]->setText(QString::fromStdString(text)); m_radPlots[index]->setToolTip(QString::fromStdString(tooltip)); } else addPlotRadioButton(text, tooltip, bIntegrated); } }
bool MDGeometryBuilderXML<CheckDimensionPolicy>::addZDimension( IMDDimension_const_sptr dimension) const { bool bAdded = false; if (dimension.get() != NULL) { applyPolicyChecking(dimension); addOrdinaryDimension(dimension); m_spZDimension = dimension; m_changed = true; bAdded = true; } return bAdded; }
/* Extract the geometry and function information This implementation is an override of the base-class method, which deals with the more common event based route. However the SQW files will provide complete dimensions with ranges already set. Less work needs to be done here than for event workspaces where the extents of each dimension need to be individually extracted. @param eventWs : event workspace to get the information from. */ void SQWLoadingPresenter::extractMetadata( const Mantid::API::IMDEventWorkspace &eventWs) { using namespace Mantid::Geometry; MDGeometryBuilderXML<NoDimensionPolicy> refresh; this->xmlBuilder = refresh; // Reassign. 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); axisLabels.push_back(makeAxisTitle(*inDim)); // Copy the dimension, but set the ID and name to be the same. This is an // assumption in bintohistoworkspace. dimensions.push_back(boost::make_shared<MDHistoDimension>( inDim->getName(), inDim->getName(), inDim->getMDFrame(), inDim->getMinimum(), inDim->getMaximum(), size_t{10})); } // 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) { this->xmlBuilder.addXDimension(dimensions[0]); } if (nDimensions > 1) { this->xmlBuilder.addYDimension(dimensions[1]); } if (nDimensions > 2) { this->xmlBuilder.addZDimension(dimensions[2]); } if (nDimensions > 3) { this->tDimension = dimensions[3]; this->xmlBuilder.addTDimension(this->tDimension); } this->m_isSetup = true; }
bool MDGeometryBuilderXML<CheckDimensionPolicy>::addOrdinaryDimension( IMDDimension_const_sptr dimensionToAdd) const { bool bAdded = false; // Addition fails by default. if (dimensionToAdd.get() != NULL) { CompareIMDDimension_const_sptr comparitor(dimensionToAdd); DimensionContainerType::iterator location = std::find_if( m_vecDimensions.begin(), m_vecDimensions.end(), comparitor); if (location == m_vecDimensions.end()) { m_vecDimensions.push_back(dimensionToAdd); bAdded = true; m_changed = true; } } return bAdded; }
/** 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; }
/** 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(); }
/* Extract the geometry and function information @param histoWs : histogram workspace to get the information from. */ void MDHWLoadingPresenter::extractMetadata( const Mantid::API::IMDHistoWorkspace &histoWs) { using namespace Mantid::Geometry; MDGeometryBuilderXML<NoDimensionPolicy> refresh; xmlBuilder = refresh; // Reassign. std::vector<IMDDimension_sptr> dimensions; size_t nDimensions = histoWs.getNumDims(); for (size_t d = 0; d < nDimensions; d++) { IMDDimension_const_sptr inDim = histoWs.getDimension(d); coord_t min = inDim->getMinimum(); coord_t max = inDim->getMaximum(); if (min > max) { min = 0.0; max = 1.0; } // std::cout << "dim " << d << min << " to " << max << '\n'; axisLabels.push_back(makeAxisTitle(*inDim)); dimensions.push_back(boost::make_shared<MDHistoDimension>( inDim->getName(), inDim->getName(), inDim->getMDFrame(), min, max, inDim->getNBins())); } // 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; }
bool operator()(IMDDimension_const_sptr b) { return _a->getDimensionId() == b->getDimensionId(); }
/** Execute the algorithm. */ void BinaryOperationMD::exec() { // Get the properties m_lhs = getProperty(inputPropName1()); m_rhs = getProperty(inputPropName2()); m_out = getProperty(outputPropName()); // Flip LHS and RHS if commutative and : // 1. A = B + A -> becomes -> A += B // 1. C = 1 + A -> becomes -> C = A + 1 (number is always on RHS if // possible) if (this->commutative() && ((m_out == m_rhs) || boost::dynamic_pointer_cast<WorkspaceSingleValue>(m_lhs))) { // So we flip RHS/LHS Mantid::API::IMDWorkspace_sptr temp = m_lhs; m_lhs = m_rhs; m_rhs = temp; } // Do not compare conventions if one is single value if (!boost::dynamic_pointer_cast<WorkspaceSingleValue>(m_rhs)) { if (m_lhs->getConvention() != m_rhs->getConvention()) { throw std::runtime_error( "Workspaces have different conventions for Q. " "Use algorithm ChangeQConvention on one workspace. "); } } // Can't do A = 1 / B if (boost::dynamic_pointer_cast<MatrixWorkspace>(m_lhs)) throw std::invalid_argument("BinaryOperationMD: can't have a " "MatrixWorkspace (e.g. WorkspaceSingleValue) " "as the LHS argument of " + this->name() + "."); // Check the inputs. First cast to everything m_lhs_event = boost::dynamic_pointer_cast<IMDEventWorkspace>(m_lhs); m_lhs_histo = boost::dynamic_pointer_cast<MDHistoWorkspace>(m_lhs); m_lhs_scalar = boost::dynamic_pointer_cast<WorkspaceSingleValue>(m_lhs); m_rhs_event = boost::dynamic_pointer_cast<IMDEventWorkspace>(m_rhs); m_rhs_histo = boost::dynamic_pointer_cast<MDHistoWorkspace>(m_rhs); m_rhs_scalar = boost::dynamic_pointer_cast<WorkspaceSingleValue>(m_rhs); // MDEventWorkspaces only: // If you have to clone any WS, and the operation is commutative, and is NOT // in-place, then clone the one that is file-backed. if (this->commutative() && (m_lhs_event && m_rhs_event) && (m_out != m_lhs)) { if (m_rhs_event->isFileBacked() && !m_lhs_event->isFileBacked()) { // So we flip RHS/LHS Mantid::API::IMDWorkspace_sptr temp = m_lhs; m_lhs = m_rhs; m_rhs = temp; m_lhs_event = boost::dynamic_pointer_cast<IMDEventWorkspace>(m_lhs); m_rhs_event = boost::dynamic_pointer_cast<IMDEventWorkspace>(m_rhs); } } this->checkInputs(); if (m_out == m_lhs) { // A = A * B. -> we will do A *= B } else { // C = A + B. -> So first we clone A (lhs) into C IAlgorithm_sptr clone = this->createChildAlgorithm("CloneMDWorkspace", 0.0, 0.5, true); clone->setProperty("InputWorkspace", m_lhs); clone->executeAsChildAlg(); m_out = clone->getProperty("OutputWorkspace"); } // Okay, at this point we are ready to do, e.g., // "m_out /= m_rhs" if (!m_out) throw std::runtime_error("Error creating the output workspace"); if (!m_rhs) throw std::runtime_error("No RHS workspace specified!"); m_operand_event = boost::dynamic_pointer_cast<IMDEventWorkspace>(m_rhs); m_operand_histo = boost::dynamic_pointer_cast<MDHistoWorkspace>(m_rhs); m_operand_scalar = boost::dynamic_pointer_cast<WorkspaceSingleValue>(m_rhs); m_out_event = boost::dynamic_pointer_cast<IMDEventWorkspace>(m_out); m_out_histo = boost::dynamic_pointer_cast<MDHistoWorkspace>(m_out); if (m_out_event) { // Call the templated virtual function for this type of MDEventWorkspace this->execEvent(); } else if (m_out_histo) { // MDHistoWorkspace as the output if (m_operand_histo) { if (m_out_histo->getNumDims() != m_operand_histo->getNumDims()) throw std::invalid_argument( "Cannot perform " + this->name() + " on MDHistoWorkspace's with a different number of dimensions."); if (m_out_histo->getNPoints() != m_operand_histo->getNPoints()) throw std::invalid_argument( "Cannot perform " + this->name() + " on MDHistoWorkspace's with a different number of points."); // Check that the dimensions span the same size, warn if they don't for (size_t d = 0; d < m_out_histo->getNumDims(); d++) { IMDDimension_const_sptr dimA = m_out_histo->getDimension(0); IMDDimension_const_sptr dimB = m_operand_histo->getDimension(0); if (dimA->getMinimum() != dimB->getMinimum() || dimA->getMaximum() != dimB->getMaximum()) g_log.warning() << "Dimension " << d << " (" << dimA->getName() << ") has different extents in the two " "MDHistoWorkspaces. The operation may not make " "sense!" << std::endl; } this->execHistoHisto(m_out_histo, m_operand_histo); } else if (m_operand_scalar) this->execHistoScalar(m_out_histo, m_operand_scalar); else throw std::runtime_error( "Unexpected operand workspace type. Expected MDHistoWorkspace or " "WorkspaceSingleValue, got " + m_rhs->id()); // When operating on MDHistoWorkspaces, add a simple flag // that will be checked in BinMD to avoid binning a modified workspace if (m_out_histo->getNumExperimentInfo() == 0) // Create a run if needed m_out_histo->addExperimentInfo(ExperimentInfo_sptr(new ExperimentInfo())); m_out_histo->getExperimentInfo(0)->mutableRun().addProperty( new PropertyWithValue<std::string>("mdhisto_was_modified", "1"), true); } else { throw std::runtime_error( "Unexpected output workspace type. Expected MDEventWorkspace or " "MDHistoWorkspace, got " + m_out->id()); } // Give the output setProperty("OutputWorkspace", m_out); }
/** 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; }