Source code for atom_hifi.soap_ML.soap

import logging
from typing import List
from scipy.spatial.distance import pdist, squareform
import numpy as np
import decaf

logger = logging.getLogger(__name__)



[docs] def get_dist(soap_1, soap_2): return squareform(pdist(np.vstack([soap_1, soap_2])))
[docs] def generate_ED_SOAP(lib: List, lengthscale=1.2, SOAP_S_cut=(1+np.sqrt(3))/2, SOAP_S_nmax=8, SOAP_S_lmax=4, SOAP_L_cut=(2+3)/2, SOAP_L_nmax=4, SOAP_L_lmax=3, species = None, periodic=True, atom_ids_per_structure=None, ): """Embedded Doubled SOAP (ED-SOAP): concatenates a short-range and a long-range SOAP per atom (hence 'doubled'), scaled by `lengthscale`. Designed for use with DECAF's PCA embedding + MSC clustering (`decaf.embed_cluster`). ``atom_ids_per_structure`` optionally selects SOAP evaluation centers for each structure. It does not remove atoms from the structures, so every selected center retains the same neighbours and descriptor row as a full evaluation. """ # Gaussian widths and cutoffs are in units of the physical lengthscale. SOAP_S_sigma = SOAP_S_cut / 8 SOAP_L_sigma = SOAP_L_cut / 8 if species is None: species = np.unique(np.concatenate([struct.numbers for struct in lib])).astype(int) # Obtain the full SOAP of the library. Periodicity is decided per structure: # the `periodic` master switch is honoured only where a structure actually has # periodic boundary conditions, so non-PBC systems (e.g. organic molecules, # pbc=F F F) and mixed libraries are handled correctly without a cell error. if atom_ids_per_structure is None: atom_ids_per_structure = [np.array([], dtype=int) for _ in lib] elif len(atom_ids_per_structure) != len(lib): raise ValueError( 'atom_ids_per_structure must contain one index array per structure') training_set = np.concatenate([ decaf.get_SOAP( struct, lengthscale, species=species, SOAP_S_cut=SOAP_S_cut, SOAP_S_sigma=SOAP_S_sigma, SOAP_S_nmax=SOAP_S_nmax, SOAP_S_lmax=SOAP_S_lmax, SOAP_L_cut=SOAP_L_cut, SOAP_L_sigma=SOAP_L_sigma, SOAP_L_nmax=SOAP_L_nmax, SOAP_L_lmax=SOAP_L_lmax, periodic=bool(periodic and struct.pbc.any()), atomID=np.asarray(atom_ids, dtype=int), ) for struct, atom_ids in zip(lib, atom_ids_per_structure) ]) logger.debug(f'The shape of the training set is [atoms,soap_shape]: {training_set.shape}') return training_set