moved anglecalibration stuff to own repository still keep some changes

This commit is contained in:
2025-06-20 21:28:35 +02:00
parent 1c7b9b7121
commit f0e1ed3e2a
13 changed files with 0 additions and 1860 deletions

View File

@ -62,7 +62,6 @@ option(AARE_FETCH_CATCH "Use FetchContent to download catch2" ON)
option(AARE_FETCH_JSON "Use FetchContent to download nlohmann::json" ON)
option(AARE_FETCH_ZMQ "Use FetchContent to download libzmq" ON)
option(AARE_FETCH_LMFIT "Use FetchContent to download lmfit" ON)
option(AARE_FETCH_HDF5 "Use FetchContent to download hdf5-devel" OFF)
#Convenience option to use system libraries only (no FetchContent)
@ -74,7 +73,6 @@ if(AARE_SYSTEM_LIBRARIES)
set(AARE_FETCH_CATCH OFF CACHE BOOL "Disabled FetchContent for catch2" FORCE)
set(AARE_FETCH_JSON OFF CACHE BOOL "Disabled FetchContent for nlohmann::json" FORCE)
set(AARE_FETCH_ZMQ OFF CACHE BOOL "Disabled FetchContent for libzmq" FORCE)
set(AARE_FETCH_HDF5 OFF CACHE BOOL "Disabled FetchContent for hdf5" FORCE)
# Still fetch lmfit when setting AARE_SYSTEM_LIBRARIES since this is not available
# on conda-forge
endif()
@ -221,23 +219,6 @@ else()
find_package(nlohmann_json 3.11.3 REQUIRED)
endif()
if(AARE_FETCH_HDF5)
message(FATAL_ERROR "Fetching HDF5 via FetchContent is not supported here. Please install it via your system.
For Ubuntu: sudo apt install libhdf5-dev
For Red Hat: sudo dnf install hdf5-devel
For MacOS: brew install hdf5")
else()
find_package(HDF5 QUIET COMPONENTS CXX)
if (HDF5_FOUND)
message(STATUS "Found HDF5: ${HDF5_INCLUDE_DIRS}")
else()
message(FATAL_ERROR "HDF5 was NOT found! Please install it via your system
For Ubuntu: sudo apt install libhdf5-dev
For Red Hat: sudo dnf install hdf5-devel
For MacOS: brew install hdf5")
endif()
endif()
include(GNUInstallDirs)
# If conda build, always set lib dir to 'lib'
@ -359,7 +340,6 @@ endif()
###------------------------------------------------------------------------------------------
set(PUBLICHEADERS
include/aare/AngleCalibration.hpp
include/aare/ArrayExpr.hpp
include/aare/CalculateEta.hpp
include/aare/Cluster.hpp
@ -367,7 +347,6 @@ set(PUBLICHEADERS
include/aare/ClusterFile.hpp
include/aare/CtbRawFile.hpp
include/aare/ClusterVector.hpp
include/aare/CustomFiles.hpp
include/aare/decode.hpp
include/aare/defs.hpp
include/aare/Dtype.hpp
@ -375,14 +354,10 @@ set(PUBLICHEADERS
include/aare/Fit.hpp
include/aare/FileInterface.hpp
include/aare/FilePtr.hpp
include/aare/FlatField.hpp
include/aare/Frame.hpp
include/aare/GainMap.hpp
include/aare/geo_helpers.hpp
include/aare/Hdf5FileReader.hpp
include/aare/JungfrauDataFile.hpp
include/aare/MythenDetectorSpecifications.hpp
include/aare/MythenFileReader.hpp
include/aare/NDArray.hpp
include/aare/NDView.hpp
include/aare/NumpyFile.hpp
@ -398,9 +373,7 @@ set(PUBLICHEADERS
set(SourceFiles
${CMAKE_CURRENT_SOURCE_DIR}/src/AngleCalibration.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/CtbRawFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/CustomFiles.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/defs.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/decode.cpp
@ -417,7 +390,6 @@ set(SourceFiles
${CMAKE_CURRENT_SOURCE_DIR}/src/RawFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/RawSubFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/RawMasterFile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/task.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/ifstream_helpers.cpp
)
@ -436,13 +408,11 @@ target_link_libraries(
PUBLIC
fmt::fmt
nlohmann_json::nlohmann_json
HDF5::HDF5
${STD_FS_LIB} # from helpers.cmake
PRIVATE
aare_compiler_flags
Threads::Threads
$<BUILD_INTERFACE:lmfit>
)
set_target_properties(aare_core PROPERTIES
@ -457,14 +427,12 @@ endif()
if(AARE_TESTS)
set(TestSources
${CMAKE_CURRENT_SOURCE_DIR}/src/algorithm.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/AngleCalibration.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/defs.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/decode.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Dtype.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Frame.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/geo_helpers.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/RawMasterFile.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Hdf5FileReader.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/NDArray.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/NDView.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFinder.test.cpp
@ -475,7 +443,6 @@ if(AARE_TESTS)
${CMAKE_CURRENT_SOURCE_DIR}/src/ClusterFinderMT.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Pedestal.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/JungfrauDataFile.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/MythenFileReader.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyFile.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/NumpyHelpers.test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/RawFile.test.cpp

View File

@ -1,64 +0,0 @@
from slsdet import Mythen3,timingMode,detectorSettings,runStatus,dacIndex,scanParameters
#from patterntools.zmqreceiver import ZmqReceiver
#from detConf_module import *
import numpy as np
from slsdet.lookup import view, find
from epics import caput, caget
import time
d = Mythen3()
#d.detsize = [10, 1]
d.hostname = 'localhost:2000+localhost:2002'
d.rx_hostname = 'localhost'
#d.rx_tcpport = 2012
d.udp_dstport = 5006
d.udp_dstip = 'auto'
d.udp_srcip = 'auto'
#rx=makeReceiver(d)
nmod=len(d.hostname)
print("num modules: ", nmod)
d.frames = 3
d.exptime = 5
d.fwrite=1
#d.counters = [0, 1]
print(d.counters)
d.fpath = "~/Documents/tmp/Flatfieldacquisition"
d.fwrite = 1
#where do i set the strips?
#d.detsize = 2 do I have to set this
d.startReceiver()
d.startDetector()
for angle in [87,2]:
d.fname = 'run_'+str(angle)
caput('BL11I-MO-DIFF-01:DELTA.VAL',angle,wait=False)
print("moving detector to ",angle)
d.acquire()
time.sleep(d.exptime)
while d.status != runStatus.IDLE:
time.sleep(0.01)
nf=np.min(d.rx_framescaught)
ang=caget('BL11I-MO-DIFF-01:DELTA.RBV')
print("angle is: ", ang)
print("caught frames: ", nf)
d.stopReceiver()
#dd, hh = rx[imod].receive_one_frame() what is this - does this exist in cpp?

View File

@ -1,164 +0,0 @@
#pragma once
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "FlatField.hpp"
#include "MythenDetectorSpecifications.hpp"
#include "MythenFileReader.hpp"
#include "NDArray.hpp"
namespace aare {
using parameters =
std::tuple<std::vector<double>, std::vector<double>, std::vector<double>>;
class AngleCalibration {
public:
AngleCalibration(
std::shared_ptr<MythenDetectorSpecifications> mythen_detector_,
std::shared_ptr<FlatField> flat_field_,
std::shared_ptr<MythenFileReader> mythen_file_reader_);
/** set the histogram bin width [degrees] */
void set_histogram_bin_width(double bin_width);
double get_histogram_bin_width() const;
ssize_t get_new_num_bins() const;
/** reads the historical Detector Group (DG) parameters from file **/
void read_initial_calibration_from_file(const std::string &filename);
std::vector<double> get_centers() const;
std::vector<double> get_conversions() const;
std::vector<double> get_offsets() const;
NDView<double, 1> get_new_photon_counts() const;
NDView<double, 1> get_new_statistical_errors() const;
/** converts DG parameters to easy EE parameters e.g.geometric
* parameters */
parameters convert_to_EE_parameters() const;
std::tuple<double, double, double>
convert_to_EE_parameters(const size_t module_index) const;
std::tuple<double, double, double>
convert_to_EE_parameters(const double center, const double conversion,
const double offset) const;
/** converts DG parameters to BC parameters e.g. best computing
* parameters */
parameters convert_to_BC_parameters() const;
/**
* calculates new histogram with fixed sized angle bins
* for several acquisitions at different detector angles for given frame
* indices
* @param start_frame_index, end_frame_index gives range of frames
*/
void
calculate_fixed_bin_angle_width_histogram(const size_t start_frame_index,
const size_t end_frame_index);
void write_to_file(const std::string &filename,
const bool store_nonzero_bins = false,
const std::filesystem::path &filepath =
std::filesystem::current_path()) const;
/** calculates diffraction angle from EE module parameters (used in
* Beer's Law)
* @param strip_index local strip index of module
*/
double diffraction_angle_from_EE_parameters(
const double module_center_distance, const double normal_distance,
const double angle, const size_t strip_index,
const double distance_to_strip = 0) const;
/** calculates diffraction angle from EE module parameters (used in
* Beer's Law)
* @param center module center
* @param conversion module conversion
* @param offset module offset
* @param strip_index local strip index of module
* @param distance_to_strip distance to strip given by strip_index and
* module -> note needs to be small enough to be in the respective module
*/
double diffraction_angle_from_DG_parameters(
const double center, const double conversion, const double offset,
const size_t strip_index, const double distance_to_strip = 0) const;
/** calculated the strip width expressed as angle [degrees]
* @param strip_index local strip index of module
*/
double angular_strip_width_from_DG_parameters(
const double center, const double conversion, const double offset,
const size_t local_strip_index) const;
double angular_strip_width_from_EE_parameters(
const double module_center_distance, const double normal_distance,
const double angle, const size_t local_strip_index) const;
protected:
/** converts global strip index to local strip index of that module */
size_t global_to_local_strip_index_conversion(
const size_t global_strip_index) const;
/**
* redistributes photon counts with of histogram using one bin per strip
* to histogram with fixed size angle bins
* @param frame MythenFrame storing data from image
* @param bin_counts accumulate new photon counts
* @param new_statistical_weights accumulate new statistical weights
* @param new_errors accumulate new_errors
*/
void redistribute_photon_counts_to_fixed_angle_bins(
const MythenFrame &frame, NDView<double, 1> bin_counts,
NDView<double, 1> new_statistical_weights, NDView<double, 1> new_errors,
NDView<double, 1> inverse_nromalized_flatfield) const;
private:
// TODO: Design maybe have a struct with three vectors, store all three
// sets of parameters as member variables
// TODO: check if interpretation and units are correct
// historical DG parameters
// TODO change to NDArray
std::vector<double> centers; // orthogonal projection of sample onto
// detector (given in strip number) [mm]
// D/pitch
std::vector<double> conversions; // pitch/(normal distance from sample
// to detector (R)) [mm]
// //used for easy conversion
std::vector<double>
offsets; // position of strip zero relative to sample [degrees] phi
// - 180/pi*D/R TODO: expected an arcsin(D/R)?
std::shared_ptr<MythenDetectorSpecifications> mythen_detector;
std::shared_ptr<FlatField> flat_field;
NDArray<double, 1> new_photon_counts;
NDArray<double, 1> new_photon_count_errors;
double histogram_bin_width = 0.0036; // [degrees]
ssize_t num_bins{};
std::shared_ptr<MythenFileReader>
mythen_file_reader; // TODO replace by FileInterface ptr
};
} // namespace aare

View File

@ -1,59 +0,0 @@
#include "Dtype.hpp"
#include "FileInterface.hpp"
#include <cstdint>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
namespace aare {
// TODO a lot to overload
class CustomMythenFile : public FileInterface {
public:
CustomMythenFile(const std::string &filename, const ssize_t rows,
const ssize_t cols = 1, const std::string &mode = "r");
~CustomMythenFile();
Frame read_frame() override;
Frame read_frame(size_t frame_number) override;
std::vector<Frame> read_n(size_t n_frames) override;
void read_into(std::byte *image_buf) override;
void read_into(std::byte *image_buf, size_t n_frames) override;
size_t frame_number(size_t frame_index) override;
size_t bytes_per_frame() override;
size_t pixels_per_frame() override;
void seek(size_t frame_number) override;
size_t tell() override;
size_t total_frames() const override;
size_t rows() const override;
size_t cols() const override;
size_t bitdepth() const override;
DetectorType detector_type() const override;
private:
std::string m_filename{};
std::ifstream m_file{};
ssize_t m_num_strips{};
// uint8_t m_num_counts{}; TODO extend
ssize_t m_rows{};
ssize_t m_cols{};
static const Dtype m_dtype;
static const DetectorType det_type = DetectorType::Mythen3;
};
} // namespace aare

View File

@ -1,215 +0,0 @@
/**
* stores flatfield for angle calibration
*/
#pragma once
#include <cmath>
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include "File.hpp"
#include "MythenDetectorSpecifications.hpp"
#include "NDArray.hpp"
namespace aare {
template <class CustomFile> struct custom_file_compatibility {
static constexpr bool value =
std::is_base_of<FileInterface, CustomFile>::value &&
std::is_constructible<CustomFile, std::string, ssize_t, ssize_t,
std::string>::value;
};
template <class CustomFile>
constexpr bool custom_file_compatibility_v =
custom_file_compatibility<CustomFile>::value;
class FlatField {
public:
FlatField(std::shared_ptr<MythenDetectorSpecifications> mythen_detector_)
: mythen_detector(mythen_detector_) {
flat_field = NDArray<uint32_t, 1>(
std::array<ssize_t, 1>{mythen_detector->num_strips()}, 0);
}
/**
* @brief sums up the photon counts for multiple acquisitions
* @param file_path: path to filesystem - the filesystem should contain
* multiple acqisitions for different detector angles acquired using
* slsReceiver and mythen3Detector //TODO: constructor needs to be the same
* - ugly
*/
// TODO unsure about design - maybe scientist has to give file with paths
// one wants to accumulate - what to do with strange file format?
// TODO: adjust for different counters!!!!
void create_flatfield_from_rawfilesystem(
const std::filesystem::path &file_path) {
try {
for (const auto &file_in_path :
std::filesystem::recursive_directory_iterator(file_path)) {
if (file_in_path.is_regular_file()) {
std::string filename =
file_in_path.path().filename().string();
if (filename.find("master") != std::string::npos) {
File f(file_in_path);
auto frames = f.read_n(f.total_frames());
for (const auto &frame : frames) {
if (frame.rows() * frame.cols() !=
mythen_detector->num_strips() *
mythen_detector->num_counters()) {
throw std::runtime_error(fmt::format(
"sizes mismatch. Expect a size of "
"{} - frame has a size of {}",
mythen_detector->num_strips() *
mythen_detector->num_counters(),
frame.rows() * frame.cols()));
}
for (ssize_t row = 0; row < frame.rows(); ++row)
for (ssize_t col = 0; col < frame.cols();
++col) {
flat_field(row * frame.cols() + col) +=
*reinterpret_cast<uint32_t *>(
frame.pixel_ptr(
row,
col)); // TODO inefficient as
// one has to copy twice
// into frame and into
// flat_field
}
}
}
}
}
} catch (const std::filesystem::filesystem_error &e) {
std::cerr << "Filesystem error: " << e.what()
<< '\n'; // TODO replace with log
} catch (const std::exception &e) {
std::cerr << "Runtime error: " << e.what() << '\n';
}
}
/**
* @brief sums up the photon counts for multiple acquisitions
* @param filelist: path to file that stores the file paths to the aquired
* data the list should contain multiple acquisitions for different detector
* angles
* @tparam CustomFile: Fileclass that inherits from aare::FileInterface
* class needs to overload read_frame and constructor needs to have the
* signature CustomFile(std::string filename, ssize_t rows, ssize_t cols,
* std::string reading_mode) rows, and cols define the intended image size
* to read
*/
template <class CustomFile,
typename = std::enable_if_t<
custom_file_compatibility_v<CustomFile>, void>>
void create_flatfield_from_filelist(const std::filesystem::path &filelist) {
std::ifstream file_filelist(filelist);
try {
std::string filename;
while (std::getline(file_filelist, filename)) {
CustomFile file(filename, mythen_detector->num_strips(), 1);
Frame frame = file.read_frame();
if (frame.rows() * frame.cols() !=
mythen_detector->num_strips()) {
throw std::runtime_error(
fmt::format("sizes mismatch. Expect a size of "
"{} - frame has a size of {}",
mythen_detector->num_strips(),
frame.rows() * frame.cols()));
}
for (ssize_t row = 0; row < frame.rows(); ++row)
for (ssize_t col = 0; col < frame.cols(); ++col) {
flat_field(row * frame.cols() + col) +=
*reinterpret_cast<uint32_t *>(frame.pixel_ptr(
row,
col)); // TODO inefficient as one has to copy
// twice into frame and into flat_field
}
}
file_filelist.close();
} catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << '\n';
}
}
/**
* @tparam CustomFile: Fileclass that inherits from aare::FileInterface
* class needs to overload read_frame and constructor needs to have the
* signature CustomFile(std::string filename, ssize_t rows, ssize_t cols,
* std::string reading_mode) rows, and cols define the intended image size
* to read
*/
template <class CustomFile,
typename = std::enable_if_t<
custom_file_compatibility_v<CustomFile>, void>>
void read_flatfield_from_file(const std::string &filename) {
CustomFile file(filename, mythen_detector->num_strips(), 1);
file.read_into(reinterpret_cast<std::byte *>(flat_field.data()));
}
NDView<uint32_t, 1> get_flatfield() const { return flat_field.view(); }
// TODO: remove tolerance
double calculate_mean(double tolerance) const {
auto [sum, count] = std::accumulate(
flat_field.begin(), flat_field.end(),
std::make_pair<double, ssize_t>(0.0, 0),
[&tolerance](std::pair<double, ssize_t> acc, const auto &element) {
return element == 0 ? acc
: std::make_pair(acc.first + element,
acc.second + 1);
});
return sum / count;
}
NDArray<double, 1>
inverse_normalized_flatfield(double tolerance = 0.0001) const {
double mean = calculate_mean(tolerance);
NDArray<double, 1> inverse_normalized_flatfield(flat_field.shape());
for (ssize_t i = 0; i < flat_field.size(); ++i) {
inverse_normalized_flatfield[i] =
(flat_field[i] <= tolerance ? 0.0 : mean / flat_field[i]);
if (inverse_normalized_flatfield[i] < tolerance)
mythen_detector->get_bad_channels()[i] = true;
}
return inverse_normalized_flatfield; // TODO: better to have a copy in
// this context but unneccessary
// for angle calibration code
// maybe provide inplace and copy option
// maybe store as member variable access with view
}
NDArray<double, 1> normalized_flatfield(double tolerance = 0.0001) const {
double mean = calculate_mean(tolerance);
NDArray<double, 1> normalized_flatfield(flat_field.shape());
for (ssize_t i = 0; i < flat_field.size(); ++i) {
normalized_flatfield[i] = (flat_field[i] == flat_field[i] / mean);
if (normalized_flatfield[i] < tolerance)
mythen_detector->get_bad_channels()[i] = true;
}
return normalized_flatfield;
}
private:
NDArray<uint32_t, 1> flat_field; // TODO: should be 2d
std::shared_ptr<MythenDetectorSpecifications> mythen_detector;
};
} // namespace aare

View File

@ -1,212 +0,0 @@
/************************************************
* @file HD5FFileReader.hpp
* @short HDF5FileReader based on H5File object
***********************************************/
#pragma once
#include "Frame.hpp"
#include "NDArray.hpp"
#include <H5Cpp.h>
#include <array>
#include <cxxabi.h>
#include <optional>
namespace aare {
// return std::type_info
inline const std::type_info &deduce_cpp_type(const H5::DataType datatype) {
if (H5Tequal(datatype.getId(), H5::PredType::NATIVE_UINT8.getId())) {
return typeid(uint8_t);
} else if (H5Tequal(datatype.getId(),
H5::PredType::NATIVE_UINT16.getId())) {
return typeid(uint16_t);
} else if (H5Tequal(datatype.getId(),
H5::PredType::NATIVE_UINT32.getId())) {
return typeid(uint32_t);
} else if (H5Tequal(datatype.getId(),
H5::PredType::NATIVE_UINT64.getId())) {
return typeid(uint64_t);
} else if (H5Tequal(datatype.getId(), H5::PredType::NATIVE_INT8.getId())) {
return typeid(int8_t);
} else if (H5Tequal(datatype.getId(), H5::PredType::NATIVE_INT16.getId())) {
return typeid(int16_t);
} else if (H5Tequal(datatype.getId(), H5::PredType::NATIVE_INT32.getId())) {
return typeid(int32_t);
} else if (H5Tequal(datatype.getId(), H5::PredType::NATIVE_INT64.getId())) {
return typeid(int64_t);
} else if (H5Tequal(datatype.getId(), H5::PredType::NATIVE_INT.getId())) {
return typeid(int);
} else if (H5Tequal(datatype.getId(), H5::PredType::IEEE_F64LE.getId())) {
return typeid(double);
} else if (H5Tequal(datatype.getId(), H5::PredType::IEEE_F32LE.getId())) {
return typeid(float);
} else if (H5Tequal(datatype.getId(), H5::PredType::NATIVE_FLOAT.getId())) {
return typeid(float);
} else if (H5Tequal(datatype.getId(),
H5::PredType::NATIVE_DOUBLE.getId())) {
return typeid(float);
} else if (H5Tequal(datatype.getId(), H5::PredType::NATIVE_CHAR.getId()) &&
datatype.getId() == H5::PredType::NATIVE_CHAR.getId()) {
return typeid(char);
} else {
throw std::runtime_error("c++ type cannot be deduced");
}
}
struct Subset {
std::vector<hsize_t> shape;
std::vector<hsize_t> offset; // index where data subset should start
};
class HDF5Dataset {
public:
HDF5Dataset(const std::string &datasetname_, const H5::DataSet dataset_)
: datasetname(datasetname_), dataset(dataset_) {
datatype = dataset.getDataType();
cpp_type = &deduce_cpp_type(datatype);
dataspace = dataset.getSpace();
rank = dataspace.getSimpleExtentNdims(); // number of dimensions
shape.resize(rank);
dataspace.getSimpleExtentDims(shape.data(), nullptr);
}
hsize_t get_shape(ssize_t index) const { return shape[index]; }
std::vector<hsize_t> get_shape() const { return shape; }
H5::DataType get_datatype() const { return datatype; }
const std::type_info *get_cpp_type() const { return cpp_type; }
/**
* Reads subset of dataset into the buffer
* e.g. to read one 2d frame pass Subset({shape[1], shape[2]}, {frame_index,
* 0,0})
*/
void
read_into_buffer(std::byte *buffer,
std::optional<const Subset> subset = std::nullopt) const {
if (subset) {
// TODO treat scalar cases
if (static_cast<ssize_t>(subset->offset.size()) != rank) {
throw std::runtime_error("provide an offset for" +
std::to_string(rank) + "dimensions");
}
for (ssize_t i = 0; i < rank; ++i) {
hsize_t size =
i < rank - static_cast<ssize_t>(subset->shape.size())
? 0
: subset->shape[i - (rank - subset->shape.size())];
if ((size + subset->offset[i]) > shape[i]) {
throw std::runtime_error(
"subset is too large or offset is out of bounds");
}
}
H5::DataSpace memspace(static_cast<int>(subset->shape.size()),
subset->shape.data());
dataspace.selectHyperslab(H5S_SELECT_SET, subset->shape.data(),
subset->offset.data());
dataset.read(buffer, datatype, memspace, dataspace);
} else {
dataset.read(buffer, datatype);
}
}
Frame store_as_frame() const {
uint32_t rows{}, cols{};
if (rank == 1) {
rows = 1;
// TODO overflow
cols = static_cast<uint32_t>(shape[0]);
} else if (rank == 2) {
rows = static_cast<uint32_t>(shape[0]);
cols = static_cast<uint32_t>(shape[1]);
} else {
throw std::runtime_error("Frame only supports 2d images");
}
Frame frame(rows, cols, Dtype(*cpp_type));
read_into_buffer(frame.data());
return frame;
}
template <typename T, ssize_t NDim>
NDArray<T, NDim> store_as_ndarray() const {
if (NDim != rank) {
std::cout
<< "Warning: dataset dimension and array dimension mismatch"
<< std::endl; // TODO: replace with log - still valid if we
// want subset
}
if (typeid(T) != *cpp_type) {
std::cout << "Warning: dataset and array type mismatch"
<< std::endl;
}
std::array<ssize_t, NDim> array_shape{};
std::transform(
shape.begin(), shape.end(), array_shape.begin(),
[](const auto dim) { return static_cast<ssize_t>(dim); });
aare::NDArray<T, NDim> dataset_array(array_shape);
read_into_buffer(reinterpret_cast<std::byte *>(dataset_array.data()));
return dataset_array;
}
// getMemDataSize()
private:
std::string datasetname{};
H5::DataSet dataset;
H5::DataSpace dataspace;
H5::DataType datatype;
const std::type_info *cpp_type;
ssize_t rank{};
std::vector<hsize_t> shape{};
};
class HDF5FileReader {
public:
HDF5FileReader() = default;
void open_file(const std::string &filename_) {
filename = filename_;
try {
file = H5::H5File(filename, H5F_ACC_RDONLY);
} catch (H5::Exception &e) {
std::cerr << "Error: " << e.getDetailMsg() << std::endl;
}
}
void close_file() { file.close(); }
HDF5Dataset get_dataset(const std::string &dataset_name) const {
H5::DataSet dataset;
try {
dataset = file.openDataSet(dataset_name);
} catch (H5::Exception &e) {
std::cerr << "Error: " << e.getDetailMsg() << std::endl;
}
// TODO use optional to handle error
return HDF5Dataset(dataset_name, dataset);
}
private:
std::string filename{};
H5::H5File file;
};
} // namespace aare

View File

@ -1,157 +0,0 @@
#pragma once
#include <cmath>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include "NDArray.hpp"
namespace aare {
class MythenDetectorSpecifications {
public:
// TODO: constructor that reads from a config file
MythenDetectorSpecifications() {
num_strips_ = max_modules_ * strips_per_module_;
num_connected_modules_ = max_modules_;
bad_channels =
NDArray<bool, 1>(std::array<ssize_t, 1>{num_strips_}, false);
connected_modules = NDArray<bool, 1>(
std::array<ssize_t, 1>{static_cast<ssize_t>(max_modules_)}, true);
}
MythenDetectorSpecifications(const size_t max_modules,
const double exposure_time,
const double num_counters = 1,
double bloffset = 1.532)
: max_modules_(max_modules), num_counters_(num_counters),
exposure_time_(exposure_time), bloffset_(bloffset) {
num_strips_ = max_modules_ * strips_per_module_;
num_connected_modules_ = max_modules_;
bad_channels =
NDArray<bool, 1>(std::array<ssize_t, 1>{num_strips_}, false);
connected_modules = NDArray<bool, 1>(
std::array<ssize_t, 1>{static_cast<ssize_t>(max_modules_)}, true);
}
// TODO templated on filereader
void read_bad_channels_from_file(const std::string &filename) {
std::string line;
try {
std::ifstream file(filename, std::ios_base::in);
if (!file.good()) {
throw std::logic_error("file does not exist");
}
while (std::getline(file, line)) {
std::size_t pos = line.find("-");
if (pos == std::string::npos) {
bad_channels(std::stoi(line)) = true;
} else {
size_t line_size = line.size();
for (int i = std::stoi(line.substr(0, pos));
i <= std::stoi(line.substr(pos + 1, line_size - pos));
++i)
bad_channels(i) = true;
}
}
file.close();
} catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
// TODO template on filereader
void read_unconnected_modules_from_file(const std::string &filename) {
std::string line;
try {
std::ifstream file(filename, std::ios_base::in);
if (!file.good()) {
throw std::logic_error("file does not exist");
}
std::stringstream file_buffer;
file_buffer << file.rdbuf();
file_buffer >> line;
num_connected_modules_ -= std::stoi(line);
while (file_buffer >> line) {
size_t module = std::stoi(line);
connected_modules[module] = false;
for (size_t i = module * strips_per_module_;
i < (module + 1) * strips_per_module_; ++i)
bad_channels[i] = true;
}
} catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
NDView<bool, 1> get_bad_channels() const { return bad_channels.view(); }
NDView<bool, 1> get_connected_modules() const {
return connected_modules.view();
}
static constexpr double pitch() { return pitch_; }
static constexpr size_t strips_per_module() { return strips_per_module_; }
size_t max_modules() const { return max_modules_; }
size_t num_counters() const { return num_counters_; }
double exposure_time() const { return exposure_time_; }
double bloffset() const { return bloffset_; }
double dtt0() const { return dtt0_; }
static constexpr double min_angle() { return min_angle_; }
static constexpr double max_angle() { return max_angle_; }
ssize_t num_strips() const { return num_strips_; }
private:
static constexpr size_t strips_per_module_ = 1280;
static constexpr double pitch_ = 0.05; // strip width [mm]
static constexpr double min_angle_ =
-180.0; // maybe shoudnt be static but configurable
static constexpr double max_angle_ = 180.0;
static constexpr double dtt0_ =
0.0; // No idea what this is - probably configurable
size_t max_modules_ = 48;
size_t num_counters_ = 1;
double exposure_time_ = 5.0; // TODO: could read from acquired file but
// maybe should be configurable
double bloffset_ = 1.532; // what is this? detector offset relative to what?
size_t num_connected_modules_{};
ssize_t num_strips_{};
NDArray<bool, 1> bad_channels;
NDArray<bool, 1> connected_modules; // connected modules
};
} // namespace aare

View File

@ -1,82 +0,0 @@
/************************************************
* @file MythenFileReader.hpp
* @short minimal file reader to read mythen files
***********************************************/
#include <bitset>
#include <filesystem>
#include <string>
#include "Hdf5FileReader.hpp"
#include "NDArray.hpp"
namespace aare {
struct MythenFrame {
NDArray<uint32_t, 1> photon_counts;
double detector_angle{};
// double reference_intensity{}; not needed
std::array<uint8_t, 3> channel_mask{};
};
/** minimal version for a mythen file reader */
class MythenFileReader : public HDF5FileReader {
public:
MythenFileReader(const std::filesystem::path &file_path_,
const std::string &file_prefix_)
: m_base_path(file_path_), file_prefix(file_prefix_) {};
MythenFrame read_frame(ssize_t frame_index) {
// TODO not a good design fixed number of digits in file name for frame
// number -> pad with zeros
// not even sure if files have the same name
std::string current_file_name =
m_base_path / (file_prefix + std::to_string(frame_index) + ".h5");
MythenFrame frame;
open_file(current_file_name);
auto dataset_photon_count =
get_dataset("/entry/instrument/detector/data");
frame.photon_counts =
dataset_photon_count.store_as_ndarray<uint32_t, 1>();
++frame.photon_counts; // Why though?
auto dataset_detector_angle =
get_dataset("/entry/instrument/NDAttributes/DetectorAngle");
dataset_detector_angle.read_into_buffer(
reinterpret_cast<std::byte *>(&frame.detector_angle));
auto dataset_channel_number =
get_dataset("/entry/instrument/NDAttributes/CounterMask");
uint8_t channel_number;
dataset_channel_number.read_into_buffer(
reinterpret_cast<std::byte *>(&channel_number));
std::bitset<3> binary_channel_numbers(channel_number); // 1 0 0
// binary_channel_numbers.flip(); // TODO not sure where most
// significant
// bit is ask Anna again
frame.channel_mask = std::array<uint8_t, 3>{binary_channel_numbers[0],
binary_channel_numbers[1],
binary_channel_numbers[2]};
close_file();
return frame;
}
private:
std::filesystem::path m_base_path{};
std::string file_prefix{};
};
} // namespace aare

View File

@ -1,377 +0,0 @@
#include "aare/AngleCalibration.hpp"
namespace aare {
AngleCalibration::AngleCalibration(
std::shared_ptr<MythenDetectorSpecifications> mythen_detector_,
std::shared_ptr<FlatField> flat_field_,
std::shared_ptr<MythenFileReader> mythen_file_reader_)
: mythen_detector(mythen_detector_), flat_field(flat_field_),
mythen_file_reader(mythen_file_reader_) {
centers.reserve(mythen_detector->max_modules());
conversions.reserve(mythen_detector->max_modules());
offsets.reserve(mythen_detector->max_modules());
num_bins = std::floor(mythen_detector->max_angle() / histogram_bin_width) -
std::floor(mythen_detector->min_angle() / histogram_bin_width) +
1; // TODO only works if negative
// and positive angle
}
void AngleCalibration::set_histogram_bin_width(double bin_width) {
histogram_bin_width = bin_width;
num_bins = std::floor(mythen_detector->max_angle() / histogram_bin_width) -
std::floor(mythen_detector->min_angle() / histogram_bin_width) +
1; // TODO only works if negative
// and positive angle
}
double AngleCalibration::get_histogram_bin_width() const {
return histogram_bin_width;
}
ssize_t AngleCalibration::get_new_num_bins() const { return num_bins; }
std::vector<double> AngleCalibration::get_centers() const { return centers; }
std::vector<double> AngleCalibration::get_conversions() const {
return conversions;
}
std::vector<double> AngleCalibration::get_offsets() const { return offsets; }
NDView<double, 1> AngleCalibration::get_new_photon_counts() const {
return new_photon_counts.view();
}
NDView<double, 1> AngleCalibration::get_new_statistical_errors() const {
return new_photon_count_errors.view();
}
void AngleCalibration::read_initial_calibration_from_file(
const std::string &filename) {
std::string line;
uint32_t module_number{};
try {
std::ifstream file(filename, std::ios_base::in);
if (!file.good()) {
throw std::logic_error("file does not exist");
}
std::stringstream file_buffer;
file_buffer << file.rdbuf();
while (file_buffer >> line) {
if (line == "module") {
file_buffer >> line;
module_number = std::stoi(line);
}
if (line == "center") {
file_buffer >> line;
centers.insert(centers.begin() + module_number,
std::stod(line));
}
if (line == "conversion") {
file_buffer >> line;
conversions.insert(conversions.begin() + module_number,
std::stod(line));
}
if (line == "offset") {
file_buffer >> line;
offsets.insert(offsets.begin() + module_number,
std::stod(line));
}
}
file.close();
} catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
parameters AngleCalibration::convert_to_EE_parameters() const {
// normal distance between sample and detector (R)
std::vector<double> normal_distances(centers.size());
// distances between intersection point of sample normal and module origin
// (D)
std::vector<double> module_center_distances(centers.size());
// angles between undiffracted beam and orthogonal sample projection on
// detector (phi)
std::vector<double> angles(centers.size());
for (size_t i = 0; i < centers.size(); ++i) {
auto [module_center_distance, normal_distance, angle] =
convert_to_EE_parameters(i);
normal_distances[i] = normal_distance;
module_center_distances[i] = module_center_distance;
angles[i] = angle;
}
return std::make_tuple(module_center_distances, normal_distances, angles);
}
std::tuple<double, double, double>
AngleCalibration::convert_to_EE_parameters(const size_t module_index) const {
return convert_to_EE_parameters(centers[module_index],
conversions[module_index],
offsets[module_index]);
}
std::tuple<double, double, double> AngleCalibration::convert_to_EE_parameters(
const double center, const double conversion, const double offset) const {
const double module_center_distance =
center * MythenDetectorSpecifications::pitch();
const double normal_distance =
MythenDetectorSpecifications::pitch() / std::abs(conversion);
const double angle = offset + 180.0 / M_PI * center * std::abs(conversion);
return std::make_tuple(module_center_distance, normal_distance, angle);
}
size_t AngleCalibration::global_to_local_strip_index_conversion(
const size_t global_strip_index) const {
const size_t module_index =
global_strip_index / MythenDetectorSpecifications::strips_per_module();
// local strip index in module
size_t local_strip_index =
global_strip_index -
module_index * MythenDetectorSpecifications::strips_per_module();
// switch if indexing is in clock-wise direction
local_strip_index =
std::signbit(conversions[module_index])
? MythenDetectorSpecifications::strips_per_module() - 1 -
local_strip_index
: local_strip_index;
return local_strip_index;
}
/*
parameters
AngleCalibration::convert_to_BC_parameters() {}
*/
double AngleCalibration::diffraction_angle_from_DG_parameters(
const double center, const double conversion, const double offset,
const size_t strip_index, const double distance_to_strip) const {
return offset + 180.0 / M_PI *
(center * std::abs(conversion) -
atan((center - (strip_index + distance_to_strip)) *
std::abs(conversion)));
}
double AngleCalibration::diffraction_angle_from_EE_parameters(
const double module_center_distance, const double normal_distance,
const double angle, const size_t strip_index,
const double distance_to_strip) const {
return angle - 180.0 / M_PI *
atan((module_center_distance -
MythenDetectorSpecifications::pitch() *
(strip_index + distance_to_strip)) /
normal_distance); // TODO: why is it minus
// is it defined counter
// clockwise? thought
// should have a flipped
// sign
}
double AngleCalibration::angular_strip_width_from_DG_parameters(
const double center, const double conversion, const double offset,
const size_t local_strip_index) const {
return std::abs(diffraction_angle_from_DG_parameters(
center, conversion, offset, local_strip_index, -0.5) -
diffraction_angle_from_DG_parameters(
center, conversion, offset, local_strip_index, 0.5));
}
double AngleCalibration::angular_strip_width_from_EE_parameters(
const double module_center_distance, const double normal_distance,
const double angle, const size_t local_strip_index) const {
return std::abs(diffraction_angle_from_EE_parameters(
module_center_distance, normal_distance, angle,
local_strip_index, -0.5) -
diffraction_angle_from_EE_parameters(
module_center_distance, normal_distance, angle,
local_strip_index, 0.5));
// TODO: again not sure about division order - taking abs anyway
}
void AngleCalibration::calculate_fixed_bin_angle_width_histogram(
const size_t start_frame_index, const size_t end_frame_index) {
new_photon_counts = NDArray<double, 1>(std::array<ssize_t, 1>{num_bins});
new_photon_count_errors =
NDArray<double, 1>(std::array<ssize_t, 1>{num_bins});
// TODO: maybe group these into a 2d array - better cache usage
NDArray<double, 1> bin_counts(std::array<ssize_t, 1>{num_bins}, 0.0);
NDArray<double, 1> new_statistical_weights(std::array<ssize_t, 1>{num_bins},
0.0);
NDArray<double, 1> new_errors(std::array<ssize_t, 1>{num_bins}, 0.0);
NDArray<double, 1> inverse_normalized_flatfield =
flat_field->inverse_normalized_flatfield();
for (size_t frame_index = start_frame_index; frame_index < end_frame_index;
++frame_index) {
MythenFrame frame = mythen_file_reader->read_frame(frame_index);
redistribute_photon_counts_to_fixed_angle_bins(
frame, bin_counts.view(), new_statistical_weights.view(),
new_errors.view(), inverse_normalized_flatfield.view());
}
for (ssize_t i = 0; i < new_photon_counts.size(); ++i) {
new_photon_counts[i] = (new_statistical_weights[i] <=
std::numeric_limits<double>::epsilon())
? 0.
: bin_counts[i] / new_statistical_weights[i];
new_photon_count_errors[i] =
(bin_counts[i] <= std::numeric_limits<double>::epsilon())
? 0.
: 1.0 / std::sqrt(bin_counts[i]);
}
}
void AngleCalibration::redistribute_photon_counts_to_fixed_angle_bins(
const MythenFrame &frame, NDView<double, 1> bin_counts,
NDView<double, 1> new_statistical_weights, NDView<double, 1> new_errors,
NDView<double, 1> inverse_normalized_flatfield) const {
ssize_t channel = 0; // TODO handle mask - FlatField still 1d
if (frame.photon_counts.shape()[0] != mythen_detector->num_strips()) {
throw std::runtime_error("wrong number of strips read");
}
ssize_t num_bins1 = mythen_detector->min_angle() / histogram_bin_width;
ssize_t num_bins2 = mythen_detector->max_angle() / histogram_bin_width;
std::cout << "position: " << frame.detector_angle
<< std::endl; // replace with log
double exposure_rate = 1. / mythen_detector->exposure_time();
for (ssize_t strip_index = 0; strip_index < mythen_detector->num_strips();
++strip_index) {
size_t module_index =
strip_index / MythenDetectorSpecifications::strips_per_module();
if (mythen_detector->get_bad_channels()[strip_index] ||
!mythen_detector->get_connected_modules()[module_index])
continue;
double poisson_error = std::sqrt(frame.photon_counts(strip_index)) *
inverse_normalized_flatfield(strip_index) *
exposure_rate;
double corrected_photon_count =
frame.photon_counts(strip_index) *
inverse_normalized_flatfield(strip_index) * exposure_rate;
size_t local_strip_index =
global_to_local_strip_index_conversion(strip_index);
double diffraction_angle = diffraction_angle_from_DG_parameters(
centers[module_index], conversions[module_index],
offsets[module_index], local_strip_index);
diffraction_angle += (frame.detector_angle + mythen_detector->dtt0() +
mythen_detector->bloffset());
if (diffraction_angle < mythen_detector->min_angle() ||
diffraction_angle > mythen_detector->max_angle())
continue;
double angle_covered_by_strip = angular_strip_width_from_DG_parameters(
centers[module_index], conversions[module_index],
offsets[module_index], local_strip_index);
double photon_count_per_bin = histogram_bin_width *
corrected_photon_count /
angle_covered_by_strip;
double error_photon_count_per_bin =
histogram_bin_width * poisson_error / angle_covered_by_strip;
double statistical_weights =
1.0 / std::pow(error_photon_count_per_bin, 2); // 1./sigma²
double strip_boundary_left =
diffraction_angle - 0.5 * angle_covered_by_strip;
double strip_boundary_right =
diffraction_angle + 0.5 * angle_covered_by_strip;
ssize_t left_bin_index = std::max(
num_bins1,
static_cast<ssize_t>(
std::floor(strip_boundary_left / histogram_bin_width) - 1));
ssize_t right_bin_index = std::min(
num_bins2,
static_cast<ssize_t>(
std::ceil(strip_boundary_right / histogram_bin_width) + 1));
// TODO should it be < or <=
for (ssize_t bin = left_bin_index; bin <= right_bin_index; ++bin) {
double bin_coverage = std::min(strip_boundary_right,
(bin + 0.5) * histogram_bin_width) -
std::max(strip_boundary_left,
(bin - 0.5) * histogram_bin_width);
double bin_coverage_factor = bin_coverage / histogram_bin_width;
ssize_t bin_index = bin - num_bins1;
// TODO: maybe have this threshold configurable
if (bin_coverage >= 0.0001) {
new_statistical_weights(bin_index) +=
statistical_weights * bin_coverage_factor;
bin_counts(bin_index) += statistical_weights *
bin_coverage_factor *
photon_count_per_bin;
new_errors(bin_index) += statistical_weights *
bin_coverage_factor *
std::pow(photon_count_per_bin, 2);
}
}
}
}
void AngleCalibration::write_to_file(
const std::string &filename, const bool store_nonzero_bins,
const std::filesystem::path &filepath) const {
std::ofstream output_file(filepath / filename);
if (!output_file) {
std::cerr << "Error opening file!"
<< std::endl; // TODO: replace with log
}
output_file << std::fixed << std::setprecision(15);
for (ssize_t i = 0; i < num_bins; ++i) {
if (new_photon_counts[i] <= std::numeric_limits<double>::epsilon() &&
store_nonzero_bins) {
continue;
}
output_file << std::floor(mythen_detector->min_angle() /
histogram_bin_width) *
histogram_bin_width +
i * histogram_bin_width
<< " " << new_photon_counts[i] << " "
<< new_photon_count_errors[i] << std::endl;
}
output_file.close();
}
} // namespace aare

View File

@ -1,265 +0,0 @@
/************************************************
* @file AngleCalibration.test.cpp
* @short test case for angle calibration class
***********************************************/
#include "aare/AngleCalibration.hpp"
#include "aare/CustomFiles.hpp"
#include "aare/FlatField.hpp"
#include <filesystem>
#include "test_config.hpp"
#include <iomanip>
#include <type_traits>
#include <catch2/catch_all.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
using namespace aare;
TEST_CASE("read initial angle calibration file",
"[anglecalibration] [.files]") {
std::shared_ptr<MythenDetectorSpecifications> mythen_detector_ptr =
std::make_shared<MythenDetectorSpecifications>();
AngleCalibration anglecalibration(mythen_detector_ptr,
std::shared_ptr<FlatField>{},
std::shared_ptr<MythenFileReader>{});
std::string filename = test_data_path() / "AngleCalibration_Test_Data" /
"Angcal_2E_Feb2023_P29.off";
REQUIRE(std::filesystem::exists(filename));
anglecalibration.read_initial_calibration_from_file(filename);
auto centers = anglecalibration.get_centers();
auto conversions = anglecalibration.get_conversions();
auto offsets = anglecalibration.get_offsets();
std::cout.precision(17);
CHECK(centers.size() == 48);
CHECK(conversions.size() == 48);
CHECK(offsets.size() == 48);
CHECK(centers[9] == Catch::Approx(660.342326));
CHECK(offsets[47] == Catch::Approx(5.8053312));
CHECK(conversions[27] == Catch::Approx(-0.6581179125e-4));
}
TEST_CASE("read bad channels",
"[anglecalibration][mythenspecifications][.files]") {
MythenDetectorSpecifications mythen_detector;
std::string bad_channels_filename = test_data_path() /
"AngleCalibration_Test_Data" /
"bc2023_003_RING.chans";
REQUIRE(std::filesystem::exists(bad_channels_filename));
mythen_detector.read_bad_channels_from_file(bad_channels_filename);
CHECK(mythen_detector.get_bad_channels().size() == 61440);
CHECK(mythen_detector.get_bad_channels()[61437] == true);
CHECK(std::all_of(mythen_detector.get_bad_channels().begin() + 30720,
mythen_detector.get_bad_channels().begin() + 61439,
[](const bool element) { return element; }));
}
TEST_CASE("read unconnected modules",
"[anglecalibration][mythenspecifications][.files]") {
MythenDetectorSpecifications mythen_detector;
std::string unconnected_modules_filename =
test_data_path() / "AngleCalibration_Test_Data" / "ModOut.txt";
REQUIRE(std::filesystem::exists(unconnected_modules_filename));
mythen_detector.read_unconnected_modules_from_file(
unconnected_modules_filename);
CHECK(mythen_detector.get_connected_modules().size() == 48);
CHECK(std::all_of(mythen_detector.get_connected_modules().begin(),
mythen_detector.get_connected_modules().end(),
[](const bool element) { return element; }));
}
TEST_CASE("read flatfield", "[anglecalibration][flatfield][.files]") {
std::shared_ptr<MythenDetectorSpecifications> mythen_detector_ptr =
std::make_shared<MythenDetectorSpecifications>();
FlatField flatfield(mythen_detector_ptr);
std::string flatfield_filename =
test_data_path() / "AngleCalibration_Test_Data" /
"Flatfield_E22p0keV_T11000eV_up_48M_a_LONG_Feb2023_open_WS_SUMC.raw";
REQUIRE(std::filesystem::exists(flatfield_filename));
flatfield.read_flatfield_from_file<CustomMythenFile>(flatfield_filename);
auto flatfield_data = flatfield.get_flatfield();
CHECK(flatfield_data.size() == 61440);
CHECK(flatfield_data[0] == 0);
CHECK(flatfield_data[21] == 4234186);
}
TEST_CASE("create flatfield", "[anglecalibration], [flatfield], [.files]") {
ssize_t n_modules = 2;
double exposure_time = 5.0;
size_t n_counters = 1;
std::shared_ptr<MythenDetectorSpecifications> mythen_detector_ptr =
std::make_shared<MythenDetectorSpecifications>(n_modules, exposure_time,
n_counters);
FlatField flatfield(mythen_detector_ptr);
auto data_path = test_data_path() / "AngleCalibration_Test_Data" /
"Flatfieldacquisition";
REQUIRE(std::filesystem::exists(data_path));
CHECK_NOTHROW(flatfield.create_flatfield_from_rawfilesystem(data_path));
auto flatfield_data = flatfield.get_flatfield();
CHECK(flatfield_data.size() == n_modules * 1280);
CHECK(flatfield_data[0] == 0);
CHECK(flatfield_data[21] ==
2 * 3 *
21); // virtual data 2 angles, 3 frames - 21 as increasing numbers
}
TEST_CASE("compare result with python code", "[anglecalibration] [.files]") {
auto fpath = test_data_path() / "AngleCalibration_Test_Data";
REQUIRE(std::filesystem::exists(fpath));
std::shared_ptr<MythenDetectorSpecifications> mythen_detector_ptr =
std::make_shared<MythenDetectorSpecifications>();
std::string bad_channels_filename = fpath / "bc2023_003_RING.chans";
REQUIRE(std::filesystem::exists(bad_channels_filename));
mythen_detector_ptr->read_bad_channels_from_file(bad_channels_filename);
std::string unconnected_modules_filename = fpath / "ModOut.txt";
REQUIRE(std::filesystem::exists(unconnected_modules_filename));
mythen_detector_ptr->read_unconnected_modules_from_file(
unconnected_modules_filename);
std::shared_ptr<FlatField> flat_field_ptr =
std::make_shared<FlatField>(mythen_detector_ptr);
std::string flatfield_filename =
fpath /
"Flatfield_E22p0keV_T11000eV_up_48M_a_LONG_Feb2023_open_WS_SUMC.raw";
REQUIRE(std::filesystem::exists(flatfield_filename));
flat_field_ptr->read_flatfield_from_file<CustomMythenFile>(
flatfield_filename);
std::shared_ptr<MythenFileReader> mythen_file_reader_ptr =
std::make_shared<MythenFileReader>(fpath,
"ang1up_22keV_LaB60p3mm_48M_a_0");
AngleCalibration anglecalibration(mythen_detector_ptr, flat_field_ptr,
mythen_file_reader_ptr);
std::string initial_angles_filename = fpath / "Angcal_2E_Feb2023_P29.off";
REQUIRE(std::filesystem::exists(initial_angles_filename));
anglecalibration.read_initial_calibration_from_file(
initial_angles_filename);
anglecalibration.calculate_fixed_bin_angle_width_histogram(320, 340);
// anglecalibration.write_to_file("cpp_new_photon_counts.xye");
auto expected_filename_photons =
test_data_path() / "AngleCalibration_Test_Data" / "new_photons.bin";
REQUIRE(std::filesystem::exists(expected_filename_photons));
auto expected_filename_errors =
test_data_path() / "AngleCalibration_Test_Data" / "new_errors.bin";
REQUIRE(std::filesystem::exists(expected_filename_errors));
ssize_t new_num_bins = anglecalibration.get_new_num_bins();
auto python_output_errors = load<double, 1>(
expected_filename_errors, std::array<ssize_t, 1>{new_num_bins});
auto python_output_photons = load<double, 1>(
expected_filename_photons, std::array<ssize_t, 1>{new_num_bins});
CHECK(anglecalibration.get_new_photon_counts().equals(
python_output_photons.view(),
1e-8)); // not sure about precision does not exactly match to all
// decimal digits
CHECK(anglecalibration.get_new_statistical_errors().equals(
python_output_errors.view(),
1e-8)); //
}
TEST_CASE("check conversion from DG to EE parameters", "[anglecalibration]") {
std::shared_ptr<MythenDetectorSpecifications> mythen_detector_ptr =
std::make_shared<MythenDetectorSpecifications>();
AngleCalibration anglecalibration(mythen_detector_ptr,
std::shared_ptr<FlatField>{},
std::shared_ptr<MythenFileReader>{});
// DG test parameters
const double center = 642.197591224993;
const double conversion = 0.657694036246975e-4;
const double offset = 5.004892881251670;
const ssize_t local_strip_index = 1;
double diffraction_angle_DG_param =
anglecalibration.diffraction_angle_from_DG_parameters(
center, conversion, offset, local_strip_index);
auto [distance_center, normal_distance, angle] =
anglecalibration.convert_to_EE_parameters(center, conversion, offset);
double diffraction_angle_EE_param =
anglecalibration.diffraction_angle_from_EE_parameters(
distance_center, normal_distance, angle, local_strip_index);
CHECK(diffraction_angle_EE_param ==
Catch::Approx(diffraction_angle_DG_param));
double strip_width_DG_param =
anglecalibration.angular_strip_width_from_DG_parameters(
center, conversion, offset, local_strip_index);
double strip_width_EE_param =
anglecalibration.angular_strip_width_from_EE_parameters(
distance_center, normal_distance, angle, local_strip_index);
CHECK(strip_width_DG_param == Catch::Approx(strip_width_EE_param));
}

View File

@ -1,89 +0,0 @@
#include "aare/CustomFiles.hpp"
namespace aare {
CustomMythenFile::CustomMythenFile(const std::string &filename,
const ssize_t rows, const ssize_t cols,
const std::string &mode)
: m_filename(filename), m_rows(rows), m_cols(cols) {
m_mode = mode;
if (m_mode == "r") {
try {
m_file.open(m_filename, std::ios_base::in);
if (!m_file.good()) {
throw std::logic_error("file does not exist");
}
} catch (std::exception &e) {
std::cerr << "Error: " << e.what()
<< std::endl; // TODO replace with log
}
} else {
throw std::runtime_error(LOCATION +
"Unsupported mode. Can only read RawFiles.");
}
}
CustomMythenFile::~CustomMythenFile() { m_file.close(); }
Frame CustomMythenFile::read_frame() {
auto f = Frame(m_rows, m_cols, m_dtype);
uint32_t *frame_buffer = reinterpret_cast<uint32_t *>(f.data());
uint32_t strip_index, photon_count;
while (m_file >> strip_index >> photon_count) {
*frame_buffer = photon_count;
++frame_buffer;
}
return f;
}
void CustomMythenFile::read_into(std::byte *image_buf) {
uint32_t strip_index, photon_count;
while (m_file >> strip_index >> photon_count) {
std::memcpy(image_buf, &photon_count, sizeof(photon_count));
image_buf += sizeof(photon_count);
}
}
size_t CustomMythenFile::bytes_per_frame() {
return m_num_strips * m_dtype.bytes(); // TODO do i want m_counts?
}
Frame CustomMythenFile::read_frame(size_t frame_number) {
return read_frame(); // maybe give count as frame_number
}
std::vector<Frame> CustomMythenFile::read_n(size_t n_frames) {
std::vector<Frame> vec;
vec.reserve(1);
vec.push_back(read_frame());
return vec; // std::vector<Frame>{read_frame()};
}
void CustomMythenFile::read_into(std::byte *image_buf, size_t n_frames) {
read_into(image_buf);
}
size_t CustomMythenFile::frame_number(size_t frame_index) { return 1; }
size_t CustomMythenFile::pixels_per_frame() { return m_rows * m_cols; }
void CustomMythenFile::seek(size_t frame_number) {}
size_t CustomMythenFile::tell() { return 1; }
size_t CustomMythenFile::total_frames() const { return 1; }
size_t CustomMythenFile::rows() const { return m_rows; }
size_t CustomMythenFile::cols() const { return m_cols; }
size_t CustomMythenFile::bitdepth() const { return m_dtype.bitdepth(); }
DetectorType CustomMythenFile::detector_type() const { return det_type; }
const Dtype CustomMythenFile::m_dtype(Dtype::TypeIndex::UINT32);
} // namespace aare

View File

@ -1,110 +0,0 @@
/************************************************
* @file Hdf5FileReader.test.cpp
* @short test case for reading hdf5 files
***********************************************/
#include <filesystem>
#include "test_config.hpp"
#include <H5Cpp.h>
#include "aare/Hdf5FileReader.hpp"
#include "aare/NDArray.hpp"
#include <catch2/catch_all.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
using namespace aare;
TEST_CASE("read hdf5 file", "[.hdf5file][.files]") {
// TODO generalize datasetpath
std::string filename = test_data_path() / "AngleCalibration_Test_Data" /
"ang1up_22keV_LaB60p3mm_48M_a_0320.h5";
REQUIRE(std::filesystem::exists(filename));
HDF5FileReader file_reader;
file_reader.open_file(filename);
auto dataset = file_reader.get_dataset("/entry/data/data");
auto shape = dataset.get_shape();
CHECK(shape[0] == 61440);
auto type = dataset.get_datatype();
const std::type_info *type_info = dataset.get_cpp_type();
CHECK(*type_info == typeid(uint32_t));
SECTION("read dataset into NDArray") {
NDArray<uint32_t, 1> dataset_array =
dataset.store_as_ndarray<uint32_t, 1>();
CHECK(dataset_array(0) == 866);
CHECK(dataset_array(61439) == 1436);
}
SECTION("read dataset into Frame") {
Frame frame = dataset.store_as_frame();
CHECK(*(reinterpret_cast<uint32_t *>(frame.pixel_ptr(0, 0))) == 866);
CHECK(*(reinterpret_cast<uint32_t *>(frame.pixel_ptr(0, 61439))) ==
1436);
}
SECTION("read subset of dataset") {
Frame frame(1, 10, Dtype(typeid(uint32_t)));
Subset subset{std::vector<hsize_t>{10}, std::vector<hsize_t>{10}};
dataset.read_into_buffer(frame.data(), subset);
CHECK(*(reinterpret_cast<uint32_t *>(frame.pixel_ptr(0, 0))) == 664);
CHECK(*(reinterpret_cast<uint32_t *>(frame.pixel_ptr(0, 9))) == 654);
}
/*
SECTION("read scalar") {
}
*/
}
TEST_CASE("test datatypes", "[.hdf5file]") {
auto [dtype, expected_type_info] = GENERATE(
std::make_tuple(H5::DataType(H5::PredType::NATIVE_INT), &typeid(int)),
std::make_tuple(H5::DataType(H5::PredType::NATIVE_INT8),
&typeid(int8_t)),
std::make_tuple(H5::DataType(H5::PredType::NATIVE_UINT16),
&typeid(uint16_t)),
std::make_tuple(H5::DataType(H5::PredType::NATIVE_INT16),
&typeid(int16_t)),
std::make_tuple(H5::DataType(H5::PredType::STD_U32LE),
&typeid(uint32_t)),
std::make_tuple(H5::DataType(H5::PredType::STD_I32LE),
&typeid(int32_t)),
std::make_tuple(H5::DataType(H5::PredType::NATIVE_INT32),
&typeid(int32_t)),
std::make_tuple(H5::DataType(H5::PredType::IEEE_F64LE),
&typeid(double)),
std::make_tuple(H5::DataType(H5::PredType::IEEE_F32LE), &typeid(float)),
std::make_tuple(H5::DataType(H5::PredType::NATIVE_FLOAT),
&typeid(float)),
std::make_tuple(H5::DataType(H5::PredType::NATIVE_DOUBLE),
&typeid(double)),
std::make_tuple(H5::DataType(H5::PredType::NATIVE_CHAR),
&typeid(int8_t)));
const std::type_info &type_info = deduce_cpp_type(dtype);
CHECK(type_info == *expected_type_info);
// TODO: handle bit swapping
REQUIRE_THROWS(deduce_cpp_type(
H5::DataType(H5::PredType::IEEE_F32BE))); // does not convert from big
// to little endian
}

View File

@ -1,33 +0,0 @@
/************************************************
* @file MythenFileReader.test.cpp
* @short test case for angle calibration class
***********************************************/
#include "aare/MythenFileReader.hpp"
#include <filesystem>
#include "test_config.hpp"
#include <catch2/catch_all.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
using namespace aare;
TEST_CASE("test mythenfile_reader", "[.mythenfilereader][.files]") {
auto fpath = test_data_path() / "AngleCalibration_Test_Data";
REQUIRE(std::filesystem::exists(fpath));
MythenFileReader file_reader(fpath, "ang1up_22keV_LaB60p3mm_48M_a_0");
auto frame = file_reader.read_frame(320);
CHECK(frame.detector_angle == 0.99955);
CHECK(frame.channel_mask == std::array<uint8_t, 3>{0, 0, 1});
CHECK(frame.photon_counts.size() == 61440);
}