/** * Loads the mapping between index -> set of detector IDs * * If "detector_index", "detector_count" and "detector_list" are all present, * use these to get the mapping, otherwise spectrum number = detector ID * (one-to-one) * * The spectrum spectrum_index[i] maps to detector_count[i] detectors, whose * detector IDs are in detector_list starting at the index detector_index[i] * * @returns :: map of index -> detector IDs * @throws std::runtime_error if fails to read data from file */ std::map<int, std::set<int>> LoadMuonNexus2::loadDetectorMapping(const Mantid::NeXus::NXInt &spectrumIndex) { std::map<int, std::set<int>> mapping; const int nSpectra = spectrumIndex.dim0(); // Find and open the data group NXRoot root(getPropertyValue("Filename")); NXEntry entry = root.openEntry(m_entry_name); const std::string detectorName = [&entry]() { // Only the first NXdata found for (auto &group : entry.groups()) { std::string className = group.nxclass; if (className == "NXdata") { return group.nxname; } } throw std::runtime_error("No NXdata found in file"); }(); NXData dataGroup = entry.openNXData(detectorName); // Usually for muon data, detector id = spectrum number // If not, the optional groups "detector_index", "detector_list" and // "detector_count" will be present to map one to the other const bool hasDetectorMapping = dataGroup.containsDataSet("detector_index") && dataGroup.containsDataSet("detector_list") && dataGroup.containsDataSet("detector_count"); if (hasDetectorMapping) { // Read detector IDs try { const auto detIndex = dataGroup.openNXInt("detector_index"); const auto detCount = dataGroup.openNXInt("detector_count"); const auto detList = dataGroup.openNXInt("detector_list"); const int nSpectra = detIndex.dim0(); for (int i = 0; i < nSpectra; ++i) { const int start = detIndex[i]; const int nDetectors = detCount[i]; std::set<int> detIDs; for (int jDet = 0; jDet < nDetectors; ++jDet) { detIDs.insert(detList[start + jDet]); } mapping[i] = detIDs; } } catch (const ::NeXus::Exception &err) { // Throw a more user-friendly message std::ostringstream message; message << "Failed to read detector mapping: " << err.what(); throw std::runtime_error(message.str()); } } else { for (int i = 0; i < nSpectra; ++i) { mapping[i] = std::set<int>{spectrumIndex[i]}; } } return mapping; }
/** * Load a table */ API::Workspace_sptr LoadNexusProcessed::loadTableEntry(NXEntry & entry) { API::ITableWorkspace_sptr workspace; workspace = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace"); NXData nx_tw = entry.openNXData("table_workspace"); std::vector<double> values; bool hasNumberOfRowBeenSet = false; //int numberOfRows = 0; int columnNumber = 1; do { std::string str = "column_" + boost::lexical_cast<std::string>(columnNumber); NXInfo info = nx_tw.getDataSetInfo(str.c_str()); if (info.stat == NX_ERROR) { break; } if ( info.type == NX_FLOAT64 ) { NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); std::string columnTitle = nxDouble.attributes("name"); if (!columnTitle.empty()) { workspace->addColumn("double", columnTitle); nxDouble.load(); int length = nxDouble.dim0(); if ( !hasNumberOfRowBeenSet ) { workspace->setRowCount(length); hasNumberOfRowBeenSet = true; } for (int i = 0; i < length; i++) workspace->cell<double>(i,columnNumber-1) = *(nxDouble() + i); } } else if ( info.type == NX_CHAR ) { NXChar data = nx_tw.openNXChar(str.c_str()); std::string columnTitle = data.attributes("name"); if (!columnTitle.empty()) { workspace->addColumn("str", columnTitle); int nRows = info.dims[0]; if ( !hasNumberOfRowBeenSet ) { workspace->setRowCount(nRows); hasNumberOfRowBeenSet = true; } int maxStr = info.dims[1]; std::string fromCrap(maxStr,' '); data.load(); for (int iR = 0; iR < nRows; iR++) { for (int i = 0; i < maxStr; i++) fromCrap[i] = *(data()+i+maxStr*iR); workspace->cell<std::string>(iR,columnNumber-1) = fromCrap; } } } columnNumber++; } while ( 1 ); return boost::static_pointer_cast<API::Workspace>(workspace); }
/** * Load a given period into the workspace * @param period :: The period number to load (starting from 1) * @param entry :: The opened root entry node for accessing the monitor and data nodes * @param local_workspace :: The workspace to place the data in */ void LoadISISNexus2::loadPeriodData(int64_t period, NXEntry & entry, DataObjects::Workspace2D_sptr local_workspace) { int64_t hist_index = 0; int64_t period_index(period - 1); int64_t first_monitor_spectrum = 0; if( !m_monitors.empty() ) { first_monitor_spectrum = m_monitors.begin()->first; hist_index = first_monitor_spectrum - 1; for(std::map<int64_t,std::string>::const_iterator it = m_monitors.begin(); it != m_monitors.end(); ++it) { NXData monitor = entry.openNXData(it->second); NXInt mondata = monitor.openIntData(); m_progress->report("Loading monitor"); mondata.load(1,static_cast<int>(period-1)); // TODO this is just wrong MantidVec& Y = local_workspace->dataY(hist_index); Y.assign(mondata(),mondata() + m_numberOfChannels); MantidVec& E = local_workspace->dataE(hist_index); std::transform(Y.begin(), Y.end(), E.begin(), dblSqrt); local_workspace->getAxis(1)->spectraNo(hist_index) = static_cast<specid_t>(it->first); NXFloat timeBins = monitor.openNXFloat("time_of_flight"); timeBins.load(); local_workspace->dataX(hist_index).assign(timeBins(),timeBins() + timeBins.dim0()); hist_index++; } if (first_monitor_spectrum > 1) { hist_index = 0; } } if( m_have_detector ) { NXData nxdata = entry.openNXData("detector_1"); NXDataSetTyped<int> data = nxdata.openIntData(); data.open(); //Start with thelist members that are lower than the required spectrum const int * const spec_begin = m_spec.get(); std::vector<int64_t>::iterator min_end = m_spec_list.end(); if( !m_spec_list.empty() ) { // If we have a list, by now it is ordered so first pull in the range below the starting block range // Note the reverse iteration as we want the last one if( m_range_supplied ) { min_end = std::find_if(m_spec_list.begin(), m_spec_list.end(), std::bind2nd(std::greater<int>(), m_spec_min)); } for( std::vector<int64_t>::iterator itr = m_spec_list.begin(); itr < min_end; ++itr ) { // Load each int64_t spectra_no = (*itr); // For this to work correctly, we assume that the spectrum list increases monotonically int64_t filestart = std::lower_bound(spec_begin,m_spec_end,spectra_no) - spec_begin; m_progress->report("Loading data"); loadBlock(data, static_cast<int64_t>(1), period_index, filestart, hist_index, spectra_no, local_workspace); } } if( m_range_supplied ) { // When reading in blocks we need to be careful that the range is exactly divisible by the blocksize // and if not have an extra read of the left overs const int64_t blocksize = 8; const int64_t rangesize = (m_spec_max - m_spec_min + 1) - m_monitors.size(); const int64_t fullblocks = rangesize / blocksize; int64_t read_stop = 0; int64_t spectra_no = m_spec_min; if (first_monitor_spectrum == 1) {// this if crudely checks whether the monitors are at the begining or end of the spectra spectra_no += static_cast<int>(m_monitors.size()); } // For this to work correctly, we assume that the spectrum list increases monotonically int64_t filestart = std::lower_bound(spec_begin,m_spec_end,spectra_no) - spec_begin; if( fullblocks > 0 ) { read_stop = (fullblocks * blocksize);// + m_monitors.size(); //RNT: I think monitors are excluded from the data //for( ; hist_index < read_stop; ) for(int64_t i = 0; i < fullblocks; ++i) { loadBlock(data, blocksize, period_index, filestart, hist_index, spectra_no, local_workspace); filestart += blocksize; } } int64_t finalblock = rangesize - (fullblocks * blocksize); if( finalblock > 0 ) { loadBlock(data, finalblock, period_index, filestart, hist_index, spectra_no, local_workspace); } } //Load in the last of the list indices for( std::vector<int64_t>::iterator itr = min_end; itr < m_spec_list.end(); ++itr ) { // Load each int64_t spectra_no = (*itr); // For this to work correctly, we assume that the spectrum list increases monotonically int64_t filestart = std::lower_bound(spec_begin,m_spec_end,spectra_no) - spec_begin; loadBlock(data, 1, period_index, filestart, hist_index, spectra_no, local_workspace); } } try { const std::string title = entry.getString("title"); local_workspace->setTitle(title); // write the title into the log file (run object) local_workspace->mutableRun().addProperty("run_title", title, true); } catch (std::runtime_error &) { g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") << std::endl; } }
/** * Load a given period into the workspace * @param period :: The period number to load (starting from 1) * @param entry :: The opened root entry node for accessing the monitor and data * nodes * @param local_workspace :: The workspace to place the data in * @param update_spectra2det_mapping :: reset spectra-detector map to the one * calculated earlier. (Warning! -- this map has to be calculated correctly!) */ void LoadISISNexus2::loadPeriodData(int64_t period, NXEntry &entry, DataObjects::Workspace2D_sptr &local_workspace, bool update_spectra2det_mapping) { int64_t hist_index = 0; int64_t period_index(period - 1); // int64_t first_monitor_spectrum = 0; for (auto block = m_spectraBlocks.begin(); block != m_spectraBlocks.end(); ++block) { if (block->isMonitor) { NXData monitor = entry.openNXData(block->monName); NXInt mondata = monitor.openIntData(); m_progress->report("Loading monitor"); mondata.load(1, static_cast<int>(period - 1)); // TODO this is just wrong MantidVec &Y = local_workspace->dataY(hist_index); Y.assign(mondata(), mondata() + m_monBlockInfo.numberOfChannels); MantidVec &E = local_workspace->dataE(hist_index); std::transform(Y.begin(), Y.end(), E.begin(), dblSqrt); if (update_spectra2det_mapping) { // local_workspace->getAxis(1)->setValue(hist_index, // static_cast<specid_t>(it->first)); auto spec = local_workspace->getSpectrum(hist_index); specid_t specID = m_specInd2specNum_map.at(hist_index); spec->setDetectorIDs( m_spec2det_map.getDetectorIDsForSpectrumNo(specID)); spec->setSpectrumNo(specID); } NXFloat timeBins = monitor.openNXFloat("time_of_flight"); timeBins.load(); local_workspace->dataX(hist_index) .assign(timeBins(), timeBins() + timeBins.dim0()); hist_index++; } else if (m_have_detector) { NXData nxdata = entry.openNXData("detector_1"); NXDataSetTyped<int> data = nxdata.openIntData(); data.open(); // Start with the list members that are lower than the required spectrum const int *const spec_begin = m_spec.get(); // When reading in blocks we need to be careful that the range is exactly // divisible by the block-size // and if not have an extra read of the left overs const int64_t blocksize = 8; const int64_t rangesize = block->last - block->first + 1; const int64_t fullblocks = rangesize / blocksize; int64_t spectra_no = block->first; // For this to work correctly, we assume that the spectrum list increases // monotonically int64_t filestart = std::lower_bound(spec_begin, m_spec_end, spectra_no) - spec_begin; if (fullblocks > 0) { for (int64_t i = 0; i < fullblocks; ++i) { loadBlock(data, blocksize, period_index, filestart, hist_index, spectra_no, local_workspace); filestart += blocksize; } } int64_t finalblock = rangesize - (fullblocks * blocksize); if (finalblock > 0) { loadBlock(data, finalblock, period_index, filestart, hist_index, spectra_no, local_workspace); } } } try { const std::string title = entry.getString("title"); local_workspace->setTitle(title); // write the title into the log file (run object) local_workspace->mutableRun().addProperty("run_title", title, true); } catch (std::runtime_error &) { g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") << std::endl; } }
/**Method takes input parameters which describe monitor loading and analyze *them against spectra/monitor block information in the file. * The result is the option if monitors can be loaded together with spectra or *mast be treated separately * and additional information on how to treat monitor spectra. * *@param entry :: entry to the NeXus file, opened at root folder *@param spectrum_index :: array of spectra indexes of the data present in *the file *@param ndets :: size of the spectrum index array *@param n_vms_compat_spectra :: number of data entries containing common time *bins (e.g. all spectra, or all spectra and monitors or some spectra (this is *not fully supported) *@param monitors :: map connecting monitor spectra ID against *monitor group name in the file. *@param excludeMonitors :: input property indicating if it is requested to *exclude monitors from the target workspace *@param separateMonitors :: input property indicating if it is requested to *load monitors separately (and exclude them from target data workspace this way) * *@param OvelapMonitors :: output property containing the list of monitors *ID for monitors, which are also included with spectra. *@return excludeMonitors :: indicator if monitors should or mast be excluded *from the main data workspace if they can not be loaded with the data * (contain different number of time channels) * */ bool LoadISISNexus2::findSpectraDetRangeInFile( NXEntry &entry, boost::shared_array<int> &spectrum_index, int64_t ndets, int64_t n_vms_compat_spectra, std::map<int64_t, std::string> &monitors, bool excludeMonitors, bool separateMonitors, std::map<int64_t, std::string> &OvelapMonitors) { OvelapMonitors.clear(); size_t nmons = monitors.size(); if (nmons > 0) { NXInt chans = entry.openNXInt(m_monitors.begin()->second + "/data"); m_monBlockInfo = DataBlock(chans); m_monBlockInfo.numberOfSpectra = nmons; // each monitor is in separate group // so number of spectra is equal to // number of groups. // identify monitor ID range. for (auto it = monitors.begin(); it != monitors.end(); it++) { int64_t mon_id = static_cast<int64_t>(it->first); if (m_monBlockInfo.spectraID_min > mon_id) m_monBlockInfo.spectraID_min = mon_id; if (m_monBlockInfo.spectraID_max < mon_id) m_monBlockInfo.spectraID_max = mon_id; } if (m_monBlockInfo.spectraID_max - m_monBlockInfo.spectraID_min + 1 != static_cast<int64_t>(nmons)) { g_log.warning() << "When trying to find the range of monitor spectra: " "non-consequent monitor ID-s in the monitor block. " "Unexpected situation for the loader\n"; } // at this stage we assume that the only going to load monitors m_loadBlockInfo = m_monBlockInfo; } if (ndets == 0) { separateMonitors = false; // only monitors in the main workspace. No // detectors. Will be loaded in the main workspace // Possible function exit point return separateMonitors; } // detectors are present in the file NXData nxData = entry.openNXData("detector_1"); NXInt data = nxData.openIntData(); m_detBlockInfo = DataBlock(data); // We assume again that this spectrum list ID increase monotonically m_detBlockInfo.spectraID_min = spectrum_index[0]; m_detBlockInfo.spectraID_max = spectrum_index[ndets - 1]; if (m_detBlockInfo.spectraID_max - m_detBlockInfo.spectraID_min + 1 != static_cast<int64_t>(m_detBlockInfo.numberOfSpectra)) { g_log.warning() << "When trying to find the range of monitor spectra: " "non-consequent spectra ID-s in the detectors block. " "Unexpected situation for the loader\n"; } m_loadBlockInfo = m_detBlockInfo; // now we are analyzing what is actually going or can be loaded bool removeMonitors = excludeMonitors || separateMonitors; if (((m_detBlockInfo.numberOfPeriods != m_monBlockInfo.numberOfPeriods) || (m_detBlockInfo.numberOfChannels != m_monBlockInfo.numberOfChannels)) && nmons > 0) { // detectors and monitors have different characteristics. Can be loaded only // to separate workspaces. if (!removeMonitors) { g_log.warning() << " Performing separate loading as can not load spectra " "and monitors in the single workspace:\n"; g_log.warning() << " Monitors data contain :" << m_monBlockInfo.numberOfChannels << " time channels and: " << m_monBlockInfo.numberOfPeriods << " period(s)\n"; g_log.warning() << " Spectra data contain :" << m_detBlockInfo.numberOfChannels << " time channels and: " << m_detBlockInfo.numberOfPeriods << " period(s)\n"; } separateMonitors = true; removeMonitors = true; } int64_t spectraID_min = std::min(m_monBlockInfo.spectraID_min, m_detBlockInfo.spectraID_min); int64_t spectraID_max = std::max(m_monBlockInfo.spectraID_max, m_detBlockInfo.spectraID_max); size_t totNumOfSpectra = m_monBlockInfo.numberOfSpectra + m_detBlockInfo.numberOfSpectra; if (!removeMonitors) { m_loadBlockInfo.numberOfSpectra = totNumOfSpectra; m_loadBlockInfo.spectraID_min = spectraID_min; m_loadBlockInfo.spectraID_max = spectraID_max; } if (separateMonitors) m_loadBlockInfo = m_detBlockInfo; // verify integrity of the monitor and detector information if ((totNumOfSpectra == static_cast<size_t>(n_vms_compat_spectra)) && (spectraID_max - spectraID_min + 1 == static_cast<int64_t>(n_vms_compat_spectra))) { // all information written in the file is correct, there are no spurious // spectra and detectors & monitors form continuous block on HDD return separateMonitors; } // something is wrong and we need to analyze spectra map. Currently we can // identify and manage the case when all monitor's spectra are written // together with detectors // make settings for this situation m_detBlockInfo.numberOfSpectra -= m_monBlockInfo.numberOfSpectra; m_loadBlockInfo.numberOfSpectra -= m_monBlockInfo.numberOfSpectra; std::map<int64_t, std::string> remaining_monitors; if (removeMonitors) { for (auto it = monitors.begin(); it != monitors.end(); it++) { if (it->first >= m_detBlockInfo.spectraID_min && it->first <= m_detBlockInfo.spectraID_max) { // monitors ID-s are // included with spectra // ID-s -- let's try not // to load it twice. OvelapMonitors.insert(*it); } else { remaining_monitors.insert(*it); } } } monitors.swap(remaining_monitors); return separateMonitors; }