The total grist mass that puts a bill of shares on a target OG, or null.
This is the inverse of the waterfall at the top of this file. Each addition
contributes kg × pointsPerKgPerL × efficiency, and with fixed shares every
kg is the same multiple of the total, so the gravity is proportional to the
total mass and the answer is a single division:
The result is exact because nothing in the forward calculation adds a term
that doesn't scale with mass. Efficiency is a per-class constant
(fermentableEfficiencyFraction reads class and use, never a
mass). When designing forward, the post-boil volume comes from the target
batch size and the equipment's losses. Grain absorption changes the water
required, not the volume in the kettle (volumes.ts). gravity.test.ts
checks this by sizing a grist and reading the target back out of
predictGravities.
Why this isn't sugarToTargetGravity
sugarToTargetGravity answers the brew-day question ("my gravity is low,
how much DME?") and returns 0 when the deficit isn't positive, because you
can't take sugar back out of a kettle. When you're designing a recipe, the
most common reason to set a target is that the bill overshoots, so this
function has to size down as well as up.
null covers every grist that no mass can satisfy: nothing in it has
extract, every share is zero, the volume isn't positive, or the target is at
or below water. These are states a half-entered bill passes through, so we
return null and let the caller decide what to show, instead of throwing.
The total grist mass that puts a bill of shares on a target OG, or
null.This is the inverse of the waterfall at the top of this file. Each addition contributes
kg × pointsPerKgPerL × efficiency, and with fixed shares everykgis the same multiple of the total, so the gravity is proportional to the total mass and the answer is a single division:The result is exact because nothing in the forward calculation adds a term that doesn't scale with mass. Efficiency is a per-class constant (fermentableEfficiencyFraction reads
classanduse, never a mass). When designing forward, the post-boil volume comes from the target batch size and the equipment's losses. Grain absorption changes the water required, not the volume in the kettle (volumes.ts).gravity.test.tschecks this by sizing a grist and reading the target back out of predictGravities.Why this isn't
sugarToTargetGravitysugarToTargetGravityanswers the brew-day question ("my gravity is low, how much DME?") and returns 0 when the deficit isn't positive, because you can't take sugar back out of a kettle. When you're designing a recipe, the most common reason to set a target is that the bill overshoots, so this function has to size down as well as up.nullcovers every grist that no mass can satisfy: nothing in it has extract, every share is zero, the volume isn't positive, or the target is at or below water. These are states a half-entered bill passes through, so we returnnulland let the caller decide what to show, instead of throwing.