diff --git a/.gitignore b/.gitignore index 2502477..d32c7d9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ __pycache__/ .vscode/ build/ dist/ -*.egg-info/ \ No newline at end of file +*.egg-info/ +.idea/ \ No newline at end of file diff --git a/molextract/rules/orca/__init__.py b/molextract/rules/orca/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/molextract/rules/orca/general.py b/molextract/rules/orca/general.py new file mode 100644 index 0000000..7b7c3eb --- /dev/null +++ b/molextract/rules/orca/general.py @@ -0,0 +1,70 @@ +import re +from molextract.rule import Rule + + +class ORCADipoleMoment(Rule): + """ + Parses every "DIPOLE MOMENT" block in an ORCA .out/.log file. + + A block with no "State:" line is the ground state (state=0). + A block with "State: N" is that excited state. + """ + _HEADER_RE = re.compile(r"DIPOLE MOMENT") + _STATE_RE = re.compile(r"State\s*:\s*(\d+)") + _VECTOR_RE = re.compile( + r"Total Dipole Moment\s*:\s*([-\d.]+)\s+([-\d.]+)\s+([-\d.]+)") + _MAGNITUDE_RE = re.compile(r"Magnitude \(Debye\)\s*:\s*([-\d.]+)") + + def __init__(self): + super().__init__(start_tag=r".*", + end_tag=r"ORCA TERMINATED NORMALLY", + check_only_beginning=False) + self._results = [] + + def process_lines(self, start_line): + state = 0 + magnitude = None + x = y = z = None + in_block = False + + for line in self: + # Find the dipole moment block + if self._HEADER_RE.search(line): + in_block = True + magnitude = None + x = y = z = None + state = 0 + continue + + if not in_block: + continue + + # Get the state value + state_match = self._STATE_RE.search(line) + if state_match: + state = int(state_match.group(1)) + continue + + # Get the x,y,z total dipole moment vector (in a.u.) + vector_match = self._VECTOR_RE.search(line) + if vector_match: + x, y, z = (float(v) for v in vector_match.groups()) + continue + + # Get the magnitude in Debye + mag_match = self._MAGNITUDE_RE.search(line) + if mag_match: + magnitude = float(mag_match.group(1)) + self._results.append({ + "state": state, + "total": magnitude, + "x": x, + "y": y, + "z": z, + }) + in_block = False + + def reset(self): + tmp = self._results.copy() + self._results.clear() + return tmp diff --git a/test/orca_rules_test.py b/test/orca_rules_test.py new file mode 100644 index 0000000..93cb463 --- /dev/null +++ b/test/orca_rules_test.py @@ -0,0 +1,69 @@ +from molextract.rules.orca import general +from molextract.parser import Parser + +ORCA_LOG = """************** + +------------- +DIPOLE MOMENT +------------- + +Method : SCF +Type of density : Electron Density +Multiplicity : 1 +Irrep : 0 +Energy : -153.9592467839026426 Eh +Relativity type : +Basis : AO + X Y Z +Electronic contribution: 3.030774285 0.000000001 1.409400234 +Nuclear contribution : -4.096753110 0.000000000 -1.551790077 + ----------------------------------------- +Total Dipole Moment : -1.065978825 0.000000001 -0.142389843 + ----------------------------------------- +Magnitude (a.u.) : 1.075446755 +Magnitude (Debye) : 2.733568410 + + +------------- +DIPOLE MOMENT +------------- + +Method : TD-DFT/RPA +Type of density : Electron Density +Level : Relaxed density +State : 1 +Multiplicity : 1 +Irrep : 0 +Energy : 0.0000000000000000 Eh +Relativity type : +Basis : AO + X Y Z +Electronic contribution: 3.386122984 -0.000000001 1.463710336 +Nuclear contribution : -4.096753110 0.000000000 -1.551790077 + ----------------------------------------- +Total Dipole Moment : -0.710630126 -0.000000001 -0.088079741 + ----------------------------------------- +Magnitude (a.u.) : 0.716067886 +Magnitude (Debye) : 1.820099920 + +ORCA TERMINATED NORMALLY +""" + + +def test_dipole_moment(): + parser = Parser(general.ORCADipoleMoment()) + data = parser.feed(ORCA_LOG) + + ground_state = data[0] + assert ground_state['state'] == 0 + assert ground_state['total'] == 2.733568410 + assert ground_state['x'] == -1.065978825 + assert ground_state['y'] == 0.000000001 + assert ground_state['z'] == -0.142389843 + + excited_state = data[1] + assert excited_state['state'] == 1 + assert excited_state['total'] == 1.820099920 + assert excited_state['x'] == -0.710630126 + assert excited_state['y'] == -0.000000001 + assert excited_state['z'] == -0.088079741