# -*- coding: utf-8 -*-
"""a node to create a structure from a SMILES string"""
import logging
import from_smiles_step
import molsystem
import seamm
import seamm_util.printing as printing
from seamm_util.printing import FormattedText as __
logger = logging.getLogger(__name__)
job = printing.getPrinter()
printer = printing.getPrinter("from_smiles")
[docs]
class FromSMILES(seamm.Node):
def __init__(self, flowchart=None, extension=None):
"""Initialize a specialized start node, which is the
anchor for the graph.
Keyword arguments:
"""
logger.debug("Creating FromSMILESNode {}".format(self))
super().__init__(
flowchart=flowchart, title="from SMILES", extension=extension, logger=logger
)
self.parameters = from_smiles_step.FromSMILESParameters()
@property
def version(self):
"""The semantic version of this module."""
return from_smiles_step.__version__
@property
def git_revision(self):
"""The git version of this module."""
return from_smiles_step.__git_revision__
[docs]
def description_text(self, P=None):
"""Return a short description of this step.
Return a nicely formatted string describing what this step will
do.
Keyword arguments:
P: a dictionary of parameter values, which may be variables
or final values. If None, then the parameters values will
be used as is.
"""
if not P:
P = self.parameters.values_to_dict()
if P["notation"] == "perceive":
if P["smiles string"][0] == "$":
text = (
"Perceive the line notation (SMILES, InChI,...) and create the "
"structure from the string in the variable '{smiles string}', "
)
else:
text = (
"Perceive the line notation (SMILES, InChI,...) and create the "
"structure from the string '{smiles string}', "
)
else:
if P["smiles string"][0] == "$":
text = (
"Create the structure from the {notation} in the variable"
" '{smiles string}', "
)
else:
text = "Create the structure from the {notation} '{smiles string}', "
text += seamm.standard_parameters.structure_handling_description(P)
return self.header + "\n" + __(text, **P, indent=4 * " ").__str__()
[docs]
def run(self):
"""Create 3-D structure from a SMILES string"""
self.logger.debug("Entering from_smiles:run")
next_node = super().run(printer)
P = self.parameters.current_values_to_dict(
context=seamm.flowchart_variables._data
)
# Print what we are doing
printer.important(self.description_text(P))
if P["smiles string"] is None or P["smiles string"] == "":
return None
notation = P["notation"]
flavor = P["smiles flavor"]
# Get the system
system, configuration = self.get_system_configuration(P, same_as=None)
# Create the structure in the given configuration
text = P["smiles string"]
# Perceive the notation if requested
perceived = False
if notation == "perceive":
perceived = True
tmp = text.split("-")
if (
len(text) == 27
and len(tmp) == 3
and len(tmp[0]) == 14
and len(tmp[1]) == 10
):
notation = "InChIKey"
elif text[0:7] == "InChI=":
notation = "InChI"
else:
notation = "SMILES or name"
if notation == "SMILES":
try:
configuration.from_smiles(text, flavor=flavor)
except Exception:
try:
configuration.PC_from_identifier(
text, namespace="smiles", properties=None
)
flavor = "PUBCHEM"
except Exception:
# If using rdkit, try openbabel since it is more robust
if flavor == "rdkit":
try:
configuration.from_smiles(text, flavor="openbabel")
flavor = "openbabel"
except Exception:
raise RuntimeError(
f"Can not create a structure from the string '{text}'"
" as a SMILES."
)
elif notation == "InChI":
try:
configuration.from_inchi(text)
flavor = "openbabel"
except Exception:
raise RuntimeError(
f"Can not create a structure from the string '{text}'"
" as an InChI."
)
elif notation == "InChIKey":
try:
configuration.from_inchikey(text)
flavor = "openbabel"
except Exception:
raise RuntimeError(
f"Can not create a structure from the string '{text}'"
" as an InChIKey."
)
elif notation == "name":
try:
configuration.PC_from_identifier(text, namespace="name")
flavor = "PubChem"
except Exception:
raise RuntimeError(
f"Can not create a structure from the string '{text}'"
" as a chemical name."
)
elif notation == "SMILES or name":
try:
configuration.from_smiles(text, flavor=flavor)
except Exception:
try:
configuration.PC_from_identifier(text, namespace="name")
flavor = "PubChem"
notation = "name"
except Exception:
try:
configuration.PC_from_identifier(text, namespace="smiles")
flavor = "PubChem"
notation = "SMILES"
except Exception:
# If using rdkit, try openbabel since it is more robust
if flavor == "rdkit":
flavor = "openbabel"
try:
configuration.from_smiles(text, flavor="openbabel")
except Exception:
raise RuntimeError(
"Can not create a structure from the string "
f"'{text}' as a SMILES."
)
else:
raise RuntimeError(f"Can not handle line notation '{text}'")
# Now set the names of the system and configuration, as appropriate.
seamm.standard_parameters.set_names(system, configuration, P, _first=True)
# Finish the output
if perceived:
if notation == "SMILES":
printer.important(
__(
"\n Created a molecular structure with "
f"{configuration.n_atoms} atoms from the perceived notation "
f"{notation} using {flavor}.",
indent=4 * " ",
)
)
else:
printer.important(
__(
"\n Created a molecular structure with "
f"{configuration.n_atoms} atoms from the perceived notation "
f"{notation}.",
indent=4 * " ",
)
)
else:
if notation == "SMILES":
printer.important(
__(
"\n Created a molecular structure with "
f"{configuration.n_atoms} atoms from the notation "
f"{notation} using {flavor}.",
indent=4 * " ",
)
)
else:
printer.important(
__(
"\n Created a molecular structure with "
f"{configuration.n_atoms} atoms from the notation "
f"{notation}.",
indent=4 * " ",
)
)
printer.important(
__(
f"\n System name = {system.name}"
f"\n Configuration name = {configuration.name}",
indent=4 * " ",
)
)
printer.important("")
if flavor == "openbabel":
citations = molsystem.openbabel_citations()
for i, citation in enumerate(citations, start=1):
self.references.cite(
raw=citation,
alias=f"openbabel_{i}",
module="from_smiles_step",
level=1,
note=f"The principle citation #{i} for OpenBabel.",
)
elif flavor == "rdkit":
citations = molsystem.rdkit_citations()
for i, citation in enumerate(citations, start=1):
self.references.cite(
raw=citation,
alias=f"rdkit_{i}",
module="from_smiles_step",
level=1,
note=f"The principle citation #{i} for RDKit.",
)
return next_node