if sx is not None and sy is not None: sz = ( 1e24*mass/(density*mol) )/(sx*sy) a.set_cell([sx,sy,sz], scale_atoms=True) else: a0 = ( 1e24*mass/(density*mol) )**(1./3) a.set_cell([a0,a0,a0], scale_atoms=True) a.set_initial_charges([0]*len(a)) return a ### # For coordination counting cutoff = 1.85 els = parameter('stoichiometry') densities = parameter('densities') T1 = parameter('T1', 5000*kB) T2 = parameter('T2', 300*kB) dt1 = parameter('dt1', 0.1*fs) dt2 = parameter('dt2', 0.1*fs) tau1 = parameter('tau1', 5000*fs) tau2 = parameter('tau2', 500*fs) dtdump = parameter('dtdump', 100*fs) teq = parameter('teq', 50e3*fs) tqu = parameter('tqu', 20e3*fs) ### quick_calc = parameter('quick_calc')
FITTED_CRACK_TIP = 'Ag' ### logger = screen ### cryst = params.cryst.copy() cryst.set_pbc(True) ncryst = len(cryst) # Double check elastic constants. We're just assuming this is really a periodic # system. (True if it comes out of the cluster routines.) compute_elastic_constants = parameter('compute_elastic_constants', False) elastic_fmax = parameter('elastic_fmax', 0.05) elastic_symmetry = parameter('elastic_symmetry', 'triclinic') fmax = parameter('fmax', 0.01) if compute_elastic_constants: cryst.set_calculator(params.calc) log_file = open('elastic_constants.log', 'w') C, C_err = fit_elastic_constants(cryst, verbose=False, symmetry=elastic_symmetry, optimizer=ase.optimize.FIRE, logfile=log_file, fmax=elastic_fmax) log_file.close() print('Measured elastic constants (in GPa):') print(np.round(C*10/GPa)/10)
ACTUAL_CRACK_TIP = 'Au' FITTED_CRACK_TIP = 'Ag' ### logger = screen ### a, cryst, crk, k1g, tip_x, tip_y, bond1, bond2, boundary_mask, \ boundary_mask_bulk, tip_mask = setup_crack(logger=logger) ase.io.write('notch.xyz', a, format='extxyz') # Get general parameters basename = parameter('basename', 'energy_barrier') calc = parameter('calc') fmax = parameter('fmax', 0.01) # Get parameter used for fitting crack tip position optimize_tip_position = parameter('optimize_tip_position', False) residual_func = parameter('residual_func', crack.displacement_residual) _residual_func = residual_func tip_tol = parameter('tip_tol', 1e-4) tip_mixing_alpha = parameter('tip_mixing_alpha', 1.0) write_trajectory_during_optimization = parameter('write_trajectory_during_optimization', False) if optimize_tip_position: tip_x = (a.positions[bond1, 0] + a.positions[bond2, 0])/2 tip_y = (a.positions[bond1, 1] + a.positions[bond2, 1])/2
def setup_crack(logger=screen): calc = parameter('calc') cryst = parameter('cryst').copy() cryst.set_pbc(True) # Double check elastic constants. We're just assuming this is really a periodic # system. (True if it comes out of the cluster routines.) compute_elastic_constants = parameter('compute_elastic_constants', False) elastic_fmax = parameter('elastic_fmax', 0.01) elastic_symmetry = parameter('elastic_symmetry', 'triclinic') elastic_optimizer = parameter('elastic_optimizer', ase.optimize.FIRE) if compute_elastic_constants: cryst.set_calculator(calc) log_file = open('elastic_constants.log', 'w') C, C_err = fit_elastic_constants(cryst, verbose=False, symmetry=elastic_symmetry, optimizer=elastic_optimizer, logfile=log_file, fmax=elastic_fmax) log_file.close() logger.pr('Measured elastic constants (in GPa):') logger.pr(np.round(C * 10 / GPa) / 10) crk = crack.CubicCrystalCrack(parameter('crack_surface'), parameter('crack_front'), Crot=C / GPa) else: if has_parameter('C'): crk = crack.CubicCrystalCrack(parameter('crack_surface'), parameter('crack_front'), C=parameter('C')) else: crk = crack.CubicCrystalCrack(parameter('crack_surface'), parameter('crack_front'), parameter('C11'), parameter('C12'), parameter('C44')) logger.pr('Elastic constants used for boundary condition (in GPa):') logger.pr(np.round(crk.C * 10) / 10) # Get Griffith's k1. k1g = crk.k1g(parameter('surface_energy')) logger.pr('Griffith k1 = %f' % k1g) # Apply initial strain field. tip_x = parameter('tip_x', cryst.cell.diagonal()[0] / 2) tip_y = parameter('tip_y', cryst.cell.diagonal()[1] / 2) bondlength = parameter('bondlength', 2.7) bulk_nn = parameter('bulk_nn', 4) a = cryst.copy() a.set_pbc([False, False, True]) hydrogenate_flag = parameter('hydrogenate', False) hydrogenate_crack_face_flag = parameter('hydrogenate_crack_face', True) if hydrogenate_flag and not hydrogenate_crack_face_flag: # Get surface atoms of cluster with crack a = hydrogenate(cryst, bondlength, parameter('XH_bondlength'), b=a) g = a.get_array('groups') g[a.numbers == 1] = -1 a.set_array('groups', g) cryst = a.copy() k1 = parameter('k1') try: k1 = k1[0] except: pass ux, uy = crk.displacements(cryst.positions[:, 0], cryst.positions[:, 1], tip_x, tip_y, k1 * k1g) a.positions[:len(cryst), 0] += ux a.positions[:len(cryst), 1] += uy # Center notched configuration in simulation cell and ensure enough vacuum. oldr = a[0].position.copy() vacuum = parameter('vacuum') a.center(vacuum=vacuum, axis=0) a.center(vacuum=vacuum, axis=1) tip_x += a[0].x - oldr[0] tip_y += a[0].y - oldr[1] # Choose which bond to break. bond1, bond2 = \ parameter('bond', crack.find_tip_coordination(a, bondlength=bondlength, bulk_nn=bulk_nn)) if parameter('center_crack_tip_on_bond', False): tip_x, tip_y, dummy = (a.positions[bond1] + a.positions[bond2]) / 2 # Hydrogenate? coord = np.bincount(neighbour_list('i', a, bondlength), minlength=len(a)) a.set_array('coord', coord) if parameter('optimize_full_crack_face', False): g = a.get_array('groups') gcryst = cryst.get_array('groups') coord = a.get_array('coord') g[coord != 4] = -1 gcryst[coord != 4] = -1 a.set_array('groups', g) cryst.set_array('groups', gcryst) if hydrogenate_flag and hydrogenate_crack_face_flag: # Get surface atoms of cluster with crack exclude = np.logical_and(a.get_array('groups') == 1, coord != 4) a.set_array('exclude', exclude) a = hydrogenate(cryst, bondlength, parameter('XH_bondlength'), b=a, exclude=exclude) g = a.get_array('groups') g[a.numbers == 1] = -1 a.set_array('groups', g) basename = parameter('basename', 'energy_barrier') ase.io.write('{0}_hydrogenated.xyz'.format(basename), a, format='extxyz') # Move reference crystal by same amount cryst.set_cell(a.cell) cryst.set_pbc([False, False, True]) cryst.translate(a[0].position - oldr) # Groups mark the fixed region and the region use for fitting the crack tip. g = a.get_array('groups') gcryst = cryst.get_array('groups') logger.pr('Opening bond {0}--{1}, initial bond length {2}'.format( bond1, bond2, a.get_distance(bond1, bond2, mic=True))) # centre vertically on the opening bond if parameter('center_cell_on_bond', True): a.translate([ 0., a.cell[1, 1] / 2.0 - (a.positions[bond1, 1] + a.positions[bond2, 1]) / 2.0, 0. ]) a.info['bond1'] = bond1 a.info['bond2'] = bond2 return a, cryst, crk, k1g, tip_x, tip_y, bond1, bond2, g == 0, gcryst == 0, g == 1
Optimizer = ase.optimize.FIRE #Optimizer = ase.optimize.precon.LBFGS # Atom types used for outputting the crack tip position. ACTUAL_CRACK_TIP = 'Au' FITTED_CRACK_TIP = 'Ag' ### logger = screen ### # Get general parameters residual_func = parameter('residual_func', crack.displacement_residual) _residual_func = residual_func basename = parameter('basename', 'neb') calc = parameter('calc') fmax_neb = parameter('fmax_neb', 0.1) maxsteps_neb = parameter('maxsteps_neb', 100) Nimages = parameter('Nimages', 7) k_neb = parameter('k_neb', 1.0) a, cryst, crk, k1g, tip_x, tip_y, bond1, bond2, boundary_mask, \ boundary_mask_bulk, tip_mask = setup_crack(logger=logger) # Deformation gradient residual needs full Atoms object and therefore # special treatment here. if _residual_func == crack.deformation_gradient_residual:
from ase.optimize.precon import PreconLBFGS from matscipy import parameter from matscipy.elasticity import fit_elastic_constants from matscipy.fracture_mechanics.crack import CubicCrystalCrack, SinclairCrack from scipy.optimize import fsolve, fminbound from scipy.optimize.nonlin import NoConvergence import sys sys.path.insert(0, '.') import params calc = parameter('calc') fmax_flex = parameter('fmax_flex', 1e-2) fmax_arc = parameter('fmax_arc', 1e-3) max_opt_steps = parameter('max_opt_steps', 100) max_arc_steps = parameter('max_arc_steps', 10) vacuum = parameter('vacuum', 10.0) flexible = parameter('flexible', True) continuation = parameter('continuation', False) ds = parameter('ds', 1e-2) nsteps = parameter('nsteps', 10) a0 = parameter('a0') # lattice constant k0 = parameter('k0', 1.0) extended_far_field = parameter('extended_far_field', False) alpha0 = parameter('alpha0', 0.0) # initial guess for crack position dump = parameter('dump', False) precon = parameter('precon', False)
import ase.io from ase.units import GPa from matscipy import parameter from matscipy.elasticity import fit_elastic_constants from matscipy.fracture_mechanics.crack import CubicCrystalCrack, SinclairCrack args = sys.argv[1:] if not args: args = ['.'] # current directory only sys.path.insert(0, args[0]) import params calc = parameter('calc') fmax = parameter('fmax', 1e-3) vacuum = parameter('vacuum', 10.0) flexible = parameter('flexible', True) extended_far_field = parameter('extended_far_field', False) k0 = parameter('k0', 1.0) alpha0 = parameter('alpha0', 0.0) # initial guess for crack position colors = parameter('colors', ["#1B9E77", "#D95F02", "#7570B3", "#E7298A", "#66A61E"]) colors = itertools.cycle(colors) # compute elastic constants cryst = params.cryst.copy()
### Optimizer = ase.optimize.FIRE # Atom types used for outputting the crack tip position. ACTUAL_CRACK_TIP = 'Au' FITTED_CRACK_TIP = 'Ag' ### logger = screen ### calc = parameter('calc') cryst = params.cryst.copy() cryst.set_pbc(True) # Double check elastic constants. We're just assuming this is really a periodic # system. (True if it comes out of the cluster routines.) compute_elastic_constants = parameter('compute_elastic_constants', False) elastic_fmax = parameter('elastic_fmax', 0.01) elastic_symmetry = parameter('elastic_symmetry', 'triclinic') fmax = parameter('fmax', 0.01) if compute_elastic_constants: cryst.set_calculator(calc) log_file = open('elastic_constants.log', 'w')
if sx is not None and sy is not None: sz = ( 1e24*mass/(density*mol) )/(sx*sy) a.set_cell([sx,sy,sz], scale_atoms=True) else: a0 = ( 1e24*mass/(density*mol) )**(1./3) a.set_cell([a0,a0,a0], scale_atoms=True) a.set_initial_charges([0]*len(a)) return a ### # For coordination counting cutoff = 1.85 els = parameter('stoichiometry') densities = parameter('densities') T1 = parameter('T1', 5000*kB) T2 = parameter('T2', 300*kB) dt1 = parameter('dt1', 0.1*fs) dt2 = parameter('dt2', 0.1*fs) tau1 = parameter('tau1', 5000*fs) tau2 = parameter('tau2', 500*fs) dtdump = parameter('dtdump', 100*fs) teq = parameter('teq', 50e3*fs) tqu = parameter('tqu', 20e3*fs) nsteps_relax = parameter('nsteps_relax', 10000) ###
ACTUAL_CRACK_TIP = 'Au' FITTED_CRACK_TIP = 'Ag' ### logger = screen ### a, cryst, crk, k1g, tip_x, tip_y, bond1, bond2, boundary_mask, \ boundary_mask_bulk, tip_mask = setup_crack(logger=logger) ase.io.write('notch.xyz', a, format='extxyz') # Get general parameters basename = parameter('basename', 'crack_tip') calc = parameter('calc') fmax = parameter('fmax', 0.01) # Get parameter used for fitting crack tip position residual_func = parameter('residual_func', crack.displacement_residual) _residual_func = residual_func tip_tol = parameter('tip_tol', 1e-4) tip_mixing_alpha = parameter('tip_mixing_alpha', 1.0) write_trajectory_during_optimization = parameter( 'write_trajectory_during_optimization', False) tip_x = (a.positions[bond1, 0] + a.positions[bond2, 0]) / 2 tip_y = (a.positions[bond1, 1] + a.positions[bond2, 1]) / 2 logger.pr('Optimizing tip position -> initially centering tip bond. '
def setup_crack(logger=screen): calc = parameter('calc') cryst = parameter('cryst').copy() cryst.set_pbc(True) # Double check elastic constants. We're just assuming this is really a periodic # system. (True if it comes out of the cluster routines.) compute_elastic_constants = parameter('compute_elastic_constants', False) elastic_fmax = parameter('elastic_fmax', 0.01) elastic_symmetry = parameter('elastic_symmetry', 'triclinic') elastic_optimizer = parameter('elastic_optimizer', ase.optimize.FIRE) if compute_elastic_constants: cryst.set_calculator(calc) log_file = open('elastic_constants.log', 'w') C, C_err = fit_elastic_constants(cryst, verbose=False, symmetry=elastic_symmetry, optimizer=elastic_optimizer, logfile=log_file, fmax=elastic_fmax) log_file.close() logger.pr('Measured elastic constants (in GPa):') logger.pr(np.round(C*10/GPa)/10) crk = crack.CubicCrystalCrack(parameter('crack_surface'), parameter('crack_front'), Crot=C/GPa) else: if has_parameter('C'): crk = crack.CubicCrystalCrack(parameter('crack_surface'), parameter('crack_front'), C=parameter('C')) else: crk = crack.CubicCrystalCrack(parameter('crack_surface'), parameter('crack_front'), parameter('C11'), parameter('C12'), parameter('C44')) logger.pr('Elastic constants used for boundary condition (in GPa):') logger.pr(np.round(crk.C*10)/10) # Get Griffith's k1. k1g = crk.k1g(parameter('surface_energy')) logger.pr('Griffith k1 = %f' % k1g) # Apply initial strain field. tip_x = parameter('tip_x', cryst.cell.diagonal()[0]/2) tip_y = parameter('tip_y', cryst.cell.diagonal()[1]/2) bondlength = parameter('bondlength', 2.7) bulk_nn = parameter('bulk_nn', 4) a = cryst.copy() a.set_pbc([False, False, True]) hydrogenate_flag = parameter('hydrogenate', False) hydrogenate_crack_face_flag = parameter('hydrogenate_crack_face', True) if hydrogenate_flag and not hydrogenate_crack_face_flag: # Get surface atoms of cluster with crack a = hydrogenate(cryst, bondlength, parameter('XH_bondlength'), b=a) g = a.get_array('groups') g[a.numbers==1] = -1 a.set_array('groups', g) cryst = a.copy() k1 = parameter('k1') try: k1 = k1[0] except: pass ux, uy = crk.displacements(cryst.positions[:,0], cryst.positions[:,1], tip_x, tip_y, k1*k1g) a.positions[:len(cryst),0] += ux a.positions[:len(cryst),1] += uy # Center notched configuration in simulation cell and ensure enough vacuum. oldr = a[0].position.copy() vacuum = parameter('vacuum') a.center(vacuum=vacuum, axis=0) a.center(vacuum=vacuum, axis=1) tip_x += a[0].x - oldr[0] tip_y += a[0].y - oldr[1] # Choose which bond to break. bond1, bond2 = \ parameter('bond', crack.find_tip_coordination(a, bondlength=bondlength, bulk_nn=bulk_nn)) if parameter('center_crack_tip_on_bond', False): tip_x, tip_y, dummy = (a.positions[bond1]+a.positions[bond2])/2 # Hydrogenate? coord = np.bincount(neighbour_list('i', a, bondlength), minlength=len(a)) a.set_array('coord', coord) if parameter('optimize_full_crack_face', False): g = a.get_array('groups') gcryst = cryst.get_array('groups') coord = a.get_array('coord') g[coord!=4] = -1 gcryst[coord!=4] = -1 a.set_array('groups', g) cryst.set_array('groups', gcryst) if hydrogenate_flag and hydrogenate_crack_face_flag: # Get surface atoms of cluster with crack exclude = np.logical_and(a.get_array('groups')==1, coord!=4) a.set_array('exclude', exclude) a = hydrogenate(cryst, bondlength, parameter('XH_bondlength'), b=a, exclude=exclude) g = a.get_array('groups') g[a.numbers==1] = -1 a.set_array('groups', g) basename = parameter('basename', 'energy_barrier') ase.io.write('{0}_hydrogenated.xyz'.format(basename), a, format='extxyz') # Move reference crystal by same amount cryst.set_cell(a.cell) cryst.set_pbc([False, False, True]) cryst.translate(a[0].position - oldr) # Groups mark the fixed region and the region use for fitting the crack tip. g = a.get_array('groups') gcryst = cryst.get_array('groups') logger.pr('Opening bond {0}--{1}, initial bond length {2}'. format(bond1, bond2, a.get_distance(bond1, bond2, mic=True))) # centre vertically on the opening bond if parameter('center_cell_on_bond', True): a.translate([0., a.cell[1,1]/2.0 - (a.positions[bond1, 1] + a.positions[bond2, 1])/2.0, 0.]) a.info['bond1'] = bond1 a.info['bond2'] = bond2 return a, cryst, crk, k1g, tip_x, tip_y, bond1, bond2, g==0, gcryst==0, g==1
# Atom types used for outputting the crack tip position. ACTUAL_CRACK_TIP = 'Au' FITTED_CRACK_TIP = 'Ag' ### logger = screen ### a, cryst, crk, k1g, tip_x0, tip_y0, bond1, bond2, boundary_mask, \ boundary_mask_bulk, tip_mask = setup_crack(logger=logger) ase.io.write('notch.xyz', a, format='extxyz') # Global parameters basename = parameter('basename', 'quasistatic_crack') calc = parameter('calc') fmax = parameter('fmax', 0.01) # Determine simulation control k1_list = parameter('k1') old_k1 = k1_list[0] nsteps = len(k1_list) tip_dx_list = parameter('tip_dx', np.zeros(nsteps)) tip_dy_list = parameter('tip_dy', np.zeros(nsteps)) # Run crack calculation. tip_x = tip_x0 tip_y = tip_y0 a.set_calculator(calc) for i, ( k1, tip_dx, tip_dy ) in enumerate(zip(k1_list, tip_dx_list,
import sys import numpy as np from ase.units import GPa from matscipy import parameter from matscipy.elasticity import fit_elastic_constants from matscipy.fracture_mechanics.crack import CubicCrystalCrack, SinclairCrack from scipy.optimize import fsolve sys.path.insert(0, '.') import params calc = parameter('calc') fmax = parameter('fmax', 1e-3) max_steps = parameter('max_steps', 100) vacuum = parameter('vacuum', 10.0) alpha_scale = parameter('alpha_scale', 1.0) continuation = parameter('continuation', False) ds = parameter('ds', 1e-2) nsteps = parameter('nsteps', 10) method = parameter('method', 'full') k0 = parameter('k0', 1.0) # compute elastic constants cryst = params.cryst.copy() cryst.pbc = True cryst.calc = calc C, C_err = fit_elastic_constants(cryst,
import os import numpy as np import ase.io from ase.units import GPa from matscipy import parameter from matscipy.elasticity import fit_elastic_constants from matscipy.fracture_mechanics.crack import CubicCrystalCrack, SinclairCrack import sys sys.path.insert(0, '.') import params calc = parameter('calc') fmax = parameter('fmax', 1e-3) vacuum = parameter('vacuum', 10.0) flexible = parameter('flexible', True) extended_far_field = parameter('extended_far_field', False) k0 = parameter('k0', 1.0) alpha0 = parameter('alpha0', 0.0) # initial guess for crack position dump = parameter('dump', False) precon = parameter('precon', False) prerelax = parameter('prerelax', False) # compute elastic constants cryst = params.cryst.copy() cryst.pbc = True cryst.calc = calc C, C_err = fit_elastic_constants(cryst,
import h5py import ase.io from ase.units import GPa from matscipy import parameter from matscipy.elasticity import fit_elastic_constants from matscipy.fracture_mechanics.crack import CubicCrystalCrack, SinclairCrack from scipy.optimize.nonlin import NoConvergence import sys sys.path.insert(0, '.') import params calc = parameter('calc') fmax = parameter('fmax', 1e-3) max_steps = parameter('max_steps', 100) vacuum = parameter('vacuum', 10.0) flexible = parameter('flexible', True) continuation = parameter('continuation', False) ds = parameter('ds', 1e-2) nsteps = parameter('nsteps', 10) k0 = parameter('k0', 1.0) extended_far_field = parameter('extended_far_field', False) alpha0 = parameter('alpha0', 0.0) # initial guess for crack position dump = parameter('dump', False) precon = parameter('precon', False) prerelax = parameter('prerelax', False) traj_file = parameter('traj_file', 'x_traj.h5') traj_interval = parameter('traj_interval', 1)