/// Retrieve and check the Start/EndX parameters, if set void Linear::setRange(const MantidVec& X, const MantidVec& Y) { //read in the values that the user selected double startX = getProperty("StartX"); double endX = getProperty("EndX"); //If the user didn't a start default to the start of the data if ( isEmpty(startX) ) startX = X.front(); //the default for the end is the end of the data if ( isEmpty(endX) ) endX = X.back(); // Check the validity of startX if ( startX < X.front() ) { g_log.warning("StartX out of range! Set to start of frame."); startX = X.front(); } // Now get the corresponding bin boundary that comes before (or coincides with) this value for (m_minX = 0; X[m_minX+1] < startX; ++m_minX) {} // Check the validity of endX and get the bin boundary that come after (or coincides with) it if ( endX >= X.back() || endX < startX ) { if ( endX != X.back() ) { g_log.warning("EndX out of range! Set to end of frame"); endX = X.back(); } m_maxX = static_cast<int>(Y.size()); } else { for (m_maxX = m_minX; X[m_maxX] < endX; ++m_maxX) {} } }
/** Calculates the rebin parameters in the case where the range of the second * workspace is * entirely within that of the first workspace. * 'Inclusion' is used in the sense of a set being included in anothre. * @param X1 :: The bin boundaries from the first workspace * @param i :: Indicates the index in X1 immediately before the overlap * region starts * @param X2 :: The bin boundaries from the second workspace * @param params :: A reference to the vector of rebinning parameters */ void MergeRuns::inclusionParams(const MantidVec &X1, int64_t &i, const MantidVec &X2, std::vector<double> ¶ms) const { // First calculate the number of bins in each workspace that are in the // overlap region int64_t overlapbins1, overlapbins2; for (overlapbins1 = 1; X1[i + overlapbins1] < X2.back(); ++overlapbins1) { } //++overlapbins1; overlapbins2 = X2.size() - 1; // In the overlap region, we want to use whichever one has the larger bins (on // average) if (overlapbins1 + 1 <= overlapbins2) { // In the case where the first workspace has larger bins it's easy // - just add the rest of X1's bins for (; i < static_cast<int64_t>(X1.size()); ++i) { params.push_back(X1[i] - X1[i - 1]); params.push_back(X1[i]); } } else { // In this case we want all of X2's bins first (without the first and last // boundaries) for (size_t j = 1; j < X2.size() - 1; ++j) { params.push_back(X2[j] - params.back()); params.push_back(X2[j]); } // And now those from X1 that lie above the overlap region i += overlapbins1; for (; i < static_cast<int64_t>(X1.size()); ++i) { params.push_back(X1[i] - params.back()); params.push_back(X1[i]); } } }
/** Calculates the rebin parameters in the case where the bins of the two * workspaces intersect. * 'Intersect' is used in the sense of two intersecting sets. * @param X1 :: The bin boundaries from the first workspace * @param i :: Indicates the index in X1 immediately before the overlap * region starts * @param X2 :: The bin boundaries from the second workspace * @param params :: A reference to the vector of rebinning parameters */ void MergeRuns::intersectionParams(const MantidVec &X1, int64_t &i, const MantidVec &X2, std::vector<double> ¶ms) const { // First calculate the number of bins in each workspace that are in the // overlap region int64_t overlapbins1, overlapbins2; overlapbins1 = X1.size() - i; for (overlapbins2 = 0; X2[overlapbins2] < X1.back(); ++overlapbins2) { } // We want to use whichever one has the larger bins (on average) if (overlapbins1 < overlapbins2) { // In this case we want the rest of the bins from the first workspace..... for (; i < static_cast<int64_t>(X1.size()); ++i) { params.push_back(X1[i] - X1[i - 1]); params.push_back(X1[i]); } // Now remove the last bin & boundary params.pop_back(); params.pop_back(); // ....and then the non-overlap ones from the second workspace for (size_t j = overlapbins2; j < X2.size(); ++j) { params.push_back(X2[j] - params.back()); params.push_back(X2[j]); } } else { // In this case we just have to add all the bins from the second workspace for (size_t j = 1; j < X2.size(); ++j) { params.push_back(X2[j] - params.back()); params.push_back(X2[j]); } } }
/** Calculates the rebin paramters in the case where the two input workspaces do * not overlap at all. * @param X1 :: The bin boundaries from the first workspace * @param X2 :: The bin boundaries from the second workspace * @param params :: A reference to the vector of rebinning parameters */ void MergeRuns::noOverlapParams(const MantidVec &X1, const MantidVec &X2, std::vector<double> ¶ms) const { // Add all the bins from the first workspace for (size_t i = 1; i < X1.size(); ++i) { params.push_back(X1[i - 1]); params.push_back(X1[i] - X1[i - 1]); } // Put a single bin in the 'gap' (but check first the 'gap' isn't zero) if (X1.back() < X2.front()) { params.push_back(X1.back()); params.push_back(X2.front() - X1.back()); } // Now add all the bins from the second workspace for (size_t j = 1; j < X2.size(); ++j) { params.push_back(X2[j - 1]); params.push_back(X2[j] - X2[j - 1]); } params.push_back(X2.back()); }
/** Calculates the overall normalization factor. * This multiplies result by (bin width * sum of monitor counts) / total frame * width. * @param X The X vector * @param Y The data vector * @param E The error vector */ void NormaliseToMonitor::normalisationFactor(const MantidVec &X, MantidVec *Y, MantidVec *E) { const double monitorSum = std::accumulate(Y->begin(), Y->end(), 0.0); const double range = X.back() - X.front(); MantidVec::size_type specLength = Y->size(); for (MantidVec::size_type j = 0; j < specLength; ++j) { const double factor = range / ((X[j + 1] - X[j]) * monitorSum); (*Y)[j] *= factor; (*E)[j] *= factor; } }
/** * @param tofMin Return value for minimum tof to be masked * @param tofMax Return value for maximum tof to be masked * @param tofPeak time-of-flight of the single crystal peak * @param tof tof-of-flight axis for the spectrum where the peak supposedly * exists */ void MaskPeaksWorkspace::getTofRange(double &tofMin, double &tofMax, const double tofPeak, const MantidVec &tof) { tofMin = tof.front(); tofMax = tof.back() - 1; if (!isEmpty(m_tofMin)) { tofMin = tofPeak + m_tofMin; } if (!isEmpty(m_tofMax)) { tofMax = tofPeak + m_tofMax; } }
/** * Get the start and end of the x-interval. * @param X :: The x-vector of a spectrum. * @param isHistogram :: Is the x-vector comming form a histogram? If it's true * the bin * centres are used. * @return :: A pair of start x and end x. */ std::pair<double, double> WienerSmooth::getStartEnd(const MantidVec &X, bool isHistogram) const { const size_t n = X.size(); if (n < 3) { // 3 is the smallest number for this method to work without breaking throw std::runtime_error( "Number of bins/data points cannot be smaller than 3."); } if (isHistogram) { return std::make_pair((X[0] + X[1]) / 2, (X[n - 1] + X[n - 2]) / 2); } // else return std::make_pair(X.front(), X.back()); }
/** * Use the binning information to generate a x-axis. * * @param xValues The new x-axis. * @param xmin The x-min to be used. * @param xmax The x-max to be used. * * @return The final delta value (absolute value). */ double ResampleX::determineBinning(MantidVec &xValues, const double xmin, const double xmax) { xValues.clear(); // clear out the x-values int numBoundaries(0); int reqNumBoundaries(m_numBins); int expNumBoundaries(m_numBins); if (m_isDistribution) reqNumBoundaries -= 1; // to get the VectorHelper to do the right thing else expNumBoundaries += 1; // should be one more bin boundary for histograms vector<double> params; // xmin, delta, xmax params.push_back(xmin); params.push_back(0.); // dummy delta value params.push_back(xmax); // constant binning is easy if (m_useLogBinning) { if (xmin == 0) throw std::invalid_argument("Cannot calculate log of xmin=0"); if (xmax == 0) throw std::invalid_argument("Cannot calculate log of xmax=0"); const int MAX_ITER(100); // things went wrong if we get this far // starting delta value assuming everything happens exactly double delta = (log(xmax) - log(xmin)) / static_cast<double>(m_numBins); double shift = .1; int sign = 0; for (int numIter = 0; numIter < MAX_ITER; ++numIter) { params[1] = -1. * delta; if (!m_isDistribution) params[2] = xmax + delta; numBoundaries = VectorHelper::createAxisFromRebinParams(params, xValues, true); if (numBoundaries == expNumBoundaries) { double diff = (xmax - xValues.back()); if (diff != 0.) { g_log.debug() << "Didn't get the exact xmax value: [xmax - xValues.back()=" << diff << "] [relative diff = " << fabs(100. * diff / xmax) << "%]\n"; g_log.debug() << "Resetting final x-value to xmax\n"; *(xValues.rbegin()) = xmax; } break; } else if (numBoundaries > expNumBoundaries) // too few points { delta *= (1. + shift); if (sign < 0) shift *= .9; sign = 1; } else // too many points { delta *= (1. - shift); if (sign > 0) shift *= .9; sign = -1; } } } else { params[1] = (xmax - xmin) / static_cast<double>(reqNumBoundaries); numBoundaries = VectorHelper::createAxisFromRebinParams(params, xValues, true); } if (numBoundaries != expNumBoundaries) { g_log.warning() << "Did not generate the requested number of bins: generated " << numBoundaries << " requested " << expNumBoundaries << "\n"; } // return the delta value so the caller can do debug printing return params[1]; }
/** * Copy over the metadata from the input matrix workspace to output *MDEventWorkspace * @param mdEventWS :: The output MDEventWorkspace where metadata are copied to. *The source of the metadata is the input matrix workspace * */ void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr &mdEventWS) const { // found detector which is not a monitor to get proper bin boundaries. size_t spectra_index(0); bool dector_found(false); for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) { try { auto det = m_InWS2D->getDetector(i); if (!det->isMonitor()) { spectra_index = i; dector_found = true; g_log.debug() << "Using spectra N " << i << " as the source of the bin " "boundaries for the " "resolution corrections \n"; break; } } catch (...) { } } if (!dector_found) g_log.warning() << "No detectors in the workspace are associated with " "spectra. Using spectrum 0 trying to retrieve the bin " "boundaries \n"; // retrieve representative bin boundaries MantidVec binBoundaries = m_InWS2D->readX(spectra_index); // check if the boundaries transformation is necessary if (m_Convertor->getUnitConversionHelper().isUnitConverted()) { if (!dynamic_cast<DataObjects::EventWorkspace *>(m_InWS2D.get())) { g_log.information() << " ConvertToMD converts input workspace units, but " "the bin boundaries are copied from the first " "workspace spectra. The resolution estimates can " "be incorrect if unit conversion depends on " "spectra number.\n"; UnitsConversionHelper &unitConv = m_Convertor->getUnitConversionHelper(); unitConv.updateConversion(spectra_index); for (double &binBoundarie : binBoundaries) { binBoundarie = unitConv.convertUnits(binBoundarie); } } // sort bin boundaries in case if unit transformation have swapped them. if (binBoundaries[0] > binBoundaries.back()) { g_log.information() << "Bin boundaries are not arranged monotonously. " "Sorting performed\n"; std::sort(binBoundaries.begin(), binBoundaries.end()); } } // Replacement for SpectraDetectorMap::createIDGroupsMap using the ISpectrum // objects instead auto mapping = boost::make_shared<det2group_map>(); for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) { const auto &dets = m_InWS2D->getSpectrum(i).getDetectorIDs(); if (!dets.empty()) { mapping->emplace(*dets.begin(), std::vector<detid_t>(dets.begin(), dets.end())); } } // The last experiment info should always be the one that refers // to latest converting workspace. All others should have had this // information set already uint16_t nexpts = mdEventWS->getNumExperimentInfo(); if (nexpts > 0) { ExperimentInfo_sptr expt = mdEventWS->getExperimentInfo(static_cast<uint16_t>(nexpts - 1)); expt->mutableRun().storeHistogramBinBoundaries(binBoundaries); expt->cacheDetectorGroupings(*mapping); } }