Sat, 02 Jul 2022 15:45:01 +0200
Version 0.2.14
/** * EditRecipe.cpp is part of bmsapp. * * tab 6, water. * * bmsapp is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * bmsapp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ void EditRecipe::refreshWaters() { // calc_acid ui->mw_phEdit->setValue(recipe->mash_ph); // mash_name //ui->mw_acidpercEdit->setValue(recipe-> } /* * Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) */ double EditRecipe::ZAlkalinity(double pHZ) { double C43 = Utils::Charge(4.3); double Cw = Utils::Charge(recipe->wg_ph); double Cz = Utils::Charge(pHZ); double DeltaCNaught = -C43 + Cw; double CT = recipe->wg_total_alkalinity / 50 / DeltaCNaught; double DeltaCZ = -Cz + Cw; return CT * DeltaCZ; } /* * Z Residual alkalinity is the amount of acid (in mEq/l) needed * to bring the water in the mash to the target pH (Z pH). */ double EditRecipe::ZRA(double pHZ) { double Calc = recipe->wg_calcium / (MMCa / 2); double Magn = recipe->wg_magnesium / (MMMg / 2); double Z = ZAlkalinity(pHZ); return Z - (Calc / 3.5 + Magn / 7); } double EditRecipe::BufferCapacity(Fermentables F) { double C1 = 0; if ((F.di_ph != 5.7) && ((F.acid_to_ph_57 < - 0.1) || (F.acid_to_ph_57 > 0.1))) { C1 = F.acid_to_ph_57 / (F.di_ph - 5.7); } else { /* * If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid. */ switch (F.graintype) { case 0: // Base, Special, Kilned case 3: case 5: C1 = 0.014 * F.color - 34.192; break; case 2: C1 = -0.0597 * F.color - 32.457; // Crystal break; case 1: C1 = 0.0107 * F.color - 54.768; // Roast break; case 4: C1 = -149; // Sour malt break; } } return C1; } double EditRecipe::AcidRequired(double ZpH, Fermentables F) { double C1 = BufferCapacity(F); double x = F.di_ph; return C1 * (ZpH - x); } double EditRecipe::ProtonDeficit(double pHZ) { double C1, x; int i, error_count = 0; double Result = ZRA(pHZ) * recipe->wg_amount; Fermentables F; /* * proton deficit for the grist */ if (recipe->fermentables.size()) { for (i = 0; i < recipe->fermentables.size(); i++) { F = recipe->fermentables.at(i); if (F.added == 0 && F.graintype != 6) { // Added == Mash && graintype != No Malt x = AcidRequired(pHZ, F) * F.amount; Result += x; } } } else { error_count++; if (error_count < 5) qDebug() << " ProtonDeficit" << pHZ << "invalid grist, return" << Result; } return Result; } double EditRecipe::MashpH() { int n = 0; double pH = 5.4; double deltapH = 0.001; double deltapd = 0.1; double pd = ProtonDeficit(pH); while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) { n++; if (pd < -deltapd) pH -= deltapH; else if (pd > deltapd) pH += deltapH; pd = ProtonDeficit(pH); } pH = round(pH * 1000000) / 1000000.0; qDebug() << " MashpH() n:" << n << "pH:" << pH; return pH; } void EditRecipe::calcWater() { double liters = 0; double calcium = 0; double magnesium = 0; double sodium = 0; double total_alkalinity = 0; double bicarbonate = 0; double chloride = 0; double sulfate = 0; double ph = 0; double TpH = 0; double frac, RA; double protonDeficit = 0; double Acid = 0, Acidmg = 0; int AT; qDebug() << "calcWater()"; /* * If there is a dilute water source, mix the waters. */ if (recipe->w2_name != "") { liters = recipe->w1_amount + recipe->w2_amount; calcium = Utils::mix(recipe->w1_amount, recipe->w2_amount, recipe->w1_calcium, recipe->w2_calcium); magnesium = Utils::mix(recipe->w1_amount, recipe->w2_amount, recipe->w1_magnesium, recipe->w2_magnesium); sodium = Utils::mix(recipe->w1_amount, recipe->w2_amount, recipe->w1_sodium, recipe->w2_sodium); chloride = Utils::mix(recipe->w1_amount, recipe->w2_amount, recipe->w1_chloride, recipe->w2_chloride); 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); } else { liters = recipe->w1_amount; calcium = recipe->w1_calcium; magnesium = recipe->w1_magnesium; sodium = recipe->w1_sodium; chloride = recipe->w1_chloride; sulfate = recipe->w1_sulfate; total_alkalinity = recipe->w1_total_alkalinity; ph = recipe->w1_ph; } recipe->wg_amount = liters; recipe->wg_calcium = round(calcium * 10.0) / 10.0; recipe->wg_magnesium = round(magnesium * 10.0) / 10.0; recipe->wg_sodium = round(sodium * 10.0) / 10.0; recipe->wg_chloride = round(chloride * 10.0) / 10.0; recipe->wg_sulfate = round(sulfate * 10.0) / 10.0; recipe->wg_total_alkalinity = round(total_alkalinity * 10.0) / 10.0; recipe->wg_ph = ph; ui->wg_volEdit->setValue(liters); ui->wg_caEdit->setValue(calcium); ui->wg_mgEdit->setValue(magnesium); ui->wg_hco3Edit->setValue(total_alkalinity * 1.22); ui->wg_caco3Edit->setValue(total_alkalinity); ui->wg_naEdit->setValue(sodium); ui->wg_clEdit->setValue(chloride); ui->wg_so4Edit->setValue(sulfate); ui->wg_phEdit->setValue(ph); bicarbonate = total_alkalinity * 1.22; /* Save mixed water ions for later */ double wg_calcium = calcium; double wg_sodium = sodium; double wg_total_alkalinity = total_alkalinity; double wg_chloride = chloride; double wg_sulfate = sulfate; double wg_bicarbonate = bicarbonate; double mash_ph = MashpH(); qDebug() << " Distilled water mash pH:" << mash_ph; /* Calculate Salt additions */ if (liters > 0) { calcium += ( ui->bs_cacl2Edit->value() * MMCa / MMCaCl2 * 1000 + ui->bs_caso4Edit->value() * MMCa / MMCaSO4 * 1000 + ui->bs_caco3Edit->value() * MMCa / MMCaCO3 * 1000) / liters; magnesium += (ui->bs_mgso4Edit->value() * MMMg / MMMgSO4 * 1000 + ui->bs_mgcl2Edit->value() * MMMg / MMMgCl2 * 1000) / liters; sodium += (ui->bs_naclEdit->value() * MMNa / MMNaCl * 1000 + ui->bs_nahco3Edit->value() * MMNa / MMNaHCO3 * 1000) / liters; sulfate += (ui->bs_caso4Edit->value() * MMSO4 / MMCaSO4 * 1000 + ui->bs_mgso4Edit->value() * MMSO4 / MMMgSO4 * 1000) / liters; chloride += (2 * ui->bs_cacl2Edit->value() * MMCl / MMCaCl2 * 1000 + ui->bs_naclEdit->value() * MMCl / MMNaCl * 1000 + ui->bs_mgcl2Edit->value() * MMCl / MMMgCl2 * 1000) / liters; bicarbonate += (ui->bs_nahco3Edit->value() * MMHCO3 / MMNaHCO3 * 1000 + ui->bs_caco3Edit->value() / 3 * MMHCO3 / MMCaCO3 * 1000) / liters; } const QSignalBlocker blocker1(ui->mw_acidPick); const QSignalBlocker blocker2(ui->mw_acidpercEdit); const QSignalBlocker blocker3(ui->mw_acidvolEdit); const QSignalBlocker blocker4(ui->wb_phEdit); const QSignalBlocker blocker5(ui->mw_phEdit); if (recipe->wa_acid_name < 0 || recipe->wa_acid_name >= my_acids.size()) { recipe->wa_acid_name = 0; recipe->wa_acid_perc = my_acids.at(0).AcidPrc; ui->mw_acidPick->setCurrentIndex(0); ui->mw_acidpercEdit->setValue(my_acids.at(0).AcidPrc); } AT = recipe->wa_acid_name; /* * Note that the next calculations do not correct the pH change by the added salts. * This pH change is at most 0.1 pH and is a minor difference in Acid amount. */ if (recipe->calc_acid) { /* * Auto calculate the needed acid. */ TpH = recipe->mash_ph; protonDeficit = ProtonDeficit(TpH); qDebug() << " calc_acid tgt:" << TpH << "protonDeficit:" << protonDeficit; if (protonDeficit > 0) { frac = Utils::CalcFrac(TpH, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3); Acid = protonDeficit / frac; Acid *= my_acids[AT].MolWt; // mg. Acidmg = Acid; Acid = Acid / my_acids[AT].AcidSG; Acid = round((Acid / (recipe->wa_acid_perc / 100.0)) * 100.0) / 100.0; qDebug() << " Mash auto Acid final ml:" << Acid; QString w = my_acids[AT].name_en + ' ' + my_acids[AT].name_nl; brewing_salt_sub(w, Acid); ui->mw_acidvolEdit->setValue(Acid); bicarbonate = bicarbonate - protonDeficit * frac / liters; total_alkalinity = bicarbonate * 50 / 61; } ph = TpH; ui->wb_phEdit->setValue(ph); recipe->mash_ph = ph; } else { // Manual /* * Manual adjust acid, calculate resulting pH. */ double pHa = ph; // Mixed water pH. // Then calculate the new pH with added acids and malts qDebug() << " Mash pH:" << pHa; Acid = my_acids[AT].AcidSG * (recipe->wa_acid_perc / 100.0); // ml Acid *= ui->mw_acidvolEdit->value(); Acid /= my_acids[AT].MolWt; // mg; Acidmg = Acid; //find the pH where the protondeficit = protondeficit by the acid frac = Utils::CalcFrac(pHa, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3); protonDeficit = Acid * frac; //qDebug() << " protonDeficit Acid:" << protonDeficit << "frac:" << frac << "pH:" << pHa; double deltapH = 0.001; double deltapd = 0.1; double pd = round(ProtonDeficit(pHa) * 1000000.0) / 1000000.0; int n = 0; while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 4000)) { n++; if (pd < (protonDeficit - deltapd)) pHa -= deltapH; else if (pd > (protonDeficit + deltapd)) pHa += deltapH; frac = Utils::CalcFrac(pHa, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3); protonDeficit = Acid * frac; pd = ProtonDeficit(pHa); } //qDebug() << " n:" << n << "pd:" << pd << "protonDeficit:" << protonDeficit << "frac:" << frac << "pHa:" << pHa; bicarbonate = wg_bicarbonate - protonDeficit * frac / liters; total_alkalinity = bicarbonate * 50 / 61; ph = pHa; ui->wb_phEdit->setValue(ph); ui->mw_phEdit->setValue(ph); recipe->mash_ph = ph; } if ((AT == 3) && (liters > 0)) { // Sulfuctic / Zwavelzuur RA = ui->bs_caso4Edit->value() * MMSO4 / MMCaSO4 + ui->bs_mgso4Edit->value() * MMSO4 / MMMgSO4 + Acidmg / 1000 * MMSO4 / (MMSO4 + 2); RA = 1000 * RA / liters; sulfate = wg_sulfate + RA; // Not add to sulfate?? } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur RA = ui->bs_cacl2Edit->value() * MMCl / MMCaCl2 + ui->bs_naclEdit->value() * MMCl / MMNaCl + Acidmg / 1000 * MMCl / (MMCl + 1); RA = 1000 * RA / liters; chloride = wg_chloride + RA; } double BUGU = GetBUGU(); ui->buguEdit->setValue(BUGU); if (BUGU < 0.32) ui->buguResult->setText(tr("Very malty and sweet")); else if (BUGU < 0.43) ui->buguResult->setText(tr("Malty, sweet")); else if (BUGU < 0.52) ui->buguResult->setText(tr("Balanced")); else if (BUGU < 0.63) ui->buguResult->setText(tr("Hoppy, bitter")); else ui->buguResult->setText(tr("Very hoppy, very bitter")); double OptSO4Clratio = GetOptSO4Clratio(); ui->so4clEdit->setValue(OptSO4Clratio); ui->cur_so4clResult->setRange(0.7 * OptSO4Clratio, 1.3 * OptSO4Clratio); if (OptSO4Clratio < 0.4) ui->so4clResult->setText(tr("Too malty")); else if (OptSO4Clratio < 0.6) ui->so4clResult->setText(tr("Very malty")); else if (OptSO4Clratio < 0.8) ui->so4clResult->setText(tr("Malty")); else if (OptSO4Clratio < 1.5) ui->so4clResult->setText(tr("Balanced")); else if (OptSO4Clratio < 2.0) ui->so4clResult->setText(tr("Little bitter")); else if (OptSO4Clratio < 4.0) ui->so4clResult->setText(tr("Bitter")); else if (OptSO4Clratio < 9.0) ui->so4clResult->setText(tr("Very bitter")); else ui->so4clResult->setText(tr("Too bitter")); if (chloride > 0) RA = sulfate / chloride; else RA = 10; ui->cur_so4clEdit->setValue(RA); ui->cur_so4clResult->setValue(RA); recipe->wb_calcium = calcium; recipe->wb_magnesium = magnesium; recipe->wb_total_alkalinity = total_alkalinity; recipe->wb_sodium = sodium; recipe->wb_chloride = chloride; recipe->wb_sulfate = sulfate; recipe->wb_ph = ph; ui->wb_caEdit->setValue(calcium); ui->wb_mgEdit->setValue(magnesium); ui->wb_hco3Edit->setValue(bicarbonate); ui->wb_caco3Edit->setValue(total_alkalinity); ui->wb_naEdit->setValue(sodium); ui->wb_clEdit->setValue(chloride); ui->wb_so4Edit->setValue(sulfate); 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"); ui->wb_naEdit->setStyleSheet((sodium > 150) ? "background-color: red":"background-color: green"); /* * Both chloride and sulfate should be above 50 according to * John Palmer. So the Cl/SO4 ratio calculation will work. */ ui->wb_clEdit->setStyleSheet((chloride <= 50 || chloride > 150) ? "background-color: red":"background-color: green"); ui->wb_so4Edit->setStyleSheet((sulfate <= 50 || sulfate > 400) ? "background-color: red":"background-color: green"); /* * (cloride + sulfate) > 500 is too high */ if ((chloride + sulfate) > 500) { ui->wb_clEdit->setStyleSheet("background-color: red"); ui->wb_so4Edit->setStyleSheet("background-color: red"); } ui->wb_phEdit->setStyleSheet((ph < 5.2 || ph > 5.6) ? "background-color: red":"background-color: green"); ui->wb_hco3Edit->setStyleSheet((bicarbonate > 250) ? "background-color: red":"background-color: green"); ui->wb_caco3Edit->setStyleSheet((bicarbonate > 250) ? "background-color: red":"background-color: green"); calcSparge(); } /* * Based on the work of ajDeLange. */ void EditRecipe::calcSparge() { double TargetpH = recipe->sparge_ph; double Source_pH = recipe->w1_ph; double Source_alkalinity = recipe->w1_total_alkalinity; qDebug() << "calcSparge()"; const QSignalBlocker blocker1(ui->sp_sourceEdit); // Select watersource or fallback to the first source. if (recipe->sparge_source == 1) { // Source 2 if (recipe->w2_ph > 0.0 && recipe->w2_amount > 0) { Source_pH = recipe->w2_ph; Source_alkalinity = recipe->w2_total_alkalinity; } else { recipe->sparge_source = 0; // Source 1 ui->sp_sourceEdit->setCurrentIndex(0); } } else if (recipe->sparge_source == 2) { // Mixed if (recipe->w2_ph > 0.0 && recipe->w2_amount > 0) { Source_pH = recipe->wg_ph; Source_alkalinity = recipe->wg_total_alkalinity; } else { recipe->sparge_source = 0; // Source 1 ui->sp_sourceEdit->setCurrentIndex(0); } } // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH double r1 = pow(10, Source_pH - 6.35); double r2 = pow(10, Source_pH - 10.33); double d = 1 + r1 + r1 * r2; double f1 = 1 / d; double f3 = r1 * r2 / d; // Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) double r143 = pow(10, 4.3 - 6.35); double r243 = pow(10, 4.3 - 10.33); double d43 = 1 + r143 + r143 * r243; double f143 = 1 / d43; double f343 = r143 * r243 / d43; // Step 4. Solve //double Ct = (Source_alkalinity - 1000 * (pow(10, -4.3) - pow(10, -Source_pH))) / ((f143 - f1) + (f3 - f343)); double Ct = Source_alkalinity / 50 / ((f143 - f1) + (f3 - f343)); // Step 5. Compute mole fractions at desired pH double r1g = pow(10, TargetpH - 6.35); double r2g = pow(10, TargetpH - 10.33); double dg = 1 + r1g + r1g * r2g; double f1g = 1 / dg; double f3g = r1g * r2g / dg; // Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L) double Acid = Ct * ((f1g - f1) + (f3 - f3g)) + pow(10, -TargetpH) - pow(10, -Source_pH); //mEq/l Acid += 0.01; // Add acid that would be required for distilled water. //Step 8. Get the acid data. int AT = recipe->sparge_acid_type; if (AT < 0 || AT >= my_acids.size()) { AT = 0; recipe->sparge_acid_type = 0; ui->sp_acidtypeEdit->setCurrentIndex(0); recipe->sparge_acid_perc = my_acids[0].AcidPrc; ui->sp_acidpercEdit->setValue(recipe->sparge_acid_perc); } double fract = Utils::CalcFrac(TargetpH, my_acids[AT].pK1, my_acids[AT].pK2, my_acids[AT].pK3); // Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. Acid /= fract; // Step 10. Multiply by molecular weight of the acid Acid *= my_acids[AT].MolWt; //mg // Step 11. Divide by Specific Gravity and Percentage to get the final ml. Acid = Acid / my_acids[AT].AcidSG / (recipe->sparge_acid_perc / 100); //ml Acid *= recipe->sparge_volume; //ml acid total Acid = round(Acid * 100.0) / 100.0; recipe->sparge_acid_amount = Acid / 1000; ui->sp_acidvolEdit->setValue(Acid); } void EditRecipe::sp_source_changed(int val) { recipe->sparge_source = val; calcSparge(); is_changed(); } void EditRecipe::sp_type_changed(int val) { recipe->sparge_acid_type = val; recipe->sparge_acid_perc = my_acids[val].AcidPrc; ui->sp_acidpercEdit->setValue(recipe->sparge_acid_perc); calcSparge(); is_changed(); } void EditRecipe::sp_ph_changed(double val) { recipe->sparge_ph = val; calcSparge(); is_changed(); } double EditRecipe::GetBUGU() { double gu = (recipe->est_og - 1) * 1000; if (gu > 0) return recipe->est_ibu / gu; return 0.5; } double EditRecipe::GetOptSO4Clratio() { if (ui->wt_so4Edit->value() > 0 && ui->wt_clEdit->value()) { /* If target water is selected .. */ return (ui->wt_so4Edit->value() / ui->wt_clEdit->value()); } double BUGU = GetBUGU(); return (-1.2 * BUGU + 1.4); } void EditRecipe::mw_calc_acid_clicked() { recipe->calc_acid = ! recipe->calc_acid; ui->mw_autoEdit->setChecked(recipe->calc_acid); ui->mw_phEdit->setReadOnly(! recipe->calc_acid); ui->mw_phEdit->setButtonSymbols(recipe->calc_acid ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons); ui->mw_acidvolEdit->setReadOnly(recipe->calc_acid); ui->mw_acidvolEdit->setButtonSymbols(recipe->calc_acid ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows); is_changed(); calcWater(); } void EditRecipe::mw_ph_changed(double val) { if (! recipe->calc_acid) return; if (recipe->mash_ph != val) { qDebug() << "mw_ph_changed" << val << recipe->mash_ph; recipe->mash_ph = val; is_changed(); calcWater(); } } void EditRecipe::mw_acid_changed(double val) { if (recipe->calc_acid) return; qDebug() << "on_mw_acid_changed" << val; QString w = my_acids[recipe->wa_acid_name].name_en + ' ' + my_acids[recipe->wa_acid_name].name_nl; set_brewing_salt(w, val); } void EditRecipe::mw_type_changed(int val) { if (val == recipe->wa_acid_name) return; qDebug() << "on_mw_type_changed" << val << "old" << recipe->wa_acid_name; /* * First remove current acid. */ QString w = my_acids[recipe->wa_acid_name].name_en + ' ' + my_acids[recipe->wa_acid_name].name_nl; brewing_salt_sub(w, 0); recipe->wa_acid_name = val; w = my_acids[recipe->wa_acid_name].name_en + ' ' + my_acids[recipe->wa_acid_name].name_nl; recipe->wa_acid_perc = my_acids.at(val).AcidPrc; ui->mw_acidpercEdit->setValue(my_acids.at(val).AcidPrc); brewing_salt_sub(w, ui->mw_acidvolEdit->value()); // For now, set old amount. is_changed(); calcWater(); } void EditRecipe::w2_volume_changed(double val) { qDebug() << "w2_vol_changed" << val; if (recipe->w2_total_alkalinity && recipe->w2_sulfate) { /* * Seems a valid water, but don't go over the total. */ if (val < (recipe->w1_amount + recipe->w2_amount)) { recipe->w1_amount -= val - recipe->w2_amount; recipe->w2_amount = val; ui->w1_volEdit->setValue(recipe->w1_amount); } } else { /* * Invalid water, block changes. */ recipe->w2_amount = 0; } ui->w2_volEdit->setValue(recipe->w2_amount); calcWater(); is_changed(); } void EditRecipe::w1_name_changed(int val) { QSqlQuery query; qDebug() << "w1_name_changed" << val; const QSignalBlocker blocker1(ui->w1_nameEdit); if (val == 0) { /* * If no water is selected, take the default water. */ val = my_default_water; ui->w1_nameEdit->setCurrentIndex(val); } query.prepare("SELECT * FROM inventory_waters ORDER BY record"); query.exec(); query.first(); for (int i = 0; i < (val - 1); i++) { query.next(); } qDebug() << "set water" << query.value(1).toString(); recipe->w1_name = query.value(1).toString(); recipe->w1_calcium = query.value(3).toDouble(); recipe->w1_magnesium = query.value(8).toDouble(); recipe->w1_total_alkalinity = query.value(11).toDouble(); recipe->w1_sodium = query.value(7).toDouble(); recipe->w1_chloride = query.value(6).toDouble(); recipe->w1_sulfate = query.value(5).toDouble(); recipe->w1_ph = query.value(9).toDouble(); ui->w1_caEdit->setValue(recipe->w1_calcium); ui->w1_mgEdit->setValue(recipe->w1_magnesium); ui->w1_hco3Edit->setValue(recipe->w1_total_alkalinity * 1.22); ui->w1_caco3Edit->setValue(recipe->w1_total_alkalinity); ui->w1_naEdit->setValue(recipe->w1_sodium); ui->w1_clEdit->setValue(recipe->w1_chloride); ui->w1_so4Edit->setValue(recipe->w1_sulfate); ui->w1_phEdit->setValue(recipe->w1_ph); is_changed(); calcWater(); } void EditRecipe::w2_name_changed(int val) { QSqlQuery query; qDebug() << "w2_name_changed" << val; if (val == 0) { // Clear water 2. recipe->w2_name = ""; recipe->w2_calcium = 0; recipe->w2_magnesium = 0; recipe->w2_total_alkalinity = 0; recipe->w2_sodium = 0; recipe->w2_chloride = 0; recipe->w2_sulfate = 0; recipe->w2_ph = 0; recipe->w1_amount += recipe->w2_amount; recipe->w2_amount = 0; } else { query.prepare("SELECT * FROM inventory_waters ORDER BY record"); query.exec(); query.first(); for (int i = 0; i < (val - 1); i++) { query.next(); } qDebug() << "set water" << query.value(1).toString(); recipe->w2_name = query.value(1).toString(); recipe->w2_calcium = query.value(3).toDouble(); recipe->w2_magnesium = query.value(8).toDouble(); recipe->w2_total_alkalinity = query.value(11).toDouble(); recipe->w2_sodium = query.value(7).toDouble(); recipe->w2_chloride = query.value(6).toDouble(); recipe->w2_sulfate = query.value(5).toDouble(); recipe->w2_ph = query.value(9).toDouble(); } ui->w1_volEdit->setValue(recipe->w1_amount); ui->w2_volEdit->setValue(recipe->w2_amount); ui->w2_caEdit->setValue(recipe->w2_calcium); ui->w2_mgEdit->setValue(recipe->w2_magnesium); ui->w2_hco3Edit->setValue(recipe->w2_total_alkalinity * 1.22); ui->w2_caco3Edit->setValue(recipe->w2_total_alkalinity); ui->w2_naEdit->setValue(recipe->w2_sodium); ui->w2_clEdit->setValue(recipe->w2_chloride); ui->w2_so4Edit->setValue(recipe->w2_sulfate); ui->w2_phEdit->setValue(recipe->w2_ph); is_changed(); calcWater(); } void EditRecipe::wt_target_changed(int val) { QSqlQuery query; if (val == 0) { /* Clear values */ ui->wt_caEdit->setValue(0); ui->wt_mgEdit->setValue(0); ui->wt_hco3Edit->setValue(0); ui->wt_caco3Edit->setValue(0); ui->wt_naEdit->setValue(0); ui->wt_clEdit->setValue(0); ui->wt_so4Edit->setValue(0); } else { query.prepare("SELECT * FROM profile_water ORDER BY name"); query.exec(); query.first(); 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()); } calcWater(); } void EditRecipe::adjustWaters(double factor) { int i; double amount; if (recipe->mashs.size() == 0) return; double mash_infuse = 0; for (i = 0; i < recipe->mashs.size(); i++) { if (recipe->mashs.at(i).step_type == 0) { // Infusion amount = round(recipe->mashs.at(i).step_infuse_amount * factor * 1000000.0) / 1000000.0; recipe->mashs[i].step_infuse_amount = amount; mash_infuse += amount; recipe->mashs[i].step_volume = mash_infuse; } } const QSignalBlocker blocker1(ui->w1_volEdit); const QSignalBlocker blocker2(ui->w2_volEdit); if (recipe->w2_amount == 0) { recipe->w1_amount = mash_infuse; ui->w1_volEdit->setValue(mash_infuse); } else { double w1 = (recipe->w1_amount / (recipe->w1_amount + recipe->w2_amount)) * mash_infuse; double w2 = (recipe->w2_amount / (recipe->w1_amount + recipe->w2_amount)) * mash_infuse; recipe->w1_amount = w1; recipe->w2_amount = w2; ui->w1_volEdit->setValue(recipe->w1_amount); ui->w2_volEdit->setValue(recipe->w2_amount); } recipe->wg_amount = mash_infuse; ui->wg_volEdit->setValue(mash_infuse); } void EditRecipe::wb_cacl2_changed(double val) { set_brewing_salt("CaCl2", val); } void EditRecipe::wb_caso4_changed(double val) { set_brewing_salt("CaSO4", val); } void EditRecipe::wb_mgso4_changed(double val) { set_brewing_salt("MgSO4", val); } void EditRecipe::wb_nacl_changed(double val) { set_brewing_salt("NaCl", val); } void EditRecipe::wb_mgcl2_changed(double val) { set_brewing_salt("MgCl2", val); } void EditRecipe::wb_nahco3_changed(double val) { set_brewing_salt("NaHCO3", val); } void EditRecipe::wb_caco3_changed(double val) { set_brewing_salt("CaCO3", val); }