Mission + analyse du code original
Mission et analyse du code original
Mission
Porter le code de simulation gamma-imaging de Radience, écrit pour NVIDIA OptiX SDK 4.0.2 (sortie 2017), vers la dernière version NVIDIA OptiX 9.x (sortie 2024-2025), en exploitant l'occasion pour poser les fondations d'une intégration durable dans la chaîne de calcul scientifique de Radience.
Le projet est un portage architectural, pas une modernisation incrémentale (cf. docs/adr/ADR-001-vocabulaire-portage-radience.md). OptiX 7 (2019) a complètement refondu l'API : disparition du wrapper C++ optix::Context, passage à l'API C OptixDeviceContext + OptixModule + OptixProgramGroup + OptixPipeline + OptixShaderBindingTable. Le saut OptiX 4 vers 9 traverse cette frontière d'API sans pouvoir être incrémental.
Cadre contractuel
- NDA Mutuel Radience signé bilatéralement le 2026-05-01 (envelope DocuSign
AB716352-BDB6-8A21-82CF-987C13855A62). - Authorized Purpose (art. 2.3) : « évaluer la mise en place d'un partenariat technique sans engagement de prestation, autour de l'orchestration agentique des chaînes de calcul scientifique de Radience ».
- Fenêtre d'évaluation : 90 jours calendaires (NDA art. 12.8). Compteur démarré 2026-05-01. Date butoir : 2026-07-30.
- Confidentialité : tout artefact dérivé du code reçu est Information Confidentielle au sens art. 1.1, soumis aux obligations art. 2.1 (confidentialité), art. 2.3 (non-usage hors Authorized Purpose), art. 4.2 (retour ou destruction sur demande), art. 4.3 (durée de protection 5 ans post-terme NDA).
Trois choses que ce livrable doit prouver
Issue de la délibération delib-20260504-1de1, le contrat à J+45 (mid-point) puis J+90 (final) doit prouver trois choses :
- Compréhension — un wiki literate qui rend explicites les bits du système (pinhole geometry, bicouche W/Fe, RNG xorshift, 6 processus EM, 18 constantes hard-codées tracées vers leurs sources), lisible en 2-4 h par un nouvel ingénieur.
- Mesure falsifiable — 4-5 niveaux de tests numériques (L0-L4) avec seuils pré-déclarés et conditions de réfutation explicites, parcourus par une chaîne d'autorité de signature à 4 signataires (Emmanuel auto vers red-team agent vers Agustin vers François).
- Honnêteté sur les bornes — section "Bornes" en première page de chaque artefact nommant ce qui n'a pas pu être prouvé : robustesse production, conformité réglementaire éventuelle, bit-exactitude image, fidélité totale sans entretien Agustin.
L'observable principal de Radience n'est pas le binaire OptiX 9 fonctionnel (sous-produit nécessaire) — c'est le signal de fiabilité opérationnelle qui qualifie l'orchestration agentique comme partenaire. Le portage est l'instrument de cette évaluation, pas son objet.
Bornes (à nommer dès la première page)
Suivant la discipline carnot :
- Robustesse production — non-prouvable dans la fenêtre. Pas d'accès au pipeline VHEE complet, pas de jeu d'images calibrées en conditions opérationnelles.
- Conformité réglementaire — non-prouvable. Le NDA n'inclut ni cahier des charges clinique, ni traçabilité IEC 62304 / FDA 21 CFR 820. Le contexte semble non-destructif industriel (ferrure brute + IQI Sinus) plutôt que dosimétrie médicale, mais à confirmer avec Agustin.
- Performance scaling à grande taille — partiellement prouvable.
ferrure_brute.obj26 Mo +IQI_Sinus.obj1,1 Mo livrés ; au-delà, extrapolation seulement. - Bit-exactitude image OptiX 4 vs OptiX 9 — réfutable, jamais prouvable. Au mieux : convergence statistique (cf.
docs/adr/ADR-09-validation-protocol-L0-L4.md). - Fidélité numérique sans entretien Agustin — non-décidable. Le code original contient un savoir tacite (constantes magiques, bicouche W/Fe non documentée, branche basse-énergie Brems jamais implémentée
||3==3) qui ne peut pas être reverse-engineeré sans entretien direct. Coût d'absence : 5-15 j-ingénieur perdus en déduction approximative.
Analyse du code original
Origine et licence
Le code reçu d'Agustin Lifschitz (cofondateur Radience) le 2026-05-04 est un fork du sample NVIDIA OptiX SDK 4.0.2 optixMeshViewer (Copyright 2016 NVIDIA), licence BSD-style — pas de souci IP sur la base, IP custom uniquement sur les modifications Radience.
| Fichier source | Rôle | Taille | Date dernière mod |
|---|---|---|---|
optixMeshViewer.cpp | Host program — entrypoint OptiX | 13 Ko (438 LOC) | 2026-02-27 (récent) |
pinhole_camera.cu | Raygen kernel — logique gamma-imaging custom | 35 Ko (1012 LOC) | 2026-02-27 (récent) |
parallelogram.cu | Hit kernel — intersection parallélogramme | 3,4 Ko | 2017-09 (intact) |
constantbg.cu | Miss kernel — background uniforme | 1,8 Ko | 2016-11 (intact) |
commonStructs.h | Structures C/CUDA partagées | 1,9 Ko | 2017-04 |
helpers.h | Helpers utilitaires | 9,5 Ko | 2016-11 |
random.h | RNG xorshift32 + Wang hash | 1,2 Ko | 2017-05 |
Source-of-truth : gamma_gpu.tgz.gz SHA256 eea6ee773bc0630b504780c086b7e0114b95a3a21ab6f5423f9dba80533ccf99, BLAKE3 96156b0566870dce766e394b82ee9a05b311308f7b9b2b956a46c37410a9d214, ancrage OpenTimestamps 4 calendriers (Bitcoin pending) le 2026-05-04. Cf. poc/inbound/2026-05-04-gamma-gpu-agustin/RECEIVED.md.
Architecture algorithmique
Le programme raygen pinhole_camera() (pinhole_camera.cu:900-956) est inhabituel pour un sample OptiX. Au lieu de tracer un rayon par lancement et accumuler la radiance, il simule une cascade de particules dans une boucle while sur le launch index. C'est un Monte Carlo de transport, pas un path tracer.
RT_PROGRAM pinhole_camera() // pinhole_camera.cu:900-956
├─ initializeRandomState (seed = i*100 + iter)
├─ X = source position (uniform sur ±0.05 mm × ±0.05 mm × z=500)
├─ P = direction (uniform sur ±0.25 cône, P.z = -sqrt(1-...))
├─ ray1[0..9], data[0..9] // pile de 10 particules max
├─ data[0].x = 10 * U[0,1) // énergie initiale ∈ [0, 10) MeV
├─ data[0].y = 0 // type : 0 = gamma
└─ while (j >= 0) {
Advance_part(&j, &k, ray1, data, &state);
if (ii++ > 100) break; // garde-fou anti-boucle infinie
}
Advance_part est une DFS sur l'arbre de cascade électromagnétique :
- soit empile une particule secondaire (Bremsstrahlung produit un \(\gamma\), Compton produit un \(e^{-}\), Pair-prod produit \(e^{-}+e^{+})\) vers
(*j1)++ou(*j1)+=2; - soit dépile la particule courante quand elle atteint l'écran (
hit_point.z < z_screen = -50) ou est absorbée vers(*j1)--; - soit met à jour position/direction sans changer la pile.
C'est exactement comme PENELOPE et Geant4 le font côté CPU, mais ici déroulé par thread GPU.
Six processus physiques modélisés
Audit knuth :
| # | Processus | Code (pinhole_camera.cu:) | Cible matérielle | Source documentaire revendiquée |
|---|---|---|---|---|
| 1 | Bremsstrahlung (section efficace) | L194-239 | Tungstène (Z=74, voldens=6.32e19) | Seltzer-Berger fit (sb_W, sb_Fe) |
| 2 | Bremsstrahlung (énergie \(\gamma\) émise) | L253-322 | Tungstène | Geant4 + Seltzer-Berger |
| 3 | Rayleigh scattering | L347-361, L830-884 | Fer (Z=26, voldens=8.486e19) | Geant4.9.5 (Livermore polarized) |
| 4 | Compton scattering | L362-415, L529-609 | Fer | Klein-Nishina (Geant4) |
| 5 | Photoélectrique | L417-443, L611-670 | Fer | Biggs & Lighthill SAND87-0070, Sauter-Gavrila K-shell |
| 6 | Production de paires | L446-497, L672-828 | Fer | Bethe-Heitler + Coulomb correction (L. Urban / Geant3) |
Quatre anomalies de modélisation détectées
Issu de l'audit knuth — à préserver textuellement par le portage, signaler dans la wiki, interroger Agustin :
- Bicouche W/Fe implicite jamais documentée — le matériau cible diffère selon le type de particule (électrons vers W, gammas vers Fe). Si intentionnel, modélise probablement une géométrie bicouche (anode tungstène générant le Bremsstrahlung, écran/fantôme fer pour la propagation gamma) — cohérent avec gammagraphie industrielle. Mais nulle part documenté. Point critique : si on "nettoie" en mettant un seul matériau par mégarde, toute la simulation casse silencieusement.
- Branche basse-énergie Brems jamais implémentée —
if (Energy > 0.5 || 3==3)(L277). La condition3==3est toujours vraie vers le test surEnergy > 0.5est désactivé. Le commentaire L276 dit « below 500 keV vers To do it (from Penelope) ». TODO devenu silencieux. Un re-lecteur OptiX 9 qui "nettoie" cette ligne casse silencieusement la simulation. - Pile tronquée à 10 —
ray1[10], data[10](L923-925), mais une cascade de pair-production peut empiler 2 secondaires d'un coup ((*j1)+=2, L822). Le testif(*j1<nr-2)(L814) protège, mais quand il échoue le code ne fait queprintf("Pair couldn't be created!\n")et continue vers biais silencieux : aux hautes énergies où la pair-production est fréquente, on tronque la cascade. - Boucle bornée à 100 itérations —
if(ii++ > 100) break;(L950). Pour un photon de 10 MeV qui rebondit Compton de nombreuses fois, 100 itérations peuvent être atteintes vers cascade tronquée silencieusement. Biais de queue (haute multiplicité vers sous-estimation). À exposer comme paramètre dans le portage.
Bug critique côté host
Hors de pinhole_camera.cu, dans optixMeshViewer.cpp :
Le
main()allouedouble lanex[2100][2100][8]sur la pile (~280 Mo). Sur Linux aveculimitpar défaut (8 Mo), ce programme seg-fault sans le montrer clairement.
C'est le bug n°1 à corriger d'emblée dans le portage Rust (allocation Vec<f64> heap), indépendamment d'OptiX. À mentionner à Agustin — il connaît peut-être déjà le contournement (probablement ulimit -s unlimited dans son environnement de production).
RNG : découverte critique pour la stratégie de validation
Le RNG dans random.h:13-19 est xorshift32 (Marsaglia 2003) + wang_hash déterministe — pas curand, malgré l'#include <curand.h> à pinhole_camera.cu:30 (legacy non utilisé, à confirmer). Seed = i*100 + iter (pinhole_camera.cu:910).
Conséquence : la non-bit-exactitude n'est pas condamnée d'avance comme on le craindrait avec curand. Un test L1 mono-thread bit-exact entre OptiX 4 et OptiX 9 est défendable comme falsifier le plus fort, AVANT de replier sur L2 statistique.
Position adoptée (cf. docs/adr/ADR-06-rng-provenance.md, ADR-09) : tenter L1 mono-thread comme test interne ; le livrable s'engage uniquement sur convergence statistique (L2 SSIM \(\geq\) 0.95, L3 conservation d'énergie, L4 reproductibilité intra-version).
Données livrées et données manquantes
| Fichier | Taille | Rôle | Statut |
|---|---|---|---|
ferrure_brute.obj | 26 Mo | Mesh 3D principal (pièce industrielle) | ✓ |
ferrure_brute.dat | 21 Mo | Données associées (géométrie pré-calculée ou volumes) | ✓ — usage à clarifier |
IQI_Sinus.obj | 1,1 Mo | Phantom calibration gamma-imaging (Image Quality Indicator) | ✓ |
piramide.obj | 174 octets | Mesh test minimal (pyramide debug) | ✓ |
spectre.dat | 23 Ko | Spectre énergétique de la source gamma | ✓ |
gammas.dat | 0 octets | Vraisemblablement input ou output | ⚠ vide — à clarifier avec Agustin (oubli d'envoi, placeholder, ou généré au runtime ?) |
f_pri.jpg, f_tot.jpg | — | Sorties simulation (flux primaire + flux total) | ✓ — référence visuelle |
ima.jpg, ima_zoom.jpg | — | Images de l'objet imagé | ✓ |
Manque critique : un dump binaire brut des output_buffer et extra_buffer du run de référence. Les JPG sont des post-process gnuplot 8-bit compressés ; pour la validation numérique, on a besoin du buffer flottant brut. Question à Agustin (cf. fleet M1).
Diagnostic technique — version OptiX source
✓ Confirmé : OptiX SDK 4.0.2 (NVIDIA, sortie 2017) — chemin extrait du CMakeCache.txt : NVIDIA-OptiX-SDK-4.0.2-linux64/SDK/optixMeshViewer.
API utilisée :
#include <optix_world.h>— header OptiX legacy/pre-7#include <optixu/optixpp_namespace.h>— wrapper C++ pre-7 (supprimé en OptiX 7)#include <curand.h>— CUDA RNG underlying (legacy non utilisé)
Pattern objet : Context::create(), Buffer::create(), Geometry::create(), Material::create(), Program::create(), Acceleration::create("Trbvh").
Fuite mineure mais irréversible
CMakeCache.txt contient /home/lifschitz/Downloads/optix/NVIDIA-OptiX-SDK-4.0.2-linux64/SDK/optixMeshViewer — chemin du user Linux d'Agustin. PII mineure mais irréversible (impossible de "non-recevoir"). Ne pas propager hors-galaxie radience. Documenté dans la chronique d'inbound (RECEIVED.md ligne 73).
Estimation effort (synthèse de la délibération)
| Hypothèse | Effort | Conditions |
|---|---|---|
| Migration OptiX 4 vers 9 d'un sample standard (1 raygen simple + 1-2 hit programs) | 3-4 j | Dev expérimenté OptiX 7+, machine Linux+GPU prête |
| Avec version pro-modernisée comme baseline | 4-6 j | Réduit de 30-40 % le temps + supprime le reverse-engineering |
| Sans version pro-modernisée | 6-8 j | Reverse-engineering inclus |
| Sans entretien-walk-through Agustin | +5-15 j | Coût de re-spécifier le savoir tacite |
Borne basse incompressible (smoke L0 = PNG OptiX 9 non-vide) : 2-4 j avec setup environnement préparé.
Compteur NDA aujourd'hui : J+4 sur 90, soit 4.4 % du budget consommé sur de la pure latence administrative (compteur démarré à signature, pas à réception code).
Sections suivantes (à rédiger)
| Section | Titre | Statut |
|---|---|---|
| 02 | Choix de modernisation (récap ADRs 001-08, vocabulaire, hexagonal, FFI, validation) | ⏳ pending |
| 03 | Bibliographie OptiX / gamma-imaging / Monte Carlo (12 refs Zotero) | ⏳ pending |
| 04 | Wiki-doc structurée (8 dossiers TAOCP-style) | ⏳ pending |
| 05 | Stratégie de validation L0-L4 + chaîne d'autorité S1-S4 | ⏳ pending |
| 06 | Résultats du portage (tests numériques, performance, anomalies découvertes) | ⏳ post-implémentation |
| 07 | Bornes atteintes vs bornes non atteintes (honnêteté > complétude) | ⏳ post-implémentation |
Cross-références
- Délibération source :
~/galaxies/radience/.cosmon/state/fleets/default/molecules/delib-20260504-1de1/(frame.md, responses/, synthesis.md) - ADRs :
docs/adr/ADR-001àADR-08 - Inbound RECEIVED :
../inbound/2026-05-04-gamma-gpu-agustin/RECEIVED.md - NDA actif :
../../../pactum/contracts/radience/v0.2.4/signed/SIGNED.md - Chronique signature :
../../docs/lore/CHRONICLES.md(entrée 2026-05-01 « La maison ouverte ») - Contacts :
../../contacts.md