diff -r 029e65ca3678 -r 1246550451ca www/js/rec_edit.js --- a/www/js/rec_edit.js Fri May 01 21:37:23 2020 +0200 +++ b/www/js/rec_edit.js Wed May 06 14:14:14 2020 +0200 @@ -48,7 +48,12 @@ MMNaHCO3 = 84.007, MMNa2CO3 = 105.996, MMNaCl = 58.443, - MMCaOH2 = 74.06268; + MMCaOH2 = 74.06268, + SpecificHeatWater = 1.0, + SpecificHeatMalt = 0.399, //cal/g.°C + SlakingHeat = 10.318, //cal/g.°C + eq_tun_weight = 2.0, // 2 Kg pot + eq_tun_specific_heat = 0.110, // Stainless Steel data_loaded = 0; function createDelElements() { @@ -348,18 +353,90 @@ } +function swapMash(r1, r2) { + + console.log('swap mash rows ' + r1 + ' ' + r2); + var row1 = $('#mashGrid').jqxGrid('getrowdata', r1); + var row2 = $('#mashGrid').jqxGrid('getrowdata', r2); + var obj1 = { step_name: row1.step_name, step_type: row1.step_type, step_volume: row1.step_volume, step_infuse_amount: row1.step_infuse_amount, + step_infuse_temp: row1.step_infuse_temp, step_temp: row1.step_temp, step_time: row1.step_time, + ramp_time: row1.ramp_time, end_temp: row1.end_temp, step_wg_ratio: row1.step_wg_ratio }; + var obj2 = { step_name: row2.step_name, step_type: row2.step_type, step_volume: row2.step_volume, step_infuse_amount: row2.step_infuse_amount, + step_infuse_temp: row2.step_infuse_temp, step_temp: row2.step_temp, step_time: row2.step_time, + ramp_time: row2.ramp_time, end_temp: row2.end_temp, step_wg_ratio: row2.step_wg_ratio }; + $("#mashGrid").jqxGrid('updaterow', r1, obj2); + $("#mashGrid").jqxGrid('updaterow', r2, obj1); +} + + +function infusionVol(step_infused, step_mashkg, infuse_temp, step_temp, last_temp) { + var a = last_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + var b = step_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + var vol = Round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)), 2); + console.log('infusionVol(' + step_infused + ', ' + step_mashkg + ', ' + infuse_temp + ', ' + step_temp + ', ' + last_temp + '): ' + vol); + return vol; +} + + +function decoctionVol(step_volume, step_temp, prev_temp) { + var a = (eq_tun_weight * 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); + console.log('decoctionVol(' + step_volume + ', ' + step_temp + ', ' + prev_temp + '): ' + vol); + return vol; +} + + function calcMash() { - var infused = 0, i, row, rows; - if (!(rows = $('#mashGrid').jqxGrid('getrows'))) - return; - if (mashkg == 0) - return; + var infused = 0, vol, i, j, n, a, b, row, rows, temp; + var lasttemp = 18.0; + var graintemp = 18.0; + var tuntemp = 18.0; - for (i = 0; i < rows.length; i++) { - row = $('#mashGrid').jqxGrid('getrowdata', i); - if (row.step_type == 0) // Infusion - infused += row.step_infuse_amount; - $('#mashGrid').jqxGrid('setcellvalue', i, 'step_thickness', infused / mashkg); + if ((rows = $('#mashGrid').jqxGrid('getrows')) && (mashkg > 0)) { + console.log('calcMash()'); + for (i = 0; i < rows.length; i++) { + row = $('#mashGrid').jqxGrid('getrowdata', 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 + eq_tun_weight * tuntemp * eq_tun_specific_heat; + b = row.step_temp * (eq_tun_weight * 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 += 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); + } } } @@ -1685,18 +1762,6 @@ // inline mash editor var editMash = function(data) { - var generaterow = function() { - var row = {}; - row['step_name'] = 'Stap 1'; - row['step_type'] = 0; - row['step_infuse_amount'] = 15; - row['step_temp'] = 62.0; - row['step_time'] = 20.0; - row['step_thickness'] = 0; - row['ramp_time'] = 1.0; - row['end_temp'] = 62.0; - return row; - }; var mashSource = { localdata: data.mashs, datatype: 'local', @@ -1705,19 +1770,17 @@ 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_thickness', type: 'float' }, + { name: 'step_wg_ratio', type: 'float' }, { name: 'ramp_time', type: 'float' }, { name: 'end_temp', type: 'float' } ], - addrow: function(rowid, rowdata, position, commit) { - commit(true); - }, - deleterow: function(rowid, commit) { - commit(true); - } + addrow: function(rowid, rowdata, position, commit) { commit(true); }, + deleterow: function(rowid, commit) { commit(true); } }, mashAdapter = new $.jqx.dataAdapter(mashSource, { beforeLoadComplete: function(records) { @@ -1727,7 +1790,7 @@ row = records[i]; if (row.step_type == 0) // Infusion mash_infuse += parseFloat(row.step_infuse_amount); - row.step_thickness = 0; // Init this field. + row.step_wg_ratio = 0; // Init this field. data.push(row); } }, @@ -1747,8 +1810,25 @@ container.append(''); $('#saddrowbutton').jqxButton({ template: 'primary', theme: theme, height: 27, width: 150 }); $('#saddrowbutton').on('click', function() { - var datarow = generaterow(); + var row = {}, rowscount = $('#mashGrid').jqxGrid('getdatainformation').rowscount; + row['step_name'] = 'Stap ' + (rowscount + 1); + if (rowscount > 0) { + row['step_type'] = 1; + row['step_infuse_amount'] = 0; + row['step_volume'] = mash_infuse; + } else { + row['step_type'] = 0; + row['step_infuse_amount'] = 15; + row['step_volume'] = 15; + } + row['step_infuse_temp'] = 0; + row['step_temp'] = 62.0; + row['step_time'] = 20.0; + row['step_wg_ratio'] = 0; + row['ramp_time'] = 1.0; + row['end_temp'] = 62.0; $('#mashGrid').jqxGrid('addrow', null, datarow); + calcMash(); }); // delete selected yeast. $('#sdeleterowbutton').jqxButton({ template: 'danger', theme: theme, height: 27, width: 150 }); @@ -1758,6 +1838,7 @@ if (selectedrowindex >= 0 && selectedrowindex < rowscount) { id = $('#mashGrid').jqxGrid('getrowid', selectedrowindex); $('#mashGrid').jqxGrid('deleterow', id); + calcMash(); } }); }, @@ -1779,27 +1860,82 @@ { text: 'Eind °C', datafield: 'end_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, { text: 'Rust min.', datafield: 'step_time', width: 90, align: 'right', cellsalign: 'right' }, { text: 'Stap min.', datafield: 'ramp_time', width: 90, align: 'right', cellsalign: 'right' }, - { text: 'Infuse L.', datafield: 'step_infuse_amount', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, - { text: 'L/Kg.', datafield: 'step_thickness', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f2' }, - { text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', + { text: 'Inf/dec L.', datafield: 'step_infuse_amount', width: 90, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + if (rowdata.step_type == 1) + return ''; + 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: 90, 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: '', columntype: 'button', width: 15, align: 'center', + cellsrenderer: function(row) { + if (row < 2) + return ' '; + return '▴'; + }, buttonclick: function(row) { + if (row >= 2) { + swapMash(row, row-1); + } + } + }, + { text: '', columntype: 'button', width: 15, align: 'center', + cellsrenderer: function(row) { + rowscount = $('#mashGrid').jqxGrid('getdatainformation').rowscount; + if (row < 1 || row > (rowscount -2)) + return ' '; + return '▾'; + }, buttonclick: function(row) { + rowscount = $('#mashGrid').jqxGrid('getdatainformation').rowscount; + if (row >= 1 && row <= (rowscount -2)) { + swapMash(row, row+1); + } + } + }, + { text: '', datafield: 'Edit', columntype: 'button', width: 80, align: 'center', cellsrenderer: function() { return 'Wijzig'; }, buttonclick: function(row) { mashRow = row; mashData = $('#mashGrid').jqxGrid('getrowdata', mashRow); + if (mashRow == 0) + $("#wstep_type").jqxDropDownList('disableAt', 2); + else + $("#wstep_type").jqxDropDownList('enableAt', 2); $('#wstep_name').val(mashData.step_name); $('#wstep_type').val(mashData.step_type); $('#wstep_infuse_amount').val(mashData.step_infuse_amount); + $('#wstep_infuse_temp').val(mashData.step_infuse_temp); $('#wstep_temp').val(mashData.step_temp); $('#wend_temp').val(mashData.end_temp); $('#wstep_time').val(mashData.step_time); $('#wramp_time').val(mashData.ramp_time); + $('#wstep_infuse_amount').hide(); // Hide all untile we need it. + $('#wstep_infuse_temp').hide(); + $('#wstep_pmpt_amount').hide(); + $('#wstep_pmpt_temp').hide(); if (mashData.step_type == 0) { - $('#wstep_infuse_amount').show(); - $('#wstep_pmpt').show(); - } else { - $('#wstep_infuse_amount').hide(); - $('#wstep_pmpt').hide(); + if (mashRow == 0) { + $('#wstep_infuse_amount').show(); + $('#wstep_pmpt_amount').show(); + } else { + $('#wstep_infuse_temp').show(); + $('#wstep_pmpt_temp').show(); + } } // show the popup window. $('#popupMash').jqxWindow('open'); @@ -1826,7 +1962,6 @@ theme: theme }); - function setWaterAgent(name, amount) { var record, records, miscs, i, id, row, found = false, rows = $('#miscGrid').jqxGrid('getrows'); @@ -3582,7 +3717,7 @@ }); $('#mash_select').on('select', function(event) { if (event.args) { - var data, datarecord, i, row, rows, rowIDs, index = event.args.index; + var infused = 0, data, datarecord, i, row, rows, rowIDs, index = event.args.index; // First delete all current steps rowIDs = new Array(); rows = $('#mashGrid').jqxGrid('getdisplayrows'); @@ -3598,29 +3733,37 @@ data = datarecord.steps[i]; row = {}; row['step_name'] = data.step_name; - row['step_type'] = data.step_type; - // For now, but this must be smarter. - if (mash_infuse == 0 && dataRecord.w1_amount > 0) - mash_infuse = dataRecord.w1_amount; - if (i == 0) - row['step_infuse_amount'] = mash_infuse; + row['step_type'] = parseInt(data.step_type); + row['step_temp'] = parseFloat(data.step_temp); + row['end_temp'] = parseFloat(data.end_temp); + row['step_time'] = parseFloat(data.step_time); + row['ramp_time'] = parseFloat(data.ramp_time); + row['step_infuse_temp'] = 0.0; + row['step_infuse_amount'] = 0.0; + if (mash_infuse == 0 && dataRecord.wg_amount > 0) + mash_infuse = dataRecord.wg_amount; + if (data.step_type == 0) { // Infusion + if (i == 0) { + row['step_infuse_amount'] = parseFloat(mash_infuse); + } else { + row['step_infuse_temp'] = 99.0; + } + } + //console.log(i + ' type: ' + row['step_type'] + ' start infusion: ' + parseFloat(row['step_infuse_amount']) + ' mash_infuse: ' + mash_infuse); + infused += parseFloat(row['step_infuse_amount']); + row['step_volume'] = infused; + if (mashkg > 0) + row['step_wg_ratio'] = Round(parseFloat(mash_infuse / mashkg), 2); else - row['step_infuse_amount'] = 0; - row['step_temp'] = data.step_temp; - if (mashkg > 0) - row['step_thickness'] = parseFloat(mash_infuse / mashkg); - else - row['step_thickness'] = 0; - row['end_temp'] = data.end_temp; - row['step_time'] = data.step_time; - row['ramp_time'] = data.ramp_time; + row['step_wg_ratio'] = 0; $('#mashGrid').jqxGrid('addrow', null, row); } + calcMash(); } }); $('#popupMash').jqxWindow({ width: 800, - height: 350, + height: 375, position: { x: 230, y: 100 }, resizable: false, theme: theme, @@ -3636,7 +3779,7 @@ $('#wstep_name').jqxInput({ theme: theme, width: 320, height: 23 }); $('#wstep_name').on('change', function(event) { var rowdata = $('#mashGrid').jqxGrid('getrowdata', mashRow); - rowdata.step_name = event.args.value; + rowdata.step_name = $('#wstep_name').val(); }); $('#wstep_type').jqxDropDownList({ theme: theme, @@ -3651,28 +3794,61 @@ if (event.args) { var rowdata, rows, i, row, index = event.args.index; rowdata = $('#mashGrid').jqxGrid('getrowdata', mashRow); - rowdata.step_type = index; - if (index == 0) { - $('#wstep_infuse_amount').show(); - $('#wstep_pmpt').show(); - } else { - rowdata.step_infuse_amount = 0; + if (rowdata.step_type != index) { + rowdata.step_type = index; $('#wstep_infuse_amount').hide(); - $('#wstep_pmpt').hide(); - } - mash_infuse = 0; - rows = $('#mashGrid').jqxGrid('getrows'); - for (i = 0; i < rows.length; i++) { - row = rows[i]; - if (row.step_type == 0) // Infusion - mash_infuse += parseFloat(row.step_infuse_amount); + $('#wstep_infuse_temp').hide(); + $('#wstep_pmpt_amount').hide(); + $('#wstep_pmpt_temp').hide(); + if (index == 0) { // Infusion + if (mashRow == 0) { + $('#wstep_infuse_amount').show(); + $('#wstep_pmpt_amount').show(); + } else { + $('#wstep_infuse_temp').show(); + $('#wstep_pmpt_temp').show(); + } + } + if (index == 1) { // Temperature + if (mashRow > 0) + rowdata.step_infuse_amount = 0; + rowdata.step_infuse_temp = 0; + } + if (index == 2) { // Decoction + var rowprev = $('#mashGrid').jqxGrid('getrowdata', mashRow-1); + rowdata.step_infuse_temp = 99; + rowdata.step_infuse_amount = decoctionVol(rowdata.step_volume, rowdata.step_temp, rowprev.end_temp); + console.log('decoction: ' + rowdata.step_infuse_amount + '/' + rowdata.step_infuse_temp); + } + $('#mashGrid').jqxGrid('updaterow', mashRow, rowdata); + mash_infuse = 0; + rows = $('#mashGrid').jqxGrid('getrows'); + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.step_type == 0) // Infusion + mash_infuse += parseFloat(row.step_infuse_amount); + } + calcMash(); } } }); $('#wstep_temp').jqxNumberInput(Spin1dec); $('#wstep_temp').on('change', function(event) { var rowdata = $('#mashGrid').jqxGrid('getrowdata', mashRow); - rowdata.step_temp = parseFloat(event.args.value); + if (rowdata.step_type == 2) { // Decoction + var rowprev = $('#mashGrid').jqxGrid('getrowdata', mashRow-1); + var a = (eq_tun_weight * eq_tun_specific_heat + rowdata.step_volume * SpecificHeatWater) * + (parseFloat(event.args.value) - rowprev.end_temp); + var b = SpecificHeatWater * (99 - parseFloat(event.args.value)); + if (b > 0) { + rowdata.step_temp = parseFloat(event.args.value); + rowdata.step_infuse_amount = Round(a / b, 2); + } else + rowdata.step_infuse_amount = 0; + console.log('change temp ' + rowdata.step_temp + ' decoction: ' + rowdata.step_infuse_amount + '/' + rowdata.step_infuse_temp); + } else { + rowdata.step_temp = parseFloat(event.args.value); + } }); $('#wend_temp').jqxNumberInput(Spin1dec); $('#wend_temp').on('change', function(event) { @@ -3693,23 +3869,40 @@ $('#wstep_infuse_amount').on('change', function(event) { var i, rows, row, rowdata = $('#mashGrid').jqxGrid('getrowdata', mashRow); rowdata.step_infuse_amount = parseFloat(event.args.value); - mash_infuse = 0; - rows = $('#mashGrid').jqxGrid('getrows'); - for (i = 0; i < rows.length; i++) { - row = rows[i]; - if (row.step_type == 0) // Infusion - mash_infuse += parseFloat(row.step_infuse_amount); + if (mashRow == 0) { + rowdata.step_infuse_amount = parseFloat(event.args.value); + mash_infuse = 0; + rows = $('#mashGrid').jqxGrid('getrows'); + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.step_type == 0) // Infusion + mash_infuse += parseFloat(row.step_infuse_amount); + } + if (dataRecord.w2_amount == 0) { + dataRecord.w1_amount = mash_infuse; + $('#w1_amount').val(mash_infuse); + } else { + var w1_amount = (dataRecord.w1_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse; + var w2_amount = (dataRecord.w2_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse; + dataRecord.w1_amount = Round(w1_amount, 3); + dataRecord.w2_amount = Round(w2_amount, 3); + $('#w1_amount').val(dataRecord.w1_amount); + $('#w2_amount').val(dataRecord.w2_amount); + } + $('#wg_amount').val(mash_infuse); + console.log('new infuse amount: ' + mash_infuse); + calcWater(); } - if (dataRecord.w2_amount == 0) { - dataRecord.w1_amount = mash_infuse; - $('#w1_amount').val(mash_infuse); - } else { - dataRecord.w1_amount = (dataRecord.w1_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse; - dataRecord.w2_amount = (dataRecord.w2_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse; - $('#w1_amount').val(dataRecord.w1_amount); - $('#w2_amount').val(dataRecord.w2_amount); - } - $('#wg_amount').val(mash_infuse); + }); + $('#wstep_infuse_temp').jqxNumberInput(Spin1dec); + $('#wstep_infuse_temp').on('change', function(event) { + var prevdata = $('#mashGrid').jqxGrid('getrowdata', mashRow-1); + var rowdata = $('#mashGrid').jqxGrid('getrowdata', mashRow); + rowdata.step_infuse_temp = parseFloat(event.args.value); + var vol = infusionVol(prevdata.step_volume, mashkg, rowdata.step_infuse_temp, rowdata.step_temp, prevdata.end_temp); + console.log('new vol: ' + vol); + rowdata.step_infuse_amount = vol; + $('#wstep_infuse_amount').val(vol); }); // Tab 7, Water