Skip to content

Commit cebb220

Browse files
smparkerclaude
andcommitted
Parse state-to-state difference moments in addition to transition moments
Update StateToStateParser regex to match both "transition moments" and "difference moments" sections (e.g., <2|W|2> difference density). Fix SimpleLineParser first_only option to work without a title by checking if any of the output keys already exist before updating. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6af585d commit cebb220

File tree

3 files changed

+17
-6
lines changed

3 files changed

+17
-6
lines changed

mudslide/turboparse/line_parser.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def process(self, m, out):
5050
if not (self.first_only and self.title in out):
5151
out[self.title] = data
5252
else:
53+
# For first_only without title, check if any of the keys already exist
54+
if self.first_only and any(n in out for n in self.names):
55+
return
5356
out.update(data)
5457
else:
5558
if self.title not in out:

mudslide/turboparse/response_parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ class StateToStateParser(ParseSection):
8585

8686
def __init__(self):
8787
super(self.__class__,
88-
self).__init__(r"<\s*\d+\s*\|\s*W\s*\|\s*\d+\s*>\s*transition moments",
89-
r"(<\s*\d+\s*\|\s*W\s*\|\s*\d+\s*>\s*transition moments)|(S\+T\+V CONTRIBUTIONS TO)",
88+
self).__init__(r"<\s*\d+\s*\|\s*W\s*\|\s*\d+\s*>.*(?:transition|difference) moments",
89+
r"(<\s*\d+\s*\|\s*W\s*\|\s*\d+\s*>.*(?:transition|difference) moments)|(S\+T\+V CONTRIBUTIONS TO)",
9090
multi=True)
9191

9292

test/test_turboparse.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,21 @@ def test_state_to_state_parsed(self, parsed):
241241
"""Test that state-to-state transition moments are parsed"""
242242
assert 'state-to-state' in parsed['egrad']
243243
s2s = parsed['egrad']['state-to-state']
244-
# Only <1|W|2> is parsed (labeled as "transition moments")
245-
# <2|W|2> is labeled as "difference moments" and not captured
246-
assert len(s2s) == 1
244+
# Should have 2 blocks: <2|W|2> difference moments and <1|W|2> transition moments
245+
assert len(s2s) == 2
246+
247+
def test_state_to_state_2_2(self, parsed):
248+
"""Test <2|W|2> difference moments"""
249+
s2s = parsed['egrad']['state-to-state'][0]
250+
assert s2s['bra'] == 2
251+
assert s2s['ket'] == 2
252+
# Relaxed electric transition dipole moment (length rep.) from line 549
253+
# z = 3.819847
254+
assert np.isclose(s2s['diplen']['z'], 3.819847)
247255

248256
def test_state_to_state_1_2(self, parsed):
249257
"""Test <1|W|2> transition moments"""
250-
s2s = parsed['egrad']['state-to-state'][0]
258+
s2s = parsed['egrad']['state-to-state'][1]
251259
assert s2s['bra'] == 1
252260
assert s2s['ket'] == 2
253261
# Relaxed electric transition dipole moment (length rep.) from line 608

0 commit comments

Comments
 (0)