“Know how to solve every problem that has been solved.” “What I cannot create, I do not understand.” — Richard Feynman
python 67 lines · 3.0 KB
"""Build your own shell model -- step 3: read the interaction.

The physics of the valence space lives in one small text file: usdb.int, the
USDB interaction (Brown & Richter 2006), fit to hundreds of measured sd-shell
levels. The format (oxbash convention) is:

  header line:   -63  2.1117  -3.9257  -3.2079   16.0  18.0  0.3
                  |     |________|________|        |     |    |
                  |     single-particle energies   |     |    |
                  |     for labels 1,2,3 (MeV):    A_core A_ref power
                  |     1=d3/2  2=d5/2  3=s1/2
                  '-- line count (negative flags the mass scaling below)

  then one line per two-body matrix element (TBME):
      a  b  c  d   J  T   V
  meaning <ab; JT| V |cd; JT> in MeV: the interaction energy between a PAIR
  of particles put in orbitals (a,b) and a pair in (c,d), with the pair
  coupled to total angular momentum J and isospin T. Isospin is the
  proton/neutron label treated like a spin-1/2: T=1 pairs are the
  symmetric combination (includes nn and pp), T=0 pairs antisymmetric
  (proton-neutron only).

The mass scaling: USDB was fit at A = 18, but orbitals shrink as more valence
particles pile in, so every TBME is scaled by (18/A)^0.3 for nucleus mass A.
For 18O the factor is exactly 1; for 24Mg it is 0.917315 -- and BIGSTICK's
input file carries the same "1.0 18.0 24.0 0.3" line, which is how the
convention was cross-checked.
"""

def read_int(path):
    spe, tbme, tail, n = {}, [], None, None
    with open(path) as fh:
        for raw in fh:
            line = raw.strip()
            if not line or line.startswith(('!', '#')):
                continue
            w = line.split()
            if n is None:
                n = int(w[0])
                spe = {1: float(w[1]), 2: float(w[2]), 3: float(w[3])}
                tail = [float(x) for x in w[4:]]
                continue
            a, b, c, d, J, T = (int(x) for x in w[:6])
            tbme.append(((a, b, c, d, J, T), float(w[6])))
    return spe, tbme, tail

NAMES = {1: 'd3/2', 2: 'd5/2', 3: 's1/2'}
spe, tbme, tail = read_int('usdb.int')

print("single-particle energies (the seat prices, MeV):")
for label in (2, 3, 1):   # printed in energy order
    print(f"  {NAMES[label]:>5}: {spe[label]:+8.4f}")
print("d5/2 lowest -- filling it first is the cheap move; the interaction")
print("decides whether that naive filling survives.")

print(f"\n{len(tbme)} two-body matrix elements. The first few:")
print(f"{'a':>5} {'b':>5} {'c':>5} {'d':>5} {'J':>2} {'T':>2} {'V (MeV)':>9}")
for (key, V) in tbme[:5]:
    a, b, c, d, J, T = key
    print(f"{NAMES[a]:>5} {NAMES[b]:>5} {NAMES[c]:>5} {NAMES[d]:>5} {J:>2} {T:>2} {V:>9.4f}")

a_core, a_ref, power = tail[-3], tail[-2], tail[-1]
for A in (18, 20, 24):
    scale = (a_ref / A) ** power
    print(f"mass scaling for A = {A}:  ({a_ref:.0f}/{A})^{power} = {scale:.6f}")
print("\nEvery number the final calculation produces is built from these")
print(f"{len(tbme)} matrix elements, 3 seat prices, and antisymmetry. Nothing else.")