// Global variables. Yeah yeah I know. Just felt like making this one as a procedural program rather than OOP. var width = 10, cells = [], cellWidth = 0.01, // 10 centimeters cellDepth = 0.01, // 10 millimeter cellEdgeArea = cellWidth*cellDepth, materialConductivities = {copper: 400, aluminum: 215, brick: 1.3, iron: 80}, // Assume constant. (W / m K) materialSpecificHeats = {copper: 390, aluminum: 910, brick: 900, iron: 450}, // Assume constant. (J / kg K) materialDensities = {copper: 8940, aluminum: 2712, brick: 2000, iron: 7850}, // Assume constant. (kg / m^3) convectionCoefficient = 30, // (W / m^2) currentMaterial = 'copper', inputHeat = 800, // Watts heatAppliedTo = 40, // Cell id# initialTemp = 295, // Room temperature. (K) lastTimestamp = null ; var createCells = function() { var table = $("#plate"); var index = 0; for (var row = 0; row < width; row += 1) { var tr = $("<tr>"); for (var col = 0; col < width; col += 1) { var td = $("<td>").attr("id", index); tr.append(td); cells[index] = initialTemp; index++; } table.append(tr); } }; var keyForNeighbor = function(myKey, whichNeighbor) { // whichNeighbor: 0 = north, 1 = east, 2 = south, 3 = west (clockwise) if (whichNeighbor === 0 && myKey >= width) return myKey - width; if (whichNeighbor === 1 && ( (myKey + 1) % width !== 0 ) ) return myKey + 1; if (whichNeighbor === 2 && myKey < (width*width - width) ) return myKey + width; if (whichNeighbor === 3 && myKey % width !== 0) return myKey - 1; return null; }; var _ = function(id) { return $("#" + id); }; var cellMass = function() { return cellWidth * cellWidth * cellDepth * materialDensities[currentMaterial]; }; var energyTransfer = function(myTemp, yourTemp, dTime) { var J = cellWidth * (yourTemp - myTemp) * materialConductivities[currentMaterial] * dTime; return J; // This is the heat transfer INTO the cell, though general convention is to measure transfer out. // Returns the number of Joules transfered into the cell in dTime seconds. }; var temperatureChange = function(energyIn) { var heatCapacity = cellMass() * materialSpecificHeats[currentMaterial]; return energyIn / heatCapacity; // Returns change of temp in K }; var updateCell = function(id, newTemp) { cells[id] = newTemp; //_(id).text(Math.round(newTemp)); }; var colorCells = function() { for (var i = 0, len = cells.length; i < len; i+=1) { var opacity = (cells[i] - initialTemp) / 2000; if (opacity > 1) opacity = 1; if (opacity < 0) opacity = 0; _(i).css("background", "rgba(255,0,0,"+opacity+")"); }; }; var loop = function() { var now = new Date().getTime(); var dTime = (now - lastTimestamp) / 1000; lastTimestamp = now; var cellCache = []; for (var i = 0, len = cells.length; i < len; i += 1) cellCache[i] = cells[i]; for (var i = 0, len = cells.length; i < len; i += 1) { var energyIn = 0; var myTemp = cellCache[i]; for (var n = 0; n < 4; n += 1) { var neighborKey = keyForNeighbor(i, n); if (neighborKey === null) continue; var neighborTemp = cellCache[neighborKey]; energyIn += energyTransfer(myTemp, neighborTemp, dTime); }; energyIn -= convectionCoefficient * cellWidth * cellWidth * 2 * (myTemp - initialTemp); if (i === heatAppliedTo) energyIn += inputHeat; updateCell(i, myTemp + temperatureChange(energyIn) ); }; colorCells(); }; $(document).ready(function() { lastTimestamp = new Date().getTime(); createCells(); $("td").click(function() { heatAppliedTo = parseInt($(this).attr("id")); }); setInterval(loop, 20); });
<table id="plate"> </table>
#plate { border-collapse:collapse; margin:20px auto; font-family:"Verdana", "Arial"; font-size:8px; text-align:center; color:#CCC; border: 1px solid #DDD; } #plate td { /*border:1px solid #DDD;*/ width:20px; height:20px; overflow:hidden; }