PK!aacscribe/__init__.pyfrom .soap import SOAP from .sf import SymmetryFunctions components = [SOAP, SymmetryFunctions] PK!0( ( cscribe/conversion.py"""Convert representations for cmlkit""" import numpy as np def to_local(data, rep): """Convert dscribe-style atomic rep to cmlkit-style atomic rep. dscribe returns local descriptors as one flat array of dimension n_total_atoms x dim, whereas cmlkit expects a ndarray-list of length n_systems, where each entry is an ndarry of dim n_atoms_system x dim, i.e. the local representations for each atom in this particular system. The translation between these two notations is done via an offset array, which keeps track of which entries in the dscribe array belong to which atom. Args: data: Dataset instance rep: ndarray n_total_atoms x dim Returns: cmlkit-style atomic representation """ counts = data.info["atoms_by_system"] offsets = np.zeros(len(counts) + 1, dtype=int) offsets[1::] = np.cumsum(counts) return np.array( [rep[offsets[i] : offsets[i + 1]] for i in range(data.n)], dtype=object ) def in_blocks(data, rep): """Arrange local representation in blocks by element. Some representations (ACSF) are returned without taking the central atom type into account. This doesn't work with kernel ridge regression, so we re-arrange the respresentation into zero-padded element blocks, like so: Let (...) be the representation. Let's say we have Z's 1 and 2. Let's say we have one molecule with first atom Z1=1, second Z2=1. Let's say we have dim=2. The result of this function will be [ (Z1=1) (0, 0), (0, 0), (Z2=1) ] I.e. we will have separate blocks for each central atom, filled with zeros where the central atom type is "not in use". Args: dataset: Dataset instance rep: cmlkit-style atomic representation Returns: cmlkit-style atomic representation """ n_elems = data.info["total_elements"] elem_idx = {e: i for i, e in enumerate(data.info["elements"])} all_new = [] for i, rep_system in enumerate(rep): dim = len(rep_system[0]) new = np.zeros((len(rep_system), dim*n_elems)) for j, rep_atom in enumerate(rep_system): idx = elem_idx[data.z[i][j]] new[j, idx * dim : (idx + 1) * dim] = rep_atom all_new.append(new) return np.array(all_new, dtype=object) PK!"n"jj cscribe/sf.pyimport numpy as np from cmlkit.representation import Representation from cmlkit.representation.sf.config import prepare_config from cmlkit.engine import parse_config from dscribe.descriptors import ACSF from .conversion import to_local, in_blocks class SymmetryFunctions(Representation): """Atom-Centered Symmetry Functions (with DScribe). Symmetry functions are an atomic representation, consisting of an array of function values computed with different parametrisations. They were introduced by Jörg Behler in Behler, JCP 134, 074106 (2011). At the moment, we support only the "standard" angular and radial symmetry functions, which are: "rad": G_i^2 (eq. 6) in the paper. Parameters: eta: Width of the Gaussian. mu: Shift of center. (R_S in equation.) "ang": G_i^4 (eq. 8) in the paper. Parameters: eta: Width of Gaussian. zeta: Roughly, the width of the angular distribution. lambd: "Direction" of angular distribution. (Only +-1.) (not that `lambda` is a keyword, so it's lambd) *** Individual symmetry functions are specified in the default `cmlkit` config format, i.e. one radial symmetry function is `{"rad": {"eta": 1.0, "mu": 0.0}}`. In the `dscribe` interface, only a global cutoff can be specified, and all symmetry functions are applied to all element combinations. Note that the G_i^1 SF is automatically added by `dscribe`. *** Additionally, parametrization schemes are available for the radial symmetry functions. They are: shifted: With argument "n", the n symmetry functions are distributed so their mean is on a regular grid between 0 and cutoff. centered: Same as shifted, but all SFs are centered on 0, with widths on a grid up to the cutoff. Both schemes are also specified as configs, for instance: `{"shifted": {"n": 10}}` *** Parametrisation schemes can be combined, and augmented with hand-defined SFs. Parameters: elems: List of elements for which SFs are supposed to be computed cutoff: Cutoff sfs: List of configs of SFs or configs of parametrization schemes """ kind = "ds_sf" default_context = {"verbose": False, "n_jobs": 1} def __init__(self, elems, cutoff, sfs=[], context={}): super().__init__(context=context) sfs_with_cutoff = [] for sf in sfs: kind, inner = parse_config(sf) inner["cutoff"] = cutoff sfs_with_cutoff.append({kind: inner}) self.runner_config = prepare_config( elems=elems, elemental=[], universal=sfs_with_cutoff ) self.config = {"elems": elems, "sfs": sfs, "cutoff": cutoff} def compute(self, data): return compute_symmfs( data, elems=self.config["elems"], cutoff=self.config["cutoff"], sfs=self.runner_config["universal"], n_jobs=self.context["n_jobs"], verbose=self.context["verbose"], ) def _get_config(self): return self.config def compute_symmfs(data, elems, cutoff, sfs, n_jobs=1, verbose=False): g2_params, g4_params = make_params(sfs) acsf = ACSF( rcut=cutoff, g2_params=g2_params, g4_params=g4_params, species=elems, sparse=False ) rep = acsf.create(data.as_Atoms(), n_jobs=n_jobs, verbose=verbose) return in_blocks(data, to_local(data, rep)) def make_params(sfs): g2_params = [] g4_params = [] for sf in sfs: kind, inner = parse_config(sf) if kind == "rad": g2_params.append([inner["eta"], inner["mu"]]) elif kind == "ang": g4_params.append([inner["eta"], inner["zeta"], inner["lambd"]]) else: raise ValueError( f"ACSF kind {kind} is not yet implemented. (Allowed: rad and ang.)" ) if len(g2_params) == 0: g2_params = None else: g2_params = np.array(g2_params) if len(g4_params) == 0: g4_params = None else: g4_params = np.array(g4_params) return g2_params, g4_params PK!Nccscribe/soap.pyfrom cmlkit.representation import Representation from dscribe.descriptors import SOAP as dsSOAP from .conversion import to_local class SOAP(Representation): """SOAP Representation (implemented in DScribe). For details, see https://singroup.github.io/dscribe/tutorials/soap.html or the dscribe source. Parametrisation here is identical to "original" quippy SOAP, with the addition of the "rbf" argument. Parameters: elems: Elements for which we compute SOAP cutoff: Cutoff radius sigma: Broadening n_max: Number of radial basis functions l_max: Number of angular basis functions rbf: Radial basis set. Either "gto" for Gaussians, or "polynomial" for a polynomial basis set more similar to the "original" SOAP approach. """ kind = "ds_soap" default_context = {"n_jobs": 1, "verbose": False} def __init__(self, elems, cutoff, sigma, n_max, l_max, rbf="gto", context={}): super().__init__(context=context) self.config = { "elems": elems, "cutoff": cutoff, "sigma": sigma, "n_max": n_max, "l_max": l_max, "rbf": rbf, } def _get_config(self): return self.config def compute(self, data): if data.b is None: ds_soap = dsSOAP( species=self.config["elems"], rcut=self.config["cutoff"], nmax=self.config["n_max"], lmax=self.config["l_max"], sigma=self.config["sigma"], rbf=self.config["rbf"], crossover=True, periodic=False, ) else: ds_soap = dsSOAP( species=self.config["elems"], rcut=self.config["cutoff"], nmax=self.config["n_max"], lmax=self.config["l_max"], sigma=self.config["sigma"], rbf=self.config["rbf"], crossover=True, periodic=True, ) rep = ds_soap.create( data.as_Atoms(), n_jobs=self.context["n_jobs"], verbose=self.context["verbose"], ) return to_local(data, rep) PK!;f..cscribe-0.2.0.dist-info/LICENSEMIT License Copyright (c) 2019 Marcel Langer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HڽTUcscribe-0.2.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HZ cscribe-0.2.0.dist-info/METADATARn@Sĥb;i*Yj$Qrqۻ쎓z>/[G`?Bn;|7sgu'Spvե.0'vNxvԸ* jl^Tql]V'szk D1dQg4LLyrB`m ( *Όx.St My 3\4j+ra-@~zr_\{Owºiq W>Yg[oӿ I. *ӕJkNMtywz"~=j=l\~]Vn}R&܌1Ol\M ,sS2\VVxϑ3,z=xzoא!(`+5٠'@4NN] Cd?_vH6_] }6}l؋\z`Rc+FXhGЊnLYA_{"TPK!HKcscribe-0.2.0.dist-info/RECORDu9@мvQ,"b#&zJcfe:zNۇW<. n#yA&mc1[;)ZY8<6pQִQhJ