Brownian motion · Laboratory preview

From wandering
to a measurable spread.

How far from its starting point might a suspended particle be? Change the time, viscosity or radius, then ask about a whole interval, not just a single position.

Start with the no-algebra encounter →

Read the argument and open its missing steps →

Start from a pinned tracer trial and bring its D into this question →

BM-06 · An executable model

The spreading laboratory

Ideal model, host calculation

CurrentThese numbers match the current settings.

Model note
  • Primary output diffusionCoefficient: Host calculation (diffusion.stokesEinsteinD). Owner diffusion.stokesEinsteinD.
  • Primary output activeDiffusionCoefficient: Host calculation (bm06.evaluate). Owner bm06.evaluate.
  • Primary output rmsDisplacement1d: Host calculation (diffusion.rmsDisplacement). Owner diffusion.rmsDisplacement.
  • Primary output meanSquareDisplacement1d: Host calculation (diffusion.moments). Owner diffusion.moments.
  • Primary output intervalProbability: Host calculation (diffusion.intervalProbability). Owner diffusion.intervalProbability.
  • Primary output positionCoordinate1d: Host calculation (bm06.evaluate). Owner bm06.evaluate.
  • Primary output probabilityDensity: Host calculation (diffusion.gaussianPropagator). Owner diffusion.gaussianPropagator.
  • Primary output comparisonTimes: Host calculation (bm06.evaluate). Owner bm06.evaluate.
  • Primary output comparisonRms: Host calculation (diffusion.rmsDisplacement). Owner diffusion.rmsDisplacement.
  • Primary output meanRadius2d: Host calculation (diffusion.moments). Owner diffusion.moments.
  • Primary output rmsRadius2d: Host calculation (diffusion.moments). Owner diffusion.moments.
  • Primary output mostLikelyRadius2d: Host calculation (diffusion.mostLikelyRadius2d). Owner diffusion.mostLikelyRadius2d.
  • Primary output meanRadius3d: Host calculation (diffusion.moments). Owner diffusion.moments.
  • Primary output rmsRadius3d: Host calculation (diffusion.moments). Owner diffusion.moments.
  • Primary output gridDensity: Host calculation (diffusion.ftcs1d). Owner diffusion.ftcs1d.
  • Primary output cellMasses: Host calculation (diffusion.ftcsAnalyticComparison). Owner diffusion.ftcsAnalyticComparison.
  • Primary output cellProbabilities: Host calculation (diffusion.ftcsAnalyticComparison). Owner diffusion.ftcsAnalyticComparison.
  • Primary output maxCellMassDifference: Host calculation (diffusion.ftcsAnalyticComparison). Owner diffusion.ftcsAnalyticComparison.
  • Primary output wallContact: Host calculation (diffusion.ftcsAnalyticComparison). Owner diffusion.ftcsAnalyticComparison.
  • Primary output stabilityRatio: Host calculation (diffusion.ftcs1d). Owner diffusion.ftcs1d.
  • Primary output gridTimeStep: Host calculation (bm06.evaluate). Owner bm06.evaluate.
  • Accepted input revision 1.
  • Snapshot version 1.
  • Not modeled: The ballistic short-time regime and inertia.
  • Show the code

Choose an interval and ask how likely a tracer is to finish inside it. Changing a field only edits a request. The plot and table change together after you apply valid settings.

Set up the question

Positive temperature, viscosity and radius; nonnegative time. Interval endpoints are closed. Grid: 3–4097 cells and a separate work budget. Values outside a calculation’s domain are refused, never clamped.

Accepted result: RMS displacement 0.92676 micrometres; selected interval probability 71.943 percent.

Accepted settings
293.15 K · 1 mPa·s · radius 0.5 μm · elapsed 1 s
Constants: modern SI (2019). Viscosity is a declared input, not inferred from temperature. D is calculated from these physical inputs.
Displacement probability densityA symmetric model density centered at zero. The selected interval is shaded. Peak density is 0.43047 per micrometre. The probability and interval are also given in the results table.Density (per μm)-3.70703.707Signed displacement (μm)
The curve shows four RMS distances on either side of zero. The interval probability uses the full unbounded model, including any part outside this picture.
One accepted calculation, in explicit units
Diffusion coefficient0.42944 μm²/s
RMS displacement0.92676 μm
Mean square displacement0.85888 μm²
Selected closed interval[-1, 1] μm
Probability inside that interval71.943%

Density is measured per unit length; probability is a dimensionless area. A taller curve is not a larger total probability.

One setup, three observation times

Calculated from the same accepted diffusivity
Elapsed timeRMS displacement
1 s0.92676 μm
10 s2.9307 μm
60 s7.1786 μm

The same spread, as a 2D or 3D radius

A radius is not a signed coordinate: it is never negative, and the growing circumference (2D) or surface area (3D) of positions at a given distance changes which average is largest.

Radial moments at the accepted diffusivity and elapsed time
Quantity2D radius3D radius
Mean radius ⟨r⟩1.1615 μm1.4789 μm
RMS radius √⟨r²⟩1.3106 μm1.6052 μm
Most likely radius0.92676 μmnot modeled

The mean 2D radius <r> = sqrt(pi D t / 2) is smaller than the RMS radius sqrt(<r^2>) = sqrt(4 D t): the extra factor of r in the 2D density weights larger radii more heavily than a signed 1D coordinate does, so the two averages of the same spread disagree.

The RMS 2D radius sqrt(<r^2>) = sqrt(4 D t) is the square root of the mean squared distance from the start, not the mean distance itself -- squaring before averaging always weights the tail more than averaging the radius directly.

The most likely 2D radius, where the density p_r(r,t) = (r / 2Dt) e^(-r^2/4Dt) peaks, is sqrt(2 D t): the same number as the 1D RMS displacement. The growing circumference of available positions at radius r (proportional to r itself) exactly cancels the falling Gaussian density near the start, moving the peak away from the origin.

The mean 3D radius <r> = 4 sqrt(D t / pi) counts positions on a growing sphere (area proportional to r^2), pulling the average distance from the start out further than the 2D circumference case.

The RMS 3D radius sqrt(<r^2>) = sqrt(6 D t) reflects three independent coordinate directions, each contributing its own 2 D t to the mean squared displacement (compare the 1D case's single 2 D t).

What this model leaves out

Dilute spherical tracers in a homogeneous Newtonian liquid; no drift or particle interactions.

Low Reynolds number and times long compared with momentum relaxation are assumed, not checked.

The analytic curve describes an unbounded line; the numerical grid has reflecting walls.

These are consequences of a model, not measurements or evidence that the model describes nature.

No FrankenSim artifact is used here. A verified historical transcription and the full critical edition are still in preparation.

Show the calculation owner and source identity

Density, interval probability and displacement come from src/physics/reference/diffusion/distributions.ts. The grid comes from src/physics/reference/diffusion/ftcs.ts. One worker operation assembles all views.

source:sha256:dc169c752c5e4796eaea3df6e77f15bf8def24ccf00cf445ff9162d625f0ccfb

Read the calculation source

The source link opens current main, which may differ from this build. The digest above identifies the evaluator sources used by this page.

Show the code

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

gaussianPropagator · src/physics/reference/diffusion/distributions.ts · revision workspace · sha256:08378ddf8b6720db47f4949e26c3bb6de95c5ab5ba5851fe4b52b651ef62f55a

This is the function that produced the current snapshot.

In words

On an unbounded line the probability density is a Gaussian whose width grows as the square root of elapsed time.

Mathematics

Implementation

export function gaussianPropagator(x: number, t: number, D: number): Evaluation {
  if (!Number.isFinite(x) || !validDt(D, t))
    return outside(
      "probabilityDensity",
      "gaussianPropagator",
      "finite x, D >= 0, t >= 0",
      "Use finite position and nonnegative diffusivity and time.",
    );
  if (D === 0 || t === 0) return pointMass("probabilityDensity", "gaussianPropagator");
  const sigma = scale(D, t);
  const z = x / sigma;
  if (!(sigma > 0) || !Number.isFinite(sigma))
    return outside(
      "probabilityDensity",
      "gaussianPropagator",
      "representable spread",
      "The spread is outside the numerical range.",
      "numerical",
    );
  return number(
    "probabilityDensity",
    "gaussianPropagator",
    Math.exp(-Math.log(sigma) - 0.5 * Math.log(2 * Math.PI) - 0.5 * z * z),
    undefined,
    undefined,
    true,
  );
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

intervalProbability · src/physics/reference/diffusion/distributions.ts · revision workspace · sha256:fdf333ecee819e1097ee25fb89e2caea663dd27fc5f8818d3a28cd8a15ff9a56

This function computes the listed outputs when it runs.

In words

The probability of landing between two points is the integral of that Gaussian.

Mathematics

Implementation

/** Closed intervals include the atom at t=0, including the interval [0,0]. */
export function intervalProbability(x1: number, x2: number, t: number, D: number): Evaluation {
  const owner = "intervalProbability";
  if (![x1, x2].every(Number.isFinite) || x1 > x2 || !validDt(D, t))
    return outside(
      "intervalProbability",
      owner,
      "x1 <= x2, D >= 0, t >= 0",
      "Use ordered finite interval endpoints and nonnegative diffusivity and time.",
    );
  if (D === 0 || t === 0) return number("intervalProbability", owner, x1 <= 0 && x2 >= 0 ? 1 : 0);
  if (x1 === x2) return number("intervalProbability", owner, 0);
  const s = 2 * Math.sqrt(D) * Math.sqrt(t);
  if (!(s > 0) || !Number.isFinite(s))
    return outside(
      "intervalProbability",
      owner,
      "representable spread",
      "The spread is outside the numerical range.",
      "numerical",
    );
  const lo = x1 / s;
  const hi = x2 / s;
  const width = (x2 - x1) / s;
  const mid = lo + width / 2;
  let p: number;
  // Very narrow intervals need direct integration, even when both tails are small.
  if (width > 0 && width * (1 + Math.abs(mid)) < 0.01) {
    const nodes = [0.1834346424956498, 0.525532409916329, 0.7966664774136267, 0.9602898564975363];
    const weights = [0.362683783378362, 0.3137066458778873, 0.2223810344533745, 0.1012285362903763];
    let sum = 0;
    for (let i = 0; i < 4; i++) {
      const offset = (width / 2) * nodes[i]!;
      sum += weights[i]! * (Math.exp(-((mid - offset) ** 2)) + Math.exp(-((mid + offset) ** 2)));
    }
    p = (width / (2 * Math.sqrt(Math.PI))) * sum;
  } else
    p =
      lo >= 0
        ? 0.5 * (tail(lo) - tail(hi))
        : hi <= 0
          ? 0.5 * (tail(-hi) - tail(-lo))
          : 0.5 * (central(hi) - central(lo));
  if (p < 0 || p > 1)
    return outside(
      "intervalProbability",
      owner,
      "probability range",
      "Numerical evaluation did not produce an admissible probability.",
      "numerical",
    );
  return number("intervalProbability", owner, p, undefined, undefined, true);
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

erf · src/physics/reference/special/erf.ts · revision workspace · sha256:58ba0038d43059073d60c1af94ee48c8052c076685e393ce5eeab85362edda77

This function computes the listed outputs when it runs.

In words

The error function is the integral that turns a Gaussian density into an interval probability.

Mathematics

Implementation

export function erf(x: number): number {
  validate(x);
  if (x < 0) return -erf(-x);
  return x < 1.5 ? erfPositive(x) : 1 - erfcPositive(x);
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

erfc · src/physics/reference/special/erf.ts · revision workspace · sha256:45a75bb57d3658953e37bdc7ea1e9f0abbd6296180b6101f231d0631f5cb0922

This function computes the listed outputs when it runs.

In words

The complementary error function evaluates the Gaussian tail without subtracting from one.

Mathematics

Implementation

export function erfc(x: number): number {
  validate(x);
  return x < 0 ? 2 - erfcPositive(-x) : erfcPositive(x);
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

radialPropagator2d · src/physics/reference/diffusion/distributions.ts · revision workspace · sha256:58040898d39023e9e0e937741b8bb0885bad8976be85b6817c2b5ff3ef0916b2

This function computes the listed outputs when it runs.

In words

In two dimensions the radial density is not itself a Gaussian.

Mathematics

Implementation

export function radialPropagator2d(r: number, t: number, D: number): Evaluation {
  return radial(r, t, D, 2);
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

radialPropagator3d · src/physics/reference/diffusion/distributions.ts · revision workspace · sha256:37f9cc144c032a6104ceaa5b2020114d14a16a314620ad493149e5ee1bfdb6e8

This function computes the listed outputs when it runs.

In words

In three dimensions the radial density is not itself a Gaussian.

Mathematics

Implementation

export function radialPropagator3d(r: number, t: number, D: number): Evaluation {
  return radial(r, t, D, 3);
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

ftcs1d · src/physics/reference/diffusion/ftcs.ts · revision workspace · sha256:c04f80e8182597a114b7d20f492eb86053f90b4cc9e7cd299f516a6b44eb4755

This function computes the listed outputs when it runs.

In words

Advance a one-dimensional density with an explicit three-point Laplacian. Refuse when the stability ratio exceeds one half.

Mathematics

Implementation

export function ftcs1d(p: FtcsParameters, budget = REFERENCE_FTCS_BUDGET): Computation<FtcsFrames> {
  const { n, frames, stepsPerFrame, D, dx, dt, profile } = p;
  if (!integer(n, 3) || !integer(frames, 1) || !integer(stepsPerFrame, 1))
    return invalid(
      ["n", "frames", "stepsPerFrame"],
      "Use at least three cells and positive whole-number frame and step counts.",
    );
  if (![D, dx, dt].every(Number.isFinite))
    return {
      kind: "refused",
      refusal: makeRefusal("nonfinite-input", { parameterIds: ["D", "dx", "dt"] }),
    };
  if (D < 0 || dx <= 0 || dt <= 0 || ![0, 1, 2].includes(profile))
    return invalid(
      ["D", "dx", "dt", "profile"],
      "Use nonnegative D, positive dx and dt, and profile 0, 1, or 2.",
    );
  // This exact operation order is part of the planned upstream conformance contract.
  const r = D === 0 ? 0 : (D * dt) / (dx * dx);
  if (!Number.isFinite(r) || (D > 0 && r === 0))
    return numerical("The stability ratio is outside binary64 range; the grid was not advanced.");
  if (r > 0.5) {
    const dtMax = (dx * dx) / (2 * D);
    const dxMin = Math.sqrt(2 * D * dt);
    const dMax = (dx * dx) / (2 * dt);
    if (![dtMax, dxMin, dMax].every((v) => Number.isFinite(v) && v > 0))
      return numerical("The dimensional stability repairs are outside binary64 range.");
    // Mathematical bounds can round to a value with r=0.5000000000000001.
    // Preserve dtMax in the explanation; make each offered action executable.
    const dtRepair = stableRepair(dtMax, false, (v) => (D * v) / (dx * dx));
    const dxRepair = stableRepair(dxMin, true, (v) => (D * dt) / (v * v));
    const dRepair = stableRepair(dMax, false, (v) => (v * dt) / (dx * dx));
    if (dtRepair === null || dxRepair === null || dRepair === null)
      return numerical(
        "No representable repair was found near the dimensional stability boundary.",
      );
    return {
      kind: "refused",
      refusal: makeRefusal(
        "ftcs-unstable",
        { parameterIds: ["dt", "dx", "D"] },
        {
          details: { ratio: r, limit: 0.5, dtMax },
          rankedRepairs: [
            {
              label: "Reduce the time step to the explicit scheme's limit.",
              action: { parameterId: "dt", value: dtRepair },
            },
            {
              label: "Use a coarser spatial grid.",
              action: { parameterId: "dx", value: dxRepair },
            },
            {
              label: "Choose a smaller diffusivity; this changes the physical setup.",
              action: { parameterId: "D", value: dRepair },
            },
          ],
        },
      ),
    };
  }
  const stepCount = (frames - 1) * stepsPerFrame;
  const limited = budgetCheck(n * stepCount, 8 * n * (frames + 2), budget);
  if (limited) return limited;
  const elapsedTime = stepCount * dt;
  if (!Number.isFinite(elapsedTime) || (stepCount > 0 && elapsedTime === 0))
    return numerical("Elapsed model time is outside binary64 range.");
  const field = new Float64Array(n);
  if (profile === 0) field[Math.floor(n / 2)] = 1 / dx;
  else if (profile === 1) field.fill(1, 0, Math.floor(n / 2));
  else {
    field[Math.floor(n / 4)] = 0.5 / dx;
    field[Math.floor((3 * n) / 4)] = 0.5 / dx;
  }
  if (!field.every(Number.isFinite))
    return numerical("The initial cell density is outside binary64 range.");
  const derivative = new Float64Array(n);
  const values = new Float64Array(n * frames);
  values.set(field);
  for (let frame = 1; frame < frames; frame++) {
    if (!advanceInPlace(field, derivative, r, stepsPerFrame))
      return numerical("A cell became nonfinite or negative; no partial frames are returned.");
    values.set(field, frame * n);
  }
  return {
    kind: "accepted",
    data: Object.freeze({
      values,
      shape: Object.freeze([frames, n] as const),
      stepCount,
      elapsedTime,
      stabilityRatio: r,
      boundary: "zero-flux",
      ownerId: "diffusion.ftcs1d",
    }),
  };
}

Compare two setups side by side in your reading. Each laboratory has its own settings, worker and accepted results.

The relationship behind the instrument

D=kBT6πηa,x2=2Dt,λx=2DtD = \frac{k_B T}{6\pi\eta a}, \qquad \langle x^2\rangle = 2Dt, \qquad \lambda_x = \sqrt{2Dt}

Temperature is T, viscosity is η, particle radius is a, and the diffusion coefficient is D. The constant kB is supplied by the explicitly named modern SI set. The RMS displacement λx is the square root of the mean squared displacement along one coordinate.

These are not a particle’s total travelled distance or instantaneous speed. For the unbounded model, the curve gives a probability density; an interval gets its probability from the area under that curve.

p(x,t)=14πDtexp ⁣(x24Dt)(D>0, t>0)p(x,t)=\frac{1}{\sqrt{4\pi Dt}}\exp\!\left(-\frac{x^2}{4Dt}\right)\quad (D>0,\ t>0)

At the starting time there is a point distribution, not a finite density curve. The laboratory keeps that limiting state distinct.

What the numerical comparison asks

The finite grid approximates diffusion with an explicit stepping scheme. Its diffusion number must not exceed one half. A refused timestep is a limitation of this algorithm, not a prohibition on diffusion.

r=DΔt(Δx)212r=\frac{D\,\Delta t}{(\Delta x)^2}\leq\frac12

The numerical box reflects probability at its walls. Once the spread reaches them, comparing it with an unbounded Gaussian is also comparing two boundary models.