Пример #1
0
def extend_strip(atoms, a, N, M, vacuum):
    x = atoms.positions[:, 0]
    left = x.min()
    width = x.max() - x.min()

    tip_x = atoms.info['tip_x']
    if tip_x < left + 0.6 * width:
        # only need to extend strip when crack gets near end
        return False

    print('tip_x (%.2f) > left + 0.75*width (%.2f)' %
          (tip_x, left + 0.75 * width))

    # extra material for pasting onto end
    a = atoms.get_calculator().parameters['a']
    extra = triangular_lattice_slab(a, M, N)

    # apply uniform strain and append to slab
    strain = get_strain(atoms)

    extra.center(vacuum, axis=1)
    fix = atoms.get_array('fix')
    extra.positions[:, 0] += atoms.positions[fix, 0].max() + a / 2.0
    extra.positions[:, 1] -= extra.positions[:, 1].mean()
    extra.positions[:, 1] *= (1.0 + strain)

    print('Adding %d atoms' % len(extra))
    atoms += extra
    atoms.set_constraint([])

    discard = atoms.positions[:, 0].argsort()[:len(extra)]
    print('Discarding %d atoms' % len(discard))
    del atoms[discard]

    return True
Пример #2
0
def extend_strip(atoms, a, N, M, vacuum):
    x = atoms.positions[:, 0]
    left = x.min()
    width = x.max() - x.min()

    tip_x = atoms.info['tip_x']
    if tip_x < left + 0.6*width:
        # only need to extend strip when crack gets near end
        return False

    print 'tip_x (%.2f) > left + 0.75*width (%.2f)' % (tip_x, left + 0.75*width)
    
    # extra material for pasting onto end
    a = atoms.get_calculator().parameters['a']    
    extra = triangular_lattice_slab(a, M, N)

    # apply uniform strain and append to slab
    strain = get_strain(atoms)
    
    extra.center(vacuum, axis=1)
    fix = atoms.get_array('fix')
    extra.positions[:, 0] += atoms.positions[fix, 0].max() + a/2.0
    extra.positions[:, 1] -= extra.positions[:, 1].mean()
    extra.positions[:, 1] *= (1.0 + strain)

    print 'Adding %d atoms' % len(extra)
    atoms += extra
    atoms.set_constraint([])

    discard = atoms.positions[:, 0].argsort()[:len(extra)]
    print 'Discarding %d atoms' % len(discard)
    del atoms[discard]

    return True
Пример #3
0
def find_crack_tip(atoms, dt=None, store=True, results=None):
    """
    Return atom at the crack tip and its x-coordinate
    
    Crack tip is defined to be location of rightmost atom
    whose nearest neighbour is at distance > 2.5*a
    """
    calc = atoms.get_calculator()
    a = calc.parameters['a']
    rc = calc.parameters['rc']
    
    i = neighbour_list('i', atoms, rc)
    nn = np.bincount(i) # number of nearest neighbours, equal to 6 in bulk
    
    x = atoms.positions[:, 0]
    y = atoms.positions[:, 1]

    bottom = y.min()
    left = x.min()
    width = x.max() - x.min()
    height = y.max() - y.min()
    old_tip_x = atoms.info.get('tip_x', left + 0.3*width)

    # crack cannot have advanced more than c_R*dt
    if dt is not None:
        cl, ct, cR = calc.get_wave_speeds(atoms)
        tip_max_x = old_tip_x + 10.0*cR*dt # FIXME definition of cR seems wrong, shouldn't need factor of 10 here...
    else:
        tip_max_x = left + 0.8*width
    
    broken = ((nn != 6) &
              (x > left + 0.2*width) & (x < tip_max_x) &
              (y > bottom + 0.1*height) & (y < bottom + 0.9*height))
        
    index = atoms.positions[broken, 0].argmax()
    tip_atom = broken.nonzero()[0][index]
    tip_x = atoms.positions[tip_atom, 0]

    strain = get_strain(atoms)
    eps_G = atoms.info['eps_G']
    print 'tip_x: %.3f strain: %.4f delta: %.3f' % (tip_x, strain, strain/eps_G)

    if store:
        atoms.info['tip_atom'] = tip_atom
        atoms.info['tip_x'] = tip_x

    if results is not None:
        results.append(tip_x)
    
    return (tip_atom, tip_x, broken)
Пример #4
0
def find_crack_tip(atoms, dt=None, store=True, results=None):
    """
    Return atom at the crack tip and its x-coordinate

    Crack tip is defined to be location of rightmost atom
    whose nearest neighbour is at distance > 2.5*a
    """
    calc = atoms.get_calculator()
    a = calc.parameters['a']
    rc = calc.parameters['rc']

    i = neighbour_list('i', atoms, rc)
    nn = np.bincount(i)  # number of nearest neighbours, equal to 6 in bulk

    x = atoms.positions[:, 0]
    y = atoms.positions[:, 1]

    bottom = y.min()
    left = x.min()
    width = x.max() - x.min()
    height = y.max() - y.min()
    old_tip_x = atoms.info.get('tip_x', left + 0.3 * width)

    # crack cannot have advanced more than c_R*dt
    if dt is not None:
        cl, ct, cR = calc.get_wave_speeds(atoms)
        tip_max_x = old_tip_x + 10.0 * cR * dt  # FIXME definition of cR seems wrong, shouldn't need factor of 10 here...
    else:
        tip_max_x = left + 0.8 * width

    broken = ((nn != 6) & (x > left + 0.2 * width) & (x < tip_max_x) &
              (y > bottom + 0.1 * height) & (y < bottom + 0.9 * height))

    index = atoms.positions[broken, 0].argmax()
    tip_atom = broken.nonzero()[0][index]
    tip_x = atoms.positions[tip_atom, 0]

    strain = get_strain(atoms)
    eps_G = atoms.info['eps_G']
    print('tip_x: %.3f strain: %.4f delta: %.3f' %
          (tip_x, strain, strain / eps_G))

    if store:
        atoms.info['tip_atom'] = tip_atom
        atoms.info['tip_x'] = tip_x

    if results is not None:
        results.append(tip_x)

    return (tip_atom, tip_x, broken)
def printstatus():
    if dynamics.nsteps == 1:
        print """
State      Time/fs    Temp/K     Strain      G/(J/m^2)  CrackPos/A D(CrackPos)/A
---------------------------------------------------------------------------------"""

    log_format = ('%(label)-4s%(time)12.1f%(temperature)12.6f'+
                  '%(strain)12.4f%(crack_pos_x)12.2f    (%(d_crack_pos_x)+5.2f)')

    atoms.info['label'] = 'D'                  # Label for the status line
    atoms.info['time'] = dynamics.get_time()/units.fs
    atoms.info['temperature'] = get_temperature(atoms)
    atoms.info['strain'] = get_strain(atoms)
    # FIXME no local virial in TS, need another way to track the crack
    atoms.info['crack_pos_x'] = 0.
    atoms.info['d_crack_pos_x'] = 0.

    print log_format % atoms.info
Пример #6
0
def printstatus():
    if dynamics.nsteps == 1:
        print """
State      Time/fs    Temp/K     Strain      G/(J/m^2)  CrackPos/A D(CrackPos)/A 
---------------------------------------------------------------------------------"""

    log_format = ('%(label)-4s%(time)12.1f%(temperature)12.6f'+
                  '%(strain)12.5f%(G)12.4f%(crack_pos_x)12.2f    (%(d_crack_pos_x)+5.2f)')

    atoms.info['label'] = 'D'                  # Label for the status line
    atoms.info['time'] = dynamics.get_time()/units.fs
    atoms.info['temperature'] = (atoms.get_kinetic_energy() /
                                 (1.5*units.kB*len(atoms)))
    atoms.info['strain'] = get_strain(atoms)
    atoms.info['G'] = get_energy_release_rate(atoms)/(units.J/units.m**2)
    
    crack_pos = find_tip_stress_field(atoms)
    atoms.info['crack_pos_x'] = crack_pos[0]
    atoms.info['d_crack_pos_x'] = crack_pos[0] - orig_crack_pos[0]

    print log_format % atoms.info
Пример #7
0
def printstatus():
    if dynamics.nsteps == 1:
        print """
State      Time/fs    Temp/K     Strain      G/(J/m^2)  CrackPos/A D(CrackPos)/A 
---------------------------------------------------------------------------------"""

    log_format = (
        '%(label)-4s%(time)12.1f%(temperature)12.6f' +
        '%(strain)12.5f%(G)12.4f%(crack_pos_x)12.2f    (%(d_crack_pos_x)+5.2f)'
    )

    atoms.info['label'] = 'D'  # Label for the status line
    atoms.info['time'] = dynamics.get_time() / units.fs
    atoms.info['temperature'] = (atoms.get_kinetic_energy() /
                                 (1.5 * units.kB * len(atoms)))
    atoms.info['strain'] = get_strain(atoms)
    atoms.info['G'] = get_energy_release_rate(atoms) / (units.J / units.m**2)

    crack_pos = find_tip_stress_field(atoms)
    atoms.info['crack_pos_x'] = crack_pos[0]
    atoms.info['d_crack_pos_x'] = crack_pos[0] - orig_crack_pos[0]

    print log_format % atoms.info
Пример #8
0
def find_crack_tip(atoms,
                   coord=None,
                   d=None,
                   tipxfile=None,
                   cout=None,
                   dt=None,
                   store=True,
                   results=None,
                   siv=False):
    """
    Return atom at the crack tip and its x-coordinate

    Crack tip is defined to be location of rightmost atom
    whose nearest neighbour is at distance > 2.5*a
    """
    calc = atoms.get_calculator()
    a = calc.parameters['a']
    rc = calc.parameters['rc']

    i = neighbour_list('i', atoms, rc)
    nn = np.bincount(i)  # number of nearest neighbours, equal to 6 in bulk

    x = atoms.positions[:, 0]
    y = atoms.positions[:, 1]

    bottom = y.min()
    left = x.min()
    width = x.max() - x.min()
    height = y.max() - y.min()
    old_tip_x = atoms.info.get('tip_x', left + 0.3 * width)
    """Function to print the potential, kinetic and total energy"""
    epot = atoms.get_potential_energy() / len(atoms)
    ekin = atoms.get_kinetic_energy() / len(atoms)
    # print('Energy per atom: Epot = %.3feV  Ekin = %.3feV (T=%3.0fK)  '
    #       'Etot = %.3feV' % (epot, ekin, ekin / (1.5 * units.kB), epot + ekin))

    T = ekin / (1.5 * units.kB)
    # crack cannot have advanced more than c_R*dt
    if dt is not None:
        cl, ct, cR = calc.get_wave_speeds(atoms)
        #tip_max_x = old_tip_x + 10.0*cR*dt # FIXME definition of cR seems wrong, shouldn't need factor of 10 here...
        tip_max_x = old_tip_x + cR * dt  # FIXME unit conversion included now
    else:
        tip_max_x = left + 0.8 * width

    broken = ((nn != 6) & (x > left + 0.2 * width) & (x < tip_max_x) &
              (y > bottom + 0.1 * height) & (y < bottom + 0.9 * height))

    index = atoms.positions[broken, 0].argmax()
    tip_atom = broken.nonzero()[0][index]
    tip_x = atoms.positions[tip_atom, 0]
    tip_y = atoms.positions[tip_atom, 1]
    coord.append([tip_x, tip_y])
    #! d is distance
    if len(coord) >= 2:
        d.append(((coord[-1][0] - coord[-2][0])**2 +
                  (coord[-1][1] - coord[-2][1])**2)**(0.5))

    total_d = sum(d)
    strain = get_strain(atoms)
    eps_G = atoms.info['eps_G']
    print('tip_x: %.3f tip_y: %.0f d: %.2f T: %.1f strain: %.4f delta: %.3f' %
          (tip_x, tip_y, total_d, T, strain, strain / eps_G))
    # print(atoms.get_temperature())
    #! No need to write anything if set_initial_velocity() calls this function
    if not siv:
        #!saving tip_x to text file
        tipxfile.write(str(tip_x) + ',' + str(strain) + '\n')
        #!saving console output
        cout.write(
            'tip_x: %.3f tip_y: %.3f d: %.3f T: %d strain: %.4f delta: %.3f \n'
            % (tip_x, tip_y, total_d, T, strain, strain / eps_G))

    if store:
        atoms.info['tip_atom'] = tip_atom
        atoms.info['tip_x'] = tip_x

    if results is not None:
        results.append(tip_x)

    return (tip_atom, tip_x, broken)
traj_file = open('traj-m-6r.xyz', 'w')
minimiser = FIRE(atoms, restart='hess.traj')

def trajectory_write():
    ase.io.extxyz.write_xyz(traj_file, atoms)

# swap is an array of atom indices that have to be sent in opposite direction wrt
# what thin_strip_displacement_y would do.
swap = np.loadtxt('swap_topbottom_atoms.csv')
for i in range(1000):

    minimiser.run(fmax=params.relax_fmax)
    trajectory_write()
    # Find initial position of crack tip
    #crack_pos = find_tip_stress_field(crack_slab, calc=params.calc)
    #print 'Found crack tip at position %s' % crack_pos
    
    atoms.info['strain'] = get_strain(atoms)
    strain = atoms.info['strain']
    print("Strain: %f" % strain)
    # update atomic positions
    displacement = thin_strip_displacement_y(
        atoms.positions[:, 0],
        atoms.positions[:, 1],
        params.strain_rate * params.timestep,
        left + params.crack_seed_length,
        left + params.crack_seed_length +
        params.strain_ramp_length)
    displacement[swap] = -displacement[swap]
    atoms.positions[:, 1] += displacement