Skip to content

Commit

Permalink
Tried to add support for parsing Mulliken charges of simpler spin types
Browse files Browse the repository at this point in the history
  • Loading branch information
ahkole committed Mar 8, 2024
1 parent fc18e35 commit af95fd7
Showing 1 changed file with 79 additions and 10 deletions.
89 changes: 79 additions & 10 deletions src/sisl/io/siesta/stdout.py
Original file line number Diff line number Diff line change
Expand Up @@ -1189,16 +1189,20 @@ def _mulliken_charges():
# 1 Total 6.99733 0.41305 -0.288 -0.296 0.007

# Define the function that parses the charges

Check warning on line 1191 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1185-L1191

Added lines #L1185 - L1191 were not covered by tests
def _parse_charge_total(line):
def _parse_charge_total_nc(line): # non-colinear and soc
atom_idx, _, *vals = line.split()

Check warning on line 1193 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1193

Added line #L1193 was not covered by tests
# assert that this is a proper line
# this should catch cases where the following line of charge output
# is still parseable
# atom_idx = int(atom_idx)
return int(atom_idx), list(map(float, vals))

def _parse_charge_total(line): # unpolarized and colinear spin
atom_idx, val, *_ = line.split()
return int(atom_idx), float(val)

# Define the function that parses a single species
def _parse_species():
def _parse_species_nc(): # non-colinear and soc

Check warning on line 1205 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1201-L1205

Added lines #L1201 - L1205 were not covered by tests
nonlocal header, atom_idx, atom_charges

Check warning on line 1207 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1207

Added line #L1207 was not covered by tests
# The mulliken charges are organized per species where the charges
Expand All @@ -1224,18 +1228,83 @@ def _parse_species():
while "----" not in line:
line = self.readline()

Check warning on line 1229 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1228-L1229

Added lines #L1228 - L1229 were not covered by tests
if "Total" in line:
ia, charge_vals = _parse_charge_total(line)
ia, charge_vals = _parse_charge_total_nc(line)
atom_idx.append(ia)
atom_charges.append(charge_vals)

Check warning on line 1233 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1232-L1233

Added lines #L1232 - L1233 were not covered by tests

# Parse as long as we find new species
atom_idx = []
atom_charges = []
header = None
found, _ = self.step_to("Species:", allow_reread=False)
while found:
_parse_species()
def _parse_spin_pol(): # unpolarized and colinear spin
nonlocal atom_idx, atom_charges

# The mulliken charges are organized per spin
# polarization (UP/DOWN). The end of a spin

Check warning on line 1239 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1235-L1239

Added lines #L1235 - L1239 were not covered by tests
# block is marked by a Qtot

# Read until we encounter "mulliken: Qtot"
def try_parse_int(s):
try:
int(s)
except ValueError:
return False
else:

Check warning on line 1248 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1241-L1248

Added lines #L1241 - L1248 were not covered by tests
return True

line = ""
while "mulliken: Qtot" not in line:
line = self.readline()
words = line.split()
if len(words) > 0 and try_parse_int(words[0]):

Check warning on line 1255 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1251-L1255

Added lines #L1251 - L1255 were not covered by tests
# This should be a line containing the total charge for an atom
ia, charge = _parse_charge_total(line)
atom_idx.append(ia)
atom_charges.append(charge)

# Determine with which spin type we are dealing
IDX_NON_POL = 0
IDX_POL = 1

Check warning on line 1263 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1257-L1263

Added lines #L1257 - L1263 were not covered by tests
IDX_NC = 2
search_keys_spin = [

Check warning on line 1265 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1265

Added line #L1265 was not covered by tests
"Qatom", # if we find Qatom and no "mulliken: Spin UP" we are dealing with spin unpolarized
"mulliken: Spin UP",
"Svec",
]

Check warning on line 1269 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1268-L1269

Added lines #L1268 - L1269 were not covered by tests
loc = self.fh.tell()
ret = self.step_to(

Check warning on line 1271 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1271

Added line #L1271 was not covered by tests
search_keys_spin, case=True, ret_index=True, allow_reread=False
)

Check warning on line 1273 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1273

Added line #L1273 was not covered by tests
self.fh.seek(loc)
if ret[2] == IDX_NON_POL:
# No spin components so just parse charge
atom_charges = []
atom_idx = []

Check warning on line 1278 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1277-L1278

Added lines #L1277 - L1278 were not covered by tests
header = ["e"]
_parse_spin_pol()
elif ret[2] == IDX_POL:

Check warning on line 1281 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1281

Added line #L1281 was not covered by tests
# Parse both spin polarizations
atom_charges_pol = []
header = ["e", "Sz"]
for s in ["UP", "DOWN"]:
atom_charges = []
atom_idx = []
self.step_to(f"mulliken: Spin {s}", allow_reread=False)
_parse_spin_pol()
atom_charges_pol.append(atom_charges)

# Compute the charge and spin of each atom
atom_charges_pol_array = _a.arrayf(atom_charges_pol)
atom_q = atom_charges_pol_array[0, :] + atom_charges_pol_array[1, :]
atom_s = atom_charges_pol_array[0, :] - atom_charges_pol_array[1, :]
atom_charges[:] = np.stack((atom_q, atom_s), axis=-1)
elif ret[2] == IDX_NC:
# Parse as long as we find new species
atom_charges = []
atom_idx = []
header = None
found, _ = self.step_to("Species:", allow_reread=False)
while found:

Check warning on line 1303 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1301-L1303

Added lines #L1301 - L1303 were not covered by tests
_parse_species_nc()
found, _ = self.step_to("Species:", allow_reread=False)

Check warning on line 1305 in src/sisl/io/siesta/stdout.py

View check run for this annotation

Codecov / codecov/patch

src/sisl/io/siesta/stdout.py#L1305

Added line #L1305 was not covered by tests
else:
assert False # It should never reach here

# Convert to array and sort in the order of the atoms
sort_idx = np.argsort(atom_idx)
Expand Down

0 comments on commit af95fd7

Please sign in to comment.