Backport water treatment to the product editor (inluding the bugs).

Mon, 31 Dec 2018 14:41:08 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 31 Dec 2018 14:41:08 +0100
changeset 159
6428dae0605d
parent 158
3b9e4dfb0476
child 160
fea87a8d320b

Backport water treatment to the product editor (inluding the bugs).

www/includes/db_product.php file | annotate | diff | comparison | revisions
www/js/prod_edit.js file | annotate | diff | comparison | revisions
www/js/rec_edit.js file | annotate | diff | comparison | revisions
www/prod_edit.php file | annotate | diff | comparison | revisions
--- a/www/includes/db_product.php	Sun Dec 30 22:01:27 2018 +0100
+++ b/www/includes/db_product.php	Mon Dec 31 14:41:08 2018 +0100
@@ -203,12 +203,13 @@
 	$sql .= "', sparge_temp='" . $_POST['sparge_temp'];
 	$sql .= "', sparge_ph='" . $_POST['sparge_ph'];
 	$sql .= "', sparge_volume='" . $_POST['sparge_volume'];
-//	$sql .= "', sparge_acid_type='" . $_POST['sparge_acid_type'];
-//	$sql .= "', sparge_acid_perc='" . $_POST['sparge_acid_perc'];
-//	$sql .= "', sparge_acid_amount='" . $_POST['sparge_acid_amount'];
+	$sql .= "', sparge_source='" . $_POST['sparge_source'];
+	$sql .= "', sparge_acid_type='" . $_POST['sparge_acid_type'];
+	$sql .= "', sparge_acid_perc='" . $_POST['sparge_acid_perc'];
+	$sql .= "', sparge_acid_amount='" . $_POST['sparge_acid_amount'];
 	$sql .= "', mash_ph='" . $_POST['mash_ph'];
 	$sql .= "', mash_name='" . $_POST['mash_name'];
-	$sql .= "', calc_acid='" . $_POST['calc_acid'];
+	($_POST['calc_acid'] == 'true') ? $sql .= "', calc_acid='1" : $sql .= "', calc_acid='0";
 	if (isset($_POST['w1_name'])) {
 		$sql .= "', w1_name='" . mysqli_real_escape_string($connect, $_POST['w1_name']);
 		$sql .= "', w1_amount='" . $_POST['w1_amount'];
@@ -297,21 +298,18 @@
 		$sql .= "' WHERE record='" . $_POST['record'] . "';";
 	}
 
-
-//	$result = mysqli_query($connect, $sql);
-//	if (! $result) {
-	//		syslog(LOG_NOTICE, "db_product: result: ".mysqli_error($connect));
-	//		echo $result;
-	//		return;
-//	} else {
-//		if (isset($_POST['update'])) {
-//			syslog(LOG_NOTICE, "db_product: updated record ".$_POST['record']);
-//		} else {
-//			$lastid = mysqli_insert_id($connect);
-//			syslog(LOG_NOTICE, "db_product: inserted record ".$lastid);
-//		}
-//	}
-//	echo $result;
+	$result = mysqli_query($connect, $sql);
+	if (! $result) {
+			syslog(LOG_NOTICE, "db_product: result: ".mysqli_error($connect));
+	} else {
+		if (isset($_POST['update'])) {
+			syslog(LOG_NOTICE, "db_product: updated record ".$_POST['record']);
+		} else {
+			$lastid = mysqli_insert_id($connect);
+			syslog(LOG_NOTICE, "db_product: inserted record ".$lastid);
+		}
+	}
+	echo $result;
 
 } else if (isset($_POST['delete'])) {
 	/*
@@ -494,7 +492,8 @@
 		$brew .= '","sparge_temp":' . floatval($row['sparge_temp']);
 		$brew .= ',"sparge_ph":' . floatval($row['sparge_ph']);
 		$brew .= ',"sparge_volume":' . floatval($row['sparge_volume']);
-		$brew .= ',"sparge_acid_type":"' . $row['sparge_acid_type'];
+		$brew .= ',"sparge_source":"' . $row['sparge_source'];
+		$brew .= '","sparge_acid_type":"' . $row['sparge_acid_type'];
 		$brew .= '","sparge_acid_perc":' . floatval($row['sparge_acid_perc']);
 		$brew .= ',"sparge_acid_amount":' . floatval($row['sparge_acid_amount']);
 		$brew .= ',"mash_ph":' . $row['mash_ph'];
--- a/www/js/prod_edit.js	Sun Dec 30 22:01:27 2018 +0100
+++ b/www/js/prod_edit.js	Mon Dec 31 14:41:08 2018 +0100
@@ -305,6 +305,19 @@
 			$("#brew_mash_efficiency").val(0);
 	};
 
+	function GetBUGU() {
+		var gu = (dataRecord.est_og - 1) * 1000;
+		if (gu > 0)
+			return dataRecord.est_ibu / gu;
+		else
+			return 0.5;
+	}
+
+	function GetOptClSO4ratio() {
+		var BUGU = GetBUGU();
+		return (-1.2 * BUGU + 1.4);
+	}
+
 	function setWaterAgent(name, amount) {
 		console.log("setWaterAgent(" + name + ", " + amount + ")");
 		var rows = $('#miscGrid').jqxGrid('getrows');
@@ -313,9 +326,7 @@
 				var row = rows[i];
 				if (row.m_name == name) {
 					var id = $("#miscGrid").jqxGrid('getrowid', i);
-					// console.log("name found, erase "+ id);
 					var commit = $("#miscGrid").jqxGrid('deleterow', id);
-					// console.log("result: "+commit);
 				}
 			}
 		} else {
@@ -329,7 +340,6 @@
 					break;
 				}
 			}
-			console.log("set something, found: "+found);
 			if (! found) {
 				var miscs = new $.jqx.dataAdapter(miscInvSource, {
 					loadComplete: function () {
@@ -368,7 +378,138 @@
 		return 0;
 	}
 
-	// pH calculations
+	// mg/l as CaCO3
+	function ResidualAlkalinity(total_alkalinity, calcium, magnesium) {
+		return total_alkalinity - (calcium / 1.4 + magnesium / 1.7);
+	}
+
+	var Ka1 = 0.0000004445;
+	var Ka2 = 0.0000000000468;
+
+	function PartCO3(pH) {
+		var H = Math.pow(10, -pH);
+		return 100 * Ka1 * Ka2 / (H*H + H * Ka1 + Ka1 * Ka2);
+	}
+
+	function PartHCO3(pH) {
+		var H = Math.pow(10, -pH);
+		return 100 * Ka1 * H / (H*H + H * Ka1 + Ka1 * Ka2);
+	}
+
+	function Charge(pH) {
+		return (-2 * PartCO3(pH) - PartHCO3(pH));
+	}
+
+	//Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH)
+	function ZAlkalinity(pHZ) {
+		var C43 = Charge(4.3);
+		var Cw = Charge(parseFloat($("#wg_ph").jqxNumberInput('decimal')));
+		var Cz = Charge(pHZ);
+		var DeltaCNaught = -C43+Cw;
+		var CT = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')) / 50 / DeltaCNaught;
+		var 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)
+	function ZRA(pHZ) {
+
+		var Calc = parseFloat($("#wg_calcium").jqxNumberInput('decimal')) / (MMCa / 2);
+		var Magn = parseFloat($("#wg_magnesium").jqxNumberInput('decimal')) / (MMMg / 2);
+		var Z = ZAlkalinity(pHZ);
+		return Z - (Calc / 3.5 + Magn / 7);
+	}
+
+	function ProtonDeficit(pHZ) {
+
+		var Result = ZRA(pHZ) * parseFloat($("#wg_amount").jqxNumberInput('decimal'));
+		// proton deficit for the grist
+		var rows = $('#fermentableGrid').jqxGrid('getrows');
+		for (var i = 0; i < rows.length; i++) {
+			var row = rows[i];
+			if (row.f_added == 'Mash' && row.f_graintype != 'No malt') {
+				// Check if acid is required
+				var C1 = 0;
+				if ((row.f_di_ph != 5.7) && ((row.f_acid_to_ph_57 < - 0.1) || (row.f_acid_to_ph_57 > 0.1))) {
+						C1 = row.f_acid_to_ph_57 / (row.f_di_ph - 5.7);
+				} else {
+					// If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid.
+					var ebc = row.f_color;
+					switch (row.f_graintype) {
+						case 'Base':
+						case 'Special':
+						case 'Kilned':  C1 = 0.014 * ebc - 34.192;
+								break;
+						case 'Crystal': C1 = -0.0597 * ebc - 32.457;
+								break;
+						case 'Roast':   C1 = 0.0107 * ebc - 54.768;
+								break;
+						case 'Sour':    C1 = -149;
+								break;
+					}
+				}
+				x = C1 * (pHZ - row.f_di_ph);   // AcidRequired(ZpH)
+				Result += x * row.f_amount;
+			}
+		}
+		return Result;
+	}
+
+	function MashpH() {
+		var n = 0;
+		var pH = 5.4;
+		var deltapH = 0.001;
+		var deltapd = 0.1;
+		var 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);
+		}
+		console.log("MashpH() n: "+n+" pH: "+pH);
+		return pH;
+	}
+
+	function GetAcidSpecs(AT) {
+		switch(AT) {
+			case 'Melkzuur':        return {
+							pK1: 3.08,
+							pK2: 20,
+							pK3: 20,
+							MolWt: 90.08,
+							AcidSG: 1214,
+							AcidPrc: 0.88
+						};
+			case 'Zoutzuur':        return {
+							pK1: -10,
+							pK2: 20,
+							pK3: 20,
+							MolWt: 36.46,
+							AcidSG: 1142,
+							AcidPrc: 0.28
+						};
+			case 'Fosforzuur':      return {
+							pK1: 2.12,
+							pK2: 7.20,
+							pK3: 12.44,
+							MolWt: 98.00,
+							AcidSG: 1170,
+							AcidPrc: 0.25
+						};
+			case 'Zwavelzuur':      return {
+							pK1: -10,
+							pK2: 1.92,
+							pK3: 20,
+							MolWt: 98.07,
+							AcidSG: 1700,
+							AcidPrc: 0.93
+						};
+		}
+	}
+
 
 	function calcWater() {
 
@@ -378,6 +519,7 @@
 		var magnesium = 0;
 		var sodium = 0;
 		var total_alkalinity = 0;
+		var bicarbonate = 0;
 		var chloride = 0;
 		var sulfate = 0;
 		var ph = 0;
@@ -393,122 +535,316 @@
 		var AcidPrc = 0;
 		var protonDeficit = 0;
 
-		if (dataRecord.w1_name != "") {
-			if (dataRecord.w2_name != "") {
-				liters = dataRecord.w1_amount + dataRecord.w2_amount;
-				calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium);
-				magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium);
-				sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium);
-				chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride);
-				sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate);
-				total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity);
-				ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount))  / liters);
-			} else {
-				liters = dataRecord.w1_amount;
-				calcium = dataRecord.w1_calcium;
-				magnesium = dataRecord.w1_magnesium;
-				sodium = dataRecord.w1_sodium;
-				chloride = dataRecord.w1_chloride;
-				sulfate = dataRecord.w1_sulfate;
-				total_alkalinity = dataRecord.w1_total_alkalinity;
-				ph = dataRecord.w1_ph;
-			}
+		if (dataRecord.w1_name == "") {
+			return;
+		}
+
+		// If there is a dillute water source, mix the waters.
+		if (dataRecord.w2_name != "") {
+			liters = dataRecord.w1_amount + dataRecord.w2_amount;
+			calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium);
+			magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium);
+			sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium);
+			chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride);
+			sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate);
+			total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity);
+			ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount))  / liters);
+		} else {
+			liters = dataRecord.w1_amount;
+			calcium = dataRecord.w1_calcium;
+			magnesium = dataRecord.w1_magnesium;
+			sodium = dataRecord.w1_sodium;
+			chloride = dataRecord.w1_chloride;
+			sulfate = dataRecord.w1_sulfate;
+			total_alkalinity = dataRecord.w1_total_alkalinity;
+			ph = dataRecord.w1_ph;
 		}
 		$('#wg_amount').val(liters);
+		var wg_calcium = calcium;
 		$('#wg_calcium').val(Math.round(calcium * 10) / 10);
+		var wg_magnesium = magnesium;
 		$('#wg_magnesium').val(Math.round(magnesium * 10) / 10);
+		var wg_sodium = sodium;
 		$('#wg_sodium').val(Math.round(sodium * 10) / 10);
+		var wg_total_alkalinity = total_alkalinity;
 		$('#wg_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10);
+		var wg_chloride = chloride;
 		$('#wg_chloride').val(Math.round(chloride * 10) / 10);
+		var wg_sulfate = sulfate;
 		$('#wg_sulfate').val(Math.round(sulfate * 10) / 10);
 		// Note: brouwhulp has the malts included here in the result.
+		var wg_ph = ph;
 		$('#wg_ph').val(Math.round(ph * 10) / 10);
+		$('#wb_ph').val(Math.round(MashpH() * 10) / 10);
+		bicarbonate = total_alkalinity * 1.22;
+		var wg_bicarbonate = bicarbonate;
 
 		// Noot: de volgende berekeningen geven bijna gelijke resultaten in Brun'water.
 		// Calculate Ca
 		RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
 		     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4;
-		calcium += 1000 * RA / parseFloat($("#wg_amount").jqxNumberInput('decimal'));
+		calcium += 1000 * RA / liters;
 
 		// Calculate Mg
 		RA = parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMMg / MMMgSO4;
-		magnesium += 1000 * RA / parseFloat($("#wg_amount").jqxNumberInput('decimal'));
+		magnesium += 1000 * RA / liters;
 
 		// Calculate Na
 		RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
 		     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
-		sodium += 1000 * RA / parseFloat($("#wg_amount").jqxNumberInput('decimal'));
+		sodium += 1000 * RA / liters;
 
 		// Calculate SO4
 		RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
 		     parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4;
-		sulfate += 1000 * RA / parseFloat($("#wg_amount").jqxNumberInput('decimal'));
+		sulfate += 1000 * RA / liters;
 
 		// Calculate Cl
 		RA = 2 * parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
 			 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl;
-		chloride += 1000 * RA / parseFloat($("#wg_amount").jqxNumberInput('decimal'));
+		chloride += 1000 * RA / liters;
 		// Einde noot.
 
-		TpH = parseFloat(dataRecord.mash_ph);
-		if (TpH < 5.0 || TpH > 6.0) {
-			TpH = 5.4;
-			dataRecord.mash_ph = 5.4;
-			$("#mash_ph").val(5.4);
-			$("#tgt_mash_ph").val(5.4);
+		if ($("#wa_acid_name").val() == "") {
+			$("#wa_acid_name").val('Melkzuur');
+			last_acid = 'Melkzuur';
+		}
+		if ($("#wa_base_name").val() == "") {
+			$("#wa_base_name").val('NaHCO3');
+			last_base = 'NaHCO3';
 		}
-		var acid_amount = parseFloat($("#wa_acid").jqxNumberInput('decimal'));
-		var acid_perc = parseFloat($("#wa_acid_perc").jqxNumberInput('decimal'));
+
+		var AT = $("#wa_acid_name").val();
+		var BT = $("#wa_base_name").val();
+
+		var result = GetAcidSpecs(AT);
+		pK1 = result.pK1;
+		pK2 = result.pK2;
+		pK3 = result.pK3;
+		MolWt = result.MolWt;
+		AcidSG = result.AcidSG;
+		AcidPrc = result.AcidPrc;
 
-		switch ($("#wa_acid_name").val()) {
-			case 'Melkzuur':        pK1 = 3.08;
-						pK2 = 20;
-						pK3 = 20;
-						MolWt = 90.08;
-						AcidSG = 1214; //@88%
-						AcidPrc = 0.88;
-						//frac = CalcFrac(TpH, pK1, pK2, pK3);
-						acid += acid_amount * acid_perc / 100 * AcidSG / MolWt * frac / liters; //mEq/l
-						break;
+		if (dataRecord.calc_acid) {
+			TpH = parseFloat(dataRecord.mash_ph);
+			protonDeficit = ProtonDeficit(TpH);
+			console.log("calc_acid tgt: "+TpH+" protonDeficit: "+protonDeficit);
+			if (protonDeficit > 0) { // Add acid
+				$("#wa_base").val(0);
+				setWaterAgent(last_base, 0);
+				frac = CalcFrac(TpH, pK1, pK2, pK3);
+				Acid = protonDeficit / frac;
+				Acid *= MolWt; // mg
+				Acidmg = Acid;
+				Acid = Acid / AcidSG; // ml
+
+				if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0)
+					$("#wa_acid_perc").val(AcidPrc);
+				Acid = Acid * AcidPrc / (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
+				console.log("Final ml: "+Acid);
+				$("#wa_acid").val(Math.round(Acid * 100) / 100);
+				setWaterAgent(AT, Math.round(Acid * 100) / 100);
 
-			case 'Zoutzuur':        pK1 = -10;
-						pK2 =  20;
-						pK3 =  20;
-						MolWt = 36.46;
-						AcidSG = 1142; //@28%
-						AcidPrc = 0.28;
-						//frac = CalcFrac(TpH, pK1, pK2, pK3);
-						Acidmg = acid_amount * acid_perc / 100 * AcidSG / liters;
-						acid += Acidmg / MolWt * frac; //mEq/l
-						chloride += Acidmg / 1000 * MMCl / (MMCl + 1);
-						break;
+				bicarbonate = bicarbonate - protonDeficit * frac / liters;
+				total_alkalinity = bicarbonate * 50 / 61;
+			} else if (protonDeficit < 0) { //Add base
+				$("#wa_acid").val(0);
+				setWaterAgent(last_acid, 0);
+				r1d = Math.pow(10, (TpH - 6.38));
+				r2d = Math.pow(10, (TpH - 10.38));
+				f1d = 1 / (1 + r1d + r1d * r2d);
+				f2d = f1d * r1d;
+				f3d = f2d * r2d;
+				switch (BT) {
+					case 'NaHCO3':  base = -protonDeficit / (f1d - f3d); //mmol totaal
+							base = base * MMNaHCO3/1000; //gram
+							$("#wa_base").val(Math.round(base * 100) / 100);
+							setWaterAgent(BT, Math.round(base * 100) / 100);
+							if (liters > 0) {
+								// Na
+								RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
+								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
+								RA = 1000 * RA / liters;
+								sodium = wg_sodium + RA;
+								// HCO3
+								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
+								RA = 1000 * RA / liters;
+								bicarbonate = wg_bicarbonate + RA;
+								total_alkalinity = bicarbonate * 50 / 61;
+								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+							}
+							break;
+					case 'Na2CO3':  base = -protonDeficit / (2 * f1d + f2d); //mmol totaal
+							base = base * MMNa2CO3/1000; //gram
+							$("#wa_base").val(Math.round(base * 100) / 100);
+							setWaterAgent(BT, Math.round(base * 100) / 100);
+							if (liters > 0) {
+								RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
+								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
+								RA = 1000 * RA / liters;
+								sodium = wg_sodium + RA;
+								// HCO3
+								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
+								RA = 1000 * RA / liters;
+								bicarbonate = wg_bicarbonate + RA;
+								total_alkalinity = bicarbonate * 50 / 61;
+								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+							}
+							break;
+					case 'CaCO3':   base = -protonDeficit * (f1d - f3d); //mmol totaal
+							base = base * MMCaCO3/1000; //gram
+							//but only 1/3 is effective, so add 3 times as much
+							base = 3 * base;
+							$("#wa_base").val(Math.round(base * 100) / 100);
+							setWaterAgent(BT, Math.round(base * 100) / 100);
+							if (liters > 0) {
+								//Bicarbonate
+								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
+								RA = 1000 * RA / liters;
+								bicarbonate = wg_bicarbonate + RA;
+								total_alkalinity = bicarbonate * 50 / 61;
+								//Ca precipitates out as Ca10(PO4)6(OH)2
+								RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
+								     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
+								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
+								RA = 1000 * RA / liters;
+								calcium = wg_calcium + RA;
+								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+							}
+							break;
+					case 'Ca(OH)2': base = -protonDeficit / 19.3; // g
+							$("#wa_base").val(Math.round(base * 100) / 100);
+							setWaterAgent(BT, Math.round(base * 100) / 100);
+							if (liters > 0) {
+								// Bicarbonate
+								RA = -protonDeficit / liters;
+								total_alkalinity = wg_total_alkalinity + RA;
+								bicarbonate = total_alkalinity * 61 / 50;
+								// Calcium
+								RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
+								parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
+								parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaOH2;
+								RA = 1000 * RA / liters;
+								calcium = wg_calcium + RA;
+								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+							}
+							break;
+				}
+			}
+			ph = TpH;
+			$('#wb_ph').val(Math.round(ph * 10) / 10);
+		} else { // Manual
+			console.log("calc_acid no");
+			// First add base salts
+			if (parseFloat($("#wa_base").jqxNumberInput('decimal')) > 0) {
+				if (liters > 0) {
+					switch (BT) {
+						case 'NaHCO3':  // Na
+							        RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
+								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
+								RA = 1000 * RA / liters;
+								sodium = wg_sodium + RA;
+								// HCO3
+								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
+								RA = 1000 * RA / liters;
+								bicarbonate = wg_bicarbonate + RA;
+								total_alkalinity = bicarbonate * 50 / 61;
+								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+								break;
+						case 'Na2CO3':  RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
+								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
+								RA = 1000 * RA / liters;
+								sodium = wg_sodium + RA;
+								// HCO3
+								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
+								RA = 1000 * RA / liters;
+								bicarbonate = wg_bicarbonate + RA;
+								total_alkalinity = bicarbonate * 50 / 61;
+								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+								break;
+						case 'CaCO3':   // Bicarbonate
+								RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
+								RA = 1000 * RA / liters;
+								bicarbonate = wg_bicarbonate + RA;
+								total_alkalinity = bicarbonate * 50 / 61;
+								RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+								// Ca
+								RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
+								     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
+								     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
+								RA = 1000 * RA / liters;
+								calcium = wg_calcium + RA;
+								break;
+					}
+				}
+			}
 
-			case 'Fosforzuur':      pK1 = 2.12;
-						pK2 = 7.20;
-						pK3 =  12.44;
-						MolWt = 98.00;
-						AcidSG = 1170; //@25%
-						AcidPrc = 0.25;
-						//frac = CalcFrac(TpH, pK1, pK2, pK3);
-						Acidmg = acid_amount * acid_perc / 100 * AcidSG / liters;
-						acid += Acidmg / MolWt * frac; //mEq/l
-						break;
+			TpH = parseFloat(dataRecord.mash_ph);
+			pHa = MashpH(); // This one is in demi water, should be in adjusted water???
+			// Then calculate the new pH with added acids
+			if (parseFloat($("#wa_acid").jqxNumberInput('decimal')) > 0) {
+				console.log("TpH: "+TpH+" water: "+pHa);
+				Acid = parseFloat($("#wa_acid").jqxNumberInput('decimal'));
+				if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0)
+					$("#wa_acid_perc").val(AcidPrc);
+				Acid = Acid / AcidPrc * (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
+				Acid *= AcidSG; // ml
+				Acid /= MolWt;  // mg
+				Acidmg = Acid;
+
+				//find the pH where the protondeficit = protondeficit by the acid
+				frac = CalcFrac(pHa, pK1, pK2, pK3);
+				protonDeficit = Acid * frac;
 
-			case 'Zwavelzuur':      pK1 = -10;
-						pK2 = 1.92;
-						pK3 = 20;
-						MolWt = 98.07;
-						AcidSG = 1700; //@93%
-						AcidPrc = 0.93;
-						//frac = CalcFrac(TpH, pK1, pK2, pK3);
-						Acidmg = acid_amount * acid_perc / 100 * AcidSG / liters;
-						acid += Acidmg / MolWt * frac; //mEq/l
-						sulfate += Acidmg / 1000 * MMSO4 / (MMSO4 + 2);
-						break;
+				deltapH = 0.001;
+				deltapd = 0.1;
+				pd = ProtonDeficit(pHa);
+				n = 0;
+				while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 2000)) {
+					n++;
+					if (pd < (protonDeficit-deltapd))
+						pHa -= deltapH;
+					else if (pd > (protonDeficit+deltapd))
+						pHa += deltapH;
+					frac = CalcFrac(pHa, pK1, pK2, pK3);
+					protonDeficit = Acid * frac;
+					pd = ProtonDeficit(pHa);
+				}
+				console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa);
+				RA = wg_bicarbonate - protonDeficit * frac / liters;
+				bicarbonate = RA;
+				total_alkalinity = RA * 50 / 61;
+				ph = pHa;
+				$('#wb_ph').val(Math.round(ph * 10) / 10);
+			}
 		}
-		//protonDeficit = ProtonDeficit(TpH);
-		//console.log("frac: "+frac+"  acid: "+acid+"  protonDeficit: "+protonDeficit);
-		//total_alkalinity -= 50 / 61 * protonDeficit * frac / liters;
+
+		if ((AT == 'Zwavelzuur') && (liters > 0)) {
+			RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
+			     parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 +
+			     Acidmg / 1000 * MMSO4 / (MMSO4 + 2);
+			RA = 1000 * RA / liters;
+			sulfate = wg_sulfate + RA;      // Not add to sulfate??
+		} else if ((AT == 'Zoutzuur') && (liters > 0)) {
+			RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
+			     parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl +
+			     Acidmg / 1000 * MMCl / (MMCL + 1);
+			RA = 1000 * RA / liters;
+			chloride = wg_chloride + RA;
+		}
+
+		// 2:1 Sulfate to Chroride IPA's, Pale Ales.
+		// 1:1 Sulfate to Chloride Balanced
+		// 1:2 Sulfate to Chloride Malty
+		$('#tgt_bu').val(Math.round(GetBUGU() * 100) / 100);
+		$('#tgt_cl_so4').val(Math.round(GetOptClSO4ratio() * 10) / 10); // Show real value too
+		if (sulfate > 0)
+			RA = chloride / sulfate;
+		else
+			RA = 10;
+		var piCLSO4_low = 0.8 * GetOptClSO4ratio();
+		var piCLSO4_high = 1.2 * GetOptClSO4ratio();
+		console.log("low: "+piCLSO4_low+" val: "+RA+" high: "+piCLSO4_high);
 
 		$('#wb_calcium').val(Math.round(calcium * 10) / 10);
 		$('#wb_magnesium').val(Math.round(magnesium * 10) / 10);
@@ -544,6 +880,105 @@
 		} else {
 			setRangeIndicator("sulfate", "high");
 		}
+		if (ph < 5.2) {
+			setRangeIndicator("ph", "low");
+		} else if (ph > 5.6) {
+			setRangeIndicator("ph", "high");
+		} else {
+			setRangeIndicator("ph", "normal");
+		}
+		calcSparge();
+	}
+
+	function calcSparge() {
+
+		// Code from BrewBuddy/Brouwhulp, who got it from http://www.brewery.org/brewery/library/Acidi0,00fWaterAJD0497.html
+		var TargetpH = dataRecord.sparge_ph;
+		var Source_pH = dataRecord.w1_ph;
+		var Source_alkalinity = dataRecord.w1_total_alkalinity;
+		// Select watersource or fallback to the first source.
+		if (dataRecord.sparge_source == 'Bron 2') {
+			if (dataRecord.w2_ph > 0.0) {
+				Source_pH = dataRecord.w2_ph;
+				Source_alkalinity = dataRecord.w2_total_alkalinity;
+			} else {
+				dataRecord.sparge_source = 'Bron 1';
+				$("#sparge_source").val('Bron 1');
+			}
+		} else if (dataRecord.sparge_source == 'Gemengd') {
+			if (dataRecord.w2_ph > 0.0) {
+				Source_pH = parseFloat($("#wg_ph").jqxNumberInput('decimal'));
+				Source_alkalinity = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal'));
+			} else {
+				dataRecord.sparge_source = 'Bron 1';
+				$("#sparge_source").val('Bron 1');
+			}
+		}
+
+		console.log("calcSparge() target pH: "+TargetpH+" Source: "+Source_pH+" alkalinity: "+Source_alkalinity);
+
+		// Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH
+		r1 = Math.pow(10, Source_pH - 6.38);
+		r2 = Math.pow(10, Source_pH - 10.33);
+		d = 1 + r1 + r1*r2;
+		f1 = 1/d;
+		f2 = r1/d;
+		f3 = r1 * r2 / d;
+
+		//Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity)
+		r143 = Math.pow(10, 4.3 - 6.38);
+		r243 = Math.pow(10, 4.3 - 10.33);
+		d43 = 1 + r143 + r143*r243;
+		f143 = 1/d43;
+		f243 = r143 / d43;
+		f343 = r143 * r243 / d43;
+
+		//Step 3. Convert the sample alkalinity to milliequivalents/L
+		alkalinity = Source_alkalinity / 50;
+		//Step 4. Solve
+		alkalinity = alkalinity / ((f143-f1)+(f3-f343));
+
+		//Step 5. Compute mole fractions at desired pH
+		r1g = Math.pow(10, TargetpH - 6.38);
+		r2g = Math.pow(10, TargetpH - 10.33);
+		dg = 1 + r1g + r1g*r2g;
+		f1g = 1/dg;
+		f2g = r1g / dg;
+		f3g = r1g * r2g / dg;
+
+		//Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
+		Acid = alkalinity * ((f1g-f1)+(f3-f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH);  //mEq/l
+
+		if ($("#sparge_acid_type").val() == "") {
+			$("#sparge_acid_type").val('Melkzuur');
+			dataRecord.sparge_acid_type = 'Melkzuur';
+		}
+		AT = dataRecord.sparge_acid_type;
+		var result = GetAcidSpecs(AT);
+		pK1 = result.pK1;
+		pK2 = result.pK2;
+		pK3 = result.pK3;
+		MolWt = result.MolWt;
+		AcidSG = result.AcidSG;
+		AcidPrc = result.AcidPrc;
+		fract = CalcFrac(TargetpH, pK1, pK2, 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 *= MolWt; //mg
+
+		Acid = Acid / AcidSG; //ml ; 88% lactic solution
+		f1 = dataRecord.sparge_acid_perc;
+		if (f1 <= 0.1)
+			f1 = AcidPrc;
+		Acid = Acid * AcidPrc / (f1 / 100);
+
+		Acid *= dataRecord.sparge_volume; //ml lactic acid total
+		Acid = Math.round(Acid * 100) / 100;
+		dataRecord.sparge_acid_amount = Acid / 1000;
+		$("#sparge_acid_amount").val(Acid);
 	}
 
 	function calcInit () {
@@ -552,6 +987,14 @@
 		calcSGendMash();
 		calcMashEfficiency();
 
+		$("#calc_acid").on('checked', function (event) {
+			dataRecord.calc_acid = true;
+			calcWater();
+		});
+		$("#calc_acid").on('unchecked', function (event) {
+			dataRecord.calc_acid = false;
+			calcWater();
+		});
 		$("#w1_name").jqxDropDownList('selectItem', dataRecord.w1_name);
 		$("#w2_name").jqxDropDownList('selectItem', dataRecord.w2_name);
 		// Fix tap water if zero using mash infuse amount.
@@ -664,9 +1107,30 @@
 		});
 		$('#mash_ph').on('change', function (event) {
 			dataRecord.mash_ph = parseFloat(event.args.value);
-			$("#tgt_mash_ph").val(parseFloat(event.args.value));
 			calcWater();
 		});
+
+		$('#sparge_ph').on('change', function (event) {
+			dataRecord.sparge_ph = parseFloat(event.args.value);
+			calcSparge();
+		});
+		$('#sparge_volume').on('change', function (event) {
+			dataRecord.sparge_volume = parseFloat(event.args.value);
+			calcSparge();
+		});
+		$('#sparge_source').on('change', function (event) {
+			dataRecord.sparge_source= event.args.item.value;
+			calcSparge();
+		});
+		$('#sparge_acid_type').on('change', function (event) {
+			dataRecord.sparge_acid_type = event.args.item.value;
+			console.log("new sparge_acid_type: "+dataRecord.sparge_acid_type);
+			calcSparge();
+		});
+		$('#sparge_acid_perc').on('change', function (event) {
+			dataRecord.sparge_acid_perc = parseFloat(event.args.value);
+			calcSparge();
+		});
 	};
 
 	$("#styleSelect").jqxDropDownList({
@@ -858,6 +1322,7 @@
 	$("#st_abv_max").jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'});
 	$("#st_carb_min").jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'});
 	$("#st_carb_max").jqxTooltip({ content: 'Het maximum koolzuur volume voor deze bierstijl.'});
+	$("#mash_ph").jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'});
 	$("#wa_cacl2").jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.'});
 	$("#wa_caso4").jqxTooltip({ content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.'});
 	$("#wa_mgso4").jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!'});
@@ -1005,6 +1470,7 @@
 			{ name: 'sparge_temp', type: 'float' },
 			{ name: 'sparge_ph', type: 'float' },
 			{ name: 'sparge_volume', type: 'float' },
+			{ name: 'sparge_source', type: 'string' },
 			{ name: 'sparge_acid_type', type: 'string' },
 			{ name: 'sparge_acid_perc', type: 'float' },
 			{ name: 'sparge_acid_amount', type: 'float' },
@@ -1152,13 +1618,13 @@
 			$("#est_carb").val(dataRecord.est_carb);
 			$("#mash_name").val(dataRecord.mash_name);
 			$("#mash_ph").val(dataRecord.mash_ph);
-			$("#tgt_mash_ph").val(dataRecord.mash_ph);
 			$("#sparge_temp").val(dataRecord.sparge_temp);
 			$("#sparge_ph").val(dataRecord.sparge_ph);
 			$("#sparge_volume").val(dataRecord.sparge_volume);
+			$("#sparge_source").val(dataRecord.sparge_source);
 			$("#sparge_acid_type").val(dataRecord.sparge_acid_type);
 			$("#sparge_acid_perc").val(dataRecord.sparge_acid_perc);
-			$("#sparge_acid_amount").val(dataRecord.sparge_acid_amount);
+			$("#sparge_acid_amount").val(dataRecord.sparge_acid_amount * 1000);
 			$("#calc_acid").val(dataRecord.calc_acid);
 			$("#w1_name").val(dataRecord.w1_name);
 			$("#w1_amount").val(dataRecord.w1_amount);
@@ -2310,6 +2776,7 @@
         var srcIBU = [ "Tinseth", "Rager", "Daniels" ]; // Only these are supported at this time.
         var srcBase = [ "NaHCO3", "Na2CO3", "CaCO3", "Ca(OH)2" ];
         var srcAcid = [ "Melkzuur", "Zoutzuur", "Fosforzuur", "Zwavelzuur" ];
+	var srcSource = [ "Bron 1", "Bron 2", "Gemengd" ];
 	var srcMaterial= [ "RVS", "Aluminium", "Kunststof", "Koper" ];
 	var srcAeration= [ 'None', 'Air', 'Oxygen' ];
 	var srcCooling= [ '-', 'Emersion chiller', 'Counterflow chiller', 'Au bain marie', 'Natural' ];
@@ -2438,8 +2905,6 @@
 
 	$("#mash_name").jqxInput({ theme: theme, width: 320, height: 23 });
 	$("#mash_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 4, max: 8, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#tgt_mash_ph").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 1, readOnly: true });
-	$("#sparge_temp").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 70, max: 98, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
 
 	$("#est_mash_sg").jqxNumberInput({ inputMode: 'simple', readOnly: true, theme: theme, width: 70, height: 23, decimalDigits: 3 });
 
@@ -2582,21 +3047,29 @@
         $("#pr_total_alkalinity").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
         $("#pr_chloride").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
         $("#pr_sulfate").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
-        $("#wa_cacl2").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
-        $("#wa_caso4").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
-        $("#wa_mgso4").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
-        $("#wa_nacl").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
+
+	$("#tgt_bu").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 2, readOnly: true });
+	$("#tgt_cl_so4").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 74, height: 23, decimalDigits: 1, readOnly: true });
+
+        $("#wa_cacl2").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, max: 1000, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
+        $("#wa_caso4").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, max: 1000, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
+        $("#wa_mgso4").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, max: 1000, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
+        $("#wa_nacl").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, max: 1000, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1, symbol: ' gr', symbolPosition: 'right' });
 
         $("#calc_acid").jqxCheckBox({ theme: theme, width: 120, height: 23 });
-        $("#wa_base_name").jqxDropDownList({ theme: theme, source: srcBase, width: 125, height: 23, dropDownHeight: 128 });
+        $("#wa_base_name").jqxDropDownList({ theme: theme, source: srcBase, width: 100, height: 23, dropDownHeight: 128 });
         $("#wa_base").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, decimalDigits: 2, spinButtons: true, spinButtonsStep: 0.05, symbol: ' gr', symbolPosition: 'right' });
-        $("#wa_acid_name").jqxDropDownList({ theme: theme, source: srcAcid, width: 125, height: 23, dropDownHeight: 128 })
+        $("#wa_acid_name").jqxDropDownList({ theme: theme, source: srcAcid, width: 100, height: 23, dropDownHeight: 128 })
         $("#wa_acid").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 0, decimalDigits: 2, spinButtons: true, spinButtonsStep: 0.05, symbol: ' ml', symbolPosition: 'right' });
         $("#wa_acid_perc").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 80, height: 23, min: 0, max: 100, decimalDigits: 0, spinButtons: true, symbol: '%', symbolPosition: 'right' });
 
+	$("#sparge_temp").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 70, max: 98, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
         $("#sparge_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-        $("#sparge_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-        $("#sparge_acid_amount").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 5, readOnly: true });
+        $("#sparge_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 4.5, max: 6.5, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
+        $("#sparge_source").jqxDropDownList({ theme: theme, source: srcSource, width: 100, height: 23, dropDownHeight: 95 });
+	$("#sparge_acid_amount").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 2, readOnly: true, symbol: ' ml', symbolPosition: 'right' });
+	$("#sparge_acid_type").jqxDropDownList({ theme: theme, source: srcAcid, width: 100, height: 23, dropDownHeight: 128 });
+	$("#sparge_acid_perc").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, spinButtons: true, decimalDigits: 0, symbol: '%', symbolPosition: 'right' });
 
 	$('#jqxTabs').jqxTabs({
 		theme: theme,
@@ -2721,9 +3194,10 @@
 			sparge_temp: parseFloat($("#sparge_temp").jqxNumberInput('decimal')),
 			sparge_ph: parseFloat($("#sparge_ph").jqxNumberInput('decimal')),
 			sparge_volume: parseFloat($("#sparge_volume").jqxNumberInput('decimal')),
-		//      sparge_acid_type: $("#sparge_acid_type").val(),
-		//      sparge_acid_perc: parseFloat($("#sparge_acid_perc").jqxNumberInput('decimal')),
-		//      sparge_acid_amount: parseFloat($("#sparge_acid_amount").jqxNumberInput('decimal')),
+			sparge_source: $("#sparge_source").val(),
+			sparge_acid_type: $("#sparge_acid_type").val(),
+			sparge_acid_perc: parseFloat($("#sparge_acid_perc").jqxNumberInput('decimal')),
+			sparge_acid_amount: dataRecord.sparge_acid_amount,
 			calc_acid: $("#calc_acid").val(),
 			w1_name: $("#w1_name").val(),
 			w1_amount: parseFloat($("#w1_amount").jqxNumberInput('decimal')),
--- a/www/js/rec_edit.js	Sun Dec 30 22:01:27 2018 +0100
+++ b/www/js/rec_edit.js	Mon Dec 31 14:41:08 2018 +0100
@@ -2633,7 +2633,7 @@
 
 	$("#sparge_temp").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 70, max: 98, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5 });
 	$("#sparge_volume").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
-	$("#sparge_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
+	$("#sparge_ph").jqxNumberInput({ inputMode: 'simple', spinMode: 'simple', theme: theme, width: 100, height: 23, min: 4.5, max: 6.5, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.1 });
 	$("#sparge_source").jqxDropDownList({ theme: theme, source: srcSource, width: 100, height: 23, dropDownHeight: 95 });
 	$("#sparge_acid_amount").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 100, height: 23, decimalDigits: 2, readOnly: true, symbol: ' ml', symbolPosition: 'right' });
 	$("#sparge_acid_type").jqxDropDownList({ theme: theme, source: srcAcid, width: 100, height: 23, dropDownHeight: 128 });
--- a/www/prod_edit.php	Sun Dec 30 22:01:27 2018 +0100
+++ b/www/prod_edit.php	Mon Dec 31 14:41:08 2018 +0100
@@ -270,11 +270,7 @@
       <table style="width: 100%;">
        <tr>
         <td style="vertical-align: top; float: right; padding: 3px;">Maischchema:</td>
-        <td align="left" style="vertical-align: top; padding: 3px;"><input id="mash_name" /></td>
-        <td style="vertical-align: top; float: right; padding: 3px;">Maish pH:</td>
-        <td style="padding: 3px;"><div id="mash_ph"></div></td>
-        <td style="vertical-align: top; float: right; padding: 3px;">Spoelwater temp:</td>
-        <td style="padding: 3px;"><div id="sparge_temp"></div></td>
+        <td align="left" colspan="5" style="vertical-align: top; padding: 3px;"><input id="mash_name" /></td>
        </tr>
        <tr>
         <td align="right" style="vertical-align: top; padding: 3px;">Stappen:</td>
@@ -289,11 +285,9 @@
       <table style="width: 100%;">
        <tr>
         <td style="vertical-align: top; float: right; padding: 3px;">Bitterheidsindex:</td>
-        <td style="padding: 3px;"><div id="tgt_bu"></div></td>
+        <td style="padding: 3px;" colspan="2"><div id="tgt_bu"></div></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Richtgetal Cl/SO4:</td>
-        <td style="padding: 3px;"><div id="tgt_cl_so4"></div></td>
-        <td style="vertical-align: top; float: right; padding: 3px;">Doel maisch pH:</td>
-        <td style="padding: 3px;"><div id="tgt_mash_ph"></div></td>
+        <td style="padding: 3px;" colspan="2"><div id="tgt_cl_so4"></div></td>
        </tr>
        <tr>
         <td></td>
@@ -384,38 +378,49 @@
        </tr>
        <tr>
         <td style="vertical-align: top; float: right; padding: 3px;">Calciumchloride (CaCl2):</td>
-        <td style="padding: 3px;"><div id="wa_cacl2"></div></td>
-        <td style="vertical-align: top; float: right; padding: 3px;">Automatisch pH aanpassen:</td>
-        <td style="padding: 3px;"><div id="calc_acid"></div></td>
+	<td style="padding: 3px;"><div id="wa_cacl2"></div></td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Maish pH:</td>
+        <td style="padding: 3px;"><div id="mash_ph"></div></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Spoelwater volume:</td>
         <td style="padding: 3px;"><div id="sparge_volume"></div></td>
        </tr>
        <tr>
         <td style="vertical-align: top; float: right; padding: 3px;">Gips (CaSO4):</td>
-        <td style="padding: 3px;"><div id="wa_caso4"></div></td>
+	<td style="padding: 3px;"><div id="wa_caso4"></div></td>
+        <td style="vertical-align: top; float: right; padding: 3px;">pH Automatisch:</td>
+        <td style="padding: 3px;"><div id="calc_acid"></div></td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Spoelwater temp:</td>
+        <td style="padding: 3px;"><div id="sparge_temp"></div></td>
+       </tr>
+       <tr>
+        <td style="vertical-align: top; float: right; padding: 3px;">Epsom zout (MgSO4):</td>
+	<td style="padding: 3px;"><div id="wa_mgso4"></div></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Ontzuren met:</td>
         <td style="padding: 3px;"><div style="float: left;" id="wa_base_name"></div><div style="float: left; margin-left: 15px;" id="wa_base"></div></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Spoelwater bron:</td>
         <td style="padding: 3px;"><div id="sparge_source"></div></td>
        </tr>
        <tr>
-        <td style="vertical-align: top; float: right; padding: 3px;">Epsom zout (MgSO4):</td>
-        <td style="padding: 3px;"><div id="wa_mgso4"></div></td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Keukenzout (NaCl):</td>
+	<td style="padding: 3px;"><div id="wa_nacl"></div></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Aanzuren met:</td>
         <td style="padding: 3px;"><div style="float: left;" id="wa_acid_name"></div><div style="float: left; margin-left: 15px;" id="wa_acid"></div><div style="float: left; margin-left: 15px;" id="wa_acid_perc"></div></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Spoelwater pH:</td>
         <td style="padding: 3px;"><div id="sparge_ph"></div></td>
        </tr>
        <tr>
-        <td style="vertical-align: top; float: right; padding: 3px;">Keukenzout (NaCl):</td>
-        <td style="padding: 3px;"><div id="wa_nacl"></div></td>
-        <td colspan="2"></td>
+         <td colspan="4"></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Aanzuren met:</td>
         <td style="padding: 3px;"><div id="sparge_acid_type"></div></td>
        </tr>
        <tr>
         <td colspan="4"></td>
-        <td style="vertical-align: top; float: right; padding: 3px;">Aanzuren hoeveelheid:</td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Percentage:</td>
+        <td style="padding: 3px;"><div id="sparge_acid_perc"></div></td>
+       </tr>
+       <tr>
+        <td colspan="4"></td>
+        <td style="vertical-align: top; float: right; padding: 3px;">Hoeveelheid:</td>
         <td style="padding: 3px;"><div id="sparge_acid_amount"></div></td>
        </tr>
       </table>

mercurial