Repository navigation
Process chemistry
extensions/chemistry/ is a library that models the requirements of a process step: what must hold for a material to become a product. It computes driving forces, equilibria and phase changes from thermochemical data. It checks stated bounds from experiments and from the equipment. It returns the operating window, the temperatures where every requirement holds, and a report that says why each bound is there.
This is not a three.js port. See Extensions. For the reasons behind the method, see Why a process runs where it does.
This page covers steps, requirements, windows and reactions. Each area of the library has its own page:
| Page | What it covers |
|---|---|
| Thermochemical data | NASA-7, NASA-9 and Shomate fits, CHEMKIN and CEA files, fitting a table, uncertainty |
| Chemical equilibrium | The composition of a charge at a temperature and a pressure |
| Process maps | Scans of two variables, Ellingham diagrams and predominance maps |
| Rates and transport | Arrhenius rates, the shrinking core, evaporation, case depth and heating |
| Electrolysis and film color | Cell voltages, Faraday's law and the color of thin oxides |
| Binary solutions | Activities and phase boundaries of alloys |
| Flowsheets and routes | Steps joined by streams with recycle, and the search for routes |
| Materials and coatings | Expansion curves, melting points, eutectics and coating mechanics |
| Crystals and figures | A CIF reader, chart axes and the gallery figures |
Each layer uses only the layers above it in this table. Extend the library at the layer that owns the concept.
| Module | What it gives |
|---|---|
quantities |
Molar values per mole, Amount64, GAS_CONSTANT, STANDARD_PRESSURE, BAR, ATMOSPHERE, TORR, MICROMETER, ANGSTROM, FractureEnergy64 and amount_of
|
kinds |
Phase, RequirementKind, Check and Hazard
|
elements |
Element for the 84 elements with an IUPAC standard atomic weight, element_from_symbol, Formula and parse_formula
|
thermo |
ThermoFit with nasa7, nasa9 and shomate, Species and Substance
|
chemkin |
read_chemkin_thermo and write_chemkin_thermo
|
cea |
read_cea_thermo, a reader for NASA CEA thermo.inp files |
fitting |
ThermoPoint and fit_nasa7
|
catalog |
Built-in substances, with NASA data |
reaction |
Term, reactant, product and Reaction, with delta_g, delta_h, equilibrium_temperature, equilibrium_pressure, mass_ratio and their uncertainties |
requirement |
The Constraint trait, Requirement and its constructors |
window |
Interval, met_intervals, intersect and window_of, for any constraint |
step |
Step, operating_window, unmet and report
|
equilibrium |
Charge, equilibrate, Equilibrium and EquilibriumShare
|
maps |
scan, boundary, ellingham, oxygen_pressure, reducing_ratio, predominance and oxide_map
|
kinetics |
Arrhenius, RateAtLeast and ShrinkingCore
|
transport |
vapor_pressure, evaporation_flux, Diffusivity, case_depth and heating_time
|
electrochemistry |
reversible_voltage, decomposition_voltage, faraday_mass, CellVoltage and specific_energy
|
optics |
film_reflectance, film_color, linear_srgb and anodic_thickness
|
solution |
Linear, PhaseModel and phase_boundaries
|
balance |
StreamItem, stream_enthalpy and heat_duty
|
flowsheet |
Flowsheet, StreamId and UnitKind
|
routes |
find_routes |
materials |
ExpansionCurve, melting_point and eutectic_temperature
|
coating |
ElasticLayer, the coating stresses, and the peeling, buckling and cracking limits |
crystal |
read_cif, Crystal and bonds
|
plot |
Axes, nice_ticks and tick_text
|
processes |
Worked processes: titanium, diamond and lime
|
Make a Step with its pressure, a range to search and the planned temperature. Add one requirement for each condition. Then ask for the window and the report.
from extensions.chemistry.catalog import (
magnesium, magnesium_chloride, magnesium_gas, titanium,
titanium_tetrachloride_gas,
)
from extensions.chemistry.kinds import ENGINEERING, PHASE, THERMODYNAMIC
from extensions.chemistry.quantities import ATMOSPHERE
from extensions.chemistry.reaction import Reaction, product, reactant
from extensions.chemistry.requirement import above, below, held_back, proceeds
from extensions.chemistry.step import Step, operating_window, report
from units.si import Pressure64
from units.temperature import CELSIUS, Temperature64
var step = Step(
"Reduce TiCl4", Pressure64(1, ATMOSPHERE),
Temperature64(800), Temperature64(1500), Temperature64(850, CELSIUS),
)
step.add(proceeds(THERMODYNAMIC, Reaction([
reactant(titanium_tetrachloride_gas()), reactant(magnesium(), 2),
product(titanium()), product(magnesium_chloride(), 2),
]), "Magnesium must reduce the chloride."))
step.add(above(PHASE, magnesium_chloride().melting_point(),
"MgCl2 must drain as a liquid.", "NASA TM-4513"))
step.add(held_back(PHASE,
Reaction([reactant(magnesium()), product(magnesium_gas())]),
"Magnesium must not boil."))
step.add(below(ENGINEERING, Temperature64(1085, CELSIUS),
"The steel retort must stay below the Fe-Ti eutectic.", "Murray (1981)"))
var window = operating_window(step) # 987 K to 1358 K
print(report(step))The report gives each requirement at the planned temperature, with its number and its source:
Reduce TiCl4
Hazards: none listed
Pressure: 101.325 kPa
Window: 987.0 K (713.9 degC) to 1358.2 K (1085.0 degC)
Planned: 1123.2 K (850.0 degC), every requirement met
[met] thermodynamic: Magnesium must reduce the chloride.
TiCl4(g) + 2 Mg -> Ti + 2 MgCl2: dG -309.9 kJ/mol; computed from the thermochemical data
[met] phase: MgCl2 must drain as a liquid.
bound 987.0 K (713.9 degC); NASA TM-4513
...
step.add_hazard adds a Hazard. step.add_fact adds a reaction that the report evaluates at the planned temperature. A fact does not limit the window. unmet(step) counts the requirements that fail at the planned temperature.
Each requirement has a RequirementKind: THERMODYNAMIC, PHASE, KINETIC, PHYSICAL or ENGINEERING. The kind names the science that the requirement comes from. The Check says how the library tests it:
| Constructor | Check | Holds where |
|---|---|---|
proceeds |
PROCEEDS |
The reaction's Gibbs energy change is below zero |
held_back |
HELD_BACK |
The change is above zero |
above, below
|
ABOVE, BELOW
|
The temperature is above or below the stated bound |
pressure_above, pressure_below
|
PRESSURE_ABOVE, PRESSURE_BELOW
|
The pressure is above or below the bound |
action |
ACTION |
Always. The report lists it as a thing to do |
A reaction check computes its result. A phase change is a reaction too, so a boiling point at the step's pressure comes from the data. A stated bound names its source. A reaction check is not met where a substance's data does not reach.
Constraint is the extension point for a new kind of requirement. A type that implements holds and describe works with met_intervals, intersect and window_of. It needs no change to the library.
from extensions.chemistry.requirement import Constraint
from extensions.chemistry.window import intersect, met_intervals
@fieldwise_init
struct Near(Constraint):
var target: Float64
def holds(self, temperature: Temperature64, pressure: Pressure64) raises -> Bool:
return abs(temperature.kelvin - self.target) < 50
def describe(self, temperature: Temperature64, pressure: Pressure64) raises -> String:
return String("within 50 K of ", self.target)
var narrowed = intersect(
operating_window(step),
met_intervals(Near(1000), step.low, step.high, step.pressure),
)window_of(constraints, low, high, pressure) intersects a list of constraints of one type. met_intervals samples a constraint at 400 points in the range and finds each change by bisection. A feature narrower than a 400th of the range can be missed.
read_chemkin_thermo reads NASA seven-coefficient data in the CHEMKIN thermo format. GRI-Mech, the Burcat tables and most combustion codes publish their data in this format. Each record gives one Species. Join the phases of one formula in a Substance, coldest first:
from std.pathlib import Path
from extensions.chemistry.chemkin import read_chemkin_thermo
from extensions.chemistry.thermo import Substance
var species = read_chemkin_thermo(Path("thermo.dat").read_text())
var methane = Substance("CH4(g)", [species[0].copy()])The reader refuses a short or misnumbered record with its line number. A loaded species has no molar volume. Set one where the pressure term of a condensed phase matters. For NASA-9 and Shomate data, CEA files, fitted tables and uncertainties, see Thermochemical data.
parse_formula reads a formula from text, with groups: parse_formula("Ca(OH)2") has one calcium, two oxygen and two hydrogen. element_from_symbol accepts either case, as data files write TI for titanium.
A Term is a substance with a coefficient: reactant makes it negative and product makes it positive. A gas term also has a mole fraction of the total pressure. A condensed term has an activity, one for a pure phase. Reaction refuses terms that do not balance every element.
The change is the sum of coefficient times chemical potential. For an ideal gas, the potential is G(T) + R T ln(x P / p0). For a condensed phase that does not compress, it is G(T) + V (P - p0) + R T ln a. p0 is one bar. Below zero, the reaction proceeds.
equilibrium_temperature finds where the change crosses zero between two temperatures. equilibrium_pressure finds where it crosses zero between two pressures, on a logarithmic scale. For an evaporation into a pure vapor, that is the vapor pressure. mass_ratio gives the kilograms of one substance per kilogram of another.
The built-in coefficients are the NASA polynomials of McBride, Gordon and Reno, NASA TM-4513, 1993. Iron's solid phase uses the NASA-9 data of NASA TP-2002-211556. All were copied unchanged from the conversion that Cantera 3.2 ships. The comment above each species gives its source code. See Thermochemical data and THIRD-PARTY-NOTICES.md.
A Species is one phase of one formula, valid over the range of its data. A Substance joins the condensed phases of one formula, or holds one gas. It uses the phase whose range holds the temperature. The ends of adjacent ranges are the transitions, so melting_point reads the data.
TM-4513 has no diamond. diamond is graphite's data, moved by the CODATA change at 298.15 K: 1.895 kJ/mol and -3.363 J/(mol K). That assumes equal heat capacities, so the change is low by roughly 1 kJ/mol at 1000 K.
Each piece of data stops at its range. The calcite data ends at 1200 K, and the liquid TiCl4 data starts at 300 K. A computation outside a range raises an error.
| Step | Window | Lower bound | Upper bound |
|---|---|---|---|
| Chlorinate rutile with coke | 900 to 1227 degC | Rate (kinetic, stated) | End of the search |
| Distill TiCl4 | From 136 degC | TiCl4 boils (computed) | End of the search |
| Reduce TiCl4 with Mg (Kroll) | 714 to 1085 degC | MgCl2 melts (data) | Fe-Ti eutectic (stated) |
| Vacuum distillation at 10 Pa | 702 to 1085 degC | MgCl2 evaporates (computed) | Fe-Ti eutectic (stated) |
| Diamond on carbide at 30 Torr | 700 to 1000 degC | Growth rate (stated) | Cobalt (stated) |
| Hydrogen filament at 30 Torr | 1758 to 3422 degC | 1 % atomic hydrogen (computed) | Tungsten melts (stated) |
| Lime burning | 894 to 927 degC | CaCO3 gives off CO2 (computed) | The calcite data ends |
Print them with tools/process_report.mojo:
.venv/bin/mojo run -I . tools/process_report.mojo # every process
.venv/bin/mojo run -I . tools/process_report.mojo titanium # titanium, diamond or limeThe diamond step shows a metastable product. Graphite to diamond does not proceed at 30 Torr: its change is +5.7 kJ/mol at 850 degC. Methane at 1 % in hydrogen can still deposit diamond, at -14.5 kJ/mol. Atomic hydrogen from the filament etches graphite faster than diamond, so the diamond survives. That last requirement is kinetic, so the step states it as an action.
- Add a module to
extensions/chemistry/processes/. - Build each step from the public layers: substances from
catalogor from your own data, reactions, and requirements. - Give each stated bound its source. Leave a computed bound to the data.
- Test each window edge against a reference that does not come from the same data.
mismatch_stress gives the biaxial stress in a thin coating on a thick substrate after cooling. delamination_thickness gives the thickest coating that does not peel from an edge. processes.diamond holds typical properties in CVD_DIAMOND and CEMENTED_CARBIDE. Diamond on carbide cools to about 2.5 GPa of compression, which limits it to about 11 micrometers at 30 J/m². For expansion curves, Stoney's stress, buckling and thermal shock, see Materials and coatings.
A StreamItem is an amount of a substance at a temperature. heat_duty returns the enthalpy that leaves minus the enthalpy that enters. Above zero, the step needs heat. Below zero, it gives off heat that the equipment must remove. The Kroll reduction gives off about 1.35 kWh per kilogram of titanium, from a feed at 300 K to products at 850 degC.
The tests compare computed values with references that do not come from TM-4513:
| Quantity | Computed | Reference |
|---|---|---|
| TiCl4 normal boiling point | 409.2 K | 409.6 K, CRC Handbook |
| Mg normal boiling point | 1365.7 K | 1363 K, CRC Handbook |
| Mg vapor pressure, 701 K to 1361 K | Within 10 % | 1 Pa to 100 kPa, CRC Handbook |
| CaCO3 to CaO in 1 atm of CO2 | 1167 K | About 1171 K |
| Boudouard balance at 1 bar | 973 K | About 973 K |
| Methane to graphite and H2 at 1 bar | 818 K | About 818 K |
| Graphite to diamond at 298 K | 1.54 GPa | About 1.5 GPa, Berman and Simon |
| Methane read from a CHEMKIN record | The catalog's G | Equal to 1e-6 J/mol |
The MgCl2 vapor data gives a boiling point of 1631 K at one atmosphere. The measured value is about 1685 K, so treat MgCl2 evaporation as an estimate.
Gases are ideal. A condensed phase is pure, or a binary solution with given parameters. There are no slags or aqueous species, so there are no Pourbaix diagrams. Rates come from measured constants. The library does not predict them.
A hazard list names the dangers of a step. It is not a risk assessment. The worked processes are models of requirements, not operating procedures. Chemistry separates and combines elements. It does not change one element into another.
Tutorials
How-to
- Install
- Run the checks
- GPU backend
- Coverage
- Measure examples
- Add a feature
- Add a scanned building
- Write documentation
Reference
- Scene graph
- Rotations
- Cameras
- Geometry
- Geometry addons
- Lofts and clipping groups
- Sculptor
- Procedural generators
- Meshes and assets
- Lines
- Points and sprites
- Helpers
- Scene objects
- Animated objects
- Raycasting
- Curves and paths
- Animation
- Skinning
- Materials
- Node materials
- TSL functions
- Lights
- Lighting addons
- Fog
- Textures
- Renderer
- Renderer hooks and material flags
- Rasterization
- GPU backend
- Render target
- Post-processing
- GPU computation
- Compute nodes
- Progressive light map
- Gaussian splats
- Voxel global illumination
- SVG renderer
- Image files
- Image decode queue
- Model files
- More model files
- Exporters
- Scene JSON
- Windowing and controls
- C ABI and hosts
- Math
- Norm consumers
- Math addons
- Units
- Coverage tool
- Commands
- Examples
- Benchmarks
- Extensions
- Shared physics
- Physics query snapshots
- Continuous collision
- Tick force restoration
- Water
- Warp drives
- Vegetation
- Village
- Streamline
- Animals
-
Buildings
- Numerics
- Building topology
- Building model
- IFC exchange
- Procedural towers
- Floor plans and interiors
- Frame analysis
- Shell analysis
- Building energy
- Construction kits
- Bearing walls
- Scanned buildings
- SOG files
- Compressed PLY files
- Scan parts
- Cleaning and orienting scans
- Walking through a scan
- Virtual scans
- Castle
- CARLA
- Femur
- Tibia
- Fibula
- Patella
- Knee
- Muscles
- Vessels
- Lymph
- Nerves
- Integument
- Leg
- Foot
- Pelvis
- Torso
- Arm
- Hand
- Head
- Genome
- Game humanoid
- Humanoid fidelity
- Mixamo animations
- Audio-aligned game faces
- Converted assets
- Mesh quality
- Garments
- Outfits and armor
- Cloth and spring bones
- Attire estimates
- Segment inertia
- Process chemistry
- Thermochemical data
- Chemical equilibrium
- Process maps
- Rates and transport
- Electrolysis and film color
- Binary solutions
- Flowsheets and routes
- Materials and coatings
- Crystals and figures
Explanation
- Software rasterizer
- Scene graph as an array
- Linear color
- Normals are not colors
- Perspective correction
- Fixed-point coverage
- Per-fragment shading
- Mipmaps
- Sorted transparency
- Types and checks
- Render hooks as a trait
- Shared CPU and GPU code
- Bands and threads
- PNG structure
- Extensions beside the port
- Process temperatures
- Scans as building models
- CUDA teardown hang
- Mojo compiler hang