예제 #1
0
def cluster_from_grs(filename, rI, rII, new_rI=None, r=None):
    '''Reads in the .grs file output after a successful cluster-based dislocation
    simulation and use it to construct a <TwoRegionCluster>. <new_rI> allows 
    us to change the size of region I, whether by enlarging or reducing it.
    '''

    # read in the .grs file and convert it to cartesian coordinates
    grs_struc = cry.Crystal()
    sysinfo = parse_gulp(filename, grs_struc)

    for atom in grs_struc:
        # arrange coords in order x, y, z
        atom.from_cluster()
        # convert z from pcell units to length units
        atom.to_cart(grs_struc)

    # determine the region I radius to use for the new cluster
    if new_rI is None:
        new_rI = rI
    else:
        # check that <new_rI> is not ridiculous
        if new_rI >= rII:
            raise ValueError(
                "New region I radius must be less than total radius.")

    # create the cluster
    height = norm(grs_struc.getC())
    new_cluster = rs.TwoRegionCluster(R=rI,
                                      regionI=new_rI,
                                      regionII=rII,
                                      height=height,
                                      periodic_atoms=grs_struc)

    return new_cluster, sysinfo
예제 #2
0
def read_unit_cell(cellname, program, shift, permutation=[0, 1, 2], path='./'):
    '''Reads in the unit from which the dislocation-bearing cluster will be 
    built.
    '''

    # read in cell using the program-appropriate parse function
    basestruc = cry.Crystal()
    if program == 'gulp':
        parse_fn = parse_gulp
    elif program == 'qe':
        parse_fn = parse_qe
    elif program == 'castep':
        parse_fn = parse_castep
    else:
        raise ValueError("Program {} not supported.".format(program))

    sinfo = parse_fn(cellname, basestruc, path=path)

    if len(shift) < 3:
        # create 3-vector, populating first n elements from shift
        new_shift = np.zeros(3)
        for i in range(len(shift)):
            new_shift[i] = shift[i]
        shift = new_shift

    basestruc.translate_cell(np.array(shift), modulo=True)

    # permute the coordinates of the unit cell. Usually necessary as the glide
    # plane normal is usually aligned along z for GSF calculations, whereas here
    # it should be along y
    permute.check_permutation(permutation)
    permute.permute_cell(basestruc, program, permutation)

    return basestruc
예제 #3
0
def perfect_bonds(cellname,
                  atom_index,
                  max_bond_length,
                  use_species=False,
                  bonded_type=None):
    '''Extracts all bonds between atom <atom_index> and adjacent atoms of type 
    <atom_type> out to the given 
    distance in the undeformed crystal <cellname>.
    '''

    # read in crystal structure
    unit_cell = cry.Crystal()
    sinfo = gulp.parse_gulp(cellname, unit_cell)

    # extract the coordinates of the atom specified and convert to angstroms
    atom0 = unit_cell[atom_index]
    x0 = atom0.getCoordinates()
    lattice = unit_cell.getLattice()
    x0 = x0[0] * lattice[0] + x0[1] * lattice[1] + x0[2] * lattice[2]

    # if <bonded_type> is not given, assume that we are calculating the Nye
    # tensor on the sublattice to which <atom_index> belongs
    if bonded_type is None:
        bonded_type = atom0.getSpecies()

    # extract bonds
    P = []
    for i in range(len(unit_cell)):
        # check that atom i is of the correct species
        if use_species:
            if unit_cell[i].getSpecies() != bonded_type:
                continue

        # convert coordinates of atom <i> to angstroms
        y0 = unit_cell[i].getCoordinates()
        y0 = y0[0] * lattice[0] + y0[1] * lattice[1] + y0[2] * lattice[2]

        # iterate through all periodic images of the cell that share a face,
        # edge, or corner with the original cell
        for j in range(-1, 2):
            for k in range(-1, 2):
                for l in range(-1, 2):
                    # check that this is not the original atom
                    if i == atom_index and (j == k == l == 0):
                        continue

                    # calculate and store the bond vector from <atom_index> to
                    # this site
                    y = y0 + j * lattice[0] + k * lattice[1] + l * lattice[2]
                    if norm(x0 - y) < max_bond_length:
                        P.append(x0 - y)

    return P
예제 #4
0
def bond_candidates_sc(dis_cell,
                       atom_type,
                       max_bond_length,
                       use_species=False,
                       bonded_type=None):
    '''Extracts candidate bonds for atoms in a 3D-periodic supercell, which may
    contain topological defects
    '''

    if bonded_type is None:
        # use <atom_type> sublattice
        bonded_type = atom_type

    # extract cell parameters of <discell>
    dis_sc = cry.Crystal()
    sinfo = gulp.parse_gulp(dis_cell, dis_sc)
    lattice = dis_sc.getLattice()

    Qpot = dict()
    for i in range(dis_sc.numberOfAtoms):
        if use_species:
            atomspecies = dis_sc[i].getSpecies()
            if atomspecies != atom_type:
                continue

        # extract coordinates of atom i (in \AA, a.u., etc.)
        xi = dis_sc[i].getCoordinates()
        xi = xi[0] * lattice[0] + xi[1] * lattice[1] + xi[2] * lattice[2]
        # search neighbouring atoms
        Qpoti = []
        for j in range(dis_sc.numberOfAtoms):
            # extract coordinates and convert from fractional to cartesian
            xj0 = dis_sc[j].getCoordinates()
            xj0 = xj0[0] * lattice[0] + xj0[1] * lattice[1] + xj0[2] * lattice[
                2]
            # iterate through periodic images of atom j
            for l in range(-1, 2):
                for m in range(-1, 2):
                    for n in range(-1, 2):
                        if j == i and (l == 0 and m == 0 and n == 0):
                            # original atom, skip
                            continue

                        xj = xj0 + l * lattice[0] + m * lattice[
                            1] + n * lattice[2]

                        if norm(xi - xj) < max_bond_length:
                            Qpoti.append([j, xi - xj])

        Qpot[i] = [xi, Qpoti]

    return Qpot
    def make_supercell(self):  #NEW
        '''Constructs the supercell that will be used in subsequent simulations.
        '''

        base_sc = cry.Crystal()  #NEW
        self.sysinfo = gulp.parse_gulp(self.control('dislocation_file'),
                                       base_sc)  #NEW

        # extend normal to dislocation line
        self.supercell = cry.superConstructor(base_sc,
                                              np.array(
                                                  [1., 1.,
                                                   self.control('n')]))  #NEW
예제 #6
0
def main():
    '''Make supercell. This is just a utility script for personal use, so we'll
    hard code all of the parameters.
    
    CURRENT_VERSION: GULP
    '''

    options = input_options()
    args = options.parse_args()

    base_struc = cry.Crystal()
    ab_initio = False
    if args.prog == 'gulp':
        read_fn = gulp.parse_gulp
        write_fn = gulp.write_gulp
    elif args.prog == 'qe':
        read_fn = qe.parse_qe
        write_fn = qe.write_qe
        ab_initio = True
    elif args.prog == 'castep':
        read_fn = castep.parse_castep
        write_fn = castep.write_castep
        ab_initio = True
    else:
        raise ValueError(
            "{} is not a supported atomistic simulation code".format(
                args.prog))

    sys_info = read_fn(args.unitcell, base_struc)
    if ab_initio:
        atm.scale_kpoints(sys_info['cards']['K_POINTS'], np.array(args.dims))
        if args.prog == 'qe':
            qe.scale_nbands(sys_info['namelists']['&system'],
                            np.array(args.dims))

    supercell = cry.superConstructor(base_struc, np.array(args.dims))

    outstream = open(args.supercell_name, 'w')
    write_fn(outstream,
             supercell,
             sys_info,
             defected=False,
             do_relax=args.relax,
             relax_type=args.calc_type,
             prop=args.prop,
             to_cart=False)
예제 #7
0
def main():
    '''Read in and permute structure.
    '''

    options = input_options()
    args = options.parse_args()

    base_struc = cry.Crystal()
    ab_initio = False
    if args.prog == 'gulp':
        read_fn = gulp.parse_gulp
        write_fn = gulp.write_gulp
    elif args.prog == 'qe':
        read_fn = qe.parse_qe
        write_fn = qe.write_qe
        ab_initio = True
    elif args.prog == 'castep':
        read_fn = castep.parse_castep
        write_fn = castep.write_castep
        ab_initio = True
    else:
        raise ValueError(
            "{} is not a supported atomistic simulation code".format(
                args.prog))

    sys_info = read_fn(args.input_struc, base_struc)

    # check permutation and permute coordinates
    check_permutation(args.perm)
    permute_cell(base_struc, args.prog, args.perm)

    if ab_initio:
        # permute order of k-points
        permute_kgrid(sys_info['cards']['K_POINTS'], args.perm)

    # write to output
    if args.output_name:
        ostream = open(args.output_name, 'w')
    else:  # overwrite input file
        ostream = open(args.input_struc, 'w')

    write_fn(ostream, base_struc, sys_info, to_cart=False)

    return
예제 #8
0
def excess_energy_edge(energy_grid, Edict, parse_fn, in_suffix):
    '''Calculate the excess energy due to the presence of a dislocation multipole
    by subtracting from the energy of a dislocated cell the energies of all its
    atoms calculated individually in the reference (i.e. undislocated) state.
    '''

    for discell in energy_grid:
        # extract atoms in simulation cell
        temp_crystal = cry.Crystal()
        sysinfo = parse_fn('{}.{}'.format(discell[-1], in_suffix),
                           temp_crystal)

        # calculate total energy of atoms in cell if no dislocations were present
        Eperf = 0.
        for atom in temp_crystal:
            Eperf += Edict[atom.getSpecies()]

        E_excess.append([discell[0], discell[1], discell[2] - Eperf])

    return E_excess
예제 #9
0
def main():
    '''Controller program.
    '''
    
    if not sys.argv[1:]:
        # test to see if command line options have been passed. If they have
        # not, start interactive prompt
        args = manual_options()
    elif len(sys.argv[1:]) == 1:
        # assume that the user is providing the name of an input file
        args = read_control(sys.argv[1])
    else:
        # parse arguments
        options = command_line_options()
        args = options.parse_args()
        if args.control:
            # read simulation parameters from control file
            args = read_control(args.control)
        else:
            pass
            
    # make sure that the atomic simulation code specified by the user is supported
    if args.prog.lower() in supported_codes:
        pass
    else:
        raise ValueError("{} is not a supported atomistic simulation code." +
                         "Supported codes are: GULP; QE; CASTEP.")

    # extract unit cell and GULP run parameters from file <cell_name>
    ab_initio = False   
    if 'gulp' == args.prog.lower():
        unit_cell = cry.Crystal()
        parse_fn = gulp.parse_gulp
    elif 'qe' == args.prog.lower():
        unit_cell = cry.Crystal()
        parse_fn = qe.parse_qe
        ab_initio = True
    elif 'castep' == args.prog.lower():
        unit_cell = castep.CastepCrystal()
        parse_fn = castep.parse_castep
        ab_initio = True
        
    sys_info = parse_fn(args.cell_name, unit_cell)

    # if the calculation uses an ab initio solver, scale the k-point grid
    if ab_initio:
        if 'qe' == args.prog.lower():
            atm.scale_kpoints(sys_info['cards']['K_POINTS'], 
                              np.array([1., 1., args.n]))
            qe.scale_nbands(sys_info['namelists']['&system'], np.array([1., 1., args.n]))
        elif 'castep' == args.prog.lower():
            atm.scale_kpoints(sys_info['mp_kgrid'], np.array([1., 1., args.n]))
    
    # shift origin of cell
    unit_cell.translate_cell(np.array([0., 0., -1*args.shift]), modulo=True)
    
    # select output mode appropriate for the atomistic calculator used, together
    # with the correct suffix for the input files (may be better to let the 
    # output functions determine the suffix?)
    if 'gulp' == args.prog.lower():
        write_fn = gulp.write_gulp
        suffix = 'gin'
        relax = None
    elif 'qe' == args.prog.lower():
        write_fn = qe.write_qe
        suffix = 'in'
        relax = 'relax'
    elif 'castep' == args.prog.lower():
        write_fn = castep.write_castep
        suffix = 'cell'
        relax = None
    
    # make the slab and construct the gamma surface/line
    new_slab = gsf.make_slab(unit_cell, args.n, args.vac, d_fix=args.d_fix, 
                                                 free_atoms=args.free_atoms)
    if args.simulation_type == 'gsurface':
        limits = (args.max_x, args.max_y)          
        gsf.gamma_surface(new_slab, args.res, write_fn, sys_info, suffix=suffix,
                          limits=limits, basename=args.sim_name, vacuum=args.vac,
                                                                    relax=relax)    
        
        # run the calculations, if an executable has been provided. Otherwise,
        # assume that that the input files will be transferred to another machine
        # and run by the user.
        if not (args.progexec is None):
            # extract increments
            N, M = gsf.gs_sampling(new_slab.getLattice(), args.res, limits)
            for n in range(0, N+1):
                for m in range(0, M+1):
                    print("Relaxing cell with generalized stacking fault vector" +
                            " ({}, {})...".format(n, m), end="")
                    basename = '{}.{}.{}'.format(args.sim_name, n, m)
                    if 'gulp' == args.prog.lower():
                        gulp.run_gulp(args.progexec, basename) 
                    elif 'qe' == args.prog.lower():
                        qe.run_qe(args.progexec, basename)
                    elif 'castep' == args.prog.lower():
                        castep.run_castep(args.progexec, basename)
                    
                    print("complete.") 
        else:
            pass
    elif args.simulation_type == 'gline':      
        gsf.gamma_line(new_slab, np.array(args.line_vec), args.res, write_fn,  
                           sys_info, suffix=suffix, limits=args.max_x,  
                           basename=args.sim_name, vacuum=args.vac, relax=relax)
        
        if not (args.progexec is None):
            # extract limits
            N = gsf.gl_sampling(new_slab.getLattice(), resolution=args.res, 
                            vector=np.array(args.line_vec), limits=args.max_x)
            # run calculations
            for n in range(0, N+1):
                print("Relaxing cell {}...".format(n), end="")
                basename = '{}.{}'.format(args.sim_name, n)
                if 'gulp' == args.prog.lower():
                    gulp.run_gulp(args.progexec, basename)
                elif 'qe' == args.prog.lower():
                    qe.run_qe(args.progexec, basename)
                elif 'castep' == args.prog.lower():
                    castep.run_castep(args.progexec, basename)

                print("complete.")
        else:
            pass
    else:
        pass