def bcc_grains(size, perturbation=0.0): "Creates a grain layout based on a perturbed BCC lattice." graincenters = BodyCenteredCubic(symbol='H', latticeconstant=1.0, size=size) graincenters = graincenters.get_positions() + 0.25 graincenters /= size pert = np.random.standard_normal(graincenters.shape) * perturbation graincenters += pert rotations = [random_rot() for g in graincenters] return graincenters, rotations
from ase.lattice.cubic import BodyCenteredCubic import numpy as np bulk = BodyCenteredCubic(directions=[[1,0,0], [0,1,0], [0,0,1]], size=(2,2,2), latticeconstant=2.87, symbol='Fe') newbasis = 2.87*np.array([[-0.5, 0.5, 0.5], [0.5, -0.5, 0.5], [0.5, 0.5, -0.5]]) pos = bulk.get_positions() s = np.dot(np.linalg.inv(newbasis.T), pos.T).T print('atom positions in primitive basis') print(s) # let us see the unit cell in terms of the primitive basis too print('unit cell in terms of the primitive basis') print(np.dot(np.linalg.inv(newbasis.T), bulk.get_cell().T).T)
from ase.lattice.cubic import BodyCenteredCubic import numpy as np bulk = BodyCenteredCubic(directions=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], size=(2, 2, 2), latticeconstant=2.87, symbol='Fe') newbasis = 2.87 * np.array([[-0.5, 0.5, 0.5], [0.5, -0.5, 0.5], [0.5, 0.5, -0.5]]) pos = bulk.get_positions() s = np.dot(np.linalg.inv(newbasis.T), pos.T).T print 'atom positions in primitive basis' print s #let us see the unit cell in terms of the primitive basis too print 'unit cell in terms of the primitive basis' print np.dot(np.linalg.inv(newbasis.T), bulk.get_cell().T).T
def build_emitter_from_scratch(element, basis, z_axis, filename="emitter.txt", x_axis="auto", y_axis="auto", emitter_radius=100, emitter_side_height=50, vacuum_radius=25, alloy={}): """ Build an emitter (set of nodes, TAPSim style) based on an element, basis, orientation, and dimensions. """ IDS = {element: "10"} if x_axis == "auto" and y_axis == "auto": if 0.99 < np.dot(z_axis, (1, 0, 0)) < 1.01: x_axis = tuple(np.cross(z_axis, (1, 0, 0))) else: x_axis = tuple(np.cross(z_axis, (0, 1, 0))) y_axis = tuple(np.cross(z_axis, x_axis)) R = emitter_radius + vacuum_radius if basis.lower() == "bcc": lattice = BodyCenteredCubic( size=(1, 1, 1), directions=[x_axis, y_axis, z_axis], symbol=element ) pts = lattice.get_positions() supercell_dimensions = ( int(math.ceil((2*R)/max([pt[0] for pt in pts])))+1, int(math.ceil((2*R)/max([pt[1] for pt in pts])))+1, int(math.ceil((emitter_side_height+R)/max([pt[2] for pt in pts])))+1 ) lattice = BodyCenteredCubic( size=supercell_dimensions, directions=[x_axis, y_axis, z_axis], symbol=element ) elif basis.lower() == "fcc": lattice = FaceCenteredCubic( size=(1, 1, 1), directions=[x_axis, y_axis, z_axis], symbol=element ) pts = lattice.get_positions() supercell_dimensions = ( int(math.ceil((2*R)/max([pt[0] for pt in pts])))+1, int(math.ceil((2*R)/max([pt[1] for pt in pts])))+1, int(math.ceil((emitter_side_height+R)/max([pt[2] for pt in pts])))+1 ) lattice = FaceCenteredCubic( size=supercell_dimensions, directions=[x_axis, y_axis, z_axis], symbol=element ) elif basis.lower() == "sc": lattice = SimpleCubic( size=(1, 1, 1), directions=[x_axis, y_axis, z_axis], symbol=element ) pts = lattice.get_positions() supercell_dimensions = ( int(math.ceil((2*R)/max([pt[0] for pt in pts])))+1, int(math.ceil((2*R)/max([pt[1] for pt in pts])))+1, int(math.ceil((emitter_side_height+R)/max([pt[2] for pt in pts])))+1 ) lattice = SimpleCubic( size=supercell_dimensions, directions=[x_axis, y_axis, z_axis], symbol=element ) pts = lattice.get_positions() cx = np.mean([pt[0] for pt in pts]) cy = np.mean([pt[1] for pt in pts]) min_z = min([pt[2] for pt in pts]) emitter_points, vacuum_points, bottom_points = [], [], [] number = 0 for pt in pts: pt = [pt[0], pt[1], pt[2]-min_z] if (pt[2] < 1e-5 and (pt[0]-cx)**2+(pt[1]-cy)**2<R**2): pt = [pt[0], pt[1], 0.0] pt = [i*1e-10 for i in pt] pt.append(2) # bottom ID number += 1 bottom_points.append(pt) elif (pt[2]<emitter_side_height and (pt[0]-cx)**2+(pt[1]-cy)**2\ <emitter_radius**2): pt = [i*1e-10 for i in pt] pt.append(IDS[element]) # emitter ID number += 1 emitter_points.append(pt) elif (pt[0]-cx)**2+(pt[1]-cy)**2+(pt[2]-emitter_side_height)**2\ <emitter_radius**2: pt = [i*1e-10 for i in pt] pt.append(IDS[element]) # emitter ID number += 1 emitter_points.append(pt) elif (pt[2]<emitter_side_height and (pt[0]-cx)**2+(pt[1]-cy)**2<R**2): pt = [i*1e-10 for i in pt] pt.append(0) # vacuum ID number += 1 vacuum_points.append(pt) elif (pt[0]-cx)**2+(pt[1]-cy)**2+(pt[2]-emitter_side_height)**2<R**2: pt = [i*1e-10 for i in pt] pt.append(0) # vacuum ID number += 1 vacuum_points.append(pt) alloy_id = 20 all_substitution_indices = [] for elt in alloy: substitution_indices = [] conc = alloy[elt] num_atoms = len(emitter_points) num_substitution_atoms = math.floor(conc*num_atoms) j = 0 while j < num_substitution_atoms: x = randint(0, num_atoms-1) if x not in all_substitution_indices: substitution_indices.append(x) all_substitution_indices.append(x) j += 1 for i in substitution_indices: emitter_points[i][3] = alloy_id IDS[elt] = str(alloy_id) alloy_id += 10 with open(filename, "w") as e: n_nodes = number e.write("ASCII {} 0 0\n".format(n_nodes)) for pt in emitter_points + vacuum_points + bottom_points: # It's required that the coordinates be # separated by a tab character (^I), not # by regular spaces. e.write(" ".join([str(i) for i in pt])) e.write("\n") comment = ["#"] comment += [" {}={}".format(IDS[elt], elt) for elt in IDS] e.write("{}\n".format(" ".join(comment)))
class System(): def __init__(self, setting): self.setting = setting self.elsProps = [] # elements properties self.setting['nAt'] = [] # number of atoms per specie self.px = self.setting['period'][0] self.py = self.setting['period'][1] self.pz = self.setting['period'][2] self.a0 = self.setting['a'] self.box =[[0, self.px*self.a0],\ [0,self.py*self.a0],\ [0,self.pz*self.a0]] self.setElsProps() self.setCrystal() if self.setting['positions'] == 'rnd': self.setRandomStructure() self.setNumbers() self.bulk.set_atomic_numbers(self.numbers) def setNumbers(self): self.numbers = [] for e in self.t1_: self.numbers.append( self.elsProps[e - 1]['number']) def setElsProps(self): for e in self.setting['elements']: a = ase.Atom(e) mass = a.mass / _Nav number = a.number form = pt.formula(a.symbol) e_ = form.structure[0][1] crys = e_.crystal_structure['symmetry'] a_ = e_.crystal_structure['a'] self.elsProps.append({'ase':a, 'mass': mass, 'structure': crys, 'a':a_ , 'number':number}) def setCrystal(self): crys = self.setting['structure'] if crys == 'rnd': print 'rnd implemented' self.genRandomPositions() d = 1.104 # N2 bondlength formula = 'Cu'+str(len(self.pos)) cell =[(self.px*self.a0,0,0),(0,self.py*self.a0,0),(0,0,self.pz*self.a0)] self.bulk = ase.Atoms(formula, self.pos, pbc=True, cell=cell) if crys == 'fcc': print 'fcc implemented' from ase.lattice.cubic import FaceCenteredCubic self.bulk = FaceCenteredCubic(directions=[[1,0,0], [0,1,0], [0,0,1]], size=(self.px,self.py,self.pz), symbol='Cu', pbc=(1,1,1), latticeconstant=self.a0) if crys == 'bcc': print 'bcc implemented' from ase.lattice.cubic import BodyCenteredCubic self.bulk = BodyCenteredCubic(directions=[[1,0,0], [0,1,0], [0,0,1]], size=(self.px,self.py,self.pz), symbol='Cu', pbc=(1,1,1), latticeconstant=self.a0) if self.setting['structure'] == 'hcp': print 'hcp no implemented' sys.exit(0) self.setting['nAtoms'] = self.bulk.get_number_of_atoms() self.calcAtoms2() self.genStructure() self.pos = self.bulk.get_positions() def update (self): cell = self.bulk.get_cell() self.box =[[0, cell[0][0]],[0, cell[1][1]],[0, cell[2][2]]] self.pos = self.bulk.get_positions() def genStructure(self): self.t1_ = [] for i,e in enumerate(self.setting['nAt']): [self.t1_.append(i+1) for j in range(e)] def setRandomStructure(self): x = [int(random.random()*len(self.t1_)) for i in range(len(self.t1_))] for i in range(len(x) - 1): t1 = self.t1_[x[i]] t2 = self.t1_[x[i+1]] self.t1_[x[i]] = t2 self.t1_[x[i+1]] = t1 return self.pos, self.t1_, self.box def genRandomPositions(self): Lx = self.box[0][1] Ly = self.box[1][1] Lz = self.box[2][1] self.pos =[] for i in range(self.setting['nAtoms']): x = random.random() * Lx y = random.random() * Ly z = random.random() * Lz self.pos.append([x,y,z]) def getAtoms(self): return self.elsProps def Interaction (self): if self.setting['pot'] == 'lj': ljp = ljParameters.LjParameters() str_ = ljp.lammpsInteraction(self.elsProps) if self.setting['pot'] == 'zhou': gz = zhou.calcPotentials(self.setting['elements']) gz.createPot() str_ = gz.lammpsZhouEam() return str_ def calcAtoms2(self): nAt = [] sum_ = 0 sumpc = 0.0000001 len_elements = len(self.setting['elements']) len_pca = len(self.setting['pca']) print 'calcAtom2', len_pca, len_elements if len_elements != len_pca + 1: print 'error len' sys.exit(0) for p in self.setting['pca']: sumpc +=p if sumpc >= 100 or sumpc <= 0: print 'error pc' sys.exit(0) sumpc = 0 for i in range(len(self.setting['elements']) - 1): p = self.setting['pca'][i] sumpc +=p t = int(p * self.setting['nAtoms'] / 100.0) sum_ +=t nAt.append(t) nAt.append(self.setting['nAtoms'] - sum_) self.setting['nAtoms'] = 0 for e in nAt: self.setting['nAtoms'] +=e print 'pca', self.setting['pca'] self.setting['nAt'] = nAt def getMasess(self): str_ ='' i = 1 for e in self.elsProps: str_ += 'mass ' + str(i) + ' ' +str(e['mass']) + '\n' i+=1 return str_