<?xml version="1.0" encoding="UTF-8" standalone="no"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" version="2.0">

<channel>
	<title>Macs in Chemistry</title>
	<atom:link href="https://macinchem.org/feed/" rel="self" type="application/rss+xml"/>
	<link>https://macinchem.org</link>
	<description>A site for chemists using Macs in Chemistry</description>
	<lastBuildDate>Sat, 24 Oct 2026 13:55:33 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://macinchem.org/wp-content/uploads/2023/02/macinchem-150x150.png</url>
	<title>Macs in Chemistry</title>
	<link>https://macinchem.org</link>
	<width>32</width>
	<height>32</height>
</image> 
	<xhtml:meta content="noindex" name="robots" xmlns:xhtml="http://www.w3.org/1999/xhtml"/><item>
		<title>Burette Updated</title>
		<link>https://macinchem.org/2026/10/24/burette-updated/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Sat, 24 Oct 2026 13:55:29 +0000</pubDate>
				<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[Science Apps]]></category>
		<category><![CDATA[cheminformatics]]></category>
		<category><![CDATA[molecular visualisation]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3271</guid>

					<description><![CDATA[Burette is a macOS desktop app and Quick Look extension for molecular previews: Mol* 3D, xyzrender SVG, and RDKit grids. There is a review of]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://github.com/SergeiNikolenko/Burette">Burette</a> is a macOS desktop app and Quick Look extension for molecular previews: Mol* 3D, xyzrender SVG, and RDKit grids.</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="789" height="751" src="https://macinchem.org/wp-content/uploads/2026/07/Screenshot-2026-07-13-at-12.54.00.png" alt="" class="wp-image-3073" srcset="https://macinchem.org/wp-content/uploads/2026/07/Screenshot-2026-07-13-at-12.54.00.png 789w, https://macinchem.org/wp-content/uploads/2026/07/Screenshot-2026-07-13-at-12.54.00-300x286.png 300w, https://macinchem.org/wp-content/uploads/2026/07/Screenshot-2026-07-13-at-12.54.00-768x731.png 768w" sizes="(max-width: 789px) 100vw, 789px" /></figure>



<p class="wp-block-paragraph">There is a <a href="https://macinchem.org/2026/07/28/review-of-burrete/">review of Burette here </a></p>



<p class="wp-block-paragraph">it can be use in four ways</p>



<ul class="wp-block-list">
<li><strong>Finder previews:</strong> select a molecular file in Finder and press Space.</li>



<li><strong>Desktop workspace:</strong> open Burette directly to inspect files in tabs, browse project folders, search commands and structures, sketch molecules, review collections, and send files to external chemistry tools.</li>



<li><strong>iPhone preview app:</strong> build the <code>BuretteMobile</code> Xcode target from source, then open molecular documents from Files or another iOS document provider.</li>



<li><strong>Public molecular plugin:</strong> preview an authorized molecular attachment or a public PDB entry directly in the Burette workspace through ChatGPT or Codex.</li>
</ul>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Avogadro Updated</title>
		<link>https://macinchem.org/2026/10/23/avogadro-updated/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Fri, 23 Oct 2026 17:47:38 +0000</pubDate>
				<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[Science Apps]]></category>
		<category><![CDATA[cheminformatics]]></category>
		<category><![CDATA[compchem]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3267</guid>

					<description><![CDATA[Avogadro is an advanced open source molecular editor and visualization tool. Download and installation instructions are here https://avogadro.cc/install/index.html]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Avogadro is an advanced open source molecular editor and visualization tool.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="894" src="https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-23-at-18.41.25-1024x894.png" alt="" class="wp-image-3268" srcset="https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-23-at-18.41.25-1024x894.png 1024w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-23-at-18.41.25-300x262.png 300w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-23-at-18.41.25-768x671.png 768w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-23-at-18.41.25.png 1135w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Download and installation instructions are here <a href="https://avogadro.cc/install/index.html">https://avogadro.cc/install/index.html</a></p>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>OpenBind Blind Challenge: Zika virus NS2B-NS3 protease</title>
		<link>https://macinchem.org/2026/10/22/openbind-blind-challenge-zika-virus-ns2b-ns3-protease/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Thu, 22 Oct 2026 10:38:39 +0000</pubDate>
				<category><![CDATA[Hints and Tutorials]]></category>
		<category><![CDATA[Jupyter Notebook]]></category>
		<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[cheminformatics]]></category>
		<category><![CDATA[docking]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[rdkit]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3246</guid>

					<description><![CDATA[On October 14th the OpenBind Blind Challenge was launched, the target is the Zika virus NS2B-NS3 protease. This challenge focuses on predicting how small molecules]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">On October 14th the OpenBind Blind Challenge was launched, the target is the<a href="https://openbind.uk/news/announcing-the-first-openbind-blind-challenge-zika-virus-ns2b-ns3-protease-2/"> Zika virus NS2B-NS3 protease.</a></p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">This challenge focuses on predicting how small molecules bind to the Zika virus NS2B-NS3 protease. We invite the molecular modelling community to predict protein–ligand complexes for 400 compounds, spanning small fragments to larger, lead-like molecules. Our aim is not simply to produce a leaderboard, but to understand where methods succeed, where they fail, and how they can be improved</p>
</blockquote>



<p class="wp-block-paragraph">Having just updated the <a href="https://macinchem.org/2026/10/15/an-updated-jupyter-notebook-for-docking/">docking scoring Jupyter notebook</a> I thought it might be interesting to provide a version for the blind challenge.  This notebook could perhaps be modified to try different docking algorithms or alternative scoring functions.</p>



<p class="wp-block-paragraph">As the website highlights structural studies have shown&nbsp;that the ZIKV NS2B-NS3 protease can adopt several conformations involving rearrangement of the NS2B cofactor: a closed conformation, an open conformation, and a super-open conformation. The open and super-open conformations are considered proteolytically inactive, as the C-terminal part of NS2B that contributes to the substrate-binding site is unstructured in these conformations.</p>



<p class="wp-block-paragraph">The focus been on the closed conformation of NS2B-NS3, using a bicistronic vector to co-express the NS2B cofactor and the NS3 protease. This optimised system gave us crystals in the P4<sub>3</sub>22 space group with only one NS2B-NS3 complex in the asymmetric unit and an accessible active site, ideal for fragment screening and ligand soaking (PDB code:&nbsp;<a href="https://www.rcsb.org/structure/29HN"></a><strong><a href="https://www.rcsb.org/structure/29HN" target="_blank" rel="noopener">29HN</a></strong>). This structure has no ligand bound, but there are several other structures in the PDB that contain a bound ligand including <a href="https://www.rcsb.org/structure/7H1J">7H1J</a> and <a href="https://www.rcsb.org/structure/9RM4">9RM4</a>. All three structures were imported into <a href="https://www.chemcomp.com/en/Products.htm">MOE</a> and the structures prepared. They were then superimposed as shown below.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="824" height="1024" src="https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.15-824x1024.png" alt="" class="wp-image-3247" srcset="https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.15-824x1024.png 824w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.15-242x300.png 242w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.15-768x954.png 768w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.15.png 1028w" sizes="(max-width: 824px) 100vw, 824px" /></figure>



<p class="wp-block-paragraph">A close up view of the binding site is shown below.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="914" src="https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.53-1024x914.png" alt="" class="wp-image-3248" srcset="https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.53-1024x914.png 1024w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.53-300x268.png 300w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.53-768x686.png 768w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-15-at-15.30.53.png 1028w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">And the key ligand interactions are shown here.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="768" src="https://macinchem.org/wp-content/uploads/2026/10/ZIKV_NS2B-NS3_protease_site-1024x768.png" alt="" class="wp-image-3253" srcset="https://macinchem.org/wp-content/uploads/2026/10/ZIKV_NS2B-NS3_protease_site-1024x768.png 1024w, https://macinchem.org/wp-content/uploads/2026/10/ZIKV_NS2B-NS3_protease_site-300x225.png 300w, https://macinchem.org/wp-content/uploads/2026/10/ZIKV_NS2B-NS3_protease_site-768x576.png 768w, https://macinchem.org/wp-content/uploads/2026/10/ZIKV_NS2B-NS3_protease_site-800x600.png 800w, https://macinchem.org/wp-content/uploads/2026/10/ZIKV_NS2B-NS3_protease_site.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">This ligand was copied into the binding site of the superimposed structure 29HN and minimised. This was then exported in pdb format and used for the docking studies. </p>



<p class="wp-block-paragraph">The notebook used for docking <a href="https://macinchem.org/wp-content/uploads/2026/10/ZIKV_DockingScoring_flexible.html">can be seen here</a>, this version actually only docks a trial 10 compounds to test the process. In this html version the sliders to scroll through the poses don&#8217;t work but you can download the actual notebook at the bottom of the page.</p>



<p class="wp-block-paragraph">After docking the poses are scored using AEV-Plig and the best scoring poses for each ligand is exported as both a pdb file and as a PyMOL session file.</p>



<p class="wp-block-paragraph">As you can see from the plot below there is little correlation between Smina docking score and the AEV-plig score.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="590" height="440" src="https://macinchem.org/wp-content/uploads/2026/10/Unknown.png" alt="" class="wp-image-3258" srcset="https://macinchem.org/wp-content/uploads/2026/10/Unknown.png 590w, https://macinchem.org/wp-content/uploads/2026/10/Unknown-300x224.png 300w" sizes="auto, (max-width: 590px) 100vw, 590px" /></figure>



<p class="wp-block-paragraph">The notebook and associated files can all be downloaded from GitHub <a href="https://github.com/drc007/zika_docking">https://github.com/drc007/zika_docking</a></p>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>An Updated Jupyter Notebook for docking</title>
		<link>https://macinchem.org/2026/10/15/an-updated-jupyter-notebook-for-docking/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Thu, 15 Oct 2026 09:58:32 +0000</pubDate>
				<category><![CDATA[Hints and Tutorials]]></category>
		<category><![CDATA[Jupyter Notebook]]></category>
		<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[Science Apps]]></category>
		<category><![CDATA[artificial intelligence]]></category>
		<category><![CDATA[cheminformatics]]></category>
		<category><![CDATA[compchem]]></category>
		<category><![CDATA[docking]]></category>
		<category><![CDATA[molecular modelling]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[rdkit]]></category>
		<category><![CDATA[smina]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3210</guid>

					<description><![CDATA[In 2020 as a result of lockdown I was asked to help create a course for MRes students as an introduction to computer-aided drug design]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In 2020 as a result of lockdown I was asked to help create a course for MRes students as an introduction to computer-aided drug design [<a href="https://doi.org/10.1021/acs.jchemed.1c00289">DOI</a>] that they all complete at home.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="367" src="https://macinchem.org/wp-content/uploads/2026/03/images_large_ed1c00289_0004-1024x367.jpeg" alt="" class="wp-image-2901" srcset="https://macinchem.org/wp-content/uploads/2026/03/images_large_ed1c00289_0004-1024x367.jpeg 1024w, https://macinchem.org/wp-content/uploads/2026/03/images_large_ed1c00289_0004-300x108.jpeg 300w, https://macinchem.org/wp-content/uploads/2026/03/images_large_ed1c00289_0004-768x276.jpeg 768w, https://macinchem.org/wp-content/uploads/2026/03/images_large_ed1c00289_0004.jpeg 1257w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">This work lead to the above publication which has had over 18,500 total views and been downloaded almost 5000 times.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="293" src="https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-07-at-15.30.59-1024x293.png" alt="" class="wp-image-3212" srcset="https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-07-at-15.30.59-1024x293.png 1024w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-07-at-15.30.59-300x86.png 300w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-07-at-15.30.59-768x220.png 768w, https://macinchem.org/wp-content/uploads/2026/10/Screenshot-2026-10-07-at-15.30.59.png 1336w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">There is also a lab manual and the old Jupyter notebook all of which are freely available on GitHub</p>



<p class="wp-block-paragraph"><a href="https://github.com/UCL/Open_Docking_Lab_Handbook">https://github.com/UCL/Open_Docking_Lab_Handbook</a></p>



<p class="wp-block-paragraph">Over the years I&#8217;ve updated the notebook to fix bugs and add features that students at different universities have requested, the result is a project that become a little unwieldy and I thought I&#8217;d spend a few weeks (with Claude) cleaning it all up and making it a lot more efficient.</p>



<p class="wp-block-paragraph">This notebook does not include the preparation of the target protein for docking, but here are a few of the things that need to be addressed. </p>



<p class="wp-block-paragraph">–Alternates, Residues with alternate locations and/or ambiguous sequence identities (choose highest occupancy) but remember proteins are not static.</p>



<p class="wp-block-paragraph">–Termini, Protein chain C- or N-termini which need to be charged or capped, or if DNA the terminal PO4 may only have three oxygens bonded to the phosphorous and an additional oxygen needs to be added. Sometimes loops are very disordered and appear as a breaks in the chain, it may be possible to use a loop library to model a replacement.</p>



<p class="wp-block-paragraph">–Hydrogens, usually not visible and so need to be added/checked, particularly check hydrogens on heteroatoms, especially active site residues where the local environment may influence&nbsp;pKa&nbsp;</p>



<p class="wp-block-paragraph">–Ligand, Novel ligands in particular need checking to confirm atoms and bond orders are correct (PDB files do not contain bond information)</p>



<p class="wp-block-paragraph">–Conformation, check that torsions are reasonable and there are no clashes.</p>



<p class="wp-block-paragraph">–Charge, It with worth checking the charge on all ionisable groups.</p>



<p class="wp-block-paragraph">–It can be difficult to be certain of the position of&nbsp;nitrogens&nbsp;in His or the primary amide in&nbsp;Asn,&nbsp;Gln.</p>



<p class="wp-block-paragraph">The new README for the docking and scoring is shown below</p>



<h1 class="wp-block-heading">Docking_scoring</h1>



<p class="wp-block-paragraph">A Jupyter notebook for docking ligands into a protein with <strong>smina</strong> and rescoring the poses with the <strong>AEV-PLIG</strong> binding-affinity model. It covers conformer generation, binding-site preparation, rigid or flexible docking, pose viewing, affinity prediction using AEV-plig and export in a variety of formats.</p>



<p class="wp-block-paragraph">The example is the SARS-CoV-2 main protease (Mpro) fragment structure <strong>5RHD</strong>. A fully run copy of the notebook is in <code>DockingScoring.html</code> (download it and open it in a browser to see the outputs and interactive 3D views) and, for printing or quick viewing on GitHub, <code>DockingScoring.pdf</code>.</p>



<h2 class="wp-block-heading">Workflow</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="583" src="https://macinchem.org/wp-content/uploads/2026/10/docking_scoring_schematic-1024x583.png" alt="" class="wp-image-3239" srcset="https://macinchem.org/wp-content/uploads/2026/10/docking_scoring_schematic-1024x583.png 1024w, https://macinchem.org/wp-content/uploads/2026/10/docking_scoring_schematic-300x171.png 300w, https://macinchem.org/wp-content/uploads/2026/10/docking_scoring_schematic-768x437.png 768w, https://macinchem.org/wp-content/uploads/2026/10/docking_scoring_schematic-1536x875.png 1536w, https://macinchem.org/wp-content/uploads/2026/10/docking_scoring_schematic-2048x1166.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<ol class="wp-block-list">
<li><strong>Ligands.</strong> Load an SDF of 3D structures, check that the names are unique, and browse the molecules with a slider.<br>1b. <strong>Ionisation states.</strong> Optionally predict each ligand&#8217;s ionisation state at a chosen pH with QupKake (micro-pKa prediction), and dock the ligands in those states.</li>



<li><strong>Conformers.</strong> Generate conformers with RDKit srETKDGv3 (or ETKDGv3, ETKDG, ETDG), pruned by RMSD, MMFF94-minimised and filtered by an energy window. Undefined stereocentres can optionally be enumerated.</li>



<li><strong>Binding site.</strong> Either:
<ul class="wp-block-list">
<li>load a <strong>protein–ligand complex PDB</strong> and pick the ligand that defines the site, or</li>



<li>supply <strong>prepared files</strong>: a protein without the ligand plus the extracted ligand.</li>
</ul>
</li>



<li><strong>Images.</strong> Ray-traced PyMOL images of the whole protein with the ligand bound, and of the ligand in the binding site.</li>



<li><strong>Docking.</strong> An smina input panel for rigid docking, flexible side chains, or <code>--minimize</code>.</li>



<li><strong>Results.</strong> Step through the poses in 3D with a slider.</li>



<li><strong>AEV-PLIG.</strong> Predict the pK of every pose, and score the ligand from the PDB in its crystal pose as a reference.</li>



<li><strong>Export.</strong> Write the best pose of each ligand as PDB files and as a PyMOL session.</li>
</ol>



<h2 class="wp-block-heading">Setup</h2>



<p class="wp-block-paragraph">Run these commands from the repository folder.</p>



<h3 class="wp-block-heading">1. Conda environment and Jupyter kernel</h3>



<pre class="wp-block-code"><code>conda env create -f environment.yml</code></pre>



<pre class="wp-block-code"><code>conda run -n docking_scoring python -m ipykernel install --user --name docking_scoring --display-name "Python (docking_scoring)"</code></pre>



<p class="wp-block-paragraph"><code>environment.yml</code> is portable (macOS and Linux) and installs current versions. <code>docking_scoring.yml</code> pins the exact versions this was developed and tested with on an Apple-silicon Mac. It has never been tested under Windows and the best option might be to try<a href="https://learn.microsoft.com/en-us/windows/wsl/install"> Windows Subsystem for Linux</a> .</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Package</th><th>Tested version</th></tr></thead><tbody><tr><td>Python</td><td>3.12</td></tr><tr><td>RDKit</td><td>2026.09</td></tr><tr><td>PyTorch</td><td>2.10 (conda-forge)</td></tr><tr><td>torch-geometric</td><td>2.8</td></tr><tr><td>torchani</td><td>2.9</td></tr><tr><td>PyMOL (open source)</td><td>3.1</td></tr><tr><td>Open Babel</td><td>3.2</td></tr><tr><td>gemmi</td><td>0.7</td></tr><tr><td>py3Dmol</td><td>2.5</td></tr><tr><td>ipywidgets</td><td>8.1</td></tr><tr><td>JupyterLab</td><td>4.6</td></tr></tbody></table></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>Install PyTorch from conda-forge, not pip.</strong> The pip wheel bundles its own OpenMP library, which clashes with conda&#8217;s and crashes on import with <code>OMP: Error #15</code>.</p>
</blockquote>



<h3 class="wp-block-heading">2. AEV-PLIG trained models</h3>



<p class="wp-block-paragraph">The trained models (about 300 MB) are not stored in this repository. Download them from the official <a href="https://github.com/oxpig/AEV-PLIG">AEV-PLIG repository</a>:</p>



<pre class="wp-block-code"><code>conda run -n docking_scoring python aev_plig/download_models.py</code></pre>



<p class="wp-block-paragraph">The script fetches the 10-model <code>model_GATv2Net_ligsim90_fep_benchmark</code> ensemble and its scaler from a fixed upstream commit, checks each file&#8217;s checksum, and saves them to <code>aev_plig/output/trained_models/</code>.</p>



<h3 class="wp-block-heading">3. smina</h3>



<p class="wp-block-paragraph">smina is not included in <code>environment.yml</code>: the conda-forge smina package (2020 build) needs an old version of Boost that forces an old RDKit. Install it in one of two ways:</p>



<ul class="wp-block-list">
<li><strong>A separate conda environment</strong>, which the notebook finds automatically: <code>conda create -n smina -c conda-forge smina</code></li>



<li><strong>The prebuilt binary</strong> from <a href="https://sourceforge.net/projects/smina/">https://sourceforge.net/projects/smina/</a>. Make it executable (<code>chmod +x</code>), then put it on your <code>PATH</code> or set the <code>SMINA</code> environment variable to its full path.</li>
</ul>



<p class="wp-block-paragraph">The notebook looks for smina in this order:</p>



<ol class="wp-block-list">
<li>the <code>SMINA</code> environment variable;</li>



<li><code>smina</code>, <code>smina.static</code> or <code>smina.osx.12</code> in the notebook&#8217;s environment or on the <code>PATH</code>;</li>



<li>a conda environment called <code>smina</code>;</li>



<li><code>/usr/local/smina.osx.12</code> and other common locations.</li>
</ol>



<p class="wp-block-paragraph">You can also type the path into the smina panel.</p>



<h3 class="wp-block-heading">4. Run</h3>



<p class="wp-block-paragraph">Open <code>DockingScoring.ipynb</code> in JupyterLab with the <strong>Python (docking_scoring)</strong> kernel.</p>



<ul class="wp-block-list">
<li>Each step has a panel with a <strong>Run</strong> or <strong>Apply</strong> button. Running all cells sets the panels up but does not start the long jobs.</li>



<li>To run every step with the default settings, set <code>AUTO_RUN = True</code> in the first code cell.</li>
</ul>



<h2 class="wp-block-heading">Project layout</h2>



<pre class="wp-block-code"><code>DockingScoring.ipynb         the notebook
DockingScoring.html          a fully run copy of the notebook (static)
DockingScoring.pdf           the same, as a PDF (A4 landscape)
docking_tools.py             all helper code (panels, viewers, docking, scoring, export)
environment.yml              conda environment (portable)
docking_scoring.yml          exact tested environment (macOS arm64)
aev_plig/                    AEV-PLIG prediction code (models: aev_plig/download_models.py)
example/                     5RHD example inputs; results are written here when you run the notebook</code></pre>



<p class="wp-block-paragraph">Generated results are not tracked in git (see <code>.gitignore</code>). Run the notebook to recreate them, or see <code>DockingScoring.html</code>.</p>



<h2 class="wp-block-heading">Inputs</h2>



<h3 class="wp-block-heading">Ligand SDF</h3>



<ul class="wp-block-list">
<li>3D structures, ideally with hydrogens.</li>



<li>Each record needs a name on its first line.</li>



<li>smina keeps only that name, and the results are grouped by it, so different structures must not share a name.</li>
</ul>



<p class="wp-block-paragraph">The notebook checks for duplicate names. If it finds any, it offers two fixes:</p>



<ul class="wp-block-list">
<li>use an SD field with a unique value for every molecule (e.g. <code>ID</code>, <code>IDNUMBER</code>, <code>Record_ID</code>) as the ligand ID, or</li>



<li>assign unique names automatically (<code>name</code>, <code>name_2</code>, …).</li>
</ul>



<p class="wp-block-paragraph">The original name is kept in the <code>original_name</code> property, and the input file is not modified.</p>



<h3 class="wp-block-heading">Binding site</h3>



<p class="wp-block-paragraph"><strong>Complex structure mode</strong> (PDB or mmCIF)</p>



<ul class="wp-block-list">
<li>Reads <code>.pdb</code> and mmCIF (<code>.cif</code>, <code>.mmcif</code>, optionally gzipped). mmCIF is the PDB&#8217;s standard format, and is read with <a href="https://gemmi.readthedocs.io">gemmi</a>.</li>



<li><strong>Lists all ligands</strong>, with chemical names where the file has them, and <strong>selects the largest automatically</strong>. The panel says which one was chosen; pick another from the list if the file holds several ligands.</li>



<li>Hides waters, solvents and crystallisation additives (e.g. DMSO, glycerol, PEG, sulfate), ions, and terminal caps such as NME. Tick <em>Also list solvents, ions, additives and caps</em> to show them.</li>



<li>Uses only the first alternate location (A) of the protein and ligand.</li>



<li>Bond orders for the extracted ligand come from, in order of preference:
<ol class="wp-block-list">
<li>a SMILES template, if you paste one. Its charges are kept, so it can set the protonation state;</li>



<li>the ligand&#8217;s hydrogens and formal charges (RDKit), when hydrogens are present;</li>



<li>the ligand&#8217;s entry in the PDB Chemical Component Dictionary, fetched from RCSB, for files without hydrogens such as RCSB X-ray structures. It is used only if its heavy atoms match, and gives the neutral molecule;</li>



<li>Open Babel perception from the geometry.</li>
</ol>
</li>



<li>The protein file keeps the HELIX and SHEET records, but other HET groups and waters are removed. Metal ions are kept unless you untick that option.</li>



<li>Output files are named after the input, e.g. <code>5RHD_protein.pdb</code>. mmCIF input adds <code>_cif</code> (<code>5RHD_cif_protein.pdb</code>), so it never overwrites files made from a PDB file of the same entry, which may use a different coordinate frame.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>Example:</strong> <code>example/5RHD.pdb</code> was prepared in MOE (hydrogens added, piperazine protonated, ligand named <code>LIG</code>). <code>example/5RHD.cif</code> is the RCSB file: its ligand <code>US7</code> has no hydrogens and is taken as the neutral molecule. Paste <code>CS(=O)(=O)c1ccc(N2CC[NH2+]CC2)cc1</code> as the SMILES template for the protonated form. Using the CIF gave the same best-pose AEV-PLIG pK for FromXRay (5.31) as the PDB file.</p>
</blockquote>



<p class="wp-block-paragraph"><strong>Prepared-files mode</strong> uses your protein and ligand PDB files as they are.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>Note:</strong> The two modes can give different smina scores for the same ligand. For example, <code>proteinNoligand.pdb</code> keeps the waters and DMS molecules, which add contacts. Compare runs that used the same mode.</p>
</blockquote>



<h2 class="wp-block-heading">Outputs</h2>



<p class="wp-block-paragraph">Docked poses are stored as SDF files. The best pose of each ligand is also exported as PDB files (ligand only, and protein–ligand complex) and as a PyMOL session file.</p>



<p class="wp-block-paragraph">Every output is written next to the input it was derived from.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>File</th><th>Location</th></tr></thead><tbody><tr><td><code>&lt;input&gt;_pH7.4.sdf</code> / <code>.csv</code> (ligands in QupKake-predicted ionisation states) and <code>qupkake/</code></td><td>next to the ligand SDF</td></tr><tr><td><code>&lt;input&gt;_confs.sdf</code></td><td>next to the ligand SDF</td></tr><tr><td><code>&lt;stem&gt;_protein.pdb</code>, <code>&lt;stem&gt;_ligand_&lt;RES&gt;&lt;chain&gt;&lt;num&gt;.pdb/.sdf</code></td><td>next to the complex PDB</td></tr><tr><td><code>&lt;stem&gt;_complex.png</code>, <code>&lt;stem&gt;_site.png</code></td><td>next to the binding-site input</td></tr><tr><td><code>&lt;input&gt;_docked.sdf</code> / <code>_flexdocked.sdf</code> / <code>_minimized.sdf</code>, plus <code>.log</code> and <code>.run.json</code> (run record)</td><td>next to the ligand SDF</td></tr><tr><td><code>&lt;output&gt;_flexres.pdb</code> (flexible docking: one model per pose)</td><td>next to the docked SDF</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">All prediction results go to a <code>predictions/</code> folder next to the docked SDF:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>File</th><th>Contents</th></tr></thead><tbody><tr><td><code>&lt;docked&gt;_summary.csv</code></td><td>every pose: smina score, AEV-PLIG pK (10-model mean ± std), heavy atoms, ligand efficiency, box margin, best-pose flags</td></tr><tr><td><code>&lt;docked&gt;_run_info.json</code></td><td>run record: docking and scoring settings, software versions, input checksums</td></tr><tr><td><code>&lt;docked&gt;_best_poses_table.csv</code></td><td>best pose per ligand, plus the PDB ligand row (AEV-PLIG pK, smina scores, ligand efficiency, box margin)</td></tr><tr><td><code>&lt;docked&gt;_scored.sdf</code>, <code>&lt;docked&gt;_best_poses.sdf</code></td><td>poses annotated with pK</td></tr><tr><td><code>best_poses_pdb/&lt;docked&gt;/</code></td><td>best pose per ligand as <code>_ligand.pdb</code> and <code>_complex.pdb</code> (ligand = chain L, resname LIG)</td></tr><tr><td><code>&lt;docked&gt;_best_poses.pse</code></td><td>PyMOL session of the best poses</td></tr><tr><td><code>&lt;docked&gt;_smina_vs_aevplig.png</code></td><td>smina score vs pK; the dashed line is the PDB ligand</td></tr><tr><td><code>poses/&lt;docked&gt;/</code></td><td>per-pose AEV-PLIG inputs (and per-pose receptors after flexible docking)</td></tr><tr><td><code>pdb_ligand/</code></td><td>the PDB ligand as scored by smina, its minimised pose and the log</td></tr><tr><td><code>&lt;docked&gt;_aevplig_input.csv</code>, <code>&lt;docked&gt;_predictions.csv</code>, logs</td><td>raw AEV-PLIG input and output</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Copies of the docked SDF, receptor, reference ligand, conformers and images are also placed in <code>predictions/</code>, so the folder is a self-contained record.</p>



<h2 class="wp-block-heading">Search box</h2>



<p class="wp-block-paragraph">smina docks only inside the search box: the extent of the autobox ligand (all atoms, hydrogens included) plus <code>autobox_add</code> (default 4 Å) on every side. Atoms outside the box are heavily penalised during the search, and smina gives <strong>no warning</strong> when a ligand is too large. The ligand is simply squeezed: it curls up, or groups that would reach a neighbouring sub-pocket point elsewhere.</p>



<p class="wp-block-paragraph"><strong>Before docking</strong>, the smina panel shows the box size and compares each ligand&#8217;s longest heavy-atom span, taken from the conformer file, with the smallest box side:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Status</th><th>Meaning</th></tr></thead><tbody><tr><td>ok</td><td>at least 2 Å to spare</td></tr><tr><td><em>tight</em></td><td>less than 2 Å to spare</td></tr><tr><td><em>longer than smallest box side</em></td><td>the ligand can only fit along a diagonal</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">When any ligand is tight or longer, the panel suggests an <code>autobox_add</code>. It also warns above Vina&#8217;s recommended 27,000 Å³.</p>



<p class="wp-block-paragraph"><strong>After docking</strong>, smina&#8217;s output reports how many poses have a heavy atom within 1 Å of a box face. The summary and best-poses tables add <code>box_margin</code>, the closest heavy-atom distance to a face in Å (negative means outside), and <code>at_box_edge</code>. A <strong>best pose at the box edge</strong> means the box may have limited that ligand: re-dock with a larger <code>autobox_add</code>, or set the box explicitly with <code>--center_x/y/z --size_x/y/z</code> under &#8220;extra arguments&#8221;.</p>



<p class="wp-block-paragraph">Example (5RHD fragment + 4 Å = 16.8 × 13.2 × 15.5 Å):</p>



<ul class="wp-block-list">
<li>Phenyl (11.4 Å) and iProAmine (11.9 Å) are <em>tight</em>.</li>



<li>38 of 297 poses come within 1 Å of the edge, and 3 have an atom slightly outside.</li>



<li>iProAmine&#8217;s best AEV-PLIG pose is 0.13 Å outside the box.</li>
</ul>



<p class="wp-block-paragraph">The box is stored in each run record (<code>&lt;output&gt;.run.json</code>).</p>



<h2 class="wp-block-heading">Ligand efficiency</h2>



<p class="wp-block-paragraph">The summary and best-poses tables include ligand efficiency (LE), the binding free energy per heavy atom, in kcal/mol per heavy atom:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Column</th><th>Definition</th></tr></thead><tbody><tr><td><code>heavy_atoms</code></td><td>number of non-hydrogen atoms</td></tr><tr><td><code>LE_AEV_PLIG</code></td><td>1.364 × pK / heavy atoms, from the AEV-PLIG pK (ΔG = −2.303 RT pK at 298 K)</td></tr><tr><td><code>LE_smina</code></td><td>−(smina score) / heavy atoms</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">An LE of about 0.3 or more is the usual guide for a good starting point. Small fragments such as the 5RHD series (15–21 heavy atoms) typically score 0.4–0.5 on <code>LE_AEV_PLIG</code>.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>Note:</strong> After flexible docking, <code>LE_smina</code> is inflated, because the flexible smina score appears to include the flexed side chains. Use <code>LE_AEV_PLIG</code> to compare across docking modes.</p>
</blockquote>



<h2 class="wp-block-heading">Ionisation states (QupKake)</h2>



<p class="wp-block-paragraph"><a href="https://github.com/Shualdon/QupKake">QupKake</a> (Abarbanel &amp; Hutchison, <em>J. Chem. Theory Comput.</em> 2024, <a href="https://doi.org/10.1021/acs.jctc.4c00328">https://doi.org/10.1021/acs.jctc.4c00328</a>) predicts micro-pKa values from GFN2-xTB calculations and graph neural networks. Step 1b of the notebook uses it to set the ionisation state of the input ligands and of the ligand from the PDB.</p>



<p class="wp-block-paragraph"><strong>How the state is set:</strong></p>



<ol class="wp-block-list">
<li>Each ligand is neutralised and submitted to QupKake, which predicts a pKa for every basic and acidic site.</li>



<li>At the chosen pH (default 7.4), the <strong>most basic site is protonated</strong> if its pKa is above the pH, and the <strong>most acidic site is deprotonated</strong> if its pKa is below it. At most one of each is applied. Other sites that also cross the pH are reported, not applied.</li>



<li><strong>Implausible basic sites are ignored</strong> (on by default; untick the box to use every site). For this ligand series QupKake reported sulphonamide N, amide N and aryl-amine N, such as the N-aryl nitrogen of an aryl-piperazine, as the most basic sites. Taken at face value, that would protonate a sulphonamide (<code>[NH3+]S(=O)(=O)…</code>).</li>
</ol>



<p class="wp-block-paragraph">The ligands in their predicted states are written to <code>&lt;input&gt;_pH7.4.sdf</code>, with a table in <code>&lt;input&gt;_pH7.4.csv</code>. When docking in the predicted states is ticked, that file is docked, so every later output is named <code>&lt;input&gt;_pH7.4_…</code> and never overwrites the results for the input states. The PDB ligand keeps its crystal coordinates and is used as the reference in the final table. QupKake&#8217;s own files are in <code>qupkake/</code> next to the input.</p>



<p class="wp-block-paragraph"><strong>Example result (pH 7.4).</strong> With the filter on, QupKake&#8217;s states match the MOE-prepared input exactly: the piperazine or piperidine NH is protonated, or the N-isopropyl N for iProAmine. Re-docking therefore reproduced all 297 poses and scores. The neutral US7 from <code>5RHD.cif</code> is protonated to the same state.</p>



<p class="wp-block-paragraph">With the filter off, 6 of the 7 ligands were charged on a sulphonamide or aryl-amine N, and the best-pose AEV-PLIG pK changed by −0.27 to +0.35:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Ligand</th><th>pK, input / QupKake (filtered)</th><th>pK, QupKake raw</th><th>Raw protonation site</th></tr></thead><tbody><tr><td>iProAmine</td><td>6.87</td><td>6.77</td><td>sulphonamide NH₂</td></tr><tr><td>sulphonamide</td><td>6.57</td><td>6.46</td><td>sulphonamide NH₂</td></tr><tr><td>Phenyl</td><td>5.67</td><td>5.47</td><td>aryl N</td></tr><tr><td>piperidine</td><td>5.45</td><td>5.45</td><td>piperidine NH (same)</td></tr><tr><td>FromXRay</td><td>5.31</td><td>5.04</td><td>aryl N</td></tr><tr><td>DimethylN</td><td>5.22</td><td>5.57</td><td>sulphonamide N(CH₃)₂</td></tr><tr><td>amide</td><td>4.67</td><td>4.40</td><td>aryl N</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><strong>Installing QupKake.</strong> It needs its own conda environment, named <code>qupkake</code>, with xtb 6.4.1 built from source; see the QupKake README. On Apple silicon, build xtb at <code>-O2</code>, because gfortran 16 at <code>-O3</code> miscompiles it. The notebook finds the environment automatically and limits each xtb process to one thread. If QupKake is not installed, the input ionisation states are used. </p>



<p class="wp-block-paragraph">Full details for installing QupKake are available here <a href="https://github.com/drc007/qupkake-apple-silicon/tree/main/qupkake-apple-silicon">https://github.com/drc007/qupkake-apple-silicon/tree/main/qupkake-apple-silicon</a></p>



<h2 class="wp-block-heading">Reproducibility</h2>



<p class="wp-block-paragraph">Every smina run writes a run record next to its output, <code>&lt;output&gt;.run.json</code>, and the same summary at the top of <code>&lt;output&gt;.log</code>. The record holds:</p>



<ul class="wp-block-list">
<li>the smina version and path, and the full command;</li>



<li>seed, <code>--cpu</code>, exhaustiveness and every other setting;</li>



<li>the platform;</li>



<li>SHA-256 checksums of the receptor, ligand and autobox files and of the output.</li>
</ul>



<p class="wp-block-paragraph">AEV-PLIG adds <code>predictions/&lt;docked&gt;_run_info.json</code>, which contains that docking record plus the model, scoring options, library versions, receptor checksum and the PDB-ligand scores.</p>



<p class="wp-block-paragraph"><strong>Seed and thread count.</strong> With the tested smina build (<code>master:dc3dfab</code>, based on AutoDock Vina 1.1.2), a fixed <code>--seed</code> gave identical poses whatever the <code>--cpu</code> value:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Mode</th><th><code>--cpu</code> values compared</th><th>Coordinates</th><th>Reported scores</th></tr></thead><tbody><tr><td>Rigid</td><td>1, 4, 8, 24</td><td>identical</td><td>identical</td></tr><tr><td>Flexible</td><td>1, 3, 24</td><td>identical</td><td>identical at <code>--cpu</code> 1 and 24</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">At <code>--cpu 3</code> (fewer threads than exhaustiveness runs), flexible docking showed a run-to-run jitter of up to 0.002 kcal/mol in the reported score. That is below the 0.01 kcal/mol precision of smina&#8217;s log.</p>



<p class="wp-block-paragraph"><code>--cpu</code> therefore defaults to the number of cores. Results can still differ with a different smina or Vina build, platform or compiler, so keep the run record with your results.</p>



<h2 class="wp-block-heading">Flexible docking</h2>



<ul class="wp-block-list">
<li>Choose <strong>Flexible side chains</strong> in the smina panel.</li>



<li><strong>Automatic</strong> selection takes every residue within a set distance of the ligand (default 5 Å).</li>



<li><strong>Manual</strong> selection lets you pick residues from a list, or type them (<code>A:41,A:145</code>).</li>



<li>Gly, Ala and Pro are excluded, because their side chains have no rotatable bonds.</li>
</ul>



<p class="wp-block-paragraph"><strong>It is much slower than rigid docking.</strong> For the example&#8217;s 33 conformers:</p>



<ul class="wp-block-list">
<li>rigid docking took about 40 s;</li>



<li>flexible docking with 4 residues at exhaustiveness 8 took about 8½ min.</li>
</ul>



<p class="wp-block-paragraph">The automatic 5 Å selection picks 13 residues for 5RHD, which would be far slower again.</p>



<p class="wp-block-paragraph">smina writes the flexed side chains for every pose. They come out in the same order as the poses, but without PDB atom names. The notebook maps them back onto the receptor and rebuilds a complete receptor for each pose, which is used:</p>



<ul class="wp-block-list">
<li>in the 3D viewer, where the flexed side chains are magenta and the original ones grey;</li>



<li>by AEV-PLIG, which scores each pose against its own receptor;</li>



<li>in the PDB and PyMOL exports.</li>
</ul>



<p class="wp-block-paragraph"><strong>Pairing poses with their side chains is verified, not assumed.</strong> smina writes each ligand&#8217;s poses and side-chain models together, so if it skips a ligand both files lose it and stay in step (tested). Before anything is paired, the notebook checks:</p>



<ul class="wp-block-list">
<li>Names: the docked SDF&#8217;s record titles and the models&#8217; names must match. If they don&#8217;t, ligand blocks are aligned by name, and a block is paired only when its pose and model counts agree.</li>



<li>Geometry: a pose that overlaps its own flexed side chains (&lt; 1.5 Å) is rejected.</li>
</ul>



<p class="wp-block-paragraph">AEV-PLIG stops with an error on any mismatch, rather than score a pose against the wrong receptor. The viewer shows such poses with the rigid protein and a warning.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>Note:</strong> The flexible-docking smina score appears to include the flexed side chains, so its values (around −8 to −11 kcal/mol for the example) are not comparable with rigid scores or with the PDB-ligand row. AEV-PLIG pK values are comparable between modes.</p>
</blockquote>



<h2 class="wp-block-heading">AEV-PLIG</h2>



<p class="wp-block-paragraph"><code>aev_plig/</code> contains the AEV-PLIG prediction code (<code>process_and_predict.py</code> and its modules) from <a href="https://github.com/oxpig/AEV-PLIG">https://github.com/oxpig/AEV-PLIG</a>, licensed under the BSD 3-Clause licence in <code>aev_plig/LICENSE.txt</code>. The trained <code>model_GATv2Net_ligsim90_fep_benchmark</code> ensemble (10 models) is downloaded separately (see Setup).</p>



<p class="wp-block-paragraph">Changes for the current library versions:</p>



<ul class="wp-block-list">
<li>torchani 2.9 changed its <code>SpeciesConverter</code>, so the species index is now computed directly as atomic number − 1 (equivalent).</li>



<li><code>pkg_resources</code> is replaced by <code>importlib.metadata</code>.</li>



<li>Model weights are loaded with <code>torch.load(..., weights_only=False)</code>, which torch ≥ 2.6 requires.</li>



<li>A new <code>--output_dir</code> option controls where the predictions are written.</li>



<li>Dataset paths are handled with <code>os.path.splitext</code>.</li>



<li>RDKit&#8217;s deprecated <code>GetExplicitValence()</code> is replaced.</li>
</ul>



<p class="wp-block-paragraph"><strong>Regression check:</strong> on AEV-PLIG&#8217;s example dataset, all 241 predictions from the patched code in the new environment match the original code in a Python 3.8 / torch 2.4 environment to within 2×10⁻⁶.</p>



<h3 class="wp-block-heading">Hydrogens</h3>



<p class="wp-block-paragraph"><strong>Before scoring, all hydrogens are added to each ligand pose</strong>, because AEV-PLIG was trained on fully protonated ligands and one of its atom features counts attached hydrogens. smina writes polar hydrogens only. Scoring the same poses with every hydrogen removed changes the predicted pK by up to about 1 unit.</p>



<h3 class="wp-block-heading">Citation</h3>



<p class="wp-block-paragraph">Valsson <em>et al.</em>, &#8220;Narrowing the gap between machine learning scoring functions and free energy perturbation using augmented data&#8221;, <em>Communications Chemistry</em> (2025), <a href="https://doi.org/10.1038/s42004-025-01428-y">https://doi.org/10.1038/s42004-025-01428-y</a>. The licence is in <code>aev_plig/LICENSE.txt</code>.</p>



<h2 class="wp-block-heading">Display options</h2>



<ul class="wp-block-list">
<li><strong>Protein colouring</strong> uses the RasMol secondary-structure scheme by default: helix magenta-red, sheet yellow, coil and turn white. Coil is drawn light grey so it shows on a white background.
<ul class="wp-block-list">
<li>Set <code>dt.PROTEIN_COLOURING</code> to <code>"rainbow"</code> or <code>"grey"</code> for other schemes.</li>



<li>Set <code>dt.RASMOL_COIL = "#FFFFFF"</code> for strict RasMol white coil.</li>
</ul>
</li>



<li><strong>Pose viewers</strong> have toggles for the binding-site residues, the ligand from the PDB, and (after flexible docking) the original side chains.</li>



<li><strong>Binding-site image</strong> has a toggle to hide the side chains.</li>
</ul>



<h2 class="wp-block-heading">Known limitations</h2>



<ul class="wp-block-list">
<li><strong>smina silently stops at an unreadable SDF record.</strong> Every later ligand is skipped, the exit code is still 0, and the log says nothing. The smina panel warns before docking if the ligand file has unreadable records. After docking it compares the input ligands with the docked ones, reports any ligand with no poses, and records them in the run record (<code>ligands_missing</code>).</li>



<li>Running the notebook from the command line with <code>jupyter nbconvert --execute</code> stalls on the slider cells; this is an nbclient issue. All the steps still complete and their files are written. Use JupyterLab interactively.</li>



<li>Turns are coloured as coil unless the PDB file has TURN records, because neither 3Dmol.js nor PyMOL assigns turns.</li>



<li>AEV-PLIG accepts only the elements C, N, O, S, P, F, Cl, Br, I and B. Ligands with any other element are skipped, and the notebook reports how many were rejected.</li>
</ul>



<h2 class="wp-block-heading">Licence</h2>



<p class="wp-block-paragraph">The notebook, <code>docking_tools.py</code> and documentation are released under the MIT licence (see <code>LICENSE</code>) and are available on GitHub <a href="https://github.com/drc007/docking_scoring">https://github.com/drc007/docking_scoring</a>. </p>



<p class="wp-block-paragraph">The bundled AEV-PLIG code in <code>aev_plig/</code> keeps its own BSD 3-Clause licence (see <code>aev_plig/LICENSE.txt</code>). The 5RHD structure comes from the Protein Data Bank (<a href="https://www.rcsb.org/structure/5RHD">https://www.rcsb.org/structure/5RHD</a>).</p>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Icms2yield AI-Predicted Full-Spectrum UV Correction Factors: An Analyte-Standard-Free Framework for Reaction Yield Quantification</title>
		<link>https://macinchem.org/2026/10/13/icms2yield-ai-predicted-full-spectrum-uv-correction-factors-an-analyte-standard-free-framework-for-reaction-yield-quantification/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Tue, 13 Oct 2026 07:02:29 +0000</pubDate>
				<category><![CDATA[Data Analysis Tools]]></category>
		<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[Other Tips]]></category>
		<category><![CDATA[artificial intelligence]]></category>
		<category><![CDATA[cheminformatics]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3235</guid>

					<description><![CDATA[This looks interesting, High-throughput experimentation (HTE) accelerates molecular discovery but struggles to quantify yields without pure analyte standards. The current need to purify standards increases]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">This looks interesting, </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">High-throughput experimentation (HTE) accelerates molecular discovery but struggles to quantify yields without pure analyte standards. The current need to purify standards increases cost, complexity, and cycle time, limiting the scalability of new molecular discovery. Here, we introduce an integrated “detect-predict” framework that leverages artificial intelligence (AI) for analyte standard-free yield quantification.</p>
</blockquote>



<p class="wp-block-paragraph">Paper is here <a href="https://doi.org/10.1021/jacsau.6c00812">https://doi.org/10.1021/jacsau.6c00812</a></p>



<p class="wp-block-paragraph">Code <a href="https://github.com/xtalpi-inc/lcms2yield">https://github.com/xtalpi-inc/lcms2yield</a></p>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Compound Lookup Extensions</title>
		<link>https://macinchem.org/2026/10/11/compound-lookup-extensions/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Sun, 11 Oct 2026 07:13:49 +0000</pubDate>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[Science Apps]]></category>
		<category><![CDATA[cheminformatics]]></category>
		<category><![CDATA[molecular visualisation]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3230</guid>

					<description><![CDATA[I just noticed that the Compound Lookup extensions have been downloaded over 100 times (Safari + Chrome) and I&#8217;ve received some positive feedback.. I&#8217;m delighted]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I just noticed that the Compound Lookup extensions have been downloaded over 100 times (Safari + Chrome) and I&#8217;ve received some positive feedback.. I&#8217;m delighted that such a niche utility is proving useful.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Safari Extension, it allows you so select a drug name in a web page <a href="https://cambridgemedchemconsulting.com/distribution-and-plasma-protein-binding/">(for example</a>), right-click and from the dropdown menu there is the option to choose either PubChem or ChEMBL as shown below. Compound Lookup turns any compound name on a web page into a structure and a set of database identifiers, without leaving the page.</p>
</blockquote>



<p class="wp-block-paragraph">For Safari <a href="https://macinchem.org/2026/09/29/safari-extension/">https://macinchem.org/2026/09/29/safari-extension/</a></p>



<p class="wp-block-paragraph">For Chrome <a href="https://macinchem.org/2026/09/29/google-chrome-extension/">https://macinchem.org/2026/09/29/google-chrome-extension/</a> </p>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Building QupKake on Apple Silicon (macOS arm64)</title>
		<link>https://macinchem.org/2026/10/10/building-qupkake-on-apple-silicon-macos-arm64/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Sat, 10 Oct 2026 07:59:35 +0000</pubDate>
				<category><![CDATA[Hints and Tutorials]]></category>
		<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[Science Apps]]></category>
		<category><![CDATA[artificial intelligence]]></category>
		<category><![CDATA[compchem]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3223</guid>

					<description><![CDATA[QupKake predicts micro-pKa values with GFN2-xTB plus graph neural networks. Its README targets Linux. On an Apple Silicon Mac the obvious routes all fail: This]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://github.com/Shualdon/QupKake">QupKake</a> predicts micro-pKa values with GFN2-xTB plus graph neural networks. Its README targets Linux. On an Apple Silicon Mac the obvious routes all fail:</p>



<ul class="wp-block-list">
<li><strong>The bundled <code>xtb-641</code> binary</strong> is Linux x86-64 and can&#8217;t run on macOS.</li>



<li><strong>conda-forge <code>xtb</code></strong> is rejected by QupKake on import (&#8220;Conda version of xTB is currently not supported&#8221;). The conda-forge build also fails at runtime with <code>Library not loaded: @rpath/libgfortran.5.dylib</code>.</li>



<li><strong>A source build of xtb 6.4.1 with current compilers</strong> builds and runs, but at the default <code>-O3</code> it is <strong>silently miscompiled</strong>: geometry optimizations climb in energy and never converge (details under <a href="#pitfalls">Pitfalls</a>).</li>
</ul>



<p class="wp-block-paragraph">This guide gives a setup that works, tested on macOS 26.6 (Mac Studio, M-series, 24 cores) in October 2026.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Component</th><th>Version used</th></tr></thead><tbody><tr><td>Python</td><td>3.9 (conda-forge)</td></tr><tr><td>PyTorch / torchvision</td><td>2.1.2 / 0.16.1 (conda-forge, CPU)</td></tr><tr><td>pytorch-lightning / torchmetrics</td><td>2.1.4 / 1.8.2</td></tr><tr><td>torch_geometric</td><td>2.4.0 (pip)</td></tr><tr><td>RDKit</td><td>2025.03.5</td></tr><tr><td>xtb</td><td><strong>6.4.1 from source</strong>, gfortran 16.2 (conda-forge), OpenBLAS 0.3.34, meson 1.8</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Throughout this guide, <code>QK</code> is the directory the QupKake repo is cloned into:</p>



<pre class="wp-block-code"><code>export QK=$HOME/Projects/QupKake</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1. Clone QupKake</h2>



<pre class="wp-block-code"><code>git clone https://github.com/Shualdon/QupKake.git "$QK"</code></pre>



<h2 class="wp-block-heading">2. Create the conda environment</h2>



<p class="wp-block-paragraph">Use <strong>conda-forge only</strong>. The <code>pytorch</code> channel named in the repo&#8217;s <code>environment.yaml</code> no longer publishes builds. The same environment also supplies the Fortran toolchain for xtb, so the binary links against the env&#8217;s own <code>libgfortran</code> and <code>openblas</code>.</p>



<pre class="wp-block-code"><code>conda create -n qupkake -c conda-forge --override-channels -y \
  python=3.9 pip "pytorch=2.1" torchvision torchmetrics "pytorch-lightning=2.1" \
  pandas numpy scipy rdkit matplotlib jupyterlab ipykernel \
  meson ninja pkg-config gfortran openblas liblapack c-compiler
conda activate qupkake

pip install torch_geometric==2.4
pip install "$QK"</code></pre>



<p class="wp-block-paragraph">Torch is pinned to 2.1, as in the repo&#8217;s <code>environment.yaml</code>, to match the shipped model checkpoints.</p>



<h2 class="wp-block-heading">3. Build xtb 6.4.1 from source</h2>



<h3 class="wp-block-heading">3a. Download and verify</h3>



<pre class="wp-block-code"><code>mkdir -p "$QK/xtb-src" &amp;&amp; cd "$QK/xtb-src"
curl -LO https://github.com/grimme-lab/xtb/releases/download/v6.4.1/xtb-6.4.1.tar.xz
curl -LO https://github.com/grimme-lab/xtb/releases/download/v6.4.1/xtb-6.4.1.tar.xz.sha256
shasum -a 256 xtb-6.4.1.tar.xz; cat xtb-6.4.1.tar.xz.sha256   # must match:
# 15cfd8743dd963c54e0fee12da5ee34a08dde78625cf8a0a21eee1eaa652beae
tar xf xtb-6.4.1.tar.xz &amp;&amp; cd xtb-6.4.1</code></pre>



<h3 class="wp-block-heading">3b. Patch one format string</h3>



<p class="wp-block-paragraph">gfortran 16 rejects a malformed format descriptor at runtime: <code>Fortran runtime error: Missing comma between descriptors</code>. xtb hits it during every <code>--opt</code> run. The patch adds the missing commas:</p>



<pre class="wp-block-code"><code>sed -i '' '624s/(1x,"("f7.2"%)")/(1x,"(",f7.2,"%)")/' src/optimizer.f90
sed -n 624p src/optimizer.f90
# expected:       write(env%unit,'(1x,"(",f7.2,"%)")')         (depred-echng)/echng*100</code></pre>



<h3 class="wp-block-heading">3c. Configure and build at <code>-O2</code> (not the default <code>-O3</code>)</h3>



<pre class="wp-block-code"><code>FC=gfortran CC=cc meson setup build-o2 \
  --prefix="$QK/xtb-6.4.1" \
  --buildtype=debugoptimized \
  -Dla_backend=openblas -Dopenmp=true
ninja -C build-o2 install</code></pre>



<ul class="wp-block-list">
<li><code>debugoptimized</code> means <code>-O2 -g</code>. <strong>Do not use <code>--buildtype=release</code>.</strong> It gives <code>-O3</code>, which gfortran 16 miscompiles.</li>



<li><code>la_backend=openblas</code>: the default is <code>mkl-static</code>, which doesn&#8217;t exist on Apple Silicon.</li>



<li>meson prints <code>WARNING: FC and CC are not from the same vendor</code>. That&#8217;s expected and harmless.</li>
</ul>



<p class="wp-block-paragraph">The installed binary finds <code>libgfortran</code>, <code>libopenblas</code> and <code>libomp</code> through rpaths into the conda env. To confirm:</p>



<pre class="wp-block-code"><code>otool -l "$QK/xtb-6.4.1/bin/xtb" | grep -A2 LC_RPATH   # should list .../envs/qupkake/lib</code></pre>



<h3 class="wp-block-heading">3d. Verify with a real optimization</h3>



<p class="wp-block-paragraph">A <code>--version</code> check or a single-point energy is <strong>not enough</strong>: the miscompiled <code>-O3</code> binary passes both. Run a full geometry optimization, in gas phase and in ALPB water (the settings QupKake uses):</p>



<pre class="wp-block-code"><code>cd "$(mktemp -d)"
python -c "
from rdkit import Chem; from rdkit.Chem import AllChem
m = Chem.AddHs(Chem.MolFromSmiles('CC(=O)Oc1ccccc1C(=O)O')); AllChem.EmbedMolecule(m, randomSeed=42)
AllChem.MMFFOptimizeMolecule(m); Chem.MolToMolFile(m, 'aspirin.mol')"
export OMP_STACKSIZE=4G
"$QK/xtb-6.4.1/bin/xtb" aspirin.mol --opt &gt; gas.txt 2&gt;&amp;1
"$QK/xtb-6.4.1/bin/xtb" aspirin.mol --opt --alpb water --lmo -P 4 &gt; water.txt 2&gt;&amp;1
grep -E 'OPTIMIZATION CONVERGED|FAILED TO CONVERGE|TOTAL ENERGY|abnormal' gas.txt water.txt</code></pre>



<p class="wp-block-paragraph">Expected result: both runs print <code>GEOMETRY OPTIMIZATION CONVERGED</code> after about 20–25 iterations, with total energies of about −39.632 Eh (gas) and −39.652 Eh (water). A broken build gives <code>FAILED TO CONVERGE</code> or <code>abnormal termination</code> instead, and its energy rises at every optimization step.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>Shell gotcha when scripting tests:</strong> in zsh (the macOS default shell), an unquoted <code>$args</code> holding <code>"--opt --alpb water"</code> does not word-split. xtb receives one garbage argument, quietly ignores it and runs a gas-phase single point. Use <code>bash</code>, or <code>${=args}</code> in zsh.</p>
</blockquote>



<h2 class="wp-block-heading">4. Point QupKake at xtb</h2>



<p class="wp-block-paragraph">QupKake reads <code>XTBPATH</code> <strong>once, at import time</strong> (<code>qupkake/__init__.py</code>), and it must be the path to the executable. Set it, along with OpenMP settings, in conda activation hooks so <code>conda activate qupkake</code> sets everything:</p>



<pre class="wp-block-code"><code>mkdir -p "$CONDA_PREFIX/etc/conda/activate.d" "$CONDA_PREFIX/etc/conda/deactivate.d"

cat &gt; "$CONDA_PREFIX/etc/conda/activate.d/xtb.sh" &lt;&lt;EOF
export _QUPKAKE_OLD_OMP_STACKSIZE="\${OMP_STACKSIZE:-}"
export _QUPKAKE_OLD_OMP_NUM_THREADS="\${OMP_NUM_THREADS:-}"
export XTBPATH=$QK/xtb-6.4.1/bin/xtb
export XTBHOME=$QK/xtb-6.4.1/share/xtb
export OMP_STACKSIZE=4G
export OMP_NUM_THREADS=1
EOF

cat &gt; "$CONDA_PREFIX/etc/conda/deactivate.d/xtb.sh" &lt;&lt;'EOF'
unset XTBPATH XTBHOME
if &#91; -n "$_QUPKAKE_OLD_OMP_STACKSIZE" ]; then export OMP_STACKSIZE="$_QUPKAKE_OLD_OMP_STACKSIZE"; else unset OMP_STACKSIZE; fi
if &#91; -n "$_QUPKAKE_OLD_OMP_NUM_THREADS" ]; then export OMP_NUM_THREADS="$_QUPKAKE_OLD_OMP_NUM_THREADS"; else unset OMP_NUM_THREADS; fi
unset _QUPKAKE_OLD_OMP_STACKSIZE _QUPKAKE_OLD_OMP_NUM_THREADS
EOF

conda deactivate &amp;&amp; conda activate qupkake &amp;&amp; echo "$XTBPATH"</code></pre>



<p class="wp-block-paragraph">xtb 6.4.1 has its GFN2 parameters compiled in, so <code>XTBHOME</code> is optional. It&#8217;s set anyway for completeness.</p>



<h2 class="wp-block-heading">5. Jupyter kernel</h2>



<p class="wp-block-paragraph">Jupyter kernels don&#8217;t run conda activation hooks, so put the variables in the kernel spec. The kernel&#8217;s <code>PATH</code> must also include <code>conda</code>: on import QupKake runs <code>conda list xtb</code>, and if <code>conda</code> is missing the import crashes with a confusing <code>NameError: name 'XTB_LOCATION' is not defined</code>.</p>



<pre class="wp-block-code"><code>python -m ipykernel install --user --name qupkake --display-name "Python (qupkake)"
python - &lt;&lt;EOF
import json, os
p = os.path.expanduser("~/Library/Jupyter/kernels/qupkake/kernel.json")
k = json.load(open(p))
k&#91;"env"] = {
    "XTBPATH": "$QK/xtb-6.4.1/bin/xtb",
    "XTBHOME": "$QK/xtb-6.4.1/share/xtb",
    "OMP_STACKSIZE": "4G",
    "OMP_NUM_THREADS": "1",
    "PATH": "$CONDA_PREFIX/bin:$(dirname "$CONDA_EXE")/../condabin:/usr/bin:/bin:/usr/sbin:/sbin",
}
json.dump(k, open(p, "w"), indent=1)
EOF</code></pre>



<p class="wp-block-paragraph">A worked example notebook is in <code>QupKake_usage.ipynb</code>. It covers a single SMILES, a CSV batch, tautomers, site drawings and calling QupKake from Python.</p>



<h2 class="wp-block-heading">6. Verify QupKake end to end</h2>



<pre class="wp-block-code"><code>cd "$(mktemp -d)"
python -c "import qupkake; print(qupkake.XTB_LOCATION)"     # source-built xtb path
qupkake smiles "CC(=O)Oc1ccccc1C(=O)O" -n aspirin -r test
grep -A1 "&lt;pka" test/output/qupkake_output.sdf</code></pre>



<p class="wp-block-paragraph">Expected result: it runs in about 6 s and predicts an acidic pKa of about <strong>3.58</strong> for aspirin&#8217;s carboxylic acid (experimental ≈ 3.5), plus a basic site at about 1.5.</p>



<p class="wp-block-paragraph">Two harmless messages appear on every import:</p>



<ul class="wp-block-list">
<li><code>CondaValueError: No packages match 'xtb'</code> — QupKake checking for a conda xtb, which is deliberately absent.</li>



<li><code>GPU available but not used</code> — QupKake runs on CPU.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Pitfalls</h2>



<h3 class="wp-block-heading"><code>-O3</code> miscompilation (the main trap)</h3>



<p class="wp-block-paragraph">With gfortran 16 at <code>-O3</code>, xtb 6.4.1 runs, prints the right version and gives correct single-point energies. In geometry optimizations, though, the energy rises at every step until the SCF fails. QupKake reports this as:</p>



<pre class="wp-block-code"><code>RuntimeError: Problem running xtb on molecule
...
TypeError: 'NoneType' object is not iterable      (in predict_sites)</code></pre>



<p class="wp-block-paragraph">and the input SDF in <code>&lt;root&gt;/raw/</code> is truncated to 0 bytes. <code>-O2</code> and <code>-O0</code> give identical, correct results. The cause wasn&#8217;t investigated further: a gfortran 16 optimizer bug or undefined behaviour in the 2021 xtb code.</p>



<h3 class="wp-block-heading"><code>-mp N</code> oversubscribes the CPU</h3>



<p class="wp-block-paragraph">QupKake passes its worker count to every xtb call as <code>-P N</code>. <code>-mp 16</code> therefore launches 16 xtb jobs with 16 threads each. For batch runs, point <code>XTBPATH</code> at a small wrapper that forces one thread per xtb process:</p>



<pre class="wp-block-code"><code>#!/bin/bash
# xtb1: force "-P 1" whatever QupKake asks for
args=(); skip=0
for a in "$@"; do
  if &#91; $skip = 1 ]; then args+=("1"); skip=0; continue; fi
  &#91; "$a" = "-P" ] &amp;&amp; skip=1
  args+=("$a")
done
exec "$QK/xtb-6.4.1/bin/xtb" "${args&#91;@]}"</code></pre>



<p class="wp-block-paragraph">Use it with <code>XTBPATH=/path/to/xtb1 qupkake file mols.csv -mp 22 ...</code>. Without <code>-mp</code>, QupKake still passes <code>-P &lt;all cores&gt;</code>, so the wrapper helps there too.</p>



<h3 class="wp-block-heading">Input structures</h3>



<ul class="wp-block-list">
<li><strong>Give 2D SDFs as SMILES (CSV), not SDF.</strong> For SDF input QupKake passes the coordinates to xtb unchanged, with no hydrogens added. For CSV input it adds hydrogens and embeds in 3D first.</li>



<li><strong>One unembeddable molecule kills the whole file.</strong> RDKit&#8217;s <code>Bad Conformer Id</code> aborts the run. Pre-check with <code>qupkake.cli.embed_molecule</code> and remove failures.</li>



<li><strong>Output pKa values are sometimes the string <code>tensor(4.21)</code>.</strong> Strip that before converting to float.</li>



<li><strong>Tautomer and charge state matter.</strong> QupKake predicts micro-pKa of the structure as drawn, so a different tautomer gives different values. On a 4.6k-compound set:
<ul class="wp-block-list">
<li>RDKit&#8217;s canonical tautomer (<code>rdMolStandardize.TautomerEnumerator.Canonicalize</code>) changed the most acidic pKa by &gt;1 unit for 18% of the 1,900 molecules it altered.</li>



<li>The registered structures agreed better with QupKake&#8217;s own xtb-based tautomer search (<code>-t</code>) than the RDKit canonical ones did.</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading"><code>-t</code> (tautomer search)</h3>



<ul class="wp-block-list">
<li><code>-t</code> runs one xtb optimization per RDKit-enumerated tautomer: a median of about 12 per molecule, up to 700+ for some. At about 4 CPU-seconds each, budget accordingly.</li>



<li>If xtb fails on <strong>any</strong> tautomer, QupKake aborts the molecule (<code>KeyError: 'totalenergy'</code>). A drop-in launcher that skips failed tautomers is in <code>runs/ForPKA_taut/qupkake_t.py</code> (use <code>python qupkake_t.py file ... -t</code> in place of <code>qupkake file ... -t</code>).</li>



<li>The GFN2-xTB/ALPB energy ranking sometimes favours implausible imidic-acid (<code>C(OH)=N</code>) and enol tautomers. Check its picks by eye.</li>
</ul>



<h3 class="wp-block-heading">Batch runs</h3>



<p class="wp-block-paragraph">For thousands of molecules, run many small single-worker QupKake jobs through <code>xargs -P &lt;cores&gt;</code>, not one big <code>-mp</code> run. QupKake splits a file into equal-<em>count</em> blocks per worker, so a single slow molecule stalls the whole run. Example scripts are in <code>runs/</code> (<code>ForPKA*/run_all.sh</code>, <code>run_job.sh</code>, <code>combine.py</code>). Throughput on 22 cores is about 4.5 h per 4,600 drug-like molecules without <code>-t</code>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Rebuilding xtb</h2>



<pre class="wp-block-code"><code>conda activate qupkake
cd "$QK/xtb-src/xtb-6.4.1"
ninja -C build-o2 install</code></pre>



<p class="wp-block-paragraph">Then re-run the check in 3d.</p>



<p class="wp-block-paragraph">I&#8217;ve uploaded details to GitHub <a href="https://github.com/drc007/qupkake-apple-silicon/tree/main/qupkake-apple-silicon">https://github.com/drc007/qupkake-apple-silicon/tree/main/qupkake-apple-silicon</a></p>



<h2 class="wp-block-heading">Citation</h2>



<p class="wp-block-paragraph">Abarbanel, O. D.; Hutchison, G. R. <em>QupKake: Integrating Machine Learning and Quantum Chemistry for micro-pKa Predictions.</em> J. Chem. Theory Comput. 2024. <a href="https://pubs.acs.org/doi/10.1021/acs.jctc.4c00328">doi:10.1021/acs.jctc.4c00328</a></p>



<p class="wp-block-paragraph">xtb: Bannwarth, C.; Ehlert, S.; Grimme, S. <em>J. Chem. Theory Comput.</em> 2019, 15, 1652. <a href="https://github.com/grimme-lab/xtb">github.com/grimme-lab/xtb</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>A collection of Python scripts for PyMOL</title>
		<link>https://macinchem.org/2026/10/09/a-collection-of-python-scripts-for-pymol/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Fri, 09 Oct 2026 11:31:21 +0000</pubDate>
				<category><![CDATA[Hints and Tutorials]]></category>
		<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[molecular visualisation]]></category>
		<category><![CDATA[pymol]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3220</guid>

					<description><![CDATA[Jeremy Tame recently mentioned a python script to produce clickable Ramachandran plots, code is available on GitHub https://github.com/JezTame/pymol-rama His website also describes several other useful]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Jeremy Tame recently mentioned a python script to produce clickable Ramachandran plots, code is available on GitHub <a href="https://github.com/JezTame/pymol-rama">https://github.com/JezTame/pymol-rama</a></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="748" src="https://macinchem.org/wp-content/uploads/2026/10/image-1024x748.png" alt="" class="wp-image-3221" srcset="https://macinchem.org/wp-content/uploads/2026/10/image-1024x748.png 1024w, https://macinchem.org/wp-content/uploads/2026/10/image-300x219.png 300w, https://macinchem.org/wp-content/uploads/2026/10/image-768x561.png 768w, https://macinchem.org/wp-content/uploads/2026/10/image.png 1300w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">His website also describes several other useful scripts <a href="http://www.tsurumi.yokohama-cu.ac.jp/pdl/PDL/PYTHON/index.html">http://www.tsurumi.yokohama-cu.ac.jp/pdl/PDL/PYTHON/index.html</a></p>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Frontier AI: SME Champions, phase 1</title>
		<link>https://macinchem.org/2026/10/06/frontier-ai-sme-champions-phase-1/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Tue, 06 Oct 2026 10:04:41 +0000</pubDate>
				<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[Uncategorised]]></category>
		<category><![CDATA[artificial intelligence]]></category>
		<category><![CDATA[funding]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3208</guid>

					<description><![CDATA[UK registered micro, small or medium sized enterprise (SMEs) can apply for a share of up to £3.1 million to deliver feasibility studies for frontier]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">UK registered micro, small or medium sized enterprise (SMEs) can apply for a share of up to £3.1 million to deliver feasibility studies for frontier artificial intelligence, and machine learning technologies with a clear route to defensible scale-up.</p>



<p class="wp-block-paragraph">Details here <a href="https://www.ukri.org/opportunity/frontier-ai-sme-champions-phase-1/">https://www.ukri.org/opportunity/frontier-ai-sme-champions-phase-1/</a></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Clustering</title>
		<link>https://macinchem.org/2026/10/01/clustering/</link>
		
		<dc:creator><![CDATA[chris]]></dc:creator>
		<pubDate>Thu, 01 Oct 2026 11:11:38 +0000</pubDate>
				<category><![CDATA[Data Analysis Tools]]></category>
		<category><![CDATA[Hints and Tutorials]]></category>
		<category><![CDATA[Macinchem Blog]]></category>
		<category><![CDATA[cheminformatics]]></category>
		<category><![CDATA[clustering]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://macinchem.org/?p=3204</guid>

					<description><![CDATA[Clustering is an invaluable cheminformatics technique for subdividing a typically large compound collection into small groups of similar compounds. One of the advantages is that]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Clustering is an invaluable cheminformatics technique for subdividing a typically large compound collection into small groups of similar compounds. One of the advantages is that once clustered you can store the cluster identifiers and then refer to them later this is particularly valuable when dealing with very large datasets. This often used in the analysis of high-throughput screening results, or the analysis of virtual screening or docking studies. A while back I looked at the options for clustering large datasets.</p>



<figure class="wp-block-embed is-type-wp-embed is-provider-macs-in-chemistry wp-block-embed-macs-in-chemistry"><div class="wp-block-embed__wrapper">
<blockquote class="wp-embedded-content" data-secret="UE9zA2rore"><a href="https://macinchem.org/2023/03/05/options-for-clustering-large-datasets-of-molecules/">Options for Clustering large datasets of Molecules</a></blockquote><iframe loading="lazy" class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="“Options for Clustering large datasets of Molecules” — Macs in Chemistry" src="https://macinchem.org/2023/03/05/options-for-clustering-large-datasets-of-molecules/embed/#?secret=1aPZ064IsY#?secret=UE9zA2rore" data-secret="UE9zA2rore" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</div></figure>



<p class="wp-block-paragraph">I thought it might be interesting to compare the performance of various clustering approaches on Apple Silicon (Apple M2 Ultra Mac with 192 GB of RAM.).</p>



<p class="wp-block-paragraph">These four Jupyter notebooks cluster a set of molecules by structural similarity, using RDKit Morgan fingerprints (radius 3, 2048 bits) and Tanimoto similarity.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Notebook</th><th>Method</th><th>Use it for</th></tr></thead><tbody><tr><td><code>BitBirchclustering.ipynb</code></td><td><a href="https://github.com/mqcomplab/bitbirch">BitBIRCH</a></td><td>Any size, from hundreds to hundreds of thousands of molecules</td></tr><tr><td><code>Butinaclustering.ipynb</code></td><td>RDKit Taylor–Butina (<code>rdkit.ML.Cluster.Butina</code>)</td><td>Small to medium sets; memory grows with the square of the set size</td></tr><tr><td><code>MLXButinaclustering.ipynb</code></td><td>Taylor–Butina on the Apple-silicon GPU (<a href="https://github.com/guillaume-osmo/mlxmolkit">mlxmolkit</a>)</td><td>The same clusters as RDKit Butina, about 6× faster and in about 20× less memory at 150k molecules. Needs macOS on Apple silicon.</td></tr><tr><td><code>KMeansclustering.ipynb</code></td><td>k-means (scikit-learn)</td><td>Splitting a set into a chosen number of groups, e.g. for diverse subsets or train/test splits. It suggests a number of clusters and lets you change it.</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">All four notebooks have the same inputs, outputs and layout, so you can run a dataset through any of them and compare the results. BitBIRCH and the two Butina notebooks group molecules by a similarity threshold. k-means instead uses a number of clusters you choose.  All notebook use the same conda enviroment. Passing a square matrix to <code>Butina.ClusterData</code> needs a recent RDKit, so <code>environment.yml</code> requires RDKit 2026.03 or newer.</p>



<h3 class="wp-block-heading">Choosing a threshold</h3>



<p class="wp-block-paragraph">Diverse sets, such as approved drugs or random screening compounds, give mostly single-molecule clusters at 0.65. Around 0.35–0.45 gives useful families. Some reference points:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Data set</th><th>Threshold</th><th>Clusters (BitBIRCH)</th><th>Largest</th></tr></thead><tbody><tr><td>789 approved drugs</td><td>0.65</td><td>769</td><td>3</td></tr><tr><td>789 approved drugs</td><td>0.35</td><td>632</td><td>9</td></tr><tr><td>149k random ZINC compounds</td><td>0.65</td><td>104,935</td><td>30</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Performance and memory</h2>



<p class="wp-block-paragraph">Timings are from an Apple M2 Ultra Mac with 192 GB of RAM.</p>



<p class="wp-block-paragraph">All four notebooks were run on the same two sets: 149,396 random ZINC compounds and the 4,629-molecule ERK set. The clustering time is the clustering step alone. The notebook time includes loading the file (about 50 s for 150k), fingerprints and export. &#8220;Agreement&#8221; is the adjusted Rand index against RDKit Butina at the same threshold (1 = identical partition, 0 = no better than chance).</p>



<p class="wp-block-paragraph"><strong>150k molecules:</strong></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Method</th><th>Setting</th><th>Clustering</th><th>Notebook</th><th>Peak RAM</th><th>Clusters</th><th>Single-molecule</th><th>Largest</th><th>Agreement with RDKit Butina</th></tr></thead><tbody><tr><td>RDKit Butina</td><td>similarity ≥ 0.65</td><td>139 s</td><td>191 s</td><td>97 GB</td><td>89,464</td><td>54,535</td><td>40</td><td>reference</td></tr><tr><td>MLX Butina (GPU)</td><td>similarity ≥ 0.65</td><td>23 s</td><td>76 s</td><td>4.6 GB</td><td>89,233</td><td>54,393</td><td>40</td><td>0.94</td></tr><tr><td>BitBIRCH</td><td>similarity ≥ 0.65</td><td>23 s</td><td>76 s</td><td>12 GB</td><td>104,935</td><td>75,886</td><td>30</td><td>0.54</td></tr><tr><td>RDKit Butina</td><td>similarity ≥ 0.35</td><td>139 s</td><td>190 s</td><td>97 GB</td><td>23,064</td><td>7,525</td><td>346</td><td>reference</td></tr><tr><td>MLX Butina (GPU)</td><td>similarity ≥ 0.35</td><td>23 s</td><td>74 s</td><td>4.8 GB</td><td>21,362</td><td>7,457</td><td>346</td><td>0.76</td></tr><tr><td>BitBIRCH</td><td>similarity ≥ 0.35</td><td>21 s</td><td>74 s</td><td>10 GB</td><td>68,795</td><td>41,786</td><td>127</td><td>0.12</td></tr><tr><td>k-means</td><td>k = 103 (suggested)</td><td>39 s, plus a 181 s k scan</td><td>273 s</td><td>6.6 GB</td><td>103</td><td>5</td><td>18,775</td><td>—</td></tr><tr><td>k-means</td><td>k = 250</td><td>109 s</td><td>163 s</td><td>6.4 GB</td><td>250</td><td>23</td><td>44,183</td><td>—</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">An optional t-SNE map adds about 4 minutes at 150k, and about 20 s for the ERK set, in every notebook.</p>



<p class="wp-block-paragraph"><strong>ERK set (4,629 molecules):</strong> every method clusters in 0.2–0.6 s, apart from k-means (2 s at k = 41, 14 s at k = 250, plus 23 s for the k scan). Peak RAM is under 1.2 GB. The agreement with RDKit Butina is 0.95 for MLX Butina at both thresholds, and 0.60 (at 0.65) and 0.34 (at 0.35) for BitBIRCH.</p>



<p class="wp-block-paragraph"><strong>What this shows:</strong></p>



<ul class="wp-block-list">
<li><strong>MLX Butina gives Butina results at BitBIRCH cost.</strong> At 150k it is about 6× faster than RDKit Butina and uses about 20× less memory, because it keeps only the neighbour pairs instead of the full distance matrix. Its GPU memory peak was only 0.16 GB.</li>



<li><strong>MLX and RDKit Butina differ only in the greedy step.</strong> The neighbour lists are identical: every pair above the threshold matches RDKit&#8217;s Tanimoto exactly. mlxmolkit recounts neighbours after each cluster (RDKit&#8217;s <code>reordering=True</code>) and breaks ties the other way. RDKit&#8217;s notebook defaults to <code>reordering=False</code>. The difference is small at 0.65 (0.94–0.95 agreement, the same largest clusters). It grows at 0.35 on 150k (0.76, 21,362 against 23,064 clusters), where recounting lets later clusters absorb more molecules.</li>



<li><strong>BitBIRCH is fast but partitions differently.</strong> It makes more, smaller clusters than Butina at the same threshold, and agrees less with it at low thresholds.</li>



<li><strong>k-means isn&#8217;t suited to diverse sets.</strong> MiniBatchKMeans on 150k diverse molecules produces one huge catch-all cluster (19k molecules at k = 103, 44k at k = 250) alongside many small ones. Use it to split a set into a fixed number of groups, not to find families.</li>
</ul>



<p class="wp-block-paragraph"><strong>MLX Butina check.</strong> Before clustering, the MLX notebook checks that a Metal GPU is available. It estimates memory from the neighbour density in a sample, which matters most at low thresholds on sets of close analogues. It also times two trial runs to give a rough, usually high, estimate of the run time.</p>



<p class="wp-block-paragraph"><strong>Butina memory check.</strong> Butina needs every pairwise distance, and RDKit holds them in a full n × n matrix. The notebook builds this matrix as float32 in blocks, which uses about 5× less memory than RDKit&#8217;s usual flat distance list. Before clustering starts, a check runs that:</p>



<ul class="wp-block-list">
<li>estimates the peak memory, including the matrix and neighbour lists</li>



<li>compares it with the RAM available at that moment</li>



<li>prints the largest set size that would fit, and an estimate of the run time</li>



<li><strong>stops with an error</strong> if the estimate is more than <code>MEMORY_FRACTION</code> of the available RAM</li>
</ul>



<div align="center"><script type="text/javascript"><!--

google_ad_client = "pub-4009912495867492";

google_ad_width = 728;

google_ad_height = 90;

google_ad_format = "728x90_as";

google_ad_type = "text";

google_ad_channel = "";

//--></script>

<script type="text/javascript"

  src="https://pagead2.googlesyndication.com/pagead/show_ads.js">

</script></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>