Skip to content

Commit

Permalink
Merge pull request #919 from matty0ung/usability
Browse files Browse the repository at this point in the history
Fix places where we are using old ABV formulae
  • Loading branch information
matty0ung authored Jan 4, 2025
2 parents c643f74 + a0a092c commit 2f94637
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 26 deletions.
28 changes: 17 additions & 11 deletions src/Algorithms.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
* Algorithms.cpp is part of Brewtarget, and is copyright the following authors 2009-2023:
* Algorithms.cpp is part of Brewtarget, and is copyright the following authors 2009-2025:
* • Eric Tamme <[email protected]>
* • Matt Young <[email protected]>
* • Philip Greggory Lee <[email protected]>
Expand Down Expand Up @@ -247,7 +247,7 @@ double Polynomial::rootFind( double x0, double x1 ) const {
return newGuess;
}

//╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
//======================================================================================================================

bool Algorithms::isNan(double d) {
// If using IEEE floating points, all comparisons with a NaN
Expand Down Expand Up @@ -475,6 +475,12 @@ double Algorithms::abvFromOgAndFg(double og, double fg) {
// Assert the parameters were supplied in the right order by checking that FG cannot by higher than OG
Q_ASSERT(og >= fg);

//
// Previously, in different places in the code, we either used a very rough rule of thumb:
//
// double calculatedABV_pct = (og - fg) * 130
//
// or we used the FALLBACK METHOD described below.
//
// The current calculation method we use comes from the UK Laboratory of the Government Chemist. It is what HM
// Revenue and Customs (HMRC) encourage UK microbreweries to use to calculate ABV if they have "no or minimal
Expand Down Expand Up @@ -526,7 +532,7 @@ double Algorithms::abvFromOgAndFg(double og, double fg) {
);

//
// OLD METHOD, which is also the fallback
// FALLBACK METHOD
//
// From http://www.brewersfriend.com/2011/06/16/alcohol-by-volume-calculator-updated/:
// "[This] formula, and variations on it, comes from Ritchie Products Ltd, (Zymurgy, Summer 1995, vol. 18, no. 2)
Expand All @@ -536,31 +542,31 @@ double Algorithms::abvFromOgAndFg(double og, double fg) {
// The relationship between the change in gravity, and the change in ABV is not linear. All these equations are
// approximations."
//
double abvByOldMethod = (76.08 * (og - fg) / (1.775 - og)) * (fg / 0.794);
double const abvByFallbackMethod = (76.08 * (og - fg) / (1.775 - og)) * (fg / 0.794);

if (matchingGravityDifferenceRec == gravityDifferenceFactors.cend()) {
qCritical() <<
Q_FUNC_INFO << "Could not find gravity difference record for difference of " <<
(excessGravityDiffx10 / 10.0) << "so using fallback method";
return abvByOldMethod;
return abvByFallbackMethod;
}

double abvByNewMethod = excessGravityDiff * matchingGravityDifferenceRec->factorToUse;
double const abvByHmrcMethod = excessGravityDiff * matchingGravityDifferenceRec->factorToUse;

qDebug() <<
Q_FUNC_INFO << "ABV old method:" << abvByOldMethod << "% , new method:" << abvByNewMethod << "% (used factor" <<
Q_FUNC_INFO << "ABV old method:" << abvByFallbackMethod << "% , new method:" << abvByHmrcMethod << "% (used factor" <<
matchingGravityDifferenceRec->factorToUse << "and should be in range" <<
matchingGravityDifferenceRec->pctAbv_Min << "% -" << matchingGravityDifferenceRec->pctAbv_Max << "%)";

// The tables from UK HMRC have some sanity-check data, so let's use it!
if (abvByNewMethod < matchingGravityDifferenceRec->pctAbv_Min ||
abvByNewMethod > matchingGravityDifferenceRec->pctAbv_Max) {
if (abvByHmrcMethod < matchingGravityDifferenceRec->pctAbv_Min ||
abvByHmrcMethod > matchingGravityDifferenceRec->pctAbv_Max) {
qWarning() <<
Q_FUNC_INFO << "Calculated ABV of" << abvByNewMethod << "% is outside expected range (" <<
Q_FUNC_INFO << "Calculated ABV of" << abvByHmrcMethod << "% is outside expected range (" <<
matchingGravityDifferenceRec->pctAbv_Min << "% -" << matchingGravityDifferenceRec->pctAbv_Max << "%)";
}

return abvByNewMethod;
return abvByHmrcMethod;
}

double Algorithms::correctSgForTemperature(double measuredSg, double readingTempInC, double calibrationTempInC) {
Expand Down
15 changes: 8 additions & 7 deletions src/model/BrewNote.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
* model/BrewNote.cpp is part of Brewtarget, and is copyright the following authors 2009-2024:
* model/BrewNote.cpp is part of Brewtarget, and is copyright the following authors 2009-2025:
* • Brian Rower <[email protected]>
* • Greg Meess <[email protected]>
* • Jonatan Pålsson <[email protected]>
Expand Down Expand Up @@ -563,16 +563,17 @@ double BrewNote::calculateABV_pct() {
// 1 + [(og - 1) * (1.0 - %/100)]
double const estFg = 1 + ((m_og-1.0)*(1.0 - atten_pct/100.0));

double const calculatedABV = (m_og-estFg)*130;
this->setProjABV_pct(calculatedABV);
double const calculatedAbv_pct = Algorithms::abvFromOgAndFg(this->m_og, estFg);

return calculatedABV;
this->setProjABV_pct(calculatedAbv_pct);

return calculatedAbv_pct;
}

double BrewNote::calculateActualABV_pct() {
double const abv = (m_og - m_fg) * 130;
this->setABV(abv);
return abv;
double const abv_pct = Algorithms::abvFromOgAndFg(this->m_og, this->m_fg);
this->setABV(abv_pct);
return abv_pct;
}

double BrewNote::calculateAttenuation_pct() {
Expand Down
17 changes: 9 additions & 8 deletions src/model/Recipe.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
* model/Recipe.cpp is part of Brewtarget, and is copyright the following authors 2009-2024:
* model/Recipe.cpp is part of Brewtarget, and is copyright the following authors 2009-2025:
* • Brian Rower <[email protected]>
* • Greg Greenaae <[email protected]>
* • Greg Meess <[email protected]>
Expand Down Expand Up @@ -1225,16 +1225,11 @@ class Recipe::impl {
return;
}


/**
* Emits changed(ABV_pct). Depends on: m_og, m_fg
*/
void recalcABV_pct() {
// The complex formula, and variations comes from Ritchie Products Ltd, (Zymurgy, Summer 1995, vol. 18, no. 2)
// Michael L. Hall’s article Brew by the Numbers: Add Up What’s in Your Beer, and Designing Great Beers by Daniels.
double calculatedABV_pct =
(76.08 * (this->m_og_fermentable - this->m_fg_fermentable) / (1.775 - this->m_og_fermentable)) *
(this->m_fg_fermentable / 0.794);
double const calculatedABV_pct = Algorithms::abvFromOgAndFg(this->m_og_fermentable, this->m_fg_fermentable);

if (!qFuzzyCompare(calculatedABV_pct, m_ABV_pct)) {
qDebug() <<
Expand Down Expand Up @@ -2657,9 +2652,15 @@ double Recipe::ibuFromHopAddition(RecipeAdditionHop const & hopAddition) {
boilTime_mins = static_cast<int>(equipment->boilTime_min().value_or(Equipment::default_boilTime_mins));
}

// Assume 30 min cool time if boil is not set
double coolTime_mins = 30.0;

auto boil = this->boil();
if (boil) {
boilTime_mins = boil->boilTime_mins();
if (boil->coolTime_mins()) {
coolTime_mins = *boil->coolTime_mins();
}
}

qDebug() <<
Expand All @@ -2674,7 +2675,7 @@ double Recipe::ibuFromHopAddition(RecipeAdditionHop const & hopAddition) {
.postBoilVolume_liters = this->pimpl->m_finalVolumeNoLosses_l,
.wortGravity_sg = m_og,
.timeInBoil_minutes = boilTime_mins, // Seems unlikely in reality that there would be fractions of a minute
.coolTime_minutes = boil->coolTime_mins(),
.coolTime_minutes = coolTime_mins,
};
if (equipment) {
parms.kettleInternalDiameter_cm = equipment->kettleInternalDiameter_cm();
Expand Down

0 comments on commit 2f94637

Please sign in to comment.