# \[ANN\] Glenn.jl v0.30 — Thermochemical properties calculator from NASA Glenn coefficients

**URL:** <https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618>\
**Category:** Package Announcements\
**Tags:** community, simulations, modelling, chemical-engineering\
**Created:** [August 5, 2026, 1:38pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618 "2026-08-05T13:38:23Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![R.Leao.Jr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/r.leao.jr/32/29656_2.png) [@R.Leao.Jr](https://discourse.julialang.org/u/R.Leao.Jr)\
**Post date:** [August 5, 2026, 1:38pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/1 "2026-08-05T13:38:23Z")

</div>

I’m happy to announce **Glenn.jl v0.30** , a Julia package that computes thermochemical properties (Cp(T) , H°(T), S°(T)) from NASA-7 polynomial coefficients stored in a bundled SQLite database.

The package is a Julia port of my Python library [pyglenn]( [GitHub - ProfLeao/pyglenn: A Python package for calculating thermodynamic properties using NASA polynomial coefficients. · GitHub](https://github.com/ProfLeao/pyglenn) ), built for the Julia community.

**Highlights**

- **Zero-config** — `Calculator()` uses the bundled `thermo.db`; no setup required
- **Context manager** — automatic connection management with `do`-block syntax
- **Exact-match species lookup** — `exact_match=true` for case-insensitive exact search (e.g. `"N2"` returns only N₂, not Be₃N₂)
- Query species by name, phase, molecular weight - Calculate Cp(T), H°(T), S°(T) at any valid temperature - Enthalpy of formation lookup
- Enthalpy change between two temperatures (ΔH)
- Properties over arbitrary temperature ranges
- Build databases from NASA FORTRAN `thermo.inp` files
- Command-line interface (`build` and `query`)
- **NIST-JANAF cross-validation** — validated against reference data for 7 species (CO₂, N₂, CO, H₂O, O₂, NH₃, SO₂)
- ~2030 species, 3772 temperature intervals
- Full [Documenter.jl](https://documenter.juliadocs.org) documentation.

**Installation**

```julia
julia using Pkg Pkg.add("Glenn")

```

**Quick Start — Basic usage**

The database ships inside the package — `Calculator()` works immediately with zero configuration. All properties are returned in SI units (Cp, S° → J/(mol·K); H° → J/mol).

```julia
using Glenn

# No setup needed — uses the bundled thermo.db
calc = Calculator()

# exact_match=true: case-insensitive exact lookup
# "O2" returns only O₂, not Al₂O₂ or Be₃N₂
o2 = only(get_available_species(calc, "O2", exact_match = true))

# Single-point calculation at 1000 K
props = calculate_properties(calc, o2.id, 1000.0)
println("Species: ", props.species_name, " (", props.phase, ")")
println("T = ", props.temperature, " K")
println("Cp = ", round(props.cp, digits = 2), " J/(mol·K)")
println("H° = ", round(props.h_relative, digits = 1), " J/mol")
println("S° = ", round(props.s, digits = 3), " J/(mol·K)")

# Enthalpy of formation
hf = calculate_formation_enthalpy(calc, o2.id) # J/mol

# Enthalpy change between two temperatures
dh = calculate_enthalpy_change(calc, o2.id, 300.0, 1500.0)

# Properties over a temperature range (vectorized — fast)
results = get_properties_range(calc, o2.id, 300:50:2000)

close(calc)

```

**Context manager (`do`-block)**

Use the `do`-block syntax for automatic connection management — the database is opened before the block and closed after, even if an exception occurs.

```julia
using Glenn

# Recommended pattern: no manual connect/close needed
Calculator() do calc
    ch4 = only(get_available_species(calc, "CH4", exact_match = true))
    props = calculate_properties(calc, ch4.id, 500.0)
    println("Cp(CH₄, 500 K) = ", round(props.cp, digits = 2), " J/(mol·K)")
end
# Database is automatically closed here

```

**Command-line interface**

Quick access to species data and database operations without opening a REPL.

```bash
# Quick species lookup
julia --project -e 'using Glenn; Glenn.cli_main()' -- query -s CH4
julia --project -e 'using Glenn; Glenn.cli_main()' -- query -s CO2

# Or use the convenience script
julia --project bin/glenn.jl query -s O2

# Database rebuild (only if needed — see section above)
julia --project -e 'using Glenn; Glenn.cli_main()' -- build
julia --project bin/glenn.jl build -i custom.inp -o custom.db

```

**NIST-JANAF Cross-Validation**

Run the cross-validation audit to compare Glenn.jl against NIST-JANAF reference data:

`julia --project docs/audit/audit.jl`

Outputs: `glenn_vs_nist.csv` (point-by-point comparison) and `validation_summary.txt` (aggregated statistics).

**Database**

The `thermo.db` database is bundled with the package (`data/thermo.db`), generated by [pyglenn](https://github.com/ProfLeao/pyglenn) from the NASA Glenn FORTRAN thermochemical tables.

| Table | Records | Description |
| --- | --- | --- |
| `species` | 2030 | Chemical species (name, formula, phase, MW, ΔH°f) |
| `temperature_intervals` | 3772 | Valid T ranges per species |
| `coefficients` | 3772 | NASA-7 polynomial coefficients (a1–a7, b1, b2) |
| `file_metadata` | 1 | Global file metadata |

**Requirements:** Julia ≥ 1.6 · SQLite.jl

**Links:**

- GitHub: [GitHub - ProfLeao/Glenn.jl: A Julia Lang package to access the NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species · GitHub](https://github.com/ProfLeao/Glenn.jl)
- Documentation: [Home · Glenn.jl](https://profleao.github.io/Glenn.jl/)
- pyglenn (Python version): [GitHub - ProfLeao/pyglenn: A Python package for calculating thermodynamic properties using NASA polynomial coefficients. · GitHub](https://github.com/ProfLeao/pyglenn)

Feedback, issues, and contributions are very welcome!

---

<div class="post-metadata">

**Author:** ![R.Leao.Jr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/r.leao.jr/32/29656_2.png) [@R.Leao.Jr](https://discourse.julialang.org/u/R.Leao.Jr)\
**Post date:** [August 15, 2026, 6:34pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/2 "2026-08-15T18:34:13Z")

</div>

Recently, I’ve been working on a playground for the Glenn.jl package. The goal is to create a repository of ideas and usage examples for the package to inspire users. The repository will also serve as a way to aggregate ideas from everyone who wants and is able to contribute.

Feel free to fork it, work on brilliant ideas, and submit a pull request when you’re ready — just don’t forget to place your project in a separate directory and document it very well.

Below I’m leaving the simulation report of a KNSB Motor.

Playground: [GitHub - ProfLeao/PlaygroundGlenn.jl · GitHub](https://github.com/ProfLeao/PlaygroundGlenn.jl)

Glenn.jl: [GitHub - ProfLeao/Glenn.jl: A Julia Lang package to access the NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species · GitHub](https://github.com/ProfLeao/Glenn.jl)

# KNSB Motor Simulation Report

**Original run:** 2026-08-11 11:20:00 · **Revised:** 2026-08-15  
**Simulator:** MiniRocket.jl — Solid Rocket Combustion CFD  
**Model:** 0D internal ballistics (uniform chamber)  
**NAR/Tripoli Classification:** Class B (2.51–5.00 N·s) — original run · **Class I** after burn-rate correction

* * *

## 1. Physical Model

### 1.1 Governing Equations (0D Model)

The zero-dimensional model treats the entire combustion chamber as a single uniform control volume. Three coupled equations govern the system:

**Conservation of mass in the chamber:**

\frac{d}{dt}(\rho\_c V\_c) = \underbrace{\rho\_p A\_b r\_b}\_{\text{gas generation}} - \underbrace{\dot{m}\_{nozzle}}\_{\text{nozzle exit}}

where \rho\_c is the chamber gas density, V\_c the chamber free volume, \rho\_p the propellant density, A\_b the burning surface area, r\_b the linear burning rate, and \dot{m}\_{nozzle} the mass flow through the nozzle.

**Saint Robert’s burning rate law:**

r\_b = a \cdot P\_c^{\,n}

This empirical power-law relates the linear regression rate of the propellant surface to chamber pressure P\_c. The coefficients a (burning rate coefficient) and n (pressure exponent, typically 0.3–0.5 for sugar propellants) are determined experimentally. The exponent n \< 1 is critical for stability — if n \geq 1, the motor is inherently unstable and prone to catastrophic overpressure.

**Equation of state (ideal gas):**

P\_c = \frac{m\_{gas} \cdot R\_{gas} \cdot T\_c}{V\_c}

The chamber gas is treated as an ideal gas at the adiabatic flame temperature T\_c, with gas constant R\_{gas} = R\_u / MW\_{products}. This assumption is reasonable for the low-to-moderate pressures (~1–20 bar) typical of amateur solid motors.

**Nozzle mass flow (choked):**

\dot{m}\_{nozzle} = \frac{P\_c \cdot A\_t}{c^\*}

where A\_t is the throat area and c^\* is the characteristic velocity:

c^\* = \frac{\sqrt{\gamma \cdot R\_{gas} \cdot T\_c}}{\gamma \cdot \left(\frac{2}{\gamma+1}\right)^{\frac{\gamma+1}{2(\gamma-1)}}}

Choked flow (M = 1 at the throat) is assumed whenever P\_c / P\_{amb} \gtrsim 1.8, which holds for all meaningful operating conditions.

**Thrust equation:**

F = \eta \cdot \left[\dot{m}\_{nozzle} \cdot v\_e + (P\_e - P\_{amb}) \cdot A\_e\right]

where the exit velocity v\_e and exit pressure P\_e are computed via isentropic expansion from the throat to the exit area ratio A\_e/A\_t, and \eta accounts for nozzle losses (friction, divergence, two-phase flow).

### 1.2 The Kn Parameter — Key to Motor Design

The dimensionless parameter Kn = A\_b / A\_t (burning area to throat area ratio) is the single most important design variable for solid rocket motors:

- The equilibrium chamber pressure is approximately P\_c \propto Kn^{1/(1-n)}
- Higher Kn → higher pressure → higher thrust → faster burn
- Lower Kn → lower pressure → risk of extinction
- Typical amateur KNSB motors operate at $Kn \approx 200$–$450$ (Nakka), with \approx 300 a common design point

For this motor, the initial Kn = 250. Because the grain is BATES with uninhibited ends, the burning area changes over time. For this geometry (L/D = 3.75, web = 15 mm) the area is **progressive** : A\_b grows from 70.7 cm² toward ~150 cm² at burnout, so Kn **increases** during the burn (250 → ~360 within the simulated 10 s) and the equilibrium pressure slowly rises with it.

* * *

## 2. Motor Configuration

### 2.1 Propellant: KNSB

| Property | Value | Description |
| --- | --- | --- |
| Name | KNSB (65% KNO₃ + 35% C₆H₁₄O₆) | Potassium Nitrate + Sorbitol |
| Density | 1750 kg/m³ | Compacted granular propellant |
| T\_adiabatic (estimated) | 1600 K | From literature (Nakka) |
| γ (estimated) | 1.220 | Specific heat ratio of product gases |
| MW products | 28.5 g/mol | Average molecular weight of exhaust |
| Heat of explosion | 3.8 MJ/kg | Chemical energy content |
| Burning rate: a | 8.26×10⁻⁶ m/s/Paⁿ | Saint Robert coefficient |
| Burning rate: n | 0.319 | Pressure exponent (\< 1 → stable) |

KNSB is the most widely used propellant in Brazilian model rocketry due to its **low cost** , **stable burning characteristics** , and **ease of manufacture**. The combustion reaction (simplified) is:

10\,\text{KNO}\_3 + 3\,\text{C}\_6\text{H}\_{14}\text{O}\_6 \rightarrow 5\,\text{K}\_2\text{CO}\_3 + 6\,\text{CO}\_2 + 7\,\text{CO} + 14\,\text{H}\_2\text{O} + 7\,\text{H}\_2 + 5\,\text{N}\_2

This is a **balanced, representative** form (10 : 3 molar ratio = 65.0 : 35.0 by weight, matching the 65/35 KNSB mix). Because KNSB is fuel-rich, the products contain substantial CO and H₂ in addition to CO₂; the exact CO₂/CO/H₂/H₂O split is set by chemical equilibrium (the water–gas shift), so this equation is representative rather than unique. _The original report’s equation (5 KNO₃ + C₆H₁₄O₆ → …) was not atom-balanced — K, N, C and O did not match._

### 2.2 Grain Geometry: BATES

| Property | Value | Significance |
| --- | --- | --- |
| Length | 150 mm | Total grain length |
| Outer diameter | 40 mm | Fits standard 40 mm PVC casing |
| Inner diameter | 10 mm | Initial port for flame propagation |
| Outer inhibited | Yes | PVC casing prevents outer surface burn |
| Ends inhibited | No | Both ends burn → progressive thrust profile |
| Initial burning area | 70.7 cm² | Sum of inner cylinder + both end faces |
| Propellant volume | 176.7 cm³ | Total solid propellant |
| Propellant mass | 309.3 g | ≈ 0.3 kg fuel load |

The BATES (Ballistic Test and Evaluation System) geometry is a hollow cylinder that burns on all non-inhibited surfaces. For this grain the inner cylindrical surface dominates: as the port enlarges (r\_i: 5 → 20 mm) the inner area grows faster than the end faces shrink, so the total burning area is **progressive** (70.7 → ~150 cm² at burnout), not regressive. _The original report described this geometry as regressive, which is incorrect — regressive behaviour occurs only in short, end-face-dominated grains._

### 2.3 Motor Assembly

| Property | Value | Significance |
| --- | --- | --- |
| Chamber (L × D) | 180 × 40 mm | 30 mm extra length for combustion zone |
| Throat diameter (D\_t) | 6.0 mm | Critical flow control |
| Exit diameter (D\_e) | 12.0 mm | 4:1 area expansion ratio |
| Nozzle efficiency | 92% | Accounts for losses |
| Initial Kn (A\_b/A\_t) | 250 | Design point for pressure balance |

The nozzle is the **convergent-divergent** type (de Laval). At 6.0 mm throat, A\_t = 28.3\text{ mm}^2 and Kn = 250 — within the typical KNSB operating range, so the throat is _not_ abnormally large. The real mismatch is the **expansion ratio** : \varepsilon = 4 (D\_e = 12 mm) is matched to a chamber pressure of ~20 bar, whereas this motor only reaches ~3 bar, so the nozzle is severely over-expanded (see §3.2).

* * *

## 3. Simulation Results

### 3.1 Performance Summary

| Metric | Value | Notes |
| --- | --- | --- |
| Burn time | 10.000 s | **Truncated at T\_max** — only ~21% of propellant consumed |
| Max chamber pressure | 3.08 bar | Still slowly rising at cutoff (no plateau) |
| Avg chamber pressure | 2.39 bar | Corrected (original said ~0.91 bar) |
| Max thrust | 2.28 N | Occurs at t = 10 s (cutoff), **not** at ignition |
| Avg thrust | 0.46 N | ≈ 0 for the first ~6 s (over-expanded nozzle) |
| Total impulse | 4.64 N·s | Low for a 309 g propellant load |
| Specific impulse (Isp) | 74.9 s | ≈ 76% of the ideal ~99 s at 3 bar |
| Propellant consumed | 65 g (21%) | 244 g remains |
| **NAR/Tripoli Class** | **B** | 2.51–5.00 N·s (corrected; original said 1/2A) |

### 3.2 Thrust and Pressure Curves

 ![knsb_thrust_pressure](https://global.discourse-cdn.com/julialang/original/3X/3/f/3fec4031293d67cc6c6d03453983bff56c686d53.png)

The combined plot reveals several key features (several differ from the original report):

- **Gradual pressurization, no sharp ignition spike** — pressure rises from 1.01 bar to ~1.8 bar over the first ~1–2 s, then slowly climbs to 3.08 bar, tracking the increasing Kn. The model starts at ambient pressure with a 50% “incipient” burn rate below 1.5\,P\_{amb}, so no explosive ignition transient is captured.
- **No pressure plateau** — at t = 10 s the pressure is still rising; it never levels off because the equilibrium pressure itself rises as the port grows.
- **Thrust ≈ 0 for the first ~6 s** despite rising pressure — thrust does _not_ simply follow pressure here.
- **Over-expanded nozzle is the cause** : at \varepsilon = 4 and \gamma = 1.22, M\_e \approx 2.65 and P\_e/P\_c \approx 0.042. At P\_c = 3.08 bar this gives P\_e \approx 0.13 bar, so the pressure term (P\_e - P\_{amb})\,A\_e \approx -10 N nearly cancels the \approx 12.5 N momentum term. Thrust only turns positive once P\_c \gtrsim 2.5 bar. The ideal expansion ratio at 3 bar would be \varepsilon \approx 1.14; the 4:1 nozzle is sized for ~20 bar.

### 3.3 Grain Evolution

 ![knsb_grain_evolution](https://global.discourse-cdn.com/julialang/original/3X/a/a/aaba32d8bc77f0ae8bb44d81bb9cd0843bbd87de.png)

The grain evolution plots show (corrected values from `knsb_results.csv`):

- **Burning area** : increases from 70.7 to 102.2 cm² (+44%) over the 10 s — the grain is **progressive** , not regressive.
- **Burned web** : 4.28 mm of the 15 mm web (28.5%). The burn rate is ~0.35–0.46 mm/s (r\_b \propto P\_c^{0.319} at 1–3 bar).
- **Remaining mass** : falls from 309 g to 244 g — 65 g (21%) consumed, not “nearly flat”.

### 3.4 Why Did This Motor Underperform? (Root-Cause Analysis)

The original report attributed the failure to “oversized throat / low Kn”. The review below shows the **dominant cause is a ~12× error in the burning-rate coefficient** , not the throat.

**1. Dominant error — the Saint Robert coefficient is ~12× too low.** The model uses a = 8.26\times10^{-6}\ \text{m/(s·Pa}^n), which yields a burn rate of only \approx 0.68 mm/s at 10 bar and \approx 1.25 mm/s at 68 bar. The widely cited Nakka law for KNSB is r[\text{mm/s}] = 8.26\cdot P[\text{MPa}]^{0.319} — i.e. \approx 8.3 mm/s at 10 bar and \approx 15 mm/s at 68 bar, **~12× faster**. This is consistent with a unit-conversion error (mm/s per MPaⁿ vs m/s per Paⁿ); the correct SI coefficient is a \approx 1.0\times10^{-4}\ \text{m/(s·Pa}^n), not 8.26\times10^{-6}.

**2. Consequence.** The equilibrium pressure P\_{eq} = \left(\rho\_p a c^\* Kn\right)^{1/(1-n)} scales as a^{1.47}. With the wrong a the motor settles near ~1.8 bar (rising with Kn to ~3 bar). After correcting a and re-running, this same 40 mm motor reaches **~200 bar peak, 822 N and Class I (466.8 N·s)** — far beyond what a 40 mm PVC casing can withstand. The 6 mm throat is _not_ the problem; with the correct burn rate this throat is already aggressive for such a casing.

**3. Secondary error — over-expanded nozzle.** Even at the low pressures reached, the 4:1 nozzle cancels ~80% of the momentum thrust (see §3.2), which is why thrust ≈ 0 for the first 6 s and Isp is reduced.

**4. The parametric study’s “fix” is unsafe.** Its recommendation (reduce D\_t to 4–5 mm) is an artifact of the wrong a. With a corrected coefficient, D\_t = 4 mm (Kn \approx 700) would imply hundreds of bar — a **CATO (catastrophic failure) risk**. The parametric study has since been re-run with the corrected coefficient — see parametric\_report.md: all 25 configurations are Class I, 85–601 bar, confirming this risk.

* * *

## 4. Glenn.jl Thermochemical Verification

Glenn.jl provides high-fidelity thermochemical properties from the NASA-7 polynomial database (~2030 species). This section cross-validates the propellant’s estimated properties against Glenn.jl calculations.

### 4.1 Product Species at Adiabatic Temperature

| Species | Cp at 1600 K (J/mol·K) | S° at 1600 K (J/mol·K) | Phase |
| --- | --- | --- | --- |
| CO₂ | 58.87 | 295.98 | Gas |
| CO | 35.47 | 250.71 | Gas |
| H₂O | 48.34 | 253.74 | Gas |
| N₂ | 35.13 | 244.14 | Gas |
| H₂ | 32.73 | 180.94 | Gas |
| CH₄ | 93.37 | 287.69 | Gas |

The NASA-7 polynomials capture the temperature dependence of Cp(T) with high accuracy (typically \< 1% error in the 200–6000 K range). The large Cp of CH₄ (93.37 J/mol·K) reflects its polyatomic structure with many vibrational degrees of freedom, while the diatomic species (CO, N₂, H₂) cluster around ~33–35 J/mol·K — close to the theoretical \frac{7}{2}R = 29.1 J/mol·K for diatomic ideal gases.

### 4.2 Adiabatic Temperature and Impulse Comparison

| Comparison | Value | Source |
| --- | --- | --- |
| **T\_adiabatic (Glenn.jl)** | **4118 K** | NASA-7 + simplified equilibrium |
| T\_adiabatic (estimated) | 1600 K | Literature (Nakka) |
| **Isp theoretical (Glenn.jl + isentropic)** | **141.0 s** | Frozen isentropic expansion |
| Isp simulated (0D) | 74.9 s | 0D ballistics at ~3 bar |

**Critical observation:** The Glenn.jl adiabatic temperature (4118 K) **overpredicts** the literature value (~1600 K). The root causes are more specific than “simplified equilibrium”:

1. **Zero reactants enthalpy.** `knsb_rocket.jl` calls `adiabatic_flame_temperature(calc, 0.0, products_glenn)`. Passing `0.0` for the reactants enthalpy makes the energy balance H\_{products}(T) = 0, which searches for the temperature where the products’ _absolute_ enthalpy (including their strongly negative heats of formation) crosses zero. This is not a meaningful flame-temperature condition — the heat of explosion (3.8 MJ/kg) is never supplied to the calculation.
2. **Condensed species treated as gas.** K₂CO₃ and KOH are condensed (solid/liquid) products; `estimate_combustion_products` deliberately selects their _gas-phase_ entries, removing their latent heat of vaporization and inflating T.
3. **No Gibbs minimization.** The product set is a fixed guess; a full equilibrium calculation (NASA CEA) would redistribute species and lower T.

**Isp consequence.** The “theoretical” 141.0 s is inflated by the bogus T\_{ad} (I\_{sp} \propto \sqrt{T\_c}). Using the correct T\_c = 1600 K, the ideal sea-level frozen Isp at P\_c = 3.08 bar is \approx 99 s; the simulated 74.9 s is \approx 76\% of that (consistent with \eta = 0.92 plus over-expansion). The original claim that “141 s aligns with literature” was a coincidence of two compensating errors. _After the energy-balance correction, the re-run gives T\_{ad} \approx 2602 K and Isp$\_{theo} \approx 224$ s, with simulated Isp \approx 154 s (\approx 68\% of theoretical)._

**Recommendation:** pass the heat of explosion as the reactants enthalpy, treat K₂CO₃/KOH as condensed, and cross-validate against NASA CEA.

* * *

## 5. Conclusions

| Aspect | Finding |
| --- | --- |
| **Motor Class** | B (2.51–5.00 N·s) — corrected from “1/2A” |
| **Primary Issue** | Burning-rate coefficient ~12× too low (unit-conversion error) |
| **Secondary Issue** | 4:1 nozzle over-expanded at ~3 bar (ideal \varepsilon \approx 1.14) |
| **Grain behaviour** | Progressive (A\_b: 70.7 → 102 cm² in 10 s), not regressive |
| **Glenn.jl Validation** | Species Cp/S° accurate; T\_{ad} = 4118 K is an artifact of zero reactants enthalpy + gas-phase condensed species |
| **Fix** | Correct a \approx 1.0\times10^{-4} m/(s·Paⁿ) and re-run before trusting any throat recommendation |
| **Model Limitations** | 0D, fixed T\_c, no heat losses, no ignition transient |

* * *

## 6. Model Issues Identified During Review

| # | Issue | Severity | Location | Suggested Fix |
| --- | --- | --- | --- | --- |
| 1 | Saint Robert coefficient a ~12× too low (unit error) | **Critical** | `src/propellant.jl` (`KNSB`) | a \approx 1.0\times10^{-4} m/(s·Paⁿ) |
| 2 | NAR/Tripoli class thresholds deviate from the standard table (4.64 N·s is reported as “1/2A” but is Class B) | High | `src/ballistics.jl` (`print_results`), `README.md` | Use the standard table (B = 2.51–5.00 N·s) |
| 3 | `adiabatic_flame_temperature` called with zero reactants enthalpy | High | `examples/knsb_rocket.jl` | Pass the heat of explosion (3.8 MJ/kg) |
| 4 | Condensed products (K₂CO₃, KOH) looked up as gas phase | Medium | `src/equilibrium.jl` | Keep condensed-phase entries |
| 5 | No ignition transient / fixed T\_c / no heat losses | Medium | `src/ballistics.jl` | Add ignition model, T\_c(P), or quasi-1D |
| 6 | Fixed 4:1 expansion assumed appropriate at all pressures | Low | `examples/*.jl` | Size \varepsilon to the design P\_c |

**Safety note.** Before flying or static-testing any configuration, re-run the simulation with the corrected burning-rate coefficient. With the original (too-low) coefficient the tool systematically _underpredicts_ pressure and thrust: after the correction, this same 40 mm motor re-runs at **~200 bar / 822 N / Class I** (vs. the original 3 bar / 2.3 N / Class B), confirming that throat sizes optimized against the wrong coefficient (e.g., D\_t → 4–5 mm) would be catastrophic.

* * *

_Report based on execution of `examples/knsb_rocket.jl` using MiniRocket.jl; revised 2026-08-15 after a full review of the code, the raw results (`examples/data/knsb_results.csv`) and the execution logs. After correcting the burning-rate coefficient and re-running (2026-08-15), the motor predicts ~200 bar / Class I — see §3.4. The parametric study (parametric\_report.md) has also been re-run with the corrected coefficient._

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [August 15, 2026, 8:15pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/3 "2026-08-15T20:15:47Z")

</div>

This package looks super useful! I have used Clapeyron.jl quite a bit, and find that package very useful. But Clapeyron.jl lacks enthalpy of formation, reference entropy, and ideal gas heat capacity (to some degree) for use with chemical reactions. So I assume it is possible to combine these two packages to achieve what I want?

---

<div class="post-metadata">

**Author:** ![R.Leao.Jr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/r.leao.jr/32/29656_2.png) [@R.Leao.Jr](https://discourse.julialang.org/u/R.Leao.Jr)\
**Post date:** [August 15, 2026, 8:45pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/4 "2026-08-15T20:45:46Z")

</div>

Hello, I believe so. If you give me more details about what you are doing, I can offer suggestions on how to use it or on the integration you mentioned.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [August 16, 2026, 8:29am UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/5 "2026-08-16T08:29:49Z")

</div>

I don’t work on chemical reactions daily, but here is an example I did some time ago (while trying to understand components in the modeling language package ModelingToolkit.jl):

 ![image](https://global.discourse-cdn.com/julialang/original/3X/b/6/b69db10df124cab1b3c3d6ad12608479524b6b8e.png)  
I dug up enthalpy of formation and reference enthalpy from the data book Properties of Gases and Liquids. Clapeyron supports, e.g., Reid ideal gas (heat capacity is a simple polynomial in T), but for some substances I needed in Properties… the heat capacity was given in some “Einstein” form, so I just converted it to Reid form (sampling + model fit).

Here are a couple of results I got:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/5/7/5743a9082d03e7108746e96ef07a46c43407ac95.png)  
The solid lines are with the indicated reactor configuration = specifying pressure in the feed tanks, and letting liquid compressibility determine the reactor pressure and flow rates; response to a 5 degree increase in cooling temperature.

Dark line: PCPSAFT EoS (because the substances I used were supported in that EoS), while the lighter line is using an Ideal Solution assumption.

For the dashed lines, I assumed “perfect” reactor pressure control, and _pumped_ feed into the tank.

With ModelingToolkit, I could also linearize the system, and, e.g., find a Bode plot:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/8/68f3bb14e175bc9fd71160550527a77b50494c66.png)

Seems like Glenn supports some 2000+ substances, while Clapeyron has (or used to have) some 100 substances built-in. I don’t know whether these substances overlap, but finding data is definitely a possible improvement.

Lots of other uses, though. Like for turbo machines, etc.

---

<div class="post-metadata">

**Author:** ![quarknode351](https://avatars.discourse-cdn.com/v4/letter/q/ce7236/32.png) [@quarknode351](https://discourse.julialang.org/u/quarknode351)\
**Post date:** [August 16, 2026, 8:42am UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/6 "2026-08-16T08:42:34Z")

</div>

This post was temporarily hidden by the community for possibly being off-topic, unfocused, inappropriate, or spammy.

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [August 16, 2026, 8:32pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/7 "2026-08-16T20:32:25Z")

</div>

> [@BLI](#):
>
> Seems like Glenn supports some 2000+ substances, while Clapeyron has (or used to have) some 100 substances built-in. I don’t know whether these substances overlap, but finding data is definitely a possible improvement.
> 
> Lots of other uses, though. Like for turbo machines, etc.

Hello,

on Clapeyron.jl, there is a PR working on adding the the NASA polynomials to Clapeyron, but the main problem is the standarization of substance names. I can add a Glenn extension to Clapeyron, so we can use Glenn.jl as a database for an ideal model + reference state.

---

<div class="post-metadata">

**Author:** ![R.Leao.Jr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/r.leao.jr/32/29656_2.png) [@R.Leao.Jr](https://discourse.julialang.org/u/R.Leao.Jr)\
**Post date:** [August 16, 2026, 11:15pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/8 "2026-08-16T23:15:53Z")

</div>

I understand. If you would like any support with your model, let me know more details, preferably by sharing a repository. I will be at your disposal.

---

<div class="post-metadata">

**Author:** ![R.Leao.Jr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/r.leao.jr/32/29656_2.png) [@R.Leao.Jr](https://discourse.julialang.org/u/R.Leao.Jr)\
**Post date:** [August 16, 2026, 11:19pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/9 "2026-08-16T23:19:30Z")

</div>

At another time, we discussed the possibility of integrating Glenn.jl with Clapeyron.jl. However, as an independent (garage) developer, it took me a long time to reach a reasonably mature version. If you would like to link your PR here, I can work on a proposal.

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [August 16, 2026, 11:25pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/10 "2026-08-16T23:25:47Z")

</div>

> [@R.Leao.Jr](#):
>
> an independent (garage) developer, it took me a long time to reach a reasonably mature version. If you would like to link your PR here, I can work on a proposal.

yeah! i remember that, happy to see it finally done!

I have an extension almost ready, but i noticed a (minor) issue (i just opened it). The extension just wraps a list of `IntervalData` for each component and evaluates the helmholtz energy:

```julia
julia> calc = Calculator()
Calculator("thermo.db")

julia> o2 = only(get_available_species(calc, "O2", exact_match = true))
SpeciesInfo(931, "O2", nothing, "gas", 31.9988, 0.0, 3)

julia> n2 = only(get_available_species(calc, "N2", exact_match = true))
SpeciesInfo(861, "N2", nothing, "gas", 28.0134, 0.0, 3)

julia> Clapeyron.GlennJL(calc,[o2,n2])

julia> glenn_model = Clapeyron.GlennJL(calc,[o2,n2])
Clapeyron.GlennJL{SpeciesInfo, Vector{IntervalData}} with 2 components:
 "O2"
 "N2"

```

that ideal model then can be used as the ideal model for any Clapeyron model:

```julia
julia> model = PR(["oxygen","nitrogen"], idealmodel = glenn_model)
PR{Clapeyron.GlennJL{SpeciesInfo, Vector{IntervalData}}, PRAlpha, NoTranslation, vdW1fRule} with 2 components:
 "oxygen"
 "nitrogen"
Contains parameters: a, b, Tc, Pc, Mw

```

---

<div class="post-metadata">

**Author:** ![R.Leao.Jr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/r.leao.jr/32/29656_2.png) [@R.Leao.Jr](https://discourse.julialang.org/u/R.Leao.Jr)\
**Post date:** [August 21, 2026, 3:58pm UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/11 "2026-08-21T15:58:38Z")

</div>

[ANN] Glenn.jl v0.4.0 — Thermochemical properties calculator for Julia

I’m happy to announce the release of Glenn.jl v0.4.0, a Julia package that computes Cp(T), H°(T) and S°(T) from NASA-7 polynomial coefficients stored in a bundled SQLite database (~2030 species, 3772 temperature intervals). Zero configuration — `Calculator()` works out of the box.

What’s new in v0.4.0:

🐛 Fixed — reference gas constant in property denormalisation. The bundled NASA Glenn/CEA polynomials are dimensionless (Cp/R₀, H/R₀T, S/R₀) and were fitted with the CODATA 1986 constant R₀ = 8.314510 J/(mol·K) (NASA TP-2002-211556). The runtime previously denormalised them with `R_UNIVERSAL = 8.314462618` (CODATA 2018), producing a systematic −5.7 ppm bias. Results are now denormalised with the dataset reference constant.

✨ Added

- `R_GLENN = 8.314510` — reference constant of the bundled dataset (CODATA 1986)
- `get_gas_constant_ref(db)` — reads the reference constant from the SQLite `metadata` table, with fallback to `R_UNIVERSAL`
- `migrate_metadata!(db)` — self-contained migration for existing databases
- `metadata` table in the builder schema
- `DatabaseStats` — typed struct replacing the `Dict` from `get_statistics`

🔧 Changed

- `R_UNIVERSAL` now uses full CODATA 2018/2022 precision (`8.31446261815324`)
- `Calculator` stores `R_ref` and uses it for all Cp/H/S denormalisation (scalar and vectorised)
- `ThermoDBBuilder` writes dataset metadata automatically during `build`
- `parse_and_load` now reports `New species loaded` / `Already existing` separately
- `calculate_cp/h/s` deprecate the `Dict` coefficient methods in favour of `NASACoefficients`

⚠ Breaking change: `get_statistics` now returns a `DatabaseStats` struct — switch from `stats["total_species"]` to `stats.total_species`.

Install with `Pkg.add("Glenn")`. Docs: [profleao.github.io/Glenn.jl/](https://profleao.github.io/Glenn.jl/)

Thanks to [@longemen3000](https://github.com/longemen3000) for identifying the reference gas constant inconsistency.

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [August 24, 2026, 3:32am UTC](https://discourse.julialang.org/t/ann-glenn-jl-v0-30-thermochemical-properties-calculator-from-nasa-glenn-coefficients/138618/12 "2026-08-24T03:32:13Z")

</div>

From Clapeyron 0.6.27 onwards, Glenn.jl can be used as a provider of ideal gas data, via the `GlennJL` ideal model ([Ideal Models · Clapeyron.jl](https://clapeyronthermo.github.io/Clapeyron.jl/dev/eos/ideal/#Clapeyron.GlennJL))
