CalculiX MCP

Solver de FEM de código abierto (ccx) como servidor FastMCP, integrado en el ecosistema de agente CAE-Agent-Hub + visor de navegador

Documentación

CalculiX MCP

Un servidor MCP que expone el solucionador FEM de código abierto CalculiX (ccx) a clientes MCP. CalculiX es GPLv2, no requiere licencia y se ejecuta como una CLI de "disparar y olvidar" — por lo que este servidor es completamente autónomo, sin puente de sesión en vivo ni máquina de estados de licencia.

El flujo de trabajo es: analizar un archivo de entrada .inp de CalculiX/Abaqus, inspeccionar sus variables de diseño ajustables, editar un valor en su lugar, enviarlo a ccx, leer los resultados de texto (.dat), y exportar esos resultados .dat a result_mesh.json para que el Visor de Texto a CAE del repositorio pueda renderizar la malla y el campo de tensiones.

Este es el primer MCP FEM con solucionador de código abierto en el hub (la línea FEA existente se detuvo en referencias a FEniCS), cubriendo la brecha señalada en el Issue #14.

Herramientas

HerramientaPropósito
fea_healthInformar la disponibilidad de meshio y el ejecutable ccx detectado.
parse_inpAnalizar un archivo .inp: nodos, conteos de elementos, secciones de lámina/viga, materiales, cargas.
list_design_vars_toolListar variables de diseño ajustables (espesor de lámina, sección de viga, material E/nu/densidad, magnitud de carga), cada una con un localizador var_id.
modify_card_toolEditar una variable de diseño en su lugar mediante var_id; reemplazo de texto puro, escribe un nuevo .inp.
run_solver_toolEjecutar ccx -i <jobname> sobre un archivo. El éxito ignora el código de salida (ver más abajo).
read_results_toolAnalizar el .dat para obtener el máximo von Mises (autocalculado), desplazamiento máximo, volumen, masa; para pasos *FREQUENCY también la tabla de valores propios (frequencies, n_modes).
export_results_toolExportar la ejecución a result_mesh.json (formato de visor); para ejecuciones modales pasar mode=N para exportar la forma de ese modo.
optimize_structure_toolOptimización de dimensionamiento en dos etapas (barrido LHS + descenso por coordenadas): minimizar masa sujeto a límites de tensión/desplazamiento (archivos estáticos) o un piso de frecuencia natural (archivos modales, "evitar resonancia") ajustando variables de diseño escalares (espesor de lámina, sección de viga, material, carga). Solo modelos de lámina/viga — ver Optimización.

Contratos CalculiX difíciles de conseguir (codificados en el solucionador)

Estas son las razones por las que este servidor no es trivial — todo del comportamiento público de CalculiX:

  • El código de salida de ccx no es confiableccx devuelve 0 incluso cuando imprime *ERROR. Éxito = sin *ERROR en stdout y el archivo .sta tiene una fila de datos y sin tiempo de espera agotado.
  • .dat no tiene von Mises — solo 6 componentes de tensión; σ_vm se autocalcula.
  • .dat no tiene volumen/masa total — calculado a partir de la geometría de la malla × *DENSITY.
  • Nunca meshio.write — elimina cada tarjeta y reescribe B31B31H (corrompe el archivo). modify_card hace ediciones de texto puro en su lugar.
  • Los pasos *FREQUENCY escriben un .sta solo con encabezado — una solución de valores propios no tiene incrementos, por lo que el éxito también acepta un .dat no vacío (de lo contrario, cada ejecución modal parecería fallida). Las frecuencias y los vectores propios por modo están en el texto .dat, no solo en el .frd.

Optimización

optimize_structure_tool ejecuta optimización de dimensionamiento en dos etapas: un barrido grueso de Hipercubo Latino, luego refinamiento por descenso de coordenadas (salto al límite más bisección repetida hacia el límite factible), minimizando masa sujeto a restricciones de tensión y desplazamiento editando tarjetas escalares en su lugar.

optimize_structure_tool(
    path="examples/bracket.inp",
    variables={"shell.PLATE.thickness": [2.0, 8.0]},
    n_lhs=8, max_solves=18,
)
# -> best ~4.1 mm, ~-48% mass, stress < 250 MPa, displacement < 1.5 mm

Las restricciones de frecuencia ("evitar resonancia") ejecutan el mismo bucle contra un archivo *FREQUENCY: cada evaluación es una solución de valores propios, el modo N se lee de la tabla de valores propios .dat, y el adelgazamiento se detiene donde el modo se sitúa justo por encima de su piso. Las métricas estáticas y de frecuencia provienen de archivos estáticos y modales respectivamente — un conjunto de restricciones no coincidente hace que cada punto sea inviable, lo que la ejecución reporta como una advertencia de métricas faltantes.

optimize_structure_tool(
    path="examples/plate_modal.inp",
    variables={"shell.PLATE.thickness": [2.0, 8.0]},
    constraints=[{"metric": "freq_1_hz", "op": ">", "value": 30.0}],
    n_lhs=5, max_solves=24,
)
# -> best ~3.23 mm, ~-19% mass, f1 = 30.4 Hz

Alcance y honestidad:

  • Solo modelos de lámina/viga. Los sólidos (C3D8) no exponen una tarjeta de geometría escalar, por lo que no hay espesor que adelgazar; use optimización de forma/topología en su lugar.
  • Esto es optimización de dimensionamiento/parámetros, no optimización de topología — adelgaza secciones, no redistribuye material en el espacio.
  • El mejor archivo se escribe junto a la entrada como <stem>.optimized.inp; páselo a export_results_tool para renderizar el diseño optimizado.

Análisis modal

Los archivos *FREQUENCY funcionan con las mismas herramientas. El .dat lo lleva todo: una tabla E I G E N V A L U E O U T P U T (modo, valor propio, rad/s, ciclos/s) seguida de bloques de vectores propios por modo marcados como E I G E N V A L U E N U M B E R N — los vectores reutilizan el formato de fila estático displacements (vx,vy,vz), por lo que las formas de modo se exportan sin tocar el .frd.

read_results_tool(result_path=...)     # -> frequencies: [{mode, eigenvalue,
                                       #     freq_rad_s, freq_hz}], n_modes
export_results_tool(path="examples/cantilever_modal.inp", mode=1)
# -> result_mesh.json holding mode 1's eigenvector (stress-free shape)

Dos notas de física que vale la pena reportar honestamente: una sección doblemente simétrica da pares degenerados (f1 = f2), y los hexaedros C3D8 totalmente integrados se bloquean por cortante en flexión, por lo que las frecuencias son ~5-10% más altas que el cálculo manual de Euler-Bernoulli (examples/cantilever_modal.inp: ccx f1 ~ 502 Hz vs cálculo manual ~ 464 Hz).

Instalación

Desde este directorio (Linux/macOS; adapte la activación del venv en Windows):

uv venv .venv --python 3.11
uv pip install --python .venv/bin/python "mcp>=1.0,<1.8" meshio numpy "python-dotenv>=1,<2"
uv pip install --python .venv/bin/python pytest   # dev only

mcp está fijado por debajo de 1.8: mcp 2.0 eliminó mcp.server.fastmcp (la importación de FastMCP usada aquí y por los otros MCP del hub).

Instale CalculiX por separado (por ejemplo, ccx o ccx_preCICE en su PATH, o establezca CCX_EXE). fea_health le dirá si se detectó el ejecutable.

Ejecución

.venv/bin/python mcp_server.py          # stdio MCP transport

Regístrelo con un cliente MCP usando examples/mcp_config.example.json.

Ejemplo: punto de referencia de voladizo

examples/cantilever.inp es un voladizo de libro de texto público (barra sólida de acero C3D8, empotrada en un extremo, cargada transversalmente en el otro). Regénérelo con:

python3 examples/gen_cantilever.py

Objetivos de verificación por cálculo manual (Euler-Bernoulli, mm-t-s-MPa, P = 100 N): deflexión en la punta ≈ 0.8 mm, tensión en la raíz ≈ 140 MPa. El visor auto-magnifica la pequeña deformación elástica para su visualización.

examples/cantilever_modal.inp es la misma barra con un paso *FREQUENCY de 5 modos: f1 = f2 ≈ 502 Hz (par degenerado), f3 = f4 ≈ 3089 Hz, f5 ≈ 6309 Hz, vs el cálculo manual f1 ≈ 464 Hz (bloqueo por cortante C3D8). El caso del visor models/text-to-cae-calculix-modal renderiza el modo 1.

examples/plate_modal.inp (regenerar con python3 examples/gen_plate_modal.py) es una placa voladiza de lámina S4 construida para dimensionamiento con restricción de frecuencia: ccx f1 = 37.6 Hz a t = 4 mm vs el cálculo manual de Euler-Bernoulli f1 = (1.8751²/2π)(t/L²)√(E/12ρ) ≈ 37.1 Hz, y la ejecución de evitar resonancia anterior aterriza en t = 3.23 mm contra el óptimo analítico t* = 30/9.29 ≈ 3.23 mm.

Pruebas

.venv/bin/python -m pytest

Las pruebas de analizador y exportador se ejecutan sin solucionador. Las pruebas del solucionador se omiten automáticamente cuando ccx no se detecta, por lo que la suite permanece en verde antes de instalar CalculiX.

Contenido

  • mcp_server.py — servidor stdio FastMCP.
  • tools/inp_parser.py — análisis de tarjetas .inp + edición de texto en su lugar.
  • tools/solver.py — subproceso ccx + análisis de resultados .dat.
  • tools/result_exporter.py.dat/.inpresult_mesh.json (formato de visor).
  • tools/optimizer.py — optimización de dimensionamiento en dos etapas (LHS + descenso por coordenadas).
  • examples/ — punto de referencia público de voladizo + generador + ejemplo de configuración MCP.
  • tests/ — suite pytest.

Reglas del repositorio

Confirme solo código fuente reutilizable, ejemplos (puntos de referencia públicos), pruebas y documentación. No confirme el entorno virtual, .env, ni ninguna salida generada del solucionador (.frd, .dat, .sta, .cvg, directorios de trabajo). Los archivos de entrada .inp son fuente y se confirman.