# HG changeset patch # User Michiel Broek # Date 1650449976 -7200 # Node ID ba25a566b1001c2dbbe9a5a024ad89083070ba0f # Parent af1386a6ece70d1ab963a6063c4cd0134400c37e Added calcMash(). Display total mash time. diff -r af1386a6ece7 -r ba25a566b100 src/EditRecipe.cpp --- a/src/EditRecipe.cpp Tue Apr 19 22:27:18 2022 +0200 +++ b/src/EditRecipe.cpp Wed Apr 20 12:19:36 2022 +0200 @@ -727,6 +727,7 @@ refreshMiscs(); refreshYeasts(); calcYeast(); + calcMash(); refreshMashs(); refreshWaters(); calcWater(); diff -r af1386a6ece7 -r ba25a566b100 src/EditRecipe.h --- a/src/EditRecipe.h Tue Apr 19 22:27:18 2022 +0200 +++ b/src/EditRecipe.h Wed Apr 20 12:19:36 2022 +0200 @@ -234,6 +234,8 @@ int miscs_row; int yeasts_row; int mashs_row; + double mashs_kg; ///< Kg fermentables in the mash. + int mashs_time; ///< Total mash time. double preboil_sg; }; @@ -396,6 +398,9 @@ double GetBUGU(); double GetOptSO4Clratio(); void calcYeast(); + double infusionVol(double step_infused, double step_mashkg, double infuse_temp, double step_temp, double last_temp); + double decoctionVol(double step_volume, double step_temp, double prev_temp); + void calcMash(); }; #endif diff -r af1386a6ece7 -r ba25a566b100 src/EditRecipeTab2.cpp --- a/src/EditRecipeTab2.cpp Tue Apr 19 22:27:18 2022 +0200 +++ b/src/EditRecipeTab2.cpp Wed Apr 20 12:19:36 2022 +0200 @@ -154,7 +154,6 @@ double addedmass = 0; // Added mass after boil double mvol = 0; // Mash volume double lintner = 0; // Total recipe lintner - double mashkg = 0; double sugarsf = 0; // fermentable sugars mash + boil double sugarsm = 0; // fermentable sugars in mash double sugardensity = 1.611; // kg/l in solution @@ -213,10 +212,12 @@ ui->est_abvShow->setValue(0); recipe->est_abv = 0; ui->calEdit->setValue(0); + recipe->mashs_kg = 0; return; } qDebug() << " adjust to 100" << recipe->fermentables_use100; + recipe->mashs_kg = 0; for (i = 0; i < recipe->fermentables.size(); i++) { if (recipe->fermentables.at(i).f_type == 1 && recipe->fermentables.at(i).f_added < 4) // Sugars psugar += recipe->fermentables.at(i).f_percentage; @@ -230,7 +231,7 @@ } d = ui->efficiencyEdit->value() / 100 * d; sugarsm += d; - mashkg += recipe->fermentables.at(i).f_amount; + recipe->mashs_kg += recipe->fermentables.at(i).f_amount; } if (recipe->fermentables.at(i).f_added == 0 || recipe->fermentables.at(i).f_added == 1) // Mash or boil sugarsf += d; @@ -291,11 +292,16 @@ * We don't have a equipment profile in recipes, * so we assume a certain guessed mashtun size. */ - ui->perc_mashShow->setValue(round(mashkg / (ui->boil_sizeEdit->value() / 3) * 100)); + ui->perc_mashShow->setValue(round(recipe->mashs_kg / (ui->boil_sizeEdit->value() / 3) * 100)); ui->perc_sugarsShow->setValue(round(psugar)); ui->perc_caraShow->setValue(round(pcara)); - qDebug() << " lintner" << lintner << " mashkg" << mashkg << "final" << round(lintner / mashkg); - ui->lintnerShow->setValue(round(lintner / mashkg)); + if (recipe->mashs_kg > 0) { + qDebug() << " lintner" << lintner << " mashkg" << recipe->mashs_kg << "final" << round(lintner / recipe->mashs_kg); + ui->lintnerShow->setValue(round(lintner / recipe->mashs_kg)); + } else { + qDebug() << " lintner N/A"; + ui->lintnerShow->setValue(0); + } /* * Calculate the apparant attenuation. @@ -316,8 +322,8 @@ ui->est_svgEdit->setValue(svg); double fg; - if (mashkg > 0 && mashinfuse > 0 && mashtime > 0 && mashtemp > 0) - fg = Utils::estimate_fg(psugar, pcara, mashinfuse / mashkg, mashtime, mashtemp, svg, og); + if (recipe->mashs_kg > 0 && mashinfuse > 0 && mashtime > 0 && mashtemp > 0) + fg = Utils::estimate_fg(psugar, pcara, mashinfuse / recipe->mashs_kg, mashtime, mashtemp, svg, og); else fg = Utils::estimate_fg(psugar, pcara, 0, 0, 0, svg, og); qDebug() << " FG" << ui->est_fgEdit->value() << fg; diff -r af1386a6ece7 -r ba25a566b100 src/EditRecipeTab6.cpp --- a/src/EditRecipeTab6.cpp Tue Apr 19 22:27:18 2022 +0200 +++ b/src/EditRecipeTab6.cpp Wed Apr 20 12:19:36 2022 +0200 @@ -26,12 +26,11 @@ QTableWidgetItem *item; QIcon down_icon, up_icon; + qDebug() << "refreshMashs" << recipe->mashs.size(); + down_icon.addFile(QString::fromUtf8(":/icons/silk/bullet_arrow_down.png"), QSize(), QIcon::Normal, QIcon::Off); up_icon.addFile(QString::fromUtf8(":/icons/silk/bullet_arrow_up.png"), QSize(), QIcon::Normal, QIcon::Off); - qDebug() << "refreshYeasts" << recipe->yeasts.size(); - std::sort(recipe->yeasts.begin(), recipe->yeasts.end(), yeast_sort_test); - /* * During filling the table turn off the cellChanged signal because every cell that is filled * triggers the cellChanged signal. The QTableWidget has no better signal to use. @@ -159,6 +158,97 @@ } +double EditRecipe::infusionVol(double step_infused, double step_mashkg, double infuse_temp, double step_temp, double last_temp) +{ + double a = last_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + double b = step_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + double vol = round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)) * 100.0) / 100.0; + + if (vol < 0) + vol = 0; + qDebug() << " infusionVol(" << step_infused << "," << step_mashkg << "," << infuse_temp <<"," << step_temp << "," << last_temp << "):" << vol; + return vol; +} + + +double EditRecipe::decoctionVol(double step_volume, double step_temp, double prev_temp) +{ + double a = (eq_tun_weight * eq_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp); + double b = SpecificHeatWater * (99 - step_temp); + double vol = 0; + + if (b > 0) + vol = round((a / b) * 1000000.0) / 1000000.0; + qDebug() << " decoctionVol(" << step_volume << "," << step_temp << "," << prev_temp << "):" << vol; + return vol; +} + + +void EditRecipe::calcMash() +{ + double infused = 0, vol, a, b, temp; + int i, j, n; + double lasttemp = 18.0; + double graintemp = 18.0; + double tuntemp = 18.0; + + recipe->mashs_time = 0; + + if (recipe->mashs.size() && recipe->mashs_kg > 0) { + qDebug() << "calcMash()"; + + for (i = 0; i < recipe->mashs.size(); i++) { + if (recipe->mashs.at(i).step_type == 0) { // Infusion + if (i == 0) { + // First mash step, temperature from the mashtun and malt. + n = 20; // tun is preheated. + tuntemp = recipe->mashs.at(i).step_temp; + for (j = 0; j < n; j++) { + a = recipe->mashs_kg * graintemp * SpecificHeatMalt + eq_tun_weight * tuntemp * eq_tun_specific_heat; + b = recipe->mashs[i].step_temp * + (eq_tun_weight * eq_tun_specific_heat + + recipe->mashs.at(i).step_infuse_amount * SpecificHeatWater + + recipe->mashs_kg * SpecificHeatMalt) - + SlakingHeat * recipe->mashs_kg; + if (recipe->mashs.at(i).step_infuse_amount > 0) { + temp = (b - a) / (recipe->mashs.at(i).step_infuse_amount * SpecificHeatWater); + } else { + temp = 99; + } + tuntemp += (temp - tuntemp) / 2; + recipe->mashs[i].step_infuse_temp = round(temp * 1000000.0) / 1000000.0; + } + qDebug() << " init infuse temp:" << recipe->mashs.at(i).step_infuse_temp; + } else { + // Calculate amount of infusion water. + recipe->mashs[i].step_infuse_amount = + infusionVol(infused, recipe->mashs_kg, recipe->mashs.at(i).step_infuse_temp, recipe->mashs.at(i).step_temp, lasttemp); + qDebug() << i << " vol:" << recipe->mashs.at(i).step_infuse_amount << "temp:" << recipe->mashs.at(i).step_infuse_temp; + } + infused += recipe->mashs.at(i).step_infuse_amount; + } else if (recipe->mashs.at(i).step_type == 1) { // Temperature + if (i > 0) + recipe->mashs[i].step_infuse_amount = 0; + recipe->mashs[i].step_infuse_temp = 0; + } else if (recipe->mashs.at(i).step_type == 2) { // Decoction + recipe->mashs[i].step_infuse_amount = decoctionVol(infused, recipe->mashs.at(i).step_temp, lasttemp); + recipe->mashs[i].step_infuse_temp = 99; + } + recipe->mashs[i].step_volume = infused; + qDebug() << i << " type:" << recipe->mashs.at(i).step_type << "volume:" << recipe->mashs.at(i).step_infuse_amount << "temp:" << recipe->mashs.at(i).step_infuse_temp; + lasttemp = recipe->mashs.at(i).step_temp; + recipe->mashs_time += recipe->mashs.at(i).step_time; + if (i > 0) + recipe->mashs_time += recipe->mashs.at(i).ramp_time; + recipe->mashs[i].step_wg_ratio = round((infused / recipe->mashs_kg) * 1000000.0) / 1000000.0; + } + } + + /* Show the calculated total mash time. */ + ui->mash_timeEdit->setText(QString("%1:%2").arg(recipe->mashs_time / 60).arg(recipe->mashs_time % 60, 2, 'f', 0, '0')); +} + + void EditRecipe::addMashRow_clicked() { Mashs newm; @@ -287,6 +377,7 @@ ui->mashsTable->setItem(recipe->mashs_row, 2, item); this->ignoreChanges = false; is_changed(); + emit refreshAll(); } @@ -300,6 +391,7 @@ ui->mashsTable->setItem(recipe->mashs_row, 3, item); this->ignoreChanges = false; is_changed(); + emit refreshAll(); } @@ -313,6 +405,7 @@ ui->mashsTable->setItem(recipe->mashs_row, 4, item); this->ignoreChanges = false; is_changed(); + emit refreshAll(); } @@ -326,6 +419,7 @@ ui->mashsTable->setItem(recipe->mashs_row, 5, item); this->ignoreChanges = false; is_changed(); + emit refreshAll(); } @@ -548,6 +642,7 @@ /* * Got the json data in the steps array, replace the recipe steps. */ + double infuse = recipe->mashs.at(0).step_infuse_amount; recipe->mashs.clear(); ui->mashsTable->clear(); if (newsteps.isArray()) { @@ -582,6 +677,8 @@ recipe->mashs.append(m); } } + if (recipe->mashs.at(0).step_type == 0) + recipe->mashs[0].step_infuse_amount = infuse; // Restore save initial infusion } } is_changed(); diff -r af1386a6ece7 -r ba25a566b100 ui/EditRecipe.ui --- a/ui/EditRecipe.ui Tue Apr 19 22:27:18 2022 +0200 +++ b/ui/EditRecipe.ui Wed Apr 20 12:19:36 2022 +0200 @@ -95,7 +95,7 @@ QTabWidget::Rounded - 5 + 0 Qt::ElideNone @@ -2384,6 +2384,35 @@ + + + + 570 + 40 + 131 + 20 + + + + Mash time: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 710 + 40 + 71 + 23 + + + + true + +