# HG changeset patch # User Michiel Broek # Date 1659816628 -7200 # Node ID 2641860ad61d071ba5a9ebcee21737450ff7a824 # Parent 21fae4d2203e9f1b92e7dc19a9f48735efad4b00 Renamed prod_edit to prod_view. diff -r 21fae4d2203e -r 2641860ad61d www/Makefile --- a/www/Makefile Sat Aug 06 22:02:42 2022 +0200 +++ b/www/Makefile Sat Aug 06 22:10:28 2022 +0200 @@ -10,7 +10,7 @@ index.php \ log_co2pressure.php log_fermentation.php log_ispindel.php \ mon_brewer.php mon_co2meter.php mon_fermenter.php mon_ispindel.php mon_node.php \ - prod_edit.php prod_inprod.php rec_view.php rec_main.php version.php + prod_view.php prod_inprod.php rec_view.php rec_main.php version.php SUB = version.php.in images/* css/* jqwidgets/* jqwidgets/styles/* \ jqwidgets/styles/images/* jqwidgets/globalization/* js/* \ includes/* fpdf/* import/* diff -r 21fae4d2203e -r 2641860ad61d www/js/prod_edit.js --- a/www/js/prod_edit.js Sat Aug 06 22:02:42 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3308 +0,0 @@ -/***************************************************************************** - * Copyright (C) 2018-2022 - * - * Michiel Broek - * - * This file is part of BMS - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * BrewCloud is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ThermFerm; see the file COPYING. If not, write to the Free - * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - *****************************************************************************/ - - -function block_fermentable(stage, added) { - if (stage > 5 && added < 4) // After fermentation and added before packaging - return true; - if (stage > 3 && added < 3) // After primary and added before sec/tert - return true; - if (stage > 2 && added < 2) // After boil and added during mash or boil - return true; - return false; -} - -function block_hop(stage, useat) -{ - if (stage > 2 && useat < 5) - return true; - return false; -} - -function block_misc(stage, use_use) { - if (stage > 5 && use_use < 5) - return true; - if (stage > 3 && use_use < 4) - return true; - if (stage > 2 && use_use < 3) - return true; - if (stage > 1 && use_use < 1) - return true; - return false; -} - -function block_yeast(stage, use) { - if (stage > 3 && use < 1) - return true; - if (stage > 4 && use < 2) - return true; - if (stage > 5 && use < 3) - return true; - if (stage > 6 && use < 4) - return true; - return false; -} - - -$(document).ready(function() { - - var i, - to_100 = false, // Fermentables adjust to 100% - preboil_sg = 0, - aboil_sg = 0, - est_mash_sg = 0, - psugar = 0, // Percentage real sugars - pcara = 0, // Percentage cara/crystal malts - svg = 77, // Default attenuation - mashkg = 0, // Malt in mash weight - initcells = 0, // Initial yeast cell count - - ok_fermentables = 1, // Fermentables are in stock - ok_hops = 1, // Hops are in stock - ok_miscs = 1, // Miscs are in stock - ok_yeasts = 1, // Yeasts are in stock - ok_waters = 1, // Waters are in stock - - data_loaded = 0; - error_count = 0; - k_cm = 0; - k_vol = 0; - k_what = 0; - - hop_flavour = 0, - hop_aroma = 0, - mash_infuse = 0, - last_acid = '', - - MMCa = 40.048, - MMMg = 24.305, - MMNa = 22.98976928, - MMCl = 35.453, - MMSO4 = 96.0626, - MMHCO3 = 61.01684, - MMCaSO4 = 172.171, - MMCaCl2 = 147.015, - MMCaCO3 = 100.087, - MMMgCl2 = 95.211, /* Since 27-06-2021 */ - MMMgSO4 = 246.475, - MMNaHCO3 = 84.007, - MMNa2CO3 = 105.996, - MMNaCl = 58.443, - MMCaOH2 = 74.06268, - - fermentableRow = 0, - fermentableData = {}, - fermentableInit = 1, - hopRow = 0, - hopData = {}, - miscRow = 0, - miscData = {}, - yeastRow = 0, - yeastData = {}, - mashRow = 0, - mashData = {}, - Ka1 = 0.0000004445, - Ka2 = 0.0000000000468, - dataRecord = {}, - url = 'includes/db_product.php', - MaltVolume = 0.87, // l/kg 0.688 volgens internetbronnen, gemeten 0.874 l/kg, na enige tijd maischen 0,715 l/kg (A3 Otten). - SpecificHeatWater = 1.0, - SpecificHeatMalt = 0.399, //cal/g.°C - SlakingHeat = 10.318, //cal/g.°C - - // Prepare the data - source = { - datatype: 'json', - cache: false, - async: true, - datafields: [ - // From prod_main - { name: 'record', type: 'number' }, - { name: 'uuid', type: 'string' }, - { name: 'name', type: 'string' }, - { name: 'code', type: 'string' }, - { name: 'birth', type: 'string' }, - { name: 'stage', type: 'int' }, - { name: 'notes', type: 'string' }, - { name: 'log_brew', type: 'int' }, - { name: 'log_fermentation', type: 'int' }, - { name: 'log_ispindel', type: 'int' }, - { name: 'log_co2pressure', type: 'int' }, - { name: 'inventory_reduced', type: 'int' }, - { name: 'locked', type: 'int' }, - { name: 'eq_name', type: 'string' }, - { name: 'eq_boil_size', type: 'float' }, - { name: 'eq_batch_size', type: 'float' }, - { name: 'eq_tun_volume', type: 'float' }, - { name: 'eq_tun_weight', type: 'float' }, - { name: 'eq_tun_specific_heat', type: 'float' }, - { name: 'eq_tun_material', type: 'int' }, - { name: 'eq_tun_height', type: 'float' }, - { name: 'eq_top_up_water', type: 'float' }, - { name: 'eq_trub_chiller_loss', type: 'float' }, - { name: 'eq_evap_rate', type: 'float' }, - { name: 'eq_boil_time', type: 'float' }, - { name: 'eq_calc_boil_volume', type: 'int' }, - { name: 'eq_top_up_kettle', type: 'float' }, - { name: 'eq_hop_utilization', type: 'float' }, - { name: 'eq_notes', type: 'string' }, - { name: 'eq_lauter_volume', type: 'float' }, - { name: 'eq_lauter_height', type: 'float' }, - { name: 'eq_lauter_deadspace', type: 'float' }, - { name: 'eq_kettle_volume', type: 'float' }, - { name: 'eq_kettle_height', type: 'float' }, - { name: 'eq_mash_volume', type: 'float' }, - { name: 'eq_mash_max', type: 'float' }, - { name: 'eq_efficiency', type: 'float' }, - { name: 'brew_date_start', type: 'string' }, - { name: 'brew_mash_ph', type: 'float' }, - { name: 'brew_mash_sg', type: 'float' }, - { name: 'brew_mash_efficiency', type: 'float' }, - { name: 'brew_sparge_est', type: 'float' }, - { name: 'brew_sparge_ph', type: 'float' }, - { name: 'brew_preboil_volume', type: 'float' }, - { name: 'brew_preboil_sg', type: 'float' }, - { name: 'brew_preboil_ph', type: 'float' }, - { name: 'brew_preboil_efficiency', type: 'float' }, - { name: 'brew_aboil_volume', type: 'float' }, - { name: 'brew_aboil_sg', type: 'float' }, - { name: 'brew_aboil_ph', type: 'float' }, - { name: 'brew_aboil_efficiency', type: 'float' }, - { name: 'brew_cooling_method', type: 'int' }, - { name: 'brew_cooling_time', type: 'float' }, - { name: 'brew_cooling_to', type: 'float' }, - { name: 'brew_whirlpool9', type: 'float' }, - { name: 'brew_whirlpool7', type: 'float' }, - { name: 'brew_whirlpool6', type: 'float' }, - { name: 'brew_whirlpool2', type: 'float' }, - { name: 'brew_fermenter_volume', type: 'float' }, - { name: 'brew_fermenter_extrawater', type: 'float' }, - { name: 'brew_fermenter_tcloss', type: 'float' }, - { name: 'brew_aeration_time', type: 'float' }, - { name: 'brew_aeration_speed', type: 'float' }, - { name: 'brew_aeration_type', type: 'int' }, - { name: 'brew_fermenter_sg', type: 'float' }, - { name: 'brew_fermenter_ibu', type: 'float' }, - { name: 'brew_fermenter_color', type: 'float' }, - { name: 'brew_date_end', type: 'string' }, - { name: 'og', type: 'float' }, - { name: 'fg', type: 'float' }, - { name: 'primary_start_temp', type: 'float' }, - { name: 'primary_max_temp', type: 'float' }, - { name: 'primary_end_temp', type: 'float' }, - { name: 'primary_end_sg', type: 'float' }, - { name: 'primary_end_date', type: 'string' }, - { name: 'secondary_temp', type: 'float' }, - { name: 'secondary_end_sg', type: 'float' }, - { name: 'secondary_end_date', type: 'string' }, - { name: 'tertiary_temp', type: 'float' }, - { name: 'package_date', type: 'string' }, - { name: 'package_volume', type: 'float' }, - { name: 'package_infuse_amount', type: 'float' }, - { name: 'package_infuse_abv', type: 'float' }, - { name: 'package_infuse_notes', type: 'string' }, - { name: 'package_abv', type: 'float' }, - { name: 'package_ph', type: 'float' }, - { name: 'bottle_amount', type: 'float' }, - { name: 'bottle_carbonation', type: 'float' }, - { name: 'bottle_priming_water', type: 'float' }, - { name: 'bottle_priming_amount', type: 'float' }, - { name: 'bottle_carbonation_temp', type: 'float' }, - { name: 'keg_amount', type: 'float' }, - { name: 'keg_carbonation', type: 'float' }, - { name: 'keg_priming_water', type: 'float' }, - { name: 'keg_priming_amount', type: 'float' }, - { name: 'keg_carbonation_temp', type: 'float' }, - { name: 'keg_forced_carb', type: 'int' }, - { name: 'keg_pressure', type: 'float' }, - { name: 'taste_notes', type: 'string' }, - { name: 'taste_rate', type: 'float' }, - { name: 'taste_date', type: 'string' }, - { name: 'taste_color', type: 'string' }, - { name: 'taste_transparency', type: 'string' }, - { name: 'taste_head', type: 'string' }, - { name: 'taste_aroma', type: 'string' }, - { name: 'taste_taste', type: 'string' }, - { name: 'taste_mouthfeel', type: 'string' }, - { name: 'taste_aftertaste', type: 'string' }, - { name: 'st_name', type: 'string' }, - { name: 'st_letter', type: 'string' }, - { name: 'st_guide', type: 'string' }, - { name: 'st_category', type: 'string' }, - { name: 'st_category_number', type: 'int' }, - { name: 'st_type', type: 'int' }, - { name: 'st_og_min', type: 'float' }, - { name: 'st_og_max', type: 'float' }, - { name: 'st_fg_min', type: 'float' }, - { name: 'st_fg_max', type: 'float' }, - { name: 'st_ibu_min', type: 'float' }, - { name: 'st_ibu_max', type: 'float' }, - { name: 'st_color_min', type: 'float' }, - { name: 'st_color_max', type: 'float' }, - { name: 'st_carb_min', type: 'float' }, - { name: 'st_carb_max', type: 'float' }, - { name: 'st_abv_min', type: 'float' }, - { name: 'st_abv_max', type: 'float' }, - { name: 'type', type: 'int' }, - { name: 'batch_size', type: 'float' }, - { name: 'boil_size', type: 'float' }, - { name: 'boil_time', type: 'float' }, - { name: 'efficiency', type: 'float' }, - { name: 'est_og', type: 'float' }, - { name: 'est_og3', type: 'float' }, - { name: 'est_fg', type: 'float' }, - { name: 'est_abv', type: 'float' }, - { name: 'est_color', type: 'float' }, - { name: 'color_method', type: 'int' }, - { name: 'est_ibu', type: 'float' }, - { name: 'ibu_method', type: 'int' }, - { name: 'est_carb', type: 'float' }, - { name: 'sparge_temp', type: 'float' }, - { name: 'sparge_ph', type: 'float' }, - { name: 'sparge_volume', type: 'float' }, - { name: 'sparge_source', type: 'int' }, - { name: 'sparge_acid_type', type: 'int' }, - { name: 'sparge_acid_perc', type: 'float' }, - { name: 'sparge_acid_amount', type: 'float' }, - { name: 'mash_ph', type: 'float' }, - { name: 'mash_name', type: 'string' }, - { name: 'calc_acid', type: 'int' }, - { name: 'w1_name', type: 'string' }, - { name: 'w1_amount', type: 'float' }, - { name: 'w1_calcium', type: 'float' }, - { name: 'w1_sulfate', type: 'float' }, - { name: 'w1_chloride', type: 'float' }, - { name: 'w1_sodium', type: 'float' }, - { name: 'w1_magnesium', type: 'float' }, - { name: 'w1_total_alkalinity', type: 'float' }, - { name: 'w1_ph', type: 'float' }, - { name: 'w1_cost', type: 'float' }, - { name: 'w2_name', type: 'string' }, - { name: 'w2_amount', type: 'float' }, - { name: 'w2_calcium', type: 'float' }, - { name: 'w2_sulfate', type: 'float' }, - { name: 'w2_chloride', type: 'float' }, - { name: 'w2_sodium', type: 'float' }, - { name: 'w2_magnesium', type: 'float' }, - { name: 'w2_total_alkalinity', type: 'float' }, - { name: 'w2_ph', type: 'float' }, - { name: 'w2_cost', type: 'float' }, - { name: 'wg_amount', type: 'float' }, - { name: 'wg_calcium', type: 'float' }, - { name: 'wg_sulfate', type: 'float' }, - { name: 'wg_chloride', type: 'float' }, - { name: 'wg_sodium', type: 'float' }, - { name: 'wg_magnesium', type: 'float' }, - { name: 'wg_total_alkalinity', type: 'float' }, - { name: 'wg_ph', type: 'float' }, - { name: 'wb_calcium', type: 'float' }, - { name: 'wb_sulfate', type: 'float' }, - { name: 'wb_chloride', type: 'float' }, - { name: 'wb_sodium', type: 'float' }, - { name: 'wb_magnesium', type: 'float' }, - { name: 'wb_total_alkalinity', type: 'float' }, - { name: 'wb_ph', type: 'float' }, - { name: 'wa_acid_name', type: 'int' }, - { name: 'wa_acid_perc', type: 'int' }, - { name: 'wa_base_name', type: 'int' }, - { name: 'starter_enable', type: 'int' }, - { name: 'starter_type', type: 'int' }, - { name: 'starter_sg', type: 'float' }, - { name: 'starter_viability', type: 'int' }, - { name: 'yeast_prod_date', type: 'string' }, - { name: 'yeast_pitchrate', type: 'float' }, - { name: 'prop1_type', type: 'int' }, - { name: 'prop1_volume', type: 'float' }, - { name: 'prop2_type', type: 'int' }, - { name: 'prop2_volume', type: 'float' }, - { name: 'prop3_type', type: 'int' }, - { name: 'prop3_volume', type: 'float' }, - { name: 'prop4_type', type: 'int' }, - { name: 'prop4_volume', type: 'float' }, - { name: 'divide_type', type: 'int' }, - { name: 'divide_size', type: 'float' }, - { name: 'divide_factor', type: 'float' }, - { name: 'divide_parts', type: 'int' }, - { name: 'divide_part', type: 'int' }, - { name: 'fermentables', type: 'string' }, - { name: 'hops', type: 'string' }, - { name: 'miscs', type: 'string' }, - { name: 'yeasts', type: 'string' }, - { name: 'mashs', type: 'string' } - ], - id: 'record', - url: url + '?record=' + my_record - }, - - // Load data and select one record. - dataAdapter = new $.jqx.dataAdapter(source, { - loadComplete: function() { - dataRecord = dataAdapter.records[0]; - // Hidden record uuid - $('#name').val(dataRecord.name); - $('#code').val(dataRecord.code); - $('#birth').val(dataRecord.birth); - $('#stage').val(StageData[dataRecord.stage].nl); - $('#notes').val(dataRecord.notes); - $('#locked').val(dataRecord.locked); - $('#eq_name').val(dataRecord.eq_name); - $('#eq_notes').val(dataRecord.eq_notes); - $('#eq_boil_size').val(dataRecord.eq_boil_size); - $('#eq_batch_size').val(dataRecord.eq_batch_size); - $('#eq_tun_volume').val(dataRecord.eq_tun_volume); - $('#eq_top_up_water').val(dataRecord.eq_top_up_water); - $('#eq_trub_chiller_loss').val(dataRecord.eq_trub_chiller_loss); - $('#eq_evap_rate').val(dataRecord.eq_evap_rate); - $('#eq_boil_time').val(dataRecord.eq_boil_time); - $('#eq_top_up_kettle').val(dataRecord.eq_top_up_kettle); - $('#eq_hop_utilization').val(dataRecord.eq_hop_utilization); - $('#eq_lauter_volume').val(dataRecord.eq_lauter_volume); - $('#eq_lauter_deadspace').val(dataRecord.eq_lauter_deadspace); - $('#eq_kettle_volume').val(dataRecord.eq_kettle_volume); - $('#eq_mash_volume').val(dataRecord.eq_mash_volume); - $('#eq_mash_max').val(dataRecord.eq_mash_max); - $('#eq_efficiency').val(dataRecord.eq_efficiency); - // Brewdate - $('#brew_date_start').val(dataRecord.brew_date_start); - $('#brew_mash_ph').val(dataRecord.brew_mash_ph); - $('#brew_mash_sg').val(dataRecord.brew_mash_sg); - $('#brew_mash_efficiency').val(dataRecord.brew_mash_efficiency); - // Header Spoelen en filteren - $('#brew_sparge_temperature').val(dataRecord.sparge_temp); - $('#brew_sparge_volume').val(dataRecord.sparge_volume); - $('#brew_sparge_est').val(dataRecord.brew_sparge_est); - $('#brew_sparge_ph').val(dataRecord.brew_sparge_ph); - // Header Beluchten - $('#brew_aeration_type').val(AerationTypeData[dataRecord.brew_aeration_type].nl); - $('#brew_aeration_time').val(dataRecord.brew_aeration_time); - $('#brew_aeration_speed').val(dataRecord.brew_aeration_speed); - - $('#brew_preboil_ph').val(dataRecord.brew_preboil_ph); - $('#brew_preboil_sg').val(dataRecord.brew_preboil_sg); - $('#brew_preboil_volume').val(dataRecord.brew_preboil_volume); - $('#brew_preboil_efficiency').val(dataRecord.brew_preboil_efficiency); - // Header Koelen en whirlpoolen - $('#brew_whirlpool9').val(dataRecord.brew_whirlpool9); - $('#brew_whirlpool7').val(dataRecord.brew_whirlpool7); - $('#brew_whirlpool6').val(dataRecord.brew_whirlpool6); - $('#brew_whirlpool2').val(dataRecord.brew_whirlpool2); - // Header Naar gistvat - $('#brew_fermenter_volume').val(dataRecord.brew_fermenter_volume); - $('#brew_fermenter_sg').val(dataRecord.brew_fermenter_sg); - $('#brew_fermenter_sg2').val(dataRecord.brew_fermenter_sg); - $('#brew_fermenter_ibu').val(dataRecord.brew_fermenter_ibu); - $('#brew_fermenter_color').val(dataRecord.brew_fermenter_color); - $('#brew_fermenter_extrawater').val(dataRecord.brew_fermenter_extrawater); - $('#brew_fermenter_tcloss').val(dataRecord.brew_fermenter_tcloss); - - $('#brew_aboil_ph').val(dataRecord.brew_aboil_ph); - $('#brew_aboil_sg').val(dataRecord.brew_aboil_sg); - $('#brew_aboil_volume').val(dataRecord.brew_aboil_volume); - $('#brew_aboil_efficiency').val(dataRecord.brew_aboil_efficiency); - // Header Koelen en whirlpoolen - $('#brew_cooling_to').val(dataRecord.brew_cooling_to); - $('#brew_cooling_method').val(CoolingTypeData[dataRecord.brew_cooling_method].nl); - $('#brew_cooling_time').val(dataRecord.brew_cooling_time); - // Niks - $('#brew_date_end').val(dataRecord.brew_date_end); - $('#og').val(dataRecord.og); - $('#fg').val(dataRecord.fg); - $('#primary_start_temp').val(dataRecord.primary_start_temp); - $('#primary_max_temp').val(dataRecord.primary_max_temp); - $('#primary_end_temp').val(dataRecord.primary_end_temp); - $('#primary_end_sg').val(dataRecord.primary_end_sg); - $('#primary_end_date').val(dataRecord.primary_end_date); - $('#secondary_temp').val(dataRecord.secondary_temp); - $('#secondary_end_sg').val(dataRecord.secondary_end_sg); - $('#secondary_end_date').val(dataRecord.secondary_end_date); - $('#tertiary_temp').val(dataRecord.tertiary_temp); - $('#package_date').val(dataRecord.package_date); - $('#package_volume').val(dataRecord.package_volume); - $('#package_infuse_amount').val(dataRecord.package_infuse_amount); - $('#package_infuse_abv').val(dataRecord.package_infuse_abv); - $('#package_infuse_notes').val(dataRecord.package_infuse_notes); - $('#package_abv').val(dataRecord.package_abv); - $('#package_ph').val(dataRecord.package_ph); - $('#bottle_amount').val(dataRecord.bottle_amount); - $('#bottle_carbonation').val(dataRecord.bottle_carbonation); - $('#bottle_priming_water').val(dataRecord.bottle_priming_water); - $('#bottle_priming_amount').val(dataRecord.bottle_priming_amount); - $('#bottle_carbonation_temp').val(dataRecord.bottle_carbonation_temp); - $('#keg_amount').val(dataRecord.keg_amount); - $('#keg_carbonation').val(dataRecord.keg_carbonation); - $('#keg_priming_water').val(dataRecord.keg_priming_water); - $('#keg_priming_amount').val(dataRecord.keg_priming_amount); - $('#keg_carbonation_temp').val(dataRecord.keg_carbonation_temp); - $('#keg_forced_carb').val(dataRecord.keg_forced_carb); - $('#keg_pressure').val(dataRecord.keg_pressure); - $('#taste_notes').val(dataRecord.taste_notes); - $('#taste_rate').val(dataRecord.taste_rate); - $('#taste_date').val(dataRecord.taste_date); - $('#taste_color').val(dataRecord.taste_color); - $('#taste_transparency').val(dataRecord.taste_transparency); - $('#taste_head').val(dataRecord.taste_head); - $('#taste_aroma').val(dataRecord.taste_aroma); - $('#taste_taste').val(dataRecord.taste_taste); - $('#taste_mouthfeel').val(dataRecord.taste_mouthfeel); - $('#taste_aftertaste').val(dataRecord.taste_aftertaste); - - // Recipe - $('#st_name').val(dataRecord.st_name); - $('#st_letter').val(dataRecord.st_letter); - $('#st_guide').val(dataRecord.st_guide); - $('#st_category').val(dataRecord.st_category); - $('#st_category_number').val(dataRecord.st_category_number); - $('#st_type').val(StyleTypeData[dataRecord.st_type].nl); - $('#st_og_min').val(dataRecord.st_og_min); - $('#st_og_max').val(dataRecord.st_og_max); - $('#st_fg_min').val(dataRecord.st_fg_min); - $('#st_fg_max').val(dataRecord.st_fg_max); - $('#st_abv_min').val(dataRecord.st_abv_min); - $('#st_abv_max').val(dataRecord.st_abv_max); - $('#st_color_min').val(dataRecord.st_color_min); - $('#st_color_max').val(dataRecord.st_color_max); - $('#st_ibu_min').val(dataRecord.st_ibu_min); - $('#st_ibu_max').val(dataRecord.st_ibu_max); - $('#st_carb_min').val(dataRecord.st_carb_min); - $('#st_carb_min2').val(dataRecord.st_carb_min); - $('#st_carb_max').val(dataRecord.st_carb_max); - $('#st_carb_max2').val(dataRecord.st_carb_max); - $('#type').val(RecipeTypeData[dataRecord.type].nl); - $('#batch_size').val(dataRecord.batch_size); - $('#est_a_vol').val(dataRecord.batch_size * 1.04); - $('#boil_size').val(dataRecord.boil_size); - $('#est_pre_vol').val(dataRecord.boil_size * 1.04); - $('#boil_time').val(dataRecord.boil_time); - $('#efficiency').val(dataRecord.efficiency); - $('#est_og').val(dataRecord.est_og); - $('#est_og2').val(dataRecord.est_og); - $('#est_og3').val(dataRecord.est_og3); - $('#est_fg').val(dataRecord.est_fg); - $('#est_fg2').val(dataRecord.est_fg); - $('#est_fg3').val(dataRecord.est_fg); - $('#est_color').val(dataRecord.est_color); - $('#est_color2').val(dataRecord.est_color); - $('#est_abv').val(dataRecord.est_abv); - $('#color_method').val(ColorMethodData[dataRecord.color_method].nl); - $('#est_ibu').val(dataRecord.est_ibu); - $('#est_ibu2').val(dataRecord.est_ibu); - $('#ibu_method').val(IBUmethodData[dataRecord.ibu_method].nl); - $('#est_carb').val(dataRecord.est_carb); - $('#mash_name').val(dataRecord.mash_name); - $('#mash_ph').val(dataRecord.mash_ph); - $('#sparge_temp').val(dataRecord.sparge_temp); - $('#sparge_ph').val(dataRecord.sparge_ph); - $('#sparge_volume').val(dataRecord.sparge_volume); - $('#sparge_source').val(dataRecord.sparge_source); - $('#sparge_acid_type').val(AcidTypeData[dataRecord.sparge_acid_type].nl); - $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); - $('#sparge_acid_amount').val(dataRecord.sparge_acid_amount * 1000); - $('#calc_acid').val(dataRecord.calc_acid); - $('#w1_name').val(dataRecord.w1_name); - $('#w1_amount').val(dataRecord.w1_amount); - $('#w1_calcium').val(dataRecord.w1_calcium); - $('#w1_sulfate').val(dataRecord.w1_sulfate); - $('#w1_chloride').val(dataRecord.w1_chloride); - $('#w1_sodium').val(dataRecord.w1_sodium); - $('#w1_magnesium').val(dataRecord.w1_magnesium); - $('#w1_total_alkalinity').val(dataRecord.w1_total_alkalinity); - $('#w1_bicarbonate').val(dataRecord.w1_total_alkalinity * 1.22); - $('#w1_ph').val(dataRecord.w1_ph); - $('#w1_cost').val(dataRecord.w1_cost); - $('#w2_name').val(dataRecord.w2_name); - $('#w2_amount').val(dataRecord.w2_amount); - $('#w2_calcium').val(dataRecord.w2_calcium); - $('#w2_sulfate').val(dataRecord.w2_sulfate); - $('#w2_chloride').val(dataRecord.w2_chloride); - $('#w2_sodium').val(dataRecord.w2_sodium); - $('#w2_magnesium').val(dataRecord.w2_magnesium); - $('#w2_total_alkalinity').val(dataRecord.w2_total_alkalinity); - $('#w2_bicarbonate').val(dataRecord.w2_total_alkalinity * 1.22); - $('#w2_ph').val(dataRecord.w2_ph); - $('#w2_cost').val(dataRecord.w2_cost); - $('#wg_amount').val(dataRecord.wg_amount); - $('#wg_calcium').val(dataRecord.wg_calcium); - $('#wg_sulfate').val(dataRecord.wg_sulfate); - $('#wg_chloride').val(dataRecord.wg_chloride); - $('#wg_sodium').val(dataRecord.wg_sodium); - $('#wg_magnesium').val(dataRecord.wg_magnesium); - $('#wg_total_alkalinity').val(dataRecord.wg_total_alkalinity); - $('#wg_ph').val(dataRecord.wg_ph); - $('#wb_calcium').val(dataRecord.wb_calcium); - $('#wb_sulfate').val(dataRecord.wb_sulfate); - $('#wb_chloride').val(dataRecord.wb_chloride); - $('#wb_sodium').val(dataRecord.wb_sodium); - $('#wb_magnesium').val(dataRecord.wb_magnesium); - $('#wb_total_alkalinity').val(dataRecord.wb_total_alkalinity); - $('#wb_ph').val(dataRecord.wb_ph); - $('#wa_acid_name').val(dataRecord.wa_acid_name); - $('#wa_acid_perc').val(dataRecord.wa_acid_perc); - $('#starter_type').val(StarterTypeData[dataRecord.starter_type].nl); - $('#starter_sg').val(dataRecord.starter_sg); - $('#starter_viability').val(dataRecord.starter_viability); - $('#yeast_prod_date').val(dataRecord.yeast_prod_date); - $('#yeast_pitchrate').val(dataRecord.yeast_pitchrate); - $('#prop1_type').val(StarterTypeData[dataRecord.prop1_type].nl); - $('#prop1_volume').val(dataRecord.prop1_volume); - $('#prop2_type').val(StarterTypeData[dataRecord.prop2_type].nl); - $('#prop2_volume').val(dataRecord.prop2_volume); - $('#prop3_type').val(StarterTypeData[dataRecord.prop3_type].nl); - $('#prop3_volume').val(dataRecord.prop3_volume); - $('#prop4_type').val(StarterTypeData[dataRecord.prop4_type].nl); - $('#prop4_volume').val(dataRecord.prop4_volume); - $('#divide_type').val(SplitData[dataRecord.divide_type].nl); - if (dataRecord.divide_type > 0) - $('#divide_batch').val((dataRecord.divide_part + 1) + ' van ' + (dataRecord.divide_parts + 1)); - else - $('#divide_batch').val('n.v.t.'); - // hidden divide_size - // hidden divide_factor - // hidden divide_parts - // hidden divide_part - editFermentable(dataRecord); - editHop(dataRecord); - editMisc(dataRecord); - editYeast(dataRecord); - editMash(dataRecord); - calcStage(); - $('#jqxTabs').jqxTabs('select', 2); - data_loaded = 1; - }, - loadError: function(jqXHR, status, error) { - console.log('main data load error: ' + status + ' ' + error); - } - }); - - // Inline fermentables editor - var editFermentable = function(data) { - var fermentableSource = { - localdata: data.fermentables, - datafields: [ - { name: 'f_name', type: 'string' }, - { name: 'f_origin', type: 'string' }, - { name: 'f_supplier', type: 'string' }, - { name: 'f_amount', type: 'float' }, - { name: 'f_cost', type: 'float' }, - { name: 'f_type', type: 'int' }, - { name: 'f_yield', type: 'float' }, - { name: 'f_color', type: 'float' }, - { name: 'f_coarse_fine_diff', type: 'float' }, - { name: 'f_moisture', type: 'float' }, - { name: 'f_diastatic_power', type: 'float' }, - { name: 'f_protein', type: 'float' }, - { name: 'f_max_in_batch', type: 'float' }, - { name: 'f_graintype', type: 'int' }, - { name: 'f_added', type: 'int' }, - { name: 'f_dissolved_protein', type: 'float' }, - { name: 'f_recommend_mash', type: 'int' }, - { name: 'f_add_after_boil', type: 'int' }, - { name: 'f_adjust_to_total_100', type: 'int' }, - { name: 'f_percentage', type: 'float' }, - { name: 'f_di_ph', type: 'float' }, - { name: 'f_acid_to_ph_57', type: 'float' }, - { name: 'f_inventory', type: 'float' }, - { name: 'f_avail', type: 'int' } - ], - }, - fermentableAdapter = new $.jqx.dataAdapter(fermentableSource); - - $('#fermentableGrid').jqxGrid({ - width: 1240, - height: 470, - source: fermentableAdapter, - theme: theme, - editable: false, - ready: function() { calcFermentables(); $('#jqxTabs').jqxTabs('next'); }, - columns: [ - { text: 'Vergistbaar ingrediënt', datafield: 'f_name' }, - { text: 'Leverancier', datafield: 'f_supplier', width: 180 }, - { text: 'Kleur', datafield: 'f_color', width: 90, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + dataAdapter.formatNumber(value, 'f0') + ' EBC'; - } - }, - { text: 'Type', width: 100, datafield: 'f_type', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + FermentableTypeData[value].nl + ''; - } - }, - { text: 'Moment', width: 110, datafield: 'f_added', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + AddedData[value].nl + ''; - } - }, - { text: 'Maxinbatch', datafield: 'f_max_in_batch', hidden: true }, - { text: 'Opbrengst', datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, - { text: 'Gewicht Kg', datafield: 'f_amount', width: 110, align: 'right', cellsalign: 'right', cellsformat: 'f3' }, - { text: 'Voorraad Kg', datafield: 'f_inventory', width: 110, align: 'right', - cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { - var color = (value < rowdata.f_amount) ? '#ff4040':'#ffffff'; - if (block_fermentable(dataRecord.inventory_reduced, rowdata.f_added) == false) { - return '' + fermentableAdapter.formatNumber(value, 'f3') + ''; - } else { - return ''; - } - } - }, - { text: 'Procent', datafield: 'f_percentage', width: 90, align: 'right', - cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { - if (rowdata.f_added >= 4) - return ''; - var color = (value > rowdata.f_max_in_batch) ? '#ff4040':'#ffffff'; - return '' + fermentableAdapter.formatNumber(value, 'p1') + ''; - } - }, - { text: '100%', datafield: 'f_adjust_to_total_100', width: 70, align: 'center', cellsalign: 'center', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - if (value == 0) - return ''; - return ''; - } - } - ] - }); - }; - - // Inline hops editor - var editHop = function(data) { - var hopSource = { - localdata: data.hops, - datafields: [ - { name: 'h_name', type: 'string' }, - { name: 'h_origin', type: 'string' }, - { name: 'h_amount', type: 'float' }, - { name: 'h_cost', type: 'float' }, - { name: 'h_type', type: 'int' }, - { name: 'h_form', type: 'int' }, - { name: 'h_useat', type: 'int' }, - { name: 'h_time', type: 'int' }, - { name: 'h_alpha', type: 'float' }, - { name: 'h_beta', type: 'float' }, - { name: 'h_hsi', type: 'float' }, - { name: 'h_humulene', type: 'float' }, - { name: 'h_caryophyllene', type: 'float' }, - { name: 'h_cohumulone', type: 'float' }, - { name: 'h_myrcene', type: 'float' }, - { name: 'h_total_oil', type: 'float' }, - { name: 'h_inventory', type: 'float' }, - { name: 'h_avail', type: 'int' }, - { name: 'h_utilisation', type: 'float' }, - { name: 'h_bu_factor', type: 'float' } - ], - }, - hopAdapter = new $.jqx.dataAdapter(hopSource); - - $('#hopGrid').jqxGrid({ - width: 1240, - height: 560, - source: hopAdapter, - theme: theme, - editable: false, - ready: function() { $('#jqxTabs').jqxTabs('next'); }, - columns: [ - { text: 'Hop', datafield: 'h_name' }, - { text: 'Origin', width: 180, datafield: 'h_origin' }, - { text: 'Type', width: 90, datafield: 'h_type', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + HopTypeData[value].nl + ''; - } - }, - { text: 'Vorm', width: 110, datafield: 'h_form', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + HopFormData[value].nl + ''; - } - }, - { text: 'Alpha', datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, - { text: 'Gebruik', width: 110, datafield: 'h_useat', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + HopUseData[value].nl + ''; - } - }, - { text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - var duration = ''; - if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4)) // Boil, Whirlpool - duration = dataAdapter.formatNumber(value, 'f0') + ' min.'; - else if (rowdata.h_useat == 5) // Dry hop - duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; - return '' + duration + ''; - } - }, - { text: 'IBU', datafield: 'ibu', width: 80, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat(dataRecord.batch_size), - parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), dataRecord.ibu_method, - dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); - return '' + dataAdapter.formatNumber(ibu, 'f1') + ''; - } - }, - { text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - var amount = dataAdapter.formatNumber(value, 'f1') + ' kg'; - if (value < 1) - amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; - return '' + amount + ''; - } - }, - { text: 'Voorraad', datafield: 'h_inventory', width: 110, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - if (block_hop(dataRecord.inventory_reduced, rowdata.h_useat) == false) { - var amount = dataAdapter.formatNumber(value, 'f1') + ' kg', - color = (value < rowdata.h_amount) ? '#ff4040':'#ffffff'; - if (value < 1) - amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; - return '' + amount + ''; - } else { - return ''; - } - } - } - ] - }); - }; - - // Inline miscs editor - var editMisc = function(data) { - var miscSource = { - localdata: data.miscs, - datafields: [ - { name: 'm_name', type: 'string' }, - { name: 'm_amount', type: 'float' }, - { name: 'm_cost', type: 'float' }, - { name: 'm_type', type: 'int' }, - { name: 'm_use_use', type: 'int' }, - { name: 'm_time', type: 'float' }, - { name: 'm_amount_is_weight', type: 'int' }, - { name: 'm_inventory', type: 'float' }, - { name: 'm_avail', type: 'int' } - ], - }, - miscAdapter = new $.jqx.dataAdapter(miscSource, { - beforeLoadComplete: function(records) { - var row, i, data = new Array(); - for (i = 0; i < records.length; i++) { - row = records[i]; - data.push(row); - // Initial set water agent values. - if (row.m_use_use == 1) { // Mash - switch (row.m_name) { - case 'CaCl2': - $('#wa_cacl2').val(row.m_amount * 1000); - break; - case 'CaSO4': - $('#wa_caso4').val(row.m_amount * 1000); - break; - case 'MgSO4': - $('#wa_mgso4').val(row.m_amount * 1000); - break; - case 'NaCl': - $('#wa_nacl').val(row.m_amount * 1000); - break; - case 'MgCl2': - $('#wa_mgcl2').val(row.m_amount * 1000); - break; - case 'NaHCO3': - $('#wa_nahco3').val(row.m_amount * 1000); - break; - case 'CaCO3': - $('#wa_caco3').val(row.m_amount * 1000); - break; - case 'Melkzuur': - $('#wa_acid_name').val(AcidTypeData[0].nl); - $('#wa_acid').val(row.m_amount * 1000); - $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); - last_acid = 'Melkzuur'; - break; - case 'Zoutzuur': - $('#wa_acid_name').val(AcidTypeData[1].nl); - $('#wa_acid').val(row.m_amount * 1000); - $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc); - last_acid = 'Zoutzuur'; - break; - case 'Fosforzuur': - $('#wa_acid_name').val(AcidTypeData[2].nl); - $('#wa_acid').val(row.m_amount * 1000); - $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc); - last_acid = 'Fosforzuur'; - break; - case 'Zwavelzuur': - $('#wa_acid_name').val(AcidTypeData[3].nl); - $('#wa_acid').val(row.m_amount * 1000); - $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc); - last_acid = 'Zwavelzuur'; - break; - } - } - if (row.m_use_use == 6) { // Sparge - switch (row.m_name) { - case 'CaCl2': - $('#ss_cacl2').val(row.m_amount * 1000); - break; - case 'CaSO4': - $('#ss_caso4').val(row.m_amount * 1000); - break; - case 'MgSO4': - $('#ss_mgso4').val(row.m_amount * 1000); - break; - case 'NaCl': - $('#ss_nacl').val(row.m_amount * 1000); - break; - case 'MgCl2': - $('#ss_mgcl2').val(row.m_amount * 1000); - break; - } - } - } - return data; - }, - loadError: function(jqXHR, status, error) { console.log('miscs load error ' + status + ' ' + error); }, - }); - $('#miscGrid').jqxGrid({ - width: 1240, - height: 575, - source: miscAdapter, - theme: theme, - editable: false, - ready: function() { $('#jqxTabs').jqxTabs('next'); }, - columns: [ - { text: 'Ingredient', datafield: 'm_name' }, - { text: 'Type', width: 140, datafield: 'm_type', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + MiscTypeData[value].nl + ''; - } - }, - { text: 'Gebruik', width: 140, datafield: 'm_use_use', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + MiscUseData[value].nl + ''; - } - }, - { text: 'Tijd', datafield: 'm_time', width: 90, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - var duration = ''; - if (rowdata.m_use_use == 2) // Boil - duration = dataAdapter.formatNumber(value, 'f0') + ' min.'; - else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) // Primary or Secondary - duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; - return '' + duration + ''; - } - }, - { text: 'Hoeveel', datafield: 'm_amount', width: 110, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml'; - return '' + dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr + ''; - } - }, - { text: 'Voorraad', datafield: 'm_inventory', width: 110, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - if (block_misc(dataRecord.inventory_reduced, rowdata.m_use_use) == false) { - var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml', - color = (value < rowdata.m_amount) ? '#ff4040':'#ffffff', - amount = dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr; - return '' + amount + ''; - } else { - return ''; - } - } - } - ] - }); - }; - - // Inline yeasts editor - var editYeast = function(data) { - var yeastSource = { - localdata: data.yeasts, - datafields: [ - { name: 'y_name', type: 'string' }, - { name: 'y_laboratory', type: 'string' }, - { name: 'y_product_id', type: 'string' }, - { name: 'y_amount', type: 'float' }, - { name: 'y_cost', type: 'float' }, - { name: 'y_type', type: 'int' }, - { name: 'y_form', type: 'int' }, - { name: 'y_flocculation', type: 'int' }, - { name: 'y_min_temperature', type: 'float' }, - { name: 'y_max_temperature', type: 'float' }, - { name: 'y_attenuation', type: 'float' }, - { name: 'y_use', type: 'int' }, - { name: 'y_cells', type: 'float' }, - { name: 'y_tolerance', type: 'float' }, - { name: 'y_inventory', type: 'float' }, - { name: 'y_sta1', type: 'int' }, - { name: 'y_bacteria', type: 'int' }, - { name: 'y_harvest_top', type: 'int' }, - { name: 'y_harvest_time', type: 'int' }, - { name: 'y_pitch_temperature', type: 'float' }, - { name: 'y_pofpos', type: 'int' }, - { name: 'y_zymocide', type: 'int' }, - { name: 'y_gr_hl_lo', type: 'int' }, - { name: 'y_sg_lo', type: 'float' }, - { name: 'y_gr_hl_hi', type: 'int' }, - { name: 'y_sg_hi', type: 'float' }, - { name: 'y_avail', type: 'int' } - ], - }, - yeastAdapter = new $.jqx.dataAdapter(yeastSource); - - $('#yeastGrid').jqxGrid({ - width: 1240, - height: 325, - source: yeastAdapter, - theme: theme, - editable: false, - ready: function() { $('#jqxTabs').jqxTabs('next'); }, - columns: [ - { text: 'Gist', datafield: 'y_name' }, - { text: 'Laboratorium', width: 150, datafield: 'y_laboratory' }, - { text: 'Code', width: 90, datafield: 'y_product_id' }, - { text: 'Soort', width: 100, datafield: 'y_form', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + YeastFormData[value].nl + ''; - } - }, - { text: 'Min. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' }, - { text: 'Max. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' }, - { text: 'Tol. %', width: 60, align: 'right', cellsalign: 'right', datafield: 'y_tolerance', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - var amount = '', color = (dataRecord.est_abv > value) ? '#ff4040':'#ffffff'; - if (value > 0) { - amount = dataAdapter.formatNumber(value, 'f1'); - } - return '' + amount + ''; - } - }, - { text: 'Attn. %', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' }, - { text: 'Voor', width: 120, datafield: 'y_use', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + YeastUseData[value].nl + ''; - } - }, - { text: 'Hoeveel', datafield: 'y_amount', width: 90, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - var amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml'; - if (rowdata.y_form == 0) // Liquid - amount = dataAdapter.formatNumber(value, 'f0') + ' pk'; - else if (rowdata.y_form == 1 || rowdata.y_form == 6) // Dry - amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; - return '' + amount + ''; - } - }, - { text: 'Voorraad', datafield: 'y_inventory', width: 90, align: 'right', - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - var color, amount; - if (block_yeast(dataRecord.inventory_reduced, rowdata.y_use) == false) { - color = '#ffffff'; - if (value < rowdata.y_amount) - color = '#ff4040'; - amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml'; - if (rowdata.y_form == 0) // Liquid - amount = dataAdapter.formatNumber(value, 'f0') + ' pk'; - else if (rowdata.y_form == 1 || rowdata.y_form == 6) // Dry - amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; - return '' + amount + ''; - } else { - return ''; - } - } - } - ] - }); - }; - - // inline mash editor - var editMash = function(data) { - var mashSource = { - localdata: data.mashs, - datafields: [ - { name: 'step_name', type: 'string' }, - { name: 'step_type', type: 'int' }, - { name: 'step_volume', type: 'float' }, - { name: 'step_infuse_amount', type: 'float' }, - { name: 'step_infuse_temp', type: 'float' }, - { name: 'step_temp', type: 'float' }, - { name: 'step_time', type: 'float' }, - { name: 'step_wg_ratio', type: 'float' }, - { name: 'ramp_time', type: 'float' }, - { name: 'end_temp', type: 'float' }, - { name: 'step_ph', type: 'float' }, - { name: 'step_sg', type: 'float' } - ], - }, - mashAdapter = new $.jqx.dataAdapter(mashSource); - - $('#mashGrid').jqxGrid({ - width: 1240, - height: 400, - source: mashAdapter, - theme: theme, - selectionmode: 'singlerow', - editable: false, - ready: function() { - /* Calculate the whole recipe */ - console.log('ready mashs, start calculations'); - /* calcFermentables() must be first and is done by the grid load. Here it is too late. */ - calcMash(); - calcWater(); - calcIBUs(); - whirlpoolHops(); - calcMiscs(); - calcViability(); - calcYeast(); - kookTijd(); - calcFermentation(); - calcCarbonation(); - $('#FLog').jqxButton({ disabled: (dataRecord.log_fermentation) ? false : true}); - $('#ILog').jqxButton({ disabled: (dataRecord.log_ispindel) ? false : true}); - $('#CLog').jqxButton({ disabled: (dataRecord.log_co2pressure) ? false : true}); - console.log('calculations ready'); - $('#jqxLoader').jqxLoader('close'); - $('#jqxTabs').jqxTabs('first'); - }, - columns: [ - { text: 'Stap naam', datafield: 'step_name' }, - { text: 'Stap type', datafield: 'step_type', width: 150, - cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { - return '' + MashStepTypeData[value].nl + ''; - } - }, - { text: 'Start °C', datafield: 'step_temp', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, - { text: 'Eind °C', datafield: 'end_temp', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, - { text: 'Rust min.', datafield: 'step_time', width: 80, align: 'right', cellsalign: 'right' }, - { text: 'Stap min.', datafield: 'ramp_time', width: 80, align: 'right', cellsalign: 'right' }, - { text: 'Inf/dec L.', datafield: 'step_infuse_amount', width: 80, align: 'right', - cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { - if (rowdata.step_type == 1) - return ''; - var color = '#ffffff'; - var mvol = mashkg * MaltVolume; - if ((rowdata.step_wg_ratio * mashkg + mvol) > dataRecord.eq_tun_volume) - color = '#ff4040'; - return '' + dataAdapter.formatNumber(value, 'f1') + ''; - } - }, - { text: 'Inf/dec °C', datafield: 'step_infuse_temp', width: 90, align: 'right', - cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { - if (rowdata.step_type == 1) - return ''; - return '' + dataAdapter.formatNumber(value, 'f2') + ''; - } - }, - { text: 'L/Kg.', datafield: 'step_wg_ratio', width: 80, align: 'right', - cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { - var color = '#ffffff'; - if (value < 2.0 || value > 6.0) - color = '#ff4040'; - return '' + dataAdapter.formatNumber(value, 'f2') + ''; - } - }, - { text: 'pH', datafield: 'step_ph', width: 70, align: 'right', cellsalign: 'right', cellsformat: 'f2' }, - { text: 'SG', datafield: 'step_sg', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f3' } - ] - }); - }; - - /* - * Remove the top menu so that we MUST use the button to leave the editor. - */ - $('#jqxMenu').jqxMenu('destroy'); - console.log('record:' + my_record + ' return:' + my_return + ' theme:' + theme); - $('#jqxLoader').jqxLoader({ width: 250, height: 150, isModal: true, text: 'Laden product ...', theme: theme }); - $('#jqxLoader').jqxLoader('open'); - - /* Moved to before all functions */ - dataAdapter.dataBind(); - - /* - * Generic functions - */ - function kookTijd() { - if (dataRecord.boil_time) { - $('#brew_pmpt_koken').html('Koken ' + dataRecord.boil_time + ' minuten'); - } else { - $('#brew_pmpt_koken').html('Koken "no-boil"'); - } - } - - function infusionVol(step_infused, step_mashkg, infuse_temp, step_temp, last_temp) { - var a = last_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); - var b = step_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); - var vol = Round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)), 2); - return vol; - } - - function decoctionVol(step_volume, step_temp, prev_temp) { - var a = (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp); - var b = SpecificHeatWater * (99 - step_temp); - var vol = 0; - if (b > 0) - vol = Round(a / b, 6); - return vol; - } - - function calcViability() { - var vpm = 1.00; - var max = 100; - var rowscount = dataRecord.yeasts.length; - if (rowscount) { - for (i = 0; i < rowscount; i++) { - row = dataRecord.yeasts[i]; - if (row.y_use == 0) { - if (row.y_form == 0) { // Liquid - vpm = 0.80; - max = 97; - if (row.y_laboratory == 'White Labs') { // PurePitch - vpm = 0.95; - max = 100; - } - } else if (row.y_form == 1) { // dry yeast - vpm = 0.998; - max = 100; - } else if (row.y_form == 6) { // Dried kveik - vpm = 0.92; - max = 100; - } else { // Slant, Culture, Frozen, Bottle - vpm = 0.99; - max = 97; - } - } - } - } - var base = max; - var days = 0; - - if (parseFloat($('#yeast_prod_date').val()) > 2000) { - console.log('calculate viability'); - var d = new Date(); - var date2 = $('#yeast_prod_date').val(); - date2 = date2.split('-'); - // Now we convert the array to a Date object - var date1 = new Date(d.getFullYear(), d.getMonth(), d.getDate()); - date2 = new Date(date2[0], date2[1] - 1, date2[2]); - var diff = parseInt(date1.getTime()) - parseInt(date2.getTime()); - days = Math.floor(diff/1000/60/60/24); - - var degrade = 1 - ((1 - vpm) / 30.41); // viability degradation per day. - for (i = 0; i < days; i++) { - base = base * degrade; - } - if (base > max) { - base = max; - } - base = Math.round(base); - } - console.log('age:' + days + ' max:' + max + ' vpm:' + vpm + ' base:' + base); - - if (dataRecord.starter_viability != base) { - dataRecord.starter_viability = base; - $('#starter_viability').val(dataRecord.starter_viability); - } - } - - function calcSupplies() { - if (dataRecord.inventory_reduced > 6) { - $('#ok_pmpt').hide(); - return; - } - if (ok_fermentables && ok_hops && ok_miscs && ok_yeasts && ok_waters) - $('#ok_supplies').html(""); - else - $('#ok_supplies').html(""); - } - - /* - * All calculations that depend on changes in the fermentables, - * volumes and equipments. - */ - function calcFermentables() { - - var sugarsf = 0, // fermentable sugars mash + boil - sugarsm = 0, // fermentable sugars in mash - vol = 0, // Volume sugars after boil - addedS = 0, // Added sugars after boil - addedmass = 0, // Added mass after boil - mvol = 0, // mash volume - infuse = 0, // mash infuse volume - colort = 0, // Colors srm * vol totals - colorh = 0, // Colors ebc * vol * kt - colorn = 0, // Colors ebc * pt * pct - my_100 = false, - mashtime = 0, // Total mash time - mashtemp = 0, // Average mash temperature - bv = 0.925, // Bierverlies rendement - sr = 0.95, // Mash en spoel rendement - lintner = 0, // Total recipe lintner - i, row, rows, org, timem, aboil_volume, spoelw, ogx, topw, s = 0, d, v, x, - sug, alc, pt, cw, color, scolor, fig; - - /* Init global variables */ - psugar = 0; - pcara = 0; - mashkg = 0; - ok_fermentables = 1; // All is in stock. - ok_yeasts = 1; - - if (dataRecord.mashs.length) { - for (i = 0; i < dataRecord.mashs.length; i++) { - row = dataRecord.mashs[i]; - if (parseFloat(row.step_type) == 0) // Infusion - mvol += parseFloat(row.step_infuse_amount); - if (row.step_temp <= 75 && row.step_temp >= 60) { // Ignore mashout - timem = row.step_time; - if (i > 0) - timem += row.ramp_time; - mashtime += timem; - mashtemp += timem * row.step_temp; - } - } - infuse = mvol; - mashtemp = Round(mashtemp / mashtime, 2); - } else { - console.log("calcFermentables() no mash steps"); - } - - if (! dataRecord.fermentables.length) { - console.log("calcFermentables() no fermentables"); - return; // grid not yet loaded. - } - - for (i = 0; i < dataRecord.fermentables.length; i++) { - row = dataRecord.fermentables[i]; - if (row.f_adjust_to_total_100) - my_100 = true; - if (row.f_type == 1 && row.f_added < 4) // Sugar - psugar += row.f_percentage; - if (row.f_graintype == 2 && row.f_added < 4) // Crystal - pcara += row.f_percentage; - d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); - if (row.f_added == 0) { // Mash - if (mvol > 0) { // Only if mash already known. - mvol += row.f_amount * row.f_moisture / 100; - s += d; - } - d = parseFloat(dataRecord.efficiency) / 100 * d; - sugarsm += d; - mashkg += parseFloat(row.f_amount); - } - if (row.f_added == 0 || row.f_added == 1) // Mash or Boil - sugarsf += d; - if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering - x = (row.f_yield / 100) * (1 - row.f_moisture / 100); - addedS += row.f_amount * x; - addedmass += row.f_amount; - vol += (x * sugardensity + (1 - x) * 1) * row.f_amount; - } - if (row.f_added < 4) { - colort += row.f_amount * ebc_to_srm(row.f_color); - colorh += row.f_amount * row.f_color * get_kt(row.f_color); - colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort. - } - if (fermentableInit) { - if (row.f_added == 4) { - $('#bottle_priming_total').val(row.f_amount * 1000); // Prevent clearing - $('#bottle_priming_sugar').val(row.f_name); - } - if (row.f_added == 5) { - $('#keg_priming_total').val(row.f_amount * 1000); - $('#keg_priming_sugar').val(row.f_name); - } - } - // Check supplies. - if ((((dataRecord.inventory_reduced <= 2) && (row.f_added <= 1)) || // Mash or boil - ((dataRecord.inventory_reduced <= 3) && (row.f_added == 2)) || // Primary - ((dataRecord.inventory_reduced <= 5) && (row.f_added == 3)) || // Secondary or Tertiary - ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4)) || // Bottle - ((dataRecord.inventory_reduced <= 6) && (row.f_added == 5))) && row.f_inventory < row.f_amount) { - ok_fermentables = 0; - } - if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50 - lintner += row.f_diastatic_power * row.f_amount; - } - } - fermentableInit = 0; - $('#ferm_lintner').val(Math.round(parseFloat(lintner / mashkg))); - $('#mash_kg').val(mashkg); - console.log('calcFermentables() supplies:' + ok_fermentables + ' moutsuiker:' + Round(sugarsm, 3) + '/' + Round(sugarsf, 3)); - to_100 = my_100; - - if (mvol > 0) { - v = s / sugardensity + mvol; - s = 1000 * s / (v * 10); //deg. Plato - est_mash_sg = Round(plato_to_sg(s), 5); - $('#est_mash_sg').val(est_mash_sg); - } - - // Estimate total recipe OG. - dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size)); - $('#est_og').val(dataRecord.est_og); - $('#est_og2').val(dataRecord.est_og); - org = dataRecord.est_og; - - // Estimate SG in kettle after boil - aboil_sg = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size)); - $('#est_og3').val(aboil_sg); - - // Estimate SG in kettle before boil - preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size)); - $('#est_pre_sg').val(preboil_sg); - - // Recalculate volumes. - aboil_volume = parseFloat(dataRecord.batch_size); - if (dataRecord.brew_aboil_volume > 0) - aboil_volume = dataRecord.brew_aboil_volume / 1.04; // volume @ 20 degrees - if (dataRecord.brew_fermenter_tcloss == 0) { - dataRecord.brew_fermenter_tcloss = dataRecord.eq_trub_chiller_loss; - $('#brew_fermenter_tcloss').val(dataRecord.brew_fermenter_tcloss); - } - dataRecord.brew_fermenter_volume = aboil_volume - dataRecord.brew_fermenter_tcloss + dataRecord.brew_fermenter_extrawater; - $('#brew_fermenter_volume').val(dataRecord.brew_fermenter_volume); - // Calculate SG in fermenter - ogx = dataRecord.brew_aboil_sg; - if (ogx < 1.002) - ogx = aboil_sg; - topw = dataRecord.brew_fermenter_extrawater; - - if (dataRecord.brew_fermenter_volume > 0) { - sug = sg_to_plato(ogx) * dataRecord.brew_fermenter_volume * ogx / 100; //kg of sugar in - sug += addedS; //kg - - if ((dataRecord.brew_fermenter_volume * ogx + addedmass) > 0) { - pt = 100 * sug / (dataRecord.brew_fermenter_volume * ogx + addedmass + topw); - dataRecord.og = dataRecord.brew_fermenter_sg = Round(plato_to_sg(pt), 4); - $('#brew_fermenter_sg').val(dataRecord.brew_fermenter_sg); - // color - if (dataRecord.color_method == 4) { - dataRecord.brew_fermenter_color = Math.round(((pt / 8.6) * colorn) + (dataRecord.boil_time / 60)); - } else if (dataRecord.color_method == 3) { - dataRecord.brew_fermenter_color = Math.round((4.46 * bv * sr) / (aboil_volume + topw) * colorh); - } else { - cw = colort / (aboil_volume + topw) * 8.34436; - dataRecord.brew_fermenter_color = kw_to_ebc(dataRecord.color_method, cw); - } - $('#brew_fermenter_color').val(dataRecord.brew_fermenter_color); - scolor = ebc_to_color(dataRecord.brew_fermenter_color); - $('#bcolorf').show(); - document.getElementById('bcolorf').style.background = scolor; - } - } else { - // Negative volume - dataRecord.brew_fermenter_sg = dataRecord.brew_fermenter_color = 0; - $('#brew_fermenter_sg').val(0); - $('#brew_fermenter_color').val(0); - $('#bcolorf').hide(); - } - - // Color of the wort - if (dataRecord.color_method == 4) { - color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60)); - } else if (dataRecord.color_method == 3) { // Hans Halberstadt - color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh); - } else { - cw = colort / parseFloat(dataRecord.batch_size) * 8.34436; - color = kw_to_ebc(dataRecord.color_method, cw); - } - dataRecord.est_color = color; - $('#est_color').val(color); - $('#est_color2').val(color); - scolor = ebc_to_color(color); - document.getElementById('bcolor').style.background = scolor; - document.getElementById('bcolor2').style.background = scolor; - - // Progress bars - pmalts = mashkg / dataRecord.eq_mash_max * 100; - $('#perc_malts').jqxProgressBar('val', pmalts); - $('#perc_sugars').jqxProgressBar('val', psugar); - $('#perc_cara').jqxProgressBar('val', pcara); - calcStage(); - - // Calculate estimated svg. - svg = 0; // default. - initcells = 0; - for (i = 0; i < dataRecord.yeasts.length; i++) { - row = dataRecord.yeasts[i]; - if (row.y_use == 0) { // Primary - if (parseFloat(row.y_attenuation) > svg) - svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts. - if (row.y_form == 0) - initcells += (parseFloat(row.y_cells) / 1000000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100); - else - initcells += (parseFloat(row.y_cells) / 1000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100); - } - // TODO: brett in secondary ?? - if ((((dataRecord.inventory_reduced <= 3) && (row.y_use == 0)) || // Primary - ((dataRecord.inventory_reduced <= 4) && (row.y_use == 1)) || // Secondary - ((dataRecord.inventory_reduced <= 5) && (row.y_use == 2)) || // Tertiary - ((dataRecord.inventory_reduced <= 6) && (row.y_use == 3))) && // Bottle - (row.y_inventory < row.y_amount)) { - ok_yeasts = 0; - } - } - calcSupplies(); - if (svg == 0) - svg = 77; - if ((mashkg > 0) && (infuse > 0) && (mashtime > 0) && (mashtemp > 0)) { - dataRecord.est_fg = estimate_fg(psugar, pcara, infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og); - } else { - dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og); - } - $('#est_fg').val(dataRecord.est_fg); - $('#est_fg2').val(dataRecord.est_fg); - $('#est_fg3').val(dataRecord.est_fg); - fig = dataRecord.est_fg; - - dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg); - $('#est_abv').val(dataRecord.est_abv); - $('#est_abv2').val(dataRecord.est_abv); - - // Calculate the final svg if available use the real value. - if ((dataRecord.stage >= 6) && (dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { - svg = calc_svg(dataRecord.brew_fermenter_sg, dataRecord.fg); - org = dataRecord.brew_fermenter_sg; - fig = dataRecord.fg; - } - - $('#yeast_cells').val(initcells); - $('#need_cells').val(getNeededYeastCells()); - - // Calculate the calories in kcal/l (from brouwhulp) - alc = 1881.22 * fig * (org - fig) / (1.775 - org); - sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004); - $('#kcal').val(Math.round((alc + sug) / (12 * 0.0295735296))); - }; - - function calcMash() { - - var h, m, infused = 0, mashtime = 0, mashvol = 0, vol, i, j, n, a, b, row, temp; - var lasttemp = 18.0; - var graintemp = 18.0; - var tuntemp = 18.0; - - if (dataRecord.mashs.length && (mashkg > 0)) { - console.log('calcMash()'); - for (i = 0; i < dataRecord.mashs.length; i++) { - row = dataRecord.mashs[i]; - if (row.step_type == 0) { // Infusion - if (i == 0) { - // First mash step, temperature from the mashtun and malt. - n = 20; // tun is preheated. - tuntemp = row.step_temp; - for (j = 0; j < n; j++) { - a = mashkg * graintemp * SpecificHeatMalt + dataRecord.eq_tun_weight * tuntemp * dataRecord.eq_tun_specific_heat; - b = row.step_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + row.step_infuse_amount * SpecificHeatWater + mashkg * SpecificHeatMalt) - SlakingHeat * mashkg; - if (row.step_infuse_amount > 0) { - temp = (b - a) / (row.step_infuse_amount * SpecificHeatWater); - } else { - temp = 99; - } - tuntemp += (temp - tuntemp) / 2; - row.step_infuse_temp = Round(temp, 6); - } - //console.log('init infuse temp: ' + row.step_infuse_temp); - } else { - // Calculate amount of infusion water. - row.step_infuse_amount = infusionVol(infused, mashkg, row.step_infuse_temp, row.step_temp, lasttemp); - //console.log('vol: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); - } - infused += parseFloat(row.step_infuse_amount); - } else if (row.step_type == 1) { // Temperature - if (i > 0) - row.step_infuse_amount = 0; - row.step_infuse_temp = 0; - } else if (row.step_type == 2) { // Decoction - row.step_infuse_amount = decoctionVol(infused, row.step_temp, lasttemp); - row.step_infuse_temp = 99; - } - row.step_volume = infused; - //console.log(i + ' type: ' + row.step_type + ' volume: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); - lasttemp = row.step_temp; - mashtime += row.step_time + row.ramp_time; - row.step_wg_ratio = Round(infused / mashkg, 6); - $('#mashGrid').jqxGrid('updaterow', i, row); - } - } - if ((dataRecord.w1_amount + dataRecord.w2_amount) == 0) { - dataRecord.w1_amount = infused; - $('#w1_amount').val(infused); - console.log("calcMash() fixed water 1 to " + infused); - } - mashvol = Round(mashkg * MaltVolume + infused, 6); - $('#est_mashvol').val(mashvol); - h = Math.floor(mashtime / 60); - m = Math.floor(mashtime - (h * 60)); - if (h < 10) - h = '0' + h; - if (m < 10) - m = '0' + m; - $('#est_mashtime').val(h + ':' + m); - // Estimated needed sparge water corrected for the temperature. - spoelw = Round((dataRecord.boil_size - infused + (mashkg * my_grain_absorbtion) + dataRecord.eq_lauter_deadspace) * 1.03, 6); - $('#brew_sparge_est').val(spoelw); - } - - function getNeededYeastCells() { - - var plato, volume, sg = dataRecord.brew_fermenter_sg; - if (sg <= 1.0001 && dataRecord.fg > 1.000) - sg = dataRecord.fg; - else if (sg <= 1.0001) - sg = dataRecord.est_og; - plato = sg_to_plato(sg); - - volume = dataRecord.brew_fermenter_volume; - if (volume <= 0) - volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; - - return dataRecord.yeast_pitchrate * volume * plato; - } - - function hopFlavourContribution(bt, vol, use, amount) { - var result; - - if (use == 4 || use == 5) // Whirlpool or Dry-hop - return 0; - if (use == 1) { // First wort - result = 0.15; // assume 15% flavourcontribution for fwh - } else if (bt > 50) { - result = 0.10; // assume 10% flavourcontribution as a minimum - } else { - result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) / 6, 2)); - if (result < 0.10) - result = 0.10; // assume 10% flavourcontribution as a minimum - } - return (result * amount * 1000) / vol; - } - - function hopAromaContribution(bt, vol, use, amount) { - var result = 0; - - if (use == 5) { // Dry hop - result = 1.33; - } else if (use == 4) { // Whirlpool - if (bt > 30) - bt = 30; // Max 30 minutes - result = 0.62 * bt / 30; - } else if (bt > 20) { - result = 0; - } else if (bt > 7.5) { - result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) / 4, 2)); - } else if (use == 2) { // Boil - result = 1; - } else if (use == 3) { // Aroma - result = 1.2; - } - return (result * amount * 1000) / vol; - } - - function calcIBUs() { - var total_ibus = 0, ferm_ibus = 0, rows = {}, i, row; - hop_aroma = hop_flavour = 0; - if (!(rows = $('#hopGrid').jqxGrid('getrows'))) { - return; - } - ok_hops = 1; - for (i = 0; i < rows.length; i++) { - row = rows[i]; - total_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, parseFloat(dataRecord.batch_size), - parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method, - dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); - ferm_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, - parseFloat(dataRecord.brew_fermenter_volume) + parseFloat(dataRecord.brew_fermenter_tcloss), - parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method, - dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); - hop_flavour += hopFlavourContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), row.h_useat, parseFloat(row.h_amount)); - hop_aroma += hopAromaContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), row.h_useat, parseFloat(row.h_amount)); - if ((((dataRecord.inventory_reduced <= 2) && (row.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool - ((dataRecord.inventory_reduced <= 6) && (row.h_useat == 5))) && // Dry-hop - (row.h_inventory < row.h_amount)) - ok_hops = 0; - } - total_ibus = Round(total_ibus, 1); - ferm_ibus = Round(ferm_ibus, 1); - hop_flavour = Round(hop_flavour * 100 / 5, 1); - hop_aroma = Round(hop_aroma * 100 / 6, 1); - if (hop_flavour > 100) - hop_flavour = 100; - if (hop_aroma > 100) - hop_aroma = 100; - console.log('calcIBUs(): ' + total_ibus + ' flavour: ' + hop_flavour + ' aroma: ' + hop_aroma + - ' fermenter:' + ferm_ibus + ' supplies:' + ok_hops); - dataRecord.est_ibu = total_ibus; - $('#est_ibu').val(total_ibus); - $('#est_ibu2').val(total_ibus); - $('#hop_flavour').jqxProgressBar('val', hop_flavour); - $('#hop_aroma').jqxProgressBar('val', hop_aroma); - $('#brew_fermenter_ibu').val(ferm_ibus); - calcStage(); - calcSupplies(); - }; - - /* - * http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ - * - * stype: 0=stirred, 1=shaken, 2=simple - * totcells: initial cells - * egrams: gram extract - */ - function getGrowthRate(stype, totcells, egrams) { - - /* Cells per grams extract (B/g) */ - var cpe = totcells / egrams; - - if (cpe > 3.5) - return 0; // no growth - if (stype == 2) - return 0.4; // simple starter - if (stype == 1) - return 0.62; // shaken starter - if (cpe <= 1.4) // stirred starter - return 1.4; - return 2.33 - (.67 * cpe); - }; - - function calcStep(svol, stype, start) { - - var gperpoint = 2.72715, //number of grams of extract per point of starter gravity per liter - prate = start / svol * 1000, - irate = Round(prate, 1), - egrams = (dataRecord.starter_sg - 1) * svol * gperpoint, - grate = getGrowthRate(stype, start, egrams), - ncells = Round(egrams * grate, 1), - totcells = parseFloat(ncells) + start; - - return { - svol: svol, - irate: irate, - prate: Round(prate, 1), - ncells: ncells, - totcells: totcells, - growf: Round(ncells / start, 2) - }; - } - - function killstep2() { - - dataRecord.prop2_volume = 0; - $('#prop2_volume').val(0); - $('#prop2_tcells').val(0); - $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').hide(); - $('#r2_pmpt').show(); - } - - function killstep3() { - - dataRecord.prop3_volume = 0; - $('#prop3_volume').val(0); - $('#prop3_tcells').val(0); - $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').hide(); - $('#r3_pmpt').show(); - } - - function killstep4() { - - dataRecord.prop4_volume = 0; - $('#prop4_volume').val(0); - $('#prop4_tcells').val(0); - $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').hide(); - $('#r4_pmpt').show(); - } - - /* - * Calculate all starter steps. - * stype: final starter type: 0 = stirred, 1 = shaked, 2 = simple. - * start: initial cells in billions - * needed: needed cells in billions - * - * result: all values updated. - */ - function calcSteps(stype, start, needed) { - - var uvols = [20, 40, 60, 80, 100, 150, 200, 250, 375, 500, 625, 750, 875, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000], - mvols = uvols.length, svol = 0, lasti = 0, result = {}, i; - - /* - * If no values are set, auto calculate the starter. - */ - if ((parseFloat($('#prop1_volume').jqxNumberInput('decimal')) + parseFloat($('#prop2_volume').jqxNumberInput('decimal')) + - parseFloat($('#prop3_volume').jqxNumberInput('decimal')) + parseFloat($('#prop4_volume').jqxNumberInput('decimal'))) == 0) { - // clear by default - for (i = 1; i < 5; i++) { - $('#prop' + i + '_type,#prop' + i + '_volume,#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells,#prop' + i + '_growf').hide(); - $('#r' + i + '_pmpt').show(); - $('#prop' + i + '_type').val(stype); - $('#prop' + i + '_volume').val(0); - } - if (start > needed) { - return; // no starter needed - } - $('#prop1_type,#prop1_volume,#prop1_irate,#prop1_ncells,#prop1_tcells,#prop1_growf').show(); - $('#r1_pmpt').hide(); - for (i = lasti; i <= mvols; i++) { - lasti = i; - svol = uvols[lasti]; - result = calcStep(svol, stype, start); - if (result.irate < 25) { - // inocculation rate too low, backup one step and break out. - lasti = i - 1; - svol = uvols[lasti]; - result = calcStep(svol, stype, start); - break; - } - if (result.totcells > needed || i == mvols) { // hit the target or loops done - break; - } - } - $('#prop1_volume').val(result.svol / 1000); // to liters - $('#prop1_irate').val(result.prate); - $('#prop1_ncells').val(result.ncells); - $('#prop1_tcells').val(result.totcells); - $('#prop1_growf').val(result.growf); - if (result.totcells > needed) - return; // hit the target - - // second stage - $('#r2_pmpt').hide(); - $('#prop2_type').val(stype); - $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').show(); - for (i = lasti; i <= mvols; i++) { - lasti = i; - svol = uvols[lasti]; - result = calcStep(svol, stype, $('#prop1_tcells').val()); - if (result.irate < 25) { - lasti = i - 1; - svol = uvols[lasti]; - result = calcStep(svol, stype, $('#prop1_tcells').val()); - break; - } - if (result.totcells > needed || i == mvols) { // hit the target or loops done - break; - } - } - $('#prop2_volume').val(result.svol / 1000); // to liters - $('#prop2_irate').val(result.prate); - $('#prop2_ncells').val(result.ncells); - $('#prop2_tcells').val(result.totcells); - $('#prop2_growf').val(result.growf); - if (result.totcells > needed) - return; // hit the target - - // third stage - $('#r3_pmpt').hide(); - $('#prop3_type').val(stype); - $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').show(); - for (i = lasti; i <= mvols; i++) { - lasti = i; - svol = uvols[lasti]; - result = calcStep(svol, stype, $('#prop2_tcells').val()); - if (result.irate < 25) { - lasti = i - 1; - svol = uvols[lasti]; - result = calcStep(svol, stype, $('#prop2_tcells').val()); - break; - } - if (result.totcells > needed || i == mvols) { // hit the target or loops done - break; - } - } - $('#prop3_volume').val(result.svol / 1000); // to liters - $('#prop3_irate').val(result.prate); - $('#prop3_ncells').val(result.ncells); - $('#prop3_tcells').val(result.totcells); - $('#prop3_growf').val(result.growf); - if (result.totcells > needed) - return; // hit the target - - // fourth stage - $('#r4_pmpt').hide(); - $('#prop4_type').val(stype); - $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').show(); - for (i = lasti; i <= mvols; i++) { - lasti = i; - svol = uvols[lasti]; - result = calcStep(svol, stype, $('#prop3_tcells').val()); - if (result.totcells > needed || i == mvols) { // hit the target or loops done - $('#prop4_volume').val(result.svol / 1000); // to liters - $('#prop4_irate').val(result.prate); - $('#prop4_ncells').val(result.ncells); - $('#prop4_tcells').val(result.totcells); - $('#prop4_growf').val(result.growf); - return; - } - } - } else { - // recalculate - if (dataRecord.prop1_volume > 0) { - $('#r1_pmpt').hide(); - $('#prop1_type,#prop1_volume,#prop1_irate,#prop1_ncells,#prop1_tcells,#prop1_growf').show(); - result = calcStep($('#prop1_volume').val() * 1000, dataRecord.prop1_type, start); - $('#prop1_irate').val(result.prate); - $('#prop1_ncells').val(result.ncells); - $('#prop1_tcells').val(result.totcells); - $('#prop1_growf').val(result.growf); - if (result.totcells > needed) { - killstep2(); - killstep3(); - killstep4(); - } else if (dataRecord.prop2_volume == 0) { - dataRecord.prop2_volume = dataRecord.prop1_volume; /* Extra step needed, start with the same size */ - dataRecord.prop2_type = dataRecord.prop1_type; - $('#prop2_volume').val(dataRecord.prop2_volume); - $('#prop2_type').val(dataRecord.prop2_type); - } - } - if (dataRecord.prop2_volume > 0) { - $('#r2_pmpt').hide(); - $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').show(); - result = calcStep($('#prop2_volume').val() * 1000, dataRecord.prop2_type, $('#prop1_tcells').val()); - $('#prop2_irate').val(result.prate); - $('#prop2_ncells').val(result.ncells); - $('#prop2_tcells').val(result.totcells); - $('#prop2_growf').val(result.growf); - if (result.totcells > needed) { - killstep3(); - killstep4(); - } else if (dataRecord.prop3_volume == 0) { - dataRecord.prop3_volume = dataRecord.prop2_volume; /* Extra step needed, start with the same size */ - dataRecord.prop3_type = dataRecord.prop2_type; - $('#prop3_volume').val(dataRecord.prop3_volume); - $('#prop3_type').val(dataRecord.prop3_type); - } - } - if (dataRecord.prop3_volume > 0) { - $('#r3_pmpt').hide(); - $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').show(); - result = calcStep($('#prop3_volume').val() * 1000, dataRecord.prop3_type, $('#prop2_tcells').val()); - $('#prop3_irate').val(result.prate); - $('#prop3_ncells').val(result.ncells); - $('#prop3_tcells').val(result.totcells); - $('#prop3_growf').val(result.growf); - if (result.totcells > needed) { - killstep4(); - } else if (dataRecord.prop4_volume == 0) { - dataRecord.prop4_volume = dataRecord.prop3_volume; /* Extra step needed, start with the same size */ - dataRecord.prop4_type = dataRecord.prop3_type; - $('#prop4_volume').val(dataRecord.prop4_volume); - $('#prop4_type').val(dataRecord.prop4_type); - } - } - if (dataRecord.prop4_volume > 0) { - $('#r4_pmpt').hide(); - $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').show(); - result = calcStep($('#prop4_volume').val() * 1000, dataRecord.prop4_type, $('#prop3_tcells').val()); - $('#prop4_irate').val(result.prate); - $('#prop4_ncells').val(result.ncells); - $('#prop4_tcells').val(result.totcells); - $('#prop4_growf').val(result.growf); - } - } - } - - function calcYeast() { - - // Calculate needed cells. - var plato, volume, rows, rowscount, row, i, needed, use_cells, sg = dataRecord.brew_fermenter_sg; - - if (sg <= 1.0001 && dataRecord.fg > 1.000) - sg = dataRecord.fg; - else if (sg <= 1.0001) - sg = dataRecord.est_og; - plato = sg_to_plato(sg); - - volume = dataRecord.brew_fermenter_volume; - if (volume > 0) { - if (dataRecord.brew_fermenter_extrawater > 0) - volume += dataRecord.brew_fermenter_extrawater; - } else { - volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; - } - - // Also in calcFermentables() - $('#yeast_cells').val(initcells); - - if (!(rows = $('#yeastGrid').jqxGrid('getrows'))) { - return; // grid not yet loaded. - } - rowscount = dataRecord.yeasts.length; - if (rowscount == 0) - return; // no yeast in recipe - - $('.primary_dry').hide(); - $('.primary_liquid').hide(); - - var maybe_starter = 0; - var pitchrate = 0.75; // Yeast pitch rate default - for (i = 0; i < rowscount; i++) { - row = dataRecord.yeasts[i]; - if (row.y_use == 0) { // primary - if (row.y_form == 1) { - // Dry yeast - $('.primary_dry').show(); - console.log('dry yeast: ' + row.y_gr_hl_lo + '@' + row.y_sg_lo + ' ' + row.y_gr_hl_hi + '@' + row.y_sg_hi); - // Build the formule with the yeast parameters. - // Based on https://www.lallemandbrewing.com/en/canada/brewers-corner/brewing-tools/pitching-rate-calculator/ - var og = row.y_sg_lo; - var f1 = row.y_gr_hl_lo / 100; - var f2 = Round(f1 / 5, 6); - // After a lot of try and error, study, the best thing to increase the pitch amount is actually - // use this simple formula by Lallemand. This is about the same as sugar weight increment in the wort. - var multiplier = (sg <= og) ? f1 : (f1 + f2 * (sg - og) / 0.008); - console.log('sg: ' + sg + ' og: ' + og + ' f1: ' + f1 + ' f2: ' + f2 + ' multiplier: ' + multiplier); - // dataRecord.starter_viability - var yeast_grams = Round(volume * multiplier * (100 / dataRecord.starter_viability), 2); - $('#yeast_grams').val(yeast_grams); - var yeast_gr_hl = Round(yeast_grams / (volume * 0.01), 2); - $('#yeast_gr_hl').val(yeast_gr_hl); - //console.log('need ' + yeast_grams + ' grams, gr/hl: ' + yeast_gr_hl); - - } else { - // Liquid yeast - $('.primary_liquid').show(); - // pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/ - // and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ - if (row.y_type == 0) { // lager yeast - pitchrate = 1.5; - if (dataRecord.est_og > 1.060) - pitchrate = 2.0; - } else if (row.y_type == 6) { // Kveik - pitchrate = 0.075; - } else { - pitchrate = 0.75; - if (dataRecord.est_og > 1.060) - pitchrate = 1.0; - } - if (dataRecord.yeast_pitchrate < 0.01) { - dataRecord.yeast_pitchrate = pitchrate; - $('#yeast_pitchrate').val(pitchrate); - } - maybe_starter = 1; - } - } - } - - needed = Round(dataRecord.yeast_pitchrate * volume * plato, 1); - $('#need_cells').val(needed); - use_cells = initcells; - if (needed <= initcells) - maybe_starter = 0; - //console.log('calcYeast() pitchrate:' + dataRecord.yeast_pitchrate + ' start:' + initcells + ' needed:' + needed + ' volume:' + volume + ' maybe_starter:' + maybe_starter); - - if (maybe_starter != dataRecord.starter_enable) { - dataRecord.starter_enable = maybe_starter; - } - if (maybe_starter) - $('#propagator').show(); - else - $('#propagator').hide(); - - if (dataRecord.starter_enable) { - - calcSteps(dataRecord.starter_type, initcells, needed); - - for (i = 1; i < 5; i++) { - $('#r' + i + '_irate').html(''); - $('#r' + i + '_growf').html(''); - $('#r' + i + '_tcells').html(''); - if (parseFloat($('#prop' + i + '_volume').val()) > 0) { - if ((parseFloat($('#prop' + i + '_irate').val()) < 25) || (parseFloat($('#prop' + i + '_irate').val()) > 100)) { - $('#r' + i + '_irate').html(""); - } else { - $('#r' + i + '_irate').html(""); - } - if (parseFloat($('#prop' + i + '_growf').val()) < 1) - $('#r' + i + '_growf').html(""); - if (($('#prop' + i + '_type').val() > 0) && (parseFloat($('#prop' + i + '_growf').val()) > 3)) - $('#r' + i + '_growf').html(""); - if (parseFloat($('#prop' + i + '_tcells').val()) > needed) - $('#r' + i + '_tcells').html(""); - use_cells = parseFloat($('#prop' + i + '_tcells').val()); - } else { - $('#r' + i + '_irate').html(''); - } - } - } - $('#plato_cells').val(parseFloat(use_cells / (volume * plato))); - }; - - function whirlpoolHops() { - var row, i, time, rowscount = dataRecord.hops.length; - if (rowscount == 0) - return; - for (i = 0; i < rowscount; i++) { - row = dataRecord.hops[i]; - if (row.h_useat == 4) { - time = parseFloat(dataRecord.brew_whirlpool9) + parseFloat(dataRecord.brew_whirlpool7) + parseFloat(dataRecord.brew_whirlpool6); - dataRecord.hops[i].h_time = time; - $('#hopGrid').jqxGrid('setcellvalue', i, 'h_time', time); - } - } - }; - - function calcMiscs() { - - ok_miscs = 1; - var row, i, rowscount = dataRecord.miscs.length; - if (rowscount == 0) - return; - for (i = 0; i < rowscount; i++) { - row = dataRecord.miscs[i]; - if ((((dataRecord.inventory_reduced <= 2) && (row.m_use_use <= 2)) || // Starter, Mash, Boil - ((dataRecord.inventory_reduced <= 2) && (row.m_use_use == 6)) || // Sparge - ((dataRecord.inventory_reduced <= 3) && (row.m_use_use == 3)) || // Primary - ((dataRecord.inventory_reduced <= 5) && (row.m_use_use == 4)) || // Secondary, Teriary - ((dataRecord.inventory_reduced <= 6) && (row.m_use_use == 5))) && // Bottle - (row.m_inventory < row.m_amount)) { - ok_miscs = 0; - } - } - calcSupplies(); - }; - - function GetBUGU() { - var gu = (dataRecord.est_og - 1) * 1000; - if (gu > 0) - return dataRecord.est_ibu / gu; - else - return 0.5; - } - - function GetOptSO4Clratio() { - var BUGU = GetBUGU(); - return (1.0 / (-1.2 * BUGU + 1.4)); - } - - function setWaterAgent(name, amount, use) { - var row, i, id, found = false, miscs, rows = $('#miscGrid').jqxGrid('getrows'); - if (amount == 0) { - for (i = 0; i < rows.length; i++) { - row = rows[i]; - if (row.m_name == name && row.m_use_use == use) { - id = $('#miscGrid').jqxGrid('getrowid', i); - $('#miscGrid').jqxGrid('deleterow', id); - } - } - } else { - for (i = 0; i < rows.length; i++) { - row = rows[i]; - if (row.m_name == name && row.m_use_use == use) { - found = true; - $('#miscGrid').jqxGrid('setcellvalue', i, 'm_amount', amount / 1000); - break; - } - } - if (! found) { - miscs = new $.jqx.dataAdapter(miscInvSource, { - loadComplete: function() { - var record, i, row = {}, records = miscs.records; - for (i = 0; i < records.length; i++) { - record = records[i]; - if (record.name == name) { - row['m_name'] = record.name; - row['m_amount'] = amount / 1000; - row['m_cost'] = record.cost; - row['m_type'] = record.type; - row['m_use_use'] = use; - row['m_time'] = 0; - row['m_amount_is_weight'] = record.amount_is_weight; - row['m_inventory'] = record.inventory; - row['m_avail'] = 1; - $('#miscGrid').jqxGrid('addrow', null, row); - } - } - } - }); - miscs.dataBind(); - return; - } - } - } - - function setRangeIndicator(ion, rangeCode) { - if ((rangeCode == 'laag') || (rangeCode == 'hoog')) - $('#wr_' + ion).html("" + rangeCode + ''); - else - $('#wr_' + ion).html(""); - } - - function mix(v1, v2, c1, c2) { - if ((v1 + v2) > 0) { - return ((v1 * c1) + (v2 * c2)) / (v1 + v2); - } - return 0; - } - - function PartCO3(pH) { - var H = Math.pow(10, -pH); - return 100 * Ka1 * Ka2 / (H * H + H * Ka1 + Ka1 * Ka2); - } - - function PartHCO3(pH) { - var H = Math.pow(10, -pH); - return 100 * Ka1 * H / (H * H + H * Ka1 + Ka1 * Ka2); - } - - function Charge(pH) { - return (-2 * PartCO3(pH) - PartHCO3(pH)); - } - - //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) - function ZAlkalinity(pHZ) { - var C43 = Charge(4.3), - Cw = Charge(parseFloat($('#wg_ph').jqxNumberInput('decimal'))), - Cz = Charge(pHZ), - DeltaCNaught = -C43 + Cw, - CT = parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) / 50 / DeltaCNaught, - DeltaCZ = -Cz + Cw; - return CT * DeltaCZ; - } - - //Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH) - function ZRA(pHZ) { - - var Magn, Z, Calc = parseFloat($('#wg_calcium').jqxNumberInput('decimal')) / (MMCa / 2); - Magn = parseFloat($('#wg_magnesium').jqxNumberInput('decimal')) / (MMMg / 2); - Z = ZAlkalinity(pHZ); - return Z - (Calc / 3.5 + Magn / 7); - } - - function BufferCapacity(di_ph, acid_to_ph_57, ebc, graintype) { - C1 = 0; - if ((di_ph != 5.7) && ((acid_to_ph_57 < - 0.1) || (acid_to_ph_57 > 0.1))) { - C1 = acid_to_ph_57 / (di_ph - 5.7); - } else { - // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid. - switch (graintype) { - case 0: // Base, Special, Kilned - case 3: - case 5: C1 = 0.014 * ebc - 34.192; - break; - case 2: C1 = -0.0597 * ebc - 32.457; // Crystal - break; - case 1: C1 = 0.0107 * ebc - 54.768; // Roast - break; - case 4: C1 = -149; // Sour malt - break; - } - } - return C1; - } - - function ProtonDeficit(pHZ) { - - var i, C1, x, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal')); - // proton deficit for the grist - if (( $('#fermentableGrid').jqxGrid('getrows'))) { - for (i = 0; i < dataRecord.fermentables.length; i++) { - row = dataRecord.fermentables[i]; - if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt - C1 = BufferCapacity(row.f_di_ph, row.f_acid_to_ph_57, row.f_color, row.f_graintype); - x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH) - Result += x * row.f_amount; - } - } - } else { - error_count++; - if (error_count < 5) - console.log('ProtonDeficit(' + pHZ + ') invalid grist, return ' + Result); - } - return Result; - } - - function MashpH() { - - var n = 0, pH = 5.4, deltapH = 0.001, deltapd = 0.1, pd = ProtonDeficit(pH); - while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) { - n++; - if (pd < -deltapd) - pH -= deltapH; - else if (pd > deltapd) - pH += deltapH; - pd = ProtonDeficit(pH); - } - pH = Round(pH, 6); - //console.log('MashpH() n: ' + n + ' pH: ' + pH); - return pH; - } - - function calcWater() { - - /* Can be called during loading and building the screens */ - if (! data_loaded) { - console.log('calcWater() failsave'); - return; - } - - var liters = 0, - calcium = 0, - magnesium = 0, - sodium = 0, - total_alkalinity = 0, - chloride = 0, - sulfate = 0, - ph = 0, - RA = 0, - frac = 0, - TpH = 0, - protonDeficit = 0, - AT, /*BT,*/ - r1d, r2d, f1d, f2d, f3d, - deltapH, deltapd, pd, n, - Res; - - if (dataRecord.w1_name == '') { - return; - } - - $('#w1_hardness').val(Hardness(dataRecord.w1_calcium, dataRecord.w1_magnesium)); - $('#w1_ra').val(ResidualAlkalinity(dataRecord.w1_total_alkalinity, dataRecord.w1_calcium, dataRecord.w1_magnesium)); - - // If there is a dillute water source, mix the waters. - if ((dataRecord.w2_name != '') && (dataRecord.w2_name != 'Geen mengwater')) { - liters = dataRecord.w1_amount + dataRecord.w2_amount; - calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium); - magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium); - sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium); - chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride); - sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate); - total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity); - ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters); - $('#w2_hardness').val(Hardness(dataRecord.w2_calcium, dataRecord.w2_magnesium)); - $('#w2_ra').val(ResidualAlkalinity(dataRecord.w2_total_alkalinity, dataRecord.w2_calcium, dataRecord.w2_magnesium)); - } else { - liters = dataRecord.w1_amount; - calcium = dataRecord.w1_calcium; - magnesium = dataRecord.w1_magnesium; - sodium = dataRecord.w1_sodium; - chloride = dataRecord.w1_chloride; - sulfate = dataRecord.w1_sulfate; - total_alkalinity = dataRecord.w1_total_alkalinity; - ph = dataRecord.w1_ph; - } - var bicarbonate = Bicarbonate(total_alkalinity, ph); - - /* Save mixed water ions for later */ - var wg_calcium = calcium; - var wg_sodium = sodium; - var wg_total_alkalinity = total_alkalinity; - var wg_chloride = chloride; - var wg_sulfate = sulfate; - var wg_bicarbonate = bicarbonate; - - dataRecord.wg_amount = liters; - dataRecord.wg_ph = ph; - - $('#wg_amount').val(liters); - $('#wg_calcium').val(Round(calcium, 1)); - $('#wg_magnesium').val(Round(magnesium, 1)); - $('#wg_sodium').val(Round(sodium, 1)); - $('#wg_bicarbonate').val(Round(bicarbonate, 1)); - $('#wg_total_alkalinity').val(Round(total_alkalinity, 1)); - $('#wg_chloride').val(Round(chloride, 1)); - $('#wg_sulfate').val(Round(sulfate, 1)); - $('#wg_ph').val(Round(ph, 2)); - $('#wg_hardness').val(Round(Hardness(calcium, magnesium), 1)); - $('#wg_ra').val(Round(ResidualAlkalinity(total_alkalinity, calcium, magnesium), 1)); - - var mash_ph = Round(MashpH(), 3); - console.log('Distilled water mash pH: ' + mash_ph); - - /* Calculate Salt additions */ - if (liters > 0) { - calcium += (parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + - parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000 + - parseFloat($('#wa_caco3').jqxNumberInput('decimal')) * MMCa / MMCaCO3 * 1000) / liters; - magnesium += (parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + - parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / liters; - sodium += (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 + - parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters; - sulfate += (parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + - parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / liters; - chloride += (2 * parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + - parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + - parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / liters; - bicarbonate += (parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3 * 1000 + - parseFloat($('#wa_caco3').jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3 * 1000) / liters; - } - - if (dataRecord.wa_acid_name < 0 || dataRecord,wa_acid_name >= AcidTypeData.length) { - $('#wa_acid_name').val(0); - dataRecord.wa_acid_name = 0; - dataRecord.wa_acid_perc = AcidTypeData[0].AcidPrc; - $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); - } - if (last_acid == '') - last_acid = AcidTypeData[dataRecord.wa_acid_name].nl; - - if (parseFloat(dataRecord.wa_acid_perc) == 0) { - dataRecord.wa_acid_perc = AcidTypeData[AT].AcidPrc; - $('#wa_acid_perc').val(AcidTypeData[AT].AcidPrc); - } - - AT = dataRecord.wa_acid_name; - - /* Note that the next calculations do not correct the pH change by the added salts. - This pH change is at most 0.1 pH and is a minor difference in Acid amount. */ - - if (dataRecord.calc_acid) { - /* Auto calculate pH */ - $('.c_mashph').show(); - TpH = parseFloat(dataRecord.mash_ph); - protonDeficit = ProtonDeficit(TpH); - //console.log('calc_acid tgt: ' + TpH + ' protonDeficit: ' + protonDeficit); - if (protonDeficit > 0) { // Add acid - frac = CalcFrac(TpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); - Acid = protonDeficit / frac; - Acid *= AcidTypeData[AT].MolWt; // mg - Acidmg = Acid; - var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (parseFloat(dataRecord.wa_acid_perc) / 100)) + 1000, 2); - Acid /= RealSG; - Acid /= AcidTypeData[AT].AcidPrc / 100; - Acid = Round(Acid, 2); - console.log('Mash auto Acid final ml: ' + Acid); - $('#wa_acid').val(Acid); - setWaterAgent(AcidTypeData[AT].nl, Acid, 1); - - bicarbonate = bicarbonate - protonDeficit * frac / liters; - total_alkalinity = bicarbonate * 50 / 61; - } - ph = TpH; - dataRecord.wb_ph = ph; - $('#wb_ph').val(Round(ph, 2)); - $('#est_mash_ph').val(Round(ph, 2)); - } else { - /* Manual calculate pH */ - $('.c_mashph').hide(); - console.log('calc_acid no'); - pHa = Round(ph, 3); // Adjusted water pH - // Then calculate the new pH with added acids and malts - console.log('Mash pH: ' + pHa); - Acid = AcidTypeData[AT].AcidSG * (parseFloat(dataRecord.wa_acid_perc) / 100); // ml - Acid *= parseFloat($('#wa_acid').jqxNumberInput('decimal')); - Acid /= AcidTypeData[AT].MolWt; // mg - Acidmg = Acid; - - //find the pH where the protondeficit = protondeficit by the acid - frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); - protonDeficit = Round(Acid * frac, 3); - //console.log('protonDeficit Acid: ' + protonDeficit + ' frac: ' + frac + ' pH: ' + pHa); - - deltapH = 0.001; - deltapd = 0.1; - pd = Round(ProtonDeficit(pHa), 6); - n = 0; - while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 4000)) { - n++; - if (pd < (protonDeficit - deltapd)) - pHa -= deltapH; - else if (pd > (protonDeficit + deltapd)) - pHa += deltapH; - frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); - protonDeficit = Acid * frac; - pd = ProtonDeficit(pHa); - } - //console.log('n: ' + n + ' pd: ' + pd + ' protonDeficit: ' + protonDeficit + ' frac: ' + frac + ' pHa: ' + pHa); - bicarbonate = wg_bicarbonate - protonDeficit * frac / liters; - total_alkalinity = bicarbonate * 50 / 61; - ph = pHa; - $('#wb_ph').val(Round(ph, 2)); - $('#est_mash_ph').val(Round(ph, 2)); - } - - if ((AT == 3) && (liters > 0)) { // Sulfuric / Zwavelzuur - RA = parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + - parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 + - Acidmg / 1000 * MMSO4 / (MMSO4 + 2); - RA = 1000 * RA / liters; - sulfate = wg_sulfate + RA; // Not add to sulfate?? - } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur - RA = parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 + - parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl + - Acidmg / 1000 * MMCl / (MMCl + 1); - RA = 1000 * RA / liters; - chloride = wg_chloride + RA; - } - - var BUGU = GetBUGU(); - $('#tgt_bu').val(Round(BUGU, 2)); - // From brouwhulp. - if (BUGU < 0.32) - $('#wr_bu').html("Zeer moutig en zoet"); - else if (BUGU < 0.43) - $('#wr_bu').html("Moutig, zoet"); - else if (BUGU < 0.52) - $('#wr_bu').html("Evenwichtig"); - else if (BUGU < 0.63) - $('#wr_bu').html("Licht hoppig, bitter"); - else - $('#wr_bu').html("Extra hoppig, zeer bitter"); - - // Sulfate to Chloride ratio (Palmer). - var OptSO4Clratio = GetOptSO4Clratio(); - $('#tgt_so4_cl').val(Round(OptSO4Clratio, 1)); - if (OptSO4Clratio < 0.4) - $('#wrt_so4_cl').html("Te moutig"); - else if (OptSO4Clratio < 0.6) - $('#wrt_so4_cl').html("Zeer moutig"); - else if (OptSO4Clratio < 0.8) - $('#wrt_so4_cl').html("Moutig"); - else if (OptSO4Clratio < 1.5) - $('#wrt_so4_cl').html("Gebalanceerd"); - else if (OptSO4Clratio < 2.0) - $('#wrt_so4_cl').html("Licht bitter"); - else if (OptSO4Clratio < 4.0) - $('#wrt_so4_cl').html("Bitter"); - else if (OptSO4Clratio < 9.0) - $('#wrt_so4_cl').html("Zeer bitter"); - else - $('#wrt_so4_cl').html("Te bitter"); - if (chloride > 0) - RA = sulfate / chloride; - else - RA = 10; - $('#got_so4_cl').val(Round(RA, 1)); - Res = 'normaal'; - if (RA < (0.8 * OptSO4Clratio)) - Res = 'laag'; - else if (RA > (1.2 * OptSO4Clratio)) - Res = 'hoog'; - setRangeIndicator('so4_cl', Res); - - $('#wb_calcium').val(Round(calcium, 1)); - $('#wb_magnesium').val(Round(magnesium, 1)); - $('#wb_sodium').val(Round(sodium, 1)); - $('#wb_sulfate').val(Round(sulfate, 1)); - $('#wb_chloride').val(Round(chloride, 1)); - $('#wb_bicarbonate').val(Round(bicarbonate, 1)); - $('#wb_total_alkalinity').val(Round(total_alkalinity, 1)); - $('#wb_hardness').val(Hardness(calcium, magnesium)); - $('#wb_ra').val(ResidualAlkalinity(total_alkalinity, calcium, magnesium)); - - if (calcium < 40) { - setRangeIndicator('calcium', 'laag'); - } else if (calcium > 150) { - setRangeIndicator('calcium', 'hoog'); - } else { - setRangeIndicator('calcium', 'normaal'); - } - if (magnesium < 5) { - setRangeIndicator('magnesium', 'laag'); - } else if (magnesium > 40) { - setRangeIndicator('magnesium', 'hoog'); - } else { - setRangeIndicator('magnesium', 'normaal'); - } - if (sodium <= 150) { - setRangeIndicator('sodium', 'normaal'); - } else { - setRangeIndicator('sodium', 'hoog'); - } - // Both chloride and sulfate should be above 50 according to - // John Palmer. So the Cl/SO4 ratio calculation will work. - if (chloride <= 50) { - setRangeIndicator('chloride', 'laag'); - } else if (chloride <= 150) { - setRangeIndicator('chloride', 'normaal'); - } else { - setRangeIndicator('chloride', 'hoog'); - } - if (sulfate <= 50) { - setRangeIndicator('sulfate', 'laag'); - } else if (sulfate <= 400) { - setRangeIndicator('sulfate', 'normaal'); - } else { - setRangeIndicator('sulfate', 'hoog'); - } - // (cloride + sulfate) > 500 is too high - if ((chloride + sulfate) > 500) { - setRangeIndicator('chloride', 'hoog'); - setRangeIndicator('sulfate', 'hoog'); - } - if (ph < 5.2) { - setRangeIndicator('ph', 'laag'); - } else if (ph > 5.6) { - setRangeIndicator('ph', 'hoog'); - } else { - setRangeIndicator('ph', 'normaal'); - } - if (bicarbonate > 250) { - setRangeIndicator('bicarbonate', 'hoog'); - } else { - setRangeIndicator('bicarbonate', 'normaal'); - } - calcSparge(); - calcMiscs(); - calcSupplies(); - } - - function calcSparge() { - - /* Based on the work of ajDeLange. */ - var ws_calcium, ws_magnesium, ws_total_alkalinity, ws_sodium, ws_chloride; - var ws_sulfate, ws_ph, ws_hardness, ws_ra; - var TargetpH = dataRecord.sparge_ph; - var Source_pH = 7.0; - - // Select watersource or fallback to the first source. - if ((dataRecord.sparge_source == 1) && (dataRecord.w2_ph > 0.0)) { // Source 2 - ws_calcium = dataRecord.w2_calcium; - ws_magnesium = dataRecord.w2_magnesium; - ws_total_alkalinity = dataRecord.w2_total_alkalinity; - ws_sodium = dataRecord.w2_sodium; - ws_chloride = dataRecord.w2_chloride; - ws_sulfate = dataRecord.w2_sulfate; - Source_pH = dataRecord.w2_ph; - $('#w2_button').jqxRadioButton({ checked: true }); - } else if ((dataRecord.sparge_source == 2) && (dataRecord.w2_ph > 0.0)) { // Mixed - ws_calcium = dataRecord.wg_calcium; - ws_magnesium = dataRecord.wg_magnesium; - ws_total_alkalinity = dataRecord.wg_total_alkalinity; - ws_sodium = dataRecord.wg_sodium; - ws_chloride = dataRecord.wg_chloride; - ws_sulfate = dataRecord.wg_sulfate; - Source_pH = dataRecord.wg_ph; - $('#wg_button').jqxRadioButton({ checked: true }); - } else { - ws_calcium = dataRecord.w1_calcium; - ws_magnesium = dataRecord.w1_magnesium; - ws_total_alkalinity = dataRecord.w1_total_alkalinity; - ws_sodium = dataRecord.w1_sodium; - ws_chloride = dataRecord.w1_chloride; - ws_sulfate = dataRecord.w1_sulfate; - Source_pH = dataRecord.w1_ph; - $('#w1_button').jqxRadioButton({ checked: true }); - } - - if (dataRecord.sparge_volume > 0) { - ws_calcium += (parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + - parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000) / dataRecord.sparge_volume; - ws_magnesium += (parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + - parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / dataRecord.sparge_volume; - ws_sodium += (parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000) / dataRecord.sparge_volume; - ws_sulfate += (parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + - parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / dataRecord.sparge_volume; - ws_chloride += (2 * parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + - parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + - parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / dataRecord.sparge_volume; - } - - /* Show the spargewate with salt additions */ - $('#sw_calcium').val(Round(ws_calcium, 1)); - $('#sw_magnesium').val(Round(ws_magnesium, 1)); - $('#sw_sodium').val(Round(ws_sodium, 1)); - $('#sw_sulfate').val(Round(ws_sulfate, 1)); - $('#sw_chloride').val(Round(ws_chloride, 1)); - $('#sw_bicarbonate').val(Round(Bicarbonate(ws_total_alkalinity, Source_pH), 1)); - $('#sw_total_alkalinity').val(Round(ws_total_alkalinity, 1)); - $('#sw_ph').val(dataRecord.sparge_ph); - $('#sw_hardness').val(Hardness(ws_calcium, ws_magnesium)); - $('#sw_ra').val(ResidualAlkalinity(ws_total_alkalinity, ws_calcium, ws_magnesium)); - - AT = dataRecord.sparge_acid_type; - if (AT < 0 || AT >= AcidTypeData.length) { - AT = 0; - dataRecord.sparge_acid_type = 0; - $('#sparge_acid_type').val(AcidTypeData[0].nl); - dataRecord.sparge_acid_perc = AcidTypeData[0].AcidPrc; - $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); - } - - /* - * Auto calculate the required acid - */ - if (dataRecord.calc_acid) { - // Step 1: Compute the mole fractions of carbonic (f1) and carbonate(f3) at the source water pH - var r1 = Math.pow(10, Source_pH - 6.35); - var r2 = Math.pow(10, Source_pH - 10.33); - var d = 1 + r1 + r1 * r2; - var f1 = 1 / d; - var f3 = r1 * r2 / d; - - //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) - var r143 = Math.pow(10, 4.3 - 6.35); - var r243 = Math.pow(10, 4.3 - 10.33); - var d43 = 1 + r143 + r143 * r243; - var f143 = 1 / d43; - var f343 = r143 * r243 / d43; - - //Step 4. Solve - var Ct = ws_total_alkalinity / 50 / ((f143 - f1) + (f3 - f343)); - - //Step 5. Compute mole fractions at desired pH - var r1g = Math.pow(10, TargetpH - 6.35); - var r2g = Math.pow(10, TargetpH - 10.33); - var dg = 1 + r1g + r1g * r2g; - var f1g = 1 / dg; - var f3g = r1g * r2g / dg; - - //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L) - var Acid = Ct * ((f1g - f1) + (f3 - f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l - Acid += 0.01; // Add acid that would be required for distilled water. - - //Step 8. Get the acid data. - var fract = CalcFrac(TargetpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); - - //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. - Acid /= fract; - - //Step 10. Multiply by molecular weight of the acid - Acid *= AcidTypeData[AT].MolWt; //mg - - //Step 11. Divide by Specific Gravity and Percentage to get the final ml. - var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (dataRecord.sparge_acid_perc / 100)) + 1000, 2); - Acid = Acid / RealSG; //ml - Acid *= dataRecord.sparge_volume; //ml acid total at 100% - Acid /= AcidTypeData[AT].AcidPrc / 100; //ml acid at supplied strength - Acid = Round(Acid, 2); - dataRecord.sparge_acid_amount = Acid / 1000; - $('#sparge_acid_amount').val(Acid); - } - - // Finally calculate the estimate preboil pH - var ph = -Math.log10(((Math.pow(10, -dataRecord.wb_ph) * dataRecord.wg_amount) + (Math.pow(10, -dataRecord.sparge_ph) * dataRecord.sparge_volume)) / - (dataRecord.wg_amount + dataRecord.sparge_volume)); - $('#preboil_ph').val(ph); - } - - function calcFermentation() { - var primary_svg, secondary_svg, final_svg, ABV; - if (dataRecord.brew_fermenter_sg < 1.020) - return; - if ((dataRecord.primary_end_sg > 0.990) && (dataRecord.primary_end_sg < dataRecord.brew_fermenter_sg)) { - primary_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.primary_end_sg), 1); - $('#primary_svg').val(primary_svg); - if ((dataRecord.secondary_end_sg > 0.990) && (dataRecord.secondary_end_sg < dataRecord.brew_fermenter_sg)) { - secondary_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.secondary_end_sg), 1); - $('#secondary_svg').val(secondary_svg); - if ((dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { - final_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.fg), 1); - $('#final_svg').val(final_svg); - ABV = Round(abvol(dataRecord.brew_fermenter_sg, dataRecord.fg), 2); - $('#final_abv').val(ABV); - } - } - } - } - - function ResCO2(T) { - var F = T * 1.8 + 32; - return Round(3.0378 - 0.050062 * F + 0.00026555 * F * F, 6); - } - - function CarbCO2toS(CO2, T, SFactor) { - //var sugar = SFactor * (CO2 - ResCO2(CO2, T)) / 0.286; - var sugar = Round(SFactor * (CO2 - ResCO2(T)) * 4.014094, 6); - if (sugar < 0) - sugar = 0; - return Round(sugar, 3); - } - - function GetPressure(CO2, T1, T2) { - var P, V = CO2 - ResCO2(T1); - V = CO2; // TODO: temp only total pressure, testing - if (V < 0) - return 0; - P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V + - 0.674996600795854 * V + -0.00471757220150754 * V * V; - if (P < 0) - P = 0; - P = Round(P * 1.01325, 2); // atm to bar - console.log("GetPressure(" + CO2 + ", " + T1 + ", " + T2 + ") V:" + V + " Bar: " + P + " ignored ResCO2: " + ResCO2(T1)); - return P; - } - - function CarbCO2ToPressure(CO2, T) { - return (CO2 - (-0.000005594056 * Math.pow(T, 4) + 0.000144357886 * Math.pow(T, 3) + - 0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049)) / - (0.00000498031 * Math.pow(T, 4) - 0.00024358267 * Math.pow(T, 3) + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376); - } - - function calcCarbonation() { - - var TSec, ABV, bvol, balc, babv, mvol, malc, tvol, talc, i, row, SFactor, pvol, pabv, Pressure, kabv; - - console.log('calcCarbonation()'); - - TSec = dataRecord.secondary_temp; - if (TSec < 1) - TSec = dataRecord.primary_end_temp; - if (TSec < 1) - TSec = 18; - - if (dataRecord.fg == 0.000) - ABV = abvol(dataRecord.brew_fermenter_sg, parseFloat($('#est_fg').jqxNumberInput('decimal'))); - else - ABV = abvol(dataRecord.brew_fermenter_sg, dataRecord.fg); - - /* Calculate new volume and alcohol. */ - bvol = dataRecord.package_volume - (ABV * dataRecord.package_volume) / 100; - balc = dataRecord.package_volume - bvol; - mvol = dataRecord.package_infuse_amount - (dataRecord.package_infuse_abv * dataRecord.package_infuse_amount) / 100; - malc = dataRecord.package_infuse_amount - mvol; - talc = balc + malc; - tvol = bvol + mvol; - ABV = Round(talc / (tvol + talc) * 100, 2); - dataRecord.package_abv = ABV; - $('#package_abv').val(ABV); - - //console.log("calcCarbonation() TSec:"+TSec+" ABV:"+ABV); - if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { - return; - } - - // Bottles - dataRecord.bottle_priming_amount = 0; - dataRecord.bottle_priming_total = 0; - for (i = 0; i < rows.length; i++) { - row = rows[i]; - if (row.f_added == 4) { - SFactor = 1 / ((row.f_yield / 100) * (1 - row.f_moisture / 100)); - dataRecord.bottle_priming_amount = CarbCO2toS(dataRecord.bottle_carbonation, TSec, SFactor); - dataRecord.bottle_priming_total = Round(dataRecord.bottle_amount * dataRecord.bottle_priming_amount, 2); - $('#fermentableGrid').jqxGrid('setcellvalue', i, 'f_amount', dataRecord.bottle_priming_total / 1000); - } - } - $('#bottle_priming_amount').val(Round(dataRecord.bottle_priming_amount, 1)); - $('#bottle_priming_total').val(dataRecord.bottle_priming_total); - pabv = ABV + dataRecord.bottle_priming_amount * 0.47 / 7.907; - pvol = dataRecord.bottle_amount - (pabv * dataRecord.bottle_amount) / 100; - talc = dataRecord.bottle_amount - pvol; - tvol = pvol + dataRecord.bottle_priming_water; - babv = Round(talc / (tvol + talc) * 100, 2); - //console.log("bottle pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.bottle_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+babv); - $('#bottle_abv').val(babv); - $('#bottle_pressure').val(GetPressure(dataRecord.bottle_carbonation, TSec, dataRecord.bottle_carbonation_temp)); - - // Kegs - Pressure = CarbCO2ToPressure(dataRecord.keg_carbonation, dataRecord.keg_carbonation_temp); - if (Pressure < 0) - Pressure = 0; - dataRecord.keg_pressure = Pressure; - $('#keg_pressure').val(Round(Pressure, 1)); - - dataRecord.keg_priming_amount = 0; - dataRecord.keg_priming_total = 0; - if (!dataRecord.keg_forced_carb) { - for (i = 0; i < rows.length; i++) { - row = rows[i]; - if (row.f_added == 5) { - SFactor = 1 / ((row.f_yield / 100) * (1 - row.f_moisture / 100)); - dataRecord.keg_priming_amount = CarbCO2toS(dataRecord.keg_carbonation, TSec, SFactor); - dataRecord.keg_priming_total = Round(dataRecord.keg_amount * dataRecord.keg_priming_amount, 2); - $('#fermentableGrid').jqxGrid('setcellvalue', i, 'f_amount', dataRecord.keg_priming_total / 1000); - } - } - $('#keg_priming_amount').val(Round(dataRecord.keg_priming_amount, 1)); - $('#keg_priming_total').val(dataRecord.keg_priming_total); - pabv = ABV + dataRecord.keg_priming_amount * 0.47 / 7.907; - pvol = dataRecord.keg_amount - (pabv * dataRecord.keg_amount) / 100; - talc = dataRecord.keg_amount - pvol; - tvol = pvol + dataRecord.keg_priming_water; - kabv = Round(talc / (tvol + talc) * 100, 2); - //console.log("kegs pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.keg_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+kabv); - $('#keg_abv').val(kabv); - } else { - $('#keg_priming_amount').val(0); - $('#keg_priming_total').val(0); - $('#keg_abv').val(ABV); - } - } - - function calcStage() { - /* - * Set stage and enable or disable parts of the screens. - */ - $('#stage').val(StageData[dataRecord.stage].nl); - - /* - * Enable or disable parts of the screens. - */ - $('#jqxTabs').jqxTabs((dataRecord.stage < 1) ? 'disableAt':'enableAt', 8); // Brewday tab - $('#jqxTabs').jqxTabs((dataRecord.stage > 2) ? 'enableAt':'disableAt', 9); // Fermentation tab - $('#jqxTabs').jqxTabs((dataRecord.stage < 9) ? 'disableAt':'enableAt', 11); // Tasting tab - } - - - // initialize the input fields. - // Tab 1, Algemeen - $('#name').jqxTooltip({ content: 'De naam voor dit product.' }); - $('#code').jqxTooltip({ content: 'Product code nummer.' }); - $('#birth').jqxTooltip({ content: 'De ontwerp datum van dit product.' }); - $('#stage').jqxTooltip({ content: 'De productie fase van dit product.' }); - $('#divide_batch').jqxTooltip({ content: 'Het aantal extra gesplitste batches.' }); - $('#divide_type').jqxTooltip({ content: 'Het splitsing moment in het productie proces.' }); - $('#notes').jqxTooltip({ content: 'De uitgebreide opmerkingen over dit product.' }); - $('#type').jqxTooltip({ content: 'Het brouw type van dit recept.' }); - $('#efficiency').jqxTooltip({ content: 'Het rendement van maischen en koken.' }); - $('#batch_size').jqxTooltip({ content: 'Het volume van het gekoelde wort na het koken.' }); - $('#boil_time').jqxTooltip({ content: 'De kooktijd in minuten.' }); - $('#boil_size').jqxTooltip({ content: 'Het volume van het wort voor het koken.' }); - $('#st_guide').jqxTooltip({ content: 'De bierstijl gids voor dit recept.'}); - $('#st_name').jqxTooltip({ content: 'De bierstijl naam voor dit recept.'}); - $('#st_letter').jqxTooltip({ content: 'De bierstijl letter voor dit recept.'}); - $('#st_letter').jqxInput({ theme: theme, width: 90, height: 23 }); - $('#st_type').jqxTooltip({ content: 'Het bierstijl type.'}); - $('#st_category').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie.'}); - $('#st_category_number').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie sub nummer.'}); - $('#est_og').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' }); - $('#st_og_min').jqxTooltip({ content: 'Het minimum begin SG voor deze bierstijl.'}); - $('#st_og_max').jqxTooltip({ content: 'Het maximum begin SG voor deze bierstijl.'}); - $('#est_fg').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); - $('#st_fg_min').jqxTooltip({ content: 'Het minimum eind SG voor deze bierstijl.'}); - $('#st_fg_max').jqxTooltip({ content: 'Het maximum eind SG voor deze bierstijl.'}); - $('#est_abv').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' }); - $('#st_abv_min').jqxTooltip({ content: 'Het minimum alcohol volume % voor deze bierstijl.'}); - $('#st_abv_max').jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'}); - $('#est_color').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); - $('#st_color_min').jqxTooltip({ content: 'De minimum kleur voor deze bierstijl.'}); - $('#st_color_max').jqxTooltip({ content: 'De maximum kleur voor deze bierstijl.'}); - $('#est_ibu').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); - $('#st_ibu_min').jqxTooltip({ content: 'De minimum bitterheid voor deze bierstijl.'}); - $('#st_ibu_max').jqxTooltip({ content: 'De maximum bitterheid voor deze bierstijl.'}); - $('#kcal').jqxTooltip({ content: 'Energie-inhoud in kcal/liter.' }); - $('#est_carb').jqxTooltip({ content: 'Koolzuur volume. Dit wordt automatisch berekend.' }); - $('#st_carb_min').jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'}); - $('#st_carb_max').jqxTooltip({ content: 'Het maximum koolzuur volume voor deze bierstijl.'}); - - $('#name').jqxInput({ theme: theme, width: 640, height: 23 }); - $('#code, #stage').jqxInput({ theme: theme, width: 100, height: 23 }); - $('#locked').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); - $('#birth,#divide_batch,#divide_type').jqxInput({ theme: theme, width: 120, height: 23 }); - $('#notes').jqxInput({ theme: theme, width: 960, height: 100 }); - $('#type').jqxInput({ theme: theme, width: 180, height: 23 }); - $('#efficiency').jqxNumberInput(Show1dec); - $('#batch_size').jqxNumberInput(Show1dec); - $('#boil_time').jqxNumberInput(Show0dec); - $('#boil_size').jqxNumberInput(Show2dec); - $('#st_guide,#st_name,#st_type,#st_category').jqxInput({ theme: theme, width: 250, height: 23 }); - $('#est_og').jqxNumberInput(Show3dec); - $('#est_fg').jqxNumberInput(Show3dec); - $('#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 }); - $('#est_ibu,#est_color').jqxNumberInput(Show0dec); - $('#color_method').jqxInput({ theme: theme, width: 180, height: 23 }); - $('#st_color_min,#st_color_max,#st_category_number,#st_ibu_min,#st_ibu_max,#kcal').jqxNumberInput(Smal0dec); - $('#ibu_method').jqxInput({ theme: theme, width: 180, height: 23 }); - $('#est_abv,#st_abv_min,#st_abv_max,#est_carb,#st_carb_min,#st_carb_max').jqxNumberInput(Smal1dec); - - // Tab 2, Equipment - $('#eq_name').jqxTooltip({ content: 'De naam van deze brouw apparatuur.' }); - $('#eq_boil_size').jqxTooltip({ content: 'Normaal kook volume in liters' }); - $('#eq_batch_size').jqxTooltip({ content: 'Berekende batch grootte in liters aan het eind van de kook.' }); - $('#eq_tun_volume').jqxTooltip({ content: 'Maisch ketel volume.' }); - $('#eq_top_up_water').jqxTooltip({ content: 'Extra water in het gistvat.' }); - $('#eq_trub_chiller_loss').jqxTooltip({ content: 'Standaard verlies bij het overbrengen naar het gistvat.' }); - $('#eq_evap_rate').jqxTooltip({ content: 'Verdamping in liters per uur.' }); - $('#eq_boil_time').jqxTooltip({ content: 'Normale kooktijd in minuten, 0 voor no-boil recepten.' }); - $('#eq_top_up_kettle').jqxTooltip({ content: 'Extra water toevoegen tijdens de kook.' }); - $('#eq_hop_utilization').jqxTooltip({ content: '100% voor kleine installaties, hoger voor grote brouwerijen.' }); - $('#eq_notes').jqxTooltip({ content: 'Opmerkingen over deze apparatuur.' }); - $('#eq_lauter_volume').jqxTooltip({ content: 'Filterkuip volume.' }); - $('#eq_lauter_deadspace').jqxTooltip({ content: 'Filterkuip verlies in liters.' }); - $('#eq_kettle_volume').jqxTooltip({ content: 'Kook ketel volume in liters.' }); - $('#eq_mash_volume').jqxTooltip({ content: 'Maisch water voor de eerste stap.' }); - $('#eq_mash_max').jqxTooltip({ content: 'De maximale moutstort in Kg.' }); - $('#eq_efficiency').jqxTooltip({ content: 'Gemiddeld brouwzaal rendement.' }); - - $('#eq_name').jqxInput({ theme: theme, width: 250, height: 23 }); - $('#eq_evap_rate').jqxNumberInput(Show2dec); - $('#eq_boil_time,#eq_hop_utilization').jqxNumberInput(Show0dec); - $('#eq_notes').jqxInput({ theme: theme, width: 960, height: 200 }); - $('#eq_boil_size,#eq_batch_size,#eq_tun_volume,#eq_top_up_water,#eq_trub_chiller_loss,#eq_top_up_kettle').jqxNumberInput(Show1dec); - $('#eq_lauter_volume,#eq_lauter_deadspace,#eq_kettle_volume,#eq_mash_volume,#eq_mash_max,#eq_efficiency').jqxNumberInput(Show1dec); - - // Tab 3, Fermentables - $('#est_color2').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); - $('#est_og2').jqxTooltip({ content: 'Het geschatte begin SG van dit product.' }); - $('#mash_kg').jqxTooltip({ content: 'Het gewicht van alle mouten in de maisch.' }); - - $('#est_color2').jqxNumberInput(Show0dec); - $('#est_og2,#mash_kg').jqxNumberInput(Show3dec); - - $('#perc_malts').jqxProgressBar({ - width: 300, height: 23, theme: theme, showText: true, max: 120, animationDuration: 0, - colorRanges: [{ stop: 90, color: '#008C00' },{ stop: 100, color: '#EB7331' },{ stop: 120, color: '#FF0000' }], - renderText: function(text) { return (Math.round(parseInt(text) * 1.2)) + '%'; } - }); - $('#perc_sugars').jqxProgressBar({ - width: 300, height: 23, theme: theme, showText: true, max: 50, animationDuration: 0, - colorRanges: [{ stop: 20, color: '#008C00' },{ stop: 50, color: '#FF0000' }], - renderText: function(text) { return (Math.round(parseInt(text) * 5) / 10) + '%'; } - }); - $('#perc_cara').jqxProgressBar({ - width: 300, height: 23, theme: theme, showText: true, max: 50, animationDuration: 0, - colorRanges: [{ stop: 25, color: '#008C00' },{ stop: 50, color: '#FF0000' }], - renderText: function(text) { return (Math.round(parseInt(text) * 5) / 10) + '%'; } - }); - $('#ferm_lintner').jqxProgressBar({ - width: 300, height: 23, theme: theme, showText: true, max: 200, animationDuration: 0, - colorRanges: [{ stop: 30, color: '#FF0000' },{ stop: 40, color: '#EB7331' },{ stop: 200, color: '#008C00' }], - renderText: function(text) { return (parseInt(text) * 2) + ' lintner'; } - }); - - // Tab 4, Hops - $('#est_ibu2').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); - $('#est_ibu2').jqxNumberInput(Smal0dec); - $('#hop_flavour').jqxProgressBar({ - width: 300, height: 23, theme: theme, showText: true, animationDuration: 0, - colorRanges: [ - { stop: 20, color: '#004D00' }, - { stop: 40, color: '#008C00' }, - { stop: 60, color: '#00BF00' }, - { stop: 80, color: '#00FF00' }, - { stop: 100, color: '#80FF80' } - ], - renderText: function(text) { - var val = parseInt(text); - if (val < 20) - return 'Weinig'; - else if (val < 40) - return 'Matig'; - else if (val < 60) - return 'Redelijk'; - else if (val < 80) - return 'Veel'; - else - return 'Zeer veel'; - } - }); - $('#hop_aroma').jqxProgressBar({ - width: 300, height: 23, theme: theme, showText: true, animationDuration: 0, - colorRanges: [ - { stop: 20, color: '#004D00' }, - { stop: 40, color: '#008C00' }, - { stop: 60, color: '#00BF00' }, - { stop: 80, color: '#00FF00' }, - { stop: 100, color: '#80FF80' } - ], - renderText: function(text) { - var val = parseInt(text); - if (val < 20) - return 'Weinig'; - else if (val < 40) - return 'Matig'; - else if (val < 60) - return 'Redelijk'; - else if (val < 80) - return 'Veel'; - else - return 'Zeer veel'; - } - }); - - // Tab 5, Miscs - - // Tab 6, Yeasts - $('#est_fg2').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); - $('#est_abv2').jqxTooltip({ content: 'Verwacht alcohol volume %. Dit wordt automatisch berekend.' }); - $('#yeast_grams').jqxTooltip({ content: 'De gewenste totale hoeveelheid droge gist voor dit bier.' }); - $('#yeast_gr_hl').jqxTooltip({ content: 'De werkelijke hoeveelheid gist per hectoliter.' }); - $('#yeast_cells').jqxTooltip({ content: 'Het aantal miljard beschikbare gistcellen zonder eventuele starter.' }); - $('#need_cells').jqxTooltip({ content: 'Het aantal miljard nodige cellen is afhankelijk van het begin SG, biertype en volume.' }); - $('#plato_cells').jqxTooltip({ content: 'De berekende pitchrate in miljard cellen per ml per graad Plato.' }); - $('#yeast_prod_date').jqxTooltip({ content: 'Bij korrelgisten is meestal "best voor" datum op het zakje gedrukt.
Gebruik die datum maar dan twee jaar eerder als productie datum.
Bij White Labs is de productie datum vier maanden voor de "Best by" datum die geprint op het buisje.
Bij Wyeast is dit de "manufacture date" die op het pak geprint is.
Voor schuine buis, slurry, opkweek en gedroogd is dit de datum dat je de gist geoogst hebt.' }); - $('#yeast_pitchrate').jqxTooltip({ content: 'De gewenste pitchrate in miljard cellen per ml per graad Plato voor de vergisting van dit bier.' }); - - $('#est_fg2,#plato_cells').jqxNumberInput(Show3dec); - $('#est_fg2').jqxNumberInput({ width: 70 }); - $('#est_abv2').jqxNumberInput(Show2dec); - $('#est_abv2').jqxNumberInput({ width: 70, symbol: '%', symbolPosition: 'right' }); - $('#yeast_grams').jqxNumberInput(Show1dec); - $('#yeast_gr_hl').jqxNumberInput(Show1dec); - $('#yeast_cells,#need_cells').jqxNumberInput(Show1dec); - $('#yeast_prod_date').jqxDateTimeInput(Dateopts); - $('#yeast_prod_date').jqxDateTimeInput({ disabled: true }); - $('#yeast_pitchrate').jqxNumberInput(Show3dec); - for (i = 1; i < 5; i++) { - $('#prop' + i + '_volume').jqxTooltip({ content: 'Het volume van deze starter stap.' }); - $('#prop' + i + '_irate').jqxTooltip({ content: 'Voor de beste gistgroei, houd de injectie factor tussen de 25 en 100 miljoen cellen per ml.' }); - $('#prop' + i + '_ncells').jqxTooltip({ content: 'Het aantal miljard nieuwe gistcellen in deze stap.' }); - $('#prop' + i + '_tcells').jqxTooltip({ content: 'Het totaal aantal miljard gistcellen na deze stap.' }); - $('#prop' + i + '_growf').jqxTooltip({ content: 'De groeifactor, minstens 1. Ongeroerde starters komen meestal niet boven de 3.' }); - - $('#prop' + i + '_type').jqxInput({ theme: theme, width: 120, height: 23 }); - $('#prop' + i + '_volume').jqxNumberInput(Show3dec); - $('#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells').jqxNumberInput(Show1dec); - $('#prop' + i + '_growf').jqxNumberInput(Show2dec); - $('#prop' + i + '_type,#prop' + i + '_volume,#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells,#prop' + i + '_growf').hide(); - } - $('#starter_type').jqxInput({ theme: theme, width: 120, height: 23 }); - $('#starter_sg').jqxTooltip({ content: 'Het ideale starter SG moet tussen de 1.030 en 1.040 zijn. Optimaal is 1.037.' }); - $('#starter_sg').jqxNumberInput(Show3dec); - $('#starter_viability').jqxTooltip({ content: 'De gist conditie.' }); - $('#starter_viability').jqxNumberInput(Show0dec); - - // Tab 7, Mashing - $('#mash_name').jqxTooltip({ content: 'De omschrijving van dit maisch profiel.' }); - $('#mash_name').jqxInput({ theme: theme, width: 320, height: 23 }); - $('#est_mashvol').jqxTooltip({ content: 'Het totale volume van het maishwater en de mout in de maish pan.' }); - $('#est_mashvol').jqxNumberInput(Show1dec); - $('#est_mashtime').jqxTooltip({ content: 'De totale tijdsduur van het maischen.' }); - $('#est_mashtime').jqxInput({ theme: theme, width: 70, height: 23 }); - - // Tab 8, Water - $('#tgt_bu').jqxNumberInput(Show2wat); - $('#tgt_so4_cl,#got_so4_cl').jqxNumberInput(Show1wat); - $('#preboil_ph').jqxNumberInput(Show2wat); - - // Water source 1 - $('#w1_name').jqxInput({ theme: theme, width: 200, height: 23 }); - $('#w1_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); - $('#w1_amount,#w1_calcium,#w1_magnesium,#w1_sodium,#w1_bicarbonate,#w1_total_alkalinity,#w1_chloride,#w1_sulfate').jqxNumberInput(Show1wat); - $('#w1_ph').jqxNumberInput(Show2wat); - $('#w1_hardness').jqxNumberInput(Show1wat); - $('#w1_ra').jqxNumberInput(Show1wat); - // Water source 2 - $('#w2_name').jqxInput({ theme: theme, width: 200, height: 23 }); - $('#w2_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); - $('#w2_amount').jqxNumberInput(Show1wat); - $('#w2_calcium,#w2_magnesium,#w2_sodium,#w2_bicarbonate,#w2_total_alkalinity,#w2_chloride,#w2_sulfate').jqxNumberInput(Show1wat); - $('#w2_ph').jqxNumberInput(Show2wat); - $('#w2_hardness').jqxNumberInput(Show1wat); - $('#w2_ra').jqxNumberInput(Show1wat); - // Water mixed - $('#wg_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); - $('#wg_amount,#wg_calcium,#wg_magnesium,#wg_sodium,#wg_bicarbonate,#wg_total_alkalinity,#wg_chloride,#wg_sulfate').jqxNumberInput(Show1wat); - $('#wg_ph').jqxNumberInput(Show2wat); - $('#wg_hardness').jqxNumberInput(Show1wat); - $('#wg_ra').jqxNumberInput(Show1wat); - // Water treated - $('#wb_calcium').jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'}); - $('#wb_calcium').jqxNumberInput(Show1wat); - $('#wb_magnesium').jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is tussen 5 en 40.'}); - $('#wb_magnesium').jqxNumberInput(Show1wat); - $('#wb_sodium').jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'}); - $('#wb_sodium').jqxNumberInput(Show1wat); - $('#wb_chloride').jqxTooltip({ content: 'De ideale hoeveelheid Chloride is tussen 50 en 150. Samen met Sulfaat minder dan 500.'}); - $('#wb_chloride').jqxNumberInput(Show1wat); - $('#wb_sulfate').jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 400. Samen met Chloride minder dan 500.'}); - $('#wb_sulfate').jqxNumberInput(Show1wat); - $('#wb_bicarbonate').jqxTooltip({ content: '0 tot 50 lichte bieren, 50 tot 150 amber bieren, 150 tot 250 donkere bieren.'}); - $('#wb_bicarbonate').jqxNumberInput(Show1wat); - $('#wb_ph').jqxNumberInput(Show2wat); - $('#wb_hardness').jqxNumberInput(Show1wat); - $('#wb_ra').jqxNumberInput(Show1wat); - // Sparge water - $('#sw_amount').jqxNumberInput(Show1wat); - $('#sw_calcium').jqxNumberInput(Show1wat); - $('#sw_magnesium').jqxNumberInput(Show1wat); - $('#sw_sodium').jqxNumberInput(Show1wat); - $('#sw_bicarbonate').jqxNumberInput(Show1wat); - $('#sw_total_alkalinity').jqxNumberInput(Show1wat); - $('#sw_chloride').jqxNumberInput(Show1wat); - $('#sw_sulfate').jqxNumberInput(Show1wat); - $('#sw_ph').jqxNumberInput(Show2wat); - $('#sw_hardness').jqxNumberInput(Show1wat); - $('#sw_ra').jqxNumberInput(Show1wat); - - // Water agents - $('#wa_cacl2').jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.' }); - $('#wa_cacl2').jqxNumberInput(Show2wat); - $('#ss_cacl2').jqxNumberInput(Show2wat); - - $('#wa_caso4').jqxTooltip({ - content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.' - }); - $('#wa_caso4').jqxNumberInput(Show2wat); - $('#ss_caso4').jqxNumberInput(Show2wat); - - $('#wa_mgso4').jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!' }); - $('#wa_mgso4').jqxNumberInput(Show2wat); - $('#ss_mgso4').jqxNumberInput(Show2wat); - - $('#wa_nacl').jqxTooltip({ - content: 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. ' + - 'Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.' - }); - $('#wa_nacl').jqxNumberInput(Show2wat); - $('#ss_nacl').jqxNumberInput(Show2wat); - - $('#wa_mgcl2').jqxTooltip({ content: 'Magnesiumchloride'}); - $('#wa_mgcl2').jqxNumberInput(Show2wat); - $('#ss_mgcl2').jqxNumberInput(Show2wat); - - $('#wa_nahco3').jqxTooltip({ content: 'Baksoda'}); - $('#wa_caco3').jqxTooltip({ content: 'Kalk'}); - $('#wa_nahco3,#wa_caco3').jqxNumberInput(Show2wat); - - $('#mash_ph').jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'}); - $('#mash_ph').jqxNumberInput(Show2dec); - - $('#calc_acid').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); - - $('#wa_acid_name').jqxInput({ theme: theme, width: 130, height: 23 }); - $('#wa_acid').jqxNumberInput(Show2dec); - $('#wa_acid').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); - $('#wa_acid_perc').jqxNumberInput(Show0dec); - $('#wa_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); - - // Sparge water - $('#sparge_ph').jqxNumberInput(Show2dec); - $('#sparge_acid_amount').jqxNumberInput(Show2dec); - $('#sparge_acid_amount').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); - $('#sparge_acid_type').jqxInput({ theme: theme, width: 130, height: 23 }); - $('#sparge_acid_perc').jqxNumberInput(Show0dec); - $('#sparge_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); - - // Tab 9, Brewday - $('#brew_date_start').jqxTooltip({ content: 'Brouw datum en tijd. Voor planning laat de tijd op 00:00:00 staan.' }); - $('#brew_date_end').jqxTooltip({ content: 'End datum en tijd van de brouw. Leeg laten als er nog niet gebrouwen is.' }); - $('#brew_mash_ph').jqxTooltip({ content: 'De gemeten pH tijdens het maischen eventueel na correctie.' }); - $('#est_mash_ph').jqxTooltip({ content: 'De gewenste pH tijdens het maischen.' }); - $('#brew_preboil_ph').jqxTooltip({ content: 'De gemeten pH in de kookketel na het spoelen en voor de kook.' }); - $('#brew_aboil_ph').jqxTooltip({ content: 'De gemeten pH na het koken.' }); - $('#brew_mash_sg').jqxTooltip({ content: 'Het bereikte SG na het maischen.' }); - $('#est_mash_sg').jqxTooltip({ content: 'Het berekende verwachte SG na het maischen.' }); - $('#brew_preboil_sg').jqxTooltip({ content: 'Het gemeten SG in de kookketel na het spoelen en voor het koken.' }); - $('#est_pre_sg').jqxTooltip({ content: 'Het berekende SG in de kookketel na het spoelen en voor het koken.' }); - $('#brew_aboil_sg').jqxTooltip({ content: 'Het gemeten SG in de kookketel na het koken.' }); - $('#est_og3').jqxTooltip({ content: 'Het gewenste SG in de kookketel na het koken zonder eventuele suikers die tijdens de vergisting toegevoegd worden.' }); - $('#brew_mash_efficiency').jqxTooltip({ content: 'Het behaalde maisch rendement.' }); - $('#brew_preboil_volume').jqxTooltip({ content: 'Het gemeten volume van het wort voor het koken.' }); - $('#est_pre_vol').jqxTooltip({ content: 'Het berekende volume van het wort voor het koken.' }); - $('#brew_aboil_volume').jqxTooltip({ content: 'Het gemeten volume van het wort na het koken.' }); - $('#est_a_vol').jqxTooltip({ content: 'Het gewenste volume na het koken.' }); - $('#brew_preboil_efficiency').jqxTooltip({ content: 'Het berekende rendement voor het koken.' }); - $('#brew_aboil_efficiency').jqxTooltip({ content: 'Het bereikte rendement na het koken.' }); - $('#brew_sparge_temperature').jqxTooltip({ content: 'De spoelwater temperatuur, in te stellen in de Water tab.' }); - $('#brew_sparge_volume').jqxTooltip({ content: 'Het spoelwater voorraad volume, in te stellen in de Water tab.' }); - $('#brew_date_start,#brew_date_end').jqxDateTimeInput(DateTimeopts); - $('#brew_date_start,#brew_date_end').jqxDateTimeInput({ disabled: true }); - $('#est_mash_ph').jqxNumberInput(Show2wat); - $('#brew_mash_ph,#brew_preboil_ph,#brew_aboil_ph').jqxNumberInput(Show2dec); - $('#brew_mash_sg,#brew_preboil_sg,#brew_aboil_sg').jqxNumberInput(Show3dec); - $('#est_mash_sg,#est_pre_sg,#est_og3').jqxNumberInput(Show3wat); - $('#brew_mash_efficiency').jqxNumberInput(Show1dec); - $('#brew_preboil_volume,#brew_aboil_volume').jqxNumberInput(Show1dec); - $('#ketel_volume').jqxNumberInput(Show1dec); - $('#ketel_cm').jqxNumberInput(Show1dec); - $('#est_pre_vol,#est_a_vol').jqxNumberInput(Show1wat); - $('#brew_preboil_efficiency,#brew_aboil_efficiency,#brew_sparge_temperature,#brew_sparge_volume,#brew_sparge_est').jqxNumberInput(Show1dec); - $('#brew_cooling_to').jqxNumberInput(Show1dec); - $('#brew_sparge_ph').jqxNumberInput(Show2dec); - $('#brew_cooling_method').jqxInput({ theme: theme, width: 180, height: 23 }); - $('#brew_cooling_time,#brew_whirlpool9,#brew_whirlpool7,#brew_whirlpool6,#brew_whirlpool2,#brew_aeration_time,#brew_aeration_speed').jqxNumberInput(Show0dec); - $('#brew_aeration_type').jqxInput({ theme: theme, width: 180, height: 23 }); - $('#brew_fermenter_volume').jqxNumberInput(Show1dec); - $('#brew_fermenter_sg').jqxNumberInput(Show3dec); - $('#brew_fermenter_extrawater,#brew_fermenter_tcloss').jqxNumberInput(Show1dec); - $('#brew_fermenter_ibu,#brew_fermenter_color').jqxNumberInput(Show0dec); - - // Tab 10, Fermentation - $('#brew_fermenter_sg2').jqxTooltip({ content: 'Het behaalde SG in het gistvat, overgenomen van de brouwdag.' }); - $('#primary_start_temp').jqxTooltip({ content: 'De begintemperatuur van de hoofdvergisting.' }); - $('#primary_max_temp').jqxTooltip({ content: 'De hoogst bereikte piek temperatuur tijdens de hoofgvergisting.' }); - $('#primary_end_temp').jqxTooltip({ content: 'De eind temperatuur van de hoofdvergisting.' }); - $('#primary_end_sg').jqxTooltip({ content: 'Het gemeten SG aan het eind van de hoofdvergisting.' }); - $('#primary_svg').jqxTooltip({ content: 'De schijnbare vergisting graad behaald na de hoofdgisting.' }); - $('#primary_end_date').jqxTooltip({ content: 'De eind datum van de hoofdvergisting en eventueel overhevelen.' }); - $('#secondary_end_sg').jqxTooltip({ content: 'Het gemeten SG aan het eind van de navergisting.' }); - $('#secondary_svg').jqxTooltip({ content: 'De schijnbare vergisting graad behaald na de nagisting.' }); - $('#secondary_end_date').jqxTooltip({ content: 'De eind datum van de navergisting en het begin van het lageren.' }); - $('#est_fg3').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); - - $('#primary_end_sg,#secondary_end_sg').jqxNumberInput(Show3dec); - $('#primary_end_date,#secondary_end_date').jqxDateTimeInput(Dateopts); - $('#primary_end_date,#secondary_end_date').jqxDateTimeInput({ disabled: true }); - $('#primary_start_temp,#primary_max_temp,#primary_end_temp,#secondary_temp,#tertiary_temp').jqxNumberInput(Show1dec); - $('#fg').jqxNumberInput(Show3dec); - $('#brew_fermenter_sg2,#est_fg3').jqxNumberInput(Show3dec); - $('#final_abv').jqxNumberInput(Show2dec); - $('#primary_svg,#secondary_svg,#final_svg').jqxNumberInput(Show1dec); - $('#FLog').jqxButton({ template: 'info', width: '150px', theme: theme }); - $('#FLog').click(function() { - // Open log in a new tab. - window.open('log_fermentation.php?code=' + dataRecord.code + '&name=' + dataRecord.name); - }); - $('#ILog').jqxButton({ template: 'info', width: '150px', theme: theme }); - $('#ILog').click(function() { - // Open log in a new tab. - window.open('log_ispindel.php?code=' + dataRecord.code + '&name=' + dataRecord.name); - }); - - // Tab 11, Packaging - // TODO: high gravity packaging, extra water and recalc abv, color and ibu. - $('#package_date').jqxTooltip({ content: 'De verpakkings datum van dit bier.' }); - $('#package_volume').jqxTooltip({ content: 'Het beschikbare volume om te bottelen of op fust te zetten.' }); - $('#package_infuse_amount').jqxTooltip({ content: 'De hoeveelheid water of drank extra toe te voegen.' }); - $('#package_infuse_abv').jqxTooltip({ content: 'De hoeveelheid alcohol in de drank, of 0.0 als het water is.' }); - $('#package_infuse_notes').jqxTooltip({ content: 'Omschrijving van de extra toevoeging.' }); - $('#package_abv').jqxTooltip({ content: 'De uiteindelijke hoeveelheid alcohol volume %.' }); - $('#package_ph').jqxTooltip({ content: 'De gemeten pH vlak voor het verpakken.' }); - $('#st_carb_min2').jqxTooltip({ content: 'Het minimum aanbevolen koolzuur volume voor deze bierstijl.'}); - $('#st_carb_max2').jqxTooltip({ content: 'Het maximum aamnevolen koolzuur volume voor deze bierstijl.'}); - $('#bottle_amount').jqxTooltip({ content: 'De totale hoeveelheid te bottelen bier.' }); - $('#keg_amount').jqxTooltip({ content: 'De totale hoeveelheid op fust te zetten bier.' }); - $('#bottle_carbonation').jqxTooltip({ content: 'Het gewenste CO2 volume in de flessen.' }); - $('#keg_carbonation').jqxTooltip({ content: 'Het gewenste CO2 volume door de suiker in de fusten.' }); - $('#bottle_priming_water,#keg_priming_water').jqxTooltip({ content: 'De hoeveelheid water om de suiker op te lossen.' }); - $('#bottle_pressure').jqxTooltip({ content: 'De maximaal te verwachten druk tijdens het hergisten.' }); - $('#package_date').jqxDateTimeInput(Dateopts); - $('#package_date').jqxDateTimeInput({ disabled: true }); - $('#package_infuse_amount').jqxNumberInput(Show3dec); - $('#package_infuse_notes').jqxInput({ theme: theme, width: 640, height: 23 }); - $('#package_abv').jqxNumberInput(Show2dec); - $('#package_ph').jqxNumberInput(Show2dec); - $('#st_carb_min2,#st_carb_max2').jqxNumberInput(Smal1dec); - $('#package_volume,#package_infuse_abv,#bottle_amount,#keg_amount').jqxNumberInput(Show1dec); - $('#bottle_carbonation,#keg_carbonation').jqxNumberInput(Show2dec); - $('#bottle_priming_sugar').jqxInput({ theme: theme, width: 200, height: 23 }); - $('#keg_priming_sugar').jqxInput({ theme: theme, width: 200, height: 23 }); - $('#bottle_priming_water,#keg_priming_water').jqxNumberInput(Show3dec); - $('#keg_forced_carb').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); - $('#bottle_priming_amount,#keg_priming_amount,#bottle_priming_total,#bottle_pressure,#keg_priming_total,#keg_pressure').jqxNumberInput(Show1dec); - $('#bottle_abv,#keg_abv').jqxNumberInput(Show2dec); - $('#bottle_carbonation_temp,#keg_carbonation_temp').jqxNumberInput(Show1dec); - $('#CLog').jqxButton({ template: 'info', width: '150px', theme: theme }); - $('#CLog').click(function() { - // Open log in a new tab. - window.open('log_co2pressure.php?code=' + dataRecord.code + '&name=' + dataRecord.name); - }); - - // Tab 12, Tasting - $('#taste_date').jqxTooltip({ content: 'De proef datum van dit bier.' }); - $('#taste_date').jqxDateTimeInput(Dateopts); - $('#taste_date').jqxDateTimeInput({ disabled: true }); - $('#taste_rate').jqxTooltip({ content: 'Het cijfer voor dit bier van 1 tot 10.' }); - $('#taste_rate').jqxNumberInput(Show1dec); - $('#taste_color').jqxTooltip({ content: 'De kleur van het bier.' }); - $('#taste_transparency').jqxTooltip({ content: 'De helderheid van het bier.' }); - $('#taste_head').jqxTooltip({ content: 'Het schuim op het bier.' }); - $('#taste_color,#taste_transparency,#taste_head').jqxInput({ theme: theme, width: 320, height: 23 }); - $('#taste_aroma').jqxTooltip({ content: 'Het aroma van het bier.' }); - $('#taste_taste').jqxTooltip({ content: 'De smaak van het bier.' }); - $('#taste_aftertaste').jqxTooltip({ content: 'De nasmaak van het bier.' }); - $('#taste_mouthfeel').jqxTooltip({ content: 'Het mondgevoelvan het bier.' }); - $('#taste_aroma,#taste_taste,#taste_aftertaste,#taste_mouthfeel').jqxInput({ theme: theme, width: 960, height: 23 }); - $('#taste_notes').jqxTooltip({ content: 'Het oordeel en opmerkingen over dit bier.' }); - $('#taste_notes').jqxInput({ theme: theme, width: 960, height: 100 }); - - $('#jqxTabs').jqxTabs({ - theme: theme, - width: 1280, - height: 660, - autoHeight: false, - position: 'top' - }); - - // Buttons below - $('#Terug').jqxButton({ template: 'primary', width: '80px', theme: theme }); - $('#Terug').bind('click', function() { - window.location.href = my_return; - }); -}); - diff -r 21fae4d2203e -r 2641860ad61d www/js/prod_inprod.js --- a/www/js/prod_inprod.js Sat Aug 06 22:02:42 2022 +0200 +++ b/www/js/prod_inprod.js Sat Aug 06 22:10:28 2022 +0200 @@ -80,10 +80,10 @@ } }, { text: '', datafield: 'Edit', width: 100, align: 'center', columntype: 'button', cellsrenderer: function() { - return 'Wijzig'; + return 'Bekijk'; }, buttonclick: function(row) { var datarecord = dataAdapter.records[row]; - window.location.href = 'prod_edit.php?record=' + datarecord.record + '&select=inprod&return=prod_inprod.php'; + window.location.href = 'prod_view.php?record=' + datarecord.record + '&select=inprod&return=prod_inprod.php'; } } ], diff -r 21fae4d2203e -r 2641860ad61d www/js/prod_view.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/www/js/prod_view.js Sat Aug 06 22:10:28 2022 +0200 @@ -0,0 +1,3306 @@ +/***************************************************************************** + * Copyright (C) 2018-2022 + * + * Michiel Broek + * + * This file is part of BMS + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * BrewCloud is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ThermFerm; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + + +function block_fermentable(stage, added) { + if (stage > 5 && added < 4) // After fermentation and added before packaging + return true; + if (stage > 3 && added < 3) // After primary and added before sec/tert + return true; + if (stage > 2 && added < 2) // After boil and added during mash or boil + return true; + return false; +} + +function block_hop(stage, useat) +{ + if (stage > 2 && useat < 5) + return true; + return false; +} + +function block_misc(stage, use_use) { + if (stage > 5 && use_use < 5) + return true; + if (stage > 3 && use_use < 4) + return true; + if (stage > 2 && use_use < 3) + return true; + if (stage > 1 && use_use < 1) + return true; + return false; +} + +function block_yeast(stage, use) { + if (stage > 3 && use < 1) + return true; + if (stage > 4 && use < 2) + return true; + if (stage > 5 && use < 3) + return true; + if (stage > 6 && use < 4) + return true; + return false; +} + + +$(document).ready(function() { + + var i, + to_100 = false, // Fermentables adjust to 100% + preboil_sg = 0, + aboil_sg = 0, + est_mash_sg = 0, + psugar = 0, // Percentage real sugars + pcara = 0, // Percentage cara/crystal malts + svg = 77, // Default attenuation + mashkg = 0, // Malt in mash weight + initcells = 0, // Initial yeast cell count + + ok_fermentables = 1, // Fermentables are in stock + ok_hops = 1, // Hops are in stock + ok_miscs = 1, // Miscs are in stock + ok_yeasts = 1, // Yeasts are in stock + ok_waters = 1, // Waters are in stock + + data_loaded = 0; + error_count = 0; + k_cm = 0; + k_vol = 0; + k_what = 0; + + hop_flavour = 0, + hop_aroma = 0, + mash_infuse = 0, + last_acid = '', + + MMCa = 40.048, + MMMg = 24.305, + MMNa = 22.98976928, + MMCl = 35.453, + MMSO4 = 96.0626, + MMHCO3 = 61.01684, + MMCaSO4 = 172.171, + MMCaCl2 = 147.015, + MMCaCO3 = 100.087, + MMMgCl2 = 95.211, /* Since 27-06-2021 */ + MMMgSO4 = 246.475, + MMNaHCO3 = 84.007, + MMNa2CO3 = 105.996, + MMNaCl = 58.443, + MMCaOH2 = 74.06268, + + fermentableRow = 0, + fermentableData = {}, + fermentableInit = 1, + hopRow = 0, + hopData = {}, + miscRow = 0, + miscData = {}, + yeastRow = 0, + yeastData = {}, + mashRow = 0, + mashData = {}, + Ka1 = 0.0000004445, + Ka2 = 0.0000000000468, + dataRecord = {}, + url = 'includes/db_product.php', + MaltVolume = 0.87, // l/kg 0.688 volgens internetbronnen, gemeten 0.874 l/kg, na enige tijd maischen 0,715 l/kg (A3 Otten). + SpecificHeatWater = 1.0, + SpecificHeatMalt = 0.399, //cal/g.°C + SlakingHeat = 10.318, //cal/g.°C + + // Prepare the data + source = { + datatype: 'json', + cache: false, + async: true, + datafields: [ + // From prod_main + { name: 'record', type: 'number' }, + { name: 'uuid', type: 'string' }, + { name: 'name', type: 'string' }, + { name: 'code', type: 'string' }, + { name: 'birth', type: 'string' }, + { name: 'stage', type: 'int' }, + { name: 'notes', type: 'string' }, + { name: 'log_brew', type: 'int' }, + { name: 'log_fermentation', type: 'int' }, + { name: 'log_ispindel', type: 'int' }, + { name: 'log_co2pressure', type: 'int' }, + { name: 'inventory_reduced', type: 'int' }, + { name: 'locked', type: 'int' }, + { name: 'eq_name', type: 'string' }, + { name: 'eq_boil_size', type: 'float' }, + { name: 'eq_batch_size', type: 'float' }, + { name: 'eq_tun_volume', type: 'float' }, + { name: 'eq_tun_weight', type: 'float' }, + { name: 'eq_tun_specific_heat', type: 'float' }, + { name: 'eq_tun_material', type: 'int' }, + { name: 'eq_tun_height', type: 'float' }, + { name: 'eq_top_up_water', type: 'float' }, + { name: 'eq_trub_chiller_loss', type: 'float' }, + { name: 'eq_evap_rate', type: 'float' }, + { name: 'eq_boil_time', type: 'float' }, + { name: 'eq_calc_boil_volume', type: 'int' }, + { name: 'eq_top_up_kettle', type: 'float' }, + { name: 'eq_hop_utilization', type: 'float' }, + { name: 'eq_notes', type: 'string' }, + { name: 'eq_lauter_volume', type: 'float' }, + { name: 'eq_lauter_height', type: 'float' }, + { name: 'eq_lauter_deadspace', type: 'float' }, + { name: 'eq_kettle_volume', type: 'float' }, + { name: 'eq_kettle_height', type: 'float' }, + { name: 'eq_mash_volume', type: 'float' }, + { name: 'eq_mash_max', type: 'float' }, + { name: 'eq_efficiency', type: 'float' }, + { name: 'brew_date_start', type: 'string' }, + { name: 'brew_mash_ph', type: 'float' }, + { name: 'brew_mash_sg', type: 'float' }, + { name: 'brew_mash_efficiency', type: 'float' }, + { name: 'brew_sparge_est', type: 'float' }, + { name: 'brew_sparge_ph', type: 'float' }, + { name: 'brew_preboil_volume', type: 'float' }, + { name: 'brew_preboil_sg', type: 'float' }, + { name: 'brew_preboil_ph', type: 'float' }, + { name: 'brew_preboil_efficiency', type: 'float' }, + { name: 'brew_aboil_volume', type: 'float' }, + { name: 'brew_aboil_sg', type: 'float' }, + { name: 'brew_aboil_ph', type: 'float' }, + { name: 'brew_aboil_efficiency', type: 'float' }, + { name: 'brew_cooling_method', type: 'int' }, + { name: 'brew_cooling_time', type: 'float' }, + { name: 'brew_cooling_to', type: 'float' }, + { name: 'brew_whirlpool9', type: 'float' }, + { name: 'brew_whirlpool7', type: 'float' }, + { name: 'brew_whirlpool6', type: 'float' }, + { name: 'brew_whirlpool2', type: 'float' }, + { name: 'brew_fermenter_volume', type: 'float' }, + { name: 'brew_fermenter_extrawater', type: 'float' }, + { name: 'brew_fermenter_tcloss', type: 'float' }, + { name: 'brew_aeration_time', type: 'float' }, + { name: 'brew_aeration_speed', type: 'float' }, + { name: 'brew_aeration_type', type: 'int' }, + { name: 'brew_fermenter_sg', type: 'float' }, + { name: 'brew_fermenter_ibu', type: 'float' }, + { name: 'brew_fermenter_color', type: 'float' }, + { name: 'brew_date_end', type: 'string' }, + { name: 'og', type: 'float' }, + { name: 'fg', type: 'float' }, + { name: 'primary_start_temp', type: 'float' }, + { name: 'primary_max_temp', type: 'float' }, + { name: 'primary_end_temp', type: 'float' }, + { name: 'primary_end_sg', type: 'float' }, + { name: 'primary_end_date', type: 'string' }, + { name: 'secondary_temp', type: 'float' }, + { name: 'secondary_end_sg', type: 'float' }, + { name: 'secondary_end_date', type: 'string' }, + { name: 'tertiary_temp', type: 'float' }, + { name: 'package_date', type: 'string' }, + { name: 'package_volume', type: 'float' }, + { name: 'package_infuse_amount', type: 'float' }, + { name: 'package_infuse_abv', type: 'float' }, + { name: 'package_infuse_notes', type: 'string' }, + { name: 'package_abv', type: 'float' }, + { name: 'package_ph', type: 'float' }, + { name: 'bottle_amount', type: 'float' }, + { name: 'bottle_carbonation', type: 'float' }, + { name: 'bottle_priming_water', type: 'float' }, + { name: 'bottle_priming_amount', type: 'float' }, + { name: 'bottle_carbonation_temp', type: 'float' }, + { name: 'keg_amount', type: 'float' }, + { name: 'keg_carbonation', type: 'float' }, + { name: 'keg_priming_water', type: 'float' }, + { name: 'keg_priming_amount', type: 'float' }, + { name: 'keg_carbonation_temp', type: 'float' }, + { name: 'keg_forced_carb', type: 'int' }, + { name: 'keg_pressure', type: 'float' }, + { name: 'taste_notes', type: 'string' }, + { name: 'taste_rate', type: 'float' }, + { name: 'taste_date', type: 'string' }, + { name: 'taste_color', type: 'string' }, + { name: 'taste_transparency', type: 'string' }, + { name: 'taste_head', type: 'string' }, + { name: 'taste_aroma', type: 'string' }, + { name: 'taste_taste', type: 'string' }, + { name: 'taste_mouthfeel', type: 'string' }, + { name: 'taste_aftertaste', type: 'string' }, + { name: 'st_name', type: 'string' }, + { name: 'st_letter', type: 'string' }, + { name: 'st_guide', type: 'string' }, + { name: 'st_category', type: 'string' }, + { name: 'st_category_number', type: 'int' }, + { name: 'st_type', type: 'int' }, + { name: 'st_og_min', type: 'float' }, + { name: 'st_og_max', type: 'float' }, + { name: 'st_fg_min', type: 'float' }, + { name: 'st_fg_max', type: 'float' }, + { name: 'st_ibu_min', type: 'float' }, + { name: 'st_ibu_max', type: 'float' }, + { name: 'st_color_min', type: 'float' }, + { name: 'st_color_max', type: 'float' }, + { name: 'st_carb_min', type: 'float' }, + { name: 'st_carb_max', type: 'float' }, + { name: 'st_abv_min', type: 'float' }, + { name: 'st_abv_max', type: 'float' }, + { name: 'type', type: 'int' }, + { name: 'batch_size', type: 'float' }, + { name: 'boil_size', type: 'float' }, + { name: 'boil_time', type: 'float' }, + { name: 'efficiency', type: 'float' }, + { name: 'est_og', type: 'float' }, + { name: 'est_og3', type: 'float' }, + { name: 'est_fg', type: 'float' }, + { name: 'est_abv', type: 'float' }, + { name: 'est_color', type: 'float' }, + { name: 'color_method', type: 'int' }, + { name: 'est_ibu', type: 'float' }, + { name: 'ibu_method', type: 'int' }, + { name: 'est_carb', type: 'float' }, + { name: 'sparge_temp', type: 'float' }, + { name: 'sparge_ph', type: 'float' }, + { name: 'sparge_volume', type: 'float' }, + { name: 'sparge_source', type: 'int' }, + { name: 'sparge_acid_type', type: 'int' }, + { name: 'sparge_acid_perc', type: 'float' }, + { name: 'sparge_acid_amount', type: 'float' }, + { name: 'mash_ph', type: 'float' }, + { name: 'mash_name', type: 'string' }, + { name: 'calc_acid', type: 'int' }, + { name: 'w1_name', type: 'string' }, + { name: 'w1_amount', type: 'float' }, + { name: 'w1_calcium', type: 'float' }, + { name: 'w1_sulfate', type: 'float' }, + { name: 'w1_chloride', type: 'float' }, + { name: 'w1_sodium', type: 'float' }, + { name: 'w1_magnesium', type: 'float' }, + { name: 'w1_total_alkalinity', type: 'float' }, + { name: 'w1_ph', type: 'float' }, + { name: 'w1_cost', type: 'float' }, + { name: 'w2_name', type: 'string' }, + { name: 'w2_amount', type: 'float' }, + { name: 'w2_calcium', type: 'float' }, + { name: 'w2_sulfate', type: 'float' }, + { name: 'w2_chloride', type: 'float' }, + { name: 'w2_sodium', type: 'float' }, + { name: 'w2_magnesium', type: 'float' }, + { name: 'w2_total_alkalinity', type: 'float' }, + { name: 'w2_ph', type: 'float' }, + { name: 'w2_cost', type: 'float' }, + { name: 'wg_amount', type: 'float' }, + { name: 'wg_calcium', type: 'float' }, + { name: 'wg_sulfate', type: 'float' }, + { name: 'wg_chloride', type: 'float' }, + { name: 'wg_sodium', type: 'float' }, + { name: 'wg_magnesium', type: 'float' }, + { name: 'wg_total_alkalinity', type: 'float' }, + { name: 'wg_ph', type: 'float' }, + { name: 'wb_calcium', type: 'float' }, + { name: 'wb_sulfate', type: 'float' }, + { name: 'wb_chloride', type: 'float' }, + { name: 'wb_sodium', type: 'float' }, + { name: 'wb_magnesium', type: 'float' }, + { name: 'wb_total_alkalinity', type: 'float' }, + { name: 'wb_ph', type: 'float' }, + { name: 'wa_acid_name', type: 'int' }, + { name: 'wa_acid_perc', type: 'int' }, + { name: 'wa_base_name', type: 'int' }, + { name: 'starter_enable', type: 'int' }, + { name: 'starter_type', type: 'int' }, + { name: 'starter_sg', type: 'float' }, + { name: 'starter_viability', type: 'int' }, + { name: 'yeast_prod_date', type: 'string' }, + { name: 'yeast_pitchrate', type: 'float' }, + { name: 'prop1_type', type: 'int' }, + { name: 'prop1_volume', type: 'float' }, + { name: 'prop2_type', type: 'int' }, + { name: 'prop2_volume', type: 'float' }, + { name: 'prop3_type', type: 'int' }, + { name: 'prop3_volume', type: 'float' }, + { name: 'prop4_type', type: 'int' }, + { name: 'prop4_volume', type: 'float' }, + { name: 'divide_type', type: 'int' }, + { name: 'divide_size', type: 'float' }, + { name: 'divide_factor', type: 'float' }, + { name: 'divide_parts', type: 'int' }, + { name: 'divide_part', type: 'int' }, + { name: 'fermentables', type: 'string' }, + { name: 'hops', type: 'string' }, + { name: 'miscs', type: 'string' }, + { name: 'yeasts', type: 'string' }, + { name: 'mashs', type: 'string' } + ], + id: 'record', + url: url + '?record=' + my_record + }, + + // Load data and select one record. + dataAdapter = new $.jqx.dataAdapter(source, { + loadComplete: function() { + dataRecord = dataAdapter.records[0]; + // Hidden record uuid + $('#name').val(dataRecord.name); + $('#code').val(dataRecord.code); + $('#birth').val(dataRecord.birth); + $('#stage').val(StageData[dataRecord.stage].nl); + $('#notes').val(dataRecord.notes); + $('#locked').val(dataRecord.locked); + $('#eq_name').val(dataRecord.eq_name); + $('#eq_notes').val(dataRecord.eq_notes); + $('#eq_boil_size').val(dataRecord.eq_boil_size); + $('#eq_batch_size').val(dataRecord.eq_batch_size); + $('#eq_tun_volume').val(dataRecord.eq_tun_volume); + $('#eq_top_up_water').val(dataRecord.eq_top_up_water); + $('#eq_trub_chiller_loss').val(dataRecord.eq_trub_chiller_loss); + $('#eq_evap_rate').val(dataRecord.eq_evap_rate); + $('#eq_boil_time').val(dataRecord.eq_boil_time); + $('#eq_top_up_kettle').val(dataRecord.eq_top_up_kettle); + $('#eq_hop_utilization').val(dataRecord.eq_hop_utilization); + $('#eq_lauter_volume').val(dataRecord.eq_lauter_volume); + $('#eq_lauter_deadspace').val(dataRecord.eq_lauter_deadspace); + $('#eq_kettle_volume').val(dataRecord.eq_kettle_volume); + $('#eq_mash_volume').val(dataRecord.eq_mash_volume); + $('#eq_mash_max').val(dataRecord.eq_mash_max); + $('#eq_efficiency').val(dataRecord.eq_efficiency); + // Brewdate + $('#brew_date_start').val(dataRecord.brew_date_start); + $('#brew_mash_ph').val(dataRecord.brew_mash_ph); + $('#brew_mash_sg').val(dataRecord.brew_mash_sg); + $('#brew_mash_efficiency').val(dataRecord.brew_mash_efficiency); + // Header Spoelen en filteren + $('#brew_sparge_temperature').val(dataRecord.sparge_temp); + $('#brew_sparge_volume').val(dataRecord.sparge_volume); + $('#brew_sparge_est').val(dataRecord.brew_sparge_est); + $('#brew_sparge_ph').val(dataRecord.brew_sparge_ph); + // Header Beluchten + $('#brew_aeration_type').val(AerationTypeData[dataRecord.brew_aeration_type].nl); + $('#brew_aeration_time').val(dataRecord.brew_aeration_time); + $('#brew_aeration_speed').val(dataRecord.brew_aeration_speed); + + $('#brew_preboil_ph').val(dataRecord.brew_preboil_ph); + $('#brew_preboil_sg').val(dataRecord.brew_preboil_sg); + $('#brew_preboil_volume').val(dataRecord.brew_preboil_volume); + $('#brew_preboil_efficiency').val(dataRecord.brew_preboil_efficiency); + // Header Koelen en whirlpoolen + $('#brew_whirlpool9').val(dataRecord.brew_whirlpool9); + $('#brew_whirlpool7').val(dataRecord.brew_whirlpool7); + $('#brew_whirlpool6').val(dataRecord.brew_whirlpool6); + $('#brew_whirlpool2').val(dataRecord.brew_whirlpool2); + // Header Naar gistvat + $('#brew_fermenter_volume').val(dataRecord.brew_fermenter_volume); + $('#brew_fermenter_sg').val(dataRecord.brew_fermenter_sg); + $('#brew_fermenter_sg2').val(dataRecord.brew_fermenter_sg); + $('#brew_fermenter_ibu').val(dataRecord.brew_fermenter_ibu); + $('#brew_fermenter_color').val(dataRecord.brew_fermenter_color); + $('#brew_fermenter_extrawater').val(dataRecord.brew_fermenter_extrawater); + $('#brew_fermenter_tcloss').val(dataRecord.brew_fermenter_tcloss); + + $('#brew_aboil_ph').val(dataRecord.brew_aboil_ph); + $('#brew_aboil_sg').val(dataRecord.brew_aboil_sg); + $('#brew_aboil_volume').val(dataRecord.brew_aboil_volume); + $('#brew_aboil_efficiency').val(dataRecord.brew_aboil_efficiency); + // Header Koelen en whirlpoolen + $('#brew_cooling_to').val(dataRecord.brew_cooling_to); + $('#brew_cooling_method').val(CoolingTypeData[dataRecord.brew_cooling_method].nl); + $('#brew_cooling_time').val(dataRecord.brew_cooling_time); + // Niks + $('#brew_date_end').val(dataRecord.brew_date_end); + $('#og').val(dataRecord.og); + $('#fg').val(dataRecord.fg); + $('#primary_start_temp').val(dataRecord.primary_start_temp); + $('#primary_max_temp').val(dataRecord.primary_max_temp); + $('#primary_end_temp').val(dataRecord.primary_end_temp); + $('#primary_end_sg').val(dataRecord.primary_end_sg); + $('#primary_end_date').val(dataRecord.primary_end_date); + $('#secondary_temp').val(dataRecord.secondary_temp); + $('#secondary_end_sg').val(dataRecord.secondary_end_sg); + $('#secondary_end_date').val(dataRecord.secondary_end_date); + $('#tertiary_temp').val(dataRecord.tertiary_temp); + $('#package_date').val(dataRecord.package_date); + $('#package_volume').val(dataRecord.package_volume); + $('#package_infuse_amount').val(dataRecord.package_infuse_amount); + $('#package_infuse_abv').val(dataRecord.package_infuse_abv); + $('#package_infuse_notes').val(dataRecord.package_infuse_notes); + $('#package_abv').val(dataRecord.package_abv); + $('#package_ph').val(dataRecord.package_ph); + $('#bottle_amount').val(dataRecord.bottle_amount); + $('#bottle_carbonation').val(dataRecord.bottle_carbonation); + $('#bottle_priming_water').val(dataRecord.bottle_priming_water); + $('#bottle_priming_amount').val(dataRecord.bottle_priming_amount); + $('#bottle_carbonation_temp').val(dataRecord.bottle_carbonation_temp); + $('#keg_amount').val(dataRecord.keg_amount); + $('#keg_carbonation').val(dataRecord.keg_carbonation); + $('#keg_priming_water').val(dataRecord.keg_priming_water); + $('#keg_priming_amount').val(dataRecord.keg_priming_amount); + $('#keg_carbonation_temp').val(dataRecord.keg_carbonation_temp); + $('#keg_forced_carb').val(dataRecord.keg_forced_carb); + $('#keg_pressure').val(dataRecord.keg_pressure); + $('#taste_notes').val(dataRecord.taste_notes); + $('#taste_rate').val(dataRecord.taste_rate); + $('#taste_date').val(dataRecord.taste_date); + $('#taste_color').val(dataRecord.taste_color); + $('#taste_transparency').val(dataRecord.taste_transparency); + $('#taste_head').val(dataRecord.taste_head); + $('#taste_aroma').val(dataRecord.taste_aroma); + $('#taste_taste').val(dataRecord.taste_taste); + $('#taste_mouthfeel').val(dataRecord.taste_mouthfeel); + $('#taste_aftertaste').val(dataRecord.taste_aftertaste); + + // Recipe + $('#st_name').val(dataRecord.st_name); + $('#st_letter').val(dataRecord.st_letter); + $('#st_guide').val(dataRecord.st_guide); + $('#st_category').val(dataRecord.st_category); + $('#st_category_number').val(dataRecord.st_category_number); + $('#st_type').val(StyleTypeData[dataRecord.st_type].nl); + $('#st_og_min').val(dataRecord.st_og_min); + $('#st_og_max').val(dataRecord.st_og_max); + $('#st_fg_min').val(dataRecord.st_fg_min); + $('#st_fg_max').val(dataRecord.st_fg_max); + $('#st_abv_min').val(dataRecord.st_abv_min); + $('#st_abv_max').val(dataRecord.st_abv_max); + $('#st_color_min').val(dataRecord.st_color_min); + $('#st_color_max').val(dataRecord.st_color_max); + $('#st_ibu_min').val(dataRecord.st_ibu_min); + $('#st_ibu_max').val(dataRecord.st_ibu_max); + $('#st_carb_min').val(dataRecord.st_carb_min); + $('#st_carb_min2').val(dataRecord.st_carb_min); + $('#st_carb_max').val(dataRecord.st_carb_max); + $('#st_carb_max2').val(dataRecord.st_carb_max); + $('#type').val(RecipeTypeData[dataRecord.type].nl); + $('#batch_size').val(dataRecord.batch_size); + $('#est_a_vol').val(dataRecord.batch_size * 1.04); + $('#boil_size').val(dataRecord.boil_size); + $('#est_pre_vol').val(dataRecord.boil_size * 1.04); + $('#boil_time').val(dataRecord.boil_time); + $('#efficiency').val(dataRecord.efficiency); + $('#est_og').val(dataRecord.est_og); + $('#est_og2').val(dataRecord.est_og); + $('#est_og3').val(dataRecord.est_og3); + $('#est_fg').val(dataRecord.est_fg); + $('#est_fg2').val(dataRecord.est_fg); + $('#est_fg3').val(dataRecord.est_fg); + $('#est_color').val(dataRecord.est_color); + $('#est_color2').val(dataRecord.est_color); + $('#est_abv').val(dataRecord.est_abv); + $('#color_method').val(ColorMethodData[dataRecord.color_method].nl); + $('#est_ibu').val(dataRecord.est_ibu); + $('#est_ibu2').val(dataRecord.est_ibu); + $('#ibu_method').val(IBUmethodData[dataRecord.ibu_method].nl); + $('#est_carb').val(dataRecord.est_carb); + $('#mash_name').val(dataRecord.mash_name); + $('#mash_ph').val(dataRecord.mash_ph); + $('#sparge_temp').val(dataRecord.sparge_temp); + $('#sparge_ph').val(dataRecord.sparge_ph); + $('#sparge_volume').val(dataRecord.sparge_volume); + $('#sparge_source').val(dataRecord.sparge_source); + $('#sparge_acid_type').val(AcidTypeData[dataRecord.sparge_acid_type].nl); + $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); + $('#sparge_acid_amount').val(dataRecord.sparge_acid_amount * 1000); + $('#calc_acid').val(dataRecord.calc_acid); + $('#w1_name').val(dataRecord.w1_name); + $('#w1_amount').val(dataRecord.w1_amount); + $('#w1_calcium').val(dataRecord.w1_calcium); + $('#w1_sulfate').val(dataRecord.w1_sulfate); + $('#w1_chloride').val(dataRecord.w1_chloride); + $('#w1_sodium').val(dataRecord.w1_sodium); + $('#w1_magnesium').val(dataRecord.w1_magnesium); + $('#w1_total_alkalinity').val(dataRecord.w1_total_alkalinity); + $('#w1_bicarbonate').val(dataRecord.w1_total_alkalinity * 1.22); + $('#w1_ph').val(dataRecord.w1_ph); + $('#w1_cost').val(dataRecord.w1_cost); + $('#w2_name').val(dataRecord.w2_name); + $('#w2_amount').val(dataRecord.w2_amount); + $('#w2_calcium').val(dataRecord.w2_calcium); + $('#w2_sulfate').val(dataRecord.w2_sulfate); + $('#w2_chloride').val(dataRecord.w2_chloride); + $('#w2_sodium').val(dataRecord.w2_sodium); + $('#w2_magnesium').val(dataRecord.w2_magnesium); + $('#w2_total_alkalinity').val(dataRecord.w2_total_alkalinity); + $('#w2_bicarbonate').val(dataRecord.w2_total_alkalinity * 1.22); + $('#w2_ph').val(dataRecord.w2_ph); + $('#w2_cost').val(dataRecord.w2_cost); + $('#wg_amount').val(dataRecord.wg_amount); + $('#wg_calcium').val(dataRecord.wg_calcium); + $('#wg_sulfate').val(dataRecord.wg_sulfate); + $('#wg_chloride').val(dataRecord.wg_chloride); + $('#wg_sodium').val(dataRecord.wg_sodium); + $('#wg_magnesium').val(dataRecord.wg_magnesium); + $('#wg_total_alkalinity').val(dataRecord.wg_total_alkalinity); + $('#wg_ph').val(dataRecord.wg_ph); + $('#wb_calcium').val(dataRecord.wb_calcium); + $('#wb_sulfate').val(dataRecord.wb_sulfate); + $('#wb_chloride').val(dataRecord.wb_chloride); + $('#wb_sodium').val(dataRecord.wb_sodium); + $('#wb_magnesium').val(dataRecord.wb_magnesium); + $('#wb_total_alkalinity').val(dataRecord.wb_total_alkalinity); + $('#wb_ph').val(dataRecord.wb_ph); + $('#wa_acid_name').val(dataRecord.wa_acid_name); + $('#wa_acid_perc').val(dataRecord.wa_acid_perc); + $('#starter_type').val(StarterTypeData[dataRecord.starter_type].nl); + $('#starter_sg').val(dataRecord.starter_sg); + $('#starter_viability').val(dataRecord.starter_viability); + $('#yeast_prod_date').val(dataRecord.yeast_prod_date); + $('#yeast_pitchrate').val(dataRecord.yeast_pitchrate); + $('#prop1_type').val(StarterTypeData[dataRecord.prop1_type].nl); + $('#prop1_volume').val(dataRecord.prop1_volume); + $('#prop2_type').val(StarterTypeData[dataRecord.prop2_type].nl); + $('#prop2_volume').val(dataRecord.prop2_volume); + $('#prop3_type').val(StarterTypeData[dataRecord.prop3_type].nl); + $('#prop3_volume').val(dataRecord.prop3_volume); + $('#prop4_type').val(StarterTypeData[dataRecord.prop4_type].nl); + $('#prop4_volume').val(dataRecord.prop4_volume); + $('#divide_type').val(SplitData[dataRecord.divide_type].nl); + if (dataRecord.divide_type > 0) + $('#divide_batch').val((dataRecord.divide_part + 1) + ' van ' + (dataRecord.divide_parts + 1)); + else + $('#divide_batch').val('n.v.t.'); + // hidden divide_size + // hidden divide_factor + // hidden divide_parts + // hidden divide_part + editFermentable(dataRecord); + editHop(dataRecord); + editMisc(dataRecord); + editYeast(dataRecord); + editMash(dataRecord); + calcStage(); + $('#jqxTabs').jqxTabs('select', 2); + data_loaded = 1; + }, + loadError: function(jqXHR, status, error) { + console.log('main data load error: ' + status + ' ' + error); + } + }); + + // Inline fermentables editor + var editFermentable = function(data) { + var fermentableSource = { + localdata: data.fermentables, + datafields: [ + { name: 'f_name', type: 'string' }, + { name: 'f_origin', type: 'string' }, + { name: 'f_supplier', type: 'string' }, + { name: 'f_amount', type: 'float' }, + { name: 'f_cost', type: 'float' }, + { name: 'f_type', type: 'int' }, + { name: 'f_yield', type: 'float' }, + { name: 'f_color', type: 'float' }, + { name: 'f_coarse_fine_diff', type: 'float' }, + { name: 'f_moisture', type: 'float' }, + { name: 'f_diastatic_power', type: 'float' }, + { name: 'f_protein', type: 'float' }, + { name: 'f_max_in_batch', type: 'float' }, + { name: 'f_graintype', type: 'int' }, + { name: 'f_added', type: 'int' }, + { name: 'f_dissolved_protein', type: 'float' }, + { name: 'f_recommend_mash', type: 'int' }, + { name: 'f_add_after_boil', type: 'int' }, + { name: 'f_adjust_to_total_100', type: 'int' }, + { name: 'f_percentage', type: 'float' }, + { name: 'f_di_ph', type: 'float' }, + { name: 'f_acid_to_ph_57', type: 'float' }, + { name: 'f_inventory', type: 'float' }, + { name: 'f_avail', type: 'int' } + ], + }, + fermentableAdapter = new $.jqx.dataAdapter(fermentableSource); + + $('#fermentableGrid').jqxGrid({ + width: 1240, + height: 470, + source: fermentableAdapter, + theme: theme, + editable: false, + ready: function() { calcFermentables(); $('#jqxTabs').jqxTabs('next'); }, + columns: [ + { text: 'Vergistbaar ingrediënt', datafield: 'f_name' }, + { text: 'Leverancier', datafield: 'f_supplier', width: 180 }, + { text: 'Kleur', datafield: 'f_color', width: 90, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + dataAdapter.formatNumber(value, 'f0') + ' EBC'; + } + }, + { text: 'Type', width: 100, datafield: 'f_type', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + FermentableTypeData[value].nl + ''; + } + }, + { text: 'Moment', width: 110, datafield: 'f_added', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + AddedData[value].nl + ''; + } + }, + { text: 'Maxinbatch', datafield: 'f_max_in_batch', hidden: true }, + { text: 'Opbrengst', datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, + { text: 'Gewicht Kg', datafield: 'f_amount', width: 110, align: 'right', cellsalign: 'right', cellsformat: 'f3' }, + { text: 'Voorraad Kg', datafield: 'f_inventory', width: 110, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + var color = (value < rowdata.f_amount) ? '#ff4040':'#ffffff'; + if (block_fermentable(dataRecord.inventory_reduced, rowdata.f_added) == false) { + return '' + fermentableAdapter.formatNumber(value, 'f3') + ''; + } else { + return ''; + } + } + }, + { text: 'Procent', datafield: 'f_percentage', width: 90, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + if (rowdata.f_added >= 4) + return ''; + var color = (value > rowdata.f_max_in_batch) ? '#ff4040':'#ffffff'; + return '' + fermentableAdapter.formatNumber(value, 'p1') + ''; + } + }, + { text: '100%', datafield: 'f_adjust_to_total_100', width: 70, align: 'center', cellsalign: 'center', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + if (value == 0) + return ''; + return ''; + } + } + ] + }); + }; + + // Inline hops editor + var editHop = function(data) { + var hopSource = { + localdata: data.hops, + datafields: [ + { name: 'h_name', type: 'string' }, + { name: 'h_origin', type: 'string' }, + { name: 'h_amount', type: 'float' }, + { name: 'h_cost', type: 'float' }, + { name: 'h_type', type: 'int' }, + { name: 'h_form', type: 'int' }, + { name: 'h_useat', type: 'int' }, + { name: 'h_time', type: 'int' }, + { name: 'h_alpha', type: 'float' }, + { name: 'h_beta', type: 'float' }, + { name: 'h_hsi', type: 'float' }, + { name: 'h_humulene', type: 'float' }, + { name: 'h_caryophyllene', type: 'float' }, + { name: 'h_cohumulone', type: 'float' }, + { name: 'h_myrcene', type: 'float' }, + { name: 'h_total_oil', type: 'float' }, + { name: 'h_inventory', type: 'float' }, + { name: 'h_avail', type: 'int' }, + { name: 'h_utilisation', type: 'float' }, + { name: 'h_bu_factor', type: 'float' } + ], + }, + hopAdapter = new $.jqx.dataAdapter(hopSource); + + $('#hopGrid').jqxGrid({ + width: 1240, + height: 560, + source: hopAdapter, + theme: theme, + editable: false, + ready: function() { $('#jqxTabs').jqxTabs('next'); }, + columns: [ + { text: 'Hop', datafield: 'h_name' }, + { text: 'Origin', width: 180, datafield: 'h_origin' }, + { text: 'Type', width: 90, datafield: 'h_type', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + HopTypeData[value].nl + ''; + } + }, + { text: 'Vorm', width: 110, datafield: 'h_form', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + HopFormData[value].nl + ''; + } + }, + { text: 'Alpha', datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, + { text: 'Gebruik', width: 110, datafield: 'h_useat', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + HopUseData[value].nl + ''; + } + }, + { text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var duration = ''; + if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4)) // Boil, Whirlpool + duration = dataAdapter.formatNumber(value, 'f0') + ' min.'; + else if (rowdata.h_useat == 5) // Dry hop + duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; + return '' + duration + ''; + } + }, + { text: 'IBU', datafield: 'ibu', width: 80, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat(dataRecord.batch_size), + parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), dataRecord.ibu_method, + dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); + return '' + dataAdapter.formatNumber(ibu, 'f1') + ''; + } + }, + { text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var amount = dataAdapter.formatNumber(value, 'f1') + ' kg'; + if (value < 1) + amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; + return '' + amount + ''; + } + }, + { text: 'Voorraad', datafield: 'h_inventory', width: 110, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + if (block_hop(dataRecord.inventory_reduced, rowdata.h_useat) == false) { + var amount = dataAdapter.formatNumber(value, 'f1') + ' kg', + color = (value < rowdata.h_amount) ? '#ff4040':'#ffffff'; + if (value < 1) + amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; + return '' + amount + ''; + } else { + return ''; + } + } + } + ] + }); + }; + + // Inline miscs editor + var editMisc = function(data) { + var miscSource = { + localdata: data.miscs, + datafields: [ + { name: 'm_name', type: 'string' }, + { name: 'm_amount', type: 'float' }, + { name: 'm_cost', type: 'float' }, + { name: 'm_type', type: 'int' }, + { name: 'm_use_use', type: 'int' }, + { name: 'm_time', type: 'float' }, + { name: 'm_amount_is_weight', type: 'int' }, + { name: 'm_inventory', type: 'float' }, + { name: 'm_avail', type: 'int' } + ], + }, + miscAdapter = new $.jqx.dataAdapter(miscSource, { + beforeLoadComplete: function(records) { + var row, i, data = new Array(); + for (i = 0; i < records.length; i++) { + row = records[i]; + data.push(row); + // Initial set water agent values. + if (row.m_use_use == 1) { // Mash + switch (row.m_name) { + case 'CaCl2': + $('#wa_cacl2').val(row.m_amount * 1000); + break; + case 'CaSO4': + $('#wa_caso4').val(row.m_amount * 1000); + break; + case 'MgSO4': + $('#wa_mgso4').val(row.m_amount * 1000); + break; + case 'NaCl': + $('#wa_nacl').val(row.m_amount * 1000); + break; + case 'MgCl2': + $('#wa_mgcl2').val(row.m_amount * 1000); + break; + case 'NaHCO3': + $('#wa_nahco3').val(row.m_amount * 1000); + break; + case 'CaCO3': + $('#wa_caco3').val(row.m_amount * 1000); + break; + case 'Melkzuur': + $('#wa_acid_name').val(AcidTypeData[0].nl); + $('#wa_acid').val(row.m_amount * 1000); + $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); + last_acid = 'Melkzuur'; + break; + case 'Zoutzuur': + $('#wa_acid_name').val(AcidTypeData[1].nl); + $('#wa_acid').val(row.m_amount * 1000); + $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc); + last_acid = 'Zoutzuur'; + break; + case 'Fosforzuur': + $('#wa_acid_name').val(AcidTypeData[2].nl); + $('#wa_acid').val(row.m_amount * 1000); + $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc); + last_acid = 'Fosforzuur'; + break; + case 'Zwavelzuur': + $('#wa_acid_name').val(AcidTypeData[3].nl); + $('#wa_acid').val(row.m_amount * 1000); + $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc); + last_acid = 'Zwavelzuur'; + break; + } + } + if (row.m_use_use == 6) { // Sparge + switch (row.m_name) { + case 'CaCl2': + $('#ss_cacl2').val(row.m_amount * 1000); + break; + case 'CaSO4': + $('#ss_caso4').val(row.m_amount * 1000); + break; + case 'MgSO4': + $('#ss_mgso4').val(row.m_amount * 1000); + break; + case 'NaCl': + $('#ss_nacl').val(row.m_amount * 1000); + break; + case 'MgCl2': + $('#ss_mgcl2').val(row.m_amount * 1000); + break; + } + } + } + return data; + }, + loadError: function(jqXHR, status, error) { console.log('miscs load error ' + status + ' ' + error); }, + }); + $('#miscGrid').jqxGrid({ + width: 1240, + height: 575, + source: miscAdapter, + theme: theme, + editable: false, + ready: function() { $('#jqxTabs').jqxTabs('next'); }, + columns: [ + { text: 'Ingredient', datafield: 'm_name' }, + { text: 'Type', width: 140, datafield: 'm_type', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + MiscTypeData[value].nl + ''; + } + }, + { text: 'Gebruik', width: 140, datafield: 'm_use_use', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + MiscUseData[value].nl + ''; + } + }, + { text: 'Tijd', datafield: 'm_time', width: 90, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var duration = ''; + if (rowdata.m_use_use == 2) // Boil + duration = dataAdapter.formatNumber(value, 'f0') + ' min.'; + else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) // Primary or Secondary + duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; + return '' + duration + ''; + } + }, + { text: 'Hoeveel', datafield: 'm_amount', width: 110, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml'; + return '' + dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr + ''; + } + }, + { text: 'Voorraad', datafield: 'm_inventory', width: 110, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + if (block_misc(dataRecord.inventory_reduced, rowdata.m_use_use) == false) { + var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml', + color = (value < rowdata.m_amount) ? '#ff4040':'#ffffff', + amount = dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr; + return '' + amount + ''; + } else { + return ''; + } + } + } + ] + }); + }; + + // Inline yeasts editor + var editYeast = function(data) { + var yeastSource = { + localdata: data.yeasts, + datafields: [ + { name: 'y_name', type: 'string' }, + { name: 'y_laboratory', type: 'string' }, + { name: 'y_product_id', type: 'string' }, + { name: 'y_amount', type: 'float' }, + { name: 'y_cost', type: 'float' }, + { name: 'y_type', type: 'int' }, + { name: 'y_form', type: 'int' }, + { name: 'y_flocculation', type: 'int' }, + { name: 'y_min_temperature', type: 'float' }, + { name: 'y_max_temperature', type: 'float' }, + { name: 'y_attenuation', type: 'float' }, + { name: 'y_use', type: 'int' }, + { name: 'y_cells', type: 'float' }, + { name: 'y_tolerance', type: 'float' }, + { name: 'y_inventory', type: 'float' }, + { name: 'y_sta1', type: 'int' }, + { name: 'y_bacteria', type: 'int' }, + { name: 'y_harvest_top', type: 'int' }, + { name: 'y_harvest_time', type: 'int' }, + { name: 'y_pitch_temperature', type: 'float' }, + { name: 'y_pofpos', type: 'int' }, + { name: 'y_zymocide', type: 'int' }, + { name: 'y_gr_hl_lo', type: 'int' }, + { name: 'y_sg_lo', type: 'float' }, + { name: 'y_gr_hl_hi', type: 'int' }, + { name: 'y_sg_hi', type: 'float' }, + { name: 'y_avail', type: 'int' } + ], + }, + yeastAdapter = new $.jqx.dataAdapter(yeastSource); + + $('#yeastGrid').jqxGrid({ + width: 1240, + height: 325, + source: yeastAdapter, + theme: theme, + editable: false, + ready: function() { $('#jqxTabs').jqxTabs('next'); }, + columns: [ + { text: 'Gist', datafield: 'y_name' }, + { text: 'Laboratorium', width: 150, datafield: 'y_laboratory' }, + { text: 'Code', width: 90, datafield: 'y_product_id' }, + { text: 'Soort', width: 100, datafield: 'y_form', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + YeastFormData[value].nl + ''; + } + }, + { text: 'Min. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' }, + { text: 'Max. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' }, + { text: 'Tol. %', width: 60, align: 'right', cellsalign: 'right', datafield: 'y_tolerance', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var amount = '', color = (dataRecord.est_abv > value) ? '#ff4040':'#ffffff'; + if (value > 0) { + amount = dataAdapter.formatNumber(value, 'f1'); + } + return '' + amount + ''; + } + }, + { text: 'Attn. %', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' }, + { text: 'Voor', width: 120, datafield: 'y_use', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + YeastUseData[value].nl + ''; + } + }, + { text: 'Hoeveel', datafield: 'y_amount', width: 90, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml'; + if (rowdata.y_form == 0) // Liquid + amount = dataAdapter.formatNumber(value, 'f0') + ' pk'; + else if (rowdata.y_form == 1 || rowdata.y_form == 6) // Dry + amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; + return '' + amount + ''; + } + }, + { text: 'Voorraad', datafield: 'y_inventory', width: 90, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var color, amount; + if (block_yeast(dataRecord.inventory_reduced, rowdata.y_use) == false) { + color = '#ffffff'; + if (value < rowdata.y_amount) + color = '#ff4040'; + amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml'; + if (rowdata.y_form == 0) // Liquid + amount = dataAdapter.formatNumber(value, 'f0') + ' pk'; + else if (rowdata.y_form == 1 || rowdata.y_form == 6) // Dry + amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; + return '' + amount + ''; + } else { + return ''; + } + } + } + ] + }); + }; + + // inline mash editor + var editMash = function(data) { + var mashSource = { + localdata: data.mashs, + datafields: [ + { name: 'step_name', type: 'string' }, + { name: 'step_type', type: 'int' }, + { name: 'step_volume', type: 'float' }, + { name: 'step_infuse_amount', type: 'float' }, + { name: 'step_infuse_temp', type: 'float' }, + { name: 'step_temp', type: 'float' }, + { name: 'step_time', type: 'float' }, + { name: 'step_wg_ratio', type: 'float' }, + { name: 'ramp_time', type: 'float' }, + { name: 'end_temp', type: 'float' }, + { name: 'step_ph', type: 'float' }, + { name: 'step_sg', type: 'float' } + ], + }, + mashAdapter = new $.jqx.dataAdapter(mashSource); + + $('#mashGrid').jqxGrid({ + width: 1240, + height: 400, + source: mashAdapter, + theme: theme, + selectionmode: 'singlerow', + editable: false, + ready: function() { + /* Calculate the whole recipe */ + console.log('ready mashs, start calculations'); + /* calcFermentables() must be first and is done by the grid load. Here it is too late. */ + calcMash(); + calcWater(); + calcIBUs(); + whirlpoolHops(); + calcMiscs(); + calcViability(); + calcYeast(); + kookTijd(); + calcFermentation(); + calcCarbonation(); + $('#FLog').jqxButton({ disabled: (dataRecord.log_fermentation) ? false : true}); + $('#ILog').jqxButton({ disabled: (dataRecord.log_ispindel) ? false : true}); + $('#CLog').jqxButton({ disabled: (dataRecord.log_co2pressure) ? false : true}); + console.log('calculations ready'); + $('#jqxLoader').jqxLoader('close'); + $('#jqxTabs').jqxTabs('first'); + }, + columns: [ + { text: 'Stap naam', datafield: 'step_name' }, + { text: 'Stap type', datafield: 'step_type', width: 150, + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + MashStepTypeData[value].nl + ''; + } + }, + { text: 'Start °C', datafield: 'step_temp', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, + { text: 'Eind °C', datafield: 'end_temp', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, + { text: 'Rust min.', datafield: 'step_time', width: 80, align: 'right', cellsalign: 'right' }, + { text: 'Stap min.', datafield: 'ramp_time', width: 80, align: 'right', cellsalign: 'right' }, + { text: 'Inf/dec L.', datafield: 'step_infuse_amount', width: 80, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + if (rowdata.step_type == 1) + return ''; + var color = '#ffffff'; + var mvol = mashkg * MaltVolume; + if ((rowdata.step_wg_ratio * mashkg + mvol) > dataRecord.eq_tun_volume) + color = '#ff4040'; + return '' + dataAdapter.formatNumber(value, 'f1') + ''; + } + }, + { text: 'Inf/dec °C', datafield: 'step_infuse_temp', width: 90, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + if (rowdata.step_type == 1) + return ''; + return '' + dataAdapter.formatNumber(value, 'f2') + ''; + } + }, + { text: 'L/Kg.', datafield: 'step_wg_ratio', width: 80, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + var color = '#ffffff'; + if (value < 2.0 || value > 6.0) + color = '#ff4040'; + return '' + dataAdapter.formatNumber(value, 'f2') + ''; + } + }, + { text: 'pH', datafield: 'step_ph', width: 70, align: 'right', cellsalign: 'right', cellsformat: 'f2' }, + { text: 'SG', datafield: 'step_sg', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'f3' } + ] + }); + }; + + /* + * Remove the top menu so that we MUST use the button to leave the editor. + */ + $('#jqxMenu').jqxMenu('destroy'); + console.log('record:' + my_record + ' return:' + my_return + ' theme:' + theme); + $('#jqxLoader').jqxLoader({ width: 250, height: 150, isModal: true, text: 'Laden product ...', theme: theme }); + $('#jqxLoader').jqxLoader('open'); + + /* Moved to before all functions */ + dataAdapter.dataBind(); + + /* + * Generic functions + */ + function kookTijd() { + if (dataRecord.boil_time) { + $('#brew_pmpt_koken').html('Koken ' + dataRecord.boil_time + ' minuten'); + } else { + $('#brew_pmpt_koken').html('Koken "no-boil"'); + } + } + + function infusionVol(step_infused, step_mashkg, infuse_temp, step_temp, last_temp) { + var a = last_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + var b = step_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + var vol = Round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)), 2); + return vol; + } + + function decoctionVol(step_volume, step_temp, prev_temp) { + var a = (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp); + var b = SpecificHeatWater * (99 - step_temp); + var vol = 0; + if (b > 0) + vol = Round(a / b, 6); + return vol; + } + + function calcViability() { + var vpm = 1.00; + var max = 100; + var rowscount = dataRecord.yeasts.length; + if (rowscount) { + for (i = 0; i < rowscount; i++) { + row = dataRecord.yeasts[i]; + if (row.y_use == 0) { + if (row.y_form == 0) { // Liquid + vpm = 0.80; + max = 97; + if (row.y_laboratory == 'White Labs') { // PurePitch + vpm = 0.95; + max = 100; + } + } else if (row.y_form == 1) { // dry yeast + vpm = 0.998; + max = 100; + } else if (row.y_form == 6) { // Dried kveik + vpm = 0.92; + max = 100; + } else { // Slant, Culture, Frozen, Bottle + vpm = 0.99; + max = 97; + } + } + } + } + var base = max; + var days = 0; + + if (parseFloat($('#yeast_prod_date').val()) > 2000) { + console.log('calculate viability'); + var d = new Date(); + var date2 = $('#yeast_prod_date').val(); + date2 = date2.split('-'); + // Now we convert the array to a Date object + var date1 = new Date(d.getFullYear(), d.getMonth(), d.getDate()); + date2 = new Date(date2[0], date2[1] - 1, date2[2]); + var diff = parseInt(date1.getTime()) - parseInt(date2.getTime()); + days = Math.floor(diff/1000/60/60/24); + + var degrade = 1 - ((1 - vpm) / 30.41); // viability degradation per day. + for (i = 0; i < days; i++) { + base = base * degrade; + } + if (base > max) { + base = max; + } + base = Math.round(base); + } + console.log('age:' + days + ' max:' + max + ' vpm:' + vpm + ' base:' + base); + + if (dataRecord.starter_viability != base) { + dataRecord.starter_viability = base; + $('#starter_viability').val(dataRecord.starter_viability); + } + } + + function calcSupplies() { + if (dataRecord.inventory_reduced > 6) { + $('#ok_pmpt').hide(); + return; + } + if (ok_fermentables && ok_hops && ok_miscs && ok_yeasts && ok_waters) + $('#ok_supplies').html(""); + else + $('#ok_supplies').html(""); + } + + /* + * All calculations that depend on changes in the fermentables, + * volumes and equipments. + */ + function calcFermentables() { + + var sugarsf = 0, // fermentable sugars mash + boil + sugarsm = 0, // fermentable sugars in mash + vol = 0, // Volume sugars after boil + addedS = 0, // Added sugars after boil + addedmass = 0, // Added mass after boil + mvol = 0, // mash volume + infuse = 0, // mash infuse volume + colort = 0, // Colors srm * vol totals + colorh = 0, // Colors ebc * vol * kt + colorn = 0, // Colors ebc * pt * pct + my_100 = false, + mashtime = 0, // Total mash time + mashtemp = 0, // Average mash temperature + bv = 0.925, // Bierverlies rendement + sr = 0.95, // Mash en spoel rendement + lintner = 0, // Total recipe lintner + i, row, rows, org, timem, aboil_volume, spoelw, ogx, topw, s = 0, d, v, x, + sug, alc, pt, cw, color, scolor, fig; + + /* Init global variables */ + psugar = 0; + pcara = 0; + mashkg = 0; + ok_fermentables = 1; // All is in stock. + ok_yeasts = 1; + + if (dataRecord.mashs.length) { + for (i = 0; i < dataRecord.mashs.length; i++) { + row = dataRecord.mashs[i]; + if (parseFloat(row.step_type) == 0) // Infusion + mvol += parseFloat(row.step_infuse_amount); + if (row.step_temp <= 75 && row.step_temp >= 60) { // Ignore mashout + timem = row.step_time; + if (i > 0) + timem += row.ramp_time; + mashtime += timem; + mashtemp += timem * row.step_temp; + } + } + infuse = mvol; + mashtemp = Round(mashtemp / mashtime, 2); + } else { + console.log("calcFermentables() no mash steps"); + } + + if (! dataRecord.fermentables.length) { + console.log("calcFermentables() no fermentables"); + return; // grid not yet loaded. + } + + for (i = 0; i < dataRecord.fermentables.length; i++) { + row = dataRecord.fermentables[i]; + if (row.f_adjust_to_total_100) + my_100 = true; + if (row.f_type == 1 && row.f_added < 4) // Sugar + psugar += row.f_percentage; + if (row.f_graintype == 2 && row.f_added < 4) // Crystal + pcara += row.f_percentage; + d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); + if (row.f_added == 0) { // Mash + if (mvol > 0) { // Only if mash already known. + mvol += row.f_amount * row.f_moisture / 100; + s += d; + } + d = parseFloat(dataRecord.efficiency) / 100 * d; + sugarsm += d; + mashkg += parseFloat(row.f_amount); + } + if (row.f_added == 0 || row.f_added == 1) // Mash or Boil + sugarsf += d; + if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering + x = (row.f_yield / 100) * (1 - row.f_moisture / 100); + addedS += row.f_amount * x; + addedmass += row.f_amount; + vol += (x * sugardensity + (1 - x) * 1) * row.f_amount; + } + if (row.f_added < 4) { + colort += row.f_amount * ebc_to_srm(row.f_color); + colorh += row.f_amount * row.f_color * get_kt(row.f_color); + colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort. + } + if (fermentableInit) { + if (row.f_added == 4) { + $('#bottle_priming_total').val(row.f_amount * 1000); // Prevent clearing + $('#bottle_priming_sugar').val(row.f_name); + } + if (row.f_added == 5) { + $('#keg_priming_total').val(row.f_amount * 1000); + $('#keg_priming_sugar').val(row.f_name); + } + } + // Check supplies. + if ((((dataRecord.inventory_reduced <= 2) && (row.f_added <= 1)) || // Mash or boil + ((dataRecord.inventory_reduced <= 3) && (row.f_added == 2)) || // Primary + ((dataRecord.inventory_reduced <= 5) && (row.f_added == 3)) || // Secondary or Tertiary + ((dataRecord.inventory_reduced <= 6) && (row.f_added == 4)) || // Bottle + ((dataRecord.inventory_reduced <= 6) && (row.f_added == 5))) && row.f_inventory < row.f_amount) { + ok_fermentables = 0; + } + if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50 + lintner += row.f_diastatic_power * row.f_amount; + } + } + fermentableInit = 0; + $('#ferm_lintner').val(Math.round(parseFloat(lintner / mashkg))); + $('#mash_kg').val(mashkg); + console.log('calcFermentables() supplies:' + ok_fermentables + ' moutsuiker:' + Round(sugarsm, 3) + '/' + Round(sugarsf, 3)); + to_100 = my_100; + + if (mvol > 0) { + v = s / sugardensity + mvol; + s = 1000 * s / (v * 10); //deg. Plato + est_mash_sg = Round(plato_to_sg(s), 5); + $('#est_mash_sg').val(est_mash_sg); + } + + // Estimate total recipe OG. + dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size)); + $('#est_og').val(dataRecord.est_og); + $('#est_og2').val(dataRecord.est_og); + org = dataRecord.est_og; + + // Estimate SG in kettle after boil + aboil_sg = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size)); + $('#est_og3').val(aboil_sg); + + // Estimate SG in kettle before boil + preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size)); + $('#est_pre_sg').val(preboil_sg); + + // Recalculate volumes. + aboil_volume = parseFloat(dataRecord.batch_size); + if (dataRecord.brew_aboil_volume > 0) + aboil_volume = dataRecord.brew_aboil_volume / 1.04; // volume @ 20 degrees + if (dataRecord.brew_fermenter_tcloss == 0) { + dataRecord.brew_fermenter_tcloss = dataRecord.eq_trub_chiller_loss; + $('#brew_fermenter_tcloss').val(dataRecord.brew_fermenter_tcloss); + } + dataRecord.brew_fermenter_volume = aboil_volume - dataRecord.brew_fermenter_tcloss + dataRecord.brew_fermenter_extrawater; + $('#brew_fermenter_volume').val(dataRecord.brew_fermenter_volume); + // Calculate SG in fermenter + ogx = dataRecord.brew_aboil_sg; + if (ogx < 1.002) + ogx = aboil_sg; + topw = dataRecord.brew_fermenter_extrawater; + + if (dataRecord.brew_fermenter_volume > 0) { + sug = sg_to_plato(ogx) * dataRecord.brew_fermenter_volume * ogx / 100; //kg of sugar in + sug += addedS; //kg + + if ((dataRecord.brew_fermenter_volume * ogx + addedmass) > 0) { + pt = 100 * sug / (dataRecord.brew_fermenter_volume * ogx + addedmass + topw); + dataRecord.og = dataRecord.brew_fermenter_sg = Round(plato_to_sg(pt), 4); + $('#brew_fermenter_sg').val(dataRecord.brew_fermenter_sg); + // color + if (dataRecord.color_method == 4) { + dataRecord.brew_fermenter_color = Math.round(((pt / 8.6) * colorn) + (dataRecord.boil_time / 60)); + } else if (dataRecord.color_method == 3) { + dataRecord.brew_fermenter_color = Math.round((4.46 * bv * sr) / (aboil_volume + topw) * colorh); + } else { + cw = colort / (aboil_volume + topw) * 8.34436; + dataRecord.brew_fermenter_color = kw_to_ebc(dataRecord.color_method, cw); + } + $('#brew_fermenter_color').val(dataRecord.brew_fermenter_color); + scolor = ebc_to_color(dataRecord.brew_fermenter_color); + $('#bcolorf').show(); + document.getElementById('bcolorf').style.background = scolor; + } + } else { + // Negative volume + dataRecord.brew_fermenter_sg = dataRecord.brew_fermenter_color = 0; + $('#brew_fermenter_sg').val(0); + $('#brew_fermenter_color').val(0); + $('#bcolorf').hide(); + } + + // Color of the wort + if (dataRecord.color_method == 4) { + color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60)); + } else if (dataRecord.color_method == 3) { // Hans Halberstadt + color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh); + } else { + cw = colort / parseFloat(dataRecord.batch_size) * 8.34436; + color = kw_to_ebc(dataRecord.color_method, cw); + } + dataRecord.est_color = color; + $('#est_color').val(color); + $('#est_color2').val(color); + scolor = ebc_to_color(color); + document.getElementById('bcolor').style.background = scolor; + document.getElementById('bcolor2').style.background = scolor; + + // Progress bars + pmalts = mashkg / dataRecord.eq_mash_max * 100; + $('#perc_malts').jqxProgressBar('val', pmalts); + $('#perc_sugars').jqxProgressBar('val', psugar); + $('#perc_cara').jqxProgressBar('val', pcara); + calcStage(); + + // Calculate estimated svg. + svg = 0; // default. + initcells = 0; + for (i = 0; i < dataRecord.yeasts.length; i++) { + row = dataRecord.yeasts[i]; + if (row.y_use == 0) { // Primary + if (parseFloat(row.y_attenuation) > svg) + svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts. + if (row.y_form == 0) + initcells += (parseFloat(row.y_cells) / 1000000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100); + else + initcells += (parseFloat(row.y_cells) / 1000000) * parseFloat(row.y_amount) * (dataRecord.starter_viability / 100); + } + // TODO: brett in secondary ?? + if ((((dataRecord.inventory_reduced <= 3) && (row.y_use == 0)) || // Primary + ((dataRecord.inventory_reduced <= 4) && (row.y_use == 1)) || // Secondary + ((dataRecord.inventory_reduced <= 5) && (row.y_use == 2)) || // Tertiary + ((dataRecord.inventory_reduced <= 6) && (row.y_use == 3))) && // Bottle + (row.y_inventory < row.y_amount)) { + ok_yeasts = 0; + } + } + calcSupplies(); + if (svg == 0) + svg = 77; + if ((mashkg > 0) && (infuse > 0) && (mashtime > 0) && (mashtemp > 0)) { + dataRecord.est_fg = estimate_fg(psugar, pcara, infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og); + } else { + dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og); + } + $('#est_fg').val(dataRecord.est_fg); + $('#est_fg2').val(dataRecord.est_fg); + $('#est_fg3').val(dataRecord.est_fg); + fig = dataRecord.est_fg; + + dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg); + $('#est_abv').val(dataRecord.est_abv); + $('#est_abv2').val(dataRecord.est_abv); + + // Calculate the final svg if available use the real value. + if ((dataRecord.stage >= 6) && (dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { + svg = calc_svg(dataRecord.brew_fermenter_sg, dataRecord.fg); + org = dataRecord.brew_fermenter_sg; + fig = dataRecord.fg; + } + + $('#yeast_cells').val(initcells); + $('#need_cells').val(getNeededYeastCells()); + + // Calculate the calories in kcal/l (from brouwhulp) + alc = 1881.22 * fig * (org - fig) / (1.775 - org); + sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004); + $('#kcal').val(Math.round((alc + sug) / (12 * 0.0295735296))); + }; + + function calcMash() { + + var h, m, infused = 0, mashtime = 0, mashvol = 0, vol, i, j, n, a, b, row, temp; + var lasttemp = 18.0; + var graintemp = 18.0; + var tuntemp = 18.0; + + if (dataRecord.mashs.length && (mashkg > 0)) { + console.log('calcMash()'); + for (i = 0; i < dataRecord.mashs.length; i++) { + row = dataRecord.mashs[i]; + if (row.step_type == 0) { // Infusion + if (i == 0) { + // First mash step, temperature from the mashtun and malt. + n = 20; // tun is preheated. + tuntemp = row.step_temp; + for (j = 0; j < n; j++) { + a = mashkg * graintemp * SpecificHeatMalt + dataRecord.eq_tun_weight * tuntemp * dataRecord.eq_tun_specific_heat; + b = row.step_temp * (dataRecord.eq_tun_weight * dataRecord.eq_tun_specific_heat + row.step_infuse_amount * SpecificHeatWater + mashkg * SpecificHeatMalt) - SlakingHeat * mashkg; + if (row.step_infuse_amount > 0) { + temp = (b - a) / (row.step_infuse_amount * SpecificHeatWater); + } else { + temp = 99; + } + tuntemp += (temp - tuntemp) / 2; + row.step_infuse_temp = Round(temp, 6); + } + //console.log('init infuse temp: ' + row.step_infuse_temp); + } else { + // Calculate amount of infusion water. + row.step_infuse_amount = infusionVol(infused, mashkg, row.step_infuse_temp, row.step_temp, lasttemp); + //console.log('vol: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); + } + infused += parseFloat(row.step_infuse_amount); + } else if (row.step_type == 1) { // Temperature + if (i > 0) + row.step_infuse_amount = 0; + row.step_infuse_temp = 0; + } else if (row.step_type == 2) { // Decoction + row.step_infuse_amount = decoctionVol(infused, row.step_temp, lasttemp); + row.step_infuse_temp = 99; + } + row.step_volume = infused; + //console.log(i + ' type: ' + row.step_type + ' volume: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); + lasttemp = row.step_temp; + mashtime += row.step_time + row.ramp_time; + row.step_wg_ratio = Round(infused / mashkg, 6); + $('#mashGrid').jqxGrid('updaterow', i, row); + } + } + if ((dataRecord.w1_amount + dataRecord.w2_amount) == 0) { + dataRecord.w1_amount = infused; + $('#w1_amount').val(infused); + console.log("calcMash() fixed water 1 to " + infused); + } + mashvol = Round(mashkg * MaltVolume + infused, 6); + $('#est_mashvol').val(mashvol); + h = Math.floor(mashtime / 60); + m = Math.floor(mashtime - (h * 60)); + if (h < 10) + h = '0' + h; + if (m < 10) + m = '0' + m; + $('#est_mashtime').val(h + ':' + m); + // Estimated needed sparge water corrected for the temperature. + spoelw = Round((dataRecord.boil_size - infused + (mashkg * my_grain_absorbtion) + dataRecord.eq_lauter_deadspace) * 1.03, 6); + $('#brew_sparge_est').val(spoelw); + } + + function getNeededYeastCells() { + + var plato, volume, sg = dataRecord.brew_fermenter_sg; + if (sg <= 1.0001 && dataRecord.fg > 1.000) + sg = dataRecord.fg; + else if (sg <= 1.0001) + sg = dataRecord.est_og; + plato = sg_to_plato(sg); + + volume = dataRecord.brew_fermenter_volume; + if (volume <= 0) + volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; + + return dataRecord.yeast_pitchrate * volume * plato; + } + + function hopFlavourContribution(bt, vol, use, amount) { + var result; + + if (use == 4 || use == 5) // Whirlpool or Dry-hop + return 0; + if (use == 1) { // First wort + result = 0.15; // assume 15% flavourcontribution for fwh + } else if (bt > 50) { + result = 0.10; // assume 10% flavourcontribution as a minimum + } else { + result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) / 6, 2)); + if (result < 0.10) + result = 0.10; // assume 10% flavourcontribution as a minimum + } + return (result * amount * 1000) / vol; + } + + function hopAromaContribution(bt, vol, use, amount) { + var result = 0; + + if (use == 5) { // Dry hop + result = 1.33; + } else if (use == 4) { // Whirlpool + if (bt > 30) + bt = 30; // Max 30 minutes + result = 0.62 * bt / 30; + } else if (bt > 20) { + result = 0; + } else if (bt > 7.5) { + result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) / 4, 2)); + } else if (use == 2) { // Boil + result = 1; + } else if (use == 3) { // Aroma + result = 1.2; + } + return (result * amount * 1000) / vol; + } + + function calcIBUs() { + var total_ibus = 0, ferm_ibus = 0, rows = {}, i, row; + hop_aroma = hop_flavour = 0; + if (!(rows = $('#hopGrid').jqxGrid('getrows'))) { + return; + } + ok_hops = 1; + for (i = 0; i < rows.length; i++) { + row = rows[i]; + total_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, parseFloat(dataRecord.batch_size), + parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method, + dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); + ferm_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, + parseFloat(dataRecord.brew_fermenter_volume) + parseFloat(dataRecord.brew_fermenter_tcloss), + parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method, + dataRecord.brew_whirlpool9, dataRecord.brew_whirlpool7, dataRecord.brew_whirlpool6); + hop_flavour += hopFlavourContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), row.h_useat, parseFloat(row.h_amount)); + hop_aroma += hopAromaContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size), row.h_useat, parseFloat(row.h_amount)); + if ((((dataRecord.inventory_reduced <= 2) && (row.h_useat <= 4)) || // Mash, FW, Boil, Aroma, Whirlpool + ((dataRecord.inventory_reduced <= 6) && (row.h_useat == 5))) && // Dry-hop + (row.h_inventory < row.h_amount)) + ok_hops = 0; + } + total_ibus = Round(total_ibus, 1); + ferm_ibus = Round(ferm_ibus, 1); + hop_flavour = Round(hop_flavour * 100 / 5, 1); + hop_aroma = Round(hop_aroma * 100 / 6, 1); + if (hop_flavour > 100) + hop_flavour = 100; + if (hop_aroma > 100) + hop_aroma = 100; + console.log('calcIBUs(): ' + total_ibus + ' flavour: ' + hop_flavour + ' aroma: ' + hop_aroma + + ' fermenter:' + ferm_ibus + ' supplies:' + ok_hops); + dataRecord.est_ibu = total_ibus; + $('#est_ibu').val(total_ibus); + $('#est_ibu2').val(total_ibus); + $('#hop_flavour').jqxProgressBar('val', hop_flavour); + $('#hop_aroma').jqxProgressBar('val', hop_aroma); + $('#brew_fermenter_ibu').val(ferm_ibus); + calcStage(); + calcSupplies(); + }; + + /* + * http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ + * + * stype: 0=stirred, 1=shaken, 2=simple + * totcells: initial cells + * egrams: gram extract + */ + function getGrowthRate(stype, totcells, egrams) { + + /* Cells per grams extract (B/g) */ + var cpe = totcells / egrams; + + if (cpe > 3.5) + return 0; // no growth + if (stype == 2) + return 0.4; // simple starter + if (stype == 1) + return 0.62; // shaken starter + if (cpe <= 1.4) // stirred starter + return 1.4; + return 2.33 - (.67 * cpe); + }; + + function calcStep(svol, stype, start) { + + var gperpoint = 2.72715, //number of grams of extract per point of starter gravity per liter + prate = start / svol * 1000, + irate = Round(prate, 1), + egrams = (dataRecord.starter_sg - 1) * svol * gperpoint, + grate = getGrowthRate(stype, start, egrams), + ncells = Round(egrams * grate, 1), + totcells = parseFloat(ncells) + start; + + return { + svol: svol, + irate: irate, + prate: Round(prate, 1), + ncells: ncells, + totcells: totcells, + growf: Round(ncells / start, 2) + }; + } + + function killstep2() { + + dataRecord.prop2_volume = 0; + $('#prop2_volume').val(0); + $('#prop2_tcells').val(0); + $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').hide(); + $('#r2_pmpt').show(); + } + + function killstep3() { + + dataRecord.prop3_volume = 0; + $('#prop3_volume').val(0); + $('#prop3_tcells').val(0); + $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').hide(); + $('#r3_pmpt').show(); + } + + function killstep4() { + + dataRecord.prop4_volume = 0; + $('#prop4_volume').val(0); + $('#prop4_tcells').val(0); + $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').hide(); + $('#r4_pmpt').show(); + } + + /* + * Calculate all starter steps. + * stype: final starter type: 0 = stirred, 1 = shaked, 2 = simple. + * start: initial cells in billions + * needed: needed cells in billions + * + * result: all values updated. + */ + function calcSteps(stype, start, needed) { + + var uvols = [20, 40, 60, 80, 100, 150, 200, 250, 375, 500, 625, 750, 875, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000], + mvols = uvols.length, svol = 0, lasti = 0, result = {}, i; + + /* + * If no values are set, auto calculate the starter. + */ + if ((parseFloat($('#prop1_volume').jqxNumberInput('decimal')) + parseFloat($('#prop2_volume').jqxNumberInput('decimal')) + + parseFloat($('#prop3_volume').jqxNumberInput('decimal')) + parseFloat($('#prop4_volume').jqxNumberInput('decimal'))) == 0) { + // clear by default + for (i = 1; i < 5; i++) { + $('#prop' + i + '_type,#prop' + i + '_volume,#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells,#prop' + i + '_growf').hide(); + $('#r' + i + '_pmpt').show(); + $('#prop' + i + '_type').val(stype); + $('#prop' + i + '_volume').val(0); + } + if (start > needed) { + return; // no starter needed + } + $('#prop1_type,#prop1_volume,#prop1_irate,#prop1_ncells,#prop1_tcells,#prop1_growf').show(); + $('#r1_pmpt').hide(); + for (i = lasti; i <= mvols; i++) { + lasti = i; + svol = uvols[lasti]; + result = calcStep(svol, stype, start); + if (result.irate < 25) { + // inocculation rate too low, backup one step and break out. + lasti = i - 1; + svol = uvols[lasti]; + result = calcStep(svol, stype, start); + break; + } + if (result.totcells > needed || i == mvols) { // hit the target or loops done + break; + } + } + $('#prop1_volume').val(result.svol / 1000); // to liters + $('#prop1_irate').val(result.prate); + $('#prop1_ncells').val(result.ncells); + $('#prop1_tcells').val(result.totcells); + $('#prop1_growf').val(result.growf); + if (result.totcells > needed) + return; // hit the target + + // second stage + $('#r2_pmpt').hide(); + $('#prop2_type').val(stype); + $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').show(); + for (i = lasti; i <= mvols; i++) { + lasti = i; + svol = uvols[lasti]; + result = calcStep(svol, stype, $('#prop1_tcells').val()); + if (result.irate < 25) { + lasti = i - 1; + svol = uvols[lasti]; + result = calcStep(svol, stype, $('#prop1_tcells').val()); + break; + } + if (result.totcells > needed || i == mvols) { // hit the target or loops done + break; + } + } + $('#prop2_volume').val(result.svol / 1000); // to liters + $('#prop2_irate').val(result.prate); + $('#prop2_ncells').val(result.ncells); + $('#prop2_tcells').val(result.totcells); + $('#prop2_growf').val(result.growf); + if (result.totcells > needed) + return; // hit the target + + // third stage + $('#r3_pmpt').hide(); + $('#prop3_type').val(stype); + $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').show(); + for (i = lasti; i <= mvols; i++) { + lasti = i; + svol = uvols[lasti]; + result = calcStep(svol, stype, $('#prop2_tcells').val()); + if (result.irate < 25) { + lasti = i - 1; + svol = uvols[lasti]; + result = calcStep(svol, stype, $('#prop2_tcells').val()); + break; + } + if (result.totcells > needed || i == mvols) { // hit the target or loops done + break; + } + } + $('#prop3_volume').val(result.svol / 1000); // to liters + $('#prop3_irate').val(result.prate); + $('#prop3_ncells').val(result.ncells); + $('#prop3_tcells').val(result.totcells); + $('#prop3_growf').val(result.growf); + if (result.totcells > needed) + return; // hit the target + + // fourth stage + $('#r4_pmpt').hide(); + $('#prop4_type').val(stype); + $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').show(); + for (i = lasti; i <= mvols; i++) { + lasti = i; + svol = uvols[lasti]; + result = calcStep(svol, stype, $('#prop3_tcells').val()); + if (result.totcells > needed || i == mvols) { // hit the target or loops done + $('#prop4_volume').val(result.svol / 1000); // to liters + $('#prop4_irate').val(result.prate); + $('#prop4_ncells').val(result.ncells); + $('#prop4_tcells').val(result.totcells); + $('#prop4_growf').val(result.growf); + return; + } + } + } else { + // recalculate + if (dataRecord.prop1_volume > 0) { + $('#r1_pmpt').hide(); + $('#prop1_type,#prop1_volume,#prop1_irate,#prop1_ncells,#prop1_tcells,#prop1_growf').show(); + result = calcStep($('#prop1_volume').val() * 1000, dataRecord.prop1_type, start); + $('#prop1_irate').val(result.prate); + $('#prop1_ncells').val(result.ncells); + $('#prop1_tcells').val(result.totcells); + $('#prop1_growf').val(result.growf); + if (result.totcells > needed) { + killstep2(); + killstep3(); + killstep4(); + } else if (dataRecord.prop2_volume == 0) { + dataRecord.prop2_volume = dataRecord.prop1_volume; /* Extra step needed, start with the same size */ + dataRecord.prop2_type = dataRecord.prop1_type; + $('#prop2_volume').val(dataRecord.prop2_volume); + $('#prop2_type').val(dataRecord.prop2_type); + } + } + if (dataRecord.prop2_volume > 0) { + $('#r2_pmpt').hide(); + $('#prop2_type,#prop2_volume,#prop2_irate,#prop2_ncells,#prop2_tcells,#prop2_growf').show(); + result = calcStep($('#prop2_volume').val() * 1000, dataRecord.prop2_type, $('#prop1_tcells').val()); + $('#prop2_irate').val(result.prate); + $('#prop2_ncells').val(result.ncells); + $('#prop2_tcells').val(result.totcells); + $('#prop2_growf').val(result.growf); + if (result.totcells > needed) { + killstep3(); + killstep4(); + } else if (dataRecord.prop3_volume == 0) { + dataRecord.prop3_volume = dataRecord.prop2_volume; /* Extra step needed, start with the same size */ + dataRecord.prop3_type = dataRecord.prop2_type; + $('#prop3_volume').val(dataRecord.prop3_volume); + $('#prop3_type').val(dataRecord.prop3_type); + } + } + if (dataRecord.prop3_volume > 0) { + $('#r3_pmpt').hide(); + $('#prop3_type,#prop3_volume,#prop3_irate,#prop3_ncells,#prop3_tcells,#prop3_growf').show(); + result = calcStep($('#prop3_volume').val() * 1000, dataRecord.prop3_type, $('#prop2_tcells').val()); + $('#prop3_irate').val(result.prate); + $('#prop3_ncells').val(result.ncells); + $('#prop3_tcells').val(result.totcells); + $('#prop3_growf').val(result.growf); + if (result.totcells > needed) { + killstep4(); + } else if (dataRecord.prop4_volume == 0) { + dataRecord.prop4_volume = dataRecord.prop3_volume; /* Extra step needed, start with the same size */ + dataRecord.prop4_type = dataRecord.prop3_type; + $('#prop4_volume').val(dataRecord.prop4_volume); + $('#prop4_type').val(dataRecord.prop4_type); + } + } + if (dataRecord.prop4_volume > 0) { + $('#r4_pmpt').hide(); + $('#prop4_type,#prop4_volume,#prop4_irate,#prop4_ncells,#prop4_tcells,#prop4_growf').show(); + result = calcStep($('#prop4_volume').val() * 1000, dataRecord.prop4_type, $('#prop3_tcells').val()); + $('#prop4_irate').val(result.prate); + $('#prop4_ncells').val(result.ncells); + $('#prop4_tcells').val(result.totcells); + $('#prop4_growf').val(result.growf); + } + } + } + + function calcYeast() { + + // Calculate needed cells. + var plato, volume, rows, rowscount, row, i, needed, use_cells, sg = dataRecord.brew_fermenter_sg; + + if (sg <= 1.0001 && dataRecord.fg > 1.000) + sg = dataRecord.fg; + else if (sg <= 1.0001) + sg = dataRecord.est_og; + plato = sg_to_plato(sg); + + volume = dataRecord.brew_fermenter_volume; + if (volume > 0) { + if (dataRecord.brew_fermenter_extrawater > 0) + volume += dataRecord.brew_fermenter_extrawater; + } else { + volume = dataRecord.batch_size - dataRecord.eq_trub_chiller_loss; + } + + // Also in calcFermentables() + $('#yeast_cells').val(initcells); + + if (!(rows = $('#yeastGrid').jqxGrid('getrows'))) { + return; // grid not yet loaded. + } + rowscount = dataRecord.yeasts.length; + if (rowscount == 0) + return; // no yeast in recipe + + $('.primary_dry').hide(); + $('.primary_liquid').hide(); + + var maybe_starter = 0; + var pitchrate = 0.75; // Yeast pitch rate default + for (i = 0; i < rowscount; i++) { + row = dataRecord.yeasts[i]; + if (row.y_use == 0) { // primary + if (row.y_form == 1) { + // Dry yeast + $('.primary_dry').show(); + console.log('dry yeast: ' + row.y_gr_hl_lo + '@' + row.y_sg_lo + ' ' + row.y_gr_hl_hi + '@' + row.y_sg_hi); + // Build the formule with the yeast parameters. + // Based on https://www.lallemandbrewing.com/en/canada/brewers-corner/brewing-tools/pitching-rate-calculator/ + var og = row.y_sg_lo; + var f1 = row.y_gr_hl_lo / 100; + var f2 = Round(f1 / 5, 6); + // After a lot of try and error, study, the best thing to increase the pitch amount is actually + // use this simple formula by Lallemand. This is about the same as sugar weight increment in the wort. + var multiplier = (sg <= og) ? f1 : (f1 + f2 * (sg - og) / 0.008); + console.log('sg: ' + sg + ' og: ' + og + ' f1: ' + f1 + ' f2: ' + f2 + ' multiplier: ' + multiplier); + // dataRecord.starter_viability + var yeast_grams = Round(volume * multiplier * (100 / dataRecord.starter_viability), 2); + $('#yeast_grams').val(yeast_grams); + var yeast_gr_hl = Round(yeast_grams / (volume * 0.01), 2); + $('#yeast_gr_hl').val(yeast_gr_hl); + //console.log('need ' + yeast_grams + ' grams, gr/hl: ' + yeast_gr_hl); + + } else { + // Liquid yeast + $('.primary_liquid').show(); + // pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/ + // and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ + if (row.y_type == 0) { // lager yeast + pitchrate = 1.5; + if (dataRecord.est_og > 1.060) + pitchrate = 2.0; + } else if (row.y_type == 6) { // Kveik + pitchrate = 0.075; + } else { + pitchrate = 0.75; + if (dataRecord.est_og > 1.060) + pitchrate = 1.0; + } + if (dataRecord.yeast_pitchrate < 0.01) { + dataRecord.yeast_pitchrate = pitchrate; + $('#yeast_pitchrate').val(pitchrate); + } + maybe_starter = 1; + } + } + } + + needed = Round(dataRecord.yeast_pitchrate * volume * plato, 1); + $('#need_cells').val(needed); + use_cells = initcells; + if (needed <= initcells) + maybe_starter = 0; + //console.log('calcYeast() pitchrate:' + dataRecord.yeast_pitchrate + ' start:' + initcells + ' needed:' + needed + ' volume:' + volume + ' maybe_starter:' + maybe_starter); + + if (maybe_starter != dataRecord.starter_enable) { + dataRecord.starter_enable = maybe_starter; + } + if (maybe_starter) + $('#propagator').show(); + else + $('#propagator').hide(); + + if (dataRecord.starter_enable) { + + calcSteps(dataRecord.starter_type, initcells, needed); + + for (i = 1; i < 5; i++) { + $('#r' + i + '_irate').html(''); + $('#r' + i + '_growf').html(''); + $('#r' + i + '_tcells').html(''); + if (parseFloat($('#prop' + i + '_volume').val()) > 0) { + if ((parseFloat($('#prop' + i + '_irate').val()) < 25) || (parseFloat($('#prop' + i + '_irate').val()) > 100)) { + $('#r' + i + '_irate').html(""); + } else { + $('#r' + i + '_irate').html(""); + } + if (parseFloat($('#prop' + i + '_growf').val()) < 1) + $('#r' + i + '_growf').html(""); + if (($('#prop' + i + '_type').val() > 0) && (parseFloat($('#prop' + i + '_growf').val()) > 3)) + $('#r' + i + '_growf').html(""); + if (parseFloat($('#prop' + i + '_tcells').val()) > needed) + $('#r' + i + '_tcells').html(""); + use_cells = parseFloat($('#prop' + i + '_tcells').val()); + } else { + $('#r' + i + '_irate').html(''); + } + } + } + $('#plato_cells').val(parseFloat(use_cells / (volume * plato))); + }; + + function whirlpoolHops() { + var row, i, time, rowscount = dataRecord.hops.length; + if (rowscount == 0) + return; + for (i = 0; i < rowscount; i++) { + row = dataRecord.hops[i]; + if (row.h_useat == 4) { + time = parseFloat(dataRecord.brew_whirlpool9) + parseFloat(dataRecord.brew_whirlpool7) + parseFloat(dataRecord.brew_whirlpool6); + dataRecord.hops[i].h_time = time; + $('#hopGrid').jqxGrid('setcellvalue', i, 'h_time', time); + } + } + }; + + function calcMiscs() { + + ok_miscs = 1; + var row, i, rowscount = dataRecord.miscs.length; + if (rowscount == 0) + return; + for (i = 0; i < rowscount; i++) { + row = dataRecord.miscs[i]; + if ((((dataRecord.inventory_reduced <= 2) && (row.m_use_use <= 2)) || // Starter, Mash, Boil + ((dataRecord.inventory_reduced <= 2) && (row.m_use_use == 6)) || // Sparge + ((dataRecord.inventory_reduced <= 3) && (row.m_use_use == 3)) || // Primary + ((dataRecord.inventory_reduced <= 5) && (row.m_use_use == 4)) || // Secondary, Teriary + ((dataRecord.inventory_reduced <= 6) && (row.m_use_use == 5))) && // Bottle + (row.m_inventory < row.m_amount)) { + ok_miscs = 0; + } + } + calcSupplies(); + }; + + function GetBUGU() { + var gu = (dataRecord.est_og - 1) * 1000; + if (gu > 0) + return dataRecord.est_ibu / gu; + else + return 0.5; + } + + function GetOptSO4Clratio() { + var BUGU = GetBUGU(); + return (1.0 / (-1.2 * BUGU + 1.4)); + } + + function setWaterAgent(name, amount, use) { + var row, i, id, found = false, miscs, rows = $('#miscGrid').jqxGrid('getrows'); + if (amount == 0) { + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.m_name == name && row.m_use_use == use) { + id = $('#miscGrid').jqxGrid('getrowid', i); + $('#miscGrid').jqxGrid('deleterow', id); + } + } + } else { + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.m_name == name && row.m_use_use == use) { + found = true; + $('#miscGrid').jqxGrid('setcellvalue', i, 'm_amount', amount / 1000); + break; + } + } + if (! found) { + miscs = new $.jqx.dataAdapter(miscInvSource, { + loadComplete: function() { + var record, i, row = {}, records = miscs.records; + for (i = 0; i < records.length; i++) { + record = records[i]; + if (record.name == name) { + row['m_name'] = record.name; + row['m_amount'] = amount / 1000; + row['m_cost'] = record.cost; + row['m_type'] = record.type; + row['m_use_use'] = use; + row['m_time'] = 0; + row['m_amount_is_weight'] = record.amount_is_weight; + row['m_inventory'] = record.inventory; + row['m_avail'] = 1; + $('#miscGrid').jqxGrid('addrow', null, row); + } + } + } + }); + miscs.dataBind(); + return; + } + } + } + + function setRangeIndicator(ion, rangeCode) { + if ((rangeCode == 'laag') || (rangeCode == 'hoog')) + $('#wr_' + ion).html("" + rangeCode + ''); + else + $('#wr_' + ion).html(""); + } + + function mix(v1, v2, c1, c2) { + if ((v1 + v2) > 0) { + return ((v1 * c1) + (v2 * c2)) / (v1 + v2); + } + return 0; + } + + function PartCO3(pH) { + var H = Math.pow(10, -pH); + return 100 * Ka1 * Ka2 / (H * H + H * Ka1 + Ka1 * Ka2); + } + + function PartHCO3(pH) { + var H = Math.pow(10, -pH); + return 100 * Ka1 * H / (H * H + H * Ka1 + Ka1 * Ka2); + } + + function Charge(pH) { + return (-2 * PartCO3(pH) - PartHCO3(pH)); + } + + //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) + function ZAlkalinity(pHZ) { + var C43 = Charge(4.3), + Cw = Charge(parseFloat($('#wg_ph').jqxNumberInput('decimal'))), + Cz = Charge(pHZ), + DeltaCNaught = -C43 + Cw, + CT = parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) / 50 / DeltaCNaught, + DeltaCZ = -Cz + Cw; + return CT * DeltaCZ; + } + + //Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH) + function ZRA(pHZ) { + + var Magn, Z, Calc = parseFloat($('#wg_calcium').jqxNumberInput('decimal')) / (MMCa / 2); + Magn = parseFloat($('#wg_magnesium').jqxNumberInput('decimal')) / (MMMg / 2); + Z = ZAlkalinity(pHZ); + return Z - (Calc / 3.5 + Magn / 7); + } + + function BufferCapacity(di_ph, acid_to_ph_57, ebc, graintype) { + C1 = 0; + if ((di_ph != 5.7) && ((acid_to_ph_57 < - 0.1) || (acid_to_ph_57 > 0.1))) { + C1 = acid_to_ph_57 / (di_ph - 5.7); + } else { + // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid. + switch (graintype) { + case 0: // Base, Special, Kilned + case 3: + case 5: C1 = 0.014 * ebc - 34.192; + break; + case 2: C1 = -0.0597 * ebc - 32.457; // Crystal + break; + case 1: C1 = 0.0107 * ebc - 54.768; // Roast + break; + case 4: C1 = -149; // Sour malt + break; + } + } + return C1; + } + + function ProtonDeficit(pHZ) { + + var i, C1, x, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal')); + // proton deficit for the grist + if (( $('#fermentableGrid').jqxGrid('getrows'))) { + for (i = 0; i < dataRecord.fermentables.length; i++) { + row = dataRecord.fermentables[i]; + if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt + C1 = BufferCapacity(row.f_di_ph, row.f_acid_to_ph_57, row.f_color, row.f_graintype); + x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH) + Result += x * row.f_amount; + } + } + } else { + error_count++; + if (error_count < 5) + console.log('ProtonDeficit(' + pHZ + ') invalid grist, return ' + Result); + } + return Result; + } + + function MashpH() { + + var n = 0, pH = 5.4, deltapH = 0.001, deltapd = 0.1, pd = ProtonDeficit(pH); + while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) { + n++; + if (pd < -deltapd) + pH -= deltapH; + else if (pd > deltapd) + pH += deltapH; + pd = ProtonDeficit(pH); + } + pH = Round(pH, 6); + //console.log('MashpH() n: ' + n + ' pH: ' + pH); + return pH; + } + + function calcWater() { + + /* Can be called during loading and building the screens */ + if (! data_loaded) { + console.log('calcWater() failsave'); + return; + } + + var liters = 0, + calcium = 0, + magnesium = 0, + sodium = 0, + total_alkalinity = 0, + chloride = 0, + sulfate = 0, + ph = 0, + RA = 0, + frac = 0, + TpH = 0, + protonDeficit = 0, + AT, /*BT,*/ + r1d, r2d, f1d, f2d, f3d, + deltapH, deltapd, pd, n, + Res; + + if (dataRecord.w1_name == '') { + return; + } + + $('#w1_hardness').val(Hardness(dataRecord.w1_calcium, dataRecord.w1_magnesium)); + $('#w1_ra').val(ResidualAlkalinity(dataRecord.w1_total_alkalinity, dataRecord.w1_calcium, dataRecord.w1_magnesium)); + + // If there is a dillute water source, mix the waters. + if ((dataRecord.w2_name != '') && (dataRecord.w2_name != 'Geen mengwater')) { + liters = dataRecord.w1_amount + dataRecord.w2_amount; + calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium); + magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium); + sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium); + chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride); + sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate); + total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity); + ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters); + $('#w2_hardness').val(Hardness(dataRecord.w2_calcium, dataRecord.w2_magnesium)); + $('#w2_ra').val(ResidualAlkalinity(dataRecord.w2_total_alkalinity, dataRecord.w2_calcium, dataRecord.w2_magnesium)); + } else { + liters = dataRecord.w1_amount; + calcium = dataRecord.w1_calcium; + magnesium = dataRecord.w1_magnesium; + sodium = dataRecord.w1_sodium; + chloride = dataRecord.w1_chloride; + sulfate = dataRecord.w1_sulfate; + total_alkalinity = dataRecord.w1_total_alkalinity; + ph = dataRecord.w1_ph; + } + var bicarbonate = Bicarbonate(total_alkalinity, ph); + + /* Save mixed water ions for later */ + var wg_calcium = calcium; + var wg_sodium = sodium; + var wg_total_alkalinity = total_alkalinity; + var wg_chloride = chloride; + var wg_sulfate = sulfate; + var wg_bicarbonate = bicarbonate; + + dataRecord.wg_amount = liters; + dataRecord.wg_ph = ph; + + $('#wg_amount').val(liters); + $('#wg_calcium').val(Round(calcium, 1)); + $('#wg_magnesium').val(Round(magnesium, 1)); + $('#wg_sodium').val(Round(sodium, 1)); + $('#wg_bicarbonate').val(Round(bicarbonate, 1)); + $('#wg_total_alkalinity').val(Round(total_alkalinity, 1)); + $('#wg_chloride').val(Round(chloride, 1)); + $('#wg_sulfate').val(Round(sulfate, 1)); + $('#wg_ph').val(Round(ph, 2)); + $('#wg_hardness').val(Round(Hardness(calcium, magnesium), 1)); + $('#wg_ra').val(Round(ResidualAlkalinity(total_alkalinity, calcium, magnesium), 1)); + + var mash_ph = Round(MashpH(), 3); + console.log('Distilled water mash pH: ' + mash_ph); + + /* Calculate Salt additions */ + if (liters > 0) { + calcium += (parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + + parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000 + + parseFloat($('#wa_caco3').jqxNumberInput('decimal')) * MMCa / MMCaCO3 * 1000) / liters; + magnesium += (parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + + parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / liters; + sodium += (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 + + parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters; + sulfate += (parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + + parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / liters; + chloride += (2 * parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + + parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + + parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / liters; + bicarbonate += (parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3 * 1000 + + parseFloat($('#wa_caco3').jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3 * 1000) / liters; + } + + if (dataRecord.wa_acid_name < 0 || dataRecord,wa_acid_name >= AcidTypeData.length) { + $('#wa_acid_name').val(0); + dataRecord.wa_acid_name = 0; + dataRecord.wa_acid_perc = AcidTypeData[0].AcidPrc; + $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); + } + if (last_acid == '') + last_acid = AcidTypeData[dataRecord.wa_acid_name].nl; + + if (parseFloat(dataRecord.wa_acid_perc) == 0) { + dataRecord.wa_acid_perc = AcidTypeData[AT].AcidPrc; + $('#wa_acid_perc').val(AcidTypeData[AT].AcidPrc); + } + + AT = dataRecord.wa_acid_name; + + /* Note that the next calculations do not correct the pH change by the added salts. + This pH change is at most 0.1 pH and is a minor difference in Acid amount. */ + + if (dataRecord.calc_acid) { + /* Auto calculate pH */ + $('.c_mashph').show(); + TpH = parseFloat(dataRecord.mash_ph); + protonDeficit = ProtonDeficit(TpH); + //console.log('calc_acid tgt: ' + TpH + ' protonDeficit: ' + protonDeficit); + if (protonDeficit > 0) { // Add acid + frac = CalcFrac(TpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); + Acid = protonDeficit / frac; + Acid *= AcidTypeData[AT].MolWt; // mg + Acidmg = Acid; + var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (parseFloat(dataRecord.wa_acid_perc) / 100)) + 1000, 2); + Acid /= RealSG; + Acid /= AcidTypeData[AT].AcidPrc / 100; + Acid = Round(Acid, 2); + console.log('Mash auto Acid final ml: ' + Acid); + $('#wa_acid').val(Acid); + setWaterAgent(AcidTypeData[AT].nl, Acid, 1); + + bicarbonate = bicarbonate - protonDeficit * frac / liters; + total_alkalinity = bicarbonate * 50 / 61; + } + ph = TpH; + dataRecord.wb_ph = ph; + $('#wb_ph').val(Round(ph, 2)); + $('#est_mash_ph').val(Round(ph, 2)); + } else { + /* Manual calculate pH */ + $('.c_mashph').hide(); + console.log('calc_acid no'); + pHa = Round(ph, 3); // Adjusted water pH + // Then calculate the new pH with added acids and malts + console.log('Mash pH: ' + pHa); + Acid = AcidTypeData[AT].AcidSG * (parseFloat(dataRecord.wa_acid_perc) / 100); // ml + Acid *= parseFloat($('#wa_acid').jqxNumberInput('decimal')); + Acid /= AcidTypeData[AT].MolWt; // mg + Acidmg = Acid; + + //find the pH where the protondeficit = protondeficit by the acid + frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); + protonDeficit = Round(Acid * frac, 3); + //console.log('protonDeficit Acid: ' + protonDeficit + ' frac: ' + frac + ' pH: ' + pHa); + + deltapH = 0.001; + deltapd = 0.1; + pd = Round(ProtonDeficit(pHa), 6); + n = 0; + while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 4000)) { + n++; + if (pd < (protonDeficit - deltapd)) + pHa -= deltapH; + else if (pd > (protonDeficit + deltapd)) + pHa += deltapH; + frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); + protonDeficit = Acid * frac; + pd = ProtonDeficit(pHa); + } + //console.log('n: ' + n + ' pd: ' + pd + ' protonDeficit: ' + protonDeficit + ' frac: ' + frac + ' pHa: ' + pHa); + bicarbonate = wg_bicarbonate - protonDeficit * frac / liters; + total_alkalinity = bicarbonate * 50 / 61; + ph = pHa; + $('#wb_ph').val(Round(ph, 2)); + $('#est_mash_ph').val(Round(ph, 2)); + } + + if ((AT == 3) && (liters > 0)) { // Sulfuric / Zwavelzuur + RA = parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + + parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 + + Acidmg / 1000 * MMSO4 / (MMSO4 + 2); + RA = 1000 * RA / liters; + sulfate = wg_sulfate + RA; // Not add to sulfate?? + } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur + RA = parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 + + parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl + + Acidmg / 1000 * MMCl / (MMCl + 1); + RA = 1000 * RA / liters; + chloride = wg_chloride + RA; + } + + var BUGU = GetBUGU(); + $('#tgt_bu').val(Round(BUGU, 2)); + // From brouwhulp. + if (BUGU < 0.32) + $('#wr_bu').html("Zeer moutig en zoet"); + else if (BUGU < 0.43) + $('#wr_bu').html("Moutig, zoet"); + else if (BUGU < 0.52) + $('#wr_bu').html("Evenwichtig"); + else if (BUGU < 0.63) + $('#wr_bu').html("Licht hoppig, bitter"); + else + $('#wr_bu').html("Extra hoppig, zeer bitter"); + + // Sulfate to Chloride ratio (Palmer). + var OptSO4Clratio = GetOptSO4Clratio(); + $('#tgt_so4_cl').val(Round(OptSO4Clratio, 1)); + if (OptSO4Clratio < 0.4) + $('#wrt_so4_cl').html("Te moutig"); + else if (OptSO4Clratio < 0.6) + $('#wrt_so4_cl').html("Zeer moutig"); + else if (OptSO4Clratio < 0.8) + $('#wrt_so4_cl').html("Moutig"); + else if (OptSO4Clratio < 1.5) + $('#wrt_so4_cl').html("Gebalanceerd"); + else if (OptSO4Clratio < 2.0) + $('#wrt_so4_cl').html("Licht bitter"); + else if (OptSO4Clratio < 4.0) + $('#wrt_so4_cl').html("Bitter"); + else if (OptSO4Clratio < 9.0) + $('#wrt_so4_cl').html("Zeer bitter"); + else + $('#wrt_so4_cl').html("Te bitter"); + if (chloride > 0) + RA = sulfate / chloride; + else + RA = 10; + $('#got_so4_cl').val(Round(RA, 1)); + Res = 'normaal'; + if (RA < (0.8 * OptSO4Clratio)) + Res = 'laag'; + else if (RA > (1.2 * OptSO4Clratio)) + Res = 'hoog'; + setRangeIndicator('so4_cl', Res); + + $('#wb_calcium').val(Round(calcium, 1)); + $('#wb_magnesium').val(Round(magnesium, 1)); + $('#wb_sodium').val(Round(sodium, 1)); + $('#wb_sulfate').val(Round(sulfate, 1)); + $('#wb_chloride').val(Round(chloride, 1)); + $('#wb_bicarbonate').val(Round(bicarbonate, 1)); + $('#wb_total_alkalinity').val(Round(total_alkalinity, 1)); + $('#wb_hardness').val(Hardness(calcium, magnesium)); + $('#wb_ra').val(ResidualAlkalinity(total_alkalinity, calcium, magnesium)); + + if (calcium < 40) { + setRangeIndicator('calcium', 'laag'); + } else if (calcium > 150) { + setRangeIndicator('calcium', 'hoog'); + } else { + setRangeIndicator('calcium', 'normaal'); + } + if (magnesium < 5) { + setRangeIndicator('magnesium', 'laag'); + } else if (magnesium > 40) { + setRangeIndicator('magnesium', 'hoog'); + } else { + setRangeIndicator('magnesium', 'normaal'); + } + if (sodium <= 150) { + setRangeIndicator('sodium', 'normaal'); + } else { + setRangeIndicator('sodium', 'hoog'); + } + // Both chloride and sulfate should be above 50 according to + // John Palmer. So the Cl/SO4 ratio calculation will work. + if (chloride <= 50) { + setRangeIndicator('chloride', 'laag'); + } else if (chloride <= 150) { + setRangeIndicator('chloride', 'normaal'); + } else { + setRangeIndicator('chloride', 'hoog'); + } + if (sulfate <= 50) { + setRangeIndicator('sulfate', 'laag'); + } else if (sulfate <= 400) { + setRangeIndicator('sulfate', 'normaal'); + } else { + setRangeIndicator('sulfate', 'hoog'); + } + // (cloride + sulfate) > 500 is too high + if ((chloride + sulfate) > 500) { + setRangeIndicator('chloride', 'hoog'); + setRangeIndicator('sulfate', 'hoog'); + } + if (ph < 5.2) { + setRangeIndicator('ph', 'laag'); + } else if (ph > 5.6) { + setRangeIndicator('ph', 'hoog'); + } else { + setRangeIndicator('ph', 'normaal'); + } + if (bicarbonate > 250) { + setRangeIndicator('bicarbonate', 'hoog'); + } else { + setRangeIndicator('bicarbonate', 'normaal'); + } + calcSparge(); + calcMiscs(); + calcSupplies(); + } + + function calcSparge() { + + /* Based on the work of ajDeLange. */ + var ws_calcium, ws_magnesium, ws_total_alkalinity, ws_sodium, ws_chloride; + var ws_sulfate, ws_ph, ws_hardness, ws_ra; + var TargetpH = dataRecord.sparge_ph; + var Source_pH = 7.0; + + // Select watersource or fallback to the first source. + if ((dataRecord.sparge_source == 1) && (dataRecord.w2_ph > 0.0)) { // Source 2 + ws_calcium = dataRecord.w2_calcium; + ws_magnesium = dataRecord.w2_magnesium; + ws_total_alkalinity = dataRecord.w2_total_alkalinity; + ws_sodium = dataRecord.w2_sodium; + ws_chloride = dataRecord.w2_chloride; + ws_sulfate = dataRecord.w2_sulfate; + Source_pH = dataRecord.w2_ph; + $('#w2_button').jqxRadioButton({ checked: true }); + } else if ((dataRecord.sparge_source == 2) && (dataRecord.w2_ph > 0.0)) { // Mixed + ws_calcium = dataRecord.wg_calcium; + ws_magnesium = dataRecord.wg_magnesium; + ws_total_alkalinity = dataRecord.wg_total_alkalinity; + ws_sodium = dataRecord.wg_sodium; + ws_chloride = dataRecord.wg_chloride; + ws_sulfate = dataRecord.wg_sulfate; + Source_pH = dataRecord.wg_ph; + $('#wg_button').jqxRadioButton({ checked: true }); + } else { + ws_calcium = dataRecord.w1_calcium; + ws_magnesium = dataRecord.w1_magnesium; + ws_total_alkalinity = dataRecord.w1_total_alkalinity; + ws_sodium = dataRecord.w1_sodium; + ws_chloride = dataRecord.w1_chloride; + ws_sulfate = dataRecord.w1_sulfate; + Source_pH = dataRecord.w1_ph; + $('#w1_button').jqxRadioButton({ checked: true }); + } + + if (dataRecord.sparge_volume > 0) { + ws_calcium += (parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + + parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000) / dataRecord.sparge_volume; + ws_magnesium += (parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + + parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / dataRecord.sparge_volume; + ws_sodium += (parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000) / dataRecord.sparge_volume; + ws_sulfate += (parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + + parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / dataRecord.sparge_volume; + ws_chloride += (2 * parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + + parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + + parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / dataRecord.sparge_volume; + } + + /* Show the spargewate with salt additions */ + $('#sw_calcium').val(Round(ws_calcium, 1)); + $('#sw_magnesium').val(Round(ws_magnesium, 1)); + $('#sw_sodium').val(Round(ws_sodium, 1)); + $('#sw_sulfate').val(Round(ws_sulfate, 1)); + $('#sw_chloride').val(Round(ws_chloride, 1)); + $('#sw_bicarbonate').val(Round(Bicarbonate(ws_total_alkalinity, Source_pH), 1)); + $('#sw_total_alkalinity').val(Round(ws_total_alkalinity, 1)); + $('#sw_ph').val(dataRecord.sparge_ph); + $('#sw_hardness').val(Hardness(ws_calcium, ws_magnesium)); + $('#sw_ra').val(ResidualAlkalinity(ws_total_alkalinity, ws_calcium, ws_magnesium)); + + AT = dataRecord.sparge_acid_type; + if (AT < 0 || AT >= AcidTypeData.length) { + AT = 0; + dataRecord.sparge_acid_type = 0; + $('#sparge_acid_type').val(AcidTypeData[0].nl); + dataRecord.sparge_acid_perc = AcidTypeData[0].AcidPrc; + $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); + } + + /* + * Auto calculate the required acid + */ + if (dataRecord.calc_acid) { + // Step 1: Compute the mole fractions of carbonic (f1) and carbonate(f3) at the source water pH + var r1 = Math.pow(10, Source_pH - 6.35); + var r2 = Math.pow(10, Source_pH - 10.33); + var d = 1 + r1 + r1 * r2; + var f1 = 1 / d; + var f3 = r1 * r2 / d; + + //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) + var r143 = Math.pow(10, 4.3 - 6.35); + var r243 = Math.pow(10, 4.3 - 10.33); + var d43 = 1 + r143 + r143 * r243; + var f143 = 1 / d43; + var f343 = r143 * r243 / d43; + + //Step 4. Solve + var Ct = ws_total_alkalinity / 50 / ((f143 - f1) + (f3 - f343)); + + //Step 5. Compute mole fractions at desired pH + var r1g = Math.pow(10, TargetpH - 6.35); + var r2g = Math.pow(10, TargetpH - 10.33); + var dg = 1 + r1g + r1g * r2g; + var f1g = 1 / dg; + var f3g = r1g * r2g / dg; + + //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L) + var Acid = Ct * ((f1g - f1) + (f3 - f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l + Acid += 0.01; // Add acid that would be required for distilled water. + + //Step 8. Get the acid data. + var fract = CalcFrac(TargetpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); + + //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. + Acid /= fract; + + //Step 10. Multiply by molecular weight of the acid + Acid *= AcidTypeData[AT].MolWt; //mg + + //Step 11. Divide by Specific Gravity and Percentage to get the final ml. + var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (dataRecord.sparge_acid_perc / 100)) + 1000, 2); + Acid = Acid / RealSG; //ml + Acid *= dataRecord.sparge_volume; //ml acid total at 100% + Acid /= AcidTypeData[AT].AcidPrc / 100; //ml acid at supplied strength + Acid = Round(Acid, 2); + dataRecord.sparge_acid_amount = Acid / 1000; + $('#sparge_acid_amount').val(Acid); + } + + // Finally calculate the estimate preboil pH + var ph = -Math.log10(((Math.pow(10, -dataRecord.wb_ph) * dataRecord.wg_amount) + (Math.pow(10, -dataRecord.sparge_ph) * dataRecord.sparge_volume)) / + (dataRecord.wg_amount + dataRecord.sparge_volume)); + $('#preboil_ph').val(ph); + } + + function calcFermentation() { + var primary_svg, secondary_svg, final_svg, ABV; + if (dataRecord.brew_fermenter_sg < 1.020) + return; + if ((dataRecord.primary_end_sg > 0.990) && (dataRecord.primary_end_sg < dataRecord.brew_fermenter_sg)) { + primary_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.primary_end_sg), 1); + $('#primary_svg').val(primary_svg); + if ((dataRecord.secondary_end_sg > 0.990) && (dataRecord.secondary_end_sg < dataRecord.brew_fermenter_sg)) { + secondary_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.secondary_end_sg), 1); + $('#secondary_svg').val(secondary_svg); + if ((dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) { + final_svg = Round(calc_svg(dataRecord.brew_fermenter_sg, dataRecord.fg), 1); + $('#final_svg').val(final_svg); + ABV = Round(abvol(dataRecord.brew_fermenter_sg, dataRecord.fg), 2); + $('#final_abv').val(ABV); + } + } + } + } + + function ResCO2(T) { + var F = T * 1.8 + 32; + return Round(3.0378 - 0.050062 * F + 0.00026555 * F * F, 6); + } + + function CarbCO2toS(CO2, T, SFactor) { + //var sugar = SFactor * (CO2 - ResCO2(CO2, T)) / 0.286; + var sugar = Round(SFactor * (CO2 - ResCO2(T)) * 4.014094, 6); + if (sugar < 0) + sugar = 0; + return Round(sugar, 3); + } + + function GetPressure(CO2, T1, T2) { + var P, V = CO2 - ResCO2(T1); + V = CO2; // TODO: temp only total pressure, testing + if (V < 0) + return 0; + P = -1.09145427669121 + 0.00800006989646477 * T2 + 0.000260276315484684 * T2 * T2 + 0.0215142075945119 * T2 * V + + 0.674996600795854 * V + -0.00471757220150754 * V * V; + if (P < 0) + P = 0; + P = Round(P * 1.01325, 2); // atm to bar + console.log("GetPressure(" + CO2 + ", " + T1 + ", " + T2 + ") V:" + V + " Bar: " + P + " ignored ResCO2: " + ResCO2(T1)); + return P; + } + + function CarbCO2ToPressure(CO2, T) { + return (CO2 - (-0.000005594056 * Math.pow(T, 4) + 0.000144357886 * Math.pow(T, 3) + + 0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049)) / + (0.00000498031 * Math.pow(T, 4) - 0.00024358267 * Math.pow(T, 3) + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376); + } + + function calcCarbonation() { + + var TSec, ABV, bvol, balc, babv, mvol, malc, tvol, talc, i, row, SFactor, pvol, pabv, Pressure, kabv; + + console.log('calcCarbonation()'); + + TSec = dataRecord.secondary_temp; + if (TSec < 1) + TSec = dataRecord.primary_end_temp; + if (TSec < 1) + TSec = 18; + + if (dataRecord.fg == 0.000) + ABV = abvol(dataRecord.brew_fermenter_sg, parseFloat($('#est_fg').jqxNumberInput('decimal'))); + else + ABV = abvol(dataRecord.brew_fermenter_sg, dataRecord.fg); + + /* Calculate new volume and alcohol. */ + bvol = dataRecord.package_volume - (ABV * dataRecord.package_volume) / 100; + balc = dataRecord.package_volume - bvol; + mvol = dataRecord.package_infuse_amount - (dataRecord.package_infuse_abv * dataRecord.package_infuse_amount) / 100; + malc = dataRecord.package_infuse_amount - mvol; + talc = balc + malc; + tvol = bvol + mvol; + ABV = Round(talc / (tvol + talc) * 100, 2); + dataRecord.package_abv = ABV; + $('#package_abv').val(ABV); + + //console.log("calcCarbonation() TSec:"+TSec+" ABV:"+ABV); + if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { + return; + } + + // Bottles + dataRecord.bottle_priming_amount = 0; + dataRecord.bottle_priming_total = 0; + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.f_added == 4) { + SFactor = 1 / ((row.f_yield / 100) * (1 - row.f_moisture / 100)); + dataRecord.bottle_priming_amount = CarbCO2toS(dataRecord.bottle_carbonation, TSec, SFactor); + dataRecord.bottle_priming_total = Round(dataRecord.bottle_amount * dataRecord.bottle_priming_amount, 2); + $('#fermentableGrid').jqxGrid('setcellvalue', i, 'f_amount', dataRecord.bottle_priming_total / 1000); + } + } + $('#bottle_priming_amount').val(Round(dataRecord.bottle_priming_amount, 1)); + $('#bottle_priming_total').val(dataRecord.bottle_priming_total); + pabv = ABV + dataRecord.bottle_priming_amount * 0.47 / 7.907; + pvol = dataRecord.bottle_amount - (pabv * dataRecord.bottle_amount) / 100; + talc = dataRecord.bottle_amount - pvol; + tvol = pvol + dataRecord.bottle_priming_water; + babv = Round(talc / (tvol + talc) * 100, 2); + //console.log("bottle pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.bottle_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+babv); + $('#bottle_abv').val(babv); + $('#bottle_pressure').val(GetPressure(dataRecord.bottle_carbonation, TSec, dataRecord.bottle_carbonation_temp)); + + // Kegs + Pressure = CarbCO2ToPressure(dataRecord.keg_carbonation, dataRecord.keg_carbonation_temp); + if (Pressure < 0) + Pressure = 0; + dataRecord.keg_pressure = Pressure; + $('#keg_pressure').val(Round(Pressure, 1)); + + dataRecord.keg_priming_amount = 0; + dataRecord.keg_priming_total = 0; + if (!dataRecord.keg_forced_carb) { + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.f_added == 5) { + SFactor = 1 / ((row.f_yield / 100) * (1 - row.f_moisture / 100)); + dataRecord.keg_priming_amount = CarbCO2toS(dataRecord.keg_carbonation, TSec, SFactor); + dataRecord.keg_priming_total = Round(dataRecord.keg_amount * dataRecord.keg_priming_amount, 2); + $('#fermentableGrid').jqxGrid('setcellvalue', i, 'f_amount', dataRecord.keg_priming_total / 1000); + } + } + $('#keg_priming_amount').val(Round(dataRecord.keg_priming_amount, 1)); + $('#keg_priming_total').val(dataRecord.keg_priming_total); + pabv = ABV + dataRecord.keg_priming_amount * 0.47 / 7.907; + pvol = dataRecord.keg_amount - (pabv * dataRecord.keg_amount) / 100; + talc = dataRecord.keg_amount - pvol; + tvol = pvol + dataRecord.keg_priming_water; + kabv = Round(talc / (tvol + talc) * 100, 2); + //console.log("kegs pabv:"+pabv+" pvol:"+pvol+" wvol:"+dataRecord.keg_priming_water+" tvol:"+tvol+" talc:"+talc+" abv:"+kabv); + $('#keg_abv').val(kabv); + } else { + $('#keg_priming_amount').val(0); + $('#keg_priming_total').val(0); + $('#keg_abv').val(ABV); + } + } + + function calcStage() { + /* + * Set stage and enable or disable parts of the screens. + */ + $('#stage').val(StageData[dataRecord.stage].nl); + + /* + * Enable or disable parts of the screens. + */ + $('#jqxTabs').jqxTabs((dataRecord.stage < 1) ? 'disableAt':'enableAt', 8); // Brewday tab + $('#jqxTabs').jqxTabs((dataRecord.stage > 2) ? 'enableAt':'disableAt', 9); // Fermentation tab + $('#jqxTabs').jqxTabs((dataRecord.stage < 9) ? 'disableAt':'enableAt', 11); // Tasting tab + } + + + // initialize the input fields. + // Tab 1, Algemeen + $('#name').jqxTooltip({ content: 'De naam voor dit product.' }); + $('#code').jqxTooltip({ content: 'Product code nummer.' }); + $('#birth').jqxTooltip({ content: 'De ontwerp datum van dit product.' }); + $('#stage').jqxTooltip({ content: 'De productie fase van dit product.' }); + $('#divide_batch').jqxTooltip({ content: 'Het aantal extra gesplitste batches.' }); + $('#divide_type').jqxTooltip({ content: 'Het splitsing moment in het productie proces.' }); + $('#notes').jqxTooltip({ content: 'De uitgebreide opmerkingen over dit product.' }); + $('#type').jqxTooltip({ content: 'Het brouw type van dit recept.' }); + $('#efficiency').jqxTooltip({ content: 'Het rendement van maischen en koken.' }); + $('#batch_size').jqxTooltip({ content: 'Het volume van het gekoelde wort na het koken.' }); + $('#boil_time').jqxTooltip({ content: 'De kooktijd in minuten.' }); + $('#boil_size').jqxTooltip({ content: 'Het volume van het wort voor het koken.' }); + $('#st_guide').jqxTooltip({ content: 'De bierstijl gids voor dit recept.'}); + $('#st_name').jqxTooltip({ content: 'De bierstijl naam voor dit recept.'}); + $('#st_letter').jqxTooltip({ content: 'De bierstijl letter voor dit recept.'}); + $('#st_letter').jqxInput({ theme: theme, width: 90, height: 23 }); + $('#st_type').jqxTooltip({ content: 'Het bierstijl type.'}); + $('#st_category').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie.'}); + $('#st_category_number').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie sub nummer.'}); + $('#est_og').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' }); + $('#st_og_min').jqxTooltip({ content: 'Het minimum begin SG voor deze bierstijl.'}); + $('#st_og_max').jqxTooltip({ content: 'Het maximum begin SG voor deze bierstijl.'}); + $('#est_fg').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); + $('#st_fg_min').jqxTooltip({ content: 'Het minimum eind SG voor deze bierstijl.'}); + $('#st_fg_max').jqxTooltip({ content: 'Het maximum eind SG voor deze bierstijl.'}); + $('#est_abv').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' }); + $('#st_abv_min').jqxTooltip({ content: 'Het minimum alcohol volume % voor deze bierstijl.'}); + $('#st_abv_max').jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'}); + $('#est_color').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); + $('#st_color_min').jqxTooltip({ content: 'De minimum kleur voor deze bierstijl.'}); + $('#st_color_max').jqxTooltip({ content: 'De maximum kleur voor deze bierstijl.'}); + $('#est_ibu').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); + $('#st_ibu_min').jqxTooltip({ content: 'De minimum bitterheid voor deze bierstijl.'}); + $('#st_ibu_max').jqxTooltip({ content: 'De maximum bitterheid voor deze bierstijl.'}); + $('#kcal').jqxTooltip({ content: 'Energie-inhoud in kcal/liter.' }); + $('#est_carb').jqxTooltip({ content: 'Koolzuur volume. Dit wordt automatisch berekend.' }); + $('#st_carb_min').jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'}); + $('#st_carb_max').jqxTooltip({ content: 'Het maximum koolzuur volume voor deze bierstijl.'}); + + $('#name').jqxInput({ theme: theme, width: 640, height: 23 }); + $('#code, #stage').jqxInput({ theme: theme, width: 100, height: 23 }); + $('#locked').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); + $('#birth,#divide_batch,#divide_type').jqxInput({ theme: theme, width: 120, height: 23 }); + $('#notes').jqxInput({ theme: theme, width: 960, height: 100 }); + $('#type').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#efficiency').jqxNumberInput(Show1dec); + $('#batch_size').jqxNumberInput(Show1dec); + $('#boil_time').jqxNumberInput(Show0dec); + $('#boil_size').jqxNumberInput(Show2dec); + $('#st_guide,#st_name,#st_type,#st_category').jqxInput({ theme: theme, width: 250, height: 23 }); + $('#est_og').jqxNumberInput(Show3dec); + $('#est_fg').jqxNumberInput(Show3dec); + $('#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 }); + $('#est_ibu,#est_color').jqxNumberInput(Show0dec); + $('#color_method').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#st_color_min,#st_color_max,#st_category_number,#st_ibu_min,#st_ibu_max,#kcal').jqxNumberInput(Smal0dec); + $('#ibu_method').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#est_abv,#st_abv_min,#st_abv_max,#est_carb,#st_carb_min,#st_carb_max').jqxNumberInput(Smal1dec); + + // Tab 2, Equipment + $('#eq_name').jqxTooltip({ content: 'De naam van deze brouw apparatuur.' }); + $('#eq_boil_size').jqxTooltip({ content: 'Normaal kook volume in liters' }); + $('#eq_batch_size').jqxTooltip({ content: 'Berekende batch grootte in liters aan het eind van de kook.' }); + $('#eq_tun_volume').jqxTooltip({ content: 'Maisch ketel volume.' }); + $('#eq_top_up_water').jqxTooltip({ content: 'Extra water in het gistvat.' }); + $('#eq_trub_chiller_loss').jqxTooltip({ content: 'Standaard verlies bij het overbrengen naar het gistvat.' }); + $('#eq_evap_rate').jqxTooltip({ content: 'Verdamping in liters per uur.' }); + $('#eq_boil_time').jqxTooltip({ content: 'Normale kooktijd in minuten, 0 voor no-boil recepten.' }); + $('#eq_top_up_kettle').jqxTooltip({ content: 'Extra water toevoegen tijdens de kook.' }); + $('#eq_hop_utilization').jqxTooltip({ content: '100% voor kleine installaties, hoger voor grote brouwerijen.' }); + $('#eq_notes').jqxTooltip({ content: 'Opmerkingen over deze apparatuur.' }); + $('#eq_lauter_volume').jqxTooltip({ content: 'Filterkuip volume.' }); + $('#eq_lauter_deadspace').jqxTooltip({ content: 'Filterkuip verlies in liters.' }); + $('#eq_kettle_volume').jqxTooltip({ content: 'Kook ketel volume in liters.' }); + $('#eq_mash_volume').jqxTooltip({ content: 'Maisch water voor de eerste stap.' }); + $('#eq_mash_max').jqxTooltip({ content: 'De maximale moutstort in Kg.' }); + $('#eq_efficiency').jqxTooltip({ content: 'Gemiddeld brouwzaal rendement.' }); + + $('#eq_name').jqxInput({ theme: theme, width: 250, height: 23 }); + $('#eq_evap_rate').jqxNumberInput(Show2dec); + $('#eq_boil_time,#eq_hop_utilization').jqxNumberInput(Show0dec); + $('#eq_notes').jqxInput({ theme: theme, width: 960, height: 200 }); + $('#eq_boil_size,#eq_batch_size,#eq_tun_volume,#eq_top_up_water,#eq_trub_chiller_loss,#eq_top_up_kettle').jqxNumberInput(Show1dec); + $('#eq_lauter_volume,#eq_lauter_deadspace,#eq_kettle_volume,#eq_mash_volume,#eq_mash_max,#eq_efficiency').jqxNumberInput(Show1dec); + + // Tab 3, Fermentables + $('#est_color2').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); + $('#est_og2').jqxTooltip({ content: 'Het geschatte begin SG van dit product.' }); + $('#mash_kg').jqxTooltip({ content: 'Het gewicht van alle mouten in de maisch.' }); + + $('#est_color2').jqxNumberInput(Show0dec); + $('#est_og2,#mash_kg').jqxNumberInput(Show3dec); + + $('#perc_malts').jqxProgressBar({ + width: 300, height: 23, theme: theme, showText: true, max: 120, animationDuration: 0, + colorRanges: [{ stop: 90, color: '#008C00' },{ stop: 100, color: '#EB7331' },{ stop: 120, color: '#FF0000' }], + renderText: function(text) { return (Math.round(parseInt(text) * 1.2)) + '%'; } + }); + $('#perc_sugars').jqxProgressBar({ + width: 300, height: 23, theme: theme, showText: true, max: 50, animationDuration: 0, + colorRanges: [{ stop: 20, color: '#008C00' },{ stop: 50, color: '#FF0000' }], + renderText: function(text) { return (Math.round(parseInt(text) * 5) / 10) + '%'; } + }); + $('#perc_cara').jqxProgressBar({ + width: 300, height: 23, theme: theme, showText: true, max: 50, animationDuration: 0, + colorRanges: [{ stop: 25, color: '#008C00' },{ stop: 50, color: '#FF0000' }], + renderText: function(text) { return (Math.round(parseInt(text) * 5) / 10) + '%'; } + }); + $('#ferm_lintner').jqxProgressBar({ + width: 300, height: 23, theme: theme, showText: true, max: 200, animationDuration: 0, + colorRanges: [{ stop: 30, color: '#FF0000' },{ stop: 40, color: '#EB7331' },{ stop: 200, color: '#008C00' }], + renderText: function(text) { return (parseInt(text) * 2) + ' lintner'; } + }); + + // Tab 4, Hops + $('#est_ibu2').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); + $('#est_ibu2').jqxNumberInput(Smal0dec); + $('#hop_flavour').jqxProgressBar({ + width: 300, height: 23, theme: theme, showText: true, animationDuration: 0, + colorRanges: [ + { stop: 20, color: '#004D00' }, + { stop: 40, color: '#008C00' }, + { stop: 60, color: '#00BF00' }, + { stop: 80, color: '#00FF00' }, + { stop: 100, color: '#80FF80' } + ], + renderText: function(text) { + var val = parseInt(text); + if (val < 20) + return 'Weinig'; + else if (val < 40) + return 'Matig'; + else if (val < 60) + return 'Redelijk'; + else if (val < 80) + return 'Veel'; + else + return 'Zeer veel'; + } + }); + $('#hop_aroma').jqxProgressBar({ + width: 300, height: 23, theme: theme, showText: true, animationDuration: 0, + colorRanges: [ + { stop: 20, color: '#004D00' }, + { stop: 40, color: '#008C00' }, + { stop: 60, color: '#00BF00' }, + { stop: 80, color: '#00FF00' }, + { stop: 100, color: '#80FF80' } + ], + renderText: function(text) { + var val = parseInt(text); + if (val < 20) + return 'Weinig'; + else if (val < 40) + return 'Matig'; + else if (val < 60) + return 'Redelijk'; + else if (val < 80) + return 'Veel'; + else + return 'Zeer veel'; + } + }); + + // Tab 5, Miscs + + // Tab 6, Yeasts + $('#est_fg2').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); + $('#est_abv2').jqxTooltip({ content: 'Verwacht alcohol volume %. Dit wordt automatisch berekend.' }); + $('#yeast_grams').jqxTooltip({ content: 'De gewenste totale hoeveelheid droge gist voor dit bier.' }); + $('#yeast_gr_hl').jqxTooltip({ content: 'De werkelijke hoeveelheid gist per hectoliter.' }); + $('#yeast_cells').jqxTooltip({ content: 'Het aantal miljard beschikbare gistcellen zonder eventuele starter.' }); + $('#need_cells').jqxTooltip({ content: 'Het aantal miljard nodige cellen is afhankelijk van het begin SG, biertype en volume.' }); + $('#plato_cells').jqxTooltip({ content: 'De berekende pitchrate in miljard cellen per ml per graad Plato.' }); + $('#yeast_prod_date').jqxTooltip({ content: 'Bij korrelgisten is meestal "best voor" datum op het zakje gedrukt.
Gebruik die datum maar dan twee jaar eerder als productie datum.
Bij White Labs is de productie datum vier maanden voor de "Best by" datum die geprint op het buisje.
Bij Wyeast is dit de "manufacture date" die op het pak geprint is.
Voor schuine buis, slurry, opkweek en gedroogd is dit de datum dat je de gist geoogst hebt.' }); + $('#yeast_pitchrate').jqxTooltip({ content: 'De gewenste pitchrate in miljard cellen per ml per graad Plato voor de vergisting van dit bier.' }); + + $('#est_fg2,#plato_cells').jqxNumberInput(Show3dec); + $('#est_fg2').jqxNumberInput({ width: 70 }); + $('#est_abv2').jqxNumberInput(Show2dec); + $('#est_abv2').jqxNumberInput({ width: 70, symbol: '%', symbolPosition: 'right' }); + $('#yeast_grams').jqxNumberInput(Show1dec); + $('#yeast_gr_hl').jqxNumberInput(Show1dec); + $('#yeast_cells,#need_cells').jqxNumberInput(Show1dec); + $('#yeast_prod_date').jqxDateTimeInput(Dateopts); + $('#yeast_prod_date').jqxDateTimeInput({ disabled: true }); + $('#yeast_pitchrate').jqxNumberInput(Show3dec); + for (i = 1; i < 5; i++) { + $('#prop' + i + '_volume').jqxTooltip({ content: 'Het volume van deze starter stap.' }); + $('#prop' + i + '_irate').jqxTooltip({ content: 'Voor de beste gistgroei, houd de injectie factor tussen de 25 en 100 miljoen cellen per ml.' }); + $('#prop' + i + '_ncells').jqxTooltip({ content: 'Het aantal miljard nieuwe gistcellen in deze stap.' }); + $('#prop' + i + '_tcells').jqxTooltip({ content: 'Het totaal aantal miljard gistcellen na deze stap.' }); + $('#prop' + i + '_growf').jqxTooltip({ content: 'De groeifactor, minstens 1. Ongeroerde starters komen meestal niet boven de 3.' }); + + $('#prop' + i + '_type').jqxInput({ theme: theme, width: 120, height: 23 }); + $('#prop' + i + '_volume').jqxNumberInput(Show3dec); + $('#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells').jqxNumberInput(Show1dec); + $('#prop' + i + '_growf').jqxNumberInput(Show2dec); + $('#prop' + i + '_type,#prop' + i + '_volume,#prop' + i + '_irate,#prop' + i + '_ncells,#prop' + i + '_tcells,#prop' + i + '_growf').hide(); + } + $('#starter_type').jqxInput({ theme: theme, width: 120, height: 23 }); + $('#starter_sg').jqxTooltip({ content: 'Het ideale starter SG moet tussen de 1.030 en 1.040 zijn. Optimaal is 1.037.' }); + $('#starter_sg').jqxNumberInput(Show3dec); + $('#starter_viability').jqxTooltip({ content: 'De gist conditie.' }); + $('#starter_viability').jqxNumberInput(Show0dec); + + // Tab 7, Mashing + $('#mash_name').jqxTooltip({ content: 'De omschrijving van dit maisch profiel.' }); + $('#mash_name').jqxInput({ theme: theme, width: 320, height: 23 }); + $('#est_mashvol').jqxTooltip({ content: 'Het totale volume van het maishwater en de mout in de maish pan.' }); + $('#est_mashvol').jqxNumberInput(Show1dec); + $('#est_mashtime').jqxTooltip({ content: 'De totale tijdsduur van het maischen.' }); + $('#est_mashtime').jqxInput({ theme: theme, width: 70, height: 23 }); + + // Tab 8, Water + $('#tgt_bu').jqxNumberInput(Show2wat); + $('#tgt_so4_cl,#got_so4_cl').jqxNumberInput(Show1wat); + $('#preboil_ph').jqxNumberInput(Show2wat); + + // Water source 1 + $('#w1_name').jqxInput({ theme: theme, width: 200, height: 23 }); + $('#w1_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); + $('#w1_amount,#w1_calcium,#w1_magnesium,#w1_sodium,#w1_bicarbonate,#w1_total_alkalinity,#w1_chloride,#w1_sulfate').jqxNumberInput(Show1wat); + $('#w1_ph').jqxNumberInput(Show2wat); + $('#w1_hardness').jqxNumberInput(Show1wat); + $('#w1_ra').jqxNumberInput(Show1wat); + // Water source 2 + $('#w2_name').jqxInput({ theme: theme, width: 200, height: 23 }); + $('#w2_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); + $('#w2_amount').jqxNumberInput(Show1wat); + $('#w2_calcium,#w2_magnesium,#w2_sodium,#w2_bicarbonate,#w2_total_alkalinity,#w2_chloride,#w2_sulfate').jqxNumberInput(Show1wat); + $('#w2_ph').jqxNumberInput(Show2wat); + $('#w2_hardness').jqxNumberInput(Show1wat); + $('#w2_ra').jqxNumberInput(Show1wat); + // Water mixed + $('#wg_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); + $('#wg_amount,#wg_calcium,#wg_magnesium,#wg_sodium,#wg_bicarbonate,#wg_total_alkalinity,#wg_chloride,#wg_sulfate').jqxNumberInput(Show1wat); + $('#wg_ph').jqxNumberInput(Show2wat); + $('#wg_hardness').jqxNumberInput(Show1wat); + $('#wg_ra').jqxNumberInput(Show1wat); + // Water treated + $('#wb_calcium').jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'}); + $('#wb_calcium').jqxNumberInput(Show1wat); + $('#wb_magnesium').jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is tussen 5 en 40.'}); + $('#wb_magnesium').jqxNumberInput(Show1wat); + $('#wb_sodium').jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'}); + $('#wb_sodium').jqxNumberInput(Show1wat); + $('#wb_chloride').jqxTooltip({ content: 'De ideale hoeveelheid Chloride is tussen 50 en 150. Samen met Sulfaat minder dan 500.'}); + $('#wb_chloride').jqxNumberInput(Show1wat); + $('#wb_sulfate').jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 400. Samen met Chloride minder dan 500.'}); + $('#wb_sulfate').jqxNumberInput(Show1wat); + $('#wb_bicarbonate').jqxTooltip({ content: '0 tot 50 lichte bieren, 50 tot 150 amber bieren, 150 tot 250 donkere bieren.'}); + $('#wb_bicarbonate').jqxNumberInput(Show1wat); + $('#wb_ph').jqxNumberInput(Show2wat); + $('#wb_hardness').jqxNumberInput(Show1wat); + $('#wb_ra').jqxNumberInput(Show1wat); + // Sparge water + $('#sw_amount').jqxNumberInput(Show1wat); + $('#sw_calcium').jqxNumberInput(Show1wat); + $('#sw_magnesium').jqxNumberInput(Show1wat); + $('#sw_sodium').jqxNumberInput(Show1wat); + $('#sw_bicarbonate').jqxNumberInput(Show1wat); + $('#sw_total_alkalinity').jqxNumberInput(Show1wat); + $('#sw_chloride').jqxNumberInput(Show1wat); + $('#sw_sulfate').jqxNumberInput(Show1wat); + $('#sw_ph').jqxNumberInput(Show2wat); + $('#sw_hardness').jqxNumberInput(Show1wat); + $('#sw_ra').jqxNumberInput(Show1wat); + + // Water agents + $('#wa_cacl2').jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.' }); + $('#wa_cacl2').jqxNumberInput(Show2wat); + $('#ss_cacl2').jqxNumberInput(Show2wat); + + $('#wa_caso4').jqxTooltip({ + content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.' + }); + $('#wa_caso4').jqxNumberInput(Show2wat); + $('#ss_caso4').jqxNumberInput(Show2wat); + + $('#wa_mgso4').jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!' }); + $('#wa_mgso4').jqxNumberInput(Show2wat); + $('#ss_mgso4').jqxNumberInput(Show2wat); + + $('#wa_nacl').jqxTooltip({ + content: 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. ' + + 'Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.' + }); + $('#wa_nacl').jqxNumberInput(Show2wat); + $('#ss_nacl').jqxNumberInput(Show2wat); + + $('#wa_mgcl2').jqxTooltip({ content: 'Magnesiumchloride'}); + $('#wa_mgcl2').jqxNumberInput(Show2wat); + $('#ss_mgcl2').jqxNumberInput(Show2wat); + + $('#wa_nahco3').jqxTooltip({ content: 'Baksoda'}); + $('#wa_caco3').jqxTooltip({ content: 'Kalk'}); + $('#wa_nahco3,#wa_caco3').jqxNumberInput(Show2wat); + + $('#mash_ph').jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'}); + $('#mash_ph').jqxNumberInput(Show2dec); + + $('#calc_acid').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); + + $('#wa_acid_name').jqxInput({ theme: theme, width: 130, height: 23 }); + $('#wa_acid').jqxNumberInput(Show2dec); + $('#wa_acid').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); + $('#wa_acid_perc').jqxNumberInput(Show0dec); + $('#wa_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); + + // Sparge water + $('#sparge_ph').jqxNumberInput(Show2dec); + $('#sparge_acid_amount').jqxNumberInput(Show2dec); + $('#sparge_acid_amount').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); + $('#sparge_acid_type').jqxInput({ theme: theme, width: 130, height: 23 }); + $('#sparge_acid_perc').jqxNumberInput(Show0dec); + $('#sparge_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); + + // Tab 9, Brewday + $('#brew_date_start').jqxTooltip({ content: 'Brouw datum en tijd. Voor planning laat de tijd op 00:00:00 staan.' }); + $('#brew_date_end').jqxTooltip({ content: 'End datum en tijd van de brouw. Leeg laten als er nog niet gebrouwen is.' }); + $('#brew_mash_ph').jqxTooltip({ content: 'De gemeten pH tijdens het maischen eventueel na correctie.' }); + $('#est_mash_ph').jqxTooltip({ content: 'De gewenste pH tijdens het maischen.' }); + $('#brew_preboil_ph').jqxTooltip({ content: 'De gemeten pH in de kookketel na het spoelen en voor de kook.' }); + $('#brew_aboil_ph').jqxTooltip({ content: 'De gemeten pH na het koken.' }); + $('#brew_mash_sg').jqxTooltip({ content: 'Het bereikte SG na het maischen.' }); + $('#est_mash_sg').jqxTooltip({ content: 'Het berekende verwachte SG na het maischen.' }); + $('#brew_preboil_sg').jqxTooltip({ content: 'Het gemeten SG in de kookketel na het spoelen en voor het koken.' }); + $('#est_pre_sg').jqxTooltip({ content: 'Het berekende SG in de kookketel na het spoelen en voor het koken.' }); + $('#brew_aboil_sg').jqxTooltip({ content: 'Het gemeten SG in de kookketel na het koken.' }); + $('#est_og3').jqxTooltip({ content: 'Het gewenste SG in de kookketel na het koken zonder eventuele suikers die tijdens de vergisting toegevoegd worden.' }); + $('#brew_mash_efficiency').jqxTooltip({ content: 'Het behaalde maisch rendement.' }); + $('#brew_preboil_volume').jqxTooltip({ content: 'Het gemeten volume van het wort voor het koken.' }); + $('#est_pre_vol').jqxTooltip({ content: 'Het berekende volume van het wort voor het koken.' }); + $('#brew_aboil_volume').jqxTooltip({ content: 'Het gemeten volume van het wort na het koken.' }); + $('#est_a_vol').jqxTooltip({ content: 'Het gewenste volume na het koken.' }); + $('#brew_preboil_efficiency').jqxTooltip({ content: 'Het berekende rendement voor het koken.' }); + $('#brew_aboil_efficiency').jqxTooltip({ content: 'Het bereikte rendement na het koken.' }); + $('#brew_sparge_temperature').jqxTooltip({ content: 'De spoelwater temperatuur, in te stellen in de Water tab.' }); + $('#brew_sparge_volume').jqxTooltip({ content: 'Het spoelwater voorraad volume, in te stellen in de Water tab.' }); + $('#brew_date_start,#brew_date_end').jqxDateTimeInput(DateTimeopts); + $('#brew_date_start,#brew_date_end').jqxDateTimeInput({ disabled: true }); + $('#est_mash_ph').jqxNumberInput(Show2wat); + $('#brew_mash_ph,#brew_preboil_ph,#brew_aboil_ph').jqxNumberInput(Show2dec); + $('#brew_mash_sg,#brew_preboil_sg,#brew_aboil_sg').jqxNumberInput(Show3dec); + $('#est_mash_sg,#est_pre_sg,#est_og3').jqxNumberInput(Show3wat); + $('#brew_mash_efficiency').jqxNumberInput(Show1dec); + $('#brew_preboil_volume,#brew_aboil_volume').jqxNumberInput(Show1dec); + $('#est_pre_vol,#est_a_vol').jqxNumberInput(Show1wat); + $('#brew_preboil_efficiency,#brew_aboil_efficiency,#brew_sparge_temperature,#brew_sparge_volume,#brew_sparge_est').jqxNumberInput(Show1dec); + $('#brew_cooling_to').jqxNumberInput(Show1dec); + $('#brew_sparge_ph').jqxNumberInput(Show2dec); + $('#brew_cooling_method').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#brew_cooling_time,#brew_whirlpool9,#brew_whirlpool7,#brew_whirlpool6,#brew_whirlpool2,#brew_aeration_time,#brew_aeration_speed').jqxNumberInput(Show0dec); + $('#brew_aeration_type').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#brew_fermenter_volume').jqxNumberInput(Show1dec); + $('#brew_fermenter_sg').jqxNumberInput(Show3dec); + $('#brew_fermenter_extrawater,#brew_fermenter_tcloss').jqxNumberInput(Show1dec); + $('#brew_fermenter_ibu,#brew_fermenter_color').jqxNumberInput(Show0dec); + + // Tab 10, Fermentation + $('#brew_fermenter_sg2').jqxTooltip({ content: 'Het behaalde SG in het gistvat, overgenomen van de brouwdag.' }); + $('#primary_start_temp').jqxTooltip({ content: 'De begintemperatuur van de hoofdvergisting.' }); + $('#primary_max_temp').jqxTooltip({ content: 'De hoogst bereikte piek temperatuur tijdens de hoofgvergisting.' }); + $('#primary_end_temp').jqxTooltip({ content: 'De eind temperatuur van de hoofdvergisting.' }); + $('#primary_end_sg').jqxTooltip({ content: 'Het gemeten SG aan het eind van de hoofdvergisting.' }); + $('#primary_svg').jqxTooltip({ content: 'De schijnbare vergisting graad behaald na de hoofdgisting.' }); + $('#primary_end_date').jqxTooltip({ content: 'De eind datum van de hoofdvergisting en eventueel overhevelen.' }); + $('#secondary_end_sg').jqxTooltip({ content: 'Het gemeten SG aan het eind van de navergisting.' }); + $('#secondary_svg').jqxTooltip({ content: 'De schijnbare vergisting graad behaald na de nagisting.' }); + $('#secondary_end_date').jqxTooltip({ content: 'De eind datum van de navergisting en het begin van het lageren.' }); + $('#est_fg3').jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' }); + + $('#primary_end_sg,#secondary_end_sg').jqxNumberInput(Show3dec); + $('#primary_end_date,#secondary_end_date').jqxDateTimeInput(Dateopts); + $('#primary_end_date,#secondary_end_date').jqxDateTimeInput({ disabled: true }); + $('#primary_start_temp,#primary_max_temp,#primary_end_temp,#secondary_temp,#tertiary_temp').jqxNumberInput(Show1dec); + $('#fg').jqxNumberInput(Show3dec); + $('#brew_fermenter_sg2,#est_fg3').jqxNumberInput(Show3dec); + $('#final_abv').jqxNumberInput(Show2dec); + $('#primary_svg,#secondary_svg,#final_svg').jqxNumberInput(Show1dec); + $('#FLog').jqxButton({ template: 'info', width: '150px', theme: theme }); + $('#FLog').click(function() { + // Open log in a new tab. + window.open('log_fermentation.php?code=' + dataRecord.code + '&name=' + dataRecord.name); + }); + $('#ILog').jqxButton({ template: 'info', width: '150px', theme: theme }); + $('#ILog').click(function() { + // Open log in a new tab. + window.open('log_ispindel.php?code=' + dataRecord.code + '&name=' + dataRecord.name); + }); + + // Tab 11, Packaging + // TODO: high gravity packaging, extra water and recalc abv, color and ibu. + $('#package_date').jqxTooltip({ content: 'De verpakkings datum van dit bier.' }); + $('#package_volume').jqxTooltip({ content: 'Het beschikbare volume om te bottelen of op fust te zetten.' }); + $('#package_infuse_amount').jqxTooltip({ content: 'De hoeveelheid water of drank extra toe te voegen.' }); + $('#package_infuse_abv').jqxTooltip({ content: 'De hoeveelheid alcohol in de drank, of 0.0 als het water is.' }); + $('#package_infuse_notes').jqxTooltip({ content: 'Omschrijving van de extra toevoeging.' }); + $('#package_abv').jqxTooltip({ content: 'De uiteindelijke hoeveelheid alcohol volume %.' }); + $('#package_ph').jqxTooltip({ content: 'De gemeten pH vlak voor het verpakken.' }); + $('#st_carb_min2').jqxTooltip({ content: 'Het minimum aanbevolen koolzuur volume voor deze bierstijl.'}); + $('#st_carb_max2').jqxTooltip({ content: 'Het maximum aamnevolen koolzuur volume voor deze bierstijl.'}); + $('#bottle_amount').jqxTooltip({ content: 'De totale hoeveelheid te bottelen bier.' }); + $('#keg_amount').jqxTooltip({ content: 'De totale hoeveelheid op fust te zetten bier.' }); + $('#bottle_carbonation').jqxTooltip({ content: 'Het gewenste CO2 volume in de flessen.' }); + $('#keg_carbonation').jqxTooltip({ content: 'Het gewenste CO2 volume door de suiker in de fusten.' }); + $('#bottle_priming_water,#keg_priming_water').jqxTooltip({ content: 'De hoeveelheid water om de suiker op te lossen.' }); + $('#bottle_pressure').jqxTooltip({ content: 'De maximaal te verwachten druk tijdens het hergisten.' }); + $('#package_date').jqxDateTimeInput(Dateopts); + $('#package_date').jqxDateTimeInput({ disabled: true }); + $('#package_infuse_amount').jqxNumberInput(Show3dec); + $('#package_infuse_notes').jqxInput({ theme: theme, width: 640, height: 23 }); + $('#package_abv').jqxNumberInput(Show2dec); + $('#package_ph').jqxNumberInput(Show2dec); + $('#st_carb_min2,#st_carb_max2').jqxNumberInput(Smal1dec); + $('#package_volume,#package_infuse_abv,#bottle_amount,#keg_amount').jqxNumberInput(Show1dec); + $('#bottle_carbonation,#keg_carbonation').jqxNumberInput(Show2dec); + $('#bottle_priming_sugar').jqxInput({ theme: theme, width: 200, height: 23 }); + $('#keg_priming_sugar').jqxInput({ theme: theme, width: 200, height: 23 }); + $('#bottle_priming_water,#keg_priming_water').jqxNumberInput(Show3dec); + $('#keg_forced_carb').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); + $('#bottle_priming_amount,#keg_priming_amount,#bottle_priming_total,#bottle_pressure,#keg_priming_total,#keg_pressure').jqxNumberInput(Show1dec); + $('#bottle_abv,#keg_abv').jqxNumberInput(Show2dec); + $('#bottle_carbonation_temp,#keg_carbonation_temp').jqxNumberInput(Show1dec); + $('#CLog').jqxButton({ template: 'info', width: '150px', theme: theme }); + $('#CLog').click(function() { + // Open log in a new tab. + window.open('log_co2pressure.php?code=' + dataRecord.code + '&name=' + dataRecord.name); + }); + + // Tab 12, Tasting + $('#taste_date').jqxTooltip({ content: 'De proef datum van dit bier.' }); + $('#taste_date').jqxDateTimeInput(Dateopts); + $('#taste_date').jqxDateTimeInput({ disabled: true }); + $('#taste_rate').jqxTooltip({ content: 'Het cijfer voor dit bier van 1 tot 10.' }); + $('#taste_rate').jqxNumberInput(Show1dec); + $('#taste_color').jqxTooltip({ content: 'De kleur van het bier.' }); + $('#taste_transparency').jqxTooltip({ content: 'De helderheid van het bier.' }); + $('#taste_head').jqxTooltip({ content: 'Het schuim op het bier.' }); + $('#taste_color,#taste_transparency,#taste_head').jqxInput({ theme: theme, width: 320, height: 23 }); + $('#taste_aroma').jqxTooltip({ content: 'Het aroma van het bier.' }); + $('#taste_taste').jqxTooltip({ content: 'De smaak van het bier.' }); + $('#taste_aftertaste').jqxTooltip({ content: 'De nasmaak van het bier.' }); + $('#taste_mouthfeel').jqxTooltip({ content: 'Het mondgevoelvan het bier.' }); + $('#taste_aroma,#taste_taste,#taste_aftertaste,#taste_mouthfeel').jqxInput({ theme: theme, width: 960, height: 23 }); + $('#taste_notes').jqxTooltip({ content: 'Het oordeel en opmerkingen over dit bier.' }); + $('#taste_notes').jqxInput({ theme: theme, width: 960, height: 100 }); + + $('#jqxTabs').jqxTabs({ + theme: theme, + width: 1280, + height: 660, + autoHeight: false, + position: 'top' + }); + + // Buttons below + $('#Terug').jqxButton({ template: 'primary', width: '80px', theme: theme }); + $('#Terug').bind('click', function() { + window.location.href = my_return; + }); +}); + diff -r 21fae4d2203e -r 2641860ad61d www/prod_edit.php --- a/www/prod_edit.php Sat Aug 06 22:02:42 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,931 +0,0 @@ - - -
-
    -
  • Algemeen
  • -
  • Apparatuur
  • -
  • Vergistbaar
  • -
  • Hoppen
  • -
  • Diversen
  • -
  • Gist
  • -
  • Maischen
  • -
  • Water
  • -
  • Brouwdag
  • -
  • Vergisten
  • -
  • Verpakken
  • -
  • Proeven
  • -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Brouw naam:Afgesloten:
Brouw code:Start planning:Brouw fase:
Splits product:Gesplitst product:Splits focus:
Opmerkingen:
Brouw type:Brouwzaal rendement:
Ingredienten aanwezig:
Brouw volume:
Kooktijd minuten:
Kook volume:

Bierstijl gegevens
Stijlgids:Bier stijl:Bier groep:
Stijl type:Categorie:Categorie nr:
Start SG:
Eind SG:
Alcohol vol.%:
Kleur EBC:
Kleur methode:Koolzuur vol:
Bitterheid IBU:
Bitterheid methode:Energie-inhoud kcal/l:
-
- -
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Installatie naam:
Opmerkingen:
MaischenKoken
Maischkuip volume L:
Kookketel volume L:
Maischwater L:
Kook volume L:
Maximum moutstort Kg:
Verdamping per uur L:
FilterenKooktijd in minuten:
Filter volume L:
Extra water bij koken L:
Filterkuip verlies L:
Hopfactor %:
KoelenVolume eind koken L:
Trub verlies kookketel L:
Brouwzaalrendement %:
Extra water in gistvat:
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Kleur EBC:
Percentage moutstort:
Begin SG:
Percentage suiker:
Maisch KG:
Percentage cara:
Lintner totaal:
-
-
- -
-
- - - - - - - - - - - - -
Bitterheid IBU:
Smaak bijdrage:
Aroma bijdrage:
-
-
- -
-
- - - -
 
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Verwacht FG en ABV:
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Giststarter stappen
StapMethodeVolumeInj. factorNieuwe cellenTotaal cellenGroei factor
1
Niet nodig
2
Niet nodig
3
Niet nodig
4
Niet nodig
-
-
Gist productie datum:
Gist conditie %:
Gist nodig gram:
Ent hoeveelheid gr/hl:
Gistcellen miljard:
Pitch rate:
Cellen nodig miljard:
Pitch cellen/ml °P:
Starter type:Starter SG:
       
-
-
- -
-
- - - - - - - - - - - - - -
Maischchema:
Volume van de maisch L:
Tijdsduur maischen:
 
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Water overzicht
Water profielSpoelVolumeCaMgHCO3CaCO3NaClSO4pHHardheidRA
Gemengd water:
Behandeld maisch water:
Resultaat:
Behandeld spoelwater:
-
-
BrouwzoutenSpoelwater
CaCl2 gr:
Bitterheidsindex:
Auto bereken:
CaSO4 gr:
Richtgetal SO4:Cl:
Gewenst maish pH:
MgSO4 gr:
Huidig SO4:Cl:
Aanzuren met:
NaCl gr:
Voor koken pH:
Zuur hoeveelheid:
MgCl2 gr:
Gewenst spoel pH:
NaHCO3 gr:
Aanzuren met:
CaCO3 gr:
Zuur hoeveelheid:
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Brouwdag start:
Brouwdag eind:
Maischen
Koken
Maisch pH:
Voor koken pH:
Na koken pH:
Maisch SG:
Voor koken SG:
Na koken SG:
Maisch rendement %:
Voor koken vol@100°C:
Na koken vol@100°C:
Voor koken rendement %:
Na koken rendement %:
 
Spoelen en filterenKoelen en whirlpoolen
Spoelwater °C:
Whirlpool 85..100°C min:
Koelen tot °C:
Spoelwater voorraad L:
Whirlpool 72..79°C min:
Koelen met:
Spoelwater nodig L:
Whirlpool 60..66°C min:
Koelen minuten:
Spoelwater pH:
Whirlpool koud min:
 
BeluchtenNaar gistvat
Beluchten met:Koeler en trub verlies L:
SG in gistvat:
Beluchten tijd min:
Extra water in gistvat L:
Kleur in gistvat EBC:
Beluchten snelheid:
Volume naar gistvat L:
Bitterheid in gistvat IBU:
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hoofdvergisting
Begin vergisting SG:
Start temperatuur hoofdvergisting °C:
Piek temperatuur hoofdvergisting °C:
Eind temperatuur hoofdvergisting °C:
Eind hoofdvergisting SG:
Eind hoofdvergisting/overhevelen:
Schijnbare vergistingsgraad:

Nagisting
Temperatuur nagisting °C:
Eind nagisting SG:
Eind nagisting/start lageren:
Schijnbare vergistingsgraad %:

Lageren
Temperatuur lageren °C:
Het verwachte eind SG:
Het behaalde eind SG:
Alcoholgehalte voor hergisting vol.%:
Schijnbare vergistingsgraad %:
-
- - -
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Datum:
Aanbevolen volume CO2:

Verdunnen of infusie
Volume na vergisting L:
Toevoeging Liter:
Toevoeging ABV %:
Toevoeging omschrijving:
Alcohol volume %:
Bij verpakken pH:

FlessenFusten
Hoeveelheid Liter:
Hoeveelheid Liter:
Gewenst volume CO2:
Gewenst volume CO2:
Suiker:Suiker:
Toevoegen suiker g/L:
Toevoegen suiker g/L:
Suiker totaal gram:
Suiker totaal gram:
Suikeroplossing water L:
Suikeroplossing water L:
Op druk brengen met CO2:
Verwachte flesdruk in bar:
Druk op fust bar:
Alcoholgehalte flessen vol.%:
Alcoholgehalte fusten vol.%:
Hergisting temperatuur:
Keg temperatuur:
-
- -
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Datum:
Cijfer:
Kleur:Helderheid:
Schuim:
Aroma:
Smaak:
Nasmaak:
Mondgevoel:
Oordeel:
-
-
- -
- - diff -r 21fae4d2203e -r 2641860ad61d www/prod_view.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/www/prod_view.php Sat Aug 06 22:10:28 2022 +0200 @@ -0,0 +1,931 @@ + + +
+
    +
  • Algemeen
  • +
  • Apparatuur
  • +
  • Vergistbaar
  • +
  • Hoppen
  • +
  • Diversen
  • +
  • Gist
  • +
  • Maischen
  • +
  • Water
  • +
  • Brouwdag
  • +
  • Vergisten
  • +
  • Verpakken
  • +
  • Proeven
  • +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Brouw naam:Afgesloten:
Brouw code:Start planning:Brouw fase:
Splits product:Gesplitst product:Splits focus:
Opmerkingen:
Brouw type:Brouwzaal rendement:
Ingredienten aanwezig:
Brouw volume:
Kooktijd minuten:
Kook volume:

Bierstijl gegevens
Stijlgids:Bier stijl:Bier groep:
Stijl type:Categorie:Categorie nr:
Start SG:
Eind SG:
Alcohol vol.%:
Kleur EBC:
Kleur methode:Koolzuur vol:
Bitterheid IBU:
Bitterheid methode:Energie-inhoud kcal/l:
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Installatie naam:
Opmerkingen:
MaischenKoken
Maischkuip volume L:
Kookketel volume L:
Maischwater L:
Kook volume L:
Maximum moutstort Kg:
Verdamping per uur L:
FilterenKooktijd in minuten:
Filter volume L:
Extra water bij koken L:
Filterkuip verlies L:
Hopfactor %:
KoelenVolume eind koken L:
Trub verlies kookketel L:
Brouwzaalrendement %:
Extra water in gistvat:
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Kleur EBC:
Percentage moutstort:
Begin SG:
Percentage suiker:
Maisch KG:
Percentage cara:
Lintner totaal:
+
+
+ +
+
+ + + + + + + + + + + + +
Bitterheid IBU:
Smaak bijdrage:
Aroma bijdrage:
+
+
+ +
+
+ + + +
 
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Verwacht FG en ABV:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Giststarter stappen
StapMethodeVolumeInj. factorNieuwe cellenTotaal cellenGroei factor
1
Niet nodig
2
Niet nodig
3
Niet nodig
4
Niet nodig
+
+
Gist productie datum:
Gist conditie %:
Gist nodig gram:
Ent hoeveelheid gr/hl:
Gistcellen miljard:
Pitch rate:
Cellen nodig miljard:
Pitch cellen/ml °P:
Starter type:Starter SG:
       
+
+
+ +
+
+ + + + + + + + + + + + + +
Maischchema:
Volume van de maisch L:
Tijdsduur maischen:
 
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Water overzicht
Water profielSpoelVolumeCaMgHCO3CaCO3NaClSO4pHHardheidRA
Gemengd water:
Behandeld maisch water:
Resultaat:
Behandeld spoelwater:
+
+
BrouwzoutenSpoelwater
CaCl2 gr:
Bitterheidsindex:
Auto bereken:
CaSO4 gr:
Richtgetal SO4:Cl:
Gewenst maish pH:
MgSO4 gr:
Huidig SO4:Cl:
Aanzuren met:
NaCl gr:
Voor koken pH:
Zuur hoeveelheid:
MgCl2 gr:
Gewenst spoel pH:
NaHCO3 gr:
Aanzuren met:
CaCO3 gr:
Zuur hoeveelheid:
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Brouwdag start:
Brouwdag eind:
Maischen
Koken
Maisch pH:
Voor koken pH:
Na koken pH:
Maisch SG:
Voor koken SG:
Na koken SG:
Maisch rendement %:
Voor koken vol@100°C:
Na koken vol@100°C:
Voor koken rendement %:
Na koken rendement %:
 
Spoelen en filterenKoelen en whirlpoolen
Spoelwater °C:
Whirlpool 85..100°C min:
Koelen tot °C:
Spoelwater voorraad L:
Whirlpool 72..79°C min:
Koelen met:
Spoelwater nodig L:
Whirlpool 60..66°C min:
Koelen minuten:
Spoelwater pH:
Whirlpool koud min:
 
BeluchtenNaar gistvat
Beluchten met:Koeler en trub verlies L:
SG in gistvat:
Beluchten tijd min:
Extra water in gistvat L:
Kleur in gistvat EBC:
Beluchten snelheid:
Volume naar gistvat L:
Bitterheid in gistvat IBU:
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hoofdvergisting
Begin vergisting SG:
Start temperatuur hoofdvergisting °C:
Piek temperatuur hoofdvergisting °C:
Eind temperatuur hoofdvergisting °C:
Eind hoofdvergisting SG:
Eind hoofdvergisting/overhevelen:
Schijnbare vergistingsgraad:

Nagisting
Temperatuur nagisting °C:
Eind nagisting SG:
Eind nagisting/start lageren:
Schijnbare vergistingsgraad %:

Lageren
Temperatuur lageren °C:
Het verwachte eind SG:
Het behaalde eind SG:
Alcoholgehalte voor hergisting vol.%:
Schijnbare vergistingsgraad %:
+
+ + +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Datum:
Aanbevolen volume CO2:

Verdunnen of infusie
Volume na vergisting L:
Toevoeging Liter:
Toevoeging ABV %:
Toevoeging omschrijving:
Alcohol volume %:
Bij verpakken pH:

FlessenFusten
Hoeveelheid Liter:
Hoeveelheid Liter:
Gewenst volume CO2:
Gewenst volume CO2:
Suiker:Suiker:
Toevoegen suiker g/L:
Toevoegen suiker g/L:
Suiker totaal gram:
Suiker totaal gram:
Suikeroplossing water L:
Suikeroplossing water L:
Op druk brengen met CO2:
Verwachte flesdruk in bar:
Druk op fust bar:
Alcoholgehalte flessen vol.%:
Alcoholgehalte fusten vol.%:
Hergisting temperatuur:
Keg temperatuur:
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Datum:
Cijfer:
Kleur:Helderheid:
Schuim:
Aroma:
Smaak:
Nasmaak:
Mondgevoel:
Oordeel:
+
+
+ +
+ +