How the PC-side toolchain turns validated orbital math and atomSFE solutions into the two binary blobs the firmware reads from flash — data/orbital_samplers.bin and data/hfs_tables.bin — and how those blobs get from the repo onto the device's SPIFFS "storage" partition.
This is the build side of Tables to Point Clouds: the two blobs produced here are exactly the flash-resident "given" tables that page's pipelines consume (the hydrogen samplers and the atomSFE radial rows). The math behind the hydrogen samplers is the subject of Coefficients to Tables; the atomSFE model's design and the full regenerate/flash runbook live in ATOMS.md (§5) and pc/RUN_HFS.md.
tools/orbital_table_gen.py · micropython/pointcloud.py — one run per library entry (36 hydrogen presets), host-side in Python (double precision)
Given — the preset list and the math
Same code path already cross-validated bit-identical against the C++/JS ports by tools/orbitals_host/run_crosscheck.sh — this generator is not a third reimplementation, it reuses the MicroPython port itself.
kOrbitalLibrary / ORBITAL_PRESETS / micropython_shim1 · Sample each preset's inverse-CDF tables
Exactly the three quantile tables Coefficients to Tables describes buildOrbitalSamplerConstexpr() produces in C++ — same 1001-point resolution, same math, just executed on the PC instead of inside the compiler.
init_orbital_sampler()2 · Flatten to little-endian records
Tables are fixed at float32 on disk regardless of the generator's own precision — the C++ reader static_asserts sizeof(orb_real_t) == sizeof(float) so the fread() sizes can never silently drift. A missing or stale blob is caught by the 2-value header check and degrades to a single point at the origin, never a crash (see orbital_library.cpp).
Deliverable — data/orbital_samplers.bin
Regenerate with python3 tools/orbital_table_gen.py whenever kOrbitalLibrary / ORBITAL_PRESETS changes. No offset table: a preset's record index IS its index in kOrbitalLibrary, which stays compiled into the firmware.
pc/hfs_atomsfe.py → pc/hfs_tables.py --compact → tools/hfs_table_gen.py
Given — the solved wavefunctions
Eigenvalues reproduce the NIST dftdata LDA reference to ≤7×10⁻⁶ Ha across all 915 subshells, ground-state configurations 92/92 (pc/nist_compare_atomsfe.py, tolerance 2e-5 Ha/subshell). Non-relativistic — no Dirac pass for Z ≥ 55 (see ATOMS.md §5.2).
pc/hfs_atomsfe.py1 · Reduce to device resolution
The radial density is smooth in log-r, so downsampling keeps the shape: hfs_tables.compact()'s docstring measures the mode radius accurate to ~0.1% at its 513-point setting; 128 is the device reference. E/occ values ride along in the npz but are dropped in the blob.
hfs_tables.compact()2 · Pack into one flat blob
u = r·R, the same quantity the atom pipeline consumes as R(r) = u(r)/r. E/occ are dropped — occupancy already comes from each port's own configuration source (slater.h / slater.py), which the NIST cross-check matches 92/92 anyway.
build_flat() / emit_binary()Deliverable — data/hfs_tables.bin
Readers (src/physics/hfs_radial.cpp, micropython/hfs_radial_tables.py) sanity-check the file's own header against those constants at load. hfs_radial.cpp keeps its FILE* open across lookups — re-opening SPIFFS once per subshell measured ~800–980 ms for Fe's 7 subshells vs ~30–60 ms hydrogenic, so the open cost is paid once, not per row.
tools/hfs_table_gen.pyESP32 C++ (S3 / CYD)
partitions_16M.csv: spiffs, 7M at 0x810000. Chained onto every `pio run -t upload` by tools/extra_script_uploadfs.py (the CYD env uses tools/extra_script_uploadfs_cyd.py's pure-Python spiffsgen target instead). Both blobs are read on demand — once per preset/element switch, never per frame. Note: uploadfs reformats the whole partition, so it also wipes on-device screenshots.
MicroPython
Read by micropython/hfs_radial_tables.py (header/index resident in RAM, rows via open/seek). The hydrogen samplers are NOT a blob here — cloud_common.build_point_cloud() builds them at runtime with init_orbital_sampler(), memoized in a per-(n,ℓ,m) cache.
Missing or stale blob never crashes: the C++ readers return nullptr and the pipelines fall back (hydrogenic radii / single point at the origin) — a board that never ran `uploadfs` still boots and renders with the old math.
extra_script_uploadfs.py / mpremote fs cptools/atom_size_calib_gen.py — the κ_Z size-calibration tables
Elements without a CR literature value (Fr, Ra) get 1.0. Unlike the two blobs, these are generated source (headers/modules) compiled or copied into each port, not read from flash.
tools/atom_size_calib_gen.py