/** The function expects that the string passed to it contains a series of integers, * ranges specified with a '-' are possible * @param line :: a line read from the file, we'll interpret this * @param specs2index :: a map with spectra numbers as indexes and index numbers as values * @param output :: the list of integers, with any ranges expanded * @param unUsedSpec :: the list of spectra indexes that have been included in a group (so far) * @param seperator :: the symbol for the index range separator * @throw invalid_argument when a number couldn't be found or the number is not in the spectra map */ void GroupDetectors2::readSpectraIndexes(std::string line, spec2index_map &specs2index, std::vector<size_t> &output, std::vector<int64_t> &unUsedSpec, std::string seperator) { // remove comments and white space Poco::StringTokenizer dataComment(line, seperator, IGNORE_SPACES); Poco::StringTokenizer::Iterator iend = dataComment.end(); for( Poco::StringTokenizer::Iterator itr = dataComment.begin(); itr != iend; ++itr ) { std::vector<size_t> specNums; specNums.reserve(output.capacity()); RangeHelper::getList(*itr, specNums); std::vector<size_t>::const_iterator specN = specNums.begin(); for( ;specN!=specNums.end(); ++specN) { specid_t spectrumNum = static_cast<specid_t>(*specN); spec2index_map::const_iterator ind = specs2index.find(spectrumNum); if ( ind == specs2index.end() ) { g_log.debug() << name() << ": spectrum number " << spectrumNum << " refered to in the input file was not found in the input workspace\n"; throw std::invalid_argument("Spectrum number " + boost::lexical_cast<std::string>(spectrumNum) + " not found"); } if ( unUsedSpec[ind->second] != USED ) {// this array is used when the user sets KeepUngroupedSpectra, as well as to find duplicates unUsedSpec[ind->second] = USED; output.push_back( ind->second ); } else {// the spectra was already included in a group output.push_back( ind->second ); } } } }
/** Set the mask on the spectrum numbers or convert them to detector-s id if * sample workspace is provided *@param mask -- to mask or unmask appropriate spectra *@param maskedSpecID -- vector of the spectra numbers to process *@param singleDetIds -- vector of det-id-s to extend if workspace- * source of spectra-detector map is provided */ void LoadMask::processMaskOnWorkspaceIndex(bool mask, std::vector<int32_t> &maskedSpecID, std::vector<int32_t> &singleDetIds) { // 1. Check if (maskedSpecID.empty()) return; if (m_sourceMapWS) { // convert spectra masks into det-id mask using source workspace convertSpMasksToDetIDs(*m_sourceMapWS, maskedSpecID, singleDetIds); maskedSpecID .clear(); // spectra ID not needed any more as all converted to det-ids return; } // 2. Get Map const spec2index_map s2imap = m_maskWS->getSpectrumToWorkspaceIndexMap(); spec2index_map::const_iterator s2iter; // 3. Set mask auto spec0 = maskedSpecID[0]; auto prev_masks = spec0; for (size_t i = 0; i < maskedSpecID.size(); i++) { auto spec2mask = maskedSpecID[i]; s2iter = s2imap.find(spec2mask); if (s2iter == s2imap.end()) { // spectrum not found. bad branch g_log.error() << "Spectrum " << spec2mask << " does not have an entry in GroupWorkspace's spec2index map\n"; throw std::runtime_error("Logic error"); } else { size_t wsindex = s2iter->second; if (wsindex >= m_maskWS->getNumberHistograms()) { // workspace index is out of range. bad branch g_log.error() << "Group workspace's spec2index map is set wrong: " << " Found workspace index = " << wsindex << " for spectrum No " << spec2mask << " with workspace size = " << m_maskWS->getNumberHistograms() << '\n'; } else { // Finally set the masking; m_maskWS->mutableY(wsindex)[0] = (mask) ? 1.0 : 0.0; } // IF-ELSE: ws index out of range } // IF-ELSE: spectrum No has an entry if (spec2mask > prev_masks + 1) { g_log.debug() << "Masked Spectrum " << spec0 << " To " << prev_masks << '\n'; spec0 = spec2mask; } } // FOR EACH SpecNo }
/** Set the mask on the spectrum Nos */ void LoadMask::processMaskOnWorkspaceIndex(bool mask, std::vector<int32_t> pairslow, std::vector<int32_t> pairsup) { // 1. Check if (pairslow.empty()) return; if (pairslow.size() != pairsup.size()) { g_log.error() << "Input spectrum Nos are not paired. Size(low) = " << pairslow.size() << ", Size(up) = " << pairsup.size() << std::endl; throw std::invalid_argument("Input spectrum Nos are not paired. "); } // 2. Get Map const spec2index_map s2imap = m_maskWS->getSpectrumToWorkspaceIndexMap(); spec2index_map::const_iterator s2iter; // 3. Set mask for (size_t i = 0; i < pairslow.size(); i++) { // TODO Make this function work! g_log.debug() << "Mask Spectrum " << pairslow[i] << " To " << pairsup[i] << std::endl; for (int32_t specNo = pairslow[i]; specNo <= pairsup[i]; specNo++) { s2iter = s2imap.find(specNo); if (s2iter == s2imap.end()) { // spectrum not found. bad branch g_log.error() << "Spectrum " << specNo << " does not have an entry in GroupWorkspace's spec2index map" << std::endl; throw std::runtime_error("Logic error"); } else { size_t wsindex = s2iter->second; if (wsindex >= m_maskWS->getNumberHistograms()) { // workspace index is out of range. bad branch g_log.error() << "Group workspace's spec2index map is set wrong: " << " Found workspace index = " << wsindex << " for spectrum No " << specNo << " with workspace size = " << m_maskWS->getNumberHistograms() << std::endl; } else { // Finally set the group workspace. only good branch if (mask) m_maskWS->dataY(wsindex)[0] = 1.0; else m_maskWS->dataY(wsindex)[0] = 0.0; } // IF-ELSE: ws index out of range } // IF-ELSE: spectrum No has an entry } // FOR EACH SpecNo } // FOR EACH Pair return; }
/** A memory efficient function that adjusts the X-value bin boundaries that only creates a new * cow_ptr array when the offset has changed * @param offsets :: an array of times to adjust all the bins in each workspace histogram by * @param spectraList :: a list of spectra numbers in the same order as the offsets * @param specs2index :: a map that allows finding a spectra indexes from spectra numbers * @param missingDetectors :: this will be filled with the array indices of the detector offsets that we can't find spectra indices for */ void LoadDetectorInfo::adjustXsCommon(const std::vector<float> &offsets, const std::vector<specid_t> &spectraList, spec2index_map &specs2index, std::vector<detid_t> missingDetectors) { // space for cached values float cachedOffSet = UNSETOFFSET; MantidVecPtr monitorXs; MantidVecPtr cachedXs; double fracCompl = 1.0/3.0; for ( std::vector<int>::size_type j = 0; j < spectraList.size(); ++j ) {// first check that our spectranumber to spectra index map is working for us if ( specs2index.find(spectraList[j]) == specs2index.end() ) {// we can't find the spectrum associated the detector prepare to log that missingDetectors.push_back(static_cast<int>(j)); // and then move on to the next detector in the loop continue; } const size_t specIndex = specs2index[spectraList[j]]; // check if we dealing with a monitor as these are dealt by a different function const std::set<detid_t> & dets = m_workspace->getSpectrum(specIndex)->getDetectorIDs(); if ( dets.size() > 0 ) {// is it in the monitors list if ( m_monitors.find(*dets.begin()) == m_monitors.end() ) {// it's not a monitor, it's a regular detector if ( offsets[j] != cachedOffSet ) { setUpXArray(cachedXs, specIndex, offsets[j]); cachedOffSet = offsets[j]; } else m_workspace->setX(specIndex, cachedXs); } else {// it's a monitor if ( (*monitorXs).empty() ) { // negative because we add the monitor offset, not take away as for detectors, the difference between the monitor delay and the detectors that counts setUpXArray(monitorXs, specIndex, -m_monitOffset); } else m_workspace->setX(specIndex, monitorXs); } } if ( j % INTERVAL == INTERVAL/2 ) { fracCompl += (2.0*INTERVAL/3.0)/static_cast<double>(spectraList.size()); progress( fracCompl ); interruption_point(); } } }
/* * Set workspace index/group id by spectrum IDs */ void LoadDetectorsGroupingFile::setBySpectrumIDs() { // 1. Get map const spec2index_map s2imap = m_groupWS->getSpectrumToWorkspaceIndexMap(); spec2index_map::const_iterator s2iter; // 2. Locate in loop // std::map<int, std::vector<int> > m_groupSpectraMap; std::map<int, std::vector<int>>::iterator gsiter; for (gsiter = m_groupSpectraMap.begin(); gsiter != m_groupSpectraMap.end(); ++gsiter) { int groupid = gsiter->first; for (auto specid : gsiter->second) { s2iter = s2imap.find(specid); if (s2iter == s2imap.end()) { g_log.error() << "Spectrum " << specid << " does not have an entry in GroupWorkspace's spec2index map" << std::endl; throw std::runtime_error("Logic error"); } else { size_t wsindex = s2iter->second; if (wsindex >= m_groupWS->getNumberHistograms()) { g_log.error() << "Group workspace's spec2index map is set wrong: " << " Found workspace index = " << wsindex << " for spectrum ID " << specid << " with workspace size = " << m_groupWS->getNumberHistograms() << std::endl; } else { // Finally set the group workspace m_groupWS->dataY(wsindex)[0] = groupid; } // IF-ELSE: ws index out of range } // IF-ELSE: spectrum ID has an entry } // FOR: each spectrum ID } // FOR: each group ID return; }
/** * Updates from a more generic ascii file * @param filename :: The input filename */ void UpdateInstrumentFromFile::updateFromAscii(const std::string & filename) { AsciiFileHeader header; const bool isSpectrum = parseAsciiHeader(header); Geometry::Instrument_const_sptr inst = m_workspace->getInstrument(); // Throws for multiple detectors const spec2index_map specToIndex(m_workspace->getSpectrumToWorkspaceIndexMap()); std::ifstream datfile(filename.c_str(), std::ios_base::in); const int skipNLines = getProperty("SkipFirstNLines"); std::string line; int lineCount(0); while(lineCount < skipNLines) { std::getline(datfile,line); ++lineCount; } std::vector<double> colValues(header.colCount - 1, 0.0); while(std::getline(datfile,line)) { boost::trim(line); std::istringstream is(line); // Column 0 should be ID/spectrum number int32_t detOrSpec(-1000); is >> detOrSpec; // If first thing read is not a number then skip the line if(is.fail()) { g_log.debug() << "Skipping \"" << line << "\". Cannot interpret as list of numbers.\n"; continue; } Geometry::IDetector_const_sptr det; try { if(isSpectrum) { auto it = specToIndex.find(detOrSpec); if(it != specToIndex.end()) { const size_t wsIndex = it->second; det = m_workspace->getDetector(wsIndex); } else { g_log.debug() << "Skipping \"" << line << "\". Spectrum is not in workspace.\n"; continue; } } else { det = inst->getDetector(detOrSpec); } } catch(Kernel::Exception::NotFoundError&) { g_log.debug() << "Skipping \"" << line << "\". Spectrum in workspace but cannot find associated detector.\n"; continue; } // Special cases for detector r,t,p. Everything else is // attached as an detector parameter double R(0.0),theta(0.0), phi(0.0); for(size_t i = 1; i < header.colCount; ++i) { double value(0.0); is >> value; if(i < header.colCount - 1 && is.eof()) { //If stringstream is at EOF & we are not at the last column then // there aren't enought columns in the file throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - " "File contains fewer than expected number of columns, check AsciiHeader property."); } if(i == header.rColIdx) R = value; else if(i == header.thetaColIdx) theta = value; else if(i == header.phiColIdx) phi = value; else if(header.detParCols.count(i) == 1) { Geometry::ParameterMap & pmap = m_workspace->instrumentParameters(); pmap.addDouble(det->getComponentID(), header.colToName[i],value); } } // Check stream state. stringstream::EOF should have been reached, if not then there is still more to // read and the file has more columns than the header indicated if(!is.eof()) { throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - " "File contains more than expected number of columns, check AsciiHeader property."); } // If not supplied use current values double r,t,p; det->getPos().getSpherical(r,t,p); if(header.rColIdx == 0) R = r; if(header.thetaColIdx == 0) theta = t; if(header.phiColIdx == 0) phi = p; setDetectorPosition(det, static_cast<float>(R), static_cast<float>(theta), static_cast<float>(phi)); } }
/** Use NearestNeighbours to find the neighbours for any instrument */ void SmoothNeighbours::findNeighboursUbiqutious() { g_log.debug( "SmoothNeighbours processing NOT assuming rectangular detectors."); m_progress->resetNumSteps(inWS->getNumberHistograms(), 0.2, 0.5); this->progress(0.2, "Building Neighbour Map"); Instrument_const_sptr inst = inWS->getInstrument(); const spec2index_map spec2index = inWS->getSpectrumToWorkspaceIndexMap(); // Resize the vector we are setting m_neighbours.resize(inWS->getNumberHistograms()); bool ignoreMaskedDetectors = getProperty("IgnoreMaskedDetectors"); WorkspaceNearestNeighbourInfo neighbourInfo(*inWS, ignoreMaskedDetectors, nNeighbours); // Cull by radius RadiusFilter radiusFilter(Radius); // Go through every input workspace pixel outWI = 0; int sum = getProperty("SumNumberOfNeighbours"); boost::shared_ptr<const Geometry::IComponent> parent, neighbParent, grandparent, neighbGParent; auto used = new bool[inWS->getNumberHistograms()]; if (sum > 1) { for (size_t wi = 0; wi < inWS->getNumberHistograms(); wi++) used[wi] = false; } const auto &detectorInfo = inWS->detectorInfo(); for (size_t wi = 0; wi < inWS->getNumberHistograms(); wi++) { if (sum > 1) if (used[wi]) continue; // We want to skip monitors try { // Get the list of detectors in this pixel const auto &dets = inWS->getSpectrum(wi).getDetectorIDs(); const auto index = detectorInfo.indexOf(*dets.begin()); if (detectorInfo.isMonitor(index)) continue; // skip monitor if (detectorInfo.isMasked(index)) { // Calibration masks many detectors, but there should be 0s after // smoothing if (sum == 1) outWI++; continue; // skip masked detectors } if (sum > 1) { const auto &det = detectorInfo.detector(index); parent = det.getParent(); if (parent) grandparent = parent->getParent(); } } catch (Kernel::Exception::NotFoundError &) { continue; // skip missing detector } specnum_t inSpec = inWS->getSpectrum(wi).getSpectrumNo(); // Step one - Get the number of specified neighbours SpectraDistanceMap insideGrid = neighbourInfo.getNeighboursExact(inSpec); // Step two - Filter the results by the radius cut off. SpectraDistanceMap neighbSpectra = radiusFilter.apply(insideGrid); // Force the central pixel to always be there // There seems to be a bug in nearestNeighbours, returns distance != 0.0 for // the central pixel. So we force distance = 0 neighbSpectra[inSpec] = V3D(0.0, 0.0, 0.0); // Neighbours and weights list double totalWeight = 0; int noNeigh = 0; std::vector<weightedNeighbour> neighbours; // Convert from spectrum numbers to workspace indices for (auto &specDistance : neighbSpectra) { specnum_t spec = specDistance.first; // Use the weighting strategy to calculate the weight. double weight = WeightedSum->weightAt(specDistance.second); if (weight > 0) { // Find the corresponding workspace index auto mapIt = spec2index.find(spec); if (mapIt != spec2index.end()) { size_t neighWI = mapIt->second; if (sum > 1) { // Get the list of detectors in this pixel const std::set<detid_t> &dets = inWS->getSpectrum(neighWI).getDetectorIDs(); const auto &det = detectorInfo.detector(*dets.begin()); neighbParent = det.getParent(); neighbGParent = neighbParent->getParent(); if (noNeigh >= sum || neighbParent->getName() != parent->getName() || neighbGParent->getName() != grandparent->getName() || used[neighWI]) continue; noNeigh++; used[neighWI] = true; } neighbours.emplace_back(neighWI, weight); totalWeight += weight; } } } // Adjust the weights of each neighbour to normalize to unity if (sum == 1) for (auto &neighbour : neighbours) neighbour.second /= totalWeight; // Save the list of neighbours for this output workspace index. m_neighbours[outWI] = neighbours; outWI++; m_progress->report("Finding Neighbours"); } // each workspace index delete[] used; }
/** * Updates from a more generic ascii file * @param filename :: The input filename */ void UpdateInstrumentFromFile::updateFromAscii(const std::string &filename) { AsciiFileHeader header; const bool isSpectrum = parseAsciiHeader(header); // Throws for multiple detectors const spec2index_map specToIndex( m_workspace->getSpectrumToWorkspaceIndexMap()); std::ifstream datfile(filename.c_str(), std::ios_base::in); const int skipNLines = getProperty("SkipFirstNLines"); std::string line; int lineCount(0); while (lineCount < skipNLines) { std::getline(datfile, line); ++lineCount; } Geometry::ParameterMap &pmap = m_workspace->instrumentParameters(); auto &detectorInfo = m_workspace->mutableDetectorInfo(); const auto &spectrumInfo = m_workspace->spectrumInfo(); std::vector<double> colValues(header.colCount - 1, 0.0); while (std::getline(datfile, line)) { boost::trim(line); std::istringstream is(line); // Column 0 should be ID/spectrum number int32_t detOrSpec(-1000); is >> detOrSpec; // If first thing read is not a number then skip the line if (is.fail()) { g_log.debug() << "Skipping \"" << line << "\". Cannot interpret as list of numbers.\n"; continue; } bool skip{false}; size_t index = static_cast<size_t>(-1); const Geometry::IDetector *det{nullptr}; if (isSpectrum) { auto it = specToIndex.find(detOrSpec); if (it != specToIndex.end()) { index = it->second; if (spectrumInfo.hasDetectors(index)) { det = &spectrumInfo.detector(index); } else { skip = true; } } else { g_log.debug() << "Skipping \"" << line << "\". Spectrum is not in workspace.\n"; continue; } } else { try { index = detectorInfo.indexOf(detOrSpec); det = &detectorInfo.detector(index); } catch (std::out_of_range &) { skip = true; } } if (skip || index == static_cast<size_t>(-1)) { g_log.debug() << "Skipping \"" << line << "\". Spectrum in workspace but cannot find associated detector.\n"; continue; } std::vector<size_t> indices; if (isSpectrum) { if (auto group = dynamic_cast<const Geometry::DetectorGroup *>(det)) { for (const auto detID : group->getDetectorIDs()) indices.push_back(detectorInfo.indexOf(detID)); } else { indices.push_back(detectorInfo.indexOf(det->getID())); } } else { indices.push_back(index); } // Special cases for detector r,t,p. Everything else is // attached as an detector parameter double R(0.0), theta(0.0), phi(0.0); for (size_t i = 1; i < header.colCount; ++i) { double value(0.0); is >> value; if (i < header.colCount - 1 && is.eof()) { // If stringstream is at EOF & we are not at the last column then // there aren't enought columns in the file throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - " "File contains fewer than expected number of " "columns, check AsciiHeader property."); } if (i == header.rColIdx) R = value; else if (i == header.thetaColIdx) theta = value; else if (i == header.phiColIdx) phi = value; else if (header.detParCols.count(i) == 1) { for (const auto index : indices) { auto id = detectorInfo.detector(index).getComponentID(); pmap.addDouble(id, header.colToName[i], value); } } } // Check stream state. stringstream::EOF should have been reached, if not // then there is still more to // read and the file has more columns than the header indicated if (!is.eof()) { throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - " "File contains more than expected number of " "columns, check AsciiHeader property."); } // If not supplied use current values double r, t, p; if (isSpectrum) spectrumInfo.position(index).getSpherical(r, t, p); else detectorInfo.position(index).getSpherical(r, t, p); if (header.rColIdx == 0) R = r; if (header.thetaColIdx == 0) theta = t; if (header.phiColIdx == 0 || m_ignorePhi) phi = p; for (const auto index : indices) setDetectorPosition(detectorInfo, index, static_cast<float>(R), static_cast<float>(theta), static_cast<float>(phi)); } }