Coverage for gpaw/analyse/multipole.py: 98%
52 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-20 00:19 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-20 00:19 +0000
1import numpy as np
3from ase.units import Bohr
4from ase.parallel import paropen
6from gpaw.spherical_harmonics import Y
7from gpaw.utilities.tools import coordinates
10class Multipole:
12 """Expand a function on the grid in multipole moments
13 relative to a given center.
15 center: Vector [Angstrom]
16 """
18 def __init__(self, center, calculator=None, lmax=6):
20 self.center = center / Bohr
21 self.lmax = lmax
23 self.gd = None
24 self.y_Lg = None
25 self.l_L = None
27 if calculator is not None:
28 self.initialize(calculator.density.finegd)
30 def initialize(self, gd):
31 """Initialize Y_L arrays"""
33 self.gd = gd
35 r_cg, r2_g = coordinates(gd, self.center, tiny=1.e-78)
36 r_g = np.sqrt(r2_g)
37 rhat_cg = r_cg / r_g
39 self.l_L = []
40 self.y_Lg = []
41 npY = np.vectorize(Y, (float,), 'spherical harmonic')
42 L = 0
43 for l in range(self.lmax + 1):
44 for m in range(2 * l + 1):
45 self.y_Lg.append(
46 np.sqrt(4 * np.pi / (2 * l + 1)) * r_g ** l *
47 npY(L, rhat_cg[0], rhat_cg[1], rhat_cg[2])
48 )
49 self.l_L.append(l)
50 L += 1
52 def expand(self, f_g):
53 """Expand a function f_g in multipole moments
54 units [e * Angstrom**l]"""
56 assert f_g.shape == self.gd.empty().shape
58 q_L = []
59 for L, y_g in enumerate(self.y_Lg):
60 q_L.append(self.gd.integrate(f_g * y_g))
61 q_L[L] *= Bohr ** self.l_L[L]
63 return np.array(q_L)
65 def to_file(self, calculator,
66 filename='multipole.dat',
67 mode='a'):
68 """Expand the charge distribution in multipoles and write
69 the result to a file"""
71 if self.gd is None:
72 self.initialize(calculator.density.finegd)
73 q_L = self.expand(-calculator.density.rhot_g)
75 f = paropen(filename, mode)
77 print('# Multipole expansion of the charge density', file=f)
78 print('# center =', self.center * Bohr, 'Angstrom', file=f)
79 print('# lmax =', self.lmax, file=f)
80 print('# see https://gitlab.com/gpaw/gpaw/-/blob/master/c/bmgs/'
81 'sharmonic.py', file=f)
82 print('# for the definition of spherical harmonics', file=f)
83 print('# l m q_lm[|e| Angstrom**l]', file=f)
85 L = 0
86 for l in range(self.lmax + 1):
87 for m in range(-l, l + 1):
88 print(f'{l:2d} {m:3d} {q_L[L]:g}', file=f)
89 L += 1
90 f.close()