src/Utils.cpp

changeset 373
b02aca4e926c
parent 356
f60f5a1fece9
child 375
c21567bfd703
--- a/src/Utils.cpp	Tue Jul 26 19:46:44 2022 +0200
+++ b/src/Utils.cpp	Fri Jul 29 13:12:26 2022 +0200
@@ -391,10 +391,51 @@
 }
 
 
-double Utils::TinsethIBU(int Form, double SG, double Volume, double Amount, double T1, double T2, double Alpha)
+double Utils::TinsethIBU(int Form, double SG, double Volume, double Amount, double T1, double T2, double Alpha, double Utilisation, double BU_factor)
 {
     double alpha = Alpha / 100.0;
     double mass = Amount * 1000.0;
+    double ibu = 0.0;
+
+    /*
+     * Most suppliers of CO2 hop extract (not isomerized) use formulas
+     * like this. For now, manual set a utilisation factor of 35%.
+     */
+    if (Form == HOP_FORMS_CO2EXTRACT) {
+	double utilisation = 0.35;	// 35%
+	double factor_sg = 1.0;
+	double factor_bt = 1.0;
+	double bt = T2 - T1;
+
+	/* Table from Wildabouthops */
+	if (SG >= 1.150)
+	    factor_sg = 1.3;
+	else if (SG >= 1.110)
+	    factor_sg = 1.2;
+	else if (SG >= 1.080)
+	    factor_sg = 1.1;
+
+	if (bt > 60) {
+	    factor_bt = ((bt - 60) / 300) + 1.0;
+	} else {
+	    factor_bt = (bt / 60.0);
+	}
+	qDebug() << "factor_sg" << factor_sg << "factor_bt" << factor_bt;
+
+	ibu = ((Utilisation / 100.0) * alpha * mass * 1000.0) / Volume;
+	ibu = (ibu * factor_bt) / factor_sg;
+	qDebug() << "TinsethIBU CO2" << Amount << Alpha << Volume << Utilisation << BU_factor << "SG" << SG << "T" << T1 << T2 << "ibu:" << ibu;
+	return ibu;
+    }
+
+    if (Form == HOP_FORMS_ISOEXTRACT) {
+
+	double dosageHl = ((100.0 / Utilisation) * (100.0 / Alpha) * 0.001) / BU_factor;	// IBU per liter
+	qDebug() << (100 / Utilisation) << (100 / Alpha) << dosageHl << dosageHl * Volume << mass / (dosageHl * Volume);
+	ibu = mass / (dosageHl * Volume);
+	qDebug() << "TinsethIBU ISO" << Amount << Alpha << Volume << Utilisation << BU_factor << "ibu:" << ibu;
+	return ibu;
+    }
 
     /*
      * Basic Tinseth formula.
@@ -404,7 +445,8 @@
     double Bigness_factor = 1.65 * pow(0.000125, SG - 1);
     double BoilTime_factor1 = ((1 - exp(-0.04 * T1)) / 4.15);
     double BoilTime_factor2 = ((1 - exp(-0.04 * T2)) / 4.15);
-    double ibu = Bigness_factor * (BoilTime_factor2 - BoilTime_factor1) * AddedAlphaAcids;
+    ibu = Bigness_factor * (BoilTime_factor2 - BoilTime_factor1) * AddedAlphaAcids;
+    qDebug() << "TinsethIBU nor" << SG << Amount << Alpha << Volume << Bigness_factor * (BoilTime_factor2 - BoilTime_factor1) << "ibu:" << ibu;
 
     /*
      * Correction for hop forms
@@ -417,17 +459,16 @@
 	ibu *= (1 + my_factor_wethop / 100.0);      // From https://github.com/chrisgilmerproj/brewday/blob/master/brew/constants.py
     } else if (Form == HOP_FORMS_CRYO) {
 	ibu *= (1 + my_factor_cryohop / 100.0);
-    } else if (Form == HOP_FORMS_EXTRACT) {
-	// Nothing for now.
     }
 
-    //qDebug() << "boilIBU" << Form << SG << Volume << Amount << T1 << T2 << Alpha << "IBU:" << ibu;
+    qDebug() << "boilIBU" << Form << SG << Volume << Amount << BoilTime_factor2 << BoilTime_factor1 << Alpha << "IBU:" << ibu;
     return ibu;
 }
 
 
-double Utils::toIBU(int Use, int Form, double SG, double Volume, double Amount, double Boiltime, double Alpha,
-		    int Method, double Whirlpool9, double Whirlpool7, double Whirlpool6, double Fulltime, int Cooltype, double Coolparm1, double Coolparm2)
+double Utils::toIBU(int Use, int Form, double preSG, double postSG, double Volume, double Amount, double Boiltime, double Alpha,
+		    int Method, double Whirlpool9, double Whirlpool7, double Whirlpool6, double Fulltime,
+		    int Cooltype, double Coolparm1, double Coolparm2, double Utilisation, double BU_factor)
 {
     double ibu = 0.0;
 
@@ -440,7 +481,7 @@
 	 *
 	 * http://scottjanish.com/the-locksmith-utilizing-bioengineered-yeast-and-high-bound-thiol-precersour-hops-and-phantasm-powder-to-thiol-drive-beer/
 	 */
-	ibu = TinsethIBU(Form, SG, Volume, Amount, 0, 60, Alpha) * (1 + my_factor_mashhop / 100.0);
+	ibu = TinsethIBU(Form, preSG, Volume, Amount, 0, 60, Alpha, Utilisation, BU_factor) * (1 + my_factor_mashhop / 100.0);
 
     } else if ((Use == HOP_USEAT_FWH) || (Use == HOP_USEAT_BOIL)) {
 	/*
@@ -449,10 +490,12 @@
 	double boil_time = Fulltime;
 	if (Use == HOP_USEAT_BOIL)
 	    boil_time = Boiltime;
-	ibu = TinsethIBU(Form, SG, Volume, Amount, 0, boil_time, Alpha);
+	double fromSG = postSG - ((boil_time / Fulltime) * (postSG - preSG));	/* SG when this hop addition starts */
+	double avgSG = (postSG + fromSG) / 2;					/* Average SG during this addition */
+	ibu = TinsethIBU(Form, avgSG, Volume, Amount, 0, boil_time, Alpha, Utilisation, BU_factor);
 
 	/*
-	 * Corrections for Mash and FWH
+	 * Correction for FWH
 	 */
 	if (Use == HOP_USEAT_FWH) {
             ibu *= (1 + my_factor_fwh / 100.0);
@@ -466,7 +509,7 @@
 	     * Flameout, currently fixed 1 minute.
 	     */
 	    double flameout_time = 1;
-	    double fibu = TinsethIBU(Form, SG, Volume, Amount, boil_time, boil_time + flameout_time, Alpha);
+	    double fibu = TinsethIBU(Form, postSG, Volume, Amount, boil_time, boil_time + flameout_time, Alpha, Utilisation, BU_factor);
 	    fibu *= IBU_reduction(98.0);
 	    //qDebug() << "during flameout" << fibu;
 	    nibu += fibu;
@@ -476,19 +519,19 @@
 	     * Hopstands, this boil hop adds some IBU's too.
 	     */
 	    if (Whirlpool9) {
-		double wibu9 = TinsethIBU(Form, SG, Volume, Amount, boil_time + flameout_time, boil_time + flameout_time + Whirlpool9, Alpha);
+		double wibu9 = TinsethIBU(Form, postSG, Volume, Amount, boil_time + flameout_time, boil_time + flameout_time + Whirlpool9, Alpha, Utilisation, BU_factor);
 		wibu9 *= IBU_reduction(87.0);
 		//qDebug() << "during whirlpool9" << wibu9;
 		nibu += wibu9;
 	    }
 	    if (Whirlpool7) {
-		double wibu7 = TinsethIBU(Form, SG, Volume, Amount, boil_time + flameout_time, boil_time + flameout_time + Whirlpool7, Alpha);
+		double wibu7 = TinsethIBU(Form, postSG, Volume, Amount, boil_time + flameout_time, boil_time + flameout_time + Whirlpool7, Alpha, Utilisation, BU_factor);
 		wibu7 *= IBU_reduction(74.0);
 		//qDebug() << "during whirlpool7" << wibu7;
 		nibu += wibu7;
 	    }
 	    if (Whirlpool6) {
-                double wibu6 = TinsethIBU(Form, SG, Volume, Amount, boil_time + flameout_time, boil_time + flameout_time + Whirlpool6, Alpha);
+                double wibu6 = TinsethIBU(Form, postSG, Volume, Amount, boil_time + flameout_time, boil_time + flameout_time + Whirlpool6, Alpha, Utilisation, BU_factor);
                 wibu6 *= IBU_reduction(63.0);
                 //qDebug() << "during whirlpool6" << wibu6;
                 nibu += wibu6;
@@ -502,25 +545,25 @@
 	 * At flameout, and only using extended calculation.
 	 */
 	double flameout_time = 1;
-        ibu = TinsethIBU(Form, SG, Volume, Amount, 0, flameout_time, Alpha);
+        ibu = TinsethIBU(Form, postSG, Volume, Amount, 0, flameout_time, Alpha, Utilisation, BU_factor);
         ibu *= IBU_reduction(98.0);
 	/*
          * Hopstands, this flameout hop adds some IBU's too.
          */
         if (Whirlpool9) {
-            double wibu9 = TinsethIBU(Form, SG, Volume, Amount, flameout_time, flameout_time + Whirlpool9, Alpha);
+            double wibu9 = TinsethIBU(Form, postSG, Volume, Amount, flameout_time, flameout_time + Whirlpool9, Alpha, Utilisation, BU_factor);
             wibu9 *= IBU_reduction(87.0);
             //qDebug() << "during whirlpool9" << wibu9;
             ibu += wibu9;
         }
         if (Whirlpool7) {
-            double wibu7 = TinsethIBU(Form, SG, Volume, Amount, flameout_time, flameout_time + Whirlpool7, Alpha);
+            double wibu7 = TinsethIBU(Form, postSG, Volume, Amount, flameout_time, flameout_time + Whirlpool7, Alpha, Utilisation, BU_factor);
             wibu7 *= IBU_reduction(74.0);
             //qDebug() << "during whirlpool7" << wibu7;
             ibu += wibu7;
         }
         if (Whirlpool6) {
-            double wibu6 = TinsethIBU(Form, SG, Volume, Amount, flameout_time, flameout_time + Whirlpool6, Alpha);
+            double wibu6 = TinsethIBU(Form, postSG, Volume, Amount, flameout_time, flameout_time + Whirlpool6, Alpha, Utilisation, BU_factor);
             wibu6 *= IBU_reduction(63.0);
             //qDebug() << "during whirlpool6" << wibu6;
             ibu += wibu6;
@@ -531,33 +574,39 @@
          * Hopstands.
          */
         if (Whirlpool9) {
-            double wibu9 = TinsethIBU(Form, SG, Volume, Amount, 0, Whirlpool9, Alpha);
+            double wibu9 = TinsethIBU(Form, postSG, Volume, Amount, 0, Whirlpool9, Alpha, Utilisation, BU_factor);
             wibu9 *= IBU_reduction(87.0);
             //qDebug() << "during whirlpool9" << wibu9;
             ibu = wibu9;
         }
         if (Whirlpool7) {
-            double wibu7 = TinsethIBU(Form, SG, Volume, Amount, 0, Whirlpool7, Alpha);
+            double wibu7 = TinsethIBU(Form, postSG, Volume, Amount, 0, Whirlpool7, Alpha, Utilisation, BU_factor);
             wibu7 *= IBU_reduction(74.0);
             //qDebug() << "during whirlpool7" << wibu7;
             ibu = wibu7;
         }
         if (Whirlpool6) {
-            double wibu6 = TinsethIBU(Form, SG, Volume, Amount, 0, Whirlpool6, Alpha);
+            double wibu6 = TinsethIBU(Form, postSG, Volume, Amount, 0, Whirlpool6, Alpha, Utilisation, BU_factor);
             wibu6 *= IBU_reduction(63.0);
             //qDebug() << "during whirlpool6" << wibu6;
             ibu = wibu6;
         }
+    } else if (Use == HOP_USEAT_BOTTLING) {
+	/*
+	 * Isomerized hop extracts to use at bottling.
+	 * Assume 10% volume is lost during fermentation and transfers.
+	 */
+	ibu = TinsethIBU(Form, postSG, Volume * 0.9, Amount, 0, 0, Alpha, Utilisation, BU_factor);
     }
 
     double rc = round(ibu * 1000.0) / 1000.0;
 
-    qDebug() << "toIBU" << Use << Form << SG << Volume << Amount << Boiltime << Alpha << Method << Whirlpool9 << Whirlpool7 << Whirlpool6 << Fulltime << Cooltype << Coolparm1 << Coolparm2 << "rc:" << rc;
+    qDebug() << "toIBU" << Use << Form << preSG << postSG << Volume << Amount << Boiltime << Alpha << Method << Whirlpool9 << Whirlpool7 << Whirlpool6 << Fulltime << Cooltype << Coolparm1 << Coolparm2 << Utilisation << BU_factor << "rc:" << rc;
     return rc;
 }
 
 
-double Utils::hopFlavourContribution(double bt, double vol, int use, double amount)
+double Utils::hopFlavourContribution(double bt, double vol, int use, double amount, int form)
 {
     double result;
 
@@ -576,9 +625,13 @@
 }
 
 
-double Utils::hopAromaContribution(double bt, double vol, int use, double amount)
+double Utils::hopAromaContribution(double bt, double vol, int use, double amount, int form)
 {
     double result = 0.0;
+    double factor = 1.0;
+
+    if (form == HOP_FORMS_CRYO)
+	factor = 2.0;
 
     if (use == HOP_USEAT_DRY_HOP) {
 	result = 1.33;
@@ -595,7 +648,7 @@
     } else if (use == HOP_USEAT_AROMA) {  // Aroma
 	result = 1.2;
     }
-    return (result * amount * 1000.0) / vol;
+    return (result * amount * factor * 1000.0) / vol;
 }
 
 

mercurial