示例#1
0
    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!")
示例#3
0
 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)
示例#4
0
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
示例#5
0
    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")
示例#6
0
    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
示例#7
0
    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)
示例#8
0
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)
示例#9
0
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
示例#10
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)
示例#11
0
    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
示例#12
0
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)
示例#13
0
    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
示例#14
0
    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
示例#15
0
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)