44 |
44 |
45 |
45 |
46 |
46 |
47 $(document).ready(function () { |
47 $(document).ready(function () { |
48 |
48 |
49 var to_100 = false; // Fermentables adjust to 100% |
49 var i, |
50 var preboil_sg = 0; |
50 to_100 = false, // Fermentables adjust to 100% |
51 var aboil_sg = 0; |
51 preboil_sg = 0, |
52 var est_mash_sg = 0; |
52 aboil_sg = 0, |
53 var psugar = 0; // Percentage real sugars |
53 est_mash_sg = 0, |
54 var pcara = 0; // Percentage cara/crystal malts |
54 psugar = 0, // Percentage real sugars |
55 var svg = 77; // Default attenuation |
55 pcara = 0, // Percentage cara/crystal malts |
56 var mashkg = 0; // Malt in mash weight |
56 svg = 77, // Default attenuation |
57 var pitchrate = 0.75; // Yeast pitch rate default |
57 mashkg = 0, // Malt in mash weight |
58 var initcells = 0; // Initial yeast cell count |
58 pitchrate = 0.75, // Yeast pitch rate default |
59 |
59 initcells = 0, // Initial yeast cell count |
60 var ok_fermentables = 1; // Fermentables are in stock |
60 |
61 var ok_hops = 1; // Hops are in stock |
61 ok_fermentables = 1, // Fermentables are in stock |
62 var ok_miscs = 1; // Miscs are in stock |
62 ok_hops = 1, // Hops are in stock |
63 var ok_yeasts = 1; // Yeasts are in stock |
63 ok_miscs = 1, // Miscs are in stock |
64 var ok_waters = 1; // Waters are in stock |
64 ok_yeasts = 1, // Yeasts are in stock |
65 |
65 ok_waters = 1, // Waters are in stock |
66 var hop_flavour = 0; |
66 |
67 var hop_aroma = 0; |
67 hop_flavour = 0, |
68 var mash_infuse = 0; |
68 hop_aroma = 0, |
69 var last_base = ''; |
69 mash_infuse = 0, |
70 var last_acid = ''; |
70 last_base = '', |
71 |
71 last_acid = '', |
72 var MMCa = 40.048; |
72 |
73 var MMMg = 24.305; |
73 MMCa = 40.048, |
74 var MMNa = 22.98976928; |
74 MMMg = 24.305, |
75 var MMCl = 35.453; |
75 MMNa = 22.98976928, |
76 var MMSO4 = 96.0626; |
76 MMCl = 35.453, |
77 var MMHCO3 = 61.01684; |
77 MMSO4 = 96.0626, |
78 var MMCaSO4 = 172.171; |
78 MMHCO3 = 61.01684, |
79 var MMCaCl2 = 147.015; |
79 MMCaSO4 = 172.171, |
80 var MMCaCO3 = 100.087; |
80 MMCaCl2 = 147.015, |
81 var MMMgSO4 = 246.475; |
81 MMCaCO3 = 100.087, |
82 var MMNaHCO3 = 84.007; |
82 MMMgSO4 = 246.475, |
83 var MMNa2CO3 = 105.996; |
83 MMNaHCO3 = 84.007, |
84 var MMNaCl = 58.443; |
84 MMNa2CO3 = 105.996, |
85 var MMCaOH2 = 74.06268; |
85 MMNaCl = 58.443, |
86 |
86 MMCaOH2 = 74.06268, |
87 var fermentableRow = 0; |
87 |
88 var fermentableData = {}; |
88 fermentableRow = 0, |
89 var fermentableInit = 1; |
89 fermentableData = {}, |
90 var hopRow = 0; |
90 fermentableInit = 1, |
91 var hopData = {}; |
91 hopRow = 0, |
92 var miscRow = 0; |
92 hopData = {}, |
93 var miscData = {}; |
93 miscRow = 0, |
94 var yeastRow = 0; |
94 miscData = {}, |
95 var yeastData = {}; |
95 yeastRow = 0, |
96 var mashRow = 0; |
96 yeastData = {}, |
97 var mashData = {}; |
97 mashRow = 0, |
98 |
98 mashData = {}, |
99 /* |
99 Ka1 = 0.0000004445, |
100 * Remove the top menu so that we MUST use the buttons to leave the editor. |
100 Ka2 = 0.0000000000468, |
101 */ |
101 dataRecord = {}, |
102 $('#jqxMenu').jqxMenu('destroy'); |
102 url = "includes/db_product.php", |
103 |
|
104 console.log("record:" + my_record + " return:" + my_return + " theme:" + theme); |
|
105 $("#jqxLoader").jqxLoader({width:250,height:150,isModal:true,text:"Laden product ...",theme:theme}); |
|
106 |
|
107 function calcSupplies() { |
|
108 if (dataRecord.inventory_reduced > 6) { |
|
109 $("#ok_pmpt").hide(); |
|
110 return; |
|
111 } |
|
112 if (ok_fermentables && ok_hops && ok_miscs && ok_yeasts && ok_waters) |
|
113 $("#ok_supplies").html("<img src='images/dialog-ok-apply.png'>"); |
|
114 else |
|
115 $("#ok_supplies").html("<img src='images/dialog-error.png'>"); |
|
116 } |
|
117 |
|
118 function calcPercentages() { |
|
119 |
|
120 console.log("calcPercentages()"); |
|
121 var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; |
|
122 if (rowscount > 1) { |
|
123 var tw = 0; |
|
124 for (i = 0; i < rowscount; i++) { |
|
125 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i); |
|
126 if (rowdata.f_added < 4) |
|
127 tw += Math.round(rowdata.f_amount * 1000) / 1000; |
|
128 }; |
|
129 tw = Math.round(tw * 1000) / 1000; |
|
130 |
|
131 for (i = 0; i < rowscount; i++) { |
|
132 var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i); |
|
133 if (rowdata.f_added < 4) { |
|
134 var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0; |
|
135 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage); |
|
136 } else { |
|
137 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", 0); |
|
138 } |
|
139 }; |
|
140 } else { |
|
141 $("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100); |
|
142 } |
|
143 } |
|
144 |
|
145 /* |
|
146 * All calculations that depend on changes in the fermentables, |
|
147 * volumes and equipments. |
|
148 */ |
|
149 function calcFermentables() { |
|
150 |
|
151 var sugarsf = 0; // fermentable sugars mash + boil |
|
152 var sugarsm = 0; // fermentable sugars in mash |
|
153 psugar = 0; |
|
154 pcara = 0; |
|
155 mashkg = 0; |
|
156 ok_fermentables = 1; // All is in stock. |
|
157 ok_yeasts = 1; |
|
158 var vol = 0; // Volume sugars after boil |
|
159 var addedS = 0; // Added sugars after boil |
|
160 var addedmass = 0; // Added mass after boil |
|
161 var mvol = 0; // mash volume |
|
162 var colort = 0; // Colors srm * vol totals |
|
163 var colorh = 0; // Colors ebc * vol * kt |
|
164 var colorn = 0; // Colors ebc * pt * pct |
|
165 var my_100 = false; |
|
166 var mashtime = 0; // Total mash time |
|
167 var mashtemp = 0; // Average mash temperature |
|
168 var bv = 0.925; // Bierverlies rendement |
|
169 var sr = 0.95; // Mash en spoel rendement |
|
170 var lintner = 0; // Total recipe lintner |
|
171 |
|
172 if ((rows = $('#mashGrid').jqxGrid('getrows'))){ |
|
173 for(var i=0;i<rows.length;i++){ |
|
174 var row=rows[i]; |
|
175 if(row.step_type==0) // Infusion |
|
176 mvol+=parseFloat(row.step_infuse_amount); |
|
177 if(row.step_temp<=75){ // Ignore mashout |
|
178 var timem=row.step_time+row.ramp_time; |
|
179 mashtime+=timem; |
|
180 mashtemp+=timem*row.step_temp; |
|
181 } |
|
182 } |
|
183 if(mashtime>5) |
|
184 mashtime-=5;//Correct last ramp > 75 |
|
185 mashtemp=Round(mashtemp/mashtime,2); |
|
186 } |
|
187 |
|
188 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { |
|
189 return; // grid not yet loaded. |
|
190 } |
|
191 |
|
192 var s = 0; |
|
193 for (var i = 0; i < rows.length; i++) { |
|
194 var row = rows[i]; |
|
195 if (row.f_adjust_to_total_100) |
|
196 my_100 = true; |
|
197 if (row.f_type == 1 && row.f_added < 4) // Sugar |
|
198 psugar += row.f_percentage; |
|
199 if (row.f_graintype == 2 && row.f_added < 4) // Crystal |
|
200 pcara += row.f_percentage; |
|
201 var d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
202 if (row.f_added == 0) { // Mash |
|
203 if (mvol > 0) { // Only if mash already known. |
|
204 mvol += row.f_amount * row.f_moisture / 100; |
|
205 s += d; |
|
206 } |
|
207 d = parseFloat(dataRecord.efficiency) / 100 * d; |
|
208 sugarsm += d; |
|
209 mashkg += parseFloat(row.f_amount); |
|
210 } |
|
211 if (row.f_added == 0 || row.f_added == 1) // Mash or Boil |
|
212 sugarsf += d; |
|
213 if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering |
|
214 var x = (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
215 addedS += row.f_amount * x; |
|
216 addedmass += row.f_amount; |
|
217 vol += (x * sugardensity + (1 - x) * 1) * row.f_amount; |
|
218 } |
|
219 if (row.f_added < 4) { |
|
220 colort += row.f_amount * ebc_to_srm(row.f_color); |
|
221 colorh += row.f_amount * row.f_color * get_kt(row.f_color); |
|
222 colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort. |
|
223 } |
|
224 if (fermentableInit) { |
|
225 if (row.f_added == 4) { |
|
226 $("#bottle_priming_total").val(row.f_amount * 1000); // Prevent clearing |
|
227 $("#bottle_priming_sugar").jqxDropDownList('selectItem', row.f_name); |
|
228 } |
|
229 if (row.f_added == 5) { |
|
230 $("#keg_priming_total").val(row.f_amount * 1000); |
|
231 $("#keg_priming_sugar").jqxDropDownList('selectItem', row.f_name); |
|
232 } |
|
233 } |
|
234 // Check supplies. |
|
235 if ((((dataRecord.inventory_reduced <= 2) && (row.f_added <= 1)) || // Mash or boil |
|
236 ((dataRecord.inventory_reduced <= 3) && (row.f_added == 2)) || // Primary |
|
237 ((dataRecord.inventory_reduced <= 5) && (row.f_added == 3)) || // Secondary or Tertiary |
|
238 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4)) || // Bottle |
|
239 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 5))) && row.f_inventory < row.f_amount) { |
|
240 ok_fermentables = 0; |
|
241 } |
|
242 if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50 |
|
243 lintner += row.f_diastatic_power * row.f_amount; |
|
244 } |
|
245 } |
|
246 fermentableInit = 0; |
|
247 $("#ferm_lintner").val(Math.round(parseFloat(lintner / mashkg))); |
|
248 $("#mash_kg").val(mashkg); |
|
249 console.log("calcFermentables() supplies:"+ok_fermentables+" moutsuiker:"+sugarsm+"/"+sugarsf); |
|
250 to_100 = my_100; |
|
251 if (to_100) { |
|
252 $("#wf_amount").jqxNumberInput({ width: 90, readOnly: true, spinButtons: false }); |
|
253 } else { |
|
254 $("#wf_amount").jqxNumberInput({ width: 110, readOnly: false, spinButtons: true }); |
|
255 } |
|
256 |
|
257 if (mvol > 0) { |
|
258 var v = s / sugardensity + mvol; |
|
259 s = 1000 * s / (v * 10); //deg. Plato |
|
260 est_mash_sg = Math.round(plato_to_sg(s) * 10000) / 10000; |
|
261 $('#est_mash_sg').val(est_mash_sg); |
|
262 } |
|
263 |
|
264 // Estimate total recipe OG. |
|
265 dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size)); |
|
266 $('#est_og').val(dataRecord.est_og); |
|
267 $('#est_og2').val(dataRecord.est_og); |
|
268 var org = dataRecord.est_og; |
|
269 |
|
270 // Estimate SG in kettle after boil |
|
271 aboil_sg = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size)); |
|
272 $('#est_og3').val(aboil_sg); |
|
273 |
|
274 // Estimate SG in kettle before boil |
|
275 preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size)); |
|
276 $('#est_pre_sg').val(preboil_sg); |
|
277 |
|
278 // Recalculate volumes. |
|
279 var aboil_volume = parseFloat(dataRecord.batch_size); |
|
280 if (dataRecord.brew_aboil_volume > 0) |
|
281 aboil_volume = dataRecord.brew_aboil_volume / 1.04; // volume @ 20 degrees |
|
282 if (dataRecord.brew_fermenter_tcloss == 0) { |
|
283 dataRecord.brew_fermenter_tcloss = dataRecord.eq_trub_chiller_loss; |
|
284 $("#brew_fermenter_tcloss").val(dataRecord.brew_fermenter_tcloss); |
|
285 } |
|
286 dataRecord.brew_fermenter_volume = aboil_volume - dataRecord.brew_fermenter_tcloss + dataRecord.brew_fermenter_extrawater; |
|
287 $("#brew_fermenter_volume").val(dataRecord.brew_fermenter_volume); |
|
288 // Estimated needed sparge water corrected for the temperature. |
|
289 var spoelw = (dataRecord.boil_size - mash_infuse + (mashkg * my_grain_absorbtion) + dataRecord.eq_lauter_deadspace) * 1.03; |
|
290 $("#brew_sparge_est").val(spoelw); |
|
291 |
|
292 // Calculate SG in fermenter |
|
293 var ogx = dataRecord.brew_aboil_sg; |
|
294 if (ogx < 1.002) |
|
295 ogx = aboil_sg; |
|
296 var top = dataRecord.brew_fermenter_extrawater; |
|
297 |
|
298 if (dataRecord.brew_fermenter_volume > 0) { |
|
299 var sug = sg_to_plato(ogx) * dataRecord.brew_fermenter_volume * ogx / 100; //kg of sugar in |
|
300 sug += addedS; //kg |
|
301 |
|
302 if ((dataRecord.brew_fermenter_volume * ogx + addedmass) > 0) { |
|
303 var pt = 100 * sug / (dataRecord.brew_fermenter_volume * ogx + addedmass + top); |
|
304 dataRecord.brew_fermenter_sg = Round(plato_to_sg(pt),4); |
|
305 $("#brew_fermenter_sg").val(dataRecord.brew_fermenter_sg); |
|
306 // color |
|
307 if (dataRecord.color_method == 4) { |
|
308 dataRecord.brew_fermenter_color = Math.round(((pt / 8.6) * colorn) + (dataRecord.boil_time / 60)); |
|
309 } else if (dataRecord.color_method == 3) { |
|
310 dataRecord.brew_fermenter_color = Math.round((4.46 * bv * sr) / (aboil_volume + top) * colorh); |
|
311 } else { |
|
312 var cw = colort / (aboil_volume + top) * 8.34436; |
|
313 dataRecord.brew_fermenter_color = kw_to_ebc(dataRecord.color_method, cw); |
|
314 } |
|
315 $("#brew_fermenter_color").val(dataRecord.brew_fermenter_color); |
|
316 var scolor = ebc_to_color(dataRecord.brew_fermenter_color); |
|
317 $("#bcolorf").show(); |
|
318 document.getElementById("bcolorf").style.background= scolor; |
|
319 } |
|
320 } else { |
|
321 // Negative volume |
|
322 dataRecord.brew_fermenter_sg = dataRecord.brew_fermenter_color = 0; |
|
323 $("#brew_fermenter_sg").val(0); |
|
324 $("#brew_fermenter_color").val(0); |
|
325 $("#bcolorf").hide(); |
|
326 } |
|
327 |
|
328 // Color of the wort |
|
329 if (dataRecord.color_method == 4) { |
|
330 var color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60)); |
|
331 } else if (dataRecord.color_method == 3) { // Hans Halberstadt |
|
332 var color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh); |
|
333 } else { |
|
334 var cw = colort / parseFloat(dataRecord.batch_size) * 8.34436; |
|
335 var color = kw_to_ebc(dataRecord.color_method, cw); |
|
336 } |
|
337 dataRecord.est_color = color; |
|
338 $('#est_color').val(color); |
|
339 $('#est_color2').val(color); |
|
340 var scolor = ebc_to_color(color); |
|
341 document.getElementById("bcolor").style.background= scolor; |
|
342 document.getElementById("bcolor2").style.background= scolor; |
|
343 |
|
344 // Progress bars |
|
345 pmalts = mashkg / dataRecord.eq_mash_max * 100; |
|
346 $("#perc_malts").jqxProgressBar('val', pmalts); |
|
347 $("#perc_sugars").jqxProgressBar('val', psugar); |
|
348 $("#perc_cara").jqxProgressBar('val', pcara); |
|
349 calcStage(); |
|
350 |
|
351 // Calculate estimated svg. |
|
352 svg = 0; // default. |
|
353 initcells = 0; |
|
354 var rows = $('#yeastGrid').jqxGrid('getrows'); |
|
355 for (var i = 0; i < rows.length; i++) { |
|
356 var row = rows[i]; |
|
357 if (row.y_use == 0) { // Primary |
|
358 if (parseFloat(row.y_attenuation) > svg) |
|
359 svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts. |
|
360 if (row.y_form == 0) |
|
361 initcells += (parseFloat(row.y_cells) / 1000000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100); |
|
362 else |
|
363 initcells += (parseFloat(row.y_cells) / 1000000) * parseFloat(row.y_amount); |
|
364 } |
|
365 // TODO: brett in secondary ?? |
|
366 if ((((dataRecord.inventory_reduced <= 3) && (row.y_use == 0)) || // Primary |
|
367 ((dataRecord.inventory_reduced <= 4) && (row.y_use == 1)) || // Secondary |
|
368 ((dataRecord.inventory_reduced <= 5) && (row.y_use == 2)) || // Tertiary |
|
369 ((dataRecord.inventory_reduced <= 6) && (row.y_use == 3))) && // Bottle |
|
370 (row.y_inventory < row.y_amount)) { |
|
371 ok_yeasts = 0; |
|
372 } |
|
373 } |
|
374 calcSupplies(); |
|
375 if (svg == 0) |
|
376 svg = 77; |
|
377 |
|
378 if ((mashkg > 0) && (mash_infuse > 0) && (mashtime > 0) && (mashtemp > 0)) { |
|
379 dataRecord.est_fg = estimate_fg(psugar, pcara, mash_infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og); |
|
380 } else { |
|
381 dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og); |
|
382 } |
|
383 $('#est_fg').val(dataRecord.est_fg); |
|
384 $('#est_fg2').val(dataRecord.est_fg); |
|
385 $('#est_fg3').val(dataRecord.est_fg); |
|
386 var fig = dataRecord.est_fg; |
|
387 |
|
388 dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg); |
|
389 $("#est_abv").val(dataRecord.est_abv); |
|
390 $("#est_abv2").val(dataRecord.est_abv); |
|
391 |
|
392 // Calculate the final svg if available use the real value. |
|
393 if ((dataRecord.stage >= 6) && (dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { |
|
394 svg = 100 * (dataRecord.brew_fermenter_sg - dataRecord.fg) / (dataRecord.brew_fermenter_sg - 1); |
|
395 org = dataRecord.brew_fermenter_sg; |
|
396 fig = dataRecord.fg; |
|
397 } |
|
398 |
|
399 $("#yeast_cells").val(initcells); |
|
400 $("#need_cells").val(getNeededYeastCells()); |
|
401 |
|
402 // Calculate the calories in kcal/l (from brouwhulp) |
|
403 var alc = 1881.22 * fig * (org - fig) / (1.775 - org); |
|
404 var sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004); |
|
405 $("#kcal").val(Math.round((alc + sug) / (12 * 0.0295735296))); |
|
406 }; |
|
407 |
|
408 function calcMash() { |
|
409 |
|
410 if (!(rows = $('#mashGrid').jqxGrid('getrows'))) |
|
411 return; |
|
412 if (mashkg == 0) |
|
413 return; |
|
414 |
|
415 var infused = 0; |
|
416 for (var i = 0; i < rows.length; i++) { |
|
417 var row = $("#mashGrid").jqxGrid('getrowdata', i); |
|
418 if (row.step_type == 0) // Infusion |
|
419 infused += row.step_infuse_amount; |
|
420 $("#mashGrid").jqxGrid('setcellvalue', i, "step_thickness", infused / mashkg); |
|
421 } |
|
422 } |
|
423 |
|
424 /* |
|
425 * Change OG of recipe but keep the water volumes. |
|
426 */ |
|
427 function calcFermentablesFromOG(OG) { |
|
428 |
|
429 console.log("calcFermentablesFromOG("+OG+")"); |
|
430 var efficiency = parseFloat($("#efficiency").jqxNumberInput('decimal')); |
|
431 var sug = sg_to_plato(OG) * parseFloat($("#batch_size").jqxNumberInput('decimal')) * OG / 100; //total amount of sugars in kg |
|
432 var tot = 0; |
|
433 var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; |
|
434 |
|
435 for (var i = 0; i < rowscount; i++) { |
|
436 var row = $("#fermentableGrid").jqxGrid('getrowdata', i); |
|
437 if (row.f_added < 4) { |
|
438 var d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
439 if (row.f_added == 0) // Mash |
|
440 d = efficiency / 100 * d; |
|
441 tot += d; |
|
442 } |
|
443 } |
|
444 var totmass = 0; |
|
445 if (tot) |
|
446 totmass = Math.round((sug / tot) * 1000) / 1000; |
|
447 |
|
448 if (totmass) { |
|
449 for (i = 0; i < rowscount; i++) { |
|
450 var row = $("#fermentableGrid").jqxGrid('getrowdata', i); |
|
451 if (row.f_added < 4) { |
|
452 var amount = Math.round(row.f_percentage * 10 * totmass) / 1000; |
|
453 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount); |
|
454 } |
|
455 } |
|
456 } |
|
457 }; |
|
458 |
|
459 function getNeededYeastCells() { |
|
460 |
|
461 var sg = dataRecord.brew_fermenter_sg; |
|
462 if (sg <= 1.0001 && dataRecord.fg > 1.000) |
|
463 sg = dataRecord.fg; |
|
464 else if (sg <= 1.0001) |
|
465 sg = dataRecord.est_og; |
|
466 var plato = sg_to_plato(sg); |
|
467 |
|
468 var volume = dataRecord.brew_fermenter_volume; |
|
469 if (volume <= 0) |
|
470 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; |
|
471 |
|
472 var result = pitchrate * volume * plato; |
|
473 return result; |
|
474 } |
|
475 |
|
476 function hopFlavourContribution(bt, vol, use, amount) { |
|
477 var result; |
|
478 |
|
479 if (use == 1) { // First wort |
|
480 result = 0.15; // assume 15% flavourcontribution for fwh |
|
481 } else if (bt > 50) { |
|
482 result = 0.10; // assume 10% flavourcontribution as a minimum |
|
483 } else { |
|
484 result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) /6, 2)); |
|
485 if (result < 0.10) |
|
486 result = 0.10; // assume 10% flavourcontribution as a minimum |
|
487 } |
|
488 return (result * amount * 1000) / vol; |
|
489 } |
|
490 |
|
491 function hopAromaContribution(bt, vol, use, amount) { |
|
492 var result = 0; |
|
493 |
|
494 if (use == 5) { // Dry hop |
|
495 result = 1.33; |
|
496 } else if (bt > 20) { |
|
497 result = 0; |
|
498 } else if (bt > 7.5) { |
|
499 result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) /4, 2)); |
|
500 } else if (use == 2) { // Boil |
|
501 result = 1; |
|
502 } else if (use == 3) { // Aroma |
|
503 result = 1.2; |
|
504 } else if (use == 4) { // Whirlpool |
|
505 result = 1.2; |
|
506 } |
|
507 return (result * amount * 1000) / vol; |
|
508 } |
|
509 |
|
510 function calcIBUs() { |
|
511 var total_ibus = 0; |
|
512 var ferm_ibus = 0; |
|
513 var rows = {}; |
|
514 hop_aroma = hop_flavour = 0; |
|
515 if (!(rows = $('#hopGrid').jqxGrid('getrows'))) { |
|
516 return; |
|
517 } |
|
518 ok_hops = 1; |
|
519 for (var i = 0; i < rows.length; i++) { |
|
520 var row = rows[i]; |
|
521 total_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, parseFloat(dataRecord.batch_size), |
|
522 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method); |
|
523 ferm_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, |
|
524 parseFloat(dataRecord.brew_fermenter_volume) + parseFloat(dataRecord.brew_fermenter_tcloss), |
|
525 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method); |
|
526 hop_flavour += hopFlavourContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), |
|
527 row.h_useat, parseFloat(row.h_amount)); |
|
528 hop_aroma += hopAromaContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), |
|
529 row.h_useat, parseFloat(row.h_amount)); |
|
530 if ((((dataRecord.inventory_reduced <= 2) && (row.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool |
|
531 ((dataRecord.inventory_reduced <= 6) && (row.h_useat == 5))) && // Dry-hop |
|
532 (row.h_inventory < row.h_amount)) |
|
533 ok_hops = 0; |
|
534 } |
|
535 total_ibus = Math.round(total_ibus * 10) / 10; |
|
536 ferm_ibus = Math.round(ferm_ibus * 10) / 10; |
|
537 hop_flavour = Math.round(hop_flavour * 1000 / 5) / 10; |
|
538 hop_aroma = Math.round(hop_aroma * 1000 / 6) / 10; |
|
539 if (hop_flavour > 100) |
|
540 hop_flavour = 100; |
|
541 if (hop_aroma > 100) |
|
542 hop_aroma = 100; |
|
543 console.log("calcIBUs(): " + total_ibus + " flavour: " + hop_flavour + " aroma: " + hop_aroma+" fermenter:"+ferm_ibus+" supplies:"+ok_hops); |
|
544 dataRecord.est_ibu = total_ibus; |
|
545 $('#est_ibu').val(total_ibus); |
|
546 $('#est_ibu2').val(total_ibus); |
|
547 $("#hop_flavour").jqxProgressBar('val', hop_flavour); |
|
548 $("#hop_aroma").jqxProgressBar('val', hop_aroma); |
|
549 $("#brew_fermenter_ibu").val(ferm_ibus); |
|
550 calcStage(); |
|
551 calcSupplies(); |
|
552 }; |
|
553 |
|
554 /* |
|
555 * http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ |
|
556 * |
|
557 * stype: 0=stirred, 1=shaken, 2=simple |
|
558 * totcells: initial cells |
|
559 * egrams: gram extract |
|
560 */ |
|
561 function getGrowthRate(stype, totcells, egrams){ |
|
562 |
|
563 /* Cells per grams extract (B/g) */ |
|
564 var cpe = totcells / egrams; |
|
565 |
|
566 if (cpe > 3.5) |
|
567 return 0; // no growth |
|
568 if (stype == 2) |
|
569 return 0.4; // simple starter |
|
570 if (stype == 1) |
|
571 return 0.62; // shaken starter |
|
572 if (cpe <= 1.4) // stirred starter |
|
573 return 1.4; |
|
574 return 2.33 - (.67 * cpe ); |
|
575 }; |
|
576 |
|
577 function calcStep(svol, stype, start) { |
|
578 |
|
579 var gperpoint = 2.72715; //number of grams of extract per point of starter gravity per liter |
|
580 var prate = start/svol * 1000; |
|
581 var irate = Math.round(prate * 10) / 10; |
|
582 var egrams = (dataRecord.starter_sg - 1) * svol * gperpoint; |
|
583 var grate = getGrowthRate(stype, start, egrams); |
|
584 var ncells = Math.round(egrams * grate * 10) / 10; |
|
585 var totcells = parseFloat(ncells) + start; |
|
586 console.log("svol:"+svol+" start:"+start+" irate:"+irate+" egrams:"+egrams+" grate:"+grate+" ncells:"+ncells); |
|
587 return { |
|
588 svol: svol, |
|
589 irate: irate, |
|
590 prate: Math.round(prate * 10)/10, |
|
591 ncells: ncells, |
|
592 totcells: totcells, |
|
593 growf: Math.round(ncells/start*100)/100 |
|
594 }; |
|
595 } |
|
596 |
|
597 /* |
|
598 * Calculate all starter steps. |
|
599 * stype: final starter type: 0 = stirred, 1 = shaked, 2 = simple. |
|
600 * start: initial cells in billions |
|
601 * needed: needed cells in billions |
|
602 * |
|
603 * result: all values updated. |
|
604 */ |
|
605 function calcSteps(stype, start, needed) { |
|
606 |
|
607 var uvols = [ 20, 40, 60, 80, 100, 150, 200, 250, 375, 500, 625, 750, 875, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000 ]; |
|
608 var mvols = uvols.length; |
|
609 var svol = 0; |
|
610 var lasti = 0; |
|
611 var result = {}; |
|
612 |
|
613 /* |
|
614 * If no values are set, auto calculate the starter. |
|
615 */ |
|
616 if ((parseFloat($("#prop1_volume").jqxNumberInput('decimal')) + parseFloat($("#prop2_volume").jqxNumberInput('decimal')) + |
|
617 parseFloat($("#prop3_volume").jqxNumberInput('decimal')) + parseFloat($("#prop4_volume").jqxNumberInput('decimal'))) == 0) { |
|
618 // clear by default |
|
619 for (var i = 1; i < 5; i++) { |
|
620 $("#prop"+i+"_type").hide(); |
|
621 $("#r"+i+"_pmpt").show(); |
|
622 $("#prop"+i+"_type").val(stype); |
|
623 $("#prop"+i+"_volume").hide(); |
|
624 $("#prop"+i+"_volume").val(0); |
|
625 $("#prop"+i+"_irate").hide(); |
|
626 $("#prop"+i+"_ncells").hide(); |
|
627 $("#prop"+i+"_tcells").hide(); |
|
628 $("#prop"+i+"_growf").hide(); |
|
629 } |
|
630 if (start > needed) { |
|
631 return; // no starter needed |
|
632 } |
|
633 $("#prop1_type").show(); |
|
634 $("#r1_pmpt").hide(); |
|
635 $("#prop1_volume").show(); |
|
636 $("#prop1_irate").show(); |
|
637 $("#prop1_ncells").show(); |
|
638 $("#prop1_tcells").show(); |
|
639 $("#prop1_growf").show(); |
|
640 for (var i = lasti; i <= mvols; i++) { |
|
641 lasti = i; |
|
642 svol = uvols[lasti]; |
|
643 result = calcStep(svol, stype, start); |
|
644 if (result.irate < 25) { |
|
645 // inocculation rate too low, backup one step and break out. |
|
646 lasti = i - 1; |
|
647 svol = uvols[lasti]; |
|
648 result = calcStep(svol, stype, start); |
|
649 break; |
|
650 } |
|
651 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
652 break; |
|
653 } |
|
654 } |
|
655 $("#prop1_volume").val(result.svol / 1000); // to liters |
|
656 $("#prop1_irate").val(result.prate); |
|
657 $("#prop1_ncells").val(result.ncells); |
|
658 $("#prop1_tcells").val(result.totcells); |
|
659 $("#prop1_growf").val(result.growf); |
|
660 if (result.totcells > needed) |
|
661 return; // hit the target |
|
662 |
|
663 // second stage |
|
664 $("#r2_pmpt").hide(); |
|
665 $("#prop2_type").val(stype); |
|
666 $("#prop2_type").show(); |
|
667 $("#prop2_volume").show(); |
|
668 $("#prop2_irate").show(); |
|
669 $("#prop2_ncells").show(); |
|
670 $("#prop2_tcells").show(); |
|
671 $("#prop2_growf").show(); |
|
672 for (var i = lasti; i <= mvols; i++) { |
|
673 lasti = i; |
|
674 svol = uvols[lasti]; |
|
675 result = calcStep(svol, stype, $("#prop1_tcells").val()); |
|
676 if (result.irate < 25) { |
|
677 lasti = i - 1; |
|
678 svol = uvols[lasti]; |
|
679 result = calcStep(svol, stype, $("#prop1_tcells").val()); |
|
680 break; |
|
681 } |
|
682 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
683 break; |
|
684 } |
|
685 } |
|
686 $("#prop2_volume").val(result.svol / 1000); // to liters |
|
687 $("#prop2_irate").val(result.prate); |
|
688 $("#prop2_ncells").val(result.ncells); |
|
689 $("#prop2_tcells").val(result.totcells); |
|
690 $("#prop2_growf").val(result.growf); |
|
691 if (result.totcells > needed) |
|
692 return; // hit the target |
|
693 |
|
694 // third stage |
|
695 $("#r3_pmpt").hide(); |
|
696 $("#prop3_type").val(stype); |
|
697 $("#prop3_type").show(); |
|
698 $("#prop3_volume").show(); |
|
699 $("#prop3_irate").show(); |
|
700 $("#prop3_ncells").show(); |
|
701 $("#prop3_tcells").show(); |
|
702 $("#prop3_growf").show(); |
|
703 for (var i = lasti; i <= mvols; i++) { |
|
704 lasti = i; |
|
705 svol = uvols[lasti]; |
|
706 result = calcStep(svol, stype, $("#prop2_tcells").val()); |
|
707 if (result.irate < 25) { |
|
708 lasti = i - 1; |
|
709 svol = uvols[lasti]; |
|
710 result = calcStep(svol, stype, $("#prop2_tcells").val()); |
|
711 break; |
|
712 } |
|
713 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
714 break; |
|
715 } |
|
716 } |
|
717 $("#prop3_volume").val(result.svol / 1000); // to liters |
|
718 $("#prop3_irate").val(result.prate); |
|
719 $("#prop3_ncells").val(result.ncells); |
|
720 $("#prop3_tcells").val(result.totcells); |
|
721 $("#prop3_growf").val(result.growf); |
|
722 if (result.totcells > needed) |
|
723 return; // hit the target |
|
724 |
|
725 // fourth stage |
|
726 $("#r4_pmpt").hide(); |
|
727 $("#prop4_type").val(stype); |
|
728 $("#prop4_type").show(); |
|
729 $("#prop4_volume").show(); |
|
730 $("#prop4_irate").show(); |
|
731 $("#prop4_ncells").show(); |
|
732 $("#prop4_tcells").show(); |
|
733 $("#prop4_growf").show(); |
|
734 for (var i = lasti; i <= mvols; i++) { |
|
735 lasti = i; |
|
736 svol = uvols[lasti]; |
|
737 result = calcStep(svol, stype, $("#prop3_tcells").val()); |
|
738 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
739 $("#prop4_volume").val(result.svol / 1000); // to liters |
|
740 $("#prop4_irate").val(result.prate); |
|
741 $("#prop4_ncells").val(result.ncells); |
|
742 $("#prop4_tcells").val(result.totcells); |
|
743 $("#prop4_growf").val(result.growf); |
|
744 return; |
|
745 } |
|
746 } |
|
747 } else { |
|
748 // recalculate |
|
749 if (dataRecord.prop1_volume > 0) { |
|
750 $("#r1_pmpt").hide(); |
|
751 $("#prop1_type").show(); |
|
752 $("#prop1_volume").show(); |
|
753 $("#prop1_irate").show(); |
|
754 $("#prop1_ncells").show(); |
|
755 $("#prop1_tcells").show(); |
|
756 $("#prop1_growf").show(); |
|
757 result = calcStep($("#prop1_volume").val() * 1000, dataRecord.prop1_type, start); |
|
758 $("#prop1_irate").val(result.prate); |
|
759 $("#prop1_ncells").val(result.ncells); |
|
760 $("#prop1_tcells").val(result.totcells); |
|
761 $("#prop1_growf").val(result.growf); |
|
762 } |
|
763 if (dataRecord.prop2_volume > 0) { |
|
764 $("#r2_pmpt").hide(); |
|
765 $("#prop2_type").show(); |
|
766 $("#prop2_volume").show(); |
|
767 $("#prop2_irate").show(); |
|
768 $("#prop2_ncells").show(); |
|
769 $("#prop2_tcells").show(); |
|
770 $("#prop2_growf").show(); |
|
771 result = calcStep($("#prop2_volume").val() * 1000, dataRecord.prop2_type, $("#prop1_tcells").val()); |
|
772 $("#prop2_irate").val(result.prate); |
|
773 $("#prop2_ncells").val(result.ncells); |
|
774 $("#prop2_tcells").val(result.totcells); |
|
775 $("#prop2_growf").val(result.growf); |
|
776 } |
|
777 if (dataRecord.prop3_volume > 0) { |
|
778 $("#r3_pmpt").hide(); |
|
779 $("#prop3_type").show(); |
|
780 $("#prop3_volume").show(); |
|
781 $("#prop3_irate").show(); |
|
782 $("#prop3_ncells").show(); |
|
783 $("#prop3_tcells").show(); |
|
784 $("#prop3_growf").show(); |
|
785 result = calcStep($("#prop3_volume").val() * 1000, dataRecord.prop3_type, $("#prop2_tcells").val()); |
|
786 $("#prop3_irate").val(result.prate); |
|
787 $("#prop3_ncells").val(result.ncells); |
|
788 $("#prop3_tcells").val(result.totcells); |
|
789 $("#prop3_growf").val(result.growf); |
|
790 } |
|
791 if (dataRecord.prop4_volume > 0) { |
|
792 $("#r4_pmpt").hide(); |
|
793 $("#prop4_type").show(); |
|
794 $("#prop4_volume").show(); |
|
795 $("#prop4_irate").show(); |
|
796 $("#prop4_ncells").show(); |
|
797 $("#prop4_tcells").show(); |
|
798 $("#prop4_growf").show(); |
|
799 result = calcStep($("#prop4_volume").val() * 1000, dataRecord.prop4_type, $("#prop3_tcells").val()); |
|
800 $("#prop4_irate").val(result.prate); |
|
801 $("#prop4_ncells").val(result.ncells); |
|
802 $("#prop4_tcells").val(result.totcells); |
|
803 $("#prop4_growf").val(result.growf); |
|
804 } |
|
805 |
|
806 } |
|
807 } |
|
808 |
|
809 function calcYeast() { |
|
810 |
|
811 // Calculate needed cells. |
|
812 var sg = dataRecord.brew_fermenter_sg; |
|
813 if (sg <= 1.0001 && dataRecord.fg > 1.000) |
|
814 sg = dataRecord.fg; |
|
815 else if (sg <= 1.0001) |
|
816 sg = dataRecord.est_og; |
|
817 var plato = sg_to_plato(sg); |
|
818 |
|
819 var volume = dataRecord.brew_fermenter_volume; |
|
820 if (volume > 0) { |
|
821 if (dataRecord.brew_fermenter_extrawater > 0) |
|
822 volume += dataRecord.brew_fermenter_extrawater; |
|
823 } else { |
|
824 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; |
|
825 } |
|
826 |
|
827 // Also in calcFermentables() |
|
828 $("#yeast_cells").val(initcells); |
|
829 |
|
830 if (!(rows = $('#yeastGrid').jqxGrid('getrows'))) { |
|
831 return; // grid not yet loaded. |
|
832 } |
|
833 var rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount; |
|
834 if (rowscount == 0) |
|
835 return; // no yeast in recipe |
|
836 |
|
837 for (var i = 0; i < rowscount; i++) { |
|
838 var row = $("#yeastGrid").jqxGrid('getrowdata', i); |
|
839 if (row.y_use == 0) { // primary |
|
840 // pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/ |
|
841 // and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ |
|
842 pitchrate = 0.75; |
|
843 if (dataRecord.est_og > 1.060) |
|
844 pitchrate = 1.0; |
|
845 // if (dataRecord.est_og > 1.076) |
|
846 // pitchrate = 1.25; // Wyeast labs. http://www.wyeastlab.com/hb_pitchrates.cfm |
|
847 if (row.y_type == 0) // lager yeast |
|
848 pitchrate *= 2; |
|
849 |
|
850 if (row.y_form == 1) { // dry yeast |
|
851 } else { // possible starter needed |
|
852 } |
|
853 } |
|
854 } |
|
855 var needed = pitchrate * volume * plato; |
|
856 console.log("calcYeast() pitchrate:"+pitchrate+" start:"+initcells+" needed:"+needed+" volume:"+volume); |
|
857 $("#need_cells").val(needed); |
|
858 var use_cells = initcells; |
|
859 |
|
860 if (dataRecord.starter_enable) { |
|
861 calcSteps(dataRecord.starter_type, initcells, needed); |
|
862 |
|
863 for (var i = 1; i < 5; i++) { |
|
864 $("#r"+i+"_irate").html(""); |
|
865 $("#r"+i+"_growf").html(""); |
|
866 $("#r"+i+"_tcells").html(""); |
|
867 if (parseFloat($("#prop"+i+"_volume").val()) > 0) { |
|
868 if ((parseFloat($("#prop"+i+"_irate").val()) < 25) || (parseFloat($("#prop"+i+"_irate").val()) > 100)) { |
|
869 $("#r"+i+"_irate").html("<img src='images/dialog-error.png'>"); |
|
870 } else { |
|
871 $("#r"+i+"_irate").html("<img src='images/dialog-ok-apply.png'>"); |
|
872 } |
|
873 if (parseFloat($("#prop"+i+"_growf").val()) < 1) |
|
874 $("#r"+i+"_growf").html("<img src='images/dialog-error.png'>"); |
|
875 if (($("#prop"+i+"_type").val() > 0) && (parseFloat($("#prop"+i+"_growf").val()) > 3)) |
|
876 $("#r"+i+"_growf").html("<img src='images/dialog-error.png'>"); |
|
877 if (parseFloat($("#prop"+i+"_tcells").val()) > needed) |
|
878 $("#r"+i+"_tcells").html("<img src='images/dialog-ok-apply.png'>"); |
|
879 use_cells = parseFloat($("#prop"+i+"_tcells").val()); |
|
880 } else { |
|
881 $("#r"+i+"_irate").html(""); |
|
882 } |
|
883 } |
|
884 } |
|
885 $("#plato_cells").val(parseFloat(use_cells / (volume * plato) )); |
|
886 }; |
|
887 |
|
888 function adjustHops(factor) { |
|
889 |
|
890 console.log("adjustHops("+factor+")"); |
|
891 |
|
892 var rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount; |
|
893 if (rowscount == 0) |
|
894 return; |
|
895 |
|
896 for (var i = 0; i < rowscount; i++) { |
|
897 var row = $("#hopGrid").jqxGrid('getrowdata', i); |
|
898 var amount = row.h_amount * factor; |
|
899 $("#hopGrid").jqxGrid('setcellvalue', i, "h_amount", amount); |
|
900 } |
|
901 }; |
|
902 |
|
903 function calcMiscs() { |
|
904 |
|
905 ok_miscs = 1; |
|
906 var rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount; |
|
907 |
|
908 if (rowscount == 0) |
|
909 return; |
|
910 |
|
911 for (var i = 0; i < rowscount; i++) { |
|
912 var row = $("#miscGrid").jqxGrid('getrowdata', i); |
|
913 if ((((dataRecord.inventory_reduced <= 2) && (row.m_use_use <= 2)) || // Starter, Mash, Boil |
|
914 ((dataRecord.inventory_reduced <= 3) && (row.m_use_use == 3)) || // Primary |
|
915 ((dataRecord.inventory_reduced <= 5) && (row.m_use_use == 4)) || // Secondary, Teriary |
|
916 ((dataRecord.inventory_reduced <= 6) && (row.m_use_use == 5))) && // Bottle |
|
917 (row.m_inventory < row.m_amount)) { |
|
918 ok_miscs = 0; |
|
919 } |
|
920 } |
|
921 calcSupplies(); |
|
922 }; |
|
923 |
|
924 function adjustMiscs(factor) { |
|
925 |
|
926 console.log("adjustMiscs("+factor+")"); |
|
927 |
|
928 var rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount; |
|
929 if (rowscount == 0) |
|
930 return; |
|
931 |
|
932 for (var i = 0; i < rowscount; i++) { |
|
933 var row = $("#miscGrid").jqxGrid('getrowdata', i); |
|
934 var amount = row.m_amount * factor; |
|
935 $("#miscGrid").jqxGrid('setcellvalue', i, "m_amount", amount); |
|
936 switch (row.m_name) { |
|
937 case 'CaCl2': $("#wa_cacl2").val(row.m_amount * 1000); |
|
938 break; |
|
939 case 'CaSO4': $("#wa_caso4").val(row.m_amount * 1000); |
|
940 break; |
|
941 case 'MgSO4': $("#wa_mgso4").val(row.m_amount * 1000); |
|
942 break; |
|
943 case 'NaCl': $("#wa_nacl").val(row.m_amount * 1000); |
|
944 break; |
|
945 case 'Melkzuur': |
|
946 case 'Zoutzuur': |
|
947 case 'Fosforzuur': |
|
948 case 'Zwavelzuur': $("#wa_acid").val(row.m_amount * 1000); |
|
949 break; |
|
950 case 'NaHCO3': |
|
951 case 'Na2CO3': |
|
952 case 'CaCO3': |
|
953 case 'Ca(OH)2': $("#wa_base").val(row.m_amount * 1000); |
|
954 break; |
|
955 } |
|
956 } |
|
957 }; |
|
958 |
|
959 function adjustYeasts(factor) { |
|
960 |
|
961 console.log("adjustYeasts("+factor+")"); |
|
962 |
|
963 var rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount; |
|
964 if (rowscount == 0) |
|
965 return; |
|
966 |
|
967 for (var i = 0; i < rowscount; i++) { |
|
968 var row = $("#yeastGrid").jqxGrid('getrowdata', i); |
|
969 if (row.y_form == 1) { // Only adjust dry yeast |
|
970 var amount = row.y_amount * factor; |
|
971 $("#yeastGrid").jqxGrid('setcellvalue', i, "y_amount", amount); |
|
972 } |
|
973 } |
|
974 |
|
975 calcYeast(); |
|
976 }; |
|
977 |
|
978 function adjustWaters(factor) { |
|
979 |
|
980 console.log("adjustWaters("+factor+")"); |
|
981 |
|
982 var rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount; |
|
983 if (rowscount == 0) |
|
984 return; |
|
985 |
|
986 mash_infuse = 0; |
|
987 for (var i = 0; i < rowscount; i++) { |
|
988 var row = $("#mashGrid").jqxGrid('getrowdata', i); |
|
989 if (row.step_type == 0) { // Infusion |
|
990 var amount = Math.round(row.step_infuse_amount * factor * 10) / 10; |
|
991 $("#mashGrid").jqxGrid('setcellvalue', i, "step_infuse_amount", amount); |
|
992 mash_infuse += amount; |
|
993 } |
|
994 } |
|
995 if (dataRecord.w2_amount == 0) { |
|
996 dataRecord.w1_amount = mash_infuse; |
|
997 $("#w1_amount").val(mash_infuse); |
|
998 } else { |
|
999 dataRecord.w1_amount = (dataRecord.w1_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse; |
|
1000 dataRecord.w2_amount = (dataRecord.w2_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse; |
|
1001 $("#w1_amount").val(dataRecord.w1_amount); |
|
1002 $("#w2_amount").val(dataRecord.w2_amount); |
|
1003 } |
|
1004 $('#wg_amount').val(mash_infuse); |
|
1005 }; |
|
1006 |
|
1007 |
|
1008 |
|
1009 function calcMashEfficiency() { |
|
1010 if (parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')) < 1.002) |
|
1011 return; |
|
1012 var c = sg_to_plato(est_mash_sg); |
|
1013 var m = sg_to_plato(parseFloat($("#brew_mash_sg").jqxNumberInput('decimal'))); |
|
1014 if (c > 0.5) |
|
1015 $("#brew_mash_efficiency").val(100 * m / c); |
|
1016 else |
|
1017 $("#brew_mash_efficiency").val(0); |
|
1018 }; |
|
1019 |
|
1020 function calcEfficiencyBeforeBoil() { |
|
1021 var m = 0; |
|
1022 var rows = {}; |
|
1023 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { |
|
1024 return; // grid not yet loaded. |
|
1025 } |
|
1026 for (var i = 0; i < rows.length; i++) { |
|
1027 var row = rows[i]; |
|
1028 if (row.f_added == 0) { // Mash |
|
1029 m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
1030 } |
|
1031 } |
|
1032 var tot = sg_to_plato(dataRecord.brew_preboil_sg) * (dataRecord.brew_preboil_volume / 1.04) * dataRecord.brew_preboil_sg * 10 / 1000; |
|
1033 var result = 0; |
|
1034 if (m > 0) |
|
1035 result = Math.round((tot / m * 100) * 10) / 10; |
|
1036 if (result < 0) |
|
1037 result = 0; |
|
1038 $("#brew_preboil_efficiency").val(result); |
|
1039 } |
|
1040 |
|
1041 function calcEfficiencyAfterBoil() { |
|
1042 var m = 0; // Sugars added at mash |
|
1043 var b = 0; // Sugars added at boil |
|
1044 var rows = {}; |
|
1045 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { |
|
1046 return; // grid not yet loaded. |
|
1047 } |
|
1048 for (var i = 0; i < rows.length; i++) { |
|
1049 var row = rows[i]; |
|
1050 if (row.f_added == 0) { // Mash |
|
1051 m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
1052 } else if (row.f_added == 1) { // Boil |
|
1053 b += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
1054 } |
|
1055 } |
|
1056 var tot = sg_to_plato(dataRecord.brew_aboil_sg) * (dataRecord.brew_aboil_volume / 1.04) * dataRecord.brew_aboil_sg * 10 / 1000; |
|
1057 tot -= b; // total sugars in wort minus added sugars. |
|
1058 var result = 0; |
|
1059 if (m > 0) |
|
1060 result = Math.round((tot / m * 100) * 10) / 10; |
|
1061 if (result < 0) |
|
1062 result = 0; |
|
1063 dataRecord.brew_aboil_efficiency = result; |
|
1064 $("#brew_aboil_efficiency").val(result); |
|
1065 |
|
1066 } |
|
1067 |
|
1068 function GetBUGU() { |
|
1069 var gu = (dataRecord.est_og - 1) * 1000; |
|
1070 if (gu > 0) |
|
1071 return dataRecord.est_ibu / gu; |
|
1072 else |
|
1073 return 0.5; |
|
1074 } |
|
1075 |
|
1076 function GetOptClSO4ratio() { |
|
1077 var BUGU = GetBUGU(); |
|
1078 return (-1.2 * BUGU + 1.4); |
|
1079 } |
|
1080 |
|
1081 function setWaterAgent(name, amount) { |
|
1082 var rows = $('#miscGrid').jqxGrid('getrows'); |
|
1083 if (amount == 0) { |
|
1084 for (var i = 0; i < rows.length; i++) { |
|
1085 var row = rows[i]; |
|
1086 if (row.m_name == name) { |
|
1087 var id = $("#miscGrid").jqxGrid('getrowid', i); |
|
1088 $("#miscGrid").jqxGrid('deleterow', id); |
|
1089 } |
|
1090 } |
|
1091 } else { |
|
1092 var found = false; |
|
1093 for (var i = 0; i < rows.length; i++) { |
|
1094 var row = rows[i]; |
|
1095 if (row.m_name == name) { |
|
1096 found = true; |
|
1097 $("#miscGrid").jqxGrid('setcellvalue', i, 'm_amount', amount / 1000); |
|
1098 break; |
|
1099 } |
|
1100 } |
|
1101 if (! found) { |
|
1102 var miscs = new $.jqx.dataAdapter(miscInvSource, { |
|
1103 loadComplete: function () { |
|
1104 var records = miscs.records; |
|
1105 for (var i = 0; i < records.length; i++) { |
|
1106 var record = records[i]; |
|
1107 if (record.name == name) { |
|
1108 var row = {}; |
|
1109 row["m_name"] = record.name; |
|
1110 row["m_amount"] = amount / 1000; |
|
1111 row["m_cost"] = record.cost; |
|
1112 row["m_type"] = record.type; |
|
1113 row["m_use_use"] = record.use_use; |
|
1114 row["m_time"] = 0; |
|
1115 row["m_amount_is_weight"] = record.amount_is_weight; |
|
1116 row["m_inventory"] = record.inventory; |
|
1117 row["m_avail"] = 1; |
|
1118 $("#miscGrid").jqxGrid('addrow', null, row); |
|
1119 } |
|
1120 } |
|
1121 } |
|
1122 }); |
|
1123 miscs.dataBind(); |
|
1124 return; |
|
1125 } |
|
1126 } |
|
1127 } |
|
1128 |
|
1129 function setRangeIndicator(ion, rangeCode) { |
|
1130 if ((rangeCode == "laag") || (rangeCode == "hoog")) |
|
1131 $("#wr_"+ion).html("<img src='images/dialog-error.png'><span style='vertical-align: top; font-size: 10px; font-style: italic;'>"+rangeCode + "</span>"); |
|
1132 else |
|
1133 $("#wr_"+ion).html("<img src='images/dialog-ok-apply.png'>"); |
|
1134 } |
|
1135 |
|
1136 function mix(v1, v2, c1, c2) { |
|
1137 if ((v1 + v2) > 0) { |
|
1138 return ((v1 * c1) + (v2 * c2)) / (v1 + v2); |
|
1139 } |
|
1140 return 0; |
|
1141 } |
|
1142 |
|
1143 // mg/l as CaCO3 |
|
1144 function ResidualAlkalinity(total_alkalinity, calcium, magnesium) { |
|
1145 return total_alkalinity - (calcium / 1.4 + magnesium / 1.7); |
|
1146 } |
|
1147 |
|
1148 var Ka1 = 0.0000004445; |
|
1149 var Ka2 = 0.0000000000468; |
|
1150 |
|
1151 function PartCO3(pH) { |
|
1152 var H = Math.pow(10, -pH); |
|
1153 return 100 * Ka1 * Ka2 / (H*H + H * Ka1 + Ka1 * Ka2); |
|
1154 } |
|
1155 |
|
1156 function PartHCO3(pH) { |
|
1157 var H = Math.pow(10, -pH); |
|
1158 return 100 * Ka1 * H / (H*H + H * Ka1 + Ka1 * Ka2); |
|
1159 } |
|
1160 |
|
1161 function Charge(pH) { |
|
1162 return (-2 * PartCO3(pH) - PartHCO3(pH)); |
|
1163 } |
|
1164 |
|
1165 //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) |
|
1166 function ZAlkalinity(pHZ) { |
|
1167 var C43 = Charge(4.3); |
|
1168 var Cw = Charge(parseFloat($("#wg_ph").jqxNumberInput('decimal'))); |
|
1169 var Cz = Charge(pHZ); |
|
1170 var DeltaCNaught = -C43+Cw; |
|
1171 var CT = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')) / 50 / DeltaCNaught; |
|
1172 var DeltaCZ = -Cz+Cw; |
|
1173 return CT * DeltaCZ; |
|
1174 } |
|
1175 |
|
1176 //Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH) |
|
1177 function ZRA(pHZ) { |
|
1178 |
|
1179 var Calc = parseFloat($("#wg_calcium").jqxNumberInput('decimal')) / (MMCa / 2); |
|
1180 var Magn = parseFloat($("#wg_magnesium").jqxNumberInput('decimal')) / (MMMg / 2); |
|
1181 var Z = ZAlkalinity(pHZ); |
|
1182 return Z - (Calc / 3.5 + Magn / 7); |
|
1183 } |
|
1184 |
|
1185 function ProtonDeficit(pHZ) { |
|
1186 |
|
1187 var Result = ZRA(pHZ) * parseFloat($("#wg_amount").jqxNumberInput('decimal')); |
|
1188 // proton deficit for the grist |
|
1189 var rows = $('#fermentableGrid').jqxGrid('getrows'); |
|
1190 for (var i = 0; i < rows.length; i++) { |
|
1191 var row = rows[i]; |
|
1192 if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt |
|
1193 // Check if acid is required |
|
1194 var C1 = 0; |
|
1195 if ((row.f_di_ph != 5.7) && ((row.f_acid_to_ph_57 < - 0.1) || (row.f_acid_to_ph_57 > 0.1))) { |
|
1196 C1 = row.f_acid_to_ph_57 / (row.f_di_ph - 5.7); |
|
1197 } else { |
|
1198 // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid. |
|
1199 var ebc = row.f_color; |
|
1200 switch (row.f_graintype) { |
|
1201 case 0: // Base, Special, Kilned |
|
1202 case 3: |
|
1203 case 5: C1 = 0.014 * ebc - 34.192; |
|
1204 break; |
|
1205 case 2: C1 = -0.0597 * ebc - 32.457; // Crystal |
|
1206 break; |
|
1207 case 1: C1 = 0.0107 * ebc - 54.768; // Roast |
|
1208 break; |
|
1209 case 4: C1 = -149; // Sour malt |
|
1210 break; |
|
1211 } |
|
1212 } |
|
1213 x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH) |
|
1214 Result += x * row.f_amount; |
|
1215 } |
|
1216 } |
|
1217 return Result; |
|
1218 } |
|
1219 |
|
1220 function MashpH() { |
|
1221 var n = 0; |
|
1222 var pH = 5.4; |
|
1223 var deltapH = 0.001; |
|
1224 var deltapd = 0.1; |
|
1225 var pd = ProtonDeficit(pH); |
|
1226 while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) { |
|
1227 n++; |
|
1228 if (pd < -deltapd) |
|
1229 pH -= deltapH; |
|
1230 else if (pd > deltapd) |
|
1231 pH += deltapH; |
|
1232 pd = ProtonDeficit(pH); |
|
1233 } |
|
1234 console.log("MashpH() n: "+n+" pH: "+pH); |
|
1235 return pH; |
|
1236 } |
|
1237 |
|
1238 function GetAcidSpecs(AT) { |
|
1239 switch(AT) { |
|
1240 case 0: return { // Melkzuur |
|
1241 pK1: 3.86, |
|
1242 pK2: 20, |
|
1243 pK3: 20, |
|
1244 MolWt: 90.08, |
|
1245 AcidSG: 1214, // 1214 1209 |
|
1246 AcidPrc: 0.88 // 0.88 0.80 |
|
1247 }; |
|
1248 case 1: return { // Zoutzuur |
|
1249 pK1: -7, |
|
1250 pK2: 20, |
|
1251 pK3: 20, |
|
1252 MolWt: 36.46, |
|
1253 AcidSG: 1142, |
|
1254 AcidPrc: 0.28 |
|
1255 }; |
|
1256 case 2: return { // Fosforzuur |
|
1257 pK1: 2.12, |
|
1258 pK2: 7.20, |
|
1259 pK3: 12.44, |
|
1260 MolWt: 98.00, |
|
1261 AcidSG: 1170, |
|
1262 AcidPrc: 0.25 |
|
1263 }; |
|
1264 case 3: return { // Zwavelzuur |
|
1265 pK1: -1, |
|
1266 pK2: 1.92, |
|
1267 pK3: 20, |
|
1268 MolWt: 98.07, |
|
1269 AcidSG: 1700, |
|
1270 AcidPrc: 0.93 |
|
1271 }; |
|
1272 } |
|
1273 } |
|
1274 |
|
1275 |
|
1276 function calcWater() { |
|
1277 |
|
1278 console.log("calcWater()"); |
|
1279 var liters = 0; |
|
1280 var calcium = 0; |
|
1281 var magnesium = 0; |
|
1282 var sodium = 0; |
|
1283 var total_alkalinity = 0; |
|
1284 var bicarbonate = 0; |
|
1285 var chloride = 0; |
|
1286 var sulfate = 0; |
|
1287 var ph = 0; |
|
1288 var RA = 0; |
|
1289 var frac = 0; |
|
1290 var TpH = 0; |
|
1291 var protonDeficit = 0; |
|
1292 |
|
1293 if (dataRecord.w1_name == "") { |
|
1294 return; |
|
1295 } |
|
1296 |
|
1297 // If there is a dillute water source, mix the waters. |
|
1298 if (dataRecord.w2_name != "") { |
|
1299 liters = dataRecord.w1_amount + dataRecord.w2_amount; |
|
1300 calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium); |
|
1301 magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium); |
|
1302 sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium); |
|
1303 chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride); |
|
1304 sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate); |
|
1305 total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity); |
|
1306 ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters); |
|
1307 } else { |
|
1308 liters = dataRecord.w1_amount; |
|
1309 calcium = dataRecord.w1_calcium; |
|
1310 magnesium = dataRecord.w1_magnesium; |
|
1311 sodium = dataRecord.w1_sodium; |
|
1312 chloride = dataRecord.w1_chloride; |
|
1313 sulfate = dataRecord.w1_sulfate; |
|
1314 total_alkalinity = dataRecord.w1_total_alkalinity; |
|
1315 ph = dataRecord.w1_ph; |
|
1316 } |
|
1317 $('#wg_amount').val(liters); |
|
1318 var wg_calcium = calcium; |
|
1319 $('#wg_calcium').val(Math.round(calcium * 10) / 10); |
|
1320 //var wg_magnesium = magnesium; |
|
1321 $('#wg_magnesium').val(Math.round(magnesium * 10) / 10); |
|
1322 var wg_sodium = sodium; |
|
1323 $('#wg_sodium').val(Math.round(sodium * 10) / 10); |
|
1324 var wg_total_alkalinity = total_alkalinity; |
|
1325 $('#wg_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10); |
|
1326 var wg_chloride = chloride; |
|
1327 $('#wg_chloride').val(Math.round(chloride * 10) / 10); |
|
1328 var wg_sulfate = sulfate; |
|
1329 $('#wg_sulfate').val(Math.round(sulfate * 10) / 10); |
|
1330 // Note: brouwhulp has the malts included here in the result. |
|
1331 //var wg_ph = ph; |
|
1332 $('#wg_ph').val(Math.round(ph * 10) / 10); |
|
1333 $('#wb_ph').val(Math.round(MashpH() * 10) / 10); |
|
1334 $('#est_mash_ph').val(Math.round(MashpH() * 10) / 10); |
|
1335 bicarbonate = total_alkalinity * 1.22; |
|
1336 var wg_bicarbonate = bicarbonate; |
|
1337 |
|
1338 // Noot: de volgende berekeningen geven bijna gelijke resultaten in Brun'water. |
|
1339 // Calculate Ca |
|
1340 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 + |
|
1341 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4; |
|
1342 calcium += 1000 * RA / liters; |
|
1343 |
|
1344 // Calculate Mg |
|
1345 RA = parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMMg / MMMgSO4; |
|
1346 magnesium += 1000 * RA / liters; |
|
1347 |
|
1348 // Calculate Na |
|
1349 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
1350 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3; |
|
1351 sodium += 1000 * RA / liters; |
|
1352 |
|
1353 // Calculate SO4 |
|
1354 RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + |
|
1355 parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4; |
|
1356 sulfate += 1000 * RA / liters; |
|
1357 |
|
1358 // Calculate Cl |
|
1359 RA = 2 * parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 + |
|
1360 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl; |
|
1361 chloride += 1000 * RA / liters; |
|
1362 // Einde noot. |
|
1363 |
|
1364 if ($("#wa_acid_name").val() < 0 || $("#wa_acid_name").val() > 3) { |
|
1365 $("#wa_acid_name").val(0); |
|
1366 dataRecord.wa_acid_name = 0; |
|
1367 } |
|
1368 if (last_acid == '') |
|
1369 last_acid = AcidTypeData[$("#wa_acid_name").val()].nl; |
|
1370 |
|
1371 if ($("#wa_base_name").val() < 0 || $("#wa_base_name").val() > 3) { |
|
1372 $("#wa_base_name").val(0); |
|
1373 dataRecord.wa_base_name = 0; |
|
1374 } |
|
1375 if (last_base == '') |
|
1376 last_base = BaseTypeData[$("#wa_base_name").val()].nl; |
|
1377 |
|
1378 var AT = dataRecord.wa_acid_name; |
|
1379 var BT = dataRecord.wa_base_name; |
|
1380 |
|
1381 var result = GetAcidSpecs(AT); |
|
1382 var pK1 = result.pK1; |
|
1383 var pK2 = result.pK2; |
|
1384 var pK3 = result.pK3; |
|
1385 var MolWt = result.MolWt; |
|
1386 var AcidSG = result.AcidSG; |
|
1387 var AcidPrc = result.AcidPrc; |
|
1388 |
|
1389 if (dataRecord.calc_acid) { |
|
1390 TpH = parseFloat(dataRecord.mash_ph); |
|
1391 protonDeficit = ProtonDeficit(TpH); |
|
1392 console.log("calc_acid tgt: "+TpH+" protonDeficit: "+protonDeficit); |
|
1393 if (protonDeficit > 0) { // Add acid |
|
1394 $("#wa_base").val(0); |
|
1395 setWaterAgent(last_base, 0); |
|
1396 frac = CalcFrac(TpH, pK1, pK2, pK3); |
|
1397 Acid = protonDeficit / frac; |
|
1398 Acid *= MolWt; // mg |
|
1399 Acidmg = Acid; |
|
1400 Acid = Acid / AcidSG; // ml |
|
1401 |
|
1402 if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0) |
|
1403 $("#wa_acid_perc").val(AcidPrc); |
|
1404 Acid = Acid * AcidPrc / (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml |
|
1405 console.log("Final ml: "+Acid); |
|
1406 $("#wa_acid").val(Math.round(Acid * 100) / 100); |
|
1407 setWaterAgent(AcidTypeData[AT].nl, Math.round(Acid * 100) / 100); |
|
1408 |
|
1409 bicarbonate = bicarbonate - protonDeficit * frac / liters; |
|
1410 total_alkalinity = bicarbonate * 50 / 61; |
|
1411 } else if (protonDeficit < 0) { //Add base |
|
1412 $("#wa_acid").val(0); |
|
1413 setWaterAgent(last_acid, 0); |
|
1414 var r1d = Math.pow(10, (TpH - 6.38)); |
|
1415 var r2d = Math.pow(10, (TpH - 10.38)); |
|
1416 var f1d = 1 / (1 + r1d + r1d * r2d); |
|
1417 var f2d = f1d * r1d; |
|
1418 var f3d = f2d * r2d; |
|
1419 switch (BT) { |
|
1420 case 0: RA = -protonDeficit / (f1d - f3d); // Sodiumbicarbonate, mmol totaal |
|
1421 RA = RA * MMNaHCO3/1000; //gram |
|
1422 $("#wa_base").val(Math.round(RA * 100) / 100); |
|
1423 setWaterAgent('NaHCO3', Math.round(RA * 100) / 100); |
|
1424 if (liters > 0) { |
|
1425 // Na |
|
1426 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
1427 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3; |
|
1428 RA = 1000 * RA / liters; |
|
1429 sodium = wg_sodium + RA; |
|
1430 // HCO3 |
|
1431 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3; |
|
1432 RA = 1000 * RA / liters; |
|
1433 bicarbonate = wg_bicarbonate + RA; |
|
1434 total_alkalinity = bicarbonate * 50 / 61; |
|
1435 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
1436 } |
|
1437 break; |
|
1438 case 1: RA = -protonDeficit / (2 * f1d + f2d); // Sodiumcarbonate, mmol totaal |
|
1439 RA = RA * MMNa2CO3/1000; //gram |
|
1440 $("#wa_base").val(Math.round(RA * 100) / 100); |
|
1441 setWaterAgent('Na2CO3', Math.round(RA * 100) / 100); |
|
1442 if (liters > 0) { |
|
1443 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
1444 parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3; |
|
1445 RA = 1000 * RA / liters; |
|
1446 sodium = wg_sodium + RA; |
|
1447 // HCO3 |
|
1448 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3; |
|
1449 RA = 1000 * RA / liters; |
|
1450 bicarbonate = wg_bicarbonate + RA; |
|
1451 total_alkalinity = bicarbonate * 50 / 61; |
|
1452 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
1453 } |
|
1454 break; |
|
1455 case 2: RA = -protonDeficit * (f1d - f3d); // Calciumcarbonate, mmol totaal |
|
1456 RA = RA * MMCaCO3/1000; //gram |
|
1457 //but only 1/3 is effective, so add 3 times as much |
|
1458 RA = 3 * RA; |
|
1459 $("#wa_base").val(Math.round(RA * 100) / 100); |
|
1460 setWaterAgent('CaCO3', Math.round(RA * 100) / 100); |
|
1461 if (liters > 0) { |
|
1462 //Bicarbonate |
|
1463 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3; |
|
1464 RA = 1000 * RA / liters; |
|
1465 bicarbonate = wg_bicarbonate + RA; |
|
1466 total_alkalinity = bicarbonate * 50 / 61; |
|
1467 //Ca precipitates out as Ca10(PO4)6(OH)2 |
|
1468 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 + |
|
1469 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 + |
|
1470 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3; |
|
1471 RA = 1000 * RA / liters; |
|
1472 calcium = wg_calcium + RA; |
|
1473 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
1474 } |
|
1475 break; |
|
1476 case 3: RA = -protonDeficit / 19.3; // Calciumhydroxide |
|
1477 $("#wa_base").val(Math.round(RA * 100) / 100); |
|
1478 setWaterAgent('Ca(OH)2', Math.round(RA * 100) / 100); |
|
1479 if (liters > 0) { |
|
1480 // Bicarbonate |
|
1481 RA = -protonDeficit / liters; |
|
1482 total_alkalinity = wg_total_alkalinity + RA; |
|
1483 bicarbonate = total_alkalinity * 61 / 50; |
|
1484 // Calcium |
|
1485 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 + |
|
1486 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 + |
|
1487 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaOH2; |
|
1488 RA = 1000 * RA / liters; |
|
1489 calcium = wg_calcium + RA; |
|
1490 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
1491 } |
|
1492 break; |
|
1493 } |
|
1494 } |
|
1495 ph = TpH; |
|
1496 $('#wb_ph').val(Math.round(ph * 10) / 10); |
|
1497 $('#est_mash_ph').val(Math.round(ph * 10) / 10); |
|
1498 } else { // Manual |
|
1499 console.log("calc_acid no"); |
|
1500 // First add base salts |
|
1501 if (parseFloat($("#wa_base").jqxNumberInput('decimal')) > 0) { |
|
1502 if (liters > 0) { |
|
1503 switch (BT) { |
|
1504 case 0: // Sodiumbicarbonate, Na |
|
1505 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
1506 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3; |
|
1507 RA = 1000 * RA / liters; |
|
1508 sodium = wg_sodium + RA; |
|
1509 // HCO3 |
|
1510 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3; |
|
1511 RA = 1000 * RA / liters; |
|
1512 bicarbonate = wg_bicarbonate + RA; |
|
1513 total_alkalinity = bicarbonate * 50 / 61; |
|
1514 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
1515 break; |
|
1516 case 1: // Sodiumcarbonate |
|
1517 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
1518 parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3; |
|
1519 RA = 1000 * RA / liters; |
|
1520 sodium = wg_sodium + RA; |
|
1521 // HCO3 |
|
1522 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3; |
|
1523 RA = 1000 * RA / liters; |
|
1524 bicarbonate = wg_bicarbonate + RA; |
|
1525 total_alkalinity = bicarbonate * 50 / 61; |
|
1526 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
1527 break; |
|
1528 case 2: // Calciumcarbonate: Bicarbonate |
|
1529 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3; |
|
1530 RA = 1000 * RA / liters; |
|
1531 bicarbonate = wg_bicarbonate + RA; |
|
1532 total_alkalinity = bicarbonate * 50 / 61; |
|
1533 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
1534 // Ca |
|
1535 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 + |
|
1536 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 + |
|
1537 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3; |
|
1538 RA = 1000 * RA / liters; |
|
1539 calcium = wg_calcium + RA; |
|
1540 break; |
|
1541 } |
|
1542 } |
|
1543 } |
|
1544 |
|
1545 TpH = parseFloat(dataRecord.mash_ph); |
|
1546 pHa = MashpH(); // This one is in demi water, should be in adjusted water??? |
|
1547 // Then calculate the new pH with added acids |
|
1548 if (parseFloat($("#wa_acid").jqxNumberInput('decimal')) > 0) { |
|
1549 console.log("TpH: "+TpH+" water: "+pHa); |
|
1550 Acid = parseFloat($("#wa_acid").jqxNumberInput('decimal')); |
|
1551 if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0) |
|
1552 $("#wa_acid_perc").val(AcidPrc); |
|
1553 Acid = Acid / AcidPrc * (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml |
|
1554 Acid *= AcidSG; // ml |
|
1555 Acid /= MolWt; // mg |
|
1556 Acidmg = Acid; |
|
1557 |
|
1558 //find the pH where the protondeficit = protondeficit by the acid |
|
1559 frac = CalcFrac(pHa, pK1, pK2, pK3); |
|
1560 protonDeficit = Acid * frac; |
|
1561 |
|
1562 var deltapH = 0.001; |
|
1563 var deltapd = 0.1; |
|
1564 var pd = ProtonDeficit(pHa); |
|
1565 var n = 0; |
|
1566 while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 2000)) { |
|
1567 n++; |
|
1568 if (pd < (protonDeficit-deltapd)) |
|
1569 pHa -= deltapH; |
|
1570 else if (pd > (protonDeficit+deltapd)) |
|
1571 pHa += deltapH; |
|
1572 frac = CalcFrac(pHa, pK1, pK2, pK3); |
|
1573 protonDeficit = Acid * frac; |
|
1574 pd = ProtonDeficit(pHa); |
|
1575 } |
|
1576 console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa); |
|
1577 RA = wg_bicarbonate - protonDeficit * frac / liters; |
|
1578 bicarbonate = RA; |
|
1579 total_alkalinity = RA * 50 / 61; |
|
1580 ph = pHa; |
|
1581 $('#wb_ph').val(Math.round(ph * 10) / 10); |
|
1582 $('#est_mash_ph').val(Math.round(ph * 10) / 10); |
|
1583 } |
|
1584 } |
|
1585 |
|
1586 if ((AT == 3) && (liters > 0)) { // Sulfuctic / Zwavelzuur |
|
1587 RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + |
|
1588 parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 + |
|
1589 Acidmg / 1000 * MMSO4 / (MMSO4 + 2); |
|
1590 RA = 1000 * RA / liters; |
|
1591 sulfate = wg_sulfate + RA; // Not add to sulfate?? |
|
1592 } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur |
|
1593 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 + |
|
1594 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl + |
|
1595 Acidmg / 1000 * MMCl / (MMCl + 1); |
|
1596 RA = 1000 * RA / liters; |
|
1597 chloride = wg_chloride + RA; |
|
1598 } |
|
1599 |
|
1600 // 2:1 Sulfate to Chroride IPA's, Pale Ales. |
|
1601 // 1:1 Sulfate to Chloride Balanced |
|
1602 // 1:2 Sulfate to Chloride Malty |
|
1603 // Note, values below are the other way, cl to so4! |
|
1604 // So: 0.5 is IPA's, Pale Ales. |
|
1605 // 1 Balanced |
|
1606 // 2 Malty. |
|
1607 $('#tgt_bu').val(Math.round(GetBUGU() * 100) / 100); |
|
1608 // From brouwhulp. |
|
1609 if (GetBUGU() < 0.32) |
|
1610 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig en zoet</span>"); |
|
1611 else if (GetBUGU() < 0.43) |
|
1612 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig, zoet</span>"); |
|
1613 else if (GetBUGU() < 0.52) |
|
1614 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Evenwichtig</span>"); |
|
1615 else if (GetBUGU() < 0.63) |
|
1616 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht hoppig, bitter</span>"); |
|
1617 else |
|
1618 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Extra hoppig, zeer bitter</span>"); |
|
1619 $('#tgt_cl_so4').val(Math.round(GetOptClSO4ratio() * 10) / 10); |
|
1620 if (sulfate > 0) |
|
1621 RA = chloride / sulfate; |
|
1622 else |
|
1623 RA = 10; |
|
1624 $('#got_cl_so4').val(Math.round(RA * 10) / 10); |
|
1625 var piCLSO4_low = 0.8 * GetOptClSO4ratio(); |
|
1626 var piCLSO4_high = 1.2 * GetOptClSO4ratio(); |
|
1627 var Res = 'normaal'; |
|
1628 if (RA < piCLSO4_low) |
|
1629 Res = 'laag'; |
|
1630 else if (RA > piCLSO4_high) |
|
1631 Res = 'hoog'; |
|
1632 setRangeIndicator('cl_so4', Res); |
|
1633 |
|
1634 $('#wb_calcium').val(Math.round(calcium * 10) / 10); |
|
1635 $('#wb_magnesium').val(Math.round(magnesium * 10) / 10); |
|
1636 $('#wb_sodium').val(Math.round(sodium * 10) / 10); |
|
1637 $('#wb_sulfate').val(Math.round(sulfate * 10) / 10); |
|
1638 $('#wb_chloride').val(Math.round(chloride * 10) / 10); |
|
1639 $('#wb_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10); |
|
1640 |
|
1641 if (calcium < 40) { |
|
1642 setRangeIndicator("calcium", "laag"); |
|
1643 } else if (calcium > 150) { |
|
1644 setRangeIndicator("calcium", "hoog"); |
|
1645 } else { |
|
1646 setRangeIndicator("calcium", "normaal"); |
|
1647 } |
|
1648 if (magnesium >= 0 && magnesium <= 30) { |
|
1649 setRangeIndicator("magnesium", "normaal"); |
|
1650 } else { |
|
1651 setRangeIndicator("magnesium", "hoog"); |
|
1652 } |
|
1653 if (sodium <= 150) { |
|
1654 setRangeIndicator("sodium", "normaal"); |
|
1655 } else { |
|
1656 setRangeIndicator("sodium", "hoog"); |
|
1657 } |
|
1658 // Both chloride and sulfate should be above 50 according to |
|
1659 // John Palmer. So the Cl/SO4 ratio calculation will work. |
|
1660 if (chloride <= 50) { |
|
1661 setRangeIndicator("chloride", "laag"); |
|
1662 } else if (chloride <= 100) { |
|
1663 setRangeIndicator("chloride", "normaal"); |
|
1664 } else { |
|
1665 setRangeIndicator("chloride", "hoog"); |
|
1666 } |
|
1667 if (sulfate <= 50) { |
|
1668 setRangeIndicator("sulfate", "laag"); |
|
1669 } else if (sulfate <= 350) { |
|
1670 setRangeIndicator("sulfate", "normaal"); |
|
1671 } else { |
|
1672 setRangeIndicator("sulfate", "hoog"); |
|
1673 } |
|
1674 if (ph < 5.2) { |
|
1675 setRangeIndicator("ph", "laag"); |
|
1676 } else if (ph > 5.6) { |
|
1677 setRangeIndicator("ph", "hoog"); |
|
1678 } else { |
|
1679 setRangeIndicator("ph", "normaal"); |
|
1680 } |
|
1681 calcSparge(); |
|
1682 calcMiscs(); |
|
1683 calcSupplies(); |
|
1684 } |
|
1685 |
|
1686 function calcSparge() { |
|
1687 |
|
1688 // Code from BrewBuddy/Brouwhulp, who got it from http://www.brewery.org/brewery/library/Acidi0,00fWaterAJD0497.html |
|
1689 var TargetpH = dataRecord.sparge_ph; |
|
1690 var Source_pH = dataRecord.w1_ph; |
|
1691 var Source_alkalinity = dataRecord.w1_total_alkalinity; |
|
1692 // Select watersource or fallback to the first source. |
|
1693 if (dataRecord.sparge_source == 1) { // Source 2 |
|
1694 if (dataRecord.w2_ph > 0.0) { |
|
1695 Source_pH = dataRecord.w2_ph; |
|
1696 Source_alkalinity = dataRecord.w2_total_alkalinity; |
|
1697 } else { |
|
1698 dataRecord.sparge_source = 0; // Source 1 |
|
1699 $("#sparge_source").val(0); |
|
1700 } |
|
1701 } else if (dataRecord.sparge_source == 2) { // Mixed |
|
1702 if (dataRecord.w2_ph > 0.0) { |
|
1703 Source_pH = parseFloat($("#wg_ph").jqxNumberInput('decimal')); |
|
1704 Source_alkalinity = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')); |
|
1705 } else { |
|
1706 dataRecord.sparge_source = 0; |
|
1707 $("#sparge_source").val(0); |
|
1708 } |
|
1709 } |
|
1710 |
|
1711 // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH |
|
1712 var r1 = Math.pow(10, Source_pH - 6.38); |
|
1713 var r2 = Math.pow(10, Source_pH - 10.373); |
|
1714 var d = 1 + r1 + r1*r2; |
|
1715 var f1 = 1/d; |
|
1716 //var f2 = r1/d; |
|
1717 var f3 = r1 * r2 / d; |
|
1718 |
|
1719 //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) |
|
1720 var r143 = Math.pow(10, 4.3 - 6.38); |
|
1721 var r243 = Math.pow(10, 4.3 - 10.373); |
|
1722 var d43 = 1 + r143 + r143*r243; |
|
1723 var f143 = 1/d43; |
|
1724 //var f243 = r143 / d43; |
|
1725 var f343 = r143 * r243 / d43; |
|
1726 |
|
1727 //Step 3. Convert the water alkalinity to milliequivalents/L |
|
1728 var alkalinity = Source_alkalinity / 50; |
|
1729 |
|
1730 //Step 4. Solve |
|
1731 var Ct = (alkalinity - 1000 * (Math.pow(10, -4.3) - Math.pow(10, -Source_pH))) / ((f143-f1)+(f3-f343)); |
|
1732 |
|
1733 //Step 5. Compute mole fractions at desired pH |
|
1734 var r1g = Math.pow(10, TargetpH - 6.38); |
|
1735 var r2g = Math.pow(10, TargetpH - 10.373); |
|
1736 var dg = 1 + r1g + r1g*r2g; |
|
1737 var f1g = 1/dg; |
|
1738 //var f2g = r1g / dg; |
|
1739 var f3g = r1g * r2g / dg; |
|
1740 |
|
1741 //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L) |
|
1742 var Acid = Ct * ((f1g-f1)+(f3-f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l |
|
1743 Acid += 0.01; // Add acid that would be required for distilled water. |
|
1744 if (dataRecord.sparge_acid_type < 0 || dataRecord.sparge_acid_type > 3) { |
|
1745 dataRecord.sparge_acid_type = 0; |
|
1746 $("#sparge_acid_type").val(0); |
|
1747 } |
|
1748 |
|
1749 //Step 8. Get the acid data. |
|
1750 var AT = dataRecord.sparge_acid_type; |
|
1751 var result = GetAcidSpecs(AT); |
|
1752 var pK1 = result.pK1; |
|
1753 var pK2 = result.pK2; |
|
1754 var pK3 = result.pK3; |
|
1755 var MolWt = result.MolWt; |
|
1756 var AcidSG = result.AcidSG; |
|
1757 var AcidPrc = result.AcidPrc; |
|
1758 var fract = CalcFrac(TargetpH, pK1, pK2, pK3); |
|
1759 |
|
1760 //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. |
|
1761 Acid /= fract; |
|
1762 |
|
1763 //Step 10. Multiply by molecular weight of the acid |
|
1764 Acid *= MolWt; //mg |
|
1765 |
|
1766 Acid = Acid / AcidSG; //ml ; 88% lactic solution |
|
1767 var f1 = dataRecord.sparge_acid_perc; |
|
1768 if (f1 <= 0.1) |
|
1769 f1 = AcidPrc; |
|
1770 Acid = Acid * AcidPrc / (f1 / 100); |
|
1771 |
|
1772 Acid *= dataRecord.sparge_volume; //ml lactic acid total |
|
1773 Acid = Math.round(Acid * 100) / 100; |
|
1774 dataRecord.sparge_acid_amount = Acid / 1000; |
|
1775 $("#sparge_acid_amount").val(Acid); |
|
1776 } |
|
1777 |
|
1778 function calcFermentation(){ |
|
1779 |
|
1780 if (dataRecord.brew_fermenter_sg<1.020) |
|
1781 return; |
|
1782 |
|
1783 // var obrix = sg_to_brix(dataRecord.brew_fermenter_sg); |
|
1784 if ((dataRecord.primary_end_sg>0.990)&&(dataRecord.primary_end_sg<dataRecord.brew_fermenter_sg)){ |
|
1785 var primary_svg=Round(100*(dataRecord.brew_fermenter_sg-dataRecord.primary_end_sg)/(dataRecord.brew_fermenter_sg-1),1); |
|
1786 $("#primary_svg").val(primary_svg); |
|
1787 if((dataRecord.secondary_end_sg>0.990)&&(dataRecord.secondary_end_sg<dataRecord.brew_fermenter_sg)){ |
|
1788 var secondary_svg=Round(100*(dataRecord.brew_fermenter_sg-dataRecord.secondary_end_sg)/(dataRecord.brew_fermenter_sg-1),1); |
|
1789 $("#secondary_svg").val(secondary_svg); |
|
1790 if((dataRecord.fg>0.990)&&(dataRecord.fg<dataRecord.brew_fermenter_sg)){ |
|
1791 var final_svg=Round(100*(dataRecord.brew_fermenter_sg-dataRecord.fg)/(dataRecord.brew_fermenter_sg-1),1); |
|
1792 $("#final_svg").val(final_svg); |
|
1793 var ABV=Round(abvol(dataRecord.brew_fermenter_sg,dataRecord.fg),2); |
|
1794 $("#final_abv").val(ABV); |
|
1795 } |
|
1796 } |
|
1797 } |
|
1798 } |
|
1799 |
|
1800 |
|
1801 |
|
1802 function ResCO2(CO2,T){ |
|
1803 |
|
1804 var F=T*1.8+32; |
|
1805 return 3.0378-0.050062*F+0.00026555*F*F; |
|
1806 } |
|
1807 |
|
1808 |
|
1809 |
|
1810 function CarbCO2toS(CO2,T,SFactor){ |
|
1811 var sugar=SFactor*(CO2-ResCO2(CO2,T))/0.286; |
|
1812 if(sugar<0) |
|
1813 sugar=0; |
|
1814 return Round(sugar,3); |
|
1815 } |
|
1816 |
|
1817 function GetPressure(CO2, T1, T2) { |
|
1818 var V = CO2 - ResCO2(CO2, T1); |
|
1819 if (V < 0) |
|
1820 return 0; |
|
1821 var P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V + |
|
1822 0.674996600795854 * V + -0.00471757220150754 * V * V; |
|
1823 //console.log("CO2: "+CO2+" "+V+" Temp: "+T1+" "+T2+" Pressure: "+P); |
|
1824 if (P < 0) |
|
1825 P = 0; |
|
1826 P = P * 1.01325; // atm to bar |
|
1827 return Round(P,1); |
|
1828 } |
|
1829 |
|
1830 function CarbCO2ToPressure(CO2, T) { |
|
1831 return (CO2-(-0.000005594056*Math.pow(T,4)+0.000144357886*Math.pow(T,3)+0.000362999168*T*T-0.064872987645*T+1.641145175049)) / |
|
1832 (0.00000498031*Math.pow(T,4)-0.00024358267*Math.pow(T,3)+0.00385867329*T*T-0.05671206825*T+1.53801423376); |
|
1833 } |
|
1834 |
|
1835 function calcCarbonation() { |
|
1836 |
|
1837 var TSec=dataRecord.secondary_temp; |
|
1838 if(TSec<1) |
|
1839 TSec=dataRecord.primary_end_temp; |
|
1840 if(TSec<1) |
|
1841 TSec=18; |
|
1842 |
|
1843 if(dataRecord.fg==0.000) |
|
1844 var ABV=abvol(dataRecord.brew_fermenter_sg,parseFloat($("#est_fg").jqxNumberInput('decimal'))); |
|
1845 else |
|
1846 var ABV=abvol(dataRecord.brew_fermenter_sg,dataRecord.fg); |
|
1847 |
|
1848 /* Calculate new volume and alcohol. */ |
|
1849 var bvol=dataRecord.package_volume-(ABV*dataRecord.package_volume)/100; |
|
1850 var balc=dataRecord.package_volume-bvol; |
|
1851 var mvol=dataRecord.package_infuse_amount-(dataRecord.package_infuse_abv*dataRecord.package_infuse_amount)/100; |
|
1852 var malc=dataRecord.package_infuse_amount-mvol; |
|
1853 var talc=balc+malc; |
|
1854 var tvol=bvol+mvol; |
|
1855 ABV = Round(talc/(tvol+talc)*100,2); |
|
1856 dataRecord.package_abv=ABV; |
|
1857 $("#package_abv").val(ABV); |
|
1858 |
|
1859 // console.log("calcCarbonation() TSec:"+TSec+" ABV:"+ABV); |
|
1860 if(!(rows = $('#fermentableGrid').jqxGrid('getrows'))){return;} |
|
1861 |
|
1862 // Bottles |
|
1863 dataRecord.bottle_priming_amount=0; |
|
1864 dataRecord.bottle_priming_total=0; |
|
1865 for (var i=0;i<rows.length;i++){ |
|
1866 var row=rows[i]; |
|
1867 if(row.f_added==4){ |
|
1868 var SFactor=1/((row.f_yield/100)*(1-row.f_moisture/100)); |
|
1869 dataRecord.bottle_priming_amount=CarbCO2toS(dataRecord.bottle_carbonation,TSec,SFactor); |
|
1870 dataRecord.bottle_priming_total=Round(dataRecord.bottle_amount*dataRecord.bottle_priming_amount,2); |
|
1871 $("#fermentableGrid").jqxGrid('setcellvalue',i,'f_amount',dataRecord.bottle_priming_total/1000); |
|
1872 } |
|
1873 } |
|
1874 $("#bottle_priming_amount").val(Round(dataRecord.bottle_priming_amount,1)); |
|
1875 $("#bottle_priming_total").val(dataRecord.bottle_priming_total); |
|
1876 var pabv=ABV+dataRecord.bottle_priming_amount*0.47/7.907; |
|
1877 var pvol=dataRecord.bottle_amount-(pabv*dataRecord.bottle_amount)/100; |
|
1878 var talc=dataRecord.bottle_amount-pvol; |
|
1879 var tvol=pvol+dataRecord.bottle_priming_water; |
|
1880 var babv = Round(talc/(tvol+talc)*100,2); |
|
1881 //console.log("bottle pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.bottle_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+babv); |
|
1882 $("#bottle_abv").val(babv); |
|
1883 $("#bottle_pressure").val(GetPressure(dataRecord.bottle_carbonation,TSec,dataRecord.bottle_carbonation_temp)); |
|
1884 |
|
1885 // Kegs |
|
1886 var Pressure=CarbCO2ToPressure(dataRecord.keg_carbonation,dataRecord.keg_carbonation_temp); |
|
1887 if(Pressure<0)Pressure=0; |
|
1888 dataRecord.keg_pressure=Pressure; |
|
1889 $("#keg_pressure").val(Round(Pressure,1)); |
|
1890 |
|
1891 dataRecord.keg_priming_amount=0; |
|
1892 dataRecord.keg_priming_total=0; |
|
1893 if(!dataRecord.keg_forced_carb){ |
|
1894 for(var i=0;i<rows.length;i++){ |
|
1895 var row=rows[i]; |
|
1896 if(row.f_added==5){ |
|
1897 var SFactor=1/((row.f_yield/100)*(1-row.f_moisture/100)); |
|
1898 dataRecord.keg_priming_amount=CarbCO2toS(dataRecord.keg_carbonation,TSec,SFactor); |
|
1899 dataRecord.keg_priming_total=Round(dataRecord.keg_amount*dataRecord.keg_priming_amount,2); |
|
1900 $("#fermentableGrid").jqxGrid('setcellvalue',i,'f_amount',dataRecord.keg_priming_total/1000); |
|
1901 } |
|
1902 } |
|
1903 $("#keg_priming_amount").val(Round(dataRecord.keg_priming_amount,1)); |
|
1904 $("#keg_priming_total").val(dataRecord.keg_priming_total); |
|
1905 var pabv=ABV+dataRecord.keg_priming_amount*0.47/7.907; |
|
1906 var pvol=dataRecord.keg_amount-(pabv*dataRecord.keg_amount)/100; |
|
1907 var talc=dataRecord.keg_amount-pvol; |
|
1908 var tvol=pvol+dataRecord.keg_priming_water; |
|
1909 var kabv=Round(talc/(tvol+talc)*100,2); |
|
1910 //console.log("kegs pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.keg_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+kabv); |
|
1911 $("#keg_abv").val(kabv); |
|
1912 } else { |
|
1913 $("#keg_priming_amount").val(0); |
|
1914 $("#keg_priming_total").val(0); |
|
1915 $("#keg_abv").val(ABV); |
|
1916 } |
|
1917 } |
|
1918 |
|
1919 function calcStage() { |
|
1920 |
|
1921 var newstage = dataRecord.stage; |
|
1922 /* parseFloat$("#brew_date_start").val()) returns the year if it is a valid mysql style date. */ |
|
1923 if (newstage == 0 && dataRecord.est_og > 1.005 && dataRecord.est_color > 3 && dataRecord.est_ibu > 3) |
|
1924 newstage = 1; |
|
1925 if (newstage == 1 && parseFloat($("#brew_date_start").val()) > 2000) |
|
1926 newstage = 2; // Brewday |
|
1927 if (newstage == 2 && ($("#brew_date_start").val() == '')) |
|
1928 newstage = 1; // No brewday |
|
1929 if (newstage == 2 && parseFloat($("#brew_date_end").val()) > 2000) |
|
1930 newstage = 3; // Primary |
|
1931 if (newstage == 3 && parseFloat($("#primary_end_date").val()) > 2000) |
|
1932 newstage = 4; // Secondary |
|
1933 if (newstage == 4 && parseFloat($("#secondary_end_date").val()) > 2000) |
|
1934 newstage = 5; // Tertiary |
|
1935 if (newstage == 5 && parseFloat($("#package_date").val()) > 2000) |
|
1936 newstage = 6; // Package |
|
1937 if (newstage >= 6 && newstage < 9) { |
|
1938 var d = new Date(); |
|
1939 var date2 = $("#package_date").val(); |
|
1940 date2 = date2.split('-'); |
|
1941 // Now we convert the array to a Date object |
|
1942 date1 = new Date(d.getFullYear(), d.getMonth(), d.getDate()); |
|
1943 date2 = new Date(date2[0], date2[1]-1, date2[2]); |
|
1944 // We use the getTime() method and get the unixtime |
|
1945 date1_unixtime = parseInt(date1.getTime() / 1000); |
|
1946 date2_unixtime = parseInt(date2.getTime() / 1000); |
|
1947 // This is the calculated difference in seconds |
|
1948 var timeDifference = date1_unixtime - date2_unixtime; |
|
1949 var timeDifferenceInDays = timeDifference / 60 / 60 / 24; |
|
1950 if (timeDifferenceInDays > 0) { // At least one day |
|
1951 if (timeDifferenceInDays >= 42) // 6 weeks |
|
1952 newstage = 9; // Ready to taste |
|
1953 else if (timeDifferenceInDays >= 14) // 14 days |
|
1954 newstage = 8; // Mature |
|
1955 else |
|
1956 newstage = 7; // Carbonation |
|
1957 } |
|
1958 } |
|
1959 if (newstage == 9 && parseFloat($("#taste_date").val()) > 2000) |
|
1960 newstage = 10; // Ready |
|
1961 |
|
1962 if (newstage != dataRecord.stage) { |
|
1963 console.log("calcStage() old: "+dataRecord.stage+" new: "+newstage); |
|
1964 dataRecord.stage = newstage; |
|
1965 } |
|
1966 |
|
1967 /* |
|
1968 * Set stage and enable or disable parts of the screens. |
|
1969 */ |
|
1970 $("#stage").val(StageData[dataRecord.stage].nl); |
|
1971 if (dataRecord.stage >= 10) { |
|
1972 $("#locked").jqxCheckBox({ disabled:false }); |
|
1973 } |
|
1974 |
|
1975 /* |
|
1976 * When the brew is in progress or done, block equipment select and delete. |
|
1977 */ |
|
1978 if (dataRecord.stage > 1) { |
|
1979 $("#equipmentSelect").jqxDropDownList({ disabled: true }); |
|
1980 $("#Delete").jqxButton({ disabled: true }); |
|
1981 } |
|
1982 |
|
1983 if (dataRecord.stage < 1) // Planning, no ingredients |
|
1984 $('#jqxTabs').jqxTabs('disableAt', 8); // Brewday tab |
|
1985 else |
|
1986 $('#jqxTabs').jqxTabs('enableAt', 8); |
|
1987 |
|
1988 if (dataRecord.stage < 3) { // Primary |
|
1989 $('#jqxTabs').jqxTabs('disableAt', 9); // Fermentation tab |
|
1990 } else { |
|
1991 $('#jqxTabs').jqxTabs('enableAt', 9); |
|
1992 $("#name").jqxInput({ disabled: true }); |
|
1993 $("#code").jqxInput({ disabled: true }); |
|
1994 $("#batch_size").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
1995 $("#boil_size").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
1996 $("#boil_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
1997 $("#efficiency").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
1998 $("#est_og").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
1999 $("#type").jqxDropDownList({ disabled: true }); |
|
2000 $("#styleSelect").jqxDropDownList({ disabled: true }); |
|
2001 $("#color_method").jqxDropDownList({ disabled: true }); |
|
2002 $("#ibu_method").jqxDropDownList({ disabled: true }); |
|
2003 $("#mash_select").jqxDropDownList({ disabled: true }); |
|
2004 $("#w1_name").jqxDropDownList({ disabled: true }); |
|
2005 $("#w2_name").jqxDropDownList({ disabled: true }); |
|
2006 $("#w2_amount").jqxNumberInput({ readOnly: true }); |
|
2007 $("#pr_name").jqxDropDownList({ disabled: true }); |
|
2008 $("#wa_cacl2").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2009 $("#wa_caso4").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2010 $("#wa_mgso4").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2011 $("#wa_nacl").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2012 $("#mash_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2013 $("#calc_acid").jqxCheckBox({ disabled: true }); |
|
2014 $("#wa_base_name").jqxDropDownList({ disabled: true }); |
|
2015 $("#wa_base").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2016 $("#wa_acid_name").jqxDropDownList({ disabled: true }); |
|
2017 $("#wa_acid").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2018 $("#wa_acid_perc").jqxNumberInput({ spinButtons: false, readOnly: true, width: 70 }); |
|
2019 $("#sparge_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2020 $("#sparge_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2021 $("#sparge_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2022 $("#sparge_source").jqxDropDownList({ disabled: true }); |
|
2023 $("#sparge_acid_type").jqxDropDownList({ disabled: true }); |
|
2024 $("#sparge_acid_perc").jqxNumberInput({ spinButtons: false, readOnly: true, width: false }); |
|
2025 $("#starter_enable").jqxCheckBox({ disabled: true }); |
|
2026 $("#starter_type").jqxDropDownList({ disabled: true }); |
|
2027 $("#starter_try").jqxButton({ disabled: true }); |
|
2028 $("#starter_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2029 $("#starter_viability").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2030 } |
|
2031 if (dataRecord.stage > 3) { // Primary fermentation done |
|
2032 $("#brew_date_start").jqxDateTimeInput({ disabled: true }); |
|
2033 $("#brew_date_end").jqxDateTimeInput({ disabled: true }); |
|
2034 $("#brew_mash_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2035 $("#brew_preboil_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2036 $("#brew_aboil_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2037 $("#brew_mash_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2038 $("#brew_preboil_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2039 $("#brew_aboil_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2040 $("#brew_preboil_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2041 $("#brew_aboil_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2042 $("#brew_whirlpool9").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2043 $("#brew_cooling_to").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2044 $("#brew_whirlpool7").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2045 $("#brew_cooling_method").jqxDropDownList({ disabled: true }); |
|
2046 $("#brew_whirlpool6").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2047 $("#brew_cooling_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2048 $("#brew_sparge_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2049 $("#brew_whirlpool2").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2050 $("#brew_aeration_type").jqxDropDownList({ disabled: true }); |
|
2051 $("#brew_fermenter_tcloss").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2052 $("#brew_aeration_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2053 $("#brew_fermenter_extrawater").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2054 $("#brew_aeration_speed").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2055 } |
|
2056 if (dataRecord.stage == 5) // Lagering, allow packaging |
|
2057 $("#package_date").jqxDateTimeInput({ disabled: false }); |
|
2058 else |
|
2059 $("#package_date").jqxDateTimeInput({ disabled: true }); |
|
2060 if (dataRecord.stage >= 5) { // At least secondary |
|
2061 $("#primary_start_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2062 $("#primary_max_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2063 $("#primary_end_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2064 $("#primary_end_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2065 $("#primary_end_brix").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2066 $("#primary_end_date").jqxDateTimeInput({ disabled: true }); |
|
2067 } |
|
2068 if (dataRecord.stage >= 6) { // Packaged |
|
2069 $("#secondary_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2070 $("#secondary_end_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2071 $("#secondary_end_date").jqxDateTimeInput({ disabled: true }); |
|
2072 $("#tertiary_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2073 $("#fg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2074 $("#final_brix").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2075 $("#package_date").jqxDateTimeInput({ disabled: true }); |
|
2076 $("#package_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2077 $("#package_infuse_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2078 $("#package_infuse_abv").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2079 $("#package_infuse_notes").jqxInput({ disabled: true }); |
|
2080 $("#package_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2081 $("#bottle_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2082 $("#bottle_priming_water").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2083 $("#keg_priming_water").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2084 $("#keg_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2085 $("#bottle_carbonation").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2086 $("#keg_carbonation").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2087 $("#bottle_priming_sugar").jqxDropDownList({ disabled: true }); |
|
2088 $("#keg_priming_sugar").jqxDropDownList({ disabled: true }); |
|
2089 $("#keg_forced_carb").jqxCheckBox({ disabled : true }); |
|
2090 $("#bottle_carbonation_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2091 $("#keg_carbonation_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2092 } |
|
2093 if (dataRecord.stage < 8) { // Taste when at least Mature. |
|
2094 $('#jqxTabs').jqxTabs('disableAt', 11); // Tasting tab |
|
2095 } else { |
|
2096 $('#jqxTabs').jqxTabs('enableAt', 11); |
|
2097 } |
|
2098 |
|
2099 if (dataRecord.stage == 11) { // Locked |
|
2100 $("#taste_date").jqxDateTimeInput({ disabled: true }); |
|
2101 $("#taste_rate").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2102 $("#taste_color").jqxInput({ disabled: true }); |
|
2103 $("#taste_transparency").jqxInput({ disabled: true }); |
|
2104 $("#taste_head").jqxInput({ disabled: true }); |
|
2105 $("#taste_aroma").jqxInput({ disabled: true }); |
|
2106 $("#taste_taste").jqxInput({ disabled: true }); |
|
2107 $("#taste_aftertaste").jqxInput({ disabled: true }); |
|
2108 $("#taste_mouthfeel").jqxInput({ disabled: true }); |
|
2109 $("#taste_notes").jqxInput({ disabled: true }); |
|
2110 $("#notes").jqxInput({ disabled: true }); |
|
2111 } else { |
|
2112 $("#notes").jqxInput({ disabled: false }); |
|
2113 } |
|
2114 } |
|
2115 |
|
2116 function showStarter() { |
|
2117 |
|
2118 if (dataRecord.starter_enable) { |
|
2119 $("#propagator").show(); |
|
2120 $("#starter_type").jqxDropDownList( {disabled: false }); |
|
2121 $("#starter_try").jqxButton({ disabled: false }); |
|
2122 $("#starter_sg").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 }); |
|
2123 $("#starter_viability").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 }); |
|
2124 } else { |
|
2125 $("#propagator").hide(); |
|
2126 $("#starter_type").jqxDropDownList( {disabled: true }); |
|
2127 $("#starter_try").jqxButton({ disabled: true }); |
|
2128 $("#starter_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2129 $("#starter_viability").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
2130 } |
|
2131 } |
|
2132 |
|
2133 function calcInit () { |
|
2134 console.log("calcInit()"); |
|
2135 |
|
2136 calcMashEfficiency(); |
|
2137 calcEfficiencyBeforeBoil(); |
|
2138 calcEfficiencyAfterBoil(); |
|
2139 |
|
2140 $("#starter_enable").on('checked', function (event) { |
|
2141 dataRecord.starter_enable = 1; |
|
2142 showStarter(); |
|
2143 calcYeast(); |
|
2144 }); |
|
2145 $("#starter_enable").on('unchecked', function (event) { |
|
2146 dataRecord.starter_enable = 0; |
|
2147 showStarter(); |
|
2148 calcYeast(); |
|
2149 }); |
|
2150 $("#starter_try").click(function () { |
|
2151 $("#prop1_volume").val(0); |
|
2152 $("#prop2_volume").val(0); |
|
2153 $("#prop3_volume").val(0); |
|
2154 $("#prop4_volume").val(0); |
|
2155 calcYeast(); |
|
2156 }); |
|
2157 $('#starter_type').on('change', function (event) { |
|
2158 if (event.args) { |
|
2159 var index = event.args.index; |
|
2160 dataRecord.starter_type = index; |
|
2161 calcYeast(); |
|
2162 } |
|
2163 }); |
|
2164 $('#starter_sg').on('change', function (event) { |
|
2165 if (event.args) { |
|
2166 dataRecord.starter_sg = event.args.value; |
|
2167 calcYeast(); |
|
2168 } |
|
2169 }); |
|
2170 $('#starter_viability').on('change', function (event) { |
|
2171 if (event.args) { |
|
2172 dataRecord.starter_viability = event.args.value; |
|
2173 calcFermentables(); |
|
2174 calcYeast(); |
|
2175 } |
|
2176 }); |
|
2177 $('#prop1_type').on('change', function (event) { |
|
2178 if (event.args) { |
|
2179 var index = event.args.index; |
|
2180 dataRecord.prop1_type = index; |
|
2181 calcYeast(); |
|
2182 } |
|
2183 }); |
|
2184 $('#prop1_volume').on('change', function (event) { |
|
2185 if (event.args) { |
|
2186 dataRecord.prop1_volume = event.args.value; |
|
2187 calcYeast(); |
|
2188 } |
|
2189 }); |
|
2190 $('#prop2_type').on('change', function (event) { |
|
2191 if (event.args) { |
|
2192 var index = event.args.index; |
|
2193 dataRecord.prop2_type = index; |
|
2194 calcYeast(); |
|
2195 } |
|
2196 }); |
|
2197 $('#prop2_volume').on('change', function (event) { |
|
2198 if (event.args) { |
|
2199 dataRecord.prop2_volume = event.args.value; |
|
2200 calcYeast(); |
|
2201 } |
|
2202 }); |
|
2203 $('#prop3_type').on('change', function (event) { |
|
2204 if (event.args) { |
|
2205 var index = event.args.index; |
|
2206 dataRecord.prop3_type = index; |
|
2207 calcYeast(); |
|
2208 } |
|
2209 }); |
|
2210 $('#prop3_volume').on('change', function (event) { |
|
2211 if (event.args) { |
|
2212 dataRecord.prop3_volume = event.args.value; |
|
2213 calcYeast(); |
|
2214 } |
|
2215 }); |
|
2216 $('#prop4_type').on('change', function (event) { |
|
2217 if (event.args) { |
|
2218 var index = event.args.index; |
|
2219 dataRecord.prop4_type = index; |
|
2220 calcYeast(); |
|
2221 } |
|
2222 }); |
|
2223 $('#prop4_volume').on('change', function (event) { |
|
2224 if (event.args) { |
|
2225 dataRecord.prop4_volume = event.args.value; |
|
2226 calcYeast(); |
|
2227 } |
|
2228 }); |
|
2229 |
|
2230 $("#calc_acid").on('checked', function (event) { |
|
2231 dataRecord.calc_acid = 1; |
|
2232 calcWater(); |
|
2233 }); |
|
2234 $("#calc_acid").on('unchecked', function (event) { |
|
2235 dataRecord.calc_acid = 0; |
|
2236 calcWater(); |
|
2237 }); |
|
2238 $("#w1_name").jqxDropDownList('selectItem', dataRecord.w1_name); |
|
2239 $("#w2_name").jqxDropDownList('selectItem', dataRecord.w2_name); |
|
2240 // Fix tap water if zero using mash infuse amount. |
|
2241 if (parseFloat($("#w1_amount").jqxNumberInput('decimal')) == 0 && mash_infuse > 0) { |
|
2242 $("#w1_amount").val(mash_infuse); |
|
2243 dataRecord.w1_amount = mash_infuse; |
|
2244 $("#wg_amount").val(mash_infuse); |
|
2245 $("#w2_amount").val(0); |
|
2246 dataRecord.w2_amount = 0; |
|
2247 } |
|
2248 calcWater(); |
|
2249 $("#w2_amount").on('change', function (event) { |
|
2250 var newval = parseFloat(event.args.value); |
|
2251 |
|
2252 if (newval > mash_infuse) { |
|
2253 $("#w2_amount").val(dataRecord.w2_amount); |
|
2254 return; |
|
2255 } |
|
2256 dataRecord.w1_amount = parseFloat($("#wg_amount").jqxNumberInput('decimal')) - newval; |
|
2257 $("#w1_amount").val(dataRecord.w1_amount); |
|
2258 dataRecord.w2_amount = newval; |
|
2259 console.log("new: "+event.args.value+" w1: "+dataRecord.w1_amount+" w2: "+dataRecord.w2_amount); |
|
2260 calcWater(); |
|
2261 }); |
|
2262 $('#wa_cacl2').on('change', function (event) { |
|
2263 if (event.args) { |
|
2264 setWaterAgent('CaCl2', 0); // This can prevent double entries. |
|
2265 setWaterAgent('CaCl2', event.args.value); |
|
2266 calcWater(); |
|
2267 } |
|
2268 }); |
|
2269 $('#wa_caso4').on('change', function (event) { |
|
2270 if (event.args) { |
|
2271 setWaterAgent('CaSO4', 0); |
|
2272 setWaterAgent('CaSO4', event.args.value); |
|
2273 calcWater(); |
|
2274 } |
|
2275 }); |
|
2276 $('#wa_mgso4').on('change', function (event) { |
|
2277 if (event.args) { |
|
2278 setWaterAgent('MgSO4', 0); |
|
2279 setWaterAgent('MgSO4', event.args.value); |
|
2280 calcWater(); |
|
2281 } |
|
2282 }); |
|
2283 $('#wa_nacl').on('change', function (event) { |
|
2284 if (event.args) { |
|
2285 setWaterAgent('NaCl', 0); |
|
2286 setWaterAgent('NaCl', event.args.value); |
|
2287 calcWater(); |
|
2288 } |
|
2289 }); |
|
2290 $('#wa_base_name').on('change', function (event) { |
|
2291 if (event.args) { |
|
2292 var index = event.args.index; |
|
2293 console.log("wa_base_name "+index); |
|
2294 setWaterAgent(last_base, 0); |
|
2295 last_base = BaseTypeData[index].nl; |
|
2296 setWaterAgent(last_base, parseFloat($("#wa_base").jqxNumberInput('decimal'))); |
|
2297 dataRecord.wa_base_name = index; |
|
2298 calcWater(); |
|
2299 } |
|
2300 }); |
|
2301 $('#wa_base').on('change', function (event) { |
|
2302 var name = BaseTypeData[$("#wa_base_name").val()].nl; |
|
2303 setWaterAgent(name, parseFloat(event.args.value)); |
|
2304 calcWater(); |
|
2305 }); |
|
2306 $('#wa_acid_name').on('change', function (event) { |
|
2307 if (event.args) { |
|
2308 var index = event.args.index; |
|
2309 console.log("wa_acid_name "+index); |
|
2310 setWaterAgent(last_acid, 0); |
|
2311 last_acid = AcidTypeData[index].nl; |
|
2312 setWaterAgent(last_acid, parseFloat($("#wa_acid").jqxNumberInput('decimal'))); |
|
2313 dataRecord.wa_acid_name = index; |
|
2314 calcWater(); |
|
2315 } |
|
2316 }); |
|
2317 $('#wa_acid').on('change', function (event) { |
|
2318 var name = AcidTypeData[$("#wa_acid_name").val()].nl; |
|
2319 setWaterAgent(name, parseFloat(event.args.value)); |
|
2320 calcWater(); |
|
2321 }); |
|
2322 $('#wa_acid_perc').on('change', function (event) { calcWater(); }); |
|
2323 |
|
2324 $('#color_method').on('change', function (event) { |
|
2325 dataRecord.color_method = event.args.index; |
|
2326 calcFermentables(); |
|
2327 }); |
|
2328 $('#ibu_method').on('change', function (event) { |
|
2329 dataRecord.ibu_method = event.args.index; |
|
2330 calcFermentables(); |
|
2331 calcIBUs(); |
|
2332 }); |
|
2333 |
|
2334 $('#batch_size').on('change', function (event) { |
|
2335 console.log("batch_size change:"+event.args.value+" old:"+dataRecord.batch_size); |
|
2336 $("#est_a_vol").val(event.args.value * 1.04); |
|
2337 var new_boil = parseFloat(event.args.value) + dataRecord.boil_size - dataRecord.batch_size; |
|
2338 var factor = parseFloat(event.args.value) / dataRecord.batch_size; |
|
2339 dataRecord.boil_size = new_boil; |
|
2340 $("#boil_size").val(Math.round(new_boil * 100) / 100); |
|
2341 $("#est_pre_vol").val(Math.round(new_boil * 1.04 * 100) / 100); |
|
2342 dataRecord.sparge_volume *= factor; |
|
2343 $("#sparge_volume").val(dataRecord.sparge_volume); |
|
2344 $("#brew_sparge_volume").val(dataRecord.sparge_volume); |
|
2345 dataRecord.batch_size = parseFloat(event.args.value); |
|
2346 calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal'))); // Keep the OG |
|
2347 adjustWaters(factor); |
|
2348 calcFermentables(); |
|
2349 adjustHops(factor); |
|
2350 adjustMiscs(factor); |
|
2351 adjustYeasts(factor); |
|
2352 calcIBUs(); |
|
2353 calcWater(); |
|
2354 calcSparge(); |
|
2355 calcMash(); |
|
2356 }); |
|
2357 $('#boil_time').on('change', function (event) { |
|
2358 console.log("boil_time change:"+parseFloat(event.args.value)+" old:"+dataRecord.boil_time); |
|
2359 var old_evap = parseFloat(dataRecord.boil_size) - parseFloat(dataRecord.batch_size); |
|
2360 var new_evap = old_evap * (parseFloat(event.args.value) / dataRecord.boil_time); |
|
2361 var new_boil = parseFloat(dataRecord.batch_size) + new_evap; |
|
2362 //var factor = new_boil / dataRecord.boil_size; |
|
2363 dataRecord.boil_time = parseFloat(event.args.value); |
|
2364 dataRecord.boil_size = new_boil; |
|
2365 $("#est_pre_vol").val(Math.round(new_boil * 1.04 * 100) / 100); |
|
2366 $("#boil_size").val(Math.round(new_boil * 100) / 100); |
|
2367 calcFermentables(); |
|
2368 calcIBUs(); |
|
2369 calcYeast(); |
|
2370 }); |
|
2371 $('#efficiency').on('change', function (event) { |
|
2372 var estog = parseFloat($("#est_og").jqxNumberInput('decimal')); |
|
2373 dataRecord.efficiency = parseFloat(event.args.value); |
|
2374 console.log("efficiency change:"+dataRecord.efficiency+" est_og:"+estog); |
|
2375 calcFermentablesFromOG(estog); // Keep the OG |
|
2376 calcFermentables(); |
|
2377 calcIBUs(); |
|
2378 calcYeast(); |
|
2379 }); |
|
2380 $('#est_og').on('change', function (event) { |
|
2381 dataRecord.est_og = parseFloat(event.args.value); |
|
2382 console.log("est_og change:"+dataRecord.est_og); |
|
2383 $('#est_og2').val(dataRecord.est_og); |
|
2384 calcFermentablesFromOG(dataRecord.est_og); // Adjust fermentables amounts |
|
2385 calcFermentables(); // Update the recipe details |
|
2386 calcIBUs(); // and the IBU's. |
|
2387 calcMash(); |
|
2388 calcYeast(); |
|
2389 }); |
|
2390 $('#mash_ph').on('change', function (event) { |
|
2391 dataRecord.mash_ph = parseFloat(event.args.value); |
|
2392 calcWater(); |
|
2393 }); |
|
2394 |
|
2395 $('#sparge_ph').on('change', function (event) { |
|
2396 dataRecord.sparge_ph = parseFloat(event.args.value); |
|
2397 calcSparge(); |
|
2398 }); |
|
2399 $('#sparge_volume').on('change', function (event) { |
|
2400 dataRecord.sparge_volume = parseFloat(event.args.value); |
|
2401 $('#brew_sparge_volume').val(dataRecord.sparge_volume); |
|
2402 calcSparge(); |
|
2403 }); |
|
2404 $("#sparge_temp").on('change', function (event) { |
|
2405 dataRecord.sparge_temp = parseFloat(event.args.value); |
|
2406 $('#brew_sparge_temperature').val(dataRecord.sparge_temp); |
|
2407 }); |
|
2408 $('#sparge_source').on('change', function (event) { |
|
2409 if (event.args) { |
|
2410 var index = event.args.index; |
|
2411 dataRecord.sparge_source= index; |
|
2412 calcSparge(); |
|
2413 } |
|
2414 }); |
|
2415 $('#sparge_acid_type').on('change', function (event) { |
|
2416 if (event.args) { |
|
2417 var index = event.args.index; |
|
2418 dataRecord.sparge_acid_type = index; |
|
2419 console.log("new sparge_acid_type: "+dataRecord.sparge_acid_type); |
|
2420 calcSparge(); |
|
2421 } |
|
2422 }); |
|
2423 $('#sparge_acid_perc').on('change', function (event) { |
|
2424 dataRecord.sparge_acid_perc = parseFloat(event.args.value); |
|
2425 calcSparge(); |
|
2426 }); |
|
2427 |
|
2428 calcFermentation(); |
|
2429 calcCarbonation(); |
|
2430 $('#package_volume').on('change', function (event) { |
|
2431 var told = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
2432 dataRecord.package_volume = parseFloat(event.args.value); |
|
2433 if (dataRecord.package_volume > dataRecord.brew_fermenter_volume) { |
|
2434 dataRecord.package_volume = dataRecord.brew_fermenter_volume; |
|
2435 $('#package_volume').val(dataRecord.package_volume); |
|
2436 } |
|
2437 var tnew = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
2438 var diff = tnew - told; |
|
2439 if (told > 0) { |
|
2440 dataRecord.bottle_amount += (dataRecord.bottle_amount / told) * diff; |
|
2441 dataRecord.keg_amount += (dataRecord.keg_amount / told) * diff; |
|
2442 } else { |
|
2443 dataRecord.bottle_amount = tnew; |
|
2444 dataRecord.keg_amount = 0; |
|
2445 } |
|
2446 console.log("diff:"+diff+" old:"+told+" bottle:"+dataRecord.bottle_amount+" keg:"+dataRecord.keg_amount); |
|
2447 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount * 1000) / 1000); |
|
2448 $('#keg_amount').val(parseFloat(dataRecord.keg_amount * 1000) / 1000); |
|
2449 calcCarbonation(); |
|
2450 }); |
|
2451 $('#package_infuse_amount').on('change', function (event) { |
|
2452 var told = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
2453 dataRecord.package_infuse_amount = parseFloat(event.args.value); |
|
2454 var tnew = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
2455 var diff = tnew - told; |
|
2456 if (told > 0) { |
|
2457 dataRecord.bottle_amount += (dataRecord.bottle_amount / told) * diff; |
|
2458 dataRecord.keg_amount += (dataRecord.keg_amount / told) * diff; |
|
2459 } else { |
|
2460 dataRecord.bottle_amount = tnew; |
|
2461 dataRecord.keg_amount = 0; |
|
2462 } |
|
2463 console.log("diff:"+diff+" old:"+told+" bottle:"+dataRecord.bottle_amount+" keg:"+dataRecord.keg_amount); |
|
2464 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount * 1000) / 1000); |
|
2465 $('#keg_amount').val(parseFloat(dataRecord.keg_amount * 1000) / 1000); |
|
2466 calcCarbonation(); |
|
2467 }); |
|
2468 $('#package_infuse_abv').on('change', function (event) { |
|
2469 dataRecord.package_infuse_abv = parseFloat(event.args.value); |
|
2470 calcCarbonation(); |
|
2471 }); |
|
2472 $('#bottle_amount').on('change', function (event) { |
|
2473 var vnew = parseFloat(event.args.value); |
|
2474 var vtot = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
2475 if (vnew > vtot) |
|
2476 vnew = vtot; |
|
2477 diff = dataRecord.bottle_amount - vnew; |
|
2478 dataRecord.bottle_amount = Math.round((dataRecord.bottle_amount - diff) * 1000) / 1000; |
|
2479 dataRecord.keg_amount = Math.round((dataRecord.keg_amount + diff) * 1000) / 1000; |
|
2480 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount)); |
|
2481 $('#keg_amount').val(parseFloat(dataRecord.keg_amount)); |
|
2482 calcCarbonation(); |
|
2483 }); |
|
2484 $("#bottle_priming_water").on('change', function (event) { |
|
2485 dataRecord.bottle_priming_water = parseFloat(event.args.value); |
|
2486 calcCarbonation(); |
|
2487 }); |
|
2488 $('#keg_amount').on('change', function (event) { |
|
2489 var vnew = parseFloat(event.args.value); |
|
2490 var vtot = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
2491 if (vnew > vtot) |
|
2492 vnew = vtot; |
|
2493 diff = dataRecord.keg_amount - vnew; |
|
2494 dataRecord.bottle_amount = Math.round((dataRecord.bottle_amount + diff) * 1000) / 1000; |
|
2495 dataRecord.keg_amount = Math.round((dataRecord.keg_amount - diff) * 1000) / 1000; |
|
2496 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount)); |
|
2497 $('#keg_amount').val(parseFloat(dataRecord.keg_amount)); |
|
2498 calcCarbonation(); |
|
2499 }); |
|
2500 $("#keg_priming_water").on('change', function (event) { |
|
2501 dataRecord.keg_priming_water = parseFloat(event.args.value); |
|
2502 calcCarbonation(); |
|
2503 }); |
|
2504 $('#bottle_carbonation').on('change', function (event) { |
|
2505 dataRecord.bottle_carbonation = parseFloat(event.args.value); |
|
2506 calcCarbonation(); |
|
2507 }); |
|
2508 $('#bottle_carbonation_temp').on('change', function (event) { |
|
2509 dataRecord.bottle_carbonation_temp = parseFloat(event.args.value); |
|
2510 calcCarbonation(); |
|
2511 }); |
|
2512 $('#keg_carbonation').on('change', function (event) { |
|
2513 dataRecord.keg_carbonation = parseFloat(event.args.value); |
|
2514 calcCarbonation(); |
|
2515 }); |
|
2516 $("#keg_forced_carb").on('checked', function (event) { |
|
2517 dataRecord.keg_forced_carb = 1; |
|
2518 calcCarbonation(); |
|
2519 }); |
|
2520 $("#keg_forced_carb").on('unchecked', function (event) { |
|
2521 dataRecord.keg_forced_carb = 0; |
|
2522 calcCarbonation(); |
|
2523 }); |
|
2524 $('#keg_carbonation_temp').on('change', function (event) { |
|
2525 dataRecord.keg_carbonation_temp = parseFloat(event.args.value); |
|
2526 calcCarbonation(); |
|
2527 }); |
|
2528 |
|
2529 $("#brew_fermenter_extrawater").on('change',function (event){ |
|
2530 dataRecord.brew_fermenter_extrawater=parseFloat(event.args.value);calcFermentables();calcIBUs();calcYeast(); |
|
2531 }); |
|
2532 $("#brew_fermenter_tcloss").on('change',function (event){ |
|
2533 dataRecord.brew_fermenter_tcloss=parseFloat(event.args.value);calcFermentables();calcIBUs();calcYeast(); |
|
2534 }); |
|
2535 $("#primary_end_sg").on('change',function (event){dataRecord.primary_end_sg=parseFloat(event.args.value);calcFermentation();}); |
|
2536 $("#primary_end_brix").on('change', function (event) { |
|
2537 if(dataRecord.brew_fermenter_sg>=1.020){ |
|
2538 OBrix=sg_to_brix(dataRecord.brew_fermenter_sg); |
|
2539 FBrix=parseFloat(event.args.value); |
|
2540 var FG=Round(1.0031-0.002318474*OBrix-0.000007775*(OBrix*OBrix)-0.000000034*Math.pow(OBrix,3)+0.00574*(FBrix)+0.00003344*(FBrix*FBrix)+0.000000086*Math.pow(FBrix,3),4); |
|
2541 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG); |
|
2542 if(FBrix>0.05){$("#primary_end_sg").val(FG);dataRecord.primary_end_sg=FG;} |
|
2543 calcFermentation(); |
|
2544 } |
|
2545 }); |
|
2546 $("#secondary_end_sg").on('change',function (event){dataRecord.secondary_end_sg=parseFloat(event.args.value);calcFermentation();}); |
|
2547 $("#secondary_end_brix").on('change', function (event) { |
|
2548 if(dataRecord.brew_fermenter_sg>=1.020){ |
|
2549 OBrix=sg_to_brix(dataRecord.brew_fermenter_sg); |
|
2550 FBrix=parseFloat(event.args.value); |
|
2551 var FG=Round(1.0031-0.002318474*OBrix-0.000007775*(OBrix*OBrix)-0.000000034*Math.pow(OBrix,3)+0.00574*(FBrix)+0.00003344*(FBrix*FBrix)+0.000000086*Math.pow(FBrix,3),4); |
|
2552 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG); |
|
2553 if(FBrix>0.05){$("#secondary_end_sg").val(FG);dataRecord.secondary_end_sg=FG;} |
|
2554 calcFermentation(); |
|
2555 } |
|
2556 }); |
|
2557 $("#final_brix").on('change',function (event){ |
|
2558 if(dataRecord.brew_fermenter_sg>=1.020){ |
|
2559 OBrix=sg_to_brix(dataRecord.brew_fermenter_sg); |
|
2560 FBrix=parseFloat(event.args.value); |
|
2561 var FG=Round(1.0031-0.002318474*OBrix-0.000007775*(OBrix*OBrix)-0.000000034*Math.pow(OBrix,3)+0.00574*(FBrix)+0.00003344*(FBrix*FBrix)+0.000000086*Math.pow(FBrix,3),4); |
|
2562 // Ook brouwhulp SGFerm() maar is niet in gebruik. |
|
2563 //var FG=((1.001843-0.002318474*OBrix-0.000007775*(OBrix*OBrix)-0.000000034*Math.pow(OBrix,3)+0.00574*(FBrix)+0.00003344*(FBrix*FBrix)+0.000000086*Math.pow(FBrix,3))+(1.313454)*0.001); |
|
2564 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG); |
|
2565 if(FBrix>0.05){$("#fg").val(FG);dataRecord.fg=FG;} |
|
2566 calcFermentation(); |
|
2567 } |
|
2568 }); |
|
2569 $("#fg").on('change',function (event){dataRecord.fg=parseFloat(event.args.value);calcFermentation();}); |
|
2570 $("#BLog").jqxButton({disabled:(dataRecord.log_brew)?false:true}); |
|
2571 $("#FLog").jqxButton({disabled:(dataRecord.log_fermentation)?false:true}); |
|
2572 }; |
|
2573 |
|
2574 $("#styleSelect").jqxDropDownList({ |
|
2575 placeHolder: "Kies bierstijl:", |
|
2576 theme: theme, |
|
2577 source: styleslist, |
|
2578 displayMember: "name", |
|
2579 width: 180, |
|
2580 height: 23, |
|
2581 dropDownVerticalAlignment: 'top', |
|
2582 dropDownWidth: 500, |
|
2583 dropDownHeight: 380, |
|
2584 renderer: function (index, label, value) { |
|
2585 var datarecord = styleslist.records[index]; |
|
2586 return datarecord.style_guide + " " + datarecord.style_letter+ " " + datarecord.name; |
|
2587 } |
|
2588 }); |
|
2589 $("#styleSelect").on('select', function (event) { |
|
2590 if (event.args) { |
|
2591 var index = event.args.index; |
|
2592 var datarecord = styleslist.records[index]; |
|
2593 $("#st_name").val(datarecord.name); |
|
2594 $("#st_category").val(datarecord.category); |
|
2595 $("#st_category_number").val(datarecord.category_number); |
|
2596 $("#st_letter").val(datarecord.style_letter); |
|
2597 $("#st_guide").val(datarecord.style_guide); |
|
2598 $("#st_type").val(StyleTypeData[datarecord.type].nl); |
|
2599 $("#st_og_min").val(datarecord.og_min); |
|
2600 $("#st_og_max").val(datarecord.og_max); |
|
2601 $("#st_fg_min").val(datarecord.fg_min); |
|
2602 $("#st_fg_max").val(datarecord.fg_max); |
|
2603 $("#st_ibu_min").val(datarecord.ibu_min); |
|
2604 $("#st_ibu_max").val(datarecord.ibu_max); |
|
2605 $("#st_color_min").val(datarecord.color_min); |
|
2606 $("#st_color_max").val(datarecord.color_max); |
|
2607 $("#st_carb_min").val(datarecord.carb_min); |
|
2608 $("#st_carb_min2").val(datarecord.carb_min); |
|
2609 $("#st_carb_max").val(datarecord.carb_max); |
|
2610 $("#st_carb_max2").val(datarecord.carb_max); |
|
2611 $("#st_abv_min").val(datarecord.abv_min); |
|
2612 $("#st_abv_max").val(datarecord.abv_max); |
|
2613 } |
|
2614 }); |
|
2615 |
|
2616 // Equipemnt dropdown list |
|
2617 $("#equipmentSelect").jqxDropDownList({ |
|
2618 placeHolder: "Kies apparatuur:", |
|
2619 theme: theme, |
|
2620 source: equipmentlist, |
|
2621 displayMember: "name", |
|
2622 width: 170, |
|
2623 height: 23, |
|
2624 dropDownWidth: 300, |
|
2625 renderer: function (index, label, value) { |
|
2626 var datarecord = equipmentlist.records[index]; |
|
2627 return datarecord.batch_size + " liter " + datarecord.name; |
|
2628 } |
|
2629 }); |
|
2630 $("#equipmentSelect").on('select', function (event) { |
|
2631 if (event.args) { |
|
2632 var index = event.args.index; |
|
2633 var datarecord = equipmentlist.records[index]; |
|
2634 var factor = datarecord.batch_size / dataRecord.batch_size; |
|
2635 $("#eq_name").val(datarecord.name); |
|
2636 $("#eq_boil_size").val(datarecord.boil_size); |
|
2637 dataRecord.boil_size = datarecord.boil_size; |
|
2638 $("#boil_size").val(datarecord.boil_size); |
|
2639 $("#eq_batch_size").val(datarecord.batch_size); |
|
2640 dataRecord.batch_size = datarecord.batch_size; |
|
2641 $("#batch_size").val(datarecord.batch_size); |
|
2642 $("#est_a_vol").val(datarecord.batch_size * 1.04); |
|
2643 $("#eq_tun_volume").val(datarecord.tun_volume); |
|
2644 dataRecord.eq_tun_weight = datarecord.tun_weight; |
|
2645 dataRecord.eq_tun_specific_heat = datarecord.tun_specific_heat; |
|
2646 dataRecord.eq_tun_material = datarecord.tun_material; |
|
2647 dataRecord.eq_tun_height = datarecord.tun_height / 100.0; |
|
2648 $("#eq_top_up_water").val(datarecord.top_up_water); |
|
2649 dataRecord.eq_trub_chiller_loss = datarecord.trub_chiller_loss; |
|
2650 $("#eq_trub_chiller_loss").val(datarecord.trub_chiller_loss); |
|
2651 $("#eq_evap_rate").val(datarecord.evap_rate); |
|
2652 $("#eq_boil_time").val(datarecord.boil_time); |
|
2653 dataRecord.eq_calc_boil_volume = datarecord.calc_boil_volume; |
|
2654 $("#eq_top_up_kettle").val(datarecord.top_up_kettle); |
|
2655 $("#eq_hop_utilization").val(datarecord.hop_utilization); |
|
2656 $("#eq_notes").val(datarecord.notes); |
|
2657 $("#eq_lauter_volume").val(datarecord.lauter_volume); |
|
2658 dataRecord.eq_lauter_height = datarecord.lauter_height / 100.0; |
|
2659 $("#eq_lauter_deadspace").val(datarecord.lauter_deadspace); |
|
2660 $("#eq_kettle_volume").val(datarecord.kettle_volume); |
|
2661 dataRecord.eq_kettle_height = datarecord.kettle_height / 100.0; |
|
2662 $("#eq_mash_volume").val(datarecord.mash_volume); |
|
2663 $("#eq_mash_max").val(datarecord.mash_max); |
|
2664 dataRecord.eq_mash_max = datarecord.mash_max; |
|
2665 $("#mash_max").val(datarecord.mash_max); |
|
2666 $("#eq_efficiency").val(datarecord.efficiency); |
|
2667 dataRecord.efficiency = datarecord.efficiency; |
|
2668 $("#efficiency").val(datarecord.efficiency); |
|
2669 |
|
2670 dataRecord.sparge_volume = Math.round(datarecord.boil_size * 5) / 10; |
|
2671 $("#sparge_volume").val(dataRecord.sparge_volume); |
|
2672 $("#brew_sparge_volume").val(dataRecord.sparge_volume); |
|
2673 $("#est_pre_vol").val(datarecord.boil_size * 1.04); |
|
2674 calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal'))); // Keep the OG |
|
2675 adjustWaters(factor); |
|
2676 calcFermentables(); |
|
2677 adjustHops(factor); |
|
2678 adjustMiscs(factor); |
|
2679 adjustYeasts(factor); |
|
2680 calcIBUs(); |
|
2681 calcWater(); |
|
2682 calcSparge(); |
|
2683 } |
|
2684 }); |
|
2685 |
|
2686 function saveRecord() { |
|
2687 console.log("saveRecord()"); |
|
2688 var fermentablerow = $('#fermentableGrid').jqxGrid('getrows'); |
|
2689 var hoprow = $('#hopGrid').jqxGrid('getrows'); |
|
2690 var miscrow = $('#miscGrid').jqxGrid('getrows'); |
|
2691 var yeastrow = $('#yeastGrid').jqxGrid('getrows'); |
|
2692 var mashrow = $('#mashGrid').jqxGrid('getrows'); |
|
2693 var row = { |
|
2694 record: my_record, |
|
2695 uuid: dataRecord.uuid, |
|
2696 name: $("#name").val(), |
|
2697 code: $("#code").val(), |
|
2698 birth: $("#birth").val(), |
|
2699 stage: dataRecord.stage, |
|
2700 notes: $("#notes").val(), |
|
2701 log_brew: dataRecord.log_brew, |
|
2702 log_fermentation: dataRecord.log_fermentation, |
|
2703 inventory_reduced: dataRecord.inventory_reduced, |
|
2704 locked: dataRecord.locked, |
|
2705 eq_name: $("#eq_name").val(), |
|
2706 eq_boil_size: parseFloat($("#eq_boil_size").jqxNumberInput('decimal')), |
|
2707 eq_batch_size: parseFloat($("#eq_batch_size").jqxNumberInput('decimal')), |
|
2708 eq_tun_volume: parseFloat($("#eq_tun_volume").jqxNumberInput('decimal')), |
|
2709 eq_tun_weight: dataRecord.eq_tun_weight, |
|
2710 eq_tun_specific_heat: dataRecord.eq_tun_specific_heat, |
|
2711 eq_tun_material: dataRecord.eq_tun_material, |
|
2712 eq_tun_height: dataRecord.eq_tun_height, |
|
2713 eq_top_up_water: parseFloat($("#eq_top_up_water").jqxNumberInput('decimal')), |
|
2714 eq_trub_chiller_loss: parseFloat($("#eq_trub_chiller_loss").jqxNumberInput('decimal')), |
|
2715 eq_evap_rate: parseFloat($("#eq_evap_rate").jqxNumberInput('decimal')), |
|
2716 eq_boil_time: parseFloat($("#eq_boil_time").jqxNumberInput('decimal')), |
|
2717 eq_calc_boil_volume: dataRecord.eq_calc_boil_volume, |
|
2718 eq_top_up_kettle: parseFloat($("#eq_top_up_kettle").jqxNumberInput('decimal')), |
|
2719 eq_hop_utilization: parseFloat($("#eq_hop_utilization").jqxNumberInput('decimal')), |
|
2720 eq_notes: $("#eq_notes").val(), |
|
2721 eq_lauter_volume: parseFloat($("#eq_lauter_volume").jqxNumberInput('decimal')), |
|
2722 eq_lauter_height: dataRecord.eq_lauter_height, |
|
2723 eq_lauter_deadspace: parseFloat($("#eq_lauter_deadspace").jqxNumberInput('decimal')), |
|
2724 eq_kettle_volume: parseFloat($("#eq_kettle_volume").jqxNumberInput('decimal')), |
|
2725 eq_kettle_height: dataRecord.eq_kettle_height, |
|
2726 eq_mash_volume: parseFloat($("#eq_mash_volume").jqxNumberInput('decimal')), |
|
2727 eq_mash_max: parseFloat($("#eq_mash_max").jqxNumberInput('decimal')), |
|
2728 eq_efficiency: parseFloat($("#eq_efficiency").jqxNumberInput('decimal')), |
|
2729 brew_date_start: $("#brew_date_start").val(), |
|
2730 brew_mash_ph: parseFloat($("#brew_mash_ph").jqxNumberInput('decimal')), |
|
2731 brew_mash_sg: parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')), |
|
2732 brew_mash_efficiency: parseFloat($("#brew_mash_efficiency").jqxNumberInput('decimal')), |
|
2733 brew_sparge_est: parseFloat($("#brew_sparge_est").jqxNumberInput('decimal')), |
|
2734 brew_sparge_ph: parseFloat($("#brew_sparge_ph").jqxNumberInput('decimal')), |
|
2735 brew_preboil_volume: parseFloat($("#brew_preboil_volume").jqxNumberInput('decimal')), |
|
2736 brew_preboil_sg: parseFloat($("#brew_preboil_sg").jqxNumberInput('decimal')), |
|
2737 brew_preboil_ph: parseFloat($("#brew_preboil_ph").jqxNumberInput('decimal')), |
|
2738 brew_preboil_efficiency: parseFloat($("#brew_preboil_efficiency").jqxNumberInput('decimal')), |
|
2739 brew_aboil_volume: parseFloat($("#brew_aboil_volume").jqxNumberInput('decimal')), |
|
2740 brew_aboil_sg: parseFloat($("#brew_aboil_sg").jqxNumberInput('decimal')), |
|
2741 brew_aboil_ph: parseFloat($("#brew_aboil_ph").jqxNumberInput('decimal')), |
|
2742 brew_aboil_efficiency: parseFloat($("#brew_aboil_efficiency").jqxNumberInput('decimal')), |
|
2743 brew_cooling_method: $("#brew_cooling_method").val(), |
|
2744 brew_cooling_time: parseFloat($("#brew_cooling_time").jqxNumberInput('decimal')), |
|
2745 brew_cooling_to: parseFloat($("#brew_cooling_to").jqxNumberInput('decimal')), |
|
2746 brew_whirlpool9: parseFloat($("#brew_whirlpool9").jqxNumberInput('decimal')), |
|
2747 brew_whirlpool7: parseFloat($("#brew_whirlpool7").jqxNumberInput('decimal')), |
|
2748 brew_whirlpool6: parseFloat($("#brew_whirlpool6").jqxNumberInput('decimal')), |
|
2749 brew_whirlpool2: parseFloat($("#brew_whirlpool2").jqxNumberInput('decimal')), |
|
2750 brew_fermenter_volume: parseFloat($("#brew_fermenter_volume").jqxNumberInput('decimal')), |
|
2751 brew_fermenter_extrawater: parseFloat($("#brew_fermenter_extrawater").jqxNumberInput('decimal')), |
|
2752 brew_fermenter_tcloss: parseFloat($("#brew_fermenter_tcloss").jqxNumberInput('decimal')), |
|
2753 brew_aeration_time: parseFloat($("#brew_aeration_time").jqxNumberInput('decimal')), |
|
2754 brew_aeration_speed: parseFloat($("#brew_aeration_speed").jqxNumberInput('decimal')), |
|
2755 brew_aeration_type: $("#brew_aeration_type").val(), |
|
2756 brew_fermenter_sg: parseFloat($("#brew_fermenter_sg").jqxNumberInput('decimal')), |
|
2757 brew_fermenter_ibu: parseFloat($("#brew_fermenter_ibu").jqxNumberInput('decimal')), |
|
2758 brew_fermenter_color: parseFloat($("#brew_fermenter_color").jqxNumberInput('decimal')), |
|
2759 brew_date_end: $("#brew_date_end").val(), |
|
2760 og: dataRecord.og, |
|
2761 fg: parseFloat($("#fg").jqxNumberInput('decimal')), |
|
2762 primary_start_temp: parseFloat($("#primary_start_temp").jqxNumberInput('decimal')), |
|
2763 primary_max_temp: parseFloat($("#primary_max_temp").jqxNumberInput('decimal')), |
|
2764 primary_end_temp: parseFloat($("#primary_end_temp").jqxNumberInput('decimal')), |
|
2765 primary_end_sg: parseFloat($("#primary_end_sg").jqxNumberInput('decimal')), |
|
2766 primary_end_date: $("#primary_end_date").val(), |
|
2767 secondary_temp: parseFloat($("#secondary_temp").jqxNumberInput('decimal')), |
|
2768 secondary_end_sg: parseFloat($("#secondary_end_sg").jqxNumberInput('decimal')), |
|
2769 secondary_end_date: $("#secondary_end_date").val(), |
|
2770 tertiary_temp: parseFloat($("#tertiary_temp").jqxNumberInput('decimal')), |
|
2771 package_date: $("#package_date").val(), |
|
2772 package_volume: parseFloat($("#package_volume").jqxNumberInput('decimal')), |
|
2773 package_infuse_amount: parseFloat($("#package_infuse_amount").jqxNumberInput('decimal')), |
|
2774 package_infuse_abv: parseFloat($("#package_infuse_abv").jqxNumberInput('decimal')), |
|
2775 package_infuse_notes: $("#package_infuse_notes").val(), |
|
2776 package_abv: parseFloat($("#package_abv").jqxNumberInput('decimal')), |
|
2777 package_ph: parseFloat($("#package_ph").jqxNumberInput('decimal')), |
|
2778 bottle_amount: parseFloat($("#bottle_amount").jqxNumberInput('decimal')), |
|
2779 bottle_carbonation: parseFloat($("#bottle_carbonation").jqxNumberInput('decimal')), |
|
2780 bottle_priming_water: parseFloat($("#bottle_priming_water").jqxNumberInput('decimal')), |
|
2781 bottle_priming_amount: parseFloat($("#bottle_priming_amount").jqxNumberInput('decimal')), |
|
2782 bottle_carbonation_temp: parseFloat($("#bottle_carbonation_temp").jqxNumberInput('decimal')), |
|
2783 keg_amount: parseFloat($("#keg_amount").jqxNumberInput('decimal')), |
|
2784 keg_carbonation: parseFloat($("#keg_carbonation").jqxNumberInput('decimal')), |
|
2785 keg_priming_water: parseFloat($("#keg_priming_water").jqxNumberInput('decimal')), |
|
2786 keg_priming_amount: parseFloat($("#keg_priming_amount").jqxNumberInput('decimal')), |
|
2787 keg_carbonation_temp: parseFloat($("#keg_carbonation_temp").jqxNumberInput('decimal')), |
|
2788 keg_forced_carb: dataRecord.keg_forced_carb, |
|
2789 keg_pressure: parseFloat($("#keg_pressure").jqxNumberInput('decimal')), |
|
2790 taste_notes: $("#taste_notes").val(), |
|
2791 taste_rate: parseFloat($("#taste_rate").jqxNumberInput('decimal')), |
|
2792 taste_date: $("#taste_date").val(), |
|
2793 taste_color: $("#taste_color").val(), |
|
2794 taste_transparency: $("#taste_transparency").val(), |
|
2795 taste_head: $("#taste_head").val(), |
|
2796 taste_aroma: $("#taste_aroma").val(), |
|
2797 taste_taste: $("#taste_taste").val(), |
|
2798 taste_mouthfeel: $("#taste_mouthfeel").val(), |
|
2799 taste_aftertaste: $("#taste_aftertaste").val(), |
|
2800 st_name: $('#st_name').val(), |
|
2801 st_letter: $('#st_letter').val(), |
|
2802 st_guide: $('#st_guide').val(), |
|
2803 st_type: dataRecord.st_type, |
|
2804 st_category: $('#st_category').val(), |
|
2805 st_category_number: parseFloat($("#st_category_number").jqxNumberInput('decimal')), |
|
2806 st_og_min: parseFloat($("#st_og_min").jqxNumberInput('decimal')), |
|
2807 st_og_max: parseFloat($("#st_og_max").jqxNumberInput('decimal')), |
|
2808 st_fg_min: parseFloat($("#st_fg_min").jqxNumberInput('decimal')), |
|
2809 st_fg_max: parseFloat($("#st_fg_max").jqxNumberInput('decimal')), |
|
2810 st_ibu_min: parseFloat($("#st_ibu_min").jqxNumberInput('decimal')), |
|
2811 st_ibu_max: parseFloat($("#st_ibu_max").jqxNumberInput('decimal')), |
|
2812 st_color_min: parseFloat($("#st_color_min").jqxNumberInput('decimal')), |
|
2813 st_color_max: parseFloat($("#st_color_max").jqxNumberInput('decimal')), |
|
2814 st_carb_min: parseFloat($("#st_carb_min").jqxNumberInput('decimal')), |
|
2815 st_carb_max: parseFloat($("#st_carb_max").jqxNumberInput('decimal')), |
|
2816 st_abv_min: parseFloat($("#st_abv_min").jqxNumberInput('decimal')), |
|
2817 st_abv_max: parseFloat($("#st_abv_max").jqxNumberInput('decimal')), |
|
2818 type: $("#type").val(), |
|
2819 batch_size: parseFloat($("#batch_size").jqxNumberInput('decimal')), |
|
2820 boil_size: parseFloat($("#boil_size").jqxNumberInput('decimal')), |
|
2821 boil_time: parseFloat($("#boil_time").jqxNumberInput('decimal')), |
|
2822 efficiency: parseFloat($("#efficiency").jqxNumberInput('decimal')), |
|
2823 est_og: parseFloat($("#est_og").jqxNumberInput('decimal')), |
|
2824 est_fg: parseFloat($("#est_fg").jqxNumberInput('decimal')), |
|
2825 est_abv: parseFloat($("#est_abv").jqxNumberInput('decimal')), |
|
2826 est_color: parseFloat($("#est_color").jqxNumberInput('decimal')), |
|
2827 color_method: $("#color_method").val(), |
|
2828 est_ibu: parseFloat($("#est_ibu").jqxNumberInput('decimal')), |
|
2829 ibu_method: $("#ibu_method").val(), |
|
2830 est_carb: parseFloat($("#est_carb").jqxNumberInput('decimal')), |
|
2831 mash_name: $("#mash_name").val(), |
|
2832 mash_ph: parseFloat($("#mash_ph").jqxNumberInput('decimal')), |
|
2833 sparge_temp: parseFloat($("#sparge_temp").jqxNumberInput('decimal')), |
|
2834 sparge_ph: parseFloat($("#sparge_ph").jqxNumberInput('decimal')), |
|
2835 sparge_volume: parseFloat($("#sparge_volume").jqxNumberInput('decimal')), |
|
2836 sparge_source: $("#sparge_source").val(), |
|
2837 sparge_acid_type: $("#sparge_acid_type").val(), |
|
2838 sparge_acid_perc: parseFloat($("#sparge_acid_perc").jqxNumberInput('decimal')), |
|
2839 sparge_acid_amount: dataRecord.sparge_acid_amount, |
|
2840 calc_acid: dataRecord.calc_acid, |
|
2841 w1_name: $("#w1_name").val(), |
|
2842 w1_amount: parseFloat($("#w1_amount").jqxNumberInput('decimal')), |
|
2843 w1_calcium: parseFloat($("#w1_calcium").jqxNumberInput('decimal')), |
|
2844 w1_sulfate: parseFloat($("#w1_sulfate").jqxNumberInput('decimal')), |
|
2845 w1_chloride: parseFloat($("#w1_chloride").jqxNumberInput('decimal')), |
|
2846 w1_sodium: parseFloat($("#w1_sodium").jqxNumberInput('decimal')), |
|
2847 w1_magnesium: parseFloat($("#w1_magnesium").jqxNumberInput('decimal')), |
|
2848 w1_total_alkalinity: parseFloat($("#w1_total_alkalinity").jqxNumberInput('decimal')), |
|
2849 w1_ph: parseFloat($("#w1_ph").jqxNumberInput('decimal')), |
|
2850 w1_cost: dataRecord.w1_cost, |
|
2851 w2_name: $("#w2_name").val(), |
|
2852 w2_amount: parseFloat($("#w2_amount").jqxNumberInput('decimal')), |
|
2853 w2_calcium: parseFloat($("#w2_calcium").jqxNumberInput('decimal')), |
|
2854 w2_sulfate: parseFloat($("#w2_sulfate").jqxNumberInput('decimal')), |
|
2855 w2_chloride: parseFloat($("#w2_chloride").jqxNumberInput('decimal')), |
|
2856 w2_sodium: parseFloat($("#w2_sodium").jqxNumberInput('decimal')), |
|
2857 w2_magnesium: parseFloat($("#w2_magnesium").jqxNumberInput('decimal')), |
|
2858 w2_total_alkalinity: parseFloat($("#w2_total_alkalinity").jqxNumberInput('decimal')), |
|
2859 w2_ph: parseFloat($("#w2_ph").jqxNumberInput('decimal')), |
|
2860 w2_cost: dataRecord.w2_cost, |
|
2861 wg_amount: parseFloat($("#wg_amount").jqxNumberInput('decimal')), |
|
2862 wg_calcium: parseFloat($("#wg_calcium").jqxNumberInput('decimal')), |
|
2863 wg_sulfate: parseFloat($("#wg_sulfate").jqxNumberInput('decimal')), |
|
2864 wg_chloride: parseFloat($("#wg_chloride").jqxNumberInput('decimal')), |
|
2865 wg_sodium: parseFloat($("#wg_sodium").jqxNumberInput('decimal')), |
|
2866 wg_magnesium: parseFloat($("#wg_magnesium").jqxNumberInput('decimal')), |
|
2867 wg_total_alkalinity: parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')), |
|
2868 wg_ph: parseFloat($("#wg_ph").jqxNumberInput('decimal')), |
|
2869 wb_calcium: parseFloat($("#wb_calcium").jqxNumberInput('decimal')), |
|
2870 wb_sulfate: parseFloat($("#wb_sulfate").jqxNumberInput('decimal')), |
|
2871 wb_chloride: parseFloat($("#wb_chloride").jqxNumberInput('decimal')), |
|
2872 wb_sodium: parseFloat($("#wb_sodium").jqxNumberInput('decimal')), |
|
2873 wb_magnesium: parseFloat($("#wb_magnesium").jqxNumberInput('decimal')), |
|
2874 wb_total_alkalinity: parseFloat($("#wb_total_alkalinity").jqxNumberInput('decimal')), |
|
2875 wb_ph: parseFloat($("#wb_ph").jqxNumberInput('decimal')), |
|
2876 wa_acid_name: $("#wa_acid_name").val(), |
|
2877 wa_acid_perc: parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')), |
|
2878 wa_base_name: $("#wa_base_name").val(), |
|
2879 starter_enable: dataRecord.starter_enable, |
|
2880 starter_type: $("#starter_type").val(), |
|
2881 starter_sg: parseFloat($("#starter_sg").jqxNumberInput('decimal')), |
|
2882 starter_viability: parseFloat($("#starter_viability").jqxNumberInput('decimal')), |
|
2883 prop1_type: $("#prop1_type").val(), |
|
2884 prop1_volume: parseFloat($("#prop1_volume").jqxNumberInput('decimal')), |
|
2885 prop2_type: $("#prop2_type").val(), |
|
2886 prop2_volume: parseFloat($("#prop2_volume").jqxNumberInput('decimal')), |
|
2887 prop3_type: $("#prop3_type").val(), |
|
2888 prop3_volume: parseFloat($("#prop3_volume").jqxNumberInput('decimal')), |
|
2889 prop4_type: $("#prop4_type").val(), |
|
2890 prop4_volume: parseFloat($("#prop4_volume").jqxNumberInput('decimal')), |
|
2891 fermentables: fermentablerow, |
|
2892 hops: hoprow, |
|
2893 miscs: miscrow, |
|
2894 yeasts: yeastrow, |
|
2895 mashs: mashrow |
|
2896 }; |
|
2897 var data = "update=true&" + $.param(row); |
|
2898 $.ajax({ |
|
2899 dataType: 'json', |
|
2900 url: url, |
|
2901 cache: false, |
|
2902 data: data, |
|
2903 async: false, |
|
2904 type: "POST", |
|
2905 success: function (data, status, xhr) { |
|
2906 console.log("saveRecord() success"); |
|
2907 }, |
|
2908 error: function(jqXHR, textStatus, errorThrown) { |
|
2909 console.log("saveRecord() error"); |
|
2910 } |
|
2911 }); |
|
2912 }; |
|
2913 |
|
2914 var dataRecord = {}; |
|
2915 var url = "includes/db_product.php"; |
|
2916 |
103 |
2917 // Prepare the data |
104 // Prepare the data |
2918 var source = { |
105 source = { |
2919 datatype: "json", |
106 datatype: "json", |
2920 cache: false, |
107 cache: false, |
2921 datafields: [ |
108 datafields: [ |
2922 // From prod_main |
109 // From prod_main |
2923 { name: 'record', type: 'number' }, |
110 { name: 'record', type: 'number' }, |
4387 } |
1572 } |
4388 ] |
1573 ] |
4389 }); |
1574 }); |
4390 }; |
1575 }; |
4391 |
1576 |
|
1577 /* |
|
1578 * Remove the top menu so that we MUST use the buttons to leave the editor. |
|
1579 */ |
|
1580 $('#jqxMenu').jqxMenu('destroy'); |
|
1581 console.log("record:" + my_record + " return:" + my_return + " theme:" + theme); |
|
1582 $("#jqxLoader").jqxLoader({width:250,height:150,isModal:true,text:"Laden product ...",theme:theme}); |
|
1583 dataAdapter.dataBind(); |
|
1584 |
|
1585 /* |
|
1586 * Generic functions |
|
1587 */ |
|
1588 function calcSupplies() { |
|
1589 if (dataRecord.inventory_reduced > 6) { |
|
1590 $("#ok_pmpt").hide(); |
|
1591 return; |
|
1592 } |
|
1593 if (ok_fermentables && ok_hops && ok_miscs && ok_yeasts && ok_waters) |
|
1594 $("#ok_supplies").html("<img src='images/dialog-ok-apply.png'>"); |
|
1595 else |
|
1596 $("#ok_supplies").html("<img src='images/dialog-error.png'>"); |
|
1597 } |
|
1598 |
|
1599 function calcPercentages() { |
|
1600 |
|
1601 console.log("calcPercentages()"); |
|
1602 var tw = 0, rowdata, percentage, rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; |
|
1603 if (rowscount > 1) { |
|
1604 for (i = 0; i < rowscount; i++) { |
|
1605 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i); |
|
1606 if (rowdata.f_added < 4) |
|
1607 tw += Round(rowdata.f_amount, 3); |
|
1608 }; |
|
1609 tw = Round(tw, 3); |
|
1610 |
|
1611 for (i = 0; i < rowscount; i++) { |
|
1612 rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i); |
|
1613 if (rowdata.f_added < 4) { |
|
1614 percentage = Round(rowdata.f_amount / tw * 100, 1); |
|
1615 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage); |
|
1616 } else { |
|
1617 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", 0); |
|
1618 } |
|
1619 }; |
|
1620 } else { |
|
1621 $("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100); |
|
1622 } |
|
1623 } |
|
1624 |
|
1625 /* |
|
1626 * All calculations that depend on changes in the fermentables, |
|
1627 * volumes and equipments. |
|
1628 */ |
|
1629 function calcFermentables() { |
|
1630 |
|
1631 var sugarsf = 0, // fermentable sugars mash + boil |
|
1632 sugarsm = 0, // fermentable sugars in mash |
|
1633 vol = 0, // Volume sugars after boil |
|
1634 addedS = 0, // Added sugars after boil |
|
1635 addedmass = 0, // Added mass after boil |
|
1636 mvol = 0, // mash volume |
|
1637 colort = 0, // Colors srm * vol totals |
|
1638 colorh = 0, // Colors ebc * vol * kt |
|
1639 colorn = 0, // Colors ebc * pt * pct |
|
1640 my_100 = false, |
|
1641 mashtime = 0, // Total mash time |
|
1642 mashtemp = 0, // Average mash temperature |
|
1643 bv = 0.925, // Bierverlies rendement |
|
1644 sr = 0.95, // Mash en spoel rendement |
|
1645 lintner = 0, // Total recipe lintner |
|
1646 i, row, rows, org, timem, aboil_volume, spoelw, ogx, topw, s = 0, d, v, x, |
|
1647 sug, alc, pt, cw, color, scolor, fig; |
|
1648 |
|
1649 /* Init global variables */ |
|
1650 psugar = 0; |
|
1651 pcara = 0; |
|
1652 mashkg = 0; |
|
1653 ok_fermentables = 1; // All is in stock. |
|
1654 ok_yeasts = 1; |
|
1655 |
|
1656 if ((rows = $('#mashGrid').jqxGrid('getrows'))){ |
|
1657 for (i = 0; i <rows.length; i++){ |
|
1658 row=rows[i]; |
|
1659 if(row.step_type==0) // Infusion |
|
1660 mvol+=parseFloat(row.step_infuse_amount); |
|
1661 if(row.step_temp<=75){ // Ignore mashout |
|
1662 timem=row.step_time+row.ramp_time; |
|
1663 mashtime+=timem; |
|
1664 mashtemp+=timem*row.step_temp; |
|
1665 } |
|
1666 } |
|
1667 if(mashtime>5) |
|
1668 mashtime-=5;//Correct last ramp > 75 |
|
1669 mashtemp=Round(mashtemp/mashtime,2); |
|
1670 } |
|
1671 |
|
1672 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { |
|
1673 return; // grid not yet loaded. |
|
1674 } |
|
1675 |
|
1676 for (i = 0; i < rows.length; i++) { |
|
1677 row = rows[i]; |
|
1678 if (row.f_adjust_to_total_100) |
|
1679 my_100 = true; |
|
1680 if (row.f_type == 1 && row.f_added < 4) // Sugar |
|
1681 psugar += row.f_percentage; |
|
1682 if (row.f_graintype == 2 && row.f_added < 4) // Crystal |
|
1683 pcara += row.f_percentage; |
|
1684 d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
1685 if (row.f_added == 0) { // Mash |
|
1686 if (mvol > 0) { // Only if mash already known. |
|
1687 mvol += row.f_amount * row.f_moisture / 100; |
|
1688 s += d; |
|
1689 } |
|
1690 d = parseFloat(dataRecord.efficiency) / 100 * d; |
|
1691 sugarsm += d; |
|
1692 mashkg += parseFloat(row.f_amount); |
|
1693 } |
|
1694 if (row.f_added == 0 || row.f_added == 1) // Mash or Boil |
|
1695 sugarsf += d; |
|
1696 if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering |
|
1697 x = (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
1698 addedS += row.f_amount * x; |
|
1699 addedmass += row.f_amount; |
|
1700 vol += (x * sugardensity + (1 - x) * 1) * row.f_amount; |
|
1701 } |
|
1702 if (row.f_added < 4) { |
|
1703 colort += row.f_amount * ebc_to_srm(row.f_color); |
|
1704 colorh += row.f_amount * row.f_color * get_kt(row.f_color); |
|
1705 colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort. |
|
1706 } |
|
1707 if (fermentableInit) { |
|
1708 if (row.f_added == 4) { |
|
1709 $("#bottle_priming_total").val(row.f_amount * 1000); // Prevent clearing |
|
1710 $("#bottle_priming_sugar").jqxDropDownList('selectItem', row.f_name); |
|
1711 } |
|
1712 if (row.f_added == 5) { |
|
1713 $("#keg_priming_total").val(row.f_amount * 1000); |
|
1714 $("#keg_priming_sugar").jqxDropDownList('selectItem', row.f_name); |
|
1715 } |
|
1716 } |
|
1717 // Check supplies. |
|
1718 if ((((dataRecord.inventory_reduced <= 2) && (row.f_added <= 1)) || // Mash or boil |
|
1719 ((dataRecord.inventory_reduced <= 3) && (row.f_added == 2)) || // Primary |
|
1720 ((dataRecord.inventory_reduced <= 5) && (row.f_added == 3)) || // Secondary or Tertiary |
|
1721 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4)) || // Bottle |
|
1722 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 5))) && row.f_inventory < row.f_amount) { |
|
1723 ok_fermentables = 0; |
|
1724 } |
|
1725 if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50 |
|
1726 lintner += row.f_diastatic_power * row.f_amount; |
|
1727 } |
|
1728 } |
|
1729 fermentableInit = 0; |
|
1730 $("#ferm_lintner").val(Math.round(parseFloat(lintner / mashkg))); |
|
1731 $("#mash_kg").val(mashkg); |
|
1732 console.log("calcFermentables() supplies:"+ok_fermentables+" moutsuiker:"+sugarsm+"/"+sugarsf); |
|
1733 to_100 = my_100; |
|
1734 if (to_100) { |
|
1735 $("#wf_amount").jqxNumberInput({ width: 90, readOnly: true, spinButtons: false }); |
|
1736 } else { |
|
1737 $("#wf_amount").jqxNumberInput({ width: 110, readOnly: false, spinButtons: true }); |
|
1738 } |
|
1739 |
|
1740 if (mvol > 0) { |
|
1741 v = s / sugardensity + mvol; |
|
1742 s = 1000 * s / (v * 10); //deg. Plato |
|
1743 est_mash_sg = Round(plato_to_sg(s), 5); |
|
1744 $('#est_mash_sg').val(est_mash_sg); |
|
1745 } |
|
1746 |
|
1747 // Estimate total recipe OG. |
|
1748 dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size)); |
|
1749 $('#est_og').val(dataRecord.est_og); |
|
1750 $('#est_og2').val(dataRecord.est_og); |
|
1751 org = dataRecord.est_og; |
|
1752 |
|
1753 // Estimate SG in kettle after boil |
|
1754 aboil_sg = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size)); |
|
1755 $('#est_og3').val(aboil_sg); |
|
1756 |
|
1757 // Estimate SG in kettle before boil |
|
1758 preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size)); |
|
1759 $('#est_pre_sg').val(preboil_sg); |
|
1760 |
|
1761 // Recalculate volumes. |
|
1762 aboil_volume = parseFloat(dataRecord.batch_size); |
|
1763 if (dataRecord.brew_aboil_volume > 0) |
|
1764 aboil_volume = dataRecord.brew_aboil_volume / 1.04; // volume @ 20 degrees |
|
1765 if (dataRecord.brew_fermenter_tcloss == 0) { |
|
1766 dataRecord.brew_fermenter_tcloss = dataRecord.eq_trub_chiller_loss; |
|
1767 $("#brew_fermenter_tcloss").val(dataRecord.brew_fermenter_tcloss); |
|
1768 } |
|
1769 dataRecord.brew_fermenter_volume = aboil_volume - dataRecord.brew_fermenter_tcloss + dataRecord.brew_fermenter_extrawater; |
|
1770 $("#brew_fermenter_volume").val(dataRecord.brew_fermenter_volume); |
|
1771 // Estimated needed sparge water corrected for the temperature. |
|
1772 spoelw = (dataRecord.boil_size - mash_infuse + (mashkg * my_grain_absorbtion) + dataRecord.eq_lauter_deadspace) * 1.03; |
|
1773 $("#brew_sparge_est").val(spoelw); |
|
1774 // Calculate SG in fermenter |
|
1775 ogx = dataRecord.brew_aboil_sg; |
|
1776 if (ogx < 1.002) |
|
1777 ogx = aboil_sg; |
|
1778 topw = dataRecord.brew_fermenter_extrawater; |
|
1779 |
|
1780 if (dataRecord.brew_fermenter_volume > 0) { |
|
1781 sug = sg_to_plato(ogx) * dataRecord.brew_fermenter_volume * ogx / 100; //kg of sugar in |
|
1782 sug += addedS; //kg |
|
1783 |
|
1784 if ((dataRecord.brew_fermenter_volume * ogx + addedmass) > 0) { |
|
1785 pt = 100 * sug / (dataRecord.brew_fermenter_volume * ogx + addedmass + topw); |
|
1786 dataRecord.brew_fermenter_sg = Round(plato_to_sg(pt),4); |
|
1787 $("#brew_fermenter_sg").val(dataRecord.brew_fermenter_sg); |
|
1788 // color |
|
1789 if (dataRecord.color_method == 4) { |
|
1790 dataRecord.brew_fermenter_color = Math.round(((pt / 8.6) * colorn) + (dataRecord.boil_time / 60)); |
|
1791 } else if (dataRecord.color_method == 3) { |
|
1792 dataRecord.brew_fermenter_color = Math.round((4.46 * bv * sr) / (aboil_volume + topw) * colorh); |
|
1793 } else { |
|
1794 cw = colort / (aboil_volume + topw) * 8.34436; |
|
1795 dataRecord.brew_fermenter_color = kw_to_ebc(dataRecord.color_method, cw); |
|
1796 } |
|
1797 $("#brew_fermenter_color").val(dataRecord.brew_fermenter_color); |
|
1798 scolor = ebc_to_color(dataRecord.brew_fermenter_color); |
|
1799 $("#bcolorf").show(); |
|
1800 document.getElementById("bcolorf").style.background = scolor; |
|
1801 } |
|
1802 } else { |
|
1803 // Negative volume |
|
1804 dataRecord.brew_fermenter_sg = dataRecord.brew_fermenter_color = 0; |
|
1805 $("#brew_fermenter_sg").val(0); |
|
1806 $("#brew_fermenter_color").val(0); |
|
1807 $("#bcolorf").hide(); |
|
1808 } |
|
1809 |
|
1810 // Color of the wort |
|
1811 if (dataRecord.color_method == 4) { |
|
1812 color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60)); |
|
1813 } else if (dataRecord.color_method == 3) { // Hans Halberstadt |
|
1814 color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh); |
|
1815 } else { |
|
1816 cw = colort / parseFloat(dataRecord.batch_size) * 8.34436; |
|
1817 color = kw_to_ebc(dataRecord.color_method, cw); |
|
1818 } |
|
1819 dataRecord.est_color = color; |
|
1820 $('#est_color').val(color); |
|
1821 $('#est_color2').val(color); |
|
1822 scolor = ebc_to_color(color); |
|
1823 document.getElementById("bcolor").style.background= scolor; |
|
1824 document.getElementById("bcolor2").style.background= scolor; |
|
1825 |
|
1826 // Progress bars |
|
1827 pmalts = mashkg / dataRecord.eq_mash_max * 100; |
|
1828 $("#perc_malts").jqxProgressBar('val', pmalts); |
|
1829 $("#perc_sugars").jqxProgressBar('val', psugar); |
|
1830 $("#perc_cara").jqxProgressBar('val', pcara); |
|
1831 calcStage(); |
|
1832 |
|
1833 // Calculate estimated svg. |
|
1834 svg = 0; // default. |
|
1835 initcells = 0; |
|
1836 rows = $('#yeastGrid').jqxGrid('getrows'); |
|
1837 for (i = 0; i < rows.length; i++) { |
|
1838 row = rows[i]; |
|
1839 if (row.y_use == 0) { // Primary |
|
1840 if (parseFloat(row.y_attenuation) > svg) |
|
1841 svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts. |
|
1842 if (row.y_form == 0) |
|
1843 initcells += (parseFloat(row.y_cells) / 1000000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100); |
|
1844 else |
|
1845 initcells += (parseFloat(row.y_cells) / 1000000) * parseFloat(row.y_amount); |
|
1846 } |
|
1847 // TODO: brett in secondary ?? |
|
1848 if ((((dataRecord.inventory_reduced <= 3) && (row.y_use == 0)) || // Primary |
|
1849 ((dataRecord.inventory_reduced <= 4) && (row.y_use == 1)) || // Secondary |
|
1850 ((dataRecord.inventory_reduced <= 5) && (row.y_use == 2)) || // Tertiary |
|
1851 ((dataRecord.inventory_reduced <= 6) && (row.y_use == 3))) && // Bottle |
|
1852 (row.y_inventory < row.y_amount)) { |
|
1853 ok_yeasts = 0; |
|
1854 } |
|
1855 } |
|
1856 calcSupplies(); |
|
1857 if (svg == 0) |
|
1858 svg = 77; |
|
1859 |
|
1860 if ((mashkg > 0) && (mash_infuse > 0) && (mashtime > 0) && (mashtemp > 0)) { |
|
1861 dataRecord.est_fg = estimate_fg(psugar, pcara, mash_infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og); |
|
1862 } else { |
|
1863 dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og); |
|
1864 } |
|
1865 $('#est_fg').val(dataRecord.est_fg); |
|
1866 $('#est_fg2').val(dataRecord.est_fg); |
|
1867 $('#est_fg3').val(dataRecord.est_fg); |
|
1868 fig = dataRecord.est_fg; |
|
1869 |
|
1870 dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg); |
|
1871 $("#est_abv").val(dataRecord.est_abv); |
|
1872 $("#est_abv2").val(dataRecord.est_abv); |
|
1873 |
|
1874 // Calculate the final svg if available use the real value. |
|
1875 if ((dataRecord.stage >= 6) && (dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { |
|
1876 svg = 100 * (dataRecord.brew_fermenter_sg - dataRecord.fg) / (dataRecord.brew_fermenter_sg - 1); |
|
1877 org = dataRecord.brew_fermenter_sg; |
|
1878 fig = dataRecord.fg; |
|
1879 } |
|
1880 |
|
1881 $("#yeast_cells").val(initcells); |
|
1882 $("#need_cells").val(getNeededYeastCells()); |
|
1883 |
|
1884 // Calculate the calories in kcal/l (from brouwhulp) |
|
1885 alc = 1881.22 * fig * (org - fig) / (1.775 - org); |
|
1886 sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004); |
|
1887 $("#kcal").val(Math.round((alc + sug) / (12 * 0.0295735296))); |
|
1888 }; |
|
1889 |
|
1890 function calcMash() { |
|
1891 |
|
1892 var infused = 0, i, row; |
|
1893 |
|
1894 if (!(rows = $('#mashGrid').jqxGrid('getrows'))) |
|
1895 return; |
|
1896 if (mashkg == 0) |
|
1897 return; |
|
1898 |
|
1899 for (i = 0; i < rows.length; i++) { |
|
1900 row = $("#mashGrid").jqxGrid('getrowdata', i); |
|
1901 if (row.step_type == 0) // Infusion |
|
1902 infused += row.step_infuse_amount; |
|
1903 $("#mashGrid").jqxGrid('setcellvalue', i, "step_thickness", infused / mashkg); |
|
1904 } |
|
1905 } |
|
1906 |
|
1907 /* |
|
1908 * Change OG of recipe but keep the water volumes. |
|
1909 */ |
|
1910 function calcFermentablesFromOG(OG) { |
|
1911 |
|
1912 console.log("calcFermentablesFromOG("+OG+")"); |
|
1913 var amount, row, d, i, sug, tot = 0, totmass = 0, rowscount, efficiency = parseFloat($("#efficiency").jqxNumberInput('decimal')); |
|
1914 sug = sg_to_plato(OG) * parseFloat($("#batch_size").jqxNumberInput('decimal')) * OG / 100; //total amount of sugars in kg |
|
1915 rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount; |
|
1916 |
|
1917 for (i = 0; i < rowscount; i++) { |
|
1918 row = $("#fermentableGrid").jqxGrid('getrowdata', i); |
|
1919 if (row.f_added < 4) { |
|
1920 d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
1921 if (row.f_added == 0) // Mash |
|
1922 d = efficiency / 100 * d; |
|
1923 tot += d; |
|
1924 } |
|
1925 } |
|
1926 if (tot) |
|
1927 totmass = Round(sug / tot,3); |
|
1928 |
|
1929 if (totmass) { |
|
1930 for (i = 0; i < rowscount; i++) { |
|
1931 row = $("#fermentableGrid").jqxGrid('getrowdata', i); |
|
1932 if (row.f_added < 4) { |
|
1933 amount = Math.round(row.f_percentage * 10 * totmass) / 1000; |
|
1934 $("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount); |
|
1935 } |
|
1936 } |
|
1937 } |
|
1938 }; |
|
1939 |
|
1940 function getNeededYeastCells() { |
|
1941 |
|
1942 var plato, volume, sg = dataRecord.brew_fermenter_sg; |
|
1943 if (sg <= 1.0001 && dataRecord.fg > 1.000) |
|
1944 sg = dataRecord.fg; |
|
1945 else if (sg <= 1.0001) |
|
1946 sg = dataRecord.est_og; |
|
1947 plato = sg_to_plato(sg); |
|
1948 |
|
1949 volume = dataRecord.brew_fermenter_volume; |
|
1950 if (volume <= 0) |
|
1951 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; |
|
1952 |
|
1953 return pitchrate * volume * plato; |
|
1954 } |
|
1955 |
|
1956 function hopFlavourContribution(bt, vol, use, amount) { |
|
1957 var result; |
|
1958 |
|
1959 if (use == 1) { // First wort |
|
1960 result = 0.15; // assume 15% flavourcontribution for fwh |
|
1961 } else if (bt > 50) { |
|
1962 result = 0.10; // assume 10% flavourcontribution as a minimum |
|
1963 } else { |
|
1964 result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) /6, 2)); |
|
1965 if (result < 0.10) |
|
1966 result = 0.10; // assume 10% flavourcontribution as a minimum |
|
1967 } |
|
1968 return (result * amount * 1000) / vol; |
|
1969 } |
|
1970 |
|
1971 function hopAromaContribution(bt, vol, use, amount) { |
|
1972 var result = 0; |
|
1973 |
|
1974 if (use == 5) { // Dry hop |
|
1975 result = 1.33; |
|
1976 } else if (bt > 20) { |
|
1977 result = 0; |
|
1978 } else if (bt > 7.5) { |
|
1979 result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) /4, 2)); |
|
1980 } else if (use == 2) { // Boil |
|
1981 result = 1; |
|
1982 } else if (use == 3) { // Aroma |
|
1983 result = 1.2; |
|
1984 } else if (use == 4) { // Whirlpool |
|
1985 result = 1.2; |
|
1986 } |
|
1987 return (result * amount * 1000) / vol; |
|
1988 } |
|
1989 |
|
1990 function calcIBUs() { |
|
1991 var total_ibus = 0, ferm_ibus = 0, rows = {}, i, row; |
|
1992 hop_aroma = hop_flavour = 0; |
|
1993 if (!(rows = $('#hopGrid').jqxGrid('getrows'))) { |
|
1994 return; |
|
1995 } |
|
1996 ok_hops = 1; |
|
1997 for (i = 0; i < rows.length; i++) { |
|
1998 row = rows[i]; |
|
1999 total_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, parseFloat(dataRecord.batch_size), |
|
2000 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method); |
|
2001 ferm_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, |
|
2002 parseFloat(dataRecord.brew_fermenter_volume) + parseFloat(dataRecord.brew_fermenter_tcloss), |
|
2003 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method); |
|
2004 hop_flavour += hopFlavourContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), |
|
2005 row.h_useat, parseFloat(row.h_amount)); |
|
2006 hop_aroma += hopAromaContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), |
|
2007 row.h_useat, parseFloat(row.h_amount)); |
|
2008 if ((((dataRecord.inventory_reduced <= 2) && (row.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool |
|
2009 ((dataRecord.inventory_reduced <= 6) && (row.h_useat == 5))) && // Dry-hop |
|
2010 (row.h_inventory < row.h_amount)) |
|
2011 ok_hops = 0; |
|
2012 } |
|
2013 total_ibus = Math.round(total_ibus * 10) / 10; |
|
2014 ferm_ibus = Math.round(ferm_ibus * 10) / 10; |
|
2015 hop_flavour = Math.round(hop_flavour * 1000 / 5) / 10; |
|
2016 hop_aroma = Math.round(hop_aroma * 1000 / 6) / 10; |
|
2017 if (hop_flavour > 100) |
|
2018 hop_flavour = 100; |
|
2019 if (hop_aroma > 100) |
|
2020 hop_aroma = 100; |
|
2021 console.log("calcIBUs(): " + total_ibus + " flavour: " + hop_flavour + " aroma: " + hop_aroma+" fermenter:"+ferm_ibus+" supplies:"+ok_hops); |
|
2022 dataRecord.est_ibu = total_ibus; |
|
2023 $('#est_ibu').val(total_ibus); |
|
2024 $('#est_ibu2').val(total_ibus); |
|
2025 $("#hop_flavour").jqxProgressBar('val', hop_flavour); |
|
2026 $("#hop_aroma").jqxProgressBar('val', hop_aroma); |
|
2027 $("#brew_fermenter_ibu").val(ferm_ibus); |
|
2028 calcStage(); |
|
2029 calcSupplies(); |
|
2030 }; |
|
2031 |
|
2032 /* |
|
2033 * http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ |
|
2034 * |
|
2035 * stype: 0=stirred, 1=shaken, 2=simple |
|
2036 * totcells: initial cells |
|
2037 * egrams: gram extract |
|
2038 */ |
|
2039 function getGrowthRate(stype, totcells, egrams){ |
|
2040 |
|
2041 /* Cells per grams extract (B/g) */ |
|
2042 var cpe = totcells / egrams; |
|
2043 |
|
2044 if (cpe > 3.5) |
|
2045 return 0; // no growth |
|
2046 if (stype == 2) |
|
2047 return 0.4; // simple starter |
|
2048 if (stype == 1) |
|
2049 return 0.62; // shaken starter |
|
2050 if (cpe <= 1.4) // stirred starter |
|
2051 return 1.4; |
|
2052 return 2.33 - (.67 * cpe ); |
|
2053 }; |
|
2054 |
|
2055 function calcStep(svol, stype, start) { |
|
2056 |
|
2057 var gperpoint = 2.72715, //number of grams of extract per point of starter gravity per liter |
|
2058 prate = start/svol * 1000, |
|
2059 irate = Round(prate,1), |
|
2060 egrams = (dataRecord.starter_sg - 1) * svol * gperpoint; |
|
2061 grate = getGrowthRate(stype, start, egrams), |
|
2062 ncells = Round(egrams * grate, 1), |
|
2063 totcells = parseFloat(ncells) + start; |
|
2064 |
|
2065 console.log("svol:"+svol+" start:"+start+" irate:"+irate+" egrams:"+egrams+" grate:"+grate+" ncells:"+ncells); |
|
2066 return { |
|
2067 svol: svol, |
|
2068 irate: irate, |
|
2069 prate: Round(prate,1), |
|
2070 ncells: ncells, |
|
2071 totcells: totcells, |
|
2072 growf: Round(ncells/start, 2) |
|
2073 }; |
|
2074 } |
|
2075 |
|
2076 /* |
|
2077 * Calculate all starter steps. |
|
2078 * stype: final starter type: 0 = stirred, 1 = shaked, 2 = simple. |
|
2079 * start: initial cells in billions |
|
2080 * needed: needed cells in billions |
|
2081 * |
|
2082 * result: all values updated. |
|
2083 */ |
|
2084 function calcSteps(stype, start, needed) { |
|
2085 |
|
2086 var uvols = [ 20, 40, 60, 80, 100, 150, 200, 250, 375, 500, 625, 750, 875, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000 ], |
|
2087 mvols = uvols.length, svol = 0, lasti = 0, result = {}, i; |
|
2088 |
|
2089 /* |
|
2090 * If no values are set, auto calculate the starter. |
|
2091 */ |
|
2092 if ((parseFloat($("#prop1_volume").jqxNumberInput('decimal')) + parseFloat($("#prop2_volume").jqxNumberInput('decimal')) + |
|
2093 parseFloat($("#prop3_volume").jqxNumberInput('decimal')) + parseFloat($("#prop4_volume").jqxNumberInput('decimal'))) == 0) { |
|
2094 // clear by default |
|
2095 for (i = 1; i < 5; i++) { |
|
2096 $("#prop"+i+"_type").hide(); |
|
2097 $("#r"+i+"_pmpt").show(); |
|
2098 $("#prop"+i+"_type").val(stype); |
|
2099 $("#prop"+i+"_volume").hide(); |
|
2100 $("#prop"+i+"_volume").val(0); |
|
2101 $("#prop"+i+"_irate").hide(); |
|
2102 $("#prop"+i+"_ncells").hide(); |
|
2103 $("#prop"+i+"_tcells").hide(); |
|
2104 $("#prop"+i+"_growf").hide(); |
|
2105 } |
|
2106 if (start > needed) { |
|
2107 return; // no starter needed |
|
2108 } |
|
2109 $("#prop1_type").show(); |
|
2110 $("#r1_pmpt").hide(); |
|
2111 $("#prop1_volume").show(); |
|
2112 $("#prop1_irate").show(); |
|
2113 $("#prop1_ncells").show(); |
|
2114 $("#prop1_tcells").show(); |
|
2115 $("#prop1_growf").show(); |
|
2116 for (i = lasti; i <= mvols; i++) { |
|
2117 lasti = i; |
|
2118 svol = uvols[lasti]; |
|
2119 result = calcStep(svol, stype, start); |
|
2120 if (result.irate < 25) { |
|
2121 // inocculation rate too low, backup one step and break out. |
|
2122 lasti = i - 1; |
|
2123 svol = uvols[lasti]; |
|
2124 result = calcStep(svol, stype, start); |
|
2125 break; |
|
2126 } |
|
2127 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
2128 break; |
|
2129 } |
|
2130 } |
|
2131 $("#prop1_volume").val(result.svol / 1000); // to liters |
|
2132 $("#prop1_irate").val(result.prate); |
|
2133 $("#prop1_ncells").val(result.ncells); |
|
2134 $("#prop1_tcells").val(result.totcells); |
|
2135 $("#prop1_growf").val(result.growf); |
|
2136 if (result.totcells > needed) |
|
2137 return; // hit the target |
|
2138 |
|
2139 // second stage |
|
2140 $("#r2_pmpt").hide(); |
|
2141 $("#prop2_type").val(stype); |
|
2142 $("#prop2_type").show(); |
|
2143 $("#prop2_volume").show(); |
|
2144 $("#prop2_irate").show(); |
|
2145 $("#prop2_ncells").show(); |
|
2146 $("#prop2_tcells").show(); |
|
2147 $("#prop2_growf").show(); |
|
2148 for (i = lasti; i <= mvols; i++) { |
|
2149 lasti = i; |
|
2150 svol = uvols[lasti]; |
|
2151 result = calcStep(svol, stype, $("#prop1_tcells").val()); |
|
2152 if (result.irate < 25) { |
|
2153 lasti = i - 1; |
|
2154 svol = uvols[lasti]; |
|
2155 result = calcStep(svol, stype, $("#prop1_tcells").val()); |
|
2156 break; |
|
2157 } |
|
2158 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
2159 break; |
|
2160 } |
|
2161 } |
|
2162 $("#prop2_volume").val(result.svol / 1000); // to liters |
|
2163 $("#prop2_irate").val(result.prate); |
|
2164 $("#prop2_ncells").val(result.ncells); |
|
2165 $("#prop2_tcells").val(result.totcells); |
|
2166 $("#prop2_growf").val(result.growf); |
|
2167 if (result.totcells > needed) |
|
2168 return; // hit the target |
|
2169 |
|
2170 // third stage |
|
2171 $("#r3_pmpt").hide(); |
|
2172 $("#prop3_type").val(stype); |
|
2173 $("#prop3_type").show(); |
|
2174 $("#prop3_volume").show(); |
|
2175 $("#prop3_irate").show(); |
|
2176 $("#prop3_ncells").show(); |
|
2177 $("#prop3_tcells").show(); |
|
2178 $("#prop3_growf").show(); |
|
2179 for (i = lasti; i <= mvols; i++) { |
|
2180 lasti = i; |
|
2181 svol = uvols[lasti]; |
|
2182 result = calcStep(svol, stype, $("#prop2_tcells").val()); |
|
2183 if (result.irate < 25) { |
|
2184 lasti = i - 1; |
|
2185 svol = uvols[lasti]; |
|
2186 result = calcStep(svol, stype, $("#prop2_tcells").val()); |
|
2187 break; |
|
2188 } |
|
2189 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
2190 break; |
|
2191 } |
|
2192 } |
|
2193 $("#prop3_volume").val(result.svol / 1000); // to liters |
|
2194 $("#prop3_irate").val(result.prate); |
|
2195 $("#prop3_ncells").val(result.ncells); |
|
2196 $("#prop3_tcells").val(result.totcells); |
|
2197 $("#prop3_growf").val(result.growf); |
|
2198 if (result.totcells > needed) |
|
2199 return; // hit the target |
|
2200 |
|
2201 // fourth stage |
|
2202 $("#r4_pmpt").hide(); |
|
2203 $("#prop4_type").val(stype); |
|
2204 $("#prop4_type").show(); |
|
2205 $("#prop4_volume").show(); |
|
2206 $("#prop4_irate").show(); |
|
2207 $("#prop4_ncells").show(); |
|
2208 $("#prop4_tcells").show(); |
|
2209 $("#prop4_growf").show(); |
|
2210 for (i = lasti; i <= mvols; i++) { |
|
2211 lasti = i; |
|
2212 svol = uvols[lasti]; |
|
2213 result = calcStep(svol, stype, $("#prop3_tcells").val()); |
|
2214 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
2215 $("#prop4_volume").val(result.svol / 1000); // to liters |
|
2216 $("#prop4_irate").val(result.prate); |
|
2217 $("#prop4_ncells").val(result.ncells); |
|
2218 $("#prop4_tcells").val(result.totcells); |
|
2219 $("#prop4_growf").val(result.growf); |
|
2220 return; |
|
2221 } |
|
2222 } |
|
2223 } else { |
|
2224 // recalculate |
|
2225 if (dataRecord.prop1_volume > 0) { |
|
2226 $("#r1_pmpt").hide(); |
|
2227 $("#prop1_type").show(); |
|
2228 $("#prop1_volume").show(); |
|
2229 $("#prop1_irate").show(); |
|
2230 $("#prop1_ncells").show(); |
|
2231 $("#prop1_tcells").show(); |
|
2232 $("#prop1_growf").show(); |
|
2233 result = calcStep($("#prop1_volume").val() * 1000, dataRecord.prop1_type, start); |
|
2234 $("#prop1_irate").val(result.prate); |
|
2235 $("#prop1_ncells").val(result.ncells); |
|
2236 $("#prop1_tcells").val(result.totcells); |
|
2237 $("#prop1_growf").val(result.growf); |
|
2238 } |
|
2239 if (dataRecord.prop2_volume > 0) { |
|
2240 $("#r2_pmpt").hide(); |
|
2241 $("#prop2_type").show(); |
|
2242 $("#prop2_volume").show(); |
|
2243 $("#prop2_irate").show(); |
|
2244 $("#prop2_ncells").show(); |
|
2245 $("#prop2_tcells").show(); |
|
2246 $("#prop2_growf").show(); |
|
2247 result = calcStep($("#prop2_volume").val() * 1000, dataRecord.prop2_type, $("#prop1_tcells").val()); |
|
2248 $("#prop2_irate").val(result.prate); |
|
2249 $("#prop2_ncells").val(result.ncells); |
|
2250 $("#prop2_tcells").val(result.totcells); |
|
2251 $("#prop2_growf").val(result.growf); |
|
2252 } |
|
2253 if (dataRecord.prop3_volume > 0) { |
|
2254 $("#r3_pmpt").hide(); |
|
2255 $("#prop3_type").show(); |
|
2256 $("#prop3_volume").show(); |
|
2257 $("#prop3_irate").show(); |
|
2258 $("#prop3_ncells").show(); |
|
2259 $("#prop3_tcells").show(); |
|
2260 $("#prop3_growf").show(); |
|
2261 result = calcStep($("#prop3_volume").val() * 1000, dataRecord.prop3_type, $("#prop2_tcells").val()); |
|
2262 $("#prop3_irate").val(result.prate); |
|
2263 $("#prop3_ncells").val(result.ncells); |
|
2264 $("#prop3_tcells").val(result.totcells); |
|
2265 $("#prop3_growf").val(result.growf); |
|
2266 } |
|
2267 if (dataRecord.prop4_volume > 0) { |
|
2268 $("#r4_pmpt").hide(); |
|
2269 $("#prop4_type").show(); |
|
2270 $("#prop4_volume").show(); |
|
2271 $("#prop4_irate").show(); |
|
2272 $("#prop4_ncells").show(); |
|
2273 $("#prop4_tcells").show(); |
|
2274 $("#prop4_growf").show(); |
|
2275 result = calcStep($("#prop4_volume").val() * 1000, dataRecord.prop4_type, $("#prop3_tcells").val()); |
|
2276 $("#prop4_irate").val(result.prate); |
|
2277 $("#prop4_ncells").val(result.ncells); |
|
2278 $("#prop4_tcells").val(result.totcells); |
|
2279 $("#prop4_growf").val(result.growf); |
|
2280 } |
|
2281 |
|
2282 } |
|
2283 } |
|
2284 |
|
2285 function calcYeast() { |
|
2286 |
|
2287 // Calculate needed cells. |
|
2288 var plato, volume, rows, rowscount, row, i, needed, use_cells, |
|
2289 sg = dataRecord.brew_fermenter_sg; |
|
2290 if (sg <= 1.0001 && dataRecord.fg > 1.000) |
|
2291 sg = dataRecord.fg; |
|
2292 else if (sg <= 1.0001) |
|
2293 sg = dataRecord.est_og; |
|
2294 plato = sg_to_plato(sg); |
|
2295 |
|
2296 volume = dataRecord.brew_fermenter_volume; |
|
2297 if (volume > 0) { |
|
2298 if (dataRecord.brew_fermenter_extrawater > 0) |
|
2299 volume += dataRecord.brew_fermenter_extrawater; |
|
2300 } else { |
|
2301 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; |
|
2302 } |
|
2303 |
|
2304 // Also in calcFermentables() |
|
2305 $("#yeast_cells").val(initcells); |
|
2306 |
|
2307 if (!(rows = $('#yeastGrid').jqxGrid('getrows'))) { |
|
2308 return; // grid not yet loaded. |
|
2309 } |
|
2310 rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount; |
|
2311 if (rowscount == 0) |
|
2312 return; // no yeast in recipe |
|
2313 |
|
2314 for (i = 0; i < rowscount; i++) { |
|
2315 row = $("#yeastGrid").jqxGrid('getrowdata', i); |
|
2316 if (row.y_use == 0) { // primary |
|
2317 // pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/ |
|
2318 // and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ |
|
2319 pitchrate = 0.75; |
|
2320 if (dataRecord.est_og > 1.060) |
|
2321 pitchrate = 1.0; |
|
2322 // if (dataRecord.est_og > 1.076) |
|
2323 // pitchrate = 1.25; // Wyeast labs. http://www.wyeastlab.com/hb_pitchrates.cfm |
|
2324 if (row.y_type == 0) // lager yeast |
|
2325 pitchrate *= 2; |
|
2326 |
|
2327 if (row.y_form == 1) { // dry yeast |
|
2328 } else { // possible starter needed |
|
2329 } |
|
2330 } |
|
2331 } |
|
2332 needed = pitchrate * volume * plato; |
|
2333 console.log("calcYeast() pitchrate:"+pitchrate+" start:"+initcells+" needed:"+needed+" volume:"+volume); |
|
2334 $("#need_cells").val(needed); |
|
2335 use_cells = initcells; |
|
2336 |
|
2337 if (dataRecord.starter_enable) { |
|
2338 calcSteps(dataRecord.starter_type, initcells, needed); |
|
2339 |
|
2340 for (i = 1; i < 5; i++) { |
|
2341 $("#r"+i+"_irate").html(""); |
|
2342 $("#r"+i+"_growf").html(""); |
|
2343 $("#r"+i+"_tcells").html(""); |
|
2344 if (parseFloat($("#prop"+i+"_volume").val()) > 0) { |
|
2345 if ((parseFloat($("#prop"+i+"_irate").val()) < 25) || (parseFloat($("#prop"+i+"_irate").val()) > 100)) { |
|
2346 $("#r"+i+"_irate").html("<img src='images/dialog-error.png'>"); |
|
2347 } else { |
|
2348 $("#r"+i+"_irate").html("<img src='images/dialog-ok-apply.png'>"); |
|
2349 } |
|
2350 if (parseFloat($("#prop"+i+"_growf").val()) < 1) |
|
2351 $("#r"+i+"_growf").html("<img src='images/dialog-error.png'>"); |
|
2352 if (($("#prop"+i+"_type").val() > 0) && (parseFloat($("#prop"+i+"_growf").val()) > 3)) |
|
2353 $("#r"+i+"_growf").html("<img src='images/dialog-error.png'>"); |
|
2354 if (parseFloat($("#prop"+i+"_tcells").val()) > needed) |
|
2355 $("#r"+i+"_tcells").html("<img src='images/dialog-ok-apply.png'>"); |
|
2356 use_cells = parseFloat($("#prop"+i+"_tcells").val()); |
|
2357 } else { |
|
2358 $("#r"+i+"_irate").html(""); |
|
2359 } |
|
2360 } |
|
2361 } |
|
2362 $("#plato_cells").val(parseFloat(use_cells / (volume * plato) )); |
|
2363 }; |
|
2364 |
|
2365 function adjustHops(factor) { |
|
2366 |
|
2367 console.log("adjustHops("+factor+")"); |
|
2368 var row, i, amount, rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount; |
|
2369 if (rowscount == 0) |
|
2370 return; |
|
2371 for (i = 0; i < rowscount; i++) { |
|
2372 row = $("#hopGrid").jqxGrid('getrowdata', i); |
|
2373 amount = row.h_amount * factor; |
|
2374 $("#hopGrid").jqxGrid('setcellvalue', i, "h_amount", amount); |
|
2375 } |
|
2376 }; |
|
2377 |
|
2378 function calcMiscs() { |
|
2379 |
|
2380 ok_miscs = 1; |
|
2381 var row, i, rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount; |
|
2382 if (rowscount == 0) |
|
2383 return; |
|
2384 for (i = 0; i < rowscount; i++) { |
|
2385 row = $("#miscGrid").jqxGrid('getrowdata', i); |
|
2386 if ((((dataRecord.inventory_reduced <= 2) && (row.m_use_use <= 2)) || // Starter, Mash, Boil |
|
2387 ((dataRecord.inventory_reduced <= 3) && (row.m_use_use == 3)) || // Primary |
|
2388 ((dataRecord.inventory_reduced <= 5) && (row.m_use_use == 4)) || // Secondary, Teriary |
|
2389 ((dataRecord.inventory_reduced <= 6) && (row.m_use_use == 5))) && // Bottle |
|
2390 (row.m_inventory < row.m_amount)) { |
|
2391 ok_miscs = 0; |
|
2392 } |
|
2393 } |
|
2394 calcSupplies(); |
|
2395 }; |
|
2396 |
|
2397 function adjustMiscs(factor) { |
|
2398 |
|
2399 console.log("adjustMiscs("+factor+")"); |
|
2400 var row, i, amount, rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount; |
|
2401 if (rowscount == 0) |
|
2402 return; |
|
2403 for (i = 0; i < rowscount; i++) { |
|
2404 row = $("#miscGrid").jqxGrid('getrowdata', i); |
|
2405 amount = row.m_amount * factor; |
|
2406 $("#miscGrid").jqxGrid('setcellvalue', i, "m_amount", amount); |
|
2407 switch (row.m_name) { |
|
2408 case 'CaCl2': $("#wa_cacl2").val(row.m_amount * 1000); |
|
2409 break; |
|
2410 case 'CaSO4': $("#wa_caso4").val(row.m_amount * 1000); |
|
2411 break; |
|
2412 case 'MgSO4': $("#wa_mgso4").val(row.m_amount * 1000); |
|
2413 break; |
|
2414 case 'NaCl': $("#wa_nacl").val(row.m_amount * 1000); |
|
2415 break; |
|
2416 case 'Melkzuur': |
|
2417 case 'Zoutzuur': |
|
2418 case 'Fosforzuur': |
|
2419 case 'Zwavelzuur': $("#wa_acid").val(row.m_amount * 1000); |
|
2420 break; |
|
2421 case 'NaHCO3': |
|
2422 case 'Na2CO3': |
|
2423 case 'CaCO3': |
|
2424 case 'Ca(OH)2': $("#wa_base").val(row.m_amount * 1000); |
|
2425 break; |
|
2426 } |
|
2427 } |
|
2428 }; |
|
2429 |
|
2430 function adjustYeasts(factor) { |
|
2431 |
|
2432 console.log("adjustYeasts("+factor+")"); |
|
2433 var row, i, amount, rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount; |
|
2434 if (rowscount == 0) |
|
2435 return; |
|
2436 for (i = 0; i < rowscount; i++) { |
|
2437 row = $("#yeastGrid").jqxGrid('getrowdata', i); |
|
2438 if (row.y_form == 1) { // Only adjust dry yeast |
|
2439 amount = row.y_amount * factor; |
|
2440 $("#yeastGrid").jqxGrid('setcellvalue', i, "y_amount", amount); |
|
2441 } |
|
2442 } |
|
2443 calcYeast(); |
|
2444 }; |
|
2445 |
|
2446 function adjustWaters(factor) { |
|
2447 |
|
2448 console.log("adjustWaters("+factor+")"); |
|
2449 var amount, row, i, rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount; |
|
2450 if (rowscount == 0) |
|
2451 return; |
|
2452 mash_infuse = 0; |
|
2453 for (i = 0; i < rowscount; i++) { |
|
2454 row = $("#mashGrid").jqxGrid('getrowdata', i); |
|
2455 if (row.step_type == 0) { // Infusion |
|
2456 amount = Round(row.step_infuse_amount * factor, 1); |
|
2457 $("#mashGrid").jqxGrid('setcellvalue', i, "step_infuse_amount", amount); |
|
2458 mash_infuse += amount; |
|
2459 } |
|
2460 } |
|
2461 if (dataRecord.w2_amount == 0) { |
|
2462 dataRecord.w1_amount = mash_infuse; |
|
2463 $("#w1_amount").val(mash_infuse); |
|
2464 } else { |
|
2465 dataRecord.w1_amount = (dataRecord.w1_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse; |
|
2466 dataRecord.w2_amount = (dataRecord.w2_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse; |
|
2467 $("#w1_amount").val(dataRecord.w1_amount); |
|
2468 $("#w2_amount").val(dataRecord.w2_amount); |
|
2469 } |
|
2470 $('#wg_amount').val(mash_infuse); |
|
2471 }; |
|
2472 |
|
2473 function calcMashEfficiency() { |
|
2474 var c, m; |
|
2475 if (parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')) < 1.002) |
|
2476 return; |
|
2477 c = sg_to_plato(est_mash_sg); |
|
2478 m = sg_to_plato(parseFloat($("#brew_mash_sg").jqxNumberInput('decimal'))); |
|
2479 if (c > 0.5) |
|
2480 $("#brew_mash_efficiency").val(100 * m / c); |
|
2481 else |
|
2482 $("#brew_mash_efficiency").val(0); |
|
2483 }; |
|
2484 |
|
2485 function calcEfficiencyBeforeBoil() { |
|
2486 var m = 0, rows = {}, i, row, tot, result = 0; |
|
2487 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { |
|
2488 return; // grid not yet loaded. |
|
2489 } |
|
2490 for (i = 0; i < rows.length; i++) { |
|
2491 row = rows[i]; |
|
2492 if (row.f_added == 0) { // Mash |
|
2493 m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
2494 } |
|
2495 } |
|
2496 tot = sg_to_plato(dataRecord.brew_preboil_sg) * (dataRecord.brew_preboil_volume / 1.04) * dataRecord.brew_preboil_sg * 10 / 1000; |
|
2497 if (m > 0) |
|
2498 result = Round((tot / m * 100), 1); |
|
2499 if (result < 0) |
|
2500 result = 0; |
|
2501 $("#brew_preboil_efficiency").val(result); |
|
2502 } |
|
2503 |
|
2504 function calcEfficiencyAfterBoil() { |
|
2505 var m = 0, // Sugars added at mash |
|
2506 b = 0, // Sugars added at boil |
|
2507 rows = {}, i, row, tot, result = 0; |
|
2508 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { |
|
2509 return; // grid not yet loaded. |
|
2510 } |
|
2511 for (i = 0; i < rows.length; i++) { |
|
2512 row = rows[i]; |
|
2513 if (row.f_added == 0) { // Mash |
|
2514 m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
2515 } else if (row.f_added == 1) { // Boil |
|
2516 b += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
2517 } |
|
2518 } |
|
2519 tot = sg_to_plato(dataRecord.brew_aboil_sg) * (dataRecord.brew_aboil_volume / 1.04) * dataRecord.brew_aboil_sg * 10 / 1000; |
|
2520 tot -= b; // total sugars in wort minus added sugars. |
|
2521 if (m > 0) |
|
2522 result = Round((tot / m * 100), 1); |
|
2523 if (result < 0) |
|
2524 result = 0; |
|
2525 dataRecord.brew_aboil_efficiency = result; |
|
2526 $("#brew_aboil_efficiency").val(result); |
|
2527 |
|
2528 } |
|
2529 |
|
2530 function GetBUGU() { |
|
2531 var gu = (dataRecord.est_og - 1) * 1000; |
|
2532 if (gu > 0) |
|
2533 return dataRecord.est_ibu / gu; |
|
2534 else |
|
2535 return 0.5; |
|
2536 } |
|
2537 |
|
2538 function GetOptClSO4ratio() { |
|
2539 var BUGU = GetBUGU(); |
|
2540 return (-1.2 * BUGU + 1.4); |
|
2541 } |
|
2542 |
|
2543 function setWaterAgent(name, amount) { |
|
2544 var row, i, id, found = false, miscs, rows = $('#miscGrid').jqxGrid('getrows'); |
|
2545 if (amount == 0) { |
|
2546 for (i = 0; i < rows.length; i++) { |
|
2547 row = rows[i]; |
|
2548 if (row.m_name == name) { |
|
2549 id = $("#miscGrid").jqxGrid('getrowid', i); |
|
2550 $("#miscGrid").jqxGrid('deleterow', id); |
|
2551 } |
|
2552 } |
|
2553 } else { |
|
2554 for (i = 0; i < rows.length; i++) { |
|
2555 row = rows[i]; |
|
2556 if (row.m_name == name) { |
|
2557 found = true; |
|
2558 $("#miscGrid").jqxGrid('setcellvalue', i, 'm_amount', amount / 1000); |
|
2559 break; |
|
2560 } |
|
2561 } |
|
2562 if (! found) { |
|
2563 miscs = new $.jqx.dataAdapter(miscInvSource, { |
|
2564 loadComplete: function () { |
|
2565 var record, i, row = {}, records = miscs.records; |
|
2566 for (i = 0; i < records.length; i++) { |
|
2567 record = records[i]; |
|
2568 if (record.name == name) { |
|
2569 row["m_name"] = record.name; |
|
2570 row["m_amount"] = amount / 1000; |
|
2571 row["m_cost"] = record.cost; |
|
2572 row["m_type"] = record.type; |
|
2573 row["m_use_use"] = record.use_use; |
|
2574 row["m_time"] = 0; |
|
2575 row["m_amount_is_weight"] = record.amount_is_weight; |
|
2576 row["m_inventory"] = record.inventory; |
|
2577 row["m_avail"] = 1; |
|
2578 $("#miscGrid").jqxGrid('addrow', null, row); |
|
2579 } |
|
2580 } |
|
2581 } |
|
2582 }); |
|
2583 miscs.dataBind(); |
|
2584 return; |
|
2585 } |
|
2586 } |
|
2587 } |
|
2588 |
|
2589 function setRangeIndicator(ion, rangeCode) { |
|
2590 if ((rangeCode == "laag") || (rangeCode == "hoog")) |
|
2591 $("#wr_"+ion).html("<img src='images/dialog-error.png'><span style='vertical-align: top; font-size: 10px; font-style: italic;'>"+rangeCode + "</span>"); |
|
2592 else |
|
2593 $("#wr_"+ion).html("<img src='images/dialog-ok-apply.png'>"); |
|
2594 } |
|
2595 |
|
2596 function mix(v1, v2, c1, c2) { |
|
2597 if ((v1 + v2) > 0) { |
|
2598 return ((v1 * c1) + (v2 * c2)) / (v1 + v2); |
|
2599 } |
|
2600 return 0; |
|
2601 } |
|
2602 |
|
2603 // mg/l as CaCO3 |
|
2604 function ResidualAlkalinity(total_alkalinity, calcium, magnesium) { |
|
2605 return total_alkalinity - (calcium / 1.4 + magnesium / 1.7); |
|
2606 } |
|
2607 |
|
2608 function PartCO3(pH) { |
|
2609 var H = Math.pow(10, -pH); |
|
2610 return 100 * Ka1 * Ka2 / (H*H + H * Ka1 + Ka1 * Ka2); |
|
2611 } |
|
2612 |
|
2613 function PartHCO3(pH) { |
|
2614 var H = Math.pow(10, -pH); |
|
2615 return 100 * Ka1 * H / (H*H + H * Ka1 + Ka1 * Ka2); |
|
2616 } |
|
2617 |
|
2618 function Charge(pH) { |
|
2619 return (-2 * PartCO3(pH) - PartHCO3(pH)); |
|
2620 } |
|
2621 |
|
2622 //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) |
|
2623 function ZAlkalinity(pHZ) { |
|
2624 var C43 = Charge(4.3), |
|
2625 Cw = Charge(parseFloat($("#wg_ph").jqxNumberInput('decimal'))), |
|
2626 Cz = Charge(pHZ), |
|
2627 DeltaCNaught = -C43+Cw, |
|
2628 CT = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')) / 50 / DeltaCNaught, |
|
2629 DeltaCZ = -Cz+Cw; |
|
2630 return CT * DeltaCZ; |
|
2631 } |
|
2632 |
|
2633 //Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH) |
|
2634 function ZRA(pHZ) { |
|
2635 |
|
2636 var Magn, Z, Calc = parseFloat($("#wg_calcium").jqxNumberInput('decimal')) / (MMCa / 2); |
|
2637 Magn = parseFloat($("#wg_magnesium").jqxNumberInput('decimal')) / (MMMg / 2); |
|
2638 Z = ZAlkalinity(pHZ); |
|
2639 return Z - (Calc / 3.5 + Magn / 7); |
|
2640 } |
|
2641 |
|
2642 function ProtonDeficit(pHZ) { |
|
2643 |
|
2644 var rows, i, C1, ebc, x, Result = ZRA(pHZ) * parseFloat($("#wg_amount").jqxNumberInput('decimal')); |
|
2645 // proton deficit for the grist |
|
2646 rows = $('#fermentableGrid').jqxGrid('getrows'); |
|
2647 for (i = 0; i < rows.length; i++) { |
|
2648 row = rows[i]; |
|
2649 if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt |
|
2650 // Check if acid is required |
|
2651 C1 = 0; |
|
2652 if ((row.f_di_ph != 5.7) && ((row.f_acid_to_ph_57 < - 0.1) || (row.f_acid_to_ph_57 > 0.1))) { |
|
2653 C1 = row.f_acid_to_ph_57 / (row.f_di_ph - 5.7); |
|
2654 } else { |
|
2655 // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid. |
|
2656 ebc = row.f_color; |
|
2657 switch (row.f_graintype) { |
|
2658 case 0: // Base, Special, Kilned |
|
2659 case 3: |
|
2660 case 5: C1 = 0.014 * ebc - 34.192; |
|
2661 break; |
|
2662 case 2: C1 = -0.0597 * ebc - 32.457; // Crystal |
|
2663 break; |
|
2664 case 1: C1 = 0.0107 * ebc - 54.768; // Roast |
|
2665 break; |
|
2666 case 4: C1 = -149; // Sour malt |
|
2667 break; |
|
2668 } |
|
2669 } |
|
2670 x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH) |
|
2671 Result += x * row.f_amount; |
|
2672 } |
|
2673 } |
|
2674 return Result; |
|
2675 } |
|
2676 |
|
2677 function MashpH() { |
|
2678 var n = 0, pH = 5.4, deltapH = 0.001, deltapd = 0.1, pd = ProtonDeficit(pH); |
|
2679 while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) { |
|
2680 n++; |
|
2681 if (pd < -deltapd) |
|
2682 pH -= deltapH; |
|
2683 else if (pd > deltapd) |
|
2684 pH += deltapH; |
|
2685 pd = ProtonDeficit(pH); |
|
2686 } |
|
2687 console.log("MashpH() n: "+n+" pH: "+pH); |
|
2688 return pH; |
|
2689 } |
|
2690 |
|
2691 function GetAcidSpecs(AT) { |
|
2692 switch(AT) { |
|
2693 case 0: return { // Melkzuur |
|
2694 pK1: 3.86, |
|
2695 pK2: 20, |
|
2696 pK3: 20, |
|
2697 MolWt: 90.08, |
|
2698 AcidSG: 1214, // 1214 1209 |
|
2699 AcidPrc: 0.88 // 0.88 0.80 |
|
2700 }; |
|
2701 case 1: return { // Zoutzuur |
|
2702 pK1: -7, |
|
2703 pK2: 20, |
|
2704 pK3: 20, |
|
2705 MolWt: 36.46, |
|
2706 AcidSG: 1142, |
|
2707 AcidPrc: 0.28 |
|
2708 }; |
|
2709 case 2: return { // Fosforzuur |
|
2710 pK1: 2.12, |
|
2711 pK2: 7.20, |
|
2712 pK3: 12.44, |
|
2713 MolWt: 98.00, |
|
2714 AcidSG: 1170, |
|
2715 AcidPrc: 0.25 |
|
2716 }; |
|
2717 case 3: return { // Zwavelzuur |
|
2718 pK1: -1, |
|
2719 pK2: 1.92, |
|
2720 pK3: 20, |
|
2721 MolWt: 98.07, |
|
2722 AcidSG: 1700, |
|
2723 AcidPrc: 0.93 |
|
2724 }; |
|
2725 } |
|
2726 } |
|
2727 |
|
2728 function calcWater() { |
|
2729 |
|
2730 console.log("calcWater()"); |
|
2731 var liters = 0, |
|
2732 calcium = 0, |
|
2733 magnesium = 0, |
|
2734 sodium = 0, |
|
2735 total_alkalinity = 0, |
|
2736 bicarbonate = 0, |
|
2737 chloride = 0, |
|
2738 sulfate = 0, |
|
2739 ph = 0, |
|
2740 RA = 0, |
|
2741 frac = 0, |
|
2742 TpH = 0, |
|
2743 protonDeficit = 0, |
|
2744 AT, BT, result, pK1, pK2, pK3, MolWt, AcidSG, AcidPrc, |
|
2745 r1d, r2d, f1d, f2d, f3d, |
|
2746 deltapH, deltapd, pd, n, |
|
2747 piCLSO4_low, piCLSO4_high, Res, |
|
2748 wg_calcium, wg_sodium, wg_total_alkalinity, wg_chloride, wg_sulfate, wg_bicarbonate; |
|
2749 |
|
2750 if (dataRecord.w1_name == "") { |
|
2751 return; |
|
2752 } |
|
2753 |
|
2754 // If there is a dillute water source, mix the waters. |
|
2755 if (dataRecord.w2_name != "") { |
|
2756 liters = dataRecord.w1_amount + dataRecord.w2_amount; |
|
2757 calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium); |
|
2758 magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium); |
|
2759 sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium); |
|
2760 chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride); |
|
2761 sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate); |
|
2762 total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity); |
|
2763 ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters); |
|
2764 } else { |
|
2765 liters = dataRecord.w1_amount; |
|
2766 calcium = dataRecord.w1_calcium; |
|
2767 magnesium = dataRecord.w1_magnesium; |
|
2768 sodium = dataRecord.w1_sodium; |
|
2769 chloride = dataRecord.w1_chloride; |
|
2770 sulfate = dataRecord.w1_sulfate; |
|
2771 total_alkalinity = dataRecord.w1_total_alkalinity; |
|
2772 ph = dataRecord.w1_ph; |
|
2773 } |
|
2774 $('#wg_amount').val(liters); |
|
2775 wg_calcium = calcium; |
|
2776 $('#wg_calcium').val(Math.round(calcium * 10) / 10); |
|
2777 //var wg_magnesium = magnesium; |
|
2778 $('#wg_magnesium').val(Math.round(magnesium * 10) / 10); |
|
2779 wg_sodium = sodium; |
|
2780 $('#wg_sodium').val(Math.round(sodium * 10) / 10); |
|
2781 wg_total_alkalinity = total_alkalinity; |
|
2782 $('#wg_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10); |
|
2783 wg_chloride = chloride; |
|
2784 $('#wg_chloride').val(Math.round(chloride * 10) / 10); |
|
2785 wg_sulfate = sulfate; |
|
2786 $('#wg_sulfate').val(Math.round(sulfate * 10) / 10); |
|
2787 // Note: brouwhulp has the malts included here in the result. |
|
2788 //var wg_ph = ph; |
|
2789 $('#wg_ph').val(Round(ph,1)); |
|
2790 $('#wb_ph').val(Round(MashpH(), 1)); |
|
2791 $('#est_mash_ph').val(Round(MashpH(), 1)); |
|
2792 bicarbonate = total_alkalinity * 1.22; |
|
2793 wg_bicarbonate = bicarbonate; |
|
2794 |
|
2795 // Noot: de volgende berekeningen geven bijna gelijke resultaten in Brun'water. |
|
2796 // Calculate Ca |
|
2797 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 + |
|
2798 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4; |
|
2799 calcium += 1000 * RA / liters; |
|
2800 |
|
2801 // Calculate Mg |
|
2802 RA = parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMMg / MMMgSO4; |
|
2803 magnesium += 1000 * RA / liters; |
|
2804 |
|
2805 // Calculate Na |
|
2806 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
2807 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3; |
|
2808 sodium += 1000 * RA / liters; |
|
2809 |
|
2810 // Calculate SO4 |
|
2811 RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + |
|
2812 parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4; |
|
2813 sulfate += 1000 * RA / liters; |
|
2814 |
|
2815 // Calculate Cl |
|
2816 RA = 2 * parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 + |
|
2817 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl; |
|
2818 chloride += 1000 * RA / liters; |
|
2819 // Einde noot. |
|
2820 |
|
2821 if ($("#wa_acid_name").val() < 0 || $("#wa_acid_name").val() > 3) { |
|
2822 $("#wa_acid_name").val(0); |
|
2823 dataRecord.wa_acid_name = 0; |
|
2824 } |
|
2825 if (last_acid == '') |
|
2826 last_acid = AcidTypeData[$("#wa_acid_name").val()].nl; |
|
2827 |
|
2828 if ($("#wa_base_name").val() < 0 || $("#wa_base_name").val() > 3) { |
|
2829 $("#wa_base_name").val(0); |
|
2830 dataRecord.wa_base_name = 0; |
|
2831 } |
|
2832 if (last_base == '') |
|
2833 last_base = BaseTypeData[$("#wa_base_name").val()].nl; |
|
2834 |
|
2835 AT = dataRecord.wa_acid_name; |
|
2836 BT = dataRecord.wa_base_name; |
|
2837 |
|
2838 result = GetAcidSpecs(AT); |
|
2839 pK1 = result.pK1; |
|
2840 pK2 = result.pK2; |
|
2841 pK3 = result.pK3; |
|
2842 MolWt = result.MolWt; |
|
2843 AcidSG = result.AcidSG; |
|
2844 AcidPrc = result.AcidPrc; |
|
2845 |
|
2846 if (dataRecord.calc_acid) { |
|
2847 TpH = parseFloat(dataRecord.mash_ph); |
|
2848 protonDeficit = ProtonDeficit(TpH); |
|
2849 console.log("calc_acid tgt: "+TpH+" protonDeficit: "+protonDeficit); |
|
2850 if (protonDeficit > 0) { // Add acid |
|
2851 $("#wa_base").val(0); |
|
2852 setWaterAgent(last_base, 0); |
|
2853 frac = CalcFrac(TpH, pK1, pK2, pK3); |
|
2854 Acid = protonDeficit / frac; |
|
2855 Acid *= MolWt; // mg |
|
2856 Acidmg = Acid; |
|
2857 Acid = Acid / AcidSG; // ml |
|
2858 |
|
2859 if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0) |
|
2860 $("#wa_acid_perc").val(AcidPrc); |
|
2861 Acid = Acid * AcidPrc / (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml |
|
2862 console.log("Final ml: "+Acid); |
|
2863 $("#wa_acid").val(Round(Acid, 2)); |
|
2864 setWaterAgent(AcidTypeData[AT].nl, Round(Acid, 2)); |
|
2865 |
|
2866 bicarbonate = bicarbonate - protonDeficit * frac / liters; |
|
2867 total_alkalinity = bicarbonate * 50 / 61; |
|
2868 } else if (protonDeficit < 0) { //Add base |
|
2869 $("#wa_acid").val(0); |
|
2870 setWaterAgent(last_acid, 0); |
|
2871 r1d = Math.pow(10, (TpH - 6.38)); |
|
2872 r2d = Math.pow(10, (TpH - 10.38)); |
|
2873 f1d = 1 / (1 + r1d + r1d * r2d); |
|
2874 f2d = f1d * r1d; |
|
2875 f3d = f2d * r2d; |
|
2876 switch (BT) { |
|
2877 case 0: RA = -protonDeficit / (f1d - f3d); // Sodiumbicarbonate, mmol totaal |
|
2878 RA = RA * MMNaHCO3/1000; //gram |
|
2879 $("#wa_base").val(Round(RA, 2)); |
|
2880 setWaterAgent('NaHCO3', Round(RA, 2)); |
|
2881 if (liters > 0) { |
|
2882 // Na |
|
2883 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
2884 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3; |
|
2885 RA = 1000 * RA / liters; |
|
2886 sodium = wg_sodium + RA; |
|
2887 // HCO3 |
|
2888 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3; |
|
2889 RA = 1000 * RA / liters; |
|
2890 bicarbonate = wg_bicarbonate + RA; |
|
2891 total_alkalinity = bicarbonate * 50 / 61; |
|
2892 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
2893 } |
|
2894 break; |
|
2895 case 1: RA = -protonDeficit / (2 * f1d + f2d); // Sodiumcarbonate, mmol totaal |
|
2896 RA = RA * MMNa2CO3/1000; //gram |
|
2897 $("#wa_base").val(Round(RA, 2)); |
|
2898 setWaterAgent('Na2CO3', Round(RA, 2)); |
|
2899 if (liters > 0) { |
|
2900 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
2901 parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3; |
|
2902 RA = 1000 * RA / liters; |
|
2903 sodium = wg_sodium + RA; |
|
2904 // HCO3 |
|
2905 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3; |
|
2906 RA = 1000 * RA / liters; |
|
2907 bicarbonate = wg_bicarbonate + RA; |
|
2908 total_alkalinity = bicarbonate * 50 / 61; |
|
2909 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
2910 } |
|
2911 break; |
|
2912 case 2: RA = -protonDeficit * (f1d - f3d); // Calciumcarbonate, mmol totaal |
|
2913 RA = RA * MMCaCO3/1000; //gram |
|
2914 //but only 1/3 is effective, so add 3 times as much |
|
2915 RA = 3 * RA; |
|
2916 $("#wa_base").val(Round(RA, 2)); |
|
2917 setWaterAgent('CaCO3', Round(RA, 2)); |
|
2918 if (liters > 0) { |
|
2919 //Bicarbonate |
|
2920 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3; |
|
2921 RA = 1000 * RA / liters; |
|
2922 bicarbonate = wg_bicarbonate + RA; |
|
2923 total_alkalinity = bicarbonate * 50 / 61; |
|
2924 //Ca precipitates out as Ca10(PO4)6(OH)2 |
|
2925 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 + |
|
2926 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 + |
|
2927 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3; |
|
2928 RA = 1000 * RA / liters; |
|
2929 calcium = wg_calcium + RA; |
|
2930 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
2931 } |
|
2932 break; |
|
2933 case 3: RA = -protonDeficit / 19.3; // Calciumhydroxide |
|
2934 $("#wa_base").val(Round(RA, 2)); |
|
2935 setWaterAgent('Ca(OH)2', Round(RA, 2)); |
|
2936 if (liters > 0) { |
|
2937 // Bicarbonate |
|
2938 RA = -protonDeficit / liters; |
|
2939 total_alkalinity = wg_total_alkalinity + RA; |
|
2940 bicarbonate = total_alkalinity * 61 / 50; |
|
2941 // Calcium |
|
2942 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 + |
|
2943 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 + |
|
2944 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaOH2; |
|
2945 RA = 1000 * RA / liters; |
|
2946 calcium = wg_calcium + RA; |
|
2947 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
2948 } |
|
2949 break; |
|
2950 } |
|
2951 } |
|
2952 ph = TpH; |
|
2953 $('#wb_ph').val(Round(ph, 1)); |
|
2954 $('#est_mash_ph').val(Round(ph, 1)); |
|
2955 } else { // Manual |
|
2956 console.log("calc_acid no"); |
|
2957 // First add base salts |
|
2958 if (parseFloat($("#wa_base").jqxNumberInput('decimal')) > 0) { |
|
2959 if (liters > 0) { |
|
2960 switch (BT) { |
|
2961 case 0: // Sodiumbicarbonate, Na |
|
2962 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
2963 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3; |
|
2964 RA = 1000 * RA / liters; |
|
2965 sodium = wg_sodium + RA; |
|
2966 // HCO3 |
|
2967 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3; |
|
2968 RA = 1000 * RA / liters; |
|
2969 bicarbonate = wg_bicarbonate + RA; |
|
2970 total_alkalinity = bicarbonate * 50 / 61; |
|
2971 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
2972 break; |
|
2973 case 1: // Sodiumcarbonate |
|
2974 RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl + |
|
2975 parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3; |
|
2976 RA = 1000 * RA / liters; |
|
2977 sodium = wg_sodium + RA; |
|
2978 // HCO3 |
|
2979 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3; |
|
2980 RA = 1000 * RA / liters; |
|
2981 bicarbonate = wg_bicarbonate + RA; |
|
2982 total_alkalinity = bicarbonate * 50 / 61; |
|
2983 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
2984 break; |
|
2985 case 2: // Calciumcarbonate: Bicarbonate |
|
2986 RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3; |
|
2987 RA = 1000 * RA / liters; |
|
2988 bicarbonate = wg_bicarbonate + RA; |
|
2989 total_alkalinity = bicarbonate * 50 / 61; |
|
2990 RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium); |
|
2991 // Ca |
|
2992 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 + |
|
2993 parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 + |
|
2994 parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3; |
|
2995 RA = 1000 * RA / liters; |
|
2996 calcium = wg_calcium + RA; |
|
2997 break; |
|
2998 } |
|
2999 } |
|
3000 } |
|
3001 |
|
3002 TpH = parseFloat(dataRecord.mash_ph); |
|
3003 pHa = MashpH(); // This one is in demi water, should be in adjusted water??? |
|
3004 // Then calculate the new pH with added acids |
|
3005 if (parseFloat($("#wa_acid").jqxNumberInput('decimal')) > 0) { |
|
3006 console.log("TpH: "+TpH+" water: "+pHa); |
|
3007 Acid = parseFloat($("#wa_acid").jqxNumberInput('decimal')); |
|
3008 if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0) |
|
3009 $("#wa_acid_perc").val(AcidPrc); |
|
3010 Acid = Acid / AcidPrc * (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml |
|
3011 Acid *= AcidSG; // ml |
|
3012 Acid /= MolWt; // mg |
|
3013 Acidmg = Acid; |
|
3014 |
|
3015 //find the pH where the protondeficit = protondeficit by the acid |
|
3016 frac = CalcFrac(pHa, pK1, pK2, pK3); |
|
3017 protonDeficit = Acid * frac; |
|
3018 |
|
3019 deltapH = 0.001; |
|
3020 deltapd = 0.1; |
|
3021 pd = ProtonDeficit(pHa); |
|
3022 n = 0; |
|
3023 while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 2000)) { |
|
3024 n++; |
|
3025 if (pd < (protonDeficit-deltapd)) |
|
3026 pHa -= deltapH; |
|
3027 else if (pd > (protonDeficit+deltapd)) |
|
3028 pHa += deltapH; |
|
3029 frac = CalcFrac(pHa, pK1, pK2, pK3); |
|
3030 protonDeficit = Acid * frac; |
|
3031 pd = ProtonDeficit(pHa); |
|
3032 } |
|
3033 console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa); |
|
3034 RA = wg_bicarbonate - protonDeficit * frac / liters; |
|
3035 bicarbonate = RA; |
|
3036 total_alkalinity = RA * 50 / 61; |
|
3037 ph = pHa; |
|
3038 $('#wb_ph').val(Round(ph, 1)); |
|
3039 $('#est_mash_ph').val(Round(ph, 1)); |
|
3040 } |
|
3041 } |
|
3042 |
|
3043 if ((AT == 3) && (liters > 0)) { // Sulfuctic / Zwavelzuur |
|
3044 RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + |
|
3045 parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 + |
|
3046 Acidmg / 1000 * MMSO4 / (MMSO4 + 2); |
|
3047 RA = 1000 * RA / liters; |
|
3048 sulfate = wg_sulfate + RA; // Not add to sulfate?? |
|
3049 } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur |
|
3050 RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 + |
|
3051 parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl + |
|
3052 Acidmg / 1000 * MMCl / (MMCl + 1); |
|
3053 RA = 1000 * RA / liters; |
|
3054 chloride = wg_chloride + RA; |
|
3055 } |
|
3056 |
|
3057 // 2:1 Sulfate to Chroride IPA's, Pale Ales. |
|
3058 // 1:1 Sulfate to Chloride Balanced |
|
3059 // 1:2 Sulfate to Chloride Malty |
|
3060 // Note, values below are the other way, cl to so4! |
|
3061 // So: 0.5 is IPA's, Pale Ales. |
|
3062 // 1 Balanced |
|
3063 // 2 Malty. |
|
3064 $('#tgt_bu').val(Round(GetBUGU(), 2)); |
|
3065 // From brouwhulp. |
|
3066 if (GetBUGU() < 0.32) |
|
3067 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig en zoet</span>"); |
|
3068 else if (GetBUGU() < 0.43) |
|
3069 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig, zoet</span>"); |
|
3070 else if (GetBUGU() < 0.52) |
|
3071 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Evenwichtig</span>"); |
|
3072 else if (GetBUGU() < 0.63) |
|
3073 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht hoppig, bitter</span>"); |
|
3074 else |
|
3075 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Extra hoppig, zeer bitter</span>"); |
|
3076 $('#tgt_cl_so4').val(Round(GetOptClSO4ratio(), 1)); |
|
3077 if (sulfate > 0) |
|
3078 RA = chloride / sulfate; |
|
3079 else |
|
3080 RA = 10; |
|
3081 $('#got_cl_so4').val(Round(RA, 1)); |
|
3082 piCLSO4_low = 0.8 * GetOptClSO4ratio(); |
|
3083 piCLSO4_high = 1.2 * GetOptClSO4ratio(); |
|
3084 Res = 'normaal'; |
|
3085 if (RA < piCLSO4_low) |
|
3086 Res = 'laag'; |
|
3087 else if (RA > piCLSO4_high) |
|
3088 Res = 'hoog'; |
|
3089 setRangeIndicator('cl_so4', Res); |
|
3090 |
|
3091 $('#wb_calcium').val(Round(calcium, 1)); |
|
3092 $('#wb_magnesium').val(Round(magnesium, 1)); |
|
3093 $('#wb_sodium').val(Round(sodium, 1)); |
|
3094 $('#wb_sulfate').val(Round(sulfate, 1)); |
|
3095 $('#wb_chloride').val(Round(chloride, 1)); |
|
3096 $('#wb_total_alkalinity').val(Round(total_alkalinity, 1)); |
|
3097 |
|
3098 if (calcium < 40) { |
|
3099 setRangeIndicator("calcium", "laag"); |
|
3100 } else if (calcium > 150) { |
|
3101 setRangeIndicator("calcium", "hoog"); |
|
3102 } else { |
|
3103 setRangeIndicator("calcium", "normaal"); |
|
3104 } |
|
3105 if (magnesium >= 0 && magnesium <= 30) { |
|
3106 setRangeIndicator("magnesium", "normaal"); |
|
3107 } else { |
|
3108 setRangeIndicator("magnesium", "hoog"); |
|
3109 } |
|
3110 if (sodium <= 150) { |
|
3111 setRangeIndicator("sodium", "normaal"); |
|
3112 } else { |
|
3113 setRangeIndicator("sodium", "hoog"); |
|
3114 } |
|
3115 // Both chloride and sulfate should be above 50 according to |
|
3116 // John Palmer. So the Cl/SO4 ratio calculation will work. |
|
3117 if (chloride <= 50) { |
|
3118 setRangeIndicator("chloride", "laag"); |
|
3119 } else if (chloride <= 100) { |
|
3120 setRangeIndicator("chloride", "normaal"); |
|
3121 } else { |
|
3122 setRangeIndicator("chloride", "hoog"); |
|
3123 } |
|
3124 if (sulfate <= 50) { |
|
3125 setRangeIndicator("sulfate", "laag"); |
|
3126 } else if (sulfate <= 350) { |
|
3127 setRangeIndicator("sulfate", "normaal"); |
|
3128 } else { |
|
3129 setRangeIndicator("sulfate", "hoog"); |
|
3130 } |
|
3131 if (ph < 5.2) { |
|
3132 setRangeIndicator("ph", "laag"); |
|
3133 } else if (ph > 5.6) { |
|
3134 setRangeIndicator("ph", "hoog"); |
|
3135 } else { |
|
3136 setRangeIndicator("ph", "normaal"); |
|
3137 } |
|
3138 calcSparge(); |
|
3139 calcMiscs(); |
|
3140 calcSupplies(); |
|
3141 } |
|
3142 |
|
3143 function calcSparge() { |
|
3144 |
|
3145 var TargetpH, Source_pH, Source_alkalinity, r1, r2, d, f1, f3, |
|
3146 r143, r243, d43, f143, f343, alkalinity, Ct, r1g, r2g, dg, f1g, f3g, |
|
3147 Acid, AT, result, pK1, pK2, pK3, MolWt, AcidSG, AcidPrc, fract; |
|
3148 |
|
3149 // Code from BrewBuddy/Brouwhulp, who got it from http://www.brewery.org/brewery/library/Acidi0,00fWaterAJD0497.html |
|
3150 TargetpH = dataRecord.sparge_ph; |
|
3151 Source_pH = dataRecord.w1_ph; |
|
3152 Source_alkalinity = dataRecord.w1_total_alkalinity; |
|
3153 // Select watersource or fallback to the first source. |
|
3154 if (dataRecord.sparge_source == 1) { // Source 2 |
|
3155 if (dataRecord.w2_ph > 0.0) { |
|
3156 Source_pH = dataRecord.w2_ph; |
|
3157 Source_alkalinity = dataRecord.w2_total_alkalinity; |
|
3158 } else { |
|
3159 dataRecord.sparge_source = 0; // Source 1 |
|
3160 $("#sparge_source").val(0); |
|
3161 } |
|
3162 } else if (dataRecord.sparge_source == 2) { // Mixed |
|
3163 if (dataRecord.w2_ph > 0.0) { |
|
3164 Source_pH = parseFloat($("#wg_ph").jqxNumberInput('decimal')); |
|
3165 Source_alkalinity = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')); |
|
3166 } else { |
|
3167 dataRecord.sparge_source = 0; |
|
3168 $("#sparge_source").val(0); |
|
3169 } |
|
3170 } |
|
3171 |
|
3172 // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH |
|
3173 r1 = Math.pow(10, Source_pH - 6.38); |
|
3174 r2 = Math.pow(10, Source_pH - 10.373); |
|
3175 d = 1 + r1 + r1*r2; |
|
3176 f1 = 1/d; |
|
3177 f3 = r1 * r2 / d; |
|
3178 |
|
3179 //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) |
|
3180 r143 = Math.pow(10, 4.3 - 6.38); |
|
3181 r243 = Math.pow(10, 4.3 - 10.373); |
|
3182 d43 = 1 + r143 + r143*r243; |
|
3183 f143 = 1/d43; |
|
3184 f343 = r143 * r243 / d43; |
|
3185 |
|
3186 //Step 3. Convert the water alkalinity to milliequivalents/L |
|
3187 alkalinity = Source_alkalinity / 50; |
|
3188 |
|
3189 //Step 4. Solve |
|
3190 Ct = (alkalinity - 1000 * (Math.pow(10, -4.3) - Math.pow(10, -Source_pH))) / ((f143-f1)+(f3-f343)); |
|
3191 |
|
3192 //Step 5. Compute mole fractions at desired pH |
|
3193 r1g = Math.pow(10, TargetpH - 6.38); |
|
3194 r2g = Math.pow(10, TargetpH - 10.373); |
|
3195 dg = 1 + r1g + r1g*r2g; |
|
3196 f1g = 1/dg; |
|
3197 f3g = r1g * r2g / dg; |
|
3198 |
|
3199 //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L) |
|
3200 Acid = Ct * ((f1g-f1)+(f3-f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l |
|
3201 Acid += 0.01; // Add acid that would be required for distilled water. |
|
3202 if (dataRecord.sparge_acid_type < 0 || dataRecord.sparge_acid_type > 3) { |
|
3203 dataRecord.sparge_acid_type = 0; |
|
3204 $("#sparge_acid_type").val(0); |
|
3205 } |
|
3206 |
|
3207 //Step 8. Get the acid data. |
|
3208 AT = dataRecord.sparge_acid_type; |
|
3209 result = GetAcidSpecs(AT); |
|
3210 pK1 = result.pK1; |
|
3211 pK2 = result.pK2; |
|
3212 pK3 = result.pK3; |
|
3213 MolWt = result.MolWt; |
|
3214 AcidSG = result.AcidSG; |
|
3215 AcidPrc = result.AcidPrc; |
|
3216 fract = CalcFrac(TargetpH, pK1, pK2, pK3); |
|
3217 |
|
3218 //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. |
|
3219 Acid /= fract; |
|
3220 |
|
3221 //Step 10. Multiply by molecular weight of the acid |
|
3222 Acid *= MolWt; //mg |
|
3223 |
|
3224 Acid = Acid / AcidSG; //ml ; 88% lactic solution |
|
3225 f1 = dataRecord.sparge_acid_perc; |
|
3226 if (f1 <= 0.1) |
|
3227 f1 = AcidPrc; |
|
3228 Acid = Acid * AcidPrc / (f1 / 100); |
|
3229 |
|
3230 Acid *= dataRecord.sparge_volume; //ml lactic acid total |
|
3231 Acid = Round(Acid, 2); |
|
3232 dataRecord.sparge_acid_amount = Acid / 1000; |
|
3233 $("#sparge_acid_amount").val(Acid); |
|
3234 } |
|
3235 |
|
3236 function calcFermentation(){ |
|
3237 |
|
3238 var primary_svg, secondary_svg, final_svg, ABV; |
|
3239 if (dataRecord.brew_fermenter_sg<1.020) |
|
3240 return; |
|
3241 |
|
3242 if ((dataRecord.primary_end_sg > 0.990) && (dataRecord.primary_end_sg < dataRecord.brew_fermenter_sg)) { |
|
3243 primary_svg = Round(100*(dataRecord.brew_fermenter_sg-dataRecord.primary_end_sg)/(dataRecord.brew_fermenter_sg-1),1); |
|
3244 $("#primary_svg").val(primary_svg); |
|
3245 if ((dataRecord.secondary_end_sg > 0.990) && (dataRecord.secondary_end_sg < dataRecord.brew_fermenter_sg)) { |
|
3246 secondary_svg = Round(100*(dataRecord.brew_fermenter_sg-dataRecord.secondary_end_sg)/(dataRecord.brew_fermenter_sg-1),1); |
|
3247 $("#secondary_svg").val(secondary_svg); |
|
3248 if ((dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { |
|
3249 final_svg = Round(100*(dataRecord.brew_fermenter_sg-dataRecord.fg)/(dataRecord.brew_fermenter_sg-1),1); |
|
3250 $("#final_svg").val(final_svg); |
|
3251 ABV = Round(abvol(dataRecord.brew_fermenter_sg,dataRecord.fg),2); |
|
3252 $("#final_abv").val(ABV); |
|
3253 } |
|
3254 } |
|
3255 } |
|
3256 } |
|
3257 |
|
3258 function ResCO2(CO2,T){ |
|
3259 |
|
3260 var F=T*1.8+32; |
|
3261 return 3.0378-0.050062*F+0.00026555*F*F; |
|
3262 } |
|
3263 |
|
3264 function CarbCO2toS(CO2,T,SFactor){ |
|
3265 var sugar=SFactor*(CO2-ResCO2(CO2,T))/0.286; |
|
3266 if(sugar<0) |
|
3267 sugar=0; |
|
3268 return Round(sugar,3); |
|
3269 } |
|
3270 |
|
3271 function GetPressure(CO2, T1, T2) { |
|
3272 var P, V = CO2 - ResCO2(CO2, T1); |
|
3273 if (V < 0) |
|
3274 return 0; |
|
3275 P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V + |
|
3276 0.674996600795854 * V + -0.00471757220150754 * V * V; |
|
3277 //console.log("CO2: "+CO2+" "+V+" Temp: "+T1+" "+T2+" Pressure: "+P); |
|
3278 if (P < 0) |
|
3279 P = 0; |
|
3280 P = P * 1.01325; // atm to bar |
|
3281 return Round(P,1); |
|
3282 } |
|
3283 |
|
3284 function CarbCO2ToPressure(CO2, T) { |
|
3285 return (CO2-(-0.000005594056*Math.pow(T,4)+0.000144357886*Math.pow(T,3)+0.000362999168*T*T-0.064872987645*T+1.641145175049)) / |
|
3286 (0.00000498031*Math.pow(T,4)-0.00024358267*Math.pow(T,3)+0.00385867329*T*T-0.05671206825*T+1.53801423376); |
|
3287 } |
|
3288 |
|
3289 function calcCarbonation() { |
|
3290 |
|
3291 var TSec, ABV, bvol, balc, babv, mvol, malc, tvol, talc, |
|
3292 i, row, SFactor, pvol, pabv, Pressure, kabv; |
|
3293 |
|
3294 TSec=dataRecord.secondary_temp; |
|
3295 if(TSec<1) |
|
3296 TSec=dataRecord.primary_end_temp; |
|
3297 if(TSec<1) |
|
3298 TSec=18; |
|
3299 |
|
3300 if(dataRecord.fg==0.000) |
|
3301 ABV=abvol(dataRecord.brew_fermenter_sg,parseFloat($("#est_fg").jqxNumberInput('decimal'))); |
|
3302 else |
|
3303 ABV=abvol(dataRecord.brew_fermenter_sg,dataRecord.fg); |
|
3304 |
|
3305 /* Calculate new volume and alcohol. */ |
|
3306 bvol = dataRecord.package_volume-(ABV*dataRecord.package_volume)/100; |
|
3307 balc = dataRecord.package_volume-bvol; |
|
3308 mvol = dataRecord.package_infuse_amount-(dataRecord.package_infuse_abv*dataRecord.package_infuse_amount)/100; |
|
3309 malc = dataRecord.package_infuse_amount-mvol; |
|
3310 talc = balc+malc; |
|
3311 tvol = bvol+mvol; |
|
3312 ABV = Round(talc/(tvol+talc)*100,2); |
|
3313 dataRecord.package_abv=ABV; |
|
3314 $("#package_abv").val(ABV); |
|
3315 |
|
3316 // console.log("calcCarbonation() TSec:"+TSec+" ABV:"+ABV); |
|
3317 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))){ |
|
3318 return; |
|
3319 } |
|
3320 |
|
3321 // Bottles |
|
3322 dataRecord.bottle_priming_amount=0; |
|
3323 dataRecord.bottle_priming_total=0; |
|
3324 for (i = 0; i < rows.length; i++) { |
|
3325 row = rows[i]; |
|
3326 if(row.f_added==4){ |
|
3327 SFactor=1/((row.f_yield/100)*(1-row.f_moisture/100)); |
|
3328 dataRecord.bottle_priming_amount=CarbCO2toS(dataRecord.bottle_carbonation,TSec,SFactor); |
|
3329 dataRecord.bottle_priming_total=Round(dataRecord.bottle_amount*dataRecord.bottle_priming_amount,2); |
|
3330 $("#fermentableGrid").jqxGrid('setcellvalue',i,'f_amount',dataRecord.bottle_priming_total/1000); |
|
3331 } |
|
3332 } |
|
3333 $("#bottle_priming_amount").val(Round(dataRecord.bottle_priming_amount,1)); |
|
3334 $("#bottle_priming_total").val(dataRecord.bottle_priming_total); |
|
3335 pabv=ABV+dataRecord.bottle_priming_amount*0.47/7.907; |
|
3336 pvol=dataRecord.bottle_amount-(pabv*dataRecord.bottle_amount)/100; |
|
3337 talc=dataRecord.bottle_amount-pvol; |
|
3338 tvol=pvol+dataRecord.bottle_priming_water; |
|
3339 babv = Round(talc/(tvol+talc)*100,2); |
|
3340 //console.log("bottle pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.bottle_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+babv); |
|
3341 $("#bottle_abv").val(babv); |
|
3342 $("#bottle_pressure").val(GetPressure(dataRecord.bottle_carbonation,TSec,dataRecord.bottle_carbonation_temp)); |
|
3343 |
|
3344 // Kegs |
|
3345 Pressure=CarbCO2ToPressure(dataRecord.keg_carbonation,dataRecord.keg_carbonation_temp); |
|
3346 if(Pressure<0)Pressure=0; |
|
3347 dataRecord.keg_pressure=Pressure; |
|
3348 $("#keg_pressure").val(Round(Pressure,1)); |
|
3349 |
|
3350 dataRecord.keg_priming_amount=0; |
|
3351 dataRecord.keg_priming_total=0; |
|
3352 if(!dataRecord.keg_forced_carb){ |
|
3353 for(i = 0; i < rows.length; i++){ |
|
3354 row=rows[i]; |
|
3355 if(row.f_added==5){ |
|
3356 SFactor=1/((row.f_yield/100)*(1-row.f_moisture/100)); |
|
3357 dataRecord.keg_priming_amount=CarbCO2toS(dataRecord.keg_carbonation,TSec,SFactor); |
|
3358 dataRecord.keg_priming_total=Round(dataRecord.keg_amount*dataRecord.keg_priming_amount,2); |
|
3359 $("#fermentableGrid").jqxGrid('setcellvalue',i,'f_amount',dataRecord.keg_priming_total/1000); |
|
3360 } |
|
3361 } |
|
3362 $("#keg_priming_amount").val(Round(dataRecord.keg_priming_amount,1)); |
|
3363 $("#keg_priming_total").val(dataRecord.keg_priming_total); |
|
3364 pabv=ABV+dataRecord.keg_priming_amount*0.47/7.907; |
|
3365 pvol=dataRecord.keg_amount-(pabv*dataRecord.keg_amount)/100; |
|
3366 talc=dataRecord.keg_amount-pvol; |
|
3367 tvol=pvol+dataRecord.keg_priming_water; |
|
3368 kabv=Round(talc/(tvol+talc)*100,2); |
|
3369 //console.log("kegs pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.keg_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+kabv); |
|
3370 $("#keg_abv").val(kabv); |
|
3371 } else { |
|
3372 $("#keg_priming_amount").val(0); |
|
3373 $("#keg_priming_total").val(0); |
|
3374 $("#keg_abv").val(ABV); |
|
3375 } |
|
3376 } |
|
3377 |
|
3378 function calcStage() { |
|
3379 |
|
3380 var newstage = dataRecord.stage, d, date1, date2, date1_unixtime, date2_unixtime, |
|
3381 timeDifference, timeDifferenceInDays; |
|
3382 |
|
3383 if (newstage == 0 && dataRecord.est_og > 1.005 && dataRecord.est_color > 3 && dataRecord.est_ibu > 3) |
|
3384 newstage = 1; |
|
3385 if (newstage == 1 && parseFloat($("#brew_date_start").val()) > 2000) |
|
3386 newstage = 2; // Brewday |
|
3387 if (newstage == 2 && ($("#brew_date_start").val() == '')) |
|
3388 newstage = 1; // No brewday |
|
3389 if (newstage == 2 && parseFloat($("#brew_date_end").val()) > 2000) |
|
3390 newstage = 3; // Primary |
|
3391 if (newstage == 3 && parseFloat($("#primary_end_date").val()) > 2000) |
|
3392 newstage = 4; // Secondary |
|
3393 if (newstage == 4 && parseFloat($("#secondary_end_date").val()) > 2000) |
|
3394 newstage = 5; // Tertiary |
|
3395 if (newstage == 5 && parseFloat($("#package_date").val()) > 2000) |
|
3396 newstage = 6; // Package |
|
3397 if (newstage >= 6 && newstage < 9) { |
|
3398 d = new Date(); |
|
3399 date2 = $("#package_date").val(); |
|
3400 date2 = date2.split('-'); |
|
3401 // Now we convert the array to a Date object |
|
3402 date1 = new Date(d.getFullYear(), d.getMonth(), d.getDate()); |
|
3403 date2 = new Date(date2[0], date2[1]-1, date2[2]); |
|
3404 // We use the getTime() method and get the unixtime |
|
3405 date1_unixtime = parseInt(date1.getTime() / 1000); |
|
3406 date2_unixtime = parseInt(date2.getTime() / 1000); |
|
3407 // This is the calculated difference in seconds |
|
3408 timeDifference = date1_unixtime - date2_unixtime; |
|
3409 timeDifferenceInDays = timeDifference / 60 / 60 / 24; |
|
3410 if (timeDifferenceInDays > 0) { // At least one day |
|
3411 if (timeDifferenceInDays >= 42) // 6 weeks |
|
3412 newstage = 9; // Ready to taste |
|
3413 else if (timeDifferenceInDays >= 14) // 14 days |
|
3414 newstage = 8; // Mature |
|
3415 else |
|
3416 newstage = 7; // Carbonation |
|
3417 } |
|
3418 } |
|
3419 if (newstage == 9 && parseFloat($("#taste_date").val()) > 2000) |
|
3420 newstage = 10; // Ready |
|
3421 |
|
3422 if (newstage != dataRecord.stage) { |
|
3423 console.log("calcStage() old: "+dataRecord.stage+" new: "+newstage); |
|
3424 dataRecord.stage = newstage; |
|
3425 } |
|
3426 |
|
3427 /* |
|
3428 * Set stage and enable or disable parts of the screens. |
|
3429 */ |
|
3430 $("#stage").val(StageData[dataRecord.stage].nl); |
|
3431 if (dataRecord.stage >= 10) { |
|
3432 $("#locked").jqxCheckBox({ disabled:false }); |
|
3433 } |
|
3434 |
|
3435 /* |
|
3436 * When the brew is in progress or done, block equipment select and delete. |
|
3437 */ |
|
3438 if (dataRecord.stage > 1) { |
|
3439 $("#equipmentSelect").jqxDropDownList({ disabled: true }); |
|
3440 $("#Delete").jqxButton({ disabled: true }); |
|
3441 } |
|
3442 |
|
3443 if (dataRecord.stage < 1) // Planning, no ingredients |
|
3444 $('#jqxTabs').jqxTabs('disableAt', 8); // Brewday tab |
|
3445 else |
|
3446 $('#jqxTabs').jqxTabs('enableAt', 8); |
|
3447 |
|
3448 if (dataRecord.stage < 3) { // Primary |
|
3449 $('#jqxTabs').jqxTabs('disableAt', 9); // Fermentation tab |
|
3450 } else { |
|
3451 $('#jqxTabs').jqxTabs('enableAt', 9); |
|
3452 $("#name").jqxInput({ disabled: true }); |
|
3453 $("#code").jqxInput({ disabled: true }); |
|
3454 $("#batch_size").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3455 $("#boil_size").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3456 $("#boil_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3457 $("#efficiency").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3458 $("#est_og").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3459 $("#type").jqxDropDownList({ disabled: true }); |
|
3460 $("#styleSelect").jqxDropDownList({ disabled: true }); |
|
3461 $("#color_method").jqxDropDownList({ disabled: true }); |
|
3462 $("#ibu_method").jqxDropDownList({ disabled: true }); |
|
3463 $("#mash_select").jqxDropDownList({ disabled: true }); |
|
3464 $("#w1_name").jqxDropDownList({ disabled: true }); |
|
3465 $("#w2_name").jqxDropDownList({ disabled: true }); |
|
3466 $("#w2_amount").jqxNumberInput({ readOnly: true }); |
|
3467 $("#pr_name").jqxDropDownList({ disabled: true }); |
|
3468 $("#wa_cacl2").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3469 $("#wa_caso4").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3470 $("#wa_mgso4").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3471 $("#wa_nacl").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3472 $("#mash_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3473 $("#calc_acid").jqxCheckBox({ disabled: true }); |
|
3474 $("#wa_base_name").jqxDropDownList({ disabled: true }); |
|
3475 $("#wa_base").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3476 $("#wa_acid_name").jqxDropDownList({ disabled: true }); |
|
3477 $("#wa_acid").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3478 $("#wa_acid_perc").jqxNumberInput({ spinButtons: false, readOnly: true, width: 70 }); |
|
3479 $("#sparge_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3480 $("#sparge_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3481 $("#sparge_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3482 $("#sparge_source").jqxDropDownList({ disabled: true }); |
|
3483 $("#sparge_acid_type").jqxDropDownList({ disabled: true }); |
|
3484 $("#sparge_acid_perc").jqxNumberInput({ spinButtons: false, readOnly: true, width: false }); |
|
3485 $("#starter_enable").jqxCheckBox({ disabled: true }); |
|
3486 $("#starter_type").jqxDropDownList({ disabled: true }); |
|
3487 $("#starter_try").jqxButton({ disabled: true }); |
|
3488 $("#starter_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3489 $("#starter_viability").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3490 } |
|
3491 if (dataRecord.stage > 3) { // Primary fermentation done |
|
3492 $("#brew_date_start").jqxDateTimeInput({ disabled: true }); |
|
3493 $("#brew_date_end").jqxDateTimeInput({ disabled: true }); |
|
3494 $("#brew_mash_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3495 $("#brew_preboil_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3496 $("#brew_aboil_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3497 $("#brew_mash_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3498 $("#brew_preboil_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3499 $("#brew_aboil_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3500 $("#brew_preboil_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3501 $("#brew_aboil_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3502 $("#brew_whirlpool9").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3503 $("#brew_cooling_to").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3504 $("#brew_whirlpool7").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3505 $("#brew_cooling_method").jqxDropDownList({ disabled: true }); |
|
3506 $("#brew_whirlpool6").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3507 $("#brew_cooling_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3508 $("#brew_sparge_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3509 $("#brew_whirlpool2").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3510 $("#brew_aeration_type").jqxDropDownList({ disabled: true }); |
|
3511 $("#brew_fermenter_tcloss").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3512 $("#brew_aeration_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3513 $("#brew_fermenter_extrawater").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3514 $("#brew_aeration_speed").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3515 } |
|
3516 if (dataRecord.stage == 5) // Lagering, allow packaging |
|
3517 $("#package_date").jqxDateTimeInput({ disabled: false }); |
|
3518 else |
|
3519 $("#package_date").jqxDateTimeInput({ disabled: true }); |
|
3520 if (dataRecord.stage >= 5) { // At least secondary |
|
3521 $("#primary_start_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3522 $("#primary_max_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3523 $("#primary_end_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3524 $("#primary_end_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3525 $("#primary_end_brix").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3526 $("#primary_end_date").jqxDateTimeInput({ disabled: true }); |
|
3527 } |
|
3528 if (dataRecord.stage >= 6) { // Packaged |
|
3529 $("#secondary_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3530 $("#secondary_end_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3531 $("#secondary_end_date").jqxDateTimeInput({ disabled: true }); |
|
3532 $("#tertiary_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3533 $("#fg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3534 $("#final_brix").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3535 $("#package_date").jqxDateTimeInput({ disabled: true }); |
|
3536 $("#package_volume").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3537 $("#package_infuse_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3538 $("#package_infuse_abv").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3539 $("#package_infuse_notes").jqxInput({ disabled: true }); |
|
3540 $("#package_ph").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3541 $("#bottle_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3542 $("#bottle_priming_water").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3543 $("#keg_priming_water").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3544 $("#keg_amount").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3545 $("#bottle_carbonation").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3546 $("#keg_carbonation").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3547 $("#bottle_priming_sugar").jqxDropDownList({ disabled: true }); |
|
3548 $("#keg_priming_sugar").jqxDropDownList({ disabled: true }); |
|
3549 $("#keg_forced_carb").jqxCheckBox({ disabled : true }); |
|
3550 $("#bottle_carbonation_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3551 $("#keg_carbonation_temp").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3552 } |
|
3553 if (dataRecord.stage < 8) { // Taste when at least Mature. |
|
3554 $('#jqxTabs').jqxTabs('disableAt', 11); // Tasting tab |
|
3555 } else { |
|
3556 $('#jqxTabs').jqxTabs('enableAt', 11); |
|
3557 } |
|
3558 |
|
3559 if (dataRecord.stage == 11) { // Locked |
|
3560 $("#taste_date").jqxDateTimeInput({ disabled: true }); |
|
3561 $("#taste_rate").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3562 $("#taste_color").jqxInput({ disabled: true }); |
|
3563 $("#taste_transparency").jqxInput({ disabled: true }); |
|
3564 $("#taste_head").jqxInput({ disabled: true }); |
|
3565 $("#taste_aroma").jqxInput({ disabled: true }); |
|
3566 $("#taste_taste").jqxInput({ disabled: true }); |
|
3567 $("#taste_aftertaste").jqxInput({ disabled: true }); |
|
3568 $("#taste_mouthfeel").jqxInput({ disabled: true }); |
|
3569 $("#taste_notes").jqxInput({ disabled: true }); |
|
3570 $("#notes").jqxInput({ disabled: true }); |
|
3571 } else { |
|
3572 $("#notes").jqxInput({ disabled: false }); |
|
3573 } |
|
3574 } |
|
3575 |
|
3576 function showStarter() { |
|
3577 |
|
3578 if (dataRecord.starter_enable) { |
|
3579 $("#propagator").show(); |
|
3580 $("#starter_type").jqxDropDownList( {disabled: false }); |
|
3581 $("#starter_try").jqxButton({ disabled: false }); |
|
3582 $("#starter_sg").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 }); |
|
3583 $("#starter_viability").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 }); |
|
3584 } else { |
|
3585 $("#propagator").hide(); |
|
3586 $("#starter_type").jqxDropDownList( {disabled: true }); |
|
3587 $("#starter_try").jqxButton({ disabled: true }); |
|
3588 $("#starter_sg").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3589 $("#starter_viability").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 }); |
|
3590 } |
|
3591 } |
|
3592 |
|
3593 function calcInit () { |
|
3594 console.log("calcInit()"); |
|
3595 |
|
3596 calcMashEfficiency(); |
|
3597 calcEfficiencyBeforeBoil(); |
|
3598 calcEfficiencyAfterBoil(); |
|
3599 |
|
3600 $("#starter_enable").on('checked', function (event) { |
|
3601 dataRecord.starter_enable = 1; |
|
3602 showStarter(); |
|
3603 calcYeast(); |
|
3604 }); |
|
3605 $("#starter_enable").on('unchecked', function (event) { |
|
3606 dataRecord.starter_enable = 0; |
|
3607 showStarter(); |
|
3608 calcYeast(); |
|
3609 }); |
|
3610 $("#starter_try").click(function () { |
|
3611 $("#prop1_volume").val(0); |
|
3612 $("#prop2_volume").val(0); |
|
3613 $("#prop3_volume").val(0); |
|
3614 $("#prop4_volume").val(0); |
|
3615 calcYeast(); |
|
3616 }); |
|
3617 $('#starter_type').on('change', function (event) { |
|
3618 if (event.args) { |
|
3619 var index = event.args.index; |
|
3620 dataRecord.starter_type = index; |
|
3621 calcYeast(); |
|
3622 } |
|
3623 }); |
|
3624 $('#starter_sg').on('change', function (event) { |
|
3625 if (event.args) { |
|
3626 dataRecord.starter_sg = event.args.value; |
|
3627 calcYeast(); |
|
3628 } |
|
3629 }); |
|
3630 $('#starter_viability').on('change', function (event) { |
|
3631 if (event.args) { |
|
3632 dataRecord.starter_viability = event.args.value; |
|
3633 calcFermentables(); |
|
3634 calcYeast(); |
|
3635 } |
|
3636 }); |
|
3637 $('#prop1_type').on('change', function (event) { |
|
3638 if (event.args) { |
|
3639 var index = event.args.index; |
|
3640 dataRecord.prop1_type = index; |
|
3641 calcYeast(); |
|
3642 } |
|
3643 }); |
|
3644 $('#prop1_volume').on('change', function (event) { |
|
3645 if (event.args) { |
|
3646 dataRecord.prop1_volume = event.args.value; |
|
3647 calcYeast(); |
|
3648 } |
|
3649 }); |
|
3650 $('#prop2_type').on('change', function (event) { |
|
3651 if (event.args) { |
|
3652 var index = event.args.index; |
|
3653 dataRecord.prop2_type = index; |
|
3654 calcYeast(); |
|
3655 } |
|
3656 }); |
|
3657 $('#prop2_volume').on('change', function (event) { |
|
3658 if (event.args) { |
|
3659 dataRecord.prop2_volume = event.args.value; |
|
3660 calcYeast(); |
|
3661 } |
|
3662 }); |
|
3663 $('#prop3_type').on('change', function (event) { |
|
3664 if (event.args) { |
|
3665 var index = event.args.index; |
|
3666 dataRecord.prop3_type = index; |
|
3667 calcYeast(); |
|
3668 } |
|
3669 }); |
|
3670 $('#prop3_volume').on('change', function (event) { |
|
3671 if (event.args) { |
|
3672 dataRecord.prop3_volume = event.args.value; |
|
3673 calcYeast(); |
|
3674 } |
|
3675 }); |
|
3676 $('#prop4_type').on('change', function (event) { |
|
3677 if (event.args) { |
|
3678 var index = event.args.index; |
|
3679 dataRecord.prop4_type = index; |
|
3680 calcYeast(); |
|
3681 } |
|
3682 }); |
|
3683 $('#prop4_volume').on('change', function (event) { |
|
3684 if (event.args) { |
|
3685 dataRecord.prop4_volume = event.args.value; |
|
3686 calcYeast(); |
|
3687 } |
|
3688 }); |
|
3689 |
|
3690 $("#calc_acid").on('checked', function (event) { |
|
3691 dataRecord.calc_acid = 1; |
|
3692 calcWater(); |
|
3693 }); |
|
3694 $("#calc_acid").on('unchecked', function (event) { |
|
3695 dataRecord.calc_acid = 0; |
|
3696 calcWater(); |
|
3697 }); |
|
3698 $("#w1_name").jqxDropDownList('selectItem', dataRecord.w1_name); |
|
3699 $("#w2_name").jqxDropDownList('selectItem', dataRecord.w2_name); |
|
3700 // Fix tap water if zero using mash infuse amount. |
|
3701 if (parseFloat($("#w1_amount").jqxNumberInput('decimal')) == 0 && mash_infuse > 0) { |
|
3702 $("#w1_amount").val(mash_infuse); |
|
3703 dataRecord.w1_amount = mash_infuse; |
|
3704 $("#wg_amount").val(mash_infuse); |
|
3705 $("#w2_amount").val(0); |
|
3706 dataRecord.w2_amount = 0; |
|
3707 } |
|
3708 calcWater(); |
|
3709 $("#w2_amount").on('change', function (event) { |
|
3710 var newval = parseFloat(event.args.value); |
|
3711 |
|
3712 if (newval > mash_infuse) { |
|
3713 $("#w2_amount").val(dataRecord.w2_amount); |
|
3714 return; |
|
3715 } |
|
3716 dataRecord.w1_amount = parseFloat($("#wg_amount").jqxNumberInput('decimal')) - newval; |
|
3717 $("#w1_amount").val(dataRecord.w1_amount); |
|
3718 dataRecord.w2_amount = newval; |
|
3719 console.log("new: "+event.args.value+" w1: "+dataRecord.w1_amount+" w2: "+dataRecord.w2_amount); |
|
3720 calcWater(); |
|
3721 }); |
|
3722 $('#wa_cacl2').on('change', function (event) { |
|
3723 if (event.args) { |
|
3724 setWaterAgent('CaCl2', 0); // This can prevent double entries. |
|
3725 setWaterAgent('CaCl2', event.args.value); |
|
3726 calcWater(); |
|
3727 } |
|
3728 }); |
|
3729 $('#wa_caso4').on('change', function (event) { |
|
3730 if (event.args) { |
|
3731 setWaterAgent('CaSO4', 0); |
|
3732 setWaterAgent('CaSO4', event.args.value); |
|
3733 calcWater(); |
|
3734 } |
|
3735 }); |
|
3736 $('#wa_mgso4').on('change', function (event) { |
|
3737 if (event.args) { |
|
3738 setWaterAgent('MgSO4', 0); |
|
3739 setWaterAgent('MgSO4', event.args.value); |
|
3740 calcWater(); |
|
3741 } |
|
3742 }); |
|
3743 $('#wa_nacl').on('change', function (event) { |
|
3744 if (event.args) { |
|
3745 setWaterAgent('NaCl', 0); |
|
3746 setWaterAgent('NaCl', event.args.value); |
|
3747 calcWater(); |
|
3748 } |
|
3749 }); |
|
3750 $('#wa_base_name').on('change', function (event) { |
|
3751 if (event.args) { |
|
3752 var index = event.args.index; |
|
3753 console.log("wa_base_name "+index); |
|
3754 setWaterAgent(last_base, 0); |
|
3755 last_base = BaseTypeData[index].nl; |
|
3756 setWaterAgent(last_base, parseFloat($("#wa_base").jqxNumberInput('decimal'))); |
|
3757 dataRecord.wa_base_name = index; |
|
3758 calcWater(); |
|
3759 } |
|
3760 }); |
|
3761 $('#wa_base').on('change', function (event) { |
|
3762 var name = BaseTypeData[$("#wa_base_name").val()].nl; |
|
3763 setWaterAgent(name, parseFloat(event.args.value)); |
|
3764 calcWater(); |
|
3765 }); |
|
3766 $('#wa_acid_name').on('change', function (event) { |
|
3767 if (event.args) { |
|
3768 var index = event.args.index; |
|
3769 console.log("wa_acid_name "+index); |
|
3770 setWaterAgent(last_acid, 0); |
|
3771 last_acid = AcidTypeData[index].nl; |
|
3772 setWaterAgent(last_acid, parseFloat($("#wa_acid").jqxNumberInput('decimal'))); |
|
3773 dataRecord.wa_acid_name = index; |
|
3774 calcWater(); |
|
3775 } |
|
3776 }); |
|
3777 $('#wa_acid').on('change', function (event) { |
|
3778 var name = AcidTypeData[$("#wa_acid_name").val()].nl; |
|
3779 setWaterAgent(name, parseFloat(event.args.value)); |
|
3780 calcWater(); |
|
3781 }); |
|
3782 $('#wa_acid_perc').on('change', function (event) { calcWater(); }); |
|
3783 |
|
3784 $('#color_method').on('change', function (event) { |
|
3785 dataRecord.color_method = event.args.index; |
|
3786 calcFermentables(); |
|
3787 }); |
|
3788 $('#ibu_method').on('change', function (event) { |
|
3789 dataRecord.ibu_method = event.args.index; |
|
3790 calcFermentables(); |
|
3791 calcIBUs(); |
|
3792 }); |
|
3793 |
|
3794 $('#batch_size').on('change', function (event) { |
|
3795 console.log("batch_size change:"+event.args.value+" old:"+dataRecord.batch_size); |
|
3796 $("#est_a_vol").val(event.args.value * 1.04); |
|
3797 var factor, new_boil = parseFloat(event.args.value) + dataRecord.boil_size - dataRecord.batch_size; |
|
3798 factor = parseFloat(event.args.value) / dataRecord.batch_size; |
|
3799 dataRecord.boil_size = new_boil; |
|
3800 $("#boil_size").val(Round(new_boil, 2)); |
|
3801 $("#est_pre_vol").val(Round(new_boil * 1.04, 2)); |
|
3802 dataRecord.sparge_volume *= factor; |
|
3803 $("#sparge_volume").val(dataRecord.sparge_volume); |
|
3804 $("#brew_sparge_volume").val(dataRecord.sparge_volume); |
|
3805 dataRecord.batch_size = parseFloat(event.args.value); |
|
3806 calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal'))); // Keep the OG |
|
3807 adjustWaters(factor); |
|
3808 calcFermentables(); |
|
3809 adjustHops(factor); |
|
3810 adjustMiscs(factor); |
|
3811 adjustYeasts(factor); |
|
3812 calcIBUs(); |
|
3813 calcWater(); |
|
3814 calcSparge(); |
|
3815 calcMash(); |
|
3816 }); |
|
3817 $('#boil_time').on('change', function (event) { |
|
3818 console.log("boil_time change:"+parseFloat(event.args.value)+" old:"+dataRecord.boil_time); |
|
3819 var new_boil, new_evap, old_evap = parseFloat(dataRecord.boil_size) - parseFloat(dataRecord.batch_size); |
|
3820 new_evap = old_evap * (parseFloat(event.args.value) / dataRecord.boil_time); |
|
3821 new_boil = parseFloat(dataRecord.batch_size) + new_evap; |
|
3822 dataRecord.boil_time = parseFloat(event.args.value); |
|
3823 dataRecord.boil_size = new_boil; |
|
3824 $("#est_pre_vol").val(Round(new_boil * 1.04, 2)); |
|
3825 $("#boil_size").val(Round(new_boil, 2)); |
|
3826 calcFermentables(); |
|
3827 calcIBUs(); |
|
3828 calcYeast(); |
|
3829 }); |
|
3830 $('#efficiency').on('change', function (event) { |
|
3831 var estog = parseFloat($("#est_og").jqxNumberInput('decimal')); |
|
3832 dataRecord.efficiency = parseFloat(event.args.value); |
|
3833 console.log("efficiency change:"+dataRecord.efficiency+" est_og:"+estog); |
|
3834 calcFermentablesFromOG(estog); // Keep the OG |
|
3835 calcFermentables(); |
|
3836 calcIBUs(); |
|
3837 calcYeast(); |
|
3838 }); |
|
3839 $('#est_og').on('change', function (event) { |
|
3840 dataRecord.est_og = parseFloat(event.args.value); |
|
3841 console.log("est_og change:"+dataRecord.est_og); |
|
3842 $('#est_og2').val(dataRecord.est_og); |
|
3843 calcFermentablesFromOG(dataRecord.est_og); // Adjust fermentables amounts |
|
3844 calcFermentables(); // Update the recipe details |
|
3845 calcIBUs(); // and the IBU's. |
|
3846 calcMash(); |
|
3847 calcYeast(); |
|
3848 }); |
|
3849 $('#mash_ph').on('change', function (event) { |
|
3850 dataRecord.mash_ph = parseFloat(event.args.value); |
|
3851 calcWater(); |
|
3852 }); |
|
3853 |
|
3854 $('#sparge_ph').on('change', function (event) { |
|
3855 dataRecord.sparge_ph = parseFloat(event.args.value); |
|
3856 calcSparge(); |
|
3857 }); |
|
3858 $('#sparge_volume').on('change', function (event) { |
|
3859 dataRecord.sparge_volume = parseFloat(event.args.value); |
|
3860 $('#brew_sparge_volume').val(dataRecord.sparge_volume); |
|
3861 calcSparge(); |
|
3862 }); |
|
3863 $("#sparge_temp").on('change', function (event) { |
|
3864 dataRecord.sparge_temp = parseFloat(event.args.value); |
|
3865 $('#brew_sparge_temperature').val(dataRecord.sparge_temp); |
|
3866 }); |
|
3867 $('#sparge_source').on('change', function (event) { |
|
3868 if (event.args) { |
|
3869 var index = event.args.index; |
|
3870 dataRecord.sparge_source= index; |
|
3871 calcSparge(); |
|
3872 } |
|
3873 }); |
|
3874 $('#sparge_acid_type').on('change', function (event) { |
|
3875 if (event.args) { |
|
3876 var index = event.args.index; |
|
3877 dataRecord.sparge_acid_type = index; |
|
3878 console.log("new sparge_acid_type: "+dataRecord.sparge_acid_type); |
|
3879 calcSparge(); |
|
3880 } |
|
3881 }); |
|
3882 $('#sparge_acid_perc').on('change', function (event) { |
|
3883 dataRecord.sparge_acid_perc = parseFloat(event.args.value); |
|
3884 calcSparge(); |
|
3885 }); |
|
3886 |
|
3887 calcFermentation(); |
|
3888 calcCarbonation(); |
|
3889 $('#package_volume').on('change', function (event) { |
|
3890 var diff, tnew, told = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
3891 dataRecord.package_volume = parseFloat(event.args.value); |
|
3892 if (dataRecord.package_volume > dataRecord.brew_fermenter_volume) { |
|
3893 dataRecord.package_volume = dataRecord.brew_fermenter_volume; |
|
3894 $('#package_volume').val(dataRecord.package_volume); |
|
3895 } |
|
3896 tnew = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
3897 diff = tnew - told; |
|
3898 if (told > 0) { |
|
3899 dataRecord.bottle_amount += (dataRecord.bottle_amount / told) * diff; |
|
3900 dataRecord.keg_amount += (dataRecord.keg_amount / told) * diff; |
|
3901 } else { |
|
3902 dataRecord.bottle_amount = tnew; |
|
3903 dataRecord.keg_amount = 0; |
|
3904 } |
|
3905 console.log("diff:"+diff+" old:"+told+" bottle:"+dataRecord.bottle_amount+" keg:"+dataRecord.keg_amount); |
|
3906 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount * 1000) / 1000); |
|
3907 $('#keg_amount').val(parseFloat(dataRecord.keg_amount * 1000) / 1000); |
|
3908 calcCarbonation(); |
|
3909 }); |
|
3910 $('#package_infuse_amount').on('change', function (event) { |
|
3911 var diff, tnew, told = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
3912 dataRecord.package_infuse_amount = parseFloat(event.args.value); |
|
3913 tnew = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
3914 diff = tnew - told; |
|
3915 if (told > 0) { |
|
3916 dataRecord.bottle_amount += (dataRecord.bottle_amount / told) * diff; |
|
3917 dataRecord.keg_amount += (dataRecord.keg_amount / told) * diff; |
|
3918 } else { |
|
3919 dataRecord.bottle_amount = tnew; |
|
3920 dataRecord.keg_amount = 0; |
|
3921 } |
|
3922 console.log("diff:"+diff+" old:"+told+" bottle:"+dataRecord.bottle_amount+" keg:"+dataRecord.keg_amount); |
|
3923 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount * 1000) / 1000); |
|
3924 $('#keg_amount').val(parseFloat(dataRecord.keg_amount * 1000) / 1000); |
|
3925 calcCarbonation(); |
|
3926 }); |
|
3927 $('#package_infuse_abv').on('change', function (event) { |
|
3928 dataRecord.package_infuse_abv = parseFloat(event.args.value); |
|
3929 calcCarbonation(); |
|
3930 }); |
|
3931 $('#bottle_amount').on('change', function (event) { |
|
3932 var vtot, diff, vnew = parseFloat(event.args.value); |
|
3933 vtot = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
3934 if (vnew > vtot) |
|
3935 vnew = vtot; |
|
3936 diff = dataRecord.bottle_amount - vnew; |
|
3937 dataRecord.bottle_amount = Math.round((dataRecord.bottle_amount - diff) * 1000) / 1000; |
|
3938 dataRecord.keg_amount = Math.round((dataRecord.keg_amount + diff) * 1000) / 1000; |
|
3939 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount)); |
|
3940 $('#keg_amount').val(parseFloat(dataRecord.keg_amount)); |
|
3941 calcCarbonation(); |
|
3942 }); |
|
3943 $("#bottle_priming_water").on('change', function (event) { |
|
3944 dataRecord.bottle_priming_water = parseFloat(event.args.value); |
|
3945 calcCarbonation(); |
|
3946 }); |
|
3947 $('#keg_amount').on('change', function (event) { |
|
3948 var diff, vtot, vnew = parseFloat(event.args.value); |
|
3949 vtot = dataRecord.package_volume + dataRecord.package_infuse_amount; |
|
3950 if (vnew > vtot) |
|
3951 vnew = vtot; |
|
3952 diff = dataRecord.keg_amount - vnew; |
|
3953 dataRecord.bottle_amount = Math.round((dataRecord.bottle_amount + diff) * 1000) / 1000; |
|
3954 dataRecord.keg_amount = Math.round((dataRecord.keg_amount - diff) * 1000) / 1000; |
|
3955 $('#bottle_amount').val(parseFloat(dataRecord.bottle_amount)); |
|
3956 $('#keg_amount').val(parseFloat(dataRecord.keg_amount)); |
|
3957 calcCarbonation(); |
|
3958 }); |
|
3959 $("#keg_priming_water").on('change', function (event) { |
|
3960 dataRecord.keg_priming_water = parseFloat(event.args.value); |
|
3961 calcCarbonation(); |
|
3962 }); |
|
3963 $('#bottle_carbonation').on('change', function (event) { |
|
3964 dataRecord.bottle_carbonation = parseFloat(event.args.value); |
|
3965 calcCarbonation(); |
|
3966 }); |
|
3967 $('#bottle_carbonation_temp').on('change', function (event) { |
|
3968 dataRecord.bottle_carbonation_temp = parseFloat(event.args.value); |
|
3969 calcCarbonation(); |
|
3970 }); |
|
3971 $('#keg_carbonation').on('change', function (event) { |
|
3972 dataRecord.keg_carbonation = parseFloat(event.args.value); |
|
3973 calcCarbonation(); |
|
3974 }); |
|
3975 $("#keg_forced_carb").on('checked', function (event) { |
|
3976 dataRecord.keg_forced_carb = 1; |
|
3977 calcCarbonation(); |
|
3978 }); |
|
3979 $("#keg_forced_carb").on('unchecked', function (event) { |
|
3980 dataRecord.keg_forced_carb = 0; |
|
3981 calcCarbonation(); |
|
3982 }); |
|
3983 $('#keg_carbonation_temp').on('change', function (event) { |
|
3984 dataRecord.keg_carbonation_temp = parseFloat(event.args.value); |
|
3985 calcCarbonation(); |
|
3986 }); |
|
3987 |
|
3988 $("#brew_fermenter_extrawater").on('change',function (event){ |
|
3989 dataRecord.brew_fermenter_extrawater=parseFloat(event.args.value);calcFermentables();calcIBUs();calcYeast(); |
|
3990 }); |
|
3991 $("#brew_fermenter_tcloss").on('change',function (event){ |
|
3992 dataRecord.brew_fermenter_tcloss=parseFloat(event.args.value);calcFermentables();calcIBUs();calcYeast(); |
|
3993 }); |
|
3994 $("#primary_end_sg").on('change',function (event){dataRecord.primary_end_sg=parseFloat(event.args.value);calcFermentation();}); |
|
3995 $("#primary_end_brix").on('change', function (event) { |
|
3996 var OBrix, FBrix, FG; |
|
3997 if(dataRecord.brew_fermenter_sg>=1.020){ |
|
3998 OBrix = sg_to_brix(dataRecord.brew_fermenter_sg); |
|
3999 FBrix = parseFloat(event.args.value); |
|
4000 FG = Round(1.0031 - 0.002318474*OBrix - 0.000007775*(OBrix*OBrix) - 0.000000034*Math.pow(OBrix,3) + |
|
4001 0.00574*(FBrix) + 0.00003344*(FBrix*FBrix) + 0.000000086*Math.pow(FBrix,3), 4); |
|
4002 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG); |
|
4003 if (FBrix > 0.05) { |
|
4004 $("#primary_end_sg").val(FG); |
|
4005 dataRecord.primary_end_sg=FG; |
|
4006 } |
|
4007 calcFermentation(); |
|
4008 } |
|
4009 }); |
|
4010 $("#secondary_end_sg").on('change',function (event){dataRecord.secondary_end_sg=parseFloat(event.args.value);calcFermentation();}); |
|
4011 $("#secondary_end_brix").on('change', function (event) { |
|
4012 var OBrix, FBrix, FG; |
|
4013 if(dataRecord.brew_fermenter_sg>=1.020){ |
|
4014 OBrix = sg_to_brix(dataRecord.brew_fermenter_sg); |
|
4015 FBrix = parseFloat(event.args.value); |
|
4016 FG = Round(1.0031 - 0.002318474*OBrix - 0.000007775*(OBrix*OBrix) - 0.000000034*Math.pow(OBrix,3) + |
|
4017 0.00574*(FBrix) + 0.00003344*(FBrix*FBrix) + 0.000000086*Math.pow(FBrix,3), 4); |
|
4018 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG); |
|
4019 if (FBrix > 0.05) { |
|
4020 $("#secondary_end_sg").val(FG); |
|
4021 dataRecord.secondary_end_sg=FG; |
|
4022 } |
|
4023 calcFermentation(); |
|
4024 } |
|
4025 }); |
|
4026 $("#final_brix").on('change',function (event){ |
|
4027 var OBrix, FBrix, FG; |
|
4028 if(dataRecord.brew_fermenter_sg>=1.020){ |
|
4029 OBrix = sg_to_brix(dataRecord.brew_fermenter_sg); |
|
4030 FBrix = parseFloat(event.args.value); |
|
4031 FG = Round(1.0031 - 0.002318474*OBrix - 0.000007775*(OBrix*OBrix) - 0.000000034*Math.pow(OBrix,3) + |
|
4032 0.00574*(FBrix) + 0.00003344*(FBrix*FBrix) + 0.000000086*Math.pow(FBrix,3), 4); |
|
4033 //console.log("OBrix:"+OBrix+" FBrix:"+FBrix+" FG:"+FG); |
|
4034 if (FBrix > 0.05) { |
|
4035 $("#fg").val(FG); |
|
4036 dataRecord.fg=FG; |
|
4037 } |
|
4038 calcFermentation(); |
|
4039 } |
|
4040 }); |
|
4041 $("#fg").on('change',function (event){dataRecord.fg=parseFloat(event.args.value);calcFermentation();}); |
|
4042 $("#BLog").jqxButton({disabled:(dataRecord.log_brew)?false:true}); |
|
4043 $("#FLog").jqxButton({disabled:(dataRecord.log_fermentation)?false:true}); |
|
4044 } |
|
4045 |
|
4046 $("#styleSelect").jqxDropDownList({ |
|
4047 placeHolder: "Kies bierstijl:", |
|
4048 theme: theme, |
|
4049 source: styleslist, |
|
4050 displayMember: "name", |
|
4051 width: 180, |
|
4052 height: 23, |
|
4053 dropDownVerticalAlignment: 'top', |
|
4054 dropDownWidth: 500, |
|
4055 dropDownHeight: 380, |
|
4056 renderer: function (index, label, value) { |
|
4057 var datarecord = styleslist.records[index]; |
|
4058 return datarecord.style_guide + " " + datarecord.style_letter+ " " + datarecord.name; |
|
4059 } |
|
4060 }); |
|
4061 $("#styleSelect").on('select', function (event) { |
|
4062 if (event.args) { |
|
4063 var datarecord, index = event.args.index; |
|
4064 datarecord = styleslist.records[index]; |
|
4065 $("#st_name").val(datarecord.name); |
|
4066 $("#st_category").val(datarecord.category); |
|
4067 $("#st_category_number").val(datarecord.category_number); |
|
4068 $("#st_letter").val(datarecord.style_letter); |
|
4069 $("#st_guide").val(datarecord.style_guide); |
|
4070 $("#st_type").val(StyleTypeData[datarecord.type].nl); |
|
4071 $("#st_og_min").val(datarecord.og_min); |
|
4072 $("#st_og_max").val(datarecord.og_max); |
|
4073 $("#st_fg_min").val(datarecord.fg_min); |
|
4074 $("#st_fg_max").val(datarecord.fg_max); |
|
4075 $("#st_ibu_min").val(datarecord.ibu_min); |
|
4076 $("#st_ibu_max").val(datarecord.ibu_max); |
|
4077 $("#st_color_min").val(datarecord.color_min); |
|
4078 $("#st_color_max").val(datarecord.color_max); |
|
4079 $("#st_carb_min").val(datarecord.carb_min); |
|
4080 $("#st_carb_min2").val(datarecord.carb_min); |
|
4081 $("#st_carb_max").val(datarecord.carb_max); |
|
4082 $("#st_carb_max2").val(datarecord.carb_max); |
|
4083 $("#st_abv_min").val(datarecord.abv_min); |
|
4084 $("#st_abv_max").val(datarecord.abv_max); |
|
4085 } |
|
4086 }); |
|
4087 |
|
4088 // Equipemnt dropdown list |
|
4089 $("#equipmentSelect").jqxDropDownList({ |
|
4090 placeHolder: "Kies apparatuur:", |
|
4091 theme: theme, |
|
4092 source: equipmentlist, |
|
4093 displayMember: "name", |
|
4094 width: 170, |
|
4095 height: 23, |
|
4096 dropDownWidth: 300, |
|
4097 renderer: function (index, label, value) { |
|
4098 var datarecord = equipmentlist.records[index]; |
|
4099 return datarecord.batch_size + " liter " + datarecord.name; |
|
4100 } |
|
4101 }); |
|
4102 $("#equipmentSelect").on('select', function (event) { |
|
4103 if (event.args) { |
|
4104 var datarecord, factor, index = event.args.index; |
|
4105 datarecord = equipmentlist.records[index]; |
|
4106 factor = datarecord.batch_size / dataRecord.batch_size; |
|
4107 $("#eq_name").val(datarecord.name); |
|
4108 $("#eq_boil_size").val(datarecord.boil_size); |
|
4109 dataRecord.boil_size = datarecord.boil_size; |
|
4110 $("#boil_size").val(datarecord.boil_size); |
|
4111 $("#eq_batch_size").val(datarecord.batch_size); |
|
4112 dataRecord.batch_size = datarecord.batch_size; |
|
4113 $("#batch_size").val(datarecord.batch_size); |
|
4114 $("#est_a_vol").val(datarecord.batch_size * 1.04); |
|
4115 $("#eq_tun_volume").val(datarecord.tun_volume); |
|
4116 dataRecord.eq_tun_weight = datarecord.tun_weight; |
|
4117 dataRecord.eq_tun_specific_heat = datarecord.tun_specific_heat; |
|
4118 dataRecord.eq_tun_material = datarecord.tun_material; |
|
4119 dataRecord.eq_tun_height = datarecord.tun_height / 100.0; |
|
4120 $("#eq_top_up_water").val(datarecord.top_up_water); |
|
4121 dataRecord.eq_trub_chiller_loss = datarecord.trub_chiller_loss; |
|
4122 $("#eq_trub_chiller_loss").val(datarecord.trub_chiller_loss); |
|
4123 $("#eq_evap_rate").val(datarecord.evap_rate); |
|
4124 $("#eq_boil_time").val(datarecord.boil_time); |
|
4125 dataRecord.eq_calc_boil_volume = datarecord.calc_boil_volume; |
|
4126 $("#eq_top_up_kettle").val(datarecord.top_up_kettle); |
|
4127 $("#eq_hop_utilization").val(datarecord.hop_utilization); |
|
4128 $("#eq_notes").val(datarecord.notes); |
|
4129 $("#eq_lauter_volume").val(datarecord.lauter_volume); |
|
4130 dataRecord.eq_lauter_height = datarecord.lauter_height / 100.0; |
|
4131 $("#eq_lauter_deadspace").val(datarecord.lauter_deadspace); |
|
4132 $("#eq_kettle_volume").val(datarecord.kettle_volume); |
|
4133 dataRecord.eq_kettle_height = datarecord.kettle_height / 100.0; |
|
4134 $("#eq_mash_volume").val(datarecord.mash_volume); |
|
4135 $("#eq_mash_max").val(datarecord.mash_max); |
|
4136 dataRecord.eq_mash_max = datarecord.mash_max; |
|
4137 $("#mash_max").val(datarecord.mash_max); |
|
4138 $("#eq_efficiency").val(datarecord.efficiency); |
|
4139 dataRecord.efficiency = datarecord.efficiency; |
|
4140 $("#efficiency").val(datarecord.efficiency); |
|
4141 |
|
4142 dataRecord.sparge_volume = Math.round(datarecord.boil_size * 5) / 10; |
|
4143 $("#sparge_volume").val(dataRecord.sparge_volume); |
|
4144 $("#brew_sparge_volume").val(dataRecord.sparge_volume); |
|
4145 $("#est_pre_vol").val(datarecord.boil_size * 1.04); |
|
4146 calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal'))); // Keep the OG |
|
4147 adjustWaters(factor); |
|
4148 calcFermentables(); |
|
4149 adjustHops(factor); |
|
4150 adjustMiscs(factor); |
|
4151 adjustYeasts(factor); |
|
4152 calcIBUs(); |
|
4153 calcWater(); |
|
4154 calcSparge(); |
|
4155 } |
|
4156 }); |
|
4157 |
|
4158 function saveRecord() { |
|
4159 console.log("saveRecord()"); |
|
4160 var row = { |
|
4161 record: my_record, |
|
4162 uuid: dataRecord.uuid, |
|
4163 name: $("#name").val(), |
|
4164 code: $("#code").val(), |
|
4165 birth: $("#birth").val(), |
|
4166 stage: dataRecord.stage, |
|
4167 notes: $("#notes").val(), |
|
4168 log_brew: dataRecord.log_brew, |
|
4169 log_fermentation: dataRecord.log_fermentation, |
|
4170 inventory_reduced: dataRecord.inventory_reduced, |
|
4171 locked: dataRecord.locked, |
|
4172 eq_name: $("#eq_name").val(), |
|
4173 eq_boil_size: parseFloat($("#eq_boil_size").jqxNumberInput('decimal')), |
|
4174 eq_batch_size: parseFloat($("#eq_batch_size").jqxNumberInput('decimal')), |
|
4175 eq_tun_volume: parseFloat($("#eq_tun_volume").jqxNumberInput('decimal')), |
|
4176 eq_tun_weight: dataRecord.eq_tun_weight, |
|
4177 eq_tun_specific_heat: dataRecord.eq_tun_specific_heat, |
|
4178 eq_tun_material: dataRecord.eq_tun_material, |
|
4179 eq_tun_height: dataRecord.eq_tun_height, |
|
4180 eq_top_up_water: parseFloat($("#eq_top_up_water").jqxNumberInput('decimal')), |
|
4181 eq_trub_chiller_loss: parseFloat($("#eq_trub_chiller_loss").jqxNumberInput('decimal')), |
|
4182 eq_evap_rate: parseFloat($("#eq_evap_rate").jqxNumberInput('decimal')), |
|
4183 eq_boil_time: parseFloat($("#eq_boil_time").jqxNumberInput('decimal')), |
|
4184 eq_calc_boil_volume: dataRecord.eq_calc_boil_volume, |
|
4185 eq_top_up_kettle: parseFloat($("#eq_top_up_kettle").jqxNumberInput('decimal')), |
|
4186 eq_hop_utilization: parseFloat($("#eq_hop_utilization").jqxNumberInput('decimal')), |
|
4187 eq_notes: $("#eq_notes").val(), |
|
4188 eq_lauter_volume: parseFloat($("#eq_lauter_volume").jqxNumberInput('decimal')), |
|
4189 eq_lauter_height: dataRecord.eq_lauter_height, |
|
4190 eq_lauter_deadspace: parseFloat($("#eq_lauter_deadspace").jqxNumberInput('decimal')), |
|
4191 eq_kettle_volume: parseFloat($("#eq_kettle_volume").jqxNumberInput('decimal')), |
|
4192 eq_kettle_height: dataRecord.eq_kettle_height, |
|
4193 eq_mash_volume: parseFloat($("#eq_mash_volume").jqxNumberInput('decimal')), |
|
4194 eq_mash_max: parseFloat($("#eq_mash_max").jqxNumberInput('decimal')), |
|
4195 eq_efficiency: parseFloat($("#eq_efficiency").jqxNumberInput('decimal')), |
|
4196 brew_date_start: $("#brew_date_start").val(), |
|
4197 brew_mash_ph: parseFloat($("#brew_mash_ph").jqxNumberInput('decimal')), |
|
4198 brew_mash_sg: parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')), |
|
4199 brew_mash_efficiency: parseFloat($("#brew_mash_efficiency").jqxNumberInput('decimal')), |
|
4200 brew_sparge_est: parseFloat($("#brew_sparge_est").jqxNumberInput('decimal')), |
|
4201 brew_sparge_ph: parseFloat($("#brew_sparge_ph").jqxNumberInput('decimal')), |
|
4202 brew_preboil_volume: parseFloat($("#brew_preboil_volume").jqxNumberInput('decimal')), |
|
4203 brew_preboil_sg: parseFloat($("#brew_preboil_sg").jqxNumberInput('decimal')), |
|
4204 brew_preboil_ph: parseFloat($("#brew_preboil_ph").jqxNumberInput('decimal')), |
|
4205 brew_preboil_efficiency: parseFloat($("#brew_preboil_efficiency").jqxNumberInput('decimal')), |
|
4206 brew_aboil_volume: parseFloat($("#brew_aboil_volume").jqxNumberInput('decimal')), |
|
4207 brew_aboil_sg: parseFloat($("#brew_aboil_sg").jqxNumberInput('decimal')), |
|
4208 brew_aboil_ph: parseFloat($("#brew_aboil_ph").jqxNumberInput('decimal')), |
|
4209 brew_aboil_efficiency: parseFloat($("#brew_aboil_efficiency").jqxNumberInput('decimal')), |
|
4210 brew_cooling_method: $("#brew_cooling_method").val(), |
|
4211 brew_cooling_time: parseFloat($("#brew_cooling_time").jqxNumberInput('decimal')), |
|
4212 brew_cooling_to: parseFloat($("#brew_cooling_to").jqxNumberInput('decimal')), |
|
4213 brew_whirlpool9: parseFloat($("#brew_whirlpool9").jqxNumberInput('decimal')), |
|
4214 brew_whirlpool7: parseFloat($("#brew_whirlpool7").jqxNumberInput('decimal')), |
|
4215 brew_whirlpool6: parseFloat($("#brew_whirlpool6").jqxNumberInput('decimal')), |
|
4216 brew_whirlpool2: parseFloat($("#brew_whirlpool2").jqxNumberInput('decimal')), |
|
4217 brew_fermenter_volume: parseFloat($("#brew_fermenter_volume").jqxNumberInput('decimal')), |
|
4218 brew_fermenter_extrawater: parseFloat($("#brew_fermenter_extrawater").jqxNumberInput('decimal')), |
|
4219 brew_fermenter_tcloss: parseFloat($("#brew_fermenter_tcloss").jqxNumberInput('decimal')), |
|
4220 brew_aeration_time: parseFloat($("#brew_aeration_time").jqxNumberInput('decimal')), |
|
4221 brew_aeration_speed: parseFloat($("#brew_aeration_speed").jqxNumberInput('decimal')), |
|
4222 brew_aeration_type: $("#brew_aeration_type").val(), |
|
4223 brew_fermenter_sg: parseFloat($("#brew_fermenter_sg").jqxNumberInput('decimal')), |
|
4224 brew_fermenter_ibu: parseFloat($("#brew_fermenter_ibu").jqxNumberInput('decimal')), |
|
4225 brew_fermenter_color: parseFloat($("#brew_fermenter_color").jqxNumberInput('decimal')), |
|
4226 brew_date_end: $("#brew_date_end").val(), |
|
4227 og: dataRecord.og, |
|
4228 fg: parseFloat($("#fg").jqxNumberInput('decimal')), |
|
4229 primary_start_temp: parseFloat($("#primary_start_temp").jqxNumberInput('decimal')), |
|
4230 primary_max_temp: parseFloat($("#primary_max_temp").jqxNumberInput('decimal')), |
|
4231 primary_end_temp: parseFloat($("#primary_end_temp").jqxNumberInput('decimal')), |
|
4232 primary_end_sg: parseFloat($("#primary_end_sg").jqxNumberInput('decimal')), |
|
4233 primary_end_date: $("#primary_end_date").val(), |
|
4234 secondary_temp: parseFloat($("#secondary_temp").jqxNumberInput('decimal')), |
|
4235 secondary_end_sg: parseFloat($("#secondary_end_sg").jqxNumberInput('decimal')), |
|
4236 secondary_end_date: $("#secondary_end_date").val(), |
|
4237 tertiary_temp: parseFloat($("#tertiary_temp").jqxNumberInput('decimal')), |
|
4238 package_date: $("#package_date").val(), |
|
4239 package_volume: parseFloat($("#package_volume").jqxNumberInput('decimal')), |
|
4240 package_infuse_amount: parseFloat($("#package_infuse_amount").jqxNumberInput('decimal')), |
|
4241 package_infuse_abv: parseFloat($("#package_infuse_abv").jqxNumberInput('decimal')), |
|
4242 package_infuse_notes: $("#package_infuse_notes").val(), |
|
4243 package_abv: parseFloat($("#package_abv").jqxNumberInput('decimal')), |
|
4244 package_ph: parseFloat($("#package_ph").jqxNumberInput('decimal')), |
|
4245 bottle_amount: parseFloat($("#bottle_amount").jqxNumberInput('decimal')), |
|
4246 bottle_carbonation: parseFloat($("#bottle_carbonation").jqxNumberInput('decimal')), |
|
4247 bottle_priming_water: parseFloat($("#bottle_priming_water").jqxNumberInput('decimal')), |
|
4248 bottle_priming_amount: parseFloat($("#bottle_priming_amount").jqxNumberInput('decimal')), |
|
4249 bottle_carbonation_temp: parseFloat($("#bottle_carbonation_temp").jqxNumberInput('decimal')), |
|
4250 keg_amount: parseFloat($("#keg_amount").jqxNumberInput('decimal')), |
|
4251 keg_carbonation: parseFloat($("#keg_carbonation").jqxNumberInput('decimal')), |
|
4252 keg_priming_water: parseFloat($("#keg_priming_water").jqxNumberInput('decimal')), |
|
4253 keg_priming_amount: parseFloat($("#keg_priming_amount").jqxNumberInput('decimal')), |
|
4254 keg_carbonation_temp: parseFloat($("#keg_carbonation_temp").jqxNumberInput('decimal')), |
|
4255 keg_forced_carb: dataRecord.keg_forced_carb, |
|
4256 keg_pressure: parseFloat($("#keg_pressure").jqxNumberInput('decimal')), |
|
4257 taste_notes: $("#taste_notes").val(), |
|
4258 taste_rate: parseFloat($("#taste_rate").jqxNumberInput('decimal')), |
|
4259 taste_date: $("#taste_date").val(), |
|
4260 taste_color: $("#taste_color").val(), |
|
4261 taste_transparency: $("#taste_transparency").val(), |
|
4262 taste_head: $("#taste_head").val(), |
|
4263 taste_aroma: $("#taste_aroma").val(), |
|
4264 taste_taste: $("#taste_taste").val(), |
|
4265 taste_mouthfeel: $("#taste_mouthfeel").val(), |
|
4266 taste_aftertaste: $("#taste_aftertaste").val(), |
|
4267 st_name: $('#st_name').val(), |
|
4268 st_letter: $('#st_letter').val(), |
|
4269 st_guide: $('#st_guide').val(), |
|
4270 st_type: dataRecord.st_type, |
|
4271 st_category: $('#st_category').val(), |
|
4272 st_category_number: parseFloat($("#st_category_number").jqxNumberInput('decimal')), |
|
4273 st_og_min: parseFloat($("#st_og_min").jqxNumberInput('decimal')), |
|
4274 st_og_max: parseFloat($("#st_og_max").jqxNumberInput('decimal')), |
|
4275 st_fg_min: parseFloat($("#st_fg_min").jqxNumberInput('decimal')), |
|
4276 st_fg_max: parseFloat($("#st_fg_max").jqxNumberInput('decimal')), |
|
4277 st_ibu_min: parseFloat($("#st_ibu_min").jqxNumberInput('decimal')), |
|
4278 st_ibu_max: parseFloat($("#st_ibu_max").jqxNumberInput('decimal')), |
|
4279 st_color_min: parseFloat($("#st_color_min").jqxNumberInput('decimal')), |
|
4280 st_color_max: parseFloat($("#st_color_max").jqxNumberInput('decimal')), |
|
4281 st_carb_min: parseFloat($("#st_carb_min").jqxNumberInput('decimal')), |
|
4282 st_carb_max: parseFloat($("#st_carb_max").jqxNumberInput('decimal')), |
|
4283 st_abv_min: parseFloat($("#st_abv_min").jqxNumberInput('decimal')), |
|
4284 st_abv_max: parseFloat($("#st_abv_max").jqxNumberInput('decimal')), |
|
4285 type: $("#type").val(), |
|
4286 batch_size: parseFloat($("#batch_size").jqxNumberInput('decimal')), |
|
4287 boil_size: parseFloat($("#boil_size").jqxNumberInput('decimal')), |
|
4288 boil_time: parseFloat($("#boil_time").jqxNumberInput('decimal')), |
|
4289 efficiency: parseFloat($("#efficiency").jqxNumberInput('decimal')), |
|
4290 est_og: parseFloat($("#est_og").jqxNumberInput('decimal')), |
|
4291 est_fg: parseFloat($("#est_fg").jqxNumberInput('decimal')), |
|
4292 est_abv: parseFloat($("#est_abv").jqxNumberInput('decimal')), |
|
4293 est_color: parseFloat($("#est_color").jqxNumberInput('decimal')), |
|
4294 color_method: $("#color_method").val(), |
|
4295 est_ibu: parseFloat($("#est_ibu").jqxNumberInput('decimal')), |
|
4296 ibu_method: $("#ibu_method").val(), |
|
4297 est_carb: parseFloat($("#est_carb").jqxNumberInput('decimal')), |
|
4298 mash_name: $("#mash_name").val(), |
|
4299 mash_ph: parseFloat($("#mash_ph").jqxNumberInput('decimal')), |
|
4300 sparge_temp: parseFloat($("#sparge_temp").jqxNumberInput('decimal')), |
|
4301 sparge_ph: parseFloat($("#sparge_ph").jqxNumberInput('decimal')), |
|
4302 sparge_volume: parseFloat($("#sparge_volume").jqxNumberInput('decimal')), |
|
4303 sparge_source: $("#sparge_source").val(), |
|
4304 sparge_acid_type: $("#sparge_acid_type").val(), |
|
4305 sparge_acid_perc: parseFloat($("#sparge_acid_perc").jqxNumberInput('decimal')), |
|
4306 sparge_acid_amount: dataRecord.sparge_acid_amount, |
|
4307 calc_acid: dataRecord.calc_acid, |
|
4308 w1_name: $("#w1_name").val(), |
|
4309 w1_amount: parseFloat($("#w1_amount").jqxNumberInput('decimal')), |
|
4310 w1_calcium: parseFloat($("#w1_calcium").jqxNumberInput('decimal')), |
|
4311 w1_sulfate: parseFloat($("#w1_sulfate").jqxNumberInput('decimal')), |
|
4312 w1_chloride: parseFloat($("#w1_chloride").jqxNumberInput('decimal')), |
|
4313 w1_sodium: parseFloat($("#w1_sodium").jqxNumberInput('decimal')), |
|
4314 w1_magnesium: parseFloat($("#w1_magnesium").jqxNumberInput('decimal')), |
|
4315 w1_total_alkalinity: parseFloat($("#w1_total_alkalinity").jqxNumberInput('decimal')), |
|
4316 w1_ph: parseFloat($("#w1_ph").jqxNumberInput('decimal')), |
|
4317 w1_cost: dataRecord.w1_cost, |
|
4318 w2_name: $("#w2_name").val(), |
|
4319 w2_amount: parseFloat($("#w2_amount").jqxNumberInput('decimal')), |
|
4320 w2_calcium: parseFloat($("#w2_calcium").jqxNumberInput('decimal')), |
|
4321 w2_sulfate: parseFloat($("#w2_sulfate").jqxNumberInput('decimal')), |
|
4322 w2_chloride: parseFloat($("#w2_chloride").jqxNumberInput('decimal')), |
|
4323 w2_sodium: parseFloat($("#w2_sodium").jqxNumberInput('decimal')), |
|
4324 w2_magnesium: parseFloat($("#w2_magnesium").jqxNumberInput('decimal')), |
|
4325 w2_total_alkalinity: parseFloat($("#w2_total_alkalinity").jqxNumberInput('decimal')), |
|
4326 w2_ph: parseFloat($("#w2_ph").jqxNumberInput('decimal')), |
|
4327 w2_cost: dataRecord.w2_cost, |
|
4328 wg_amount: parseFloat($("#wg_amount").jqxNumberInput('decimal')), |
|
4329 wg_calcium: parseFloat($("#wg_calcium").jqxNumberInput('decimal')), |
|
4330 wg_sulfate: parseFloat($("#wg_sulfate").jqxNumberInput('decimal')), |
|
4331 wg_chloride: parseFloat($("#wg_chloride").jqxNumberInput('decimal')), |
|
4332 wg_sodium: parseFloat($("#wg_sodium").jqxNumberInput('decimal')), |
|
4333 wg_magnesium: parseFloat($("#wg_magnesium").jqxNumberInput('decimal')), |
|
4334 wg_total_alkalinity: parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')), |
|
4335 wg_ph: parseFloat($("#wg_ph").jqxNumberInput('decimal')), |
|
4336 wb_calcium: parseFloat($("#wb_calcium").jqxNumberInput('decimal')), |
|
4337 wb_sulfate: parseFloat($("#wb_sulfate").jqxNumberInput('decimal')), |
|
4338 wb_chloride: parseFloat($("#wb_chloride").jqxNumberInput('decimal')), |
|
4339 wb_sodium: parseFloat($("#wb_sodium").jqxNumberInput('decimal')), |
|
4340 wb_magnesium: parseFloat($("#wb_magnesium").jqxNumberInput('decimal')), |
|
4341 wb_total_alkalinity: parseFloat($("#wb_total_alkalinity").jqxNumberInput('decimal')), |
|
4342 wb_ph: parseFloat($("#wb_ph").jqxNumberInput('decimal')), |
|
4343 wa_acid_name: $("#wa_acid_name").val(), |
|
4344 wa_acid_perc: parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')), |
|
4345 wa_base_name: $("#wa_base_name").val(), |
|
4346 starter_enable: dataRecord.starter_enable, |
|
4347 starter_type: $("#starter_type").val(), |
|
4348 starter_sg: parseFloat($("#starter_sg").jqxNumberInput('decimal')), |
|
4349 starter_viability: parseFloat($("#starter_viability").jqxNumberInput('decimal')), |
|
4350 prop1_type: $("#prop1_type").val(), |
|
4351 prop1_volume: parseFloat($("#prop1_volume").jqxNumberInput('decimal')), |
|
4352 prop2_type: $("#prop2_type").val(), |
|
4353 prop2_volume: parseFloat($("#prop2_volume").jqxNumberInput('decimal')), |
|
4354 prop3_type: $("#prop3_type").val(), |
|
4355 prop3_volume: parseFloat($("#prop3_volume").jqxNumberInput('decimal')), |
|
4356 prop4_type: $("#prop4_type").val(), |
|
4357 prop4_volume: parseFloat($("#prop4_volume").jqxNumberInput('decimal')), |
|
4358 fermentables: $('#fermentableGrid').jqxGrid('getrows'), |
|
4359 hops: $('#hopGrid').jqxGrid('getrows'), |
|
4360 miscs: $('#miscGrid').jqxGrid('getrows'), |
|
4361 yeasts: $('#yeastGrid').jqxGrid('getrows'), |
|
4362 mashs: $('#mashGrid').jqxGrid('getrows') |
|
4363 }, |
|
4364 data = "update=true&" + $.param(row); |
|
4365 $.ajax({ |
|
4366 dataType: 'json', |
|
4367 url: url, |
|
4368 cache: false, |
|
4369 data: data, |
|
4370 async: false, |
|
4371 type: "POST", |
|
4372 success: function (data, status, xhr) { |
|
4373 console.log("saveRecord() success"); |
|
4374 }, |
|
4375 error: function(jqXHR, textStatus, errorThrown) { |
|
4376 console.log("saveRecord() error"); |
|
4377 } |
|
4378 }); |
|
4379 }; |
|
4380 |
4392 // initialize the input fields. |
4381 // initialize the input fields. |
4393 // Tab 1, Algemeen |
4382 // Tab 1, Algemeen |
4394 $("#name").jqxTooltip({ content: 'De naam voor dit product.' }); |
4383 $("#name").jqxTooltip({ content: 'De naam voor dit product.' }); |
4395 $("#name").jqxInput({ theme: theme, width: 640, height: 23 }); |
4384 $("#name").jqxInput({ theme: theme, width: 640, height: 23 }); |
4396 $("#code").jqxTooltip({ content: 'Product code nummer.' }); |
4385 $("#code").jqxTooltip({ content: 'Product code nummer.' }); |