API#
The Simulation Class#
- class gamdpy.Simulation(configuration: Configuration, interactions: Interaction | list[Interaction], integrator: Integrator, runtime_actions: list[RuntimeAction], num_timeblocks, steps_per_timeblock, storage: str, compute_plan=None, verbose=False, timing=True, steps_in_kernel_test=1)#
Class for running a simulation.
- Parameters:
configuration (gamdpy.Configuration) – The configuration to simulate.
interactions (list of interactions) – Interactions such as pair potentials, bonds, external fields, etc.
integrator (an integrator) – The integrator to use for the simulation.
runtime_actions (list of runtime actions) – Runtime actions such as ScalarSaver, TrajectorySaver or MomentumReset
num_timeblocks (int) – Number of timeblocks to run the simulation. If not 0, then steps_per_timeblock should be set.
steps_per_timeblock (int) – Number of steps per timeblock.
compute_plan (dict) – A dictionary with the compute plan for the simulation. If None, a default compute plan is used.
storage (str) – Storage for the simulation output. Can be ‘memory’ or a filename with extension ‘.h5’.
verbose (bool) – If True, print verbose output.
timing (bool) – If True, timing information is saved.
See also
- run(verbose=True)#
Run the simulation.
See also
gamdpy.Simulation.timeblocks()
- run_timeblocks(num_timeblocks=-1)#
Generator for running the simulation one block at a time.
- Parameters:
num_timeblocks (int) – Number of blocks to run. If -1, all blocks are run.
Examples
>>> import gamdpy as gp >>> sim = gp.get_default_sim() >>> for block in sim.run_timeblocks(num_timeblocks=3): ... print(f'{block=}') # Replace with code to analyze the current configuration block=0 block=1 block=2
See also
- status(per_particle=False) str#
String with the current status Should be executed during the simulation run, see
gamdpy.Simulation.timeblocks()- Parameters:
per_particle (bool) – If True, the values are divided by the number of particles in the configuration.
- Returns:
A string with the current status of the simulation.
- Return type:
str
- summary() str#
Returns a summary string of the simulation run. Should be called after the simulation has been run, see
gamdpy.Simulation.timeblocks()orgamdpy.Simulation.run()
The Configuration Class#
- class gamdpy.Configuration(D: int, N: int = None, type_names=None, compute_flags=None, ftype=<class 'numpy.float32'>, itype=<class 'numpy.int32'>)#
The configuration class
Store particle vectors (positions, velocities, forces) and scalars (energy, virial, mass …). Also store particle type, image coordinates, and the simulation box.
- Parameters:
D (int) – Spatial dimension for the configuration.
N (int [Optional]) – Number of particles. If not set, this will be determined the first time particle data is written to the configuration.
Examples
>>> import gamdpy as gp >>> conf = gp.Configuration(D=3, N=1000) >>> print(conf.vector_columns) # Print names of vector columns ['r', 'v', 'f'] >>> print(conf.scalar_columns) # Print names of scalar columns ['U', 'W', 'K', 'm'] >>> print(conf['r'].shape) # Vectors are stored as (N, D) numpy arrays (1000, 3) >>> print(conf['m'].shape) # Scalars are stored as (N,) numpy arrays (1000,)
Data can be accessed via string keys (similar to dataframes in pandas):
>>> conf['r'] = np.ones((1000, 3)) >>> conf['v'] = 2 # Broadcast by numpy to correct shape >>> print(conf['r'] + 0.01*conf['v']) [[1.02 1.02 1.02] [1.02 1.02 1.02] [1.02 1.02 1.02] ... [1.02 1.02 1.02] [1.02 1.02 1.02] [1.02 1.02 1.02]]
A configuration can be specified without setting the number particles, N. In that case N is determined the first time the particle data is written to the configuration:
>>> import numpy as np >>> conf = gp.Configuration(D=3) >>> conf['r'] = np.zeros((400, 3)) >>> print(conf['r'].shape) (400, 3)
- copy_to_device()#
Copy all data to device memory
- copy_to_host()#
Copy all data to host memory
- get_potential_energy() float#
Get total potential energy of the configuration
- get_volume()#
Get volume of simulation box associated with configuration
- make_lattice(unit_cell: dict, cells: list, rho: float = None) None#
Generate a lattice configuration
The lattice is constructed by replicating the unit cell in all directions. Unit cell is a dictonary with fractional_coordinates for particles, and the lattice_constants as a list of unit cell lengths in all directions.
Unit cells are available in gamdpy.unit_cells
Example
>>> import gamdpy as gp >>> conf = gp.Configuration(D=3) >>> conf.make_lattice(gp.unit_cells.FCC, cells=[8, 8, 8], rho=1.0) >>> print(gp.unit_cells.FCC) # Example of a unit cell dict {'fractional_coordinates': [[0.0, 0.0, 0.0], [0.5, 0.5, 0.0], [0.5, 0.0, 0.5], [0.0, 0.5, 0.5]], 'lattice_constants': [1.0, 1.0, 1.0]}
- make_positions(N, rho)#
Generate particle positions in D dimensions.
Positions are generated in a simple cubic configuration in D dimensions. Takes the number of particles N and the density rho as inputs
Example
>>> import gamdpy as gp >>> conf = gp.Configuration(D=3) >>> conf.make_positions(N=27, rho=0.2)
- randomize_velocities(temperature, seed=None, ndofs=None)#
Randomize velocities according to a given temperature. If T <= 0, set all velocities to zero.
- save(output: File, group_name: str, mode='w', include_topology=False) None#
Write a configuration to a HDF5 file
- Parameters:
configuration (gamdpy.Configuration) – a gamdpy configuration object
output (h5py.File) – h5 file
group_name (str) – name of the group which will be created in the h5 and in which the configuration will be saved
mode (str) – default value is “w” and corresponds to replacing existing dataset
Example
>>> import os >>> import h5py >>> import gamdpy as gp >>> conf = gp.Configuration(D=3) >>> conf.make_positions(N=10, rho=1.0) >>> conf.save(output=h5py.File("final.h5", "w"), group_name="configuration", mode="w") >>> os.remove("final.h5") # Removes file (for doctests) >>> with h5py.File("manyconfs.h5", "a") as fout: ... conf.save(output=fout, group_name="restarts/restart0000", mode="w") ... conf.save(output=fout, group_name="restarts/restart0001", mode="w") ... conf.save(output=fout, group_name="restarts/restart0002", mode="w") >>> os.remove("manyconfs.h5") # Removes file (for doctests)
Simulation boxes#
An simulation box object is attached to an configuration object.
- class gamdpy.Orthorhombic(D, lengths)#
Standard rectangular simulation box class
Example
>>> import gamdpy as gp >>> import numpy as np >>> simbox = gp.Orthorhombic(D=3, lengths=np.array([3,4,5]))
- get_dist_sq_dr_function()#
Generates function dist_sq_dr which computes displacement and distance squared for one neighbor
- get_dist_sq_function()#
Generates.function dist_sq_function which computes distance squared for one neighbor
- get_lengths()#
Return the box lengths as a numpy array
- get_volume()#
Return the box volume
- get_volume_function()#
Return the box volume
- scale(scale_factor)#
Scale the box lengths by scale_factor
- class gamdpy.LeesEdwards(D, lengths, box_shift=0.0, box_shift_image=0)#
Simulation box class with LeesEdwards bondary conditions
Example
>>> import gamdpy as gp >>> import numpy as np >>> simbox = gp.LeesEdwards(D=3, lengths=np.array([3,4,5]), box_shift=1.0)
- get_dist_sq_dr_function()#
Generates function dist_sq_dr which computes displacement and distance for one neighbor
- get_dist_sq_function()#
Generates.function dist_sq_function which computes distance squared for one neighbor
- get_volume()#
Calculate and return the volume, on the host
- get_volume_function()#
Returns the function which calculates the volume of the simulation box
- scale(scale_factor)#
Rescale the box by a factor scale_factor, in all directions, if scale_factor is a single float or by a different factor in each direction if scale_factor is an array of length D
Integrators#
- class gamdpy.NVE(dt)#
Total energy conserving integrator
Use the Leap-frog algorithm to integrate the equations of motion:
\[ \begin{align}\begin{aligned}v(t+dt/2) &= v(t-dt/2) + f(t) dt / m\\r(t+dt) &= r(t) + v(t+dt/2) dt\end{aligned}\end{align} \]- Parameters:
dt (float) – Time step for the integration.
- get_kernel(configuration: Configuration, compute_plan: dict, compute_flags: dict[str, bool], interactions_kernel, verbose=False)#
Get a kernel (or python function depending on compute_plan[“gridsync”]) that implements performing a number of steps of the integrator
- get_params(configuration: Configuration, interactions_params: tuple, verbose=False) tuple#
Get a tuple with the parameters expected by the associated kernel
- class gamdpy.NVT(temperature, tau: float, dt: float)#
The leapfrog algorithm with a Nose-Hoover thermostat
Integrator keeping N (number of particles), V (volume), and T (temperature) constant, using the leapfrog algorithm and a Nose-Hoover thermostat.
- Parameters:
temperature (float or function) – The temperature to keep the system at. If a function, it should take time as argument.
tau (float) – The relaxation time of the thermostat.
dt (float) – The time step of the integration.
- get_kernel(configuration: Configuration, compute_plan: dict, compute_flags: dict, interactions_kernel, verbose=False)#
Get a kernel (or python function depending on compute_plan[“gridsync”]) that implements performing a number of steps of the integrator
- get_params(configuration: Configuration, interactions_params: tuple, verbose=False) tuple#
Get a tuple with the parameters expected by the associated kernel
- class gamdpy.NVT_Langevin(temperature, alpha: float, dt: float, seed: int)#
NVT Langevin Leap-frog integrator
The langevin thermostat is a stochastic thermostat that keeps the system at a constant temperature:
\[m a = f - \alpha v + \beta\]where \(a\) is the acceleration, \(f\) is the force, \(v\) is the velocity, \(m\) is the mass, \(\alpha\) is the friction coefficient, and \(\beta\) is a random number drawn from a normal distribution. The implementation uses the leap-frog algorithm described in reference https://arxiv.org/pdf/1303.7011.pdf
- Parameters:
temperature (float or function) – Temperature of the thermostat. If a function, it must take a single argument, time, and return a float.
alpha (float) – Friction coefficient of the thermostat.
dt (float) – Time step for the integration.
- get_kernel(configuration: Configuration, compute_plan: dict, compute_flags: dict[str, bool], interactions_kernel, verbose=False)#
Get a kernel (or python function depending on compute_plan[“gridsync”]) that implements performing a number of steps of the integrator
- get_params(configuration: Configuration, interactions_params: tuple, verbose=False) tuple#
Get a tuple with the parameters expected by the associated kernel
- class gamdpy.NPT_Atomic(temperature, tau: float, pressure, tau_p: float, dt: float)#
Constant NPT integrator for atomic systems
Integrator keeping N (number of particles), P (pressure), and T (temperature) constant, using the leapfrog algorithm and the thermostat-barostat by G Martyna, DJ Tobias and ML Klein in Molecular Physics 87(5), 1117 (1996), doi:10.1063/1.467468 Note that the thermostat and barostat states defined here are \(p_\xi/Q\) and \(p_\epsilon/W\) from Eq. 2.9 in the paper.
- Parameters:
temperature (float or function) – Target temperature as a function of time or constant
tau (float) – Thermostat relaxation time
pressure (float or function) – Target pressure as a function of time or constant
tau_p (float) – Barostat relaxation time
dt (float) – Timestep size
- get_kernel(configuration: Configuration, compute_plan: dict, compute_flags: dict, interactions_kernel, verbose=False)#
Get a kernel (or python function depending on compute_plan[“gridsync”]) that implements performing a number of steps of the integrator
- get_params(configuration: Configuration, interactions_params: tuple, verbose=False) tuple#
Get a tuple with the parameters expected by the associated kernel
- class gamdpy.NPT_Langevin(temperature, pressure, alpha: float, alpha_baro, mass_baro, volume_velocity, barostatModeISO, boxFlucCoord, dt: float, seed: int)#
Constant NPT Langevin integrator NPT Langevin Leap-frog integrator based on N. Grønbech-Jensen and Oded Farago, J. Chem. Phys. 141, 194108 (2014), doi:10.1063/1.4901303
- get_kernel(configuration: Configuration, compute_plan: dict, compute_flags: dict[str, bool], interactions_kernel, verbose=False)#
Get a kernel (or python function depending on compute_plan[“gridsync”]) that implements performing a number of steps of the integrator
- get_params(configuration: Configuration, interactions_params: tuple, verbose=False) tuple#
Get a tuple with the parameters expected by the associated kernel
- class gamdpy.SLLOD(shear_rate, dt)#
The SLLOD integrator
Shear an atomic system in the xy-plane using the SLLOD equations.
- Parameters:
shear_rate (float) – The shear rate of the system.
dt (float) – The time step of the simulation.
- get_kernel(configuration, compute_plan, compute_flags, interactions_kernel, verbose=False)#
Get a kernel (or python function depending on compute_plan[“gridsync”]) that implements performing a number of steps of the integrator
- get_params(configuration, interactions_params, verbose=False)#
Get a tuple with the parameters expected by the associated kernel
- class gamdpy.NVU_RT(target_u: float, threshold: float, initial_step: float = 0.1, initial_step_if_high: float = 0.01, step: float = 1, max_steps: int = 20, max_initial_step_corrections: int = 20, max_abs_val: float = 2, eps: float = 1e-07, debug_print: bool = False, mode: Literal['reflection', 'no-inertia', 'reflection-mass_scaling'] = 'reflection-mass_scaling', save_path_u: bool = False, raytracing_method: Literal['parabola', 'parabola-newton', 'bisection'] = 'parabola', float_type: Literal['32', '64'] = '64')#
Potential energy conserving integrator. Calculate the positions by reflecting on the constant potential energy hypersurface and doing Ray Tracing (RT).
Uses parabola approximations, newton-rhapson or bisection to perform raytrcing.
- Parameters:
target_u (float) – Target Potential Energy (U_0) to maintain constant along the simulation
threshold (float) – Width of the potential energy “shell” relative to U_0. [Iterative Method] When the potential energy of a certain configuration is within threshold if the potential energy of the fist step, iteration is finished. |U(t) / U_0 - 1| < threshold. It needs to be small enough so that the iterative method is precise enough (it can get very chaotic if it is too high). For example: 1e-6.
initial_step (float, default=0.1) – [Iterative Metod] Initial step in configuration space so that x = positions + d * initial_step is the initial guess for the root algorithm. d is the velocity normalized. For method bisection, it needs to be big enough so that it steps away from the initial position but small enough so that it doesn’t reach out of the surface. If it is two big the algorithm will try to correct it. For method parabola it needs to be as big as possible but it needs to be a point that is below U_0. For example: 0.01. It is better to be based on the density so a good value is something like 0.5 / rho^(1/3).
initial_step_if_high (float, default=0.01) – [Iterative Metod] Initial step if the potential energy of the initial configuration (time == 0) is higher than the target potential energy. It should be high enough to “enter” the potential energy surface U = U_0. For example: same setting as initial step.
step (float, default=1) – [Iterative Method] (only for bisection method) Step to look for a point with u > u0. For example: 1. As in initial it is better for it to based on the density.
max_steps (int, default=20) – [Iterative Method] Maximum calls to the interactions kernel to find a point outside the hypersurface. Good enough value is maybe 10 for parabola method and 100 for bisection method.
max_initial_step_corrections (int, default=20) – [Iterative Method] If initial_step is too big the algorithm will try to correct it this amount of times. At the nth correction step initial_step_n = initial_step_0 * (1/2)^n. In the first iteration if U > U0 then initial step is corrected to make it bigger (s_n = s_0 * 2^n). For example: 10 (max correction will be approximately 1000).
max_abs_val (float, default=2) – [Iterative Metod] (only for bisection) Some potential energy functions increas rapidly at a certain configurations. To prevent numerical errors, if the absolute potential energy of a given configuration, |U|, is above U_0 * max_abs_val, the iterative method will discard that configuration as invalid and reach “less far” into configurational space. For example: 2.
eps (float, default=1e-7) – [Iterative Method] Because of numerical inaccuracies, it could happen that the same value calculated twice once is positive and once is negative. Values of the potential energy relative to the target potential enery with |x| < eps are considered neither positive or negative in the algo. Needs to be smaller than threshold.
debug_print (bool, default=False) – If a root is not found, the 0th thread prints useful debugging information if debug_print is enabled.
mode ({"reflection", "no-inertia", "reflection-mass_scaling"}, default = "reflection-mass_scaling") – Mode to perform the reflection. reflection-mass_scaling applies a correction that takes into account the mass of each particle. If the setup does not include particles with different masses,
reflectionwill be faster (not that much). no-inertia is a testing feature: instead of reflecitng velocities in the hyper surface the new velocities follow the direction of the normal vector (the force).save_path_u (optional, default=False) – Save the potential energy between two consecutive points in the iteration
raytracing_method ({"parabola", "parabola-newton", "bisection"}, default = "parabola") – Methodology to find the next point in the surface with same potential energy
float_type ({"64", "32"}, default = "64") – Float type for the potential energy. Higher threshold can work with float32
- get_kernel(configuration, compute_plan, compute_flags, interactions_kernel, verbose=False)#
Get a kernel (or python function depending on compute_plan[“gridsync”]) that implements performing a number of steps of the integrator
- get_params(configuration, interaction_params, verbose=False)#
Get a tuple with the parameters expected by the associated kernel
Interactions#
Pair potentials#
- class gamdpy.PairPotential(pairpotential_function, params, max_num_nbs, exclusions=None)#
Pair potential
- check_datastructure_validity() bool#
Interactions which have an internal data structure (think: PairPotential and its NbList) should overwrite this method with one that checks the validity of it, and throws an error if not valid (Later: repair it and signal rerun of timeblock)
- get_kernel(configuration: Configuration, compute_plan: dict, compute_flags: dict[str, bool], verbose=False)#
Get a kernel (or python function depending on compute_plan[“gridsync”]) that implements calculation of the interaction
- get_params(configuration: Configuration, compute_plan: dict, verbose=False) tuple#
Get a tuple with the parameters expected by the associated kernel
Functions (pair potentials)#
- gamdpy.LJ_12_6(dist, params)#
The 12-6 Lennard-Jones potential
See
gamdpy.apply_shifted_potential_cutoff()for a usage example.\[ \begin{align}\begin{aligned}u(r) = A_{12} r^{-12} + A_6 r^{-6}\\u'(r) = -12*A_{12} r^{-13} - 6*A_6 r^{-7}\end{aligned}\end{align} \]- Parameters:
dist (float) – Distance between particles
params (array-like) – A₁₂, A₆
- Returns:
u (float) – Potential energy
s (float) – Force multiplier, -u’(r)/r
umm (float) – Second derivative of potential energy
- gamdpy.LJ_12_6_sigma_epsilon(dist, params)#
The 12-6 Lennard-Jones potential
\[u(r) = 4\epsilon( (r/\sigma)^{-12} - (r/\sigma)^{-6} )\]This is the same as the
gamdpy.LJ_12_6()potential, but with \(\sigma\) (sigma) and \(\epsilon\) (epsilon) as parameters.- Parameters:
dist (float) – Distance between particles
params (array-like) – σ, ε
- gamdpy.harmonic_repulsion(dist, params)#
The harmonic repulsion pair potential
\[u(r) = ½\epsilon(1-r/\sigma)^2\]for \(r<\sigma\) and zero otherwise. Parameters: ε=epsilon, σ=cut. Note that this potential is naturally truncated at r=σ.
- Parameters:
dist (float) – Distance between particles
params (array-like) – ε, σ
- gamdpy.hertzian(dist, params)#
Hertzian potential
\[u(r) = \epsilon(1-r/\sigma)^\alpha\]for \(r<\sigma\) and zero otherwise. Parameters: ε=epsilon, α=alpha, σ=cut. Note that this potential is naturally truncated at r=σ. For Hertzian disks chose α=7/2, and for Hertzian spheres chose α=5/2
- Parameters:
dist (float) – Distance between particles
params (array-like) – ε, α, σ
- gamdpy.SAAP(dist, params)#
The SAAP potential is a pair potential for noble elements, its parameters are derived from fitting on data obtained from ab initio methods (coupled cluster):
\[u(x=r/\sigma)/\epsilon = (a_0\exp(a_1 x)/x + a_2\exp(a_3 x) + a_4) / (1+a_5 x^6)\]The six \(a_i\) parameters are given in units of eps and sigma.
Reference: https://doi.org/10.1063/1.5085420
- Parameters:
dist (float) – Distance between particles
params (array-like) – a₀, a₁, a₂, a₃, a₄, a₅, σ, ε
Functions (bonds)#
- gamdpy.harmonic_bond_function(dist: float, params: ndarray) tuple#
Harmonic bond potential
\[u(r) = \frac{1}{2} k (r - r_0)^2\]- Parameters:
dist (float) – Distance between particles
params (array-like) – r₀, k
- Returns:
u (float) – Potential energy
s (float) – Force multiplier, -u’(r)/r
umm (float) – Second derivative of potential energy
See also
Generators#
Generators return a function that can be used to calculate the potential energy and the force between two particles.
- gamdpy.add_potential_functions(potential_1, potential_2)#
Add two potential functions into a single potential function
Note that the two potential functions will have the same cut-off, by convention always stored as the last entry in params. The potential_1 cannot explicitly depend on cut-off (last entry in params). The potential_2 should know where to look for its first parameter in the list of parmeters (params), see e.g. first_parameter in
gamdpy.make_IPL_n().- Parameters:
potential_1 (callable) – a function that calculates a pair-potential: u, s, umm = potential_1(dist, params)
potential_2 (callable) – a function that calculates a pair-potential: u, s, umm = potential_2(dist, params)
- Returns:
potential – a function implementing the sum of potential_1 and potential_2
- Return type:
callable
Example
Below we make the 12-6 Lennard-Jones potential by adding two inverse power-law potentials.
>>> import gamdpy as gp >>> LJ = gp.add_potential_functions(gp.make_IPL_n(12), gp.make_IPL_n(6, first_parameter=1)) >>> params = A12, A6, cut = 4.0, -4.0, 2.5 >>> dist = 2**(1/6) # Minima of LJ potential >>> LJ(dist,params)[0] # Pair energy in minima -1.0
- gamdpy.make_potential_function_from_sympy(ufunc, param_names) callable#
Make a potential function from a sympy expression
Known to result in slow code. Use for testing and prototyping.
- Parameters:
ufunc (sympy expression) – The potential energy expression in Sympy’s symbolic form It has to be a radial function and the pair distance symbol shuould be r
param_names (list) – List of parameters
- Returns:
potential_function – A function that calculates the potential energy, force multiplier, and second derivative of the potential energy u, s, umm = potential_function(dist, params)
- Return type:
callable
- gamdpy.make_LJ_m_n(m: float, n: float) callable#
Mie Potential
Also known as the generalized Lennard-Jones potential:
\[u(r) = A_m r^{-m} - A_n r^{-n}\]- Returns:
potential_function – A function that calculates the Mie potential, u, s, umm = potential_function(dist, params). where params = [A_m, A_n]
- Return type:
callable
- gamdpy.make_IPL_n(n: float, first_parameter: int = 0) callable#
Inverse Power Law Potential
\[u(r) = A_n r^{-n}\]- Parameters:
n (float) – Exponent in the potential
first_parameter (int) – The index of the first parameter in the list of parameters. See usage in
gamdpy.add_potential_functions().
- Returns:
potential_function – A function that calculates the IPL potential, u, s, umm = potential_function(dist, params). where params = [A_n]
- Return type:
callable
Modifies#
Modifies are typically used to smoothly truncate the potential at a certain distance.
- gamdpy.apply_shifted_potential_cutoff(pair_potential: callable) callable#
Apply shifted potential cutoff to a pair-potential function
If the input pair potential is \(u(r)\), then the shifted potential is \(u(r) - u(r_{c})\), where \(r_c\) is the cutoff distance.
Note: calls original potential function twice, avoiding changes to params.
- Parameters:
pair_potential (callable) – A function that calculates a pair-potential: u, s, umm = pair_potential(dist, params)
- Returns:
pair_potential – A function where shifted_potential_cutoff is applied to original function
- Return type:
callable
Example
The following example demonstrates how to use this function to set up the Lenard-Jones 12-6 potential truncated and shifted to zero at the cutoff distance of 2.5:
>>> import gamdpy as gp >>> pair_func = gp.apply_shifted_force_cutoff(gp.LJ_12_6) >>> A12, A6, cut = 1.0, 1.0, 2.5 >>> pair_pot = gp.PairPotential(pair_func, params=[A12, A6, cut], max_num_nbs=1000)
- gamdpy.apply_shifted_force_cutoff(pair_potential)#
Apply shifted force cutoff to a pair-potential function
If the input pair potential is \(u(r)\), then the shifted force potential is \(u(r) - u(r_{c}) + s(r_{c})(r - r_{c})\), where \(r_c\) is the cutoff distance, and \(s(r) = -u'(r)/r\).
Note: calls original potential function twice, avoiding changes to params
- Parameters:
pair_potential (callable) – a function that calculates a pair-potential: u, s, umm = pair_potential(dist, params)
- Returns:
potential – a function where shifted force cutoff is applied to original function
- Return type:
callable
Fixed interactions#
Classes#
- class gamdpy.Bonds(bond_potential, potential_params, indices)#
Fixed bond interactions between particles, such as harmonic bonds or FENE bonds.
- Parameters:
bond_potential (function) – A function that takes the distance between two particles and the bond type as arguments and returns the potential energy, force and laplacian. See :func:gamdpy.potential_functions.harmonic_bond_function for an example.
potential_params (list) – A list of parameters for each bond type. Each entry is a list of parameters for a specific bond type.
indices (list) – A list of lists, each containing the indices of the two particles involved in a bond and the bond
See also
gamdpy.harmonic_bond_functionHarmonic bond potential
- class gamdpy.Angles(potential, indices, parameters)#
- class gamdpy.Tether#
Connect particles to anchor-points in space with a harmonic spring force.
- Parameters:
either (Points and spring constants are defined using)
constants ((b) A list of particle types to be tethered and associated list of spring)
constants
examples/tethered_particles.py (See)
- class gamdpy.Gravity#
Adding a gravitational-like force on particles.
- Parameters:
forces ((b) A list of particle types one which the forces act and associated list of)
forces
x-direction (At the moment the force will act in the)
examples/poiseuille.py (See)
- class gamdpy.Relaxtemp#
Thermostat using simple kinetic temperature relaxation of each particles.
- Parameters:
time ((a) A list of particle indices to be thermostated and associated list of relaxation)
times ((b) A list of particle types to be thermostated and associated list of relaxation)
examples/poiseuille.py (See)
Generators#
- gamdpy.make_planar_calculator(configuration, potential_function) callable#
Returns a function that calculates a planar interaction for particles
This function is used to create a planar interaction such as a smooth wall, gravity or an electric field.
- gamdpy.setup_planar_interactions(configuration, potential_function, potential_params_list, particles_list, point_list, normal_vector_list, compute_plan, verbose=True) dict#
Returns a dictionary with planar interactions
- gamdpy.make_fixed_interactions(configuration, fixed_potential, compute_plan, verbose=True)#
Generate a kernel for fixed interactions between particles.
Runtime Actions#
- class gamdpy.TrajectorySaver(include_simbox=False, verbose=False, compression='gzip', compression_opts=4)#
Runtime action for saving configurations during timeblock. Does logarithmic saving.
- class gamdpy.ScalarSaver(steps_between_output: int = 16, compute_flags=None, verbose=False, compression='gzip', compression_opts=4)#
Runtime action for saving scalar data (such as thermodynamic properties) during a timeblock every steps_between_output time steps.
- class gamdpy.RestartSaver(timeblocks_between_restarts=1)#
Runtime action for saving restarts, ie. the current configuration at beginning of every timebock .
- class gamdpy.MomentumReset(steps_between_reset: int)#
Runtime action that sets the total momentum of configuration to zero every steps_between_reset time step.
- class gamdpy.StressSaver(steps_between_output: int = 16, compute_flags=None, verbose=False)#
Runtime action for saving stress tensor(a D x D matrix) during a timeblock every steps_between_output time steps.
Calculators#
- class gamdpy.CalculatorRadialDistribution(configuration, bins, compute_plan=None, ptype=None)#
Calculator class for the radial distribution function, g(r)
- Parameters:
configuration (gamdpy.Configuration) – The configuration object for which the radial distribution function is calculated.
bins (int) – The number of bins in the radial distribution function.
compute_plan (dict)
ptype (optional) – If specified, array ptypes used to calculate g(r). If not specfified default is configuration.ptype
Example
>>> import gamdpy as gp >>> sim = gp.get_default_sim() >>> calc_rdf = gp.CalculatorRadialDistribution(sim.configuration, bins=1000) >>> for _ in sim.run_timeblocks(): ... calc_rdf.update() # Current configuration to rdf >>> rdf_data = calc_rdf.read() # Read the rdf data as a dictionary >>> r = rdf_data['distances'] # Pair distances >>> rdf = rdf_data['rdf'] # Radial distribution function
- read()#
Read the radial distribution function
- Returns:
A dictionary containing the distances and the radial distribution function.
- Return type:
dict
- save_average(output_filename='rdf.dat', save_ptype=False) None#
Save the average radial distribution function to a file
- Parameters:
output_filename (str) – The name of the file to which the radial distribution function is saved.
save_ptype (bool) – Save the type of each particle in a file name ptype_* (default False)
- update()#
Update the radial distribution function with the current configuration.
- class gamdpy.CalculatorStructureFactor(configuration: Configuration, n_vectors: ndarray = None, atomic_form_factors: ndarray = None, backend='CPU multi core')#
Calculator class for the static structure factor, S(q). The calculation is done for several \({\bf q}\) vectors given by
\[{\bf q} = (2\pi n_x/L_x, 2\pi n_y/L_y, ...)\]where \(n=(n_x, n_y, ...)\) is a D-dimensional vector of integers and \(L_x\), \(L_y\), … are the box lengths in the \(x\), \(y\), … directions, respectively. Note that box length are assumed to be constant during the simulation (as in a NVT simulation). The collective density \(\rho_{\bf q}\) is calculated as
\[\rho_{\bf q} = \frac{1}{\sqrt{N}} \sum_{n} f_n \exp(-i {\bf q}\cdot {\bf r}_n)\]where \(x_n\) is the position of particle \(n\), and \(f_n\) is the atomic form factor for that particle (one by default). The normalization constant is
\[N = \sum_{n} f_n.\]From this, the static structure factor is defined as
\[S({\bf q}) = |\rho_{\bf q}|^2.\]The method
update()updates the structure factor with the current configuration. The methodread()returns the structure factor for the q vectors in the q_direction.- Parameters:
configuration (gamdpy.Configuration) – The configuration object to calculate the structure factor for.
q_max (float or None) – The maximum value of the q vectors.
n_vectors (numpy.ndarray or None) – n-vectors defining q-vectors. The shape of n_vectors, if specified, must be (N, D) where N is the number of q vectors and D is the number of dimensions. If None, then use generate_q_vectors method.
atomic_form_factors (numpy.ndarray or None) – The atomic form factors, \(f_n\). If None (default), then the atomic form factors are set to 1. Can be given as an array of floats, one for each atom.
backend (str) – The backend to use for the calculation. Either ‘CPU multi core’ or ‘CPU single core’.
See also
- generate_q_vectors(q_max: float)#
Generate q-vectors inside a sphere of radius q_max
- read(bins) dict#
Return the structure factor S(q) for the q vectors in the q_direction.
- Parameters:
bins (int | None) – If bins is an integer, the data is binned (ready to be plotted). If bins is None, the raw S(q) data is returned.
- Returns:
A dictionary containing the q vectors, the q lengths, the structure factor S(q), the collective density rho_q, and the number of q vectors in each bin. Output depends on the value of the bins parameter.
- Return type:
dict
- save_average(bins=None, output_filename='sq.dat')#
Save average structure factors to a file.
- update() None#
Update the structure factor with the current configuration.
- class gamdpy.CalculatorWidomInsertion(configuration, pair_potential, temperature, ghost_positions, ptype_ghost=0, compute_plan=None, backend='GPU')#
Calculator class for Widom’s particle insertion method for computing chemical potentials
This class is used to calculate the chemical potential of a not to dense fluid using Widom’s particle insertion method. The excess chemical potential, μᵉˣ, fluid can be computed as μᵉˣ = -kT ln 〈exp(-ΔU/kT)〉 where ΔU is the energy difference between the system with and without a ghost particle. Here, 〈…〉 is an average for all possible positions of the ghost particle (sometimes writte as an integral over space).
The method should be used on a NVT trajectory in equlibrium.
- Parameters:
configuration (gamdpy.Configuration) – The configuration object representing the system.
pair_potential (gamdpy.PairPotential) – The pair potential object representing the interaction between particles.
temperature (float) – The temperature of the system.
ghost_positions (ndarray) – The positions of the ghost particles for which the chemical potential is to be calculated.
ptype_ghost (int, optional) – The particle type of the ghost particles. Default is 0.
compute_plan (dict, optional) – The compute plan for the system. Default is None (then a default plan is used).
backend (str, optional) – The backend to use for the calculations. Default is ‘GPU’. Supported backends are ‘CPU’ (testing) and ‘GPU’ (recomended).
Example
>>> import numpy as np >>> import gamdpy as gp >>> sim = gp.get_default_sim() # Replace with your own equbriliated simulation >>> pair_pot = sim.interactions[0] >>> num_ghost_particles = 500_000 >>> ghost_positions = np.random.rand(num_ghost_particles, sim.configuration.D) * sim.configuration.simbox.get_lengths() >>> calc_widom = gp.CalculatorWidomInsertion(sim.configuration, pair_pot, sim.integrator.temperature, ghost_positions) >>> for block in sim.run_timeblocks(): ... calc_widom.update() >>> calc_widom_data = calc_widom.read() # Dictionary with chemical potential and more >>> calc_widom_data.keys() dict_keys(['chemical_potential', 'boltzmann_factors', 'chemical_potentials']) >>> mu_ex = calc_widom_data['chemical_potential'] # Estimated excess chemical potential
- read()#
Read data
Return the current chemical potential, average Boltzmann factors, and timeblock-specific chemical potentials for the ghost particles.
- Returns:
A dictionary containing the following keys:
- ’chemical_potential’: float
The best estimate of the overall chemical potential for the system.
- ’boltzmann_factors’: ndarray
The average Boltzmann factors for each ghost particle, representing the statistical weights based on their interaction energies.
- ’chemical_potentials’: ndarray
An array of estimated chemical potentials for each timeblock, providing insight into the variability of the chemical potential over time.
- Return type:
dict
- update()#
Update state the current configuration.
- class gamdpy.CalculatorHydrodynamicCorrelations(configuration, dtsample, ptype=0, nwaves=10, lvec=100, verbose=False)#
Calculates the tranverse current autocorrelation function (jacf) and the longitudinal density autocorrelation function (dacf).
Example: See hydrocorr.py
Initialization variables - configuration: Instance of the configuration class - dtsample: Time between sampling (= integrator time step * steps_per_timeblock) - ptype: The particle type for which the correlations are calculated (default 0) - nwaves: Number of wavevectors (default 10) - lvec: Length of the time vector - sample time span then dtsample*lvec (defulat 100) - verbose: Write a bit to screen (default False)
- Output:
With the method read() data is written to files and returned to user
- class gamdpy.CalculatorHydrodynamicProfile(configuration, ptype, bins=100, profdir=2, veldir=0, verbose=True)#
Calculates the density, streaming velocity, and kinetic temperature profiles.
Example: See atomistic_wall example
Initialization variables: - configuration: Instance of the configuration class - ptype: The particle type for which the profile is calculated - bins: Number of bins to use in the profiles; more bins higher resolution. (default 100) - profdir: Profile spatial direction (default 2 - or z - direction) - veldir: The streaming velocity component used (default 0 - or x - direction) - verbose: If true print some information (default True)
- Output:
With the method read() you can retrieve the current data. By default a data file is printed with the same
Tools and helper functions#
Input and Output#
The TrajectoryIO class#
- class gamdpy.tools.TrajectoryIO(name='')#
This class handles the loading and saving of simulation data. When the class can be instantiated with an output from a previous simulation. The data can be saved in self.h5 in the same format of the sim.output object. When the class is instantiated without an input, self.h5 is None and can be assigned afterward (used to save output from memory simulation)
- Parameters:
name (str) – Name of the file or folder to read output from. Can be a gamdpy .h5 output or a rumd3 TrajectoryFiles folder.
Examples
>>> import gamdpy as gp >>> import h5py >>> output = gp.tools.TrajectoryIO("examples/Data/LJ_r0.973_T0.70_toread.h5").get_h5() Found .h5 file (examples/Data/LJ_r0.973_T0.70_toread.h5), loading to gamdpy as output dictionary >>> nblocks, nconfs, N, D = output['trajectory_saver/positions'].shape >>> print(f"Output file examples/Data/LJ_r0.973_T0.70.h5 contains a simulation of {N} particles in {D} dimensions") Output file examples/Data/LJ_r0.973_T0.70.h5 contains a simulation of 2048 particles in 3 dimensions >>> print(f"The simulation output is divided into {nblocks} blocks, each of them with {nconfs} configurations") The simulation output is divided into 32 blocks, each of them with 12 configurations >>> output = gp.tools.TrajectoryIO("examples/Data/NVT_N4000_T2.0_rho1.2_KABLJ_rumd3/TrajectoryFiles").get_h5() # Read from rumd3 Found rumd3 TrajectoryFiles, loading to rumpdy as output dictionary >>> nblocks, nconfs, N, D = output['trajectory_saver/positions'].shape >>> print(f"File examples/Data/NVT_N4000_T2.0_rho1.2_KABLJ_rumd3/TrajectoryFiles contains a simulation of {N} particles in {D} dimensions") File examples/Data/NVT_N4000_T2.0_rho1.2_KABLJ_rumd3/TrajectoryFiles contains a simulation of 4000 particles in 3 dimensions >>> print(f"The simulation output is divided into {nblocks} blocks, each of them with {nconfs} configurations") The simulation output is divided into 2 blocks, each of them with 24 configurations
- get_h5() File#
Returns self.h5
- load_h5(name: str) File#
Makes self.h5 a view of the .h5 files
- load_rumd3(name: str) File#
Reads a rumd3 TrajectoryFiles folder and convert it into gamdpy .h5 output. Assumes RectangularSimulationBox, corresponding to gamdpy’s Orthorhombic. This function returns a memory .h5
- save_h5(name: str)#
This method saves self.h5 to disk. It can be used to save sim.output to file if class is initialized without arguments and then self.h5 = sim.output . By default output is compressed. This can be avoided setting self.compression_type = “gzip” and self.compression_opts=0 .
IO functions#
- gamdpy.tools.save_configuration(configuration, filename: str, format='xyz', append=False)#
Saves configuration to file.
Helpful for, e.g., VMD visualization This current version only supports the standard xyz-format.
Example
>>> import os >>> import gamdpy as gp >>> import numpy as np >>> conf = gp.Configuration(D=3, N=10) >>> gp.tools.save_configuration(configuration=conf, filename="final.xyz", format="xyz") >>> os.remove("final.xyz") # Removes file (for doctests)
- gamdpy.configuration_to_hdf5(configuration: Configuration, filename: str, meta_data=None) None#
Write a configuration to a HDF5 file
- Parameters:
configuration (gamdpy.Configuration) – a gamdpy configuration object
filename (str) – filename of the output file .h5
meta_data (str) – not used in the function so far (default None)
Example
>>> import os >>> import gamdpy as gp >>> conf = gp.Configuration(D=3) >>> conf.make_positions(N=10, rho=1.0) >>> gp.configuration_to_hdf5(configuration=conf, filename="final.h5") >>> os.remove("final.h5") # Removes file (for doctests)
- gamdpy.configuration_from_hdf5(filename: str, reset_images=False, compute_flags=None) Configuration#
Read a configuration from a HDF5 file
- Parameters:
filename (str) – filename of the input file .h5
reset_images (bool) – if True set the images to zero (default False)
- Returns:
configuration – a gamdpy configuration object
- Return type:
Example
>>> import gamdpy as gp >>> conf = gp.configuration_from_hdf5("examples/Data/final.h5") >>> print(conf.D, conf.N, conf['r'][0]) # Print number of dimensions D, number of particles N and position of first particle 3 10 [-0.7181449 -1.3644753 -1.5799187]
- gamdpy.configuration_to_rumd3(configuration: Configuration, filename: str) None#
Write a configuration to a RUMD3 file
- Parameters:
configuration (gamdpy.Configuration) – a gamdpy configuration object
filename (str) – filename of the output file .xyz.gz
Example
>>> import os >>> import gamdpy as gp >>> conf = gp.Configuration(D=3) >>> conf.make_positions(N=10, rho=1.0) >>> gp.configuration_to_rumd3(configuration=conf, filename="restart.xyz.gz") >>> os.remove("restart.xyz.gz") # Removes file (for doctests)
- gamdpy.configuration_from_rumd3(filename: str, reset_images=False, compute_flags=None) Configuration#
Read a configuration from a RUMD3 file
- Parameters:
filename (str) – filename of the output file .xyz.gz
- Returns:
configuration – a gamdpy configuration object
- Return type:
Example
>>> import gamdpy as gp >>> conf = gp.configuration_from_rumd3("examples/Data/NVT_N4000_T2.0_rho1.2_KABLJ_rumd3/TrajectoryFiles/restart0000.xyz.gz") >>> print(conf.D, conf.N, conf['r'][0]) # Print number of dimensions D, number of particles N and position of first particle 3 4000 [ 7.197245 6.610052 -4.7467813]
- gamdpy.configuration_to_lammps(configuration, timestep=0) str#
Convert a configuration to a string formatted as LAMMPS dump file
- Parameters:
configuration (gamdpy.Configuration) – a gamdpy configuration object
timestep (float) – time at which the configuration is saved
- Returns:
string formatted as LAMMPS dump file
- Return type:
str
Example
>>> import gamdpy as gp >>> conf = gp.Configuration(D=3) >>> conf.make_positions(N=10, rho=1.0) >>> lmp_dump = gp.configuration_to_lammps(configuration=conf)
Post-analysis tools#
- gamdpy.tools.calc_dynamics(trajectory, first_block, qvalues=None)#
Compute dynamical properties from a saved trajectory HDF5 file.
This function processes blocks of saved configurations to evaluate time‐dependent dynamical observables, including the mean square displacement (MSD), the non‐Gaussian parameter (alpha2), and the self‐intermediate scattering function (Fs), for one or more particle types.
- Parameters:
trajectory (h5py.File object in the gamdpy style)
first_block (int) – Index of the first block to use as the reference origin.
qvalues (float or array‐like of shape (num_types,), optional) – Wavevector magnitudes at which to compute the self‐intermediate scattering function Fs. If a single float is provided, it is broadcast to all particle types. If None, Fs is not computed (remains zero).
- Returns:
results – Dictionary containing dynamcal data.
- Return type:
dict
Examples
- For command‐line usage, see:
$ python -m gamdpy.tools.calc_dynamics -h
Usage within a Python script:
>>> import gamdpy as gp >>> sim = gp.get_default_sim() # Replace with your simulation object >>> for block in sim.run_timeblocks(): pass >>> dynamics = gp.calc_dynamics(sim.output, first_block=0, qvalues=7.5) >>> dynamics.keys() dict_keys(['times', 'msd', 'alpha2', 'qvalues', 'Fs', 'count'])
Mathematical functions#
The below returns functions that can be executed fast in a GPU kernel. As an example, they can be used to set a time-dependent target temperature.
- gamdpy.make_function_constant(value)#
Return a function that returns a constant value
- gamdpy.make_function_ramp(value0, x0, value1, x1)#
Return a function that ramps linearly between two values
Return a function that returns a constant value for x<x0, linearly ramps from value0 to value1 for x0<=x<=x1, and returns value1 for x>x1.
- gamdpy.make_function_sin(period, amplitude, offset)#
Return a function that returns a sin function with given period, amplitude and offset
Extract data#
- gamdpy.extract_scalars(data, column_list, first_block=0, D=3)#
Extracts scalar data from simulation output.
- Parameters:
data (dict) – Output from a Simulation object.
column_list (list of str)
first_block (int) – Index of the first timeblock to extract data from.
D (int) – Dimension of the simulation.
- Returns:
Tuple of 1D numpy arrays containing the extracted scalar data.
- Return type:
tuple
Example
>>> import numpy as np >>> import gamdpy as gp >>> sim = gp.get_default_sim() # Replace with your simulation object >>> for block in sim.run_timeblocks(): pass >>> U, W = gp.extract_scalars(sim.output, ['U', 'W'], first_block=1)
Miscellaneous#
- gamdpy.select_gpu()#
Select the first available GPU (necessary on some multi-gpu systems).
- gamdpy.get_default_sim()#
Return a sim object of the single component LJ crystal in the NVT ensemble. The purpose of this function is to provide a default simulation for testing and simplifying examples.
Example
>>> import os >>> os.environ['NUMBA_CUDA_LOW_OCCUPANCY_WARNINGS'] = '0' # Removes warnings from low occupacy (optional) >>> import gamdpy as gp >>> sim = gp.get_default_sim()
- gamdpy.get_default_compute_plan(configuration)#
Return a default compute_plan The default compute_plan is a dictionary with a set of parameters specifying how computations are done on the GPU. The returned plan depends on the number of particles, and properties of the GPU. The keys of the dictionary are:
‘pb’: particle per thread block
‘tp’: threads per particle
‘gridsync’: Boolean indicating if syncronization should be done by grid.sync() calls
‘skin’: used when updating nblist
‘UtilizeNIII’: Boolean indicating if Newton’s third law (NIII) should be utilized (see pairpotential_calculator).
‘nblist’ : ‘N squared’ (default) or ‘linked lists’. Determines algorithm updating nblist
- gamdpy.get_default_compute_flags()#
- gamdpy.plot_molecule(top, positions, particle_types, filename='molecule.pdf', block=False)#
This function write a pdf file with a drawing of the molecule
- Parameters:
top (gamdpy topology object)
positions (list or numpy array with positions of all atoms)
particle_types (types of the molecule)
filename (name of the output pdf file, default is molecule.pdf)
block (boolean, default False. If True shows plot and blocks script until display window is closed)
- gamdpy.tools.print_h5_structure(node, indent=0)#
Recursively print groups and datasets with metadata of an h5 file.
Example
>>> import gamdpy as gp >>> sim = gp.get_default_sim() >>> for _ in sim.run_timeblocks(): pass >>> gp.tools.print_h5_structure(sim.output) initial_configuration/ (Group) ptype (Dataset, shape=(2048,), dtype=int32) r_im (Dataset, shape=(2048, 3), dtype=int32) scalars (Dataset, shape=(2048, 4), dtype=float32) topology/ (Group) angles (Dataset, shape=(0,), dtype=int32) bonds (Dataset, shape=(0,), dtype=int32) dihedrals (Dataset, shape=(0,), dtype=int32) molecules/ (Group) vectors (Dataset, shape=(3, 2048, 3), dtype=float32) scalar_saver/ (Group) scalars (Dataset, shape=(8, 64, 3), dtype=float32) trajectory_saver/ (Group) images (Dataset, shape=(8, 12, 2048, 3), dtype=int32) positions (Dataset, shape=(8, 12, 2048, 3), dtype=float32)
- gamdpy.tools.print_h5_attributes(obj, path='/')#
Recursively print attrs of every group/dataset of an h5 file.
Example
>>> import gamdpy as gp >>> sim = gp.get_default_sim() >>> for _ in sim.run_timeblocks(): pass >>> gp.tools.print_h5_attributes(sim.output) Attributes at /: - dt: 0.005 - script_content: ... - script_name: ... Attributes at /initial_configuration/: - simbox_data: [12.815602 12.815602 12.815602] - simbox_name: Orthorhombic Attributes at /initial_configuration/scalars: - scalar_columns: ['U' 'W' 'K' 'm'] Attributes at /initial_configuration/topology/molecules/: - names: [] Attributes at /initial_configuration/vectors: - vector_columns: ['r' 'v' 'f'] Attributes at /scalar_saver/: - compression_info: gzip with opts 4 - scalar_names: ['U' 'W' 'K'] - steps_between_output: 16 Attributes at /trajectory_saver/: - compression_info: gzip with opts 4