3. CAE solver landscape
Automating a CAE workflow in Python begins with a clear-eyed inventory of the solvers you intend to drive. A solver is not a single executable; it is a bundle of a physics kernel, a file format contract, a licensing model, and one or more programmatic entry points. Choosing the wrong integration surface — for example, screen-scraping a GUI when a documented Python API exists — creates fragile automation that breaks on every minor release. This chapter maps the solver landscape along four axes: license and distribution model, native input format, execution mode, and integration surface. Understanding these axes lets you predict how much glue code a given solver will require before you write a single line.
Commercial versus open-source solvers
Commercial solvers such as Ansys Mechanical, Abaqus, Nastran (MSC or NX), COMSOL Multiphysics, and STAR-CCM+ ship with vendor-supported APIs, versioned documentation, and regression-tested behavior across releases. Their licensing typically uses a license server (FlexNet or similar), which means an automated run can fail not because of a modeling error but because a token was unavailable. Open-source solvers such as CalculiX, Code_Aster, OpenFOAM, SU2, FEniCS/FEniCSx, and deal.II offer unrestricted execution and source-level transparency, but their input formats and Python bindings vary widely in maturity. A practical rule: commercial solvers reward you with stable APIs but constrain concurrency through licensing; open-source solvers reward you with unlimited parallel runs but require you to validate the build and the input deck yourself.
Input formats and what they imply for automation
The input format determines whether you can generate a model programmatically or must template an existing file. Three families dominate:
- Text decks (Abaqus
.inp, CalculiX.inp, Nastran.bdf, OpenFOAM dictionaries): human-readable, diff-friendly, and easy to generate from Python string templates or dedicated writers. Parameter sweeps are straightforward because you can rewrite a single keyword block. - Binary or hierarchical containers (COMSOL
.mph, STAR-CCM+.sim): not safely editable as text. Automation must go through the vendor API, which manipulates the model in memory and saves a new container. - Structured mesh and field formats (CGNS, VTK/VTU, Exodus II, MED): these carry geometry, mesh, and boundary tags but usually not solver control cards. They pair with a separate solver input file.
For example, a CalculiX deck for a static cantilever can be generated by substituting a thickness parameter into a template:
*NODE
1, 0.0, 0.0, 0.0
2, 100.0, 0.0, 0.0
*ELEMENT, TYPE=C3D8, ELSET=EALL
1, 1, 2, ...
*MATERIAL, NAME=STEEL
*ELASTIC
210000.0, 0.3
*STEP
*STATIC
*BOUNDARY
1, 1, 3, 0.0
*CLOAD
2, 2, -500.0
*END STEP
Here the load -500.0 and the elastic modulus 210000.0 are the natural sweep variables. A Python driver reads a base template, writes a new deck per sample, and launches the solver. The same pattern applies to Nastran and OpenFOAM, though OpenFOAM splits control across controlDict, fvSchemes, and fvSolution, so a sweep may touch several files.
Execution modes
Solvers run in three modes that matter for orchestration:
- Batch/command-line:
ccx job.inp,abaqus job=job.inp interactive,simpleFoam. Python invokes these withsubprocess.run, captures stdout/stderr, and checks the exit code plus a solver-specific success marker (for example,*ERRORabsence in the.datfile, orEndin the OpenFOAM log). - In-process library: FEniCSx, deal.II, and PyMAPDL load the solver into the Python process. No file round-trip is needed, but a crash takes down your driver, so isolate these runs in separate processes when sweeping.
- Server/session: COMSOL
mphserverand STAR-CCM+ run as persistent sessions that accept multiple jobs. This amortizes startup cost but requires connection management and explicit teardown.
Integration surfaces
The integration surface is the contract your Python code depends on. Ranked from most to least robust:
| Surface | Example | Stability | Typical use |
|---|---|---|---|
| Native Python API | PyMAPDL, PyFluent, FEniCSx, compas_fea | High | Model build, solve, post-process in one process |
| Vendor scripting (wrapped) | COMSOL mph, Abaqus abaqus python | Medium-high | Container models, batch parametric runs |
| File templating + CLI | CalculiX, OpenFOAM, SU2 | Medium | Large sweeps, HPC queues |
| GUI automation | pywinauto, pyautogui | Low | Last resort for legacy tools |
Prefer the highest row you can reach. File templating is often the pragmatic choice for open-source solvers because it is transparent and parallelizes trivially, but it demands that you validate the generated deck. A useful safeguard is to run one reference case through the solver, store its key outputs, and re-run it after any template change as a regression check.
Choosing a solver for an automated pipeline
Before committing, answer four questions. Does the solver expose a documented, versioned API or a stable CLI? Can its input be generated without a GUI? Does its license permit the concurrency your sweep needs? And can you detect failure programmatically? A solver that answers "no" to the last question will silently poison an optimization loop with garbage objective values.
The diagram below summarizes how the four axes combine for representative solvers and where the Python integration point sits in each case.
Practical checklist before writing the driver
For each candidate solver, record the following in a short integration note. This note becomes the specification your Python driver must satisfy.
| Field | What to record | Why it matters |
|---|---|---|
| Solver + version | Exact build string | API and format behavior change across releases |
| Input format | Text deck, container, or in-memory | Determines generation strategy |
| Invocation | CLI command or API entry point | Defines the subprocess or import call |
| Success marker | Exit code plus log token | Prevents false positives in sweeps |
| License constraint | Token count / concurrency limit | Sets the sweep's parallelism ceiling |
| Output artifacts | Result files and their parsers | Feeds the objective function |
With this inventory complete, the next step is to wrap each solver behind a uniform Python interface so that the optimization layer never needs to know which solver it is calling. That abstraction — a common solve(parameters) -> results contract — is what makes a multi-solver CAE pipeline maintainable, and it is the subject of the following chapter.