{"spec_id":"line-tanabe-sugano","library":"echarts","language":"javascript","code":"// anyplot.ai\n// line-tanabe-sugano: Tanabe-Sugano Diagram for Crystal Field Theory\n// Library: echarts 6.1.0 | JavaScript 22.23.3\n// Quality: 91/100 | Created: 2026-10-01\n//# anyplot-orientation: square\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: d3 (Cr3+) term energies from the Tanabe-Sugano matrices ----------\n// Energies are in units of the Racah parameter B, the field strength is\n// Dq/B with the octahedral splitting delta_o = 10 Dq.\n\nconst B = 1;\nconst C = 4.5 * B; // C/B of the classic d3 diagram\nconst r2 = Math.SQRT2;\nconst r3 = Math.sqrt(3);\n\n// Symmetric matrix from its diagonal plus the upper-triangle entries.\nconst symmetric = (diagonal, offDiagonal) => {\n  const m = diagonal.map((d, i) => diagonal.map((_, j) => (i === j ? d : 0)));\n  offDiagonal.forEach(([i, j, value]) => {\n    m[i][j] = value;\n    m[j][i] = value;\n  });\n  return m;\n};\n\n// Ascending eigenvalues by cyclic Jacobi rotation — the browser has no\n// linear-algebra package, so the sweep is written out.\nconst eigenvalues = (matrix) => {\n  const n = matrix.length;\n  const a = matrix.map((row) => row.slice());\n  for (let sweep = 0; sweep < 40; sweep += 1) {\n    let offSquared = 0;\n    for (let p = 0; p < n - 1; p += 1) {\n      for (let q = p + 1; q < n; q += 1) offSquared += a[p][q] * a[p][q];\n    }\n    if (offSquared < 1e-20) break;\n    for (let p = 0; p < n - 1; p += 1) {\n      for (let q = p + 1; q < n; q += 1) {\n        if (a[p][q] === 0) continue;\n        const theta = (a[q][q] - a[p][p]) / (2 * a[p][q]);\n        const tan =\n          Math.sign(theta || 1) /\n          (Math.abs(theta) + Math.sqrt(theta * theta + 1));\n        const cos = 1 / Math.sqrt(tan * tan + 1);\n        const sin = tan * cos;\n        for (let k = 0; k < n; k += 1) {\n          const kp = a[k][p];\n          const kq = a[k][q];\n          a[k][p] = cos * kp - sin * kq;\n          a[k][q] = sin * kp + cos * kq;\n        }\n        for (let k = 0; k < n; k += 1) {\n          const pk = a[p][k];\n          const qk = a[q][k];\n          a[p][k] = cos * pk - sin * qk;\n          a[q][k] = sin * pk + cos * qk;\n        }\n      }\n    }\n  }\n  return a.map((row, i) => row[i]).sort((x, y) => x - y);\n};\n\n// Term energies at one field strength, measured from the 4A2g ground term.\nconst termEnergies = (fieldStrength) => {\n  const dq = fieldStrength / 10;\n  const ground = -12 * dq - 15 * B; // t2g^3, 4A2g\n\n  const quartetT1 = eigenvalues(\n    symmetric([-2 * dq - 3 * B, 8 * dq - 12 * B], [[0, 1, 6 * B]]),\n  );\n  const doubletE = eigenvalues(\n    symmetric(\n      [\n        -12 * dq - 6 * B + 3 * C,\n        -2 * dq + 8 * B + 6 * C,\n        -2 * dq - B + 3 * C,\n        18 * dq - 8 * B + 4 * C,\n      ],\n      [\n        [0, 1, -6 * r2 * B],\n        [0, 2, -3 * r2 * B],\n        [1, 2, 10 * B],\n        [1, 3, r3 * (2 * B + C)],\n        [2, 3, 2 * r3 * B],\n      ],\n    ),\n  );\n  const doubletT1 = eigenvalues(\n    symmetric(\n      [\n        -12 * dq - 6 * B + 3 * C,\n        -2 * dq + 3 * C,\n        -2 * dq - 6 * B + 3 * C,\n        8 * dq - 6 * B + 3 * C,\n        8 * dq - 2 * B + 3 * C,\n      ],\n      [\n        [0, 1, -3 * B],\n        [0, 2, 3 * B],\n        [0, 4, -2 * r3 * B],\n        [1, 2, -3 * B],\n        [1, 3, 3 * B],\n        [1, 4, 3 * r3 * B],\n        [2, 3, -3 * B],\n        [2, 4, -r3 * B],\n        [3, 4, 2 * r3 * B],\n      ],\n    ),\n  );\n  const doubletT2 = eigenvalues(\n    symmetric(\n      [\n        -12 * dq + 5 * C,\n        -2 * dq - 6 * B + 3 * C,\n        -2 * dq + 4 * B + 3 * C,\n        8 * dq + 6 * B + 5 * C,\n        8 * dq - 2 * B + 3 * C,\n      ],\n      [\n        [0, 1, -3 * r3 * B],\n        [0, 2, -5 * r3 * B],\n        [0, 3, 4 * B + 2 * C],\n        [0, 4, 2 * B],\n        [1, 2, 3 * B],\n        [1, 3, -3 * r3 * B],\n        [1, 4, -3 * r3 * B],\n        [2, 3, -r3 * B],\n        [2, 4, r3 * B],\n        [3, 4, 10 * B],\n      ],\n    ),\n  );\n\n  return [\n    0,\n    -2 * dq - 15 * B - ground,\n    quartetT1[0] - ground,\n    quartetT1[1] - ground,\n    doubletE[0] - ground,\n    doubletT1[0] - ground,\n    doubletT2[0] - ground,\n    -2 * dq - 11 * B + 3 * C - ground,\n  ];\n};\n\n// Spin-allowed terms share the quartet multiplicity of the 4A2g ground term.\nconst terms = [\n  { sup: \"4\", core: \"A\", sub: \"2g\", tail: \"\", allowed: true, shift: 0 },\n  { sup: \"4\", core: \"T\", sub: \"2g\", tail: \"\", allowed: true, shift: 0 },\n  { sup: \"4\", core: \"T\", sub: \"1g\", tail: \"(F)\", allowed: true, shift: 0 },\n  { sup: \"4\", core: \"T\", sub: \"1g\", tail: \"(P)\", allowed: true, shift: 0 },\n  { sup: \"2\", core: \"E\", sub: \"g\", tail: \"\", allowed: false, shift: 17 },\n  { sup: \"2\", core: \"T\", sub: \"1g\", tail: \"\", allowed: false, shift: -17 },\n  { sup: \"2\", core: \"T\", sub: \"2g\", tail: \"\", allowed: false, shift: 0 },\n  { sup: \"2\", core: \"A\", sub: \"1g\", tail: \"\", allowed: false, shift: 0 },\n];\n\nconst samples = 321;\nconst curves = terms.map(() => []);\nfor (let i = 0; i < samples; i += 1) {\n  const fieldStrength = (i * 40) / (samples - 1);\n  termEnergies(fieldStrength).forEach((energy, k) =>\n    curves[k].push([fieldStrength, energy]),\n  );\n}\n\n// --- Plot -------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nconst axis = {\n  type: \"value\",\n  nameLocation: \"middle\",\n  nameTextStyle: { color: t.ink, fontSize: 17 },\n  axisLabel: { color: t.inkSoft, fontSize: 15 },\n  axisLine: { lineStyle: { color: t.inkSoft, width: 1.5 } },\n  axisTick: { show: false },\n  splitLine: { lineStyle: { color: t.grid, width: 1 } },\n};\n\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"line-tanabe-sugano · javascript · echarts · anyplot.ai\",\n    subtext:\n      \"d³ (Cr³⁺) in an octahedral field · C/B = 4.5\\n\" +\n      \"solid = spin-allowed (quartet) · dashed = spin-forbidden (doublet)\",\n    left: \"center\",\n    top: 18,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },\n    subtextStyle: { color: t.inkSoft, fontSize: 15, lineHeight: 23 },\n  },\n  grid: { left: 104, right: 136, top: 158, bottom: 94 },\n  xAxis: {\n    ...axis,\n    min: 0,\n    max: 40,\n    interval: 5,\n    name: \"Δₒ / B   ligand-field strength\",\n    nameGap: 46,\n  },\n  yAxis: {\n    ...axis,\n    min: 0,\n    max: 90,\n    interval: 10,\n    name: \"E / B   term energy above ground\",\n    nameGap: 60,\n  },\n  series: terms.map((term, i) => {\n    const color = t.palette[i];\n    return {\n      type: \"line\",\n      name: `${term.sup}${term.core}${term.sub}${term.tail}`,\n      data: curves[i],\n      showSymbol: false,\n      clip: false,\n      lineStyle: {\n        color,\n        width: term.allowed ? 4.5 : 2.4,\n        type: term.allowed ? \"solid\" : [11, 7],\n      },\n      endLabel: {\n        show: true,\n        distance: 12,\n        offset: [0, term.shift],\n        color,\n        fontSize: 20,\n        formatter: `{s|${term.sup}}${term.core}{b|${term.sub}}${term.tail}`,\n        rich: {\n          s: { color, fontSize: 13, verticalAlign: \"top\" },\n          b: { color, fontSize: 13, verticalAlign: \"bottom\" },\n        },\n      },\n    };\n  }),\n});\n"}