def check_polar(self): """ Check if the surface structure is polar. Comparing atom types at top and bottom. Applicable for sufcae with vaccums only. Args: file:atoms object (surface with vacuum) Returns: polar:True/False """ up = 0 dn = 0 coords = np.array(self.frac_coords) z_max = max(coords[:, 2]) z_min = min(coords[:, 2]) for site, element in zip(self.frac_coords, self.elements): if site[2] == z_max: up = up + Specie(element).Z if site[2] == z_min: dn = dn + Specie(element).Z polar = False if up != dn: print("Seems like a polar materials.") polar = True if up == dn: print("Non-polar") polar = False return polar
def coulomb_matrix(atoms="", max_dim=100): """Convert Atoms class to max_dim x max_dim matrix. Args: atoms: atoms object max_dim: maximum number of atoms=sqrt(max_dim) Returns: z: numpy array of 1 x max_dim dimension """ natoms = atoms.num_atoms mat = np.zeros((natoms, natoms)) for ii, i in enumerate(atoms.elements): for jj, j in enumerate(atoms.elements): if ii == jj: mat[ii, jj] = 0.5 * Specie(i).Z**2.4 else: a = atoms.cart_coords[ii] b = atoms.cart_coords[jj] dist = np.linalg.norm(a - b) mat[ii, jj] = (Specie(i).Z * Specie(j).Z) / dist tmp = mat.ravel() if max_dim < len(tmp): print("WARNING: Increase max_dim") padding = max_dim - len(tmp) z = np.pad(tmp, (0, padding), "constant") return z
def atomic_fraction_array(self): """Get atomic fraction array.""" nelements = len(list(Specie()._data.keys())) frac_arr = np.zeros(nelements) fracs = self.atomic_fraction for i, j in fracs.items(): frac_arr[int(Specie(i).Z) - 1] = j return frac_arr
def find_ldau_magmom( atoms="", default_magmom=True, U=3.0, mag=5.0, amix=0.2, bmix=0.00001, amixmag=0.8, bmixmag=0.00001, lsorbit=False, ): """Get necessary INCAR tags for DFT+U calculations.""" sps = atoms.uniq_species LDAUL = [] LDAUU = [] LDAUTYPE = 2 lmix = 4 for i in sps: el = Specie(i) el_u = 0 el_l = -1 if el.element_property("is_transition_metal"): el_u = U el_l = 2 if el.element_property("is_actinoid") or el.element_property( "is_lanthanoid"): el_u = U el_l = 3 lmix = 6 LDAUL.append(el_l) LDAUU.append(el_u) if 3 in LDAUL: LDAUTYPE = 3 nat = atoms.num_atoms magmom = str(nat) + str("*") + str(mag) if lsorbit: magmom = "" tmp = " 0 0 " + str(mag) for i in range(0, nat): magmom = magmom + tmp info = {} info["LDAU"] = ".TRUE." info["LDAUTYPE"] = LDAUTYPE info["LDAUL"] = " ".join(str(m) for m in LDAUL) info["LDAUU"] = " ".join(str(m) for m in LDAUU) info["LDAUPRINT"] = 2 info["LMAMIX"] = lmix if not default_magmom: info["MAGMOM"] = magmom info["AMIX"] = amix info["BMIX"] = bmix info["AMIX_MAG"] = amixmag info["BMIX_MAG"] = bmixmag return info
def atomic_species_string(self): """Obtain string for QE atomic species.""" line = "" for i in self.species: line = line + (i + " " + str(round(Specie(i).atomic_mass, 2)) + " " + str(self.get_psp(i)) + "\n") return line
def packing_fraction(self): """Get packing fraction of the atoms object.""" total_rad = 0 for i in self.elements: total_rad = total_rad + Specie(i).atomic_rad**3 pf = np.array([4 * np.pi * total_rad / (3 * self.volume)]) return round(pf[0], 5)
def test_sp(): el = Specie("Al") assert ( el.Z, round(el.atomic_mass, 2), el.symbol, round(el.get_chgdescrp_arr[1], 2), round(el.get_descrp_arr[1], 2), ) == (13, 26.98, "Al", 12.17, 2792.11)
def get_center_of_mass(self): """Get center of mass of the atoms object.""" # atomic_mass m = [] for i in self.elements: m.append(Specie(i).atomic_mass) m = np.array(m) com = np.dot(m, self.cart_coords) / m.sum() # com = np.linalg.solve(self.lattice_mat.T, com) return com
def write_prismatic_xyz(atoms=None): """Write Atoms in prismatic format.""" from jarvis.core.specie import Specie line = str(atoms.num_atoms) + "\n" abc = atoms.lattice.abc line += str(abc[0]) + " " + str(abc[1]) + " " + str(abc[2]) + "\n" for i, j in zip(atoms.elements, atoms.cart_coords): line += (str(Specie(i).Z) + " " + str(j[0]) + " " + str(j[1]) + " " + str(j[2]) + str(" 1 .076\n")) line += "-1\n" return line
def test_sp(): el = Specie("Al") assert ( el.Z, round(el.atomic_mass, 2), el.symbol, round(el.get_chgdescrp_arr[1], 2), round(el.get_descrp_arr[1], 2), ) == (13, 26.98, "Al", 12.17, 2792.11) dat = get_feats_hot_encoded() fat = get_digitized_feats_hot_encoded() x, y, z = get_specie_data()
def reduced_formula(self): """Get reduced formula.""" form = "" reduced, repeat = self.reduce() X = {} for i, j in reduced.items(): X[i] = Specie(i).X Y = dict(sorted(X.items(), key=lambda item: item[1])) Z = {} for i, j in Y.items(): Z[i] = reduced[i] for specie, count in Z.items(): if float(count).is_integer(): form = form + specie + str(int(count)) else: form = form + specie + str(count) return form.replace("1", "")
def refined_atoms(self): """Refine atoms based on spacegroup data.""" phonopy_atoms = ( self._atoms.lattice_mat, self._atoms.frac_coords, self._atoms.atomic_numbers, ) lattice, scaled_positions, numbers = spglib.refine_cell( phonopy_atoms, self._symprec, self._angle_tolerance) elements = self._atoms.elements el_dict = {} for i in elements: el_dict.setdefault(Specie(i).Z, i) ref_elements = [el_dict[i] for i in numbers] ref_atoms = Atoms( lattice_mat=lattice, elements=ref_elements, coords=scaled_positions, cartesian=False, ) return ref_atoms
def primitive_atoms(self): """Get primitive atoms.""" phonopy_atoms = ( self._atoms.lattice_mat, self._atoms.frac_coords, self._atoms.atomic_numbers, ) lattice, scaled_positions, numbers = spglib.find_primitive( phonopy_atoms, symprec=self._symprec) elements = self._atoms.elements el_dict = {} for i in elements: el_dict.setdefault(Specie(i).Z, i) prim_elements = [el_dict[i] for i in numbers] prim_atoms = Atoms( lattice_mat=lattice, elements=prim_elements, coords=scaled_positions, cartesian=False, ) return prim_atoms
def read_data( self, filename="lammps.data", element_order=[], potential_file="pot.mod", verbose=True, ): """Read Lammps data file.""" # n_atoms = len(self._species) if element_order == []: # Reading potential file for element order if verbose: print("element_order is empty, reading from", potential_file) pot_file = open(potential_file, "r") lines = pot_file.read().splitlines() pot_file.close() symb = [] # count = 0 for i, line in enumerate(lines): if "pair_coeff" in line.split(): sp = line.split() # print("spsplit", sp, os.getcwd()) for el in sp: try: if str(Specie(el).Z) != "nan": # if el=='M': # el='Mo' # count=count+1 # if count >4: symb.append(Specie(el).symbol) except Exception: pass else: symb = [Specie(i).symbol for i in element_order] # print("symb=", symb) f = open(filename, "r") lines = f.read().splitlines() for i, line in enumerate(lines): if "atoms" in line.split(): natoms = int(line.split()[0]) if "types" in line.split(): # print(line) ntypes = int(line.split()[0]) if "xlo" in line.split(): xlo = float(line.split()[0]) xhi = float(line.split()[1]) if "ylo" in line.split(): ylo = float(line.split()[0]) yhi = float(line.split()[1]) if "zlo" in line.split(): zlo = float(line.split()[0]) zhi = float(line.split()[1]) if "xy" in line.split(): xy = float(line.split()[0]) xz = float(line.split()[1]) yz = float(line.split()[2]) if len(symb) != ntypes: ValueError("Something wrong in atom type assignment", len(symb), ntypes) lat = np.array([[xhi - xlo, 0.0, 0.0], [xy, yhi - ylo, 0.0], [xz, yz, zhi - zlo]]) typ = np.empty((natoms), dtype="S20") x = np.zeros((natoms)) y = np.zeros((natoms)) z = np.zeros((natoms)) q = np.zeros((natoms)) coords = list() for i, line in enumerate(lines): if "Atoms" in line.split(): for j in range(0, natoms): # print int(((lines[j+2]).split()[1]))-1 typ[j] = symb[int(((lines[i + j + 2]).split()[1])) - 1] q[j] = (lines[i + j + 2]).split()[2] x[j] = (lines[i + j + 2]).split()[3] y[j] = (lines[i + j + 2]).split()[4] z[j] = (lines[i + j + 2]).split()[5] coords.append([x[j], y[j], z[j]]) f.close() # print ("info",(typ),'coo',(coords),'latt',lat) typ_sp = [str(i, "utf-8") for i in typ] # print ('typ_sp',typ_sp) atoms = Atoms( lattice_mat=lat, elements=typ_sp, coords=np.array(coords), cartesian=True, ) return atoms
def write_lammps_in( self, lammps_in="init.mod", lammps_in1="potential.mod", lammps_in2="in.main", lammps_trj=None, lammps_data=None, parameters={}, ): """ Write lammps input file. From ase with custom modifications LAMMPS input is devided into three parts Args: lammps_in: generally"init.mod", with unit and conversion factor information lammps_in1: generally "potential.mod", with force-field/potential style and element type information lammps_in2: generally "in.elastic", a generic main input file to be fed in LAMMPS usin lmp_*<...,parameters['exec'] parameters: input parameters """ f = open(lammps_in, "w") f1 = open(lammps_in1, "w") # potential.mod f2 = open(lammps_in2, "w") f.write(('variable dump_file string "%s"\n' % lammps_trj) + ("variable up equal 1.0e-6\n") + ("variable cfac equal 1.0e-4\n") + ("variable cunits string GPa\n") + ("variable etol equal 0\n") + ("variable ftol equal 1.0e-10\n") + ("variable maxiter equal 1000\n") + ("variable maxeval equal 10000\n") + ("variable dmax equal 1.0e-2\n") + ('variable data_file string "%s"\n' % "data")) if "control_file" in parameters: f2.write("include %s \n" % parameters["control_file"]) if "units" in parameters: f.write("units %s \n" % parameters["units"]) else: f.write("units metal \n") if "atom_style" in parameters: f.write("atom_style %s \n" % parameters["atom_style"]) else: f.write("atom_style atomic \n") if "boundary" in parameters: f.write("boundary %s \n" % parameters["boundary"]) else: pbc = self.pbc f.write("boundary %s %s %s \n" % (pbc[0], pbc[1], pbc[2])) f.write("atom_modify sort 0 0.0 \n") for key in ("neighbor", "newton"): if key in parameters: f.write("%s %s \n" % (key, parameters[key])) f.write("\n") f.write("read_data %s\n" % "data") f.write("\n### interactions \n") if "lib" in parameters: lib = parameters["lib"] f1.write("%s \n" % lib) if ("pair_style" in parameters) and ("pair_coeff" in parameters): pair_style = parameters["pair_style"] f1.write("pair_style %s \n" % pair_style) symbols = self.LammpsDataObj._element_order tag = "" for i in symbols: tag = tag + " " + i pair_coef = "* * " + str(parameters["pair_coeff"]) + " " + tag f1.write("pair_coeff %s \n" % pair_coef) masses = [] for i in symbols: m = Specie(i).atomic_mass if m not in masses: masses.append(m) count = 0 for i in masses: count = count + 1 f.write("mass" + " " + str(count) + " " + str(i) + "\n") else: # default interaction f.write("pair_style lj/cut 2.5 \n" + "pair_coeff * * 1 1 \n" + "mass * 1.0 \n") f1.write("neighbor 1.0 nsq\n") f1.write("neigh_modify once no every 1 delay 0 check yes\n") if "min" not in parameters: f1.write("min_style cg\n") f1.write("min_modify dmax ${dmax} line quadratic\n") f1.write("thermo 1\n") f1.write("thermo_style custom step temp press cpu pxx pyy pzz\ pxy pxz pyz ke pe etotal vol lx ly lz atoms\n") f1.write("thermo_modify norm no\n") if "fix" in parameters: if parameters["fix"]: for i in parameters["fix"]: f1.write("fix %s\n" % i) f.close() f1.close() f2.close()
def get_string(self, cart=True, sort_order="X"): """ Convert Atoms to string. Optional arguments below. Args: cart:True/False for cartesian/fractional coords. sort_order: sort by chemical properties of elements. Default electronegativity. """ system = str(self.composition.formula) header = (str(system) + str("\n1.0\n") + str(self.lattice_mat[0][0]) + " " + str(self.lattice_mat[0][1]) + " " + str(self.lattice_mat[0][2]) + "\n" + str(self.lattice_mat[1][0]) + " " + str(self.lattice_mat[1][1]) + " " + str(self.lattice_mat[1][2]) + "\n" + str(self.lattice_mat[2][0]) + " " + str(self.lattice_mat[2][1]) + " " + str(self.lattice_mat[2][2]) + "\n") if sort_order is None: order = np.argsort(self.elements) else: order = np.argsort([ Specie(i).element_property(sort_order) for i in self.elements ]) if cart: coords = self.cart_coords else: coords = self.frac_coords coords_ordered = np.array(coords)[order] elements_ordered = np.array(self.elements)[order] props_ordered = np.array(self.props)[order] # check_selective_dynamics = False # TODO counts = get_counts(elements_ordered) cart_frac = "" if cart: cart_frac = "\nCartesian\n" else: cart_frac = "\nDirect\n" if "T" in "".join(map(str, self.props[0])): middle = (" ".join(map(str, counts.keys())) + "\n" + " ".join(map(str, counts.values())) + "\nSelective dynamics\n" + cart_frac) else: middle = (" ".join(map(str, counts.keys())) + "\n" + " ".join(map(str, counts.values())) + cart_frac) rest = "" for ii, i in enumerate(coords_ordered): if self.show_props: rest = (rest + " ".join(map(str, i)) + " " + str(props_ordered[ii]) + "\n") else: rest = rest + " ".join(map(str, i)) + "\n" result = header + middle + rest return result
def dfpt_data(self, fc_mass=True): """Get DFPT IBRION=8 related data.""" info = {} hessian = [] data = self._data for i in (data["modeling"]["calculation"]["dynmat"]["varray"])[0]["v"]: hessian.append(i.split()) hessian = np.array(hessian, dtype="double") struct = self.all_structures[-1] natoms = struct.num_atoms force_constants = np.zeros((natoms, natoms, 3, 3), dtype="double") for i in range(natoms): for j in range(natoms): force_constants[i, j] = hessian[ i * 3 : (i + 1) * 3, j * 3 : (j + 1) * 3 ] masses = [Specie(i).atomic_mass for i in struct.elements] if fc_mass: for i in range(natoms): for j in range(natoms): force_constants[i, j] *= -np.sqrt(masses[i] * masses[j]) born_charges = [] for n in range(natoms): born_charges.append( [ i.split() for i in (data["modeling"]["calculation"]["array"]["set"])[ n ]["v"] ] ) born_charges = np.array(born_charges, dtype="double") phonon_eigenvals = np.array( data["modeling"]["calculation"]["dynmat"]["v"]["#text"].split(), dtype="double", ) eigvecs = np.array( [ i.split() for i in ( data["modeling"]["calculation"]["dynmat"]["varray"][1]["v"] ) ], dtype="float", ) phonon_eigenvectors = [] for ev in eigvecs: phonon_eigenvectors.append(np.array(ev).reshape(natoms, 3)) phonon_eigenvectors = np.array(phonon_eigenvectors, dtype="float") epsilon = {} for i in data["modeling"]["calculation"]["varray"]: if "epsilon" in i["@name"]: epsilon[i["@name"]] = np.array( [j.split() for j in i["v"]], dtype="float" ) info["born_charges"] = born_charges info["phonon_eigenvectors"] = phonon_eigenvectors info["epsilon"] = epsilon info["phonon_eigenvalues"] = phonon_eigenvals info["masses"] = masses return info
def atomic_numbers(self): """Get list of atomic numbers of atoms in the atoms object.""" numbers = [] for i in self.elements: numbers.append(Specie(i).Z) return numbers
def simulate(self, atoms=None): """ Simulate XRD pattern. Forked from https://github.com/qzhu2017/XRD. """ # atoms=Spacegroup3D(atoms).conventional_standard_structure rec_matrix = atoms.lattice.reciprocal_lattice_crystallographic().matrix min_r = self.wavelength / np.sin(self.max2theta / 2) / 2 r1 = list(range(1, self.max_index + 1)) r2 = list(range(-self.max_index, 1)) r2.reverse() r3 = r1 + r2 r = r3 hkl_index = [ miller for miller in itertools.product(r, r, r) if any([i != 0 for i in miller]) ] # hkl_index=symmetrically_distinct_miller_indices(cvn_atoms=atoms,max_index=self.max_index) hkl_max = np.array([self.max_index, self.max_index, self.max_index]) for index in hkl_index: d = np.linalg.norm(np.dot(index, rec_matrix)) multiple = int(np.ceil(1 / d / min_r)) index *= multiple for i in range(len(hkl_max)): if hkl_max[i] < index[i]: hkl_max[i] = index[i] h1, k1, l1 = hkl_max h = np.arange(-h1, h1 + 1) k = np.arange(-k1, k1 + 1) L = np.arange(-l1, l1 + 1) hkl = np.array((np.meshgrid(h, k, L))).transpose() hkl_list = np.reshape(hkl, [len(h) * len(k) * len(L), 3]) hkl_list = hkl_list[np.where(hkl_list.any(axis=1))[0]] d_hkl = 1 / np.linalg.norm(np.dot(hkl_list, rec_matrix), axis=1) shortlist = d_hkl > (min_r) d_hkl = d_hkl[shortlist] hkl_list = hkl_list[shortlist] sintheta = self.wavelength / 2 / d_hkl self.theta = np.arcsin(sintheta) self.hkl_list = np.array(hkl_list) self.d_hkl = d_hkl fp = os.path.join(os.path.dirname(__file__), "atomic_scattering_params.json") with open(fp, "r") as f: ATOMIC_SCATTERING_PARAMS = json.load(f) d0 = (1 / 2 / self.d_hkl)**2 coeffs = [] zs = [] for elem in atoms.elements: if elem == "D": elem = "H" c = ATOMIC_SCATTERING_PARAMS[elem] z = Specie(elem).Z coeffs.append(c) zs.append(z) coeffs = np.array(coeffs) self.peaks = {} two_thetas = [] for hkl, s2, theta, d_hkl in zip(self.hkl_list, d0, self.theta, self.d_hkl): # Calculate the scattering factor sf g_dot_r = np.dot(atoms.frac_coords, np.transpose([hkl])).T[0] sf = zs - 41.78214 * s2 * np.sum( coeffs[:, :, 0] * np.exp(-coeffs[:, :, 1] * s2), axis=1) # Calculate the structure factor f f = np.sum(sf * np.exp(2j * np.pi * g_dot_r)) # Calculate the lorentz polarization factor lf lf = (1 + np.cos(2 * theta)**2) / (np.sin(theta)**2 * np.cos(theta)) po = 1 # Calculate the intensity I intensity_tmp = (f * f.conjugate()).real # calculate 2*theta two_theta = np.degrees(2 * theta) # Find where the scattered angles are equal ind = np.where( np.abs(np.subtract(two_thetas, two_theta)) < self.two_theta_tol ) # Append intensity, hkl plane, and thetas to lists if len(ind[0]) > 0: self.peaks[two_thetas[ind[0][0]]][0] += intensity_tmp * lf * po self.peaks[two_thetas[ind[0][0]]][1].append(tuple(hkl)) else: self.peaks[two_theta] = [ intensity_tmp * lf * po, [tuple(hkl)], d_hkl, ] two_thetas.append(two_theta) # max_intensity = max([v[0] for v in self.peaks.values()]) x = [] y = [] d_hkls = [] hkl_families = [] for k in sorted(self.peaks.keys()): v = self.peaks[k] x.append(k) y.append(v[0]) d_hkls.append(v[2]) family = self.get_unique_families(v[1]) hkl_families.append(family) x = np.array(x) y = np.array(y) d_hkls = np.array(d_hkls) const = np.sum(y, axis=0) y = y * self.scaling_factor / const screen = y > self.intensity_tol self.intensity_array = y[screen] self.two_theta_array = x[screen] self.dhkl_array = d_hkls[screen] return ( x[screen].tolist(), d_hkls[screen].tolist(), y[screen].tolist(), # hkl_families[screen], )
def weight(self): """Get atomic weight.""" wt = 0.0 for specie, count in self._content.items(): wt = wt + Specie(specie).atomic_mass * count return wt
def from_atoms( atoms=None, get_prim=False, zero_diag=False, node_atomwise_angle_dist=False, node_atomwise_rdf=False, features="basic", enforce_c_size=10.0, max_n=100, max_cut=5.0, verbose=False, make_colormap=True, ): """ Get Networkx graph. Requires Networkx installation. Args: atoms: jarvis.core.Atoms object. rcut: cut-off after which distance will be set to zero in the adjacency matrix. features: Node features. 'atomic_number': graph with atomic numbers only. 'cfid': 438 chemical descriptors from CFID. 'basic':10 features 'atomic_fraction': graph with atomic fractions in 103 elements. array: array with CFID chemical descriptor names. See: jarvis/core/specie.py enforce_c_size: minimum size of the simulation cell in Angst. """ if get_prim: atoms = atoms.get_primitive_atoms dim = get_supercell_dims(atoms=atoms, enforce_c_size=enforce_c_size) atoms = atoms.make_supercell(dim) adj = np.array(atoms.raw_distance_matrix.copy()) # zero out edges with bond length greater than threshold adj[adj >= max_cut] = 0 if zero_diag: np.fill_diagonal(adj, 0.0) nodes = np.arange(atoms.num_atoms) if features == "atomic_number": node_attributes = np.array( [[np.array(Specie(i).Z)] for i in atoms.elements], dtype="float", ) if features == "atomic_fraction": node_attributes = [] fracs = atoms.composition.atomic_fraction_array for i in fracs: node_attributes.append(np.array([float(i)])) node_attributes = np.array(node_attributes) elif features == "basic": feats = [ "Z", "coulmn", "row", "X", "atom_rad", "nsvalence", "npvalence", "ndvalence", "nfvalence", "first_ion_en", "elec_aff", ] node_attributes = [] for i in atoms.elements: tmp = [] for j in feats: tmp.append(Specie(i).element_property(j)) node_attributes.append(tmp) node_attributes = np.array(node_attributes, dtype="float") elif features == "cfid": node_attributes = np.array( [np.array(Specie(i).get_descrp_arr) for i in atoms.elements], dtype="float", ) elif isinstance(features, list): node_attributes = [] for i in atoms.elements: tmp = [] for j in features: tmp.append(Specie(i).element_property(j)) node_attributes.append(tmp) node_attributes = np.array(node_attributes, dtype="float") else: print("Please check the input options.") if node_atomwise_rdf or node_atomwise_angle_dist: nbr = NeighborsAnalysis(atoms, max_n=max_n, verbose=verbose, max_cut=max_cut) if node_atomwise_rdf: node_attributes = np.concatenate( (node_attributes, nbr.atomwise_radial_dist()), axis=1) node_attributes = np.array(node_attributes, dtype="float") if node_atomwise_angle_dist: node_attributes = np.concatenate( (node_attributes, nbr.atomwise_angle_dist()), axis=1) node_attributes = np.array(node_attributes, dtype="float") # construct edge list uv = [] edge_features = [] for ii, i in enumerate(atoms.elements): for jj, j in enumerate(atoms.elements): bondlength = adj[ii, jj] if bondlength > 0: uv.append((ii, jj)) edge_features.append(bondlength) edge_attributes = edge_features if make_colormap: sps = atoms.uniq_species color_dict = random_colors(number_of_colors=len(sps)) new_colors = {} for i, j in color_dict.items(): new_colors[sps[i]] = j color_map = [] for ii, i in enumerate(atoms.elements): color_map.append(new_colors[i]) return Graph( nodes=nodes, edges=uv, node_attributes=np.array(node_attributes), edge_attributes=np.array(edge_attributes), color_map=color_map, )
def get_comp_descp( self, jcell=True, jmean_chem=True, jmean_chg=True, jrdf=False, jrdf_adf=True, print_names=False, ): """ Get chemo-structural CFID decriptors. Args: struct: Structure object jcell: whether to use cell-size descriptors jmean_chem: whether to use average chemical descriptors jmean_chg: whether to use average charge distribution descriptors jmean_rdf: whether to use radial distribution descriptors jrdf_adf: whether to use radial and angle distribution descriptors print_names: whether to print names of descriptors Returns: cat: catenated final descriptors """ cat = [] s = self._atoms cell = [] mean_chem = [] rdf = [] nn = [] mean_chg = [] adfa = [] adfb = [] ddf = [] if jmean_chem: el_dict = s.composition._content # print (el_dict,type(el_dict)) arr = [] for k, v in el_dict.items(): des = Specie(k).get_descrp_arr arr.append(des) mean_chem = np.mean(np.array(arr), axis=0) # print ('mean_chem',len(mean_chem)) if jcell: v_pa = round(float(s.volume) / float(s.num_atoms), 5) logv_pa = round(log(v_pa), 5) pf = s.packing_fraction density = round(s.density, 5) cell = np.array([v_pa, logv_pa, pf, density]) # print ('jcell',len(cell)) if jrdf: Nbrs = NeighborsAnalysis(s) _, distrdf, nn = Nbrs.get_rdf() rdf = np.array(distrdf) print("rdf", len(rdf)) if jrdf_adf: try: adfa = np.zeros(179) adfb = np.zeros(179) ddf = np.zeros(179) rdf = np.zeros(100) nn = np.zeros(100) distributions = NeighborsAnalysis(s).get_all_distributions rdf = distributions["rdf"] nn = distributions["nn"] adfa = distributions["adfa"] adfb = distributions["adfb"] ddf = distributions["ddf"] except Exception: pass adfa = np.array(adfa) adfb = np.array(adfb) rdf = np.array(rdf) ddf = np.array(ddf) nn = np.array(nn) # print ('adfa',len(adfa)) # print ('ddf',len(ddf)) # print ('adfb',len(adfb)) # print ('rdf',len(rdf)) # print ('nn',len(nn)) if jmean_chg: chgarr = [] el_dict = s.composition._content for k, v in el_dict.items(): chg = Specie(k).get_chgdescrp_arr chgarr.append(chg) mean_chg = np.mean(chgarr, axis=0) # print ('mean_chg',len(mean_chg)) if print_names: nmes = [] chem_nm = get_descrp_arr_name() for d, nm in zip( [mean_chem, cell, mean_chg, rdf, adfa, adfb, ddf, nn], ["mean_chem", "cell", "mean_chg", "rdf", "adfa", "adfb", "ddf", "nn"], ): if len(d) != 0: for ff, dd in enumerate(d): cat.append(dd) if nm == "mean_chem": tag = chem_nm[ff] else: tag = str(nm) + str("_") + str(ff) nmes.append(str(tag)) cat = np.array(cat).astype(float) # print (nmes,len(nmes)) return nmes else: for d, nm in zip( [mean_chem, cell, mean_chg, rdf, adfa, adfb, ddf, nn], ["mean_chem", "cell", "mean_chg", "rdf", "adfa", "adfb", "ddf", "nn"], ): if len(d) != 0: # if d != []: for ff, dd in enumerate(d): cat.append(dd) cat = np.array(cat).astype(float) return cat