165 lines
8.2 KiB
Python
165 lines
8.2 KiB
Python
#!/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())
|