# =*= coding: utf-8 -*-
"""LammpsIO
Created on 21 September 2018
@author: Robert Ivancic
This module was created to facilitate input and output of LAMMPS
trajectory files in dump and netCDF (AMBER) format.
Notes
-----
We plan to add a log reading functionality to this module soon.
"""
import numpy as np
import sys
from netCDF4 import Dataset
from netCDF4 import stringtochar
[docs]class NetCDFIO:
"""Input and output of LAMMPS trajectories in NetCDF (AMBER).
This class inputs and outputs individual frames from an AMBER
format molecular dynamics trajectory. More on AMBER can be found
here: http://ambermd.org/netcdf/nctraj.xhtml. More on NetCDF can
be found here: https://en.wikipedia.org/wiki/NetCDF. There are two
major advantages to this output format over standard dump files.
First, these files are in binary format and thus, use about 1/3 of
the space of standard dump files. Second, reading standard dump files
must be done sequentially. With NetCDF you may obtain data from any
frame of interest *f* instantly by simply selecting that frame in the
data array. The major disadvantage of this format is that it assumes
a constant number of particles throughout a simulation or experiment.
Particles are assumed to be ordered by their ids.
"""
def __init__(self):
self.__openO = False
self.__sett = False
self.__setBB = False
self.__setPos = False
self.__setDataCol = False
self.__closeO = False
self.__openI = False
self.__numDims = False
self.__numFrames = False
self.__numParts = False
self.__gett = False
self.__getBB = False
self.__getPos = False
self.__getDataCol = False
self.__closeI = False
self.__DataCols = []
self.__DataCol_vars = []
[docs] def OpenO(self, nc_file_name):
"""Opens NetCDF file for output.
Opens a NetCDF file of nc_file_name for writing (output).
Parameters
----------
nc_file_name : str
Name of netCDF file you wish to write to.
"""
if self.__openI:
print 'ERROR: Cannot set input and output in same instance'
sys.exit(-1)
if self.__openO:
print 'ERROR: Cannot open file twice!'
sys.exit(-1)
# Conventions
self.__nc_file = Dataset(nc_file_name, 'w', format='NETCDF4')
self.__nc_file.Conventions = 'AMBER'
self.__nc_file.ConventionVersion = '1.0'
self.__nc_file.program ='LammpsPy.py'
self.__nc_file.programVersion = '1.0'
# Dimensions except number of particles
self.__nc_file.createDimension('frame', 0)
self.__nc_file.createDimension('spatial', 3)
self.__nc_file.createDimension('cell_spatial', 3)
self.__nc_file.createDimension('cell_angular', 3)
self.__nc_file.createDimension('label', 5)
# Preliminary variables
char_sp_var = self.__nc_file.createVariable('char spatial',
'S1', ('spatial'))
char_sp_var[:] = ['x','y','z']
char_csp_var = self.__nc_file.createVariable('char cell_spatial',
'S1', ('cell_spatial'))
char_csp_var[:] = ['a','b','c']
char_sp_var = self.__nc_file.createVariable('char cell_angular',
'S1',('cell_angular','label'))
char_sp_var[:] = stringtochar(np.array(['alpha','beta','gamma']))
# notes OpenO has been run
self.__openO = True
[docs] def Sett(self, f, t):
"""Sets timestep t of frame f
Parameters
----------
f : int
frame number
t : int
timestep at frame f
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
if not self.__sett:
self.__t_var = self.__nc_file.createVariable('time', 'f4',
('frame'))
self.__t_var.units = 'LJ'
self.__t_var[f] = t
self.__sett = True
[docs] def SetBB(self, f, bb_t):
"""Sets box boundaries of frame f. These are formatted as
[low_x, high_x] for each dimension.
Parameters
----------
f : int
frame number
bb_t : numpy array (dimension,2)
box boundaries at time t
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
if not self.__setBB:
self.__cell_o_var = self.__nc_file.createVariable('cell_origin',
'f4', ('frame','cell_spatial'))
self.__cell_o_var.units = 'LJ'
self.__cell_l_var = self.__nc_file.createVariable('cell_lengths',
'f4', ('frame','cell_spatial'))
self.__cell_l_var.units = 'LJ'
self.__cell_a_var = self.__nc_file.createVariable('cell_angles',
'f4', ('frame','cell_angular'))
self.__cell_a_var.units = 'degree'
# Sets dimension of output
if not self.__setBB and not self.__setPos:
if bb_t.shape[0] != 2 and bb_t.shape[0] != 3:
print 'ERROR: bb_t.shape[0] != 2 or 3'
sys.exit(-1)
self.__d = bb_t.shape[0]
self.__nc_file.dimension = self.__d
# Adds a 3rd dimension for 2D data
if self.__d != bb_t.shape[0]:
print 'ERROR: dimension != bb_t.shape[0]'
sys.exit(-1)
if self.__d == 2:
bb_t = np.vstack((bb_t, np.array([[-10**(-6),10**(-6)]])))
self.__cell_o_var[f] = bb_t[:,0]
self.__cell_l_var[f] = bb_t[:,1]-bb_t[:,0]
self.__cell_a_var[f] = np.ones(3)*90
self.__setBB = True
[docs] def SetPos(self, f, pos_t):
"""Sets particle positions (coordinates) at frame f
Parameters
----------
f : int
frame number
pos_t : numpy array (number of particles, dimension)
particle positions (coordinates) at frame f
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
if not self.__setPos and not self.__setDataCol:
self.__nc_file.createDimension('atom', pos_t.shape[0])
if not self.__setPos:
self.__c_var = self.__nc_file.createVariable('coordinates', 'f4',
('frame','atom','spatial'))
self.__c_var.units = 'LJ'
# Sets dimension of output
if not self.__setBB and not self.__setPos:
if pos_t.shape[1] != 2 and pos_t.shape[1] != 3:
print 'ERROR: pos_t.shape[1] != 2 or 3'
sys.exit(-1)
self.__d = pos_t.shape[1]
self.__nc_file.dimension = self.__d
# Adds a 3rd dimension for 2D data
if self.__d != pos_t.shape[1]:
print 'ERROR: dimension != pos_t.shape[1]'
sys.exit(-1)
if self.__d == 2:
pos_t = np.hstack((pos_t, np.array([np.zeros(pos_t.shape[0])]).T))
self.__c_var[f] = pos_t
self.__setPos = True
[docs] def SetDataCol(self, f, label, data_col_t):
"""Sets a data column at frame f
A data column is a way of storing values that are associated with
every particle in a simulation or experiment at every timestep.
Examples include: J2, D2min, p_{hop}, or softness of every particle
at every timestep. This sets a data column for time t.
Parameters
----------
f : int
frame number
label : str
data column name
data_col_t : numpy array (number of particles,)
data column values for all particles at frame f
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
if not self.__setPos and not self.__setDataCol:
self.__nc_file.createDimension('atom', pos_t.shape[0])
if label not in self.__DataCols:
self.__DataCols.append(label)
self.__DataCol_vars.append(self.__nc_file.createVariable(
label, 'f4', ('frame','atom')))
self.__DataCol_vars[-1].units = 'LJ'
idx_col = (self.__DataCols).index(label)
(self.__DataCol_vars)[idx_col][f] = data_col_t
self.__setDataCol = True
# Closes output file
[docs] def CloseO(self):
"""Closes output NetCDF file
"""
self.__nc_file.close()
self.__closeO = True
# Opens input file
[docs] def OpenI(self, nc_file_name):
"""Opens NetCDF file for input.
Opens a NetCDF file of nc_file_name for reading (input).
Parameters
----------
nc_file_name : str
Name of netCDF file you wish to read from.
"""
if self.__openI:
print 'ERROR: Cannot open file twice!'
sys.exit(-1)
if self.__openO:
print 'ERROR: Cannot set input and output in same instance'
sys.exit(-1)
self.__nc_file = Dataset(nc_file_name, 'r', format='NETCDF4')
self.__openI = True
# returns number of dimensions
[docs] def NumDims(self):
"""Outputs number of dimensions of current simulation being read.
Returns
-------
d : int
Number of dimensions of simulation you are reading.
"""
if not self.__openI:
print 'ERROR: Must use OpenI before num functions'
sys.exit(-1)
self.__numDims = True
# Checks if has attribute dimensions. If it does takes that
# number to be ground truth. Otherwise assumes 3D.
if hasattr(self.__nc_file, 'dimension'):
self.__d = self.__nc_file.dimension
else:
self.__d = 3
return self.__d
# returns number of frames
[docs] def NumFrames(self):
"""Outputs number of frames of current simulation being read.
Returns
-------
n_f : int
Number of frames of simulation you are reading.
"""
if not self.__openI:
print 'ERROR: Must use OpenI before num functions'
sys.exit(-1)
self.__numFrames = True
n_f = self.__nc_file.dimensions['frame'].size
return n_f
# returns number of particles
[docs] def NumParts(self):
"""Outputs number of particles of current simulation being read.
Returns
-------
n_p : int
Number of particles of simulation you are reading.
"""
if not self.__openI:
print 'ERROR: Must use OpenI before num functions'
sys.exit(-1)
self.__numParts = True
n_p = self.__nc_file.dimensions['atom'].size
return n_p
# returns timestep for frame f
[docs] def Gett(self, f):
"""Gets timestep t of frame f
Parameters
----------
f : int
frame number
Returns
-------
t : int
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__gett = True
t = self.__nc_file.variables['time'][f]
return t
# returns box boundaries for frame f
[docs] def GetBB(self, f):
"""Gets box boundaries (BB) of frame f. These are formatted as
[low_x, high_x] for each dimension.
Parameters
----------
f : int
frame number
Returns
-------
bb_t : numpy array (dimension,2)
box boundaries at time t
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__getBB = True
bb_L = self.__nc_file.variables['cell_origin'][f]
bb_R = self.__nc_file.variables['cell_lengths'][f] + bb_L
bb_t = np.vstack((bb_L, bb_R)).T
# Gets dimensions of array
d = self.NumDims()
return bb_t[:d]
# returns atom coordinates for frame f
[docs] def GetPos(self, f):
"""Gets particle positions (coordinates) at frame f
Parameters
----------
f : int
frame number
Returns
-------
pos_t : numpy array (number of particles, dimension)
particle positions (coordinates) at frame f
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__getPos = True
pos_t = self.__nc_file.variables['coordinates'][f]
# Gets dimensions of array
d = self.NumDims()
return pos_t[:,:int(d)]
# returns box boundaries for frame f
[docs] def GetDataCol(self, f, label):
"""Sets a data column at frame f
A data column is a way of storing values that are associated with
every particle in a simulation or experiment at every timestep.
Examples include: J2, D2min, p_{hop}, or softness of every particle
at every timestep. This gets a data column for time t.
Parameters
----------
f : int
frame number
label : str
data column name
Returns
-------
data_col_t : numpy array (number of particles,)
data column values for all particles at frame f
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__getDataCol = True
data_col = self.__nc_file.variables[label][f]
return data_col
# Closes output file
[docs] def CloseI(self):
"""Closes input NetCDF file
"""
self.__nc_file.close()
self.__closeI = True
[docs]class DumpIO:
""" Input and output LAMMPS trajectories in dump (lammpstrj) format.
This class inputs and outputs frames of a LAMMPS trajectory. It does
this *sequentially*, i.e. it reads (writes) in a single frame of a dump
(lammpstrj) trajectory at a time starting at frame 0. This approach has
two benefits to reading in an entire trajectory at once both steming
from the fact that it is more memory efficient. First (and most
importantly), python has memory limits that are easily reached if
the number of particles times the number of frames loaded in at one
time is greater than 25,000,000. Practically, it is very easy to hit
this limit when running large or long time simulations. Second,
this approach is generally faster than loading in all frames at once
as it requires much less time to allocate memory.
"""
def __init__(self):
self.__openO = False
self.__sett = False
self.__setBB = False
self.__setPos = False
self.__setID = False
self.__setDataCol = False
self.__id_t = np.array([])
self.__writeNextFrame = False
self.__setIDWarning = False
self.__closeO = False
self.__openI = False
self.__loadNextFrame = False
self.__numDims = False
self.__numFrames = False
self.__numParts = False
self.__gett = False
self.__getBB = False
self.__getPos = False
self.__getDataCol = False
self.__closeI = False
self.__DataCols = []
self.__DataCol_arrs = []
[docs] def OpenO(self, dump_file_name):
""" Opens dump file for output.
Opens a dump (lammpstrj) file of name dumpe_file_name for writing
(output).
"""
if self.__openI:
print 'ERROR: Cannot set input and output in same instance'
sys.exit(-1)
if self.__openO:
print 'ERROR: Cannot open file twice!'
sys.exit(-1)
# Opens file for writing
self.__dump_file = open(dump_file_name, 'w')
# notes OpenO has been run
self.__openO = True
[docs] def Sett(self, t):
""" Sets timestep t of current frame
Parameters
----------
t : int
timestep of current frame
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
self.__t = t
self.__sett = True
[docs] def SetBB(self, bb_t):
""" Sets box boundaries (BB) of current frame
Parameters
----------
bb_t : numpy array (dimension,2)
box boundaries of current frame
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
# Sets dimension of output
if not self.__setBB and not self.__setPos:
if bb_t.shape[0] != 2 and bb_t.shape[0] != 3:
print 'ERROR: bb_t.shape[0] != 2 or 3'
sys.exit(-1)
self.__d = bb_t.shape[0]
# Adds a 3rd dimension for 2D data
if self.__d != bb_t.shape[0]:
print 'ERROR: dimension != bb_t.shape[0]'
sys.exit(-1)
if self.__d == 2:
bb_t = np.vstack((bb_t, np.array([[-10**(-6),10**(-6)]])))
self.__bb_t = bb_t
self.__setBB = True
[docs] def SetID(self, id_t):
""" Sets particle ids of current frame
Parameters
----------
id_t : numpy array (number of particles,)
particle ids of each particle of current frame
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
self.__id_t = id_t
self.__setID = True
[docs] def SetPos(self, pos_t):
""" Sets particle positions of current frame
Parameters
----------
pos_t : numpy array (number of particles, dimensions)
particle positions (coordinates) of current frame in order of
id_t
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
# Sets dimension of output
if not self.__setBB and not self.__setPos:
if pos_t.shape[1] != 2 and pos_t.shape[1] != 3:
print 'ERROR: pos_t.shape[1] != 2 or 3'
sys.exit(-1)
self.__d = pos_t.shape[1]
# Adds a 3rd dimension for 2D data
if self.__d != pos_t.shape[1]:
print 'ERROR: dimension != pos_t.shape[1]'
sys.exit(-1)
self.__pos_t = pos_t
self.__setPos = True
[docs] def SetDataCol(self, label, data_col_t):
""" Sets particle positions of current frame
Parameters
----------
label : str
name of the data column
data_col_t : numpy array (number of particles,)
particle positions (coordinates) of current frame in order of
id_t
"""
if not self.__openO:
print 'ERROR: Must use OpenO before set functions'
sys.exit(-1)
if label not in self.__DataCols:
self.__DataCols.append(label)
# Finds index of data column
idx_col = (self.__DataCols).index(label)
while(idx_col >= len(self.__DataCol_arrs)):
self.__DataCol_arrs.append([])
self.__DataCol_arrs[idx_col] = data_col_t
self.__setDataCol = True
[docs] def WriteNextFrame(self):
""" Writes the next frame to the dump file.
Writes all timestep, box boundary, particle id, particle position,
and data column information given in frame to file. Must use OpenO
and Set functions before use.
Warnings
--------
Will run without having set particle ids. Assumes particles in order
from 1,...,(number of particles).
"""
error_message = 'ERROR: Incorrect input formatting. Ensure:\n\t'
if not self.__openO:
print 'ERROR: Must use OpenO before Write functions'
sys.exit(-1)
if not self.__sett:
print error_message + 'Sett is used'
sys.exit(-1)
if not self.__setBB:
print error_message + 'SetBB is used'
sys.exit(-1)
if not self.__setPos:
print error_message + 'SetPos is used'
sys.exit(-1)
if len(self.__DataCols) != len(self.__DataCol_arrs):
print error_message+'All data columns are stored in each frame'
sys.exit(-1)
if self.__id_t.shape[0] != self.__pos_t.shape[0] and self.__setID:
print error_message+'id_t.shape[0] == pos_t.shape[0]'
sys.exit(-1)
elif not self.__setID:
# Automatically assumes particles in order if ids not set
if not self.__setIDWarning:
print 'WARNING: SetID function not used. Assuming particle ID'
print '\tis in order particles are in pos_t'
self.__setIDWarning = True
self.__id_t = np.arange(self.__pos_t.shape[0])+1
for col in range(len(self.__DataCols)):
if self.__DataCol_arrs[col].shape[0] != self.__pos_t.shape[0]:
print error_message+'For data column '+\
str(self.__DataCols[col])+', '+\
'col.shape[0] == pos_t.shape[0]'
sys.exit(-1)
# Finds number of particles and dimension
n_p = self.__pos_t.shape[0]
bb_t = self.__bb_t
if self.__d == 2:
dim_str = 'x y '
elif self.__d==3:
dim_str = 'x y z '
else:
print 'ERROR: Must have 2 or 3 dimensions'
sys.exit(-1)
# Writes frame header
self.__dump_file.write('ITEM: TIMESTEP\n'+str(self.__t)+'\n')
self.__dump_file.write('ITEM: NUMBER OF ATOMS\n'+str(n_p)+'\n')
self.__dump_file.write('ITEM: BOX BOUNDS\n')
bb_str_t = ' \n'.join([' '.join(lin) for lin \
in bb_t.astype(str)])+'\n'
self.__dump_file.write(bb_str_t)
dataH_str = 'ITEM: ATOMS '+'id '+dim_str+\
' '.join(self.__DataCols)+' \n'
self.__dump_file.write(dataH_str)
# Writes frame data
ids = self.__id_t.astype(str)
pos_t = self.__pos_t.astype(str)
if len(self.__DataCol_arrs) > 0:
dataCols_t = np.array(self.__DataCol_arrs).astype(str)
data_t = np.vstack((ids, pos_t.T, dataCols_t)).T
else:
data_t = np.vstack((ids, pos_t.T)).T
data_str_t = ' \n'.join([' '.join(lin) for lin in data_t])+'\n'
self.__dump_file.write(data_str_t)
[docs] def CloseO(self):
""" Closes output file for dump
"""
self.__dump_file.close()
self.__closeO = True
[docs] def OpenI(self, dump_file_name):
""" Opens lammpstrj file for input
Opens a dump (lammpstrj) file of name dump_file_name for reading
(input)
"""
if self.__openI:
print 'ERROR: Cannot open file twice!'
sys.exit(-1)
if self.__openO:
print 'ERROR: Cannot set input and output in same instance'
sys.exit(-1)
# Opens file for writing
self.__dump_file = open(dump_file_name, 'r')
self.__openI = True
[docs] def LoadNextFrame(self):
""" Loads next frame in the dump (lammpstrj) file.
Reads all timestep, box boundary, particle id, particle position,
and data column information given in frame to file. Must use OpenI
before use. Get functions may be used after this function.
"""
# Reads the header of dump file
line = ''
while line[:11] != 'ITEM: ATOMS':
line = self.__dump_file.readline()
if line[:16] == 'ITEM: BOX BOUNDS':
bb_t = []
line = self.__dump_file.readline()
while line[:5] != 'ITEM:':
last_pos = self.__dump_file.tell()
bb_t.append(np.array(line.split()).astype(float))
line = self.__dump_file.readline()
self.__dump_file.seek(last_pos)
self.__bb_t = np.array(bb_t)
line = ''
if line[:14] == 'ITEM: TIMESTEP':
line = self.__dump_file.readline()
self.__t = int(line)
if line[:21] == 'ITEM: NUMBER OF ATOMS':
line = self.__dump_file.readline()
n_p = int(line)
# Obtains data columns of data
DataCols = np.array(line[11:].split())
col_id = np.where(DataCols=='id')[0][0]
col_x = np.where(DataCols=='x')[0][0]
col_y = np.where(DataCols=='y')[0][0]
if 'z' in DataCols:
self.__d = 3
col_z = np.where(DataCols=='z')[0][0]
col_coordinates = np.array([col_x, col_y, col_z, col_id])
else:
self.__d = 2
col_coordinates = np.array([col_x, col_y, col_id])
remove_cols = np.array(['id','x','y','z'])
DataCols_no_coordinates = np.setdiff1d(DataCols,remove_cols)
self.__DataCols = DataCols_no_coordinates
DataCols_idx = np.array([np.where(DataCols==col)[0][0] \
for col in self.__DataCols])
n_DataCols = len(self.__DataCols)
# Obtains data from frame
self.__pos_t = np.zeros((n_p, self.__d))
self.__id_t = np.zeros(n_p)
self.__DataCol_arrs = [np.zeros(n_p) for ii in range(n_DataCols)]
for pp in range(n_p):
line = self.__dump_file.readline()
data_pp = line.split()
# Stores data
self.__pos_t[pp,0] = float(data_pp[col_x])
self.__pos_t[pp,1] = float(data_pp[col_y])
if self.__d != 2:
self.__pos_t[pp,2] = float(data_pp[col_z])
self.__id_t[pp] = int(data_pp[col_id])
for idx, col in enumerate(DataCols_idx):
self.__DataCol_arrs[idx][pp] = float(data_pp[col])
self.__loadNextFrame = True
[docs] def NumDims(self):
"""Outputs number of dimensions of current simulation being read.
Returns
-------
d : int
Number of dimensions of simulation you are reading.
"""
if not self.__openI:
print 'ERROR: Must use OpenI before num functions'
sys.exit(-1)
if not self.__loadNextFrame:
last_pos = self.__dump_file.tell()
self.LoadNextFrame()
self.__dump_file.seek(last_pos)
self.__numDims = True
return self.__d
[docs] def NumFrames(self):
"""Outputs number of frames of current simulation being read.
Returns
-------
n_f : int
Number of frames of the simulation you are reading.
"""
if not self.__openI:
print 'ERROR: Must use OpenI before num functions'
sys.exit(-1)
# stores current position in file and restarts read
# loops through all lines in file to find ITEM: ATOMS
n_f = 0
last_pos = self.__dump_file.tell()
self.__dump_file.seek(0)
for line in self.__dump_file:
if line[:11] == 'ITEM: ATOMS':
n_f += 1
self.__dump_file.seek(last_pos)
self.__numFrames = True
return n_f
[docs] def NumPartsCurrentf(self):
"""Outputs number of particles in current frame.
Returns
-------
n_p : int
Number of particles in the current frame.
Warnings
--------
If used without loading any frames, gives number of particles of
first frame.
"""
if not self.__openI:
print 'ERROR: Must use OpenI before num functions'
sys.exit(-1)
if not self.__loadNextFrame:
last_pos = self.__dump_file.tell()
self.LoadNextFrame()
self.__dump_file.seek(last_pos)
self.__numParts = True
return self.__pos_t.shape[0]
[docs] def Gett(self):
""" Gets timestep t of current frame.
Returns
-------
t : int
timestep of the current frame.
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__gett = True
t = self.__t
return t
[docs] def GetBB(self):
""" Gets box boundary (BB) of current frame. These are formatted as
[low_x, high_x] for each dimension.
Returns
-------
bb_t : numpy array (dimension,2)
box boundaries of current frame
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__getBB = True
bb_t = self.__bb_t
return bb_t[:self.__d]
[docs] def GetID(self):
""" Gets particle ids of current frame
Returns
----------
id_t : numpy array (number of particles,)
particle ids of each particle of current frame
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__getBB = True
id_t = self.__id_t.astype(int)
return id_t
[docs] def GetPos(self):
""" Gets particle positions (coordinates) of current frame
Returns
----------
pos_t : numpy array (number of particles, dimension)
particle positions (coordinates) of each particle of current
frame
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__getPos = True
pos_t = self.__pos_t
return pos_t
# returns box boundaries for current frame
[docs] def GetDataCol(self, label):
""" Gets data column of current frame
A data column is a way of storing values that are associated with
every particle in a simulation or experiment at every timestep.
Examples include: J2, D2min, p_{hop}, or softness of every
particle at every timestep. This gets a data column for the current
frame in the dump file.
Parameters
----------
label : str
name of data column label
Returns
----------
id_t : numpy array (number of particles,)
particle ids of each particle of current frame
"""
if not self.__openI:
print 'ERROR: Must use OpenI before get functions'
sys.exit(-1)
self.__getDataCol = True
try:
data_col = np.where(self.__DataCols==label)[0][0]
data = self.__DataCol_arrs[data_col]
except:
print 'ERROR: label for data column not in dump file'
sys.exit(-1)
return data
# Closes output file
[docs] def CloseI(self):
""" Closes input (reading) dump file.
"""
self.__dump_file.close()
self.__closeO = True
[docs] def SortByID(self):
""" Sorts particles of all arrays by their id
Sorts pos_t, id_t, and data_col_t arrays so that
id_t = range(n_p)
"""
# ranking of id values
ranks = self.__id_t.argsort()
# Performs sorting
self.__id_t = self.__id_t[ranks]
self.__pos_t = self.__pos_t[ranks]
for col in range(len(self.__DataCol_arrs)):
self.__DataCol_arrs[col] = self.__DataCol_arrs[col][ranks]