.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/dispersion/01_dftd3_molecule.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_dispersion_01_dftd3_molecule.py: DFT-D3 Dispersion Correction for a Molecule ============================================ DFT-D3 Dispersion Correction for a Molecule ============================================ This example demonstrates how to compute the DFT-D3 dispersion energy and forces for a single molecular system using GPU-accelerated kernels. The DFT-D3 method provides London dispersion corrections to standard DFT calculations, which is essential for accurately modeling non-covalent interactions. This implementation uses environment-dependent C6 coefficients and includes Becke-Johnson damping (D3-BJ). In this example you will learn: - How to set up DFT-D3 parameters for a specific functional (PBE0) - Loading molecular coordinates from an XYZ file - Computing neighbor lists for non-periodic systems - Calculating dispersion energies and forces on the GPU .. important:: This script is intended as an API demonstration. Do not use this script for performance benchmarking; refer to the `benchmarks` folder instead. .. GENERATED FROM PYTHON SOURCE LINES 43-48 Setup and Parameter Loading ---------------------------- First, we need to import the necessary modules and load the DFT-D3 parameters. The parameters contain element-specific C6 coefficients and radii that are used in the dispersion energy calculation. .. GENERATED FROM PYTHON SOURCE LINES 48-78 .. code-block:: Python from __future__ import annotations import os from pathlib import Path import torch # Import utilities for parameter generation and example DFTD3 module from utils import ( DFTD3, extract_dftd3_parameters, save_dftd3_parameters, ) from nvalchemiops.neighborlist.neighborlist import neighbor_list # Check for cached parameters, download if needed # This step downloads ~500 KB of reference data from the Grimme group param_file = ( Path(os.path.expanduser("~")) / ".cache" / "nvalchemiops" / "dftd3_parameters.pt" ) if not param_file.exists(): print("Downloading DFT-D3 parameters...") params = extract_dftd3_parameters() save_dftd3_parameters(params) else: params = torch.load(param_file, weights_only=True) print("Loaded cached DFT-D3 parameters") .. rst-class:: sphx-glr-script-out .. code-block:: none Loaded cached DFT-D3 parameters .. GENERATED FROM PYTHON SOURCE LINES 79-87 Configure Device and Initialize D3 Module ------------------------------------------ We'll use GPU if available for faster computation. The DFTD3 module is initialized with functional-specific parameters. Here we use PBE0 parameters: - s6: scales the C6/R^6 term (always 1.0 for D3-BJ) - s8: scales the C8/R^8 term (functional-specific) - a1, a2: Becke-Johnson damping parameters (functional-specific) .. GENERATED FROM PYTHON SOURCE LINES 87-101 .. code-block:: Python device = "cuda" if torch.cuda.is_available() else "cpu" dtype = torch.float32 print(f"Using device: {device}") # Initialize with PBE0 parameters d3_module = DFTD3( s6=1.0, # C6 term coefficient s8=1.2177, # C8 term coefficient (PBE0) a1=0.4145, # BJ damping parameter (PBE0) a2=4.8593, # BJ damping radius (PBE0) units="conventional", # Coordinates in Angstrom, energy in eV ) .. rst-class:: sphx-glr-script-out .. code-block:: none Using device: cuda .. GENERATED FROM PYTHON SOURCE LINES 102-107 Load Molecular Structure ------------------------ We'll load a molecular dimer from an XYZ file. This is a simple text format where the first line contains the number of atoms, the second line is a comment, and subsequent lines contain: element symbol, x, y, z coordinates. .. GENERATED FROM PYTHON SOURCE LINES 107-130 .. code-block:: Python with open("./dimer.xyz") as f: lines = f.readlines() num_atoms = int(lines[0]) coords = torch.zeros(num_atoms, 3, device=device, dtype=dtype) atomic_numbers = torch.zeros(num_atoms, device=device, dtype=torch.int32) for i, line in enumerate(lines[2:]): parts = line.split() symbol = parts[0] # Map element symbols to atomic numbers atomic_number = 6 if symbol == "C" else 1 # Carbon or Hydrogen atomic_numbers[i] = atomic_number # Store coordinates (in Angstrom) coords[i, 0] = float(parts[1]) coords[i, 1] = float(parts[2]) coords[i, 2] = float(parts[3]) print(f"Loaded molecule with {num_atoms} atoms") print(f"Coordinates shape: {coords.shape}") .. rst-class:: sphx-glr-script-out .. code-block:: none Loaded molecule with 36 atoms Coordinates shape: torch.Size([36, 3]) .. GENERATED FROM PYTHON SOURCE LINES 131-138 Compute Neighbor List --------------------- The DFT-D3 calculation requires knowing which atoms are within interaction range of each other. We use the GPU-accelerated neighbor list from nvalchemiops. For a non-periodic (molecular) system, we create a large cubic cell and set periodic boundary conditions (PBC) to False. .. GENERATED FROM PYTHON SOURCE LINES 138-157 .. code-block:: Python # Large cell to contain the molecule (30 Angstrom box) cell = torch.eye(3, device=device, dtype=dtype).unsqueeze(0) * 30.0 pbc = torch.tensor([False, False, False], device=device, dtype=torch.bool) # Compute neighbor list with 20 Angstrom cutoff # Returns a neighbor matrix (num_atoms x max_neighbors) with padding neighbor_matrix, num_neighbors_per_atom, neighbor_matrix_shifts = neighbor_list( coords, cutoff=20.0, # Interaction cutoff in Angstrom cell=cell, pbc=pbc, method="cell_list", # O(N) cell list algorithm max_neighbors=64, # Maximum neighbors per atom ) print(f"Neighbor matrix shape: {neighbor_matrix.shape}") print(f"Average neighbors per atom: {num_neighbors_per_atom.float().mean():.1f}") .. rst-class:: sphx-glr-script-out .. code-block:: none Neighbor matrix shape: torch.Size([36, 64]) Average neighbors per atom: 35.0 .. GENERATED FROM PYTHON SOURCE LINES 158-165 Calculate Dispersion Energy and Forces --------------------------------------- Now we can compute the DFT-D3 dispersion correction. The module returns: - energies: dispersion energy contribution per atom (eV) - forces: dispersion forces on each atom (eV/Angstrom) - coord_num: coordination numbers (used internally for C6 calculation) .. GENERATED FROM PYTHON SOURCE LINES 165-172 .. code-block:: Python energies, forces, coord_num = d3_module( positions=coords, numbers=atomic_numbers, neighbor_matrix=neighbor_matrix, ) .. GENERATED FROM PYTHON SOURCE LINES 173-177 Results ------- The total dispersion energy is the sum of atomic contributions. Forces point in the direction that would lower the energy. .. GENERATED FROM PYTHON SOURCE LINES 177-185 .. code-block:: Python total_energy = energies.sum().item() max_force = forces.norm(dim=1).max().item() print(f"\nDispersion Energy: {total_energy:.6f} eV") print(f"Energy per atom: {total_energy / num_atoms:.6f} eV") print(f"Maximum force magnitude: {max_force:.6f} eV/Angstrom") print(f"\nCoordination numbers: {coord_num.cpu().numpy()}") .. rst-class:: sphx-glr-script-out .. code-block:: none Dispersion Energy: -1.340935 eV Energy per atom: -0.037248 eV Maximum force magnitude: 0.047128 eV/Angstrom Coordination numbers: [3.2349308 3.2337396 3.2349308 3.2771623 3.103629 3.2771623 3.0788734 3.103629 3.0788734 3.0804553 1.0007789 1.0004164 1.000779 1.004757 1.004581 1.004757 1.004581 1.0048931 3.2349312 3.2337399 3.2349312 3.2771623 3.103629 3.2771626 3.0788734 3.1036294 3.0788732 3.0804563 1.0007788 1.0004163 1.0007789 1.0047572 1.004581 1.0047572 1.004581 1.0048931] .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.215 seconds) .. _sphx_glr_download_examples_dispersion_01_dftd3_molecule.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 01_dftd3_molecule.ipynb <01_dftd3_molecule.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 01_dftd3_molecule.py <01_dftd3_molecule.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 01_dftd3_molecule.zip <01_dftd3_molecule.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_