{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "c608caff",
"metadata": {},
"outputs": [],
"source": [
"try:\n",
" import google.colab\n",
" %pip install -q ugropy\n",
"except ImportError:\n",
" pass"
]
},
{
"cell_type": "markdown",
"id": "03a6b598",
"metadata": {},
"source": [
"# Filtering multiple solutions\n",
"\n",
"[](https://colab.research.google.com/github/ipqa-research/ugropy/blob/main/docs/source/tutorial/filtering.ipynb)"
]
},
{
"cell_type": "markdown",
"id": "d42977db",
"metadata": {},
"source": [
"Due to the nature of the `ugropy` algorithm, some molecules may present\n",
"multiple fragmentation solutions for a specific model. In such cases, the\n",
"experience of the user with a model may be sufficient to determine \n",
"the most appropriate solution. Besides, `ugropy` provides some heuristic\n",
"methods to determine the \"best solution\" along with some criteria.\n",
"\n",
"These methods are relatively simple to implement, and users are welcome to\n",
"create their own if necessary.\n",
"\n",
"In the `ugropy` library, the fragmentation models are instances of diverse\n",
"classes that require more or less information to describe a specific model.\n",
"\n",
"All the fragmentation classes inherit from the base class `FragmentationModel`.\n",
"For that, some filters are implemented for the base class `FragmentationModel`\n",
"and are available for all the fragmentation models. Other filters are specific\n",
"to a subclass, for example, the `GibbsModel` (unifac, psrk, dortmund, etc).\n",
"\n",
"**Recommendation**\n",
"\n",
"**Is recommended to explore the \"DDBST Validation\" subsection on the \"Tests book\" section of this documentation to explore the performance of these filters on the UNIFAC model.**\n",
"\n",
"\n",
"All filters receive a list of solutions obtained by `ugropy` and return\n",
"another list of solutions that were filtered. Sometimes the length of the\n",
"returned list could be one (only on solution selected) other times could be\n",
"more (generally because the filter could not decide which one is best)."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "b812311f",
"metadata": {},
"outputs": [],
"source": [
"from ugropy import unifac"
]
},
{
"cell_type": "markdown",
"id": "7fc660c5",
"metadata": {},
"source": [
"## FragmentationModel class filters\n",
"\n",
"As said before, these filters are available for all the fragmentation models\n",
"and rely on basic heuristics. Let's check and explain each one:"
]
},
{
"cell_type": "markdown",
"id": "88d7075e",
"metadata": {},
"source": [
"### Filter: Mostly polyatomic\n",
"\n",
"This filter selects the solution with the highest amount of atoms occupied\n",
"by polyatomic fragments (hydrogens don't count). Let's analyze the following\n",
"example that has two solutions:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "760a21dc",
"metadata": {},
"outputs": [],
"source": [
"solutions = unifac.get_groups(\"COC(=O)CC1=CC=CC=C1\", \"smiles\", search_multiple_solutions=True) "
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "f4e19a40",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"solutions[0].draw(width=600)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "b74e1954",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"solutions[1].draw(width=600)"
]
},
{
"cell_type": "markdown",
"id": "d275d341",
"metadata": {},
"source": [
"To use a filter for a model, we can use the filter methods implemented in that\n",
"model like the following:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "da76041d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered = unifac.filter_mostly_polyatomic(solutions)\n",
"\n",
"len(filtered)"
]
},
{
"cell_type": "markdown",
"id": "1cee557f",
"metadata": {},
"source": [
"As you can observe, the filter found a unique preferred solution along with\n",
"its criteria. The solution is the one that uses the groups \"COO\" and \"ACCH2\"\n",
"since more atoms of the molecule are occupied by polyatomic fragments: "
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "ef47e2ad",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered[0].draw(width=600)"
]
},
{
"cell_type": "markdown",
"id": "0b1e6e72",
"metadata": {},
"source": [
"### Filter: Mostly polarity"
]
},
{
"cell_type": "markdown",
"id": "72d54c2c",
"metadata": {},
"source": [
"This filter prefers the solutions that have the most atoms occupied by\n",
"fragments of and specified polarity. The arguments for the polarity could be\n",
"\"polar\" or \"apolar\" respectively. A group is considered polar if its SMARTS\n",
"pattern contains at least one of the following atoms: {\"O\", \"N\", \"S\", \"P\", \"F\",\n",
"\"Cl\", \"Br\", \"I\"}. Of course, a group is considered apolar if it does not contain\n",
"any of those atoms."
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "7a0ee01a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_polarity = unifac.filter_mostly_polarity(solutions, polarity=\"polar\")\n",
"\n",
"len(filtered_polarity)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "94bc763d",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_polarity[0].draw(width=600)"
]
},
{
"cell_type": "markdown",
"id": "9e19d982",
"metadata": {},
"source": [
"In this case, the other solution is preferred since the \"CH2COO\" (a polar\n",
"group) is occupying more atoms of the molecule. If we call the same filter\n",
"with the \"apolar\" argument:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "09118e01",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_polarity = unifac.filter_mostly_polarity(solutions, polarity=\"apolar\")\n",
"\n",
"len(filtered_polarity)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "47cddbcf",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_polarity[0].draw(width=600)"
]
},
{
"cell_type": "markdown",
"id": "9a457847",
"metadata": {},
"source": [
"The other solution is preferred, since the \"ACCH2\" occupies and additional atom."
]
},
{
"cell_type": "markdown",
"id": "b2193176",
"metadata": {},
"source": [
"## GibbsModel class filters\n",
"\n",
"These filters are available only for `GibbsModel`s fragmentation models since\n",
"they rely on the $R$ and $Q$ information about the groups."
]
},
{
"cell_type": "markdown",
"id": "e6dc5273",
"metadata": {},
"source": [
"### Filter: Polarity contribution (recommended)\n",
"\n",
"This filter chooses the correct solution based on the total size of the\n",
"molecule occupied by groups of the specified polarity (\"polar\" or \"apolar\").\n",
"The size is either quantified by the $R$ or $Q$ values of the groups, specified\n",
"by the user. A group is considered polar if its SMARTS pattern contains at\n",
"least one of the following atoms: {\"O\", \"N\", \"S\", \"P\", \"F\", \"Cl\", \"Br\", \"I\"}.\n",
"Of course, a group is considered apolar if it does not contain any of those\n",
"atoms.\n",
"\n",
"\n",
"**This is the best found heuristic for GibbsModels configuring it to prioritize polar groups with the Q size criteria. Please refer to the DDBST Validation on the Tests book documentation to learn more.**\n",
"\n",
"\n",
"For the best heuristic found, the best solution is:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "265025d7",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_polar_Q = unifac.filter_polarity_contribution(solutions, criteria=\"Q\", polarity=\"polar\")\n",
"\n",
"filtered_polar_Q[0].draw(width=600)"
]
},
{
"cell_type": "markdown",
"id": "75be8fac",
"metadata": {},
"source": [
"Of course, you can change those configurations as you please:"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "9bad88f6",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_apolar_R = unifac.filter_polarity_contribution(solutions, criteria=\"R\", polarity=\"apolar\")\n",
"\n",
"filtered_apolar_R[0].draw(width=600)"
]
},
{
"cell_type": "markdown",
"id": "74a14c61",
"metadata": {},
"source": [
"### Filter: Bigger polyatomics\n",
"\n",
"This filter chooses the correct solution based on the total size of the\n",
"molecule occupied by polyatomic groups. The size is either quantified by the\n",
"$R$ or $Q$ values of the groups, specified by the user."
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "26e1a35c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_bigger_R = unifac.filter_bigger_polyatomics(solutions, criteria=\"R\")\n",
"\n",
"len(filtered_bigger_R)"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "a4482dc3",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_bigger_R[0].draw(width=600)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "94982eca",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_bigger_Q = unifac.filter_bigger_polyatomics(solutions, criteria=\"Q\")\n",
"\n",
"len(filtered_bigger_Q)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "e8e5b49a",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"filtered_bigger_Q[0].draw(width=600)"
]
},
{
"cell_type": "markdown",
"id": "afdcb0bd",
"metadata": {},
"source": [
"In this case, it doesn't matter the selected size criteria, the same solution\n",
"is preferred."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "ugropy (3.10.12)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}