def __init__(self, start_monomer, s_head, s_tail, monomer, head, tail, end_monomer, e_head, e_tail, n_units, link_distance=1.0, linear_chain=False): """ Args: start_monomer (Molecule): Starting molecule s_head (int): starting atom index of the start_monomer molecule s_tail (int): tail atom index of the start_monomer monomer (Molecule): The monomer head (int): index of the atom in the monomer that forms the head tail (int): tail atom index. monomers will be connected from tail to head end_monomer (Molecule): Terminal molecule e_head (int): starting atom index of the end_monomer molecule e_tail (int): tail atom index of the end_monomer n_units (int): number of monomer units excluding the start and terminal molecules link_distance (float): distance between consecutive monomers linear_chain (bool): linear or random walk polymer chain """ self.start = s_head self.end = s_tail self.monomer = monomer self.n_units = n_units self.link_distance = link_distance self.linear_chain = linear_chain # translate monomers so that head atom is at the origin start_monomer.translate_sites(range(len(start_monomer)), - monomer.cart_coords[s_head]) monomer.translate_sites(range(len(monomer)), - monomer.cart_coords[head]) end_monomer.translate_sites(range(len(end_monomer)), - monomer.cart_coords[e_head]) self.mon_vector = monomer.cart_coords[tail] - monomer.cart_coords[head] self.moves = {1: [1, 0, 0], 2: [0, 1, 0], 3: [0, 0, 1], 4: [-1, 0, 0], 5: [0, -1, 0], 6: [0, 0, -1]} self.prev_move = 1 # places the start monomer at the beginning of the chain self.molecule = start_monomer.copy() self.length = 1 # create the chain self._create(self.monomer, self.mon_vector) # terminate the chain with the end_monomer self.n_units += 1 end_mon_vector = end_monomer.cart_coords[e_tail] - \ end_monomer.cart_coords[e_head] self._create(end_monomer, end_mon_vector) self.molecule = Molecule.from_sites(self.molecule.sites)
def insert_g3testset(coll): for f in glob.glob("g*.txt"): print("Parsing " + f) for (m, charge, spin) in parse_file(f): try: clean_sites = [] for site in m: if Element.is_valid_symbol(site.specie.symbol): clean_sites.append(site) clean_mol = Molecule.from_sites(clean_sites, charge=charge, spin_multiplicity=spin) xyz = XYZ(clean_mol) bb = BabelMolAdaptor.from_string(str(xyz), "xyz") pbmol = pb.Molecule(bb.openbabel_mol) smiles = pbmol.write("smi").split()[0] can = pbmol.write("can").split()[0] inchi = pbmol.write("inchi") svg = pbmol.write("svg") d = {"molecule": clean_mol.as_dict()} comp = clean_mol.composition d["pretty_formula"] = comp.reduced_formula d["formula"] = comp.formula d["composition"] = comp.as_dict() d["elements"] = list(comp.as_dict().keys()) d["nelements"] = len(comp) d["charge"] = charge d["spin_multiplicity"] = spin d["smiles"] = smiles d["can"] = can d["inchi"] = inchi # d["names"] = get_nih_names(smiles) d["svg"] = svg d["xyz"] = str(xyz) d["tags"] = ["G305 test set"] coll.update( { "inchi": inchi, "charge": charge, "spin_multiplicity": spin }, {"$set": d}, upsert=True) except Exception as ex: print("Error in {}".format(f)) exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_traceback, limit=2, file=sys.stdout) print("{} parsed!".format(f))
def fit(self, p: Molecule): """Order, rotate and transform `p` molecule according to the best match. Args: p: a `Molecule` object what will be matched with the target one. Returns: p_prime: Rotated and translated of the `p` `Molecule` object rmsd: Root-mean-square-deviation between `p_prime` and the `target` """ inds, U, V, rmsd = self.match(p) # Translate and rotate `mol1` unto `mol2` using Kabsch algorithm. p_prime = Molecule.from_sites([p[i] for i in inds]) for site in p_prime: site.coords = np.dot(site.coords, U) + V return p_prime, rmsd
def fit(self, p: Molecule, ignore_warning=False): """Order, rotate and transform `p` molecule according to the best match. A `ValueError` will be raised when the total number of possible combinations become unfeasible (more than a million combinations). Args: p: a `Molecule` object what will be matched with the target one. ignore_warning: ignoring error when the number of combination is too large Returns: p_prime: Rotated and translated of the `p` `Molecule` object rmsd: Root-mean-square-deviation between `p_prime` and the `target` """ inds, U, V, rmsd = self.match(p, ignore_warning=ignore_warning) p_prime = Molecule.from_sites([p[i] for i in inds]) for site in p_prime: site.coords = np.dot(site.coords, U) + V return p_prime, rmsd
def __init__(self, sites, ff_label=None, charges=None, velocities=None, topologies=None): """ Args: sites ([Site] or SiteCollection): A group of sites in a list or as a Molecule/Structure. ff_label (str): Site property key for labeling atoms of different types. Default to None, i.e., use site.species_string. charges ([q, ...]): Charge of each site in a (n,) array/list, where n is the No. of sites. Default to None, i.e., search site property for charges. velocities ([[vx, vy, vz], ...]): Velocity of each site in a (n, 3) array/list, where n is the No. of sites. Default to None, i.e., search site property for velocities. topologies (dict): Bonds, angles, dihedrals and improper dihedrals defined by site indices. Default to None, i.e., no additional topology. All four valid keys listed below are optional. { "Bonds": [[i, j], ...], "Angles": [[i, j, k], ...], "Dihedrals": [[i, j, k, l], ...], "Impropers": [[i, j, k, l], ...] } """ if not isinstance(sites, SiteCollection): sites = Molecule.from_sites(sites) if ff_label: type_by_sites = sites.site_properties.get(ff_label) else: type_by_sites = [site.species_string for site in sites] # search for site property if not override if charges is None: charges = sites.site_properties.get("charge") if velocities is None: velocities = sites.site_properties.get("velocities") # validate shape if charges is not None: charge_arr = np.array(charges) assert charge_arr.shape == (len(sites),),\ "Wrong format for charges" charges = charge_arr.tolist() if velocities is not None: velocities_arr = np.array(velocities) assert velocities_arr.shape == (len(sites), 3), \ "Wrong format for velocities" velocities = velocities_arr.tolist() if topologies: topologies = {k: v for k, v in topologies.items() if k in SECTION_KEYWORDS["topology"]} self.sites = sites self.ff_label = ff_label self.charges = charges self.velocities = velocities self.topologies = topologies self.type_by_sites = type_by_sites self.species = set(type_by_sites)
def __init__(self, sites, ff_label=None, charges=None, velocities=None, topologies=None): """ Args: sites ([Site] or SiteCollection): A group of sites in a list or as a Molecule/Structure. ff_label (str): Site property key for labeling atoms of different types. Default to None, i.e., use site.species_string. charges ([q, ...]): Charge of each site in a (n,) array/list, where n is the No. of sites. Default to None, i.e., search site property for charges. velocities ([[vx, vy, vz], ...]): Velocity of each site in a (n, 3) array/list, where n is the No. of sites. Default to None, i.e., search site property for velocities. topologies (dict): Bonds, angles, dihedrals and improper dihedrals defined by site indices. Default to None, i.e., no additional topology. All four valid keys listed below are optional. { "Bonds": [[i, j], ...], "Angles": [[i, j, k], ...], "Dihedrals": [[i, j, k, l], ...], "Impropers": [[i, j, k, l], ...] } """ if not isinstance(sites, (Molecule, Structure)): sites = Molecule.from_sites(sites) if ff_label: type_by_sites = sites.site_properties.get(ff_label) else: type_by_sites = [site.specie.symbol for site in sites] # search for site property if not override if charges is None: charges = sites.site_properties.get("charge") if velocities is None: velocities = sites.site_properties.get("velocities") # validate shape if charges is not None: charge_arr = np.array(charges) assert charge_arr.shape == (len(sites),),\ "Wrong format for charges" charges = charge_arr.tolist() if velocities is not None: velocities_arr = np.array(velocities) assert velocities_arr.shape == (len(sites), 3), \ "Wrong format for velocities" velocities = velocities_arr.tolist() if topologies: topologies = {k: v for k, v in topologies.items() if k in SECTION_KEYWORDS["topology"]} self.sites = sites self.ff_label = ff_label self.charges = charges self.velocities = velocities self.topologies = topologies self.type_by_sites = type_by_sites self.species = set(type_by_sites)
def __init__( self, site_collection: Union[SiteCollection, Site], color_scheme: str = "Jmol", radius_scheme: str = "uniform", cmap: str = "coolwarm", cmap_range: Optional[Tuple[float, float]] = None, ): """ Create a legend for a given SiteCollection to choose how to display colors and radii for the given sites and the species on those sites. If a site has a "display_color" or "display_radius" site property defined, this can be used to manually override the displayed colors and radii respectively. Args: site_collection: SiteCollection or, for convenience, a single site can be provided and this will be converted into a SiteCollection color_scheme: choose how to color-code species, one of "Jmol", "VESTA", "accessible" or a scalar site property (e.g. magnetic moment) or a categorical/string site property (e.g. Wyckoff label) radius_scheme: choose the radius for a species, one of ... cmap: only used if color_mode is set to a scalar site property, defines the matplotlib color map to use, by default is blue-white-red for negative to postive values cmap_range: only used if color_mode is set to a scalar site property, defines the minimum and maximum values of the color scape """ if isinstance(site_collection, Site): site_collection = Molecule.from_sites([site_collection]) site_prop_types = self.analyze_site_props(site_collection) self.allowed_schemes = (["VESTA", "Jmol", "accessible"] + site_prop_types.get("scalar", []) + site_prop_types.get("categorical", [])) if color_scheme not in self.allowed_schemes: warnings.warn(f"Color scheme {color_scheme} not available, " f"falling back to {self.default_scheme}.") color_scheme = self.default_scheme # if color-coding by a scalar site property, determine minimum and # maximum values for color scheme, will default to be symmetric # about zero if color_scheme in site_prop_types.get("scalar", []) and not cmap_range: props = np.array(site_collection.site_properties[color_scheme]) prop_max = max([abs(min(props)), max(props)]) prop_min = -prop_max cmap_range = (prop_min, prop_max) el_colors = EL_COLORS.copy() el_colors.update( self.generate_accessible_color_scheme_on_the_fly(site_collection)) self.categorical_colors = self.generate_categorical_color_scheme_on_the_fly( site_collection, site_prop_types) self.el_colors = el_colors self.site_prop_types = site_prop_types self.site_collection = site_collection self.color_scheme = color_scheme self.radius_mode = radius_scheme self.cmap = cmap self.cmap_range = cmap_range
def site_layout(symmetrizer: StructureSymmetrizer): columns = [] distance_cutoff = 2.0 angle_cutoff = 0.3 cnn = CrystalNN() nn_info = cnn.get_all_nn_info(structure=symmetrizer.structure) for name, site in symmetrizer.sites.items(): wyckoff_contents = [] data = dict() data["Site Symmetry"] = site.site_symmetry data["Wyckoff Letter"] = site.wyckoff_letter wyckoff_contents.append(html.Label(f"{name}", className="mpc-label")) site_data = [] repr_idx = site.equivalent_atoms[0] for idx in site.equivalent_atoms: coords = symmetrizer.structure[idx].frac_coords site_data += [(pretty_frac_format(coords[0]), pretty_frac_format(coords[1]), pretty_frac_format(coords[2]))] # lgf = LocalGeometryFinder() # lgf.setup_structure(structure=symmetrizer.structure) # se = lgf.compute_structure_environments( # maximum_distance_factor=distance_cutoff + 0.01) # strategy = SimplestChemenvStrategy( # distance_cutoff=distance_cutoff, angle_cutoff=angle_cutoff # ) # lse = LightStructureEnvironments.from_structure_environments( # strategy=strategy, structure_environments=se) # represent the local environment as a molecule mol = Molecule.from_sites( [symmetrizer.structure[repr_idx]] + [i["site"] for i in nn_info[repr_idx]] ) mol = mol.get_centered_molecule() mg = MoleculeGraph.with_empty_graph(molecule=mol) for i in range(1, len(mol)): mg.add_edge(0, i) view = html.Div( [ StructureMoleculeComponent( struct_or_mol=mg, disable_callbacks=True, id=f"{symmetrizer.structure.composition.reduced_formula}_site_{repr_idx}", scene_settings={"enableZoom": False, "defaultZoom": 0.6}, )._sub_layouts["struct"] ], style={"width": "300px", "height": "300px"}, ) # env = lse.coordination_environments[repr_idx] # all_ce = AllCoordinationGeometries() # co = all_ce.get_geometry_from_mp_symbol(env[0]["ce_symbol"]) # name = co.name data.update( { # "Environment": name, # "IUPAC Symbol": co.IUPAC_symbol_str, "Structure": view, } ) wyckoff_contents.append(get_data_list(data)) wyckoff_contents.append(Reveal(get_table(site_data), title=f"Positions ({len(site_data)})", id=f"{name}-positions")) columns.append(Column(html.Div(wyckoff_contents))) _layout = Columns(columns) return Columns([Column([H4("Sites"), html.Div(_layout)])])