def makecrack_main(params, stem): """Given a CrackParams object `param`, construct and return a new crack slab Atoms object.""" xmlfilename = stem+'.xml' print_title('Initialisation') verbosity_push(params.io_verbosity) params.print_() print("Initialising classical potential with args " + params.classical_args.strip() + " from file " + xmlfilename) classicalpot = Potential(params.classical_args, param_filename=xmlfilename) classicalpot.print_() mpi_glob = MPI_context() crack_slab, width, height, E, v, v2, bulk = crack_make_slab(params, classicalpot) if params.crack_free_surfaces: depth = crack_slab.pos[3,:].max() - crack_slab.pos[3,:].min() else: depth = crack_slab.lattice[3,3] # Save bulk cube (used for qm_rescale_r parameter in crack code) if params.qm_args.startswith('TB'): bigger_bulk = supercell(bulk, 2, 2, 2) bulk = bigger_bulk bulk.write(stem+'_bulk.xyz') crack_slab.write(stem+'_slab.xyz') crack_slab.params['OrigWidth'] = width crack_slab.params['OrigHeight'] = height crack_slab.params['OrigDepth'] = depth crack_slab.params['YoungsModulus'] = E crack_slab.params['PoissonRatio_yx'] = v crack_slab.params['PoissonRatio_yz'] = v2 # Open surfaces, remain periodic in z direction (normal to plane) # and optionally also in x direction if crack_double_ended is true if not params.crack_double_ended: crack_slab.lattice[1,1] = crack_slab.lattice[1,1] + params.crack_vacuum_size crack_slab.lattice[2,2] = crack_slab.lattice[2,2] + params.crack_vacuum_size crack_slab.set_lattice(crack_slab.lattice, False) # 3D crack with free surfaces at z = +/- depth/2 if params.crack_free_surfaces: crack_slab.pos[3,:] -= crack_slab.pos[3,:].mean() # center on z=0 crack_slab.lattice[3,3] = crack_slab.lattice[3,3] + params.crack_vacuum_size crack_slab.set_lattice(crack_slab.lattice, False) # Map atoms into cell AFTER changing to the new lattice crack_slab.map_into_cell() miny, maxy = crack_slab.pos[2,:].min(), crack_slab.pos[2,:].max() assert abs((maxy-miny) - height) < 1e-5 # be sure that remapping didn't change height of slab # Add various properties to crack_slab crack_slab.add_property('hybrid', 0) crack_slab.add_property('hybrid_mark', HYBRID_NO_MARK) crack_slab.add_property('changed_nn', 0) crack_slab.add_property('move_mask', 0) crack_slab.add_property('nn', 0) crack_slab.add_property('old_nn', 0) crack_slab.add_property('md_old_changed_nn', 0) crack_slab.add_property('edge_mask', 0) crack_slab.add_property('crack_surface', False) crack_slab.add_property('crack_front', False) if params.crack_fix_dipoles: crack_slab.add_property('fixdip', False) print_title('Fixing Atoms') # Fix top and bottom edges - anything within crack_edge_fix_tol of ymax or ymin is fixed miny, maxy = crack_slab.pos[2,:].min(), crack_slab.pos[2,:].max() crack_slab.move_mask[:] = 1 crack_slab.move_mask[(abs(crack_slab.pos[2,:]-maxy) < params.crack_edge_fix_tol) | (abs(crack_slab.pos[2,:]-miny) < params.crack_edge_fix_tol)] = 0 if params.crack_fix_sides: maxx, minx = crack_slab.pos[1,:].min(), crack_slab.pos[1,:].max() crack_slab.move_mask[(abs(crack_slab.pos[1,:]-maxx) < params.crack_edge_fix_tol) | (abs(crack_slab.pos[1,:]-minx) < params.crack_edge_fix_tol)] = 0 print('%d atoms. %d fixed atoms' % (crack_slab.n, crack_slab.n - crack_slab.move_mask.sum())) print_title('Setting edge mask') crack_slab.edge_mask[:] = 0 minx, maxx = crack_slab.pos[1,:].min(), crack_slab.pos[1,:].max() crack_slab.edge_mask[(abs(crack_slab.pos[1,:]-minx) < params.selection_edge_tol) | (abs(crack_slab.pos[1,:]-maxx) < params.selection_edge_tol)] = 1 miny, maxy = crack_slab.pos[2,:].min(), crack_slab.pos[2,:].max() crack_slab.edge_mask[(abs(crack_slab.pos[2,:]-miny) < params.selection_edge_tol) | (abs(crack_slab.pos[2,:]-maxy) < params.selection_edge_tol)] = 1 if params.crack_free_surfaces: # Open surfaces at +/- z minz, maxz = crack_slab.pos[3,:].min(), crack_slab.pos[3,:].max() crack_slab.edge_mask[(abs(crack_slab.pos[3,:]-minz) < params.selection_edge_tol) | (abs(crack_slab.pos[3,:]-maxz) < params.selection_edge_tol)] = 1 if params.crack_fix_dipoles: print_title('Fixing dipoles') crack_slab.fixdip[(abs(crack_slab.pos[2,:]-maxy) < params.crack_fix_dipoles_tol) | (abs(crack_slab.pos[2,:]-miny) < params.crack_fix_dipoles_tol)] = 1 if params.crack_fix_sides: maxx, minx = crack_slab.pos[1,:].min(), crack_slab.pos[1,:].max() crack_slab.fixdip[(abs(crack_slab.pos[1,:]-maxx) < params.crack_fix_dipoles_tol) | (abs(crack_slab.pos[1,:]-minx) < params.crack_fix_dipoles_tol)] = 1 if params.crack_curved_front: crack_make_seed_curved_front(crack_slab, params) else: crack_make_seed(crack_slab, params) if params.crack_apply_initial_load: crack_calc_load_field(crack_slab, params, classicalpot, params.crack_loading, overwrite_pos=True, mpi=mpi_glob) crack_slab.write('dump.xyz') crack_update_connect(crack_slab, params) if not params.simulation_classical: if (params.selection_method.strip() == 'crack_front' or params.crack_tip_method.strip() == 'local_energy'): classicalpot.calc(crack_slab, local_energy=True) crack_setup_marks(crack_slab, params) crack_update_selection(crack_slab, params) if params.any_per_atom_tau(): # Set up per_atom_tau property for ramped Langevin thermostat: # # tau # ^ # |\ /| |\ /| max_tau # | \ / | | \ / | # | \ / | constant E | \ / | # | \ / | (tau = 0) | \ / | # | \/ | | \/ | # +----------+---------------------+----------+---> x # -w/2 -w/2+r w/2-r w/2 w_by_2 = crack_slab.OrigWidth/2. ramp_len = params.crack_thermostat_ramp_length max_tau = params.crack_thermostat_ramp_max_tau print 'Adding thermostat ramp with length', ramp_len, 'max_tau', max_tau @np.vectorize def tau(x): if x < -w_by_2 + ramp_len/2: q = (x+w_by_2)/(ramp_len/2.) return max_tau*(1.- q) elif (x > -w_by_2 + ramp_len/2 and x < -w_by_2 + ramp_len): q = (x+w_by_2-ramp_len/2.)/(ramp_len/2.) return max_tau*q elif (x > -w_by_2 + ramp_len and x < w_by_2 - ramp_len): return 0. elif (x > w_by_2 - ramp_len and x < w_by_2 - ramp_len/2): q = (x-w_by_2+ramp_len)/(ramp_len/2.) return max_tau*(1.- q) else: q = (x-w_by_2+ramp_len/2.)/(ramp_len/2.) return max_tau*q crack_slab.add_property('per_atom_tau', tau(crack_slab.pos[1,:])) return crack_slab
def crack_strain_energy_release_rate(at, bulk=None, f_min=.8, f_max=.9, stem=None, avg_pos=False): """ Compute strain energy release rate G from elastic potential energy in a strip """ print 'Analytical effective elastic modulus E\' = ', at.YoungsModulus/(1-at.PoissonRatio_yx**2), 'GPa' print 'Analytical energy release rate G = ', crack_measure_g(at, at.YoungsModulus, at.PoissonRatio_yx, at.OrigHeight), 'J/m^2' if bulk is None: if stem is None: raise ValueError('Either "bulk" or "stem" must be present') bulk = Atoms(stem+'_bulk.xyz') if not hasattr(at, 'local_energy') or not hasattr(bulk, 'energy'): if stem is None: raise ValueError('local_energy property not found in Atoms and "stem" is missing') xmlfile = stem+'.xml' params = CrackParams(xmlfile) pot = Potential(params.classical_args, param_filename=stem+'.xml') pot.print_() if not hasattr(at, 'local_energy'): if avg_pos: tmp_pos = at.pos.copy() at.pos[...] = at.avgpos at.set_cutoff(pot.cutoff()+1.) at.calc_connect() pot.calc(at, args_str="local_energy") if avg_pos: at.pos[...] = tmp_pos if not hasattr(bulk, 'energy'): bulk.set_cutoff(pot.cutoff()+1.) bulk.calc_connect() pot.calc(bulk, args_str='energy') h = at.pos[2,:].max() - at.pos[2,:].min() h0 = at.OrigHeight strain = (h - h0)/h0 print 'Applied strain', strain x_min = f_min*at.OrigWidth - at.OrigWidth/2. x_max = f_max*at.OrigWidth - at.OrigWidth/2. strip = np.logical_and(at.move_mask == 1, np.logical_and(at.pos[1,:] > x_min, at.pos[1,:] < x_max)) at.add_property('strip', strip, overwrite=True) strip_depth = at.lattice[3,3] strip_width = at.pos[1,strip].max() - at.pos[1,strip].min() strip_height = at.pos[2,strip].max() - at.pos[2,strip].min() strip_volume = strip_width*strip_height*strip_depth print 'Strip contains', strip.sum(), 'atoms', 'width', strip_width, 'height', strip_height, 'volume', strip_volume strain_energy_density = (at.local_energy[strip].sum() - bulk.energy/bulk.n*strip.sum())/strip_volume print 'Strain energy density in strip', strain_energy_density, 'eV/A**3' E_effective = 2*strain_energy_density/strain**2*GPA print 'Effective elastic modulus E =', E_effective, 'GPa' G_effective = strain_energy_density*strip_height*J_PER_M2 print 'Effective energy release rate G =', G_effective, 'J/m^2' return G_effective
def molecular_dynamics(system, potential, potential_filename=None, temperature=300, total_steps=1100000, timestep=1.0, connect_interval=200, write_interval=20000, equilibration_steps=100000, out_of_plane=None, random_seed=None): """ Run very simple molecular dynamics to generate some configurations. Writes configurations out as xyz and CASTEP files. """ info("Inside MD.") if random_seed is None: random_seed = random.SystemRandom().randint(0, 2**63) quippy.system.system_set_random_seeds(random_seed) info("Quippy Random Seed {0}.".format(random_seed)) system = Atoms(system) # Can take Potential objects, or just use a string if not isinstance(potential, Potential): if potential_filename: potential = Potential(potential, param_filename=potential_filename) else: potential = Potential(potential) system.set_calculator(potential) dynamical_system = DynamicalSystem(system) with Capturing(debug_on_exit=True): dynamical_system.rescale_velo(temperature) if out_of_plane is not None: # Stop things moving vertically in the cell dynamical_system.atoms.velo[3, :] = 0 base_dir = os.getcwd() run_path = '{0}_{1:g}/'.format(system.info['name'], temperature) info("Putting files in {0}.".format(run_path)) os.mkdir(run_path) os.chdir(run_path) trajectory = 'traj_{0}_{1:g}.xyz'.format(system.info['name'], temperature) out = AtomsWriter(trajectory) dynamical_system.atoms.set_cutoff(potential.cutoff() + 2.0) dynamical_system.atoms.calc_connect() potential.calc(dynamical_system.atoms, force=True, energy=True, virial=True) structure_count = 0 # Basic NVE molecular dynamics for step_number in range(1, total_steps + 1): dynamical_system.advance_verlet1(timestep, virial=dynamical_system.atoms.virial) potential.calc(dynamical_system.atoms, force=True, energy=True, virial=True) dynamical_system.advance_verlet2(timestep, f=dynamical_system.atoms.force, virial=dynamical_system.atoms.virial) # Maintenance of the system if not step_number % connect_interval: debug("Connect at step {0}".format(step_number)) dynamical_system.atoms.calc_connect() if step_number < equilibration_steps: with Capturing(debug_on_exit=True): dynamical_system.rescale_velo(temperature) if not step_number % write_interval: debug("Status at step {0}".format(step_number)) # Print goes to captured stdout with Capturing(debug_on_exit=True): dynamical_system.print_status( epot=dynamical_system.atoms.energy) dynamical_system.rescale_velo(temperature) if step_number > equilibration_steps: debug("Write at step {0}".format(step_number)) out.write(dynamical_system.atoms) sp_path = '{0:03d}'.format(structure_count) write_filename = '{0}_{1:g}.{2:03d}'.format( system.info['name'], temperature, structure_count) os.mkdir(sp_path) os.chdir(sp_path) castep_write(dynamical_system.atoms, filename=write_filename) espresso_write(dynamical_system.atoms, prefix=write_filename) write_extxyz("{0}.xyz".format(write_filename), dynamical_system.atoms) info("Wrote a configuration {0}.".format(write_filename)) os.chdir('..') structure_count += 1 out.close() os.chdir(base_dir) info("MD Done.")
# setup clusters to be calculated d = diamond(5.44, 14) at = supercell(d, 2, 2, 2) at.rattle(0.05) at.calc_connect() clusters = list( iter_atom_centered_clusters(at, buffer_hops=4, randomise_buffer=False)) pot = Potential('IP SW', param_filename='params.xml') for i, c in enumerate(clusters): client_id, nstep = i % N_JOBS, i // N_JOBS data = pack_atoms_to_reftraj_str(c, nstep) cluster_map[(client_id, nstep)] = (c, i) input_qs[client_id].put(data) pot.calc(c, args_str='energy force virial') t_clus = time.time() # write initial input file for each client for client_id, input_q in enumerate(input_qs): data = input_q.get() c, i = cluster_map[(client_id, 0)] c.write('atoms.%d.xyz' % client_id, real_format=MSG_FLOAT_FORMAT) scp = subprocess.Popen( ['scp', 'atoms.%d.xyz' % client_id, remote_host + ':']) scp.wait() t_input = time.time() for param_file in param_files:
def quippy_client(ip, port, client_id, maxsteps): pot = Potential('IP SW') args_str = 'force energy virial' print 'Starting client with ID %d maxsteps %d' % (client_id, maxsteps) for step in range(maxsteps): # open connection to server sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) try: # say hello and ask server for some Atoms (status 'A') # identify ourselves with an ID number, formatted as an 8-byte ascii string id_str = ('A%7d' % client_id).encode('ascii') totalsent = 0 while totalsent < MSG_LEN_SIZE: sent = sock.send(id_str[totalsent:]) if sent == 0: raise RuntimeError('socket connection broken while sending client ID') totalsent += sent # now receive the length of the data, formatted as an 8-byte ascii string data_length = '' while len(data_length) < MSG_LEN_SIZE: chunk = sock.recv(MSG_LEN_SIZE - len(data_length)) if not chunk: raise RuntimeError('socket connection broken while reading length') data_length += chunk data_length = int(data_length) # now receive the data itself data = '' while len(data) < data_length: chunk = sock.recv(data_length - len(data)) if not chunk: raise RuntimeError('socket connection broken while reading data') data += chunk # and finally receive the end marker marker = '' while len(marker) < MSG_END_MARKER_SIZE: chunk = sock.recv(MSG_END_MARKER_SIZE - len(marker)) if not chunk: raise RuntimeError('socket connection broken while reading end marker') marker += chunk assert marker == MSG_END_MARKER finally: sock.close() # construct Atoms object from data string in REFTRAJ format at = unpack_reftraj_str_to_atoms(data) # do the calculation - this will take a long time in real use-case pot.calc(at, args_str=args_str) print 'client %d calculation on %d atoms complete' % (client_id, len(at)) # format the results into a string, cf. vasp_driver REJTRAJ_OUTPUT format data = pack_results_to_reftraj_output_str(at) # open a new connection to the server to send back the results sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) try: # say hello and tell server we've got some results (status 'R') # identify ourselves with an ID number, formatted as an 8-byte ascii string id_str = ('R%7d' % client_id).encode('ascii') totalsent = 0 while totalsent < MSG_LEN_SIZE: sent = sock.send(id_str[totalsent:]) if sent == 0: raise RuntimeError('socket connection broken while sending client ID') totalsent += sent # send back results of the calculation totalsent = 0 while totalsent < len(data): sent = sock.send(data[totalsent:]) if sent == 0: raise RuntimeError('socket connection broken while sending results') totalsent += sent # wait to receive the end marker marker = '' while len(marker) < MSG_END_MARKER_SIZE: chunk = sock.recv(MSG_END_MARKER_SIZE - len(marker)) if not chunk: raise RuntimeError('socket connection broken while reading end marker') marker += chunk assert marker == MSG_END_MARKER finally: sock.close()
w_epsilon=10000.0, w_epsilon_factor=10000.0, t=TEMPERATURE) dynamical_system.add_thermostat(type=THERMOSTAT_ALL_PURPOSE, t=TEMPERATURE, tau=100.0) dynamical_system.rescale_velo(TEMPERATURE) total_steps = 1100000 timestep = 0.1 # fs connect_interval = 200 write_interval = 20000 equilibration_steps = 100000 trajectory = 'traj_{}_{}.xyz'.format(lattice.func_name, TEMPERATURE) out = AtomsWriter(trajectory) dynamical_system.atoms.calc_connect() fs_potential.calc(dynamical_system.atoms, force=True, energy=True, virial=True) # Basic NVE molecular dynamics for step_number in range(1, total_steps+1): dynamical_system.advance_verlet1(timestep, virial=dynamical_system.atoms.virial) fs_potential.calc(dynamical_system.atoms, force=True, energy=True, virial=True) dynamical_system.advance_verlet2(timestep, f=dynamical_system.atoms.force, virial=dynamical_system.atoms.virial) # Maintenance of the system if not step_number % connect_interval: dynamical_system.atoms.calc_connect() if step_number < equilibration_steps: dynamical_system.rescale_velo(TEMPERATURE)