Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
compression_tools.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This file is part of Vlasiator.
4 * Copyright 2010-2024 Finnish Meteorological Institute
5 *
6 * For details of usage, see the COPYING file and read the "Rules of the Road"
7 * at http://www.physics.helsinki.fi/vlasiator/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24// These tools are fwd declared here and implemented at the end of the file for
25// better clarity. They are not for external usage and as such they do not go
26// into the header file
27
28#include "../definitions.h"
29#include "../object_wrapper.h"
30#include <dccrg.hpp>
31#include "../logger.h"
32#include "../mpiconversion.h"
35#include "stdlib.h"
36#include <algorithm>
37#include <array>
38#include <cstdint>
39#include <fstream>
40#include <limits>
41#include <span>
42#include <stdexcept>
43#include <unordered_map>
44#include <vector>
45#include <cstring>
46#ifdef ASTERIX_OCTREE
47#include "toctree_compressor.h"
48#endif
49#ifdef ASTERIX_MLP
50#include "genericTsPool.h"
51#endif
52#ifdef ASTERIX_ZFP
53#include <zfp.h>
54#include "zfp/array1.hpp"
55#endif
56
57#ifdef ASTERIX_MLP
58#ifdef __cplusplus
59extern "C" {
60#endif
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);
65
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);
70#ifdef __cplusplus
71}
72#endif
73#endif //ASTERIX_MLP
74
75#define MLP_KEY 42
76
77namespace ASTERIX {
78struct VCoords {
80 VCoords operator+(const VCoords& other) { return {vx + other.vx, vy + other.vy, vz + other.vz}; }
81 VCoords operator-(const VCoords& other) { return {vx - other.vx, vy - other.vy, vz - other.vz}; }
82};
83
84struct OrderedVDF {
85
87 std::size_t ignore_bytes;
88 std::size_t octree_bytes;
89 };
90
91 std::vector<vmesh::GlobalID> blocks_to_ignore;
92 std::size_t sparse_vdf_bytes = {0};
93 std::vector<Realf> vdf_vals;
94 std::array<Real, 6> v_limits; // vx_min,vy_min,vz_min,vx_max,vy_max,vz_max
95 std::array<std::size_t, 3> shape; // x,y,z
96 std::size_t index(std::size_t i, std::size_t j, std::size_t k) const noexcept {
97 return i * (shape[1] * shape[2]) + j * shape[2] + k;
98 }
99
100 Realf& at(std::size_t i, std::size_t j, std::size_t k) noexcept { return vdf_vals.at(index(i, j, k)); }
101
102 const Realf& at(std::size_t i, std::size_t j, std::size_t k) const noexcept { return vdf_vals.at(index(i, j, k)); }
103
104 bool save_to_file(const char* filename) const noexcept {
105 std::ofstream file(filename, std::ios::out | std::ios::binary);
106 if (!file) {
107 std::cerr << "Could not open file for writting! Exiting!" << std::endl;
108 return false;
109 }
110 file.write((char*)shape.data(), 3 * sizeof(size_t));
111 if (!file) {
112 std::cerr << "Error writing shape data to file!" << std::endl;
113 return false;
114 }
115
116 file.write((char*)vdf_vals.data(), vdf_vals.size() * sizeof(Realf));
117 if (!file) {
118 std::cerr << "Error writing vdf_vals data to file!" << std::endl;
119 return false;
120 }
121 return true;
122 }
123};
124
126 std::vector<Realf> vdf_vals;
127 std::vector<std::array<Real, 3>> vdf_coords;
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()};
131
132 bool save_to_file(const char* filename) const noexcept {
133 std::ofstream file(filename, std::ios::out | std::ios::binary);
134 if (!file) {
135 std::cerr << "Could not open file for writting! Exiting!" << std::endl;
136 return false;
137 }
138
139 file.write((char*)vdf_vals.size(), sizeof(size_t));
140 if (!file) {
141 std::cerr << "Error writing size data to file!" << std::endl;
142 return false;
143 }
144
145 file.write((char*)v_limits.data(), 6 * sizeof(Real));
146 if (!file) {
147 std::cerr << "Error writing size data to file!" << std::endl;
148 return false;
149 }
150
151 file.write((char*)vdf_coords.data(), vdf_coords.size() * 3 * sizeof(Real));
152 if (!file) {
153 std::cerr << "Error writing vdf_coords data to file!" << std::endl;
154 return false;
155 }
156
157 file.write((char*)vdf_vals.data(), vdf_vals.size() * sizeof(Realf));
158 if (!file) {
159 std::cerr << "Error writing vdf_vals data to file!" << std::endl;
160 return false;
161 }
162 return true;
163 }
164};
165
166template <typename T> class PhaseSpaceUnion {
167public:
168 //---- No need for these------
169 PhaseSpaceUnion(const PhaseSpaceUnion& other) = delete;
173 //----------------------------
174 explicit PhaseSpaceUnion(const unsigned char* buffer) { deserialize_from(buffer); }
175
176 explicit PhaseSpaceUnion(const std::span<const CellID> cids, uint popID,
177 const dccrg::Dccrg<spatial_cell::SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid, bool center_vdfs)
178 : _center_vdfs(center_vdfs) {
179
180 // Let's find out which of these cellids has the largest VDF
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) {
184 spatial_cell::SpatialCell* sc = mpiGrid[cid];
185 const auto blockContainer = sc->get_velocity_blocks(popID);
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);
189 }
190 _effective_vdf_size = bytes_of_all_local_vdfs;
191
192 std::vector<std::vector<T>> vspaces(cids.size());
193 std::vector<double> f_sums(cids.size(), 0);
194 const Real sparse = static_cast<double>(getObjectWrapper().particleSpecies[popID].sparseMinValue);
195 for (std::size_t cc = 0; cc < cids.size(); ++cc) {
196 const auto& cid = cids[cc];
197 _cids.push_back(cid);
198 spatial_cell::SpatialCell* sc = mpiGrid[cid];
199 auto blockContainer = sc->get_velocity_blocks(popID);
200 const std::array<T, 3> bulkv{static_cast<T>(sc->get_population(popID).V[0]),
201 static_cast<T>(sc->get_population(popID).V[1]),
202 static_cast<T>(sc->get_population(popID).V[2])};
203
204 _vbulks.push_back(bulkv);
205 const size_t total_blocks = blockContainer->size();
206 Realf* data = blockContainer->getData();
207 const Real* blockParams = sc->get_block_parameters(popID);
208 for (std::size_t n = 0; n < total_blocks; ++n) {
209 const auto bp = blockParams + n * BlockParams::N_VELOCITY_BLOCK_PARAMS;
210 const vmesh::GlobalID gid = sc->get_velocity_block_global_id(n, popID);
211 const Realf* vdf_data = &data[n * WID3];
212
213 auto [it, block_inserted] = _map.try_emplace(gid, _vcoords.size());
214 std::size_t cnt = 0;
215 for (uint k = 0; k < WID; ++k) {
216 for (uint j = 0; j < WID; ++j) {
217 for (uint i = 0; i < WID; ++i) {
218
219 std::array<T, 3> coords = {
220 static_cast<T>(bp[BlockParams::VXCRD] + (i + 0.5) * bp[BlockParams::DVX]),
221 static_cast<T>(bp[BlockParams::VYCRD] + (j + 0.5) * bp[BlockParams::DVY]),
222 static_cast<T>(bp[BlockParams::VZCRD] + (k + 0.5) * bp[BlockParams::DVZ])};
223
224 if (_center_vdfs) {
225 coords[0] = coords[0] - bulkv[0];
226 coords[1] = coords[1] - bulkv[1];
227 coords[2] = coords[2] - bulkv[2];
228 }
229
230 _v_limits[0] = std::min(_v_limits[0], static_cast<T>(coords[0]));
231 _v_limits[1] = std::min(_v_limits[1], static_cast<T>(coords[1]));
232 _v_limits[2] = std::min(_v_limits[2], static_cast<T>(coords[2]));
233 _v_limits[3] = std::max(_v_limits[3], static_cast<T>(coords[0]));
234 _v_limits[4] = std::max(_v_limits[4], static_cast<T>(coords[1]));
235 _v_limits[5] = std::max(_v_limits[5], static_cast<T>(coords[2]));
236 const double vdf_val = static_cast<double>(vdf_data[cellIndex(i, j, k)]);
237 if (block_inserted) { // which means the block was not there before
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));
241 }
242 } else { // So the block was there
243 vspaces[cc].at(it->second + cnt) = vdf_val;
244 }
245 f_sums.at(cc) += static_cast<double>(vdf_val);
246 cnt++;
247 }
248 }
249 }
250 }
251 }
252 _nrows = vspaces.front().size();
253 _ncols = cids.size();
254 // This will be used further down for indexing into the vspace_union
255 auto index_2d = [this](std::size_t row, std::size_t col) -> std::size_t { return row * _ncols + col; };
256
257 // Resize to fit the union of vspace coords and vspace density
258 _vspace = std::move(std::vector<T>(_nrows * _ncols, T(0)));
259 for (std::size_t i = 0; i < _nrows; ++i) {
260 for (std::size_t j = 0; j < _ncols; ++j) {
261 _vspace.at(index_2d(i, j)) = vspaces[j][i];
262 }
263 }
264 // Scale now
265 scale(sparse);
266 // Store norms
267 _norms = std::move(std::vector<Norms>(_ncols, Norms{}));
268 }
269
270 void scale(T sparse) noexcept {
271 std::for_each(_vspace.begin(), _vspace.end(),
272 [sparse](T& value) { value = std::log10(std::max(value, sparse)) - std::log10(sparse); });
273 }
274
275 //Here we min max normalize both VDF(per VDF minmax) and VCOORDS
276 //TODO remove uneeded stuff from NORMS
277 void normalize() noexcept {
278 // Vcoords
279 std::ranges::for_each(_vcoords, [this](std::array<T, 3>& x) {
280 x[0] = 2.0 * ((x[0] - _v_limits[0]) / (_v_limits[3] - _v_limits[0])) - 1.0;
281 x[1] = 2.0 * ((x[1] - _v_limits[1]) / (_v_limits[4] - _v_limits[1])) - 1.0;
282 x[2] = 2.0 * ((x[2] - _v_limits[2]) / (_v_limits[5] - _v_limits[2])) - 1.0;
283 });
284 // Per VDF min max scaling
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) {
290 min_val = std::min(min_val, _vspace[index_2d(i, v)]);
291 max_val = std::max(max_val, _vspace[index_2d(i, v)]);
292 }
293 for (std::size_t i = 0; i < _nrows; ++i) {
294 _vspace[index_2d(i, v)] /= max_val;
295 }
296 _norms[v] = Norms{.min = min_val, .max = max_val};
297 }
298 }
299
300 //We do the reverse of normalize()
301 void unormalize_and_unscale(T sparse) noexcept {
302 std::ranges::for_each(_vcoords, [this](std::array<T, 3>& x) {
303 x[0] = ((x[0] + 1.0) / 2.0) * (_v_limits[3] - _v_limits[0]) + _v_limits[0];
304 x[1] = ((x[1] + 1.0) / 2.0) * (_v_limits[4] - _v_limits[1]) + _v_limits[1];
305 x[2] = ((x[2] + 1.0) / 2.0) * (_v_limits[5] - _v_limits[2]) + _v_limits[2];
306 });
307
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) {
313 _vspace[index_2d(i, v)] = sparse*std::pow(10.0, _vspace[index_2d(i, v)]*max_val );
314 }
315 }
316 }
317
318 constexpr std::size_t index_2d(std::size_t row, std::size_t col) const noexcept { return row * _ncols + col; };
319
320 void sparsify(T sparse) noexcept {
321 std::for_each(_vspace.begin(), _vspace.end(), [sparse](T& x) {
322 if (x - sparse < 0.0) {
323 x = 0.0;
324 }
325 });
326 }
327
328 std::size_t total_serialized_size_bytes() const {
329 return sizeof(Header) + _cids.size() * sizeof(CellID) + _norms.size() * sizeof(Norms) +
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>);
332 ;
333 }
334
335 void serialize_into(unsigned char* buffer) const {
336 Header header;
337 header.key = MLP_KEY;
339 header.rows = _nrows;
340 header.cols = _ncols;
341 header.n_weights = _n_weights;
342 header.type_size = sizeof(T);
343 std::size_t write_index = 0;
344
345 std::memcpy(&buffer[write_index], &header, sizeof(Header));
346 write_index += sizeof(Header);
347
348 std::memcpy(&buffer[write_index], &_cids[0], _cids.size() * sizeof(CellID));
349 write_index += _cids.size() * sizeof(CellID);
350
351 std::memcpy(&buffer[write_index], &_norms[0], _norms.size() * sizeof(Norms));
352 write_index += _norms.size() * sizeof(Norms);
353
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>);
356
357 std::memcpy(&buffer[write_index], &_v_limits[0], 6 * sizeof(T));
358 write_index += 6 * sizeof(T);
359
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>);
362
363 std::memcpy(&buffer[write_index], &_network_weights[0], _n_weights * sizeof(T));
364 write_index += _n_weights * sizeof(T);
365
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>);
369 }
370 assert(header.total_size == write_index);
371 if (!(header.total_size == write_index)) {
372 throw std::runtime_error("Failed to fully write state");
373 }
374 }
375
376 void deserialize_from(const unsigned char* buffer) {
377 const Header* const header = reinterpret_cast<const Header*>(&buffer[0]);
378 assert(header->key == MLP_KEY && "Blame Kostis Papadakis for this!");
379 if (!(header->key == MLP_KEY)){
380 throw std::runtime_error("Wrong MLP Header KEY");
381 }
382
383 // Inflate vspave union
384 _vspace.resize(header->cols * header->rows);
385 _ncols = header->cols;
386 _nrows = header->rows;
387
388 // Recover cids in this union;
389 std::size_t read_index = sizeof(Header);
390 std::size_t cids_size = header->cols;
391 _cids.resize(cids_size);
392
393 std::memcpy(_cids.data(), &buffer[read_index], cids_size * sizeof(CellID));
394 read_index += cids_size * sizeof(CellID);
395
396 std::size_t norms_size = cids_size;
397 _norms.resize(cids_size);
398 std::memcpy(_norms.data(), &buffer[read_index], norms_size * sizeof(Norms));
399 read_index += norms_size * sizeof(Norms);
400
401 std::size_t vbulk_size = cids_size;
402 _vbulks.resize(vbulk_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>);
405
406 std::memcpy(&_v_limits[0], &buffer[read_index], 6 * sizeof(T));
407 read_index += 6 * sizeof(T);
408
409 std::size_t vcoords_size = header->rows;
410 _vcoords.resize(vcoords_size);
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>);
413
414 if (_network_weights != nullptr) {
415 free(_network_weights);
416 }
417
418 _network_weights = (T*)malloc(header->n_weights * sizeof(T));
419 _n_weights = header->n_weights;
420 std::memcpy(_network_weights, &buffer[read_index], header->n_weights * sizeof(T));
421 read_index += _n_weights * sizeof(T);
422
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>);
428 }
429 assert(read_index == header->total_size && "Size mismatch while reading in serialized VDF Union!");
430 if (!(read_index == header->total_size)){
431 throw std::runtime_error("Failed to fully read state");
432 }
433 }
434
435 struct Norms {
436 double min = std::numeric_limits<double>::max();
437 double max = std::numeric_limits<double>::min();
438 };
439
440 struct Header {
441 std::size_t key;
442 std::size_t total_size;
443 std::size_t rows;
444 std::size_t cols;
445 std::size_t n_weights;
446 std::size_t type_size;
447 };
448
449 std::size_t _nrows = {0};
450 std::size_t _ncols = {0};
452
453 std::vector<Norms> _norms;
454 std::vector<CellID> _cids;
455 std::vector<std::array<T, 3>> _vcoords;
456 std::vector<std::array<T, 3>> _vbulks;
457 std::vector<T> _vspace;
458 std::unordered_map<vmesh::GlobalID, std::size_t> _map;
459 T* _network_weights = nullptr;
460 std::size_t _effective_vdf_size = {0};
461 std::size_t _n_weights = {0};
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()};
465};
466
467auto extract_pop_vdf_from_spatial_cell(spatial_cell::SpatialCell* sc, uint popID) -> UnorderedVDF;
468
469auto extract_pop_vdf_from_spatial_cell_ordered_min_bbox_zoomed(spatial_cell::SpatialCell* sc, uint popID, int zoom) -> OrderedVDF;
470
471constexpr auto isPow2(std::unsigned_integral auto val) -> bool { return (val & (val - 1)) == 0; };
472
473auto overwrite_pop_spatial_cell_vdf(spatial_cell::SpatialCell* sc, uint popID, const std::vector<Realf>& new_vspace) -> void;
474
475auto overwrite_pop_spatial_cell_vdf(spatial_cell::SpatialCell* sc, uint popID, const OrderedVDF& vdf) -> void;
476
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;
481
482auto dump_vdf_to_binary_file(const char* filename, CellID cid) -> void;
483
484auto dump_vdf_to_binary_file(const char* filename, CellID cid,
485 dccrg::Dccrg<spatial_cell::SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) -> void;
486
487// https://en.wikipedia.org/wiki/Entropy_(information_theory)
488template <typename T>
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();
491 if (sz == 0) {
492 return 0.0;
493 }
494
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]))]++;
499 }
500 T entropy = 0.0;
501 for (const auto& [byte, count] : frequency) {
502 T pk = static_cast<T>(count) / sz;
503 entropy -= pk * std::log2(pk);
504 }
505 return entropy;
506}
507
508template <typename T>
509requires(std::is_same_v<T, float> ||
510 std::is_same_v<T, double>) auto theoritical_lossless_compression_ratio(const std::vector<T>& data,
511 std::size_t bits) -> T {
512 T entorpy = shannon_entropy(data);
513 return static_cast<T>(bits) / entorpy;
514}
515
516template <typename NetworkType>
517requires(std::is_same_v<NetworkType, float> || std::is_same_v<NetworkType, double>) auto calculate_total_size_bytes(
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.");
521 }
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];
526
527 for (std::size_t i = 1; i < architecture.size(); ++i) {
528 total_size += architecture[i - 1] * architecture[i];
529 total_size += architecture[i];
530 }
531
532 total_size += architecture.back() * output_dim;
533 total_size += output_dim;
534
535 return total_size * sizeof(NetworkType);
536}
537
538template <typename NetworkType>
539requires(std::is_same_v<NetworkType, float> || std::is_same_v<NetworkType, double>) auto calculate_hidden_neurons(
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); // 2 input and output
543 neurons[0] = N_input;
544 neurons[num_hidden_layers + 1] = N_output;
545
546 // We guess this heyuristically
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;
550 }
551 std::size_t current_size = calculate_total_size_bytes<NetworkType>(neurons);
552
553 while (current_size < target_size) {
554 for (std::size_t i = 1; i <= num_hidden_layers; ++i) {
555 neurons[i]++;
556 }
557 current_size = calculate_total_size_bytes<NetworkType>(neurons);
558 }
559
560 while (current_size > target_size) {
561 for (std::size_t i = 1; i <= num_hidden_layers; ++i) {
562 if (neurons[i] > 1) {
563 neurons[i]--;
564 }
565 }
566 current_size = calculate_total_size_bytes<NetworkType>(neurons);
567 }
568 return neurons;
569}
570Real get_Non_MaxWellianity(const spatial_cell::SpatialCell* cell, uint popID);
571
572#ifdef ASTERIX_MLP
573template <typename T> void decompressPhaseSpace(PhaseSpaceUnion<T>& rv) {
574 // Memory allocation
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(),
578 P::mlp_fourier_order, P::mlp_arch.data(), P::mlp_arch.size(), rv._network_weights,
579 rv._n_weights * sizeof(float), true);
580 } else {
581 decompress_phasespace6D_f64(&p, 3, rv._ncols, &rv._vcoords[0][0], rv._vspace.data(), rv._vcoords.size(),
582 P::mlp_fourier_order, P::mlp_arch.data(), P::mlp_arch.size(), rv._network_weights,
583 rv._n_weights * sizeof(double), true);
584 }
585}
586#endif //ASTERIX_MLP
587
588template <typename T>
589void overwrite_cellids_vdf_single_cell(const std::span<const CellID> cids, uint popID, spatial_cell::SpatialCell* sc, size_t cc,
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();
594 // This will be used further down for indexing into the vspace_union
595 auto index_2d = [nrows, ncols](std::size_t row, std::size_t col) -> std::size_t { return row * ncols + col; };
596
597 const auto& cid = cids[cc];
598 auto blockContainer = sc->get_velocity_blocks(popID);
599 const size_t total_blocks = blockContainer->size();
600 Realf* data = blockContainer->getData();
601 const Real* blockParams = sc->get_block_parameters(popID);
602 for (std::size_t n = 0; n < total_blocks; ++n) {
603 const auto bp = blockParams + n * BlockParams::N_VELOCITY_BLOCK_PARAMS;
604 const vmesh::GlobalID gid = sc->get_velocity_block_global_id(n, popID);
605 const auto it = map_exists_id.find(gid);
606 const bool exists = it != map_exists_id.end();
607 if (!exists) {
608 continue;
609 }
610 const auto index = it->second;
611 Realf* vdf_data = &data[n * WID3];
612 size_t cnt = 0;
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;
617 vdf_data[cellIndex(i, j, k)] = vspace_union[index_2d(index + cnt, cc)];
618 cnt++;
619 }
620 }
621 }
622 }
623 return;
624}
625
626} // namespace ASTERIX
Binary file
Definition Dispersion.m:11
for i
Definition Dispersion.m:24
Numerical propagation V
Definition Dispersion.m:98
std::array< T, 6 > _v_limits
PhaseSpaceUnion & operator=(const PhaseSpaceUnion &other)=delete
void sparsify(T sparse) noexcept
std::unordered_map< vmesh::GlobalID, std::size_t > _map
void serialize_into(unsigned char *buffer) const
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
#define WID
Definition common.h:514
const int WID3
Definition common.h:517
#define MLP_KEY
float Real
Definition definitions.h:41
uint64_t CellID
Definition definitions.h:54
float Realf
Definition definitions.h:33
const int j
const int k
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
#define index(i, j, k)
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
Definition common.h:115
uint32_t GlobalID
Definition definitions.h:59
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::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
Definition parameters.h:257
static std::size_t mlp_fourier_order
Definition parameters.h:258