|
1 /***************************************************************************** |
|
2 * Copyright (C) 2018-2022 |
|
3 * |
|
4 * Michiel Broek <mbroek at mbse dot eu> |
|
5 * |
|
6 * This file is part of BMS |
|
7 * |
|
8 * This is free software; you can redistribute it and/or modify it |
|
9 * under the terms of the GNU General Public License as published by the |
|
10 * Free Software Foundation; either version 2, or (at your option) any |
|
11 * later version. |
|
12 * |
|
13 * BrewCloud is distributed in the hope that it will be useful, but |
|
14 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 * General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU General Public License |
|
19 * along with ThermFerm; see the file COPYING. If not, write to the Free |
|
20 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
|
21 *****************************************************************************/ |
|
22 |
|
23 |
|
24 function block_fermentable(stage, added) { |
|
25 if (stage > 5 && added < 4) // After fermentation and added before packaging |
|
26 return true; |
|
27 if (stage > 3 && added < 3) // After primary and added before sec/tert |
|
28 return true; |
|
29 if (stage > 2 && added < 2) // After boil and added during mash or boil |
|
30 return true; |
|
31 return false; |
|
32 } |
|
33 |
|
34 function block_hop(stage, useat) |
|
35 { |
|
36 if (stage > 2 && useat < 5) |
|
37 return true; |
|
38 return false; |
|
39 } |
|
40 |
|
41 function block_misc(stage, use_use) { |
|
42 if (stage > 5 && use_use < 5) |
|
43 return true; |
|
44 if (stage > 3 && use_use < 4) |
|
45 return true; |
|
46 if (stage > 2 && use_use < 3) |
|
47 return true; |
|
48 if (stage > 1 && use_use < 1) |
|
49 return true; |
|
50 return false; |
|
51 } |
|
52 |
|
53 function block_yeast(stage, use) { |
|
54 if (stage > 3 && use < 1) |
|
55 return true; |
|
56 if (stage > 4 && use < 2) |
|
57 return true; |
|
58 if (stage > 5 && use < 3) |
|
59 return true; |
|
60 if (stage > 6 && use < 4) |
|
61 return true; |
|
62 return false; |
|
63 } |
|
64 |
|
65 |
|
66 $(document).ready(function() { |
|
67 |
|
68 var i, |
|
69 to_100 = false, // Fermentables adjust to 100% |
|
70 preboil_sg = 0, |
|
71 aboil_sg = 0, |
|
72 est_mash_sg = 0, |
|
73 psugar = 0, // Percentage real sugars |
|
74 pcara = 0, // Percentage cara/crystal malts |
|
75 svg = 77, // Default attenuation |
|
76 mashkg = 0, // Malt in mash weight |
|
77 initcells = 0, // Initial yeast cell count |
|
78 |
|
79 ok_fermentables = 1, // Fermentables are in stock |
|
80 ok_hops = 1, // Hops are in stock |
|
81 ok_miscs = 1, // Miscs are in stock |
|
82 ok_yeasts = 1, // Yeasts are in stock |
|
83 ok_waters = 1, // Waters are in stock |
|
84 |
|
85 data_loaded = 0; |
|
86 error_count = 0; |
|
87 k_cm = 0; |
|
88 k_vol = 0; |
|
89 k_what = 0; |
|
90 |
|
91 hop_flavour = 0, |
|
92 hop_aroma = 0, |
|
93 mash_infuse = 0, |
|
94 last_acid = '', |
|
95 |
|
96 MMCa = 40.048, |
|
97 MMMg = 24.305, |
|
98 MMNa = 22.98976928, |
|
99 MMCl = 35.453, |
|
100 MMSO4 = 96.0626, |
|
101 MMHCO3 = 61.01684, |
|
102 MMCaSO4 = 172.171, |
|
103 MMCaCl2 = 147.015, |
|
104 MMCaCO3 = 100.087, |
|
105 MMMgCl2 = 95.211, /* Since 27-06-2021 */ |
|
106 MMMgSO4 = 246.475, |
|
107 MMNaHCO3 = 84.007, |
|
108 MMNa2CO3 = 105.996, |
|
109 MMNaCl = 58.443, |
|
110 MMCaOH2 = 74.06268, |
|
111 |
|
112 fermentableRow = 0, |
|
113 fermentableData = {}, |
|
114 fermentableInit = 1, |
|
115 hopRow = 0, |
|
116 hopData = {}, |
|
117 miscRow = 0, |
|
118 miscData = {}, |
|
119 yeastRow = 0, |
|
120 yeastData = {}, |
|
121 mashRow = 0, |
|
122 mashData = {}, |
|
123 Ka1 = 0.0000004445, |
|
124 Ka2 = 0.0000000000468, |
|
125 dataRecord = {}, |
|
126 url = 'includes/db_product.php', |
|
127 MaltVolume = 0.87, // l/kg 0.688 volgens internetbronnen, gemeten 0.874 l/kg, na enige tijd maischen 0,715 l/kg (A3 Otten). |
|
128 SpecificHeatWater = 1.0, |
|
129 SpecificHeatMalt = 0.399, //cal/g.°C |
|
130 SlakingHeat = 10.318, //cal/g.°C |
|
131 |
|
132 // Prepare the data |
|
133 source = { |
|
134 datatype: 'json', |
|
135 cache: false, |
|
136 async: true, |
|
137 datafields: [ |
|
138 // From prod_main |
|
139 { name: 'record', type: 'number' }, |
|
140 { name: 'uuid', type: 'string' }, |
|
141 { name: 'name', type: 'string' }, |
|
142 { name: 'code', type: 'string' }, |
|
143 { name: 'birth', type: 'string' }, |
|
144 { name: 'stage', type: 'int' }, |
|
145 { name: 'notes', type: 'string' }, |
|
146 { name: 'log_brew', type: 'int' }, |
|
147 { name: 'log_fermentation', type: 'int' }, |
|
148 { name: 'log_ispindel', type: 'int' }, |
|
149 { name: 'log_co2pressure', type: 'int' }, |
|
150 { name: 'inventory_reduced', type: 'int' }, |
|
151 { name: 'locked', type: 'int' }, |
|
152 { name: 'eq_name', type: 'string' }, |
|
153 { name: 'eq_boil_size', type: 'float' }, |
|
154 { name: 'eq_batch_size', type: 'float' }, |
|
155 { name: 'eq_tun_volume', type: 'float' }, |
|
156 { name: 'eq_tun_weight', type: 'float' }, |
|
157 { name: 'eq_tun_specific_heat', type: 'float' }, |
|
158 { name: 'eq_tun_material', type: 'int' }, |
|
159 { name: 'eq_tun_height', type: 'float' }, |
|
160 { name: 'eq_top_up_water', type: 'float' }, |
|
161 { name: 'eq_trub_chiller_loss', type: 'float' }, |
|
162 { name: 'eq_evap_rate', type: 'float' }, |
|
163 { name: 'eq_boil_time', type: 'float' }, |
|
164 { name: 'eq_calc_boil_volume', type: 'int' }, |
|
165 { name: 'eq_top_up_kettle', type: 'float' }, |
|
166 { name: 'eq_hop_utilization', type: 'float' }, |
|
167 { name: 'eq_notes', type: 'string' }, |
|
168 { name: 'eq_lauter_volume', type: 'float' }, |
|
169 { name: 'eq_lauter_height', type: 'float' }, |
|
170 { name: 'eq_lauter_deadspace', type: 'float' }, |
|
171 { name: 'eq_kettle_volume', type: 'float' }, |
|
172 { name: 'eq_kettle_height', type: 'float' }, |
|
173 { name: 'eq_mash_volume', type: 'float' }, |
|
174 { name: 'eq_mash_max', type: 'float' }, |
|
175 { name: 'eq_efficiency', type: 'float' }, |
|
176 { name: 'brew_date_start', type: 'string' }, |
|
177 { name: 'brew_mash_ph', type: 'float' }, |
|
178 { name: 'brew_mash_sg', type: 'float' }, |
|
179 { name: 'brew_mash_efficiency', type: 'float' }, |
|
180 { name: 'brew_sparge_est', type: 'float' }, |
|
181 { name: 'brew_sparge_ph', type: 'float' }, |
|
182 { name: 'brew_preboil_volume', type: 'float' }, |
|
183 { name: 'brew_preboil_sg', type: 'float' }, |
|
184 { name: 'brew_preboil_ph', type: 'float' }, |
|
185 { name: 'brew_preboil_efficiency', type: 'float' }, |
|
186 { name: 'brew_aboil_volume', type: 'float' }, |
|
187 { name: 'brew_aboil_sg', type: 'float' }, |
|
188 { name: 'brew_aboil_ph', type: 'float' }, |
|
189 { name: 'brew_aboil_efficiency', type: 'float' }, |
|
190 { name: 'brew_cooling_method', type: 'int' }, |
|
191 { name: 'brew_cooling_time', type: 'float' }, |
|
192 { name: 'brew_cooling_to', type: 'float' }, |
|
193 { name: 'brew_whirlpool9', type: 'float' }, |
|
194 { name: 'brew_whirlpool7', type: 'float' }, |
|
195 { name: 'brew_whirlpool6', type: 'float' }, |
|
196 { name: 'brew_whirlpool2', type: 'float' }, |
|
197 { name: 'brew_fermenter_volume', type: 'float' }, |
|
198 { name: 'brew_fermenter_extrawater', type: 'float' }, |
|
199 { name: 'brew_fermenter_tcloss', type: 'float' }, |
|
200 { name: 'brew_aeration_time', type: 'float' }, |
|
201 { name: 'brew_aeration_speed', type: 'float' }, |
|
202 { name: 'brew_aeration_type', type: 'int' }, |
|
203 { name: 'brew_fermenter_sg', type: 'float' }, |
|
204 { name: 'brew_fermenter_ibu', type: 'float' }, |
|
205 { name: 'brew_fermenter_color', type: 'float' }, |
|
206 { name: 'brew_date_end', type: 'string' }, |
|
207 { name: 'og', type: 'float' }, |
|
208 { name: 'fg', type: 'float' }, |
|
209 { name: 'primary_start_temp', type: 'float' }, |
|
210 { name: 'primary_max_temp', type: 'float' }, |
|
211 { name: 'primary_end_temp', type: 'float' }, |
|
212 { name: 'primary_end_sg', type: 'float' }, |
|
213 { name: 'primary_end_date', type: 'string' }, |
|
214 { name: 'secondary_temp', type: 'float' }, |
|
215 { name: 'secondary_end_sg', type: 'float' }, |
|
216 { name: 'secondary_end_date', type: 'string' }, |
|
217 { name: 'tertiary_temp', type: 'float' }, |
|
218 { name: 'package_date', type: 'string' }, |
|
219 { name: 'package_volume', type: 'float' }, |
|
220 { name: 'package_infuse_amount', type: 'float' }, |
|
221 { name: 'package_infuse_abv', type: 'float' }, |
|
222 { name: 'package_infuse_notes', type: 'string' }, |
|
223 { name: 'package_abv', type: 'float' }, |
|
224 { name: 'package_ph', type: 'float' }, |
|
225 { name: 'bottle_amount', type: 'float' }, |
|
226 { name: 'bottle_carbonation', type: 'float' }, |
|
227 { name: 'bottle_priming_water', type: 'float' }, |
|
228 { name: 'bottle_priming_amount', type: 'float' }, |
|
229 { name: 'bottle_carbonation_temp', type: 'float' }, |
|
230 { name: 'keg_amount', type: 'float' }, |
|
231 { name: 'keg_carbonation', type: 'float' }, |
|
232 { name: 'keg_priming_water', type: 'float' }, |
|
233 { name: 'keg_priming_amount', type: 'float' }, |
|
234 { name: 'keg_carbonation_temp', type: 'float' }, |
|
235 { name: 'keg_forced_carb', type: 'int' }, |
|
236 { name: 'keg_pressure', type: 'float' }, |
|
237 { name: 'taste_notes', type: 'string' }, |
|
238 { name: 'taste_rate', type: 'float' }, |
|
239 { name: 'taste_date', type: 'string' }, |
|
240 { name: 'taste_color', type: 'string' }, |
|
241 { name: 'taste_transparency', type: 'string' }, |
|
242 { name: 'taste_head', type: 'string' }, |
|
243 { name: 'taste_aroma', type: 'string' }, |
|
244 { name: 'taste_taste', type: 'string' }, |
|
245 { name: 'taste_mouthfeel', type: 'string' }, |
|
246 { name: 'taste_aftertaste', type: 'string' }, |
|
247 { name: 'st_name', type: 'string' }, |
|
248 { name: 'st_letter', type: 'string' }, |
|
249 { name: 'st_guide', type: 'string' }, |
|
250 { name: 'st_category', type: 'string' }, |
|
251 { name: 'st_category_number', type: 'int' }, |
|
252 { name: 'st_type', type: 'int' }, |
|
253 { name: 'st_og_min', type: 'float' }, |
|
254 { name: 'st_og_max', type: 'float' }, |
|
255 { name: 'st_fg_min', type: 'float' }, |
|
256 { name: 'st_fg_max', type: 'float' }, |
|
257 { name: 'st_ibu_min', type: 'float' }, |
|
258 { name: 'st_ibu_max', type: 'float' }, |
|
259 { name: 'st_color_min', type: 'float' }, |
|
260 { name: 'st_color_max', type: 'float' }, |
|
261 { name: 'st_carb_min', type: 'float' }, |
|
262 { name: 'st_carb_max', type: 'float' }, |
|
263 { name: 'st_abv_min', type: 'float' }, |
|
264 { name: 'st_abv_max', type: 'float' }, |
|
265 { name: 'type', type: 'int' }, |
|
266 { name: 'batch_size', type: 'float' }, |
|
267 { name: 'boil_size', type: 'float' }, |
|
268 { name: 'boil_time', type: 'float' }, |
|
269 { name: 'efficiency', type: 'float' }, |
|
270 { name: 'est_og', type: 'float' }, |
|
271 { name: 'est_og3', type: 'float' }, |
|
272 { name: 'est_fg', type: 'float' }, |
|
273 { name: 'est_abv', type: 'float' }, |
|
274 { name: 'est_color', type: 'float' }, |
|
275 { name: 'color_method', type: 'int' }, |
|
276 { name: 'est_ibu', type: 'float' }, |
|
277 { name: 'ibu_method', type: 'int' }, |
|
278 { name: 'est_carb', type: 'float' }, |
|
279 { name: 'sparge_temp', type: 'float' }, |
|
280 { name: 'sparge_ph', type: 'float' }, |
|
281 { name: 'sparge_volume', type: 'float' }, |
|
282 { name: 'sparge_source', type: 'int' }, |
|
283 { name: 'sparge_acid_type', type: 'int' }, |
|
284 { name: 'sparge_acid_perc', type: 'float' }, |
|
285 { name: 'sparge_acid_amount', type: 'float' }, |
|
286 { name: 'mash_ph', type: 'float' }, |
|
287 { name: 'mash_name', type: 'string' }, |
|
288 { name: 'calc_acid', type: 'int' }, |
|
289 { name: 'w1_name', type: 'string' }, |
|
290 { name: 'w1_amount', type: 'float' }, |
|
291 { name: 'w1_calcium', type: 'float' }, |
|
292 { name: 'w1_sulfate', type: 'float' }, |
|
293 { name: 'w1_chloride', type: 'float' }, |
|
294 { name: 'w1_sodium', type: 'float' }, |
|
295 { name: 'w1_magnesium', type: 'float' }, |
|
296 { name: 'w1_total_alkalinity', type: 'float' }, |
|
297 { name: 'w1_ph', type: 'float' }, |
|
298 { name: 'w1_cost', type: 'float' }, |
|
299 { name: 'w2_name', type: 'string' }, |
|
300 { name: 'w2_amount', type: 'float' }, |
|
301 { name: 'w2_calcium', type: 'float' }, |
|
302 { name: 'w2_sulfate', type: 'float' }, |
|
303 { name: 'w2_chloride', type: 'float' }, |
|
304 { name: 'w2_sodium', type: 'float' }, |
|
305 { name: 'w2_magnesium', type: 'float' }, |
|
306 { name: 'w2_total_alkalinity', type: 'float' }, |
|
307 { name: 'w2_ph', type: 'float' }, |
|
308 { name: 'w2_cost', type: 'float' }, |
|
309 { name: 'wg_amount', type: 'float' }, |
|
310 { name: 'wg_calcium', type: 'float' }, |
|
311 { name: 'wg_sulfate', type: 'float' }, |
|
312 { name: 'wg_chloride', type: 'float' }, |
|
313 { name: 'wg_sodium', type: 'float' }, |
|
314 { name: 'wg_magnesium', type: 'float' }, |
|
315 { name: 'wg_total_alkalinity', type: 'float' }, |
|
316 { name: 'wg_ph', type: 'float' }, |
|
317 { name: 'wb_calcium', type: 'float' }, |
|
318 { name: 'wb_sulfate', type: 'float' }, |
|
319 { name: 'wb_chloride', type: 'float' }, |
|
320 { name: 'wb_sodium', type: 'float' }, |
|
321 { name: 'wb_magnesium', type: 'float' }, |
|
322 { name: 'wb_total_alkalinity', type: 'float' }, |
|
323 { name: 'wb_ph', type: 'float' }, |
|
324 { name: 'wa_acid_name', type: 'int' }, |
|
325 { name: 'wa_acid_perc', type: 'int' }, |
|
326 { name: 'wa_base_name', type: 'int' }, |
|
327 { name: 'starter_enable', type: 'int' }, |
|
328 { name: 'starter_type', type: 'int' }, |
|
329 { name: 'starter_sg', type: 'float' }, |
|
330 { name: 'starter_viability', type: 'int' }, |
|
331 { name: 'yeast_prod_date', type: 'string' }, |
|
332 { name: 'yeast_pitchrate', type: 'float' }, |
|
333 { name: 'prop1_type', type: 'int' }, |
|
334 { name: 'prop1_volume', type: 'float' }, |
|
335 { name: 'prop2_type', type: 'int' }, |
|
336 { name: 'prop2_volume', type: 'float' }, |
|
337 { name: 'prop3_type', type: 'int' }, |
|
338 { name: 'prop3_volume', type: 'float' }, |
|
339 { name: 'prop4_type', type: 'int' }, |
|
340 { name: 'prop4_volume', type: 'float' }, |
|
341 { name: 'divide_type', type: 'int' }, |
|
342 { name: 'divide_size', type: 'float' }, |
|
343 { name: 'divide_factor', type: 'float' }, |
|
344 { name: 'divide_parts', type: 'int' }, |
|
345 { name: 'divide_part', type: 'int' }, |
|
346 { name: 'fermentables', type: 'string' }, |
|
347 { name: 'hops', type: 'string' }, |
|
348 { name: 'miscs', type: 'string' }, |
|
349 { name: 'yeasts', type: 'string' }, |
|
350 { name: 'mashs', type: 'string' } |
|
351 ], |
|
352 id: 'record', |
|
353 url: url + '?record=' + my_record |
|
354 }, |
|
355 |
|
356 // Load data and select one record. |
|
357 dataAdapter = new $.jqx.dataAdapter(source, { |
|
358 loadComplete: function() { |
|
359 dataRecord = dataAdapter.records[0]; |
|
360 // Hidden record uuid |
|
361 $('#name').val(dataRecord.name); |
|
362 $('#code').val(dataRecord.code); |
|
363 $('#birth').val(dataRecord.birth); |
|
364 $('#stage').val(StageData[dataRecord.stage].nl); |
|
365 $('#notes').val(dataRecord.notes); |
|
366 $('#locked').val(dataRecord.locked); |
|
367 $('#eq_name').val(dataRecord.eq_name); |
|
368 $('#eq_notes').val(dataRecord.eq_notes); |
|
369 $('#eq_boil_size').val(dataRecord.eq_boil_size); |
|
370 $('#eq_batch_size').val(dataRecord.eq_batch_size); |
|
371 $('#eq_tun_volume').val(dataRecord.eq_tun_volume); |
|
372 $('#eq_top_up_water').val(dataRecord.eq_top_up_water); |
|
373 $('#eq_trub_chiller_loss').val(dataRecord.eq_trub_chiller_loss); |
|
374 $('#eq_evap_rate').val(dataRecord.eq_evap_rate); |
|
375 $('#eq_boil_time').val(dataRecord.eq_boil_time); |
|
376 $('#eq_top_up_kettle').val(dataRecord.eq_top_up_kettle); |
|
377 $('#eq_hop_utilization').val(dataRecord.eq_hop_utilization); |
|
378 $('#eq_lauter_volume').val(dataRecord.eq_lauter_volume); |
|
379 $('#eq_lauter_deadspace').val(dataRecord.eq_lauter_deadspace); |
|
380 $('#eq_kettle_volume').val(dataRecord.eq_kettle_volume); |
|
381 $('#eq_mash_volume').val(dataRecord.eq_mash_volume); |
|
382 $('#eq_mash_max').val(dataRecord.eq_mash_max); |
|
383 $('#eq_efficiency').val(dataRecord.eq_efficiency); |
|
384 // Brewdate |
|
385 $('#brew_date_start').val(dataRecord.brew_date_start); |
|
386 $('#brew_mash_ph').val(dataRecord.brew_mash_ph); |
|
387 $('#brew_mash_sg').val(dataRecord.brew_mash_sg); |
|
388 $('#brew_mash_efficiency').val(dataRecord.brew_mash_efficiency); |
|
389 // Header Spoelen en filteren |
|
390 $('#brew_sparge_temperature').val(dataRecord.sparge_temp); |
|
391 $('#brew_sparge_volume').val(dataRecord.sparge_volume); |
|
392 $('#brew_sparge_est').val(dataRecord.brew_sparge_est); |
|
393 $('#brew_sparge_ph').val(dataRecord.brew_sparge_ph); |
|
394 // Header Beluchten |
|
395 $('#brew_aeration_type').val(AerationTypeData[dataRecord.brew_aeration_type].nl); |
|
396 $('#brew_aeration_time').val(dataRecord.brew_aeration_time); |
|
397 $('#brew_aeration_speed').val(dataRecord.brew_aeration_speed); |
|
398 |
|
399 $('#brew_preboil_ph').val(dataRecord.brew_preboil_ph); |
|
400 $('#brew_preboil_sg').val(dataRecord.brew_preboil_sg); |
|
401 $('#brew_preboil_volume').val(dataRecord.brew_preboil_volume); |
|
402 $('#brew_preboil_efficiency').val(dataRecord.brew_preboil_efficiency); |
|
403 // Header Koelen en whirlpoolen |
|
404 $('#brew_whirlpool9').val(dataRecord.brew_whirlpool9); |
|
405 $('#brew_whirlpool7').val(dataRecord.brew_whirlpool7); |
|
406 $('#brew_whirlpool6').val(dataRecord.brew_whirlpool6); |
|
407 $('#brew_whirlpool2').val(dataRecord.brew_whirlpool2); |
|
408 // Header Naar gistvat |
|
409 $('#brew_fermenter_volume').val(dataRecord.brew_fermenter_volume); |
|
410 $('#brew_fermenter_sg').val(dataRecord.brew_fermenter_sg); |
|
411 $('#brew_fermenter_sg2').val(dataRecord.brew_fermenter_sg); |
|
412 $('#brew_fermenter_ibu').val(dataRecord.brew_fermenter_ibu); |
|
413 $('#brew_fermenter_color').val(dataRecord.brew_fermenter_color); |
|
414 $('#brew_fermenter_extrawater').val(dataRecord.brew_fermenter_extrawater); |
|
415 $('#brew_fermenter_tcloss').val(dataRecord.brew_fermenter_tcloss); |
|
416 |
|
417 $('#brew_aboil_ph').val(dataRecord.brew_aboil_ph); |
|
418 $('#brew_aboil_sg').val(dataRecord.brew_aboil_sg); |
|
419 $('#brew_aboil_volume').val(dataRecord.brew_aboil_volume); |
|
420 $('#brew_aboil_efficiency').val(dataRecord.brew_aboil_efficiency); |
|
421 // Header Koelen en whirlpoolen |
|
422 $('#brew_cooling_to').val(dataRecord.brew_cooling_to); |
|
423 $('#brew_cooling_method').val(CoolingTypeData[dataRecord.brew_cooling_method].nl); |
|
424 $('#brew_cooling_time').val(dataRecord.brew_cooling_time); |
|
425 // Niks |
|
426 $('#brew_date_end').val(dataRecord.brew_date_end); |
|
427 $('#og').val(dataRecord.og); |
|
428 $('#fg').val(dataRecord.fg); |
|
429 $('#primary_start_temp').val(dataRecord.primary_start_temp); |
|
430 $('#primary_max_temp').val(dataRecord.primary_max_temp); |
|
431 $('#primary_end_temp').val(dataRecord.primary_end_temp); |
|
432 $('#primary_end_sg').val(dataRecord.primary_end_sg); |
|
433 $('#primary_end_date').val(dataRecord.primary_end_date); |
|
434 $('#secondary_temp').val(dataRecord.secondary_temp); |
|
435 $('#secondary_end_sg').val(dataRecord.secondary_end_sg); |
|
436 $('#secondary_end_date').val(dataRecord.secondary_end_date); |
|
437 $('#tertiary_temp').val(dataRecord.tertiary_temp); |
|
438 $('#package_date').val(dataRecord.package_date); |
|
439 $('#package_volume').val(dataRecord.package_volume); |
|
440 $('#package_infuse_amount').val(dataRecord.package_infuse_amount); |
|
441 $('#package_infuse_abv').val(dataRecord.package_infuse_abv); |
|
442 $('#package_infuse_notes').val(dataRecord.package_infuse_notes); |
|
443 $('#package_abv').val(dataRecord.package_abv); |
|
444 $('#package_ph').val(dataRecord.package_ph); |
|
445 $('#bottle_amount').val(dataRecord.bottle_amount); |
|
446 $('#bottle_carbonation').val(dataRecord.bottle_carbonation); |
|
447 $('#bottle_priming_water').val(dataRecord.bottle_priming_water); |
|
448 $('#bottle_priming_amount').val(dataRecord.bottle_priming_amount); |
|
449 $('#bottle_carbonation_temp').val(dataRecord.bottle_carbonation_temp); |
|
450 $('#keg_amount').val(dataRecord.keg_amount); |
|
451 $('#keg_carbonation').val(dataRecord.keg_carbonation); |
|
452 $('#keg_priming_water').val(dataRecord.keg_priming_water); |
|
453 $('#keg_priming_amount').val(dataRecord.keg_priming_amount); |
|
454 $('#keg_carbonation_temp').val(dataRecord.keg_carbonation_temp); |
|
455 $('#keg_forced_carb').val(dataRecord.keg_forced_carb); |
|
456 $('#keg_pressure').val(dataRecord.keg_pressure); |
|
457 $('#taste_notes').val(dataRecord.taste_notes); |
|
458 $('#taste_rate').val(dataRecord.taste_rate); |
|
459 $('#taste_date').val(dataRecord.taste_date); |
|
460 $('#taste_color').val(dataRecord.taste_color); |
|
461 $('#taste_transparency').val(dataRecord.taste_transparency); |
|
462 $('#taste_head').val(dataRecord.taste_head); |
|
463 $('#taste_aroma').val(dataRecord.taste_aroma); |
|
464 $('#taste_taste').val(dataRecord.taste_taste); |
|
465 $('#taste_mouthfeel').val(dataRecord.taste_mouthfeel); |
|
466 $('#taste_aftertaste').val(dataRecord.taste_aftertaste); |
|
467 |
|
468 // Recipe |
|
469 $('#st_name').val(dataRecord.st_name); |
|
470 $('#st_letter').val(dataRecord.st_letter); |
|
471 $('#st_guide').val(dataRecord.st_guide); |
|
472 $('#st_category').val(dataRecord.st_category); |
|
473 $('#st_category_number').val(dataRecord.st_category_number); |
|
474 $('#st_type').val(StyleTypeData[dataRecord.st_type].nl); |
|
475 $('#st_og_min').val(dataRecord.st_og_min); |
|
476 $('#st_og_max').val(dataRecord.st_og_max); |
|
477 $('#st_fg_min').val(dataRecord.st_fg_min); |
|
478 $('#st_fg_max').val(dataRecord.st_fg_max); |
|
479 $('#st_abv_min').val(dataRecord.st_abv_min); |
|
480 $('#st_abv_max').val(dataRecord.st_abv_max); |
|
481 $('#st_color_min').val(dataRecord.st_color_min); |
|
482 $('#st_color_max').val(dataRecord.st_color_max); |
|
483 $('#st_ibu_min').val(dataRecord.st_ibu_min); |
|
484 $('#st_ibu_max').val(dataRecord.st_ibu_max); |
|
485 $('#st_carb_min').val(dataRecord.st_carb_min); |
|
486 $('#st_carb_min2').val(dataRecord.st_carb_min); |
|
487 $('#st_carb_max').val(dataRecord.st_carb_max); |
|
488 $('#st_carb_max2').val(dataRecord.st_carb_max); |
|
489 $('#type').val(RecipeTypeData[dataRecord.type].nl); |
|
490 $('#batch_size').val(dataRecord.batch_size); |
|
491 $('#est_a_vol').val(dataRecord.batch_size * 1.04); |
|
492 $('#boil_size').val(dataRecord.boil_size); |
|
493 $('#est_pre_vol').val(dataRecord.boil_size * 1.04); |
|
494 $('#boil_time').val(dataRecord.boil_time); |
|
495 $('#efficiency').val(dataRecord.efficiency); |
|
496 $('#est_og').val(dataRecord.est_og); |
|
497 $('#est_og2').val(dataRecord.est_og); |
|
498 $('#est_og3').val(dataRecord.est_og3); |
|
499 $('#est_fg').val(dataRecord.est_fg); |
|
500 $('#est_fg2').val(dataRecord.est_fg); |
|
501 $('#est_fg3').val(dataRecord.est_fg); |
|
502 $('#est_color').val(dataRecord.est_color); |
|
503 $('#est_color2').val(dataRecord.est_color); |
|
504 $('#est_abv').val(dataRecord.est_abv); |
|
505 $('#color_method').val(ColorMethodData[dataRecord.color_method].nl); |
|
506 $('#est_ibu').val(dataRecord.est_ibu); |
|
507 $('#est_ibu2').val(dataRecord.est_ibu); |
|
508 $('#ibu_method').val(IBUmethodData[dataRecord.ibu_method].nl); |
|
509 $('#est_carb').val(dataRecord.est_carb); |
|
510 $('#mash_name').val(dataRecord.mash_name); |
|
511 $('#mash_ph').val(dataRecord.mash_ph); |
|
512 $('#sparge_temp').val(dataRecord.sparge_temp); |
|
513 $('#sparge_ph').val(dataRecord.sparge_ph); |
|
514 $('#sparge_volume').val(dataRecord.sparge_volume); |
|
515 $('#sparge_source').val(dataRecord.sparge_source); |
|
516 $('#sparge_acid_type').val(AcidTypeData[dataRecord.sparge_acid_type].nl); |
|
517 $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); |
|
518 $('#sparge_acid_amount').val(dataRecord.sparge_acid_amount * 1000); |
|
519 $('#calc_acid').val(dataRecord.calc_acid); |
|
520 $('#w1_name').val(dataRecord.w1_name); |
|
521 $('#w1_amount').val(dataRecord.w1_amount); |
|
522 $('#w1_calcium').val(dataRecord.w1_calcium); |
|
523 $('#w1_sulfate').val(dataRecord.w1_sulfate); |
|
524 $('#w1_chloride').val(dataRecord.w1_chloride); |
|
525 $('#w1_sodium').val(dataRecord.w1_sodium); |
|
526 $('#w1_magnesium').val(dataRecord.w1_magnesium); |
|
527 $('#w1_total_alkalinity').val(dataRecord.w1_total_alkalinity); |
|
528 $('#w1_bicarbonate').val(dataRecord.w1_total_alkalinity * 1.22); |
|
529 $('#w1_ph').val(dataRecord.w1_ph); |
|
530 $('#w1_cost').val(dataRecord.w1_cost); |
|
531 $('#w2_name').val(dataRecord.w2_name); |
|
532 $('#w2_amount').val(dataRecord.w2_amount); |
|
533 $('#w2_calcium').val(dataRecord.w2_calcium); |
|
534 $('#w2_sulfate').val(dataRecord.w2_sulfate); |
|
535 $('#w2_chloride').val(dataRecord.w2_chloride); |
|
536 $('#w2_sodium').val(dataRecord.w2_sodium); |
|
537 $('#w2_magnesium').val(dataRecord.w2_magnesium); |
|
538 $('#w2_total_alkalinity').val(dataRecord.w2_total_alkalinity); |
|
539 $('#w2_bicarbonate').val(dataRecord.w2_total_alkalinity * 1.22); |
|
540 $('#w2_ph').val(dataRecord.w2_ph); |
|
541 $('#w2_cost').val(dataRecord.w2_cost); |
|
542 $('#wg_amount').val(dataRecord.wg_amount); |
|
543 $('#wg_calcium').val(dataRecord.wg_calcium); |
|
544 $('#wg_sulfate').val(dataRecord.wg_sulfate); |
|
545 $('#wg_chloride').val(dataRecord.wg_chloride); |
|
546 $('#wg_sodium').val(dataRecord.wg_sodium); |
|
547 $('#wg_magnesium').val(dataRecord.wg_magnesium); |
|
548 $('#wg_total_alkalinity').val(dataRecord.wg_total_alkalinity); |
|
549 $('#wg_ph').val(dataRecord.wg_ph); |
|
550 $('#wb_calcium').val(dataRecord.wb_calcium); |
|
551 $('#wb_sulfate').val(dataRecord.wb_sulfate); |
|
552 $('#wb_chloride').val(dataRecord.wb_chloride); |
|
553 $('#wb_sodium').val(dataRecord.wb_sodium); |
|
554 $('#wb_magnesium').val(dataRecord.wb_magnesium); |
|
555 $('#wb_total_alkalinity').val(dataRecord.wb_total_alkalinity); |
|
556 $('#wb_ph').val(dataRecord.wb_ph); |
|
557 $('#wa_acid_name').val(dataRecord.wa_acid_name); |
|
558 $('#wa_acid_perc').val(dataRecord.wa_acid_perc); |
|
559 $('#starter_type').val(StarterTypeData[dataRecord.starter_type].nl); |
|
560 $('#starter_sg').val(dataRecord.starter_sg); |
|
561 $('#starter_viability').val(dataRecord.starter_viability); |
|
562 $('#yeast_prod_date').val(dataRecord.yeast_prod_date); |
|
563 $('#yeast_pitchrate').val(dataRecord.yeast_pitchrate); |
|
564 $('#prop1_type').val(StarterTypeData[dataRecord.prop1_type].nl); |
|
565 $('#prop1_volume').val(dataRecord.prop1_volume); |
|
566 $('#prop2_type').val(StarterTypeData[dataRecord.prop2_type].nl); |
|
567 $('#prop2_volume').val(dataRecord.prop2_volume); |
|
568 $('#prop3_type').val(StarterTypeData[dataRecord.prop3_type].nl); |
|
569 $('#prop3_volume').val(dataRecord.prop3_volume); |
|
570 $('#prop4_type').val(StarterTypeData[dataRecord.prop4_type].nl); |
|
571 $('#prop4_volume').val(dataRecord.prop4_volume); |
|
572 $('#divide_type').val(SplitData[dataRecord.divide_type].nl); |
|
573 if (dataRecord.divide_type > 0) |
|
574 $('#divide_batch').val((dataRecord.divide_part + 1) + ' van ' + (dataRecord.divide_parts + 1)); |
|
575 else |
|
576 $('#divide_batch').val('n.v.t.'); |
|
577 // hidden divide_size |
|
578 // hidden divide_factor |
|
579 // hidden divide_parts |
|
580 // hidden divide_part |
|
581 editFermentable(dataRecord); |
|
582 editHop(dataRecord); |
|
583 editMisc(dataRecord); |
|
584 editYeast(dataRecord); |
|
585 editMash(dataRecord); |
|
586 calcStage(); |
|
587 $('#jqxTabs').jqxTabs('select', 2); |
|
588 data_loaded = 1; |
|
589 }, |
|
590 loadError: function(jqXHR, status, error) { |
|
591 console.log('main data load error: ' + status + ' ' + error); |
|
592 } |
|
593 }); |
|
594 |
|
595 // Inline fermentables editor |
|
596 var editFermentable = function(data) { |
|
597 var fermentableSource = { |
|
598 localdata: data.fermentables, |
|
599 datafields: [ |
|
600 { name: 'f_name', type: 'string' }, |
|
601 { name: 'f_origin', type: 'string' }, |
|
602 { name: 'f_supplier', type: 'string' }, |
|
603 { name: 'f_amount', type: 'float' }, |
|
604 { name: 'f_cost', type: 'float' }, |
|
605 { name: 'f_type', type: 'int' }, |
|
606 { name: 'f_yield', type: 'float' }, |
|
607 { name: 'f_color', type: 'float' }, |
|
608 { name: 'f_coarse_fine_diff', type: 'float' }, |
|
609 { name: 'f_moisture', type: 'float' }, |
|
610 { name: 'f_diastatic_power', type: 'float' }, |
|
611 { name: 'f_protein', type: 'float' }, |
|
612 { name: 'f_max_in_batch', type: 'float' }, |
|
613 { name: 'f_graintype', type: 'int' }, |
|
614 { name: 'f_added', type: 'int' }, |
|
615 { name: 'f_dissolved_protein', type: 'float' }, |
|
616 { name: 'f_recommend_mash', type: 'int' }, |
|
617 { name: 'f_add_after_boil', type: 'int' }, |
|
618 { name: 'f_adjust_to_total_100', type: 'int' }, |
|
619 { name: 'f_percentage', type: 'float' }, |
|
620 { name: 'f_di_ph', type: 'float' }, |
|
621 { name: 'f_acid_to_ph_57', type: 'float' }, |
|
622 { name: 'f_inventory', type: 'float' }, |
|
623 { name: 'f_avail', type: 'int' } |
|
624 ], |
|
625 }, |
|
626 fermentableAdapter = new $.jqx.dataAdapter(fermentableSource); |
|
627 |
|
628 $('#fermentableGrid').jqxGrid({ |
|
629 width: 1240, |
|
630 height: 470, |
|
631 source: fermentableAdapter, |
|
632 theme: theme, |
|
633 editable: false, |
|
634 ready: function() { calcFermentables(); $('#jqxTabs').jqxTabs('next'); }, |
|
635 columns: [ |
|
636 { text: 'Vergistbaar ingrediënt', datafield: 'f_name' }, |
|
637 { text: 'Leverancier', datafield: 'f_supplier', width: 180 }, |
|
638 { text: 'Kleur', datafield: 'f_color', width: 90, align: 'right', |
|
639 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
640 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value, 'f0') + ' EBC</span>'; |
|
641 } |
|
642 }, |
|
643 { text: 'Type', width: 100, datafield: 'f_type', |
|
644 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
645 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + FermentableTypeData[value].nl + '</span>'; |
|
646 } |
|
647 }, |
|
648 { text: 'Moment', width: 110, datafield: 'f_added', |
|
649 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
650 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + AddedData[value].nl + '</span>'; |
|
651 } |
|
652 }, |
|
653 { text: 'Maxinbatch', datafield: 'f_max_in_batch', hidden: true }, |
|
654 { text: 'Opbrengst', datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, |
|
655 { text: 'Gewicht Kg', datafield: 'f_amount', width: 110, align: 'right', cellsalign: 'right', cellsformat: 'f3' }, |
|
656 { text: 'Voorraad Kg', datafield: 'f_inventory', width: 110, align: 'right', |
|
657 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { |
|
658 var color = (value < rowdata.f_amount) ? '#ff4040':'#ffffff'; |
|
659 if (block_fermentable(dataRecord.inventory_reduced, rowdata.f_added) == false) { |
|
660 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + fermentableAdapter.formatNumber(value, 'f3') + '</span>'; |
|
661 } else { |
|
662 return '<span></span>'; |
|
663 } |
|
664 } |
|
665 }, |
|
666 { text: 'Procent', datafield: 'f_percentage', width: 90, align: 'right', |
|
667 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { |
|
668 if (rowdata.f_added >= 4) |
|
669 return '<span></span>'; |
|
670 var color = (value > rowdata.f_max_in_batch) ? '#ff4040':'#ffffff'; |
|
671 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + fermentableAdapter.formatNumber(value, 'p1') + '</span>'; |
|
672 } |
|
673 }, |
|
674 { text: '100%', datafield: 'f_adjust_to_total_100', width: 70, align: 'center', cellsalign: 'center', |
|
675 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
676 if (value == 0) |
|
677 return '<span></span>'; |
|
678 return '<span><img style="float:left; margin-left:25px; margin-top:4px;" src="images/dialog-ok-apply.png"></span>'; |
|
679 } |
|
680 } |
|
681 ] |
|
682 }); |
|
683 }; |
|
684 |
|
685 // Inline hops editor |
|
686 var editHop = function(data) { |
|
687 var hopSource = { |
|
688 localdata: data.hops, |
|
689 datafields: [ |
|
690 { name: 'h_name', type: 'string' }, |
|
691 { name: 'h_origin', type: 'string' }, |
|
692 { name: 'h_amount', type: 'float' }, |
|
693 { name: 'h_cost', type: 'float' }, |
|
694 { name: 'h_type', type: 'int' }, |
|
695 { name: 'h_form', type: 'int' }, |
|
696 { name: 'h_useat', type: 'int' }, |
|
697 { name: 'h_time', type: 'int' }, |
|
698 { name: 'h_alpha', type: 'float' }, |
|
699 { name: 'h_beta', type: 'float' }, |
|
700 { name: 'h_hsi', type: 'float' }, |
|
701 { name: 'h_humulene', type: 'float' }, |
|
702 { name: 'h_caryophyllene', type: 'float' }, |
|
703 { name: 'h_cohumulone', type: 'float' }, |
|
704 { name: 'h_myrcene', type: 'float' }, |
|
705 { name: 'h_total_oil', type: 'float' }, |
|
706 { name: 'h_inventory', type: 'float' }, |
|
707 { name: 'h_avail', type: 'int' }, |
|
708 { name: 'h_utilisation', type: 'float' }, |
|
709 { name: 'h_bu_factor', type: 'float' } |
|
710 ], |
|
711 }, |
|
712 hopAdapter = new $.jqx.dataAdapter(hopSource); |
|
713 |
|
714 $('#hopGrid').jqxGrid({ |
|
715 width: 1240, |
|
716 height: 560, |
|
717 source: hopAdapter, |
|
718 theme: theme, |
|
719 editable: false, |
|
720 ready: function() { $('#jqxTabs').jqxTabs('next'); }, |
|
721 columns: [ |
|
722 { text: 'Hop', datafield: 'h_name' }, |
|
723 { text: 'Origin', width: 180, datafield: 'h_origin' }, |
|
724 { text: 'Type', width: 90, datafield: 'h_type', |
|
725 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
726 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopTypeData[value].nl + '</span>'; |
|
727 } |
|
728 }, |
|
729 { text: 'Vorm', width: 110, datafield: 'h_form', |
|
730 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
731 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopFormData[value].nl + '</span>'; |
|
732 } |
|
733 }, |
|
734 { text: 'Alpha', datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, |
|
735 { text: 'Gebruik', width: 110, datafield: 'h_useat', |
|
736 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
737 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopUseData[value].nl + '</span>'; |
|
738 } |
|
739 }, |
|
740 { text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right', |
|
741 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
742 var duration = ''; |
|
743 if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4)) // Boil, Whirlpool |
|
744 duration = dataAdapter.formatNumber(value, 'f0') + ' min.'; |
|
745 else if (rowdata.h_useat == 5) // Dry hop |
|
746 duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; |
|
747 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + duration + '</span>'; |
|
748 } |
|
749 }, |
|
750 { text: 'IBU', datafield: 'ibu', width: 80, align: 'right', |
|
751 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
752 var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat(dataRecord.batch_size), |
|
753 parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), dataRecord.ibu_method, |
|
754 dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); |
|
755 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(ibu, 'f1') + '</span>'; |
|
756 } |
|
757 }, |
|
758 { text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right', |
|
759 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
760 var amount = dataAdapter.formatNumber(value, 'f1') + ' kg'; |
|
761 if (value < 1) |
|
762 amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; |
|
763 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>'; |
|
764 } |
|
765 }, |
|
766 { text: 'Voorraad', datafield: 'h_inventory', width: 110, align: 'right', |
|
767 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
768 if (block_hop(dataRecord.inventory_reduced, rowdata.h_useat) == false) { |
|
769 var amount = dataAdapter.formatNumber(value, 'f1') + ' kg', |
|
770 color = (value < rowdata.h_amount) ? '#ff4040':'#ffffff'; |
|
771 if (value < 1) |
|
772 amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; |
|
773 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>'; |
|
774 } else { |
|
775 return '<span></span>'; |
|
776 } |
|
777 } |
|
778 } |
|
779 ] |
|
780 }); |
|
781 }; |
|
782 |
|
783 // Inline miscs editor |
|
784 var editMisc = function(data) { |
|
785 var miscSource = { |
|
786 localdata: data.miscs, |
|
787 datafields: [ |
|
788 { name: 'm_name', type: 'string' }, |
|
789 { name: 'm_amount', type: 'float' }, |
|
790 { name: 'm_cost', type: 'float' }, |
|
791 { name: 'm_type', type: 'int' }, |
|
792 { name: 'm_use_use', type: 'int' }, |
|
793 { name: 'm_time', type: 'float' }, |
|
794 { name: 'm_amount_is_weight', type: 'int' }, |
|
795 { name: 'm_inventory', type: 'float' }, |
|
796 { name: 'm_avail', type: 'int' } |
|
797 ], |
|
798 }, |
|
799 miscAdapter = new $.jqx.dataAdapter(miscSource, { |
|
800 beforeLoadComplete: function(records) { |
|
801 var row, i, data = new Array(); |
|
802 for (i = 0; i < records.length; i++) { |
|
803 row = records[i]; |
|
804 data.push(row); |
|
805 // Initial set water agent values. |
|
806 if (row.m_use_use == 1) { // Mash |
|
807 switch (row.m_name) { |
|
808 case 'CaCl2': |
|
809 $('#wa_cacl2').val(row.m_amount * 1000); |
|
810 break; |
|
811 case 'CaSO4': |
|
812 $('#wa_caso4').val(row.m_amount * 1000); |
|
813 break; |
|
814 case 'MgSO4': |
|
815 $('#wa_mgso4').val(row.m_amount * 1000); |
|
816 break; |
|
817 case 'NaCl': |
|
818 $('#wa_nacl').val(row.m_amount * 1000); |
|
819 break; |
|
820 case 'MgCl2': |
|
821 $('#wa_mgcl2').val(row.m_amount * 1000); |
|
822 break; |
|
823 case 'NaHCO3': |
|
824 $('#wa_nahco3').val(row.m_amount * 1000); |
|
825 break; |
|
826 case 'CaCO3': |
|
827 $('#wa_caco3').val(row.m_amount * 1000); |
|
828 break; |
|
829 case 'Melkzuur': |
|
830 $('#wa_acid_name').val(AcidTypeData[0].nl); |
|
831 $('#wa_acid').val(row.m_amount * 1000); |
|
832 $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); |
|
833 last_acid = 'Melkzuur'; |
|
834 break; |
|
835 case 'Zoutzuur': |
|
836 $('#wa_acid_name').val(AcidTypeData[1].nl); |
|
837 $('#wa_acid').val(row.m_amount * 1000); |
|
838 $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc); |
|
839 last_acid = 'Zoutzuur'; |
|
840 break; |
|
841 case 'Fosforzuur': |
|
842 $('#wa_acid_name').val(AcidTypeData[2].nl); |
|
843 $('#wa_acid').val(row.m_amount * 1000); |
|
844 $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc); |
|
845 last_acid = 'Fosforzuur'; |
|
846 break; |
|
847 case 'Zwavelzuur': |
|
848 $('#wa_acid_name').val(AcidTypeData[3].nl); |
|
849 $('#wa_acid').val(row.m_amount * 1000); |
|
850 $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc); |
|
851 last_acid = 'Zwavelzuur'; |
|
852 break; |
|
853 } |
|
854 } |
|
855 if (row.m_use_use == 6) { // Sparge |
|
856 switch (row.m_name) { |
|
857 case 'CaCl2': |
|
858 $('#ss_cacl2').val(row.m_amount * 1000); |
|
859 break; |
|
860 case 'CaSO4': |
|
861 $('#ss_caso4').val(row.m_amount * 1000); |
|
862 break; |
|
863 case 'MgSO4': |
|
864 $('#ss_mgso4').val(row.m_amount * 1000); |
|
865 break; |
|
866 case 'NaCl': |
|
867 $('#ss_nacl').val(row.m_amount * 1000); |
|
868 break; |
|
869 case 'MgCl2': |
|
870 $('#ss_mgcl2').val(row.m_amount * 1000); |
|
871 break; |
|
872 } |
|
873 } |
|
874 } |
|
875 return data; |
|
876 }, |
|
877 loadError: function(jqXHR, status, error) { console.log('miscs load error ' + status + ' ' + error); }, |
|
878 }); |
|
879 $('#miscGrid').jqxGrid({ |
|
880 width: 1240, |
|
881 height: 575, |
|
882 source: miscAdapter, |
|
883 theme: theme, |
|
884 editable: false, |
|
885 ready: function() { $('#jqxTabs').jqxTabs('next'); }, |
|
886 columns: [ |
|
887 { text: 'Ingredient', datafield: 'm_name' }, |
|
888 { text: 'Type', width: 140, datafield: 'm_type', |
|
889 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
890 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + MiscTypeData[value].nl + '</span>'; |
|
891 } |
|
892 }, |
|
893 { text: 'Gebruik', width: 140, datafield: 'm_use_use', |
|
894 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
895 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + MiscUseData[value].nl + '</span>'; |
|
896 } |
|
897 }, |
|
898 { text: 'Tijd', datafield: 'm_time', width: 90, align: 'right', |
|
899 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
900 var duration = ''; |
|
901 if (rowdata.m_use_use == 2) // Boil |
|
902 duration = dataAdapter.formatNumber(value, 'f0') + ' min.'; |
|
903 else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) // Primary or Secondary |
|
904 duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; |
|
905 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + duration + '</span>'; |
|
906 } |
|
907 }, |
|
908 { text: 'Hoeveel', datafield: 'm_amount', width: 110, align: 'right', |
|
909 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
910 var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml'; |
|
911 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr + '</span>'; |
|
912 } |
|
913 }, |
|
914 { text: 'Voorraad', datafield: 'm_inventory', width: 110, align: 'right', |
|
915 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
916 if (block_misc(dataRecord.inventory_reduced, rowdata.m_use_use) == false) { |
|
917 var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml', |
|
918 color = (value < rowdata.m_amount) ? '#ff4040':'#ffffff', |
|
919 amount = dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr; |
|
920 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>'; |
|
921 } else { |
|
922 return '<span></span>'; |
|
923 } |
|
924 } |
|
925 } |
|
926 ] |
|
927 }); |
|
928 }; |
|
929 |
|
930 // Inline yeasts editor |
|
931 var editYeast = function(data) { |
|
932 var yeastSource = { |
|
933 localdata: data.yeasts, |
|
934 datafields: [ |
|
935 { name: 'y_name', type: 'string' }, |
|
936 { name: 'y_laboratory', type: 'string' }, |
|
937 { name: 'y_product_id', type: 'string' }, |
|
938 { name: 'y_amount', type: 'float' }, |
|
939 { name: 'y_cost', type: 'float' }, |
|
940 { name: 'y_type', type: 'int' }, |
|
941 { name: 'y_form', type: 'int' }, |
|
942 { name: 'y_flocculation', type: 'int' }, |
|
943 { name: 'y_min_temperature', type: 'float' }, |
|
944 { name: 'y_max_temperature', type: 'float' }, |
|
945 { name: 'y_attenuation', type: 'float' }, |
|
946 { name: 'y_use', type: 'int' }, |
|
947 { name: 'y_cells', type: 'float' }, |
|
948 { name: 'y_tolerance', type: 'float' }, |
|
949 { name: 'y_inventory', type: 'float' }, |
|
950 { name: 'y_sta1', type: 'int' }, |
|
951 { name: 'y_bacteria', type: 'int' }, |
|
952 { name: 'y_harvest_top', type: 'int' }, |
|
953 { name: 'y_harvest_time', type: 'int' }, |
|
954 { name: 'y_pitch_temperature', type: 'float' }, |
|
955 { name: 'y_pofpos', type: 'int' }, |
|
956 { name: 'y_zymocide', type: 'int' }, |
|
957 { name: 'y_gr_hl_lo', type: 'int' }, |
|
958 { name: 'y_sg_lo', type: 'float' }, |
|
959 { name: 'y_gr_hl_hi', type: 'int' }, |
|
960 { name: 'y_sg_hi', type: 'float' }, |
|
961 { name: 'y_avail', type: 'int' } |
|
962 ], |
|
963 }, |
|
964 yeastAdapter = new $.jqx.dataAdapter(yeastSource); |
|
965 |
|
966 $('#yeastGrid').jqxGrid({ |
|
967 width: 1240, |
|
968 height: 325, |
|
969 source: yeastAdapter, |
|
970 theme: theme, |
|
971 editable: false, |
|
972 ready: function() { $('#jqxTabs').jqxTabs('next'); }, |
|
973 columns: [ |
|
974 { text: 'Gist', datafield: 'y_name' }, |
|
975 { text: 'Laboratorium', width: 150, datafield: 'y_laboratory' }, |
|
976 { text: 'Code', width: 90, datafield: 'y_product_id' }, |
|
977 { text: 'Soort', width: 100, datafield: 'y_form', |
|
978 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
979 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + YeastFormData[value].nl + '</span>'; |
|
980 } |
|
981 }, |
|
982 { text: 'Min. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' }, |
|
983 { text: 'Max. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' }, |
|
984 { text: 'Tol. %', width: 60, align: 'right', cellsalign: 'right', datafield: 'y_tolerance', |
|
985 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
986 var amount = '', color = (dataRecord.est_abv > value) ? '#ff4040':'#ffffff'; |
|
987 if (value > 0) { |
|
988 amount = dataAdapter.formatNumber(value, 'f1'); |
|
989 } |
|
990 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>'; |
|
991 } |
|
992 }, |
|
993 { text: 'Attn. %', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' }, |
|
994 { text: 'Voor', width: 120, datafield: 'y_use', |
|
995 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
996 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + YeastUseData[value].nl + '</span>'; |
|
997 } |
|
998 }, |
|
999 { text: 'Hoeveel', datafield: 'y_amount', width: 90, align: 'right', |
|
1000 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
1001 var amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml'; |
|
1002 if (rowdata.y_form == 0) // Liquid |
|
1003 amount = dataAdapter.formatNumber(value, 'f0') + ' pk'; |
|
1004 else if (rowdata.y_form == 1 || rowdata.y_form == 6) // Dry |
|
1005 amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; |
|
1006 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>'; |
|
1007 } |
|
1008 }, |
|
1009 { text: 'Voorraad', datafield: 'y_inventory', width: 90, align: 'right', |
|
1010 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
1011 var color, amount; |
|
1012 if (block_yeast(dataRecord.inventory_reduced, rowdata.y_use) == false) { |
|
1013 color = '#ffffff'; |
|
1014 if (value < rowdata.y_amount) |
|
1015 color = '#ff4040'; |
|
1016 amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml'; |
|
1017 if (rowdata.y_form == 0) // Liquid |
|
1018 amount = dataAdapter.formatNumber(value, 'f0') + ' pk'; |
|
1019 else if (rowdata.y_form == 1 || rowdata.y_form == 6) // Dry |
|
1020 amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; |
|
1021 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>'; |
|
1022 } else { |
|
1023 return '<span></span>'; |
|
1024 } |
|
1025 } |
|
1026 } |
|
1027 ] |
|
1028 }); |
|
1029 }; |
|
1030 |
|
1031 // inline mash editor |
|
1032 var editMash = function(data) { |
|
1033 var mashSource = { |
|
1034 localdata: data.mashs, |
|
1035 datafields: [ |
|
1036 { name: 'step_name', type: 'string' }, |
|
1037 { name: 'step_type', type: 'int' }, |
|
1038 { name: 'step_volume', type: 'float' }, |
|
1039 { name: 'step_infuse_amount', type: 'float' }, |
|
1040 { name: 'step_infuse_temp', type: 'float' }, |
|
1041 { name: 'step_temp', type: 'float' }, |
|
1042 { name: 'step_time', type: 'float' }, |
|
1043 { name: 'step_wg_ratio', type: 'float' }, |
|
1044 { name: 'ramp_time', type: 'float' }, |
|
1045 { name: 'end_temp', type: 'float' }, |
|
1046 { name: 'step_ph', type: 'float' }, |
|
1047 { name: 'step_sg', type: 'float' } |
|
1048 ], |
|
1049 }, |
|
1050 mashAdapter = new $.jqx.dataAdapter(mashSource); |
|
1051 |
|
1052 $('#mashGrid').jqxGrid({ |
|
1053 width: 1240, |
|
1054 height: 400, |
|
1055 source: mashAdapter, |
|
1056 theme: theme, |
|
1057 selectionmode: 'singlerow', |
|
1058 editable: false, |
|
1059 ready: function() { |
|
1060 /* Calculate the whole recipe */ |
|
1061 console.log('ready mashs, start calculations'); |
|
1062 /* calcFermentables() must be first and is done by the grid load. Here it is too late. */ |
|
1063 calcMash(); |
|
1064 calcWater(); |
|
1065 calcIBUs(); |
|
1066 whirlpoolHops(); |
|
1067 calcMiscs(); |
|
1068 calcViability(); |
|
1069 calcYeast(); |
|
1070 kookTijd(); |
|
1071 calcFermentation(); |
|
1072 calcCarbonation(); |
|
1073 $('#FLog').jqxButton({ disabled: (dataRecord.log_fermentation) ? false : true}); |
|
1074 $('#ILog').jqxButton({ disabled: (dataRecord.log_ispindel) ? false : true}); |
|
1075 $('#CLog').jqxButton({ disabled: (dataRecord.log_co2pressure) ? false : true}); |
|
1076 console.log('calculations ready'); |
|
1077 $('#jqxLoader').jqxLoader('close'); |
|
1078 $('#jqxTabs').jqxTabs('first'); |
|
1079 }, |
|
1080 columns: [ |
|
1081 { text: 'Stap naam', datafield: 'step_name' }, |
|
1082 { text: 'Stap type', datafield: 'step_type', width: 150, |
|
1083 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
1084 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + MashStepTypeData[value].nl + '</span>'; |
|
1085 } |
|
1086 }, |
|
1087 { text: 'Start °C', datafield: 'step_temp', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, |
|
1088 { text: 'Eind °C', datafield: 'end_temp', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, |
|
1089 { text: 'Rust min.', datafield: 'step_time', width: 80, align: 'right', cellsalign: 'right' }, |
|
1090 { text: 'Stap min.', datafield: 'ramp_time', width: 80, align: 'right', cellsalign: 'right' }, |
|
1091 { text: 'Inf/dec L.', datafield: 'step_infuse_amount', width: 80, align: 'right', |
|
1092 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { |
|
1093 if (rowdata.step_type == 1) |
|
1094 return '<span></span>'; |
|
1095 var color = '#ffffff'; |
|
1096 var mvol = mashkg * MaltVolume; |
|
1097 if ((rowdata.step_wg_ratio * mashkg + mvol) > dataRecord.eq_tun_volume) |
|
1098 color = '#ff4040'; |
|
1099 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + dataAdapter.formatNumber(value, 'f1') + '</span>'; |
|
1100 } |
|
1101 }, |
|
1102 { text: 'Inf/dec °C', datafield: 'step_infuse_temp', width: 90, align: 'right', |
|
1103 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { |
|
1104 if (rowdata.step_type == 1) |
|
1105 return '<span></span>'; |
|
1106 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value, 'f2') + '</span>'; |
|
1107 } |
|
1108 }, |
|
1109 { text: 'L/Kg.', datafield: 'step_wg_ratio', width: 80, align: 'right', |
|
1110 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { |
|
1111 var color = '#ffffff'; |
|
1112 if (value < 2.0 || value > 6.0) |
|
1113 color = '#ff4040'; |
|
1114 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + dataAdapter.formatNumber(value, 'f2') + '</span>'; |
|
1115 } |
|
1116 }, |
|
1117 { text: 'pH', datafield: 'step_ph', width: 70, align: 'right', cellsalign: 'right', cellsformat: 'f2' }, |
|
1118 { text: 'SG', datafield: 'step_sg', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f3' } |
|
1119 ] |
|
1120 }); |
|
1121 }; |
|
1122 |
|
1123 /* |
|
1124 * Remove the top menu so that we MUST use the button to leave the editor. |
|
1125 */ |
|
1126 $('#jqxMenu').jqxMenu('destroy'); |
|
1127 console.log('record:' + my_record + ' return:' + my_return + ' theme:' + theme); |
|
1128 $('#jqxLoader').jqxLoader({ width: 250, height: 150, isModal: true, text: 'Laden product ...', theme: theme }); |
|
1129 $('#jqxLoader').jqxLoader('open'); |
|
1130 |
|
1131 /* Moved to before all functions */ |
|
1132 dataAdapter.dataBind(); |
|
1133 |
|
1134 /* |
|
1135 * Generic functions |
|
1136 */ |
|
1137 function kookTijd() { |
|
1138 if (dataRecord.boil_time) { |
|
1139 $('#brew_pmpt_koken').html('Koken ' + dataRecord.boil_time + ' minuten'); |
|
1140 } else { |
|
1141 $('#brew_pmpt_koken').html('Koken "no-boil"'); |
|
1142 } |
|
1143 } |
|
1144 |
|
1145 function infusionVol(step_infused, step_mashkg, infuse_temp, step_temp, last_temp) { |
|
1146 var a = last_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); |
|
1147 var b = step_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); |
|
1148 var vol = Round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)), 2); |
|
1149 return vol; |
|
1150 } |
|
1151 |
|
1152 function decoctionVol(step_volume, step_temp, prev_temp) { |
|
1153 var a = (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp); |
|
1154 var b = SpecificHeatWater * (99 - step_temp); |
|
1155 var vol = 0; |
|
1156 if (b > 0) |
|
1157 vol = Round(a / b, 6); |
|
1158 return vol; |
|
1159 } |
|
1160 |
|
1161 function calcViability() { |
|
1162 var vpm = 1.00; |
|
1163 var max = 100; |
|
1164 var rowscount = dataRecord.yeasts.length; |
|
1165 if (rowscount) { |
|
1166 for (i = 0; i < rowscount; i++) { |
|
1167 row = dataRecord.yeasts[i]; |
|
1168 if (row.y_use == 0) { |
|
1169 if (row.y_form == 0) { // Liquid |
|
1170 vpm = 0.80; |
|
1171 max = 97; |
|
1172 if (row.y_laboratory == 'White Labs') { // PurePitch |
|
1173 vpm = 0.95; |
|
1174 max = 100; |
|
1175 } |
|
1176 } else if (row.y_form == 1) { // dry yeast |
|
1177 vpm = 0.998; |
|
1178 max = 100; |
|
1179 } else if (row.y_form == 6) { // Dried kveik |
|
1180 vpm = 0.92; |
|
1181 max = 100; |
|
1182 } else { // Slant, Culture, Frozen, Bottle |
|
1183 vpm = 0.99; |
|
1184 max = 97; |
|
1185 } |
|
1186 } |
|
1187 } |
|
1188 } |
|
1189 var base = max; |
|
1190 var days = 0; |
|
1191 |
|
1192 if (parseFloat($('#yeast_prod_date').val()) > 2000) { |
|
1193 console.log('calculate viability'); |
|
1194 var d = new Date(); |
|
1195 var date2 = $('#yeast_prod_date').val(); |
|
1196 date2 = date2.split('-'); |
|
1197 // Now we convert the array to a Date object |
|
1198 var date1 = new Date(d.getFullYear(), d.getMonth(), d.getDate()); |
|
1199 date2 = new Date(date2[0], date2[1] - 1, date2[2]); |
|
1200 var diff = parseInt(date1.getTime()) - parseInt(date2.getTime()); |
|
1201 days = Math.floor(diff/1000/60/60/24); |
|
1202 |
|
1203 var degrade = 1 - ((1 - vpm) / 30.41); // viability degradation per day. |
|
1204 for (i = 0; i < days; i++) { |
|
1205 base = base * degrade; |
|
1206 } |
|
1207 if (base > max) { |
|
1208 base = max; |
|
1209 } |
|
1210 base = Math.round(base); |
|
1211 } |
|
1212 console.log('age:' + days + ' max:' + max + ' vpm:' + vpm + ' base:' + base); |
|
1213 |
|
1214 if (dataRecord.starter_viability != base) { |
|
1215 dataRecord.starter_viability = base; |
|
1216 $('#starter_viability').val(dataRecord.starter_viability); |
|
1217 } |
|
1218 } |
|
1219 |
|
1220 function calcSupplies() { |
|
1221 if (dataRecord.inventory_reduced > 6) { |
|
1222 $('#ok_pmpt').hide(); |
|
1223 return; |
|
1224 } |
|
1225 if (ok_fermentables && ok_hops && ok_miscs && ok_yeasts && ok_waters) |
|
1226 $('#ok_supplies').html("<img src='images/dialog-ok-apply.png'>"); |
|
1227 else |
|
1228 $('#ok_supplies').html("<img src='images/dialog-error.png'>"); |
|
1229 } |
|
1230 |
|
1231 /* |
|
1232 * All calculations that depend on changes in the fermentables, |
|
1233 * volumes and equipments. |
|
1234 */ |
|
1235 function calcFermentables() { |
|
1236 |
|
1237 var sugarsf = 0, // fermentable sugars mash + boil |
|
1238 sugarsm = 0, // fermentable sugars in mash |
|
1239 vol = 0, // Volume sugars after boil |
|
1240 addedS = 0, // Added sugars after boil |
|
1241 addedmass = 0, // Added mass after boil |
|
1242 mvol = 0, // mash volume |
|
1243 infuse = 0, // mash infuse volume |
|
1244 colort = 0, // Colors srm * vol totals |
|
1245 colorh = 0, // Colors ebc * vol * kt |
|
1246 colorn = 0, // Colors ebc * pt * pct |
|
1247 my_100 = false, |
|
1248 mashtime = 0, // Total mash time |
|
1249 mashtemp = 0, // Average mash temperature |
|
1250 bv = 0.925, // Bierverlies rendement |
|
1251 sr = 0.95, // Mash en spoel rendement |
|
1252 lintner = 0, // Total recipe lintner |
|
1253 i, row, rows, org, timem, aboil_volume, spoelw, ogx, topw, s = 0, d, v, x, |
|
1254 sug, alc, pt, cw, color, scolor, fig; |
|
1255 |
|
1256 /* Init global variables */ |
|
1257 psugar = 0; |
|
1258 pcara = 0; |
|
1259 mashkg = 0; |
|
1260 ok_fermentables = 1; // All is in stock. |
|
1261 ok_yeasts = 1; |
|
1262 |
|
1263 if (dataRecord.mashs.length) { |
|
1264 for (i = 0; i < dataRecord.mashs.length; i++) { |
|
1265 row = dataRecord.mashs[i]; |
|
1266 if (parseFloat(row.step_type) == 0) // Infusion |
|
1267 mvol += parseFloat(row.step_infuse_amount); |
|
1268 if (row.step_temp <= 75 && row.step_temp >= 60) { // Ignore mashout |
|
1269 timem = row.step_time; |
|
1270 if (i > 0) |
|
1271 timem += row.ramp_time; |
|
1272 mashtime += timem; |
|
1273 mashtemp += timem * row.step_temp; |
|
1274 } |
|
1275 } |
|
1276 infuse = mvol; |
|
1277 mashtemp = Round(mashtemp / mashtime, 2); |
|
1278 } else { |
|
1279 console.log("calcFermentables() no mash steps"); |
|
1280 } |
|
1281 |
|
1282 if (! dataRecord.fermentables.length) { |
|
1283 console.log("calcFermentables() no fermentables"); |
|
1284 return; // grid not yet loaded. |
|
1285 } |
|
1286 |
|
1287 for (i = 0; i < dataRecord.fermentables.length; i++) { |
|
1288 row = dataRecord.fermentables[i]; |
|
1289 if (row.f_adjust_to_total_100) |
|
1290 my_100 = true; |
|
1291 if (row.f_type == 1 && row.f_added < 4) // Sugar |
|
1292 psugar += row.f_percentage; |
|
1293 if (row.f_graintype == 2 && row.f_added < 4) // Crystal |
|
1294 pcara += row.f_percentage; |
|
1295 d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
1296 if (row.f_added == 0) { // Mash |
|
1297 if (mvol > 0) { // Only if mash already known. |
|
1298 mvol += row.f_amount * row.f_moisture / 100; |
|
1299 s += d; |
|
1300 } |
|
1301 d = parseFloat(dataRecord.efficiency) / 100 * d; |
|
1302 sugarsm += d; |
|
1303 mashkg += parseFloat(row.f_amount); |
|
1304 } |
|
1305 if (row.f_added == 0 || row.f_added == 1) // Mash or Boil |
|
1306 sugarsf += d; |
|
1307 if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering |
|
1308 x = (row.f_yield / 100) * (1 - row.f_moisture / 100); |
|
1309 addedS += row.f_amount * x; |
|
1310 addedmass += row.f_amount; |
|
1311 vol += (x * sugardensity + (1 - x) * 1) * row.f_amount; |
|
1312 } |
|
1313 if (row.f_added < 4) { |
|
1314 colort += row.f_amount * ebc_to_srm(row.f_color); |
|
1315 colorh += row.f_amount * row.f_color * get_kt(row.f_color); |
|
1316 colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort. |
|
1317 } |
|
1318 if (fermentableInit) { |
|
1319 if (row.f_added == 4) { |
|
1320 $('#bottle_priming_total').val(row.f_amount * 1000); // Prevent clearing |
|
1321 $('#bottle_priming_sugar').val(row.f_name); |
|
1322 } |
|
1323 if (row.f_added == 5) { |
|
1324 $('#keg_priming_total').val(row.f_amount * 1000); |
|
1325 $('#keg_priming_sugar').val(row.f_name); |
|
1326 } |
|
1327 } |
|
1328 // Check supplies. |
|
1329 if ((((dataRecord.inventory_reduced <= 2) && (row.f_added <= 1)) || // Mash or boil |
|
1330 ((dataRecord.inventory_reduced <= 3) && (row.f_added == 2)) || // Primary |
|
1331 ((dataRecord.inventory_reduced <= 5) && (row.f_added == 3)) || // Secondary or Tertiary |
|
1332 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4)) || // Bottle |
|
1333 ((dataRecord.inventory_reduced <= 6) && (row.f_added == 5))) && row.f_inventory < row.f_amount) { |
|
1334 ok_fermentables = 0; |
|
1335 } |
|
1336 if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50 |
|
1337 lintner += row.f_diastatic_power * row.f_amount; |
|
1338 } |
|
1339 } |
|
1340 fermentableInit = 0; |
|
1341 $('#ferm_lintner').val(Math.round(parseFloat(lintner / mashkg))); |
|
1342 $('#mash_kg').val(mashkg); |
|
1343 console.log('calcFermentables() supplies:' + ok_fermentables + ' moutsuiker:' + Round(sugarsm, 3) + '/' + Round(sugarsf, 3)); |
|
1344 to_100 = my_100; |
|
1345 |
|
1346 if (mvol > 0) { |
|
1347 v = s / sugardensity + mvol; |
|
1348 s = 1000 * s / (v * 10); //deg. Plato |
|
1349 est_mash_sg = Round(plato_to_sg(s), 5); |
|
1350 $('#est_mash_sg').val(est_mash_sg); |
|
1351 } |
|
1352 |
|
1353 // Estimate total recipe OG. |
|
1354 dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size)); |
|
1355 $('#est_og').val(dataRecord.est_og); |
|
1356 $('#est_og2').val(dataRecord.est_og); |
|
1357 org = dataRecord.est_og; |
|
1358 |
|
1359 // Estimate SG in kettle after boil |
|
1360 aboil_sg = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size)); |
|
1361 $('#est_og3').val(aboil_sg); |
|
1362 |
|
1363 // Estimate SG in kettle before boil |
|
1364 preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size)); |
|
1365 $('#est_pre_sg').val(preboil_sg); |
|
1366 |
|
1367 // Recalculate volumes. |
|
1368 aboil_volume = parseFloat(dataRecord.batch_size); |
|
1369 if (dataRecord.brew_aboil_volume > 0) |
|
1370 aboil_volume = dataRecord.brew_aboil_volume / 1.04; // volume @ 20 degrees |
|
1371 if (dataRecord.brew_fermenter_tcloss == 0) { |
|
1372 dataRecord.brew_fermenter_tcloss = dataRecord.eq_trub_chiller_loss; |
|
1373 $('#brew_fermenter_tcloss').val(dataRecord.brew_fermenter_tcloss); |
|
1374 } |
|
1375 dataRecord.brew_fermenter_volume = aboil_volume - dataRecord.brew_fermenter_tcloss + dataRecord.brew_fermenter_extrawater; |
|
1376 $('#brew_fermenter_volume').val(dataRecord.brew_fermenter_volume); |
|
1377 // Calculate SG in fermenter |
|
1378 ogx = dataRecord.brew_aboil_sg; |
|
1379 if (ogx < 1.002) |
|
1380 ogx = aboil_sg; |
|
1381 topw = dataRecord.brew_fermenter_extrawater; |
|
1382 |
|
1383 if (dataRecord.brew_fermenter_volume > 0) { |
|
1384 sug = sg_to_plato(ogx) * dataRecord.brew_fermenter_volume * ogx / 100; //kg of sugar in |
|
1385 sug += addedS; //kg |
|
1386 |
|
1387 if ((dataRecord.brew_fermenter_volume * ogx + addedmass) > 0) { |
|
1388 pt = 100 * sug / (dataRecord.brew_fermenter_volume * ogx + addedmass + topw); |
|
1389 dataRecord.og = dataRecord.brew_fermenter_sg = Round(plato_to_sg(pt), 4); |
|
1390 $('#brew_fermenter_sg').val(dataRecord.brew_fermenter_sg); |
|
1391 // color |
|
1392 if (dataRecord.color_method == 4) { |
|
1393 dataRecord.brew_fermenter_color = Math.round(((pt / 8.6) * colorn) + (dataRecord.boil_time / 60)); |
|
1394 } else if (dataRecord.color_method == 3) { |
|
1395 dataRecord.brew_fermenter_color = Math.round((4.46 * bv * sr) / (aboil_volume + topw) * colorh); |
|
1396 } else { |
|
1397 cw = colort / (aboil_volume + topw) * 8.34436; |
|
1398 dataRecord.brew_fermenter_color = kw_to_ebc(dataRecord.color_method, cw); |
|
1399 } |
|
1400 $('#brew_fermenter_color').val(dataRecord.brew_fermenter_color); |
|
1401 scolor = ebc_to_color(dataRecord.brew_fermenter_color); |
|
1402 $('#bcolorf').show(); |
|
1403 document.getElementById('bcolorf').style.background = scolor; |
|
1404 } |
|
1405 } else { |
|
1406 // Negative volume |
|
1407 dataRecord.brew_fermenter_sg = dataRecord.brew_fermenter_color = 0; |
|
1408 $('#brew_fermenter_sg').val(0); |
|
1409 $('#brew_fermenter_color').val(0); |
|
1410 $('#bcolorf').hide(); |
|
1411 } |
|
1412 |
|
1413 // Color of the wort |
|
1414 if (dataRecord.color_method == 4) { |
|
1415 color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60)); |
|
1416 } else if (dataRecord.color_method == 3) { // Hans Halberstadt |
|
1417 color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh); |
|
1418 } else { |
|
1419 cw = colort / parseFloat(dataRecord.batch_size) * 8.34436; |
|
1420 color = kw_to_ebc(dataRecord.color_method, cw); |
|
1421 } |
|
1422 dataRecord.est_color = color; |
|
1423 $('#est_color').val(color); |
|
1424 $('#est_color2').val(color); |
|
1425 scolor = ebc_to_color(color); |
|
1426 document.getElementById('bcolor').style.background = scolor; |
|
1427 document.getElementById('bcolor2').style.background = scolor; |
|
1428 |
|
1429 // Progress bars |
|
1430 pmalts = mashkg / dataRecord.eq_mash_max * 100; |
|
1431 $('#perc_malts').jqxProgressBar('val', pmalts); |
|
1432 $('#perc_sugars').jqxProgressBar('val', psugar); |
|
1433 $('#perc_cara').jqxProgressBar('val', pcara); |
|
1434 calcStage(); |
|
1435 |
|
1436 // Calculate estimated svg. |
|
1437 svg = 0; // default. |
|
1438 initcells = 0; |
|
1439 for (i = 0; i < dataRecord.yeasts.length; i++) { |
|
1440 row = dataRecord.yeasts[i]; |
|
1441 if (row.y_use == 0) { // Primary |
|
1442 if (parseFloat(row.y_attenuation) > svg) |
|
1443 svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts. |
|
1444 if (row.y_form == 0) |
|
1445 initcells += (parseFloat(row.y_cells) / 1000000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100); |
|
1446 else |
|
1447 initcells += (parseFloat(row.y_cells) / 1000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100); |
|
1448 } |
|
1449 // TODO: brett in secondary ?? |
|
1450 if ((((dataRecord.inventory_reduced <= 3) && (row.y_use == 0)) || // Primary |
|
1451 ((dataRecord.inventory_reduced <= 4) && (row.y_use == 1)) || // Secondary |
|
1452 ((dataRecord.inventory_reduced <= 5) && (row.y_use == 2)) || // Tertiary |
|
1453 ((dataRecord.inventory_reduced <= 6) && (row.y_use == 3))) && // Bottle |
|
1454 (row.y_inventory < row.y_amount)) { |
|
1455 ok_yeasts = 0; |
|
1456 } |
|
1457 } |
|
1458 calcSupplies(); |
|
1459 if (svg == 0) |
|
1460 svg = 77; |
|
1461 if ((mashkg > 0) && (infuse > 0) && (mashtime > 0) && (mashtemp > 0)) { |
|
1462 dataRecord.est_fg = estimate_fg(psugar, pcara, infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og); |
|
1463 } else { |
|
1464 dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og); |
|
1465 } |
|
1466 $('#est_fg').val(dataRecord.est_fg); |
|
1467 $('#est_fg2').val(dataRecord.est_fg); |
|
1468 $('#est_fg3').val(dataRecord.est_fg); |
|
1469 fig = dataRecord.est_fg; |
|
1470 |
|
1471 dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg); |
|
1472 $('#est_abv').val(dataRecord.est_abv); |
|
1473 $('#est_abv2').val(dataRecord.est_abv); |
|
1474 |
|
1475 // Calculate the final svg if available use the real value. |
|
1476 if ((dataRecord.stage >= 6) && (dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { |
|
1477 svg = calc_svg(dataRecord.brew_fermenter_sg, dataRecord.fg); |
|
1478 org = dataRecord.brew_fermenter_sg; |
|
1479 fig = dataRecord.fg; |
|
1480 } |
|
1481 |
|
1482 $('#yeast_cells').val(initcells); |
|
1483 $('#need_cells').val(getNeededYeastCells()); |
|
1484 |
|
1485 // Calculate the calories in kcal/l (from brouwhulp) |
|
1486 alc = 1881.22 * fig * (org - fig) / (1.775 - org); |
|
1487 sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004); |
|
1488 $('#kcal').val(Math.round((alc + sug) / (12 * 0.0295735296))); |
|
1489 }; |
|
1490 |
|
1491 function calcMash() { |
|
1492 |
|
1493 var h, m, infused = 0, mashtime = 0, mashvol = 0, vol, i, j, n, a, b, row, temp; |
|
1494 var lasttemp = 18.0; |
|
1495 var graintemp = 18.0; |
|
1496 var tuntemp = 18.0; |
|
1497 |
|
1498 if (dataRecord.mashs.length && (mashkg > 0)) { |
|
1499 console.log('calcMash()'); |
|
1500 for (i = 0; i < dataRecord.mashs.length; i++) { |
|
1501 row = dataRecord.mashs[i]; |
|
1502 if (row.step_type == 0) { // Infusion |
|
1503 if (i == 0) { |
|
1504 // First mash step, temperature from the mashtun and malt. |
|
1505 n = 20; // tun is preheated. |
|
1506 tuntemp = row.step_temp; |
|
1507 for (j = 0; j < n; j++) { |
|
1508 a = mashkg * graintemp * SpecificHeatMalt + dataRecord.eq_tun_weight * tuntemp * dataRecord.eq_tun_specific_heat; |
|
1509 b = row.step_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + row.step_infuse_amount * SpecificHeatWater + mashkg * SpecificHeatMalt) - SlakingHeat * mashkg; |
|
1510 if (row.step_infuse_amount > 0) { |
|
1511 temp = (b - a) / (row.step_infuse_amount * SpecificHeatWater); |
|
1512 } else { |
|
1513 temp = 99; |
|
1514 } |
|
1515 tuntemp += (temp - tuntemp) / 2; |
|
1516 row.step_infuse_temp = Round(temp, 6); |
|
1517 } |
|
1518 //console.log('init infuse temp: ' + row.step_infuse_temp); |
|
1519 } else { |
|
1520 // Calculate amount of infusion water. |
|
1521 row.step_infuse_amount = infusionVol(infused, mashkg, row.step_infuse_temp, row.step_temp, lasttemp); |
|
1522 //console.log('vol: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); |
|
1523 } |
|
1524 infused += parseFloat(row.step_infuse_amount); |
|
1525 } else if (row.step_type == 1) { // Temperature |
|
1526 if (i > 0) |
|
1527 row.step_infuse_amount = 0; |
|
1528 row.step_infuse_temp = 0; |
|
1529 } else if (row.step_type == 2) { // Decoction |
|
1530 row.step_infuse_amount = decoctionVol(infused, row.step_temp, lasttemp); |
|
1531 row.step_infuse_temp = 99; |
|
1532 } |
|
1533 row.step_volume = infused; |
|
1534 //console.log(i + ' type: ' + row.step_type + ' volume: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); |
|
1535 lasttemp = row.step_temp; |
|
1536 mashtime += row.step_time + row.ramp_time; |
|
1537 row.step_wg_ratio = Round(infused / mashkg, 6); |
|
1538 $('#mashGrid').jqxGrid('updaterow', i, row); |
|
1539 } |
|
1540 } |
|
1541 if ((dataRecord.w1_amount + dataRecord.w2_amount) == 0) { |
|
1542 dataRecord.w1_amount = infused; |
|
1543 $('#w1_amount').val(infused); |
|
1544 console.log("calcMash() fixed water 1 to " + infused); |
|
1545 } |
|
1546 mashvol = Round(mashkg * MaltVolume + infused, 6); |
|
1547 $('#est_mashvol').val(mashvol); |
|
1548 h = Math.floor(mashtime / 60); |
|
1549 m = Math.floor(mashtime - (h * 60)); |
|
1550 if (h < 10) |
|
1551 h = '0' + h; |
|
1552 if (m < 10) |
|
1553 m = '0' + m; |
|
1554 $('#est_mashtime').val(h + ':' + m); |
|
1555 // Estimated needed sparge water corrected for the temperature. |
|
1556 spoelw = Round((dataRecord.boil_size - infused + (mashkg * my_grain_absorbtion) + dataRecord.eq_lauter_deadspace) * 1.03, 6); |
|
1557 $('#brew_sparge_est').val(spoelw); |
|
1558 } |
|
1559 |
|
1560 function getNeededYeastCells() { |
|
1561 |
|
1562 var plato, volume, sg = dataRecord.brew_fermenter_sg; |
|
1563 if (sg <= 1.0001 && dataRecord.fg > 1.000) |
|
1564 sg = dataRecord.fg; |
|
1565 else if (sg <= 1.0001) |
|
1566 sg = dataRecord.est_og; |
|
1567 plato = sg_to_plato(sg); |
|
1568 |
|
1569 volume = dataRecord.brew_fermenter_volume; |
|
1570 if (volume <= 0) |
|
1571 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; |
|
1572 |
|
1573 return dataRecord.yeast_pitchrate * volume * plato; |
|
1574 } |
|
1575 |
|
1576 function hopFlavourContribution(bt, vol, use, amount) { |
|
1577 var result; |
|
1578 |
|
1579 if (use == 4 || use == 5) // Whirlpool or Dry-hop |
|
1580 return 0; |
|
1581 if (use == 1) { // First wort |
|
1582 result = 0.15; // assume 15% flavourcontribution for fwh |
|
1583 } else if (bt > 50) { |
|
1584 result = 0.10; // assume 10% flavourcontribution as a minimum |
|
1585 } else { |
|
1586 result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) / 6, 2)); |
|
1587 if (result < 0.10) |
|
1588 result = 0.10; // assume 10% flavourcontribution as a minimum |
|
1589 } |
|
1590 return (result * amount * 1000) / vol; |
|
1591 } |
|
1592 |
|
1593 function hopAromaContribution(bt, vol, use, amount) { |
|
1594 var result = 0; |
|
1595 |
|
1596 if (use == 5) { // Dry hop |
|
1597 result = 1.33; |
|
1598 } else if (use == 4) { // Whirlpool |
|
1599 if (bt > 30) |
|
1600 bt = 30; // Max 30 minutes |
|
1601 result = 0.62 * bt / 30; |
|
1602 } else if (bt > 20) { |
|
1603 result = 0; |
|
1604 } else if (bt > 7.5) { |
|
1605 result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) / 4, 2)); |
|
1606 } else if (use == 2) { // Boil |
|
1607 result = 1; |
|
1608 } else if (use == 3) { // Aroma |
|
1609 result = 1.2; |
|
1610 } |
|
1611 return (result * amount * 1000) / vol; |
|
1612 } |
|
1613 |
|
1614 function calcIBUs() { |
|
1615 var total_ibus = 0, ferm_ibus = 0, rows = {}, i, row; |
|
1616 hop_aroma = hop_flavour = 0; |
|
1617 if (!(rows = $('#hopGrid').jqxGrid('getrows'))) { |
|
1618 return; |
|
1619 } |
|
1620 ok_hops = 1; |
|
1621 for (i = 0; i < rows.length; i++) { |
|
1622 row = rows[i]; |
|
1623 total_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, parseFloat(dataRecord.batch_size), |
|
1624 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method, |
|
1625 dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); |
|
1626 ferm_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, |
|
1627 parseFloat(dataRecord.brew_fermenter_volume) + parseFloat(dataRecord.brew_fermenter_tcloss), |
|
1628 parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method, |
|
1629 dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); |
|
1630 hop_flavour += hopFlavourContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), row.h_useat, parseFloat(row.h_amount)); |
|
1631 hop_aroma += hopAromaContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), row.h_useat, parseFloat(row.h_amount)); |
|
1632 if ((((dataRecord.inventory_reduced <= 2) && (row.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool |
|
1633 ((dataRecord.inventory_reduced <= 6) && (row.h_useat == 5))) && // Dry-hop |
|
1634 (row.h_inventory < row.h_amount)) |
|
1635 ok_hops = 0; |
|
1636 } |
|
1637 total_ibus = Round(total_ibus, 1); |
|
1638 ferm_ibus = Round(ferm_ibus, 1); |
|
1639 hop_flavour = Round(hop_flavour * 100 / 5, 1); |
|
1640 hop_aroma = Round(hop_aroma * 100 / 6, 1); |
|
1641 if (hop_flavour > 100) |
|
1642 hop_flavour = 100; |
|
1643 if (hop_aroma > 100) |
|
1644 hop_aroma = 100; |
|
1645 console.log('calcIBUs(): ' + total_ibus + ' flavour: ' + hop_flavour + ' aroma: ' + hop_aroma + |
|
1646 ' fermenter:' + ferm_ibus + ' supplies:' + ok_hops); |
|
1647 dataRecord.est_ibu = total_ibus; |
|
1648 $('#est_ibu').val(total_ibus); |
|
1649 $('#est_ibu2').val(total_ibus); |
|
1650 $('#hop_flavour').jqxProgressBar('val', hop_flavour); |
|
1651 $('#hop_aroma').jqxProgressBar('val', hop_aroma); |
|
1652 $('#brew_fermenter_ibu').val(ferm_ibus); |
|
1653 calcStage(); |
|
1654 calcSupplies(); |
|
1655 }; |
|
1656 |
|
1657 /* |
|
1658 * http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ |
|
1659 * |
|
1660 * stype: 0=stirred, 1=shaken, 2=simple |
|
1661 * totcells: initial cells |
|
1662 * egrams: gram extract |
|
1663 */ |
|
1664 function getGrowthRate(stype, totcells, egrams) { |
|
1665 |
|
1666 /* Cells per grams extract (B/g) */ |
|
1667 var cpe = totcells / egrams; |
|
1668 |
|
1669 if (cpe > 3.5) |
|
1670 return 0; // no growth |
|
1671 if (stype == 2) |
|
1672 return 0.4; // simple starter |
|
1673 if (stype == 1) |
|
1674 return 0.62; // shaken starter |
|
1675 if (cpe <= 1.4) // stirred starter |
|
1676 return 1.4; |
|
1677 return 2.33 - (.67 * cpe); |
|
1678 }; |
|
1679 |
|
1680 function calcStep(svol, stype, start) { |
|
1681 |
|
1682 var gperpoint = 2.72715, //number of grams of extract per point of starter gravity per liter |
|
1683 prate = start / svol * 1000, |
|
1684 irate = Round(prate, 1), |
|
1685 egrams = (dataRecord.starter_sg - 1) * svol * gperpoint, |
|
1686 grate = getGrowthRate(stype, start, egrams), |
|
1687 ncells = Round(egrams * grate, 1), |
|
1688 totcells = parseFloat(ncells) + start; |
|
1689 |
|
1690 return { |
|
1691 svol: svol, |
|
1692 irate: irate, |
|
1693 prate: Round(prate, 1), |
|
1694 ncells: ncells, |
|
1695 totcells: totcells, |
|
1696 growf: Round(ncells / start, 2) |
|
1697 }; |
|
1698 } |
|
1699 |
|
1700 function killstep2() { |
|
1701 |
|
1702 dataRecord.prop2_volume = 0; |
|
1703 $('#prop2_volume').val(0); |
|
1704 $('#prop2_tcells').val(0); |
|
1705 $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').hide(); |
|
1706 $('#r2_pmpt').show(); |
|
1707 } |
|
1708 |
|
1709 function killstep3() { |
|
1710 |
|
1711 dataRecord.prop3_volume = 0; |
|
1712 $('#prop3_volume').val(0); |
|
1713 $('#prop3_tcells').val(0); |
|
1714 $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').hide(); |
|
1715 $('#r3_pmpt').show(); |
|
1716 } |
|
1717 |
|
1718 function killstep4() { |
|
1719 |
|
1720 dataRecord.prop4_volume = 0; |
|
1721 $('#prop4_volume').val(0); |
|
1722 $('#prop4_tcells').val(0); |
|
1723 $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').hide(); |
|
1724 $('#r4_pmpt').show(); |
|
1725 } |
|
1726 |
|
1727 /* |
|
1728 * Calculate all starter steps. |
|
1729 * stype: final starter type: 0 = stirred, 1 = shaked, 2 = simple. |
|
1730 * start: initial cells in billions |
|
1731 * needed: needed cells in billions |
|
1732 * |
|
1733 * result: all values updated. |
|
1734 */ |
|
1735 function calcSteps(stype, start, needed) { |
|
1736 |
|
1737 var uvols = [20, 40, 60, 80, 100, 150, 200, 250, 375, 500, 625, 750, 875, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000], |
|
1738 mvols = uvols.length, svol = 0, lasti = 0, result = {}, i; |
|
1739 |
|
1740 /* |
|
1741 * If no values are set, auto calculate the starter. |
|
1742 */ |
|
1743 if ((parseFloat($('#prop1_volume').jqxNumberInput('decimal')) + parseFloat($('#prop2_volume').jqxNumberInput('decimal')) + |
|
1744 parseFloat($('#prop3_volume').jqxNumberInput('decimal')) + parseFloat($('#prop4_volume').jqxNumberInput('decimal'))) == 0) { |
|
1745 // clear by default |
|
1746 for (i = 1; i < 5; i++) { |
|
1747 $('#prop' + i + '_type,#prop' + i + '_volume,#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells,#prop' + i + '_growf').hide(); |
|
1748 $('#r' + i + '_pmpt').show(); |
|
1749 $('#prop' + i + '_type').val(stype); |
|
1750 $('#prop' + i + '_volume').val(0); |
|
1751 } |
|
1752 if (start > needed) { |
|
1753 return; // no starter needed |
|
1754 } |
|
1755 $('#prop1_type,#prop1_volume,#prop1_irate,#prop1_ncells,#prop1_tcells,#prop1_growf').show(); |
|
1756 $('#r1_pmpt').hide(); |
|
1757 for (i = lasti; i <= mvols; i++) { |
|
1758 lasti = i; |
|
1759 svol = uvols[lasti]; |
|
1760 result = calcStep(svol, stype, start); |
|
1761 if (result.irate < 25) { |
|
1762 // inocculation rate too low, backup one step and break out. |
|
1763 lasti = i - 1; |
|
1764 svol = uvols[lasti]; |
|
1765 result = calcStep(svol, stype, start); |
|
1766 break; |
|
1767 } |
|
1768 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
1769 break; |
|
1770 } |
|
1771 } |
|
1772 $('#prop1_volume').val(result.svol / 1000); // to liters |
|
1773 $('#prop1_irate').val(result.prate); |
|
1774 $('#prop1_ncells').val(result.ncells); |
|
1775 $('#prop1_tcells').val(result.totcells); |
|
1776 $('#prop1_growf').val(result.growf); |
|
1777 if (result.totcells > needed) |
|
1778 return; // hit the target |
|
1779 |
|
1780 // second stage |
|
1781 $('#r2_pmpt').hide(); |
|
1782 $('#prop2_type').val(stype); |
|
1783 $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').show(); |
|
1784 for (i = lasti; i <= mvols; i++) { |
|
1785 lasti = i; |
|
1786 svol = uvols[lasti]; |
|
1787 result = calcStep(svol, stype, $('#prop1_tcells').val()); |
|
1788 if (result.irate < 25) { |
|
1789 lasti = i - 1; |
|
1790 svol = uvols[lasti]; |
|
1791 result = calcStep(svol, stype, $('#prop1_tcells').val()); |
|
1792 break; |
|
1793 } |
|
1794 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
1795 break; |
|
1796 } |
|
1797 } |
|
1798 $('#prop2_volume').val(result.svol / 1000); // to liters |
|
1799 $('#prop2_irate').val(result.prate); |
|
1800 $('#prop2_ncells').val(result.ncells); |
|
1801 $('#prop2_tcells').val(result.totcells); |
|
1802 $('#prop2_growf').val(result.growf); |
|
1803 if (result.totcells > needed) |
|
1804 return; // hit the target |
|
1805 |
|
1806 // third stage |
|
1807 $('#r3_pmpt').hide(); |
|
1808 $('#prop3_type').val(stype); |
|
1809 $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').show(); |
|
1810 for (i = lasti; i <= mvols; i++) { |
|
1811 lasti = i; |
|
1812 svol = uvols[lasti]; |
|
1813 result = calcStep(svol, stype, $('#prop2_tcells').val()); |
|
1814 if (result.irate < 25) { |
|
1815 lasti = i - 1; |
|
1816 svol = uvols[lasti]; |
|
1817 result = calcStep(svol, stype, $('#prop2_tcells').val()); |
|
1818 break; |
|
1819 } |
|
1820 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
1821 break; |
|
1822 } |
|
1823 } |
|
1824 $('#prop3_volume').val(result.svol / 1000); // to liters |
|
1825 $('#prop3_irate').val(result.prate); |
|
1826 $('#prop3_ncells').val(result.ncells); |
|
1827 $('#prop3_tcells').val(result.totcells); |
|
1828 $('#prop3_growf').val(result.growf); |
|
1829 if (result.totcells > needed) |
|
1830 return; // hit the target |
|
1831 |
|
1832 // fourth stage |
|
1833 $('#r4_pmpt').hide(); |
|
1834 $('#prop4_type').val(stype); |
|
1835 $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').show(); |
|
1836 for (i = lasti; i <= mvols; i++) { |
|
1837 lasti = i; |
|
1838 svol = uvols[lasti]; |
|
1839 result = calcStep(svol, stype, $('#prop3_tcells').val()); |
|
1840 if (result.totcells > needed || i == mvols) { // hit the target or loops done |
|
1841 $('#prop4_volume').val(result.svol / 1000); // to liters |
|
1842 $('#prop4_irate').val(result.prate); |
|
1843 $('#prop4_ncells').val(result.ncells); |
|
1844 $('#prop4_tcells').val(result.totcells); |
|
1845 $('#prop4_growf').val(result.growf); |
|
1846 return; |
|
1847 } |
|
1848 } |
|
1849 } else { |
|
1850 // recalculate |
|
1851 if (dataRecord.prop1_volume > 0) { |
|
1852 $('#r1_pmpt').hide(); |
|
1853 $('#prop1_type,#prop1_volume,#prop1_irate,#prop1_ncells,#prop1_tcells,#prop1_growf').show(); |
|
1854 result = calcStep($('#prop1_volume').val() * 1000, dataRecord.prop1_type, start); |
|
1855 $('#prop1_irate').val(result.prate); |
|
1856 $('#prop1_ncells').val(result.ncells); |
|
1857 $('#prop1_tcells').val(result.totcells); |
|
1858 $('#prop1_growf').val(result.growf); |
|
1859 if (result.totcells > needed) { |
|
1860 killstep2(); |
|
1861 killstep3(); |
|
1862 killstep4(); |
|
1863 } else if (dataRecord.prop2_volume == 0) { |
|
1864 dataRecord.prop2_volume = dataRecord.prop1_volume; /* Extra step needed, start with the same size */ |
|
1865 dataRecord.prop2_type = dataRecord.prop1_type; |
|
1866 $('#prop2_volume').val(dataRecord.prop2_volume); |
|
1867 $('#prop2_type').val(dataRecord.prop2_type); |
|
1868 } |
|
1869 } |
|
1870 if (dataRecord.prop2_volume > 0) { |
|
1871 $('#r2_pmpt').hide(); |
|
1872 $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').show(); |
|
1873 result = calcStep($('#prop2_volume').val() * 1000, dataRecord.prop2_type, $('#prop1_tcells').val()); |
|
1874 $('#prop2_irate').val(result.prate); |
|
1875 $('#prop2_ncells').val(result.ncells); |
|
1876 $('#prop2_tcells').val(result.totcells); |
|
1877 $('#prop2_growf').val(result.growf); |
|
1878 if (result.totcells > needed) { |
|
1879 killstep3(); |
|
1880 killstep4(); |
|
1881 } else if (dataRecord.prop3_volume == 0) { |
|
1882 dataRecord.prop3_volume = dataRecord.prop2_volume; /* Extra step needed, start with the same size */ |
|
1883 dataRecord.prop3_type = dataRecord.prop2_type; |
|
1884 $('#prop3_volume').val(dataRecord.prop3_volume); |
|
1885 $('#prop3_type').val(dataRecord.prop3_type); |
|
1886 } |
|
1887 } |
|
1888 if (dataRecord.prop3_volume > 0) { |
|
1889 $('#r3_pmpt').hide(); |
|
1890 $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').show(); |
|
1891 result = calcStep($('#prop3_volume').val() * 1000, dataRecord.prop3_type, $('#prop2_tcells').val()); |
|
1892 $('#prop3_irate').val(result.prate); |
|
1893 $('#prop3_ncells').val(result.ncells); |
|
1894 $('#prop3_tcells').val(result.totcells); |
|
1895 $('#prop3_growf').val(result.growf); |
|
1896 if (result.totcells > needed) { |
|
1897 killstep4(); |
|
1898 } else if (dataRecord.prop4_volume == 0) { |
|
1899 dataRecord.prop4_volume = dataRecord.prop3_volume; /* Extra step needed, start with the same size */ |
|
1900 dataRecord.prop4_type = dataRecord.prop3_type; |
|
1901 $('#prop4_volume').val(dataRecord.prop4_volume); |
|
1902 $('#prop4_type').val(dataRecord.prop4_type); |
|
1903 } |
|
1904 } |
|
1905 if (dataRecord.prop4_volume > 0) { |
|
1906 $('#r4_pmpt').hide(); |
|
1907 $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').show(); |
|
1908 result = calcStep($('#prop4_volume').val() * 1000, dataRecord.prop4_type, $('#prop3_tcells').val()); |
|
1909 $('#prop4_irate').val(result.prate); |
|
1910 $('#prop4_ncells').val(result.ncells); |
|
1911 $('#prop4_tcells').val(result.totcells); |
|
1912 $('#prop4_growf').val(result.growf); |
|
1913 } |
|
1914 } |
|
1915 } |
|
1916 |
|
1917 function calcYeast() { |
|
1918 |
|
1919 // Calculate needed cells. |
|
1920 var plato, volume, rows, rowscount, row, i, needed, use_cells, sg = dataRecord.brew_fermenter_sg; |
|
1921 |
|
1922 if (sg <= 1.0001 && dataRecord.fg > 1.000) |
|
1923 sg = dataRecord.fg; |
|
1924 else if (sg <= 1.0001) |
|
1925 sg = dataRecord.est_og; |
|
1926 plato = sg_to_plato(sg); |
|
1927 |
|
1928 volume = dataRecord.brew_fermenter_volume; |
|
1929 if (volume > 0) { |
|
1930 if (dataRecord.brew_fermenter_extrawater > 0) |
|
1931 volume += dataRecord.brew_fermenter_extrawater; |
|
1932 } else { |
|
1933 volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; |
|
1934 } |
|
1935 |
|
1936 // Also in calcFermentables() |
|
1937 $('#yeast_cells').val(initcells); |
|
1938 |
|
1939 if (!(rows = $('#yeastGrid').jqxGrid('getrows'))) { |
|
1940 return; // grid not yet loaded. |
|
1941 } |
|
1942 rowscount = dataRecord.yeasts.length; |
|
1943 if (rowscount == 0) |
|
1944 return; // no yeast in recipe |
|
1945 |
|
1946 $('.primary_dry').hide(); |
|
1947 $('.primary_liquid').hide(); |
|
1948 |
|
1949 var maybe_starter = 0; |
|
1950 var pitchrate = 0.75; // Yeast pitch rate default |
|
1951 for (i = 0; i < rowscount; i++) { |
|
1952 row = dataRecord.yeasts[i]; |
|
1953 if (row.y_use == 0) { // primary |
|
1954 if (row.y_form == 1) { |
|
1955 // Dry yeast |
|
1956 $('.primary_dry').show(); |
|
1957 console.log('dry yeast: ' + row.y_gr_hl_lo + '@' + row.y_sg_lo + ' ' + row.y_gr_hl_hi + '@' + row.y_sg_hi); |
|
1958 // Build the formule with the yeast parameters. |
|
1959 // Based on https://www.lallemandbrewing.com/en/canada/brewers-corner/brewing-tools/pitching-rate-calculator/ |
|
1960 var og = row.y_sg_lo; |
|
1961 var f1 = row.y_gr_hl_lo / 100; |
|
1962 var f2 = Round(f1 / 5, 6); |
|
1963 // After a lot of try and error, study, the best thing to increase the pitch amount is actually |
|
1964 // use this simple formula by Lallemand. This is about the same as sugar weight increment in the wort. |
|
1965 var multiplier = (sg <= og) ? f1 : (f1 + f2 * (sg - og) / 0.008); |
|
1966 console.log('sg: ' + sg + ' og: ' + og + ' f1: ' + f1 + ' f2: ' + f2 + ' multiplier: ' + multiplier); |
|
1967 // dataRecord.starter_viability |
|
1968 var yeast_grams = Round(volume * multiplier * (100 / dataRecord.starter_viability), 2); |
|
1969 $('#yeast_grams').val(yeast_grams); |
|
1970 var yeast_gr_hl = Round(yeast_grams / (volume * 0.01), 2); |
|
1971 $('#yeast_gr_hl').val(yeast_gr_hl); |
|
1972 //console.log('need ' + yeast_grams + ' grams, gr/hl: ' + yeast_gr_hl); |
|
1973 |
|
1974 } else { |
|
1975 // Liquid yeast |
|
1976 $('.primary_liquid').show(); |
|
1977 // pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/ |
|
1978 // and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ |
|
1979 if (row.y_type == 0) { // lager yeast |
|
1980 pitchrate = 1.5; |
|
1981 if (dataRecord.est_og > 1.060) |
|
1982 pitchrate = 2.0; |
|
1983 } else if (row.y_type == 6) { // Kveik |
|
1984 pitchrate = 0.075; |
|
1985 } else { |
|
1986 pitchrate = 0.75; |
|
1987 if (dataRecord.est_og > 1.060) |
|
1988 pitchrate = 1.0; |
|
1989 } |
|
1990 if (dataRecord.yeast_pitchrate < 0.01) { |
|
1991 dataRecord.yeast_pitchrate = pitchrate; |
|
1992 $('#yeast_pitchrate').val(pitchrate); |
|
1993 } |
|
1994 maybe_starter = 1; |
|
1995 } |
|
1996 } |
|
1997 } |
|
1998 |
|
1999 needed = Round(dataRecord.yeast_pitchrate * volume * plato, 1); |
|
2000 $('#need_cells').val(needed); |
|
2001 use_cells = initcells; |
|
2002 if (needed <= initcells) |
|
2003 maybe_starter = 0; |
|
2004 //console.log('calcYeast() pitchrate:' + dataRecord.yeast_pitchrate + ' start:' + initcells + ' needed:' + needed + ' volume:' + volume + ' maybe_starter:' + maybe_starter); |
|
2005 |
|
2006 if (maybe_starter != dataRecord.starter_enable) { |
|
2007 dataRecord.starter_enable = maybe_starter; |
|
2008 } |
|
2009 if (maybe_starter) |
|
2010 $('#propagator').show(); |
|
2011 else |
|
2012 $('#propagator').hide(); |
|
2013 |
|
2014 if (dataRecord.starter_enable) { |
|
2015 |
|
2016 calcSteps(dataRecord.starter_type, initcells, needed); |
|
2017 |
|
2018 for (i = 1; i < 5; i++) { |
|
2019 $('#r' + i + '_irate').html(''); |
|
2020 $('#r' + i + '_growf').html(''); |
|
2021 $('#r' + i + '_tcells').html(''); |
|
2022 if (parseFloat($('#prop' + i + '_volume').val()) > 0) { |
|
2023 if ((parseFloat($('#prop' + i + '_irate').val()) < 25) || (parseFloat($('#prop' + i + '_irate').val()) > 100)) { |
|
2024 $('#r' + i + '_irate').html("<img src='images/dialog-error.png'>"); |
|
2025 } else { |
|
2026 $('#r' + i + '_irate').html("<img src='images/dialog-ok-apply.png'>"); |
|
2027 } |
|
2028 if (parseFloat($('#prop' + i + '_growf').val()) < 1) |
|
2029 $('#r' + i + '_growf').html("<img src='images/dialog-error.png'>"); |
|
2030 if (($('#prop' + i + '_type').val() > 0) && (parseFloat($('#prop' + i + '_growf').val()) > 3)) |
|
2031 $('#r' + i + '_growf').html("<img src='images/dialog-error.png'>"); |
|
2032 if (parseFloat($('#prop' + i + '_tcells').val()) > needed) |
|
2033 $('#r' + i + '_tcells').html("<img src='images/dialog-ok-apply.png'>"); |
|
2034 use_cells = parseFloat($('#prop' + i + '_tcells').val()); |
|
2035 } else { |
|
2036 $('#r' + i + '_irate').html(''); |
|
2037 } |
|
2038 } |
|
2039 } |
|
2040 $('#plato_cells').val(parseFloat(use_cells / (volume * plato))); |
|
2041 }; |
|
2042 |
|
2043 function whirlpoolHops() { |
|
2044 var row, i, time, rowscount = dataRecord.hops.length; |
|
2045 if (rowscount == 0) |
|
2046 return; |
|
2047 for (i = 0; i < rowscount; i++) { |
|
2048 row = dataRecord.hops[i]; |
|
2049 if (row.h_useat == 4) { |
|
2050 time = parseFloat(dataRecord.brew_whirlpool9) + parseFloat(dataRecord.brew_whirlpool7) + parseFloat(dataRecord.brew_whirlpool6); |
|
2051 dataRecord.hops[i].h_time = time; |
|
2052 $('#hopGrid').jqxGrid('setcellvalue', i, 'h_time', time); |
|
2053 } |
|
2054 } |
|
2055 }; |
|
2056 |
|
2057 function calcMiscs() { |
|
2058 |
|
2059 ok_miscs = 1; |
|
2060 var row, i, rowscount = dataRecord.miscs.length; |
|
2061 if (rowscount == 0) |
|
2062 return; |
|
2063 for (i = 0; i < rowscount; i++) { |
|
2064 row = dataRecord.miscs[i]; |
|
2065 if ((((dataRecord.inventory_reduced <= 2) && (row.m_use_use <= 2)) || // Starter, Mash, Boil |
|
2066 ((dataRecord.inventory_reduced <= 2) && (row.m_use_use == 6)) || // Sparge |
|
2067 ((dataRecord.inventory_reduced <= 3) && (row.m_use_use == 3)) || // Primary |
|
2068 ((dataRecord.inventory_reduced <= 5) && (row.m_use_use == 4)) || // Secondary, Teriary |
|
2069 ((dataRecord.inventory_reduced <= 6) && (row.m_use_use == 5))) && // Bottle |
|
2070 (row.m_inventory < row.m_amount)) { |
|
2071 ok_miscs = 0; |
|
2072 } |
|
2073 } |
|
2074 calcSupplies(); |
|
2075 }; |
|
2076 |
|
2077 function GetBUGU() { |
|
2078 var gu = (dataRecord.est_og - 1) * 1000; |
|
2079 if (gu > 0) |
|
2080 return dataRecord.est_ibu / gu; |
|
2081 else |
|
2082 return 0.5; |
|
2083 } |
|
2084 |
|
2085 function GetOptSO4Clratio() { |
|
2086 var BUGU = GetBUGU(); |
|
2087 return (1.0 / (-1.2 * BUGU + 1.4)); |
|
2088 } |
|
2089 |
|
2090 function setWaterAgent(name, amount, use) { |
|
2091 var row, i, id, found = false, miscs, rows = $('#miscGrid').jqxGrid('getrows'); |
|
2092 if (amount == 0) { |
|
2093 for (i = 0; i < rows.length; i++) { |
|
2094 row = rows[i]; |
|
2095 if (row.m_name == name && row.m_use_use == use) { |
|
2096 id = $('#miscGrid').jqxGrid('getrowid', i); |
|
2097 $('#miscGrid').jqxGrid('deleterow', id); |
|
2098 } |
|
2099 } |
|
2100 } else { |
|
2101 for (i = 0; i < rows.length; i++) { |
|
2102 row = rows[i]; |
|
2103 if (row.m_name == name && row.m_use_use == use) { |
|
2104 found = true; |
|
2105 $('#miscGrid').jqxGrid('setcellvalue', i, 'm_amount', amount / 1000); |
|
2106 break; |
|
2107 } |
|
2108 } |
|
2109 if (! found) { |
|
2110 miscs = new $.jqx.dataAdapter(miscInvSource, { |
|
2111 loadComplete: function() { |
|
2112 var record, i, row = {}, records = miscs.records; |
|
2113 for (i = 0; i < records.length; i++) { |
|
2114 record = records[i]; |
|
2115 if (record.name == name) { |
|
2116 row['m_name'] = record.name; |
|
2117 row['m_amount'] = amount / 1000; |
|
2118 row['m_cost'] = record.cost; |
|
2119 row['m_type'] = record.type; |
|
2120 row['m_use_use'] = use; |
|
2121 row['m_time'] = 0; |
|
2122 row['m_amount_is_weight'] = record.amount_is_weight; |
|
2123 row['m_inventory'] = record.inventory; |
|
2124 row['m_avail'] = 1; |
|
2125 $('#miscGrid').jqxGrid('addrow', null, row); |
|
2126 } |
|
2127 } |
|
2128 } |
|
2129 }); |
|
2130 miscs.dataBind(); |
|
2131 return; |
|
2132 } |
|
2133 } |
|
2134 } |
|
2135 |
|
2136 function setRangeIndicator(ion, rangeCode) { |
|
2137 if ((rangeCode == 'laag') || (rangeCode == 'hoog')) |
|
2138 $('#wr_' + ion).html("<img src='images/dialog-error.png'><span style='vertical-align: top; font-size: 10px; font-style: italic;'>" + rangeCode + '</span>'); |
|
2139 else |
|
2140 $('#wr_' + ion).html("<img src='images/dialog-ok-apply.png'>"); |
|
2141 } |
|
2142 |
|
2143 function mix(v1, v2, c1, c2) { |
|
2144 if ((v1 + v2) > 0) { |
|
2145 return ((v1 * c1) + (v2 * c2)) / (v1 + v2); |
|
2146 } |
|
2147 return 0; |
|
2148 } |
|
2149 |
|
2150 function PartCO3(pH) { |
|
2151 var H = Math.pow(10, -pH); |
|
2152 return 100 * Ka1 * Ka2 / (H * H + H * Ka1 + Ka1 * Ka2); |
|
2153 } |
|
2154 |
|
2155 function PartHCO3(pH) { |
|
2156 var H = Math.pow(10, -pH); |
|
2157 return 100 * Ka1 * H / (H * H + H * Ka1 + Ka1 * Ka2); |
|
2158 } |
|
2159 |
|
2160 function Charge(pH) { |
|
2161 return (-2 * PartCO3(pH) - PartHCO3(pH)); |
|
2162 } |
|
2163 |
|
2164 //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) |
|
2165 function ZAlkalinity(pHZ) { |
|
2166 var C43 = Charge(4.3), |
|
2167 Cw = Charge(parseFloat($('#wg_ph').jqxNumberInput('decimal'))), |
|
2168 Cz = Charge(pHZ), |
|
2169 DeltaCNaught = -C43 + Cw, |
|
2170 CT = parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) / 50 / DeltaCNaught, |
|
2171 DeltaCZ = -Cz + Cw; |
|
2172 return CT * DeltaCZ; |
|
2173 } |
|
2174 |
|
2175 //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) |
|
2176 function ZRA(pHZ) { |
|
2177 |
|
2178 var Magn, Z, Calc = parseFloat($('#wg_calcium').jqxNumberInput('decimal')) / (MMCa / 2); |
|
2179 Magn = parseFloat($('#wg_magnesium').jqxNumberInput('decimal')) / (MMMg / 2); |
|
2180 Z = ZAlkalinity(pHZ); |
|
2181 return Z - (Calc / 3.5 + Magn / 7); |
|
2182 } |
|
2183 |
|
2184 function BufferCapacity(di_ph, acid_to_ph_57, ebc, graintype) { |
|
2185 C1 = 0; |
|
2186 if ((di_ph != 5.7) && ((acid_to_ph_57 < - 0.1) || (acid_to_ph_57 > 0.1))) { |
|
2187 C1 = acid_to_ph_57 / (di_ph - 5.7); |
|
2188 } else { |
|
2189 // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid. |
|
2190 switch (graintype) { |
|
2191 case 0: // Base, Special, Kilned |
|
2192 case 3: |
|
2193 case 5: C1 = 0.014 * ebc - 34.192; |
|
2194 break; |
|
2195 case 2: C1 = -0.0597 * ebc - 32.457; // Crystal |
|
2196 break; |
|
2197 case 1: C1 = 0.0107 * ebc - 54.768; // Roast |
|
2198 break; |
|
2199 case 4: C1 = -149; // Sour malt |
|
2200 break; |
|
2201 } |
|
2202 } |
|
2203 return C1; |
|
2204 } |
|
2205 |
|
2206 function ProtonDeficit(pHZ) { |
|
2207 |
|
2208 var i, C1, x, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal')); |
|
2209 // proton deficit for the grist |
|
2210 if (( $('#fermentableGrid').jqxGrid('getrows'))) { |
|
2211 for (i = 0; i < dataRecord.fermentables.length; i++) { |
|
2212 row = dataRecord.fermentables[i]; |
|
2213 if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt |
|
2214 C1 = BufferCapacity(row.f_di_ph, row.f_acid_to_ph_57, row.f_color, row.f_graintype); |
|
2215 x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH) |
|
2216 Result += x * row.f_amount; |
|
2217 } |
|
2218 } |
|
2219 } else { |
|
2220 error_count++; |
|
2221 if (error_count < 5) |
|
2222 console.log('ProtonDeficit(' + pHZ + ') invalid grist, return ' + Result); |
|
2223 } |
|
2224 return Result; |
|
2225 } |
|
2226 |
|
2227 function MashpH() { |
|
2228 |
|
2229 var n = 0, pH = 5.4, deltapH = 0.001, deltapd = 0.1, pd = ProtonDeficit(pH); |
|
2230 while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) { |
|
2231 n++; |
|
2232 if (pd < -deltapd) |
|
2233 pH -= deltapH; |
|
2234 else if (pd > deltapd) |
|
2235 pH += deltapH; |
|
2236 pd = ProtonDeficit(pH); |
|
2237 } |
|
2238 pH = Round(pH, 6); |
|
2239 //console.log('MashpH() n: ' + n + ' pH: ' + pH); |
|
2240 return pH; |
|
2241 } |
|
2242 |
|
2243 function calcWater() { |
|
2244 |
|
2245 /* Can be called during loading and building the screens */ |
|
2246 if (! data_loaded) { |
|
2247 console.log('calcWater() failsave'); |
|
2248 return; |
|
2249 } |
|
2250 |
|
2251 var liters = 0, |
|
2252 calcium = 0, |
|
2253 magnesium = 0, |
|
2254 sodium = 0, |
|
2255 total_alkalinity = 0, |
|
2256 chloride = 0, |
|
2257 sulfate = 0, |
|
2258 ph = 0, |
|
2259 RA = 0, |
|
2260 frac = 0, |
|
2261 TpH = 0, |
|
2262 protonDeficit = 0, |
|
2263 AT, /*BT,*/ |
|
2264 r1d, r2d, f1d, f2d, f3d, |
|
2265 deltapH, deltapd, pd, n, |
|
2266 Res; |
|
2267 |
|
2268 if (dataRecord.w1_name == '') { |
|
2269 return; |
|
2270 } |
|
2271 |
|
2272 $('#w1_hardness').val(Hardness(dataRecord.w1_calcium, dataRecord.w1_magnesium)); |
|
2273 $('#w1_ra').val(ResidualAlkalinity(dataRecord.w1_total_alkalinity, dataRecord.w1_calcium, dataRecord.w1_magnesium)); |
|
2274 |
|
2275 // If there is a dillute water source, mix the waters. |
|
2276 if ((dataRecord.w2_name != '') && (dataRecord.w2_name != 'Geen mengwater')) { |
|
2277 liters = dataRecord.w1_amount + dataRecord.w2_amount; |
|
2278 calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium); |
|
2279 magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium); |
|
2280 sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium); |
|
2281 chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride); |
|
2282 sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate); |
|
2283 total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity); |
|
2284 ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters); |
|
2285 $('#w2_hardness').val(Hardness(dataRecord.w2_calcium, dataRecord.w2_magnesium)); |
|
2286 $('#w2_ra').val(ResidualAlkalinity(dataRecord.w2_total_alkalinity, dataRecord.w2_calcium, dataRecord.w2_magnesium)); |
|
2287 } else { |
|
2288 liters = dataRecord.w1_amount; |
|
2289 calcium = dataRecord.w1_calcium; |
|
2290 magnesium = dataRecord.w1_magnesium; |
|
2291 sodium = dataRecord.w1_sodium; |
|
2292 chloride = dataRecord.w1_chloride; |
|
2293 sulfate = dataRecord.w1_sulfate; |
|
2294 total_alkalinity = dataRecord.w1_total_alkalinity; |
|
2295 ph = dataRecord.w1_ph; |
|
2296 } |
|
2297 var bicarbonate = Bicarbonate(total_alkalinity, ph); |
|
2298 |
|
2299 /* Save mixed water ions for later */ |
|
2300 var wg_calcium = calcium; |
|
2301 var wg_sodium = sodium; |
|
2302 var wg_total_alkalinity = total_alkalinity; |
|
2303 var wg_chloride = chloride; |
|
2304 var wg_sulfate = sulfate; |
|
2305 var wg_bicarbonate = bicarbonate; |
|
2306 |
|
2307 dataRecord.wg_amount = liters; |
|
2308 dataRecord.wg_ph = ph; |
|
2309 |
|
2310 $('#wg_amount').val(liters); |
|
2311 $('#wg_calcium').val(Round(calcium, 1)); |
|
2312 $('#wg_magnesium').val(Round(magnesium, 1)); |
|
2313 $('#wg_sodium').val(Round(sodium, 1)); |
|
2314 $('#wg_bicarbonate').val(Round(bicarbonate, 1)); |
|
2315 $('#wg_total_alkalinity').val(Round(total_alkalinity, 1)); |
|
2316 $('#wg_chloride').val(Round(chloride, 1)); |
|
2317 $('#wg_sulfate').val(Round(sulfate, 1)); |
|
2318 $('#wg_ph').val(Round(ph, 2)); |
|
2319 $('#wg_hardness').val(Round(Hardness(calcium, magnesium), 1)); |
|
2320 $('#wg_ra').val(Round(ResidualAlkalinity(total_alkalinity, calcium, magnesium), 1)); |
|
2321 |
|
2322 var mash_ph = Round(MashpH(), 3); |
|
2323 console.log('Distilled water mash pH: ' + mash_ph); |
|
2324 |
|
2325 /* Calculate Salt additions */ |
|
2326 if (liters > 0) { |
|
2327 calcium += (parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + |
|
2328 parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000 + |
|
2329 parseFloat($('#wa_caco3').jqxNumberInput('decimal')) * MMCa / MMCaCO3 * 1000) / liters; |
|
2330 magnesium += (parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + |
|
2331 parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / liters; |
|
2332 sodium += (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 + |
|
2333 parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters; |
|
2334 sulfate += (parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + |
|
2335 parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / liters; |
|
2336 chloride += (2 * parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + |
|
2337 parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + |
|
2338 parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / liters; |
|
2339 bicarbonate += (parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3 * 1000 + |
|
2340 parseFloat($('#wa_caco3').jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3 * 1000) / liters; |
|
2341 } |
|
2342 |
|
2343 if (dataRecord.wa_acid_name < 0 || dataRecord,wa_acid_name >= AcidTypeData.length) { |
|
2344 $('#wa_acid_name').val(0); |
|
2345 dataRecord.wa_acid_name = 0; |
|
2346 dataRecord.wa_acid_perc = AcidTypeData[0].AcidPrc; |
|
2347 $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); |
|
2348 } |
|
2349 if (last_acid == '') |
|
2350 last_acid = AcidTypeData[dataRecord.wa_acid_name].nl; |
|
2351 |
|
2352 if (parseFloat(dataRecord.wa_acid_perc) == 0) { |
|
2353 dataRecord.wa_acid_perc = AcidTypeData[AT].AcidPrc; |
|
2354 $('#wa_acid_perc').val(AcidTypeData[AT].AcidPrc); |
|
2355 } |
|
2356 |
|
2357 AT = dataRecord.wa_acid_name; |
|
2358 |
|
2359 /* Note that the next calculations do not correct the pH change by the added salts. |
|
2360 This pH change is at most 0.1 pH and is a minor difference in Acid amount. */ |
|
2361 |
|
2362 if (dataRecord.calc_acid) { |
|
2363 /* Auto calculate pH */ |
|
2364 $('.c_mashph').show(); |
|
2365 TpH = parseFloat(dataRecord.mash_ph); |
|
2366 protonDeficit = ProtonDeficit(TpH); |
|
2367 //console.log('calc_acid tgt: ' + TpH + ' protonDeficit: ' + protonDeficit); |
|
2368 if (protonDeficit > 0) { // Add acid |
|
2369 frac = CalcFrac(TpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); |
|
2370 Acid = protonDeficit / frac; |
|
2371 Acid *= AcidTypeData[AT].MolWt; // mg |
|
2372 Acidmg = Acid; |
|
2373 var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (parseFloat(dataRecord.wa_acid_perc) / 100)) + 1000, 2); |
|
2374 Acid /= RealSG; |
|
2375 Acid /= AcidTypeData[AT].AcidPrc / 100; |
|
2376 Acid = Round(Acid, 2); |
|
2377 console.log('Mash auto Acid final ml: ' + Acid); |
|
2378 $('#wa_acid').val(Acid); |
|
2379 setWaterAgent(AcidTypeData[AT].nl, Acid, 1); |
|
2380 |
|
2381 bicarbonate = bicarbonate - protonDeficit * frac / liters; |
|
2382 total_alkalinity = bicarbonate * 50 / 61; |
|
2383 } |
|
2384 ph = TpH; |
|
2385 dataRecord.wb_ph = ph; |
|
2386 $('#wb_ph').val(Round(ph, 2)); |
|
2387 $('#est_mash_ph').val(Round(ph, 2)); |
|
2388 } else { |
|
2389 /* Manual calculate pH */ |
|
2390 $('.c_mashph').hide(); |
|
2391 console.log('calc_acid no'); |
|
2392 pHa = Round(ph, 3); // Adjusted water pH |
|
2393 // Then calculate the new pH with added acids and malts |
|
2394 console.log('Mash pH: ' + pHa); |
|
2395 Acid = AcidTypeData[AT].AcidSG * (parseFloat(dataRecord.wa_acid_perc) / 100); // ml |
|
2396 Acid *= parseFloat($('#wa_acid').jqxNumberInput('decimal')); |
|
2397 Acid /= AcidTypeData[AT].MolWt; // mg |
|
2398 Acidmg = Acid; |
|
2399 |
|
2400 //find the pH where the protondeficit = protondeficit by the acid |
|
2401 frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); |
|
2402 protonDeficit = Round(Acid * frac, 3); |
|
2403 //console.log('protonDeficit Acid: ' + protonDeficit + ' frac: ' + frac + ' pH: ' + pHa); |
|
2404 |
|
2405 deltapH = 0.001; |
|
2406 deltapd = 0.1; |
|
2407 pd = Round(ProtonDeficit(pHa), 6); |
|
2408 n = 0; |
|
2409 while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 4000)) { |
|
2410 n++; |
|
2411 if (pd < (protonDeficit - deltapd)) |
|
2412 pHa -= deltapH; |
|
2413 else if (pd > (protonDeficit + deltapd)) |
|
2414 pHa += deltapH; |
|
2415 frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); |
|
2416 protonDeficit = Acid * frac; |
|
2417 pd = ProtonDeficit(pHa); |
|
2418 } |
|
2419 //console.log('n: ' + n + ' pd: ' + pd + ' protonDeficit: ' + protonDeficit + ' frac: ' + frac + ' pHa: ' + pHa); |
|
2420 bicarbonate = wg_bicarbonate - protonDeficit * frac / liters; |
|
2421 total_alkalinity = bicarbonate * 50 / 61; |
|
2422 ph = pHa; |
|
2423 $('#wb_ph').val(Round(ph, 2)); |
|
2424 $('#est_mash_ph').val(Round(ph, 2)); |
|
2425 } |
|
2426 |
|
2427 if ((AT == 3) && (liters > 0)) { // Sulfuric / Zwavelzuur |
|
2428 RA = parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + |
|
2429 parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 + |
|
2430 Acidmg / 1000 * MMSO4 / (MMSO4 + 2); |
|
2431 RA = 1000 * RA / liters; |
|
2432 sulfate = wg_sulfate + RA; // Not add to sulfate?? |
|
2433 } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur |
|
2434 RA = parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 + |
|
2435 parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl + |
|
2436 Acidmg / 1000 * MMCl / (MMCl + 1); |
|
2437 RA = 1000 * RA / liters; |
|
2438 chloride = wg_chloride + RA; |
|
2439 } |
|
2440 |
|
2441 var BUGU = GetBUGU(); |
|
2442 $('#tgt_bu').val(Round(BUGU, 2)); |
|
2443 // From brouwhulp. |
|
2444 if (BUGU < 0.32) |
|
2445 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig en zoet</span>"); |
|
2446 else if (BUGU < 0.43) |
|
2447 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig, zoet</span>"); |
|
2448 else if (BUGU < 0.52) |
|
2449 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Evenwichtig</span>"); |
|
2450 else if (BUGU < 0.63) |
|
2451 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht hoppig, bitter</span>"); |
|
2452 else |
|
2453 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Extra hoppig, zeer bitter</span>"); |
|
2454 |
|
2455 // Sulfate to Chloride ratio (Palmer). |
|
2456 var OptSO4Clratio = GetOptSO4Clratio(); |
|
2457 $('#tgt_so4_cl').val(Round(OptSO4Clratio, 1)); |
|
2458 if (OptSO4Clratio < 0.4) |
|
2459 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Te moutig</span>"); |
|
2460 else if (OptSO4Clratio < 0.6) |
|
2461 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig</span>"); |
|
2462 else if (OptSO4Clratio < 0.8) |
|
2463 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig</span>"); |
|
2464 else if (OptSO4Clratio < 1.5) |
|
2465 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Gebalanceerd</span>"); |
|
2466 else if (OptSO4Clratio < 2.0) |
|
2467 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht bitter</span>"); |
|
2468 else if (OptSO4Clratio < 4.0) |
|
2469 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Bitter</span>"); |
|
2470 else if (OptSO4Clratio < 9.0) |
|
2471 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer bitter</span>"); |
|
2472 else |
|
2473 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Te bitter</span>"); |
|
2474 if (chloride > 0) |
|
2475 RA = sulfate / chloride; |
|
2476 else |
|
2477 RA = 10; |
|
2478 $('#got_so4_cl').val(Round(RA, 1)); |
|
2479 Res = 'normaal'; |
|
2480 if (RA < (0.8 * OptSO4Clratio)) |
|
2481 Res = 'laag'; |
|
2482 else if (RA > (1.2 * OptSO4Clratio)) |
|
2483 Res = 'hoog'; |
|
2484 setRangeIndicator('so4_cl', Res); |
|
2485 |
|
2486 $('#wb_calcium').val(Round(calcium, 1)); |
|
2487 $('#wb_magnesium').val(Round(magnesium, 1)); |
|
2488 $('#wb_sodium').val(Round(sodium, 1)); |
|
2489 $('#wb_sulfate').val(Round(sulfate, 1)); |
|
2490 $('#wb_chloride').val(Round(chloride, 1)); |
|
2491 $('#wb_bicarbonate').val(Round(bicarbonate, 1)); |
|
2492 $('#wb_total_alkalinity').val(Round(total_alkalinity, 1)); |
|
2493 $('#wb_hardness').val(Hardness(calcium, magnesium)); |
|
2494 $('#wb_ra').val(ResidualAlkalinity(total_alkalinity, calcium, magnesium)); |
|
2495 |
|
2496 if (calcium < 40) { |
|
2497 setRangeIndicator('calcium', 'laag'); |
|
2498 } else if (calcium > 150) { |
|
2499 setRangeIndicator('calcium', 'hoog'); |
|
2500 } else { |
|
2501 setRangeIndicator('calcium', 'normaal'); |
|
2502 } |
|
2503 if (magnesium < 5) { |
|
2504 setRangeIndicator('magnesium', 'laag'); |
|
2505 } else if (magnesium > 40) { |
|
2506 setRangeIndicator('magnesium', 'hoog'); |
|
2507 } else { |
|
2508 setRangeIndicator('magnesium', 'normaal'); |
|
2509 } |
|
2510 if (sodium <= 150) { |
|
2511 setRangeIndicator('sodium', 'normaal'); |
|
2512 } else { |
|
2513 setRangeIndicator('sodium', 'hoog'); |
|
2514 } |
|
2515 // Both chloride and sulfate should be above 50 according to |
|
2516 // John Palmer. So the Cl/SO4 ratio calculation will work. |
|
2517 if (chloride <= 50) { |
|
2518 setRangeIndicator('chloride', 'laag'); |
|
2519 } else if (chloride <= 150) { |
|
2520 setRangeIndicator('chloride', 'normaal'); |
|
2521 } else { |
|
2522 setRangeIndicator('chloride', 'hoog'); |
|
2523 } |
|
2524 if (sulfate <= 50) { |
|
2525 setRangeIndicator('sulfate', 'laag'); |
|
2526 } else if (sulfate <= 400) { |
|
2527 setRangeIndicator('sulfate', 'normaal'); |
|
2528 } else { |
|
2529 setRangeIndicator('sulfate', 'hoog'); |
|
2530 } |
|
2531 // (cloride + sulfate) > 500 is too high |
|
2532 if ((chloride + sulfate) > 500) { |
|
2533 setRangeIndicator('chloride', 'hoog'); |
|
2534 setRangeIndicator('sulfate', 'hoog'); |
|
2535 } |
|
2536 if (ph < 5.2) { |
|
2537 setRangeIndicator('ph', 'laag'); |
|
2538 } else if (ph > 5.6) { |
|
2539 setRangeIndicator('ph', 'hoog'); |
|
2540 } else { |
|
2541 setRangeIndicator('ph', 'normaal'); |
|
2542 } |
|
2543 if (bicarbonate > 250) { |
|
2544 setRangeIndicator('bicarbonate', 'hoog'); |
|
2545 } else { |
|
2546 setRangeIndicator('bicarbonate', 'normaal'); |
|
2547 } |
|
2548 calcSparge(); |
|
2549 calcMiscs(); |
|
2550 calcSupplies(); |
|
2551 } |
|
2552 |
|
2553 function calcSparge() { |
|
2554 |
|
2555 /* Based on the work of ajDeLange. */ |
|
2556 var ws_calcium, ws_magnesium, ws_total_alkalinity, ws_sodium, ws_chloride; |
|
2557 var ws_sulfate, ws_ph, ws_hardness, ws_ra; |
|
2558 var TargetpH = dataRecord.sparge_ph; |
|
2559 var Source_pH = 7.0; |
|
2560 |
|
2561 // Select watersource or fallback to the first source. |
|
2562 if ((dataRecord.sparge_source == 1) && (dataRecord.w2_ph > 0.0)) { // Source 2 |
|
2563 ws_calcium = dataRecord.w2_calcium; |
|
2564 ws_magnesium = dataRecord.w2_magnesium; |
|
2565 ws_total_alkalinity = dataRecord.w2_total_alkalinity; |
|
2566 ws_sodium = dataRecord.w2_sodium; |
|
2567 ws_chloride = dataRecord.w2_chloride; |
|
2568 ws_sulfate = dataRecord.w2_sulfate; |
|
2569 Source_pH = dataRecord.w2_ph; |
|
2570 $('#w2_button').jqxRadioButton({ checked: true }); |
|
2571 } else if ((dataRecord.sparge_source == 2) && (dataRecord.w2_ph > 0.0)) { // Mixed |
|
2572 ws_calcium = dataRecord.wg_calcium; |
|
2573 ws_magnesium = dataRecord.wg_magnesium; |
|
2574 ws_total_alkalinity = dataRecord.wg_total_alkalinity; |
|
2575 ws_sodium = dataRecord.wg_sodium; |
|
2576 ws_chloride = dataRecord.wg_chloride; |
|
2577 ws_sulfate = dataRecord.wg_sulfate; |
|
2578 Source_pH = dataRecord.wg_ph; |
|
2579 $('#wg_button').jqxRadioButton({ checked: true }); |
|
2580 } else { |
|
2581 ws_calcium = dataRecord.w1_calcium; |
|
2582 ws_magnesium = dataRecord.w1_magnesium; |
|
2583 ws_total_alkalinity = dataRecord.w1_total_alkalinity; |
|
2584 ws_sodium = dataRecord.w1_sodium; |
|
2585 ws_chloride = dataRecord.w1_chloride; |
|
2586 ws_sulfate = dataRecord.w1_sulfate; |
|
2587 Source_pH = dataRecord.w1_ph; |
|
2588 $('#w1_button').jqxRadioButton({ checked: true }); |
|
2589 } |
|
2590 |
|
2591 if (dataRecord.sparge_volume > 0) { |
|
2592 ws_calcium += (parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + |
|
2593 parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000) / dataRecord.sparge_volume; |
|
2594 ws_magnesium += (parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + |
|
2595 parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / dataRecord.sparge_volume; |
|
2596 ws_sodium += (parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000) / dataRecord.sparge_volume; |
|
2597 ws_sulfate += (parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + |
|
2598 parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / dataRecord.sparge_volume; |
|
2599 ws_chloride += (2 * parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + |
|
2600 parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + |
|
2601 parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / dataRecord.sparge_volume; |
|
2602 } |
|
2603 |
|
2604 /* Show the spargewate with salt additions */ |
|
2605 $('#sw_calcium').val(Round(ws_calcium, 1)); |
|
2606 $('#sw_magnesium').val(Round(ws_magnesium, 1)); |
|
2607 $('#sw_sodium').val(Round(ws_sodium, 1)); |
|
2608 $('#sw_sulfate').val(Round(ws_sulfate, 1)); |
|
2609 $('#sw_chloride').val(Round(ws_chloride, 1)); |
|
2610 $('#sw_bicarbonate').val(Round(Bicarbonate(ws_total_alkalinity, Source_pH), 1)); |
|
2611 $('#sw_total_alkalinity').val(Round(ws_total_alkalinity, 1)); |
|
2612 $('#sw_ph').val(dataRecord.sparge_ph); |
|
2613 $('#sw_hardness').val(Hardness(ws_calcium, ws_magnesium)); |
|
2614 $('#sw_ra').val(ResidualAlkalinity(ws_total_alkalinity, ws_calcium, ws_magnesium)); |
|
2615 |
|
2616 AT = dataRecord.sparge_acid_type; |
|
2617 if (AT < 0 || AT >= AcidTypeData.length) { |
|
2618 AT = 0; |
|
2619 dataRecord.sparge_acid_type = 0; |
|
2620 $('#sparge_acid_type').val(AcidTypeData[0].nl); |
|
2621 dataRecord.sparge_acid_perc = AcidTypeData[0].AcidPrc; |
|
2622 $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); |
|
2623 } |
|
2624 |
|
2625 /* |
|
2626 * Auto calculate the required acid |
|
2627 */ |
|
2628 if (dataRecord.calc_acid) { |
|
2629 // Step 1: Compute the mole fractions of carbonic (f1) and carbonate(f3) at the source water pH |
|
2630 var r1 = Math.pow(10, Source_pH - 6.35); |
|
2631 var r2 = Math.pow(10, Source_pH - 10.33); |
|
2632 var d = 1 + r1 + r1 * r2; |
|
2633 var f1 = 1 / d; |
|
2634 var f3 = r1 * r2 / d; |
|
2635 |
|
2636 //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) |
|
2637 var r143 = Math.pow(10, 4.3 - 6.35); |
|
2638 var r243 = Math.pow(10, 4.3 - 10.33); |
|
2639 var d43 = 1 + r143 + r143 * r243; |
|
2640 var f143 = 1 / d43; |
|
2641 var f343 = r143 * r243 / d43; |
|
2642 |
|
2643 //Step 4. Solve |
|
2644 var Ct = ws_total_alkalinity / 50 / ((f143 - f1) + (f3 - f343)); |
|
2645 |
|
2646 //Step 5. Compute mole fractions at desired pH |
|
2647 var r1g = Math.pow(10, TargetpH - 6.35); |
|
2648 var r2g = Math.pow(10, TargetpH - 10.33); |
|
2649 var dg = 1 + r1g + r1g * r2g; |
|
2650 var f1g = 1 / dg; |
|
2651 var f3g = r1g * r2g / dg; |
|
2652 |
|
2653 //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L) |
|
2654 var Acid = Ct * ((f1g - f1) + (f3 - f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l |
|
2655 Acid += 0.01; // Add acid that would be required for distilled water. |
|
2656 |
|
2657 //Step 8. Get the acid data. |
|
2658 var fract = CalcFrac(TargetpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); |
|
2659 |
|
2660 //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. |
|
2661 Acid /= fract; |
|
2662 |
|
2663 //Step 10. Multiply by molecular weight of the acid |
|
2664 Acid *= AcidTypeData[AT].MolWt; //mg |
|
2665 |
|
2666 //Step 11. Divide by Specific Gravity and Percentage to get the final ml. |
|
2667 var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (dataRecord.sparge_acid_perc / 100)) + 1000, 2); |
|
2668 Acid = Acid / RealSG; //ml |
|
2669 Acid *= dataRecord.sparge_volume; //ml acid total at 100% |
|
2670 Acid /= AcidTypeData[AT].AcidPrc / 100; //ml acid at supplied strength |
|
2671 Acid = Round(Acid, 2); |
|
2672 dataRecord.sparge_acid_amount = Acid / 1000; |
|
2673 $('#sparge_acid_amount').val(Acid); |
|
2674 } |
|
2675 |
|
2676 // Finally calculate the estimate preboil pH |
|
2677 var ph = -Math.log10(((Math.pow(10, -dataRecord.wb_ph) * dataRecord.wg_amount) + (Math.pow(10, -dataRecord.sparge_ph) * dataRecord.sparge_volume)) / |
|
2678 (dataRecord.wg_amount + dataRecord.sparge_volume)); |
|
2679 $('#preboil_ph').val(ph); |
|
2680 } |
|
2681 |
|
2682 function calcFermentation() { |
|
2683 var primary_svg, secondary_svg, final_svg, ABV; |
|
2684 if (dataRecord.brew_fermenter_sg < 1.020) |
|
2685 return; |
|
2686 if ((dataRecord.primary_end_sg > 0.990) && (dataRecord.primary_end_sg < dataRecord.brew_fermenter_sg)) { |
|
2687 primary_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.primary_end_sg), 1); |
|
2688 $('#primary_svg').val(primary_svg); |
|
2689 if ((dataRecord.secondary_end_sg > 0.990) && (dataRecord.secondary_end_sg < dataRecord.brew_fermenter_sg)) { |
|
2690 secondary_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.secondary_end_sg), 1); |
|
2691 $('#secondary_svg').val(secondary_svg); |
|
2692 if ((dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { |
|
2693 final_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.fg), 1); |
|
2694 $('#final_svg').val(final_svg); |
|
2695 ABV = Round(abvol(dataRecord.brew_fermenter_sg, dataRecord.fg), 2); |
|
2696 $('#final_abv').val(ABV); |
|
2697 } |
|
2698 } |
|
2699 } |
|
2700 } |
|
2701 |
|
2702 function ResCO2(T) { |
|
2703 var F = T * 1.8 + 32; |
|
2704 return Round(3.0378 - 0.050062 * F + 0.00026555 * F * F, 6); |
|
2705 } |
|
2706 |
|
2707 function CarbCO2toS(CO2, T, SFactor) { |
|
2708 //var sugar = SFactor * (CO2 - ResCO2(CO2, T)) / 0.286; |
|
2709 var sugar = Round(SFactor * (CO2 - ResCO2(T)) * 4.014094, 6); |
|
2710 if (sugar < 0) |
|
2711 sugar = 0; |
|
2712 return Round(sugar, 3); |
|
2713 } |
|
2714 |
|
2715 function GetPressure(CO2, T1, T2) { |
|
2716 var P, V = CO2 - ResCO2(T1); |
|
2717 V = CO2; // TODO: temp only total pressure, testing |
|
2718 if (V < 0) |
|
2719 return 0; |
|
2720 P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V + |
|
2721 0.674996600795854 * V + -0.00471757220150754 * V * V; |
|
2722 if (P < 0) |
|
2723 P = 0; |
|
2724 P = Round(P * 1.01325, 2); // atm to bar |
|
2725 console.log("GetPressure(" + CO2 + ", " + T1 + ", " + T2 + ") V:" + V + " Bar: " + P + " ignored ResCO2: " + ResCO2(T1)); |
|
2726 return P; |
|
2727 } |
|
2728 |
|
2729 function CarbCO2ToPressure(CO2, T) { |
|
2730 return (CO2 - (-0.000005594056 * Math.pow(T, 4) + 0.000144357886 * Math.pow(T, 3) + |
|
2731 0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049)) / |
|
2732 (0.00000498031 * Math.pow(T, 4) - 0.00024358267 * Math.pow(T, 3) + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376); |
|
2733 } |
|
2734 |
|
2735 function calcCarbonation() { |
|
2736 |
|
2737 var TSec, ABV, bvol, balc, babv, mvol, malc, tvol, talc, i, row, SFactor, pvol, pabv, Pressure, kabv; |
|
2738 |
|
2739 console.log('calcCarbonation()'); |
|
2740 |
|
2741 TSec = dataRecord.secondary_temp; |
|
2742 if (TSec < 1) |
|
2743 TSec = dataRecord.primary_end_temp; |
|
2744 if (TSec < 1) |
|
2745 TSec = 18; |
|
2746 |
|
2747 if (dataRecord.fg == 0.000) |
|
2748 ABV = abvol(dataRecord.brew_fermenter_sg, parseFloat($('#est_fg').jqxNumberInput('decimal'))); |
|
2749 else |
|
2750 ABV = abvol(dataRecord.brew_fermenter_sg, dataRecord.fg); |
|
2751 |
|
2752 /* Calculate new volume and alcohol. */ |
|
2753 bvol = dataRecord.package_volume - (ABV * dataRecord.package_volume) / 100; |
|
2754 balc = dataRecord.package_volume - bvol; |
|
2755 mvol = dataRecord.package_infuse_amount - (dataRecord.package_infuse_abv * dataRecord.package_infuse_amount) / 100; |
|
2756 malc = dataRecord.package_infuse_amount - mvol; |
|
2757 talc = balc + malc; |
|
2758 tvol = bvol + mvol; |
|
2759 ABV = Round(talc / (tvol + talc) * 100, 2); |
|
2760 dataRecord.package_abv = ABV; |
|
2761 $('#package_abv').val(ABV); |
|
2762 |
|
2763 //console.log("calcCarbonation() TSec:"+TSec+" ABV:"+ABV); |
|
2764 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { |
|
2765 return; |
|
2766 } |
|
2767 |
|
2768 // Bottles |
|
2769 dataRecord.bottle_priming_amount = 0; |
|
2770 dataRecord.bottle_priming_total = 0; |
|
2771 for (i = 0; i < rows.length; i++) { |
|
2772 row = rows[i]; |
|
2773 if (row.f_added == 4) { |
|
2774 SFactor = 1 / ((row.f_yield / 100) * (1 - row.f_moisture / 100)); |
|
2775 dataRecord.bottle_priming_amount = CarbCO2toS(dataRecord.bottle_carbonation, TSec, SFactor); |
|
2776 dataRecord.bottle_priming_total = Round(dataRecord.bottle_amount * dataRecord.bottle_priming_amount, 2); |
|
2777 $('#fermentableGrid').jqxGrid('setcellvalue', i, 'f_amount', dataRecord.bottle_priming_total / 1000); |
|
2778 } |
|
2779 } |
|
2780 $('#bottle_priming_amount').val(Round(dataRecord.bottle_priming_amount, 1)); |
|
2781 $('#bottle_priming_total').val(dataRecord.bottle_priming_total); |
|
2782 pabv = ABV + dataRecord.bottle_priming_amount * 0.47 / 7.907; |
|
2783 pvol = dataRecord.bottle_amount - (pabv * dataRecord.bottle_amount) / 100; |
|
2784 talc = dataRecord.bottle_amount - pvol; |
|
2785 tvol = pvol + dataRecord.bottle_priming_water; |
|
2786 babv = Round(talc / (tvol + talc) * 100, 2); |
|
2787 //console.log("bottle pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.bottle_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+babv); |
|
2788 $('#bottle_abv').val(babv); |
|
2789 $('#bottle_pressure').val(GetPressure(dataRecord.bottle_carbonation, TSec, dataRecord.bottle_carbonation_temp)); |
|
2790 |
|
2791 // Kegs |
|
2792 Pressure = CarbCO2ToPressure(dataRecord.keg_carbonation, dataRecord.keg_carbonation_temp); |
|
2793 if (Pressure < 0) |
|
2794 Pressure = 0; |
|
2795 dataRecord.keg_pressure = Pressure; |
|
2796 $('#keg_pressure').val(Round(Pressure, 1)); |
|
2797 |
|
2798 dataRecord.keg_priming_amount = 0; |
|
2799 dataRecord.keg_priming_total = 0; |
|
2800 if (!dataRecord.keg_forced_carb) { |
|
2801 for (i = 0; i < rows.length; i++) { |
|
2802 row = rows[i]; |
|
2803 if (row.f_added == 5) { |
|
2804 SFactor = 1 / ((row.f_yield / 100) * (1 - row.f_moisture / 100)); |
|
2805 dataRecord.keg_priming_amount = CarbCO2toS(dataRecord.keg_carbonation, TSec, SFactor); |
|
2806 dataRecord.keg_priming_total = Round(dataRecord.keg_amount * dataRecord.keg_priming_amount, 2); |
|
2807 $('#fermentableGrid').jqxGrid('setcellvalue', i, 'f_amount', dataRecord.keg_priming_total / 1000); |
|
2808 } |
|
2809 } |
|
2810 $('#keg_priming_amount').val(Round(dataRecord.keg_priming_amount, 1)); |
|
2811 $('#keg_priming_total').val(dataRecord.keg_priming_total); |
|
2812 pabv = ABV + dataRecord.keg_priming_amount * 0.47 / 7.907; |
|
2813 pvol = dataRecord.keg_amount - (pabv * dataRecord.keg_amount) / 100; |
|
2814 talc = dataRecord.keg_amount - pvol; |
|
2815 tvol = pvol + dataRecord.keg_priming_water; |
|
2816 kabv = Round(talc / (tvol + talc) * 100, 2); |
|
2817 //console.log("kegs pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.keg_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+kabv); |
|
2818 $('#keg_abv').val(kabv); |
|
2819 } else { |
|
2820 $('#keg_priming_amount').val(0); |
|
2821 $('#keg_priming_total').val(0); |
|
2822 $('#keg_abv').val(ABV); |
|
2823 } |
|
2824 } |
|
2825 |
|
2826 function calcStage() { |
|
2827 /* |
|
2828 * Set stage and enable or disable parts of the screens. |
|
2829 */ |
|
2830 $('#stage').val(StageData[dataRecord.stage].nl); |
|
2831 |
|
2832 /* |
|
2833 * Enable or disable parts of the screens. |
|
2834 */ |
|
2835 $('#jqxTabs').jqxTabs((dataRecord.stage < 1) ? 'disableAt':'enableAt', 8); // Brewday tab |
|
2836 $('#jqxTabs').jqxTabs((dataRecord.stage > 2) ? 'enableAt':'disableAt', 9); // Fermentation tab |
|
2837 $('#jqxTabs').jqxTabs((dataRecord.stage < 9) ? 'disableAt':'enableAt', 11); // Tasting tab |
|
2838 } |
|
2839 |
|
2840 |
|
2841 // initialize the input fields. |
|
2842 // Tab 1, Algemeen |
|
2843 $('#name').jqxTooltip({ content: 'De naam voor dit product.' }); |
|
2844 $('#code').jqxTooltip({ content: 'Product code nummer.' }); |
|
2845 $('#birth').jqxTooltip({ content: 'De ontwerp datum van dit product.' }); |
|
2846 $('#stage').jqxTooltip({ content: 'De productie fase van dit product.' }); |
|
2847 $('#divide_batch').jqxTooltip({ content: 'Het aantal extra gesplitste batches.' }); |
|
2848 $('#divide_type').jqxTooltip({ content: 'Het splitsing moment in het productie proces.' }); |
|
2849 $('#notes').jqxTooltip({ content: 'De uitgebreide opmerkingen over dit product.' }); |
|
2850 $('#type').jqxTooltip({ content: 'Het brouw type van dit recept.' }); |
|
2851 $('#efficiency').jqxTooltip({ content: 'Het rendement van maischen en koken.' }); |
|
2852 $('#batch_size').jqxTooltip({ content: 'Het volume van het gekoelde wort na het koken.' }); |
|
2853 $('#boil_time').jqxTooltip({ content: 'De kooktijd in minuten.' }); |
|
2854 $('#boil_size').jqxTooltip({ content: 'Het volume van het wort voor het koken.' }); |
|
2855 $('#st_guide').jqxTooltip({ content: 'De bierstijl gids voor dit recept.'}); |
|
2856 $('#st_name').jqxTooltip({ content: 'De bierstijl naam voor dit recept.'}); |
|
2857 $('#st_letter').jqxTooltip({ content: 'De bierstijl letter voor dit recept.'}); |
|
2858 $('#st_letter').jqxInput({ theme: theme, width: 90, height: 23 }); |
|
2859 $('#st_type').jqxTooltip({ content: 'Het bierstijl type.'}); |
|
2860 $('#st_category').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie.'}); |
|
2861 $('#st_category_number').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie sub nummer.'}); |
|
2862 $('#est_og').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' }); |
|
2863 $('#st_og_min').jqxTooltip({ content: 'Het minimum begin SG voor deze bierstijl.'}); |
|
2864 $('#st_og_max').jqxTooltip({ content: 'Het maximum begin SG voor deze bierstijl.'}); |
|
2865 $('#est_fg').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); |
|
2866 $('#st_fg_min').jqxTooltip({ content: 'Het minimum eind SG voor deze bierstijl.'}); |
|
2867 $('#st_fg_max').jqxTooltip({ content: 'Het maximum eind SG voor deze bierstijl.'}); |
|
2868 $('#est_abv').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' }); |
|
2869 $('#st_abv_min').jqxTooltip({ content: 'Het minimum alcohol volume % voor deze bierstijl.'}); |
|
2870 $('#st_abv_max').jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'}); |
|
2871 $('#est_color').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); |
|
2872 $('#st_color_min').jqxTooltip({ content: 'De minimum kleur voor deze bierstijl.'}); |
|
2873 $('#st_color_max').jqxTooltip({ content: 'De maximum kleur voor deze bierstijl.'}); |
|
2874 $('#est_ibu').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); |
|
2875 $('#st_ibu_min').jqxTooltip({ content: 'De minimum bitterheid voor deze bierstijl.'}); |
|
2876 $('#st_ibu_max').jqxTooltip({ content: 'De maximum bitterheid voor deze bierstijl.'}); |
|
2877 $('#kcal').jqxTooltip({ content: 'Energie-inhoud in kcal/liter.' }); |
|
2878 $('#est_carb').jqxTooltip({ content: 'Koolzuur volume. Dit wordt automatisch berekend.' }); |
|
2879 $('#st_carb_min').jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'}); |
|
2880 $('#st_carb_max').jqxTooltip({ content: 'Het maximum koolzuur volume voor deze bierstijl.'}); |
|
2881 |
|
2882 $('#name').jqxInput({ theme: theme, width: 640, height: 23 }); |
|
2883 $('#code, #stage').jqxInput({ theme: theme, width: 100, height: 23 }); |
|
2884 $('#locked').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); |
|
2885 $('#birth,#divide_batch,#divide_type').jqxInput({ theme: theme, width: 120, height: 23 }); |
|
2886 $('#notes').jqxInput({ theme: theme, width: 960, height: 100 }); |
|
2887 $('#type').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
2888 $('#efficiency').jqxNumberInput(Show1dec); |
|
2889 $('#batch_size').jqxNumberInput(Show1dec); |
|
2890 $('#boil_time').jqxNumberInput(Show0dec); |
|
2891 $('#boil_size').jqxNumberInput(Show2dec); |
|
2892 $('#st_guide,#st_name,#st_type,#st_category').jqxInput({ theme: theme, width: 250, height: 23 }); |
|
2893 $('#est_og').jqxNumberInput(Show3dec); |
|
2894 $('#est_fg').jqxNumberInput(Show3dec); |
|
2895 $('#st_og_min,#st_og_max,#st_fg_min,#st_fg_max').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); |
|
2896 $('#est_ibu,#est_color').jqxNumberInput(Show0dec); |
|
2897 $('#color_method').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
2898 $('#st_color_min,#st_color_max,#st_category_number,#st_ibu_min,#st_ibu_max,#kcal').jqxNumberInput(Smal0dec); |
|
2899 $('#ibu_method').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
2900 $('#est_abv,#st_abv_min,#st_abv_max,#est_carb,#st_carb_min,#st_carb_max').jqxNumberInput(Smal1dec); |
|
2901 |
|
2902 // Tab 2, Equipment |
|
2903 $('#eq_name').jqxTooltip({ content: 'De naam van deze brouw apparatuur.' }); |
|
2904 $('#eq_boil_size').jqxTooltip({ content: 'Normaal kook volume in liters' }); |
|
2905 $('#eq_batch_size').jqxTooltip({ content: 'Berekende batch grootte in liters aan het eind van de kook.' }); |
|
2906 $('#eq_tun_volume').jqxTooltip({ content: 'Maisch ketel volume.' }); |
|
2907 $('#eq_top_up_water').jqxTooltip({ content: 'Extra water in het gistvat.' }); |
|
2908 $('#eq_trub_chiller_loss').jqxTooltip({ content: 'Standaard verlies bij het overbrengen naar het gistvat.' }); |
|
2909 $('#eq_evap_rate').jqxTooltip({ content: 'Verdamping in liters per uur.' }); |
|
2910 $('#eq_boil_time').jqxTooltip({ content: 'Normale kooktijd in minuten, 0 voor no-boil recepten.' }); |
|
2911 $('#eq_top_up_kettle').jqxTooltip({ content: 'Extra water toevoegen tijdens de kook.' }); |
|
2912 $('#eq_hop_utilization').jqxTooltip({ content: '100% voor kleine installaties, hoger voor grote brouwerijen.' }); |
|
2913 $('#eq_notes').jqxTooltip({ content: 'Opmerkingen over deze apparatuur.' }); |
|
2914 $('#eq_lauter_volume').jqxTooltip({ content: 'Filterkuip volume.' }); |
|
2915 $('#eq_lauter_deadspace').jqxTooltip({ content: 'Filterkuip verlies in liters.' }); |
|
2916 $('#eq_kettle_volume').jqxTooltip({ content: 'Kook ketel volume in liters.' }); |
|
2917 $('#eq_mash_volume').jqxTooltip({ content: 'Maisch water voor de eerste stap.' }); |
|
2918 $('#eq_mash_max').jqxTooltip({ content: 'De maximale moutstort in Kg.' }); |
|
2919 $('#eq_efficiency').jqxTooltip({ content: 'Gemiddeld brouwzaal rendement.' }); |
|
2920 |
|
2921 $('#eq_name').jqxInput({ theme: theme, width: 250, height: 23 }); |
|
2922 $('#eq_evap_rate').jqxNumberInput(Show2dec); |
|
2923 $('#eq_boil_time,#eq_hop_utilization').jqxNumberInput(Show0dec); |
|
2924 $('#eq_notes').jqxInput({ theme: theme, width: 960, height: 200 }); |
|
2925 $('#eq_boil_size,#eq_batch_size,#eq_tun_volume,#eq_top_up_water,#eq_trub_chiller_loss,#eq_top_up_kettle').jqxNumberInput(Show1dec); |
|
2926 $('#eq_lauter_volume,#eq_lauter_deadspace,#eq_kettle_volume,#eq_mash_volume,#eq_mash_max,#eq_efficiency').jqxNumberInput(Show1dec); |
|
2927 |
|
2928 // Tab 3, Fermentables |
|
2929 $('#est_color2').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); |
|
2930 $('#est_og2').jqxTooltip({ content: 'Het geschatte begin SG van dit product.' }); |
|
2931 $('#mash_kg').jqxTooltip({ content: 'Het gewicht van alle mouten in de maisch.' }); |
|
2932 |
|
2933 $('#est_color2').jqxNumberInput(Show0dec); |
|
2934 $('#est_og2,#mash_kg').jqxNumberInput(Show3dec); |
|
2935 |
|
2936 $('#perc_malts').jqxProgressBar({ |
|
2937 width: 300, height: 23, theme: theme, showText: true, max: 120, animationDuration: 0, |
|
2938 colorRanges: [{ stop: 90, color: '#008C00' },{ stop: 100, color: '#EB7331' },{ stop: 120, color: '#FF0000' }], |
|
2939 renderText: function(text) { return (Math.round(parseInt(text) * 1.2)) + '%'; } |
|
2940 }); |
|
2941 $('#perc_sugars').jqxProgressBar({ |
|
2942 width: 300, height: 23, theme: theme, showText: true, max: 50, animationDuration: 0, |
|
2943 colorRanges: [{ stop: 20, color: '#008C00' },{ stop: 50, color: '#FF0000' }], |
|
2944 renderText: function(text) { return (Math.round(parseInt(text) * 5) / 10) + '%'; } |
|
2945 }); |
|
2946 $('#perc_cara').jqxProgressBar({ |
|
2947 width: 300, height: 23, theme: theme, showText: true, max: 50, animationDuration: 0, |
|
2948 colorRanges: [{ stop: 25, color: '#008C00' },{ stop: 50, color: '#FF0000' }], |
|
2949 renderText: function(text) { return (Math.round(parseInt(text) * 5) / 10) + '%'; } |
|
2950 }); |
|
2951 $('#ferm_lintner').jqxProgressBar({ |
|
2952 width: 300, height: 23, theme: theme, showText: true, max: 200, animationDuration: 0, |
|
2953 colorRanges: [{ stop: 30, color: '#FF0000' },{ stop: 40, color: '#EB7331' },{ stop: 200, color: '#008C00' }], |
|
2954 renderText: function(text) { return (parseInt(text) * 2) + ' lintner'; } |
|
2955 }); |
|
2956 |
|
2957 // Tab 4, Hops |
|
2958 $('#est_ibu2').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); |
|
2959 $('#est_ibu2').jqxNumberInput(Smal0dec); |
|
2960 $('#hop_flavour').jqxProgressBar({ |
|
2961 width: 300, height: 23, theme: theme, showText: true, animationDuration: 0, |
|
2962 colorRanges: [ |
|
2963 { stop: 20, color: '#004D00' }, |
|
2964 { stop: 40, color: '#008C00' }, |
|
2965 { stop: 60, color: '#00BF00' }, |
|
2966 { stop: 80, color: '#00FF00' }, |
|
2967 { stop: 100, color: '#80FF80' } |
|
2968 ], |
|
2969 renderText: function(text) { |
|
2970 var val = parseInt(text); |
|
2971 if (val < 20) |
|
2972 return 'Weinig'; |
|
2973 else if (val < 40) |
|
2974 return 'Matig'; |
|
2975 else if (val < 60) |
|
2976 return 'Redelijk'; |
|
2977 else if (val < 80) |
|
2978 return 'Veel'; |
|
2979 else |
|
2980 return 'Zeer veel'; |
|
2981 } |
|
2982 }); |
|
2983 $('#hop_aroma').jqxProgressBar({ |
|
2984 width: 300, height: 23, theme: theme, showText: true, animationDuration: 0, |
|
2985 colorRanges: [ |
|
2986 { stop: 20, color: '#004D00' }, |
|
2987 { stop: 40, color: '#008C00' }, |
|
2988 { stop: 60, color: '#00BF00' }, |
|
2989 { stop: 80, color: '#00FF00' }, |
|
2990 { stop: 100, color: '#80FF80' } |
|
2991 ], |
|
2992 renderText: function(text) { |
|
2993 var val = parseInt(text); |
|
2994 if (val < 20) |
|
2995 return 'Weinig'; |
|
2996 else if (val < 40) |
|
2997 return 'Matig'; |
|
2998 else if (val < 60) |
|
2999 return 'Redelijk'; |
|
3000 else if (val < 80) |
|
3001 return 'Veel'; |
|
3002 else |
|
3003 return 'Zeer veel'; |
|
3004 } |
|
3005 }); |
|
3006 |
|
3007 // Tab 5, Miscs |
|
3008 |
|
3009 // Tab 6, Yeasts |
|
3010 $('#est_fg2').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); |
|
3011 $('#est_abv2').jqxTooltip({ content: 'Verwacht alcohol volume %. Dit wordt automatisch berekend.' }); |
|
3012 $('#yeast_grams').jqxTooltip({ content: 'De gewenste totale hoeveelheid droge gist voor dit bier.' }); |
|
3013 $('#yeast_gr_hl').jqxTooltip({ content: 'De werkelijke hoeveelheid gist per hectoliter.' }); |
|
3014 $('#yeast_cells').jqxTooltip({ content: 'Het aantal miljard beschikbare gistcellen zonder eventuele starter.' }); |
|
3015 $('#need_cells').jqxTooltip({ content: 'Het aantal miljard nodige cellen is afhankelijk van het begin SG, biertype en volume.' }); |
|
3016 $('#plato_cells').jqxTooltip({ content: 'De berekende pitchrate in miljard cellen per ml per graad Plato.' }); |
|
3017 $('#yeast_prod_date').jqxTooltip({ content: 'Bij korrelgisten is meestal "best voor" datum op het zakje gedrukt.<br>Gebruik die datum maar dan twee jaar eerder als productie datum.<br>Bij White Labs is de productie datum vier maanden voor de "Best by" datum die geprint op het buisje.<br>Bij Wyeast is dit de "manufacture date" die op het pak geprint is.<br>Voor schuine buis, slurry, opkweek en gedroogd is dit de datum dat je de gist geoogst hebt.' }); |
|
3018 $('#yeast_pitchrate').jqxTooltip({ content: 'De gewenste pitchrate in miljard cellen per ml per graad Plato voor de vergisting van dit bier.' }); |
|
3019 |
|
3020 $('#est_fg2,#plato_cells').jqxNumberInput(Show3dec); |
|
3021 $('#est_fg2').jqxNumberInput({ width: 70 }); |
|
3022 $('#est_abv2').jqxNumberInput(Show2dec); |
|
3023 $('#est_abv2').jqxNumberInput({ width: 70, symbol: '%', symbolPosition: 'right' }); |
|
3024 $('#yeast_grams').jqxNumberInput(Show1dec); |
|
3025 $('#yeast_gr_hl').jqxNumberInput(Show1dec); |
|
3026 $('#yeast_cells,#need_cells').jqxNumberInput(Show1dec); |
|
3027 $('#yeast_prod_date').jqxDateTimeInput(Dateopts); |
|
3028 $('#yeast_prod_date').jqxDateTimeInput({ disabled: true }); |
|
3029 $('#yeast_pitchrate').jqxNumberInput(Show3dec); |
|
3030 for (i = 1; i < 5; i++) { |
|
3031 $('#prop' + i + '_volume').jqxTooltip({ content: 'Het volume van deze starter stap.' }); |
|
3032 $('#prop' + i + '_irate').jqxTooltip({ content: 'Voor de beste gistgroei, houd de injectie factor tussen de 25 en 100 miljoen cellen per ml.' }); |
|
3033 $('#prop' + i + '_ncells').jqxTooltip({ content: 'Het aantal miljard nieuwe gistcellen in deze stap.' }); |
|
3034 $('#prop' + i + '_tcells').jqxTooltip({ content: 'Het totaal aantal miljard gistcellen na deze stap.' }); |
|
3035 $('#prop' + i + '_growf').jqxTooltip({ content: 'De groeifactor, minstens 1. Ongeroerde starters komen meestal niet boven de 3.' }); |
|
3036 |
|
3037 $('#prop' + i + '_type').jqxInput({ theme: theme, width: 120, height: 23 }); |
|
3038 $('#prop' + i + '_volume').jqxNumberInput(Show3dec); |
|
3039 $('#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells').jqxNumberInput(Show1dec); |
|
3040 $('#prop' + i + '_growf').jqxNumberInput(Show2dec); |
|
3041 $('#prop' + i + '_type,#prop' + i + '_volume,#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells,#prop' + i + '_growf').hide(); |
|
3042 } |
|
3043 $('#starter_type').jqxInput({ theme: theme, width: 120, height: 23 }); |
|
3044 $('#starter_sg').jqxTooltip({ content: 'Het ideale starter SG moet tussen de 1.030 en 1.040 zijn. Optimaal is 1.037.' }); |
|
3045 $('#starter_sg').jqxNumberInput(Show3dec); |
|
3046 $('#starter_viability').jqxTooltip({ content: 'De gist conditie.' }); |
|
3047 $('#starter_viability').jqxNumberInput(Show0dec); |
|
3048 |
|
3049 // Tab 7, Mashing |
|
3050 $('#mash_name').jqxTooltip({ content: 'De omschrijving van dit maisch profiel.' }); |
|
3051 $('#mash_name').jqxInput({ theme: theme, width: 320, height: 23 }); |
|
3052 $('#est_mashvol').jqxTooltip({ content: 'Het totale volume van het maishwater en de mout in de maish pan.' }); |
|
3053 $('#est_mashvol').jqxNumberInput(Show1dec); |
|
3054 $('#est_mashtime').jqxTooltip({ content: 'De totale tijdsduur van het maischen.' }); |
|
3055 $('#est_mashtime').jqxInput({ theme: theme, width: 70, height: 23 }); |
|
3056 |
|
3057 // Tab 8, Water |
|
3058 $('#tgt_bu').jqxNumberInput(Show2wat); |
|
3059 $('#tgt_so4_cl,#got_so4_cl').jqxNumberInput(Show1wat); |
|
3060 $('#preboil_ph').jqxNumberInput(Show2wat); |
|
3061 |
|
3062 // Water source 1 |
|
3063 $('#w1_name').jqxInput({ theme: theme, width: 200, height: 23 }); |
|
3064 $('#w1_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); |
|
3065 $('#w1_amount,#w1_calcium,#w1_magnesium,#w1_sodium,#w1_bicarbonate,#w1_total_alkalinity,#w1_chloride,#w1_sulfate').jqxNumberInput(Show1wat); |
|
3066 $('#w1_ph').jqxNumberInput(Show2wat); |
|
3067 $('#w1_hardness').jqxNumberInput(Show1wat); |
|
3068 $('#w1_ra').jqxNumberInput(Show1wat); |
|
3069 // Water source 2 |
|
3070 $('#w2_name').jqxInput({ theme: theme, width: 200, height: 23 }); |
|
3071 $('#w2_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); |
|
3072 $('#w2_amount').jqxNumberInput(Show1wat); |
|
3073 $('#w2_calcium,#w2_magnesium,#w2_sodium,#w2_bicarbonate,#w2_total_alkalinity,#w2_chloride,#w2_sulfate').jqxNumberInput(Show1wat); |
|
3074 $('#w2_ph').jqxNumberInput(Show2wat); |
|
3075 $('#w2_hardness').jqxNumberInput(Show1wat); |
|
3076 $('#w2_ra').jqxNumberInput(Show1wat); |
|
3077 // Water mixed |
|
3078 $('#wg_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); |
|
3079 $('#wg_amount,#wg_calcium,#wg_magnesium,#wg_sodium,#wg_bicarbonate,#wg_total_alkalinity,#wg_chloride,#wg_sulfate').jqxNumberInput(Show1wat); |
|
3080 $('#wg_ph').jqxNumberInput(Show2wat); |
|
3081 $('#wg_hardness').jqxNumberInput(Show1wat); |
|
3082 $('#wg_ra').jqxNumberInput(Show1wat); |
|
3083 // Water treated |
|
3084 $('#wb_calcium').jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'}); |
|
3085 $('#wb_calcium').jqxNumberInput(Show1wat); |
|
3086 $('#wb_magnesium').jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is tussen 5 en 40.'}); |
|
3087 $('#wb_magnesium').jqxNumberInput(Show1wat); |
|
3088 $('#wb_sodium').jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'}); |
|
3089 $('#wb_sodium').jqxNumberInput(Show1wat); |
|
3090 $('#wb_chloride').jqxTooltip({ content: 'De ideale hoeveelheid Chloride is tussen 50 en 150. Samen met Sulfaat minder dan 500.'}); |
|
3091 $('#wb_chloride').jqxNumberInput(Show1wat); |
|
3092 $('#wb_sulfate').jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 400. Samen met Chloride minder dan 500.'}); |
|
3093 $('#wb_sulfate').jqxNumberInput(Show1wat); |
|
3094 $('#wb_bicarbonate').jqxTooltip({ content: '0 tot 50 lichte bieren, 50 tot 150 amber bieren, 150 tot 250 donkere bieren.'}); |
|
3095 $('#wb_bicarbonate').jqxNumberInput(Show1wat); |
|
3096 $('#wb_ph').jqxNumberInput(Show2wat); |
|
3097 $('#wb_hardness').jqxNumberInput(Show1wat); |
|
3098 $('#wb_ra').jqxNumberInput(Show1wat); |
|
3099 // Sparge water |
|
3100 $('#sw_amount').jqxNumberInput(Show1wat); |
|
3101 $('#sw_calcium').jqxNumberInput(Show1wat); |
|
3102 $('#sw_magnesium').jqxNumberInput(Show1wat); |
|
3103 $('#sw_sodium').jqxNumberInput(Show1wat); |
|
3104 $('#sw_bicarbonate').jqxNumberInput(Show1wat); |
|
3105 $('#sw_total_alkalinity').jqxNumberInput(Show1wat); |
|
3106 $('#sw_chloride').jqxNumberInput(Show1wat); |
|
3107 $('#sw_sulfate').jqxNumberInput(Show1wat); |
|
3108 $('#sw_ph').jqxNumberInput(Show2wat); |
|
3109 $('#sw_hardness').jqxNumberInput(Show1wat); |
|
3110 $('#sw_ra').jqxNumberInput(Show1wat); |
|
3111 |
|
3112 // Water agents |
|
3113 $('#wa_cacl2').jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.' }); |
|
3114 $('#wa_cacl2').jqxNumberInput(Show2wat); |
|
3115 $('#ss_cacl2').jqxNumberInput(Show2wat); |
|
3116 |
|
3117 $('#wa_caso4').jqxTooltip({ |
|
3118 content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.' |
|
3119 }); |
|
3120 $('#wa_caso4').jqxNumberInput(Show2wat); |
|
3121 $('#ss_caso4').jqxNumberInput(Show2wat); |
|
3122 |
|
3123 $('#wa_mgso4').jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!' }); |
|
3124 $('#wa_mgso4').jqxNumberInput(Show2wat); |
|
3125 $('#ss_mgso4').jqxNumberInput(Show2wat); |
|
3126 |
|
3127 $('#wa_nacl').jqxTooltip({ |
|
3128 content: 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. ' + |
|
3129 'Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.' |
|
3130 }); |
|
3131 $('#wa_nacl').jqxNumberInput(Show2wat); |
|
3132 $('#ss_nacl').jqxNumberInput(Show2wat); |
|
3133 |
|
3134 $('#wa_mgcl2').jqxTooltip({ content: 'Magnesiumchloride'}); |
|
3135 $('#wa_mgcl2').jqxNumberInput(Show2wat); |
|
3136 $('#ss_mgcl2').jqxNumberInput(Show2wat); |
|
3137 |
|
3138 $('#wa_nahco3').jqxTooltip({ content: 'Baksoda'}); |
|
3139 $('#wa_caco3').jqxTooltip({ content: 'Kalk'}); |
|
3140 $('#wa_nahco3,#wa_caco3').jqxNumberInput(Show2wat); |
|
3141 |
|
3142 $('#mash_ph').jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'}); |
|
3143 $('#mash_ph').jqxNumberInput(Show2dec); |
|
3144 |
|
3145 $('#calc_acid').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); |
|
3146 |
|
3147 $('#wa_acid_name').jqxInput({ theme: theme, width: 130, height: 23 }); |
|
3148 $('#wa_acid').jqxNumberInput(Show2dec); |
|
3149 $('#wa_acid').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); |
|
3150 $('#wa_acid_perc').jqxNumberInput(Show0dec); |
|
3151 $('#wa_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); |
|
3152 |
|
3153 // Sparge water |
|
3154 $('#sparge_ph').jqxNumberInput(Show2dec); |
|
3155 $('#sparge_acid_amount').jqxNumberInput(Show2dec); |
|
3156 $('#sparge_acid_amount').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); |
|
3157 $('#sparge_acid_type').jqxInput({ theme: theme, width: 130, height: 23 }); |
|
3158 $('#sparge_acid_perc').jqxNumberInput(Show0dec); |
|
3159 $('#sparge_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); |
|
3160 |
|
3161 // Tab 9, Brewday |
|
3162 $('#brew_date_start').jqxTooltip({ content: 'Brouw datum en tijd. Voor planning laat de tijd op 00:00:00 staan.' }); |
|
3163 $('#brew_date_end').jqxTooltip({ content: 'End datum en tijd van de brouw. Leeg laten als er nog niet gebrouwen is.' }); |
|
3164 $('#brew_mash_ph').jqxTooltip({ content: 'De gemeten pH tijdens het maischen eventueel na correctie.' }); |
|
3165 $('#est_mash_ph').jqxTooltip({ content: 'De gewenste pH tijdens het maischen.' }); |
|
3166 $('#brew_preboil_ph').jqxTooltip({ content: 'De gemeten pH in de kookketel na het spoelen en voor de kook.' }); |
|
3167 $('#brew_aboil_ph').jqxTooltip({ content: 'De gemeten pH na het koken.' }); |
|
3168 $('#brew_mash_sg').jqxTooltip({ content: 'Het bereikte SG na het maischen.' }); |
|
3169 $('#est_mash_sg').jqxTooltip({ content: 'Het berekende verwachte SG na het maischen.' }); |
|
3170 $('#brew_preboil_sg').jqxTooltip({ content: 'Het gemeten SG in de kookketel na het spoelen en voor het koken.' }); |
|
3171 $('#est_pre_sg').jqxTooltip({ content: 'Het berekende SG in de kookketel na het spoelen en voor het koken.' }); |
|
3172 $('#brew_aboil_sg').jqxTooltip({ content: 'Het gemeten SG in de kookketel na het koken.' }); |
|
3173 $('#est_og3').jqxTooltip({ content: 'Het gewenste SG in de kookketel na het koken zonder eventuele suikers die tijdens de vergisting toegevoegd worden.' }); |
|
3174 $('#brew_mash_efficiency').jqxTooltip({ content: 'Het behaalde maisch rendement.' }); |
|
3175 $('#brew_preboil_volume').jqxTooltip({ content: 'Het gemeten volume van het wort voor het koken.' }); |
|
3176 $('#est_pre_vol').jqxTooltip({ content: 'Het berekende volume van het wort voor het koken.' }); |
|
3177 $('#brew_aboil_volume').jqxTooltip({ content: 'Het gemeten volume van het wort na het koken.' }); |
|
3178 $('#est_a_vol').jqxTooltip({ content: 'Het gewenste volume na het koken.' }); |
|
3179 $('#brew_preboil_efficiency').jqxTooltip({ content: 'Het berekende rendement voor het koken.' }); |
|
3180 $('#brew_aboil_efficiency').jqxTooltip({ content: 'Het bereikte rendement na het koken.' }); |
|
3181 $('#brew_sparge_temperature').jqxTooltip({ content: 'De spoelwater temperatuur, in te stellen in de Water tab.' }); |
|
3182 $('#brew_sparge_volume').jqxTooltip({ content: 'Het spoelwater voorraad volume, in te stellen in de Water tab.' }); |
|
3183 $('#brew_date_start,#brew_date_end').jqxDateTimeInput(DateTimeopts); |
|
3184 $('#brew_date_start,#brew_date_end').jqxDateTimeInput({ disabled: true }); |
|
3185 $('#est_mash_ph').jqxNumberInput(Show2wat); |
|
3186 $('#brew_mash_ph,#brew_preboil_ph,#brew_aboil_ph').jqxNumberInput(Show2dec); |
|
3187 $('#brew_mash_sg,#brew_preboil_sg,#brew_aboil_sg').jqxNumberInput(Show3dec); |
|
3188 $('#est_mash_sg,#est_pre_sg,#est_og3').jqxNumberInput(Show3wat); |
|
3189 $('#brew_mash_efficiency').jqxNumberInput(Show1dec); |
|
3190 $('#brew_preboil_volume,#brew_aboil_volume').jqxNumberInput(Show1dec); |
|
3191 $('#est_pre_vol,#est_a_vol').jqxNumberInput(Show1wat); |
|
3192 $('#brew_preboil_efficiency,#brew_aboil_efficiency,#brew_sparge_temperature,#brew_sparge_volume,#brew_sparge_est').jqxNumberInput(Show1dec); |
|
3193 $('#brew_cooling_to').jqxNumberInput(Show1dec); |
|
3194 $('#brew_sparge_ph').jqxNumberInput(Show2dec); |
|
3195 $('#brew_cooling_method').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
3196 $('#brew_cooling_time,#brew_whirlpool9,#brew_whirlpool7,#brew_whirlpool6,#brew_whirlpool2,#brew_aeration_time,#brew_aeration_speed').jqxNumberInput(Show0dec); |
|
3197 $('#brew_aeration_type').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
3198 $('#brew_fermenter_volume').jqxNumberInput(Show1dec); |
|
3199 $('#brew_fermenter_sg').jqxNumberInput(Show3dec); |
|
3200 $('#brew_fermenter_extrawater,#brew_fermenter_tcloss').jqxNumberInput(Show1dec); |
|
3201 $('#brew_fermenter_ibu,#brew_fermenter_color').jqxNumberInput(Show0dec); |
|
3202 |
|
3203 // Tab 10, Fermentation |
|
3204 $('#brew_fermenter_sg2').jqxTooltip({ content: 'Het behaalde SG in het gistvat, overgenomen van de brouwdag.' }); |
|
3205 $('#primary_start_temp').jqxTooltip({ content: 'De begintemperatuur van de hoofdvergisting.' }); |
|
3206 $('#primary_max_temp').jqxTooltip({ content: 'De hoogst bereikte piek temperatuur tijdens de hoofgvergisting.' }); |
|
3207 $('#primary_end_temp').jqxTooltip({ content: 'De eind temperatuur van de hoofdvergisting.' }); |
|
3208 $('#primary_end_sg').jqxTooltip({ content: 'Het gemeten SG aan het eind van de hoofdvergisting.' }); |
|
3209 $('#primary_svg').jqxTooltip({ content: 'De schijnbare vergisting graad behaald na de hoofdgisting.' }); |
|
3210 $('#primary_end_date').jqxTooltip({ content: 'De eind datum van de hoofdvergisting en eventueel overhevelen.' }); |
|
3211 $('#secondary_end_sg').jqxTooltip({ content: 'Het gemeten SG aan het eind van de navergisting.' }); |
|
3212 $('#secondary_svg').jqxTooltip({ content: 'De schijnbare vergisting graad behaald na de nagisting.' }); |
|
3213 $('#secondary_end_date').jqxTooltip({ content: 'De eind datum van de navergisting en het begin van het lageren.' }); |
|
3214 $('#est_fg3').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); |
|
3215 |
|
3216 $('#primary_end_sg,#secondary_end_sg').jqxNumberInput(Show3dec); |
|
3217 $('#primary_end_date,#secondary_end_date').jqxDateTimeInput(Dateopts); |
|
3218 $('#primary_end_date,#secondary_end_date').jqxDateTimeInput({ disabled: true }); |
|
3219 $('#primary_start_temp,#primary_max_temp,#primary_end_temp,#secondary_temp,#tertiary_temp').jqxNumberInput(Show1dec); |
|
3220 $('#fg').jqxNumberInput(Show3dec); |
|
3221 $('#brew_fermenter_sg2,#est_fg3').jqxNumberInput(Show3dec); |
|
3222 $('#final_abv').jqxNumberInput(Show2dec); |
|
3223 $('#primary_svg,#secondary_svg,#final_svg').jqxNumberInput(Show1dec); |
|
3224 $('#FLog').jqxButton({ template: 'info', width: '150px', theme: theme }); |
|
3225 $('#FLog').click(function() { |
|
3226 // Open log in a new tab. |
|
3227 window.open('log_fermentation.php?code=' + dataRecord.code + '&name=' + dataRecord.name); |
|
3228 }); |
|
3229 $('#ILog').jqxButton({ template: 'info', width: '150px', theme: theme }); |
|
3230 $('#ILog').click(function() { |
|
3231 // Open log in a new tab. |
|
3232 window.open('log_ispindel.php?code=' + dataRecord.code + '&name=' + dataRecord.name); |
|
3233 }); |
|
3234 |
|
3235 // Tab 11, Packaging |
|
3236 // TODO: high gravity packaging, extra water and recalc abv, color and ibu. |
|
3237 $('#package_date').jqxTooltip({ content: 'De verpakkings datum van dit bier.' }); |
|
3238 $('#package_volume').jqxTooltip({ content: 'Het beschikbare volume om te bottelen of op fust te zetten.' }); |
|
3239 $('#package_infuse_amount').jqxTooltip({ content: 'De hoeveelheid water of drank extra toe te voegen.' }); |
|
3240 $('#package_infuse_abv').jqxTooltip({ content: 'De hoeveelheid alcohol in de drank, of 0.0 als het water is.' }); |
|
3241 $('#package_infuse_notes').jqxTooltip({ content: 'Omschrijving van de extra toevoeging.' }); |
|
3242 $('#package_abv').jqxTooltip({ content: 'De uiteindelijke hoeveelheid alcohol volume %.' }); |
|
3243 $('#package_ph').jqxTooltip({ content: 'De gemeten pH vlak voor het verpakken.' }); |
|
3244 $('#st_carb_min2').jqxTooltip({ content: 'Het minimum aanbevolen koolzuur volume voor deze bierstijl.'}); |
|
3245 $('#st_carb_max2').jqxTooltip({ content: 'Het maximum aamnevolen koolzuur volume voor deze bierstijl.'}); |
|
3246 $('#bottle_amount').jqxTooltip({ content: 'De totale hoeveelheid te bottelen bier.' }); |
|
3247 $('#keg_amount').jqxTooltip({ content: 'De totale hoeveelheid op fust te zetten bier.' }); |
|
3248 $('#bottle_carbonation').jqxTooltip({ content: 'Het gewenste CO2 volume in de flessen.' }); |
|
3249 $('#keg_carbonation').jqxTooltip({ content: 'Het gewenste CO2 volume door de suiker in de fusten.' }); |
|
3250 $('#bottle_priming_water,#keg_priming_water').jqxTooltip({ content: 'De hoeveelheid water om de suiker op te lossen.' }); |
|
3251 $('#bottle_pressure').jqxTooltip({ content: 'De maximaal te verwachten druk tijdens het hergisten.' }); |
|
3252 $('#package_date').jqxDateTimeInput(Dateopts); |
|
3253 $('#package_date').jqxDateTimeInput({ disabled: true }); |
|
3254 $('#package_infuse_amount').jqxNumberInput(Show3dec); |
|
3255 $('#package_infuse_notes').jqxInput({ theme: theme, width: 640, height: 23 }); |
|
3256 $('#package_abv').jqxNumberInput(Show2dec); |
|
3257 $('#package_ph').jqxNumberInput(Show2dec); |
|
3258 $('#st_carb_min2,#st_carb_max2').jqxNumberInput(Smal1dec); |
|
3259 $('#package_volume,#package_infuse_abv,#bottle_amount,#keg_amount').jqxNumberInput(Show1dec); |
|
3260 $('#bottle_carbonation,#keg_carbonation').jqxNumberInput(Show2dec); |
|
3261 $('#bottle_priming_sugar').jqxInput({ theme: theme, width: 200, height: 23 }); |
|
3262 $('#keg_priming_sugar').jqxInput({ theme: theme, width: 200, height: 23 }); |
|
3263 $('#bottle_priming_water,#keg_priming_water').jqxNumberInput(Show3dec); |
|
3264 $('#keg_forced_carb').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); |
|
3265 $('#bottle_priming_amount,#keg_priming_amount,#bottle_priming_total,#bottle_pressure,#keg_priming_total,#keg_pressure').jqxNumberInput(Show1dec); |
|
3266 $('#bottle_abv,#keg_abv').jqxNumberInput(Show2dec); |
|
3267 $('#bottle_carbonation_temp,#keg_carbonation_temp').jqxNumberInput(Show1dec); |
|
3268 $('#CLog').jqxButton({ template: 'info', width: '150px', theme: theme }); |
|
3269 $('#CLog').click(function() { |
|
3270 // Open log in a new tab. |
|
3271 window.open('log_co2pressure.php?code=' + dataRecord.code + '&name=' + dataRecord.name); |
|
3272 }); |
|
3273 |
|
3274 // Tab 12, Tasting |
|
3275 $('#taste_date').jqxTooltip({ content: 'De proef datum van dit bier.' }); |
|
3276 $('#taste_date').jqxDateTimeInput(Dateopts); |
|
3277 $('#taste_date').jqxDateTimeInput({ disabled: true }); |
|
3278 $('#taste_rate').jqxTooltip({ content: 'Het cijfer voor dit bier van 1 tot 10.' }); |
|
3279 $('#taste_rate').jqxNumberInput(Show1dec); |
|
3280 $('#taste_color').jqxTooltip({ content: 'De kleur van het bier.' }); |
|
3281 $('#taste_transparency').jqxTooltip({ content: 'De helderheid van het bier.' }); |
|
3282 $('#taste_head').jqxTooltip({ content: 'Het schuim op het bier.' }); |
|
3283 $('#taste_color,#taste_transparency,#taste_head').jqxInput({ theme: theme, width: 320, height: 23 }); |
|
3284 $('#taste_aroma').jqxTooltip({ content: 'Het aroma van het bier.' }); |
|
3285 $('#taste_taste').jqxTooltip({ content: 'De smaak van het bier.' }); |
|
3286 $('#taste_aftertaste').jqxTooltip({ content: 'De nasmaak van het bier.' }); |
|
3287 $('#taste_mouthfeel').jqxTooltip({ content: 'Het mondgevoelvan het bier.' }); |
|
3288 $('#taste_aroma,#taste_taste,#taste_aftertaste,#taste_mouthfeel').jqxInput({ theme: theme, width: 960, height: 23 }); |
|
3289 $('#taste_notes').jqxTooltip({ content: 'Het oordeel en opmerkingen over dit bier.' }); |
|
3290 $('#taste_notes').jqxInput({ theme: theme, width: 960, height: 100 }); |
|
3291 |
|
3292 $('#jqxTabs').jqxTabs({ |
|
3293 theme: theme, |
|
3294 width: 1280, |
|
3295 height: 660, |
|
3296 autoHeight: false, |
|
3297 position: 'top' |
|
3298 }); |
|
3299 |
|
3300 // Buttons below |
|
3301 $('#Terug').jqxButton({ template: 'primary', width: '80px', theme: theme }); |
|
3302 $('#Terug').bind('click', function() { |
|
3303 window.location.href = my_return; |
|
3304 }); |
|
3305 }); |
|
3306 |