/*** * This will add the maximum spectrum number from ws1 to the data coming from ws2. * * @param ws1 The first workspace supplied to the algorithm. * @param ws2 The second workspace supplied to the algorithm. * @param output The workspace that is going to be returned by the algorithm. */ void ConjoinWorkspaces::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr /*ws2*/, API::MatrixWorkspace_sptr output) { // make sure we should bother. If you don't check for overlap, you don't need to if (this->getProperty("CheckOverlapping")) return; // is everything possibly ok? specid_t min; specid_t max; getMinMax(output, min, max); if (max - min >= static_cast<specid_t>(output->getNumberHistograms())) // nothing to do then return; // information for remapping the spectra numbers specid_t ws1min; specid_t ws1max; getMinMax(ws1, ws1min, ws1max); // change the axis by adding the maximum existing spectrum number to the current value for (size_t i = ws1->getNumberHistograms(); i < output->getNumberHistograms(); i++) { specid_t origid; origid = output->getSpectrum(i)->getSpectrumNo(); output->getSpectrum(i)->setSpectrumNo(origid + ws1max); } // To be deprecated: output->generateSpectraMap(); }
/** Calculates the normalization constant for the exponential decay * @param ws :: [input] Workspace containing the spectra to remove exponential * from * @return :: Vector containing the normalization constants, N0, for each * spectrum */ std::vector<double> PhaseQuadMuon::getExponentialDecay(const API::MatrixWorkspace_sptr &ws) { size_t nspec = ws->getNumberHistograms(); size_t npoints = ws->blocksize(); // Muon life time in microseconds double muLife = PhysicalConstants::MuonLifetime * 1e6; std::vector<double> n0(nspec, 0.); for (size_t h = 0; h < ws->getNumberHistograms(); h++) { const auto &X = ws->getSpectrum(h).x(); const auto &Y = ws->getSpectrum(h).y(); const auto &E = ws->getSpectrum(h).e(); double s, sx, sy; s = sx = sy = 0; for (size_t i = 0; i < npoints; i++) { if (Y[i] > 0) { double sig = E[i] * E[i] / Y[i] / Y[i]; s += 1. / sig; sx += (X[i] - X[0]) / sig; sy += log(Y[i]) / sig; } } n0[h] = exp((sy + sx / muLife) / s); } return n0; }
/** Add workspace2 to workspace1 by adding spectrum. */ MatrixWorkspace_sptr AlignAndFocusPowder::conjoinWorkspaces(API::MatrixWorkspace_sptr ws1, API::MatrixWorkspace_sptr ws2, size_t offset) { // Get information from ws1: maximum spectrum number, and store original // spectrum Nos size_t nspec1 = ws1->getNumberHistograms(); specnum_t maxspecNo1 = 0; std::vector<specnum_t> origspecNos; for (size_t i = 0; i < nspec1; ++i) { specnum_t tmpspecNo = ws1->getSpectrum(i).getSpectrumNo(); origspecNos.push_back(tmpspecNo); if (tmpspecNo > maxspecNo1) maxspecNo1 = tmpspecNo; } g_log.information() << "[DBx536] Max spectrum number of ws1 = " << maxspecNo1 << ", Offset = " << offset << ".\n"; size_t nspec2 = ws2->getNumberHistograms(); // Conjoin 2 workspaces Algorithm_sptr alg = this->createChildAlgorithm("AppendSpectra"); alg->initialize(); ; alg->setProperty("InputWorkspace1", ws1); alg->setProperty("InputWorkspace2", ws2); alg->setProperty("OutputWorkspace", ws1); alg->setProperty("ValidateInputs", false); alg->executeAsChildAlg(); API::MatrixWorkspace_sptr outws = alg->getProperty("OutputWorkspace"); // FIXED : Restore the original spectrum Nos to spectra from ws1 for (size_t i = 0; i < nspec1; ++i) { specnum_t tmpspecNo = outws->getSpectrum(i).getSpectrumNo(); outws->getSpectrum(i).setSpectrumNo(origspecNos[i]); g_log.information() << "[DBx540] Conjoined spectrum " << i << ": restore spectrum number to " << outws->getSpectrum(i).getSpectrumNo() << " from spectrum number = " << tmpspecNo << ".\n"; } // Rename spectrum number if (offset >= 1) { for (size_t i = 0; i < nspec2; ++i) { specnum_t newspecid = maxspecNo1 + static_cast<specnum_t>((i) + offset); outws->getSpectrum(nspec1 + i).setSpectrumNo(newspecid); // ISpectrum* spec = outws->getSpectrum(nspec1+i); // if (spec) // spec->setSpectrumNo(3); } } return outws; }
/** * Read spectra from the DAE * @param period :: Current period index * @param index :: First spectrum index * @param count :: Number of spectra to read * @param workspace :: Workspace to store the data * @param workspaceIndex :: index in workspace to store data */ void ISISHistoDataListener::getData(int period, int index, int count, API::MatrixWorkspace_sptr workspace, size_t workspaceIndex) { const int numberOfBins = m_numberOfBins[m_timeRegime]; const size_t bufferSize = count * (numberOfBins + 1) * sizeof(int); std::vector<int> dataBuffer(bufferSize); // Read in spectra from DAE int ndims = 2, dims[2]; dims[0] = count; dims[1] = numberOfBins + 1; int spectrumIndex = index + period * (m_totalNumberOfSpectra + 1); if (IDCgetdat(m_daeHandle, spectrumIndex, count, dataBuffer.data(), dims, &ndims) != 0) { g_log.error("Unable to read DATA from DAE " + m_daeName); throw Kernel::Exception::FileError("Unable to read DATA from DAE ", m_daeName); } for (size_t i = 0; i < static_cast<size_t>(count); ++i) { size_t wi = workspaceIndex + i; workspace->setX(wi, m_bins[m_timeRegime]); MantidVec &y = workspace->dataY(wi); MantidVec &e = workspace->dataE(wi); workspace->getSpectrum(wi)->setSpectrumNo(index + static_cast<specid_t>(i)); size_t shift = i * (numberOfBins + 1) + 1; y.assign(dataBuffer.begin() + shift, dataBuffer.begin() + shift + y.size()); std::transform(y.begin(), y.end(), e.begin(), dblSqrt); } }
/** This function will check how to group spectra when calculating median * * */ std::vector<std::vector<size_t> > DetectorDiagnostic::makeMap(API::MatrixWorkspace_sptr countsWS) { std::multimap<Mantid::Geometry::ComponentID,size_t> mymap; Geometry::Instrument_const_sptr instrument = countsWS->getInstrument(); if (m_parents==0) { return makeInstrumentMap(countsWS); } if (!instrument) { g_log.warning("Workspace has no instrument. LevelsUP is ignored"); return makeInstrumentMap(countsWS); } //check if not grouped. If grouped, it will throw if ( countsWS->hasGroupedDetectors() ) { throw std::runtime_error("Median detector test: not able to create detector to spectra map. Try with LevelUp=0."); } for(size_t i=0;i < countsWS->getNumberHistograms();i++) { detid_t d=(*((countsWS->getSpectrum(i))->getDetectorIDs().begin())); std::vector<boost::shared_ptr<const Mantid::Geometry::IComponent> > anc=instrument->getDetector(d)->getAncestors(); //std::vector<boost::shared_ptr<const IComponent> > anc=(*(countsWS->getSpectrum(i)->getDetectorIDs().begin()))->getAncestors(); if (anc.size()<static_cast<size_t>(m_parents)) { g_log.warning("Too many levels up. Will ignore LevelsUp"); m_parents=0; return makeInstrumentMap(countsWS); } mymap.insert(std::pair<Mantid::Geometry::ComponentID,size_t>(anc[m_parents-1]->getComponentID(),i)); } std::vector<std::vector<size_t> > speclist; std::vector<size_t> speclistsingle; std::multimap<Mantid::Geometry::ComponentID,size_t>::iterator m_it, s_it; for (m_it = mymap.begin(); m_it != mymap.end(); m_it = s_it) { Mantid::Geometry::ComponentID theKey = (*m_it).first; std::pair<std::multimap<Mantid::Geometry::ComponentID,size_t>::iterator,std::multimap<Mantid::Geometry::ComponentID,size_t>::iterator> keyRange = mymap.equal_range(theKey); // Iterate over all map elements with key == theKey speclistsingle.clear(); for (s_it = keyRange.first; s_it != keyRange.second; ++s_it) { speclistsingle.push_back( (*s_it).second ); } speclist.push_back(speclistsingle); } return speclist; }
/** Convert X units from nano-secs to micro-secs and shift to start at m_tMin * @param inputWs :: [input/output] workspace to convert */ void PhaseQuadMuon::convertToMicroSecs (API::MatrixWorkspace_sptr inputWs) { for (size_t h=0; h<inputWs->getNumberHistograms(); h++) { auto spec = inputWs->getSpectrum(h); for (int t=0; t<m_nData+1; t++) { spec->dataX()[t] = spec->dataX()[t]/1000+m_tMin; } } }
/*** * This will ensure the spectrum numbers do not overlap by starting the second *on at the first + 1 * * @param ws1 The first workspace supplied to the algorithm. * @param ws2 The second workspace supplied to the algorithm. * @param output The workspace that is going to be returned by the algorithm. */ void ConjoinWorkspaces::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr ws2, API::MatrixWorkspace_sptr output) { bool needsFix(false); if (this->getProperty("CheckOverlapping")) { // If CheckOverlapping is required, then either skip fixing spectrum number // or get stopped by an exception if (!m_overlapChecked) checkForOverlap(ws1, ws2, true); needsFix = false; } else { // It will be determined later whether spectrum number needs to be fixed. needsFix = true; } if (!needsFix) return; // is everything possibly ok? specid_t min; specid_t max; getMinMax(output, min, max); if (max - min >= static_cast<specid_t>( output->getNumberHistograms())) // nothing to do then return; // information for remapping the spectra numbers specid_t ws1min; specid_t ws1max; getMinMax(ws1, ws1min, ws1max); // change the axis by adding the maximum existing spectrum number to the // current value for (size_t i = ws1->getNumberHistograms(); i < output->getNumberHistograms(); i++) { specid_t origid; origid = output->getSpectrum(i)->getSpectrumNo(); output->getSpectrum(i)->setSpectrumNo(origid + ws1max); } }
/** * Mask the outlier values to get a better median value. * @param medianvec The median value calculated from the current counts. * @param countsWS The counts workspace. Any outliers will be masked here. * @param indexmap Index map. * @returns The number failed. */ int MedianDetectorTest::maskOutliers(const std::vector<double> medianvec, API::MatrixWorkspace_sptr countsWS,std::vector<std::vector<size_t> > indexmap) { // Fractions of the median const double out_lo = getProperty("LowOutlier"); const double out_hi = getProperty("HighOutlier"); int numFailed(0); bool checkForMask = false; Geometry::Instrument_const_sptr instrument = countsWS->getInstrument(); if (instrument != NULL) { checkForMask = ((instrument->getSource() != NULL) && (instrument->getSample() != NULL)); } for (size_t i=0; i<indexmap.size(); ++i) { std::vector<size_t> hists=indexmap.at(i); double median=medianvec.at(i); PARALLEL_FOR1(countsWS) for(int j = 0; j < static_cast<int>(hists.size()); ++j) { const double value = countsWS->readY(hists.at(j))[0]; if ((value == 0.) && checkForMask) { const std::set<detid_t>& detids = countsWS->getSpectrum(hists.at(j))->getDetectorIDs(); if (instrument->isDetectorMasked(detids)) { numFailed -= 1; // it was already masked } } if( (value < out_lo*median) && (value > 0.0) ) { countsWS->maskWorkspaceIndex(hists.at(j)); PARALLEL_ATOMIC ++numFailed; } else if( value > out_hi*median ) { countsWS->maskWorkspaceIndex(hists.at(j)); PARALLEL_ATOMIC ++numFailed; } } PARALLEL_CHECK_INTERUPT_REGION } return numFailed; }
/** Apply dead time correction to spectra in inputWs and create temporary workspace with corrected spectra * @param inputWs :: [input] input workspace containing spectra to correct * @param deadTimeTable :: [input] table containing dead times * @param tempWs :: [output] workspace containing corrected spectra */ void PhaseQuadMuon::deadTimeCorrection(API::MatrixWorkspace_sptr inputWs, API::ITableWorkspace_sptr deadTimeTable, API::MatrixWorkspace_sptr& tempWs) { // Apply correction only from t = m_tPulseOver // To do so, we first apply corrections to the whole spectrum (ApplyDeadTimeCorr // does not allow to select a range in the spectrum) // Then we recover counts from 0 to m_tPulseOver auto alg = this->createChildAlgorithm("ApplyDeadTimeCorr",-1,-1); alg->initialize(); alg->setProperty("DeadTimeTable", deadTimeTable); alg->setPropertyValue("InputWorkspace", inputWs->getName()); alg->setPropertyValue("OutputWorkspace", inputWs->getName()+"_deadtime"); bool sucDeadTime = alg->execute(); if (!sucDeadTime) { g_log.error() << "PhaseQuad: Unable to apply dead time corrections" << std::endl; throw std::runtime_error("PhaseQuad: Unable to apply dead time corrections"); } tempWs = alg->getProperty("OutputWorkspace"); // Now recover counts from t=0 to m_tPulseOver // Errors are set to m_bigNumber for (int h=0; h<m_nHist; h++) { auto specOld = inputWs->getSpectrum(h); auto specNew = tempWs->getSpectrum(h); for (int t=0; t<m_tPulseOver; t++) { specNew->dataY()[t] = specOld->dataY()[t]; specNew->dataE()[t] = m_bigNumber; } } }
/** * 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"; }
/** Fits each spectrum in the workspace to f(x) = A * sin( w * x + p) * @param ws :: [input] The workspace to fit * @param freq :: [input] Hint for the frequency (w) * @param groupName :: [input] The name of the output workspace group * @param resTab :: [output] Table workspace storing the asymmetries and phases * @param resGroup :: [output] Workspace group storing the fitting results */ void CalMuonDetectorPhases::fitWorkspace(const API::MatrixWorkspace_sptr &ws, double freq, std::string groupName, API::ITableWorkspace_sptr &resTab, API::WorkspaceGroup_sptr &resGroup) { int nhist = static_cast<int>(ws->getNumberHistograms()); // Create the fitting function f(x) = A * sin ( w * x + p ) // The same function and initial parameters are used for each fit std::string funcStr = createFittingFunction(freq, true); // Set up results table resTab->addColumn("int", "Spectrum number"); resTab->addColumn("double", "Asymmetry"); resTab->addColumn("double", "Phase"); // Loop through fitting all spectra individually const static std::string success = "success"; for (int wsIndex = 0; wsIndex < nhist; wsIndex++) { reportProgress(wsIndex, nhist); auto fit = createChildAlgorithm("Fit"); fit->initialize(); fit->setPropertyValue("Function", funcStr); fit->setProperty("InputWorkspace", ws); fit->setProperty("WorkspaceIndex", wsIndex); fit->setProperty("CreateOutput", true); fit->setPropertyValue("Output", groupName); fit->execute(); std::string status = fit->getProperty("OutputStatus"); if (!fit->isExecuted() || status != success) { std::ostringstream error; error << "Fit failed for spectrum at workspace index " << wsIndex; error << ": " << status; throw std::runtime_error(error.str()); } API::MatrixWorkspace_sptr fitOut = fit->getProperty("OutputWorkspace"); resGroup->addWorkspace(fitOut); API::ITableWorkspace_sptr tab = fit->getProperty("OutputParameters"); // Now we have our fitting results stored in tab // but we need to extract the relevant information, i.e. // the detector phases (parameter 'p') and asymmetries ('A') const auto &spectrum = ws->getSpectrum(static_cast<size_t>(wsIndex)); extractDetectorInfo(tab, resTab, spectrum.getSpectrumNo()); } }
/** If there is an overlap in spectrum numbers between ws1 and ws2, * then the spectrum numbers are reset as a simple 1-1 correspondence * with the workspace index. * * @param ws1 The first workspace supplied to the algorithm. * @param ws2 The second workspace supplied to the algorithm. * @param output The workspace that is going to be returned by the algorithm. */ void AppendSpectra::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr ws2, API::MatrixWorkspace_sptr output) { specid_t ws1min; specid_t ws1max; getMinMax(ws1, ws1min, ws1max); specid_t ws2min; specid_t ws2max; getMinMax(ws2, ws2min, ws2max); // is everything possibly ok? if (ws2min > ws1max) return; // change the axis by adding the maximum existing spectrum number to the current value for (size_t i = 0; i < output->getNumberHistograms(); i++) output->getSpectrum(i)->setSpectrumNo( specid_t(i) ); }
/** * The main method to calculate the ring profile for workspaces based on *instruments. * * It will iterate over all the spectrum inside the workspace. * For each spectrum, it will use the RingProfile::getBinForPixel method to *identify * where, in the output_bins, the sum of all the spectrum values should be *placed in. * * @param inputWS: pointer to the input workspace * @param output_bins: the reference to the vector to be filled with the *integration values */ void RingProfile::processInstrumentRingProfile( const API::MatrixWorkspace_sptr inputWS, std::vector<double> &output_bins) { for (int i = 0; i < static_cast<int>(inputWS->getNumberHistograms()); i++) { m_progress->report("Computing ring bins positions for detectors"); // for the detector based, the positions will be taken from the detector // itself. try { Mantid::Geometry::IDetector_const_sptr det = inputWS->getDetector(i); // skip monitors if (det->isMonitor()) { continue; } // this part will be executed if the instrument is attached to the // workspace // get the bin position int bin_n = getBinForPixel(det); if (bin_n < 0) // -1 is the agreement for an invalid bin, or outside the // ring being integrated continue; g_log.debug() << "Bin for the index " << i << " = " << bin_n << " Pos = " << det->getPos() << std::endl; // get the reference to the spectrum auto spectrum_pt = inputWS->getSpectrum(i); const MantidVec &refY = spectrum_pt->dataY(); // accumulate the values of this spectrum inside this bin for (size_t sp_ind = 0; sp_ind < inputWS->blocksize(); sp_ind++) output_bins[bin_n] += refY[sp_ind]; } catch (Kernel::Exception::NotFoundError &ex) { g_log.information() << "It found that detector for " << i << " is not valid. " << ex.what() << std::endl; continue; } } }
/** Create the final output workspace after converting the X axis * @returns the final output workspace * * @param progress :: Progress indicator * @param targetUnit :: Target conversion unit * @param inputWS :: Input workspace * @param nHist :: Stores the number of histograms */ MatrixWorkspace_sptr ConvertSpectrumAxis2::createOutputWorkspace( API::Progress &progress, const std::string &targetUnit, API::MatrixWorkspace_sptr &inputWS, size_t nHist) { // Create the output workspace. Can not re-use the input one because the // spectra are re-ordered. MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create( inputWS, m_indexMap.size(), inputWS->x(0).size(), inputWS->y(0).size()); // Now set up a new numeric axis holding the theta values corresponding to // each spectrum. auto const newAxis = new NumericAxis(m_indexMap.size()); outputWorkspace->replaceAxis(1, newAxis); progress.setNumSteps(nHist + m_indexMap.size()); // Set the units of the axis. if (targetUnit == "theta" || targetUnit == "Theta" || targetUnit == "signed_theta" || targetUnit == "SignedTheta") { newAxis->unit() = boost::make_shared<Units::Degrees>(); } else if (targetUnit == "ElasticQ") { newAxis->unit() = UnitFactory::Instance().create("MomentumTransfer"); } else if (targetUnit == "ElasticQSquared") { newAxis->unit() = UnitFactory::Instance().create("QSquared"); } std::multimap<double, size_t>::const_iterator it; size_t currentIndex = 0; for (it = m_indexMap.begin(); it != m_indexMap.end(); ++it) { // Set the axis value. newAxis->setValue(currentIndex, it->first); // Copy over the data. outputWorkspace->setHistogram(currentIndex, inputWS->histogram(it->second)); // We can keep the spectrum numbers etc. outputWorkspace->getSpectrum(currentIndex) .copyInfoFrom(inputWS->getSpectrum(it->second)); ++currentIndex; progress.report("Creating output workspace..."); } return outputWorkspace; }
/** * Construct an "empty" output workspace in virtual-lambda for summation in Q. * * @param detectorWS [in] :: the input workspace * @param indices [in] :: the workspace indices of the foreground histograms * @param refAngles [in] :: the reference angles * @return :: a 1D workspace where y values are all zero */ API::MatrixWorkspace_sptr ReflectometrySumInQ::constructIvsLamWS( const API::MatrixWorkspace &detectorWS, const Indexing::SpectrumIndexSet &indices, const Angles &refAngles) { // Calculate the number of bins based on the min/max wavelength, using // the same bin width as the input workspace const auto &edges = detectorWS.binEdges(refAngles.referenceWSIndex); const double binWidth = (edges.back() - edges.front()) / static_cast<double>(edges.size()); const auto wavelengthRange = findWavelengthMinMax(detectorWS, indices, refAngles); if (std::abs(wavelengthRange.max - wavelengthRange.min) < binWidth) { throw std::runtime_error("Given wavelength range too small."); } const int numBins = static_cast<int>( std::ceil((wavelengthRange.max - wavelengthRange.min) / binWidth)); // Construct the histogram with these X values. Y and E values are zero. const HistogramData::BinEdges bins( numBins + 1, HistogramData::LinearGenerator(wavelengthRange.min, binWidth)); const HistogramData::Counts counts(numBins, 0.); const HistogramData::Histogram modelHistogram(std::move(bins), std::move(counts)); // Create the output workspace API::MatrixWorkspace_sptr outputWS = DataObjects::create<DataObjects::Workspace2D>(detectorWS, 1, std::move(modelHistogram)); // Set the detector IDs and specturm number from the twoThetaR detector. const auto &thetaSpec = detectorWS.getSpectrum(refAngles.referenceWSIndex); auto &outSpec = outputWS->getSpectrum(0); outSpec.clearDetectorIDs(); outSpec.addDetectorIDs(thetaSpec.getDetectorIDs()); outSpec.setSpectrumNo(thetaSpec.getSpectrumNo()); return 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; }
/** Load a single bank into the workspace * * @param nexusfilename :: file to open * @param entry_name :: NXentry name * @param bankName :: NXdata bank name * @param WS :: workspace to modify * @param id_to_wi :: det ID to workspace index mapping */ void LoadTOFRawNexus::loadBank(const std::string &nexusfilename, const std::string &entry_name, const std::string &bankName, API::MatrixWorkspace_sptr WS, const detid2index_map &id_to_wi) { g_log.debug() << "Loading bank " << bankName << std::endl; // To avoid segfaults on RHEL5/6 and Fedora m_fileMutex.lock(); // Navigate to the point in the file auto file = new ::NeXus::File(nexusfilename); file->openGroup(entry_name, "NXentry"); file->openGroup("instrument", "NXinstrument"); file->openGroup(bankName, "NXdetector"); size_t m_numPixels = 0; std::vector<uint32_t> pixel_id; if (!m_assumeOldFile) { // Load the pixel IDs file->readData("pixel_id", pixel_id); m_numPixels = pixel_id.size(); if (m_numPixels == 0) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid pixel_id data in " << bankName << std::endl; return; } } else { // Load the x and y pixel offsets std::vector<float> xoffsets; std::vector<float> yoffsets; file->readData("x_pixel_offset", xoffsets); file->readData("y_pixel_offset", yoffsets); m_numPixels = xoffsets.size() * yoffsets.size(); if (0 == m_numPixels) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid (x,y) offsets in " << bankName << std::endl; return; } size_t bankNum = 0; if (bankName.size() > 4) { if (bankName.substr(0, 4) == "bank") { bankNum = boost::lexical_cast<size_t>(bankName.substr(4)); bankNum--; } else { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid bank number for " << bankName << std::endl; return; } } // All good, so construct the pixel ID listing size_t numX = xoffsets.size(); size_t numY = yoffsets.size(); for (size_t i = 0; i < numX; i++) { for (size_t j = 0; j < numY; j++) { pixel_id.push_back( static_cast<uint32_t>(j + numY * (i + numX * bankNum))); } } } size_t iPart = 0; if (m_spec_max != Mantid::EMPTY_INT()) { uint32_t ifirst = pixel_id[0]; range_check out_range(m_spec_min, m_spec_max, id_to_wi); auto newEnd = std::remove_if(pixel_id.begin(), pixel_id.end(), out_range); pixel_id.erase(newEnd, pixel_id.end()); // check if beginning or end of array was erased if (ifirst != pixel_id[0]) iPart = m_numPixels - pixel_id.size(); m_numPixels = pixel_id.size(); if (m_numPixels == 0) { file->close(); m_fileMutex.unlock(); g_log.warning() << "No pixels from " << bankName << std::endl; return; }; } // Load the TOF vector std::vector<float> tof; file->readData(m_axisField, tof); size_t m_numBins = tof.size() - 1; if (tof.size() <= 1) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid " << m_axisField << " data in " << bankName << std::endl; return; } // Make a shared pointer MantidVecPtr Xptr; MantidVec &X = Xptr.access(); X.resize(tof.size(), 0); X.assign(tof.begin(), tof.end()); // Load the data. Coerce ints into double. std::string errorsField = ""; std::vector<double> data; file->openData(m_dataField); file->getDataCoerce(data); if (file->hasAttr("errors")) file->getAttr("errors", errorsField); file->closeData(); // Load the errors bool hasErrors = !errorsField.empty(); std::vector<double> errors; if (hasErrors) { try { file->openData(errorsField); file->getDataCoerce(errors); file->closeData(); } catch (...) { g_log.information() << "Error loading the errors field, '" << errorsField << "' for bank " << bankName << ". Will use sqrt(counts). " << std::endl; hasErrors = false; } } /*if (data.size() != m_numBins * m_numPixels) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid size of '" << m_dataField << "' data in " << bankName << std::endl; return; } if (hasErrors && (errors.size() != m_numBins * m_numPixels)) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid size of '" << errorsField << "' errors in " << bankName << std::endl; return; } */ // Have all the data I need m_fileMutex.unlock(); file->close(); for (size_t i = iPart; i < iPart + m_numPixels; i++) { // Find the workspace index for this detector detid_t pixelID = pixel_id[i - iPart]; size_t wi = id_to_wi.find(pixelID)->second; // Set the basic info of that spectrum ISpectrum *spec = WS->getSpectrum(wi); spec->setSpectrumNo(specid_t(wi + 1)); spec->setDetectorID(pixel_id[i - iPart]); // Set the shared X pointer spec->setX(X); // Extract the Y MantidVec &Y = spec->dataY(); Y.assign(data.begin() + i * m_numBins, data.begin() + (i + 1) * m_numBins); MantidVec &E = spec->dataE(); if (hasErrors) { // Copy the errors from the loaded document E.assign(errors.begin() + i * m_numBins, errors.begin() + (i + 1) * m_numBins); } else { // Now take the sqrt(Y) to give E E = Y; std::transform(E.begin(), E.end(), E.begin(), (double (*)(double))sqrt); } } // Done! }
/** * Takes a single valued histogram workspace and assesses which histograms are within the limits. * Those that are not are masked on the input workspace. * @param countsWS :: Input/Output Integrated workspace to diagnose. * @param medianvec The median value calculated from the current counts. * @param indexmap Index map. * @param maskWS :: A mask workspace to apply. * @return The number of detectors that failed the tests, not including those skipped. */ int MedianDetectorTest::doDetectorTests(const API::MatrixWorkspace_sptr countsWS, const std::vector<double> medianvec, std::vector<std::vector<size_t> > indexmap, API::MatrixWorkspace_sptr maskWS) { g_log.debug("Applying the criteria to find failing detectors"); // A spectra can't fail if the statistics show its value is consistent with the mean value, // check the error and how many errorbars we are away const double minSigma = getProperty("SignificanceTest"); // prepare to report progress const int numSpec(m_maxSpec - m_minSpec); const int progStep = static_cast<int>(ceil(numSpec/30.0)); int steps(0); const double deadValue(1.0); int numFailed(0); bool checkForMask = false; Geometry::Instrument_const_sptr instrument = countsWS->getInstrument(); if (instrument != NULL) { checkForMask = ((instrument->getSource() != NULL) && (instrument->getSample() != NULL)); } PARALLEL_FOR2(countsWS, maskWS) for (int j=0;j<static_cast<int>(indexmap.size());++j) { std::vector<size_t> hists=indexmap.at(j); double median=medianvec.at(j); const size_t nhist = hists.size(); g_log.debug() << "new component with " <<nhist <<" spectra.\n"; for (size_t i = 0; i < nhist; ++i) { g_log.debug() << "Counts workspace index=" << i << ", Mask workspace index=" << hists.at(i) << std::endl; PARALLEL_START_INTERUPT_REGION ++steps; // update the progressbar information if (steps % progStep == 0) { progress(advanceProgress(progStep*static_cast<double>(RTMarkDetects)/numSpec)); } if (checkForMask) { const std::set<detid_t>& detids = countsWS->getSpectrum(i)->getDetectorIDs(); if (instrument->isDetectorMasked(detids)) { maskWS->dataY(hists.at(i))[0] = deadValue; continue; } if (instrument->isMonitor(detids)) { // Don't include in calculation but don't mask it continue; } } const double signal = countsWS->dataY(hists.at(i))[0]; // Mask out NaN and infinite if( boost::math::isinf(signal) || boost::math::isnan(signal) ) { maskWS->dataY(hists.at(i))[0] = deadValue; PARALLEL_ATOMIC ++numFailed; continue; } const double error = minSigma*countsWS->readE(hists.at(i))[0]; if( (signal < median*m_loFrac && (signal-median < -error)) || (signal > median*m_hiFrac && (signal-median > error)) ) { maskWS->dataY(hists.at(i))[0] = deadValue; PARALLEL_ATOMIC ++numFailed; } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Log finds g_log.information() << numFailed << " spectra failed the median tests.\n"; } return numFailed; }
/** Forms the quadrature phase signal (squashogram) * @param ws :: [input] workspace containing the measured spectra * @param phase :: [input] table workspace containing the detector phases * @param n0 :: [input] vector containing the normalization constants * @return :: workspace containing the quadrature phase signal */ API::MatrixWorkspace_sptr PhaseQuadMuon::squash(const API::MatrixWorkspace_sptr &ws, const API::ITableWorkspace_sptr &phase, const std::vector<double> &n0) { // Poisson limit: below this number we consider we don't have enough // statistics // to apply sqrt(N). This is an arbitrary number used in the original code // provided by scientists double poissonLimit = 30.; size_t nspec = ws->getNumberHistograms(); size_t npoints = ws->blocksize(); // Muon life time in microseconds double muLife = PhysicalConstants::MuonLifetime * 1e6; if (n0.size() != nspec) { throw std::invalid_argument("Invalid normalization constants"); } // Get the maximum asymmetry double maxAsym = 0.; for (size_t h = 0; h < nspec; h++) { if (phase->Double(h, 1) > maxAsym) { maxAsym = phase->Double(h, 1); } } if (maxAsym == 0.0) { throw std::invalid_argument("Invalid detector asymmetries"); } std::vector<double> aj, bj; { // Calculate coefficients aj, bj double sxx = 0; double syy = 0; double sxy = 0; for (size_t h = 0; h < nspec; h++) { double asym = phase->Double(h, 1) / maxAsym; double phi = phase->Double(h, 2); double X = n0[h] * asym * cos(phi); double Y = n0[h] * asym * sin(phi); sxx += X * X; syy += Y * Y; sxy += X * Y; } double lam1 = 2 * syy / (sxx * syy - sxy * sxy); double mu1 = 2 * sxy / (sxy * sxy - sxx * syy); double lam2 = 2 * sxy / (sxy * sxy - sxx * syy); double mu2 = 2 * sxx / (sxx * syy - sxy * sxy); for (size_t h = 0; h < nspec; h++) { double asym = phase->Double(h, 1) / maxAsym; double phi = phase->Double(h, 2); double X = n0[h] * asym * cos(phi); double Y = n0[h] * asym * sin(phi); aj.push_back((lam1 * X + mu1 * Y) * 0.5); bj.push_back((lam2 * X + mu2 * Y) * 0.5); } } // First X value double X0 = ws->x(0).front(); // Create and populate output workspace API::MatrixWorkspace_sptr ows = API::WorkspaceFactory::Instance().create( "Workspace2D", 2, npoints + 1, npoints); // X ows->setSharedX(0, ws->sharedX(0)); ows->setSharedX(1, ws->sharedX(0)); // Phase quadrature auto &realY = ows->mutableY(0); auto &imagY = ows->mutableY(1); auto &realE = ows->mutableE(0); auto &imagE = ows->mutableE(1); for (size_t i = 0; i < npoints; i++) { for (size_t h = 0; h < nspec; h++) { // (X,Y,E) with exponential decay removed const double X = ws->x(h)[i]; const double Y = ws->y(h)[i] - n0[h] * exp(-(X - X0) / muLife); const double E = (ws->y(h)[i] > poissonLimit) ? ws->e(h)[i] : sqrt(n0[h] * exp(-(X - X0) / muLife)); realY[i] += aj[h] * Y; imagY[i] += bj[h] * Y; realE[i] += aj[h] * aj[h] * E * E; imagE[i] += bj[h] * bj[h] * E * E; } realE[i] = sqrt(realE[i]); imagE[i] = sqrt(imagE[i]); // Regain exponential decay const double X = ws->getSpectrum(0).x()[i]; const double e = exp(-(X - X0) / muLife); realY[i] /= e; imagY[i] /= e; realE[i] /= e; imagE[i] /= e; } return ows; }
/** * Finds the median of values in single bin histograms rejecting spectra from masked * detectors and the results of divide by zero (infinite and NaN). * The median is an average that is less affected by small numbers of very large values. * @param input :: A histogram workspace with one entry in each bin * @param excludeZeroes :: If true then zeroes will not be included in the median calculation * @param indexmap :: indexmap * @return The median value of the histograms in the workspace that was passed to it * @throw out_of_range if a value is negative */ std::vector<double> DetectorDiagnostic::calculateMedian(const API::MatrixWorkspace_sptr input, bool excludeZeroes, std::vector<std::vector<size_t> > indexmap) { std::vector<double> medianvec; g_log.debug("Calculating the median count rate of the spectra"); for (size_t j=0; j< indexmap.size(); ++j) { std::vector<double> medianInput; std::vector<size_t> hists=indexmap.at(j); const int nhists = static_cast<int>(hists.size()); // The maximum possible length is that of workspace length medianInput.reserve(nhists); bool checkForMask = false; Geometry::Instrument_const_sptr instrument = input->getInstrument(); if (instrument != NULL) { checkForMask = ((instrument->getSource() != NULL) && (instrument->getSample() != NULL)); } PARALLEL_FOR1(input) for (int i = 0; i<static_cast<int>(hists.size()); ++i) { PARALLEL_START_INTERUPT_REGION if (checkForMask) { const std::set<detid_t>& detids = input->getSpectrum(hists[i])->getDetectorIDs(); if (instrument->isDetectorMasked(detids)) continue; if (instrument->isMonitor(detids)) continue; } const double yValue = input->readY(hists[i])[0]; if ( yValue < 0.0 ) { throw std::out_of_range("Negative number of counts found, could be corrupted raw counts or solid angle data"); } if( boost::math::isnan(yValue) || boost::math::isinf(yValue) || (excludeZeroes && yValue < DBL_EPSILON)) // NaNs/Infs { continue; } // Now we have a good value PARALLEL_CRITICAL(DetectorDiagnostic_median_d) { medianInput.push_back(yValue); } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION if(medianInput.empty()) { g_log.information("some group has no valid histograms. Will use 0 for median."); medianInput.push_back(0.); } // We need a sorted array to calculate the median std::sort(medianInput.begin(), medianInput.end()); double median = gsl_stats_median_from_sorted_data( &medianInput[0], 1, medianInput.size() ); if ( median < 0 || median > DBL_MAX/10.0 ) { throw std::out_of_range("The calculated value for the median was either negative or unreliably large"); } medianvec.push_back(median); } return medianvec; }