OpenFOAM: monitoraggio, diagnostica e verifica della convergenza
Questa è la seconda guida operativa su OpenFOAM installato su un server Linux e usato da Windows. La prima guida spiega come trasferire i casi con FileZilla, entrare in SSH da PowerShell, lanciare i calcoli in tmux e collegare ParaView al server. Questa parte da un caso che già funziona e riguarda ciò che viene dopo il lancio: monitoraggio, diagnostica e verifica della convergenza, con OpenFOAM Foundation 14.
Monitoraggio, diagnostica e verifica della convergenza
Dal lancio del calcolo alla valutazione dei risultati — OpenFOAM Foundation 14
Edizione: 16 ottobre 2026 · Manuale operativo generale · Windows + server Linux
Scopo. Questa guida parte da un caso OpenFOAM già funzionante. Spiega come controllare il calcolo, distinguere i segnali di allarme, registrare grandezze fisiche durante l’esecuzione e produrre una verifica ripetibile. Si assume che il trasferimento tramite FileZilla e l’accesso SSH da PowerShell siano già noti. Il testo non richiede un IDE particolare: Notepad++ è sufficiente.
Percorso di lettura. I capitoli 1–3 costituiscono il controllo minimo di ogni simulazione; 4–6 aggiungono il monitoraggio quantitativo; 7 è un’esercitazione; 8 e gli allegati sono materiale di riferimento. I riquadri Richiamo sono opzionali per chi conosce già la fluidodinamica.
1. Che cosa significa «simulazione riuscita»?
Una simulazione che termina senza messaggi di errore non è automaticamente affidabile. Separare almeno quattro domande:
| Livello | Domanda | Evidenza minima |
|---|---|---|
| Esecuzione | Il programma è terminato correttamente? | Codice di uscita, log completo, assenza di errori fatali |
| Numerica | Le equazioni si stanno risolvendo stabilmente? | Residui, continuità, Courant, assenza di oscillazioni incontrollate |
| Fisica | La soluzione rispetta i vincoli del problema? | Bilanci, ordini di grandezza, condizioni al contorno, Δp, Q |
| Credibilità | Il risultato dipende troppo dalla discretizzazione? | Sensibilità a mesh, passo temporale, schemi e modello |
Il controllo dei residui riguarda soprattutto la seconda riga. Per accettare una simulazione servono anche controlli delle grandezze fisiche e, in una successiva fase, uno studio di sensibilità numerica.
Richiamo facoltativo — residui e accuratezza. Il residuo misura quanto bene viene soddisfatto il sistema algebrico discretizzato nella particolare iterazione: un residuo piccolo non dimostra che la discretizzazione rappresenti accuratamente le equazioni continue. Una simulazione può convergere verso una soluzione coerente con una mesh troppo grossolana.

Approfondimento · Verifica e validazione: due domande diverse
Nella letteratura di riferimento sulla credibilità della CFD (per esempio le linee guida AIAA G-077 e i lavori di Roache) si distinguono due attività:
- Verifica: «sto risolvendo correttamente le equazioni?». Riguarda il codice e la soluzione numerica: convergenza iterativa (residui, bilanci), convergenza rispetto alla mesh e al passo temporale, stima dell’errore di discretizzazione.
- Validazione: «sto risolvendo le equazioni giuste?». Confronta il risultato con la realtà fisica (esperimenti, soluzioni esatte di problemi rappresentativi) e mette alla prova il modello: laminare o turbolento, condizioni al contorno, proprietà del fluido.
Le righe «Numerica» e «Credibilità» della tabella sono verifica; la riga «Fisica» fa da ponte verso la validazione. Questa guida copre la convergenza iterativa e i bilanci. La convergenza rispetto alla mesh è il passo successivo: nel caso 02 del percorso OpenFOAM 14 è svolta con il confronto con la soluzione di Poiseuille.
2. Prima del lancio: la checklist essenziale
Lavora su una copia del caso, non sul caso di riferimento o su una simulazione in corso. Conserva i file 0/, constant/, system/ e annota quale variante stai usando. Da PowerShell:
ssh UTENTE@SERVER
Sul server, dopo avere caricato l’ambiente OpenFOAM nella shell:
foamVersion
cd ~/cases/mioCaso
pwd
ls -la
grep -E '^[[:space:]]*(solver|startFrom|endTime|deltaT|adjustTimeStep|writeControl|writeInterval)' system/controlDict
checkMesh > "log.checkMesh_$(date +%Y%m%d_%H%M%S)" 2>&1
tail -n 25 log.checkMesh_*
L’ultimo comando è comodo solo se nella cartella non vi sono molti log storici; in alternativa annota il nome del log creato e apri quello. Controlla Mesh OK e soprattutto eventuali avvisi su skewness, non-ortogonalità, volumi negativi, patch inattese e celle fortemente distorte. Mesh OK non significa «mesh abbastanza fine».
Per i casi incomprimibili OpenFOAM Foundation 14, il solver modulare è generalmente foamRun, con solver incompressibleFluid; in system/controlDict. Non usare meccanicamente ricette per vecchi solver senza verificare la versione e il caso.
Prima dell’avvio verifica la geometria e le unità SI, il nome dei patch in constant/polyMesh/boundary, la coerenza dei campi in 0/, la configurazione di fvSchemes/fvSolution, lo spazio libero sul disco e i permessi di scrittura. Ricontrolla le dimensioni del campo p: nei casi incomprimibili standard è spesso pressione cinematica, non Pa.
Approfondimento · Leggere checkMesh: le soglie che fanno scattare gli avvisi
Le righe che iniziano con *** sono gli avvisi. Le principali, con le soglie predefinite di checkMesh:
| Controllo | Avviso quando | Che cosa comporta |
|---|---|---|
| Non ortogonalità | angolo oltre 70° («severely non-orthogonal») | il gradiente normale alle facce richiede correzioni; servono nNonOrthogonalCorrectors e schemi limited |
| Skewness | valore massimo oltre 4 | l’interpolazione al centro faccia perde accuratezza |
| Rapporto d’aspetto | oltre 1000 | possibili difficoltà dei solutori lineari |
| Volumi e determinanti | volumi negativi o nulli, determinante basso | mesh non utilizzabile: va corretta |
Per un controllo più severo prima di un calcolo lungo:
checkMesh -allGeometry -allTopology > log.checkMesh_full 2>&1
grep -n '\*\*\*' log.checkMesh_full
Il significato di non ortogonalità e skewness per gli schemi è sviluppato in Parte 5: fvSchemes e per i correttori in Parte 6: fvSolution.
Approfondimento · Controlli rapidi prima del lancio da riga di comando
foamDictionary -entry solver system/controlDict # modulo di solver
foamDictionary -entry dimensions 0/p # [0 2 -2 0 0 0 0] = pressione cinematica
grep -E '^[[:space:]]+[A-Za-z]' constant/polyMesh/boundary | head -n 20 # nomi dei patch
df -h . # spazio libero
touch .scrittura_ok && rm .scrittura_ok && echo "scrittura OK" # permessi
Annotare l’esito di questi comandi nella scheda di verifica della sezione 7 rende confrontabili le varianti successive.
3. Leggere il log mentre la simulazione lavora
Esegui nella directory del caso in una sessione persistente (tmux se disponibile), salvando un nuovo log identificabile:
LOG="log.foamRun_$(date +%Y%m%d_%H%M%S)"
echo "Log: $LOG"
foamRun > "$LOG" 2>&1
printf 'Exit code: %s\n' "$?"
Per osservare un calcolo già avviato, usa un’altra sessione SSH:
tail -n 50 -f log.foamRun_20261016_153000
Sostituisci il nome con quello reale. Ctrl+C interrompe solo tail, non il solver avviato altrove. Se avvii il solver direttamente in foreground nella stessa shell, Ctrl+C interrompe invece il solver: non confondere le due situazioni.
Un estratto tipico, inventato a scopo didattico, può apparire così:
Time = 120
smoothSolver: Solving for Ux, Initial residual = 0.00038, Final residual = 4.2e-07, No Iterations 3
GAMG: Solving for p, Initial residual = 0.0016, Final residual = 8.1e-06, No Iterations 5
time step continuity errors : sum local = 2.3e-07, global = -1.1e-09, cumulative = 7.0e-06
ExecutionTime = 54.12 s ClockTime = 55 s
| Voce nel log | Interpretazione corretta | Segnale da investigare |
|---|---|---|
Time = ... | Tempo simulato o contatore pseudo-temporale, secondo il caso | Non interpretarlo automaticamente come secondi reali |
Initial residual | Residuo prima della soluzione del sistema lineare | Plateau alto, crescita o oscillazioni persistenti |
Final residual | Residuo alla fine di quella soluzione lineare | Da solo non prova la convergenza globale |
No Iterations | Iterazioni del solutore lineare per il campo | Crescita rapida o raggiungimento sistematico del limite |
continuity errors | Indicatore della conservazione locale/globale nel passo | Deriva cumulativa o errori globali persistenti |
Courant Number | Vincolo di trasporto temporale se riportato | Picchi non giustificati; soglia dipendente dal metodo |
ExecutionTime/ClockTime | Tempi CPU / tempo trascorso | Sbilanciamento o rallentamenti anomali |
Richiamo facoltativo — steady vs transient. In un caso stazionario il campo deve stabilizzarsi e gli osservabili tendere a valori costanti. In un problema transitorio fisicamente non stazionario possono persistere oscillazioni reali: occorre verificare convergenza delle iterazioni per passo, bilanci e indipendenza dal passo temporale, non pretendere residui monotonamente decrescenti su tutta la serie.
Ricerche rapide sul server (se presenti):
grep -nE 'FOAM FATAL|Floating point exception|nan|NaN|not converged|Courant Number|continuity errors' log.foamRun_20261016_153000 | tail -n 40
grep 'ExecutionTime' log.foamRun_20261016_153000 | tail -n 5
Su Windows puoi scaricare il log con FileZilla / SFTP e aprirlo con klogg o Notepad++; per cercare da PowerShell:
Select-String -Path 'C:\CFD\log\log.foamRun_20261016_153000' -Pattern 'FOAM FATAL','Courant Number','continuity errors'
Il log scaricato durante l’esecuzione è una fotografia parziale: scaricalo nuovamente se vuoi analizzare gli ultimi passi.
Approfondimento · Come OpenFOAM normalizza i residui
Per un sistema lineare A x = b, OpenFOAM non riporta la norma grezza di b − A x, che dipenderebbe dalle unità e dalla dimensione del problema, ma un residuo normalizzato:
r = Σ|b − A x| / ( Σ|A x − A x̄| + Σ|b − A x̄| + 10−20 )
dove x̄ è la media del campo. Il denominatore misura l’ampiezza delle variazioni del campo: per questo un residuo di 10−3 ha un significato simile per pressione e velocità. Due conseguenze pratiche: un campo quasi uniforme (denominatore piccolo) può mostrare residui alti anche con errori modesti; un buon «Initial residual» all’inizio di un passo transitorio dice che il campo cambia poco da un passo all’altro, non che la soluzione sia accurata.
Tolleranze, relTol e iterazioni sono trattate in Parte 6.
Approfondimento · Codice di uscita, tee e pipefail
Nel comando della guida l’uscita va direttamente nel file, per cui $? è il codice di uscita di foamRun: 0 se il solver è terminato normalmente, diverso da 0 in caso di errore fatale. Se invece si usa tee per vedere e salvare insieme, $? diventa quello di tee (quasi sempre 0) e l’errore resterebbe nascosto. Due rimedi in bash:
set -o pipefail
foamRun 2>&1 | tee "$LOG"
echo "Exit code: $?"
# oppure / or
foamRun 2>&1 | tee "$LOG"; echo "Exit code: ${PIPESTATUS[0]}"
In tmux conviene una finestra per il solver e una per tail -f e grep: Ctrl+B poi C crea la seconda finestra, Ctrl+B poi N passa dall’una all’altra.
4. Registrare residui e sonde con le function objects
OpenFOAM 14 fornisce la configurazione riutilizzabile delle function objects. È preferibile usare i file distribuiti con l’installazione invece di copiare ricette scritte per varianti o versioni diverse.
Dalla directory del caso di prova, esegui:
foamPostProcess -list | less
foamInfo residuals
foamGet residuals
foamGet probes
I comandi foamGet creano i corrispondenti file in system/ (se nella tua installazione sono già presenti, fai prima un backup e verifica cosa sta per essere sovrascritto). Modifica system/probes con Notepad++ e FileZilla, scegliendo coordinate interne al dominio e campi esistenti. Estratto indicativo:
fields (p U);
probeLocations
(
(0.010 0.000 0.000)
(0.040 0.000 0.000)
);
Le coordinate sono segnaposto illustrativi: verifica nel tuo dominio con ParaView prima di usarle. Le sonde probes leggono i valori della cella più vicina; per misure su sezioni e interpolazioni precise scegli altri metodi di campionamento.
Nel file system/functions (crealo se assente; se esiste integrane il contenuto preservando le voci) inserisci:
#includeFunc residuals
#includeFunc probes
A seconda della configurazione i risultati appariranno, per esempio, in:
postProcessing/
residuals/0/residuals.dat
probes/0/p
probes/0/U
La sottocartella 0 è solo un esempio: può cambiare al riavvio o con un diverso startTime. Controlla con find postProcessing -maxdepth 3 -type f | sort.
Se il server dispone di un ambiente grafico e di gnuplot, puoi anche seguire i residui sul server con:
foamMonitor -l postProcessing/residuals/0/residuals.dat
Per il lavoro prevalentemente da Windows non serve eseguire foamMonitor: scarica periodicamente quel file con FileZilla e rappresentalo con Calc, Excel o Python. foamMonitor è un’opzione, non una dipendenza obbligatoria.
Per verificare senza aspettare il prossimo run puoi consultare la configurazione o usare il post-processing sui tempi già salvati, in funzione del tipo di object:
foamPostProcess -help
foamPostProcess -list
Non tutte le function objects possono ricostruire ogni grandezza a posteriori: se una grandezza dipende da valori non salvati, configurala prima del calcolo.

Approfondimento · Formato dei file e uno script Python per i residui
I file di postProcessing sono testo con righe di commento che iniziano con #. residuals.dat ha un’intestazione con i nomi delle colonne (il tempo e un residuo iniziale per campo, con eventuali N/A quando un campo non è risolto in quel passo). I file delle sonde hanno una riga di commento per sonda con le coordinate; nel file U ogni valore è un vettore tra parentesi (Ux Uy Uz).
Uno script che legge l’intestazione reale invece di presupporre le colonne (richiede Python con matplotlib su Windows):
# plot_residuals.py - python plot_residuals.py residuals.dat
import sys
import matplotlib.pyplot as plt
names, rows = None, []
for line in open(sys.argv[1], encoding='utf-8', errors='replace'):
s = line.strip()
if not s:
continue
if s.startswith('#'):
tok = s.lstrip('#').split()
if tok and tok[0] == 'Time':
names = tok # ultima riga di intestazione con i nomi delle colonne
continue
rows.append(s.split())
for j, name in enumerate(names[1:], start=1):
t, r = [], []
for row in rows:
if j < len(row) and row[j] not in ('N/A', 'nan'):
t.append(float(row[0])); r.append(float(row[j]))
if r:
plt.semilogy(t, r, label=name)
plt.xlabel('Time'); plt.ylabel('Initial residual'); plt.grid(True, which='both', alpha=0.3)
plt.legend(); plt.tight_layout(); plt.savefig('residuals.png', dpi=150)
print('grafico salvato in residuals.png')
Per il file U delle sonde, prima di importarlo, si possono togliere le parentesi sul server con sed 's/[()]//g' postProcessing/probes/0/U > U_probes.txt: ogni riga diventa tempo seguito da tre componenti per sonda.
Approfondimento · Dove si trovano le configurazioni distribuite
foamGet copia nel caso un file preso da $FOAM_ETC/caseDicts/functions. Prima di usarlo conviene leggerne i parametri con foamInfo e vedere che cosa contiene la copia:
ls $FOAM_ETC/caseDicts/functions
foamInfo probes
cat system/probes
Oltre a residuals e probes la stessa cartella contiene configurazioni pronte per medie e flussi sui patch, campionamenti lungo linee, forze e altro. La pagina 7.4 Sampling and monitoring data della User Guide v14 descrive le principali.
5. Misurare Δp e portata, non soltanto i residui
Per un problema di flusso in un canale, lo studente o l’operatore può verificare mentre la simulazione procede la pressione media su inlet/outlet e la portata attraverso gli stessi patch. Un metodo generale di OpenFOAM 14 è surfaceFieldValue.
Aggiungi in system/functions, oltre alle due direttive precedenti, questo esempio per patch effettivamente chiamati inlet e outlet:
pInlet
{
type surfaceFieldValue;
libs ("libfieldFunctionObjects.so");
patch inlet;
operation areaAverage;
writeFields false;
fields (p);
writeControl timeStep;
writeInterval 1;
}
pOutlet
{
type surfaceFieldValue;
libs ("libfieldFunctionObjects.so");
patch outlet;
operation areaAverage;
writeFields false;
fields (p);
writeControl timeStep;
writeInterval 1;
}
qInlet
{
type surfaceFieldValue;
libs ("libfieldFunctionObjects.so");
patch inlet;
operation sum;
writeFields false;
fields (phi);
writeControl timeStep;
writeInterval 1;
}
qOutlet
{
type surfaceFieldValue;
libs ("libfieldFunctionObjects.so");
patch outlet;
operation sum;
writeFields false;
fields (phi);
writeControl timeStep;
writeInterval 1;
}
Il patch deve esistere; p e phi devono essere disponibili nel caso. Le quattro serie saranno sotto postProcessing/pInlet/..., pOutlet/..., qInlet/..., qOutlet/...; i nomi dei file e l’intestazione vanno controllati nel risultato effettivo. Questa sintassi fa riferimento a OpenFOAM Foundation v14, non all’omonima implementazione di altre distribuzioni che usa talvolta regionType/name.
Calcoli da effettuare dopo l’esportazione:
- Caduta media di pressione:
Δp = p_media,in − p_media,out. - Per un incomprimibile standard con
pcinematica[0 2 -2 0 0 0 0]:ΔP [Pa] = ρ [kg/m³] × Δp [m²/s²], a densità costante. - Con
pgià in Pa, non moltiplicare per la densità. - Con
phivolumetrica:Q_inè tipicamente negativo perché la normale del patch punta verso l’esterno,Q_outpositivo. Conphimassica, il risultato è in kg/s; verifica le dimensioni. - Per un ingresso e un’uscita, errore relativo di bilancio:
ε_Q = |Q_in + Q_out| / ((|Q_in|+|Q_out|)/2) × 100%. Con più patch di flusso, includere tutte le sezioni aperte.
Esempio puramente illustrativo: p_in − p_out = 6.2 m²/s², ρ = 1000 kg/m³ → ΔP = 6200 Pa; Q_in = −2.500×10⁻⁴ m³/s, Q_out = +2.495×10⁻⁴ m³/s → ε_Q ≈ 0.20%. Questi numeri non sono soglie di accettazione.
Richiamo facoltativo — quale pressione? Per un confronto con un manometro, definisci sezioni confrontabili e chiarisci se stai osservando pressione statica, differenza di pressione idraulica, carico totale o perdite localizzate. Una media di pressione sulle superfici d’ingresso e uscita non equivale sempre alla perdita irreversibile di pressione: possono contare accelerazione, profili non uniformi e quote gravitazionali.

Approfondimento · Un controllo di ordine di grandezza sul canale del percorso
Nel canale trainingChannel della Parte 3 (sezione 10 × 5 mm, velocità d’ingresso uniforme 0,05 m/s) la portata attesa è Q = U · A = 0,05 × 5,0×10⁻⁵ = 2,5×10⁻⁶ m³/s. Il valore di qInlet deve quindi essere vicino a −2,5×10⁻⁶ fin dal primo passo, perché è imposto dalla condizione al contorno, mentre qOutlet tende a +2,5×10⁻⁶ man mano che il campo si assesta.
Per la caduta di pressione tra due lastre piane parallele a distanza H in regime laminare sviluppato vale Δp_cin = 12 ν L U_media / H² (pressione cinematica): è la relazione usata nel caso 01 per la validazione con Poiseuille. In un condotto rettangolare il coefficiente cambia con il rapporto dei lati, ma l’ordine di grandezza resta un controllo utile prima di analizzare i decimali.
Approfondimento · Alternative pronte: patchAverage e patchFlowRate
Tra le configurazioni distribuite con OpenFOAM 14 ci sono funzioni già impostate per medie e portate sui patch, richiamabili con argomenti in una riga di system/functions. Prima di usarle leggi i parametri accettati dalla tua installazione:
foamInfo patchAverage
foamInfo patchFlowRate
Con i parametri confermati da foamInfo, la forma è del tipo:
#includeFunc patchAverage(patch=inlet, fields=(p))
#includeFunc patchAverage(patch=outlet, fields=(p))
#includeFunc patchFlowRate(patch=inlet)
#includeFunc patchFlowRate(patch=outlet)
Il risultato è equivalente ai quattro blocchi espliciti; i blocchi della guida restano preferibili quando si vuole vedere e controllare ogni opzione (operation, writeControl, writeInterval).
Arresto automatico e sua interpretazione
In alcuni casi stazionari la sezione SIMPLE/residualControl di system/fvSolution definisce criteri per fermare il calcolo automaticamente. Controlla che cosa è configurato:
grep -n -A 14 'residualControl' system/fvSolution
Un messaggio di soluzione convergente indica che le condizioni d’arresto impostate dal caso sono state soddisfatte: non sostituisce i controlli di portata, pressione e discretizzazione. Nei casi transitori la logica di controllo e il significato delle iterazioni cambiano.
Approfondimento · Com’è fatto residualControl
SIMPLE
{
nNonOrthogonalCorrectors 0;
residualControl
{
p 1e-2;
U 1e-3;
"(k|epsilon|omega)" 1e-3;
}
}
Ogni valore è la soglia sull’Initial residual del campo: quando tutti i campi elencati scendono sotto la propria soglia nella stessa iterazione, il solver scrive l’ultimo tempo ed esce con un messaggio del tipo SIMPLE solution converged in ... iterations. Le soglie non hanno nulla di universale: con soglie larghe il calcolo può fermarsi mentre Δp sta ancora cambiando. Per questo la guida chiede di confrontare la fermata con gli osservabili della figura 3. Gli algoritmi SIMPLE e PIMPLE sono spiegati in Parte 6.
6. Tre segnali tipici e come reagire
| Caso osservato | Diagnosi possibile | Prima azione controllata |
|---|---|---|
Residui diminuiscono, ma Δp deriva ancora | Convergenza numerica locale, osservabile globale non stabilizzato | Continua il monitoraggio; verifica intervallo e stabilità del Δp |
| Residui e continuità crescono, picchi di Courant | Instabilità numerica, condizioni iniziali o BC inadatte, Δt eccessivo | Rivedi BC, mesh, passo temporale; confronta con variante precedente |
Residui bassi e Δp stabile, ma bilancio scorretto | Patch mancanti, flussi errati, problemi di setup o calcolo | Elenca tutti i patch aperti; confronta Σphi e sorgenti volumetriche |
Avviso mesh severo già in checkMesh | Causa geometrica/discretizzazione | Non compensare a caso con tolleranze: correggi e ricontrolla la mesh |
FOAM FATAL ERROR o Floating point exception | Interruzione anomala, non risultato valido | Conserva log e configurazione; identifica il primo messaggio causale |
La presenza di oscillazioni non identifica automaticamente un errore: possono essere fisiche in flussi transitori. La risposta corretta dipende dal modello e dagli obiettivi. Non cambiare contemporaneamente mesh, schemi, rilassamento e condizioni al contorno: perdi la capacità di identificare la causa.
Politica operativa per il debug: conserva una baseline, modifica un fattore alla volta, salva un log nuovo e confronta un insieme costante di indicatori.
Approfondimento · Trovare il primo messaggio causale e confrontare due varianti
In un log che termina con errore, l’ultimo messaggio è spesso una conseguenza. Si cerca la prima occorrenza e si leggono le righe che la precedono:
grep -n -m1 -E 'FOAM FATAL|Floating point exception|nan' log.foamRun_20261016_153000
sed -n '1180,1240p' log.foamRun_20261016_153000 # intervallo attorno alla riga trovata / range around the line found
Con due copie del caso (baseline e variante) la differenza dei dizionari dice esattamente che cosa è stato cambiato:
diff -ru mioCaso_v01/system mioCaso_v02/system
diff -ru mioCaso_v01/constant/momentumTransport mioCaso_v02/constant/momentumTransport
diff -ru mioCaso_v01/0 mioCaso_v02/0
Se il diff mostra più di un fattore cambiato, il confronto tra i due log non permette di attribuire la causa.
7. Esercitazione guidata: una verifica riproducibile
L’esercitazione usa un qualsiasi caso già testato di flusso incomprimibile con due patch inlet/outlet; se i nomi differiscono, adattali. Non è richiesto ricostruire una geometria per usare questa guida.
- Duplica il caso in una nuova cartella, ad esempio
mioCaso_monitor_v01; non cancellare i dati della versione precedente. - Esegui
checkMeshe conserva il suo log con data/ora. - Genera
system/residualsesystem/probesconfoamGet, controllando gli eventuali file già presenti. - Crea o integra
system/functions; aggiungi i monitor di pressione/portata della sezione 5 dopo aver verificato i nomi dei patch. - Avvia
foamRunintmuxo altra sessione persistente e registra il nome esatto del log. - In un’altra sessione osserva
tail -f ...; cerca messaggi di errore, continuità, eventuale Courant e tempi di calcolo. - Con FileZilla scarica solo
log.*epostProcessing/: per grafici di convergenza normalmente non servono tutti i volumi dei campi CFD. - Su Windows apri il log con klogg; importa le serie
.dat,p,Uin LibreOffice Calc, Excel o Python, rispettando intestazioni e commenti. - Realizza almeno tre grafici: residui (asse logaritmico se utile),
ΔpoΔPcontro iterazione/tempo, errore di bilancioε_Qcontro iterazione/tempo. - Riporta intervallo finale analizzato, numero di campioni e la variabilità di
Δpnell’intervallo: per esempiomax−minrelativo alla media (se la media è non nulla). Indica se è un run steady o transient.
Piccola trappola didattica. Se il grafico dei residui suggerisce un plateau, ma Δp cambia del 5% nell’ultimo intervallo, il calcolo non è ancora dimostrato stabile per l’osservabile che interessa. Se i residui diminuiscono di altri due ordini di grandezza ma Δp non cambia, approfondisci piuttosto il bilancio e la sensibilità alla discretizzazione. Il 5% è un esempio, non una soglia universale.
Approfondimento · Uno script per Δp, ε_Q e la finestra di stabilità
Lo script legge le quattro serie scaricate con FileZilla (la cartella postProcessing copiata su Windows), calcola Δp e ε_Q passo per passo e riassume le ultime N righe: media, variazione relativa (max−min)/|media| e pendenza. Usa solo la libreria standard di Python.
# monitor_report.py - python monitor_report.py <cartella postProcessing scaricata> [N]
import sys, re, pathlib, statistics as st
def read_series(path):
# restituisce (tempi, valori) leggendo la prima colonna dopo il tempo; ignora i commenti '#'
t, v = [], []
for line in open(path, encoding='utf-8', errors='replace'):
if not line.strip() or line.lstrip().startswith('#'):
continue
tok = line.split()
try:
t.append(float(tok[0])); v.append(float(tok[1]))
except (ValueError, IndexError):
pass
return t, v
def find(root, name):
files = sorted(pathlib.Path(root, name).rglob('*.dat'))
if not files:
sys.exit('nessun file .dat in ' + str(pathlib.Path(root, name)))
return files[-1] # l'ultima sottocartella di partenza (restart)
root = sys.argv[1]
N = int(sys.argv[2]) if len(sys.argv) > 2 else 100
series = {k: read_series(find(root, k)) for k in ('pInlet', 'pOutlet', 'qInlet', 'qOutlet')}
n = min(len(s[1]) for s in series.values())
pin, pout = series['pInlet'][1][:n], series['pOutlet'][1][:n]
qin, qout = series['qInlet'][1][:n], series['qOutlet'][1][:n]
t = series['pInlet'][0][:n]
dp = [a - b for a, b in zip(pin, pout)]
eps = [abs(a + b) / ((abs(a) + abs(b)) / 2) * 100 for a, b in zip(qin, qout)]
w = slice(max(0, n - N), n)
dpw, epw, tw = dp[w], eps[w], t[w]
m = st.mean(dpw)
slope = (dpw[-1] - dpw[0]) / (tw[-1] - tw[0]) if tw[-1] != tw[0] else 0.0
print(f'campioni totali {n}, finestra finale {len(dpw)} campioni, da t={tw[0]} a t={tw[-1]}')
print(f'dp medio {m:.6g} (max-min)/|media| = {(max(dpw)-min(dpw))/abs(m)*100:.3g} % pendenza {slope:.3g} per unita di tempo')
print(f'eps_Q medio {st.mean(epw):.3g} % massimo {max(epw):.3g} % Q_in {st.mean(qin[w]):.6g} Q_out {st.mean(qout[w]):.6g}')
with open('monitor_report.csv', 'w') as f:
f.write('time,dp,eps_Q_percent\n')
for a, b, e in zip(t, dp, eps):
f.write(f'{a},{b},{e}\n')
print('serie completa scritta in monitor_report.csv')
Uso: python monitor_report.py C:\CFD\log\mioCaso\postProcessing 200. La pendenza, moltiplicata per la durata della finestra, dice di quanto Δp sta ancora cambiando: se è dello stesso ordine della variazione ammessa, la finestra non è ancora stabile. Il file monitor_report.csv si apre direttamente in Excel o Calc per i grafici.
Scheda di verifica da allegare a ogni simulazione
| Parametro o controllo | Valore da registrare |
|---|---|
| Identificativo caso e revisione dei dizionari | Nome, data, cartella, note |
| Versione OpenFOAM e modello | foamVersion, solver, regime fisico |
| Mesh | Celle, risultati checkMesh, modifiche |
| Discretizzazione temporale e numerica | deltaT/maxCo, fvSchemes, fvSolution |
| Stato di esecuzione | Concluso/interrotto, exit code, nome del log |
| Diagnostica numerica | Residui, continuità, Courant (se pertinente) |
| Grandezze fisiche | Δp / ΔP, Q_in, Q_out, ε_Q e unità |
| Stabilizzazione | Finestra scelta, media e variazione degli osservabili |
| Validazione successiva | Confronti con teoria/esperimento e mesh/time-step study |
8. Errori comuni nell’analisi da Windows
Errore: un .dat è vuoto o contiene soltanto un’intestazione. Il run può non avere ancora scritto un passo valido; controlla writeControl/writeInterval, eventuali messaggi nel log e la sottocartella di postProcessing corrispondente alla partenza del run.
Errore: FileZilla mostra dati vecchi. Il file locale è una copia statica: fai un nuovo download e verifica la dimensione e l’ora di modifica. Non lavorare su una simulazione remota pensando che l’editor locale la aggiorni automaticamente.
Errore: grafici insensati importati in Excel. I file hanno spesso commenti #, separatori di spazi e colonne vettoriali del tipo (Ux Uy Uz). Scegli l’importazione come testo delimitato con opzioni adeguate, oppure separa e normalizza le componenti. Non trattare il file U automaticamente come una semplice tabella di quattro colonne.
Errore: p è interpretata sempre come Pa. Apri il file del campo, per esempio 0/p, e guarda la voce dimensions: [0 2 -2 0 0 0 0] indica pressione cinematica, [1 -1 -2 0 0 0 0] indica pressione dinamica in Pa.
Errore: epsilon_Q è interpretato come criterio sufficiente. Un buon bilancio globale non esclude fenomeni locali non risolti, errori sulle pareti, cattiva distribuzione di velocità o mesh troppo grossolana.
Errore: si usa una soglia unica per ogni modello. Residui, Courant e stabilizzazione vanno riferiti agli obiettivi della simulazione e al regime fisico; documenta i criteri prima di interpretarli.
Approfondimento · Importare in Excel con le impostazioni italiane
OpenFOAM scrive i numeri con il punto decimale (2.5e-06). Un Excel impostato in italiano usa la virgola: se si apre il file con doppio clic, molti valori diventano testo o date. La procedura corretta:
- Dati → Da testo/CSV, scegliere il file;
- origine del file: UTF-8; delimitatore: Spazio, con «considera delimitatori consecutivi come uno solo»;
- in Trasforma dati (Power Query) eliminare le righe che iniziano con
#; - cambiare il tipo delle colonne con Usando impostazioni locali → Inglese (Stati Uniti), così il punto è letto come separatore decimale.
In LibreOffice Calc: Lingua → Inglese (USA) nella finestra di importazione testo, separatore spazio, «Unisci i delimitatori». Lo script monitor_report.py della sezione 7 evita il problema producendo un CSV con virgole come separatori di campo e punti come separatori decimali, che conviene importare con la stessa impostazione.
9. Checklist conclusiva e riferimenti
Prima di dichiarare affidabile un risultato: verifica che non vi siano errori fatali, che la mesh sia utilizzabile, che i campi e le BC abbiano unità coerenti, che i residui e gli indicatori numerici siano appropriati, che i bilanci siano soddisfacenti, che le grandezze di interesse siano stabili nel senso fisicamente corretto e che siano stati considerati gli effetti della discretizzazione.
Fonti tecniche primarie (OpenFOAM Foundation 14):
- OpenFOAM v14 — User Guide — struttura generale, solutori modulari e tutorial.
- 7.4 — Sampling and monitoring data —
foamGet,probes,residuals,foamMonitor. - 2.1 — Backward-facing step — esecuzione, log e criteri di arresto nel caso stazionario.
- API v14 — surfaceFieldValue — sintassi
patch, operazionisumeareaAverage. - API v14 — Function objects —
system/functionse controllo esecuzione/scrittura. - 7.3 — Post-processing functionality — catalogo e riferimenti alle quantità dimensionali.
- klogg — software facoltativo per consultare grandi log da Windows.
I grafici di questa guida sono schemi/dati sintetici a scopo didattico, non risultati CFD misurati. I frammenti di dizionario richiedono l’adattamento ai nomi, ai campi e alla geometria del proprio caso.
Altri riferimenti utili
- klogg — visualizzatore facoltativo per consultare grandi log da Windows.
Guide collegate: OpenFOAM su server Linux, lavorando da Windows (trasferimenti, SSH, tmux, ParaView) e il percorso Imparare OpenFOAM 14, in particolare controlDict e fvSolution.