Public
Edited
Oct 23, 2023
Insert cell
md`# tf react diffuse`
Insert cell
fk_combos
Insert cell
param_levels = ({
0.125: "ks1",
0.25: "epsilon1",
0.375: "zeta2",
0.5: "kappa1",
0.625: "delta2",
0.75: "sigma1",
0.875: "Beta1"
})
Insert cell
viewof param_select = make_param_select()
Insert cell
canv_chart = {
tf.disposeVariables()
console.log(tf.memory().numTensors);
const canvas = DOM.canvas(width, width);
const context = canvas.getContext("2d");
let xyz = d3.range(3).map( i => 20*Math.random() - 10);
//let xyz = [0,0,0];
let uvd = tf.tidy(() => {
let rs = rand_starts(N, Math.max(2,Math.floor(N/20)), Math.max(2,Math.floor(N*0.05)));
let uvdt = tf.stack([tf.ones([N, N], 'float32'),
tf.tensor2d(rs, [N, N], 'float32'),
tf.exp(tf.mul(-.015, dist_matrix(yscale(xyz[1]), xscale(xyz[0]))))
]);
return(tf.variable(uvdt, true));
});
let v = tf.tidy(() => uvd.slice([1, 0, 0], [1]).arraySync()[0]);
context.clearRect(0, 0, width, width);
v.map((row, i) => {
row.map((v, j) => {
context.fillStyle = fill_scale(v);
context.fillRect(bin_scale(i), bin_scale(j),
bin_scale.bandwidth(), bin_scale.bandwidth());
})
});
let varr = null;
for (let i = 1; i < 100000; i++) {
if (i % 10 == 0) {
let vmin = tf.tidy(() => uvd.slice([1, 0, 0], [1]).min().arraySync());
let vmax = tf.tidy(() => uvd.slice([1, 0, 0], [1]).max().arraySync());
let fill_delta = vmax-vmin;
fill_scale.domain([vmin, vmax]);
//fill_scale.domain(d3.range(0,1.2,0.2).map(v => vmin+v*fill_delta));
v = tf.tidy(() => uvd.slice([1, 0, 0], [1]).arraySync()[0]);
context.clearRect(0, 0, width, width);
context.fillStyle = fill_scale(vmin);
context.fillRect(0, 0, width, width);
v.map((row, i) => {
row.map((v, j) => {
if ((v-vmin)/(vmax-vmin) > 1.0/255) {
context.fillStyle = fill_scale(v);
context.fillRect(bin_scale(i), bin_scale(j),
bin_scale.bandwidth()+1, bin_scale.bandwidth()+1);
}
})
});
context.beginPath();
context.arc(xscale(xyz[0]), yscale(xyz[1]), 2, 0, 2 * Math.PI, false);
context.fillStyle = 'white';
context.fill();
yield context.canvas;
}
xyz = lorenz(xyz)
let uvdt = react_diffuse(uvd, xyz, i);
//uvt.print();
uvd.assign(uvdt);
uvdt.dispose();
}
tf.disposeVariables();
return null
}
Insert cell
N = 100
Insert cell
param_levels
Insert cell
fk_combos
Insert cell
["alpha2", "lambda2", "mu1", "kappa1"]
Insert cell
react_diffuse = (uv, xyz, i) => {
return tf.tidy( () => {
//const [f,k] = param_select.split(",").map(parseFloat);
//const [f, k] = [0.055, 0.063];
//const k = 0.063;
//const dm = tf.exp(tf.mul(-10, tf.pow(dist_matrix(yscale(xyz[1]), xscale(xyz[0])), 2)));
const alpha = 0.001;
const [u,v, dmn_old] = tf.unstack(uv);
const curr_dmn = norm_tensor(tf.exp(tf.mul(-0.015, dist_matrix(yscale(xyz[1]), xscale(xyz[0])))));
const dmn = tf.maximum(curr_dmn, tf.mul(1, dmn_old));
const f = discretize(dmn,
[0, 0.2, 0.4, 0.75, 1.1],
[0.014, 0.034, 0.046, 0.05]);
const k = discretize(dmn,
[0, 0.2, 0.4, 0.75, 1.1],
[0.053, 0.065, 0.065, 0.063]);
//const dm = tf.add(dm_old, tf.div(tf.sub(curr_dm ,dm_old), i));
//const dm = tf.add(tf.mul(alpha, curr_dm), tf.mul(1-alpha, dm_old));
//const dm = tf.add(dm_old, curr_dm);
//const dmt = tf.div(1, tf.add(1,tf.exp(tf.mul(-10, tf.sub(dmn, 0.4)))));
//const f = tf.add(tf.mul(dmn, 0.01), tf.mul(tf.sub(1, dmn), 0.082));
//const k = tf.add(tf.mul(dmn, 0.0545), tf.mul(tf.sub(1, dmn), 0.0635));
const diff_u = diffuse(u, r_u, dt, dx);
const diff_v = diffuse(v, r_v, dt, dx);
const uvv = tf.mul(u, tf.pow(v,2));
const fu = tf.mul(dt, tf.mul(f,tf.sub(1, u)));
const fk = tf.mul(dt, tf.mul(tf.add(f,k), v));
return tf.stack([tf.add(tf.sub(diff_u, tf.mul(dt, uvv)),fu),
tf.sub(tf.add(diff_v, tf.mul(dt, uvv)), fk),
dmn]);
//return tf.stack([f,k]);
})
}
Insert cell
discretize = (t, levels, values) => {
return tf.tidy(() => {
let td = t.clone();
for (let i=1; i < levels.length; i++) {
td = tf.where(tf.logicalAnd(tf.lessEqual(td, levels[i]),
tf.greater(td, levels[i-1])),
tf.mul(tf.onesLike(t), values[i-1]),
td);
}
return(td);
})
}
Insert cell
[1,2,3].length
Insert cell
fill_scale(1)
Insert cell
fill_scale = d3.scaleSequential((t) =>d3.interpolateMagma(t)).domain([0, 1])
//fill_scale = d3.scaleLinear()
// .range(["#000000", "#264653","#2a9d8f","#e9c46a", "#f4a261", "#e76f51"])
// .domain([0,0.2,0.4,0.6,0.8,1]);
//fill_scale = d3.scaleSequential(['#FFFFFF','#000000'])
// .domain([0, 1]);
//fill_scale = d3.scaleSequential((t) => d3.interpolateGnBu(t))
// .domain([0, 1])
Insert cell
param_chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, width])
.attr('width', width)
.attr('height', width);
let kscale = d3.scaleLinear([20, 700]).domain([0.045, 0.07]);
let fscale = d3.scaleLinear([20, 700]).domain([0.005, 0.115]);
const labs = svg.append('g')
.selectAll('text')
.data(fk_combos)
.join('text')
.attr('y', d => fscale(d.value[0]))
.attr('x', d => kscale(d.value[1]))
.attr('font-family', 'sans-serif')
.text(d => d.label);
const points = svg.append('g')
.selectAll('circle')
.data(fk_combos)
.join('circle')
.attr('cy', d=> fscale(d.value[0]))
.attr('cx', d=> kscale(d.value[1]))
.attr('r', 3)
.attr('fill', '#101010');
const l1 = svg.append('line')
.style("stroke", "black")
.style("stroke-width", 1)
.attr("x1", kscale(0.0545))
.attr('x2', kscale(0.0635))
.attr('y1', fscale(0.01))
.attr('y2', fscale(0.082));
const l2 = svg.append('line')
.style("stroke", "red")
.style("stroke-width", 1)
.attr("x1", kscale(0.058))
.attr('x2', kscale(0.07))
.attr('y1', fscale(0.066))
.attr('y2', fscale(0.05));
const l3 = svg.append('line')
.style('stroke', 'blue')
.style('stroke-width', 1)
.attr('x1', kscale(0.048))
.attr('x2', kscale(0.065))
.attr('y1', fscale(0.024))
.attr('y2', fscale(0.024))
return(svg.node());
}
Insert cell
norm_tensor = (t) => {
return tf.tidy(() => {
const dmin = tf.min(t);
const dmax = tf.max(t);
return tf.div(tf.sub(t, dmin), tf.sub(dmax, dmin));
});
}
Insert cell
dist_matrix = (x, y) => {
return tf.tidy(() => {
const xcoord = tf.mul(tf.ones([N,N], 'float32'), tf.range(0,N), [N,1])
const ycoord = tf.mul(tf.ones([N,N], 'float32'), tf.reshape(tf.range(0,N), [N,1]));
const dist = tf.pow(tf.add(tf.pow(tf.sub(xcoord, N/2), 2),tf.pow(tf.sub(ycoord, N/2), 2)), 0.5);
let xN = bin_scale.invert(x)-N/2 >0 ?bin_scale.invert(x)-N/2:N/2 + bin_scale.invert(x);
let yN = bin_scale.invert(y)-N/2 >0 ?bin_scale.invert(y)-N/2:N/2 + bin_scale.invert(y);;
const shift_up = tf.concat([tf.slice(dist, [N-yN, 0], [yN, N]),
tf.slice(dist, [0, 0], [N-yN, N])]);
const shifted = tf.concat([tf.slice(shift_up, [0, N-xN], [N, xN], 1),
tf.slice(shift_up, [0, 0], [N, N-xN], 1)],1);
return shifted;
})
}
Insert cell
zscale = d3.scaleLinear()
.domain([-5, 60])
.range([0, width]);
Insert cell
yscale = d3.scaleLinear()
.domain([-37, 37])
.range([0, width]);
Insert cell
xscale = d3.scaleLinear()
.domain([-37, 37])
.range([0, width]);
Insert cell
R = 28
Insert cell
B = 8/3
Insert cell
P = 10
Insert cell
lorenz = (xyz) => {
const [x, y, z] = xyz;
const ldt = 0.01;
return([x + ldt*(P*(y-x)),
y + ldt*(R*x - y - x*z),
z + ldt*(x*y-B*z)]);
}
Insert cell
diffuse = (a, r, dt, dx) => {
return tf.tidy(() => {
const au = tf.concat([tf.slice(a, [1,0]), tf.slice(a, [0,0], 1)]);
const ad = tf.concat([tf.slice(a, [N-1, 0], 1),
tf.slice(a, [0, 0], [N-1, N])]);
const al = tf.concat([tf.slice(a,[0,1]),tf.slice(a, [0,0], [N,1])], 1);
const ar = tf.concat([tf.slice(a, [0, N-1], [N,1]), tf.slice(a, [0,0], [N, N-1])], 1);
return(tf.add(a, tf.mul(r*dt, tf.div(tf.sub(tf.add(tf.add(au, ad), tf.add(al, ar)), tf.mul(4, a)), dx*dx))));
})
}
Insert cell
rand_starts = (n, n_seeds, r) => {
var a = d3.range(n).map(i => d3.range(n).map(j => 0))
for (var _ in d3.range(n_seeds)) {
var x = d3.randomInt(n)();
var y = d3.randomInt(n)();
d3.range(x-r, x+r).map( i => {
d3.range(y-r, y+r).map(j => {
a[j<0?j+n:j%n][i<0?i+n:i%n] = 1;
})
})
}
return(a)
}
Insert cell
console.log(bin_scale.invert(358))
Insert cell
bin_scale = {
let sB = d3.scaleBand()
.domain(d3.range(N))
.range([0, width])
.padding(0);
sB.invert = x => d3.scaleQuantize().domain(sB.range()).range(sB.domain())(x);
return(sB);
}
Insert cell
dx=1
Insert cell
dt=0.5
Insert cell
r_u = 0.2
Insert cell
r_v = 0.1
Insert cell
width = 720
Insert cell
tf = require('@tensorflow/tfjs@2.7.0')
Insert cell
make_param_select = () => {
const dd3 = select({
title: "Parameter Select",
options: fk_combos,
value: [0.026, 0.059]
});
dd3.input.style.fontSize = "30px";
dd3.input.style.marginTop = "8px";
return dd3;
}
Insert cell
console.log(d3.rollup(fk_combos, v => v.length, d=> d.value[1]))
Insert cell
fk_combos = [
{ label: "α1", value: [0.010, 0.047]},
{ label: "α2", value: [0.014, 0.053]},
{ label: "β1", value: [0.014, 0.039]},
{ label: "β2", value: [0.026, 0.051]},
{ label: "γ1", value: [0.022, 0.051]},
{ label: "γ2", value: [0.026, 0.055]},
{ label: "δ1", value: [0.030, 0.055]},
{ label: "δ2", value: [0.042, 0.059]},
{ label: "ε1", value: [0.018, 0.055]},
{ label: "ε2", value: [0.022, 0.059]},
{ label: "ζ1", value: [0.022, 0.061]},
{ label: "ζ2", value: [0.026, 0.059]},
{ label: "η1", value: [0.034, 0.063]},
{ label: "θ1", value: [0.030, 0.057]},
{ label: "θ2", value: [0.038, 0.061]},
{ label: "ι1", value: [0.046, 0.0594]},
{ label: "κ1", value: [0.050, 0.063]},
{ label: "κ2", value: [0.058, 0.063]},
{ label: "λ1", value: [0.026, 0.061]},
{ label: "λ2", value: [0.034, 0.065]},
{ label: "μ1", value: [0.046, 0.065]},
{ label: "μ2", value: [0.058, 0.065]},
{ label: "ν1", value: [0.054, 0.067]},
{ label: "ν2", value: [0.082, 0.063]},
{ label: "ξ1", value: [0.010, 0.041]},
{ label: "ξ2", value: [0.014, 0.047]},
{ label: "π2", value: [0.062, 0.061]},
{ label: "ρ1", value: [0.090, 0.059]},
{ label: "ρ2", value: [0.102, 0.055]},
{ label: "σ1", value: [0.090, 0.057]},
{ label: "σ2", value: [0.110, 0.0523]}
]
Insert cell
import {select} from "@jashkenas/inputs"
Insert cell
d3 = require('d3@6');
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more