/** * Disable points in the workpsace in the way that points which are not included * in any of specified * sections are not used when fitting given workspace * @param ws :: Workspace to disable points in * @param sections :: Section we want to use for fitting */ void ALCBaselineModellingModel::disableUnwantedPoints( MatrixWorkspace_sptr ws, const std::vector<IALCBaselineModellingModel::Section> §ions) { // Whether point with particular index should be disabled const size_t numBins = ws->blocksize(); std::vector<bool> toDisable(numBins, true); // Find points which are in at least one section, and exclude them from // disable list for (size_t i = 0; i < numBins; ++i) { for (auto it = sections.begin(); it != sections.end(); ++it) { if (ws->x(0)[i] >= it->first && ws->x(0)[i] <= it->second) { toDisable[i] = false; break; // No need to check other sections } } } // XXX: Points are disabled by settings their errors to very high value. This // makes those // points to have very low weights during the fitting, effectively // disabling them. const double DISABLED_ERR = std::numeric_limits<double>::max(); // Disable chosen points for (size_t i = 0; i < numBins; ++i) { if (toDisable[i]) { ws->mutableE(0)[i] = DISABLED_ERR; } } }
/** Rebins the distributions and sets error values. */ MatrixWorkspace_sptr VesuvioL1ThetaResolution::processDistribution(MatrixWorkspace_sptr ws, const double binWidth) { const size_t numHist = ws->getNumberHistograms(); double xMin(DBL_MAX); double xMax(DBL_MIN); for (size_t i = 0; i < numHist; i++) { auto &x = ws->x(i); xMin = std::min(xMin, x.front()); xMax = std::max(xMax, x.back()); } std::stringstream binParams; binParams << xMin << "," << binWidth << "," << xMax; IAlgorithm_sptr rebin = AlgorithmManager::Instance().create("Rebin"); rebin->initialize(); rebin->setChild(true); rebin->setLogging(false); rebin->setProperty("InputWorkspace", ws); rebin->setProperty("OutputWorkspace", "__rebin"); rebin->setProperty("Params", binParams.str()); rebin->execute(); ws = rebin->getProperty("OutputWorkspace"); for (size_t i = 0; i < numHist; i++) { auto &y = ws->y(i); auto &e = ws->mutableE(i); std::transform(y.begin(), y.end(), e.begin(), [](double x) { return sqrt(x); }); } return ws; }
/** Create an output workspace of the appropriate (histogram or event) type * and * copy over the data * @param inputWS The input workspace */ API::MatrixWorkspace_sptr ConvertUnits::setupOutputWorkspace( const API::MatrixWorkspace_const_sptr inputWS) { MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); // If input and output workspaces are NOT the same, create a new workspace // for // the output if (outputWS != inputWS) { outputWS = inputWS->clone(); } if (!m_inputEvents && m_distribution) { // Loop over the histograms (detector spectra) Progress prog(this, 0.0, 0.2, m_numberOfSpectra); PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS)) for (int64_t i = 0; i < static_cast<int64_t>(m_numberOfSpectra); ++i) { PARALLEL_START_INTERUPT_REGION // Take the bin width dependency out of the Y & E data auto &X = outputWS->x(i); auto &Y = outputWS->mutableY(i); auto &E = outputWS->mutableE(i); for (size_t j = 0; j < outputWS->blocksize(); ++j) { const double width = std::abs(X[j + 1] - X[j]); Y[j] *= width; E[j] *= width; } prog.report("Convert to " + m_outputUnit->unitID()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION }
/**Convert a binned workspace to point data * * @param workspace :: The input workspace * @return the converted workspace containing point data */ MatrixWorkspace_sptr SplineInterpolation::convertBinnedData(MatrixWorkspace_sptr workspace) const { if (workspace->isHistogramData()) { const size_t histNo = workspace->getNumberHistograms(); const size_t size = workspace->y(0).size(); // make a new workspace for the point data MatrixWorkspace_sptr pointWorkspace = WorkspaceFactory::Instance().create(workspace, histNo, size, size); // loop over each histogram for (size_t i = 0; i < histNo; ++i) { const auto &xValues = workspace->x(i); pointWorkspace->setSharedY(i, workspace->sharedY(i)); auto &newXValues = pointWorkspace->mutableX(i); // set x values to be average of bin bounds for (size_t j = 0; j < size; ++j) { newXValues[j] = (xValues[j] + xValues[j + 1]) / 2; } } return pointWorkspace; } return workspace; }
MatrixWorkspace_sptr CalculateIqt::removeInvalidData(MatrixWorkspace_sptr workspace) { auto binning = (workspace->blocksize() + 1) / 2; auto binV = workspace->x(0)[binning]; workspace = cropWorkspace(workspace, binV); return replaceSpecialValues(workspace); }
/** * Sum counts from the input workspace in lambda along lines of constant Q by * projecting to "virtual lambda" at a reference angle twoThetaR. * * @param detectorWS [in] :: the input workspace in wavelength * @return :: the output workspace in wavelength */ MatrixWorkspace_sptr ReflectometryReductionOne2::sumInQ(MatrixWorkspace_sptr detectorWS) { // Construct the output array in virtual lambda MatrixWorkspace_sptr IvsLam = constructIvsLamWS(detectorWS); // Loop through each input group (and corresponding output spectrum) const size_t numGroups = detectorGroups().size(); for (size_t groupIdx = 0; groupIdx < numGroups; ++groupIdx) { auto &detectors = detectorGroups()[groupIdx]; auto &outputE = IvsLam->dataE(groupIdx); // Loop through each spectrum in the detector group for (auto spIdx : detectors) { // Get the angle of this detector and its size in twoTheta const double twoTheta = getDetectorTwoTheta(m_spectrumInfo, spIdx); const double bTwoTheta = getDetectorTwoThetaRange(spIdx); // Check X length is Y length + 1 const auto &inputX = detectorWS->x(spIdx); const auto &inputY = detectorWS->y(spIdx); const auto &inputE = detectorWS->e(spIdx); if (inputX.size() != inputY.size() + 1) { throw std::runtime_error( "Expected input workspace to be histogram data (got X len=" + std::to_string(inputX.size()) + ", Y len=" + std::to_string(inputY.size()) + ")"); } // Create a vector for the projected errors for this spectrum. // (Output Y values can simply be accumulated directly into the output // workspace, but for error values we need to create a separate error // vector for the projected errors from each input spectrum and then // do an overall sum in quadrature.) std::vector<double> projectedE(outputE.size(), 0.0); // Process each value in the spectrum const int ySize = static_cast<int>(inputY.size()); for (int inputIdx = 0; inputIdx < ySize; ++inputIdx) { // Do the summation in Q sumInQProcessValue(inputIdx, twoTheta, bTwoTheta, inputX, inputY, inputE, detectors, groupIdx, IvsLam, projectedE); } // Sum errors in quadrature const int eSize = static_cast<int>(outputE.size()); for (int outIdx = 0; outIdx < eSize; ++outIdx) { outputE[outIdx] += projectedE[outIdx] * projectedE[outIdx]; } } // Take the square root of all the accumulated squared errors for this // detector group. Assumes Gaussian errors double (*rs)(double) = std::sqrt; std::transform(outputE.begin(), outputE.end(), outputE.begin(), rs); } return IvsLam; }
/** * Extracts time bin width from workspace parameter * * The method uses the difference between first and second x-value of the * first spectrum as time bin width. If the workspace does not contain proper * data (0 spectra or less than 2 x-values), the method throws an * std::invalid_argument-exception Otherwise it calls setDeltaT. * * @param matrixWorkspace :: MatrixWorkspace with at least one spectrum with *at * least two x-values. */ void PoldiFitPeaks2D::setDeltaTFromWorkspace( const MatrixWorkspace_sptr &matrixWorkspace) { if (matrixWorkspace->getNumberHistograms() < 1) { throw std::invalid_argument("MatrixWorkspace does not contain any data."); } auto &xData = matrixWorkspace->x(0); if (xData.size() < 2) { throw std::invalid_argument( "Cannot process MatrixWorkspace with less than 2 x-values."); } // difference between first and second x-value is assumed to be the bin // width. setDeltaT(matrixWorkspace->x(0)[1] - matrixWorkspace->x(0)[0]); }
/** * Construct an "empty" output workspace in virtual-lambda for summation in Q. * The workspace will have the same x values as the input workspace but the y * values will all be zero. * * @return : a 1D workspace where y values are all zero */ MatrixWorkspace_sptr ReflectometryReductionOne2::constructIvsLamWS(MatrixWorkspace_sptr detectorWS) { // There is one output spectrum for each detector group const size_t numGroups = detectorGroups().size(); // Calculate the number of bins based on the min/max wavelength, using // the same bin width as the input workspace const double binWidth = (detectorWS->x(0).back() - detectorWS->x(0).front()) / static_cast<double>(detectorWS->blocksize()); const int numBins = static_cast<int>( std::ceil((wavelengthMax() - wavelengthMin()) / binWidth)); // Construct the histogram with these X values. Y and E values are zero. const BinEdges xValues(numBins, LinearGenerator(wavelengthMin(), binWidth)); // Create the output workspace MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create( detectorWS, numGroups, numBins, numBins - 1); // Loop through each detector group in the input for (size_t groupIdx = 0; groupIdx < numGroups; ++groupIdx) { // Get the detectors in this group auto &detectors = detectorGroups()[groupIdx]; // Set the x values for this spectrum outputWS->setBinEdges(groupIdx, xValues); // Set the detector ID from the twoThetaR detector. const size_t twoThetaRIdx = twoThetaRDetectorIdx(detectors); auto &outSpec = outputWS->getSpectrum(groupIdx); const detid_t twoThetaRDetID = m_spectrumInfo->detector(twoThetaRIdx).getID(); outSpec.clearDetectorIDs(); outSpec.addDetectorID(twoThetaRDetID); // Set the spectrum number from the twoThetaR detector SpectrumNumber specNum = detectorWS->indexInfo().spectrumNumber(twoThetaRIdx); auto indexInf = outputWS->indexInfo(); indexInf.setSpectrumNumbers(specNum, specNum); outputWS->setIndexInfo(indexInf); } return outputWS; }
MatrixWorkspace_sptr JoinISISPolarizationEfficiencies::interpolateHistogramWorkspace( MatrixWorkspace_sptr ws, size_t const maxSize) { ws->setDistribution(true); auto const &x = ws->x(0); auto const dX = (x.back() - x.front()) / double(maxSize); std::vector<double> params(2 * maxSize + 1); for (size_t i = 0; i < maxSize; ++i) { params[2 * i] = x.front() + dX * double(i); params[2 * i + 1] = dX; } params.back() = x.back(); auto alg = createChildAlgorithm("InterpolatingRebin"); alg->setProperty("InputWorkspace", ws); alg->setProperty("Params", params); alg->setProperty("OutputWorkspace", "dummy"); alg->execute(); MatrixWorkspace_sptr interpolatedWS = alg->getProperty("OutputWorkspace"); assert(interpolatedWS->y(0).size() == maxSize); assert(interpolatedWS->x(0).size() == maxSize + 1); return interpolatedWS; }
MatrixWorkspace_sptr JoinISISPolarizationEfficiencies::interpolatePointDataWorkspace( MatrixWorkspace_sptr ws, size_t const maxSize) { auto const &x = ws->x(0); auto const startX = x.front(); auto const endX = x.back(); Counts yVals(maxSize, 0.0); auto const dX = (endX - startX) / double(maxSize - 1); Points xVals(maxSize, LinearGenerator(startX, dX)); auto newHisto = Histogram(xVals, yVals); interpolateLinearInplace(ws->histogram(0), newHisto); auto interpolatedWS = boost::make_shared<Workspace2D>(); interpolatedWS->initialize(1, newHisto); assert(interpolatedWS->y(0).size() == maxSize); return interpolatedWS; }
double ReflectometryReductionOne2::findIvsLamRangeMin( MatrixWorkspace_sptr detectorWS, const std::vector<size_t> &detectors, const double lambda) { double projectedMin = 0.0; const size_t spIdx = findIvsLamRangeMinDetector(detectors); const double twoTheta = getDetectorTwoTheta(m_spectrumInfo, spIdx); const double bTwoTheta = getDetectorTwoThetaRange(spIdx); // For bLambda, use the average bin size for this spectrum const auto &xValues = detectorWS->x(spIdx); double bLambda = (xValues[xValues.size() - 1] - xValues[0]) / static_cast<int>(xValues.size()); double dummy = 0.0; getProjectedLambdaRange(lambda, twoTheta, bLambda, bTwoTheta, detectors, projectedMin, dummy, m_partialBins); return projectedMin; }
/** Convert a workspace to Q * * @param inputWS : The input workspace (in wavelength) to convert to Q * @return : output workspace in Q */ MatrixWorkspace_sptr ReflectometryReductionOne2::convertToQ(MatrixWorkspace_sptr inputWS) { bool const moreThanOneDetector = inputWS->getDetector(0)->nDets() > 1; bool const shouldCorrectAngle = !(*getProperty("ThetaIn")).isDefault() && !summingInQ(); if (shouldCorrectAngle && moreThanOneDetector) { if (inputWS->getNumberHistograms() > 1) { throw std::invalid_argument( "Expected a single group in " "ProcessingInstructions to be able to " "perform angle correction, found " + std::to_string(inputWS->getNumberHistograms())); } MatrixWorkspace_sptr IvsQ = inputWS->clone(); auto &XOut0 = IvsQ->mutableX(0); const auto &XIn0 = inputWS->x(0); double const theta = getProperty("ThetaIn"); double const factor = 4.0 * M_PI * sin(theta * M_PI / 180.0); std::transform(XIn0.rbegin(), XIn0.rend(), XOut0.begin(), [factor](double x) { return factor / x; }); auto &Y0 = IvsQ->mutableY(0); auto &E0 = IvsQ->mutableE(0); std::reverse(Y0.begin(), Y0.end()); std::reverse(E0.begin(), E0.end()); IvsQ->getAxis(0)->unit() = UnitFactory::Instance().create("MomentumTransfer"); return IvsQ; } else { auto convertUnits = this->createChildAlgorithm("ConvertUnits"); convertUnits->initialize(); convertUnits->setProperty("InputWorkspace", inputWS); convertUnits->setProperty("Target", "MomentumTransfer"); convertUnits->setProperty("AlignBins", false); convertUnits->execute(); MatrixWorkspace_sptr IvsQ = convertUnits->getProperty("OutputWorkspace"); return IvsQ; } }
void TOFSANSResolutionByPixel::exec() { MatrixWorkspace_sptr inWS = getProperty("InputWorkspace"); double deltaR = getProperty("DeltaR"); double R1 = getProperty("SourceApertureRadius"); double R2 = getProperty("SampleApertureRadius"); const bool doGravity = getProperty("AccountForGravity"); // Check the input checkInput(inWS); // Setup outputworkspace auto outWS = setupOutputWorkspace(inWS); // Convert to meters deltaR /= 1000.0; R1 /= 1000.0; R2 /= 1000.0; // The moderator workspace needs to match the data workspace // in terms of wavelength binning const MatrixWorkspace_sptr sigmaModeratorVSwavelength = getModeratorWorkspace(inWS); // create interpolation table from sigmaModeratorVSwavelength Kernel::Interpolation lookUpTable; const auto &xInterpolate = sigmaModeratorVSwavelength->points(0); const auto &yInterpolate = sigmaModeratorVSwavelength->y(0); // prefer the input to be a pointworkspace and create interpolation function if (sigmaModeratorVSwavelength->isHistogramData()) { g_log.notice() << "mid-points of SigmaModerator histogram bins will be " "used for interpolation."; } for (size_t i = 0; i < xInterpolate.size(); ++i) { lookUpTable.addPoint(xInterpolate[i], yInterpolate[i]); } // Calculate the L1 distance const V3D samplePos = inWS->getInstrument()->getSample()->getPos(); const V3D sourcePos = inWS->getInstrument()->getSource()->getPos(); const V3D SSD = samplePos - sourcePos; const double L1 = SSD.norm(); // Get the collimation length double LCollim = getProperty("CollimationLength"); if (LCollim == 0.0) { auto collimationLengthEstimator = SANSCollimationLengthEstimator(); LCollim = collimationLengthEstimator.provideCollimationLength(inWS); g_log.information() << "No collimation length was specified. A default " "collimation length was estimated to be " << LCollim << '\n'; } else { g_log.information() << "The collimation length is " << LCollim << '\n'; } const int numberOfSpectra = static_cast<int>(inWS->getNumberHistograms()); Progress progress(this, 0.0, 1.0, numberOfSpectra); const auto &spectrumInfo = inWS->spectrumInfo(); for (int i = 0; i < numberOfSpectra; i++) { IDetector_const_sptr det; if (!spectrumInfo.hasDetectors(i)) { g_log.information() << "Workspace index " << i << " has no detector assigned to it - discarding\n"; continue; } // If no detector found or if it's masked or a monitor, skip onto the next // spectrum if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i)) continue; const double L2 = spectrumInfo.l2(i); TOFSANSResolutionByPixelCalculator calculator; const double waveLengthIndependentFactor = calculator.getWavelengthIndependentFactor(R1, R2, deltaR, LCollim, L2); // Multiplicative factor to go from lambda to Q // Don't get fooled by the function name... const double theta = spectrumInfo.twoTheta(i); double sinTheta = sin(0.5 * theta); double factor = 4.0 * M_PI * sinTheta; const auto &xIn = inWS->x(i); const size_t xLength = xIn.size(); // Gravity correction std::unique_ptr<GravitySANSHelper> grav; if (doGravity) { grav = Kernel::make_unique<GravitySANSHelper>(spectrumInfo, i, getProperty("ExtraLength")); } // Get handles on the outputWorkspace auto &yOut = outWS->mutableY(i); // for each wavelenght bin of each pixel calculate a q-resolution for (size_t j = 0; j < xLength - 1; j++) { // use the midpoint of each bin const double wl = (xIn[j + 1] + xIn[j]) / 2.0; // Calculate q. Alternatively q could be calculated using ConvertUnit // If we include a gravity correction we need to adjust sinTheta // for each wavelength (in Angstrom) if (doGravity) { double sinThetaGrav = grav->calcSinTheta(wl); factor = 4.0 * M_PI * sinThetaGrav; } const double q = factor / wl; // wavelenght spread from bin assumed to be const double sigmaSpreadFromBin = xIn[j + 1] - xIn[j]; // Get the uncertainty in Q auto sigmaQ = calculator.getSigmaQValue(lookUpTable.value(wl), waveLengthIndependentFactor, q, wl, sigmaSpreadFromBin, L1, L2); // Insert the Q value and the Q resolution into the outputworkspace yOut[j] = sigmaQ; } progress.report("Computing Q resolution"); } // Set the y axis label outWS->setYUnitLabel("QResolution"); setProperty("OutputWorkspace", outWS); }
/**Executes the main part of the algorithm that handles the conversion of the * units * @param inputWS :: the input workspace that will be converted * @throw std::runtime_error :: If the workspace has invalid X axis binning * @return A pointer to a MatrixWorkspace_sptr that contains the converted units */ MatrixWorkspace_sptr ConvertUnits::executeUnitConversion(const API::MatrixWorkspace_sptr inputWS) { // A WS holding BinEdges cannot have less than 2 values, as a bin has // 2 edges, having less than 2 values would mean that the WS contains Points if (inputWS->x(0).size() < 2) { std::stringstream msg; msg << "Input workspace has invalid X axis binning parameters. Should " "have " "at least 2 values. Found " << inputWS->x(0).size() << "."; throw std::runtime_error(msg.str()); } if (inputWS->x(0).front() > inputWS->x(0).back() || inputWS->x(m_numberOfSpectra / 2).front() > inputWS->x(m_numberOfSpectra / 2).back()) throw std::runtime_error("Input workspace has invalid X axis binning " "parameters. X values should be increasing."); MatrixWorkspace_sptr outputWS; // Check whether there is a quick conversion available double factor, power; if (m_inputUnit->quickConversion(*m_outputUnit, factor, power)) // If test fails, could also check whether a quick conversion in the // opposite // direction has been entered { outputWS = this->convertQuickly(inputWS, factor, power); } else { outputWS = this->convertViaTOF(m_inputUnit, inputWS); } // If the units conversion has flipped the ascending direction of X, reverse // all the vectors if (!outputWS->x(0).empty() && (outputWS->x(0).front() > outputWS->x(0).back() || outputWS->x(m_numberOfSpectra / 2).front() > outputWS->x(m_numberOfSpectra / 2).back())) { this->reverse(outputWS); } // Need to lop bins off if converting to energy transfer. // Don't do for EventWorkspaces, where you can easily rebin to recover the // situation without losing information /* This is an ugly test - could be made more general by testing for DBL_MAX values at the ends of all spectra, but that would be less efficient */ if (m_outputUnit->unitID().find("Delta") == 0 && !m_inputEvents) outputWS = this->removeUnphysicalBins(outputWS); // Rebin the data to common bins if requested, and if necessary bool alignBins = getProperty("AlignBins"); if (alignBins && !WorkspaceHelpers::commonBoundaries(outputWS)) outputWS = this->alignBins(outputWS); // If appropriate, put back the bin width division into Y/E. if (m_distribution && !m_inputEvents) // Never do this for event workspaces { this->putBackBinWidth(outputWS); } return outputWS; }
//------------------------------------------------------------------------------------------------ /// @cond // Local function used within validateInputs() below in a call to // std::list::sort(compare) // to order the input workspaces by the start of their frame (i.e. the first X // value). static bool compare(MatrixWorkspace_sptr first, MatrixWorkspace_sptr second) { return (first->x(0).front() < second->x(0).front()); }
/** Convert the workspace units using TOF as an intermediate step in the * conversion * @param fromUnit :: The unit of the input workspace * @param inputWS :: The input workspace * @returns A shared pointer to the output workspace */ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF( Kernel::Unit_const_sptr fromUnit, API::MatrixWorkspace_const_sptr inputWS) { using namespace Geometry; // Let's see if we are using a TableWorkspace to override parameters TableWorkspace_sptr paramWS = getProperty("DetectorParameters"); // See if we have supplied a DetectorParameters Workspace // TODO: Check if paramWS is NULL and if so throw an exception // const std::string l1ColumnLabel("l1"); // Let's check all the columns exist and are readable try { auto spectraColumnTmp = paramWS->getColumn("spectra"); auto l1ColumnTmp = paramWS->getColumn("l1"); auto l2ColumnTmp = paramWS->getColumn("l2"); auto twoThetaColumnTmp = paramWS->getColumn("twotheta"); auto efixedColumnTmp = paramWS->getColumn("efixed"); auto emodeColumnTmp = paramWS->getColumn("emode"); } catch (...) { throw Exception::InstrumentDefinitionError( "DetectorParameter TableWorkspace is not defined correctly."); } // Now let's take a reference to the vectors. const auto &l1Column = paramWS->getColVector<double>("l1"); const auto &l2Column = paramWS->getColVector<double>("l2"); const auto &twoThetaColumn = paramWS->getColVector<double>("twotheta"); const auto &efixedColumn = paramWS->getColVector<double>("efixed"); const auto &emodeColumn = paramWS->getColVector<int>("emode"); const auto &spectraColumn = paramWS->getColVector<int>("spectra"); Progress prog(this, 0.2, 1.0, m_numberOfSpectra); int64_t numberOfSpectra_i = static_cast<int64_t>(m_numberOfSpectra); // cast to make openmp happy // Get the unit object for each workspace Kernel::Unit_const_sptr outputUnit = m_outputUnit; std::vector<double> emptyVec; int failedDetectorCount = 0; // Perform Sanity Validation before creating workspace size_t checkIndex = 0; int checkSpecNo = inputWS->getDetector(checkIndex)->getID(); auto checkSpecIter = std::find(spectraColumn.begin(), spectraColumn.end(), checkSpecNo); if (checkSpecIter != spectraColumn.end()) { size_t detectorRow = std::distance(spectraColumn.begin(), checkSpecIter); // copy the X values for the check auto checkXValues = inputWS->readX(checkIndex); // Convert the input unit to time-of-flight auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); double checkdelta = 0; checkFromUnit->toTOF(checkXValues, emptyVec, l1Column[detectorRow], l2Column[detectorRow], twoThetaColumn[detectorRow], emodeColumn[detectorRow], efixedColumn[detectorRow], checkdelta); // Convert from time-of-flight to the desired unit checkOutputUnit->fromTOF(checkXValues, emptyVec, l1Column[detectorRow], l2Column[detectorRow], twoThetaColumn[detectorRow], emodeColumn[detectorRow], efixedColumn[detectorRow], checkdelta); } // create the output workspace MatrixWorkspace_sptr outputWS = this->setupOutputWorkspace(inputWS); EventWorkspace_sptr eventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check // TODO: Check why this parallel stuff breaks // Loop over the histograms (detector spectra) // PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS)) for (int64_t i = 0; i < numberOfSpectra_i; ++i) { // Lets find what row this spectrum Number appears in our detector table. // PARALLEL_START_INTERUPT_REGION std::size_t wsid = i; try { double deg2rad = M_PI / 180.; auto det = outputWS->getDetector(i); int specNo = det->getID(); // int spectraNumber = static_cast<int>(spectraColumn->toDouble(i)); // wsid = outputWS->getIndexFromSpectrumNumber(spectraNumber); g_log.debug() << "###### Spectra #" << specNo << " ==> Workspace ID:" << wsid << '\n'; // Now we need to find the row that contains this spectrum std::vector<int>::const_iterator specIter; specIter = std::find(spectraColumn.begin(), spectraColumn.end(), specNo); if (specIter != spectraColumn.end()) { const size_t detectorRow = std::distance(spectraColumn.begin(), specIter); const double l1 = l1Column[detectorRow]; const double l2 = l2Column[detectorRow]; const double twoTheta = twoThetaColumn[detectorRow] * deg2rad; const double efixed = efixedColumn[detectorRow]; const int emode = emodeColumn[detectorRow]; if (g_log.is(Logger::Priority::PRIO_DEBUG)) { g_log.debug() << "specNo from detector table = " << spectraColumn[detectorRow] << '\n'; g_log.debug() << "###### Spectra #" << specNo << " ==> Det Table Row:" << detectorRow << '\n'; g_log.debug() << "\tL1=" << l1 << ",L2=" << l2 << ",TT=" << twoTheta << ",EF=" << efixed << ",EM=" << emode << '\n'; } // Make local copies of the units. This allows running the loop in // parallel auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); /// @todo Don't yet consider hold-off (delta) const double delta = 0.0; std::vector<double> values(outputWS->x(wsid).begin(), outputWS->x(wsid).end()); // Convert the input unit to time-of-flight localFromUnit->toTOF(values, emptyVec, l1, l2, twoTheta, emode, efixed, delta); // Convert from time-of-flight to the desired unit localOutputUnit->fromTOF(values, emptyVec, l1, l2, twoTheta, emode, efixed, delta); outputWS->mutableX(wsid) = std::move(values); // EventWorkspace part, modifying the EventLists. if (m_inputEvents) { eventWS->getSpectrum(wsid) .convertUnitsViaTof(localFromUnit.get(), localOutputUnit.get()); } } else { // Not found failedDetectorCount++; outputWS->maskWorkspaceIndex(wsid); } } catch (Exception::NotFoundError &) { // Get to here if exception thrown when calculating distance to detector failedDetectorCount++; // Since you usually (always?) get to here when there's no attached // detectors, this call is // the same as just zeroing out the data (calling clearData on the // spectrum) outputWS->maskWorkspaceIndex(i); } prog.report("Convert to " + m_outputUnit->unitID()); // PARALLEL_END_INTERUPT_REGION } // loop over spectra // PARALLEL_CHECK_INTERUPT_REGION if (failedDetectorCount != 0) { g_log.information() << "Something went wrong for " << failedDetectorCount << " spectra. Masking spectrum.\n"; } if (m_inputEvents) eventWS->clearMRU(); return outputWS; }