2. Python environment for CAE automation
PAM-CRASH automation scripts rarely live in isolation. A single workflow may need to parse LS-DYNA or PAM-CRASH keyword files, drive the solver from the command line, post-process THP or DSY result files, and push summary data into a report. Each of those tasks pulls in different third-party libraries, and those libraries evolve at different speeds. Without a controlled Python environment, a script that worked last quarter can break after an unrelated package upgrade. This chapter establishes the environment discipline that every later automation example assumes.
Why a Virtual Environment Is Not Optional
A virtual environment is an isolated Python interpreter plus its own site-packages directory. When activated, python and pip resolve to that environment, so installing or upgrading a package affects only that project. For CAE automation this matters for three concrete reasons:
- Version pinning across solver generations. PAM-CRASH installations are often upgraded on a fixed corporate cadence, while Python libraries such as
numpy,pandas, orlxmlmay be upgraded independently. A pinned environment guarantees the script sees the same library versions regardless of what the solver team installs. - Conflicting dependencies. A mesh-processing library may require
numpy<2.0while a newer plotting library requiresnumpy>=2.0. Separate environments let both coexist. - Reproducibility for audit. Crash simulation results are frequently reviewed months later. A frozen
requirements.txtor lock file lets a colleague rebuild the exact environment that produced a report.
The standard tool is venv, shipped with CPython since 3.3. Create and activate an environment on Windows (the most common PAM-CRASH platform):
py -3.11 -m venv .venv
.venv\Scripts\activate
python -m pip install --upgrade pip
On Linux clusters where PAM-CRASH is often run headless, the equivalent is:
python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
After activation, where python (Windows) or which python (Linux) should point inside .venv. If it still points to a system interpreter, activation failed and every subsequent pip install will pollute the global environment.
Package Management: Pinning, Locking, and Offline Installs
For a CAE automation project, keep a requirements.txt with explicit versions rather than loose ranges. A minimal starting set for PAM-CRASH post-processing looks like this:
numpy==1.26.4
pandas==2.2.2
lxml==5.2.2
matplotlib==3.8.4
pyyaml==6.0.1
Install with pip install -r requirements.txt. To capture the full transitive dependency graph for archival, use pip freeze > requirements.lock. The lock file is what you commit alongside the script; the human-readable requirements.txt is what you edit.
Many engineering workstations sit behind a proxy or have no internet access. In that case, download wheels on a connected machine with pip download -r requirements.txt -d wheels/, copy the wheels/ directory to the target machine, and install offline:
pip install --no-index --find-links=wheels -r requirements.txt
This pattern is common on isolated solver nodes and avoids the "works on my laptop" failure mode entirely.
Integrating with the PAM-CRASH Installation Directory
PAM-CRASH ships its own executables, license utilities, and sometimes a bundled Python. The automation environment should not replace that bundled interpreter; instead, it should call the solver as a subprocess and read its outputs. The integration points are:
| Item | Typical location (Windows) | How automation uses it |
|---|---|---|
| Solver executable | C:\Program Files\ESI\PAM-CRASH\2023.0\bin\pamcrash.exe | Invoked via subprocess.run |
| License server | Set by ESI_LICENSE_FILE or LM_LICENSE_FILE | Read from environment, never hard-coded |
| Result files | Working directory of the run | Parsed by numpy/pandas |
| Bundled Python | ...\tools\python | Left untouched; used only if ESI scripts require it |
Resolve the installation root from an environment variable rather than a literal path, so the same script runs against 2022.0 and 2023.0:
import os, subprocess, pathlib
PAM_ROOT = pathlib.Path(os.environ["PAM_CRASH_HOME"])
solver = PAM_ROOT / "bin" / "pamcrash.exe"
result = subprocess.run(
[str(solver), "-i", "model_input.pc", "-o", "run_01"],
cwd="run_01",
capture_output=True,
text=True,
)
if result.returncode != 0:
raise RuntimeError(result.stderr[-2000:])
Set PAM_CRASH_HOME in the activation script so it is available whenever the environment is active. On Windows, add a set PAM_CRASH_HOME=... line to .venv\Scripts\activate.bat; on Linux, append export PAM_CRASH_HOME=... to .venv/bin/activate. This keeps the solver path out of source code and makes the environment self-describing.
C:\Program Files\ESI\... often fails due to permissions and can be wiped by the next solver upgrade.
Verifying the Environment Before a Run
A short pre-flight check catches most environment problems before a long solver run is wasted. The script below confirms the interpreter, the key packages, and the solver path:
import sys, os, pathlib, importlib
print("Python:", sys.executable)
for pkg in ("numpy", "pandas", "lxml"):
m = importlib.import_module(pkg)
print(f"{pkg}: {m.__version__}")
root = pathlib.Path(os.environ.get("PAM_CRASH_HOME", ""))
solver = root / "bin" / "pamcrash.exe"
print("Solver exists:", solver.is_file())
Expected output shows the interpreter inside .venv, the pinned versions, and Solver exists: True. If sys.executable points to a system Python, the environment was not activated. If Solver exists: False, PAM_CRASH_HOME is unset or wrong. If a package import fails, the lock file was not installed into this environment.
.venv. Configure the IDE's interpreter path explicitly to .venv\Scripts\python.exe (Windows) or .venv/bin/python (Linux).
Practical Notes on Reproducibility
Two habits make the environment genuinely reproducible. First, commit both requirements.txt and requirements.lock to version control; the lock file is the source of truth for rebuilds. Second, record the environment in the run metadata: write sys.version, the output of pip freeze, and the value of PAM_CRASH_HOME into a run_environment.json next to the solver output. When a result is questioned six months later, that file answers "which Python, which libraries, which solver" without guesswork.
With the environment established, subsequent chapters can focus on the automation logic itself — keyword manipulation, batch execution, and result extraction — knowing that the interpreter and dependencies are stable and traceable.