//////////////////////////////////////////////////////////////////// var dt = 50; // time between updates, in ms var celldimen = 10; var gensym = 0; var ngray = 64; maingrid = new Array; obj = new Array; // table of static objects, indexed by ID // Constants of nature: kboltz = 1.3806505e-23 // joules per kelvin navo = 6.0221415e23 // particles per mole // Returns an integer, randomly distributed // in the interval [0, n-1] function getRand(n){ var rslt; if (!n) { // We have been called be badly broken code: throw("getRand called with no argument???"); } while (1) { rslt = Math.floor(Math.random()*n); // there is an infinitesimal chance that Math.random will // return 1.0, which is not what we want: if (rslt < n) return rslt; } } function encode2hex(n, mindigs){ // if (typeof(mindigs) != "number") mindigs = 1; if (mindigs >= 0) {} else mindigs = 1; n = Math.floor(n); var hex = "0123456789abcdef"; var mask = 0xf; var rslt = ""; var digs = 0; while(n != 0 || digs < mindigs){ rslt = hex.charAt(n&mask) + rslt; n>>>=4; digs++; } return rslt; } function encode2dec(nx, mindigs){ // if (typeof(mindigs) != "number") mindigs = 1; if (mindigs >= 0) {} else mindigs = 1; var n = Math.abs(nx); n = Math.floor(n); var dec = "0123456789"; var rslt = ""; var digs = 0; while(n != 0 || digs < mindigs){ rslt = dec.charAt(n%10) + rslt; n = Math.floor(n/10); digs++; } return (nx<0? "-" : "") + rslt; } // Return a string specifying styles used in this document: function mystyle(){ var s = "" return s; } // This is the only document.write that we do: document.write(mystyle()); // (Everything else is handled by setting innerHTML // or fiddling with the class of existing objects.) // pr is a number in the interval [0 .. 1] // We choose to encode occupation-probability by the amount // of _ink_ we put in the cell (not the amount of light). function colorcode(pr, expo){ if (!expo) expo = 0; // default for missing arg // ii is an integer in the interval [0 .. ngray] inclusive var ii = Math.round(ngray*(1-pr)); if (expo && ii == 0) return "occ"; return "gr" + encode2dec(ii, 2); } // Here row is the number of rows _above_ the veil: function set_veil(mkr, row) { var grid = obj[mkr]; var newveil = grid.nrows - row; // At this point, newveil could have any value in [1 .. nrows]: if (grid.veil >= newveil) newveil -= 1; // Now, newveil could have any value in [0 .. nrows]: grid.veil = newveil; // Veil is the number of obscured rows. collapse(grid); } // Return a string that defines a table. function createTable(grid,nrows,ncols){ grid.stirring=false var s="
" + sym + " | " grid.getrow[p] = ii; p++ } // end loop over columns s += "" } // end loop over rows s += "
prb[" + p + "] = " + thisp.toFixed(2);
}
function exposed(grid, row){
return (row < (grid.nrows - grid.veil))
}
function exp_id(grid, id){
var row = grid.getrow[id];
var rslt = exposed(grid, row);
// alert ("id: " + id + " row: " + row + " expo: " + rslt);
return rslt;
}
function writeTable(grid,nrows,ncols){
if(!nrows)nrows=20
if(!ncols)ncols=20
grid.mkr = "table" + gensym++;
obj[grid.mkr] = grid;
var s=""
s += createTable(grid,nrows,ncols)
s += ""
var txt = document.getElementById("maingrid_place");
if (txt) {
txt.innerHTML = s
}
collapse(grid, 1);
}
function toggle_ex(grid) {
set_ex(grid, !grid.stirring);
}
function set_ex(grid, ex) {
grid.stirring = ex;
if (grid.stirring) {
jostle(grid);
}
}
function jostleObj(id){
jostle(obj[id]);
}
// Jostle the grid repeatedly:
function jostle(grid){
if (!grid.stirring) return;
jos_sub(grid);
// You cannot pass "jostle(grid)" to timeout,
// presumably because (grid) would be out-of-scope
// at the time the timeout happens.
// What's more puzzling is that both of the following
// fail also:
// setTimeout("jostle(" + grid + ")", dt)
// setTimeout("jostle(" + maingrid + ")", dt)
// Meanwhile "jostle(maingrid)" would work, but
// would defeat the purpose of having an argument
// to jostle.
// Workaround: use obj[mkr].
// There may be a more elegant way to do this, using
// getElementById somehow.
setTimeout("jostleObj(\"" + grid.mkr + "\")", dt)
}
// Jostle the grid once.
function jos_sub(grid){
var src=getRand(grid.nslots)
var dst=getRand(grid.nslots)
var sexpo = exp_id(grid, src);
var dexpo = exp_id(grid, dst);
var visp, veilp, veilv;
if ((!sexpo) || (!dexpo)) {
// number of visible particles:
visp = totalize(grid, 0, grid.nrows - grid.veil);
// number of veiled particles:
veilp = grid.totp - visp;
// number of veiled vacancies:
veilv = grid.veil*grid.ncols - veilp;
}
do { // set scope for 'break' statement
// Check if src is decrementable:
if (sexpo) { // src is exposed
if (grid.prb[src] == 0) break;
} else { // src is veiled
if (veilp < 1.0) break; // no veiled particles
}
// Check if dst is incrementable:
if (dexpo) { // dst is exposed
if (grid.prb[dst] == 1.0) break;
} else { // dst is veiled
if (veilv < 1.0) break; // no veiled vacancies
}
// If we get here, we're good to go.
if (sexpo) {
grid.prb[src] = 0;
grid.totp -= 1;
} else {
incdec(grid, veilp, -1)
}
if (dexpo) {
grid.prb[dst] = 1;
grid.totp++;
} else {
incdec(grid, veilp, 1)
}
conform(grid);
} while (false);
}
function incdec(grid, veilp, delta){
var nleft = Math.round(veilp + delta);
collapse_sub(grid, grid.nrows - grid.veil, nleft, veilp);
var itotp = Math.round(grid.totp + delta); // integer part
var chk = Math.round(10000*(totalize(grid)))/10000;
if (chk != itotp) {
if (0) alert("prob not conserved; veilp: " + veilp +
" delta: " + delta + " nleft: " + nleft +
" was:" + itotp + " now: " + chk);
grid.totp = chk; // kludge?
} else {
if (0) alert("prob conserved OK; veilp: " + veilp +
" delta: " + delta + " nleft: " + nleft +
" was:" + itotp + " now: " + chk);
grid.totp = itotp;
}
}
function plog2p(foo){
if (foo == 0) return 0;
return foo * Math.log(foo) / Math.LN2;
}
function eval_s(grid){
var rslt = 0;
var p = 0;
for(var ii=0; ii