26#include "zfp/array1.hpp"
39#include <unordered_map>
44#define ASTERIX_USE_GPU
45#define MEMPOOL_BYTES 60ul*1024ul*1024ul*1024ul
53size_t compress_phasespace6D_f64(GENERIC_TS_POOL::MemPool* p, std::size_t fin,std::size_t fout,
double* coords_ptr,
double* f_ptr,
54 std::size_t size, std::size_t max_epochs, std::size_t fourier_order,
55 size_t* hidden_layers_ptr,
size_t n_hidden_layers,
double sparsity,
double tol,
56 double* weights_ptr, std::size_t weight_size,
bool use_input_weights,
57 uint32_t downsampling_factor,
double& error, uint32_t& epochs,
int& status,
int rankID);
59size_t compress_phasespace6D_f32(GENERIC_TS_POOL::MemPool* p, std::size_t fin,std::size_t fout,
float* coords_ptr,
float* f_ptr,
60 std::size_t size, std::size_t max_epochs, std::size_t fourier_order,
61 size_t* hidden_layers_ptr,
size_t n_hidden_layers,
float sparsity,
float tol,
62 float* weights_ptr, std::size_t weight_size,
bool use_input_weights,
63 uint32_t downsampling_factor,
float& error, uint32_t& epochs,
int& status,
int rankID);
69auto compress_vdfs_fourier_mlp(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
70 size_t number_of_spatial_cells,
bool update_weights, std::vector<std::vector<char>>&bytes ,uint32_t downsampling_factor)
73auto compress_vdfs_fourier_mlp_clustered(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
74 size_t number_of_spatial_cells,
bool update_weights, std::vector<std::vector<char>>&bytes,
75 uint32_t downsampling_factor) -> float;
81auto compress_vdfs_zfp(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
const std::vector<CellID>& local_cells)
84auto compress(
float* array,
size_t arraySize,
size_t& compressedSize,
float tol) -> std::vector<char>;
86auto compress(
double* array,
size_t arraySize,
size_t& compressedSize,
double tol) -> std::vector<char>;
89 -> std::vector<double>;
91auto decompressArrayFloat(
char* compressedData,
size_t compressedSize,
size_t arraySize,
float tol)
92 -> std::vector<float>;
97auto compress_vdfs_octree(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
const std::vector<CellID>& local_cells)
102void ASTERIX::compress_vdfs(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
const std::vector<CellID>& cells,
104 std::vector<std::vector<char>>& bytes, uint32_t downsampling_factor ) {
106 if (downsampling_factor < 1) {
107 throw std::runtime_error(
"Requested downsampling factor in VDF compression makes no sense!");
109 float local_compression_ratio = 0.0;
113 local_compression_ratio =
114 compress_vdfs_fourier_mlp(mpiGrid, cells.size(), update_weights, bytes,downsampling_factor);
117 local_compression_ratio =
118 compress_vdfs_fourier_mlp_clustered(mpiGrid, cells.size(), update_weights, bytes, downsampling_factor);
123 local_compression_ratio = compress_vdfs_zfp(mpiGrid, cells);
128 local_compression_ratio = compress_vdfs_octree(mpiGrid, cells);
134 throw std::runtime_error(
"This is bad!. Improper Asterix method detected!");
141 float global_compression_ratio = 0.0;
142 MPI_Comm_size(MPI_COMM_WORLD, &mpiProcs);
143 MPI_Comm_rank(MPI_COMM_WORLD, &
myRank);
144 MPI_Barrier(MPI_COMM_WORLD);
145 MPI_Reduce(&local_compression_ratio, &global_compression_ratio, 1, MPI_FLOAT, MPI_SUM,
MASTER_RANK, MPI_COMM_WORLD);
146 MPI_Barrier(MPI_COMM_WORLD);
149 logFile <<
"(VDF COMPRESSION INFO): Compression Ratio = "
150 << global_compression_ratio /
static_cast<float>(mpiProcs) << std::endl;
154std::vector<std::pair<std::size_t, std::size_t>>
partition(std::size_t array_size, std::size_t chunk_size,
155 std::size_t max_chunks) {
156 std::vector<std::pair<std::size_t, std::size_t>> result;
157 if (array_size == 0 || chunk_size <= 0 || max_chunks <= 0) {
158 throw std::runtime_error(
"ERROR: catastrophic failure in VDF partitioning.");
160 std::size_t optimal_chunks = std::max(1.0,std::ceil(array_size / chunk_size));
161 std::size_t numChunks = std::min(optimal_chunks, max_chunks);
162 std::size_t baseSize = array_size / numChunks;
163 std::size_t largerChunks = array_size % numChunks;
164 std::size_t start = 0;
165 for (std::size_t
i = 0;
i < numChunks; ++
i) {
166 std::size_t chunkSize = baseSize + (
i < largerChunks ? (1) : (0));
167 result.push_back({start, start + chunkSize});
174 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
175 std::vector<std::pair<CellID, Real>> sorted_vdf;
176 sorted_vdf.reserve(local_cells.size());
177 for (
const auto& cid : local_cells) {
180 std::ranges::sort(sorted_vdf, {}, &std::pair<CellID, Real>::second);
181 std::vector<CellID> sorted_cells;
182 sorted_cells.reserve(sorted_vdf.size());
183 for (
const auto& [cid, _] : sorted_vdf) {
184 sorted_cells.push_back(cid);
190float compress_vdfs_fourier_mlp(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
191 size_t number_of_spatial_cells,
bool update_weights,
192 std::vector<std::vector<char>>& bytes, uint32_t downsampling_factor) {
195 GENERIC_TS_POOL::MemPool
p{};
197 MPI_Comm_rank(MPI_COMM_WORLD, &
myRank);
200 throw std::runtime_error(
"Multi-Pop not implemented yet!");
202 std::atomic<float> local_compression_achieved = 0.0;
203 std::size_t total_samples = 0;
208 std::vector<CellID> local_cells;
209 for (
auto&
c : _local_cells) {
213 auto blockContainer = mpiGrid[
c]->get_velocity_blocks(popID);
214 const size_t total_blocks = blockContainer->size();
215 if (total_blocks==0){
218 local_cells.push_back(
c);
221 const std::size_t num_threads = omp_get_max_threads();
228 const std::size_t threads_needed = partitionScheme.size();
229 total_samples += partitionScheme.size();
230 omp_set_num_threads(threads_needed);
231 std::vector<std::vector<char>> thread_bytes(threads_needed);
234 std::size_t thread_id = omp_get_thread_num();
235 const std::pair<std::size_t, std::size_t> index_range = partitionScheme.at(thread_id);
236 const std::size_t count = index_range.second - index_range.first;
237 printf(
"Count = %zu \n",count);
238 const auto start = local_cells.data() + index_range.first;
239 const std::span<const CellID> span(start, count);
244 Realf error = std::numeric_limits<double>::max();
249 b._network_weights = (
Realf*)malloc(network_size);
250 b._n_weights = network_size /
sizeof(
Realf);
253 std::size_t nn_mem_footprint_bytes = compress_phasespace6D_f32(
256 b._network_weights, network_size,
false, downsampling_factor, error, epochs ,status,
myRank);
259 std::size_t nn_mem_footprint_bytes = compress_phasespace6D_f64(
262 b._network_weights, network_size,
false, downsampling_factor, error, epochs, status,
myRank);
264 for (
const auto sc:span){
265 mpiGrid[sc]->get_population(popID).mlp_error=
static_cast<float>(error);
266 mpiGrid[sc]->get_population(popID).mlp_epochs = epochs;
268 assert(network_size == nn_mem_footprint_bytes &&
"Mismatch betweeen estimated and actual network size!!!");
269 thread_bytes.at(thread_id) = std::vector<char>(
b.total_serialized_size_bytes());
270 b.serialize_into(
reinterpret_cast<unsigned char*
>(thread_bytes.at(thread_id).data()));
272 free(
b._network_weights);
273 local_compression_achieved +=
274 static_cast<float>(
b._effective_vdf_size) /
static_cast<float>(nn_mem_footprint_bytes);
276 bytes = thread_bytes;
278 return local_compression_achieved /
static_cast<float>(total_samples);
281std::vector<std::vector<std::pair<CellID, Real>>>
282clusterVDFs(
const std::vector<CellID>& local_cells,
const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
283 uint popID,
bool single_cluster =
false) {
284 std::vector<Real> non_maxwellianity(local_cells.size(), 0.0);
285 std::transform(local_cells.begin(), local_cells.end(), non_maxwellianity.begin(),
286 [&](
const auto& cid) { return get_Non_MaxWellianity(mpiGrid[cid], popID); });
287 std::vector<std::pair<CellID, Real>> sorted_vdf(local_cells.size());
288 for (std::size_t
i = 0;
i < local_cells.size(); ++
i) {
289 sorted_vdf[
i] = {local_cells[
i], non_maxwellianity[
i]};
291 std::sort(sorted_vdf.begin(), sorted_vdf.end(), [](
const auto& a,
const auto& b) { return a.second < b.second; });
292 if (single_cluster) {
295 std::vector<std::vector<std::pair<CellID, Real>>> clusters;
296 std::vector<std::pair<CellID, Real>> current_cluster;
298 for (
const auto& pair : sorted_vdf) {
299 if (current_cluster.empty()) {
300 current_cluster.push_back(pair);
303 const Real last_value = current_cluster.back().second;
304 const Real margin =
Real(0.2) * std::max(last_value, pair.second);
305 if (std::fabs(last_value - pair.second) <= margin) {
306 current_cluster.push_back(pair);
308 clusters.push_back(std::move(current_cluster));
309 current_cluster.clear();
310 current_cluster.push_back(pair);
313 if (!current_cluster.empty()) {
314 clusters.push_back(std::move(current_cluster));
319float compress_vdfs_fourier_mlp_clustered(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
320 size_t number_of_spatial_cells,
bool update_weights, std::vector<std::vector<char>>&bytes,
321 uint32_t downsampling_factor) {
326 MPI_Comm_rank(MPI_COMM_WORLD, &
myRank);
327 GENERIC_TS_POOL::MemPool
p{};
329 throw std::runtime_error(
"Multi-Pop not implemented yet!");
331 float local_compression_achieved = 0.0;
332 std::size_t total_samples = 0;
337 std::vector<CellID> local_cells;
338 for (
auto&
c : _local_cells) {
342 local_cells.push_back(
c);
344 const auto clusters = clusterVDFs(local_cells, mpiGrid, popID,
true);
348 bytes.resize(clusters.size());
349#pragma omp parallel for reduction(+ : local_compression_achieved)
350 for (std::size_t
i =0 ;
i< clusters.size();++
i) {
351 auto& cluster = clusters.at(
i);
355 std::vector<CellID> cids(cluster.size());
356 std::transform(cluster.begin(), cluster.end(), cids.begin(), [](
const auto& pair) { return pair.first; });
359 const std::span<const CellID> span(cids.data(), cids.size());
364 Realf error = std::numeric_limits<double>::max();
370 b._network_weights = (
Realf*)malloc(network_size);
371 b._n_weights = network_size /
sizeof(
Realf);
374 std::size_t nn_mem_footprint_bytes = compress_phasespace6D_f32(
377 b._network_weights, network_size,
false, downsampling_factor, error, epochs, status,
myRank);
380 std::size_t nn_mem_footprint_bytes = compress_phasespace6D_f64(
383 b._network_weights, network_size,
false, downsampling_factor, error, epochs, status,
myRank);
385 for (
const auto sc:span){
386 mpiGrid[sc]->get_population(popID).mlp_error=
static_cast<float>(error);
387 mpiGrid[sc]->get_population(popID).mlp_epochs = epochs;
389 assert(network_size == nn_mem_footprint_bytes &&
"Mismatch betweeen estimated and actual network size!!!");
391 bytes.at(
i).resize(
b.total_serialized_size_bytes());
392 b.serialize_into(
reinterpret_cast<unsigned char*
>(bytes.at(
i).data()));
393 free(
b._network_weights);
394 local_compression_achieved +=
static_cast<float>(
b._effective_vdf_size) /
static_cast<float>(nn_mem_footprint_bytes);
397 return local_compression_achieved /
static_cast<float>(total_samples);
403float compress_vdfs_zfp(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
const std::vector<CellID>& local_cells) {
404 float local_compression_achieved = 0.0;
405 std::size_t total_samples = 0;
409#pragma omp parallel for reduction(+ : local_compression_achieved)
410 for (
auto& cid : local_cells) {
412 assert(sc &&
"Invalid Pointer to Spatial Cell !");
417 const size_t total_blocks = blockContainer->
size();
418 if (total_blocks==0){
431 compress(
vdf.vdf_vals.data(),
vdf.vdf_vals.size(), ss, sparse);
432 float ratio =
static_cast<float>(
vdf.vdf_vals.size() *
sizeof(
Realf)) /
static_cast<float>(ss);
433 local_compression_achieved += ratio;
436 return local_compression_achieved /
static_cast<float>(total_samples);
443float compress_vdfs_octree(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
444 const std::vector<CellID>& local_cells) {
446 int global_total_bytes = 0;
447 float local_compression_achieved = 0.0;
448 std::size_t total_samples = 0;
451#pragma omp parallel for reduction(+ : total_bytes, local_compression_achieved)
452 for (
auto& cid : local_cells) {
458 const size_t total_blocks = blockContainer->
size();
459 if (total_blocks==0){
469 uint8_t* bytes =
nullptr;
471 constexpr std::size_t maxiter = 50000;
472 constexpr std::size_t skip_levels = 4;
473 int status = compress_with_toctree_method(
vdf.vdf_vals.data(),
vdf.shape[0],
vdf.shape[1],
vdf.shape[2],
477 case TOCTREE_COMPRESS_STAT_SUCCESS:
479 case TOCTREE_COMPRESS_STAT_FAIL_TOL:
480 logFile <<
"(VDF COMPRESSION INFO): T-Octree failed to reach tolerance " <<
484 throw std::runtime_error(
"(VDF COMPRESSION ERROR): T-Octree failed.");
491 std::size_t ignored_blocks=
vdf.blocks_to_ignore.size();
492 std::size_t write_index=0;
494 write_index+=
sizeof(std::size_t);
498 write_index+=3*
sizeof(std::size_t);
500 write_index+=6*
sizeof(
Real);
506 total_bytes += n_bytes;
507 local_compression_achieved +=
vdf.sparse_vdf_bytes /
static_cast<float>(n_bytes);
511 return local_compression_achieved /
static_cast<float>(total_samples);
516std::vector<char> compress(
float* array,
size_t arraySize,
size_t& compressedSize,
float tol) {
518 zfp_stream* zfp = zfp_stream_open(NULL);
519 zfp_field* field = zfp_field_1d(array, zfp_type_float, arraySize);
520 size_t maxSize = zfp_stream_maximum_size(zfp, field);
521 std::vector<char> compressedData(maxSize);
524 zfp_stream_set_accuracy(zfp, tol);
525 bitstream* stream = stream_open(compressedData.data(), compressedSize);
526 zfp_stream_set_bit_stream(zfp, stream);
527 zfp_stream_rewind(zfp);
530 compressedSize = zfp_compress(zfp, field);
531 compressedData.erase(compressedData.begin() + compressedSize, compressedData.end());
532 zfp_field_free(field);
533 zfp_stream_close(zfp);
534 stream_close(stream);
535 return compressedData;
542 std::vector<float> decompressedArray(arraySize);
545 zfp_stream* zfp = zfp_stream_open(NULL);
546 zfp_stream_set_accuracy(zfp, tol);
547 bitstream* stream_decompress = stream_open(compressedData, compressedSize);
548 zfp_stream_set_bit_stream(zfp, stream_decompress);
549 zfp_stream_rewind(zfp);
552 zfp_field* field_decompress = zfp_field_1d(decompressedArray.data(), zfp_type_float, decompressedArray.size());
553 size_t retval = zfp_decompress(zfp, field_decompress);
555 zfp_field_free(field_decompress);
556 zfp_stream_close(zfp);
557 stream_close(stream_decompress);
559 return decompressedArray;
563std::vector<char> compress(
double* array,
size_t arraySize,
size_t& compressedSize,
double tol) {
564 zfp_stream* zfp = zfp_stream_open(NULL);
565 zfp_field* field = zfp_field_1d(array, zfp_type_double, arraySize);
566 size_t maxSize = zfp_stream_maximum_size(zfp, field);
567 std::vector<char> compressedData(maxSize);
569 zfp_stream_set_accuracy(zfp, tol);
570 bitstream* stream = stream_open(compressedData.data(), compressedSize);
571 zfp_stream_set_bit_stream(zfp, stream);
572 zfp_stream_rewind(zfp);
574 compressedSize = zfp_compress(zfp, field);
575 compressedData.erase(compressedData.begin() + compressedSize, compressedData.end());
576 zfp_field_free(field);
577 zfp_stream_close(zfp);
578 stream_close(stream);
579 return compressedData;
585 std::vector<double> decompressedArray(arraySize);
587 zfp_stream* zfp = zfp_stream_open(NULL);
588 zfp_stream_set_accuracy(zfp, tol);
589 bitstream* stream_decompress = stream_open(compressedData, compressedSize);
590 zfp_stream_set_bit_stream(zfp, stream_decompress);
591 zfp_stream_rewind(zfp);
593 zfp_field* field_decompress = zfp_field_1d(decompressedArray.data(), zfp_type_double, decompressedArray.size());
594 size_t retval = zfp_decompress(zfp, field_decompress);
596 zfp_field_free(field_decompress);
597 zfp_stream_close(zfp);
598 stream_close(stream_decompress);
599 return decompressedArray;
vmesh::VelocityBlockContainer * get_velocity_blocks(const size_t &popID)
Population & get_population(const uint popID)
ARCH_HOSTDEV vmesh::LocalID size() const
const std::vector< CellID > & getLocalCells()
std::vector< CellID > sort_cells_based_on_maxwellianity(const std::vector< CellID > &local_cells, uint popID, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
std::vector< std::pair< std::size_t, std::size_t > > partition(std::size_t array_size, std::size_t chunk_size, std::size_t max_chunks)
ObjectWrapper & getObjectWrapper()
auto extract_pop_vdf_from_spatial_cell(spatial_cell::SpatialCell *sc, uint popID) -> UnorderedVDF
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
std::vector< double > decompressArrayDouble(char *compressedData, size_t compressedSize, size_t arraySize, double tol)
std::vector< float > decompressArrayFloat(char *compressedData, size_t compressedSize, size_t arraySize, float tol)
auto extract_pop_vdf_from_spatial_cell_ordered_min_bbox_zoomed(spatial_cell::SpatialCell *sc, uint popID, int zoom) -> OrderedVDF
void compress_vdfs(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &local_cells, P::ASTERIX_COMPRESSION_METHODS method, bool update_weights, std::vector< std::vector< char > > &mpl_bytes, uint32_t downsampling_factor=1)
Real get_Non_MaxWellianity(const spatial_cell::SpatialCell *cell, uint popID)
std::vector< species::Species > particleSpecies
ASTERIX_COMPRESSION_METHODS
static std::size_t max_vdfs_per_nn
static Real mlp_tollerance
static std::vector< std::size_t > mlp_arch
static std::size_t mlp_max_epochs
static Real octree_tolerance
static std::size_t mlp_fourier_order
std::vector< char > compressed_state_buffer