Skip to content

JDFTXOutfileSlice.vibrational_modes and JDFTXOutfileSlice.vibrational_energy_components #4440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
176a400
Filling out `JOutStructure.properties` for feeding to `frame_properti…
benrich37 May 29, 2025
0d47074
Merge pull request #91 from materialsproject/master
benrich37 May 30, 2025
94a22ce
unneccessary line
benrich37 May 30, 2025
d4e9748
better comments on joutstructure initialization order
benrich37 May 30, 2025
02babe9
TODOs
benrich37 May 30, 2025
9847461
Merge branch 'master' into jdftxoutfile-trajectory-revisions
benrich37 May 31, 2025
45b42da
Merge branch 'master' into jdftxoutfile-trajectory-revisions
benrich37 Jun 2, 2025
d6aa3e2
Merge branch 'master' into jdftxoutfile-trajectory-revisions
shyuep Jun 2, 2025
f1b7118
Merge branch 'master' into jdftxoutfile-trajectory-revisions
shyuep Jun 2, 2025
48d2a25
Merge branch 'master' into jdftxoutfile-trajectory-revisions
benrich37 Jun 4, 2025
feef77d
Merge branch 'materialsproject:master' into jdftxoutfile-trajectory-r…
benrich37 Jun 5, 2025
5b8c673
Adding missing kinetic_functional option
benrich37 Jun 5, 2025
2920451
Merge branch 'master' into jdftxoutfile-trajectory-revisions
benrich37 Jun 9, 2025
201942d
Removing vestigial function
benrich37 Jun 10, 2025
234e910
Vibrations parsing and testing
benrich37 Jun 10, 2025
29e3bdc
Merge pull request #95 from materialsproject/master
benrich37 Jun 11, 2025
d15161a
Merge branch 'materialsproject:master' into jdftxoutfile-vibrations
benrich37 Jun 18, 2025
6353ebb
removing debug comments
benrich37 Jun 18, 2025
5a21e8e
removing commented out code
benrich37 Jun 18, 2025
3638e56
Parsing and testing for vibrational energy components
benrich37 Jun 18, 2025
8e3024f
Merge branch 'materialsproject:master' into jdftxoutfile-vibrations
benrich37 Jun 30, 2025
71bcfcc
Merge branch 'materialsproject:master' into jdftxoutfile-vibrations
benrich37 Jul 8, 2025
693f161
Merge branch 'materialsproject:master' into jdftxoutfile-vibrations
benrich37 Aug 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 90 additions & 1 deletion src/pymatgen/io/jdftx/jdftxoutfileslice.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ class JDFTXOutfileSlice:
elec_grad_k: float | None = None
elec_alpha: float | None = None
elec_linmin: float | None = None
vibrational_modes: list[dict[str, Any]] | None = None
vibrational_energy_components: dict[str, float] | None = None

def _get_mu(self) -> None | float:
"""Sets mu from most recent JOutStructure. (Equivalent to efermi)"""
Expand Down Expand Up @@ -387,6 +389,8 @@ def _from_out_slice_init_all(self, text: list[str]) -> None:

# Previously were properties, but are now set as attributes
self._from_out_slice_init_all_post_init()
if "vibrations" in self.infile:
self._read_vibrational_data(text)

def _set_internal_infile(self, text: list[str]) -> None:
"""Set the internal infile for the JDFTXOutfileSlice.
Expand All @@ -400,7 +404,9 @@ def _set_internal_infile(self, text: list[str]) -> None:
start_line_idx += 2
end_line_idx = None
for i in range(start_line_idx, len(text)):
if not len(text[i].strip()):
# Sometimes the dumped in file will have a blank line in the middle, so we actually need to
# find two consecutive blank lines to determine the end of the infile. (hopefully)
if (not len(text[i].strip())) and (not len(text[i + 1].strip())):
end_line_idx = i
break
if end_line_idx is None:
Expand Down Expand Up @@ -1157,6 +1163,89 @@ def determine_is_metal(self) -> bool | None:
raise ValueError("Cannot determine if system is metal - self.nspin undefined")
return None

def _read_vibrational_data(self, text: list[str]) -> None:
"""Read vibrational data from the output file.

Args:
text (list[str]): Output of read_file for out file.
"""
# TODO: Once t`he total number of computed configurations can be determined, a lot of the
# out file can be trimmed by setting the start line as the instance of "Completed n of n configurations"
mode_start_lines = (
find_all_key("Imaginary mode ", text) + find_all_key("Zero mode ", text) + find_all_key("Real mode ", text)
)
mode_dicts = []
for start_line in mode_start_lines:
end_line = start_line + 1
while end_line < len(text) and text[end_line].strip():
end_line += 1
mode_dicts.append(self._parse_vibrational_mode_lines(text[start_line:end_line]))
self.vibrational_modes = mode_dicts
vib_nrg_components_start_line = find_all_key("Vibrational free energy components", text)[-1]
end_line = vib_nrg_components_start_line + 1
while end_line < len(text) and text[end_line].strip():
end_line += 1
vib_nrg_lines = text[vib_nrg_components_start_line:end_line]
self.vibrational_energy_components = self._parse_vibrational_energy_components_lines(vib_nrg_lines)

def _parse_vibrational_energy_components_lines(self, text: list[str]) -> dict:
"""Parse vibrational energy components from the output file.

Args:
text (list[str]): Output of read_file for out file.

Returns:
dict: Dictionary containing vibrational energy components.
"""
vib_nrg_components = {}
if "T" in text[0]:
vib_nrg_components["T"] = float(text[0].split("=")[1].split("K")[0].strip())
for line in text[1:]:
if ":" in line:
key, value = line.split(":", 1)
vib_nrg_components[key.strip()] = float(value.strip()) * Ha_to_eV
return vib_nrg_components

def _parse_vibrational_mode_lines(self, text: list[str]) -> dict:
"""Parse vibrational mode lines from the output file.

Args:
text (list[str]): Output of read_file for out file.

Returns:
dict: Dictionary containing vibrational mode information.
"""
vib_mode_data: dict[str, float | int | complex | str | None] = {}
disp_start_idx = None
for i, line in enumerate(text):
if "Displacements:" in line:
disp_start_idx = i + 1
break
key = line.split(":")[0].strip()
value = line.split(":")[1].strip()
entry_val: float | int | complex | str | None = None
if key in ["Frequency", "IR intensity"]:
value = value.split()[0].strip()
entry_val = float(value.rstrip("i")) * 1j if value.endswith("i") else float(value)
if key == "Frequency":
entry_val *= Ha_to_eV
elif key == "Degeneracy":
entry_val = int(value.split()[-1].strip())
elif "mode" in key:
vib_mode_data["Type"] = key.split()[0].strip() # "Imaginary", "Zero", or "Real"
vib_mode_data["Type index"] = int(key.split()[2].strip()) # ie the third real mode
if entry_val is not None:
vib_mode_data[key] = entry_val
if disp_start_idx is not None:
_displacements = []
for line in text[disp_start_idx:]:
if not line.strip():
break
_displacements.append(np.array([float(x) for x in line.split()[2:5]]))
vib_mode_data["Displacements"] = np.array(_displacements) * bohr_to_ang # Length of displacement
# specified in inputs
return vib_mode_data

def to_jdftxinfile(self) -> JDFTXInfile:
"""
Convert the JDFTXOutfile object to a JDFTXInfile object with the most recent structure.
Expand Down
Loading
Loading