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
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
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 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
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
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
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