Source code for pyretis.tools.lattice

# -*- coding: utf-8 -*-
# Copyright (c) 2023, PyRETIS Development Team.
# Distributed under the LGPLv2.1+ License. See LICENSE for more info.
"""Some methods for generating initial lattice structures.

Important methods defined here
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

generate_lattice (:py:func:`.generate_lattice`)
    Generate points on a simple lattice.

Examples
--------
>>> from pyretis.tools.lattice import generate_lattice
>>> xyz, size = generate_lattice('diamond', [1, 1, 1], lcon=1)

"""
import logging
import itertools
import numpy as np
logger = logging.getLogger(__name__)  # pylint: disable=invalid-name

__all__ = ['generate_lattice']


UNIT_CELL = {'sc': np.array([[0.0, 0.0, 0.0]]),
             '1d': np.array([[0.0]]),
             'sq': np.array([[0.0, 0.0]]),
             'sq2': np.array([[0.0, 0.0], [0.5, 0.5]]),
             'bcc': np.array([[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]]),
             'fcc': np.array([[0.0, 0.0, 0.0], [0.5, 0.5, 0.0],
                              [0.0, 0.5, 0.5], [0.5, 0.0, 0.5]]),
             'hcp': np.array([[0.0, 0.0, 0.0], [0.5, 0.5, 0.0],
                              [0.5, 5.0/6.0, 0.5], [0.0, 1.0/3.0, 0.5]]),
             'diamond': np.array([[0.0, 0.0, 0.0], [0.0, 0.5, 0.5],
                                  [0.5, 0.0, 0.5], [0.5, 0.5, 0.0],
                                  [0.25, 0.25, 0.25], [0.25, 0.75, 0.75],
                                  [0.75, 0.25, 0.75], [0.75, 0.75, 0.25]])}


[docs]def generate_lattice(lattice, repeat=None, lcon=None, density=None): """Generate points on a simple lattice. The lattice is one of the defined keys in the global variable `UNIT_CELL`. This lattice will be repeated a number of times. The lattice spacing can be given explicitly, or it can be given implicitly by the number density. Parameters ---------- lattice : string Select the kind of lattice. The following options are currently defined in `UNIT_CELL`: * `1d` : 1D lattice * `sc` : Simple cubic lattice. * `sq` : Square lattice (2D) with one atom in the unit cell. * `sq2` : Square lattice with two atoms in the unit cell. * `bcc` : Body-centred cubic lattice. * `fcc` : Face-centred cubic lattice. * `hcp` : Hexagonal close-packed lattice. * `diamond` : Diamond structure. repeat : list of integers, optional. How many time the cell is replicated. lcon : float, optional The lattice constant. density : float, optional The desired density. If this is given, `lcon` is calculated. Note that density will be interpreted as given in internal units. Returns ------- positions : numpy.array The lattice positions. size : list of floats The corresponding size(s), can be used to define a simulation box. """ try: unit_cell = UNIT_CELL[lattice.lower()] except KeyError as err: msg = [f'Unknown lattice "{lattice}" requested!'] msg += [f'Input lattice should be a string in {UNIT_CELL.keys()}'] raise ValueError('\n'.join(msg)) from err except AttributeError as err: msgtxt = f'Input lattice should be a string in {UNIT_CELL.keys()}' raise ValueError(msgtxt) from err ndim = len(unit_cell[0]) npart = len(unit_cell) if density is not None: lcon = (npart / density)**(1.0 / float(ndim)) if repeat is None and density is None and lcon is None: logger.debug('The construction of the simulation ' 'box is attempted with insufficient ' 'information. Please check') repeat = [1]*ndim lcon = 1 elif lcon is None: msgtxt = 'Could not determine lattice constant!' raise ValueError(msgtxt) elif len(repeat) < ndim: msgtxt = 'To few "repeat" values given: Expected {} but got {}.' raise ValueError(msgtxt.format(ndim, len(repeat))) positions = [] for i in itertools.product(*[range(nri) for nri in repeat[:ndim]]): pos = lcon * (np.array(i) + unit_cell) positions.extend(pos) size = [[0.0, i * lcon] for i in repeat[:ndim]] positions = np.array(positions) return positions, size