# HG changeset patch # User Michiel Broek # Date 1545946226 -3600 # Node ID ef298b5aa994acb353f50066a2c6ad2ca26fb4a2 # Parent 15fe253ffa83aebb5527028fbfe9f3c38ce22b0c Added f_acid_to_ph_57 to the fermentables json in the recipes. The protonDeficit now processes the grist. Water pH calculations are partly in place. Added simple BU and Cl/So4 indicators. Redesign of the water screen. diff -r 15fe253ffa83 -r ef298b5aa994 www/import/from_brouwhulp.php --- a/www/import/from_brouwhulp.php Tue Dec 25 15:06:39 2018 +0100 +++ b/www/import/from_brouwhulp.php Thu Dec 27 22:30:26 2018 +0100 @@ -583,6 +583,10 @@ $fermentables .= ',"f_di_ph":' . floatval($fermentable->DI_pH); else $fermentables .= ',"f_di_ph":0.0'; + if ($fermentable->{'ACID_TO_pH_5.7'}) + $fermentables .= ',"f_acid_to_ph_57":' . floatval($fermentable->{'ACID_TO_pH_5.7'}); + else + $fermentables .= ',"f_acid_to_ph_57":0.0'; $fermentables .= "}"; /* Sugars */ $d = $famount * ($fyield / 100) * (1 - $fmoisture / 100); diff -r 15fe253ffa83 -r ef298b5aa994 www/includes/db_recipes.php --- a/www/includes/db_recipes.php Tue Dec 25 15:06:39 2018 +0100 +++ b/www/includes/db_recipes.php Thu Dec 27 22:30:26 2018 +0100 @@ -62,9 +62,9 @@ $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_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']; diff -r 15fe253ffa83 -r ef298b5aa994 www/js/rec_edit.js --- a/www/js/rec_edit.js Tue Dec 25 15:06:39 2018 +0100 +++ b/www/js/rec_edit.js Thu Dec 27 22:30:26 2018 +0100 @@ -198,6 +198,52 @@ } } +/* function GetBUGUMin() { + + var Result = 0; + + if (((dataRecord.st_og_max + dataRecord.st_og_min) > 0) && ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) > 0)) { + var G = (dataRecord.st_og_max - dataRecord.st_og_min) / ((dataRecord.st_og_max + dataRecord.st_og_min) / 2); + var B = (dataRecord.st_ibu_max - dataRecord.st_ibu_min) / ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) / 2); + if (G > B) + Result = ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) / 2) / (1000 * (dataRecord.st_og_max - 1)); + else + Result = dataRecord.st_ibu_min / (1000 * (((dataRecord.st_og_max + dataRecord.st_og_min) / 2) - 1)); + } + console.log("GetBUGUMin(): "+Result); + return Result; + } + + function GetBUGUMax() { + + var Result = 0; + + if (((dataRecord.st_og_max + dataRecord.st_og_min) > 0) && ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) > 0) && (dataRecord.st_og_min > 0)) { + var G = (dataRecord.st_og_max - dataRecord.st_og_min) / ((dataRecord.st_og_max + dataRecord.st_og_min) / 2); + var B = (dataRecord.st_ibu_max - dataRecord.st_ibu_min) / ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) / 2); + if (G > B) + Result = ((dataRecord.st_ibu_min + dataRecord.st_ibu_max) / 2) / (1000 * (dataRecord.st_og_min - 1)); + else + Result = dataRecord.st_ibu_max / (1000 * (((dataRecord.st_og_max + dataRecord.st_og_min) / 2) - 1)); + + } + console.log("GetBUGUMax(): "+Result); + return Result; + } */ + + 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'); @@ -281,9 +327,9 @@ } //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) - function ZAlkalinity(pHZ) { + function ZAlkalinity(pHZ, WpH) { var C43 = Charge(4.3); - var Cw = Charge(parseFloat(dataRecord.mash_ph)); + var Cw = Charge(WpH); var Cz = Charge(pHZ); var DeltaCNaught = -C43+Cw; var CT = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')) / 50 / DeltaCNaught; @@ -291,21 +337,108 @@ return CT * DeltaCZ; } - function ZRA(pHZ) { + //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, WpH) { var Calc = parseFloat($("#wg_calcium").jqxNumberInput('decimal')) / (MMCa / 2); var Magn = parseFloat($("#wg_magnesium").jqxNumberInput('decimal')) / (MMMg / 2); - var Z = ZAlkalinity(pHZ); + var Z = ZAlkalinity(pHZ, WpH); return Z - (Calc / 3.5 + Magn / 7); } function ProtonDeficit(pHZ) { - var Result = ZRA(pHZ) * parseFloat($("#wg_amount").jqxNumberInput('decimal')); - + var Result = ZRA(pHZ, parseFloat($("#wg_ph").jqxNumberInput('decimal'))) * parseFloat($("#wg_amount").jqxNumberInput('decimal')); + 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); + // console.log("formula C1: "+C1); + } else { + // If the acid_to_ph_5.7 is unknown from the malter, 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; + } + // console.log("Logic C1: "+C1); + } + x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH) + // console.log(row.f_name+" C1: "+C1+" ZpH: "+pHZ+" di_ph: "+row.f_di_ph+" acid rquired: "+x); + Result += x * row.f_amount; + } + } + // console.log("Final: "+Result); 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 < 1000)) { + n++; + if (pd < -deltapd) + pH -= deltapH; + else if (pd > deltapd) + pH += deltapH; + pd = ProtonDeficit(pH); + } + console.log("MashpH() n: "+n+" pH: "+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 + }; + } + } + + // Procedure TFrmWaterAdjustment.CalcWater2; function calcWater() { console.log("calcWater()"); @@ -314,6 +447,7 @@ var magnesium = 0; var sodium = 0; var total_alkalinity = 0; + var bicarbonate = 0; var chloride = 0; var sulfate = 0; var ph = 0; @@ -329,27 +463,30 @@ var AcidPrc = 0; var protonDeficit = 0; -// console.log((dataRecord.w1_name != "") + " " + (dataRecord.w2_name != "")); - 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; + } + // Check for a recipe too. Fermentables, Mash schedule? + + // 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); $('#wg_calcium').val(Math.round(calcium * 10) / 10); @@ -360,39 +497,211 @@ $('#wg_sulfate').val(Math.round(sulfate * 10) / 10); // Note: brouwhulp has the malts included here in the result. $('#wg_ph').val(Math.round(ph * 10) / 10); + $('#wb_ph').val(Math.round(ph * 10) / 10); + bicarbonate = total_alkalinity * 1.22; // 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')); + RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl; + 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. + 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; + console.log(AT+" pK1: "+pK1+" pK2: "+pK2+" pK3: "+pK3+" MolWt: "+MolWt+" AcidSG: "+AcidSG+" AcidPrc: "+AcidPrc); + + 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); + if ($("#wa_acid_name").val() == "") { + $("#wa_acid_name").val('Melkzuur'); + last_acid = 'Melkzuur'; + } + frac = CalcFrac(TpH, pK1, pK2, pK3); + Acid = protonDeficit / frac; + console.log("Required moles: "+Acid); + Acid *= MolWt; // mg + // Acidmg = Acid; + // console.log("Required mg: "+Acidmg); + 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); + + bicarbonate = bicarbonate - protonDeficit * frac / liters; + total_alkalinity = bicarbonate * 50 / 61; + } else if (protonDeficit < 0) { //Add base + $("#wa_acid").val(0); + setWaterAgent(last_acid, 0); + if ($("#wa_base_name").val() == "") { + $("#wa_base_name").val('NaHCO3'); + last_base = 'NaHCO3'; + } + 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 = parseFloat($('#wg_sodium').jqxNumberInput('decimal')) + RA; + // HCO3 + RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3; + RA = 1000 * RA / liters; + bicarbonate = (parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) * 1.22) + RA; + total_alkalinity = bicarbonate * 50 / 61; + } + 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 = parseFloat($('#wg_sodium').jqxNumberInput('decimal')) + RA; + // HCO3 + RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3; + RA = 1000 * RA / liters; + bicarbonate = (parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) * 1.22) + RA; + total_alkalinity = bicarbonate * 50 / 61; + } + 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 = (parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) * 1.22) + 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 = parseFloat($('#wg_calcium').jqxNumberInput('decimal')) + RA; + } + 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 = parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) + 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 = parseFloat($('#wg_calcium').jqxNumberInput('decimal')) + RA; + } + 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) { + + } + + TpH = parseFloat(dataRecord.mash_ph); + pHa = parseFloat($('#wg_ph').jqxNumberInput('decimal')); + //pHa = parseFloat(dataRecord.mash_ph); + // 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 = Acid * AcidSG; // ml + Acid = Acid / MolWt; // mg + + //find the pH where the protondeficit = protondeficit by the acid + frac = CalcFrac(pHa, pK1, pK2, pK3); + protonDeficit = Acid * frac; + + deltapH = 0.01; + deltapd = 0.1; + pd = ProtonDeficit(TpH); + n = 0; + console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa); + + while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 1000)) { + n++; + if (pd < (protonDeficit-deltapd)) + pHa = pHa - deltapH; + else if (pd > (protonDeficit+deltapd)) + pHa = 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); + } + console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa); + + } + } +/* 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); } var acid_amount = parseFloat($("#wa_acid").jqxNumberInput('decimal')); var acid_perc = parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')); @@ -443,9 +752,58 @@ sulfate += Acidmg / 1000 * MMSO4 / (MMSO4 + 2); break; } - protonDeficit = ProtonDeficit(TpH); - console.log("frac: "+frac+" acid: "+acid+" protonDeficit: "+protonDeficit); + + if (dataRecord.calc_acid) { + } else if (liters > 0) { // not calc_acid + // First add base salts + if (parseFloat($("#wa_base").jqxNumberInput('decimal')) > 0) { + + } + + pHa = parseFloat($("#wb_ph").jqxNumberInput('decimal')); + console.log("Adjusted water mash pH: "+pHa); + // Then calculate the new pH with added acids + if (parseFloat($("#wa_acid").jqxNumberInput('decimal')) > 0) { + acid = parseFloat($("#wa_acid").jqxNumberInput('decimal')); + if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0) + $("#wa_acid_perc").val(AcidPrc); + console.log("screen value: "+acid); + acid = acid / AcidPrc * (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml + console.log("acid ml: "+acid); + acid = acid * AcidSG // ml + console.log("acid ml: "+acid); + acid = acid / MolWt; // mg + console.log("acid mg: "+acid); + var Acidmg = acid; + + frac = CalcFrac(pHa, pK1, pK2, pK3); + protonDeficit = acid * frac; + + deltapH = 0.001; + deltapd = 0.1; + pd = ProtonDeficit(pHa); + n = 0; + console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa); + + while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 1000)) { + n++; + if (pd < (protonDeficit-deltapd)) + pHa = pHa - deltapH; + else if (pd > (protonDeficit+deltapd)) + pHa = 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); + } + console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa); + } + } total_alkalinity -= 50 / 61 * protonDeficit * frac / liters; + MashpH(); +*/ + $('#tgt_bu').val(Math.round(GetBUGU() * 100) / 100); + $('#tgt_cl_so4').val(Math.round(GetOptClSO4ratio() * 10) / 10); $('#wb_calcium').val(Math.round(calcium * 10) / 10); $('#wb_magnesium').val(Math.round(magnesium * 10) / 10); @@ -481,6 +839,13 @@ } else { setRangeIndicator("sulfate", "high"); } + if (ph < 5.2) { + setRangeIndicator("ph", "low"); + } else if (ph > 5.6) { + setRangeIndicator("ph", "high"); + } else { + setRangeIndicator("ph", "normal"); + } } function calcFermentablesFromOG(OG) { @@ -520,6 +885,14 @@ function calcInit () { console.log("calc.init()"); + $("#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. @@ -632,7 +1005,6 @@ }); $('#mash_ph').on('change', function (event) { dataRecord.mash_ph = parseFloat(event.args.value); - $("#tgt_mash_ph").val(parseFloat(event.args.value)); calcWater(); }); }; @@ -715,6 +1087,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!'}); @@ -847,7 +1220,6 @@ $("#st_carb_max").val(dataRecord.st_carb_max); $("#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); @@ -916,7 +1288,8 @@ { name: 'f_add_after_boil', type: 'bool' }, { name: 'f_adjust_to_total_100', type: 'bool' }, { name: 'f_percentage', type: 'float' }, - { name: 'f_di_ph', type: 'float' } + { name: 'f_di_ph', type: 'float' }, + { name: 'f_acid_to_ph_57', type: 'float' } ], addrow: function (rowid, rowdata, position, commit) { commit(true); @@ -998,6 +1371,7 @@ row["f_percentage"] = 0; } row["f_di_ph"] = datarecord.di_ph; + row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57; var commit = $("#fermentableGrid").jqxGrid('addrow', null, row); } }); @@ -2010,7 +2384,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 }); // Several gauges $("#hop_flavour").jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true }); @@ -2153,10 +2526,13 @@ $("#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 }); diff -r 15fe253ffa83 -r ef298b5aa994 www/rec_edit.php --- a/www/rec_edit.php Tue Dec 25 15:06:39 2018 +0100 +++ b/www/rec_edit.php Thu Dec 27 22:30:26 2018 +0100 @@ -173,11 +173,7 @@ - - - - - + @@ -192,11 +188,9 @@
Maischchema:Maish pH:
Spoelwater temp:
Stappen:
- + - - - + @@ -287,35 +281,40 @@ - - - + + + - + + + + + + + + + - - - - - - - - - + - + + + + + + + -
Bitterheidsindex:
Richtgetal Cl/SO4:
Doel maisch pH:
Calciumchloride (CaCl2):
Automatisch pH aanpassen:
Maish pH:
Spoelwater volume:
Gips (CaSO4):
pH Automatisch:
Spoelwater temp:
Epsom zout (MgSO4):
Ontzuren met:
Spoelwater bron:
Epsom zout (MgSO4):
Aanzuren met:
Spoelwater pH:
Keukenzout (NaCl):
Aanzuren met:
Spoelwater pH:
Aanzuren met:
Aanzuren hoeveelheid: