/** Open and load the times-of-flight data */ void LoadBankFromDiskTask::loadTof(::NeXus::File &file) { // Allocate the array auto temp = new float[m_loadSize[0]]; delete[] m_event_time_of_flight; m_event_time_of_flight = temp; // Get the list of event_time_of_flight's if (!m_oldNexusFileNames) file.openData("event_time_offset"); else file.openData("event_time_of_flight"); // Check that the required space is there in the file. ::NeXus::Info tof_info = file.getInfo(); int64_t tof_dim0 = recalculateDataSize(tof_info.dims[0]); if (tof_dim0 < m_loadSize[0] + m_loadStart[0]) { m_loader.alg->getLogger().warning() << "Entry " << entry_name << "'s event_time_offset field is too small " "to load the desired data.\n"; m_loadError = true; } // Check that the type is what it is supposed to be if (tof_info.type == ::NeXus::FLOAT32) file.getSlab(m_event_time_of_flight, m_loadStart, m_loadSize); else { m_loader.alg->getLogger().warning() << "Entry " << entry_name << "'s event_time_offset field is not FLOAT32! It will be skipped.\n"; m_loadError = true; } if (!m_loadError) { std::string units; file.getAttr("units", units); if (units != "microsecond") { m_loader.alg->getLogger().warning() << "Entry " << entry_name << "'s event_time_offset field's units are " "not microsecond. It will be skipped.\n"; m_loadError = true; } file.closeData(); } // no error }
/** Load weight of weigthed events if they exist * @param file An NeXus::File object opened at the correct group * @returns A new array containing the weights or a nullptr if the weights * are not present */ std::unique_ptr<float[]> LoadBankFromDiskTask::loadEventWeights(::NeXus::File &file) { try { // First, get info about the event_weight field in this bank file.openData("event_weight"); } catch (::NeXus::Exception &) { // Field not found error is most likely. m_have_weight = false; return std::unique_ptr<float[]>(); } // OK, we've got them m_have_weight = true; // Allocate the array auto event_weight = Mantid::Kernel::make_unique<float[]>(m_loadSize[0]); ::NeXus::Info weight_info = file.getInfo(); int64_t weight_dim0 = recalculateDataSize(weight_info.dims[0]); if (weight_dim0 < m_loadSize[0] + m_loadStart[0]) { m_loader.alg->getLogger().warning() << "Entry " << entry_name << "'s event_weight field is too small to load the desired data.\n"; m_loadError = true; } // Check that the type is what it is supposed to be if (weight_info.type == ::NeXus::FLOAT32) file.getSlab(event_weight.get(), m_loadStart, m_loadSize); else { m_loader.alg->getLogger().warning() << "Entry " << entry_name << "'s event_weight field is not FLOAT32! It will be skipped.\n"; m_loadError = true; } if (!m_loadError) { file.closeData(); } return event_weight; }
/** Open and load the times-of-flight data * @param file An NeXus::File object opened at the correct group * @returns A new array containing the time of flights for this bank */ std::unique_ptr<float[]> LoadBankFromDiskTask::loadTof(::NeXus::File &file) { // Allocate the array auto event_time_of_flight = Mantid::Kernel::make_unique<float[]>(m_loadSize[0]); // Get the list of event_time_of_flight's std::string key, tof_unit; if (!m_oldNexusFileNames) key = "event_time_offset"; else key = "event_time_of_flight"; file.openData(key); // Check that the required space is there in the file. ::NeXus::Info tof_info = file.getInfo(); int64_t tof_dim0 = recalculateDataSize(tof_info.dims[0]); if (tof_dim0 < m_loadSize[0] + m_loadStart[0]) { m_loader.alg->getLogger().warning() << "Entry " << entry_name << "'s event_time_offset field is too small " "to load the desired data.\n"; m_loadError = true; } // The Nexus standard does not specify if event_time_offset should be float or // integer, so we use the NeXusIOHelper to perform the conversion to float on // the fly. If the data field already contains floats, the conversion is // skipped. auto vec = NeXus::NeXusIOHelper::readNexusSlab<float>(file, key, m_loadStart, m_loadSize); file.getAttr("units", tof_unit); file.closeData(); // Convert Tof to microseconds Kernel::Units::timeConversionVector(vec, tof_unit, "microseconds"); std::copy(vec.begin(), vec.end(), event_time_of_flight.get()); return event_time_of_flight; }
/** Load the event_id field, which has been opened * @param file An NeXus::File object opened at the correct group * @returns A new array containing the event Ids for this bank */ std::unique_ptr<uint32_t[]> LoadBankFromDiskTask::loadEventId(::NeXus::File &file) { // This is the data size ::NeXus::Info id_info = file.getInfo(); int64_t dim0 = recalculateDataSize(id_info.dims[0]); // Now we allocate the required arrays auto event_id = Mantid::Kernel::make_unique<uint32_t[]>(m_loadSize[0]); // Check that the required space is there in the file. if (dim0 < m_loadSize[0] + m_loadStart[0]) { m_loader.alg->getLogger().warning() << "Entry " << entry_name << "'s event_id field is too small (" << dim0 << ") to load the desired data size (" << m_loadSize[0] + m_loadStart[0] << ").\n"; m_loadError = true; } if (m_loader.alg->getCancel()) m_loadError = true; // To allow cancelling the algorithm if (!m_loadError) { // Must be uint32 if (id_info.type == ::NeXus::UINT32) file.getSlab(event_id.get(), m_loadStart, m_loadSize); else { m_loader.alg->getLogger().warning() << "Entry " << entry_name << "'s event_id field is not UINT32! It will be skipped.\n"; m_loadError = true; } file.closeData(); // determine the range of pixel ids for (int64_t i = 0; i < m_loadSize[0]; ++i) { const auto id = event_id[i]; if (id < m_min_id) m_min_id = id; if (id > m_max_id) m_max_id = id; } if (m_min_id > static_cast<uint32_t>(m_loader.eventid_max)) { // All the detector IDs in the bank are higher than the highest 'known' // (from the IDF) // ID. Setting this will abort the loading of the bank. m_loadError = true; } // fixup the minimum pixel id in the case that it's lower than the lowest // 'known' id. We test this by checking that when we add the offset we // would not get a negative index into the vector. Note that m_min_id is // a uint so we have to be cautious about adding it to an int which may be // negative. if (static_cast<int32_t>(m_min_id) + m_loader.pixelID_to_wi_offset < 0) { m_min_id = static_cast<uint32_t>(abs(m_loader.pixelID_to_wi_offset)); } // fixup the maximum pixel id in the case that it's higher than the // highest 'known' id if (m_max_id > static_cast<uint32_t>(m_loader.eventid_max)) m_max_id = static_cast<uint32_t>(m_loader.eventid_max); } return event_id; }
/** Open the event_id field and validate the contents * * @param file :: File handle for the NeXus file * @param start_event :: set to the index of the first event * @param stop_event :: set to the index of the last event + 1 * @param event_index :: (a list of size of # of pulses giving the index in *the event list for that pulse) */ void LoadBankFromDiskTask::prepareEventId( ::NeXus::File &file, int64_t &start_event, int64_t &stop_event, const std::vector<uint64_t> &event_index) { // Get the list of pixel ID's if (m_oldNexusFileNames) file.openData("event_pixel_id"); else file.openData("event_id"); // By default, use all available indices start_event = 0; ::NeXus::Info id_info = file.getInfo(); // dims[0] can be negative in ISIS meaning 2^32 + dims[0]. Take that into // account int64_t dim0 = recalculateDataSize(id_info.dims[0]); stop_event = dim0; // Handle the time filtering by changing the start/end offsets. for (size_t i = 0; i < thisBankPulseTimes->numPulses; i++) { if (thisBankPulseTimes->pulseTimes[i] >= m_loader.alg->filter_time_start) { start_event = static_cast<int64_t>(event_index[i]); break; // stop looking } } if (start_event > dim0) { // If the frame indexes are bad then we can't construct the times of the // events properly and filtering by time // will not work on this data m_loader.alg->getLogger().warning() << this->entry_name << "'s field 'event_index' seems to be invalid (start_index > than " "the number of events in the bank)." << "All events will appear in the same frame and filtering by time " "will not be possible on this data.\n"; start_event = 0; stop_event = dim0; } else { for (size_t i = 0; i < thisBankPulseTimes->numPulses; i++) { if (thisBankPulseTimes->pulseTimes[i] > m_loader.alg->filter_time_stop) { stop_event = event_index[i]; break; } } } // We are loading part - work out the event number range if (m_loader.chunk != EMPTY_INT()) { start_event = static_cast<int64_t>(m_loader.chunk - m_loader.firstChunkForBank) * static_cast<int64_t>(m_loader.eventsPerChunk); // Don't change stop_event for the final chunk if (start_event + static_cast<int64_t>(m_loader.eventsPerChunk) < stop_event) stop_event = start_event + static_cast<int64_t>(m_loader.eventsPerChunk); } // Make sure it is within range if (stop_event > dim0) stop_event = dim0; m_loader.alg->getLogger().debug() << entry_name << ": start_event " << start_event << " stop_event " << stop_event << "\n"; }