Skip to content

NO_JIRA Added Pharmacophore generator script to create CrossMiner que… - #99

Merged
CRingroseCCDC merged 3 commits into
mainfrom
pharmacophore_generator
Aug 7, 2026
Merged

NO_JIRA Added Pharmacophore generator script to create CrossMiner que…#99
CRingroseCCDC merged 3 commits into
mainfrom
pharmacophore_generator

Conversation

@CRingroseCCDC

Copy link
Copy Markdown
Contributor

…ries from Ligand Overlay outputs. Includes basic tests and examples.

…ries from Ligand Overlay outputs. Includes basic tests and examples.
(either directly, or in `any`/`protein`/`small_molecule` subdirectories).
Usually, the location is `C:\users\<username>\CCDC\ccdc-software\csd-crossminer\feature_definitions`

```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[markdownlint] reported by reviewdog 🐶
error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]


### Options for Ligand Overlay Output

* `cluster`: Cluster the similar pharmacophore features based on proximity

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[markdownlint] reported by reviewdog 🐶
error MD004/ul-style Unordered list style [Expected: dash; Actual: asterisk]

### Options for Ligand Overlay Output

* `cluster`: Cluster the similar pharmacophore features based on proximity
* `projected`: Treat pharmacophore features as projected when appropriate e.g. acceptors and donors

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[markdownlint] reported by reviewdog 🐶
error MD004/ul-style Unordered list style [Expected: dash; Actual: asterisk]

Comment on lines +36 to +37
* `cluster`: Cluster the similar pharmacophore features based on proximity
* `projected`: Treat pharmacophore features as projected when appropriate e.g. acceptors and donors

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[markdownlint-fix] reported by reviewdog 🐶

Suggested change
* `cluster`: Cluster the similar pharmacophore features based on proximity
* `projected`: Treat pharmacophore features as projected when appropriate e.g. acceptors and donors
- `cluster`: Cluster the similar pharmacophore features based on proximity
- `projected`: Treat pharmacophore features as projected when appropriate e.g. acceptors and donors

raise FileNotFoundError(f"Feature definitions folder {feature_definitions} does not exist.")

output_folder = Path(args.output_folder) if args.output_folder else Path('queries')
output_folder.mkdir(parents=True, exist_ok=True)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new overlay_to_pharmacophore script package that converts CSD Ligand Overlay pharmacophore outputs into CrossMiner query (.cm) files, with clustering support plus bundled example data and pytest coverage.

Changes:

  • Implement pharmacophore feature extraction from .mol2 pharmacophore files and optional clustering.
  • Generate CrossMiner query files using external .cpf feature definitions.
  • Add basic pytest suite and bundled example Ligand Overlay/pharmacophore files, plus usage documentation.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
scripts/discovery/overlay_to_pharmacophore/main.py CLI entrypoint for producing query files from one or many overlay solutions.
scripts/discovery/overlay_to_pharmacophore/overlay.py Parses pharmacophore mol2 ATOM blocks into labeled feature points (with virtual points).
scripts/discovery/overlay_to_pharmacophore/cluster.py Clusters nearby features (including projected feature virtual-point distance checks).
scripts/discovery/overlay_to_pharmacophore/write_query.py Writes CrossMiner .cm query output, embedding referenced feature definition files.
scripts/discovery/overlay_to_pharmacophore/datastructures.py Defines core datatypes (OverlayData, PharmFeaturePoint, tolerances/weights).
scripts/discovery/overlay_to_pharmacophore/crossminer_search.py Example CrossMiner search helper using CSD Python API.
scripts/discovery/overlay_to_pharmacophore/ReadMe.md Usage instructions, requirements, and feature-definition setup guidance.
scripts/discovery/overlay_to_pharmacophore/tests/tests.py Pytest suite validating parsing, projection handling, clustering, and query writing.
scripts/discovery/overlay_to_pharmacophore/tests/job1/solution_01.mol2 Bundled example Ligand Overlay solution file for tests.
scripts/discovery/overlay_to_pharmacophore/tests/job1/pharmacophores/solution_pharm_01.mol2 Bundled example pharmacophore file used by tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +12
from pathlib import Path

import pytest

from cluster import cluster_features
from datastructures import OverlayData, PharmFeaturePoint
from overlay import OverlayToPharmFeatures
from write_query import FeaturesToCrossMinerQuery

TESTS_DIR = Path(__file__).parent
REPO_ROOT = TESTS_DIR.parent
JOB_FOLDER = TESTS_DIR / "job1"
Comment on lines +56 to +60
def __repr__(self):
return (
f"PharmFeaturePoint({self.x}, {self.y}, {self.z}, "
f"label={self.label}, virtual_points={self.virtual_point}), "
)
Comment on lines +83 to +86
elif prefix == 'NL':
if last_feature_point is None:
raise ValueError("Virtual point found before its parent feature point.")
last_feature_point.virtual_point = np.array([x, y, z], dtype=float)
parser = argparse.ArgumentParser(
description="Create Pharmacophore Features from a Ligand Overlay"
)
parser.add_argument('-i', '--input_folder', type=str, help='Input file(s) path.')
@@ -0,0 +1,76 @@
import argparse

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we put this header at the top of each oy and ipynb file which we publish on the open source:

'''
This script can be used for any purpose without limitation subject to the
conditions at https://www.ccdc.cam.ac.uk/Community/Pages/Licences/v2.aspx
This permission notice and the following statement of attribution must be
included in all copies or substantial portions of this script.

"date of creation": created by the Cambridge Crystallographic Data Centre
'''

@@ -0,0 +1,18 @@
from pathlib import Path

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it is called from anywhere. You can probs add a flag like --run_search so users could do that without any extra actions.

if last_feature_point is None:
raise ValueError("Virtual point found before its parent feature point.")
last_feature_point.virtual_point = np.array([x, y, z], dtype=float)
last_feature_point.label = 'ring_planar_projected'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line suggests that it is always a planar ring. I have an example where it sems to be just a ring, I'll share the example

…ries from Ligand Overlay outputs. Includes basic tests and examples.
…ries from Ligand Overlay outputs. Includes basic tests and examples.



@dataclass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [flake8] <303> reported by reviewdog 🐶
too many blank lines (3)




@dataclass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [flake8] <303> reported by reviewdog 🐶
too many blank lines (3)

@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@CRingroseCCDC
CRingroseCCDC merged commit b25bdd3 into main Aug 7, 2026
4 of 6 checks passed
@CRingroseCCDC
CRingroseCCDC deleted the pharmacophore_generator branch August 7, 2026 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants