/** 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 }
/** * 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; } } }
MatrixWorkspace_sptr CreateFloodWorkspace::scaleToCentralPixel(MatrixWorkspace_sptr ws) { int const centralSpectrum = getProperty(Prop::CENTRAL_PIXEL); auto const nHisto = static_cast<int>(ws->getNumberHistograms()); if (centralSpectrum >= nHisto) { throw std::invalid_argument( "Spectrum index " + std::to_string(centralSpectrum) + " passed to property " + Prop::CENTRAL_PIXEL + " is outside the range 0-" + std::to_string(nHisto - 1)); } auto const spectraMap = ws->getSpectrumToWorkspaceIndexMap(); auto const centralIndex = spectraMap.at(centralSpectrum); auto const scaleFactor = ws->y(centralIndex).front(); g_log.information() << "Scale to central pixel, factor = " << scaleFactor << '\n'; if (scaleFactor <= 0.0) { throw std::runtime_error("Scale factor muhst be > 0, found " + std::to_string(scaleFactor)); } auto const axis = ws->getAxis(1); auto const sa = dynamic_cast<const SpectraAxis *>(axis); double const startX = isDefault(Prop::START_X) ? sa->getMin() : getProperty(Prop::START_X); double const endX = isDefault(Prop::END_X) ? sa->getMax() : getProperty(Prop::END_X); PARALLEL_FOR_IF(Kernel::threadSafe(*ws)) for (int i = 0; i < nHisto; ++i) { PARALLEL_START_INTERUPT_REGION auto const spec = ws->getSpectrum(i).getSpectrumNo(); if (isExcludedSpectrum(spec)) { ws->mutableY(i)[0] = VERY_BIG_VALUE; ws->mutableE(i)[0] = 0.0; } else if (spec >= startX && spec <= endX) { ws->mutableY(i)[0] /= scaleFactor; ws->mutableE(i)[0] /= scaleFactor; } else { ws->mutableY(i)[0] = 1.0; ws->mutableE(i)[0] = 0.0; } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION return ws; }
void SumEventsByLogValue::createBinnedOutput( const Kernel::TimeSeriesProperty<T> *log) { // If only the number of bins was given, add the min & max values of the log if (m_binningParams.size() == 1) { m_binningParams.insert(m_binningParams.begin(), log->minValue()); m_binningParams.push_back( log->maxValue() * 1.000001); // Make it a tiny bit larger to cover full range } // XValues will be resized in createAxisFromRebinParams() std::vector<double> XValues; const int XLength = VectorHelper::createAxisFromRebinParams(m_binningParams, XValues); assert((int)XValues.size() == XLength); // Create the output workspace - the factory will give back a Workspace2D MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create( "Workspace2D", 1, XLength, XLength - 1); // Copy the bin boundaries into the output workspace outputWorkspace->mutableX(0) = XValues; outputWorkspace->getAxis(0)->title() = m_logName; outputWorkspace->setYUnit("Counts"); auto &Y = outputWorkspace->mutableY(0); const int numSpec = static_cast<int>(m_inputWorkspace->getNumberHistograms()); Progress prog(this, 0.0, 1.0, numSpec); PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputWorkspace)) for (int spec = 0; spec < numSpec; ++spec) { PARALLEL_START_INTERUPT_REGION const IEventList &eventList = m_inputWorkspace->getSpectrum(spec); const auto pulseTimes = eventList.getPulseTimes(); for (auto pulseTime : pulseTimes) { // Find the value of the log at the time of this event const double logValue = log->getSingleValue(pulseTime); if (logValue >= XValues.front() && logValue < XValues.back()) { PARALLEL_ATOMIC ++Y[VectorHelper::getBinIndex(XValues, logValue)]; } } prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // The errors are the sqrt of the counts so long as we don't deal with // weighted events. std::transform(Y.cbegin(), Y.cend(), outputWorkspace->mutableE(0).begin(), (double (*)(double))std::sqrt); setProperty("OutputWorkspace", outputWorkspace); }
/** 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 CalculateEfficiency::normalizeDetectors(MatrixWorkspace_sptr rebinnedWS, MatrixWorkspace_sptr outputWS, double sum, double error, int nPixels, double min_eff, double max_eff) { // Number of spectra const size_t numberOfSpectra = rebinnedWS->getNumberHistograms(); // Empty vector to store the pixels that outside the acceptable efficiency // range std::vector<size_t> dets_to_mask; const auto &spectrumInfo = rebinnedWS->spectrumInfo(); for (size_t i = 0; i < numberOfSpectra; i++) { const double currProgress = 0.4 + 0.2 * (static_cast<double>(i) / static_cast<double>(numberOfSpectra)); progress(currProgress, "Computing sensitivity"); // If this spectrum is masked, skip to the next one if (spectrumInfo.isMasked(i)) continue; // Retrieve the spectrum into a vector auto &YIn = rebinnedWS->y(i); auto &EIn = rebinnedWS->e(i); auto &YOut = outputWS->mutableY(i); auto &EOut = outputWS->mutableE(i); // If this detector is a monitor, skip to the next one if (spectrumInfo.isMonitor(i)) { YOut[0] = 1.0; EOut[0] = 0.0; continue; } // Normalize counts to get relative efficiency YOut[0] = nPixels / sum * YIn[0]; const double err_sum = YIn[0] / sum * error; EOut[0] = nPixels / std::abs(sum) * std::sqrt(EIn[0] * EIn[0] + err_sum * err_sum); // Mask this detector if the signal is outside the acceptable band if (!isEmpty(min_eff) && YOut[0] < min_eff) dets_to_mask.push_back(i); if (!isEmpty(max_eff) && YOut[0] > max_eff) dets_to_mask.push_back(i); } g_log.debug() << "normalizeDetectors: Masked pixels outside the acceptable " "efficiency range [" << min_eff << "," << max_eff << "] = " << dets_to_mask.size() << " from a total of non masked = " << nPixels << " (from a total number of spectra in the ws = " << numberOfSpectra << ")\n"; // If we identified pixels to be masked, mask them now if (!dets_to_mask.empty()) { // Mask detectors that were found to be outside the acceptable efficiency // band try { IAlgorithm_sptr mask = createChildAlgorithm("MaskDetectors", 0.8, 0.9); // First we mask detectors in the output workspace mask->setProperty<MatrixWorkspace_sptr>("Workspace", outputWS); mask->setProperty<std::vector<size_t>>("WorkspaceIndexList", dets_to_mask); mask->execute(); mask = createChildAlgorithm("MaskDetectors", 0.9, 1.0); // Then we mask the same detectors in the input workspace mask->setProperty<MatrixWorkspace_sptr>("Workspace", rebinnedWS); mask->setProperty<std::vector<size_t>>("WorkspaceIndexList", dets_to_mask); mask->execute(); } catch (std::invalid_argument &err) { std::stringstream e; e << "Invalid argument to MaskDetectors Child Algorithm: " << err.what(); g_log.error(e.str()); } catch (std::runtime_error &err) { std::stringstream e; e << "Unable to successfully run MaskDetectors Child Algorithm: " << err.what(); g_log.error(e.str()); } } }
/// Execute the algorithm in case of a histogrammed data. void ExtractSpectra::execHistogram() { // Retrieve and validate the input properties this->checkProperties(); // Create the output workspace MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create( m_inputWorkspace, m_workspaceIndexList.size(), m_maxX - m_minX, m_maxX - m_minX - m_histogram); outputWorkspace->setIndexInfo( Indexing::extract(m_inputWorkspace->indexInfo(), m_workspaceIndexList)); // If this is a Workspace2D, get the spectra axes for copying in the spectraNo // later Axis *inAxis1(nullptr); TextAxis *outTxtAxis(nullptr); NumericAxis *outNumAxis(nullptr); if (m_inputWorkspace->axes() > 1) { inAxis1 = m_inputWorkspace->getAxis(1); auto outAxis1 = outputWorkspace->getAxis(1); outTxtAxis = dynamic_cast<TextAxis *>(outAxis1); if (!outTxtAxis) outNumAxis = dynamic_cast<NumericAxis *>(outAxis1); } cow_ptr<HistogramData::HistogramX> newX(nullptr); if (m_commonBoundaries) { auto &oldX = m_inputWorkspace->x(m_workspaceIndexList.front()); newX = make_cow<HistogramData::HistogramX>(oldX.begin() + m_minX, oldX.begin() + m_maxX); } bool doCrop = ((m_minX != 0) || (m_maxX != m_inputWorkspace->x(0).size())); Progress prog(this, 0.0, 1.0, (m_workspaceIndexList.size())); // Loop over the required workspace indices, copying in the desired bins for (int j = 0; j < static_cast<int>(m_workspaceIndexList.size()); ++j) { auto i = m_workspaceIndexList[j]; bool hasDx = m_inputWorkspace->hasDx(i); // Preserve/restore sharing if X vectors are the same if (m_commonBoundaries) { outputWorkspace->setSharedX(j, newX); if (hasDx) { auto &oldDx = m_inputWorkspace->dx(i); outputWorkspace->setSharedDx( j, make_cow<HistogramData::HistogramDx>( oldDx.begin() + m_minX, oldDx.begin() + m_maxX - m_histogram)); } } else { // Safe to just copy whole vector 'cos can't be cropping in X if not // common outputWorkspace->setSharedX(j, m_inputWorkspace->sharedX(i)); outputWorkspace->setSharedDx(j, m_inputWorkspace->sharedDx(i)); } if (doCrop) { auto &oldY = m_inputWorkspace->y(i); outputWorkspace->mutableY(j) .assign(oldY.begin() + m_minX, oldY.begin() + (m_maxX - m_histogram)); auto &oldE = m_inputWorkspace->e(i); outputWorkspace->mutableE(j) .assign(oldE.begin() + m_minX, oldE.begin() + (m_maxX - m_histogram)); } else { outputWorkspace->setSharedY(j, m_inputWorkspace->sharedY(i)); outputWorkspace->setSharedE(j, m_inputWorkspace->sharedE(i)); } // copy over the axis entry for each spectrum, regardless of the type of // axes present if (inAxis1) { if (outTxtAxis) { outTxtAxis->setLabel(j, inAxis1->label(i)); } else if (outNumAxis) { outNumAxis->setValue(j, inAxis1->operator()(i)); } // spectra axis is implicit in workspace creation } if (!m_commonBoundaries) this->cropRagged(outputWorkspace, static_cast<int>(i), j); // Propagate bin masking if there is any if (m_inputWorkspace->hasMaskedBins(i)) { const MatrixWorkspace::MaskList &inputMasks = m_inputWorkspace->maskedBins(i); MatrixWorkspace::MaskList::const_iterator it; for (it = inputMasks.begin(); it != inputMasks.end(); ++it) { const size_t maskIndex = (*it).first; if (maskIndex >= m_minX && maskIndex < m_maxX - m_histogram) outputWorkspace->flagMasked(j, maskIndex - m_minX, (*it).second); } } prog.report(); } setProperty("OutputWorkspace", outputWorkspace); }
void SofQWCentre::exec() { using namespace Geometry; MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); // Do the full check for common binning if (!WorkspaceHelpers::commonBoundaries(*inputWorkspace)) { g_log.error( "The input workspace must have common binning across all spectra"); throw std::invalid_argument( "The input workspace must have common binning across all spectra"); } std::vector<double> verticalAxis; MatrixWorkspace_sptr outputWorkspace = setUpOutputWorkspace( inputWorkspace, getProperty("QAxisBinning"), verticalAxis); setProperty("OutputWorkspace", outputWorkspace); // Holds the spectrum-detector mapping std::vector<specnum_t> specNumberMapping; std::vector<detid_t> detIDMapping; m_EmodeProperties.initCachedValues(*inputWorkspace, this); int emode = m_EmodeProperties.m_emode; // Get a pointer to the instrument contained in the workspace Instrument_const_sptr instrument = inputWorkspace->getInstrument(); // Get the distance between the source and the sample (assume in metres) IComponent_const_sptr source = instrument->getSource(); IComponent_const_sptr sample = instrument->getSample(); V3D beamDir = sample->getPos() - source->getPos(); beamDir.normalize(); try { double l1 = source->getDistance(*sample); g_log.debug() << "Source-sample distance: " << l1 << '\n'; } catch (Exception::NotFoundError &) { g_log.error("Unable to calculate source-sample distance"); throw Exception::InstrumentDefinitionError( "Unable to calculate source-sample distance", inputWorkspace->getTitle()); } // Conversion constant for E->k. k(A^-1) = sqrt(energyToK*E(meV)) const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass * PhysicalConstants::meV * 1e-20 / (PhysicalConstants::h * PhysicalConstants::h); // Loop over input workspace bins, reassigning data to correct bin in output // qw workspace const size_t numHists = inputWorkspace->getNumberHistograms(); const size_t numBins = inputWorkspace->blocksize(); Progress prog(this, 0.0, 1.0, numHists); for (int64_t i = 0; i < int64_t(numHists); ++i) { try { // Now get the detector object for this histogram IDetector_const_sptr spectrumDet = inputWorkspace->getDetector(i); if (spectrumDet->isMonitor()) continue; const double efixed = m_EmodeProperties.getEFixed(*spectrumDet); // For inelastic scattering the simple relationship q=4*pi*sinTheta/lambda // does not hold. In order to // be completely general we must calculate the momentum transfer by // calculating the incident and final // wave vectors and then use |q| = sqrt[(ki - kf)*(ki - kf)] DetectorGroup_const_sptr detGroup = boost::dynamic_pointer_cast<const DetectorGroup>(spectrumDet); std::vector<IDetector_const_sptr> detectors; if (detGroup) { detectors = detGroup->getDetectors(); } else { detectors.push_back(spectrumDet); } const size_t numDets = detectors.size(); // cache to reduce number of static casts const double numDets_d = static_cast<double>(numDets); const auto &Y = inputWorkspace->y(i); const auto &E = inputWorkspace->e(i); const auto &X = inputWorkspace->x(i); // Loop over the detectors and for each bin calculate Q for (size_t idet = 0; idet < numDets; ++idet) { IDetector_const_sptr det = detectors[idet]; // Calculate kf vector direction and then Q for each energy bin V3D scatterDir = (det->getPos() - sample->getPos()); scatterDir.normalize(); for (size_t j = 0; j < numBins; ++j) { const double deltaE = 0.5 * (X[j] + X[j + 1]); // Compute ki and kf wave vectors and therefore q = ki - kf double ei(0.0), ef(0.0); if (emode == 1) { ei = efixed; ef = efixed - deltaE; if (ef < 0) { std::string mess = "Energy transfer requested in Direct mode exceeds incident " "energy.\n Found for det ID: " + std::to_string(idet) + " bin No " + std::to_string(j) + " with Ei=" + boost::lexical_cast<std::string>(efixed) + " and energy transfer: " + boost::lexical_cast<std::string>(deltaE); throw std::runtime_error(mess); } } else { ei = efixed + deltaE; ef = efixed; if (ef < 0) { std::string mess = "Incident energy of a neutron is negative. Are you trying to " "process Direct data in Indirect mode?\n Found for det ID: " + std::to_string(idet) + " bin No " + std::to_string(j) + " with efied=" + boost::lexical_cast<std::string>(efixed) + " and energy transfer: " + boost::lexical_cast<std::string>(deltaE); throw std::runtime_error(mess); } } if (ei < 0) throw std::runtime_error( "Negative incident energy. Check binning."); const V3D ki = beamDir * sqrt(energyToK * ei); const V3D kf = scatterDir * (sqrt(energyToK * (ef))); const double q = (ki - kf).norm(); // Test whether it's in range of the Q axis if (q < verticalAxis.front() || q > verticalAxis.back()) continue; // Find which q bin this point lies in const MantidVec::difference_type qIndex = std::upper_bound(verticalAxis.begin(), verticalAxis.end(), q) - verticalAxis.begin() - 1; // Add this spectra-detector pair to the mapping specNumberMapping.push_back( outputWorkspace->getSpectrum(qIndex).getSpectrumNo()); detIDMapping.push_back(det->getID()); // And add the data and it's error to that bin, taking into account // the number of detectors contributing to this bin outputWorkspace->mutableY(qIndex)[j] += Y[j] / numDets_d; // Standard error on the average outputWorkspace->mutableE(qIndex)[j] = sqrt((pow(outputWorkspace->e(qIndex)[j], 2) + pow(E[j], 2)) / numDets_d); } } } catch (Exception::NotFoundError &) { // Get to here if exception thrown when calculating distance to detector // Presumably, if we get to here the spectrum will be all zeroes anyway // (from conversion to E) continue; } prog.report(); } // If the input workspace was a distribution, need to divide by q bin width if (inputWorkspace->isDistribution()) this->makeDistribution(outputWorkspace, verticalAxis); // Set the output spectrum-detector mapping SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping); outputWorkspace->updateSpectraUsing(outputDetectorMap); // Replace any NaNs in outputWorkspace with zeroes if (this->getProperty("ReplaceNaNs")) { auto replaceNans = this->createChildAlgorithm("ReplaceSpecialValues"); replaceNans->setChild(true); replaceNans->initialize(); replaceNans->setProperty("InputWorkspace", outputWorkspace); replaceNans->setProperty("OutputWorkspace", outputWorkspace); replaceNans->setProperty("NaNValue", 0.0); replaceNans->setProperty("InfinityValue", 0.0); replaceNans->setProperty("BigNumberThreshold", DBL_MAX); replaceNans->execute(); } }
/** Carries out the bin-by-bin normalization * @param inputWorkspace The input workspace * @param outputWorkspace The result workspace */ void NormaliseToMonitor::normaliseBinByBin( const MatrixWorkspace_sptr &inputWorkspace, MatrixWorkspace_sptr &outputWorkspace) { EventWorkspace_sptr inputEvent = boost::dynamic_pointer_cast<EventWorkspace>(inputWorkspace); // Only create output workspace if different to input one if (outputWorkspace != inputWorkspace) { if (inputEvent) { outputWorkspace = inputWorkspace->clone(); } else outputWorkspace = create<MatrixWorkspace>(*inputWorkspace); } auto outputEvent = boost::dynamic_pointer_cast<EventWorkspace>(outputWorkspace); const auto &inputSpecInfo = inputWorkspace->spectrumInfo(); const auto &monitorSpecInfo = m_monitor->spectrumInfo(); const auto specLength = inputWorkspace->blocksize(); for (auto &workspaceIndex : m_workspaceIndexes) { // Get hold of the monitor spectrum const auto &monX = m_monitor->binEdges(workspaceIndex); auto monY = m_monitor->counts(workspaceIndex); auto monE = m_monitor->countStandardDeviations(workspaceIndex); size_t timeIndex = 0; if (m_scanInput) timeIndex = monitorSpecInfo.spectrumDefinition(workspaceIndex)[0].second; // Calculate the overall normalization just the once if bins are all // matching if (m_commonBins) this->normalisationFactor(monX, monY, monE); const size_t numHists = inputWorkspace->getNumberHistograms(); // Flag set when a division by 0 is found bool hasZeroDivision = false; Progress prog(this, 0.0, 1.0, numHists); // Loop over spectra PARALLEL_FOR_IF( Kernel::threadSafe(*inputWorkspace, *outputWorkspace, *m_monitor)) for (int64_t i = 0; i < int64_t(numHists); ++i) { PARALLEL_START_INTERUPT_REGION prog.report(); const auto &specDef = inputSpecInfo.spectrumDefinition(i); if (!spectrumDefinitionsMatchTimeIndex(specDef, timeIndex)) continue; const auto &X = inputWorkspace->binEdges(i); // If not rebinning, just point to our monitor spectra, otherwise create // new vectors auto Y = (m_commonBins ? monY : Counts(specLength)); auto E = (m_commonBins ? monE : CountStandardDeviations(specLength)); if (!m_commonBins) { // ConvertUnits can give X vectors of all zeros - skip these, they // cause // problems if (X.back() == 0.0 && X.front() == 0.0) continue; // Rebin the monitor spectrum to match the binning of the current data // spectrum VectorHelper::rebinHistogram( monX.rawData(), monY.mutableRawData(), monE.mutableRawData(), X.rawData(), Y.mutableRawData(), E.mutableRawData(), false); // Recalculate the overall normalization factor this->normalisationFactor(X, Y, E); } if (inputEvent) { // --- EventWorkspace --- EventList &outEL = outputEvent->getSpectrum(i); outEL.divide(X.rawData(), Y.mutableRawData(), E.mutableRawData()); } else { // --- Workspace2D --- auto &YOut = outputWorkspace->mutableY(i); auto &EOut = outputWorkspace->mutableE(i); const auto &inY = inputWorkspace->y(i); const auto &inE = inputWorkspace->e(i); outputWorkspace->setSharedX(i, inputWorkspace->sharedX(i)); // The code below comes more or less straight out of Divide.cpp for (size_t k = 0; k < specLength; ++k) { // Get the input Y's const double leftY = inY[k]; const double rightY = Y[k]; if (rightY == 0.0) { hasZeroDivision = true; } // Calculate result and store in local variable to avoid overwriting // original data if output workspace is same as one of the input // ones const double newY = leftY / rightY; if (fabs(rightY) > 1.0e-12 && fabs(newY) > 1.0e-12) { const double lhsFactor = (inE[k] < 1.0e-12 || fabs(leftY) < 1.0e-12) ? 0.0 : pow((inE[k] / leftY), 2); const double rhsFactor = E[k] < 1.0e-12 ? 0.0 : pow((E[k] / rightY), 2); EOut[k] = std::abs(newY) * sqrt(lhsFactor + rhsFactor); } // Now store the result YOut[k] = newY; } // end Workspace2D case } // end loop over current spectrum PARALLEL_END_INTERUPT_REGION } // end loop over spectra PARALLEL_CHECK_INTERUPT_REGION if (hasZeroDivision) { g_log.warning() << "Division by zero in some of the bins.\n"; } if (inputEvent) outputEvent->clearMRU(); } }
/** * Read histogram data * @param histogramEntries map of the file entries that have histogram * @param nxFile Reads data from inside first first top entry * @return Names of workspaces to include in output group */ std::vector<std::string> LoadMcStas::readHistogramData( const std::map<std::string, std::string> &histogramEntries, ::NeXus::File &nxFile) { std::string nameAttrValueYLABEL; std::vector<std::string> histoWSNames; for (const auto &histogramEntry : histogramEntries) { const std::string &dataName = histogramEntry.first; const std::string &dataType = histogramEntry.second; // open second level entry nxFile.openGroup(dataName, dataType); // grap title to use to e.g. create workspace name std::string nameAttrValueTITLE; nxFile.getAttr("filename", nameAttrValueTITLE); if (nxFile.hasAttr("ylabel")) { nxFile.getAttr("ylabel", nameAttrValueYLABEL); } // Find the axis names auto nxdataEntries = nxFile.getEntries(); std::string axis1Name, axis2Name; for (auto &nxdataEntry : nxdataEntries) { if (nxdataEntry.second == "NXparameters") continue; if (nxdataEntry.first == "ncount") continue; nxFile.openData(nxdataEntry.first); if (nxFile.hasAttr("axis")) { int axisNo(0); nxFile.getAttr("axis", axisNo); if (axisNo == 1) axis1Name = nxdataEntry.first; else if (axisNo == 2) axis2Name = nxdataEntry.first; else throw std::invalid_argument("Unknown axis number"); } nxFile.closeData(); } std::vector<double> axis1Values; std::vector<double> axis2Values; nxFile.readData<double>(axis1Name, axis1Values); if (axis2Name.length() == 0) { axis2Name = nameAttrValueYLABEL; axis2Values.push_back(0.0); } else { nxFile.readData<double>(axis2Name, axis2Values); } const size_t axis1Length = axis1Values.size(); const size_t axis2Length = axis2Values.size(); g_log.debug() << "Axis lengths=" << axis1Length << " " << axis2Length << '\n'; // Require "data" field std::vector<double> data; nxFile.readData<double>("data", data); // Optional errors field std::vector<double> errors; try { nxFile.readData<double>("errors", errors); } catch (::NeXus::Exception &) { g_log.information() << "Field " << dataName << " contains no error information.\n"; } // close second level entry nxFile.closeGroup(); MatrixWorkspace_sptr ws = WorkspaceFactory::Instance().create( "Workspace2D", axis2Length, axis1Length, axis1Length); Axis *axis1 = ws->getAxis(0); axis1->title() = axis1Name; // Set caption auto lblUnit = boost::make_shared<Units::Label>(); lblUnit->setLabel(axis1Name, ""); axis1->unit() = lblUnit; Axis *axis2 = new NumericAxis(axis2Length); axis2->title() = axis2Name; // Set caption lblUnit = boost::make_shared<Units::Label>(); lblUnit->setLabel(axis2Name, ""); axis2->unit() = lblUnit; ws->setYUnit(axis2Name); ws->replaceAxis(1, axis2); for (size_t wsIndex = 0; wsIndex < axis2Length; ++wsIndex) { auto &dataX = ws->mutableX(wsIndex); auto &dataY = ws->mutableY(wsIndex); auto &dataE = ws->mutableE(wsIndex); for (size_t j = 0; j < axis1Length; ++j) { // Data is stored in column-major order so we are translating to // row major for Mantid const size_t fileDataIndex = j * axis2Length + wsIndex; dataX[j] = axis1Values[j]; dataY[j] = data[fileDataIndex]; if (!errors.empty()) dataE[j] = errors[fileDataIndex]; } axis2->setValue(wsIndex, axis2Values[wsIndex]); } // set the workspace title ws->setTitle(nameAttrValueTITLE); // use the workspace title to create the workspace name std::replace(nameAttrValueTITLE.begin(), nameAttrValueTITLE.end(), ' ', '_'); // ensure that specified name is given to workspace (eventWS) when added to // outputGroup const std::string outputWS = getProperty("OutputWorkspace"); const std::string nameUserSee = nameAttrValueTITLE + "_" + outputWS; AnalysisDataService::Instance().addOrReplace(nameUserSee, ws); histoWSNames.emplace_back(ws->getName()); } nxFile.closeGroup(); return histoWSNames; } // finish
/** * Set errors in Diff spectrum after a fit * @param data :: [input/output] Workspace containing spectrum to set errors to */ void ALCBaselineModellingModel::setErrorsAfterFit(MatrixWorkspace_sptr data) { data->mutableE(2) = data->e(0); }
/** * Enable points that were disabled for fit * @param destWs :: Workspace to enable points in * @param sourceWs :: Workspace with original errors */ void ALCBaselineModellingModel::enableDisabledPoints( MatrixWorkspace_sptr destWs, MatrixWorkspace_const_sptr sourceWs) { // Unwanted points were disabled by setting their errors to very high values. // We recover here the original errors stored in sourceWs destWs->mutableE(0) = sourceWs->e(0); }
/** Execute the algorithm. */ void ResampleX::exec() { // generically having access to the input workspace is a good idea MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); bool inPlace = (inputWS == outputWS); // Rebinning in-place m_isDistribution = inputWS->isDistribution(); m_isHistogram = inputWS->isHistogramData(); const int numSpectra = static_cast<int>(inputWS->getNumberHistograms()); // the easy parameters m_useLogBinning = getProperty("LogBinning"); m_numBins = getProperty("NumberBins"); m_preserveEvents = getProperty("PreserveEvents"); // determine the xmin/xmax for the workspace vector<double> xmins = getProperty("XMin"); vector<double> xmaxs = getProperty("XMax"); string error = determineXMinMax(inputWS, xmins, xmaxs); if (!error.empty()) throw std::runtime_error(error); bool common_limits = true; { double xmin_common = xmins[0]; double xmax_common = xmaxs[0]; for (size_t i = 1; i < xmins.size(); ++i) { if (xmins[i] != xmin_common) { common_limits = false; break; } if (xmaxs[i] != xmax_common) { common_limits = false; break; } } } if (common_limits) { g_log.debug() << "Common limits between all spectra\n"; } else { g_log.debug() << "Does not have common limits between all spectra\n"; } // start doing actual work EventWorkspace_const_sptr inputEventWS = boost::dynamic_pointer_cast<const EventWorkspace>(inputWS); if (inputEventWS != nullptr) { if (m_preserveEvents) { if (inPlace) { g_log.debug() << "Rebinning event workspace in place\n"; } else { g_log.debug() << "Rebinning event workspace out of place\n"; outputWS = inputWS->clone(); } auto outputEventWS = boost::dynamic_pointer_cast<EventWorkspace>(outputWS); if (common_limits) { // get the delta from the first since they are all the same BinEdges xValues(0); const double delta = this->determineBinning(xValues.mutableRawData(), xmins[0], xmaxs[0]); g_log.debug() << "delta = " << delta << "\n"; outputEventWS->setAllX(xValues); } else { // initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // do the rebinning PARALLEL_FOR_IF(Kernel::threadSafe(*inputEventWS, *outputWS)) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION BinEdges xValues(0); const double delta = this->determineBinning( xValues.mutableRawData(), xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << " xmin=" << xmins[wkspIndex] << " xmax=" << xmaxs[wkspIndex] << "\n"; outputEventWS->setHistogram(wkspIndex, xValues); prog.report(name()); // Report progress PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION } } // end if (m_preserveEvents) else // event workspace -> matrix workspace { //--------- Different output, OR you're inplace but not preserving Events g_log.information() << "Creating a Workspace2D from the EventWorkspace " << inputEventWS->getName() << ".\n"; outputWS = create<DataObjects::Workspace2D>( *inputWS, numSpectra, HistogramData::BinEdges(m_numBins + 1)); // Initialize progress reporting. Progress prog(this, 0.0, 1.0, numSpectra); // Go through all the histograms and set the data PARALLEL_FOR_IF(Kernel::threadSafe(*inputEventWS, *outputWS)) for (int wkspIndex = 0; wkspIndex < numSpectra; ++wkspIndex) { PARALLEL_START_INTERUPT_REGION // Set the X axis for each output histogram MantidVec xValues; const double delta = this->determineBinning(xValues, xmins[wkspIndex], xmaxs[wkspIndex]); g_log.debug() << "delta[wkspindex=" << wkspIndex << "] = " << delta << "\n"; outputWS->setBinEdges(wkspIndex, xValues); // Get a const event list reference. inputEventWS->dataY() doesn't work. const EventList &el = inputEventWS->getSpectrum(wkspIndex); MantidVec y_data, e_data; // The EventList takes care of histogramming. el.generateHistogram(xValues, y_data, e_data); // Copy the data over. outputWS->mutableY(wkspIndex) = std::move(y_data); outputWS->mutableE(wkspIndex) = std::move(e_data); // Report progress prog.report(name()); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Copy all the axes for (int i = 1; i < inputWS->axes(); i++) { outputWS->replaceAxis(i, inputWS->getAxis(i)->clone(outputWS.get())); outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } // Copy the units over too. for (int i = 0; i < outputWS->axes(); ++i) { outputWS->getAxis(i)->unit() = inputWS->getAxis(i)->unit(); } outputWS->setYUnit(inputEventWS->YUnit()); outputWS->setYUnitLabel(inputEventWS->YUnitLabel()); } // Assign it to the output workspace property setProperty("OutputWorkspace", outputWS); return; } else // (inputeventWS != NULL)