Flujo de Trabajo CFD Agentic

Resuelve un problema de flujo de fluidos de principio a fin con OpenFOAM y genera un informe HTML verificado (problema, hipótesis, teoría, decisiones, prueba previa, simulación, comparación, conclusiones). Úsalo cuando se proporcione un enunciado de problema CFD en `cases/<name>/problem.yaml` o se te pida simular un flujo y reportar sobre él.

¿Qué es Flujo de Trabajo CFD Agentic?

Este flujo de trabajo (skill) capacita a un agente de IA para actuar como un ingeniero CFD virtual, transformando un enunciado de problema en un informe de simulación confiable y totalmente verificable. Se basa en cuatro principios fundamentales: todo número en el informe debe ser generado por código (usando SymPy para teoría y verificaciones), cada elección de configuración de OpenFOAM debe estar documentada con su justificación y alternativas, ningún dato proviene de la memoria sin referencia explícita, y las observaciones del agente durante el proceso se registran en un cuaderno de bitácora (`insights.log`) en tiempo real para mejorar el flujo de trabajo. La estructura del proyecto incluye una librería compartida (`cfdlib/`) para tareas comunes (renderizado, monitoreo, verificación, gráficos, etc.) y una carpeta por caso (`cases/<name>/`) con su enunciado, datos de referencia, planes numéricos y una plantilla de caso de OpenFOAM. El flujo de trabajo consta de etapas secuenciales: ingesta del problema, desarrollo teórico, configuración y decisiones con un plan de malla, una prueba previa obligatoria para validar la configuración, las ejecuciones de producción, el análisis de resultados (incluyendo órdenes de convergencia, extrapolación de Richardson, GCI y comparación con benchmarks), y finalmente la generación del informe HTML con gráficos, tablas y un veredicto, todo verificado por un contrato de calidad. Está diseñado para plataformas como Claude Code y Cursor, y sus casos de ejemplo documentan lecciones aprendidas de problemas lineales, no lineales, estacionarios y transitorios.

Compatible con✓Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/tomyud1/agentic-cfd/tree/HEAD/.claude/skills/agentic-cfd

Installed? Explore more Investigación y análisis de datos skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Flujo de Trabajo CFD Agentic (Agentic CFD workflow)

Conviertes un enunciado de problema en un informe de simulación confiable. El lector es un ingeniero que leerá principalmente el resumen y debe poder verificar cada afirmación. Cuatro reglas:

  1. El código calcula cada número. Escribes el código; nunca escribes un resultado, valor de referencia o salida de una fórmula manualmente en el informe. La teoría se resuelve simbólicamente (SymPy) y se auto-verifica.
  2. Cada decisión está documentada. Cada configuración de OpenFOAM pertenece a una decisión con su por qué / efecto / alternativas. Un verificador se niega a renderizar el informe de lo contrario.
  3. Nada de memoria. Los datos de referencia, correlaciones y constantes provienen de los archivos reference/ del problema o de una fuente citada. Si debes usar un valor aproximado, dilo en el informe.
  4. Registra las observaciones en vivo, como un cuaderno de laboratorio. Parte de tu trabajo es mejorar este flujo de trabajo para los agentes que vienen después de ti. En el momento en que algo falla, te sorprende, necesita un segundo intento, o no está claro en estas directrices, abre una observación (antes de comenzar a solucionarlo): insights.log(case, stage, problem); completa con diagnóstico, solución, lección y directriz usando insights.resolve(...) una vez resuelto. No las guardes para el final: los recuerdos de una sesión larga se pierden y distorsionan. Espera registrar de 5 a 15 entradas; una ejecución sin ninguna no fue revisada de cerca.

Estructura de carpetas

cfdlib/                       herramientas compartidas (NO modificar; registra los cambios necesarios como observaciones, etapa "tooling")
  foam.py        render_case, run (tiempo de espera, archivo PID), stop, running; lee fields y archivos .dat de postProcessing
  monitor.py     parse_log, assess (verificaciones de salud), preflight (ejecución de prueba corta + proyección de tiempo de ejecución)
  verification.py normas de error, orden observado, extrapolación de Richardson, GCI, level_sequence
                 (convergencia de cualquier secuencia de niveles, incluida la propia de una referencia)
  signals.py     señales periódicas: ciclos, picos refinados, verificación de periodicidad, FFT de frecuencia
  plots.py       estilo y tamaños de figuras (figure, wide, sketch); to_svg verifica superposición de texto
  report.py      m(), tex_num(), tex_fix() (decimales fijos para columnas de tablas), tex_pct(), LETTERS, load_yaml,
                 environment_info(), render()
  perf.py        números de rendimiento por ejecución (resumir, máquina) para el apéndice de rendimiento
  contract.py    el verificador del contrato del informe (también modo --decisions)
  insights.py    el registro de observaciones en vivo (verifica el formato cuando registras; se niega a sobrescribir una entrada ya completada)
  foamdict.py    analizador de diccionarios de OpenFOAM (usado por el verificador)
cases/<name>/                 una carpeta por problema
  problem.yaml   DADO por el usuario: description (resumen breve), setup (lista de hechos: geometría,
                 condiciones de contorno, definiciones), given data, requested outputs [+ reference/].
                 No cambies la física. Pasa description y setup al informe sin cambios.
  reference/     datos de referencia proporcionados por el usuario con citas
  numerics.yaml  tu plan numérico (mallas, duraciones de ejecución, tolerancias)
  decisions.yaml cada decisión, escrita MIENTRAS configuras el caso
  insights.yaml  el registro en vivo (cfdlib.insights)
  template/      el caso de OpenFOAM (0/, constant/, system/) con {{ marcadores de posición }}
  theory.py / analytical.py, sketch.py, run.py, analyze.py
results/<name>/  datos sin procesar, results.json, report.html

Ejemplos trabajados (lee todos sus archivos antes de comenzar; copia la estructura, no las configuraciones numéricas):

  • cases/plane_poiseuille/: lineal, estacionario, solución exacta (verificación). Informe: results/plane_poiseuille/report.html.
  • cases/lid_driven_cavity_re100/: no lineal, estacionario, sin solución exacta, benchmark publicado (comparación con benchmark, extrapolación de Richardson, SIMPLEC detenido por residual, comandos separados de pre-vuelo y producción). Informe: results/lid_driven_cavity_re100/report.html. Su insights.yaml contiene 15 lecciones del agente que lo construyó.
  • cases/stokes_first_problem/: lineal, TRANSITORIO, solución exacta (estudios de malla y paso de tiempo combinados y separados, balance de momento por paso, ejecuciones concurrentes). Informe: results/stokes_first_problem/report.html.
  • cases/dfg_cylinder_re100/: no lineal, TRANSITORIO y periódico (desprendimiento de vórtices), benchmark con varios niveles de referencia, malla con cuerpo curvo en O generada en Python, ejecuciones MPI y apéndice de rendimiento. Informe: results/dfg_cylinder_re100/report.html. Su insights.yaml contiene 16 lecciones (la más importante: PISO fue de primer orden en el tiempo).

Etapas

0. Ingesta (Intake)

  • Lee problem.yaml y cualquier archivo de reference/. Enumera las salidas solicitadas (reciben letras a, b, c...).
  • Calcula los números adimensionales que gobiernan (Re, Ma, ...) en código. Decide qué física aplica.
  • Si faltan datos o son contradictorios, elige una hipótesis documentada y márcala en las limitaciones del informe. Nunca inventes entradas en silencio.
  • Si una referencia no da incertidumbre, estima una (su malla, sus dígitos impresos, una segunda fuente) y registra cómo; la necesitarás en la etapa 5.

1. Teoría: lo que se puede conocer sin la simulación

  • Solución exacta disponible: derívala con SymPy, verifícala (satisface ecuaciones y condiciones de contorno), evalúa las cantidades solicitadas. Ver cases/plane_poiseuille/analytical.py.
  • Sin solución exacta (caso habitual): dila en theory.intro, y proporciona lo que la teoría PUEDE decir: casos límite, escalado, leyes de conservación, simetría, signo de cantidades, estructura del flujo esperada. Ver cases/lid_driven_cavity_re100/theory.py.
  • Cada cantidad derivada obtiene: por qué es importante, el significado y valor de cada símbolo en este problema, y la fórmula con los números sustituidos (verificación manual).

2. Configuración y decisiones (Setup and decisions)

  • Encuentra el tutorial de OpenFOAM más cercano ($FOAM_TUTORIALS) y comienza desde allí; haz cambios mínimos.
  • Lee references/openfoam-primer.md para saber qué controla cada archivo y los errores conocidos.
  • Las plantillas pueden contener bucles Jinja: generar un blockMeshDict completo desde Python está bien y es la forma de mallar cuerpos curvos (ejemplo: mesh_spec() en cases/dfg_cylinder_re100/run.py).
  • Edita archivos que contengan LaTeX solo con las herramientas Edit/Write, nunca a través de heredocs de Bash o Python en línea: la herramienta Bash se come las barras invertidas (\times se convierte en TAB). Los casos 3 y 4 perdieron tiempo por esto.
  • Escribe decisions.yaml a medida que avanzas: una entrada por elección con kind (physics / accuracy / solver / output) y patrones de settings que cubran todas las configuraciones en los archivos del caso. Verifica la cobertura tan pronto como se renderice un caso: python -m cfdlib.contract --decisions cases/<name>/decisions.yaml <case dir>.
  • Planifica un estudio de malla: al menos 3 mallas, relación de refinamiento 2 (necesario para orden observado y GCI). Los problemas transitorios también necesitan un estudio de paso de tiempo (o un argumento, con números, de que el error de tiempo es despreciable).
  • Define una verificación de convergencia/estacionariedad física para tu problema (un balance, una cantidad conservada, un valor monitoreado que debe dejar de cambiar) y su tolerancia ANTES de ver los resultados. Los residuales normalizados por sí solos no son suficientes. Problemas transitorios: un balance por paso (cambio de una cantidad conservada = flujos en el contorno) es una verificación sólida; debe usar el propio esquema temporal del solucionador.
  • Las tolerancias de aprobado/reprobado deben discriminar: establécela a partir del error de la pre-prueba gruesa y el orden esperado (lo que la malla más fina debería alcanzar), no a partir de números redondos. Una tolerancia 100 veces más laxa que lo conseguido no demuestra nada (caso 3). Haz que el orden de precisión observado sea una regla propia.

3. Prueba previa (Pre-flight test) (obligatoria, antes de cualquier ejecución larga)

  • cfdlib.monitor.preflight() en las mallas más gruesa Y más fina con una ejecución corta (un pequeño % de la duración total). Funciona en una copia separada <case>_preflight; renderiza los casos de pre-vuelo y producción en directorios separados también, para que volver a ejecutar uno nunca elimine al otro.
  • Reporta bloqueos, NaN, número de Courant, tendencias de residual/Courant/continuidad y proyecta el tiempo de ejecución. Ejecuciones transitorias: la proyección es confiable. Ejecuciones estacionarias: pasa residual_targets; el resultado es una cota inferior (SIMPLE se vuelve más lento después y en mallas más finas).
  • Imprime el encabezado y las primeras filas de cada archivo postProcessing que escribió la pre-prueba y verifica que cada uno no sea trivial (caso 4: una integral de presión escribió 0 en cada paso, en silencio).
  • Problemas transitorios no lineales: un estudio de paso de tiempo corto (3 pasos de tiempo, relación 2, en una malla gruesa) pertenece a la pre-prueba, antes del estudio de malla. Muestra el orden observado en el tiempo: PISO (1 corrector externo) resultó ser de primer orden en el caso 4 y costó una re-ejecución completa.
  • Una pre-prueba que comienza desde el reposo subestima el costo de un flujo no estacionario desarrollado (caso 4: el doble). Comienza desde un campo desarrollado (mapFields de una ejecución gruesa) o presupuesta el doble de la proyección.
  • Si falla o advierte, corrige la configuración y registra una observación. No hay ejecuciones de producción en una pre-prueba que falla. Si el tiempo proyectado es excesivo (> ~15 minutos por ejecución aquí), haz el plan más grueso y dilo.

4. Ejecuciones de producción (Production runs)

  • Ejecuta mallas de gruesa a fina. Para ejecuciones estacionarias, extrapola el recuento de iteraciones de la malla más fina a partir de las más gruesas (a menudo crece 3-4 veces por refinamiento) antes de lanzarla.
  • La detención debe ser física: convierte la verificación física de la etapa 2 en la regla de detención (por ejemplo, un objeto de función runTimeControl en valores medidos, ver el primer), o verifica por malla que los objetivos residuales realmente la cumplan, primero en las mallas gruesas.
  • Las ejecuciones independientes (diferentes mallas) pueden ejecutarse al mismo tiempo, hasta 6 a la vez (8 núcleos). Dilo en las notas de reproducibilidad, ya que infla los tiempos de pared por ejecución.
  • Las ejecuciones largas van en segundo plano; python -m cfdlib.foam ps lista los procesos del solucionador, y python -m cfdlib.foam stop <case dir> mata uno (detener el contenedor de Python solo deja un solucionador huérfano). Registra por ejecución: salud (monitor.assess), la verificación física, tiempo de pared.
  • Ejecuta una secuencia de ejecuciones largas como UN script de fondo que escribe un marcador de finalización y un registro por ejecución. Después de cualquier interrupción (una pausa de API también), lee esos archivos antes de volver a ejecutar algo.
  • Mientras todos los hilos de hardware ejecutan un solucionador, tu propio trabajo se ralentiza: deja 1-2 hilos libres o presupuesta 1.5 veces la proyección.

5. Análisis (Analysis)

  • Todas las comparaciones en código. Con una solución exacta: errores y orden observado por malla. Sin ella: orden observado y extrapolación de Richardson a partir de 3 mallas, GCI en la malla más fina (verification.py), luego compara el valor extrapolado con la referencia.
  • Un benchmark también es una simulación: juzga la concordancia frente a (tu banda GCI + la incertidumbre propia de la referencia), no frente a cero. Si la diferencia no se reduce con el refinamiento, no es tu error de discretización; prueba la robustez (otro esquema, iteración más ajustada) antes de culpar a cualquiera de las partes, y recomienda una segunda referencia independiente.
  • Cuando la referencia da varios niveles de malla, todavía está convergiendo: calcula SU orden observado y valor de Richardson (verification.level_sequence) y compara tu resultado tanto con su nivel más fino como con su valor extrapolado. Decide la regla de aprobado antes de mirar (el caso 4 mantuvo la regla del nivel más fino e informó la extrapolación como contexto).
  • Salidas periódicas (desprendimiento, oscilaciones): usa cfdlib.signals (ciclos entre cruces ascendentes, picos refinados con parábola, verificación de periodicidad, verificación cruzada con FFT) en lugar de escribir las tuyas propias.
  • Una coincidencia en malla gruesa puede ser suerte (cancelación de errores). Informa las diferencias honestamente, dónde y por qué.
  • Una explicación es una afirmación: verifícala contra los datos (signo, tamaño, escalado) antes de escribirla. En el caso 3, la primera explicación de un error tenía el signo incorrecto y un tercio del tamaño.

6. Informe (Report)

  • Construye results.json en analyze.py y llama a report.render(results, svgs, out, case_dir=<finest case>). El contrato está en references/report-contract.md; render se niega a escribir un informe que lo rompa.
  • Matemáticas: cada fórmula, símbolo y número científico en texto como LaTeX dentro de () (m(), tex_num()): escribe \(0.009\,U\), nunca 0.009 U, 6.3e-06 o u*H/nu. El verificador rechaza la notación e y las matemáticas ASCII, y advierte sobre número por símbolo en texto plano.
  • Los títulos y hallazgos también son resultados: genéralos a partir de los datos (un título que dice "se reduce" debe ser calculado). Refiérete a las figuras como {fig:<key>}; render() inserta el número.
  • Figuras (cfdlib.plots): plots.figure() para un panel, plots.wide(n) para 2-3 paneles, plots.sketch() para el boceto del problema (obligatorio). to_svg() rechaza figuras cuyo texto se superpone con texto, líneas, flechas o formas, o cuya leyenda cubre datos, o que son más anchas que la columna. Arregla el diseño (etiquetas alejadas de las líneas, annotate con una línea guía, leyenda fuera); allow= solo para superposiciones que son realmente intencionadas, y registra una observación si lo necesitas.
  • Veredicto: PASA solo si cada verificación que definiste pasa; ADVERTENCIA si los resultados son utilizables con salvedades; FALLA en caso contrario. Nunca suavices una verificación fallida.

7. Revisión visual (Visual review) (obligatoria)

El contrato verifica la estructura; solo mirar detecta lo que un lector verá. Abre el informe en el navegador integrado a través del servidor local (file:// no funciona): http://localhost:8765/<name>/report.html (si no carga, inicia el servidor reports desde .claude/launch.json con la herramienta de previsualización). Agrega ?v=<n> después de volver a renderizar para evitar una copia en caché.

  • Captura de pantalla de cada sección, de arriba a abajo. Verifica: figuras legibles (texto no minúsculo, nada superpuesto, líneas guía que no cruzan curvas), tablas no cortadas, matemáticas renderizadas (sin () sin procesar), columnas de tablas alineadas, el resumen responde a cada solicitud.
  • Ejecuta en la página (espera a MathJax, abre cada panel ⓘ, luego lista cada elemento cuyo contenido está cortado; debería estar vacío; ejecútalo justo después de cargar, antes de que MathJax termine, reporta TeX sin formato como desbordamiento): await MathJax.startup.promise; document.querySelectorAll('details').forEach(d => d.open = true); [...document.querySelectorAll('section *')].filter(x => !x.tagName.startsWith('MJX') && x.scrollWidth > x.clientWidth).map(x => x.tagName + (x.id ? '#' + x.id : '') + (x.className ? '.' + x.className.replace(/ /g,'.') : ''))
  • Lee el informe en voz alta en tu mente como si fueras el ingeniero de destino. ¿Hay algún salto? ¿Alguna cifra sin fuente? ¿Algún gráfico sin llamada en el texto? Arregla lo que te moleste.
  • Todo lo que el contrato no verifica (estilo, flujo, énfasis) es tu responsabilidad.

Referencias de skill (para el agente)

Después de completar un caso, actualiza esta sección o references/ si has aprendido algo que los agentes futuros deberían saber. Las referencias actuales son:

  • references/openfoam-primer.md: Qué hace cada archivo, errores con LaTeX, objetos de función útiles.
  • references/report-contract.md: Reglas de formato que cfdlib.report.render() exige.
  • references/insight-examples.md: Patrones para observaciones útiles.

Skills relacionados