2. Python environment setup for CAE data workflows
CAE data extraction and analysis rarely lives in a single script. A typical workflow pulls nodal displacement from an .odb file, parses a .csv exported from a solver, joins it with material test data, and produces plots for a design review. Each of those steps depends on a different library — numpy, pandas, matplotlib, and often a vendor-specific SDK such as Abaqus's odbAccess or Ansys's pyMAPDL. If those libraries share one global Python installation, a version bump in one project can silently break another. Reproducibility in CAE analysis therefore starts with environment isolation, not with the analysis code itself.
Why Isolation Matters More in CAE Than in Web Development
Simulation post-processing has an unusually wide dependency surface. A single analysis script may need a specific numpy version because a downstream solver wrapper was compiled against it, a pinned h5py version to read a particular HDF5 layout, and a vendor SDK that only supports Python 3.9–3.11. When these constraints collide with a colleague's environment, the failure mode is rarely a clean error — it is a subtly wrong array shape or a silently truncated result set. Isolating each project into its own virtual environment makes the dependency set explicit and testable.
The practical rule: one environment per project, never per machine. A project environment should be reconstructible from a single manifest file, so that a reviewer can rebuild it months later and obtain identical numerical results.
Choosing an Environment Manager
Three tools cover most CAE workflows. venv ships with Python and is sufficient when all dependencies are pure Python or have wheels on PyPI. conda (or the faster mamba) is preferable when the stack includes compiled scientific libraries — scipy, vtk, netCDF4 — or when a vendor SDK requires a specific BLAS build. uv is a newer, very fast resolver that works well for pure-Python extraction pipelines and can also manage the Python interpreter itself.
For a CAE team, the deciding factor is usually the vendor SDK. If the SDK is distributed as a conda package or requires a matching MKL/OpenBLAS, use conda. If it is a plain wheel, venv plus pip is simpler and produces smaller environments.
Building a Reproducible Environment
The following example creates a conda environment for an Abaqus post-processing project. The version pins are illustrative and should be replaced with the versions your solver actually supports.
# environment.yml — project: odb_postprocess
name: odb_postprocess
channels:
- conda-forge
dependencies:
- python=3.10
- numpy=1.24.*
- pandas=2.0.*
- matplotlib=3.7.*
- h5py=3.9.*
- jupyterlab=4.*
- pip
- pip:
- odb-extract==0.4.2 # internal package, pinned by hash below
Create and activate it:
conda env create -f environment.yml
conda activate odb_postprocess
python -c "import numpy, pandas, h5py; print(numpy.__version__)"
The final command is a smoke test. If it prints 1.24.4 (or whatever your pin resolves to) without an ImportError, the core scientific stack is importable. A common failure at this stage is a DLL load failed on Windows, which almost always means a compiled dependency was installed from the wrong channel; reinstalling it from conda-forge resolves it.
numpy=1.24.*) rather than exact patch versions during development, then freeze exact versions with conda env export --no-builds > environment.lock.yml before publishing results. The lock file is what makes a numerical result reproducible; the loose file is what makes development tolerable.
Jupyter for Reproducible Analysis
JupyterLab is the natural interface for CAE post-processing because it interleaves code, plots, and interpretation. But a notebook is only reproducible if its execution order is deterministic. Two habits enforce this:
- Restart and run all before committing. A notebook that only works when cells are run out of order is not a result, it is a session.
- Keep heavy I/O in modules, not cells. Put the
.odbreader inodb_extract/reader.pyand import it. Notebooks should orchestrate, not implement.
Register the project environment as a Jupyter kernel so the notebook always uses the pinned stack:
python -m ipykernel install --user \
--name odb_postprocess \
--display-name "Python (odb_postprocess)"
After this, the kernel appears in JupyterLab's launcher. Selecting it guarantees the notebook runs against the same numpy and h5py versions as the command-line pipeline.
Dependency Flow in a CAE Analysis Project
The diagram below shows how a single project environment mediates between raw solver output, the analysis code, and the reproducible report. The key point is that every arrow passes through the environment boundary — nothing reaches the analysis code without being resolved against the pinned manifest.
Verifying the Setup Before Real Analysis
Before running a full extraction, verify three things. First, that the kernel is the project kernel: in a notebook cell, import sys; print(sys.executable) should print a path inside the environment directory, not /usr/bin/python. Second, that the vendor SDK imports: from odbAccess import openOdb (or the equivalent) should succeed. Third, that a tiny end-to-end read works — open a small .odb, read one frame, print the number of nodes. If that returns a plausible integer, the environment is sound.
pip install inside a conda environment without recording them in environment.yml. A package installed ad hoc will be missing when a colleague rebuilds the environment, and the resulting ModuleNotFoundError will appear only at the moment of result reproduction — the worst possible time.
What to Commit
Commit the loose environment.yml for development and the environment.lock.yml alongside any published result. Commit the notebook with outputs cleared, plus the executed notebook as a build artifact. Do not commit the environment directory itself; it is large, platform-specific, and reconstructible. With this discipline, a CAE analysis performed today can be re-executed next year on a different machine and produce the same numbers — which is the only definition of reproducibility that matters in simulation work.