Published
Edited
Jun 10, 2020
Insert cell
Insert cell
TDSESimulation()
Insert cell
playing
Insert cell
width
Insert cell
Insert cell
breakpoint = 900
Insert cell
function *TDSESimulation() {
potential() // set up potential texture
while (playing) {
regl.poll();

++mutable elapsedTime
if (elapsedTime > animationTimeLimit) {
reset();
}
// used to hold during click events when imported into another notebook, not relevant here
if (holdOnFirstFrame) {
reset();
}
// step through approximation, rendering each step to a frame buffer
setupDefault({time: elapsedTime}, () => {
psi_n({wave_position: wave_position, wave_unit_components: wave_unit_components});
k1();
k2();
k3();
k4();
combine_k();
})
if (width > breakpoint) {
let gl = regl._gl;
gl.enable(gl.SCISSOR_TEST);
gl.scissor(w-inset_w, 0, inset_w, inset_h);
gl.viewport(w-inset_w, 0, inset_w, inset_h);
if (selected_visualization == "probability") {
draw2DProbability();
}
if (selected_visualization == "probability_amplitude") {
draw2DProbabilityAmplitude();
}

gl.scissor(0, 0, w - inset_w, h);
gl.viewport(-w/6, 0, w, h);
camera(function () {
setup3DDefaults(() => {
if (selected_visualization == "probability") {
drawProbability();
}
if (selected_visualization == "probability_amplitude") {
drawProbabilityAmplitude();
}
drawPotential();
});
});
}
else {
if (selected_visualization == "probability") {
draw2DProbability();
}
if (selected_visualization == "probability_amplitude") {
draw2DProbabilityAmplitude();
}
}
yield regl.container;
}
if (!playing) {
while (true) {
if (elapsedTime < 1) {
// if we have reset the simulation, render the first step
setupDefault({time: elapsedTime}, () => {
psi_n({wave_position: wave_position, wave_unit_components: wave_unit_components});
k1();
k2();
k3();
k4();
combine_k();
})
}
if (width > breakpoint) {
let gl = regl._gl;
gl.enable(gl.SCISSOR_TEST);

gl.scissor(w-inset_w, 0, inset_w, inset_h);
gl.viewport(w-inset_w, 0, inset_w, inset_h);
if (selected_visualization == "probability") {
draw2DProbability();
}
if (selected_visualization == "probability_amplitude") {
draw2DProbabilityAmplitude();
}

gl.scissor(0, 0, w-inset_w, h);
gl.viewport(-inset_w/2, 0, w, h);
camera(function () {
setup3DDefaults(() => {
if (selected_visualization == "probability") {
drawProbability();
}
if (selected_visualization == "probability_amplitude") {
drawProbabilityAmplitude();
}
drawPotential();
});
});
}
else {
if (selected_visualization == "probability") {
draw2DProbability();
}
if (selected_visualization == "probability_amplitude") {
draw2DProbabilityAmplitude();
}
}
yield regl.container;
}
}}
Insert cell
{
width;
reset();
}
Insert cell
viewof restart = html`<button type="button" class="btn">Reset</button>`
Insert cell
viewof playToggle = {
const button = html`<button class="btn play">Start</button>`;
button.onclick = () => {
mutable playing = ! mutable playing;
};
return button;
}
Insert cell
viewof stopToggle = {
const button = html`<button class="btn stop">Stop</button>`;
button.onclick = () => {
mutable playing = ! mutable playing;
};
return button;
}
Insert cell
playing
Insert cell
mutable playing
Insert cell
Insert cell
viewof selected_visualization = html`
<select id="cars" class="btn">
<option value="probability">Probability</option>
<option value="probability_amplitude">Probability Amplitude</option>
</select>
`
Insert cell
Insert cell
Insert cell
Insert cell
viewof potential_selection = html`
<select class="btn">
<option value="${barrier}">Barrier</option>
<option value="${two_slit_potential}">Two Slit</option>
<option value="${scatter}">Scatter</option>
</select>
`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
camera = createCamera(regl, {
center: [0, -2, 0],
theta: 6.25 * Math.PI/6.0,
phi: Math.PI/4.0,
distance: 18.5,
damping: 0,
noScroll: false,
renderOnDirty: false,
zoomSpeed: 0, // disables zoom
rotationSpeed: 0.4,
element: regl.cameraDiv
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import
{
mutable elapsedTime,
shading_function,
kCombined,
potentialBuffer,
k1,
k2,
k3,
k4,
combine_k,
potential,
setupDefault,
psi_n,
}
with
{
TDSESimulation as TDSESimulation,
playing as playing,
animationTimeLimit as animationTimeLimit,
potential_selection as potential_function,
dt as dt,
dx as dx,
wave_position as wave_position,
wave_unit_components as wave_unit_components,
regl as regl,
createREGLInstance as createREGLInstance,
reset as reset,
}
from "@flimsyhat/tdse-simulation"
Insert cell
import
{
setup3DDefaults,
drawProbability,
drawProbabilityAmplitude,
barrier,
two_slit_potential,
scatter,
createCamera,
drawPotential,
elements,
xzPosition
}
with
{
TDSESimulation as TDSESimulation,
playing as playing,
animationTimeLimit as animationTimeLimit,
potential_selection as potential_function,
dt as dt,
dx as dx,
wave_position as wave_position,
wave_unit_components as wave_unit_components,
regl as regl,
createREGLInstance as createREGLInstance,
color_map as color_map,
kCombined as kCombined,
potentialBuffer,
reset as reset,
barrier_height as barrier_height,
camera as camera,
N as N
}
from "@flimsyhat/3d-view-of-tdse-simulation"
Insert cell
import
{ pointerdown, pointerup, pointermove, pointerout, wave_unit_components, holdOnFirstFrame }
with
{
mutable playing as playing,
regl as regl,
reset as reset,
mutable wave_angle as wave_angle,
mutable wave_position as wave_position,
}
from
"@flimsyhat/touch-interaction-for-tdse-simulation"
Insert cell
Insert cell
function clamp(number, min, max) {
return Math.max(min, Math.min(number, max));
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
regl.container.ontouchstart = e => {
if ( regl.topCanvas.contains(e.target) ) { e.preventDefault() };
}
}
Insert cell
function createREGLInstance () {
const container = document.createElement('div');
container.classList.add("container");
container.style.position = "relative";
container.style.width = w + 'px';
if (width > breakpoint) { container.style.height = h + 'px'; }
const glCanvas = document.createElement('canvas');
glCanvas.classList.add("glCanvas");
glCanvas.style.position = "absolute";
glCanvas.style.top = 0
glCanvas.style.left = 0;
glCanvas.style.width = w;
glCanvas.style.height = h;
glCanvas.style.zIndex = 1;
glCanvas.width = w;
glCanvas.height = h;
// used to provide an element to the camera, so it can properly calculate width and height of the 3D area
const cameraDiv = document.createElement('div');
cameraDiv.classList.add("cameraDiv");
cameraDiv.style.position = "absolute";
cameraDiv.style.top = 0
cameraDiv.style.left = 0;
cameraDiv.style.width = 2 * w / 3 + 'px';
cameraDiv.style.height = h + 'px';
cameraDiv.style.zIndex = 2;
if (width > breakpoint) {
cameraDiv.style.display = "block;"
}
else {
cameraDiv.style.display = "none";
}
const topCanvas = document.createElement('canvas');
topCanvas.classList.add("topCanvas");
topCanvas.style.bottom = 0
topCanvas.style.left = w - inset_w +'px';
topCanvas.style.width = inset_w + 'px';
topCanvas.style.height = inset_h + 'px';
topCanvas.style.zIndex = 2;
topCanvas.width = inset_w;
topCanvas.height = inset_h;
const controls = document.createElement('div');
controls.classList.add("controls");
if (width > breakpoint) {
controls.style.position = "absolute";
controls.style.top = 0;
controls.style.left = w - inset_w +'px';
controls.style.width = inset_w + 'px';
controls.style.height = inset_h + 'px';
}
else {
controls.style.position = "relative";
controls.style.width = "100%";
}
controls.style.zIndex = 3;
function addLabel(text) {
let d = document.createElement('span');
let n = document.createTextNode(text);
d.appendChild(n);
return d
}
function addText(text) {
let d = document.createElement('p');
let n = document.createTextNode(text);
d.appendChild(n);
return d
}
controls.appendChild(viewof playToggle);
controls.appendChild(viewof stopToggle);
controls.appendChild(viewof restart);
controls.appendChild(document.createElement('br'));
controls.appendChild(addLabel("Visualization:"));
controls.appendChild(viewof selected_visualization);
controls.appendChild(document.createElement('br'));
controls.appendChild(addLabel("Potential:"));
controls.appendChild(viewof potential_selection);
// let d = document.createElement('div');
// d.classList.add("barrier-slider");
// d.appendChild(document.createElement('br'));
// d.appendChild(addLabel("Barrier Height:"));
// d.appendChild(viewof barrier_height);
// d.appendChild(document.createElement('br'));
// controls.appendChild(d)
if (width > breakpoint) {
controls.appendChild(document.createElement('br'));
controls.appendChild(addText("Click and drag the 3D representation to the left to change the view."))
controls.appendChild(addText("Click and drag the 2D representation below to set the initial wavepacket position and direction. Release to start the simulation."));
}
else {
controls.appendChild(document.createElement('br'));
controls.appendChild(addText("Click and drag above to set the initial wavepacket position and direction. Release to start the simulation."));
}
container.appendChild(glCanvas);
container.appendChild(cameraDiv);
container.appendChild(topCanvas);
container.appendChild(controls);

const regl = createREGL(
Object.assign({canvas: glCanvas, extensions: 'OES_texture_float'}))
regl.cameraDiv = cameraDiv;
regl.canvas = glCanvas;
regl.topCanvas = topCanvas;
regl.container = container;
return regl
}
Insert cell
html`<style>
@import url('https://rsms.me/inter/inter.css');
.glCanvas {background-color: #fafafa;}
.container {overflow: hidden;}
.container {border: 2px solid black;}
.controls, .topCanvas {border-left: 2px solid black;}
.controls {
padding: 15px;
font-family: 'Inter', sans-serif !important;
background-color: #fafafa;
color: black;
border-bottom: 2px solid black;
z-index: -1;
font-size: 14px;
}
.barrier-slider {
margin-top: -20px;
}
.controls p {
font-size: 13px;
margin-right: 35px;
}
.controls span {
margin-right: 5px;
}
.controls .slider {
max-width: 150px;
}
.btn {
padding: 10px;
font-size: 14px;
margin-right: 10px;
margin-bottom: 15px;
border-radius: 5px;
background-color: white;
border: 1px solid black;

.container, .topCanvas {
touch-action: none;
}
</style>`
Insert cell
{
if (potential_selection == barrier) { return html`<style>.barrier-slider {display: block}</style>`}
else { return html`<style>.barrier-slider {display: none}</style>` }
}
Insert cell
{
if (playing) { return html`<style>.stop {display: inline-block} .play {display: none}</style>`}
else { return html`<style>.stop {display: none} .play {display: inline-block}</style>` }
}
Insert cell
{
if (width > breakpoint) {
return html`
<style>
.topCanvas {
position: absolute;
}
</style>`}
else {
return html`
<style>
.topCanvas {
position: relative;
}
.controls {
border: 0px solid;
}
</style>`}
}
Insert cell
Insert cell
Insert cell
N = 254
Insert cell
Insert cell
512 / width / 140
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
reset = () => {
mutable elapsedTime = -1;
mutable tick = 0;
}
Insert cell
{
potential_selection;
restart;
reset();
}
Insert cell
Insert cell
Insert cell
{
while (playing) {
await Promises.delay(1000);
yield ++mutable tick
}
}
Insert cell
Insert cell
function windowed_average(series, length) {
if (values.length < length) {
values.push(series)
}
else {
values.shift()
values.push(series)
}
const sum = values.reduce((a, b) => a + b, 0);
const avg = (sum / values.length) || 0;
return avg
}
Insert cell
mutable values = []
Insert cell
windowed_average(framerate, 100)
Insert cell
fps = (windowed_average(framerate, 100)).toLocaleString()
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more