# HG changeset patch # User Michiel Broek # Date 1657632857 -7200 # Node ID 37b3c690b02c92d212784e2bcabbf36203a982aa # Parent f05aeee71a14809625ee6296d29fb7142ca8a35c Added calculation preboild pH in recipes. Added water hardness and residual alkalinity calculations in the water tab. diff -r f05aeee71a14 -r 37b3c690b02c src/EditProductTab8.cpp --- a/src/EditProductTab8.cpp Tue Jul 12 12:10:20 2022 +0200 +++ b/src/EditProductTab8.cpp Tue Jul 12 15:34:17 2022 +0200 @@ -160,6 +160,9 @@ qDebug() << "calcWater()"; + ui->w1_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium)); + ui->w1_raEdit->setValue(Utils::RA_ppm(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium)); + /* * If there is a dilute water source, mix the waters. */ @@ -172,6 +175,8 @@ sulfate = Utils::mix(product->w1_amount, product->w2_amount, product->w1_sulfate, product->w2_sulfate); total_alkalinity = Utils::mix(product->w1_amount, product->w2_amount, product->w1_total_alkalinity, product->w2_total_alkalinity); ph = -log10(((pow(10, -product->w1_ph) * product->w1_amount) + (pow(10, -product->w2_ph) * product->w2_amount)) / liters); + ui->w2_hardnessEdit->setValue(Utils::Hardness(product->w2_calcium, product->w2_magnesium)); + ui->w2_raEdit->setValue(Utils::RA_ppm(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium)); } else { liters = product->w1_amount; calcium = product->w1_calcium; @@ -201,6 +206,8 @@ ui->wg_clEdit->setValue(chloride); ui->wg_so4Edit->setValue(sulfate); ui->wg_phEdit->setValue(ph); + ui->wg_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium)); + ui->wg_raEdit->setValue(Utils::RA_ppm(total_alkalinity, calcium, magnesium)); bicarbonate = total_alkalinity * 1.22; /* Save mixed water ions for later */ @@ -375,6 +382,8 @@ ui->wb_naEdit->setValue(sodium); ui->wb_clEdit->setValue(chloride); ui->wb_so4Edit->setValue(sulfate); + ui->wb_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium)); + ui->wb_raEdit->setValue(Utils::RA_ppm(total_alkalinity, calcium, magnesium)); ui->wb_caEdit->setStyleSheet((calcium < 40 || calcium > 150) ? "background-color: red":"background-color: green"); ui->wb_mgEdit->setStyleSheet((magnesium < 5 || magnesium > 40) ? "background-color: red":"background-color: green"); @@ -485,7 +494,9 @@ product->sparge_acid_amount = Acid / 1000; ui->sp_acidvolEdit->setValue(Acid); - product->est_preboil_ph = -log10(((pow(10, -product->mash_ph) * product->wg_amount) + (pow(10, -product->sparge_ph) * product->brew_sparge_est)) / (product->wg_amount + product->brew_sparge_est)); + // Finally calculate the estimate preboil pH + product->est_preboil_ph = -log10(((pow(10, -product->mash_ph) * product->wg_amount) + (pow(10, -product->sparge_ph) * product->brew_sparge_est)) / + (product->wg_amount + product->brew_sparge_est)); ui->preboil_phEdit->setValue(product->est_preboil_ph); ui->brew_preboilphShow->setValue(product->est_preboil_ph); } @@ -717,6 +728,8 @@ ui->w1_clEdit->setValue(product->w1_chloride); ui->w1_so4Edit->setValue(product->w1_sulfate); ui->w1_phEdit->setValue(product->w1_ph); + ui->w1_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium)); + ui->w1_raEdit->setValue(Utils::RA_ppm(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium)); check_waters(); is_changed(); @@ -727,6 +740,7 @@ void EditProduct::w2_name_changed(int val) { QSqlQuery query; + double hardness, ra_ppm; qDebug() << "w2_name_changed" << val; @@ -741,6 +755,7 @@ product->w2_ph = 0; product->w1_amount += product->w2_amount; product->w2_amount = 0; + hardness = ra_ppm = 0; } else { query.prepare("SELECT * FROM inventory_waters ORDER BY record"); query.exec(); @@ -758,6 +773,8 @@ product->w2_chloride = query.value(6).toDouble(); product->w2_sulfate = query.value(5).toDouble(); product->w2_ph = query.value(9).toDouble(); + hardness = Utils::Hardness(product->w2_calcium, product->w2_magnesium); + ra_ppm = Utils::RA_ppm(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium); } ui->w1_volEdit->setValue(product->w1_amount); ui->w2_volEdit->setValue(product->w2_amount); @@ -769,6 +786,8 @@ ui->w2_clEdit->setValue(product->w2_chloride); ui->w2_so4Edit->setValue(product->w2_sulfate); ui->w2_phEdit->setValue(product->w2_ph); + ui->w2_hardnessEdit->setValue(hardness); + ui->w2_raEdit->setValue(ra_ppm); check_waters(); is_changed(); @@ -789,6 +808,8 @@ ui->wt_naEdit->setValue(0); ui->wt_clEdit->setValue(0); ui->wt_so4Edit->setValue(0); + ui->wt_hardnessEdit->setValue(0); + ui->wt_raEdit->setValue(0); } else { query.prepare("SELECT * FROM profile_water ORDER BY name"); query.exec(); @@ -796,13 +817,15 @@ for (int i = 0; i < (val - 1); i++) { query.next(); } - ui->wt_caEdit->setValue(query.value(2).toDouble()); - ui->wt_mgEdit->setValue(query.value(7).toDouble()); - ui->wt_hco3Edit->setValue(query.value(3).toDouble()); - ui->wt_caco3Edit->setValue(query.value(10).toDouble()); - ui->wt_naEdit->setValue(query.value(6).toDouble()); - ui->wt_clEdit->setValue(query.value(5).toDouble()); - ui->wt_so4Edit->setValue(query.value(4).toDouble()); + ui->wt_caEdit->setValue(query.value("calcium").toDouble()); + ui->wt_mgEdit->setValue(query.value("magnesium").toDouble()); + ui->wt_hco3Edit->setValue(query.value("bicarbonate").toDouble()); + ui->wt_caco3Edit->setValue(query.value("total_alkalinity").toDouble()); + ui->wt_naEdit->setValue(query.value("sodium").toDouble()); + ui->wt_clEdit->setValue(query.value("chloride").toDouble()); + ui->wt_so4Edit->setValue(query.value("sulfate").toDouble()); + ui->wt_hardnessEdit->setValue(Utils::Hardness(query.value("calcium").toDouble(), query.value("magnesium").toDouble())); + ui->wt_raEdit->setValue(Utils::RA_ppm(query.value("total_alkalinity").toDouble(), query.value("calcium").toDouble(), query.value("magnesium").toDouble())); } calcWater(); } diff -r f05aeee71a14 -r 37b3c690b02c src/EditRecipeTab7.cpp --- a/src/EditRecipeTab7.cpp Tue Jul 12 12:10:20 2022 +0200 +++ b/src/EditRecipeTab7.cpp Tue Jul 12 15:34:17 2022 +0200 @@ -160,6 +160,9 @@ qDebug() << "calcWater()"; + ui->w1_hardnessEdit->setValue(Utils::Hardness(recipe->w1_calcium, recipe->w1_magnesium)); + ui->w1_raEdit->setValue(Utils::RA_ppm(recipe->w1_total_alkalinity, recipe->w1_calcium, recipe->w1_magnesium)); + /* * If there is a dilute water source, mix the waters. */ @@ -172,6 +175,8 @@ sulfate = Utils::mix(recipe->w1_amount, recipe->w2_amount, recipe->w1_sulfate, recipe->w2_sulfate); total_alkalinity = Utils::mix(recipe->w1_amount, recipe->w2_amount, recipe->w1_total_alkalinity, recipe->w2_total_alkalinity); ph = -log10(((pow(10, -recipe->w1_ph) * recipe->w1_amount) + (pow(10, -recipe->w2_ph) * recipe->w2_amount)) / liters); + ui->w2_hardnessEdit->setValue(Utils::Hardness(recipe->w2_calcium, recipe->w2_magnesium)); + ui->w2_raEdit->setValue(Utils::RA_ppm(recipe->w2_total_alkalinity, recipe->w2_calcium, recipe->w2_magnesium)); } else { liters = recipe->w1_amount; calcium = recipe->w1_calcium; @@ -201,6 +206,8 @@ ui->wg_clEdit->setValue(chloride); ui->wg_so4Edit->setValue(sulfate); ui->wg_phEdit->setValue(ph); + ui->wg_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium)); + ui->wg_raEdit->setValue(Utils::RA_ppm(total_alkalinity, calcium, magnesium)); bicarbonate = total_alkalinity * 1.22; /* Save mixed water ions for later */ @@ -375,6 +382,8 @@ ui->wb_naEdit->setValue(sodium); ui->wb_clEdit->setValue(chloride); ui->wb_so4Edit->setValue(sulfate); + ui->wb_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium)); + ui->wb_raEdit->setValue(Utils::RA_ppm(total_alkalinity, calcium, magnesium)); ui->wb_caEdit->setStyleSheet((calcium < 40 || calcium > 150) ? "background-color: red":"background-color: green"); ui->wb_mgEdit->setStyleSheet((magnesium < 5 || magnesium > 40) ? "background-color: red":"background-color: green"); @@ -484,6 +493,11 @@ Acid = round(Acid * 100.0) / 100.0; recipe->sparge_acid_amount = Acid / 1000; ui->sp_acidvolEdit->setValue(Acid); + + // Finally calculate the estimate preboil pH + recipe->preboil_ph = -log10(((pow(10, -recipe->mash_ph) * recipe->wg_amount) + (pow(10, -recipe->sparge_ph) * recipe->sparge_volume)) / + (recipe->wg_amount + recipe->sparge_volume)); + ui->preboil_phEdit->setValue(recipe->preboil_ph); } @@ -660,6 +674,8 @@ ui->w1_clEdit->setValue(recipe->w1_chloride); ui->w1_so4Edit->setValue(recipe->w1_sulfate); ui->w1_phEdit->setValue(recipe->w1_ph); + ui->w1_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium)); + ui->w1_raEdit->setValue(Utils::RA_ppm(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium)); is_changed(); calcWater(); @@ -669,6 +685,7 @@ void EditRecipe::w2_name_changed(int val) { QSqlQuery query; + double hardness, ra_ppm; qDebug() << "w2_name_changed" << val; @@ -683,6 +700,7 @@ recipe->w2_ph = 0; recipe->w1_amount += recipe->w2_amount; recipe->w2_amount = 0; + hardness = ra_ppm = 0; } else { query.prepare("SELECT * FROM inventory_waters ORDER BY record"); query.exec(); @@ -700,6 +718,8 @@ recipe->w2_chloride = query.value(6).toDouble(); recipe->w2_sulfate = query.value(5).toDouble(); recipe->w2_ph = query.value(9).toDouble(); + hardness = Utils::Hardness(product->w2_calcium, product->w2_magnesium); + ra_ppm = Utils::RA_ppm(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium); } ui->w1_volEdit->setValue(recipe->w1_amount); ui->w2_volEdit->setValue(recipe->w2_amount); @@ -711,6 +731,8 @@ ui->w2_clEdit->setValue(recipe->w2_chloride); ui->w2_so4Edit->setValue(recipe->w2_sulfate); ui->w2_phEdit->setValue(recipe->w2_ph); + ui->w2_hardnessEdit->setValue(hardness); + ui->w2_raEdit->setValue(ra_ppm); is_changed(); calcWater(); @@ -730,6 +752,8 @@ ui->wt_naEdit->setValue(0); ui->wt_clEdit->setValue(0); ui->wt_so4Edit->setValue(0); + ui->wt_hardnessEdit->setValue(0); + ui->wt_raEdit->setValue(0); } else { query.prepare("SELECT * FROM profile_water ORDER BY name"); query.exec(); @@ -737,13 +761,15 @@ for (int i = 0; i < (val - 1); i++) { query.next(); } - ui->wt_caEdit->setValue(query.value(2).toDouble()); - ui->wt_mgEdit->setValue(query.value(7).toDouble()); - ui->wt_hco3Edit->setValue(query.value(3).toDouble()); - ui->wt_caco3Edit->setValue(query.value(10).toDouble()); - ui->wt_naEdit->setValue(query.value(6).toDouble()); - ui->wt_clEdit->setValue(query.value(5).toDouble()); - ui->wt_so4Edit->setValue(query.value(4).toDouble()); + ui->wt_caEdit->setValue(query.value("calcium").toDouble()); + ui->wt_mgEdit->setValue(query.value("magnesium").toDouble()); + ui->wt_hco3Edit->setValue(query.value("bicarbonate").toDouble()); + ui->wt_caco3Edit->setValue(query.value("total_alkalinity").toDouble()); + ui->wt_naEdit->setValue(query.value("sodium").toDouble()); + ui->wt_clEdit->setValue(query.value("chloride").toDouble()); + ui->wt_so4Edit->setValue(query.value("sulfate").toDouble()); + ui->wt_hardnessEdit->setValue(Utils::Hardness(query.value("calcium").toDouble(), query.value("magnesium").toDouble())); + ui->wt_raEdit->setValue(Utils::RA_ppm(query.value("total_alkalinity").toDouble(), query.value("calcium").toDouble(), query.value("magnesium").toDouble())); } calcWater(); } diff -r f05aeee71a14 -r 37b3c690b02c src/Utils.cpp --- a/src/Utils.cpp Tue Jul 12 12:10:20 2022 +0200 +++ b/src/Utils.cpp Tue Jul 12 15:34:17 2022 +0200 @@ -608,6 +608,19 @@ } +double Utils::Hardness(double calcium, double magnesium) +{ + return ((calcium / 20) + (magnesium / 12.15)) * 50; +} + + +double Utils::RA_ppm(double total_alkalinity, double calcium, double magnesium) +{ + double alkalinity = total_alkalinity * (1 + (2 * pow(10, -2.33))); + return (alkalinity - ((calcium * 0.7143) + (magnesium * 0.5879))); +} + + double Utils::ResidualAlkalinity(double total_alkalinity, double calcium, double magnesium) { return total_alkalinity - (calcium / 1.4 + magnesium / 1.7); diff -r f05aeee71a14 -r 37b3c690b02c src/Utils.h --- a/src/Utils.h Tue Jul 12 12:10:20 2022 +0200 +++ b/src/Utils.h Tue Jul 12 15:34:17 2022 +0200 @@ -133,6 +133,13 @@ double mix(double v1, double v2, double c1, double c2); /** + * @brief Calculate water hardness + */ + double Hardness(double calcium, double magnesium); + + double RA_ppm(double total_alkalinity, double calcium, double magnesium); + + /** * @brief Return mg/l as CaCO3 */ double ResidualAlkalinity(double total_alkalinity, double calcium, double magnesium); diff -r f05aeee71a14 -r 37b3c690b02c src/global.h --- a/src/global.h Tue Jul 12 12:10:20 2022 +0200 +++ b/src/global.h Tue Jul 12 15:34:17 2022 +0200 @@ -397,6 +397,7 @@ double mashs_kg; ///< Kg fermentables in the mash. int mashs_time; ///< Total mash time. double preboil_sg; + double preboil_ph; }; diff -r f05aeee71a14 -r 37b3c690b02c ui/EditProduct.ui --- a/ui/EditProduct.ui Tue Jul 12 12:10:20 2022 +0200 +++ b/ui/EditProduct.ui Tue Jul 12 15:34:17 2022 +0200 @@ -3797,9 +3797,9 @@ - 50 + 10 0 - 1021 + 1101 221 @@ -5146,15 +5146,139 @@ - 940 + 1020 140 71 24 - - The ideal Sulfate amount should be between 50 and 400. -Together with Chloride it must be below 500. + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 1020 + 20 + 71 + 21 + + + + RA + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 1020 + 50 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 1020 + 80 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 1020 + 110 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 940 + 80 + 71 + 24 + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -5172,7 +5296,57 @@ 1000.000000000000000 - + + + + 940 + 110 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 + + + + + + 940 + 50 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 + + + 940 @@ -5182,10 +5356,88 @@ - RA - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Hardness + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 940 + 140 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 + + + + + + 1020 + 180 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 940 + 180 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 @@ -6238,9 +6490,6 @@ 24 - - Mash pH should be between 5.2 and 5.6. Use 5.2 for light and 5.5 for dark beers. - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter diff -r f05aeee71a14 -r 37b3c690b02c ui/EditRecipe.ui --- a/ui/EditRecipe.ui Tue Jul 12 12:10:20 2022 +0200 +++ b/ui/EditRecipe.ui Tue Jul 12 15:34:17 2022 +0200 @@ -2428,9 +2428,9 @@ - 170 + 10 0 - 941 + 1101 221 @@ -3774,6 +3774,303 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + 1020 + 180 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 940 + 110 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 + + + + + + 1020 + 80 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 940 + 180 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 + + + + + + 940 + 80 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 + + + + + + 1020 + 110 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 940 + 50 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 + + + + + + 1020 + 50 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 1020 + 20 + 71 + 21 + + + + RA + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 1020 + 140 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + 940 + 140 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 1 + + + 1000.000000000000000 + + + + + + 940 + 20 + 71 + 21 + + + + Hardness + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + @@ -4793,6 +5090,47 @@ + + + + 290 + 430 + 181 + 20 + + + + Estimate pre boil pH: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 480 + 430 + 71 + 24 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + QAbstractSpinBox::NoButtons + + + 2 + + + 1000.000000000000000 + +