formatted main branch

This commit is contained in:
2025-06-10 16:09:06 +02:00
parent efd2338f54
commit f9751902a2
87 changed files with 1710 additions and 1639 deletions

View File

@ -31,17 +31,15 @@ ClusterFile::ClusterFile(const std::filesystem::path &fname, size_t chunk_size,
}
}
void ClusterFile::set_roi(ROI roi){
m_roi = roi;
}
void ClusterFile::set_roi(ROI roi) { m_roi = roi; }
void ClusterFile::set_noise_map(const NDView<int32_t, 2> noise_map){
void ClusterFile::set_noise_map(const NDView<int32_t, 2> noise_map) {
m_noise_map = NDArray<int32_t, 2>(noise_map);
}
void ClusterFile::set_gain_map(const NDView<double, 2> gain_map){
void ClusterFile::set_gain_map(const NDView<double, 2> gain_map) {
m_gain_map = NDArray<double, 2>(gain_map);
// Gain map is passed as ADU/keV to avoid dividing in when applying the gain
// map we invert it here
for (auto &item : m_gain_map->view()) {
@ -66,42 +64,44 @@ void ClusterFile::write_frame(const ClusterVector<int32_t> &clusters) {
!(clusters.cluster_size_y() == 3)) {
throw std::runtime_error("Only 3x3 clusters are supported");
}
//First write the frame number - 4 bytes
// First write the frame number - 4 bytes
int32_t frame_number = clusters.frame_number();
if(fwrite(&frame_number, sizeof(frame_number), 1, fp)!=1){
if (fwrite(&frame_number, sizeof(frame_number), 1, fp) != 1) {
throw std::runtime_error(LOCATION + "Could not write frame number");
}
//Then write the number of clusters - 4 bytes
// Then write the number of clusters - 4 bytes
uint32_t n_clusters = clusters.size();
if(fwrite(&n_clusters, sizeof(n_clusters), 1, fp)!=1){
throw std::runtime_error(LOCATION + "Could not write number of clusters");
if (fwrite(&n_clusters, sizeof(n_clusters), 1, fp) != 1) {
throw std::runtime_error(LOCATION +
"Could not write number of clusters");
}
//Now write the clusters in the frame
if(fwrite(clusters.data(), clusters.item_size(), clusters.size(), fp)!=clusters.size()){
// Now write the clusters in the frame
if (fwrite(clusters.data(), clusters.item_size(), clusters.size(), fp) !=
clusters.size()) {
throw std::runtime_error(LOCATION + "Could not write clusters");
}
}
ClusterVector<int32_t> ClusterFile::read_clusters(size_t n_clusters){
ClusterVector<int32_t> ClusterFile::read_clusters(size_t n_clusters) {
if (m_mode != "r") {
throw std::runtime_error("File not opened for reading");
}
if (m_noise_map || m_roi){
if (m_noise_map || m_roi) {
return read_clusters_with_cut(n_clusters);
}else{
} else {
return read_clusters_without_cut(n_clusters);
}
}
ClusterVector<int32_t> ClusterFile::read_clusters_without_cut(size_t n_clusters) {
ClusterVector<int32_t>
ClusterFile::read_clusters_without_cut(size_t n_clusters) {
if (m_mode != "r") {
throw std::runtime_error("File not opened for reading");
}
ClusterVector<int32_t> clusters(3,3, n_clusters);
ClusterVector<int32_t> clusters(3, 3, n_clusters);
int32_t iframe = 0; // frame number needs to be 4 bytes!
size_t nph_read = 0;
@ -119,7 +119,7 @@ ClusterVector<int32_t> ClusterFile::read_clusters_without_cut(size_t n_clusters)
} else {
nn = nph;
}
nph_read += fread((buf + nph_read*clusters.item_size()),
nph_read += fread((buf + nph_read * clusters.item_size()),
clusters.item_size(), nn, fp);
m_num_left = nph - nn; // write back the number of photons left
}
@ -135,7 +135,7 @@ ClusterVector<int32_t> ClusterFile::read_clusters_without_cut(size_t n_clusters)
else
nn = nph;
nph_read += fread((buf + nph_read*clusters.item_size()),
nph_read += fread((buf + nph_read * clusters.item_size()),
clusters.item_size(), nn, fp);
m_num_left = nph - nn;
}
@ -147,22 +147,22 @@ ClusterVector<int32_t> ClusterFile::read_clusters_without_cut(size_t n_clusters)
// Resize the vector to the number of clusters.
// No new allocation, only change bounds.
clusters.resize(nph_read);
if(m_gain_map)
if (m_gain_map)
clusters.apply_gain_map(m_gain_map->view());
return clusters;
}
ClusterVector<int32_t> ClusterFile::read_clusters_with_cut(size_t n_clusters) {
ClusterVector<int32_t> clusters(3,3);
ClusterVector<int32_t> clusters(3, 3);
clusters.reserve(n_clusters);
// if there are photons left from previous frame read them first
if (m_num_left) {
while(m_num_left && clusters.size() < n_clusters){
while (m_num_left && clusters.size() < n_clusters) {
Cluster3x3 c = read_one_cluster();
if(is_selected(c)){
clusters.push_back(c.x, c.y, reinterpret_cast<std::byte*>(c.data));
if (is_selected(c)) {
clusters.push_back(c.x, c.y,
reinterpret_cast<std::byte *>(c.data));
}
}
}
@ -172,17 +172,21 @@ ClusterVector<int32_t> ClusterFile::read_clusters_with_cut(size_t n_clusters) {
if (clusters.size() < n_clusters) {
// sanity check
if (m_num_left) {
throw std::runtime_error(LOCATION + "Entered second loop with clusters left\n");
throw std::runtime_error(
LOCATION + "Entered second loop with clusters left\n");
}
int32_t frame_number = 0; // frame number needs to be 4 bytes!
while (fread(&frame_number, sizeof(frame_number), 1, fp)) {
if (fread(&m_num_left, sizeof(m_num_left), 1, fp)) {
clusters.set_frame_number(frame_number); //cluster vector will hold the last frame number
while(m_num_left && clusters.size() < n_clusters){
clusters.set_frame_number(
frame_number); // cluster vector will hold the last frame
// number
while (m_num_left && clusters.size() < n_clusters) {
Cluster3x3 c = read_one_cluster();
if(is_selected(c)){
clusters.push_back(c.x, c.y, reinterpret_cast<std::byte*>(c.data));
if (is_selected(c)) {
clusters.push_back(
c.x, c.y, reinterpret_cast<std::byte *>(c.data));
}
}
}
@ -191,15 +195,14 @@ ClusterVector<int32_t> ClusterFile::read_clusters_with_cut(size_t n_clusters) {
if (clusters.size() >= n_clusters)
break;
}
}
if(m_gain_map)
if (m_gain_map)
clusters.apply_gain_map(m_gain_map->view());
return clusters;
}
Cluster3x3 ClusterFile::read_one_cluster(){
Cluster3x3 ClusterFile::read_one_cluster() {
Cluster3x3 c;
auto rc = fread(&c, sizeof(c), 1, fp);
if (rc != 1) {
@ -209,13 +212,13 @@ Cluster3x3 ClusterFile::read_one_cluster(){
return c;
}
ClusterVector<int32_t> ClusterFile::read_frame(){
ClusterVector<int32_t> ClusterFile::read_frame() {
if (m_mode != "r") {
throw std::runtime_error(LOCATION + "File not opened for reading");
}
if (m_noise_map || m_roi){
if (m_noise_map || m_roi) {
return read_frame_with_cut();
}else{
} else {
return read_frame_without_cut();
}
}
@ -235,7 +238,8 @@ ClusterVector<int32_t> ClusterFile::read_frame_without_cut() {
int32_t n_clusters; // Saved as 32bit integer in the cluster file
if (fread(&n_clusters, sizeof(n_clusters), 1, fp) != 1) {
throw std::runtime_error(LOCATION + "Could not read number of clusters");
throw std::runtime_error(LOCATION +
"Could not read number of clusters");
}
ClusterVector<int32_t> clusters(3, 3, n_clusters);
@ -264,18 +268,17 @@ ClusterVector<int32_t> ClusterFile::read_frame_with_cut() {
throw std::runtime_error("Could not read frame number");
}
if (fread(&m_num_left, sizeof(m_num_left), 1, fp) != 1) {
throw std::runtime_error("Could not read number of clusters");
}
ClusterVector<int32_t> clusters(3, 3);
clusters.reserve(m_num_left);
clusters.set_frame_number(frame_number);
while(m_num_left){
while (m_num_left) {
Cluster3x3 c = read_one_cluster();
if(is_selected(c)){
clusters.push_back(c.x, c.y, reinterpret_cast<std::byte*>(c.data));
if (is_selected(c)) {
clusters.push_back(c.x, c.y, reinterpret_cast<std::byte *>(c.data));
}
}
if (m_gain_map)
@ -283,56 +286,56 @@ ClusterVector<int32_t> ClusterFile::read_frame_with_cut() {
return clusters;
}
bool ClusterFile::is_selected(Cluster3x3 &cl) {
//Should fail fast
// Should fail fast
if (m_roi) {
if (!(m_roi->contains(cl.x, cl.y))) {
return false;
}
}
if (m_noise_map){
int32_t sum_1x1 = cl.data[4]; // central pixel
if (m_noise_map) {
int32_t sum_1x1 = cl.data[4]; // central pixel
int32_t sum_2x2 = cl.sum_2x2(); // highest sum of 2x2 subclusters
int32_t sum_3x3 = cl.sum(); // sum of all pixels
int32_t sum_3x3 = cl.sum(); // sum of all pixels
auto noise = (*m_noise_map)(cl.y, cl.x); //TODO! check if this is correct
auto noise =
(*m_noise_map)(cl.y, cl.x); // TODO! check if this is correct
if (sum_1x1 <= noise || sum_2x2 <= 2 * noise || sum_3x3 <= 3 * noise) {
return false;
}
}
//we passed all checks
// we passed all checks
return true;
}
NDArray<double, 2> calculate_eta2(ClusterVector<int> &clusters) {
//TOTO! make work with 2x2 clusters
// TOTO! make work with 2x2 clusters
NDArray<double, 2> eta2({static_cast<int64_t>(clusters.size()), 2});
if (clusters.cluster_size_x() == 3 || clusters.cluster_size_y() == 3) {
for (size_t i = 0; i < clusters.size(); i++) {
auto e = calculate_eta2(clusters.at<Cluster3x3>(i));
eta2(i, 0) = e.x;
eta2(i, 1) = e.y;
}
}else if(clusters.cluster_size_x() == 2 || clusters.cluster_size_y() == 2){
} else if (clusters.cluster_size_x() == 2 ||
clusters.cluster_size_y() == 2) {
for (size_t i = 0; i < clusters.size(); i++) {
auto e = calculate_eta2(clusters.at<Cluster2x2>(i));
eta2(i, 0) = e.x;
eta2(i, 1) = e.y;
}
}else{
} else {
throw std::runtime_error("Only 3x3 and 2x2 clusters are supported");
}
return eta2;
}
/**
* @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2 struct
* containing etay, etax and the corner of the cluster.
*/
/**
* @brief Calculate the eta2 values for a 3x3 cluster and return them in a Eta2
* struct containing etay, etax and the corner of the cluster.
*/
Eta2 calculate_eta2(Cluster3x3 &cl) {
Eta2 eta{};
@ -347,56 +350,46 @@ Eta2 calculate_eta2(Cluster3x3 &cl) {
switch (c) {
case cBottomLeft:
if ((cl.data[3] + cl.data[4]) != 0)
eta.x =
static_cast<double>(cl.data[4]) / (cl.data[3] + cl.data[4]);
eta.x = static_cast<double>(cl.data[4]) / (cl.data[3] + cl.data[4]);
if ((cl.data[1] + cl.data[4]) != 0)
eta.y =
static_cast<double>(cl.data[4]) / (cl.data[1] + cl.data[4]);
eta.y = static_cast<double>(cl.data[4]) / (cl.data[1] + cl.data[4]);
eta.c = cBottomLeft;
break;
case cBottomRight:
if ((cl.data[2] + cl.data[5]) != 0)
eta.x =
static_cast<double>(cl.data[5]) / (cl.data[4] + cl.data[5]);
eta.x = static_cast<double>(cl.data[5]) / (cl.data[4] + cl.data[5]);
if ((cl.data[1] + cl.data[4]) != 0)
eta.y =
static_cast<double>(cl.data[4]) / (cl.data[1] + cl.data[4]);
eta.y = static_cast<double>(cl.data[4]) / (cl.data[1] + cl.data[4]);
eta.c = cBottomRight;
break;
case cTopLeft:
if ((cl.data[7] + cl.data[4]) != 0)
eta.x =
static_cast<double>(cl.data[4]) / (cl.data[3] + cl.data[4]);
eta.x = static_cast<double>(cl.data[4]) / (cl.data[3] + cl.data[4]);
if ((cl.data[7] + cl.data[4]) != 0)
eta.y =
static_cast<double>(cl.data[7]) / (cl.data[7] + cl.data[4]);
eta.y = static_cast<double>(cl.data[7]) / (cl.data[7] + cl.data[4]);
eta.c = cTopLeft;
break;
case cTopRight:
if ((cl.data[5] + cl.data[4]) != 0)
eta.x =
static_cast<double>(cl.data[5]) / (cl.data[5] + cl.data[4]);
eta.x = static_cast<double>(cl.data[5]) / (cl.data[5] + cl.data[4]);
if ((cl.data[7] + cl.data[4]) != 0)
eta.y =
static_cast<double>(cl.data[7]) / (cl.data[7] + cl.data[4]);
eta.y = static_cast<double>(cl.data[7]) / (cl.data[7] + cl.data[4]);
eta.c = cTopRight;
break;
// no default to allow compiler to warn about missing cases
// no default to allow compiler to warn about missing cases
}
return eta;
}
Eta2 calculate_eta2(Cluster2x2 &cl) {
Eta2 eta{};
if ((cl.data[0] + cl.data[1]) != 0)
eta.x = static_cast<double>(cl.data[1]) / (cl.data[0] + cl.data[1]);
if ((cl.data[0] + cl.data[2]) != 0)
eta.y = static_cast<double>(cl.data[2]) / (cl.data[0] + cl.data[2]);
eta.sum = cl.data[0] + cl.data[1] + cl.data[2]+ cl.data[3];
eta.c = cBottomLeft; //TODO! This is not correct, but need to put something
eta.sum = cl.data[0] + cl.data[1] + cl.data[2] + cl.data[3];
eta.c = cBottomLeft; // TODO! This is not correct, but need to put something
return eta;
}
} // namespace aare

View File

@ -10,9 +10,8 @@ using aare::Cluster;
using aare::ClusterFile;
using aare::ClusterVector;
TEST_CASE("Read one frame from a cluster file", "[.files]") {
//We know that the frame has 97 clusters
// We know that the frame has 97 clusters
auto fpath = test_data_path() / "clust" / "single_frame_97_clustrers.clust";
REQUIRE(std::filesystem::exists(fpath));
@ -27,7 +26,6 @@ TEST_CASE("Read one frame from a cluster file", "[.files]") {
std::begin(expected_cluster_data)));
}
TEST_CASE("Read one frame using ROI", "[.files]") {
// We know that the frame has 97 clusters
auto fpath = test_data_path() / "clust" / "single_frame_97_clustrers.clust";
@ -60,8 +58,6 @@ TEST_CASE("Read one frame using ROI", "[.files]") {
std::begin(expected_cluster_data)));
}
TEST_CASE("Read clusters from single frame file", "[.files]") {
// frame_number, num_clusters [135] 97

View File

@ -14,22 +14,24 @@ CtbRawFile::CtbRawFile(const std::filesystem::path &fname) : m_master(fname) {
m_file.open(m_master.data_fname(0, 0), std::ios::binary);
}
void CtbRawFile::read_into(std::byte *image_buf, DetectorHeader* header) {
if(m_current_frame >= m_master.frames_in_file()){
void CtbRawFile::read_into(std::byte *image_buf, DetectorHeader *header) {
if (m_current_frame >= m_master.frames_in_file()) {
throw std::runtime_error(LOCATION + " End of file reached");
}
if(m_current_frame != 0 && m_current_frame % m_master.max_frames_per_file() == 0){
open_data_file(m_current_subfile+1);
if (m_current_frame != 0 &&
m_current_frame % m_master.max_frames_per_file() == 0) {
open_data_file(m_current_subfile + 1);
}
if(header){
if (header) {
m_file.read(reinterpret_cast<char *>(header), sizeof(DetectorHeader));
}else{
} else {
m_file.seekg(sizeof(DetectorHeader), std::ios::cur);
}
m_file.read(reinterpret_cast<char *>(image_buf), m_master.image_size_in_bytes());
m_file.read(reinterpret_cast<char *>(image_buf),
m_master.image_size_in_bytes());
m_current_frame++;
}
@ -38,13 +40,16 @@ void CtbRawFile::seek(size_t frame_number) {
open_data_file(index);
}
size_t frame_number_in_file = frame_number % m_master.max_frames_per_file();
m_file.seekg((sizeof(DetectorHeader)+m_master.image_size_in_bytes()) * frame_number_in_file);
m_file.seekg((sizeof(DetectorHeader) + m_master.image_size_in_bytes()) *
frame_number_in_file);
m_current_frame = frame_number;
}
size_t CtbRawFile::tell() const { return m_current_frame; }
size_t CtbRawFile::image_size_in_bytes() const { return m_master.image_size_in_bytes(); }
size_t CtbRawFile::image_size_in_bytes() const {
return m_master.image_size_in_bytes();
}
size_t CtbRawFile::frames_in_file() const { return m_master.frames_in_file(); }
@ -63,12 +68,11 @@ void CtbRawFile::open_data_file(size_t subfile_index) {
throw std::runtime_error(LOCATION + "Subfile index out of range");
}
m_current_subfile = subfile_index;
m_file = std::ifstream(m_master.data_fname(0, subfile_index), std::ios::binary); // only one module for CTB
m_file = std::ifstream(m_master.data_fname(0, subfile_index),
std::ios::binary); // only one module for CTB
if (!m_file.is_open()) {
throw std::runtime_error(LOCATION + "Could not open data file");
}
}
} // namespace aare

View File

@ -10,7 +10,8 @@ namespace aare {
* @brief Construct a DType object from a type_info object
* @param t type_info object
* @throw runtime_error if the type is not supported
* @note supported types are: int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float, double
* @note supported types are: int8_t, uint8_t, int16_t, uint16_t, int32_t,
* uint32_t, int64_t, uint64_t, float, double
* @note the type_info object is obtained using typeid (e.g. typeid(int))
*/
Dtype::Dtype(const std::type_info &t) {
@ -35,7 +36,8 @@ Dtype::Dtype(const std::type_info &t) {
else if (t == typeid(double))
m_type = TypeIndex::DOUBLE;
else
throw std::runtime_error("Could not construct data type. Type not supported.");
throw std::runtime_error(
"Could not construct data type. Type not supported.");
}
/**
@ -63,7 +65,8 @@ uint8_t Dtype::bitdepth() const {
case TypeIndex::NONE:
return 0;
default:
throw std::runtime_error(LOCATION + "Could not get bitdepth. Type not supported.");
throw std::runtime_error(LOCATION +
"Could not get bitdepth. Type not supported.");
}
}
@ -138,7 +141,8 @@ Dtype Dtype::from_bitdepth(uint8_t bitdepth) {
case 64:
return Dtype(TypeIndex::UINT64);
default:
throw std::runtime_error("Could not construct data type from bitdepth.");
throw std::runtime_error(
"Could not construct data type from bitdepth.");
}
}
/**
@ -175,17 +179,27 @@ std::string Dtype::to_string() const {
case TypeIndex::DOUBLE:
return "f8";
case TypeIndex::ERROR:
throw std::runtime_error("Could not get string representation. Type not supported.");
throw std::runtime_error(
"Could not get string representation. Type not supported.");
case TypeIndex::NONE:
throw std::runtime_error("Could not get string representation. Type not supported.");
throw std::runtime_error(
"Could not get string representation. Type not supported.");
}
return {};
}
bool Dtype::operator==(const Dtype &other) const noexcept { return m_type == other.m_type; }
bool Dtype::operator!=(const Dtype &other) const noexcept { return !(*this == other); }
bool Dtype::operator==(const Dtype &other) const noexcept {
return m_type == other.m_type;
}
bool Dtype::operator!=(const Dtype &other) const noexcept {
return !(*this == other);
}
bool Dtype::operator==(const std::type_info &t) const { return Dtype(t) == *this; }
bool Dtype::operator!=(const std::type_info &t) const { return Dtype(t) != *this; }
bool Dtype::operator==(const std::type_info &t) const {
return Dtype(t) == *this;
}
bool Dtype::operator!=(const std::type_info &t) const {
return Dtype(t) != *this;
}
} // namespace aare

View File

@ -51,4 +51,6 @@ TEST_CASE("Construct from string with endianess") {
REQUIRE_THROWS(Dtype(">i4") == typeid(int32_t));
}
TEST_CASE("Convert to string") { REQUIRE(Dtype(typeid(int)).to_string() == "<i4"); }
TEST_CASE("Convert to string") {
REQUIRE(Dtype(typeid(int)).to_string() == "<i4");
}

View File

@ -19,28 +19,24 @@ File::File(const std::filesystem::path &fname, const std::string &mode,
fmt::format("File does not exist: {}", fname.string()));
}
// Assuming we are pointing at a master file?
// Assuming we are pointing at a master file?
// TODO! How do we read raw files directly?
if (fname.extension() == ".raw" || fname.extension() == ".json") {
// file_impl = new RawFile(fname, mode, cfg);
file_impl = std::make_unique<RawFile>(fname, mode);
}
else if (fname.extension() == ".npy") {
} else if (fname.extension() == ".npy") {
// file_impl = new NumpyFile(fname, mode, cfg);
file_impl = std::make_unique<NumpyFile>(fname, mode, cfg);
}else if(fname.extension() == ".dat"){
} else if (fname.extension() == ".dat") {
file_impl = std::make_unique<JungfrauDataFile>(fname);
} else {
throw std::runtime_error("Unsupported file type");
}
}
File::File(File &&other) noexcept { std::swap(file_impl, other.file_impl); }
File::File(File &&other) noexcept{
std::swap(file_impl, other.file_impl);
}
File& File::operator=(File &&other) noexcept {
File &File::operator=(File &&other) noexcept {
if (this != &other) {
File tmp(std::move(other));
std::swap(file_impl, tmp.file_impl);
@ -70,15 +66,16 @@ size_t File::frame_number(size_t frame_index) {
}
size_t File::bytes_per_frame() const { return file_impl->bytes_per_frame(); }
size_t File::pixels_per_frame() const{ return file_impl->pixels_per_frame(); }
size_t File::pixels_per_frame() const { return file_impl->pixels_per_frame(); }
void File::seek(size_t frame_index) { file_impl->seek(frame_index); }
size_t File::tell() const { return file_impl->tell(); }
size_t File::rows() const { return file_impl->rows(); }
size_t File::cols() const { return file_impl->cols(); }
size_t File::bitdepth() const { return file_impl->bitdepth(); }
size_t File::bytes_per_pixel() const { return file_impl->bitdepth() / bits_per_byte; }
size_t File::bytes_per_pixel() const {
return file_impl->bitdepth() / bits_per_byte;
}
DetectorType File::detector_type() const { return file_impl->detector_type(); }
} // namespace aare

View File

@ -6,10 +6,12 @@
namespace aare {
FilePtr::FilePtr(const std::filesystem::path& fname, const std::string& mode = "rb") {
FilePtr::FilePtr(const std::filesystem::path &fname,
const std::string &mode = "rb") {
fp_ = fopen(fname.c_str(), mode.c_str());
if (!fp_)
throw std::runtime_error(fmt::format("Could not open: {}", fname.c_str()));
throw std::runtime_error(
fmt::format("Could not open: {}", fname.c_str()));
}
FilePtr::FilePtr(FilePtr &&other) { std::swap(fp_, other.fp_); }
@ -24,15 +26,16 @@ FILE *FilePtr::get() { return fp_; }
ssize_t FilePtr::tell() {
auto pos = ftell(fp_);
if (pos == -1)
throw std::runtime_error(fmt::format("Error getting file position: {}", error_msg()));
throw std::runtime_error(
fmt::format("Error getting file position: {}", error_msg()));
return pos;
}
}
FilePtr::~FilePtr() {
if (fp_)
fclose(fp_); // check?
}
std::string FilePtr::error_msg(){
std::string FilePtr::error_msg() {
if (feof(fp_)) {
return "End of file reached";
}

View File

@ -1,13 +1,12 @@
#include "aare/Fit.hpp"
#include "aare/utils/task.hpp"
#include "aare/utils/par.hpp"
#include "aare/utils/task.hpp"
#include <lmcurve2.h>
#include <lmfit.hpp>
#include <thread>
#include <array>
namespace aare {
namespace func {
@ -34,8 +33,10 @@ NDArray<double, 1> pol1(NDView<double, 1> x, NDView<double, 1> par) {
return y;
}
double scurve(const double x, const double * par) {
return (par[0] + par[1] * x) + 0.5 * (1 + erf((x - par[2]) / (sqrt(2) * par[3]))) * (par[4] + par[5] * (x - par[2]));
double scurve(const double x, const double *par) {
return (par[0] + par[1] * x) +
0.5 * (1 + erf((x - par[2]) / (sqrt(2) * par[3]))) *
(par[4] + par[5] * (x - par[2]));
}
NDArray<double, 1> scurve(NDView<double, 1> x, NDView<double, 1> par) {
@ -46,8 +47,10 @@ NDArray<double, 1> scurve(NDView<double, 1> x, NDView<double, 1> par) {
return y;
}
double scurve2(const double x, const double * par) {
return (par[0] + par[1] * x) + 0.5 * (1 - erf((x - par[2]) / (sqrt(2) * par[3]))) * (par[4] + par[5] * (x - par[2]));
double scurve2(const double x, const double *par) {
return (par[0] + par[1] * x) +
0.5 * (1 - erf((x - par[2]) / (sqrt(2) * par[3]))) *
(par[4] + par[5] * (x - par[2]));
}
NDArray<double, 1> scurve2(NDView<double, 1> x, NDView<double, 1> par) {
@ -91,7 +94,8 @@ NDArray<double, 3> fit_gaus(NDView<double, 1> x, NDView<double, 3> y,
return result;
}
std::array<double, 3> gaus_init_par(const NDView<double, 1> x, const NDView<double, 1> y) {
std::array<double, 3> gaus_init_par(const NDView<double, 1> x,
const NDView<double, 1> y) {
std::array<double, 3> start_par{0, 0, 0};
auto e = std::max_element(y.begin(), y.end());
auto idx = std::distance(y.begin(), e);
@ -103,31 +107,29 @@ std::array<double, 3> gaus_init_par(const NDView<double, 1> x, const NDView<doub
// For sigma we estimate the fwhm and divide by 2.35
// assuming equally spaced x values
auto delta = x[1] - x[0];
start_par[2] =
std::count_if(y.begin(), y.end(),
[e](double val) { return val > *e / 2; }) *
delta / 2.35;
start_par[2] = std::count_if(y.begin(), y.end(),
[e](double val) { return val > *e / 2; }) *
delta / 2.35;
return start_par;
}
std::array<double, 2> pol1_init_par(const NDView<double, 1> x,
const NDView<double, 1> y) {
// Estimate the initial parameters for the fit
std::array<double, 2> start_par{0, 0};
std::array<double, 2> pol1_init_par(const NDView<double, 1> x, const NDView<double, 1> y){
// Estimate the initial parameters for the fit
std::array<double, 2> start_par{0, 0};
auto y2 = std::max_element(y.begin(), y.end());
auto x2 = x[std::distance(y.begin(), y2)];
auto y1 = std::min_element(y.begin(), y.end());
auto x1 = x[std::distance(y.begin(), y1)];
auto y2 = std::max_element(y.begin(), y.end());
auto x2 = x[std::distance(y.begin(), y2)];
auto y1 = std::min_element(y.begin(), y.end());
auto x1 = x[std::distance(y.begin(), y1)];
start_par[0] =
(*y2 - *y1) / (x2 - x1); // For amplitude we use the maximum value
start_par[1] =
*y1 - ((*y2 - *y1) / (x2 - x1)) *
x1; // For the mean we use the x value of the maximum value
return start_par;
start_par[0] =
(*y2 - *y1) / (x2 - x1); // For amplitude we use the maximum value
start_par[1] =
*y1 - ((*y2 - *y1) / (x2 - x1)) *
x1; // For the mean we use the x value of the maximum value
return start_par;
}
void fit_gaus(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_err,
@ -141,7 +143,6 @@ void fit_gaus(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_err,
"and par_out, par_err_out must have size 3");
}
// /* Collection of output parameters for status info. */
// typedef struct {
// double fnorm; /* norm of the residue vector fvec. */
@ -153,23 +154,32 @@ void fit_gaus(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_err,
// */
// } lm_status_struct;
lm_status_struct status;
par_out = gaus_init_par(x, y);
std::array<double, 9> cov{0, 0, 0, 0, 0, 0, 0 , 0 , 0};
std::array<double, 9> cov{0, 0, 0, 0, 0, 0, 0, 0, 0};
// void lmcurve2( const int n_par, double *par, double *parerr, double *covar, const int m_dat, const double *t, const double *y, const double *dy, double (*f)( const double ti, const double *par ), const lm_control_struct *control, lm_status_struct *status);
// n_par - Number of free variables. Length of parameter vector par.
// par - Parameter vector. On input, it must contain a reasonable guess. On output, it contains the solution found to minimize ||r||.
// parerr - Parameter uncertainties vector. Array of length n_par or NULL. On output, unless it or covar is NULL, it contains the weighted parameter uncertainties for the found parameters.
// covar - Covariance matrix. Array of length n_par * n_par or NULL. On output, unless it is NULL, it contains the covariance matrix.
// m_dat - Number of data points. Length of vectors t, y, dy. Must statisfy n_par <= m_dat.
// t - Array of length m_dat. Contains the abcissae (time, or "x") for which function f will be evaluated.
// y - Array of length m_dat. Contains the ordinate values that shall be fitted.
// dy - Array of length m_dat. Contains the standard deviations of the values y.
// f - A user-supplied parametric function f(ti;par).
// control - Parameter collection for tuning the fit procedure. In most cases, the default &lm_control_double is adequate. If f is only computed with single-precision accuracy, &lm_control_float should be used. Parameters are explained in lmmin2(3).
// status - A record used to return information about the minimization process: For details, see lmmin2(3).
// void lmcurve2( const int n_par, double *par, double *parerr, double
// *covar, const int m_dat, const double *t, const double *y, const double
// *dy, double (*f)( const double ti, const double *par ), const
// lm_control_struct *control, lm_status_struct *status); n_par - Number of
// free variables. Length of parameter vector par. par - Parameter vector.
// On input, it must contain a reasonable guess. On output, it contains the
// solution found to minimize ||r||. parerr - Parameter uncertainties
// vector. Array of length n_par or NULL. On output, unless it or covar is
// NULL, it contains the weighted parameter uncertainties for the found
// parameters. covar - Covariance matrix. Array of length n_par * n_par or
// NULL. On output, unless it is NULL, it contains the covariance matrix.
// m_dat - Number of data points. Length of vectors t, y, dy. Must statisfy
// n_par <= m_dat. t - Array of length m_dat. Contains the abcissae (time,
// or "x") for which function f will be evaluated. y - Array of length
// m_dat. Contains the ordinate values that shall be fitted. dy - Array of
// length m_dat. Contains the standard deviations of the values y. f - A
// user-supplied parametric function f(ti;par). control - Parameter
// collection for tuning the fit procedure. In most cases, the default
// &lm_control_double is adequate. If f is only computed with
// single-precision accuracy, &lm_control_float should be used. Parameters
// are explained in lmmin2(3). status - A record used to return information
// about the minimization process: For details, see lmmin2(3).
lmcurve2(par_out.size(), par_out.data(), par_err_out.data(), cov.data(),
x.size(), x.data(), y.data(), y_err.data(), aare::func::gaus,
@ -178,12 +188,14 @@ void fit_gaus(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_err,
// Calculate chi2
chi2 = 0;
for (ssize_t i = 0; i < y.size(); i++) {
chi2 += std::pow((y(i) - func::gaus(x(i), par_out.data())) / y_err(i), 2);
chi2 +=
std::pow((y(i) - func::gaus(x(i), par_out.data())) / y_err(i), 2);
}
}
void fit_gaus(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_err,
NDView<double, 3> par_out, NDView<double, 3> par_err_out, NDView<double, 2> chi2_out,
NDView<double, 3> par_out, NDView<double, 3> par_err_out,
NDView<double, 2> chi2_out,
int n_threads) {
@ -197,10 +209,9 @@ void fit_gaus(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_err,
{par_out.shape(2)});
NDView<double, 1> par_err_out_view(&par_err_out(row, col, 0),
{par_err_out.shape(2)});
fit_gaus(x, y_view, y_err_view, par_out_view, par_err_out_view,
chi2_out(row, col));
}
}
};
@ -210,7 +221,8 @@ void fit_gaus(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_err,
}
void fit_pol1(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_err,
NDView<double, 1> par_out, NDView<double, 1> par_err_out, double& chi2) {
NDView<double, 1> par_out, NDView<double, 1> par_err_out,
double &chi2) {
// Check that we have the correct sizes
if (y.size() != x.size() || y.size() != y_err.size() ||
@ -230,13 +242,14 @@ void fit_pol1(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_err,
// Calculate chi2
chi2 = 0;
for (ssize_t i = 0; i < y.size(); i++) {
chi2 += std::pow((y(i) - func::pol1(x(i), par_out.data())) / y_err(i), 2);
chi2 +=
std::pow((y(i) - func::pol1(x(i), par_out.data())) / y_err(i), 2);
}
}
void fit_pol1(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_err,
NDView<double, 3> par_out, NDView<double, 3> par_err_out, NDView<double, 2> chi2_out,
int n_threads) {
NDView<double, 3> par_out, NDView<double, 3> par_err_out,
NDView<double, 2> chi2_out, int n_threads) {
auto process = [&](ssize_t first_row, ssize_t last_row) {
for (ssize_t row = first_row; row < last_row; row++) {
@ -249,15 +262,14 @@ void fit_pol1(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_err,
NDView<double, 1> par_err_out_view(&par_err_out(row, col, 0),
{par_err_out.shape(2)});
fit_pol1(x, y_view, y_err_view, par_out_view, par_err_out_view, chi2_out(row, col));
fit_pol1(x, y_view, y_err_view, par_out_view, par_err_out_view,
chi2_out(row, col));
}
}
};
auto tasks = split_task(0, y.shape(0), n_threads);
RunInParallel(process, tasks);
}
NDArray<double, 1> fit_pol1(NDView<double, 1> x, NDView<double, 1> y) {
@ -300,27 +312,29 @@ NDArray<double, 3> fit_pol1(NDView<double, 1> x, NDView<double, 3> y,
// ~~ S-CURVES ~~
// SCURVE --
std::array<double, 6> scurve_init_par(const NDView<double, 1> x, const NDView<double, 1> y){
// Estimate the initial parameters for the fit
std::array<double, 6> start_par{0, 0, 0, 0, 0, 0};
std::array<double, 6> scurve_init_par(const NDView<double, 1> x,
const NDView<double, 1> y) {
// Estimate the initial parameters for the fit
std::array<double, 6> start_par{0, 0, 0, 0, 0, 0};
auto ymax = std::max_element(y.begin(), y.end());
auto ymin = std::min_element(y.begin(), y.end());
start_par[4] = *ymin + (*ymax - *ymin) / 2;
// Find the first x where the corresponding y value is above the threshold (start_par[4])
for (ssize_t i = 0; i < y.size(); ++i) {
if (y[i] >= start_par[4]) {
start_par[2] = x[i];
break; // Exit the loop after finding the first valid x
}
auto ymax = std::max_element(y.begin(), y.end());
auto ymin = std::min_element(y.begin(), y.end());
start_par[4] = *ymin + (*ymax - *ymin) / 2;
// Find the first x where the corresponding y value is above the threshold
// (start_par[4])
for (ssize_t i = 0; i < y.size(); ++i) {
if (y[i] >= start_par[4]) {
start_par[2] = x[i];
break; // Exit the loop after finding the first valid x
}
}
start_par[3] = 2 * sqrt(start_par[2]);
start_par[0] = 100;
start_par[1] = 0.25;
start_par[5] = 1;
return start_par;
start_par[3] = 2 * sqrt(start_par[2]);
start_par[0] = 100;
start_par[1] = 0.25;
start_par[5] = 1;
return start_par;
}
// - No error
@ -334,7 +348,8 @@ NDArray<double, 1> fit_scurve(NDView<double, 1> x, NDView<double, 1> y) {
return result;
}
NDArray<double, 3> fit_scurve(NDView<double, 1> x, NDView<double, 3> y, int n_threads) {
NDArray<double, 3> fit_scurve(NDView<double, 1> x, NDView<double, 3> y,
int n_threads) {
NDArray<double, 3> result({y.shape(0), y.shape(1), 6}, 0);
auto process = [&x, &y, &result](ssize_t first_row, ssize_t last_row) {
@ -358,8 +373,9 @@ NDArray<double, 3> fit_scurve(NDView<double, 1> x, NDView<double, 3> y, int n_th
}
// - Error
void fit_scurve(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_err,
NDView<double, 1> par_out, NDView<double, 1> par_err_out, double& chi2) {
void fit_scurve(NDView<double, 1> x, NDView<double, 1> y,
NDView<double, 1> y_err, NDView<double, 1> par_out,
NDView<double, 1> par_err_out, double &chi2) {
// Check that we have the correct sizes
if (y.size() != x.size() || y.size() != y_err.size() ||
@ -380,13 +396,15 @@ void fit_scurve(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_er
// Calculate chi2
chi2 = 0;
for (ssize_t i = 0; i < y.size(); i++) {
chi2 += std::pow((y(i) - func::pol1(x(i), par_out.data())) / y_err(i), 2);
chi2 +=
std::pow((y(i) - func::pol1(x(i), par_out.data())) / y_err(i), 2);
}
}
void fit_scurve(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_err,
NDView<double, 3> par_out, NDView<double, 3> par_err_out, NDView<double, 2> chi2_out,
int n_threads) {
void fit_scurve(NDView<double, 1> x, NDView<double, 3> y,
NDView<double, 3> y_err, NDView<double, 3> par_out,
NDView<double, 3> par_err_out, NDView<double, 2> chi2_out,
int n_threads) {
auto process = [&](ssize_t first_row, ssize_t last_row) {
for (ssize_t row = first_row; row < last_row; row++) {
@ -399,40 +417,41 @@ void fit_scurve(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_er
NDView<double, 1> par_err_out_view(&par_err_out(row, col, 0),
{par_err_out.shape(2)});
fit_scurve(x, y_view, y_err_view, par_out_view, par_err_out_view, chi2_out(row, col));
fit_scurve(x, y_view, y_err_view, par_out_view,
par_err_out_view, chi2_out(row, col));
}
}
};
auto tasks = split_task(0, y.shape(0), n_threads);
RunInParallel(process, tasks);
}
// SCURVE2 ---
std::array<double, 6> scurve2_init_par(const NDView<double, 1> x, const NDView<double, 1> y){
// Estimate the initial parameters for the fit
std::array<double, 6> start_par{0, 0, 0, 0, 0, 0};
std::array<double, 6> scurve2_init_par(const NDView<double, 1> x,
const NDView<double, 1> y) {
// Estimate the initial parameters for the fit
std::array<double, 6> start_par{0, 0, 0, 0, 0, 0};
auto ymax = std::max_element(y.begin(), y.end());
auto ymin = std::min_element(y.begin(), y.end());
start_par[4] = *ymin + (*ymax - *ymin) / 2;
// Find the first x where the corresponding y value is above the threshold (start_par[4])
for (ssize_t i = 0; i < y.size(); ++i) {
if (y[i] <= start_par[4]) {
start_par[2] = x[i];
break; // Exit the loop after finding the first valid x
}
auto ymax = std::max_element(y.begin(), y.end());
auto ymin = std::min_element(y.begin(), y.end());
start_par[4] = *ymin + (*ymax - *ymin) / 2;
// Find the first x where the corresponding y value is above the threshold
// (start_par[4])
for (ssize_t i = 0; i < y.size(); ++i) {
if (y[i] <= start_par[4]) {
start_par[2] = x[i];
break; // Exit the loop after finding the first valid x
}
}
start_par[3] = 2 * sqrt(start_par[2]);
start_par[0] = 100;
start_par[1] = 0.25;
start_par[5] = -1;
return start_par;
start_par[3] = 2 * sqrt(start_par[2]);
start_par[0] = 100;
start_par[1] = 0.25;
start_par[5] = -1;
return start_par;
}
// - No error
@ -446,7 +465,8 @@ NDArray<double, 1> fit_scurve2(NDView<double, 1> x, NDView<double, 1> y) {
return result;
}
NDArray<double, 3> fit_scurve2(NDView<double, 1> x, NDView<double, 3> y, int n_threads) {
NDArray<double, 3> fit_scurve2(NDView<double, 1> x, NDView<double, 3> y,
int n_threads) {
NDArray<double, 3> result({y.shape(0), y.shape(1), 6}, 0);
auto process = [&x, &y, &result](ssize_t first_row, ssize_t last_row) {
@ -470,8 +490,9 @@ NDArray<double, 3> fit_scurve2(NDView<double, 1> x, NDView<double, 3> y, int n_t
}
// - Error
void fit_scurve2(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_err,
NDView<double, 1> par_out, NDView<double, 1> par_err_out, double& chi2) {
void fit_scurve2(NDView<double, 1> x, NDView<double, 1> y,
NDView<double, 1> y_err, NDView<double, 1> par_out,
NDView<double, 1> par_err_out, double &chi2) {
// Check that we have the correct sizes
if (y.size() != x.size() || y.size() != y_err.size() ||
@ -492,13 +513,15 @@ void fit_scurve2(NDView<double, 1> x, NDView<double, 1> y, NDView<double, 1> y_e
// Calculate chi2
chi2 = 0;
for (ssize_t i = 0; i < y.size(); i++) {
chi2 += std::pow((y(i) - func::pol1(x(i), par_out.data())) / y_err(i), 2);
chi2 +=
std::pow((y(i) - func::pol1(x(i), par_out.data())) / y_err(i), 2);
}
}
void fit_scurve2(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_err,
NDView<double, 3> par_out, NDView<double, 3> par_err_out, NDView<double, 2> chi2_out,
int n_threads) {
void fit_scurve2(NDView<double, 1> x, NDView<double, 3> y,
NDView<double, 3> y_err, NDView<double, 3> par_out,
NDView<double, 3> par_err_out, NDView<double, 2> chi2_out,
int n_threads) {
auto process = [&](ssize_t first_row, ssize_t last_row) {
for (ssize_t row = first_row; row < last_row; row++) {
@ -511,15 +534,14 @@ void fit_scurve2(NDView<double, 1> x, NDView<double, 3> y, NDView<double, 3> y_e
NDView<double, 1> par_err_out_view(&par_err_out(row, col, 0),
{par_err_out.shape(2)});
fit_scurve2(x, y_view, y_err_view, par_out_view, par_err_out_view, chi2_out(row, col));
fit_scurve2(x, y_view, y_err_view, par_out_view,
par_err_out_view, chi2_out(row, col));
}
}
};
auto tasks = split_task(0, y.shape(0), n_threads);
RunInParallel(process, tasks);
}
} // namespace aare

View File

@ -29,8 +29,7 @@ uint64_t Frame::size() const { return m_rows * m_cols; }
size_t Frame::bytes() const { return m_rows * m_cols * m_dtype.bytes(); }
std::byte *Frame::data() const { return m_data; }
std::byte *Frame::pixel_ptr(uint32_t row, uint32_t col) const{
std::byte *Frame::pixel_ptr(uint32_t row, uint32_t col) const {
if ((row >= m_rows) || (col >= m_cols)) {
std::cerr << "Invalid row or column index" << '\n';
return nullptr;
@ -38,7 +37,6 @@ std::byte *Frame::pixel_ptr(uint32_t row, uint32_t col) const{
return m_data + (row * m_cols + col) * (m_dtype.bytes());
}
Frame &Frame::operator=(Frame &&other) noexcept {
if (this == &other) {
return *this;
@ -70,5 +68,4 @@ Frame Frame::clone() const {
return frame;
}
} // namespace aare

View File

@ -65,7 +65,8 @@ TEST_CASE("Set a value in a 64 bit frame") {
// only the value we did set should be non-zero
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
uint64_t *data = reinterpret_cast<uint64_t *>(frame.pixel_ptr(i, j));
uint64_t *data =
reinterpret_cast<uint64_t *>(frame.pixel_ptr(i, j));
REQUIRE(data != nullptr);
if (i == 5 && j == 7) {
REQUIRE(*data == value);
@ -150,4 +151,3 @@ TEST_CASE("test explicit copy constructor") {
REQUIRE(frame2.bytes() == rows * cols * bitdepth / 8);
REQUIRE(frame2.data() != data);
}

View File

@ -19,16 +19,15 @@ JungfrauDataFile::JungfrauDataFile(const std::filesystem::path &fname) {
open_file(m_current_file_index);
}
// FileInterface
Frame JungfrauDataFile::read_frame(){
Frame JungfrauDataFile::read_frame() {
Frame f(rows(), cols(), Dtype::UINT16);
read_into(reinterpret_cast<std::byte *>(f.data()), nullptr);
return f;
}
Frame JungfrauDataFile::read_frame(size_t frame_number){
Frame JungfrauDataFile::read_frame(size_t frame_number) {
seek(frame_number);
Frame f(rows(), cols(), Dtype::UINT16);
read_into(reinterpret_cast<std::byte *>(f.data()), nullptr);
@ -37,7 +36,7 @@ Frame JungfrauDataFile::read_frame(size_t frame_number){
std::vector<Frame> JungfrauDataFile::read_n(size_t n_frames) {
std::vector<Frame> frames;
for(size_t i = 0; i < n_frames; ++i){
for (size_t i = 0; i < n_frames; ++i) {
frames.push_back(read_frame());
}
return frames;
@ -48,7 +47,7 @@ void JungfrauDataFile::read_into(std::byte *image_buf) {
}
void JungfrauDataFile::read_into(std::byte *image_buf, size_t n_frames) {
read_into(image_buf, n_frames, nullptr);
}
}
size_t JungfrauDataFile::frame_number(size_t frame_index) {
seek(frame_index);
@ -59,7 +58,9 @@ std::array<ssize_t, 2> JungfrauDataFile::shape() const {
return {static_cast<ssize_t>(rows()), static_cast<ssize_t>(cols())};
}
DetectorType JungfrauDataFile::detector_type() const { return DetectorType::Jungfrau; }
DetectorType JungfrauDataFile::detector_type() const {
return DetectorType::Jungfrau;
}
std::string JungfrauDataFile::base_name() const { return m_base_name; }
@ -195,22 +196,23 @@ void JungfrauDataFile::read_into(std::byte *image_buf, size_t n_frames,
JungfrauDataHeader *header) {
if (header) {
for (size_t i = 0; i < n_frames; ++i)
read_into(image_buf + i * m_bytes_per_frame, header + i);
}else{
read_into(image_buf + i * m_bytes_per_frame, header + i);
} else {
for (size_t i = 0; i < n_frames; ++i)
read_into(image_buf + i * m_bytes_per_frame, nullptr);
}
}
void JungfrauDataFile::read_into(NDArray<uint16_t>* image, JungfrauDataHeader* header) {
if(image->shape()!=shape()){
throw std::runtime_error(LOCATION +
"Image shape does not match file size: " + std::to_string(rows()) + "x" + std::to_string(cols()));
void JungfrauDataFile::read_into(NDArray<uint16_t> *image,
JungfrauDataHeader *header) {
if (image->shape() != shape()) {
throw std::runtime_error(
LOCATION + "Image shape does not match file size: " +
std::to_string(rows()) + "x" + std::to_string(cols()));
}
read_into(reinterpret_cast<std::byte *>(image->data()), header);
}
JungfrauDataHeader JungfrauDataFile::read_header() {
JungfrauDataHeader header;
if (auto rc = fread(&header, 1, sizeof(header), m_fp.get());

View File

@ -1,21 +1,21 @@
#include "aare/JungfrauDataFile.hpp"
#include <catch2/catch_test_macros.hpp>
#include "test_config.hpp"
#include <catch2/catch_test_macros.hpp>
using aare::JungfrauDataFile;
using aare::JungfrauDataHeader;
TEST_CASE("Open a Jungfrau data file", "[.files]") {
//we know we have 4 files with 7, 7, 7, and 3 frames
//firs frame number if 1 and the bunch id is frame_number**2
//so we can check the header
// we know we have 4 files with 7, 7, 7, and 3 frames
// firs frame number if 1 and the bunch id is frame_number**2
// so we can check the header
auto fpath = test_data_path() / "dat" / "AldoJF500k_000000.dat";
REQUIRE(std::filesystem::exists(fpath));
JungfrauDataFile f(fpath);
REQUIRE(f.rows() == 512);
REQUIRE(f.cols() == 1024);
REQUIRE(f.bytes_per_frame() == 1048576);
REQUIRE(f.bytes_per_frame() == 1048576);
REQUIRE(f.pixels_per_frame() == 524288);
REQUIRE(f.bytes_per_pixel() == 2);
REQUIRE(f.bitdepth() == 16);
@ -25,7 +25,7 @@ TEST_CASE("Open a Jungfrau data file", "[.files]") {
REQUIRE(f.total_frames() == 24);
REQUIRE(f.current_file() == fpath);
//Check that the frame number and buch id is read correctly
// Check that the frame number and buch id is read correctly
for (size_t i = 0; i < 24; ++i) {
JungfrauDataHeader header;
aare::NDArray<uint16_t> image(f.shape());
@ -37,65 +37,64 @@ TEST_CASE("Open a Jungfrau data file", "[.files]") {
}
}
TEST_CASE("Seek in a JungfrauDataFile", "[.files]"){
TEST_CASE("Seek in a JungfrauDataFile", "[.files]") {
auto fpath = test_data_path() / "dat" / "AldoJF65k_000000.dat";
REQUIRE(std::filesystem::exists(fpath));
JungfrauDataFile f(fpath);
//The file should have 113 frames
// The file should have 113 frames
f.seek(19);
REQUIRE(f.tell() == 19);
auto h = f.read_header();
REQUIRE(h.framenum == 19+1);
REQUIRE(h.framenum == 19 + 1);
//Reading again does not change the file pointer
// Reading again does not change the file pointer
auto h2 = f.read_header();
REQUIRE(h2.framenum == 19+1);
REQUIRE(h2.framenum == 19 + 1);
f.seek(59);
REQUIRE(f.tell() == 59);
auto h3 = f.read_header();
REQUIRE(h3.framenum == 59+1);
REQUIRE(h3.framenum == 59 + 1);
JungfrauDataHeader h4;
aare::NDArray<uint16_t> image(f.shape());
f.read_into(&image, &h4);
REQUIRE(h4.framenum == 59+1);
REQUIRE(h4.framenum == 59 + 1);
//now we should be on the next frame
// now we should be on the next frame
REQUIRE(f.tell() == 60);
REQUIRE(f.read_header().framenum == 60+1);
REQUIRE(f.read_header().framenum == 60 + 1);
REQUIRE_THROWS(f.seek(86356)); //out of range
REQUIRE_THROWS(f.seek(86356)); // out of range
}
TEST_CASE("Open a Jungfrau data file with non zero file index", "[.files]"){
TEST_CASE("Open a Jungfrau data file with non zero file index", "[.files]") {
auto fpath = test_data_path() / "dat" / "AldoJF65k_000003.dat";
REQUIRE(std::filesystem::exists(fpath));
JungfrauDataFile f(fpath);
//18 files per data file, opening the 3rd file we ignore the first 3
REQUIRE(f.total_frames() == 113-18*3);
// 18 files per data file, opening the 3rd file we ignore the first 3
REQUIRE(f.total_frames() == 113 - 18 * 3);
REQUIRE(f.tell() == 0);
//Frame numbers start at 1 in the first file
REQUIRE(f.read_header().framenum == 18*3+1);
// Frame numbers start at 1 in the first file
REQUIRE(f.read_header().framenum == 18 * 3 + 1);
// moving relative to the third file
f.seek(5);
REQUIRE(f.read_header().framenum == 18*3+1+5);
REQUIRE(f.read_header().framenum == 18 * 3 + 1 + 5);
// ignoring the first 3 files
REQUIRE(f.n_files() == 4);
REQUIRE(f.current_file().stem() == "AldoJF65k_000003");
}
TEST_CASE("Read into throws if size doesn't match", "[.files]"){
TEST_CASE("Read into throws if size doesn't match", "[.files]") {
auto fpath = test_data_path() / "dat" / "AldoJF65k_000000.dat";
REQUIRE(std::filesystem::exists(fpath));
@ -109,6 +108,4 @@ TEST_CASE("Read into throws if size doesn't match", "[.files]"){
REQUIRE_THROWS(f.read_into(&image));
REQUIRE(f.tell() == 0);
}

View File

@ -35,7 +35,7 @@ TEST_CASE("Construct from an NDView") {
}
}
TEST_CASE("3D NDArray from NDView"){
TEST_CASE("3D NDArray from NDView") {
std::vector<int> data(27);
std::iota(data.begin(), data.end(), 0);
NDView<int, 3> view(data.data(), Shape<3>{3, 3, 3});
@ -44,9 +44,9 @@ TEST_CASE("3D NDArray from NDView"){
REQUIRE(image.size() == view.size());
REQUIRE(image.data() != view.data());
for(ssize_t i=0; i<image.shape(0); i++){
for(ssize_t j=0; j<image.shape(1); j++){
for(ssize_t k=0; k<image.shape(2); k++){
for (ssize_t i = 0; i < image.shape(0); i++) {
for (ssize_t j = 0; j < image.shape(1); j++) {
for (ssize_t k = 0; k < image.shape(2); k++) {
REQUIRE(image(i, j, k) == view(i, j, k));
}
}
@ -132,7 +132,7 @@ TEST_CASE("Elementwise multiplication of 3D image") {
NDArray<int> MultiplyNDArrayUsingOperator(NDArray<int> &a, NDArray<int> &b) {
// return a * a * b * b;
NDArray<int>c = a*b;
NDArray<int> c = a * b;
return c;
}
@ -162,7 +162,6 @@ NDArray<int> AddNDArrayUsingIndex(NDArray<int> &a, NDArray<int> &b) {
return res;
}
TEST_CASE("Compare two images") {
NDArray<int> a;
NDArray<int> b;
@ -222,7 +221,6 @@ TEST_CASE("Bitwise and on data") {
REQUIRE(a(2) == 384);
}
TEST_CASE("Elementwise operations on images") {
std::array<ssize_t, 2> shape{5, 5};
double a_val = 3.0;
@ -258,7 +256,8 @@ TEST_CASE("Elementwise operations on images") {
NDArray<double> A(shape, a_val);
NDArray<double> B(shape, b_val);
NDArray<double> C = A - B;
// auto C = A - B; // This works but the result is a lazy ArraySub object
// auto C = A - B; // This works but the result is a lazy ArraySub
// object
// Value of C matches
for (uint32_t i = 0; i < C.size(); ++i) {
@ -282,7 +281,8 @@ TEST_CASE("Elementwise operations on images") {
SECTION("Multiply two images") {
NDArray<double> A(shape, a_val);
NDArray<double> B(shape, b_val);
// auto C = A * B; // This works but the result is a lazy ArrayMul object
// auto C = A * B; // This works but the result is a lazy ArrayMul
// object
NDArray<double> C = A * B;
// Value of C matches
@ -307,7 +307,8 @@ TEST_CASE("Elementwise operations on images") {
SECTION("Divide two images") {
NDArray<double> A(shape, a_val);
NDArray<double> B(shape, b_val);
// auto C = A / B; // This works but the result is a lazy ArrayDiv object
// auto C = A / B; // This works but the result is a lazy ArrayDiv
// object
NDArray<double> C = A / B;
// Value of C matches

View File

@ -2,8 +2,8 @@
#include <catch2/catch_test_macros.hpp>
#include <iostream>
#include <vector>
#include <numeric>
#include <vector>
using aare::NDView;
using aare::Shape;
@ -151,8 +151,10 @@ TEST_CASE("divide with another span") {
std::vector<int> vec1{3, 2, 1};
std::vector<int> result{3, 6, 3};
NDView<int, 1> data0(vec0.data(), Shape<1>{static_cast<ssize_t>(vec0.size())});
NDView<int, 1> data1(vec1.data(), Shape<1>{static_cast<ssize_t>(vec1.size())});
NDView<int, 1> data0(vec0.data(),
Shape<1>{static_cast<ssize_t>(vec0.size())});
NDView<int, 1> data1(vec1.data(),
Shape<1>{static_cast<ssize_t>(vec1.size())});
data0 /= data1;
@ -181,8 +183,7 @@ TEST_CASE("compare two views") {
REQUIRE((view1 == view2));
}
TEST_CASE("Create a view over a vector"){
TEST_CASE("Create a view over a vector") {
std::vector<int> vec(12);
std::iota(vec.begin(), vec.end(), 0);
auto v = aare::make_view(vec);

View File

@ -4,16 +4,16 @@
namespace aare {
NumpyFile::NumpyFile(const std::filesystem::path &fname, const std::string &mode, FileConfig cfg) {
NumpyFile::NumpyFile(const std::filesystem::path &fname,
const std::string &mode, FileConfig cfg) {
// TODO! add opts to constructor
m_mode = mode;
if (mode == "r") {
fp = fopen(fname.string().c_str(), "rb");
if (!fp) {
throw std::runtime_error(fmt::format("Could not open: {} for reading", fname.string()));
throw std::runtime_error(
fmt::format("Could not open: {} for reading", fname.string()));
}
load_metadata();
} else if (mode == "w") {
@ -24,11 +24,15 @@ NumpyFile::NumpyFile(const std::filesystem::path &fname, const std::string &mode
m_header.shape = {0, cfg.rows, cfg.cols};
fp = fopen(fname.string().c_str(), "wb");
if (!fp) {
throw std::runtime_error(fmt::format("Could not open: {} for reading", fname.string()));
throw std::runtime_error(
fmt::format("Could not open: {} for reading", fname.string()));
}
initial_header_len = aare::NumpyHelpers::write_header(std::filesystem::path(fname.c_str()), m_header);
initial_header_len = aare::NumpyHelpers::write_header(
std::filesystem::path(fname.c_str()), m_header);
}
m_pixels_per_frame = std::accumulate(m_header.shape.begin() + 1, m_header.shape.end(), 1, std::multiplies<>());
m_pixels_per_frame =
std::accumulate(m_header.shape.begin() + 1, m_header.shape.end(), 1,
std::multiplies<>());
m_bytes_per_frame = m_header.dtype.bitdepth() / 8 * m_pixels_per_frame;
}
@ -63,7 +67,8 @@ void NumpyFile::get_frame_into(size_t frame_number, std::byte *image_buf) {
if (frame_number > m_header.shape[0]) {
throw std::invalid_argument("Frame number out of range");
}
if (fseek(fp, header_size + frame_number * m_bytes_per_frame, SEEK_SET)) // NOLINT
if (fseek(fp, header_size + frame_number * m_bytes_per_frame,
SEEK_SET)) // NOLINT
throw std::runtime_error("Could not seek to frame");
size_t const rc = fread(image_buf, m_bytes_per_frame, 1, fp);
@ -113,7 +118,8 @@ NumpyFile::~NumpyFile() noexcept {
// write header
size_t const rc = fwrite(header_str.c_str(), header_str.size(), 1, fp);
if (rc != 1) {
std::cout << "Error writing header to numpy file in destructor" << std::endl;
std::cout << "Error writing header to numpy file in destructor"
<< std::endl;
}
}
@ -140,8 +146,10 @@ void NumpyFile::load_metadata() {
}
// read version
rc = fread(reinterpret_cast<char *>(&major_ver_), sizeof(major_ver_), 1, fp);
rc += fread(reinterpret_cast<char *>(&minor_ver_), sizeof(minor_ver_), 1, fp);
rc =
fread(reinterpret_cast<char *>(&major_ver_), sizeof(major_ver_), 1, fp);
rc +=
fread(reinterpret_cast<char *>(&minor_ver_), sizeof(minor_ver_), 1, fp);
if (rc != 2) {
throw std::runtime_error("Error reading numpy version");
}
@ -159,7 +167,8 @@ void NumpyFile::load_metadata() {
if (rc != 1) {
throw std::runtime_error("Error reading header length");
}
header_size = aare::NumpyHelpers::magic_string_length + 2 + header_len_size + header_len;
header_size = aare::NumpyHelpers::magic_string_length + 2 +
header_len_size + header_len;
if (header_size % 16 != 0) {
fmt::print("Warning: header length is not a multiple of 16\n");
}

View File

@ -1,8 +1,8 @@
#include "aare/NumpyFile.hpp"
#include "aare/NDArray.hpp"
#include <catch2/catch_test_macros.hpp>
#include "test_config.hpp"
#include <catch2/catch_test_macros.hpp>
using aare::Dtype;
using aare::NumpyFile;
@ -23,7 +23,7 @@ TEST_CASE("Read a 1D numpy file with int32 data type", "[.integration]") {
REQUIRE(data(i) == i);
}
}
TEST_CASE("Read a 3D numpy file with np.double data type", "[.integration]") {
auto fpath = test_data_path() / "numpy" / "test_3d_double.npy";

View File

@ -29,7 +29,8 @@ namespace aare {
std::string NumpyHeader::to_string() const {
std::stringstream sstm;
sstm << "dtype: " << dtype.to_string() << ", fortran_order: " << fortran_order << ' ';
sstm << "dtype: " << dtype.to_string()
<< ", fortran_order: " << fortran_order << ' ';
sstm << "shape: (";
for (auto item : shape)
sstm << item << ',';
@ -37,10 +38,10 @@ std::string NumpyHeader::to_string() const {
return sstm.str();
}
namespace NumpyHelpers {
std::unordered_map<std::string, std::string> parse_dict(std::string in, const std::vector<std::string> &keys) {
std::unordered_map<std::string, std::string>
parse_dict(std::string in, const std::vector<std::string> &keys) {
std::unordered_map<std::string, std::string> map;
if (keys.empty())
return map;
@ -100,7 +101,8 @@ aare::Dtype parse_descr(std::string typestring) {
constexpr char little_endian_char = '<';
constexpr char big_endian_char = '>';
constexpr char no_endian_char = '|';
constexpr std::array<char, 3> endian_chars = {little_endian_char, big_endian_char, no_endian_char};
constexpr std::array<char, 3> endian_chars = {
little_endian_char, big_endian_char, no_endian_char};
constexpr std::array<char, 4> numtype_chars = {'f', 'i', 'u', 'c'};
const char byteorder_c = typestring[0];
@ -139,7 +141,9 @@ std::string get_value_from_map(const std::string &mapstr) {
return trim(tmp);
}
bool is_digits(const std::string &str) { return std::all_of(str.begin(), str.end(), ::isdigit); }
bool is_digits(const std::string &str) {
return std::all_of(str.begin(), str.end(), ::isdigit);
}
std::vector<std::string> parse_tuple(std::string in) {
std::vector<std::string> v;
@ -215,20 +219,25 @@ inline std::string write_boolean(bool b) {
return "False";
}
inline std::string write_header_dict(const std::string &descr, bool fortran_order, const std::vector<size_t> &shape) {
inline std::string write_header_dict(const std::string &descr,
bool fortran_order,
const std::vector<size_t> &shape) {
std::string const s_fortran_order = write_boolean(fortran_order);
std::string const shape_s = write_tuple(shape);
return "{'descr': '" + descr + "', 'fortran_order': " + s_fortran_order + ", 'shape': " + shape_s + ", }";
return "{'descr': '" + descr + "', 'fortran_order': " + s_fortran_order +
", 'shape': " + shape_s + ", }";
}
size_t write_header(const std::filesystem::path &fname, const NumpyHeader &header) {
size_t write_header(const std::filesystem::path &fname,
const NumpyHeader &header) {
std::ofstream out(fname, std::ios::binary | std::ios::out);
return write_header(out, header);
}
size_t write_header(std::ostream &out, const NumpyHeader &header) {
std::string const header_dict = write_header_dict(header.dtype.to_string(), header.fortran_order, header.shape);
std::string const header_dict = write_header_dict(
header.dtype.to_string(), header.fortran_order, header.shape);
size_t length = magic_string_length + 2 + 2 + header_dict.length() + 1;
@ -247,17 +256,22 @@ size_t write_header(std::ostream &out, const NumpyHeader &header) {
// write header length
if (version_major == 1 && version_minor == 0) {
auto header_len = static_cast<uint16_t>(header_dict.length() + padding.length() + 1);
auto header_len =
static_cast<uint16_t>(header_dict.length() + padding.length() + 1);
std::array<uint8_t, 2> header_len_le16{static_cast<uint8_t>((header_len >> 0) & 0xff),
static_cast<uint8_t>((header_len >> 8) & 0xff)};
std::array<uint8_t, 2> header_len_le16{
static_cast<uint8_t>((header_len >> 0) & 0xff),
static_cast<uint8_t>((header_len >> 8) & 0xff)};
out.write(reinterpret_cast<char *>(header_len_le16.data()), 2);
} else {
auto header_len = static_cast<uint32_t>(header_dict.length() + padding.length() + 1);
auto header_len =
static_cast<uint32_t>(header_dict.length() + padding.length() + 1);
std::array<uint8_t, 4> header_len_le32{
static_cast<uint8_t>((header_len >> 0) & 0xff), static_cast<uint8_t>((header_len >> 8) & 0xff),
static_cast<uint8_t>((header_len >> 16) & 0xff), static_cast<uint8_t>((header_len >> 24) & 0xff)};
static_cast<uint8_t>((header_len >> 0) & 0xff),
static_cast<uint8_t>((header_len >> 8) & 0xff),
static_cast<uint8_t>((header_len >> 16) & 0xff),
static_cast<uint8_t>((header_len >> 24) & 0xff)};
out.write(reinterpret_cast<char *>(header_len_le32.data()), 4);
}

View File

@ -19,7 +19,9 @@ TEST_CASE("Check for quotes and return stripped string") {
REQUIRE(parse_str("''") == "");
}
TEST_CASE("parsing a string without quotes throws") { REQUIRE_THROWS(parse_str("hej")); }
TEST_CASE("parsing a string without quotes throws") {
REQUIRE_THROWS(parse_str("hej"));
}
TEST_CASE("trim whitespace") {
REQUIRE(trim(" hej ") == "hej");
@ -53,7 +55,8 @@ TEST_CASE("is element in array") {
}
TEST_CASE("Parse numpy dict") {
std::string in = "{'descr': '<f4', 'fortran_order': False, 'shape': (3, 4)}";
std::string in =
"{'descr': '<f4', 'fortran_order': False, 'shape': (3, 4)}";
std::vector<std::string> keys{"descr", "fortran_order", "shape"};
auto map = parse_dict(in, keys);
REQUIRE(map["descr"] == "'<f4'");

View File

@ -1,8 +1,7 @@
#include "aare/Pedestal.hpp"
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <chrono>
#include <random>
@ -58,7 +57,8 @@ TEST_CASE("test pedestal push") {
if (k < 5) {
REQUIRE(pedestal.cur_samples()(i, j) == k + 1);
REQUIRE(pedestal.get_sum()(i, j) == (k + 1) * (i + j));
REQUIRE(pedestal.get_sum2()(i, j) == (k + 1) * (i + j) * (i + j));
REQUIRE(pedestal.get_sum2()(i, j) ==
(k + 1) * (i + j) * (i + j));
} else {
REQUIRE(pedestal.cur_samples()(i, j) == 5);
REQUIRE(pedestal.get_sum()(i, j) == 5 * (i + j));
@ -95,9 +95,12 @@ TEST_CASE("test pedestal with normal distribution") {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
REQUIRE_THAT(mean(i, j), Catch::Matchers::WithinAbs(MEAN, MEAN * TOLERANCE));
REQUIRE_THAT(variance(i, j), Catch::Matchers::WithinAbs(VAR, VAR * TOLERANCE));
REQUIRE_THAT(standard_deviation(i, j), Catch::Matchers::WithinAbs(STD, STD * TOLERANCE));
REQUIRE_THAT(mean(i, j),
Catch::Matchers::WithinAbs(MEAN, MEAN * TOLERANCE));
REQUIRE_THAT(variance(i, j),
Catch::Matchers::WithinAbs(VAR, VAR * TOLERANCE));
REQUIRE_THAT(standard_deviation(i, j),
Catch::Matchers::WithinAbs(STD, STD * TOLERANCE));
}
}
}

View File

@ -31,7 +31,7 @@ NDArray<ssize_t, 2> GenerateMoench03PixelMap() {
}
NDArray<ssize_t, 2> GenerateMoench05PixelMap() {
std::array<int, 3> adc_numbers = {5, 9, 1};
std::array<int, 3> adc_numbers = {5, 9, 1};
NDArray<ssize_t, 2> order_map({160, 150});
int n_pixel = 0;
for (int row = 0; row < 160; row++) {
@ -40,11 +40,11 @@ NDArray<ssize_t, 2> GenerateMoench05PixelMap() {
for (int i_sc = 0; i_sc < 3; i_sc++) {
int col = 50 * i_sc + i_col;
int adc_nr = adc_numbers[i_sc];
int i_analog = n_pixel * 12 + adc_nr;
int i_analog = n_pixel * 12 + adc_nr;
// analog_frame[row * 150 + col] = analog_data[i_analog] & 0x3FFF;
// analog_frame[row * 150 + col] = analog_data[i_analog] &
// 0x3FFF;
order_map(row, col) = i_analog;
}
}
}
@ -52,7 +52,7 @@ NDArray<ssize_t, 2> GenerateMoench05PixelMap() {
}
NDArray<ssize_t, 2> GenerateMoench05PixelMap1g() {
std::array<int, 3> adc_numbers = {1, 2, 0};
std::array<int, 3> adc_numbers = {1, 2, 0};
NDArray<ssize_t, 2> order_map({160, 150});
int n_pixel = 0;
for (int row = 0; row < 160; row++) {
@ -61,12 +61,11 @@ NDArray<ssize_t, 2> GenerateMoench05PixelMap1g() {
for (int i_sc = 0; i_sc < 3; i_sc++) {
int col = 50 * i_sc + i_col;
int adc_nr = adc_numbers[i_sc];
int i_analog = n_pixel * 3 + adc_nr;
int i_analog = n_pixel * 3 + adc_nr;
// analog_frame[row * 150 + col] = analog_data[i_analog] & 0x3FFF;
// analog_frame[row * 150 + col] = analog_data[i_analog] &
// 0x3FFF;
order_map(row, col) = i_analog;
}
}
}
@ -85,42 +84,42 @@ NDArray<ssize_t, 2> GenerateMoench05PixelMapOld() {
int adc_nr = adc_numbers[i_sc];
int i_analog = n_pixel * 32 + adc_nr;
// analog_frame[row * 150 + col] = analog_data[i_analog] & 0x3FFF;
// analog_frame[row * 150 + col] = analog_data[i_analog] &
// 0x3FFF;
order_map(row, col) = i_analog;
}
}
}
return order_map;
}
NDArray<ssize_t, 2>GenerateEigerFlipRowsPixelMap(){
NDArray<ssize_t, 2> GenerateEigerFlipRowsPixelMap() {
NDArray<ssize_t, 2> order_map({256, 512});
for(int row = 0; row < 256; row++){
for(int col = 0; col < 512; col++){
order_map(row, col) = 255*512-row*512 + col;
for (int row = 0; row < 256; row++) {
for (int col = 0; col < 512; col++) {
order_map(row, col) = 255 * 512 - row * 512 + col;
}
}
return order_map;
}
NDArray<ssize_t, 2>GenerateMH02SingleCounterPixelMap(){
NDArray<ssize_t, 2> GenerateMH02SingleCounterPixelMap() {
NDArray<ssize_t, 2> order_map({48, 48});
for(int row = 0; row < 48; row++){
for(int col = 0; col < 48; col++){
order_map(row, col) = row*48 + col;
for (int row = 0; row < 48; row++) {
for (int col = 0; col < 48; col++) {
order_map(row, col) = row * 48 + col;
}
}
return order_map;
}
NDArray<ssize_t, 3> GenerateMH02FourCounterPixelMap(){
NDArray<ssize_t, 3> GenerateMH02FourCounterPixelMap() {
NDArray<ssize_t, 3> order_map({4, 48, 48});
for (int counter=0; counter<4; counter++){
for(int row = 0; row < 48; row++){
for(int col = 0; col < 48; col++){
order_map(counter, row, col) = counter*48*48 + row*48 + col;
for (int counter = 0; counter < 4; counter++) {
for (int row = 0; row < 48; row++) {
for (int col = 0; col < 48; col++) {
order_map(counter, row, col) =
counter * 48 * 48 + row * 48 + col;
}
}
}

View File

@ -1,9 +1,9 @@
#include "aare/RawFile.hpp"
#include "aare/algorithm.hpp"
#include "aare/PixelMap.hpp"
#include "aare/algorithm.hpp"
#include "aare/defs.hpp"
#include "aare/logger.hpp"
#include "aare/geo_helpers.hpp"
#include "aare/logger.hpp"
#include <fmt/format.h>
#include <nlohmann/json.hpp>
@ -17,8 +17,9 @@ RawFile::RawFile(const std::filesystem::path &fname, const std::string &mode)
m_mode = mode;
if (mode == "r") {
find_geometry();
if (m_master.roi()){
m_geometry = update_geometry_with_roi(m_geometry, m_master.roi().value());
if (m_master.roi()) {
m_geometry =
update_geometry_with_roi(m_geometry, m_master.roi().value());
}
open_subfiles();
} else {
@ -47,32 +48,31 @@ void RawFile::read_into(std::byte *image_buf) {
return get_frame_into(m_current_frame++, image_buf);
}
void RawFile::read_into(std::byte *image_buf, DetectorHeader *header) {
return get_frame_into(m_current_frame++, image_buf, header);
}
void RawFile::read_into(std::byte *image_buf, size_t n_frames, DetectorHeader *header) {
void RawFile::read_into(std::byte *image_buf, size_t n_frames,
DetectorHeader *header) {
// return get_frame_into(m_current_frame++, image_buf, header);
for (size_t i = 0; i < n_frames; i++) {
this->get_frame_into(m_current_frame++, image_buf, header);
image_buf += bytes_per_frame();
if(header)
header+=n_modules();
if (header)
header += n_modules();
}
}
size_t RawFile::n_modules() const { return m_master.n_modules(); }
size_t RawFile::bytes_per_frame() {
return m_geometry.pixels_x * m_geometry.pixels_y * m_master.bitdepth() / bits_per_byte;
return m_geometry.pixels_x * m_geometry.pixels_y * m_master.bitdepth() /
bits_per_byte;
}
size_t RawFile::pixels_per_frame() {
// return m_rows * m_cols;
size_t RawFile::pixels_per_frame() {
// return m_rows * m_cols;
return m_geometry.pixels_x * m_geometry.pixels_y;
}
@ -128,27 +128,25 @@ DetectorHeader RawFile::read_header(const std::filesystem::path &fname) {
return h;
}
RawMasterFile RawFile::master() const { return m_master; }
/**
* @brief Find the geometry of the detector by opening all the subfiles and
* reading the headers.
* reading the headers.
*/
void RawFile::find_geometry() {
//Hold the maximal row and column number found
//Later used for calculating the total number of rows and columns
// Hold the maximal row and column number found
// Later used for calculating the total number of rows and columns
uint16_t r{};
uint16_t c{};
for (size_t i = 0; i < n_modules(); i++) {
auto h = read_header(m_master.data_fname(i, 0));
r = std::max(r, h.row);
c = std::max(c, h.column);
// positions.push_back({h.row, h.column});
ModuleGeometry g;
g.origin_x = h.column * m_master.pixels_x();
g.origin_y = h.row * m_master.pixels_y();
@ -157,34 +155,30 @@ void RawFile::find_geometry() {
g.width = m_master.pixels_x();
g.height = m_master.pixels_y();
m_geometry.module_pixel_0.push_back(g);
}
r++;
c++;
m_geometry.pixels_y = (r * m_master.pixels_y());
m_geometry.pixels_x = (c * m_master.pixels_x());
m_geometry.pixels_x = (c * m_master.pixels_x());
m_geometry.modules_x = c;
m_geometry.modules_y = r;
m_geometry.pixels_y += static_cast<size_t>((r - 1) * cfg.module_gap_row);
}
Frame RawFile::get_frame(size_t frame_index) {
auto f = Frame(m_geometry.pixels_y, m_geometry.pixels_x, Dtype::from_bitdepth(m_master.bitdepth()));
auto f = Frame(m_geometry.pixels_y, m_geometry.pixels_x,
Dtype::from_bitdepth(m_master.bitdepth()));
std::byte *frame_buffer = f.data();
get_frame_into(frame_index, frame_buffer);
return f;
}
size_t RawFile::bytes_per_pixel() const { return m_master.bitdepth() / 8; }
size_t RawFile::bytes_per_pixel() const {
return m_master.bitdepth() / 8;
}
void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, DetectorHeader *header) {
void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer,
DetectorHeader *header) {
LOG(logDEBUG) << "RawFile::get_frame_into(" << frame_index << ")";
if (frame_index >= total_frames()) {
throw std::runtime_error(LOCATION + "Frame number out of range");
@ -192,12 +186,12 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect
std::vector<size_t> frame_numbers(n_modules());
std::vector<size_t> frame_indices(n_modules(), frame_index);
// sync the frame numbers
if (n_modules() != 1) { //if we have more than one module
if (n_modules() != 1) { // if we have more than one module
for (size_t part_idx = 0; part_idx != n_modules(); ++part_idx) {
frame_numbers[part_idx] = m_subfiles[part_idx]->frame_number(frame_index);
frame_numbers[part_idx] =
m_subfiles[part_idx]->frame_number(frame_index);
}
// 1. if frame number vector is the same break
@ -218,7 +212,8 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect
}
frame_numbers[min_frame_idx] =
m_subfiles[min_frame_idx]->frame_number(frame_indices[min_frame_idx]);
m_subfiles[min_frame_idx]->frame_number(
frame_indices[min_frame_idx]);
}
}
@ -226,15 +221,18 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect
// get the part from each subfile and copy it to the frame
for (size_t part_idx = 0; part_idx != n_modules(); ++part_idx) {
auto corrected_idx = frame_indices[part_idx];
// This is where we start writing
auto offset = (m_geometry.module_pixel_0[part_idx].origin_y * m_geometry.pixels_x +
m_geometry.module_pixel_0[part_idx].origin_x)*m_master.bitdepth()/8;
if (m_geometry.module_pixel_0[part_idx].origin_x!=0)
throw std::runtime_error(LOCATION + " Implementation error. x pos not 0.");
//TODO! What if the files don't match?
// This is where we start writing
auto offset = (m_geometry.module_pixel_0[part_idx].origin_y *
m_geometry.pixels_x +
m_geometry.module_pixel_0[part_idx].origin_x) *
m_master.bitdepth() / 8;
if (m_geometry.module_pixel_0[part_idx].origin_x != 0)
throw std::runtime_error(LOCATION +
" Implementation error. x pos not 0.");
// TODO! What if the files don't match?
m_subfiles[part_idx]->seek(corrected_idx);
m_subfiles[part_idx]->read_into(frame_buffer + offset, header);
if (header)
@ -242,7 +240,7 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect
}
} else {
//TODO! should we read row by row?
// TODO! should we read row by row?
// create a buffer large enough to hold a full module
auto bytes_per_part = m_master.pixels_y() * m_master.pixels_x() *
@ -260,7 +258,7 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect
m_subfiles[part_idx]->seek(corrected_idx);
m_subfiles[part_idx]->read_into(part_buffer, header);
if(header)
if (header)
++header;
for (size_t cur_row = 0; cur_row < static_cast<size_t>(pos.height);
@ -271,15 +269,13 @@ void RawFile::get_frame_into(size_t frame_index, std::byte *frame_buffer, Detect
auto dest = (irow * this->m_geometry.pixels_x + icol);
dest = dest * m_master.bitdepth() / 8;
memcpy(frame_buffer + dest,
part_buffer + cur_row * pos.width *
m_master.bitdepth() / 8,
part_buffer +
cur_row * pos.width * m_master.bitdepth() / 8,
pos.width * m_master.bitdepth() / 8);
}
}
delete[] part_buffer;
}
}
std::vector<Frame> RawFile::read_n(size_t n_frames) {
@ -299,5 +295,4 @@ size_t RawFile::frame_number(size_t frame_index) {
return m_subfiles[0]->frame_number(frame_index);
}
} // namespace aare

View File

@ -1,18 +1,18 @@
#include "aare/RawFile.hpp"
#include "aare/File.hpp"
#include "aare/RawMasterFile.hpp" //needed for ROI
#include "aare/RawFile.hpp"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include "test_config.hpp"
using aare::File;
TEST_CASE("Read number of frames from a jungfrau raw file", "[.integration]") {
auto fpath = test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
auto fpath =
test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
File f(fpath, "r");
@ -20,7 +20,8 @@ TEST_CASE("Read number of frames from a jungfrau raw file", "[.integration]") {
}
TEST_CASE("Read frame numbers from a jungfrau raw file", "[.integration]") {
auto fpath = test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
auto fpath =
test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
File f(fpath, "r");
@ -36,7 +37,8 @@ TEST_CASE("Read frame numbers from a jungfrau raw file", "[.integration]") {
}
TEST_CASE("Read a frame number too high throws", "[.integration]") {
auto fpath = test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
auto fpath =
test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
File f(fpath, "r");
@ -49,8 +51,10 @@ TEST_CASE("Read a frame number too high throws", "[.integration]") {
REQUIRE_THROWS(f.frame_number(10));
}
TEST_CASE("Read a frame numbers where the subfile is missing throws", "[.integration]") {
auto fpath = test_data_path() / "jungfrau" / "jungfrau_missing_subfile_master_0.json";
TEST_CASE("Read a frame numbers where the subfile is missing throws",
"[.integration]") {
auto fpath = test_data_path() / "jungfrau" /
"jungfrau_missing_subfile_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
File f(fpath, "r");
@ -58,7 +62,7 @@ TEST_CASE("Read a frame numbers where the subfile is missing throws", "[.integra
// we know this file has 10 frames with frame numbers 1 to 10
// f0 1,2,3
// f1 4,5,6 - but files f1-f3 are missing
// f2 7,8,9 - gone
// f2 7,8,9 - gone
// f3 10 - gone
REQUIRE(f.frame_number(0) == 1);
REQUIRE(f.frame_number(1) == 2);
@ -69,15 +73,18 @@ TEST_CASE("Read a frame numbers where the subfile is missing throws", "[.integra
REQUIRE_THROWS(f.frame_number(10));
}
TEST_CASE("Read data from a jungfrau 500k single port raw file", "[.integration]") {
auto fpath = test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
TEST_CASE("Read data from a jungfrau 500k single port raw file",
"[.integration]") {
auto fpath =
test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
File f(fpath, "r");
// we know this file has 10 frames with pixel 0,0 being: 2123, 2051, 2109, 2117, 2089, 2095, 2072, 2126, 2097, 2102
std::vector<uint16_t> pixel_0_0 = {2123, 2051, 2109, 2117, 2089, 2095, 2072, 2126, 2097, 2102};
// we know this file has 10 frames with pixel 0,0 being: 2123, 2051, 2109,
// 2117, 2089, 2095, 2072, 2126, 2097, 2102
std::vector<uint16_t> pixel_0_0 = {2123, 2051, 2109, 2117, 2089,
2095, 2072, 2126, 2097, 2102};
for (size_t i = 0; i < 10; i++) {
auto frame = f.read_frame();
CHECK(frame.rows() == 512);
@ -100,10 +107,12 @@ TEST_CASE("Read frame numbers from a raw file", "[.integration]") {
}
TEST_CASE("Compare reading from a numpy file with a raw file", "[.files]") {
auto fpath_raw = test_data_path() / "raw/jungfrau" / "jungfrau_single_master_0.json";
auto fpath_raw =
test_data_path() / "raw/jungfrau" / "jungfrau_single_master_0.json";
REQUIRE(std::filesystem::exists(fpath_raw));
auto fpath_npy = test_data_path() / "raw/jungfrau" / "jungfrau_single_0.npy";
auto fpath_npy =
test_data_path() / "raw/jungfrau" / "jungfrau_single_0.npy";
REQUIRE(std::filesystem::exists(fpath_npy));
File raw(fpath_raw, "r");
@ -121,17 +130,23 @@ TEST_CASE("Compare reading from a numpy file with a raw file", "[.files]") {
}
TEST_CASE("Read multipart files", "[.integration]") {
auto fpath = test_data_path() / "jungfrau" / "jungfrau_double_master_0.json";
auto fpath =
test_data_path() / "jungfrau" / "jungfrau_double_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
File f(fpath, "r");
// we know this file has 10 frames check read_multiport.py for the values
std::vector<uint16_t> pixel_0_0 = {2099, 2121, 2108, 2084, 2084, 2118, 2066, 2108, 2112, 2116};
std::vector<uint16_t> pixel_0_1 = {2842, 2796, 2865, 2798, 2805, 2817, 2852, 2789, 2792, 2833};
std::vector<uint16_t> pixel_255_1023 = {2149, 2037, 2115, 2102, 2118, 2090, 2036, 2071, 2073, 2142};
std::vector<uint16_t> pixel_511_1023 = {3231, 3169, 3167, 3162, 3168, 3160, 3171, 3171, 3169, 3171};
std::vector<uint16_t> pixel_1_0 = {2748, 2614, 2665, 2629, 2618, 2630, 2631, 2634, 2577, 2598};
std::vector<uint16_t> pixel_0_0 = {2099, 2121, 2108, 2084, 2084,
2118, 2066, 2108, 2112, 2116};
std::vector<uint16_t> pixel_0_1 = {2842, 2796, 2865, 2798, 2805,
2817, 2852, 2789, 2792, 2833};
std::vector<uint16_t> pixel_255_1023 = {2149, 2037, 2115, 2102, 2118,
2090, 2036, 2071, 2073, 2142};
std::vector<uint16_t> pixel_511_1023 = {3231, 3169, 3167, 3162, 3168,
3160, 3171, 3171, 3169, 3171};
std::vector<uint16_t> pixel_1_0 = {2748, 2614, 2665, 2629, 2618,
2630, 2631, 2634, 2577, 2598};
for (size_t i = 0; i < 10; i++) {
auto frame = f.read_frame();
@ -146,11 +161,9 @@ TEST_CASE("Read multipart files", "[.integration]") {
}
TEST_CASE("Read file with unordered frames", "[.integration]") {
//TODO! Better explanation and error message
// TODO! Better explanation and error message
auto fpath = test_data_path() / "mythen" / "scan242_master_3.raw";
REQUIRE(std::filesystem::exists(fpath));
File f(fpath);
REQUIRE_THROWS((f.read_frame()));
}

View File

@ -1,5 +1,5 @@
#include "aare/RawMasterFile.hpp"
#include <sstream>
#include <sstream>
namespace aare {
RawFileNameComponents::RawFileNameComponents(
@ -37,18 +37,15 @@ std::filesystem::path RawFileNameComponents::master_fname() const {
}
std::filesystem::path RawFileNameComponents::data_fname(size_t mod_id,
size_t file_id
) const {
size_t file_id) const {
std::string fmt = "{}_d{}_f{}_{}.raw";
//Before version X we used to name the data files f000000000000
// Before version X we used to name the data files f000000000000
if (m_old_scheme) {
fmt = "{}_d{}_f{:012}_{}.raw";
}
return m_base_path / fmt::format(fmt, m_base_name, mod_id,
file_id, m_file_index);
return m_base_path /
fmt::format(fmt, m_base_name, mod_id, file_id, m_file_index);
}
void RawFileNameComponents::set_old_scheme(bool old_scheme) {
@ -65,19 +62,19 @@ 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));
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"){
while (std::getline(iss, line)) {
if (line == "enabled") {
m_enabled = true;
}else if(line.find("dac") != std::string::npos){
} else if (line.find("dac") != std::string::npos) {
m_dac = line.substr(4);
}else if(line.find("start") != std::string::npos){
} else if (line.find("start") != std::string::npos) {
m_start = std::stoi(line.substr(6));
}else if(line.find("stop") != std::string::npos){
} else if (line.find("stop") != std::string::npos) {
m_stop = std::stoi(line.substr(5));
}else if(line.find("step") != std::string::npos){
} else if (line.find("step") != std::string::npos) {
m_step = std::stoi(line.substr(5));
}
}
@ -85,14 +82,11 @@ ScanParameters::ScanParameters(const std::string& par){
int ScanParameters::start() const { return m_start; }
int ScanParameters::stop() const { return m_stop; }
void ScanParameters::increment_stop(){
m_stop += 1;
}
void ScanParameters::increment_stop() { m_stop += 1; }
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)) {
@ -163,10 +157,8 @@ ScanParameters RawMasterFile::scan_parameters() const {
return m_scan_parameters;
}
std::optional<ROI> RawMasterFile::roi() const { return m_roi; }
void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
std::ifstream ifs(fpath);
json j;
@ -205,17 +197,16 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
// keep the optional empty
}
// ----------------------------------------------------------------
// Special treatment of analog flag because of Moench03
try{
try {
m_analog_flag = j.at("Analog Flag");
}catch (const json::out_of_range &e) {
} catch (const json::out_of_range &e) {
// if it doesn't work still set it to one
// to try to decode analog samples (Old Moench03)
m_analog_flag = 1;
}
try {
try {
if (m_analog_flag) {
m_analog_samples = j.at("Analog Samples");
}
@ -248,27 +239,27 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
// keep the optional empty
}
try{
try {
m_transceiver_flag = j.at("Transceiver Flag");
if(m_transceiver_flag){
if (m_transceiver_flag) {
m_transceiver_samples = j.at("Transceiver Samples");
}
}catch (const json::out_of_range &e) {
} catch (const json::out_of_range &e) {
// keep the optional empty
}
try{
try {
std::string scan_parameters = j.at("Scan Parameters");
m_scan_parameters = ScanParameters(scan_parameters);
if(v<7.21){
m_scan_parameters.increment_stop(); //adjust for endpoint being included
}
}catch (const json::out_of_range &e) {
if (v < 7.21) {
m_scan_parameters
.increment_stop(); // adjust for endpoint being included
}
} catch (const json::out_of_range &e) {
// not a scan
}
try{
try {
ROI tmp_roi;
auto obj = j.at("Receiver Roi");
tmp_roi.xmin = obj.at("xmin");
@ -276,37 +267,32 @@ void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
tmp_roi.ymin = obj.at("ymin");
tmp_roi.ymax = obj.at("ymax");
//if any of the values are set update the roi
// if any of the values are set update the roi
if (tmp_roi.xmin != 4294967295 || tmp_roi.xmax != 4294967295 ||
tmp_roi.ymin != 4294967295 || tmp_roi.ymax != 4294967295) {
if(v<7.21){
if (v < 7.21) {
tmp_roi.xmax++;
tmp_roi.ymax++;
}
m_roi = tmp_roi;
}
}catch (const json::out_of_range &e) {
} catch (const json::out_of_range &e) {
// leave the optional empty
}
//if we have an roi we need to update the geometry for the subfiles
if (m_roi){
// if we have an roi we need to update the geometry for the subfiles
if (m_roi) {
}
// Update detector type for Moench
// TODO! How does this work with old .raw master files?
#ifdef AARE_VERBOSE
// Update detector type for Moench
// TODO! How does this work with old .raw master files?
#ifdef AARE_VERBOSE
fmt::print("Detecting Moench03: m_pixels_y: {}, m_analog_samples: {}\n",
m_pixels_y, m_analog_samples.value_or(0));
#endif
#endif
if (m_type == DetectorType::Moench && !m_analog_samples &&
m_pixels_y == 400) {
m_type = DetectorType::Moench03;
@ -332,19 +318,19 @@ void RawMasterFile::parse_raw(const std::filesystem::path &fpath) {
if (key == "Version") {
m_version = value;
//TODO!: How old versions can we handle?
// TODO!: How old versions can we handle?
auto v = std::stod(value);
//TODO! figure out exactly when we did the change
//This enables padding of f to 12 digits
if (v<4.0)
// TODO! figure out exactly when we did the change
// This enables padding of f to 12 digits
if (v < 4.0)
m_fnc.set_old_scheme(true);
} else if (key == "TimeStamp") {
} else if (key == "Detector Type") {
m_type = StringTo<DetectorType>(value);
if(m_type==DetectorType::Moench){
if (m_type == DetectorType::Moench) {
m_type = DetectorType::Moench03_old;
}
} else if (key == "Timing Mode") {
@ -381,10 +367,10 @@ void RawMasterFile::parse_raw(const std::filesystem::path &fpath) {
pos = value.find(',');
m_pixels_x = std::stoi(value.substr(1, pos));
m_pixels_y = std::stoi(value.substr(pos + 1));
}else if(key == "row"){
} else if (key == "row") {
pos = value.find('p');
m_pixels_y = std::stoi(value.substr(0, pos));
}else if(key == "col"){
} else if (key == "col") {
pos = value.find('p');
m_pixels_x = std::stoi(value.substr(0, pos));
} else if (key == "Total Frames") {
@ -395,8 +381,8 @@ void RawMasterFile::parse_raw(const std::filesystem::path &fpath) {
m_quad = std::stoi(value);
} else if (key == "Max Frames Per File") {
m_max_frames_per_file = std::stoi(value);
}else if(key == "Max. Frames Per File"){
//Version 3.0 way of writing it
} else if (key == "Max. Frames Per File") {
// Version 3.0 way of writing it
m_max_frames_per_file = std::stoi(value);
} else if (key == "Geometry") {
pos = value.find(',');
@ -410,15 +396,14 @@ void RawMasterFile::parse_raw(const std::filesystem::path &fpath) {
m_type = DetectorType::Moench03_old;
}
//TODO! Look for d0, d1...dn and update geometry
if(m_geometry.col == 0 && m_geometry.row == 0){
m_geometry = {1,1};
// TODO! Look for d0, d1...dn and update geometry
if (m_geometry.col == 0 && m_geometry.row == 0) {
m_geometry = {1, 1};
fmt::print("Warning: No geometry found in master file. Assuming 1x1\n");
}
//TODO! Read files and find actual frames
if(m_frames_in_file==0)
// TODO! Read files and find actual frames
if (m_frames_in_file == 0)
m_frames_in_file = m_total_frames_expected;
}
} // namespace aare

View File

@ -1,12 +1,11 @@
#include "aare/RawMasterFile.hpp"
#include <catch2/catch_test_macros.hpp>
#include "test_config.hpp"
#include <catch2/catch_test_macros.hpp>
using namespace aare;
TEST_CASE("Parse a master file fname"){
TEST_CASE("Parse a master file fname") {
RawFileNameComponents m("test_master_1.json");
REQUIRE(m.base_name() == "test");
REQUIRE(m.ext() == ".json");
@ -14,7 +13,7 @@ TEST_CASE("Parse a master file fname"){
REQUIRE(m.base_path() == "");
}
TEST_CASE("Extraction of base path works"){
TEST_CASE("Extraction of base path works") {
RawFileNameComponents m("some/path/test_master_73.json");
REQUIRE(m.base_name() == "test");
REQUIRE(m.ext() == ".json");
@ -22,7 +21,7 @@ TEST_CASE("Extraction of base path works"){
REQUIRE(m.base_path() == "some/path");
}
TEST_CASE("Construction of master file name and data files"){
TEST_CASE("Construction of master file name and data files") {
RawFileNameComponents m("test_master_1.json");
REQUIRE(m.master_fname() == "test_master_1.json");
REQUIRE(m.data_fname(0, 0) == "test_d0_f0_1.raw");
@ -31,7 +30,7 @@ TEST_CASE("Construction of master file name and data files"){
REQUIRE(m.data_fname(1, 1) == "test_d1_f1_1.raw");
}
TEST_CASE("Construction of master file name and data files using old scheme"){
TEST_CASE("Construction of master file name and data files using old scheme") {
RawFileNameComponents m("test_master_1.raw");
m.set_old_scheme(true);
REQUIRE(m.master_fname() == "test_master_1.raw");
@ -41,16 +40,15 @@ TEST_CASE("Construction of master file name and data files using old scheme"){
REQUIRE(m.data_fname(1, 1) == "test_d1_f000000000001_1.raw");
}
TEST_CASE("Master file name does not fit pattern"){
TEST_CASE("Master file name does not fit pattern") {
REQUIRE_THROWS(RawFileNameComponents("somefile.json"));
REQUIRE_THROWS(RawFileNameComponents("another_test_d0_f0_1.raw"));
REQUIRE_THROWS(RawFileNameComponents("test_master_1.txt"));
}
TEST_CASE("Parse scan parameters"){
ScanParameters s("[enabled\ndac dac 4\nstart 500\nstop 2200\nstep 5\nsettleTime 100us\n]");
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);
@ -58,7 +56,7 @@ TEST_CASE("Parse scan parameters"){
REQUIRE(s.step() == 5);
}
TEST_CASE("A disabled scan"){
TEST_CASE("A disabled scan") {
ScanParameters s("[disabled]");
REQUIRE_FALSE(s.enabled());
REQUIRE(s.dac() == "");
@ -67,9 +65,9 @@ TEST_CASE("A disabled scan"){
REQUIRE(s.step() == 0);
}
TEST_CASE("Parse a master file in .json format", "[.integration]"){
auto fpath = test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
TEST_CASE("Parse a master file in .json format", "[.integration]") {
auto fpath =
test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
RawMasterFile f(fpath);
@ -80,7 +78,7 @@ TEST_CASE("Parse a master file in .json format", "[.integration]"){
REQUIRE(f.detector_type() == DetectorType::Jungfrau);
// "Timing Mode": "auto",
REQUIRE(f.timing_mode() == TimingMode::Auto);
// "Geometry": {
// "x": 1,
// "y": 1
@ -100,10 +98,9 @@ TEST_CASE("Parse a master file in .json format", "[.integration]"){
// "Max Frames Per File": 3,
REQUIRE(f.max_frames_per_file() == 3);
//Jungfrau doesn't write but it is 16
// Jungfrau doesn't write but it is 16
REQUIRE(f.bitdepth() == 16);
// "Frame Discard Policy": "nodiscard",
// "Frame Padding": 1,
@ -125,33 +122,35 @@ TEST_CASE("Parse a master file in .json format", "[.integration]"){
// "Frames in File": 10,
REQUIRE(f.frames_in_file() == 10);
//TODO! Should we parse this?
// "Frame Header Format": {
// "Frame Number": "8 bytes",
// "SubFrame Number/ExpLength": "4 bytes",
// "Packet Number": "4 bytes",
// "Bunch ID": "8 bytes",
// "Timestamp": "8 bytes",
// "Module Id": "2 bytes",
// "Row": "2 bytes",
// "Column": "2 bytes",
// "Reserved": "2 bytes",
// "Debug": "4 bytes",
// "Round Robin Number": "2 bytes",
// "Detector Type": "1 byte",
// "Header Version": "1 byte",
// "Packets Caught Mask": "64 bytes"
// }
// }
// TODO! Should we parse this?
// "Frame Header Format": {
// "Frame Number": "8 bytes",
// "SubFrame Number/ExpLength": "4 bytes",
// "Packet Number": "4 bytes",
// "Bunch ID": "8 bytes",
// "Timestamp": "8 bytes",
// "Module Id": "2 bytes",
// "Row": "2 bytes",
// "Column": "2 bytes",
// "Reserved": "2 bytes",
// "Debug": "4 bytes",
// "Round Robin Number": "2 bytes",
// "Detector Type": "1 byte",
// "Header Version": "1 byte",
// "Packets Caught Mask": "64 bytes"
// }
// }
REQUIRE_FALSE(f.analog_samples());
REQUIRE_FALSE(f.digital_samples());
REQUIRE_FALSE(f.digital_samples());
}
TEST_CASE("Parse a master file in .raw format", "[.integration]"){
auto fpath = test_data_path() / "moench/moench04_noise_200V_sto_both_100us_no_light_thresh_900_master_0.raw";
TEST_CASE("Parse a master file in .raw format", "[.integration]") {
auto fpath =
test_data_path() /
"moench/"
"moench04_noise_200V_sto_both_100us_no_light_thresh_900_master_0.raw";
REQUIRE(std::filesystem::exists(fpath));
RawMasterFile f(fpath);
@ -209,80 +208,74 @@ TEST_CASE("Parse a master file in .raw format", "[.integration]"){
// Detector Type : 1 byte
// Header Version : 1 byte
// Packets Caught Mask : 64 bytes
}
TEST_CASE("Read eiger master file", "[.integration]"){
auto fpath = test_data_path() / "eiger" / "eiger_500k_32bit_master_0.json";
TEST_CASE("Read eiger master file", "[.integration]") {
auto fpath = test_data_path() / "eiger" / "eiger_500k_32bit_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
RawMasterFile f(fpath);
// {
// "Version": 7.2,
REQUIRE(f.version() == "7.2");
// "Timestamp": "Tue Mar 26 17:24:34 2024",
// "Detector Type": "Eiger",
REQUIRE(f.detector_type() == DetectorType::Eiger);
// "Timing Mode": "auto",
REQUIRE(f.timing_mode() == TimingMode::Auto);
// "Geometry": {
// "x": 2,
// "y": 2
// },
// "Image Size in bytes": 524288,
REQUIRE(f.image_size_in_bytes() == 524288);
// "Pixels": {
// "x": 512,
REQUIRE(f.pixels_x() == 512);
// "y": 256
REQUIRE(f.pixels_y() == 256);
// },
// "Max Frames Per File": 10000,
REQUIRE(f.max_frames_per_file() == 10000);
// "Frame Discard Policy": "nodiscard",
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
// "Frame Padding": 1,
REQUIRE(f.frame_padding() == 1);
// "Scan Parameters": "[disabled]",
// "Total Frames": 3,
// "Receiver Roi": {
// "xmin": 4294967295,
// "xmax": 4294967295,
// "ymin": 4294967295,
// "ymax": 4294967295
// },
// "Dynamic Range": 32,
// "Ten Giga": 0,
// "Exptime": "5s",
// "Period": "1s",
// "Threshold Energy": -1,
// "Sub Exptime": "2.62144ms",
// "Sub Period": "2.62144ms",
// "Quad": 0,
// "Number of rows": 256,
// "Rate Corrections": "[0, 0]",
// "Frames in File": 3,
// "Frame Header Format": {
// "Frame Number": "8 bytes",
// "SubFrame Number/ExpLength": "4 bytes",
// "Packet Number": "4 bytes",
// "Bunch ID": "8 bytes",
// "Timestamp": "8 bytes",
// "Module Id": "2 bytes",
// "Row": "2 bytes",
// "Column": "2 bytes",
// "Reserved": "2 bytes",
// "Debug": "4 bytes",
// "Round Robin Number": "2 bytes",
// "Detector Type": "1 byte",
// "Header Version": "1 byte",
// "Packets Caught Mask": "64 bytes"
// }
// }
// {
// "Version": 7.2,
REQUIRE(f.version() == "7.2");
// "Timestamp": "Tue Mar 26 17:24:34 2024",
// "Detector Type": "Eiger",
REQUIRE(f.detector_type() == DetectorType::Eiger);
// "Timing Mode": "auto",
REQUIRE(f.timing_mode() == TimingMode::Auto);
// "Geometry": {
// "x": 2,
// "y": 2
// },
// "Image Size in bytes": 524288,
REQUIRE(f.image_size_in_bytes() == 524288);
// "Pixels": {
// "x": 512,
REQUIRE(f.pixels_x() == 512);
// "y": 256
REQUIRE(f.pixels_y() == 256);
// },
// "Max Frames Per File": 10000,
REQUIRE(f.max_frames_per_file() == 10000);
// "Frame Discard Policy": "nodiscard",
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
// "Frame Padding": 1,
REQUIRE(f.frame_padding() == 1);
// "Scan Parameters": "[disabled]",
// "Total Frames": 3,
// "Receiver Roi": {
// "xmin": 4294967295,
// "xmax": 4294967295,
// "ymin": 4294967295,
// "ymax": 4294967295
// },
// "Dynamic Range": 32,
// "Ten Giga": 0,
// "Exptime": "5s",
// "Period": "1s",
// "Threshold Energy": -1,
// "Sub Exptime": "2.62144ms",
// "Sub Period": "2.62144ms",
// "Quad": 0,
// "Number of rows": 256,
// "Rate Corrections": "[0, 0]",
// "Frames in File": 3,
// "Frame Header Format": {
// "Frame Number": "8 bytes",
// "SubFrame Number/ExpLength": "4 bytes",
// "Packet Number": "4 bytes",
// "Bunch ID": "8 bytes",
// "Timestamp": "8 bytes",
// "Module Id": "2 bytes",
// "Row": "2 bytes",
// "Column": "2 bytes",
// "Reserved": "2 bytes",
// "Debug": "4 bytes",
// "Round Robin Number": "2 bytes",
// "Detector Type": "1 byte",
// "Header Version": "1 byte",
// "Packets Caught Mask": "64 bytes"
// }
// }
}

View File

@ -1,36 +1,30 @@
#include "aare/RawSubFile.hpp"
#include "aare/PixelMap.hpp"
#include "aare/algorithm.hpp"
#include "aare/utils/ifstream_helpers.hpp"
#include "aare/logger.hpp"
#include "aare/utils/ifstream_helpers.hpp"
#include <cstring> // memcpy
#include <fmt/core.h>
#include <iostream>
#include <regex>
namespace aare {
RawSubFile::RawSubFile(const std::filesystem::path &fname,
DetectorType detector, size_t rows, size_t cols,
size_t bitdepth, uint32_t pos_row, uint32_t pos_col)
: m_detector_type(detector), m_bitdepth(bitdepth),
m_rows(rows), m_cols(cols),
m_bytes_per_frame((m_bitdepth / 8) * m_rows * m_cols), m_pos_row(pos_row),
m_pos_col(pos_col) {
: m_detector_type(detector), m_bitdepth(bitdepth), m_rows(rows),
m_cols(cols), m_bytes_per_frame((m_bitdepth / 8) * m_rows * m_cols),
m_pos_row(pos_row), m_pos_col(pos_col) {
LOG(logDEBUG) << "RawSubFile::RawSubFile()";
LOG(logDEBUG) << "RawSubFile::RawSubFile()";
if (m_detector_type == DetectorType::Moench03_old) {
m_pixel_map = GenerateMoench03PixelMap();
} else if (m_detector_type == DetectorType::Eiger && m_pos_row % 2 == 0) {
m_pixel_map = GenerateEigerFlipRowsPixelMap();
}
parse_fname(fname);
scan_files();
open_file(m_current_file_index); // open the first file
@ -51,7 +45,8 @@ void RawSubFile::seek(size_t frame_index) {
auto frame_offset = (file_index)
? frame_index - m_last_frame_in_file[file_index - 1]
: frame_index;
auto byte_offset = frame_offset * (m_bytes_per_frame + sizeof(DetectorHeader));
auto byte_offset =
frame_offset * (m_bytes_per_frame + sizeof(DetectorHeader));
m_file.seekg(byte_offset);
}
@ -69,7 +64,7 @@ void RawSubFile::read_into(std::byte *image_buf, DetectorHeader *header) {
m_file.seekg(sizeof(DetectorHeader), std::ios::cur);
}
if (m_file.fail()){
if (m_file.fail()) {
throw std::runtime_error(LOCATION + ifstream_error_msg(m_file));
}
@ -78,14 +73,15 @@ void RawSubFile::read_into(std::byte *image_buf, DetectorHeader *header) {
// read into a temporary buffer and then copy the data to the buffer
// in the correct order
// TODO! add 4 bit support
if(m_bitdepth == 8){
if (m_bitdepth == 8) {
read_with_map<uint8_t>(image_buf);
}else if (m_bitdepth == 16) {
} else if (m_bitdepth == 16) {
read_with_map<uint16_t>(image_buf);
} else if (m_bitdepth == 32) {
read_with_map<uint32_t>(image_buf);
}else{
throw std::runtime_error("Unsupported bitdepth for read with pixel map");
} else {
throw std::runtime_error(
"Unsupported bitdepth for read with pixel map");
}
} else {
@ -93,11 +89,11 @@ void RawSubFile::read_into(std::byte *image_buf, DetectorHeader *header) {
m_file.read(reinterpret_cast<char *>(image_buf), bytes_per_frame());
}
if (m_file.fail()){
if (m_file.fail()) {
throw std::runtime_error(LOCATION + ifstream_error_msg(m_file));
}
++ m_current_frame_index;
++m_current_frame_index;
if (m_current_frame_index >= m_last_frame_in_file[m_current_file_index] &&
(m_current_frame_index < m_total_frames)) {
++m_current_file_index;
@ -105,7 +101,8 @@ void RawSubFile::read_into(std::byte *image_buf, DetectorHeader *header) {
}
}
void RawSubFile::read_into(std::byte *image_buf, size_t n_frames, DetectorHeader *header) {
void RawSubFile::read_into(std::byte *image_buf, size_t n_frames,
DetectorHeader *header) {
for (size_t i = 0; i < n_frames; i++) {
read_into(image_buf, header);
image_buf += bytes_per_frame();
@ -115,10 +112,7 @@ void RawSubFile::read_into(std::byte *image_buf, size_t n_frames, DetectorHeader
}
}
template <typename T>
void RawSubFile::read_with_map(std::byte *image_buf) {
template <typename T> void RawSubFile::read_with_map(std::byte *image_buf) {
auto part_buffer = new std::byte[bytes_per_frame()];
m_file.read(reinterpret_cast<char *>(part_buffer), bytes_per_frame());
auto *data = reinterpret_cast<T *>(image_buf);
@ -157,14 +151,17 @@ void RawSubFile::parse_fname(const std::filesystem::path &fname) {
std::smatch match;
if (std::regex_match(m_base_name, match, pattern)) {
m_offset = std::stoi(match[4].str()); // find the first file index in case of a truncated series
m_base_name = match[1].str() + match[2].str() + match[3].str() + "{}" + match[5].str();
m_offset = std::stoi(match[4].str()); // find the first file index in
// case of a truncated series
m_base_name = match[1].str() + match[2].str() + match[3].str() + "{}" +
match[5].str();
LOG(logDEBUG) << "Base name: " << m_base_name;
LOG(logDEBUG) << "Offset: " << m_offset;
LOG(logDEBUG) << "Path: " << m_path.string();
} else {
throw std::runtime_error(
LOCATION + fmt::format("Could not parse file name {}", fname.string()));
LOCATION +
fmt::format("Could not parse file name {}", fname.string()));
}
}
@ -175,12 +172,13 @@ std::filesystem::path RawSubFile::fpath(size_t file_index) const {
void RawSubFile::open_file(size_t file_index) {
m_file.close();
auto fname = fpath(file_index+m_offset);
auto fname = fpath(file_index + m_offset);
LOG(logDEBUG) << "RawSubFile::open_file(): " << fname.string();
m_file.open(fname, std::ios::binary);
if (!m_file.is_open()) {
throw std::runtime_error(
LOCATION + fmt::format("Could not open file {}", fpath(file_index).string()));
LOCATION +
fmt::format("Could not open file {}", fpath(file_index).string()));
}
m_current_file_index = file_index;
}
@ -190,20 +188,21 @@ void RawSubFile::scan_files() {
// find how many files we have and the number of frames in each file
m_last_frame_in_file.clear();
size_t file_index = m_offset;
while (std::filesystem::exists(fpath(file_index))) {
auto n_frames = std::filesystem::file_size(fpath(file_index)) /
(m_bytes_per_frame + sizeof(DetectorHeader));
m_last_frame_in_file.push_back(n_frames);
LOG(logDEBUG) << "Found: " << n_frames << " frames in file: " << fpath(file_index).string();
LOG(logDEBUG) << "Found: " << n_frames
<< " frames in file: " << fpath(file_index).string();
++file_index;
}
// find where we need to open the next file and total number of frames
m_last_frame_in_file = cumsum(m_last_frame_in_file);
if(m_last_frame_in_file.empty()){
if (m_last_frame_in_file.empty()) {
m_total_frames = 0;
}else{
} else {
m_total_frames = m_last_frame_in_file.back();
}
}

View File

@ -1,13 +1,14 @@
#include "aare/RawSubFile.hpp"
#include "aare/File.hpp"
#include "aare/NDArray.hpp"
#include <catch2/catch_test_macros.hpp>
#include "test_config.hpp"
#include <catch2/catch_test_macros.hpp>
using namespace aare;
TEST_CASE("Read frames directly from a RawSubFile", "[.files]"){
auto fpath_raw = test_data_path() / "raw/jungfrau" / "jungfrau_single_d0_f0_0.raw";
TEST_CASE("Read frames directly from a RawSubFile", "[.files]") {
auto fpath_raw =
test_data_path() / "raw/jungfrau" / "jungfrau_single_d0_f0_0.raw";
REQUIRE(std::filesystem::exists(fpath_raw));
RawSubFile f(fpath_raw, DetectorType::Jungfrau, 512, 1024, 16);
@ -17,19 +18,19 @@ TEST_CASE("Read frames directly from a RawSubFile", "[.files]"){
REQUIRE(f.bytes_per_frame() == 512 * 1024 * 2);
REQUIRE(f.bytes_per_pixel() == 2);
auto fpath_npy = test_data_path() / "raw/jungfrau" / "jungfrau_single_0.npy";
auto fpath_npy =
test_data_path() / "raw/jungfrau" / "jungfrau_single_0.npy";
REQUIRE(std::filesystem::exists(fpath_npy));
//Numpy file with the same data to use as reference
// Numpy file with the same data to use as reference
File npy(fpath_npy, "r");
CHECK(f.frames_in_file() == 10);
CHECK(npy.total_frames() == 10);
DetectorHeader header{};
NDArray<uint16_t, 2> image({static_cast<ssize_t>(f.rows()), static_cast<ssize_t>(f.cols())});
NDArray<uint16_t, 2> image(
{static_cast<ssize_t>(f.rows()), static_cast<ssize_t>(f.cols())});
for (size_t i = 0; i < 10; ++i) {
CHECK(f.tell() == i);
f.read_into(image.buffer(), &header);
@ -38,38 +39,40 @@ TEST_CASE("Read frames directly from a RawSubFile", "[.files]"){
}
}
TEST_CASE("Read frames directly from a RawSubFile starting at the second file", "[.files]"){
TEST_CASE("Read frames directly from a RawSubFile starting at the second file",
"[.files]") {
// we know this file has 10 frames with frame numbers 1 to 10
// f0 1,2,3
// f1 4,5,6 <-- starting here
// f2 7,8,9
// f3 10
auto fpath_raw = test_data_path() / "raw/jungfrau" / "jungfrau_single_d0_f1_0.raw";
auto fpath_raw =
test_data_path() / "raw/jungfrau" / "jungfrau_single_d0_f1_0.raw";
REQUIRE(std::filesystem::exists(fpath_raw));
RawSubFile f(fpath_raw, DetectorType::Jungfrau, 512, 1024, 16);
auto fpath_npy = test_data_path() / "raw/jungfrau" / "jungfrau_single_0.npy";
auto fpath_npy =
test_data_path() / "raw/jungfrau" / "jungfrau_single_0.npy";
REQUIRE(std::filesystem::exists(fpath_npy));
//Numpy file with the same data to use as reference
// Numpy file with the same data to use as reference
File npy(fpath_npy, "r");
npy.seek(3);
CHECK(f.frames_in_file() == 7);
CHECK(npy.total_frames() == 10);
DetectorHeader header{};
NDArray<uint16_t, 2> image({static_cast<ssize_t>(f.rows()), static_cast<ssize_t>(f.cols())});
NDArray<uint16_t, 2> image(
{static_cast<ssize_t>(f.rows()), static_cast<ssize_t>(f.cols())});
for (size_t i = 0; i < 7; ++i) {
CHECK(f.tell() == i);
f.read_into(image.buffer(), &header);
// frame numbers start at 1 frame index at 0
// frame numbers start at 1 frame index at 0
// adding 3 + 1 to verify the frame number
CHECK(header.frameNumber == i + 4);
CHECK(header.frameNumber == i + 4);
auto npy_frame = npy.read_frame();
CHECK((image.view() == npy_frame.view<uint16_t>()));
}

View File

@ -161,12 +161,10 @@ TEST_CASE("cumsum works with negative numbers", "[algorithm]") {
REQUIRE(result[4] == -10);
}
TEST_CASE("cumsum on an empty vector", "[algorithm]") {
std::vector<double> vec = {};
auto result = aare::cumsum(vec);
REQUIRE(result.size() == 0);
}
TEST_CASE("All equal on an empty vector is false", "[algorithm]") {
@ -184,7 +182,8 @@ TEST_CASE("All equal on a vector with 2 elements is true", "[algorithm]") {
REQUIRE(aare::all_equal(vec) == true);
}
TEST_CASE("All equal on a vector with two different elements is false", "[algorithm]") {
TEST_CASE("All equal on a vector with two different elements is false",
"[algorithm]") {
std::vector<int> vec = {1, 2};
REQUIRE(aare::all_equal(vec) == false);
}

View File

@ -2,9 +2,9 @@
#include <cmath>
namespace aare {
uint16_t adc_sar_05_decode64to16(uint64_t input){
uint16_t adc_sar_05_decode64to16(uint64_t input) {
//we want bits 29,19,28,18,31,21,27,20,24,23,25,22 and then pad to 16
// we want bits 29,19,28,18,31,21,27,20,24,23,25,22 and then pad to 16
uint16_t output = 0;
output |= ((input >> 22) & 1) << 11;
output |= ((input >> 25) & 1) << 10;
@ -21,19 +21,21 @@ uint16_t adc_sar_05_decode64to16(uint64_t input){
return output;
}
void adc_sar_05_decode64to16(NDView<uint64_t, 2> input, NDView<uint16_t,2> output){
if(input.shape() != output.shape()){
throw std::invalid_argument(LOCATION + " input and output shapes must match");
void adc_sar_05_decode64to16(NDView<uint64_t, 2> input,
NDView<uint16_t, 2> output) {
if (input.shape() != output.shape()) {
throw std::invalid_argument(LOCATION +
" input and output shapes must match");
}
for(ssize_t i = 0; i < input.shape(0); i++){
for(ssize_t j = 0; j < input.shape(1); j++){
output(i,j) = adc_sar_05_decode64to16(input(i,j));
for (ssize_t i = 0; i < input.shape(0); i++) {
for (ssize_t j = 0; j < input.shape(1); j++) {
output(i, j) = adc_sar_05_decode64to16(input(i, j));
}
}
}
uint16_t adc_sar_04_decode64to16(uint64_t input){
uint16_t adc_sar_04_decode64to16(uint64_t input) {
// bit_map = array([15,17,19,21,23,4,6,8,10,12,14,16] LSB->MSB
uint16_t output = 0;
@ -52,20 +54,23 @@ uint16_t adc_sar_04_decode64to16(uint64_t input){
return output;
}
void adc_sar_04_decode64to16(NDView<uint64_t, 2> input, NDView<uint16_t,2> output){
if(input.shape() != output.shape()){
throw std::invalid_argument(LOCATION + " input and output shapes must match");
void adc_sar_04_decode64to16(NDView<uint64_t, 2> input,
NDView<uint16_t, 2> output) {
if (input.shape() != output.shape()) {
throw std::invalid_argument(LOCATION +
" input and output shapes must match");
}
for(ssize_t i = 0; i < input.shape(0); i++){
for(ssize_t j = 0; j < input.shape(1); j++){
output(i,j) = adc_sar_04_decode64to16(input(i,j));
for (ssize_t i = 0; i < input.shape(0); i++) {
for (ssize_t j = 0; j < input.shape(1); j++) {
output(i, j) = adc_sar_04_decode64to16(input(i, j));
}
}
}
double apply_custom_weights(uint16_t input, const NDView<double, 1> weights) {
if(weights.size() > 16){
throw std::invalid_argument("weights size must be less than or equal to 16");
if (weights.size() > 16) {
throw std::invalid_argument(
"weights size must be less than or equal to 16");
}
double result = 0.0;
@ -73,30 +78,30 @@ double apply_custom_weights(uint16_t input, const NDView<double, 1> weights) {
result += ((input >> i) & 1) * std::pow(weights[i], i);
}
return result;
}
void apply_custom_weights(NDView<uint16_t, 1> input, NDView<double, 1> output, const NDView<double,1> weights) {
if(input.shape() != output.shape()){
throw std::invalid_argument(LOCATION + " input and output shapes must match");
void apply_custom_weights(NDView<uint16_t, 1> input, NDView<double, 1> output,
const NDView<double, 1> weights) {
if (input.shape() != output.shape()) {
throw std::invalid_argument(LOCATION +
" input and output shapes must match");
}
//Calculate weights to avoid repeatedly calling std::pow
// Calculate weights to avoid repeatedly calling std::pow
std::vector<double> weights_powers(weights.size());
for (ssize_t i = 0; i < weights.size(); ++i) {
weights_powers[i] = std::pow(weights[i], i);
}
// Apply custom weights to each element in the input array
for (ssize_t i = 0; i < input.shape(0); i++) {
for (ssize_t i = 0; i < input.shape(0); i++) {
double result = 0.0;
for (size_t bit_index = 0; bit_index < weights_powers.size(); ++bit_index) {
for (size_t bit_index = 0; bit_index < weights_powers.size();
++bit_index) {
result += ((input(i) >> bit_index) & 1) * weights_powers[bit_index];
}
output(i) = result;
}
}
} // namespace aare

View File

@ -1,17 +1,16 @@
#include "aare/decode.hpp"
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <catch2/catch_test_macros.hpp>
#include "aare/NDArray.hpp"
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
using Catch::Matchers::WithinAbs;
#include <vector>
TEST_CASE("test_adc_sar_05_decode64to16"){
TEST_CASE("test_adc_sar_05_decode64to16") {
uint64_t input = 0;
uint16_t output = aare::adc_sar_05_decode64to16(input);
CHECK(output == 0);
// bit 29 on th input is bit 0 on the output
input = 1UL << 29;
output = aare::adc_sar_05_decode64to16(input);
@ -25,7 +24,6 @@ TEST_CASE("test_adc_sar_05_decode64to16"){
CHECK(output == (1 << i));
}
// test a few "random" values
input = 0;
input |= (1UL << 29);
@ -34,7 +32,6 @@ TEST_CASE("test_adc_sar_05_decode64to16"){
output = aare::adc_sar_05_decode64to16(input);
CHECK(output == 7UL);
input = 0;
input |= (1UL << 18);
input |= (1UL << 27);
@ -47,10 +44,9 @@ TEST_CASE("test_adc_sar_05_decode64to16"){
input |= (1UL << 22);
output = aare::adc_sar_05_decode64to16(input);
CHECK(output == 3072UL);
}
}
TEST_CASE("test_apply_custom_weights") {
TEST_CASE("test_apply_custom_weights") {
uint16_t input = 1;
aare::NDArray<double, 1> weights_data({3}, 0.0);
@ -60,7 +56,6 @@ TEST_CASE("test_adc_sar_05_decode64to16"){
auto weights = weights_data.view();
double output = aare::apply_custom_weights(input, weights);
CHECK_THAT(output, WithinAbs(1.0, 0.001));
@ -68,7 +63,6 @@ TEST_CASE("test_adc_sar_05_decode64to16"){
output = aare::apply_custom_weights(input, weights);
CHECK_THAT(output, WithinAbs(2.1, 0.001));
input = 1 << 2;
output = aare::apply_custom_weights(input, weights);
CHECK_THAT(output, WithinAbs(3.24, 0.001));
@ -76,5 +70,4 @@ TEST_CASE("test_adc_sar_05_decode64to16"){
input = 0b111;
output = aare::apply_custom_weights(input, weights);
CHECK_THAT(output, WithinAbs(6.34, 0.001));
}
}

View File

@ -5,15 +5,11 @@
#include <fmt/core.h>
namespace aare {
void assert_failed(const std::string &msg)
{
void assert_failed(const std::string &msg) {
fmt::print(msg);
exit(1);
}
/**
* @brief Convert a DetectorType to a string
* @param type DetectorType
@ -40,7 +36,7 @@ template <> std::string ToString(DetectorType arg) {
case DetectorType::Xilinx_ChipTestBoard:
return "Xilinx_ChipTestBoard";
//Custom ones
// Custom ones
case DetectorType::Moench03:
return "Moench03";
case DetectorType::Moench03_old:
@ -48,8 +44,8 @@ template <> std::string ToString(DetectorType arg) {
case DetectorType::Unknown:
return "Unknown";
//no default case to trigger compiler warning if not all
//enum values are handled
// no default case to trigger compiler warning if not all
// enum values are handled
}
throw std::runtime_error("Could not decode detector to string");
}
@ -80,14 +76,14 @@ template <> DetectorType StringTo(const std::string &arg) {
if (arg == "Xilinx_ChipTestBoard")
return DetectorType::Xilinx_ChipTestBoard;
//Custom ones
// Custom ones
if (arg == "Moench03")
return DetectorType::Moench03;
if (arg == "Moench03_old")
return DetectorType::Moench03_old;
if (arg == "Unknown")
return DetectorType::Unknown;
throw std::runtime_error("Could not decode detector from: \"" + arg + "\"");
}
@ -102,7 +98,8 @@ template <> TimingMode StringTo(const std::string &arg) {
return TimingMode::Auto;
if (arg == "trigger")
return TimingMode::Trigger;
throw std::runtime_error("Could not decode timing mode from: \"" + arg + "\"");
throw std::runtime_error("Could not decode timing mode from: \"" + arg +
"\"");
}
template <> FrameDiscardPolicy StringTo(const std::string &arg) {
@ -112,7 +109,8 @@ template <> FrameDiscardPolicy StringTo(const std::string &arg) {
return FrameDiscardPolicy::Discard;
if (arg == "discardpartial")
return FrameDiscardPolicy::DiscardPartial;
throw std::runtime_error("Could not decode frame discard policy from: \"" + arg + "\"");
throw std::runtime_error("Could not decode frame discard policy from: \"" +
arg + "\"");
}
// template <> TimingMode StringTo<TimingMode>(std::string mode);

View File

@ -3,12 +3,12 @@
#include <catch2/catch_test_macros.hpp>
#include <string>
using aare::ToString;
using aare::StringTo;
using aare::ToString;
TEST_CASE("Enum to string conversion") {
// TODO! By the way I don't think the enum string conversions should be in the defs.hpp file
// but let's use this to show a test
// TODO! By the way I don't think the enum string conversions should be in
// the defs.hpp file but let's use this to show a test
REQUIRE(ToString(aare::DetectorType::Generic) == "Generic");
REQUIRE(ToString(aare::DetectorType::Eiger) == "Eiger");
REQUIRE(ToString(aare::DetectorType::Gotthard) == "Gotthard");
@ -17,30 +17,42 @@ TEST_CASE("Enum to string conversion") {
REQUIRE(ToString(aare::DetectorType::Moench) == "Moench");
REQUIRE(ToString(aare::DetectorType::Mythen3) == "Mythen3");
REQUIRE(ToString(aare::DetectorType::Gotthard2) == "Gotthard2");
REQUIRE(ToString(aare::DetectorType::Xilinx_ChipTestBoard) == "Xilinx_ChipTestBoard");
REQUIRE(ToString(aare::DetectorType::Xilinx_ChipTestBoard) ==
"Xilinx_ChipTestBoard");
REQUIRE(ToString(aare::DetectorType::Moench03) == "Moench03");
REQUIRE(ToString(aare::DetectorType::Moench03_old) == "Moench03_old");
REQUIRE(ToString(aare::DetectorType::Unknown) == "Unknown");
}
TEST_CASE("String to enum"){
REQUIRE(StringTo<aare::DetectorType>("Generic") == aare::DetectorType::Generic);
TEST_CASE("String to enum") {
REQUIRE(StringTo<aare::DetectorType>("Generic") ==
aare::DetectorType::Generic);
REQUIRE(StringTo<aare::DetectorType>("Eiger") == aare::DetectorType::Eiger);
REQUIRE(StringTo<aare::DetectorType>("Gotthard") == aare::DetectorType::Gotthard);
REQUIRE(StringTo<aare::DetectorType>("Jungfrau") == aare::DetectorType::Jungfrau);
REQUIRE(StringTo<aare::DetectorType>("ChipTestBoard") == aare::DetectorType::ChipTestBoard);
REQUIRE(StringTo<aare::DetectorType>("Moench") == aare::DetectorType::Moench);
REQUIRE(StringTo<aare::DetectorType>("Mythen3") == aare::DetectorType::Mythen3);
REQUIRE(StringTo<aare::DetectorType>("Gotthard2") == aare::DetectorType::Gotthard2);
REQUIRE(StringTo<aare::DetectorType>("Xilinx_ChipTestBoard") == aare::DetectorType::Xilinx_ChipTestBoard);
REQUIRE(StringTo<aare::DetectorType>("Moench03") == aare::DetectorType::Moench03);
REQUIRE(StringTo<aare::DetectorType>("Moench03_old") == aare::DetectorType::Moench03_old);
REQUIRE(StringTo<aare::DetectorType>("Unknown") == aare::DetectorType::Unknown);
REQUIRE(StringTo<aare::DetectorType>("Gotthard") ==
aare::DetectorType::Gotthard);
REQUIRE(StringTo<aare::DetectorType>("Jungfrau") ==
aare::DetectorType::Jungfrau);
REQUIRE(StringTo<aare::DetectorType>("ChipTestBoard") ==
aare::DetectorType::ChipTestBoard);
REQUIRE(StringTo<aare::DetectorType>("Moench") ==
aare::DetectorType::Moench);
REQUIRE(StringTo<aare::DetectorType>("Mythen3") ==
aare::DetectorType::Mythen3);
REQUIRE(StringTo<aare::DetectorType>("Gotthard2") ==
aare::DetectorType::Gotthard2);
REQUIRE(StringTo<aare::DetectorType>("Xilinx_ChipTestBoard") ==
aare::DetectorType::Xilinx_ChipTestBoard);
REQUIRE(StringTo<aare::DetectorType>("Moench03") ==
aare::DetectorType::Moench03);
REQUIRE(StringTo<aare::DetectorType>("Moench03_old") ==
aare::DetectorType::Moench03_old);
REQUIRE(StringTo<aare::DetectorType>("Unknown") ==
aare::DetectorType::Unknown);
}
TEST_CASE("Enum values"){
//Since some of the enums are written to file we need to make sure
//they match the value in the slsDetectorPackage
TEST_CASE("Enum values") {
// Since some of the enums are written to file we need to make sure
// they match the value in the slsDetectorPackage
REQUIRE(static_cast<int>(aare::DetectorType::Generic) == 0);
REQUIRE(static_cast<int>(aare::DetectorType::Eiger) == 1);
@ -52,7 +64,7 @@ TEST_CASE("Enum values"){
REQUIRE(static_cast<int>(aare::DetectorType::Gotthard2) == 7);
REQUIRE(static_cast<int>(aare::DetectorType::Xilinx_ChipTestBoard) == 8);
//Not included
// Not included
REQUIRE(static_cast<int>(aare::DetectorType::Moench03) == 100);
}
@ -85,5 +97,6 @@ TEST_CASE("DynamicCluster creation") {
// double v3 = c2.get<double>(33 * 44 - 1);
// REQUIRE(aare::compare_floats<double>(123.11, v3));
// REQUIRE_THROWS_AS(c2.set(0, 1), std::invalid_argument); // set int to double
// REQUIRE_THROWS_AS(c2.set(0, 1), std::invalid_argument); // set int to
// double
// }

View File

@ -2,15 +2,16 @@
#include "aare/geo_helpers.hpp"
#include "fmt/core.h"
namespace aare{
namespace aare {
DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi) {
#ifdef AARE_VERBOSE
#ifdef AARE_VERBOSE
fmt::println("update_geometry_with_roi() called with ROI: {} {} {} {}",
roi.xmin, roi.xmax, roi.ymin, roi.ymax);
fmt::println("Geometry: {} {} {} {} {} {}",
geo.modules_x, geo.modules_y, geo.pixels_x, geo.pixels_y, geo.module_gap_row, geo.module_gap_col);
#endif
fmt::println("Geometry: {} {} {} {} {} {}", geo.modules_x, geo.modules_y,
geo.pixels_x, geo.pixels_y, geo.module_gap_row,
geo.module_gap_col);
#endif
int pos_y = 0;
int pos_y_increment = 0;
for (int row = 0; row < geo.modules_y; row++) {
@ -41,9 +42,9 @@ DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi) {
if (m.origin_y + m.height < roi.ymin) {
m.height = 0;
} else {
if ((roi.ymin > m.origin_y) && (roi.ymin < m.origin_y + m.height)) {
if ((roi.ymin > m.origin_y) &&
(roi.ymin < m.origin_y + m.height)) {
m.height -= roi.ymin - m.origin_y;
}
if (roi.ymax < m.origin_y + original_height) {
m.height -= m.origin_y + original_height - roi.ymax;
@ -51,9 +52,10 @@ DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi) {
m.origin_y = pos_y;
pos_y_increment = m.height;
}
#ifdef AARE_VERBOSE
fmt::println("Module {} {} {} {}", m.origin_x, m.origin_y, m.width, m.height);
#endif
#ifdef AARE_VERBOSE
fmt::println("Module {} {} {} {}", m.origin_x, m.origin_y, m.width,
m.height);
#endif
}
// increment pos_y
pos_y += pos_y_increment;
@ -65,7 +67,6 @@ DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi) {
geo.pixels_y = roi.height();
return geo;
}
} // namespace aare

View File

@ -1,6 +1,6 @@
#include "aare/File.hpp"
#include "aare/RawMasterFile.hpp" //needed for ROI
#include "aare/RawFile.hpp"
#include "aare/RawMasterFile.hpp" //needed for ROI
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
@ -8,26 +8,24 @@
#include "aare/geo_helpers.hpp"
#include "test_config.hpp"
TEST_CASE("Simple ROIs on one module"){
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi)
TEST_CASE("Simple ROIs on one module") {
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
// roi)
aare::DetectorGeometry geo;
aare::ModuleGeometry mod;
aare::ModuleGeometry mod;
mod.origin_x = 0;
mod.origin_y = 0;
mod.width = 1024;
mod.height = 512;
geo.pixels_x = 1024;
geo.pixels_y = 512;
geo.modules_x = 1;
geo.modules_y = 1;
geo.module_pixel_0.push_back(mod);
SECTION("ROI is the whole module"){
SECTION("ROI is the whole module") {
aare::ROI roi;
roi.xmin = 0;
roi.xmax = 1024;
@ -42,7 +40,7 @@ TEST_CASE("Simple ROIs on one module"){
REQUIRE(updated_geo.module_pixel_0[0].height == 512);
REQUIRE(updated_geo.module_pixel_0[0].width == 1024);
}
SECTION("ROI is the top left corner of the module"){
SECTION("ROI is the top left corner of the module") {
aare::ROI roi;
roi.xmin = 100;
roi.xmax = 200;
@ -58,7 +56,7 @@ TEST_CASE("Simple ROIs on one module"){
REQUIRE(updated_geo.module_pixel_0[0].width == 100);
}
SECTION("ROI is a small square"){
SECTION("ROI is a small square") {
aare::ROI roi;
roi.xmin = 1000;
roi.xmax = 1010;
@ -73,7 +71,7 @@ TEST_CASE("Simple ROIs on one module"){
REQUIRE(updated_geo.module_pixel_0[0].height == 10);
REQUIRE(updated_geo.module_pixel_0[0].width == 10);
}
SECTION("ROI is a few columns"){
SECTION("ROI is a few columns") {
aare::ROI roi;
roi.xmin = 750;
roi.xmax = 800;
@ -90,14 +88,12 @@ TEST_CASE("Simple ROIs on one module"){
}
}
TEST_CASE("Two modules side by side"){
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi)
TEST_CASE("Two modules side by side") {
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
// roi)
aare::DetectorGeometry geo;
aare::ModuleGeometry mod;
aare::ModuleGeometry mod;
mod.origin_x = 0;
mod.origin_y = 0;
mod.width = 1024;
@ -112,7 +108,7 @@ TEST_CASE("Two modules side by side"){
mod.origin_x = 1024;
geo.module_pixel_0.push_back(mod);
SECTION("ROI is the whole image"){
SECTION("ROI is the whole image") {
aare::ROI roi;
roi.xmin = 0;
roi.xmax = 2048;
@ -125,7 +121,7 @@ TEST_CASE("Two modules side by side"){
REQUIRE(updated_geo.modules_x == 2);
REQUIRE(updated_geo.modules_y == 1);
}
SECTION("rectangle on both modules"){
SECTION("rectangle on both modules") {
aare::ROI roi;
roi.xmin = 800;
roi.xmax = 1300;
@ -141,11 +137,12 @@ TEST_CASE("Two modules side by side"){
REQUIRE(updated_geo.module_pixel_0[0].width == 224);
REQUIRE(updated_geo.module_pixel_0[1].height == 299);
REQUIRE(updated_geo.module_pixel_0[1].width == 276);
}
}
}
TEST_CASE("Three modules side by side"){
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi)
TEST_CASE("Three modules side by side") {
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
// roi)
aare::DetectorGeometry geo;
aare::ROI roi;
roi.xmin = 700;
@ -153,7 +150,7 @@ TEST_CASE("Three modules side by side"){
roi.ymin = 0;
roi.ymax = 123;
aare::ModuleGeometry mod;
aare::ModuleGeometry mod;
mod.origin_x = 0;
mod.origin_y = 0;
mod.width = 1024;
@ -184,8 +181,9 @@ TEST_CASE("Three modules side by side"){
REQUIRE(updated_geo.module_pixel_0[2].width == 452);
}
TEST_CASE("Four modules as a square"){
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI roi)
TEST_CASE("Four modules as a square") {
// DetectorGeometry update_geometry_with_roi(DetectorGeometry geo, aare::ROI
// roi)
aare::DetectorGeometry geo;
aare::ROI roi;
roi.xmin = 500;
@ -193,7 +191,7 @@ TEST_CASE("Four modules as a square"){
roi.ymin = 500;
roi.ymax = 600;
aare::ModuleGeometry mod;
aare::ModuleGeometry mod;
mod.origin_x = 0;
mod.origin_y = 0;
mod.width = 1024;

View File

@ -10,7 +10,7 @@ std::string ifstream_error_msg(std::ifstream &ifs) {
return " Bad file stream";
} else if (state & std::ios_base::failbit) {
return " File read failed";
}else{
} else {
return " Unknown/no error";
}
}

View File

@ -1,10 +1,9 @@
#include "aare/utils/task.hpp"
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
TEST_CASE("Split a range into multiple tasks"){
TEST_CASE("Split a range into multiple tasks") {
auto tasks = aare::split_task(0, 10, 3);
REQUIRE(tasks.size() == 3);
@ -22,11 +21,8 @@ TEST_CASE("Split a range into multiple tasks"){
tasks = aare::split_task(0, 10, 10);
REQUIRE(tasks.size() == 10);
for (int i = 0; i < 10; i++){
for (int i = 0; i < 10; i++) {
REQUIRE(tasks[i].first == i);
REQUIRE(tasks[i].second == i+1);
REQUIRE(tasks[i].second == i + 1);
}
}