43#include <unordered_map>
47#include "toctree_compressor.h"
50#include "genericTsPool.h"
54#include "zfp/array1.hpp"
61void decompress_phasespace6D_f64(GENERIC_TS_POOL::MemPool* p, std::size_t fin, std::size_t fout,
double* vcoords_ptr,
62 double* vspace_ptr, std::size_t size, std::size_t fourier_order,
63 size_t* hidden_layers_ptr,
size_t n_hidden_layers,
double* weights_ptr,
64 std::size_t weight_size,
bool use_input_weights);
66void decompress_phasespace6D_f32(GENERIC_TS_POOL::MemPool* p, std::size_t fin, std::size_t fout,
float* vcoords_ptr,
67 float* vspace_ptr, std::size_t size, std::size_t fourier_order,
68 size_t* hidden_layers_ptr,
size_t n_hidden_layers,
float* weights_ptr,
69 std::size_t weight_size,
bool use_input_weights);
95 std::array<std::size_t, 3>
shape;
96 std::size_t
index(std::size_t
i, std::size_t
j, std::size_t
k)
const noexcept {
105 std::ofstream
file(filename, std::ios::out | std::ios::binary);
107 std::cerr <<
"Could not open file for writting! Exiting!" << std::endl;
110 file.write((
char*)
shape.data(), 3 *
sizeof(
size_t));
112 std::cerr <<
"Error writing shape data to file!" << std::endl;
118 std::cerr <<
"Error writing vdf_vals data to file!" << std::endl;
128 std::array<Real, 6>
v_limits{std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max(),
129 std::numeric_limits<Real>::max(), std::numeric_limits<Real>::lowest(),
130 std::numeric_limits<Real>::lowest(), std::numeric_limits<Real>::lowest()};
133 std::ofstream
file(filename, std::ios::out | std::ios::binary);
135 std::cerr <<
"Could not open file for writting! Exiting!" << std::endl;
141 std::cerr <<
"Error writing size data to file!" << std::endl;
147 std::cerr <<
"Error writing size data to file!" << std::endl;
153 std::cerr <<
"Error writing vdf_coords data to file!" << std::endl;
159 std::cerr <<
"Error writing vdf_vals data to file!" << std::endl;
177 const dccrg::Dccrg<spatial_cell::SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
bool center_vdfs)
181 std::size_t max_cid_block_size = 0;
182 std::size_t bytes_of_all_local_vdfs = 0;
183 for (
const auto& cid : cids) {
186 const size_t total_size = blockContainer->
size();
187 max_cid_block_size = std::max(total_size, max_cid_block_size);
188 bytes_of_all_local_vdfs += total_size *
WID3 *
sizeof(
Realf);
192 std::vector<std::vector<T>> vspaces(cids.size());
193 std::vector<double> f_sums(cids.size(), 0);
195 for (std::size_t cc = 0; cc < cids.size(); ++cc) {
196 const auto& cid = cids[cc];
197 _cids.push_back(cid);
200 const std::array<T, 3> bulkv{
static_cast<T
>(sc->
get_population(popID).
V[0]),
205 const size_t total_blocks = blockContainer->size();
206 Realf* data = blockContainer->getData();
208 for (std::size_t n = 0; n < total_blocks; ++n) {
213 auto [it, block_inserted] =
_map.try_emplace(gid,
_vcoords.size());
215 for (uint
k = 0;
k <
WID; ++
k) {
216 for (uint
j = 0;
j <
WID; ++
j) {
217 for (uint
i = 0;
i <
WID; ++
i) {
219 std::array<T, 3> coords = {
225 coords[0] = coords[0] - bulkv[0];
226 coords[1] = coords[1] - bulkv[1];
227 coords[2] = coords[2] - bulkv[2];
236 const double vdf_val =
static_cast<double>(vdf_data[
cellIndex(
i,
j,
k)]);
237 if (block_inserted) {
238 _vcoords.push_back({coords[0], coords[1], coords[2]});
239 for (std::size_t x = 0; x < cids.size(); ++x) {
240 vspaces[x].push_back((x == cc) ? vdf_val : T(0));
243 vspaces[cc].at(it->second + cnt) = vdf_val;
245 f_sums.at(cc) +=
static_cast<double>(vdf_val);
252 _nrows = vspaces.front().size();
255 auto index_2d = [
this](std::size_t row, std::size_t col) -> std::size_t {
return row *
_ncols + col; };
259 for (std::size_t
i = 0;
i <
_nrows; ++
i) {
260 for (std::size_t
j = 0;
j <
_ncols; ++
j) {
272 [sparse](T& value) { value = std::log10(std::max(value, sparse)) - std::log10(sparse); });
279 std::ranges::for_each(
_vcoords, [
this](std::array<T, 3>& x) {
285 const std::size_t nVDFS =
_ncols;
286 for (std::size_t v = 0; v < nVDFS; ++v) {
287 T min_val = std::numeric_limits<T>::max();
288 T max_val = std::numeric_limits<T>::lowest();
289 for (std::size_t
i = 0;
i <
_nrows; ++
i) {
293 for (std::size_t
i = 0;
i <
_nrows; ++
i) {
302 std::ranges::for_each(
_vcoords, [
this](std::array<T, 3>& x) {
308 const std::size_t nVDFS =
_ncols;
309 for (std::size_t v = 0; v < nVDFS; ++v) {
310 const T max_val =
_norms[v].max;
311 const T min_val =
_norms[v].min;
312 for (std::size_t
i = 0;
i <
_nrows; ++
i) {
318 constexpr std::size_t
index_2d(std::size_t row, std::size_t col)
const noexcept {
return row *
_ncols + col; };
322 if (x - sparse < 0.0) {
330 _vbulks.size() *
sizeof(std::array<T, 3>) +
_vcoords.size() *
sizeof(std::array<T, 3>) + 6 *
sizeof(T) +
331 _n_weights *
sizeof(T) +
_map.size() *
sizeof(std::pair<vmesh::LocalID, std::size_t>);
343 std::size_t write_index = 0;
345 std::memcpy(&buffer[write_index], &header,
sizeof(
Header));
346 write_index +=
sizeof(
Header);
348 std::memcpy(&buffer[write_index], &
_cids[0],
_cids.size() *
sizeof(
CellID));
354 std::memcpy(&buffer[write_index], &
_vbulks[0],
_vbulks.size() *
sizeof(std::array<T, 3>));
355 write_index +=
_vbulks.size() *
sizeof(std::array<T, 3>);
357 std::memcpy(&buffer[write_index], &
_v_limits[0], 6 *
sizeof(T));
358 write_index += 6 *
sizeof(T);
360 std::memcpy(&buffer[write_index], &
_vcoords[0],
_vcoords.size() *
sizeof(std::array<T, 3>));
361 write_index +=
_vcoords.size() *
sizeof(std::array<T, 3>);
366 for (
const auto& kval :
_map) {
367 std::memcpy(&buffer[write_index], &kval,
sizeof(std::pair<vmesh::LocalID, std::size_t>));
368 write_index +=
sizeof(std::pair<vmesh::LocalID, std::size_t>);
372 throw std::runtime_error(
"Failed to fully write state");
377 const Header*
const header =
reinterpret_cast<const Header*
>(&buffer[0]);
378 assert(header->
key ==
MLP_KEY &&
"Blame Kostis Papadakis for this!");
380 throw std::runtime_error(
"Wrong MLP Header KEY");
389 std::size_t read_index =
sizeof(
Header);
390 std::size_t cids_size = header->
cols;
391 _cids.resize(cids_size);
393 std::memcpy(
_cids.data(), &buffer[read_index], cids_size *
sizeof(
CellID));
394 read_index += cids_size *
sizeof(
CellID);
396 std::size_t norms_size = cids_size;
398 std::memcpy(
_norms.data(), &buffer[read_index], norms_size *
sizeof(
Norms));
399 read_index += norms_size *
sizeof(
Norms);
401 std::size_t vbulk_size = cids_size;
403 std::memcpy(
_vbulks.data(), &buffer[read_index], vbulk_size *
sizeof(std::array<T, 3>));
404 read_index += vbulk_size *
sizeof(std::array<T, 3>);
406 std::memcpy(&
_v_limits[0], &buffer[read_index], 6 *
sizeof(T));
407 read_index += 6 *
sizeof(T);
409 std::size_t vcoords_size = header->
rows;
411 std::memcpy(
_vcoords.data(), &buffer[read_index], vcoords_size *
sizeof(std::array<T, 3>));
412 read_index += vcoords_size *
sizeof(std::array<T, 3>);
423 while (read_index < header->total_size) {
424 const std::pair<vmesh::LocalID, std::size_t>* kval =
425 reinterpret_cast<const std::pair<vmesh::LocalID, std::size_t>*
>(&buffer[read_index]);
426 _map[kval->first] = kval->second;
427 read_index +=
sizeof(std::pair<vmesh::LocalID, std::size_t>);
429 assert(read_index == header->
total_size &&
"Size mismatch while reading in serialized VDF Union!");
431 throw std::runtime_error(
"Failed to fully read state");
436 double min = std::numeric_limits<double>::max();
437 double max = std::numeric_limits<double>::min();
458 std::unordered_map<vmesh::GlobalID, std::size_t>
_map;
462 std::array<T, 6>
_v_limits{std::numeric_limits<T>::max(), std::numeric_limits<T>::max(),
463 std::numeric_limits<T>::max(), std::numeric_limits<T>::lowest(),
464 std::numeric_limits<T>::lowest(), std::numeric_limits<T>::lowest()};
469auto extract_pop_vdf_from_spatial_cell_ordered_min_bbox_zoomed(
spatial_cell::SpatialCell* sc, uint popID,
int zoom) -> OrderedVDF;
471constexpr auto isPow2(std::unsigned_integral
auto val) ->
bool {
return (val & (val - 1)) == 0; };
473auto overwrite_pop_spatial_cell_vdf(
spatial_cell::SpatialCell* sc, uint popID,
const std::vector<Realf>& new_vspace) -> void;
477auto overwrite_cellids_vdfs(
const std::span<const CellID> cids, uint popID,
478 dccrg::Dccrg<spatial_cell::SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
479 const std::vector<std::array<Real, 3>>& vcoords,
const std::vector<Realf>& vspace_union,
480 const std::unordered_map<vmesh::LocalID, std::size_t>& map_exists_id) -> void;
485 dccrg::Dccrg<spatial_cell::SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) -> void;
489requires(std::is_same_v<T, float> || std::is_same_v<T, double>)
auto shannon_entropy(
const std::vector<T>& data) -> T {
490 const std::size_t sz = data.size();
495 using key_t = std::conditional_t<std::is_same_v<T, float>, uint32_t, uint64_t>;
496 std::unordered_map<key_t, int> frequency;
497 for (std::size_t
i = 0;
i < sz; ++
i) {
498 frequency[*(
reinterpret_cast<const key_t*
>(&data[
i]))]++;
501 for (
const auto& [
byte, count] : frequency) {
502 T pk =
static_cast<T
>(count) / sz;
503 entropy -= pk * std::log2(pk);
509requires(std::is_same_v<T, float> ||
511 std::size_t bits) -> T {
513 return static_cast<T
>(bits) / entorpy;
516template <
typename NetworkType>
518 const std::vector<std::size_t>& architecture, std::size_t fourier_order, std::size_t output_dim) -> std::size_t {
519 if (architecture.empty()) {
520 throw std::runtime_error(
"Architecture cannot be empty.");
522 std::size_t input_dim = 2 * fourier_order;
523 std::size_t total_size = 0;
524 total_size += input_dim * architecture[0];
525 total_size += architecture[0];
527 for (std::size_t
i = 1;
i < architecture.size(); ++
i) {
528 total_size += architecture[
i - 1] * architecture[
i];
529 total_size += architecture[
i];
532 total_size += architecture.back() * output_dim;
533 total_size += output_dim;
535 return total_size *
sizeof(NetworkType);
538template <
typename NetworkType>
540 std::size_t N_input, std::size_t N_output, std::size_t num_hidden_layers, std::size_t target_size)
541 -> std::vector<std::size_t> {
542 std::vector<std::size_t> neurons(num_hidden_layers + 2);
543 neurons[0] = N_input;
544 neurons[num_hidden_layers + 1] = N_output;
547 std::size_t initial_hidden_size = 1;
548 for (std::size_t
i = 1;
i <= num_hidden_layers; ++
i) {
549 neurons[
i] = initial_hidden_size;
553 while (current_size < target_size) {
554 for (std::size_t
i = 1;
i <= num_hidden_layers; ++
i) {
560 while (current_size > target_size) {
561 for (std::size_t
i = 1;
i <= num_hidden_layers; ++
i) {
562 if (neurons[
i] > 1) {
573template <
typename T>
void decompressPhaseSpace(PhaseSpaceUnion<T>& rv) {
575 GENERIC_TS_POOL::MemPool p{};
576 if constexpr (
sizeof(
T) ==
sizeof(float)) {
577 decompress_phasespace6D_f32(&p, 3, rv._ncols, &rv._vcoords[0][0], rv._vspace.data(), rv._vcoords.size(),
579 rv._n_weights *
sizeof(
float),
true);
581 decompress_phasespace6D_f64(&p, 3, rv._ncols, &rv._vcoords[0][0], rv._vspace.data(), rv._vcoords.size(),
583 rv._n_weights *
sizeof(
double),
true);
590 const std::vector<std::array<T, 3>>& vcoords,
const std::vector<T>& vspace_union,
591 const std::unordered_map<vmesh::LocalID, std::size_t>& map_exists_id) {
592 const std::size_t nrows = vcoords.size();
593 const std::size_t ncols = cids.size();
595 auto index_2d = [nrows, ncols](std::size_t row, std::size_t col) -> std::size_t {
return row * ncols + col; };
597 const auto& cid = cids[cc];
599 const size_t total_blocks = blockContainer->
size();
600 Realf* data = blockContainer->getData();
602 for (std::size_t n = 0; n < total_blocks; ++n) {
605 const auto it = map_exists_id.find(gid);
606 const bool exists = it != map_exists_id.end();
610 const auto index = it->second;
613 for (uint
k = 0;
k <
WID; ++
k) {
614 for (uint
j = 0;
j <
WID; ++
j) {
615 for (uint
i = 0;
i <
WID; ++
i) {
616 const std::size_t
index = it->second;
std::array< T, 6 > _v_limits
PhaseSpaceUnion & operator=(const PhaseSpaceUnion &other)=delete
void sparsify(T sparse) noexcept
void normalize() noexcept
std::unordered_map< vmesh::GlobalID, std::size_t > _map
void serialize_into(unsigned char *buffer) const
std::size_t _effective_vdf_size
PhaseSpaceUnion(const PhaseSpaceUnion &other)=delete
std::vector< CellID > _cids
std::vector< std::array< T, 3 > > _vcoords
void deserialize_from(const unsigned char *buffer)
constexpr std::size_t index_2d(std::size_t row, std::size_t col) const noexcept
std::vector< std::array< T, 3 > > _vbulks
PhaseSpaceUnion(const unsigned char *buffer)
PhaseSpaceUnion(PhaseSpaceUnion &&other)=delete
PhaseSpaceUnion(const std::span< const CellID > cids, uint popID, const dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, bool center_vdfs)
void unormalize_and_unscale(T sparse) noexcept
std::size_t total_serialized_size_bytes() const
PhaseSpaceUnion & operator=(PhaseSpaceUnion &&other)=delete
std::vector< Norms > _norms
void scale(T sparse) noexcept
Real * get_block_parameters(const uint popID)
vmesh::GlobalID get_velocity_block_global_id(const vmesh::LocalID &blockLID, const uint popID) const
vmesh::VelocityBlockContainer * get_velocity_blocks(const size_t &popID)
Population & get_population(const uint popID)
ARCH_HOSTDEV vmesh::LocalID size() const
ObjectWrapper & getObjectWrapper()
auto calculate_total_size_bytes(const std::vector< std::size_t > &architecture, std::size_t fourier_order, std::size_t output_dim) -> std::size_t
auto dump_vdf_to_binary_file(const char *filename, CellID cid) -> void
constexpr auto isPow2(std::unsigned_integral auto val) -> bool
void overwrite_cellids_vdf_single_cell(const std::span< const CellID > cids, uint popID, spatial_cell::SpatialCell *sc, size_t cc, const std::vector< std::array< T, 3 > > &vcoords, const std::vector< T > &vspace_union, const std::unordered_map< vmesh::LocalID, std::size_t > &map_exists_id)
auto calculate_hidden_neurons(std::size_t N_input, std::size_t N_output, std::size_t num_hidden_layers, std::size_t target_size) -> std::vector< std::size_t >
auto theoritical_lossless_compression_ratio(const std::vector< T > &data, std::size_t bits) -> T
auto shannon_entropy(const std::vector< T > &data) -> T
@ N_VELOCITY_BLOCK_PARAMS
bool save_to_file(const char *filename) const noexcept
std::size_t index(std::size_t i, std::size_t j, std::size_t k) const noexcept
std::vector< Realf > vdf_vals
std::array< Real, 6 > v_limits
Realf & at(std::size_t i, std::size_t j, std::size_t k) noexcept
const Realf & at(std::size_t i, std::size_t j, std::size_t k) const noexcept
std::size_t sparse_vdf_bytes
std::vector< vmesh::GlobalID > blocks_to_ignore
std::array< std::size_t, 3 > shape
std::array< Real, 6 > v_limits
std::vector< std::array< Real, 3 > > vdf_coords
std::vector< Realf > vdf_vals
bool save_to_file(const char *filename) const noexcept
VCoords operator-(const VCoords &other)
VCoords operator+(const VCoords &other)
std::vector< species::Species > particleSpecies
static std::vector< std::size_t > mlp_arch
static std::size_t mlp_fourier_order