pynep package

Submodules

pynep.calculate module

class pynep.calculate.JointCalculator(*args, **kwargs)

Bases: Calculator

calculate(atoms=None, properties=None, system_changes=['positions', 'numbers', 'cell', 'pbc', 'initial_charges', 'initial_magmoms'])

Do the calculation.

properties: list of str

List of what needs to be calculated. Can be any combination of ‘energy’, ‘forces’, ‘stress’, ‘dipole’, ‘charges’, ‘magmom’ and ‘magmoms’.

system_changes: list of str

List of what has changed since last calculation. Can be any combination of these six: ‘positions’, ‘numbers’, ‘cell’, ‘pbc’, ‘initial_charges’ and ‘initial_magmoms’.

Subclasses need to implement this, but can ignore properties and system_changes if they want. Calculated properties should be inserted into results dictionary like shown in this dummy example:

self.results = {'energy': 0.0,
                'forces': np.zeros((len(atoms), 3)),
                'stress': np.zeros(6),
                'dipole': np.zeros(3),
                'charges': np.zeros(len(atoms)),
                'magmom': 0.0,
                'magmoms': np.zeros(len(atoms))}

The subclass implementation should first call this implementation to set the atoms attribute and create any missing directories.

implemented_properties: List[str] = ['energy', 'forces', 'stress']

Properties calculator can handle (energy, forces, …)

class pynep.calculate.NEP(model_file='nep.txt', **kwargs)

Bases: Calculator

ASE calculator for NEP (see https://github.com/brucefan1983/GPUMD) supported properties: energy, forces, stress, descriptor, latent descriptor

Examples:

Use C_2022_NEP3.txt to calculate properties of diamond (from https://github.com/brucefan1983/GPUMD/tree/master/potentials/nepCalculate)

energy, forces and stress:

>>> calc = NEP('C_2022_NEP3.txt')
>>> atoms = bulk('C', 'diamond', cubic=True)
>>> atoms.set_calculator(calc)
>>> energy = atoms.get_potential_energy()
>>> forces = atoms.get_forces()
>>> stress = atoms.get_stress()

descriptor and latent descriptor:

>>> des = calc.get_property('descriptor', atoms)
>>> lat = calc.get_property('latent', atoms)
calculate(atoms=None, properties=None, system_changes=['positions', 'numbers', 'cell', 'pbc', 'initial_charges', 'initial_magmoms'])

Do the calculation.

properties: list of str

List of what needs to be calculated. Can be any combination of ‘energy’, ‘forces’, ‘stress’, ‘dipole’, ‘charges’, ‘magmom’ and ‘magmoms’.

system_changes: list of str

List of what has changed since last calculation. Can be any combination of these six: ‘positions’, ‘numbers’, ‘cell’, ‘pbc’, ‘initial_charges’ and ‘initial_magmoms’.

Subclasses need to implement this, but can ignore properties and system_changes if they want. Calculated properties should be inserted into results dictionary like shown in this dummy example:

self.results = {'energy': 0.0,
                'forces': np.zeros((len(atoms), 3)),
                'stress': np.zeros(6),
                'dipole': np.zeros(3),
                'charges': np.zeros(len(atoms)),
                'magmom': 0.0,
                'magmoms': np.zeros(len(atoms))}

The subclass implementation should first call this implementation to set the atoms attribute and create any missing directories.

implemented_properties: List[str] = ['energy', 'energies', 'forces', 'stress', 'descriptor', 'latent']

Properties calculator can handle (energy, forces, …)

pynep.io module

pynep.io.Proc_block(lines)
pynep.io.dump_nep(filename, frames, ftype='nep', dvi_virial=False)

dump data in nep format

Parameters:
  • filename (str) – Name of the file to read from

  • frames (list) – a list of Atoms objects.

pynep.io.load_nep(filename, ftype='nep')

Read Atoms objects from file

Parameters:
  • filename (str) – Name of the file to read from

  • ftype (str) – Type of the file to read from

Returns:

frames

Return type:

A list of Atoms objects

pynep.mutate module

class pynep.mutate.ChangeAtomType(change_probability=0.8, d_ratio=0.8, min_dis_mat=None, attempt_number=200)

Bases: Mutation

Change type of atom

mutate(atoms)

mutate the atoms, every subclass must have this method

Parameters:

atoms (Atoms) – atoms to be mutated

class pynep.mutate.Combine(*op_list)

Bases: Mutation

Class to combine a series of mutations

mutate(atoms)

mutate the atoms, every subclass must have this method

Parameters:

atoms (Atoms) – atoms to be mutated

class pynep.mutate.Mutation(d_ratio=0.8, min_dis_mat=None, attempt_number=200)

Bases: ABC

Base class of Muatation

static check_distance(atoms, indices, tolerance_distances)

check distances of atoms

Parameters:
  • atoms (Atoms) – atoms to be check

  • indices (1d list) – indices of atoms to be cheak

  • tolerance_distances (allow distance between atoms) – 2d list

Returns:

If the atoms meet the requirements

Return type:

bool

generate(atoms, number=10)

generate atoms

Parameters:
  • atoms (Atoms) – atoms to be mutated

  • number (int, optional) – number of new atoms to be generated. Defaults to 10.

Returns:

Generated atoms

Return type:

A list of atoms obeject

get_tolerance_distances(atoms)

get min distance between atoms

Parameters:

atoms (Atoms) – atoms to constuct the tolerance distances

Returns:

min distances matrix

Return type:

2d list

abstract mutate(atoms)

mutate the atoms, every subclass must have this method

Parameters:

atoms (Atoms) – atoms to be mutated

class pynep.mutate.Rattle(probability=0.8, rattle_range=2, d_ratio=0.8, min_dis_mat=None, attempt_number=200)

Bases: Mutation

Randomly rattle atoms

mutate(atoms)

mutate the atoms, every subclass must have this method

Parameters:

atoms (Atoms) – atoms to be mutated

static pos_add_sphere(rattle_strength)

randomly new positions in a sphere

Parameters:

rattle_strength (float) – radius of the sphere

Returns:

positions to add

Return type:

array

class pynep.mutate.Strain(cell_cut=1.0, sigma=0.1, d_ratio=0.8, min_dis_mat=None, attempt_number=200)

Bases: Mutation

Randomly change the cell

mutate(atoms)

mutate the atoms, every subclass must have this method

Parameters:

atoms (Atoms) – atoms to be mutated

class pynep.mutate.Swap(swap_probability=0.8, d_ratio=0.8, min_dis_mat=None, attempt_number=200)

Bases: Mutation

Swap atoms

mutate(atoms)

mutate the atoms, every subclass must have this method

Parameters:

atoms (Atoms) – atoms to be mutated

pynep.nep module

nep

class pynep.nep.NepCalculator

Bases: pybind11_object

calculate(self: pynep.nep.NepCalculator) None
getDescriptors(self: pynep.nep.NepCalculator) List[float]
getForces(self: pynep.nep.NepCalculator) List[float]
getLatent(self: pynep.nep.NepCalculator) List[float]
getPotentialEnergy(self: pynep.nep.NepCalculator) List[float]
getVirials(self: pynep.nep.NepCalculator) List[float]
property info
setAtoms(self: pynep.nep.NepCalculator, arg0: int, arg1: List[int], arg2: List[float], arg3: List[float]) None

pynep.phono module

pynep.select module

class pynep.select.FarthestPointSample(min_distance=0.1, metric='euclidean', metric_para={})

Bases: object

Farthest point sampler

Example:

  1. Select points from random 2d points:

>>> data = np.random.randn(100000, 2)
>>> selector = FarthestPointSample(min_distance=0.05)
>>> indices = selector.select(data)
  1. Select atoms with structure descriptors

Suppose we already have frames to be selected and a NEP calculator. In fact, you can get descriptors by any other method, such as SOAP.

>>> des = np.array([np.mean(calc.get_property('descriptor', atoms), axis=0) for atoms in frames])
# Use average of each atomic descriptors to get structure descriptors, shape: (Nframes, Ndescriptor)
>>> sampler = FarthestPointSample()
>>> indices = sampler.select(des, [])
>>> selected_structures = [frames[i] for  i in indices]
  1. Select atoms with atomic latent descriptors

>>> lat = np.concatenate([calc.get_property('latent', atoms) for atoms in frames])
# shape: (Natoms, Nlatent)
>>> comesfrom = np.concatenate([[i] * len(atoms) for i, atoms in enumerate(frames)])
# shape: (Natoms, )  the ith data in lat belong to the atoms: frames[comesfrom[i]]
>>> sampler = FarthestPointSample()
>>> indices = [comesfrom[i] for i in sampler.select(lat, [])]
>>> indices = set(indices)  # remove repeated indices because two points may come from the same structure
>>> selected_structures = [frames[i] for  i in indices]
select(new_data, now_data=[], min_distance=None, min_select=1, max_select=None)

Select those data fartheset from given data

Parameters:
  • new_data (2d list or array) – A series of points to be selected

  • now_data (2d list or array) – Points already in the dataset. Defaults to []. (No existed data)

  • min_distance (float, optional) – If distance between two points exceeded the minimum distance, stop the selection. Defaults to None (use the self.min_distance)

  • min_select (int, optional) – Minimal numbers of points to be selected. This may cause some distance between points less than given min_distance. Defaults to 1.

  • max_select (int, optional) – Maximum numbers of points to be selected. Defaults to None. (No limitation)

Returns:

index of selected points

Return type:

A list of int

Module contents