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
| Herramienta | Propósito |
|---|---|
fea_health | Informar la disponibilidad de meshio y el ejecutable ccx detectado. |
parse_inp | Analizar un archivo .inp: nodos, conteos de elementos, secciones de lámina/viga, materiales, cargas. |
list_design_vars_tool | Listar 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_tool | Editar una variable de diseño en su lugar mediante var_id; reemplazo de texto puro, escribe un nuevo .inp. |
run_solver_tool | Ejecutar ccx -i <jobname> sobre un archivo. El éxito ignora el código de salida (ver más abajo). |
read_results_tool | Analizar 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_tool | Exportar 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_tool | Optimizació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 confiable —
ccxdevuelve 0 incluso cuando imprime*ERROR. Éxito = sin*ERRORen stdout y el archivo.statiene una fila de datos y sin tiempo de espera agotado. .datno tiene von Mises — solo 6 componentes de tensión; σ_vm se autocalcula..datno tiene volumen/masa total — calculado a partir de la geometría de la malla ×*DENSITY.- Nunca
meshio.write— elimina cada tarjeta y reescribeB31→B31H(corrompe el archivo).modify_cardhace ediciones de texto puro en su lugar. - Los pasos
*FREQUENCYescriben un.stasolo con encabezado — una solución de valores propios no tiene incrementos, por lo que el éxito también acepta un.datno 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 aexport_results_toolpara 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
mcpestá fijado por debajo de 1.8:mcp2.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— subprocesoccx+ análisis de resultados.dat.tools/result_exporter.py—.dat/.inp→result_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.