def getInitialStructure(self, verbose=True): """ read initial structure """ # read initial pos fxml = open(self.xmlFile, "r") structure = myxml.getBlocs("structure", fxml, {"name": "initialpos"}, True) fxml.close() # read lattice vectors latticeParam = myxml.getBlocs("varray", structure, {"name": "basis"}, True) veca = [float(val) for val in myxml.getNodeData(latticeParam[1])] vecb = [float(val) for val in myxml.getNodeData(latticeParam[2])] vecc = [float(val) for val in myxml.getNodeData(latticeParam[3])] # crystal object self.initialStructure = Crystal(veca = veca, vecb = vecb, vecc = vecc, \ name = "Initial structure : {0}".format(self.xmlFile)) # print lattice parameters if verbose: print("\t* a = %10.5f \t* alpha = %10.3f" % \ (self.initialStructure.a, self.initialStructure.alpha)) print("\t* b = %10.5f \t* beta = %10.3f" % \ (self.initialStructure.b, self.initialStructure.beta) ) print("\t* c = %10.5f \t* gamma = %10.3f" % \ (self.initialStructure.c, self.initialStructure.gamma)) # read reduce coordinates and compute cartesian coordinates positions = myxml.getBlocs("varray", structure, {"name": "positions"}, True) self.initialStructure.Natoms = 0 for ligne in positions[1:-1]: pos = [float(val) for val in myxml.getNodeData(ligne)] self.initialStructure.redCoord.append(pos) self.initialStructure.Natoms += 1 self.initialStructure.computeXYZCoord() if self.initialStructure.Natoms != self.Natomes: print("Natoms : {0}".format(self.Natomes)) print("Structure : {0}".format(self.initialStructure.Natoms)) print("Error : atom number") exit(1) # atom names for iat in range(self.Natomes): self.initialStructure.atomNames.append(self.atoms[iat].name) return self.initialStructure
def run_crystal(args): print("Crystal is running ", end='') sys.stdout.flush() for i in range(10): print('.', end='') sys.stdout.flush() time.sleep(200.0 / 1000.0) print() crystal = Crystal(args.size, args.num_particles, args.proba, args.time, args.delay, args.num_iters) crystal.run(args.visualise) print("Finished!")
def _create_crystal(self): crystal = Crystal(self) crystal.rect.x = randint(50, 1200) crystal.rect.y = randint(50, 800) if pygame.sprite.collide_rect(self.hero, crystal): crystal.rect.x = randint(50, 1200) crystal.rect.y = randint(50, 800) self.crystals.add(crystal)
def allocation(matrix, shape): """ Размещение элементов на плате """ crystal = Crystal(*shape) vertex, *other = list(Graph(matrix)) crystal.add(Position(0, 0), vertex) old_graph = Graph(matrix, other) # Это неразмещенные элементы new_graph = Graph(matrix, [vertex]) # Это размещенные while len(old_graph) != 0: # Ищем элемент, который максимально связан с остальными vertex = max(old_graph, key=lambda v: sum(v.distance(x) for x in new_graph) - sum( v.distance(x) for x in old_graph)) # Ищем позицию, где сумма его весов с размещенными минимальна # Если по какой-то причине у вас идет слишком хорошее размещение и итерационный алгоритм # не может ничего улучшить а в отчете хочется показать его работу # то просто, удалите vertex.distance(crystal[x]) n_pos = min(crystal.free_positions, key=lambda pos: sum( crystal.distance(x, pos) * vertex.distance(crystal[x]) for x in crystal)) crystal.add(n_pos, new_graph.add(old_graph.pop(vertex))) return crystal
def testSetConvolutionMatrixStack(self): t1 = complexArray([1.75,0,0]) t2 = complexArray([0, 1.5, 0]) erData = np.transpose(np.loadtxt(context.testLocation + '/triangleData.csv', delimiter=',')) urData = 1 * complexOnes((512, 439)) triangleCrystal = Crystal(erData, urData, t1, t2) dummyLayer = Layer(crystal=triangleCrystal) dummyStack = LayerStack(freeSpaceLayer, dummyLayer, freeSpaceLayer) dummyStack.setConvolutionMatrix(self.numberHarmonics) convolutionMatrixActual = self.layerStack.internalLayer[0].er convolutionMatrixCalculated = dummyStack.internalLayer[0].er assertAlmostEqual(convolutionMatrixActual, convolutionMatrixCalculated, self.absoluteTolerance, self.relativeTolerance, "ER convolution matrices for layer 1 not equal")
def getInitialStructure(self,verbose=True): """ read initial structure """ # read initial pos fxml = open(self.xmlFile, "r") structure = myxml.getBlocs("structure", fxml, {"name":"initialpos"}, True) fxml.close() # read lattice vectors latticeParam = myxml.getBlocs("varray", structure, {"name":"basis"}, True) veca = [ float(val) for val in myxml.getNodeData(latticeParam[1]) ] vecb = [ float(val) for val in myxml.getNodeData(latticeParam[2]) ] vecc = [ float(val) for val in myxml.getNodeData(latticeParam[3]) ] # crystal object self.initialStructure = Crystal(veca = veca, vecb = vecb, vecc = vecc, \ name = "Initial structure : {0}".format(self.xmlFile)) # print lattice parameters if verbose: print("\t* a = %10.5f \t* alpha = %10.3f" % \ (self.initialStructure.a, self.initialStructure.alpha)) print("\t* b = %10.5f \t* beta = %10.3f" % \ (self.initialStructure.b, self.initialStructure.beta) ) print("\t* c = %10.5f \t* gamma = %10.3f" % \ (self.initialStructure.c, self.initialStructure.gamma)) # read reduce coordinates and compute cartesian coordinates positions = myxml.getBlocs("varray", structure, {"name":"positions"}, True) self.initialStructure.Natoms = 0 for ligne in positions[1:-1]: pos = [float(val) for val in myxml.getNodeData(ligne)] self.initialStructure.redCoord.append(pos) self.initialStructure.Natoms += 1 self.initialStructure.computeXYZCoord() if self.initialStructure.Natoms != self.Natomes: print("Natoms : {0}".format(self.Natomes)) print("Structure : {0}".format(self.initialStructure.Natoms)) print("Error : atom number") exit(1) # atom names for iat in range(self.Natomes): self.initialStructure.atomNames.append(self.atoms[iat].name) return self.initialStructure
def setUp(self): self.absoluteTolerance = 1e-4 self.relativeTolerance = 1e-3 devicePermittivityCellData = np.transpose( np.loadtxt(context.testLocation + '/triangleData.csv', delimiter=',')) devicePermeabilityCellData = 1 + 0 * devicePermittivityCellData reflectionLayer = Layer(er=2.0, ur=1.0) transmissionLayer = Layer(er=9.0, ur=1.0) # NOTE: t1 AND t2 MUST BE NORMALIZED BY MULTIPLYING BY k0, OTHERWISE THIS WILL NOT WORK, AS # EVERYTHING WAS FORMULATED IN TERMS OF NORMALIZED WAVEVECTORS. I DON'T KNOW OF AN ELEGANT WAY # TO DO THIS OTHER THAN REQUIRING A CRYSTAL TO HAVE A SOURCE AS THE INPUT. I DON'T KNOW OF # AN EASY WAY TO FIX THIS. I'M GOING TO FUDGE IT FOR NOW. wavelength = 2 k0 = 2 * pi / wavelength theta = 60 * deg phi = 30 * deg pTEM = 1 / sqrt(2) * complexArray([1, 1j]) source = Source(wavelength=wavelength, theta=theta, phi=phi, pTEM=pTEM, layer=reflectionLayer) t1, t2 = complexArray([1.75, 0, 0]), complexArray([0, 1.5, 0]) thicknessLayer1 = 0.5 # should be 0.5 thicknessLayer2 = 0.3 # should be 0.3 numberHarmonics = (3, 3) deviceCrystal = Crystal(devicePermittivityCellData, devicePermeabilityCellData, t1, t2) layer1 = Layer(crystal=deviceCrystal, L=thicknessLayer1, numberHarmonics=numberHarmonics) layer2 = Layer(er=6.0, ur=1.0, L=thicknessLayer2) layerStack = LayerStack(reflectionLayer, layer1, layer2, transmissionLayer) self.solver = Solver(layerStack, source, numberHarmonics)
def anaStruct(): """ main program """ calcDistance = True calcAngle = True # poscar name if len(sys.argv) == 2: poscar = sys.argv[1] else: poscar = "CONTCAR" # load data if not os.path.exists(poscar): print("file {0} does not exist".format(poscar)) exit(1) else: print("Read file " + poscar) struct = Crystal.fromPOSCAR(poscar, verbose = False) # distance analysis sigma = .01 npts = 300 xmin = 1.5 xmax = 2.5 if calcDistance: getDistances(struct, sigma, npts, xmin, xmax) ## angle analysis amin = 80. amax = 100. cutoff = 3.0 centralAtom = "Co" ligandAtom = "O" sigma = .5 npts = 200 if calcAngle: getAngles(struct, sigma, npts, amin, amax, cutoff, centralAtom, ligandAtom)
def sim(gType, depthF, slope, profile, wavelength, period, har, res, material, theta, phi, pTEM, loop): tests = np.size(locals()[loop]) loops = locals()[loop] depthFs = depthF slopes = slope wavelengths = wavelength periods = period hars = har ress = res depthF = depthFs[0] slope = slopes[0] wavelength = wavelengths[0] period = periods[0] har = hars[0] res = ress[0] print(f"\nSimulating a {gType} diffraction grating made of {material}....") ##refractive index vals at 400nm Si_n = 5.5674 #Si_n=6.4732 #Si_n=5.4754 #Si_n=4.9760 #Si_n=4.6784 Al_n = 0.48787 Ag_n = 0.05 Au_n = 1.4684 Ti_n = 2.0913 #extinction coefficient vals at 400nm Si_k = 0.38612 #Si_k=1.0686 #Si_k=3.0024 #Si_k=4.1990 #Si_k=0.14851 Al_k = 4.8355 Ag_k = 2.1035 Au_k = 1.9530 Ti_k = 2.9556 er_si = (Si_n)**2 - (Si_k)**2 + 2 * Si_n * Si_k * 1j if material == 'Silicon': er = er_si elif material == 'Aluminium': er = (Al_n)**2 - (Al_k)**2 + 2 * Al_n * Al_k * 1j elif material == 'Silver': er = (Ag_n)**2 - (Ag_k)**2 + 2 * Ag_n * Ag_k * 1j elif material == 'Gold': er = (Au_n)**2 - (Au_k)**2 + 2 * Au_n * Au_k * 1j elif material == 'Titanium': er = (Ti_n)**2 - (Ti_k)**2 + 2 * Ti_n * Ti_k * 1j print(f'Permittivity = {er}') #Creating basic layers reflectionLayer = Layer(er=1.0006, ur=1, L=100) baseLayer = Layer(er=er_si, ur=1, L=1) source = Source(wavelength=wavelength, theta=theta, phi=phi, pTEM=pTEM, layer=reflectionLayer) if gType == 'Checkerboard': print("Creating layers for checkerboard simulation...\n") nLayers = Check(res, er, material, gType) if gType == 'Rectangular' and slope == 0: print( "Creating layers for rectangular simulation with vertical sidewalls...\n" ) nLayers = Slopecsv(res, slope, depthF, material, gType, er) if gType == 'Square': print("Creating layers for square simulation...\n") nLayers = Square(res, er, material, gType) if gType == 'CoatedChecker': print("Creating layers for coated checkerboard simulation...\n") nLayers = CheckCoat(res, er, material, gType, er_si) if gType == 'CheckerError': err = input( "What percentage error would you like on the checkerboard? Please enter as a decimal, eg 0.3 for 30% error." ) print( f"Creating layers for checkerboard simulation with error {err}...\n" ) nLayers = CheckErr(res, er, material, gType, err) if gType == 'CheckDiag': print(f"Creating layers for checkerboard simulation on diagonal...\n") nLayers = CheckDiag(res, er, material, gType) if gType == 'CheckDiagErr': err = input( "What percentage error would you like on the checkerboard? Please enter as a decimal, eg 0.3 for 30% reduction in square size." ) print( f"Creating layers for checkerboard simulation with error {err}...\n" ) nLayers = CheckDiagErr(res, er, material, gType, err) if gType == 'Circ': print(f"Creating layers for circular grating simulation...\n") nLayers = Circ(res, er, material, gType) #setting up arrays to hold results of zeroth and first diffraction orders from simulation firstxs = np.zeros(tests) firstys = np.zeros(tests) zeros = np.zeros(tests) diags = np.zeros(tests) count = 0 while count < tests: depthF = depthFs.take([count], mode='clip')[0] slope = slopes.take([count], mode='clip')[0] wavelength = wavelengths.take([count], mode='clip')[0] period = periods.take([count], mode='clip')[0] har = hars.take([count], mode='clip')[0] res = ress.take([count], mode='clip')[0] depth = depthF * wavelength #generate csv files if slope != 0: if gType == "Rectangular": print( f"Creating layers for rectangular grating with sloped sidewalls, slope={slope} degrees...\n" ) nLayers = Slopecsv(res, slope, depthF, material, gType, er) elif gType == "Blazed": print( f"Creating layers for blazed grating of blaze angle {slope} degrees...\n" ) nLayers = Blazedcsv(res, slope, depthF, material, gType, er) #set period in each direction t1, t2 = complexArray([period, 0, 0]), complexArray([0, period, 0]) n = 0 layers = np.empty(nLayers, Layer) print( f"Performing simulation trial {count+1} of {tests}, with {loop}={loops[count]}..." ) print(f"This simulation requires {nLayers} layers... ") #slope=90-slope while n < nLayers: print(f"creating layer {n+1} of {nLayers}...") if slope != 0: eCellData = np.transpose( np.genfromtxt( f'{path}/csvs/{gType}_{material}_slope{slope}_{depthF}_layer{count}_{res}.csv', delimiter=',', dtype=complex)) else: eCellData = np.transpose( np.genfromtxt( f'{path}/csvs/{gType}_{material}_slope0_layer{n}_{res}.csv', delimiter=',', dtype=complex)) print( f'file used:{gType}_{material}_slope0_layer{n}_{res}.csv ') uCellData = np.transpose( np.genfromtxt(f'{path}/csvs/U{res}.csv', delimiter=',')) #setting depth of grating if gType == "Blazed": depth = period * np.tan(slope) crystalThickness = depth / nLayers if gType == "CoatedChecker": crystalThickness = depth numberHarmonics = (har, har) #numberHarmonics=(har,har) #creating crystal (grating) and grating layer deviceCrystal = Crystal(eCellData, uCellData, t1, t2) layers[n] = Layer(crystal=deviceCrystal, L=crystalThickness, numberHarmonics=numberHarmonics) n = n + 1 print(f"There are {nLayers} Layers of thickness {crystalThickness}") layerStack = LayerStack(reflectionLayer, *layers, baseLayer) print("Running simulation...\n") #perform simulation solver = Solver(layerStack, source, numberHarmonics) solver.Solve() sResults = solver.results rx = np.reshape(solver.rx, (har, har)) ry = np.reshape(solver.ry, (har, har)) rz = np.reshape(solver.rz, (har, har)) # np.savetxt(f"{path}/results/RX_{gType}_{loop}_tests({tests})_{wavelength}_{period}.csv",rx , delimiter=",") # np.savetxt(f"{path}/results/RY_{gType}_{loop}_tests({tests})_{wavelength}_{period}.csv",ry , delimiter=",") # np.savetxt(f"{path}/results/RZ_{gType}_{loop}_tests({tests})_{wavelength}_{period}.csv",rz , delimiter=",") RX = np.ones([3, 3], dtype='complex') RY = np.ones([3, 3], dtype='complex') RZ = np.ones([3, 3], dtype='complex') i, j = int(har / 2) - 1, int(har / 2) - 1 a, b = 0, 0 while i >= int(har / 2) - 1 and i <= int(har / 2) + 1: j = int(har / 2) - 1 b = 0 while j >= int(har / 2) - 1 and j <= int(har / 2) + 1: RX[a, b] = complex(rx[i, j]) RY[a, b] = complex(ry[i, j]) RZ[a, b] = complex(rz[i, j]) j = j + 1 b = b + 1 i = i + 1 a = a + 1 stokes = transform(RX, RY, RZ, wavelength, period, 'x', False) print("STOKES:\n") print(stokes) # Get the diffraction efficiencies R and T and overall reflection and transmission coefficients R and T (R, RTot) = (solver.R, solver.RTot) print(f"Total Reflection {RTot}") # if profile: # makeProf(slope,depthF,nLayers,res, material) firstx = R[int(har / 2)][int(har / 2 - 1)] firsty = R[int(har / 2 - 1)][int(har / 2)] zeroth = R[int(har / 2)][int(har / 2)] diag = R[int(har / 2 + count)][int(har / 2 + count)] diags[count] = diag firstxs[count] = firstx firstys[count] = firsty zeros[count] = zeroth print("Plotting...") plotter(firstxs, firstys, zeros, diags, R, loop, gType, tests, count, profile, slope, depthF, nLayers, res, material, wavelength, period, har, loops[count]) count = count + 1 plt.figure() plt.plot( loops, zeros, label="0th order efficiency") #simulated 0th orders at varying depths plt.plot(loops, firstxs, label="1st order efficiency - x direction" ) #simulated 1st orders at varying depths #plt.scatter(loops,firstys,label="1st order efficiency - y direction") plt.plot(loops, diags, label="diagonal efficiency modes") plt.ylabel("Intensity") plt.xlabel(f"{loop}") plt.legend(loc='upper left', bbox_to_anchor=(1.05, 1)) plt.title(f"Efficiency of {gType} {material} grating at different {loop} ") tuple = (loops, zeros, firstxs, firstys, diags) results = np.vstack(tuple) np.savetxt( f"{path}/results/{gType}_{loop}_tests({tests})_{wavelength}_{period}.csv", results, delimiter=",") return 0
k0 = 2 * pi / wavelength theta = 60 * deg phi = 30 * deg pTEM = 1 / sqrt(2) * complexArray([1, 1j]) source = Source(wavelength=wavelength, theta=theta, phi=phi, pTEM=pTEM, layer=reflectionLayer) t1, t2 = complexArray([1.75, 0, 0]), complexArray([0, 1.5, 0]) crystalThickness = 0.5 numberHarmonics = (3, 3) deviceCrystal = Crystal(devicePermittivityCellData, devicePermeabilityCellData, t1, t2) layer1 = Layer(crystal=deviceCrystal, L=crystalThickness, numberHarmonics=numberHarmonics) layerStack = LayerStack(reflectionLayer, layer1, transmissionLayer) solver = Solver(layerStack, source, numberHarmonics) solver.Solve() # Get the amplitude reflection and transmission coefficients (rxCalculated, ryCalculated, rzCalculated) = (solver.rx, solver.ry, solver.rz) (txCalculated, tyCalculated, tzCalculated) = (solver.tx, solver.ty, solver.tz) # Get the diffraction efficiencies R and T and overall reflection and transmission coefficients R and T (R, T, RTot, TTot) = (solver.R, solver.T, solver.RTot, solver.TTot) print(RTot, TTot, RTot + TTot)
def getFinalStructure(self,verbose=True): """ read final structure """ # read final pos fxml = open(self.xmlFile, "r") structure = myxml.getBlocs("structure", fxml, {"name":"finalpos"}, True) fxml.close() if self.verbose: print("\n# Read final structure") if structure == None: # there is not final structure (run not terminated) # <structure>...</structure> print("\t* Warning: final structure not found, read last one instead") fxml = open(self.xmlFile, "r") blocsStructures = myxml.getBlocs("structure", fxml) fxml.close() Nstructures = len(blocsStructures) if Nstructures == 0: # aucune structure ? print("\nError : there is not any structure in this xml file!\n") exit(1) elif Nstructures == 1: # only one structure => the initial one ligne = blocsStructures[0][0] att = myxml.getClefs(ligne, ["name"]) if att["name"] != None and att["name"] == "initialpos": print("\t* Warning : I found only the initial structure") else: print("\t* Warning : I found only one structure which is not the initial one ??") structure = blocsStructures[0] else: structure = blocsStructures[Nstructures-1] # read lattice vectors latticeParam = myxml.getBlocs("varray", structure, {"name":"basis"}, True) veca = [ float(val) for val in myxml.getNodeData(latticeParam[1]) ] vecb = [ float(val) for val in myxml.getNodeData(latticeParam[2]) ] vecc = [ float(val) for val in myxml.getNodeData(latticeParam[3]) ] # definition du cristal self.finalStructure = Crystal(veca = veca, vecb = vecb, vecc = vecc, \ name = "Final structure : {0}".format(self.xmlFile)) # print lattice parameters if verbose: print("\t* a = %10.5f \t* alpha = %10.3f" % (self.finalStructure.a, self.finalStructure.alpha)) print("\t* b = %10.5f \t* beta = %10.3f" % (self.finalStructure.b, self.finalStructure.beta) ) print("\t* c = %10.5f \t* gamma = %10.3f" % (self.finalStructure.c, self.finalStructure.gamma)) # read reduce coordinates and compute cartesian coordinates positions = myxml.getBlocs( "varray", structure, {"name":"positions"}, True) self.finalStructure.Natoms = 0 for ligne in positions[1:-1]: pos = [ float(val) for val in myxml.getNodeData(ligne) ] self.finalStructure.redCoord.append(pos) self.finalStructure.Natoms += 1 self.finalStructure.computeXYZCoord() if self.finalStructure.Natoms != self.Natomes: print("Natomes : {0}".format(self.Natomes)) print("Structure : {0}".format(self.finalStructure.Natomes)) print("Error : atomic number unconsistant") exit(1) # atom names for iat in range(self.Natomes): self.finalStructure.atomNames.append(self.atoms[iat].name) return self.finalStructure
class VaspRun(object): """ VASP calculation class Arguments : * fichier : vasprun.xml output file of VASP (default is 'vasprun.xml') * verbose (bool) : verbosity of methods (default is 'True') Example : run = VaspRun() run = VaspRun("dos.xml") """ def __init__(self, xmlFile = "vasprun.xml", verbose = True): """ constructor """ self.xmlFile = xmlFile self.verbose = verbose # check xml file if os.path.exists(self.xmlFile): # read main data self.__readKeywords() self.__readAtomsData() self.getFinalStructure(self.verbose) # variable de controle self.DOSTotaleLue = False self.DOSPartiellesLues = False self.bandesLues = False self.pointsKLues = False # affichage de quelques infos if self.verbose: print("# xml file of the run : {0}\n".format(self.xmlFile)) self.printINCAR() print("") self.printAtomsData() else: print("\n\t\t### file {0} does not exist ###\n".format(xmlFile)) exit(1) # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Méthodes d'interrogation des paramètres du calcul # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def valeurMotClef(self, flag): """ return the value of the parameter 'flag' arguments: * flag(string) : parameter of VASP see listerMotsClefs() """ # interrogation des dictionnaires if flag in self.allMotsClefs.keys(): valeur = self.allMotsClefs[ flag ] if self.verbose: print("{0} = {1}".format(flag, valeur)) else: valeur = None print("{0} unknown".format(flag)) return valeur def listerMotsClefs(self): """ Print all paramters of the calculation. see valeurMotClef() """ # mots clefs du fichier INCAR print("# mots clefs du fichier INCAR") ligne = "" for i, flag in enumerate(sorted(self.INCAR.keys())): ligne += flag.rjust(15) + "," if (i % 6 == 0 and i != 0) or i == len(self.INCAR.keys()) - 1: print(ligne) ligne = "" # tous les mots clefs du calcul print("\n# mots clefs du calcul") ligne = "" for i, flag in enumerate(sorted(self.allMotsClefs.keys())): ligne += flag.rjust(15) + "," if (i % 6 == 0 and i != 0) or i == len(self.allMotsClefs.keys()) - 1: print(ligne) ligne = "" def printINCAR(self): """ print INCAR keywords """ print("# fichier INCAR du calcu") ligne="" for i, flag in enumerate(self.INCAR.keys()): ligne += flag.rjust(10) + " = " + str(self.INCAR[flag]).ljust(10) if (i % 3 == 0 and i != 0) or i == len(self.INCAR.keys()) - 1: print(ligne) ligne="" def printAtomsData(self): """ print atomic data """ print("\n# system :") print("\t* atom number : " + str(self.Natomes)) print("\t* type number : " + str(self.Ntypes)) ligne = "\t* atom list : " for i in range(self.Natomes): if i != 0 and i % 10 == 0: print(ligne) ligne = "\t " ligne += self.atoms[i].name.rjust(3) + ", " if ligne.strip() != "": print(ligne[:-2]) print("\n# Atom types :") for i in range(self.Ntypes): for atom in self.atoms: if i+1 == atom.atomType: print(atom) break # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Méthodes pour la DOS # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def lectureDOS( self ): """ Lecture de la densité d'états totale et des densités d'états partielles sur le fichier xml du calcul. Après exécution de cette méthode, on dispose de la densité d'états totale dans la liste dosTotale et des densités d'états partielles dans la liste dosPartielles. Les valeurs d'énergies pour lesquelles on dispose des valeurs de la DOS sont dans la liste energiesDOS. Ici <VaspRun> désigne un objet de type VaspRun, les listes crées sont de la forme : <VaspRun>.nptsDos => nombre de valeurs pour la DOS <VaspRun>.energiesDOS[i] i : 0 -> calcul.nptsDos-1 valeurs d'énergies pour lesquelles les DOS sont connues. <VaspRun>.dosTotale[ spin ][ E ][ i ] spin : 0 ou 1, seule la valeur 0 est disponnible pour les calculs avec spin non polarisé (ISPIN = 1). Pour les calculs spin polarisé (ISPIN = 2), spin = 0 donne la DOS pour le spin alpha et spin = 1 pour le spin beta. E : indice de parcours de la DOS pour un spin (valeurs de l'énergie) i : 0 -> 1 i = 0 -> densité d'états i = 1 -> intégrale de la DOS <VaspRun>.dosPartielles[ iat ][ spin ][ E ][ i ] iat : numéro de l'atome spin : 0 ou 1, seule la valeur 0 est disponnible pour les calculs avec spin non polarisé (ISPIN = 1). Pour les calculs spin polarisé (ISPIN = 2), spin = 0 donne la DOS pour le spin alpha et spin = 1 pour le spin beta. E : indice de parcours de la DOS pour un spin (valeurs de l'énergie) i : 0 -> 2 ou 8 valeurs de la DOS sur chaque sous couche ou OA 0 s, 1 p, 2 d 0 s, 1 py, 2 pz, 3 px, 4 dxy, 5 dyz, 6 dz2, 7 dxz, 8 dx2-y2 """ # spin polarise ? ISPIN = self.allMotsClefs["ISPIN"] if self.verbose: print("# Lecture de la densité d'états") # calcul spin polarisé ? print("\t* ISPIN = {0}".format(ISPIN)) # bloc dos fxml = open(self.xmlFile, "r") dos = myxml.getBlocs("dos", fxml, onlyfirst = True) fxml.close() # test presence de la dos if dos == None: print("Pas de densité d'états dans ce calcul") else: if self.verbose: print("\t* densité d'états totale") # niveau de Fermi for ligne in dos: att = myxml.getClefs(ligne, ["name"]) if att["name"] != None and att["name"] == "efermi": self.eFermi = float(myxml.getNodeData(ligne)[0]) print("\t* Fermi level = {0} eV (warning : accuracy depend on k-points grid)".format(self.eFermi)) break # DOS TOTALE # lecture de la dos totale blocDosTotale = myxml.getBlocs("total", dos, onlyfirst = True) self.dosTotale = list() self.energiesDOS = list() # cas spin non polarise blocDosTotaleSpin1 = myxml.getBlocs("set", blocDosTotale[1:-1], {"comment":"spin 1"}, True) self.dosTotale.append(list()) for ligne in blocDosTotaleSpin1[1:-1]: valeurs = [float(val) for val in myxml.getNodeData(ligne)] # valeurs[0] est l'energie self.energiesDOS.append(valeurs[0]) self.dosTotale[0].append(valeurs[1:]) if ISPIN == 2: # cas spin polarise blocDosTotaleSpin2 = myxml.getBlocs("set", blocDosTotale[1:-1], {"comment":"spin 2"}, True) self.dosTotale.append(list()) for ligne in blocDosTotaleSpin2[1:-1]: valeurs = [float(val) for val in myxml.getNodeData(ligne)] # valeurs[0] est l'energie self.dosTotale[1].append(valeurs[1:]) self.DOSTotaleLue = True # # DOS PARTIELLES # blocDosPartielle = myxml.getBlocs("partial", dos, onlyfirst = True ) if blocDosPartielle == None: print("\t ! pas de densité d'états partielles !") else: if self.verbose: print("\t* densités d'états partielles") self.dosPartielles = list() # boucle sur les atomes du calcul for iat in range(self.Natomes): ion = "ion " + str(iat+1) blocDosIon = myxml.getBlocs("set", blocDosPartielle, {"comment":ion}, True) self.dosPartielles.append( list() ) blocDosIonSpin1 = myxml.getBlocs( "set", blocDosIon[1:-1], {"comment":"spin 1"}, True) self.dosPartielles[iat].append( list() ) # lecture des dos projetees spin 1 for ligne in blocDosIonSpin1[1:-1]: valeurs = [ float(val) for val in myxml.getNodeData( ligne ) ] # valeurs[0] est l'energie self.dosPartielles[iat][0].append( valeurs[1:] ) if ISPIN == 2: self.dosPartielles[iat].append( list() ) blocDosIonSpin2 = myxml.getBlocs( "set", blocDosIon[1:-1], {"comment":"spin 2"}, True) # lecture des dos projetees spin 2 for ligne in blocDosIonSpin2[1:-1]: valeurs = [ float(val) for val in myxml.getNodeData( ligne ) ] # valeurs[0] est l'energie self.dosPartielles[iat][1].append( valeurs[1:] ) self.DOSPartiellesLues = True return [self.DOSTotaleLue, self.DOSPartiellesLues] # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Méthodes pour les bandes d'énergies # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def lectureBandes(self): """ Méthode permettant de lire les bandes d'énergie sur le fichier xml du calcul. Après exécution de cette méthode, on dispose des bandes d'énergie dans la liste Bandes sous la forme : <VaspRun>.bandes[ spin ][ point k ][ bandes ][ i ] spin : 0 ou 1, seule la valeur 0 est disponnible pour les calculs avec spin non polarisé (ISPIN = 1). Pour les calculs spin polarisé (ISPIN = 2), spin = 0 donne les bandes pour les spin alpha et spin = 1 pour les spin beta. point k : 0 -> nombre de point K le nombre de point k est calcul.nbrePointsK calcul.nbreLignesPointsK : nombre de directions de points k calcul.Ndivision : nombre de points k par direction Les points k sont listés direction après direction en donnant l'ensemble des points k sur chaque direction bandes : 0 -> NBANDS-1 i : 0 ou 1 i = 0 -> valeurs de l'énergie i = 1 -> occupation de la bande """ # lecture du niveau de fermi fxml = open(self.xmlFile, "r") dos = myxml.getBlocs("dos", fxml, onlyfirst = True) fxml.close() # test presence de la dos if dos == None: print("Density of state and fermi level not found in xml file") self.eFermi = 0.0 else: # niveau de Fermi for ligne in dos: att = myxml.getClefs(ligne, ["name"]) if att["name"] != None and att["name"] == "efermi": self.eFermi = float(myxml.getNodeData(ligne)[0]) break # bloc eigenvalues = bandes d'energie fxml = open(self.xmlFile, "r") eigenvalues = myxml.getBlocs("eigenvalues", fxml, onlyfirst = True) fxml.close() if eigenvalues == None: print("\nerreur : bandes d'énergie introuvable\n") exit(1) # infos sur le calcul NBANDS = self.allMotsClefs["NBANDS"] ISPIN = self.allMotsClefs["ISPIN"] # lecuture des points K self.lecturePointsK() nbreKpoints = len(self.listePointsK) if self.verbose: print("# Lecture des bandes d'énergies") print("\t* Fermi level = {0} eV (warning accuracy depend on k-points grid)".format(self.eFermi)) print("\t* ISPIN = {0}".format(ISPIN)) print("\t* nombre de bandes = {0}".format(NBANDS)) print("\t* nombre de points K = {0}".format(nbreKpoints)) setMain = myxml.getBlocs("set", eigenvalues, onlyfirst = True) blocSpin = list() blocSpin.append( myxml.getBlocs("set", setMain, {"comment":"spin 1"}, True)) if ISPIN == 2: blocSpin.append( myxml.getBlocs("set", setMain, {"comment":"spin 2"}, True)) # lecture des bandes self.bands = list() for spin in range(ISPIN): self.bands.append( list() ) # boucle sur les points k pour un spin for k in range(nbreKpoints): self.bands[spin].append( list() ) kpoint = "kpoint " + str(k+1) block = myxml.getBlocs("set", blocSpin[spin], {"comment":kpoint }, True) # boucle sur les valeurs des bandes sur un points k for ligne in block: nom = myxml.getNodeName(ligne) if nom == "r": valeurs = [float(val) for val in myxml.getNodeData(ligne) ] self.bands[spin][k].append( valeurs ) if len(self.bands[spin][k]) != NBANDS: print("\nerreur nombre de bandes incorrect\n") exit(1) # controle de lecture self.bandesLues = True return self.bandesLues # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Lecture des points K # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def lecturePointsK(self): """ lit les informations sur les point K du calcul """ # lecture des points k fxml = open(self.xmlFile, "r") kpoints = myxml.getBlocs("kpoints", fxml, onlyfirst = True ) fxml.close() # grille de points K generation = myxml.getBlocs("generation", kpoints, onlyfirst = True) if generation == None: self.typePointsK = "explicit" else: att = myxml.getClefs(generation[0], ["param"]) self.typePointsK = att["param"] if self.typePointsK == "listgenerated": ndir = 0 liste = list() for ligne in generation: nom = myxml.getNodeName(ligne) if nom == "i": self.Ndivision = int(myxml.getNodeData(ligne)[0]) if nom == "v": valeurs = [float(val) for val in myxml.getNodeData(ligne)] liste.append(valeurs) ndir += 1 # liste des directions self.directionsPointsK = list() for d in range(ndir - 1): self.directionsPointsK.append(liste[d] + liste[d + 1]) else: print("Explicit K points grid") # kpointlist varray = myxml.getBlocs( "varray", kpoints, {"name" : "kpointlist"}, True) self.listePointsK = list() for ligne in varray[1:-1]: valeurs = [float(val) for val in myxml.getNodeData(ligne)] self.listePointsK.append(valeurs) if self.typePointsK == "listgenerated": if len(self.directionsPointsK) * self.Ndivision != len(self.listePointsK): raise ValueError("k-points number unconsistent") else: self.directionsPointsK = [self.listePointsK[0] + self.listePointsK[-1]] self.Ndivision = len(self.listePointsK) # controle de lecture self.pointsKLues = True return self.pointsKLues # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Lecture de la structure initiale et finale # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def getInitialStructure(self,verbose=True): """ read initial structure """ # read initial pos fxml = open(self.xmlFile, "r") structure = myxml.getBlocs("structure", fxml, {"name":"initialpos"}, True) fxml.close() # read lattice vectors latticeParam = myxml.getBlocs("varray", structure, {"name":"basis"}, True) veca = [ float(val) for val in myxml.getNodeData(latticeParam[1]) ] vecb = [ float(val) for val in myxml.getNodeData(latticeParam[2]) ] vecc = [ float(val) for val in myxml.getNodeData(latticeParam[3]) ] # crystal object self.initialStructure = Crystal(veca = veca, vecb = vecb, vecc = vecc, \ name = "Initial structure : {0}".format(self.xmlFile)) # print lattice parameters if verbose: print("\t* a = %10.5f \t* alpha = %10.3f" % \ (self.initialStructure.a, self.initialStructure.alpha)) print("\t* b = %10.5f \t* beta = %10.3f" % \ (self.initialStructure.b, self.initialStructure.beta) ) print("\t* c = %10.5f \t* gamma = %10.3f" % \ (self.initialStructure.c, self.initialStructure.gamma)) # read reduce coordinates and compute cartesian coordinates positions = myxml.getBlocs("varray", structure, {"name":"positions"}, True) self.initialStructure.Natoms = 0 for ligne in positions[1:-1]: pos = [float(val) for val in myxml.getNodeData(ligne)] self.initialStructure.redCoord.append(pos) self.initialStructure.Natoms += 1 self.initialStructure.computeXYZCoord() if self.initialStructure.Natoms != self.Natomes: print("Natoms : {0}".format(self.Natomes)) print("Structure : {0}".format(self.initialStructure.Natoms)) print("Error : atom number") exit(1) # atom names for iat in range(self.Natomes): self.initialStructure.atomNames.append(self.atoms[iat].name) return self.initialStructure # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def getFinalStructure(self,verbose=True): """ read final structure """ # read final pos fxml = open(self.xmlFile, "r") structure = myxml.getBlocs("structure", fxml, {"name":"finalpos"}, True) fxml.close() if self.verbose: print("\n# Read final structure") if structure == None: # there is not final structure (run not terminated) # <structure>...</structure> print("\t* Warning: final structure not found, read last one instead") fxml = open(self.xmlFile, "r") blocsStructures = myxml.getBlocs("structure", fxml) fxml.close() Nstructures = len(blocsStructures) if Nstructures == 0: # aucune structure ? print("\nError : there is not any structure in this xml file!\n") exit(1) elif Nstructures == 1: # only one structure => the initial one ligne = blocsStructures[0][0] att = myxml.getClefs(ligne, ["name"]) if att["name"] != None and att["name"] == "initialpos": print("\t* Warning : I found only the initial structure") else: print("\t* Warning : I found only one structure which is not the initial one ??") structure = blocsStructures[0] else: structure = blocsStructures[Nstructures-1] # read lattice vectors latticeParam = myxml.getBlocs("varray", structure, {"name":"basis"}, True) veca = [ float(val) for val in myxml.getNodeData(latticeParam[1]) ] vecb = [ float(val) for val in myxml.getNodeData(latticeParam[2]) ] vecc = [ float(val) for val in myxml.getNodeData(latticeParam[3]) ] # definition du cristal self.finalStructure = Crystal(veca = veca, vecb = vecb, vecc = vecc, \ name = "Final structure : {0}".format(self.xmlFile)) # print lattice parameters if verbose: print("\t* a = %10.5f \t* alpha = %10.3f" % (self.finalStructure.a, self.finalStructure.alpha)) print("\t* b = %10.5f \t* beta = %10.3f" % (self.finalStructure.b, self.finalStructure.beta) ) print("\t* c = %10.5f \t* gamma = %10.3f" % (self.finalStructure.c, self.finalStructure.gamma)) # read reduce coordinates and compute cartesian coordinates positions = myxml.getBlocs( "varray", structure, {"name":"positions"}, True) self.finalStructure.Natoms = 0 for ligne in positions[1:-1]: pos = [ float(val) for val in myxml.getNodeData(ligne) ] self.finalStructure.redCoord.append(pos) self.finalStructure.Natoms += 1 self.finalStructure.computeXYZCoord() if self.finalStructure.Natoms != self.Natomes: print("Natomes : {0}".format(self.Natomes)) print("Structure : {0}".format(self.finalStructure.Natomes)) print("Error : atomic number unconsistant") exit(1) # atom names for iat in range(self.Natomes): self.finalStructure.atomNames.append(self.atoms[iat].name) return self.finalStructure # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Méthodes internes # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def __readKeywords(self): """ read xmlFile and store all keywords and their values """ if self.verbose: print("\t* Read keywords of the run") # # # parameters keywords # bloc parameters fxml = open( self.xmlFile, "r") parameters = myxml.getBlocs("parameters", fxml, onlyfirst = True) fxml.close() # dictionnary des parametres du calcul self.allMotsClefs = {} for ligne in parameters: if "<i" in ligne: nomFlag, valeurFlag = self.__lectureFlag(ligne) self.allMotsClefs[nomFlag] = valeurFlag elif "<v" in ligne: nomFlag, valeurFlag = self.__lectureFlag(ligne, vecteur=True) self.allMotsClefs[nomFlag] = valeurFlag else: continue # # # mots clefs du bloc incar # bloc incar fxml = open(self.xmlFile, "r") incar = myxml.getBlocs("incar", fxml, onlyfirst = True) fxml.close() # dictionnaire INCAR self.INCAR = {} for ligne in incar[1:-1]: if "<i" in ligne: nomFlag, valeurFlag = self.__lectureFlag(ligne) self.INCAR[ nomFlag ] = valeurFlag elif "<v" in ligne: nomFlag, valeurFlag = self.__lectureFlag(ligne, vecteur=True) self.INCAR[ nomFlag ] = valeurFlag else: continue self.allMotsClefs = dict(self.allMotsClefs.items() + self.INCAR.items()) # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def __lectureFlag( self, node, vecteur=False ) : """ lecture d'un parametre du calcul suivant son type """ valeur = myxml.getNodeData( node ) # clefs clefs = myxml.getClefs( node, ["type", "name"] ) nomFlag = clefs["name"] typeFlag = clefs["type"] if len(valeur) != 0: if typeFlag == "string" or typeFlag == "logical": if vecteur : valeurFlag = " ".join(valeur) else : valeurFlag = valeur[0] elif typeFlag == "int" : if vecteur: valeurFlag = " ".join(valeur) else : valeurFlag = int(valeur[0]) elif typeFlag == None : if vecteur: valeurFlag = " ".join(valeur) else : valeurFlag = float(valeur[0]) else: valeurFlag = "empty" return nomFlag, valeurFlag # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def __readAtomsData( self ) : """ Read bloc 'atominfo'. It contains the atom list and their description. """ if self.verbose: print("\t* Read atom data") # on recupere le bloc atominfo fxml = open(self.xmlFile, "r") atominfo = myxml.getBlocs("atominfo", fxml, onlyfirst = True) fxml.close() # nombre d'atomes et nombre de types i = 0 for ligne in atominfo: if "<atoms>" in ligne : self.Natomes = int(myxml.getNodeData(ligne)[0]) i += 1 if "<types>" in ligne : self.Ntypes = int(myxml.getNodeData(ligne)[0]) i += 1 if i == 2 : break # atom list self.atoms = list() # read atom type lignesArrayTypes = myxml.getBlocs("array", atominfo, {"name":"atomtypes"}, True) self.typesAtomes = list() debutListe = False for ligne in lignesArrayTypes: if "<set>" in ligne: debutListe = True continue if "</set>" in ligne: break if debutListe: ligne = ligne.replace("<rc><c>", "") ligne = ligne.replace("</c></rc>", "") valeurs = ligne.split("</c><c>") tmpdic = {"nom":valeurs[1].strip(), "masse":float(valeurs[2]), \ "valence":float(valeurs[3]), "pseudo":valeurs[4] } self.typesAtomes.append(tmpdic) # lecture des atomes lignesArrayAtomes = myxml.getBlocs("array", atominfo, {"name":"atoms"}, True) debutListe = False for ligne in lignesArrayAtomes: if "<set>" in ligne: debutListe = True continue if "</set>" in ligne: break if debutListe : ligne = ligne.replace("<rc><c>", "") ligne = ligne.replace("</c></rc>", "") valeurs = ligne.split("</c><c>") nom = valeurs[0].strip() typ = int(valeurs[1]) if nom != self.typesAtomes[typ-1]["nom"]: print("non concordance nom / type ") exit(1) atom = Atom(name = self.typesAtomes[typ-1]["nom"], \ atomType = typ, \ Ne = self.typesAtomes[typ-1]["valence"], \ w = self.typesAtomes[typ-1]["masse"], \ pseudo = self.typesAtomes[typ-1]["pseudo"] ) self.atoms.append(atom)
def makepolycrystal(self, names, prunecriteria=1.0): ''' Method for creating grains/crystallites in a simulation box resulting in a polycrystal configuration. Input: names - list of material/phase for each grain (see src/materials.py) ''' numgrains = self.num assert numgrains == len(names) graintypes = {gid: names[gid] for gid in range(numgrains)} polycrystal = Polycrystal(self.boxsize, numgrains, names, self.points) polycrystal.setgraintypes(graintypes) for gid, gcenter in enumerate(self.points): print("-------------------------") print("Grain id: ", gid) self.ids.append(gid) # Naive approach: Generate mask crystal such that its bigger than the simulation # box. Then calculate mask crystal center of mass and shift mask so its center # is at the center of the grain mask = Crystal(names[gid]) self.graincrystal[gid] = mask ax, ay, az = mask.crystal.cell nx, ny, nz = 3 * round(self.lx / ax[0]), 3 * round( self.ly / ay[1]), 3 * round(self.lz / az[2]) mask.expandcrystal(nx=nx, ny=ny, nz=nz) chemsymbols = mask.crystal.get_chemical_symbols() mapchemsymtoid = {k: i + 1 for i, k in enumerate(set(chemsymbols))} print("-------chemical:id--------") for s in mapchemsymtoid.keys(): print("%s : %i" % (s, mapchemsymtoid[s])) print("-------------------------") comdiff = gcenter - mask.crystal.get_center_of_mass() mask.crystal.positions[:, 0] += comdiff[0] mask.crystal.positions[:, 1] += comdiff[1] mask.crystal.positions[:, 2] += comdiff[2] seed = randint(1, 9) * 0.1 mask.xrotate(seed=seed) keep = [] #Atom index for atom in range(mask.natoms): xyz = mask.crystal.positions[atom, :] #check if atom is in box if xyz[0] < 0.0 or xyz[0] > self.lx: continue elif xyz[1] < 0.0 or xyz[1] > self.ly: continue elif xyz[2] < 0.0 or xyz[2] > self.lz: continue if self.atom_in_grain(xyz, (gid, gcenter)) == True: keep.append(atom) print("Number of atoms in cell: ", len(keep)) print("Center of grain: ", self.points[gid]) print("-------------------------") polycrystal.embedatoms(mask.crystal, gid, keep) polycrystal.compress() polycrystal.pruneoverlap(criteria=prunecriteria) return polycrystal
def getFinalStructure(self, verbose=True): """ read final structure """ # read final pos fxml = open(self.xmlFile, "r") structure = myxml.getBlocs("structure", fxml, {"name": "finalpos"}, True) fxml.close() if self.verbose: print("\n# Read final structure") if structure == None: # there is not final structure (run not terminated) # <structure>...</structure> print( "\t* Warning: final structure not found, read last one instead" ) fxml = open(self.xmlFile, "r") blocsStructures = myxml.getBlocs("structure", fxml) fxml.close() Nstructures = len(blocsStructures) if Nstructures == 0: # aucune structure ? print( "\nError : there is not any structure in this xml file!\n") exit(1) elif Nstructures == 1: # only one structure => the initial one ligne = blocsStructures[0][0] att = myxml.getClefs(ligne, ["name"]) if att["name"] != None and att["name"] == "initialpos": print("\t* Warning : I found only the initial structure") else: print( "\t* Warning : I found only one structure which is not the initial one ??" ) structure = blocsStructures[0] else: structure = blocsStructures[Nstructures - 1] # read lattice vectors latticeParam = myxml.getBlocs("varray", structure, {"name": "basis"}, True) veca = [float(val) for val in myxml.getNodeData(latticeParam[1])] vecb = [float(val) for val in myxml.getNodeData(latticeParam[2])] vecc = [float(val) for val in myxml.getNodeData(latticeParam[3])] # definition du cristal self.finalStructure = Crystal(veca = veca, vecb = vecb, vecc = vecc, \ name = "Final structure : {0}".format(self.xmlFile)) # print lattice parameters if verbose: print("\t* a = %10.5f \t* alpha = %10.3f" % (self.finalStructure.a, self.finalStructure.alpha)) print("\t* b = %10.5f \t* beta = %10.3f" % (self.finalStructure.b, self.finalStructure.beta)) print("\t* c = %10.5f \t* gamma = %10.3f" % (self.finalStructure.c, self.finalStructure.gamma)) # read reduce coordinates and compute cartesian coordinates positions = myxml.getBlocs("varray", structure, {"name": "positions"}, True) self.finalStructure.Natoms = 0 for ligne in positions[1:-1]: pos = [float(val) for val in myxml.getNodeData(ligne)] self.finalStructure.redCoord.append(pos) self.finalStructure.Natoms += 1 self.finalStructure.computeXYZCoord() if self.finalStructure.Natoms != self.Natomes: print("Natomes : {0}".format(self.Natomes)) print("Structure : {0}".format(self.finalStructure.Natomes)) print("Error : atomic number unconsistant") exit(1) # atom names for iat in range(self.Natomes): self.finalStructure.atomNames.append(self.atoms[iat].name) return self.finalStructure
class VaspRun(object): """ VASP calculation class Arguments : * fichier : vasprun.xml output file of VASP (default is 'vasprun.xml') * verbose (bool) : verbosity of methods (default is 'True') Example : run = VaspRun() run = VaspRun("dos.xml") """ def __init__(self, xmlFile="vasprun.xml", verbose=True): """ constructor """ self.xmlFile = xmlFile self.verbose = verbose # check xml file if os.path.exists(self.xmlFile): # read main data self.__readKeywords() self.__readAtomsData() self.getFinalStructure(self.verbose) # variable de controle self.DOSTotaleLue = False self.DOSPartiellesLues = False self.bandesLues = False self.pointsKLues = False # affichage de quelques infos if self.verbose: print("# xml file of the run : {0}\n".format(self.xmlFile)) self.printINCAR() print("") self.printAtomsData() else: print("\n\t\t### file {0} does not exist ###\n".format(xmlFile)) exit(1) # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Méthodes d'interrogation des paramètres du calcul # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def valeurMotClef(self, flag): """ return the value of the parameter 'flag' arguments: * flag(string) : parameter of VASP see listerMotsClefs() """ # interrogation des dictionnaires if flag in self.allMotsClefs.keys(): valeur = self.allMotsClefs[flag] if self.verbose: print("{0} = {1}".format(flag, valeur)) else: valeur = None print("{0} unknown".format(flag)) return valeur def listerMotsClefs(self): """ Print all paramters of the calculation. see valeurMotClef() """ # mots clefs du fichier INCAR print("# mots clefs du fichier INCAR") ligne = "" for i, flag in enumerate(sorted(self.INCAR.keys())): ligne += flag.rjust(15) + "," if (i % 6 == 0 and i != 0) or i == len(self.INCAR.keys()) - 1: print(ligne) ligne = "" # tous les mots clefs du calcul print("\n# mots clefs du calcul") ligne = "" for i, flag in enumerate(sorted(self.allMotsClefs.keys())): ligne += flag.rjust(15) + "," if (i % 6 == 0 and i != 0) or i == len(self.allMotsClefs.keys()) - 1: print(ligne) ligne = "" def printINCAR(self): """ print INCAR keywords """ print("# fichier INCAR du calcu") ligne = "" for i, flag in enumerate(self.INCAR.keys()): ligne += flag.rjust(10) + " = " + str(self.INCAR[flag]).ljust(10) if (i % 3 == 0 and i != 0) or i == len(self.INCAR.keys()) - 1: print(ligne) ligne = "" def printAtomsData(self): """ print atomic data """ print("\n# system :") print("\t* atom number : " + str(self.Natomes)) print("\t* type number : " + str(self.Ntypes)) ligne = "\t* atom list : " for i in range(self.Natomes): if i != 0 and i % 10 == 0: print(ligne) ligne = "\t " ligne += self.atoms[i].name.rjust(3) + ", " if ligne.strip() != "": print(ligne[:-2]) print("\n# Atom types :") for i in range(self.Ntypes): for atom in self.atoms: if i + 1 == atom.atomType: print(atom) break # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Méthodes pour la DOS # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def lectureDOS(self): """ Lecture de la densité d'états totale et des densités d'états partielles sur le fichier xml du calcul. Après exécution de cette méthode, on dispose de la densité d'états totale dans la liste dosTotale et des densités d'états partielles dans la liste dosPartielles. Les valeurs d'énergies pour lesquelles on dispose des valeurs de la DOS sont dans la liste energiesDOS. Ici <VaspRun> désigne un objet de type VaspRun, les listes crées sont de la forme : <VaspRun>.nptsDos => nombre de valeurs pour la DOS <VaspRun>.energiesDOS[i] i : 0 -> calcul.nptsDos-1 valeurs d'énergies pour lesquelles les DOS sont connues. <VaspRun>.dosTotale[ spin ][ E ][ i ] spin : 0 ou 1, seule la valeur 0 est disponnible pour les calculs avec spin non polarisé (ISPIN = 1). Pour les calculs spin polarisé (ISPIN = 2), spin = 0 donne la DOS pour le spin alpha et spin = 1 pour le spin beta. E : indice de parcours de la DOS pour un spin (valeurs de l'énergie) i : 0 -> 1 i = 0 -> densité d'états i = 1 -> intégrale de la DOS <VaspRun>.dosPartielles[ iat ][ spin ][ E ][ i ] iat : numéro de l'atome spin : 0 ou 1, seule la valeur 0 est disponnible pour les calculs avec spin non polarisé (ISPIN = 1). Pour les calculs spin polarisé (ISPIN = 2), spin = 0 donne la DOS pour le spin alpha et spin = 1 pour le spin beta. E : indice de parcours de la DOS pour un spin (valeurs de l'énergie) i : 0 -> 2 ou 8 valeurs de la DOS sur chaque sous couche ou OA 0 s, 1 p, 2 d 0 s, 1 py, 2 pz, 3 px, 4 dxy, 5 dyz, 6 dz2, 7 dxz, 8 dx2-y2 """ # spin polarise ? ISPIN = self.allMotsClefs["ISPIN"] if self.verbose: print("# Lecture de la densité d'états") # calcul spin polarisé ? print("\t* ISPIN = {0}".format(ISPIN)) # bloc dos fxml = open(self.xmlFile, "r") dos = myxml.getBlocs("dos", fxml, onlyfirst=True) fxml.close() # test presence de la dos if dos == None: print("Pas de densité d'états dans ce calcul") else: if self.verbose: print("\t* densité d'états totale") # niveau de Fermi for ligne in dos: att = myxml.getClefs(ligne, ["name"]) if att["name"] != None and att["name"] == "efermi": self.eFermi = float(myxml.getNodeData(ligne)[0]) print( "\t* Fermi level = {0} eV (warning : accuracy depend on k-points grid)" .format(self.eFermi)) break # DOS TOTALE # lecture de la dos totale blocDosTotale = myxml.getBlocs("total", dos, onlyfirst=True) self.dosTotale = list() self.energiesDOS = list() # cas spin non polarise blocDosTotaleSpin1 = myxml.getBlocs("set", blocDosTotale[1:-1], {"comment": "spin 1"}, True) self.dosTotale.append(list()) for ligne in blocDosTotaleSpin1[1:-1]: valeurs = [float(val) for val in myxml.getNodeData(ligne)] # valeurs[0] est l'energie self.energiesDOS.append(valeurs[0]) self.dosTotale[0].append(valeurs[1:]) if ISPIN == 2: # cas spin polarise blocDosTotaleSpin2 = myxml.getBlocs("set", blocDosTotale[1:-1], {"comment": "spin 2"}, True) self.dosTotale.append(list()) for ligne in blocDosTotaleSpin2[1:-1]: valeurs = [float(val) for val in myxml.getNodeData(ligne)] # valeurs[0] est l'energie self.dosTotale[1].append(valeurs[1:]) self.DOSTotaleLue = True # # DOS PARTIELLES # blocDosPartielle = myxml.getBlocs("partial", dos, onlyfirst=True) if blocDosPartielle == None: print("\t ! pas de densité d'états partielles !") else: if self.verbose: print("\t* densités d'états partielles") self.dosPartielles = list() # boucle sur les atomes du calcul for iat in range(self.Natomes): ion = "ion " + str(iat + 1) blocDosIon = myxml.getBlocs("set", blocDosPartielle, {"comment": ion}, True) self.dosPartielles.append(list()) blocDosIonSpin1 = myxml.getBlocs("set", blocDosIon[1:-1], {"comment": "spin 1"}, True) self.dosPartielles[iat].append(list()) # lecture des dos projetees spin 1 for ligne in blocDosIonSpin1[1:-1]: valeurs = [ float(val) for val in myxml.getNodeData(ligne) ] # valeurs[0] est l'energie self.dosPartielles[iat][0].append(valeurs[1:]) if ISPIN == 2: self.dosPartielles[iat].append(list()) blocDosIonSpin2 = myxml.getBlocs( "set", blocDosIon[1:-1], {"comment": "spin 2"}, True) # lecture des dos projetees spin 2 for ligne in blocDosIonSpin2[1:-1]: valeurs = [ float(val) for val in myxml.getNodeData(ligne) ] # valeurs[0] est l'energie self.dosPartielles[iat][1].append(valeurs[1:]) self.DOSPartiellesLues = True return [self.DOSTotaleLue, self.DOSPartiellesLues] # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Méthodes pour les bandes d'énergies # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def lectureBandes(self): """ Méthode permettant de lire les bandes d'énergie sur le fichier xml du calcul. Après exécution de cette méthode, on dispose des bandes d'énergie dans la liste Bandes sous la forme : <VaspRun>.bandes[ spin ][ point k ][ bandes ][ i ] spin : 0 ou 1, seule la valeur 0 est disponnible pour les calculs avec spin non polarisé (ISPIN = 1). Pour les calculs spin polarisé (ISPIN = 2), spin = 0 donne les bandes pour les spin alpha et spin = 1 pour les spin beta. point k : 0 -> nombre de point K le nombre de point k est calcul.nbrePointsK calcul.nbreLignesPointsK : nombre de directions de points k calcul.Ndivision : nombre de points k par direction Les points k sont listés direction après direction en donnant l'ensemble des points k sur chaque direction bandes : 0 -> NBANDS-1 i : 0 ou 1 i = 0 -> valeurs de l'énergie i = 1 -> occupation de la bande """ # lecture du niveau de fermi fxml = open(self.xmlFile, "r") dos = myxml.getBlocs("dos", fxml, onlyfirst=True) fxml.close() # test presence de la dos if dos == None: print("Density of state and fermi level not found in xml file") self.eFermi = 0.0 else: # niveau de Fermi for ligne in dos: att = myxml.getClefs(ligne, ["name"]) if att["name"] != None and att["name"] == "efermi": self.eFermi = float(myxml.getNodeData(ligne)[0]) break # bloc eigenvalues = bandes d'energie fxml = open(self.xmlFile, "r") eigenvalues = myxml.getBlocs("eigenvalues", fxml, onlyfirst=True) fxml.close() if eigenvalues == None: print("\nerreur : bandes d'énergie introuvable\n") exit(1) # infos sur le calcul NBANDS = self.allMotsClefs["NBANDS"] ISPIN = self.allMotsClefs["ISPIN"] # lecuture des points K self.lecturePointsK() nbreKpoints = len(self.listePointsK) if self.verbose: print("# Lecture des bandes d'énergies") print( "\t* Fermi level = {0} eV (warning accuracy depend on k-points grid)" .format(self.eFermi)) print("\t* ISPIN = {0}".format(ISPIN)) print("\t* nombre de bandes = {0}".format(NBANDS)) print("\t* nombre de points K = {0}".format(nbreKpoints)) setMain = myxml.getBlocs("set", eigenvalues, onlyfirst=True) blocSpin = list() blocSpin.append( myxml.getBlocs("set", setMain, {"comment": "spin 1"}, True)) if ISPIN == 2: blocSpin.append( myxml.getBlocs("set", setMain, {"comment": "spin 2"}, True)) # lecture des bandes self.bands = list() for spin in range(ISPIN): self.bands.append(list()) # boucle sur les points k pour un spin for k in range(nbreKpoints): self.bands[spin].append(list()) kpoint = "kpoint " + str(k + 1) block = myxml.getBlocs("set", blocSpin[spin], {"comment": kpoint}, True) # boucle sur les valeurs des bandes sur un points k for ligne in block: nom = myxml.getNodeName(ligne) if nom == "r": valeurs = [ float(val) for val in myxml.getNodeData(ligne) ] self.bands[spin][k].append(valeurs) if len(self.bands[spin][k]) != NBANDS: print("\nerreur nombre de bandes incorrect\n") exit(1) # controle de lecture self.bandesLues = True return self.bandesLues # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Lecture des points K # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def lecturePointsK(self): """ lit les informations sur les point K du calcul """ # lecture des points k fxml = open(self.xmlFile, "r") kpoints = myxml.getBlocs("kpoints", fxml, onlyfirst=True) fxml.close() # grille de points K generation = myxml.getBlocs("generation", kpoints, onlyfirst=True) if generation == None: self.typePointsK = "explicit" else: att = myxml.getClefs(generation[0], ["param"]) self.typePointsK = att["param"] if self.typePointsK == "listgenerated": ndir = 0 liste = list() for ligne in generation: nom = myxml.getNodeName(ligne) if nom == "i": self.Ndivision = int(myxml.getNodeData(ligne)[0]) if nom == "v": valeurs = [float(val) for val in myxml.getNodeData(ligne)] liste.append(valeurs) ndir += 1 # liste des directions self.directionsPointsK = list() for d in range(ndir - 1): self.directionsPointsK.append(liste[d] + liste[d + 1]) else: print("Explicit K points grid") # kpointlist varray = myxml.getBlocs("varray", kpoints, {"name": "kpointlist"}, True) self.listePointsK = list() for ligne in varray[1:-1]: valeurs = [float(val) for val in myxml.getNodeData(ligne)] self.listePointsK.append(valeurs) if self.typePointsK == "listgenerated": if len(self.directionsPointsK) * self.Ndivision != len( self.listePointsK): raise ValueError("k-points number unconsistent") else: self.directionsPointsK = [ self.listePointsK[0] + self.listePointsK[-1] ] self.Ndivision = len(self.listePointsK) # controle de lecture self.pointsKLues = True return self.pointsKLues # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Lecture de la structure initiale et finale # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def getInitialStructure(self, verbose=True): """ read initial structure """ # read initial pos fxml = open(self.xmlFile, "r") structure = myxml.getBlocs("structure", fxml, {"name": "initialpos"}, True) fxml.close() # read lattice vectors latticeParam = myxml.getBlocs("varray", structure, {"name": "basis"}, True) veca = [float(val) for val in myxml.getNodeData(latticeParam[1])] vecb = [float(val) for val in myxml.getNodeData(latticeParam[2])] vecc = [float(val) for val in myxml.getNodeData(latticeParam[3])] # crystal object self.initialStructure = Crystal(veca = veca, vecb = vecb, vecc = vecc, \ name = "Initial structure : {0}".format(self.xmlFile)) # print lattice parameters if verbose: print("\t* a = %10.5f \t* alpha = %10.3f" % \ (self.initialStructure.a, self.initialStructure.alpha)) print("\t* b = %10.5f \t* beta = %10.3f" % \ (self.initialStructure.b, self.initialStructure.beta) ) print("\t* c = %10.5f \t* gamma = %10.3f" % \ (self.initialStructure.c, self.initialStructure.gamma)) # read reduce coordinates and compute cartesian coordinates positions = myxml.getBlocs("varray", structure, {"name": "positions"}, True) self.initialStructure.Natoms = 0 for ligne in positions[1:-1]: pos = [float(val) for val in myxml.getNodeData(ligne)] self.initialStructure.redCoord.append(pos) self.initialStructure.Natoms += 1 self.initialStructure.computeXYZCoord() if self.initialStructure.Natoms != self.Natomes: print("Natoms : {0}".format(self.Natomes)) print("Structure : {0}".format(self.initialStructure.Natoms)) print("Error : atom number") exit(1) # atom names for iat in range(self.Natomes): self.initialStructure.atomNames.append(self.atoms[iat].name) return self.initialStructure # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def getFinalStructure(self, verbose=True): """ read final structure """ # read final pos fxml = open(self.xmlFile, "r") structure = myxml.getBlocs("structure", fxml, {"name": "finalpos"}, True) fxml.close() if self.verbose: print("\n# Read final structure") if structure == None: # there is not final structure (run not terminated) # <structure>...</structure> print( "\t* Warning: final structure not found, read last one instead" ) fxml = open(self.xmlFile, "r") blocsStructures = myxml.getBlocs("structure", fxml) fxml.close() Nstructures = len(blocsStructures) if Nstructures == 0: # aucune structure ? print( "\nError : there is not any structure in this xml file!\n") exit(1) elif Nstructures == 1: # only one structure => the initial one ligne = blocsStructures[0][0] att = myxml.getClefs(ligne, ["name"]) if att["name"] != None and att["name"] == "initialpos": print("\t* Warning : I found only the initial structure") else: print( "\t* Warning : I found only one structure which is not the initial one ??" ) structure = blocsStructures[0] else: structure = blocsStructures[Nstructures - 1] # read lattice vectors latticeParam = myxml.getBlocs("varray", structure, {"name": "basis"}, True) veca = [float(val) for val in myxml.getNodeData(latticeParam[1])] vecb = [float(val) for val in myxml.getNodeData(latticeParam[2])] vecc = [float(val) for val in myxml.getNodeData(latticeParam[3])] # definition du cristal self.finalStructure = Crystal(veca = veca, vecb = vecb, vecc = vecc, \ name = "Final structure : {0}".format(self.xmlFile)) # print lattice parameters if verbose: print("\t* a = %10.5f \t* alpha = %10.3f" % (self.finalStructure.a, self.finalStructure.alpha)) print("\t* b = %10.5f \t* beta = %10.3f" % (self.finalStructure.b, self.finalStructure.beta)) print("\t* c = %10.5f \t* gamma = %10.3f" % (self.finalStructure.c, self.finalStructure.gamma)) # read reduce coordinates and compute cartesian coordinates positions = myxml.getBlocs("varray", structure, {"name": "positions"}, True) self.finalStructure.Natoms = 0 for ligne in positions[1:-1]: pos = [float(val) for val in myxml.getNodeData(ligne)] self.finalStructure.redCoord.append(pos) self.finalStructure.Natoms += 1 self.finalStructure.computeXYZCoord() if self.finalStructure.Natoms != self.Natomes: print("Natomes : {0}".format(self.Natomes)) print("Structure : {0}".format(self.finalStructure.Natomes)) print("Error : atomic number unconsistant") exit(1) # atom names for iat in range(self.Natomes): self.finalStructure.atomNames.append(self.atoms[iat].name) return self.finalStructure # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Méthodes internes # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def __readKeywords(self): """ read xmlFile and store all keywords and their values """ if self.verbose: print("\t* Read keywords of the run") # # # parameters keywords # bloc parameters fxml = open(self.xmlFile, "r") parameters = myxml.getBlocs("parameters", fxml, onlyfirst=True) fxml.close() # dictionnary des parametres du calcul self.allMotsClefs = {} for ligne in parameters: if "<i" in ligne: nomFlag, valeurFlag = self.__lectureFlag(ligne) self.allMotsClefs[nomFlag] = valeurFlag elif "<v" in ligne: nomFlag, valeurFlag = self.__lectureFlag(ligne, vecteur=True) self.allMotsClefs[nomFlag] = valeurFlag else: continue # # # mots clefs du bloc incar # bloc incar fxml = open(self.xmlFile, "r") incar = myxml.getBlocs("incar", fxml, onlyfirst=True) fxml.close() # dictionnaire INCAR self.INCAR = {} for ligne in incar[1:-1]: if "<i" in ligne: nomFlag, valeurFlag = self.__lectureFlag(ligne) self.INCAR[nomFlag] = valeurFlag elif "<v" in ligne: nomFlag, valeurFlag = self.__lectureFlag(ligne, vecteur=True) self.INCAR[nomFlag] = valeurFlag else: continue self.allMotsClefs = dict(self.allMotsClefs.items() + self.INCAR.items()) # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def __lectureFlag(self, node, vecteur=False): """ lecture d'un parametre du calcul suivant son type """ valeur = myxml.getNodeData(node) # clefs clefs = myxml.getClefs(node, ["type", "name"]) nomFlag = clefs["name"] typeFlag = clefs["type"] if len(valeur) != 0: if typeFlag == "string" or typeFlag == "logical": if vecteur: valeurFlag = " ".join(valeur) else: valeurFlag = valeur[0] elif typeFlag == "int": if vecteur: valeurFlag = " ".join(valeur) else: valeurFlag = int(valeur[0]) elif typeFlag == None: if vecteur: valeurFlag = " ".join(valeur) else: valeurFlag = float(valeur[0]) else: valeurFlag = "empty" return nomFlag, valeurFlag # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * def __readAtomsData(self): """ Read bloc 'atominfo'. It contains the atom list and their description. """ if self.verbose: print("\t* Read atom data") # on recupere le bloc atominfo fxml = open(self.xmlFile, "r") atominfo = myxml.getBlocs("atominfo", fxml, onlyfirst=True) fxml.close() # nombre d'atomes et nombre de types i = 0 for ligne in atominfo: if "<atoms>" in ligne: self.Natomes = int(myxml.getNodeData(ligne)[0]) i += 1 if "<types>" in ligne: self.Ntypes = int(myxml.getNodeData(ligne)[0]) i += 1 if i == 2: break # atom list self.atoms = list() # read atom type lignesArrayTypes = myxml.getBlocs("array", atominfo, {"name": "atomtypes"}, True) self.typesAtomes = list() debutListe = False for ligne in lignesArrayTypes: if "<set>" in ligne: debutListe = True continue if "</set>" in ligne: break if debutListe: ligne = ligne.replace("<rc><c>", "") ligne = ligne.replace("</c></rc>", "") valeurs = ligne.split("</c><c>") tmpdic = {"nom":valeurs[1].strip(), "masse":float(valeurs[2]), \ "valence":float(valeurs[3]), "pseudo":valeurs[4] } self.typesAtomes.append(tmpdic) # lecture des atomes lignesArrayAtomes = myxml.getBlocs("array", atominfo, {"name": "atoms"}, True) debutListe = False for ligne in lignesArrayAtomes: if "<set>" in ligne: debutListe = True continue if "</set>" in ligne: break if debutListe: ligne = ligne.replace("<rc><c>", "") ligne = ligne.replace("</c></rc>", "") valeurs = ligne.split("</c><c>") nom = valeurs[0].strip() typ = int(valeurs[1]) if nom != self.typesAtomes[typ - 1]["nom"]: print("non concordance nom / type ") exit(1) atom = Atom(name = self.typesAtomes[typ-1]["nom"], \ atomType = typ, \ Ne = self.typesAtomes[typ-1]["valence"], \ w = self.typesAtomes[typ-1]["masse"], \ pseudo = self.typesAtomes[typ-1]["pseudo"] ) self.atoms.append(atom)