├── .github └── workflows │ └── docs.yaml ├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── bin └── images │ ├── mof-5-6x6x6.gif │ ├── mof-5.gif │ ├── sod-decoration.png │ ├── sod-supercell.png │ └── zn-formate-8x8x8.gif ├── chic ├── __init__.py ├── atomic_cluster.py ├── bonds.py ├── cif.py ├── coarse_graining_methods │ ├── __init__.py │ └── defaults.py ├── decorate.py ├── gulp.py ├── lammps.py ├── linkers │ ├── Im-C4H4.xyz │ ├── Im-H.xyz │ ├── Im_raw.xyz │ ├── bIm_raw.xyz │ └── generate_molecule_template.py ├── net.py ├── rattle.py ├── scatty.py ├── sort_sites.py ├── structure.py ├── templates.py ├── tidy.py ├── utils.py ├── vasp.py ├── vector.py ├── xyz.py └── zif.py ├── docs ├── Makefile ├── make.bat └── source │ ├── _static │ ├── 1,3-BDC.html │ ├── custom.css │ ├── homepage-grab.png │ ├── mep-nodes.data │ ├── mep-nodes.png │ ├── mep.data │ ├── mep.html │ ├── mep.png │ ├── scripts │ │ ├── dihedral.py │ │ └── viz.py │ ├── visualisations │ │ ├── chem_commun_2023.gif │ │ ├── chem_commun_2023.jpeg │ │ ├── chem_mater_2021.jpeg │ │ ├── chem_sci_2020.png │ │ ├── crystengcomm_2024.gif │ │ ├── mIm-clean.html │ │ └── mIm-disordered.html │ ├── zif4-cg-d.html │ ├── zif4-cg.html │ ├── zif4.html │ ├── zif8-cg-d.html │ ├── zif8-cg.html │ └── zif8.html │ ├── api │ ├── atomic-clusters.rst │ ├── net.rst │ └── structure.rst │ ├── case-studies │ ├── cleaning.rst │ ├── coarse-graining.rst │ ├── decorating.rst │ ├── dihedrals.rst │ └── topology-data.rst │ ├── conf.py │ ├── favicon.svg │ ├── hide-title.html │ ├── index.rst │ ├── logo-short.svg │ ├── logo.svg │ └── publications │ └── pub-main.rst ├── examples ├── 1-coarse-graining-basics.ipynb ├── 2-removing-disorder.ipynb ├── 3-decorating-basics.ipynb ├── 4-supercells.ipynb ├── 5-building-units.ipynb ├── 6-protonating-zr-clusters.ipynb ├── UiO-66(Zr) │ ├── POSCAR │ ├── UKUDEL-with-H.cif │ ├── UKUDEL.cif │ ├── UiO-66_cdc-H2O-H.cif │ └── UiO-66_cdc-H2O.cif ├── cg_lammps_output │ ├── melt.plateau_400K.data │ └── plateau_400K.dump ├── cg_zif4 │ ├── POSCAR │ ├── ZIF-4-cag-cg.data │ ├── ZIF-4-cag-overlay.cif │ ├── ZIF-4-cag-tidy.cif │ ├── ZIF-4-cag-topocif.cif │ └── ZIF-4-cag.cif ├── cg_zif8 │ ├── POSCAR │ ├── ZIF-8-cg.xyz │ ├── ZIF-8-sod-cg-1x3x2.cif │ ├── ZIF-8-sod-cg-1x3x2.data │ ├── ZIF-8-sod-cg.cif │ ├── ZIF-8-sod-cg.data │ ├── ZIF-8-sod-overlay.cif │ └── ZIF-8-sod.cif ├── cg_zif_imidzb11 │ ├── IMIDZB11-symmetrised.data │ ├── imidzb11-cg.cif │ └── imidzb11-cg.data └── decorate_sod │ ├── ZIF-8-sod-cg-decorated-CH3-topology.data │ ├── ZIF-8-sod-cg-decorated-CH3.cif │ ├── ZIF-8-sod-cg-decorated-CH3.data │ ├── ZIF-8-sod-cg-decorated-H-1x3x2.data │ ├── ZIF-8-sod-cg-decorated-H-topology.data │ ├── ZIF-8-sod-cg-decorated-H.cif │ ├── ZIF-8-sod-cg-decorated-H.data │ ├── ZIF-8-sod-cg-decorated.data │ └── ZIF-8-sod-cg.cif ├── pyproject.toml ├── setup.py └── tests.py /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: [push] 4 | 5 | permissions: 6 | contents: write 7 | 8 | env: 9 | APT_INSTALL: sudo apt-get install -y --no-install-recommends 10 | 11 | jobs: 12 | docs: 13 | name: Docs 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: actions/setup-python@v4 18 | with: 19 | cache: pip 20 | cache-dependency-path: pyproject.toml 21 | python-version: 3.8 22 | - name: Install dependencies 23 | run: pip install -e ".[dev]" 24 | - name: Install pandoc 25 | run: $APT_INSTALL pandoc 26 | - name: Sphinx build 27 | run: sphinx-build docs/source docs/build 28 | - name: Deploy 29 | uses: peaceiris/actions-gh-pages@v3 30 | with: 31 | publish_branch: gh-pages 32 | github_token: ${{ secrets.GITHUB_TOKEN }} 33 | publish_dir: docs/build/ 34 | force_orphan: true 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__/ 2 | **/.DS_Store 3 | **/cg_lammps_output/ 4 | **/cg_lammps_trajectory/ 5 | **/cg_zif_imidzb11/ 6 | **/gulp/ 7 | **/salem2/ 8 | **/aSiO2/ 9 | **/.ipynb_checkpoints/ 10 | **/*.egg-info/ 11 | tests.py 12 | sandpit.ipynb 13 | new_net.ipynb 14 | dist/ 15 | build/ 16 | site/ 17 | examples/ 18 | **/build/ 19 | **/7-framework-nodes.ipynb 20 | **/8-decorating-sio2.ipynb 21 | **/gulp-part-II.ipynb -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/MANIFEST.in -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![CHIC logo](/docs/source/logo.svg) 2 | 3 | **C**oarse-graining **H**ybrid **I**norganic **C**rystals. 4 | 5 | ## Getting started 6 | 7 | Install with `pip install chic-lib`, and you're ready to go! 8 | 9 | By way of a quick example, ZIF-8 (CSD RefCode: FAWCEN) can be coarse-grained 10 | by running: 11 | 12 | ```python 13 | from chic import Structure 14 | 15 | # read in structure and delete oxygen from the pores. 16 | struct = Structure.from_cif("ZIF-8-sod.cif") 17 | struct.remove_sites_by_symbol("O") 18 | 19 | # compute neighbour list, find atomic clusters, and coarse-grain. 20 | struct.get_neighbours_crystalnn() 21 | struct.find_atomic_clusters() 22 | struct.get_coarse_grained_net() 23 | 24 | # export structure as TopoCIF. 25 | struct.net_to_cif('ZIF-8-sod-cg.cif', write_bonds=True, name='ZIF-8-cg') 26 | ``` 27 | 28 | Head over to the [chic docs](https://tcnicholas.github.io/chic/) to see examples 29 | and more details! 30 | 31 | ## ToDo list 32 | 33 | - [x] Add docs. 34 | - [x] Add simple distance cut-off algorithm for neighbour list building. 35 | - [ ] Add custom implementation of optimised CrystalNN algorithm. 36 | - [x] Integrate back-mapping code. 37 | - [x] Integrate extraction of local energies from LAMMPS dump format. 38 | - [ ] Add registry to Net class for easier future development beyond ZIFs. 39 | 40 | ## Authors 41 | 42 | Thomas C. Nicholas 43 | -------------------------------------------------------------------------------- /bin/images/mof-5-6x6x6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/bin/images/mof-5-6x6x6.gif -------------------------------------------------------------------------------- /bin/images/mof-5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/bin/images/mof-5.gif -------------------------------------------------------------------------------- /bin/images/sod-decoration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/bin/images/sod-decoration.png -------------------------------------------------------------------------------- /bin/images/sod-supercell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/bin/images/sod-supercell.png -------------------------------------------------------------------------------- /bin/images/zn-formate-8x8x8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/bin/images/zn-formate-8x8x8.gif -------------------------------------------------------------------------------- /chic/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | chic: A Python library for coarse-graining hybrid and inorganic frameworks. 3 | 4 | This library provides tools for working with complex structures, allowing for 5 | efficient analysis and manipulation of hybrid and inorganic framework materials. 6 | 7 | Version modifications: 8 | --------------------- 9 | "24.05.24" "0.1.15", "External bonds needs to account for many PBCs." 10 | "24.04.24" "0.1.11", "Correct image type in cut-off neighbour list." 11 | "24.04.24" "0.1.10", "Added pairwise radial cut-offs with rmin and rmax options 12 | for neighbour searching." 13 | "23.04.24" "0.1.9", "Added radial cut-off for neighbour searching." 14 | """ 15 | 16 | 17 | from .structure import Structure 18 | from .net import Net 19 | 20 | 21 | __version__ = "0.1.17" 22 | __author__ = "Thomas C. Nicholas" 23 | __email__ = "tcnicholas@me.com" 24 | __url__ = "https://github.com/tcnicholas/chic" 25 | 26 | 27 | __all__ = ['Structure', 'Net'] 28 | -------------------------------------------------------------------------------- /chic/bonds.py: -------------------------------------------------------------------------------- 1 | """ 2 | 12.06.23 3 | @tcnicholas 4 | Class for handling the bond vectors. 5 | """ 6 | 7 | 8 | from typing import List 9 | 10 | import numpy as np 11 | from pymatgen.core import Structure 12 | 13 | 14 | class Bonding: 15 | """ 16 | A class for representing the bonds in a structure as vectors to extract 17 | local geometric properties. 18 | """ 19 | def __init__( 20 | self, 21 | struct: Structure, 22 | labels: List[str], 23 | bonds: List[List[int]], 24 | ) -> None: 25 | """ 26 | Initialise the bonding class. 27 | 28 | :param struct: Pymatgen Structure object. 29 | :param labels: list of atom labels. 30 | :param bonds: list of bonds in structure. e.g. 31 | """ 32 | self._struct = struct 33 | self._labels = labels 34 | self._bonds = bonds 35 | self._vectors = [] 36 | self._bonded_labels = [] 37 | self._bonds_per_atom() 38 | 39 | 40 | @property 41 | def labels(self) -> np.ndarray(1): 42 | """ 43 | Array of atom labels. 44 | 45 | :return: array of atom labels in structure. 46 | """ 47 | return np.array(self._labels, dtype=" np.ndarray(1): 52 | """ 53 | Compute all bond lengths. 54 | """ 55 | return np.linalg.norm(np.vstack(self._vectors), axis=1) 56 | 57 | 58 | def bond_by_label(self, label: str) -> np.ndarray(2): 59 | """ 60 | Return the bond vectors for a particular atom label. 61 | 62 | :param label: atom label. 63 | :return: bond vectors for atom. 64 | """ 65 | return self._vectors[self._labels.index(label)] 66 | 67 | 68 | def bound_to(self, label: str) -> np.ndarray(1): 69 | """ 70 | Return the labels of units bound to this label. 71 | 72 | :param label: atom label. 73 | :return: labels of atoms bound to this atom. 74 | """ 75 | return [sorted(b[0])[0] for b in self._bonds if label in b[0]] 76 | 77 | 78 | def _get_bond(self, 79 | a1: str, 80 | a2: str, 81 | img1: np.ndarray(3), 82 | img2: np.ndarray(3), 83 | ): 84 | """ 85 | Return the MIC bond vector between two atoms in the structure. 86 | 87 | :param a1: atom label 1. 88 | :param a2: atom label 2. 89 | :param img1: periodic image of atom 1. 90 | :param img2: periodic image of atom 2. 91 | :return: bond vector between atoms. 92 | """ 93 | a1_frac = self._struct[self._labels.index(a1)].frac_coords + img1 94 | a2_frac = self._struct[self._labels.index(a2)].frac_coords + img2 95 | a1_cart = self._struct.lattice.get_cartesian_coords(a1_frac) 96 | a2_cart = self._struct.lattice.get_cartesian_coords(a2_frac) 97 | return a2_cart - a1_cart 98 | 99 | 100 | def _bonds_per_atom(self): 101 | """ 102 | Store all bonds for each atom as centred on each atom. Note this will 103 | double count the bonds (e.g. will store for both the bond A1 - B2 for 104 | both A1 and B2). 105 | 106 | :param structure: Pymatgen Structure object. 107 | :param labels: list of atom labels. 108 | :param bonds: list of bonds in structure. e.g. 109 | [(atom1, atom2), (img1, img2)]. 110 | :return: None. 111 | """ 112 | 113 | # labels are in the same order as the atoms in structure. 114 | vectors = []; bond_labels = [] 115 | for atom1 in self._labels: 116 | 117 | # for each atom, find all bond vectors and get label of second atom. 118 | vs = []; ls = [] 119 | b = [x for x in self._bonds if atom1 in x[0]] 120 | 121 | for x in b: 122 | 123 | # get index of atom1 and atom2 in bond and atom2 label. 124 | ix1 = x[0].index(atom1) 125 | ix2 = int(bool(not ix1)) 126 | atom2 = x[0][ix2] 127 | 128 | # get vector. 129 | v = self._get_bond(atom1, atom2, x[1][ix1], x[1][ix2]) 130 | 131 | # append the vector and store label. 132 | vs.append(v) 133 | ls.append(atom2) 134 | 135 | # append lists to lists. 136 | vectors.append(np.array(vs, dtype=np.float64)) 137 | bond_labels.append(ls) 138 | 139 | # format vectors as numpy array. 140 | self._vectors = np.array(vectors, dtype="object") 141 | self._bonded_labels = np.array(bond_labels, dtype="object") -------------------------------------------------------------------------------- /chic/cif.py: -------------------------------------------------------------------------------- 1 | """ 2 | 27.07.23 3 | @tcnicholas 4 | Handling CIFs. 5 | """ 6 | 7 | import warnings 8 | from pathlib import Path 9 | from datetime import datetime 10 | from typing import Tuple, Dict, Union 11 | 12 | import numpy as np 13 | from scipy.spatial import cKDTree 14 | from pymatgen.io.cif import CifParser 15 | 16 | from .bonds import Bonding 17 | from .tidy import unit_occupancy, no_deuterium 18 | from .utils import remove_symbols, remove_uncertainties 19 | 20 | 21 | topo_tags = [ 22 | '_topol_link.node_label_1', 23 | '_topol_link.node_label_2', 24 | '_topol_link.distance', 25 | '_topol_link.site_symmetry_symop_1', 26 | '_topol_link.site_symmetry_translation_1_x', 27 | '_topol_link.site_symmetry_translation_1_y', 28 | '_topol_link.site_symmetry_translation_1_z', 29 | '_topol_link.site_symmetry_symop_2', 30 | '_topol_link.site_symmetry_translation_2_x', 31 | '_topol_link.site_symmetry_translation_2_y', 32 | '_topol_link.site_symmetry_translation_2_z', 33 | '_topol_link.type', 34 | '_topol_link.multiplicity' 35 | ] 36 | 37 | 38 | frac_tags = [ 39 | '_atom_site_fract_x', 40 | '_atom_site_fract_y', 41 | '_atom_site_fract_z' 42 | ] 43 | 44 | 45 | def parse_bonds(bonds): 46 | """ 47 | Takes raw TopoCIF input and converts to more useful arrays of bonded-atom 48 | labels and their respective perioidic images. 49 | """ 50 | # Extract the images for atoms 1 and 2 for each bond. 51 | i1s = [np.array(x, dtype=int) for x in list(zip(*bonds[4:7]))] 52 | i2s = [np.array(x, dtype=int) for x in list(zip(*bonds[8:11]))] 53 | 54 | # strip away any nonsense. 55 | modified_labels = [ 56 | [remove_symbols(item) for item in sublist] for sublist in bonds[:2] 57 | ] 58 | bonds[:2] = modified_labels 59 | 60 | # Return them, along with the two atom-labels per bond. 61 | return list(zip(list(zip(*bonds[:2])),list(zip(i1s,i2s)))) 62 | 63 | 64 | def match_cif_pym_atoms(cif_dict, structure, tol=1e-5) -> None: 65 | """ 66 | Match up the atom labels from CIF to the atoms in the Pymatgen Structure 67 | object based on fractional coordinates with a tolerance. This only works 68 | when the supplied CIF is in P1 space group, otherwise not all atoms are 69 | labelled explicitly. 70 | 71 | :param atoms: Dictionary of CIF atom labels as keys and fractional 72 | coordinates as values. 73 | :param structure: Pymatgen Structure object. 74 | :param tol: Tolerance for matching fractional coordinates. 75 | :return: None. 76 | """ 77 | 78 | # the coord tags are a list of tuples corresponding to the fractional 79 | # coordinates of each atom in the CIF. we might need to remove the 80 | # uncertainties in brackets. 81 | coord_tags = list(zip(*[cif_dict[t] for t in frac_tags])) 82 | coord_tags = [[remove_uncertainties(x) for x in y] for y in coord_tags] 83 | coords = np.array(coord_tags, dtype=np.float64) 84 | cif_atoms = { 85 | remove_symbols(atom_label):coord 86 | for atom_label,coord in zip(cif_dict["_atom_site_label"], coords) 87 | } 88 | 89 | # Create KD-Tree from Pymatgen fractional coords for efficient matching. 90 | pym_coords = structure.frac_coords % 1.0 91 | kdtree = cKDTree(pym_coords) 92 | 93 | pym_labels = {} 94 | try: 95 | for cif_label, cif_frac_coords in cif_atoms.items(): 96 | dists, indices = kdtree.query(cif_frac_coords, k=1) 97 | if dists < tol: 98 | matching_index = int(indices) 99 | pym_labels[matching_index] = cif_label 100 | else: 101 | raise ValueError( 102 | f"No matching atom found for CIF atom '{cif_label}'." 103 | ) 104 | 105 | for i,a in enumerate(structure): 106 | a.properties["label"] = remove_symbols(pym_labels[i]) 107 | 108 | return True 109 | 110 | except: 111 | 112 | return False 113 | #warnings.warn('Unable to match CIF atoms to Pymatgen atoms.') 114 | 115 | 116 | def get_bonding(cif_dict, structure, tol=1e-8): 117 | """ 118 | Extract bonding information from CIF. 119 | 120 | :param parser: Pymatgen CifParser object. 121 | :param structure: Pymatgen Structure object. 122 | :param tol: Tolerance for matching fractional coordinates. 123 | :return: Bonding object. 124 | """ 125 | 126 | # check if all of the topo_tags are in the cif_dict. 127 | if not all([t in cif_dict for t in topo_tags]): 128 | return None 129 | 130 | # Get the bonding information from the CIF. 131 | bonds = [cif_dict[t] for t in topo_tags] 132 | bonds = parse_bonds(bonds) 133 | labels = [a.properties["label"] for a in structure] 134 | 135 | # Return the Bonding object. 136 | return Bonding(structure, labels, bonds) 137 | 138 | 139 | def build_neighbor_list_from_topocif(struct, bonds): 140 | """ 141 | Build a neighbor list for each site in the Pymatgen Structure based on a 142 | list of bonds. 143 | 144 | :param struct: Pymatgen Structure object. 145 | :param bonds: List of bonds where each bond is a tuple containing 146 | ((label1, label2), (image1, image2)). 147 | :return: Dictionary mapping each site index to a list of neighboring sites. 148 | """ 149 | label_to_index = {site.properties["label"]:i for i,site in enumerate(struct)} 150 | 151 | neighbor_list = {i: [] for i in range(len(struct))} 152 | 153 | for (label1, label2), (image1, image2) in bonds: 154 | 155 | index1, index2 = label_to_index.get(label1), label_to_index.get(label2) 156 | 157 | if index1 is not None: 158 | neighbor_list[index1].append({ 159 | 'site': struct[index2], 160 | 'image': image2 - image1, 161 | 'weight': 1.0, 162 | 'site_index': index2, 163 | 'distance': np.linalg.norm(image2 - image1) 164 | }) 165 | 166 | if index2 is not None: 167 | neighbor_list[index2].append({ 168 | 'site': struct[index1], 169 | 'image': image1 - image2, 170 | 'weight': 1.0, 171 | 'site_index': index1, 172 | 'distance': np.linalg.norm(image1 - image2) 173 | }) 174 | 175 | return neighbor_list 176 | 177 | 178 | def read_cif( 179 | filename: str, 180 | primitive: bool = False, 181 | occupancy_tolerance: float = 100, 182 | merge_tolerance: float = 0.01, 183 | site_tolerance: float = 0, 184 | match_atoms_tolerance: float = 1e-8, 185 | ): 186 | """ 187 | Read CIF with Pymatgen. 188 | 189 | :param filename: filename of CIF. 190 | :param primitive: whether to return primitive structure. 191 | :param occupancy_tolerance: occupancy tolerance for CIF parser. 192 | :param merge_tolerance: merge tolerance for CIF parser. 193 | :param site_tolerance: site tolerance for CIF parser. 194 | """ 195 | 196 | # load structure from CIF. I find the Pymatgen CIF warnings irritating. 197 | with warnings.catch_warnings(): 198 | warnings.simplefilter("ignore") 199 | parser = CifParser( 200 | filename, 201 | occupancy_tolerance = occupancy_tolerance, 202 | site_tolerance = site_tolerance 203 | ) 204 | struct = parser.get_structures(primitive=primitive)[0] 205 | 206 | # tidy the structure 207 | unit_occupancy(struct) 208 | no_deuterium(struct) 209 | struct.merge_sites(tol=merge_tolerance, mode="delete") 210 | 211 | # add the raw CIF labels to the structure properties. 212 | cif_dict = [x for x in parser.as_dict().values()][0] 213 | attempt_match = match_cif_pym_atoms( 214 | cif_dict, struct, tol=match_atoms_tolerance 215 | ) 216 | 217 | # also attempt to gather the bonds from the CIF. 218 | bonding = None 219 | if attempt_match: 220 | try: 221 | bonding = get_bonding(cif_dict, struct) 222 | except: 223 | pass 224 | 225 | return struct, bonding 226 | 227 | 228 | def format_bond( 229 | atom1: str, 230 | atom2: str, 231 | image: Tuple[float, float, float], 232 | distance: float 233 | ) -> str: 234 | """ 235 | Formats the bond information into a string for writing to file. 236 | """ 237 | return (f'{atom1:>8} {atom2:>8} {distance:8.5f} ' 238 | f'{1:>4} {0:>4} {0:>4} {0:>4} ' 239 | f'{1:>4} {image[0]:4.0f} {image[1]:4.0f} {image[2]:4.0f} V 1\n') 240 | 241 | 242 | class TopoCifWriter: 243 | 244 | def __init__(self, 245 | parent_structure, 246 | beads: Dict, 247 | bead_bonds: Dict, 248 | name: str = 'net' 249 | ): 250 | """ 251 | Initialises a new instance of the TopoCifWriter class. 252 | """ 253 | self._parent_structure = parent_structure 254 | self._beads = beads 255 | self._bead_bonds = bead_bonds 256 | self._name = name 257 | 258 | 259 | def write_file(self, filename: Union[str, Path], write_bonds: bool=True): 260 | """ 261 | Writes the content to a file with the provided filename. 262 | """ 263 | if self._beads is None or self._bead_bonds is None: 264 | raise ValueError("Beads or Bead Bonds are not initialised.") 265 | 266 | sections = [self._header(), self._cell_loop(), self._positions_loop()] 267 | 268 | if write_bonds and self._bead_bonds: 269 | sections.append(self._bonds_loop()) 270 | 271 | content = "".join(sections) 272 | content += f"#End of data_{self._name}\n\n" 273 | 274 | filename = Path(filename) 275 | filename.parent.mkdir(parents=True, exist_ok=True) 276 | with filename.open("w+") as w: 277 | w.write(content) 278 | 279 | 280 | def _header(self) -> str: 281 | """ 282 | Generates the header of file string. 283 | """ 284 | form = f"'{self._parent_structure.composition.anonymized_formula}'" 285 | date = datetime.now().strftime('%Y-%m-%d') 286 | return ( 287 | f"data_{self._name}\n" 288 | f"_audit_creation_date {date:>{60-len('_audit_creation_date')}}\n" 289 | f"_chemical_formula_sum {form:>{60-len('_chemical_formula_sum')}}\n" 290 | ) 291 | 292 | 293 | def _cell_loop(self) -> str: 294 | """ 295 | Writes unit cell loop to file string. 296 | """ 297 | cell_params = np.ravel(self._parent_structure.lattice.parameters) 298 | _, Z = self._parent_structure.composition.get_reduced_composition_and_factor() 299 | volume = self._parent_structure.lattice.volume 300 | 301 | cell_string = (f"_cell_length_a\t\t\t{cell_params[0]:.5f}\n" 302 | f"_cell_length_b\t\t\t{cell_params[1]:.5f}\n" 303 | f"_cell_length_c\t\t\t{cell_params[2]:.5f}\n" 304 | f"_cell_angle_alpha\t\t{cell_params[3]:.5f}\n" 305 | f"_cell_angle_beta\t\t{cell_params[4]:.5f}\n" 306 | f"_cell_angle_gamma\t\t{cell_params[5]:.5f}\n" 307 | f"_cell_volume\t\t\t{volume:.5f}\n" 308 | f"_cell_formula_units_z\t\t{int(Z)}\n" 309 | "_symmetry_space_group_name_h-m\t'P 1'\n" 310 | "_symmetry_int_tables_number\t1\n" 311 | "loop_\n" 312 | "_space_group_symop_id\n" 313 | "_space_group_symop_operation_xyz\n" 314 | "1 x,y,z\n") 315 | 316 | return cell_string 317 | 318 | 319 | def _positions_loop(self) -> str: 320 | """ 321 | Writes atom positions loop. 322 | """ 323 | positions = [ 324 | "loop_\n", 325 | "_atom_site_label\n", 326 | "_atom_site_type_symbol\n", 327 | "_atom_site_symmetry_multiplicity\n", 328 | "_atom_site_fract_x\n", 329 | "_atom_site_fract_y\n", 330 | "_atom_site_fract_z\n", 331 | "_atom_site_occupancy\n" 332 | ] 333 | 334 | positions.extend( 335 | bead.to_topocif_string() + "\n" for bead in self._beads.values() 336 | ) 337 | return ''.join(positions) 338 | 339 | 340 | def _bonds_loop(self) -> str: 341 | """ 342 | Writes bonds loop to file string in the TopoCIF format. 343 | """ 344 | bonds = [ 345 | "loop_\n", 346 | "_topol_link.node_label_1\n", 347 | "_topol_link.node_label_2\n", 348 | "_topol_link.distance\n", 349 | "_topol_link.site_symmetry_symop_1\n", 350 | "_topol_link.site_symmetry_translation_1_x\n", 351 | "_topol_link.site_symmetry_translation_1_y\n", 352 | "_topol_link.site_symmetry_translation_1_z\n", 353 | "_topol_link.site_symmetry_symop_2\n", 354 | "_topol_link.site_symmetry_translation_2_x\n", 355 | "_topol_link.site_symmetry_translation_2_y\n", 356 | "_topol_link.site_symmetry_translation_2_z\n", 357 | "_topol_link.type\n", 358 | "_topol_link.multiplicity\n" 359 | ] 360 | 361 | for edge, images in self._bead_bonds.items(): 362 | atom1 = self._beads[edge[0]].label 363 | atom2 = self._beads[edge[1]].label 364 | for image in images: 365 | bonds.append(format_bond( 366 | atom1, 367 | atom2, 368 | image['image'], 369 | image['bead_distance'] 370 | )) 371 | return ''.join(bonds) 372 | -------------------------------------------------------------------------------- /chic/coarse_graining_methods/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/chic/coarse_graining_methods/__init__.py -------------------------------------------------------------------------------- /chic/coarse_graining_methods/defaults.py: -------------------------------------------------------------------------------- 1 | """ 2 | 02.02.24 3 | @tcnicholas 4 | Defaults for coarse-graining methods. 5 | """ 6 | 7 | import numpy as np 8 | 9 | 10 | def centroid_method1(self): 11 | pass 12 | 13 | 14 | def centroid_method2(self): 15 | pass 16 | 17 | 18 | def imidazolate_ring(self, precision=1e-8, skip_elements=None, **kwargs): 19 | """ 20 | Searches for the core 5-membered ring of an imidazolate molecule (by finding 21 | the 5-membered ring that contains the two connecting nitrogen atoms), and 22 | takes the centroid of that (excluding all substiuents and hydrogen atoms). 23 | """ 24 | 25 | bead_count = 1 26 | non_framework_count = -1 27 | for label, cluster in self._atomic_clusters.items(): 28 | 29 | # gather the rings for the current cluster. note, we do not have to deal 30 | # with single-metal nodes separately because the get_rings method 31 | # defaults to giving the one atom if the cluster only has one atom. this 32 | # will break for general usage with MOF metal clusters. 33 | find_rings_kwargs = { 34 | 'including': ['C', 'N'], 35 | 'connective_including': True, 36 | 'strong_rings': True 37 | } 38 | find_rings_kwargs.update(**kwargs) 39 | 40 | # check coordination of the cluster meets the requirements specified. 41 | if not ( 42 | self._minimum_coordination_numbers[label[0]] <= 43 | cluster.coordination_number <= 44 | self._maximum_coordination_numbers[label[0]] 45 | ): 46 | centroid = [cluster.get_centroid(skip_elements=skip_elements)] 47 | cluster.assign_beads( 48 | [non_framework_count], 49 | *self._wrap_cart_coords_to_frac( 50 | centroid, precision=precision 51 | ), 52 | {i: [0] for i in cluster.site_indices}, 53 | internal_bead_bonds=[] 54 | ) 55 | cluster.skip = True 56 | non_framework_count -= 1 57 | continue 58 | 59 | # we require one ring only. 60 | rings = cluster.find_rings(**find_rings_kwargs) 61 | assert len(rings) == 1, "Ambiguous assignment of ZIF bonding ring!" 62 | 63 | # hence get centroid of ring. 64 | ring_indices = [ 65 | cluster._site_indices.index(x) for x in rings[0]['nodes'] 66 | ] 67 | ring_centroid = [np.mean(cluster._cart_coords[ring_indices], axis=0)] 68 | 69 | # assign the values to the cluster. 70 | cluster.assign_beads( 71 | [bead_count], 72 | *self._wrap_cart_coords_to_frac(ring_centroid, precision=precision), 73 | {i: [0] for i in cluster.site_indices}, 74 | internal_bead_bonds=[] 75 | ) 76 | cluster.skip = False 77 | bead_count += 1 78 | 79 | 80 | methods = { 81 | 82 | 'centroid_method1': { 83 | 'func': centroid_method1, 84 | 'bead_type': 'single', 85 | }, 86 | 87 | 'centroid_method2': { 88 | 'func': centroid_method2, 89 | 'bead_type': 'single', 90 | }, 91 | 92 | 'imidazolate_ring': { 93 | 'func': imidazolate_ring, 94 | 'bead_type': 'single' 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /chic/decorate.py: -------------------------------------------------------------------------------- 1 | """ 2 | 12.06.23 3 | @tcnicholas 4 | Generalised decorate code for other imidazolate linkers. 5 | """ 6 | 7 | import math 8 | from typing import Union 9 | 10 | import numpy as np 11 | 12 | from . import templates 13 | from .zif import Zinc, Imidizolate 14 | from .vector import random_vector, compute_angle, align_matrix, rotate_vector 15 | from .utils import setattrs 16 | 17 | 18 | random = np.random.default_rng(seed=42) 19 | 20 | 21 | def perturb_centroid( 22 | centroid: np.ndarray(3), 23 | vectors: np.ndarray((2,3)), 24 | ) -> np.ndarray(3): 25 | """ 26 | Perturb the centroid of the ring slightly. 27 | 28 | :param centroid: centroid of the ring. 29 | :param vectors: bond vectors to use to align the linker. 30 | :return: perturbed centroid. 31 | """ 32 | vectors = vectors.astype(np.float64) 33 | v_unit = vectors / np.linalg.norm(vectors, axis=1)[:,None] 34 | rvec = random_vector(random.random(), random.random(), norm=True) 35 | perturb = np.cross(rvec, v_unit[0]) 36 | perturb /= np.linalg.norm(perturb) 37 | 38 | # original positions of bound zincs. 39 | m1 = (centroid + vectors[0]).copy() 40 | m2 = (centroid + vectors[1]).copy() 41 | 42 | # compute new bond vectors. 43 | centroid += perturb 44 | v_unit = np.array([m1-centroid, m2-centroid]) 45 | v_unit = v_unit / np.linalg.norm(vectors, axis=1)[:,None] 46 | 47 | # compute new bisecting vector. 48 | this_way = np.sum(v_unit, axis=0) 49 | this_way = this_way / np.linalg.norm(this_way) 50 | 51 | return centroid, v_unit, this_way 52 | 53 | 54 | #TODO: implement other orient methods. 55 | def place_linker( 56 | template: Union[templates.ZIF_CH3, templates.ZIF_H, templates.ZIF_C4H4], 57 | centroid: np.ndarray(3), 58 | vectors: np.ndarray((2,3)), 59 | orient: str = 'bisect', 60 | allow_defects: bool = True, 61 | desired_angle: float = 145.0, 62 | ): 63 | """ 64 | Determine how to orient the linker in the structure. 65 | 66 | :param template: template linker. 67 | :param centroid: centroid of the linker ring. 68 | :param vector: bond vectors to use to align the linker. 69 | :param orient: orientation method. 70 | """ 71 | 72 | # default to just taking the first 2 vectors if more than 2 were given. 73 | #TODO: there will be better ways of deciding this. 74 | vectors = vectors[:2].astype(np.float64) 75 | 76 | # in the case of a single bond to the oxygen atom, we randomly assign a 77 | # second vector to give the placement of the imidazolate molecule. we could 78 | # probably improve this by choosing a random vector at 145* to the first 79 | # angle. 80 | if vectors.shape==(1,3) and allow_defects: 81 | 82 | existing_vector = vectors[0] 83 | new_vector = random_vector(random.random(), random.random(), norm=True) 84 | axis_of_rotation = np.cross(existing_vector, new_vector) 85 | 86 | # If the cross product is zero, vectors are parallel. Need a 87 | # non-parallel vector. 88 | if np.all(axis_of_rotation == 0): 89 | axis_of_rotation = np.cross(existing_vector, np.array([1, 0, 0])) 90 | if np.all(axis_of_rotation == 0): 91 | axis_of_rotation = np.array([0, 1, 0]) 92 | 93 | rotated_vec = rotate_vector(new_vector, axis_of_rotation, desired_angle) 94 | vectors = np.vstack([vectors, rotated_vec]) 95 | 96 | v_unit = vectors / np.linalg.norm(vectors, axis=1)[:,None] 97 | angle = compute_angle(*v_unit) 98 | 99 | if orient == 'bisect': 100 | 101 | # in the case of 180 angles, perturb the position of the ring slightly 102 | # and determine a new bisecting vector. 103 | if math.isclose(angle, np.pi): 104 | centroid, v_unit, this_way = perturb_centroid(centroid, vectors) 105 | 106 | # define the direction as along the bisecting vector. 107 | this_way = np.sum(v_unit, axis=0) 108 | this_way = this_way / np.linalg.norm(this_way) 109 | 110 | # now align molecule along bisecting vector. 111 | mol_perp = np.cross(*v_unit).astype(np.float64) 112 | mol_perp /= np.linalg.norm(mol_perp) 113 | coords = template.coordinates.copy() 114 | if not np.allclose(np.abs(mol_perp), np.array([0,0,1])): 115 | rot1 = align_matrix(np.array([0,0,1]), mol_perp) 116 | coords = np.matmul(coords, rot1) 117 | 118 | dir2 = coords[0].copy() 119 | rot2 = align_matrix(dir2, this_way) 120 | coords = np.matmul(coords, rot2) 121 | coords += centroid 122 | 123 | return coords.astype(np.float64) 124 | 125 | 126 | def assign_closest_nitrogen( 127 | decorated_atoms: np.ndarray, 128 | get_frac: callable, 129 | get_dist: callable, 130 | a_site_unit: Zinc, 131 | b_site_unit: Imidizolate, 132 | i: int, 133 | ) -> None: 134 | """ 135 | Determine which nitrogen atom in the imidazolate is bound to this a site. 136 | 137 | :param decorated_atoms: array of decorated atoms. 138 | :param get_frac: function to get fractional coordinates. 139 | :param get_dist: function to get distance between two points. 140 | :param a_site_unit: Zinc unit. 141 | :param b_site_unit: Imidazolate unit. 142 | :param i: index of imidazolate. 143 | :return: None. 144 | """ 145 | 146 | # first gather fractional coordinates. 147 | zn_p = get_frac(decorated_atoms[a_site_unit.atom_id-1][4:]) 148 | na_p = get_frac(decorated_atoms[b_site_unit.atom_id_by_label('Na')-1][4:]) 149 | nb_p = get_frac(decorated_atoms[b_site_unit.atom_id_by_label('Nb')-1][4:]) 150 | 151 | # check two distances. 152 | r_na = get_dist(zn_p, na_p)[0] 153 | r_nb = get_dist(zn_p, nb_p)[0] 154 | assert r_na != r_nb, 'Unclear bonding assignment for Zn-N!' 155 | 156 | # assignment. 157 | if r_na < r_nb: 158 | setattrs(a_site_unit, 159 | **{f"Im{i}_N":[b_site_unit.atom_id_by_label('Na'), "a"]} 160 | ) 161 | b_site_unit.Zn_a = a_site_unit.mol_id 162 | else: 163 | setattrs(a_site_unit, 164 | **{f"Im{i}_N":[b_site_unit.atom_id_by_label('Nb'), "b"]} 165 | ) 166 | b_site_unit.Zn_b = a_site_unit.mol_id 167 | -------------------------------------------------------------------------------- /chic/linkers/Im-C4H4.xyz: -------------------------------------------------------------------------------- 1 | 14 2 | Properties=species:S:1:pos:R:3 pbc="F F F" 3 | C -0.73597585 -0.94068366 0.00096014 4 | C -1.47976724 -2.15283610 -0.01499364 5 | C -0.73109556 -3.33834693 0.01752366 6 | H -2.43004830 -2.16082845 -0.04827870 7 | H -1.19014189 -4.16953700 0.06600101 8 | N -1.18813096 0.41266361 -0.00059483 9 | C 0.73597694 -0.94068283 -0.00096007 10 | C 1.47977047 -2.15283402 0.01499333 11 | C 0.73109926 -3.33834545 -0.01752333 12 | C -0.00000089 1.05603741 0.00000013 13 | H 2.43005058 -2.16082569 0.04827899 14 | H 1.19014680 -4.16953597 -0.06600078 15 | H -0.00000089 2.00711033 -0.00000024 16 | N 1.18813076 0.41266547 0.00059463 17 | -------------------------------------------------------------------------------- /chic/linkers/Im-H.xyz: -------------------------------------------------------------------------------- 1 | 8 2 | Properties=species:S:1:pos:R:3 pbc="F F F" 3 | C -0.00259284 1.09794768 -0.00748570 4 | C -0.67922515 -0.91839665 -0.00155239 5 | C 0.68361712 -0.92484814 -0.00264092 6 | H -0.00259284 2.03807421 -0.02460687 7 | H -1.22963442 -1.67977267 -0.00552243 8 | H 1.23315722 -1.68711056 -0.00644115 9 | N -1.11273746 0.37477594 0.00550580 10 | N 1.11093832 0.37052117 0.00617321 11 | -------------------------------------------------------------------------------- /chic/linkers/Im_raw.xyz: -------------------------------------------------------------------------------- 1 | 8 2 | 3 | C 5.506638 11.234027 11.789139 4 | C 6.144145 9.386436 10.950388 5 | C 7.247966 10.075265 11.355944 6 | H 4.955651 11.941225 12.072715 7 | H 6.147224 8.541473 10.539672 8 | H 8.139337 9.789018 11.274869 9 | N 5.034473 10.125473 11.238017 10 | N 6.831685 11.253009 11.903933 11 | -------------------------------------------------------------------------------- /chic/linkers/bIm_raw.xyz: -------------------------------------------------------------------------------- 1 | 14 2 | 3 | C 3.573850 7.440566 18.099948 4 | C 2.428300 6.702277 17.693207 5 | C 2.371022 5.366436 18.116587 6 | H 1.740970 7.089879 17.162596 7 | H 1.595778 4.854248 17.915066 8 | N 3.918847 8.804093 17.859601 9 | C 4.656794 6.815328 18.876452 10 | C 4.590193 5.454108 19.283193 11 | C 3.461959 4.736584 18.859813 12 | C 5.113682 8.857158 18.488200 13 | H 5.269530 5.052664 19.813804 14 | H 3.406013 3.809108 19.061334 15 | H 5.589219 9.680811 18.488200 16 | N 5.665145 7.795868 19.116799 17 | -------------------------------------------------------------------------------- /chic/linkers/generate_molecule_template.py: -------------------------------------------------------------------------------- 1 | """ 2 | 12.06.23 3 | @tcnicholas 4 | Take imidazolate ligand in arbitrary orientation and align the molecule plane 5 | with the xy-plane, center the ring at the origin, and align the ring-centre and 6 | subsituent with the positive y-axis. 7 | """ 8 | 9 | 10 | import ase 11 | import numpy as np 12 | from ase.io import read 13 | 14 | 15 | def center_molecule( 16 | molecule: ase.Atoms, 17 | ring_coords: np.ndarray 18 | ) -> None: 19 | """ 20 | Center ring centroid at origin. 21 | 22 | :param molecule: molecule to center. 23 | :param ring_coords: coordinates of ring atoms. 24 | """ 25 | ring_center = np.mean(ring_coords, axis=0) 26 | molecule.positions -= ring_center 27 | 28 | 29 | def fit_plane( 30 | points: np.ndarray 31 | ) -> np.ndarray(3): 32 | """ 33 | Fit plane to points in 3D space, and return the normal vector. 34 | 35 | :param points: points to fit plane to. 36 | """ 37 | centroid = np.mean(points, axis=0) 38 | cov_mat = np.cov(points - centroid, rowvar=False) 39 | _, _, vh = np.linalg.svd(cov_mat) 40 | return vh[-1] 41 | 42 | 43 | def rotation_matrix_from_vectors( 44 | vec1: np.ndarray(3), 45 | vec2: np.ndarray(3), 46 | ) -> np.ndarray((3,3)): 47 | """ 48 | Find the rotation matrix that aligns vec1 to vec2. 49 | 50 | :param vec1: vector to align. 51 | :param vec2: vector to align to. 52 | """ 53 | a = (vec1 / np.linalg.norm(vec1)).reshape(3) 54 | b = (vec2 / np.linalg.norm(vec2)).reshape(3) 55 | v = np.cross(a, b) 56 | c = np.dot(a, b) 57 | s = np.linalg.norm(v) 58 | kmat = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]]) 59 | rotation_matrix = np.eye(3) + kmat + kmat.dot(kmat) * ((1 - c) / (s ** 2)) 60 | return rotation_matrix 61 | 62 | 63 | def align_to_xy_plane( 64 | points: np.ndarray(3), 65 | subset=None 66 | ) -> np.ndarray(3): 67 | """ 68 | Rotate the points so that the plane best fit to the subset lies on the 69 | xy-plane. 70 | 71 | :param points: points to rotate. 72 | :param subset: subset of points to fit plane to. 73 | """ 74 | subset = points if subset is None else subset 75 | normal = fit_plane(subset) 76 | rot_matrix = rotation_matrix_from_vectors(normal, [0, 0, 1]) 77 | rotated_points = np.dot(points, rot_matrix.T) # rotate all points 78 | return rotated_points 79 | 80 | 81 | def calculate_angle( 82 | vec1: np.ndarray(3), 83 | vec2: np.ndarray(3), 84 | ) -> float: 85 | """ 86 | Calculate angle between two vectors (radians). 87 | 88 | :param vec1: vector 1. 89 | :param vec2: vector 2. 90 | """ 91 | dot_product = np.dot(vec1, vec2) 92 | norm_product = np.linalg.norm(vec1) * np.linalg.norm(vec2) 93 | return np.arccos(dot_product / norm_product) 94 | 95 | 96 | def rotation_matrix_z( 97 | theta: float, 98 | ) -> np.ndarray((3,3)): 99 | """ 100 | Calculate 3D rotation matrix for rotation around z-axis. 101 | 102 | :param theta: angle to rotate by (radians). 103 | """ 104 | return np.array([ 105 | [np.cos(theta), -np.sin(theta), 0], 106 | [np.sin(theta), np.cos(theta), 0], 107 | [0, 0, 1] 108 | ]) 109 | 110 | 111 | def align_to_y_axis( 112 | points: np.ndarray(3), 113 | v1: np.ndarray(3), 114 | ): 115 | """ 116 | Rotate points in the xy plane such that v1 aligns with the y-axis. 117 | 118 | :param points: points to rotate. 119 | :param v1: vector to align with y-axis. 120 | """ 121 | y_axis = np.array([0, 1, 0]) 122 | v1[2] = 0 123 | 124 | angle = calculate_angle(v1, y_axis) 125 | if np.cross(v1, y_axis)[2] < 0: 126 | angle = -angle 127 | 128 | rot_matrix = rotation_matrix_z(angle) 129 | rotated_points = np.dot(points, rot_matrix.T) 130 | 131 | return rotated_points 132 | 133 | 134 | def imidazolate(): 135 | """ 136 | Generate an unsubstituted imidazolate molecule template. 137 | 138 | I started by cutting out a ligand from VEJYUF (ZIF-4) structure. 139 | """ 140 | 141 | im_h = read("Im_raw.xyz") 142 | ring_pos = np.vstack([im_h.positions[:3,:], im_h.positions[-2:,:]]) 143 | center_molecule(im_h, ring_pos) 144 | 145 | ring_pos = np.vstack([im_h.positions[:3,:], im_h.positions[-2:,:]]) 146 | coords = align_to_xy_plane(im_h.positions, ring_pos) 147 | im_h.positions = coords 148 | 149 | # point the C2-H2 bond along the y-axis. 150 | c2_axis = im_h.positions[3,:]-im_h.positions[0,:] 151 | points = align_to_y_axis(im_h.positions, c2_axis) 152 | im_h.positions = points 153 | 154 | im_h.write("Im-H.xyz") 155 | 156 | 157 | 158 | def methyl_imidazolate(): 159 | """ 160 | Generate a methyl imidazolate molecule template. 161 | 162 | I started by cutting out a ligand from the example ZIF8-CH3 structure and 163 | then we re-orient it to get a systematic template. 164 | """ 165 | 166 | im_ch3 = read("ZIF8_CH3_222.xyz") 167 | ring_pos = np.vstack([im_ch3.positions[:3,:], im_ch3.positions[-2:,:]]) 168 | center_molecule(im_ch3, ring_pos) 169 | 170 | ring_pos = np.vstack([im_ch3.positions[:3,:], im_ch3.positions[-2:,:]]) 171 | coords = align_to_xy_plane(im_ch3.positions, ring_pos) 172 | im_ch3.positions = coords 173 | 174 | methyl_carbon_vector = im_ch3.positions[3,:]-im_ch3.positions[2,:] 175 | points = align_to_y_axis(im_ch3.positions, methyl_carbon_vector) 176 | im_ch3.positions = points 177 | 178 | im_ch3.write("Im-CH3.xyz") 179 | 180 | 181 | def benzimidazolate(): 182 | """ 183 | Generate a benzene substituted imidazolate molecule template. 184 | 185 | I cut out a ligand from the ZIF-68-GME structure (GITTUZ CSD RefCode). 186 | """ 187 | 188 | im_b = read("bIm_raw.xyz") 189 | ring_pos = np.vstack([ 190 | im_b.positions[9,:], 191 | im_b.positions[5,:], 192 | im_b.positions[13,:], 193 | im_b.positions[0,:], 194 | im_b.positions[6,:], 195 | 196 | ]) 197 | center_molecule(im_b, ring_pos) 198 | coords = align_to_xy_plane(im_b.positions, ring_pos) 199 | im_b.positions = coords 200 | 201 | # point the C2-H2 bond along the y-axis. 202 | c2_axis = im_b.positions[12,:]-im_b.positions[9,:] 203 | points = align_to_y_axis(im_b.positions, c2_axis) 204 | im_b.positions = points 205 | 206 | im_b.write("Im-C4H4.xyz") 207 | 208 | 209 | if __name__ == '__main__': 210 | imidazolate() 211 | -------------------------------------------------------------------------------- /chic/rattle.py: -------------------------------------------------------------------------------- 1 | """ 2 | 22.06.23 3 | @tcnicholas 4 | Rattling methods. 5 | """ 6 | 7 | import numpy as np 8 | from ase.geometry import cellpar_to_cell 9 | from pymatgen.core.lattice import Lattice 10 | 11 | from .net import Net 12 | from .bonds import Bonding 13 | 14 | 15 | def rattle_vectors(size, stddev=0.001, seed=None, rng=None): 16 | if seed is not None and rng is not None: 17 | raise ValueError('Please do not provide both seed and rng.') 18 | if rng is None: 19 | if seed is None: 20 | seed = 42 21 | rng = np.random.default_rng(seed=seed) 22 | return rng.normal(scale=stddev, size=size) 23 | 24 | 25 | def rattle_net( 26 | net: Net, 27 | random_seed: int, 28 | rms_atoms: float, 29 | cell_length_dev: float, 30 | cell_angle_dev: float, 31 | ) -> None: 32 | """ 33 | Rattle the underlying (cg) net prior to re-decoration. 34 | 35 | Arguments: 36 | net: the Net object to manipulate. 37 | random_seed: the random seed to pass to the random number generator for 38 | generating the perturbations. 39 | rms_atoms: the root-mean-squared displacement to use for translating the 40 | atoms (Å). 41 | cell_length_dev: percentage deviation for cell length perturbations. 42 | cell_angle_dev: upper and lower limits for cell angle perturbations in 43 | degrees. 44 | """ 45 | 46 | cell_parameters = net.lattice.parameters 47 | lengths = cell_parameters[:3] 48 | angles = cell_parameters[3:] 49 | 50 | # cell perturbation. 51 | rng = np.random.default_rng(seed=random_seed) 52 | 53 | # generate cell length perturbation. 54 | n_lengths = np.zeros(3) 55 | for i,l in enumerate(lengths): 56 | n_lengths[i] = rng.uniform( 57 | low=l-(l*cell_length_dev), 58 | high=l+(l*cell_length_dev) 59 | ) 60 | 61 | # generate cell angle perturbation. 62 | n_angles = np.zeros(3) 63 | for i,a in enumerate(angles): 64 | n_angles[i] = rng.uniform(low=a-cell_angle_dev, high=a+cell_angle_dev) 65 | 66 | # hence set the new cell. 67 | ncell = cellpar_to_cell(np.concatenate([n_lengths, n_angles])) 68 | net.lattice = Lattice(ncell) 69 | 70 | # atom perturbation. 71 | displacements = rattle_vectors( 72 | size = net.cart_coords.shape, 73 | stddev = rms_atoms, 74 | rng = rng 75 | ) 76 | for i in range(len(net)): 77 | net.translate_sites( 78 | indices=i, vector=displacements[i,:], frac_coords=False 79 | ) 80 | 81 | # update the bonding information. 82 | net._bonding = Bonding( 83 | net, 84 | net._bonding._labels, 85 | net._bonding._bonds 86 | ) 87 | 88 | 89 | def rattle_atoms( 90 | net: Net, 91 | random_seed: int, 92 | rms_atoms: float, 93 | cell_length_dev: float, 94 | cell_angle_dev: float, 95 | ) -> None: 96 | """ 97 | Rattle decorated net to sample distortions of the atomistic representation. 98 | 99 | For the coarse-grained models, this likely equates to introducing noise into 100 | the dataset since we still only represent the linkers as single spherical 101 | points under the SOAP representation. 102 | 103 | Arguments: 104 | net: the Net object to manipulate. 105 | random_seed: the random seed to pass to the random number generator for 106 | generating the perturbations. 107 | rms_atoms: the root-mean-squared displacement to use for translating the 108 | atoms (Å). 109 | cell_length_dev: percentage deviation for cell length perturbations. 110 | cell_angle_dev: upper and lower limits for cell angle perturbations in 111 | degrees. 112 | """ 113 | 114 | cell_parameters = net.lattice.parameters 115 | lengths = cell_parameters[:3] 116 | angles = cell_parameters[3:] 117 | 118 | # cell perturbation. 119 | rng = np.random.default_rng(seed=random_seed) 120 | 121 | # generate cell length perturbation. 122 | n_lengths = np.zeros(3) 123 | for i,l in enumerate(lengths): 124 | n_lengths[i] = rng.uniform( 125 | low=l-(l*cell_length_dev), 126 | high=l+(l*cell_length_dev) 127 | ) 128 | 129 | # generate cell angle perturbation. 130 | n_angles = np.zeros(3) 131 | for i,a in enumerate(angles): 132 | n_angles[i] = rng.uniform(low=a-cell_angle_dev, high=a+cell_angle_dev) 133 | 134 | # hence set the new cell. 135 | ncell = cellpar_to_cell(np.concatenate([n_lengths, n_angles])) 136 | net.lattice = Lattice(ncell) 137 | 138 | # atom perturbation. 139 | coords = net._decorated_atoms[:,-3:] 140 | displacements = rattle_vectors( 141 | size = coords.shape, 142 | stddev = rms_atoms, 143 | rng = rng 144 | ) 145 | net._decorated_atoms[:,-3:] = coords + displacements 146 | -------------------------------------------------------------------------------- /chic/scatty.py: -------------------------------------------------------------------------------- 1 | """ 2 | 27.10.23 3 | @tcnicholas 4 | Converting LAMMPS dump files to scatty input files. 5 | """ 6 | 7 | from typing import List 8 | from pathlib import Path 9 | 10 | import numpy as np 11 | from ase import Atoms 12 | from pymatgen.core import Element 13 | from pymatgen.core.lattice import Lattice 14 | 15 | 16 | class ScattyNodeOnlyWriter: 17 | 18 | def __init__(self, 19 | single_unit_cell: Atoms, 20 | trajectory: List[Atoms], 21 | first_frame: Atoms = None, 22 | sub_Z: int = 30, 23 | title: str = 'Scatty-Test', 24 | box: List[int] = [2, 2, 2], 25 | precision: int = 5, 26 | ) -> None: 27 | """ 28 | Main class for writing the scatty input files. 29 | 30 | Arguments: 31 | trajectory: The trajectory of the atoms. 32 | first_frame: The first frame in the trajectory. If None, the first 33 | frame is taken as the first frame in the trajectory. 34 | sub_Z: The atomic number to replace all atoms with. 35 | """ 36 | 37 | # store the single unit cell and the trajectory. 38 | self._single_unit_cell = single_unit_cell 39 | self._trajectory = trajectory 40 | 41 | # if first frame is not given, take the first frame in the trajectory, 42 | # and remove this frame from the trajectory. 43 | self._first_frame = first_frame if first_frame is not None else self._trajectory.pop(0) 44 | 45 | # file admin. 46 | self._sub_Z = sub_Z 47 | self._element = Element.from_Z(self._sub_Z).symbol 48 | self._title = title 49 | self._box = np.array(box) 50 | self._lattice = Lattice(self._first_frame.get_cell().array) 51 | self._single_unit_cell_lattice = Lattice(self._single_unit_cell.get_cell().array) 52 | self._precision = precision 53 | 54 | # we need to relate each atom in the supercell to the single unit cell. 55 | self._supercell_mapping = None 56 | self._supercell_indices = None 57 | self._normalise_species() 58 | self._map_supercell_to_single_cell() 59 | 60 | 61 | def write_atom_files(self, output_dir: Path) -> None: 62 | """ 63 | Write the atom files for each frame in the trajectory. 64 | """ 65 | 66 | # make sure output_dir is a Path object. 67 | output_dir = Path(output_dir) 68 | output_dir.mkdir(exist_ok=True, parents=True) 69 | 70 | # gather header for all files. 71 | header = self._atoms() 72 | 73 | # loop over the trajectory of displacements and write the atom files. 74 | for file_num, displacements in enumerate(self.displacements(), 1): 75 | 76 | # combine the header and the displacements. 77 | full_file = header + self._format_displacements(displacements) 78 | 79 | # write the file. 80 | with open( 81 | output_dir / f'{self._title}_atoms_{file_num:02}.txt', 'w' 82 | ) as f: 83 | f.write(full_file) 84 | 85 | 86 | def displacements(self) -> np.ndarray: 87 | """ 88 | Calculate the displacements for each atom in the trajectory relative to 89 | the first frame. These feature in the Scatty program as (u1, u2, u3) 90 | where 91 | 92 | **u** = u1**a** + u2**b** + u3**c** 93 | """ 94 | 95 | # first get the coordinates of the first frame in frac coordinates. 96 | first_coords = self._first_frame.get_scaled_positions() 97 | 98 | # next get the coordinates of the trajectory in frac coordinates. 99 | trajectory_coordinates = np.stack([ 100 | atoms.get_scaled_positions() for atoms in self._trajectory 101 | ]) 102 | 103 | # hence compute the displacements in fractional coordinates. 104 | displacements = trajectory_coordinates - first_coords[np.newaxis, :, :] 105 | 106 | # return the displacements, taking into account the periodic boundary 107 | # conditions (using the minimum image convention). 108 | return displacements - np.round(displacements) 109 | 110 | 111 | def _format_displacements(self, displacements: np.ndarray) -> str: 112 | """ 113 | For a given frame of displacements, format the displacements for the 114 | Scatty program. 115 | """ 116 | 117 | # initialise the string. 118 | all_atoms = '' 119 | 120 | # template for the atoms block. 121 | template = ( 122 | 'ATOM {:<5d}{:<5d}{:<5d}{:<5d}' 123 | '{:>24.16E}{:>24.16E}{:>24.16E}' 124 | f' {self._element}\n' 125 | ) 126 | 127 | # loop over the atoms and format the displacements. 128 | zipped = zip( 129 | self._supercell_mapping, 130 | self._supercell_indices, 131 | displacements 132 | ) 133 | for id, cell, disp in zipped: 134 | all_atoms += template.format(id, *cell, *disp) 135 | 136 | # return the formatted displacements. 137 | return all_atoms 138 | 139 | 140 | def _atoms(self) -> None: 141 | """ 142 | Write the atoms block of the Scatty program. 143 | 144 | This will remain a constant for all [title]_atoms_[number].txt files. 145 | 146 | Title: The title of the simulation. 147 | Cell: A list of the lattice parameters a,b,c in Angstrom units, followed 148 | by a list of the cell angles alpha, beta, gamma in degrees. 149 | Box: The number of crystallographic unit cells in the supercell, given 150 | as three integers corresponding to the number of unit cells along 151 | the crystallographic axes. 152 | SITE: The fractional coordinates of the average position of a site in 153 | the crystallographic unit cell. Each site is given on a new line, 154 | with the keyword SITE followed by the x,y,z fractional coordinates. 155 | The number of SITE lines should equal the number of sites in the 156 | crystallographic unit cell. 157 | OCC: A list of element symbols, where each element symbol is followed by 158 | a real number specifying the average occupancy of the site by the 159 | given element. The element symbols and occupancies should be 160 | separated by spaces (e.g., OCC Na 0.5 Li 0.5). Neutron-scattering 161 | lengths and atomic X-ray form factors for the various elements are 162 | stored internally in Scatty. In general, the number of OCC lines 163 | must equal the number of SITE lines, and the OCC lines must be given 164 | in the same order as the SITE lines. For convenience, however, two 165 | exceptions to this are possible. First, if only one OCC line is 166 | given, Scatty will apply the same occupancy to all sites. Second, 167 | the OCC lines may optionally be omitted if only magnetic scattering 168 | is calculated; Scatty will then assume that each site is fully 169 | occupied by a single type of magnetic ion with magnetic properties 170 | specified by extra lines 171 | """ 172 | 173 | # get lattice parameters for single unit cell. 174 | single_cell = Lattice.from_parameters( 175 | *(self._first_frame.cell.lengths() / self._box), 176 | *self._first_frame.cell.angles() 177 | ) 178 | 179 | # first write the header. 180 | h = f'TITLE\t{self._title}\n' 181 | h += f'CELL {single_cell.a:.4f} {single_cell.b:.4f} {single_cell.c:.4f} ' 182 | h += f'{single_cell.alpha:.4f} {single_cell.beta:.4f} {single_cell.gamma:.4f}\n' 183 | h += f'BOX {self._box[0]} {self._box[1]} {self._box[2]}\n' 184 | 185 | # next follows the specification of the average position of the atoms 186 | # in the crystallographic unit cell. 187 | for atom in self._single_unit_cell.get_scaled_positions(): 188 | h += 'SITE{:>15.10f}{:>15.10f}{:>15.10f}\n'.format(*atom) 189 | 190 | # then the occupancies. 191 | for _ in self._single_unit_cell.get_atomic_numbers(): 192 | h += f'OCC {self._element} 1.0\n' 193 | 194 | # store the header. 195 | return h 196 | 197 | 198 | def _map_supercell_to_single_cell(self) -> None: 199 | """ 200 | Map the atoms in the supercell to the single unit cell. This should 201 | identify both the atom ID in the crystallographic unit cell and the 202 | indices of the supercell in which it resides. 203 | """ 204 | 205 | # first we determine the appropriate lattice for a single unit cell. 206 | single_cell = Lattice.from_parameters( 207 | *(self._first_frame.cell.lengths() / self._box), 208 | *self._first_frame.cell.angles() 209 | ) 210 | 211 | # we then jsue this as a change of basis matrix to determine the 212 | # fractional coordinates of the atoms in the supercell in terms of the 213 | # single unit cell. 214 | temp_atoms = self._first_frame.copy() 215 | temp_atoms.set_cell(single_cell.matrix, scale_atoms=False) 216 | 217 | self._supercell_mapping = single_cell.get_all_distances( 218 | temp_atoms.get_scaled_positions(), 219 | self._single_unit_cell.get_scaled_positions(), 220 | ).argmin(axis=1) + 1 221 | 222 | # hence go through each atom and subtract the fractional coordinates of 223 | # the atom in single unit cell which it mapped to, and then determine 224 | # the periodic image. 225 | single_unit_cell_coords = self._single_unit_cell.get_scaled_positions() 226 | supercell_transformed_coords = single_cell.get_fractional_coords( 227 | self._first_frame.get_positions() 228 | ) 229 | 230 | all_diffs = [] 231 | for coords, mapping_index in zip(supercell_transformed_coords, self._supercell_mapping): 232 | diff = np.round(coords-single_unit_cell_coords[mapping_index-1], 4).astype(np.uint) 233 | all_diffs.append(diff) 234 | self._supercell_indices = np.array(all_diffs) 235 | 236 | 237 | def _normalise_species(self) -> None: 238 | """ 239 | Relabel all atoms with the same element. 240 | """ 241 | self._single_unit_cell.numbers.fill(self._sub_Z) 242 | self._first_frame.numbers.fill(self._sub_Z) 243 | for atoms in self._trajectory: 244 | atoms.numbers.fill(self._sub_Z) -------------------------------------------------------------------------------- /chic/sort_sites.py: -------------------------------------------------------------------------------- 1 | """ 2 | 27.07.23 3 | @tcnicholas 4 | Functions for sorting sites. 5 | """ 6 | 7 | 8 | from enum import Enum 9 | from dataclasses import dataclass 10 | from typing import Callable, Dict, List, Optional 11 | 12 | from pymatgen.core import Structure 13 | from pymatgen.core.periodic_table import Element 14 | 15 | 16 | class SiteType(Enum): 17 | A = "a" 18 | B = "b" 19 | 20 | 21 | @dataclass 22 | class SortingMethod: 23 | name: str 24 | function: Callable[[Structure], List[List[str]]] 25 | 26 | 27 | InCHI = { 28 | "non_metals" : {"H", "He", "B", "C", "N", "O", "F", "Ne", 29 | "Si", "P", "S", "Cl", "Ar", "Ge", "As", "Se", 30 | "Br", "Kr", "Te", "I", "Xe", "At", "Rn"}, 31 | "non_metal_exceptions" : {"B", "Si","P"} 32 | } 33 | 34 | 35 | def sort_sites(structure: Structure, method: str) -> List[List[str]]: 36 | 37 | assert isinstance(structure, Structure), "structure must be a pymatgen.core.Structure instance" 38 | assert isinstance(method, str), "method must be a string" 39 | 40 | methods: Dict[str, SortingMethod] = { 41 | "all_atoms": SortingMethod("all_atoms", all_atoms), 42 | "mof": SortingMethod("mof", mof) 43 | } 44 | if method not in methods: 45 | raise ValueError(f"Unknown method: {method}. Available methods are: {methods.keys()}") 46 | return methods[method].function(structure) 47 | 48 | 49 | def all_atoms(structure: Structure) -> List[List[str]]: 50 | return [[e.symbol] for e in structure.composition.elements] 51 | 52 | 53 | def mof(structure: Structure) -> List[List[str]]: 54 | elements = structure.composition.elements 55 | atom_site = {SiteType.A: [], SiteType.B: []} 56 | for e in elements: 57 | site_type = get_site_type(structure, e) 58 | if site_type is not None: 59 | atom_site[site_type].append(e.symbol) 60 | else: 61 | print(f"Warning: {e.symbol} not assigned to a site type") 62 | return list(atom_site.values()) 63 | 64 | 65 | def get_site_type(structure: Structure, e: Element) -> Optional[SiteType]: 66 | if e.is_transition_metal or e.symbol in InCHI["non_metal_exceptions"] or \ 67 | ((e.is_alkali or e.is_alkaline) and e.symbol in {"Li", "Be"}): 68 | return SiteType.A 69 | if e.symbol == 'O' and is_ice(structure): 70 | return SiteType.A 71 | if e.symbol in InCHI["non_metals"]: 72 | return SiteType.B 73 | return None 74 | 75 | 76 | def is_ice(structure: Structure) -> bool: 77 | return structure.composition.reduced_formula == "H2O" 78 | 79 | 80 | def create_site_type_lookup(site_types: List[List[str]]) -> dict: 81 | lookup = {} 82 | for i, sublist in enumerate(site_types): 83 | for item in sublist: 84 | lookup[item] = i 85 | return lookup -------------------------------------------------------------------------------- /chic/tidy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 27.07.23 3 | @tcnicholas 4 | Functions for tidying up structures. 5 | """ 6 | 7 | 8 | from pymatgen.core import Structure 9 | from pymatgen.core.periodic_table import Element 10 | 11 | 12 | def unit_occupancy(struct: Structure): 13 | """ 14 | Set all atom occupancies to 1. 15 | 16 | :param struct: structure to modify. 17 | """ 18 | for i,a in enumerate(struct): 19 | d = a.species.as_dict() 20 | e = list(d.keys())[0] 21 | if d[e] != 1: 22 | struct.replace(i, Element(e)) 23 | 24 | 25 | def no_deuterium(struct: Structure): 26 | """ 27 | Replace deuterium in structure with hydrogen. 28 | 29 | :param struct: structure to modify. 30 | """ 31 | ds = [i for i,a in enumerate(struct) if a.specie.symbol == "D"] 32 | for d in ds: 33 | struct.replace(d, Element("H")) -------------------------------------------------------------------------------- /chic/vasp.py: -------------------------------------------------------------------------------- 1 | """ 2 | 20.06.23 3 | @tcnicholas 4 | Handle VASP input and output. 5 | """ 6 | 7 | from typing import Union 8 | 9 | import ase 10 | import numpy as np 11 | from ase.io.vasp import _symbol_count_from_symbols 12 | 13 | from .templates import ZIF8_CH3, ZIF8_H 14 | 15 | 16 | def lattice_to_string(atoms, fmt=' %21.16f'): 17 | """ 18 | Convert unit cell into POSCAR format. 19 | """ 20 | lattice = '' 21 | for vec in atoms.get_cell(): 22 | for el in vec: 23 | lattice += fmt % el 24 | lattice += '\n' 25 | return lattice 26 | 27 | 28 | def symbol_count_to_string(sc): 29 | """ 30 | """ 31 | symbol_string = '' 32 | for sym, _ in sc: 33 | symbol_string += ' {:3s}'.format(sym) 34 | symbol_string += '\n' 35 | for _, count in sc: 36 | symbol_string += ' {:3d}'.format(count) 37 | return symbol_string + '\n' 38 | 39 | 40 | def write_vasp( 41 | poscar_filename: str, 42 | atom_information_filename: str, 43 | atoms: ase.Atoms, 44 | template: Union[ZIF8_CH3, ZIF8_H], 45 | name: str = None, 46 | atom_data: bool = True 47 | ): 48 | """ 49 | Write structure in POSCAR format, whilst maintaining a clear mapping between 50 | identifiable atom types in the ligands. That way separate atom types can be 51 | preserved in the MLP models (if desired). 52 | 53 | :param poscar_filename: name of POSCAR file to write. 54 | :param atom_information_filename: name of file to write atom information to. 55 | :param name: name of structure. 56 | :param atoms: ASE atoms object. 57 | :param template: template to use for decorating the net (H or CH3). 58 | :return: None. 59 | 60 | Notes 61 | ----- 62 | The first line is a comment line reserved for the user to detail their 63 | simulation. 64 | The second line is a scaling factor that will be applied to the unscaled 65 | lattice vectors provided on the following three lines. 66 | """ 67 | 68 | # gather all coordinates and atom types. 69 | coord = atoms.get_scaled_positions() 70 | atom_type_symbol = np.array([ 71 | template.default_atom_types[a] for a in atoms.arrays['type'] 72 | ]) 73 | 74 | # get all chemical elements in alphabetical order. 75 | symbols = np.array(atoms.get_chemical_symbols().copy()) 76 | all_elements = sorted(np.unique(symbols)) 77 | sc = _symbol_count_from_symbols(sorted(symbols)) 78 | atom_data = np.vstack([ 79 | atoms.arrays['id'], 80 | atoms.arrays['mol-id'], 81 | atoms.arrays['type'], 82 | atom_type_symbol 83 | ]).T 84 | 85 | # generate file header. 86 | file_str = ' '.join(x[0] for x in sc) + '\n' if name is None else name+'\n' 87 | file_str += '1.0000000000000000\n' 88 | file_str += lattice_to_string(atoms) 89 | file_str += symbol_count_to_string(sc) 90 | 91 | # write (direct) coordinates and also gather the specific atom details into 92 | # an ordered array that matches the VASP POSCAR file. 93 | stored_labels = [] 94 | file_str += 'Direct\n' 95 | for sym in all_elements: 96 | ix = [i for i,s in enumerate(symbols) if s==sym] 97 | stored_labels.append(atom_data[ix]) 98 | for atom in coord[ix]: 99 | for dcoord in atom: 100 | file_str += ' %19.16f' % dcoord 101 | file_str += '\n' 102 | 103 | stored_labels = np.vstack(stored_labels) 104 | 105 | with open(poscar_filename, 'w') as file: 106 | file.write(file_str) 107 | 108 | header = 'atom_id mol_id, atom_type, symbol' 109 | np.savetxt( 110 | atom_information_filename, 111 | stored_labels, 112 | header=header, 113 | fmt='%s' 114 | ) 115 | 116 | 117 | def kpoints_gamma(filename: str) -> None: 118 | """ 119 | Write KPOINTS file for a gamma-point calculation. 120 | 121 | :param filename: name of KPOINTS file to write. 122 | :return: None. 123 | """ 124 | 125 | kpoints = 'Automatic mesh\n' 126 | kpoints += '0 ! number of k-points = 0 ->automatic generation scheme\n' 127 | kpoints += 'Gamma ! generate a Gamma centered grid\n' 128 | kpoints += '1 1 1 ! subdivisions N_1, N_2 and N_3 along recipr. l. vectors\n' 129 | kpoints += '0. 0. 0. ! optional shift of the mesh (s_1, s_2, s_3)\n' 130 | 131 | with open(filename, 'w') as file: 132 | file.write(kpoints) -------------------------------------------------------------------------------- /chic/vector.py: -------------------------------------------------------------------------------- 1 | """ 2 | 07.10.23 3 | @tcnicholas 4 | Vector functions. 5 | """ 6 | 7 | 8 | import numpy as np 9 | 10 | 11 | def unit(vector): 12 | """ 13 | Return the unit vector of a given vector. 14 | 15 | Args 16 | ---- 17 | vector: np.ndarray 18 | Vector to transform to unit vector. 19 | """ 20 | return vector / np.sqrt(np.sum(np.square(vector))) 21 | 22 | 23 | def compute_angle(vector1, vector2): 24 | """ 25 | Calculate the angle between two vectors (in radians). 26 | 27 | Args 28 | ---- 29 | vector1: np.ndarray 30 | Vector from middle point to terminal point 1. 31 | 32 | vector2: np.ndarray 33 | Vector from middle point to terminal point 2. 34 | """ 35 | 36 | d = np.dot(unit(vector1), unit(vector2)) 37 | 38 | # np.clip() to be included in numba v0.54 so can update then accordingly. 39 | if d < -1.0: 40 | d = -1.0 41 | elif d > 1.0: 42 | d = 1.0 43 | 44 | return np.arccos(d) 45 | 46 | 47 | def random_vector( 48 | rand1: float, 49 | rand2: float, 50 | norm: bool = False 51 | ) -> np.ndarray(3): 52 | """ 53 | Generate random vector. 54 | 55 | :param rand1: random number 1. 56 | :param rand2: random number 2. 57 | :param norm: whether to normalise the vector. 58 | :return: random vector. 59 | """ 60 | 61 | # Generate two random variables. 62 | phi = rand1 * 2 * np.pi 63 | z = rand2 * 2 - 1 64 | 65 | # Determine final unit vector. 66 | z2 = z * z 67 | x = np.sqrt(1 - z2) * np.sin(phi) 68 | y = np.sqrt(1 - z2) * np.cos(phi) 69 | 70 | v = np.array([x,y,z]) 71 | if norm: 72 | return v / np.linalg.norm(v) 73 | return v 74 | 75 | 76 | def renormalize_matrix_svd(R): 77 | """ 78 | Renormalize a rotation matrix using SVD. I found this to work better for 79 | some of the cases where numerical inaccuracies were causing problems. 80 | 81 | :param R: rotation matrix. 82 | :return: renormalized rotation matrix. 83 | """ 84 | u, s, vh = np.linalg.svd(R, full_matrices=True) 85 | return np.dot(u, vh) 86 | 87 | 88 | def align_matrix(f,t): 89 | """ 90 | Rotation matrix to align v(i) along v(f). 91 | See: T. Möller, J. F. Hughes; J. Graphics Tools, 1999, 4, 1--4. 92 | 93 | f and t should be numpy arrays. 94 | """ 95 | 96 | # Separate cases for vectors alligned. 97 | # (1) Opposite directions: 98 | if np.allclose(f, -1 * t): 99 | return np.array([[-1,0,0],[0,-1,0],[0,0,-1]], dtype=np.float128) 100 | # (2) Same direction (i.e. do nothing). 101 | elif np.allclose(f, t): 102 | return np.array([[1,0,0],[0,1,0],[0,0,1]], dtype=np.float128) 103 | 104 | v = np.cross(t, f).astype(np.float128) 105 | c = np.dot(f, t).astype(np.float128) 106 | h = (1 - c) / (1 - c**2) 107 | vx, vy, vz = v 108 | 109 | matrix = np.array([ [c + h*vx**2, h*vx*vy - vz, h*vx*vz + vy], 110 | [h*vx*vy+vz, c+h*vy**2, h*vy*vz-vx ], 111 | [h*vx*vz - vy, h*vy*vz + vx, c+h*vz**2 ] ], dtype=np.float64) 112 | 113 | return renormalize_matrix_svd(matrix) 114 | 115 | 116 | def rotate_vector(v, axis, theta): 117 | """ 118 | Rotate vector v around axis by theta degrees. 119 | """ 120 | axis = axis / np.linalg.norm(axis) 121 | v_rot = np.cos(np.radians(theta)) * v + np.sin(np.radians(theta)) * np.cross(axis, v) + (1 - np.cos(np.radians(theta))) * np.dot(axis, v) * axis 122 | return v_rot -------------------------------------------------------------------------------- /chic/xyz.py: -------------------------------------------------------------------------------- 1 | """ 2 | 22.06.23 3 | @tcnicholas 4 | Input and output for xyz files. 5 | """ 6 | 7 | 8 | from typing import Dict 9 | 10 | from ase.io import read 11 | 12 | from .utils import kcalmol2eV 13 | 14 | 15 | def lammps_to_extxyz( 16 | filename: str, 17 | dump_filename: str, 18 | mofff_computes: bool = False, 19 | add_info: Dict = {}, 20 | write_cif: bool = False, 21 | ) -> None: 22 | """ 23 | Read in LAMMPS dump file and write to extended xyz file. 24 | """ 25 | 26 | # Read in LAMMPS dump file. 27 | atoms = read(dump_filename, format='lammps-dump-text', index=-1) 28 | atoms.info |= add_info 29 | 30 | # If using MOF-FF, extract the MOF-FF computed energies. 31 | columns = ['symbols', 'positions'] 32 | if mofff_computes: 33 | 34 | mofff_headers = [ 35 | 'energy', 36 | 'energy_pair', 37 | 'energy_bond', 38 | 'energy_angle', 39 | 'energy_dihedral', 40 | 'energy_improper', 41 | 'energy_kspace', 42 | ] 43 | 44 | atoms.arrays["forces"] = kcalmol2eV(atoms.get_forces()) + 0 45 | for i, header in enumerate(mofff_headers, 1): 46 | atoms.arrays[header] = kcalmol2eV(atoms.arrays.pop(f'c_{i}')) 47 | columns += mofff_headers + ['forces'] 48 | 49 | # Write to extended xyz file. 50 | atoms.write(filename, format='extxyz', columns=columns, write_results=False) 51 | 52 | if write_cif: 53 | atoms.write(str(filename).replace('.xyz', '.cif'), format='cif') 54 | -------------------------------------------------------------------------------- /chic/zif.py: -------------------------------------------------------------------------------- 1 | """ 2 | 13.06.23 3 | @tcnicholas 4 | Building units for decorating nets. 5 | """ 6 | 7 | from typing import List 8 | from dataclasses import dataclass, field 9 | 10 | from .utils import replace_a_and_b 11 | 12 | 13 | @dataclass 14 | class Zinc: 15 | """ 16 | Store explicit look-up indexing for a given Zinc atom. 17 | """ 18 | # molecule label. 19 | mol_id: int = 0 20 | 21 | # atom ID this Zinc atom. 22 | atom_id: int = 0 23 | 24 | # molecule IDs of imidazole rings bound. 25 | Im1: int = 0 26 | Im2: int = 0 27 | Im3: int = 0 28 | Im4: int = 0 29 | 30 | # for each Im, also if it is bound to N_a or N_b. 31 | Im1_N: list = field(default_factory=list) 32 | Im2_N: list = field(default_factory=list) 33 | Im3_N: list = field(default_factory=list) 34 | Im4_N: list = field(default_factory=list) 35 | 36 | # bond ids. 37 | BondIDs: list = field(default_factory=list) 38 | 39 | # store dictionaries which point to: 40 | # bound imidazolate mol id : bonds ids. 41 | Bond2Im: dict = field(default_factory=dict) 42 | Angle2Im: dict = field(default_factory=dict) 43 | Dihedral2Im: dict = field(default_factory=dict) 44 | OutOfPlane2Im: dict = field(default_factory=dict) 45 | 46 | 47 | def bonds(self): 48 | """ 49 | Spit out Zn-N bonds. 50 | """ 51 | return [ [self.atom_id, self.Im1_N[0], ("N", "Zn")], 52 | [self.atom_id, self.Im2_N[0], ("N", "Zn")], 53 | [self.atom_id, self.Im3_N[0], ("N", "Zn")], 54 | [self.atom_id, self.Im4_N[0], ("N", "Zn")]] 55 | 56 | 57 | @property 58 | def bound_im(self): 59 | """ 60 | Return list of molecule IDs and the particular N ID (and a or b) 61 | of the bound imidazolate. 62 | 63 | [ ( mol-ID, [nitrogen atom ID, "a" or "b"] ), ] 64 | """ 65 | return [(self.Im1, self.Im1_N), (self.Im2, self.Im2_N), 66 | (self.Im3, self.Im3_N), (self.Im4, self.Im4_N)] 67 | 68 | 69 | @property 70 | def bound_im_mol_ids(self) -> List[int]: 71 | """ 72 | List of molecule IDs of the bound imidazolates. 73 | 74 | :return: list of molecule IDs of the bound imidazolates. 75 | """ 76 | return [self.Im1, self.Im2, self.Im3, self.Im4] 77 | 78 | 79 | @property 80 | def bound_im_a_or_b(self): 81 | return [self.Im1_N[1], self.Im2_N[1], self.Im3_N[1], self.Im4_N[1]] 82 | 83 | 84 | def a_or_b(self, im_molID): 85 | """ 86 | Helper function to get N a or b for a given molID. 87 | """ 88 | bound = zip(self.bound_im_molID, self.bound_im_a_or_b) 89 | return [a_or_b for ID, a_or_b in bound if ID==im_molID][0] 90 | 91 | 92 | def which_im(self, im_molID): 93 | """ 94 | Find which Im_i attribute of the class corresponds to the given 95 | imidazolate molecule ID. 96 | """ 97 | all_ims = zip(self.bound_im_molID, ["Im1","Im2","Im3","Im4"]) 98 | return [im for ID, im in all_ims if ID==im_molID] 99 | 100 | 101 | 102 | @dataclass 103 | class Imidizolate: 104 | """ 105 | Store explicit look-up indexing for each atom type in the imidazolate ring. 106 | """ 107 | 108 | # molecule label. 109 | mol_id: int = 0 110 | atom_ids: list = field(default_factory=list) 111 | atom_labels: list = field(default_factory=list) 112 | 113 | # bound to zinc atoms. 114 | Zn_a: int = 0 115 | Zn_b: int = 0 116 | 117 | # topology ids. 118 | BondIDs: list = field(default_factory=list) 119 | AngleIDs: list = field(default_factory=list) 120 | DihedralIDs: list = field(default_factory=list) 121 | 122 | 123 | def atom_id_by_label(self, label: str) -> int: 124 | """ 125 | Return the atom ID for a given atom label. 126 | """ 127 | return self.atom_ids[self.atom_labels.index(label)] 128 | 129 | 130 | def topology_indices(self, template, topology_type='bonds'): 131 | """ 132 | Return list of bonds in the imidazolate ring. 133 | """ 134 | all_bonds = [] 135 | values = getattr(template, f'{topology_type}_by_index') 136 | for bond in values: 137 | ids = [self.atom_ids[i] for i in bond] 138 | labels = tuple([ 139 | replace_a_and_b(self.atom_labels[i]) for i in bond 140 | ]) 141 | all_bonds.append([*ids, labels]) 142 | return all_bonds 143 | 144 | 145 | def topology_indices_2body(self, 146 | template, 147 | a_or_b: int, 148 | topology_type='angles', 149 | ): 150 | """ 151 | Return list of angles in the imidazolate ring involved in 2-body 152 | interactions. 153 | 154 | :param template: template object. 155 | :param a_or_b: 0 or 1, for N_a or N_b. 156 | :param topology_type: topology type. 157 | 158 | """ 159 | all_angles = [] 160 | values = getattr(template, f'{topology_type}_2body_by_index')[a_or_b] 161 | for bond in values: 162 | ids = [self.atom_ids[i] for i in bond] 163 | labels = tuple([ 164 | replace_a_and_b(self.atom_labels[i]) for i in bond 165 | ] + ['Zn']) 166 | all_angles.append([*ids, labels]) 167 | return all_angles 168 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd -------------------------------------------------------------------------------- /docs/source/_static/custom.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | font-size: 3em; 3 | text-align: center; 4 | /* pad on top, but not on bottom */ 5 | padding-top: 0.5em; 6 | padding-bottom: 0; 7 | border-bottom: 0; 8 | } 9 | 10 | /* margin highlights left and right by 5% */ 11 | .highlight { 12 | margin-left: 7%; 13 | margin-right: 7%; 14 | width: 86%; 15 | border-radius: 10px; 16 | } 17 | 18 | /* squish code blocks so that everything looks a bit prettier */ 19 | article[role="main"] .highlight pre { 20 | line-height: 1.3; 21 | } 22 | 23 | /* unless child of "input-area" */ 24 | .input_area .highlight { 25 | margin-left: 0; 26 | margin-right: 0; 27 | width: 100%; 28 | border-radius: 0; 29 | } 30 | 31 | /* center all children of viz divs */ 32 | /* and don't allow highlighting when clicked */ 33 | .viz { 34 | display: flex; 35 | justify-content: center; 36 | width: 100%; 37 | } 38 | 39 | img { 40 | margin-top: 30px; 41 | margin-bottom: 20px; 42 | } 43 | 44 | /* align content vertically */ 45 | .info-card { 46 | display: flex; 47 | justify-content: center; /* Align horizontal */ 48 | align-items: center; /* Align vertical */ 49 | } 50 | 51 | /* align text center in each cell */ 52 | .table-wrapper td { 53 | text-align: center; 54 | } 55 | 56 | /* anything that lives in a span wrapped by a .sphinx-codeautolink-a */ 57 | .sphinx-codeautolink-a span { 58 | text-decoration: underline; 59 | text-decoration-color: var(--color-api-name); 60 | } 61 | /* make it obviously clickable on hover by turning bold */ 62 | .sphinx-codeautolink-a span:hover { 63 | font-weight: bold; 64 | } 65 | -------------------------------------------------------------------------------- /docs/source/_static/homepage-grab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/docs/source/_static/homepage-grab.png -------------------------------------------------------------------------------- /docs/source/_static/mep-nodes.data: -------------------------------------------------------------------------------- 1 | # 'net' generated by CHIC (2024-05-05 21:49:10.040247) 2 | 3 | 46 atoms 4 | 92 bonds 5 | 134 angles 6 | 0 dihedrals 7 | 0 impropers 8 | 9 | 1 atom types 10 | 1 bond types 11 | 2 angle types 12 | 0 dihedral types 13 | 0 improper types 14 | 15 | # Average bond length information: 16 | # type 1: 3.188 Å 17 | 18 | # Average bond angle information: 19 | # type 1: 108.120 degrees 20 | # type 2: 125.884 degrees 21 | 22 | 0.0 13.705 xlo xhi 23 | 0.0 13.705 ylo yhi 24 | 0.0 13.705 zlo zhi 25 | -------------------------------------------------------------------------------- /docs/source/_static/mep-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/docs/source/_static/mep-nodes.png -------------------------------------------------------------------------------- /docs/source/_static/mep.data: -------------------------------------------------------------------------------- 1 | # 'MEP' generated by CHIC (2024-05-05 12:40:36.512531) 2 | 3 | 138 atoms 4 | 184 bonds 5 | 198 angles 6 | 0 dihedrals 7 | 0 impropers 8 | 9 | 2 atom types 10 | 1 bond types 11 | 4 angle types 12 | 0 dihedral types 13 | 0 improper types 14 | 15 | # Average bond length information: 16 | # type 1: 1.609 Å 17 | 18 | # Average bond angle information: 19 | # type 1: 109.492 degrees 20 | # type 2: 179.007 degrees 21 | # type 3: 166.402 degrees 22 | # type 4: 146.246 degrees 23 | 24 | 0.0 13.705 xlo xhi 25 | 0.0 13.705 ylo yhi 26 | 0.0 13.705 zlo zhi 27 | 28 | Masses 29 | 30 | 1 15.9994 # O 31 | 2 28.0855 # Si 32 | -------------------------------------------------------------------------------- /docs/source/_static/mep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/docs/source/_static/mep.png -------------------------------------------------------------------------------- /docs/source/_static/scripts/dihedral.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Dict 2 | from dataclasses import dataclass 3 | from itertools import combinations 4 | 5 | import numpy as np 6 | from networkx import all_shortest_paths 7 | from chic.atomic_cluster import AtomicCluster 8 | 9 | class DihedralAnalysis: 10 | """ 11 | Identifies the carbonate groups on a 1,3-BDC linker and computes the 12 | dihedral angles between the carbonate and the ring. Assumes the molecular 13 | graph for the building unit is reasonable (CrystalNN neighbour list is 14 | likely more reliable for this task). 15 | 16 | Attributes: 17 | None 18 | 19 | Methods: 20 | get_coord_by_ix(unit: AtomicCluster, ix: int) -> np.ndarray: Retrieves 21 | coordinate by index. 22 | compute_dihedral(A, B, C, D) -> float: Computes the dihedral angle 23 | between points A, B, C, and D. 24 | analyse_ligand(unit: AtomicCluster) -> Dict[str, np.ndarray]: Analyses 25 | ligands in the building unit, computing dihedrals for carbonates. 26 | 27 | Inner Classes: 28 | Carbonate: Represents a carbonate group with methods to check carbon 29 | presence and compute dihedrals. 30 | """ 31 | 32 | @staticmethod 33 | def get_coord_by_ix(unit: AtomicCluster, ix: int) -> np.ndarray: 34 | """ 35 | Retrieves coordinate by index. 36 | 37 | Arguments: 38 | unit (AtomicCluster): The building unit. 39 | ix (int): The index to retrieve. 40 | 41 | Returns: 42 | np.ndarray: The coordinate. 43 | """ 44 | ix_ = np.argwhere(np.array(unit.site_indices, dtype=int) == ix)[0][0] 45 | return unit.cart_coords[ix_] 46 | 47 | @staticmethod 48 | def compute_dihedral( 49 | A: np.ndarray, B: np.ndarray, C: np.ndarray, D: np.ndarray 50 | ) -> float: 51 | """ 52 | Computes the dihedral angle between points A, B, C, and D. 53 | 54 | Arguments: 55 | A (np.ndarray): The first point. 56 | B (np.ndarray): The second point. 57 | C (np.ndarray): The third point. 58 | D (np.ndarray): The fourth point. 59 | 60 | Returns: 61 | float: The dihedral angle in degrees. 62 | """ 63 | BA, BC = A - B, C - B 64 | CB, CD = -BC, D - C 65 | n1, n2 = np.cross(BA, BC), np.cross(CB, CD) 66 | n1 /= np.linalg.norm(n1) 67 | n2 /= np.linalg.norm(n2) 68 | d = np.dot(n1, n2) 69 | sign = 1 if np.dot(np.cross(BA, CD), BC) >= 0 else -1 70 | return sign * np.arccos(d) * 180 / np.pi 71 | 72 | @dataclass 73 | class Carbonate: 74 | """ 75 | Represents a carbonate group with methods to check carbon presence and 76 | compute dihedrals. 77 | 78 | C(3) O(1) 79 | \ / 80 | C(2) --- C(1) 81 | \ 82 | O(2) 83 | 84 | Attributes: 85 | o1 (int): The index of the first oxygen atom. 86 | c1 (int): The index of the first carbon atom. 87 | o2 (int): The index of the second oxygen atom. 88 | c2 (int): The index of the second carbon atom. 89 | c3 (int): The index of the third carbon atom. 90 | 91 | Methods: 92 | has_c(ix: int) -> bool: Checks if given index ix is a carbon in the 93 | carbonate. 94 | dihedrals(bu: AtomicCluster) -> Tuple[float, float]: Computes and 95 | returns dihedral angles for the carbonate based on building unit 96 | provided. 97 | """ 98 | o1: int 99 | c1: int 100 | o2: int 101 | c2: int = None 102 | c3: int = None 103 | 104 | def has_c(self, ix: int) -> bool: 105 | """ 106 | Checks if given index ix is a carbon in the carbonate. 107 | 108 | Arguments: 109 | ix (int): The index to check. 110 | 111 | Returns: 112 | bool: True if the index is a carbon in the carbonate. 113 | """ 114 | return ix==self.c1 115 | 116 | def dihedrals(self, unit: AtomicCluster) -> Tuple[float, float]: 117 | """ 118 | Computes and returns dihedral angles for the carbonate based on 119 | building unit provided. 120 | 121 | Arguments: 122 | unit (AtomicCluster): The building unit. 123 | 124 | Returns: 125 | Tuple[float, float]: The dihedral angles in degrees. 126 | """ 127 | coords = lambda idx: DihedralAnalysis.get_coord_by_ix(unit, idx) 128 | dh1 = DihedralAnalysis.compute_dihedral( 129 | coords(self.o1), coords(self.c1), 130 | coords(self.c2), coords(self.c3) 131 | ) 132 | dh2 = DihedralAnalysis.compute_dihedral( 133 | coords(self.o2), coords(self.c1), 134 | coords(self.c2), coords(self.c3) 135 | ) 136 | return dh1, dh2 137 | 138 | def analyse_ligand(self, unit: AtomicCluster) -> Dict[str, np.ndarray]: 139 | """ 140 | Analyzes ligands in a given building unit, computing dihedrals for 141 | carbonates. 142 | 143 | Arguments: 144 | unit (AtomicCluster): The building unit. 145 | 146 | Returns: 147 | Dict[str, np.ndarray]: A dictionary with dihedral angles for each 148 | carbonate. 149 | """ 150 | 151 | # get unique combinations of oxygen atoms to search for paths between. 152 | oxygen_combinations = combinations([ 153 | x for s,x in zip(unit._symbols,unit.site_indices) if s=='O'], r=2 154 | ) 155 | 156 | backbone = [] 157 | carbonates = [] 158 | for n1, n2 in oxygen_combinations: 159 | 160 | # access the molecular graph automatically found by chic. 161 | p = list(all_shortest_paths(unit.graph, n1, n2)) 162 | 163 | if len(p) == 1: 164 | p = p[0] 165 | 166 | # this is the path between oxygens on the same carbonate group. 167 | if len(p) == 3: 168 | carbonates.append(self.Carbonate(*p)) 169 | 170 | # this is a linking path between the two carbonte groups. 171 | else: 172 | backbone.append(tuple(p[1:-1])) 173 | 174 | # each 1,3-BDC ligand should have two carbnate groups, and one obvious 175 | # shortest path passing through C(2) of the ring. 176 | assert len(carbonates)==2 and len(set(backbone))==1, "Analysis failed." 177 | backbone = list(backbone)[0] 178 | 179 | # Assign additional carbon indices based on backbone analysis 180 | for carbonate in carbonates: 181 | if carbonate.has_c(backbone[0]): 182 | carbonate.c2, carbonate.c3 = backbone[1], backbone[2] 183 | else: 184 | carbonate.c2, carbonate.c3 = backbone[-2], backbone[-3] 185 | 186 | # Compute dihedrals for each carbonate 187 | dihedrals = [carbonate.dihedrals(unit) for carbonate in carbonates] 188 | dihedrals = [sorted(d, key=abs, reverse=True) for d in dihedrals] 189 | 190 | return { 191 | 'carboxylate_a': np.round(dihedrals[0],3), 192 | 'carboxylate_b': np.round(dihedrals[1],3) 193 | } -------------------------------------------------------------------------------- /docs/source/_static/scripts/viz.py: -------------------------------------------------------------------------------- 1 | from load_atoms import view 2 | from IPython.core.display import HTML 3 | from pymatgen.io.ase import AseAtomsAdaptor 4 | from chic.atomic_cluster import AtomicCluster 5 | 6 | def view_molecule(cluster: AtomicCluster) -> HTML: 7 | """ 8 | Convert the building unit to an ASE Atoms object and inspect it with 9 | load-atoms visaulisation tool. 10 | 11 | Arguments: 12 | cluster (AtomicCluster): the building unit to inspect. 13 | 14 | Returns: 15 | The HTML visualisation. 16 | """ 17 | molecule = AseAtomsAdaptor.get_atoms(cluster.to_molecule()) 18 | return view(molecule, show_bonds=True) -------------------------------------------------------------------------------- /docs/source/_static/visualisations/chem_commun_2023.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/docs/source/_static/visualisations/chem_commun_2023.gif -------------------------------------------------------------------------------- /docs/source/_static/visualisations/chem_commun_2023.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/docs/source/_static/visualisations/chem_commun_2023.jpeg -------------------------------------------------------------------------------- /docs/source/_static/visualisations/chem_mater_2021.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/docs/source/_static/visualisations/chem_mater_2021.jpeg -------------------------------------------------------------------------------- /docs/source/_static/visualisations/chem_sci_2020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/docs/source/_static/visualisations/chem_sci_2020.png -------------------------------------------------------------------------------- /docs/source/_static/visualisations/crystengcomm_2024.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tcnicholas/chic/e018d24c0751faad0b6a5dd482ea88e32ddb4feb/docs/source/_static/visualisations/crystengcomm_2024.gif -------------------------------------------------------------------------------- /docs/source/api/atomic-clusters.rst: -------------------------------------------------------------------------------- 1 | Atomic clusters 2 | =============== 3 | 4 | The main information on the nodes and linkers in :code:`chic` is exposed by 5 | the :class:`AtomicCluster ` class: 6 | 7 | .. autoclass:: chic.atomic_cluster.AtomicCluster() 8 | :members: -------------------------------------------------------------------------------- /docs/source/api/net.rst: -------------------------------------------------------------------------------- 1 | Net 2 | === 3 | 4 | The main entry point for decorating nets with :code:`chic` is the 5 | :class:`Net ` class: 6 | 7 | .. autoclass:: chic.Net 8 | :members: 9 | :show-inheritance: -------------------------------------------------------------------------------- /docs/source/api/structure.rst: -------------------------------------------------------------------------------- 1 | Structure 2 | ========= 3 | 4 | The main entry point for coarse-graining with :code:`chic` is the 5 | :class:`Structure ` class: 6 | 7 | .. autoclass:: chic.Structure() 8 | :members: 9 | :special-members: __getitem__, __iter__, __len__ 10 | -------------------------------------------------------------------------------- /docs/source/case-studies/cleaning.rst: -------------------------------------------------------------------------------- 1 | Cleaning structures 2 | =================== 3 | 4 | :code:`chic` can be used to "clean-up" disordered structures. Here, I show how 5 | the thermal disorder in the methyl-substituted imidazolate molecules in a ZIF 6 | can be averaged to single positions. 7 | 8 | In this case study, I will use the :code:`load_atoms` Python package for 9 | visualising the molecules. You can instsall it easily with 10 | :code:`pip install load-atoms`. Below is a helper function: 11 | 12 | .. dropdown:: viz.py 13 | 14 | .. literalinclude:: ../_static/scripts/viz.py 15 | 16 | First, let's load the ZIF-8 structure. 17 | 18 | >>> from chic import Structure 19 | >>> from viz import view_molecule 20 | >>> mof = Structure.from_cif("ZIF-8-sod.cif") 21 | >>> mof.remove_sites_by_symbol("O") 22 | >>> mof.get_neighbours_crystalnn() 23 | >>> mof.find_atomic_clusters() 24 | 25 | Let's visualise the cluster. 26 | 27 | >>> disordered_linker = mof.atomic_clusters[("b", 1)] 28 | >>> view_molecule(disordered_linker) 29 | 30 | .. raw:: html 31 | :file: ../_static/visualisations/mIm-disordered.html 32 | 33 | We can "fix" this by averaging pairs of H atoms within a distance of 0.9 Å of 34 | each other. Note, after inserting/deleting atoms, we need to force a rebuild of 35 | the neighbourlist. It is therefore advised to perform structral cleaning before 36 | further analysis. 37 | 38 | >>> mof.average_element_pairs("H", rmax=0.9) 39 | >>> mof.get_neighbours_crystalnn(force=True) 40 | >>> mof.find_atomic_clusters() 41 | >>> ordered_linker = mof.atomic_clusters[("b", 1)] 42 | >>> view_molecule(ordered_linker) 43 | 44 | .. raw:: html 45 | :file: ../_static/visualisations/mIm-clean.html 46 | 47 | We can write the ordered structure back to a CIF using Pymatgen functionality 48 | directly. 49 | 50 | >>> mof.to("ZIF-8-sod-ordered.cif"); -------------------------------------------------------------------------------- /docs/source/case-studies/coarse-graining.rst: -------------------------------------------------------------------------------- 1 | Coarse-graining 2 | =============== 3 | 4 | Coarse-graining MOFs was at the heart of the chic development. This can be 5 | performed with just a few lines of code. 6 | 7 | First, we can load the structure and remove the oxygen from the pores. 8 | 9 | >>> from chic import Structure 10 | >>> struct = Structure.from_cif("ZIF-8-sod.cif") 11 | >>> struct.remove_sites_by_symbol("O") 12 | 13 | .. raw:: html 14 | :file: ../_static/zif8.html 15 | 16 | Then, we can identify connected atoms, group them into atomic clusters (i.e. 17 | nodes and linkers), and reduce the structure to it's underyling net: 18 | 19 | >>> struct.get_neighbours_crystalnn() 20 | >>> struct.find_atomic_clusters() 21 | >>> struct.get_coarse_grained_net() 22 | 23 | .. raw:: html 24 | :file: ../_static/zif8-cg.html -------------------------------------------------------------------------------- /docs/source/case-studies/decorating.rst: -------------------------------------------------------------------------------- 1 | Decorating 2 | ========== 3 | 4 | With knowledge of the underlying net, it is also possible reverse the 5 | coarse-graining process, and "decorate" it with different molecules. The focus 6 | so far has been on zeolitic imidazolate frameworks (ZIFs), however it is 7 | generalisable, in principle. 8 | 9 | -------------------------------------------------------------------------------- /docs/source/case-studies/dihedrals.rst: -------------------------------------------------------------------------------- 1 | Dihedral angle analysis 2 | ======================= 3 | 4 | :code:`chic` can be used to find the organic linkers to assist structural 5 | analysis. Here, I show how we can calculate dihedral angles for a MOF with 6 | 1,3-BDC linkers. 7 | 8 | .. raw:: html 9 | :file: ../_static/1,3-BDC.html 10 | 11 | Here, I've included a quick analysis script that can take a 12 | :class:`AtomicCluster ` object as an 13 | argument. Note in particular how I make use of the :code:`AtomicCluster.graph` 14 | molecular graph object in order to traverse the shortest paths between oxygens 15 | in the molecule. 16 | 17 | .. dropdown:: dihedral.py 18 | 19 | .. literalinclude:: ../_static/scripts/dihedral.py 20 | 21 | We can load structure in the usual way and search for nodes and linkers. This 22 | particular MOF can be downloaded from the Cambridge Structural Database (CDC), 23 | with RefCode `JOLFEZ `_ 24 | 25 | >>> from chic import Structure 26 | >>> mof = Structure.from_cif("JOLFEZ.cif") 27 | >>> mof.get_neighbours_crystalnn() 28 | >>> mof.find_atomic_clusters() 29 | >>> mof.get_coarse_grained_net() 30 | 31 | First we can select a linker molecule from the atomic_clusters dictionary, where 32 | the linkers will default to "B sites" (and zinc nodes will be "A sites"). 33 | 34 | >>> linker = mof.atomic_clusters[("b", 2)] 35 | >>> print(linker) 36 | AtomicCluster("C8 O4 H4", site_indices=[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) 37 | 38 | We can instantiate our analysis class and analyse our chosen linker molecule: 39 | 40 | >>> from dihedral import DihedralAnalysis 41 | >>> analysis = DihedralAnalysis() 42 | >>> results = analysis.analyse_ligand(linker) 43 | >>> print(results) 44 | {'carboxylate_a': array([176.342, -5.238]), 45 | 'carboxylate_b': array([149.77 , -32.647])} 46 | 47 | 48 | Related content 49 | --------------- 50 | .. card:: Torsional flexibility in zinc–benzenedicarboxylate metal–organic frameworks 51 | :link: https://pubs.rsc.org/en/content/articlelanding/2024/ce/d3ce01078c 52 | 53 | Emily G. Meekel, Thomas C. Nicholas, Ben Slater and Andrew L. Goodwin 54 | 55 | *CrystEngComm*, **26**, 673–680 (2024) -------------------------------------------------------------------------------- /docs/source/case-studies/topology-data.rst: -------------------------------------------------------------------------------- 1 | Topology data 2 | ============= 3 | 4 | Assigning topology data (i.e. how atoms are connected) to a structure might be 5 | required, for example to run simple molecular dynamics simulations. This can be 6 | applied even when structural coarse-graining isn't required, such as for 7 | zeolites. 8 | 9 | Let's load the zeolite **MEP** net, find neighbours using a cut-off, and save the 10 | file in LAMMPS data format. 11 | 12 | >>> from chic import Structure 13 | >>> mep = Structure.from_cif("MEP.cif") 14 | >>> mep.get_neighbours_by_cutoff(rcut=1.8) # Ā 15 | >>> mep.find_atomic_clusters() 16 | >>> mep.get_coarse_grained_net() 17 | >>> mep.net_to_lammps_data("MEP.data", write_bonds=True, write_angles=True) 18 | 19 | .. image:: ../_static/mep.png 20 | :align: center 21 | :width: 400px 22 | :target: . 23 | 24 | The bonds and angles will automatically be *clustered* into unique types. Here 25 | is the header of the file we wrote 26 | 27 | .. include:: ../_static/mep.data 28 | :literal: 29 | 30 | 31 | What if we only wanted the Si nodes of the network? One easy way would be to 32 | simply delete the bridging oxygen atoms, and connect up Si nodes. We can do this 33 | with a careful chosen neighbour list. 34 | 35 | >>> mep.remove_sites_by_symbol("O") # remove bridging oxygens 36 | >>> mep.get_neighbours_by_cutoff(by_element_pair={("Si", "Si"): (2.5, 3.5)}) 37 | >>> mep.find_atomic_clusters(max_intra_bond_length=0.5, max_inter_bond_length=3.5) 38 | >>> mep.get_coarse_grained_net() 39 | >>> mep.net_to_lammps_data("MEP-nodes.data", write_bonds=True, write_angles=True) 40 | 41 | .. image:: ../_static/mep-nodes.png 42 | :align: center 43 | :width: 400px 44 | :target: . 45 | 46 | Similarly, the bonds and angles will be assigned to unique types. 47 | 48 | .. include:: ../_static/mep-nodes.data 49 | :literal: -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | project = "chic" 4 | copyright = "2024, Thomas Nicholas" 5 | author = "Thomas Nicholas" 6 | release = "0.1.01" 7 | 8 | 9 | extensions = [ 10 | "sphinx.ext.duration", 11 | "sphinx.ext.autodoc", 12 | "sphinx.ext.autosummary", 13 | "nbsphinx", 14 | "sphinx.ext.mathjax", 15 | "sphinx.ext.napoleon", 16 | "sphinx.ext.intersphinx", 17 | "sphinx_copybutton", 18 | "sphinx_design", 19 | "sphinx.ext.viewcode", 20 | "sphinx_codeautolink", 21 | "sphinxext.opengraph", 22 | ] 23 | 24 | 25 | intersphinx_mapping = { 26 | "ase": ("https://wiki.fysik.dtu.dk/ase/", None), 27 | "python": ("https://docs.python.org/3", None), 28 | "numpy": ("https://numpy.org/doc/stable/", None), 29 | } 30 | 31 | 32 | html_theme = "furo" 33 | html_static_path = ["_static"] 34 | html_logo = "logo.svg" 35 | 36 | blue = "#5599ff" 37 | red = "#ff5555" 38 | 39 | html_theme_options = { 40 | "sidebar_hide_name": True, 41 | "light_css_variables": { 42 | "color-brand-primary": blue, 43 | "color-brand-content": blue, 44 | "color-problematic": red, 45 | }, 46 | "dark_css_variables": { 47 | "color-brand-primary": blue, 48 | "color-brand-content": blue, 49 | "color-problematic": red, 50 | }, 51 | } 52 | # autodoc_typehints = "description" 53 | autodoc_member_order = "bysource" 54 | html_title = "chic" 55 | 56 | pygments_dark_style = "monokai" 57 | html_css_files = ["custom.css"] 58 | html_favicon = "favicon.svg" 59 | 60 | 61 | ogp_image = "_static/homepage-grab.png" 62 | -------------------------------------------------------------------------------- /docs/source/hide-title.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | chic 2 | ==== 3 | 4 | .. raw:: html 5 | :file: hide-title.html 6 | 7 | .. image:: logo.svg 8 | :align: center 9 | :alt: chic logo 10 | :target: . 11 | 12 | 13 | .. important:: 14 | 15 | This project is under active development. Until version 1.0.0 is released, breaking changes to the API may occur. 16 | 17 | :code:`chic` is a Python package for :strong:`c`\ oarse-graining :strong:`h`\ ybrid and :strong:`i`\ norganic :strong:`c`\ rystals. 18 | 19 | Quickstart 20 | ---------- 21 | Install using :code:`pip install chic-lib`, and then use 22 | :class:`~chic.Structure` to begin processing your structure... 23 | 24 | >>> from chic import Structure 25 | >>> struct = Structure.from_cif("ZIF-4-cag.cif") 26 | >>> struct.remove_sites_by_symbol("O") 27 | 28 | ... find the nodes, linkers, and underlying net... 29 | 30 | >>> struct.get_neighbours_crystalnn() 31 | >>> struct.find_atomic_clusters() 32 | >>> struct.get_coarse_grained_net() 33 | >>> struct.net_to_cif("cag-net.cif") 34 | 35 | .. raw:: html 36 | :file: ./_static/zif4-cg.html 37 | 38 | ... and redecorate with a different chemistry... 39 | 40 | >>> cag_net = struct.to_net() 41 | >>> cag_net.add_zif_atoms(template="CH3") # methyl-substituted imidazolate 42 | 43 | .. raw:: html 44 | :file: ./_static/zif4-cg-d.html 45 | 46 | :code:`chic` is built upon the :class:`pymatgen.core.Structure` class: 47 | 48 | >>> struct 49 | Structure Summary 50 | Lattice 51 | abc : 16.8509 16.8509 16.8509 52 | angles : 90.0 90.0 90.0 53 | volume : 4784.860756696228 54 | A : 16.8509 0.0 1.0318200373876067e-15 55 | B : -1.0318200373876067e-15 16.8509 1.0318200373876067e-15 56 | C : 0.0 0.0 16.8509 57 | pbc : True True True 58 | PeriodicSite: H (7.669, 7.093, 15.44) [0.4551, 0.4209, 0.9161] 59 | PeriodicSite: H (7.093, 7.669, 15.44) [0.4209, 0.4551, 0.9161] 60 | [...] 61 | 62 | for which all of the usual functionality is available. 63 | 64 | 65 | Contributing 66 | ------------ 67 | 68 | :code:`chic` was developed by me, Thomas Nicholas, as part of my PhD research at 69 | the University of Oxford within the `Goodwin Group `_ 70 | and the `Deringer Group `_. 71 | During this time, it has been adapted several times over, with new directions 72 | defined by collaborations too (see :doc:`publications `)! 73 | 74 | Please do open an issue or pull request on the 75 | `GitHub repository `_ if you are interested 76 | in suggesting new functionality, identifying and/or fixing a bug, or simply 77 | want to start a dicussion. 78 | 79 | 80 | .. toctree:: 81 | :maxdepth: 1 82 | :hidden: 83 | 84 | Quickstart 85 | 86 | .. toctree:: 87 | :maxdepth: 3 88 | :hidden: 89 | :caption: API Reference 90 | 91 | api/structure 92 | api/net 93 | api/atomic-clusters 94 | 95 | .. toctree:: 96 | :maxdepth: 3 97 | :hidden: 98 | :caption: Publications 99 | 100 | publications/pub-main 101 | 102 | .. toctree:: 103 | :maxdepth: 1 104 | :hidden: 105 | :caption: Case studies 106 | 107 | case-studies/coarse-graining 108 | case-studies/topology-data 109 | case-studies/decorating 110 | case-studies/cleaning 111 | case-studies/dihedrals 112 | -------------------------------------------------------------------------------- /docs/source/publications/pub-main.rst: -------------------------------------------------------------------------------- 1 | ############ 2 | Publications 3 | ############ 4 | 5 | .. card:: Torsional flexibility in zinc–benzenedicarboxylate metal–organic frameworks (2024) 6 | :link: https://pubs.rsc.org/en/content/articlelanding/2024/ce/d3ce01078c 7 | 8 | .. image:: ../_static/visualisations/crystengcomm_2024.gif 9 | :align: left 10 | :width: 200px 11 | :target: . 12 | 13 | Emily G. Meekel, Thomas C. Nicholas, Ben Slater and Andrew L. Goodwin 14 | 15 | *CrystEngComm*, **26**, 673–680 (2024) 16 | 17 | 18 | .. card:: Coarse-grained versus fully atomistic machine learning for zeolitic imidazolate frameworks (2023) 19 | :link: https://pubs.rsc.org/en/content/articlelanding/2023/cc/d3cc02265j 20 | 21 | .. image:: ../_static/visualisations/chem_commun_2023.gif 22 | :align: left 23 | :width: 200px 24 | :target: . 25 | 26 | 27 | Zoé Faure Beaulieu, Thomas C. Nicholas, John L. A. Gardner, Andrew L. Goodwin and Volker L. Deringer 28 | 29 | *Chem. Commun.*, **59**, 11405–11408 (2023) 30 | 31 | 32 | .. card:: Visualization and Quantification of Geometric Diversity in Metal–Organic Frameworks (2021) 33 | :link: https://pubs.acs.org/doi/10.1021/acs.chemmater.1c02439 34 | 35 | .. image:: ../_static/visualisations/chem_mater_2021.jpeg 36 | :align: left 37 | :width: 200px 38 | :target: . 39 | 40 | Thomas C. Nicholas, Eugeny V. Alexandrov, Vladislav A. Blatov, Alexander P. Shevchenko, Davide M. Proserpio, Andrew L. Goodwin, and Volker L. Deringer 41 | 42 | *Chem. Mater.*, **33**, 8289–8300 (2021) 43 | 44 | 45 | 46 | .. card:: Understanding the geometric diversity of inorganic and hybrid frameworks through structural coarse-graining (2020) 47 | :link: https://pubs.rsc.org/en/content/articlelanding/2020/sc/d0sc03287e 48 | 49 | .. image:: ../_static/visualisations/chem_sci_2020.png 50 | :align: left 51 | :width: 200px 52 | :target: . 53 | 54 | Thomas C. Nicholas, Andrew L. Goodwin, Volker L. Deringer 55 | 56 | *Chem. Sci.*, **11**, 12580–12587 (2020) 57 | -------------------------------------------------------------------------------- /examples/1-coarse-graining-basics.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from pathlib import Path\n", 10 | "from chic import Structure" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "## Coarse-graining basics (ZIF-8 example)\n", 18 | "\n", 19 | "In this example we take the CIF for the prototypical zeolitic imidazolate \n", 20 | "framework, ZIF-8, and coarse-grain it. We check the coarse-graining is \n", 21 | "reasonable by overlaying the atomistic structure and coarse-grained structure \n", 22 | "before writing the final net in TopoCIF format." 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 2, 28 | "metadata": {}, 29 | "outputs": [ 30 | { 31 | "name": "stderr", 32 | "output_type": "stream", 33 | "text": [ 34 | "/Users/tcnicholas/miniconda3/envs/chic23/lib/python3.8/site-packages/chic/cif.py:107: UserWarning: Unable to match CIF atoms to Pymatgen atoms.\n", 35 | " warnings.warn('Unable to match CIF atoms to Pymatgen atoms.')\n" 36 | ] 37 | } 38 | ], 39 | "source": [ 40 | "# path to test example directory.\n", 41 | "eg_dir = Path('cg_zif8')\n", 42 | "\n", 43 | "# instantiate a Structure object from a CIF file.\n", 44 | "zif8 = Structure.from_cif(eg_dir / 'ZIF-8-sod.cif', cores=4, verbose=True)" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 3, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "# we can apply methods native to the Pymatgen Structure class. here we remove \n", 54 | "# all oxygen atoms from the structure, which reside in the pores.\n", 55 | "zif8.remove_species('O')" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 4, 61 | "metadata": {}, 62 | "outputs": [ 63 | { 64 | "name": "stdout", 65 | "output_type": "stream", 66 | "text": [ 67 | "\u001b[94maverage_element_pairs() took 0.02 seconds to execute.\u001b[0m\n" 68 | ] 69 | } 70 | ], 71 | "source": [ 72 | "# we can apply chic methods for dealing with structural distorder. here we\n", 73 | "# take the average position between pairs of H atoms.\n", 74 | "zif8.average_element_pairs('H', rmin=0.0, rmax=0.9)" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 5, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stdout", 84 | "output_type": "stream", 85 | "text": [ 86 | "\u001b[94mget_neighbours_crystalnn() took 9.10 seconds to execute.\u001b[0m\n", 87 | "\u001b[94mfind_atomic_clusters() took 0.03 seconds to execute.\u001b[0m\n", 88 | "\u001b[94mget_coarse_grained_net() took 0.01 seconds to execute.\u001b[0m\n" 89 | ] 90 | } 91 | ], 92 | "source": [ 93 | "# compute the neighbour list using the CrystalNN algorithm.\n", 94 | "zif8.get_neighbours_crystalnn()\n", 95 | "\n", 96 | "# determine atomic clusters.\n", 97 | "zif8.find_atomic_clusters()\n", 98 | "\n", 99 | "# coarse-grain with centroid method.\n", 100 | "zif8.get_coarse_grained_net()" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 6, 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [ 109 | "# we can write the coarse-grained net with the bond information to a TopoCIF.\n", 110 | "zif8.net_to_cif(eg_dir / 'ZIF-8-sod-cg.cif', write_bonds=True, name='ZIF-8-cg')\n", 111 | "\n", 112 | "# we can also write to LAMMPS data file.\n", 113 | "zif8.net_to_lammps_data(\n", 114 | " eg_dir / 'ZIF-8-sod-cg.data', write_bonds=True, name='ZIF-8-cg'\n", 115 | ")\n", 116 | "\n", 117 | "# we can check the coarse-grained net seems reasonable.\n", 118 | "zif8.overlay_cg_atomistic_representations(eg_dir / 'ZIF-8-sod-overlay.cif')" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 7, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "# call Pymatgen's writer to write to a VASP POSCAR format.\n", 128 | "zif8.net_to(eg_dir / 'POSCAR', fmt='poscar')" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 8, 134 | "metadata": {}, 135 | "outputs": [], 136 | "source": [ 137 | "# use ASE writer to write an xyz file.\n", 138 | "zif8.net_to_ase_to(eg_dir / 'ZIF-8-cg.xyz')" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 9, 144 | "metadata": {}, 145 | "outputs": [ 146 | { 147 | "data": { 148 | "text/plain": [ 149 | "(pymatgen.core.structure.Structure,\n", 150 | " Structure Summary\n", 151 | " Lattice\n", 152 | " abc : 16.8509 16.8509 16.8509\n", 153 | " angles : 90.0 90.0 90.0\n", 154 | " volume : 4784.860756696228\n", 155 | " A : 16.8509 0.0 1.0318200373876067e-15\n", 156 | " B : -1.0318200373876067e-15 16.8509 1.0318200373876067e-15\n", 157 | " C : 0.0 0.0 16.8509\n", 158 | " pbc : True True True\n", 159 | " PeriodicSite: O (6.252, 6.252, 0.2886) [0.371, 0.371, 0.01713]\n", 160 | " PeriodicSite: O (0.2886, 10.6, 10.6) [0.01713, 0.629, 0.629]\n", 161 | " PeriodicSite: O (0.2886, 6.252, 6.252) [0.01713, 0.371, 0.371]\n", 162 | " PeriodicSite: O (10.6, 10.6, 0.2886) [0.629, 0.629, 0.01713]\n", 163 | " PeriodicSite: O (10.6, 0.2886, 10.6) [0.629, 0.01713, 0.629]\n", 164 | " PeriodicSite: O (6.252, 0.2886, 6.252) [0.371, 0.01713, 0.371]\n", 165 | " PeriodicSite: O (8.137, 14.68, 2.173) [0.4829, 0.871, 0.129]\n", 166 | " PeriodicSite: O (6.252, 16.56, 10.6) [0.371, 0.9829, 0.629]\n", 167 | " PeriodicSite: Si (8.425, 12.64, 1.29e-15) [0.5, 0.75, 0.0]\n", 168 | " PeriodicSite: O (8.714, 14.68, 14.68) [0.5171, 0.871, 0.871]\n", 169 | " PeriodicSite: Si (8.425, 0.0, 12.64) [0.5, 0.0, 0.75]\n", 170 | " PeriodicSite: O (8.137, 2.173, 14.68) [0.4829, 0.129, 0.871]\n", 171 | " PeriodicSite: Si (8.425, 4.213, 7.739e-16) [0.5, 0.25, 0.0]\n", 172 | " PeriodicSite: O (8.714, 2.173, 2.173) [0.5171, 0.129, 0.129]\n", 173 | " PeriodicSite: O (10.6, 6.252, 16.56) [0.629, 0.371, 0.9829]\n", 174 | " PeriodicSite: O (6.252, 10.6, 16.56) [0.371, 0.629, 0.9829]\n", 175 | " PeriodicSite: Si (-2.58e-16, 4.213, 8.425) [0.0, 0.25, 0.5]\n", 176 | " PeriodicSite: O (2.173, 2.173, 8.714) [0.129, 0.129, 0.5171]\n", 177 | " PeriodicSite: Si (4.213, 0.0, 8.425) [0.25, 0.0, 0.5]\n", 178 | " PeriodicSite: Si (-5.159e-16, 8.425, 4.213) [0.0, 0.5, 0.25]\n", 179 | " PeriodicSite: Si (8.425, 0.0, 4.213) [0.5, 0.0, 0.25]\n", 180 | " PeriodicSite: O (10.6, 16.56, 6.252) [0.629, 0.9829, 0.371]\n", 181 | " PeriodicSite: O (16.56, 10.6, 6.252) [0.9829, 0.629, 0.371]\n", 182 | " PeriodicSite: O (14.68, 14.68, 8.714) [0.871, 0.871, 0.5171]\n", 183 | " PeriodicSite: Si (12.64, 0.0, 8.425) [0.75, 0.0, 0.5]\n", 184 | " PeriodicSite: O (14.68, 2.173, 8.137) [0.871, 0.129, 0.4829]\n", 185 | " PeriodicSite: Si (-7.739e-16, 12.64, 8.425) [0.0, 0.75, 0.5]\n", 186 | " PeriodicSite: O (2.173, 14.68, 8.137) [0.129, 0.871, 0.4829]\n", 187 | " PeriodicSite: Si (4.213, 8.425, 7.739e-16) [0.25, 0.5, 0.0]\n", 188 | " PeriodicSite: O (2.173, 8.714, 2.173) [0.129, 0.5171, 0.129]\n", 189 | " PeriodicSite: O (16.56, 6.252, 10.6) [0.9829, 0.371, 0.629]\n", 190 | " PeriodicSite: Si (-5.159e-16, 8.425, 12.64) [0.0, 0.5, 0.75]\n", 191 | " PeriodicSite: O (2.173, 8.137, 14.68) [0.129, 0.4829, 0.871]\n", 192 | " PeriodicSite: O (14.68, 8.137, 2.173) [0.871, 0.4829, 0.129]\n", 193 | " PeriodicSite: Si (12.64, 8.425, 1.29e-15) [0.75, 0.5, 0.0]\n", 194 | " PeriodicSite: O (14.68, 8.714, 14.68) [0.871, 0.5171, 0.871])" 195 | ] 196 | }, 197 | "execution_count": 9, 198 | "metadata": {}, 199 | "output_type": "execute_result" 200 | } 201 | ], 202 | "source": [ 203 | "# net to Pymatgen Structure object.\n", 204 | "pym_net = zif8.net_to_struct()\n", 205 | "type(pym_net), pym_net" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 10, 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "data": { 215 | "text/plain": [ 216 | "(ase.atoms.Atoms,\n", 217 | " Atoms(symbols='O24Si12', pbc=True, cell=[[16.8509, 0.0, 1.0318200373876067e-15], [-1.0318200373876067e-15, 16.8509, 1.0318200373876067e-15], [0.0, 0.0, 16.8509]]))" 218 | ] 219 | }, 220 | "execution_count": 10, 221 | "metadata": {}, 222 | "output_type": "execute_result" 223 | } 224 | ], 225 | "source": [ 226 | "# net to ASE Atoms object.\n", 227 | "ase_net = zif8.net_to_ase_atoms()\n", 228 | "type(ase_net), ase_net" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": null, 234 | "metadata": {}, 235 | "outputs": [], 236 | "source": [] 237 | } 238 | ], 239 | "metadata": { 240 | "kernelspec": { 241 | "display_name": "chic23", 242 | "language": "python", 243 | "name": "python3" 244 | }, 245 | "language_info": { 246 | "codemirror_mode": { 247 | "name": "ipython", 248 | "version": 3 249 | }, 250 | "file_extension": ".py", 251 | "mimetype": "text/x-python", 252 | "name": "python", 253 | "nbconvert_exporter": "python", 254 | "pygments_lexer": "ipython3", 255 | "version": "3.8.17" 256 | } 257 | }, 258 | "nbformat": 4, 259 | "nbformat_minor": 2 260 | } 261 | -------------------------------------------------------------------------------- /examples/2-removing-disorder.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from pathlib import Path\n", 10 | "from chic.structure import Structure" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 2, 16 | "metadata": {}, 17 | "outputs": [ 18 | { 19 | "name": "stderr", 20 | "output_type": "stream", 21 | "text": [ 22 | "/Users/tcnicholas/miniconda3/envs/chic23/lib/python3.8/site-packages/chic/cif.py:107: UserWarning: Unable to match CIF atoms to Pymatgen atoms.\n", 23 | " warnings.warn('Unable to match CIF atoms to Pymatgen atoms.')\n" 24 | ] 25 | } 26 | ], 27 | "source": [ 28 | "# path to test example directory.\n", 29 | "eg_dir = Path('cg_zif4')\n", 30 | "\n", 31 | "# instantiate a Structure object from a CIF file. we turn off the timings\n", 32 | "# this time (verbose=False).\n", 33 | "zif4 = Structure.from_cif(eg_dir / 'ZIF-4-cag.cif', cores=4, verbose=False)" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 3, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "# here the thermal motion of the imidazolate ring leads to split positions, so\n", 43 | "# we average the positions of the atoms.\n", 44 | "zif4.average_element_pairs('H', rmin=0.99, rmax=1.1)\n", 45 | "zif4.average_element_pairs('C', rmin=0.6, rmax=0.7)\n", 46 | "\n", 47 | "# use Pymatgen to write the \"tidy\" structure to a CIF. note we need to convert\n", 48 | "# the Path object to a string for the Pymatgen writer function.\n", 49 | "zif4.to(str(eg_dir / 'ZIF-4-cag-tidy.cif'));" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 4, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# follow coarse-graining protocol.\n", 59 | "zif4.get_neighbours_crystalnn()\n", 60 | "zif4.find_atomic_clusters()" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 5, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "# when we coarse-grain the structure, we can skip the hydrogen atoms when \n", 70 | "# calculating the geometric centroid of the clusters. this means that we are\n", 71 | "# essentially taking the centroid of the imidazolate ring. this parameter is\n", 72 | "# passed to the default \"centroid\" function in the Structure class.\n", 73 | "zif4.get_coarse_grained_net(skip_elements=['H'])" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 6, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "# here we can overlay the atomistic and coarse-grained structures to check\n", 83 | "# that the coarse-graining has been performed correctly. we can also pass a\n", 84 | "# dictionary to map the bead types to elements. in this case, we also keep the\n", 85 | "# non-framework (solvent) atoms, but indicate chic has correctly identified\n", 86 | "# them as non-framework atoms by placing a Be atom at their position.\n", 87 | "zif4.overlay_cg_atomistic_representations(\n", 88 | " eg_dir / 'ZIF-4-cag-overlay.cif', \n", 89 | " skip_non_framework=False,\n", 90 | " bead_type_to_element_mapping = {'a': 'Si', 'b': 'Ce', 'X': 'Be'}\n", 91 | ")" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [ 100 | "# we can write the coarse-grained net to a CIF file with the bonds formatted\n", 101 | "# for TopoCIF.\n", 102 | "zif4.net_to_cif(\n", 103 | " eg_dir / 'ZIF-4-cag-topocif.cif', \n", 104 | " write_bonds=True, \n", 105 | " name='ZIF-4-cg',\n", 106 | " skip_non_framework=True,\n", 107 | ")\n", 108 | "\n", 109 | "# we can also write to LAMMPS data file. It is more obvious if the bonds are\n", 110 | "# not correct because we can view it directly in OVITO.\n", 111 | "zif4.net_to_lammps_data(\n", 112 | " eg_dir / 'ZIF-4-cag-cg.data', write_bonds=True, name='ZIF-4-cg'\n", 113 | ")" 114 | ] 115 | } 116 | ], 117 | "metadata": { 118 | "kernelspec": { 119 | "display_name": "chic23", 120 | "language": "python", 121 | "name": "python3" 122 | }, 123 | "language_info": { 124 | "codemirror_mode": { 125 | "name": "ipython", 126 | "version": 3 127 | }, 128 | "file_extension": ".py", 129 | "mimetype": "text/x-python", 130 | "name": "python", 131 | "nbconvert_exporter": "python", 132 | "pygments_lexer": "ipython3", 133 | "version": "3.8.17" 134 | } 135 | }, 136 | "nbformat": 4, 137 | "nbformat_minor": 2 138 | } 139 | -------------------------------------------------------------------------------- /examples/3-decorating-basics.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from pathlib import Path\n", 10 | "from chic import Net" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "## Decorating basics (**sod** example)\n", 18 | "\n", 19 | "*chic* also provides backmapping functionality that allows you to ''decorate'' a\n", 20 | "coarse-grained with MOF buildig units. This is primarily handled by the \n", 21 | "chic.Net class. Here, we use the coarse-grained sodalite net from example 1 as a\n", 22 | "starting point." 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 2, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "# path to test example directory.\n", 32 | "eg_dir = Path('decorate_sod')\n", 33 | "\n", 34 | "# instantiate a Net object from a topocif file.\n", 35 | "sod_net = Net.from_topocif(eg_dir / 'ZIF-8-sod-cg.cif')" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 3, 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "# we can now decorate the Net object with a linker. the default linker is\n", 45 | "# an unsubstituted imidazole linker (i.e. H substituent).\n", 46 | "sod_net.add_zif_atoms(template='H')" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "# as with the chic.Structure class, we can also write our decorated net to\n", 56 | "# files using the ASE interface.\n", 57 | "sod_net.to_ase_to(eg_dir / 'ZIF-8-sod-cg-decorated-H.cif')" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 5, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "# we can write the decorated net to a LAMMPS data file. note, so that the \n", 67 | "# decorated net is compatible with the MOF-FF force field, we distingush\n", 68 | "# between different types of atoms within the molecule.\n", 69 | "sod_net.to_lammps_data(eg_dir / 'ZIF-8-sod-cg-decorated-H.data')" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "# finally, we can additionally write the LAMMPS data file with the topology\n", 79 | "# information needed to run a simulation with the MOF-FF for ZIFs force field.\n", 80 | "# we first need to assign the topology.\n", 81 | "sod_net.assign_mofff_topology()" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": 8, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "# then we can call the to_lammps_data method as before, which will now by \n", 91 | "# default write the topology information to the data file.\n", 92 | "sod_net.to_lammps_data(eg_dir / 'ZIF-8-sod-cg-decorated-H-topology.data')" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 6, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "# we also have the option to decorate the net with a methyl-substituted linker.\n", 102 | "# note, this will clear the current decoration and replace it with the new one.\n", 103 | "sod_net.add_zif_atoms(template='CH3')\n", 104 | "\n", 105 | "# as before, we can write this decoration to CIF and LAMMPS data files.\n", 106 | "sod_net.to_ase_to(eg_dir / 'ZIF-8-sod-cg-decorated-CH3.cif')\n", 107 | "sod_net.to_lammps_data(eg_dir / 'ZIF-8-sod-cg-decorated-CH3.data')\n", 108 | "\n", 109 | "# let's add the topology information.\n", 110 | "sod_net.assign_mofff_topology()\n", 111 | "\n", 112 | "# and write the full LAMMPS data file.\n", 113 | "sod_net.to_lammps_data(eg_dir / 'ZIF-8-sod-cg-decorated-CH3-topology.data')" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": null, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [] 122 | } 123 | ], 124 | "metadata": { 125 | "kernelspec": { 126 | "display_name": "chic23", 127 | "language": "python", 128 | "name": "python3" 129 | }, 130 | "language_info": { 131 | "codemirror_mode": { 132 | "name": "ipython", 133 | "version": 3 134 | }, 135 | "file_extension": ".py", 136 | "mimetype": "text/x-python", 137 | "name": "python", 138 | "nbconvert_exporter": "python", 139 | "pygments_lexer": "ipython3", 140 | "version": "3.8.17" 141 | } 142 | }, 143 | "nbformat": 4, 144 | "nbformat_minor": 2 145 | } 146 | -------------------------------------------------------------------------------- /examples/4-supercells.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from pathlib import Path\n", 10 | "from chic import Structure, Net" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "---\n", 18 | "## Coarse-graining supercells" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 2, 24 | "metadata": {}, 25 | "outputs": [ 26 | { 27 | "name": "stdout", 28 | "output_type": "stream", 29 | "text": [ 30 | "\u001b[94maverage_element_pairs() took 0.02 seconds to execute.\u001b[0m\n" 31 | ] 32 | }, 33 | { 34 | "name": "stderr", 35 | "output_type": "stream", 36 | "text": [ 37 | "/Users/tcnicholas/miniconda3/envs/chic23/lib/python3.8/site-packages/chic/cif.py:107: UserWarning: Unable to match CIF atoms to Pymatgen atoms.\n", 38 | " warnings.warn('Unable to match CIF atoms to Pymatgen atoms.')\n" 39 | ] 40 | } 41 | ], 42 | "source": [ 43 | "# path to test example directory.\n", 44 | "eg_dir = Path('cg_zif8')\n", 45 | "\n", 46 | "# instantiate a Structure object from a CIF file.\n", 47 | "zif8 = Structure.from_cif(eg_dir / 'ZIF-8-sod.cif', cores=4, verbose=True)\n", 48 | "zif8.remove_species('O')\n", 49 | "zif8.average_element_pairs('H', rmin=0.0, rmax=0.9)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 3, 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "name": "stdout", 59 | "output_type": "stream", 60 | "text": [ 61 | "\u001b[94mget_neighbours_crystalnn() took 8.75 seconds to execute.\u001b[0m\n" 62 | ] 63 | } 64 | ], 65 | "source": [ 66 | "# we *strongly* reccomend you first compute the neighbour list for your\n", 67 | "# structure *before* you replicate it, otherwise you will have to recompute\n", 68 | "# the neighbour list for all atoms in the supercell.\n", 69 | "zif8.get_neighbours_crystalnn()" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 4, 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "name": "stdout", 79 | "output_type": "stream", 80 | "text": [ 81 | "\u001b[92mreplicate() took 0.88 seconds to execute.\u001b[0m\n" 82 | ] 83 | } 84 | ], 85 | "source": [ 86 | "# now we can replicate the cell. we pass it a list of three integers, which are \n", 87 | "# the number of times we want to replicate the unit cell in each direction. in \n", 88 | "#this case, we replicate the unit cell once in the x direction, three times in \n", 89 | "# the y direction, and twice in the z direction. it returns a new Net object, \n", 90 | "# which we can assign to a new variable.\n", 91 | "zif8_supercell = zif8.replicate([1, 3, 2])" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 5, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "name": "stdout", 101 | "output_type": "stream", 102 | "text": [ 103 | "\u001b[94mfind_atomic_clusters() took 0.20 seconds to execute.\u001b[0m\n", 104 | "\u001b[94mget_coarse_grained_net() took 0.08 seconds to execute.\u001b[0m\n" 105 | ] 106 | } 107 | ], 108 | "source": [ 109 | "# now we can proceed as normal, since we have now got a supercell and the \n", 110 | "# neighbour list has been updated to account for it.\n", 111 | "zif8_supercell.find_atomic_clusters()\n", 112 | "zif8_supercell.get_coarse_grained_net()\n", 113 | "zif8_supercell.net_to_cif(\n", 114 | " eg_dir / 'ZIF-8-sod-cg-1x3x2.cif', \n", 115 | " write_bonds=True, \n", 116 | " name='ZIF-8-cg-supercell'\n", 117 | ")\n", 118 | "zif8_supercell.net_to_lammps_data(\n", 119 | " eg_dir / 'ZIF-8-sod-cg-1x3x2.data',\n", 120 | " write_bonds=True,\n", 121 | " name='ZIF-8-cg-supercell'\n", 122 | ")" 123 | ] 124 | }, 125 | { 126 | "cell_type": "markdown", 127 | "metadata": {}, 128 | "source": [ 129 | "---\n", 130 | "## Decorating supercells\n", 131 | "\n", 132 | "You might have the TopoCIF for a single unit cell, but need a larger decorated \n", 133 | "net (e.g. for simulation). We can achieve this with the replicate() function.\n", 134 | "\n", 135 | "One particular use-case might be when using the structure for LAMMPS\n", 136 | "simulations, where explicit bonds are given. Sometimes the unit cells might be \n", 137 | "too small for the minimum image convention (MIC) to work, and therefore the \n", 138 | "force field will fail." 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 6, 144 | "metadata": {}, 145 | "outputs": [], 146 | "source": [ 147 | "# path to test example directory.\n", 148 | "eg_dir = Path('decorate_sod')\n", 149 | "\n", 150 | "# instantiate a Net object from a topocif file.\n", 151 | "sod_net = Net.from_topocif(eg_dir / 'ZIF-8-sod-cg.cif')" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 7, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "# now that we have our Net object, we can replicate the unit cell. we pass it\n", 161 | "# a list of three integers, which are the number of times we want to replicate\n", 162 | "# the unit cell in each direction. in this case, we replicate the unit cell\n", 163 | "# once in the x direction, three times in the y direction, and twice in the z\n", 164 | "# direction. it returns a new Net object, which we can assign to a new variable.\n", 165 | "supercell_net = sod_net.replicate([1, 3, 2])" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": 8, 171 | "metadata": {}, 172 | "outputs": [], 173 | "source": [ 174 | "# we can now proceed as usual.\n", 175 | "supercell_net.add_zif_atoms(template='H')\n", 176 | "supercell_net.assign_mofff_topology()\n", 177 | "supercell_net.to_lammps_data(eg_dir / 'ZIF-8-sod-cg-decorated-H-1x3x2.data')" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": null, 183 | "metadata": {}, 184 | "outputs": [], 185 | "source": [] 186 | } 187 | ], 188 | "metadata": { 189 | "kernelspec": { 190 | "display_name": "chic23", 191 | "language": "python", 192 | "name": "python3" 193 | }, 194 | "language_info": { 195 | "codemirror_mode": { 196 | "name": "ipython", 197 | "version": 3 198 | }, 199 | "file_extension": ".py", 200 | "mimetype": "text/x-python", 201 | "name": "python", 202 | "nbconvert_exporter": "python", 203 | "pygments_lexer": "ipython3", 204 | "version": "3.8.17" 205 | } 206 | }, 207 | "nbformat": 4, 208 | "nbformat_minor": 2 209 | } 210 | -------------------------------------------------------------------------------- /examples/5-building-units.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from pathlib import Path\n", 10 | "from chic import Structure\n", 11 | "from chic.utils import crystal_toolkit_display" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 2, 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "name": "stderr", 21 | "output_type": "stream", 22 | "text": [ 23 | "/Users/tcnicholas/miniconda3/envs/chic23/lib/python3.8/site-packages/chic/cif.py:107: UserWarning: Unable to match CIF atoms to Pymatgen atoms.\n", 24 | " warnings.warn('Unable to match CIF atoms to Pymatgen atoms.')\n" 25 | ] 26 | }, 27 | { 28 | "name": "stdout", 29 | "output_type": "stream", 30 | "text": [ 31 | "\u001b[94mget_neighbours_crystalnn() took 9.65 seconds to execute.\u001b[0m\n", 32 | "\u001b[94mfind_atomic_clusters() took 0.03 seconds to execute.\u001b[0m\n" 33 | ] 34 | } 35 | ], 36 | "source": [ 37 | "# path to test example directory.\n", 38 | "eg_dir = Path('cg_zif8')\n", 39 | "\n", 40 | "# instantiate a Structure object from a CIF file.\n", 41 | "zif8 = Structure.from_cif(eg_dir / 'ZIF-8-sod.cif', cores=8, verbose=True)\n", 42 | "zif8.remove_species('O')\n", 43 | "zif8.get_neighbours_crystalnn()\n", 44 | "zif8.find_atomic_clusters()" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 3, 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "data": { 54 | "text/plain": [ 55 | "AtomicCluster(\"H8 C4 N2\", site_indices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])" 56 | ] 57 | }, 58 | "execution_count": 3, 59 | "metadata": {}, 60 | "output_type": "execute_result" 61 | } 62 | ], 63 | "source": [ 64 | "# we can also visualise individual atomic clusters. For example, let's look at\n", 65 | "# the first 'b-type' atomic cluster in the ZIF-8 framework.\n", 66 | "cluster = zif8.atomic_clusters[('b', 1)]\n", 67 | "cluster" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 4, 73 | "metadata": {}, 74 | "outputs": [ 75 | { 76 | "name": "stdout", 77 | "output_type": "stream", 78 | "text": [ 79 | "No module named 'phonopy'\n" 80 | ] 81 | }, 82 | { 83 | "data": { 84 | "text/html": [ 85 | "\n", 86 | " \n", 94 | " " 95 | ], 96 | "text/plain": [ 97 | "" 98 | ] 99 | }, 100 | "metadata": {}, 101 | "output_type": "display_data" 102 | } 103 | ], 104 | "source": [ 105 | "# we can also visualise the atomic cluster using crystal toolkit. note here, we\n", 106 | "# can clearly see the disordered H-atoms in the linker, associated with the \n", 107 | "# rotational freedom of the methyl substituent.\n", 108 | "cluster.visualise()" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 7, 114 | "metadata": {}, 115 | "outputs": [ 116 | { 117 | "name": "stdout", 118 | "output_type": "stream", 119 | "text": [ 120 | "\u001b[94maverage_element_pairs() took 0.02 seconds to execute.\u001b[0m\n" 121 | ] 122 | }, 123 | { 124 | "name": "stdout", 125 | "output_type": "stream", 126 | "text": [ 127 | "\u001b[94mget_neighbours_crystalnn() took 7.14 seconds to execute.\u001b[0m\n", 128 | "\u001b[94mfind_atomic_clusters() took 0.03 seconds to execute.\u001b[0m\n" 129 | ] 130 | } 131 | ], 132 | "source": [ 133 | "# let us now go back and resolve this disorder, as we did before.\n", 134 | "zif8.average_element_pairs('H', rmin=0.0, rmax=0.9)\n", 135 | "\n", 136 | "# we now need to recompute the neighbour list to account for the new atoms at\n", 137 | "# the average site.\n", 138 | "zif8.get_neighbours_crystalnn()\n", 139 | "zif8.find_atomic_clusters()" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 8, 145 | "metadata": {}, 146 | "outputs": [ 147 | { 148 | "data": { 149 | "text/html": [ 150 | "\n", 151 | " \n", 159 | " " 160 | ], 161 | "text/plain": [ 162 | "" 163 | ] 164 | }, 165 | "metadata": {}, 166 | "output_type": "display_data" 167 | } 168 | ], 169 | "source": [ 170 | "# now re-examine the cluster.\n", 171 | "cluster = zif8.atomic_clusters[('b', 1)]\n", 172 | "cluster.visualise()" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": 9, 178 | "metadata": {}, 179 | "outputs": [ 180 | { 181 | "data": { 182 | "text/plain": [ 183 | "[{'nodes': [1, 2, 3, 4, 5], 'edges': [(5, 1), (1, 2), (2, 3), (3, 4), (4, 5)]}]" 184 | ] 185 | }, 186 | "execution_count": 9, 187 | "metadata": {}, 188 | "output_type": "execute_result" 189 | } 190 | ], 191 | "source": [ 192 | "cluster.find_rings()" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [] 201 | } 202 | ], 203 | "metadata": { 204 | "kernelspec": { 205 | "display_name": "chic23", 206 | "language": "python", 207 | "name": "python3" 208 | }, 209 | "language_info": { 210 | "codemirror_mode": { 211 | "name": "ipython", 212 | "version": 3 213 | }, 214 | "file_extension": ".py", 215 | "mimetype": "text/x-python", 216 | "name": "python", 217 | "nbconvert_exporter": "python", 218 | "pygments_lexer": "ipython3", 219 | "version": "3.8.17" 220 | } 221 | }, 222 | "nbformat": 4, 223 | "nbformat_minor": 2 224 | } 225 | -------------------------------------------------------------------------------- /examples/UiO-66(Zr)/UiO-66_cdc-H2O.cif: -------------------------------------------------------------------------------- 1 | data_UiO-66_cdc-H2O 2 | _audit_creation_method 'generated by CrystalMaker X for macOS' 3 | _cell_length_a 20.800200(0) 4 | _cell_length_b 20.800200(0) 5 | _cell_length_c 20.800200(0) 6 | _cell_angle_alpha 90.000000(0) 7 | _cell_angle_beta 90.000000(0) 8 | _cell_angle_gamma 90.000000(0) 9 | 10 | _symmetry_space_group_name_H-M 'F m -3' 11 | 12 | loop_ 13 | _symmetry_equiv_pos_as_xyz 14 | '+x,+y,+z' 15 | '+z,+x,+y' 16 | '+y,+z,+x' 17 | '+x,+y,-z' 18 | '+z,+x,-y' 19 | '+y,+z,-x' 20 | '-x,+y,+z' 21 | '-z,+x,+y' 22 | '-y,+z,+x' 23 | '-x,+y,-z' 24 | '-z,+x,-y' 25 | '-y,+z,-x' 26 | '-x,-y,-z' 27 | '-z,-x,-y' 28 | '-y,-z,-x' 29 | '-x,-y,+z' 30 | '-z,-x,+y' 31 | '-y,-z,+x' 32 | '+x,-y,-z' 33 | '+z,-x,-y' 34 | '+y,-z,-x' 35 | '+x,-y,+z' 36 | '+z,-x,+y' 37 | '+y,-z,+x' 38 | '+x,1/2+y,1/2+z' 39 | '1/2+x,1/2+y,+z' 40 | '1/2+x,+y,1/2+z' 41 | '+z,1/2+x,1/2+y' 42 | '1/2+z,1/2+x,+y' 43 | '1/2+z,+x,1/2+y' 44 | '+y,1/2+z,1/2+x' 45 | '1/2+y,1/2+z,+x' 46 | '1/2+y,+z,1/2+x' 47 | '+x,1/2+y,1/2-z' 48 | '1/2+x,1/2+y,-z' 49 | '1/2+x,+y,1/2-z' 50 | '+z,1/2+x,1/2-y' 51 | '1/2+z,1/2+x,-y' 52 | '1/2+z,+x,1/2-y' 53 | '+y,1/2+z,1/2-x' 54 | '1/2+y,1/2+z,-x' 55 | '1/2+y,+z,1/2-x' 56 | '-x,1/2+y,1/2+z' 57 | '1/2-x,1/2+y,+z' 58 | '1/2-x,+y,1/2+z' 59 | '-z,1/2+x,1/2+y' 60 | '1/2-z,1/2+x,+y' 61 | '1/2-z,+x,1/2+y' 62 | '-y,1/2+z,1/2+x' 63 | '1/2-y,1/2+z,+x' 64 | '1/2-y,+z,1/2+x' 65 | '-x,1/2+y,1/2-z' 66 | '1/2-x,1/2+y,-z' 67 | '1/2-x,+y,1/2-z' 68 | '-z,1/2+x,1/2-y' 69 | '1/2-z,1/2+x,-y' 70 | '1/2-z,+x,1/2-y' 71 | '-y,1/2+z,1/2-x' 72 | '1/2-y,1/2+z,-x' 73 | '1/2-y,+z,1/2-x' 74 | '-x,1/2-y,1/2-z' 75 | '1/2-x,1/2-y,-z' 76 | '1/2-x,-y,1/2-z' 77 | '-z,1/2-x,1/2-y' 78 | '1/2-z,1/2-x,-y' 79 | '1/2-z,-x,1/2-y' 80 | '-y,1/2-z,1/2-x' 81 | '1/2-y,1/2-z,-x' 82 | '1/2-y,-z,1/2-x' 83 | '-x,1/2-y,1/2+z' 84 | '1/2-x,1/2-y,+z' 85 | '1/2-x,-y,1/2+z' 86 | '-z,1/2-x,1/2+y' 87 | '1/2-z,1/2-x,+y' 88 | '1/2-z,-x,1/2+y' 89 | '-y,1/2-z,1/2+x' 90 | '1/2-y,1/2-z,+x' 91 | '1/2-y,-z,1/2+x' 92 | '+x,1/2-y,1/2-z' 93 | '1/2+x,1/2-y,-z' 94 | '1/2+x,-y,1/2-z' 95 | '+z,1/2-x,1/2-y' 96 | '1/2+z,1/2-x,-y' 97 | '1/2+z,-x,1/2-y' 98 | '+y,1/2-z,1/2-x' 99 | '1/2+y,1/2-z,-x' 100 | '1/2+y,-z,1/2-x' 101 | '+x,1/2-y,1/2+z' 102 | '1/2+x,1/2-y,+z' 103 | '1/2+x,-y,1/2+z' 104 | '+z,1/2-x,1/2+y' 105 | '1/2+z,1/2-x,+y' 106 | '1/2+z,-x,1/2+y' 107 | '+y,1/2-z,1/2+x' 108 | '1/2+y,1/2-z,+x' 109 | '1/2+y,-z,1/2+x' 110 | 111 | loop_ 112 | _atom_site_label 113 | _atom_site_type_symbol 114 | _atom_site_occupancy 115 | _atom_site_fract_x 116 | _atom_site_fract_y 117 | _atom_site_fract_z 118 | _atom_site_U_iso_or_equiv 119 | C1 C 1.0 0.15000000(800000) 0.00000000(0) 0.14700000(900000) 0.05190 120 | C2 C 1.0 0.21000000(300000) 0.00000000(0) 0.19000000(300000) 0.05190 121 | C3 C 1.0 0.21620000(140000) -0.05940000(110000) 0.23420000(180000) 0.05190 122 | H1 H 1.0 0.25165900(0) 0.00000000(0) 0.15828900(0) . 123 | H2 H 1.0 0.21008000(0) -0.10302100(0) 0.20590100(0) . 124 | H3 H 1.0 0.17944600(0) -0.05745390(0) 0.27143500(0) . 125 | O1 O 1.0 0.08800000(500000) 0.00000000(0) 0.17200000(400000) 0.05190 126 | O2 O 1.0 0.17500000(400000) 0.00000000(0) 0.08500000(500000) 0.05190 127 | O8 O 1.0 0.05880000(60000) 0.05880000(60000) 0.05880000(60000) 0.05190 128 | Zr1 Zr 1.0 0.00000000(0) 0.00000000(0) 0.11680000(30000) 0.01040 129 | 130 | -------------------------------------------------------------------------------- /examples/cg_zif4/ZIF-4-cag-cg.data: -------------------------------------------------------------------------------- 1 | # 'ZIF-4-cg' generated by CHIC (2023-10-24 21:17:10.014084) 2 | 3 | 48 atoms 4 | 64 bonds 5 | 0 angles 6 | 0 dihedrals 7 | 0 impropers 8 | 9 | 2 atom types 10 | 1 bond types 11 | 0 angle types 12 | 0 dihedral types 13 | 0 improper types 14 | 15 | 0.000000 15.395000 xlo xhi 16 | 0.000000 15.307300 ylo yhi 17 | 0.000000 18.426000 zlo zhi 18 | 19 | Masses 20 | 21 | 1 15.9994 # O 22 | 2 28.0855 # Si 23 | 24 | Atoms # style = "full" 25 | 26 | 1 1 1 0.00000 13.3559630400 15.0636996278 14.9601062520 27 | 2 2 1 0.00000 6.1529812300 12.5461079968 2.2344841680 28 | 3 3 1 0.00000 2.3792972500 13.5545529208 17.0855085000 29 | 4 4 2 0.00000 3.1120992500 13.1720847230 1.6896273480 30 | 5 5 1 0.00000 1.5115118900 12.1746916696 12.2336847360 31 | 6 6 2 0.00000 0.1483308250 12.7972089460 14.9940285180 32 | 7 7 1 0.00000 5.6584630400 7.8972503722 3.4658937480 33 | 8 8 1 0.00000 13.8504812300 10.4148420032 16.1915158320 34 | 9 9 1 0.00000 10.0767972500 9.4063970792 1.3404915000 35 | 10 10 2 0.00000 10.8095992500 9.7888652770 16.7363726520 36 | 11 11 1 0.00000 9.2090118900 10.7862583304 6.1923152640 37 | 12 12 2 0.00000 7.8458308250 10.1637410540 3.4319714820 38 | 13 13 1 0.00000 9.7365369600 7.4100496278 14.9601062520 39 | 14 14 1 0.00000 1.5445187700 4.8924579968 2.2344841680 40 | 15 15 1 0.00000 5.3182027500 5.9009029208 17.0855085000 41 | 16 16 2 0.00000 4.5854007500 5.5184347230 1.6896273480 42 | 17 17 1 0.00000 6.1859881100 4.5210416696 12.2336847360 43 | 18 18 2 0.00000 7.5491691750 5.1435589460 14.9940285180 44 | 19 19 1 0.00000 2.0390369600 0.2436003722 3.4658937480 45 | 20 20 1 0.00000 9.2420187700 2.7611920032 16.1915158320 46 | 21 21 1 0.00000 13.0157027500 1.7527470792 1.3404915000 47 | 22 22 2 0.00000 12.2829007500 2.1352152770 16.7363726520 48 | 23 23 1 0.00000 13.8834881100 3.1326083304 6.1923152640 49 | 24 24 2 0.00000 15.2466691750 2.5100910540 3.4319714820 50 | 25 25 1 0.00000 2.0390369600 7.4100496278 12.6788937480 51 | 26 26 1 0.00000 9.2420187700 4.8924579968 6.9785158320 52 | 27 27 1 0.00000 13.0157027500 5.9009029208 10.5534915000 53 | 28 28 2 0.00000 12.2829007500 5.5184347230 7.5233726520 54 | 29 29 1 0.00000 13.8834881100 4.5210416696 15.4053152640 55 | 30 30 2 0.00000 15.2466691750 5.1435589460 12.6449714820 56 | 31 31 1 0.00000 9.7365369600 0.2436003722 5.7471062520 57 | 32 32 1 0.00000 1.5445187700 2.7611920032 11.4474841680 58 | 33 33 1 0.00000 5.3182027500 1.7527470792 7.8725085000 59 | 34 34 2 0.00000 4.5854007500 2.1352152770 10.9026273480 60 | 35 35 1 0.00000 6.1859881100 3.1326083304 3.0206847360 61 | 36 36 2 0.00000 7.5491691750 2.5100910540 5.7810285180 62 | 37 37 1 0.00000 13.3559630400 7.8972503722 5.7471062520 63 | 38 38 1 0.00000 6.1529812300 10.4148420032 11.4474841680 64 | 39 39 1 0.00000 2.3792972500 9.4063970792 7.8725085000 65 | 40 40 2 0.00000 3.1120992500 9.7888652770 10.9026273480 66 | 41 41 1 0.00000 1.5115118900 10.7862583304 3.0206847360 67 | 42 42 2 0.00000 0.1483308250 10.1637410540 5.7810285180 68 | 43 43 1 0.00000 5.6584630400 15.0636996278 12.6788937480 69 | 44 44 1 0.00000 13.8504812300 12.5461079968 6.9785158320 70 | 45 45 1 0.00000 10.0767972500 13.5545529208 10.5534915000 71 | 46 46 2 0.00000 10.8095992500 13.1720847230 7.5233726520 72 | 47 47 1 0.00000 9.2090118900 12.1746916696 15.4053152640 73 | 48 48 2 0.00000 7.8458308250 12.7972089460 12.6449714820 74 | 75 | Bonds 76 | 77 | 1 1 1 22 78 | 2 1 1 6 79 | 3 1 2 4 80 | 4 1 2 12 81 | 5 1 3 6 82 | 6 1 3 4 83 | 7 1 4 41 84 | 8 1 4 19 85 | 9 1 5 6 86 | 10 1 5 40 87 | 11 1 6 8 88 | 12 1 7 16 89 | 13 1 7 12 90 | 14 1 8 10 91 | 15 1 9 12 92 | 16 1 9 10 93 | 17 1 10 47 94 | 18 1 10 13 95 | 19 1 11 12 96 | 20 1 11 46 97 | 21 1 13 18 98 | 22 1 14 16 99 | 23 1 14 24 100 | 24 1 15 18 101 | 25 1 15 16 102 | 26 1 16 35 103 | 27 1 17 18 104 | 28 1 17 34 105 | 29 1 18 20 106 | 30 1 19 24 107 | 31 1 20 22 108 | 32 1 21 24 109 | 33 1 21 22 110 | 34 1 22 29 111 | 35 1 23 24 112 | 36 1 23 28 113 | 37 1 25 40 114 | 38 1 25 30 115 | 39 1 26 28 116 | 40 1 26 36 117 | 41 1 27 30 118 | 42 1 27 28 119 | 43 1 28 37 120 | 44 1 29 30 121 | 45 1 30 32 122 | 46 1 31 46 123 | 47 1 31 36 124 | 48 1 32 34 125 | 49 1 33 36 126 | 50 1 33 34 127 | 51 1 34 43 128 | 52 1 35 36 129 | 53 1 37 42 130 | 54 1 38 40 131 | 55 1 38 48 132 | 56 1 39 42 133 | 57 1 39 40 134 | 58 1 41 42 135 | 59 1 42 44 136 | 60 1 43 48 137 | 61 1 44 46 138 | 62 1 45 48 139 | 63 1 45 46 140 | 64 1 47 48 141 | -------------------------------------------------------------------------------- /examples/cg_zif4/ZIF-4-cag-topocif.cif: -------------------------------------------------------------------------------- 1 | data_ZIF-4-cg 2 | _chemical_formula_sum 'AB2C9D15E19' 3 | _cell_length_a 15.39500 4 | _cell_length_b 15.30730 5 | _cell_length_c 18.42600 6 | _cell_angle_alpha 90.00000 7 | _cell_angle_beta 90.00000 8 | _cell_angle_gamma 90.00000 9 | _cell_volume 4342.19531 10 | _cell_formula_units_Z 8 11 | _symmetry_space_group_name_H-M 'P 1' 12 | _symmetry_Int_Tables_number 1 13 | loop_ 14 | _symmetry_equiv_pos_site_id 15 | _symmetry_equiv_pos_as_xyz 16 | 1 x,y,z 17 | loop_ 18 | _atom_site_label 19 | _atom_site_type_symbol 20 | _atom_site_symmetry_multiplicity 21 | _atom_site_fract_x 22 | _atom_site_fract_y 23 | _atom_site_fract_z 24 | _atom_site_occupancy 25 | O1 O 1 0.8675520000 0.9840860000 0.8119020000 1 26 | O2 O 1 0.3996740000 0.8196160000 0.1212680000 1 27 | O3 O 1 0.1545500000 0.8854960000 0.9272500000 1 28 | Si1 Si 1 0.2021500000 0.8605100000 0.0916980000 1 29 | O4 O 1 0.0981820000 0.7953520000 0.6639360000 1 30 | Si2 Si 1 0.0096350000 0.8360200000 0.8137430000 1 31 | O5 O 1 0.3675520000 0.5159140000 0.1880980000 1 32 | O6 O 1 0.8996740000 0.6803840000 0.8787320000 1 33 | O7 O 1 0.6545500000 0.6145040000 0.0727500000 1 34 | Si3 Si 1 0.7021500000 0.6394900000 0.9083020000 1 35 | O8 O 1 0.5981820000 0.7046480000 0.3360640000 1 36 | Si4 Si 1 0.5096350000 0.6639800000 0.1862570000 1 37 | O9 O 1 0.6324480000 0.4840860000 0.8119020000 1 38 | O10 O 1 0.1003260000 0.3196160000 0.1212680000 1 39 | O11 O 1 0.3454500000 0.3854960000 0.9272500000 1 40 | Si5 Si 1 0.2978500000 0.3605100000 0.0916980000 1 41 | O12 O 1 0.4018180000 0.2953520000 0.6639360000 1 42 | Si6 Si 1 0.4903650000 0.3360200000 0.8137430000 1 43 | O13 O 1 0.1324480000 0.0159140000 0.1880980000 1 44 | O14 O 1 0.6003260000 0.1803840000 0.8787320000 1 45 | O15 O 1 0.8454500000 0.1145040000 0.0727500000 1 46 | Si7 Si 1 0.7978500000 0.1394900000 0.9083020000 1 47 | O16 O 1 0.9018180000 0.2046480000 0.3360640000 1 48 | Si8 Si 1 0.9903650000 0.1639800000 0.1862570000 1 49 | O17 O 1 0.1324480000 0.4840860000 0.6880980000 1 50 | O18 O 1 0.6003260000 0.3196160000 0.3787320000 1 51 | O19 O 1 0.8454500000 0.3854960000 0.5727500000 1 52 | Si9 Si 1 0.7978500000 0.3605100000 0.4083020000 1 53 | O20 O 1 0.9018180000 0.2953520000 0.8360640000 1 54 | Si10 Si 1 0.9903650000 0.3360200000 0.6862570000 1 55 | O21 O 1 0.6324480000 0.0159140000 0.3119020000 1 56 | O22 O 1 0.1003260000 0.1803840000 0.6212680000 1 57 | O23 O 1 0.3454500000 0.1145040000 0.4272500000 1 58 | Si11 Si 1 0.2978500000 0.1394900000 0.5916980000 1 59 | O24 O 1 0.4018180000 0.2046480000 0.1639360000 1 60 | Si12 Si 1 0.4903650000 0.1639800000 0.3137430000 1 61 | O25 O 1 0.8675520000 0.5159140000 0.3119020000 1 62 | O26 O 1 0.3996740000 0.6803840000 0.6212680000 1 63 | O27 O 1 0.1545500000 0.6145040000 0.4272500000 1 64 | Si13 Si 1 0.2021500000 0.6394900000 0.5916980000 1 65 | O28 O 1 0.0981820000 0.7046480000 0.1639360000 1 66 | Si14 Si 1 0.0096350000 0.6639800000 0.3137430000 1 67 | O29 O 1 0.3675520000 0.9840860000 0.6880980000 1 68 | O30 O 1 0.8996740000 0.8196160000 0.3787320000 1 69 | O31 O 1 0.6545500000 0.8854960000 0.5727500000 1 70 | Si15 Si 1 0.7021500000 0.8605100000 0.4083020000 1 71 | O32 O 1 0.5981820000 0.7953520000 0.8360640000 1 72 | Si16 Si 1 0.5096350000 0.8360200000 0.6862570000 1 73 | loop_ 74 | _topol_link.node_label_1 75 | _topol_link.node_label_2 76 | _topol_link.distance 77 | _topol_link.site_symmetry_symop_1 78 | _topol_link.site_symmetry_translation_1_x 79 | _topol_link.site_symmetry_translation_1_y 80 | _topol_link.site_symmetry_translation_1_z 81 | _topol_link.site_symmetry_symop_2 82 | _topol_link.site_symmetry_translation_2_x 83 | _topol_link.site_symmetry_translation_2_y 84 | _topol_link.site_symmetry_translation_2_z 85 | _topol_link.type 86 | _topol_link.multiplicity 87 | O1 Si7 3.15679 1 0 0 0 1 0 1 0 V 1 88 | O1 Si2 3.15003 1 0 0 0 1 1 0 0 V 1 89 | O2 Si1 3.15209 1 0 0 0 1 0 0 0 V 1 90 | O2 Si4 3.15838 1 0 0 0 1 0 0 0 V 1 91 | O3 Si2 3.15041 1 0 0 0 1 0 0 0 V 1 92 | O3 Si1 3.14084 1 0 0 0 1 0 0 1 V 1 93 | Si1 O28 3.16635 1 0 0 0 1 0 0 0 V 1 94 | Si1 O13 3.15679 1 0 0 0 1 0 1 0 V 1 95 | O4 Si2 3.14091 1 0 0 0 1 0 0 0 V 1 96 | O4 Si13 3.16635 1 0 0 0 1 0 0 0 V 1 97 | Si2 O6 3.15838 1 0 0 0 1 -1 0 0 V 1 98 | O5 Si5 3.15679 1 0 0 0 1 0 0 0 V 1 99 | O5 Si4 3.15003 1 0 0 0 1 0 0 0 V 1 100 | O6 Si3 3.15209 1 0 0 0 1 0 0 0 V 1 101 | O7 Si4 3.15041 1 0 0 0 1 0 0 0 V 1 102 | O7 Si3 3.14084 1 0 0 0 1 0 0 -1 V 1 103 | Si3 O32 3.16635 1 0 0 0 1 0 0 0 V 1 104 | Si3 O9 3.15679 1 0 0 0 1 0 0 0 V 1 105 | O8 Si4 3.14091 1 0 0 0 1 0 0 0 V 1 106 | O8 Si15 3.16635 1 0 0 0 1 0 0 0 V 1 107 | O9 Si6 3.15003 1 0 0 0 1 0 0 0 V 1 108 | O10 Si5 3.15209 1 0 0 0 1 0 0 0 V 1 109 | O10 Si8 3.15838 1 0 0 0 1 -1 0 0 V 1 110 | O11 Si6 3.15041 1 0 0 0 1 0 0 0 V 1 111 | O11 Si5 3.14084 1 0 0 0 1 0 0 1 V 1 112 | Si5 O24 3.16635 1 0 0 0 1 0 0 0 V 1 113 | O12 Si6 3.14091 1 0 0 0 1 0 0 0 V 1 114 | O12 Si11 3.16635 1 0 0 0 1 0 0 0 V 1 115 | Si6 O14 3.15838 1 0 0 0 1 0 0 0 V 1 116 | O13 Si8 3.15003 1 0 0 0 1 -1 0 0 V 1 117 | O14 Si7 3.15209 1 0 0 0 1 0 0 0 V 1 118 | O15 Si8 3.15041 1 0 0 0 1 0 0 0 V 1 119 | O15 Si7 3.14084 1 0 0 0 1 0 0 -1 V 1 120 | Si7 O20 3.16635 1 0 0 0 1 0 0 0 V 1 121 | O16 Si8 3.14091 1 0 0 0 1 0 0 0 V 1 122 | O16 Si9 3.16635 1 0 0 0 1 0 0 0 V 1 123 | O17 Si13 3.15679 1 0 0 0 1 0 0 0 V 1 124 | O17 Si10 3.15003 1 0 0 0 1 -1 0 0 V 1 125 | O18 Si9 3.15209 1 0 0 0 1 0 0 0 V 1 126 | O18 Si12 3.15838 1 0 0 0 1 0 0 0 V 1 127 | O19 Si10 3.15041 1 0 0 0 1 0 0 0 V 1 128 | O19 Si9 3.14084 1 0 0 0 1 0 0 0 V 1 129 | Si9 O25 3.15679 1 0 0 0 1 0 0 0 V 1 130 | O20 Si10 3.14091 1 0 0 0 1 0 0 0 V 1 131 | Si10 O22 3.15838 1 0 0 0 1 1 0 0 V 1 132 | O21 Si15 3.15679 1 0 0 0 1 0 -1 0 V 1 133 | O21 Si12 3.15003 1 0 0 0 1 0 0 0 V 1 134 | O22 Si11 3.15209 1 0 0 0 1 0 0 0 V 1 135 | O23 Si12 3.15041 1 0 0 0 1 0 0 0 V 1 136 | O23 Si11 3.14084 1 0 0 0 1 0 0 0 V 1 137 | Si11 O29 3.15679 1 0 0 0 1 0 -1 0 V 1 138 | O24 Si12 3.14091 1 0 0 0 1 0 0 0 V 1 139 | O25 Si14 3.15003 1 0 0 0 1 1 0 0 V 1 140 | O26 Si13 3.15209 1 0 0 0 1 0 0 0 V 1 141 | O26 Si16 3.15838 1 0 0 0 1 0 0 0 V 1 142 | O27 Si14 3.15041 1 0 0 0 1 0 0 0 V 1 143 | O27 Si13 3.14084 1 0 0 0 1 0 0 0 V 1 144 | O28 Si14 3.14091 1 0 0 0 1 0 0 0 V 1 145 | Si14 O30 3.15838 1 0 0 0 1 -1 0 0 V 1 146 | O29 Si16 3.15003 1 0 0 0 1 0 0 0 V 1 147 | O30 Si15 3.15209 1 0 0 0 1 0 0 0 V 1 148 | O31 Si16 3.15041 1 0 0 0 1 0 0 0 V 1 149 | O31 Si15 3.14084 1 0 0 0 1 0 0 0 V 1 150 | O32 Si16 3.14091 1 0 0 0 1 0 0 0 V 1 151 | #End of data_ZIF-4-cg 152 | 153 | -------------------------------------------------------------------------------- /examples/cg_zif8/POSCAR: -------------------------------------------------------------------------------- 1 | Si12 O24 2 | 1.0 3 | 16.8508999999999993 0.0000000000000000 0.0000000000000010 4 | -0.0000000000000010 16.8508999999999993 0.0000000000000010 5 | 0.0000000000000000 0.0000000000000000 16.8508999999999993 6 | O Si O Si O Si O Si O Si O Si O Si O Si O Si O Si O 7 | 8 1 1 1 1 1 3 1 1 3 3 1 1 1 1 1 2 1 2 1 1 8 | direct 9 | 0.3710181800000000 0.3710181800000000 0.0171272700000000 O 10 | 0.0171272700000000 0.6289818200000000 0.6289818200000000 O 11 | 0.0171272700000000 0.3710181800000000 0.3710181800000000 O 12 | 0.6289818200000000 0.6289818200000000 0.0171272700000000 O 13 | 0.6289818200000000 0.0171272700000000 0.6289818200000000 O 14 | 0.3710181800000000 0.0171272700000000 0.3710181800000000 O 15 | 0.4828727300000000 0.8710181800000000 0.1289818200000000 O 16 | 0.3710181800000000 0.9828727300000000 0.6289818200000000 O 17 | 0.5000000000000000 0.7500000000000000 0.0000000000000000 Si 18 | 0.5171272700000000 0.8710181800000000 0.8710181800000000 O 19 | 0.5000000000000000 0.0000000000000000 0.7500000000000000 Si 20 | 0.4828727300000000 0.1289818200000000 0.8710181800000000 O 21 | 0.5000000000000000 0.2500000000000000 0.0000000000000000 Si 22 | 0.5171272700000000 0.1289818200000000 0.1289818200000000 O 23 | 0.6289818200000000 0.3710181800000000 0.9828727300000000 O 24 | 0.3710181800000000 0.6289818200000000 0.9828727300000000 O 25 | 0.0000000000000000 0.2500000000000000 0.5000000000000000 Si 26 | 0.1289818200000000 0.1289818200000000 0.5171272700000000 O 27 | 0.2500000000000000 0.0000000000000000 0.5000000000000000 Si 28 | 0.0000000000000000 0.5000000000000000 0.2500000000000000 Si 29 | 0.5000000000000000 0.0000000000000000 0.2500000000000000 Si 30 | 0.6289818200000000 0.9828727300000000 0.3710181800000000 O 31 | 0.9828727300000000 0.6289818200000000 0.3710181800000000 O 32 | 0.8710181800000000 0.8710181800000000 0.5171272700000000 O 33 | 0.7500000000000000 0.0000000000000000 0.5000000000000000 Si 34 | 0.8710181800000000 0.1289818200000000 0.4828727300000000 O 35 | 0.0000000000000000 0.7500000000000000 0.5000000000000000 Si 36 | 0.1289818200000000 0.8710181800000000 0.4828727300000000 O 37 | 0.2500000000000000 0.5000000000000000 0.0000000000000000 Si 38 | 0.1289818200000000 0.5171272700000000 0.1289818200000000 O 39 | 0.9828727300000000 0.3710181800000000 0.6289818200000000 O 40 | 0.0000000000000000 0.5000000000000000 0.7500000000000000 Si 41 | 0.1289818200000000 0.4828727300000000 0.8710181800000000 O 42 | 0.8710181800000000 0.4828727300000000 0.1289818200000000 O 43 | 0.7500000000000000 0.5000000000000000 0.0000000000000000 Si 44 | 0.8710181800000000 0.5171272700000000 0.8710181800000000 O 45 | -------------------------------------------------------------------------------- /examples/cg_zif8/ZIF-8-cg.xyz: -------------------------------------------------------------------------------- 1 | 36 2 | Lattice="16.8509 0.0 1.0318200373876067e-15 -1.0318200373876067e-15 16.8509 1.0318200373876067e-15 0.0 0.0 16.8509" Properties=species:S:1:pos:R:3 pbc="T T T" 3 | O 6.25199025 6.25199025 0.28860991 4 | O 0.28860991 10.59890975 10.59890975 5 | O 0.28860991 6.25199025 6.25199025 6 | O 10.59890975 10.59890975 0.28860991 7 | O 10.59890975 0.28860991 10.59890975 8 | O 6.25199025 0.28860991 6.25199025 9 | O 8.13684009 14.67744025 2.17345975 10 | O 6.25199025 16.56229009 10.59890975 11 | O 8.71405991 14.67744025 14.67744025 12 | O 8.13684009 2.17345975 14.67744025 13 | O 8.71405991 2.17345975 2.17345975 14 | O 10.59890975 6.25199025 16.56229009 15 | O 6.25199025 10.59890975 16.56229009 16 | O 2.17345975 2.17345975 8.71405991 17 | O 10.59890975 16.56229009 6.25199025 18 | O 16.56229009 10.59890975 6.25199025 19 | O 14.67744025 14.67744025 8.71405991 20 | O 14.67744025 2.17345975 8.13684009 21 | O 2.17345975 14.67744025 8.13684009 22 | O 2.17345975 8.71405991 2.17345975 23 | O 16.56229009 6.25199025 10.59890975 24 | O 2.17345975 8.13684009 14.67744025 25 | O 14.67744025 8.13684009 2.17345975 26 | O 14.67744025 8.71405991 14.67744025 27 | Si 8.42545000 12.63817500 0.00000000 28 | Si 8.42545000 0.00000000 12.63817500 29 | Si 8.42545000 4.21272500 0.00000000 30 | Si -0.00000000 4.21272500 8.42545000 31 | Si 4.21272500 0.00000000 8.42545000 32 | Si -0.00000000 8.42545000 4.21272500 33 | Si 8.42545000 0.00000000 4.21272500 34 | Si 12.63817500 0.00000000 8.42545000 35 | Si -0.00000000 12.63817500 8.42545000 36 | Si 4.21272500 8.42545000 0.00000000 37 | Si -0.00000000 8.42545000 12.63817500 38 | Si 12.63817500 8.42545000 0.00000000 39 | -------------------------------------------------------------------------------- /examples/cg_zif8/ZIF-8-sod-cg.cif: -------------------------------------------------------------------------------- 1 | data_ZIF-8-cg 2 | _chemical_formula_sum 'AB4C8D10' 3 | _cell_length_a 16.85090 4 | _cell_length_b 16.85090 5 | _cell_length_c 16.85090 6 | _cell_angle_alpha 90.00000 7 | _cell_angle_beta 90.00000 8 | _cell_angle_gamma 90.00000 9 | _cell_volume 4784.86076 10 | _cell_formula_units_Z 12 11 | _symmetry_space_group_name_H-M 'P 1' 12 | _symmetry_Int_Tables_number 1 13 | loop_ 14 | _symmetry_equiv_pos_site_id 15 | _symmetry_equiv_pos_as_xyz 16 | 1 x,y,z 17 | loop_ 18 | _atom_site_label 19 | _atom_site_type_symbol 20 | _atom_site_symmetry_multiplicity 21 | _atom_site_fract_x 22 | _atom_site_fract_y 23 | _atom_site_fract_z 24 | _atom_site_occupancy 25 | O1 O 1 0.3710181800 0.3710181800 0.0171272700 1 26 | O2 O 1 0.0171272700 0.6289818200 0.6289818200 1 27 | O3 O 1 0.0171272700 0.3710181800 0.3710181800 1 28 | O4 O 1 0.6289818200 0.6289818200 0.0171272700 1 29 | O5 O 1 0.6289818200 0.0171272700 0.6289818200 1 30 | O6 O 1 0.3710181800 0.0171272700 0.3710181800 1 31 | O7 O 1 0.4828727300 0.8710181800 0.1289818200 1 32 | O8 O 1 0.3710181800 0.9828727300 0.6289818200 1 33 | Si1 Si 1 0.5000000000 0.7500000000 0.0000000000 1 34 | O9 O 1 0.5171272700 0.8710181800 0.8710181800 1 35 | Si2 Si 1 0.5000000000 0.0000000000 0.7500000000 1 36 | O10 O 1 0.4828727300 0.1289818200 0.8710181800 1 37 | Si3 Si 1 0.5000000000 0.2500000000 0.0000000000 1 38 | O11 O 1 0.5171272700 0.1289818200 0.1289818200 1 39 | O12 O 1 0.6289818200 0.3710181800 0.9828727300 1 40 | O13 O 1 0.3710181800 0.6289818200 0.9828727300 1 41 | Si4 Si 1 0.0000000000 0.2500000000 0.5000000000 1 42 | O14 O 1 0.1289818200 0.1289818200 0.5171272700 1 43 | Si5 Si 1 0.2500000000 0.0000000000 0.5000000000 1 44 | Si6 Si 1 0.0000000000 0.5000000000 0.2500000000 1 45 | Si7 Si 1 0.5000000000 0.0000000000 0.2500000000 1 46 | O15 O 1 0.6289818200 0.9828727300 0.3710181800 1 47 | O16 O 1 0.9828727300 0.6289818200 0.3710181800 1 48 | O17 O 1 0.8710181800 0.8710181800 0.5171272700 1 49 | Si8 Si 1 0.7500000000 0.0000000000 0.5000000000 1 50 | O18 O 1 0.8710181800 0.1289818200 0.4828727300 1 51 | Si9 Si 1 0.0000000000 0.7500000000 0.5000000000 1 52 | O19 O 1 0.1289818200 0.8710181800 0.4828727300 1 53 | Si10 Si 1 0.2500000000 0.5000000000 0.0000000000 1 54 | O20 O 1 0.1289818200 0.5171272700 0.1289818200 1 55 | O21 O 1 0.9828727300 0.3710181800 0.6289818200 1 56 | Si11 Si 1 0.0000000000 0.5000000000 0.7500000000 1 57 | O22 O 1 0.1289818200 0.4828727300 0.8710181800 1 58 | O23 O 1 0.8710181800 0.4828727300 0.1289818200 1 59 | Si12 Si 1 0.7500000000 0.5000000000 0.0000000000 1 60 | O24 O 1 0.8710181800 0.5171272700 0.8710181800 1 61 | loop_ 62 | _topol_link.node_label_1 63 | _topol_link.node_label_2 64 | _topol_link.distance 65 | _topol_link.site_symmetry_symop_1 66 | _topol_link.site_symmetry_translation_1_x 67 | _topol_link.site_symmetry_translation_1_y 68 | _topol_link.site_symmetry_translation_1_z 69 | _topol_link.site_symmetry_symop_2 70 | _topol_link.site_symmetry_translation_2_x 71 | _topol_link.site_symmetry_translation_2_y 72 | _topol_link.site_symmetry_translation_2_z 73 | _topol_link.type 74 | _topol_link.multiplicity 75 | O1 Si3 2.99430 1 0 0 0 1 0 0 0 V 1 76 | O1 Si10 2.99430 1 0 0 0 1 0 0 0 V 1 77 | O2 Si11 2.99430 1 0 0 0 1 0 0 0 V 1 78 | O2 Si9 2.99430 1 0 0 0 1 0 0 0 V 1 79 | O3 Si4 2.99430 1 0 0 0 1 0 0 0 V 1 80 | O3 Si6 2.99430 1 0 0 0 1 0 0 0 V 1 81 | O4 Si12 2.99430 1 0 0 0 1 0 0 0 V 1 82 | O4 Si1 2.99430 1 0 0 0 1 0 0 0 V 1 83 | O5 Si2 2.99430 1 0 0 0 1 0 0 0 V 1 84 | O5 Si8 2.99430 1 0 0 0 1 0 0 0 V 1 85 | O6 Si5 2.99430 1 0 0 0 1 0 0 0 V 1 86 | O6 Si7 2.99430 1 0 0 0 1 0 0 0 V 1 87 | O7 Si7 2.99430 1 0 0 0 1 0 1 0 V 1 88 | O7 Si1 2.99430 1 0 0 0 1 0 0 0 V 1 89 | O8 Si5 2.99430 1 0 0 0 1 0 1 0 V 1 90 | O8 Si2 2.99430 1 0 0 0 1 0 1 0 V 1 91 | Si1 O9 2.99430 1 0 0 0 1 0 0 -1 V 1 92 | Si1 O13 2.99430 1 0 0 0 1 0 0 -1 V 1 93 | O9 Si2 2.99430 1 0 0 0 1 0 1 0 V 1 94 | Si2 O10 2.99430 1 0 0 0 1 0 0 0 V 1 95 | O10 Si3 2.99430 1 0 0 0 1 0 0 1 V 1 96 | Si3 O11 2.99430 1 0 0 0 1 0 0 0 V 1 97 | Si3 O12 2.99430 1 0 0 0 1 0 0 -1 V 1 98 | O11 Si7 2.99430 1 0 0 0 1 0 0 0 V 1 99 | O12 Si12 2.99430 1 0 0 0 1 0 0 1 V 1 100 | O13 Si10 2.99430 1 0 0 0 1 0 0 1 V 1 101 | Si4 O18 2.99430 1 0 0 0 1 -1 0 0 V 1 102 | Si4 O21 2.99430 1 0 0 0 1 -1 0 0 V 1 103 | Si4 O14 2.99430 1 0 0 0 1 0 0 0 V 1 104 | O14 Si5 2.99430 1 0 0 0 1 0 0 0 V 1 105 | Si5 O19 2.99430 1 0 0 0 1 0 -1 0 V 1 106 | Si6 O16 2.99430 1 0 0 0 1 -1 0 0 V 1 107 | Si6 O20 2.99430 1 0 0 0 1 0 0 0 V 1 108 | Si6 O23 2.99430 1 0 0 0 1 -1 0 0 V 1 109 | Si7 O15 2.99430 1 0 0 0 1 0 -1 0 V 1 110 | O15 Si8 2.99430 1 0 0 0 1 0 1 0 V 1 111 | O16 Si9 2.99430 1 0 0 0 1 1 0 0 V 1 112 | O17 Si8 2.99430 1 0 0 0 1 0 1 0 V 1 113 | O17 Si9 2.99430 1 0 0 0 1 1 0 0 V 1 114 | Si8 O18 2.99430 1 0 0 0 1 0 0 0 V 1 115 | Si9 O19 2.99430 1 0 0 0 1 0 0 0 V 1 116 | Si10 O20 2.99430 1 0 0 0 1 0 0 0 V 1 117 | Si10 O22 2.99430 1 0 0 0 1 0 0 -1 V 1 118 | O21 Si11 2.99430 1 0 0 0 1 1 0 0 V 1 119 | Si11 O24 2.99430 1 0 0 0 1 -1 0 0 V 1 120 | Si11 O22 2.99430 1 0 0 0 1 0 0 0 V 1 121 | O23 Si12 2.99430 1 0 0 0 1 0 0 0 V 1 122 | Si12 O24 2.99430 1 0 0 0 1 0 0 -1 V 1 123 | #End of data_ZIF-8-cg 124 | 125 | -------------------------------------------------------------------------------- /examples/cg_zif8/ZIF-8-sod-cg.data: -------------------------------------------------------------------------------- 1 | # 'ZIF-8-cg' generated by CHIC (2023-10-25 17:58:44.900414) 2 | 3 | 36 atoms 4 | 48 bonds 5 | 0 angles 6 | 0 dihedrals 7 | 0 impropers 8 | 9 | 2 atom types 10 | 1 bond types 11 | 0 angle types 12 | 0 dihedral types 13 | 0 improper types 14 | 15 | 0.000000 16.850900 xlo xhi 16 | 0.000000 16.850900 ylo yhi 17 | 0.000000 16.850900 zlo zhi 18 | 19 | Masses 20 | 21 | 1 28.0855 # Si 22 | 2 15.9994 # O 23 | 24 | Atoms # style = "full" 25 | 26 | 1 1 2 0.00000 6.2519902494 6.2519902494 0.2886099140 27 | 2 2 2 0.00000 0.2886099140 10.5989097506 10.5989097506 28 | 3 3 2 0.00000 0.2886099140 6.2519902494 6.2519902494 29 | 4 4 2 0.00000 10.5989097506 10.5989097506 0.2886099140 30 | 5 5 2 0.00000 10.5989097506 0.2886099140 10.5989097506 31 | 6 6 2 0.00000 6.2519902494 0.2886099140 6.2519902494 32 | 7 7 2 0.00000 8.1368400860 14.6774402494 2.1734597506 33 | 8 8 2 0.00000 6.2519902494 16.5622900860 10.5989097506 34 | 9 9 1 0.00000 8.4254500000 12.6381750000 0.0000000000 35 | 10 10 2 0.00000 8.7140599140 14.6774402494 14.6774402494 36 | 11 11 1 0.00000 8.4254500000 0.0000000000 12.6381750000 37 | 12 12 2 0.00000 8.1368400860 2.1734597506 14.6774402494 38 | 13 13 1 0.00000 8.4254500000 4.2127250000 0.0000000000 39 | 14 14 2 0.00000 8.7140599140 2.1734597506 2.1734597506 40 | 15 15 2 0.00000 10.5989097506 6.2519902494 16.5622900860 41 | 16 16 2 0.00000 6.2519902494 10.5989097506 16.5622900860 42 | 17 17 1 0.00000 -0.0000000000 4.2127250000 8.4254500000 43 | 18 18 2 0.00000 2.1734597506 2.1734597506 8.7140599140 44 | 19 19 1 0.00000 4.2127250000 0.0000000000 8.4254500000 45 | 20 20 1 0.00000 -0.0000000000 8.4254500000 4.2127250000 46 | 21 21 1 0.00000 8.4254500000 0.0000000000 4.2127250000 47 | 22 22 2 0.00000 10.5989097506 16.5622900860 6.2519902494 48 | 23 23 2 0.00000 16.5622900860 10.5989097506 6.2519902494 49 | 24 24 2 0.00000 14.6774402494 14.6774402494 8.7140599140 50 | 25 25 1 0.00000 12.6381750000 0.0000000000 8.4254500000 51 | 26 26 2 0.00000 14.6774402494 2.1734597506 8.1368400860 52 | 27 27 1 0.00000 -0.0000000000 12.6381750000 8.4254500000 53 | 28 28 2 0.00000 2.1734597506 14.6774402494 8.1368400860 54 | 29 29 1 0.00000 4.2127250000 8.4254500000 0.0000000000 55 | 30 30 2 0.00000 2.1734597506 8.7140599140 2.1734597506 56 | 31 31 2 0.00000 16.5622900860 6.2519902494 10.5989097506 57 | 32 32 1 0.00000 -0.0000000000 8.4254500000 12.6381750000 58 | 33 33 2 0.00000 2.1734597506 8.1368400860 14.6774402494 59 | 34 34 2 0.00000 14.6774402494 8.1368400860 2.1734597506 60 | 35 35 1 0.00000 12.6381750000 8.4254500000 0.0000000000 61 | 36 36 2 0.00000 14.6774402494 8.7140599140 14.6774402494 62 | 63 | Bonds 64 | 65 | 1 1 1 13 66 | 2 1 1 29 67 | 3 1 2 32 68 | 4 1 2 27 69 | 5 1 3 17 70 | 6 1 3 20 71 | 7 1 4 35 72 | 8 1 4 9 73 | 9 1 5 11 74 | 10 1 5 25 75 | 11 1 6 19 76 | 12 1 6 21 77 | 13 1 7 21 78 | 14 1 7 9 79 | 15 1 8 19 80 | 16 1 8 11 81 | 17 1 9 10 82 | 18 1 9 16 83 | 19 1 10 11 84 | 20 1 11 12 85 | 21 1 12 13 86 | 22 1 13 14 87 | 23 1 13 15 88 | 24 1 14 21 89 | 25 1 15 35 90 | 26 1 16 29 91 | 27 1 17 26 92 | 28 1 17 31 93 | 29 1 17 18 94 | 30 1 18 19 95 | 31 1 19 28 96 | 32 1 20 23 97 | 33 1 20 30 98 | 34 1 20 34 99 | 35 1 21 22 100 | 36 1 22 25 101 | 37 1 23 27 102 | 38 1 24 25 103 | 39 1 24 27 104 | 40 1 25 26 105 | 41 1 27 28 106 | 42 1 29 30 107 | 43 1 29 33 108 | 44 1 31 32 109 | 45 1 32 36 110 | 46 1 32 33 111 | 47 1 34 35 112 | 48 1 35 36 113 | -------------------------------------------------------------------------------- /examples/cg_zif8/ZIF-8-sod.cif: -------------------------------------------------------------------------------- 1 | ####################################################################### 2 | # 3 | # This file contains crystal structure data downloaded from the 4 | # Cambridge Structural Database (CSD) hosted by the Cambridge 5 | # Crystallographic Data Centre (CCDC). 6 | # 7 | # Full information about CCDC data access policies and citation 8 | # guidelines are available at http://www.ccdc.cam.ac.uk/access/V1 9 | # 10 | # Audit and citation data items may have been added by the CCDC. 11 | # Please retain this information to preserve the provenance of 12 | # this file and to allow appropriate attribution of the data. 13 | # 14 | ####################################################################### 15 | 16 | data_zif8_100k_0m 17 | _audit_block_doi 10.5517/ccy0cy7 18 | _database_code_depnum_ccdc_archive 'CCDC 864309' 19 | loop_ 20 | _citation_id 21 | _citation_doi 22 | _citation_year 23 | 1 10.1021/jp303907p 2012 24 | _audit_update_record 25 | ; 26 | 2012-01-24 deposited with the CCDC. 2023-06-20 downloaded from the CCDC. 27 | ; 28 | #TrackingRef 'web_deposit_cif_file_0_WilliamMorris_1327431059.zif-8-100K.cif' 29 | 30 | 31 | _audit_creation_method SHELXL-97 32 | _chemical_name_systematic 33 | ; 34 | ? 35 | ; 36 | _chemical_name_common ? 37 | _chemical_melting_point ? 38 | _chemical_formula_moiety ? 39 | _chemical_formula_sum 'C24 H30 N12 O4 Zn3' 40 | _chemical_formula_weight 746.7 41 | 42 | loop_ 43 | _atom_type_symbol 44 | _atom_type_description 45 | _atom_type_scat_dispersion_real 46 | _atom_type_scat_dispersion_imag 47 | _atom_type_scat_source 48 | C C 0.0181 0.0091 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 49 | N N 0.0311 0.0180 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 50 | Zn Zn -1.5491 0.6778 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 51 | O O 0.0492 0.0322 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 52 | H H 0.0000 0.0000 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' 53 | 54 | _symmetry_cell_setting ? 55 | _symmetry_space_group_name_H-M I-43m 56 | 57 | loop_ 58 | _symmetry_equiv_pos_as_xyz 59 | 'x, y, z' 60 | '-x, -y, z' 61 | '-x, y, -z' 62 | 'x, -y, -z' 63 | 'z, x, y' 64 | 'z, -x, -y' 65 | '-z, -x, y' 66 | '-z, x, -y' 67 | 'y, z, x' 68 | '-y, z, -x' 69 | 'y, -z, -x' 70 | '-y, -z, x' 71 | 'y, x, z' 72 | '-y, -x, z' 73 | 'y, -x, -z' 74 | '-y, x, -z' 75 | 'x, z, y' 76 | '-x, z, -y' 77 | '-x, -z, y' 78 | 'x, -z, -y' 79 | 'z, y, x' 80 | 'z, -y, -x' 81 | '-z, y, -x' 82 | '-z, -y, x' 83 | 'x+1/2, y+1/2, z+1/2' 84 | '-x+1/2, -y+1/2, z+1/2' 85 | '-x+1/2, y+1/2, -z+1/2' 86 | 'x+1/2, -y+1/2, -z+1/2' 87 | 'z+1/2, x+1/2, y+1/2' 88 | 'z+1/2, -x+1/2, -y+1/2' 89 | '-z+1/2, -x+1/2, y+1/2' 90 | '-z+1/2, x+1/2, -y+1/2' 91 | 'y+1/2, z+1/2, x+1/2' 92 | '-y+1/2, z+1/2, -x+1/2' 93 | 'y+1/2, -z+1/2, -x+1/2' 94 | '-y+1/2, -z+1/2, x+1/2' 95 | 'y+1/2, x+1/2, z+1/2' 96 | '-y+1/2, -x+1/2, z+1/2' 97 | 'y+1/2, -x+1/2, -z+1/2' 98 | '-y+1/2, x+1/2, -z+1/2' 99 | 'x+1/2, z+1/2, y+1/2' 100 | '-x+1/2, z+1/2, -y+1/2' 101 | '-x+1/2, -z+1/2, y+1/2' 102 | 'x+1/2, -z+1/2, -y+1/2' 103 | 'z+1/2, y+1/2, x+1/2' 104 | 'z+1/2, -y+1/2, -x+1/2' 105 | '-z+1/2, y+1/2, -x+1/2' 106 | '-z+1/2, -y+1/2, x+1/2' 107 | 108 | _cell_length_a 16.8509(3) 109 | _cell_length_b 16.8509(3) 110 | _cell_length_c 16.8509(3) 111 | _cell_angle_alpha 90.00 112 | _cell_angle_beta 90.00 113 | _cell_angle_gamma 90.00 114 | _cell_volume 4784.86(15) 115 | _cell_formula_units_Z 4 116 | _cell_measurement_temperature 296(2) 117 | _cell_measurement_reflns_used ? 118 | _cell_measurement_theta_min ? 119 | _cell_measurement_theta_max ? 120 | 121 | _exptl_crystal_description ? 122 | _exptl_crystal_colour ? 123 | _exptl_crystal_size_max 0.20 124 | _exptl_crystal_size_mid 0.20 125 | _exptl_crystal_size_min 0.20 126 | _exptl_crystal_density_meas ? 127 | _exptl_crystal_density_diffrn 1.037 128 | _exptl_crystal_density_method 'not measured' 129 | _exptl_crystal_F_000 1520 130 | _exptl_absorpt_coefficient_mu 2.035 131 | _exptl_absorpt_correction_type multi-scan 132 | _exptl_absorpt_correction_T_min 0.6864 133 | _exptl_absorpt_correction_T_max 0.6864 134 | _exptl_absorpt_process_details ? 135 | 136 | _exptl_special_details 137 | ; 138 | ? 139 | ; 140 | 141 | _diffrn_ambient_temperature 100(2) 142 | _diffrn_radiation_wavelength 1.54178 143 | _diffrn_radiation_type CuK\a 144 | _diffrn_radiation_source 'fine-focus sealed tube' 145 | _diffrn_radiation_monochromator graphite 146 | _diffrn_measurement_device_type ? 147 | _diffrn_measurement_method ? 148 | _diffrn_detector_area_resol_mean ? 149 | _diffrn_reflns_number 11078 150 | _diffrn_reflns_av_R_equivalents 0.0358 151 | _diffrn_reflns_av_sigmaI/netI 0.0144 152 | _diffrn_reflns_limit_h_min -15 153 | _diffrn_reflns_limit_h_max 17 154 | _diffrn_reflns_limit_k_min -17 155 | _diffrn_reflns_limit_k_max 15 156 | _diffrn_reflns_limit_l_min -17 157 | _diffrn_reflns_limit_l_max 17 158 | _diffrn_reflns_theta_min 3.71 159 | _diffrn_reflns_theta_max 53.91 160 | _reflns_number_total 573 161 | _reflns_number_gt 570 162 | _reflns_threshold_expression >2sigma(I) 163 | 164 | _computing_data_collection ? 165 | _computing_cell_refinement ? 166 | _computing_data_reduction ? 167 | _computing_structure_solution 'SHELXS-97 (Sheldrick, 2008)' 168 | _computing_structure_refinement 'SHELXL-97 (Sheldrick, 2008)' 169 | _computing_molecular_graphics ? 170 | _computing_publication_material ? 171 | 172 | _refine_special_details 173 | ; 174 | Refinement of F^2^ against ALL reflections. The weighted R-factor wR and 175 | goodness of fit S are based on F^2^, conventional R-factors R are based 176 | on F, with F set to zero for negative F^2^. The threshold expression of 177 | F^2^ > 2sigma(F^2^) is used only for calculating R-factors(gt) etc. and is 178 | not relevant to the choice of reflections for refinement. R-factors based 179 | on F^2^ are statistically about twice as large as those based on F, and R- 180 | factors based on ALL data will be even larger. 181 | ; 182 | 183 | _refine_ls_structure_factor_coef Fsqd 184 | _refine_ls_matrix_type full 185 | _refine_ls_weighting_scheme calc 186 | _refine_ls_weighting_details 187 | 'calc w=1/[\s^2^(Fo^2^)+(0.1000P)^2^+0.0000P] where P=(Fo^2^+2Fc^2^)/3' 188 | _atom_sites_solution_primary direct 189 | _atom_sites_solution_secondary difmap 190 | _atom_sites_solution_hydrogens geom 191 | _refine_ls_hydrogen_treatment constr 192 | _refine_ls_extinction_method none 193 | _refine_ls_extinction_coef ? 194 | _refine_ls_abs_structure_details 'Flack H D (1983), Acta Cryst. A39, 876-881' 195 | _refine_ls_abs_structure_Flack 0.04(12) 196 | _refine_ls_number_reflns 573 197 | _refine_ls_number_parameters 40 198 | _refine_ls_number_restraints 0 199 | _refine_ls_R_factor_all 0.0689 200 | _refine_ls_R_factor_gt 0.0688 201 | _refine_ls_wR_factor_ref 0.2090 202 | _refine_ls_wR_factor_gt 0.2089 203 | _refine_ls_goodness_of_fit_ref 2.098 204 | _refine_ls_restrained_S_all 2.098 205 | _refine_ls_shift/su_max 0.000 206 | _refine_ls_shift/su_mean 0.000 207 | 208 | loop_ 209 | _atom_site_label 210 | _atom_site_type_symbol 211 | _atom_site_fract_x 212 | _atom_site_fract_y 213 | _atom_site_fract_z 214 | _atom_site_U_iso_or_equiv 215 | _atom_site_adp_type 216 | _atom_site_occupancy 217 | _atom_site_symmetry_multiplicity 218 | _atom_site_calc_flag 219 | _atom_site_refinement_flags 220 | _atom_site_disorder_assembly 221 | _atom_site_disorder_group 222 | Zn1 Zn 0.5000 0.0000 0.2500 0.0503(9) Uani 1 4 d S . . 223 | C3 C 0.6240(3) 0.0053(10) 0.3760(3) 0.049(2) Uani 1 2 d S . . 224 | N1 N 0.5883(4) -0.0357(3) 0.3173(4) 0.0529(14) Uani 1 1 d . . . 225 | C1 C 0.6276(5) -0.1088(4) 0.3160(6) 0.063(2) Uani 1 1 d . . . 226 | H1 H 0.6165 -0.1506 0.2817 0.076 Uiso 1 1 calc R . . 227 | C4 C 0.5985(6) 0.0861(6) 0.4015(6) 0.062(3) Uani 1 2 d S . . 228 | H4A H 0.5570 0.1047 0.3672 0.093 Uiso 0.50 1 calc PR . . 229 | H4B H 0.6428 0.1218 0.3988 0.093 Uiso 0.50 1 calc PR . . 230 | H4C H 0.5791 0.0839 0.4551 0.093 Uiso 0.50 1 calc PR . . 231 | O1 O 0.6920(11) 0.6920(11) 0.3080(11) 0.126(8) Uani 1 6 d S . . 232 | O2 O 0.816(3) 0.816(3) 0.184(3) 0.51(9) Uani 1 6 d S . . 233 | 234 | loop_ 235 | _atom_site_aniso_label 236 | _atom_site_aniso_U_11 237 | _atom_site_aniso_U_22 238 | _atom_site_aniso_U_33 239 | _atom_site_aniso_U_23 240 | _atom_site_aniso_U_13 241 | _atom_site_aniso_U_12 242 | Zn1 0.0507(9) 0.0507(9) 0.0496(11) 0.000 0.000 0.000 243 | C3 0.053(3) 0.041(5) 0.053(3) -0.001(4) 0.005(4) 0.001(4) 244 | N1 0.056(3) 0.049(3) 0.054(3) -0.002(3) -0.007(3) 0.001(3) 245 | C1 0.071(5) 0.046(4) 0.071(5) -0.009(4) -0.017(4) 0.007(4) 246 | C4 0.064(4) 0.057(6) 0.064(4) -0.005(4) -0.010(6) 0.005(4) 247 | O1 0.126(8) 0.126(8) 0.126(8) -0.011(9) -0.011(9) 0.011(9) 248 | O2 0.51(9) 0.51(9) 0.51(9) 0.11(7) 0.11(7) -0.11(7) 249 | 250 | _geom_special_details 251 | ; 252 | All esds (except the esd in the dihedral angle between two l.s. planes) 253 | are estimated using the full covariance matrix. The cell esds are taken 254 | into account individually in the estimation of esds in distances, angles 255 | and torsion angles; correlations between esds in cell parameters are only 256 | used when they are defined by crystal symmetry. An approximate (isotropic) 257 | treatment of cell esds is used for estimating esds involving l.s. planes. 258 | ; 259 | 260 | loop_ 261 | _geom_bond_atom_site_label_1 262 | _geom_bond_atom_site_label_2 263 | _geom_bond_distance 264 | _geom_bond_site_symmetry_2 265 | _geom_bond_publ_flag 266 | Zn1 N1 1.966(6) . ? 267 | Zn1 N1 1.966(6) 39 ? 268 | Zn1 N1 1.966(6) 40_545 ? 269 | Zn1 N1 1.966(6) 2_655 ? 270 | C3 N1 1.347(10) . ? 271 | C3 N1 1.347(10) 23_656 ? 272 | C3 C4 1.49(2) . ? 273 | N1 C1 1.399(10) . ? 274 | C1 C1 1.344(16) 23_656 ? 275 | 276 | loop_ 277 | _geom_angle_atom_site_label_1 278 | _geom_angle_atom_site_label_2 279 | _geom_angle_atom_site_label_3 280 | _geom_angle 281 | _geom_angle_site_symmetry_1 282 | _geom_angle_site_symmetry_3 283 | _geom_angle_publ_flag 284 | N1 Zn1 N1 109.5(2) . 39 ? 285 | N1 Zn1 N1 109.5(2) . 40_545 ? 286 | N1 Zn1 N1 109.5(4) 39 40_545 ? 287 | N1 Zn1 N1 109.5(4) . 2_655 ? 288 | N1 Zn1 N1 109.5(2) 39 2_655 ? 289 | N1 Zn1 N1 109.5(2) 40_545 2_655 ? 290 | N1 C3 N1 113.1(12) . 23_656 ? 291 | N1 C3 C4 123.4(6) . . ? 292 | N1 C3 C4 123.4(6) 23_656 . ? 293 | C3 N1 C1 104.6(9) . . ? 294 | C3 N1 Zn1 127.2(7) . . ? 295 | C1 N1 Zn1 128.2(6) . . ? 296 | C1 C1 N1 108.8(5) 23_656 . ? 297 | 298 | _diffrn_measured_fraction_theta_max 1.000 299 | _diffrn_reflns_theta_full 53.91 300 | _diffrn_measured_fraction_theta_full 1.000 301 | _refine_diff_density_max 0.949 302 | _refine_diff_density_min -0.443 303 | _refine_diff_density_rms 0.201 304 | -------------------------------------------------------------------------------- /examples/cg_zif_imidzb11/imidzb11-cg.cif: -------------------------------------------------------------------------------- 1 | data_ZIF-4 2 | _chemical_formula_sum 'AB4C6D6' 3 | _cell_length_a 15.50050 4 | _cell_length_b 15.52010 5 | _cell_length_c 18.05820 6 | _cell_angle_alpha 90.00000 7 | _cell_angle_beta 90.00000 8 | _cell_angle_gamma 90.00000 9 | _cell_volume 4344.24871 10 | _cell_formula_units_Z 16 11 | _symmetry_space_group_name_H-M 'P 1' 12 | _symmetry_Int_Tables_number 1 13 | loop_ 14 | _symmetry_equiv_pos_site_id 15 | _symmetry_equiv_pos_as_xyz 16 | 1 x,y,z 17 | loop_ 18 | _atom_site_label 19 | _atom_site_type_symbol 20 | _atom_site_symmetry_multiplicity 21 | _atom_site_fract_x 22 | _atom_site_fract_y 23 | _atom_site_fract_z 24 | _atom_site_occupancy 25 | Si-1 Si 1 0.9946000000 0.3438000000 0.6877000000 1 26 | Si-2 Si 1 0.9946000000 0.1562000000 0.1877000000 1 27 | Si-3 Si 1 0.8002000000 0.1457000000 0.9088000000 1 28 | Si-4 Si 1 0.8002000000 0.3543000000 0.4088000000 1 29 | Si-5 Si 1 0.0054000000 0.6562000000 0.3123000000 1 30 | Si-6 Si 1 0.1998000000 0.6457000000 0.5912000000 1 31 | Si-7 Si 1 0.0054000000 0.8438000000 0.8123000000 1 32 | Si-8 Si 1 0.1998000000 0.8543000000 0.0912000000 1 33 | Si-9 Si 1 0.4946000000 0.1562000000 0.3123000000 1 34 | Si-10 Si 1 0.3002000000 0.1457000000 0.5912000000 1 35 | Si-11 Si 1 0.4946000000 0.3438000000 0.8123000000 1 36 | Si-12 Si 1 0.3002000000 0.3543000000 0.0912000000 1 37 | Si-13 Si 1 0.5054000000 0.6562000000 0.1877000000 1 38 | Si-14 Si 1 0.6998000000 0.6457000000 0.9088000000 1 39 | Si-15 Si 1 0.5054000000 0.8438000000 0.6877000000 1 40 | Si-16 Si 1 0.6998000000 0.8543000000 0.4088000000 1 41 | O-1 O 1 0.1392637500 0.0106875000 0.1987475000 1 42 | O-2 O 1 0.9037537500 0.1933487500 0.3420912500 1 43 | O-3 O 1 0.0953162500 0.3176604200 0.1277775000 1 44 | O-4 O 1 0.8428950000 0.1109275000 0.0796475000 1 45 | O-5 O 1 0.1392637500 0.4893125000 0.6987475000 1 46 | O-6 O 1 0.9037537500 0.3066512500 0.8420912500 1 47 | O-7 O 1 0.0953162500 0.1823395800 0.6277775000 1 48 | O-8 O 1 0.8428950000 0.3890725000 0.5796475000 1 49 | O-9 O 1 0.8607362500 0.5106875000 0.3012525000 1 50 | O-10 O 1 0.0962462500 0.6933487500 0.1579087500 1 51 | O-11 O 1 0.9046837500 0.8176604200 0.3722225000 1 52 | O-12 O 1 0.1571050000 0.6109275000 0.4203525000 1 53 | O-13 O 1 0.8607362500 0.9893125000 0.8012525000 1 54 | O-14 O 1 0.0962462500 0.8066512500 0.6579087500 1 55 | O-15 O 1 0.9046837500 0.6823395800 0.8722225000 1 56 | O-16 O 1 0.1571050000 0.8890725000 0.9203525000 1 57 | O-17 O 1 0.6392637500 0.0106875000 0.3012525000 1 58 | O-18 O 1 0.4046837500 0.6823395800 0.6277775000 1 59 | O-19 O 1 0.6571050000 0.8890725000 0.5796475000 1 60 | O-20 O 1 0.4037537500 0.1933487500 0.1579087500 1 61 | O-21 O 1 0.5953162500 0.3176604200 0.3722225000 1 62 | O-22 O 1 0.3428950000 0.1109275000 0.4203525000 1 63 | O-23 O 1 0.6392637500 0.4893125000 0.8012525000 1 64 | O-24 O 1 0.4037537500 0.3066512500 0.6579087500 1 65 | O-25 O 1 0.5953162500 0.1823395800 0.8722225000 1 66 | O-26 O 1 0.3428950000 0.3890725000 0.9203525000 1 67 | O-27 O 1 0.3607362500 0.5106875000 0.1987475000 1 68 | O-28 O 1 0.5962462500 0.6933487500 0.3420912500 1 69 | O-29 O 1 0.4046837500 0.8176604200 0.1277775000 1 70 | O-30 O 1 0.6571050000 0.6109275000 0.0796475000 1 71 | O-31 O 1 0.3607362500 0.9893125000 0.6987475000 1 72 | O-32 O 1 0.5962462500 0.8066512500 0.8420912500 1 73 | loop_ 74 | _topol_link.node_label_1 75 | _topol_link.node_label_2 76 | _topol_link.distance 77 | _topol_link.site_symmetry_symop_1 78 | _topol_link.site_symmetry_translation_1_x 79 | _topol_link.site_symmetry_translation_1_y 80 | _topol_link.site_symmetry_translation_1_z 81 | _topol_link.site_symmetry_symop_2 82 | _topol_link.site_symmetry_translation_2_x 83 | _topol_link.site_symmetry_translation_2_y 84 | _topol_link.site_symmetry_translation_2_z 85 | _topol_link.type 86 | _topol_link.multiplicity 87 | Si-1 O-8 3.13537 1 0 0 0 1 0 0 0 V 1 88 | Si-1 O-7 3.14445 1 0 0 0 1 1 0 0 V 1 89 | Si-1 O-6 3.17623 1 0 0 0 1 0 0 0 V 1 90 | Si-1 O-5 3.18876 1 0 0 0 1 1 0 0 V 1 91 | Si-2 O-4 3.13537 1 0 0 0 1 0 0 0 V 1 92 | Si-2 O-3 3.14445 1 0 0 0 1 1 0 0 V 1 93 | Si-2 O-2 3.17623 1 0 0 0 1 0 0 0 V 1 94 | Si-2 O-1 3.18876 1 0 0 0 1 1 0 0 V 1 95 | Si-3 O-6 3.20430 1 0 0 0 1 0 0 0 V 1 96 | Si-3 O-4 3.20120 1 0 0 0 1 0 0 1 V 1 97 | Si-3 O-13 3.24705 1 0 0 0 1 0 -1 0 V 1 98 | Si-3 O-25 3.29323 1 0 0 0 1 0 0 0 V 1 99 | Si-4 O-2 3.20430 1 0 0 0 1 0 0 0 V 1 100 | Si-4 O-8 3.20120 1 0 0 0 1 0 0 0 V 1 101 | Si-4 O-9 3.24705 1 0 0 0 1 0 0 0 V 1 102 | Si-4 O-21 3.29323 1 0 0 0 1 0 0 0 V 1 103 | Si-5 O-12 3.13537 1 0 0 0 1 0 0 0 V 1 104 | Si-5 O-11 3.14445 1 0 0 0 1 -1 0 0 V 1 105 | Si-5 O-10 3.17623 1 0 0 0 1 0 0 0 V 1 106 | Si-5 O-9 3.18876 1 0 0 0 1 -1 0 0 V 1 107 | Si-6 O-14 3.20430 1 0 0 0 1 0 0 0 V 1 108 | Si-6 O-12 3.20120 1 0 0 0 1 0 0 0 V 1 109 | Si-6 O-5 3.24705 1 0 0 0 1 0 0 0 V 1 110 | Si-6 O-18 3.29323 1 0 0 0 1 0 0 0 V 1 111 | Si-7 O-16 3.13537 1 0 0 0 1 0 0 0 V 1 112 | Si-7 O-15 3.14445 1 0 0 0 1 -1 0 0 V 1 113 | Si-7 O-14 3.17623 1 0 0 0 1 0 0 0 V 1 114 | Si-7 O-13 3.18876 1 0 0 0 1 -1 0 0 V 1 115 | Si-8 O-10 3.20430 1 0 0 0 1 0 0 0 V 1 116 | Si-8 O-16 3.20120 1 0 0 0 1 0 0 -1 V 1 117 | Si-8 O-1 3.24705 1 0 0 0 1 0 1 0 V 1 118 | Si-8 O-29 3.29323 1 0 0 0 1 0 0 0 V 1 119 | Si-9 O-22 3.13537 1 0 0 0 1 0 0 0 V 1 120 | Si-9 O-21 3.14445 1 0 0 0 1 0 0 0 V 1 121 | Si-9 O-20 3.17623 1 0 0 0 1 0 0 0 V 1 122 | Si-9 O-17 3.18876 1 0 0 0 1 0 0 0 V 1 123 | Si-10 O-24 3.20430 1 0 0 0 1 0 0 0 V 1 124 | Si-10 O-22 3.20120 1 0 0 0 1 0 0 0 V 1 125 | Si-10 O-31 3.24705 1 0 0 0 1 0 -1 0 V 1 126 | Si-10 O-7 3.29323 1 0 0 0 1 0 0 0 V 1 127 | Si-11 O-26 3.13537 1 0 0 0 1 0 0 0 V 1 128 | Si-11 O-25 3.14445 1 0 0 0 1 0 0 0 V 1 129 | Si-11 O-24 3.17623 1 0 0 0 1 0 0 0 V 1 130 | Si-11 O-23 3.18876 1 0 0 0 1 0 0 0 V 1 131 | Si-12 O-20 3.20430 1 0 0 0 1 0 0 0 V 1 132 | Si-12 O-26 3.20120 1 0 0 0 1 0 0 -1 V 1 133 | Si-12 O-27 3.24705 1 0 0 0 1 0 0 0 V 1 134 | Si-12 O-3 3.29323 1 0 0 0 1 0 0 0 V 1 135 | Si-13 O-30 3.13537 1 0 0 0 1 0 0 0 V 1 136 | Si-13 O-29 3.14445 1 0 0 0 1 0 0 0 V 1 137 | Si-13 O-28 3.17623 1 0 0 0 1 0 0 0 V 1 138 | Si-13 O-27 3.18876 1 0 0 0 1 0 0 0 V 1 139 | Si-14 O-32 3.20430 1 0 0 0 1 0 0 0 V 1 140 | Si-14 O-30 3.20120 1 0 0 0 1 0 0 1 V 1 141 | Si-14 O-23 3.24705 1 0 0 0 1 0 0 0 V 1 142 | Si-14 O-15 3.29323 1 0 0 0 1 0 0 0 V 1 143 | Si-15 O-19 3.13537 1 0 0 0 1 0 0 0 V 1 144 | Si-15 O-18 3.14445 1 0 0 0 1 0 0 0 V 1 145 | Si-15 O-32 3.17623 1 0 0 0 1 0 0 0 V 1 146 | Si-15 O-31 3.18876 1 0 0 0 1 0 0 0 V 1 147 | Si-16 O-28 3.20430 1 0 0 0 1 0 0 0 V 1 148 | Si-16 O-19 3.20120 1 0 0 0 1 0 0 0 V 1 149 | Si-16 O-17 3.24705 1 0 0 0 1 0 1 0 V 1 150 | Si-16 O-11 3.29323 1 0 0 0 1 0 0 0 V 1 151 | #End of data_ZIF-4 152 | 153 | -------------------------------------------------------------------------------- /examples/cg_zif_imidzb11/imidzb11-cg.data: -------------------------------------------------------------------------------- 1 | # 'ZIF-4' generated by CHIC (2023-08-16 14:10:51.327859) 2 | 3 | 48 atoms 4 | 0 bonds 5 | 0 angles 6 | 0 dihedrals 7 | 0 impropers 8 | 9 | 2 atom types 10 | 0 bond types 11 | 0 angle types 12 | 0 dihedral types 13 | 0 improper types 14 | 15 | 0.000000 15.500500 xlo xhi 16 | 0.000000 15.520100 ylo yhi 17 | 0.000000 18.058200 zlo zhi 18 | 19 | Masses 20 | 21 | 1 15.9994 # O 22 | 2 28.0855 # Si 23 | 24 | Atoms # style = "full" 25 | 26 | 1 1 2 0.00000 15.4167973000 5.3358103800 12.4186241400 27 | 2 2 2 0.00000 15.4167973000 2.4242396200 3.3895241400 28 | 3 3 2 0.00000 12.4035001000 2.2612785700 16.4112921600 29 | 4 4 2 0.00000 12.4035001000 5.4987714300 7.3821921600 30 | 5 5 2 0.00000 0.0837027000 10.1842896200 5.6395758600 31 | 6 6 2 0.00000 3.0969999000 10.0213285700 10.6760078400 32 | 7 7 2 0.00000 0.0837027000 13.0958603800 14.6686758600 33 | 8 8 2 0.00000 3.0969999000 13.2588214300 1.6469078400 34 | 9 9 2 0.00000 7.6665473000 2.4242396200 5.6395758600 35 | 10 10 2 0.00000 4.6532501000 2.2612785700 10.6760078400 36 | 11 11 2 0.00000 7.6665473000 5.3358103800 14.6686758600 37 | 12 12 2 0.00000 4.6532501000 5.4987714300 1.6469078400 38 | 13 13 2 0.00000 7.8339527000 10.1842896200 3.3895241400 39 | 14 14 2 0.00000 10.8472499000 10.0213285700 16.4112921600 40 | 15 15 2 0.00000 7.8339527000 13.0958603800 12.4186241400 41 | 16 16 2 0.00000 10.8472499000 13.2588214300 7.3821921600 42 | 17 17 1 0.00000 2.0736878910 0.1601674320 3.4473103800 43 | 18 18 1 0.00000 13.9929213700 3.1254377380 6.0700833480 44 | 19 19 1 0.00000 1.5741997790 4.7986701175 2.3334444876 45 | 20 20 1 0.00000 13.1866163610 1.8043357858 1.3623106080 46 | 21 21 1 0.00000 2.0736878910 7.5998825680 12.4764103800 47 | 22 22 1 0.00000 13.9929213700 4.6346122620 15.0991833480 48 | 23 23 1 0.00000 1.5741997790 2.9613798825 11.3625444876 49 | 24 24 1 0.00000 13.1866163610 5.9557142142 10.3914106080 50 | 25 25 1 0.00000 13.4268121090 7.9202174320 5.5817896200 51 | 26 26 1 0.00000 1.5075786300 10.8854877380 2.9590166520 52 | 27 27 1 0.00000 13.9263002210 12.5587201175 6.6956555124 53 | 28 28 1 0.00000 2.3138836390 9.5643857858 7.6667893920 54 | 29 29 1 0.00000 13.4268121090 15.3599325680 14.6108896200 55 | 30 30 1 0.00000 1.5075786300 12.3946622620 11.9881166520 56 | 31 31 1 0.00000 13.9263002210 10.7214298825 15.7247555124 57 | 32 32 1 0.00000 2.3138836390 13.7157642142 16.6958893920 58 | 33 33 1 0.00000 9.8239378910 0.1601674320 5.5817896200 59 | 34 34 1 0.00000 6.1760502210 10.7214298825 11.3625444876 60 | 35 35 1 0.00000 10.0641336390 13.7157642142 10.3914106080 61 | 36 36 1 0.00000 6.2426713700 3.1254377380 2.9590166520 62 | 37 37 1 0.00000 9.3244497790 4.7986701175 6.6956555124 63 | 38 38 1 0.00000 5.4363663610 1.8043357858 7.6667893920 64 | 39 39 1 0.00000 9.8239378910 7.5998825680 14.6108896200 65 | 40 40 1 0.00000 6.2426713700 4.6346122620 11.9881166520 66 | 41 41 1 0.00000 9.3244497790 2.9613798825 15.7247555124 67 | 42 42 1 0.00000 5.4363663610 5.9557142142 16.6958893920 68 | 43 43 1 0.00000 5.6765621090 7.9202174320 3.4473103800 69 | 44 44 1 0.00000 9.2578286300 10.8854877380 6.0700833480 70 | 45 45 1 0.00000 6.1760502210 12.5587201175 2.3334444876 71 | 46 46 1 0.00000 10.0641336390 9.5643857858 1.3623106080 72 | 47 47 1 0.00000 5.6765621090 15.3599325680 12.4764103800 73 | 48 48 1 0.00000 9.2578286300 12.3946622620 15.0991833480 74 | 75 | -------------------------------------------------------------------------------- /examples/decorate_sod/ZIF-8-sod-cg-decorated-H.cif: -------------------------------------------------------------------------------- 1 | data_image0 2 | _chemical_formula_structural C72H72N48Zn12 3 | _chemical_formula_sum "C72 H72 N48 Zn12" 4 | _cell_length_a 16.8509 5 | _cell_length_b 16.8509 6 | _cell_length_c 16.8509 7 | _cell_angle_alpha 90 8 | _cell_angle_beta 90 9 | _cell_angle_gamma 90 10 | 11 | _space_group_name_H-M_alt "P 1" 12 | _space_group_IT_number 1 13 | 14 | loop_ 15 | _space_group_symop_operation_xyz 16 | 'x, y, z' 17 | 18 | loop_ 19 | _atom_site_type_symbol 20 | _atom_site_label 21 | _atom_site_symmetry_multiplicity 22 | _atom_site_fract_x 23 | _atom_site_fract_y 24 | _atom_site_fract_z 25 | _atom_site_occupancy 26 | C C1 1.0 0.11416 0.54661 0.88584 1.0000 27 | C C2 1.0 0.17055 0.42972 0.88791 1.0000 28 | C C3 1.0 0.11209 0.42972 0.82944 1.0000 29 | C C4 1.0 0.04661 0.38584 0.61416 1.0000 30 | C C5 1.0 0.92973 0.32942 0.61211 1.0000 31 | C C6 1.0 0.92974 0.38787 0.67059 1.0000 32 | C C7 1.0 0.88584 0.54661 0.11416 1.0000 33 | C C8 1.0 0.88788 0.42974 0.17058 1.0000 34 | C C9 1.0 0.82942 0.42974 0.11212 1.0000 35 | C C10 1.0 0.88584 0.45339 0.88584 1.0000 36 | C C11 1.0 0.88790 0.57027 0.82944 1.0000 37 | C C12 1.0 0.82940 0.57025 0.88786 1.0000 38 | C C13 1.0 0.61416 0.38584 0.04661 1.0000 39 | C C14 1.0 0.61211 0.32943 0.92973 1.0000 40 | C C15 1.0 0.67054 0.38793 0.92971 1.0000 41 | C C16 1.0 0.11416 0.88584 0.54661 1.0000 42 | C C17 1.0 0.17059 0.88788 0.42974 1.0000 43 | C C18 1.0 0.11212 0.82942 0.42974 1.0000 44 | C C19 1.0 0.04661 0.61416 0.38584 1.0000 45 | C C20 1.0 0.92973 0.61210 0.32944 1.0000 46 | C C21 1.0 0.92972 0.67055 0.38792 1.0000 47 | C C22 1.0 0.54661 0.88584 0.11416 1.0000 48 | C C23 1.0 0.42972 0.88791 0.17056 1.0000 49 | C C24 1.0 0.42972 0.82945 0.11209 1.0000 50 | C C25 1.0 0.45339 0.88584 0.88584 1.0000 51 | C C26 1.0 0.57026 0.82941 0.88788 1.0000 52 | C C27 1.0 0.57026 0.88789 0.82942 1.0000 53 | C C28 1.0 0.54661 0.11416 0.88584 1.0000 54 | C C29 1.0 0.42973 0.11210 0.82944 1.0000 55 | C C30 1.0 0.42972 0.17055 0.88792 1.0000 56 | C C31 1.0 0.38584 0.04661 0.61416 1.0000 57 | C C32 1.0 0.32944 0.92972 0.61209 1.0000 58 | C C33 1.0 0.38791 0.92972 0.67055 1.0000 59 | C C34 1.0 0.88584 0.88584 0.45339 1.0000 60 | C C35 1.0 0.82940 0.88786 0.57025 1.0000 61 | C C36 1.0 0.88790 0.82944 0.57027 1.0000 62 | C C37 1.0 0.88584 0.11416 0.54661 1.0000 63 | C C38 1.0 0.88791 0.17055 0.42972 1.0000 64 | C C39 1.0 0.82944 0.11209 0.42973 1.0000 65 | C C40 1.0 0.38584 0.95339 0.38584 1.0000 66 | C C41 1.0 0.32942 0.07026 0.38788 1.0000 67 | C C42 1.0 0.38788 0.07026 0.32942 1.0000 68 | C C43 1.0 0.38584 0.38584 0.95339 1.0000 69 | C C44 1.0 0.38791 0.32944 0.07028 1.0000 70 | C C45 1.0 0.32945 0.38791 0.07028 1.0000 71 | C C46 1.0 0.45339 0.11416 0.11416 1.0000 72 | C C47 1.0 0.57026 0.17059 0.11213 1.0000 73 | C C48 1.0 0.57027 0.11211 0.17057 1.0000 74 | C C49 1.0 0.11416 0.11416 0.45339 1.0000 75 | C C50 1.0 0.11207 0.17053 0.57029 1.0000 76 | C C51 1.0 0.17057 0.11211 0.57027 1.0000 77 | C C52 1.0 0.61416 0.04661 0.38584 1.0000 78 | C C53 1.0 0.61212 0.92974 0.32941 1.0000 79 | C C54 1.0 0.67058 0.92974 0.38788 1.0000 80 | C C55 1.0 0.95339 0.38584 0.38584 1.0000 81 | C C56 1.0 0.07026 0.32941 0.38788 1.0000 82 | C C57 1.0 0.07026 0.38789 0.32942 1.0000 83 | C C58 1.0 0.11416 0.45339 0.11416 1.0000 84 | C C59 1.0 0.11209 0.57028 0.17055 1.0000 85 | C C60 1.0 0.17055 0.57028 0.11209 1.0000 86 | C C61 1.0 0.95339 0.61416 0.61416 1.0000 87 | C C62 1.0 0.07028 0.61207 0.67054 1.0000 88 | C C63 1.0 0.07027 0.67057 0.61211 1.0000 89 | C C64 1.0 0.61416 0.61416 0.95339 1.0000 90 | C C65 1.0 0.67058 0.61212 0.07026 1.0000 91 | C C66 1.0 0.61212 0.67059 0.07026 1.0000 92 | C C67 1.0 0.61416 0.95339 0.61416 1.0000 93 | C C68 1.0 0.61209 0.07028 0.67055 1.0000 94 | C C69 1.0 0.67055 0.07028 0.61209 1.0000 95 | C C70 1.0 0.38584 0.61416 0.04661 1.0000 96 | C C71 1.0 0.38791 0.67055 0.92972 1.0000 97 | C C72 1.0 0.32944 0.61209 0.92973 1.0000 98 | H H1 1.0 0.21184 0.38298 0.90651 1.0000 99 | H H2 1.0 0.09349 0.38299 0.78815 1.0000 100 | H H3 1.0 0.10048 0.60883 0.89952 1.0000 101 | H H4 1.0 0.88259 0.28900 0.59264 1.0000 102 | H H5 1.0 0.88260 0.40734 0.71103 1.0000 103 | H H6 1.0 0.10817 0.40093 0.59907 1.0000 104 | H H7 1.0 0.90735 0.38260 0.21101 1.0000 105 | H H8 1.0 0.78899 0.38260 0.09265 1.0000 106 | H H9 1.0 0.90093 0.60817 0.09907 1.0000 107 | H H10 1.0 0.90739 0.61742 0.78903 1.0000 108 | H H11 1.0 0.78895 0.61738 0.90731 1.0000 109 | H H12 1.0 0.90093 0.39183 0.90093 1.0000 110 | H H13 1.0 0.59353 0.28812 0.88300 1.0000 111 | H H14 1.0 0.71181 0.40655 0.88297 1.0000 112 | H H15 1.0 0.60048 0.39952 0.10883 1.0000 113 | H H16 1.0 0.21102 0.90734 0.38260 1.0000 114 | H H17 1.0 0.09264 0.78899 0.38259 1.0000 115 | H H18 1.0 0.09907 0.90093 0.60817 1.0000 116 | H H19 1.0 0.88299 0.59351 0.28814 1.0000 117 | H H20 1.0 0.88298 0.71183 0.40653 1.0000 118 | H H21 1.0 0.10883 0.60048 0.39952 1.0000 119 | H H22 1.0 0.38299 0.90651 0.21185 1.0000 120 | H H23 1.0 0.38298 0.78816 0.09348 1.0000 121 | H H24 1.0 0.60883 0.89952 0.10048 1.0000 122 | H H25 1.0 0.61740 0.78898 0.90734 1.0000 123 | H H26 1.0 0.61741 0.90736 0.78900 1.0000 124 | H H27 1.0 0.39183 0.90093 0.90093 1.0000 125 | H H28 1.0 0.38299 0.09351 0.78814 1.0000 126 | H H29 1.0 0.38298 0.21183 0.90653 1.0000 127 | H H30 1.0 0.60883 0.10048 0.89952 1.0000 128 | H H31 1.0 0.28815 0.88299 0.59349 1.0000 129 | H H32 1.0 0.40652 0.88298 0.71184 1.0000 130 | H H33 1.0 0.39952 0.10883 0.60048 1.0000 131 | H H34 1.0 0.78895 0.90731 0.61739 1.0000 132 | H H35 1.0 0.90739 0.78903 0.61742 1.0000 133 | H H36 1.0 0.90093 0.90093 0.39183 1.0000 134 | H H37 1.0 0.90652 0.21184 0.38298 1.0000 135 | H H38 1.0 0.78815 0.09349 0.38299 1.0000 136 | H H39 1.0 0.89952 0.10048 0.60883 1.0000 137 | H H40 1.0 0.28899 0.11740 0.40735 1.0000 138 | H H41 1.0 0.40735 0.11740 0.28899 1.0000 139 | H H42 1.0 0.40093 0.89183 0.40093 1.0000 140 | H H43 1.0 0.40651 0.28815 0.11701 1.0000 141 | H H44 1.0 0.28816 0.40652 0.11702 1.0000 142 | H H45 1.0 0.39952 0.39952 0.89117 1.0000 143 | H H46 1.0 0.61739 0.21103 0.09267 1.0000 144 | H H47 1.0 0.61741 0.09263 0.21099 1.0000 145 | H H48 1.0 0.39183 0.09907 0.09907 1.0000 146 | H H49 1.0 0.09345 0.21181 0.61703 1.0000 147 | H H50 1.0 0.21189 0.09353 0.61700 1.0000 148 | H H51 1.0 0.10048 0.10048 0.39117 1.0000 149 | H H52 1.0 0.59266 0.88260 0.28898 1.0000 150 | H H53 1.0 0.71101 0.88259 0.40736 1.0000 151 | H H54 1.0 0.59907 0.10817 0.40093 1.0000 152 | H H55 1.0 0.11740 0.28898 0.40734 1.0000 153 | H H56 1.0 0.11741 0.40736 0.28900 1.0000 154 | H H57 1.0 0.89183 0.40093 0.40093 1.0000 155 | H H58 1.0 0.09349 0.61701 0.21185 1.0000 156 | H H59 1.0 0.21185 0.61701 0.09349 1.0000 157 | H H60 1.0 0.10048 0.39117 0.10048 1.0000 158 | H H61 1.0 0.11703 0.59345 0.71181 1.0000 159 | H H62 1.0 0.11700 0.71188 0.59352 1.0000 160 | H H63 1.0 0.89117 0.60048 0.60048 1.0000 161 | H H64 1.0 0.71100 0.59265 0.11741 1.0000 162 | H H65 1.0 0.59266 0.71102 0.11740 1.0000 163 | H H66 1.0 0.59907 0.59907 0.89183 1.0000 164 | H H67 1.0 0.59349 0.11701 0.71185 1.0000 165 | H H68 1.0 0.71185 0.11701 0.59349 1.0000 166 | H H69 1.0 0.60048 0.89117 0.60048 1.0000 167 | H H70 1.0 0.40652 0.71184 0.88298 1.0000 168 | H H71 1.0 0.28815 0.59349 0.88299 1.0000 169 | H H72 1.0 0.39952 0.60048 0.10883 1.0000 170 | N N1 1.0 0.17144 0.50415 0.92334 1.0000 171 | N N2 1.0 0.07666 0.50415 0.82856 1.0000 172 | N N3 1.0 0.00414 0.32860 0.57662 1.0000 173 | N N4 1.0 0.00415 0.42335 0.67142 1.0000 174 | N N5 1.0 0.92337 0.50414 0.17141 1.0000 175 | N N6 1.0 0.82859 0.50414 0.07663 1.0000 176 | N N7 1.0 0.92340 0.49587 0.82862 1.0000 177 | N N8 1.0 0.82856 0.49584 0.92333 1.0000 178 | N N9 1.0 0.57669 0.32853 0.00417 1.0000 179 | N N10 1.0 0.67141 0.42337 0.00414 1.0000 180 | N N11 1.0 0.17141 0.92336 0.50414 1.0000 181 | N N12 1.0 0.07663 0.82860 0.50414 1.0000 182 | N N13 1.0 0.00416 0.57668 0.32855 1.0000 183 | N N14 1.0 0.00415 0.67142 0.42335 1.0000 184 | N N15 1.0 0.50416 0.92333 0.17144 1.0000 185 | N N16 1.0 0.50415 0.82857 0.07666 1.0000 186 | N N17 1.0 0.49586 0.82858 0.92336 1.0000 187 | N N18 1.0 0.49586 0.92337 0.82860 1.0000 188 | N N19 1.0 0.50416 0.07668 0.82855 1.0000 189 | N N20 1.0 0.50415 0.17142 0.92335 1.0000 190 | N N21 1.0 0.32856 0.00416 0.57667 1.0000 191 | N N22 1.0 0.42334 0.00415 0.67143 1.0000 192 | N N23 1.0 0.82856 0.92334 0.49584 1.0000 193 | N N24 1.0 0.92340 0.82862 0.49587 1.0000 194 | N N25 1.0 0.92334 0.17143 0.50415 1.0000 195 | N N26 1.0 0.82856 0.07667 0.50416 1.0000 196 | N N27 1.0 0.32859 0.99586 0.42337 1.0000 197 | N N28 1.0 0.42337 0.99586 0.32859 1.0000 198 | N N29 1.0 0.42333 0.32856 0.99584 1.0000 199 | N N30 1.0 0.32857 0.42334 0.99585 1.0000 200 | N N31 1.0 0.49585 0.17142 0.07665 1.0000 201 | N N32 1.0 0.49587 0.07662 0.17139 1.0000 202 | N N33 1.0 0.07663 0.17141 0.49586 1.0000 203 | N N34 1.0 0.17147 0.07669 0.49583 1.0000 204 | N N35 1.0 0.57664 0.00414 0.32859 1.0000 205 | N N36 1.0 0.67140 0.00414 0.42337 1.0000 206 | N N37 1.0 0.99586 0.32858 0.42336 1.0000 207 | N N38 1.0 0.99586 0.42337 0.32860 1.0000 208 | N N39 1.0 0.07666 0.49584 0.17144 1.0000 209 | N N40 1.0 0.17144 0.49585 0.07666 1.0000 210 | N N41 1.0 0.99586 0.57663 0.67141 1.0000 211 | N N42 1.0 0.99583 0.67147 0.57669 1.0000 212 | N N43 1.0 0.67140 0.57663 0.99586 1.0000 213 | N N44 1.0 0.57664 0.67141 0.99586 1.0000 214 | N N45 1.0 0.57666 0.99584 0.67144 1.0000 215 | N N46 1.0 0.67144 0.99585 0.57666 1.0000 216 | N N47 1.0 0.42334 0.67143 0.00415 1.0000 217 | N N48 1.0 0.32856 0.57667 0.00416 1.0000 218 | Zn Zn1 1.0 0.00000 0.50000 0.75000 1.0000 219 | Zn Zn2 1.0 0.75000 0.50000 0.00000 1.0000 220 | Zn Zn3 1.0 0.00000 0.75000 0.50000 1.0000 221 | Zn Zn4 1.0 0.50000 0.75000 0.00000 1.0000 222 | Zn Zn5 1.0 0.50000 0.00000 0.75000 1.0000 223 | Zn Zn6 1.0 0.75000 0.00000 0.50000 1.0000 224 | Zn Zn7 1.0 0.50000 0.00000 0.25000 1.0000 225 | Zn Zn8 1.0 0.50000 0.25000 0.00000 1.0000 226 | Zn Zn9 1.0 0.25000 0.00000 0.50000 1.0000 227 | Zn Zn10 1.0 0.00000 0.50000 0.25000 1.0000 228 | Zn Zn11 1.0 0.00000 0.25000 0.50000 1.0000 229 | Zn Zn12 1.0 0.25000 0.50000 0.00000 1.0000 230 | -------------------------------------------------------------------------------- /examples/decorate_sod/ZIF-8-sod-cg.cif: -------------------------------------------------------------------------------- 1 | data_ZIF-8-cg 2 | _chemical_formula_sum 'AB4C8D10' 3 | _cell_length_a 16.85090 4 | _cell_length_b 16.85090 5 | _cell_length_c 16.85090 6 | _cell_angle_alpha 90.00000 7 | _cell_angle_beta 90.00000 8 | _cell_angle_gamma 90.00000 9 | _cell_volume 4784.86076 10 | _cell_formula_units_Z 12 11 | _symmetry_space_group_name_H-M 'P 1' 12 | _symmetry_Int_Tables_number 1 13 | loop_ 14 | _symmetry_equiv_pos_site_id 15 | _symmetry_equiv_pos_as_xyz 16 | 1 x,y,z 17 | loop_ 18 | _atom_site_label 19 | _atom_site_type_symbol 20 | _atom_site_symmetry_multiplicity 21 | _atom_site_fract_x 22 | _atom_site_fract_y 23 | _atom_site_fract_z 24 | _atom_site_occupancy 25 | O1 O 1 0.3710181800 0.3710181800 0.0171272700 1 26 | O2 O 1 0.0171272700 0.6289818200 0.6289818200 1 27 | O3 O 1 0.0171272700 0.3710181800 0.3710181800 1 28 | O4 O 1 0.6289818200 0.6289818200 0.0171272700 1 29 | O5 O 1 0.6289818200 0.0171272700 0.6289818200 1 30 | O6 O 1 0.3710181800 0.0171272700 0.3710181800 1 31 | O7 O 1 0.4828727300 0.8710181800 0.1289818200 1 32 | O8 O 1 0.3710181800 0.9828727300 0.6289818200 1 33 | Si1 Si 1 0.5000000000 0.7500000000 0.0000000000 1 34 | O9 O 1 0.5171272700 0.8710181800 0.8710181800 1 35 | Si2 Si 1 0.5000000000 0.0000000000 0.7500000000 1 36 | O10 O 1 0.4828727300 0.1289818200 0.8710181800 1 37 | Si3 Si 1 0.5000000000 0.2500000000 0.0000000000 1 38 | O11 O 1 0.5171272700 0.1289818200 0.1289818200 1 39 | O12 O 1 0.6289818200 0.3710181800 0.9828727300 1 40 | O13 O 1 0.3710181800 0.6289818200 0.9828727300 1 41 | Si4 Si 1 0.0000000000 0.2500000000 0.5000000000 1 42 | O14 O 1 0.1289818200 0.1289818200 0.5171272700 1 43 | Si5 Si 1 0.2500000000 0.0000000000 0.5000000000 1 44 | Si6 Si 1 0.0000000000 0.5000000000 0.2500000000 1 45 | Si7 Si 1 0.5000000000 0.0000000000 0.2500000000 1 46 | O15 O 1 0.6289818200 0.9828727300 0.3710181800 1 47 | O16 O 1 0.9828727300 0.6289818200 0.3710181800 1 48 | O17 O 1 0.8710181800 0.8710181800 0.5171272700 1 49 | Si8 Si 1 0.7500000000 0.0000000000 0.5000000000 1 50 | O18 O 1 0.8710181800 0.1289818200 0.4828727300 1 51 | Si9 Si 1 0.0000000000 0.7500000000 0.5000000000 1 52 | O19 O 1 0.1289818200 0.8710181800 0.4828727300 1 53 | Si10 Si 1 0.2500000000 0.5000000000 0.0000000000 1 54 | O20 O 1 0.1289818200 0.5171272700 0.1289818200 1 55 | O21 O 1 0.9828727300 0.3710181800 0.6289818200 1 56 | Si11 Si 1 0.0000000000 0.5000000000 0.7500000000 1 57 | O22 O 1 0.1289818200 0.4828727300 0.8710181800 1 58 | O23 O 1 0.8710181800 0.4828727300 0.1289818200 1 59 | Si12 Si 1 0.7500000000 0.5000000000 0.0000000000 1 60 | O24 O 1 0.8710181800 0.5171272700 0.8710181800 1 61 | loop_ 62 | _topol_link.node_label_1 63 | _topol_link.node_label_2 64 | _topol_link.distance 65 | _topol_link.site_symmetry_symop_1 66 | _topol_link.site_symmetry_translation_1_x 67 | _topol_link.site_symmetry_translation_1_y 68 | _topol_link.site_symmetry_translation_1_z 69 | _topol_link.site_symmetry_symop_2 70 | _topol_link.site_symmetry_translation_2_x 71 | _topol_link.site_symmetry_translation_2_y 72 | _topol_link.site_symmetry_translation_2_z 73 | _topol_link.type 74 | _topol_link.multiplicity 75 | O1 Si3 2.99430 1 0 0 0 1 0 0 0 V 1 76 | O1 Si10 2.99430 1 0 0 0 1 0 0 0 V 1 77 | O2 Si11 2.99430 1 0 0 0 1 0 0 0 V 1 78 | O2 Si9 2.99430 1 0 0 0 1 0 0 0 V 1 79 | O3 Si4 2.99430 1 0 0 0 1 0 0 0 V 1 80 | O3 Si6 2.99430 1 0 0 0 1 0 0 0 V 1 81 | O4 Si12 2.99430 1 0 0 0 1 0 0 0 V 1 82 | O4 Si1 2.99430 1 0 0 0 1 0 0 0 V 1 83 | O5 Si2 2.99430 1 0 0 0 1 0 0 0 V 1 84 | O5 Si8 2.99430 1 0 0 0 1 0 0 0 V 1 85 | O6 Si5 2.99430 1 0 0 0 1 0 0 0 V 1 86 | O6 Si7 2.99430 1 0 0 0 1 0 0 0 V 1 87 | O7 Si7 2.99430 1 0 0 0 1 0 1 0 V 1 88 | O7 Si1 2.99430 1 0 0 0 1 0 0 0 V 1 89 | O8 Si5 2.99430 1 0 0 0 1 0 1 0 V 1 90 | O8 Si2 2.99430 1 0 0 0 1 0 1 0 V 1 91 | Si1 O9 2.99430 1 0 0 0 1 0 0 -1 V 1 92 | Si1 O13 2.99430 1 0 0 0 1 0 0 -1 V 1 93 | O9 Si2 2.99430 1 0 0 0 1 0 1 0 V 1 94 | Si2 O10 2.99430 1 0 0 0 1 0 0 0 V 1 95 | O10 Si3 2.99430 1 0 0 0 1 0 0 1 V 1 96 | Si3 O11 2.99430 1 0 0 0 1 0 0 0 V 1 97 | Si3 O12 2.99430 1 0 0 0 1 0 0 -1 V 1 98 | O11 Si7 2.99430 1 0 0 0 1 0 0 0 V 1 99 | O12 Si12 2.99430 1 0 0 0 1 0 0 1 V 1 100 | O13 Si10 2.99430 1 0 0 0 1 0 0 1 V 1 101 | Si4 O18 2.99430 1 0 0 0 1 -1 0 0 V 1 102 | Si4 O21 2.99430 1 0 0 0 1 -1 0 0 V 1 103 | Si4 O14 2.99430 1 0 0 0 1 0 0 0 V 1 104 | O14 Si5 2.99430 1 0 0 0 1 0 0 0 V 1 105 | Si5 O19 2.99430 1 0 0 0 1 0 -1 0 V 1 106 | Si6 O16 2.99430 1 0 0 0 1 -1 0 0 V 1 107 | Si6 O20 2.99430 1 0 0 0 1 0 0 0 V 1 108 | Si6 O23 2.99430 1 0 0 0 1 -1 0 0 V 1 109 | Si7 O15 2.99430 1 0 0 0 1 0 -1 0 V 1 110 | O15 Si8 2.99430 1 0 0 0 1 0 1 0 V 1 111 | O16 Si9 2.99430 1 0 0 0 1 1 0 0 V 1 112 | O17 Si8 2.99430 1 0 0 0 1 0 1 0 V 1 113 | O17 Si9 2.99430 1 0 0 0 1 1 0 0 V 1 114 | Si8 O18 2.99430 1 0 0 0 1 0 0 0 V 1 115 | Si9 O19 2.99430 1 0 0 0 1 0 0 0 V 1 116 | Si10 O20 2.99430 1 0 0 0 1 0 0 0 V 1 117 | Si10 O22 2.99430 1 0 0 0 1 0 0 -1 V 1 118 | O21 Si11 2.99430 1 0 0 0 1 1 0 0 V 1 119 | Si11 O24 2.99430 1 0 0 0 1 -1 0 0 V 1 120 | Si11 O22 2.99430 1 0 0 0 1 0 0 0 V 1 121 | O23 Si12 2.99430 1 0 0 0 1 0 0 0 V 1 122 | Si12 O24 2.99430 1 0 0 0 1 0 0 -1 V 1 123 | #End of data_ZIF-8-cg 124 | 125 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "chic-lib" 7 | version = "0.1.17" 8 | description = "Coarse-grainig hybrid and inorganic crystals (CHIC)" 9 | readme = "README.md" 10 | authors = [{ name = "Thomas C Nicholas", email = "tcnicholas@me.com" }] 11 | license = { file = "LICENSE" } 12 | classifiers = [ 13 | "License :: OSI Approved :: MIT License", 14 | "Programming Language :: Python", 15 | "Programming Language :: Python :: 3", 16 | ] 17 | keywords = ["chemistry", "machine learning", "coarse-graining"] 18 | dependencies = [ 19 | 'numpy', 20 | 'scipy', 21 | 'scikit-learn', 22 | 'pymatgen', 23 | 'ase', 24 | 'networkx', 25 | ] 26 | requires-python = ">=3.8" 27 | 28 | [project.optional-dependencies] 29 | dev = [ 30 | "notebook", 31 | "pytest==7.2.0", # kept < 8 to allow for importing from test/setup 32 | "sphinx", 33 | "furo", 34 | "nbsphinx", 35 | "sphinx-autobuild", 36 | "pytest-cov", 37 | "build", 38 | "bumpver", 39 | "twine", 40 | "ruff", 41 | "sphinx_autodoc_typehints", 42 | "sphinx-design", 43 | "sphinx_copybutton", 44 | "sphinx-codeautolink", 45 | "sphinxext-opengraph", 46 | ] 47 | 48 | [project.urls] 49 | Homepage = "https://github.com/tcnicholas/chic" -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | 4 | setup( 5 | name='chic-lib', 6 | version='0.1.17', 7 | packages=find_packages(), 8 | install_requires=[ 9 | 'numpy', 10 | 'scipy', 11 | 'scikit-learn', 12 | 'pymatgen', 13 | 'ase', 14 | 'networkx', 15 | #'crystal-toolkit', # this might cause dependency issues. 16 | #'crystaltoolkit-extension' # this might cause dependency issues. 17 | ], 18 | author='Thomas C Nicholas', 19 | author_email='thomas.nicholas@chem.ox.ac.uk', 20 | description='A set of tools for coarse-graining and back-mapping frameworks.', 21 | long_description=open('README.md').read(), 22 | long_description_content_type='text/markdown', 23 | url='https://github.com/tcnicholas/chic', 24 | classifiers=[ 25 | 'Development Status :: 3 - Alpha', 26 | 'Intended Audience :: Science/Research', 27 | 'License :: OSI Approved :: BSD License', 28 | 'Programming Language :: Python :: 3', 29 | 'Programming Language :: Python :: 3.8', 30 | ], 31 | ) 32 | 33 | -------------------------------------------------------------------------------- /tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class Test1(unittest.TestCase): 5 | """Test 1.""" 6 | def test_sum(self): 7 | return 3+3 8 | 9 | 10 | class Test2(unittest.TestCase): 11 | """Test 2.""" 12 | def test_sum_triple(self): 13 | return 3+3+3 14 | 15 | def test_mult(self): 16 | return 3*3 17 | 18 | 19 | if __name__=='__main__': 20 | unittest.main() 21 | --------------------------------------------------------------------------------