1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

二次元isingモデルのwebアプリ

1
Posted at

Isingモデル

Isingモデルとは格子に二種のスピンを配置したモデルです。相転移のモデルとして有名です。今回はIsingモデルのwebアプリを作成したので、この動作を解説します。
以下、アプリ画面とURLを示します。

ising.png

原理

isingモデルでは系のエネルギーを次のように計算します。

$$
E = -J\sum_{<i, j>} s_i s_j
$$

ここで、$s_i$が格子点$i$のスピン、$J$が相互作用の強さ、$⟨i,j⟩$が隣接するスピンの組です。

$J>0$の時、隣り合う格子のスピンは同じ向きを向くと安定です。つまり、$J>0$は強磁性的な相互作用です。反対に、$J<0$の時、隣り合う格子のスピンは反対の向きを向くと安定です。つまり、$J<0$は反強磁性的な相互作用です。

系のエネルギーを最低にするスピンの配列が最安定のスピン状態です。ここでランダムな格子点$i$のスピンを反転させることを考えます。この時のエネルギー変化$\Delta E$が、$\Delta E<=0$である場合、スピンの反転により系のエネルギーが減少するので、スピン反転が起こります。
反対に、$\Delta E>0$である場合、スピンの反転により系のエネルギーが増加するので、次の確率でスピン反転が起こるようにします。

$$
\exp (\frac{\Delta E}{T})
$$

こうすることで、モデルに温度$T$を組み込むことができます。

スクリプト

プログラムは次のHTMLファイルになります。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>Ising Model JS</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    body {
      font-family: sans-serif;
      margin: 1rem;
    }
    #controls {
      display: flex;
      flex-wrap: wrap;
      gap: 1rem;
      margin-bottom: 1rem;
    }
    label {
      display: block;
      font-size: 0.8rem;
    }
    canvas {
      border: 1px solid #ccc;
      image-rendering: pixelated; /* 拡大してもカリッと */
    }
    button {
      padding: 0.4rem 0.8rem;
    }
  </style>
</head>
<body>
  <h1>2D Ising Model</h1>

  <!-- ボタン行 -->
  <div id="controls">
    <div>
      <button id="randBtn"> Initialize</button>
      <button id="startBtn"> Start</button>
      <button id="stopBtn"> Stop</button>
    </div>
  </div>
  
  <!-- スライダー行(T, J, hだけ) -->
  <div id="controls">
    <div>
      <label>Temperature T: <span id="tVal">2.5</span></label>
      <input type="range" id="tRange" min="0.5" max="5.0" step="0.1" value="2.5" />
    </div>
    <div>
      <label>Interaction J: <span id="jVal">1.0</span></label>
      <input type="range" id="jRange" min="-3" max="3" step="0.1" value="1.0" />
    </div>
    <div>
      <label>External field h: <span id="hVal">0.0</span></label>
      <input type="range" id="hRange" min="-2" max="2" step="0.1" value="0.0" />
    </div>
  </div>

  <canvas id="ising" width="480" height="480"></canvas>

  <script>
    // ====== parameters ======
    const N = 40;                   // 40x40 に固定
    const scale = 12;               // 表示拡大用 → 40*12=480px
    const canvas = document.getElementById("ising");
    const ctx = canvas.getContext("2d");

    // UI elements
    const tRange = document.getElementById("tRange");
    const tVal = document.getElementById("tVal");
    const jRange = document.getElementById("jRange");
    const jVal = document.getElementById("jVal");
    const hRange = document.getElementById("hRange");
    const hVal = document.getElementById("hVal");
    const startBtn = document.getElementById("startBtn");
    const stopBtn = document.getElementById("stopBtn");
    const randBtn = document.getElementById("randBtn");

    let T = parseFloat(tRange.value);
    let J = parseFloat(jRange.value);
    let H = parseFloat(hRange.value);
    let beta = 1.0 / T;

    const intervalMs = 100;
    let lastTime = 0;

    // ====== lattice ======
    let lattice = initLattice();

    function initLattice() {
      const arr = new Array(N);
      for (let i = 0; i < N; i++) {
        arr[i] = new Array(N);
        for (let j = 0; j < N; j++) {
          arr[i][j] = Math.random() < 0.5 ? -1 : 1;
        }
      }
      return arr;
    }

    function energyChange(i, j) {
      const s = lattice[i][j];
      // periodic boundary
      const up    = lattice[(i - 1 + N) % N][j];
      const down  = lattice[(i + 1) % N][j];
      const left  = lattice[i][(j - 1 + N) % N];
      const right = lattice[i][(j + 1) % N];
      const nb = up + down + left + right;
      // ΔE = 2 s (J * nb + H)
      return 2 * s * (J * nb + H);
    }

    // 1 Monte Carlo sweep (N*N trial)
    function metropolisSweep() {
      for (let k = 0; k < N * N; k++) {
        const i = Math.floor(Math.random() * N);
        const j = Math.floor(Math.random() * N);
        const dE = energyChange(i, j);
        if (dE <= 0) {
          lattice[i][j] *= -1;
        } else {
          const r = Math.random();
          if (r < Math.exp(-beta * dE)) {
            lattice[i][j] *= -1;
          }
        }
      }
    }

    // draw lattice
    function draw() {
      for (let i = 0; i < N; i++) {
        for (let j = 0; j < N; j++) {
          const s = lattice[i][j];
          if (s === 1) {
            ctx.fillStyle = "rgb(255,80,80)";  // red
          } else {
            ctx.fillStyle = "rgb(80,80,255)";  // blue
          }
          ctx.fillRect(j * scale, i * scale, scale, scale);
        }
      }
    }

    // ====== animation loop ======
    let running = false;
    function loop(timestamp) {
      if (running) {
        const elapsed = timestamp - lastTime;
        if (elapsed >= intervalMs) {
          metropolisSweep();
          draw();
          lastTime = timestamp;
        }
        requestAnimationFrame(loop);
      }
    }

    // ====== UI handlers ======
    tRange.addEventListener("input", () => {
      T = parseFloat(tRange.value);
      beta = 1.0 / T;
      tVal.textContent = T.toFixed(1);
    });
    jRange.addEventListener("input", () => {
      J = parseFloat(jRange.value);
      jVal.textContent = J.toFixed(1);
    });
    hRange.addEventListener("input", () => {
      H = parseFloat(hRange.value);
      hVal.textContent = H.toFixed(1);
    });

    startBtn.addEventListener("click", () => {
      if (!running) {
        running = true;
        lastTime = performance.now(); // 開始時にリセット
        requestAnimationFrame(loop);
      }
    });

    stopBtn.addEventListener("click", () => {
      running = false;
    });

    randBtn.addEventListener("click", () => {
      lattice = initLattice();
      draw();
    });

    // 初期描画
    draw();
  </script>
</body>
</html>

動作

例えば、温度のパラメタを小さくすると、赤と青の色のドメインが大きくなり、逆に温度のパラメタを大きくすると赤と青の色のドメインが小さくなります。これは、磁石を加熱すると磁力がなくなり、温度を下げると磁力が回復する現象に対応します。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?