Version 0.3.32 Inventory water and profile water edit screens updated and added ion balance fields. Moved acid specs to global.js. In prod_edit and rec_edit changed the water calculations, eliminated the double percentage calculation. The pH values in the water tab have now 2 decimal digits. The mash pH field is only shown in auto calculate mode. The calculated acid addition results are now a bit better and compare with several famous spreadsheets.

Fri, 01 May 2020 11:56:24 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 01 May 2020 11:56:24 +0200
changeset 662
4bb005694ce7
parent 661
74b442eae07b
child 663
7de681f68506

Version 0.3.32 Inventory water and profile water edit screens updated and added ion balance fields. Moved acid specs to global.js. In prod_edit and rec_edit changed the water calculations, eliminated the double percentage calculation. The pH values in the water tab have now 2 decimal digits. The mash pH field is only shown in auto calculate mode. The calculated acid addition results are now a bit better and compare with several famous spreadsheets.

config.status file | annotate | diff | comparison | revisions
configure file | annotate | diff | comparison | revisions
configure.ac file | annotate | diff | comparison | revisions
www/inv_waters.php file | annotate | diff | comparison | revisions
www/js/global.js file | annotate | diff | comparison | revisions
www/js/inv_waters.js file | annotate | diff | comparison | revisions
www/js/prod_edit.js file | annotate | diff | comparison | revisions
www/js/profile_water.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
www/profile_water.php file | annotate | diff | comparison | revisions
www/rec_edit.php file | annotate | diff | comparison | revisions
--- a/config.status	Sun Apr 26 10:36:38 2020 +0200
+++ b/config.status	Fri May 01 11:56:24 2020 +0200
@@ -621,7 +621,7 @@
 S["CC"]="gcc"
 S["CYEARS"]="2016-2020"
 S["COPYRIGHT"]="Copyright (C) 2016-2020 Michiel Broek, All Rights Reserved"
-S["VERSION"]="0.3.31"
+S["VERSION"]="0.3.32"
 S["PACKAGE"]="bms"
 S["SUBDIRS"]="bmsd doc script tools www"
 S["target_alias"]=""
@@ -710,7 +710,7 @@
 D["PACKAGE_STRING"]=" \"\""
 D["PACKAGE_BUGREPORT"]=" \"\""
 D["PACKAGE_URL"]=" \"\""
-D["VERSION"]=" \"0.3.31\""
+D["VERSION"]=" \"0.3.32\""
 D["COPYRIGHT"]=" \"Copyright (C) 2016-2020 Michiel Broek, All Rights Reserved\""
 D["STDC_HEADERS"]=" 1"
 D["HAVE_SYS_TYPES_H"]=" 1"
--- a/configure	Sun Apr 26 10:36:38 2020 +0200
+++ b/configure	Fri May 01 11:56:24 2020 +0200
@@ -2043,7 +2043,7 @@
 
 
 PACKAGE="bms"
-VERSION="0.3.31"
+VERSION="0.3.32"
 COPYRIGHT="Copyright (C) 2016-2020 Michiel Broek, All Rights Reserved"
 CYEARS="2016-2020"
 
--- a/configure.ac	Sun Apr 26 10:36:38 2020 +0200
+++ b/configure.ac	Fri May 01 11:56:24 2020 +0200
@@ -8,7 +8,7 @@
 dnl General settings
 dnl After changeing the version number, run autoconf!
 PACKAGE="bms"
-VERSION="0.3.31"
+VERSION="0.3.32"
 COPYRIGHT="Copyright (C) 2016-2020 Michiel Broek, All Rights Reserved"
 CYEARS="2016-2020"
 AC_SUBST(PACKAGE)
--- a/www/inv_waters.php	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/inv_waters.php	Fri May 01 11:56:24 2020 +0200
@@ -26,28 +26,37 @@
        <td colspan="4">&nbsp;</td>
       </tr>
       <tr>
-       <td style="vertical-align: top; float: right;">Calcium (Ca) mg/l:</td>
+       <td style="vertical-align: top; float: right;">Calcium (Ca) mg/L:</td>
        <td><div id="calcium"></div></td>
-       <td style="vertical-align: top; float: right;">Chloride (Cl) mg/l:</td>
+       <td style="vertical-align: top; float: right;">Sulfaat (CaSO4) mg/L:</td>
+       <td><div id="sulfate"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Magnesium (Mg) mg/L:</td>
+       <td><div id="magnesium"></div></td>
+       <td style="vertical-align: top; float: right;">Chloride (Cl) mg/L:</td>
        <td><div id="chloride"></div></td>
       </tr>
       <tr>
-       <td style="vertical-align: top; float: right;">Magnesium (Mg) mg/l:</td>
-       <td><div id="magnesium"></div></td>
-       <td style="vertical-align: top; float: right;">Sulfaat (CaSO4) mg/l:</td>
-       <td><div id="sulfate"></div></td>
+       <td style="vertical-align: top; float: right;">Natrium (Na) mg/L:</td>
+       <td><div id="sodium"></div></td>
+       <td style="vertical-align: top; float: right;">Bicarbonaat (HCO3) mg/L:</td> <!-- Input for total_alkalinity -->
+       <td><div id="bicarbonate"></div></td>
       </tr>
       <tr>
-       <td style="vertical-align: top; float: right;">Natrium (Na) mg/l:</td>
-       <td><div id="sodium"></div></td>
-       <td style="vertical-align: top; float: right;">Bicarbonaat (HCO3) mg/l:</td> <!-- Input for total_alkalinity -->
-       <td><div id="bicarbonate"></div></td>
+       <td></td>
+       <td></td>
+       <td style="vertical-align: top; float: right;">Totale alkaliteit (CaCO3) mg/L:</td>
+       <td><div id="total_alkalinity"></div></td>
+      </tr>
+      <tr>
+       <td colspan="4">&nbsp;</td>
       </tr>
       <tr>
        <td style="vertical-align: top; float: right;">Zuurgraad (pH):</td>
        <td><div id="ph"></div></td>
-       <td style="vertical-align: top; float: right;">Totale alkaliteit (CaCO3) mg/l:</td>
-       <td><div id="total_alkalinity"></div></td>
+       <td style="vertical-align: top; float: right;">Ionen balans meq/L:</td>
+       <td><div style="float: left;" id="balance"></div><div style="float: left; margin-left: 10px;" id="wr_balance"></div></td>
       </tr>
       <tr>
        <td colspan="4">&nbsp;</td>
@@ -63,10 +72,10 @@
        <td><div id="cost"></div></td>
       </tr>
       <tr>
-       <td style="padding-top: 110px; float: right;"><input type="button" id="Delete" value="Verwijder" /></td>
+       <td style="padding-top: 70px; float: right;"><input type="button" id="Delete" value="Verwijder" /></td>
        <td></td>
        <td></td>
-       <td style="padding-top: 110px;"><input style="margin-right: 5px;" type="button" id="Save" value="Sla op" /><input id="Cancel" type="button" value="Annuleer" /></td>
+       <td style="padding-top: 70px;"><input style="margin-right: 5px;" type="button" id="Save" value="Sla op" /><input id="Cancel" type="button" value="Annuleer" /></td>
       </tr>
      </table>
     </div>
--- a/www/js/global.js	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/js/global.js	Fri May 01 11:56:24 2020 +0200
@@ -370,10 +370,11 @@
 AerationTypeAdapter = new $.jqx.dataAdapter(AerationTypeSource),
 
 AcidTypeData = [
- { id: 0, en: 'Lactic', nl: 'Melkzuur' },
- { id: 1, en: 'Hydrochloric', nl: 'Zoutzuur' },
- { id: 2, en: 'Phosphoric', nl: 'Fosforzuur' },
- { id: 3, en: 'Sulfuric', nl: 'Zwavelzuur' }
+ /* Note: AcidSG is for 100% use. AcidPrc is the default setting. */
+ { id: 0, en: 'Lactic', nl: 'Melkzuur', pK1: 3.86, pK2: 20, pK3: 20, MolWt: 90.08, AcidSG: 1238, AcidPrc: 80 },
+ { id: 1, en: 'Hydrochloric', nl: 'Zoutzuur', pK1: -7, pK2: 20, pK3: 20, MolWt: 36.46, AcidSG: 1497, AcidPrc: 28 },
+ { id: 2, en: 'Phosphoric', nl: 'Fosforzuur', pK1: 2.12, pK2: 7.20, pK3: 12.44, MolWt: 98.00, AcidSG: 1765, AcidPrc: 25 },
+ { id: 3, en: 'Sulfuric', nl: 'Zwavelzuur', pK1: -1, pK2: 1.92, pK3: 20, MolWt: 98.07, AcidSG: 1884, AcidPrc: 93 }
 ],
 AcidTypeSource = {
  localdata: AcidTypeData,
--- a/www/js/inv_waters.js	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/js/inv_waters.js	Fri May 01 11:56:24 2020 +0200
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * Copyright (C) 2014-2019
+ * Copyright (C) 2014-2020
  *
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -56,6 +56,7 @@
  $('#magnesium').jqxTooltip({ content: 'Magnesium (Mg).' });
  $('#ph').jqxTooltip({ content: 'De zuurgraad (pH).' });
  $('#total_alkalinity').jqxTooltip({ content: 'Totale alkaliniteit. Berekend meteen de Bicarbonaat.' });
+ $('#balance').jqxTooltip({ content: 'De ionen balans van het water. Ideaal minder dan 0.1 verschil tussen kationen en anionen. Meer dan 0.5 is een fout in het waterraport.' });
  $('#inventory').jqxTooltip({ content: 'Voorraad in liters.' });
  $('#cost').jqxTooltip({ content: 'Kostprijs per liter. 5 cijfers achter de comma zodat het kraanwater er ook in kan.' });
 
@@ -151,6 +152,7 @@
  $('#magnesium').jqxNumberInput(Spin1dec);
  $('#ph').jqxNumberInput(Spin2pH);
  $('#total_alkalinity').jqxNumberInput(Spin1dec);
+ $('#balance').jqxNumberInput(Show2dec);
  $('#inventory').jqxNumberInput(Spin1dec);
  $('#cost').jqxNumberInput({inputMode: 'simple', theme: theme, width: 110, height: 23, min: 0, decimalDigits: 5, spinButtons: true });
 
@@ -231,19 +233,57 @@
      $('#inventory').val(dataRecord.inventory);
      $('#cost').val(dataRecord.cost);
      // show the popup window.
+     calcBalance();
      $('#popupWindow').jqxWindow('open');
     }
    }
   ]
  });
 
+ function calcBalance() {
+  var cations = (dataRecord.calcium / 20.039) + (dataRecord.magnesium / 12.1525) + (dataRecord.sodium / 22.989);
+  var anions = (dataRecord.bicarbonate / 61.016) + (dataRecord.sulfate / 48.031) + (dataRecord.chloride / 35.4527);
+  var balance = Round(cations - anions, 2);
+  $('#balance').val(balance);
+  if (balance <= 0.1 && balance >= -0.1)
+   $('#wr_balance').html("<img src='images/dialog-ok-apply.png'>");
+  else if (balance <= 0.5 && balance >= -0.5)
+   $('#wr_balance').html("<img src='images/dialog-ok.png'>");
+  else
+   $('#wr_balance').html("<img src='images/dialog-error.png'>");
+ }
+
+ $('#calcium').on('change', function(event) {
+  dataRecord.calcium = parseFloat(event.args.value);
+  calcBalance();
+ });
+ $('#magnesium').on('change', function(event) {
+  dataRecord.magnesium = parseFloat(event.args.value);
+  calcBalance();
+ });
+ $('#sodium').on('change', function(event) {
+  dataRecord.sodium = parseFloat(event.args.value);
+  calcBalance();
+ });
  $('#total_alkalinity').on('change', function(event) {
+  dataRecord.total_alkalinity = parseFloat(event.args.value);
   dataRecord.bicarbonate = parseFloat(event.args.value) * 1.22;
   $('#bicarbonate').val(dataRecord.bicarbonate);
+  calcBalance();
  });
  $('#bicarbonate').on('change', function(event) {
+  dataRecord.bicarbonate = parseFloat(event.args.value);
   dataRecord.total_alkalinity = parseFloat(event.args.value) * 50 / 61;
   $('#total_alkalinity').val(dataRecord.total_alkalinity);
+  calcBalance();
+ });
+ $('#sulfate').on('change', function(event) {
+  dataRecord.sulfate = parseFloat(event.args.value);
+  calcBalance();
+ });
+ $('#chloride').on('change', function(event) {
+  dataRecord.chloride = parseFloat(event.args.value);
+  calcBalance();
  });
 
  // initialize the popup window and buttons.
--- a/www/js/prod_edit.js	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/js/prod_edit.js	Fri May 01 11:56:24 2020 +0200
@@ -1064,25 +1064,25 @@
       case 'Melkzuur':
        $('#wa_acid_name').val(0);
        $('#wa_acid').val(row.m_amount * 1000);
-       $('#wa_acid_perc').val(80);
+       $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc);	// TODO: this ignores changed percentages.
        last_acid = 'Melkzuur';
        break;
       case 'Zoutzuur':
        $('#wa_acid_name').val(1);
        $('#wa_acid').val(row.m_amount * 1000);
-       $('#wa_acid_perc').val(80);
+       $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc);
        last_acid = 'Zoutzuur';
        break;
       case 'Fosforzuur':
        $('#wa_acid_name').val(2);
        $('#wa_acid').val(row.m_amount * 1000);
-       $('#wa_acid_perc').val(80);
+       $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc);
        last_acid = 'Fosforzuur';
        break;
       case 'Zwavelzuur':
        $('#wa_acid_name').val(3);
        $('#wa_acid').val(row.m_amount * 1000);
-       $('#wa_acid_perc').val(80);
+       $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc);
        last_acid = 'Zwavelzuur';
        break;
       case 'NaHCO3':
@@ -2794,22 +2794,13 @@
   return Z - (Calc / 3.5 + Magn / 7);
  }
 
- function ProtonDeficit(pHZ) {
-
-  var rows, i, C1, ebc, x, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal'));
-  // proton deficit for the grist
-  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
-     // 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 {
+ 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.
-      ebc = row.f_color;
-      switch (row.f_graintype) {
+      switch (graintype) {
        case 0:                                 // Base, Special, Kilned
        case 3:
        case 5: C1 = 0.014 * ebc - 34.192;
@@ -2821,7 +2812,19 @@
        case 4: C1 = -149;                      // Sour malt
                break;
       }
-     }
+  }
+  return C1;
+ }
+
+ function ProtonDeficit(pHZ) {
+
+  var rows, i, C1, x, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal'));
+  // proton deficit for the grist
+  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;
     }
@@ -2845,24 +2848,11 @@
     pH += deltapH;
    pd = ProtonDeficit(pH);
   }
-  pH = Round(pH, 2);
+  pH = Round(pH, 6);
   //console.log('MashpH() n: ' + n + ' pH: ' + pH);
   return pH;
  }
 
- function GetAcidSpecs(AT) {
-  switch (AT) {
-   case 0: // Melkzuur
-    return { pK1: 3.86, pK2: 20, pK3: 20, MolWt: 90.08, AcidSG: 1214, AcidPrc: 0.88 };
-   case 1: // Zoutzuur
-    return { pK1: -7, pK2: 20, pK3: 20, MolWt: 36.46, AcidSG: 1142, AcidPrc: 0.28 };
-   case 2: // Fosforzuur
-    return { pK1: 2.12, pK2: 7.20, pK3: 12.44, MolWt: 98.00, AcidSG: 1170, AcidPrc: 0.25 };
-   case 3: // Zwavelzuur
-    return { pK1: -1, pK2: 1.92, pK3: 20, MolWt: 98.07, AcidSG: 1700, AcidPrc: 0.93 };
-  }
- }
-
  function calcWater() {
 
   /* Can be called during loading and building the screens */
@@ -2876,7 +2866,6 @@
   magnesium = 0,
   sodium = 0,
   total_alkalinity = 0,
-  bicarbonate = 0,
   chloride = 0,
   sulfate = 0,
   ph = 0,
@@ -2884,11 +2873,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;
@@ -2914,96 +2902,85 @@
    total_alkalinity = dataRecord.w1_total_alkalinity;
    ph = dataRecord.w1_ph;
   }
+  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;
+
   $('#wg_amount').val(liters);
-  wg_calcium = calcium;
-  $('#wg_calcium').val(Math.round(calcium * 10) / 10);
-  //var 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.
-  //var wg_ph = ph;
-  var mash_ph = Round(MashpH(), 1);
-  $('#wg_ph').val(Round(ph, 1));
-  $('#wb_ph').val(mash_ph);
-  $('#est_mash_ph').val(mash_ph);
-  bicarbonate = total_alkalinity * 1.22;
-  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;
-
-  // Calculate Mg
-  RA = parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4;
-  magnesium += 1000 * RA / liters;
-
-  // Calculate Na
-  RA = parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl +
-       parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
-  sodium += 1000 * RA / 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 (parseInt($('#wa_acid_name').val()) < 0 || parseInt($('#wa_acid_name').val()) > 3) {
+  $('#wg_calcium').val(Round(calcium, 1));
+  $('#wg_magnesium').val(Round(magnesium, 1));
+  $('#wg_sodium').val(Round(sodium, 1));
+  $('#wg_total_alkalinity').val(Round(total_alkalinity, 1));
+  $('#wg_chloride').val(Round(chloride, 1));
+  $('#wg_sulfate').val(Round(sulfate, 1));
+  $('#wg_ph').val(Round(ph, 2));
+
+  var mash_ph = Round(MashpH(), 3);
+  console.log('Distilled water mash pH: ' + mash_ph);
+
+  /* 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;
+  }
+
+  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;
-
-  if (parseInt($('#wa_base_name').val()) < 0 || parseInt($('#wa_base_name').val()) > 3) {
+   last_acid = AcidTypeData[dataRecord.wa_acid_name].nl;
+
+  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) {
+   /* Auto calculate pH */
+   $('.c_mashph').show();
    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);
+    dataRecord.wa_base = 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 = Round(Acid * AcidPrc / (parseFloat($('#wa_acid_perc').jqxNumberInput('decimal')) / 100), 2); // ml
-    //console.log('Final ml: ' + Acid);
+    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);
 
@@ -3011,9 +2988,10 @@
     total_alkalinity = bicarbonate * 50 / 61;
    } else if (protonDeficit < 0) { //Add base
     $('#wa_acid').val(0);
+    dataRecord.wa_acid = 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;
@@ -3025,13 +3003,11 @@
       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;
+       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;
-       RA = 1000 * RA / liters;
+       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);
@@ -3043,13 +3019,11 @@
       $('#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;
+       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;
-       RA = 1000 * RA / liters;
+       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);
@@ -3064,15 +3038,13 @@
       setWaterAgent('CaCO3', Round(RA, 2));
       if (liters > 0) {
        //Bicarbonate
-       RA = parseFloat($('#wa_base').jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
-       RA = 1000 * RA / liters;
+       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 +
-            parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
-            parseFloat($('#wa_base').jqxNumberInput('decimal')) * MMCa / MMCaCO3;
-       RA = 1000 * RA / liters;
+       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);
       }
@@ -3087,10 +3059,9 @@
        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;
+       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);
       }
@@ -3098,98 +3069,86 @@
     }
    }
    ph = TpH;
-   $('#wb_ph').val(Round(ph, 1));
-   $('#est_mash_ph').val(Round(ph, 1));
-  } else { // Manual
+   $('#wb_ph').val(Round(ph, 2));
+   $('#est_mash_ph').val(Round(ph, 2));
+  } else {
+   /* 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;
-
-    //find the pH where the protondeficit = protondeficit by the acid
-    frac = CalcFrac(pHa, pK1, pK2, pK3);
-    protonDeficit = Acid * frac;
-
-    deltapH = 0.001;
-    deltapd = 0.1;
-    console.log('in calcWater() manual');
-    pd = ProtonDeficit(pHa);
-    n = 0;
-    while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 2000)) {
+   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, 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 = 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));
-    $('#est_mash_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
+  if ((AT == 3) && (liters > 0)) {        // Sulfuric / Zwavelzuur
    RA = parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
         parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 +
         Acidmg / 1000 * MMSO4 / (MMSO4 + 2);
@@ -3304,13 +3263,10 @@
 
  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) {
@@ -3322,73 +3278,62 @@
    }
   } else if (dataRecord.sparge_source == 2) {     // Mixed
    if (dataRecord.w2_ph > 0.0) {
-    Source_pH = parseFloat($('#wg_ph').jqxNumberInput('decimal'));
-    Source_alkalinity = parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal'));
+    Source_pH = parseFloat(dataRecord.wg_ph);
+    Source_alkalinity = parseFloat(dataRecord.wg_total_alkalinity);
    } else {
     dataRecord.sparge_source = 0;
     $('#sparge_source').val(0);
    }
   }
 
-  // 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;
+  // Step 1: Compute the mole fractions of carbonic (f1) and carbonate(f3) at the source water pH
+  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;
-
-  //Step 3. Convert the water alkalinity to milliequivalents/L
-  alkalinity = Source_alkalinity / 50;
+  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 4. Solve
-  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) {
+
+  //Step 8. Get the acid data.
+  var AT = dataRecord.sparge_acid_type;
+  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);
   }
-
-  //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);
+  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 = 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 *= AcidTypeData[AT].MolWt; //mg
+
+  //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);
@@ -3923,20 +3868,25 @@
   $('#wa_acid_name').on('select', function(event) {
    if (event.args) {
     var index = event.args.index;
-    console.log('wa_acid_name ' + index);
+    console.log('wa_acid_name ' + index + ' last_acid: ' + last_acid);
     setWaterAgent(last_acid, 0);
     last_acid = AcidTypeData[index].nl;
+    dataRecord.wa_acid_name = index;
+    dataRecord.wa_acid_perc = AcidTypeData[index].AcidPrc;
+    $('#wa_acid_perc').val(dataRecord.wa_acid_perc);
+    calcWater();
     setWaterAgent(last_acid, parseFloat($('#wa_acid').jqxNumberInput('decimal')));
-    dataRecord.wa_acid_name = index;
-    calcWater();
    }
   });
   $('#wa_acid').on('change', function(event) {
-   var name = AcidTypeData[$('#wa_acid_name').val()].nl;
+   var name = AcidTypeData[dataRecord.wa_acid_name].nl;
    setWaterAgent(name, parseFloat(event.args.value));
    calcWater();
   });
-  $('#wa_acid_perc').on('change', function(event) { calcWater(); });
+  $('#wa_acid_perc').on('change', function(event) {
+   dataRecord.wa_acid_perc = parseFloat(event.args.value);
+   calcWater();
+  });
 
   $('#color_method').on('select', function(event) {
    dataRecord.color_method = event.args.index;
@@ -4034,6 +3984,8 @@
    if (event.args) {
     dataRecord.sparge_acid_type = event.args.index;
     console.log('new sparge_acid_type: ' + dataRecord.sparge_acid_type);
+    dataRecord.sparge_acid_perc = AcidTypeData[event.args.index].AcidPrc;
+    $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc);
     calcSparge();
    }
   });
@@ -5626,7 +5578,8 @@
    calcWater();
   }
  });
- $('#w1_amount,#w1_calcium,#w1_magnesium,#w1_sodium,#w1_total_alkalinity,#w1_chloride,#w1_sulfate,#w1_ph').jqxNumberInput(Show1wat);
+ $('#w1_amount,#w1_calcium,#w1_magnesium,#w1_sodium,#w1_total_alkalinity,#w1_chloride,#w1_sulfate').jqxNumberInput(Show1wat);
+ $('#w1_ph').jqxNumberInput(Show2wat);
  // Water source 2
  $('#w2_name').jqxDropDownList({
   placeHolder: 'Kies meng water:',
@@ -5668,16 +5621,19 @@
   inputMode: 'simple', spinMode: 'simple', theme: theme, width: 94, height: 23, min: 0, max: 0, decimalDigits: 1,
   spinButtons: true, spinButtonsStep: 0.1, readOnly: true
  });
- $('#w2_calcium,#w2_magnesium,#w2_sodium,#w2_total_alkalinity,#w2_chloride,#w2_sulfate,#w2_ph').jqxNumberInput(Show1wat);
+ $('#w2_calcium,#w2_magnesium,#w2_sodium,#w2_total_alkalinity,#w2_chloride,#w2_sulfate').jqxNumberInput(Show1wat);
+ $('#w2_ph').jqxNumberInput(Show2wat);
  // Water mixed
- $('#wg_amount,#wg_calcium,#wg_magnesium,#wg_sodium,#wg_total_alkalinity,#wg_chloride,#wg_sulfate,#wg_ph').jqxNumberInput(Show1wat);
+ $('#wg_amount,#wg_calcium,#wg_magnesium,#wg_sodium,#wg_total_alkalinity,#wg_chloride,#wg_sulfate').jqxNumberInput(Show1wat);
+ $('#wg_ph').jqxNumberInput(Show2wat);
  // Water treated
  $('#wb_calcium').jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'});
  $('#wb_magnesium').jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is tusse 10 en 30.'});
  $('#wb_sodium').jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'});
  $('#wb_chloride').jqxTooltip({ content: 'De ideale hoeveelheid Chloride is tussen 50 en 100.'});
  $('#wb_sulfate').jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 350.'});
- $('#wb_calcium,#wb_magnesium,#wb_sodium,#wb_total_alkalinity,#wb_chloride,#wb_sulfate,#wb_ph').jqxNumberInput(Show1wat);
+ $('#wb_calcium,#wb_magnesium,#wb_sodium,#wb_total_alkalinity,#wb_chloride,#wb_sulfate').jqxNumberInput(Show1wat);
+ $('#wb_ph').jqxNumberInput(Show2wat);
  // Water target profile
  $('#pr_name').jqxDropDownList({
   placeHolder: 'Kies doel profiel:',
@@ -5790,7 +5746,7 @@
  $('#brew_sparge_volume').jqxTooltip({ content: 'Het spoelwater voorraad volume, in te stellen in de Water tab.' });
  $('#brew_date_start,#brew_date_end').jqxDateTimeInput(DateTimeopts);
  $('#brew_date_start,#brew_date_end').on('close', function(event) { calcStage(); });
- $('#est_mash_ph').jqxNumberInput(Show1wat);
+ $('#est_mash_ph').jqxNumberInput(Show2wat);
  $('#brew_mash_ph,#brew_preboil_ph,#brew_aboil_ph').jqxNumberInput(SpinpH);
  $('#brew_mash_sg').on('valueChanged', function() { calcMashEfficiency(); });
  $('#brew_preboil_sg').on('valueChanged', function(event) {
--- a/www/js/profile_water.js	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/js/profile_water.js	Fri May 01 11:56:24 2020 +0200
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * Copyright (C) 2014-2019
+ * Copyright (C) 2014-2020
  *
  * Michiel Broek <mbroek at mbse dot eu>
  *
@@ -131,6 +131,7 @@
  $('#magnesium').jqxTooltip({ content: 'Magnesium (Mg).' });
  $('#ph').jqxTooltip({ content: 'De zuurgraad (pH).' });
  $('#total_alkalinity').jqxTooltip({ content: 'Totale alkaliniteit. Berekend meteen de Bicarbonaat.' });
+ $('#balance').jqxTooltip({ content: 'De ionen balans van het water. Ideaal minder dan 0.1 verschil tussen kationen en anionen. Meer dan 0.5 is een fout in het waterraport.' });
 
  // initialize the input fields.
  $('#name').jqxInput({ theme: theme, width: 640, height: 23 });
@@ -143,6 +144,7 @@
  $('#magnesium').jqxNumberInput(Spin1dec);
  $('#ph').jqxNumberInput(Spin2pH);
  $('#total_alkalinity').jqxNumberInput(Spin1dec);
+ $('#balance').jqxNumberInput(Show2dec);
 
  // initialize jqxGrid
  $('#jqxgrid').jqxGrid({
@@ -206,6 +208,7 @@
      $('#ph').val(dataRecord.ph);
      $('#notes').val(dataRecord.notes);
      $('#total_alkalinity').val(dataRecord.total_alkalinity);
+     calcBalance();
      // show the popup window.
      $('#popupWindow').jqxWindow('open');
     }
@@ -213,13 +216,50 @@
   ]
  });
 
+ function calcBalance() {
+  var cations = (dataRecord.calcium / 20.039) + (dataRecord.magnesium / 12.1525) + (dataRecord.sodium / 22.989);
+  var anions = (dataRecord.bicarbonate / 61.016) + (dataRecord.sulfate / 48.031) + (dataRecord.chloride / 35.4527);
+  var balance = Round(cations - anions, 2);
+  $('#balance').val(balance);
+  if (balance <= 0.1 && balance >= -0.1)
+   $('#wr_balance').html("<img src='images/dialog-ok-apply.png'>");
+  else if (balance <= 0.5 && balance >= -0.5)
+   $('#wr_balance').html("<img src='images/dialog-ok.png'>");
+  else
+   $('#wr_balance').html("<img src='images/dialog-error.png'>");
+ }
+
+ $('#calcium').on('change', function(event) {
+  dataRecord.calcium = parseFloat(event.args.value);
+  calcBalance();
+ });
+ $('#magnesium').on('change', function(event) {
+  dataRecord.magnesium = parseFloat(event.args.value);
+  calcBalance();
+ });
+ $('#sodium').on('change', function(event) {
+  dataRecord.sodium = parseFloat(event.args.value);
+  calcBalance();
+ });
  $('#total_alkalinity').on('change', function(event) {
+  dataRecord.total_alkalinity = parseFloat(event.args.value);
   dataRecord.bicarbonate = parseFloat(event.args.value) * 1.22;
   $('#bicarbonate').val(dataRecord.bicarbonate);
+  calcBalance();
  });
  $('#bicarbonate').on('change', function(event) {
+  dataRecord.bicarbonate = parseFloat(event.args.value);
   dataRecord.total_alkalinity = parseFloat(event.args.value) * 50 / 61;
   $('#total_alkalinity').val(dataRecord.total_alkalinity);
+  calcBalance();
+ });
+ $('#sulfate').on('change', function(event) {
+  dataRecord.sulfate = parseFloat(event.args.value);
+  calcBalance();
+ });
+ $('#chloride').on('change', function(event) {
+  dataRecord.chloride = parseFloat(event.args.value);
+  calcBalance();
  });
 
  // initialize the popup window and buttons.
--- 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:',
--- a/www/prod_edit.php	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/prod_edit.php	Fri May 01 11:56:24 2020 +0200
@@ -477,8 +477,8 @@
        <tr>
         <td style="vertical-align: top; float: right; padding: 3px;">Calciumchloride (CaCl2) gr:</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;"><div class='c_mashph'>Maish pH:</div></td>
+        <td style="padding: 3px;"><div id="mash_ph" class='c_mashph'></div></td>
         <td style="vertical-align: top; float: right; padding: 3px;">Spoelwater voorraad L:</td>
         <td style="padding: 3px;"><div id="sparge_volume"></div></td>
        </tr>
--- a/www/profile_water.php	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/profile_water.php	Fri May 01 11:56:24 2020 +0200
@@ -26,28 +26,37 @@
        <td colspan="4">&nbsp;</td>
       </tr>
       <tr>
-       <td style="vertical-align: top; float: right;">Calcium (Ca) mg/l:</td>
+       <td style="vertical-align: top; float: right;">Calcium (Ca) mg/L:</td>
        <td><div id="calcium"></div></td>
-       <td style="vertical-align: top; float: right;">Chloride (Cl) mg/l:</td>
+       <td style="vertical-align: top; float: right;">Sulfaat (CaSO4) mg/L:</td>
+       <td><div id="sulfate"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right;">Magnesium (Mg) mg/L:</td>
+       <td><div id="magnesium"></div></td>
+       <td style="vertical-align: top; float: right;">Chloride (Cl) mg/L:</td>
        <td><div id="chloride"></div></td>
       </tr>
       <tr>
-       <td style="vertical-align: top; float: right;">Magnesium (Mg) mg/l:</td>
-       <td><div id="magnesium"></div></td>
-       <td style="vertical-align: top; float: right;">Sulfaat (CaSO4) mg/l:</td>
-       <td><div id="sulfate"></div></td>
+       <td style="vertical-align: top; float: right;">Natrium (Na) mg/L:</td>
+       <td><div id="sodium"></div></td>
+       <td style="vertical-align: top; float: right;">Bicarbonaat (HCO3) mg/L:</td> <!-- Input for total_alkalinity -->
+       <td><div id="bicarbonate"></div></td>
       </tr>
       <tr>
-       <td style="vertical-align: top; float: right;">Natrium (Na) mg/l:</td>
-       <td><div id="sodium"></div></td>
-       <td style="vertical-align: top; float: right;">Bicarbonaat (HCO3) mg/l:</td> <!-- Input for total_alkalinity -->
-       <td><div id="bicarbonate"></div></td>
+       <td></td>
+       <td></td>
+       <td style="vertical-align: top; float: right;">Totale alkaliteit (CaCO3) mg/L:</td>
+       <td><div id="total_alkalinity"></div></td>
+      </tr>
+      <tr>
+       <td colspan="4">&nbsp;</td>
       </tr>
       <tr>
        <td style="vertical-align: top; float: right;">Zuurgraad (pH):</td>
        <td><div id="ph"></div></td>
-       <td style="vertical-align: top; float: right;">Totale alkaliteit (CaCO3) mg/l:</td>
-       <td><div id="total_alkalinity"></div></td>
+       <td style="vertical-align: top; float: right;">Ionen balans meq/L:</td>
+       <td><div style="float: left;" id="balance"></div><div style="float: left; margin-left: 10px;" id="wr_balance"></div></td>
       </tr>
       <tr>
        <td style="padding-top: 110px;" align="right"><input type="button" id="Delete" value="Verwijder" /></td>
--- a/www/rec_edit.php	Sun Apr 26 10:36:38 2020 +0200
+++ b/www/rec_edit.php	Fri May 01 11:56:24 2020 +0200
@@ -296,8 +296,8 @@
         <tr>
          <td style="vertical-align: top; float: right; padding: 3px;">Calciumchloride (CaCl2) gr:</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;"><div class='c_mashph'>Maish pH:</div></td>
+         <td style="padding: 3px;"><div id="mash_ph" class='c_mashph'></div></td>
          <td style="vertical-align: top; float: right; padding: 3px;">Spoelwater liters:</td>
          <td style="padding: 3px;"><div id="sparge_volume"></div></td>
         </tr>

mercurial