Appendix B. Running the code

Everything reported in this documentation is produced by the package described here and pinned by its test suite. API reference documents the modules themselves; each opens with why its model is what it is, what was tried and rejected, and where the approximations are.

Install

Any of these works; pick whichever fits your setup.

# uv (fastest)
uv venv && uv pip install -e ".[dev,moea]"

# pip
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev,moea]"

# conda
conda env create -f environment.yml && conda activate exlink
pip install -e ".[dev]"

# tox — creates its own envs and runs the suite
tox

# make
make dev && make test

The moea extra pulls in gemseo-pymoo for NSGA-II. Everything except exlink pareto works without it.


Command line and library

exlink analyse                       # the study's result; see --design below
exlink analyse --design published    # the historical baseline design (see Provenance)
exlink plot -o figures               # motion, p-V cycle, torque, mechanism, variables
exlink diagram -o figures            # GEMSEO's N2 chart and XDSM of the coupled problem
exlink animate -o figures/exlink.gif # animated mechanism + live cycle and torque
exlink animate --formulations \
  -o figures/formulations.gif        # each formulation's final design, side by side
exlink refine --design published --save refined.json   # augmented Lagrangian
exlink optimize --save best.json     # differential evolution over the full box
exlink pareto --pop-size 200 --max-gen 60              # NSGA-II front
exlink cycle --module 0.8 --teeth 48 --baseline        # over a schedule of speeds (§5.4)
exlink size --rpm 1400 --bore 0.6                     # tubular members (§5.1)

--design takes published, refined, coupled, range, reliable or a path to a JSON design file. It defaults to reliable — RELIABLE_DESIGN, the design §5.5 arrives at — so every figure in this documentation is produced by the commands above with no arguments beyond an output path.

The commands chain through JSON design files:

exlink optimize --save best.json && exlink refine -d best.json --save final.json
exlink animate -d final.json -o final.gif

As a library:

from exlink import analyse, PUBLISHED_DESIGN
from exlink.scenarios import refine, pareto_front, format_analysis

print(format_analysis(analyse(PUBLISHED_DESIGN)))

outcome = refine(PUBLISHED_DESIGN)          # augmented Lagrangian polish
print(outcome.feasible, outcome.analysis.metrics.efficiency)

front = pareto_front(pop_size=200, max_gen=60)   # NSGA-II

Module map

src/exlink/
  constants.py     engine spec, constraint targets, penalty values
  design.py        the 11-variable design vector and its box bounds
  kinematics.py    closed-form loop-closure inversion  →  λ(θ₁)
  cycle.py         four-phase detection + approximate Atkinson cycle
  loads.py         quasi-static force chain  →  crankshaft torque
  metrics.py       η, φ, H, B, mra, W, g, d, γ
  model.py         analyse(): the whole chain, penalising instead of raising
  disciplines.py   GEMSEO Discipline wrappers
  scenarios.py     design space, constraints, and the five workflows
  plots.py         motion / p-V / torque / mechanism / Pareto figures
  animation.py     animated mechanism: alone, with a live dashboard, or one
                   panel per formulation on a common scale
  cli.py           the `exlink` command

  derivatives.py   exact spectral d/dtheta and d2/dtheta2 of periodic histories
  materials.py     material data, Marin factors, the Goodman line
  dynamics.py      inertia in the load path: the 18x18 equilibrium solve
  sizing.py        internal loads, then static / fatigue / buckling sizing
  coupled.py       the sizing <-> dynamics fixed point, and why it converges
  jacobian.py      exact d/dX of the analysis chain, by forward mode + envelope
  dynamics_jacobian.py   exact derivatives through the coupling itself

  friction.py      journal, ring and mesh losses -> real mechanical efficiency
  gears.py         the 2:1 pair, and the lattice the module imposes on I
  manufacturing.py preferred stock sizes, IT grades, minimum wall thicknesses
  mass_budget.py   the whole engine: crankcase from H x B, flywheel from ripple
  vehicle.py       burn-and-coast road load  ->  kilometres per litre
  performance.py   the full chain, from 11 dimensions to km/L
  robustness.py    ISO 286 tolerance, propagated first-order and by sampling
  formulations.py  coupling strength from the MDA residuals; MDF vs IDF, and
                   the coupling recounted in a Fourier basis
  slidercrank.py   the second mechanism, on identical terms
  synthesis.py     prescribed-motion targets, the constrained fit, and range
                   under every constraint with the target as a fallback

Reproducing the results

result in 5. Results

produced by

the reference designs

python examples/01_analyse_reference.py

the augmented-Lagrangian polish

python examples/03_optimize.py

the efficiency/size trade-off

python examples/04_pareto.py

sizing, dynamics and the singularity result

python examples/05_sizing_and_dynamics.py

the mass budget, loss breakdown and both mechanism comparisons of §5.4

python examples/06_range.py

the N2 chart and the XDSM of §4.8

exlink diagram -o docs/figures

the drive-cycle scores of §5.4

python examples/08_drive_cycle.py

what tubular sections are worth, §5.1

python examples/09_tubular_sections.py

the widened uncertainty model of §5.3

python examples/10_widened_uncertainty.py

the sampling check of §5.3

python examples/11_sampling_check.py

the third point on the dimensionality axis, §5.4

exlink.slidercrank.SliderCrank(offset=...)

the restoration and continuation of §5.5

exlink.restoration.restore, exlink.continuation.reliability_continuation

the topology synthesis of §5.6 and §5.7

python examples/12_topology_synthesis.py

the tolerance study, ISO grades and coupling curve

python examples/07_robustness.py

Tests

pytest -m "not slow"    # fast: physics, grammars, figures
pytest                  # everything, optimizers included
tox                     # across Python 3.10 – 3.12

Every claim above is pinned by a test, including the ones that would be embarrassing to get wrong: that inertia does no net work over a cycle, that burn-and-coast conserves energy, that the Otto cycle reproduces its closed-form efficiency, that ρ = 0 at rest, that stock rounding never shrinks a member, and that both engines complete a cycle in 720° of their crankshaft so the comparison needs no firing-rate correction.

Provenance

The mechanism and the design brief come from an unpublished student study by the author (Université de Technologie de Compiègne, 2015), which set up the kinematics, the idealised cycle, the quasi-static load chain and the efficiency measure, and solved the quasi-static problem in MATLAB. Everything needed to read, run and check this repository is restated here; the document itself is not a citable reference, and the only things taken from it directly are the two parametrisation figures of §3.1 and the two design vectors below.

Two designs carry over from that study as historical baselines, and they are labelled as such wherever they appear:

  • PUBLISHED_DESIGN — the design vector tabulated there. Re-analysed it violates five constraints (notably g = 8.5 mm against a 0.01 mm bound), so it is used as a starting point, not as a result. See exlink/reference.py for why it cannot be the design that produced the properties reported alongside it.

  • REFINED_DESIGN — what an augmented Lagrangian makes of it here: feasible, η = 27.87 %. The quasi-static reference point the rest of the study is measured against.

Everything else — the dynamic load analysis, the sizing disciplines, the coupled MDA, the analytic derivatives, and the GRADIENT_DESIGN and COUPLED_DESIGN results — is new work in this repository.

Mechanism topology after Honda’s EXlink, modified as described in 1. Introduction.


Next: API reference