API Reference

Simulator Core

simulator

simulator.cli

simulator.cli.create_sphinx_skeleton(dest=None, *, force=False)[source]

Create a conservative Sphinx skeleton for the vICE simulator package.

Parameters:
  • dest (str | Path | None)

  • force (bool)

Return type:

Path

simulator.cli.build_parser()[source]

Build the vICE command-line parser.

Return type:

ArgumentParser

simulator.cli.main(argv=None)[source]

Run the command-line interface.

Parameters:

argv (Sequence[str] | None)

Return type:

int

simulator.main

simulator.main.main()[source]
Return type:

None

simulator.app

class simulator.app.ICESimulatorApp(root=None)[source]

Bases: object

Simple text-based front-end for the ICE simulator.

This is deliberately console-first so it’s easy to wrap with richer UIs later (PySide6, Tk, web, etc.).

Parameters:

root (Path | None)

run_main_menu()[source]
Return type:

None

simulator.app.run()[source]
Return type:

None

simulator.apis

class simulator.apis.RunRequest(verb: 'str', params: 'Dict[str, Any]'=<factory>, infile: 'Optional[str]' = None, outfile: 'Optional[str]' = None)[source]

Bases: object

Parameters:
  • verb (str)

  • params (Dict[str, Any])

  • infile (str | None)

  • outfile (str | None)

verb: str
params: Dict[str, Any]
infile: str | None = None
outfile: str | None = None
class simulator.apis.RunResult(ok: 'bool', data: 'Dict[str, Any]'=<factory>, reason: 'str' = '')[source]

Bases: object

Parameters:
  • ok (bool)

  • data (Dict[str, Any])

  • reason (str)

ok: bool
data: Dict[str, Any]
reason: str = ''
simulator.apis.run(request)[source]

Dispatch high-level verbs for the simulator CLI / TUI.

Currently supported verbs:
  • “run-sim”: run a cycle simulation from JSON config

  • “list-inputs”: list available JSON inputs under simulator/in

  • “plot-indicator”: generate a P–V HTML plot from a result JSON

Parameters:

request (RunRequest)

Return type:

RunResult

simulator.core

class simulator.core.EngineGeometry(bore_m: 'float', stroke_m: 'float', con_rod_m: 'float', compression_ratio: 'float', piston_pin_offset_m: 'float' = 0.0)[source]

Bases: object

Parameters:
  • bore_m (float)

  • stroke_m (float)

  • con_rod_m (float)

  • compression_ratio (float)

  • piston_pin_offset_m (float)

bore_m: float
stroke_m: float
con_rod_m: float
compression_ratio: float
piston_pin_offset_m: float = 0.0
area()[source]

Piston crown area [m²].

Return type:

float

displacement_volume()[source]

Single-cylinder displacement volume [m³].

Return type:

float

clearance_volume()[source]

Clearance volume [m³].

Return type:

float

volume(crank_deg)[source]

Instantaneous cylinder volume vs crank angle.

Classic slider–crank kinematics, ignoring pin offset for now.

Parameters:

crank_deg (numpy.ndarray)

Return type:

numpy.ndarray

class simulator.core.OperatingConditions(engine_speed_rpm: 'float', air_fuel_ratio: 'float', intake_pressure_Pa: 'float', exhaust_pressure_Pa: 'float', intake_temp_K: 'float', crank_angle_ignition_deg: 'float', combustion_duration_deg: 'float', fuel_id: 'str' = 'gasoline', integration_tolerance: 'float' = 1e-05, crank_step_deg: 'float' = 1.0, egr_mass_fraction: 'float' = 0.0, combustion_efficiency: 'float' = 0.98, pressure_rise_factor: 'float' = 3.0, wiebe_a: 'float' = 5.0, wiebe_m: 'float' = 2.0, compression_polytropic_index: 'float' = 1.32, expansion_polytropic_index: 'float' = 1.25, num_cylinders: 'int' = 1, stroke_type: 'str' = 'four-stroke', friction_model: 'str' = 'fmep-speed', friction_mode: 'str' = 'generic', mechanical_efficiency: 'float' = 0.9, fmep_base_bar: 'float' = 2.0, fmep_speed_coeff_bar_per_krpm: 'float' = 0.12, fmep_speed_quad_bar_per_krpm2: 'float' = 0.0, fmep_load_coeff_bar_per_bar: 'float' = 0.0, ve_model: 'str' = 'gaussian', ve_base: 'float' = 0.9, ve_peak: 'float' = 1.0, ve_min: 'float' = 0.7, ve_N_peak_rpm: 'float' = 3500.0, ve_sigma_N_rpm: 'float' = 1500.0, heat_loss_model: 'str' = 'parametric', heat_loss_k: 'float' = 0.12, heat_loss_ref_speed_rpm: 'float' = 2500.0, heat_loss_exp: 'float' = 0.5, heat_loss_ref_bore_m: 'float' = 0.086, heat_loss_geom_exponent: 'float' = 1.0, combustion_eff_model: 'str' = 'parabolic', combustion_eff_phi_opt: 'float' = 1.0, combustion_eff_k: 'float' = 0.15, combustion_eff_min: 'float' = 0.88, combustion_duration_model: 'str' = 'parabolic', combustion_duration_phi_opt: 'float' = 1.0, combustion_duration_k: 'float' = 2.0, phi_best_for_bsfc: 'float' = 0.9, phi_lean_slope: 'float' = 1.5, phi_rich_slope: 'float' = 1.0, work_scale_factor: 'float' = 2.3)[source]

Bases: object

Parameters:
  • engine_speed_rpm (float)

  • air_fuel_ratio (float)

  • intake_pressure_Pa (float)

  • exhaust_pressure_Pa (float)

  • intake_temp_K (float)

  • crank_angle_ignition_deg (float)

  • combustion_duration_deg (float)

  • fuel_id (str)

  • integration_tolerance (float)

  • crank_step_deg (float)

  • egr_mass_fraction (float)

  • combustion_efficiency (float)

  • pressure_rise_factor (float)

  • wiebe_a (float)

  • wiebe_m (float)

  • compression_polytropic_index (float)

  • expansion_polytropic_index (float)

  • num_cylinders (int)

  • stroke_type (str)

  • friction_model (str)

  • friction_mode (str)

  • mechanical_efficiency (float)

  • fmep_base_bar (float)

  • fmep_speed_coeff_bar_per_krpm (float)

  • fmep_speed_quad_bar_per_krpm2 (float)

  • fmep_load_coeff_bar_per_bar (float)

  • ve_model (str)

  • ve_base (float)

  • ve_peak (float)

  • ve_min (float)

  • ve_N_peak_rpm (float)

  • ve_sigma_N_rpm (float)

  • heat_loss_model (str)

  • heat_loss_k (float)

  • heat_loss_ref_speed_rpm (float)

  • heat_loss_exp (float)

  • heat_loss_ref_bore_m (float)

  • heat_loss_geom_exponent (float)

  • combustion_eff_model (str)

  • combustion_eff_phi_opt (float)

  • combustion_eff_k (float)

  • combustion_eff_min (float)

  • combustion_duration_model (str)

  • combustion_duration_phi_opt (float)

  • combustion_duration_k (float)

  • phi_best_for_bsfc (float)

  • phi_lean_slope (float)

  • phi_rich_slope (float)

  • work_scale_factor (float)

engine_speed_rpm: float
air_fuel_ratio: float
intake_pressure_Pa: float
exhaust_pressure_Pa: float
intake_temp_K: float
crank_angle_ignition_deg: float
combustion_duration_deg: float
fuel_id: str = 'gasoline'
integration_tolerance: float = 1e-05
crank_step_deg: float = 1.0
egr_mass_fraction: float = 0.0
combustion_efficiency: float = 0.98
pressure_rise_factor: float = 3.0
wiebe_a: float = 5.0
wiebe_m: float = 2.0
compression_polytropic_index: float = 1.32
expansion_polytropic_index: float = 1.25
num_cylinders: int = 1
stroke_type: str = 'four-stroke'
friction_model: str = 'fmep-speed'
friction_mode: str = 'generic'
mechanical_efficiency: float = 0.9
fmep_base_bar: float = 2.0
fmep_speed_coeff_bar_per_krpm: float = 0.12
fmep_speed_quad_bar_per_krpm2: float = 0.0
fmep_load_coeff_bar_per_bar: float = 0.0
ve_model: str = 'gaussian'
ve_base: float = 0.9
ve_peak: float = 1.0
ve_min: float = 0.7
ve_N_peak_rpm: float = 3500.0
ve_sigma_N_rpm: float = 1500.0
heat_loss_model: str = 'parametric'
heat_loss_k: float = 0.12
heat_loss_ref_speed_rpm: float = 2500.0
heat_loss_exp: float = 0.5
heat_loss_ref_bore_m: float = 0.086
heat_loss_geom_exponent: float = 1.0
combustion_eff_model: str = 'parabolic'
combustion_eff_phi_opt: float = 1.0
combustion_eff_k: float = 0.15
combustion_eff_min: float = 0.88
combustion_duration_model: str = 'parabolic'
combustion_duration_phi_opt: float = 1.0
combustion_duration_k: float = 2.0
phi_best_for_bsfc: float = 0.9
phi_lean_slope: float = 1.5
phi_rich_slope: float = 1.0
work_scale_factor: float = 2.3
class simulator.core.SimulationResult(crank_deg: 'List[float]', pressure_Pa: 'List[float]', temperature_K: 'List[float]', volume_m3: 'List[float]', mass_fraction_burned: 'List[float]', imep_Pa: 'float | None' = None, imep_bar: 'float | None' = None, indicated_work_per_cycle_J: 'float | None' = None, indicated_power_per_cyl_W: 'float | None' = None, indicated_power_per_cyl_kW: 'float | None' = None, brake_power_per_cyl_W: 'float | None' = None, brake_power_per_cyl_kW: 'float | None' = None, indicated_torque_per_cyl_Nm: 'float | None' = None, brake_torque_per_cyl_Nm: 'float | None' = None, indicated_power_W: 'float | None' = None, indicated_power_kW: 'float | None' = None, indicated_torque_Nm: 'float | None' = None, brake_power_W: 'float | None' = None, brake_power_kW: 'float | None' = None, brake_torque_Nm: 'float | None' = None, bmep_Pa: 'float | None' = None, bmep_bar: 'float | None' = None, friction_power_W: 'float | None' = None, friction_power_kW: 'float | None' = None, fmep_Pa: 'float | None' = None, fmep_bar: 'float | None' = None, mechanical_efficiency_effective: 'float | None' = None, bsfc_g_per_kWh: 'float | None' = None, brake_thermal_efficiency: 'float | None' = None, indicated_thermal_efficiency: 'float | None' = None, cov_imep_percent: 'float | None' = None, peak_pressure_Pa: 'float | None' = None, peak_pressure_bar: 'float | None' = None, crank_deg_peak_pressure: 'float | None' = None, mfb10_deg: 'float | None' = None, mfb50_deg: 'float | None' = None, mfb90_deg: 'float | None' = None, knock_index_proxy: 'float | None' = None, lambda_value: 'float | None' = None, volumetric_efficiency: 'float | None' = None, heat_transfer_eff_factor: 'float | None' = None)[source]

Bases: object

Parameters:
  • crank_deg (List[float])

  • pressure_Pa (List[float])

  • temperature_K (List[float])

  • volume_m3 (List[float])

  • mass_fraction_burned (List[float])

  • imep_Pa (float | None)

  • imep_bar (float | None)

  • indicated_work_per_cycle_J (float | None)

  • indicated_power_per_cyl_W (float | None)

  • indicated_power_per_cyl_kW (float | None)

  • brake_power_per_cyl_W (float | None)

  • brake_power_per_cyl_kW (float | None)

  • indicated_torque_per_cyl_Nm (float | None)

  • brake_torque_per_cyl_Nm (float | None)

  • indicated_power_W (float | None)

  • indicated_power_kW (float | None)

  • indicated_torque_Nm (float | None)

  • brake_power_W (float | None)

  • brake_power_kW (float | None)

  • brake_torque_Nm (float | None)

  • bmep_Pa (float | None)

  • bmep_bar (float | None)

  • friction_power_W (float | None)

  • friction_power_kW (float | None)

  • fmep_Pa (float | None)

  • fmep_bar (float | None)

  • mechanical_efficiency_effective (float | None)

  • bsfc_g_per_kWh (float | None)

  • brake_thermal_efficiency (float | None)

  • indicated_thermal_efficiency (float | None)

  • cov_imep_percent (float | None)

  • peak_pressure_Pa (float | None)

  • peak_pressure_bar (float | None)

  • crank_deg_peak_pressure (float | None)

  • mfb10_deg (float | None)

  • mfb50_deg (float | None)

  • mfb90_deg (float | None)

  • knock_index_proxy (float | None)

  • lambda_value (float | None)

  • volumetric_efficiency (float | None)

  • heat_transfer_eff_factor (float | None)

crank_deg: List[float]
pressure_Pa: List[float]
temperature_K: List[float]
volume_m3: List[float]
mass_fraction_burned: List[float]
imep_Pa: float | None = None
imep_bar: float | None = None
indicated_work_per_cycle_J: float | None = None
indicated_power_per_cyl_W: float | None = None
indicated_power_per_cyl_kW: float | None = None
brake_power_per_cyl_W: float | None = None
brake_power_per_cyl_kW: float | None = None
indicated_torque_per_cyl_Nm: float | None = None
brake_torque_per_cyl_Nm: float | None = None
indicated_power_W: float | None = None
indicated_power_kW: float | None = None
indicated_torque_Nm: float | None = None
brake_power_W: float | None = None
brake_power_kW: float | None = None
brake_torque_Nm: float | None = None
bmep_Pa: float | None = None
bmep_bar: float | None = None
friction_power_W: float | None = None
friction_power_kW: float | None = None
fmep_Pa: float | None = None
fmep_bar: float | None = None
mechanical_efficiency_effective: float | None = None
bsfc_g_per_kWh: float | None = None
brake_thermal_efficiency: float | None = None
indicated_thermal_efficiency: float | None = None
cov_imep_percent: float | None = None
peak_pressure_Pa: float | None = None
peak_pressure_bar: float | None = None
crank_deg_peak_pressure: float | None = None
mfb10_deg: float | None = None
mfb50_deg: float | None = None
mfb90_deg: float | None = None
knock_index_proxy: float | None = None
lambda_value: float | None = None
volumetric_efficiency: float | None = None
heat_transfer_eff_factor: float | None = None
to_dict()[source]
Return type:

Dict[str, Any]

class simulator.core.EngineSimulator(geometry: 'EngineGeometry', operating: 'OperatingConditions')[source]

Bases: object

Parameters:
geometry: EngineGeometry
operating: OperatingConditions
classmethod from_dict(cfg)[source]
Parameters:

cfg (Dict[str, Any])

Return type:

EngineSimulator

property fuel: FuelProperties
property equivalence_ratio: float
property lambda_value: float

Air–fuel ratio relative to stoichiometric (λ).

volumetric_efficiency()[source]

Return volumetric efficiency VE(N) used for trapped mass.

  • ‘constant’: VE = ve_base

  • ‘gaussian’: VE(N) with a Gaussian peak at ve_N_peak_rpm.

Return type:

float

run(cycles=1)[source]
Parameters:

cycles (int)

Return type:

SimulationResult

summary(result=None)[source]
Parameters:

result (SimulationResult | None)

Return type:

Dict[str, Any]

simulator.design

class simulator.design.SweepResult(label: 'str', outfile: 'str')[source]

Bases: object

Parameters:
  • label (str)

  • outfile (str)

label: str
outfile: str
simulator.design.sweep_intake_pressure(base_config_path, pressures_Pa, out_prefix)[source]

Simple design sweep over intake pressure.

For each intake pressure value, we run one cycle and write out a result JSON.

Parameters:
  • base_config_path (str)

  • pressures_Pa (List[float])

  • out_prefix (str)

Return type:

List[SweepResult]

simulator.design.sweep_speed_full_load(base_config_path, speeds_rpm, out_prefix)[source]

Full-load style speed sweep (virtual dyno).

We keep the thermodynamic setup fixed (AFR, pressure-rise factor, etc.) and vary engine speed. Because the core model is 0-D, “full load” here simply means WOT-style fixed inputs; brake power scales with speed.

Each point writes a JSON result and returns a simple label/outfile pair.

Parameters:
  • base_config_path (str)

  • speeds_rpm (List[float])

  • out_prefix (str)

Return type:

List[SweepResult]

simulator.design.sweep_speed_motored(base_config_path, speeds_rpm, out_prefix)[source]

Motored sweep vs speed (virtual motoring test).

We set pressure_rise_factor=0 and combustion_efficiency=0 so the cycle is pure compression/expansion + pumping. That mimics dyno motoring tests used to derive friction / pumping maps.

Parameters:
  • base_config_path (str)

  • speeds_rpm (List[float])

  • out_prefix (str)

Return type:

List[SweepResult]

simulator.fuels

class simulator.fuels.FuelProperties(id, name, afr_stoich, LHV_J_per_kg, rho_kg_per_m3)[source]

Bases: object

Basic fuel properties for simple heat-release scaling.

This is not a full chemical-equilibrium model, just enough to: - define a stoichiometric AFR reference, and - scale heat release by LHV across fuels.

Parameters:
  • id (str)

  • name (str)

  • afr_stoich (float)

  • LHV_J_per_kg (float)

  • rho_kg_per_m3 (float)

id: str
name: str
afr_stoich: float
LHV_J_per_kg: float
rho_kg_per_m3: float
simulator.fuels.get_fuel(fuel_id)[source]
Parameters:

fuel_id (str)

Return type:

FuelProperties

simulator.io

simulator.io.ensure_dir_for(path)[source]
Parameters:

path (str | Path)

Return type:

None

simulator.io.load_json(path)[source]
Parameters:

path (str | Path)

Return type:

Dict[str, Any]

simulator.io.save_json(path, data)[source]
Parameters:
  • path (str | Path)

  • data (Dict[str, Any])

Return type:

None

simulator.io.list_input_files()[source]
Return type:

List[str]

simulator.io.default_plot_path(result_path, kind='pv')[source]
Parameters:
  • result_path (str | Path)

  • kind (str)

Return type:

str

simulator.io.plot_indicator_pv(result_path)[source]
Parameters:

result_path (str | Path)

Return type:

plotly.graph_objects.Figure

simulator.turbo

class simulator.turbo.TurboConfig(enabled=True, p_amb_bar=1.013, T_amb_K=298.15, p_manifold_target_bar=2.0, N_idle_rpm=1000.0, N_full_boost_rpm=2000.0, compressor_efficiency=0.72, gamma_air=1.4, cp_air_J_per_kgK=1005.0, R_air_J_per_kgK=287.0, intercooler_effectiveness=0.7, volumetric_efficiency=0.9)[source]

Bases: object

Mean‑value turbocharger configuration parsed from JSON.

This is intentionally simple and algebraic. It represents a single turbocharger feeding the intake manifold of the engine.

The key design decision for v0 is that boost is prescribed via a smooth schedule vs RPM (to mimic wastegate / VGT behaviour), rather than solved from a turbine/compressor power balance.

Parameters:
  • enabled (bool)

  • p_amb_bar (float)

  • T_amb_K (float)

  • p_manifold_target_bar (float)

  • N_idle_rpm (float)

  • N_full_boost_rpm (float)

  • compressor_efficiency (float)

  • gamma_air (float)

  • cp_air_J_per_kgK (float)

  • R_air_J_per_kgK (float)

  • intercooler_effectiveness (float)

  • volumetric_efficiency (float)

enabled: bool = True
p_amb_bar: float = 1.013
T_amb_K: float = 298.15
p_manifold_target_bar: float = 2.0
N_idle_rpm: float = 1000.0
N_full_boost_rpm: float = 2000.0
compressor_efficiency: float = 0.72
gamma_air: float = 1.4
cp_air_J_per_kgK: float = 1005.0
R_air_J_per_kgK: float = 287.0
intercooler_effectiveness: float = 0.7
volumetric_efficiency: float = 0.9
classmethod from_config(cfg)[source]

Build from a full engine JSON dict (top‑level).

Looks for a turbo block; falls back to operating for volumetric efficiency if not present there.

Parameters:

cfg (Mapping[str, Any])

Return type:

TurboConfig

boost_pressure_ratio(N_rpm)[source]

Return compressor pressure ratio PR = p2/p1 at a given RPM.

We use a simple piecewise‑linear schedule:

  • N <= N_idle → PR = 1.0 (no boost)

  • N >= N_full → PR = p_manifold_target / p_amb

  • otherwise → linear interpolation between 1.0 and PR_full

Parameters:

N_rpm (float)

Return type:

float

manifold_state_from_PR(PR)[source]

Return (p2_bar, T2_ic_K) from a given PR using a simple model.

Steps:

  1. Compressor isentropic outlet temperature:

    T2s = T1 * PR^{(γ−1)/γ}

  2. Actual compressor outlet temperature:

    T2 = T1 + (T2s − T1) / η_c

  3. Intercooler with effectiveness ε:
    T3 = T2 − ε (T2 − T1)

    = T1 + (1 − ε) (T2 − T1)

Parameters:

PR (float)

Return type:

Tuple[float, float]

class simulator.turbo.TurboMatchPoint(speed_rpm, na_bmep_bar=None, na_torque_Nm=None, na_power_kW=None, na_bsfc_g_per_kWh=None, na_eta_b_th=None, pr_c=None, p_int_bar=None, T_int_K=None, m_dot_air_kg_per_s=None, tb_bmep_bar=None, tb_torque_Nm=None, tb_power_kW=None, tb_bsfc_g_per_kWh=None, tb_eta_b_th=None, m_dot_corr_kg_per_s=None)[source]

Bases: object

One steady‑state operating point for NA and turbocharged cases.

Parameters:
  • speed_rpm (float)

  • na_bmep_bar (float | None)

  • na_torque_Nm (float | None)

  • na_power_kW (float | None)

  • na_bsfc_g_per_kWh (float | None)

  • na_eta_b_th (float | None)

  • pr_c (float | None)

  • p_int_bar (float | None)

  • T_int_K (float | None)

  • m_dot_air_kg_per_s (float | None)

  • tb_bmep_bar (float | None)

  • tb_torque_Nm (float | None)

  • tb_power_kW (float | None)

  • tb_bsfc_g_per_kWh (float | None)

  • tb_eta_b_th (float | None)

  • m_dot_corr_kg_per_s (float | None)

speed_rpm: float
na_bmep_bar: float | None = None
na_torque_Nm: float | None = None
na_power_kW: float | None = None
na_bsfc_g_per_kWh: float | None = None
na_eta_b_th: float | None = None
pr_c: float | None = None
p_int_bar: float | None = None
T_int_K: float | None = None
m_dot_air_kg_per_s: float | None = None
tb_bmep_bar: float | None = None
tb_torque_Nm: float | None = None
tb_power_kW: float | None = None
tb_bsfc_g_per_kWh: float | None = None
tb_eta_b_th: float | None = None
m_dot_corr_kg_per_s: float | None = None
to_dict()[source]
Return type:

Dict[str, Any]

simulator.turbo.match_turbo_over_speeds(base_cfg_path, speeds_rpm, compare_na=True)[source]

Run NA and turbocharged sweeps over a list of speeds.

Parameters:
  • base_cfg_path (str | os.PathLike[str]) – Path to your existing engine JSON (geometry + operating + optional turbo block).

  • speeds_rpm (Sequence[float]) – List of engine speeds [rpm].

  • compare_na (bool) – If True, we also run a baseline NA case at each speed using the original intake conditions from the JSON.

Returns:

  • “config” → a copy of the turbo config used

  • ”speeds_rpm” → list of speeds

  • ”points” → list of TurboMatchPoint.to_dict()

Return type:

A dict with

simulator.utils

simulator.utils.ensure_dir(path)[source]
Parameters:

path (str | Path)

Return type:

None

simulator.utils.dataclass_from_dict(cls, data)[source]
Parameters:
  • cls (Type[T])

  • data (Dict[str, Any])

Return type:

T

simulator.utils.load_json(path)[source]
Parameters:

path (str | Path)

Return type:

dict

simulator.utils.save_json(path, data)[source]
Parameters:
  • path (str | Path)

  • data (dict)

Return type:

None

simulator.utils.log_call(func)[source]
Parameters:

func (Callable[[...], T])

Return type:

Callable[[…], T]

simulator.pumps

simulator.pumps.affinity

class simulator.pumps.affinity.AffinityScale(reference_speed_rpm, target_speed_rpm)[source]

Bases: object

Scale factor between a reference pump speed and a target pump speed.

Parameters:
  • reference_speed_rpm (float)

  • target_speed_rpm (float)

reference_speed_rpm: float
target_speed_rpm: float
property ratio: float
flow_to_reference(flow_at_target)[source]
Parameters:

flow_at_target (float)

Return type:

float

flow_from_reference(flow_at_reference)[source]
Parameters:

flow_at_reference (float)

Return type:

float

head_from_reference(head_at_reference)[source]
Parameters:

head_at_reference (float)

Return type:

float

power_from_reference(power_at_reference)[source]
Parameters:

power_at_reference (float)

Return type:

float

simulator.pumps.cavitation

class simulator.pumps.cavitation.SuctionState(fixed_npsha_ft=None, absolute_pressure_kPa=None, vapor_pressure_kPa=None, rho_kg_per_m3=1000.0, suction_velocity_m_per_s=0.0, suction_elevation_m=0.0, suction_losses_m=0.0, suction_loss_k_ft_per_flow2=0.0, suction_loss_k_m_per_flow2=0.0)[source]

Bases: object

Suction-side state used to estimate NPSH available.

The simplest path is to provide fixed_npsha_ft in the input JSON. If it is not provided, the calculation uses absolute suction pressure, vapor pressure, suction velocity, elevation, and suction-side losses.

For RPM sweeps, the optional flow-dependent loss coefficients make the model more realistic:

suction_loss_k_ft_per_flow2

Additional suction loss in feet: h_loss = K * Q**2. The flow unit is the native pump/system flow unit for the run, usually gpm.

suction_loss_k_m_per_flow2

Same idea, but coefficient is expressed in meters of loss.

These coefficients are intentionally unit-light because the pump package is curve-first: if the pump/system curves use gpm, then K is ft/gpm^2 or m/gpm^2; if they use 1000_gal_per_min, then K follows that curve unit.

Parameters:
  • fixed_npsha_ft (float | None)

  • absolute_pressure_kPa (float | None)

  • vapor_pressure_kPa (float | None)

  • rho_kg_per_m3 (float)

  • suction_velocity_m_per_s (float)

  • suction_elevation_m (float)

  • suction_losses_m (float)

  • suction_loss_k_ft_per_flow2 (float)

  • suction_loss_k_m_per_flow2 (float)

fixed_npsha_ft: float | None = None
absolute_pressure_kPa: float | None = None
vapor_pressure_kPa: float | None = None
rho_kg_per_m3: float = 1000.0
suction_velocity_m_per_s: float = 0.0
suction_elevation_m: float = 0.0
suction_losses_m: float = 0.0
suction_loss_k_ft_per_flow2: float = 0.0
suction_loss_k_m_per_flow2: float = 0.0
classmethod from_dict(data)[source]
Parameters:

data (Mapping[str, Any] | None)

Return type:

SuctionState

npsha_ft(flow=None)[source]

Return NPSH available [ft].

Parameters:

flow (float | None) – Optional operating flow in the native pump/system flow unit. When provided, any configured K*Q^2 suction-loss terms are subtracted from NPSHA. fixed_npsha_ft remains fixed by design and bypasses the calculated model.

Return type:

float | None

to_dict()[source]
Return type:

dict[str, Any]

simulator.pumps.cavitation.npsh_margin_ft(npsha_ft, npshr_ft)[source]
Parameters:
  • npsha_ft (float | None)

  • npshr_ft (float | None)

Return type:

float | None

simulator.pumps.combined

class simulator.pumps.combined.CombinedPumpOperatingPoint(pump_name, arrangement, number_of_pumps, pump_speed_rpm, engine_speed_rpm, flow_total, flow_total_gpm, flow_per_pump, flow_per_pump_gpm, head_combined_ft, head_system_ft, head_per_pump_ft, efficiency_per_pump, water_hp_total, brake_hp_total, brake_kw_total, brake_hp_per_pump, brake_kw_per_pump, npsha_ft, npshr_per_pump_ft, npsh_margin_ft, bep_flow_per_pump, bep_ratio_per_pump, status)[source]

Bases: object

Operating point for an identical-pump series/parallel arrangement.

Parameters:
  • pump_name (str)

  • arrangement (str)

  • number_of_pumps (int)

  • pump_speed_rpm (float)

  • engine_speed_rpm (float | None)

  • flow_total (float)

  • flow_total_gpm (float)

  • flow_per_pump (float)

  • flow_per_pump_gpm (float)

  • head_combined_ft (float)

  • head_system_ft (float)

  • head_per_pump_ft (float)

  • efficiency_per_pump (float | None)

  • water_hp_total (float)

  • brake_hp_total (float | None)

  • brake_kw_total (float | None)

  • brake_hp_per_pump (float | None)

  • brake_kw_per_pump (float | None)

  • npsha_ft (float | None)

  • npshr_per_pump_ft (float | None)

  • npsh_margin_ft (float | None)

  • bep_flow_per_pump (float | None)

  • bep_ratio_per_pump (float | None)

  • status (str)

pump_name: str
arrangement: str
number_of_pumps: int
pump_speed_rpm: float
engine_speed_rpm: float | None
flow_total: float
flow_total_gpm: float
flow_per_pump: float
flow_per_pump_gpm: float
head_combined_ft: float
head_system_ft: float
head_per_pump_ft: float
efficiency_per_pump: float | None
water_hp_total: float
brake_hp_total: float | None
brake_kw_total: float | None
brake_hp_per_pump: float | None
brake_kw_per_pump: float | None
npsha_ft: float | None
npshr_per_pump_ft: float | None
npsh_margin_ft: float | None
bep_flow_per_pump: float | None
bep_ratio_per_pump: float | None
status: str
to_dict()[source]
Return type:

dict[str, Any]

class simulator.pumps.combined.BepSpeedResult(pump_name, possible, reason, reference_speed_rpm, target_speed_rpm, speed_ratio, speed_ratio_squared, bep_flow_reference, bep_head_reference_ft, target_bep_flow, target_bep_flow_gpm, target_bep_head_ft, system_head_at_target_bep_ft, residual_ft, equation)[source]

Bases: object

Result for the speed needed to put a pump on its scaled BEP.

Parameters:
  • pump_name (str)

  • possible (bool)

  • reason (str)

  • reference_speed_rpm (float)

  • target_speed_rpm (float | None)

  • speed_ratio (float | None)

  • speed_ratio_squared (float | None)

  • bep_flow_reference (float | None)

  • bep_head_reference_ft (float | None)

  • target_bep_flow (float | None)

  • target_bep_flow_gpm (float | None)

  • target_bep_head_ft (float | None)

  • system_head_at_target_bep_ft (float | None)

  • residual_ft (float | None)

  • equation (str)

pump_name: str
possible: bool
reason: str
reference_speed_rpm: float
target_speed_rpm: float | None
speed_ratio: float | None
speed_ratio_squared: float | None
bep_flow_reference: float | None
bep_head_reference_ft: float | None
target_bep_flow: float | None
target_bep_flow_gpm: float | None
target_bep_head_ft: float | None
system_head_at_target_bep_ft: float | None
residual_ft: float | None
equation: str
to_dict()[source]
Return type:

dict[str, Any]

simulator.pumps.combined.match_combined_system(pump, system, pump_speed_rpm, *, arrangement, number_of_pumps=2, suction=None, engine_speed_rpm=None, npsh_margin_required_ft=3.0, preferred_bep_min=0.85, preferred_bep_max=1.1, acceptable_bep_min=0.7, acceptable_bep_max=1.25)[source]

Match identical pumps in series or parallel against a system curve.

Parameters:
  • pump (CentrifugalWaterPump)

  • system (QuadraticSystemCurve)

  • pump_speed_rpm (float)

  • arrangement (str)

  • number_of_pumps (int)

  • suction (SuctionState | None)

  • engine_speed_rpm (float | None)

  • npsh_margin_required_ft (float)

  • preferred_bep_min (float)

  • preferred_bep_max (float)

  • acceptable_bep_min (float)

  • acceptable_bep_max (float)

Return type:

CombinedPumpOperatingPoint

simulator.pumps.combined.bep_speed_to_match_system(pump, system)[source]

Return the pump speed needed for the scaled BEP to lie on the system curve.

This is the programmatic form of Frank White Example 11.6 part (b). The closed-form solution is exact for a quadratic system curve with the same flow unit as the pump curve:

H_bep*r^2 = H_static + K*(Q_bep*r)^2

where r = n_target / n_reference.

Parameters:
Return type:

BepSpeedResult

simulator.pumps.combined.write_combined_json(path, payload)[source]
Parameters:
  • path (str | Path)

  • payload (Mapping[str, Any])

Return type:

None

simulator.pumps.combined.write_combined_csv(path, points)[source]
Parameters:
Return type:

None

simulator.pumps.curves

class simulator.pumps.curves.Curve1D(name, kind, points=(), coefficients_desc=(), extrapolate=False)[source]

Bases: object

One-dimensional curve with either tabulated points or a polynomial.

Supported JSON forms

Point curve:

{"kind": "points", "points": [[0, 55], [20, 52], [40, 45]]}

Polynomial curve, coefficients in descending powers:

{"kind": "polynomial", "coefficients_desc": [-0.26, 0.0, 490.0]}

Notes

Point curves use linear interpolation. Values outside the point range are clamped by default because supplier maps are normally not valid outside their tested range. Set extrapolate=true in JSON to allow endpoint-slope extrapolation.

name: str
kind: str
points: tuple[tuple[float, float], ...] = ()
coefficients_desc: tuple[float, ...] = ()
extrapolate: bool = False
classmethod from_dict(name, data)[source]
Parameters:
  • name (str)

  • data (Mapping[str, Any] | Sequence[Sequence[float | int]])

Return type:

Curve1D

x_min()[source]
Return type:

float | None

x_max()[source]
Return type:

float | None

y(x)[source]
Parameters:

x (float)

Return type:

float

sample(n=101, *, x_min=None, x_max=None)[source]
Parameters:
  • n (int)

  • x_min (float | None)

  • x_max (float | None)

Return type:

list[dict[str, float]]

Parameters:
  • name (str)

  • kind (str)

  • points (tuple[tuple[float, float], ...])

  • coefficients_desc (tuple[float, ...])

  • extrapolate (bool)

simulator.pumps.power

simulator.pumps.power.flow_to_gpm(flow, flow_unit)[source]

Convert a flow value from a supported unit to US gal/min.

Parameters:
  • flow (float) – Flow value in the native pump-curve unit.

  • flow_unit (str) – Unit string from the pump JSON, for example "gpm" or "1000_gal_per_min".

Returns:

Flow in US gal/min.

Return type:

float

Raises:

ValueError – If the unit is unknown. This is intentional: silently treating a large-pump chart value of 15.2 as 15.2 gpm is a thousand-fold error.

simulator.pumps.power.water_horsepower_gpm_ft(flow_gpm, head_ft, specific_gravity=1.0)[source]

Return hydraulic horsepower for US customary pump data.

Formula:

WHP = Q_gpm * H_ft * SG / 3960

Parameters:
  • flow_gpm (float)

  • head_ft (float)

  • specific_gravity (float)

Return type:

float

simulator.pumps.power.water_horsepower_from_curve_flow(flow, flow_unit, head_ft, specific_gravity=1.0)[source]

Return water horsepower using a pump curve’s native flow unit.

Parameters:
  • flow (float)

  • flow_unit (str)

  • head_ft (float)

  • specific_gravity (float)

Return type:

float

simulator.pumps.power.brake_horsepower_from_efficiency(water_hp, efficiency)[source]
Parameters:
  • water_hp (float)

  • efficiency (float | None)

Return type:

float | None

simulator.pumps.power.hp_to_kw(hp)[source]
Parameters:

hp (float | None)

Return type:

float | None

simulator.pumps.pump_map

class simulator.pumps.pump_map.DigitizedPumpFamilyMap(name, source_note, reference_speed_rpm, flow_unit, head_unit, npsh_unit, diameter_head_curves, npshr_curve, efficiency_contours, brake_hp_lines, raw)[source]

Bases: object

Digitized multi-curve pump-family map.

Parameters:
  • name (str)

  • source_note (str)

  • reference_speed_rpm (float)

  • flow_unit (str)

  • head_unit (str)

  • npsh_unit (str)

  • diameter_head_curves (dict[str, Curve1D])

  • npshr_curve (Curve1D | None)

  • efficiency_contours (dict[str, tuple[tuple[float, float], ...]])

  • brake_hp_lines (dict[str, tuple[tuple[float, float], ...]])

  • raw (dict[str, Any])

name: str
source_note: str
reference_speed_rpm: float
flow_unit: str
head_unit: str
npsh_unit: str
diameter_head_curves: dict[str, Curve1D]
npshr_curve: Curve1D | None
efficiency_contours: dict[str, tuple[tuple[float, float], ...]]
brake_hp_lines: dict[str, tuple[tuple[float, float], ...]]
raw: dict[str, Any]
classmethod from_dict(data)[source]
Parameters:

data (Mapping[str, Any])

Return type:

DigitizedPumpFamilyMap

classmethod from_json(path)[source]
Parameters:

path (str | Path)

Return type:

DigitizedPumpFamilyMap

available_diameters()[source]
Return type:

list[str]

to_summary_dict()[source]
Return type:

dict[str, Any]

extract_pump(diameter_key, *, name=None, bep_flow=None, bep_head=None, efficiency_curve=None, npshr_curve=None, specific_gravity=1.0)[source]

Extract one impeller head curve as a normal solver pump.

Efficiency contours are not automatically converted into an efficiency curve because they are 2-D paths. For solver work, pass a dedicated efficiency curve or use a separate single-pump JSON with an eta(Q) cut.

Parameters:
  • diameter_key (str)

  • name (str | None)

  • bep_flow (float | None)

  • bep_head (float | None)

  • efficiency_curve (Curve1D | None)

  • npshr_curve (Curve1D | None)

  • specific_gravity (float)

Return type:

CentrifugalWaterPump

simulator.pumps.pump_map.load_pump_family_json(path)[source]
Parameters:

path (str | Path)

Return type:

DigitizedPumpFamilyMap

simulator.pumps.system_curve

class simulator.pumps.system_curve.QuadraticSystemCurve(static_head_ft=0.0, k=0.0, exponent=2.0, flow_unit='gpm', head_unit='ft')[source]

Bases: object

System curve H = H_static + K Q^exponent.

For turbulent piping and cooling passages, exponent=2 is the usual first model. Units are intentionally tied to the input data: if Q is in gpm and H is in ft, then K has units ft / gpm^2. For Frank White Example 11.6, Q is in thousands of gal/min, so K has units ft / (1000 gal/min)^2.

Parameters:
  • static_head_ft (float)

  • k (float)

  • exponent (float)

  • flow_unit (str)

  • head_unit (str)

static_head_ft: float = 0.0
k: float = 0.0
exponent: float = 2.0
flow_unit: str = 'gpm'
head_unit: str = 'ft'
classmethod from_dict(data)[source]
Parameters:

data (Mapping[str, Any])

Return type:

QuadraticSystemCurve

head_ft(flow)[source]
Parameters:

flow (float)

Return type:

float

to_dict()[source]
Return type:

dict[str, Any]

simulator.pumps.water_pump

class simulator.pumps.water_pump.CentrifugalWaterPump(name: 'str', reference_speed_rpm: 'float', flow_unit: 'str', head_unit: 'str', head_curve: 'Curve1D', efficiency_curve: 'Curve1D | None' = None, npshr_curve: 'Curve1D | None' = None, bep_flow: 'float | None' = None, bep_head: 'float | None' = None, specific_gravity: 'float' = 1.0, valid_flow_min: 'float | None' = None, valid_flow_max: 'float | None' = None)[source]

Bases: object

Parameters:
  • name (str)

  • reference_speed_rpm (float)

  • flow_unit (str)

  • head_unit (str)

  • head_curve (Curve1D)

  • efficiency_curve (Curve1D | None)

  • npshr_curve (Curve1D | None)

  • bep_flow (float | None)

  • bep_head (float | None)

  • specific_gravity (float)

  • valid_flow_min (float | None)

  • valid_flow_max (float | None)

name: str
reference_speed_rpm: float
flow_unit: str
head_unit: str
head_curve: Curve1D
efficiency_curve: Curve1D | None = None
npshr_curve: Curve1D | None = None
bep_flow: float | None = None
bep_head: float | None = None
specific_gravity: float = 1.0
valid_flow_min: float | None = None
valid_flow_max: float | None = None
classmethod from_dict(data)[source]
Parameters:

data (Mapping[str, Any])

Return type:

CentrifugalWaterPump

classmethod from_json(path)[source]
Parameters:

path (str | Path)

Return type:

CentrifugalWaterPump

speed_scale(pump_speed_rpm)[source]
Parameters:

pump_speed_rpm (float)

Return type:

AffinityScale

head_ft(flow, pump_speed_rpm=None)[source]
Parameters:
  • flow (float)

  • pump_speed_rpm (float | None)

Return type:

float

efficiency(flow, pump_speed_rpm=None)[source]
Parameters:
  • flow (float)

  • pump_speed_rpm (float | None)

Return type:

float | None

npshr_ft(flow, pump_speed_rpm=None)[source]
Parameters:
  • flow (float)

  • pump_speed_rpm (float | None)

Return type:

float | None

bep_flow_at_speed(pump_speed_rpm)[source]
Parameters:

pump_speed_rpm (float)

Return type:

float | None

flow_bounds_at_speed(pump_speed_rpm)[source]
Parameters:

pump_speed_rpm (float)

Return type:

tuple[float, float]

to_summary_dict()[source]
Return type:

dict[str, Any]

class simulator.pumps.water_pump.PumpOperatingPoint(pump_name: 'str', pump_speed_rpm: 'float', engine_speed_rpm: 'float | None', flow: 'float', flow_gpm: 'float', head_pump_ft: 'float', head_system_ft: 'float', efficiency: 'float | None', water_hp: 'float', brake_hp: 'float | None', brake_kw: 'float | None', npsha_ft: 'float | None', npshr_ft: 'float | None', npsh_margin_ft: 'float | None', bep_flow: 'float | None', bep_ratio: 'float | None', status: 'str')[source]

Bases: object

Parameters:
  • pump_name (str)

  • pump_speed_rpm (float)

  • engine_speed_rpm (float | None)

  • flow (float)

  • flow_gpm (float)

  • head_pump_ft (float)

  • head_system_ft (float)

  • efficiency (float | None)

  • water_hp (float)

  • brake_hp (float | None)

  • brake_kw (float | None)

  • npsha_ft (float | None)

  • npshr_ft (float | None)

  • npsh_margin_ft (float | None)

  • bep_flow (float | None)

  • bep_ratio (float | None)

  • status (str)

pump_name: str
pump_speed_rpm: float
engine_speed_rpm: float | None
flow: float
flow_gpm: float
head_pump_ft: float
head_system_ft: float
efficiency: float | None
water_hp: float
brake_hp: float | None
brake_kw: float | None
npsha_ft: float | None
npshr_ft: float | None
npsh_margin_ft: float | None
bep_flow: float | None
bep_ratio: float | None
status: str
to_dict()[source]
Return type:

dict[str, Any]

simulator.pumps.water_pump.load_system_json(path)[source]
Parameters:

path (str | Path)

Return type:

dict[str, Any]

simulator.pumps.water_pump.match_system(pump, system, pump_speed_rpm, *, suction=None, engine_speed_rpm=None, npsh_margin_required_ft=3.0, preferred_bep_min=0.85, preferred_bep_max=1.1, acceptable_bep_min=0.7, acceptable_bep_max=1.25)[source]
Parameters:
  • pump (CentrifugalWaterPump)

  • system (QuadraticSystemCurve)

  • pump_speed_rpm (float)

  • suction (SuctionState | None)

  • engine_speed_rpm (float | None)

  • npsh_margin_required_ft (float)

  • preferred_bep_min (float)

  • preferred_bep_max (float)

  • acceptable_bep_min (float)

  • acceptable_bep_max (float)

Return type:

PumpOperatingPoint

simulator.pumps.water_pump.rpm_sweep(pump, system, *, engine_rpm_min, engine_rpm_max, engine_rpm_step, pulley_ratio=1.0, suction=None, npsh_margin_required_ft=3.0, preferred_bep_min=0.85, preferred_bep_max=1.1, acceptable_bep_min=0.7, acceptable_bep_max=1.25)[source]
Parameters:
  • pump (CentrifugalWaterPump)

  • system (QuadraticSystemCurve)

  • engine_rpm_min (float)

  • engine_rpm_max (float)

  • engine_rpm_step (float)

  • pulley_ratio (float)

  • suction (SuctionState | None)

  • npsh_margin_required_ft (float)

  • preferred_bep_min (float)

  • preferred_bep_max (float)

  • acceptable_bep_min (float)

  • acceptable_bep_max (float)

Return type:

list[PumpOperatingPoint]

simulator.pumps.water_pump.write_points_json(path, payload)[source]
Parameters:
  • path (str | Path)

  • payload (Mapping[str, Any])

Return type:

None

simulator.pumps.water_pump.write_points_csv(path, points)[source]
Parameters:
Return type:

None

Thermochemistry Core

simulator.thermo.equilibrium

simulator.thermo.equilibrium.parse_empirical_formula(formula)[source]

Parse a very small subset of chemical formulas (C_a H_b O_c N_d).

This is intentionally limited but covers common fuels like CH4, C8H18, CH3OH, C2H5OH, etc.

Examples

>>> parse_empirical_formula("C8H18")
{'C': 8, 'H': 18}
Parameters:

formula (str)

Return type:

Dict[str, int]

simulator.thermo.equilibrium.stoich_O2_for_complete_combustion(fuel_formula)[source]

Return stoichiometric moles of O2 per mole of fuel.

Assumes complete conversion of C→CO2 and H→H2O and any O in the fuel contributes its share.

Parameters:

fuel_formula (str)

Return type:

float

class simulator.thermo.equilibrium.IdealEquilibriumResult(T_ad, p, burned_state, species_moles)[source]

Bases: object

Result of the simple equilibrium calculation.

This is not a full Gibbs-minimisation model. It assumes:

  • One global reaction with complete combustion to CO2 and H2O.

  • No dissociation or minor species.

  • Air = O2 + 3.76 N2.

Parameters:
  • T_ad (float)

  • p (float)

  • burned_state (ThermoState)

  • species_moles (Dict[str, float])

T_ad: float
p: float
burned_state: ThermoState
species_moles: Dict[str, float]
simulator.thermo.equilibrium.ideal_adiabatic_flame(fuel_name, phi, p, T_intake, afr_stoich, backend='legacy', mechanism=None, fuel_species=None)[source]

Compute adiabatic flame state for a selected equilibrium backend.

Parameters:
  • fuel_name (str) – Fuel identifier used by the selected backend. For the legacy backend, this is a species key in SPECIES_DB such as C8H18 or CH3OH. For the ideal backend, this is a fuel key in simulator.fuels.FUEL_DB such as gasoline, methanol, or e85. For the cantera backend, this value is only a label.

  • phi (float) – Equivalence ratio.

  • p (float) – Pressure in pascals.

  • T_intake (float) – Unburned-gas temperature in kelvin.

  • afr_stoich (float) – Stoichiometric air-fuel ratio by mass. This value is used by the legacy backend. The ideal backend reads the stoichiometric value from simulator.fuels.

  • backend (BackendType, optional) – Equilibrium backend. Use legacy for the original complete- combustion model, ideal for the LHV plus constant-cp energy balance, or cantera for Cantera HP equilibrium.

  • mechanism (str or None, optional) – Cantera mechanism file, for example gri30.yaml. This is used only by the cantera backend.

  • fuel_species (str or None, optional) – Fuel species name in the Cantera mechanism, for example CH4. This is required when backend is cantera.

Returns:

Adiabatic flame result containing flame temperature, pressure, burned gas state, and species mole data.

Return type:

IdealEquilibriumResult

Raises:

ValueError – If an unknown backend is requested, or if the Cantera backend is used without a fuel species.

simulator.thermo.reactor0d

class simulator.thermo.reactor0d.ProgressVariableReactor(lam, state)[source]

Bases: object

Very simple 0-D reactor based on a single progress variable.

This is not a detailed chemical-kinetics model. It is meant as a drop-in replacement for a Wiebe function when you want the burn shape x_b(θ) to come from an ODE rather than a closed form.

State variables

  • lamfloat

    Progress variable in [0, 1], analogous to mass fraction burned.

  • stateThermoState

    Thermodynamic state of the zone (typically the burned or unburned gas). In this first version we keep T fixed and only evolve lam.

lam: float
state: ThermoState
rhs(t)[source]

Right-hand side dλ/dt for the progress variable ODE.

We use a simple Arrhenius-like law modulated by (1−λ):

dλ/dt = A * exp(−E / (R T)) * λ^m * (1 − λ)

All parameters are set through attributes and can be tuned to roughly match a desired CA10/50/90 at a given operating point.

Parameters:

t (float)

Return type:

float

step(dt)[source]

Advance the reactor by a small time step dt using RK4.

Parameters:

dt (float)

Return type:

None

Parameters:

simulator.thermo.species

class simulator.thermo.species.NasaPoly7(t_low, t_high, coeffs)[source]

Bases: object

NASA 7-coefficient polynomial for one temperature range.

This follows the common form used in NASA CEA reports:

cp/R = a1 + a2 T + a3 T² + a4 T³ + a5 T⁴ h/(R T) = a1 + a2 T/2 + a3 T²/3 + a4 T³/4 + a5 T⁴/5 + a6/T s/R = a1 ln T + a2 T + a3 T²/2 + a4 T³/3 + a5 T⁴/4 + a7

Parameters:
  • t_low (float) – Valid temperature bounds [K]. The polynomial is not extrapolated outside this range except in very narrow margins for robustness.

  • t_high (float) – Valid temperature bounds [K]. The polynomial is not extrapolated outside this range except in very narrow margins for robustness.

  • coeffs (Sequence[float]) – The 7 polynomial coefficients [a1..a7].

t_low: float
t_high: float
coeffs: Sequence[float]
cp_R(T)[source]

Dimensionless cp/R at temperature T.

Parameters:

T (float | np.ndarray)

Return type:

float | np.ndarray

h_RT(T)[source]

Dimensionless h/(R T) at temperature T.

Parameters:

T (float | np.ndarray)

Return type:

float | np.ndarray

s_R(T)[source]

Dimensionless entropy s/R at temperature T.

Parameters:

T (float | np.ndarray)

Return type:

float | np.ndarray

class simulator.thermo.species.Species(name, molar_mass, elements, thermo=None, cp_R_const=3.5)[source]

Bases: object

Basic thermodynamic model for a single chemical species.

Parameters:
  • name (str) – Identifier (e.g. “O2”, “CO2”, “CH4”).

  • molar_mass (float) – Molar mass [kg/mol].

  • elements (Dict[str, int]) – Elemental composition (e.g. {“C”: 1, “O”: 2}).

  • thermo (NasaPoly7 | None) – NASA-style polynomial data. If this is None a constant-cp approximation is used instead.

  • cp_R_const (float) – Constant cp/R used when thermo is None. For many gases 3.5 is a reasonable ballpark (diatomic ideal gas).

Note

The default species defined in SPECIES_DB use simple constant cp/R values via cp_R_const. They are not authoritative NASA polynomials; they are provided only so that the rest of the code runs out-of-the-box. You should replace them with genuine NASA CEA / JANAF data for serious work.

name: str
molar_mass: float
elements: Dict[str, int]
thermo: NasaPoly7 | None = None
cp_R_const: float = 3.5
cp_mass(T)[source]

Return cp [J/(kg·K)] at temperature T.

Parameters:

T (float)

Return type:

float

h_mass(T)[source]

Very simple sensible enthalpy model [J/kg].

If NASA data are present we integrate the polynomial; otherwise we use cp_const * (T − T_ref) with T_ref = 298 K.

Parameters:

T (float)

Return type:

float

simulator.thermo.species.register_species(sp)[source]

Register a species in the global SPECIES_DB.

Parameters:

sp (Species)

Return type:

None

simulator.thermo.species.get_species(name)[source]

Lookup helper with a clearer error message.

Parameters:

name (str)

Return type:

Species

simulator.thermo.thermo_state

class simulator.thermo.thermo_state.ThermoState(T, p, mass_fractions, rho, cp, cv, gamma, R_mix, h, u)[source]

Bases: object

Thermodynamic state for a gas mixture.

The dataclass stores temperature, pressure, species mass fractions, density, specific heats, mixture gas constant, enthalpy, and internal energy for a gas mixture.

Use from_T_p_Y() when the mixture is described by species names in the internal species database. Use from_cantera() when the state is supplied by a Cantera Solution object.

The field annotations below are intentionally left as the source of truth for autodoc. Avoiding a separate Attributes section prevents duplicate object-description warnings for dataclass fields in Sphinx.

Parameters:
  • T (float)

  • p (float)

  • mass_fractions (Dict[str, float])

  • rho (float)

  • cp (float)

  • cv (float)

  • gamma (float)

  • R_mix (float)

  • h (float)

  • u (float)

T: float
p: float
mass_fractions: Dict[str, float]
rho: float
cp: float
cv: float
gamma: float
R_mix: float
h: float
u: float
classmethod from_T_p_Y(T, p, Y)[source]

Build a mixture state from temperature, pressure, and mass fractions.

Species keys must exist in SPECIES_DB. Unknown species are ignored, and the remaining positive fractions are renormalized before mixture properties are computed.

Parameters:
  • T (float)

  • p (float)

  • Y (Mapping[str, float])

Return type:

ThermoState

classmethod from_cantera(gas)[source]

Build a mixture state from a Cantera Solution object.

Cantera provides the thermodynamic properties directly. The mixture gas constant is computed from the ideal-gas identity R_mix = cp_mass - cv_mass so the method does not depend on version-specific Cantera attributes.

Return type:

ThermoState

copy_with_T_p(T=None, p=None)[source]

Return a new state with updated temperature and/or pressure.

The new state is recomputed through from_T_p_Y() using the existing mass fractions. If the original state came from Cantera and contains species that are not present in SPECIES_DB, those species are ignored during recomputation.

Parameters:
  • T (float | None)

  • p (float | None)

Return type:

ThermoState

copy_with(**changes)[source]

Return a shallow copy with arbitrary field overrides.

This helper does not recompute thermodynamic properties. It simply replaces selected dataclass fields, which is useful for diagnostics or small reporting tweaks.

Example:

state2 = state.copy_with(T=2100.0, p=4e6)
Parameters:

changes (Any)

Return type:

ThermoState

Thermochemistry Tools

simulator.thermo.tools.equilibrium_flame

simulator.thermo.tools.equilibrium_flame.build_arg_parser()[source]
Return type:

ArgumentParser

simulator.thermo.tools.equilibrium_flame.run_sweep(fuel_id, backend, mech, fuel_species, phi_start, phi_stop, phi_step, p_cyl, Tin, out_json, out_html)[source]
Parameters:
  • fuel_id (str)

  • backend (str)

  • mech (str)

  • fuel_species (str | None)

  • phi_start (float)

  • phi_stop (float)

  • phi_step (float)

  • p_cyl (float)

  • Tin (float)

  • out_json (Path)

  • out_html (Path | None)

Return type:

None

simulator.thermo.tools.equilibrium_flame.main(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

int

simulator.thermo.tools.equilibrium_flame_compare

class simulator.thermo.tools.equilibrium_flame_compare.FlameCurve(fuel_id: 'str', backend: 'BackendType', mechanism: 'str | None', fuel_species: 'str | None', phi: 'np.ndarray', T_ad: 'np.ndarray')[source]

Bases: object

Parameters:
  • fuel_id (str)

  • backend (Literal['legacy', 'ideal', 'cantera'])

  • mechanism (str | None)

  • fuel_species (str | None)

  • phi (numpy.ndarray)

  • T_ad (numpy.ndarray)

fuel_id: str
backend: Literal['legacy', 'ideal', 'cantera']
mechanism: str | None
fuel_species: str | None
phi: numpy.ndarray
T_ad: numpy.ndarray
simulator.thermo.tools.equilibrium_flame_compare.sweep_flame_curve(fuel_id, backend, phi_vals, p, Tin, mechanism=None, fuel_species=None)[source]

Compute T_ad(φ) for one fuel / backend combination.

Notes

  • For backend=”ideal” or “legacy”, fuel_id must exist in simulator.fuels.

  • For backend=”cantera”, fuel_id is only used as a label in the plot; the actual thermo comes from the Cantera mechanism / fuel_species.

Parameters:
  • fuel_id (str)

  • backend (Literal['legacy', 'ideal', 'cantera'])

  • phi_vals (numpy.ndarray)

  • p (float)

  • Tin (float)

  • mechanism (str | None)

  • fuel_species (str | None)

Return type:

FlameCurve

simulator.thermo.tools.equilibrium_flame_compare.make_plot(curves, out_html, title_suffix='')[source]
Parameters:
  • curves (List[FlameCurve])

  • out_html (Path | None)

  • title_suffix (str)

Return type:

plotly.graph_objects.Figure

simulator.thermo.tools.equilibrium_flame_compare.write_json(curves, out_json)[source]
Parameters:
  • curves (List[FlameCurve])

  • out_json (Path | None)

Return type:

None

simulator.thermo.tools.equilibrium_flame_compare.parse_args(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

Namespace

simulator.thermo.tools.equilibrium_flame_compare.main(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

int

Engineering Tools

simulator.tools.bsfc_sweep_phi

simulator.tools.bsfc_sweep_phi.run_bsfc_sweep(config_path, out_csv, out_html, rc_list, phi_min, phi_max, phi_step)[source]
Parameters:
  • config_path (str | Path)

  • out_csv (str | Path | None)

  • out_html (str | Path | None)

  • rc_list (List[float])

  • phi_min (float)

  • phi_max (float)

  • phi_step (float)

Return type:

None

simulator.tools.bsfc_sweep_phi.main(argv=None)[source]
Parameters:

argv (List[str] | None)

Return type:

int

simulator.tools.tool_bsfc_contours

simulator.tools.tool_bsfc_contours.main()[source]
Return type:

None

simulator.tools.tool_bsfc_map_epa

simulator.tools.tool_bsfc_map_epa.main(argv=None)[source]
Parameters:

argv (List[str] | None)

Return type:

None

simulator.tools.tool_bsfc_table

simulator.tools.tool_bsfc_table.main()[source]
Return type:

None

simulator.tools.tool_bsfc_vs_displacement

simulator.tools.tool_bsfc_vs_displacement.main()[source]
Return type:

None

simulator.tools.tool_bsfc_vs_phi_rc

simulator.tools.tool_bsfc_vs_phi_rc.main()[source]
Return type:

None

simulator.tools.tool_bsfc_vs_speed_rc

simulator.tools.tool_bsfc_vs_speed_rc.main()[source]
Return type:

None

simulator.tools.tool_compressor_map_efr71

tool_compressor_map_efr71.py

Plot a BorgWarner‑EFR‑style compressor map from CSV and optionally overlay an engine operating line exported by tool_turbo_match_opline.

Usage (from project root):

python -m simulator.tools.tool_compressor_map_efr71

–csv simulator/in/compressor_efr71_grid.csv –speedlines-csv simulator/in/compressor_efr71_speedlines.csv –opline-csv simulator/out/turbo_match_opline.csv –out-html simulator/out/compressor_efr71_map.html

Map CSV columns (rectangular grid):

m_dot_corr_kg_per_s, PR_comp, eta_c

Speed‑line CSV columns (one row per point):

N_krpm, m_dot_corr_kg_per_s, PR_comp

Operating‑line CSV columns (from tool_turbo_match_opline):

speed_rpm, pr_comp, m_dot_corr_kg_per_s, …

simulator.tools.tool_compressor_map_efr71.build_figure(map_csv, speedlines_csv=None, opline_csv=None)[source]
Parameters:
  • map_csv (Path)

  • speedlines_csv (Path | None)

  • opline_csv (Path | None)

Return type:

plotly.graph_objects.Figure

simulator.tools.tool_compressor_map_efr71.parse_args(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

Namespace

simulator.tools.tool_compressor_map_efr71.main(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

int

simulator.tools.tool_cycle_thermo_plot

simulator.tools.tool_cycle_thermo_plot.parse_args(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

Namespace

simulator.tools.tool_cycle_thermo_plot.infer_temperature(data, p, V_key, mass_key, R_mix)[source]

If no temperature array is present, infer T from p V = m R T.

Parameters:
  • data (dict)

  • p (numpy.ndarray)

  • V_key (str)

  • mass_key (str)

  • R_mix (float)

Return type:

numpy.ndarray

simulator.tools.tool_cycle_thermo_plot.make_plot(theta, p, T, out_html)[source]
Parameters:
  • theta (numpy.ndarray)

  • p (numpy.ndarray)

  • T (numpy.ndarray)

  • out_html (Path)

Return type:

None

simulator.tools.tool_cycle_thermo_plot.main(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

int

simulator.tools.tool_flame_summary

class simulator.tools.tool_flame_summary.FlameSummaryRow(filename: 'str', N_rpm: 'float', phi: 'float', T_ad: 'float', bsfc_g_per_kWh: 'Optional[float]')[source]

Bases: object

Parameters:
  • filename (str)

  • N_rpm (float)

  • phi (float)

  • T_ad (float)

  • bsfc_g_per_kWh (float | None)

filename: str
N_rpm: float
phi: float
T_ad: float
bsfc_g_per_kWh: float | None
simulator.tools.tool_flame_summary.collect_rows(pattern, fuel_id, backend, pressure_Pa, Tin_K, mechanism=None, fuel_species=None)[source]

Walk dyno-style JSON outputs and attach a T_ad to each point.

pattern is a glob pattern, e.g. ‘simulator/out/full_load_N_*.json’.

Parameters:
  • pattern (str)

  • fuel_id (str)

  • backend (Literal['legacy', 'ideal', 'cantera'])

  • pressure_Pa (float)

  • Tin_K (float)

  • mechanism (str | None)

  • fuel_species (str | None)

Return type:

List[FlameSummaryRow]

simulator.tools.tool_flame_summary.write_csv(rows, out_csv)[source]
Parameters:
Return type:

None

simulator.tools.tool_flame_summary.make_plot(rows, out_html, backend, fuel_id)[source]

Plot BSFC vs N (primary y-axis) and T_ad vs N (secondary y-axis).

For your current full-load sweeps at fixed φ, T_ad is expected to be almost constant vs speed (ideal backend has no speed dependence). BSFC, however, varies strongly with N.

Parameters:
  • rows (List[FlameSummaryRow])

  • out_html (Path | None)

  • backend (Literal['legacy', 'ideal', 'cantera'])

  • fuel_id (str)

Return type:

plotly.graph_objects.Figure

simulator.tools.tool_flame_summary.parse_args(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

Namespace

simulator.tools.tool_flame_summary.main(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

int

simulator.tools.tool_full_load_sweep

simulator.tools.tool_full_load_sweep.build_parser()[source]
Return type:

ArgumentParser

simulator.tools.tool_full_load_sweep.main(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

int

simulator.tools.tool_generate_template_input

simulator.tools.tool_generate_template_input.main()[source]
Return type:

None

simulator.tools.tool_indicator_from_result

simulator.tools.tool_indicator_from_result.main()[source]
Return type:

None

simulator.tools.tool_turbine_map_gt4088

tool_turbine_map_gt4088.py

Plot a Garrett-style turbine swallowing map from CSV and optionally overlay an engine turbine operating line.

Map CSV columns:

A_over_R, PR_turb, m_corr_lb_per_min, eta

Operating-line CSV (from tool_turbo_match_opline):

pr_turb, m_corr_lb_per_min, speed_rpm, …

Usage:

python -m simulator.tools.tool_turbine_map_gt4088

–csv simulator/in/turbine_gt4088_like.csv –opline-csv simulator/out/turbo_match_opline.csv –out-html simulator/out/turbine_gt4088_map.html

simulator.tools.tool_turbine_map_gt4088.build_figure(map_csv, opline_csv=None)[source]
Parameters:
  • map_csv (Path)

  • opline_csv (Path | None)

Return type:

plotly.graph_objects.Figure

simulator.tools.tool_turbine_map_gt4088.parse_args(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

Namespace

simulator.tools.tool_turbine_map_gt4088.main(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

int

simulator.tools.tool_turbo_match_opline

tool_turbo_match_opline.py

Very simple steady-state turbo-match helper. See docstring in source for details.

simulator.tools.tool_turbo_match_opline.run_match(config_path, out_csv, p_amb_bar, N_list)[source]
Parameters:
  • config_path (Path)

  • out_csv (Path)

  • p_amb_bar (float)

  • N_list (List[float])

Return type:

None

simulator.tools.tool_turbo_match_opline.parse_args(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

Namespace

simulator.tools.tool_turbo_match_opline.main(argv=None)[source]
Parameters:

argv (List[str] | None)

Return type:

int

simulator.tools.turbo_match

simulator.tools.turbo_match.build_arg_parser()[source]
Return type:

ArgumentParser

simulator.tools.turbo_match.main(argv=None)[source]
Parameters:

argv (list[str] | None)

Return type:

int