first commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Ignore everything
|
||||
*
|
||||
|
||||
# But track these files
|
||||
!.gitignore
|
||||
!dump2rotorang.py
|
||||
!example.lammpstrj
|
||||
!Readme.org
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
#+TITLE: dump2rotorang.py
|
||||
#+AUTHOR:
|
||||
#+DATE:
|
||||
|
||||
* Overview
|
||||
|
||||
=dump2rotorang.py= analyzes LAMMPS trajectory files and calculates
|
||||
orientation and z-position distributions of benzene molecules.
|
||||
|
||||
The script reads LAMMPS dump trajectory files =*.lammpstrj=, extracts the
|
||||
coordinates of selected atoms in each molecule, and evaluates:
|
||||
|
||||
- the in-plane orientation angle of each benzene molecule
|
||||
- the center z-position of each benzene molecule
|
||||
|
||||
The resulting histograms are saved as Python pickle files.
|
||||
|
||||
* Requirements
|
||||
|
||||
This script requires Python 3 and the following Python packages:
|
||||
|
||||
- numpy
|
||||
- pandas
|
||||
|
||||
Install them, for example, using pip:
|
||||
|
||||
#+begin_src sh
|
||||
pip install numpy pandas
|
||||
#+end_src
|
||||
|
||||
* Input files
|
||||
|
||||
The script searches for trajectory files with the following filename
|
||||
patterns:
|
||||
|
||||
#+begin_src text
|
||||
D3d-o_*K.lammpstrj
|
||||
D3d-p_*K.lammpstrj
|
||||
#+end_src
|
||||
|
||||
For example:
|
||||
|
||||
#+begin_src text
|
||||
D3d-o_300K.lammpstrj
|
||||
D3d-o_400K.lammpstrj
|
||||
D3d-p_300K.lammpstrj
|
||||
D3d-p_400K.lammpstrj
|
||||
#+end_src
|
||||
|
||||
The temperature is extracted from the filename using the pattern:
|
||||
|
||||
#+begin_src text
|
||||
_(number)K.lammpstrj
|
||||
#+end_src
|
||||
|
||||
For example, =D3d-o_300K.lammpstrj= is interpreted as 300 K.
|
||||
|
||||
* LAMMPS dump format
|
||||
|
||||
The trajectory file is assumed to be a LAMMPS dump file containing
|
||||
unwrapped atomic coordinates:
|
||||
|
||||
#+begin_src text
|
||||
xu yu zu
|
||||
#+end_src
|
||||
|
||||
The script also assumes that the dump file contains a =mol= column, which
|
||||
is used to identify molecules.
|
||||
|
||||
A typical header should include columns such as:
|
||||
|
||||
#+begin_src text
|
||||
ITEM: ATOMS id mol type xu yu zu
|
||||
#+end_src
|
||||
|
||||
* Analysis details
|
||||
|
||||
The benzene atoms are selected by the following atom indices within each
|
||||
molecule:
|
||||
|
||||
#+begin_src python
|
||||
benzene_id = [24, 25, 26, 27, 28, 29]
|
||||
#+end_src
|
||||
|
||||
These indices are hard-coded in the script.
|
||||
|
||||
The orientation of each benzene molecule is calculated from the vector
|
||||
between:
|
||||
|
||||
- the center of the selected benzene atoms
|
||||
- the midpoint of atoms 25 and 26 in the selected benzene atom list
|
||||
|
||||
The orientation angle is calculated using:
|
||||
|
||||
#+begin_src python
|
||||
np.arctan2(vec[:, 1], vec[:, 0])
|
||||
#+end_src
|
||||
|
||||
The z-position is calculated as the mean z-coordinate of the selected
|
||||
benzene atoms.
|
||||
|
||||
* Output files
|
||||
|
||||
The script creates the following pickle files:
|
||||
|
||||
#+begin_src text
|
||||
D3d-o.pkl
|
||||
D3d-p.pkl
|
||||
#+end_src
|
||||
|
||||
Each pickle file contains a dictionary indexed by temperature.
|
||||
|
||||
For example:
|
||||
|
||||
#+begin_src python
|
||||
dset[300]["orientation"]
|
||||
#+end_src
|
||||
|
||||
contains a pandas DataFrame with the following columns:
|
||||
|
||||
| Column | Description |
|
||||
|-----------+------------------------------------------|
|
||||
| angle | Bin center of orientation angle |
|
||||
| angle_y | Histogram count of orientation angle |
|
||||
| zpos | Bin center of z-position |
|
||||
| zpos_y | Histogram count of z-position |
|
||||
|
||||
* Usage
|
||||
|
||||
Place =dump2rotorang.py= in the directory containing the LAMMPS trajectory
|
||||
files, then run:
|
||||
|
||||
#+begin_src sh
|
||||
python dump2rotorang.py
|
||||
#+end_src
|
||||
|
||||
If trajectory files matching the expected patterns exist, the script will
|
||||
print the processed filenames and create pickle files.
|
||||
|
||||
Example:
|
||||
|
||||
#+begin_src text
|
||||
D3d-o_300K.lammpstrj
|
||||
D3d-o_400K.lammpstrj
|
||||
D3d-o.pkl was created.
|
||||
D3d-p_300K.lammpstrj
|
||||
D3d-p_400K.lammpstrj
|
||||
D3d-p.pkl was created.
|
||||
#+end_src
|
||||
|
||||
* Example
|
||||
|
||||
If =example.lammpstrj= is included as a sample trajectory file, rename or
|
||||
copy it to match the expected naming rule before running the script:
|
||||
|
||||
#+begin_src sh
|
||||
cp example.lammpstrj D3d-o_300K.lammpstrj
|
||||
python dump2rotorang.py
|
||||
#+end_src
|
||||
|
||||
This will create:
|
||||
|
||||
#+begin_src text
|
||||
D3d-o.pkl
|
||||
#+end_src
|
||||
|
||||
* Notes
|
||||
|
||||
- The atom indices used for benzene are currently hard-coded.
|
||||
- The script assumes that all molecules have the same number of atoms.
|
||||
- The orientation histogram is calculated in the range from =-pi= to =pi=.
|
||||
- The z-position histogram is calculated in the range from =24= to =25=.
|
||||
- If the target system or molecule definition is changed, the values of
|
||||
=benzene_id= and the histogram range for z-position may need to be
|
||||
modified.
|
||||
|
||||
* Files managed in this repository
|
||||
|
||||
This repository is intended to manage only the following files:
|
||||
|
||||
#+begin_src text
|
||||
dump2rotorang.py
|
||||
example.lammpstrj
|
||||
README.org
|
||||
.gitignore
|
||||
#+end_src
|
||||
|
||||
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python
|
||||
import numpy as np
|
||||
import io
|
||||
import re
|
||||
import pickle
|
||||
import glob
|
||||
import pandas as pd
|
||||
|
||||
|
||||
class LammpsTrj():
|
||||
def __init__(self, trjfile):
|
||||
self.fp = open(trjfile)
|
||||
lines = [self.fp.readline() for i in range(4)]
|
||||
self.atoms = int(lines[-1])
|
||||
self.fp.seek(0)
|
||||
self.getOnestep()
|
||||
# print(self.df)
|
||||
self.fp.seek(0)
|
||||
self.molecules = np.unique(self.df["mol"]).shape[0]
|
||||
|
||||
def __del__(self):
|
||||
self.fp.close()
|
||||
|
||||
def getOnestep(self):
|
||||
block = self.atoms + 9
|
||||
lines = [self.fp.readline() for i in range(block)]
|
||||
if lines[0] == "":
|
||||
return 0
|
||||
self.step = int(lines[1])
|
||||
self.lx = float(lines[5].split()[1])
|
||||
self.ly = float(lines[6].split()[1])
|
||||
self.lz = float(lines[7].split()[1])
|
||||
header = lines[8].split()[2:]
|
||||
data = io.StringIO(" ".join(lines[9:]))
|
||||
self.df = pd.read_csv(data, delimiter=r"\s+", header=None)
|
||||
self.df.columns = header
|
||||
return 1
|
||||
|
||||
def getOrientation(self, benzene_id):
|
||||
xyz = self.df[["xu", "yu", "zu"]].to_numpy()
|
||||
xyz = xyz.reshape((self.molecules, -1, 3))
|
||||
benzene_id = np.array(benzene_id, dtype=int) - 1
|
||||
xyz = xyz[:, benzene_id, :]
|
||||
g = xyz.mean(axis=1)
|
||||
p = xyz[:, [1, 2], :].mean(axis=1)
|
||||
vec = p - g
|
||||
angle = np.arctan2(vec[:, 1], vec[:, 0])
|
||||
return angle
|
||||
# for i, xyz_i in enumerate(xyz):
|
||||
# body = "{}\n\n".format(benzene_id.shape[0])
|
||||
# for r in xyz_i:
|
||||
# body += "C {} {} {}\n".format(*r)
|
||||
# outfile = f"{i:04d}.xyz"
|
||||
# with open(outfile, "w") as o:
|
||||
# o.write(body)
|
||||
|
||||
def getZposition(self, benzene_id):
|
||||
xyz = self.df[["xu", "yu", "zu"]].to_numpy()
|
||||
xyz = xyz.reshape((self.molecules, -1, 3))
|
||||
benzene_id = np.array(benzene_id, dtype=int) - 1
|
||||
xyz = xyz[:, benzene_id, :]
|
||||
zpos = xyz.mean(axis=1)[:, 2]
|
||||
return zpos
|
||||
|
||||
|
||||
def run(trjfile):
|
||||
benzene_id = [24, 25, 26, 27, 28, 29]
|
||||
lmp = LammpsTrj(trjfile)
|
||||
orientation = np.empty((0, lmp.molecules))
|
||||
zpos = np.empty((0, lmp.molecules))
|
||||
while lmp.getOnestep():
|
||||
# print(lmp.step)
|
||||
orientation_ = lmp.getOrientation(benzene_id)
|
||||
orientation = np.vstack((orientation, orientation_))
|
||||
zpos_ = lmp.getZposition(benzene_id)
|
||||
zpos = np.vstack((zpos, zpos_))
|
||||
hist, x = np.histogram(orientation, bins=np.linspace(-np.pi, np.pi, 200))
|
||||
df = pd.DataFrame()
|
||||
df["angle"] = x[0:-1] + (x[1]-x[0])*0.5
|
||||
df["angle_y"] = hist
|
||||
hist, x = np.histogram(zpos, bins=np.linspace(24, 25, 200))
|
||||
df["zpos"] = x[0:-1] + (x[1]-x[0])*0.5
|
||||
df["zpos_y"] = hist
|
||||
temp = int(re.search(r"_(\d+)K\.", trjfile).group(1))
|
||||
dset[temp] = {}
|
||||
dset[temp]["orientation"] = df
|
||||
|
||||
|
||||
for k in ["D3d-o", "D3d-p"]:
|
||||
dset = {}
|
||||
files = sorted(glob.glob(f"{k}_*K.lammpstrj"))
|
||||
for f in files:
|
||||
print(f)
|
||||
run(f)
|
||||
outfile = f"{k}.pkl"
|
||||
with open(outfile, "wb") as f:
|
||||
pickle.dump(dset, f)
|
||||
print(f"{outfile} was created.")
|
||||
+217530
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user