From b04a8108ea15e21f97d70aa98875647fb63d5890 Mon Sep 17 00:00:00 2001 From: Alex Buts <Alex.Buts@stfc.ac.uk> Date: Tue, 27 Nov 2012 15:29:12 +0000 Subject: [PATCH] refs #6230 Modified sum spectra to produce weighted sum on request --- .gitignore | 1 + .../inc/MantidAlgorithms/SumSpectra.h | 9 +- .../Framework/Algorithms/src/SumSpectra.cpp | 130 ++++++++++++++---- .../Algorithms/test/SumSpectraTest.h | 114 ++++++++++++++- 4 files changed, 221 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 3a6cdc58602..dfee419542c 100644 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,4 @@ Desktop.ini # Mac OS X Finder .DS_Store +/Code\Mantid\Framework\API\test/*.cpp diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h index ecf4a074a83..a0064014fac 100644 --- a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h @@ -69,10 +69,12 @@ public: private: /// Handle logic for RebinnedOutput workspaces void doRebinnedOutput(API::MatrixWorkspace_sptr outputWorkspace, - API::Progress &progress); + API::Progress &progress, + size_t &numSpectra,size_t &numMasked,size_t &numZeros); /// Handle logic for Workspace2D workspaces void doWorkspace2D(API::MatrixWorkspace_const_sptr localworkspace, - API::ISpectrum *outSpec, API::Progress &progress); + API::ISpectrum *outSpec, API::Progress &progress, + size_t &numSpectra,size_t &numMasked,size_t &numZeros); /// Sets documentation strings for this algorithm virtual void initDocs(); // Overridden Algorithm methods @@ -95,6 +97,9 @@ private: int yLength; /// Set of indicies to sum std::set<int> indices; + + // if calculateing additional workspace with specially weighted averages is necessary + bool m_CalculateWeightedSum; }; } // namespace Algorithm diff --git a/Code/Mantid/Framework/Algorithms/src/SumSpectra.cpp b/Code/Mantid/Framework/Algorithms/src/SumSpectra.cpp index 90b728eba19..1dc5cbdda2a 100644 --- a/Code/Mantid/Framework/Algorithms/src/SumSpectra.cpp +++ b/Code/Mantid/Framework/Algorithms/src/SumSpectra.cpp @@ -60,6 +60,10 @@ void SumSpectra::init() "Can be specified instead of in addition to StartWorkspaceIndex and EndWorkspaceIndex."); declareProperty("IncludeMonitors",true,"Whether to include monitor spectra in the sum (default: yes)"); + + declareProperty("WeightedSum",false,"Instead of the usual spectra sum, calculate the weighted sum in the form: \n" + "<math>\\Sigma(Signal_i/Error_i^2)/\\Sigma(1/Error_i^2)</math> This property is ignored for event workspace.\n" + "The sums are defined for <math>Error_i != 0</math> only, so the values are NaN if error for some value is equal to 0."); } /** Executes the algorithm @@ -115,9 +119,13 @@ void SumSpectra::exec() g_log.information() << "Spectra remapping gives single spectra with spectra number: " << m_outSpecId << "\n"; + m_CalculateWeightedSum = getProperty("WeightedSum"); + + EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const EventWorkspace>(localworkspace); if (eventW) { + m_CalculateWeightedSum = false; this->execEvent(eventW, this->indices); } else @@ -127,7 +135,10 @@ void SumSpectra::exec() // Create the 2D workspace for the output MatrixWorkspace_sptr outputWorkspace = API::WorkspaceFactory::Instance().create(localworkspace, 1,localworkspace->readX(0).size(),this->yLength); - + size_t numSpectra(0); // total number of processed spectra + size_t numMasked(0); // total number of the masked and skipped spectra + size_t numZeros(0); // number of spectra which have 0 value in the first column (used in special cases of evaluating how good Puasonian statistics is) + Progress progress(this, 0, 1, this->indices.size()); // This is the (only) output spectrum @@ -142,11 +153,11 @@ void SumSpectra::exec() if (localworkspace->id() == "RebinnedOutput") { - this->doRebinnedOutput(outputWorkspace, progress); + this->doRebinnedOutput(outputWorkspace, progress,numSpectra,numMasked,numZeros); } else { - this->doWorkspace2D(localworkspace, outSpec, progress); + this->doWorkspace2D(localworkspace, outSpec, progress,numSpectra,numMasked,numZeros); } // Pointer to sqrt function @@ -157,6 +168,11 @@ void SumSpectra::exec() std::transform(YError.begin(), YError.end(), YError.begin(), rs); outputWorkspace->generateSpectraMap(); + // set up the summing statistics + outputWorkspace->mutableRun().addProperty("NumAllSpectra",numSpectra,"",true); + outputWorkspace->mutableRun().addProperty("NumMaskSpectra",numMasked,"",true); + outputWorkspace->mutableRun().addProperty("NumZeroSpectra",numZeros,"",true); + // Assign it to the output workspace property setProperty("OutputWorkspace", outputWorkspace); @@ -199,12 +215,17 @@ specid_t SumSpectra::getOutputSpecId(MatrixWorkspace_const_sptr localworkspace) * @param progress the progress indicator */ void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace, - ISpectrum *outSpec, Progress &progress) + ISpectrum *outSpec, Progress &progress, + size_t &numSpectra,size_t &numMasked,size_t &numZeros) { // Get references to the output workspaces's data vectors MantidVec& YSum = outSpec->dataY(); MantidVec& YError = outSpec->dataE(); + MantidVec Weight; + if(m_CalculateWeightedSum)Weight.assign(YSum.size(),0); + + // Loop over spectra std::set<int>::iterator it; //for (int i = m_MinSpec; i <= m_MaxSpec; ++i) @@ -225,28 +246,60 @@ void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace, // Skip monitors, if the property is set to do so if ( !keepMonitors && det->isMonitor() ) continue; // Skip masked detectors - if ( det->isMasked() ) continue; + 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); - - for (int k = 0; k < this->yLength; ++k) + if(m_CalculateWeightedSum) { - YSum[k] += YValues[k]; - YError[k] += YErrors[k]*YErrors[k]; + for (int k = 0; k < this->yLength; ++k) + { + if(YErrors[k]!=0) + { + double errsq = YErrors[k]*YErrors[k]; + YError[k] +=errsq; + Weight[k] +=1./errsq; + YSum[k] += YValues[k]/errsq; + } + else + { + YSum[k] =std::numeric_limits<double>::quiet_NaN(); + Weight[k]=std::numeric_limits<double>::quiet_NaN(); + } + } + } + else + { + for (int k = 0; k < this->yLength; ++k) + { + YSum[k] += YValues[k]; + YError[k] += YErrors[k]*YErrors[k]; + } } // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs( localworkspace->getSpectrum(i)->getDetectorIDs() ); + if(YSum[0]==0)numZeros++; progress.report(); } + if(m_CalculateWeightedSum) + { + for(size_t i=0;i<Weight.size();i++) + YSum[i]/=Weight[i]; + } + } /** @@ -255,7 +308,8 @@ void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace, * @param progress the progress indicator */ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, - Progress &progress) + Progress &progress, + size_t &numSpectra,size_t &numMasked,size_t &numZeros) { // Get a copy of the input workspace MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); @@ -283,12 +337,11 @@ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, MantidVec& YSum = outSpec->dataY(); MantidVec& YError = outSpec->dataE(); MantidVec& FracSum = outWS->dataF(0); + MantidVec Weight; + if(m_CalculateWeightedSum)Weight.assign(YSum.size(),0); // Loop over spectra std::set<int>::iterator it; - size_t numSpectra(0); // total number of processed spectra - size_t numMasked(0); // total number of the masked and skipped spectra - size_t numZeros(0); // number of spectra which have 0 value in the first column (used in special cases of evaluating how good Puasonian statistics is) //for (int i = m_MinSpec; i <= m_MaxSpec; ++i) for (it = indices.begin(); it != indices.end(); ++it) { @@ -300,7 +353,6 @@ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, break; } - numSpectra++; try { // Get the detector object for this spectrum @@ -318,19 +370,43 @@ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, { // 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); - for (int k = 0; k < this->yLength; ++k) + if(m_CalculateWeightedSum) + { + for (int k = 0; k < this->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 + { + YSum[k] =std::numeric_limits<double>::quiet_NaN(); + Weight[k]=std::numeric_limits<double>::quiet_NaN(); + FracSum[k] += FracArea[k]; + } + } + } + else { - YSum[k] += YValues[k] * FracArea[k]; - YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; - FracSum[k] += FracArea[k]; + for (int k = 0; k < this->yLength; ++k) + { + YSum[k] += YValues[k] * FracArea[k]; + YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; + FracSum[k] += FracArea[k]; + } } - if(YValues[0]==0)numZeros++; + if(YSum[0]==0)numZeros++; // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs()); @@ -338,11 +414,7 @@ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, progress.report(); } - outWS->mutableRun().addProperty("NumAllSpectra",numSpectra,"",true); - outWS->mutableRun().addProperty("NumMaskSpectra",numMasked,"",true); - outWS->mutableRun().addProperty("NumZeroSpectra",numZeros,"",true); - - // Create the correct representation + // Create the correct representation outWS->finalize(); } @@ -367,10 +439,9 @@ void SumSpectra::execEvent(EventWorkspace_const_sptr localworkspace, std::set<in // Loop over spectra std::set<int>::iterator it; - size_t numSpectra(0); // total number of processed spectra - size_t numMasked(0); // total number of the masked and skipped spectra - size_t numZeros(0); // number of fully empty spectra with no events (used in special cases of evaluating how good Puasonian statistics is) - + size_t numSpectra(0); + size_t numMasked(0); + size_t numZeros(0); //for (int i = m_MinSpec; i <= m_MaxSpec; ++i) for (it = indices.begin(); it != indices.end(); ++it) { @@ -382,7 +453,6 @@ void SumSpectra::execEvent(EventWorkspace_const_sptr localworkspace, std::set<in break; } - numSpectra++; try { // Get the detector object for this spectrum @@ -400,6 +470,8 @@ void SumSpectra::execEvent(EventWorkspace_const_sptr localworkspace, std::set<in { // if the detector not found just carry on } + numSpectra++; + //Add the event lists with the operator const EventList & tOutEL = localworkspace->getEventList(i); if(tOutEL.empty()) diff --git a/Code/Mantid/Framework/Algorithms/test/SumSpectraTest.h b/Code/Mantid/Framework/Algorithms/test/SumSpectraTest.h index b53f7297c11..60ec923ce59 100644 --- a/Code/Mantid/Framework/Algorithms/test/SumSpectraTest.h +++ b/Code/Mantid/Framework/Algorithms/test/SumSpectraTest.h @@ -8,6 +8,7 @@ #include "MantidDataObjects/Workspace2D.h" #include "MantidGeometry/Instrument/ParameterMap.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include <boost/lexical_cast.hpp> #include <cxxtest/TestSuite.h> using namespace Mantid; @@ -22,8 +23,9 @@ public: SumSpectraTest() { - inputSpace = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(10,102,true); - inputSpace->instrumentParameters().addBool(inputSpace->getDetector(1).get(),"masked",true); + this->nTestHist=10; + this->inputSpace = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(nTestHist,102,true); + this->inputSpace->instrumentParameters().addBool(inputSpace->getDetector(1).get(),"masked",true); } ~SumSpectraTest() @@ -82,6 +84,15 @@ public: TS_ASSERT_EQUALS( spec->getDetectorIDs().size(), 2); TS_ASSERT( spec->hasDetectorID(3) ); TS_ASSERT( spec->hasDetectorID(4) ); + + TS_ASSERT(output2D->run().hasProperty("NumAllSpectra")) + TS_ASSERT(output2D->run().hasProperty("NumMaskSpectra")) + TS_ASSERT(output2D->run().hasProperty("NumZeroSpectra")) + + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(3-1),output2D->run().getLogData("NumAllSpectra")->value()) + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(1),output2D->run().getLogData("NumMaskSpectra")->value()) + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(0),output2D->run().getLogData("NumZeroSpectra")->value()) + } void testExecWithoutLimits() @@ -140,6 +151,17 @@ public: TS_ASSERT( spec->hasDetectorID(6) ); TS_ASSERT( spec->hasDetectorID(7) ); + + TS_ASSERT(output2D->run().hasProperty("NumAllSpectra")) + TS_ASSERT(output2D->run().hasProperty("NumMaskSpectra")) + TS_ASSERT(output2D->run().hasProperty("NumZeroSpectra")) + + // Spectra at workspace index 1 is masked, 8 & 9 are monitors + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(nTestHist-3),output2D->run().getLogData("NumAllSpectra")->value()) + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(1),output2D->run().getLogData("NumMaskSpectra")->value()) + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(0),output2D->run().getLogData("NumZeroSpectra")->value()) + + } void testExecEvent_inplace() @@ -186,6 +208,11 @@ public: TS_ASSERT_EQUALS(output->getNumberHistograms(), 1); TS_ASSERT_EQUALS(output->getNumberEvents(), 9 * numEvents); TS_ASSERT_EQUALS(input->readX(0).size(), output->readX(0).size()); + + TS_ASSERT(output->run().hasProperty("NumAllSpectra")) + TS_ASSERT(output->run().hasProperty("NumMaskSpectra")) + TS_ASSERT(output->run().hasProperty("NumZeroSpectra")) + } void testRebinnedOutputSum() @@ -195,6 +222,7 @@ public: std::string outName = "rebin_sum"; AnalysisDataService::Instance().addOrReplace(inName, ws); + size_t nHist = ws->getNumberHistograms(); // Start with a clean algorithm Mantid::Algorithms::SumSpectra alg3; @@ -223,9 +251,91 @@ public: TS_ASSERT_DELTA(output->dataY(0)[5], 0.66666, 1.e-5); TS_ASSERT_DELTA(output->dataE(0)[5], 0.47140452079103173, 1.e-5); TS_ASSERT_EQUALS(output->dataF(0)[5], 3.); + + TS_ASSERT(output->run().hasProperty("NumAllSpectra")) + TS_ASSERT(output->run().hasProperty("NumMaskSpectra")) + TS_ASSERT(output->run().hasProperty("NumZeroSpectra")) + + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(nHist),output->run().getLogData("NumAllSpectra")->value()) + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(0),output->run().getLogData("NumMaskSpectra")->value()) + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(3),output->run().getLogData("NumZeroSpectra")->value()) + } + void testExecNoLimitsWeighted() + { + Mantid::Algorithms::SumSpectra alg2; + TS_ASSERT_THROWS_NOTHING( alg2.initialize()); + TS_ASSERT( alg2.isInitialized() ); + + + const Mantid::MantidVec &y0 = inputSpace->readY(0); + const Mantid::MantidVec &e0 = inputSpace->readE(0); + // Set the properties + alg2.setProperty("InputWorkspace",inputSpace); + const std::string outputSpace2 = "SumSpectraOut2"; + alg2.setPropertyValue("OutputWorkspace",outputSpace2); + alg2.setProperty("IncludeMonitors",false); + alg2.setProperty("WeightedSum",true); + + TS_ASSERT_THROWS_NOTHING( alg2.execute()); + TS_ASSERT( alg2.isExecuted() ); + + // Get back the saved workspace + Workspace_sptr output; + TS_ASSERT_THROWS_NOTHING(output = AnalysisDataService::Instance().retrieve(outputSpace2)); + Workspace2D_const_sptr output2D = boost::dynamic_pointer_cast<const Workspace2D>(output); + + TS_ASSERT_EQUALS( output2D->getNumberHistograms(), 1); + + const Mantid::MantidVec &x = output2D->readX(0); + const Mantid::MantidVec &y = output2D->readY(0); + const Mantid::MantidVec &e = output2D->readE(0); + TS_ASSERT_EQUALS( x.size(), 103 ); + TS_ASSERT_EQUALS( y.size(), 102 ); + TS_ASSERT_EQUALS( e.size(), 102 ); + + TS_ASSERT(output2D->run().hasProperty("NumAllSpectra")) + TS_ASSERT(output2D->run().hasProperty("NumMaskSpectra")) + TS_ASSERT(output2D->run().hasProperty("NumZeroSpectra")) + + // Spectra at workspace index 1 is masked, 8 & 9 are monitors + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(nTestHist-3),output2D->run().getLogData("NumAllSpectra")->value()) + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(1),output2D->run().getLogData("NumMaskSpectra")->value()) + TS_ASSERT_EQUALS(boost::lexical_cast<std::string>(0),output2D->run().getLogData("NumZeroSpectra")->value()) + + size_t nSignals = nTestHist-3; + // Check a few bins + TS_ASSERT_EQUALS( x[0], inputSpace->readX(0)[0] ); + TS_ASSERT_EQUALS( x[50], inputSpace->readX(0)[50] ); + TS_ASSERT_EQUALS( x[100], inputSpace->readX(0)[100] ); + TS_ASSERT_EQUALS( y[7], y0[7] ); + TS_ASSERT_EQUALS( y[38],y0[38] ); + TS_ASSERT_EQUALS( y[72],y0[72] ); + TS_ASSERT_DELTA( e[28], std::sqrt(double(nSignals))*e0[28], 0.00001 ); + TS_ASSERT_DELTA( e[47], std::sqrt(double(nSignals))*e0[47], 0.00001 ); + TS_ASSERT_DELTA( e[99], std::sqrt(double(nSignals))*e0[99], 0.00001 ); + + + // Check the detectors mapped to the single spectra + const ISpectrum * spec = output2D->getSpectrum(0); + TS_ASSERT_EQUALS( spec->getSpectrumNo(), 1); + // Spectra at workspace index 1 is masked, 8 & 9 are monitors + TS_ASSERT_EQUALS( spec->getDetectorIDs().size(), 7); + TS_ASSERT( spec->hasDetectorID(1) ); + TS_ASSERT( spec->hasDetectorID(3) ); + TS_ASSERT( spec->hasDetectorID(4) ); + TS_ASSERT( spec->hasDetectorID(5) ); + TS_ASSERT( spec->hasDetectorID(6) ); + TS_ASSERT( spec->hasDetectorID(7) ); + + + + + } + private: + int nTestHist; Mantid::Algorithms::SumSpectra alg; // Test with range limits MatrixWorkspace_sptr inputSpace; }; -- GitLab