diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt index e83eab36a955123e3b1c5c66f7c31a5357e716e4..59fc757e04b17587fdbb9cb0fbd904756e39a186 100644 --- a/Framework/DataHandling/CMakeLists.txt +++ b/Framework/DataHandling/CMakeLists.txt @@ -107,6 +107,7 @@ set ( SRC_FILES src/ModifyDetectorDotDatFile.cpp src/MoveInstrumentComponent.cpp src/NexusTester.cpp + src/PatchBBY.cpp src/PDLoadCharacterizations.cpp src/ProcessDasNexusLog.cpp src/RawFileInfo.cpp @@ -263,6 +264,7 @@ set ( INC_FILES inc/MantidDataHandling/ModifyDetectorDotDatFile.h inc/MantidDataHandling/MoveInstrumentComponent.h inc/MantidDataHandling/NexusTester.h + inc/MantidDataHandling/PatchBBY.h inc/MantidDataHandling/PDLoadCharacterizations.h inc/MantidDataHandling/ProcessDasNexusLog.h inc/MantidDataHandling/RawFileInfo.h diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadANSTOHelper.h b/Framework/DataHandling/inc/MantidDataHandling/LoadANSTOHelper.h index 3b0e7bbe2460f938f41c6919904f1da986ccdef0..5b2849f9f669dbbd435c89629b25d754c65839c6 100644 --- a/Framework/DataHandling/inc/MantidDataHandling/LoadANSTOHelper.h +++ b/Framework/DataHandling/inc/MantidDataHandling/LoadANSTOHelper.h @@ -53,25 +53,29 @@ protected: // fields const std::vector<bool> &m_roi; const size_t m_stride; + // number of frames + size_t m_frames; // tof correction const double m_period; const double m_phase; // boundaries const double m_tofMinBoundary; const double m_tofMaxBoundary; + const double m_timeMinBoundary; + const double m_timeMaxBoundary; // methods - virtual void endOfFrameImpl() = 0; virtual void addEventImpl(size_t id, double tof) = 0; public: // construction EventProcessor(const std::vector<bool> &roi, const size_t stride, const double period, const double phase, - const double tofMinBoundary, const double tofMaxBoundary); + const double tofMinBoundary, const double tofMaxBoundary, + const double timeMinBoundary, const double timeMaxBoundary); // methods - void endOfFrame(); + void newFrame(); void addEvent(size_t x, size_t y, double tof); }; @@ -79,21 +83,19 @@ class EventCounter : public EventProcessor { protected: // fields std::vector<size_t> &m_eventCounts; - // number of frames - size_t m_numFrames; // tof double m_tofMin; double m_tofMax; // methods - void endOfFrameImpl() override; - void addEventImpl(size_t id, double tof) override; + virtual void addEventImpl(size_t id, double tof); // override public: // construction EventCounter(const std::vector<bool> &roi, const size_t stride, const double period, const double phase, const double tofMinBoundary, const double tofMaxBoundary, + const double timeMinBoundary, const double timeMaxBoundary, std::vector<size_t> &eventCounts); // properties @@ -108,14 +110,14 @@ protected: std::vector<EventVector_pt> &m_eventVectors; // methods - void endOfFrameImpl() override; - void addEventImpl(size_t id, double tof) override; + virtual void addEventImpl(size_t id, double tof) override; public: // construction EventAssigner(const std::vector<bool> &roi, const size_t stride, const double period, const double phase, const double tofMinBoundary, const double tofMaxBoundary, + const double timeMinBoundary, const double timeMaxBoundary, std::vector<EventVector_pt> &eventVectors); }; @@ -135,6 +137,7 @@ public: void *handle() const; // methods + void close(); bool read(void *buffer, uint32_t size); bool seek(int64_t offset, int whence, int64_t *newPosition = NULL); }; @@ -172,6 +175,11 @@ struct EntryHeader { char DeviceMinorNumber[8]; // cppcheck-suppress unusedStructMember char FilenamePrefix[155]; + + // methods + void writeChecksum(); + void writeFileSize(int64_t value); + int64_t readFileSize(); }; class File { @@ -205,6 +213,7 @@ private: public: // construction File(const std::string &path); + void close(); // properties bool good() const; @@ -219,6 +228,10 @@ public: bool skip(uint64_t offset); size_t read(void *dst, size_t size); int read_byte(); + + // helpers + static bool append(const std::string &path, const std::string &name, + const void *buffer, size_t size); }; } // Tar @@ -226,4 +239,4 @@ public: } // DataHandling } // Mantid -#endif // DATAHANDING_ANSTO_H_ \ No newline at end of file +#endif // DATAHANDING_ANSTO_H_ diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadBBY.h b/Framework/DataHandling/inc/MantidDataHandling/LoadBBY.h index 4ac247b96ee12a2e86497ba6db5ca8f3d7bcc52e..bab73f346e6a722f3731e9dbdf68eed378178c95 100644 --- a/Framework/DataHandling/inc/MantidDataHandling/LoadBBY.h +++ b/Framework/DataHandling/inc/MantidDataHandling/LoadBBY.h @@ -78,9 +78,9 @@ public: // description int version() const override { return 1; } const std::string name() const override { return "LoadBBY"; } - const std::string category() const override { return "DataHandling\\Nexus"; } + virtual const std::string category() const { return "DataHandling"; } const std::string summary() const override { - return "Loads a BilBy data file into an workspace."; + return "Loads a BilBy data file into a workspace."; } // returns a confidence value that this algorithm can load a specified file @@ -115,4 +115,4 @@ private: } // DataHandling } // Mantid -#endif // DATAHANDING_LOADBBY_H_ \ No newline at end of file +#endif // DATAHANDING_LOADBBY_H_ diff --git a/Framework/DataHandling/inc/MantidDataHandling/PatchBBY.h b/Framework/DataHandling/inc/MantidDataHandling/PatchBBY.h new file mode 100644 index 0000000000000000000000000000000000000000..272694b6d58d2e23d9b16873b2e262166523bd86 --- /dev/null +++ b/Framework/DataHandling/inc/MantidDataHandling/PatchBBY.h @@ -0,0 +1,70 @@ +#ifndef DATAHANDING_PATCHBBY_H_ +#define DATAHANDING_PATCHBBY_H_ + +//--------------------------------------------------- +// Includes +//--------------------------------------------------- + +#include "MantidAPI/IFileLoader.h" +#include "MantidGeometry/Instrument.h" +#include "MantidDataObjects/EventWorkspace.h" +#include "MantidNexus/NexusClasses.h" +#include "LoadANSTOHelper.h" + +namespace Mantid { +namespace DataHandling { +/** +Patches a Bilby data file. Implements API::Algorithm and its file check methods +to recognise a file as the one containing Bilby data. + +@author David Mannicke (ANSTO), Anders Markvardsen (ISIS), Roman Tolchenov +(Tessella plc) +@date 22/01/2016 + +Copyright © 2010 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +File change history is stored at: <https://github.com/mantidproject/mantid> +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ + +class DLLExport PatchBBY : public API::Algorithm { +public: + // construction + PatchBBY() {} + virtual ~PatchBBY() {} + + // description + virtual int version() const override { return 1; } + virtual const std::string name() const override { return "PatchBBY"; } + virtual const std::string category() const override { return "DataHandling"; } + virtual const std::string summary() const override { + return "Patches a BilBy data file."; + } + +protected: + // initialisation + virtual void init() override; + // execution + virtual void exec() override; +}; + +} // DataHandling +} // Mantid + +#endif // DATAHANDING_PATCHBBY_H_ diff --git a/Framework/DataHandling/src/LoadANSTOHelper.cpp b/Framework/DataHandling/src/LoadANSTOHelper.cpp index a7fc77bad17d636e6316edddb2f1876aae068968..9749fe7917bfac10fab72ab73fd959be6766de0c 100644 --- a/Framework/DataHandling/src/LoadANSTOHelper.cpp +++ b/Framework/DataHandling/src/LoadANSTOHelper.cpp @@ -8,6 +8,8 @@ #include "MantidGeometry/Objects/ShapeFactory.h" #include "MantidNexus/NexusClasses.h" +#include <numeric> + namespace Mantid { namespace DataHandling { namespace ANSTO { @@ -51,10 +53,14 @@ void ProgressTracker::complete() { EventProcessor::EventProcessor(const std::vector<bool> &roi, const size_t stride, const double period, const double phase, const double tofMinBoundary, - const double tofMaxBoundary) - : m_roi(roi), m_stride(stride), m_period(period), m_phase(phase), - m_tofMinBoundary(tofMinBoundary), m_tofMaxBoundary(tofMaxBoundary) {} -void EventProcessor::endOfFrame() { endOfFrameImpl(); } + const double tofMaxBoundary, + const double timeMinBoundary, + const double timeMaxBoundary) + : m_roi(roi), m_stride(stride), m_frames(0), m_period(period), + m_phase(phase), m_tofMinBoundary(tofMinBoundary), + m_tofMaxBoundary(tofMaxBoundary), m_timeMinBoundary(timeMinBoundary), + m_timeMaxBoundary(timeMaxBoundary) {} +void EventProcessor::newFrame() { m_frames++; } void EventProcessor::addEvent(size_t x, size_t y, double tof) { // tof correction if (m_period > 0.0) { @@ -66,16 +72,27 @@ void EventProcessor::addEvent(size_t x, size_t y, double tof) { } // check if event is in valid range - if ((y < m_stride) && (m_tofMinBoundary <= tof) && - (tof <= m_tofMaxBoundary)) { - // detector id - size_t id = m_stride * x + y; + // frame boundary + double frameTime = + (static_cast<double>(m_frames) * m_period) * 1e-6; // in seconds + if ((frameTime < m_timeMinBoundary) || (frameTime > m_timeMaxBoundary)) + return; - // check if neutron is in region of intreset - if (m_roi[id]) - addEventImpl(id, tof); - } + // ToF boundary + if ((tof < m_tofMinBoundary) && (tof > m_tofMaxBoundary)) + return; + + // detector id + size_t id = m_stride * x + y; + + // image size + if ((y >= m_stride) || (id >= m_roi.size())) + return; + + // check if neutron is in region of intreset + if (m_roi[id]) + addEventImpl(id, tof); } // EventCounter @@ -83,20 +100,20 @@ EventCounter::EventCounter(const std::vector<bool> &roi, const size_t stride, const double period, const double phase, const double tofMinBoundary, const double tofMaxBoundary, + const double timeMinBoundary, + const double timeMaxBoundary, std::vector<size_t> &eventCounts) - : EventProcessor(roi, stride, period, phase, tofMinBoundary, - tofMaxBoundary), - m_eventCounts(eventCounts), m_numFrames(0), - m_tofMin(std::numeric_limits<double>::max()), + : EventProcessor(roi, stride, period, phase, tofMinBoundary, tofMaxBoundary, + timeMinBoundary, timeMaxBoundary), + m_eventCounts(eventCounts), m_tofMin(std::numeric_limits<double>::max()), m_tofMax(std::numeric_limits<double>::min()) {} -size_t EventCounter::numFrames() const { return m_numFrames; } +size_t EventCounter::numFrames() const { return m_frames; } double EventCounter::tofMin() const { return m_tofMin <= m_tofMax ? m_tofMin : 0.0; } double EventCounter::tofMax() const { return m_tofMin <= m_tofMax ? m_tofMax : 0.0; } -void EventCounter::endOfFrameImpl() { m_numFrames++; } void EventCounter::addEventImpl(size_t id, double tof) { if (m_tofMin > tof) m_tofMin = tof; @@ -111,13 +128,12 @@ EventAssigner::EventAssigner(const std::vector<bool> &roi, const size_t stride, const double period, const double phase, const double tofMinBoundary, const double tofMaxBoundary, + const double timeMinBoundary, + const double timeMaxBoundary, std::vector<EventVector_pt> &eventVectors) - : EventProcessor(roi, stride, period, phase, tofMinBoundary, - tofMaxBoundary), + : EventProcessor(roi, stride, period, phase, tofMinBoundary, tofMaxBoundary, + timeMinBoundary, timeMaxBoundary), m_eventVectors(eventVectors) {} -void EventAssigner::endOfFrameImpl() { - // ignore -} void EventAssigner::addEventImpl(size_t id, double tof) { m_eventVectors[id]->push_back(tof); } @@ -128,11 +144,12 @@ FastReadOnlyFile::FastReadOnlyFile(const char *filename) { m_handle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } -FastReadOnlyFile::~FastReadOnlyFile() { +FastReadOnlyFile::~FastReadOnlyFile() { close(); } +void *FastReadOnlyFile::handle() const { return m_handle; } +void FastReadOnlyFile::close() { CloseHandle(m_handle); m_handle = NULL; } -void *FastReadOnlyFile::handle() const { return m_handle; } bool FastReadOnlyFile::read(void *buffer, uint32_t size) { DWORD bytesRead; return (FALSE != ReadFile(m_handle, buffer, size, &bytesRead, NULL)) && @@ -146,11 +163,12 @@ bool FastReadOnlyFile::seek(int64_t offset, int whence, int64_t *newPosition) { FastReadOnlyFile::FastReadOnlyFile(const char *filename) { m_handle = fopen(filename, "rb"); } -FastReadOnlyFile::~FastReadOnlyFile() { +FastReadOnlyFile::~FastReadOnlyFile() { close(); } +void *FastReadOnlyFile::handle() const { return m_handle; } +void FastReadOnlyFile::close() { fclose(m_handle); m_handle = nullptr; } -void *FastReadOnlyFile::handle() const { return m_handle; } bool FastReadOnlyFile::read(void *buffer, uint32_t size) { return 1 == fread(buffer, static_cast<size_t>(size), 1, m_handle); } @@ -163,10 +181,34 @@ bool FastReadOnlyFile::seek(int64_t offset, int whence, int64_t *newPosition) { namespace Tar { -template <size_t N> int64_t octalToInt(char(&str)[N]) { +void EntryHeader::writeChecksum() { + memset(Checksum, ' ', sizeof(Checksum)); + size_t value = std::accumulate( + (const char *)this, (const char *)this + sizeof(EntryHeader), (size_t)0); + + std::ostringstream buffer; + + buffer << std::oct << std::setfill('0') + << std::setw(static_cast<int>(sizeof(Checksum)) - 1) << value; + std::string string = buffer.str(); + + std::copy(string.cbegin(), string.cend(), Checksum); + Checksum[string.size()] = 0; +} +void EntryHeader::writeFileSize(int64_t value) { + std::ostringstream buffer; + + buffer << std::oct << std::setfill('0') + << std::setw(static_cast<int>(sizeof(FileSize)) - 1) << value; + std::string string = buffer.str(); + + std::copy(string.cbegin(), string.cend(), FileSize); + FileSize[string.size()] = 0; +} +int64_t EntryHeader::readFileSize() { int64_t result = 0; - char *p = str; - for (size_t n = N; n > 1; --n) { // last character is '\0' + const char *p = FileSize; + for (size_t n = sizeof(FileSize) - 1; n != 0; --n) { // last character is '\0' char c = *p++; if (('0' <= c) && (c <= '9')) result = result * 8 + (c - '0'); @@ -195,7 +237,7 @@ File::File(const std::string &path) FileInfo fileInfo; fileInfo.Offset = position; - fileInfo.Size = octalToInt(header.FileSize); + fileInfo.Size = header.readFileSize(); if (header.TypeFlag == TarTypeFlag_NormalFile) { m_fileNames.push_back(fileName); @@ -209,6 +251,17 @@ File::File(const std::string &path) m_good &= m_file.seek(fileInfo.Size + offset, SEEK_CUR); } } +void File::close() { + m_good = false; + m_file.close(); + m_fileNames.clear(); + m_fileInfos.clear(); + m_selected = static_cast<size_t>(-1); + m_position = 0; + m_size = 0; + m_bufferPosition = 0; + m_bufferAvailable = 0; +} // properties bool File::good() const { return m_good; } @@ -330,8 +383,96 @@ int File::read_byte() { m_position++; return m_buffer[m_bufferPosition++]; } +bool File::append(const std::string &path, const std::string &name, + const void *buffer, size_t size) { + std::unique_ptr<FILE, decltype(&fclose)> handle(fopen(path.c_str(), "rb+"), + fclose); + + bool good = handle != NULL; + int64_t lastHeaderPosition = 0; + int64_t targetPosition = -1; + + while (good) { + EntryHeader header; + int64_t position; + + lastHeaderPosition = static_cast<int64_t>(ftell(handle.get())); + + good &= 1 == fread(&header, sizeof(EntryHeader), 1, handle.get()); + good &= 0 == fseek(handle.get(), 512 - sizeof(EntryHeader), SEEK_CUR); + good &= 0 <= (position = static_cast<int64_t>(ftell(handle.get()))); + + if (!good) + return false; + + std::string fileName(header.FileName); + if (fileName.length() == 0) + break; + + if (fileName.compare(name) == 0) + targetPosition = lastHeaderPosition; + else if (targetPosition != -1) + throw std::runtime_error( + "format exception"); // it has to be the last file in the archive + + FileInfo fileInfo; + fileInfo.Offset = position; + fileInfo.Size = header.readFileSize(); + + size_t offset = static_cast<size_t>(fileInfo.Size % 512); + if (offset != 0) + offset = 512 - offset; + + good &= 0 == fseek(handle.get(), static_cast<long>(fileInfo.Size + offset), + SEEK_CUR); + } + + if (!good) + return false; + + if (targetPosition == -1) + targetPosition = lastHeaderPosition; + + // empty buffer + char padding[512]; + memset(padding, 0, 512); + + // prepare new header + EntryHeader header; + memset(&header, 0, sizeof(EntryHeader)); + memcpy(header.FileName, name.c_str(), name.size()); + memset(header.FileMode, '0', sizeof(header.FileMode) - 1); + memset(header.OwnerUserID, '0', sizeof(header.OwnerUserID) - 1); + memset(header.OwnerGroupID, '0', sizeof(header.OwnerGroupID) - 1); + memset(header.LastModification, '0', sizeof(header.LastModification) - 1); + + header.TypeFlag = TarTypeFlag_NormalFile; + header.writeFileSize(size); + header.writeChecksum(); + + // write header + good &= 0 == fseek(handle.get(), static_cast<long>(targetPosition), SEEK_SET); + good &= 1 == fwrite(&header, sizeof(EntryHeader), 1, handle.get()); + good &= 1 == fwrite(padding, 512 - sizeof(EntryHeader), 1, handle.get()); + + // write content + good &= 1 == fwrite(buffer, size, 1, handle.get()); + + // write padding + size_t offset = static_cast<size_t>(size % 512); + if (offset != 0) { + offset = 512 - offset; + + good &= 1 == fwrite(padding, offset, 1, handle.get()); + } + + // write final + good &= 1 == fwrite(padding, 512, 1, handle.get()); + + return good; +} } // Tar } // ANSTO } // DataHandling -} // Mantid \ No newline at end of file +} // Mantid diff --git a/Framework/DataHandling/src/LoadBBY.cpp b/Framework/DataHandling/src/LoadBBY.cpp index dbdbdd9d608dd0747d6a5e51f2020b4166a7d898..c46e13ca2e1c8d97accb10d5085f66a8fc49d668 100644 --- a/Framework/DataHandling/src/LoadBBY.cpp +++ b/Framework/DataHandling/src/LoadBBY.cpp @@ -13,7 +13,9 @@ #include "MantidKernel/UnitFactory.h" #include "MantidNexus/NexusClasses.h" +#include <Poco/AutoPtr.h> #include <Poco/TemporaryFile.h> +#include <Poco/Util/PropertyFileConfiguration.h> namespace Mantid { namespace DataHandling { @@ -40,6 +42,9 @@ static char const *const PhaseSlaveStr = "PhaseSlave"; static char const *const FilterByTofMinStr = "FilterByTofMin"; static char const *const FilterByTofMaxStr = "FilterByTofMax"; +static char const *const FilterByTimeStartStr = "FilterByTimeStart"; +static char const *const FilterByTimeStopStr = "FilterByTimeStop"; + using ANSTO::EventVector_pt; template <typename TYPE> @@ -48,7 +53,8 @@ void AddSinglePointTimeSeriesProperty(API::LogManager &logManager, const std::string &name, const TYPE value) { // create time series property and add single value - auto p = new Kernel::TimeSeriesProperty<TYPE>(name); + Kernel::TimeSeriesProperty<TYPE> *p = + new Kernel::TimeSeriesProperty<TYPE>(name); p->addValue(time, value); // add to log manager @@ -155,14 +161,14 @@ void LoadBBY::init() { // FilterByTimeStart declareProperty( - new Kernel::PropertyWithValue<double>("FilterByTimeStart", EMPTY_DBL(), + new Kernel::PropertyWithValue<double>(FilterByTimeStartStr, 0.0, Kernel::Direction::Input), "Optional: To only include events after the provided start time, in " "seconds (relative to the start of the run)."); // FilterByTimeStop declareProperty( - new Kernel::PropertyWithValue<double>("FilterByTimeStop", EMPTY_DBL(), + new Kernel::PropertyWithValue<double>(FilterByTimeStopStr, EMPTY_DBL(), Kernel::Direction::Input), "Optional: To only include events before the provided stop time, in " "seconds (relative to the start of the run)."); @@ -181,8 +187,8 @@ void LoadBBY::init() { std::string grpOptional = "Filters"; setPropertyGroup(FilterByTofMinStr, grpOptional); setPropertyGroup(FilterByTofMaxStr, grpOptional); - setPropertyGroup("FilterByTimeStart", grpOptional); - setPropertyGroup("FilterByTimeStop", grpOptional); + setPropertyGroup(FilterByTimeStartStr, grpOptional); + setPropertyGroup(FilterByTimeStopStr, grpOptional); std::string grpPhaseCorrection = "Phase Correction"; setPropertyGroup(PeriodMasterStr, grpPhaseCorrection); @@ -210,6 +216,14 @@ void LoadBBY::exec() { double tofMinBoundary = getProperty(FilterByTofMinStr); double tofMaxBoundary = getProperty(FilterByTofMaxStr); + double timeMinBoundary = getProperty(FilterByTimeStartStr); + double timeMaxBoundary = getProperty(FilterByTimeStopStr); + + if (isEmpty(tofMaxBoundary)) + tofMaxBoundary = std::numeric_limits<double>::infinity(); + if (isEmpty(timeMaxBoundary)) + timeMaxBoundary = std::numeric_limits<double>::infinity(); + API::Progress prog(this, 0.0, 1.0, Progress_Total); prog.doReport("creating instrument"); @@ -291,8 +305,9 @@ void LoadBBY::exec() { double shift = -1.0 / 6.0 * periodMaster - periodSlave * phaseSlave / 360.0; // count total events per pixel to reserve necessary memory - ANSTO::EventCounter eventCounter(roi, HISTO_BINS_Y, period, shift, - tofMinBoundary, tofMaxBoundary, eventCounts); + ANSTO::EventCounter eventCounter( + roi, HISTO_BINS_Y, period, shift, tofMinBoundary, tofMaxBoundary, + timeMinBoundary, timeMaxBoundary, eventCounts); loadEvents(prog, "loading neutron counts", tarFile, eventCounter); @@ -306,8 +321,8 @@ void LoadBBY::exec() { eventList.setSortOrder(DataObjects::PULSETIME_SORT); eventList.reserve(eventCounts[i]); - eventList.setDetectorID(Mantid::detid_t(i)); - eventList.setSpectrumNo(Mantid::detid_t(i)); + eventList.setDetectorID(static_cast<detid_t>(i)); + eventList.setSpectrumNo(static_cast<detid_t>(i)); DataObjects::getEventsFrom(eventList, eventVectors[i]); @@ -315,9 +330,9 @@ void LoadBBY::exec() { } progTracker.complete(); - ANSTO::EventAssigner eventAssigner(roi, HISTO_BINS_Y, period, shift, - tofMinBoundary, tofMaxBoundary, - eventVectors); + ANSTO::EventAssigner eventAssigner( + roi, HISTO_BINS_Y, period, shift, tofMinBoundary, tofMaxBoundary, + timeMinBoundary, timeMaxBoundary, eventVectors); loadEvents(prog, "loading neutron events", tarFile, eventAssigner); @@ -469,6 +484,9 @@ std::vector<bool> LoadBBY::createRoiVector(const std::string &maskfile) { Geometry::Instrument_sptr LoadBBY::createInstrument(ANSTO::Tar::File &tarFile, InstrumentInfo &instrumentInfo) { + + const double toMeters = 1.0 / 1000; + instrumentInfo.bm_counts = 0; instrumentInfo.att_pos = 0; @@ -491,12 +509,13 @@ LoadBBY::createInstrument(ANSTO::Tar::File &tarFile, instrumentInfo.D_curtainu_value = 0.3947; instrumentInfo.D_curtaind_value = 0.3978; - // extract hdf file - int64_t fileSize = 0; + // extract log and hdf file const std::vector<std::string> &files = tarFile.files(); - for (const auto &file : files) - if (file.rfind(".hdf") == file.length() - 4) { - tarFile.select(file.c_str()); + + int64_t fileSize = 0; + for (auto itr = files.begin(); itr != files.end(); ++itr) + if (itr->rfind(".hdf") == itr->length() - 4) { + tarFile.select(itr->c_str()); fileSize = tarFile.selected_size(); break; } @@ -518,7 +537,6 @@ LoadBBY::createInstrument(ANSTO::Tar::File &tarFile, float tmp_float; int32_t tmp_int32 = 0; - const double toMeters = 1.0 / 1000; if (loadNXDataSet(entry, "monitor/bm1_counts", tmp_int32)) instrumentInfo.bm_counts = tmp_int32; @@ -561,6 +579,67 @@ LoadBBY::createInstrument(ANSTO::Tar::File &tarFile, } } + // patching + std::string logContent; + for (auto itr = files.begin(); itr != files.end(); ++itr) + if (itr->compare("History.log") == 0) { + tarFile.select(itr->c_str()); + logContent.resize(tarFile.selected_size()); + tarFile.read(&logContent[0], logContent.size()); + break; + } + + if (logContent.size() > 0) { + std::istringstream data(logContent); + Poco::AutoPtr<Poco::Util::PropertyFileConfiguration> conf( + new Poco::Util::PropertyFileConfiguration(data)); + + if (conf->hasProperty("bm1_counts")) + instrumentInfo.bm_counts = conf->getInt("bm1_counts"); + if (conf->hasProperty("att_pos")) + instrumentInfo.att_pos = + static_cast<int32_t>(conf->getDouble("att_pos") + 0.5f); + + if (conf->hasProperty("master_chopper_freq")) + instrumentInfo.period_master = + 1.0 / conf->getDouble("master_chopper_freq") * 1.0e6; + if (conf->hasProperty("t0_chopper_freq")) + instrumentInfo.period_slave = + 1.0 / conf->getDouble("t0_chopper_freq") * 1.0e6; + if (conf->hasProperty("t0_chopper_phase")) + instrumentInfo.phase_slave = conf->getDouble("t0_chopper_phase"); + + if (conf->hasProperty("L2_det")) + instrumentInfo.L2_det_value = conf->getDouble("L2_det") * toMeters; + if (conf->hasProperty("Ltof_det")) + instrumentInfo.L1_chopper_value = + conf->getDouble("Ltof_det") * toMeters - instrumentInfo.L2_det_value; + // if (conf->hasProperty("L1")) + // instrumentInfo.L1_source_value = conf->getDouble("L1") * toMeters; + + if (conf->hasProperty("L2_curtainl")) + instrumentInfo.L2_curtainl_value = + conf->getDouble("L2_curtainl") * toMeters; + if (conf->hasProperty("L2_curtainr")) + instrumentInfo.L2_curtainr_value = + conf->getDouble("L2_curtainr") * toMeters; + if (conf->hasProperty("L2_curtainu")) + instrumentInfo.L2_curtainu_value = + conf->getDouble("L2_curtainu") * toMeters; + if (conf->hasProperty("L2_curtaind")) + instrumentInfo.L2_curtaind_value = + conf->getDouble("L2_curtaind") * toMeters; + + if (conf->hasProperty("curtainl")) + instrumentInfo.D_curtainl_value = conf->getDouble("curtainl") * toMeters; + if (conf->hasProperty("curtainr")) + instrumentInfo.D_curtainr_value = conf->getDouble("curtainr") * toMeters; + if (conf->hasProperty("curtainu")) + instrumentInfo.D_curtainu_value = conf->getDouble("curtainu") * toMeters; + if (conf->hasProperty("curtaind")) + instrumentInfo.D_curtaind_value = conf->getDouble("curtaind") * toMeters; + } + return Geometry::Instrument_sptr(); /* @@ -699,8 +778,6 @@ void LoadBBY::loadEvents(API::Progress &prog, const char *progMsg, EventProcessor &eventProcessor) { prog.doReport(progMsg); - bool countsInFrame = false; - // select bin file int64_t fileSize = 0; const std::vector<std::string> &files = tarFile.files(); @@ -771,27 +848,19 @@ void LoadBBY::loadEvents(API::Progress &prog, const char *progMsg, if ((x == 0) && (y == 0) && (dt == 0xFFFFFFFF)) { tof = 0.0; - - // only count frames that contain neutrons - if (countsInFrame) { - eventProcessor.endOfFrame(); - countsInFrame = false; - } + eventProcessor.newFrame(); } else if ((x >= HISTO_BINS_X) || (y >= HISTO_BINS_Y)) { + // ignore } else { // conversion from 100 nanoseconds to 1 microsecond - tof += (static_cast<int>(dt)) * 0.1; + tof += static_cast<int>(dt) * 0.1; eventProcessor.addEvent(x, y, tof); - countsInFrame = true; } progTracker.update(tarFile.selected_position()); } } - - if (countsInFrame) - eventProcessor.endOfFrame(); } // DetectorBankFactory diff --git a/Framework/DataHandling/src/PatchBBY.cpp b/Framework/DataHandling/src/PatchBBY.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c70a8571420fd5dc7c27023c6ca845e57c7f81b --- /dev/null +++ b/Framework/DataHandling/src/PatchBBY.cpp @@ -0,0 +1,275 @@ +#include "MantidAPI/FileProperty.h" +#include "MantidDataHandling/PatchBBY.h" +#include "MantidKernel/PropertyWithValue.h" + +#include <Poco/TemporaryFile.h> + +namespace Mantid { +namespace DataHandling { + +// register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(PatchBBY) + +enum TYPE { + TYPE_INT, + TYPE_DBL, +}; + +struct PropertyInfo { + const char *const Group; + const char *const Name; + TYPE const Type; +}; + +// consts +static char const *const HistoryStr = "History.log"; +static char const *const FilenameStr = "Filename"; +static PropertyInfo PatchableProperties[] = { + {"Group1", "Bm1Counts", TYPE_INT}, + {"Group1", "AttPos", TYPE_DBL}, + + {"Group2", "MasterChopperFreq", TYPE_DBL}, + {"Group2", "T0ChopperFreq", TYPE_DBL}, + {"Group2", "T0ChopperPhase", TYPE_DBL}, + + //{ "Group3", "L1", TYPE_DBL}, + {"Group3", "L2Det", TYPE_DBL}, + {"Group3", "LTofDet", TYPE_DBL}, + + {"Group4", "L2CurtainL", TYPE_DBL}, + {"Group4", "L2CurtainR", TYPE_DBL}, + {"Group4", "L2CurtainU", TYPE_DBL}, + {"Group4", "L2CurtainD", TYPE_DBL}, + + {"Group5", "CurtainL", TYPE_DBL}, + {"Group5", "CurtainR", TYPE_DBL}, + {"Group5", "CurtainU", TYPE_DBL}, + {"Group5", "CurtainD", TYPE_DBL}, +}; + +// load nx dataset +template <class T> +bool loadNXDataSet(NeXus::NXEntry &entry, const std::string &path, T &value) { + try { + NeXus::NXDataSetTyped<T> dataSet = entry.openNXDataSet<T>(path); + dataSet.load(); + + value = *dataSet(); + return true; + } catch (std::runtime_error &) { + return false; + } +} + +/** + * Initialise the algorithm. Declare properties which can be set before + * execution (input) or + * read from after the execution (output). + */ +void PatchBBY::init() { + // Specify file extensions which can be associated with a specific file. + std::vector<std::string> exts; + + // Declare the Filename algorithm property. Mandatory. Sets the path to the + // file to load. + exts.clear(); + exts.push_back(".tar"); + declareProperty( + new API::FileProperty(FilenameStr, "", API::FileProperty::Load, exts), + "The filename of the stored data to be patched"); + + // patchable properties + for (auto itr = std::begin(PatchableProperties); + itr != std::end(PatchableProperties); ++itr) { + switch (itr->Type) { + case TYPE_INT: + declareProperty(new Kernel::PropertyWithValue<int>( + itr->Name, EMPTY_INT(), Kernel::Direction::Input), + "Optional"); + break; + + case TYPE_DBL: + declareProperty(new Kernel::PropertyWithValue<double>( + itr->Name, EMPTY_DBL(), Kernel::Direction::Input), + "Optional"); + break; + } + + setPropertyGroup(itr->Name, itr->Group); + } + + declareProperty(new Kernel::PropertyWithValue<bool>("Reset", false, + Kernel::Direction::Input), + "Optional"); +} +/** + * Execute the algorithm. + */ +void PatchBBY::exec() { + // get the name of the data file + std::string filename = getPropertyValue(FilenameStr); + ANSTO::Tar::File tarFile(filename); + if (!tarFile.good()) + throw std::invalid_argument("invalid BBY file"); + + size_t hdfFiles = 0; + size_t binFiles = 0; + size_t logFiles = 0; + size_t logSize = 0; + + // open file (and select hisotry file if it exists) + const std::vector<std::string> &files = tarFile.files(); + for (auto itr = files.begin(); itr != files.end(); ++itr) { + auto len = itr->length(); + + if ((len > 4) && (itr->find_first_of("\\/", 0, 2) == std::string::npos)) { + if ((itr->compare(0, 3, "BBY") == 0) && (itr->rfind(".hdf") == len - 4)) + hdfFiles++; + else if (itr->rfind(".bin") == len - 4) + binFiles++; + else if (itr->compare(HistoryStr) == 0) { + if (std::distance(itr, files.end()) != 1) + throw std::invalid_argument( + "invalid BBY file (history has to be at the end)"); + + logFiles++; + tarFile.select(itr->c_str()); + logSize = tarFile.selected_size(); + } + } + } + + // check if it's valid + if ((hdfFiles != 1) || (binFiles != 1) || (logFiles > 1)) + throw std::invalid_argument("invalid BBY file"); + + // read existing history + std::string logContent; + if (logFiles != 0) { + logContent.resize(logSize); + tarFile.read(&logContent[0], logSize); + } + + // create new content + std::ostringstream logContentNewBuffer; + int tmp_int; + double tmp_dbl; + for (auto itr = std::begin(PatchableProperties); + itr != std::end(PatchableProperties); ++itr) { + auto property_value = getProperty(itr->Name); + // if (!isEmpty(property_value)) + switch (itr->Type) { + case TYPE_INT: + tmp_int = property_value; + if (tmp_int != EMPTY_INT()) // !!! + logContentNewBuffer << itr->Name << " = " << tmp_int << std::endl; + break; + + case TYPE_DBL: + tmp_dbl = property_value; + if (tmp_dbl != EMPTY_DBL()) // !!! + logContentNewBuffer << itr->Name << " = " << tmp_dbl << std::endl; + break; + } + } + + // load original values from hdf + bool reset = getProperty("Reset"); + if (reset) { + int64_t fileSize = 0; + for (auto itr = files.begin(); itr != files.end(); ++itr) + if (itr->rfind(".hdf") == itr->length() - 4) { + tarFile.select(itr->c_str()); + fileSize = tarFile.selected_size(); + break; + } + + if (fileSize != 0) { + // extract hdf file into tmp file + Poco::TemporaryFile hdfFile; + boost::shared_ptr<FILE> handle(fopen(hdfFile.path().c_str(), "wb"), + fclose); + if (handle) { + // copy content + char buffer[4096]; + size_t bytesRead; + while (0 != (bytesRead = tarFile.read(buffer, sizeof(buffer)))) + fwrite(buffer, bytesRead, 1, handle.get()); + handle.reset(); + + NeXus::NXRoot root(hdfFile.path()); + NeXus::NXEntry entry = root.openFirstEntry(); + + float tmp_float; + int32_t tmp_int32 = 0; + + if (loadNXDataSet(entry, "monitor/bm1_counts", tmp_int32)) + logContentNewBuffer << "bm1_counts" + << " = " << tmp_int32 << std::endl; + if (loadNXDataSet(entry, "instrument/att_pos", tmp_float)) + logContentNewBuffer << "att_pos" + << " = " << tmp_float << std::endl; + + if (loadNXDataSet(entry, "instrument/master_chopper_freq", tmp_float)) + logContentNewBuffer << "master_chopper_freq" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/t0_chopper_freq", tmp_float)) + logContentNewBuffer << "t0_chopper_freq" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/t0_chopper_phase", tmp_float)) + logContentNewBuffer << "t0_chopper_phase" + << " = " << (tmp_float < 999.0 ? tmp_float : 0.0) + << std::endl; + + if (loadNXDataSet(entry, "instrument/L2_det", tmp_float)) + logContentNewBuffer << "L2_det" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/Ltof_det", tmp_float)) + logContentNewBuffer << "Ltof_det" + << " = " << tmp_float << std::endl; + + if (loadNXDataSet(entry, "instrument/L2_curtainl", tmp_float)) + logContentNewBuffer << "L2_curtainl" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/L2_curtainr", tmp_float)) + logContentNewBuffer << "L2_curtainr" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/L2_curtainu", tmp_float)) + logContentNewBuffer << "L2_curtainu" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/L2_curtaind", tmp_float)) + logContentNewBuffer << "L2_curtaind" + << " = " << tmp_float << std::endl; + + if (loadNXDataSet(entry, "instrument/detector/curtainl", tmp_float)) + logContentNewBuffer << "curtainl" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/detector/curtainr", tmp_float)) + logContentNewBuffer << "curtainr" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/detector/curtainu", tmp_float)) + logContentNewBuffer << "curtainu" + << " = " << tmp_float << std::endl; + if (loadNXDataSet(entry, "instrument/detector/curtaind", tmp_float)) + logContentNewBuffer << "curtaind" + << " = " << tmp_float << std::endl; + } + } + } + + std::string logContentNew = logContentNewBuffer.str(); + if (logContentNew.size() == 0) + throw std::invalid_argument("nothing to patch"); + + // merge log content + logContent.append(logContentNew); + + // append patches to file + tarFile.close(); + if (!ANSTO::Tar::File::append(filename, HistoryStr, logContent.c_str(), + logContent.size())) + throw std::runtime_error("unable to patch"); +} + +} // DataHandling +} // Mantid