def random_cell(composition): comp = Composition(composition) volume = comp.covalent_volume(packing='cubes') random.seed() # make 3 random lengths a = (1.0 + 0.5 * random.random()) b = (1.0 + 0.5 * random.random()) c = (1.0 + 0.5 * random.random()) # now we make 3 random angles alpha = 60.0 + 60.0 * random.random() beta = 60.0 + 60.0 * random.random() gamma = 60.0 + 60.0 * random.random() lattice = Lattice().from_parameters_to_cell(a, b, c, alpha, beta, gamma) factor = (volume / lattice.volume)**(1 / 3.0) lattice = Lattice().from_parameters_to_cell(factor * a, factor * b, factor * c, alpha, beta, gamma) lattice.align_with_axis() lattice.align_with_plane() return lattice
def random_cell(composition): comp = Composition(composition) volume = comp.covalent_volume(packing='cubes') random.seed() # make 3 random lengths a = (1.0 + 0.5 * random.random()) b = (1.0 + 0.5 * random.random()) c = (1.0 + 0.5 * random.random()) # now we make 3 random angles alpha = 60.0 + 60.0 * random.random() beta = 60.0 + 60.0 * random.random() gamma = 60.0 + 60.0 * random.random() lattice = Lattice().from_parameters_to_cell(a, b, c, alpha, beta, gamma) factor = (volume / lattice.volume) ** (1 / 3.0) lattice = Lattice().from_parameters_to_cell(factor * a, factor * b, factor * c, alpha, beta, gamma) lattice.align_with_axis() lattice.align_with_plane() return lattice
def get_composition(self, gcd=True): """ Computes the composition of the Structure as the count of each species in the cell If gcd is True the values are divided by the greatest common divisor :param gcd: bool :rtype : Composition """ if self._composition is None: species = {} for atom in self.symbols: if atom in species: species[atom] += 1 else: species[atom] = 1 self._composition = Composition(species) return self._composition
def testraise(self): """ Test exceptions in Composition : """ a = Composition('H2O') self.assertRaises(ValueError, a.covalent_volume, 'torus')
def random_cell(composition, method='stretching', stabilization_number=20, nparal=5, periodic=True): """ Generate a random cell There are two algorithms implemented: scaling: Generate a random cell and random distribution of atoms and scale the lattice to separate the atoms. stretching: Generating a random cell and random distribution of atoms and stretching their bonds until the distance between any two atoms is always greater than the sum of covalent radius. :param composition: (pychemia.Composition) :param method: (str) :param stabilization_number: (int) :param nparal: (int) :param periodic: (bool) :return: Examples: >>> import pychemia >>> import os >>> st = pychemia.Structure.random_cell('LiAlCl4', stabilization_number=3) >>> st.natom 6 >>> st.save_json('test.json') >>> st2 = pychemia.Structure.load_json('test.json') >>> st == st2 True >>> os.remove('test.json') """ comp = Composition(composition) pcm_log.debug('Generating a random structure with composition: ' + str(comp.composition)) natom = comp.natom symbols = comp.symbols best_volume = sys.float_info.max best_volume = float('inf') best_structure = None optimal_volume = comp.covalent_volume('cubes') stabilization_history = 0 pool = Pool(processes=nparal) trial = 0 while stabilization_history < stabilization_number: args = list(best_volume * np.ones(10)) ret = pool.map(worker_star, zip(repeat(method), repeat(composition), repeat(periodic), args)) ngood = 0 for structure in ret: if structure is not None: ngood += 1 if best_structure is not None: if structure.volume < best_structure.volume: best_structure = structure else: best_structure = structure # log.debug('Good structures: %d/10 Best volume: %7.3f' % (ngood, best_structure.volume)) if best_structure is not None and best_volume > best_structure.volume: best_volume = best_structure.volume stabilization_history = 0 else: stabilization_history += 1 trial += 1 # log.debug('Trial: %4d Volume: %7.2f Optimal Volume: %7.2f Ratio: %5.2f' % # (trial, best_volume, optimal_volume, best_volume/optimal_volume)) pool.close() if best_structure is not None and periodic: # Analysis of the quality for the best structure rpos = best_structure.reduced for i, j in combinations(range(natom), 2): distance = best_structure.lattice.minimal_distance(rpos[i], rpos[j]) covalent_distance = sum(covalent_radius([symbols[i], symbols[j]])) if distance < covalent_distance: pcm_log.debug('Covalent distance: %7.4f Minimal distance: %7.4f Difference: %7.3e' % (covalent_distance, distance, covalent_distance - distance)) best_structure.canonical_form() return best_structure
def random_cell(composition, method='stretching', stabilization_number=20, nparal=5, periodic=True): """ Generate a random cell There are two algorithms implemented: scaling: Generate a random cell and random distribution of atoms and scale the lattice to separate the atoms. stretching: Generating a random cell and random distribution of atoms and stretching their bonds until the distance between any two atoms is always greater than the sum of covalent radius. :param composition: (pychemia.Composition) :param method: (str) :param stabilization_number: (int) :param nparal: (int) :param periodic: (bool) :return: Examples: >>> import pychemia >>> import os >>> st = pychemia.Structure.random_cell('LiAlCl4', stabilization_number=3) >>> st.natom 6 >>> st.save_json('test.json') >>> st2 = pychemia.Structure.load_json('test.json') >>> st == st2 True >>> os.remove('test.json') """ comp = Composition(composition) pcm_log.debug('Generating a random structure with composition: ' + str(comp.composition)) natom = comp.natom symbols = comp.symbols best_volume = sys.float_info.max best_volume = float('inf') best_structure = None optimal_volume = comp.covalent_volume('cubes') stabilization_history = 0 pool = Pool(processes=nparal) trial = 0 while stabilization_history < stabilization_number: args = list(best_volume * np.ones(10)) ret = pool.map( worker_star, zip(repeat(method), repeat(composition), repeat(periodic), args)) ngood = 0 for structure in ret: if structure is not None: ngood += 1 if best_structure is not None: if structure.volume < best_structure.volume: best_structure = structure else: best_structure = structure # log.debug('Good structures: %d/10 Best volume: %7.3f' % (ngood, best_structure.volume)) if best_structure is not None and best_volume > best_structure.volume: best_volume = best_structure.volume stabilization_history = 0 else: stabilization_history += 1 trial += 1 # log.debug('Trial: %4d Volume: %7.2f Optimal Volume: %7.2f Ratio: %5.2f' % # (trial, best_volume, optimal_volume, best_volume/optimal_volume)) pool.close() if best_structure is not None and periodic: # Analysis of the quality for the best structure rpos = best_structure.reduced for i, j in combinations(range(natom), 2): distance = best_structure.lattice.minimal_distance( rpos[i], rpos[j]) covalent_distance = sum( covalent_radius([symbols[i], symbols[j]])) if distance < covalent_distance: pcm_log.debug( 'Covalent distance: %7.4f Minimal distance: %7.4f Difference: %7.3e' % (covalent_distance, distance, covalent_distance - distance)) best_structure.canonical_form() return best_structure
def random_structure(method, composition, periodic=True, best_volume=1E10): comp = Composition(composition) natom = comp.natom symbols = comp.symbols np.random.seed(struct.unpack("<L", os.urandom(4))[0]) if periodic: new_structure = None assert (method in ['scaling', 'stretching']) if method == 'scaling': lattice = Lattice.random_cell(comp) # Random reduced positions rpos = np.random.rand(natom, 3) mins = [min(rpos[:, i]) for i in range(3)] rpos -= mins new_lattice = lattice.scale(symbols, rpos, tolerance=1.0) else: lattice = Lattice.random_cell(comp) # Random reduced positions rpos = np.random.rand(natom, 3) mins = [min(rpos[:, i]) for i in range(3)] rpos -= mins new_lattice = lattice.stretch(symbols, rpos, tolerance=1.0, extra=0.1) if new_lattice.volume < best_volume: test = True for i in range(natom): for j in range(i + 1, natom): distance = new_lattice.minimal_distance(rpos[i], rpos[j]) covalent_dim = sum( covalent_radius([symbols[i], symbols[j]])) if distance < covalent_dim: test = False if test: new_structure = Structure(symbols=symbols, reduced=rpos, cell=new_lattice.cell, periodicity=True) else: new_structure = None else: pos = np.random.rand(natom, 3) mindis = cluster_minimal_distance(pos) if mindis == 0: raise ValueError("Distance too small") max_cov = np.max(covalent_radius(symbols)) pos *= max_cov / mindis current_volume = (max(pos[:, 0]) - min(pos[:, 0])) * (max( pos[:, 1]) - min(pos[:, 1])) * (max(pos[:, 2]) - min(pos[:, 2])) if current_volume < best_volume: new_structure = Structure(symbols=symbols, positions=pos, periodicity=False) else: new_structure = None return new_structure
def random_structure(method, composition, periodic=True, max_volume=1E10): """ Random Structure created by random positioning of atoms followed by either scaling of the cell or adding a sheer stretching along the smaller distances. The purpose of the lattice change is to avoid any two atoms to be closer than the sum of their covalent radius. :param method: Can be 'stretching' or 'scaling'. :param composition: Can be a Composition object or formula. :param periodic: If True, the structure will be periodical in all directions, otherwise a finite system is created. :param max_volume: Threshold for creating the Structure, if the volume exceeds the target the method returns None :return: Structure if the volume is below than best_volume, None otherwise >>> st = random_structure(method='scaling', composition='H2O', periodic=False) >>> st.natom 3 >>> st = random_structure(method='stretching', composition='NaCl', periodic=True) >>> st.natom 2 """ comp = Composition(composition) natom = comp.natom symbols = comp.symbols np.random.seed(struct.unpack("<L", os.urandom(4))[0]) if periodic: new_structure = None assert (method in ['scaling', 'stretching']) while True: trial = 0 if method == 'scaling': lattice = Lattice.random_cell(comp) # Random reduced positions rpos = np.random.rand(natom, 3) mins = [min(rpos[:, i]) for i in range(3)] rpos -= mins new_lattice = lattice else: lattice = Lattice.random_cell(comp) # Random reduced positions rpos = np.random.rand(natom, 3) mins = [min(rpos[:, i]) for i in range(3)] rpos -= mins new_lattice = lattice.stretch(symbols, rpos, tolerance=1.0, extra=0.1) if new_lattice.volume < max_volume: test = True for i in range(natom): for j in range(i + 1, natom): distance = new_lattice.minimal_distance( rpos[i], rpos[j]) covalent_dim = sum( covalent_radius([symbols[i], symbols[j]])) if distance < covalent_dim: test = False if test: new_structure = Structure(symbols=symbols, reduced=rpos, cell=new_lattice.cell, periodicity=True) minimal_distance = np.min(new_structure.distance_matrix() + 10 * np.eye(new_structure.natom)) break else: print( "Trial failed, distance %f is less than covalent radious %f" % (distance, covalent_dim)) trial += 1 if trial > 100: print("Leaving after 100 attemps") break # else: # print('Volume of Structure %f is larger than max_volume=%f' % (new_lattice.volume, max_volume)) # new_structure = None else: pos = np.random.rand(natom, 3) mindis = cluster_minimal_distance(pos) if mindis == 0: raise ValueError("Distance too small") max_cov = np.max(covalent_radius(symbols)) pos *= max_cov / mindis current_volume = (max(pos[:, 0]) - min(pos[:, 0])) * (max( pos[:, 1]) - min(pos[:, 1])) * (max(pos[:, 2]) - min(pos[:, 2])) if current_volume < max_volume: new_structure = Structure(symbols=symbols, positions=pos, periodicity=False) else: print('Volume of Structure %f is larger than max_volume=%f' % (current_volume, max_volume)) new_structure = None return new_structure