Files
space-cubion/outils/verify-physique.py
2026-08-12 00:34:34 +00:00

165 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SPACE CUBION — annexe reproductible (RS-1, 2026-08-11)
Recalcule les 7 blocs de calcul du papier resources/papers/space-cubion.md
(version v1 corrigée : table carré-cube ×3, cellule cubion ~1,2×10⁻⁷ s, n=3
divisions pour r/2) et imprime un tableau attendu-vs-calculé avec ✓/✗.
Régime : tout ce qui est vérifié ici est RÉEL (physique établie, arithmétique).
Aucune dépendance hors stdlib. Usage : python3 space-cubion-verify.py
Sortie 0 si tout est ✓, 1 sinon.
"""
import math
import sys
# ── Constantes ────────────────────────────────────────────────────────────────
G = 6.674e-11 # m³·kg⁻¹·s⁻² (constante gravitationnelle)
c_ms = 2.998e8 # m/s
g0 = 9.81 # m/s² (1 g)
AL = 9.4607e15 # m par année-lumière
AN = 3.15576e7 # s par an (année julienne)
L_SUN = 3.8e26 # W (luminosité solaire totale, valeur du papier)
CHECKS = []
def check(bloc, label, attendu, calcule, tol_rel=0.02, unite=""):
"""Compare attendu vs calculé à tol_rel près, mémorise ✓/✗."""
ok = attendu == calcule if attendu == 0 else abs(calcule - attendu) <= tol_rel * abs(attendu)
CHECKS.append((bloc, label, attendu, calcule, unite, ok))
return ok
def fmt(x):
if x == 0:
return "0"
ax = abs(x)
if ax >= 1e5 or ax < 1e-3:
return f"{x:.3g}"
return f"{x:.4g}"
# ── Bloc 1 · Temps propres à 1 g avec retournement (§7.1, RÉEL) ──────────────
# τ = (2c/a)·acosh(1 + a·d/(2c²)) — unités naturelles c=1 al/an, a en al/an².
def bloc1():
a = g0 * AN**2 / AL # 1 g ≈ 1,0326 al/an²
tau = lambda d_al: (2.0 / a) * math.acosh(1.0 + a * d_al / 2.0)
# (cible, distance al — table canonique Baez pour Vega/centre/Andromède, attendu ans)
cibles = [
("Proxima Centauri (4,24 al)", 4.24, 3.54),
("Alpha du Centaure (4,37 al)", 4.37, 3.58),
("Tau Ceti (11,9 al)", 11.9, 5.14),
("Vega (27 al)", 27.0, 6.58),
("TRAPPIST-1 (40,7 al)", 40.7, 7.33),
("Centre galactique (30 000 al)", 30000.0, 20.0),
("Andromède (2×10⁶ al)", 2.0e6, 28.2),
]
for nom, d, att in cibles:
check("1 · τ à 1 g", f"τ {nom}", att, tau(d), tol_rel=0.01, unite="ans")
# ── Bloc 2 · Table carré-cube CORRIGÉE (§5.1, RÉEL) ──────────────────────────
# a = 3·F_s/(ρ·r), F_s = 10⁵ N/m², ρ = 2 000 kg/m³ → 1,5 / 0,15 / 0,015 / 0,0015.
def bloc2():
Fs, rho = 1e5, 2000.0
a = lambda r: 3.0 * Fs / (rho * r)
for r, att in [(100.0, 1.5), (1e3, 0.15), (1e4, 0.015), (1e5, 0.0015)]:
check("2 · carré-cube", f"a(r={fmt(r)} m)", att, a(r), tol_rel=1e-9, unite="m/s²")
# ── Bloc 3 · Tsiolkovsky m₀/m_f = exp(Δv/v_e) (§7.3 + §15, RÉEL) ─────────────
def bloc3():
dv1 = 3.0e7 # m/s — 0,1 c, valeur explicite du papier (§7.3, c arrondi à 3×10⁸)
check("3 · Tsiolkovsky", "exposant chimique (v_e=4,5 km/s)", 6667.0, dv1 / 4.5e3, 1e-3)
check("3 · Tsiolkovsky", "exposant ionique (v_e=50 km/s)", 600.0, dv1 / 5.0e4, 1e-9)
check("3 · Tsiolkovsky", "m₀/m_f fusion (v_e=10⁴ km/s), 0,1 c", 20.09, math.exp(dv1 / 1e7), 1e-3)
check("3 · Tsiolkovsky", "m₀/m_f fusion, 0,2 c", 403.4, math.exp(2.0 * dv1 / 1e7), 1e-3)
check("3 · Tsiolkovsky", "m₀/m_f rendez-vous 0,01 c (§15)", 1.35, math.exp(0.1 * dv1 / 1e7), 5e-3)
# ── Bloc 4 · Budgets ½mv² vs L_☉ (§7.2, RÉEL — cellule cubion CORRIGÉE) ──────
# E = ½·m·(0,1c)² ; temps équivalent = E / L_☉. Cubion 100 t → ~1,2×10⁻⁷ s
# (~0,1 µs — l'ancien « ~0,1 s » du papier v0 était faux d'un facteur 10⁶).
def bloc4():
v = 3e7 # m/s — 0,1 c (arrondi du papier, c≈3×10⁸)
t_eq = lambda m: 0.5 * m * v**2 / L_SUN
lignes = [
("cubion 100 t (10⁵ kg)", 1e5, 1.18e-7, "s"),
("vaisseau 1 km (10¹² kg)", 1e12, 1.18, "s"),
("vaisseau 10 km (10¹⁵ kg)", 1e15, 19.7, "min"),
("vaisseau 100 km (10¹⁸ kg)", 1e18, 13.7, "jours"),
("masse lunaire (7,35×10²² kg)", 7.35e22, 2758.0, "ans"),
]
div = {"s": 1.0, "min": 60.0, "jours": 86400.0, "ans": AN}
for nom, m, att, u in lignes:
check("4 · ½mv²/L_☉", f"E/L_☉ {nom}", att, t_eq(m) / div[u], tol_rel=0.01, unite=u)
# ── Bloc 5 · Vitesse de libération (§2, RÉEL) ────────────────────────────────
# g_s = (4/3)·π·G·ρ·r ; v_esc = √(2·g_s·r).
def bloc5():
g_s = lambda rho, r: (4.0 / 3.0) * math.pi * G * rho * r
v_esc = lambda rho, r: math.sqrt(2.0 * g_s(rho, r) * r)
check("5 · v_esc", "g_s Lune (ρ=3340, r=1737 km)", 1.62, g_s(3340.0, 1.737e6), 0.01, "m/s²")
check("5 · v_esc", "v_esc Lune", 2.37, v_esc(3340.0, 1.737e6) / 1e3, 0.01, "km/s")
check("5 · v_esc", "g_s agrégat 100 km (ρ=2500)", 0.070, g_s(2500.0, 1e5), 0.01, "m/s²")
check("5 · v_esc", "v_esc agrégat 100 km", 0.118, v_esc(2500.0, 1e5) / 1e3, 0.01, "km/s")
# ── Bloc 6 · Ceinture d'astéroïdes et cubions (§8, RÉEL) ─────────────────────
# ⚠ ERRATUM v1 : le papier v0 écrit « ~0,03 % de la ceinture » pour 8×10⁹
# cubions ; le vrai ratio est 8×10¹⁴/3×10²¹ ≈ 2,7×10⁻⁷ soit ~0,00003 %
# (facteur ~10³) — l'argument s'en trouve RENFORCÉ, mais le chiffre est à
# corriger dans le papier au même titre que les 3 erreurs déjà relevées.
def bloc6():
M_ceinture, m_cubion, humains = 3e21, 1e5, 8e9
check("6 · ceinture", "cubions fabricables (3×10²¹/10⁵)", 3e16, M_ceinture / m_cubion, 1e-9)
check("6 · ceinture", "fraction pour 8×10⁹ humains", 2.67e-7, humains * m_cubion / M_ceinture, 0.01)
check("6 · ceinture", "doublements 1 → 10¹⁶", 53.2, math.log2(1e16), 0.01)
# ── Bloc 7 · Mitose 2^(1/3) et échelle 2ⁿ (§5.2 + §8.1, RÉEL — CORRIGÉ n=3) ──
# Couper en 2 → rayon × 2^(-1/3) ≈ 0,794. Il faut n = 3 divisions par 2
# successives pour diviser le rayon par 2 (0,794³ = 0,5) — pas « huit » ;
# 8 = le nombre de morceaux d'UN octa-découpage (2³). Et l'arête décidée :
# 4 m = 2⁸ bions de 16 mm (16 mm × 2⁸ = 4,096 m).
def bloc7():
f = 2.0 ** (1.0 / 3.0)
check("7 · mitose", "facteur de rayon 2^(1/3)", 1.26, f, 0.01)
check("7 · mitose", "rayon d'une moitié (r×2^(-1/3))", 0.794, 1.0 / f, 0.01)
check("7 · mitose", "n divisions pour r/2 (ln2/ln2^(1/3))", 3.0, math.log(2.0) / math.log(f), 1e-9)
check("7 · mitose", "morceaux d'un octa-découpage (2³)", 8.0, 2.0**3, 1e-9)
check("7 · mitose", "arête cubion 16 mm × 2⁸", 4.096, 0.016 * 2**8, 1e-9, "m")
# ── Exécution + tableau ──────────────────────────────────────────────────────
def main():
for bloc in (bloc1, bloc2, bloc3, bloc4, bloc5, bloc6, bloc7):
bloc()
print("SPACE CUBION — annexe reproductible : attendu vs calculé (papier v1 corrigé)")
print("=" * 96)
print(f"{'bloc':<16} {'grandeur':<44} {'attendu':>12} {'calculé':>12} {'ok':<2}")
print("-" * 96)
dernier_bloc = None
for bloc, label, att, cal, unite, ok in CHECKS:
if bloc != dernier_bloc and dernier_bloc is not None:
print("-" * 96)
dernier_bloc = bloc
u = f" {unite}" if unite else ""
print(f"{bloc:<16} {label:<44} {fmt(att):>12} {fmt(cal):>12} {'' if ok else ''}{u}")
print("=" * 96)
n_ok = sum(1 for chk in CHECKS if chk[-1])
n = len(CHECKS)
tout_bon = n_ok == n
print(f"{n_ok}/{n} vérifications ✓ — {'papier v1 corrigé COHÉRENT' if tout_bon else 'DIVERGENCE : corriger le papier ou le script'}")
return 0 if tout_bon else 1
if __name__ == "__main__":
sys.exit(main())