Exemplo n.º 1
0
def cost_function(pos, dislo, bulk, cylinder_r, elastic_param,
                  print_info=True):
    """Cost function for fitting analytical displacement field
       and detecting dislcoation core position. Uses `compare_configurations`
       function for the minisation of the core position.

    Parameters
    ----------
    pos : list of float
        Positions of the core to build the analytical solution [x, y].
    dislo : ase.Atoms
        Dislocation configuration.
    bulk : ase.Atoms
        Corresponding bulk configuration for calculation of displacements.
    cylinder_r : float or None
        Radius of region of comparison around the dislocation coreself.
        If None makes global comparison based on the radius of
        `dislo` configuration, else compares the regions with `cylinder_r`
        around the dislocation core position.
    elastic_param : list of float
        List containing alat, C11, C12, C44
    print_info : bool
        Flag to switch print statement about the type of the comparison

    Returns
    -------
    float
        Error for optimisation (result from `compare_configurations` function)

    """


    # Create a Stroh ojbect with junk data
    stroh = am.defect.Stroh(am.ElasticConstants(C11=141, C12=110, C44=98),
                            np.array([0, 0, 1]))

    axes = np.array([[1, 1, -2],
                    [-1, 1, 0],
                    [1, 1, 1]])

    alat, C11, C12, C44 = elastic_param

    c = am.ElasticConstants(C11=C11, C12=C12, C44=C44)
    burgers = alat * np.array([1., 1., 1.])/2.

    # Solving a new problem with Stroh.solve
    stroh.solve(c, burgers, axes=axes)

    center = (pos[0], pos[1], 0.0)
    u = stroh.displacement(bulk.positions - center)

    dislo_guess = bulk.copy()
    dislo_guess.positions += u

    err = compare_configurations(dislo, bulk,
                                 dislo_guess, bulk,
                                 alat, cylinder_r=cylinder_r,
                                 print_info=print_info)

    return err
Exemplo n.º 2
0
    def intro_edge(self):
        self.find_angles_1100(il=[[1], [1]], jl=[1])    # 58.361
        ux = self.pot['ahcp']
        uy = self.pot['chcp']
        uz = self.pot['ahcp'] * sqrt(3.)
        atoms = ase.io.read("dump/dump.00017", format='lammps-dump')

        atoms.rotate(self.ag[0][0], 'z')  # rotate
        atoms.translate(np.array([80 * ux, 0.0, 0]))
        # # introduce dislocation
        axes = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0])
        c = am.ElasticConstants()
        c.hexagonal(C11=self.pot['C11'], C12=self.pot['C12'],
                    C33=self.pot['C33'], C13=self.pot['C13'], C44=self.pot['C44'])
        stroh = stroh_solve.Stroh(c, burgers, axes=axes)
        pos = atoms.get_positions()
        cx = 60 * ux + 0.01
        cy = 60 * uy + 0.01
        shift = np.ones(pos.shape) * np.array([cx, cy, 0.0])
        disp = stroh.displacement(pos - shift)
        atoms.set_positions(pos + np.real(disp))

        atoms.translate(np.array([-80 * ux, 0.0, 0]))
        atoms.rotate(-self.ag[0][0], 'z')  # rotate back

        # try with non periodict boundary conditions
        cell = atoms.get_cell()
        cell[0, 0] += 30
        cell[1, 1] += 30
        atoms.translate(np.array([15, 15, 0.0]))
        atoms.set_cell(cell)
        # ase.io.write("pos02", images=atoms, format='cfg')
        self.write_lmp_config_data(atoms, "pos02")
Exemplo n.º 3
0
    def build_screw_basal_hcp_atoms_dipole(self, atoms):
        axes = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0])

        c = am.ElasticConstants()
        c.hexagonal(C11=64.3218889159844,
                    C33=70.9452244231304,
                    C12=25.4175328222502,
                    C13=20.306421440903,
                    C44=18.0690056385527)  # curtin

        stroh1 = stroh_solve.Stroh(c, burgers, axes=axes)
        # stroh2 = stroh_solve.Stroh(c, -burgers, axes=axes)

        cell = atoms.get_cell()
        pos = atoms.get_positions()

        cx = 0.25 * cell[0, 0] + 0.01
        cy1 = 0.25 * cell[1, 1] + 0.01
        cy2 = 0.75 * cell[1, 1] + 0.01

        pos = atoms.get_positions()
        print(cy1, cy2)

        shift1 = np.ones(pos.shape) * np.array([cx, cy1, 0.0])
        shift2 = np.ones(pos.shape) * np.array([cx, cy2, 0.0])

        disp1 = stroh1.displacement(pos - shift1)
        disp2 = stroh1.displacement(pos - shift2)

        # atoms.set_positions(pos + np.real(disp1))
        atoms.set_positions(pos + np.real(disp1) - np.real(disp2))
        return atoms
Exemplo n.º 4
0
    def hcp_edge_dislocation(self):
        sz = (40, 40, 10)
        atoms = othoHCP(latticeconstant=(self.pot['ahcp'], self.pot['chcp'],
                                         self.pot['ahcp'] * sqrt(3.)),
                        size=sz,
                        symbol=self.pot['element'])

        # let the axes consistent with the elastic constants
        axes = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0])
        c = am.ElasticConstants()

        # the lattice constant has conventional direction as
        # x - [1 -2 1 0]  y[1, 0, -1, 0] z [0, 0, 0, 1]
        c.hexagonal(C11=61.8, C33=67.5, C12=25.9, C13=21.9, C44=18.2)  # kim
        stroh = stroh_solve.Stroh(c, burgers, axes=axes)
        pos = atoms.get_positions()

        cx = 20 * self.pot["ahcp"] + 0.01
        cy = 20 * self.pot["chcp"] + 0.01
        s1 = np.ones(pos.shape) * np.array([cx, cy, 0.0])
        d1 = stroh.displacement(pos - s1)

        # cy = 60 * self.pot["chcp"] - 0.01
        # s2 = np.ones(pos.shape) * np.array([cx, cy, 0.0])
        # d2 = stroh.displacement(pos - s2)
        atoms.set_positions(pos + np.real(d1))

        # cut a layer normal the burger direction
        # atoms = self.cut_x_normal_atoms(atoms, lata, 1, sqrt(3) / 4.0)
        # atoms = self.cut_x_normal_atoms(atoms)
        atoms = self.cut_y_normal_atoms(atoms)
        atoms = self.cut_x_normal_atoms(atoms)
        self.write_lmp_config_data(atoms)
Exemplo n.º 5
0
    def build_screw_basal_hcp_atoms(self, atoms):
        axes = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0])
        c = am.ElasticConstants()

        # the lattice constant has conventional direction as
        # x - [1 -2 1 0]  y[1, 0, -1, 0] z [0, 0, 0, 1]
        # c.hexagonal(C11=61.8, C33=67.5, C12=25.9, C13=21.9, C44=18.2)  # kim
        c.hexagonal(C11=64.3218889159844,
                    C33=70.9452244231304,
                    C12=25.4175328222502,
                    C13=20.306421440903,
                    C44=18.0690056385527)  # curtin

        stroh = stroh_solve.Stroh(c, burgers, axes=axes)

        cell = atoms.get_cell()
        cx = 0.25 * cell[0, 0] + 0.01
        cy = 0.50 * cell[1, 1] + 0.01

        pos = atoms.get_positions()
        shift = np.ones(pos.shape) * np.array([cx, cy, 0.0])
        disp = stroh.displacement(pos - shift)
        atoms.set_positions(pos + np.real(disp))

        # pos = atoms.get_positions()
        # shiftN = np.ones(pos.shape) * np.array([cx + 0.5 * cell[0, 0],
        #                                         cy, 0.0])
        # dispN = stroh.displacement(pos - shiftN)
        # atoms.set_positions(pos + np.real(dispN))
        return atoms
Exemplo n.º 6
0
    def load_model(self, model, name=None):
        """
        Loads record contents from a given model.

        Parameters
        ----------
        model : str or DataModelDict
            The model contents of the record to load.
        name : str, optional
            The name to assign to the record.  Often inferred from other
            attributes if not given.
        """
        # Load universal and subset content
        super().load_model(model, name=name)
        calc = self.model[self.modelroot]

        # Load calculation-specific content
        run_params = calc['calculation']['run-parameter']
        self.strainrange = run_params['strain-range']

        # Load results
        if self.status == 'finished':
            self.__raw_Cij_negative = uc.value_unit(calc['raw-elastic-constants'][0]['Cij'])
            self.__raw_Cij_positive = uc.value_unit(calc['raw-elastic-constants'][1]['Cij'])
            Cij = uc.value_unit(calc['elastic-constants']['Cij'])
            self.__C = am.ElasticConstants(Cij=Cij)
Exemplo n.º 7
0
 def load_model(self, model):
     """Loads subset attributes from an existing model."""
     try:
         c_model = DM([('elastic-constants', model[self.modelroot])])
     except:
         self.__C = None
     else:
         self.__C = am.ElasticConstants(model=c_model)
Exemplo n.º 8
0
    def fcc_edge(self):
        axes = np.array([[1, 0, -1], [1, 1, 1], [1, -2, 1]])

        alat = uc.set_in_units(4.0248, 'angstrom')

        C11 = uc.set_in_units(113.76, 'GPa')
        C12 = uc.set_in_units(61.71, 'GPa')
        C44 = uc.set_in_units(31.25, 'GPa')

        c = am.ElasticConstants(C11=C11, C12=C12, C44=C44)
        burgers = alat / 2 * np.array([1., 0., -1.])

        # initializing a new Stroh object using the data
        stroh = am.defect.Stroh(c, burgers, axes=axes)

        pos_test = uc.set_in_units(np.array([12.4, 13.5, -10.6]), 'angstrom')

        disp = stroh.displacement(pos_test)

        print("displacement =", uc.get_in_units(disp, 'angstrom'), 'angstrom')

        # monopole system
        box = am.Box(a=alat, b=alat, c=alat)
        atoms = am.Atoms(natoms=4,
                         prop={
                             'atype':
                             1,
                             'pos': [[0.0, 0.0, 0.0], [0.5, 0.5, 0.0],
                                     [0.0, 0.5, 0.5], [0.5, 0.0, 0.5]]
                         })
        ucell = am.System(atoms=atoms, box=box, scale=True)
        system = am.rotate_cubic(ucell, axes)

        shift = np.array(
            [0.12500000000000, 0.50000000000000, 0.00000000000000])
        new_pos = system.atoms_prop(key='pos', scale=True) + shift
        system.atoms_prop(key='pos', value=new_pos, scale=True)

        system.supersize((-7, 7), (-6, 6), (0, 1))
        disp = stroh.displacement(system.atoms_prop(key='pos'))

        system.atoms_prop(key='pos', value=system.atoms_prop(key='pos') + disp)

        system.pbc = (False, False, True)
        system.wrap()

        pos = system.atoms_prop(key='pos')
        x = uc.get_in_units(pos[:, 0], 'angstrom')
        y = uc.get_in_units(pos[:, 1], 'angstrom')

        plt.figure(figsize=(8, 8))
        plt.scatter(x, y, s=30)
        plt.xlim(min(x), max(x))
        plt.ylim(min(y), max(y))
        plt.xlabel('x-position (Angstrom)', fontsize='large')
        plt.ylabel('y-position (Angstrom)', fontsize='large')
        plt.show()
Exemplo n.º 9
0
def estimate_elastic_constants(raw_dict):
    """Computes elastic constants using the calculation data."""
    
    results_dict = {}
    
    # Copy the zero strain data to results_dict
    results_dict.update(raw_dict['0'])
    
    # Initialize cij and cij_std arrays
    cij = np.empty((6,6))
    cij_std = np.zeros((6,6))
    
    # Relate the simulation states to strain components
    all_eps = [['xx+', 'xx-'], ['yy+', 'yy-'], ['zz+', 'zz-'], ['yz+', 'yz-'], ['xz+', 'xz-'], ['xy+', 'xy-']]
    
    # Iterate over strain components
    for i, eps in enumerate(all_eps):
        
        # Calculate elastic constants
        delta_strain = raw_dict[eps[0]]['strain'][i] - raw_dict[eps[1]]['strain'][i]
        print delta_strain
        delta_stress = - np.array([ raw_dict[eps[0]]['pxx'][0] - raw_dict[eps[1]]['pxx'][0], 
                                    raw_dict[eps[0]]['pyy'][0] - raw_dict[eps[1]]['pyy'][0], 
                                    raw_dict[eps[0]]['pzz'][0] - raw_dict[eps[1]]['pzz'][0], 
                                    raw_dict[eps[0]]['pyz'][0] - raw_dict[eps[1]]['pyz'][0], 
                                    raw_dict[eps[0]]['pxz'][0] - raw_dict[eps[1]]['pxz'][0], 
                                    raw_dict[eps[0]]['pxy'][0] - raw_dict[eps[1]]['pxy'][0] ])
        print np.array_str(delta_stress, precision=4, supress_small=True)
        cij[i] = delta_stress / delta_strain
        
        # Calculate error
        cij_std[i] = np.array([ raw_dict[eps[0]]['pxx'][1]**2 + raw_dict[eps[1]]['pxx'][1]**2,
                                raw_dict[eps[0]]['pyy'][1]**2 + raw_dict[eps[1]]['pyy'][1]**2,
                                raw_dict[eps[0]]['pzz'][1]**2 + raw_dict[eps[1]]['pzz'][1]**2,
                                raw_dict[eps[0]]['pyz'][1]**2 + raw_dict[eps[1]]['pyz'][1]**2,
                                raw_dict[eps[0]]['pxz'][1]**2 + raw_dict[eps[1]]['pxz'][1]**2,
                                raw_dict[eps[0]]['pxy'][1]**2 + raw_dict[eps[1]]['pxy'][1]**2 ])**0.5 / delta_strain

    print
    print np.array_str(cij, precision=4, suppress_small=True)
    print np.array_str(cij_std, precision=4, suppress_small=True)
    
    # Average symmetric terms
    for i in xrange(6):
        for j in xrange(i):
            cij[i,j] = cij[j,i] = (cij[i,j] + cij[j,i]) / 2
            cij_std[i,j] = cij_std[j,i] = (cij_std[i,j] + cij_std[j,i]) / 2
    print
    print np.array_str(cij, precision=4, suppress_small=True)
    print np.array_str(cij_std, precision=4, suppress_small=True)
            
    results_dict['C'] = am.ElasticConstants(Cij=cij)
    results_dict['cij_std'] = cij_std
    
    return results_dict
Exemplo n.º 10
0
    def make_screw_plate(self,
                         size=[70, 90, 3],
                         rad=[150, 160],
                         move=[0., 0., 0.],
                         filename="lmp_init.txt",
                         opt=None):
        e1 = [1, -2, 1]
        e2 = [1, 0, -1]
        e3 = [1, 1, 1]
        axes = np.array([e1, e2, e3])
        alat = self.pot['lattice']
        c = am.ElasticConstants(C11=self.pot['c11'],
                                C12=self.pot['c12'],
                                C44=self.pot['c44'])
        ux = np.sqrt(6) / 3. * self.pot['lattice']
        uy = np.sqrt(2) / 2. * self.pot['lattice']

        burgers = 0.5 * alat * np.array([1., 1., 1.])
        stroh = am.defect.Stroh(c, burgers, axes=axes)

        atoms = self.set_bcc_convention([e1, e2, e3],
                                        (size[0], size[1], size[2]))
        pos = atoms.get_positions()

        center = np.array([3 * 0.5 * size[0] * ux, size[1] * uy])

        delindex = []
        radius2 = rad[0] * rad[0]
        radiusout2 = rad[1] * rad[1]
        for i in range(len(pos)):
            atom = atoms[i]
            dx = pos[i, 0] - center[0]
            dy = pos[i, 1] - center[1]
            r = dx * dx + dy * dy
            if r > radiusout2:
                delindex.append(atom.index)
            if r < radius2:
                # atom.symbol = 'W'
                continue
        del atoms[delindex]

        pos = atoms.get_positions()
        discenter = np.array(
            [center[0] + 0.5 * ux, center[1] + 1. / 3. * uy, 0.0])
        shf = np.ones(pos.shape) * discenter
        print(pos - shf)
        d1 = stroh.displacement(pos - shf)

        # before displace generate perfect atoms
        self.write_lmp_config_data(atoms, 'lmp_perf.txt')
        atoms.set_positions(pos + np.real(d1))
        self.write_lmp_config_data(atoms, 'lmp_init.txt')
        np.savetxt("dis_center.txt", discenter)
Exemplo n.º 11
0
    def build_hcp_ase_1100_with_edge(self):
        self.find_angles_1100(il=[[1], [1]], jl=[1])  # 58.361
        ux = self.pot['ahcp']
        uy = self.pot['chcp']
        uz = self.pot['ahcp'] * sqrt(3.)

        print(self.ag)
        atoms = othoHCP(latticeconstant=(ux, uy, uz),
                        size=(80, 80, 2),
                        symbol=self.pot['element'])

        # introduce dislocation
        axes = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0])
        c = am.ElasticConstants()
        c.hexagonal(C11=self.pot['C11'],
                    C12=self.pot['C12'],
                    C33=self.pot['C33'],
                    C13=self.pot['C13'],
                    C44=self.pot['C44'])

        stroh = stroh_solve.Stroh(c, burgers, axes=axes)
        pos = atoms.get_positions()

        cell = atoms.get_cell()
        cell[0, 0], cell[1, 1] = 8 * self.ag[0][1], 300

        cx = 30 * ux + 0.01
        cy = 30 * uy + 0.01

        shift = np.ones(pos.shape) * np.array([cx, cy, 0.0])
        disp = stroh.displacement(pos - shift)
        atoms.set_positions(pos + np.real(disp))

        atoms.rotate(self.ag[0][0], 'z')
        atoms.translate(np.array([cell[0, 0], -100, 0]))
        lob = np.array([0.0, 10, 0.0])
        hib = np.array([cell[0, 0], 0.5 * cell[1, 1] + 0.3, cell[2, 2]])
        atoms = self.make_cubic('out', atoms, lob, hib)
        atoms2 = othoHCP(latticeconstant=(ux, uy, uz),
                         size=(80, 80, 2),
                         symbol=self.pot['element'])

        lob = np.array([0.0, 0.5 * cell[1, 1], 0.0])
        hib = np.array([cell[0, 0], cell[1, 1] - 10, cell[2, 2]])
        atoms2.rotate(-self.ag[0][0], 'z')
        atoms2.translate(np.array([-90, cell[1, 1], 0]))  # for 72.877
        atoms2 = self.make_cubic('out', atoms2, lob, hib)
        atoms.extend(atoms2)

        # try with non periodict boundary conditions
        atoms.set_cell(cell)
        self.write_lmp_config_data(atoms, "lmp_init.txt")
Exemplo n.º 12
0
    def cal_screw_const(self, tag='intro'):
        axes = np.array([[1, 1, -2], [-1, 1, 0], [1, 1, 1]])

        alat = uc.set_in_units(self.pot['lattice'], 'angstrom')
        C11 = uc.set_in_units(self.pot['c11'], 'GPa')
        C12 = uc.set_in_units(self.pot['c12'], 'GPa')
        C44 = uc.set_in_units(self.pot['c44'], 'GPa')

        c = am.ElasticConstants(C11=C11, C12=C12, C44=C44)
        burgers = alat / 2 * np.array([1., 1., 1.])

        stroh = am.defect.Stroh(c, burgers, axes=axes)
        print("K tensor", stroh.K_tensor)
        print("K (biKijbj)", stroh.K_coeff, "eV/A")
        print("pre-ln alpha = biKijbj/4pi", stroh.preln, "ev/A")
Exemplo n.º 13
0
    def build_screw_basal_hcp(self):
        sz = (100, 100, 5)
        ux = self.pot["ahcp"] * sqrt(3)
        uy = self.pot["chcp"]
        uz = self.pot['ahcp']

        atoms = othoHCPB(latticeconstant=(ux, uy, uz),
                         size=sz,
                         symbol=self.pot['element'])

        # let the axes consistent with the elastic constants
        axes = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0])
        c = am.ElasticConstants()

        # the lattice constant has conventional direction as
        # x - [1 -2 1 0]  y[1, 0, -1, 0] z [0, 0, 0, 1]
        # c.hexagonal(C11=61.8, C33=67.5, C12=25.9, C13=21.9, C44=18.2)
        # c.hexagonal(C11=62.807, C33=69.615, C12=25.974,
        #             C13=21.184, C44=17.138)                       # Kim
        c.hexagonal(C11=64.3218889159844,
                    C33=70.9452244231304,
                    C12=25.4175328222502,
                    C13=20.306421440903,
                    C44=18.0690056385527)  # curtin

        stroh = stroh_solve.Stroh(c, burgers, axes=axes)
        pos = atoms.get_positions()

        cx = 0.5 * sz[0] * ux + 0.01
        cy = 0.5 * sz[1] * uy + 0.01

        print(cx, cy)
        self.write_lmp_config_data(atoms, "before.txt")
        shift = np.ones(pos.shape) * np.array([cx, cy, 0.0])
        disp = stroh.displacement(pos - shift)
        atoms.set_positions(pos + np.real(disp))
        self.write_lmp_config_data(atoms)
        ase.io.write("SCREW.cfg", atoms, format="cfg")
        return atoms
Exemplo n.º 14
0
    def print_dis_constants(self):
        struct = "hex"
        if struct in ["cubic"]:
            # Cubic
            c = tool_elastic_constants.elastic_constants(C11=self.pot['c11'],
                                                         C12=self.pot['c12'],
                                                         C44=self.pot['c44'])
            axes = np.array([[1, -1, 1], [2, 1, -1], [0, 1, 1]])
            burgers = self.pot['lattice'] / 2 * np.array([1., 1., 1.])
            stroh = stroh_solve.Stroh(c, burgers, axes=axes)
            print(stroh.A[0])

        # hexagonal
        if struct in ["hex"]:
            print(self.pot["lattice"])
            axes = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])

        burgers = self.pot['lattice'] / 2 * np.array([1., 1, 0])
        c = am.ElasticConstants()
        c.hexagonal(C11=326.08, C33=357.50, C12=129.56, C13=119.48, C44=92.54)
        stroh = stroh_solve.Stroh(c, burgers, axes=axes)
        print(stroh.A)
        print(stroh.L)
Exemplo n.º 15
0
    def build_edge_basal_hcp_atoms(self, atoms, center, sign=1):
        # let the axes consistent with the elastic constants
        axes = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0]) * sign
        c = am.ElasticConstants()

        print("build edge basial hcp")
        # x - [1 -2 1 0]  y[1, 0, -1, 0] z [0, 0, 0, 1]
        # c.hexagonal(C11=61.8, C33=67.5, C12=25.9, C13=21.9, C44=18.2)  # kim
        c.hexagonal(C11=64.3218889159844,
                    C33=70.9452244231304,
                    C12=25.4175328222502,
                    C13=20.306421440903,
                    C44=18.0690056385527)  # curtin
        stroh = stroh_solve.Stroh(c, burgers, axes=axes)
        pos = atoms.get_positions()
        cx = center[0] + 0.01
        cy = center[1] + 0.01
        print(cx, cy)
        shift = np.ones(pos.shape) * np.array([cx, cy, 0.0])
        disp = stroh.displacement(pos - shift)
        atoms.set_positions(pos + np.real(disp))
        return atoms
Exemplo n.º 16
0
    def build_edge_basal_hcp(self):
        sz = (200, 100, 3)
        atoms = othoHCP(latticeconstant=(self.pot['ahcp'], self.pot['chcp'],
                                         self.pot['ahcp'] * sqrt(3.)),
                        size=sz,
                        symbol=self.pot['element'])

        # let the axes consistent with the elastic constants
        axes = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0])
        c = am.ElasticConstants()

        # the lattice constant has conventional direction as
        # x - [1 -2 1 0]  y[1, 0, -1, 0] z [0, 0, 0, 1]
        # c.hexagonal(C11=61.8, C33=67.5, C12=25.9, C13=21.9, C44=18.2)  # kim
        # c.hexagonal(C11=62.369, C33=67.788, C12=26.252,
        #             C13=22.113, C44=18.274)  # Coco
        # c.hexagonal(C11=62.807, C33=69.615, C12=25.974,
        #             C13=21.184, C44=17.138)                       # Kim
        c.hexagonal(C11=64.3556,
                    C33=70.9849,
                    C12=25.460289,
                    C13=20.333408,
                    C44=18.06331)  # Curtin

        stroh = stroh_solve.Stroh(c, burgers, axes=axes)
        pos = atoms.get_positions()

        cx = 0.5 * sz[0] * self.pot["ahcp"] + 0.01
        cy = 0.5 * sz[1] * self.pot["chcp"] + 0.01

        print(cx, cy)
        shift = np.ones(pos.shape) * np.array([cx, cy, 0.0])
        disp = stroh.displacement(pos - shift)
        atoms.set_positions(pos + np.real(disp))
        self.write_lmp_config_data(atoms)
        return atoms
Exemplo n.º 17
0
    def todict(self, record_model, params, full=True, flat=False):
        """
        Converts the structured content to a simpler dictionary.
        
        Parameters
        ----------
        record_model : DataModelDict.DataModelDict
            The record content (after root element) to interpret.
        params : dict
            The dictionary to add the interpreted content to
        full : bool, optional
            Flag used by the calculation records.  A True value will include
            terms for both the calculation's input and results, while a value
            of False will only include input terms (Default is True).
        flat : bool, optional
            Flag affecting the format of the dictionary terms.  If True, the
            dictionary terms are limited to having only str, int, and float
            values, which is useful for comparisons.  If False, the term
            values can be of any data type, which is convenient for analysis.
            (Default is False).
        """
        prefix = self.prefix
        modelprefix = prefix.replace('_', '-')

        c_model = DM()
        c_model['elastic-constants'] = record_model[
            f'{modelprefix}elastic-constants']

        if flat is True:
            for C in c_model['elastic-constants'].aslist('C'):
                params['C' + str(C['ij'][0]) +
                       str(C['ij'][2])] = uc.value_unit(C['stiffness'])
        else:
            try:
                params['C'] = am.ElasticConstants(model=calc)
            except:
                params['C'] = 'Invalid'
Exemplo n.º 18
0
    def formular_make_edge_large(self):
        self.find_angles_1100(il=[[1], [1]], jl=[1])  # 58.361
        ux = self.pot['ahcp']
        uy = self.pot['chcp']
        uz = self.pot['ahcp'] * np.sqrt(3.)

        atoms = ase.io.read(glob.glob("dump_init_v2/dump.*")[-1],
                            format='lammps-dump')

        atoms.rotate(180 - self.ag[0][0], 'z')  # rotate
        atoms.translate(np.array([80 * ux, 0, 0]))
        axes = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
        burgers = self.pot['lattice'] * np.array([1, 0, 0])

        c = am.ElasticConstants()
        c.hexagonal(C11=self.pot['C11'],
                    C12=self.pot['C12'],
                    C33=self.pot['C33'],
                    C13=self.pot['C13'],
                    C44=self.pot['C44'])

        stroh = stroh_solve.Stroh(c, burgers, axes=axes)
        pos = atoms.get_positions()
        cell = atoms.get_cell()
        sh1 = np.ones(pos.shape) * \
            np.array([-30 * ux + 0.1, 10 * uy, cell[2, 2]])
        sh2 = np.ones(pos.shape) * \
            np.array([-30 * ux + 0.1, 30 * uy, cell[2, 2]])

        d1 = stroh.displacement(pos - sh1)
        d2 = stroh.displacement(pos - sh2)
        atoms.set_positions(pos + np.real(d1) - np.real(d2))

        atoms.translate(np.array([-80 * ux, 0.0, 0]))
        atoms.rotate(self.ag[0][0] - 180, 'z')  # rotate back
        self.write_lmp_config_data(atoms, "lmp_init02.txt")
Exemplo n.º 19
0
def make_edge_cyl_001_100(a0, C11, C12, C44,
                          cylinder_r,
                          cutoff=5.5,
                          tol=1e-6,
                          symbol="W"):
    """Function to produce consistent edge dislocation configuration.

    Parameters
    ----------
    alat : float
        Lattice constant of the material.
    C11 : float
        C11 elastic constant of the material.
    C12 : float
        C12 elastic constant of the material.
    C44 : float
        C44 elastic constant of the material.
    cylinder_r : float
        Radius of cylinder of unconstrained atoms around the
        dislocation  in angstrom.
    cutoff : float
        Potential cutoff for determenition of size of
        fixed atoms region (2*cutoff)
    tol : float
        Tolerance for generation of self consistent solution.
    symbol : string
        Symbol of the element to pass to ase.lattuce.cubic.SimpleCubicFactory
        default is "W" for tungsten

    Returns
    -------
    bulk : ase.Atoms object
        Bulk configuration.
    disloc : ase.Atoms object
        Dislocation configuration.
    disp : np.array
        Correstonding displacement.
    """

    # Create a Stroh ojbect with junk data
    stroh = am.defect.Stroh(am.ElasticConstants(C11=141, C12=110, C44=98),
                            np.array([0, 0, 1]))

    axes = np.array([[1, 0, 0],
                     [0, 1, 0],
                     [0, 0, 1]])

    c = am.ElasticConstants(C11=C11, C12=C12, C44=C44)
    burgers = a0 * np.array([1., 0., 0.])

    # Solving a new problem with Stroh.solve
    # Does not work with the new version of atomman
    stroh.solve(c, burgers, axes=axes)

    unit_cell = BodyCenteredCubic(directions=axes.tolist(),
                                  size=(1, 1, 1), symbol=symbol,
                                  pbc=(False, False, True),
                                  latticeconstant=a0)

    bulk = unit_cell.copy()

    # shift to make the zeros of the cell betweem the atomic planes
    # and under the midplane on Y axes
    X_midplane_shift = -0.25*a0
    Y_midplane_shift = -0.25*a0

    bulk_shift = [X_midplane_shift,
                  Y_midplane_shift,
                  0.0]

    bulk.positions += bulk_shift

    tot_r = cylinder_r + 2*cutoff + 0.01

    Lx = int(round(tot_r/a0))
    Ly = int(round(tot_r/a0))

    # factor 2 to make sure odd number of images is translated
    # it is important for the correct centering of the dislocation core
    bulk = bulk * (2*Lx, 2*Ly, 1)

    center_shift = [Lx * a0, Ly * a0, 0.0]

    bulk.positions -= center_shift
    # bulk.write("before.xyz")

    disp1 = stroh.displacement(bulk.positions)
    disloc = bulk.copy()
    res = np.inf
    i = 0
    while res > tol:
        disloc.positions = bulk.positions + disp1
        disp2 = stroh.displacement(disloc.positions)
        res = np.abs(disp1 - disp2).max()
        disp1 = disp2
        print 'disloc SCF', i, '|d1-d2|_inf =', res
        i += 1
        if i > 10:
            raise RuntimeError('Self-consistency did \
                                not converge in 10 cycles')
    disp = disp2

    x, y, z = disloc.positions.T
    radius_x_y_zero = np.sqrt(x**2 + y**2)
    mask = radius_x_y_zero < tot_r
    disloc = disloc[mask]
    bulk = bulk[mask]
    # disloc.write("after_disp.xyz")

    x, y, z = disloc.positions.T
    radius_x_y_zero = np.sqrt(x**2 + y**2)
    mask_zero = radius_x_y_zero > cylinder_r
    fix_atoms = FixAtoms(mask=mask_zero)
    disloc.set_constraint(fix_atoms)

    return bulk, disloc, disp
Exemplo n.º 20
0
    def todict(self, full=True, flat=False):
        """
        Converts the structured content to a simpler dictionary.
        
        Parameters
        ----------
        full : bool, optional
            Flag used by the calculation records.  A True value will include
            terms for both the calculation's input and results, while a value
            of False will only include input terms (Default is True).
        flat : bool, optional
            Flag affecting the format of the dictionary terms.  If True, the
            dictionary terms are limited to having only str, int, and float
            values, which is useful for comparisons.  If False, the term
            values can be of any data type, which is convenient for analysis.
            (Default is False).
            
        Returns
        -------
        dict
            A dictionary representation of the record's content.
        """

        # Extract universal content
        params = super().todict(full=full, flat=flat)
        calc = self.content[self.contentroot]

        # Extract minimization info
        subset('lammps_minimize').todict(calc, params, full=full, flat=flat)

        params['strainrange'] = calc['calculation']['run-parameter'][
            'strain-range']

        # Extract potential info
        subset('lammps_potential').todict(calc, params, full=full, flat=flat)

        # Extract system info
        subset('atomman_systemload').todict(calc, params, full=full, flat=flat)
        subset('atomman_systemmanipulate').todict(calc,
                                                  params,
                                                  full=full,
                                                  flat=flat)

        if full is True and params['status'] == 'finished':

            cij = uc.value_unit(calc['elastic-constants']['Cij'])
            if flat is True:
                params['C11'] = cij[0, 0]
                params['C12'] = cij[0, 1]
                params['C13'] = cij[0, 2]
                params['C14'] = cij[0, 3]
                params['C15'] = cij[0, 4]
                params['C16'] = cij[0, 5]
                params['C22'] = cij[1, 1]
                params['C23'] = cij[1, 2]
                params['C24'] = cij[1, 3]
                params['C25'] = cij[1, 4]
                params['C26'] = cij[1, 5]
                params['C33'] = cij[2, 2]
                params['C34'] = cij[2, 3]
                params['C35'] = cij[2, 4]
                params['C36'] = cij[2, 5]
                params['C44'] = cij[3, 3]
                params['C45'] = cij[3, 4]
                params['C46'] = cij[3, 5]
                params['C55'] = cij[4, 4]
                params['C56'] = cij[4, 5]
                params['C66'] = cij[5, 5]

            else:
                params['raw_cij_negative'] = uc.value_unit(
                    calc['raw-elastic-constants'][0]['Cij'])
                params['raw_cij_positive'] = uc.value_unit(
                    calc['raw-elastic-constants'][1]['Cij'])
                params['C'] = am.ElasticConstants(Cij=cij)

        return params
Exemplo n.º 21
0
    def todict(self, full=True, flat=False):
        """
        Converts the structured content to a simpler dictionary.
        
        Parameters
        ----------
        full : bool, optional
            Flag used by the calculation records.  A True value will include
            terms for both the calculation's input and results, while a value
            of False will only include input terms (Default is True).
        flat : bool, optional
            Flag affecting the format of the dictionary terms.  If True, the
            dictionary terms are limited to having only str, int, and float
            values, which is useful for comparisons.  If False, the term
            values can be of any data type, which is convenient for analysis.
            (Default is False).
            
        Returns
        -------
        dict
            A dictionary representation of the record's content.
        """

        calc = self.content[self.contentroot]
        params = {}
        params['key'] = calc['key']
        params['script'] = calc['calculation']['script']
        params['iprPy_version'] = calc['calculation']['iprPy-version']
        params['atomman_version'] = calc['calculation']['atomman-version']

        rp = calc['calculation']['run-parameter']
        params['halfwidth'] = uc.value_unit(rp['halfwidth'])
        params['xmax'] = rp['xmax']
        params['xnum'] = rp['xnum']
        params['xstep'] = rp['xstep']

        params['load_file'] = calc['system-info']['artifact']['file']
        params['load_style'] = calc['system-info']['artifact']['format']
        params['load_options'] = calc['system-info']['artifact'][
            'load_options']
        params['family'] = calc['system-info']['family']
        symbols = aslist(calc['system-info']['symbol'])

        params['dislocation_key'] = calc['dislocation-monopole']['key']
        params['dislocation_id'] = calc['dislocation-monopole']['id']

        params['gammasurface_calc_key'] = calc['gamma-surface']['calc_key']

        pnp = calc['semidiscrete-variational-Peierls-Nabarro']['parameter']
        try:
            K_tensor = uc.value_unit(pnp['K_tensor'])
        except:
            K_tensor = np.nan
        tau = uc.value_unit(pnp['tau'])
        alpha = uc.value_unit(pnp['alpha'])
        beta = uc.value_unit(pnp['beta'])
        params['cdiffelastic'] = pnp['cdiffelastic']
        params['cdiffsurface'] = pnp['cdiffsurface']
        params['cdiffstress'] = pnp['cdiffstress']
        params['cutofflongrange'] = uc.value_unit(pnp['cutofflongrange'])
        params['fullstress'] = pnp['fullstress']
        params['min_method'] = pnp['min_method']
        params['min_options'] = pnp['min_options']

        if flat is True:
            params['symbols'] = ' '.join(symbols)
            for i in range(3):
                for j in range(i, 3):
                    try:
                        params['K' + str(i + 1) + str(j + 1)] = K_tensor[i, j]
                    except:
                        params['K' + str(i + 1) + str(j + 1)] = np.nan
                    params['tau' + str(i + 1) + str(j + 1)] = tau[i, j]
                    params['beta' + str(i + 1) + str(j + 1)] = beta[i, j]
            if not isinstance(alpha, list):
                alpha = [alpha]
            for i in range(len(alpha)):
                params['alpha' + str(i + 1)] = alpha[i]
        else:
            params['symbols'] = symbols
            params['K_tensor'] = K_tensor
            params['tau'] = tau
            params['alpha'] = alpha
            params['beta'] = beta

        params['status'] = calc.get('status', 'finished')

        if full is True:
            if params['status'] == 'error':
                params['error'] = calc['error']

            elif params['status'] == 'not calculated':
                pass
            else:
                if flat is True:
                    pass
                else:
                    try:
                        params['C'] = am.ElasticConstants(model=calc)
                    except:
                        params['C'] = np.nan
                    if True:
                        params['SDVPN_model'] = DM()
                        params['SDVPN_model'][
                            'semidiscrete-variational-Peierls-Nabarro'] = calc.find(
                                'semidiscrete-variational-Peierls-Nabarro')
                    else:
                        params['SDVPN_model'] = np.nan

        return params
Exemplo n.º 22
0
def elastic_constants_static(lammps_command,
                             system,
                             potential,
                             mpi_command=None,
                             strainrange=1e-6,
                             etol=0.0,
                             ftol=0.0,
                             maxiter=10000,
                             maxeval=100000,
                             dmax=uc.set_in_units(0.01, 'angstrom')):
    """
    Repeatedly runs the ELASTIC example distributed with LAMMPS until box
    dimensions converge within a tolerance.
    
    Parameters
    ----------
    lammps_command :str
        Command for running LAMMPS.
    system : atomman.System
        The system to perform the calculation on.
    potential : atomman.lammps.Potential
        The LAMMPS implemented potential to use.
    mpi_command : str, optional
        The MPI command for running LAMMPS in parallel.  If not given, LAMMPS
        will run serially.
    strainrange : float, optional
        The small strain value to apply when calculating the elastic
        constants (default is 1e-6).
    etol : float, optional
        The energy tolerance for the structure minimization. This value is
        unitless. (Default is 0.0).
    ftol : float, optional
        The force tolerance for the structure minimization. This value is in
        units of force. (Default is 0.0).
    maxiter : int, optional
        The maximum number of minimization iterations to use (default is 10000).
    maxeval : int, optional
        The maximum number of minimization evaluations to use (default is 
        100000).
    dmax : float, optional
        The maximum distance in length units that any atom is allowed to relax
        in any direction during a single minimization iteration (default is
        0.01 Angstroms).
    
    Returns
    -------
    dict
        Dictionary of results consisting of keys:
        
        - **'a_lat'** (*float*) - The relaxed a lattice constant.
        - **'b_lat'** (*float*) - The relaxed b lattice constant.
        - **'c_lat'** (*float*) - The relaxed c lattice constant.
        - **'alpha_lat'** (*float*) - The alpha lattice angle.
        - **'beta_lat'** (*float*) - The beta lattice angle.
        - **'gamma_lat'** (*float*) - The gamma lattice angle.
        - **'E_coh'** (*float*) - The cohesive energy of the relaxed system.
        - **'stress'** (*numpy.array*) - The measured stress state of the
          relaxed system.
        - **'C_elastic'** (*atomman.ElasticConstants*) - The relaxed system's
          elastic constants.
        - **'system_relaxed'** (*atomman.System*) - The relaxed system.
    """

    # Convert hexagonal cells to orthorhombic to avoid LAMMPS tilt issues
    if am.tools.ishexagonal(system.box):
        system = system.rotate([[2, -1, -1, 0], [0, 1, -1, 0], [0, 0, 0, 1]])

    # Get lammps units
    lammps_units = lmp.style.unit(potential.units)

    # Get lammps version date
    lammps_date = lmp.checkversion(lammps_command)['date']

    # Define lammps variables
    lammps_variables = {}
    system_info = system.dump('atom_data',
                              f='init.dat',
                              units=potential.units,
                              atom_style=potential.atom_style)
    lammps_variables['atomman_system_info'] = system_info
    lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols)
    lammps_variables['strainrange'] = strainrange
    lammps_variables['etol'] = etol
    lammps_variables['ftol'] = uc.get_in_units(ftol, lammps_units['force'])
    lammps_variables['maxiter'] = maxiter
    lammps_variables['maxeval'] = maxeval
    lammps_variables['dmax'] = uc.get_in_units(dmax, lammps_units['length'])

    # Fill in template files
    template_file = 'cij.template'
    lammps_script = 'cij.in'
    with open(template_file) as f:
        template = f.read()
    with open(lammps_script, 'w') as f:
        f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>'))
    template_file2 = 'potential.template'
    lammps_script2 = 'potential.in'
    with open(template_file2) as f:
        template = f.read()
    with open(lammps_script2, 'w') as f:
        f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>'))

    # Run LAMMPS
    output = lmp.run(lammps_command, lammps_script, mpi_command)

    # Pull out initial state
    thermo = output.simulations[0]['thermo']
    pxx0 = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure'])
    pyy0 = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure'])
    pzz0 = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure'])
    pyz0 = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure'])
    pxz0 = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure'])
    pxy0 = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure'])

    # Negative strains
    cij_n = np.empty((6, 6))
    for i in range(6):
        j = 1 + i * 2
        # Pull out strained state
        thermo = output.simulations[j]['thermo']
        pxx = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure'])
        pyy = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure'])
        pzz = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure'])
        pyz = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure'])
        pxz = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure'])
        pxy = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure'])

        # Calculate cij_n using stress changes
        cij_n[i] = np.array([
            pxx - pxx0, pyy - pyy0, pzz - pzz0, pyz - pyz0, pxz - pxz0,
            pxy - pxy0
        ]) / strainrange

    # Positive strains
    cij_p = np.empty((6, 6))
    for i in range(6):
        j = 2 + i * 2
        # Pull out strained state
        thermo = output.simulations[j]['thermo']
        pxx = uc.set_in_units(thermo.Pxx.values[-1], lammps_units['pressure'])
        pyy = uc.set_in_units(thermo.Pyy.values[-1], lammps_units['pressure'])
        pzz = uc.set_in_units(thermo.Pzz.values[-1], lammps_units['pressure'])
        pyz = uc.set_in_units(thermo.Pyz.values[-1], lammps_units['pressure'])
        pxz = uc.set_in_units(thermo.Pxz.values[-1], lammps_units['pressure'])
        pxy = uc.set_in_units(thermo.Pxy.values[-1], lammps_units['pressure'])

        # Calculate cij_p using stress changes
        cij_p[i] = -np.array([
            pxx - pxx0, pyy - pyy0, pzz - pzz0, pyz - pyz0, pxz - pxz0,
            pxy - pxy0
        ]) / strainrange

    # Average symmetric values
    cij = (cij_n + cij_p) / 2
    for i in range(6):
        for j in range(i):
            cij[i, j] = cij[j, i] = (cij[i, j] + cij[j, i]) / 2

    # Define results_dict
    results_dict = {}
    results_dict['raw_cij_negative'] = cij_n
    results_dict['raw_cij_positive'] = cij_p
    results_dict['C'] = am.ElasticConstants(Cij=cij)

    return results_dict
Exemplo n.º 23
0
    def todict(self, full=True, flat=False):
        """
        Converts the structured content to a simpler dictionary.
        
        Parameters
        ----------
        full : bool, optional
            Flag used by the calculation records.  A True value will include
            terms for both the calculation's input and results, while a value
            of False will only include input terms (Default is True).
        flat : bool, optional
            Flag affecting the format of the dictionary terms.  If True, the
            dictionary terms are limited to having only str, int, and float
            values, which is useful for comparisons.  If False, the term
            values can be of any data type, which is convenient for analysis.
            (Default is False).
            
        Returns
        -------
        dict
            A dictionary representation of the record's content.
        """
        
        # Extract universal content
        params = super().todict(full=full, flat=flat)
        calc = self.content[self.contentroot]

        # Extract minimization info
        subset('lammps_minimize').todict(calc, params, full=full, flat=flat)
        
        params['annealtemperature'] = calc['calculation']['run-parameter']['annealtemperature']
        params['annealsteps'] = calc['calculation']['run-parameter']['annealsteps']
        
        # Extract potential info
        subset('lammps_potential').todict(calc, params, full=full, flat=flat)
        
        # Extract system info
        subset('atomman_systemload').todict(calc, params, full=full, flat=flat)
        
        subset('dislocation').todict(calc, params, full=full, flat=flat)
        
        if full is True and params['status'] == 'finished':
            params['preln'] = uc.value_unit(calc['elastic-solution']['pre-ln-factor'])
            K_tensor = uc.value_unit(calc['elastic-solution']['K-tensor'])

            if flat is True:
                for C in calc['elastic-constants'].aslist('C'):
                    params['C'+str(C['ij'][0])+str(C['ij'][2])] = uc.value_unit(C['stiffness'])
                params['K11'] = K_tensor[0,0]
                params['K12'] = K_tensor[0,1]
                params['K13'] = K_tensor[0,2]
                params['K22'] = K_tensor[1,1]
                params['K23'] = K_tensor[1,2]
                params['K33'] = K_tensor[2,2]
            else:
                try:
                    params['C'] = am.ElasticConstants(model=calc)
                except:
                    params['C'] = 'Invalid'
                params['K_tensor'] = K_tensor
        
        return params
Exemplo n.º 24
0
def calc_cij(lammps_command,
             system,
             potential,
             mpi_command=None,
             p_xx=0.0,
             p_yy=0.0,
             p_zz=0.0,
             strainrange=1e-6,
             cycle=0):
    """
    Runs cij.in LAMMPS script to evaluate Cij, and E_coh of the current system,
    and define a new system with updated box dimensions to test.
    
    Parameters
    ----------
    lammps_command :str
        Command for running LAMMPS.
    system : atomman.System
        The system to perform the calculation on.
    potential : atomman.lammps.Potential
        The LAMMPS implemented potential to use.
    mpi_command : str, optional
        The MPI command for running LAMMPS in parallel.  If not given, LAMMPS
        will run serially.
    strainrange : float, optional
        The small strain value to apply when calculating the elastic
        constants (default is 1e-6).
    p_xx : float, optional
        The value to relax the x tensile pressure component to (default is
        0.0).
    p_yy : float, optional
        The value to relax the y tensile pressure component to (default is
        0.0).
    p_zz : float, optional
        The value to relax the z tensile pressure component to (default is
        0.0).
    cycle : int, optional
        Indicates the iteration cycle of quick_a_Cij().  This is used to
        uniquely save the LAMMPS input and output files.
    
    Returns
    -------
    dict
        Dictionary of results consisting of keys:
        
        - **'E_coh'** (*float*) - The cohesive energy of the supplied system.
        - **'stress'** (*numpy.array*) - The measured stress state of the
          supplied system.
        - **'C_elastic'** (*atomman.ElasticConstants*) - The supplied system's
          elastic constants.
        - **'system_new'** (*atomman.System*) - System with updated box
          dimensions.
    
    Raises
    ------
    RuntimeError
        If any of the new box dimensions are less than zero.
    """
    try:
        # Get script's location if __file__ exists
        script_dir = Path(__file__).parent
    except:
        # Use cwd otherwise
        script_dir = Path.cwd()

    # Get lammps units
    lammps_units = lmp.style.unit(potential.units)

    # Define lammps variables
    lammps_variables = {}
    system_info = system.dump('atom_data',
                              f='init' + str(cycle) + '.dat',
                              units=potential.units,
                              atom_style=potential.atom_style)
    lammps_variables['atomman_system_info'] = system_info
    lammps_variables['atomman_pair_info'] = potential.pair_info(system.symbols)
    lammps_variables['delta'] = strainrange
    lammps_variables['steps'] = 2

    # Write lammps input script
    template_file = Path(script_dir, 'cij.template')
    lammps_script = 'cij.in'
    with open(template_file) as f:
        template = f.read()
    with open(lammps_script, 'w') as f:
        f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>'))

    # Run lammps
    output = lmp.run(lammps_command,
                     lammps_script,
                     mpi_command=mpi_command,
                     return_style='model')
    shutil.move('log.lammps', 'cij-' + str(cycle) + '-log.lammps')

    # Extract LAMMPS thermo data. Each term ranges i=0-12 where i=0 is undeformed
    # The remaining values are for -/+ strain pairs in the six unique directions
    lx = uc.set_in_units(np.array(output.finds('Lx')), lammps_units['length'])
    ly = uc.set_in_units(np.array(output.finds('Ly')), lammps_units['length'])
    lz = uc.set_in_units(np.array(output.finds('Lz')), lammps_units['length'])
    xy = uc.set_in_units(np.array(output.finds('Xy')), lammps_units['length'])
    xz = uc.set_in_units(np.array(output.finds('Xz')), lammps_units['length'])
    yz = uc.set_in_units(np.array(output.finds('Yz')), lammps_units['length'])

    pxx = uc.set_in_units(np.array(output.finds('Pxx')),
                          lammps_units['pressure'])
    pyy = uc.set_in_units(np.array(output.finds('Pyy')),
                          lammps_units['pressure'])
    pzz = uc.set_in_units(np.array(output.finds('Pzz')),
                          lammps_units['pressure'])
    pxy = uc.set_in_units(np.array(output.finds('Pxy')),
                          lammps_units['pressure'])
    pxz = uc.set_in_units(np.array(output.finds('Pxz')),
                          lammps_units['pressure'])
    pyz = uc.set_in_units(np.array(output.finds('Pyz')),
                          lammps_units['pressure'])

    pe = uc.set_in_units(
        np.array(output.finds('PotEng')) / system.natoms,
        lammps_units['energy'])

    # Set the six non-zero strain values
    strains = np.array([(lx[2] - lx[1]) / lx[0], (ly[4] - ly[3]) / ly[0],
                        (lz[6] - lz[5]) / lz[0], (yz[8] - yz[7]) / lz[0],
                        (xz[10] - xz[9]) / lz[0], (xy[12] - xy[11]) / ly[0]])

    # Calculate cij using stress changes associated with each non-zero strain
    cij = np.empty((6, 6))
    for i in range(6):
        delta_stress = np.array([
            pxx[2 * i + 1] - pxx[2 * i + 2], pyy[2 * i + 1] - pyy[2 * i + 2],
            pzz[2 * i + 1] - pzz[2 * i + 2], pyz[2 * i + 1] - pyz[2 * i + 2],
            pxz[2 * i + 1] - pxz[2 * i + 2], pxy[2 * i + 1] - pxy[2 * i + 2]
        ])

        cij[i] = delta_stress / strains[i]

    for i in range(6):
        for j in range(i):
            cij[i, j] = cij[j, i] = (cij[i, j] + cij[j, i]) / 2

    C = am.ElasticConstants(Cij=cij)

    S = C.Sij

    # Extract the current stress state
    stress = -1 * np.array([[pxx[0], pxy[0], pxz[0]], [pxy[0], pyy[0], pyz[0]],
                            [pxz[0], pyz[0], pzz[0]]])

    s_xx = stress[0, 0] + p_xx
    s_yy = stress[1, 1] + p_yy
    s_zz = stress[2, 2] + p_zz

    new_a = system.box.a / (S[0, 0] * s_xx + S[0, 1] * s_yy + S[0, 2] * s_zz +
                            1)
    new_b = system.box.b / (S[1, 0] * s_xx + S[1, 1] * s_yy + S[1, 2] * s_zz +
                            1)
    new_c = system.box.c / (S[2, 0] * s_xx + S[2, 1] * s_yy + S[2, 2] * s_zz +
                            1)

    if new_a <= 0 or new_b <= 0 or new_c <= 0:
        raise RuntimeError('Divergence of box dimensions to <= 0')

    system_new = deepcopy(system)
    system_new.box_set(a=new_a, b=new_b, c=new_c, scale=True)

    results_dict = {}
    results_dict['E_coh'] = pe[0]
    results_dict['system_new'] = system_new
    results_dict['measured_pxx'] = pxx[0]
    results_dict['measured_pyy'] = pyy[0]
    results_dict['measured_pzz'] = pzz[0]
    results_dict['measured_pxy'] = pxy[0]
    results_dict['measured_pxz'] = pxz[0]
    results_dict['measured_pyz'] = pyz[0]
    return results_dict
Exemplo n.º 25
0
def screw_cyl_octahedral(alat, C11, C12, C44,
                         scan_r=15,
                         symbol="W",
                         imp_symbol='H',
                         hard_core=False,
                         center=(0., 0., 0.)):
    """Generates a set of octahedral positions with `scan_r` radius.
       Applies the screw dislocation displacement for creating an initial guess
       for the H positions at dislocation core.

    Parameters
    ----------
    alat : float
        Lattice constant of the material.
    C11 : float
        C11 elastic constant of the material.
    C12 : float
        C12 elastic constant of the material.
    C44 : float
        C44 elastic constant of the material.
    symbol : string
        Symbol of the element to pass to ase.lattuce.cubic.SimpleCubicFactory
        default is "W" for tungsten
    imp_symbol : string
        Symbol of the elemnt to pass creat Atoms object
        default is "H" for hydrogen
    symbol : string
        Symbol of the elemnt to pass creat Atoms object
    hard_core : float
        Type of the dislocatino core if True then -u
        (sign of displacement is flipped) is applied.
        Default is False i.e. soft core is created.
    center : tuple of floats
        Coordinates of dislocation core (center) (x, y, z).
        Default is (0., 0., 0.)

    Returns
    -------
    ase.Atoms object
        Atoms object with predicted tetrahedral
        positions around dislocation core.

    """
    # TODO: Make one function for impurities and pass factory to it:
    # TODO: i.e. octahedral or terahedral

    axes = np.array([[1, 1, -2],
                     [-1, 1, 0],
                     [1, 1, 1]])

    unit_cell = BodyCenteredCubic(directions=axes.tolist(),
                                  size=(1, 1, 1), symbol=symbol,
                                  pbc=(False, False, True),
                                  latticeconstant=alat)

    BCCOctas = BodyCenteredCubicOctahedralFactory()

    impurities = BCCOctas(directions=axes.tolist(),
                          size=(1, 1, 1), symbol=imp_symbol,
                          pbc=(False, False, True),
                          latticeconstant=alat)

    impurities = impurities[impurities.positions.T[2] < alat*1.2]
    impurities.set_cell(unit_cell.get_cell())
    impurities.wrap()

    disloCenterY = alat * np.sqrt(2.)/6.0
    disloCenterX = alat * np.sqrt(6.)/6.0

    impurities.positions[:, 0] -= disloCenterX
    impurities.positions[:, 1] -= disloCenterY

    L = int(round(2.0*scan_r/(alat*np.sqrt(2.)))) + 1

    bulk_octa = impurities * (L, L, 1)

    # make 0, 0, at the center
    bulk_octa.positions[:, 0] -= L * alat * np.sqrt(6.)/2. - center[0]
    bulk_octa.positions[:, 1] -= L * alat * np.sqrt(2.)/2. - center[1]

    x, y, z = bulk_octa.positions.T

    radius_x_y_zero = np.sqrt(x**2 + y**2)
    mask_zero = radius_x_y_zero < scan_r

    radius_x_y_center = np.sqrt((x - center[0])**2 + (y - center[1])**2)
    mask_center = radius_x_y_center < scan_r

    final_mask = mask_center | mask_zero
    # leave only atoms inside the cylinder
    bulk_octa = bulk_octa[final_mask]

    # Create a Stroh ojbect with junk data
    stroh = am.defect.Stroh(am.ElasticConstants(C11=141, C12=110, C44=98),
                            np.array([0, 0, 1]))

    c = am.ElasticConstants(C11=C11, C12=C12, C44=C44)
    burgers = alat * np.array([1., 1., 1.])/2.

    # Solving a new problem with Stroh.solve
    stroh.solve(c, burgers, axes=axes)

    dislo_octa = bulk_octa.copy()

    impurities_u = stroh.displacement(bulk_octa.positions - center)
    impurities_u = -impurities_u if hard_core else impurities_u

    dislo_octa.positions += impurities_u

    return dislo_octa
Exemplo n.º 26
0
def make_edge_cyl(alat, C11, C12, C44,
                  cylinder_r=10, cutoff=5.5,
                  symbol='W'):
    '''
    makes edge dislocation using atomman library

    cylinder_r - radius of cylinder of unconstrained atoms around the
                 dislocation  in angstrom

    cutoff - potential cutoff for marinica potentials for FS cutoff = 4.4

    symbol : string
        Symbol of the element to pass to ase.lattuce.cubic.SimpleCubicFactory
        default is "W" for tungsten
    '''

    # Create a Stroh ojbect with junk data
    stroh = am.defect.Stroh(am.ElasticConstants(C11=141, C12=110, C44=98),
                            np.array([0, 0, 1]))

    axes = np.array([[1, 1, 1],
                     [1, -1, 0],
                     [1, 1, -2]])

    c = am.ElasticConstants(C11=C11, C12=C12, C44=C44)
    burgers = alat * np.array([1., 1., 1.])/2.

    # Solving a new problem with Stroh.solve
    # Does not work with the new version of atomman
    stroh.solve(c, burgers, axes=axes)

    unit_cell = BodyCenteredCubic(directions=axes.tolist(),
                                  size=(1, 1, 1), symbol='W',
                                  pbc=(False, False, True),
                                  latticeconstant=alat)

    bulk = unit_cell.copy()

    # shift to make the zeros of the cell betweem the atomic planes
    # and under the midplane on Y axes
    X_midplane_shift = (1.0/3.0)*alat*np.sqrt(3.0)/2.0
    Y_midplane_shift = 0.25*alat*np.sqrt(2.0)

    bulk_shift = [X_midplane_shift,
                  Y_midplane_shift,
                  0.0]

    bulk.positions += bulk_shift

    tot_r = cylinder_r + cutoff + 0.01

    Lx = int(round(tot_r/(alat*np.sqrt(3.0)/2.0)))
    Ly = int(round(tot_r/(alat*np.sqrt(2.))))

    # factor 2 to make shure odd number of images is translated
    # it is important for the correct centering of the dislocation core
    bulk = bulk * (2*Lx, 2*Ly, 1)

    center_shift = [Lx * alat * np.sqrt(3.0)/2.,
                    Ly * alat * np.sqrt(2.),
                    0.0]

    bulk.positions -= center_shift

    ED = bulk.copy()

    disp = stroh.displacement(ED.positions)

    ED.positions += disp

    x, y, z = ED.positions.T
    radius_x_y_zero = np.sqrt(x**2 + y**2)
    mask = radius_x_y_zero < tot_r

    ED = ED[mask]
    bulk = bulk[mask]

    bulk.write("before.xyz")

    ED.write("after_disp.xyz")

    x, y, z = ED.positions.T
    radius_x_y_zero = np.sqrt(x**2 + y**2)
    mask_zero = radius_x_y_zero > cylinder_r
    fix_atoms = FixAtoms(mask=mask_zero)

    ED.set_constraint(fix_atoms)

    x, y, z = bulk.positions.T
    # move lower left segment
    bulk.positions[(y < 0.0) & (x < X_midplane_shift)] -= \
        [alat * np.sqrt(3.0) / 2.0, 0.0, 0.0]
    # make the doslocation extraplane center
    bulk.positions += [(1.0/3.0)*alat*np.sqrt(3.0)/2.0, 0.0, 0.0]

    return ED, bulk
Exemplo n.º 27
0
def read_input(f, uuid=None):
    """Reads the calc_*.in input commands for this calculation."""

    #Read input file in as dictionary
    input_dict = input.file_to_dict(f)

    #Load a dislocation model if given
    if 'dislocation_model' in input_dict:
        assert 'x-axis' not in input_dict, 'x-axis and dislocation_model cannot both be supplied'
        assert 'y-axis' not in input_dict, 'y-axis and dislocation_model cannot both be supplied'
        assert 'z-axis' not in input_dict, 'z-axis and dislocation_model cannot both be supplied'

        with open(input_dict['dislocation_model']) as f:
            input_dict['dislocation_model'] = DM(f)

        params = input_dict['dislocation_model'].find(
            'atomman-defect-Stroh-parameters')
        x_axis = params['crystallographic-axes']['x-axis']
        y_axis = params['crystallographic-axes']['y-axis']
        z_axis = params['crystallographic-axes']['z-axis']

    else:
        #Remove any axes so system is not rotated
        input_dict['dislocation_model'] = None
        x_axis = input_dict.pop('x-axis', [1, 0, 0])
        y_axis = input_dict.pop('y-axis', [0, 1, 0])
        z_axis = input_dict.pop('z-axis', [0, 0, 1])

    #Interpret input terms common across calculations
    input.process_common_terms(input_dict, uuid)

    #Add axes back to input_dict
    input_dict['x-axis'] = x_axis
    input_dict['y-axis'] = y_axis
    input_dict['z-axis'] = z_axis

    #Interpret input terms unique to this calculation.
    input_dict['chi_angle'] = float(input_dict.get('chi_angle', 0.0))
    input_dict['rss_steps'] = int(input_dict.get('rss_steps', 0))
    input_dict['sigma'] = input.value_unit(
        input_dict,
        'sigma',
        default_unit=input_dict['pressure_unit'],
        default_term='0.0 GPa')
    input_dict['tau_1'] = input.value_unit(
        input_dict,
        'tau_1',
        default_unit=input_dict['pressure_unit'],
        default_term='0.0 GPa')
    input_dict['tau_2'] = input.value_unit(
        input_dict,
        'tau_2',
        default_unit=input_dict['pressure_unit'],
        default_term='0.0 GPa')
    input_dict['press'] = input.value_unit(
        input_dict,
        'press',
        default_unit=input_dict['pressure_unit'],
        default_term='0.0 GPa')

    input_dict['energy_tolerance'] = float(
        input_dict.get('energy_tolerance', 0.0))
    input_dict['force_tolerance'] = input.value_unit(
        input_dict,
        'force_tolerance',
        default_unit=input_dict['force_unit'],
        default_term='1e-6 eV/angstrom')
    input_dict['maximum_iterations'] = int(
        input_dict.get('maximum_iterations', 100000))
    input_dict['maximum_evaluations'] = int(
        input_dict.get('maximum_evaluations', 100000))

    #Extract explicit elastic constants from input_dict
    Cdict = {}
    for key in input_dict.iterkeys():
        if key[0] == 'C':
            Cdict[key] = input.value_unit(
                input_dict, key, default_unit=input_dict['pressure_unit'])
    if len(Cdict) > 0:
        assert 'elastic_constants_model' not in input_dict, 'Cij values and elastic_constants_model cannot both be specified.'
        input_dict['elastic_constants_model'] = None
        input_dict['C'] = am.ElasticConstants(**Cdict)

    #If no Cij elastic constants defined check for elastic_constants_model
    else:
        #load file may be the elastic_constants_model file
        input_dict['elastic_constants_model'] = input_dict.get(
            'elastic_constants_model', input_dict['load'].split()[1])

        with open(input_dict['elastic_constants_model']) as f:
            C_model = DM(f)

        try:
            input_dict['elastic_constants_model'] = DM([
                ('elastic-constants', C_model.find('elastic-constants'))
            ])
            input_dict['C'] = am.ElasticConstants(
                model=input_dict['elastic_constants_model'])
        except:
            input_dict['elastic_constants_model'] = None
            input_dict['C'] = None

    return input_dict
Exemplo n.º 28
0
def calc_cij(lammps_command,
             system,
             potential,
             symbols,
             p_xx=0.0,
             p_yy=0.0,
             p_zz=0.0,
             delta=1e-5,
             cycle=0):
    """Runs cij_script and returns current Cij, stress, Ecoh, and new system guess."""

    #Get lammps units
    lammps_units = lmp.style.unit(potential.units)

    #Define lammps variables
    lammps_variables = {}
    lammps_variables['atomman_system_info'] = lmp.sys_gen(
        units=potential.units,
        atom_style=potential.atom_style,
        ucell=system,
        size=np.array([[0, 3], [0, 3], [0, 3]]))
    lammps_variables['atomman_pair_info'] = potential.pair_info(symbols)
    lammps_variables['delta'] = delta
    lammps_variables['steps'] = 2

    #Write lammps input script
    template_file = 'cij.template'
    lammps_script = 'cij.in'
    with open(template_file) as f:
        template = f.read()
    with open(lammps_script, 'w') as f:
        f.write(iprPy.tools.filltemplate(template, lammps_variables, '<', '>'))

    #Run lammps
    output = lmp.run(lammps_command, lammps_script)
    shutil.move('log.lammps', 'cij-' + str(cycle) + '-log.lammps')

    #Extract LAMMPS thermo data. Each term ranges i=0-12 where i=0 is undeformed
    #The remaining values are for -/+ strain pairs in the six unique directions
    lx = uc.set_in_units(np.array(output.finds('Lx')), lammps_units['length'])
    ly = uc.set_in_units(np.array(output.finds('Ly')), lammps_units['length'])
    lz = uc.set_in_units(np.array(output.finds('Lz')), lammps_units['length'])
    xy = uc.set_in_units(np.array(output.finds('Xy')), lammps_units['length'])
    xz = uc.set_in_units(np.array(output.finds('Xz')), lammps_units['length'])
    yz = uc.set_in_units(np.array(output.finds('Yz')), lammps_units['length'])

    pxx = uc.set_in_units(np.array(output.finds('Pxx')),
                          lammps_units['pressure'])
    pyy = uc.set_in_units(np.array(output.finds('Pyy')),
                          lammps_units['pressure'])
    pzz = uc.set_in_units(np.array(output.finds('Pzz')),
                          lammps_units['pressure'])
    pxy = uc.set_in_units(np.array(output.finds('Pxy')),
                          lammps_units['pressure'])
    pxz = uc.set_in_units(np.array(output.finds('Pxz')),
                          lammps_units['pressure'])
    pyz = uc.set_in_units(np.array(output.finds('Pyz')),
                          lammps_units['pressure'])
    try:
        pe = uc.set_in_units(np.array(output.finds('v_peatom')),
                             lammps_units['energy'])
        assert len(pe) > 0
    except:
        pe = uc.set_in_units(np.array(output.finds('peatom')),
                             lammps_units['energy'])

    #Set the six non-zero strain values
    strains = np.array([(lx[2] - lx[1]) / lx[0], (ly[4] - ly[3]) / ly[0],
                        (lz[6] - lz[5]) / lz[0], (yz[8] - yz[7]) / lz[0],
                        (xz[10] - xz[9]) / lz[0], (xy[12] - xy[11]) / ly[0]])

    #calculate cij using stress changes associated with each non-zero strain
    cij = np.empty((6, 6))
    for i in xrange(6):
        delta_stress = np.array([
            pxx[2 * i + 1] - pxx[2 * i + 2], pyy[2 * i + 1] - pyy[2 * i + 2],
            pzz[2 * i + 1] - pzz[2 * i + 2], pyz[2 * i + 1] - pyz[2 * i + 2],
            pxz[2 * i + 1] - pxz[2 * i + 2], pxy[2 * i + 1] - pxy[2 * i + 2]
        ])

        cij[i] = delta_stress / strains[i]

    for i in xrange(6):
        for j in xrange(i):
            cij[i, j] = cij[j, i] = (cij[i, j] + cij[j, i]) / 2

    C = am.ElasticConstants(Cij=cij)

    if np.allclose(C.Cij, 0.0):
        raise RuntimeError('Divergence of elastic constants to <= 0')
    try:
        S = C.Sij
    except:
        raise RuntimeError('singular C:\n' + str(C.Cij))

    #extract the current stress state
    stress = -1 * np.array([[pxx[0], pxy[0], pxz[0]], [pxy[0], pyy[0], pyz[0]],
                            [pxz[0], pyz[0], pzz[0]]])

    s_xx = stress[0, 0] + p_xx
    s_yy = stress[1, 1] + p_yy
    s_zz = stress[2, 2] + p_zz

    new_a = system.box.a / (S[0, 0] * s_xx + S[0, 1] * s_yy + S[0, 2] * s_zz +
                            1)
    new_b = system.box.b / (S[1, 0] * s_xx + S[1, 1] * s_yy + S[1, 2] * s_zz +
                            1)
    new_c = system.box.c / (S[2, 0] * s_xx + S[2, 1] * s_yy + S[2, 2] * s_zz +
                            1)

    if new_a <= 0 or new_b <= 0 or new_c <= 0:
        raise RuntimeError('Divergence of box dimensions to <= 0')

    newbox = am.Box(a=new_a, b=new_b, c=new_c)
    system_new = deepcopy(system)
    system_new.box_set(vects=newbox.vects, scale=True)

    return {'C': C, 'stress': stress, 'ecoh': pe[0], 'system_new': system_new}
Exemplo n.º 29
0
    def make_screw_plate_old(self,
                             size=[40, 60, 3],
                             rad=[100, 115],
                             move=[0., 0., 0.],
                             filename="lmp_init.txt",
                             opt=None):
        alat = uc.set_in_units(self.pot['lattice'], 'angstrom')
        C11 = uc.set_in_units(self.pot['c11'], 'GPa')
        C12 = uc.set_in_units(self.pot['c12'], 'GPa')
        C44 = uc.set_in_units(self.pot['c44'], 'GPa')

        axes = np.array([[1, -2, 1], [1, 0, -1], [1, 1, 1]])

        unitx = alat * np.sqrt(6)
        unity = alat * np.sqrt(2)
        sizex = size[0]
        sizey = size[1]

        sizez = size[2]
        c = am.ElasticConstants(C11=C11, C12=C12, C44=C44)
        burgers = 0.5 * alat * -np.array([1., 1., 1.])

        # initializing a new Stroh object using the data
        stroh = am.defect.Stroh(c, burgers, axes=axes)

        # monopole system
        box = am.Box(a=alat, b=alat, c=alat)
        atoms = am.Atoms(natoms=2,
                         prop={
                             'atype': 2,
                             'pos': [[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]]
                         })
        ucell = am.System(atoms=atoms, box=box, scale=True)
        system = am.rotate_cubic(ucell, axes)

        # shftx = 0.5 * alat * np.sqrt(6.) / 3.
        shftx = 0.0
        shfty = -1. / 3. * alat * np.sqrt(2) / 2.
        # shfty = 2. / 3. * alat * np.sqrt(2) / 2.

        center = [0.5 * unitx * sizex, 0.5 * unity * sizey]
        new_pos = system.atoms_prop(key='pos') + np.array([shftx, shfty, 0.0])
        system.atoms_prop(key='pos', value=new_pos)
        system.supersize((0, sizex), (0, sizey), (0, sizez))

        # to make a plate #
        radius2 = rad[0] * rad[0]
        radiusout2 = rad[1] * rad[1]

        elements = []
        for atom in system.atoms:
            elements.append('Nb')

        ase_atoms = am.convert.ase_Atoms.dump(system, elements)
        pos = ase_atoms.get_positions()
        delindex = []
        for i in range(len(pos)):
            atom = ase_atoms[i]
            dx = pos[i, 0] - center[0]
            dy = pos[i, 1] - center[1]
            r = dx * dx + dy * dy

            if r > radiusout2:
                delindex.append(atom.index)
            if r < radius2:
                atom.symbol = 'W'
        del ase_atoms[delindex]

        (system, elements) = am.convert.ase_Atoms.load(ase_atoms)

        # use neb, it's to generate init configuration
        if opt in ['neb']:
            system_init = copy.deepcopy(system)

            shift = np.array([-0.5, -0.5, 0.0])
            new_pos = system_init.atoms_prop(key='pos', scale=True) + shift
            system_init.atoms_prop(key='pos', value=new_pos, scale=True)

            disp = stroh.displacement(system_init.atoms_prop(key='pos'))
            system_init.atoms_prop(key='pos',
                                   value=system_init.atoms_prop(key='pos') +
                                   disp)

            shift = np.array([0.5, 0.50, 0.0])
            new_pos = system_init.atoms_prop(key='pos', scale=True) + shift
            system_init.atoms_prop(key='pos', value=new_pos, scale=True)

            # for lammps read structure
            lmp.atom_data.dump(system_init, "init.txt")

        # for dd map plot
        ase.io.write("lmp_perf.cfg", images=ase_atoms, format='cfg')
        lmp.atom_data.dump(system, "lmp_perf.txt")

        shift = np.array([-0.5, -0.5, 0.0])
        new_pos = system.atoms_prop(key='pos', scale=True) + shift
        system.atoms_prop(key='pos', value=new_pos, scale=True)

        new_pos = system.atoms_prop(key='pos') + move
        system.atoms_prop(key='pos', value=new_pos)

        disp = stroh.displacement(system.atoms_prop(key='pos'))

        # pull
        pull = False
        if pull is True:
            core_rows = [disp[:, 2].argsort()[-3:][::-1]]
            print(disp[core_rows])
            exclus = np.arange(len(disp), dtype=int)
            unitburger = np.mean(disp[core_rows][:, 2])
            print(unitburger)
            exclus = np.delete(exclus, core_rows)
            disp[core_rows] -= 1. / 3. * unitburger
            # disp[exclus] -= 1. / 3. * unitburger

        system.atoms_prop(key='pos', value=system.atoms_prop(key='pos') + disp)

        new_pos = system.atoms_prop(key='pos') - move
        system.atoms_prop(key='pos', value=new_pos)

        shift = np.array([0.500000, 0.500000, 0.000000])
        new_pos = system.atoms_prop(key='pos', scale=True) + shift
        system.atoms_prop(key='pos', value=new_pos, scale=True)

        new_pos = system.atoms_prop(key='pos', scale=False)

        # for lammps read structure
        lmp.atom_data.dump(system, filename)

        dis_atoms = am.convert.ase_Atoms.dump(system, elements)
        return (ase_atoms, dis_atoms)
Exemplo n.º 30
0
def make_screw_cyl(alat, C11, C12, C44,
                   cylinder_r=10, cutoff=5.5,
                   hard_core=False,
                   center=(0., 0., 0.),
                   l_extend=(0., 0., 0.),
                   symbol='W'):

    """Makes screw dislocation using atomman library

    Parameters
    ----------
    alat : float
        Lattice constant of the material.
    C11 : float
        C11 elastic constant of the material.
    C12 : float
        C12 elastic constant of the material.
    C44 : float
        C44 elastic constant of the material.
    cylinder_r : float
        radius of cylinder of unconstrained atoms around the
        dislocation  in angstrom
    cutoff : float
        Potential cutoff for marinica potentials for FS cutoff = 4.4
    hard_core : bool
        Description of parameter `hard_core`.
    center : type
        The position of the dislocation core and the center of the
                 cylinder with FixAtoms condition
    l_extend : float
        extention of the box. used for creation of initial
        dislocation position with box equivalent to the final position
    symbol : string
        Symbol of the element to pass to ase.lattuce.cubic.SimpleCubicFactory
        default is "W" for tungsten

    Returns
    -------
    disloc : ase.Atoms object
        screw dislocation cylinder.
    bulk : ase.Atoms object
        bulk disk used to generate dislocation
    u : np.array
        displacement per atom.
    """
    # Create a Stroh ojbect with junk data
    stroh = am.defect.Stroh(am.ElasticConstants(C11=141, C12=110, C44=98),
                            np.array([0, 0, 1]))

    axes = np.array([[1, 1, -2],
                     [-1, 1, 0],
                     [1, 1, 1]])

    c = am.ElasticConstants(C11=C11, C12=C12, C44=C44)
    burgers = alat * np.array([1., 1., 1.])/2.

    # Solving a new problem with Stroh.solve
    stroh.solve(c, burgers, axes=axes)

    # test the solution that it does not crash
    # pos_test = uc.set_in_units(np.array([12.4, 13.5, -10.6]), 'angstrom')
    # disp = stroh.displacement(pos_test)
    # print("displacement =", uc.get_in_units(disp, 'angstrom'), 'angstrom')

    unit_cell = BodyCenteredCubic(directions=axes.tolist(),
                                  size=(1, 1, 1), symbol=symbol,
                                  pbc=(False, False, True),
                                  latticeconstant=alat)

    # make the dislocation core center of the box
    disloCenterX = alat * np.sqrt(6.)/6.0
    disloCenterY = alat * np.sqrt(2.)/6.0

    unit_cell.positions[:, 0] -= disloCenterX
    unit_cell.positions[:, 1] -= disloCenterY

    # shift to move the fixed atoms boundary condition for the
    # configuration with shifted dislocation core
    shift_x = 2.0 * center[0]
    shift_y = 2.0 * center[1]

    l_shift_x = 2.0 * l_extend[0]
    l_shift_y = 2.0 * l_extend[1]

    # size of the cubic cell as a 112 direction
    Lx = int(round((cylinder_r + 3.*cutoff + shift_x + l_shift_x)
                   / (alat * np.sqrt(6.))))

    # size of the cubic cell as a 110 direction
    Ly = int(round((cylinder_r + 3.*cutoff + shift_y + l_shift_y)
                   / (alat * np.sqrt(2.))))
    # factor 2 to make shure odd number of images is translated
    # it is important for the correct centering of the dislocation core
    bulk = unit_cell * (2*Lx, 2*Ly, 1)
    # make 0, 0, at the center
    bulk.positions[:, 0] -= Lx * alat * np.sqrt(6.)
    bulk.positions[:, 1] -= Ly * alat * np.sqrt(2.)

    # wrap
    # bulk.set_scaled_positions(bulk.get_scaled_positions())
    # apply shear here:
    # bulk.cell *= D
    # bulk.positions *= D

    x, y, z = bulk.positions.T

    radius_x_y_zero = np.sqrt(x**2 + y**2)
    mask_zero = radius_x_y_zero < cylinder_r + 2.*cutoff

    radius_x_y_center = np.sqrt((x - center[0])**2 + (y - center[1])**2)
    mask_center = radius_x_y_center < cylinder_r + 2.*cutoff

    radius_x_y_l_shift = np.sqrt((x - l_extend[0])**2 + (y - l_extend[1])**2)
    mask_l_shift = radius_x_y_l_shift < cylinder_r + 2.*cutoff

    final_mask = mask_center | mask_zero | mask_l_shift
    # leave only atoms inside the cylinder
    bulk = bulk[final_mask]

    disloc = bulk.copy()
    # calculate and apply the displacements for atomic positions
    u = stroh.displacement(bulk.positions - center)
    u = -u if hard_core else u

    disloc.positions += u
    x, y, z = disloc.positions.T

    radius_x_y_zero = np.sqrt(x**2 + y**2)
    mask_zero = radius_x_y_zero > cylinder_r

    radius_x_y_center = np.sqrt((x - center[0])**2 + (y - center[1])**2)
    mask_center = radius_x_y_center > cylinder_r

    radius_x_y_l_shift = np.sqrt((x - l_extend[0])**2 + (y - l_extend[1])**2)
    mask_l_shift = radius_x_y_l_shift > cylinder_r

    fix_mask = mask_center & mask_zero & mask_l_shift
    # leave only atoms inside the cylinder
    fix_atoms = FixAtoms(mask=fix_mask)
    disloc.set_constraint(fix_atoms)

    # make an "region" array to map bulk and fixed atoms
    # all atoms are "MM" by default
    region = np.full_like(disloc, "MM")
    region[fix_mask] = np.full_like(disloc[fix_mask], "fixed")
    disloc.new_array("region", region)

    return disloc, bulk, u