Files
simulatore-induttori/CLAUDE.md
T
davideandClaude Opus 5 97ebab844e Esporta in CSV la temperatura simulata e la lettura del sensore
Nuova azione `python main.py csv`: esporta_csv.py integra il campo FEM e scrive
output/csv/run_XXXX.csv con la temperatura vera della parete nel punto
osservato, la lettura del sensore reale e il massimo nodale istante per
istante, più un metadata.csv con una riga per analisi. La cartella è ricreata a
ogni esecuzione.

Le righe sono campionate a FEM["frequenza_campionamento_hz"],
indipendente dal passo di integrazione, e FEM["num_run"] analisi vengono
esportate di seguito: con la randomizzazione abilitata ognuna ha parametri
diversi ma riproducibili dallo stesso seed.

simula_campo_fem accetta salva_campi=False, perché all'export servono solo le
serie scalari e non i campi nodali di ogni campione, e restituisce anche la
temperatura nodale massima per campione.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 11:44:58 +02:00

66 lines
6.8 KiB
Markdown
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.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Lingua
L'utente comunica in italiano. Tutto il codice, i commenti, la documentazione e i messaggi di commit devono essere scritti in italiano.
## Comandi
Usare sempre il virtual environment:
```bash
# Creare e attivare il venv (prima volta)
python -m venv .venv
source .venv/bin/activate
# Installare le dipendenze
pip install -r requirements.txt
# Punto di ingresso unico: `python main.py` elenca le azioni disponibili
python main.py mesh # disegna la sola mesh a elementi shell
python main.py fem # animazione 3D del campo FEM sulla mesh shell
python main.py csv # esporta output/csv/run_XXXX.csv + metadata.csv
```
Ogni modulo resta eseguibile anche direttamente (`python plot_mesh.py`, `python plot_animazione_fem.py`, `python esporta_csv.py`).
Attivare sempre il venv (`source .venv/bin/activate`) prima di eseguire qualsiasi comando Python.
Non sono configurati test o linter.
## Architettura
Analisi termica transitoria a elementi finiti di una fascetta (anello cilindrico sottile) riscaldata da sorgenti a induzione in movimento.
**Geometria:** la fascetta ha diametro, spessore e lunghezza configurabili. Il dominio discretizzato è la superficie media del cilindro: x = asse (le sorgenti si muovono lungo x sulla superficie esterna), theta = coordinata circonferenziale con theta = 0 sul piano del sensore, s = R·theta la lunghezza d'arco. Lo spessore non è discretizzato. Il sensore è un pirometro a infrarossi dentro la fascetta che misura la parete in un punto x fisso sul piano theta = 0.
**Flusso dei dati:**
1. `main.py` — dispatcher da riga di comando che seleziona l'azione (mesh, fem, csv)
2. `config.py` — tutti i parametri configurabili (dizionari FASCETTA, MESH, FEM, ARIA, SORGENTE, SENSORE, RANDOMIZZAZIONE, USCITA)
3. `materials.py` — dizionario MATERIALI con proprietà termofisiche ed elettriche per materiale
4. `mesh.py` — mesh a elementi shell quadrangolari della superficie media del cilindro, visualizzata da `plot_mesh.py`
5. `fem.py` — solutore termico transitorio a elementi finiti sulla mesh shell, animato da `plot_animazione_fem.py` ed esportato in CSV da `esporta_csv.py`
**Mesh shell (`mesh.py`):** griglia strutturata `n_elementi_x × n_elementi_circonferenza` di quadrilateri a 4 nodi sulla superficie media (raggio = (diametro spessore)/2); lo spessore non è discretizzato, è un attributo della shell. La mesh è chiusa lungo la circonferenza (nessun nodo duplicato sulla cucitura) e usa coordinate globali x = asse, y = R·sin(theta), z = R·cos(theta), con theta = 0 sul piano del sensore.
**Pipeline FEM dentro `fem.py`:** equazione risolta per unità di superficie media, `rho·cp·t ∂T/∂t = k·t ∇²T + q(x, s, t) (h_est + h_int)(T T_amb)`, con convezione `h_bordi` sui due bordi anulari (area = spessore × perimetro). Il collasso in spessore è lecito perché Biot ≈ 1e-7 e il tempo di diffusione nella parete è di pochi ms: la profondità di penetrazione del riscaldamento non entra nel modello, conta solo il flusso assorbito. La skin depth è comunque calcolata dalla frequenza dell'induttore (`calcola_skin_depth_m`) e riportata in `stato["skin_depth_m"]` come sola diagnostica. L'impronta della sorgente è una gaussiana isotropa in (x, s) con distanza circonferenziale valutata sull'immagine più vicina (superficie chiusa). Gli elementi sono bilineari a 4 nodi e tutti identici (rettangoli dx × ds), quindi le matrici di elemento (`MASSA_RIF`, `RIGIDEZZA_X`, `RIGIDEZZA_S`) sono calcolate una volta e assemblate in forma vettorizzata; la matrice di massa di superficie è riusata per capacità, convezione e carico della sorgente. Eulero implicito con matrice costante fattorizzata LU una volta per analisi (`prepara_stato_fem`), poi `passo_implicito_fem` assembla solo il termine noto. In `fem.py` stanno anche la cinematica del gruppo di sorgenti (`_x_riferimento_iniziale_m`, `_x_riferimento_finale_m`, `_intervallo_attivo`) e la lettura della configurazione (`configurazione_randomizzata`).
**Sensore e randomizzazione:** il campo nodale è la temperatura vera della parete; `simula_campo_fem` restituisce anche `T_lette`, la lettura del sensore degradata da inerzia del primo ordine (a ogni passo dt), rumore gaussiano e quantizzazione (a ogni campionamento di frame). `configurazione_randomizzata` perturba velocità, flusso di picco, sigma dello spot, offset y, temperatura ambiente e rumore del sensore con un RNG con seed `FEM["seed"]`, così due analisi restano riproducibili ma diverse; con `RANDOMIZZAZIONE["abilitata"] = False` restituisce i valori nominali di `config.py`.
**Export CSV (`esporta_csv.py`):** `FEM["num_run"]` analisi (una per file `output/csv/run_XXXX.csv`), righe campionate a `FEM["frequenza_campionamento_hz"]` indipendentemente da `FEM["dt_s"]`. Colonne: `id_run, tempo_s, x_sorgente_m, T_vera_sensore_C, T_misurata_sensore_C, T_massima_fascetta_C, T_ambiente_C, offset_y_sorgente_m, velocita_m_s, sigma_punto_m, flusso_picco_W_m2, skin_depth_m, materiale`. `metadata.csv` ha una riga per analisi con tutti i parametri e i picchi. L'export chiama `simula_campo_fem(salva_campi=False)`: usa solo le serie scalari, i campi nodali non vengono accumulati. La cartella `output/csv` è cancellata e ricreata a ogni esecuzione (`shutil.rmtree`).
## Convenzioni su `config.py`
Ogni parametro in [config.py](config.py) ha un commento che spiega solo cos'è (il suo significato fisico/funzionale), mai perché è impostato a un valore specifico. Quando si modifica un parametro per ottenere un certo comportamento (es. una velocità diversa, un range di temperatura target), va cambiato solo il valore: non aggiungere commenti che giustificano o motivano quel valore, perché diventano obsoleti/fuorvianti alla prossima modifica.
## Vincoli progettuali chiave
- Il modello è una shell: la circonferenza è risolta, lo spessore è collassato (temperatura uniforme nella parete). Non introdurre effetti attraverso lo spessore (skin depth, gradiente radiale) senza prima discretizzarlo.
- Le posizioni di inizio/fine corsa delle sorgenti (`x_inizio_m`, `x_fine_m`) sono distanze dal punto x del sensore lungo il verso di marcia; il segno di `velocita_m_s` determina il verso (negativo = -x).
- La matrice implicita è costruita e fattorizzata una volta sola (proprietà del materiale costanti, nessun coefficiente dipendente dalla temperatura). Se si aggiungono proprietà dipendenti dalla temperatura, la matrice deve essere ricostruita e rifattorizzata ad ogni passo temporale.
- Le visualizzazioni salvano in `USCITA["cartella"]` solo quando il backend matplotlib non è interattivo; altrimenti aprono una finestra.
- Aggiungere un nuovo materiale richiede solo una nuova voce nel dizionario `MATERIALI` in [materials.py](materials.py); la chiave del materiale va poi impostata in `FASCETTA["materiale"]` in [config.py](config.py).