def distance(self, entry_id, entry_jd, rcut=50): """ Return a measure of the distance between two clusters by computing a n-dimensional vector of the distances between each atom to the origin and :param rcut: :param entry_id: The id of one population entry :param entry_jd: The id of another population entry :return: (int) The distance between two clusters """ ids_pair = tuple(np.sort([entry_id, entry_jd])) distance_entry = self.distancer.get_distance(ids_pair) if distance_entry is None: fingerprints = {} for entry_ijd in [entry_id, entry_jd]: if self.fingerprinter.get_fingerprint(entry_ijd) is None: structure = self.get_structure(entry_ijd) analysis = ClusterAnalysis(structure) x, ys = analysis.discrete_radial_distribution_function() fingerprint = {'_id': entry_ijd} for k in ys: atomic_number1 = atomic_number(k[0]) atomic_number2 = atomic_number(k[1]) pair = '%06d' % min(atomic_number1 * 1000 + atomic_number2, atomic_number2 * 1000 + atomic_number1) fingerprint[pair] = list(ys[k]) if self.fingerprinter.get_fingerprint(entry_ijd) is None: self.fingerprinter.set_fingerprint(fingerprint) else: self.fingerprinter.update(entry_ijd, fingerprint) fingerprints[entry_ijd] = fingerprint else: fingerprints[entry_ijd] = self.fingerprinter.get_fingerprint(entry_ijd) dij = [] for pair in fingerprints[entry_id]: if pair in fingerprints[entry_jd] and pair != '_id': vect1 = fingerprints[entry_id][pair] vect2 = fingerprints[entry_jd][pair] if len(vect1) < len(vect2): tmp = np.zeros(len(vect2)) tmp[:len(vect1)] = vect1 vect1 = tmp elif len(vect1) > len(vect2): tmp = np.zeros(len(vect1)) tmp[:len(vect2)] = vect2 vect2 = tmp uvect1 = unit_vector(vect1) uvect2 = unit_vector(vect2) dij.append(0.5 * (1.0 - np.dot(uvect1, uvect2))) distance = float(np.mean(dij)) self.distancer.set_distance(ids_pair, distance) else: distance = distance_entry['distance'] return distance
def all_distances_by_species(self): all_distances = self.all_distances() ret = OrderedDict() atom_numbers = atomic_number(self.structure.species) a = list(itertools.combinations_with_replacement(atom_numbers, 2)) keys = sorted([tuple(sorted(list(x))) for x in a]) for key in keys: ret[key] = [] for ipair in all_distances: key = tuple( sorted( atomic_number([ self.structure.symbols[ipair[0]], self.structure.symbols[ipair[1]] ]))) if self.structure.is_periodic: ret[key] = np.concatenate( (ret[key], all_distances[ipair]['distance'])) else: ret[key].append(all_distances[ipair]) # Sorting arrays for key in ret: ret[key].sort() ret[key] = np.array(ret[key]) return ret
def distance(self, entry_id, entry_jd, rcut=50): ids_pair = [entry_id, entry_jd] ids_pair.sort() distance_entry = self.pcdb.db.distances.find_one({'pair': ids_pair}, {'distance': 1}) self.pcdb.db.distances.create_index([("pair", ASCENDING)]) if distance_entry is None: print('Distance not in DB') fingerprints = {} for entry_ijd in [entry_id, entry_jd]: if self.pcdb.db.fingerprints.find_one({'_id': entry_ijd }) is None: structure = self.get_structure(entry_ijd) analysis = StructureAnalysis(structure, radius=rcut) x, ys = analysis.fp_oganov() fingerprint = {'_id': entry_ijd} for k in ys: atomic_number1 = atomic_number(structure.species[k[0]]) atomic_number2 = atomic_number(structure.species[k[1]]) pair = '%06d' % min( atomic_number1 * 1000 + atomic_number2, atomic_number2 * 1000 + atomic_number1) fingerprint[pair] = list(ys[k]) if self.pcdb.db.fingerprints.find_one({'_id': entry_ijd }) is None: self.pcdb.db.fingerprints.insert(fingerprint) else: self.pcdb.db.fingerprints.update({'_id': entry_ijd}, fingerprint) fingerprints[entry_ijd] = fingerprint else: fingerprints[ entry_ijd] = self.pcdb.db.fingerprints.find_one( {'_id': entry_ijd}) dij = [] for pair in fingerprints[entry_id]: if pair in fingerprints[entry_jd] and pair != '_id': uvect1 = unit_vector(fingerprints[entry_id][pair]) uvect2 = unit_vector(fingerprints[entry_jd][pair]) dij.append(0.5 * (1.0 - np.dot(uvect1, uvect2))) distance = float(np.mean(dij)) self.pcdb.db.distances.insert({ 'pair': ids_pair, 'distance': distance }) else: distance = distance_entry['distance'] return distance
def species_encoded(self, base): ret = 0 i = 0 for atom_number in sorted(atomic_number(self.species)): ret += atom_number * (base ** i) i += 1 return ret
def match(self): species = self.structure1.species species = list(np.array(species)[np.array(atomic_number(species)).argsort()]) permutation = np.zeros(len(self.structure1.positions), dtype=int) num = 0 for ispecie in species: pos1 = self.structure1.positions[np.array(self.structure1.symbols) == ispecie] pos2 = self.structure2.positions[np.array(self.structure2.symbols) == ispecie] dm = scipy.spatial.distance_matrix(pos1, pos2) match_list = np.zeros(len(pos1)) maxdis = np.max(dm.flatten()) for i in range(len(pos1)): match = dm[i, :].argmin() # print " %3s %3d %9.3f %9.3f %9.3f" % (ispecie, match, np.linalg.norm(pos1[i]), # np.linalg.norm(pos1[match]), dm[i,match]) match_list[i] = match dm[:, match] = maxdis + 1 match_list += num permutation[num:num + len(pos1)] = match_list num += len(pos1) # print permutation self.structure2.sort_sites_using_list(permutation)
def species_encoded(self, base): ret = 0 i = 0 for atom_number in sorted(atomic_number(self.species)): ret += atom_number * (base**i) i += 1 return ret
def species_hex(self): spec_hex = 0 i = 0 for atom_number in sorted(atomic_number(self.species)): spec_hex += atom_number * (256 ** i) i += 1 return spec_hex
def center_mass(self, list_of_atoms=None): """ Computes the center of mass (CM) of the XYZ object or a partial list of atoms. The default is to compute the CM of all the atoms in the object, if a list is enter only those in the list will be included for the CM Return the CM as a numpy array """ if list_of_atoms is None: list_of_atoms = range(self.natom) total_mass = 0.0 center_of_mass = np.zeros(3) if self.natom == 0: return center_of_mass atomicnumber = atomic_number(list(self.symbols)) for i in range(self.natom): if i in list_of_atoms: total_mass = total_mass + mass(atomicnumber[i]) center_of_mass = center_of_mass + mass( atomicnumber[i]) * self.positions[i] return center_of_mass / total_mass
def match(self): species = self.structure1.species species = list(np.array(species)[np.array(atomic_number(species)).argsort()]) permutation = np.zeros(len(self.structure1.positions)) num = 0 for ispecie in species: pos1 = self.structure1.positions[np.array(self.structure1.symbols) == ispecie] pos2 = self.structure2.positions[np.array(self.structure2.symbols) == ispecie] dm = scipy.spatial.distance_matrix(pos1, pos2) match_list = np.zeros(len(pos1)) maxdis = np.max(dm.flatten()) for i in range(len(pos1)): match = dm[i, :].argmin() # print " %3s %3d %9.3f %9.3f %9.3f" % (ispecie, match, np.linalg.norm(pos1[i]), # np.linalg.norm(pos1[match]), dm[i,match]) match_list[i] = match dm[:, match] = maxdis + 1 match_list += num permutation[num:num + len(pos1)] = match_list num += len(pos1) # print permutation self.structure2.sort_sites_using_list(list(permutation))
def create_pov(self): ret = """ #version 3.7; #include "colors.inc" // The include files contain #include "stones.inc" // pre-defined scene elements #include "glass.inc" background{rgb 0} """ if self.structure.is_crystal: self.distance = max(self.structure.lattice.lengths) else: self.distance = 10 ret += "#declare r=%7.3f;\n #declare s=%7.3f;" % (self.distance, self.distance) ret += "camera {\n" ret += "\tlocation <%7.3f, %7.3f, %7.3f>\n" % (1.3 * self.distance, 1.3 * self.distance, -1.3 * self.distance) ret += "\tlook_at <%7.3f, %7.3f, %7.3f>\n" % tuple(0.5 * sum(self.structure.cell[:])) ret += "}\n\n" if self.structure.nsites > 0: d = self.distance ret += "light_source { <%7.3f, %7.3f, %7.3f> color White}\n" % (2 * d, 2 * d, 2 * d) for imagx in np.arange(-1, 2): for imagy in np.arange(-1, 2): for imagz in np.arange(-1, 2): for site in self.structure: for symbol in site.symbols: cell = self.structure.cell x = site.position[0] - imagx * cell[0, 0] - imagy * cell[1, 0] - imagz * cell[2, 0] y = site.position[1] - imagx * cell[0, 1] - imagy * cell[1, 1] - imagz * cell[2, 1] z = site.position[2] - imagx * cell[0, 2] - imagy * cell[1, 2] - imagz * cell[2, 2] if (x - self.distance) ** 2 + (y - self.distance) ** 2 + (z + self.distance) ** 2 < 2: continue cr = 0.5 * covalent_radius(symbol) rgb = cpk_colors[atomic_number(symbol)] color = 'rgb < %7.3f, %7.3f, %7.3f>' % (rgb[0], rgb[1], rgb[2]) ret += "sphere {\n" ret += "\t<%7.3f, %7.3f, %7.3f>, %7.3f\n\ttexture {\n" % (x, y, z, cr) ret += "\t\tpigment { color %s filter 0.4 transmit %7.3f}\n" % \ (color, 1 - 0.9 * np.exp(-0.1 * (abs(imagx) + abs(imagy) + abs(imagz)))) ret += "\t\tnormal { bumps 0.8 scale 0.1 }\n\t\tfinish { phong %7.3f }\n\t}\n}\n\n" % \ np.exp(-0.1 * (abs(imagx) + abs(imagy) + abs(imagz))) if self.structure.nsites <= 0: ret += "light_source { <%7.3f, %7.3f, %7.3f> color White}\n" % (x, y, z) ret += """union{ #include "cell.pov" scale 1 rotate <0, 0, 0> pigment{rgb <0.3,0.3,0.9>} finish{phong 0.9 ambient 0.42 reflection 0.1} } """ return ret
def test(self): """ DocTests exceptions (pychemia.utils) : """ from pychemia.utils.periodic import atomic_number with self.assertRaises(Exception) as context: atomic_number(['H', u'A']) # self.assertTrue(u'Atomic symbol not found' == context.exception) from pychemia.utils.computing import read_file with self.assertRaises(Exception) as context: read_file('/dev/abc') # self.assertTrue('Could not open file: /dev/abc' in context.exception) from pychemia.utils.computing import get_float with self.assertRaises(Exception) as context: get_float('3i')
def hardness_XX(self, initial_cutoff_radius=0.8, use_laplacian=True): bonds, coordination, cutoff_radius = self.bonds_coordination( initial_cutoff_radius=initial_cutoff_radius, use_laplacian=use_laplacian) sigma = 3.0 c_hard = 1300.0 xprod = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 atomicnumbers = atomic_number(self.structure.species) pcm_log.debug('Atomic numbers in the structure : %s' % str(atomicnumbers)) for i in atomicnumbers: f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) if f_d == 0: pcm_log.debug('Returning zero as hardness. f_d= %10.3f' % f_d) return 0.0 f = 1.0 - (self.structure.nspecies * f_n**(1.0 / self.structure.nspecies) / f_d)**2 diff_bonds = [x for x in bonds if len(bonds[x]) > 0] for pair in diff_bonds: i1 = pair[0] i2 = pair[1] ei = valence(self.structure.symbols[i1]) / covalent_radius( self.structure.symbols[i1]) ej = valence(self.structure.symbols[i2]) / covalent_radius( self.structure.symbols[i2]) for dij in bonds[pair]: sij = math.sqrt( ei * ej) / (coordination[i1] * coordination[i2]) / dij xprod *= sij num_i_j_bonds = len(bonds[pair]) pcm_log.debug('Number of bonds for pair %s = %d' % (str(pair), num_i_j_bonds)) tot += num_i_j_bonds vol = self.structure.volume pcm_log.debug("Structure volume: %7.3f" % vol) pcm_log.debug("Total number of bonds: %d" % tot) pcm_log.debug("Bonds: %s" % str(bonds)) hardness_value = (c_hard / vol) * tot * (xprod**(1. / tot)) * math.exp( -sigma * f) return round(hardness_value, 3), cutoff_radius, coordination
def hardness_XX(self, initial_cutoff_radius=0.8, use_laplacian=True): """ Implementation of Hardness algorithm: First-principles structural design of superhard materials J. Chem. Phys. 138, 114101 (2013); https://doi.org/10.1063/1.4794424 Xinxin Zhang, et al. """ bonds, coordination, cutoff_radius = self.bonds_coordination(initial_cutoff_radius=initial_cutoff_radius, use_laplacian=use_laplacian) sigma = 3.0 c_hard = 1300.0 xprod = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 atomicnumbers = atomic_number(self.structure.species) pcm_log.debug('Atomic numbers in the structure : %s' % str(atomicnumbers)) for i in atomicnumbers: f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) if f_d == 0: pcm_log.debug('Returning zero as hardness. f_d= %10.3f' % f_d) return 0.0 f = 1.0 - (self.structure.nspecies * f_n ** (1.0 / self.structure.nspecies) / f_d) ** 2 diff_bonds = [x for x in bonds if len(bonds[x]) > 0] for pair in diff_bonds: i1 = pair[0] i2 = pair[1] ei = valence(self.structure.symbols[i1]) / covalent_radius(self.structure.symbols[i1]) ej = valence(self.structure.symbols[i2]) / covalent_radius(self.structure.symbols[i2]) for dij in bonds[pair]: sij = math.sqrt(ei * ej) / (coordination[i1] * coordination[i2]) / dij xprod *= sij num_i_j_bonds = len(bonds[pair]) pcm_log.debug('Number of bonds for pair %s = %d' % (str(pair), num_i_j_bonds)) tot += num_i_j_bonds vol = self.structure.volume pcm_log.debug("Structure volume: %7.3f" % vol) pcm_log.debug("Total number of bonds: %d" % tot) pcm_log.debug("Bonds: %s" % str(bonds)) hardness_value = (c_hard / vol) * tot * (xprod ** (1. / tot)) * math.exp(-sigma * f) return round(hardness_value, 3), cutoff_radius, coordination
def distance(self, entry_id, entry_jd, rcut=50): ids_pair = [entry_id, entry_jd] ids_pair.sort() distance_entry = self.pcdb.db.distances.find_one({'pair': ids_pair}, {'distance': 1}) self.pcdb.db.distances.create_index([("pair", pymongo.ASCENDING)]) if distance_entry is None: print('Distance not in DB') fingerprints = {} for entry_ijd in [entry_id, entry_jd]: if self.pcdb.db.fingerprints.find_one({'_id': entry_ijd}) is None: structure = self.get_structure(entry_ijd) analysis = StructureAnalysis(structure, radius=rcut) x, ys = analysis.fp_oganov() fingerprint = {'_id': entry_ijd} for k in ys: atomic_number1 = atomic_number(structure.species[k[0]]) atomic_number2 = atomic_number(structure.species[k[1]]) pair = '%06d' % min(atomic_number1 * 1000 + atomic_number2, atomic_number2 * 1000 + atomic_number1) fingerprint[pair] = list(ys[k]) if self.pcdb.db.fingerprints.find_one({'_id': entry_ijd}) is None: self.pcdb.db.fingerprints.insert(fingerprint) else: self.pcdb.db.fingerprints.update({'_id': entry_ijd}, fingerprint) fingerprints[entry_ijd] = fingerprint else: fingerprints[entry_ijd] = self.pcdb.db.fingerprints.find_one({'_id': entry_ijd}) dij = [] for pair in fingerprints[entry_id]: if pair in fingerprints[entry_jd] and pair != '_id': uvect1 = unit_vector(fingerprints[entry_id][pair]) uvect2 = unit_vector(fingerprints[entry_jd][pair]) dij.append(0.5 * (1.0 - np.dot(uvect1, uvect2))) distance = float(np.mean(dij)) self.pcdb.db.distances.insert({'pair': ids_pair, 'distance': distance}) else: distance = distance_entry['distance'] return distance
def sort_sites(self): # First: Sort sites using the distance to the origin sorted_indices = np.array([np.linalg.norm(self.positions[i]) for i in range(self.nsites)]).argsort() # print sorted_indices self.sort_sites_using_list(sorted_indices) # Second: Sort again using the atomic number if len(self.species) > 1: sorted_indices = np.array([atomic_number(x) for x in self.symbols]).argsort() self.sort_sites_using_list(sorted_indices)
def view_projections(self): """ Show the 3 projections of the molecule in a single figure """ import matplotlib.patches as mpatches from matplotlib.collections import PatchCollection from matplotlib.pylab import subplots fig, ax = subplots(nrows=1, ncols=3) fig.set_size_inches(15, 4) color = ['r', 'g', 'b'] j = 0 structure = self.get_structure() for i in structure.cell: ax[0].plot([0, i[0]], [0, i[1]], color[j] + '-', lw=3) ax[1].plot([0, i[1]], [0, i[2]], color[j] + '-', lw=3) ax[2].plot([0, i[2]], [0, i[0]], color[j] + '-', lw=3) j += 1 proj = [[0, 1], [1, 2], [2, 0]] labels = [['x', 'y'], ['y', 'z'], ['z', 'x']] for j in range(3): patches = [] for i in range(structure.natom): radius = 0.5 * covalent_radius( atomic_number(structure.symbols[i])) pos = structure.positions[i] art = mpatches.Circle((pos[proj[j][0]], pos[proj[j][1]]), radius, fc='g', ec='g') patches.append(art) collection = PatchCollection(patches, color='k', alpha=0.5) col = ax[j].add_collection(collection) ax[j].set_xlim( min(structure.positions[:, proj[j][0]]) - 1, max(structure.positions[:, proj[j][0]]) + 1) ax[j].set_ylim( min(structure.positions[:, proj[j][1]]) - 1, max(structure.positions[:, proj[j][1]]) + 1) ax[j].set_aspect('equal', adjustable='datalim') ax[j].set_xlabel(labels[j][0]) ax[j].set_ylabel(labels[j][1]) return fig, ax
def write_geometry_bas(structure, filename): wf = open(filename, 'w') wf.write('%3d\n' % structure.natom) for i in range(structure.natom): if structure.is_periodic: x = structure.reduced[i, 0] y = structure.reduced[i, 1] z = structure.reduced[i, 2] else: x = structure.positions[i, 0] y = structure.positions[i, 1] z = structure.positions[i, 2] wf.write('%3d %13.7f %13.7f %13.7f\n' % (atomic_number(structure.symbols[i]), x, y, z)) wf.close()
def sort_sites(self): # First: Sort sites using the distance to the origin sorted_indices = np.array([ np.linalg.norm(self.positions[i]) for i in range(self.nsites) ]).argsort() # print sorted_indices self.sort_sites_using_list(sorted_indices) # Second: Sort again using the atomic number if len(self.species) > 1: sorted_indices = np.array([atomic_number(x) for x in self.symbols]).argsort() self.sort_sites_using_list(sorted_indices)
def write_geometry_bas(structure, filename): wf = open(filename, 'w') wf.write('%3d\n' % structure.natom) for i in range(structure.natom): if structure.is_periodic: x = structure.reduced[i, 0] y = structure.reduced[i, 1] z = structure.reduced[i, 2] else: x = structure.positions[i, 0] y = structure.positions[i, 1] z = structure.positions[i, 2] wf.write('%3d %13.7f %13.7f %13.7f\n' % (atomic_number(structure.symbols[i]), x, y, z)) wf.close()
def hardness_XX(self, initial_cutoff_radius=0.8, use_laplacian=True): bonds, coordination, cutoff_radius = self.bonds_coordination(initial_cutoff_radius=initial_cutoff_radius, use_laplacian=use_laplacian, verbose=True) sigma = 3.0 c_hard = 1300.0 xprod = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 atomicnumbers = atomic_number(self.structure.species) pcm_log.debug('Atomic numbers in the structure : %s' % str(atomicnumbers)) for i in atomicnumbers: f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) if f_d == 0: pcm_log.debug('Returning zero as hardness. f_d= %10.3f' % f_d) return 0.0 f = 1.0 - (self.structure.nspecies * f_n ** (1.0 / self.structure.nspecies) / f_d) ** 2 diff_bonds = [x for x in bonds if len(bonds[x]) > 0] for pair in diff_bonds: i1 = pair[0] i2 = pair[1] ei = valence(self.structure.symbols[i1]) / covalent_radius(self.structure.symbols[i1]) ej = valence(self.structure.symbols[i2]) / covalent_radius(self.structure.symbols[i2]) for dij in bonds[pair]: sij = math.sqrt(ei * ej) / (coordination[i1] * coordination[i2]) / dij xprod *= sij num_i_j_bonds = len(bonds[pair]) pcm_log.debug('Number of bonds for pair %s = %d' % (str(pair), num_i_j_bonds)) tot += num_i_j_bonds vol = self.structure.volume pcm_log.debug("Structure volume: %7.3f" % vol) pcm_log.debug("Total number of bonds: %d" % tot) pcm_log.debug("Bonds: %s" % str(bonds)) hardness_value = (c_hard / vol) * tot * (xprod ** (1. / tot)) * math.exp(-sigma * f) return round(hardness_value, 3), cutoff_radius, coordination
def all_distances_by_species(self): all_distances = self.all_distances() ret = OrderedDict() atom_numbers = atomic_number(self.structure.species) a = list(itertools.combinations_with_replacement(atom_numbers, 2)) keys=sorted([tuple(sorted(list(x))) for x in a]) for key in keys: ret[key] = [] for ipair in all_distances: key = tuple(sorted(atomic_number([self.structure.symbols[ipair[0]], self.structure.symbols[ipair[1]]]))) if self.structure.is_periodic: ret[key] = np.concatenate((ret[key], all_distances[ipair]['distance'])) else: ret[key].append(all_distances[ipair]) # Sorting arrays for key in ret: ret[key].sort() ret[key] = np.array(ret[key]) return ret
def species_encoded(self, base): """Encode the list of species with a number :return: Encodes the species as a number. :param base: Integer used as base for encoding. :rtype: int >>> cp = Composition('H2O') >>> cp.species_encoded(100) 801 """ ret = 0 i = 0 for atom_number in sorted(atomic_number(self.species)): ret += atom_number * (base**i) i += 1 return ret
def view_projections(self): """ Show the 3 projections of the molecule in a single figure """ import matplotlib.patches as mpatches from matplotlib.collections import PatchCollection from matplotlib.pylab import subplots fig, ax = subplots(nrows=1, ncols=3) fig.set_size_inches(15, 4) color = ['r', 'g', 'b'] j = 0 structure = self.get_structure() for i in structure.cell: ax[0].plot([0, i[0]], [0, i[1]], color[j] + '-', lw=3) ax[1].plot([0, i[1]], [0, i[2]], color[j] + '-', lw=3) ax[2].plot([0, i[2]], [0, i[0]], color[j] + '-', lw=3) j += 1 proj = [[0, 1], [1, 2], [2, 0]] labels = [['x', 'y'], ['y', 'z'], ['z', 'x']] for j in range(3): patches = [] for i in range(structure.natom): radius = 0.5 * covalent_radius(atomic_number(structure.symbols[i])) pos = structure.positions[i] art = mpatches.Circle((pos[proj[j][0]], pos[proj[j][1]]), radius, fc='g', ec='g') patches.append(art) collection = PatchCollection(patches, color='k', alpha=0.5) col = ax[j].add_collection(collection) ax[j].set_xlim(min(structure.positions[:, proj[j][0]]) - 1, max(structure.positions[:, proj[j][0]]) + 1) ax[j].set_ylim(min(structure.positions[:, proj[j][1]]) - 1, max(structure.positions[:, proj[j][1]]) + 1) ax[j].set_aspect('equal', adjustable='datalim') ax[j].set_xlabel(labels[j][0]) ax[j].set_ylabel(labels[j][1]) return fig, ax
def from_structure(self, structure): """ Set input variables for a given structure :param structure: (pychemia.Structure) Structure to set ABINIT input variables :return: """ natom = structure.natom ntypat = len(structure.species) znucl = atomic_number(structure.species) typat_dict = {} index = 1 for ispec in structure.species: typat_dict[ispec] = index index += 1 typat = [typat_dict[i] for i in structure.symbols] xcart = angstrom_bohr * structure.positions.flatten() acell = angstrom_bohr * np.array(structure.lattice.lengths) rprim = unit_vectors(structure.cell).T.flatten() for i in ['natom', 'ntypat', 'znucl', 'typat', 'xcart', 'acell', 'rprim']: self.set_value(i, eval(i))
def from_structure(self, structure): """ Set input variables for a given structure :param structure: (pychemia.Structure) Structure to set ABINIT input variables :return: """ natom = structure.natom ntypat = len(structure.species) znucl = atomic_number(structure.species) typat_dict = {} index = 1 for ispec in structure.species: typat_dict[ispec] = index index += 1 typat = [typat_dict[i] for i in structure.symbols] xcart = angstrom_bohr * structure.positions.flatten() acell = angstrom_bohr * np.array(structure.lattice.lengths) rprim = unit_vectors(structure.cell).T.flatten() for i in ['natom', 'ntypat', 'znucl', 'typat', 'xcart', 'acell', 'rprim']: self.set_value(i, eval(i))
def center_mass(self, list_of_atoms=None): """ Computes the center of mass (CM) of the XYZ object or a partial list of atoms. The default is to compute the CM of all the atoms in the object, if a list is enter only those in the list will be included for the CM Return the CM as a numpy array """ if list_of_atoms is None: list_of_atoms = range(self.natom) total_mass = 0.0 center_of_mass = np.zeros(3) if self.natom == 0: return center_of_mass atomicnumber = atomic_number(list(self.symbols)) for i in range(self.natom): if i in list_of_atoms: total_mass = total_mass + mass(atomicnumber[i]) center_of_mass = center_of_mass + mass(atomicnumber[i]) * self.positions[i] return center_of_mass / total_mass
def hardness_old(self, noupdate=False, verbose=False, tolerance=0.05): """ Calculates the hardness of a structure based in the model of XX We use the covalent radii from pychemia.utils.periodic. If noupdate=False the Laplacian matrix method is not used and rcut is 2*max(cov_radii) :param noupdate: (bool) If True, the Laplacian method is used :param verbose: (bool) To print some debug info :param tolerance: (float) :rtype : (float) """ superc = self.structure.copy() superc.supercell(2, 2, 2) structure_analisys = StructureAnalysis(superc) natom = superc.natom volume = superc.volume max_covalent_radius = max(covalent_radius(superc.symbols)) if verbose: print('Number of atoms', natom) print('Volume ', volume) print('Covalent rad max', max_covalent_radius) rcut, coord, dis_dic = structure_analisys.get_bonds(2.0 * max_covalent_radius, noupdate, verbose, tolerance) sigma = 3.0 c_hard = 1300.0 x = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 dic_atms = {} for i in superc.symbols: dic_atms[i] = atomic_number(i) for i in dic_atms.keys(): f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) f = 1.0 - (len(dic_atms) * f_n ** (1.0 / len(dic_atms)) / f_d) ** 2 if verbose: print('BONDS') print(dis_dic) print('COORDINATION') print(coord) for i in dis_dic.keys(): i1 = dis_dic[i][2][0] i2 = dis_dic[i][2][1] ei = valence(superc.symbols[i1]) / covalent_radius(superc.symbols[i1]) ej = valence(superc.symbols[i2]) / covalent_radius(superc.symbols[i2]) sij = math.sqrt(ei * ej) / (coord[i1] * coord[i2]) / dis_dic[i][0] tot += dis_dic[i][1] x *= sij * dis_dic[i][1] if verbose: print("V:", volume) print("f:", f) print("x:", x) hardness_value = c_hard / volume * (len(dis_dic) * x ** (1. / (len(dis_dic)))) * math.exp(-sigma * f) if verbose: print(hardness_value) return round(hardness_value, 3)
def hardness(self, verbose=False, initial_cutoff_radius=0.8, ensure_conectivity=False, use_laplacian=True, use_jump=True): """ Calculates the hardness of a structure based in the model of XX We use the covalent radii from pychemia.utils.periodic. If noupdate=False the Laplacian matrix method is not used and rcut is 2*max(cov_radii) :param use_jump: :param ensure_conectivity: :param verbose: (bool) To print some debug info :param initial_cutoff_radius: (float) :param use_laplacian: (bool) If True, the Laplacian method is used :rtype : (float) """ if self._supercell == (1, 1, 1) and verbose: print('''Only internal connectivity can be ensure, for complete connectivity in the crystal you must use a supercell at of (2,2,2)''') bonds, coordination, all_distances, tolerances, cutoff_radius = \ self.get_bonds_coordination(initial_cutoff_radius=initial_cutoff_radius, ensure_conectivity=ensure_conectivity, use_laplacian=use_laplacian, verbose=verbose, use_jump=use_jump) if verbose: print('Structure coordination : ', coordination) sigma = 3.0 c_hard = 1300.0 x = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 atomicnumbers = atomic_number(self.structure.species) if verbose: print('Atomic numbers in the structure :', atomicnumbers) for i in atomicnumbers: f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) # if verbose: # print 'fd', f_d # print 'fn', f_n # print atomicnumbers if f_d == 0: return 0.0 f = 1.0 - (len(atomicnumbers) * f_n ** (1.0 / len(atomicnumbers)) / f_d) ** 2 # Selection of different bonds diff_bonds = np.unique(np.array(reduce(lambda xx, y: xx + y, bonds))) if verbose: print('Number of different bonds : ', len(diff_bonds)) for i in diff_bonds: i1 = all_distances[i]['pair'][0] i2 = all_distances[i]['pair'][1] ei = valence(self.structure.symbols[i1]) / covalent_radius(self.structure.symbols[i1]) ej = valence(self.structure.symbols[i2]) / covalent_radius(self.structure.symbols[i2]) # print 'bond ->', sqrt(ei * ej), (coordination[i1] * coordination[i2]), all_distances[i]['distance'] sij = math.sqrt(ei * ej) / (coordination[i1] * coordination[i2]) / all_distances[i]['distance'] num_i_j_bonds = len([j for j in diff_bonds if i1 in all_distances[j]['pair'] and i2 in all_distances[j]['pair']]) # print 'sij', sij # print 'num_i_j_bonds', num_i_j_bonds tot += num_i_j_bonds x *= sij # print 'x', x vol = self.structure.volume if verbose: print("Structure volume:", vol) # print("f:", f) # print("x:", x) # print 'len_bonds', len(diff_bonds hardness_value = c_hard / vol * (len(diff_bonds) * x ** (1. / (len(diff_bonds)))) * math.exp(-sigma * f) return round(hardness_value, 3), cutoff_radius, coordination
def distance(self, entry_id, entry_jd, rcut=50): """ Return a measure of the distance between two clusters by computing a n-dimensional vector of the distances between each atom to the origin and :param rcut: :param entry_id: The id of one population entry :param entry_jd: The id of another population entry :return: (int) The distance between two clusters """ ids_pair = tuple(np.sort([entry_id, entry_jd])) distance_entry = self.distancer.get_distance(ids_pair) if distance_entry is None: fingerprints = {} for entry_ijd in [entry_id, entry_jd]: if self.fingerprinter.get_fingerprint(entry_ijd) is None: structure = self.get_structure(entry_ijd) analysis = ClusterAnalysis(structure) x, ys = analysis.discrete_radial_distribution_function() fingerprint = {'_id': entry_ijd} for k in ys: atomic_number1 = atomic_number(k[0]) atomic_number2 = atomic_number(k[1]) pair = '%06d' % min( atomic_number1 * 1000 + atomic_number2, atomic_number2 * 1000 + atomic_number1) fingerprint[pair] = list(ys[k]) if self.fingerprinter.get_fingerprint(entry_ijd) is None: self.fingerprinter.set_fingerprint(fingerprint) else: self.fingerprinter.update(entry_ijd, fingerprint) fingerprints[entry_ijd] = fingerprint else: fingerprints[ entry_ijd] = self.fingerprinter.get_fingerprint( entry_ijd) dij = [] for pair in fingerprints[entry_id]: if pair in fingerprints[entry_jd] and pair != '_id': vect1 = fingerprints[entry_id][pair] vect2 = fingerprints[entry_jd][pair] if len(vect1) < len(vect2): tmp = np.zeros(len(vect2)) tmp[:len(vect1)] = vect1 vect1 = tmp elif len(vect1) > len(vect2): tmp = np.zeros(len(vect1)) tmp[:len(vect2)] = vect2 vect2 = tmp uvect1 = unit_vector(vect1) uvect2 = unit_vector(vect2) dij.append(0.5 * (1.0 - np.dot(uvect1, uvect2))) distance = float(np.mean(dij)) self.distancer.set_distance(ids_pair, distance) else: distance = distance_entry['distance'] return distance
def hardness_old(self, noupdate=False, verbose=False, tolerance=0.05): """ Calculates the hardness of a structure based in the model of XX We use the covalent radii from pychemia.utils.periodic. If noupdate=False the Laplacian matrix method is not used and rcut is 2*max(cov_radii) :param noupdate: (bool) If True, the Laplacian method is used :param verbose: (bool) To print some debug info :param tolerance: (float) :rtype : (float) """ superc = self.structure.copy() superc.supercell(2, 2, 2) structure_analisys = StructureAnalysis(superc) natom = superc.natom volume = superc.volume max_covalent_radius = max(covalent_radius(superc.symbols)) if verbose: print('Number of atoms', natom) print('Volume ', volume) print('Covalent rad max', max_covalent_radius) rcut, coord, dis_dic = structure_analisys.get_bonds( 2.0 * max_covalent_radius, noupdate, verbose, tolerance) sigma = 3.0 c_hard = 1300.0 x = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 dic_atms = {} for i in superc.symbols: dic_atms[i] = atomic_number(i) for i in dic_atms.keys(): f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) f = 1.0 - (len(dic_atms) * f_n**(1.0 / len(dic_atms)) / f_d)**2 if verbose: print('BONDS') print(dis_dic) print('COORDINATION') print(coord) for i in dis_dic.keys(): i1 = dis_dic[i][2][0] i2 = dis_dic[i][2][1] ei = valence(superc.symbols[i1]) / covalent_radius( superc.symbols[i1]) ej = valence(superc.symbols[i2]) / covalent_radius( superc.symbols[i2]) sij = math.sqrt(ei * ej) / (coord[i1] * coord[i2]) / dis_dic[i][0] tot += dis_dic[i][1] x *= sij * dis_dic[i][1] if verbose: print("V:", volume) print("f:", f) print("x:", x) hardness_value = c_hard / volume * ( len(dis_dic) * x**(1. / (len(dis_dic)))) * math.exp(-sigma * f) if verbose: print(hardness_value) return round(hardness_value, 3)
def hardness(self, verbose=True, initial_cutoff_radius=0.8, ensure_conectivity=False, use_laplacian=True, use_jump=True, tol=1E-15): """ Calculates the hardness of a structure based in the model of XX We use the covalent radii from pychemia.utils.periodic. If noupdate=False the Laplacian matrix method is not used and rcut is 2*max(cov_radii) :param use_jump: :param ensure_conectivity: :param verbose: (bool) To print some debug info :param initial_cutoff_radius: (float) :param use_laplacian: (bool) If True, the Laplacian method is used :param tol: (float) Tolerance for considering two atoms bonded :rtype : (float) """ if self._supercell == (1, 1, 1) and verbose: print( '''Only internal connectivity can be ensure, for complete connectivity in the crystal you must use a supercell at of (2,2,2)''') bonds, coordination, all_distances, tolerances, cutoff_radius = \ self.get_bonds_coordination(initial_cutoff_radius=initial_cutoff_radius, ensure_conectivity=ensure_conectivity, use_laplacian=use_laplacian, verbose=verbose, use_jump=use_jump, tol=tol) if verbose: print('Structure coordination : ', coordination) sigma = 3.0 c_hard = 1300.0 x = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 atomicnumbers = atomic_number(self.structure.species) if verbose: print('Atomic numbers in the structure :', atomicnumbers) for i in atomicnumbers: f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) # if verbose: # print 'fd', f_d # print 'fn', f_n # print atomicnumbers if f_d == 0: return 0.0 f = 1.0 - (len(atomicnumbers) * f_n**(1.0 / len(atomicnumbers)) / f_d)**2 # Selection of different bonds diff_bonds = np.unique( np.array(functools.reduce(lambda xx, y: xx + y, bonds))) if verbose: print('Number of different bonds : ', len(diff_bonds)) for i in diff_bonds: i1 = all_distances[i]['pair'][0] i2 = all_distances[i]['pair'][1] ei = valence(self.structure.symbols[i1]) / covalent_radius( self.structure.symbols[i1]) ej = valence(self.structure.symbols[i2]) / covalent_radius( self.structure.symbols[i2]) # print 'bond ->', sqrt(ei * ej), (coordination[i1] * coordination[i2]), all_distances[i]['distance'] sij = math.sqrt(ei * ej) / (coordination[i1] * coordination[i2] ) / all_distances[i]['distance'] num_i_j_bonds = len([ j for j in diff_bonds if i1 in all_distances[j]['pair'] and i2 in all_distances[j]['pair'] ]) # print 'sij', sij # print 'num_i_j_bonds', num_i_j_bonds tot += num_i_j_bonds x *= sij # print 'x', x vol = self.structure.volume if verbose: print("Structure volume:", vol) # print("f:", f) # print("x:", x) # print 'len_bonds', len(diff_bonds hardness_value = c_hard / vol * ( len(diff_bonds) * x**(1. / (len(diff_bonds)))) * math.exp(-sigma * f) return round(hardness_value, 3), cutoff_radius, coordination
def hardness(self, noupdate=False, verbose=False, tolerance=1): """ Calculates the hardness of a structure based in the model of XX We use the covalent radii from pychemia.utils.periodic. If noupdate=False the Laplacian matrix method is not used and rcut is 2*max(cov_radii) :param noupdate: (bool) If True, the Laplacian method is used :param verbose: (bool) To print some debug info :param tolerance: (float) :rtype : (float) """ bonds, coordination, all_distances, tolerances = self.get_bonds_coordination(tolerance=tolerance, ensure_conectivity=True) if verbose: print 'BONDS' print bonds print 'COORDINATION' print coordination sigma = 3.0 c_hard = 1300.0 x = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 atomicnumbers = atomic_number(self.get_composition().species) if verbose: print atomicnumbers for i in atomicnumbers: f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) f = 1.0 - (len(atomicnumbers) * f_n ** (1.0 / len(atomicnumbers)) / f_d) ** 2 # Selection of different bonds diff_bonds = _np.unique(_np.array(reduce(lambda x, y: x+y, bonds))) for i in diff_bonds: i1 = all_distances[i]['pair'][0] i2 = all_distances[i]['pair'][1] ei = valence(self.symbols[i1]) / covalent_radius(self.symbols[i1]) ej = valence(self.symbols[i2]) / covalent_radius(self.symbols[i2]) #print 'bond ->', sqrt(ei * ej), (coordination[i1] * coordination[i2]), all_distances[i]['distance'] sij = sqrt(ei * ej) / (coordination[i1] * coordination[i2]) / all_distances[i]['distance'] num_i_j_bonds = len([j for j in diff_bonds if i1 in all_distances[j]['pair'] and i2 in all_distances[j]['pair']]) #print 'sij', sij #print 'num_i_j_bonds', num_i_j_bonds tot += num_i_j_bonds x *= sij #print 'x', x if verbose: print("V:", self.volume) print("f:", f) print("x:", x) #print 'len_bonds', len(diff_bonds) #print 'hardness_value =', c_hard, self.volume, (len(diff_bonds)), ( x ** (1. / (len(diff_bonds)))), exp(-sigma * f) hardness_value = c_hard / self.volume * (len(diff_bonds) * x ** (1. / (len(diff_bonds)))) * exp(-sigma * f) if verbose: print hardness_value return round(hardness_value, 3)
def worker(db_settings, entry_id, workdir, target_forces, relaxator_params): pcdb = get_database(db_settings) pcm_log.info('[%s]: Starting relaxation. Target forces: %7.3e' % (str(entry_id), target_forces)) if pcdb.is_locked(entry_id): return else: pcdb.lock(entry_id) structure = pcdb.get_structure(entry_id) structure = structure.scale() print('relaxator_params', relaxator_params) relaxer = IonRelaxation(structure, workdir=workdir, target_forces=target_forces, waiting=False, binary=relaxator_params['binary'], encut=1.3, kp_grid=None, kp_density=1E4, relax_cell=True, max_calls=10) print('relaxing on:', relaxer.workdir) relaxer.run(relaxator_params['nmpiparal']) pcm_log.info('[%s]: Finished relaxation. Target forces: %7.3e' % (str(entry_id), target_forces)) filename = workdir + os.sep + 'OUTCAR' if os.path.isfile(filename): forces, stress, total_energy = relaxer.get_forces_stress_energy() if forces is not None: magnitude_forces = np.apply_along_axis(np.linalg.norm, 1, forces) print('Forces: Max: %9.3e Avg: %9.3e' % (np.max(magnitude_forces), np.average(magnitude_forces))) print('Stress: ', np.max(np.abs(stress.flatten()))) if forces is None: pcm_log.error('No forces found on %s' % filename) if stress is None: pcm_log.error('No stress found on %s' % filename) if total_energy is None: pcm_log.error('No total_energy found on %s' % filename) new_structure = relaxer.get_final_geometry() if forces is not None and stress is not None and total_energy is not None and new_structure is not None: pcm_log.info('[%s]: Updating properties' % str(entry_id)) pcdb.update(entry_id, structure=new_structure) te = total_energy pcdb.entries.update({'_id': entry_id}, { '$set': { 'status.relaxation': 'succeed', 'status.target_forces': target_forces, 'properties.forces': generic_serializer(forces), 'properties.stress': generic_serializer(stress), 'properties.energy': te, 'properties.energy_pa': te / new_structure.natom, 'properties.energy_pf': te / new_structure.get_composition().gcd } }) # Fingerprint # Update the fingerprints only if the two structures are really different diffnatom = structure.natom != new_structure.natom diffcell = np.max( np.abs((structure.cell - new_structure.cell).flatten())) diffreduced = np.max( np.abs((structure.reduced - new_structure.reduced).flatten())) if diffnatom != 0 or diffcell > 1E-7 or diffreduced > 1E-7: analysis = StructureAnalysis(new_structure, radius=50) x, ys = analysis.fp_oganov(delta=0.01, sigma=0.01) fingerprint = {'_id': entry_id} for k in ys: atomic_number1 = atomic_number(new_structure.species[k[0]]) atomic_number2 = atomic_number(new_structure.species[k[1]]) pair = '%06d' % min(atomic_number1 * 1000 + atomic_number2, atomic_number2 * 1000 + atomic_number1) fingerprint[pair] = list(ys[k]) if pcdb.db.fingerprints.find_one({'_id': entry_id}) is None: pcdb.db.fingerprints.insert(fingerprint) else: pcdb.db.fingerprints.update({'_id': entry_id}, fingerprint) else: pcm_log.debug('Original and new structures are very similar.') pcm_log.debug('Max diff cell: %10.3e' % np.max( np.absolute( (structure.cell - new_structure.cell).flatten()))) if structure.natom == new_structure.natom: pcm_log.debug( 'Max diff reduced coordinates: %10.3e' % np.max( np.absolute((structure.reduced - new_structure.reduced).flatten()))) else: pcdb.entries.update({'_id': entry_id}, {'$set': { 'status.relaxation': 'failed' }}) pcm_log.error( 'Bad data after relaxation. Tagging relaxation as failed') else: pcm_log.error('ERROR: File not found %s' % filename) pcm_log.info('[%s]: Unlocking the entry' % str(entry_id)) pcdb.unlock(entry_id)
def worker(db_settings, entry_id, workdir, target_forces, relaxator_params): pcdb = get_database(db_settings) pcm_log.info('[%s]: Starting relaxation. Target forces: %7.3e' % (str(entry_id), target_forces)) if pcdb.is_locked(entry_id): return else: pcdb.lock(entry_id) structure = pcdb.get_structure(entry_id) structure = structure.scale() print('relaxator_params', relaxator_params) relaxer = IonRelaxation2(structure, workdir=workdir, target_forces=target_forces, waiting=False, binary=relaxator_params['binary'], encut=1.3, kp_grid=None, kp_density=1E4, relax_cell=True) print('relaxing on:', relaxer.workdir) relaxer.run(relaxator_params['nmpiparal']) pcm_log.info('[%s]: Finished relaxation. Target forces: %7.3e' % (str(entry_id), target_forces)) filename = workdir + os.sep + 'OUTCAR' if os.path.isfile(filename): forces, stress, total_energy = relaxer.get_forces_stress_energy() if forces is not None: magnitude_forces = np.apply_along_axis(np.linalg.norm, 1, forces) print('Forces: Max: %9.3e Avg: %9.3e' % (np.max(magnitude_forces), np.average(magnitude_forces))) print('Stress: ', np.max(np.abs(stress.flatten()))) if forces is None: pcm_log.error('No forces found on %s' % filename) if stress is None: pcm_log.error('No stress found on %s' % filename) if total_energy is None: pcm_log.error('No total_energy found on %s' % filename) new_structure = relaxer.get_final_geometry() if forces is not None and stress is not None and total_energy is not None and new_structure is not None: pcm_log.info('[%s]: Updating properties' % str(entry_id)) pcdb.update(entry_id, structure=new_structure) te = total_energy pcdb.entries.update({'_id': entry_id}, {'$set': {'status.relaxation': 'succeed', 'status.target_forces': target_forces, 'properties.forces': generic_serializer(forces), 'properties.stress': generic_serializer(stress), 'properties.energy': te, 'properties.energy_pa': te / new_structure.natom, 'properties.energy_pf': te / new_structure.get_composition().gcd}}) # Fingerprint # Update the fingerprints only if the two structures are really different diffnatom = structure.natom != new_structure.natom diffcell = np.max(np.abs((structure.cell - new_structure.cell).flatten())) diffreduced = np.max(np.abs((structure.reduced - new_structure.reduced).flatten())) if diffnatom != 0 or diffcell > 1E-7 or diffreduced > 1E-7: analysis = StructureAnalysis(new_structure, radius=50) x, ys = analysis.fp_oganov(delta=0.01, sigma=0.01) fingerprint = {'_id': entry_id} for k in ys: atomic_number1 = atomic_number(new_structure.species[k[0]]) atomic_number2 = atomic_number(new_structure.species[k[1]]) pair = '%06d' % min(atomic_number1 * 1000 + atomic_number2, atomic_number2 * 1000 + atomic_number1) fingerprint[pair] = list(ys[k]) if pcdb.db.fingerprints.find_one({'_id': entry_id}) is None: pcdb.db.fingerprints.insert(fingerprint) else: pcdb.db.fingerprints.update({'_id': entry_id}, fingerprint) else: pcm_log.debug('Original and new structures are very similar.') pcm_log.debug('Max diff cell: %10.3e' % np.max(np.absolute((structure.cell - new_structure.cell).flatten()))) if structure.natom == new_structure.natom: pcm_log.debug('Max diff reduced coordinates: %10.3e' % np.max(np.absolute((structure.reduced - new_structure.reduced).flatten()))) else: pcdb.entries.update({'_id': entry_id}, {'$set': {'status.relaxation': 'failed'}}) pcm_log.error('Bad data after relaxation. Tagging relaxation as failed') else: pcm_log.error('ERROR: File not found %s' % filename) pcm_log.info('[%s]: Unlocking the entry' % str(entry_id)) pcdb.unlock(entry_id)
def species_bin(self): spec_bin = 0 for i in atomic_number(self.species): spec_bin += 2 ** i return spec_bin
def hardness_OLD(self, noupdate=False, verbose=False, tolerance=0.05): """ Calculates the hardness of a structure based in the model of XX We use the covalent radii from pychemia.utils.periodic. If noupdate=False the Laplacian matrix method is not used and rcut is 2*max(cov_radii) :param noupdate: (bool) If True, the Laplacian method is used :param verbose: (bool) To print some debug info :param tolerance: (float) :rtype : (float) """ #from ase.data import covalent_radii #atms=atms.repeat([2,2,2]) spc = self.copy() spc.supercell(2, 2, 2) natom = spc.natom volume = spc.volume #max_covalent_radius = max([covalent_radii[i.number] for i in atms]) max_covalent_radius = max(covalent_radius(spc.symbols)) if verbose: print('Number of atoms', natom) print('Volume ', volume) print('Covalent rad max', max_covalent_radius) #rcut, coord, dis_dic = get_bonds(atms,2.0*max_covalent_radius, noupdate,verbose,tolerance) rcut, coord, dis_dic = spc.get_bonds(2.0 * max_covalent_radius, noupdate, verbose, tolerance) sigma = 3.0 c_hard = 1300.0 x = 1. tot = 0.0 f_d = 0.0 f_n = 1.0 dic_atms = {} #for i in atms: # dic_atms[i.symbol] = i.number for i in spc.symbols: dic_atms[i] = atomic_number(i) #for i in dic_atms.keys(): # f_d += Z[i] / covalent_radii[dic_atms[i]] # f_n *= Z[i] / covalent_radii[dic_atms[i]] #f = 1.0 - (len(dic_atms)*f_n**(1.0/len(dic_atms)) / f_d)**2 for i in dic_atms.keys(): f_d += valence(i) / covalent_radius(i) f_n *= valence(i) / covalent_radius(i) f = 1.0 - (len(dic_atms) * f_n ** (1.0 / len(dic_atms)) / f_d) ** 2 if verbose: print 'BONDS' print dis_dic print 'COORDINATION' print coord for i in dis_dic.keys(): i1 = dis_dic[i][2][0] i2 = dis_dic[i][2][1] #ei = Z[atms[i1].symbol] / covalent_radii[atms[i1].number] #ej = Z[atms[i2].symbol] / covalent_radii[atms[i2].number] ei = valence(spc.symbols[i1]) / covalent_radius(spc.symbols[i1]) ej = valence(spc.symbols[i2]) / covalent_radius(spc.symbols[i2]) #print 'bond ->', sqrt(ei * ej), (coord[i1] * coord[i2]), dis_dic[i][0] # print atms[i1].symbol, ei, atms[i2].symbol, ej sij = sqrt(ei * ej) / (coord[i1] * coord[i2]) / dis_dic[i][0] #print 'sij', sij #print 'num_i_j_bonds', dis_dic[i][1] tot += dis_dic[i][1] x *= sij * dis_dic[i][1] #print 'x', x if verbose: print("V:", volume) print("f:", f) print("x:", x) #print 'len_bonds', len(dis_dic) #print 'hardness_value =', c_hard, volume, (len(dis_dic)), ( x ** (1. / (len(dis_dic)))), exp(-sigma * f) hardness_value = c_hard / volume * (len(dis_dic) * x ** (1. / (len(dis_dic)))) * exp(-sigma * f) if verbose: print hardness_value return round(hardness_value, 3)