src/EditRecipeTab7.cpp

Wed, 20 Apr 2022 14:30:06 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 20 Apr 2022 14:30:06 +0200
changeset 149
d73719fa2ebb
parent 139
f947c6988e91
child 150
fd568cc1dd0e
permissions
-rw-r--r--

Implemented choose main and dillution waters. Implement change dillution water volume.

/**
 * 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;
    }

    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;
	this->ignoreChanges = true;
	ui->mw_acidPick->setCurrentIndex(0);
	ui->mw_acidpercEdit->setValue(my_acids.at(0).AcidPrc);
	this->ignoreChanges = false;
    }
    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);
	    this->ignoreChanges = true;
	    ui->mw_acidvolEdit->setValue(Acid);
	    this->ignoreChanges = false;

	    bicarbonate = bicarbonate - protonDeficit * frac / liters;
	    total_alkalinity = bicarbonate * 50 / 61;
	}
	ph = TpH;
	this->ignoreChanges = true;
	ui->wb_phEdit->setValue(ph);
	this->ignoreChanges = false;
	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;
	this->ignoreChanges = true;
	ui->wb_phEdit->setValue(ph);
	ui->mw_phEdit->setValue(ph);
	this->ignoreChanges = false;
        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;
    if (val == 0) {
	/*
	 * If no water is selected, take the default water.
	 */
	this->ignoreChanges = true;
	val = my_default_water;
	ui->w1_nameEdit->setCurrentIndex(val);
	this->ignoreChanges = false;
    }

    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_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_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_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::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