Mon, 18 Apr 2022 20:00:49 +0200
Added calcYeast(). Added show svg from calcFermentables() on the yeast tab. Fixed wrong data displayed in the yeast table. Show estimated needed dry yeast or starters.
src/EditRecipe.cpp | file | annotate | diff | comparison | revisions | |
src/EditRecipe.h | file | annotate | diff | comparison | revisions | |
src/EditRecipeTab2.cpp | file | annotate | diff | comparison | revisions | |
src/EditRecipeTab5.cpp | file | annotate | diff | comparison | revisions | |
ui/EditRecipe.ui | file | annotate | diff | comparison | revisions |
--- a/src/EditRecipe.cpp Mon Apr 18 10:55:33 2022 +0200 +++ b/src/EditRecipe.cpp Mon Apr 18 20:00:49 2022 +0200 @@ -713,6 +713,7 @@ calcIBUs(); refreshMiscs(); refreshYeasts(); + calcYeast(); refreshMashs(); refreshWaters(); calcWater();
--- a/src/EditRecipe.h Mon Apr 18 10:55:33 2022 +0200 +++ b/src/EditRecipe.h Mon Apr 18 20:00:49 2022 +0200 @@ -331,8 +331,10 @@ QStringList h_useat = { tr("Mash"), tr("First wort"), tr("Boil"), tr("Aroma"), tr("Whirlpool"), tr("Dry hop") }; QStringList m_types = { tr("Spice"), tr("Herb"), tr("Flavor"), tr("Fining"), tr("Water agent"), tr("Yeast nutrient"), tr("Other") }; QStringList m_uses = { tr("Starter"), tr("Mash"), tr("Boil"), tr("Primary"), tr("Secondary"), tr("Bottling") }; - QStringList y_types = { tr("Liquid"), tr("Dry"), tr("Slant"), tr("Culture"), tr("Frozen"), tr("Bottle"), tr("Dried") }; + //QStringList y_types = { tr("Lager"), tr("Ale"), tr("Wheat"), tr("Wine"), tr("Champagne"), tr("Brett"), tr("Kveik"), tr("Hybrid") }; + QStringList y_forms = { tr("Liquid"), tr("Dry"), tr("Slant"), tr("Culture"), tr("Frozen"), tr("Bottle"), tr("Dried") }; QStringList y_use = { tr("Primary"), tr("Secondary"), tr("Tertiary"), tr("Bottle") }; + QStringList starters = { tr("Stirred"), tr("Shaken"), tr("Simple") }; QString bar_red = "QProgressBar::chunk {background: #FF0000;}"; QString bar_orange = "QProgressBar::chunk {background: #EB7331;}"; QString bar_green = "QProgressBar::chunk {background: #008C00;}"; @@ -374,6 +376,7 @@ void calcWater(); double GetBUGU(); double GetOptSO4Clratio(); + void calcYeast(); }; #endif
--- a/src/EditRecipeTab2.cpp Mon Apr 18 10:55:33 2022 +0200 +++ b/src/EditRecipeTab2.cpp Mon Apr 18 20:00:49 2022 +0200 @@ -313,6 +313,7 @@ } if (svg == 0) svg = 77.0; + ui->est_svgEdit->setValue(svg); double fg; if (mashkg > 0 && mashinfuse > 0 && mashtime > 0 && mashtemp > 0)
--- a/src/EditRecipeTab5.cpp Mon Apr 18 10:55:33 2022 +0200 +++ b/src/EditRecipeTab5.cpp Mon Apr 18 20:00:49 2022 +0200 @@ -70,7 +70,7 @@ ui->yeastsTable->setItem(i, 1, new QTableWidgetItem(recipe->yeasts.at(i).y_laboratory)); ui->yeastsTable->setItem(i, 2, new QTableWidgetItem(recipe->yeasts.at(i).y_product_id)); - item = new QTableWidgetItem(y_types[recipe->yeasts.at(i).y_type]); + item = new QTableWidgetItem(y_forms[recipe->yeasts.at(i).y_form]); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 3, item); @@ -94,9 +94,9 @@ item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 8, item); - if (recipe->yeasts.at(i).y_type == 0) - item = new QTableWidgetItem(QString("%1 pack").arg(recipe->yeasts.at(i).y_amount * 1000.0, 3, 'f', 2, '0')); - else if (recipe->yeasts.at(i).y_type == 1) + if (recipe->yeasts.at(i).y_form == 0) + item = new QTableWidgetItem(QString("%1 pack").arg(recipe->yeasts.at(i).y_amount, 1, 'f', 0, '0')); + else if (recipe->yeasts.at(i).y_form == 1) item = new QTableWidgetItem(QString("%1 gr").arg(recipe->yeasts.at(i).y_amount * 1000.0, 3, 'f', 2, '0')); else item = new QTableWidgetItem(QString("%1 ml").arg(recipe->yeasts.at(i).y_amount * 1000.0, 3, 'f', 2, '0')); @@ -130,6 +130,90 @@ } +/* + * The results are not stored line in EditProduct. This is just a hint. + */ +void EditRecipe::calcYeast() +{ + double sg = recipe->est_og; + double plato = Utils::sg_to_plato(sg); + double volume = recipe->batch_size * 0.9; // Volume min trub chiller loss. + bool maybe_starter = false; + double pitchrate = 0.75; + double initcells = 0; + + qDebug() << "calcYeast()"; + ui->yeastProcedure->setCurrentIndex(0); + + if (recipe->yeasts.size() == 0) + return; // No yeast in recipe. + + for (int i = 0; i < recipe->yeasts.size(); i++) { + if (recipe->yeasts.at(i).y_use == 0) { // Primary + if (recipe->yeasts.at(i).y_form == 1) { + /* + * Dry yeast, build the formule with the yeast parameters. + * Based on https://www.lallemandbrewing.com/en/canada/brewers-corner/brewing-tools/pitching-rate-calculator/ + */ + ui->yeastProcedure->setCurrentIndex(2); + ui->lo_gr_hlEdit->setValue(recipe->yeasts.at(i).y_gr_hl_lo); + ui->hi_gr_hlEdit->setValue(recipe->yeasts.at(i).y_gr_hl_hi); + ui->lo_sgEdit->setValue(recipe->yeasts.at(i).y_sg_lo); + ui->hi_sgEdit->setValue(recipe->yeasts.at(i).y_sg_hi); + double og = recipe->yeasts.at(i).y_sg_lo; + double f1 = recipe->yeasts.at(i).y_gr_hl_lo / 100.0; + double f2 = round(f1 / 5 * 1000000.0) / 1000000.0; + double multiplier = (sg <= og) ? f1 : (f1 + f2 * (sg - og) / 0.008); + qDebug() << " sg:" << sg << "og:" << og << "f1:" << f1 << "f2:" << f2 << "multiplier:" << multiplier; + double yeast_grams = round(volume * multiplier * 100.0) / 100.0; // * (100 / dataRecord.starter_viability), 2); + double yeast_gr_hl = round((yeast_grams / (volume * 0.01)) * 100.0) / 100.0; + ui->need_grEdit->setValue(yeast_grams); + ui->pitch_grEdit->setValue(yeast_gr_hl); + qDebug() << " need" << yeast_grams << "grams, gr/hl:" << yeast_gr_hl; + return; + } else { + /* + * Liquid, slant, culture etc. + * pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/ + * and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ + */ + ui->yeastProcedure->setCurrentIndex(1); + if (recipe->yeasts.at(i).y_type == 0) { // Lager yeast + pitchrate = 1.5; + if (sg > 1.060) + pitchrate = 2.0; + } else if (recipe->yeasts.at(i).y_type == 6) { // Real Kveik + pitchrate = 0.075; + } else { + pitchrate = 0.75; + if (sg > 1.060) + pitchrate = 1.0; + } + if (recipe->yeasts.at(i).y_form == 0) + initcells = (recipe->yeasts.at(i).y_cells / 1000000000) * recipe->yeasts.at(i).y_amount * 0.97; // 97% viability assumed. + else + initcells = (recipe->yeasts.at(i).y_cells / 1000000) * recipe->yeasts.at(i).y_amount * 0.97; + + double needed = round(pitchrate * volume * plato * 10.0) / 10.0; + double starter = 0; + if (needed > initcells) { + maybe_starter = true; + starter = round(needed / 2.0) / 100.0; // A very rough starter size estimate. + } + + ui->pitchrateEdit->setValue(pitchrate); + ui->initcellsEdit->setValue(initcells); + ui->targetcellsEdit->setValue(needed); + ui->starterEdit->setValue(starter); + + qDebug() << " pitchrate:" << pitchrate << "needed:" << needed << "initcells:" << initcells << "starter" << maybe_starter << "size" << starter; + } + break; + } + } +} + + void EditRecipe::addYeastRow_clicked() {
--- a/ui/EditRecipe.ui Mon Apr 18 10:55:33 2022 +0200 +++ b/ui/EditRecipe.ui Mon Apr 18 20:00:49 2022 +0200 @@ -95,7 +95,7 @@ <enum>QTabWidget::Rounded</enum> </property> <property name="currentIndex"> - <number>3</number> + <number>4</number> </property> <property name="elideMode"> <enum>Qt::ElideNone</enum> @@ -1771,7 +1771,7 @@ <double>0.000000000000000</double> </property> <property name="maximum"> - <double>80.000000000000000</double> + <double>120.000000000000000</double> </property> <property name="singleStep"> <double>0.100000000000000</double> @@ -1797,21 +1797,207 @@ </rect> </property> <property name="currentIndex"> - <number>0</number> + <number>1</number> </property> <widget class="QWidget" name="yeastNot"/> <widget class="QWidget" name="yeastLiquid"> <widget class="QLabel" name="label"> <property name="geometry"> <rect> - <x>15</x> - <y>0</y> - <width>81</width> + <x>200</x> + <y>20</y> + <width>341</width> + <height>20</height> + </rect> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Liquid yeast advice</string> + </property> + </widget> + <widget class="QDoubleSpinBox" name="pitchrateEdit"> + <property name="geometry"> + <rect> + <x>200</x> + <y>60</y> + <width>91</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="maximum"> + <double>1000.000000000000000</double> + </property> + </widget> + <widget class="QLabel" name="pitchrateLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>60</y> + <width>181</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Pitchrate million cells/ml/°P:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QLabel" name="initcellsLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>90</y> + <width>181</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Initial billion cells:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QLabel" name="targetcellsLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>120</y> + <width>181</width> <height>20</height> </rect> </property> <property name="text"> - <string>Liquid Yeast</string> + <string>Target billion cells:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QDoubleSpinBox" name="initcellsEdit"> + <property name="geometry"> + <rect> + <x>200</x> + <y>90</y> + <width>91</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="decimals"> + <number>0</number> + </property> + <property name="maximum"> + <double>100000.000000000000000</double> + </property> + </widget> + <widget class="QDoubleSpinBox" name="targetcellsEdit"> + <property name="geometry"> + <rect> + <x>200</x> + <y>120</y> + <width>91</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="decimals"> + <number>0</number> + </property> + <property name="maximum"> + <double>100000.000000000000000</double> + </property> + </widget> + <widget class="QLabel" name="starterLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>150</y> + <width>181</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Starter volume L:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QDoubleSpinBox" name="starterEdit"> + <property name="geometry"> + <rect> + <x>200</x> + <y>150</y> + <width>91</width> + <height>24</height> + </rect> + </property> + <property name="toolTip"> + <string>A very rough starter volume estimate.</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="maximum"> + <double>100000.000000000000000</double> </property> </widget> </widget> @@ -1819,14 +2005,276 @@ <widget class="QLabel" name="label_2"> <property name="geometry"> <rect> - <x>15</x> - <y>0</y> - <width>71</width> + <x>170</x> + <y>10</y> + <width>261</width> + <height>20</height> + </rect> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Dry yeast advice</string> + </property> + </widget> + <widget class="QLabel" name="lo_gr_hlLabel"> + <property name="geometry"> + <rect> + <x>50</x> + <y>60</y> + <width>111</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Low grams/hl:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QLabel" name="hi_gr_hlLabel"> + <property name="geometry"> + <rect> + <x>50</x> + <y>90</y> + <width>111</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>High grams/hl:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QSpinBox" name="lo_gr_hlEdit"> + <property name="geometry"> + <rect> + <x>170</x> + <y>60</y> + <width>61</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="maximum"> + <number>500</number> + </property> + </widget> + <widget class="QSpinBox" name="hi_gr_hlEdit"> + <property name="geometry"> + <rect> + <x>170</x> + <y>90</y> + <width>61</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="maximum"> + <number>1000</number> + </property> + </widget> + <widget class="QLabel" name="lo_atLabel"> + <property name="geometry"> + <rect> + <x>240</x> + <y>60</y> + <width>31</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>at</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QLabel" name="hi_atLabel"> + <property name="geometry"> + <rect> + <x>240</x> + <y>90</y> + <width>31</width> <height>20</height> </rect> </property> <property name="text"> - <string>Dry Yeast</string> + <string>at</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QDoubleSpinBox" name="lo_sgEdit"> + <property name="geometry"> + <rect> + <x>280</x> + <y>60</y> + <width>71</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="maximum"> + <double>2.000000000000000</double> + </property> + <property name="value"> + <double>0.000000000000000</double> + </property> + </widget> + <widget class="QDoubleSpinBox" name="hi_sgEdit"> + <property name="geometry"> + <rect> + <x>280</x> + <y>90</y> + <width>71</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="maximum"> + <double>2.000000000000000</double> + </property> + </widget> + <widget class="QLabel" name="need_grLabel"> + <property name="geometry"> + <rect> + <x>50</x> + <y>120</y> + <width>111</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Pitch grams:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QDoubleSpinBox" name="need_grEdit"> + <property name="geometry"> + <rect> + <x>170</x> + <y>120</y> + <width>61</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="decimals"> + <number>1</number> + </property> + <property name="maximum"> + <double>1000.000000000000000</double> + </property> + </widget> + <widget class="QLabel" name="pitch_grLabel"> + <property name="geometry"> + <rect> + <x>50</x> + <y>150</y> + <width>111</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Pitch grams/hl:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QDoubleSpinBox" name="pitch_grEdit"> + <property name="geometry"> + <rect> + <x>170</x> + <y>150</y> + <width>61</width> + <height>24</height> + </rect> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="decimals"> + <number>2</number> + </property> + <property name="maximum"> + <double>1000.000000000000000</double> </property> </widget> </widget>