def _update_neigh(self, influence_distance: float): """ Update neighbor list and model input. """ # inquire information from conf cell = np.asarray(self.conf.cell, dtype=np.double) PBC = np.asarray(self.conf.PBC, dtype=np.intc) contributing_coords = np.asarray(self.conf.coords, dtype=np.double) contributing_species = self.conf.species num_contributing = self.conf.get_num_atoms() self.num_contributing_particles = num_contributing # species support and code unique_species = list(set(contributing_species)) species_map = dict() for s in unique_species: if s in self.supported_species: species_map[s] = self.supported_species[s] else: report_error(f"species `{s}` not supported by model") contributing_species_code = np.array( [species_map[s] for s in contributing_species], dtype=np.intc) if any(PBC): # need padding atoms out = nl.create_paddings( influence_distance, cell, PBC, contributing_coords, contributing_species_code, ) padding_coords, padding_species_code, self.padding_image_of, error = out check_error(error, "nl.create_paddings") num_padding = padding_species_code.size self.num_particles = np.array([num_contributing + num_padding], dtype=np.intc) tmp = np.concatenate((contributing_coords, padding_coords)) self.coords = np.asarray(tmp, dtype=np.double) tmp = np.concatenate( (contributing_species_code, padding_species_code)) self.species_code = np.asarray(tmp, dtype=np.intc) self.particle_contributing = np.ones(self.num_particles[0], dtype=np.intc) self.particle_contributing[num_contributing:] = 0 # TODO check whether padding need neigh and create accordingly # for now, create neigh for all atoms, including paddings need_neigh = np.ones(self.num_particles[0], dtype=np.intc) else: # do not need padding atoms self.padding_image_of = np.array([]) self.num_particles = np.array([num_contributing], dtype=np.intc) self.coords = np.array(contributing_coords, dtype=np.double) self.species_code = np.array(contributing_species_code, dtype=np.intc) self.particle_contributing = np.ones(num_contributing, dtype=np.intc) need_neigh = self.particle_contributing error = nl.build( self.neigh, self.coords, influence_distance, np.asarray([influence_distance], dtype=np.double), need_neigh, ) check_error(error, "nl.build")
def test_main(): # create contributing atoms alat = 2.46 d = 3.35 cell, contrib_coords, contrib_species = create_graphite_unit_cell(alat, d) # create padding atoms cutoffs = np.array([d + 0.01, d + 0.02], dtype=np.double) influence_dist = cutoffs[1] pbc = np.array([1, 1, 1], dtype=np.intc) out = nl.create_paddings(influence_dist, cell, pbc, contrib_coords, contrib_species) pad_coords, pad_species, pad_image, error = out check_error(error, 'nl.create_padding') assert pad_coords.shape == (96, 3) # print('pad_coords is of shape:', pad_coords.shape) coords = np.concatenate((contrib_coords, pad_coords)) coords = np.asarray(coords, dtype=np.double) species = np.concatenate((contrib_species, pad_species)) species = np.asarray(species, dtype=np.intc) fname = 'atoms.xyz' write_XYZ(fname, cell, species, coords) # flag to indicate wheter create neighbor list for an atom n_pad = pad_coords.shape[0] n_contrib = contrib_coords.shape[0] need_neigh = np.concatenate((np.ones(n_contrib), np.zeros(n_pad))) need_neigh = np.asarray(need_neigh, dtype=np.intc) # create neighbor list neigh = nl.initialize() error = nl.build(neigh, coords, influence_dist, cutoffs, need_neigh) check_error(error, 'nl.build') # build again (it will automatically empty previous neigh list) error = nl.build(neigh, coords, influence_dist, cutoffs, need_neigh) check_error(error, 'nl.build') # test get neigh function neigh_list_index = 0 particle = 1 num_neigh, neighbors, error = nl.get_neigh( neigh, cutoffs, neigh_list_index, particle) check_error(error, 'nl.get_neigh') assert num_neigh == 14 # print('Atom 1 has {} neighbors:'.format(num_neigh), end=' ') # for i in neighbors: # print(i, end=' ') neigh_list_index = 1 particle = 4 num_neigh, neighbors, error = nl.get_neigh( neigh, cutoffs, neigh_list_index, particle) check_error(error, 'nl.get_neigh') assert num_neigh == 0 # expect error message from this # neigh_list_index = 1 # particle = n_contrib + n_pad # num_neigh, neighbors, error = nl.get_neigh(neigh, cutoffs, neigh_list_index, particle) # assert error == 1 # delete neighbor list nl.clean(neigh) # remove the created file try: os.remove(fname) os.remove('kim.log') except: pass
def build(self): return neighlist.build(self.neigh, self.coords, self.influence_dist, self.cutoffs, self.need_neigh)
def test_main(): modelname = 'ex_model_Ar_P_Morse_07C' print() print('=' * 80) print('Matching results for KIM model:', modelname) print() # create model requestedUnitsAccepted, kim_model, error = kimpy.model.create( kimpy.numbering.zeroBased, kimpy.length_unit.A, kimpy.energy_unit.eV, kimpy.charge_unit.e, kimpy.temperature_unit.K, kimpy.time_unit.ps, modelname, ) check_error(error, 'kimpy.model.create') if not requestedUnitsAccepted: report_error('requested units not accepted in kimpy.model.create') # units l_unit, e_unit, c_unit, te_unit, ti_unit = kim_model.get_units() check_error(error, 'kim_model.get_units') print('Length unit is:', str(l_unit)) print('Energy unit is:', str(e_unit)) print('Charge unit is:', str(c_unit)) print('Temperature unit is:', str(te_unit)) print('Time unit is:', str(ti_unit)) print() # create compute arguments compute_arguments, error = kim_model.compute_arguments_create() check_error(error, 'kim_model.compute_arguments_create') # check compute arguments num_compute_arguments = ( kimpy.compute_argument_name.get_number_of_compute_argument_names()) print('Number of compute_arguments:', num_compute_arguments) for i in range(num_compute_arguments): name, error = kimpy.compute_argument_name.get_compute_argument_name(i) check_error(error, 'kim_model.get_compute_argument_name') dtype, error = \ kimpy.compute_argument_name.get_compute_argument_data_type(name) check_error(error, 'kim_model.get_compute_argument_data_type') support_status, error = \ compute_arguments.get_argument_support_status(name) check_error(error, 'compute_argument.get_argument_support_status') n_space_1 = 21 - len(str(name)) n_space_2 = 7 - len(str(dtype)) print('Compute Argument name "{}" '.format(name) + ' ' * n_space_1 + 'is of type "{}" '.format(dtype) + ' ' * n_space_2 + 'and has support status "{}".'.format(support_status)) # can only handle energy and force as a required arg if support_status == kimpy.support_status.required: if name not in (kimpy.compute_argument_name.partialEnergy, kimpy.compute_argument_name.partialForces): report_error('Unsupported required ComputeArgument') # must have energy and forces if name in (kimpy.compute_argument_name.partialEnergy, kimpy.compute_argument_name.partialForces): if support_status not in (kimpy.support_status.required, kimpy.support_status.optional): report_error('Energy or forces not available') print() # check compute callbacks num_callbacks = \ kimpy.compute_callback_name.get_number_of_compute_callback_names() print('Number of callbacks:', num_callbacks) for i in range(num_callbacks): name, error = kimpy.compute_callback_name.get_compute_callback_name(i) check_error(error, 'kim_model.get_compute_callback_name') support_status, error = \ compute_arguments.get_callback_support_status(name) check_error(error, 'compute_argument.get_callback_support_status') n_space = 18 - len(str(name)) print('Compute callback "{}"'.format(name) + ' ' * n_space + 'has support status "{}".'.format(support_status)) # cannot handle any "required" callbacks if support_status == kimpy.support_status.required: report_error('Unsupported required ComputeCallback') print() # parameter num_params = kim_model.get_number_of_parameters() print('Number of parameters:', num_params) print() for i in range(num_params): out = kim_model.get_parameter_metadata(i) dtype, extent, name, description, error = out check_error(error, 'kim_model.get_parameter_metadata') print('Parameter No.', i) print(' data type:', dtype) print(' extent:', extent) print(' name:', name) print(' description:', description) print() # register argument argon = create_fcc_argon() coords = np.asarray(argon.get_positions(), dtype=np.double) N = coords.shape[0] print('Number of particles:', N) forces = np.zeros((N, 3), dtype=np.double) energy = np.array([0.0], dtype=np.double) num_particles = np.array([N], dtype=np.intc) species_code = np.zeros(num_particles, dtype=np.intc) particle_contributing = np.zeros(num_particles, dtype=np.intc) error = compute_arguments.set_argument_pointer( kimpy.compute_argument_name.numberOfParticles, num_particles) check_error(error, 'kimpy.compute_argument.set_argument_pointer') error = compute_arguments.set_argument_pointer( kimpy.compute_argument_name.particleSpeciesCodes, species_code) check_error(error, 'kimpy.compute_argument.set_argument_pointer') error = compute_arguments.set_argument_pointer( kimpy.compute_argument_name.particleContributing, particle_contributing) check_error(error, 'kimpy.compute_argument.set_argument_pointer') error = compute_arguments.set_argument_pointer( kimpy.compute_argument_name.coordinates, coords) check_error(error, 'kimpy.compute_argument.set_argument_pointer') error = compute_arguments.set_argument_pointer( kimpy.compute_argument_name.partialEnergy, energy) check_error(error, 'kimpy.compute_argument.set_argument_pointer') error = compute_arguments.set_argument_pointer( kimpy.compute_argument_name.partialForces, forces) check_error(error, 'kimpy.compute_argument.set_argument_pointer') # create neighbor list neigh = nl.initialize() # register get neigh callback error = compute_arguments.set_callback_pointer( kimpy.compute_callback_name.GetNeighborList, nl.get_neigh_kim(), neigh) check_error(error, 'kimpy.compute_argument.set_callback_pointer') # influence distance and cutoff of model model_influence_dist = kim_model.get_influence_distance() out = kim_model.get_neighbor_list_cutoffs_and_hints() model_cutoffs, padding_not_require_neigh_hints = out print('Model influence distance:', model_influence_dist) print('Model cutoffs:', model_cutoffs) print('Model padding neighbors hints:', padding_not_require_neigh_hints) print() # species support and code species_support, code, error = \ kim_model.get_species_support_and_code(kimpy.species_name.Ar) check_error(error or not species_support, 'kim_model.get_species_support_and_code') print('Species Ar is supported and its code is:', code) print() # setup particle species species_code[:] = code # setup particleContributing particle_contributing[:] = 1 # setup neighbor list need_neigh = np.ones(N, dtype='intc') # compute energy and force for different structures alat = 5.26 min_alat = 0.8 * 5.26 max_alat = 1.2 * 5.26 inc_alat = 0.025 * alat all_alat = np.arange(min_alat, max_alat, inc_alat) print('=' * 80) print('Result for KIM model:', modelname) print() print(' energy force norm lattice spacing') print() for a in all_alat: argon = create_fcc_argon(a) # NOTE cannot change coords address np.copyto(coords, argon.get_positions()) error = nl.build(neigh, coords, model_influence_dist, model_cutoffs, need_neigh) check_error(error, 'nl.build') error = kim_model.compute(compute_arguments) print('{:18.10e} {:18.10e} {:18.10e}'.format(energy[0], np.linalg.norm(forces), a)) # destory neighbor list nl.clean(neigh) # destory compute arguments error = kim_model.compute_arguments_destroy(compute_arguments) check_error(error, 'kim_model.compute_arguments_destroy') # destory model kimpy.model.destroy(kim_model)