def check_extension(sim_par, base_mof, mobile_mof, emap, emap_atom_list, new_structure): """ Checks collision between interpenetrating layer and base layer for a determined distance. Distance is calculated from given ext_cut_off value which determines the packing amount of the interpenetrating layer. Each coordinate in the interpenetrating layer is checked for high energy values by applying perodic boundary conditions to the coordinate according to energy map of the base layer. """ emap_max = [emap[-1][0], emap[-1][1], emap[-1][2]] emap_min = [emap[0][0], emap[0][1], emap[0][2]] side_length = [emap_max[0] - emap_min[0] + 1, emap_max[1] - emap_min[1] + 1, emap_max[2] - emap_min[2] + 1] x_length, y_length = int(side_length[1] * side_length[2]), int(side_length[2]) energy_limit = sim_par['atom_energy_limit'] ext_cut_off = sim_par['ext_cut_off'] rotation_info = new_structure['rotation'] first_point = new_structure['first_point'] translation_vector = new_structure['translation_vector'] packing_factor = Packing.factor(mobile_mof.uc_size, ext_cut_off) uc_vectors = Packing.uc_vectors(mobile_mof.uc_size, mobile_mof.uc_angle) trans_vec = Packing.translation_vectors(packing_factor, uc_vectors) packed_coors = Packing.uc_coors(trans_vec, packing_factor, uc_vectors, mobile_mof.atom_coors) x_angle, y_angle, z_angle = rotation_info collision = False collision_info = {'exist': collision, 'coor': None, 'pbc_coor': None} for unit_cell in packed_coors: if not collision: for coor_index, coor in enumerate(unit_cell): if not collision: rot_coor = coor rot_coor = xyz_rotation(rot_coor, [x_angle, y_angle, z_angle]) new_coor = add3(rot_coor, translation_vector) pbc_coor = pbc3(new_coor, base_mof.to_frac, base_mof.to_car) atom_name = mobile_mof.atom_names[coor_index] atom_index = energy_map_atom_index(atom_name, emap_atom_list) point_energy = tripolate(pbc_coor, atom_index, emap, x_length, y_length) if point_energy < energy_limit: continue else: collision = True collision_info = {'exist': collision, 'coor': [float(round(p, 3)) for p in new_coor], 'pbc_coor': [float(round(p, 3)) for p in pbc_coor]} break else: break else: break return collision_info
def regenerate(s1_name, s2_name, rotation, initial_coordinate, sim_par, sim_dir, export_dir, colorify=True, index=1, format='cif'): """ Reconstruct interpenetrated structure for given MOFs with rotation and initial coordinate. """ s1_mof = MOF(os.path.join(sim_dir['mof_dir'], s1_name + '.cif')) s2_mof = MOF(os.path.join(sim_dir['mof_dir'], s2_name + '.cif')) s2_mof_length = len(s2_mof) first_point = initial_coordinate x_angle, y_angle, z_angle = [math.radians(a) for a in rotation] structure = {'atom_names': [], 'atom_coors': [], 'pbc_coors': []} for idx in range(s2_mof_length): if idx == 0: atom_name = s2_mof.atom_names[idx] rot_coor = s2_mof.atom_coors[idx] rot_coor = xyz_rotation(rot_coor, [x_angle, y_angle, z_angle]) translation_vector = sub3(first_point, rot_coor) else: atom_name = s2_mof.atom_names[idx] rot_coor = s2_mof.atom_coors[idx] rot_coor = xyz_rotation(rot_coor, [x_angle, y_angle, z_angle]) new_coor = add3(rot_coor, translation_vector) pbc_coor = pbc3(new_coor, s1_mof.to_frac, s1_mof.to_car) structure['atom_coors'].append(new_coor) structure['pbc_coors'].append(pbc_coor) structure['atom_names'].append(atom_name) new_structure = {'atom_names': structure['atom_names'], 'name': s2_mof.name} if sim_par['export_pbc']: new_structure['atom_coors'] = structure['pbc_coors'] else: new_structure['atom_coors'] = structure['atom_coors'] # Export structure file new_s2_mof = MOF(new_structure, file_format='dict') joined_mof = s1_mof.join(new_s2_mof, colorify=False) joined_mof.name += '_' + str(index) joined_mof.export(export_dir, file_format=format) if colorify: new_s2_mof = MOF(new_structure, file_format='dict') joined_mof_color = s1_mof.join(new_s2_mof, colorify=True) joined_mof_color.name += '_' + str(index) + 'C' joined_mof_color.export(export_dir, file_format=format)
def reshape(mof, rotation, initial_coordinate): """ Apply rotation and translation operations to given MOF - rotation = [x_angle, y_angle, z_angle] in degrees - initial_coordinate = [x, y, z] in cartesian coordinates """ first_point = initial_coordinate x_angle, y_angle, z_angle = [math.radians(a) for a in rotation] structure = {'atom_names': [], 'atom_coors': [], 'name': mof.name} rot_coor = mof.packed_coors[0][0] translation_vector = sub3(first_point, rot_coor) for unit_cell in mof.packed_coors: for atom_coor in unit_cell: rot_coor = atom_coor rot_coor = xyz_rotation(rot_coor, [x_angle, y_angle, z_angle]) new_coor = add3(rot_coor, translation_vector) structure['atom_coors'].append(new_coor) structure['atom_names'] = len(mof.packed_coors) * mof.atom_names return structure
def save_extension(sim_par, base_mof, mobile_mof, emap, emap_atom_list, new_structure): """ Using the rotation_info and translation_vector from interpenetration to extended_coors mobile structure for a given distance (cut_off). Returns atom names, coordinates and packing factor. """ emap_max = [emap[-1][0], emap[-1][1], emap[-1][2]] emap_min = [emap[0][0], emap[0][1], emap[0][2]] export_cut_off = sim_par['cut_off'] rotation_info = new_structure['rotation'] first_point = new_structure['first_point'] translation_vector = new_structure['translation_vector'] packing_factor = Packing.factor(mobile_mof.uc_size, export_cut_off) uc_vectors = Packing.uc_vectors(mobile_mof.uc_size, mobile_mof.uc_angle) trans_vec = Packing.translation_vectors(packing_factor, uc_vectors) packed_coors = Packing.uc_coors(trans_vec, packing_factor, uc_vectors, mobile_mof.atom_coors) x_angle, y_angle, z_angle = rotation_info extended_coors = [] extended_names = [] for unit_cell in packed_coors: for coor_index, coor in enumerate(unit_cell): rot_coor = xyz_rotation(coor, [x_angle, y_angle, z_angle]) new_coor = add3(rot_coor, translation_vector) atom_name = mobile_mof.atom_names[coor_index] extended_names.append(atom_name) extended_coors.append(new_coor) extended_structure = {'atom_names': extended_names, 'atom_coors': extended_coors} extended_structure['name'] = mobile_mof.name extended_structure['packing_factor'] = packing_factor return extended_structure
def check_interpenetration(sim_par, base_mof, mobile_mof, emap, atom_list): """ Run interpenetration algorithm with given simulation parameters and energy map. Returns simulation summary and structural information on the discovered structures. """ # Initialize simulation parameters structure_energy_limit = sim_par['structure_energy_limit'] atom_energy_limit = sim_par['atom_energy_limit'] # atom_energy_limit = sim_par['energy_density_limit'] * mobile_mof.ucv energy_density_limit = sim_par['energy_density_limit'] rotation_freedom = sim_par['rotation_freedom'] summary_percent = sim_par['summary_percent'] try_all_rotations = sim_par['try_all_rotations'] # Get energy map dimensions for trilinear interpolation emap_max = [emap[-1][0], emap[-1][1], emap[-1][2]] emap_min = [emap[0][0], emap[0][1], emap[0][2]] side_length = [emap_max[0] - emap_min[0] + 1, emap_max[1] - emap_min[1] + 1, emap_max[2] - emap_min[2] + 1] x_length, y_length = int(side_length[1] * side_length[2]), int(side_length[2]) if try_all_rotations: all_rot_degrees = possible_rotations(sim_par['rotation_freedom']) rotation_limit = len(all_rot_degrees) sim_par['rotation_limit'] = rotation_limit else: rotation_limit = sim_par['rotation_limit'] initial_coors = initial_coordinates(base_mof, emap, atom_list, atom_energy_limit) trial_limit = len(initial_coors) * rotation_limit div = round(trial_limit / (100 / summary_percent)) rot_freedom = 360 / rotation_freedom # omitted_coordinates = len(emap) - len(initial_coors) summary = {'percent': [], 'structure_count': [], 'trial_count': []} new_structures = [] abort_ip = False mobile_mof_length = len(mobile_mof) structure_count = 0 structure_total_energy = 0 ucv = mobile_mof.ucv energy_density = 0 initial_coor_index = 0 rotation_index = 0 # Interpenetration trial loop for different positions and orientations for t in range(trial_limit): abort_ip = False # Interpenetration trial loop for a specific position and different orientations for idx in range(mobile_mof_length): if not abort_ip: # If the interpenetration is just starting select rotation angles if idx == 0: # Determine random angles for rotation in 3D space # Determine first point for interpenetrating structure if t % rotation_limit == 0: # Start with original orientation for first trial x_angle, y_angle, z_angle = [0, 0, 0] first_point = initial_coors[initial_coor_index] initial_coor_index += 1 rotation_index = 0 elif try_all_rotations: x_angle, y_angle, z_angle = all_rot_degrees[rotation_index] else: x_angle = 2 * math.pi * math.floor(random() * rot_freedom) / rot_freedom y_angle = 2 * math.pi * math.floor(random() * rot_freedom) / rot_freedom z_angle = 2 * math.pi * math.floor(random() * rot_freedom) / rot_freedom rotation_index += 1 # Rotate first atom of the mobile MOF atom_name = mobile_mof.atom_names[idx] rot_coor = mobile_mof.atom_coors[idx] rot_coor = xyz_rotation(rot_coor, [x_angle, y_angle, z_angle]) translation_vector = sub3(first_point, rot_coor) # Initialize new structure dictionary structure = {'atom_names': [], 'atom_coors': [], 'pbc_coors': []} structure['first_point'] = first_point structure['translation_vector'] = translation_vector structure['atom_coors'].append(first_point) structure['pbc_coors'].append(first_point) structure['atom_names'].append(atom_name) structure['rotation'] = [x_angle, y_angle, z_angle] # If interpenetration is still going on elif idx < mobile_mof_length - 1: atom_name = mobile_mof.atom_names[idx] rot_coor = mobile_mof.atom_coors[idx] rot_coor = xyz_rotation(rot_coor, [x_angle, y_angle, z_angle]) new_coor = add3(rot_coor, translation_vector) pbc_coor = pbc3(new_coor, base_mof.to_frac, base_mof.to_car) emap_atom_index = energy_map_atom_index(atom_name, atom_list) point_energy = tripolate(pbc_coor, emap_atom_index, emap, x_length, y_length) structure_total_energy += point_energy energy_density += point_energy / ucv if energy_density > energy_density_limit: structure_total_energy = 0 energy_density = 0 abort_ip = True break # Fix this part (break interpenetration trial loop) else: structure['atom_coors'].append(new_coor) structure['pbc_coors'].append(pbc_coor) structure['atom_names'].append(atom_name) # If interpenetration trial ended with no collision - record structure info else: structure['energy'] = structure_total_energy structure['energy_density'] = energy_density new_structures.append(structure) structure_count += 1 structure_total_energy = 0 energy_density = 0 # Record simulation progress according to division (div) and summary if t % div == 0: percent_complete = round(t / trial_limit * 100) summary['percent'].append(percent_complete) summary['structure_count'].append(structure_count) summary['trial_count'].append(t) return summary, new_structures