OpenFOAM: verifica, validazione e indipendenza dalla mesh
Quarta guida operativa su OpenFOAM installato su un server Linux e usato da Windows, dopo quelle su server e trasferimenti, monitoraggio e convergenza e analisi quantitativa con ParaView. Questa risponde alla domanda che viene dopo: il risultato è abbastanza affidabile per rispondere a una domanda fisica? Riferimento: OpenFOAM Foundation 14.
OpenFOAM Foundation 14 · Windows + server Linux · Manuale operativo CFD
Obiettivo. Stabilire se il risultato di una simulazione è sufficientemente affidabile per rispondere a una domanda fisica. Questa guida sviluppa un protocollo replicabile con tre mesh, verifica dei bilanci, confronto con una soluzione analitica e stima indicativa dell’incertezza da discretizzazione. I risultati numerici dell’esercizio GCI sono sintetici: non provengono da un’esecuzione di OpenFOAM.
Prerequisiti. Saper accedere al server via SSH, trasferire file con FileZilla e modificare dizionari con Notepad++ (Guida 1); leggere residui e log (Guida 2); estrarre misure da ParaView client/server (Guida 3). Non è necessario Visual Studio Code. I richiami separati sono facoltativi per chi conosce già l’argomento.
1. Il significato di «risultato affidabile»
Una soluzione numerica può essere iterativamente convergente senza essere accurata; può essere quasi invariata passando da una mesh a un’altra, ma riprodurre il fenomeno fisico sbagliato; può rispettare il bilancio di massa e non prevedere correttamente la caduta di pressione. Occorre separare almeno quattro domande:
| Verifica | Domanda | Evidenza minima |
|---|---|---|
| Convergenza iterativa | Le equazioni discrete sono risolte abbastanza bene? | Residui + stabilità delle grandezze di interesse |
| Verifica spaziale | La risposta cambia raffinando la mesh? | Tre mesh comparabili e stima dell’errore |
| Verifica temporale | Il passo temporale influenza il risultato? | Studio su almeno tre deltaT, se transitorio |
| Validazione fisica | Il modello rappresenta l’esperimento o la soluzione nota? | Confronto documentato e incertezza dei dati |
La verifica riguarda in primo luogo la soluzione delle equazioni scelte; la validazione valuta se quelle equazioni, ipotesi e condizioni rappresentano il sistema reale, rispetto a dati adeguati. Non dire «modello validato» solo perché checkMesh riporta Mesh OK.

Richiamo — errori e incertezze. L’errore iterativo nasce dall’arresto del solver; l’errore di discretizzazione dalla rappresentazione spaziale e temporale; l’incertezza dei dati riguarda input, misure o modelli. Un indice di convergenza sulla griglia non include automaticamente questi altri contributi.
Approfondimento · Verifica del codice e verifica della soluzione
La letteratura sulla credibilità della CFD (Roache; Oberkampf e Roy; lo standard ASME V&V 20) distingue tre livelli:
- Verifica del codice: il programma risolve correttamente il modello matematico? Si controlla con soluzioni esatte o manufatte, misurando che l’errore diminuisca con l’ordine formale degli schemi. È il compito degli sviluppatori; l’utente lo riprende in piccolo con un caso a soluzione nota, come Poiseuille.
- Verifica della soluzione: quanto è grande l’errore numerico di questo calcolo? Convergenza iterativa, studio di mesh e di passo temporale, GCI. È il cuore di questa guida.
- Validazione: il modello rappresenta la realtà con l’accuratezza richiesta? Richiede dati di riferimento con la propria incertezza.
L’ordine conta: senza verifica della soluzione non si sa quanta parte della differenza con l’esperimento sia errore numerico, e la validazione diventa un confronto tra due numeri di origine ignota.
2. Definire prima la grandezza da verificare
Stabilire prima del calcolo la quantity of interest (QoI): ad esempio DeltaP tra due sezioni in Pa, portata in m³/s, velocità assiale in un punto, lunghezza di riattacco in m oppure un flusso di materia in mol/s. Ogni QoI richiede una procedura di estrazione invariata fra le mesh.
Compilare una scheda breve:
| Campo | Esempio controllabile |
|---|---|
| Oggetto | Canale 2D con profilo laminare completamente sviluppato |
| QoI principale | DeltaP = pA - pB tra due sezioni fisse |
| Condizione imposta | Portata o velocità media, non entrambe arbitrariamente |
| Unità | p cinematica o pressione Pa: verificare dimensions |
| Criterio dichiarato | Variazione di DeltaP fra due mesh più fini < 1% e analisi GCI attendibile |
| Confronto indipendente | Valore analitico, benchmark o dati sperimentali |
Il limite dell’1% è solo una soglia progettuale di esempio: non è uno standard generale. Per un risultato vicino a una soglia di sicurezza o per una derivata locale, la tolleranza può essere molto diversa.
Approfondimento · Grandezze integrali e grandezze locali convergono in modo diverso
Le grandezze integrali (portata, caduta di pressione media, forza su una parete) mediano gli errori locali e in genere convergono rapidamente e in modo regolare. Le grandezze locali, e soprattutto le derivate (tensione di parete, gradienti, flussi termici locali, posizione di un punto di riattacco), convergono più lentamente e spesso in modo non monotono, perché dipendono dalla risoluzione nella zona specifica e dall’interpolazione.
Conseguenza pratica: una mesh «indipendente» per ΔP può non esserlo per la tensione di parete. Lo studio va dichiarato per ogni QoI, non per la mesh in generale.
3. Congelare il modello: cambiare soltanto la discretizzazione
Lo studio di mesh non è interpretabile se fra i casi cambiano contemporaneamente geometria, condizioni al contorno, viscosità, proprietà del fluido, modello di turbolenza o definizione delle sezioni. Occorre una famiglia di mesh geometricamente coerenti, non tre modelli CAD differenti.
Creare tre directory distinte, senza sovrascrivere il caso di partenza:
# Terminale SSH sul server Linux; adattare il percorso
cd ~/cases
cp -a riferimento caso_M1_fine
cp -a riferimento caso_M2_media
cp -a riferimento caso_M3_grossa
# Conservare una fotografia dei parametri di ciascun caso
for c in caso_M1_fine caso_M2_media caso_M3_grossa; do
( cd "$c" && sha256sum system/controlDict system/fvSchemes system/fvSolution ) \
> "$c.input.sha256"
done
Il comando precedente copia l’intero caso, inclusi eventuali risultati: preferire un template pulito se disponibile, per non introdurre risultati vecchi. Su ognuna delle copie modificare solo il dizionario della mesh (oppure i parametri di generazione). Non eliminare in modo indiscriminato tempi o risultati.
Per una mesh 2D estrusa con una cella nello spessore, ad esempio, scegliere Nx × Ny × Nz pari a 20×10×1, 40×20×1, 80×40×1. A parità di geometria si ottengono idealmente 200, 800 e 3200 celle e un rapporto di raffinamento lineare r=2 tra mesh successive. Il numero delle celle aumenta di 4, non di 2.

3.1 Dimensione caratteristica h
Per mesh omogeneamente raffinate su un dominio fisico fisso, si può usare h ~ (V/N)^(1/d) con dimensione effettiva d: 2 per un caso realmente bidimensionale, 3 per un caso tridimensionale. Il volume V (o area nel 2D) deve rappresentare lo stesso dominio. In mesh 3D anisotrope con raffinamento non uniforme, un unico h ricavato dal numero di celle è solo un indicatore grossolano e non dimostra un rapporto di raffinamento omogeneo.
Approfondimento · Generare la famiglia di mesh con blockMesh o refineMesh
Con blockMesh si cambiano solo i numeri di celle nella voce blocks di system/blockMeshDict, raddoppiando le direzioni del piano e lasciando 1 cella nello spessore:
foamDictionary -entry blocks system/blockMeshDict # leggere la voce attuale
# grossa: hex (0 1 2 3 4 5 6 7) (20 10 1) simpleGrading (1 1 1)
# media: hex (0 1 2 3 4 5 6 7) (40 20 1) simpleGrading (1 1 1)
# fine: hex (0 1 2 3 4 5 6 7) (80 40 1) simpleGrading (1 1 1)
Con simpleGrading diverso da 1 il rapporto tra ultima e prima cella resta lo stesso a ogni livello: raddoppiando le celle, ogni cella si dimezza in modo approssimativamente uniforme e la famiglia rimane geometricamente simile, anche se il rapporto tra celle adiacenti cambia. La costruzione del grading è spiegata in Parte 2: blockMeshDict.
In alternativa refineMesh divide ogni cella in due lungo le direzioni indicate, producendo esattamente r = 2; nei casi 2D serve un system/refineMeshDict che escluda la direzione dello spessore. Per accorciare i calcoli sulle mesh fini si può inizializzare il campo dalla soluzione della mesh precedente:
cd ~/cases/caso_M2_media
mapFields ../caso_M3_grossa -consistent -sourceTime latestTime
L’inizializzazione cambia solo il punto di partenza delle iterazioni: la soluzione finale, se la convergenza iterativa è completa, non ne dipende.
Approfondimento · h calcolato sull’esempio
Per un dominio 2D di 0,100 × 0,010 m (area 1,0×10⁻³ m²): con 200 celle h = (1,0×10⁻³/200)^½ = 2,24 mm; con 800 celle 1,12 mm; con 3200 celle 0,559 mm. Il rapporto tra valori successivi è 2,00, coerente con il raddoppio delle celle in ciascuna direzione. Nel file per lo script si può usare h relativo (4, 2, 1): conta solo il rapporto.
4. Controlli su ciascuna mesh: qualità e coerenza
Usare OpenFOAM Foundation 14; verificare di aver caricato l’ambiente software nel terminale. Eseguire per ogni caso:
foamVersion
cd ~/cases/caso_M2_media
blockMesh > log.blockMesh 2>&1 # solo se questa mesh usa blockMesh
checkMesh -allGeometry -allTopology > log.checkMesh 2>&1
tail -n 35 log.checkMesh
Verificare: numero di celle, volumi positivi, topologia, non ortogonalità, skewness, zone con forte anisotropia e distribuzione locale del raffinamento. Mesh OK è una verifica di integrità, non una prova che la mesh sia abbastanza fine. Valori di qualità ammissibili dipendono dagli schemi numerici e dal problema; non adottare un limite universale per ogni caso.
Se si usa snappyHexMesh, documentare i layer vicino alla parete e l’eventuale variazione della geometria discretizzata. Un cambiamento di superficie bagnata, apertura o volume solido fra mesh può influenzare DeltaP in modo non riconducibile alla sola discretizzazione. Per turbolenza vicino a parete riportare y+ e la compatibilità con il wall treatment.
Approfondimento · Estrarre da checkMesh i numeri da confrontare
for c in caso_M1_fine caso_M2_media caso_M3_grossa; do
echo "== $c"
grep -E 'cells:|Max non-orthogonality|Max skewness|Max aspect ratio|Mesh OK|\*\*\*' $c/log.checkMesh
done
In una famiglia ben costruita il numero di celle scala come rd e gli indicatori di qualità restano simili o migliorano con il raffinamento. Se la mesh fine ha una non ortogonalità massima molto peggiore delle altre, la famiglia non è coerente: lo studio confronterebbe qualità di mesh diverse oltre che dimensioni diverse.
5. Lanciare e registrare tre simulazioni comparabili
Esempio generico per casi già completi e configurati, non un comando valido per qualsiasi directory:
cd ~/cases/caso_M1_fine
# Per OpenFOAM Foundation 14 il solver può essere scelto da system/controlDict
# Verificare solver, condizioni iniziali e modello prima dell'esecuzione.
foamRun > log.foamRun 2>&1
grep -E 'Time =|ExecutionTime|Solving for|continuity errors' log.foamRun | tail -n 30
Per lavori lunghi avviare il comando in una sessione tmux (Guida 1), e non chiudere la sessione che sta eseguendo il processo. Ripetere lo stesso protocollo sugli altri casi. Il file Allrun, se presente, potrebbe lanciare più comandi: leggerlo con less Allrun prima dell’esecuzione; non assumere che un qualunque Allrun sia innocuo o equivalente a foamRun.
Annotare hardware, versione foamVersion, revisione dei file, modello fisico, schemi di fvSchemes, solver lineari e tolleranze di fvSolution. Per un caso steady usare uno stato finale convergente; per un caso transitorio comparare lo stesso tempo fisico o le stesse statistiche temporali (non il medesimo numero di iterazioni).
5.1 Ridurre il disturbo iterativo
Prima di attribuire una differenza alla mesh, verificare che ciascuna QoI sia stabile rispetto a ulteriori iterazioni. Se DeltaP cambia ancora dello 0,8% proseguendo il calcolo e la differenza fra due mesh è 0,5%, lo studio di raffinamento non è interpretabile. Conservare un grafico di DeltaP in funzione delle iterazioni oltre al grafico dei residui.
Approfondimento · Quanto piccolo deve essere l’errore iterativo
Una regola pratica ricorrente nella letteratura sulla verifica (per esempio Roy, Oberkampf e il tutorial NASA sulla convergenza iterativa) è che l’errore iterativo sulla QoI sia almeno un ordine di grandezza più piccolo dell’errore di discretizzazione che si vuole stimare. Con le differenze del paragrafo precedente: se la mesh fine e la media differiscono dello 0,5%, la QoI della mesh fine deve essere stabile entro circa lo 0,05%.
Un modo concreto per stimarlo: prendere ΔP negli ultimi N passi e calcolarne la variazione relativa e la pendenza, come fa lo script di monitoraggio della guida 2. Se le tolleranze di residualControl fermano il calcolo prima di questo livello, vanno strette.
6. Misurare le stesse grandezze su tutte le mesh
Riutilizzare una procedura identica in ParaView (Guida 3) oppure function objects OpenFOAM. Per una caduta di pressione: due superfici fisicamente identiche a coordinate fissate; stessa definizione di media pesata sull’area; stesso istante e stesso sistema di unità.
Per il flusso incomprimibile con densità costante, se il campo p ha dimensioni [0 2 -2 0 0 0 0], rappresenta pressione cinematica: DeltaP[Pa] = rho[kg/m3] × Deltap[m2/s2]. Se il campo p ha già dimensioni di pressione, non moltiplicare per rho.
Una linea di campionamento e una sezione integrata non sono equivalenti. In una rete porosa è importante mantenere lo stesso piano fisico anche quando cambia l’intersezione fluida. Se il piano attraversa differenti porzioni di solido tra geometrie ricostruite, il confronto include differenze geometriche: riportarle separatamente.
6.1 Bilancio di massa
Per un fluido incomprimibile stazionario, a pareti impermeabili, Qin + Qout con flussi orientati verso l’esterno del dominio dovrebbe essere prossimo a zero. Per ingressi e uscite multipli sommare tutti i contributi e definire un indicatore, ad esempio:
epsilon_m = abs(sum(Qorientati)) / max(sum(Qentranti in valore assoluto), soglia_nonzero)
La soglia al denominatore serve a evitare la divisione per zero; va dichiarata. Per fluidi comprimibili usare le portate massiche, includendo eventuale accumulo; per flussi transitori il flusso netto istantaneo può non essere nullo. Controllare anche che le normali delle sezioni siano coerenti.
Approfondimento · Misurare portate e Δp con le function object
Il modo più ripetibile di misurare le stesse grandezze su tre mesh è affidarle a OpenFOAM durante il calcolo: le function object surfaceFieldValue su inlet e outlet (medie di p pesate sull’area e somme di phi) sono descritte nella guida 2, con uno script che calcola ΔP, ε_Q e la stabilità nell’ultima finestra. Copiando lo stesso system/functions nei tre casi la definizione della misura è identica per costruzione.
Per sezioni interne, non coincidenti con patch, la procedura ParaView della guida 3 (Slice, Integrate Variables) va salvata come stato o script e riapplicata senza modifiche.
7. Verifica con soluzione analitica: canale laminare
Per moto piano laminare completamente sviluppato, fluido newtoniano incomprimibile e due piastre parallele immobili, distanti H, la teoria fornisce:
u(y) = 6 * Umean * (y/H) * (1 - y/H)
DeltaP = 12 * mu * L * Umean / H^2
Con mu=0.001 Pa·s, H=0.010 m, L=0.100 m e Umean=0.020 m/s, il valore teorico è 0.240 Pa. Il profilo e il salto di pressione vanno valutati in un tratto dove le ipotesi di sviluppo sono soddisfatte; un ingresso uniforme in un canale corto può introdurre una regione di sviluppo e produrre differenze del tutto legittime. Non applicare questo riferimento a un condotto turbolento o a un canale 3D di rapporto d’aspetto limitato senza le dovute correzioni.

Esercizio A. Estrarre 21 o più valori di U_x lungo una sezione, confrontarli alla parabola nella stessa ascissa normalizzata y/H, calcolare RMSE, errore sul valore massimo e sul salto di pressione. In aggiunta eseguire una verifica della massa. I CSV nella cartella examples/ sono esempi analitici, non risultati CFD.
Richiamo — RMSE. RMSE = sqrt(mean((u_CFD - u_teoria)^2)). Il valore dipende dal modo di campionare il profilo e dal peso dei punti: registrare posizione, interpolazione e campionamento. Una RMSE piccola per un profilo non assicura che tutte le QoI siano accurate.
Approfondimento · Due scritture dello stesso profilo
Questa guida misura y dalla parete inferiore (0 ≤ y ≤ H); la guida 3 lo misura dall’asse (−H/2 ≤ y′ ≤ H/2). Con y = y′ + H/2 le due forme coincidono:
6 U (y/H)(1 − y/H) = 6 U (½ + y′/H)(½ − y′/H) = 6 U (¼ − y′²/H²) = 3/2 U [1 − (2y′/H)²]
Nel confrontare i CSV di ParaView conviene quindi controllare dove la mesh pone lo zero della coordinata trasversale: un errore di H/2 sposta tutta la parabola e produce una RMSE enorme che non ha nulla a che vedere con la soluzione numerica.
Per un controllo di ordine di grandezza dell’esercizio: Re = ρ U_media D_h / μ con D_h = 2H vale 400 con ρ = 1000 kg/m³, e la stima L_e ≈ 0,05 Re D_h dà circa 0,4 m: con questi dati il tratto di 0,100 m è sviluppato solo se l’ingresso impone già il profilo parabolico, oppure se il canale è preceduto da un tratto sufficiente.
8. Studio a tre mesh: ordine osservato, Richardson e GCI
Indichiamo con f1, f2, f3 la stessa grandezza calcolata sulla mesh rispettivamente fine, media, grossa; con h1<h2<h3 le dimensioni caratteristiche; r=h2/h1=h3/h2>1 per una famiglia a rapporto costante. Se la convergenza è monotona e approssimativamente asintotica, l’ordine osservato è:
p = ln(abs((f3-f2)/(f2-f1))) / ln(r)
L’estrapolazione di Richardson dalla coppia fine/media e l’indice GCI della griglia fine sono:
f_ext = f1 + (f1-f2)/(r^p-1)
GCI_12 = Fs * abs((f2-f1)/f1) / (r^p-1) * 100 [%]
GCI_23 = Fs * abs((f3-f2)/f2) / (r^p-1) * 100 [%]
Per uno studio con almeno tre griglie in regime asintotico, si usa spesso Fs=1.25. Non è una garanzia universale di copertura statistica. Un utile controllo di coerenza è GCI_23 / (r^p * GCI_12) vicino a 1, con la differenza tra denominatori f1 e f2 tenuta presente. L’ordine osservato può essere diverso dall’ordine formale dello schema e può essere fuorviante fuori dal regime asintotico.
| Mesh | Celle 2D | h relativo | DeltaP sintetico [Pa] |
|---|---|---|---|
| M3 grossa | 200 | 4 | 103.2 |
| M2 media | 800 | 2 | 100.8 |
| M1 fine | 3200 | 1 | 100.2 |
Si ricava r=2, p=2, f_ext=100.0 Pa, GCI_12≈0.2495% e GCI_23≈0.9921%. Il rapporto di controllo vale circa 0.994, compatibile con il comportamento asintotico per questo esempio costruito appositamente. Il valore estrapolato non è una misura sperimentale e non prova la correttezza del modello fisico.

Approfondimento · Il calcolo passo per passo
- Differenze:
f2 − f1 = 0,6,f3 − f2 = 2,4; stesso segno, quindi convergenza monotona. - Rapporto:
2,4/0,6 = 4;p = ln 4 / ln 2 = 2, uguale all’ordine formale di uno schema del secondo ordine. r^p − 1 = 3;f_ext = 100,2 + (100,2 − 100,8)/3 = 100,0.GCI_12 = 1,25 × (0,6/100,2) / 3 × 100 = 0,2495%;GCI_23 = 1,25 × (2,4/100,8) / 3 × 100 = 0,9921%.- Controllo:
0,9921 / (4 × 0,2495) = 0,994.
Le stesse formule in un foglio di calcolo, con f1, f2, f3 in B2:B4 e r in B5 (nella versione italiana di Excel i nomi delle funzioni sono LN e ASS):
p =LN(ASS((B4-B3)/(B3-B2)))/LN(B5)
f_ext =B2+(B2-B3)/(B5^p-1)
GCI12 =1,25*ASS((B3-B2)/B2)/(B5^p-1)*100
GCI23 =1,25*ASS((B4-B3)/B3)/(B5^p-1)*100
check =GCI23/(B5^p*GCI12)
Il fattore di sicurezza Fs proposto da Roache vale 3 per studi con due sole griglie e 1,25 con tre o più griglie e ordine osservato verificato: il valore più piccolo è il «premio» per aver dimostrato il regime asintotico.
8.1 Quando NON calcolare automaticamente un GCI
- I dati oscillano o le differenze
f3-f2ef2-f1hanno segno opposto: la formula semplice dipnon è applicabile. f2≈f1: arrotondamenti e rumore iterativo possono dominare il rapporto.- Il rapporto di raffinamento non è costante: occorre una formulazione più generale e una stima robusta di
h. - Cambiano geometria, strategia di layer,
y+, modello o condizioni al contorno. - La QoI contiene discontinuità, cambi di regime o punti sensibili a interpolazione/localizzazione.
Nel pacchetto lo script gci_three_grids.py calcola questi indici solo per tre mesh a rapporto uniforme e variazione monotona; negli altri casi segnala un blocco invece di inventare precisione.
Approfondimento · Rapporti non uniformi e convergenza oscillante
Con rapporti diversi r21 = h2/h1 e r32 = h3/h2, la procedura di Celik e coautori (Journal of Fluids Engineering, 2008) ricava p risolvendo per iterazione:
p = | ln|ε32/ε21| + q(p) | / ln r21, q(p) = ln[ (r21p − s) / (r32p − s) ], s = sign(ε32/ε21)
con ε21 = f2 − f1 ed ε32 = f3 − f2. Con r21 = r32 il termine q si annulla e si torna alla formula della guida. È uno dei motivi per cui una famiglia a rapporto costante semplifica tutto il resto.
Con convergenza oscillante (s < 0) non esiste un ordine osservato significativo. Una pratica conservativa diffusa è dichiarare come incertezza di discretizzazione l’ampiezza dell’oscillazione fra le tre mesh (massimo meno minimo), eventualmente aggiungendo una quarta mesh per capire se si entra nel regime asintotico.
Approfondimento · Lo script gci_three_grids.py
Script completo, solo libreria standard di Python (3.9 o successivo). Input: un CSV con colonne mesh,cells,h,qoi e righe fine, medium, coarse. Scrive results_gci.txt accanto al file di ingresso.
#!/usr/bin/env python3
"""Guide 04: deliberately conservative equal-ratio, monotonic 3-grid GCI.
Usage: python gci_three_grids.py results_three_grids.csv
Input columns: mesh,cells,h,qoi ; h must be a characteristic size for
geometrically equivalent meshes. The 'mesh' labels must include fine,
medium,coarse (case-insensitive); 'cells' is recorded, not used to infer h.
Generates results_gci.txt next to input. Standard library only, Python >=3.9.
GPL-3.0-or-later example, 2026.
"""
from __future__ import annotations
import csv, math, sys
from pathlib import Path
def calculate(rows):
required = {"fine", "medium", "coarse"}
if set(rows) != required:
raise ValueError("CSV must contain exactly fine, medium, coarse labels")
x = [rows[key] for key in ("fine", "medium", "coarse")]
for row in x:
if row['cells'] <= 0 or row['h'] <= 0:
raise ValueError("cells and h must be positive")
if not all(math.isfinite(row[z]) for z in ('cells', 'h', 'qoi')):
raise ValueError("All numerical values must be finite")
(f1, f2, f3) = (p['qoi'] for p in x)
(h1, h2, h3) = (p['h'] for p in x)
if not h1 < h2 < h3:
raise ValueError("Must have h(fine) < h(medium) < h(coarse)")
r12, r23 = h2/h1, h3/h2
if not math.isclose(r12, r23, rel_tol=0.002, abs_tol=0):
raise ValueError("Unequal refinement ratios: this simple GCI model does not apply")
r = (r12*r23)**0.5
d21, d32 = f2-f1, f3-f2
if d21 == 0 or d32 == 0:
raise ValueError("Zero QoI difference: observed order is indeterminate")
if d21*d32 <= 0:
raise ValueError("Oscillatory or non-monotonic convergence: no simple GCI")
if f1 == 0 or f2 == 0:
raise ValueError("Zero QoI denominator: relative GCI is undefined")
ratio = abs(d32/d21)
if ratio <= 1:
raise ValueError("No positive observed order: no defensible extrapolation")
p = math.log(ratio)/math.log(r)
denom = r**p - 1.0
if not (0 < p < 10) or denom <= 0 or not math.isfinite(denom):
raise ValueError("Observed order implausible / non-finite; inspect data")
fext = f1 + (f1-f2)/denom
fs = 1.25
gci12 = fs * abs((f2-f1)/f1) / denom * 100
gci23 = fs * abs((f3-f2)/f2) / denom * 100
asym = gci23/(r**p*gci12)
return dict(r=r,p=p,fext=fext,gci12=gci12,gci23=gci23,asym=asym,fs=fs,
f1=f1,f2=f2,f3=f3, h1=h1,h2=h2,h3=h3)
def read_csv(path):
out={}
with path.open(newline='',encoding='utf-8-sig') as f:
reader=csv.DictReader(f)
cols=set(reader.fieldnames or ())
if not {'mesh','cells','h','qoi'} <= cols:
raise ValueError("Required CSV columns: mesh,cells,h,qoi")
for row in reader:
label=row['mesh'].strip().lower()
if label in out:
raise ValueError(f"Duplicate mesh label: {label}")
out[label]={'cells':float(row['cells']), 'h':float(row['h']), 'qoi':float(row['qoi'])}
return out
def report(a, path):
return f'''OpenFOAM Guide 04 -- 3-grid GCI (training utility)
Input: {path.name}
Assumptions: identical geometry/physics/measurement, uniform refinement,
monotonic asymptotic convergence, negligible iterative noise.
Fine/medium/coarse QoI: {a['f1']:.10g} / {a['f2']:.10g} / {a['f3']:.10g}
Characteristic sizes h: {a['h1']:.10g} / {a['h2']:.10g} / {a['h3']:.10g}
Refinement ratio r: {a['r']:.8f}
Observed order p: {a['p']:.8f}
Richardson estimate f(h=0): {a['fext']:.10f} [input QoI unit]
Fine-grid GCI12: {a['gci12']:.6f} %
Medium-grid GCI23: {a['gci23']:.6f} %
Asymptotic indicator: {a['asym']:.6f} (near 1 expected)
Safety factor Fs: {a['fs']:.2f}
CAUTION: GCI is not a total uncertainty budget, does not validate physics,
and is not a confidence interval. Inspect logs and all assumptions.
'''
def main(argv):
if len(argv)!=2:
print(__doc__,file=sys.stderr)
return 2
path=Path(argv[1])
try:
a=calculate(read_csv(path))
text=report(a,path)
out=path.with_name('results_gci.txt')
out.write_text(text,encoding='utf-8')
print(text)
print(f'Written: {out}')
return 0
except (ValueError, OSError, KeyError, OverflowError) as ex:
print(f'GCI NOT COMPUTED: {ex}',file=sys.stderr)
return 1
if __name__=='__main__':
sys.exit(main(sys.argv))
Il file di prova results_three_grids.csv contiene i dati della tabella sopra; il risultato atteso è:
Refinement ratio r: 2.00000000
Observed order p: 2.00000000
Richardson estimate f(h=0): 100.0000000000 [input QoI unit]
Fine-grid GCI12: 0.249501 %
Medium-grid GCI23: 0.992063 %
Asymptotic indicator: 0.994048 (near 1 expected)
Safety factor Fs: 1.25
9. Studio temporale: deltaT non è la mesh
Per problemi non stazionari, anche una mesh spazialmente convergente può mostrare differenze legate a deltaT. A mesh e modello fissi, ripetere con deltaT, deltaT/2, deltaT/4 e confrontare la stessa QoI a tempi fisici identici, dopo lo stesso transitorio iniziale. Per segnali periodici confrontare frequenza, ampiezza, fase e statistiche calcolate sulla stessa finestra fisica.
Non confondere Co (Courant) con una prova di accuratezza. Un calcolo stabile a Courant basso può essere inaccurato se gli schemi temporali sono troppo dissipativi o il segnale non è ben risolto. Se si raffina la mesh senza modificare deltaT, l’errore temporale può impedire di osservare l’ordine spaziale.
Approfondimento · Come impostare lo studio del passo in OpenFOAM
- Con passo fisso (
adjustTimeStep no) si cambia solodeltaTincontrolDicte si mantienewriteControl adjustableRunTimeorunTime, così i tempi scritti coincidono fra i tre casi. - Con passo adattivo il parametro da dimezzare è
maxCo: il passo effettivo varia nel tempo e il rapporto fra i passi non è esattamente 2; lo si legge dal log. - Con PIMPLE, fissare anche
nOuterCorrectorse le tolleranzeFinal: ogni passo deve essere iterativamente convergente, altrimenti lo studio misura l’errore di disaccoppiamento e non quello temporale. - Le stesse formule dell’ordine osservato e del GCI si applicano sostituendo h con Δt, purché il segnale confrontato sia lo stesso istante fisico o la stessa statistica.
Le voci del controllo temporale sono spiegate in Parte 4: controlDict, gli algoritmi PIMPLE in Parte 6.
10. Verifica dei risultati fisici e delle ipotesi
Eseguire almeno tre controlli indipendenti prima di confrontare una previsione con misure di laboratorio:
- Bilanci. Massa, e dove pertinenti energia/specie, integrando tutti i flussi entranti/uscenti e i termini sorgente/accumulo.
- Sensibilità alle condizioni al contorno. Variare realisticamente una proprietà o un dato di ingresso (es. viscosità o portata) mantenendo fissa la mesh convergente. Registrare la risposta della QoI.
- Confronto con una fonte indipendente. Valore analitico, benchmark verificato o misura sperimentale accompagnata da incertezza, geometria, procedure e condizioni di prova.
Se la misura di laboratorio è DeltaP_exp = 101.0 ± 2.0 Pa (esempio fittizio) e il CFD extrapolato fornisce 100.0 Pa, la vicinanza numerica non basta per dichiarare validazione: occorre conoscere che cosa rappresenta il ±2.0, e considerare modello fisico, input, geometria ed errore numerico. Non combinare contributi incerti con una somma quadratica senza una motivazione statistica e senza verificare le correlazioni.
Approfondimento · Il confronto nello standard ASME V&V 20
Lo standard ASME V&V 20 (verifica e validazione in fluidodinamica e scambio termico) formalizza il confronto così: errore di confronto E = S − D, differenza fra simulazione e dato; incertezza di validazione u_val, che combina incertezza numerica, incertezza degli input della simulazione e incertezza sperimentale. La combinazione in quadratura u_val = √(u_num² + u_input² + u_D²) presuppone che i tre contributi siano indipendenti: è esattamente la condizione che la guida chiede di verificare prima di usarla.
Se |E| è dello stesso ordine di u_val, l’errore di modello non si distingue dal «rumore» delle incertezze; se |E| è molto maggiore, c’è un errore di modello di circa E. Nell’esempio fittizio E = −1,0 Pa: senza conoscere u_val non si può dire nulla di più.
10.1 Geometrie CFD ricostruite da immagini
Quando la forma deriva da immagini SEM, scanner o digitalizzazioni, trattare a parte l’incertezza della ricostruzione geometrica: spessore, curvature, aperture e posizione dei contorni. Una mesh sempre più fine non recupera automaticamente la geometria reale. Ripetere il calcolo su ipotesi geometriche plausibili è uno studio di sensibilità geometrica, non uno studio di convergenza di mesh.
11. Laboratorio guidato: un protocollo riutilizzabile
Esercizio B — verifica spaziale. Utilizzare un caso di canale 2D già funzionante; produrre tre griglie dello stesso dominio; avviare OpenFOAM sui tre casi; verificare residui e bilanci; estrarre DeltaP in due piani fissi; scrivere results_three_grids.csv e aprirlo sul PC Windows.
Il file d’esempio incluso contiene dati sintetici:
mesh,cells,h,qoi
fine,3200,1.0,100.2
medium,800,2.0,100.8
coarse,200,4.0,103.2
Da PowerShell in Windows, con Python opzionale installato localmente:
py -3 gci_three_grids.py results_three_grids.csv
L’analizzatore rifiuta un ordine non finito, rapporti h diversi o dati non monotoni. Non sostituisce la revisione dei log e delle ipotesi. Chi non vuole Python può ricostruire le formule in un foglio elettronico, registrando i passaggi e le cifre significative.
Esercizio C — sensitività. A mesh fine già convergente, modificare del +5% e -5% una sola grandezza di ingresso fisicamente incerta; mantenere fissi tutti gli altri parametri; misurare la risposta di DeltaP. Etichettare la variazione come sensibilità all’input, non errore di discretizzazione.

Approfondimento · Che cosa aspettarsi nell’esercizio C per un canale laminare
Per il flusso di Poiseuille ΔP = 12 μ L U / H² è lineare in μ e in U: ±5% di viscosità o di velocità media danno ±5% di ΔP; ±5% di H dà circa ∓10%, perché ΔP dipende da 1/H² (a velocità media fissata). Se la simulazione restituisce sensibilità molto diverse da queste, la QoI misurata include altri effetti (regione di sviluppo, sezioni di misura mal posizionate) da capire prima di procedere.
Il coefficiente di sensibilità normalizzato S = (ΔQoI/QoI)/(Δx/x) riassume la risposta in un numero: 1 per μ e U, circa −2 per H in questo caso.
12. Organizzare i file fra Linux e Windows
Conservare sul server i casi originali e trasferire su Windows solo ciò che serve alla revisione e alla pubblicazione:
CFD_Study_04/
case_M1_fine/ # casi e log sul server
case_M2_medium/
case_M3_coarse/
review_windows/
results_three_grids.csv
results_gci.txt
log.checkMesh_M1.txt
log.foamRun_M1.txt
figures/
verification_report.md
FileZilla: usare SFTP, scaricare CSV/log e annotare la data e la provenienza; Notepad++: visualizzare dizionari e differenze senza modificare copie già pubblicate; ParaView: salvare stati .pvsm e riferimenti ai percorsi del server. Ricordare che uno stato ParaView può contenere percorsi assoluti non validi altrove. Riportare nel rapporto gli hash e le versioni rilevanti.
Approfondimento · La scheda di verifica e validazione
Modello bilingue da compilare per ogni studio (Markdown, apribile con Notepad++):
# CFD Verification and Validation Record / Scheda di verifica e validazione
## Identification / Identificazione
- Date / Data:
- Operator / Operatore:
- OpenFOAM edition + version / Edizione e versione:
- Case path(s) on Linux server / Percorsi dei casi Linux:
- Windows review directory / Cartella di revisione Windows:
- Input revision or hash / Revisione o hash degli input:
## Physical problem / Problema fisico
- Geometry definition and source / Geometria e origine:
- Boundary and initial conditions / Condizioni al contorno e iniziali:
- Models, properties, units / Modelli, proprietà, unità:
- QoI(s) and measurement protocol / QoI e procedura di misura:
- Acceptance threshold and reason / Soglia accettazione e motivazione:
## Mesh family / Famiglia di mesh
| Grid | Cells | h | r | Worst relevant quality indicator | QoI |
|---|---:|---:|---:|---|---:|
| Fine | | | | | |
| Medium | | | | | |
| Coarse | | | | | |
## Iterative and conservation checks / Convergenza iterativa e bilanci
- Residual and QoI trends / Residui e trend delle QoI:
- Mass imbalance definition + value / Definizione e valore sbilancio massa:
- Time-step verification (if transient) / Studio deltaT (se transitorio):
## Mesh result / Esito di raffinamento
- Observed p / Ordine osservato:
- Richardson extrapolation / Estrapolazione:
- Fine-grid GCI [%]:
- Asymptotic consistency indicator / Indicatore asintotico:
- Non-monotonic / non-asymptotic issues / Eventuali problemi:
## Physical comparisons / Confronti fisici
- Benchmark or experiment and uncertainty / Benchmark o esperimento e incertezza:
- Input and geometry sensitivities / Sensibilità di input e geometria:
- Limitations / Limiti di validità:
## Conclusions / Conclusioni
- Suitability for intended use / Adeguatezza per lo scopo:
- Recommended additional work / Ulteriori verifiche necessarie:
13. Checklist di accettazione e interpretazione
| Domanda | Evidenza da allegare | Stato |
|---|---|---|
| Le tre mesh rappresentano la stessa geometria? | dimensioni, volumi/superfici e criteri di generazione | □ |
| La qualità è documentata? | tre checkMesh, dettagli vicino alle pareti | □ |
| Le tre soluzioni sono iterativamente stabili? | log, residui e QoI in funzione delle iterazioni | □ |
| Le QoI sono misurate nello stesso modo? | sezioni, medie, tempi e unità | □ |
| Il bilancio di massa è accettabile? | flussi orientati e relativo squilibrio | □ |
| Il raffinamento è monotono e asintotico? | tabella h–QoI, p, GCI e limiti del metodo | □ |
| Il tempo è sufficientemente risolto? | confronto deltaT se non stazionario | □ |
| I dati fisici di confronto hanno incertezza? | fonte, metodi, condizioni, intervallo | □ |
| La conclusione dichiara le limitazioni? | ipotesi, errore geometrico e di modello | □ |
Esempio di formulazione corretta. «Nel dominio e alle condizioni specificate, la stima GCI della caduta di pressione sulla mesh fine è 0,25%, sotto le ipotesi di raffinamento uniforme e regime asintotico; questo dato non comprende le incertezze sulla geometria, sulle condizioni al contorno e sul modello fisico.»
14. Fonti primarie e approfondimenti
- OpenFOAM Foundation 14, User Guide: https://doc.cfd.direct/openfoam/user-guide/
- OpenFOAM Foundation 14, Applications and libraries / foamRun: https://doc.cfd.direct/openfoam/user-guide-v14/applications
- OpenFOAM Foundation 14, Post-processing functionality: https://doc.cfd.direct/openfoam/user-guide-v14/post-processing-functionality
- OpenFOAM 14, sorgente del controllo mesh: https://github.com/OpenFOAM/OpenFOAM-14/blob/master/src/functionObjects/utilities/checkMesh/checkMesh.H
- NASA Glenn / NPARC, Examining Spatial (Grid) Convergence: https://www.grc.nasa.gov/www/wind/valid/tutorial/spatconv.html
- NASA Glenn / NPARC, Examining Iterative Convergence: https://www.grc.nasa.gov/WWW/wind/valid/tutorial/iterconv.html
- NASA Glenn / NPARC, Verification and Validation Tutorial: https://www.grc.nasa.gov/www/wind/valid/tutorial/tutorial.html
- NASA Glenn / NPARC, Examining Temporal Convergence: https://www.grc.nasa.gov/www/wind/valid/tutorial/tempconv.html
- NASA, D. P. Lockard (2010), In search of grid converged solutions: https://ntrs.nasa.gov/api/citations/20100027422/downloads/20100027422.pdf
Ambito e limiti. Il pacchetto include dati costruiti per esercitarsi e grafici originali illustrativi. Le procedure OpenFOAM sono adattabili a un caso già configurato. L’incertezza GCI è condizionata alle sue ipotesi; non equivale a probabilità di correttezza del risultato né a validazione sperimentale.
Guide collegate: server Linux da Windows, monitoraggio e convergenza, ParaView per l’analisi quantitativa e il percorso Imparare OpenFOAM 14, in particolare il caso 02: studio di convergenza della mesh.