#!/usr/bin/env python3 """ POTENTIAL WELL ANALYSIS ======================== Plot the Lagrangian potential well for representative elements using published ionization energies. The successive IEs reveal the shape of the potential at each electron shell depth. Question: Does the potential well SHAPE correlate with crystal structure? If FCC elements have a distinctly different well shape than BCC elements, the compass Coordinate 2 IS visually distinguishable on the cone. """ import numpy as np import json from pathlib import Path OUTPUT_DIR = Path(__file__).parent # ====================================================================== # PUBLISHED IONIZATION ENERGIES (eV) # Source: NIST Atomic Spectra Database # Each list: [IE1, IE2, IE3, ...] from outermost to innermost electron # ====================================================================== # Representative elements from each archetype IE_DATA = { # BCC alkali "Li": {"Z": 3, "struct": "BCC", "IE": [5.39, 75.64, 122.45]}, "Na": {"Z": 11, "struct": "BCC", "IE": [5.14, 47.29, 71.62, 98.91, 138.40, 172.18, 208.50, 264.25, 299.86, 1465.13, 1648.70]}, "K": {"Z": 19, "struct": "BCC", "IE": [4.34, 31.63, 45.81, 60.91, 82.66, 99.4, 117.56, 154.88, 175.82, 503.8, 564.7]}, # BCC d-block "Fe": {"Z": 26, "struct": "BCC", "IE": [7.90, 16.19, 30.65, 54.8, 75.0, 99.1, 124.98, 151.06, 233.6, 262.1]}, "W": {"Z": 74, "struct": "BCC", "IE": [7.86, 17.7, 33.5, 51.8, 64.77]}, "Cr": {"Z": 24, "struct": "BCC", "IE": [6.77, 16.49, 30.96, 49.16, 69.46, 90.64, 160.18, 184.7, 209.3, 244.4]}, "V": {"Z": 23, "struct": "BCC", "IE": [6.75, 14.66, 29.31, 46.71, 65.28, 128.13, 150.6, 173.4, 205.8, 230.5]}, # FCC late d-block (noble metals) "Cu": {"Z": 29, "struct": "FCC", "IE": [7.73, 20.29, 36.84, 57.38, 79.8, 103.0, 139.0, 166.0, 199.0, 232.2]}, "Ag": {"Z": 47, "struct": "FCC", "IE": [7.58, 21.49, 34.83]}, "Au": {"Z": 79, "struct": "FCC", "IE": [9.23, 20.5]}, "Ni": {"Z": 28, "struct": "FCC", "IE": [7.64, 18.17, 35.19, 54.9, 76.06, 108.0, 133.0, 162.0, 193.0, 224.6]}, "Al": {"Z": 13, "struct": "FCC", "IE": [5.99, 18.83, 28.45, 119.99, 153.83, 190.49, 241.76, 284.66, 330.13, 398.75]}, "Pt": {"Z": 78, "struct": "FCC", "IE": [8.96, 18.56]}, # HCP "Mg": {"Z": 12, "struct": "HCP", "IE": [7.65, 15.04, 80.14, 109.26, 141.27, 186.76, 225.02, 265.96, 328.06, 367.50]}, "Ti": {"Z": 22, "struct": "HCP", "IE": [6.83, 13.58, 27.49, 43.27, 99.30, 119.53, 140.8, 170.4, 192.1, 215.92]}, "Co": {"Z": 27, "struct": "HCP", "IE": [7.88, 17.08, 33.50, 51.3, 79.5, 102.0, 128.9, 157.8, 186.1, 275.4]}, "Zn": {"Z": 30, "struct": "HCP", "IE": [9.39, 17.96, 39.72, 59.4, 82.6, 108.0, 134.0, 174.0, 203.0, 238.0]}, "Be": {"Z": 4, "struct": "HCP", "IE": [9.32, 18.21, 153.90, 217.72]}, "Zr": {"Z": 40, "struct": "HCP", "IE": [6.63, 13.13, 22.99, 34.34, 80.35]}, # Diamond "C": {"Z": 6, "struct": "Diamond", "IE": [11.26, 24.38, 47.89, 64.49, 392.09, 489.99]}, "Si": {"Z": 14, "struct": "Diamond", "IE": [8.15, 16.35, 33.49, 45.14, 166.77, 205.28, 246.5, 303.54, 351.12, 401.37]}, "Ge": {"Z": 32, "struct": "Diamond", "IE": [7.90, 15.93, 34.22, 45.71, 93.5]}, # Noble gas (FCC but insulating) "Ne": {"Z": 10, "struct": "FCC-noble", "IE": [21.56, 40.96, 63.45, 97.12, 126.21, 157.93, 207.27, 239.10, 1195.83, 1362.20]}, "Ar": {"Z": 18, "struct": "FCC-noble", "IE": [15.76, 27.63, 40.74, 59.81, 75.02, 91.01, 124.32, 143.46, 422.45, 478.69]}, } def analyze_well_shape(name, data): """Extract potential well characteristics from ionization energies.""" ie = np.array(data["IE"]) n = len(ie) # The IE sequence IS the derivative of the potential well # Large jumps = shell boundaries (crossing to a deeper shell) # Find the biggest jump (ratio of consecutive IEs) ratios = ie[1:] / ie[:-1] max_jump_idx = np.argmax(ratios) max_jump = ratios[max_jump_idx] # Valence electrons = number of electrons before the big jump valence_count = max_jump_idx + 1 # Well depth proxy = IE of last electron we have data for deepest_ie = ie[-1] # Well steepness = average ratio between consecutive IEs in valence shell if valence_count > 1: valence_ratios = ratios[:valence_count-1] valence_steepness = np.mean(valence_ratios) else: valence_steepness = 0 # Core tightness = first core IE / last valence IE if max_jump_idx + 1 < n: core_tightness = ie[max_jump_idx + 1] / ie[max_jump_idx] else: core_tightness = 0 return { "name": name, "struct": data["struct"], "Z": data["Z"], "valence_count": valence_count, "IE1": ie[0], "max_shell_jump": round(max_jump, 2), "jump_position": max_jump_idx + 1, "valence_steepness": round(valence_steepness, 3), "core_tightness": round(core_tightness, 2), "deepest_ie": round(deepest_ie, 1), } def main(): print("=" * 80) print("POTENTIAL WELL ANALYSIS: Does well shape predict crystal structure?") print("=" * 80) print() results = [] for name, data in sorted(IE_DATA.items(), key=lambda x: x[1]["Z"]): r = analyze_well_shape(name, data) results.append(r) # Group by structure from collections import defaultdict by_struct = defaultdict(list) for r in results: by_struct[r["struct"]].append(r) print(f"{'Elem':5s} {'Z':>3s} {'Struct':>10s} {'Val':>4s} {'IE1(eV)':>8s} " f"{'Jump':>6s} {'@pos':>5s} {'Steep':>7s} {'Core/Val':>9s}") print("-" * 65) for r in results: print(f"{r['name']:5s} {r['Z']:3d} {r['struct']:>10s} {r['valence_count']:4d} " f"{r['IE1']:8.2f} {r['max_shell_jump']:6.2f} {r['jump_position']:5d} " f"{r['valence_steepness']:7.3f} {r['core_tightness']:9.2f}") # Structure-level averages print() print("=" * 80) print("AVERAGES BY CRYSTAL STRUCTURE") print("=" * 80) print(f"{'Structure':>12s} {'n':>3s} {'Avg IE1':>8s} {'Avg Jump':>9s} {'Avg Steep':>10s} {'Avg Core/Val':>13s}") print("-" * 60) for struct in ["BCC", "FCC", "HCP", "Diamond", "FCC-noble"]: members = by_struct[struct] if not members: continue avg_ie1 = np.mean([r["IE1"] for r in members]) avg_jump = np.mean([r["max_shell_jump"] for r in members]) avg_steep = np.mean([r["valence_steepness"] for r in members]) avg_core = np.mean([r["core_tightness"] for r in members]) print(f"{struct:>12s} {len(members):3d} {avg_ie1:8.2f} {avg_jump:9.2f} " f"{avg_steep:10.3f} {avg_core:13.2f}") # Key question: do the well shapes cluster by structure? print() print("=" * 80) print("KEY QUESTION: Do well shapes distinguish crystal structures?") print("=" * 80) print() # Compare BCC vs FCC vs HCP bcc = by_struct["BCC"] fcc = by_struct["FCC"] hcp = by_struct["HCP"] dia = by_struct["Diamond"] print(" IE1 (first ionization energy = how loosely held is the outermost electron):") for struct, members in [("BCC", bcc), ("FCC", fcc), ("HCP", hcp), ("Diamond", dia)]: vals = [r["IE1"] for r in members] names = [r["name"] for r in members] print(f" {struct:8s}: {', '.join(f'{n}={v:.1f}' for n, v in zip(names, vals))}") print(f" avg={np.mean(vals):.2f}, range={min(vals):.1f}-{max(vals):.1f}") print() print(" SHELL JUMP (ratio at valence/core boundary = how sharply the well deepens):") for struct, members in [("BCC", bcc), ("FCC", fcc), ("HCP", hcp), ("Diamond", dia)]: vals = [r["max_shell_jump"] for r in members] print(f" {struct:8s}: avg={np.mean(vals):.2f}, range={min(vals):.1f}-{max(vals):.1f}") print() print(" VALENCE STEEPNESS (how rapidly IE increases within the valence shell):") for struct, members in [("BCC", bcc), ("FCC", fcc), ("HCP", hcp), ("Diamond", dia)]: vals = [r["valence_steepness"] for r in members] print(f" {struct:8s}: avg={np.mean(vals):.3f}, range={min(vals):.2f}-{max(vals):.2f}") print() print("=" * 80) print("INTERPRETATION") print("=" * 80) if __name__ == "__main__": main()