/** * Apply the created mapping to the workspace */ void CreateSimulationWorkspace::applyDetectorMapping() { size_t wsIndex(0); for (auto iter = m_detGroups.begin(); iter != m_detGroups.end(); ++iter) { ISpectrum *spectrum = m_outputWS->getSpectrum(wsIndex); spectrum->setSpectrumNo( static_cast<specid_t>(wsIndex + 1)); // Ensure a contiguous mapping spectrum->clearDetectorIDs(); spectrum->addDetectorIDs(iter->second); ++wsIndex; } }
/** * Only to be used if the KeepUnGrouped property is true, moves the spectra that were not selected * to be in a group to the end of the output spectrum * @param unGroupedSet :: list of WORKSPACE indexes that were included in a group * @param inputWS :: user selected input workspace for the algorithm * @param outputWS :: user selected output workspace for the algorithm * @param outIndex :: the next spectra index available after the grouped spectra */ void GroupDetectors2::moveOthers(const std::set<int64_t> &unGroupedSet, API::MatrixWorkspace_const_sptr inputWS, API::MatrixWorkspace_sptr outputWS, size_t outIndex) { g_log.debug() << "Starting to copy the ungrouped spectra" << std::endl; double prog4Copy = (1. - 1.*static_cast<double>(m_FracCompl))/static_cast<double>(unGroupedSet.size()); std::set<int64_t>::const_iterator copyFrIt = unGroupedSet.begin(); // go thorugh all the spectra in the input workspace for ( ; copyFrIt != unGroupedSet.end(); ++copyFrIt ) { if( *copyFrIt == USED ) continue; //Marked as not to be used size_t sourceIndex = static_cast<size_t>(*copyFrIt); // The input spectrum we'll copy const ISpectrum * inputSpec = inputWS->getSpectrum(sourceIndex); // Destination of the copying ISpectrum * outputSpec = outputWS->getSpectrum(outIndex); // Copy the data outputSpec->dataX() = inputSpec->dataX(); outputSpec->dataY() = inputSpec->dataY(); outputSpec->dataE() = inputSpec->dataE(); // Spectrum numbers etc. outputSpec->setSpectrumNo(inputSpec->getSpectrumNo()); outputSpec->clearDetectorIDs(); outputSpec->addDetectorIDs( inputSpec->getDetectorIDs() ); // go to the next free index in the output workspace outIndex ++; // make regular progress reports and check for cancelling the algorithm if ( outIndex % INTERVAL == 0 ) { m_FracCompl += INTERVAL*prog4Copy; if ( m_FracCompl > 1.0 ) { m_FracCompl = 1.0; } progress(m_FracCompl); interruption_point(); } } // Refresh the spectraDetectorMap outputWS->generateSpectraMap(); g_log.debug() << name() << " copied " << unGroupedSet.size()-1 << " ungrouped spectra\n"; }
void GatherWorkspaces::execEvent() { // Every process in an MPI job must hit this next line or everything hangs! mpi::communicator included; // The communicator containing all processes // The root process needs to create a workspace of the appropriate size EventWorkspace_sptr outputWorkspace; if (included.rank() == 0) { g_log.debug() << "Total number of spectra is " << totalSpec << "\n"; // Create the workspace for the output outputWorkspace = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create("EventWorkspace", sumSpec, numBins + hist, numBins)); // Copy geometry over. API::WorkspaceFactory::Instance().initializeFromParent( eventW, outputWorkspace, true); setProperty("OutputWorkspace", outputWorkspace); ExperimentInfo_sptr inWS = inputWorkspace; outputWorkspace->copyExperimentInfoFrom(inWS.get()); } for (size_t wi = 0; wi < totalSpec; wi++) { if (included.rank() == 0) { // How do we accumulate the data? std::string accum = this->getPropertyValue("AccumulationMethod"); std::vector<Mantid::DataObjects::EventList> out_values; gather(included, eventW->getEventList(wi), out_values, 0); for (int i = 0; i < included.size(); i++) { size_t index = wi; // accum == "Add" if (accum == "Append") index = wi + i * totalSpec; outputWorkspace->dataX(index) = eventW->readX(wi); outputWorkspace->getOrAddEventList(index) += out_values[i]; const ISpectrum *inSpec = eventW->getSpectrum(wi); ISpectrum *outSpec = outputWorkspace->getSpectrum(index); outSpec->clearDetectorIDs(); outSpec->addDetectorIDs(inSpec->getDetectorIDs()); } } else { gather(included, eventW->getEventList(wi), 0); } } }
/** @ throw invalid_argument if the workspaces are not mututially compatible */ void Q1D2::exec() { m_dataWS = getProperty("DetBankWorkspace"); MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj"); MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj"); MatrixWorkspace_const_sptr wavePixelAdj = getProperty("WavePixelAdj"); const bool doGravity = getProperty("AccountForGravity"); m_doSolidAngle = getProperty("SolidAngleWeighting"); //throws if we don't have common binning or another incompatibility Qhelper helper; helper.examineInput(m_dataWS, waveAdj, pixelAdj); // FIXME: how to examine the wavePixelAdj? g_log.debug() << "All input workspaces were found to be valid\n"; // normalization as a function of wavelength (i.e. centers of x-value bins) double const * const binNorms = waveAdj ? &(waveAdj->readY(0)[0]) : NULL; // error on the wavelength normalization double const * const binNormEs = waveAdj ? &(waveAdj->readE(0)[0]) : NULL; //define the (large number of) data objects that are going to be used in all iterations of the loop below // this will become the output workspace from this algorithm MatrixWorkspace_sptr outputWS = setUpOutputWorkspace(getProperty("OutputBinning")); const MantidVec & QOut = outputWS->readX(0); MantidVec & YOut = outputWS->dataY(0); MantidVec & EOutTo2 = outputWS->dataE(0); // normalisation that is applied to counts in each Q bin MantidVec normSum(YOut.size(), 0.0); // the error on the normalisation MantidVec normError2(YOut.size(), 0.0); const int numSpec = static_cast<int>(m_dataWS->getNumberHistograms()); Progress progress(this, 0.05, 1.0, numSpec+1); PARALLEL_FOR3(m_dataWS, outputWS, pixelAdj) for (int i = 0; i < numSpec; ++i) { PARALLEL_START_INTERUPT_REGION // Get the pixel relating to this spectrum IDetector_const_sptr det; try { det = m_dataWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Workspace index " << i << " (SpectrumIndex = " << m_dataWS->getSpectrum(i)->getSpectrumNo() << ") has no detector assigned to it - discarding" << std::endl; // Catch if no detector. Next line tests whether this happened - test placed // outside here because Mac Intel compiler doesn't like 'continue' in a catch // in an openmp block. } // If no detector found or if detector is masked shouldn't be included skip onto the next spectrum if ( !det || det->isMonitor() || det->isMasked() ) { continue; } //get the bins that are included inside the RadiusCut/WaveCutcut off, those to calculate for //const size_t wavStart = waveLengthCutOff(i); const size_t wavStart = helper.waveLengthCutOff(m_dataWS, getProperty("RadiusCut"), getProperty("WaveCut"), i); if (wavStart >= m_dataWS->readY(i).size()) { // all the spectra in this detector are out of range continue; } const size_t numWavbins = m_dataWS->readY(i).size()-wavStart; // make just one call to new to reduce CPU overhead on each thread, access to these // three "arrays" is via iterators MantidVec _noDirectUseStorage_(3*numWavbins); //normalization term MantidVec::iterator norms = _noDirectUseStorage_.begin(); // the error on these weights, it contributes to the error calculation on the output workspace MantidVec::iterator normETo2s = norms + numWavbins; // the Q values calculated from input wavelength workspace MantidVec::iterator QIn = normETo2s + numWavbins; // the weighting for this input spectrum that is added to the normalization calculateNormalization(wavStart, i, pixelAdj, wavePixelAdj, binNorms, binNormEs, norms, normETo2s); // now read the data from the input workspace, calculate Q for each bin convertWavetoQ(i, doGravity, wavStart, QIn); // Pointers to the counts data and it's error MantidVec::const_iterator YIn = m_dataWS->readY(i).begin()+wavStart; MantidVec::const_iterator EIn = m_dataWS->readE(i).begin()+wavStart; //when finding the output Q bin remember that the input Q bins (from the convert to wavelength) start high and reduce MantidVec::const_iterator loc = QOut.end(); // sum the Q contributions from each individual spectrum into the output array const MantidVec::const_iterator end = m_dataWS->readY(i).end(); for( ; YIn != end; ++YIn, ++EIn, ++QIn, ++norms, ++normETo2s) { //find the output bin that each input y-value will fall into, remembering there is one more bin boundary than bins getQBinPlus1(QOut, *QIn, loc); // ignore counts that are out of the output range if ( (loc != QOut.begin()) && (loc != QOut.end()) ) { // the actual Q-bin to add something to const size_t bin = loc - QOut.begin() - 1; PARALLEL_CRITICAL(q1d_counts_sum) { YOut[bin] += *YIn; normSum[bin] += *norms; //these are the errors squared which will be summed and square rooted at the end EOutTo2[bin] += (*EIn)*(*EIn); normError2[bin] += *normETo2s; } } } PARALLEL_CRITICAL(q1d_spectra_map) { progress.report("Computing I(Q)"); // Add up the detector IDs in the output spectrum at workspace index 0 const ISpectrum * inSpec = m_dataWS->getSpectrum(i); ISpectrum * outSpec = outputWS->getSpectrum(0); outSpec->addDetectorIDs( inSpec->getDetectorIDs() ); } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION bool doOutputParts = getProperty("OutputParts"); if (doOutputParts) { MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWS); ws_sumOfCounts->dataX(0) = outputWS->dataX(0); ws_sumOfCounts->dataY(0) = outputWS->dataY(0); for (size_t i = 0; i < outputWS->dataE(0).size(); i++) { ws_sumOfCounts->dataE(0)[i] = sqrt(outputWS->dataE(0)[i]); } MatrixWorkspace_sptr ws_sumOfNormFactors = WorkspaceFactory::Instance().create(outputWS); ws_sumOfNormFactors->dataX(0) = outputWS->dataX(0); for (size_t i = 0; i < ws_sumOfNormFactors->dataY(0).size(); i++) { ws_sumOfNormFactors->dataY(0)[i] = normSum[i]; ws_sumOfNormFactors->dataE(0)[i] = sqrt(normError2[i]); } helper.outputParts(this, ws_sumOfCounts, ws_sumOfNormFactors); } progress.report("Normalizing I(Q)"); //finally divide the number of counts in each output Q bin by its weighting normalize(normSum, normError2, YOut, EOutTo2); outputWS->updateSpectraUsingMap(); setProperty("OutputWorkspace",outputWS); }
/** * Move the user selected spectra in the input workspace into groups in the output workspace * @param inputWS :: user selected input workspace for the algorithm * @param outputWS :: user selected output workspace for the algorithm * @param prog4Copy :: the amount of algorithm progress to attribute to moving a single spectra * @return number of new grouped spectra */ size_t GroupDetectors2::formGroups( API::MatrixWorkspace_const_sptr inputWS, API::MatrixWorkspace_sptr outputWS, const double prog4Copy) { // get "Behaviour" string const std::string behaviour = getProperty("Behaviour"); int bhv = 0; if ( behaviour == "Average" ) bhv = 1; API::MatrixWorkspace_sptr beh = API::WorkspaceFactory::Instance().create( "Workspace2D", static_cast<int>(m_GroupSpecInds.size()), 1, 1); g_log.debug() << name() << ": Preparing to group spectra into " << m_GroupSpecInds.size() << " groups\n"; // where we are copying spectra to, we start copying to the start of the output workspace size_t outIndex = 0; // Only used for averaging behaviour. We may have a 1:1 map where a Divide would be waste as it would be just dividing by 1 bool requireDivide(false); for ( storage_map::const_iterator it = m_GroupSpecInds.begin(); it != m_GroupSpecInds.end() ; ++it ) { // This is the grouped spectrum ISpectrum * outSpec = outputWS->getSpectrum(outIndex); // The spectrum number of the group is the key outSpec->setSpectrumNo(it->first); // Start fresh with no detector IDs outSpec->clearDetectorIDs(); // Copy over X data from first spectrum, the bin boundaries for all spectra are assumed to be the same here outSpec->dataX() = inputWS->readX(0); // the Y values and errors from spectra being grouped are combined in the output spectrum // Keep track of number of detectors required for masking size_t nonMaskedSpectra(0); beh->dataX(outIndex)[0] = 0.0; beh->dataE(outIndex)[0] = 0.0; for( std::vector<size_t>::const_iterator wsIter = it->second.begin(); wsIter != it->second.end(); ++wsIter) { const size_t originalWI = *wsIter; // detectors to add to firstSpecNum const ISpectrum * fromSpectrum = inputWS->getSpectrum(originalWI); // Add up all the Y spectra and store the result in the first one // Need to keep the next 3 lines inside loop for now until ManagedWorkspace mru-list works properly MantidVec &firstY = outSpec->dataY(); MantidVec::iterator fYit; MantidVec::iterator fEit = outSpec->dataE().begin(); MantidVec::const_iterator Yit = fromSpectrum->dataY().begin(); MantidVec::const_iterator Eit = fromSpectrum->dataE().begin(); for (fYit = firstY.begin(); fYit != firstY.end(); ++fYit, ++fEit, ++Yit, ++Eit) { *fYit += *Yit; // Assume 'normal' (i.e. Gaussian) combination of errors *fEit = std::sqrt( (*fEit)*(*fEit) + (*Eit)*(*Eit) ); } // detectors to add to the output spectrum outSpec->addDetectorIDs(fromSpectrum->getDetectorIDs() ); try { Geometry::IDetector_const_sptr det = inputWS->getDetector(originalWI); if( !det->isMasked() ) ++nonMaskedSpectra; } catch(Exception::NotFoundError&) { // If a detector cannot be found, it cannot be masked ++nonMaskedSpectra; } } if( nonMaskedSpectra == 0 ) ++nonMaskedSpectra; // Avoid possible divide by zero if(!requireDivide) requireDivide = (nonMaskedSpectra > 1); beh->dataY(outIndex)[0] = static_cast<double>(nonMaskedSpectra); // make regular progress reports and check for cancelling the algorithm if ( outIndex % INTERVAL == 0 ) { m_FracCompl += INTERVAL*prog4Copy; if ( m_FracCompl > 1.0 ) m_FracCompl = 1.0; progress(m_FracCompl); interruption_point(); } outIndex ++; } // Refresh the spectraDetectorMap outputWS->generateSpectraMap(); if ( bhv == 1 && requireDivide ) { g_log.debug() << "Running Divide algorithm to perform averaging.\n"; Mantid::API::IAlgorithm_sptr divide = createChildAlgorithm("Divide"); divide->initialize(); divide->setProperty<API::MatrixWorkspace_sptr>("LHSWorkspace", outputWS); divide->setProperty<API::MatrixWorkspace_sptr>("RHSWorkspace", beh); divide->setProperty<API::MatrixWorkspace_sptr>("OutputWorkspace", outputWS); divide->execute(); } g_log.debug() << name() << " created " << outIndex << " new grouped spectra\n"; return outIndex; }
/** * This function handles the logic for summing RebinnedOutput workspaces. * @param outputWorkspace the workspace to hold the summed input * @param progress the progress indicator * @param numSpectra * @param numMasked * @param numZeros */ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get a copy of the input workspace MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); // First, we need to clean the input workspace for nan's and inf's in order // to treat the data correctly later. This will create a new private // workspace that will be retrieved as mutable. IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_clean"; alg->setProperty("OutputWorkspace", outName); alg->setProperty("NaNValue", 0.0); alg->setProperty("NaNError", 0.0); alg->setProperty("InfinityValue", 0.0); alg->setProperty("InfinityError", 0.0); alg->executeAsChildAlg(); MatrixWorkspace_sptr localworkspace = alg->getProperty("OutputWorkspace"); // Transform to real workspace types RebinnedOutput_sptr inWS = boost::dynamic_pointer_cast<RebinnedOutput>(localworkspace); RebinnedOutput_sptr outWS = boost::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace); // Get references to the output workspaces's data vectors ISpectrum *outSpec = outputWorkspace->getSpectrum(0); MantidVec &YSum = outSpec->dataY(); MantidVec &YError = outSpec->dataE(); MantidVec &FracSum = outWS->dataF(0); MantidVec Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(YSum.size(), 0); nZeros.assign(YSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; // Loop over spectra std::set<int>::iterator it; // for (int i = m_minSpec; i <= m_maxSpec; ++i) for (it = m_indices.begin(); it != m_indices.end(); ++it) { int i = *it; // Don't go outside the range. if ((i >= m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } try { // Get the detector object for this spectrum Geometry::IDetector_const_sptr det = localworkspace->getDetector(i); // Skip monitors, if the property is set to do so if (!m_keepMonitors && det->isMonitor()) continue; // Skip masked detectors if (det->isMasked()) { numMasked++; continue; } } catch (...) { // if the detector not found just carry on } numSpectra++; // Retrieve the spectrum into a vector const MantidVec &YValues = localworkspace->readY(i); const MantidVec &YErrors = localworkspace->readE(i); const MantidVec &FracArea = inWS->readF(i); if (m_calculateWeightedSum) { for (int k = 0; k < this->m_yLength; ++k) { if (YErrors[k] != 0) { double errsq = YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; YError[k] += errsq; Weight[k] += 1. / errsq; YSum[k] += YValues[k] * FracArea[k] / errsq; FracSum[k] += FracArea[k]; } else { nZeros[k]++; FracSum[k] += FracArea[k]; } } } else { for (int k = 0; k < this->m_yLength; ++k) { YSum[k] += YValues[k] * FracArea[k]; YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; FracSum[k] += FracArea[k]; } } // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (nZeros[i] == 0) YSum[i] *= double(numSpectra) / Weight[i]; else numZeros += nZeros[i]; } } // Create the correct representation outWS->finalize(); }
void GatherWorkspaces::exec() { // Every process in an MPI job must hit this next line or everything hangs! mpi::communicator world; // The communicator containing all processes inputWorkspace = getProperty("InputWorkspace"); // Create a new communicator that includes only those processes that have an // input workspace const int haveWorkspace(inputWorkspace ? 1 : 0); included = world.split(haveWorkspace); // If the present process doesn't have an input workspace then its work is // done if (!haveWorkspace) { g_log.information("No input workspace on this process, so nothing to do."); return; } // Get the number of bins in each workspace and check they're all the same numBins = inputWorkspace->blocksize(); std::vector<std::size_t> all_numBins; all_gather(included, numBins, all_numBins); if (std::count(all_numBins.begin(), all_numBins.end(), numBins) != (int)all_numBins.size()) { // All the processes will error out if all the workspaces don't have the // same number of bins throw Exception::MisMatch<std::size_t>( numBins, 0, "All input workspaces must have the same number of bins"); } // Also check that all workspaces are either histogram or not // N.B. boost mpi doesn't seem to like me using booleans in the all_gather hist = inputWorkspace->isHistogramData(); std::vector<int> all_hist; all_gather(included, hist, all_hist); if (std::count(all_hist.begin(), all_hist.end(), hist) != (int)all_hist.size()) { // All the processes will error out if we don't have either all histogram or // all point-data workspaces throw Exception::MisMatch<int>( hist, 0, "The input workspaces must be all histogram or all point data"); } // How do we accumulate the data? std::string accum = this->getPropertyValue("AccumulationMethod"); // Get the total number of spectra in the combined inputs totalSpec = inputWorkspace->getNumberHistograms(); sumSpec = totalSpec; if (accum == "Append") { reduce(included, totalSpec, sumSpec, std::plus<std::size_t>(), 0); } else if (accum == "Add") { // barrier only helps when memory is too low for communication // included.barrier(); } eventW = boost::dynamic_pointer_cast<const EventWorkspace>(inputWorkspace); if (eventW != NULL) { if (getProperty("PreserveEvents")) { // Input workspace is an event workspace. Use the other exec method this->execEvent(); return; } } // The root process needs to create a workspace of the appropriate size MatrixWorkspace_sptr outputWorkspace; if (included.rank() == 0) { g_log.debug() << "Total number of spectra is " << sumSpec << "\n"; // Create the workspace for the output outputWorkspace = WorkspaceFactory::Instance().create( inputWorkspace, sumSpec, numBins + hist, numBins); setProperty("OutputWorkspace", outputWorkspace); ExperimentInfo_sptr inWS = inputWorkspace; outputWorkspace->copyExperimentInfoFrom(inWS.get()); } for (size_t wi = 0; wi < totalSpec; wi++) { if (included.rank() == 0) { const ISpectrum *inSpec = inputWorkspace->getSpectrum(wi); if (accum == "Add") { outputWorkspace->dataX(wi) = inputWorkspace->readX(wi); reduce(included, inputWorkspace->readY(wi), outputWorkspace->dataY(wi), vplus(), 0); reduce(included, inputWorkspace->readE(wi), outputWorkspace->dataE(wi), eplus(), 0); } else if (accum == "Append") { // Copy over data from own input workspace outputWorkspace->dataX(wi) = inputWorkspace->readX(wi); outputWorkspace->dataY(wi) = inputWorkspace->readY(wi); outputWorkspace->dataE(wi) = inputWorkspace->readE(wi); const int numReqs(3 * (included.size() - 1)); mpi::request reqs[numReqs]; int j(0); // Receive data from all the other processes // This works because the process ranks are ordered the same in // 'included' as // they are in 'world', but in general this is not guaranteed. TODO: // robustify for (int i = 1; i < included.size(); ++i) { size_t index = wi + i * totalSpec; reqs[j++] = included.irecv(i, 0, outputWorkspace->dataX(index)); reqs[j++] = included.irecv(i, 1, outputWorkspace->dataY(index)); reqs[j++] = included.irecv(i, 2, outputWorkspace->dataE(index)); ISpectrum *outSpec = outputWorkspace->getSpectrum(index); outSpec->clearDetectorIDs(); outSpec->addDetectorIDs(inSpec->getDetectorIDs()); } // Make sure everything's been received before exiting the algorithm mpi::wait_all(reqs, reqs + numReqs); } ISpectrum *outSpec = outputWorkspace->getSpectrum(wi); outSpec->clearDetectorIDs(); outSpec->addDetectorIDs(inSpec->getDetectorIDs()); } else { if (accum == "Add") { reduce(included, inputWorkspace->readY(wi), vplus(), 0); reduce(included, inputWorkspace->readE(wi), eplus(), 0); } else if (accum == "Append") { mpi::request reqs[3]; // Send the spectrum to the root process reqs[0] = included.isend(0, 0, inputWorkspace->readX(0)); reqs[1] = included.isend(0, 1, inputWorkspace->readY(0)); reqs[2] = included.isend(0, 2, inputWorkspace->readE(0)); // Make sure the sends have completed before exiting the algorithm mpi::wait_all(reqs, reqs + 3); } } } }
void GroupDetectors::exec() { // Get the input workspace const MatrixWorkspace_sptr WS = getProperty("Workspace"); std::vector<size_t> indexList = getProperty("WorkspaceIndexList"); std::vector<specid_t> spectraList = getProperty("SpectraList"); const std::vector<detid_t> detectorList = getProperty("DetectorList"); // Could create a Validator to replace the below if ( indexList.empty() && spectraList.empty() && detectorList.empty() ) { g_log.information(name() + ": WorkspaceIndexList, SpectraList, and DetectorList properties are all empty, no grouping done"); return; } // Bin boundaries need to be the same, so check if they actually are if (!API::WorkspaceHelpers::commonBoundaries(WS)) { g_log.error("Can only group if the histograms have common bin boundaries"); throw std::runtime_error("Can only group if the histograms have common bin boundaries"); } // If the spectraList property has been set, need to loop over the workspace looking for the // appropriate spectra number and adding the indices they are linked to the list to be processed if ( ! spectraList.empty() ) { WS->getIndicesFromSpectra(spectraList,indexList); }// End dealing with spectraList else if ( ! detectorList.empty() ) { // Dealing with DetectorList //convert from detectors to workspace indices WS->getIndicesFromDetectorIDs(detectorList, indexList); } if ( indexList.empty() ) { g_log.warning("Nothing to group"); return; } const size_t vectorSize = WS->blocksize(); const specid_t firstIndex = static_cast<specid_t>(indexList[0]); ISpectrum * firstSpectrum = WS->getSpectrum(firstIndex); setProperty("ResultIndex",firstIndex); // loop over the spectra to group Progress progress(this, 0.0, 1.0, static_cast<int>(indexList.size()-1)); for (size_t i = 0; i < indexList.size()-1; ++i) { // The current spectrum const size_t currentIndex = indexList[i+1]; ISpectrum * spec = WS->getSpectrum(currentIndex); // Add the current detector to belong to the first spectrum firstSpectrum->addDetectorIDs(spec->getDetectorIDs()); // Add up all the Y spectra and store the result in the first one // Need to keep the next 3 lines inside loop for now until ManagedWorkspace mru-list works properly MantidVec &firstY = WS->dataY(firstIndex); MantidVec::iterator fYit; MantidVec::iterator fEit = firstSpectrum->dataE().begin(); MantidVec::iterator Yit = spec->dataY().begin(); MantidVec::iterator Eit = spec->dataE().begin(); for (fYit = firstY.begin(); fYit != firstY.end(); ++fYit, ++fEit, ++Yit, ++Eit) { *fYit += *Yit; // Assume 'normal' (i.e. Gaussian) combination of errors *fEit = sqrt( (*fEit)*(*fEit) + (*Eit)*(*Eit) ); } // Now zero the now redundant spectrum and set its spectraNo to indicate this (using -1) // N.B. Deleting spectra would cause issues for ManagedWorkspace2D, hence the the approach taken here spec->dataY().assign(vectorSize,0.0); spec->dataE().assign(vectorSize,0.0); spec->setSpectrumNo(-1); spec->clearDetectorIDs(); progress.report(); } }
/** * This function deals with the logic necessary for summing a Workspace2D. * @param outSpec The spectrum for the summed output. * @param progress The progress indicator. * @param numSpectra The number of spectra contributed to the sum. * @param numMasked The spectra dropped from the summations because they are * masked. * @param numZeros The number of zero bins in histogram workspace or empty * spectra for event workspace. */ void SumSpectra::doWorkspace2D(ISpectrum &outSpec, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get references to the output workspaces's data vectors auto &OutputYSum = outSpec.mutableY(); auto &OutputYError = outSpec.mutableE(); std::vector<double> Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(OutputYSum.size(), 0); nZeros.assign(OutputYSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; MatrixWorkspace_sptr in_ws = getProperty("InputWorkspace"); // Clean workspace of any NANs or Inf values auto localworkspace = replaceSpecialValues(in_ws); const auto &spectrumInfo = localworkspace->spectrumInfo(); // Loop over spectra for (const auto wsIndex : this->m_indices) { // Don't go outside the range. if ((wsIndex >= this->m_numberOfSpectra) || (wsIndex < 0)) { g_log.error() << "Invalid index " << wsIndex << " was specified. Sum was aborted.\n"; break; } if (spectrumInfo.hasDetectors(wsIndex)) { // Skip monitors, if the property is set to do so if (!m_keepMonitors && spectrumInfo.isMonitor(wsIndex)) continue; // Skip masked detectors if (spectrumInfo.isMasked(wsIndex)) { numMasked++; continue; } } numSpectra++; const auto &YValues = localworkspace->y(wsIndex); const auto &YErrors = localworkspace->e(wsIndex); // Retrieve the spectrum into a vector for (int i = 0; i < m_yLength; ++i) { if (m_calculateWeightedSum) { if (std::isnormal(YErrors[i])) { const double errsq = YErrors[i] * YErrors[i]; OutputYError[i] += errsq; Weight[i] += 1. / errsq; OutputYSum[i] += YValues[i] / errsq; } else { nZeros[i]++; } } else { OutputYSum[i] += YValues[i]; OutputYError[i] += YErrors[i] * YErrors[i]; } } // Map all the detectors onto the spectrum of the output outSpec.addDetectorIDs( localworkspace->getSpectrum(wsIndex).getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (numSpectra > nZeros[i]) OutputYSum[i] *= double(numSpectra - nZeros[i]) / Weight[i]; if (nZeros[i] != 0) numZeros += nZeros[i]; } } }