www/js/rec_edit.js

changeset 662
4bb005694ce7
parent 660
0e9a725354ac
child 667
1246550451ca
--- a/www/js/rec_edit.js	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/js/rec_edit.js	Fri May 01 11:56:24 2020 +0200
@@ -33,6 +33,7 @@
  last_acid = '',
  Ka1 = 0.0000004445,
  Ka2 = 0.0000000000468,
+ error_count = 0,
  MMCa = 40.048,
  MMMg = 24.305,
  MMNa = 22.98976928,
@@ -560,36 +561,45 @@
 }
 
 
+function BufferCapacity(di_ph, acid_to_ph_57, ebc, graintype) {
+ C1 = 0;
+ if ((di_ph != 5.7) && ((acid_to_ph_57 < - 0.1) || (acid_to_ph_57 > 0.1))) {
+  C1 = acid_to_ph_57 / (di_ph - 5.7);
+ } else {
+  // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid.
+  switch (graintype) {
+   case 0:                                 // Base, Special, Kilned
+   case 3:
+   case 5: C1 = 0.014 * ebc - 34.192;
+           break;
+   case 2: C1 = -0.0597 * ebc - 32.457;    // Crystal
+           break;
+   case 1: C1 = 0.0107 * ebc - 54.768;     // Roast
+           break;
+   case 4: C1 = -149;                      // Sour malt
+           break;
+  }
+ }
+ return C1;
+}
+
+
 function ProtonDeficit(pHZ) {
- var ebc, C1, i, rows, row, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal'));
+ var C1, i, rows, row, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal'));
  // proton deficit for the grist
- rows = $('#fermentableGrid').jqxGrid('getrows');
- for (i = 0; i < rows.length; i++) {
-  row = rows[i];
-  if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt
-   // Check if acid is required
-   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.
-    ebc = row.f_color;
-    switch (row.f_graintype) {
-     case 0:                              // Base, Special, Kilned
-     case 3:
-     case 5: C1 = 0.014 * ebc - 34.192;
-             break;
-     case 2: C1 = -0.0597 * ebc - 32.457; // Crystal
-             break;
-     case 1: C1 = 0.0107 * ebc - 54.768;  // Roast
-             break;
-     case 4: C1 = -149;                   // Sour malt
-             break;
-    }
+ if ((rows = $('#fermentableGrid').jqxGrid('getrows'))) {
+  for (i = 0; i < rows.length; i++) {
+   row = rows[i];
+   if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt
+    C1 = BufferCapacity(row.f_di_ph, row.f_acid_to_ph_57, row.f_color, row.f_graintype);
+    x = C1 * (pHZ - row.f_di_ph);   // AcidRequired(ZpH)
+    Result += x * row.f_amount;
    }
-   x = C1 * (pHZ - row.f_di_ph);   // AcidRequired(ZpH)
-   Result += x * row.f_amount;
   }
+ } else {
+  error_count++;
+  if (error_count < 5)
+   console.log('ProtonDeficit(' + pHZ + ') invalid grist, return ' + Result);
  }
  return Result;
 }
@@ -609,24 +619,12 @@
    pH += deltapH;
   pd = ProtonDeficit(pH);
  }
+ pH = Round(pH, 6);
  //console.log('MashpH() n: ' + n + ' pH: ' + pH);
  return pH;
 }
 
 
-function GetAcidSpecs(AT) {
- switch (AT) {
-  case 0: return { pK1: 3.86, pK2: 20, pK3: 20, MolWt: 90.08, AcidSG: 1214, AcidPrc: 0.88 }; // Melkzuur
-  case 1: return { pK1: -7, pK2: 20, pK3: 20, MolWt: 36.46, AcidSG: 1142, AcidPrc: 0.28 }; // Zoutzuur
-  case 2: return { pK1: 2.12, pK2: 7.20, pK3: 12.44, MolWt: 98.00, AcidSG: 1170, AcidPrc: 0.25 }; // Fosforzuur
-  case 3: return { pK1: -1, pK2: 1.92, pK3: 20, MolWt: 98.07, AcidSG: 1700, AcidPrc: 0.93 }; // Zwavelzuur
- }
-}
-
-
-
-
-
 
 
 $(document).ready(function() {
@@ -1899,11 +1897,10 @@
   frac = 0,
   TpH = 0,
   protonDeficit = 0,
-  AT, BT, result, pK1, pK2, pK3, MolWt, AcidSG, AcidPrc,
+  AT, BT,
   r1d, r2d, f1d, f2d, f3d,
   deltapH, deltapd, pd, n,
-  Res,
-  wg_calcium, wg_sodium, wg_total_alkalinity, wg_chloride, wg_sulfate, wg_bicarbonate;
+  Res;
 
   if (dataRecord.w1_name == '') {
    return;
@@ -1929,269 +1926,248 @@
    total_alkalinity = dataRecord.w1_total_alkalinity;
    ph = dataRecord.w1_ph;
   }
-  $('#wg_amount').val(liters);
-  wg_calcium = calcium;
-  $('#wg_calcium').val(Math.round(calcium * 10) / 10);
-  //wg_magnesium = magnesium;
-  $('#wg_magnesium').val(Math.round(magnesium * 10) / 10);
-  wg_sodium = sodium;
-  $('#wg_sodium').val(Math.round(sodium * 10) / 10);
-  wg_total_alkalinity = total_alkalinity;
-  $('#wg_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10);
-  wg_chloride = chloride;
-  $('#wg_chloride').val(Math.round(chloride * 10) / 10);
-  wg_sulfate = sulfate;
-  $('#wg_sulfate').val(Math.round(sulfate * 10) / 10);
-  // Note: brouwhulp has the malts included here in the result.
-  //wg_ph = ph;
-  $('#wg_ph').val(Round(ph, 1));
-  $('#wb_ph').val(Round(MashpH(), 1));
-  bicarbonate = total_alkalinity * 1.22;
-  wg_bicarbonate = bicarbonate;
+  var bicarbonate = total_alkalinity * 1.22;
+
+  /* Save mixed water ions for later */
+  var wg_calcium = calcium;
+  var wg_sodium = sodium;
+  var wg_total_alkalinity = total_alkalinity;
+  var wg_chloride = chloride;
+  var wg_sulfate = sulfate;
+  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 / liters;
+  $('#wg_amount').val(liters);
+  $('#wg_calcium').val(Math.round(calcium * 10) / 10);
+  $('#wg_magnesium').val(Math.round(magnesium * 10) / 10);
+  $('#wg_sodium').val(Math.round(sodium * 10) / 10);
+  $('#wg_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10);
+  $('#wg_chloride').val(Math.round(chloride * 10) / 10);
+  $('#wg_sulfate').val(Math.round(sulfate * 10) / 10);
+  $('#wg_ph').val(Round(ph, 1));
 
-  // Calculate Mg
-  RA = parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4;
-  magnesium += 1000 * RA / liters;
+  var mash_ph = Round(MashpH(), 3);
+  console.log('Distilled water mash pH: ' + mash_ph);
 
-  // Calculate Na
-  RA = parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl;
-  sodium += 1000 * RA / liters;
+  /* Calculate Salt additions */
+  if (liters > 0) {
+   calcium += (parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 +
+    parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000) / liters;
+   magnesium += (parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000) / liters;
+   sodium += (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 +
+    parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters;
+   sulfate += (parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 +
+    parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / liters;
+   chloride += (2 * parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 +
+    parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000) / liters;
+  }
 
-  // Calculate SO4
-  RA = parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
-       parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4;
-  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 / liters;
-  // Einde noot.
-
-  if ($('#wa_acid_name').val() < 0 || $('#wa_acid_name').val() > 3) {
+  if (dataRecord.wa_acid_name < 0 || dataRecord,wa_acid_name >= AcidTypeData.length) {
    $('#wa_acid_name').val(0);
    dataRecord.wa_acid_name = 0;
+   dataRecord.wa_acid_perc = AcidTypeData[0].AcidPrc;
+   $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc);
   }
   if (last_acid == '')
-   last_acid = AcidTypeData[$('#wa_acid_name').val()].nl;
+   last_acid = AcidTypeData[dataRecord.wa_acid_name].nl;
 
-  if ($('#wa_base_name').val() < 0 || $('#wa_base_name').val() > 3) {
+  if (parseFloat(dataRecord.wa_acid_perc) == 0) {
+   dataRecord.wa_acid_perc = AcidTypeData[AT].AcidPrc;
+   $('#wa_acid_perc').val(AcidTypeData[AT].AcidPrc);
+  }
+
+  if (dataRecord.wa_base_name < 0 || dataRecord.wa_base_name > 3) {
    $('#wa_base_name').val(0);
    dataRecord.wa_base_name = 0;
   }
   if (last_base == '')
-   last_base = BaseTypeData[$('#wa_base_name').val()].nl;
+   last_base = BaseTypeData[dataRecord.wa_base_name].nl;
 
   AT = dataRecord.wa_acid_name;
   BT = dataRecord.wa_base_name;
 
-  result = GetAcidSpecs(AT);
-  pK1 = result.pK1;
-  pK2 = result.pK2;
-  pK3 = result.pK3;
-  MolWt = result.MolWt;
-  AcidSG = result.AcidSG;
-  AcidPrc = result.AcidPrc;
+  /* Note that the next calculations do not correct the pH change by the added salts.
+     This pH change is at most 0.1 pH and is a minor difference in Acid amount. */
 
   if (dataRecord.calc_acid) {
+   $('.c_mashph').show();
+   /* Auto calculate pH */
    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);
+    frac = CalcFrac(TpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3);
     Acid = protonDeficit / frac;
-    Acid *= MolWt; // mg
+    Acid *= AcidTypeData[AT].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(AcidTypeData[AT].nl, Math.round(Acid * 100) / 100);
+    Acid = Acid / AcidTypeData[AT].AcidSG; // ml
+    Acid = Round(Acid / (parseFloat(dataRecord.wa_acid_perc) / 100), 2); // ml
+    console.log('Mash auto Acid final ml: ' + Acid);
+    $('#wa_acid').val(Acid);
+    setWaterAgent(AcidTypeData[AT].nl, Acid);
 
     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));
+    r1d = Math.pow(10, (TpH - 6.35));
+    r2d = Math.pow(10, (TpH - 10.33));
     f1d = 1 / (1 + r1d + r1d * r2d);
     f2d = f1d * r1d;
     f3d = f2d * r2d;
     switch (BT) {
-     case 0: RA = -protonDeficit / (f1d - f3d); //Sodiumbicarbonate, mmol totaal
-             RA = RA * MMNaHCO3 / 1000; //gram
-             $('#wa_base').val(Round(RA, 2));
-             setWaterAgent('NaHCO3', Round(RA, 2));
-             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 1: RA = -protonDeficit / (2 * f1d + f2d); // Sodiumcarbonate, mmol totaal
-             RA = RA * MMNa2CO3 / 1000; //gram
-             $('#wa_base').val(Round(RA, 2));
-             setWaterAgent('Na2CO3', Round(RA, 2));
-             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 2: RA = -protonDeficit * (f1d - f3d); // Calciumcarbonate, mmol totaal
-             RA = RA * MMCaCO3 / 1000; //gram
-             //but only 1/3 is effective, so add 3 times as much
-             RA = 3 * RA;
-             $('#wa_base').val(Round(RA, 2));
-             setWaterAgent('CaCO3', Round(RA, 2));
-             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 3: RA = -protonDeficit / 19.3; // Calciumhydroxide
-             $('#wa_base').val(Round(RA, 2));
-             setWaterAgent('Ca(OH)2', Round(RA, 2));
-             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;
+     case 0:
+      RA = -protonDeficit / (f1d - f3d); //Sodiumbicarbonate, mmol totaal
+      RA = RA * MMNaHCO3 / 1000; //gram
+      $('#wa_base').val(Round(RA, 2));
+      setWaterAgent('NaHCO3', Round(RA, 2));
+      if (liters > 0) {
+       // Na
+       RA = (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 +
+             parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters;
+       sodium = wg_sodium + RA;
+       // HCO3
+       RA = (parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3 * 1000) / liters;
+       bicarbonate = wg_bicarbonate + RA;
+       total_alkalinity = bicarbonate * 50 / 61;
+       RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+      }
+      break;
+     case 1:
+      RA = -protonDeficit / (2 * f1d + f2d); // Sodiumcarbonate, mmol totaal
+      RA = RA * MMNa2CO3 / 1000; //gram
+      $('#wa_base').val(Round(RA, 2));
+      setWaterAgent('Na2CO3', Round(RA, 2));
+      if (liters > 0) {
+       RA = (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 +
+             parseFloat($('#wa_base').jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3 * 1000) / liters;
+       sodium = wg_sodium + RA;
+       // HCO3
+       RA = (parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3 * 1000) / liters;
+       bicarbonate = wg_bicarbonate + RA;
+       total_alkalinity = bicarbonate * 50 / 61;
+       RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+      }
+      break;
+     case 2:
+      RA = -protonDeficit * (f1d - f3d); // Calciumcarbonate, mmol totaal
+      RA = RA * MMCaCO3 / 1000; //gram
+      //but only 1/3 is effective, so add 3 times as much
+      RA = 3 * RA;
+      $('#wa_base').val(Round(RA, 2));
+      setWaterAgent('CaCO3', Round(RA, 2));
+      if (liters > 0) {
+       //Bicarbonate
+       RA = (parseFloat($('#wa_base').jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3 * 1000) / 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 * 1000 +
+             parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000 +
+             parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMCa / MMCaCO3 * 1000) / liters;
+       calcium = wg_calcium + RA;
+       RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+      }
+      break;
+     case 3:
+      RA = -protonDeficit / 19.3; // Calciumhydroxide
+      $('#wa_base').val(Round(RA, 2));
+      setWaterAgent('Ca(OH)2', Round(RA, 2));
+      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 * 1000 +
+             parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000 +
+             parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMCa / MMCaOH2 * 1000) / 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);
+   $('#wb_ph').val(Round(ph, 2));
+   $('#est_mash_ph').val(Round(ph, 2));
   } else { // Manual
+   /* Manual calculate pH */
+   $('.c_mashph').hide();
    console.log('calc_acid no');
-   // First add base salts
-   if (parseFloat($('#wa_base').jqxNumberInput('decimal')) > 0) {
-    if (liters > 0) {
-     switch (BT) {
-      case 0: // Sodiumbicarbonate, 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 1: // Sodiumcarbonate
-       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 2: // Calciumcarbonate: 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;
-     }
+   if (parseFloat($('#wa_base').jqxNumberInput('decimal')) > 0 && liters > 0) {
+    /* First add the base salts */
+    switch (BT) {
+     case 0: // Sodiumbicarbonate, Na
+      RA = (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 +
+            parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters;
+      sodium = wg_sodium + RA;
+      // HCO3
+      RA = (parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3 * 1000) / liters;
+      bicarbonate = wg_bicarbonate + RA;
+      total_alkalinity = bicarbonate * 50 / 61;
+      RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+      break;
+     case 1: // Sodiumcarbonate
+      RA = (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 +
+            parseFloat($('#wa_base').jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3 * 1000) / liters;
+      sodium = wg_sodium + RA;
+      // HCO3
+      RA = (parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3 * 1000) / liters;
+      bicarbonate = wg_bicarbonate + RA;
+      total_alkalinity = bicarbonate * 50 / 61;
+      RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
+      break;
+     case 2: // Calciumcarbonate: Bicarbonate
+      RA = (parseFloat($('#wa_base').jqxNumberInput('decimal')) / 3 * MMHCO3 * 1000 / MMCaCO3) / 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 * 1000 / MMCaCl2 +
+            parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa * 1000 / MMCaSO4 +
+            parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMCa * 1000 / MMCaCO3) / liters;
+      calcium = wg_calcium + RA;
+      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;
+   pHa = Round(ph, 3); // Adjusted water pH
+   // Then calculate the new pH with added acids and malts
+   console.log('Mash pH: ' + pHa);
+   Acid  = AcidTypeData[AT].AcidSG * (parseFloat(dataRecord.wa_acid_perc) / 100); // ml
+   Acid *= parseFloat($('#wa_acid').jqxNumberInput('decimal'));
+   Acid /= AcidTypeData[AT].MolWt;  // mg
+   Acidmg = Acid;
 
-    //find the pH where the protondeficit = protondeficit by the acid
-    frac = CalcFrac(pHa, pK1, pK2, pK3);
-    protonDeficit = Acid * frac;
+   //find the pH where the protondeficit = protondeficit by the acid
+   frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3);
+   protonDeficit = Round(Acid * frac, 3);
+   //console.log('protonDeficit Acid: ' + protonDeficit + ' frac: ' + frac + ' pH: ' + pHa);
 
-    deltapH = 0.001;
-    deltapd = 0.1;
-    pd = ProtonDeficit(pHa);
-    n = 0;
-    while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 2000)) {
+   deltapH = 0.001;
+   deltapd = 0.1;
+   pd = Round(ProtonDeficit(pHa), 6);
+   n = 0;
+   while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 4000)) {
      n++;
      if (pd < (protonDeficit - deltapd))
       pHa -= deltapH;
      else if (pd > (protonDeficit + deltapd))
       pHa += deltapH;
-     frac = CalcFrac(pHa, pK1, pK2, pK3);
+     frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].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(Round(ph, 1));
    }
+   //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(Round(ph, 2));
+   $('#est_mash_ph').val(Round(ph, 2));
   }
 
   if ((AT == 3) && (liters > 0)) {        // Sulfuctic / Zwavelzuur
@@ -2305,14 +2281,11 @@
 
 
  function calcSparge() {
-  var TargetpH, Source_pH, Source_alkalinity, r1, r2, d, f1, f3,
-  r143, r243, d43, f143, f343, alkalinity, Ct, r1g, r2g, dg, f1g, f3g,
-  Acid, AT, result, pK1, pK2, pK3, MolWt, AcidSG, AcidPrc, fract;
 
-  // Code from BrewBuddy/Brouwhulp, who got it from http://www.brewery.org/brewery/library/Acidi0,00fWaterAJD0497.html
-  TargetpH = dataRecord.sparge_ph;
-  Source_pH = dataRecord.w1_ph;
-  Source_alkalinity = dataRecord.w1_total_alkalinity;
+  /* Based on the work of ajDeLange. */
+  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 == 1) { // Source 2
    if (dataRecord.w2_ph > 0.0) {
@@ -2333,63 +2306,54 @@
   }
 
   // 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.373);
-  d = 1 + r1 + r1 * r2;
-  f1 = 1 / d;
-  f3 = r1 * r2 / d;
+  var r1 = Math.pow(10, Source_pH - 6.35);
+  var r2 = Math.pow(10, Source_pH - 10.33);
+  var d = 1 + r1 + r1 * r2;
+  var f1 = 1 / d;
+  var 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.373);
-  d43 = 1 + r143 + r143 * r243;
-  f143 = 1 / d43;
-  f343 = r143 * r243 / d43;
+  var r143 = Math.pow(10, 4.3 - 6.35);
+  var r243 = Math.pow(10, 4.3 - 10.33);
+  var d43 = 1 + r143 + r143 * r243;
+  var f143 = 1 / d43;
+  var f343 = r143 * r243 / d43;
 
-  //Step 3. Convert the sample alkalinity to milliequivalents/L
-  alkalinity = Source_alkalinity / 50;
   //Step 4. Solve
-  Ct = (alkalinity - 1000 * (Math.pow(10, -4.3) - Math.pow(10, -Source_pH))) / ((f143 - f1) + (f3 - f343));
+  //var Ct = (alkalinity - 1000 * (Math.pow(10, -4.3) - Math.pow(10, -Source_pH))) / ((f143 - f1) + (f3 - f343));
+  var Ct = Source_alkalinity / 50 / ((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.373);
-  dg = 1 + r1g + r1g * r2g;
-  f1g = 1 / dg;
-  f3g = r1g * r2g / dg;
+  var r1g = Math.pow(10, TargetpH - 6.35);
+  var r2g = Math.pow(10, TargetpH - 10.33);
+  var dg = 1 + r1g + r1g * r2g;
+  var f1g = 1 / dg;
+  var f3g = r1g * r2g / dg;
 
   //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
-  Acid = Ct * ((f1g - f1) + (f3 - f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH);  //mEq/l
+  var Acid = Ct * ((f1g - f1) + (f3 - f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH);  //mEq/l
   Acid += 0.01;   // Add acid that would be required for distilled water.
-  if (dataRecord.sparge_acid_type < 0 || dataRecord.sparge_acid_type > 3) {
-   dataRecord.sparge_acid_type = 0;
-   $('#sparge_acid_type').val(0);
-  }
 
   //Step 8. Get the acid data.
   AT = dataRecord.sparge_acid_type;
-  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);
+  if (AT < 0 || AT >= AcidTypeData.length) {
+   AT = 0;
+   dataRecord.sparge_acid_type = 0;
+   $('#sparge_acid_type').val(0);
+   dataRecord.sparge_acid_perc = AcidTypeData[0].AcidPrc;
+   $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc);
+  }
+  var fract = CalcFrac(TargetpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[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 *= MolWt; //mg
+  Acid *= AcidTypeData[AT].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
+  //Step 11. Divide by Specific Gravity and Percentage to get the final ml.
+  Acid = Acid / AcidTypeData[AT].AcidSG / (dataRecord.sparge_acid_perc / 100); //ml
+  Acid *= dataRecord.sparge_volume; //ml acid total
   Acid = Round(Acid, 2);
   dataRecord.sparge_acid_amount = Acid / 1000;
   $('#sparge_acid_amount').val(Acid);
@@ -3750,8 +3714,7 @@
 
  // Tab 7, Water
  $('#tgt_bu').jqxNumberInput(Show2wat);
- $('#tgt_so4_cl').jqxNumberInput(Show1wat);
- $('#got_so4_cl').jqxNumberInput(Show1wat);
+ $('#tgt_so4_cl,#got_so4_cl').jqxNumberInput(Show1wat);
 
  // Water source 1
  $('#w1_name').jqxDropDownList({
@@ -3795,7 +3758,7 @@
  $('#w1_total_alkalinity').jqxNumberInput(Show1wat);
  $('#w1_chloride').jqxNumberInput(Show1wat);
  $('#w1_sulfate').jqxNumberInput(Show1wat);
- $('#w1_ph').jqxNumberInput(Show1wat);
+ $('#w1_ph').jqxNumberInput(Show2wat);
  // Water source 2
  $('#w2_name').jqxDropDownList({
   placeHolder: 'Kies meng water:',
@@ -3840,7 +3803,7 @@
  $('#w2_total_alkalinity').jqxNumberInput(Show1wat);
  $('#w2_chloride').jqxNumberInput(Show1wat);
  $('#w2_sulfate').jqxNumberInput(Show1wat);
- $('#w2_ph').jqxNumberInput(Show1wat);
+ $('#w2_ph').jqxNumberInput(Show2wat);
  // Water mixed
  $('#wg_amount').jqxNumberInput(Show1wat);
  $('#wg_calcium').jqxNumberInput(Show1wat);
@@ -3849,7 +3812,7 @@
  $('#wg_total_alkalinity').jqxNumberInput(Show1wat);
  $('#wg_chloride').jqxNumberInput(Show1wat);
  $('#wg_sulfate').jqxNumberInput(Show1wat);
- $('#wg_ph').jqxNumberInput(Show1wat);
+ $('#wg_ph').jqxNumberInput(Show2wat);
  // Water treated
  $('#wb_calcium').jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'});
  $('#wb_calcium').jqxNumberInput(Show1wat);
@@ -3862,7 +3825,7 @@
  $('#wb_sulfate').jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 350.'});
  $('#wb_sulfate').jqxNumberInput(Show1wat);
  $('#wb_total_alkalinity').jqxNumberInput(Show1wat);
- $('#wb_ph').jqxNumberInput(Show1wat);
+ $('#wb_ph').jqxNumberInput(Show2wat);
  // Water target profile
  $('#pr_name').jqxDropDownList({
   placeHolder: 'Kies doel profiel:',

mercurial