Spaces:
Running
Running
| """ | |
| Grid search for accessible positions | |
| This script is heavily adapted from the `DAC-SIM <https://github.com/hspark1212/DAC-SIM>`_ package. Please cite the original work if you use this script. | |
| References | |
| ~~~~~~~~~~~ | |
| - Lim, Y., Park, H., Walsh, A., & Kim, J. (2024). Accelerating CO₂ Direct Air Capture Screening for Metal-Organic Frameworks with a Transferable Machine Learning Force Field. | |
| """ | |
| import MDAnalysis as mda | |
| import numpy as np | |
| from ase import Atoms | |
| def get_accessible_positions( | |
| structure: Atoms, | |
| grid_spacing: float = 0.5, | |
| cutoff_distance: float = 10.0, | |
| min_interplanar_distance: float = 2.0, | |
| ) -> dict: | |
| # get the supercell structure | |
| cell_volume = structure.get_volume() | |
| cell_vectors = np.array(structure.cell) | |
| dist_a = cell_volume / np.linalg.norm(np.cross(cell_vectors[1], cell_vectors[2])) | |
| dist_b = cell_volume / np.linalg.norm(np.cross(cell_vectors[2], cell_vectors[0])) | |
| dist_c = cell_volume / np.linalg.norm(np.cross(cell_vectors[0], cell_vectors[1])) | |
| plane_distances = np.array([dist_a, dist_b, dist_c]) | |
| supercell = np.ceil(min_interplanar_distance / plane_distances).astype(int) | |
| if np.any(supercell > 1): | |
| print( | |
| f"Making supercell: {supercell} to prevent interplanar distance < {min_interplanar_distance}" | |
| ) | |
| structure = structure.repeat(supercell) | |
| # get position for grid | |
| grid_size = np.ceil(np.array(structure.cell.cellpar()[:3]) / grid_spacing).astype( | |
| int | |
| ) | |
| indices = np.indices(grid_size).reshape(3, -1).T # (G, 3) | |
| pos_grid = indices.dot(cell_vectors / grid_size) # (G, 3) | |
| # get positions for atoms | |
| pos_atoms = structure.get_positions() # (N, 3) | |
| # distance matrix | |
| dist_matrix = mda.lib.distances.distance_array( | |
| pos_grid, pos_atoms, box=structure.cell.cellpar() | |
| ) # (G, N) # TODO: check if we could use other packages instead of mda | |
| # calculate the accessible positions | |
| min_dist = np.min(dist_matrix, axis=1) # (G,) | |
| idx_accessible_pos = np.where(min_dist > cutoff_distance)[0] | |
| # result | |
| return { | |
| "pos_grid": pos_grid, | |
| "idx_accessible_pos": idx_accessible_pos, | |
| "accessible_pos": pos_grid[idx_accessible_pos], | |
| "structure": structure, | |
| } | |