OpenFOAM 14, parte 6: fvSolution, solutori lineari e algoritmi di soluzione
Parte 6 di 8 della serie sulla costruzione del caso nel percorso Imparare OpenFOAM 14. La Parte 5 ha mostrato come system/fvSchemes traduce le derivate delle equazioni di bilancio in operatori discreti; questa parte si occupa di ciò che succede dopo la discretizzazione: come ogni sistema algebrico viene risolto e come le equazioni di pressione e velocità vengono accoppiate, cioè del file system/fvSolution.
fvSolution: solutori lineari e algoritmi di soluzione. Il percorso è sempre lo stesso: concetto → dizionario → conseguenze numeriche → esercizio. Ogni riquadro «Approfondimento» espande un punto con la matematica che sta sotto, il modo in cui OpenFOAM Foundation 14 lo implementa, le alternative, gli errori tipici e i controlli pratici.

fvSchemes assembla la matrice A e il termine noto b, fvSolution stabilisce come risolvere ciascun sistema e come accoppiare le equazioni, foamRun (con il modulo scelto) itera i campi nel tempo o fino alla convergenza.Prerequisiti. Questa parte viene dopo i primi sette esercizi CFD del corso (il flusso di lavoro in sette passi applicato nei casi pratici, a partire dal flusso laminare in canale con validazione di Poiseuille) e dopo la Parte 5 sugli schemi numerici. Piattaforma: OpenFOAM Foundation 14.
Prima di iniziare: patto di apprendimento
L’obiettivo è leggere, giustificare, ispezionare e modificare system/fvSolution senza confondere le impostazioni dei solutori lineari con la discretizzazione, con i modelli fisici o con il controllo del tempo di simulazione.
Che cosa dovresti saper fare alla fine
- Tradurre un’equazione ai volumi finiti nell’idea di un sistema algebrico sparso A x = b.
- Individuare il solutore lineare e le impostazioni di convergenza usate per
p,Ue per gli eventuali campi dei modelli. - Distinguere
tolerance,relTol,maxIter, gli obiettivi sui residui esterni e la convergenza fisica. - Spiegare lo scopo di SIMPLE, PIMPLE, dei correttori di pressione e del rilassamento.
- Usare la User Guide di OpenFOAM Foundation v14 e i file dei tutorial per giustificare una modifica.
Versione · La versione conta
Gli esempi usano OpenFOAM Foundation v14, dove foamRun carica moduli come incompressibleFluid. Le guide più vecchie che parlano di simpleFoam o pimpleFoam vanno interpretate con attenzione alla versione.
Approfondimento · Da simpleFoam e pimpleFoam a foamRun: che cosa è cambiato davvero
Fino alla versione 10 della distribuzione Foundation ogni combinazione di fisica e algoritmo aveva un eseguibile dedicato: simpleFoam per i flussi incomprimibili stazionari con SIMPLE, pisoFoam e pimpleFoam per quelli transitori. Dalla versione 11 questi eseguibili sono stati sostituiti da moduli solutore caricati da un unico programma, foamRun; il modulo si sceglie in system/controlDict con la voce solver incompressibleFluid; (oppure con foamRun -solver incompressibleFluid).
La conseguenza per fvSolution è importante: in v14 non è più il nome dell’eseguibile a dire se l’algoritmo è SIMPLE o PIMPLE. Lo stesso modulo incompressibleFluid gestisce entrambi i casi: il comportamento stazionario si ottiene dichiarando ddtSchemes { default steadyState; } in fvSchemes e scrivendo un sotto-dizionario SIMPLE in fvSolution, come nel tutorial pitzDailySteady della guida v14. Le voci dei solutori lineari (solvers), invece, sono rimaste sostanzialmente le stesse: per questo un vecchio fvSolution è spesso ancora leggibile, ma il suo contesto (eseguibile, file dei modelli, nomi delle dimensioni) va verificato.
foamToC -solvers # list the solver modules available to foamRun
foamInfo incompressibleFluid
foamDictionary -entry solver -value system/controlDict
Prima di cominciare
Dovresti già avere una copia funzionante del canale di riferimento, una conoscenza di base di 0/U, 0/p (Parte 3) e controlDict (Parte 4) e la capacità di ispezionare fvSchemes (Parte 5). Gli esperimenti vanno eseguiti su copie, mai sulla simulazione di riferimento.
Ambito
Questa unità insegna la configurazione e la sua interpretazione. Non sostiene che un residuo basso dimostri un risultato CFD fisicamente accurato. Restano necessari controlli indipendenti della conservazione, delle condizioni al contorno e degli effetti della mesh.
1. Architettura del caso: dove si colloca fvSolution
OpenFOAM separa i passaggi fisici, di discretizzazione e di algebra lineare di un caso CFD.

0/ contiene campi iniziali e condizioni al contorno, constant/ la mesh e i modelli fisici, system/ la numerica e il controllo dell’esecuzione. fvSolution vive in system/.| File | Che cosa controlla | Che cosa non controlla |
|---|---|---|
system/fvSchemes | Approssimazione degli operatori differenziali | Il tipo di solutore della matrice |
system/fvSolution | Solutori lineari, tolleranze, cicli di accoppiamento | Dimensioni della mesh o velocità di ingresso |
system/controlDict | Tempo, durata dell’esecuzione e scrittura dei risultati | Il precondizionatore del solutore della pressione |
constant/* | Proprietà del fluido e modelli attivi | Le tolleranze sui residui delle equazioni |
0/U, 0/p | Valori iniziali e al contorno | Il numero di iterazioni SIMPLE |
La domanda a cui risponde questa parte
Una volta discretizzate le equazioni, quale algoritmo calcola una soluzione per ciascun campo, con quale accuratezza viene risolto ogni sistema algebrico, e come si coordinano tra loro gli aggiornamenti di pressione e velocità?
Importante · Trappola di vocabolario
La parola solver (solutore) ha due livelli: incompressibleFluid è un modulo solutore per fluidi; GAMG e smoothSolver sono solutori di algebra lineare configurati in fvSolution.
Approfondimento · Che cosa contiene fvSolution e quando viene letto
Secondo la User Guide v14 (§4.6), fvSolution contiene un sotto-dizionario solvers con le impostazioni del solutore lineare di ciascuna equazione, un sotto-dizionario relaxationFactors e un sotto-dizionario di controllo dell’algoritmo, SIMPLE per i casi stazionari oppure PIMPLE per quelli transitori. Altri moduli possono leggere ulteriori voci (per esempio i moduli multifase leggono controlli specifici per la frazione di fase), ma per incompressibleFluid questi tre blocchi sono tutto ciò che serve.
Il file non viene letto una sola volta. Le impostazioni di un solutore lineare vengono cercate nel dizionario solvers ogni volta che un’equazione viene risolta, e con runTimeModifiable attivo (il comportamento abituale, vedi Parte 4) OpenFOAM rilegge i file di system/ quando vengono modificati durante l’esecuzione. Si può quindi, per esempio, abbassare un fattore di rilassamento mentre il calcolo gira; la modifica ha effetto all’iterazione successiva e il log lo segnala con una riga che indica la rilettura del dizionario. È comodo, ma rende meno riproducibile la cronologia della simulazione: annota sempre la modifica e il tempo in cui l’hai fatta.
Errore tipico: se manca il blocco di un campo che il modulo deve risolvere, l’esecuzione si ferma con un FOAM FATAL IO ERROR del tipo «keyword p is undefined in dictionary .../system/fvSolution/solvers». Il messaggio indica sia il nome cercato sia il percorso del dizionario: è la prima cosa da leggere.
2. Quadro numerico: dalla PDE ad A x = b
Una volta scelti gli schemi numerici, ogni equazione discretizzata viene assemblata in un sistema algebrico.

fvSchemes in operatori discreti e flussi alle facce; fvSolution governa la soluzione lineare e l’accoppiamento tra le equazioni.Un’equazione schematica di cella ai volumi finiti
Equazione schematica dei coefficienti
aP * phiP + sum(aN * phiN) = bP
Assemblando insieme tutte le celle, i valori incogniti si possono scrivere come un vettore x; i coefficienti formano la matrice A, di norma sparsa, e i contributi noti formano b. Quindi A x = b.
Un caso incomprimibile reale non risolve tutte le equazioni di governo come un’unica, gigantesca matrice completamente accoppiata. L’approccio comune, detto segregato, risolve le equazioni un campo alla volta e usa un algoritmo esterno per mantenere l’accoppiamento pressione–velocità.
Richiamo CFD facoltativo · Matrice sparsa
Una matrice è sparsa quando la maggior parte dei suoi elementi è nulla. Una cella ai volumi finiti interagisce soprattutto con le celle vicine, quindi memorizzare e risolvere la matrice densa completa sprecherebbe memoria e calcolo.
Approfondimento · Un esempio numerico: tre celle, una matrice 3 × 3
Consideriamo la diffusione stazionaria monodimensionale d/dx(Γ dφ/dx) = 0 su un segmento lungo 3 diviso in tre celle uguali (Δx = 1, Γ = 1), con φ = 1 al contorno sinistro e φ = 0 al contorno destro. Integrando sulla cella P e approssimando il flusso diffusivo su ciascuna faccia con la differenza tra i centri, Γ(φN − φP)/d, si ottiene un’equazione per cella. Per una faccia interna d = Δx = 1 e il coefficiente vale 1; per una faccia di contorno il centro della cella dista d = Δx/2 dalla faccia e il coefficiente vale 2.
cell 1: 3*phi1 - 1*phi2 = 2 (2 = 2*1, from the left boundary value)
cell 2: -1*phi1 + 2*phi2 - 1*phi3 = 0
cell 3: -1*phi2 + 3*phi3 = 0 (right boundary value is 0)
| 3 -1 0 | | 2 |
A = |-1 2 -1 | b = | 0 | x = (5/6, 1/2, 1/6)
| 0 -1 3 | | 0 |
La soluzione, x = (0,833; 0,5; 0,167), coincide con il profilo lineare esatto 1 − x/3 valutato nei centri delle celle (0,5; 1,5; 2,5). Nella notazione usata qui, aP è il termine diagonale (3, 2, 3), gli aN sono i coefficienti fuori diagonale (−1) e bP raccoglie i contributi noti, qui i valori al contorno. Il valore assoluto della diagonale è maggiore o uguale alla somma dei valori assoluti fuori diagonale in ogni riga: la matrice è diagonalmente dominante, ed è simmetrica perché il coefficiente che lega P a N è lo stesso che lega N a P. Con un milione di celle esaedriche la struttura è identica: ogni riga ha un elemento diagonale più uno per ciascuna faccia interna della cella (al massimo sei), quindi circa 7 milioni di elementi non nulli contro i 1012 di una matrice densa.
Approfondimento · Come OpenFOAM memorizza la matrice: il formato LDU
OpenFOAM non usa un formato sparso generico (come CSR), ma il formato LDU della classe lduMatrix, costruito direttamente sulla topologia della mesh: un vettore diag con un valore per cella, un vettore upper e un vettore lower con un valore per ogni faccia interna. Ogni faccia interna ha una cella owner (proprietaria, indice minore) e una cella neighbour (vicina): il coefficiente upper della faccia sta nella riga dell’owner e nella colonna del neighbour, il coefficiente lower nella posizione trasposta. Se la matrice è simmetrica, lower non viene nemmeno allocato.
Le facce di contorno non generano elementi fuori diagonale: la condizione al contorno (Parte 3) contribuisce con una parte implicita alla diagonale e con una parte esplicita al termine noto b. Per questo un fixedValue rafforza la diagonale della cella adiacente (come il 3 nell’esempio a tre celle), mentre un zeroGradient non aggiunge nulla. Le patch di processore nei calcoli paralleli (vedi il caso pratico sul calcolo parallelo MPI) sono trattate come «interfacce» che scambiano i valori tra sottodomini a ogni prodotto matrice-vettore: è il motivo per cui il numero di iterazioni di un solutore lineare può cambiare leggermente con il numero di processori.
Verifica di previsione
Se in fvSchemes cambia soltanto div(phi,U), la matrice assemblata può cambiare anche se l’algoritmo e le voci dei solutori in fvSolution restano identici. Viceversa, sostituire GAMG con un altro solutore lineare valido non ridefinisce la PDE sottostante.
Approfondimento · Che cosa cambia davvero, in A o in b, quando si cambia uno schema
Il «può» della verifica di previsione è preciso. In OpenFOAM molti schemi di ordine superiore sono implementati come correzione differita: la parte implicita, che finisce nella matrice, è quella dello schema upwind, mentre la differenza tra lo schema scelto e l’upwind viene calcolata con i valori correnti ed entra nel termine noto b. È il caso di linearUpwind: passando da bounded Gauss upwind a bounded Gauss linearUpwind grad(U) la matrice A dell’equazione della quantità di moto resta strutturalmente quella dell’upwind e cambia soprattutto b. Passando invece a Gauss linear (differenze centrate) cambiano i pesi di interpolazione e quindi i coefficienti di A: la dominanza diagonale si indebolisce e i solutori iterativi possono richiedere più iterazioni o diventare instabili su mesh grossolane.
Il secondo enunciato vale in entrambe le direzioni: un solutore lineare diverso, se converge alla stessa tolleranza, produce la stessa soluzione discreta a meno dell’errore algebrico residuo. Se cambiando solo il solutore lineare cambia in modo apprezzabile il risultato finale (per esempio la caduta di pressione), le tolleranze erano troppo larghe: è un test utile per verificarlo.
3. Struttura del dizionario: dentro il dizionario solvers
Il primo sotto-dizionario importante associa ai nomi dei campi le impostazioni di algebra lineare.
Estratto didattico: system/fvSolution
solvers
{
p
{
solver GAMG;
tolerance 1e-7;
relTol 0.01;
smoother DICGaussSeidel;
}
U
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-5;
relTol 0.1;
}
}
| Voce | Interpretazione |
|---|---|
p / U | Campo di cui si risolve il sistema lineare discreto |
solver | Metodo iterativo di algebra lineare scelto |
tolerance | Soglia assoluta di arresto per il residuo |
relTol | Riduzione del residuo richiesta rispetto al valore iniziale |
smoother | Operazione iterativa locale, richiesta da alcuni metodi |
Attenzione · Valori di esempio
I numeri mostrati illustrano la sintassi e uno schema comune nei tutorial; non sono tolleranze raccomandate per ogni mesh e ogni modello.
Approfondimento · Tutte le voci che un blocco di solutore lineare può contenere
La tabella qui sopra elenca le voci essenziali. La User Guide v14 ne documenta altre, con i relativi valori predefiniti:
| Voce | Ruolo | Predefinito / note |
|---|---|---|
solver | Metodo: PCG, PBiCG, PBiCGStab, smoothSolver, GAMG, diagonal | obbligatoria |
tolerance | Soglia assoluta sul residuo normalizzato | da specificare (la guida la indica come richiesta) |
relTol | Rapporto residuo finale / iniziale | da specificare (la guida la indica come richiesta) |
maxIter | Numero massimo di iterazioni | 1000 |
preconditioner | Per PCG, PBiCG, PBiCGStab | DIC/DILU, FDIC, GAMG, diagonal, none |
smoother | Per smoothSolver e GAMG | GaussSeidel, symGaussSeidel, DIC/DILU, DICGaussSeidel |
nSweeps | Passate dello smoother prima di ricalcolare il residuo (smoothSolver) | 1 |
Il solutore diagonal serve per le equazioni esplicite, la cui matrice è solo diagonale: non itera e non usa tolleranze. Per vedere quali nomi accetta la tua installazione si può provocare di proposito un errore su una copia (per esempio solver xyz;): OpenFOAM risponde con l’elenco dei solutori validi per quel tipo di matrice. Per controllare che cosa il modulo leggerà davvero dopo l’espansione delle macro, usa foamDictionary -expand -entry solvers system/fvSolution.
4. Configurazione transitoria: leggere un estratto completo in stile v14
Questo estratto segue la struttura illustrata nella descrizione ufficiale v14 di un caso transitorio con incompressibleFluid.
Schema illustrativo da tutorial v14
solvers
{
p
{
solver GAMG;
tolerance 1e-7;
relTol 0.01;
smoother DICGaussSeidel;
}
pFinal
{
$p;
relTol 0;
}
"(U|k|epsilon)"
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-5;
relTol 0.1;
}
"(U|k|epsilon)Final"
{
$U;
relTol 0;
}
}
PIMPLE
{
nNonOrthogonalCorrectors 0;
nCorrectors 2;
}
Leggilo come uno schema riutilizzabile, non come un caso completo a sé stante: devono esistere anche i campi, la mesh, le proprietà, gli schemi e i controlli di esecuzione appropriati. Il gruppo con l’espressione regolare copre i campi di turbolenza solo quando sono presenti e usati dal modello scelto.
Approfondimento · Come OpenFOAM sceglie il blocco giusto: nomi esatti, regex e macro $
Quando il modulo deve risolvere, per esempio, l’equazione di k, cerca la voce k nel dizionario solvers con questa precedenza: prima una chiave con il nome esatto; se non c’è, le chiavi tra virgolette che sono espressioni regolari, esaminate dall’ultima alla prima nell’ordine del file. L’espressione deve corrispondere al nome per intero: "(U|k|epsilon)" corrisponde a k ma non a kFinal, ed è per questo che serve il secondo gruppo "(U|k|epsilon)Final".
La macro $p; copia nel blocco corrente tutte le voci del blocco p; le voci scritte dopo la macro le sovrascrivono (qui relTol 0;). Anche $U; funziona sebbene non esista una chiave letterale U: la ricerca della macro accetta le chiavi regex, quindi trova "(U|k|epsilon)". Il risultato espanso si controlla così:
foamDictionary -expand -entry solvers/pFinal system/fvSolution
foamDictionary -expand -entry solvers system/fvSolution # whole block, macros expanded
Nel blocco PIMPLE di questo estratto nOuterCorrectors non compare: vale il predefinito 1, cioè la modalità «PISO» (un solo passaggio esterno per passo temporale con due correzioni di pressione), adatta quando il numero di Courant resta sotto 1. In un caso laminare come il canale di riferimento k ed epsilon non esistono: il gruppo regex è innocuo ma inutile, e conviene ridurlo a U e UFinal.
5. Residui e arresto: tre controlli di convergenza diversi
Le impostazioni tolerance, relTol e maxIter governano l’arresto di una singola soluzione lineare.
| Criterio | Idea matematica | Significato |
|---|---|---|
tolerance | rfinal < T | Si ferma sotto una soglia di residuo |
relTol | rfinal / rinitial < R | Si ferma dopo una riduzione relativa sufficiente |
maxIter | N raggiunge il limite | Si ferma se si raggiunge il tetto di iterazioni |
Un solutore lineare iterativo in generale si ferma quando viene raggiunta una qualsiasi di queste condizioni. Un solutore può quindi fermarsi perché è stato raggiunto l’obiettivo di riduzione relativa mentre il residuo finale è ancora sopra tolerance.
Voci in un blocco di solutore di campo
tolerance 1e-7;
relTol 0.01;
// maxIter è facoltativo; consulta i valori predefiniti della v14
Richiamo CFD facoltativo · Residuo ed errore fisico
Il residuo misura lo scarto tra la soluzione algebrica corrente e le equazioni discretizzate (con una normalizzazione specifica di OpenFOAM). Non quantifica direttamente l’errore di mesh, l’errore di modello né lo scostamento dall’esperimento.
Nella User Guide di Foundation v14 sia tolerance sia relTol vengono specificati per le voci dei solutori lineari; maxIter è facoltativo e ha un valore predefinito documentato (1000).
Approfondimento · La normalizzazione del residuo in OpenFOAM e perché il primo residuo vale spesso 1
Il residuo «grezzo» di un sistema è il vettore b − A x, che ha le unità dell’equazione e dipende dalla dimensione delle celle: un suo valore assoluto non direbbe nulla. OpenFOAM lo rende adimensionale dividendolo per un fattore di normalizzazione costruito con il valore medio x̄ del campo corrente:
sum_cells | b - A x |
r = ---------------------------------------------------
sum_cells ( | A x - A xbar | + | b - A xbar | ) + small
Il denominatore misura quanto il problema «si discosta» da una soluzione uniforme. Due conseguenze pratiche. Primo: se il campo iniziale è uniforme (x = x̄, come internalField uniform 0), il primo termine del denominatore si annulla e il secondo coincide con il numeratore, quindi il residuo iniziale del primo passo vale 1: non è un errore, è la normalizzazione. Secondo: il residuo è una somma (norma L1) su tutte le celle divisa per una somma analoga, quindi è una media; residui piccoli possono nascondere poche celle con errori grandi, motivo in più per i controlli fisici delle sezioni successive.
Su maxIter: se nel log compare No Iterations 1000 (o il valore che hai impostato), il solutore non ha raggiunto né tolerance né relTol ed è stato fermato dal tetto. Non è un messaggio d’errore, ma è quasi sempre il sintomo di un problema: matrice mal condizionata, solutore inadatto, mesh di cattiva qualità o una soluzione che sta divergendo.
6. Lettura numerica: un calcolo dei residui svolto
Un piccolo calcolo numerico è spesso più utile che imparare a memoria i nomi dei parametri del solutore.
Esempio svolto · Esempio illustrativo
Supponiamo che il residuo iniziale sia 2 × 10−3, con tolerance = 1 × 10−7 e relTol = 0,01. La soglia di arresto relativa è 2 × 10−5. L’iterazione lineare può quindi fermarsi sul criterio relativo prima di raggiungere 10−7.
| Residuo durante la soluzione | Rapporto relativo | Criterio relativo raggiunto? |
|---|---|---|
| 2,0 × 10−3 | 1,000 | No |
| 8,0 × 10−4 | 0,400 | No |
| 1,5 × 10−5 | 0,0075 | Sì |
Che cosa cambia con relTol = 0?
Se relTol = 0, la condizione di riduzione relativa è di fatto disattivata. Il solutore prosegue allora verso la soglia tolerance, a meno che non incontri un’altra condizione di arresto come maxIter.
Verifica · Domanda
Se porti relTol da 0,1 a 0,01 mantenendo identici il residuo iniziale e tutte le altre condizioni, ti aspetteresti normalmente che la soluzione lineare faccia più o meno iterazioni? Spiegalo prima di provare. (Risposta commentata nella sezione 24.)
Approfondimento · Stimare il numero di iterazioni con un fattore di riduzione costante
Molti metodi iterativi, dopo le prime iterazioni, riducono il residuo di un fattore circa costante ρ a ogni iterazione (il fattore di convergenza). Nella tabella il primo passo porta il residuo da 2,0 × 10−3 a 8,0 × 10−4, cioè ρ ≈ 0,4. Se ρ restasse 0,4, dopo n iterazioni il rapporto sarebbe 0,4n, e si possono stimare le iterazioni necessarie per ciascun criterio:
| Criterio | Rapporto da raggiungere | n minimo (ρ = 0,4) |
|---|---|---|
relTol 0.1 | 0,1 | ln 0,1 / ln 0,4 = 2,5 → 3 |
relTol 0.01 | 0,01 | ln 0,01 / ln 0,4 = 5,0 → 6 |
relTol 0, tolerance 1e-7 | 10−7 / 2 × 10−3 = 5 × 10−5 | ln(5 × 10−5) / ln 0,4 = 10,8 → 11 |
La stima mostra la regola generale: ogni decade in più di riduzione costa circa ln 10 / |ln ρ| iterazioni (qui circa 2,5). Il valore reale nella tabella scende più in fretta (1,5 × 10−5 corrisponde a un rapporto 0,0075), perché ρ non è costante: con GAMG in particolare ogni ciclo riduce il residuo molto più di un fattore 0,4. Il modo corretto di misurare ρ sul proprio caso è leggere nel log residuo iniziale, finale e numero di iterazioni: ρ ≈ (rfinal/rinitial)1/N. Con le righe di log della sezione 7: per p, (0,00008/0,014)1/5 ≈ 0,36.
7. Diagnostica dell’esecuzione: come leggere il log del solutore
OpenFOAM riporta i residui durante il calcolo. Tratta la singola soluzione della matrice separatamente dalla cronologia complessiva della convergenza CFD.
Righe di log illustrative, non output misurato
GAMG: Solving for p, Initial residual = 0.014,
Final residual = 0.00008, No Iterations 5
smoothSolver: Solving for Ux, Initial residual = 0.0032,
Final residual = 0.00021, No Iterations 2
| Elemento del log | Come interpretarlo |
|---|---|
GAMG / smoothSolver | Quale metodo lineare ha gestito l’equazione |
p, Ux | Quale campo o componente veniva risolto |
Initial residual | Scarto prima di questa particolare soluzione |
Final residual | Scarto dopo questa particolare soluzione |
No Iterations | Lavoro svolto da questa soluzione lineare |
Non confondere due cronologie
Dentro una soluzione: il residuo scende mentre si itera su un singolo sistema matriciale. Attraverso i passi temporali o le iterazioni esterne: il residuo iniziale riportato può cambiare man mano che pressione, velocità e altri campi vengono aggiornati e le equazioni vengono riassemblate.
Verifica · Controlli fisici
Anche con residui riportati piccoli, controlla gli indicatori di continuità e di bilancio di massa, la coerenza delle condizioni al contorno e la grandezza osservabile che conta per la simulazione (per esempio la caduta di pressione).
Approfondimento · Anatomia di un passo temporale nel log di foamRun
Ecco come appare, in forma tipica, un passo di un caso transitorio incompressibleFluid 3D con PIMPLE in modalità PISO (nOuterCorrectors 1, nCorrectors 2). I numeri sono illustrativi; la struttura è quella che troverai nel tuo log.
Courant Number mean: 0.12 max: 0.45
Time = 0.0025s
smoothSolver: Solving for Ux, Initial residual = 0.0032, Final residual = 0.00021, No Iterations 2
smoothSolver: Solving for Uy, Initial residual = 0.0051, Final residual = 0.00030, No Iterations 2
smoothSolver: Solving for Uz, Initial residual = 0.0047, Final residual = 0.00028, No Iterations 2
GAMG: Solving for p, Initial residual = 0.014, Final residual = 0.00008, No Iterations 5
time step continuity errors : sum local = 2.1e-07, global = -3.4e-09, cumulative = -3.4e-09
GAMG: Solving for p, Initial residual = 0.0021, Final residual = 9.1e-08, No Iterations 9
time step continuity errors : sum local = 3.0e-10, global = 1.2e-12, cumulative = -3.4e-09
ExecutionTime = 0.41 s ClockTime = 0 s
- Le tre righe
Ux,Uy,Uzsono il predittore della quantità di moto: l’equazione vettoriale viene risolta componente per componente con la stessa matrice. In un caso 2D con patchemptyla componente normale al piano non viene risolta e la sua riga manca. - Le due righe
psono le due correzioni di pressione (nCorrectors 2); la seconda usa le impostazioni dipFinal(sezione 8), quindi va fino atolerancee richiede più iterazioni. time step continuity errorsè l’indicatore di bilancio di massa richiesto dal riquadro «Controlli fisici»:sum localè la media pesata del valore assoluto della divergenza dei flussi,globalla sua somma con segno,cumulativela somma nel tempo. Valori che crescono passo dopo passo indicano che la pressione non è risolta abbastanza.- Con un precondizionatore il nome compare come prefisso:
DICPCG: Solving for p,DILUPBiCGStab: Solving for Ux.
Approfondimento · Estrarre dal log le cronologie dei residui
Per confrontare due esecuzioni (come richiede il Laboratorio A) servono numeri, non impressioni. Alcuni modi, dal più semplice al più strutturato:
# 1. every pressure solve: initial residual and iteration count
grep "Solving for p" log.foamRun | awk -F'[=,]' '{print $3, $NF}' | head
# 2. total linear iterations for p over the whole run
grep "Solving for p" log.foamRun | awk '{s += $NF} END {print s}'
# 3. continuity errors only
grep "continuity errors" log.foamRun | tail -5
# 4. split the log into one file per quantity (logs/p_0, logs/Ux_0, ...)
foamLog log.foamRun
In alternativa la funzione residuals scrive i residui iniziali in un file di testo durante l’esecuzione: aggiungi #includeFunc residuals(p, U) al sotto-dizionario functions di controlDict (Parte 4) e troverai i dati in postProcessing/residuals/; controlla le opzioni con foamInfo residuals. Ricorda che questi file registrano il residuo iniziale di ogni soluzione: è la cronologia «attraverso i passi», non quella «dentro una soluzione».
8. Uno schema di efficienza: voci Final e riuso
Un campo può essere risolto più volte per passo temporale o per iterazione esterna. La soluzione finale può usare una regola di arresto diversa.
Soluzioni della pressione e della pressione finale
p
{
solver GAMG;
tolerance 1e-7;
relTol 0.01;
smoother DICGaussSeidel;
}
pFinal
{
$p;
relTol 0;
}
pdefinisce la configurazione ordinaria del solutore lineare della pressione.pFinalè una configurazione con un nome speciale, usata quando l’algoritmo richiede la sua soluzione finale della pressione.$p;riusa le voci dip; il successivorelTol 0;cambia la condizione di arresto relativa finale.- Questo schema evita di duplicare ogni parametro e aiuta a mantenere coerenti le configurazioni.
Nota · Il nome ha un significato
Un dizionario pFinal non è un altro file di campo fisico. Il suo significato è determinato dall’algoritmo del solutore quando sceglie le impostazioni per la soluzione algebrica finale.
Lo schema Final si usa soprattutto quando la pressione viene corretta più volte per passo. Permette alle prime correzioni di essere meno costose, mentre l’ultima viene portata a una convergenza più stretta.
Approfondimento · Quando esattamente viene usata la voce Final, e che cosa succede se manca
Nell’implementazione Foundation il suffisso Final viene aggiunto al nome del campo quando l’algoritmo si trova nell’ultima iterazione: per la velocità e gli altri campi durante l’ultimo ciclo esterno PIMPLE (con nOuterCorrectors 1, quindi, a ogni passo); per la pressione nell’ultima correzione di pressione dell’ultimo ciclo esterno (e, se ci sono correttori non ortogonali, nell’ultimo di essi). La User Guide v14 descrive lo scopo: risolvere l’equazione con impostazioni separate per il correttore finale, tipicamente relTol 0, in modo che ogni passo temporale converga fino a tolerance.
Perché conta nei casi transitori: l’errore algebrico lasciato a fine passo non viene più corretto e si accumula nel tempo come errore di continuità. Le correzioni intermedie, invece, verranno comunque superate dalla successiva: è inutile pagarle a caro prezzo. Nel log della sezione 7 la differenza è visibile: 5 iterazioni con relTol 0.01, 9 con relTol 0.
Se in un caso transitorio la voce manca, l’esecuzione si interrompe alla prima soluzione finale con un errore del tipo «keyword pFinal is undefined in dictionary .../system/fvSolution/solvers». Nei casi stazionari con SIMPLE (come il File didattico A della sezione 18 e il tutorial pitzDailySteady) le voci Final normalmente non compaiono.
9. Impostazioni condivise: espressioni regolari per i campi
Le chiavi dei dizionari OpenFOAM possono usare la corrispondenza con espressioni regolari, per evitare ripetizioni quando le equazioni di più campi richiedono le stesse impostazioni del solutore.
Campi raggruppati
"(U|k|epsilon)"
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-5;
relTol 0.1;
}
"(U|k|epsilon)Final"
{
$U;
relTol 0;
}
Il primo gruppo può corrispondere a U, k o epsilon. Il secondo corrisponde ai nomi equivalenti che terminano con Final. Quando cambia il modello di turbolenza, verifica che la configurazione dei solutori copra i campi effettivamente presenti.
Una disciplina pratica
- Usa prima i nomi espliciti dei campi; aggiungi i gruppi una volta capiti gli schemi.
- Evita espressioni regolari troppo ampie, che catturano in silenzio campi estranei.
- Ispeziona il file espanso e gli esempi dei tutorial prima di usare uno schema appena introdotto.
Verifica · Esercizio
Spiega perché omega non è coperto da "(U|k|epsilon)". Modifica lo schema per includerlo senza cambiare le altre alternative. (Soluzione nella sezione 24.)
Approfondimento · Sintassi delle chiavi regex e campi risolti dai modelli più comuni
- Le virgolette doppie sono obbligatorie: è la virgolettatura che dice a OpenFOAM di trattare la chiave come espressione regolare. Senza virgolette,
(U|k|epsilon)non è nemmeno una parola valida. - La corrispondenza è sull’intero nome:
"U.*"catturaU,UFinalma anche, per esempio, un eventualeUa;".*"cattura tutto ed è legittimo solo in contesti comerelaxationFactors(sezione 19). - Il punto è un metacarattere: tra virgolette,
"alpha.water"corrisponde anche aalphaXwater. Quando conta il punto letterale, la soluzione più sicura è scrivere il nome esatto senza virgolette (alpha.water), che viene confrontato carattere per carattere. - Precedenza: il nome esatto vince sempre; tra più regex vince l’ultima nel file. Un blocco esplicito
Uscritto dopo il gruppo prevale quindi sul gruppo perU.
Quali campi vadano coperti dipende dal modello in constant/momentumTransport (Parte 7):
| Modello | Campi con equazione di trasporto |
|---|---|
laminar (canale di riferimento) | nessuno oltre a U e p |
kEpsilon, realizableKE, RNGkEpsilon | k, epsilon |
kOmega, kOmegaSST | k, omega |
SpalartAllmaras | nuTilda |
nut, la viscosità turbolenta, è calcolata dal modello e non ha equazione propria: non serve una voce in solvers. Se un campo risolto non è coperto, l’errore arriva alla prima soluzione di quel campo, con il messaggio «keyword omega is undefined in dictionary …/solvers».
10. Scegliere i solutori: matrici simmetriche e asimmetriche
Non tutti i solutori lineari sono adatti a ogni matrice: conta l’algebra della matrice.
| Solutore | Classe di matrice tipica | Osservazione chiave |
|---|---|---|
PCG | Simmetrica | Metodo del gradiente coniugato precondizionato |
PBiCG / PBiCGStab | Asimmetrica | Famiglia del gradiente bi-coniugato |
smoothSolver | Classi supportate | Passate iterative con uno smoother scelto |
GAMG | Sistemi di pressione comuni | Algoritmo multilivello, correzione su griglia grossolana |
La distinzione simmetrica/asimmetrica dipende dall’operatore assemblato. I termini di avvezione introducono spesso asimmetria; gli operatori legati alla diffusione possono portare a matrici simmetriche con una discretizzazione e un trattamento dei contorni adeguati.
Classe di errore · Un fallimento utile
Scegliere PCG per un’equazione asimmetrica può provocare un errore che elenca i solutori asimmetrici validi. È un’informazione diagnostica utile, non un motivo per cambiare a caso diverse impostazioni.
Richiamo CFD facoltativo · Simmetria della matrice
Una matrice è simmetrica se Aij = Aji. Sono la scelta degli operatori discretizzati e i coefficienti, non semplicemente il nome del campo fisico, a determinare se questa proprietà vale.
Approfondimento · Da dove nasce l’asimmetria: l’esempio a tre celle con convezione
Riprendiamo le tre celle della sezione 2 e aggiungiamo un flusso convettivo F = 1 diretto verso +x, discretizzato con l’upwind: sulla faccia di uscita di ogni cella il valore trasportato è quello della cella stessa (contributo +F sulla diagonale), sulla faccia di ingresso è quello della cella a monte (contributo −F sul coefficiente del vicino a monte). La riga della cella 2 diventa (2 + F) φ2 − (1 + F) φ1 − φ3 = 0:
diffusion only diffusion + upwind convection (F = 1)
| 3 -1 0 | | 4 -1 0 |
|-1 2 -1 | |-2 3 -1 |
| 0 -1 3 | | 0 -2 4 |
symmetric: A12 = A21 asymmetric: A21 = -2, A12 = -1
L’equazione della quantità di moto contiene sempre il termine convettivo div(phi,U), quindi la sua matrice è asimmetrica; l’equazione della pressione degli algoritmi SIMPLE/PIMPLE è invece un’equazione di Laplace (o di Poisson) ∇·((1/A)∇p) = ∇·(HbyA), con una matrice simmetrica. Ecco perché nei tutorial p usa GAMG o PCG, mentre U, k, epsilon usano smoothSolver o PBiCGStab.
Una precisazione sulla tabella: la User Guide v14 abbina PCG alle matrici simmetriche e PBiCG a quelle asimmetriche, ma presenta PBiCGStab come variante stabilizzata utilizzabile per entrambe le classi; l’output di foamSearch riportato nella guida mostra infatti tutorial che lo usano anche per p. La riga «asimmetrica» della tabella va letta come «adatta anche alle asimmetriche». GAMG e smoothSolver accettano entrambe le classi, a patto di scegliere uno smoother compatibile (sezione 11).
Approfondimento · Che aspetto ha l’errore di compatibilità
Secondo la guida v14, usare un solutore simmetrico su una matrice asimmetrica (o viceversa) produce un FOAM FATAL IO ERROR. La forma tipica è la seguente; l’elenco esatto dipende dalla versione e dalle librerie caricate:
--> FOAM FATAL IO ERROR:
Unknown asymmetric matrix solver PCG
Valid asymmetric matrix solvers are :
(
GAMG
PBiCG
PBiCGStab
smoothSolver
)
file: .../system/fvSolution/solvers/U from line ... to line ...
Leggilo come insegna il riquadro: la parola chiave sbagliata è solver, il file e il blocco sono indicati nell’ultima riga, la classe di matrice («asymmetric») è scritta nel messaggio e le alternative valide sono elencate. La correzione è una sola: cambiare solver (e di conseguenza preconditioner, perché DIC vale solo per matrici simmetriche: per PBiCGStab si usa DILU).
11. Controlli di algebra lineare: smoother e precondizionatori
Alcuni metodi iterativi usano impostazioni aggiuntive che migliorano la convergenza trasformando il problema o applicando iterazioni locali poco costose.
Precondizionatori
Un precondizionatore trasforma il problema algebrico in modo che il metodo iterativo converga più efficacemente. Tra gli esempi di Foundation v14 ci sono DIC, DILU e FDIC, per le strutture di matrice appropriate.
Sintassi illustrativa per un solutore asimmetrico
U
{
solver PBiCGStab;
preconditioner DILU;
tolerance 1e-6;
relTol 0.05;
}
Smoother
Uno smoother riduce le componenti di errore ad alta frequenza mediante iterazioni locali. Scelte comuni sono GaussSeidel, symGaussSeidel e DICGaussSeidel. Il metodo smoothSolver richiede un’impostazione smoother appropriata.
Esempio di smoothSolver
U
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-5;
relTol 0.1;
}
Nota · Interpretazione
Non leggere smoother e preconditioner come parole chiave intercambiabili: il loro ruolo e le scelte accettabili dipendono dal solutore lineare selezionato.
Approfondimento · Che cosa fanno davvero Gauss-Seidel, DIC e DILU
Gauss-Seidel. Si percorrono le celle in ordine e si aggiorna ciascuna risolvendo la propria equazione con i valori più recenti dei vicini: φP ← (bP − Σ aN φN) / aP. Ogni aggiornamento propaga l’informazione di una sola cella, quindi gli errori che oscillano da cella a cella (alta frequenza) spariscono in poche passate, mentre quelli estesi su tutto il dominio decadono lentissimamente. symGaussSeidel esegue una passata in avanti e una all’indietro, eliminando la direzionalità legata alla numerazione delle celle: è lo smoother preferito nei tutorial per U e i campi di turbolenza. La voce nSweeps (predefinito 1) fissa quante passate fare prima di ricalcolare il residuo.
DIC e DILU. Sono fattorizzazioni incomplete: si costruisce un’approssimazione M ≈ A = L D U che ha la stessa struttura sparsa di A (nessun riempimento) e in cui, nella variante «diagonale» usata da OpenFOAM, viene modificata solo la diagonale. Risolvere con M costa quanto due passate di sostituzione, e il metodo di Krylov lavora sul sistema precondizionato M−1A x = M−1b, molto meglio condizionato. DIC (Cholesky incompleta) richiede una matrice simmetrica; DILU (LU incompleta) è la versione per matrici asimmetriche; FDIC è una versione più veloce di DIC che precalcola le quantità reciproche. Gli stessi oggetti possono fungere da smoother.
DICGaussSeidel applica uno smoothing DIC seguito da Gauss-Seidel ed è la scelta classica come smoother di GAMG per la pressione: essendo basato su DIC, è per matrici simmetriche (per un’equazione asimmetrica risolta con GAMG si usa GaussSeidel o symGaussSeidel). La guida v14 elenca inoltre GAMG stesso fra i precondizionatori (un ciclo multigrid per precondizionare PCG), diagonal (in genere non usato) e none.
| Solutore | Richiede | Esempio di combinazione |
|---|---|---|
PCG | preconditioner | DIC o FDIC (simmetrica) |
PBiCG, PBiCGStab | preconditioner | DILU per U; DIC se usato per p |
smoothSolver | smoother | symGaussSeidel o GaussSeidel |
GAMG | smoother | DICGaussSeidel o GaussSeidel per p |
12. Il concetto di multigrid: GAMG, perché più livelli?
Il multigrid generalizzato geometrico-algebrico (GAMG, Generalised geometric-algebraic multigrid) è comunemente usato per l’equazione della pressione nei tutorial di OpenFOAM.

Molti metodi iterativi eliminano rapidamente gli errori che variano velocemente ma faticano con quelli che variano lentamente. Una gerarchia di sistemi più grossolani può risolvere queste componenti a grande lunghezza d’onda in modo più economico.
Esempio di opzioni GAMG
p
{
solver GAMG;
tolerance 1e-7;
relTol 0.01;
smoother DICGaussSeidel;
nCellsInCoarsestLevel 10;
}
Parametri da saper riconoscere
nCellsInCoarsestLevel: dimensione obiettivo approssimativa del livello più grossolano.cacheAgglomeration: riusa le informazioni di agglomerazione, dove applicabile.mergeLevels: strategia di sgrossamento multilivello; cambiarla può alterare robustezza e prestazioni.nPreSweeps/nPostSweeps: lavoro di smoothing sui diversi livelli.
Flusso di lavoro · Non ottimizzare troppo presto
Per un primo esperimento mantieni le opzioni GAMG esistenti e cambia un solo parametro controllato, soltanto dopo aver registrato una situazione di riferimento. Una modifica che riduce il numero di iterazioni non è automaticamente una soluzione fisicamente migliore.
Approfondimento · Perché il multigrid funziona: frequenze dell’errore e costo per cella
Scomponiamo l’errore e = x − xesatto in modi di Fourier. Un’iterazione di Gauss-Seidel smorza di molto i modi la cui lunghezza d’onda è di poche celle, ma un modo esteso su n celle si riduce solo di un fattore circa 1 − c/n2 per passata: su una mesh di 200 celle per lato servirebbero decine di migliaia di passate. L’idea del multigrid è che un errore liscio sulla griglia fine diventa oscillante su una griglia più grossolana: dopo poche passate di smoothing (pre-sweeps) il residuo viene trasferito a un livello con meno celle, dove lo stesso smoother è di nuovo efficace; scendendo fino al livello più grossolano (circa nCellsInCoarsestLevel celle) il sistema è così piccolo da essere risolto quasi esattamente; la correzione viene poi interpolata verso l’alto e rifinita con altre passate (post-sweeps). Il risultato è un numero di cicli quasi indipendente dalla dimensione della mesh e un costo proporzionale al numero di celle.
Confronto con PCG: il numero di iterazioni del gradiente coniugato cresce come la radice del numero di condizionamento, e per un laplaciano questo cresce come (L/h)2; dimezzare la dimensione delle celle raddoppia quindi circa le iterazioni di PCG, mentre quelle di GAMG restano quasi uguali. È per questo che GAMG domina per la pressione su mesh medio-grandi, mentre su mesh piccole (come il canale didattico da poche migliaia di celle) la differenza è minima. «Algebrico» significa che i livelli grossolani non sono mesh costruite geometricamente ma agglomerazioni di celle decise dai coefficienti della matrice (nei tutorial con l’agglomeratore faceAreaPair, che unisce le celle a coppie attraverso le facce più grandi).
Approfondimento · Le opzioni GAMG documentate in v14 e i loro valori predefiniti
| Opzione | Predefinito | Significato |
|---|---|---|
smoother | obbligatoria | Smoother usato su ogni livello |
agglomerator | faceAreaPair (nei tutorial) | Metodo di agglomerazione delle celle |
cacheAgglomeration | true | Conserva la gerarchia tra una soluzione e l’altra (la mesh statica non cambia) |
nCellsInCoarsestLevel | 10 | Dimensione obiettivo del livello più grossolano |
directSolveCoarsest | false | Soluzione diretta sul livello più grossolano invece che iterativa |
mergeLevels | 1 | Quanti livelli di agglomerazione fondere in un passo (1 = sgrossamento graduale) |
nPreSweeps | 0 | Passate prima di scendere al livello grossolano |
preSweepsLevelMultiplier / maxPreSweeps | 1 / 4 | Crescita e limite delle pre-passate con il livello |
nPostSweeps | 2 | Passate dopo il ritorno dal livello grossolano |
postSweepsLevelMultiplier / maxPostSweeps | 1 / 4 | Crescita e limite delle post-passate |
nFinestSweeps | 2 | Passate sul livello più fine |
Nota per la lettura della guida: la User Guide v14 scrive questa voce come directSolveCoarset; il nome usato nel codice e nei dizionari è directSolveCoarsest, ma prima di usarla verificane la grafia nei tutorial con foamSearch. Per il primo esperimento il consiglio del riquadro resta valido: questi valori predefiniti vanno bene nella stragrande maggioranza dei casi.
13. Fattori di rilassamento: sotto-rilassamento per la stabilità
Il sotto-rilassamento limita le variazioni da un’iterazione non lineare o segregata alla successiva ed è particolarmente importante per i calcoli stazionari.
Esempio in stile stazionario
relaxationFactors
{
fields
{
p 0.3;
}
equations
{
U 0.7;
}
}
| Posizione | Che cosa viene rilassato |
|---|---|
fields | Il campo dopo la soluzione del sistema lineare |
equations | L’equazione algebrica prima della soluzione |
Un rilassamento inferiore a 1 rende in generale le variazioni più prudenti. Questo può migliorare la stabilità, ma può anche rallentare il progresso. Il fattore migliore dipende dalla qualità della mesh, dall’algoritmo di accoppiamento, dal modello fisico e dal comportamento dell’equazione.
Richiamo CFD facoltativo · Formula facoltativa
Per il rilassamento di un campo l’idea è φnuovo = φvecchio + α (φcandidato − φvecchio). Con α = 0,3 viene accettato solo il 30% dell’aggiornamento proposto. Il rilassamento delle equazioni agisce sui coefficienti della matrice invece di applicare direttamente questa miscela di campi.
Attenzione · Stazionario contro transitorio
La User Guide v14 tratta il sotto-rilassamento per i casi stazionari e osserva che, per i casi transitori con incompressibleFluid, si possono invece usare fattori di equazione pari a 1; non trapiantare acriticamente i valori di rilassamento di un caso stazionario.
Approfondimento · Il rilassamento delle equazioni in formule, e perché 1 non significa «nessun effetto»
Il rilassamento implicito delle equazioni (alla Patankar) divide la diagonale per α e aggiunge al termine noto un contributo che contiene il valore precedente:
(aP/alpha) * phiP + sum(aN * phiN) = bP + ((1 - alpha)/alpha) * aP * phiP_old
A convergenza φP = φP,old e i due termini aggiunti si cancellano: la soluzione finale è la stessa, cambia solo il percorso. Con α = 0,7 la diagonale cresce di 1/0,7 ≈ 1,43 volte: la matrice diventa più diagonalmente dominante (i solutori iterativi convergono meglio) e ogni iterazione fa un passo più corto. In OpenFOAM, prima di applicare α, la diagonale viene anche portata almeno al valore della somma dei moduli dei coefficienti fuori diagonale: per questo la guida v14 indica per i casi transitori un fattore 1 per tutte le equazioni (equations { ".*" 1; }, come nel File didattico B), che non rallenta nulla ma assicura quella che la guida chiama «uguaglianza diagonale», in generale necessaria alla convergenza di un’equazione matriciale.
Esempio sul campo. Se in una cella pvecchio = 10 m²/s² e la soluzione dell’equazione della pressione propone pcandidato = 20 m²/s², con α = 0,3 il valore accettato è 10 + 0,3 × 10 = 13 m²/s². Indicazioni della guida v14: nei tutorial stazionari si usano 0,3 per p e 0,7 per U e per i campi di turbolenza (raggruppati con una regex); valori fino a 0,9 possono essere stabili in alcuni casi, mentre valori molto sotto 0,2 rendono la convergenza proibitivamente lenta. Un campo o un’equazione assenti da relaxationFactors non vengono rilassati.
14. Algoritmo pressione–velocità: SIMPLE, accoppiamento stazionario
SIMPLE collega pressione e velocità mentre cerca una soluzione stazionaria delle equazioni di conservazione accoppiate.

Il processo si ripete di iterazione in iterazione finché non sono soddisfatti i criteri di convergenza richiesti o una condizione di arresto. Non equivale a risolvere una sola volta un’unica matrice della pressione.
Schema didattico minimo, caso stazionario
SIMPLE
{
nNonOrthogonalCorrectors 0;
residualControl
{
p 1e-5;
U 1e-6;
}
}
Impostazioni dell’algoritmo e tolleranza lineare
solvers/p/tolerancegoverna una singola soluzione matriciale.SIMPLE/residualControlspecifica i controlli di convergenza per l’iterazione stazionaria complessiva, usando la misura di residuo di campo applicabile.nNonOrthogonalCorrectorscontrolla le correzioni aggiuntive dell’equazione della pressione associate alla discretizzazione non ortogonale.
Esempio dalla versione 14 · Attenzione a SIMPLEC
Un tutorial che usa consistent yes; attiva una formulazione di tipo SIMPLEC, con scelte di rilassamento che possono essere tarate con cura. Non copiare quei coefficienti in casi SIMPLE ordinari senza comprenderne il ruolo.
Approfondimento · I passi di SIMPLE in formule
Scriviamo l’equazione discreta della quantità di moto di ogni cella separando la diagonale A dal resto: A UP = H(U) − ∇p, dove H raccoglie i contributi dei vicini e le sorgenti. Da qui U = HbyA − (1/A)∇p, con HbyA = H/A. Imponendo la continuità ∇·U = 0 si ottiene l’equazione della pressione. Un’iterazione SIMPLE di incompressibleFluid procede così:
- Predittore della quantità di moto: si assembla l’equazione di U con la pressione corrente, la si rilassa (fattore
equations/U) e la si risolve con le impostazionisolvers/U(righeUx,Uy,Uznel log). - Equazione della pressione: ∇·((1/A)∇p) = ∇·(HbyA), risolta con
solvers/p, ripetutanNonOrthogonalCorrectorsvolte in più se richiesto. - Correzione dei flussi: il flusso alle facce
phiviene corretto con il gradiente di pressione appena calcolato, e diventa conservativo a meno della tolleranza della pressione. - Rilassamento della pressione (fattore
fields/p, per esempio 0,3) e correzione della velocità U = HbyA − (1/A)∇p. - Equazioni dei modelli (turbolenza ecc.), poi l’iterazione successiva.
Nella formulazione SIMPLEC (consistent yes;) al posto di 1/A si usa 1/(A − ΣH1), dove ΣH1 è la somma dei coefficienti dei vicini: si tiene conto in modo approssimato della risposta delle celle vicine, la correzione di pressione è più «coerente» e il rilassamento della pressione diventa in gran parte superfluo. La guida v14 avverte però che nel tutorial pitzDailySteady la convergenza di SIMPLEC è molto sensibile ai fattori di rilassamento, che lì valgono 0,9 e sono stati tarati con cura: non sono adatti al SIMPLE standard, e SIMPLEC è in genere affidabile solo su geometrie semplici.
Approfondimento · Come funziona residualControl e che cosa scrive nel log
All’inizio di ogni iterazione stazionaria il modulo confronta il residuo iniziale della prima soluzione di ciascun campo elencato in residualControl con la soglia indicata (per un vettore come U si considerano le componenti risolte). Quando tutti i campi elencati sono sotto soglia, la simulazione scrive i risultati e termina prima di endTime, con un messaggio del tipo SIMPLE solution converged in 285 iterations (è il numero riportato dalla guida v14 per pitzDailySteady). I campi non elencati non vengono controllati. Se le soglie non vengono mai raggiunte, l’esecuzione prosegue fino a endTime di controlDict (Parte 4), dove nei casi stazionari il «tempo» è solo un contatore di iterazioni.
Attenzione alla coerenza tra i due livelli: il residuo iniziale di un’iterazione non può scendere molto sotto la riduzione che il solutore lineare produce a ogni iterazione. Con tolerance 1e-7 per p e residualControl p 1e-5 la combinazione è sensata; con una tolerance lineare più larga della soglia di residualControl la soglia potrebbe non essere mai raggiunta.
15. Cicli interni ed esterni: PIMPLE, accoppiamento transitorio
PIMPLE combina la correzione pressione–velocità con la ripetizione facoltativa del sistema accoppiato all’interno di un passo temporale.

Voci di controllo di PIMPLE
PIMPLE
{
nOuterCorrectors 1;
nCorrectors 2;
nNonOrthogonalCorrectors 0;
momentumPredictor yes;
}
| Parametro | Che cosa controlla |
|---|---|
nOuterCorrectors | Ripetizioni del sistema di equazioni accoppiato per passo |
nCorrectors | Correzioni pressione/velocità all’interno del passo |
nNonOrthogonalCorrectors | Correzioni di pressione aggiuntive per il contributo non ortogonale |
momentumPredictor | Se viene risolto un predittore iniziale della quantità di moto |
Importante · I conteggi dei cicli non sono iterazioni lineari
Una soluzione della pressione eseguita due volte da PIMPLE non è la stessa cosa di un solutore lineare che compie due iterazioni dentro una soluzione della pressione. Questi livelli annidati devono restare concettualmente separati.
Approfondimento · Modalità PISO, cicli esterni e predittore della quantità di moto
Con nOuterCorrectors 1 PIMPLE si riduce all’algoritmo PISO: un predittore della quantità di moto e nCorrectors correzioni di pressione per passo, senza riassemblare l’equazione della quantità di moto. È accurato ed economico se il numero di Courant massimo resta indicativamente sotto 1 (vedi il controllo di deltaT nella Parte 4). Secondo la guida v14 nCorrectors vale tipicamente 2 o 3 e nOuterCorrectors tipicamente 1.
Con nOuterCorrectors > 1 l’intero sistema viene riassemblato e risolto più volte nello stesso passo: le non linearità (il flusso convettivo phi che compare nella matrice di U) vengono aggiornate, e diventano possibili passi temporali con Courant ben superiore a 1. In questo regime le iterazioni esterne si comportano come mini-iterazioni stazionarie e può servire il rilassamento anche nel transitorio. Per non sprecare cicli esterni quando il passo è già convergente, l’implementazione Foundation prevede un sotto-dizionario outerCorrectorResidualControl (soglie per campo che interrompono in anticipo i cicli esterni): prima di usarlo, cercane un esempio nei tutorial con grep -r outerCorrectorResidualControl $FOAM_TUTORIALS.
momentumPredictor no; salta la soluzione dell’equazione della quantità di moto e passa subito alla pressione, usando la velocità del passo precedente per costruire HbyA. La guida v14 indica che si può disattivare per alcuni flussi, per esempio a basso numero di Reynolds e multifase. Nel log la conseguenza è immediata: spariscono le righe Solving for Ux/Uy/Uz.
16. Criteri di arresto: tre livelli di iterazione annidati
Uno degli errori più comuni è interpretare ogni occorrenza della parola iterazione come lo stesso processo numerico.

Tre osservazioni diverse
| Osservazione | Governata da |
|---|---|
| Tempo di simulazione, eventi di scrittura | controlDict |
| Numero di passaggi di correzione della pressione | Voci SIMPLE/PIMPLE in fvSolution |
| Iterazioni per ridurre il residuo di p o U | solvers/p e solvers/U in fvSolution |
Se un’esecuzione è costosa, individua quale ciclo consuma il lavoro prima di cambiare i parametri. Più correttori esterni possono aumentare il numero di sistemi assemblati e risolti; un relTol più stretto può aumentare le iterazioni dentro ogni soluzione lineare.
Da ragionare · Scenario svolto
Un passo transitorio può eseguire 2 correzioni di pressione; la prima soluzione della matrice della pressione può richiedere 4 iterazioni GAMG e quella finale 7. Sono due conteggi di iterazioni diversi, ciascuno dei quali descrive un livello diverso dell’algoritmo.
Approfondimento · Contare il lavoro di un passo: un esempio numerico
Prendiamo un passo PIMPLE con nOuterCorrectors 2, nCorrectors 2, nNonOrthogonalCorrectors 1 e momentumPredictor yes, in 3D. Il numero di sistemi lineari risolti è:
| Equazione | Conteggio | Impostazioni usate |
|---|---|---|
| Quantità di moto | 2 cicli esterni × 3 componenti = 6 | U nel primo ciclo, UFinal nel secondo |
| Pressione | 2 esterni × 2 correttori × (1 + 1) non ortogonali = 8 | p per 7 soluzioni, pFinal per l’ultima |
Se ogni soluzione di p costa in media 5 iterazioni GAMG e quella finale 12, il passo richiede circa 7 × 5 + 12 = 47 cicli GAMG; portando nOuterCorrectors a 1 le soluzioni di pressione scendono a 4 e il lavoro circa si dimezza, mentre portando relTol di p da 0,01 a 0,001 resterebbero 8 soluzioni ma ognuna più lunga. Sono due leve diverse su due livelli diversi: per sapere quale usare bisogna prima leggere nel log quale livello pesa di più (sezione 7).
17. Legame geometria–algoritmo: qualità della mesh e riferimento della pressione
Correzione di discretizzazione, non ortogonalità della mesh e riferimento della pressione sono questioni numericamente distinte.
Correzione non ortogonale
Le mesh non ortogonali possono richiedere correzioni trattate esplicitamente nel laplaciano dell’equazione della pressione. L’impostazione nNonOrthogonalCorrectors ripete la soluzione della pressione per aggiornare questi contributi, ma non ripara una mesh progettata male.
Configurazione illustrativa
PIMPLE
{
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
Approfondimento · Da dove viene la correzione non ortogonale e quando serve
Il flusso diffusivo attraverso una faccia richiede il gradiente normale alla faccia, (∇p)f · Sf. Su una mesh ortogonale il vettore d che unisce i centri delle due celle è parallelo alla normale Sf e il gradiente si ottiene esattamente dalla differenza (pN − pP)/|d|, una parte implicita che entra nella matrice. Se d e Sf formano un angolo θ (la non ortogonalità), si scompone Sf = Δ + k con Δ parallelo a d: la parte Δ resta implicita, la parte k · (∇p)f va calcolata con il gradiente della soluzione corrente ed entra in b come correzione esplicita. Ogni correttore non ortogonale risolve di nuovo l’equazione della pressione con il gradiente aggiornato.
Su una mesh blockMesh a blocco unico come il canale della Parte 2 θ = 0 ovunque e i correttori non servono: 0 è la scelta giusta. checkMesh riporta Mesh non-orthogonality Max: … average: … e segnala le facce oltre 70° come severely non-orthogonal. La guida v14 indica valori tipici di 0 per i casi stazionari e 1 per quelli transitori; su mesh molto distorte si combinano 1–2 correttori con schemi laplaciani limitati (Gauss linear limited corrected 0.33, Parte 5). Nei casi stazionari la non ortogonalità viene comunque «assorbita» dalle iterazioni SIMPLE successive, ed è per questo che vi basta 0.
Riferimento della pressione
In un dominio incomprimibile chiuso, senza un livello assoluto di pressione prescritto, la pressione può essere determinata solo a meno di una costante additiva. Una cella di riferimento e un valore di riferimento eliminano questa indeterminazione.
Dentro SIMPLE o PIMPLE, quando serve
pRefCell 0;
pRefValue 0;
Attenzione · Quando non serve
Un caso con un riferimento di pressione fisso adeguato su un contorno può non richiedere lo stesso riferimento interno. Stabiliscilo dalle condizioni al contorno effettive della pressione e dal comportamento del modulo, non da un modello generico.
Richiamo CFD facoltativo · Gauge della pressione
In molte formulazioni dei flussi incomprimibili sono i gradienti di pressione a muovere la velocità. Aggiungere una costante alla pressione non cambia quei gradienti; un riferimento fissa il livello arbitrario in un sistema chiuso.
Approfondimento · pRefCell e pRefValue in pratica
- Le voci vengono lette solo se il campo della pressione ha bisogno di un riferimento, cioè se nessuna patch impone un valore (nessun
fixedValueo tipo equivalente). Nel canale di riferimento, confixedValue0 all’uscita (Parte 3), sarebbero ignorate anche se presenti. pRefCellè l’indice di una cella (0 è la prima cella della numerazione della mesh),pRefValueil valore di pressione attribuito lì, nelle unità del campop(m²/s² perincompressibleFluid). La guida v14 li colloca abitualmente nel sotto-dizionarioSIMPLEoPIMPLE.- L’esempio classico è la cavità con coperchio mobile: tutte pareti,
zeroGradientperpovunque, e quindipRefCell 0; pRefValue 0;. - Se servono e mancano, il modulo si ferma con un errore che segnala l’assenza della voce
pRefCell(opRefPoint, l’alternativa che indica una posizione invece di un indice) nel dizionario dell’algoritmo. Senza alcun riferimento la matrice della pressione sarebbe singolare: il livello dipderiverebbe e il solutore lineare faticherebbe a convergere.
18. File di riferimento A: un fvSolution completo in stile stazionario
Configurazione illustrativa per un semplice caso stazionario incompressibleFluid con i campi p e U. Il caso circostante deve essere fisicamente e numericamente compatibile.
File didattico A: system/fvSolution
FoamFile
{
format ascii;
class dictionary;
location "system";
object fvSolution;
}
solvers
{
p
{
solver GAMG;
tolerance 1e-7;
relTol 0.01;
smoother DICGaussSeidel;
}
U
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-6;
relTol 0.1;
}
}
SIMPLE
{
nNonOrthogonalCorrectors 0;
residualControl
{
p 1e-5;
U 1e-6;
}
}
relaxationFactors
{
fields { p 0.3; }
equations { U 0.7; }
}
I valori sono scelti per spiegare i ruoli delle voci del dizionario; non sono impostazioni ottimali validate. Per un caso didattico laminare con steadyState in fvSchemes, adatta questo file alla configurazione effettiva del solutore.
Approfondimento · Leggere il File A riga per riga e adattarlo al canale laminare
- Intestazione. Manca
version 2.0;, che in v14 è facoltativa;class dictionaryeobject fvSolutiondevono corrispondere al file. solvers. SolopeU: è proprio ciò che serve a un casolaminar, senza campi di turbolenza. Nessuna voce Final, perché conSIMPLEnon servono.SIMPLE. Mesh ortogonale → 0 correttori; nessunpRefCellperché l’uscita fissa la pressione;residualControlcon soglie piuttosto severe (1e-5 perp, 1e-6 perU, quest’ultima uguale allatolerancelineare diU). Se le soglie non vengono raggiunte, l’esecuzione arriva fino aendTime: è una situazione da riconoscere nel log, non necessariamente un errore.relaxationFactors. La forma compatta su una riga (fields { p 0.3; }) è sintatticamente identica a quella su più righe della sezione 13.
Prima di usarlo sul canale verifica la natura del caso: foamDictionary -entry ddtSchemes/default -value system/fvSchemes deve restituire steadyState. Se restituisce Euler o backward, il caso è transitorio e serve il File B della sezione successiva. Controlla anche constant/momentumTransport: con simulationType laminar; il File A è completo così com’è.
19. File di riferimento B: un fvSolution completo in stile transitorio
Un esempio PIMPLE separato, che include le voci finali dei solutori di pressione e velocità. Non mescolarlo indiscriminatamente con il caso stazionario.
File didattico B: system/fvSolution
FoamFile
{
format ascii;
class dictionary;
location "system";
object fvSolution;
}
solvers
{
p
{
solver GAMG;
tolerance 1e-7;
relTol 0.01;
smoother DICGaussSeidel;
}
pFinal
{
$p;
relTol 0;
}
U
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-6;
relTol 0.1;
}
UFinal
{
$U;
relTol 0;
}
}
PIMPLE
{
nOuterCorrectors 1;
nCorrectors 2;
nNonOrthogonalCorrectors 0;
}
relaxationFactors
{
equations { ".*" 1; }
}
Approfondimento · File A e File B a confronto
| Elemento | File A (stazionario) | File B (transitorio) | Perché |
|---|---|---|---|
ddtSchemes atteso | steadyState | Euler o backward | È lo schema temporale a decidere quale algoritmo ha senso |
| Algoritmo | SIMPLE | PIMPLE | Iterazione verso lo stato stazionario contro avanzamento nel tempo |
| Voci Final | assenti | pFinal, UFinal | Solo nel transitorio l’ultima correzione deve chiudere il passo fino a tolerance |
| Rilassamento | p 0,3 (campo), U 0,7 (equazione) | ".*" 1 sulle equazioni | Nel transitorio il termine temporale stabilizza già; 1 assicura l’uguaglianza diagonale |
| Arresto | residualControl o endTime | endTime | Il transitorio deve coprire l’intervallo di tempo fisico |
Mescolare i due file produce errori tipici: un SIMPLE in un caso con Euler non viene letto come algoritmo transitorio; un caso transitorio senza pFinal si ferma all’ultima correzione del primo passo; un rilassamento 0,3/0,7 in un caso transitorio con nOuterCorrectors 1 rende ogni passo temporale inconsistente, perché la soluzione di fine passo non soddisfa più le equazioni. Nel File B momentumPredictor non compare: vale il predefinito, cioè il predittore viene risolto.
20. Flusso di lavoro Foundation v14: ispezionare fvSolution con gli strumenti da riga di comando
Gli strumenti di gestione del caso di Foundation v14 permettono un’ispezione mirata, invece di scorrere a mano dizionari lunghi.
Comandi di ispezione in sola lettura
foamDictionary system/fvSolution
foamDictionary -entry solvers system/fvSolution
foamDictionary -entry 'solvers/p/solver' \
-value system/fvSolution
foamDictionary -entry 'solvers/p/relTol' \
-value system/fvSolution
L’ordine esatto delle opzioni mostrato qui segue la User Guide di Foundation v14. Esegui questi comandi dalla radice del caso e confronta il risultato con il file originale.
Trovare i tipi di solutore usati nei tutorial
foamSearch -c "$FOAM_TUTORIALS" fvSolution \
solvers/p/solver
Modifica sicura
Prima ispeziona, poi crea una copia di lavoro separata, quindi modifica solo il parametro previsto. Dopo, ispeziona di nuovo la voce risultante. Conservare una situazione di riferimento rende interpretabile il confronto numerico.
Sicurezza · Attenzione alle utility distruttive
Questo esercizio non richiede foamCleanCase né foamListTimes -rm. Queste utility possono cancellare mesh e risultati generati. Evitale sulla simulazione originale o su un caso di ricerca.
Approfondimento · Che cosa aspettarsi da questi comandi, e come modificare in modo tracciabile
Sul File didattico A le due interrogazioni con -value restituiscono solo il valore, senza punto e virgola: GAMG e 0.01. Senza -value si ottiene la voce completa (solver GAMG;). Altre forme utili, tutte documentate nella §4.7 della guida v14:
foamDictionary -entry solvers -keywords system/fvSolution # p, U (or p, pFinal, "(U|k|epsilon)", ...)
foamDictionary -expand system/fvSolution # macros such as $p expanded
foamDictionary -entry solvers/p/relTol -set 0.001 system/fvSolution # edit ONLY on a copy
diff -u ../step06_steady/system/fvSolution system/fvSolution # record exactly what changed
foamSearch -c conta quante volte compare ciascun valore della voce cercata in tutti i file con quel nome sotto la cartella indicata. La guida v14 riporta come esempio 64 occorrenze di GAMG, 26 di PCG, 5 di smoothSolver e 2 di PBiCGStab per solvers/p/solver: i numeri della tua installazione possono differire, ma l’indicazione resta che GAMG è la scelta più comune per la pressione. La stessa tecnica funziona per qualsiasi voce, per esempio foamSearch -c "$FOAM_TUTORIALS" fvSolution SIMPLE/consistent per scoprire quali tutorial usano SIMPLEC.
21. Esercitazione guidata — Laboratorio A: un esperimento controllato sul solutore
Esegui l’esperimento su un clone isolato di un tutorial di Foundation v14, come pitzDailySteady, dopo averne confermato la posizione effettiva.
1. Crea una copia separata del caso
Solo copia di lavoro
mkdir -p "$HOME/OpenFOAM/training_step06"
cp -a "$FOAM_TUTORIALS/modules/incompressibleFluid/pitzDailySteady" \
"$HOME/OpenFOAM/training_step06/step06_steady"
cd "$HOME/OpenFOAM/training_step06/step06_steady"
Se la distribuzione colloca il tutorial altrove, cercalo sotto $FOAM_TUTORIALS prima di copiarlo. Non sovrascrivere una cartella step06_steady già esistente.
Attenzione · Il percorso del tutorial nella guida v14
La User Guide v14 (§2.1) copia il tutorial da $FOAM_TUTORIALS/incompressibleFluid/pitzDailySteady, cioè senza la sottocartella modules/ usata nel comando precedente. Prima di copiare, verifica con find "$FOAM_TUTORIALS" -type d -name pitzDailySteady e usa il percorso che il comando restituisce.
2. Ispeziona e prepara
Non cambiare ancora alcun parametro
foamVersion
foamDictionary -entry solvers system/fvSolution
foamDictionary -entry SIMPLE system/fvSolution
blockMesh
checkMesh
3. Registra una situazione di riferimento
Esegui il caso con foamRun e salva il log del terminale. Annota il tipo di solutore di ciascun campo, i residui iniziali e finali tipici, il numero di iterazioni lineari e le informazioni di convergenza. Conserva il log e il fvSolution originale per il confronto.
4. Cambia un solo parametro
Su un altro clone dello stesso tutorial intatto, cambia solo la tolleranza relativa di una voce di solutore effettivamente presente. Mantieni identici mesh, schemi, modello fisico e controllo dell’esecuzione. Confronta il numero di iterazioni dei solutori e le cronologie globali dei residui.
Consegna
Confronto tra solutore di riferimento e solutore modificato e una conclusione motivata. Nessuna affermazione di accuratezza fisica migliorata.
Approfondimento · Il Laboratorio A passo per passo, con i comandi
Una possibile sequenza completa per i passi 3 e 4, con il percorso dei tutorial della guida v14 (adattalo a quello trovato con find). Il nome step06_relTol per il secondo clone è una scelta arbitraria.
# --- step 3: baseline
cd "$HOME/OpenFOAM/training_step06/step06_steady"
foamRun > log.foamRun 2>&1
grep "solution converged" log.foamRun # iterations to residualControl, if reached
grep -c "Solving for p" log.foamRun # number of pressure solves
grep "Solving for p" log.foamRun | awk '{s += $NF} END {print s}' # total p iterations
foamDictionary -entry solvers/p/relTol -value system/fvSolution # note the current value
# --- step 4: second pristine clone, one change only
test -e "$HOME/OpenFOAM/training_step06/step06_relTol" && echo "exists: choose another name"
cp -a "$FOAM_TUTORIALS/incompressibleFluid/pitzDailySteady" \
"$HOME/OpenFOAM/training_step06/step06_relTol"
cd "$HOME/OpenFOAM/training_step06/step06_relTol"
foamDictionary -entry solvers/p/relTol -set 0.01 system/fvSolution # choose a value different from the baseline
diff -u ../step06_steady/system/fvSolution system/fvSolution # must show ONE changed line
blockMesh > log.blockMesh 2>&1
foamRun > log.foamRun 2>&1
Raccogli i risultati in una tabella con tre righe di confronto (iterazioni SIMPLE fino alla convergenza, iterazioni lineari totali di p, tempo di esecuzione finale ExecutionTime) e, separatamente, una grandezza fisica di controllo, per esempio la differenza di pressione tra ingresso e uscita. Una conclusione motivata ha la forma: «con relTol più stretto ogni soluzione di p richiede in media N iterazioni in più, il numero di iterazioni SIMPLE cambia di M e la grandezza di controllo varia meno di X%: il costo aumenta senza un cambiamento apprezzabile della soluzione». Notare che nei casi stazionari un relTol più stretto può anche ridurre il numero di iterazioni esterne: è proprio il tipo di effetto che il confronto deve misurare, non presumere.
22. Debug guidato — Laboratorio B: diagnosticare errori di configurazione
Usa estratti volutamente difettosi per imparare a individuare gli errori prima di toccare l’esecuzione.
Esempio 1: dizionario del solutore incompleto
Trova la parola chiave mancante
p
{
solver GAMG;
tolerance 1e-7;
smoother DICGaussSeidel;
}
Domanda: quale parametro di arresto richiesto dalla User Guide v14 manca in questa configurazione minima di p?
Esempio 2: solutore della matrice sbagliato
Indaga la compatibilità con la matrice
U
{
solver PCG;
preconditioner DIC;
tolerance 1e-6;
relTol 0;
}
Domanda: se la matrice di U assemblata è asimmetrica a causa della convezione, quale classe di diagnostica potrebbe comparire? Quale famiglia di metodi dovresti esaminare?
Metodo · Non tirare a indovinare da una sola riga di log
Leggi il primo errore significativo, individua il suo file e la sua parola chiave, controlla il contesto di matrice, campo e modello, e consulta la documentazione v14 prima di cambiare la configurazione.
Approfondimento · Leggere il primo errore significativo, e un errore che non si manifesta
Gli errori fatali di OpenFOAM hanno sempre la stessa struttura: una riga --> FOAM FATAL ERROR o FOAM FATAL IO ERROR, il messaggio, poi il file con le righe coinvolte e la funzione che ha generato l’errore. Per isolarlo da un log lungo:
grep -n "FOAM FATAL" log.foamRun
grep -n -A 15 "FOAM FATAL" log.foamRun | head -40
L’Esempio 2 genera un errore fatale esplicito (sezione 10) alla prima soluzione di U, quindi è facile da diagnosticare. L’Esempio 1 è più insidioso: la User Guide v14 indica tolerance e relTol come richieste, ma a seconda dell’implementazione una voce omessa può non essere segnalata affatto e venire presa silenziosamente con un valore predefinito (per relTol lo zero, cioè nessun criterio relativo). In quel caso ogni soluzione di p andrebbe fino a tolerance e l’unico sintomo sarebbe un numero di iterazioni più alto del previsto nel log. Per questo la verifica corretta non è «il caso parte?», ma leggere il dizionario espanso con foamDictionary -expand -entry solvers/p system/fvSolution e confrontarlo con la documentazione.
23. Valutazione: esercizio autonomo e prova finale
A questo punto dovresti essere in grado di spiegare un fvSolution semplice e di apportare una modifica basata su evidenze.
Compiti autonomi
- Individua un tutorial
incompressibleFluidstazionario e uno transitorio nella distribuzione Foundation v14 installata. - Estrai i blocchi
solvers; elenca ogni campo nominato e ogni metodo di soluzione. - Stabilisci se l’algoritmo usa SIMPLE o PIMPLE e quali sono i controlli di quell’algoritmo.
- Spiega tutte le voci Final e i gruppi regex.
- Annota gli eventuali valori di riferimento della pressione, i correttori non ortogonali e i fattori di rilassamento.
- Descrivi una modifica di parametro, perché potrebbe influire sul lavoro del solutore lineare e come verificare empiricamente la previsione.
Approfondimento · Una traccia di lavoro per i compiti autonomi
I comandi seguenti svolgono la parte di raccolta dati senza modificare nulla. pitzDailySteady (stazionario) e pitzDaily (transitorio) sono le due coppie naturali, entrambe citate dalla guida v14; il percorso va confermato come nel Laboratorio A.
ls "$FOAM_TUTORIALS/incompressibleFluid"
for c in pitzDailySteady pitzDaily; do
f="$FOAM_TUTORIALS/incompressibleFluid/$c/system/fvSolution"
echo "== $c"
foamDictionary -entry solvers -keywords "$f"
foamDictionary -entry ddtSchemes/default -value "${f%fvSolution}fvSchemes"
foamDictionary -entry SIMPLE "$f" 2>/dev/null || foamDictionary -entry PIMPLE "$f"
foamDictionary -entry relaxationFactors "$f"
done
Per ogni tutorial compila una scheda con: elenco dei blocchi in solvers e, per ciascuno, solver, preconditioner/smoother, tolerance, relTol; quali nomi reali coprono le regex (confrontandoli con il modello in constant/momentumTransport); algoritmo e controlli (nCorrectors, nOuterCorrectors, nNonOrthogonalCorrectors, consistent, residualControl, pRefCell/pRefValue); fattori di rilassamento. Per l’ultimo compito usa la forma «modifica → livello interessato (sezione 16) → effetto previsto sulle iterazioni → come lo misuro nel log (sezione 7)».
Prove di apprendimento
| Domanda | Risposta minima accettabile |
|---|---|
Perché fvSolution? | Controlla le soluzioni algebriche e l’algoritmo di accoppiamento |
Che cos’è GAMG? | Un solutore multigrid di algebra lineare; non un modulo per fluidi |
Che cosa fa relTol? | Una soglia relativa di riduzione del residuo lineare |
Che cos’è pFinal? | Le impostazioni per una soluzione finale della pressione, quando l’algoritmo la usa |
| Che cos’è il rilassamento? | Limita l’aggiornamento o la variazione dell’equazione per migliorare la robustezza |
| Che cosa rende valida un’esecuzione? | Più dei residui bassi: anche fisica, conservazione e verifica |
Condizione di superamento · Criterio di completamento
Sai ispezionare un fvSolution sconosciuto, identificarne i solutori di campo e i controlli di accoppiamento, spiegare l’effetto atteso di una modifica e poi convalidare quella previsione su una copia sicura.
24. Soluzioni degli esercizi di ragionamento
Prova a risolvere gli esercizi prima di leggere le soluzioni.
Problema del rapporto tra residui
Residuo iniziale = 0,002; relTol = 0,01 permette l’arresto quando il residuo scende sotto 0,00002. Nell’esempio, 0,000015 soddisfa il criterio relativo pur essendo sopra la tolleranza assoluta di 0,0000001. Impostare relTol = 0 elimina questa scorciatoia relativa.
Restringere relTol
Ridurre relTol da 0,1 a 0,01 richiede una diminuzione frazionaria maggiore prima che il criterio relativo sia soddisfatto; a parità di tutto il resto, ci si aspetta in generale più iterazioni lineari. Il numero effettivo dipende da quale criterio, quello assoluto o il tetto di iterazioni, viene raggiunto per primo.
Con il fattore di riduzione ρ ≈ 0,4 della sezione 6, il passaggio da 0,1 a 0,01 porta la stima da 3 a 6 iterazioni: una decade in più di riduzione costa circa ln 10 / |ln ρ| ≈ 2,5 iterazioni.
Raggruppamento dei campi con regex
"(U|k|epsilon)" non corrisponde a omega: l’espressione elenca tre alternative esatte e deve corrispondere all’intero nome. Uno schema riveduto possibile è "(U|k|epsilon|omega)" (e, coerentemente, "(U|k|epsilon|omega)Final"). Controlla quali campi esistono davvero prima di inserire la modifica.
Configurazione mancante
Nella voce p volutamente incompleta manca relTol. Secondo la descrizione dei solutori lineari della v14, tolerance e relTol vanno entrambe fornite.
Matrice asimmetrica
Un metodo solo simmetrico come PCG non può essere applicato a una matrice asimmetrica. Esamina metodi come PBiCGStab, PBiCG, smoothSolver o una configurazione GAMG appropriata, a seconda dell’equazione e del caso. Cambiando solutore va cambiato anche il precondizionatore: DIC è per matrici simmetriche, con PBiCGStab o PBiCG si usa DILU.
pFinal
pFinal è un sotto-dizionario di controllo del solutore, non un nuovo campo di pressione. Usare relTol = 0 può rendere più impegnativa la soluzione finale della pressione, perché punta alla tolleranza assoluta.
25. Riferimento rapido: scheda di configurazione
Una mappa compatta di che cosa cercare quando un caso OpenFOAM funzionante si comporta in modo inatteso.
| Posizione / voce | Domanda da porsi |
|---|---|
system/fvSolution / solvers | Quale metodo lineare risolve l’equazione di ciascun campo? |
tolerance | Quale soglia assoluta di residuo ferma quella soluzione lineare? |
relTol | Quale riduzione relativa può fermarla prima? |
maxIter | Il solutore è stato fermato da un tetto di iterazioni? |
preconditioner / smoother | Quale accelerazione dell’iterazione è configurata? |
pFinal / UFinal | Le soluzioni finali sono configurate diversamente? |
SIMPLE / PIMPLE | Come sono accoppiate pressione e velocità? |
nCorrectors | Quante correzioni interne avvengono? |
nOuterCorrectors | Quanti passaggi esterni possono avvenire a ogni passo temporale? |
nNonOrthogonalCorrectors | Sono richieste correzioni di pressione aggiuntive? |
relaxationFactors | Quanto fortemente sono rilassati equazioni e campi? |
pRefCell / pRefValue | In questo dominio chiuso serve un riferimento di pressione? |
Da ricordare · Regola da conservarefvSchemes determina le equazioni discrete; fvSolution determina come quelle equazioni vengono risolte e accoppiate. Un residuo algebrico più basso è un elemento di prova, non una validazione CFD completa.
Approfondimento · Sintomo → dove guardare: una tabella diagnostica
| Sintomo nel log | Livello | Prima verifica |
|---|---|---|
No Iterations pari a maxIter | 3, lineare | Solutore/precondizionatore adatti alla matrice? Qualità della mesh (checkMesh)? |
Molte iterazioni per p a ogni soluzione | 3, lineare | PCG su mesh grande → GAMG; relTol molto piccolo nelle correzioni intermedie |
| Residui iniziali SIMPLE che oscillano o crescono | 2, accoppiamento | Fattori di rilassamento, schemi convettivi (Parte 5), condizioni al contorno |
| Residui iniziali fermi su un valore costante | 2, accoppiamento | Instazionarietà fisica reale in un calcolo stazionario; soglie residualControl irraggiungibili |
continuity errors che crescono nel tempo | 1–2 | pFinal con relTol 0? nCorrectors sufficienti? Courant (Parte 4) |
FOAM FATAL IO ERROR su una parola chiave | configurazione | File e voce indicati nel messaggio (sezione 22) |
26. Riferimenti: documentazione ufficiale e passo successivo
Consulta la documentazione corrispondente all’implementazione e alla versione di OpenFOAM installate sul server del laboratorio. La documentazione delle release di OpenFOAM.com appartiene a una distribuzione separata (ESI) e non va sostituita senza verificarne la compatibilità.
Fonti ufficiali primarie
- OpenFOAM Foundation v14 User Guide, §4.6 Controllo della soluzione e dell’algoritmo: doc.cfd.direct/openfoam/user-guide-v14/fvsolution
- User Guide, §4.7 Strumenti di gestione del caso: doc.cfd.direct/openfoam/user-guide-v14/case-management
- User Guide, §2.1 Gradino all’indietro (tutorial incomprimibile stazionario): doc.cfd.direct/openfoam/user-guide-v14/backwardstep
- User Guide, §4.5 Schemi numerici (riferimento incrociato alla Parte 5): doc.cfd.direct/openfoam/user-guide-v14/fvschemes
- Release di OpenFOAM v14: openfoam.org/release/14/
Sequenza di apprendimento suggerita
| Parte | Tema |
|---|---|
| Parte 5 | Come discretizzare la PDE |
| Parte 6 (questa) | Come risolvere e accoppiare le equazioni |
| Parte 7 | Proprietà fisiche e modelli |
Dopo questa parte si passa alla Parte 7 — Proprietà fisiche e modelli. Lì si collega la configurazione di constant/ all’insieme di equazioni e di campi la cui soluzione è stata appena studiata.
Prossima unità · Parte 7 — Proprietà fisiche e modelli
Ora sai come le equazioni discrete vengono risolte e accoppiate. La parte successiva spiega quali equazioni e quali campi esistono in base alla fisica dichiarata in constant/: physicalProperties, momentumTransport e i modelli attivi.
Parte successiva: OpenFOAM 14, parte 7: proprietà fisiche e modelli. Parte precedente: OpenFOAM 14, parte 5: fvSchemes e discretizzazione. Torna all’indice del percorso Imparare OpenFOAM 14.