src/Utils.cpp

changeset 337
8133cdb19aa1
parent 336
e97f9e87d94b
child 339
2f3cfb983fcc
--- a/src/Utils.cpp	Tue Jul 05 14:31:39 2022 +0200
+++ b/src/Utils.cpp	Thu Jul 07 08:51:57 2022 +0200
@@ -360,129 +360,163 @@
     return round((og * 1000 - fg * 1000) * factor * 100) / 100;
 }
 
+
+double Utils::brewery_hPa()
+{
+    return Seapressure * exp( - MolMassAir * Gravacc * my_height / (Gasconst * (20 + Kelvin)));
+}
+
+
+double Utils::boilPoint()
+{
+    double P2 = brewery_hPa();
+
+    return (1 / (1/(100 + Kelvin) - Gasconst * log(P2 / Seapressure) / EoVwater)) - Kelvin;
+}
+
+
 /*
+ * Formula is from the 'Mash Made Easy' spreadsheet.
+ * https://mashmadeeasy.yolasite.com/
+ * https://www.homebrewtalk.com/threads/a-rather-simplified-whirlpool-hop-ibu-computation-method.701093/
+ */
+double Utils::IBU_reduction(double Tc)
+{
+    return (2.39 * pow(10, 11) * pow(2.71828182846, - (9773 / (Tc + Kelvin))) ) * 1/1.009231744;
+}
+
+
 double Utils::boilIBU(int Form, double SG, double Volume, double Amount, double Time, double Alpha, int Method)
 {
+    double	ibu = 0.0, sgfactor, boilfactor;
+
+    double alpha = Alpha / 100.0;
+    double mass = Amount * 1000.0;
+
     if (Method == 0) { // Tinseth
-*/        /* http://realbeer.com/hops/research.html */
-/*        AddedAlphaAcids = (alpha * mass * 1000) / liters;
-        Bigness_factor = 1.65 * pow(0.000125, gravity - 1);
-        BoilTime_factor = ((1 - exp(-0.04 * time)) / 4.15);
-        utiisation = Bigness_factor * BoilTime_factor;
-        ibu = round((utiisation * AddedAlphaAcids * fmoment * pfactor + whirlibus) * 100) / 100;
+        /* http://realbeer.com/hops/research.html */
+        double AddedAlphaAcids = (alpha * mass * 1000) / Volume;
+        double Bigness_factor = 1.65 * pow(0.000125, SG - 1);
+        double BoilTime_factor = ((1 - exp(-0.04 * Time)) / 4.15);
+        ibu = Bigness_factor * BoilTime_factor * AddedAlphaAcids;
     }
     if (Method == 2) { // Daniels
         if (Form == 2) // Leaf
-            boilfactor = -(0.0041 * time * time) + (0.6162 * time) + 1.5779;
+            boilfactor = -(0.0041 * Time * Time) + (0.6162 * Time) + 1.5779;
         else
-            boilfactor = -(0.0051 * time * time) + (0.7835 * time) + 1.9348;
-        if (gravity < 1050)
+            boilfactor = -(0.0051 * Time * Time) + (0.7835 * Time) + 1.9348;
+        if (SG < 1.050)
             sgfactor = 0;
         else
-            sgfactor = (gravity - 1050) / 200;
-        ibu = round((fmoment * ((mass * (alpha * 100) * boilfactor * 0.1) / (liters * (1 + sgfactor))) + whirlibus) * 100) / 100;
+            sgfactor = ((SG * 1000) - 1050) / 200;
+        ibu = (mass * (alpha * 100) * boilfactor * 0.1) / (Volume * (1 + sgfactor));
     }
     if (Method == 1) { // Rager
-        boilfactor = fmoment * 18.11 + 13.86 * tanh((time * 31.32) / 18.27);
-        if (gravity < 1050)
+        boilfactor = 18.11 + 13.86 * tanh((Time * 31.32) / 18.27);
+        if (SG < 1.050)
             sgfactor = 0;
         else
-            sgfactor = (gravity - 1050) / 200;
-        ibu = round(((mass * (alpha * 100) * boilfactor * 0.1) / (liters * (1 + sgfactor)) + whirlibus) * 100) / 100;
+            sgfactor = ((SG * 1000) - 1050) / 200;
+        ibu = (mass * (alpha * 100) * boilfactor * 0.1) / (Volume * (1 + sgfactor));
     }
+
+    //qDebug() << "boilIBU" << Form << SG << Volume << Amount << Time << Alpha << Method << "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)
 {
-    double	fmoment = 1.0, pfactor = 1.0, ibu = 0, boilfactor;
-    double	sgfactor, AddedAlphaAcids, Bigness_factor, BoilTime_factor, utiisation;
-
-    double gravity = SG;
-    double liters = Volume;
+    double ibu = 0.0, whirlibus = 0.0;
     double alpha = Alpha / 100.0;
     double mass = Amount * 1000.0;
-    double time = Boiltime;
-
-    if ((Use == HOP_USEAT_AROMA) || (Use == HOP_USEAT_WHIRLPOOL) || (Use == HOP_USEAT_DRY_HOP) || (Use == HOP_USEAT_BOTTLING)) {
-	fmoment = 0.0;
-    } else if (Use == HOP_USEAT_MASH) {
-	fmoment += my_factor_mashhop / 100.0;	// Brouwhulp
-	time = Fulltime;			// Take the full boiltime
-    } else if (Use == HOP_USEAT_FWH) {
-	fmoment += my_factor_fwh / 100.0;	// Brouwhulp, Louis, Ozzie
-	time = Fulltime;
-    }
-
-    if (Form == HOP_FORMS_PELLET) {
-	pfactor += my_factor_pellet / 100.0;
-    } else if (Form == HOP_FORMS_PLUG) {
-	pfactor += my_factor_plug / 100.0;
-    } else if (Form == HOP_FORMS_LEAF_WET) {
-	pfactor += my_factor_wethop / 100.0;	// From https://github.com/chrisgilmerproj/brewday/blob/master/brew/constants.py
-    } else if (Form == HOP_FORMS_CRYO) {
-	pfactor += my_factor_cryohop / 100.0;
-    } else if (Form == HOP_FORMS_EXTRACT) {
-	// Nothing for now.
-    }
 
     // Ideas from Zymurgy March-April 2018. These are not exact formulas!
-    double whirlibus = 0.0;
     if (Use == HOP_USEAT_AROMA) {
 	if (Whirlpool9) {	// Flameout hops are 2 minutes in this range.
-	    whirlibus += (alpha * mass * 20) / liters * (2.0 / 50.0);
+	    whirlibus += (alpha * mass * 20) / Volume * (2.0 / 50.0);
 	}
 	if (Whirlpool7) {	// Flameout hops are 4 minutes in this range.
-	    whirlibus += (alpha * mass * 6) / liters * (4.0 / 50.0);
+	    whirlibus += (alpha * mass * 6) / Volume * (4.0 / 50.0);
 	}
+	// Experiment.
+//	double wibu = boilIBU(Form, SG, Volume, Amount, 6, Alpha, Method);	// IBU's for 6 minutes full
+//	double fibu = wibu * 0.067 * IBU_reduction(94);		// Add timed segments
+//	fibu += wibu * 0.1 * IBU_reduction(84);
+//	fibu += wibu * 0.167 * IBU_reduction(74);
+//	fibu += wibu * 0.250 * IBU_reduction(64);
+//	fibu += wibu * 0.417 * IBU_reduction(54);
+	//qDebug() << "  94" << wibu * 0.067 * IBU_reduction(94);
+	//qDebug() << "  84" << wibu * 0.1 * IBU_reduction(84);
+	//qDebug() << "  74" << wibu * 0.167 * IBU_reduction(74);
+	//qDebug() << "  64" << wibu * 0.250 * IBU_reduction(64);
+	//qDebug() << "  54" << wibu * 0.417 * IBU_reduction(54);
+//	qDebug() << "flamout" << wibu << fibu;
     }
     if (Use == HOP_USEAT_WHIRLPOOL) {	// Flameout or any whirlpool
 	if (Whirlpool9) {
 	    // 20 mg/l/50 min
-	    whirlibus += (alpha * mass * 20) / liters * (Whirlpool9 / 50.0);
+	    whirlibus += (alpha * mass * 20) / Volume * (Whirlpool9 / 50.0);
 	    //qDebug() << "Whirlpool9" << alpha * mass * 20 << " liter:" << liters << " time:" << Whirlpool9 << " ibu" << (alpha * mass * 20) / liters * (Whirlpool9 / 50.0);
 	}
 	if (Whirlpool7) {
 	    // 6 mg/l/50 min
-	    whirlibus += (alpha * mass * 6) / liters * (Whirlpool7 / 50.0);
+	    whirlibus += (alpha * mass * 6) / Volume * (Whirlpool7 / 50.0);
 	    //qDebug() << "Whirlpool7" << alpha * mass * 6 << " liter:" << liters << " time:" << Whirlpool7 << " ibu" << (alpha * mass * 6) / liters * (Whirlpool7 / 50.0);
 	}
 	if (Whirlpool6) {
 	    // 2 mg/l/50 min
-	    whirlibus += (alpha * mass * 2) / liters * (Whirlpool6 / 50.0);
+	    whirlibus += (alpha * mass * 2) / Volume * (Whirlpool6 / 50.0);
 	}
+//	double wibu = boilIBU(Form, SG, Volume, Amount, Boiltime, Alpha, Method);
+//	qDebug() << "whirpool" << wibu << wibu * IBU_reduction(74);
     }
 
-    if (Method == 0) { // Tinseth
-	/* http://realbeer.com/hops/research.html */
-	AddedAlphaAcids = (alpha * mass * 1000) / liters;
-	Bigness_factor = 1.65 * pow(0.000125, gravity - 1);
-	BoilTime_factor = ((1 - exp(-0.04 * time)) / 4.15);
-	utiisation = Bigness_factor * BoilTime_factor;
-	ibu = round((utiisation * AddedAlphaAcids * fmoment * pfactor + whirlibus) * 100) / 100;
-    }
-    if (Method == 2) { // Daniels
-	if (Form == 2) // Leaf
-	    boilfactor = -(0.0041 * time * time) + (0.6162 * time) + 1.5779;
-	else
-	    boilfactor = -(0.0051 * time * time) + (0.7835 * time) + 1.9348;
-	if (gravity < 1050)
-	    sgfactor = 0;
-	else
-	    sgfactor = (gravity - 1050) / 200;
-	ibu = round((fmoment * ((mass * (alpha * 100) * boilfactor * 0.1) / (liters * (1 + sgfactor))) + whirlibus) * 100) / 100;
-    }
-    if (Method == 1) { // Rager
-	boilfactor = fmoment * 18.11 + 13.86 * tanh((time * 31.32) / 18.27);
-	if (gravity < 1050)
-	    sgfactor = 0;
-	else
-	    sgfactor = (gravity - 1050) / 200;
-	ibu = round(((mass * (alpha * 100) * boilfactor * 0.1) / (liters * (1 + sgfactor)) + whirlibus) * 100) / 100;
+    /*
+     * IBU's from hops during Mash, FWH and boil.
+     */
+    if ((Use == HOP_USEAT_MASH) || (Use == HOP_USEAT_FWH) || (Use == HOP_USEAT_BOIL)) {
+	ibu = boilIBU(Form, SG, Volume, Amount, Fulltime, Alpha, Method);
+	/*
+	 * Corrections for Mash and FWH
+	 */
+	if (Use == HOP_USEAT_MASH) {
+	    ibu *= (1 + my_factor_mashhop / 100.0);
+	}
+	if (Use == HOP_USEAT_FWH) {
+            ibu *= (1 + my_factor_fwh / 100.0);
+	}
+
+	/*
+	 * Correction for hop forms
+	 */
+	if (Form == HOP_FORMS_PELLET) {
+            ibu *= (1 + my_factor_pellet / 100.0);
+	} else if (Form == HOP_FORMS_PLUG) {
+	    ibu *= (1 + my_factor_plug / 100.0);
+	} else if (Form == HOP_FORMS_LEAF_WET) {
+	    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.
+	}
+//	ibu *= IBU_reduction(boilPoint());
+//	qDebug() << "ibu" << ibu << IBU_reduction(boilPoint());
+
+//    } else if (Use == HOP_USEAT_AROMA) {
+	/*
+	 * At flameout. The cooling method is important.
+	 * Emersion chiller, Counterflow chiller, Au bain marie or natural.
+	 * Assume the hop is removed for all methods except Emersion chilling.
+	 */
+    } else {
+//	qDebug() << "whirlibus" <<  whirlibus << Use;
     }
 
-    return ibu;
+
+    return round((ibu + whirlibus) * 100.0) / 100.0;
 }
 
 

mercurial