Skip to content
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

Add vibrational properties #11

Merged
merged 11 commits into from
Jun 22, 2023
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ Suggestions, improvements, and edits are most welcome.
The following snippet can be used to test the code (provided that you have some VASP data or intermediate `.mat` files.

```python
import GEMDAT
GEMDAT.analyse_md('<path to data>', 'Li', 'argyrodite')
import gemdat
gemdat.analyse_md('<path to data>', 'Li', 'argyrodite')

```

Expand Down
2 changes: 1 addition & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
::: GEMDAT
::: gemdat
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ publishing = [
]

[tool.setuptools]
package-dir = {"GEMDAT" = "src", "pymatgen.analysis.GEMDAT" = "src"}
package-dir = {"gemdat" = "src", "pymatgen.analysis.gemdat" = "src"}
include-package-data = true

[tool.coverage.run]
Expand Down
5 changes: 5 additions & 0 deletions src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
plot_displacement_per_element,
plot_displacement_per_site,
)
from .project import load_project
from .vibration import plot_frequency_vs_occurence, plot_vibrational_amplitudes

__all__ = [
'calculate_displacements',
'plot_displacement_per_site',
'plot_displacement_per_element',
'plot_displacement_histogram',
'plot_frequency_vs_occurence',
'plot_vibrational_amplitudes',
'load_project',
]
3 changes: 3 additions & 0 deletions src/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
e_charge = 1.60217657e-19
k_boltzmann = 1.3806488e-23
avogadro = 6.022140857e23
69 changes: 19 additions & 50 deletions src/displacements.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,25 @@ def calculate_lengths(vectors: np.ndarray,
return np.sqrt(total_displacement)


def calculate_displacements(traj_coords: np.ndarray) -> np.ndarray:
def calculate_displacements(traj_coords: np.ndarray,
lattice: Lattice,
equilibration_steps: int = 0) -> np.ndarray:
"""Calculate displacements from first set of positions.

Corrects for elements jumping to the next unit cell.

Parameters
----------
traj_coords : np.array[i, j, k]
traj_coords : np.ndarray
3-dimensional numpy array with dimensions i: time_steps, j: sites, k: coordinates
lattice : Lattice
Lattice parameters
equilibration_steps : int, optional
Number of steps to skip before equilibration

Returns
-------
displacements : np.ndarray[i, j]
displacements : np.ndarray
Displacements from first set of positions.
"""
offsets = calculate_cell_offsets_from_coords(traj_coords)
Expand All @@ -90,7 +96,7 @@ def calculate_displacements(traj_coords: np.ndarray) -> np.ndarray:

displacements = np.array(displacements)

return displacements
return displacements.T


def plot_displacement_per_site(displacements: np.ndarray):
Expand All @@ -103,7 +109,7 @@ def plot_displacement_per_site(displacements: np.ndarray):
"""
fig, ax = plt.subplots()

for site_displacement in displacements.T:
for site_displacement in displacements:
ax.plot(site_displacement, lw=0.3)

ax.set(title='Displacement of diffusing element',
Expand All @@ -128,7 +134,7 @@ def plot_displacement_per_element(species: list[Element],

grouped = defaultdict(list)

for specie, displacement in zip(species, displacements.T):
for specie, displacement in zip(species, displacements):
grouped[specie.name].append(displacement)

fig, ax = plt.subplots()
Expand All @@ -154,69 +160,32 @@ def plot_displacement_histogram(displacements: np.ndarray):
Numpy array with displacements
"""
fig, ax = plt.subplots()
ax.hist(displacements[-1])
ax.hist(displacements[:, -1])
ax.set(title='Histogram of displacement of diffusing element',
xlabel='Displacement (Angstrom)',
ylabel='Nr. of atoms')
plt.show()


if __name__ == '__main__':
from pathlib import Path

import yaml
from pymatgen.io.vasp.outputs import Vasprun
from gemdat import load_project

vasp_xml = '/run/media/stef/Scratch/md-analysis-matlab-example/vasprun.xml'

path_coords = Path('traj_coords.npy')
path_data = Path('data.yaml')

# skip first timesteps
equilibration_steps = 1250

if not (path_coords.exists() and path_data.exists()):
vasprun = Vasprun(
vasp_xml,
parse_dos=False,
parse_eigen=False,
parse_projected_eigen=False,
parse_potcar_file=False,
)

traj = vasprun.get_trajectory()

structure = vasprun.structures[0]

lattice = structure.lattice
species = structure.species

data = {
'species': [e.as_dict() for e in species],
'lattice': lattice.as_dict()
}

with open('data.yaml', 'w') as f:
yaml.dump(data, f)

traj.to_positions()
np.save('traj_coords.npy', traj.coords)

traj_coords = traj.coords
else:
traj_coords = np.load('traj_coords.npy')

with open('data.yaml') as f:
data = yaml.safe_load(f)
traj_coords, data = load_project(vasp_xml, diffusing_element='Li')

species = [Element.from_dict(e) for e in data['species']]
lattice = Lattice.from_dict(data['lattice'])
species = data['species']
lattice = data['lattice']

print(species)
print(lattice)
print(traj_coords.shape)

displacements = calculate_displacements(traj_coords)
displacements = calculate_displacements(
traj_coords, lattice=lattice, equilibration_steps=equilibration_steps)

plot_displacement_per_site(displacements)

Expand Down
70 changes: 70 additions & 0 deletions src/project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from pathlib import Path
from typing import Optional

import numpy as np
import yaml
from pymatgen.core import Element, Lattice
from pymatgen.io.vasp.outputs import Vasprun

PATH_COORDS = Path('traj_coords.npy')
PATH_DATA = Path('data.yaml')
VASP_XML = 'vasprun.xml'


def load_project(directory: str | Path,
diffusing_element: Optional[str] = None):
"""Read coordinates and data from vasp_xml."""
vasp_xml = Path(directory) / VASP_XML

if not (PATH_COORDS.exists() and PATH_DATA.exists()):
assert vasp_xml.exists()

vasprun = Vasprun(
vasp_xml,
parse_dos=False,
parse_eigen=False,
parse_projected_eigen=False,
parse_potcar_file=False,
)

traj = vasprun.get_trajectory()

structure = vasprun.structures[0]

data = {
'species': [e.as_dict() for e in structure.species],
'lattice':
structure.lattice.as_dict(),
'parameters':
vasprun.parameters,
# Size of the timestep (*1E-15 = in femtoseconds)
'time_step':
vasprun.time_step['POTIM'] * 1e-15,
# Temperature of the MD simulation
'temperature':
vasprun.parameters['TEBEG'],
# Number of diffusing elements
'nr_diffusing':
sum([
e.name == diffusing_element
for e in vasprun.initial_structure.species
])
}

with open('data.yaml', 'w') as f:
yaml.dump(data, f)

traj.to_positions()
np.save('traj_coords.npy', traj.coords)

traj_coords = traj.coords
else:
traj_coords = np.load('traj_coords.npy')

with open('data.yaml') as f:
data = yaml.unsafe_load(f)

data['species'] = [Element.from_dict(e) for e in data['species']]
data['lattice'] = Lattice.from_dict(data['lattice'])

return traj_coords, data
Loading