def set_qmmm_pot(atoms, crack_pos, mm_pot, qm_pot, atom_mask=None): # cluster_args = dict(single_cluster=True, # cluster_calc_connect=True, # cluster_hopping=False, # cluster_hopping_nneighb_only=True, # cluster_periodic_z = True, # match Gamma vs. kpts # cluster_vacuum = 5.0, # hysteretic_buffer=True, # hysteretic_buffer_inner_radius=qm_inner_radius, # hysteretic_buffer_outer_radius=qm_outer_radius, # min_images_only=True, # terminate=False, # force_no_fix_termination_clash=True, # randomise_buffer=False) qmmm_pot = ForceMixingPotential(pot1=mm_pot, pot2=qm_pot, atoms=atoms, qm_args_str='single_cluster cluster_periodic_z carve_cluster ' + 'terminate cluster_hopping=F randomise_buffer=F', fit_hops=4, lotf_spring_hops=3, hysteretic_buffer=True, hysteretic_buffer_inner_radius=qm_inner_radius, hysteretic_buffer_outer_radius=qm_outer_radius, cluster_hopping_nneighb_only=False, min_images_only=True) qmmm_pot.atoms = atoms atoms.set_calculator(qmmm_pot) fixed_mask = (np.sqrt(map(sum, map(np.square, atoms.positions[:,0:2]-crack_pos[0:2]))) <= 3) qm_list = fixed_mask.nonzero()[0] qmmm_pot.set_qm_atoms(qm_list, atoms) return qmmm_pot
def __init__(self, mm_clients, qm_clients, ip, port=0, rundir=None, bulk_scale=None, mpi_obj=None, callback=None, calculator=None, cutoff_skin=1.0, atoms=None, qm_list=None, fpointer=None, finalise=True, error=None, cluster_args=None, test_mode=False, save_clusters=False, force_restart=False, **kwargs): def callback_factory(force_prop_name): def callback(at): at.add_property('force', getattr(at, force_prop_name), overwrite=True) return callback if isinstance(mm_clients, Potential): self.mm_local = True self.pot1 = mm_clients self.mm_clients = [] else: self.mm_local = False self.mm_clients = mm_clients if isinstance(qm_clients, Potential): self.qm_pot = qm_clients self.qm_clients = [] else: self.qm_clients = qm_clients clients = self.mm_clients + self.qm_clients print 'Clients', clients if len(clients) > 0: self.server = AtomsServerAsync((ip, port), AtomsRequestHandler, clients, bgq=True) self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread.daemon = True self.server_thread.start() if rundir is None: rundir = os.getcwd() self.rundir = rundir self.label = 1 self.cluster_args = {} if cluster_args is not None: self.cluster_args = cluster_args if not self.mm_local: self.pot1 = Potential('CallbackPot', callback=callback_factory('mm_force')) self.pot2 = Potential('CallbackPot', callback=callback_factory('qm_force')) self.test_mode = test_mode self.save_clusters = save_clusters self.force_restart = force_restart ForceMixingPotential.__init__(self, self.pot1, self.pot2, bulk_scale=bulk_scale, mpi_obj=mpi_obj, cutoff_skin=cutoff_skin, atoms=atoms, qm_list=qm_list, fpointer=fpointer, finalise=finalise, error=error, **kwargs)
def set_qmmm_pot(atoms, crack_pos, mm_pot, qm_pot, atom_mask=None): # cluster_args = dict(single_cluster=True, # cluster_calc_connect=True, # cluster_hopping=False, # cluster_hopping_nneighb_only=True, # cluster_periodic_z = True, # match Gamma vs. kpts # cluster_vacuum = 5.0, # hysteretic_buffer=True, # hysteretic_buffer_inner_radius=qm_inner_radius, # hysteretic_buffer_outer_radius=qm_outer_radius, # min_images_only=True, # terminate=False, # force_no_fix_termination_clash=True, # randomise_buffer=False) qmmm_pot = ForceMixingPotential( pot1=mm_pot, pot2=qm_pot, atoms=atoms, qm_args_str='single_cluster cluster_periodic_z carve_cluster ' + 'terminate cluster_hopping=F randomise_buffer=F', fit_hops=4, lotf_spring_hops=3, hysteretic_buffer=True, hysteretic_buffer_inner_radius=qm_inner_radius, hysteretic_buffer_outer_radius=qm_outer_radius, cluster_hopping_nneighb_only=False, min_images_only=True) qmmm_pot.atoms = atoms atoms.set_calculator(qmmm_pot) fixed_mask = (np.sqrt( map(sum, map(np.square, atoms.positions[:, 0:2] - crack_pos[0:2]))) <= 3) qm_list = fixed_mask.nonzero()[0] qmmm_pot.set_qm_atoms(qm_list, atoms) return qmmm_pot
# Density functional tight binding (DFTB) potential qm_pot = Potential(qm_init_args, param_filename=param_file) # Parameters which control how the QM calculation is carried out: # we use a single cluster, periodic in the z direction and terminated # with hydrogen atoms. The positions of the outer layer of buffer atoms # are not randomised. qm_args_str = ('single_cluster cluster_periodic_z '+ 'carve_cluster terminate randomise_buffer=F') # Construct the QM/MM potential, which mixes QM and MM forces qmmm_pot = ForceMixingPotential(pot1=mm_pot, pot2=qm_pot, qm_args_str=qm_args_str, fit_hops=4, lotf_spring_hops=3, buffer_hops=4) # Use the force mixing potential as the Atoms' calculator atoms.set_calculator(qmmm_pot) # *** Set up the initial QM region **** qm_list = update_hysteretic_qm_region(atoms, [], orig_crack_pos, qm_inner_radius, qm_outer_radius) qmmm_pot.set_qm_atoms(qm_list) # *** Milestone 3.1 -- exit early - we don't want to run the classical MD! ***
def __init__(self, mm_clients, qm_clients, ip, port=0, rundir=None, bulk_scale=None, mpi_obj=None, callback=None, calculator=None, cutoff_skin=1.0, atoms=None, qm_list=None, fpointer=None, finalise=True, error=None, cluster_args=None, test_mode=False, save_clusters=False, force_restart=False, **kwargs): def callback_factory(force_prop_name): def callback(at): at.add_property('force', getattr(at, force_prop_name), overwrite=True) return callback if isinstance(mm_clients, Potential): self.mm_local = True self.pot1 = mm_clients self.mm_clients = [] else: self.mm_local = False self.mm_clients = mm_clients if isinstance(qm_clients, Potential): self.qm_pot = qm_clients self.qm_clients = [] else: self.qm_clients = qm_clients clients = self.mm_clients + self.qm_clients print 'Clients', clients if len(clients) > 0: self.server = AtomsServerAsync((ip, port), AtomsRequestHandler, clients, bgq=True) self.server_thread = threading.Thread( target=self.server.serve_forever) self.server_thread.daemon = True self.server_thread.start() if rundir is None: rundir = os.getcwd() self.rundir = rundir self.label = 1 self.cluster_args = {} if cluster_args is not None: self.cluster_args = cluster_args if not self.mm_local: self.pot1 = Potential('CallbackPot', callback=callback_factory('mm_force')) self.pot2 = Potential('CallbackPot', callback=callback_factory('qm_force')) self.test_mode = test_mode self.save_clusters = save_clusters self.force_restart = force_restart ForceMixingPotential.__init__(self, self.pot1, self.pot2, bulk_scale=bulk_scale, mpi_obj=mpi_obj, cutoff_skin=cutoff_skin, atoms=atoms, qm_list=qm_list, fpointer=fpointer, finalise=finalise, error=error, **kwargs)
def calc(self, at, energy=None, force=None, virial=None, local_energy=None, local_virial=None, args_str=None, error=None, **kwargs): clusters = [] orig_label = self.label if not self.mm_local: # always submit the MM calc if self.test_mode: clusters.append(at) else: self.server.put(at, 0, self.label, force_restart=self.force_restart) self.label += 1 do_qm = not self.get('method').startswith('lotf') or self.get( 'lotf_do_qm') if do_qm: #print 'REGIONS', [ k for k in at.properties.keys() if re.match('hybrid_[0-9]+', k) ] n_region = len([ k for k in at.properties.keys() if re.match('hybrid_[0-9]+', k) ]) if self.get('calc_weights'): system_timer('create_hybrid_weights') # overall hybrid property is union of all the hybrids if not hasattr(at, 'hybrid'): at.add_property('hybrid', 0) at.hybrid[:] = 0 for i in frange(n_region): hybrid = getattr(at, 'hybrid_%d' % i) at.hybrid[hybrid == HYBRID_ACTIVE_MARK] = HYBRID_ACTIVE_MARK if not hasattr(at, 'hybrid_mark'): at.add_property('hybrid_mark', at.hybrid) at.hybrid_mark[:] = 0 at.hybrid_mark = at.hybrid create_hybrid_weights_args = self.cluster_args.copy() create_hybrid_weights_args['buffer_hops'] = 0 create_hybrid_weights_args[ 'transition_hops'] = 0 # ensure a fast exit # overall hybrid -> hybrid_mark, weight_region1 create_hybrid_weights( at, args_str=quippy.util.args_str(create_hybrid_weights_args)) system_timer('create_hybrid_weights') # make clusters and submit to QM clients system_timer('make_clusters') for i in frange(n_region): hybrid_name = 'hybrid_%d' % i hybrid_mark_name = 'hybrid_mark_%d' % i if self.get('calc_weights'): hybrid = getattr(at, hybrid_name) if not hasattr(at, hybrid_mark_name): at.add_property(hybrid_mark_name, HYBRID_NO_MARK) hybrid_mark = getattr(at, hybrid_mark_name) # set marks to allow previously active atoms to become buffer atoms # create_hybrid_weights will then set the buffer marks hybrid_mark[hybrid_mark == HYBRID_ACTIVE_MARK] = HYBRID_BUFFER_MARK hybrid_mark[hybrid == HYBRID_ACTIVE_MARK] = HYBRID_ACTIVE_MARK print('region %d, sum(hybrid) %d, sum(hybrid_mark) %d' % (i, sum(hybrid), sum(hybrid_mark))) create_hybrid_weights_args = self.cluster_args.copy() create_hybrid_weights_args['run_suffix'] = '_%d' % i create_hybrid_weights_args_str = quippy.util.args_str( create_hybrid_weights_args) print 'calling create_hybrid_weights with args_str %s' % create_hybrid_weights_args_str create_hybrid_weights( at, args_str=create_hybrid_weights_args_str) cluster_args_str = quippy.util.args_str(self.cluster_args) print 'calling create_cluster_simple with args_str %s' % cluster_args_str c = create_cluster_simple(at, mark_name=hybrid_mark_name, args_str=cluster_args_str) client_id = i if self.mm_local: client_id -= 1 if self.save_clusters: c.write( os.path.join( self.rundir, 'cluster.client-%03d.label-%04d.xyz' % (client_id, self.label))) if self.test_mode: clusters.append(c) else: self.server.put(c, client_id, self.label, force_restart=self.force_restart) self.label += 1 system_timer('make_clusters') # wait for results to be ready system_timer('get_results') if self.test_mode: results = [] for i, cluster in enumerate(clusters): result = cluster.copy() result.set_cutoff(self.qm_pot.cutoff()) result.calc_connect() self.qm_pot.calc(result, force=True) result.params['label'] = orig_label + i results.append(result) else: results = self.server.get_results() system_timer('get_results') system_timer('process_results') if self.mm_local: qm_results = results else: # process MM results mm_results, qm_results = results[:1], results[1:] mm_result = mm_results[0] at.add_property('mm_force', mm_result.force, overwrite=True) if do_qm: # process QM results at.add_property('qm_force', 0., n_cols=3, overwrite=True) # extract forces from each cluster for i, r in fenumerate(qm_results): #print 'qm forces (orig order?):' #print '\n'.join(['%d: pos=%s f=%s' % (j, p, f) for j, p, f in zip(r.index, r.pos, r.force)]) client_id = i if self.mm_local: client_id -= 1 if self.save_clusters: r.write( os.path.join( self.rundir, 'results.client-%03d.label-%04d.xyz' % (client_id, r.label))) mark_name = 'hybrid_mark_%d' % i mask = getattr(r, mark_name) == HYBRID_ACTIVE_MARK #print 'Cluster %d: QM forces on atoms %s' % (i, r.index[mask]) #print r.force[:, mask].T # HL if set_fortran is false we need to reduce the index here because # the atoms object is expecting python indexing. at.qm_force[:, [ind - 1 for ind in list(r.index[mask])]] = r.force[:, mask] system_timer('process_results') # now call the parent calc() to do the force mixing etc. force_mixing_args = kwargs.copy() force_mixing_args.update(self.cluster_args) force_mixing_args['calc_weights'] = False # already done this above #print 'calling ForceMixingPotential.calc() with args %r' % force_mixing_args ForceMixingPotential.calc(self, at, energy, force, virial, local_energy, local_virial, args_str, error, **force_mixing_args)
mm_pot.set_default_quantities(['stresses']) # Density functional tight binding (DFTB) potential qm_pot = Potential(qm_init_args, param_filename=param_file) # Construct the QM/MM potential, which mixes QM and MM forces. # The qm_args_str parameters control how the QM calculation is carried out: # we use a single cluster, periodic in the z direction and terminated # with hydrogen atoms. The positions of the outer layer of buffer atoms # are not randomised. qmmm_pot = ForceMixingPotential( pot1=mm_pot, pot2=qm_pot, qm_args_str='single_cluster cluster_periodic_z carve_cluster ' + 'terminate cluster_hopping=F randomise_buffer=F', fit_hops=4, lotf_spring_hops=3, hysteretic_buffer=True, hysteretic_buffer_inner_radius=7.0, hysteretic_buffer_outer_radius=9.0, cluster_hopping_nneighb_only=False, min_images_only=True) # Use the force mixing potential as the Atoms' calculator atoms.set_calculator(qmmm_pot) # *** Set up the initial QM region **** qm_list = update_hysteretic_qm_region(atoms, [], orig_crack_pos, qm_inner_radius, qm_outer_radius) qmmm_pot.set_qm_atoms(qm_list)
param_str=""" <params> <LMTO_TBE_params n_types="3" control_file="ctrl.fe"> <per_type_data type="1" atomic_num="26"/> <per_type_data type="2" atomic_num="6"/> <per_type_data type="3" atomic_num="1"/> </LMTO_TBE_params> </params>""") print 'Initializing LOTF Potential, qm_radii:', params.qm_inner_radius, params.qm_outer_radius qmmm_pot = ForceMixingPotential( pot1=mm_pot, pot2=qm_pot, atoms=defect, qm_args_str='single_cluster cluster_periodic_z carve_cluster ' + 'terminate=F cluster_hopping=F randomise_buffer=F', fit_hops=2, lotf_spring_hops=2, hysteretic_buffer=True, hysteretic_buffer_inner_radius=params.hyst_buffer_inner, hysteretic_buffer_outer_radius=params.hyst_buffer_outer, cluster_hopping_nneighb_only=False, min_images_only=True) defect.set_calculator(qmmm_pot) elif pot_type == 'EAM': eam_pot = os.path.join(potdir, 'PotBH.xml') r_scale = 1.00894848312 pot = Potential( 'IP EAM_ErcolAd do_rescale_r=T r_scale={0}'.format(r_scale), param_filename=eam_pot) defect.set_calculator(pot) else:
right = atoms.positions[:, 0].max() fixed_mask = ((abs(atoms.positions[:, 1] - top) < 1.0) | (abs(atoms.positions[:, 1] - bottom) < 1.0)) fix_atoms = FixAtoms(mask=fixed_mask) strain_atoms = ConstantStrainRate(orig_height, strain_rate*timestep) atoms.set_constraint([fix_atoms, strain_atoms]) mm_pot = Potential("IP SW", param_filename="params.xml", cutoff_skin=cutoff_skin) mm_pot.set_default_properties(['stresses']) # Density functional tight binding (DFTB) potential qm_pot = Potential(qm_init_args, param_filename="params.xml") qm_list = update_hysteretic_qm_region(atoms, [], orig_crack_pos, qm_inner_radius, qm_outer_radius) qmmm_pot = ForceMixingPotential(pot1=mm_pot, pot2=qm_pot) atoms.set_calculator(qmmm_pot) qmmm_pot.set_qm_atoms(qm_list) # *** Set up the initial QM region **** # # # MaxwellBoltzmannDistribution(atoms, 2.0*sim_T) # # dynamics = LOTFDynamics(atoms, timestep, extrapolate_steps, check_force_error=True) # # def printstatus(): # if dynamics.nsteps == 1:
npar=4, **vasp_args) qm_pot = Potential(calculator=SocketCalculator(vasp_client)) #construct_buffer_use_only_heavy_atoms might be necessary to stop confusion with H! qmmm_pot = ForceMixingPotential( pot1=mm_pot, pot2=qm_pot, atoms=atoms, qm_args_str='carve_cluster=T cluster_periodic_z=T cluster_calc_connect=T ' + 'single_cluster=T cluster_vacuum=5.0 terminate=F print_clusters=F', fit_hops=4, carve_cluster=True, lotf_spring_hops=3, terminate=False, calc_connect=True, buffer_hops=3, hysteretic_buffer=True, cluster_vacuum=5.0, cluster_hopping=True, single_cluster=True, hysteretic_buffer_inner_radius=qm_inner_radius, hysteretic_buffer_outer_radius=qm_outer_radius, cluster_hopping_nneighb_only=True, min_images_only=True) atoms.cutoff = 3.0 atoms.calc_connect() qm_list = update_hysteretic_qm_region(atoms, [], crack_pos, qm_inner_radius, qm_outer_radius) qmmm_pot.set_qm_atoms(qm_list, atoms)
def calc(self, at, energy=None, force=None, virial=None, local_energy=None, local_virial=None, args_str=None, error=None, **kwargs): clusters = [] orig_label = self.label if not self.mm_local: # always submit the MM calc if self.test_mode: clusters.append(at) else: self.server.put(at, 0, self.label, force_restart=self.force_restart) self.label += 1 do_qm = not self.get('method').startswith('lotf') or self.get('lotf_do_qm') if do_qm: #print 'REGIONS', [ k for k in at.properties.keys() if re.match('hybrid_[0-9]+', k) ] n_region = len([ k for k in at.properties.keys() if re.match('hybrid_[0-9]+', k) ]) if self.get('calc_weights'): system_timer('create_hybrid_weights') # overall hybrid property is union of all the hybrids if not hasattr(at, 'hybrid'): at.add_property('hybrid', 0) at.hybrid[:] = 0 for i in frange(n_region): hybrid = getattr(at, 'hybrid_%d' % i) at.hybrid[hybrid == HYBRID_ACTIVE_MARK] = HYBRID_ACTIVE_MARK if not hasattr(at, 'hybrid_mark'): at.add_property('hybrid_mark', at.hybrid) at.hybrid_mark[:] = 0 at.hybrid_mark = at.hybrid create_hybrid_weights_args = self.cluster_args.copy() create_hybrid_weights_args['buffer_hops'] = 0 create_hybrid_weights_args['transition_hops'] = 0 # ensure a fast exit # overall hybrid -> hybrid_mark, weight_region1 create_hybrid_weights(at, args_str=quippy.util.args_str(create_hybrid_weights_args)) system_timer('create_hybrid_weights') # make clusters and submit to QM clients system_timer('make_clusters') for i in frange(n_region): hybrid_name = 'hybrid_%d' % i hybrid_mark_name = 'hybrid_mark_%d' % i if self.get('calc_weights'): hybrid = getattr(at, hybrid_name) if not hasattr(at, hybrid_mark_name): at.add_property(hybrid_mark_name, HYBRID_NO_MARK) hybrid_mark = getattr(at, hybrid_mark_name) # set marks to allow previously active atoms to become buffer atoms # create_hybrid_weights will then set the buffer marks hybrid_mark[hybrid_mark == HYBRID_ACTIVE_MARK] = HYBRID_BUFFER_MARK hybrid_mark[hybrid == HYBRID_ACTIVE_MARK] = HYBRID_ACTIVE_MARK print ('region %d, sum(hybrid) %d, sum(hybrid_mark) %d' % (i, sum(hybrid), sum(hybrid_mark))) create_hybrid_weights_args = self.cluster_args.copy() create_hybrid_weights_args['run_suffix'] = '_%d' % i create_hybrid_weights_args_str = quippy.util.args_str(create_hybrid_weights_args) print 'calling create_hybrid_weights with args_str %s' % create_hybrid_weights_args_str create_hybrid_weights(at, args_str=create_hybrid_weights_args_str) cluster_args_str = quippy.util.args_str(self.cluster_args) print 'calling create_cluster_simple with args_str %s' % cluster_args_str c = create_cluster_simple(at, mark_name=hybrid_mark_name, args_str=cluster_args_str) client_id = i if self.mm_local: client_id -= 1 if self.save_clusters: c.write(os.path.join(self.rundir, 'cluster.client-%03d.label-%04d.xyz' % (client_id, self.label))) if self.test_mode: clusters.append(c) else: self.server.put(c, client_id, self.label, force_restart=self.force_restart) self.label += 1 system_timer('make_clusters') # wait for results to be ready system_timer('get_results') if self.test_mode: results = [] for i, cluster in enumerate(clusters): result = cluster.copy() result.set_cutoff(self.qm_pot.cutoff()) result.calc_connect() self.qm_pot.calc(result, force=True) result.params['label'] = orig_label + i results.append(result) else: results = self.server.get_results() system_timer('get_results') system_timer('process_results') if self.mm_local: qm_results = results else: # process MM results mm_results, qm_results = results[:1], results[1:] mm_result = mm_results[0] at.add_property('mm_force', mm_result.force, overwrite=True) if do_qm: # process QM results at.add_property('qm_force', 0., n_cols=3, overwrite=True) # extract forces from each cluster for i, r in fenumerate(qm_results): #print 'qm forces (orig order?):' #print '\n'.join(['%d: pos=%s f=%s' % (j, p, f) for j, p, f in zip(r.index, r.pos, r.force)]) client_id = i if self.mm_local: client_id -= 1 if self.save_clusters: r.write(os.path.join(self.rundir, 'results.client-%03d.label-%04d.xyz' % (client_id, r.label))) mark_name = 'hybrid_mark_%d' % i mask = getattr(r, mark_name) == HYBRID_ACTIVE_MARK #print 'Cluster %d: QM forces on atoms %s' % (i, r.index[mask]) #print r.force[:, mask].T # HL if set_fortran is false we need to reduce the index here because # the atoms object is expecting python indexing. at.qm_force[:, [ind-1 for ind in list(r.index[mask])]] = r.force[:, mask] system_timer('process_results') # now call the parent calc() to do the force mixing etc. force_mixing_args = kwargs.copy() force_mixing_args.update(self.cluster_args) force_mixing_args['calc_weights'] = False # already done this above #print 'calling ForceMixingPotential.calc() with args %r' % force_mixing_args ForceMixingPotential.calc(self, at, energy, force, virial, local_energy, local_virial, args_str, error, **force_mixing_args)