diff --git a/CMakeLists.txt b/CMakeLists.txt index 5edbf1f..0e221cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,7 +244,6 @@ set(PUBLICHEADERS include/aare/FileInterface.hpp include/aare/RawMasterFile.hpp include/aare/Frame.hpp - include/aare/json.hpp include/aare/NDArray.hpp include/aare/NDView.hpp include/aare/NumpyFile.hpp diff --git a/include/aare/RawMasterFile.hpp b/include/aare/RawMasterFile.hpp index 7861fb9..f86054a 100644 --- a/include/aare/RawMasterFile.hpp +++ b/include/aare/RawMasterFile.hpp @@ -23,7 +23,7 @@ class RawFileNameComponents { RawFileNameComponents(const std::filesystem::path &fname); /// @brief Get the filename including path of the master file. - /// (i.e. what was passed in to the constructor)) + /// (i.e. what was passed in to the constructor)) std::filesystem::path master_fname() const; /// @brief Get the filename including path of the data file. @@ -31,16 +31,36 @@ class RawFileNameComponents { /// @param file_id file id run_d0_f[file_id]_0 std::filesystem::path data_fname(size_t mod_id, size_t file_id) const; - const std::filesystem::path &base_path() const; const std::string &base_name() const; const std::string &ext() const; int file_index() const; }; +class ScanParameters { + bool m_enabled = false; + std::string m_dac; + int m_start = 0; + int m_stop = 0; + int m_step = 0; + //TODO! add settleTime, requires string to time conversion + + public: + ScanParameters(const std::string &par); + ScanParameters() = default; + ScanParameters(const ScanParameters &) = default; + ScanParameters &operator=(const ScanParameters &) = default; + ScanParameters(ScanParameters &&) = default; + int start() const; + int stop() const; + int step() const; + const std::string &dac() const; + bool enabled() const; +}; /** - * @brief Class for parsing a master file either in our .json format or the old .raw format + * @brief Class for parsing a master file either in our .json format or the old + * .raw format */ class RawMasterFile { RawFileNameComponents m_fnc; @@ -62,11 +82,13 @@ class RawMasterFile { FrameDiscardPolicy m_frame_discard_policy{}; size_t m_frame_padding{}; - //TODO! should these be bool? + // TODO! should these be bool? uint8_t m_analog_flag{}; uint8_t m_digital_flag{}; uint8_t m_transceiver_flag{}; + ScanParameters m_scan_parameters; + std::optional m_analog_samples; std::optional m_digital_samples; std::optional m_transceiver_samples; @@ -78,7 +100,7 @@ class RawMasterFile { std::filesystem::path data_fname(size_t mod_id, size_t file_id) const; - const std::string &version() const; //!< For example "7.2" + const std::string &version() const; //!< For example "7.2" const DetectorType &detector_type() const; const TimingMode &timing_mode() const; size_t image_size_in_bytes() const; @@ -98,6 +120,9 @@ class RawMasterFile { std::optional transceiver_samples() const; std::optional number_of_rows() const; std::optional quad() const; + + ScanParameters scan_parameters() const; + private: void parse_json(const std::filesystem::path &fpath); void parse_raw(const std::filesystem::path &fpath); diff --git a/include/aare/json.hpp b/include/aare/json.hpp deleted file mode 100644 index 2afe7f7..0000000 --- a/include/aare/json.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -#include -#include -#include -#include - -// helper functions to write json -// append to string for better performance (not tested) - -namespace aare { - -/** - * @brief write a digit to a string - * takes key and value and outputs->"key": value, - * @tparam T type of value (int, uint32_t, ...) - * @param s string to append to - * @param key key to write - * @param value value to write - * @return void - * @note - * - can't use concepts here because we are using c++17 - */ -template inline void write_digit(std::string &s, const std::string &key, const T &value) { - s += "\""; - s += key; - s += "\": "; - s += std::to_string(value); - s += ", "; -} -inline void write_str(std::string &s, const std::string &key, const std::string &value) { - s += "\""; - s += key; - s += "\": \""; - s += value; - s += "\", "; -} -inline void write_map(std::string &s, const std::string &key, const std::map &value) { - s += "\""; - s += key; - s += "\": {"; - for (const auto &kv : value) { - write_str(s, kv.first, kv.second); - } - // remove last comma or trailing spaces - for (size_t i = s.size() - 1; i > 0; i--) { - if ((s[i] == ',') || (s[i] == ' ')) { - s.pop_back(); - } else - break; - } - s += "}, "; -} - -template void write_array(std::string &s, const std::string &key, const std::array &value) { - s += "\""; - s += key; - s += "\": ["; - - for (size_t i = 0; i < N - 1; i++) { - s += std::to_string(value[i]); - s += ", "; - } - s += std::to_string(value[N - 1]); - - s += "], "; -} - -} // namespace aare diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index a8edf26..888c33c 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -29,6 +29,7 @@ set( PYTHON_FILES aare/__init__.py aare/CtbRawFile.py aare/transform.py + aare/ScanParameters.py ) # Copy the python files to the build directory diff --git a/python/aare/CtbRawFile.py b/python/aare/CtbRawFile.py index 1925ef5..4684c37 100644 --- a/python/aare/CtbRawFile.py +++ b/python/aare/CtbRawFile.py @@ -1,7 +1,7 @@ from . import _aare import numpy as np - +from .ScanParameters import ScanParameters class CtbRawFile(_aare.CtbRawFile): """File reader for the CTB raw file format. @@ -108,7 +108,24 @@ class CtbRawFile(_aare.CtbRawFile): int: Frame position in file. """ return super().tell() + + @property + def scan_parameters(self): + """Return the scan parameters. + Returns: + ScanParameters: Scan parameters. + """ + return ScanParameters(self.master.scan_parameters) + + @property + def master(self): + """Return the master file. + + Returns: + RawMasterFile: Master file. + """ + return super().master() @property def image_size_in_bytes(self) -> int: diff --git a/python/aare/ScanParameters.py b/python/aare/ScanParameters.py new file mode 100644 index 0000000..5486ca9 --- /dev/null +++ b/python/aare/ScanParameters.py @@ -0,0 +1,16 @@ +from . import _aare + +class ScanParameters(_aare.ScanParameters): + def __init__(self, s): + super().__init__(s) + + def __iter__(self): + return [getattr(self, a) for a in ['start', 'stop', 'step']].__iter__() + + def __str__(self): + return f'ScanParameters({self.dac}: {self.start}, {self.stop}, {self.step})' + + def __repr__(self): + return self.__str__() + + \ No newline at end of file diff --git a/python/aare/__init__.py b/python/aare/__init__.py index 6ebf213..76af17a 100644 --- a/python/aare/__init__.py +++ b/python/aare/__init__.py @@ -3,4 +3,5 @@ from . import _aare from ._aare import VarClusterFinder, File, RawMasterFile from ._aare import Pedestal, ClusterFinder -from .CtbRawFile import CtbRawFile \ No newline at end of file +from .CtbRawFile import CtbRawFile +from .ScanParameters import ScanParameters \ No newline at end of file diff --git a/python/aare/transform.py b/python/aare/transform.py index 47a7efc..a99f9c4 100644 --- a/python/aare/transform.py +++ b/python/aare/transform.py @@ -5,7 +5,6 @@ from . import _aare class Moench05Transform: #Could be moved to C++ without changing the interface def __init__(self): - print('map created') self.pixel_map = _aare.GenerateMoench05PixelMap() def __call__(self, data): @@ -23,6 +22,7 @@ class Matterhorn02Transform: else: return np.take(data.view(np.uint16), self.pixel_map[0:counters]) + #on import generate the pixel maps to avoid doing it every time moench05 = Moench05Transform() matterhorn02 = Matterhorn02Transform() \ No newline at end of file diff --git a/python/examples/play.py b/python/examples/play.py index 08703c2..3a12d28 100644 --- a/python/examples/play.py +++ b/python/examples/play.py @@ -95,11 +95,11 @@ f = aare.CtbRawFile(fpath, transform=transform.matterhorn02) f.seek(100) header1, image1 = f.read_frame() -fpath = Path(base / 'scan_all15keV_vrf500_vrsh700_th0_master_0.json') +# fpath = Path(base / 'scan_all15keV_vrf500_vrsh700_th0_master_0.json') -f = aare.CtbRawFile(fpath, transform=transform.matterhorn02) -f.seek(100) -header4, image4 = f.read_frame() +# f = aare.CtbRawFile(fpath, transform=transform.matterhorn02) +# f.seek(100) +# header4, image4 = f.read_frame() # n_counters = image.shape[1] / 48**2 / 2 @@ -112,7 +112,7 @@ header4, image4 = f.read_frame() #Data come in "blocks" of 4 pixels/receiver -data = get_Mh02_frames(fpath.as_posix()) +# data = get_Mh02_frames(fpath.as_posix()) # rawi = np.zeros(48*48*4+56, dtype = np.uint16) # for i,v in enumerate(rawi[56:]): @@ -130,7 +130,7 @@ data = get_Mh02_frames(fpath.as_posix()) # pm[counter, row, col] = row*48 + col+counter*48*48 -f2 = aare.CtbRawFile(fpath, transform=transform.matterhorn02) -header, data = f2.read() -plt.plot(data[:,0,20,20]) +# f2 = aare.CtbRawFile(fpath, transform=transform.matterhorn02) +# header, data = f2.read() +# plt.plot(data[:,0,20,20]) diff --git a/python/src/file.hpp b/python/src/file.hpp index 7f9b2a3..6471b44 100644 --- a/python/src/file.hpp +++ b/python/src/file.hpp @@ -166,11 +166,29 @@ void define_file_io_bindings(py::module &m) { .def_property_readonly("max_frames_per_file", &RawMasterFile::max_frames_per_file) .def_property_readonly("bitdepth", &RawMasterFile::bitdepth) + .def_property_readonly("frame_padding", &RawMasterFile::frame_padding) + .def_property_readonly("frame_discard_policy", + &RawMasterFile::frame_discard_policy) + .def_property_readonly("total_frames_expected", &RawMasterFile::total_frames_expected) + .def_property_readonly("geometry", &RawMasterFile::geometry) .def_property_readonly("analog_samples", &RawMasterFile::analog_samples) .def_property_readonly("digital_samples", &RawMasterFile::digital_samples) - .def_property_readonly("transceiver_samples", &RawMasterFile::transceiver_samples); + .def_property_readonly("transceiver_samples", &RawMasterFile::transceiver_samples) + .def_property_readonly("number_of_rows", &RawMasterFile::number_of_rows) + .def_property_readonly("quad", &RawMasterFile::quad) + .def_property_readonly("scan_parameters", &RawMasterFile::scan_parameters); + + + py::class_(m, "ScanParameters") + .def(py::init()) + .def(py::init()) + .def_property_readonly("enabled", &ScanParameters::enabled) + .def_property_readonly("dac", &ScanParameters::dac) + .def_property_readonly("start", &ScanParameters::start) + .def_property_readonly("stop", &ScanParameters::stop) + .def_property_readonly("step", &ScanParameters::step); // py::class_(m, "ClusterHeader") // .def(py::init<>()) // .def_readwrite("frame_number", &ClusterHeader::frame_number) diff --git a/src/RawFile.cpp b/src/RawFile.cpp index c53523d..31b57c5 100644 --- a/src/RawFile.cpp +++ b/src/RawFile.cpp @@ -1,7 +1,6 @@ #include "aare/RawFile.hpp" #include "aare/PixelMap.hpp" #include "aare/defs.hpp" -#include "aare/json.hpp" #include #include diff --git a/src/RawMasterFile.cpp b/src/RawMasterFile.cpp index e6a878e..09a0006 100644 --- a/src/RawMasterFile.cpp +++ b/src/RawMasterFile.cpp @@ -1,5 +1,5 @@ #include "aare/RawMasterFile.hpp" - +#include namespace aare { RawFileNameComponents::RawFileNameComponents( @@ -51,6 +51,32 @@ const std::string &RawFileNameComponents::base_name() const { const std::string &RawFileNameComponents::ext() const { return m_ext; } int RawFileNameComponents::file_index() const { return m_file_index; } +// "[enabled\ndac dac 4\nstart 500\nstop 2200\nstep 5\nsettleTime 100us\n]" +ScanParameters::ScanParameters(const std::string& par){ + std::istringstream iss(par.substr(1, par.size()-2)); + std::string line; + while(std::getline(iss, line)){ + if(line == "enabled"){ + m_enabled = true; + }else if(line.find("dac") != std::string::npos){ + m_dac = line.substr(4); + }else if(line.find("start") != std::string::npos){ + m_start = std::stoi(line.substr(6)); + }else if(line.find("stop") != std::string::npos){ + m_stop = std::stoi(line.substr(5)); + }else if(line.find("step") != std::string::npos){ + m_step = std::stoi(line.substr(5)); + } + } +} + +int ScanParameters::start() const { return m_start; } +int ScanParameters::stop() const { return m_stop; } +int ScanParameters::step() const { return m_step; } +const std::string &ScanParameters::dac() const { return m_dac; } +bool ScanParameters::enabled() const { return m_enabled; } + + RawMasterFile::RawMasterFile(const std::filesystem::path &fpath) : m_fnc(fpath) { if (!std::filesystem::exists(fpath)) { @@ -113,6 +139,10 @@ std::optional RawMasterFile::transceiver_samples() const { return m_transceiver_samples; } +ScanParameters RawMasterFile::scan_parameters() const { + return m_scan_parameters; +} + void RawMasterFile::parse_json(const std::filesystem::path &fpath) { std::ifstream ifs(fpath); json j; @@ -203,6 +233,13 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) { // keep the optional empty } + try{ + std::string scan_parameters = j.at("Scan Parameters"); + m_scan_parameters = ScanParameters(scan_parameters); + }catch (const json::out_of_range &e) { + // not a scan + } + // Update detector type for Moench // TODO! How does this work with old .raw master files? #ifdef AARE_VERBOSE diff --git a/src/RawMasterFile.test.cpp b/src/RawMasterFile.test.cpp index 1f548c5..d8e1e87 100644 --- a/src/RawMasterFile.test.cpp +++ b/src/RawMasterFile.test.cpp @@ -38,6 +38,26 @@ TEST_CASE("Master file name does not fit pattern"){ } + +TEST_CASE("Parse scan parameters"){ + ScanParameters s("[enabled\ndac dac 4\nstart 500\nstop 2200\nstep 5\nsettleTime 100us\n]"); + REQUIRE(s.enabled()); + REQUIRE(s.dac() == "dac 4"); + REQUIRE(s.start() == 500); + REQUIRE(s.stop() == 2200); + REQUIRE(s.step() == 5); +} + +TEST_CASE("A disabled scan"){ + ScanParameters s("[disabled]"); + REQUIRE_FALSE(s.enabled()); + REQUIRE(s.dac() == ""); + REQUIRE(s.start() == 0); + REQUIRE(s.stop() == 0); + REQUIRE(s.step() == 0); +} + + TEST_CASE("Parse a master file in .json format"){ auto fpath = test_data_path() / "jungfrau" / "jungfrau_single_master_0.json"; REQUIRE(std::filesystem::exists(fpath));