def testcubic_relaxed(self): C, C_err = fit_elastic_constants(self.at0, 'cubic', optimizer=FIRE, fmax=self.fmax, verbose=False, graphics=False) self.assertArrayAlmostEqual(C/units.GPa, self.C_ref_relaxed, tol=1e-2) if abs(C_err).max() > 0.: self.assertArrayAlmostEqual(C_err/units.GPa, self.C_err_ref_relaxed, tol=1e-2)
def get_elastic_constants(pot_path=None, calculator=None, delta=1e-2, symbol="W"): """ return lattice parameter, and cubic elastic constants: C11, C12, 44 using matscipy function pot_path - path to the potential symbol : string Symbol of the element to pass to ase.lattuce.cubic.SimpleCubicFactory default is "W" for tungsten """ unit_cell = bulk(symbol) if (pot_path is not None) and (calculator is None): # create lammps calculator with the potential lammps = LAMMPSlib(lmpcmds=["pair_style eam/fs", "pair_coeff * * %s W" % pot_path], atom_types={'W': 1}, keep_alive=True) calculator = lammps unit_cell.set_calculator(calculator) # simple calculation to get the lattice constant and cohesive energy # alat0 = W.cell[0][1] - W.cell[0][0] sf = StrainFilter(unit_cell) # or UnitCellFilter(W) -> to minimise wrt pos, cell opt = FIRE(sf) opt.run(fmax=1e-4) # max force in eV/A alat = unit_cell.cell[0][1] - unit_cell.cell[0][0] # print("a0 relaxation %.4f --> %.4f" % (a0, a)) # e_coh = W.get_potential_energy() # print("Cohesive energy %.4f" % e_coh) Cij, Cij_err = fit_elastic_constants(unit_cell, symmetry="cubic", delta=delta) Cij = Cij/GPa # unit conversion to GPa elasticMatrix3x3 = Cij[:3, :3] # average of diagonal elements: C11, C22, C33 C11 = elasticMatrix3x3.diagonal().mean() # make mask to extract non diagonal elements mask = np.ones((3, 3), dtype=bool) np.fill_diagonal(mask, False) # average of all non diagonal elements from 1 to 3 C12 = elasticMatrix3x3[mask].mean() # average of diagonal elements from 4 till 6: C44, C55, C66, C44 = Cij[3:, 3:].diagonal().mean() # A = 2.*C44/(C11 - C12) if (pot_path is not None) and (calculator is None): lammps.lmp.close() return alat, C11, C12, C44
def test_Grochola(self): a = FaceCenteredCubic('Au', size=[2,2,2]) calc = EAM('Au-Grochola-JCP05.eam.alloy') a.set_calculator(calc) FIRE(StrainFilter(a, mask=[1,1,1,0,0,0]), logfile=None).run(fmax=0.001) a0 = a.cell.diagonal().mean()/2 self.assertTrue(abs(a0-4.0701)<2e-5) self.assertTrue(abs(a.get_potential_energy()/len(a)+3.924)<0.0003) C, C_err = fit_elastic_constants(a, symmetry='cubic', verbose=False) C11, C12, C44 = Voigt_6x6_to_cubic(C) self.assertTrue(abs((C11-C12)/GPa-32.07)<0.7) self.assertTrue(abs(C44/GPa-45.94)<0.5)
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) crk = crack.CubicCrystalCrack(params.crack_surface, params.crack_front, Crot=C/GPa) else: if hasattr(params, 'C'): crk = crack.CubicCrystalCrack(params.crack_surface, params.crack_front, C=params.C) else: crk = crack.CubicCrystalCrack(params.crack_surface, params.crack_front, params.C11, params.C12, params.C44)
def test_embedding_size_convergence(self): calc = Tersoff(**Tersoff_PRB_39_5566_Si_C) el = 'C' a0 = 3.566 surface_energy = 2.7326 * 10 crack_surface = [1, 1, 1] crack_front = [1, -1, 0] skin_x, skin_y = 1, 1 cryst = bulk(el, cubic=True) cryst.set_calculator(calc) FIRE(UnitCellFilter(cryst), logfile=None).run(fmax=1e-6) a0 = cryst.cell.diagonal().mean() bondlength = cryst.get_distance(0, 1) #print('a0 =', a0, ', bondlength =', bondlength) cryst = diamond(el, a0, [1, 1, 1], crack_surface, crack_front) cryst.set_pbc(True) cryst.set_calculator(calc) cryst.set_cell(cryst.cell.diagonal(), scale_atoms=True) C, C_err = fit_elastic_constants(cryst, verbose=False, symmetry='cubic', optimizer=FIRE, fmax=1e-6) #print('Measured elastic constants (in GPa):') #print(np.round(C*10/units.GPa)/10) bondlengths = [] refcell = None reftip_x = None reftip_y = None #[41, 39, 1], for i, n in enumerate([[21, 19, 1], [11, 9, 1], [6, 5, 1]]): #print(n) cryst = diamond(el, a0, n, crack_surface, crack_front) set_groups(cryst, n, skin_x, skin_y) cryst.set_pbc(True) cryst.set_calculator(calc) FIRE(UnitCellFilter(cryst), logfile=None).run(fmax=1e-6) cryst.set_cell(cryst.cell.diagonal(), scale_atoms=True) ase.io.write('cryst_{}.xyz'.format(i), cryst, format='extxyz') crk = crack.CubicCrystalCrack(crack_surface, crack_front, Crot=C / units.GPa) k1g = crk.k1g(surface_energy) tip_x = cryst.cell.diagonal()[0] / 2 tip_y = cryst.cell.diagonal()[1] / 2 a = cryst.copy() a.set_pbc([False, False, True]) k1 = 1.0 ux, uy = crk.displacements(cryst.positions[:, 0], cryst.positions[:, 1], tip_x, tip_y, k1 * k1g) a.positions[:, 0] += ux a.positions[:, 1] += uy # Center notched configuration in simulation cell and ensure enough vacuum. oldr = a[0].position.copy() if refcell is None: a.center(vacuum=10.0, axis=0) a.center(vacuum=10.0, axis=1) refcell = a.cell.copy() tip_x += a[0].x - oldr[0] tip_y += a[0].y - oldr[1] reftip_x = tip_x reftip_y = tip_y else: a.set_cell(refcell) # Shift tip position so all systems are exactly centered at the same spot a.positions[:, 0] += reftip_x - tip_x a.positions[:, 1] += reftip_y - tip_y refpositions = a.positions.copy() # Move reference crystal by same amount cryst.set_cell(a.cell) cryst.set_pbc([False, False, True]) cryst.translate(a[0].position - oldr) bond1, bond2 = crack.find_tip_coordination( a, bondlength=bondlength * 1.2) # Groups mark the fixed region and the region use for fitting the crack tip. g = a.get_array('groups') gcryst = cryst.get_array('groups') ase.io.write('cryst_{}.xyz'.format(i), cryst) a.set_calculator(calc) a.set_constraint(FixAtoms(mask=g == 0)) FIRE(a, logfile=None).run(fmax=1e-6) dpos = np.sqrt(( (a.positions[:, 0] - refpositions[:, 0]) / ux)**2 + ( (a.positions[:, 1] - refpositions[:, 1]) / uy)**2) a.set_array('dpos', dpos) distance_from_tip = np.sqrt((a.positions[:, 0] - reftip_x)**2 + (a.positions[:, 1] - reftip_y)**2) ase.io.write('crack_{}.xyz'.format(i), a) # Compute average bond length per atom neighi, neighj, neighd = neighbour_list('ijd', a, cutoff=bondlength * 1.2) coord = np.bincount(neighi) assert coord.max() == 4 np.savetxt( 'dpos_{}.out'.format(i), np.transpose( [distance_from_tip[coord == 4], dpos[coord == 4]])) # Compute distances from tipcenter neighdist = np.sqrt(( (a.positions[neighi, 0] + a.positions[neighj, 0]) / 2 - reftip_x)**2 + ( (a.positions[neighi, 1] + a.positions[neighj, 1]) / 2 - reftip_y)**2) np.savetxt('bl_{}.out'.format(i), np.transpose([neighdist, neighd])) bondlengths += [a.get_distance(bond1, bond2)] print(bondlengths, np.diff(bondlengths), bondlengths / bondlengths[-1] - 1) assert np.all(np.diff(bondlengths) > 0) assert np.max(bondlengths / bondlengths[0] - 1) < 0.01
precon = parameter('precon', False) prerelax = parameter('prerelax', False) traj_file = parameter('traj_file', 'x_traj.h5') restart_file = parameter('restart_file', traj_file) traj_interval = parameter('traj_interval', 1) direction = parameter('direction', +1) lbfgs = parameter('lbfgs', False) preconlbfgs = parameter('preconlbfgs', True) ds_min = parameter('ds_min', 1e-5) # compute elastic constants cryst = params.cryst.copy() cryst.pbc = True cryst.calc = calc C, C_err = fit_elastic_constants(cryst, symmetry=parameter('elastic_symmetry', 'triclinic')) crk = CubicCrystalCrack(parameter('crack_surface'), parameter('crack_front'), Crot=C / GPa) # Get Griffith's k1. k1g = crk.k1g(parameter('surface_energy')) print('Griffith k1 = %f' % k1g) cluster = params.cluster.copy() if continuation and not os.path.exists(restart_file): continuation = False
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') 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) crk = crack.CubicCrystalCrack(params.crack_surface, params.crack_front, Crot=C / GPa) else: if hasattr(params, 'C'): crk = crack.CubicCrystalCrack(params.crack_surface, params.crack_front, C=params.C) else:
def testtriclinic_unrelaxed(self): C, C_err = fit_elastic_constants(self.at0, 'triclinic', verbose=False, graphics=False) self.assertArrayAlmostEqual(C / units.GPa, self.C_ref, tol=0.2)
def test_embedding_size_convergence(self): calc = Tersoff(**Tersoff_PRB_39_5566_Si_C) el = 'C' a0 = 3.566 surface_energy = 2.7326 * 10 crack_surface = [1, 1, 1] crack_front = [1, -1, 0] skin_x, skin_y = 1, 1 cryst = bulk(el, cubic=True) cryst.set_calculator(calc) FIRE(UnitCellFilter(cryst), logfile=None).run(fmax=1e-6) a0 = cryst.cell.diagonal().mean() bondlength = cryst.get_distance(0, 1) #print('a0 =', a0, ', bondlength =', bondlength) cryst = diamond(el, a0, [1,1,1], crack_surface, crack_front) cryst.set_pbc(True) cryst.set_calculator(calc) cryst.set_cell(cryst.cell.diagonal(), scale_atoms=True) C, C_err = fit_elastic_constants(cryst, verbose=False, symmetry='cubic', optimizer=FIRE, fmax=1e-6) #print('Measured elastic constants (in GPa):') #print(np.round(C*10/units.GPa)/10) bondlengths = [] refcell = None reftip_x = None reftip_y = None #[41, 39, 1], for i, n in enumerate([[21, 19, 1], [11, 9, 1], [6, 5, 1]]): #print(n) cryst = diamond(el, a0, n, crack_surface, crack_front) set_groups(cryst, n, skin_x, skin_y) cryst.set_pbc(True) cryst.set_calculator(calc) FIRE(UnitCellFilter(cryst), logfile=None).run(fmax=1e-6) cryst.set_cell(cryst.cell.diagonal(), scale_atoms=True) ase.io.write('cryst_{}.xyz'.format(i), cryst, format='extxyz') crk = crack.CubicCrystalCrack(crack_surface, crack_front, Crot=C/units.GPa) k1g = crk.k1g(surface_energy) tip_x = cryst.cell.diagonal()[0]/2 tip_y = cryst.cell.diagonal()[1]/2 a = cryst.copy() a.set_pbc([False, False, True]) k1 = 1.0 ux, uy = crk.displacements(cryst.positions[:,0], cryst.positions[:,1], tip_x, tip_y, k1*k1g) a.positions[:, 0] += ux a.positions[:, 1] += uy # Center notched configuration in simulation cell and ensure enough vacuum. oldr = a[0].position.copy() if refcell is None: a.center(vacuum=10.0, axis=0) a.center(vacuum=10.0, axis=1) refcell = a.cell.copy() tip_x += a[0].x - oldr[0] tip_y += a[0].y - oldr[1] reftip_x = tip_x reftip_y = tip_y else: a.set_cell(refcell) # Shift tip position so all systems are exactly centered at the same spot a.positions[:, 0] += reftip_x - tip_x a.positions[:, 1] += reftip_y - tip_y refpositions = a.positions.copy() # Move reference crystal by same amount cryst.set_cell(a.cell) cryst.set_pbc([False, False, True]) cryst.translate(a[0].position - oldr) bond1, bond2 = crack.find_tip_coordination(a, bondlength=bondlength*1.2) # Groups mark the fixed region and the region use for fitting the crack tip. g = a.get_array('groups') gcryst = cryst.get_array('groups') ase.io.write('cryst_{}.xyz'.format(i), cryst) a.set_calculator(calc) a.set_constraint(FixAtoms(mask=g==0)) FIRE(a, logfile=None).run(fmax=1e-6) dpos = np.sqrt(((a.positions[:, 0]-refpositions[:, 0])/ux)**2 + ((a.positions[:, 1]-refpositions[:, 1])/uy)**2) a.set_array('dpos', dpos) distance_from_tip = np.sqrt((a.positions[:, 0]-reftip_x)**2 + (a.positions[:, 1]-reftip_y)**2) ase.io.write('crack_{}.xyz'.format(i), a) # Compute average bond length per atom neighi, neighj, neighd = neighbour_list('ijd', a, cutoff=bondlength*1.2) coord = np.bincount(neighi) assert coord.max() == 4 np.savetxt('dpos_{}.out'.format(i), np.transpose([distance_from_tip[coord==4], dpos[coord==4]])) # Compute distances from tipcenter neighdist = np.sqrt(((a.positions[neighi,0]+a.positions[neighj,0])/2-reftip_x)**2 + ((a.positions[neighi,1]+a.positions[neighj,1])/2-reftip_y)**2) np.savetxt('bl_{}.out'.format(i), np.transpose([neighdist, neighd])) bondlengths += [a.get_distance(bond1, bond2)] print(bondlengths, np.diff(bondlengths), bondlengths/bondlengths[-1]-1) assert np.all(np.diff(bondlengths) > 0) assert np.max(bondlengths/bondlengths[0]-1) < 0.01
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
def testtriclinic_relaxed(self): C, C_err = fit_elastic_constants(self.at0, 'triclinic', optimizer=FIRE, fmax=self.fmax, verbose=False, graphics=False) self.assertArrayAlmostEqual(C/units.GPa, self.C_ref_relaxed, tol=0.2)
def testcubic_unrelaxed(self): C, C_err = fit_elastic_constants(self.at0, 'cubic', verbose=False, graphics=False) self.assertArrayAlmostEqual(C/units.GPa, self.C_ref, tol=1e-2) if abs(C_err).max() > 0.: self.assertArrayAlmostEqual(C_err/units.GPa, self.C_err_ref, tol=1e-2)
bulk_at.set_calculator(model.calculator) bulk_at = relax_config(bulk_at, relax_pos=True, relax_cell=True, tol=1.0e-4, traj_file=None) a0 = bulk_at.get_cell_lengths_and_angles()[0] * np.sqrt(2.0) bulk_at = bulk("Si", "diamond", a0) from matscipy import elasticity from ase.optimize import BFGS bulk_at.set_calculator(model.calculator) opt = BFGS b = elasticity.fit_elastic_constants(bulk_at, symmetry='cubic', optimizer=opt) bulk_modulus = elasticity.elastic_moduli(b[0])[3] try: with open("../model-{}-test-phonon_diamond-properties.json".format( model.name)) as f: j = json.load(f) f0 = j["phonon_diamond_frequencies"] bf0 = j["phonon_diamond_band_frequencies"] band_distances = j["phonon_diamond_band_distances"] weights = j["phonon_diamond_weights"] except: phonon_properties = phonons(model, bulk_at,
fit_elastic_constants = CP(fit_elastic_constants) ### cryst = params.cryst.copy() # 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 = param('compute_elastic_constants', False) if compute_elastic_constants: pbc = cryst.pbc.copy() cryst.set_pbc(True) cryst.set_calculator(params.calc) C, C_err = fit_elastic_constants(cryst, verbose=False, optimizer=ase.optimize.FIRE) cryst.set_pbc(pbc) logger.pr('Measured elastic constants (in GPa):') logger.pr(np.round(C*10/GPa)/10) crk = crack.CubicCrystalCrack(params.crack_surface, params.crack_front, Crot=C/GPa) else: if hasattr(params, 'C'): crk = crack.CubicCrystalCrack(params.crack_surface, params.crack_front, C=params.C) else: crk = crack.CubicCrystalCrack(params.crack_surface, params.crack_front, params.C11, params.C12, params.C44)
def testtriclinic_unrelaxed(self): C, C_err = fit_elastic_constants(self.at0, 'triclinic', verbose=False, graphics=False) self.assertArrayAlmostEqual(C/units.GPa, self.C_ref, tol=0.2)