prometheus_equilibrium.propellants.loader

PropellantDatabase — load propellant ingredients and formulations from TOML.

The TOML file contains two table arrays:

[[ingredient]] — a pure chemical species that enters the combustion chamber. [[formulation]] — a named blend of ingredients by mass fraction.

Each ingredient either references an entry in SpeciesDatabase via thermo_id (the canonical {HillFormula}_{PHASE} key) or defines its own element composition and thermodynamic properties inline. Inline ingredients are represented as SyntheticSpecies objects with a constant Cp model.

The key output of this module is PropellantMixture, a lightweight dataclass holding the {Species: moles} dict, total reactant enthalpy, and the element set needed to query SpeciesDatabase.get_species().

class prometheus_equilibrium.propellants.loader.SyntheticSpecies(elements: dict, state: str, dHf298: float, cp: float, phase: str | None = None, alias: str | None = None, molar_mass_g_mol: float | None = None)

Bases: Species

Constant-Cp species for propellant ingredients not in the thermo database.

Used for polymer binders (HTPB, CTPB, PBAN), kerosene-type fuels (RP-1), and other complex propellants whose thermo data is not available as a polynomial fit. The thermodynamic model is:

Cp°(T) = cp                               [J/mol/K]
H°(T)  = dHf298 + cp × (T − 298.15)      [J/mol]
S°(T)  = cp × ln(T / 298.15)              [J/mol/K]

The entropy is anchored at S°(298.15 K) = 0 — a deliberate simplification valid because synthetic species only appear as reactants, never as equilibrium products. Only enthalpy() is evaluated by the solver’s HP/SP energy constraint; Gibbs minimisation never uses these objects.

dHf298

Standard enthalpy of formation at 298.15 K [J/mol].

cp

Molar heat capacity (constant approximation) [J/mol/K].

alias

Optional human-readable name.

molar_mass() float

Return the molar mass in kg/mol.

Uses the explicitly supplied value when provided; otherwise computes from the element dictionary (inherited behaviour).

specific_heat_capacity(T: float | ndarray) float | ndarray

Cp°(T) = cp [J/mol/K] (constant).

enthalpy(T: float | ndarray) float | ndarray

H°(T) = dHf298 + cp × (T − 298.15) [J/mol].

entropy(T: float | ndarray) float | ndarray

S°(T) = cp × ln(T / 298.15) [J/mol/K] (S°₂₉₈ = 0 approximation).

reduced_gibbs(T: float | ndarray) float | ndarray

G°/(RT) computed directly for scalars.

reduced_enthalpy(T: float | ndarray) float | ndarray

H°/(RT).

class prometheus_equilibrium.propellants.loader.PropellantMixture(reactants: Dict[Species, float], enthalpy: float, elements: FrozenSet[str])

Bases: object

Resolved propellant mixture ready to pass to EquilibriumProblem.

All quantities are per 1 kg of total propellant mixture.

reactants

{Species: moles} per kg of propellant. Pass directly as the reactants argument of EquilibriumProblem.

Type:

Dict[prometheus_equilibrium.equilibrium.species.Species, float]

enthalpy

Total reactant enthalpy H₀ [J/kg] evaluated at each ingredient’s supply temperature. Use as constraint1 for HP problems.

Type:

float

elements

Frozenset of element symbols present in the mixture (e- excluded). Pass to SpeciesDatabase.get_species() to build the product candidate list.

Type:

FrozenSet[str]

reactants: Dict[Species, float]
enthalpy: float
elements: FrozenSet[str]
class prometheus_equilibrium.propellants.loader.PropellantDatabase(path: str, species_db: SpeciesDatabase | None = None)

Bases: object

Load propellant ingredient and formulation data from a TOML file.

Parameters

path:

Path to a propellants.toml file.

species_db:

A loaded SpeciesDatabase. Required for ingredients that use thermo_id; not needed if all ingredients define their composition inline.

Example

prop_db = PropellantDatabase(
    "prometheus/propellants/propellants.toml",
    species_db=db,
)
prop_db.load()

# O/F = 6 by mass
mixture = prop_db.mix([("LOX", 6.0), ("LH2", 1.0)])
products = db.get_species(mixture.elements)

problem = EquilibriumProblem(
    reactants=mixture.reactants,
    products=products,
    problem_type=ProblemType.HP,
    constraint1=mixture.enthalpy,
    constraint2=6.894757e6,   # 1000 psia in Pa
)
load() None

Parse the TOML file and resolve all ingredient Species objects.

expand(formulation_id: str) PropellantMixture

Resolve a named formulation to a PropellantMixture.

The mass fractions stored in the TOML are normalised to sum to exactly 1.0, so the result is always per 1 kg of total propellant.

Parameters

formulation_id:

Key of a [[formulation]] entry in the TOML file.

Returns

PropellantMixture

Raises

KeyError

If formulation_id is not found.

mix(components: List[Tuple[str, float]]) PropellantMixture

Build a PropellantMixture from (ingredient_id, mass_amount) pairs.

The amounts are in any consistent mass units (kg, g, proportional) — only their ratios matter. They are normalised so the result is always per 1 kg of total mixture.

Parameters

components:

[(ingredient_id, mass_amount), ...]

Returns

PropellantMixture

Example

mixture = db.mix([("LOX", 6.0), ("LH2", 1.0)])  # O/F = 6 by mass
mixture = db.mix([("AP", 0.68), ("Al", 0.18), ("HTPB", 0.14)])
find_ingredient(ingredient_id: str) dict

Return the resolved record for ingredient_id (includes _species key).

find_formulation(formulation_id: str) dict

Return the raw TOML record for formulation_id.

search_items() List[dict]

Return a list of search records for use with the GUI search dialog.

Each record has the keys id, display, and search_text. display is the human-readable name shown in the UI. search_text is a pre-lowercased concatenation of all searchable fields (ID, name, CAS number, aliases) so the dialog only needs a single in check per keystroke.

Returns:

List of {id, display, search_text} dicts, one per ingredient, in sorted ID order.

property ingredient_ids: List[str]

Sorted list of all loaded ingredient IDs.

property formulation_ids: List[str]

Sorted list of all loaded formulation IDs.