O processo rmfit
rmfit (/groups/rdeboer1/user/rdeboer1/R-matrix/rmfit/, README lá) faz o que um avaliador faz manualmente — polir, inverter sinais de interferência, adicionar ou remover níveis, desligar conjuntos de dados suspeitos — como etapas retomáveis que um script executa em um nó do cluster e uma nova sessão pode retomar a partir de STATUS.md. Não está instalado como pacote:
export PYTHONPATH=/groups/rdeboer1/user/rdeboer1/R-matrix
python3 -m rmfit.cli <campaign_dir> <comando> [opções]
Leia este arquivo de cima a baixo antes do primeiro comando em uma nova reação; para retomar uma campanha, "Leia o estado" e "O loop" são suficientes. Refinamentos vão no log ao final.
1. Leia o estado, nunca o recompute
Um diretório de campanha carrega tudo que uma nova sessão precisa:
STATUS.md— melhor objetivo verificado por estrutura, rodadas recentes e linhas de log. Regenerar comstatus;status --jsonpara um dump compacto.readme— o caderno de laboratório (rmfit anexa um parágrafo por rodada; adicione o seu próprio comlog "..."). Convenção do arquivo: leia antes de tocar em qualquer coisa.campaign.log— cada linha que o driver imprimiu;rmfit_sge.log/rmfit_*.log— logs dos jobs do cluster.ledger.sqlite+candidates/*.npz— cada vetor candidato e pontuação. O incumbente é o melhor candidato com uma pontuaçãoverified(uma avaliação de sessão única do modelo completo). Números sharded classificam; números verificados são reportados.campaign.json— modelo base, flags do motor, contagem de shards, política de limites, configuração de busca.<reaction>.azr+.sav— a exportação para revisão GUI do incumbente.variants/— arquivos de shard, modelos de janela, arquivos com/sem nível (descartáveis).
qstat -u $USER primeiro: um comando de campanha por vez por diretório (eles compartilham o ledger e variants/). O nó de login é para status, report, log, export, testes curtos (<= 6 workers, <= 30 min). Todo o resto roda como um job.
2. Iniciando uma campanha em uma nova reação
Pré-requisitos (faça-os no diretório de ajuste da reação, não no da campanha):
- Um
.azrque abre na GUI, comdata/, um diretóriooutput/e umreadme. Conheça as flags do modo CLI que esta reação usa (--use-brune,--ignore-externals,--no-long-wavelength, ...): elas não estão no.azr, variam por reação (~/R-matrix/CLAUDE.md), e rmfit precisa delas como--flagsJSON. - Reproduza o último ajuste concluído antes de construir sobre ele: carregue seu
param.savpelo nome (pyazr), confirme se o objetivo corresponde achiSquared.out(chi2 + penalidade de norma), então asse-o em um arquivo limpo (rmfit.engine.bake) e verifique-o com o CLI no modo 1 com um arquivo externo em branco. Nunca confie em um bake que foi "verificado" com o.savcomo arquivo externo (isso sobrescreve<levels>), e nunca use parâmetros de um ajuste em execução ou travado — apenas o último completo. Remova linhas de nível inativas. - Mescle quaisquer novos conjuntos de dados no arquivo assado (
AzrModel.add_data_segment), limitado ao intervalo de energia que o esquema de níveis cobre (set_segment_energy_range), com normalizações livres e um erro sistemático que reflita o artigo. Olhe para cada novo arquivo: uma única seção de choque negativa ou com pico pode dominar o objetivo. - Registre tudo isso no
readmedo diretório da reação.
Primeiros ajustes: construa parâmetros iniciais antes de qualquer ajuste global (DeBoer, 2026-10-25 — REAVALIAR DEPOIS)
Provisório. Esta é a sugestão geral de DeBoer, escrita antes de ser testada do início ao fim. Reavalie assim que 10B+α (a primeira reação a usá-lo, 10B+a/10-25-26_Rmatrix_Claude) tiver um ajuste real: registre o que funcionou e o que não funcionou aqui, e mude ou abandone o procedimento conforme necessário.
DeBoer: "Fixe as normas de um conjunto de dados representativo, mas deixe os outros variarem. Isso fornece uma escala mais fixa para as seções de choque inicialmente, mas ainda permite que conjuntos de dados com normas inconsistentes, mas formas consistentes, não atrapalhem o ajuste. No nosso caso, como temos dados em todos os canais, sugiro que fixemos nossos dados inicialmente e deixemos os outros variarem. Além disso, devemos garantir que permitimos que os canais de menor l para cada par de partículas variem, dando a eles algum valor pequeno não nulo para cada nível, mesmo que a literatura não atribua uma ramificação para esse canal. Também sugiro começar em baixa energia e fazer alguns polimentos em um nível de cada vez para ver quão bem ele pode corresponder aos dados. Depois volte e tente adicionar níveis onde ressonâncias estejam claramente presentes que não correspondam a nenhum dos níveis conhecidos em energia e/ou largura. Eu não tentaria um ajuste real até que você tenha parâmetros iniciais razoavelmente bons."
Como procedimento:
- Fixe a escala com um conjunto de dados representativo. Fixe suas normas em 1 (nossos próprios dados quando cobrem todos os canais); deixe a norma de cada outro conjunto variar. Conjuntos com formas consistentes, mas escalas diferentes, então não impedem o ajuste.
- Semeie o canal de menor L de cada par, para cada nível. Dê a ele uma pequena amplitude não nula (0.01 γ_W, definida no motor; placeholders físicos minúsculos, veja a entrada de semeadura de 2026-10-25), mesmo onde a literatura não lista ramificação para esse canal.
- Todo canal que abre dentro do intervalo de ajuste está no modelo — por padrão. Sempre que o intervalo de ajuste for estendido (uma nova janela de energia, ou um conjunto de dados que atinge mais alto), liste todas as partições abertas abaixo do TOPO do intervalo: cada estado excitado de cada núcleo residual (ENSDF) e as outras partições de partículas leves (d, t, ³He, ...), com limiares Ex = sepE + e2. Adicione um par para cada antes de ajustar, sem ser perguntado: o menor L permitido de cada spin de canal em cada nível; semeado conforme item 2 em níveis no limiar ou dentro de 0.5 MeV abaixo dele e em polos de fundo, inerte (0, fixo) em outros lugares. Adicione as novas saídas a cada segmento somado (seções de choque totais, total (n,p), (n,α), ...). NÃO limite uma janela de dados em um limiar como alternativa. Um limite é uma solução temporária: registre-o no readme com o canal que o forçou, e liste-o para o avaliador.
(DeBoer 2026-10-30, extensão HE 11B+α: a seção de choque total ELBE ¹⁴N+n havia sido limitada em E_n 5.1 MeV porque ¹⁴N(n,n₄) não tinha par. Isso deixou o topo 1.2 MeV do ajuste sem sua restrição mais forte, um total com norma fixa. Exemplo de construtor:
11B+a/10-27-26_HE_claude/model/add_pairs_he.py, 7 pares n4 a3 d0 p1 n5 n6 p2.) - Nível por nível, de baixa energia para cima. Polir um nível de cada vez (sua energia e larguras, mais as normas livres) contra os dados ao redor, e veja quão bem ele pode corresponder.
- Depois adicione níveis onde uma ressonância esteja claramente presente e nenhum nível conhecido corresponda a ela em energia e/ou largura.
- Só então um ajuste real (global):
initem uma campanha sobre o resultado.
Porquê (10B+α etapa 1, 2026-10-25): polimentos globais a partir de um início ruim (χ²/N ≈ 200, níveis de 2-27-25 com novos canais perto de zero) trocaram a força faltante por normalizações. Com cada norma livre, quase todas caíram para 0.38-0.68 em 150 avaliações. Limitadas a 0.7-1.5, oito sentaram-se em um limite e o ajuste estagnou em χ²/N 12.7. Com χ² ~ 10⁵, priores de norma de alguns por cento não custam nada (10B+a/10-25-26_rmfit_stage1, _stage1b).
Então, em um novo diretório de campanha datado (<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 acima dos dados>, "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 é passado diretamente para pyazr.azure2(), então a parametrização é escolhida lá: "use_brune": true (Brune, o padrão do arquivo), "use_park": true (Park: o vetor de ajuste contém as amplitudes de largura reduzida observadas, Gamma = 2 P gamma^2; veja a habilidade AZURE2's "Parametrização de Park"), "use_brune": false (Lane-Thomas padrão). Uma base por campanha — os vetores do ledger, instantâneos .npz e acompanhantes .sav estão todos nela.
--objective JSON opcional (campaign.json objective, deBoer et al. 2017 Seção sobre ajuste): {"dataset_weight": "reduced", "dataset_key": "file", "loss": "sivia"}. dataset_weight: reduced é o método do qui-quadrado reduzido (o qui-quadrado de cada conjunto de dados dividido pelo seu número de pontos, reescalado por N/K para que o objetivo mantenha uma magnitude de qui-quadrado; linhas de penalidade não ponderadas) — impede que um grande conjunto com pequenos erros domine; loss: sivia substitui o qui-quadrado pela PDF mais ampla de Sivia, -2 log[(1 - e^{-R^2/2})/R^2] - 2 log 2 (~R^2/2 para resíduos pequenos, ~2 log R^2 para outliers: outliers são subponderados como se sua barra de erro fosse inflada). A perda de Sivia é aplicada a resíduos padronizados pelo chi2/N de referência de cada conjunto de dados (loss_scale: dataset, escalas computadas por init a partir da linha de base simples e armazenadas em campaign.json): sem isso, em um modelo com chi2/N ~ 20-300 cada ponto está na cauda logarítmica, os dados perdem ~10x seu peso contra as penalidades de norma quadráticas e o ajuste deriva (13C+a, 2026-09-08: chi2 simples 701k -> 1.190k em um polimento, MANA abandonado, normas fixadas no nominal). Ambos os métodos são "estatisticamente incorretos, mas úteis quando as barras de erro são subestimadas". O objetivo é uma propriedade de uma campanha: candidatos verificados sob objetivos diferentes não são comparáveis, então uma mudança de objetivo significa um novo diretório de campanha (semeie-o com a exportação anterior). REPORT.md e segment_scores mantêm o qui-quadrado simples por conjunto de dados qualquer que seja o objetivo. Verificado em rmfit/tests/test_objective_13n.py.
init verifica a linha de base (uma avaliação de modelo completo), registra a estrutura, escreve STATUS.md e o script de job run_crc_rmfit (nó long de 24 núcleos, envia e-mail para [email protected], -m abe). Re-executar init mantém uma configuração existente a menos que novos valores sejam fornecidos. Significados da política: theta2_cap é o limite de Wigner para níveis físicos, bg_theta2_cap para polos de fundo (níveis com Ex >= bg_energy, cujas energias permanecem fixas) — 3.0 é um palpite inicial, não um padrão físico: verifique onde as amplitudes de fundo da linha de base já estão (auditoria de limite do init) antes de confiar nele; 12C+alpha elástico precisava de ~100 (veja a entrada de log de 2026-09-30); e_window é a liberdade de energia de um nível por polimento (MeV); norm_range multiplica a normalização nominal. narrow_window (opcional, e.g. {"gamma_kev": 5, "factor": 3, "min_kev": 1}) mantém um nível cujas larguras parciais livres somam menos que gamma_kev dentro de ±max(min_kev, factor·Γ) de sua energia atual em vez de ±e_window, para que um polimento não possa carregar um nível estreito para longe de seu pico (o 13C+a 9/2+ derivou 180 keV em um polimento de aperto). Contagem de shards = núcleos; sharding é exato (qui-quadrado é aditivo sobre segmentos), então mais shards só compram velocidade.
Verificação de custo em um novo modelo (campaign.log após init): um objetivo sharded deve levar alguns segundos e um Jacobiano dezenas de segundos. Se um segmento com convolução de efeito alvo dominar (como Cierjacks fez em 13C+a), rmfit o dobra ele mesmo (model.ConvSpec); segmentos compostos de "soma" são permitidos como peças de convolução.
2b. Especificação, auditoria, decisões (2026-11-07; Fase 1 de R-matrix/rmfit/DESIGN.md)
Antes de init, escreva a especificação da campanha (spec.json, template rmfit/templates/SPEC_TEMPLATE.json, esquema em rmfit/spec.py): cada conjunto de dados com seu papel (anchor = norma fixada no nominal; free com prior_sigma; excluded com o motivo; screen), a janela de ajuste, o bloco congelado, os pares que devem existir, limites / objetivo / busca, o que o driver pode fazer por conta própria (pre_authorized: adopt_level true / false / regras, flip_adopt, dataset_off_adopt, ...), as regras de parada e as decisões permanentes com seu proprietário e data. Então:
python3 -m rmfit.audit <base>.azr --out AUDIT.md # pré-voo, sem sessão do motor: larguras livres zero, mesclagens de 1 keV,
# normas nominais != 1, normError como FRAÇÃO, colunas FLAG como
# erros, erros minúsculos, duplicatas, picos, limiares, <targetInt>
# em segmentos de teste, nomes .sav legados, caminho de saída, pino do motor
python3 -m rmfit.cli <dir> init --base ... --spec spec.json # flags/policy/search/objective/nshards da especificação a menos que
# fornecidos; discordâncias HIGH com o .azr recusam o init
python3 -m rmfit.cli <dir> spec check # a qualquer momento: SPEC_CHECK.md; spec render -> SPEC.md; audit -> AUDIT.md
Uma constatação de auditoria HIGH é corrigida (ou registrada como aceita nas decisões permanentes da especificação) antes da linha de base. Durante a campanha, qualquer coisa que a especificação não responda vai para DECISIONS.md (rmfit decisions lista, rmfit decide D-003 "adopt" --by DeBoer responde); uma adição de nível cujo accept a especificação não pré-autoriza é registrada como accept-pending com uma decisão na fila e NÃO é adotada (a antiga adoção automática só se aplica a campanhas sem especificação). Rascunhos de especificação para copiar: 10B+a/11-6-26_s5_highE/spec_draft.json, 13C+a/11-06-26_merged_regionD/spec_draft.json.
As três revisões de tempo ocioso da seção 3b são geradas, não escritas à mão, desde 2026-11-07:
python3 -m rmfit.cli <dir> audit --kind all # audits/{input,data,literature}/PROMPT.md + FINDINGS.md vazio
# entregue cada PROMPT.md a um subagente de fundo (ferramenta de Agente, um modelo mais barato, no máximo três por vez); ele escreve FINDINGS.md
python3 -m rmfit.cli <dir> audit --findings # linhas não verificadas (candidatas) de cada FINDINGS.md
python3 -m rmfit.cli <dir> audit --status data 1 confirmed --note "linha 4007 check"