FERRETGame engine over Babylon.js
Ferret

Cookbook: fire, heat and reactions

Each recipe says what to build and what to expect. The guides (heat, chemistry, electric, links) explain the parts, and the runnable versions, with the numbers they must produce, are in tests/unit/examples/physics-cookbook-fire-and-heat.test.ts.

1. Boil a pot on a fire#

A pot is a heat part fed with the power of a fire. The temperature climbs, holds at 373.15 K while the latent heat is paid, and the water is gone only when 2.26 MJ per kilogram have gone in.

const net = new HeatNetwork();
const water = net.addPart({ name: 'water', mass: 1, material: M.water, T: 293.15, power: 2000 });
net.step(0.5);
water.phase;               // 'liquid', then 'gas' once the latent heat is paid

One kilogram on a 2 kW burner reaches the boiling point after about 170 s (80 K at 4186 J/kg K) and boils off 1130 s later. Change power for a hotter fire, mass for a bigger pot; give the part area and h and it loses heat to the air, so a weak fire never gets there.

2. A steel beam in a fire#

Steel does not melt in a building fire; it loses strength. At 600 °C (873 K) it holds only 40 % of its cold strength, so a beam that carries its load at room temperature fails. strengthFactor gives the fraction left at a temperature:

const beam = net.addPart({ name: 'beam', mass: 50, material: M.steel, T: 293.15, power: 20e3, area: 1.2, h: 25 });
net.step(1);
if (strengthFactor(M.steel, beam.T) < 0.6) { /* a beam carrying 60 % of its cold strength has failed */ }

The beam fails hot but far below the melting point. Put a cladding of insulation (a second part joined with net.join and a low conductance) between the fire and the beam, and the same code gives the fire rating of a wall: the minutes until the factor falls below the load.

3. A pressure cooker that bursts#

A sealed tank is heated from a wall; the pressure follows the temperature. When it passes the wall's limit, the tank is a bomb: hand the numbers to explosions.

const wall = net.addPart({ name: 'wall', mass: 3, material: steel, T: 293.15, power: 3000 });
const gas = new GasVolume({ moles: 2, temperature: 293.15, volume: 0.01 });
const link = gasInPart(gas, wall, net, 20);          // 20 W/K between wall and gas
const burstAt = 5 * gas.pressure;                    // the tank holds 5 times its starting pressure
// each step
net.step(dt); link.step(dt, host, []);
if (gas.pressure > burstAt) { const tnt = vesselTnt(gas.pressure, 0.01); }

Pressure at constant volume is proportional to absolute temperature, so a vessel at five times its start pressure is five times as hot in kelvin. A 10 litre cooker at that pressure makes a few tens of grams of TNT. Hand { pressure: gas.pressure, volume: 0.01 } to explosions.detonate({ vessel }) when it goes.

4. A kettle on a breaker#

A 2.3 kW kettle on 230 V draws 10 A. Add a hair-dryer on the same circuit and the 16 A breaker trips on its thermal curve:

c.add(new VSource('V', 'a', '0', 230));
const breaker = c.add(new Breaker('B', 'a', 'b', 16, 10, 8));    // 16 A rated, 10 s thermal constant, magnetic at 8 x
c.add(new Heater('Kettle', 'b', '0', 230 * 230 / 2300));
c.add(new Resistor('Dryer', 'b', '0', 230 * 230 / 2000));
c.onEvent = e => { if (e.type === 'trip') { /* ... */ } };

The kettle alone is fine. With the dryer the circuit carries 18.7 A on a 16 A breaker and trips after some seconds. The thermal element trips later for a smaller overload and sooner for a larger one; a short circuit trips the magnetic element in a couple of milliseconds.

5. A cold pack#

An endothermic dissolving reaction cools a drink: the vessel is in contact with the drink, and the drink gives the heat.

chem.add('b2a', { reactants: { B: 1 }, products: { A: 1 }, A: 0.05, Ea: 0, phase: 'solution' });   // +50 kJ per mole
const pack = new Vessel(chem, { volume: 1e-3, contents: { B: 1, Solvent: 100 }, hA: 5 });
const drink = net.addPart({ name: 'drink', mass: 2, material: water, T: 298.15 });
const link = vesselInPart(pack, drink, net);
// each step
pack.react(dt); net.step(dt); link.step(dt, host, []);

One mole at 50 kJ takes about 6 K out of 2 kg of water. The scene's energy stays closed to 0.1 %: put a pack, a drink and the link into a links capability account to see it.

6. Thermal runaway#

An exothermic batch reaction with cooling is stable below a critical ambient temperature and runs away above it. The tipping point is a property of the vessel, not of the reaction alone.

chem.add('go', { reactants: { A: 1 }, products: { B: 1 }, A: 1e9, Ea: 70e3, phase: 'solution' });
const v = new Vessel(chem, { volume: 1e-3, T: Tenv, Tenv, hA: 3, contents: { A: 1, Solvent: 20 } });
v.react(1);

The rise above ambient grows steeply with the ambient temperature; this is the signature of runaway. A batch at 280 K stays modest; the same batch at 340 K heats itself far more. With the capability on, chem:runaway fires when the heating rate passes runaway (50 K/s by default), which is the hook for an alarm or a relief valve.

7. An overloaded wire#

A wire at its ampacity settles at its rated temperature rise; above, it reaches the insulation limit on its thermal time constant.

c.add(new ISource('I', '0', 'a', amps));
c.add(new Wire('W', 'a', '0', 0.01, 5, 10, 100, 343.15, 293.15, 40));    // 10 A rating, 40 K rise, insulation limit 343 K
c.onEvent = e => { if (e.type === 'overheat') { /* ... */ } };

At 10 A the wire settles at its rated rise and never overheats; at 15 A it does. Tie circuit:overheat to a fire with the wireFire link, and put a fuse in series to prevent it: size the fuse's i2t below what takes the wire to its limit.

8. A glowing brake disc#

Braking turns the kinetic energy of the car into heat in the disc. Once the disc passes 798 K it starts to glow, and the glow is what glow paints on the mesh.

const brake = train.brake('brake', car, 3000);
brake.command = 1;
const link = slipHeats(brake, disc, net);
// each step
train.step(dt, 4); net.step(dt); link.step(dt, host, []);
const glowAmount = incandescence(disc.T), colour = blackbody(disc.T);

All the kinetic energy goes into the disc: 1.5 MJ in 2 kg of steel is far past the point where it glows red-orange. Hand the disc's T to glow(scene, mesh, () => disc.T) and the render does the rest. The numbers are exaggerated on purpose (a 2 kg disc, one hard stop): a real car brakes in many pulses with cooling in between.