Source code for pyxtal.block_crystal

"""
Module for generating crystals based on building blocks
"""

# Standard Libraries
import numpy as np

# External Libraries
from pymatgen.core import Molecule

from pyxtal.io import search_molecules_in_crystal

# PyXtal imports
from pyxtal.molecular_crystal import molecular_crystal as mol_xtal
from pyxtal.molecule import Orientation, compare_mol_connectivity, pyxtal_molecule
from pyxtal.wyckoff_site import mol_site


[docs] def block_crystal( dim, group, molecules, numMols, factor, thickness, area, block, num_block, lattice, torsions, sites, conventional, tm, seed, random_state, use_hall, ): # If block is None, directly generate mol. xtal. # Otherwise, generate crystal from building block if block is None: return mol_xtal( dim, group, molecules, numMols, factor, thickness=thickness, area=area, lattice=lattice, torsions=torsions, sites=sites, conventional=conventional, tm=tm, seed=seed, random_state=random_state, use_hall=use_hall, ) else: p_mol = pyxtal_molecule(block) block_mols = search_molecules_in_crystal(p_mol.mol, tol=0.2, once=False) xtal_mols = [pyxtal_molecule(m, fix=True) for m in molecules] orders = [] for m1 in xtal_mols: for m2 in block_mols: if len(m1.mol) == len(m2): # match, mapping = compare_mol_connectivity(m2, m1.mol) match, mapping = compare_mol_connectivity(m1.mol, m2) # print(match, len(m1.mol), len(m2)) if match: orders.append([mapping[at] for at in range(len(m2))]) break # print(mapping) # print("smile"); print(m1.mol.to('xyz')) # print("reference"); print(m2.to('xyz')) # print(orders[-1]) # import sys; sys.exit() if len(orders) != len(molecules): raise ValueError("Block is inconsistent with the molecules") # rearrange the order of block molecules numbers = [] coords = np.zeros([len(p_mol.mol), 3]) count = 0 for order, m in zip(orders, block_mols): numbers.extend([m.atomic_numbers[o] for o in order]) coords[count : count + len(m)] += m.cart_coords[order] count += len(m) mol = Molecule(numbers, coords) if num_block is not None: num_block = [num_block] # print(mol.to('xyz')); import sys; sys.exit() for i in range(10): struc = mol_xtal( dim, group, [mol], num_block, factor, thickness=thickness, area=area, lattice=lattice, torsions=torsions, sites=sites, conventional=conventional, tm=tm, random_state=random_state, use_hall=use_hall, ) if struc.valid: break struc.molecules = xtal_mols struc.numMols = struc.numMols * len(xtal_mols) # XYZ from the block_sites b_site = struc.mol_sites[0] xyz, _ = b_site._get_coords_and_species(absolute=True, first=True) # Create mol sites ori = Orientation(np.eye(3)) mol_sites = [] count = 0 for i in range(len(molecules)): mol = xtal_mols[i] m_xyz = xyz[count : count + len(mol.mol)] center = mol.get_center(m_xyz) mol.reset_positions(m_xyz - center) # print(mol.mol.to('xyz')) position = np.dot(center, np.linalg.inv(struc.lattice.matrix)) position -= np.floor(position) m_site = mol_site(mol, position, ori, b_site.wp, struc.lattice) m_site.type = i mol_sites.append(m_site) count += len(mol.mol) struc.mol_sites = mol_sites return struc
if __name__ == "__main__": import pymatgen.analysis.structure_matcher as sm from pyxtal import pyxtal from pyxtal.representation import representation smiles = [ "C1=C(C=C(C=C1[N+](=O)[O-])[N+](=O)[O-])C(=O)O.smi", "CC1=CC2=C(C=C1)N3CC4=C(C=CC(=C4)C)N(C2)C3.smi", ] for block in [None, "xxv"]: print("block", block) for i in range(30): s = pyxtal(molecular=True) s.from_random(3, 14, smiles, block=block) rep2 = representation.from_pyxtal(s) strs = rep2.to_string() print(i, strs) rep3 = representation.from_string(strs, smiles) s1 = rep3.to_pyxtal() pmg1 = s.to_pymatgen() pmg2 = s1.to_pymatgen() pmg1.remove_species("H") pmg2.remove_species("H") if not sm.StructureMatcher().fit(pmg1, pmg2): print("Mismatch") print("S1", s.check_short_distances()) print("S2", s1.check_short_distances()) s.to_file("1.cif") s1.to_file("2.cif") import sys sys.exit()