Skip to content

perf(scroll): scalar cross-product + lazy nozzle outputs (bit-identical, ~8%) - #110

Merged
ibell merged 1 commit into
masterfrom
pdsim-scalar-force-perf
Jun 10, 2026
Merged

perf(scroll): scalar cross-product + lazy nozzle outputs (bit-identical, ~8%)#110
ibell merged 1 commit into
masterfrom
pdsim-scalar-force-perf

Conversation

@ibell

@ibell ibell commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Two small, bit-identical hot-path optimizations found while profiling examples/scroll_compressor.py. No behaviour change — scroll_compressor.py mdot / volumetric efficiency / adiabatic efficiency are unchanged to every printed digit (mdot 55.175673362688805 g/s, vol-eff 91.95998551975654%, η 74.61003492585036%), verified before/after.

Changes

  1. symm_scroll_geo.SA_forces — replace two np.cross([x,y,0],[a,b,0])[2] calls with the scalar z-component x*b - y*a. Only the z-component is ever used, and np.cross pulls in normalize_axis_tuple + broadcasting machinery for what is a single multiply-subtract.
  2. flow_models.IsentropicNozzle — the default call returns only mdot, but the throat temperature/density, speed of sound, velocity and Mach number were computed on every call. They're now computed lazily, behind the OUTPUT_VELOCITY/OUTPUT_MA guard. mdot is bit-unchanged.

Impact

~8% faster on the full scroll_compressor.py solve (np.cross ~7%, nozzle ~1%), measured best-of-N. Both are pure overhead removal — exact same numerics.

Context

These came out of a profiling exercise (native sampling) showing the scroll solve is dominated by PDSim's own Python/Cython framework + numpy (the EOS is only ~13–20% on modern CoolProp), so small-array-numpy and wasted-compute removals like these are free wins. Larger gains (Cythonizing the per-step callbacks, caching the per-θ geometry kernels) are noted as follow-ups.

🤖 Generated with Claude Code

Two hot-path micro-optimizations on the scroll force/flow path, verified to
leave examples/scroll_compressor.py results unchanged to all printed digits
(mdot 55.175673362688805 g/s, vol-eff 91.95998551975654%, eta 74.61003492585036%):

- symm_scroll_geo.SA_forces: replace two `np.cross([x,y,0],[a,b,0])[2]` calls
  with the scalar z-component (x*b - y*a). np.cross pulls in normalize_axis_tuple
  + broadcasting machinery for what is one multiply-subtract.
- flow_models.IsentropicNozzle: only `mdot` is returned in the default case, so
  the throat-state / speed-of-sound / Mach-number work is now computed lazily
  behind the OUTPUT_VELOCITY/OUTPUT_MA guard instead of on every call.

~8% faster on the full scroll_compressor.py example (np.cross ~7%, nozzle ~1%),
no behaviour change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ibell
ibell merged commit 0c0b440 into master Jun 10, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant