### Install nvMolKit from Source Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/README.md Commands to activate the development environment, navigate to the repository root, and install nvMolKit using pip with parallel build support. Includes instructions for testing the installation. ```bash # Activate your environment conda activate nvmolkit_dev_py312 # Navigate to the repo root directory cd # Install nvMolKit directly # Use all CPU cores for a faster build, or replace $(nproc) with a specific number CMAKE_BUILD_PARALLEL_LEVEL=$(nproc) pip -v install . # To test the installation, run pip install pytest (cd nvmolkit/tests && pytest -v .) ``` -------------------------------- ### Install documentation dependencies Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/README.md Run this command within the docs directory to install Sphinx and required build tools. ```bash pip install -r requirements.txt ``` -------------------------------- ### Install CMake from Source Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/README.md Steps to remove an existing CMake installation and install a specific version (3.30.1) from a downloaded script on Ubuntu. Verify the installation afterward. ```bash # Remove old CMake sudo apt remove --purge --auto-remove cmake # Install CMake 3.30.1 wget https://github.com/Kitware/CMake/releases/download/v3.30.1/cmake-3.30.1-linux-x86_64.sh chmod +x cmake-3.30.1-linux-x86_64.sh sudo ./cmake-3.30.1-linux-x86_64.sh --prefix=/usr/local --skip-license # Verify installation cmake --version ``` -------------------------------- ### Install cppcheck for Development Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/README.md Use this script to download, build, and install cppcheck for code quality analysis during development. Ensure you have wget, tar, and cmake installed. ```bash wget https://github.com/danmar/cppcheck/archive/2.14.2.tar.gz tar -zxvf 2.14.2.tar.gz cd cppcheck-2.14.2 mkdir build && cd build cmake .. -DUSE_MATCHCOMPILER=ON -DCMAKE_BUILD_TYPE=release make -j sudo make install cd ../../ && rm -rf cppcheck-2.14.2 2.14.2.tar.gz ``` -------------------------------- ### Host documentation locally Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/README.md Starts a local HTTP server to view the generated documentation at http://localhost:8000. ```bash python -m http.server -d public ``` -------------------------------- ### Setup ETKDG parameters Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/conformer_generation_optimization_workflow.ipynb Initialize ETKDGv3 parameters with a random seed and enable random coordinates. ```python # Setup ETKDG parameters params = ETKDGv3() params.randomSeed = RANDOM_SEED params.useRandomCoords = True # Required for nvMolKit ``` -------------------------------- ### Set up Python Development Environment Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/README.md Commands to create and activate a conda environment, install RDKit with development headers, necessary Boost subpackages, and a GPU-enabled PyTorch version. ```bash # Create and activate environment conda create --name nvmolkit_dev_py312 python=3.12.1 conda activate nvmolkit_dev_py312 # Install RDKit with development headers conda install -c conda-forge rdkit=2024.09.6 rdkit-dev=2024.09.6 # Install Boost subpackages in case RDKit install did not include them transitively conda install -c conda-forge libboost libboost-python libboost-devel libboost-headers libboost-python-devel # Install Torch, make sure it's a GPU-enabled version. If having trouble install, check out the # torch installation guidelines: https://pytorch.org/get-started/locally/ pip install torch torchvision torchaudio python -c "import torch; print(torch.__version__); print(f'Is a CUDA build? {torch.cuda.is_available()}')" ``` -------------------------------- ### Install System Dependencies on Ubuntu Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/README.md Commands to update package lists and install essential build tools, development headers, and libraries like Eigen, libstdc++, and OpenMP on Ubuntu systems. ```bash # Update package list sudo apt-get update # Install build tools and development headers sudo apt-get install build-essential libeigen3-dev sudo apt-get install libstdc++-12-dev libomp-15-dev # nvMolKit requires a C++ compiler. You can install it system-wide or via conda: # Example: Install clang on Ubuntu: sudo apt-get install clang-15 clang-format-15 clang-tidy-15 ``` -------------------------------- ### Install nvMolKit using Conda Forge Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/index.md Install nvMolKit via Conda Forge, the recommended method. Ensure you have a conda-based environment manager like Miniconda or Miniforge installed and activated. ```bash conda install -c conda-forge nvmolkit ``` -------------------------------- ### Example Sign-off Line Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/CONTRIBUTING.md This is an example of the sign-off line automatically appended to your commit message when using the `--signoff` flag. ```text Signed-off-by: Your Name ``` -------------------------------- ### Build nvMolKit Against pip-installed RDKit Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/README.md This script configures environment variables to build nvMolKit against a pip-installed RDKit. This method is error-prone and requires manual specification of RDKit and boost header paths. The conda-based setup is strongly recommended. ```bash # Set environment variables for pip install NVMOLKIT_BUILD_AGAINST_PIP=ON \ NVMOLKIT_BUILD_AGAINST_PIP_LIBDIR= \ NVMOLKIT_BUILD_AGAINST_PIP_INCDIR= \ NVMOLKIT_BUILD_AGAINST_PIP_BOOSTINCLUDEDIR= \ pip install . ``` -------------------------------- ### Install nvMolKit with specific CUDA version Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/README.md Command to install nvMolKit with a specific CUDA version (e.g., 12.6) to ensure GPU-accelerated PyTorch. Choose a version compatible with your system's CUDA driver. ```bash conda install -c conda-forge nvmolkit cuda-version=12.6 ``` -------------------------------- ### Manage AsyncGpuResult and HardwareOptions Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Illustrates handling asynchronous GPU results and configuring hardware settings for batch processing. ```python import torch from rdkit import Chem from nvmolkit.fingerprints import MorganFingerprintGenerator from nvmolkit.types import AsyncGpuResult, HardwareOptions # AsyncGpuResult usage fpgen = MorganFingerprintGenerator(radius=2, fpSize=1024) mols = [Chem.MolFromSmiles(smi) for smi in ['CCO', 'CCCC', 'c1ccccc1']] # GetFingerprints returns AsyncGpuResult result = fpgen.GetFingerprints(mols) print(f"Result type: {type(result)}") # AsyncGpuResult # Pass directly to other nvMolKit functions without synchronization from nvmolkit.similarity import crossTanimotoSimilarity sim_result = crossTanimotoSimilarity(result) # No sync needed # Convert to torch tensor (async - stays on GPU) torch.cuda.synchronize() # Explicit sync when needed tensor = result.torch() print(f"Tensor device: {tensor.device}") # cuda:0 # Convert to numpy (blocking - syncs and copies to CPU) numpy_arr = result.numpy() print(f"Numpy shape: {numpy_arr.shape}") # HardwareOptions for controlling execution options = HardwareOptions( preprocessingThreads=8, # CPU threads (-1 for auto) batchSize=500, # Items per batch (-1 for auto) batchesPerGpu=4, # Concurrent batches per GPU gpuIds=[0, 1, 2] # Target GPUs (empty = all available) ) print(f"Preprocessing threads: {options.preprocessingThreads}") print(f"Batch size: {options.batchSize}") print(f"Batches per GPU: {options.batchesPerGpu}") print(f"GPU IDs: {options.gpuIds}") # Modify options options.batchSize = 1000 options.gpuIds = [0] # Single GPU ``` -------------------------------- ### Import nvMolKit and RDKit dependencies Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/conformer_generation_optimization_workflow.ipynb Initial imports required for molecule handling, conformer generation, and hardware configuration. ```python import os import time from rdkit import Chem from rdkit.Chem.rdDistGeom import ETKDGv3 from nvmolkit.embedMolecules import EmbedMolecules as nvMolKitEmbed from nvmolkit.types import HardwareOptions from nvmolkit.mmffOptimization import MMFFOptimizeMoleculesConfs as nvMolKitMMFFOptimize ``` -------------------------------- ### Set Up Clustering Parameters Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/clustering.ipynb Define parameters for molecule processing, fingerprint generation, and clustering. ```python # Number of molecules to process n_mols = 10000 # Hardware threads to use n_cpu_threads = 16 # Radius for Morgan fingerprinting fp_radius = 3 # Number of fingerprint bits fp_nbits = 1024 # Butina similarity threshold distance_threshold = 0.5 ``` -------------------------------- ### Build documentation with Sphinx Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/README.md Generates HTML documentation from the current directory into the public folder. ```bash sphinx-build -b html . public ``` -------------------------------- ### Generate conformers with GPU acceleration Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/conformer_generation_optimization_workflow.ipynb Execute GPU-accelerated conformer generation using the configured hardware options. ```python hardware_opts = HardwareOptions( preprocessingThreads=2, batchSize=25, batchesPerGpu=2, ) start_time = time.time() nvMolKitEmbed( molecules=molecules, params=params, confsPerMolecule=CONFORMERS_PER_MOLECULE, maxIterations=-1, # Automatic iteration calculation hardwareOptions=hardware_opts ) embedding_time = time.time() - start_time total_conformers = sum(mol.GetNumConformers() for mol in molecules) print(f"Conformer generation completed in {embedding_time:.2f} seconds") print(f"Generated {total_conformers} total conformers") print(f"Rate: {total_conformers/embedding_time:.1f} conformers/second") ``` -------------------------------- ### Handle Asynchronous GPU Results Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/index.md Demonstrates generating Morgan fingerprints and retrieving results as either a torch tensor or numpy array. Synchronization is required before accessing data. ```python # Example using fingerprints from nvmolkit.fingerprints import MorganFingerprintGenerator fpgen = MorganFingerprintGenerator(radius=2, fpSize=1024) # Get fingerprints - returns AsyncGpuResult. This can be passed to other functions that accept AsyncGpuResult such as similarity. # It can be passed to other nvMolKit functions without synchronization, so that multiple operations on the same GPU can be queued # before the first one finishes result = fpgen.GetFingerprints(mols) # To access a result, first synchronize then convert to desired format torch.cuda.synchronize() # Convert to torch tensor (stays on GPU, zero copy) fps_torch = result.torch() # Convert to numpy array (moves to CPU) fps_numpy = result.numpy() ``` -------------------------------- ### Configure Hardware Options Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/index.md Configures multi-GPU targeting, preprocessing threads, and batch sizes for operations like conformer generation. ```python from nvmolkit.types import HardwareOptions from nvmolkit.embedMolecules import EmbedMolecules options = HardwareOptions() # Target GPUs 0, 1 and 2. Defaults to using all GPUs detected options.gpuIds = [0, 1, 2] # Use 12 threads for parallel preprocessing. Defaults to using all CPUs detected options.preprocessingThreads = 12 # Divide up the work into batches of 500 conformers at a time. nvMolKit will pick a reasonable default but # optimal values may depend on the GPU. options.batchSize = 500 # Process 4 batches per GPU in parallel options.batchesPerGpu = 4 EmbedMolecules(mols, ..., hardwareOptions=options) ``` -------------------------------- ### Generate Morgan Fingerprints with nvMolKit Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Computes Morgan fingerprints for batches of molecules in parallel on the GPU. Results are returned as packed 32-bit integers. Requires importing necessary classes from nvmolkit.fingerprints. ```python import torch from rdkit import Chem from nvmolkit.fingerprints import MorganFingerprintGenerator, unpack_fingerprint, pack_fingerprint # Create fingerprint generator fpgen = MorganFingerprintGenerator(radius=2, fpSize=1024) # Parse molecules from SMILES smiles = ['C1CCCCC1', 'c1ccccc1', 'CCO', 'CCCC', 'c1ccc2ccccc2c1'] mols = [Chem.MolFromSmiles(smi) for smi in smiles] # Generate fingerprints on GPU (returns AsyncGpuResult) fps_result = fpgen.GetFingerprints(mols, num_threads=4) # Synchronize and convert to torch tensor torch.cuda.synchronize() fps_tensor = fps_result.torch() # Shape: (5, 32) for 1024-bit fingerprints print(f"Fingerprint tensor shape: {fps_tensor.shape}") print(f"Fingerprint dtype: {fps_tensor.dtype}") # int32 # Convert to numpy (blocking operation) fps_numpy = fps_result.numpy() # Unpack to boolean tensor for inspection unpacked = unpack_fingerprint(fps_tensor) # Shape: (5, 1024), dtype bool print(f"Unpacked shape: {unpacked.shape}") # Pack boolean fingerprints back to int32 (useful for database fingerprints) repacked = pack_fingerprint(unpacked) ``` -------------------------------- ### nvMolKit API Overview Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/api/nvmolkit.md Summary of available functional modules within the nvMolKit library. ```APIDOC ## nvMolKit Modules ### Fingerprint Generation Tools for generating molecular fingerprints. ### Similarity Calculations Methods for calculating molecular similarity. ### ETKDG Conformer Generation Generation of 3D conformers using the ETKDG algorithm. ### MMFF Optimization Optimization of molecular structures using the Merck Molecular Force Field (MMFF). ### Butina Clustering Clustering of molecular datasets using the Butina algorithm. ### Substructure Search Functionality for performing substructure searches within molecular sets. ### Conformer RMSD Calculation of Root Mean Square Deviation (RMSD) for molecular conformers. ``` -------------------------------- ### Configure execution parameters Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/conformer_generation_optimization_workflow.ipynb Define constants for file paths, molecule limits, and random seeds. ```python # Configuration SDF_FILE = "../benchmarks/data/MPCONF196.sdf" MAX_MOLECULES = 50 CONFORMERS_PER_MOLECULE = 5 RANDOM_SEED = 42 ``` -------------------------------- ### Add Conformer Pruning Library Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/rdkit_extensions/CMakeLists.txt Sets up a CMake library for conformer pruning. This library links against RDKit libraries and includes the current source directory. ```cmake add_library(conformer_pruning conformer_pruning.cpp) target_link_libraries(conformer_pruning PRIVATE ${RDKit_LIBS}) target_include_directories(conformer_pruning PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) ``` -------------------------------- ### nvMolKit Workflow: GPU-accelerated Fingerprints, Similarity, and Clustering Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/clustering.ipynb Performs fingerprint generation, similarity calculation, and clustering using nvMolKit with GPU acceleration. nvMolKit fingerprints utilize multithreading for preprocessing in addition to GPU acceleration. ```python import time import torch from nvmolkit.similarity import crossTanimotoSimilarity from nvmolkit.fingerprints import MorganFingerprintGenerator t = time.time() nvmolkit_fpgen = MorganFingerprintGenerator(radius=fp_radius, fpSize=fp_nbits) # Note that nvmolkit fingerprints use multithreading for preprocessing in addition to GPU acceleration nvmolkit_fps_cu = torch.as_tensor(nvmolkit_fpgen.GetFingerprints(mols, num_threads=n_cpu_threads), device='cuda') nvmolkit_distances = 1.0 - torch.as_tensor(crossTanimotoSimilarity(nvmolkit_fps_cu),device='cuda') torch.cuda.synchronize() nvmolkit_clusters = ClusterData( nvmolkit_distances.cpu().numpy(), n_mols, distance_threshold, isDistData=True, distFunc=None, reordering=True ) print(f"Total elapsed time: {time.time() - t:.2f} seconds") ``` -------------------------------- ### Configure Benchmark Library and Executables Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/benchmarks/CMakeLists.txt Defines the benchmark_utils static library and various benchmark executables with their respective RDKit, CUDA, and OpenMP dependencies. ```cmake add_library(benchmark_utils STATIC benchmark_utils.cpp) target_link_libraries(benchmark_utils PRIVATE ${RDKit_LIBS} test_utils OpenMP::OpenMP_CXX) add_executable(MorganFpBench morgan_fp.cpp) target_link_libraries( MorganFpBench PRIVATE nanobench ${RDKit_LIBS} OpenMP::OpenMP_CXX morganFingerprint) add_executable(BitVectorBench bit_vector.cpp) target_link_libraries(BitVectorBench PRIVATE nanobench ${RDKit_LIBS} flatBitVect) add_executable(EigenSolverBench eigen_solver_bench.cu) target_link_libraries( EigenSolverBench PRIVATE nanobench ${RDKit_LIBS} device_vector cuda_error_check symmetricEigenSolver) add_executable(ETKDGFFBench etkdg_ff_bench.cpp) target_link_libraries( ETKDGFFBench PRIVATE nanobench ${RDKit_LIBS} rdkit_dist_geom_flattened dist_geom device_vector ff_utils ff_kernel_utils test_utils embedder_utils cuda_error_check) add_executable(mmff_multimol_bench mmff_multimol_bench.cpp) target_link_libraries( mmff_multimol_bench PRIVATE nanobench ${RDKit_LIBS} bfgs_mmff test_utils ff_utils cuda_error_check OpenMP::OpenMP_CXX benchmark_utils) add_executable(ETKDGBench etkdg_embed_bench.cpp) target_link_libraries( ETKDGBench PRIVATE nanobench device_vector dist_geom ${RDKit_LIBS} test_utils etkdg_impl etkdg_stages etkdg embedder_utils conformer_checkers benchmark_utils) add_executable(UpdateInverseHessianBench updateInverseHessianBench.cu) target_link_libraries(UpdateInverseHessianBench PRIVATE CUDA::cudart cuda_error_check device_vector bfgs) ``` -------------------------------- ### Define packed_bonds and molecules libraries Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/src/substruct/CMakeLists.txt Initializes the packed_bonds and molecules libraries and sets their include directories. ```cmake add_library(packed_bonds packed_bonds.cpp) target_include_directories(packed_bonds PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) add_library(molecules molecules.cpp) target_include_directories(molecules PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) ``` -------------------------------- ### Build MolData Library Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/src/testutils/CMakeLists.txt Adds the molData library, which is built only if NVMOLKIT_BUILD_TESTS or NVMOLKIT_BUILD_BENCHMARKS is enabled. It includes the current source directory and links against RDKit libraries. ```cmake if(NVMOLKIT_BUILD_TESTS OR NVMOLKIT_BUILD_BENCHMARKS) add_library(molData mol_data.cpp) target_include_directories(molData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(molData PRIVATE ${RDKit_LIBS}) add_library(substruct_validation substruct_validation.cu) target_include_directories( substruct_validation PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src) target_link_libraries( substruct_validation PUBLIC ${RDKit_LIBS} substructure_search substruct_definitions cuda_error_check flatBitVect) endif() ``` -------------------------------- ### Compute gradients and evaluate conformers Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Demonstrates calculating gradients and evaluating energies for multiple conformers using the MMFFBatchedForcefield class. ```python gradients = ff.compute_gradients() print(f"Gradient for mol_a (first 9 values): {gradients[0][:9]}") # Evaluate specific conformers ff_confs = MMFFBatchedForcefield( [Chem.Mol(mol_a), Chem.Mol(mol_a)], # Same molecule twice conf_id=[0, 1] # Different conformers ) conf_energies = ff_confs.compute_energy() print(f"Conformer 0 energy: {conf_energies[0]:.2f}") print(f"Conformer 1 energy: {conf_energies[1]:.2f}") ``` -------------------------------- ### Load molecules from SDF file Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/conformer_generation_optimization_workflow.ipynb Read molecules from an SDF file and prepare them by removing existing conformers. ```python if not os.path.exists(SDF_FILE): raise FileNotFoundError(f"SDF file not found: {SDF_FILE}") supplier = Chem.SDMolSupplier(SDF_FILE, removeHs=False, sanitize=True) molecules = [] for i, mol in enumerate(supplier): if mol is None: continue if i >= MAX_MOLECULES: break # Clear any existing conformers for clean embedding tests mol.RemoveAllConformers() molecules.append(mol) print(f"Successfully loaded {len(molecules)} molecules from {SDF_FILE}") ``` -------------------------------- ### Apply molecular constraints Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Shows how to apply distance, position, and torsion constraints to molecules within a batched forcefield. ```python # Add constraints ff_constrained = MMFFBatchedForcefield([mol_a, mol_b]) # Distance constraint on mol_a (atoms 0-2, absolute distance 1.8-2.2 A) ff_constrained[0].add_distance_constraint(0, 2, False, 1.8, 2.2, 50.0) # Position constraint on mol_b (keep atom 0 near current position) ff_constrained[1].add_position_constraint(0, 0.1, 100.0) # Torsion constraint (atoms 0-1-2-3, relative dihedral bounds) ff_constrained[1].add_torsion_constraint(0, 1, 2, 3, True, -10.0, 10.0, 25.0) constrained_energies = ff_constrained.compute_energy() print(f"Constrained energies: {constrained_energies}") ``` -------------------------------- ### Compute similarity from database fingerprints Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/similarity.md Loads pre-packed uint32 fingerprints from numpy files and moves them to GPU as torch tensors. ```python import numpy as np import torch from nvmolkit.similarity import crossTanimotoSimilarity # Load packed fingerprints: shape [n, fp_size/32], dtype uint32 packed_np_a = np.load("fingerprints_a_uint32.npy") # e.g., (N, 1024//32) packed_np_b = np.load("fingerprints_b_uint32.npy") # e.g., (M, 1024//32) # Move to GPU as torch tensors (zero-copy from numpy memory semantics, then CUDA copy) fps_a = torch.as_tensor(packed_np_a, device='cuda') fps_b = torch.as_tensor(packed_np_b, device='cuda') # Compute cross-similarity sims = crossTanimotoSimilarity(fps_a, fps_b).torch() # [N_a, N_b] ``` -------------------------------- ### Generate Conformer with nvMolKit Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/index.md Utilize nvMolKit's EmbedMolecules for parallel conformer generation on the GPU. This operation modifies molecules in-place, similar to RDKit's behavior. ```python from rdkit.Chem.rdDistGeom import ETKDGv3 from rdkit.Chem import MolFromSmiles, AddHs from rdkit.Chem.AllChem import EmbedMultipleConfs from nvmolkit.embedMolecules import EmbedMolecules as nvMolKitEmbed # ETKDG conformer generation via nvMolKit mols = [AddHs(MolFromSmiles(smi)) for smi in ['C1CCCCC1', 'C1CCCCC2CCCCC12', "COO"]] params = ETKDGv3() params.useRandomCoords = True # Required for nvMolKit nvMolKitEmbed( molecules=mols, params=params, confsPerMolecule=5, maxIterations=-1, # Automatic iteration calculation ) # RDKit version would be # for mol in mols: # EmbedMultipleConfs(mol, numConfs=5, params=params) for mol in mols: print(mol.GetNumConformers()) ``` -------------------------------- ### Define flatBitVect Interface Library Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/src/data_structures/CMakeLists.txt Defines an interface library and sets the current source directory as an include path. ```cmake add_library(flatBitVect INTERFACE) target_include_directories(flatBitVect INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) ``` -------------------------------- ### Define Test Executables and Dependencies Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/tests/CMakeLists.txt Configures build targets for RDKit-related tests and CUDA device utilities using CMake. ```cmake add_subdirectory(integration) add_executable(test_rdkit_comp test_rdkit_compiles.cpp) target_link_libraries(test_rdkit_comp PRIVATE ${RDKit_LIBS}) add_executable(test_morgan_fingerprint_ref test_morgan_fingerprint_ref.cpp) target_link_libraries(test_morgan_fingerprint_ref PRIVATE ${RDKit_LIBS}) add_executable(test_morgan_fingerprint test_morgan_fingerprint.cpp) target_link_libraries( test_morgan_fingerprint PRIVATE ${RDKit_LIBS} morganFingerprint rdkit_utils molData OpenMP::OpenMP_CXX) add_executable(test_similarity test_similarity.cpp) target_link_libraries(test_similarity PRIVATE ${RDKit_LIBS} Similarity) add_executable(test_cuda_error_check test_cuda_error_check.cpp) target_link_libraries(test_cuda_error_check PRIVATE cuda_error_check) add_executable(test_device test_device.cpp) target_link_libraries(test_device PRIVATE device cuda_error_check CUDA::cudart) add_executable(test_device_timings test_device_timings.cu) target_link_libraries(test_device_timings PRIVATE device_timings) block() # cmake-format and cmake-lint disagree on this wrapped property assignment. ``` -------------------------------- ### GPU Substructure Search with NVMolKit Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Performs GPU-accelerated substructure matching using SMARTS patterns. Supports existence checks, match counting, and atom-index mapping. Requires RDKit and NVMolKit libraries. ```python import numpy as np from rdkit import Chem from nvmolkit.substructure import ( hasSubstructMatch, countSubstructMatches, getSubstructMatches, SubstructSearchConfig ) # Target molecules targets = [ Chem.MolFromSmiles('c1ccccc1O'), # phenol Chem.MolFromSmiles('c1ccccc1N'), # aniline Chem.MolFromSmiles('CCO'), # ethanol Chem.MolFromSmiles('c1ccc2ccccc2c1'), # naphthalene ] # Query patterns (SMARTS) queries = [ Chem.MolFromSmarts('c1ccccc1'), # benzene ring Chem.MolFromSmarts('[OH]'), # hydroxyl group Chem.MolFromSmarts('[NH2]'), # primary amine ] # Configure search parameters config = SubstructSearchConfig( batchSize=1024, workerThreads=-1, # Auto-select preprocessingThreads=-1, # Auto-select maxMatches=0, # 0 = unlimited uniquify=True, # Remove duplicate matches gpuIds=[0] # Use GPU 0 ) # Boolean existence check (fastest) has_match = hasSubstructMatch(targets, queries, config) print("Has substructure match (targets x queries):") print(has_match) # [[1 1 0] phenol: has benzene, has OH, no NH2 # [1 0 1] aniline: has benzene, no OH, has NH2 # [0 1 0] ethanol: no benzene, has OH, no NH2 # [1 0 0]] naphthalene: has benzene, no OH, no NH2 # Count matches per pair counts = countSubstructMatches(targets, queries, config) print(f"\nMatch counts:\n{counts}") # Get full atom-index mappings results = getSubstructMatches(targets, queries, config) # Access results for specific target/query pair target_idx, query_idx = 0, 0 # phenol vs benzene matches = results[target_idx][query_idx] print(f"\nPhenol benzene ring matches: {len(matches)}") for i, match in enumerate(matches[:3]): # Show first 3 matches print(f" Match {i}: atom indices {match}") ``` -------------------------------- ### Compute Morgan Fingerprints in Parallel with nvMolKit Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/index.md Use nvMolKit's MorganFingerprintGenerator for parallel GPU computation of Morgan fingerprints. This is a batch-oriented operation returning a matrix of fingerprints. ```python import torch # RDKit API as common base from rdkit import Chem mols = [Chem.MolFromSmiles(smi) for smi in ['C1CCCCC1', 'C1CCCCC2CCCCC12', "COO"]] # Fingerprints via RDKit from rdkit.Chem import rdFingerprintGenerator rdkit_fpgen = rdFingerprintGenerator.GetMorganGenerator(radius=2, fpSize=1024) rdkit_fps = [rdkit_fpgen.GetFingerprint(mol) for mol in mols] # Sequential processing, list of RDKit fingerprints # Fingerprints via nvMolKit from nvmolkit.fingerprints import MorganFingerprintGenerator nvmolkit_fpgen = MorganFingerprintGenerator(radius=2, fpSize=1024) nvmolkit_fps = nvmolkit_fpgen.GetFingerprints(mols) # Parallel GPU processing, matrix with each row being a fingerprint torch.cuda.synchronize() print(nvmolkit_fps.torch()) ``` -------------------------------- ### Compute similarity from nvMolKit Morgan fingerprints Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/docs/similarity.md Uses native MorganFingerprintGenerator for zero-copy similarity calculation. ```python from rdkit import Chem from nvmolkit.fingerprints import MorganFingerprintGenerator from nvmolkit.similarity import crossTanimotoSimilarity, crossCosineSimilarity import torch mols = [Chem.MolFromSmiles(smi) for smi in ["c1ccccc1", "CCO", "CCN"]] fpgen = MorganFingerprintGenerator(radius=2, fpSize=1024) fps = fpgen.GetFingerprints(mols, num_threads=0) # All-to-all Tanimoto similarity sims = crossTanimotoSimilarity(fps).torch() # [n, n] ``` -------------------------------- ### Configure Fingerprint Similarity Integration Test Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/tests/integration/CMakeLists.txt Defines the executable, links required dependencies, and registers the test suite with GTest. ```cmake add_executable(integration_test_fingerprint_similarity test_fp_sim_workflow.cpp) target_link_libraries( integration_test_fingerprint_similarity PRIVATE ${RDKit_LIBS} morganFingerprint Similarity molData) register_gtest_tests(integration_test_fingerprint_similarity) ``` -------------------------------- ### Compute Cosine Similarity with nvMolKit Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Performs GPU-accelerated cosine similarity calculations with an interface similar to Tanimoto similarity. Includes functions for both all-to-all and cross-similarity computations, as well as a memory-constrained option. ```python import torch from rdkit import Chem from nvmolkit.fingerprints import MorganFingerprintGenerator from nvmolkit.similarity import crossCosineSimilarity, crossCosineSimilarityMemoryConstrained fpgen = MorganFingerprintGenerator(radius=2, fpSize=1024) mols = [Chem.MolFromSmiles(smi) for smi in ['c1ccccc1', 'CCO', 'CCCC', 'c1ccc2ccccc2c1']] fps = fpgen.GetFingerprints(mols) torch.cuda.synchronize() # Compute all-to-all cosine similarity cosine_sim = crossCosineSimilarity(fps).torch() print(f"Cosine similarity matrix:\n{cosine_sim}") # Cross-similarity between two fingerprint sets fps_query = fpgen.GetFingerprints([Chem.MolFromSmiles('c1ccccc1O')]) torch.cuda.synchronize() query_sim = crossCosineSimilarity(fps_query, fps).torch() print(f"Query similarities: {query_sim}") ``` -------------------------------- ### Generate Conformers with ETKDG Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Performs GPU-accelerated ETKDG conformer generation. Molecules must have explicit hydrogens, and useRandomCoords must be set to True. ```python from rdkit import Chem from rdkit.Chem.rdDistGeom import ETKDGv3 from nvmolkit.embedMolecules import EmbedMolecules from nvmolkit.types import HardwareOptions # Prepare molecules (must have explicit hydrogens for 3D embedding) smiles_list = ['CCO', 'CCCC', 'c1ccccc1', 'CC(=O)O', 'CCN'] molecules = [Chem.AddHs(Chem.MolFromSmiles(smi)) for smi in smiles_list] # Configure ETKDG parameters (useRandomCoords must be True) params = ETKDGv3() params.randomSeed = 42 params.useRandomCoords = True # Required for nvMolKit # Configure hardware options for multi-GPU hardware_opts = HardwareOptions( preprocessingThreads=8, # CPU threads for preprocessing batchSize=500, # Conformers per batch batchesPerGpu=4, # Concurrent batches per GPU gpuIds=[0, 1], # Use GPUs 0 and 1 (empty list = all GPUs) ) # Generate 10 conformers per molecule EmbedMolecules( molecules=molecules, params=params, confsPerMolecule=10, maxIterations=-1, # -1 for automatic iteration calculation hardwareOptions=hardware_opts ) # Verify conformers were generated for i, mol in enumerate(molecules): print(f"Molecule {i} ({smiles_list[i]}): {mol.GetNumConformers()} conformers") conf = mol.GetConformer(0) print(f" First atom position: {conf.GetAtomPosition(0)}") ``` -------------------------------- ### Define substructure_search library Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/src/substruct/CMakeLists.txt Configures the main substructure_search library, including source files, dependencies, and compiler options. ```cmake add_library( substructure_search substruct_search.cu gpu_executor.cu recursive_preprocessor.cu minibatch_planner.cpp pinned_buffer_pool.cpp substruct_launch_config.cpp substruct_search_internal.cpp) target_include_directories(substructure_search PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries( substructure_search PUBLIC molecules device_vector flatBitVect cuda_error_check pinned_host_allocator device_timings device substruct_kernels OpenMP::OpenMP_CXX PRIVATE ${RDKit_LIBS}) target_compile_options(substructure_search PRIVATE $<$:-Xcompiler=-fopenmp>) ``` -------------------------------- ### Compare Cluster Sizes with Matplotlib Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/clustering.ipynb Plots the sizes of clusters generated by RDKit and nvMolKit for comparison. This helps visualize the differences in clustering results between the two methods. ```python import matplotlib.pyplot as plt cluster_counts = [len(item) for item in clusters] nvmolkit_cluster_counts = [len(item) for item in nvmolkit_clusters] plt.plot(range(len(cluster_counts)), cluster_counts, label="RDKit", linewidth=3) plt.plot(range(len(nvmolkit_cluster_counts)), nvmolkit_cluster_counts, linestyle="--", linewidth=3, label="nvMolKit") plt.xlabel("Cluster") plt.legend() plt.ylabel("Number of Molecules") plt.ylim(0, max(cluster_counts) * 1.05) ``` -------------------------------- ### Optimize conformers with MMFF Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/conformer_generation_optimization_workflow.ipynb Perform MMFF force field optimization on the generated conformers. ```python mmff_hardware_opts = HardwareOptions( preprocessingThreads=4, batchSize=0, # Process all conformers together ) total_conformers = sum(mol.GetNumConformers() for mol in molecules) start_time = time.time() energies = nvMolKitMMFFOptimize( molecules=molecules, maxIters=200, nonBondedThreshold=100.0, hardwareOptions=mmff_hardware_opts ) optimization_time = time.time() - start_time print(f"MMFF optimization completed in {optimization_time:.2f} seconds") print(f"Rate: {total_conformers/optimization_time:.1f} conformers/second") ``` -------------------------------- ### Build Conformer Checkers Library Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/src/testutils/CMakeLists.txt Adds the conformer_checkers library, which is always built. It links against RDKit libraries and includes the current source directory. ```cmake add_library(conformer_checkers conformer_checkers.cpp) target_link_libraries(conformer_checkers PRIVATE ${RDKit_LIBS}) target_include_directories(conformer_checkers PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) ``` -------------------------------- ### RDKit Workflow: Fingerprints, Similarity, and Clustering Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/examples/clustering.ipynb Computes Morgan fingerprints, Tanimoto distances, and Butina clusters using RDKit. The fingerprinting API is multithreaded. Parallelizing similarity and clustering requires user-defined multiprocessing. ```python import time from rdkit.Chem import rdFingerprintGenerator from rdkit.DataStructs import BulkTanimotoSimilarity from rdkit.ML.Cluster.Butina import ClusterData t = time.time() print("Computing fingerprints") generator = rdFingerprintGenerator.GetMorganGenerator(radius=fp_radius, fpSize=fp_nbits) fps = generator.GetFingerprints(mols, numThreads=n_cpu_threads) print("Computing cross tanimoto distances") distances = [] for i in range(len(mols)): distances.extend(BulkTanimotoSimilarity(fps[i], fps[:i], returnDistance=True)) print("Computing clusters") clusters = ClusterData( distances, n_mols, distance_threshold, isDistData=True, distFunc=None, reordering=True ) print(f"Total elapsed time: {time.time() - t:.2f} seconds") ``` -------------------------------- ### Batched MMFF Forcefield Evaluation Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Provides batched MMFF energy and gradient evaluation with support for geometric constraints. Requires RDKit and NVMolKit. ```python from rdkit import Chem from rdkit.Chem import rdDistGeom from nvmolkit.batchedForcefield import MMFFBatchedForcefield # Prepare molecules with conformers mol_a = Chem.AddHs(Chem.MolFromSmiles('CCO')) mol_b = Chem.AddHs(Chem.MolFromSmiles('CCCC')) rdDistGeom.EmbedMultipleConfs(mol_a, numConfs=3) rdDistGeom.EmbedMultipleConfs(mol_b, numConfs=2) # Create batched forcefield ff = MMFFBatchedForcefield([mol_a, mol_b]) # Compute energies for all molecules energies = ff.compute_energy() print(f"Energies: {energies}") ``` -------------------------------- ### Define substruct_definitions interface library Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/src/substruct/CMakeLists.txt Creates an interface library for substruct_definitions. ```cmake add_library(substruct_definitions INTERFACE) target_include_directories(substruct_definitions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) ``` -------------------------------- ### Compute Tanimoto Similarity with nvMolKit Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Calculates Tanimoto similarity matrices between fingerprint batches on the GPU. Supports all-to-all similarity within a batch or cross-similarity between two batches. A memory-constrained version is available for large datasets. ```python import torch from rdkit import Chem from nvmolkit.fingerprints import MorganFingerprintGenerator from nvmolkit.similarity import crossTanimotoSimilarity, crossTanimotoSimilarityMemoryConstrained # Generate fingerprints for two molecule sets fpgen = MorganFingerprintGenerator(radius=2, fpSize=1024) mols_a = [Chem.MolFromSmiles(smi) for smi in ['c1ccccc1', 'CCO', 'CCCC']] mols_b = [Chem.MolFromSmiles(smi) for smi in ['c1ccc2ccccc2c1', 'CCCCC', 'CC(C)C']] fps_a = fpgen.GetFingerprints(mols_a)\nfps_b = fpgen.GetFingerprints(mols_b) # All-to-all similarity within fps_a torch.cuda.synchronize() sim_matrix = crossTanimotoSimilarity(fps_a).torch() print(f"All-to-all similarity matrix shape: {sim_matrix.shape}") # (3, 3) # Cross-similarity between two batches cross_sim = crossTanimotoSimilarity(fps_a, fps_b).torch() print(f"Cross similarity shape: {cross_sim.shape}") # (3, 3) print(f"Similarity between mol_a[0] and mol_b[0]: {cross_sim[0, 0].item():.4f}") # Memory-constrained version for large datasets (returns numpy, computes in chunks) large_fps = fpgen.GetFingerprints([Chem.MolFromSmiles('CCCC')] * 1000) torch.cuda.synchronize() large_sim_np = crossTanimotoSimilarityMemoryConstrained(large_fps.torch()) print(f"Large similarity matrix shape: {large_sim_np.shape}") # (1000, 1000) ``` -------------------------------- ### Developer Certificate of Origin - Full Text Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/CONTRIBUTING.md The complete text of the Developer Certificate of Origin, Version 1.1, which contributors must agree to. ```text Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. Everyone is permitted to copy and distribute verbatim copies of this document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` -------------------------------- ### Perform Butina Clustering Source: https://context7.com/nvidia-digital-bio/nvmolkit/llms.txt Performs GPU-accelerated Taylor-Butina clustering on distance matrices. The neighborlist_max_size parameter must be a power of 2 (8, 16, 24, 32, 64, or 128). ```python import torch from rdkit import Chem from nvmolkit.fingerprints import MorganFingerprintGenerator from nvmolkit.similarity import crossTanimotoSimilarity from nvmolkit.clustering import butina # Generate fingerprints and compute distance matrix fpgen = MorganFingerprintGenerator(radius=3, fpSize=1024) smiles = ['c1ccccc1', 'c1ccc2ccccc2c1', 'CCO', 'CCCO', 'CCCCO', 'c1ccccc1O'] mols = [Chem.MolFromSmiles(smi) for smi in smiles] fps = fpgen.GetFingerprints(mols) torch.cuda.synchronize() # Compute Tanimoto distances (1 - similarity) similarities = crossTanimotoSimilarity(fps).torch() distances = 1.0 - similarities # Perform Butina clustering cutoff = 0.4 # Distance threshold for clustering clusters = butina( distance_matrix=distances, cutoff=cutoff, neighborlist_max_size=64, # Must be 8, 16, 24, 32, 64, or 128 return_centroids=False ) torch.cuda.synchronize() cluster_ids = clusters.numpy() print(f"Cluster assignments: {cluster_ids}") print(f"Number of clusters: {len(set(cluster_ids))}") # Get centroids as well clusters_with_centroids, centroids = butina(distances, cutoff, return_centroids=True) torch.cuda.synchronize() print(f"Cluster centroids (molecule indices): {centroids.numpy()}") ``` -------------------------------- ### Add MMFF Contributions Library Source: https://github.com/nvidia-digital-bio/nvmolkit/blob/main/rdkit_extensions/CMakeLists.txt Sets up the CMake build for the mmff_contribs library. It links against RDKit, CUDA, device_vector, and ff_utils, and includes the current source directory. ```cmake add_library(mmff_contribs mmff_contribs.cpp) target_link_libraries( mmff_contribs PRIVATE ${RDKit_LIBS} CUDA::cudart device_vector ff_utils PUBLIC mmff) target_include_directories(mmff_contribs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) ```