src/EditProductTab8.cpp

changeset 359
dfbb012c631c
parent 350
37b3c690b02c
child 361
ec8de79f6ff6
--- a/src/EditProductTab8.cpp	Sun Jul 17 22:18:48 2022 +0200
+++ b/src/EditProductTab8.cpp	Mon Jul 18 17:04:02 2022 +0200
@@ -161,7 +161,7 @@
     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));
+    ui->w1_raEdit->setValue(Utils::ResidualAlkalinity(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium));
 
     /*
      * If there is a dilute water source, mix the waters.
@@ -176,7 +176,7 @@
 	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));
+    	ui->w2_raEdit->setValue(Utils::ResidualAlkalinity(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium));
     } else {
 	liters = product->w1_amount;
 	calcium = product->w1_calcium;
@@ -197,18 +197,18 @@
     product->wg_total_alkalinity = round(total_alkalinity * 10.0) / 10.0;
     product->wg_ph = ph;
 
+    bicarbonate = Utils::Bicarbonate(total_alkalinity, 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_hco3Edit->setValue(bicarbonate);
     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);
     ui->wg_hardnessEdit->setValue(Utils::Hardness(calcium, magnesium));
-    ui->wg_raEdit->setValue(Utils::RA_ppm(total_alkalinity, calcium, magnesium));
-    bicarbonate = total_alkalinity * 1.22;
+    ui->wg_raEdit->setValue(Utils::ResidualAlkalinity(total_alkalinity, calcium, magnesium));
 
     /* Save mixed water ions for later */
     double wg_calcium = calcium;
@@ -265,10 +265,17 @@
 	    Acidmg = Acid;
 	    Acid = Acid / my_acids[AT].AcidSG;
 	    Acid = round((Acid / (product->wa_acid_perc / 100.0)) * 100.0) / 100.0;
+	    qDebug() << "  Mash auto Acid final old ml:" << Acid;
+	    Acid = Acidmg;
+
+	    double RealSG = round(((my_acids[AT].AcidSG - 1000) * (product->wa_acid_perc / 100)) + 1000);
+	    Acid /= RealSG;
+	    Acid /= my_acids[AT].AcidPrc / 100;
+	    Acid = round(Acid * 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);
+	    brewing_salt_sub(w, Acid, MISC_USES_MASH);
 	    ui->mw_acidvolEdit->setValue(Acid);
 
 	    bicarbonate = bicarbonate - protonDeficit * frac / liters;
@@ -282,17 +289,19 @@
 	 * Manual adjust acid, calculate resulting pH.
 	 */
 	double pHa = ph;	// Mixed water pH.
+	double RealSG = round(((my_acids[AT].AcidSG - 1000) * (product->wa_acid_perc / 100)) + 1000);
 	// Then calculate the new pH with added acids and malts
 	qDebug() << "  Mash pH:" << pHa;
-	Acid = my_acids[AT].AcidSG * (product->wa_acid_perc / 100.0);	// ml
+	Acid = RealSG;
 	Acid *= ui->mw_acidvolEdit->value();
+	Acid *= my_acids[AT].AcidPrc / 100;
 	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;
+	qDebug() << "  Acid:" << Acid << "protonDeficit:" << protonDeficit << "frac:" << frac << "pH:" << pHa;
 
 	double deltapH = 0.001;
    	double deltapd = 0.1;
@@ -308,7 +317,7 @@
 	    protonDeficit = Acid * frac;
 	    pd = ProtonDeficit(pHa);
 	}
-	//qDebug() << "  n:" << n << "pd:" << pd << "protonDeficit:" << protonDeficit << "frac:" << frac << "pHa:" << pHa;
+	qDebug() << "  n:" << n << "pd:" << pd << "protonDeficit:" << protonDeficit << "frac:" << frac << "pHa:" << pHa;
 
 	bicarbonate = wg_bicarbonate - protonDeficit * frac / liters;
 	total_alkalinity = bicarbonate * 50 / 61;
@@ -383,7 +392,7 @@
     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_raEdit->setValue(Utils::ResidualAlkalinity(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");
@@ -420,80 +429,130 @@
 
     qDebug() << "calcSparge()";
 
-    const QSignalBlocker blocker1(ui->sp_sourceEdit);
+    const QSignalBlocker blocker2(ui->w1_spButton);
+    const QSignalBlocker blocker3(ui->w2_spButton);
+    const QSignalBlocker blocker4(ui->wg_spButton);
 
     // Select watersource or fallback to the first source.
     if (product->sparge_source == 1) { // Source 2
 	if (product->w2_ph > 0.0 && product->w2_amount > 0) {
 	    Source_pH = product->w2_ph;
 	    Source_alkalinity = product->w2_total_alkalinity;
+	    ui->sp_caEdit->setValue(product->w2_calcium);
+            ui->sp_mgEdit->setValue(product->w2_magnesium);
+            ui->sp_hco3Edit->setValue(Utils::Bicarbonate(product->w2_total_alkalinity, product->w2_ph));
+            ui->sp_caco3Edit->setValue(product->w2_total_alkalinity);
+            ui->sp_naEdit->setValue(product->w2_sodium);
+            ui->sp_clEdit->setValue(product->w2_chloride);
+            ui->sp_so4Edit->setValue(product->w2_sulfate);
+            ui->sp_phShow->setValue(product->w2_ph);
+            ui->sp_hardnessEdit->setValue(Utils::Hardness(product->w2_calcium, product->w2_magnesium));
+            ui->sp_raEdit->setValue(Utils::ResidualAlkalinity(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium));
+	    ui->w2_spButton->setChecked(true);
 	} else {
-	    product->sparge_source = 0; // Source 1
-	    ui->sp_sourceEdit->setCurrentIndex(0);
+	    product->sparge_source = 0; // Fallback to source 1
+	    ui->w1_spButton->setChecked(true);
 	}
     } else if (product->sparge_source == 2) { // Mixed
 	if (product->w2_ph > 0.0 && product->w2_amount > 0) {
 	    Source_pH = product->wg_ph;
 	    Source_alkalinity = product->wg_total_alkalinity;
+	    ui->sp_caEdit->setValue(product->wg_calcium);
+	    ui->sp_mgEdit->setValue(product->wg_magnesium);
+	    ui->sp_hco3Edit->setValue(Utils::Bicarbonate(product->wg_total_alkalinity, product->wg_ph));
+	    ui->sp_caco3Edit->setValue(product->wg_total_alkalinity);
+	    ui->sp_naEdit->setValue(product->wg_sodium);
+	    ui->sp_clEdit->setValue(product->wg_chloride);
+	    ui->sp_so4Edit->setValue(product->wg_sulfate);
+	    ui->sp_phShow->setValue(product->wg_ph);
+	    ui->sp_hardnessEdit->setValue(Utils::Hardness(product->wg_calcium, product->wg_magnesium));
+	    ui->sp_raEdit->setValue(Utils::ResidualAlkalinity(product->wg_total_alkalinity, product->wg_calcium, product->wg_magnesium));
+	    ui->wg_spButton->setChecked(true);
 	} else {
-	    product->sparge_source = 0; // Source 1
-            ui->sp_sourceEdit->setCurrentIndex(0);
+	    product->sparge_source = 0; // Fallback to source 1
+	    ui->w1_spButton->setChecked(true);
 	}
     }
+    if (product->sparge_source == 0) {
+	ui->sp_caEdit->setValue(product->w1_calcium);
+	ui->sp_mgEdit->setValue(product->w1_magnesium);
+	ui->sp_hco3Edit->setValue(Utils::Bicarbonate(product->w1_total_alkalinity, product->w1_ph));
+	ui->sp_caco3Edit->setValue(product->w1_total_alkalinity);
+	ui->sp_naEdit->setValue(product->w1_sodium);
+	ui->sp_clEdit->setValue(product->w1_chloride);
+	ui->sp_so4Edit->setValue(product->w1_sulfate);
+	ui->sp_phShow->setValue(product->w1_ph);
+	ui->sp_hardnessEdit->setValue(Utils::Hardness(product->w1_calcium, product->w1_magnesium));
+	ui->sp_raEdit->setValue(Utils::ResidualAlkalinity(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium));
+	ui->w1_spButton->setChecked(true);
+    }
+    // The spargewater is set.
+
+    int AT = product->sparge_acid_type;
+    if (AT < 0 || AT >= my_acids.size()) {
+        AT = 0;
+        product->sparge_acid_type = 0;
+        ui->sp_acidtypeEdit->setCurrentIndex(0);
+        product->sparge_acid_perc = my_acids[0].AcidPrc;
+        ui->sp_acidpercEdit->setValue(product->sparge_acid_perc);
+    }
 
-    // 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;
+    /*
+     * Auto calculate the required acid
+     */
+    if (product->calc_acid) {
+    	// 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 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 4. Solve
+    	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 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 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 7. There is no step 7.
+
+    	// Step 8. Get the acid data.
+    	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 8. Get the acid data.
-    int AT = product->sparge_acid_type;
-    if (AT < 0 || AT >= my_acids.size()) {
-	AT = 0;
-	product->sparge_acid_type = 0;
-	ui->sp_acidtypeEdit->setCurrentIndex(0);
-	product->sparge_acid_perc = my_acids[0].AcidPrc;
-	ui->sp_acidpercEdit->setValue(product->sparge_acid_perc);
+    	// 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.
+    	double RealSG = round(((my_acids[AT].AcidSG - 1000) * (product->sparge_acid_perc / 100)) + 1000);
+    	Acid = Acid / RealSG;		//ml
+    	Acid *= product->sparge_volume;	//ml acid total at 100%
+    	Acid /= my_acids[AT].AcidPrc / 100;	//ml acid at supplied strength
+    	Acid = round(Acid * 100.0) / 100.0;
+    	product->sparge_acid_amount = Acid / 1000;
+    	QString w = my_acids[AT].name_en + ' ' + my_acids[AT].name_nl;
+    	brewing_salt_sub(w, Acid, MISC_USES_SPARGE);	// Put it in the miscs table.
+    	ui->sp_acidvolEdit->setValue(Acid);
     }
-    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 / (product->sparge_acid_perc / 100); //ml
-    Acid *= product->sparge_volume; //ml acid total
-    Acid = round(Acid * 100.0) / 100.0;
-    product->sparge_acid_amount = Acid / 1000;
-    ui->sp_acidvolEdit->setValue(Acid);
-
+    ui->sp_phShow->setValue(product->sparge_ph);
     // 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));
@@ -502,11 +561,13 @@
 }
 
 
-void EditProduct::sp_source_changed(int val)
+void EditProduct::sp_group_changed(int val)
 {
-    product->sparge_source = val;
-    calcSparge();
-    is_changed();
+    if (val != product->sparge_source) {
+	product->sparge_source = val;
+    	calcSparge();
+    	is_changed();
+    }
 }
 
 
@@ -522,7 +583,6 @@
 void EditProduct::sp_temp_changed(double val)
 {
     product->sparge_temp = val;
-    ui->brew_spargetempShow->setValue(val);
     calcSparge();
     is_changed();
 }
@@ -530,9 +590,23 @@
 
 void EditProduct::sp_type_changed(int val)
 {
+    if (val == product->sparge_acid_type)
+        return;
+
+    qDebug() << "sp_type_changed" << val << "old" << product->sparge_acid_type;
+    /*
+     * First remove current acid.
+     */
+    QString w = my_acids[product->sparge_acid_type].name_en + ' ' + my_acids[product->sparge_acid_type].name_nl;
+    brewing_salt_sub(w, 0, MISC_USES_SPARGE);
+
     product->sparge_acid_type = val;
+    w = my_acids[product->sparge_acid_type].name_en + ' ' + my_acids[product->sparge_acid_type].name_nl;
+
     product->sparge_acid_perc = my_acids[val].AcidPrc;
     ui->sp_acidpercEdit->setValue(product->sparge_acid_perc);
+    brewing_salt_sub(w, ui->sp_acidvolEdit->value(), MISC_USES_SPARGE);	// For now, set old amount.
+
     calcSparge();
     is_changed();
 }
@@ -547,6 +621,116 @@
 }
 
 
+void EditProduct::sp_acid_changed(double val)
+{
+    if (product->calc_acid)
+        return;
+
+    qDebug() << "sp_acid_changed" << val << product->sparge_acid_amount * 1000.0;
+
+    double TargetpH = product->sparge_ph;
+    double Source_pH = product->w1_ph;
+    double Source_alkalinity = product->w1_total_alkalinity;
+
+    if (product->sparge_source == 1) { // Source 2
+	if (product->w2_ph > 0.0 && product->w2_amount > 0) {
+	    Source_pH = product->w2_ph;
+            Source_alkalinity = product->w2_total_alkalinity;
+	}
+    } else if (product->sparge_source == 2) { // Mixed
+	if (product->w2_ph > 0.0 && product->w2_amount > 0) {
+	    Source_pH = product->wg_ph;
+            Source_alkalinity = product->wg_total_alkalinity;
+	}
+    }
+
+    int AT = product->sparge_acid_type;
+    if (AT < 0 || AT >= my_acids.size()) {
+        AT = 0;
+        product->sparge_acid_type = 0;
+        ui->sp_acidtypeEdit->setCurrentIndex(0);
+        product->sparge_acid_perc = my_acids[0].AcidPrc;
+        ui->sp_acidpercEdit->setValue(product->sparge_acid_perc);
+    }
+
+    bool go_up = (val < (product->sparge_acid_amount * 1000.0));
+    bool loop = true;
+
+    while (loop) {
+
+	if (go_up)
+	    TargetpH += 0.001;
+	else
+	    TargetpH -= 0.001;
+	//qDebug() << "  TargetpH" << TargetpH << "up" << go_up;
+
+        // 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 / 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 7. There is no step 7.
+
+        // Step 8. Get the acid data.
+        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.
+        double RealSG = round(((my_acids[AT].AcidSG - 1000) * (product->sparge_acid_perc / 100)) + 1000);
+        Acid = Acid / RealSG;           //ml
+        Acid *= product->sparge_volume; //ml acid total at 100%
+        Acid /= my_acids[AT].AcidPrc / 100;     //ml acid at supplied strength
+        Acid = round(Acid * 100.0) / 100.0;
+        product->sparge_acid_amount = Acid / 1000;
+	//qDebug() << "  acid" << product->sparge_acid_amount;
+
+	if (go_up && (val > (product->sparge_acid_amount * 1000.0)))
+	    loop = false;
+	else if (! go_up && (val < (product->sparge_acid_amount * 1000.0)))
+	    loop = false;
+
+	//qDebug() << "  test" << loop << go_up << val << product->sparge_acid_amount * 1000.0;
+    }
+
+    const QSignalBlocker blocker1(ui->sp_phEdit);
+    product->sparge_ph = round(TargetpH * 100) / 100;
+    ui->sp_phEdit->setValue(product->sparge_ph);
+    ui->sp_phShow->setValue(product->sparge_ph);
+
+    QString w = my_acids[AT].name_en + ' ' + my_acids[AT].name_nl;
+    set_brewing_salt(w, val, MISC_USES_SPARGE);
+    //qDebug() << "  new" << product->sparge_ph << val;
+}
+
+
 double EditProduct::GetBUGU()
 {
     double gu = (product->est_og - 1) * 1000;
@@ -575,6 +759,10 @@
     ui->mw_phEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
     ui->mw_acidvolEdit->setReadOnly(product->calc_acid);
     ui->mw_acidvolEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
+    ui->sp_phEdit->setReadOnly(! product->calc_acid);
+    ui->sp_phEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::UpDownArrows : QAbstractSpinBox::NoButtons);
+    ui->sp_acidvolEdit->setReadOnly(product->calc_acid);
+    ui->sp_acidvolEdit->setButtonSymbols(product->calc_acid ? QAbstractSpinBox::NoButtons : QAbstractSpinBox::UpDownArrows);
     is_changed();
     calcWater();
 }
@@ -601,7 +789,7 @@
 
     qDebug() << "on_mw_acid_changed" << val;
     QString w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl;
-    set_brewing_salt(w, val);
+    set_brewing_salt(w, val, MISC_USES_MASH);
 }
 
 
@@ -615,14 +803,14 @@
      * First remove current acid.
      */
     QString w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl;
-    brewing_salt_sub(w, 0);
+    brewing_salt_sub(w, 0, MISC_USES_MASH);
 
     product->wa_acid_name = val;
     w = my_acids[product->wa_acid_name].name_en + ' ' + my_acids[product->wa_acid_name].name_nl;
 
     product->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.
+    brewing_salt_sub(w, ui->mw_acidvolEdit->value(), MISC_USES_MASH);   // For now, set old amount.
 
     is_changed();
     calcWater();
@@ -684,7 +872,16 @@
                 product->waters_ok = false;
                 qDebug() << "w2_amount too low";
             }
+	    ui->w2_spButton->setEnabled(true);
+            ui->wg_spButton->setEnabled(true);
         }
+    } else {
+	/*
+	 * Block selecting sparge water 2 and mixed water.
+	 */
+	ui->w2_spButton->setEnabled(false);
+	ui->wg_spButton->setEnabled(false);
+	product->sparge_source = 0;      // Only water source 1
     }
 }
 
@@ -722,14 +919,14 @@
 
     ui->w1_caEdit->setValue(product->w1_calcium);
     ui->w1_mgEdit->setValue(product->w1_magnesium);
-    ui->w1_hco3Edit->setValue(product->w1_total_alkalinity * 1.22);
+    ui->w1_hco3Edit->setValue(Utils::Bicarbonate(product->w1_total_alkalinity, product->w1_ph));
     ui->w1_caco3Edit->setValue(product->w1_total_alkalinity);
     ui->w1_naEdit->setValue(product->w1_sodium);
     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));
+    ui->w1_raEdit->setValue(Utils::ResidualAlkalinity(product->w1_total_alkalinity, product->w1_calcium, product->w1_magnesium));
 
     check_waters();
     is_changed();
@@ -774,13 +971,13 @@
         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);
+	ra_ppm = Utils::ResidualAlkalinity(product->w2_total_alkalinity, product->w2_calcium, product->w2_magnesium);
     }
     ui->w1_volEdit->setValue(product->w1_amount);
     ui->w2_volEdit->setValue(product->w2_amount);
     ui->w2_caEdit->setValue(product->w2_calcium);
     ui->w2_mgEdit->setValue(product->w2_magnesium);
-    ui->w2_hco3Edit->setValue(product->w2_total_alkalinity * 1.22);
+    ui->w2_hco3Edit->setValue(Utils::Bicarbonate(product->w2_total_alkalinity, product->w2_ph));
     ui->w2_caco3Edit->setValue(product->w2_total_alkalinity);
     ui->w2_naEdit->setValue(product->w2_sodium);
     ui->w2_clEdit->setValue(product->w2_chloride);
@@ -825,7 +1022,7 @@
         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()));
+    	ui->wt_raEdit->setValue(Utils::ResidualAlkalinity(query.value("total_alkalinity").toDouble(), query.value("calcium").toDouble(), query.value("magnesium").toDouble()));
     }
     calcWater();
 }
@@ -868,12 +1065,16 @@
 }
 
 
-void EditProduct::wb_cacl2_changed(double val)  { set_brewing_salt("CaCl2", val);  }
-void EditProduct::wb_caso4_changed(double val)  { set_brewing_salt("CaSO4", val);  }
-void EditProduct::wb_mgso4_changed(double val)  { set_brewing_salt("MgSO4", val);  }
-void EditProduct::wb_nacl_changed(double val)   { set_brewing_salt("NaCl", val);   }
-void EditProduct::wb_mgcl2_changed(double val)  { set_brewing_salt("MgCl2", val);  }
-void EditProduct::wb_nahco3_changed(double val) { set_brewing_salt("NaHCO3", val); }
-void EditProduct::wb_caco3_changed(double val)  { set_brewing_salt("CaCO3", val);  }
+void EditProduct::wb_cacl2_changed(double val)  { set_brewing_salt("CaCl2", val, MISC_USES_MASH);   }
+void EditProduct::wb_caso4_changed(double val)  { set_brewing_salt("CaSO4", val, MISC_USES_MASH);   }
+void EditProduct::wb_mgso4_changed(double val)  { set_brewing_salt("MgSO4", val, MISC_USES_MASH);   }
+void EditProduct::wb_nacl_changed(double val)   { set_brewing_salt("NaCl", val, MISC_USES_MASH);    }
+void EditProduct::wb_mgcl2_changed(double val)  { set_brewing_salt("MgCl2", val, MISC_USES_MASH);   }
+void EditProduct::wb_nahco3_changed(double val) { set_brewing_salt("NaHCO3", val, MISC_USES_MASH);  }
+void EditProduct::wb_caco3_changed(double val)  { set_brewing_salt("CaCO3", val, MISC_USES_MASH);   }
+void EditProduct::sp_cacl2_changed(double val)  { set_brewing_salt("CaCl2", val, MISC_USES_SPARGE); }
+void EditProduct::sp_caso4_changed(double val)  { set_brewing_salt("CaSO4", val, MISC_USES_SPARGE); }
+void EditProduct::sp_mgso4_changed(double val)  { set_brewing_salt("MgSO4", val, MISC_USES_SPARGE); }
+void EditProduct::sp_nacl_changed(double val)   { set_brewing_salt("NaCl", val, MISC_USES_SPARGE);  }
+void EditProduct::sp_mgcl2_changed(double val)  { set_brewing_salt("MgCl2", val, MISC_USES_SPARGE); }
 
-

mercurial