Tutorial: mapeo de resultados OpenFOAM entre mallas diferentes¶
Objetivo¶
Este procedimiento permite transferir una solución CFD ya calculada desde una malla fuente hacia una malla destino diferente que representa la misma geometría física.
Caso validado:
Fuente:
B068-P180_coldFlow_AP03C_16procMalla fuente: aproximadamente 1.33 millones de celdas.
Tiempo fuente:
0.05 s.Destino:
B068-P180_coldFlow_AP04_validation_cleanNCC_v01.Malla destino: aproximadamente 3.15 millones de celdas.
Solver:
multicomponentFluid.OpenFOAM:
dev-4d09840bec89.Interfaz periódica:
nonConformalCyclic(NCC).
El mapeo efectivo se realizó con mapFields en modo no consistente, es decir,
sin la opción -consistent.
Principio fundamental¶
mapFields no requiere que la malla fuente y la malla destino tengan las
mismas celdas. Puede utilizarse para transferir campos entre discretizaciones
diferentes de un mismo dominio físico.
Debe mantenerse coherencia en:
sistema de coordenadas;
escala geométrica;
regiones físicas;
condiciones de frontera;
campos requeridos por el solver;
topología necesaria para que cada malla pueda abrirse correctamente.
En casos con interfaces NCC, la malla no debe considerarse únicamente como
constant/polyMesh. También puede existir información dependiente de la malla
en constant/fvMesh, particularmente polyFaces.
Regla práctica para NCC¶
En una malla con nonConformalCyclic se debe tratar como una unidad coherente:
constant/polyMesh/
constant/fvMesh/
y, en particular:
constant/fvMesh/polyFaces
No debe sustituirse únicamente constant/polyMesh conservando un
constant/fvMesh/polyFaces heredado de otra malla.
Preparación de la nueva malla¶
La malla destino debe existir primero como malla geométrica válida, antes de realizar el mapeo.
Una malla básica contiene normalmente:
constant/polyMesh/
boundary
faces
neighbour
owner
points
Verifique la malla con:
checkMesh -constant
En el caso AP04 validado:
cells = 3153056
Number of regions = 1
Los defectos conocidos de checkMesh deben estar evaluados previamente. El
mapeo no debe utilizarse como mecanismo para ocultar problemas geométricos o
topológicos.
Clasificación de los patches físicos¶
Cuando la superficie de referencia contiene regiones con nombres definidos, se
puede reconstruir la clasificación de los patches mediante surfaceToPatch.
Ejemplo:
surfaceToPatch \
-tol 0.001 \
../B068-P180_snappy/constant/triSurface/B068-P180_named_patches.stl
Después de ejecutar la utilidad, se deben verificar explícitamente los patches y sus números de caras.
En AP04 se obtuvieron:
AIR_INLET_PLENUM 49401
GAS_INLET_STAGE_1 136
GAS_INLET_STAGE_2 313
GAS_INLET_STAGE_3 526
OUTLET 36116
PERIODIC_0 73548
PERIODIC_180 73718
WALLS 530093
La salida debe indicar:
unmatched faces = 0
Si aparecen caras no clasificadas de forma inesperada, no se debe continuar.
Verificación del tipo de patch¶
El nombre del patch no garantiza que su tipo OpenFOAM sea correcto.
Por ejemplo, WALLS debe quedar como:
type wall;
y no simplemente como:
type patch;
Verifique el archivo boundary después de cualquier operación de
reclasificación.
En el estado pre-NCC utilizado para AP04:
AIR_INLET_PLENUM type=patch
GAS_INLET_STAGE_1 type=patch
GAS_INLET_STAGE_2 type=patch
GAS_INLET_STAGE_3 type=patch
OUTLET type=patch
PERIODIC_0 type=patch
PERIODIC_180 type=patch
WALLS type=wall
Construcción de la NCC¶
La NCC debe construirse una sola vez sobre una malla pre-NCC limpia.
Ejemplo:
createNonConformalCouples \
-dict system/createNonConformalCouplesDict.AP04.reverse
Para el caso validado se utilizaron:
patches
(
PERIODIC_180
PERIODIC_0
);
con transformación rotacional de 180 grados.
La ejecución correcta produjo:
457704 couplings calculated
fvMeshStitcher: Connecting
Writing mesh to 0.050005
End
y creó los patches auxiliares:
periodic180_on_PERIODIC_180
periodic180_on_PERIODIC_0
nonConformalError_on_PERIODIC_180
nonConformalError_on_PERIODIC_0
Conservar conjuntamente polyMesh y fvMesh¶
Después de createNonConformalCouples se deben comprobar los dos objetos
generados:
ls -lh \
0.050005/polyMesh/boundary \
0.050005/fvMesh/polyFaces
Ambos deben pertenecer a la misma generación de la malla NCC.
Para promover esa malla a constant:
cp -a 0.050005/polyMesh constant/polyMesh
cp -a 0.050005/fvMesh constant/fvMesh
No copie solamente polyMesh.
Comprobación de polyFaces heredado¶
Si el caso destino se creó inicialmente copiando otro caso, compare los
polyFaces:
cmp -s \
CASO_DESTINO/constant/fvMesh/polyFaces \
CASO_FUENTE/constant/fvMesh/polyFaces
Un control práctico:
if cmp -s \
CASO_DESTINO/constant/fvMesh/polyFaces \
CASO_FUENTE/constant/fvMesh/polyFaces
then
echo "WARNING: polyFaces identical"
else
echo "polyFaces differs"
fi
Si las mallas son distintas y polyFaces es binariamente idéntico, debe
considerarse sospechoso.
En el caso validado:
AP03C polyFaces = 821 KB
AP04 polyFaces = 1.8 MB
Esto confirmó que AP04 tenía su propio polyFaces.
Startup test antes del mapeo¶
Antes de ejecutar mapFields, la malla destino debe ser capaz de abrirse
correctamente con el solver.
Configure temporalmente:
startFrom startTime;
startTime 0.05;
stopAt endTime;
endTime 0.05;
Ejecute:
foamRun \
-solver multicomponentFluid \
-noFunctionObjects
El objetivo es que OpenFOAM construya la malla, conecte la NCC, inicialice el modelo y termine sin avanzar tiempo.
Una prueba satisfactoria alcanza:
fvMeshStitcher: Connecting
Selecting solver multicomponentFluid
...
Starting time loop
End
Esto verifica independientemente:
malla
+ NCC
+ fvMesh
+ diccionarios
No se debe diagnosticar mapFields mientras la malla destino no supere este
test.
Preparación del tiempo destino¶
Debe existir el directorio temporal donde se escribirán los campos mapeados.
Por ejemplo:
0.05/
con los campos requeridos por el solver:
U
p
T
k
omega
O2
N2
CH4
...
En un modelo multicomponente deben existir también todas las especies esperadas por el solver.
Antes de mapear:
cp -a 0.05 0.05.preMap
Configuración de mapFieldsDict¶
El procedimiento validado utilizó:
FoamFile
{
format ascii;
class dictionary;
object mapFieldsDict;
}
patchMap
(
);
cuttingPatches
(
);
Mapeo efectivo¶
Para dos mallas distintas de la misma geometría física, el procedimiento
efectivo fue ejecutar mapFields sin -consistent.
Ejemplo general:
mapFields \
../CASO_FUENTE \
-sourceTime 0.05 \
-noFunctionObjects
Caso validado:
mapFields \
../B068-P180_coldFlow_AP03C_16proc \
-sourceTime 0.05 \
-noFunctionObjects \
> log.mapFields.AP03C_to_AP04_005_nonConsistent_cleanNCC 2>&1
Verifique el código de retorno:
rc=$?
echo "exit = $rc"
Una ejecución correcta mostró:
Source mesh size: 1333396
Target mesh size: 3153056
Mapping fields for time 0.05
interpolating OH
interpolating CN
...
interpolating k
...
interpolating p
interpolating T
...
interpolating omega
...
interpolating U
End
y:
exit = 0
Uso de -consistent¶
No debe interpretarse -consistent simplemente como «misma geometría».
La opción supone una correspondencia más estricta entre source y target.
Para este caso, con dos discretizaciones NCC diferentes, la ruta efectiva y validada fue:
mapFields SOURCE -sourceTime TIME
sin:
-consistent
Uso de source reconstruido¶
Si el caso fuente dispone de una solución reconstruida en el directorio principal
del caso, no es necesario mapear desde los processor*.
Por ejemplo:
B068-P180_coldFlow_AP03C_16proc/
0.05/
processor0/
...
processor15/
En este caso se utilizó directamente:
mapFields \
../B068-P180_coldFlow_AP03C_16proc \
-sourceTime 0.05
sin -parallelSource.
Validación posterior al mapeo¶
Después del mapping, repita el startup test del solver con:
startTime 0.05;
endTime 0.05;
Ejecute:
foamRun \
-solver multicomponentFluid \
-noFunctionObjects
En el caso validado:
exit = 0
El solver inicializó correctamente:
multicomponentFluid
kOmegaSST
53 species
y alcanzó:
Starting time loop
End
Como comprobación adicional, el Courant cambió después del mapping a:
Courant Number mean: 0.004459740956
Courant Number max: 0.19484275
Esto confirmó que el campo U había sido realmente transferido al target.
Descomposición del caso destino¶
La descomposición debe realizarse después del mapping.
Elimine una descomposición anterior:
rm -rf processor*
Descomponga nuevamente:
decomposePar -force \
> log.decomposePar 2>&1
Compruebe el número de particiones:
find . -maxdepth 1 -type d -name 'processor*' | wc -l
Para 16 procesos:
16
En un caso NCC verifique también polyFaces:
find processor* \
-path '*/constant/fvMesh/polyFaces' \
-type f | wc -l
Resultado esperado:
16
Compruebe igualmente que el estado inicial fue descompuesto:
find processor* \
-path '*/0.05/U' \
-type f | wc -l
Resultado esperado:
16
Ejecución paralela¶
Una vez validado el target:
mpirun -np 16 \
foamRun \
-solver multicomponentFluid \
-parallel \
> log.run 2>&1 &
La simulación continúa sobre la nueva malla utilizando como estado inicial la solución interpolada desde la malla anterior.
Secuencia recomendada¶
La secuencia completa y reproducible es:
1. Crear nueva malla
|
v
2. checkMesh
|
v
3. Crear o clasificar patches físicos
|
v
4. Confirmar tipos de patch
|
v
5. Guardar snapshot PRE-NCC
|
v
6. createNonConformalCouples una sola vez
|
v
7. Preservar juntos:
polyMesh/
fvMesh/polyFaces
|
v
8. Startup test de la nueva malla
|
v
9. Preparar tiempo destino
|
v
10. Backup del tiempo destino
|
v
11. mapFields SOURCE -sourceTime TIME
|
v
12. Confirmar End y exit=0
|
v
13. Startup test post-mapping
|
v
14. decomposePar
|
v
15. Confirmar polyFaces en todos los processors
|
v
16. Ejecutar CFD en paralelo
Plantilla reutilizable¶
Con el caso destino como directorio actual:
SOURCE=../Caso_malla_A
TARGET_TIME=0.05
cp -a "$TARGET_TIME" "${TARGET_TIME}.preMap"
mapFields \
"$SOURCE" \
-sourceTime "$TARGET_TIME" \
-noFunctionObjects \
> log.mapFields 2>&1
rc=$?
echo "mapFields exit = $rc"
tail -n 100 log.mapFields
Solo continúe si obtiene:
End
mapFields exit = 0
Después haga el startup test, con startTime=endTime:
foamRun \
-solver multicomponentFluid \
-noFunctionObjects
Finalmente:
rm -rf processor*
decomposePar -force \
> log.decomposePar 2>&1
mpirun -np 16 \
foamRun \
-solver multicomponentFluid \
-parallel \
> log.run 2>&1 &
Conclusión¶
Una solución CFD puede transferirse entre discretizaciones distintas de una misma geometría siempre que:
la nueva malla sea válida por sí misma;
sus patches físicos estén correctamente clasificados;
la NCC se haya construido sobre la malla definitiva;
polyMeshyfvMesh/polyFacespertenezcan a la misma generación;el solver pueda abrir la nueva malla antes del mapping;
mapFieldsse ejecute en el modo adecuado para mallas diferentes;el estado mapeado se valide nuevamente antes de descomponer y correr.
Para el caso B068-P180, la ruta validada quedó:
AP03C @ 0.05 s
|
| mapFields no-consistent
v
AP04 @ 0.05 s
|
| startup validation
v
decomposePar
|
v
continuación CFD sobre AP04
Este procedimiento permite reutilizar soluciones previamente calculadas después de una remallada, evitando reiniciar la simulación desde condiciones iniciales.