src/EditRecipeTab7.cpp

Fri, 22 Apr 2022 13:46:59 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 22 Apr 2022 13:46:59 +0200
changeset 152
58e4ce7dd217
parent 150
fd568cc1dd0e
child 161
b36d249512cc
permissions
-rw-r--r--

Fixed vanishing mash profiles from some recipes. All ingnoreChanges flags removed and replaced by blocking signals. Update prompts and yeast amounts depending on the yeast form. Save water profile names fixed.

/**
 * 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.f_di_ph != 5.7) && ((F.f_acid_to_ph_57 < - 0.1) || (F.f_acid_to_ph_57 > 0.1))) {
	C1 = F.f_acid_to_ph_57 / (F.f_di_ph - 5.7);
     } else {
	/*
	 * If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid.
	 */
	switch (F.f_graintype) {
	   case 0:					// Base, Special, Kilned
	   case 3:
	   case 5:	C1 = 0.014 * F.f_color - 34.192;
			break;
	   case 2:	C1 = -0.0597 * F.f_color - 32.457;	// Crystal
			break;
	   case 1:	C1 = 0.0107 * F.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.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.f_added == 0 && F.f_graintype != 6) { // Added == Mash && graintype != No Malt
		x = AcidRequired(pHZ, F) * 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);

    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();
}


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);  }

mercurial