rdeboer1/rmfit-campaign

Processus de fitting R-matrix global avec AZURE2 : lancer une campagne sur n'importe quelle réaction, la piloter ou la reprendre, utiliser les temps d'inactivité pour auditer les fichiers d'entrée/données et la littérature, juger les résultats, exporter pour revue GUI et affiner la méthode.

Qu'est-ce que rmfit-campaign ?

Ce skill définit le processus complet « rmfit » pour effectuer des ajustements R-matrix globaux à l'aide du code AZURE2. Il automatise le travail traditionnellement manuel de l'évaluateur : polissage des paramètres, inversion des signes d'interférence, ajout ou retrait de niveaux, exclusion de jeux de données suspects, le tout via des étapes reprises et scriptées exécutées sur un nœud de cluster, avec reprise possible via un fichier `STATUS.md`. Il gère le cycle de vie complet d'une campagne : initialisation (avec vérification préalable via `audit` et création d'un `spec.json`), lancement de boucles de recherche (polissage, changement de signe, ajout/retrait de niveaux), audits en temps inactif (fichiers d'entrée, données, littérature), jugement des candidats (vérification, export pour analyse dans l'interface graphique AZURE2), et raffinement progressif de la méthode. Il est conçu pour être utilisé dans tout contexte mentionnant rmfit, une campagne, `STATUS.md`, des cycles de signe, un polissage, un test d'ajout de niveau, l'ajustement d'une nouvelle réaction « à la manière rmfit », ou la reprise d'un ajustement laissé en cours sur un cluster.

Compatible avec✓Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/rdeboer1/rmfit/tree/HEAD/.claude/skills/rmfit-campaign

Installed? Explore more Recherche et analyse de données skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Le processus rmfit

rmfit (/groups/rdeboer1/user/rdeboer1/R-matrix/rmfit/, README là-bas) fait ce qu'un évaluateur fait à la main — polir, inverser les signes d'interférence, ajouter ou retirer des niveaux, désactiver des jeux de données suspects — sous forme d'étapes reprises qu'un script exécute sur un nœud de cluster et qu'une nouvelle session peut reprendre à partir du STATUS.md. Il n'est pas installé comme un paquet :

export PYTHONPATH=/groups/rdeboer1/user/rdeboer1/R-matrix
python3 -m rmfit.cli <campaign_dir> <command> [options]

Lisez ce fichier du début à la fin avant la première commande sur une nouvelle réaction ; pour reprendre une campagne, « Lire l'état » et « La boucle » suffisent. Les améliorations vont dans le journal à la fin.

1. Lire l'état, ne jamais le recalculer

Un répertoire de campagne contient tout ce dont une nouvelle session a besoin :

  • STATUS.md — meilleur objectif vérifié par structure, cycles récents et lignes de journal. Régénérer avec status ; status --json pour un dump compact.
  • readme — le cahier de laboratoire (rmfit ajoute un paragraphe par cycle ; ajoutez le vôtre avec log "..."). Convention d'archive : le lire avant de toucher à quoi que ce soit.
  • campaign.log — chaque ligne imprimée par le pilote ; rmfit_sge.log / rmfit_*.log — journaux des tâches cluster.
  • ledger.sqlite + candidates/*.npz — chaque vecteur candidat et son score. Le candidat en place est le meilleur candidat avec un score verified (une évaluation fraîche et mono-session du modèle complet). Les nombres shardés sont classés ; les nombres vérifiés sont rapportés.
  • campaign.json — modèle de base, drapeaux du moteur, nombre de shards, politique de bornes, configuration de recherche.
  • <reaction>.azr + .sav — l'export vérifié prêt pour l'interface graphique.
  • variants/ — fichiers de shard, modèles de fenêtre, fichiers avec/sans niveau (jetables).

qstat -u $USER en premier : une commande de campagne à la fois par répertoire (elles partagent le livre de comptes et variants/). Le nœud de connexion est pour status, report, log, export, tests courts (<= 6 workers, <= 30 min). Tout le reste s'exécute comme une tâche.

2. Lancer une campagne sur une nouvelle réaction

Prérequis (faites-les dans le répertoire d'ajustement de la réaction, pas dans la campagne) :

  1. Un fichier .azr qui s'ouvre dans l'interface graphique, avec data/, un répertoire output/, et un readme. Connaître les drapeaux de mode CLI que cette réaction utilise (--use-brune, --ignore-externals, --no-long-wavelength, ...) : ils ne sont pas dans le .azr, ils varient par réaction (~/R-matrix/CLAUDE.md), et rmfit en a besoin sous forme de JSON --flags.
  2. Reproduire le dernier ajustement terminé avant de construire dessus : charger son param.sav par nom (pyazr), confirmer que l'objectif correspond à chiSquared.out (chi2 + pénalité de normalisation), puis l'intégrer dans un fichier propre (rmfit.engine.bake) et le vérifier avec le CLI en mode 1 avec un fichier externe vierge. Ne jamais faire confiance à un bake qui a été « vérifié » avec le .sav comme fichier externe (cela écrase <levels>), et ne jamais utiliser de paramètres provenant d'un ajustement en cours ou planté — seulement le dernier terminé. Purger les lignes de niveau inactives.
  3. Fusionner les nouveaux jeux de données sur le fichier baked (AzrModel.add_data_segment), plafonné à la plage d'énergie couverte par le schéma de niveaux (set_segment_energy_range), avec normalisations libres et une erreur systématique qui reflète l'article. Examiner chaque nouveau fichier : une seule section efficace négative ou aberrante peut dominer l'objectif.
  4. Enregistrer tout cela dans le readme du répertoire de la réaction.

Premiers ajustements : construire des paramètres de départ avant tout ajustement global (DeBoer, 2025-10-25 — RÉÉVALUER PLUS TARD)

Provisoire. Ceci est la suggestion générale de DeBoer, écrite avant d'avoir été testée de bout en bout. La réévaluer une fois que 10B+α (la première réaction à l'utiliser, 10B+a/10-25-26_Rmatrix_Claude) aura un ajustement réel : enregistrer ce qui a fonctionné et ce qui n'a pas fonctionné ici, et modifier ou abandonner la procédure en conséquence.

DeBoer : « Fixer les normes d'un seul jeu de données représentatif mais laisser les autres varier. Cela fournit alors une échelle plus fixe pour les sections efficaces initialement, mais permet toujours aux jeux de données avec des normes incohérentes mais des formes cohérentes de ne pas gêner l'ajustement. Dans notre cas, puisque nous avons des données dans chaque canal, je suggérerais de fixer nos données pour commencer et de laisser les autres varier. De plus, nous devons nous assurer de permettre aux canaux de plus bas L pour chaque paire de particules de varier, en donnant une petite valeur non nulle pour chaque niveau, même si la littérature ne lui donne pas de branche vers ce canal. Je suggérerais également de commencer à basse énergie et d'effectuer quelques polissages sur un niveau à la fois pour voir à quel point il peut correspondre aux données. Ensuite, revenir et essayer d'ajouter des niveaux là où des résonances sont clairement présentes et qui ne correspondent pas à l'un des niveaux connus en énergie et/ou largeur. Je ne tenterais pas un véritable ajustement avant d'avoir des paramètres de départ raisonnablement bons. »

En tant que procédure :

  1. Fixer l'échelle avec un jeu de données représentatif. Fixer ses normes à 1 (nos propres données quand elles couvrent chaque canal) ; laisser la norme de chaque autre jeu varier. Les jeux avec des formes cohérentes mais une échelle différente ne bloquent alors pas l'ajustement.
  2. Amorcer le canal de plus bas L de chaque paire, pour chaque niveau. Lui donner une petite amplitude non nulle (0,01 γ_W, définie dans le moteur ; des espaces réservés physiques minuscules, voir l'entrée d'amorçage du 2025-10-25), même là où la littérature ne liste aucune branche vers ce canal.
  3. Chaque canal qui s'ouvre dans la plage d'ajustement est dans le modèle — par défaut. Chaque fois que la plage d'ajustement est étendue (une nouvelle fenêtre d'énergie, ou un jeu de données qui atteint plus haut), lister chaque partition ouverte en dessous du HAUT de la plage : chaque état excité de chaque noyau résiduel (ENSDF) et les autres partitions de particules légères (d, t, ³He, ...), avec des seuils Ex = sepE + e2. Ajouter une paire pour chacun avant d'ajuster, sans qu'on vous le demande : le plus bas L autorisé de chaque spin de canal sur chaque niveau ; amorcé selon l'item 2 sur les niveaux au seuil ou dans les 0,5 MeV en dessous du seuil et sur les pôles de fond, inerte (0, fixe) ailleurs. Ajouter les nouvelles sorties à chaque segment sommé (sections efficaces totales, total (n,p), (n,α), …). NE PAS plafonner une fenêtre de données à un seuil à la place. Un plafond est une solution temporaire : le journaliser dans le readme avec le canal qui l'a imposé, et le lister pour l'évaluateur. (DeBoer 2026-10-30, extension HE de 11B+α : la section efficace totale d'ELBE ¹⁴N+n avait été plafonnée à E_n 5,1 MeV parce que ¹⁴N(n,n₄) n'avait pas de paire. Cela a laissé le sommet de 1,2 MeV de l'ajustement sans sa contrainte la plus forte, un total à norme fixe. Exemple de constructeur : 11B+a/10-27-26_HE_claude/model/add_pairs_he.py, 7 paires n4 a3 d0 p1 n5 n6 p2.)
  4. Niveau par niveau, à partir de la basse énergie. Polir un niveau à la fois (son énergie et ses largeurs, plus les normes libres) contre les données autour de lui, et regarder à quel point il peut correspondre.
  5. Ensuite ajouter des niveaux là où une résonance est clairement présente et qu'aucun niveau connu ne lui correspond en énergie et/ou largeur.
  6. Alors seulement un véritable ajustement (global) : init d'une campagne sur le résultat.

Pourquoi (10B+α étape 1, 2025-10-25) : les polissages globaux à partir d'un mauvais départ (χ²/N ≈ 200, niveaux du 2-27-25 avec de nouveaux canaux proches de zéro) ont échangé la force manquante contre des normalisations. Avec chaque norme libre, presque toutes sont tombées à 0,38-0,68 en 150 évaluations. Bornées à 0,7-1,5, huit étaient sur une borne et l'ajustement a stagné à χ²/N 12,7. Avec χ² ~ 10⁵, les a priori de normalisation de quelques pour cent ne coûtent rien (10B+a/10-25-26_rmfit_stage1, _stage1b).

Ensuite, dans un nouveau répertoire de campagne daté (<reaction>/<M>-<D>-<YY>_rmfit_campaign/) :

mkdir <dir> && cp <base>.azr <dir>/ && cp -r data <dir>/data && mkdir <dir>/output
python3 -m rmfit.cli <dir> init --base <dir>/<base>.azr [--sav <base>.sav] --nshards 24 \
    --flags '{"use_long_wavelength": false, "ignore_externals": true, "use_brune": true}' \
    --policy '{"theta2_cap": 1.0, "bg_theta2_cap": 3.0, "bg_energy": <Ex above the data>, "e_window": 0.3, "norm_range": [0.2, 5.0]}' \
    --search '{"top_k": 6, "pairs_per_group": 4, "stage1_nfev": 30, "stage2_nfev": 60, "union_nfev": 100}'

--flags est passé directement à pyazr.azure2(), donc la paramétrisation est choisie là : "use_brune": true (Brune, le défaut de l'archive), "use_park": true (Park : le vecteur d'ajustement contient les amplitudes de largeur réduite observées, Gamma = 2 P gamma^2 ; voir la compétence AZURE2 sur « Paramétrisation de Park »), "use_brune": false (Lane-Thomas standard). Une base par campagne — les vecteurs du livre de comptes, les instantanés .npz et les compagnons .sav sont tous dedans.

--objective JSON optionnel (campaign.json objective, deBoer et al. 2017 Sec. sur le fitting) : {"dataset_weight": "reduced", "dataset_key": "file", "loss": "sivia"}. dataset_weight: reduced est la méthode du chi-carré réduit (le chi-carré de chaque jeu de données est divisé par son nombre de points, remis à l'échelle par N/K pour que l'objectif garde une magnitude de chi-carré ; les lignes de pénalité sont non pondérées) — cela empêche un grand jeu avec de petites erreurs de dominer ; loss: sivia remplace le chi-carré par la PDF plus large de Sivia, -2 log[(1 - e^{-R^2/2})/R^2] - 2 log 2 (~R^2/2 pour les petits résidus, ~2 log R^2 pour les valeurs aberrantes : les valeurs aberrantes sont sous-pondérées comme si leur barre d'erreur était gonflée). La perte de Sivia est appliquée aux résidus standardisés par le chi2/N de référence de chaque jeu de données (loss_scale: dataset, les échelles sont calculées par init à partir de la ligne de base simple et stockées dans campaign.json) : sans cela, sur un modèle avec chi2/N ~ 20-300, chaque point se trouve dans la queue logarithmique, les données perdent ~10x leur poids face aux pénalités quadratiques de normalisation et l'ajustement dérive (13C+a, 2026-09-08 : chi2 simple 701k -> 1 190k en un polissage, MANA abandonné, les normes se sont figées au nominal). Les deux méthodes sont « statistiquement incorrectes mais utiles lorsque les barres d'erreur sont sous-estimées ». L'objectif est une propriété d'une campagne : les candidats vérifiés sous différents objectifs ne sont pas comparables, donc un changement d'objectif signifie un nouveau répertoire de campagne (l'amorcer avec l'export précédent). REPORT.md et segment_scores gardent le chi-carré simple par jeu de données quel que soit l'objectif. Vérifié dans rmfit/tests/test_objective_13n.py.

init vérifie la ligne de base (une évaluation du modèle complet), enregistre la structure, écrit STATUS.md et le script de tâche run_crc_rmfit (nœud long 24 cœurs, envoie un mail à [email protected], -m abe). Réexécuter init conserve une configuration existante à moins que de nouvelles valeurs ne soient données. Signification de la politique : theta2_cap est la limite de Wigner pour les niveaux physiques, bg_theta2_cap pour les pôles de fond (niveaux avec Ex >= bg_energy, dont les énergies restent fixes) — 3.0 est une estimation de départ, pas une valeur physique par défaut : vérifier où se situent les amplitudes de fond de la ligne de base (l'audit de cap de init) avant de lui faire confiance ; 12C+alpha élastique avait besoin de ~100 (voir l'entrée de journal du 2026-09-30) ; e_window est la liberté d'énergie d'un niveau par polissage (MeV) ; norm_range multiplie la normalisation nominale. narrow_window (optionnel, par exemple {"gamma_kev": 5, "factor": 3, "min_kev": 1}) maintient un niveau dont les largeurs partielles libres totalisent moins de gamma_kev dans ±max(min_kev, factor·Γ) de son énergie actuelle au lieu de ±e_window, afin qu'un polissage ne puisse pas éloigner un niveau étroit de son pic (le 13C+a 9/2+ a dérivé de 180 keV en un polissage de resserrement). Nombre de shards = cœurs ; le sharding est exact (le chi-carré est additif sur les segments), donc plus de shards n'achètent que de la vitesse.

Vérification du coût sur un nouveau modèle (campaign.log après init) : un objectif shardé devrait être de quelques secondes et un Jacobien de dizaines de secondes. Si un segment avec convolution cible-effet domine (comme Cierjacks l'a fait sur 13C+a), rmfit le replie lui-même (model.ConvSpec) ; les segments « somme » composites sont autorisés comme pièces de convolution.

2b. Spec, audit, décisions (2026-11-07 ; Phase 1 de R-matrix/rmfit/DESIGN.md)

Avant init, écrire la spec de la campagne (spec.json, modèle rmfit/templates/SPEC_TEMPLATE.json, schéma dans rmfit/spec.py) : chaque jeu de données avec son rôle (anchor = norme fixée au nominal ; free avec prior_sigma ; excluded avec la raison ; screen), la fenêtre d'ajustement, le bloc gelé, les paires qui doivent exister, les bornes / l'objectif / la recherche, ce que le pilote peut faire de lui-même (pre_authorized : adopt_level true / false / règles, flip_adopt, dataset_off_adopt, ...), les règles d'arrêt et les décisions permanentes avec leur propriétaire et leur date. Ensuite :

python3 -m rmfit.audit <base>.azr --out AUDIT.md       # pré-vol, sans session moteur : zéro largeurs libres, fusions à 1 keV,
                                                       # normes nominales != 1, normError en TANT QUE FRACTION, colonnes FLAG comme
                                                       # erreurs, erreurs minuscules, doublons, pics, seuils, <targetInt>
                                                       # sur les segments de test, noms de fichiers .sav hérités, chemin de sortie, broche du moteur
python3 -m rmfit.cli <dir> init --base ... --spec spec.json   # flags/policy/search/objective/nshards de la spec sauf si
                                                       # donnés ; les désaccords HAUTS avec le .azr refusent l'init
python3 -m rmfit.cli <dir> spec check                   # à tout moment : SPEC_CHECK.md ; spec render -> SPEC.md ; audit -> AUDIT.md

Un résultat d'audit HAUT est corrigé (ou enregistré comme accepté dans les décisions permanentes de la spec) avant la ligne de base. Pendant la campagne, tout ce que la spec ne répond pas va à DECISIONS.md (rmfit decisions liste, rmfit decide D-003 "adopt" --by DeBoer répond) ; un ajout de niveau dont accept n'est pas pré-autorisé par la spec est enregistré comme accept-pending avec une décision en file d'attente et n'est PAS adopté (l'ancienne adoption automatique ne s'applique qu'aux campagnes sans spec). Projets de spec à copier : 10B+a/11-6-26_s5_highE/spec_draft.json, 13C+a/11-06-26_merged_regionD/spec_draft.json.

Les trois examens en temps inactif de la section 3b sont générés, pas écrits à la main, depuis le 2026-11-07 :

python3 -m rmfit.cli <dir> audit --kind all            # audits/{input,data,literature}/PROMPT.md + FINDINGS.md vide
# donner chaque PROMPT.md à un sous-agent d'arrière-plan (outil Agent, un modèle moins cher, au plus trois à la fois) ; il écrit FINDINGS.md
python3 -m rmfit.cli <dir> audit --findings            # lignes non vérifiées (candidates) de chaque FINDINGS.md
python3 -m rmfit.cli <dir> audit --status data 1 confirmed --note "vérification ligne 4007

…

[suite tronquée pour la traduction]

Skills associés