from typing import Union, Optional, Tuple, Dict
from abc import abstractmethod
from manim import VGroup
from ..utils import PubchemAPIManager
from manim.mobject.opengl.opengl_mobject import OpenGLGroup
from ..manim_chemistry_molecule import MCMolecule
[docs]
class AbstractMolecule:
"""
Abstract molecule class used as a template to create
all the other molecule classes.
"""
group_class = VGroup
def __init__(self, *args, **kwargs):
"""
To be implemented on subclasses.
"""
...
[docs]
@classmethod
def molecule_from_file(
cls,
filepath,
ignore_hydrogens: bool = True,
ignore_all_hydrogens: bool = False,
*args,
**kwargs,
):
"""
Reads a file and returns a single molecule from that file.
By default retrieves the first molecule generated by the file.
Args:
filepath (_type_): Pathlike or str
Returns:
GraphMolecule: GraphMolecule from the file
"""
mc_molecule = MCMolecule.construct_from_file(
filepath=filepath,
ignore_hydrogens=ignore_hydrogens,
ignore_all_hydrogens=ignore_all_hydrogens,
)
if isinstance(mc_molecule, list):
mc_molecule = mc_molecule[0]
vertices, edges = cls.mc_molecule_to_atoms_and_bonds(mc_molecule=mc_molecule)
return cls(vertices, edges, *args, **kwargs)
[docs]
@classmethod
def multiple_molecules_from_file(
cls,
filepath,
ignore_hydrogens: bool = True,
ignore_all_hydrogens: bool = False,
*args,
**kwargs,
) -> Union[OpenGLGroup, VGroup]:
"""
Reads a file and returns a collection of molecules from that file as a OpenGLGroup or VGroup.
Args:
filepath (str | Pathlike): Path to the molecule
Raises:
Exception: In case the mc_molecules parsed is not a list.
Returns:
OpenGLGroup: OpenGLGroup with the molecules inside.
"""
mc_molecules = MCMolecule.construct_multiples_from_file(
filepath=filepath,
ignore_hydrogens=ignore_hydrogens,
ignore_all_hydrogens=ignore_all_hydrogens,
)
if not isinstance(mc_molecules, list):
raise Exception(f"Expected a list of molecules. Received {mc_molecules}")
mmolecules = cls.group_class()
for mc_molecule in mc_molecules:
atoms, bonds = cls.mc_molecule_to_atoms_and_bonds(mc_molecule=mc_molecule)
mmolecules.add(cls(atoms, bonds, *args, **kwargs))
return mmolecules
[docs]
@classmethod
def molecule_from_string(
cls,
string: str,
format: str = "json",
ignore_hydrogens: bool = True,
ignore_all_hydrogens: bool = False,
*args,
**kwargs,
):
"""
Reads a file and returns a single molecule from that file.
By default retrieves the first molecule generated by the file.
Args:
filepath (_type_): Pathlike or str
label (bool, optional): Add a label such as element symbol or number. Defaults to False.
Returns:
ThreeDMolecule: ThreeDMolecule from the string
"""
mc_molecule = MCMolecule.construct_from_string(
string=string,
format=format,
ignore_hydrogens=ignore_hydrogens,
ignore_all_hydrogens=ignore_all_hydrogens,
)
if isinstance(mc_molecule, list):
mc_molecule = mc_molecule[0]
vertices, edges = cls.mc_molecule_to_atoms_and_bonds(mc_molecule=mc_molecule)
return cls(vertices, edges, *args, **kwargs)
[docs]
@classmethod
def multiple_molecules_from_string(
cls,
string: str,
format: str = "json",
ignore_hydrogens: bool = True,
ignore_all_hydrogens: bool = False,
*args,
**kwargs,
) -> OpenGLGroup:
"""
Reads a file and returns a collection of molecules from that file as a OpenGLGroup.
Args:
filepath (str | Pathlike): Path to the molecule
label (bool, optional): Wether or not add a label.. Defaults to False.
Raises:
Exception: In case the mc_molecules parsed is not a list.
Returns:
OpenGLGroup: OpenGLGroup with the molecules inside.
"""
mc_molecules = MCMolecule.construct_multiples_from_string(
string=string,
format=format,
ignore_hydrogens=ignore_hydrogens,
ignore_all_hydrogens=ignore_all_hydrogens,
)
if not isinstance(mc_molecules, list):
raise Exception(f"Expected a list of molecules. Received {mc_molecules}")
mmolecules = OpenGLGroup()
for mc_molecule in mc_molecules:
atoms, bonds = cls.mc_molecule_to_atoms_and_bonds(mc_molecule=mc_molecule)
mmolecules.add(cls(atoms, bonds, *args, **kwargs))
return mmolecules
[docs]
@classmethod
def molecule_from_pubchem(
cls,
cid: Optional[str] = None,
name: Optional[str] = None,
smiles: Optional[str] = None,
inchi: Optional[str] = None,
three_d: bool = False,
*args,
**kwargs,
):
"""
Generates a GraphMolecule from an identifier using PubChem API.
Args:
cid (Optional[str], optional): Molecule cid. Defaults to None.
name (Optional[str], optional): Molecule name. Defaults to None.
smiles (Optional[str], optional): Molecule SMILES. Defaults to None.
inchi (Optional[str], optional): Molecule InChi. Defaults to None.
Returns:
GraphMolecule: GraphMolecule
"""
pubchem_api_manager = PubchemAPIManager(
cid=cid, name=name, smiles=smiles, inchi=inchi, three_d=three_d
)
return cls.molecule_from_string(
string=pubchem_api_manager.get_molecule(), format="json", *args, **kwargs
)
[docs]
@classmethod
@abstractmethod
def mc_molecule_to_atoms_and_bonds(
cls, mc_molecule: MCMolecule
) -> Tuple[Dict, Dict]:
"""
Transforms the structure of a mc_molecule to a (vertices, edges) tuple
with the following structure:
- Vertices: {<atom_index>: MCAtom}
- Edges: {(<from_atom_index>, <to_atom_index>): MCBond}
Args:
mc_molecule (MCMolecule): _description_
Returns:
Tuple[Dict, Dict]: _description_
"""
...